Reproduced this on a fresh 24.04 LTS box (openssh-client 1:9.6p1) and
verified against 26.04.
Here is what happens:
1. Old key is authorized on the server, new key is not.
2. Run:
$ ssh-copy-id -o StrictHostKeyChecking=no -i /tmp/new_key.pub -o
IdentityFile=/tmp/old_key user@target
3. Output:
/usr/bin/ssh-copy-id: WARNING: All keys were skipped because they already
exist on the remote system.
(if you think this is a mistake, you may want to use -f option)
Checking authorized_keys confirms the new key was never copied.
Why this happens:
In filter_ids(), ssh-copy-id runs:
ssh -i "${PRIV_ID_FILE:-$L_TMP_ID_FILE}" -o PreferredAuthentications=publickey
-o IdentitiesOnly=yes "$@" exit
The script assumes IdentitiesOnly=yes tests only the new key from -i.
But per ssh_config(5), IdentitiesOnly still includes any IdentityFile
passed in "$@". So ssh happily logs in using the old key, exits 0, and
ssh-copy-id pats itself on the back thinking the new key is already
there.
Review of the Codex patch:
The logic of splitting option lists is actually spot on. However, typical AI
moment: it dropped the LOGIN_ID_OPT logic straight into the cat <<-EOF block,
so on execution it literally prints shell code to the user instead of running
it. Also, on 26.04 when using -f, PRIV_ID_FILE is unset, which left a dangling
"-i " flag in the suggested login command.
Here is the cleaned-up diff that fixes both the check and the login
hint:
--- /usr/bin/ssh-copy-id
+++ /usr/bin/ssh-copy-id
@@ -82,6 +82,18 @@
printf '%s\n' "$1" | sed -e "s/'/'\\\\''/g"
}
+identity_file_option() {
+ L_OPT_KEY=$(printf '%s\n' "$1" | sed 's/[[:space:]=].*//')
+
+ case "$L_OPT_KEY" in
+ [Ii][Dd][Ee][Nn][Tt][Ii][Tt][Yy][Ff][Ii][Ll][Ee])
+ return 0
+ ;;
+ esac
+
+ return 1
+}
+
use_id_file() {
L_ID_FILE="$1"
@@ -96,7 +108,8 @@
PUB_ID_FILE="$L_ID_FILE.pub"
fi
- [ "$FORCED" ] || PRIV_ID_FILE=$(dirname "$PUB_ID_FILE")/$(basename
"$PUB_ID_FILE" .pub)
+ SUGGEST_PRIV_ID_FILE=$(dirname "$PUB_ID_FILE")/$(basename "$PUB_ID_FILE"
.pub)
+ [ "$FORCED" ] || PRIV_ID_FILE="$SUGGEST_PRIV_ID_FILE"
# check that the files are readable
for f in "$PUB_ID_FILE" ${PRIV_ID_FILE:+"$PRIV_ID_FILE"} ; do
@@ -127,7 +140,20 @@
use_id_file "${OPTARG:-$DEFAULT_PUB_ID_FILE}"
;;
o|F)
- OPTS_oF="${OPTS_oF:+$OPTS_oF }-$OPT '$(quote "${OPTARG}")'"
+ Q_OPTARG=$(quote "${OPTARG}")
+ OPTS_oF="${OPTS_oF:+$OPTS_oF }-$OPT '$Q_OPTARG'"
+ case "$OPT" in
+ o)
+ if ! identity_file_option "$OPTARG" ; then
+ OPTS_FILTER_oF="${OPTS_FILTER_oF:+$OPTS_FILTER_oF }-$OPT
'$Q_OPTARG'"
+ OPTS_LOGIN_oF="${OPTS_LOGIN_oF:+$OPTS_LOGIN_oF }-$OPT '$Q_OPTARG'"
+ fi
+ ;;
+ F)
+ OPTS_FILTER_oF="${OPTS_FILTER_oF:+$OPTS_FILTER_oF }-$OPT '$Q_OPTARG'"
+ OPTS_LOGIN_oF="${OPTS_LOGIN_oF:+$OPTS_LOGIN_oF }-$OPT '$Q_OPTARG'"
+ ;;
+ esac
;;
f)
FORCED=1
@@ -167,6 +193,9 @@
USER_HOST="$*"
# tack the hostname onto SSH_OPTS
OPTS_USER_HOST="${OPTS_oF:+$OPTS_oF }'$(quote "$USER_HOST")'"
+OPTS_FILTER_USER_HOST="${OPTS_FILTER_oF:+$OPTS_FILTER_oF }'$(quote
"$USER_HOST")'"
+OPTS_LOGIN_USER_HOST="${OPTS_LOGIN_oF:+$OPTS_LOGIN_oF }'$(quote "$USER_HOST")'"
+SSH_FILTER_OPTS="${SSH_PORT:+-p $SSH_PORT }$OPTS_FILTER_USER_HOST"
SSH_OPTS="${SSH_PORT:+-p $SSH_PORT }$OPTS_USER_HOST"
# and populate "$@" for later use (only way to get proper quoting of options)
eval set -- "$SSH_OPTS"
@@ -190,7 +219,7 @@
L_OUTPUT_FILE="$SCRATCH_DIR"/popids_output
# repopulate "$@" inside this function
- eval set -- "$SSH_OPTS"
+ eval set -- "$SSH_FILTER_OPTS"
while read -r ID || [ "$ID" ] ; do
printf '%s\n' "$ID" > "$L_TMP_ID_FILE"
@@ -375,11 +404,15 @@
EOF
else
[ -z "$SFTP" ] || PORT_OPT=P
+ LOGIN_ID_OPT=
+ if [ "$SEEN_OPT_I" ] && [ "$SUGGEST_PRIV_ID_FILE" ] && [ -r
"$SUGGEST_PRIV_ID_FILE" ] ; then
+ LOGIN_ID_OPT="-i '$(quote "$SUGGEST_PRIV_ID_FILE")' "
+ fi
cat <<-EOF
Number of key(s) added: $ADDED
- Now try logging into the machine, with: "${SFTP:-ssh}${SSH_PORT:+
-${PORT_OPT:-p} $SSH_PORT} ${OPTS_USER_HOST}"
+ Now try logging into the machine, with: "${SFTP:-ssh}
${LOGIN_ID_OPT}${SSH_PORT:+-${PORT_OPT:-p} $SSH_PORT }${OPTS_LOGIN_USER_HOST}"
and check to make sure that only the key(s) you wanted were added.
EOF
Tested on the stand:
- Normal install with -o IdentityFile: installs properly.
- Space syntax (-o "IdentityFile ..."): works.
- Idempotency: second run detects existing key and skips as expected.
- Final login hint: outputs clean command without trailing empty flags.
Moving status to Confirmed.
--
You received this bug notification because you are a member of Ubuntu
Bugs, which is subscribed to Ubuntu.
https://bugs.launchpad.net/bugs/2161129
Title:
ssh-copy-id mix up identities with -i and -o
To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/openssh/+bug/2161129/+subscriptions
--
ubuntu-bugs mailing list
[email protected]
https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs