|
|
@@ -3,29 +3,6 @@
|
|
|
set -e
|
|
|
unset GREP_OPTIONS
|
|
|
|
|
|
-GPG_CMD="gpg --ignore-time-conflict --no-options --no-default-keyring"
|
|
|
-
|
|
|
-# 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 "$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="${GPGHOMEDIR}/secring.gpg"
|
|
|
-touch $SECRETKEYRING
|
|
|
-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"
|
|
|
-
|
|
|
APT_DIR="/"
|
|
|
eval $(apt-config shell APT_DIR Dir)
|
|
|
|
|
|
@@ -37,22 +14,26 @@ REMOVED_KEYS='&keyring-removed-filename;'
|
|
|
eval $(apt-config shell REMOVED_KEYS APT::Key::RemovedKeys)
|
|
|
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
|
|
|
+get_fingerprints_of_keyring() {
|
|
|
+ $GPG_CMD --keyring "$1" --with-colons --fingerprint | while read publine; do
|
|
|
+ # search for a public key
|
|
|
+ if [ "${publine%%:*}" != 'pub' ]; then continue; fi
|
|
|
+ # search for the associated fingerprint (should be the very next line)
|
|
|
+ while read fprline; do
|
|
|
+ if [ "${fprline%%:*}" = 'sub' ]; then break; # should never happen
|
|
|
+ elif [ "${fprline%%:*}" != 'fpr' ]; then continue; fi
|
|
|
+ echo "$fprline" | cut -d':' -f 10
|
|
|
+ done
|
|
|
done
|
|
|
}
|
|
|
|
|
|
@@ -61,11 +42,11 @@ add_keys_with_verify_against_master_keyring() {
|
|
|
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
|
|
|
|
|
|
@@ -73,7 +54,7 @@ add_keys_with_verify_against_master_keyring() {
|
|
|
# is honored. so:
|
|
|
# all keys that are exported must have a valid signature
|
|
|
# from a key in the $distro-master-keyring
|
|
|
- add_keys=`$GPG_CMD --keyring $ADD_KEYRING --with-colons --list-keys | grep ^pub | cut -d: -f5`
|
|
|
+ add_keys="$(get_fingerprints_of_keyring "$ADD_KEYRING")"
|
|
|
all_add_keys=`$GPG_CMD --keyring $ADD_KEYRING --with-colons --list-keys | grep ^[ps]ub | cut -d: -f5`
|
|
|
master_keys=`$GPG_CMD --keyring $MASTER --with-colons --list-keys | grep ^pub | cut -d: -f5`
|
|
|
|
|
|
@@ -86,24 +67,28 @@ add_keys_with_verify_against_master_keyring() {
|
|
|
fi
|
|
|
done
|
|
|
done
|
|
|
-
|
|
|
+
|
|
|
for add_key in $add_keys; do
|
|
|
# export the add keyring one-by-one
|
|
|
- rm -f $TMP_KEYRING
|
|
|
- $GPG_CMD --keyring $ADD_KEYRING --output $TMP_KEYRING --export $add_key
|
|
|
- # check if signed with the master key and only add in this case
|
|
|
- ADDED=0
|
|
|
+ local TMP_KEYRING="${GPGHOMEDIR}/tmp-keyring.gpg"
|
|
|
+ $GPG_CMD --batch --yes --keyring "$ADD_KEYRING" --output "$TMP_KEYRING" --export "$add_key"
|
|
|
+ if ! $GPG_CMD --batch --yes --keyring "$TMP_KEYRING" --import "$MASTER" > "${GPGHOMEDIR}/gpgoutput.log" 2>&1; then
|
|
|
+ cat "${GPGHOMEDIR}/gpgoutput.log"
|
|
|
+ false
|
|
|
+ fi
|
|
|
+ # check if signed with the master key and only add in this case
|
|
|
+ ADDED=0
|
|
|
for master_key in $master_keys; do
|
|
|
- if $GPG_CMD --keyring $MASTER --keyring $TMP_KEYRING --check-sigs --with-colons $add_key | grep '^sig:!:' | cut -d: -f5 | grep -q $master_key; then
|
|
|
- $GPG --import $TMP_KEYRING
|
|
|
+ if $GPG_CMD --keyring $TMP_KEYRING --check-sigs --with-colons $add_key | grep '^sig:!:' | cut -d: -f5 | grep -q $master_key; then
|
|
|
+ $GPG_CMD --batch --yes --keyring "$ADD_KEYRING" --export "$add_key" | $GPG --batch --yes --import
|
|
|
ADDED=1
|
|
|
fi
|
|
|
done
|
|
|
if [ $ADDED = 0 ]; then
|
|
|
echo >&2 "Key '$add_key' not added. It is not signed with a master key"
|
|
|
fi
|
|
|
+ rm -f "${TMP_KEYRING}"
|
|
|
done
|
|
|
- rm -f $TMP_KEYRING
|
|
|
}
|
|
|
|
|
|
# update the current archive signing keyring from a network URI
|
|
|
@@ -121,7 +106,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
|
|
|
@@ -142,7 +126,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
|
|
|
}
|
|
|
@@ -153,7 +137,6 @@ update() {
|
|
|
echo >&2 "Is the &keyring-package; package installed?"
|
|
|
exit 1
|
|
|
fi
|
|
|
- requires_root
|
|
|
|
|
|
# add new keys from the package;
|
|
|
|
|
|
@@ -166,71 +149,159 @@ 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
|
|
|
+ get_fingerprints_of_keyring "$REMOVED_KEYS" | while read key; do
|
|
|
+ foreach_keyring_do 'remove_key_from_keyring' "$key"
|
|
|
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
|
|
|
+ local KEYRINGFILE="$1"
|
|
|
+ shift
|
|
|
+ # non-existent keyrings have by definition no keys
|
|
|
+ if [ ! -e "$KEYRINGFILE" ]; then
|
|
|
+ return
|
|
|
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 "$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
|
|
|
-}
|
|
|
|
|
|
-remove_key() {
|
|
|
- requires_root
|
|
|
+ local GPG="$GPG_CMD --keyring $KEYRINGFILE"
|
|
|
+ for KEY in "$@"; do
|
|
|
+ # check if the key is in this keyring: the key id is in the 5 column at the end
|
|
|
+ if ! get_fingerprints_of_keyring "$KEYRINGFILE" | grep -q "^[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' = "$(get_fingerprints_of_keyring "$KEYRINGFILE" | 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
|
|
|
+}
|
|
|
|
|
|
- # 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"
|
|
|
+ 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
|
|
|
- remove_key_from_keyring "$trusted" "$1"
|
|
|
+ if [ -s "$trusted" ]; then
|
|
|
+ $ACTION "$trusted" "$@"
|
|
|
+ fi
|
|
|
done
|
|
|
fi
|
|
|
+ fi
|
|
|
+}
|
|
|
+
|
|
|
+run_cmd_on_keyring() {
|
|
|
+ local KEYRINGFILE="$1"
|
|
|
+ shift
|
|
|
+ # fingerprint and co will fail if key isn't in this keyring
|
|
|
+ $GPG_CMD --keyring "$KEYRINGFILE" --batch "$@" 2>/dev/null || true
|
|
|
+}
|
|
|
+
|
|
|
+import_keys_from_keyring() {
|
|
|
+ local IMPORT="$1"
|
|
|
+ local KEYRINGFILE="$2"
|
|
|
+ if ! $GPG_CMD --keyring "$KEYRINGFILE" --batch --import "$IMPORT" > "${GPGHOMEDIR}/gpgoutput.log" 2>&1; then
|
|
|
+ cat "${GPGHOMEDIR}/gpgoutput.log"
|
|
|
+ false
|
|
|
fi
|
|
|
- echo "OK"
|
|
|
}
|
|
|
|
|
|
+merge_keys_into_keyrings() {
|
|
|
+ local KEYRINGFILE="$1"
|
|
|
+ local IMPORT="$2"
|
|
|
+ if ! $GPG_CMD --keyring "$KEYRINGFILE" --batch --import --import-options 'merge-only' "$IMPORT" > "${GPGHOMEDIR}/gpgoutput.log" 2>&1; then
|
|
|
+ cat "${GPGHOMEDIR}/gpgoutput.log"
|
|
|
+ false
|
|
|
+ fi
|
|
|
+}
|
|
|
+
|
|
|
+merge_back_changes() {
|
|
|
+ if [ -n "$FORCED_KEYRING" ]; then
|
|
|
+ # if the keyring was forced merge is already done
|
|
|
+ return
|
|
|
+ fi
|
|
|
+ if [ -s "${GPGHOMEDIR}/pubring.gpg" ]; then
|
|
|
+ # merge all updated keys
|
|
|
+ foreach_keyring_do 'merge_keys_into_keyrings' "${GPGHOMEDIR}/pubring.gpg"
|
|
|
+ fi
|
|
|
+ # look for keys which were added or removed
|
|
|
+ get_fingerprints_of_keyring "${GPGHOMEDIR}/pubring.orig.gpg" > "${GPGHOMEDIR}/pubring.orig.keylst"
|
|
|
+ get_fingerprints_of_keyring "${GPGHOMEDIR}/pubring.gpg" > "${GPGHOMEDIR}/pubring.keylst"
|
|
|
+ sort "${GPGHOMEDIR}/pubring.keylst" "${GPGHOMEDIR}/pubring.orig.keylst" | uniq --unique | while read key; do
|
|
|
+ if grep -q "^${key}$" "${GPGHOMEDIR}/pubring.orig.keylst"; then
|
|
|
+ # key isn't part of new keyring, so remove
|
|
|
+ foreach_keyring_do 'remove_key_from_keyring' "$key"
|
|
|
+ elif grep -q "^${key}$" "${GPGHOMEDIR}/pubring.keylst"; then
|
|
|
+ # key is part of new keyring, so we need to import it
|
|
|
+ create_new_keyring "$TRUSTEDFILE"
|
|
|
+ if ! $GPG --batch --yes --export "$key" | $GPG_CMD --keyring "$TRUSTEDFILE" --batch --yes --import > "${GPGHOMEDIR}/gpgoutput.log" 2>&1; then
|
|
|
+ cat "${GPGHOMEDIR}/gpgoutput.log"
|
|
|
+ false
|
|
|
+ fi
|
|
|
+ else
|
|
|
+ echo >&2 "Errror: Key ${key} (dis)appeared out of nowhere"
|
|
|
+ fi
|
|
|
+ done
|
|
|
+}
|
|
|
+
|
|
|
+setup_merged_keyring() {
|
|
|
+ if [ -z "$FORCED_KEYRING" ]; then
|
|
|
+ foreach_keyring_do 'import_keys_from_keyring' "${GPGHOMEDIR}/pubring.gpg"
|
|
|
+ if [ -r "${GPGHOMEDIR}/pubring.gpg" ]; then
|
|
|
+ cp -a "${GPGHOMEDIR}/pubring.gpg" "${GPGHOMEDIR}/pubring.orig.gpg"
|
|
|
+ else
|
|
|
+ touch "${GPGHOMEDIR}/pubring.gpg" "${GPGHOMEDIR}/pubring.orig.gpg"
|
|
|
+ fi
|
|
|
+ GPG="$GPG --keyring ${GPGHOMEDIR}/pubring.gpg"
|
|
|
+ else
|
|
|
+ GPG="$GPG --keyring $TRUSTEDFILE"
|
|
|
+ create_new_keyring "$TRUSTEDFILE"
|
|
|
+ fi
|
|
|
+}
|
|
|
+
|
|
|
+create_new_keyring() {
|
|
|
+ # 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"
|
|
|
+ fi
|
|
|
+ fi
|
|
|
+}
|
|
|
|
|
|
usage() {
|
|
|
echo "Usage: apt-key [--keyring file] [command] [arguments]"
|
|
|
@@ -256,17 +327,19 @@ 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
|
|
|
+ ;;
|
|
|
+ --secret-keyring)
|
|
|
shift
|
|
|
+ FORCED_SECRET_KEYRING="$1"
|
|
|
+ ;;
|
|
|
+ --readonly)
|
|
|
+ merge_back_changes() { true; }
|
|
|
;;
|
|
|
--fakeroot)
|
|
|
requires_root() { true; }
|
|
|
- shift
|
|
|
+ ;;
|
|
|
+ --quiet)
|
|
|
+ aptkey_echo() { true; }
|
|
|
;;
|
|
|
--*)
|
|
|
echo >&2 "Unknown option: $1"
|
|
|
@@ -275,28 +348,13 @@ while [ -n "$1" ]; do
|
|
|
*)
|
|
|
break;;
|
|
|
esac
|
|
|
+ shift
|
|
|
done
|
|
|
|
|
|
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"
|
|
|
- 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
|
|
|
- # 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"
|
|
|
@@ -306,52 +364,100 @@ 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
|
|
|
+ eval $(apt-config shell GPG_EXE Apt::Key::gpgcommand)
|
|
|
+
|
|
|
+ if [ -n "$GPG_EXE" ] && which "$GPG_EXE" >/dev/null 2>&1; then
|
|
|
+ true
|
|
|
+ elif which gpg >/dev/null 2>&1; then
|
|
|
+ GPG_EXE="gpg"
|
|
|
+ elif which gpg2 >/dev/null 2>&1; then
|
|
|
+ GPG_EXE="gpg2"
|
|
|
+ else
|
|
|
+ echo >&2 "Error: gnupg or gnupg2 do not seem to be installed,"
|
|
|
+ echo >&2 "Error: but apt-key requires gnupg or gnupg2 for operation."
|
|
|
+ echo >&2
|
|
|
+ exit 255
|
|
|
+ fi
|
|
|
+
|
|
|
+ GPG_CMD="$GPG_EXE --ignore-time-conflict --no-options --no-default-keyring"
|
|
|
+
|
|
|
+ # 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 "$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="${GPGHOMEDIR}/secring.gpg"
|
|
|
+ touch $SECRETKEYRING
|
|
|
+ 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"
|
|
|
+
|
|
|
+ # for advanced operations, we might really need a secret keyring after all
|
|
|
+ if [ -n "$FORCED_SECRET_KEYRING" ] && [ -r "$FORCED_SECRET_KEYRING" ]; then
|
|
|
+ rm -f "$SECRETKEYRING"
|
|
|
+ cp -a "$FORCED_SECRET_KEYRING" "$SECRETKEYRING"
|
|
|
+ fi
|
|
|
fi
|
|
|
|
|
|
case "$command" in
|
|
|
add)
|
|
|
- requires_root
|
|
|
- init_keyring "$TRUSTEDFILE"
|
|
|
- $GPG --quiet --batch --import "$1"
|
|
|
- echo "OK"
|
|
|
+ requires_root
|
|
|
+ setup_merged_keyring
|
|
|
+ $GPG --quiet --batch --import "$@"
|
|
|
+ merge_back_changes
|
|
|
+ aptkey_echo "OK"
|
|
|
;;
|
|
|
del|rm|remove)
|
|
|
- init_keyring "$TRUSTEDFILE"
|
|
|
- remove_key "$1"
|
|
|
+ requires_root
|
|
|
+ foreach_keyring_do 'remove_key_from_keyring' "$@"
|
|
|
+ aptkey_echo "OK"
|
|
|
;;
|
|
|
update)
|
|
|
- init_keyring "$TRUSTEDFILE"
|
|
|
+ requires_root
|
|
|
+ setup_merged_keyring
|
|
|
update
|
|
|
+ merge_back_changes
|
|
|
;;
|
|
|
net-update)
|
|
|
- init_keyring "$TRUSTEDFILE"
|
|
|
+ requires_root
|
|
|
+ setup_merged_keyring
|
|
|
net_update
|
|
|
+ merge_back_changes
|
|
|
;;
|
|
|
list)
|
|
|
- init_keyring "$TRUSTEDFILE"
|
|
|
- $GPG --batch --list-keys
|
|
|
- ;;
|
|
|
+ foreach_keyring_do 'run_cmd_on_keyring' --list-keys "$@"
|
|
|
+ ;;
|
|
|
finger*)
|
|
|
- init_keyring "$TRUSTEDFILE"
|
|
|
- $GPG --batch --fingerprint
|
|
|
- ;;
|
|
|
- export)
|
|
|
- init_keyring "$TRUSTEDFILE"
|
|
|
- $GPG --armor --export "$1"
|
|
|
- ;;
|
|
|
- exportall)
|
|
|
- init_keyring "$TRUSTEDFILE"
|
|
|
- $GPG --armor --export
|
|
|
- ;;
|
|
|
+ foreach_keyring_do 'run_cmd_on_keyring' --fingerprint "$@"
|
|
|
+ ;;
|
|
|
+ export|exportall)
|
|
|
+ foreach_keyring_do 'import_keys_from_keyring' "${GPGHOMEDIR}/pubring.gpg"
|
|
|
+ $GPG_CMD --keyring "${GPGHOMEDIR}/pubring.gpg" --armor --export "$@"
|
|
|
+ ;;
|
|
|
adv*)
|
|
|
- init_keyring "$TRUSTEDFILE"
|
|
|
- echo "Executing: $GPG $*"
|
|
|
- $GPG $*
|
|
|
- ;;
|
|
|
+ setup_merged_keyring
|
|
|
+ aptkey_echo "Executing: $GPG $*"
|
|
|
+ $GPG "$@"
|
|
|
+ merge_back_changes
|
|
|
+ ;;
|
|
|
+ verify)
|
|
|
+ setup_merged_keyring
|
|
|
+ if which gpgv >/dev/null 2>&1; then
|
|
|
+ gpgv --homedir "${GPGHOMEDIR}" --keyring "${GPGHOMEDIR}/pubring.gpg" --ignore-time-conflict "$@"
|
|
|
+ else
|
|
|
+ $GPG --verify "$@"
|
|
|
+ fi
|
|
|
+ ;;
|
|
|
help)
|
|
|
usage
|
|
|
;;
|