Просмотр исходного кода

merge fragment keyrings in apt-key to avoid hitting gpg limits

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
David Kalnischkies лет назад: 12
Родитель
Сommit
5beb682d2d
1 измененных файлов с 77 добавлено и 57 удалено
  1. 77 57
      cmdline/apt-key.in

+ 77 - 57
cmdline/apt-key.in

@@ -23,7 +23,6 @@ GPG_CMD="$GPG_CMD --homedir $GPGHOMEDIR"
 $GPG_CMD --quiet --check-trustdb --keyring $SECRETKEYRING >/dev/null 2>&1
 $GPG_CMD --quiet --check-trustdb --keyring $SECRETKEYRING >/dev/null 2>&1
 # tell gpg that it shouldn't try to maintain a trustdb file
 # tell gpg that it shouldn't try to maintain a trustdb file
 GPG_CMD="$GPG_CMD --no-auto-check-trustdb --trust-model always"
 GPG_CMD="$GPG_CMD --no-auto-check-trustdb --trust-model always"
-
 GPG="$GPG_CMD"
 GPG="$GPG_CMD"
 
 
 APT_DIR="/"
 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"
 	echo >&2 "ERROR: Your distribution is not supported in net-update as no uri for the archive-keyring is set"
 	exit 1
 	exit 1
     fi
     fi
-    requires_root
     # in theory we would need to depend on wget for this, but this feature
     # 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
     # isn't useable in debian anyway as we have no keyring uri nor a master key
     if ! which wget >/dev/null 2>&1; then
     if ! which wget >/dev/null 2>&1; then
@@ -145,7 +143,6 @@ update() {
 	echo >&2 "Is the &keyring-package; package installed?"
 	echo >&2 "Is the &keyring-package; package installed?"
 	exit 1
 	exit 1
     fi
     fi
-    requires_root
 
 
     # add new keys from the package;
     # add new keys from the package;
 
 
@@ -158,11 +155,8 @@ update() {
 
 
     if [ -r "$REMOVED_KEYS" ]; then
     if [ -r "$REMOVED_KEYS" ]; then
 	# remove no-longer supported/used keys
 	# 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
 	done
     else
     else
 	echo >&2 "Warning: removed keys keyring  $REMOVED_KEYS missing or not readable"
 	echo >&2 "Warning: removed keys keyring  $REMOVED_KEYS missing or not readable"
@@ -172,12 +166,17 @@ update() {
 remove_key_from_keyring() {
 remove_key_from_keyring() {
     local KEYRINGFILE="$1"
     local KEYRINGFILE="$1"
     shift
     shift
+    # non-existent keyrings have by definition no keys
+    if [ ! -e "$KEYRINGFILE" ]; then
+       return
+    fi
+
     local GPG="$GPG_CMD --keyring $KEYRINGFILE"
     local GPG="$GPG_CMD --keyring $KEYRINGFILE"
     while [ -n "$1" ]; do
     while [ -n "$1" ]; do
        local KEY="$1"
        local KEY="$1"
        shift
        shift
 	# check if the key is in this keyring: the key id is in the 5 column at the end
 	# 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
 	    continue
 	fi
 	fi
 	if [ ! -w "$KEYRINGFILE" ]; then
 	if [ ! -w "$KEYRINGFILE" ]; then
@@ -205,12 +204,6 @@ remove_key_from_keyring() {
     done
     done
 }
 }
 
 
-remove_key() {
-    requires_root
-    foreach_keyring_do 'remove_key_from_keyring' "$@"
-    aptkey_echo "OK"
- }
-
 foreach_keyring_do() {
 foreach_keyring_do() {
    local ACTION="$1"
    local ACTION="$1"
    shift
    shift
@@ -219,20 +212,62 @@ foreach_keyring_do() {
 	$ACTION "$FORCED_KEYRING" "$@"
 	$ACTION "$FORCED_KEYRING" "$@"
    else
    else
 	# otherwise all known keyrings are up for inspection
 	# 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"
 	local TRUSTEDPARTS="/etc/apt/trusted.gpg.d"
 	eval $(apt-config shell TRUSTEDPARTS Dir::Etc::TrustedParts/d)
 	eval $(apt-config shell TRUSTEDPARTS Dir::Etc::TrustedParts/d)
 	if [ -d "$TRUSTEDPARTS" ]; then
 	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
 	    for trusted in $(run-parts --list "$TRUSTEDPARTS" --regex '^.*\.gpg$'); do
-		$ACTION "$trusted" "$@"
+		if [ -s "$trusted" ]; then
+		    $ACTION "$trusted" "$@"
+		fi
 	    done
 	    done
 	fi
 	fi
    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() {
 usage() {
     echo "Usage: apt-key [--keyring file] [command] [arguments]"
     echo "Usage: apt-key [--keyring file] [command] [arguments]"
     echo
     echo
@@ -257,12 +292,6 @@ while [ -n "$1" ]; do
 	 shift
 	 shift
 	 TRUSTEDFILE="$1"
 	 TRUSTEDFILE="$1"
 	 FORCED_KEYRING="$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
 	 shift
 	 ;;
 	 ;;
       --fakeroot)
       --fakeroot)
@@ -286,22 +315,6 @@ if [ -z "$TRUSTEDFILE" ]; then
    TRUSTEDFILE="/etc/apt/trusted.gpg"
    TRUSTEDFILE="/etc/apt/trusted.gpg"
    eval $(apt-config shell TRUSTEDFILE Apt::GPGV::TrustedKeyring)
    eval $(apt-config shell TRUSTEDFILE Apt::GPGV::TrustedKeyring)
    eval $(apt-config shell TRUSTEDFILE Dir::Etc::Trusted/f)
    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
 fi
 
 
 command="$1"
 command="$1"
@@ -323,40 +336,47 @@ if [ "$command" != "help" ]; then
 	if [ -w "$(dirname "$TRUSTEDFILE")" ]; then
 	if [ -w "$(dirname "$TRUSTEDFILE")" ]; then
 	   touch -- "$TRUSTEDFILE"
 	   touch -- "$TRUSTEDFILE"
 	   chmod 0644 -- "$TRUSTEDFILE"
 	   chmod 0644 -- "$TRUSTEDFILE"
-	   GPG="$GPG --keyring $TRUSTEDFILE"
-	   GPG="$GPG --primary-keyring $TRUSTEDFILE"
 	fi
 	fi
     fi
     fi
 fi
 fi
 
 
 case "$command" in
 case "$command" in
     add)
     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)
     del|rm|remove)
-	remove_key "$@"
+	requires_root
+	foreach_keyring_do 'remove_key_from_keyring' "$@"
+	aptkey_echo "OK"
         ;;
         ;;
     update)
     update)
+	requires_root
+	setup_merged_keyring
 	update
 	update
 	;;
 	;;
     net-update)
     net-update)
+	requires_root
+	setup_merged_keyring
 	net_update
 	net_update
 	;;
 	;;
     list)
     list)
-        $GPG --batch --list-keys "$@"
-        ;;
+	foreach_keyring_do 'list_keys_from_keyring' "$@"
+	;;
     finger*)
     finger*)
-        $GPG --batch --fingerprint "$@"
-        ;;
+	foreach_keyring_do 'fingerprint_keys_from_keyring' "$@"
+	;;
     export|exportall)
     export|exportall)
-        $GPG --armor --export "$@"
-        ;;
+	foreach_keyring_do 'import_keys_from_keyring' "${GPGHOMEDIR}/trusted.gpg"
+	$GPG_CMD --keyring "${GPGHOMEDIR}/trusted.gpg" --armor --export "$@"
+	;;
     adv*)
     adv*)
-        aptkey_echo "Executing: $GPG $*"
-        $GPG "$@"
-        ;;
+	setup_merged_keyring
+	aptkey_echo "Executing: $GPG $*"
+	$GPG "$@"
+	;;
     help)
     help)
         usage
         usage
         ;;
         ;;