diff options
author | Colin Watson <cjwatson@debian.org> | 2013-05-07 11:47:26 +0100 |
---|---|---|
committer | Colin Watson <cjwatson@debian.org> | 2013-05-07 11:47:26 +0100 |
commit | 2ea3f720daeb1ca9f765365fce3a9546961fe624 (patch) | |
tree | c4fb7d1f51fa51e7677232de806aae150e29e2ac /contrib/ssh-copy-id | |
parent | f5efcd3450bbf8261915e0c4a6f851229dddaa79 (diff) | |
parent | ecebda56da46a03dafff923d91c382f31faa9eec (diff) |
* New upstream release (http://www.openssh.com/txt/release-6.2).
- Add support for multiple required authentication in SSH protocol 2 via
an AuthenticationMethods option (closes: #195716).
- Fix Sophie Germain formula in moduli(5) (closes: #698612).
- Update ssh-copy-id to Phil Hands' greatly revised version (closes:
#99785, #322228, #620428; LP: #518883, #835901, #1074798).
Diffstat (limited to 'contrib/ssh-copy-id')
-rw-r--r-- | contrib/ssh-copy-id | 309 |
1 files changed, 274 insertions, 35 deletions
diff --git a/contrib/ssh-copy-id b/contrib/ssh-copy-id index 86d037abd..af18a1929 100644 --- a/contrib/ssh-copy-id +++ b/contrib/ssh-copy-id | |||
@@ -1,54 +1,293 @@ | |||
1 | #!/bin/sh | 1 | #!/bin/sh |
2 | 2 | ||
3 | # Shell script to install your public key on a remote machine | 3 | # Copyright (c) 1999-2013 Philip Hands <phil@hands.com> |
4 | # Takes the remote machine name as an argument. | 4 | # 2013 Martin Kletzander <mkletzan@redhat.com> |
5 | # Obviously, the remote machine must accept password authentication, | 5 | # 2010 Adeodato =?iso-8859-1?Q?Sim=F3?= <asp16@alu.ua.es> |
6 | # or one of the other keys in your ssh-agent, for this to work. | 6 | # 2010 Eric Moret <eric.moret@gmail.com> |
7 | 7 | # 2009 Xr <xr@i-jeuxvideo.com> | |
8 | ID_FILE="${HOME}/.ssh/id_rsa.pub" | 8 | # 2007 Justin Pryzby <justinpryzby@users.sourceforge.net> |
9 | 9 | # 2004 Reini Urban <rurban@x-ray.at> | |
10 | if [ "-i" = "$1" ]; then | 10 | # 2003 Colin Watson <cjwatson@debian.org> |
11 | shift | 11 | # All rights reserved. |
12 | # check if we have 2 parameters left, if so the first is the new ID file | 12 | # |
13 | if [ -n "$2" ]; then | 13 | # Redistribution and use in source and binary forms, with or without |
14 | if expr "$1" : ".*\.pub" > /dev/null ; then | 14 | # modification, are permitted provided that the following conditions |
15 | ID_FILE="$1" | 15 | # are met: |
16 | else | 16 | # 1. Redistributions of source code must retain the above copyright |
17 | ID_FILE="$1.pub" | 17 | # notice, this list of conditions and the following disclaimer. |
18 | fi | 18 | # 2. Redistributions in binary form must reproduce the above copyright |
19 | shift # and this should leave $1 as the target name | 19 | # notice, this list of conditions and the following disclaimer in the |
20 | # documentation and/or other materials provided with the distribution. | ||
21 | # | ||
22 | # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||
23 | # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
24 | # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
25 | # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
26 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
27 | # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
28 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
29 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
30 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
31 | # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
32 | |||
33 | # Shell script to install your public key(s) on a remote machine | ||
34 | # See the ssh-copy-id(1) man page for details | ||
35 | |||
36 | # check that we have something mildly sane as our shell, or try to find something better | ||
37 | if false ^ printf "%s: WARNING: ancient shell, hunting for a more modern one... " "$0" | ||
38 | then | ||
39 | SANE_SH=${SANE_SH:-/usr/bin/ksh} | ||
40 | if printf 'true ^ false\n' | "$SANE_SH" | ||
41 | then | ||
42 | printf "'%s' seems viable.\n" "$SANE_SH" | ||
43 | exec "$SANE_SH" "$0" "$@" | ||
44 | else | ||
45 | cat <<-EOF | ||
46 | oh dear. | ||
47 | |||
48 | If you have a more recent shell available, that supports \$(...) etc. | ||
49 | please try setting the environment variable SANE_SH to the path of that | ||
50 | shell, and then retry running this script. If that works, please report | ||
51 | a bug describing your setup, and the shell you used to make it work. | ||
52 | |||
53 | EOF | ||
54 | printf "%s: ERROR: Less dimwitted shell required.\n" "$0" | ||
55 | exit 1 | ||
20 | fi | 56 | fi |
21 | else | 57 | fi |
22 | if [ x$SSH_AUTH_SOCK != x ] && ssh-add -L >/dev/null 2>&1; then | 58 | |
23 | GET_ID="$GET_ID ssh-add -L" | 59 | DEFAULT_PUB_ID_FILE=$(ls -t ${HOME}/.ssh/id*.pub 2>/dev/null | grep -v -- '-cert.pub$' | head -n 1) |
60 | |||
61 | usage () { | ||
62 | printf 'Usage: %s [-h|-?|-n] [-i [identity_file]] [-p port] [[-o <ssh -o options>] ...] [user@]hostname\n' "$0" >&2 | ||
63 | exit 1 | ||
64 | } | ||
65 | |||
66 | # escape any single quotes in an argument | ||
67 | quote() { | ||
68 | printf "%s\n" "$1" | sed -e "s/'/'\\\\''/g" | ||
69 | } | ||
70 | |||
71 | use_id_file() { | ||
72 | local L_ID_FILE="$1" | ||
73 | |||
74 | if expr "$L_ID_FILE" : ".*\.pub$" >/dev/null ; then | ||
75 | PUB_ID_FILE="$L_ID_FILE" | ||
76 | else | ||
77 | PUB_ID_FILE="$L_ID_FILE.pub" | ||
24 | fi | 78 | fi |
79 | |||
80 | PRIV_ID_FILE=$(dirname "$PUB_ID_FILE")/$(basename "$PUB_ID_FILE" .pub) | ||
81 | |||
82 | # check that the files are readable | ||
83 | for f in $PUB_ID_FILE $PRIV_ID_FILE ; do | ||
84 | 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/.*: *//')" | ||
86 | exit 1 | ||
87 | } | ||
88 | done | ||
89 | GET_ID="cat \"$PUB_ID_FILE\"" | ||
90 | } | ||
91 | |||
92 | if [ -n "$SSH_AUTH_SOCK" ] && ssh-add -L >/dev/null 2>&1 ; then | ||
93 | GET_ID="ssh-add -L" | ||
25 | fi | 94 | fi |
26 | 95 | ||
27 | if [ -z "`eval $GET_ID`" ] && [ -r "${ID_FILE}" ] ; then | 96 | while test "$#" -gt 0 |
28 | GET_ID="cat \"${ID_FILE}\"" | 97 | do |
98 | [ "${SEEN_OPT_I}" ] && expr "$1" : "[-]i" >/dev/null && { | ||
99 | printf "\n%s: ERROR: -i option must not be specified more than once\n\n" "$0" | ||
100 | usage | ||
101 | } | ||
102 | |||
103 | OPT= OPTARG= | ||
104 | # implement something like getopt to avoid Solaris pain | ||
105 | case "$1" in | ||
106 | -i?*|-o?*|-p?*) | ||
107 | OPT="$(printf -- "$1"|cut -c1-2)" | ||
108 | OPTARG="$(printf -- "$1"|cut -c3-)" | ||
109 | shift | ||
110 | ;; | ||
111 | -o|-p) | ||
112 | OPT="$1" | ||
113 | OPTARG="$2" | ||
114 | shift 2 | ||
115 | ;; | ||
116 | -i) | ||
117 | OPT="$1" | ||
118 | test "$#" -le 2 || expr "$2" : "[-]" >/dev/null || { | ||
119 | OPTARG="$2" | ||
120 | shift | ||
121 | } | ||
122 | shift | ||
123 | ;; | ||
124 | -n|-h|-\?) | ||
125 | OPT="$1" | ||
126 | OPTARG= | ||
127 | shift | ||
128 | ;; | ||
129 | --) | ||
130 | shift | ||
131 | while test "$#" -gt 0 | ||
132 | do | ||
133 | SAVEARGS="${SAVEARGS:+$SAVEARGS }'$(quote "$1")'" | ||
134 | shift | ||
135 | done | ||
136 | break | ||
137 | ;; | ||
138 | -*) | ||
139 | printf "\n%s: ERROR: invalid option (%s)\n\n" "$0" "$1" | ||
140 | usage | ||
141 | ;; | ||
142 | *) | ||
143 | SAVEARGS="${SAVEARGS:+$SAVEARGS }'$(quote "$1")'" | ||
144 | shift | ||
145 | continue | ||
146 | ;; | ||
147 | esac | ||
148 | |||
149 | case "$OPT" in | ||
150 | -i) | ||
151 | SEEN_OPT_I="yes" | ||
152 | use_id_file "${OPTARG:-$DEFAULT_PUB_ID_FILE}" | ||
153 | ;; | ||
154 | -o|-p) | ||
155 | SSH_OPTS="${SSH_OPTS:+$SSH_OPTS }$OPT '$(quote "$OPTARG")'" | ||
156 | ;; | ||
157 | -n) | ||
158 | DRY_RUN=1 | ||
159 | ;; | ||
160 | -h|-\?) | ||
161 | usage | ||
162 | ;; | ||
163 | esac | ||
164 | done | ||
165 | |||
166 | eval set -- "$SAVEARGS" | ||
167 | |||
168 | if [ $# != 1 ] ; then | ||
169 | printf '%s: ERROR: Too many arguments. Expecting a target hostname, got: %s\n\n' "$0" "$SAVEARGS" >&2 | ||
170 | usage | ||
29 | fi | 171 | fi |
30 | 172 | ||
31 | if [ -z "`eval $GET_ID`" ]; then | 173 | # drop trailing colon |
32 | echo "$0: ERROR: No identities found" >&2 | 174 | USER_HOST=$(printf "%s\n" "$1" | sed 's/:$//') |
33 | exit 1 | 175 | # tack the hostname onto SSH_OPTS |
176 | SSH_OPTS="${SSH_OPTS:+$SSH_OPTS }'$(quote "$USER_HOST")'" | ||
177 | # and populate "$@" for later use (only way to get proper quoting of options) | ||
178 | eval set -- "$SSH_OPTS" | ||
179 | |||
180 | if [ -z "$(eval $GET_ID)" ] && [ -r "${PUB_ID_FILE:=$DEFAULT_PUB_ID_FILE}" ] ; then | ||
181 | use_id_file "$PUB_ID_FILE" | ||
34 | fi | 182 | fi |
35 | 183 | ||
36 | if [ "$#" -lt 1 ] || [ "$1" = "-h" ] || [ "$1" = "--help" ]; then | 184 | if [ -z "$(eval $GET_ID)" ] ; then |
37 | echo "Usage: $0 [-i [identity_file]] [user@]machine" >&2 | 185 | printf '%s: ERROR: No identities found\n' "$0" >&2 |
38 | exit 1 | 186 | exit 1 |
39 | fi | 187 | fi |
40 | 188 | ||
41 | # strip any trailing colon | 189 | # populate_new_ids() uses several global variables ($USER_HOST, $SSH_OPTS ...) |
42 | host=`echo $1 | sed 's/:$//'` | 190 | # and has the side effect of setting $NEW_IDS |
191 | populate_new_ids() { | ||
192 | local L_SUCCESS="$1" | ||
43 | 193 | ||
44 | { eval "$GET_ID" ; } | ssh $host "umask 077; test -d ~/.ssh || mkdir ~/.ssh ; cat >> ~/.ssh/authorized_keys && (test -x /sbin/restorecon && /sbin/restorecon ~/.ssh ~/.ssh/authorized_keys >/dev/null 2>&1 || true)" || exit 1 | 194 | # repopulate "$@" inside this function |
195 | eval set -- "$SSH_OPTS" | ||
45 | 196 | ||
46 | cat <<EOF | 197 | umask 0177 |
47 | Now try logging into the machine, with "ssh '$host'", and check in: | 198 | local L_TMP_ID_FILE=$(mktemp ~/.ssh/ssh-copy-id_id.XXXXXXXXXX) |
199 | trap "rm -f $L_TMP_ID_FILE*" EXIT TERM INT QUIT | ||
200 | printf '%s: INFO: attempting to log in with the new key(s), to filter out any that are already installed\n' "$0" >&2 | ||
201 | NEW_IDS=$( | ||
202 | eval $GET_ID | { | ||
203 | while read ID ; do | ||
204 | printf '%s\n' "$ID" > $L_TMP_ID_FILE | ||
48 | 205 | ||
49 | ~/.ssh/authorized_keys | 206 | # the next line assumes $PRIV_ID_FILE only set if using a single id file - this |
207 | # assumption will break if we implement the possibility of multiple -i options. | ||
208 | # The point being that if file based, ssh needs the private key, which it cannot | ||
209 | # find if only given the contents of the .pub file in an unrelated tmpfile | ||
210 | ssh -i "${PRIV_ID_FILE:-$L_TMP_ID_FILE}" \ | ||
211 | -o PreferredAuthentications=publickey \ | ||
212 | -o IdentitiesOnly=yes "$@" exit 2>$L_TMP_ID_FILE.stderr </dev/null | ||
213 | if [ "$?" = "$L_SUCCESS" ] ; then | ||
214 | : > $L_TMP_ID_FILE | ||
215 | else | ||
216 | grep 'Permission denied' $L_TMP_ID_FILE.stderr >/dev/null || { | ||
217 | sed -e 's/^/ERROR: /' <$L_TMP_ID_FILE.stderr >$L_TMP_ID_FILE | ||
218 | cat >/dev/null #consume the other keys, causing loop to end | ||
219 | } | ||
220 | fi | ||
221 | |||
222 | cat $L_TMP_ID_FILE | ||
223 | done | ||
224 | } | ||
225 | ) | ||
226 | rm -f $L_TMP_ID_FILE* && trap - EXIT TERM INT QUIT | ||
227 | |||
228 | if expr "$NEW_IDS" : "^ERROR: " >/dev/null ; then | ||
229 | printf '\n%s: %s\n\n' "$0" "$NEW_IDS" >&2 | ||
230 | exit 1 | ||
231 | fi | ||
232 | if [ -z "$NEW_IDS" ] ; then | ||
233 | printf '\n%s: WARNING: All keys were skipped because they already exist on the remote system.\n\n' "$0" >&2 | ||
234 | exit 0 | ||
235 | fi | ||
236 | 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 | ||
237 | } | ||
50 | 238 | ||
51 | to make sure we haven't added extra keys that you weren't expecting. | 239 | REMOTE_VERSION=$(ssh -v -o PreferredAuthentications=',' "$@" 2>&1 | |
240 | sed -ne 's/.*remote software version //p') | ||
52 | 241 | ||
53 | EOF | 242 | case "$REMOTE_VERSION" in |
243 | NetScreen*) | ||
244 | populate_new_ids 1 | ||
245 | for KEY in $(printf "%s" "$NEW_IDS" | cut -d' ' -f2) ; do | ||
246 | KEY_NO=$(($KEY_NO + 1)) | ||
247 | printf "%s\n" "$KEY" | grep ssh-dss >/dev/null || { | ||
248 | printf '%s: WARNING: Non-dsa key (#%d) skipped (NetScreen only supports DSA keys)\n' "$0" "$KEY_NO" >&2 | ||
249 | continue | ||
250 | } | ||
251 | [ "$DRY_RUN" ] || printf 'set ssh pka-dsa key %s\nsave\nexit\n' "$KEY" | ssh -T "$@" >/dev/null 2>&1 | ||
252 | if [ $? = 255 ] ; then | ||
253 | 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 | ||
254 | else | ||
255 | ADDED=$(($ADDED + 1)) | ||
256 | fi | ||
257 | done | ||
258 | if [ -z "$ADDED" ] ; then | ||
259 | exit 1 | ||
260 | fi | ||
261 | ;; | ||
262 | *) | ||
263 | # Assuming that the remote host treats ~/.ssh/authorized_keys as one might expect | ||
264 | populate_new_ids 0 | ||
265 | [ "$DRY_RUN" ] || printf '%s\n' "$NEW_IDS" | ssh "$@" " | ||
266 | umask 077 ; | ||
267 | mkdir -p .ssh && cat >> .ssh/authorized_keys || exit 1 ; | ||
268 | if type restorecon >/dev/null 2>&1 ; then restorecon -F .ssh .ssh/authorized_keys ; fi" \ | ||
269 | || exit 1 | ||
270 | ADDED=$(printf '%s\n' "$NEW_IDS" | wc -l) | ||
271 | ;; | ||
272 | esac | ||
273 | |||
274 | if [ "$DRY_RUN" ] ; then | ||
275 | cat <<-EOF | ||
276 | =-=-=-=-=-=-=-= | ||
277 | Would have added the following key(s): | ||
278 | |||
279 | $NEW_IDS | ||
280 | =-=-=-=-=-=-=-= | ||
281 | EOF | ||
282 | else | ||
283 | cat <<-EOF | ||
284 | |||
285 | Number of key(s) added: $ADDED | ||
286 | |||
287 | Now try logging into the machine, with: "ssh $SSH_OPTS" | ||
288 | and check to make sure that only the key(s) you wanted were added. | ||
289 | |||
290 | EOF | ||
291 | fi | ||
54 | 292 | ||
293 | # =-=-=-= | ||