X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/259d88d94843fbce7c8100f8b337b7b8fb58b840..4b30c1dc053278a6b9bdb50f0d91b3f934e8613d:/cmdline/apt-key.in diff --git a/cmdline/apt-key.in b/cmdline/apt-key.in index 463e4b4b4..9adbd6443 100644 --- a/cmdline/apt-key.in +++ b/cmdline/apt-key.in @@ -5,22 +5,23 @@ unset GREP_OPTIONS GPG_CMD="gpg --ignore-time-conflict --no-options --no-default-keyring" -# gpg needs a trustdb to function, but it can't be invalid (not even empty) -# so we create a temporary directory to store our fresh readable trustdb in -TRUSTDBDIR="$(mktemp -d)" -CURRENTTRAP="${CURRENTTRAP} rm -rf '${TRUSTDBDIR}';" +# gpg needs (in different versions more or less) files to function correctly, +# so we give it its own homedir and generate some valid content for it +GPGHOMEDIR="$(mktemp -d)" +CURRENTTRAP="${CURRENTTRAP} rm -rf '${GPGHOMEDIR}';" trap "${CURRENTTRAP}" 0 HUP INT QUIT ILL ABRT FPE SEGV PIPE TERM -chmod 700 "$TRUSTDBDIR" -# We also don't use a secret keyring, of course, but gpg panics and +chmod 700 "$GPGHOMEDIR" +# We don't use a secret keyring, of course, but gpg panics and # implodes if there isn't one available - and writeable for imports -SECRETKEYRING="${TRUSTDBDIR}/secring.gpg" +SECRETKEYRING="${GPGHOMEDIR}/secring.gpg" touch $SECRETKEYRING -GPG_CMD="$GPG_CMD --secret-keyring $SECRETKEYRING" -GPG_CMD="$GPG_CMD --trustdb-name ${TRUSTDBDIR}/trustdb.gpg" - -# now create the trustdb with an (empty) dummy keyring -$GPG_CMD --quiet --check-trustdb --keyring $SECRETKEYRING -# and make sure that gpg isn't trying to update the file +GPG_CMD="$GPG_CMD --homedir $GPGHOMEDIR" +# create the trustdb with an (empty) dummy keyring +# older gpgs required it, newer gpgs even warn that it isn't needed, +# but require it nonetheless for some commands, so we just play safe +# here for the foreseeable future and create a dummy one +$GPG_CMD --quiet --check-trustdb --keyring $SECRETKEYRING >/dev/null 2>&1 +# tell gpg that it shouldn't try to maintain a trustdb file GPG_CMD="$GPG_CMD --no-auto-check-trustdb --trust-model always" GPG="$GPG_CMD" @@ -38,33 +39,25 @@ ARCHIVE_KEYRING_URI='&keyring-uri;' eval $(apt-config shell ARCHIVE_KEYRING_URI APT::Key::ArchiveKeyringURI) TMP_KEYRING=${APT_DIR}/var/lib/apt/keyrings/maybe-import-keyring.gpg +aptkey_echo() { echo "$@"; } + requires_root() { if [ "$(id -u)" -ne 0 ]; then - echo >&1 "ERROR: This command can only be used by root." + echo >&2 "ERROR: This command can only be used by root." exit 1 fi } -# gpg defaults to mode 0600 for new keyrings. Create one with 0644 instead. -init_keyring() { - for path; do - if ! [ -e "$path" ]; then - touch -- "$path" - chmod 0644 -- "$path" - fi - done -} - add_keys_with_verify_against_master_keyring() { ADD_KEYRING=$1 MASTER=$2 if [ ! -f "$ADD_KEYRING" ]; then - echo "ERROR: '$ADD_KEYRING' not found" + echo >&2 "ERROR: '$ADD_KEYRING' not found" return - fi + fi if [ ! -f "$MASTER" ]; then - echo "ERROR: '$MASTER' not found" + echo >&2 "ERROR: '$MASTER' not found" return fi @@ -141,7 +134,7 @@ net_update() { fi new_mtime=$(stat -c %Y $keyring) if [ $new_mtime -ne $old_mtime ]; then - echo "Checking for new archive signing keys now" + aptkey_echo "Checking for new archive signing keys now" add_keys_with_verify_against_master_keyring $keyring $MASTER_KEYRING fi } @@ -172,65 +165,74 @@ update() { fi done else - echo "Warning: removed keys keyring $REMOVED_KEYS missing or not readable" >&2 + echo >&2 "Warning: removed keys keyring $REMOVED_KEYS missing or not readable" fi } remove_key_from_keyring() { - local GPG="$GPG_CMD --keyring $1" - # check if the key is in this keyring: the key id is in the 5 column at the end - if ! $GPG --with-colons --list-keys 2>&1 | grep -q "^pub:[^:]*:[^:]*:[^:]*:[0-9A-F]\+$2:"; then - return - fi - if [ ! -w "$1" ]; then - echo >&2 "Key ${2} is in keyring ${1}, but can't be removed as it is read only." - return - fi - # check if it is the only key in the keyring and if so remove the keyring alltogether - if [ '1' = "$($GPG --with-colons --list-keys | grep "^pub:[^:]*:[^:]*:[^:]*:[0-9A-F]\+:" | wc -l)" ]; then - mv -f "$1" "${1}~" # behave like gpg - return - fi - # we can't just modify pointed to files as these might be in /usr or something - local REALTARGET - if [ -L "$1" ]; then - REALTARGET="$(readlink -f "$1")" - mv -f "$1" "${1}.dpkg-tmp" - cp -a "$REALTARGET" "$1" - ls "$(dirname $1)" - fi - # delete the key from the keyring - $GPG --batch --delete-key --yes "$2" - if [ -n "$REALTARGET" ]; then - # the real backup is the old link, not the copy we made - mv -f "${1}.dpkg-tmp" "${1}~" - fi + local KEYRINGFILE="$1" + shift + local GPG="$GPG_CMD --keyring $KEYRINGFILE" + while [ -n "$1" ]; do + local KEY="$1" + shift + # check if the key is in this keyring: the key id is in the 5 column at the end + if ! $GPG --with-colons --list-keys 2>&1 | grep -q "^pub:[^:]*:[^:]*:[^:]*:[0-9A-F]\+${KEY}:"; then + continue + fi + if [ ! -w "$KEYRINGFILE" ]; then + echo >&2 "Key ${KEY} is in keyring ${KEYRINGFILE}, but can't be removed as it is read only." + continue + fi + # check if it is the only key in the keyring and if so remove the keyring altogether + if [ '1' = "$($GPG --with-colons --list-keys | grep "^pub:[^:]*:[^:]*:[^:]*:[0-9A-F]\+:" | wc -l)" ]; then + mv -f "$KEYRINGFILE" "${KEYRINGFILE}~" # behave like gpg + return + fi + # we can't just modify pointed to files as these might be in /usr or something + local REALTARGET + if [ -L "$KEYRINGFILE" ]; then + REALTARGET="$(readlink -f "$KEYRINGFILE")" + mv -f "$KEYRINGFILE" "${KEYRINGFILE}.dpkg-tmp" + cp -a "$REALTARGET" "$KEYRINGFILE" + fi + # delete the key from the keyring + $GPG --batch --delete-key --yes "$KEY" + if [ -n "$REALTARGET" ]; then + # the real backup is the old link, not the copy we made + mv -f "${KEYRINGFILE}.dpkg-tmp" "${KEYRINGFILE}~" + fi + done } remove_key() { requires_root + foreach_keyring_do 'remove_key_from_keyring' "$@" + aptkey_echo "OK" + } - # if a --keyring was given, just remove from there - if [ -n "$FORCED_KEYRING" ]; then - remove_key_from_keyring "$FORCED_KEYRING" "$1" - else +foreach_keyring_do() { + local ACTION="$1" + shift + # if a --keyring was given, just remove from there + if [ -n "$FORCED_KEYRING" ]; then + $ACTION "$FORCED_KEYRING" "$@" + else # otherwise all known keyrings are up for inspection local TRUSTEDFILE="/etc/apt/trusted.gpg" eval $(apt-config shell TRUSTEDFILE Apt::GPGV::TrustedKeyring) eval $(apt-config shell TRUSTEDFILE Dir::Etc::Trusted/f) - remove_key_from_keyring "$TRUSTEDFILE" "$1" - TRUSTEDPARTS="/etc/apt/trusted.gpg.d" + $ACTION "$TRUSTEDFILE" "$@" + local TRUSTEDPARTS="/etc/apt/trusted.gpg.d" eval $(apt-config shell TRUSTEDPARTS Dir::Etc::TrustedParts/d) if [ -d "$TRUSTEDPARTS" ]; then for trusted in $(run-parts --list "$TRUSTEDPARTS" --regex '^.*\.gpg$'); do - remove_key_from_keyring "$trusted" "$1" + $ACTION "$trusted" "$@" done fi - fi - echo "OK" + fi } - usage() { echo "Usage: apt-key [--keyring file] [command] [arguments]" echo @@ -267,6 +269,10 @@ while [ -n "$1" ]; do requires_root() { true; } shift ;; + --quiet) + aptkey_echo() { true; } + shift + ;; --*) echo >&2 "Unknown option: $1" usage @@ -282,8 +288,8 @@ if [ -z "$TRUSTEDFILE" ]; then eval $(apt-config shell TRUSTEDFILE Dir::Etc::Trusted/f) if [ -r "$TRUSTEDFILE" ]; then GPG="$GPG --keyring $TRUSTEDFILE" + GPG="$GPG --primary-keyring $TRUSTEDFILE" fi - GPG="$GPG --primary-keyring $TRUSTEDFILE" TRUSTEDPARTS="/etc/apt/trusted.gpg.d" eval $(apt-config shell TRUSTEDPARTS Dir::Etc::TrustedParts/d) if [ -d "$TRUSTEDPARTS" ]; then @@ -305,51 +311,51 @@ if [ -z "$command" ]; then fi shift -if [ "$command" != "help" ] && ! which gpg >/dev/null 2>&1; then - echo >&2 "Warning: gnupg does not seem to be installed." - echo >&2 "Warning: apt-key requires gnupg for most operations." - echo >&2 +if [ "$command" != "help" ]; then + if ! which gpg >/dev/null 2>&1; then + echo >&2 "Warning: gnupg does not seem to be installed." + echo >&2 "Warning: apt-key requires gnupg for most operations." + echo >&2 + fi + + # gpg defaults to mode 0600 for new keyrings. Create one with 0644 instead. + if ! [ -e "$TRUSTEDFILE" ]; then + if [ -w "$(dirname "$TRUSTEDFILE")" ]; then + touch -- "$TRUSTEDFILE" + chmod 0644 -- "$TRUSTEDFILE" + GPG="$GPG --keyring $TRUSTEDFILE" + GPG="$GPG --primary-keyring $TRUSTEDFILE" + fi + fi fi case "$command" in add) requires_root - init_keyring "$TRUSTEDFILE" - $GPG --quiet --batch --import "$1" - echo "OK" + $GPG --quiet --batch --import "$@" + aptkey_echo "OK" ;; del|rm|remove) - init_keyring "$TRUSTEDFILE" - remove_key "$1" + remove_key "$@" ;; update) - init_keyring "$TRUSTEDFILE" update ;; net-update) - init_keyring "$TRUSTEDFILE" net_update ;; list) - init_keyring "$TRUSTEDFILE" - $GPG --batch --list-keys + $GPG --batch --list-keys "$@" ;; finger*) - init_keyring "$TRUSTEDFILE" - $GPG --batch --fingerprint - ;; - export) - init_keyring "$TRUSTEDFILE" - $GPG --armor --export "$1" + $GPG --batch --fingerprint "$@" ;; - exportall) - init_keyring "$TRUSTEDFILE" - $GPG --armor --export + export|exportall) + $GPG --armor --export "$@" ;; adv*) - init_keyring "$TRUSTEDFILE" - echo "Executing: $GPG $*" - $GPG $* + aptkey_echo "Executing: $GPG $*" + $GPG "$@" ;; help) usage