From 5beb682d2de2003e1c022cb298d6c2ec0cf91c0d Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Fri, 24 Jan 2014 22:40:52 +0100 Subject: 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 --- cmdline/apt-key.in | 134 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 77 insertions(+), 57 deletions(-) (limited to 'cmdline') diff --git a/cmdline/apt-key.in b/cmdline/apt-key.in index 9adbd6443..9d8e60ec0 100644 --- a/cmdline/apt-key.in +++ b/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 # 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 ;; -- cgit v1.2.3