3 """ Imports a keyring into the database """
4 # Copyright (C) 2007 Anthony Towns <aj@erisian.com.au>
5 # Copyright (C) 2009 Mark Hymers <mhy@debian.org>
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 2 of the License, or
10 # (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with this program; if not, write to the Free Software
19 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 ################################################################################
26 from daklib.config import Config
27 from daklib.dbconn import *
32 ################################################################################
34 def get_uid_info(session):
37 q = session.execute("SELECT id, uid, name FROM uid")
38 for (keyid, uid, name) in q.fetchall():
39 byname[uid] = (keyid, name)
40 byid[keyid] = (uid, name)
44 def get_fingerprint_info(session):
46 q = session.execute("SELECT f.fingerprint, f.id, f.uid, f.keyring FROM fingerprint f")
47 for (fingerprint, fingerprint_id, uid, keyring) in q.fetchall():
48 fins[fingerprint] = (uid, fingerprint_id, keyring)
51 def list_uids(session, pattern):
52 sql_pattern = "%%%s%%" % pattern
53 message = "List UIDs matching pattern %s" % sql_pattern
54 message += "\n" + ("=" * len(message))
56 uid_query = session.query(Uid).filter(Uid.uid.ilike(sql_pattern))
57 for uid in uid_query.all():
58 print "\nuid %s" % uid.uid
59 for fp in uid.fingerprint:
60 print " fingerprint %s" % fp.fingerprint
63 keyring = fp.keyring.keyring_name
64 print " keyring %s" % keyring
66 ################################################################################
68 def usage (exit_code=0):
69 print """Usage: dak import-keyring [OPTION]... [KEYRING]
70 -h, --help show this help and exit.
71 -L, --import-ldap-users generate uid entries for keyring from LDAP
72 -U, --generate-users FMT generate uid entries from keyring as FMT
73 -l, --list-uids STRING list all uids matching *STRING*"""
77 ################################################################################
83 Arguments = [('h',"help","Import-Keyring::Options::Help"),
84 ('L',"import-ldap-users","Import-Keyring::Options::Import-Ldap-Users"),
85 ('U',"generate-users","Import-Keyring::Options::Generate-Users", "HasArg"),
86 ('l',"list-uids","Import-Keyring::Options::List-UIDs", "HasArg"),
89 for i in [ "help", "report-changes", "generate-users", "import-ldap-users", "list-uids"]:
90 if not cnf.has_key("Import-Keyring::Options::%s" % (i)):
91 cnf["Import-Keyring::Options::%s" % (i)] = ""
93 keyring_names = apt_pkg.ParseCommandLine(cnf.Cnf, Arguments, sys.argv)
97 Options = cnf.SubTree("Import-Keyring::Options")
103 session = DBConn().session()
105 if Options["List-UIDs"]:
106 list_uids(session, Options["List-UIDs"])
109 if len(keyring_names) != 1:
112 ### Keep track of changes made
113 changes = [] # (uid, changes strings)
115 ### Cache all the existing fingerprint entries
116 db_fin_info = get_fingerprint_info(session)
118 ### Parse the keyring
120 keyringname = keyring_names[0]
121 keyring = get_keyring(keyringname, session)
123 print "E: Can't load keyring %s from database" % keyringname
126 keyring.load_keys(keyringname)
128 ### Generate new uid entries if they're needed (from LDAP or the keyring)
129 if Options["Generate-Users"]:
130 format = Options["Generate-Users"]
131 (desuid_byname, desuid_byid) = keyring.generate_users_from_keyring(Options["Generate-Users"], session)
132 elif Options["Import-Ldap-Users"]:
133 (desuid_byname, desuid_byid) = keyring.import_users_from_ldap(session)
135 (desuid_byname, desuid_byid) = ({}, {})
137 ### Cache all the existing uid entries
138 (db_uid_byname, db_uid_byid) = get_uid_info(session)
140 ### Update full names of applicable users
141 for keyid in desuid_byid.keys():
142 uid = (keyid, desuid_byid[keyid][0])
143 name = desuid_byid[keyid][1]
144 oname = db_uid_byid[keyid][1]
145 if name and oname != name:
146 changes.append((uid[1], "Full name: %s" % (name)))
147 session.execute("UPDATE uid SET name = :name WHERE id = :keyid",
148 {'name': name, 'keyid': keyid})
150 # The fingerprint table (fpr) points to a uid and a keyring.
151 # If the uid is being decided here (ldap/generate) we set it to it.
152 # Otherwise, if the fingerprint table already has a uid (which we've
153 # cached earlier), we preserve it.
154 # Otherwise we leave it as None
157 for z in keyring.keys.keys():
158 keyid = db_uid_byname.get(keyring.keys[z].get("uid", None), [None])[0]
160 keyid = db_fin_info.get(keyring.keys[z]["fingerprints"][0], [None])[0]
161 for y in keyring.keys[z]["fingerprints"]:
162 fpr[y] = (keyid, keyring.keyring_id)
164 # For any keys that used to be in this keyring, disassociate them.
165 # We don't change the uid, leaving that for historical info; if
166 # the id should change, it'll be set when importing another keyring.
168 for f,(u,fid,kr) in db_fin_info.iteritems():
169 if kr != keyring.keyring_id:
175 changes.append((db_uid_byid.get(u, [None])[0], "Removed key: %s" % (f)))
176 session.execute("""UPDATE fingerprint
178 source_acl_id = NULL,
179 binary_acl_id = NULL,
181 WHERE id = :fprid""", {'fprid': fid})
183 session.execute("""DELETE FROM binary_acl_map WHERE fingerprint_id = :fprid""", {'fprid': fid})
185 # For the keys in this keyring, add/update any fingerprints that've
190 newuiduid = db_uid_byid.get(newuid, [None])[0]
192 (olduid, oldfid, oldkid) = db_fin_info.get(f, [-1,-1,-1])
201 changes.append((newuiduid, "Added key: %s" % (f)))
204 fp.keyring_id = keyring.keyring_id
208 fp.binary_acl_id = keyring.default_binary_acl_id
209 fp.source_acl_id = keyring.default_source_acl_id
210 fp.default_binary_reject = keyring.default_binary_reject
214 for k in keyring.keyring_acl_map:
216 ba.fingerprint_id = fp.fingerprint_id
217 ba.architecture_id = k.architecture_id
222 if newuid and olduid != newuid and olduid == -1:
223 changes.append((newuiduid, "Linked key: %s" % f))
224 changes.append((newuiduid, " (formerly unowned)"))
225 session.execute("UPDATE fingerprint SET uid = :uid WHERE id = :fpr",
226 {'uid': newuid, 'fpr': oldfid})
228 # Don't move a key from a keyring with a higher priority to a lower one
229 if oldkid != keyring.keyring_id:
235 oldkeyring = session.query(Keyring).filter_by(keyring_id=oldkid).one()
236 except NotFoundError:
237 print "ERROR: Cannot find old keyring with id %s" % oldkid
240 if oldkeyring.priority < keyring.priority:
243 # Only change the keyring if it won't result in a loss of permissions
245 session.execute("""DELETE FROM binary_acl_map WHERE fingerprint_id = :fprid""", {'fprid': oldfid})
247 session.execute("""UPDATE fingerprint
248 SET keyring = :keyring,
249 source_acl_id = :source_acl_id,
250 binary_acl_id = :binary_acl_id,
251 binary_reject = :binary_reject
253 {'keyring': keyring.keyring_id,
254 'source_acl_id': keyring.default_source_acl_id,
255 'binary_acl_id': keyring.default_binary_acl_id,
256 'binary_reject': keyring.default_binary_reject,
261 for k in keyring.keyring_acl_map:
263 ba.fingerprint_id = oldfid
264 ba.architecture_id = k.architecture_id
269 print "Key %s exists in both %s and %s keyrings. Not demoting." % (f,
270 oldkeyring.keyring_name,
271 keyring.keyring_name)
278 for (k, v) in changes:
279 if k not in changesd:
281 changesd[k] += " %s\n" % (v)
283 keys = changesd.keys()
286 print "%s\n%s\n" % (k, changesd[k])
288 ################################################################################
290 if __name__ == '__main__':