]> git.saurik.com Git - apt.git/commitdiff
merge fragment keyrings in apt-key to avoid hitting gpg limits
authorDavid Kalnischkies <david@kalnischkies.de>
Fri, 24 Jan 2014 21:40:52 +0000 (22:40 +0100)
committerDavid Kalnischkies <david@kalnischkies.de>
Fri, 26 Sep 2014 22:12:14 +0000 (00:12 +0200)
gnupg has a hardlimit of 40 (at the moment) keyrings per invocation,
which can be exceeded with (many) repositories. That is rather
misfortune as the longrun goal was to drop gnupg dependency at some
point in the future, but this can now be considered missed and dropped.

It also means that 'apt-key adv' commands might not have the behaviour
one would expect it to have as it mainly operates on a big temporary
keyring, so commands modifying keys will break. Doing this was never a
good idea anyway through, so lets just hope nothing break too badly.

Closes: 733028
cmdline/apt-key.in

index 9adbd6443eea08667619ce9df57348619130cfa1..9d8e60ec04bab70f3f512ac24a14ef598d5c3488 100644 (file)
@@ -23,7 +23,6 @@ GPG_CMD="$GPG_CMD --homedir $GPGHOMEDIR"
 $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"
 
 APT_DIR="/"
@@ -113,7 +112,6 @@ net_update() {
        echo >&2 "ERROR: Your distribution is not supported in net-update as no uri for the archive-keyring is set"
        exit 1
     fi
-    requires_root
     # in theory we would need to depend on wget for this, but this feature
     # isn't useable in debian anyway as we have no keyring uri nor a master key
     if ! which wget >/dev/null 2>&1; then
@@ -145,7 +143,6 @@ update() {
        echo >&2 "Is the &keyring-package; package installed?"
        exit 1
     fi
-    requires_root
 
     # add new keys from the package;
 
@@ -158,11 +155,8 @@ update() {
 
     if [ -r "$REMOVED_KEYS" ]; then
        # remove no-longer supported/used keys
-       keys=`$GPG_CMD --keyring $REMOVED_KEYS --with-colons --list-keys | grep ^pub | cut -d: -f5`
-       for key in $keys; do
-           if $GPG --list-keys --with-colons | grep ^pub | cut -d: -f5 | grep -q $key; then
-               $GPG --quiet --batch --delete-key --yes ${key}
-           fi
+       $GPG_CMD --keyring $REMOVED_KEYS --with-colons --list-keys | grep ^pub | cut -d: -f5 | while read key; do
+           foreach_keyring_do 'remove_key_from_keyring' "$key"
        done
     else
        echo >&2 "Warning: removed keys keyring  $REMOVED_KEYS missing or not readable"
@@ -172,12 +166,17 @@ update() {
 remove_key_from_keyring() {
     local KEYRINGFILE="$1"
     shift
+    # non-existent keyrings have by definition no keys
+    if [ ! -e "$KEYRINGFILE" ]; then
+       return
+    fi
+
     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
+       if ! $GPG --with-colons --list-keys 2>&1 | grep -q "^pub:[^:]*:[^:]*:[^:]*:[0-9A-F]*${KEY}:"; then
            continue
        fi
        if [ ! -w "$KEYRINGFILE" ]; then
@@ -205,12 +204,6 @@ remove_key_from_keyring() {
     done
 }
 
-remove_key() {
-    requires_root
-    foreach_keyring_do 'remove_key_from_keyring' "$@"
-    aptkey_echo "OK"
- }
-
 foreach_keyring_do() {
    local ACTION="$1"
    shift
@@ -219,20 +212,62 @@ foreach_keyring_do() {
        $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)
-       $ACTION "$TRUSTEDFILE" "$@"
+       if [ -s "$TRUSTEDFILE" ]; then
+           $ACTION "$TRUSTEDFILE" "$@"
+       fi
        local TRUSTEDPARTS="/etc/apt/trusted.gpg.d"
        eval $(apt-config shell TRUSTEDPARTS Dir::Etc::TrustedParts/d)
        if [ -d "$TRUSTEDPARTS" ]; then
+           # strip / suffix as gpg will double-slash in that case (#665411)
+           local STRIPPED_TRUSTEDPARTS="${TRUSTEDPARTS%/}"
+           if [ "${STRIPPED_TRUSTEDPARTS}/" = "$TRUSTEDPARTS" ]; then
+               TRUSTEDPARTS="$STRIPPED_TRUSTEDPARTS"
+           fi
            for trusted in $(run-parts --list "$TRUSTEDPARTS" --regex '^.*\.gpg$'); do
-               $ACTION "$trusted" "$@"
+               if [ -s "$trusted" ]; then
+                   $ACTION "$trusted" "$@"
+               fi
            done
        fi
    fi
 }
 
+list_keys_from_keyring() {
+    local KEYRINGFILE="$1"
+    shift
+    # don't show the error message if this keyring doesn't include the key
+    $GPG_CMD --keyring "$KEYRINGFILE" --batch --list-keys "$@" 2>/dev/null || true
+}
+
+fingerprint_keys_from_keyring() {
+    local KEYRINGFILE="$1"
+    shift
+    # don't show the error message if this keyring doesn't include the fingerprint
+    $GPG_CMD --keyring "$KEYRINGFILE" --batch --fingerprint "$@" 2>/dev/null || true
+}
+
+import_keys_from_keyring() {
+    local IMPORT="$1"
+    local KEYRINGFILE="$2"
+    $GPG_CMD --keyring "$KEYRINGFILE" --batch --import "$IMPORT" >/dev/null 2>&1
+}
+
+setup_merged_keyring() {
+    local TRUSTEDFILE_BAK="$TRUSTEDFILE"
+    TRUSTEDFILE='/dev/null'
+    foreach_keyring_do 'import_keys_from_keyring' "${GPGHOMEDIR}/trusted.gpg"
+    TRUSTEDFILE="$TRUSTEDFILE_BAK"
+    # mark it as non-writeable so users get errors if gnupg tries to modify it
+    if [ -s "${GPGHOMEDIR}/trusted.gpg" ]; then
+       chmod -w "${GPGHOMEDIR}/trusted.gpg"
+       GPG="$GPG --keyring ${GPGHOMEDIR}/trusted.gpg"
+    fi
+    if [ -r "$TRUSTEDFILE" ]; then
+       GPG="$GPG --keyring $TRUSTEDFILE --primary-keyring $TRUSTEDFILE"
+    fi
+}
+
+
 usage() {
     echo "Usage: apt-key [--keyring file] [command] [arguments]"
     echo
@@ -257,12 +292,6 @@ while [ -n "$1" ]; do
         shift
         TRUSTEDFILE="$1"
         FORCED_KEYRING="$1"
-        if [ -r "$TRUSTEDFILE" ] || [ "$2" = 'add' ] || [ "$2" = 'adv' ]; then
-           GPG="$GPG --keyring $TRUSTEDFILE --primary-keyring $TRUSTEDFILE"
-        else
-           echo >&2 "Error: The specified keyring »$TRUSTEDFILE« is missing or not readable"
-           exit 1
-        fi
         shift
         ;;
       --fakeroot)
@@ -286,22 +315,6 @@ if [ -z "$TRUSTEDFILE" ]; then
    TRUSTEDFILE="/etc/apt/trusted.gpg"
    eval $(apt-config shell TRUSTEDFILE Apt::GPGV::TrustedKeyring)
    eval $(apt-config shell TRUSTEDFILE Dir::Etc::Trusted/f)
-   if [ -r "$TRUSTEDFILE" ]; then
-      GPG="$GPG --keyring $TRUSTEDFILE"
-      GPG="$GPG --primary-keyring $TRUSTEDFILE"
-   fi
-   TRUSTEDPARTS="/etc/apt/trusted.gpg.d"
-   eval $(apt-config shell TRUSTEDPARTS Dir::Etc::TrustedParts/d)
-   if [ -d "$TRUSTEDPARTS" ]; then
-      # strip / suffix as gpg will double-slash in that case (#665411)
-      STRIPPED_TRUSTEDPARTS="${TRUSTEDPARTS%/}"
-      if [ "${STRIPPED_TRUSTEDPARTS}/" = "$TRUSTEDPARTS" ]; then
-        TRUSTEDPARTS="$STRIPPED_TRUSTEDPARTS"
-      fi
-      for trusted in $(run-parts --list "$TRUSTEDPARTS" --regex '^.*\.gpg$'); do
-        GPG="$GPG --keyring $trusted"
-      done
-   fi
 fi
 
 command="$1"
@@ -323,40 +336,47 @@ if [ "$command" != "help" ]; 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
-        $GPG --quiet --batch --import "$@"
-        aptkey_echo "OK"
+       requires_root
+       setup_merged_keyring
+       $GPG --quiet --batch --import "$@"
+       aptkey_echo "OK"
         ;;
     del|rm|remove)
-       remove_key "$@"
+       requires_root
+       foreach_keyring_do 'remove_key_from_keyring' "$@"
+       aptkey_echo "OK"
         ;;
     update)
+       requires_root
+       setup_merged_keyring
        update
        ;;
     net-update)
+       requires_root
+       setup_merged_keyring
        net_update
        ;;
     list)
-        $GPG --batch --list-keys "$@"
-        ;;
+       foreach_keyring_do 'list_keys_from_keyring' "$@"
+       ;;
     finger*)
-        $GPG --batch --fingerprint "$@"
-        ;;
+       foreach_keyring_do 'fingerprint_keys_from_keyring' "$@"
+       ;;
     export|exportall)
-        $GPG --armor --export "$@"
-        ;;
+       foreach_keyring_do 'import_keys_from_keyring' "${GPGHOMEDIR}/trusted.gpg"
+       $GPG_CMD --keyring "${GPGHOMEDIR}/trusted.gpg" --armor --export "$@"
+       ;;
     adv*)
-        aptkey_echo "Executing: $GPG $*"
-        $GPG "$@"
-        ;;
+       setup_merged_keyring
+       aptkey_echo "Executing: $GPG $*"
+       $GPG "$@"
+       ;;
     help)
         usage
         ;;