#!/usr/bin/python -tt # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Library General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # Copyright 2003 Duke University # Seth Vidal skvidal at phy.duke.edu ###### # Simple docs: run it with a list of rpms as the args # it will tell you if any of them is damaged and if so how # it will tell you if any of them has a bad key or invalid sig or whatever # it exits with the largest error code possible for the set of pkgs # error codes are: # 0 - all fine # 100 = damaged pkg # 101 = unsigned pkg # 102 = signed but bad pkg - if we ever get this one I'll be amazed # 103 = signed - but key not in rpmdb # 104 = signed but untrusted key import rpm import re import os import os.path import sys def lookupKeyID(ts, keyid): """looks up a key id - returns the header""" mi = ts.dbMatch('name','gpg-pubkey') mi.pattern('version', rpm.RPMMIRE_STRCMP, keyid) for hdr in mi: sum = hdr['summary'] mo = re.search('\<.*\>', sum) email = mo.group() return email def checkSig(ts, package): """ take a package, check it's sigs, return 0 if they are all fine, return 103 if the gpg key can't be found, 104 if the key is not trusted,100 if the header is in someway damaged""" try: fdno = os.open(package, os.O_RDONLY) except OSError, e: return 100 stderr = os.dup(2) null = os.open("/dev/null", os.O_WRONLY | os.O_APPEND) os.dup2(null, 2) try: ts.hdrFromFdno(fdno) except rpm.error, e: if str(e) == "public key not availaiable": error = 103 if str(e) == "public key not available": error = 103 if str(e) == "public key not trusted": error = 104 if str(e) == "error reading package header": error = 100 os.dup2(stderr, 2) os.close(null) os.close(stderr) os.close(fdno) return error os.dup2(stderr, 2) os.close(null) os.close(stderr) os.close(fdno) return 0 def returnHdr(ts, package): """hand back the hdr - duh - if the pkg is foobar handback None""" try: fdno = os.open(package, os.O_RDONLY) except OSError, e: hdr = None return hdr ts.setVSFlags(~(rpm.RPMVSF_NOMD5|rpm.RPMVSF_NEEDPAYLOAD)) try: hdr = ts.hdrFromFdno(fdno) except rpm.error, e: hdr = None if type(hdr) != rpm.hdr: hdr = None ts.setVSFlags(0) os.close(fdno) return hdr def getSigInfo(hdr): """hand back signature information and an error code""" string = '%|DSAHEADER?{%{DSAHEADER:pgpsig}}:{%|RSAHEADER?{%{RSAHEADER:pgpsig}}:{%|SIGGPG?{%{SIGGPG:pgpsig}}:{%|SIGPGP?{%{SIGPGP:pgpsig}}:{(none)}|}|}|}|' siginfo = hdr.sprintf(string) if siginfo != '(none)': error = 0 sigtype, sigdate, sigid = siginfo.split(',') else: error = 101 sigtype = 'MD5' sigdate = 'None' sigid = 'None' infotuple = (sigtype, sigdate, sigid) return error, infotuple def main(args): finalexit = 0 ts = rpm.TransactionSet() for package in args: error = 0 sigerror = 0 ts.setVSFlags(0) error = checkSig(ts, package) hdr = returnHdr(ts, package) if hdr == None: error = 100 print '%s: FAILED - None ' % package else: sigerror, (sigtype, sigdate, sigid) = getSigInfo(hdr) if sigid == 'None': email = '' keyid = 'None' else: keyid = sigid[-8:] email = lookupKeyID(ts, keyid) if error != 0: if error == 103: print '%s: MISSING KEY - %s' % (package, keyid) else: print '%s: FAILED - %s %s' % (package, keyid, email) else: print '%s: %s - %s - %s' % (package, sigtype, keyid, email) if error < sigerror: error = sigerror if error > finalexit: finalexit = error del hdr sys.exit(finalexit) if __name__ == '__main__': main(sys.argv[1:])