2 # No way I try to deal with a crippled sh just for POSIX foo.
4 # Copyright (C) 2011 Joerg Jaspert <joerg@debian.org>
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License as
8 # published by the Free Software Foundation; version 2.
10 # This program is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 # General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 # make sure to only use defined variables
24 # ERR traps should be inherited from functions too.
27 # import the general variable set.
28 export SCRIPTVARS=/srv/ftp-master.debian.org/dak/config/debian/vars
33 # And use one locale, no matter what the caller has set
36 PROGRAM="buildd-remove-keys"
38 # common functions are "outsourced"
39 . "${configdir}/common"
43 trap - ERR EXIT TERM HUP INT QUIT
45 for TEMPFILE in GPGSTATUS GPGLOGS GPGOUTF TEMPKEYDATA; do
46 TFILE=${TEMPFILE:=$TEMPFILE}
48 if [ -n "${DELF}" ] && [ -f "${DELF}" ]; then
55 base="${base}/scripts/builddkeyrings"
56 INCOMING="${base}/incoming"
57 ERRORS="${base}/errors"
58 ADMINS="${base}/adminkeys.gpg"
59 REMOVED="${base}/removed-buildd-keys.gpg"
60 STAMPFILE="${base}/updatedkeyring"
62 # Default options for our gpg calls
63 DEFGPGOPT="--no-default-keyring --batch --no-tty --no-options --exit-on-status-write-error --no-greeting"
65 if ! [ -d "${INCOMING}" ]; then
66 log "Missing incoming dir, nothing to do"
71 KEYS=$(find . -maxdepth 1 -mindepth 1 -type f -name \*.del | sed -e "s,./,," | xargs)
72 if [ -z "${KEYS}" ]; then
76 trap cleanup ERR EXIT TERM HUP INT QUIT
78 # Tell prepare-dir that there is an update and it can run
81 # Whenever something goes wrong, its put in there.
84 # We process all new files in our incoming directory
85 for file in ${KEYS}; do
87 # First we want to see if we recognize the filename. The buildd people have
88 # to follow a certain schema:
89 # architecture_builddname.YEAR-MONTH-DAY_HOURMINUTE.del
90 if [[ $file =~ (.*)_(.*).([0-9]{4}-[0-9]{2}-[0-9]{2}_[0-9]{2}[0-9]{2}).del ]]; then
91 ARCH=${BASH_REMATCH[1]}
92 BUILDD=${BASH_REMATCH[2]}
93 # Right now timestamp is unused
94 TIMESTAMP=${BASH_REMATCH[3]}
96 log "Unknown file ${file}, not processing"
97 mv "${INCOMING}/${file}" "${ERRORS}/unknown.${file}.$(date -Is)"
101 # Do we know the architecture?
103 for carch in ${archs}; do
104 if [ "${ARCH}" == "${carch}" ]; then
105 log "Known arch ${ARCH}, buildd ${BUILDD}"
111 if [ ${found} -eq 0 ]; then
112 log "Unknown architecture ${ARCH}"
113 mv "${INCOMING}/${file}" "${ERRORS}/unknownarch.${file}.$(date -Is)"
117 # If we did have a file with this name already somethings wrong
118 if [ -f "${base}/${ARCH}/${file}" ]; then
119 log "Already processed this file"
120 mv "${INCOMING}/${file}" "${ERRORS}/duplicate.${file}.$(date -Is)"
124 # Where we want the status-fd from gpgv turn up
125 GPGSTATUS=$(mktemp -p "${TMPDIR}" GPGSTATUS.XXXXXX)
126 # Same for the loggger-fd
127 GPGLOGS=$(mktemp -p "${TMPDIR}" GPGLOGS.XXXXXX)
128 # And "decrypt" gives us output, the key without the pgp sig around it
129 GPGOUTF=$(mktemp -p "${TMPDIR}" GPGOUTF.XXXXXX)
131 # Open the filehandles, assigning them to the two files, so we can let gpg use them
132 exec 4> "${GPGSTATUS}"
135 # So lets run gpg, status/logger into the two files, to "decrypt" the keyfile
136 if ! gpg ${DEFGPGOPT} --keyring "${ADMINS}" --status-fd 4 --logger-fd 5 --decrypt "${INCOMING}/${file}" > "${GPGOUTF}"; then
138 log "gpg returned with ${ret}, not removing key using ${file}"
140 mv "${INCOMING}/${file}" "${ERRORS}/gpgerror.${file}.${DATE}"
141 mv "${GPGSTATUS}" "${ERRORS}/gpgerror.${file}.gpgstatus.${DATE}"
142 mv "${GPGLOGS}" "${ERRORS}/gpgerror.${file}.gpglogs.${DATE}"
147 # Read in the status output
148 GPGSTAT=$(cat "${GPGSTATUS}")
149 # And check if we like the sig. It has to be both, GOODISG and VALIDSIG or we don't accept it
150 if [[ ${GPGSTAT} =~ "GOODSIG" ]] && [[ ${GPGSTAT} =~ "VALIDSIG" ]]; then
151 log "Signature for ${file} accepted"
153 log "We are missing one of GOODSIG or VALIDSIG"
155 mv "${INCOMING}/${file}" "${ERRORS}/badsig.${file}.${DATE}"
156 mv "${GPGSTATUS}" "${ERRORS}/badsig.${file}.gpgstatus.${DATE}"
157 mv "${GPGLOGS}" "${ERRORS}/badsig.${file}.gpglogs.${DATE}"
162 # So at this point we know we accepted the signature of the file as valid,
163 # that is it is from a key allowed for this architecture. Which only
164 # leaves us with the task of checking if there is a key to remove, and then remove
165 # it. We won't even check they have a key left, so if they want to they can
166 # empty out the set for an architecture
168 # Read in the GPGOUTF, but avoid using a subshell like a
169 # while read line otherwise would do
170 exec 4<> "${GPGOUTF}"
172 while read line <&4; do
173 if [[ $line =~ key:.([0-9A-F]{16}) ]]; then
174 KEYID=${BASH_REMATCH[1]}
175 elif [[ $line =~ comment:.(.*) ]]; then
176 COMMENT=${BASH_REMATCH[1]}
182 # Right, we have the keyid, know the arch, lets see if we can remove it
183 ARCHKEYRING="${base}/${ARCH}/keyring.gpg"
185 # Is the key in there?
186 KEYNO=$(gpg ${DEFGPGOPT} --keyring "${ARCHKEYRING}" --with-colons --list-keys ${KEYID} | grep -c '^pub:' || /bin/true )
188 if [ $KEYNO -eq 1 ]; then
189 # Right, exactly one there, lets get rid of it
190 # So put it into the removed keyring
191 gpg ${DEFGPGOPT} --keyring "${ARCHKEYRING}" --export ${KEYID} | gpg ${DEFGPGOPT} --keyring "${REMOVED}" --import 2>/dev/null
192 if gpg ${DEFGPGOPT} --keyring "${ARCHKEYRING}" --yes --delete-keys ${KEYID}; then
193 log "Removed key ${KEYID}, reason: ${COMMENT}"
194 mv "${INCOMING}/${file}" "${base}/${ARCH}"
198 log "Found more (or less) than one key I could delete. Not doing anything"
200 mv "${INCOMING}/${file}" "${ERRORS}/toomanykeys.${file}.${DATE}"
201 mv "${GPGSTATUS}" "${ERRORS}/toomanykeys.${file}.gpgstatus.${DATE}"
202 mv "${GPGLOGS}" "${ERRORS}/toomanykeys.${file}.gpglogs.${DATE}"
203 echo "${error}" >> "${ERRORS}/toomanykeys.${file}.error.${DATE}"