提交 1dccc682 编写于 作者: A Anthony Towns

import_keyring: add support for creating users from LDAP, so that

   dak import-keyring -L .../debian-keyring.gpg
can be used as a (non-interactive) replacement for import-ldap-fingerprints
上级 dca65005
...@@ -20,8 +20,8 @@ ...@@ -20,8 +20,8 @@
################################################################################ ################################################################################
import daklib.database, daklib.logging import daklib.database, daklib.logging
import apt_pkg, pg import sys, os, re
import sys, os, email.Utils, re import apt_pkg, pg, ldap, email.Utils
# Globals # Globals
Cnf = None Cnf = None
...@@ -31,9 +31,6 @@ Logger = None ...@@ -31,9 +31,6 @@ Logger = None
################################################################################ ################################################################################
# These could possibly be daklib.db functions, and reused by
# import-ldap-fingerprints
def get_uid_info(): def get_uid_info():
byname = {} byname = {}
byid = {} byid = {}
...@@ -52,12 +49,23 @@ def get_fingerprint_info(): ...@@ -52,12 +49,23 @@ def get_fingerprint_info():
################################################################################ ################################################################################
def get_ldap_name(entry):
name = []
for k in ["cn", "mn", "sn"]:
ret = entry.get(k)
if ret and ret[0] != "" and ret[0] != "-":
name.append(ret[0])
return " ".join(name)
################################################################################
class Keyring: class Keyring:
gpg_invocation = "gpg --no-default-keyring --keyring %s" +\ gpg_invocation = "gpg --no-default-keyring --keyring %s" +\
" --with-colons --fingerprint --fingerprint" " --with-colons --fingerprint --fingerprint"
keys = {} keys = {}
fpr_lookup = {}
def de_escape_str(self, str): def de_escape_gpg_str(self, str):
esclist = re.split(r'(\\x..)', str) esclist = re.split(r'(\\x..)', str)
for x in range(1,len(esclist),2): for x in range(1,len(esclist),2):
esclist[x] = "%c" % (int(esclist[x][2:],16)) esclist[x] = "%c" % (int(esclist[x][2:],16))
...@@ -67,6 +75,7 @@ class Keyring: ...@@ -67,6 +75,7 @@ class Keyring:
k = os.popen(self.gpg_invocation % keyring, "r") k = os.popen(self.gpg_invocation % keyring, "r")
keys = self.keys keys = self.keys
key = None key = None
fpr_lookup = self.fpr_lookup
signingkey = False signingkey = False
for line in k.xreadlines(): for line in k.xreadlines():
field = line.split(":") field = line.split(":")
...@@ -77,7 +86,7 @@ class Keyring: ...@@ -77,7 +86,7 @@ class Keyring:
if name == "" or addr == "" or "@" not in addr: if name == "" or addr == "" or "@" not in addr:
name = field[9] name = field[9]
addr = "invalid-uid" addr = "invalid-uid"
name = self.de_escape_str(name) name = self.de_escape_gpg_str(name)
keys[key] = {"email": addr} keys[key] = {"email": addr}
if name != "": keys[key]["name"] = name if name != "": keys[key]["name"] = name
keys[key]["aliases"] = [name] keys[key]["aliases"] = [name]
...@@ -91,11 +100,51 @@ class Keyring: ...@@ -91,11 +100,51 @@ class Keyring:
keys[key]["aliases"].append(name) keys[key]["aliases"].append(name)
elif signingkey and field[0] == "fpr": elif signingkey and field[0] == "fpr":
keys[key]["fingerprints"].append(field[9]) keys[key]["fingerprints"].append(field[9])
fpr_lookup[field[9]] = key
def generate_desired_users(self):
if Options["Generate-Users"]:
format = Options["Generate-Users"]
return self.generate_users_from_keyring(format)
if Options["Import-Ldap-Users"]:
return self.import_users_from_ldap()
return ({}, {})
def import_users_from_ldap(self):
LDAPDn = Cnf["Import-LDAP-Fingerprints::LDAPDn"]
LDAPServer = Cnf["Import-LDAP-Fingerprints::LDAPServer"]
l = ldap.open(LDAPServer)
l.simple_bind_s("","")
Attrs = l.search_s(LDAPDn, ldap.SCOPE_ONELEVEL,
"(&(keyfingerprint=*)(gidnumber=%s))" % (Cnf["Import-Users-From-Passwd::ValidGID"]),
["uid", "keyfingerprint", "cn", "mn", "sn"])
ldap_fin_uid_id = {}
def desired_users(self, format="%s"): byuid = {}
if not Options["Generate-Users"]: byname = {}
return ({}, {}) keys = self.keys
fpr_lookup = self.fpr_lookup
for i in Attrs:
entry = i[1]
uid = entry["uid"][0]
name = get_ldap_name(entry)
fingerprints = entry["keyFingerPrint"]
id = None
for f in fingerprints:
key = fpr_lookup.get(f, None)
if key not in keys: continue
keys[key]["uid"] = uid
if id != None: continue
id = daklib.database.get_or_set_uid_id(uid)
byuid[id] = (uid, name)
byname[uid] = (id, name)
return (byname, byuid)
def generate_users_from_keyring(self, format):
byuid = {} byuid = {}
byname = {} byname = {}
keys = self.keys keys = self.keys
...@@ -103,11 +152,13 @@ class Keyring: ...@@ -103,11 +152,13 @@ class Keyring:
for x in keys.keys(): for x in keys.keys():
if keys[x]["email"] == "invalid-uid": if keys[x]["email"] == "invalid-uid":
any_invalid = True any_invalid = True
keys[x]["uid"] = format % "invalid-uid"
else: else:
uid = format % keys[x]["email"] uid = format % keys[x]["email"]
id = daklib.database.get_or_set_uid_id(uid) id = daklib.database.get_or_set_uid_id(uid)
byuid[id] = (uid, keys[x]["name"]) byuid[id] = (uid, keys[x]["name"])
byname[uid] = (id, keys[x]["name"]) byname[uid] = (id, keys[x]["name"])
keys[x]["uid"] = uid
if any_invalid: if any_invalid:
uid = format % "invalid-uid" uid = format % "invalid-uid"
id = daklib.database.get_or_set_uid_id(uid) id = daklib.database.get_or_set_uid_id(uid)
...@@ -120,6 +171,7 @@ class Keyring: ...@@ -120,6 +171,7 @@ class Keyring:
def usage (exit_code=0): def usage (exit_code=0):
print """Usage: dak import-keyring [OPTION]... [KEYRING] print """Usage: dak import-keyring [OPTION]... [KEYRING]
-h, --help show this help and exit. -h, --help show this help and exit.
-L, --import-ldap-users generate uid entries for keyring from LDAP
-U, --generate-users FMT generate uid entries from keyring as FMT""" -U, --generate-users FMT generate uid entries from keyring as FMT"""
sys.exit(exit_code) sys.exit(exit_code)
...@@ -131,50 +183,55 @@ def main(): ...@@ -131,50 +183,55 @@ def main():
Cnf = daklib.utils.get_conf() Cnf = daklib.utils.get_conf()
Arguments = [('h',"help","Import-Keyring::Options::Help"), Arguments = [('h',"help","Import-Keyring::Options::Help"),
('L',"import-ldap-users","Import-Keyring::Options::Import-Ldap-Users"),
('U',"generate-users","Import-Keyring::Options::Generate-Users", "HasArg"), ('U',"generate-users","Import-Keyring::Options::Generate-Users", "HasArg"),
] ]
for i in [ "help", "report-changes", "generate-users" ]: for i in [ "help", "report-changes", "generate-users", "import-ldap-users" ]:
if not Cnf.has_key("Import-Keyring::Options::%s" % (i)): if not Cnf.has_key("Import-Keyring::Options::%s" % (i)):
Cnf["Import-Keyring::Options::%s" % (i)] = "" Cnf["Import-Keyring::Options::%s" % (i)] = ""
keyring_names = apt_pkg.ParseCommandLine(Cnf, Arguments, sys.argv) keyring_names = apt_pkg.ParseCommandLine(Cnf, Arguments, sys.argv)
### Parse options
Options = Cnf.SubTree("Import-Keyring::Options") Options = Cnf.SubTree("Import-Keyring::Options")
if Options["Help"]: if Options["Help"]:
usage() usage()
uid_format = "%s" if len(keyring_names) != 1:
if Options["Generate-Users"]: usage(1)
uid_format = Options["Generate-Users"]
### Keep track of changes made
changes = [] # (uid, changes strings) changes = [] # (uid, changes strings)
### Initialise
projectB = pg.connect(Cnf["DB::Name"], Cnf["DB::Host"], int(Cnf["DB::Port"])) projectB = pg.connect(Cnf["DB::Name"], Cnf["DB::Host"], int(Cnf["DB::Port"]))
daklib.database.init(Cnf, projectB) daklib.database.init(Cnf, projectB)
projectB.query("BEGIN WORK") projectB.query("BEGIN WORK")
if len(keyring_names) != 1: ### Cache all the existing fingerprint entries
usage(1)
db_fin_info = get_fingerprint_info()
### Parse the keyring
# Parse the keyring
keyringname = keyring_names[0] keyringname = keyring_names[0]
keyring = Keyring(keyringname) keyring = Keyring(keyringname)
keyring_id = daklib.database.get_or_set_keyring_id( keyring_id = daklib.database.get_or_set_keyring_id(
keyringname.split("/")[-1]) keyringname.split("/")[-1])
# If we're generating uids, make sure we have entries in the uid ### Generate new uid entries if they're needed (from LDAP or the keyring)
# table for every uid (desuid_byname, desuid_byid) = keyring.generate_desired_users()
(desuid_byname, desuid_byid) = keyring.desired_users(uid_format)
# Cache all the existing fingerprint and uid entries ### Cache all the existing uid entries
db_fin_info = get_fingerprint_info()
(db_uid_byname, db_uid_byid) = get_uid_info() (db_uid_byname, db_uid_byid) = get_uid_info()
# Update full names of uids ### Update full names of applicable users
for id in desuid_byid.keys(): for id in desuid_byid.keys():
uid = (id, desuid_byid[id][0]) uid = (id, desuid_byid[id][0])
name = desuid_byid[id][1] name = desuid_byid[id][1]
...@@ -184,27 +241,30 @@ def main(): ...@@ -184,27 +241,30 @@ def main():
projectB.query("UPDATE uid SET name = '%s' WHERE id = %s" % projectB.query("UPDATE uid SET name = '%s' WHERE id = %s" %
(pg.escape_string(name), id)) (pg.escape_string(name), id))
# Work out what the fingerprint table should look like for the keys # The fingerprint table (fpr) points to a uid and a keyring.
# in this keyring # If the uid is being decided here (ldap/generate) we set it to it.
# Otherwise, if the fingerprint table already has a uid (which we've
# cached earlier), we preserve it.
# Otherwise we leave it as None
fpr = {} fpr = {}
for z in keyring.keys.keys(): for z in keyring.keys.keys():
id = db_uid_byname.get(uid_format % keyring.keys[z]["email"], [None])[0] id = db_uid_byname.get(keyring.keys[z].get("uid", None), [None])[0]
if id == None: if id == None:
id = db_fin_info.get(keyring.keys[z]["fingerprints"][0], [None])[0] id = db_fin_info.get(keyring.keys[z]["fingerprints"][0], [None])[0]
for y in keyring.keys[z]["fingerprints"]: for y in keyring.keys[z]["fingerprints"]:
fpr[y] = (id,keyring_id) fpr[y] = (id,keyring_id)
# For any keys that used to be in this keyring, disassociate them. # For any keys that used to be in this keyring, disassociate them.
# We don't change the uid, leaving that to for historical info; if # We don't change the uid, leaving that for historical info; if
# the id should change, it'll be set when importing another keyring # the id should change, it'll be set when importing another keyring.
# or importing ldap fingerprints.
for f,(u,fid,kr) in db_fin_info.iteritems(): for f,(u,fid,kr) in db_fin_info.iteritems():
if kr != keyring_id: continue if kr != keyring_id: continue
if f in fpr: continue if f in fpr: continue
changes.append((db_uid_byid.get(u, [None])[0], "Removed key: %s\n" % (f))) changes.append((db_uid_byid.get(u, [None])[0], "Removed key: %s\n" % (f)))
projectB.query("UPDATE fingerprint SET keyring = NULL WHERE id = %d" % (fid)) projectB.query("UPDATE fingerprint SET keyring = NULL WHERE id = %d" % (fid))
# For the keys in this keyring, add/update any fingerprints that've # For the keys in this keyring, add/update any fingerprints that've
# changed. # changed.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册