summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2016-02-16 10:34:39 +1100
committerDamien Miller <djm@mindrot.org>2016-02-16 10:34:39 +1100
commitef39e8c0497ff0564990a4f9e8b7338b3ba3507c (patch)
tree6c40198fb24b430ad1d20d2c623e58da08c0a72e
parentd2d772f55b19bb0e8d03c2fe1b9bb176d9779efd (diff)
sync ssh-copy-id with upstream 783ef08b0a75
-rw-r--r--contrib/ssh-copy-id53
-rw-r--r--contrib/ssh-copy-id.15
2 files changed, 40 insertions, 18 deletions
diff --git a/contrib/ssh-copy-id b/contrib/ssh-copy-id
index ae88e9958..afde8b170 100644
--- a/contrib/ssh-copy-id
+++ b/contrib/ssh-copy-id
@@ -56,10 +56,13 @@ then
56 fi 56 fi
57fi 57fi
58 58
59DEFAULT_PUB_ID_FILE=$(ls -t ${HOME}/.ssh/id*.pub 2>/dev/null | grep -v -- '-cert.pub$' | head -n 1) 59DEFAULT_PUB_ID_FILE="$HOME/$(cd "$HOME" ; ls -t .ssh/id*.pub 2>/dev/null | grep -v -- '-cert.pub$' | head -n 1)"
60 60
61usage () { 61usage () {
62 printf 'Usage: %s [-h|-?|-n] [-i [identity_file]] [-p port] [[-o <ssh -o options>] ...] [user@]hostname\n' "$0" >&2 62 printf 'Usage: %s [-h|-?|-f|-n] [-i [identity_file]] [-p port] [[-o <ssh -o options>] ...] [user@]hostname\n' "$0" >&2
63 printf '\t-f: force mode -- copy keys without trying to check if they are already installed\n' >&2
64 printf '\t-n: dry run -- no keys are actually copied\n' >&2
65 printf '\t-h|-?: print this help\n' >&2
63 exit 1 66 exit 1
64} 67}
65 68
@@ -77,15 +80,18 @@ use_id_file() {
77 PUB_ID_FILE="$L_ID_FILE.pub" 80 PUB_ID_FILE="$L_ID_FILE.pub"
78 fi 81 fi
79 82
80 PRIV_ID_FILE=$(dirname "$PUB_ID_FILE")/$(basename "$PUB_ID_FILE" .pub) 83 [ "$FORCED" ] || PRIV_ID_FILE=$(dirname "$PUB_ID_FILE")/$(basename "$PUB_ID_FILE" .pub)
81 84
82 # check that the files are readable 85 # check that the files are readable
83 for f in $PUB_ID_FILE $PRIV_ID_FILE ; do 86 for f in "$PUB_ID_FILE" ${PRIV_ID_FILE:+"$PRIV_ID_FILE"} ; do
84 ErrMSG=$( { : < $f ; } 2>&1 ) || { 87 ErrMSG=$( { : < "$f" ; } 2>&1 ) || {
85 printf "\n%s: ERROR: failed to open ID file '%s': %s\n\n" "$0" "$f" "$(printf "%s\n" "$ErrMSG" | sed -e 's/.*: *//')" 88 local L_PRIVMSG=""
89 [ "$f" = "$PRIV_ID_FILE" ] && L_PRIVMSG=" (to install the contents of '$PUB_ID_FILE' anyway, look at the -f option)"
90 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/.*: *//')"
86 exit 1 91 exit 1
87 } 92 }
88 done 93 done
94 printf '%s: INFO: Source of key(s) to be installed: "%s"\n' "$0" "$PUB_ID_FILE" >&2
89 GET_ID="cat \"$PUB_ID_FILE\"" 95 GET_ID="cat \"$PUB_ID_FILE\""
90} 96}
91 97
@@ -121,7 +127,7 @@ do
121 } 127 }
122 shift 128 shift
123 ;; 129 ;;
124 -n|-h|-\?) 130 -f|-n|-h|-\?)
125 OPT="$1" 131 OPT="$1"
126 OPTARG= 132 OPTARG=
127 shift 133 shift
@@ -154,6 +160,9 @@ do
154 -o|-p) 160 -o|-p)
155 SSH_OPTS="${SSH_OPTS:+$SSH_OPTS }$OPT '$(quote "$OPTARG")'" 161 SSH_OPTS="${SSH_OPTS:+$SSH_OPTS }$OPT '$(quote "$OPTARG")'"
156 ;; 162 ;;
163 -f)
164 FORCED=1
165 ;;
157 -n) 166 -n)
158 DRY_RUN=1 167 DRY_RUN=1
159 ;; 168 ;;
@@ -194,27 +203,35 @@ fi
194populate_new_ids() { 203populate_new_ids() {
195 local L_SUCCESS="$1" 204 local L_SUCCESS="$1"
196 205
206 if [ "$FORCED" ] ; then
207 NEW_IDS=$(eval $GET_ID)
208 return
209 fi
210
197 # repopulate "$@" inside this function 211 # repopulate "$@" inside this function
198 eval set -- "$SSH_OPTS" 212 eval set -- "$SSH_OPTS"
199 213
200 umask 0177 214 umask 0177
201 local L_TMP_ID_FILE=$(mktemp ~/.ssh/ssh-copy-id_id.XXXXXXXXXX) 215 local L_TMP_ID_FILE=$(mktemp ~/.ssh/ssh-copy-id_id.XXXXXXXXXX)
202 if test $? -ne 0 || test "x$L_TMP_ID_FILE" = "x" ; then 216 if test $? -ne 0 || test "x$L_TMP_ID_FILE" = "x" ; then
203 echo "mktemp failed" 1>&2 217 printf '%s: ERROR: mktemp failed\n' "$0" >&2
204 exit 1 218 exit 1
205 fi 219 fi
206 trap "rm -f $L_TMP_ID_FILE ${L_TMP_ID_FILE}.pub" EXIT TERM INT QUIT 220 local L_CLEANUP="rm -f \"$L_TMP_ID_FILE\" \"${L_TMP_ID_FILE}.stderr\""
221 trap "$L_CLEANUP" EXIT TERM INT QUIT
207 printf '%s: INFO: attempting to log in with the new key(s), to filter out any that are already installed\n' "$0" >&2 222 printf '%s: INFO: attempting to log in with the new key(s), to filter out any that are already installed\n' "$0" >&2
208 NEW_IDS=$( 223 NEW_IDS=$(
209 eval $GET_ID | { 224 eval $GET_ID | {
210 while read ID ; do 225 while read ID || [ "$ID" ] ; do
211 printf '%s\n' "$ID" > $L_TMP_ID_FILE 226 printf '%s\n' "$ID" > "$L_TMP_ID_FILE"
212 227
213 # the next line assumes $PRIV_ID_FILE only set if using a single id file - this 228 # the next line assumes $PRIV_ID_FILE only set if using a single id file - this
214 # assumption will break if we implement the possibility of multiple -i options. 229 # assumption will break if we implement the possibility of multiple -i options.
215 # The point being that if file based, ssh needs the private key, which it cannot 230 # The point being that if file based, ssh needs the private key, which it cannot
216 # find if only given the contents of the .pub file in an unrelated tmpfile 231 # find if only given the contents of the .pub file in an unrelated tmpfile
217 ssh -i "${PRIV_ID_FILE:-$L_TMP_ID_FILE}" \ 232 ssh -i "${PRIV_ID_FILE:-$L_TMP_ID_FILE}" \
233 -o ControlPath=none \
234 -o LogLevel=INFO \
218 -o PreferredAuthentications=publickey \ 235 -o PreferredAuthentications=publickey \
219 -o IdentitiesOnly=yes "$@" exit 2>$L_TMP_ID_FILE.stderr </dev/null 236 -o IdentitiesOnly=yes "$@" exit 2>$L_TMP_ID_FILE.stderr </dev/null
220 if [ "$?" = "$L_SUCCESS" ] ; then 237 if [ "$?" = "$L_SUCCESS" ] ; then
@@ -230,20 +247,21 @@ populate_new_ids() {
230 done 247 done
231 } 248 }
232 ) 249 )
233 rm -f $L_TMP_ID_FILE* && trap - EXIT TERM INT QUIT 250 eval "$L_CLEANUP" && trap - EXIT TERM INT QUIT
234 251
235 if expr "$NEW_IDS" : "^ERROR: " >/dev/null ; then 252 if expr "$NEW_IDS" : "^ERROR: " >/dev/null ; then
236 printf '\n%s: %s\n\n' "$0" "$NEW_IDS" >&2 253 printf '\n%s: %s\n\n' "$0" "$NEW_IDS" >&2
237 exit 1 254 exit 1
238 fi 255 fi
239 if [ -z "$NEW_IDS" ] ; then 256 if [ -z "$NEW_IDS" ] ; then
240 printf '\n%s: WARNING: All keys were skipped because they already exist on the remote system.\n\n' "$0" >&2 257 printf '\n%s: WARNING: All keys were skipped because they already exist on the remote system.\n' "$0" >&2
258 printf '\t\t(if you think this is a mistake, you may want to use -f option)\n\n' "$0" >&2
241 exit 0 259 exit 0
242 fi 260 fi
243 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 261 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
244} 262}
245 263
246REMOTE_VERSION=$(ssh -v -o PreferredAuthentications=',' "$@" 2>&1 | 264REMOTE_VERSION=$(ssh -v -o PreferredAuthentications=',' -o ControlPath=none "$@" 2>&1 |
247 sed -ne 's/.*remote software version //p') 265 sed -ne 's/.*remote software version //p')
248 266
249case "$REMOTE_VERSION" in 267case "$REMOTE_VERSION" in
@@ -269,10 +287,9 @@ case "$REMOTE_VERSION" in
269 *) 287 *)
270 # Assuming that the remote host treats ~/.ssh/authorized_keys as one might expect 288 # Assuming that the remote host treats ~/.ssh/authorized_keys as one might expect
271 populate_new_ids 0 289 populate_new_ids 0
272 [ "$DRY_RUN" ] || printf '%s\n' "$NEW_IDS" | ssh "$@" " 290 # in ssh below - to defend against quirky remote shells: use 'exec sh -c' to get POSIX; 'cd' to be at $HOME; and all on one line, because tcsh.
273 umask 077 ; 291 [ "$DRY_RUN" ] || printf '%s\n' "$NEW_IDS" | \
274 mkdir -p .ssh && cat >> .ssh/authorized_keys || exit 1 ; 292 ssh "$@" "exec sh -c 'cd ; umask 077 ; mkdir -p .ssh && cat >> .ssh/authorized_keys || exit 1 ; if type restorecon >/dev/null 2>&1 ; then restorecon -F .ssh .ssh/authorized_keys ; fi'" \
275 if type restorecon >/dev/null 2>&1 ; then restorecon -F .ssh .ssh/authorized_keys ; fi" \
276 || exit 1 293 || exit 1
277 ADDED=$(printf '%s\n' "$NEW_IDS" | wc -l) 294 ADDED=$(printf '%s\n' "$NEW_IDS" | wc -l)
278 ;; 295 ;;
diff --git a/contrib/ssh-copy-id.1 b/contrib/ssh-copy-id.1
index 67a59e492..8850cceda 100644
--- a/contrib/ssh-copy-id.1
+++ b/contrib/ssh-copy-id.1
@@ -29,6 +29,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29.Nd use locally available keys to authorise logins on a remote machine 29.Nd use locally available keys to authorise logins on a remote machine
30.Sh SYNOPSIS 30.Sh SYNOPSIS
31.Nm 31.Nm
32.Op Fl f
32.Op Fl n 33.Op Fl n
33.Op Fl i Op Ar identity_file 34.Op Fl i Op Ar identity_file
34.Op Fl p Ar port 35.Op Fl p Ar port
@@ -76,6 +77,10 @@ is used.
76Note that this can be used to ensure that the keys copied have the 77Note that this can be used to ensure that the keys copied have the
77comment one prefers and/or extra options applied, by ensuring that the 78comment one prefers and/or extra options applied, by ensuring that the
78key file has these set as preferred before the copy is attempted. 79key file has these set as preferred before the copy is attempted.
80.It Fl f
81Forced mode: doesn't check if the keys are present on the remote server.
82This means that it does not need the private key. Of course, this can result
83in more than one copy of the key being installed on the remote system.
79.It Fl n 84.It Fl n
80do a dry-run. Instead of installing keys on the remote system simply 85do a dry-run. Instead of installing keys on the remote system simply
81prints the key(s) that would have been installed. 86prints the key(s) that would have been installed.