X-Git-Url: https://git.adam-barratt.org.uk/?p=mirror%2Fuserdir-ldap.git;a=blobdiff_plain;f=ud-gpgimport;h=4e26a5e8bb9905a9ba95821392792ab062c326bc;hp=c85c9ba7770b80631ee1601a136efc1e0cac2379;hb=HEAD;hpb=8be45fd03d84447c0f75dc77bd94ed4e6580f0f6 diff --git a/ud-gpgimport b/ud-gpgimport index c85c9ba..4e26a5e 100755 --- a/ud-gpgimport +++ b/ud-gpgimport @@ -1,5 +1,25 @@ #!/usr/bin/env python # -*- mode: python -*- + +# Copyright (c) 1999-2000 Jason Gunthorpe +# Copyright (c) 2004 Joey Schulze +# Copyright (c) 2008, 2009, 2010 Peter Palfrader +# Copyright (c) 2010 Martin Zobel-Helas +# +# 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 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., 675 Mass Ave, Cambridge, MA 02139, USA. + # This script tries to match key fingerprints from a keyring with user # name in a directory. When an unassigned key is found a heuristic match # against the keys given cn/sn and the directory is performed to try to get @@ -14,7 +34,7 @@ # in the directory but not in the key ring will be removed from the # directory. -import string, re, time, ldap, getopt, sys, pwd, posix; +import re, time, ldap, getopt, sys, pwd, os; from userdir_ldap import *; from userdir_gpg import *; @@ -23,8 +43,6 @@ from userdir_gpg import *; UnknownMap = {}; NoAct = 1; -AddressSplit = re.compile("(.*).*<([^@]*)@([^>]*)>"); - # Read the override file into the unknown map. The override file is a list # of colon delimited entires mapping PGP email addresess to local users def LoadOverride(File): @@ -34,107 +52,107 @@ def LoadOverride(File): if Line == "": break; Split = re.split("[:\n]",Line); - UnknownMap[Split[0]] = string.strip(Split[1]); - -# Convert the PGP name string to a uid value -def GetUID(l,Name): - # Crack up the email address into a best guess first/middle/last name - (cn,mn,sn) = NameSplit(re.sub('["]','',Name[0])) - - # Brackets anger the ldap searcher - cn = re.sub('[(")]','?',cn); - sn = re.sub('[(")]','?',sn); - - # First check the unknown map for the email address - if UnknownMap.has_key(Name[1] + '@' + Name[2]): - print "unknown map hit for",Name; - return UnknownMap[Name[1] + '@' + Name[2]]; - - # Then the cruft component (ie there was no email address to match) - if UnknownMap.has_key(Name[2]): - print "unknown map hit for",Name; - return UnknownMap[Name[2]]; - - # Search for a possible first/last name hit - try: - Attrs = l.search_s(BaseDn,ldap.SCOPE_ONELEVEL,"(&(cn=%s)(sn=%s))"%(cn,sn),["uid"]); - except ldap.FILTER_ERROR: - print "Filter failure:","(&(cn=%s)(sn=%s))"%(cn,sn); - return None; - - # Hmm, more than one/no return - if (len(Attrs) != 1): - # Key claims a local address - if Name[2] == EmailAppend: - - # Pull out the record for the claimed user - Attrs = l.search_s(BaseDn,ldap.SCOPE_ONELEVEL,"(uid=%s)"%(Name[1]),["uid","sn","cn"]); - - # We require the UID surname to be someplace in the key name, this - # deals with special purpose keys like 'James Troup (Alternate Debian key)' - # Some people put their names backwards on their key too.. check that as well - if len(Attrs) == 1 and \ - (string.find(string.lower(sn),string.lower(Attrs[0][1]["sn"][0])) != -1 or \ - string.find(string.lower(cn),string.lower(Attrs[0][1]["sn"][0])) != -1): - print EmailAppend,"hit for",Name; - return Name[1]; - - # Attempt to give some best guess suggestions for use in editing the - # override file. - print "None for",Name; - Attrs = l.search_s(BaseDn,ldap.SCOPE_ONELEVEL,"(sn~=%s)"%(sn),["uid","sn","cn"]); - for x in Attrs: - print " But might be:",x[1]["cn"][0],x[1]["sn"][0],"<" + x[1]["uid"][0] + "@debian.org>"; - else: - return Attrs[0][1]["uid"][0]; + UnknownMap[Split[0]] = Split[1].strip() + + +def load_keys_from_gpg(keyrings): + keys = {} + + # Popen GPG with the correct magic special options + ClearKeyrings() + SetKeyrings(keyrings) + + Args = [GPGPath] + GPGBasicOptions + GPGKeyRings + GPGSearchOptions + [" 2> /dev/null"] + Keys = os.popen(" ".join(Args),"r"); + + # Loop over the GPG key file + Outstanding = 0; + while(1): + Line = Keys.readline(); + if Line == "": + break; + + Split = Line.split(":") + if len(Split) < 8 or Split[0] != "pub": + continue; + + while (1): + Line2 = Keys.readline(); + if Line2 == "": + break; + Split2 = Line2.split(":"); + if len(Split2) < 11 or Split2[0] != "fpr": + continue; + break; + if Line2 == "": + break; + + pgp_uid = Split[9] + fingerprint = Split2[9] + + if fingerprint in keys: + print "Duplicate key in keyrings: %s, belonging to %s"%(fingerprint, pgp_uid) + continue + keys[fingerprint] = pgp_uid + + if Keys.close() != None: + raise "Error","GPG failed" + + return keys + + + + - return None; # Process options -AdminUser = pwd.getpwuid(posix.getuid())[0]; -(options, arguments) = getopt.getopt(sys.argv[1:], "au:m:n") +AdminUser = pwd.getpwuid(os.getuid())[0]; +(options, arguments) = getopt.getopt(sys.argv[1:], "ahu:m:") for (switch, val) in options: if (switch == '-u'): AdminUser = val elif (switch == '-m'): LoadOverride(val); + elif (switch == '-h'): + print "Usage: ud-gpgimport " + print "Available options:" + print " -h Show this help" + print " -u= Admin user (defaults to current username)" + print " -m= Override file to use" + print " -a actually do changes, not dry-run" + sys.exit(0) elif (switch == '-a'): NoAct = 0; -if len(arguments) == 0: - print "Give some keyrings to probe"; - os.exit(0); + # Main program starts here # Connect to the ldap server -l = ldap.open(LDAPServer); if NoAct == 0: - print "Accessing LDAP directory as '" + AdminUser + "'"; - Password = getpass(AdminUser + "'s password: "); - UserDn = "uid=" + AdminUser + "," + BaseDn; - l.simple_bind_s(UserDn,Password); + l = passwdAccessLDAP(BaseDn, AdminUser) else: + l = connectLDAP() l.simple_bind_s("",""); # Download the existing key list and put it into a map print "Fetching key list..", sys.stdout.flush(); -Attrs = l.search_s(BaseDn,ldap.SCOPE_ONELEVEL,"keyfingerprint=*",["keyfingerprint","uid"]); +Attrs = l.search_s(BaseDn,ldap.SCOPE_ONELEVEL,"keyFingerPrint=*",["keyFingerPrint","uid"]); KeyMap = {}; KeyCount = {}; for x in Attrs: try: # Sense a bad fingerprint.. Slapd has problems, it will store a null # value that ldapsearch doesn't show up.. detect and remove - if len(x[1]["keyfingerprint"]) == 0 or x[1]["keyfingerprint"][0] == "": + if len(x[1]["keyFingerPrint"]) == 0 or x[1]["keyFingerPrint"][0] == "": print; print "Fixing bad fingerprint for",x[1]["uid"][0], sys.stdout.flush(); if NoAct == 0: l.modify_s("uid="+x[1]["uid"][0]+","+BaseDn,\ - [(ldap.MOD_DELETE,"keyfingerprint",None)]); + [(ldap.MOD_DELETE,"keyFingerPrint",None)]); else: - for I in x[1]["keyfingerprint"]: + for I in x[1]["keyFingerPrint"]: KeyMap[I] = [x[1]["uid"][0],0]; if KeyCount.has_key(x[1]["uid"][0]): KeyCount[x[1]["uid"][0]] = KeyCount[x[1]["uid"][0]] + 1; @@ -145,70 +163,36 @@ for x in Attrs: Attrs = None; print; -# Popen GPG with the correct magic special options -Args = [GPGPath] + GPGBasicOptions; -for x in arguments: - Args.append("--keyring"); - if string.find(x,"/") == -1: - Args.append("./"+x); - else: - Args.append(x); -Args = Args + GPGSearchOptions + [" 2> /dev/null"] -Keys = os.popen(string.join(Args," "),"r"); -# Loop over the GPG key file -Outstanding = 0; -Ignored = 0; -SeenKeys = {}; -while(1): - Line = Keys.readline(); - if Line == "": - break; - - Split = string.split(Line,":"); - if len(Split) < 8 or Split[0] != "pub": - continue; +pgpkeys = load_keys_from_gpg( ConfModule.add_keyrings.split(":") ) +pgpkeys_extra = load_keys_from_gpg( ConfModule.add_keyrings_guest.split(":") ) - while (1): - Line2 = Keys.readline(); - if Line2 == "": - break; - Split2 = string.split(Line2,":"); - if len(Split2) < 11 or Split2[0] != "fpr": - continue; - break; - if Line2 == "": - break; - - if SeenKeys.has_key(Split2[9]): - print "Dup key 0x",Split2[9],"belonging to",KeyMap[Split2[9]][0]; - continue; - SeenKeys[Split2[9]] = None; - - if KeyMap.has_key(Split2[9]): +Ignored = 0; +for fpr in pgpkeys: + pgp_uid = pgpkeys[fpr] + if fpr in KeyMap: Ignored = Ignored + 1; - # print "Ignoring keyID",Split2[9],"belonging to",KeyMap[Split2[9]][0]; - KeyMap[Split2[9]][1] = 1; + # print "Ignoring keyID",fpr,"belonging to",KeyMap[fpr][0]; + KeyMap[fpr][1] = 1; continue; - Match = AddressSplit.match(Split[9]); - if Match == None: - UID = GetUID(l,("","",Split[9])); - else: - UID = GetUID(l,Match.groups()); - - if UID == None: - print "MISSING 0x" + Split2[9]; + UID = GetUID(l,SplitEmail(pgp_uid),UnknownMap); + if UID[0] == None: + print "Unassigned key in keyrings: %s, belonging to %s"%(fpr, pgp_uid) + if UID[1] != None: + for x in UID[1]: print x; + print "MISSING " + fpr; continue; - Rec = [(ldap.MOD_ADD,"keyfingerprint",Split2[9])]; + UID = UID[0] + Rec = [(ldap.MOD_ADD,"keyFingerPrint",fpr)]; Dn = "uid=" + UID + "," + BaseDn; - print "Adding key 0x",Split2[9],"to",UID; + print "Adding key "+fpr,"to",UID; if KeyCount.has_key(UID): KeyCount[UID] = KeyCount[UID] + 1; else: KeyCount[UID] = 1; - + if NoAct == 1: continue; @@ -221,20 +205,20 @@ while(1): if NoAct == 0: FlushOutstanding(l,Outstanding); -if Keys.close() != None: - raise "Error","GPG failed" - print Ignored,"keys already in the directory (ignored)"; # Look for unmatched keys for x in KeyMap.keys(): - if KeyMap[x][1] == 0: - print "key 0x",x,"belonging to",KeyMap[x][0],"removed"; + if KeyMap[x][1] == 0 and not x in pgpkeys_extra: + print "key %s belonging to %s removed"%(x,KeyMap[x][0]); if KeyCount.has_key(KeyMap[x][0]) : KeyCount[KeyMap[x][0]] = KeyCount[KeyMap[x][0]] - 1 if KeyCount[KeyMap[x][0]] <= 0: print "**",KeyMap[x][0],"no longer has any keys"; if NoAct == 0: l.modify_s("uid="+KeyMap[x][0]+","+BaseDn,\ - [(ldap.MOD_DELETE,"keyfingerprint",x)]); - + [(ldap.MOD_DELETE,"keyFingerPrint",x)]); + +# vim:set et: +# vim:set ts=3: +# vim:set shiftwidth=3: