Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(438)

Side by Side Diff: remoting/host/linux/linux_me2me_host.py

Issue 2323153002: Add PAM session wrapper (Closed)
Patch Set: Option A: Use wrapper for boot only Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 #!/usr/bin/python 1 #!/usr/bin/python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 # Virtual Me2Me implementation. This script runs and manages the processes 6 # Virtual Me2Me implementation. This script runs and manages the processes
7 # required for a Virtual Me2Me desktop, which are: X server, X desktop 7 # required for a Virtual Me2Me desktop, which are: X server, X desktop
8 # session, and Host process. 8 # session, and Host process.
9 # This script is intended to run continuously as a background daemon 9 # This script is intended to run continuously as a background daemon
10 # process, running under an ordinary (non-root) user account. 10 # process, running under an ordinary (non-root) user account.
(...skipping 341 matching lines...) Expand 10 before | Expand all | Expand 10 after
352 352
353 @staticmethod 353 @staticmethod
354 def get_unused_display_number(): 354 def get_unused_display_number():
355 """Return a candidate display number for which there is currently no 355 """Return a candidate display number for which there is currently no
356 X Server lock file""" 356 X Server lock file"""
357 display = FIRST_X_DISPLAY_NUMBER 357 display = FIRST_X_DISPLAY_NUMBER
358 while os.path.exists(X_LOCK_FILE_TEMPLATE % display): 358 while os.path.exists(X_LOCK_FILE_TEMPLATE % display):
359 display += 1 359 display += 1
360 return display 360 return display
361 361
362 def _init_child_env(self): 362 def _init_child_env(self, keep_env):
363 # Create clean environment for new session, so it is cleanly separated from 363 if keep_env:
364 # the user's console X session. 364 self.child_env = dict(os.environ)
365 self.child_env = {} 365 else:
366 # Create clean environment for new session, so it is cleanly separated
367 # from the user's console X session.
368 self.child_env = {}
366 369
367 for key in [ 370 for key in [
368 "HOME", 371 "HOME",
369 "LANG", 372 "LANG",
370 "LOGNAME", 373 "LOGNAME",
371 "PATH", 374 "PATH",
372 "SHELL", 375 "SHELL",
373 "USER", 376 "USER",
374 "USERNAME", 377 "USERNAME",
375 LOG_FILE_ENV_VAR]: 378 LOG_FILE_ENV_VAR]:
376 if key in os.environ: 379 if key in os.environ:
377 self.child_env[key] = os.environ[key] 380 self.child_env[key] = os.environ[key]
381
382 # Initialize the environment from files that would normally be read in a
383 # PAM-authenticated session.
Jamie 2016/11/16 01:27:27 Is this comment still correct now that we are usin
rkjnsn 2016/11/18 22:46:48 The comment is correct because the relevant code i
384 for env_filename in [
385 "/etc/environment",
386 "/etc/default/locale",
387 os.path.expanduser("~/.pam_environment")]:
388 if not os.path.exists(env_filename):
389 continue
390 try:
391 with open(env_filename, "r") as env_file:
392 for line in env_file:
393 line = line.rstrip("\n")
394 # Split at the first "=", leaving any further instances in the
395 # value.
396 key_value_pair = line.split("=", 1)
397 if len(key_value_pair) == 2:
398 key, value = tuple(key_value_pair)
399 # The file stores key=value assignments, but the value may be
400 # quoted, so strip leading & trailing quotes from it.
401 value = value.strip("'\"")
402 self.child_env[key] = value
403 except IOError:
404 logging.error("Failed to read file: %s" % env_filename)
378 405
379 # Ensure that the software-rendering GL drivers are loaded by the desktop 406 # Ensure that the software-rendering GL drivers are loaded by the desktop
380 # session, instead of any hardware GL drivers installed on the system. 407 # session, instead of any hardware GL drivers installed on the system.
381 self.child_env["LD_LIBRARY_PATH"] = ( 408 library_path = (
382 "/usr/lib/%(arch)s-linux-gnu/mesa:" 409 "/usr/lib/%(arch)s-linux-gnu/mesa:"
383 "/usr/lib/%(arch)s-linux-gnu/dri:" 410 "/usr/lib/%(arch)s-linux-gnu/dri:"
384 "/usr/lib/%(arch)s-linux-gnu/gallium-pipe" % 411 "/usr/lib/%(arch)s-linux-gnu/gallium-pipe" %
385 { "arch": platform.machine() }) 412 { "arch": platform.machine() })
386 413
387 # Initialize the environment from files that would normally be read in a 414 if "LD_LIBRARY_PATH" in self.child_env:
Lambros 2016/11/17 21:19:35 Appreciate the bug-fix :) I agree this should norm
388 # PAM-authenticated session. 415 library_path += ":" + self.child_env["LD_LIBRARY_PATH"]
389 for env_filename in [ 416
390 "/etc/environment", 417 self.child_env["LD_LIBRARY_PATH"] = library_path
391 "/etc/default/locale",
392 os.path.expanduser("~/.pam_environment")]:
393 if not os.path.exists(env_filename):
394 continue
395 try:
396 with open(env_filename, "r") as env_file:
397 for line in env_file:
398 line = line.rstrip("\n")
399 # Split at the first "=", leaving any further instances in the
400 # value.
401 key_value_pair = line.split("=", 1)
402 if len(key_value_pair) == 2:
403 key, value = tuple(key_value_pair)
404 # The file stores key=value assignments, but the value may be
405 # quoted, so strip leading & trailing quotes from it.
406 value = value.strip("'\"")
407 self.child_env[key] = value
408 except IOError:
409 logging.error("Failed to read file: %s" % env_filename)
410 418
411 def _setup_pulseaudio(self): 419 def _setup_pulseaudio(self):
412 self.pulseaudio_pipe = None 420 self.pulseaudio_pipe = None
413 421
414 # pulseaudio uses UNIX sockets for communication. Length of UNIX socket 422 # pulseaudio uses UNIX sockets for communication. Length of UNIX socket
415 # name is limited to 108 characters, so audio will not work properly if 423 # name is limited to 108 characters, so audio will not work properly if
416 # the path is too long. To workaround this problem we use only first 10 424 # the path is too long. To workaround this problem we use only first 10
417 # symbols of the host hash. 425 # symbols of the host hash.
418 pulse_path = os.path.join(CONFIG_DIR, 426 pulse_path = os.path.join(CONFIG_DIR,
419 "pulseaudio#%s" % g_host_hash[0:10]) 427 "pulseaudio#%s" % g_host_hash[0:10])
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after
642 raise Exception("Unable to choose suitable X session command.") 650 raise Exception("Unable to choose suitable X session command.")
643 651
644 logging.info("Launching X session: %s" % xsession_command) 652 logging.info("Launching X session: %s" % xsession_command)
645 self.session_proc = subprocess.Popen(xsession_command, 653 self.session_proc = subprocess.Popen(xsession_command,
646 stdin=open(os.devnull, "r"), 654 stdin=open(os.devnull, "r"),
647 cwd=HOME_DIR, 655 cwd=HOME_DIR,
648 env=self.child_env) 656 env=self.child_env)
649 if not self.session_proc.pid: 657 if not self.session_proc.pid:
650 raise Exception("Could not start X session") 658 raise Exception("Could not start X session")
651 659
652 def launch_session(self, x_args): 660 def launch_session(self, keep_env, x_args):
653 self._init_child_env() 661 self._init_child_env(keep_env)
654 self._setup_pulseaudio() 662 self._setup_pulseaudio()
655 self._setup_gnubby() 663 self._setup_gnubby()
656 self._launch_x_server(x_args) 664 self._launch_x_server(x_args)
657 self._launch_x_session() 665 self._launch_x_session()
658 666
659 def launch_host(self, host_config): 667 def launch_host(self, host_config):
660 # Start remoting host 668 # Start remoting host
661 args = [HOST_BINARY_PATH, "--host-config=-"] 669 args = [HOST_BINARY_PATH, "--host-config=-"]
662 if self.pulseaudio_pipe: 670 if self.pulseaudio_pipe:
663 args.append("--audio-pipe-name=%s" % self.pulseaudio_pipe) 671 args.append("--audio-pipe-name=%s" % self.pulseaudio_pipe)
(...skipping 565 matching lines...) Expand 10 before | Expand all | Expand 10 after
1229 parser.add_option("", "--reload", dest="reload", default=False, 1237 parser.add_option("", "--reload", dest="reload", default=False,
1230 action="store_true", 1238 action="store_true",
1231 help="Signal currently running host to reload the config.") 1239 help="Signal currently running host to reload the config.")
1232 parser.add_option("", "--add-user", dest="add_user", default=False, 1240 parser.add_option("", "--add-user", dest="add_user", default=False,
1233 action="store_true", 1241 action="store_true",
1234 help="Add current user to the chrome-remote-desktop group.") 1242 help="Add current user to the chrome-remote-desktop group.")
1235 parser.add_option("", "--add-user-as-root", dest="add_user_as_root", 1243 parser.add_option("", "--add-user-as-root", dest="add_user_as_root",
1236 action="store", metavar="USER", 1244 action="store", metavar="USER",
1237 help="Adds the specified user to the chrome-remote-desktop " 1245 help="Adds the specified user to the chrome-remote-desktop "
1238 "group (must be run as root).") 1246 "group (must be run as root).")
1247 parser.add_option("", "--keep-parent-env", dest="keep_env", default=False,
rkjnsn 2016/11/15 22:52:57 Should this flag be public and documented?
Jamie 2016/11/16 01:27:27 TBH, I don't see the point of having separate publ
Lambros 2016/11/17 21:19:35 I don't think it matters either way. The help-text
1248 action="store_true",
1249 help=optparse.SUPPRESS_HELP)
1239 parser.add_option("", "--watch-resolution", dest="watch_resolution", 1250 parser.add_option("", "--watch-resolution", dest="watch_resolution",
1240 type="int", nargs=2, default=False, action="store", 1251 type="int", nargs=2, default=False, action="store",
1241 help=optparse.SUPPRESS_HELP) 1252 help=optparse.SUPPRESS_HELP)
1242 (options, args) = parser.parse_args() 1253 (options, args) = parser.parse_args()
1243 1254
1244 # Determine the filename of the host configuration and PID files. 1255 # Determine the filename of the host configuration and PID files.
1245 if not options.config: 1256 if not options.config:
1246 options.config = os.path.join(CONFIG_DIR, "host#%s.json" % g_host_hash) 1257 options.config = os.path.join(CONFIG_DIR, "host#%s.json" % g_host_hash)
1247 1258
1248 # Check for a modal command-line option (start, stop, etc.) 1259 # Check for a modal command-line option (start, stop, etc.)
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after
1462 logging.info("Relaunching self") 1473 logging.info("Relaunching self")
1463 relaunch_self() 1474 relaunch_self()
1464 else: 1475 else:
1465 # If there is a non-zero |failures| count, restarting the whole script 1476 # If there is a non-zero |failures| count, restarting the whole script
1466 # would lose this information, so just launch the session as normal. 1477 # would lose this information, so just launch the session as normal.
1467 if x_server_inhibitor.is_inhibited(): 1478 if x_server_inhibitor.is_inhibited():
1468 logging.info("Waiting before launching X server") 1479 logging.info("Waiting before launching X server")
1469 relaunch_times.append(x_server_inhibitor.earliest_relaunch_time) 1480 relaunch_times.append(x_server_inhibitor.earliest_relaunch_time)
1470 else: 1481 else:
1471 logging.info("Launching X server and X session.") 1482 logging.info("Launching X server and X session.")
1472 desktop.launch_session(args) 1483 desktop.launch_session(options.keep_env, args)
1473 x_server_inhibitor.record_started(MINIMUM_PROCESS_LIFETIME, 1484 x_server_inhibitor.record_started(MINIMUM_PROCESS_LIFETIME,
1474 backoff_time) 1485 backoff_time)
1475 allow_relaunch_self = True 1486 allow_relaunch_self = True
1476 1487
1477 if desktop.host_proc is None: 1488 if desktop.host_proc is None:
1478 if host_inhibitor.is_inhibited(): 1489 if host_inhibitor.is_inhibited():
1479 logging.info("Waiting before launching host process") 1490 logging.info("Waiting before launching host process")
1480 relaunch_times.append(host_inhibitor.earliest_relaunch_time) 1491 relaunch_times.append(host_inhibitor.earliest_relaunch_time)
1481 else: 1492 else:
1482 logging.info("Launching host process") 1493 logging.info("Launching host process")
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
1536 else: 1547 else:
1537 logging.info("Host exited with status %s." % os.WEXITSTATUS(status)) 1548 logging.info("Host exited with status %s." % os.WEXITSTATUS(status))
1538 elif os.WIFSIGNALED(status): 1549 elif os.WIFSIGNALED(status):
1539 logging.info("Host terminated by signal %s." % os.WTERMSIG(status)) 1550 logging.info("Host terminated by signal %s." % os.WTERMSIG(status))
1540 1551
1541 1552
1542 if __name__ == "__main__": 1553 if __name__ == "__main__":
1543 logging.basicConfig(level=logging.DEBUG, 1554 logging.basicConfig(level=logging.DEBUG,
1544 format="%(asctime)s:%(levelname)s:%(message)s") 1555 format="%(asctime)s:%(levelname)s:%(message)s")
1545 sys.exit(main()) 1556 sys.exit(main())
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698