commit:     0347637fe5033d3d8eb4fdafa1e86de171934819
Author:     Sam James <sam <AT> gentoo <DOT> org>
AuthorDate: Sat Aug 19 13:31:19 2023 +0000
Commit:     Sam James <sam <AT> gentoo <DOT> org>
CommitDate: Sat Aug 19 13:33:47 2023 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=0347637f

misc/emerge-delta-webrsync: fix pgp verification

Sync the logic with bin/emerge-webrsync to bring in the recent updates
from portage-3.0.47 onwards.

Bug: https://bugs.gentoo.org/911335
Signed-off-by: Sam James <sam <AT> gentoo.org>

 NEWS                       |   4 +
 misc/emerge-delta-webrsync | 295 ++++++++++++++++++++++++++++++++++++---------
 2 files changed, 242 insertions(+), 57 deletions(-)

diff --git a/NEWS b/NEWS
index ad541b95b1..f7e092808a 100644
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,10 @@ Features:
 * sync: git, rsync: now respects --debug for better output from gemato. This is
   especially useful for debugging hangs during the 'Refreshing keys' stage.
 
+Bug fixes:
+* misc/emerge-delta-webrsync: Fix PGP logic which prevented syncing for this
+  rarely-used tool (bug #911335).
+
 portage-3.0.50 (2023-08-09)
 --------------
 

diff --git a/misc/emerge-delta-webrsync b/misc/emerge-delta-webrsync
index d4c70fb9c4..8859bd79fe 100755
--- a/misc/emerge-delta-webrsync
+++ b/misc/emerge-delta-webrsync
@@ -19,6 +19,51 @@
 # gpg --homedir /etc/portage/gnupg --edit-key $KEY_ID trust
 #
 
+# Opportunistically use gentoo-functions for nicer output
+functions_script="${EPREFIX:-/}/lib/gentoo/functions.sh"
+source "${functions_script}" || {
+       echo "${argv0}: Could not source ${functions_script}!" 1>&2
+
+       ebegin() {
+               printf '%s*%s %s ... ' "${GOOD}" "${NORMAL}" "$*"
+       }
+
+       eend() {
+               local r=${1:-0}
+               shift
+               if [[ $r -eq 0 ]] ; then
+                       printf '[ %sok%s ]\n' "${GOOD}" "${NORMAL}"
+               else
+                       printf '%s [ %s!!%s ]\n' "$*" "${BAD}" "${NORMAL}"
+               fi
+               return "${r}"
+       }
+
+       einfo() {
+               echo "${argv0##*/}: $*"
+       }
+
+       ewarn() {
+               echo "${argv0##*/}: warning: $*" 1>&2
+       }
+
+       eerror() {
+               echo "${argv0##*/}: error: $*" 1>&2
+       }
+
+}
+
+# Only echo if in normal mode
+vvecho() { [[ ${PORTAGE_QUIET} != 1 ]] && echo "$@" ; }
+# Only echo if in quiet mode
+nvecho() { [[ ${PORTAGE_QUIET} == 1 ]] && echo "$@" ; }
+
+# Unfortunately, gentoo-functions doesn't yet have a die() (bug #878505)
+die() {
+       eerror "$@"
+       exit 1
+}
+
 argv0=$0
 
 # Only echo if not in verbose mode
@@ -52,13 +97,12 @@ eval "$("${portageq}" envvar -v DISTDIR EPREFIX FEATURES \
        USERLAND http_proxy ftp_proxy)"
 export http_proxy ftp_proxy
 
-source "${PORTAGE_BIN_PATH}"/isolated-functions.sh || exit 
+source "${PORTAGE_BIN_PATH}"/isolated-functions.sh || exit
 
 repo_name=gentoo
 repo_location=$(__repo_attr "${repo_name}" location)
 if [[ -z ${repo_location} ]]; then
-       eecho "Repository '${repo_name}' not found"
-       exit 1
+       die "Repository '${repo_name}' not found"
 fi
 
 if [ -z "$NICENESS_PULLED" ]; then
@@ -89,7 +133,12 @@ for x in $*; do
                        PORTAGE_QUIET=1
                        continue
                        ;;
+               --no-pgp-verify)
+                       no_pgp_verify=1
+                       continue
+                       ;;
        esac
+
        if [[ $x == "-u" ]]; then
                MUST_SYNC=''
        elif [[ $x == "-k" ]]; then
@@ -103,6 +152,7 @@ for x in $*; do
                echo "$x isn't a valid arg.  bailing."
        fi
        if [[ -n $PUKE_HELP ]]; then
+               echo "--no-pgp-verify; disable PGP verification of snapshot 
(note that patches are not verified either way)"
                echo "-u for upgrade; sync only if new snapshots are found"
                echo "-k for keep; keep old tree snapshots around"
                exit -1
@@ -114,35 +164,68 @@ if [[ ! -d $STATE_DIR ]]; then
        exit -2
 fi
 
-has webrsync-gpg ${FEATURES} && webrsync_gpg=1 || webrsync_gpg=0
+handle_pgp_setup() {
+       # WEBRSYNC_VERIFY_SIGNATURE=0: disable PGP verification
+       # WEBRSYNC_VERIFY_SIGNATURE=1: use gemato for verification, fallback to 
regular gpg
+       # WEBRSYNC_VERIFY_SIGNATURE=2: use legacy FEATURES="webrsync-gpg"
+       WEBRSYNC_VERIFY_SIGNATURE=1
+
+       has webrsync-gpg ${FEATURES} && webrsync_gpg=1 || webrsync_gpg=0
+
+       repo_has_webrsync_verify=$(
+               has $(__repo_attr "${repo_name}" sync-webrsync-verify-signature 
| LC_ALL=C tr '[:upper:]' '[:lower:]') true yes
+       )
+
+       if [[ -n ${PORTAGE_TEMP_GPG_DIR} ]] || [[ ${repo_has_webrsync_verify} 
-eq 1 ]]; then
+               # If FEATURES=webrsync-gpg is enabled then allow direct 
emerge-webrsync
+               # calls for backward compatibility (this triggers a deprecation 
warning
+               # above). Since direct emerge-webrsync calls do not use gemato 
for secure
+               # key refresh, this behavior will not be supported in a future 
release.
+               if [[ ! ( -d ${PORTAGE_GPG_DIR} && ${webrsync_gpg} -eq 1 ) && 
-z ${PORTAGE_TEMP_GPG_DIR} ]]; then
+                       die "Do not call ${argv0##*/} directly, instead call 
emerge --sync or emaint sync."
+               fi
 
-if [[ ${webrsync_gpg} -eq 1 ]]; then
-       wecho "FEATURES=webrsync-gpg is deprecated, see the make.conf(5) man 
page."
-fi
+               # Use gemato for the standard Portage-calling-us case w/ 
sync-type='webrsync'.
+               WEBRSYNC_VERIFY_SIGNATURE=1
+       elif [[ ${webrsync_gpg} -eq 1 ]]; then
+               # We only warn if FEATURES="webrsync-gpg" is in make.conf, not 
if
+               # Portage is calling us for 'sync-type=webrsync' with 
verification, because
+               # that path uses gemato now (plus the user can't help it, 
obviously).
+               ewarn "FEATURES=webrsync-gpg is deprecated, see the 
make.conf(5) man page."
+               WEBRSYNC_VERIFY_SIGNATURE=2
+       elif [[ -n ${no_pgp_verify} ]]; then
+               WEBRSYNC_VERIFY_SIGNATURE=0
+       else
+               # The default at the beginning of handle_pgp_setup is 
WEBRSYNC_VERIFY_SIGNATURE=1
+               # i.e. gemato.
+               :;
+       fi
 
-if [[ -n ${PORTAGE_TEMP_GPG_DIR} ]] ||
-       has $(__repo_attr "${repo_name}" sync-webrsync-verify-signature |
-       LC_ALL=C tr '[:upper:]' '[:lower:]') true yes; then
-       # If FEATURES=webrsync-gpg is enabled then allow direct emerge-webrsync
-       # calls for backward compatibility (this triggers a deprecation warning
-       # above). Since direct emerge-webrsync calls do not use gemato for 
secure
-       # key refresh, this behavior will not be supported in a future release.
-       if [[ ! ( -d ${PORTAGE_GPG_DIR} && ${webrsync_gpg} -eq 1 ) &&
-               -z ${PORTAGE_TEMP_GPG_DIR} ]]; then
-               eecho "Do not call ${argv0##*/} directly, instead call emerge 
--sync or emaint sync."
-               exit 1
+       case "${WEBRSYNC_VERIFY_SIGNATURE}" in
+               0)
+                       [[ ${PORTAGE_QUIET} -eq 1 ]] || ewarn "PGP verification 
method: disabled"
+                       ;;
+               1)
+                       [[ ${PORTAGE_QUIET} -eq 1 ]] || einfo "PGP verification 
method: gemato"
+                       ;;
+               2)
+                       ewarn "PGP verification method: legacy gpg path"
+                       ;;
+               *)
+                       die "Unknown WEBRSYNC_VERIFY_SIGNATURE state: 
\${WEBRSYNC_VERIFY_SIGNATURE}=${WEBRSYNC_VERIFY_SIGNATURE}"
+                       ;;
+       esac
+
+       if [[ -n ${PORTAGE_TEMP_GPG_DIR} ]]; then
+               PORTAGE_GPG_DIR=${PORTAGE_TEMP_GPG_DIR}
        fi
-       WEBSYNC_VERIFY_SIGNATURE=1
-elif has webrsync-gpg ${FEATURES}; then
-       WEBSYNC_VERIFY_SIGNATURE=1
-else
-       WEBSYNC_VERIFY_SIGNATURE=0
-fi
-[[ -n ${PORTAGE_TEMP_GPG_DIR} ]] && PORTAGE_GPG_DIR=${PORTAGE_TEMP_GPG_DIR}
-if [ ${WEBSYNC_VERIFY_SIGNATURE} != 0 -a -z "${PORTAGE_GPG_DIR}" ]; then
-       eecho "please set PORTAGE_GPG_DIR in make.conf"
-       exit 1
-fi
+
+       if [[ ${WEBRSYNC_VERIFY_SIGNATURE} == 2 && -z "${PORTAGE_GPG_DIR}" ]]; 
then
+               die "Please set PORTAGE_GPG_DIR in make.conf!"
+       fi
+}
+
+handle_pgp_setup
 
 [[ -d ${repo_location} ]] || mkdir -p "${repo_location}"
 if [[ ! -w ${repo_location} ]] ; then
@@ -156,7 +239,7 @@ if [[ ! -w ${DISTDIR} ]] ; then
        exit 1
 fi
 
-[[ -d ${PORTAGE_TMPDIR}/portage ]] || mkdir -p "${PORTAGE_TMPDIR}/portage" 
+[[ -d ${PORTAGE_TMPDIR}/portage ]] || mkdir -p "${PORTAGE_TMPDIR}/portage"
 TMPDIR=$(mktemp -d "${PORTAGE_TMPDIR}/portage/delta-webrsync-XXXXXX")
 if [[ ! -w ${TMPDIR} ]] ; then
        eecho "TMPDIR is not writable: ${TMPDIR}"
@@ -291,36 +374,134 @@ check_file_digest() {
        return "${r}"
 }
 
+
+check_file_signature_gemato() {
+       local signature="$1"
+       local file="$2"
+       local r=1
+
+       if type -P gemato > /dev/null; then
+               if [[ -n ${PORTAGE_GPG_KEY} ]] ; then
+                       local key="${PORTAGE_GPG_KEY}"
+               else
+                       local 
key="${EPREFIX:-/}"/usr/share/openpgp-keys/gentoo-release.asc
+               fi
+
+               if [[ ! -f "${key}" ]] ; then
+                       eerror "${key} not available. Is 
sec-keys/openpgp-keys-gentoo-release installed?"
+                       die "Needed keys unavailable! Install its package or 
set PORTAGE_GPG_KEY to the right path."
+               fi
+
+               local keyserver
+               if [[ -n ${PORTAGE_GPG_KEY_SERVER} ]] ; then
+                       keyserver="--keyserver ${PORTAGE_GPG_KEY_SERVER}"
+               fi
+
+               local gemato_args=(
+                       openpgp-verify-detached
+                       -K "${key}"
+               )
+
+               [[ -n ${PORTAGE_GPG_KEY_SERVER} ]] && gemato_args+=( 
--keyserver "${PORTAGE_GPG_KEY_SERVER}" )
+               [[ ${PORTAGE_QUIET} == 1 ]] && gemato_args+=( --quiet )
+               [[ ${do_debug} == 1 ]] && gemato_args+=( --debug )
+
+               gemato "${gemato_args[@]}" -- "${signature}" "${file}"
+               r=$?
+
+               if [[ ${r} -ne 0 ]]; then
+                       # Exit early since it's typically inappropriate to
+                       # try other mirrors in this case (it may indicate
+                       # a keyring problem).
+                       die "signature verification failed"
+               fi
+       else
+               return 127
+       fi
+
+       return "${r}"
+}
+
+check_file_signature_gpg_unwrapped() {
+       local signature="$1"
+       local file="$2"
+
+       if type -P gpg > /dev/null; then
+               if [[ -n ${PORTAGE_GPG_KEY} ]] ; then
+                       local key="${PORTAGE_GPG_KEY}"
+               else
+                       local 
key="${EPREFIX:-/}"/usr/share/openpgp-keys/gentoo-release.asc
+               fi
+
+               if [[ ! -f "${key}" ]] ; then
+                       eerror "${key} not available. Is 
sec-keys/openpgp-keys-gentoo-release installed?"
+                       die "Needed keys unavailable! Install its package or 
set PORTAGE_GPG_KEY to the right path."
+               fi
+
+               local gpgdir="${PORTAGE_GPG_DIR}"
+               if [[ -z ${gpgdir} ]] ; then
+                       gpgdir=$(mktemp -d 
"${PORTAGE_TMPDIR}/portage/webrsync-XXXXXX")
+                       if [[ ! -w ${gpgdir} ]] ; then
+                               die "gpgdir is not writable: ${gpgdir}"
+                       fi
+
+                       # If we're created our own temporary directory, it's 
okay for us
+                       # to import the keyring by ourselves. But we'll avoid 
doing it
+                       # if the user has set PORTAGE_GPG_DIR by themselves.
+                       gpg --no-default-keyring --homedir "${gpgdir}" --batch 
--import "${key}"
+               fi
+
+               if gnupg_status=$(gpg --no-default-keyring --homedir 
"${gpgdir}" --batch \
+                       --status-fd 1 --verify "${signature}" "${file}"); then
+                       while read -r line; do
+                               if [[ ${line} == "[GNUPG:] GOODSIG"* ]]; then
+                                       r=0
+                                       break
+                               fi
+                       done <<< "${gnupg_status}"
+               fi
+
+               if [[ ${r} -ne 0 ]]; then
+                       # Exit early since it's typically inappropriate to
+                       # try other mirrors in this case (it may indicate
+                       # a keyring problem).
+                       die "signature verification failed"
+               fi
+       else
+               die "cannot check signature: gpg binary not found"
+       fi
+}
+
 check_file_signature() {
        local signature="$1"
        local file="$2"
        local r=1
        local gnupg_status line
 
-       if [[ ${WEBSYNC_VERIFY_SIGNATURE} != 0 ]] ; then
+       if [[ ${WEBRSYNC_VERIFY_SIGNATURE} != 0 ]]; then
+               [[ ${PORTAGE_QUIET} -eq 1 ]] || einfo "Checking signature ..."
 
-               __vecho "Checking signature ..."
+               case ${WEBRSYNC_VERIFY_SIGNATURE} in
+                       1)
+                               check_file_signature_gemato "${signature}" 
"${file}"
+                               r=$?
 
-               if type -P gpg > /dev/null; then
-                       if gnupg_status=$(gpg --homedir "${PORTAGE_GPG_DIR}" 
--batch \
-                               --status-fd 1 --verify "${signature}" 
"${file}"); then
-                               while read -r line; do
-                                       if [[ ${line} == "[GNUPG:] GOODSIG"* 
]]; then
-                                               r=0
-                                               break
-                                       fi
-                               done <<< "${gnupg_status}"
-                       fi
-                       if [[ ${r} -ne 0 ]]; then
-                               # Exit early since it's typically inappropriate 
to
-                               # try other mirrors in this case (it may 
indicate
-                               # a keyring problem).
-                               eecho "signature verification failed"
-                               exit 1
-                       fi
-               else
-                       eecho "cannot check signature: gpg binary not found"
-                       exit 1
+                               if [[ ${r} -eq 127 ]] ; then
+                                       ewarn "Falling back to gpg as gemato is 
not installed"
+                                       check_file_signature_gpg_unwrapped 
"${signature}" "${file}"
+                                       r=$?
+                               fi
+
+                               ;;
+                       2)
+                               check_file_signature_gpg_unwrapped 
"${signature}" "${file}"
+                               r=$?
+                               ;;
+               esac
+
+               if [[ ${r} != 0 ]] ; then
+                       eerror "Error occurred in check_file_signature: ${r}. 
Aborting."
+                       die "Verification error occured."
                fi
        else
                r=0
@@ -710,13 +891,13 @@ if [[ -z $patches ]]; then
        echo "no patches found? up to date?"
        if [[ -n $MUST_SYNC ]]; then
                echo "syncing with existing file"
-               if [[ ${WEBSYNC_VERIFY_SIGNATURE} == 1 &&
+               if [[ ${WEBRSYNC_VERIFY_SIGNATURE} == 1 &&
                        ! -e ${DISTDIR}/portage-${base_date}.tar.bz2.gpgsig ]] 
&& \
                        ! fetch_from_mirrors 
"/snapshots/portage-${base_date}.tar.bz2.gpgsig" 
"portage-${base_date}.tar.bz2.gpgsig" ; then
                        eecho "Couldn't fetch 
portage-${base_date}.tar.bz2.gpgsig"
                        exit 5
                fi
-               if [[ ${WEBSYNC_VERIFY_SIGNATURE} == 1 ]] ; then
+               if [[ ${WEBRSYNC_VERIFY_SIGNATURE} == 1 ]] ; then
                        check_file_signature 
"${DISTDIR}/portage-${base_date}.tar.bz2.gpgsig" "${dfile}" || exit 1
                fi
                sync_local "${dfile}" && rm -fr "${TMPDIR}"
@@ -745,7 +926,7 @@ else
        fi
 fi
 
-if [[ ${WEBSYNC_VERIFY_SIGNATURE} == 1 && ! -e 
portage-${final_date}.tar.bz2.gpgsig ]] && \
+if [[ ${WEBRSYNC_VERIFY_SIGNATURE} == 1 && ! -e 
portage-${final_date}.tar.bz2.gpgsig ]] && \
        ! fetch_from_mirrors "/snapshots/portage-${final_date}.tar.bz2.gpgsig" 
"portage-${final_date}.tar.bz2.gpgsig" ; then
        echo "warning... couldn't grab the gpgsig for ${final_date}.  which is 
odd"
        echo "thus, bailing (sorry)"
@@ -778,7 +959,7 @@ fi
 unset need_last_sync
 if [ "$verified" == "1" ]; then
        need_last_sync="dar"
-       if [[ ${WEBSYNC_VERIFY_SIGNATURE} == 1 ]] ; then
+       if [[ ${WEBRSYNC_VERIFY_SIGNATURE} == 1 ]] ; then
                # BUG: Signature verification will fail if the local bzip2
                # program does not produce output that is perfectly identical
                # to the bzip2 program used to compress the signed tar file.
@@ -829,7 +1010,7 @@ else
 fi
 
 if [ -z "${need_last_sync}" ]; then
-       if [[ ${WEBSYNC_VERIFY_SIGNATURE} == 1 ]] ; then
+       if [[ ${WEBRSYNC_VERIFY_SIGNATURE} == 1 ]] ; then
                check_file_signature 
"${DISTDIR}/portage-${final_date}.tar.bz2.gpgsig" "${dfile}" || exit 1
        fi
        echo "beginning update to the tree"

Reply via email to