OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env 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 26 matching lines...) Expand all Loading... |
37 # By default this script will try to determine the most appropriate X session | 37 # By default this script will try to determine the most appropriate X session |
38 # command for the system. To use a specific session instead, set this variable | 38 # command for the system. To use a specific session instead, set this variable |
39 # to the executable filename, or a list containing the executable and any | 39 # to the executable filename, or a list containing the executable and any |
40 # arguments, for example: | 40 # arguments, for example: |
41 # XSESSION_COMMAND = "/usr/bin/gnome-session-fallback" | 41 # XSESSION_COMMAND = "/usr/bin/gnome-session-fallback" |
42 # XSESSION_COMMAND = ["/usr/bin/gnome-session", "--session=ubuntu-2d"] | 42 # XSESSION_COMMAND = ["/usr/bin/gnome-session", "--session=ubuntu-2d"] |
43 XSESSION_COMMAND = None | 43 XSESSION_COMMAND = None |
44 | 44 |
45 REMOTING_COMMAND = "remoting_me2me_host" | 45 REMOTING_COMMAND = "remoting_me2me_host" |
46 | 46 |
47 # Command-line switch for passing the config path to remoting_me2me_host. | |
48 HOST_CONFIG_SWITCH_NAME = "host-config" | |
49 | |
50 # Needs to be an absolute path, since the current working directory is changed | 47 # Needs to be an absolute path, since the current working directory is changed |
51 # when this process self-daemonizes. | 48 # when this process self-daemonizes. |
52 SCRIPT_PATH = os.path.dirname(sys.argv[0]) | 49 SCRIPT_PATH = os.path.dirname(sys.argv[0]) |
53 if SCRIPT_PATH: | 50 if SCRIPT_PATH: |
54 SCRIPT_PATH = os.path.abspath(SCRIPT_PATH) | 51 SCRIPT_PATH = os.path.abspath(SCRIPT_PATH) |
55 else: | 52 else: |
56 SCRIPT_PATH = os.getcwd() | 53 SCRIPT_PATH = os.getcwd() |
57 | 54 |
58 # These are relative to SCRIPT_PATH. | 55 # These are relative to SCRIPT_PATH. |
59 EXE_PATHS_TO_TRY = [ | 56 EXE_PATHS_TO_TRY = [ |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
141 * load_config(): Load a config from disk, with details of an existing Host | 138 * load_config(): Load a config from disk, with details of an existing Host |
142 registration. | 139 registration. |
143 | 140 |
144 After calling register() (or making any config changes) the method | 141 After calling register() (or making any config changes) the method |
145 save_config() should be called to save the details to disk. | 142 save_config() should be called to save the details to disk. |
146 """ | 143 """ |
147 | 144 |
148 server = 'www.googleapis.com' | 145 server = 'www.googleapis.com' |
149 url = 'https://' + server + '/chromoting/v1/@me/hosts' | 146 url = 'https://' + server + '/chromoting/v1/@me/hosts' |
150 | 147 |
151 def __init__(self, config_file): | 148 def __init__(self, config_file, auth): |
| 149 """ |
| 150 Args: |
| 151 config_file: Host configuration file path |
| 152 auth: Authentication object with credentials for authenticating with the |
| 153 Directory service. |
| 154 """ |
152 self.config_file = config_file | 155 self.config_file = config_file |
| 156 self.auth = auth |
153 self.host_id = str(uuid.uuid1()) | 157 self.host_id = str(uuid.uuid1()) |
154 self.host_name = socket.gethostname() | 158 self.host_name = socket.gethostname() |
155 self.host_secret_hash = None | 159 self.host_secret_hash = None |
156 self.private_key = None | 160 self.private_key = None |
157 | 161 |
158 def register(self, auth): | 162 def register(self): |
159 """Generates a private key for the stored |host_id|, and registers it with | 163 """Generates a private key for the stored |host_id|, and registers it with |
160 the Directory service. | 164 the Directory service. |
161 | 165 |
162 Args: | |
163 auth: Authentication object with credentials for authenticating with the | |
164 Directory service. | |
165 | |
166 Raises: | 166 Raises: |
167 urllib2.HTTPError: An error occurred talking to the Directory server | 167 urllib2.HTTPError: An error occurred talking to the Directory server |
168 (for example, if the |auth| credentials were rejected). | 168 (for example, if the |auth| credentials were rejected). |
169 """ | 169 """ |
170 | 170 |
171 logging.info("HostId: " + self.host_id) | 171 logging.info("HostId: " + self.host_id) |
172 logging.info("HostName: " + self.host_name) | 172 logging.info("HostName: " + self.host_name) |
173 | 173 |
174 logging.info("Generating RSA key pair...") | 174 logging.info("Generating RSA key pair...") |
175 (self.private_key, public_key) = keygen.generateRSAKeyPair() | 175 (self.private_key, public_key) = keygen.generateRSAKeyPair() |
176 logging.info("Done") | 176 logging.info("Done") |
177 | 177 |
178 json_data = { | 178 json_data = { |
179 "data": { | 179 "data": { |
180 "hostId": self.host_id, | 180 "hostId": self.host_id, |
181 "hostName": self.host_name, | 181 "hostName": self.host_name, |
182 "publicKey": public_key, | 182 "publicKey": public_key, |
183 } | 183 } |
184 } | 184 } |
185 params = json.dumps(json_data) | 185 params = json.dumps(json_data) |
186 headers = { | 186 headers = { |
187 "Authorization": "GoogleLogin auth=" + auth.chromoting_auth_token, | 187 "Authorization": "GoogleLogin auth=" + self.auth.chromoting_auth_token, |
188 "Content-Type": "application/json", | 188 "Content-Type": "application/json", |
189 } | 189 } |
190 | 190 |
191 request = urllib2.Request(self.url, params, headers) | 191 request = urllib2.Request(self.url, params, headers) |
192 opener = urllib2.OpenerDirector() | 192 opener = urllib2.OpenerDirector() |
193 opener.add_handler(urllib2.HTTPDefaultErrorHandler()) | 193 opener.add_handler(urllib2.HTTPDefaultErrorHandler()) |
194 | 194 |
195 logging.info("Registering host with directory service...") | 195 logging.info("Registering host with directory service...") |
196 | 196 |
197 res = urllib2.urlopen(request) | 197 res = urllib2.urlopen(request) |
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
376 self.session_proc = subprocess.Popen(XSESSION_COMMAND, | 376 self.session_proc = subprocess.Popen(XSESSION_COMMAND, |
377 stdin=open(os.devnull, "r"), | 377 stdin=open(os.devnull, "r"), |
378 cwd=HOME_DIR, | 378 cwd=HOME_DIR, |
379 env=self.child_env) | 379 env=self.child_env) |
380 if not self.session_proc.pid: | 380 if not self.session_proc.pid: |
381 raise Exception("Could not start X session") | 381 raise Exception("Could not start X session") |
382 | 382 |
383 def launch_host(self, host): | 383 def launch_host(self, host): |
384 # Start remoting host | 384 # Start remoting host |
385 args = [locate_executable(REMOTING_COMMAND), | 385 args = [locate_executable(REMOTING_COMMAND), |
386 "--%s=%s" % (HOST_CONFIG_SWITCH_NAME, host.config_file)] | 386 "--host_config=%s" % (host.config_file), |
| 387 "--auth_config=%s" % (host.auth.config_file)] |
387 self.host_proc = subprocess.Popen(args, env=self.child_env) | 388 self.host_proc = subprocess.Popen(args, env=self.child_env) |
388 if not self.host_proc.pid: | 389 if not self.host_proc.pid: |
389 raise Exception("Could not start remoting host") | 390 raise Exception("Could not start remoting host") |
390 | 391 |
391 | 392 |
392 class PidFile: | 393 class PidFile: |
393 """Class to allow creating and deleting a file which holds the PID of the | 394 """Class to allow creating and deleting a file which holds the PID of the |
394 running process. This is used to detect if a process is already running, and | 395 running process. This is used to detect if a process is already running, and |
395 inform the user of the PID. On process termination, the PID file is | 396 inform the user of the PID. On process termination, the PID file is |
396 deleted. | 397 deleted. |
(...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
685 # Ensure full path to config directory exists. | 686 # Ensure full path to config directory exists. |
686 if not os.path.exists(CONFIG_DIR): | 687 if not os.path.exists(CONFIG_DIR): |
687 os.makedirs(CONFIG_DIR, mode=0700) | 688 os.makedirs(CONFIG_DIR, mode=0700) |
688 | 689 |
689 if options.explicit_config: | 690 if options.explicit_config: |
690 for file_name in ["auth.json", "host#%s.json" % host_hash]: | 691 for file_name in ["auth.json", "host#%s.json" % host_hash]: |
691 settings_file = open(os.path.join(CONFIG_DIR, file_name), 'w') | 692 settings_file = open(os.path.join(CONFIG_DIR, file_name), 'w') |
692 settings_file.write(options.explicit_config) | 693 settings_file.write(options.explicit_config) |
693 settings_file.close() | 694 settings_file.close() |
694 | 695 |
| 696 # TODO(sergeyu): Move auth parameters to the host config. |
695 auth = Authentication(os.path.join(CONFIG_DIR, "auth.json")) | 697 auth = Authentication(os.path.join(CONFIG_DIR, "auth.json")) |
696 need_auth_tokens = not auth.load_config() | 698 need_auth_tokens = not auth.load_config() |
697 | 699 |
698 host = Host(os.path.join(CONFIG_DIR, "host#%s.json" % host_hash)) | 700 host = Host(os.path.join(CONFIG_DIR, "host#%s.json" % host_hash), auth) |
699 register_host = not host.load_config() | 701 register_host = not host.load_config() |
700 | 702 |
701 # Outside the loop so user doesn't get asked twice. | 703 # Outside the loop so user doesn't get asked twice. |
702 if register_host: | 704 if register_host: |
703 host.ask_pin() | 705 host.ask_pin() |
704 elif options.new_pin or not host.is_pin_set(): | 706 elif options.new_pin or not host.is_pin_set(): |
705 host.ask_pin() | 707 host.ask_pin() |
706 host.save_config() | 708 host.save_config() |
707 running, pid = PidFile(pid_filename).check() | 709 running, pid = PidFile(pid_filename).check() |
708 if running and pid != 0: | 710 if running and pid != 0: |
(...skipping 10 matching lines...) Expand all Loading... |
719 if need_auth_tokens: | 721 if need_auth_tokens: |
720 auth.generate_tokens() | 722 auth.generate_tokens() |
721 auth.save_config() | 723 auth.save_config() |
722 need_auth_tokens = False | 724 need_auth_tokens = False |
723 except Exception: | 725 except Exception: |
724 logging.error("Authentication failed") | 726 logging.error("Authentication failed") |
725 return 1 | 727 return 1 |
726 | 728 |
727 try: | 729 try: |
728 if register_host: | 730 if register_host: |
729 host.register(auth) | 731 host.register() |
730 host.save_config() | 732 host.save_config() |
731 except urllib2.HTTPError, err: | 733 except urllib2.HTTPError, err: |
732 if err.getcode() == 401: | 734 if err.getcode() == 401: |
733 # Authentication failed - re-prompt for username & password. | 735 # Authentication failed - re-prompt for username & password. |
734 need_auth_tokens = True | 736 need_auth_tokens = True |
735 continue | 737 continue |
736 else: | 738 else: |
737 # Not an authentication error. | 739 # Not an authentication error. |
738 logging.error("Directory returned error: " + str(err)) | 740 logging.error("Directory returned error: " + str(err)) |
739 logging.error(err.read()) | 741 logging.error(err.read()) |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
848 os.remove(host.config_file) | 850 os.remove(host.config_file) |
849 return 0 | 851 return 0 |
850 elif os.WEXITSTATUS(status) == 4: | 852 elif os.WEXITSTATUS(status) == 4: |
851 logging.info("OAuth credentials are invalid - exiting.") | 853 logging.info("OAuth credentials are invalid - exiting.") |
852 os.remove(auth.config_file) | 854 os.remove(auth.config_file) |
853 return 0 | 855 return 0 |
854 | 856 |
855 if __name__ == "__main__": | 857 if __name__ == "__main__": |
856 logging.basicConfig(level=logging.DEBUG) | 858 logging.basicConfig(level=logging.DEBUG) |
857 sys.exit(main()) | 859 sys.exit(main()) |
OLD | NEW |