Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1# -*- coding: utf-8 -*- 

2# This file is part of Xpra. 

3# Copyright (C) 2011 Serviware (Arthur Huillet, <ahuillet@serviware.com>) 

4# Copyright (C) 2010-2021 Antoine Martin <antoine@xpra.org> 

5# Copyright (C) 2008 Nathaniel Smith <njs@pobox.com> 

6# Xpra is released under the terms of the GNU GPL v2, or, at your option, any 

7# later version. See the file COPYING for details. 

8 

9import os 

10import sys 

11import errno 

12import socket 

13import signal 

14import platform 

15import threading 

16from weakref import WeakKeyDictionary 

17from time import sleep, time 

18 

19from xpra.version_util import ( 

20 XPRA_VERSION, full_version_str, version_compat_check, get_version_info_full, 

21 get_platform_info, get_host_info, 

22 ) 

23from xpra.scripts.server import deadly_signal 

24from xpra.server.server_util import write_pidfile, rm_pidfile 

25from xpra.scripts.config import parse_bool, parse_with_unit, TRUE_OPTIONS, FALSE_OPTIONS 

26from xpra.net.common import may_log_packet, SOCKET_TYPES, MAX_PACKET_SIZE 

27from xpra.net.socket_util import ( 

28 hosts, mdns_publish, peek_connection, PEEK_TIMEOUT_MS, 

29 add_listen_socket, accept_connection, guess_packet_type, 

30 ) 

31from xpra.net.bytestreams import ( 

32 SocketConnection, SSLSocketConnection, 

33 log_new_connection, pretty_socket, SOCKET_TIMEOUT, 

34 ) 

35from xpra.net.net_util import ( 

36 get_network_caps, get_info as get_net_info, 

37 import_netifaces, get_interfaces_addresses, 

38 ) 

39from xpra.net.protocol import Protocol, sanity_checks 

40from xpra.net.digest import get_salt, gendigest, choose_digest 

41from xpra.platform import set_name 

42from xpra.platform.paths import get_app_dir, get_system_conf_dirs, get_user_conf_dirs 

43from xpra.os_util import ( 

44 register_SIGUSR_signals, 

45 get_frame_info, get_info_env, get_sysconfig_info, 

46 filedata_nocrlf, get_machine_id, get_user_uuid, platform_name, get_ssh_port, 

47 strtobytes, bytestostr, get_hex_uuid, 

48 getuid, monotonic_time, hexstr, 

49 WIN32, POSIX, BITS, 

50 parse_encoded_bin_data, 

51 ) 

52from xpra.server.background_worker import stop_worker, get_worker, add_work_item 

53from xpra.server.auth.auth_helper import get_auth_module 

54from xpra.make_thread import start_thread 

55from xpra.util import ( 

56 first_time, noerr, 

57 csv, merge_dicts, typedict, notypedict, flatten_dict, 

58 ellipsizer, dump_all_frames, envint, envbool, envfloat, 

59 SERVER_SHUTDOWN, SERVER_UPGRADE, LOGIN_TIMEOUT, DONE, PROTOCOL_ERROR, 

60 SERVER_ERROR, VERSION_ERROR, CLIENT_REQUEST, SERVER_EXIT, 

61 ) 

62from xpra.log import Logger 

63 

64log = Logger("server") 

65netlog = Logger("network") 

66ssllog = Logger("ssl") 

67httplog = Logger("http") 

68wslog = Logger("websocket") 

69proxylog = Logger("proxy") 

70commandlog = Logger("command") 

71authlog = Logger("auth") 

72timeoutlog = Logger("timeout") 

73dbuslog = Logger("dbus") 

74mdnslog = Logger("mdns") 

75 

76main_thread = threading.current_thread() 

77 

78MAX_CONCURRENT_CONNECTIONS = envint("XPRA_MAX_CONCURRENT_CONNECTIONS", 100) 

79SIMULATE_SERVER_HELLO_ERROR = envbool("XPRA_SIMULATE_SERVER_HELLO_ERROR", False) 

80SERVER_SOCKET_TIMEOUT = envfloat("XPRA_SERVER_SOCKET_TIMEOUT", "0.1") 

81LEGACY_SALT_DIGEST = envbool("XPRA_LEGACY_SALT_DIGEST", False) 

82CHALLENGE_TIMEOUT = envint("XPRA_CHALLENGE_TIMEOUT", 120) 

83SYSCONFIG = envbool("XPRA_SYSCONFIG", True) 

84SHOW_NETWORK_ADDRESSES = envbool("XPRA_SHOW_NETWORK_ADDRESSES", True) 

85 

86ENCRYPTED_SOCKET_TYPES = os.environ.get("XPRA_ENCRYPTED_SOCKET_TYPES", "tcp,ws") 

87 

88HTTP_UNSUPORTED = b"""HTTP/1.1 400 Bad request syntax or unsupported method 

89 

90<head> 

91<title>Server Error</title> 

92</head> 

93<body> 

94<h1>Server Error</h1> 

95<p>Error code 400. 

96<p>Message: this port does not support HTTP requests. 

97<p>Error code explanation: 400 = Bad request syntax or unsupported method. 

98</body> 

99""" 

100 

101 

102#class used to distinguish internal errors 

103#which should not be shown to the client, 

104#from useful messages we do want to pass on 

105class ClientException(Exception): 

106 pass 

107 

108 

109def get_server_info(): 

110 #this function is for non UI thread info 

111 info = { 

112 "platform" : get_platform_info(), 

113 "build" : get_version_info_full(), 

114 } 

115 info.update(get_host_info()) 

116 return info 

117 

118def get_thread_info(proto=None): 

119 #threads: 

120 if proto: 

121 info_threads = proto.get_threads() 

122 else: 

123 info_threads = () 

124 return get_frame_info(info_threads) 

125 

126 

127class ServerCore: 

128 """ 

129 This is the simplest base class for servers. 

130 It only handles the connection layer: 

131 authentication and the initial handshake. 

132 """ 

133 

134 def __init__(self): 

135 log("ServerCore.__init__()") 

136 self.start_time = time() 

137 self.auth_classes = {} 

138 self._when_ready = [] 

139 self.child_reaper = None 

140 self.original_desktop_display = None 

141 self.session_type = "unknown" 

142 self.display_name = "" 

143 

144 self._closing = False 

145 self._upgrading = False 

146 #networking bits: 

147 self._socket_info = {} 

148 self._potential_protocols = [] 

149 self._udp_listeners = [] 

150 self._udp_protocols = {} 

151 self._tcp_proxy_clients = [] 

152 self._tcp_proxy = "" 

153 self._rfb_upgrade = 0 

154 self._ssl_attributes = {} 

155 self._accept_timeout = SOCKET_TIMEOUT + 1 

156 self.ssl_mode = None 

157 self._html = False 

158 self._www_dir = None 

159 self._http_headers_dirs = () 

160 self._aliases = {} 

161 self.socket_info = {} 

162 self.socket_options = {} 

163 self.socket_cleanup = [] 

164 self.socket_verify_timer = WeakKeyDictionary() 

165 self.socket_rfb_upgrade_timer = WeakKeyDictionary() 

166 self._max_connections = MAX_CONCURRENT_CONNECTIONS 

167 self._socket_timeout = SERVER_SOCKET_TIMEOUT 

168 self._ws_timeout = 5 

169 self._socket_dir = None 

170 self.dbus_pid = 0 

171 self.dbus_env = {} 

172 self.dbus_control = False 

173 self.dbus_server = None 

174 self.unix_socket_paths = [] 

175 self.touch_timer = None 

176 self.exec_cwd = os.getcwd() 

177 self.pidfile = None 

178 self.pidinode = 0 

179 

180 self.session_name = "" 

181 

182 #Features: 

183 self.mdns = False 

184 self.mdns_publishers = {} 

185 self.encryption = None 

186 self.encryption_keyfile = None 

187 self.tcp_encryption = None 

188 self.tcp_encryption_keyfile = None 

189 self.password_file = None 

190 self.compression_level = 1 

191 self.exit_with_client = False 

192 self.server_idle_timeout = 0 

193 self.server_idle_timer = None 

194 self.bandwidth_limit = 0 

195 

196 self.init_uuid() 

197 sanity_checks() 

198 

199 def get_server_mode(self): 

200 return "core" 

201 

202 

203 def idle_add(self, *args, **kwargs): 

204 raise NotImplementedError() 

205 

206 def timeout_add(self, *args, **kwargs): 

207 raise NotImplementedError() 

208 

209 def source_remove(self, timer): 

210 raise NotImplementedError() 

211 

212 def init_when_ready(self, callbacks): 

213 log("init_when_ready(%s)", callbacks) 

214 self._when_ready = callbacks 

215 

216 

217 def init(self, opts): 

218 log("ServerCore.init(%s)", opts) 

219 self.session_name = bytestostr(opts.session_name) 

220 set_name("Xpra", self.session_name or "Xpra") 

221 

222 self.bandwidth_limit = parse_with_unit("bandwidth-limit", opts.bandwidth_limit) 

223 self.unix_socket_paths = [] 

224 self._socket_dir = opts.socket_dir or "" 

225 if not self._socket_dir and opts.socket_dirs: 

226 self._socket_dir = opts.socket_dirs[0] 

227 self.encryption = opts.encryption 

228 self.encryption_keyfile = opts.encryption_keyfile 

229 self.tcp_encryption = opts.tcp_encryption 

230 self.tcp_encryption_keyfile = opts.tcp_encryption_keyfile 

231 if self.encryption or self.tcp_encryption: 

232 from xpra.net.crypto import crypto_backend_init 

233 crypto_backend_init() 

234 self.password_file = opts.password_file 

235 self.compression_level = opts.compression_level 

236 self.exit_with_client = opts.exit_with_client 

237 self.server_idle_timeout = opts.server_idle_timeout 

238 self.readonly = opts.readonly 

239 self.ssh_upgrade = opts.ssh_upgrade 

240 self.dbus_control = opts.dbus_control 

241 self.pidfile = opts.pidfile 

242 self.mdns = opts.mdns 

243 self.init_html_proxy(opts) 

244 self.init_auth(opts) 

245 self.init_ssl(opts) 

246 if self.pidfile: 

247 self.pidinode = write_pidfile(self.pidfile) 

248 

249 

250 def init_ssl(self, opts): 

251 self.ssl_mode = opts.ssl 

252 from xpra.net.socket_util import get_ssl_attributes 

253 self._ssl_attributes = get_ssl_attributes(opts, True) 

254 netlog("init_ssl(..) ssl attributes=%s", self._ssl_attributes) 

255 

256 def server_ready(self): 

257 return True 

258 

259 def server_init(self): 

260 if self.mdns: 

261 add_work_item(self.mdns_publish) 

262 self.start_listen_sockets() 

263 

264 def setup(self): 

265 self.init_packet_handlers() 

266 self.init_aliases() 

267 self.init_dbus_server() 

268 self.init_control_commands() 

269 

270 

271 ###################################################################### 

272 # run / stop: 

273 def signal_quit(self, signum, _frame=None): 

274 self.closing() 

275 self.install_signal_handlers(deadly_signal) 

276 self.idle_add(self.clean_quit) 

277 self.idle_add(sys.exit, 128+signum) 

278 

279 def clean_quit(self, upgrading=False): 

280 log("clean_quit(%s)", upgrading) 

281 self._upgrading = upgrading 

282 self.closing() 

283 self.cleanup() 

284 w = get_worker() 

285 log("clean_quit: worker=%s", w) 

286 if w: 

287 stop_worker() 

288 try: 

289 w.join(0.05) 

290 except Exception: 

291 pass 

292 if w.is_alive(): 

293 def quit_timer(): 

294 log("quit_timer() worker=%s", w) 

295 if w and w.is_alive(): 

296 #wait up to 1 second for the worker thread to exit 

297 try: 

298 w.wait(1) 

299 except Exception: 

300 pass 

301 if w.is_alive(): 

302 #still alive, force stop: 

303 stop_worker(True) 

304 try: 

305 w.wait(1) 

306 except Exception: 

307 pass 

308 self.quit(upgrading) 

309 self.timeout_add(250, quit_timer) 

310 log("clean_quit(..) quit timers scheduled, worker=%s", w) 

311 else: 

312 log("clean_quit(..) worker ended") 

313 w = None 

314 def force_quit(): 

315 log("force_quit()") 

316 from xpra import os_util 

317 os_util.force_quit() 

318 self.timeout_add(5000, force_quit) 

319 log("clean_quit(..) quit timers scheduled") 

320 if not w: 

321 self.quit(upgrading) 

322 

323 def quit(self, upgrading=False): 

324 log("quit(%s)", upgrading) 

325 self._upgrading = upgrading 

326 self.closing() 

327 noerr(sys.stdout.flush) 

328 self.do_quit() 

329 log("quit(%s) do_quit done!", upgrading) 

330 dump_all_frames() 

331 

332 def closing(self): 

333 if not self._closing: 

334 self._closing = True 

335 self.log_closing_message() 

336 

337 def log_closing_message(self): 

338 log.info("xpra %s server is %s", self.get_server_mode(), ["terminating", "exiting"][bool(self._upgrading)]) 

339 

340 def do_quit(self): 

341 raise NotImplementedError() 

342 

343 def install_signal_handlers(self, callback): 

344 def os_signal(signum, _frame=None): 

345 callback(signum) 

346 signal.signal(signal.SIGINT, os_signal) 

347 signal.signal(signal.SIGTERM, os_signal) 

348 register_SIGUSR_signals(self.idle_add) 

349 

350 

351 def run(self): 

352 self.install_signal_handlers(self.signal_quit) 

353 def start_ready_callbacks(): 

354 for x in self._when_ready: 

355 try: 

356 x() 

357 except Exception as e: 

358 log("start_ready_callbacks()", exc_info=True) 

359 log.error("Error on server start ready callback '%s':", x) 

360 log.error(" %s", e) 

361 del e 

362 self.idle_add(start_ready_callbacks) 

363 self.idle_add(self.reset_server_timeout) 

364 self.idle_add(self.server_is_ready) 

365 self.idle_add(self.print_run_info) 

366 self.do_run() 

367 log("run()") 

368 return 0 

369 

370 def server_is_ready(self): 

371 log.info("xpra is ready.") 

372 noerr(sys.stdout.flush) 

373 

374 def do_run(self): 

375 raise NotImplementedError() 

376 

377 def cleanup(self): 

378 netlog("cleanup() stopping %s tcp proxy clients: %s", len(self._tcp_proxy_clients), self._tcp_proxy_clients) 

379 for p in tuple(self._tcp_proxy_clients): 

380 p.quit() 

381 netlog("cleanup will disconnect: %s", self._potential_protocols) 

382 self.cancel_touch_timer() 

383 if self.mdns_publishers: 

384 add_work_item(self.mdns_cleanup) 

385 if self._upgrading: 

386 reason = SERVER_UPGRADE 

387 else: 

388 reason = SERVER_SHUTDOWN 

389 protocols = self.get_all_protocols() 

390 self.cleanup_protocols(protocols, reason) 

391 self.do_cleanup() 

392 self.cleanup_protocols(protocols, reason, True) 

393 self._potential_protocols = [] 

394 self.cleanup_udp_listeners() 

395 self.cleanup_sockets() 

396 self.cleanup_dbus_server() 

397 if not self._upgrading: 

398 self.stop_dbus_server() 

399 if self.pidfile: 

400 self.pidinode = rm_pidfile(self.pidfile, self.pidinode) 

401 

402 def do_cleanup(self): 

403 #allow just a bit of time for the protocol packet flush 

404 sleep(0.1) 

405 

406 

407 def cleanup_sockets(self): 

408 #stop listening for IO events: 

409 for sc in self.socket_cleanup: 

410 sc() 

411 #actually close the socket: 

412 si = self._socket_info 

413 self._socket_info = {} 

414 for socktype, _, info, cleanup in si: 

415 log("cleanup_sockets() calling %s for %s %s", cleanup, socktype, info) 

416 try: 

417 cleanup() 

418 except Exception: 

419 log("cleanup error on %s", cleanup, exc_info=True) 

420 

421 

422 ###################################################################### 

423 # dbus: 

424 def init_dbus(self, dbus_pid, dbus_env): 

425 if not POSIX: 

426 return 

427 self.dbus_pid = dbus_pid 

428 self.dbus_env = dbus_env 

429 

430 def stop_dbus_server(self): 

431 dbuslog("stop_dbus_server() dbus_pid=%s", self.dbus_pid) 

432 if not self.dbus_pid: 

433 return 

434 try: 

435 os.kill(self.dbus_pid, signal.SIGINT) 

436 except ProcessLookupError as e: 

437 dbuslog("os.kill(%i, SIGINT)", self.dbus_pid, exc_info=True) 

438 dbuslog.warn("Warning: dbus process not found (pid=%i)", self.dbus_pid) 

439 except Exception as e: 

440 dbuslog("os.kill(%i, SIGINT)", self.dbus_pid, exc_info=True) 

441 dbuslog.warn("Warning: error trying to stop dbus with pid %i:", self.dbus_pid) 

442 dbuslog.warn(" %s", e) 

443 

444 def init_dbus_server(self): 

445 if not POSIX: 

446 return 

447 dbuslog("init_dbus_server() dbus_control=%s", self.dbus_control) 

448 dbuslog("init_dbus_server() env: %s", dict((k,v) for k,v in os.environ.items() 

449 if bytestostr(k).startswith("DBUS_"))) 

450 if not self.dbus_control: 

451 return 

452 try: 

453 from xpra.server.dbus.dbus_common import dbus_exception_wrap 

454 self.dbus_server = dbus_exception_wrap(self.make_dbus_server, "setting up server dbus instance") 

455 except Exception as e: 

456 log("init_dbus_server()", exc_info=True) 

457 log.error("Error: cannot load dbus server:") 

458 log.error(" %s", e) 

459 self.dbus_server = None 

460 

461 def cleanup_dbus_server(self): 

462 ds = self.dbus_server 

463 if ds: 

464 ds.cleanup() 

465 self.dbus_server = None 

466 

467 def make_dbus_server(self): #pylint: disable=useless-return 

468 dbuslog("make_dbus_server() no dbus server for %s", self) 

469 return None 

470 

471 

472 def init_uuid(self): 

473 # Define a server UUID if needed: 

474 self.uuid = os.environ.get("XPRA_PROXY_START_UUID") or self.get_uuid() 

475 if not self.uuid: 

476 self.uuid = bytestostr(get_hex_uuid()) 

477 self.save_uuid() 

478 log("server uuid is %s", self.uuid) 

479 

480 def get_uuid(self): 

481 return None 

482 

483 def save_uuid(self): 

484 pass 

485 

486 

487 def init_html_proxy(self, opts): 

488 httplog("init_html_proxy(..) options: tcp_proxy=%s, html='%s'", opts.tcp_proxy, opts.html) 

489 self._tcp_proxy = opts.tcp_proxy 

490 #opts.html can contain a boolean, "auto" or the path to the webroot 

491 www_dir = None 

492 if opts.html and os.path.isabs(opts.html): 

493 www_dir = opts.html 

494 self._html = True 

495 else: 

496 self._html = parse_bool("html", opts.html) 

497 if self._html is not False: #True or None (for "auto") 

498 if not (opts.bind_tcp or opts.bind_ws or opts.bind_wss or opts.bind or opts.bind_ssl): 

499 #we need a socket! 

500 if self._html: 

501 #html was enabled, so log an error: 

502 httplog.error("Error: cannot use the html server without a socket") 

503 self._html = False 

504 httplog("init_html_proxy(..) html=%s", self._html) 

505 if self._html is not False: 

506 try: 

507 from xpra.net.websockets.handler import WebSocketRequestHandler 

508 assert WebSocketRequestHandler 

509 self._html = True 

510 except ImportError as e: 

511 httplog("importing WebSocketRequestHandler", exc_info=True) 

512 if self._html is None: #auto mode 

513 httplog.info("html server unavailable, cannot find websocket module") 

514 else: 

515 httplog.error("Error: cannot import websocket connection handler:") 

516 httplog.error(" %s", e) 

517 httplog.error(" the html server will not be available") 

518 self._html = False 

519 #make sure we have the web root: 

520 from xpra.platform.paths import get_resources_dir 

521 if www_dir: 

522 self._www_dir = www_dir 

523 else: 

524 for ad,d in ( 

525 (get_resources_dir(), "html5"), 

526 (get_resources_dir(), "www"), 

527 (get_app_dir(), "www"), 

528 ): 

529 self._www_dir = os.path.abspath(os.path.join(ad, d)) 

530 if os.path.exists(self._www_dir): 

531 httplog("found html5 client in '%s'", self._www_dir) 

532 break 

533 if not os.path.exists(self._www_dir) and self._html: 

534 httplog.error("Error: cannot find the html web root") 

535 httplog.error(" '%s' does not exist", self._www_dir) 

536 self._html = False 

537 if self._html: 

538 httplog.info("serving html content from '%s'", self._www_dir) 

539 self._http_headers_dirs = [] 

540 for d in get_system_conf_dirs(): 

541 self._http_headers_dirs.append(os.path.join(d, "http-headers")) 

542 if not POSIX or getuid()>0: 

543 for d in get_user_conf_dirs(): 

544 self._http_headers_dirs.append(os.path.join(d, "http-headers")) 

545 self._http_headers_dirs.append(os.path.abspath(os.path.join(self._www_dir, "../http-headers"))) 

546 if self._html and self._tcp_proxy: 

547 httplog.warn("Warning: the built in html server is enabled,") 

548 httplog.warn(" disabling the tcp-proxy option") 

549 self._tcp_proxy = False 

550 

551 

552 ###################################################################### 

553 # authentication: 

554 def init_auth(self, opts): 

555 auth = self.get_auth_modules("local-auth", opts.auth or []) 

556 if WIN32: 

557 self.auth_classes["named-pipe"] = auth 

558 else: 

559 self.auth_classes["unix-domain"] = auth 

560 for x in SOCKET_TYPES: 

561 opts_value = getattr(opts, "%s_auth" % x) 

562 self.auth_classes[x] = self.get_auth_modules(x, opts_value) 

563 authlog("init_auth(..) auth=%s", self.auth_classes) 

564 

565 def get_auth_modules(self, socket_type, auth_strs): 

566 authlog("get_auth_modules(%s, %s, {..})", socket_type, auth_strs) 

567 if not auth_strs: 

568 return None 

569 return tuple(get_auth_module(auth_str) for auth_str in auth_strs) 

570 

571 

572 ###################################################################### 

573 # control commands: 

574 def init_control_commands(self): 

575 from xpra.server.control_command import HelloCommand, HelpCommand, DebugControl 

576 self.control_commands = {"hello" : HelloCommand(), 

577 "debug" : DebugControl()} 

578 help_command = HelpCommand(self.control_commands) 

579 self.control_commands["help"] = help_command 

580 

581 def handle_command_request(self, proto, *args): 

582 """ client sent a command request as part of the hello packet """ 

583 assert args 

584 code, response = self.process_control_command(*args) 

585 hello = {"command_response" : (code, response)} 

586 proto.send_now(("hello", hello)) 

587 

588 def process_control_command(self, *args): 

589 from xpra.server.control_command import ControlError 

590 assert args, "control command must have arguments" 

591 name = args[0] 

592 try: 

593 command = self.control_commands.get(name) 

594 commandlog("process_control_command control_commands[%s]=%s", name, command) 

595 if not command: 

596 commandlog.warn("invalid command: '%s' (must be one of: %s)", name, csv(self.control_commands)) 

597 return 6, "invalid command" 

598 commandlog("process_control_command calling %s%s", command.run, args[1:]) 

599 v = command.run(*args[1:]) 

600 return 0, v 

601 except ControlError as e: 

602 commandlog.error("error %s processing control command '%s'", e.code, name) 

603 msgs = [" %s" % e] 

604 if e.help: 

605 msgs.append(" '%s': %s" % (name, e.help)) 

606 for msg in msgs: 

607 commandlog.error(msg) 

608 return e.code, "\n".join(msgs) 

609 except Exception as e: 

610 commandlog.error("error processing control command '%s'", name, exc_info=True) 

611 return 127, "error processing control command: %s" % e 

612 

613 

614 def print_run_info(self): 

615 add_work_item(self.do_print_run_info) 

616 

617 def do_print_run_info(self): 

618 log.info("xpra %s version %s %i-bit", self.get_server_mode(), full_version_str(), BITS) 

619 try: 

620 pinfo = get_platform_info() 

621 osinfo = " on %s" % platform_name(sys.platform, pinfo.get("linux_distribution") or pinfo.get("sysrelease", "")) 

622 except Exception: 

623 log("platform name error:", exc_info=True) 

624 osinfo = "" 

625 if POSIX: 

626 uid = os.getuid() 

627 gid = os.getgid() 

628 try: 

629 import pwd 

630 import grp #@UnresolvedImport 

631 user = pwd.getpwuid(uid)[0] 

632 group = grp.getgrgid(gid)[0] 

633 log.info(" uid=%i (%s), gid=%i (%s)", uid, user, gid, group) 

634 except: 

635 log.info(" uid=%i, gid=%i", uid, gid) 

636 log.info(" running with pid %s%s", os.getpid(), osinfo) 

637 self.idle_add(self.print_screen_info) 

638 

639 def notify_new_user(self, ss): 

640 pass 

641 

642 

643 ###################################################################### 

644 # screen / display: 

645 def get_display_bit_depth(self): 

646 return 0 

647 

648 def print_screen_info(self): 

649 display = os.environ.get("DISPLAY") 

650 if display and display.startswith(":"): 

651 extra = "" 

652 bit_depth = self.get_display_bit_depth() 

653 if bit_depth: 

654 extra = " with %i bit colors" % bit_depth 

655 log.info(" connected to X11 display %s%s", display, extra) 

656 

657 

658 ###################################################################### 

659 # sockets / connections / packets: 

660 def init_sockets(self, sockets): 

661 self._socket_info = sockets 

662 

663 

664 def mdns_publish(self): 

665 if not self.mdns: 

666 return 

667 #find all the records we want to publish: 

668 mdns_recs = {} 

669 for sock_def, options in self._socket_info.items(): 

670 socktype, _, info, _ = sock_def 

671 socktypes = self.get_mdns_socktypes(socktype) 

672 mdns_option = options.get("mdns") 

673 if mdns_option: 

674 v = parse_bool("mdns", mdns_option, False) 

675 if not v: 

676 mdnslog("mdns_publish() mdns(%s)=%s, skipped", info, mdns_option) 

677 continue 

678 mdnslog("mdns_publish() info=%s, socktypes(%s)=%s", info, socktype, socktypes) 

679 for st in socktypes: 

680 recs = mdns_recs.setdefault(st, []) 

681 if socktype=="unix-domain": 

682 assert st=="ssh" 

683 host = "*" 

684 iport = get_ssh_port() 

685 if not iport: 

686 continue 

687 else: 

688 host, iport = info 

689 for h in hosts(host): 

690 rec = (h, iport) 

691 if rec not in recs: 

692 recs.append(rec) 

693 mdnslog("mdns_publish() recs[%s]=%s", st, recs) 

694 mdns_info = self.get_mdns_info() 

695 self.mdns_publishers = {} 

696 for mdns_mode, listen_on in mdns_recs.items(): 

697 info = dict(mdns_info) 

698 info["mode"] = mdns_mode 

699 aps = mdns_publish(self.display_name, listen_on, info) 

700 for ap in aps: 

701 ap.start() 

702 self.mdns_publishers[ap] = mdns_mode 

703 

704 def get_mdns_socktypes(self, socktype): 

705 #for a given socket type, 

706 #what socket types we should expose via mdns 

707 if socktype in ("vsock", "named-pipe"): 

708 #cannot be accessed remotely 

709 return () 

710 ssh_access = get_ssh_port()>0 #and opts.ssh.lower().strip() not in FALSE_OPTIONS 

711 ssl = bool(self._ssl_attributes) 

712 #only available with the RFBServer 

713 rfb_upgrades = getattr(self, "_rfb_upgrade", False) 

714 socktypes = [socktype] 

715 if socktype=="tcp": 

716 if ssl: 

717 socktypes.append("ssl") 

718 if self._html: 

719 socktypes.append("ws") 

720 if self._html and ssl: 

721 socktypes.append("wss") 

722 if self.ssh_upgrade: 

723 socktypes.append("ssh") 

724 if rfb_upgrades: 

725 socktypes.append("rfb") 

726 elif socktype=="ws": 

727 if ssl: 

728 socktypes.append("wss") 

729 elif socktype=="unix-domain": 

730 if ssh_access: 

731 socktypes = ["ssh"] 

732 return socktypes 

733 

734 def get_mdns_info(self) -> dict: 

735 from xpra.platform.info import get_username 

736 mdns_info = { 

737 "display" : self.display_name, 

738 "username" : get_username(), 

739 "uuid" : self.uuid, 

740 "platform" : sys.platform, 

741 "type" : self.session_type, 

742 } 

743 MDNS_EXPOSE_NAME = envbool("XPRA_MDNS_EXPOSE_NAME", True) 

744 if MDNS_EXPOSE_NAME and self.session_name: 

745 mdns_info["name"] = self.session_name 

746 return mdns_info 

747 

748 def mdns_cleanup(self): 

749 mp = self.mdns_publishers 

750 self.mdns_publishers = {} 

751 for ap in tuple(mp.keys()): 

752 ap.stop() 

753 

754 def mdns_update(self): 

755 if not self.mdns: 

756 return 

757 txt = self.get_mdns_info() 

758 for mdns_publisher, mode in dict(self.mdns_publishers).items(): 

759 info = dict(txt) 

760 info["mode"] = mode 

761 try: 

762 mdns_publisher.update_txt(info) 

763 except Exception as e: 

764 mdnslog("mdns_update: %s(%s)", mdns_publisher.update_txt, info, exc_info=True) 

765 mdnslog.warn("Warning: mdns update failed") 

766 mdnslog.warn(" %s", e) 

767 

768 

769 def start_listen_sockets(self): 

770 ### All right, we're ready to accept customers: 

771 for sock_def, options in self._socket_info.items(): 

772 socktype, sock, info, _ = sock_def 

773 netlog("init_sockets(%s) will add %s socket %s (%s)", self._socket_info, socktype, sock, info) 

774 self.socket_info[sock] = info 

775 self.socket_options[sock] = options 

776 self.idle_add(self.add_listen_socket, socktype, sock, options) 

777 if socktype=="unix-domain" and info: 

778 try: 

779 p = os.path.abspath(info) 

780 self.unix_socket_paths.append(p) 

781 netlog("added unix socket path: %s", p) 

782 except Exception as e: 

783 log.error("failed to set socket path to %s: %s", info, e) 

784 del e 

785 if self.unix_socket_paths: 

786 self.touch_timer = self.timeout_add(60*1000, self.touch_sockets) 

787 

788 

789 def cancel_touch_timer(self): 

790 tt = self.touch_timer 

791 if tt: 

792 self.touch_timer = None 

793 self.source_remove(tt) 

794 

795 def touch_sockets(self): 

796 netlog("touch_sockets() unix socket paths=%s", self.unix_socket_paths) 

797 for sockpath in self.unix_socket_paths: 

798 if not os.path.exists(sockpath): 

799 if first_time("missing-socket-%s" % sockpath): 

800 log.warn("Warning: the unix domain socket cannot be found:") 

801 log.warn(" '%s'", sockpath) 

802 log.warn(" was it deleted by mistake?") 

803 continue 

804 try: 

805 os.utime(sockpath, None) 

806 except Exception: 

807 netlog("touch_sockets() error on %s", sockpath, exc_info=True) 

808 return True 

809 

810 def init_packet_handlers(self): 

811 netlog("initializing packet handlers") 

812 self._default_packet_handlers = { 

813 "hello": self._process_hello, 

814 "disconnect": self._process_disconnect, 

815 "udp-control": self._process_udp_control, 

816 Protocol.CONNECTION_LOST: self._process_connection_lost, 

817 Protocol.GIBBERISH: self._process_gibberish, 

818 Protocol.INVALID: self._process_invalid, 

819 } 

820 

821 def init_aliases(self): 

822 self.do_init_aliases(self._default_packet_handlers.keys()) 

823 

824 def do_init_aliases(self, packet_types): 

825 i = 1 

826 for key in packet_types: 

827 self._aliases[i] = key 

828 i += 1 

829 

830 def cleanup_udp_listeners(self): 

831 for udpl in self._udp_listeners: 

832 udpl.close() 

833 self._udp_listeners = [] 

834 

835 def cleanup_all_protocols(self, reason): 

836 protocols = self.get_all_protocols() 

837 self.cleanup_protocols(protocols, reason) 

838 

839 def get_all_protocols(self): 

840 return tuple(self._potential_protocols) 

841 

842 def cleanup_protocols(self, protocols, reason, force=False): 

843 netlog("cleanup_protocols(%s, %s, %s)", protocols, reason, force) 

844 for protocol in protocols: 

845 if force: 

846 self.force_disconnect(protocol) 

847 else: 

848 self.disconnect_protocol(protocol, reason) 

849 

850 def add_listen_socket(self, socktype, sock, options): 

851 info = self.socket_info.get(sock) 

852 netlog("add_listen_socket(%s, %s, %s) info=%s", socktype, sock, options, info) 

853 cleanup = add_listen_socket(socktype, sock, info, self._new_connection, self._new_udp_connection, options) 

854 if cleanup: 

855 self.socket_cleanup.append(cleanup) 

856 

857 def _new_udp_connection(self, sock): 

858 from xpra.net.udp_protocol import UDPListener 

859 socket_options = self.socket_options.get(sock, {}) 

860 udpl = UDPListener(sock, self.process_udp_packet, socket_options) 

861 self._udp_listeners.append(udpl) 

862 

863 def _new_connection(self, socktype, listener, handle=0): 

864 """ 

865 Accept the new connection, 

866 verify that there aren't too many, 

867 start a thread to dispatch it to the correct handler. 

868 """ 

869 log("_new_connection%s", (listener, socktype, handle)) 

870 if self._closing: 

871 netlog("ignoring new connection during shutdown") 

872 return False 

873 socket_info = self.socket_info.get(listener) 

874 assert socktype, "cannot find socket type for %s" % listener 

875 #TODO: just like add_listen_socket above, this needs refactoring 

876 socket_options = self.socket_options.get(listener, {}) 

877 if socktype=="named-pipe": 

878 from xpra.platform.win32.namedpipes.connection import NamedPipeConnection 

879 conn = NamedPipeConnection(listener.pipe_name, handle, socket_options) 

880 netlog.info("New %s connection received on %s", socktype, conn.target) 

881 return self.make_protocol(socktype, conn, socket_options) 

882 

883 conn = accept_connection(socktype, listener, self._socket_timeout, socket_options) 

884 if conn is None: 

885 return True 

886 #limit number of concurrent network connections: 

887 if socktype not in ("unix-domain", ) and len(self._potential_protocols)>=self._max_connections: 

888 netlog.error("Error: too many connections (%i)", len(self._potential_protocols)) 

889 netlog.error(" ignoring new one: %s", conn.endpoint) 

890 conn.close() 

891 return True 

892 #from here on, we run in a thread, so we can poll (peek does) 

893 start_thread(self.handle_new_connection, "new-%s-connection" % socktype, True, 

894 args=(conn, socket_info, socket_options)) 

895 return True 

896 

897 def new_conn_err(self, conn, sock, socktype, socket_info, packet_type, msg=None): 

898 #not an xpra client 

899 netlog.error("Error: %s connection failed:", socktype) 

900 if conn.remote: 

901 netlog.error(" packet from %s", pretty_socket(conn.remote)) 

902 if socket_info: 

903 netlog.error(" received on %s", pretty_socket(socket_info)) 

904 if packet_type: 

905 netlog.error(" this packet looks like a '%s' packet", packet_type) 

906 else: 

907 netlog.error(" invalid packet format, not an xpra client?") 

908 packet_data = b"disconnect: connection setup failed" 

909 if msg: 

910 netlog.error(" %s", msg) 

911 packet_data += b", %s?" % strtobytes(msg) 

912 packet_data += b"\n" 

913 try: 

914 #default to plain text: 

915 sock.settimeout(1) 

916 if packet_type=="xpra": 

917 #try xpra packet format: 

918 from xpra.net.packet_encoding import pack_one_packet 

919 packet_data = pack_one_packet(["disconnect", "invalid protocol for this port"]) or packet_data 

920 elif packet_type=="http": 

921 #HTTP 400 error: 

922 packet_data = HTTP_UNSUPORTED 

923 conn.write(packet_data) 

924 self.timeout_add(500, self.force_close_connection, conn) 

925 except Exception as e: 

926 netlog("error sending %r: %s", packet_data, e) 

927 

928 def force_close_connection(self, conn): 

929 try: 

930 conn.close() 

931 except OSError: 

932 log("close_connection()", exc_info=True) 

933 

934 def handle_new_connection(self, conn, socket_info, socket_options): 

935 """ 

936 Use peek to decide what sort of connection this is, 

937 and start the appropriate handler for it. 

938 """ 

939 sock = conn._socket 

940 address = conn.remote 

941 socktype = conn.socktype 

942 peername = conn.endpoint 

943 

944 sockname = sock.getsockname() 

945 target = peername or sockname 

946 sock.settimeout(self._socket_timeout) 

947 

948 netlog("handle_new_connection%s sockname=%s, target=%s", 

949 (conn, socket_info, socket_options), sockname, target) 

950 #peek so we can detect invalid clients early, 

951 #or handle non-xpra / wrapped traffic: 

952 timeout = PEEK_TIMEOUT_MS 

953 if socktype=="rfb": 

954 #rfb does not send any data, waits for a server packet 

955 #so don't bother waiting for something that should never come: 

956 timeout = 0 

957 peek_data = peek_connection(conn, timeout) 

958 line1 = peek_data.split(b"\n")[0] 

959 log("socket peek=%s", ellipsizer(peek_data, limit=512)) 

960 log("socket peek hex=%s", hexstr(peek_data[:128])) 

961 log("socket peek line1=%s", ellipsizer(line1)) 

962 packet_type = guess_packet_type(peek_data) 

963 log("guess_packet_type(..)=%s", packet_type) 

964 

965 def ssl_wrap(): 

966 ssl_sock = self._ssl_wrap_socket(socktype, sock, socket_options) 

967 ssllog("ssl wrapped socket(%s)=%s", sock, ssl_sock) 

968 if ssl_sock is None: 

969 return None 

970 ssl_conn = SSLSocketConnection(ssl_sock, sockname, address, target, socktype) 

971 ssllog("ssl_wrap()=%s", ssl_conn) 

972 return ssl_conn 

973 

974 if socktype in ("ssl", "wss"): 

975 #verify that this isn't plain HTTP / xpra: 

976 if packet_type not in ("ssl", None): 

977 self.new_conn_err(conn, sock, socktype, socket_info, packet_type) 

978 return 

979 #always start by wrapping with SSL: 

980 ssl_conn = ssl_wrap() 

981 if not ssl_conn: 

982 return 

983 if socktype=="wss": 

984 http = True 

985 else: 

986 assert socktype=="ssl" 

987 wss = socket_options.get("wss", "").lower() 

988 if wss is not None: 

989 if wss=="auto": 

990 http = None 

991 else: 

992 http = wss in TRUE_OPTIONS 

993 else: 

994 #no "wss" option, fallback to "ssl_mode" option: 

995 if self.ssl_mode.lower()=="auto": 

996 http = None 

997 else: 

998 http = self.ssl_mode.lower()=="wss" 

999 if http is None: 

1000 #look for HTTPS request to handle: 

1001 if line1.find(b"HTTP/")>0 or peek_data.find(b"\x08http/")>0: 

1002 http = True 

1003 else: 

1004 ssl_conn.enable_peek() 

1005 peek_data = peek_connection(ssl_conn) 

1006 line1 = peek_data.split(b"\n")[0] 

1007 http = line1.find(b"HTTP/")>0 

1008 if http: 

1009 if not self._html: 

1010 self.new_conn_err(conn, sock, socktype, socket_info, packet_type, 

1011 "the builtin http server is not enabled") 

1012 return 

1013 self.start_http_socket(socktype, ssl_conn, socket_options, True, peek_data) 

1014 else: 

1015 ssl_conn._socket.settimeout(self._socket_timeout) 

1016 log_new_connection(ssl_conn, socket_info) 

1017 self.make_protocol(socktype, ssl_conn, socket_options) 

1018 return 

1019 

1020 if socktype=="ws": 

1021 if peek_data: 

1022 #honour socket option, fallback to "ssl_mode" attribute: 

1023 wss = socket_options.get("wss", "").lower() 

1024 if wss: 

1025 wss_upgrade = wss in TRUE_OPTIONS 

1026 else: 

1027 wss_upgrade = self.ssl_mode.lower() in TRUE_OPTIONS or self.ssl_mode.lower() in ("auto", "wss") 

1028 if wss_upgrade and packet_type=="ssl": 

1029 ssllog("ws socket receiving ssl, upgrading to wss") 

1030 conn = ssl_wrap() 

1031 if conn is None: 

1032 return 

1033 elif packet_type not in (None, "http"): 

1034 self.new_conn_err(conn, sock, socktype, socket_info, packet_type) 

1035 return 

1036 self.start_http_socket(socktype, conn, socket_options, False, peek_data) 

1037 return 

1038 

1039 if socktype=="rfb": 

1040 if peek_data: 

1041 self.new_conn_err(conn, sock, socktype, socket_info, packet_type) 

1042 return 

1043 self.handle_rfb_connection(conn) 

1044 return 

1045 

1046 if socktype=="ssh": 

1047 conn = self.handle_ssh_connection(conn, socket_options) 

1048 if not conn: 

1049 return 

1050 peek_data, line1, packet_type = b"", b"", None 

1051 

1052 if socktype in ("tcp", "unix-domain", "named-pipe") and peek_data: 

1053 #see if the packet data is actually xpra or something else 

1054 #that we need to handle via a tcp proxy, ssl wrapper or the websocket adapter: 

1055 try: 

1056 cont, conn, peek_data = self.may_wrap_socket(conn, socktype, socket_info, socket_options, peek_data) 

1057 netlog("may_wrap_socket(..)=(%s, %s, %r)", cont, conn, peek_data) 

1058 if not cont: 

1059 return 

1060 packet_type = guess_packet_type(peek_data) 

1061 except IOError as e: 

1062 netlog("socket wrapping failed", exc_info=True) 

1063 self.new_conn_err(conn, sock, socktype, socket_info, None, str(e)) 

1064 return 

1065 

1066 if packet_type not in ("xpra", None): 

1067 self.new_conn_err(conn, sock, socktype, socket_info, packet_type) 

1068 return 

1069 

1070 #get the new socket object as we may have wrapped it with ssl: 

1071 sock = getattr(conn, "_socket", sock) 

1072 sock.settimeout(self._socket_timeout) 

1073 log_new_connection(conn, socket_info) 

1074 proto = self.make_protocol(socktype, conn, socket_options) 

1075 if socktype=="tcp" and not peek_data and self._rfb_upgrade>0: 

1076 t = self.timeout_add(self._rfb_upgrade*1000, self.try_upgrade_to_rfb, proto) 

1077 self.socket_rfb_upgrade_timer[proto] = t 

1078 

1079 def _ssl_wrap_socket(self, socktype, sock, socket_options): 

1080 ssllog("ssl_wrap_socket(%s, %s, %s)", socktype, sock, socket_options) 

1081 try: 

1082 from xpra.net.socket_util import ssl_wrap_socket 

1083 kwargs = self._ssl_attributes.copy() 

1084 for k,v in socket_options.items(): 

1085 #options use '-' but attributes and parameters use '_': 

1086 k = k.replace("-", "_") 

1087 if k.startswith("ssl_"): 

1088 k = k[4:] 

1089 kwargs[k] = v 

1090 ssl_sock = ssl_wrap_socket(sock, **kwargs) 

1091 ssllog("_ssl_wrap_socket(%s, %s)=%s", sock, kwargs, ssl_sock) 

1092 if ssl_sock is None: 

1093 #None means EOF! (we don't want to import ssl bits here) 

1094 ssllog("ignoring SSL EOF error") 

1095 return ssl_sock 

1096 except Exception as e: 

1097 ssllog("SSL error", exc_info=True) 

1098 ssl_paths = [socket_options.get(x, kwargs.get(x)) for x in ("ssl-cert", "ssl-key")] 

1099 cpaths = csv("'%s'" % x for x in ssl_paths if x) 

1100 log.error("Error: failed to create SSL socket") 

1101 log.error(" from %s socket: %s", socktype, sock) 

1102 if not cpaths: 

1103 log.error(" no certificate paths specified") 

1104 else: 

1105 log.error(" check your certificate paths: %s", cpaths) 

1106 log.error(" %s", e) 

1107 return None 

1108 

1109 

1110 def handle_ssh_connection(self, conn, socket_options): 

1111 from xpra.server.ssh import make_ssh_server_connection, log as sshlog 

1112 socktype = conn.socktype_wrapped 

1113 none_auth = not self.auth_classes[socktype] 

1114 sshlog("handle_ssh_connection(%s, %s) socktype wrapped=%s", conn, socket_options, socktype) 

1115 def ssh_password_authenticate(username, password): 

1116 if not POSIX or getuid()!=0: 

1117 import getpass 

1118 sysusername = getpass.getuser() 

1119 if sysusername!=username: 

1120 sshlog.warn("Warning: ssh password authentication failed,") 

1121 sshlog.warn(" username does not match:") 

1122 sshlog.warn(" expected '%s', got '%s'", sysusername, username) 

1123 return False 

1124 auth_modules = self.make_authenticators(socktype, username, conn) 

1125 sshlog("ssh_password_authenticate auth_modules(%s, %s)=%s", username, "*"*len(password), auth_modules) 

1126 for auth in auth_modules: 

1127 #mimic a client challenge: 

1128 digests = ["xor"] 

1129 try: 

1130 salt, digest = auth.get_challenge(digests) 

1131 salt_digest = auth.choose_salt_digest(digests) 

1132 assert digest=="xor" and salt_digest=="xor" 

1133 except ValueError as e: 

1134 sshlog("authentication with %s", auth, exc_info=True) 

1135 sshlog.warn("Warning: ssh transport cannot use %r authentication:", auth) 

1136 sshlog.warn(" %s", e) 

1137 return False 

1138 else: 

1139 client_salt = get_salt(len(salt)) 

1140 combined_salt = gendigest("xor", client_salt, salt) 

1141 xored_password = gendigest("xor", password, combined_salt) 

1142 r = auth.authenticate(xored_password, client_salt) 

1143 sshlog("%s.authenticate(..)=%s", auth, r) 

1144 if not r: 

1145 return False 

1146 return True 

1147 return make_ssh_server_connection(conn, socket_options, none_auth=none_auth, password_auth=ssh_password_authenticate) 

1148 

1149 def try_upgrade_to_rfb(self, proto): 

1150 self.cancel_upgrade_to_rfb_timer(proto) 

1151 if proto.is_closed(): 

1152 return False 

1153 conn = proto._conn 

1154 netlog("may_upgrade_to_rfb() input_bytecount=%i", conn.input_bytecount) 

1155 if conn.input_bytecount==0: 

1156 proto.steal_connection() 

1157 self._potential_protocols.remove(proto) 

1158 proto.wait_for_io_threads_exit(1) 

1159 conn.set_active(True) 

1160 self.handle_rfb_connection(conn) 

1161 return False 

1162 

1163 def cancel_upgrade_to_rfb_timer(self, protocol): 

1164 t = self.socket_rfb_upgrade_timer.pop(protocol, None) 

1165 if t: 

1166 self.source_remove(t) 

1167 

1168 

1169 def make_protocol(self, socktype, conn, socket_options, protocol_class=Protocol): 

1170 """ create a new xpra Protocol instance and start it """ 

1171 def xpra_protocol_class(conn): 

1172 """ adds xpra protocol tweaks after creating the instance """ 

1173 protocol = protocol_class(self, conn, self.process_packet) 

1174 protocol.large_packets.append(b"info-response") 

1175 protocol.receive_aliases.update(self._aliases) 

1176 return protocol 

1177 return self.do_make_protocol(socktype, conn, socket_options, xpra_protocol_class) 

1178 

1179 def do_make_protocol(self, socktype, conn, socket_options, protocol_class): 

1180 """ create a new Protocol instance and start it """ 

1181 netlog("make_protocol(%s, %s, %s, %s)", socktype, conn, socket_options, protocol_class) 

1182 socktype = socktype.lower() 

1183 protocol = protocol_class(conn) 

1184 protocol.socket_type = socktype 

1185 self._potential_protocols.append(protocol) 

1186 protocol.authenticators = () 

1187 protocol.encryption = None 

1188 protocol.keyfile = None 

1189 protocol.keydata = None 

1190 if socktype in ENCRYPTED_SOCKET_TYPES: 

1191 #special case for legacy encryption code: 

1192 protocol.encryption = socket_options.get("encryption", self.tcp_encryption) 

1193 protocol.keyfile = socket_options.get("encryption-keyfile") or socket_options.get("keyfile") or self.tcp_encryption_keyfile 

1194 protocol.keydata = parse_encoded_bin_data(socket_options.get("encryption-keydata") or socket_options.get("keydata")) 

1195 netlog("%s: encryption=%s, keyfile=%s", socktype, protocol.encryption, protocol.keyfile) 

1196 if protocol.encryption: 

1197 from xpra.net.crypto import crypto_backend_init 

1198 crypto_backend_init() 

1199 from xpra.net.crypto import ( 

1200 ENCRYPT_FIRST_PACKET, 

1201 DEFAULT_IV, 

1202 DEFAULT_SALT, 

1203 DEFAULT_ITERATIONS, 

1204 INITIAL_PADDING, 

1205 ) 

1206 if ENCRYPT_FIRST_PACKET: 

1207 authlog("encryption=%s, keyfile=%s", protocol.encryption, protocol.keyfile) 

1208 password = protocol.keydata or self.get_encryption_key(None, protocol.keyfile) 

1209 protocol.set_cipher_in(protocol.encryption, 

1210 DEFAULT_IV, password, 

1211 DEFAULT_SALT, DEFAULT_ITERATIONS, INITIAL_PADDING) 

1212 else: 

1213 netlog("no encryption for %s", socktype) 

1214 protocol.invalid_header = self.invalid_header 

1215 authlog("socktype=%s, encryption=%s, keyfile=%s", socktype, protocol.encryption, protocol.keyfile) 

1216 protocol.start() 

1217 self.schedule_verify_connection_accepted(protocol, self._accept_timeout) 

1218 return protocol 

1219 

1220 def may_wrap_socket(self, conn, socktype, socket_info, socket_options, peek_data=b""): 

1221 """ 

1222 Returns: 

1223 * a flag indicating if we should continue processing this connection 

1224 * (False for webosocket and tcp proxies as they take over the socket) 

1225 * the connection object (which may now be wrapped, ie: for ssl) 

1226 * new peek data (which may now be empty), 

1227 """ 

1228 if not peek_data: 

1229 netlog("may_wrap_socket: no data, not wrapping") 

1230 return True, conn, peek_data 

1231 line1 = peek_data.split(b"\n")[0] 

1232 packet_type = guess_packet_type(peek_data) 

1233 if packet_type=="xpra": 

1234 netlog("may_wrap_socket: xpra protocol header '%s', not wrapping", peek_data[0]) 

1235 #xpra packet header, no need to wrap this connection 

1236 return True, conn, peek_data 

1237 frominfo = pretty_socket(conn.remote) 

1238 netlog("may_wrap_socket(..) peek_data=%s from %s", ellipsizer(peek_data), frominfo) 

1239 netlog("may_wrap_socket(..) packet_type=%s", packet_type) 

1240 def conn_err(msg): 

1241 self.new_conn_err(conn, conn._socket, socktype, socket_info, packet_type, msg) 

1242 return False, None, None 

1243 if packet_type=="ssh": 

1244 ssh_upgrade = socket_options.get("ssh", self.ssh_upgrade) in TRUE_OPTIONS 

1245 if not ssh_upgrade: 

1246 conn_err("ssh upgrades are not enabled") 

1247 return False, None, None 

1248 conn = self.handle_ssh_connection(conn, socket_options) 

1249 return conn is not None, conn, None 

1250 if packet_type=="ssl": 

1251 ssl_mode = socket_options.get("ssl", self.ssl_mode) 

1252 if ssl_mode in FALSE_OPTIONS: 

1253 conn_err("ssl upgrades are not enabled") 

1254 return False, None, None 

1255 sock, sockname, address, endpoint = conn._socket, conn.local, conn.remote, conn.endpoint 

1256 sock = self._ssl_wrap_socket(socktype, sock, socket_options) 

1257 if sock is None: 

1258 return False, None, None 

1259 conn = SSLSocketConnection(sock, sockname, address, endpoint, "ssl") 

1260 conn.socktype_wrapped = socktype 

1261 #we cannot peek on SSL sockets, just clear the unencrypted data: 

1262 http = False 

1263 if ssl_mode=="tcp": 

1264 http = False 

1265 elif ssl_mode=="www": 

1266 http = True 

1267 elif ssl_mode=="auto" or ssl_mode in TRUE_OPTIONS: 

1268 http = False 

1269 #use the header to guess: 

1270 if line1.find(b"HTTP/")>0 or peek_data.find(b"\x08http/1.1")>0: 

1271 http = True 

1272 else: 

1273 conn.enable_peek() 

1274 peek_data = peek_connection(conn) 

1275 line1 = peek_data.split(b"\n")[0] 

1276 http = line1.find(b"HTTP/")>0 

1277 ssllog("may_wrap_socket SSL: %s, ssl mode=%s, http=%s", conn, ssl_mode, http) 

1278 is_ssl = True 

1279 else: 

1280 http = line1.find(b"HTTP/")>0 

1281 is_ssl = False 

1282 if http: 

1283 http_protocol = "https" if is_ssl else "http" 

1284 http_upgrade = socket_options.get(http_protocol, self._html) not in FALSE_OPTIONS 

1285 if not http_upgrade: 

1286 conn_err("%s upgrades are not enabled" % http_protocol) 

1287 return False, None, None 

1288 self.start_http_socket(socktype, conn, socket_options, is_ssl, peek_data) 

1289 return False, conn, None 

1290 if self._tcp_proxy and not is_ssl: 

1291 netlog.info("New tcp proxy connection received from %s", frominfo) 

1292 t = start_thread(self.start_tcp_proxy, "tcp-proxy-for-%s" % frominfo, daemon=True, args=(conn, conn.remote)) 

1293 netlog("may_wrap_socket handling via tcp proxy thread %s", t) 

1294 return False, conn, None 

1295 return True, conn, peek_data 

1296 

1297 def invalid_header(self, proto, data, msg=""): 

1298 netlog("invalid header: input_packetcount=%s, tcp_proxy=%s, html=%s, ssl=%s", 

1299 proto.input_packetcount, self._tcp_proxy, self._html, bool(self._ssl_attributes)) 

1300 proto._invalid_header(proto, data, msg) 

1301 

1302 ###################################################################### 

1303 # http / websockets: 

1304 def get_http_scripts(self): 

1305 return { 

1306 "/Status" : self.http_status_request, 

1307 "/Info" : self.http_info_request, 

1308 } 

1309 

1310 def start_http_socket(self, socktype, conn, socket_options, is_ssl=False, peek_data=""): 

1311 frominfo = pretty_socket(conn.remote) 

1312 line1 = peek_data.split(b"\n")[0] 

1313 http_proto = "http"+["","s"][int(is_ssl)] 

1314 netlog("start_http_socket(%s, %s, %s, %s, ..) http proto=%s, line1=%r", 

1315 socktype, conn, socket_options, is_ssl, http_proto, bytestostr(line1)) 

1316 if line1.startswith(b"GET ") or line1.startswith(b"POST "): 

1317 parts = bytestostr(line1).split(" ") 

1318 httplog("New %s %s request received from %s for '%s'", http_proto, parts[0], frominfo, parts[1]) 

1319 tname = "%s-request" % parts[0] 

1320 req_info = "%s %s" % (http_proto, parts[0]) 

1321 else: 

1322 httplog("New %s connection received from %s", http_proto, frominfo) 

1323 req_info = "ws"+["","s"][int(is_ssl)] 

1324 tname = "%s-proxy" % req_info 

1325 #we start a new thread, 

1326 #only so that the websocket handler thread is named correctly: 

1327 start_thread(self.start_http, "%s-for-%s" % (tname, frominfo), 

1328 daemon=True, args=(socktype, conn, socket_options, is_ssl, req_info, line1, conn.remote)) 

1329 

1330 def start_http(self, socktype, conn, socket_options, is_ssl, req_info, line1, frominfo): 

1331 httplog("start_http(%s, %s, %s, %s, %s, %r, %s) www dir=%s, headers dir=%s", 

1332 socktype, conn, socket_options, is_ssl, req_info, line1, frominfo, 

1333 self._www_dir, self._http_headers_dirs) 

1334 try: 

1335 from xpra.net.websockets.handler import WebSocketRequestHandler 

1336 sock = conn._socket 

1337 sock.settimeout(self._ws_timeout) 

1338 def new_websocket_client(wsh): 

1339 from xpra.net.websockets.protocol import WebSocketProtocol 

1340 wslog("new_websocket_client(%s) socket=%s", wsh, sock) 

1341 newsocktype = "ws%s" % ["","s"][int(is_ssl)] 

1342 self.make_protocol(newsocktype, conn, socket_options, WebSocketProtocol) 

1343 scripts = self.get_http_scripts() 

1344 conn.socktype = "wss" if is_ssl else "ws" 

1345 WebSocketRequestHandler(sock, frominfo, new_websocket_client, 

1346 self._www_dir, self._http_headers_dirs, scripts) 

1347 return 

1348 except (IOError, ValueError) as e: 

1349 httplog("start_http%s", (socktype, conn, is_ssl, req_info, frominfo), exc_info=True) 

1350 err = e.args[0] 

1351 if err==1 and line1 and line1[0]==0x16: 

1352 l = httplog 

1353 elif err in (errno.EPIPE, errno.ECONNRESET): 

1354 l = httplog 

1355 else: 

1356 l = httplog.error 

1357 l("Error: %s request failure", req_info) 

1358 l(" errno=%s", err) 

1359 l(" for client %s:", pretty_socket(frominfo)) 

1360 if line1 and line1[0]>=128 or line1[0]==0x16: 

1361 l(" request as hex: '%s'", hexstr(line1)) 

1362 else: 

1363 l(" request: %r", bytestostr(line1)) 

1364 l(" %s", e) 

1365 except Exception as e: 

1366 wslog.error("Error: %s request failure for client %s:", req_info, pretty_socket(frominfo), exc_info=True) 

1367 try: 

1368 conn.close() 

1369 except Exception as ce: 

1370 wslog("error closing connection following error: %s", ce) 

1371 

1372 def http_info_request(self, handler): 

1373 import json 

1374 ji = json.dumps(self.get_http_info()) 

1375 return self.send_http_response(handler, ji, "application/json") 

1376 

1377 def get_http_info(self) -> dict: 

1378 return { 

1379 "mode" : self.get_server_mode(), 

1380 "type" : "Python", 

1381 "uuid" : self.uuid, 

1382 } 

1383 

1384 def http_status_request(self, handler): 

1385 return self.send_http_response(handler, "ready") 

1386 

1387 def send_http_response(self, handler, content, content_type="text/plain"): 

1388 handler.send_response(200) 

1389 headers = { 

1390 "Content-type" : content_type, 

1391 "Content-Length" : len(content), 

1392 } 

1393 for k,v in headers.items(): 

1394 handler.send_header(k, v) 

1395 handler.end_headers() 

1396 return content 

1397 

1398 

1399 def start_tcp_proxy(self, conn, frominfo): 

1400 proxylog("start_tcp_proxy(%s, %s)", conn, frominfo) 

1401 #connect to web server: 

1402 try: 

1403 host, port = self._tcp_proxy.split(":", 1) 

1404 port = int(port) 

1405 except ValueError as e: 

1406 proxylog.error("Error: invalid tcp proxy value '%s'", self._tcp_proxy) 

1407 proxylog.error(" %s", e) 

1408 conn.close() 

1409 return 

1410 try: 

1411 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 

1412 sock.settimeout(10) 

1413 sock.connect((host, int(port))) 

1414 sock.settimeout(None) 

1415 tcp_server_connection = SocketConnection(sock, sock.getsockname(), sock.getpeername(), 

1416 "tcp-proxy-for-%s" % frominfo, "tcp") 

1417 except Exception as e: 

1418 proxylog("start_tcp_proxy(%s, %s)", conn, frominfo, exc_info=True) 

1419 proxylog.error("Error: failed to connect to TCP proxy endpoint: %s:%s", host, port) 

1420 proxylog.error(" %s", e) 

1421 conn.close() 

1422 return 

1423 proxylog("proxy connected to tcp server at %s:%s : %s", host, port, tcp_server_connection) 

1424 sock.settimeout(self._socket_timeout) 

1425 

1426 #we can use blocking sockets for the client: 

1427 conn.settimeout(None) 

1428 #but not for the server, which could deadlock on exit: 

1429 sock.settimeout(1) 

1430 

1431 #now start forwarding: 

1432 from xpra.scripts.fdproxy import XpraProxy 

1433 p = XpraProxy(frominfo, conn, tcp_server_connection, self.tcp_proxy_quit) 

1434 self._tcp_proxy_clients.append(p) 

1435 proxylog.info("client connection from %s forwarded to proxy server on %s:%s", frominfo, host, port) 

1436 p.start_threads() 

1437 

1438 

1439 def tcp_proxy_quit(self, proxy): 

1440 proxylog("tcp_proxy_quit(%s)", proxy) 

1441 if proxy in self._tcp_proxy_clients: 

1442 self._tcp_proxy_clients.remove(proxy) 

1443 

1444 def is_timedout(self, protocol): 

1445 #subclasses may override this method (ServerBase does) 

1446 v = not protocol.is_closed() and protocol in self._potential_protocols and \ 

1447 protocol not in self._tcp_proxy_clients 

1448 netlog("is_timedout(%s)=%s", protocol, v) 

1449 return v 

1450 

1451 def schedule_verify_connection_accepted(self, protocol, timeout=60): 

1452 t = self.timeout_add(timeout*1000, self.verify_connection_accepted, protocol) 

1453 self.socket_verify_timer[protocol] = t 

1454 

1455 def verify_connection_accepted(self, protocol): 

1456 self.cancel_verify_connection_accepted(protocol) 

1457 if self.is_timedout(protocol): 

1458 conn = getattr(protocol, "_conn", None) 

1459 log.error("Error: connection timed out: %s", conn or protocol) 

1460 elapsed = monotonic_time()-protocol.start_time 

1461 log.error(" after %i seconds", elapsed) 

1462 if conn: 

1463 log.error(" received %i bytes", conn.input_bytecount) 

1464 if conn.input_bytecount==0: 

1465 try: 

1466 data = conn.peek(200) 

1467 except Exception: 

1468 data = b"" 

1469 if data: 

1470 log.error(" read buffer=%r", data) 

1471 packet_type = guess_packet_type(data) 

1472 if packet_type: 

1473 log.error(" looks like '%s' ", packet_type) 

1474 self.send_disconnect(protocol, LOGIN_TIMEOUT) 

1475 

1476 def cancel_verify_connection_accepted(self, protocol): 

1477 t = self.socket_verify_timer.pop(protocol, None) 

1478 if t: 

1479 self.source_remove(t) 

1480 

1481 def send_disconnect(self, proto, *reasons): 

1482 netlog("send_disconnect(%s, %s)", proto, reasons) 

1483 self.cancel_verify_connection_accepted(proto) 

1484 self.cancel_upgrade_to_rfb_timer(proto) 

1485 if proto.is_closed(): 

1486 return 

1487 proto.send_disconnect(reasons) 

1488 self.timeout_add(1000, self.force_disconnect, proto) 

1489 

1490 def force_disconnect(self, proto): 

1491 netlog("force_disconnect(%s)", proto) 

1492 self.cleanup_protocol(proto) 

1493 self.cancel_verify_connection_accepted(proto) 

1494 self.cancel_upgrade_to_rfb_timer(proto) 

1495 proto.close() 

1496 

1497 def disconnect_client(self, protocol, reason, *extra): 

1498 netlog("disconnect_client(%s, %s, %s)", protocol, reason, extra) 

1499 if protocol and not protocol.is_closed(): 

1500 self.disconnect_protocol(protocol, reason, *extra) 

1501 

1502 def disconnect_protocol(self, protocol, *reasons): 

1503 netlog("disconnect_protocol(%s, %s)", protocol, reasons) 

1504 i = str(reasons[0]) 

1505 if len(reasons)>1: 

1506 i += " (%s)" % csv(reasons[1:]) 

1507 proto_info = " %s" % protocol 

1508 try: 

1509 conn = protocol._conn 

1510 info = conn.get_info() 

1511 endpoint = info.get("endpoint") 

1512 if endpoint: 

1513 proto_info = " %s" % pretty_socket(endpoint) 

1514 else: 

1515 proto_info = " %s" % pretty_socket(conn.local) 

1516 except (KeyError, AttributeError): 

1517 pass 

1518 self._log_disconnect(protocol, "Disconnecting client%s:", proto_info) 

1519 self._log_disconnect(protocol, " %s", i) 

1520 self.cancel_verify_connection_accepted(protocol) 

1521 self.cancel_upgrade_to_rfb_timer(protocol) 

1522 protocol.send_disconnect(reasons) 

1523 self.cleanup_protocol(protocol) 

1524 

1525 def cleanup_protocol(self, proto): 

1526 pass 

1527 

1528 def _process_disconnect(self, proto, packet): 

1529 info = bytestostr(packet[1]) 

1530 if len(packet)>2: 

1531 info += " (%s)" % csv(bytestostr(x) for x in packet[2:]) 

1532 #only log protocol info if there is more than one client: 

1533 proto_info = self._disconnect_proto_info(proto) 

1534 self._log_disconnect(proto, "client%s has requested disconnection: %s", proto_info, info) 

1535 self.disconnect_protocol(proto, CLIENT_REQUEST) 

1536 

1537 def _log_disconnect(self, _proto, *args): 

1538 netlog.info(*args) 

1539 

1540 def _disconnect_proto_info(self, _proto): 

1541 #overriden in server_base in case there is more than one protocol 

1542 return "" 

1543 

1544 def _process_connection_lost(self, proto, packet): 

1545 netlog("process_connection_lost(%s, %s)", proto, packet) 

1546 self.cancel_verify_connection_accepted(proto) 

1547 self.cancel_upgrade_to_rfb_timer(proto) 

1548 if proto in self._potential_protocols: 

1549 if not proto.is_closed(): 

1550 self._log_disconnect(proto, "Connection lost") 

1551 self._potential_protocols.remove(proto) 

1552 #remove from UDP protocol map: 

1553 uuid = getattr(proto, "uuid", None) 

1554 if uuid: 

1555 self._udp_protocols.pop(uuid, None) 

1556 self.cleanup_protocol(proto) 

1557 

1558 def _process_gibberish(self, proto, packet): 

1559 message, data = packet[1:3] 

1560 netlog("Received uninterpretable nonsense from %s: %s", proto, message) 

1561 netlog(" data: %s", ellipsizer(data)) 

1562 self.disconnect_client(proto, message) 

1563 

1564 def _process_invalid(self, protocol, packet): 

1565 message, data = packet[1:3] 

1566 netlog("Received invalid packet: %s", message) 

1567 netlog(" data: %s", ellipsizer(data)) 

1568 self.disconnect_client(protocol, message) 

1569 

1570 

1571 ###################################################################### 

1572 # hello / authentication: 

1573 def send_version_info(self, proto, full=False): 

1574 version = XPRA_VERSION 

1575 if full: 

1576 version = full_version_str() 

1577 proto.send_now(("hello", {"version" : version})) 

1578 #client is meant to close the connection itself, but just in case: 

1579 self.timeout_add(5*1000, self.send_disconnect, proto, DONE, "version sent") 

1580 

1581 def _process_hello(self, proto, packet): 

1582 capabilities = packet[1] 

1583 c = typedict(capabilities) 

1584 proto.set_compression_level(c.intget("compression_level", self.compression_level)) 

1585 proto.enable_compressor_from_caps(c) 

1586 if not proto.enable_encoder_from_caps(c): 

1587 #this should never happen: 

1588 #if we got here, we parsed a packet from the client! 

1589 #(maybe the client used an encoding it claims not to support?) 

1590 self.disconnect_client(proto, PROTOCOL_ERROR, "failed to negotiate a packet encoder") 

1591 return 

1592 

1593 log("process_hello: capabilities=%s", capabilities) 

1594 if c.boolget("version_request"): 

1595 self.send_version_info(proto, c.boolget("full-version-request")) 

1596 return 

1597 #verify version: 

1598 remote_version = c.strget("version") 

1599 verr = version_compat_check(remote_version) 

1600 if verr is not None: 

1601 self.disconnect_client(proto, VERSION_ERROR, "incompatible version: %s" % verr) 

1602 proto.close() 

1603 return 

1604 #this will call auth_verified if successful 

1605 #it may also just send challenge packets, 

1606 #in which case we'll end up here parsing the hello again 

1607 start_thread(self.verify_auth, "authenticate connection", daemon=True, args=(proto, packet, c)) 

1608 

1609 def make_authenticators(self, socktype, username, conn): 

1610 authlog("make_authenticators%s socket options=%s", (socktype, username, conn), conn.options) 

1611 sock_auth = conn.options.get("auth", "") 

1612 if sock_auth: 

1613 #per socket authentication option: 

1614 #ie: --bind-tcp=0.0.0.0:10000,auth=hosts,auth=file:filename=pass.txt:foo=bar 

1615 # -> sock_auth = ["hosts", "file:filename=pass.txt:foo=bar"] 

1616 if not isinstance(sock_auth, list): 

1617 sock_auth = sock_auth.split(",") 

1618 auth_classes = self.get_auth_modules(conn.socktype, sock_auth) 

1619 else: 

1620 #use authentication configuration defined for all sockets of this type: 

1621 auth_classes = self.auth_classes[socktype] 

1622 i = 0 

1623 authenticators = [] 

1624 if auth_classes: 

1625 authlog("creating authenticators %s for %s, with username=%s, connection=%s", 

1626 csv(auth_classes), socktype, username, conn) 

1627 for auth, _, aclass, options in auth_classes: 

1628 opts = dict(options) 

1629 opts["connection"] = conn 

1630 authenticator = aclass(username, **opts) 

1631 authlog("authenticator %i: %s(%s, %s)=%s", i, auth, username, opts, authenticator) 

1632 authenticators.append(authenticator) 

1633 i += 1 

1634 return tuple(authenticators) 

1635 

1636 def send_challenge(self, proto, salt, auth_caps, digest, salt_digest, prompt="password"): 

1637 proto.send_now(("challenge", salt, auth_caps or "", digest, salt_digest, prompt)) 

1638 self.schedule_verify_connection_accepted(proto, CHALLENGE_TIMEOUT) 

1639 

1640 def verify_auth(self, proto, packet, c): 

1641 def auth_failed(msg): 

1642 authlog.warn("Warning: authentication failed") 

1643 authlog.warn(" %s", msg) 

1644 self.timeout_add(1000, self.disconnect_client, proto, msg) 

1645 

1646 username = c.strget("username") 

1647 if not username: 

1648 import getpass 

1649 username = getpass.getuser() 

1650 conn = proto._conn 

1651 #authenticator: 

1652 if not proto.authenticators: 

1653 socktype = conn.socktype_wrapped 

1654 try: 

1655 proto.authenticators = self.make_authenticators(socktype, username, conn) 

1656 except Exception as e: 

1657 authlog("instantiating authenticator for %s", socktype, exc_info=True) 

1658 authlog.error("Error instantiating authenticator for %s:", proto.socket_type) 

1659 authlog.error(" %s", e) 

1660 auth_failed(str(e)) 

1661 return 

1662 

1663 digest_modes = c.strtupleget("digest", ("hmac", )) 

1664 salt_digest_modes = c.strtupleget("salt-digest", ("xor",)) 

1665 #client may have requested encryption: 

1666 cipher = c.strget("cipher") 

1667 cipher_iv = c.strget("cipher.iv") 

1668 key_salt = c.strget("cipher.key_salt") 

1669 auth_caps = {} 

1670 if cipher and cipher_iv: 

1671 from xpra.net.crypto import DEFAULT_PADDING, ALL_PADDING_OPTIONS, ENCRYPTION_CIPHERS, new_cipher_caps 

1672 iterations = c.intget("cipher.key_stretch_iterations") 

1673 padding = c.strget("cipher.padding", DEFAULT_PADDING) 

1674 padding_options = c.strtupleget("cipher.padding.options", (DEFAULT_PADDING,)) 

1675 if cipher not in ENCRYPTION_CIPHERS: 

1676 authlog.warn("Warning: unsupported cipher: %s", cipher) 

1677 if ENCRYPTION_CIPHERS: 

1678 authlog.warn(" should be: %s", csv(ENCRYPTION_CIPHERS)) 

1679 auth_failed("unsupported cipher") 

1680 return 

1681 encryption_key = proto.keydata or self.get_encryption_key(proto.authenticators, proto.keyfile) 

1682 if encryption_key is None: 

1683 auth_failed("encryption key is missing") 

1684 return 

1685 if padding not in ALL_PADDING_OPTIONS: 

1686 auth_failed("unsupported padding: %s" % padding) 

1687 return 

1688 authlog("set output cipher using encryption key '%s'", ellipsizer(encryption_key)) 

1689 proto.set_cipher_out(cipher, cipher_iv, encryption_key, key_salt, iterations, padding) 

1690 #use the same cipher as used by the client: 

1691 auth_caps = new_cipher_caps(proto, cipher, encryption_key, padding_options) 

1692 authlog("server cipher=%s", auth_caps) 

1693 else: 

1694 if proto.encryption and conn.socktype in ENCRYPTED_SOCKET_TYPES: 

1695 authlog("client does not provide encryption tokens") 

1696 auth_failed("missing encryption tokens") 

1697 return 

1698 auth_caps = None 

1699 

1700 def send_fake_challenge(): 

1701 #fake challenge so the client will send the real hello: 

1702 salt = get_salt() 

1703 digest = choose_digest(digest_modes) 

1704 salt_digest = choose_digest(salt_digest_modes) 

1705 self.send_challenge(proto, salt, auth_caps, digest, salt_digest) 

1706 

1707 #skip the authentication module we have "passed" already: 

1708 remaining_authenticators = tuple(x for x in proto.authenticators if not x.passed) 

1709 

1710 client_expects_challenge = c.strget("challenge") is not None 

1711 if client_expects_challenge and not remaining_authenticators: 

1712 authlog.warn("Warning: client expects an authentication challenge,") 

1713 authlog.warn(" sending a fake one") 

1714 send_fake_challenge() 

1715 return 

1716 

1717 authlog("processing authentication with %s, remaining=%s, digest_modes=%s, salt_digest_modes=%s", 

1718 proto.authenticators, remaining_authenticators, digest_modes, salt_digest_modes) 

1719 #verify each remaining authenticator: 

1720 for index, authenticator in enumerate(proto.authenticators): 

1721 if authenticator not in remaining_authenticators: 

1722 authlog("authenticator[%i]=%s (already passed)", index, authenticator) 

1723 continue 

1724 req = authenticator.requires_challenge() 

1725 authlog("authenticator[%i]=%s, requires-challenge=%s, challenge-sent=%s", 

1726 index, authenticator, req, authenticator.challenge_sent) 

1727 if not req: 

1728 #this authentication module does not need a challenge 

1729 #(ie: "peercred" or "none") 

1730 if not authenticator.authenticate(c): 

1731 auth_failed("%s authentication failed" % authenticator) 

1732 return 

1733 authenticator.passed = True 

1734 authlog("authentication passed for %s (no challenge provided)", authenticator) 

1735 continue 

1736 if not authenticator.challenge_sent: 

1737 #we'll re-schedule this when we call send_challenge() 

1738 #as the authentication module is free to take its time 

1739 self.cancel_verify_connection_accepted(proto) 

1740 #note: we may have received a challenge_response from a previous auth module's challenge 

1741 challenge = authenticator.get_challenge(digest_modes) 

1742 if challenge is None: 

1743 if authenticator.requires_challenge(): 

1744 auth_failed("invalid state, unexpected challenge response") 

1745 return 

1746 authlog.warn("Warning: authentication module '%s' does not require any credentials", authenticator) 

1747 authlog.warn(" but the client %s supplied them", proto) 

1748 #fake challenge so the client will send the real hello: 

1749 send_fake_challenge() 

1750 return 

1751 salt, digest = challenge 

1752 actual_digest = digest.split(":", 1)[0] 

1753 authlog("get_challenge(%s)= %s, %s", digest_modes, hexstr(salt), digest) 

1754 authlog.info("Authentication required by %s authenticator module %i", authenticator, (index+1)) 

1755 authlog.info(" sending challenge for username '%s' using %s digest", username, actual_digest) 

1756 if actual_digest not in digest_modes: 

1757 auth_failed("cannot proceed without %s digest support" % actual_digest) 

1758 return 

1759 salt_digest = authenticator.choose_salt_digest(salt_digest_modes) 

1760 if salt_digest in ("xor", "des"): 

1761 if not LEGACY_SALT_DIGEST: 

1762 auth_failed("insecure salt digest '%s' rejected" % salt_digest) 

1763 return 

1764 log.warn("Warning: using legacy support for '%s' salt digest", salt_digest) 

1765 self.send_challenge(proto, salt, auth_caps, digest, salt_digest, authenticator.prompt) 

1766 return 

1767 if not authenticator.authenticate(c): 

1768 auth_failed("authentication failed") 

1769 return 

1770 authlog("all authentication modules passed") 

1771 self.auth_verified(proto, packet, auth_caps) 

1772 

1773 def auth_verified(self, proto, packet, auth_caps): 

1774 capabilities = packet[1] 

1775 c = typedict(capabilities) 

1776 command_req = c.strtupleget("command_request") 

1777 if command_req: 

1778 #call from UI thread: 

1779 authlog("auth_verified(..) command request=%s", command_req) 

1780 self.idle_add(self.handle_command_request, proto, *command_req) 

1781 return 

1782 #continue processing hello packet in UI thread: 

1783 self.idle_add(self.call_hello_oked, proto, packet, c, auth_caps) 

1784 

1785 

1786 def get_encryption_key(self, authenticators=None, keyfile=None): 

1787 #if we have a keyfile specified, use that: 

1788 authlog("get_encryption_key(%s, %s)", authenticators, keyfile) 

1789 if keyfile: 

1790 authlog("loading encryption key from keyfile: %s", keyfile) 

1791 v = filedata_nocrlf(keyfile) 

1792 if v: 

1793 return v 

1794 v = os.environ.get('XPRA_ENCRYPTION_KEY') 

1795 if v: 

1796 authlog("using encryption key from %s environment variable", 'XPRA_ENCRYPTION_KEY') 

1797 return v 

1798 if authenticators: 

1799 for authenticator in authenticators: 

1800 v = authenticator.get_password() 

1801 if v: 

1802 authlog("using password from authenticator %s", authenticator) 

1803 return v 

1804 return None 

1805 

1806 def call_hello_oked(self, proto, packet, c, auth_caps): 

1807 try: 

1808 if SIMULATE_SERVER_HELLO_ERROR: 

1809 raise Exception("Simulating a server error") 

1810 self.hello_oked(proto, packet, c, auth_caps) 

1811 except ClientException as e: 

1812 log("call_hello_oked(%s, %s, %s, %s)", proto, packet, ellipsizer(c), auth_caps, exc_info=True) 

1813 log.error("Error setting up new connection for") 

1814 log.error(" %s:", proto) 

1815 log.error(" %s", e) 

1816 self.disconnect_client(proto, SERVER_ERROR, str(e)) 

1817 except Exception as e: 

1818 #log exception but don't disclose internal details to the client 

1819 log.error("server error processing new connection from %s: %s", proto, e, exc_info=True) 

1820 self.disconnect_client(proto, SERVER_ERROR, "error accepting new connection") 

1821 

1822 def hello_oked(self, proto, _packet, c, _auth_caps): 

1823 proto.accept() 

1824 generic_request = c.strget("request") 

1825 def is_req(mode): 

1826 return generic_request==mode or c.boolget("%s_request" % mode) 

1827 if is_req("connect_test"): 

1828 ctr = c.strget("connect_test_request") 

1829 response = {"connect_test_response" : ctr} 

1830 proto.send_now(("hello", response)) 

1831 return True 

1832 if is_req("id"): 

1833 self.send_id_info(proto) 

1834 return True 

1835 if is_req("info"): 

1836 self.send_hello_info(proto) 

1837 return True 

1838 if self._closing: 

1839 self.disconnect_client(proto, SERVER_EXIT, "server is shutting down") 

1840 return True 

1841 return False 

1842 

1843 

1844 def accept_client(self, proto, c): 

1845 #max packet size from client (the biggest we can get are clipboard packets) 

1846 netlog("accept_client(%s, %s)", proto, c) 

1847 #note: when uploading files, we send them in chunks smaller than this size 

1848 proto.max_packet_size = MAX_PACKET_SIZE 

1849 proto.parse_remote_caps(c) 

1850 self.accept_protocol(proto) 

1851 

1852 def accept_protocol(self, proto): 

1853 if proto in self._potential_protocols: 

1854 self._potential_protocols.remove(proto) 

1855 self.reset_server_timeout(False) 

1856 self.cancel_verify_connection_accepted(proto) 

1857 self.cancel_upgrade_to_rfb_timer(proto) 

1858 

1859 def reset_server_timeout(self, reschedule=True): 

1860 timeoutlog("reset_server_timeout(%s) server_idle_timeout=%s, server_idle_timer=%s", 

1861 reschedule, self.server_idle_timeout, self.server_idle_timer) 

1862 if self.server_idle_timeout<=0: 

1863 return 

1864 if self.server_idle_timer: 

1865 self.source_remove(self.server_idle_timer) 

1866 self.server_idle_timer = None 

1867 if reschedule: 

1868 self.server_idle_timer = self.timeout_add(self.server_idle_timeout*1000, self.server_idle_timedout) 

1869 

1870 def server_idle_timedout(self): 

1871 timeoutlog.info("No valid client connections for %s seconds, exiting the server", self.server_idle_timeout) 

1872 self.clean_quit(False) 

1873 

1874 

1875 def make_hello(self, source=None): 

1876 now = time() 

1877 capabilities = flatten_dict(get_network_caps()) 

1878 if source is None or source.wants_versions: 

1879 capabilities.update(flatten_dict(get_server_info())) 

1880 capabilities.update({ 

1881 "version" : XPRA_VERSION, 

1882 "start_time" : int(self.start_time), 

1883 "current_time" : int(now), 

1884 "elapsed_time" : int(now - self.start_time), 

1885 "server_type" : "core", 

1886 "server.mode" : self.get_server_mode(), 

1887 "hostname" : socket.gethostname(), 

1888 }) 

1889 if source is None or source.wants_features: 

1890 capabilities.update({ 

1891 "readonly-server" : True, 

1892 "readonly" : self.readonly, 

1893 "server-log" : os.environ.get("XPRA_SERVER_LOG", ""), 

1894 }) 

1895 if source is None or source.wants_versions: 

1896 capabilities["uuid"] = get_user_uuid() 

1897 mid = get_machine_id() 

1898 if mid: 

1899 capabilities["machine_id"] = mid 

1900 if self.session_name: 

1901 capabilities["session_name"] = self.session_name.encode("utf-8") 

1902 return capabilities 

1903 

1904 

1905 ###################################################################### 

1906 # info: 

1907 def send_id_info(self, proto): 

1908 log("id info request from %s", proto._conn) 

1909 proto.send_now(("hello", self.get_session_id_info())) 

1910 

1911 def get_session_id_info(self) -> dict: 

1912 #minimal information for identifying the session 

1913 id_info = { 

1914 "session-type" : self.session_type, 

1915 "session-name" : self.session_name, 

1916 "uuid" : self.uuid, 

1917 "platform" : sys.platform, 

1918 "pid" : os.getpid(), 

1919 "machine-id" : get_machine_id(), 

1920 } 

1921 display = os.environ.get("DISPLAY") 

1922 if display: 

1923 id_info["display"] = display 

1924 return id_info 

1925 

1926 def send_hello_info(self, proto): 

1927 #Note: this can be overriden in subclasses to pass arguments to get_ui_info() 

1928 #(ie: see server_base) 

1929 log.info("processing info request from %s", proto._conn) 

1930 def cb(proto, info): 

1931 self.do_send_info(proto, info) 

1932 self.get_all_info(cb, proto) 

1933 

1934 def do_send_info(self, proto, info): 

1935 proto.send_now(("hello", notypedict(info))) 

1936 

1937 def get_all_info(self, callback, proto=None, *args): 

1938 start = monotonic_time() 

1939 ui_info = self.get_ui_info(proto, *args) 

1940 end = monotonic_time() 

1941 log("get_all_info: ui info collected in %ims", (end-start)*1000) 

1942 start_thread(self._get_info_in_thread, "Info", daemon=True, args=(callback, ui_info, proto, args)) 

1943 

1944 def _get_info_in_thread(self, callback, ui_info, proto, args): 

1945 log("get_info_in_thread%s", (callback, {}, proto, args)) 

1946 start = monotonic_time() 

1947 #this runs in a non-UI thread 

1948 try: 

1949 info = self.get_info(proto, *args) 

1950 merge_dicts(ui_info, info) 

1951 except Exception: 

1952 log.error("Error during info collection using %s", self.get_info, exc_info=True) 

1953 end = monotonic_time() 

1954 log("get_all_info: non ui info collected in %ims", (end-start)*1000) 

1955 callback(proto, ui_info) 

1956 

1957 def get_ui_info(self, _proto, *_args) -> dict: 

1958 #this function is for info which MUST be collected from the UI thread 

1959 return {} 

1960 

1961 def get_thread_info(self, proto) -> dict: 

1962 return get_thread_info(proto) 

1963 

1964 def get_minimal_server_info(self) -> dict: 

1965 now = time() 

1966 info = { 

1967 "mode" : self.get_server_mode(), 

1968 "session-type" : self.session_type, 

1969 "type" : "Python", 

1970 "python" : {"version" : platform.python_version()}, 

1971 "start_time" : int(self.start_time), 

1972 "current_time" : int(now), 

1973 "elapsed_time" : int(now - self.start_time), 

1974 "uuid" : self.uuid, 

1975 "machine-id" : get_machine_id(), 

1976 } 

1977 return info 

1978 

1979 def get_server_info(self) -> dict: 

1980 #this function is for non UI thread info 

1981 si = {} 

1982 si.update(self.get_minimal_server_info()) 

1983 si.update(get_server_info()) 

1984 si.update({ 

1985 "argv" : sys.argv, 

1986 "path" : sys.path, 

1987 "exec_prefix" : sys.exec_prefix, 

1988 "executable" : sys.executable, 

1989 "idle-timeout" : int(self.server_idle_timeout), 

1990 }) 

1991 if self.pidfile: 

1992 si["pidfile"] = { 

1993 "path" : self.pidfile, 

1994 "inode" : self.pidinode, 

1995 } 

1996 logfile = os.environ.get("XPRA_SERVER_LOG") 

1997 if logfile: 

1998 si["log-file"] = logfile 

1999 if POSIX: 

2000 si["load"] = tuple(int(x*1000) for x in os.getloadavg()) 

2001 if self.original_desktop_display: 

2002 si["original-desktop-display"] = self.original_desktop_display 

2003 return si 

2004 

2005 def get_info(self, proto, *_args): 

2006 start = monotonic_time() 

2007 #this function is for non UI thread info 

2008 info = {} 

2009 def up(prefix, d): 

2010 info[prefix] = d 

2011 

2012 si = self.get_server_info() 

2013 if SYSCONFIG: 

2014 si["sysconfig"] = get_sysconfig_info() 

2015 up("server", si) 

2016 

2017 ni = get_net_info() 

2018 ni.update({ 

2019 "sockets" : self.get_socket_info(), 

2020 "encryption" : self.encryption or "", 

2021 "tcp-encryption" : self.tcp_encryption or "", 

2022 "bandwidth-limit": self.bandwidth_limit or 0, 

2023 "packet-handlers" : self.get_packet_handlers_info(), 

2024 "www" : { 

2025 "" : self._html, 

2026 "dir" : self._www_dir or "", 

2027 "http-headers-dirs" : self._http_headers_dirs or "", 

2028 }, 

2029 "mdns" : self.mdns, 

2030 }) 

2031 up("network", ni) 

2032 up("threads", self.get_thread_info(proto)) 

2033 from xpra.platform.info import get_sys_info 

2034 up("sys", get_sys_info()) 

2035 up("env", get_info_env()) 

2036 if self.session_name: 

2037 info["session"] = {"name" : self.session_name} 

2038 if self.child_reaper: 

2039 info.update(self.child_reaper.get_info()) 

2040 end = monotonic_time() 

2041 log("ServerCore.get_info took %ims", (end-start)*1000) 

2042 return info 

2043 

2044 def get_packet_handlers_info(self) -> dict: 

2045 return { 

2046 "default" : sorted(self._default_packet_handlers.keys()), 

2047 } 

2048 

2049 def get_socket_info(self) -> dict: 

2050 si = {} 

2051 def add_listener(socktype, info): 

2052 si.setdefault(socktype, {}).setdefault("listeners", []).append(info) 

2053 def add_address(socktype, address, port): 

2054 addresses = si.setdefault(socktype, {}).setdefault("addresses", []) 

2055 if (address, port) not in addresses: 

2056 addresses.append((address, port)) 

2057 if socktype=="tcp": 

2058 if self._html: 

2059 add_address("ws", address, port) 

2060 if self._ssl_attributes: 

2061 add_address("ssl", address, port) 

2062 if self.ssh_upgrade: 

2063 add_address("ssh", address, port) 

2064 if socktype=="ws": 

2065 if self._ssl_attributes: 

2066 add_address("wss", address, port) 

2067 netifaces = import_netifaces() 

2068 for sock_details, options in self._socket_info.items(): 

2069 socktype, _, info, _ = sock_details 

2070 if not info: 

2071 continue 

2072 add_listener(socktype, info) 

2073 if not SHOW_NETWORK_ADDRESSES: 

2074 continue 

2075 if socktype not in ("tcp", "ssl", "ws", "wss", "ssh", "udp"): 

2076 #we expose addresses only for TCP and UDP sockets 

2077 continue 

2078 upnp_address = options.get("upnp-address") 

2079 if upnp_address: 

2080 add_address(socktype, *upnp_address) 

2081 if len(info)!=2 or not isinstance(info[0], str) or not isinstance(info[1], int): 

2082 #unsupported listener info format 

2083 continue 

2084 address, port = info 

2085 if address not in ("0.0.0.0", "::/0", "::"): 

2086 #not a wildcard address, use it as-is: 

2087 add_address(socktype, address, port) 

2088 continue 

2089 if not netifaces: 

2090 if first_time("netifaces-socket-address"): 

2091 netlog.warn("Warning: netifaces is missing") 

2092 netlog.warn(" socket addresses cannot be queried") 

2093 continue 

2094 ips = [] 

2095 for inet in get_interfaces_addresses().values(): 

2096 #ie: inet = { 

2097 # 18: [{'addr': ''}], 

2098 # 2: [{'peer': '127.0.0.1', 'netmask': '255.0.0.0', 'addr': '127.0.0.1'}], 

2099 # 30: [{'peer': '::1', 'netmask': 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', 'addr': '::1'}, 

2100 # {'peer': '', 'netmask': 'ffff:ffff:ffff:ffff::', 'addr': 'fe80::1%lo0'}] 

2101 # } 

2102 for v in (socket.AF_INET, socket.AF_INET6): 

2103 addresses = inet.get(v, ()) 

2104 for addr in addresses: 

2105 #ie: addr = {'peer': '127.0.0.1', 'netmask': '255.0.0.0', 'addr': '127.0.0.1'}] 

2106 ip = addr.get("addr") 

2107 if ip and ip not in ips: 

2108 ips.append(ip) 

2109 for ip in ips: 

2110 add_address(socktype, ip, port) 

2111 

2112 for socktype, auth_classes in self.auth_classes.items(): 

2113 if auth_classes: 

2114 authenticators = si.setdefault(socktype, {}).setdefault("authenticator", {}) 

2115 for i, auth_class in enumerate(auth_classes): 

2116 authenticators[i] = auth_class[0], auth_class[3] 

2117 return si 

2118 

2119 

2120 ###################################################################### 

2121 # packet handling: 

2122 def process_packet(self, proto, packet): 

2123 packet_type = None 

2124 handler = None 

2125 try: 

2126 packet_type = bytestostr(packet[0]) 

2127 may_log_packet(False, packet_type, packet) 

2128 handler = self._default_packet_handlers.get(packet_type) 

2129 if handler: 

2130 netlog("process packet %s", packet_type) 

2131 handler(proto, packet) 

2132 return 

2133 if not self._closing: 

2134 netlog("invalid packet: %s", packet) 

2135 netlog.error("unknown or invalid packet type: '%s' from %s", packet_type, proto) 

2136 proto.close() 

2137 except KeyboardInterrupt: 

2138 raise 

2139 except Exception: 

2140 netlog.error("Unhandled error while processing a '%s' packet from peer using %s", 

2141 packet_type, handler, exc_info=True) 

2142 

2143 

2144 def handle_rfb_connection(self, conn): 

2145 log.error("Error: RFB protocol is not supported by this server") 

2146 conn.close() 

2147 

2148 

2149 def _process_udp_control(self, proto, packet): 

2150 proto.process_control(*packet[1:]) 

2151 

2152 def process_udp_packet(self, udp_listener, uuid, seqno, synchronous, chunk, chunks, data, bfrom, options): 

2153 #log.info("process_udp_packet%s", (udp_listener, uuid, seqno, synchronous, chunk, chunks, len(data), bfrom, options)) 

2154 protocol = self._udp_protocols.get(uuid) 

2155 if not protocol: 

2156 from xpra.net.udp_protocol import UDPServerProtocol, UDPSocketConnection 

2157 def udp_protocol_class(conn): 

2158 protocol = UDPServerProtocol(self, conn, self.process_packet) 

2159 protocol.uuid = uuid 

2160 protocol.large_packets.append(b"info-response") 

2161 protocol.receive_aliases.update(self._aliases) 

2162 return protocol 

2163 socktype = "udp" 

2164 host, port = bfrom 

2165 sock = udp_listener._socket 

2166 sockname = sock.getsockname() 

2167 conn = UDPSocketConnection(sock, sockname, (host, port), (host, port), socktype, None, options) 

2168 conn.timeout = SOCKET_TIMEOUT 

2169 protocol = self.do_make_protocol(socktype, conn, options, udp_protocol_class) 

2170 self._udp_protocols[uuid] = protocol 

2171 else: 

2172 #update remote address in case the client is roaming: 

2173 conn = protocol._conn 

2174 if conn: 

2175 conn.remote = bfrom 

2176 protocol.process_udp_data(uuid, seqno, synchronous, chunk, chunks, data, bfrom)