| #!/bin/bash |
| # |
| # Installs device manager on the local machine. |
| # |
| # Specifically: |
| # |
| # 1. Fetches the binaries required for a device manager installation from a few |
| # possible sources. |
| # |
| # 2. Sets up the helper with setuid. The helper binary needs to be owned by |
| # root and have the suid bit set, to enable the device manager to run binaries |
| # under different system accounts than itself. |
| # |
| # 3. Runs the self-install command on the device manager. |
| # |
| # Usage: |
| # |
| # # Gets binaries from local repository |
| # ./dminstall <install parent dir> |
| # |
| # # Gets binaries from local filesystem |
| # ./dminstall <install parent dir> /path/to/binaries |
| # |
| # # Gets binaries from HTTP server |
| # ./dminstall <install parent dir> http://host/path |
| |
| set -e |
| |
| usage() { |
| echo "usage:" |
| echo "./dminstall [--single_user] <install parent dir> [<binary source>] [-- args for device manager...]" |
| } |
| |
| readonly BIN_NAMES=(deviced suidhelper agentd) |
| readonly STOP_EXIT_CODE=140 |
| |
| ############################################################################### |
| # Copies one binary from source to destination. |
| # Arguments: |
| # name of the binary |
| # source dir of binary |
| # destination dir of binary |
| # Returns: |
| # None |
| ############################################################################### |
| copy_binary() { |
| local -r BIN_NAME="$1" |
| local -r BIN_SRC_DIR="$2" |
| local -r BIN_DEST_DIR="$3" |
| local -r SOURCE="${BIN_SRC_DIR}/${BIN_NAME}" |
| if [[ -x "${SOURCE}" ]]; then |
| local -r DESTINATION="${BIN_DEST_DIR}/${BIN_NAME}" |
| cp "${SOURCE}" "${DESTINATION}" |
| chmod 700 "${DESTINATION}" |
| else |
| echo "couldn't find ${SOURCE}" |
| exit 1 |
| fi |
| } |
| |
| ############################################################################### |
| # Fetches binaries needed by device manager installation. |
| # Globals: |
| # BIN_NAMES |
| # VANADIUM_ROOT |
| # Arguments: |
| # destination for binaries |
| # source of binaries |
| # Returns: |
| # None |
| ############################################################################### |
| get_binaries() { |
| local -r BIN_INSTALL="$1" |
| local -r BIN_SOURCE="$2" |
| |
| local bin_names_str="" |
| for bin_name in "${BIN_NAMES[@]}"; do |
| bin_names_str+=" ${bin_name}" |
| done |
| |
| # If source is not specified, try to look for it in the repository. |
| if [[ -z "${BIN_SOURCE}" ]]; then |
| if [[ -z "${VANADIUM_ROOT}" ]]; then |
| echo 'ERROR: binary source not specified and no local repository available' |
| exit 1 |
| fi |
| local -r REPO_BIN_DIR="${VANADIUM_ROOT}/release/go/bin" |
| echo "Fetching binaries:${bin_names_str} from build repository: ${REPO_BIN_DIR} ..." |
| for bin_name in "${BIN_NAMES[@]}"; do |
| copy_binary "${bin_name}" "${REPO_BIN_DIR}" "${BIN_INSTALL}" |
| done |
| return |
| fi |
| |
| # If the source is specified as an existing local filesystem path, |
| # look for the binaries there. |
| if [[ -d "${BIN_SOURCE}" ]]; then |
| echo "Fetching binaries:${bin_names_str} locally from: ${BIN_SOURCE} ..." |
| for bin_name in "${BIN_NAMES[@]}"; do |
| copy_binary "${bin_name}" "${BIN_SOURCE}" "${BIN_INSTALL}" |
| done |
| return |
| fi |
| |
| # If the source looks like a URL, use HTTP to fetch. |
| local -r URL_REGEXP='^(https?|ftp|file)://' |
| if [[ "${BIN_SOURCE}" =~ ${URL_REGEXP} ]]; then |
| echo "Fetching binaries:${bin_names_str} remotely from: ${BIN_SOURCE} ..." |
| for bin_name in "${BIN_NAMES[@]}"; do |
| local DEST="${BIN_INSTALL}/${bin_name}" |
| curl -f -o "${DEST}" "${BIN_SOURCE}/${bin_name}" |
| chmod 700 "${DEST}" |
| done |
| return |
| fi |
| |
| echo 'ERROR: couldn'"'"'t fetch binaries.' |
| exit 1 |
| } |
| |
| main() { |
| if [[ "$1" == "--single_user" ]]; then |
| local -r SINGLE_USER=true |
| shift |
| local AGENT_FLAG="--no_passphrase" |
| else |
| local -r SINGLE_USER=false |
| local AGENT_FLAG="" |
| fi |
| |
| local -r INSTALL_PARENT_DIR="$1" |
| if [[ -z "${INSTALL_PARENT_DIR}" ]]; then |
| echo 'No local install destination specified!' |
| usage |
| exit 1 |
| fi |
| shift |
| |
| if [[ ! -d "${INSTALL_PARENT_DIR}" ]]; then |
| echo "${INSTALL_PARENT_DIR} is not a directory!" |
| exit 1 |
| fi |
| |
| local -r INSTALL_DIR="${INSTALL_PARENT_DIR}/device_manager" |
| |
| # TODO(caprita): Check that the device manager is not already installed before |
| # proceeding. We should require an explicit uninstall to avoid wiping away |
| # the device manager accidentally. |
| if [[ ${SINGLE_USER} == false ]]; then |
| sudo rm -rf "${INSTALL_DIR}" |
| else |
| rm -rf "${INSTALL_DIR}" |
| fi |
| mkdir -m 700 "${INSTALL_DIR}" |
| |
| local -r BIN_INSTALL="${INSTALL_DIR}/bin" |
| mkdir -m 700 "${BIN_INSTALL}" |
| |
| # Fetch the binaries. |
| if [[ $# = 0 || "$1" = "--" ]]; then |
| local -r BIN_SOURCE="" |
| else |
| local -r BIN_SOURCE="$1" |
| shift |
| fi |
| get_binaries "${BIN_INSTALL}" "${BIN_SOURCE}" |
| for bin_name in "${BIN_NAMES[@]}"; do |
| local BINARY="${BIN_INSTALL}/${bin_name}" |
| if [[ ! -s "${BINARY}" ]]; then |
| echo "${BINARY} is empty." |
| exit 1 |
| fi |
| done |
| echo "Binaries are in ${BIN_INSTALL}." |
| |
| # Set up the suidhelper. |
| echo "Configuring suidhelper ..." |
| local -r SETUID_SCRIPT="${BIN_INSTALL}/suidhelper" |
| if [[ ${SINGLE_USER} == false ]]; then |
| sudo bash -c "chown root:root \"${SETUID_SCRIPT}\"; chmod 4551 \"${SETUID_SCRIPT}\"" |
| fi |
| echo "Suidhelper configured." |
| |
| # Tell the device manager to install itself. |
| local -r DM_ROOT="${INSTALL_DIR}/dmroot" |
| echo "Installing device manager under ${DM_ROOT} ..." |
| local -r PUBLISH=$(hostname) |
| if [[ "$1" = "--" ]]; then |
| shift |
| elif [[ $# != 0 ]]; then |
| echo "Unexpected arguments: $@" |
| usage |
| exit 1 |
| fi |
| |
| VEYRON_DM_CURRENT="${INSTALL_DIR}/deviced.curr" VEYRON_DM_ROOT="${DM_ROOT}" \ |
| VEYRON_DM_HELPER="${SETUID_SCRIPT}" "${BIN_INSTALL}/deviced" install -- \ |
| --name="${PUBLISH}" --stop_exit_code=${STOP_EXIT_CODE} "$@" |
| echo "Device manager installed." |
| |
| local -r SECURITY_DIR="${INSTALL_DIR}/security" |
| mkdir -m 700 "${SECURITY_DIR}" |
| local -r PRINCIPAL_DIR="${SECURITY_DIR}/principal" |
| mkdir -m 700 "${PRINCIPAL_DIR}" |
| local -r AGENT_KEY_DIR="${SECURITY_DIR}/keys" |
| mkdir -m 700 "${AGENT_KEY_DIR}" |
| |
| # Run device manager under the security agent. |
| echo |
| echo "Running:" |
| echo "VEYRON_CREDENTIALS=\"${PRINCIPAL_DIR}\" \"${BIN_INSTALL}/agentd\" \ |
| ${AGENT_FLAG} --restart_exit_code=!${STOP_EXIT_CODE} \ |
| --additional_principals=\"${AGENT_KEY_DIR}\" \"${INSTALL_DIR}/deviced.curr\"" |
| echo |
| # NOTE: If you update the command below, please also update the command echoed |
| # above to keep the two in sync. |
| VEYRON_CREDENTIALS="${PRINCIPAL_DIR}" exec "${BIN_INSTALL}/agentd" \ |
| ${AGENT_FLAG} --restart_exit_code=!${STOP_EXIT_CODE} \ |
| --additional_principals="${AGENT_KEY_DIR}" "${INSTALL_DIR}/deviced.curr" |
| } |
| |
| main "$@" |