Changeset View
Changeset View
Standalone View
Standalone View
contrib/ssh-copy-id
#!/bin/sh | #!/bin/sh | ||||
# Copyright (c) 1999-2016 Philip Hands <phil@hands.com> | # Copyright (c) 1999-2020 Philip Hands <phil@hands.com> | ||||
# 2017 Sebastien Boyron <seb@boyron.eu> | |||||
# 2013 Martin Kletzander <mkletzan@redhat.com> | # 2013 Martin Kletzander <mkletzan@redhat.com> | ||||
# 2010 Adeodato =?iso-8859-1?Q?Sim=F3?= <asp16@alu.ua.es> | # 2010 Adeodato =?iso-8859-1?Q?Sim=F3?= <asp16@alu.ua.es> | ||||
# 2010 Eric Moret <eric.moret@gmail.com> | # 2010 Eric Moret <eric.moret@gmail.com> | ||||
# 2009 Xr <xr@i-jeuxvideo.com> | # 2009 Xr <xr@i-jeuxvideo.com> | ||||
# 2007 Justin Pryzby <justinpryzby@users.sourceforge.net> | # 2007 Justin Pryzby <justinpryzby@users.sourceforge.net> | ||||
# 2004 Reini Urban <rurban@x-ray.at> | # 2004 Reini Urban <rurban@x-ray.at> | ||||
# 2003 Colin Watson <cjwatson@debian.org> | # 2003 Colin Watson <cjwatson@debian.org> | ||||
# All rights reserved. | # All rights reserved. | ||||
Show All 16 Lines | |||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||||
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
# Shell script to install your public key(s) on a remote machine | # Shell script to install your public key(s) on a remote machine | ||||
# See the ssh-copy-id(1) man page for details | # See the ssh-copy-id(1) man page for details | ||||
# shellcheck shell=dash | |||||
# check that we have something mildly sane as our shell, or try to find something better | # check that we have something mildly sane as our shell, or try to find something better | ||||
if false ^ printf "%s: WARNING: ancient shell, hunting for a more modern one... " "$0" | if false ^ printf "%s: WARNING: ancient shell, hunting for a more modern one... " "$0" | ||||
then | then | ||||
SANE_SH=${SANE_SH:-/usr/bin/ksh} | SANE_SH=${SANE_SH:-/usr/bin/ksh} | ||||
if printf 'true ^ false\n' | "$SANE_SH" | if printf 'true ^ false\n' | "$SANE_SH" | ||||
then | then | ||||
printf "'%s' seems viable.\n" "$SANE_SH" | printf "'%s' seems viable.\\n" "$SANE_SH" | ||||
exec "$SANE_SH" "$0" "$@" | exec "$SANE_SH" "$0" "$@" | ||||
else | else | ||||
cat <<-EOF | cat <<-EOF | ||||
oh dear. | oh dear. | ||||
If you have a more recent shell available, that supports \$(...) etc. | If you have a more recent shell available, that supports \$(...) etc. | ||||
please try setting the environment variable SANE_SH to the path of that | please try setting the environment variable SANE_SH to the path of that | ||||
shell, and then retry running this script. If that works, please report | shell, and then retry running this script. If that works, please report | ||||
a bug describing your setup, and the shell you used to make it work. | a bug describing your setup, and the shell you used to make it work. | ||||
EOF | EOF | ||||
printf "%s: ERROR: Less dimwitted shell required.\n" "$0" | printf '%s: ERROR: Less dimwitted shell required.\n' "$0" | ||||
exit 1 | exit 1 | ||||
fi | fi | ||||
fi | fi | ||||
most_recent_id="$(cd "$HOME" ; ls -t .ssh/id*.pub 2>/dev/null | grep -v -- '-cert.pub$' | head -n 1)" | # shellcheck disable=SC2010 | ||||
DEFAULT_PUB_ID_FILE="${most_recent_id:+$HOME/}$most_recent_id" | DEFAULT_PUB_ID_FILE=$(ls -t "${HOME}"/.ssh/id*.pub 2>/dev/null | grep -v -- '-cert.pub$' | head -n 1) | ||||
usage () { | usage () { | ||||
printf 'Usage: %s [-h|-?|-f|-n] [-i [identity_file]] [-p port] [[-o <ssh -o options>] ...] [user@]hostname\n' "$0" >&2 | printf 'Usage: %s [-h|-?|-f|-n] [-i [identity_file]] [-p port] [-F alternative ssh_config file] [[-o <ssh -o options>] ...] [user@]hostname\n' "$0" >&2 | ||||
printf '\t-f: force mode -- copy keys without trying to check if they are already installed\n' >&2 | printf '\t-f: force mode -- copy keys without trying to check if they are already installed\n' >&2 | ||||
printf '\t-n: dry run -- no keys are actually copied\n' >&2 | printf '\t-n: dry run -- no keys are actually copied\n' >&2 | ||||
printf '\t-h|-?: print this help\n' >&2 | printf '\t-h|-?: print this help\n' >&2 | ||||
exit 1 | exit 1 | ||||
} | } | ||||
# escape any single quotes in an argument | # escape any single quotes in an argument | ||||
quote() { | quote() { | ||||
printf "%s\n" "$1" | sed -e "s/'/'\\\\''/g" | printf '%s\n' "$1" | sed -e "s/'/'\\\\''/g" | ||||
} | } | ||||
use_id_file() { | use_id_file() { | ||||
local L_ID_FILE="$1" | local L_ID_FILE="$1" | ||||
if [ -z "$L_ID_FILE" ] ; then | if [ -z "$L_ID_FILE" ] ; then | ||||
printf "%s: ERROR: no ID file found\n" "$0" | printf '%s: ERROR: no ID file found\n' "$0" | ||||
exit 1 | exit 1 | ||||
fi | fi | ||||
if expr "$L_ID_FILE" : ".*\.pub$" >/dev/null ; then | if expr "$L_ID_FILE" : '.*\.pub$' >/dev/null ; then | ||||
PUB_ID_FILE="$L_ID_FILE" | PUB_ID_FILE="$L_ID_FILE" | ||||
else | else | ||||
PUB_ID_FILE="$L_ID_FILE.pub" | PUB_ID_FILE="$L_ID_FILE.pub" | ||||
fi | fi | ||||
[ "$FORCED" ] || PRIV_ID_FILE=$(dirname "$PUB_ID_FILE")/$(basename "$PUB_ID_FILE" .pub) | [ "$FORCED" ] || PRIV_ID_FILE=$(dirname "$PUB_ID_FILE")/$(basename "$PUB_ID_FILE" .pub) | ||||
# check that the files are readable | # check that the files are readable | ||||
for f in "$PUB_ID_FILE" ${PRIV_ID_FILE:+"$PRIV_ID_FILE"} ; do | for f in "$PUB_ID_FILE" ${PRIV_ID_FILE:+"$PRIV_ID_FILE"} ; do | ||||
ErrMSG=$( { : < "$f" ; } 2>&1 ) || { | ErrMSG=$( { : < "$f" ; } 2>&1 ) || { | ||||
local L_PRIVMSG="" | local L_PRIVMSG="" | ||||
[ "$f" = "$PRIV_ID_FILE" ] && L_PRIVMSG=" (to install the contents of '$PUB_ID_FILE' anyway, look at the -f option)" | [ "$f" = "$PRIV_ID_FILE" ] && L_PRIVMSG=" (to install the contents of '$PUB_ID_FILE' anyway, look at the -f option)" | ||||
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/.*: *//')" | 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/.*: *//')" | ||||
exit 1 | exit 1 | ||||
} | } | ||||
done | done | ||||
printf '%s: INFO: Source of key(s) to be installed: "%s"\n' "$0" "$PUB_ID_FILE" >&2 | printf '%s: INFO: Source of key(s) to be installed: "%s"\n' "$0" "$PUB_ID_FILE" >&2 | ||||
GET_ID="cat \"$PUB_ID_FILE\"" | GET_ID="cat \"$PUB_ID_FILE\"" | ||||
} | } | ||||
if [ -n "$SSH_AUTH_SOCK" ] && ssh-add -L >/dev/null 2>&1 ; then | if [ -n "$SSH_AUTH_SOCK" ] && ssh-add -L >/dev/null 2>&1 ; then | ||||
GET_ID="ssh-add -L" | GET_ID="ssh-add -L" | ||||
fi | fi | ||||
while test "$#" -gt 0 | while getopts "i:o:p:F:fnh?" OPT | ||||
do | do | ||||
[ "${SEEN_OPT_I}" ] && expr "$1" : "[-]i" >/dev/null && { | |||||
printf "\n%s: ERROR: -i option must not be specified more than once\n\n" "$0" | |||||
usage | |||||
} | |||||
OPT= OPTARG= | |||||
# implement something like getopt to avoid Solaris pain | |||||
case "$1" in | |||||
-i?*|-o?*|-p?*) | |||||
OPT="$(printf -- "$1"|cut -c1-2)" | |||||
OPTARG="$(printf -- "$1"|cut -c3-)" | |||||
shift | |||||
;; | |||||
-o|-p) | |||||
OPT="$1" | |||||
OPTARG="$2" | |||||
shift 2 | |||||
;; | |||||
-i) | |||||
OPT="$1" | |||||
test "$#" -le 2 || expr "$2" : "[-]" >/dev/null || { | |||||
OPTARG="$2" | |||||
shift | |||||
} | |||||
shift | |||||
;; | |||||
-f|-n|-h|-\?) | |||||
OPT="$1" | |||||
OPTARG= | |||||
shift | |||||
;; | |||||
--) | |||||
shift | |||||
while test "$#" -gt 0 | |||||
do | |||||
SAVEARGS="${SAVEARGS:+$SAVEARGS }'$(quote "$1")'" | |||||
shift | |||||
done | |||||
break | |||||
;; | |||||
-*) | |||||
printf "\n%s: ERROR: invalid option (%s)\n\n" "$0" "$1" | |||||
usage | |||||
;; | |||||
*) | |||||
SAVEARGS="${SAVEARGS:+$SAVEARGS }'$(quote "$1")'" | |||||
shift | |||||
continue | |||||
;; | |||||
esac | |||||
case "$OPT" in | case "$OPT" in | ||||
-i) | i) | ||||
[ "${SEEN_OPT_I}" ] && { | |||||
printf '\n%s: ERROR: -i option must not be specified more than once\n\n' "$0" | |||||
usage | |||||
} | |||||
SEEN_OPT_I="yes" | SEEN_OPT_I="yes" | ||||
use_id_file "${OPTARG:-$DEFAULT_PUB_ID_FILE}" | use_id_file "${OPTARG:-$DEFAULT_PUB_ID_FILE}" | ||||
;; | ;; | ||||
-o|-p) | o|p|F) | ||||
SSH_OPTS="${SSH_OPTS:+$SSH_OPTS }$OPT '$(quote "$OPTARG")'" | SSH_OPTS="${SSH_OPTS:+$SSH_OPTS }-$OPT '$(quote "${OPTARG}")'" | ||||
;; | ;; | ||||
-f) | f) | ||||
FORCED=1 | FORCED=1 | ||||
;; | ;; | ||||
-n) | n) | ||||
DRY_RUN=1 | DRY_RUN=1 | ||||
;; | ;; | ||||
-h|-\?) | h|\?) | ||||
usage | usage | ||||
;; | ;; | ||||
esac | esac | ||||
done | done | ||||
#shift all args to keep only USER_HOST | |||||
shift $((OPTIND-1)) | |||||
eval set -- "$SAVEARGS" | |||||
if [ $# = 0 ] ; then | if [ $# = 0 ] ; then | ||||
usage | usage | ||||
fi | fi | ||||
if [ $# != 1 ] ; then | if [ $# != 1 ] ; then | ||||
printf '%s: ERROR: Too many arguments. Expecting a target hostname, got: %s\n\n' "$0" "$SAVEARGS" >&2 | printf '%s: ERROR: Too many arguments. Expecting a target hostname, got: %s\n\n' "$0" "$SAVEARGS" >&2 | ||||
usage | usage | ||||
fi | fi | ||||
# drop trailing colon | # drop trailing colon | ||||
USER_HOST=$(printf "%s\n" "$1" | sed 's/:$//') | USER_HOST="$*" | ||||
# tack the hostname onto SSH_OPTS | # tack the hostname onto SSH_OPTS | ||||
SSH_OPTS="${SSH_OPTS:+$SSH_OPTS }'$(quote "$USER_HOST")'" | SSH_OPTS="${SSH_OPTS:+$SSH_OPTS }'$(quote "$USER_HOST")'" | ||||
# and populate "$@" for later use (only way to get proper quoting of options) | # and populate "$@" for later use (only way to get proper quoting of options) | ||||
eval set -- "$SSH_OPTS" | eval set -- "$SSH_OPTS" | ||||
# shellcheck disable=SC2086 | |||||
if [ -z "$(eval $GET_ID)" ] && [ -r "${PUB_ID_FILE:=$DEFAULT_PUB_ID_FILE}" ] ; then | if [ -z "$(eval $GET_ID)" ] && [ -r "${PUB_ID_FILE:=$DEFAULT_PUB_ID_FILE}" ] ; then | ||||
use_id_file "$PUB_ID_FILE" | use_id_file "$PUB_ID_FILE" | ||||
fi | fi | ||||
# shellcheck disable=SC2086 | |||||
if [ -z "$(eval $GET_ID)" ] ; then | if [ -z "$(eval $GET_ID)" ] ; then | ||||
printf '%s: ERROR: No identities found\n' "$0" >&2 | printf '%s: ERROR: No identities found\n' "$0" >&2 | ||||
exit 1 | exit 1 | ||||
fi | fi | ||||
# populate_new_ids() uses several global variables ($USER_HOST, $SSH_OPTS ...) | # populate_new_ids() uses several global variables ($USER_HOST, $SSH_OPTS ...) | ||||
# and has the side effect of setting $NEW_IDS | # and has the side effect of setting $NEW_IDS | ||||
populate_new_ids() { | populate_new_ids() { | ||||
local L_SUCCESS="$1" | local L_SUCCESS="$1" | ||||
# shellcheck disable=SC2086 | |||||
if [ "$FORCED" ] ; then | if [ "$FORCED" ] ; then | ||||
NEW_IDS=$(eval $GET_ID) | NEW_IDS=$(eval $GET_ID) | ||||
return | return | ||||
fi | fi | ||||
# repopulate "$@" inside this function | # repopulate "$@" inside this function | ||||
eval set -- "$SSH_OPTS" | eval set -- "$SSH_OPTS" | ||||
umask 0177 | umask 0177 | ||||
local L_TMP_ID_FILE=$(mktemp ~/.ssh/ssh-copy-id_id.XXXXXXXXXX) | local L_TMP_ID_FILE | ||||
L_TMP_ID_FILE=$(mktemp ~/.ssh/ssh-copy-id_id.XXXXXXXXXX) | |||||
if test $? -ne 0 || test "x$L_TMP_ID_FILE" = "x" ; then | if test $? -ne 0 || test "x$L_TMP_ID_FILE" = "x" ; then | ||||
printf '%s: ERROR: mktemp failed\n' "$0" >&2 | printf '%s: ERROR: mktemp failed\n' "$0" >&2 | ||||
exit 1 | exit 1 | ||||
fi | fi | ||||
local L_CLEANUP="rm -f \"$L_TMP_ID_FILE\" \"${L_TMP_ID_FILE}.stderr\"" | local L_CLEANUP="rm -f \"$L_TMP_ID_FILE\" \"${L_TMP_ID_FILE}.stderr\"" | ||||
# shellcheck disable=SC2064 | |||||
trap "$L_CLEANUP" EXIT TERM INT QUIT | trap "$L_CLEANUP" EXIT TERM INT QUIT | ||||
printf '%s: INFO: attempting to log in with the new key(s), to filter out any that are already installed\n' "$0" >&2 | printf '%s: INFO: attempting to log in with the new key(s), to filter out any that are already installed\n' "$0" >&2 | ||||
# shellcheck disable=SC2086 | |||||
NEW_IDS=$( | NEW_IDS=$( | ||||
eval $GET_ID | { | eval $GET_ID | { | ||||
while read ID || [ "$ID" ] ; do | while read -r ID || [ "$ID" ] ; do | ||||
printf '%s\n' "$ID" > "$L_TMP_ID_FILE" | printf '%s\n' "$ID" > "$L_TMP_ID_FILE" | ||||
# the next line assumes $PRIV_ID_FILE only set if using a single id file - this | # the next line assumes $PRIV_ID_FILE only set if using a single id file - this | ||||
# assumption will break if we implement the possibility of multiple -i options. | # assumption will break if we implement the possibility of multiple -i options. | ||||
# The point being that if file based, ssh needs the private key, which it cannot | # The point being that if file based, ssh needs the private key, which it cannot | ||||
# find if only given the contents of the .pub file in an unrelated tmpfile | # find if only given the contents of the .pub file in an unrelated tmpfile | ||||
ssh -i "${PRIV_ID_FILE:-$L_TMP_ID_FILE}" \ | ssh -i "${PRIV_ID_FILE:-$L_TMP_ID_FILE}" \ | ||||
-o ControlPath=none \ | -o ControlPath=none \ | ||||
Show All 16 Lines | populate_new_ids() { | ||||
eval "$L_CLEANUP" && trap - EXIT TERM INT QUIT | eval "$L_CLEANUP" && trap - EXIT TERM INT QUIT | ||||
if expr "$NEW_IDS" : "^ERROR: " >/dev/null ; then | if expr "$NEW_IDS" : "^ERROR: " >/dev/null ; then | ||||
printf '\n%s: %s\n\n' "$0" "$NEW_IDS" >&2 | printf '\n%s: %s\n\n' "$0" "$NEW_IDS" >&2 | ||||
exit 1 | exit 1 | ||||
fi | fi | ||||
if [ -z "$NEW_IDS" ] ; then | if [ -z "$NEW_IDS" ] ; then | ||||
printf '\n%s: WARNING: All keys were skipped because they already exist on the remote system.\n' "$0" >&2 | printf '\n%s: WARNING: All keys were skipped because they already exist on the remote system.\n' "$0" >&2 | ||||
printf '\t\t(if you think this is a mistake, you may want to use -f option)\n\n' "$0" >&2 | printf '\t\t(if you think this is a mistake, you may want to use -f option)\n\n' >&2 | ||||
exit 0 | exit 0 | ||||
fi | fi | ||||
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 | 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 | ||||
} | } | ||||
# installkey_sh [target_path] | |||||
# produce a one-liner to add the keys to remote authorized_keys file | |||||
# optionally takes an alternative path for authorized_keys | |||||
installkeys_sh() { | |||||
local AUTH_KEY_FILE=${1:-.ssh/authorized_keys} | |||||
# In setting INSTALLKEYS_SH: | |||||
# the tr puts it all on one line (to placate tcsh) | |||||
# (hence the excessive use of semi-colons (;) ) | |||||
# then in the command: | |||||
# cd to be at $HOME, just in case; | |||||
# the -z `tail ...` checks for a trailing newline. The echo adds one if was missing | |||||
# the cat adds the keys we're getting via STDIN | |||||
# and if available restorecon is used to restore the SELinux context | |||||
INSTALLKEYS_SH=$(tr '\t\n' ' ' <<-EOF) | |||||
cd; | |||||
umask 077; | |||||
mkdir -p $(dirname "${AUTH_KEY_FILE}") && | |||||
{ [ -z \`tail -1c ${AUTH_KEY_FILE} 2>/dev/null\` ] || echo >> ${AUTH_KEY_FILE}; } && | |||||
cat >> ${AUTH_KEY_FILE} || | |||||
exit 1; | |||||
if type restorecon >/dev/null 2>&1; then | |||||
restorecon -F .ssh ${AUTH_KEY_FILE}; | |||||
fi | |||||
EOF | |||||
# to defend against quirky remote shells: use 'exec sh -c' to get POSIX; | |||||
printf "exec sh -c '%s'" "${INSTALLKEYS_SH}" | |||||
} | |||||
REMOTE_VERSION=$(ssh -v -o PreferredAuthentications=',' -o ControlPath=none "$@" 2>&1 | | REMOTE_VERSION=$(ssh -v -o PreferredAuthentications=',' -o ControlPath=none "$@" 2>&1 | | ||||
sed -ne 's/.*remote software version //p') | sed -ne 's/.*remote software version //p') | ||||
# shellcheck disable=SC2029 | |||||
case "$REMOTE_VERSION" in | case "$REMOTE_VERSION" in | ||||
NetScreen*) | NetScreen*) | ||||
populate_new_ids 1 | populate_new_ids 1 | ||||
for KEY in $(printf "%s" "$NEW_IDS" | cut -d' ' -f2) ; do | for KEY in $(printf "%s" "$NEW_IDS" | cut -d' ' -f2) ; do | ||||
KEY_NO=$(($KEY_NO + 1)) | KEY_NO=$((KEY_NO + 1)) | ||||
printf "%s\n" "$KEY" | grep ssh-dss >/dev/null || { | printf '%s\n' "$KEY" | grep ssh-dss >/dev/null || { | ||||
printf '%s: WARNING: Non-dsa key (#%d) skipped (NetScreen only supports DSA keys)\n' "$0" "$KEY_NO" >&2 | printf '%s: WARNING: Non-dsa key (#%d) skipped (NetScreen only supports DSA keys)\n' "$0" "$KEY_NO" >&2 | ||||
continue | continue | ||||
} | } | ||||
[ "$DRY_RUN" ] || printf 'set ssh pka-dsa key %s\nsave\nexit\n' "$KEY" | ssh -T "$@" >/dev/null 2>&1 | [ "$DRY_RUN" ] || printf 'set ssh pka-dsa key %s\nsave\nexit\n' "$KEY" | ssh -T "$@" >/dev/null 2>&1 | ||||
if [ $? = 255 ] ; then | if [ $? = 255 ] ; then | ||||
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 | 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 | ||||
else | else | ||||
ADDED=$(($ADDED + 1)) | ADDED=$((ADDED + 1)) | ||||
fi | fi | ||||
done | done | ||||
if [ -z "$ADDED" ] ; then | if [ -z "$ADDED" ] ; then | ||||
exit 1 | exit 1 | ||||
fi | fi | ||||
;; | ;; | ||||
dropbear*) | |||||
populate_new_ids 0 | |||||
[ "$DRY_RUN" ] || printf '%s\n' "$NEW_IDS" | \ | |||||
ssh "$@" "$(installkeys_sh /etc/dropbear/authorized_keys)" \ | |||||
|| exit 1 | |||||
ADDED=$(printf '%s\n' "$NEW_IDS" | wc -l) | |||||
;; | |||||
*) | *) | ||||
# Assuming that the remote host treats ~/.ssh/authorized_keys as one might expect | # Assuming that the remote host treats ~/.ssh/authorized_keys as one might expect | ||||
populate_new_ids 0 | populate_new_ids 0 | ||||
# in ssh below - to defend against quirky remote shells: use 'exec sh -c' to get POSIX; | |||||
# 'cd' to be at $HOME; add a newline if it's missing; and all on one line, because tcsh. | |||||
[ "$DRY_RUN" ] || printf '%s\n' "$NEW_IDS" | \ | [ "$DRY_RUN" ] || printf '%s\n' "$NEW_IDS" | \ | ||||
ssh "$@" "exec sh -c 'cd ; umask 077 ; mkdir -p .ssh && { [ -z "'`tail -1c .ssh/authorized_keys 2>/dev/null`'" ] || echo >> .ssh/authorized_keys ; } && cat >> .ssh/authorized_keys || exit 1 ; if type restorecon >/dev/null 2>&1 ; then restorecon -F .ssh .ssh/authorized_keys ; fi'" \ | ssh "$@" "$(installkeys_sh)" \ | ||||
|| exit 1 | || exit 1 | ||||
ADDED=$(printf '%s\n' "$NEW_IDS" | wc -l) | ADDED=$(printf '%s\n' "$NEW_IDS" | wc -l) | ||||
;; | ;; | ||||
esac | esac | ||||
if [ "$DRY_RUN" ] ; then | if [ "$DRY_RUN" ] ; then | ||||
cat <<-EOF | cat <<-EOF | ||||
=-=-=-=-=-=-=-= | =-=-=-=-=-=-=-= | ||||
Show All 17 Lines |