153254411SSascha Wildner#!/bin/sh 253254411SSascha Wildner 3*ba1276acSMatthew Dillon# Copyright (c) 1999-2023 Philip Hands <phil@hands.com> 4*ba1276acSMatthew Dillon# 2021 Carlos Rodríguez Gili <carlos.rodriguez-gili@upc.edu> 550a69bb5SSascha Wildner# 2020 Matthias Blümel <blaimi@blaimi.de> 650a69bb5SSascha Wildner# 2017 Sebastien Boyron <seb@boyron.eu> 753254411SSascha Wildner# 2013 Martin Kletzander <mkletzan@redhat.com> 853254411SSascha Wildner# 2010 Adeodato =?iso-8859-1?Q?Sim=F3?= <asp16@alu.ua.es> 953254411SSascha Wildner# 2010 Eric Moret <eric.moret@gmail.com> 1053254411SSascha Wildner# 2009 Xr <xr@i-jeuxvideo.com> 1153254411SSascha Wildner# 2007 Justin Pryzby <justinpryzby@users.sourceforge.net> 1253254411SSascha Wildner# 2004 Reini Urban <rurban@x-ray.at> 1353254411SSascha Wildner# 2003 Colin Watson <cjwatson@debian.org> 1453254411SSascha Wildner# All rights reserved. 1553254411SSascha Wildner# 1653254411SSascha Wildner# Redistribution and use in source and binary forms, with or without 1753254411SSascha Wildner# modification, are permitted provided that the following conditions 1853254411SSascha Wildner# are met: 1953254411SSascha Wildner# 1. Redistributions of source code must retain the above copyright 2053254411SSascha Wildner# notice, this list of conditions and the following disclaimer. 2153254411SSascha Wildner# 2. Redistributions in binary form must reproduce the above copyright 2253254411SSascha Wildner# notice, this list of conditions and the following disclaimer in the 2353254411SSascha Wildner# documentation and/or other materials provided with the distribution. 2453254411SSascha Wildner# 2553254411SSascha Wildner# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2653254411SSascha Wildner# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2753254411SSascha Wildner# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2853254411SSascha Wildner# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2953254411SSascha Wildner# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 3053254411SSascha Wildner# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3153254411SSascha Wildner# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3253254411SSascha Wildner# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3353254411SSascha Wildner# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3453254411SSascha Wildner# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3553254411SSascha Wildner 3653254411SSascha Wildner# Shell script to install your public key(s) on a remote machine 3753254411SSascha Wildner# See the ssh-copy-id(1) man page for details 3853254411SSascha Wildner 3950a69bb5SSascha Wildner# shellcheck shell=dash 4050a69bb5SSascha Wildner 4153254411SSascha Wildner# check that we have something mildly sane as our shell, or try to find something better 4253254411SSascha Wildnerif false ^ printf "%s: WARNING: ancient shell, hunting for a more modern one... " "$0" 4353254411SSascha Wildnerthen 4453254411SSascha Wildner SANE_SH=${SANE_SH:-/usr/bin/ksh} 4553254411SSascha Wildner if printf 'true ^ false\n' | "$SANE_SH" 4653254411SSascha Wildner then 4750a69bb5SSascha Wildner printf "'%s' seems viable.\\n" "$SANE_SH" 4853254411SSascha Wildner exec "$SANE_SH" "$0" "$@" 4953254411SSascha Wildner else 5053254411SSascha Wildner cat <<-EOF 5153254411SSascha Wildner oh dear. 5253254411SSascha Wildner 5353254411SSascha Wildner If you have a more recent shell available, that supports \$(...) etc. 5453254411SSascha Wildner please try setting the environment variable SANE_SH to the path of that 5553254411SSascha Wildner shell, and then retry running this script. If that works, please report 5653254411SSascha Wildner a bug describing your setup, and the shell you used to make it work. 5753254411SSascha Wildner 5853254411SSascha Wildner EOF 5950a69bb5SSascha Wildner printf '%s: ERROR: Less dimwitted shell required.\n' "$0" 6053254411SSascha Wildner exit 1 6153254411SSascha Wildner fi 6253254411SSascha Wildnerfi 6353254411SSascha Wildner 6450a69bb5SSascha Wildner# shellcheck disable=SC2010 6550a69bb5SSascha WildnerDEFAULT_PUB_ID_FILE=$(ls -t "${HOME}"/.ssh/id*.pub 2>/dev/null | grep -v -- '-cert.pub$' | head -n 1) 6650a69bb5SSascha WildnerSSH="ssh -a -x" 67*ba1276acSMatthew DillonTARGET_PATH=".ssh/authorized_keys" 6850a69bb5SSascha Wildnerumask 0177 6953254411SSascha Wildner 7053254411SSascha Wildnerusage () { 71*ba1276acSMatthew Dillon printf 'Usage: %s [-h|-?|-f|-n|-s|-x] [-i [identity_file]] [-p port] [-F alternative ssh_config file] [-t target_path] [[-o <ssh -o options>] ...] [user@]hostname\n' "$0" >&2 7253254411SSascha Wildner printf '\t-f: force mode -- copy keys without trying to check if they are already installed\n' >&2 7353254411SSascha Wildner printf '\t-n: dry run -- no keys are actually copied\n' >&2 7450a69bb5SSascha Wildner printf '\t-s: use sftp -- use sftp instead of executing remote-commands. Can be useful if the remote only allows sftp\n' >&2 75*ba1276acSMatthew Dillon printf '\t-x: debug -- enables -x in this shell, for debugging\n' >&2 7653254411SSascha Wildner printf '\t-h|-?: print this help\n' >&2 7753254411SSascha Wildner exit 1 7853254411SSascha Wildner} 7953254411SSascha Wildner 8053254411SSascha Wildner# escape any single quotes in an argument 8153254411SSascha Wildnerquote() { 8250a69bb5SSascha Wildner printf '%s\n' "$1" | sed -e "s/'/'\\\\''/g" 8353254411SSascha Wildner} 8453254411SSascha Wildner 8553254411SSascha Wildneruse_id_file() { 8650a69bb5SSascha Wildner L_ID_FILE="$1" 8753254411SSascha Wildner 8853254411SSascha Wildner if [ -z "$L_ID_FILE" ] ; then 8950a69bb5SSascha Wildner printf '%s: ERROR: no ID file found\n' "$0" 9053254411SSascha Wildner exit 1 9153254411SSascha Wildner fi 9253254411SSascha Wildner 9350a69bb5SSascha Wildner if expr "$L_ID_FILE" : '.*\.pub$' >/dev/null ; then 9453254411SSascha Wildner PUB_ID_FILE="$L_ID_FILE" 9553254411SSascha Wildner else 9653254411SSascha Wildner PUB_ID_FILE="$L_ID_FILE.pub" 9753254411SSascha Wildner fi 9853254411SSascha Wildner 9953254411SSascha Wildner [ "$FORCED" ] || PRIV_ID_FILE=$(dirname "$PUB_ID_FILE")/$(basename "$PUB_ID_FILE" .pub) 10053254411SSascha Wildner 10153254411SSascha Wildner # check that the files are readable 10253254411SSascha Wildner for f in "$PUB_ID_FILE" ${PRIV_ID_FILE:+"$PRIV_ID_FILE"} ; do 10353254411SSascha Wildner ErrMSG=$( { : < "$f" ; } 2>&1 ) || { 10450a69bb5SSascha Wildner L_PRIVMSG="" 10553254411SSascha Wildner [ "$f" = "$PRIV_ID_FILE" ] && L_PRIVMSG=" (to install the contents of '$PUB_ID_FILE' anyway, look at the -f option)" 10650a69bb5SSascha Wildner printf "\\n%s: ERROR: failed to open ID file '%s': %s\\n" "$0" "$f" "$(printf '%s\n%s\n' "$ErrMSG" "$L_PRIVMSG" | sed -e 's/.*: *//')" 10753254411SSascha Wildner exit 1 10853254411SSascha Wildner } 10953254411SSascha Wildner done 11053254411SSascha Wildner printf '%s: INFO: Source of key(s) to be installed: "%s"\n' "$0" "$PUB_ID_FILE" >&2 11153254411SSascha Wildner GET_ID="cat \"$PUB_ID_FILE\"" 11253254411SSascha Wildner} 11353254411SSascha Wildner 11453254411SSascha Wildnerif [ -n "$SSH_AUTH_SOCK" ] && ssh-add -L >/dev/null 2>&1 ; then 11553254411SSascha Wildner GET_ID="ssh-add -L" 11653254411SSascha Wildnerfi 11753254411SSascha Wildner 118*ba1276acSMatthew Dillonwhile getopts "i:o:p:F:t:fnsxh?" OPT 11953254411SSascha Wildnerdo 12053254411SSascha Wildner case "$OPT" in 12150a69bb5SSascha Wildner i) 12250a69bb5SSascha Wildner [ "${SEEN_OPT_I}" ] && { 12350a69bb5SSascha Wildner printf '\n%s: ERROR: -i option must not be specified more than once\n\n' "$0" 12450a69bb5SSascha Wildner usage 12550a69bb5SSascha Wildner } 12653254411SSascha Wildner SEEN_OPT_I="yes" 12753254411SSascha Wildner use_id_file "${OPTARG:-$DEFAULT_PUB_ID_FILE}" 12853254411SSascha Wildner ;; 129*ba1276acSMatthew Dillon o|F) 130*ba1276acSMatthew Dillon OPTS_oF="${OPTS_oF:+$OPTS_oF }-$OPT '$(quote "${OPTARG}")'" 13153254411SSascha Wildner ;; 13250a69bb5SSascha Wildner f) 13353254411SSascha Wildner FORCED=1 13453254411SSascha Wildner ;; 13550a69bb5SSascha Wildner n) 13653254411SSascha Wildner DRY_RUN=1 13753254411SSascha Wildner ;; 138*ba1276acSMatthew Dillon p) 139*ba1276acSMatthew Dillon SSH_PORT=${OPTARG} 140*ba1276acSMatthew Dillon ;; 14150a69bb5SSascha Wildner s) 14250a69bb5SSascha Wildner SFTP=sftp 14350a69bb5SSascha Wildner ;; 144*ba1276acSMatthew Dillon t) 145*ba1276acSMatthew Dillon TARGET_PATH="${OPTARG}" 146*ba1276acSMatthew Dillon ;; 147*ba1276acSMatthew Dillon x) 148*ba1276acSMatthew Dillon SET_X="set -x;" 149*ba1276acSMatthew Dillon set -x 150*ba1276acSMatthew Dillon ;; 15150a69bb5SSascha Wildner h|\?) 15253254411SSascha Wildner usage 15353254411SSascha Wildner ;; 15453254411SSascha Wildner esac 15553254411SSascha Wildnerdone 15650a69bb5SSascha Wildner#shift all args to keep only USER_HOST 15750a69bb5SSascha Wildnershift $((OPTIND-1)) 15853254411SSascha Wildner 15953254411SSascha Wildnerif [ $# = 0 ] ; then 16053254411SSascha Wildner usage 16153254411SSascha Wildnerfi 16253254411SSascha Wildnerif [ $# != 1 ] ; then 16353254411SSascha Wildner printf '%s: ERROR: Too many arguments. Expecting a target hostname, got: %s\n\n' "$0" "$SAVEARGS" >&2 16453254411SSascha Wildner usage 16553254411SSascha Wildnerfi 16653254411SSascha Wildner 16750a69bb5SSascha WildnerUSER_HOST="$*" 16853254411SSascha Wildner# tack the hostname onto SSH_OPTS 169*ba1276acSMatthew DillonOPTS_USER_HOST="${OPTS_oF:+$OPTS_oF }'$(quote "$USER_HOST")'" 170*ba1276acSMatthew DillonSSH_OPTS="${SSH_PORT:+-p $SSH_PORT }$OPTS_USER_HOST" 17153254411SSascha Wildner# and populate "$@" for later use (only way to get proper quoting of options) 17253254411SSascha Wildnereval set -- "$SSH_OPTS" 17353254411SSascha Wildner 17450a69bb5SSascha Wildner# shellcheck disable=SC2086 17553254411SSascha Wildnerif [ -z "$(eval $GET_ID)" ] && [ -r "${PUB_ID_FILE:=$DEFAULT_PUB_ID_FILE}" ] ; then 17653254411SSascha Wildner use_id_file "$PUB_ID_FILE" 17753254411SSascha Wildnerfi 17853254411SSascha Wildner 17950a69bb5SSascha Wildner# shellcheck disable=SC2086 18053254411SSascha Wildnerif [ -z "$(eval $GET_ID)" ] ; then 18153254411SSascha Wildner printf '%s: ERROR: No identities found\n' "$0" >&2 18253254411SSascha Wildner exit 1 18353254411SSascha Wildnerfi 18453254411SSascha Wildner 18550a69bb5SSascha Wildner# filter_ids() 18650a69bb5SSascha Wildner# tries to log in using the keys piped to it, and filters out any that work 18750a69bb5SSascha Wildnerfilter_ids() { 18850a69bb5SSascha Wildner L_SUCCESS="$1" 18950a69bb5SSascha Wildner L_TMP_ID_FILE="$SCRATCH_DIR"/popids_tmp_id 19050a69bb5SSascha Wildner L_OUTPUT_FILE="$SCRATCH_DIR"/popids_output 19153254411SSascha Wildner 19253254411SSascha Wildner # repopulate "$@" inside this function 19353254411SSascha Wildner eval set -- "$SSH_OPTS" 19453254411SSascha Wildner 19550a69bb5SSascha Wildner while read -r ID || [ "$ID" ] ; do 19653254411SSascha Wildner printf '%s\n' "$ID" > "$L_TMP_ID_FILE" 19753254411SSascha Wildner 19853254411SSascha Wildner # the next line assumes $PRIV_ID_FILE only set if using a single id file - this 19953254411SSascha Wildner # assumption will break if we implement the possibility of multiple -i options. 20053254411SSascha Wildner # The point being that if file based, ssh needs the private key, which it cannot 20153254411SSascha Wildner # find if only given the contents of the .pub file in an unrelated tmpfile 20250a69bb5SSascha Wildner $SSH -i "${PRIV_ID_FILE:-$L_TMP_ID_FILE}" \ 20353254411SSascha Wildner -o ControlPath=none \ 20453254411SSascha Wildner -o LogLevel=INFO \ 20553254411SSascha Wildner -o PreferredAuthentications=publickey \ 20650a69bb5SSascha Wildner -o IdentitiesOnly=yes "$@" exit >"$L_OUTPUT_FILE" 2>&1 </dev/null 20750a69bb5SSascha Wildner if [ "$?" = "$L_SUCCESS" ] || { 20850a69bb5SSascha Wildner [ "$SFTP" ] && grep 'allows sftp connections only' "$L_OUTPUT_FILE" >/dev/null 20950a69bb5SSascha Wildner # this error counts as a success if we're setting up an sftp connection 21050a69bb5SSascha Wildner } 21150a69bb5SSascha Wildner then 21253254411SSascha Wildner : > "$L_TMP_ID_FILE" 21353254411SSascha Wildner else 21450a69bb5SSascha Wildner grep 'Permission denied' "$L_OUTPUT_FILE" >/dev/null || { 21550a69bb5SSascha Wildner sed -e 's/^/ERROR: /' <"$L_OUTPUT_FILE" >"$L_TMP_ID_FILE" 21653254411SSascha Wildner cat >/dev/null #consume the other keys, causing loop to end 21753254411SSascha Wildner } 21853254411SSascha Wildner fi 21953254411SSascha Wildner 22053254411SSascha Wildner cat "$L_TMP_ID_FILE" 22153254411SSascha Wildner done 22253254411SSascha Wildner} 22350a69bb5SSascha Wildner 22450a69bb5SSascha Wildner# populate_new_ids() uses several global variables ($USER_HOST, $SSH_OPTS ...) 22550a69bb5SSascha Wildner# and has the side effect of setting $NEW_IDS 22650a69bb5SSascha Wildnerpopulate_new_ids() { 22750a69bb5SSascha Wildner if [ "$FORCED" ] ; then 22850a69bb5SSascha Wildner # shellcheck disable=SC2086 22950a69bb5SSascha Wildner NEW_IDS=$(eval $GET_ID) 23050a69bb5SSascha Wildner return 23150a69bb5SSascha Wildner fi 23250a69bb5SSascha Wildner 23350a69bb5SSascha Wildner printf '%s: INFO: attempting to log in with the new key(s), to filter out any that are already installed\n' "$0" >&2 23450a69bb5SSascha Wildner # shellcheck disable=SC2086 23550a69bb5SSascha Wildner NEW_IDS=$(eval $GET_ID | filter_ids $1) 23653254411SSascha Wildner 23753254411SSascha Wildner if expr "$NEW_IDS" : "^ERROR: " >/dev/null ; then 23853254411SSascha Wildner printf '\n%s: %s\n\n' "$0" "$NEW_IDS" >&2 23953254411SSascha Wildner exit 1 24053254411SSascha Wildner fi 24153254411SSascha Wildner if [ -z "$NEW_IDS" ] ; then 24253254411SSascha Wildner printf '\n%s: WARNING: All keys were skipped because they already exist on the remote system.\n' "$0" >&2 24350a69bb5SSascha Wildner printf '\t\t(if you think this is a mistake, you may want to use -f option)\n\n' >&2 24453254411SSascha Wildner exit 0 24553254411SSascha Wildner fi 24653254411SSascha Wildner printf '%s: INFO: %d key(s) remain to be installed -- if you are prompted now it is to install the new keys\n' "$0" "$(printf '%s\n' "$NEW_IDS" | wc -l)" >&2 24753254411SSascha Wildner} 24853254411SSascha Wildner 24950a69bb5SSascha Wildner# installkey_sh [target_path] 250*ba1276acSMatthew Dillon# produce a one-liner to add the keys to remote $TARGET_PATH 25150a69bb5SSascha Wildnerinstallkeys_sh() { 25250a69bb5SSascha Wildner # In setting INSTALLKEYS_SH: 25350a69bb5SSascha Wildner # the tr puts it all on one line (to placate tcsh) 25450a69bb5SSascha Wildner # (hence the excessive use of semi-colons (;) ) 25550a69bb5SSascha Wildner # then in the command: 25650a69bb5SSascha Wildner # cd to be at $HOME, just in case; 25750a69bb5SSascha Wildner # the -z `tail ...` checks for a trailing newline. The echo adds one if was missing 25850a69bb5SSascha Wildner # the cat adds the keys we're getting via STDIN 25950a69bb5SSascha Wildner # and if available restorecon is used to restore the SELinux context 260*ba1276acSMatthew Dillon # OpenWrt has a special case for root only. 26150a69bb5SSascha Wildner INSTALLKEYS_SH=$(tr '\t\n' ' ' <<-EOF 262*ba1276acSMatthew Dillon $SET_X 26350a69bb5SSascha Wildner cd; 26450a69bb5SSascha Wildner umask 077; 265*ba1276acSMatthew Dillon AUTH_KEY_FILE="${TARGET_PATH}"; 266*ba1276acSMatthew Dillon [ -f /etc/openwrt_release ] && [ "\$LOGNAME" = "root" ] && 267*ba1276acSMatthew Dillon AUTH_KEY_FILE=/etc/dropbear/authorized_keys; 268*ba1276acSMatthew Dillon AUTH_KEY_DIR=\`dirname "\${AUTH_KEY_FILE}"\`; 269*ba1276acSMatthew Dillon mkdir -p "\${AUTH_KEY_DIR}" && 270*ba1276acSMatthew Dillon { [ -z "\`tail -1c "\${AUTH_KEY_FILE}" 2>/dev/null\`" ] || 271*ba1276acSMatthew Dillon echo >> "\${AUTH_KEY_FILE}" || exit 1; } && 272*ba1276acSMatthew Dillon cat >> "\${AUTH_KEY_FILE}" || exit 1; 27350a69bb5SSascha Wildner if type restorecon >/dev/null 2>&1; then 274*ba1276acSMatthew Dillon restorecon -F "\${AUTH_KEY_DIR}" "\${AUTH_KEY_FILE}"; 27550a69bb5SSascha Wildner fi 27650a69bb5SSascha Wildner EOF 27750a69bb5SSascha Wildner ) 27850a69bb5SSascha Wildner 27950a69bb5SSascha Wildner # to defend against quirky remote shells: use 'exec sh -c' to get POSIX; 28050a69bb5SSascha Wildner printf "exec sh -c '%s'" "${INSTALLKEYS_SH}" 28150a69bb5SSascha Wildner} 28250a69bb5SSascha Wildner 28350a69bb5SSascha Wildner#shellcheck disable=SC2120 # the 'eval set' confuses this 28450a69bb5SSascha Wildnerinstallkeys_via_sftp() { 285*ba1276acSMatthew Dillon AUTH_KEY_FILE=${TARGET_PATH} 286*ba1276acSMatthew Dillon AUTH_KEY_DIR=$(dirname "${AUTH_KEY_FILE}") 28750a69bb5SSascha Wildner 28850a69bb5SSascha Wildner # repopulate "$@" inside this function 28950a69bb5SSascha Wildner eval set -- "$SSH_OPTS" 29050a69bb5SSascha Wildner 29150a69bb5SSascha Wildner L_KEYS=$SCRATCH_DIR/authorized_keys 29250a69bb5SSascha Wildner L_SHARED_CON=$SCRATCH_DIR/master-conn 29350a69bb5SSascha Wildner $SSH -f -N -M -S "$L_SHARED_CON" "$@" 29450a69bb5SSascha Wildner L_CLEANUP="$SSH -S $L_SHARED_CON -O exit 'ignored' >/dev/null 2>&1 ; $SCRATCH_CLEANUP" 29550a69bb5SSascha Wildner #shellcheck disable=SC2064 29650a69bb5SSascha Wildner trap "$L_CLEANUP" EXIT TERM INT QUIT 29750a69bb5SSascha Wildner sftp -b - -o "ControlPath=$L_SHARED_CON" "ignored" <<-EOF || return 1 298*ba1276acSMatthew Dillon -get "$AUTH_KEY_FILE" "$L_KEYS" 29950a69bb5SSascha Wildner EOF 30050a69bb5SSascha Wildner # add a newline or create file if it's missing, same like above 30150a69bb5SSascha Wildner [ -z "$(tail -1c "$L_KEYS" 2>/dev/null)" ] || echo >> "$L_KEYS" 30250a69bb5SSascha Wildner # append the keys being piped in here 30350a69bb5SSascha Wildner cat >> "$L_KEYS" 30450a69bb5SSascha Wildner sftp -b - -o "ControlPath=$L_SHARED_CON" "ignored" <<-EOF || return 1 305*ba1276acSMatthew Dillon -mkdir "$AUTH_KEY_DIR" 306*ba1276acSMatthew Dillon chmod 700 "$AUTH_KEY_DIR" 307*ba1276acSMatthew Dillon put $L_KEYS "$AUTH_KEY_FILE" 308*ba1276acSMatthew Dillon chmod 600 "$AUTH_KEY_FILE" 30950a69bb5SSascha Wildner EOF 31050a69bb5SSascha Wildner #shellcheck disable=SC2064 31150a69bb5SSascha Wildner eval "$L_CLEANUP" && trap "$SCRATCH_CLEANUP" EXIT TERM INT QUIT 31250a69bb5SSascha Wildner} 31350a69bb5SSascha Wildner 31450a69bb5SSascha Wildner 31550a69bb5SSascha Wildner# create a scratch dir for any temporary files needed 31650a69bb5SSascha Wildnerif SCRATCH_DIR=$(mktemp -d ~/.ssh/ssh-copy-id.XXXXXXXXXX) && 31750a69bb5SSascha Wildner [ "$SCRATCH_DIR" ] && [ -d "$SCRATCH_DIR" ] 31850a69bb5SSascha Wildnerthen 31950a69bb5SSascha Wildner chmod 0700 "$SCRATCH_DIR" 32050a69bb5SSascha Wildner SCRATCH_CLEANUP="rm -rf \"$SCRATCH_DIR\"" 32150a69bb5SSascha Wildner #shellcheck disable=SC2064 32250a69bb5SSascha Wildner trap "$SCRATCH_CLEANUP" EXIT TERM INT QUIT 32350a69bb5SSascha Wildnerelse 32450a69bb5SSascha Wildner printf '%s: ERROR: failed to create required temporary directory under ~/.ssh\n' "$0" >&2 32550a69bb5SSascha Wildner exit 1 32650a69bb5SSascha Wildnerfi 32750a69bb5SSascha Wildner 32850a69bb5SSascha WildnerREMOTE_VERSION=$($SSH -v -o PreferredAuthentications=',' -o ControlPath=none "$@" 2>&1 | 32953254411SSascha Wildner sed -ne 's/.*remote software version //p') 33053254411SSascha Wildner 33150a69bb5SSascha Wildner# shellcheck disable=SC2029 33253254411SSascha Wildnercase "$REMOTE_VERSION" in 33353254411SSascha Wildner NetScreen*) 33453254411SSascha Wildner populate_new_ids 1 33553254411SSascha Wildner for KEY in $(printf "%s" "$NEW_IDS" | cut -d' ' -f2) ; do 33650a69bb5SSascha Wildner KEY_NO=$((KEY_NO + 1)) 33750a69bb5SSascha Wildner printf '%s\n' "$KEY" | grep ssh-dss >/dev/null || { 33853254411SSascha Wildner printf '%s: WARNING: Non-dsa key (#%d) skipped (NetScreen only supports DSA keys)\n' "$0" "$KEY_NO" >&2 33953254411SSascha Wildner continue 34053254411SSascha Wildner } 34150a69bb5SSascha Wildner [ "$DRY_RUN" ] || printf 'set ssh pka-dsa key %s\nsave\nexit\n' "$KEY" | $SSH -T "$@" >/dev/null 2>&1 34253254411SSascha Wildner if [ $? = 255 ] ; then 34353254411SSascha Wildner printf '%s: ERROR: installation of key #%d failed (please report a bug describing what caused this, so that we can make this message useful)\n' "$0" "$KEY_NO" >&2 34453254411SSascha Wildner else 34550a69bb5SSascha Wildner ADDED=$((ADDED + 1)) 34653254411SSascha Wildner fi 34753254411SSascha Wildner done 34853254411SSascha Wildner if [ -z "$ADDED" ] ; then 34953254411SSascha Wildner exit 1 35053254411SSascha Wildner fi 35153254411SSascha Wildner ;; 35253254411SSascha Wildner *) 353*ba1276acSMatthew Dillon # Assuming that the remote host treats $TARGET_PATH as one might expect 35453254411SSascha Wildner populate_new_ids 0 35550a69bb5SSascha Wildner if ! [ "$DRY_RUN" ] ; then 35650a69bb5SSascha Wildner printf '%s\n' "$NEW_IDS" | \ 35750a69bb5SSascha Wildner if [ "$SFTP" ] ; then 35850a69bb5SSascha Wildner #shellcheck disable=SC2119 35950a69bb5SSascha Wildner installkeys_via_sftp 36050a69bb5SSascha Wildner else 36150a69bb5SSascha Wildner $SSH "$@" "$(installkeys_sh)" 36250a69bb5SSascha Wildner fi || exit 1 36350a69bb5SSascha Wildner fi 36453254411SSascha Wildner ADDED=$(printf '%s\n' "$NEW_IDS" | wc -l) 36553254411SSascha Wildner ;; 36653254411SSascha Wildneresac 36753254411SSascha Wildner 36853254411SSascha Wildnerif [ "$DRY_RUN" ] ; then 36953254411SSascha Wildner cat <<-EOF 37053254411SSascha Wildner =-=-=-=-=-=-=-= 37153254411SSascha Wildner Would have added the following key(s): 37253254411SSascha Wildner 37353254411SSascha Wildner $NEW_IDS 37453254411SSascha Wildner =-=-=-=-=-=-=-= 37553254411SSascha Wildner EOF 37653254411SSascha Wildnerelse 377*ba1276acSMatthew Dillon [ -z "$SFTP" ] || PORT_OPT=P 37853254411SSascha Wildner cat <<-EOF 37953254411SSascha Wildner 38053254411SSascha Wildner Number of key(s) added: $ADDED 38153254411SSascha Wildner 382*ba1276acSMatthew Dillon Now try logging into the machine, with: "${SFTP:-ssh}${SSH_PORT:+ -${PORT_OPT:-p} $SSH_PORT} ${OPTS_USER_HOST}" 38353254411SSascha Wildner and check to make sure that only the key(s) you wanted were added. 38453254411SSascha Wildner 38553254411SSascha Wildner EOF 38653254411SSascha Wildnerfi 38753254411SSascha Wildner 38853254411SSascha Wildner# =-=-=-= 389