15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#!/bin/sh 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2012 The Chromium Authors. All rights reserved. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file. 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NAME=org.chromium.chromoting 8e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen MurdochHOST_BUNDLE_NAME=@@HOST_BUNDLE_NAME@@ 9e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen MurdochPREFPANE_BUNDLE_NAME=@@PREFPANE_BUNDLE_NAME@@ 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CONFIG_DIR=/Library/PrivilegedHelperTools 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ENABLED_FILE=$CONFIG_DIR/$NAME.me2me_enabled 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CONFIG_FILE=$CONFIG_DIR/$NAME.json 13effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochHOST_EXE=$CONFIG_DIR/$HOST_BUNDLE_NAME/Contents/MacOS/remoting_me2me_host 14effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochPLIST_FILE=$CONFIG_DIR/$HOST_BUNDLE_NAME/Contents/Info.plist 15effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochPREF_PANE_BUNDLE=/Library/PreferencePanes/$PREFPANE_BUNDLE_NAME 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# The exit code returned by 'wait' when a process is terminated by SIGTERM. 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SIGTERM_EXIT_CODE=143 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Range of exit codes returned by the host to indicate that a permanent error 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# has occurred and that the host should not be restarted. Please, keep these 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# constants in sync with remoting/host/host_exit_codes.h. 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MIN_PERMANENT_ERROR_EXIT_CODE=100 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MAX_PERMANENT_ERROR_EXIT_CODE=105 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# Constants controlling the host process relaunch throttling. 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)MINIMUM_RELAUNCH_INTERVAL=60 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)MAXIMUM_HOST_FAILURES=10 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# Exit code 126 is defined by Posix to mean "Command found, but not 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# executable", and is returned if the process cannot be launched due to 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# parental control. 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)PERMISSION_DENIED_PARENTAL_CONTROL=126 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HOST_PID=0 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SIGNAL_WAS_TRAPPED=0 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# This script works as a proxy between launchd and the host. Signals of 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# interest to the host must be forwarded. 402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SIGNAL_LIST="SIGHUP SIGINT SIGQUIT SIGILL SIGTRAP SIGABRT SIGEMT \ 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SIGFPE SIGKILL SIGBUS SIGSEGV SIGSYS SIGPIPE SIGALRM SIGTERM SIGURG \ 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SIGSTOP SIGTSTP SIGCONT SIGCHLD SIGTTIN SIGTTOU SIGIO SIGXCPU SIGXFSZ \ 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SIGVTALRM SIGPROF SIGWINCH SIGINFO SIGUSR1 SIGUSR2" 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)handle_signal() { 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIGNAL_WAS_TRAPPED=1 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)run_host() { 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) local host_failure_count=0 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) local host_start_time=0 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while true; do 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ ! -f "$ENABLED_FILE" ]]; then 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) echo "Daemon is disabled." 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 0 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # If this is not the first time the host has run, make sure we don't 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # relaunch it too soon. 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if [[ "$host_start_time" -gt 0 ]]; then 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) local host_lifetime=$(($(date +%s) - $host_start_time)) 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) echo "Host ran for ${host_lifetime}s" 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if [[ "$host_lifetime" -lt "$MINIMUM_RELAUNCH_INTERVAL" ]]; then 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # If the host didn't run for very long, assume it crashed. Relaunch only 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # after a suitable delay and increase the failure count. 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) host_failure_count=$(($host_failure_count + 1)) 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) echo "Host failure count $host_failure_count/$MAXIMUM_HOST_FAILURES" 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if [[ "$host_failure_count" -ge "$MAXIMUM_HOST_FAILURES" ]]; then 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) echo "Too many host failures. Giving up." 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) exit 1 722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fi 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) local relaunch_in=$(($MINIMUM_RELAUNCH_INTERVAL - $host_lifetime)) 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) echo "Relaunching in ${relaunch_in}s" 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sleep "$relaunch_in" 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) else 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # If the host ran for long enough, reset the crash counter. 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) host_failure_count=0 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fi 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fi 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # Execute the host asynchronously and forward signals to it. 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) trap "handle_signal" $SIGNAL_LIST 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) host_start_time=$(date +%s) 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "$HOST_EXE" --host-config="$CONFIG_FILE" & 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HOST_PID="$!" 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Wait for the host to return and process its exit code. 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while true; do 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wait "$HOST_PID" 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXIT_CODE="$?" 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ $SIGNAL_WAS_TRAPPED -eq 1 ]]; then 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # 'wait' returned as the result of a trapped signal and the exit code is 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # the signal that was trapped + 128. Forward the signal to the host. 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIGNAL_WAS_TRAPPED=0 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local SIGNAL=$(($EXIT_CODE - 128)) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) echo "Forwarding signal $SIGNAL to host" 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kill -$SIGNAL "$HOST_PID" 992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) elif [[ "$EXIT_CODE" -eq "0" || 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "$EXIT_CODE" -eq "$SIGTERM_EXIT_CODE" || 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "$EXIT_CODE" -eq "$PERMISSION_DENIED_PARENTAL_CONTROL" || 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ("$EXIT_CODE" -ge "$MIN_PERMANENT_ERROR_EXIT_CODE" && \ 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "$EXIT_CODE" -le "$MAX_PERMANENT_ERROR_EXIT_CODE") ]]; then 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) echo "Host returned permanent exit code $EXIT_CODE at ""$(date)""" 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if [[ "$EXIT_CODE" -eq 101 ]]; then 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # Exit code 101 is "hostID deleted", which indicates that the host 1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # was taken off-line remotely. To prevent the host being restarted 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # when the login context changes, try to delete the "enabled" file. 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # Since this requires root privileges, this is only possible when 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # this script is launched in the "login" context. In the "aqua" 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # context, just exit and try again next time. 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) echo "Host id deleted - disabling" 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) rm -f "$ENABLED_FILE" 2>/dev/null 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fi 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit "$EXIT_CODE" 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # Ignore non-permanent error-code and launch host again. Stop handling 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # signals temporarily in case the script has to sleep to throttle host 1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # relaunches. While throttling, there is no host process to which to 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # forward the signal, so the default behaviour should be restored. 1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) echo "Host returned non-permanent exit code $EXIT_CODE at ""$(date)""" 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) trap - $SIGNAL_LIST 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HOST_PID=0 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) done 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) done 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if [[ "$1" = "--disable" ]]; then 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # This script is executed from base::mac::ExecuteWithPrivilegesAndWait(), 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # which requires the child process to write its PID to stdout before 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # anythine else. See base/mac/authorization_util.h for details. 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) echo $$ 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rm -f "$ENABLED_FILE" 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)elif [[ "$1" = "--enable" ]]; then 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) echo $$ 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Ensure the config file is private whilst being written. 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rm -f "$CONFIG_FILE" 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) umask 0077 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cat > "$CONFIG_FILE" 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Ensure the config is readable by the user registering the host. 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chmod +a "$USER:allow:read" "$CONFIG_FILE" 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) touch "$ENABLED_FILE" 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)elif [[ "$1" = "--save-config" ]]; then 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) echo $$ 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cat > "$CONFIG_FILE" 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)elif [[ "$1" = "--host-version" ]]; then 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /usr/libexec/PlistBuddy -c "Print CFBundleVersion" "$PLIST_FILE" 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)elif [[ "$1" = "--relaunch-prefpane" ]]; then 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Wait for the parent (System Preferences applet) to die, by reading from 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # stdin until the pipe is broken. 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cat 2>/dev/null || true 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) open "$PREF_PANE_BUNDLE" 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)elif [[ "$1" = "--run-from-launchd" ]]; then 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) echo Host started for user $USER at $"$(date)" 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) run_host 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)else 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) echo $$ 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 1 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)fi 162