]> git.saurik.com Git - apt.git/blobdiff - cmdline/apt-key.in
refactor key removal code to reuse it in next step
[apt.git] / cmdline / apt-key.in
index 463e4b4b49ea588c81c5100eff8ece216912285b..9adbd6443eea08667619ce9df57348619130cfa1 100644 (file)
@@ -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