Package dak :: Module import_keyring
[hide private]
[frames] | no frames]

Source Code for Module dak.import_keyring

  1  #! /usr/bin/env python3 
  2   
  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> 
  6   
  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. 
 11   
 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. 
 16   
 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 
 20   
 21  ################################################################################ 
 22   
 23  import sys 
 24  import apt_pkg 
 25   
 26  from daklib.config import Config 
 27  from daklib.dbconn import * 
 28   
 29  # Globals 
 30  Options = None 
 31   
 32  ################################################################################ 
 33   
 34   
35 -def get_uid_info(session):
36 byname = {} 37 byid = {} 38 q = session.execute("SELECT id, uid, name FROM uid") 39 for (keyid, uid, name) in q.fetchall(): 40 byname[uid] = (keyid, name) 41 byid[keyid] = (uid, name) 42 43 return (byname, byid)
44 45
46 -def get_fingerprint_info(session):
47 fins = {} 48 q = session.execute("SELECT f.fingerprint, f.id, f.uid, f.keyring FROM fingerprint f") 49 for (fingerprint, fingerprint_id, uid, keyring) in q.fetchall(): 50 fins[fingerprint] = (uid, fingerprint_id, keyring) 51 return fins
52 53
54 -def list_uids(session, pattern):
55 sql_pattern = f"%{pattern}%" 56 message = "List UIDs matching pattern %s" % sql_pattern 57 message += "\n" + ("=" * len(message)) 58 print(message) 59 uid_query = session.query(Uid).filter(Uid.uid.ilike(sql_pattern)) 60 for uid in uid_query.all(): 61 print("\nuid %s" % uid.uid) 62 for fp in uid.fingerprint: 63 print(" fingerprint %s" % fp.fingerprint) 64 keyring = "unknown" 65 if fp.keyring: 66 keyring = fp.keyring.keyring_name 67 print(" keyring %s" % keyring)
68 69 ################################################################################ 70 71
72 -def usage(exit_code=0):
73 print("""Usage: dak import-keyring [OPTION]... [KEYRING] 74 -h, --help show this help and exit. 75 -L, --import-ldap-users generate uid entries for keyring from LDAP 76 -U, --generate-users FMT generate uid entries from keyring as FMT 77 -l, --list-uids STRING list all uids matching *STRING* 78 -n, --no-action don't change database""") 79 sys.exit(exit_code)
80 81 82 ################################################################################ 83
84 -def main():
85 global Options 86 87 cnf = Config() 88 Arguments = [('h', "help", "Import-Keyring::Options::Help"), 89 ('L', "import-ldap-users", "Import-Keyring::Options::Import-Ldap-Users"), 90 ('U', "generate-users", "Import-Keyring::Options::Generate-Users", "HasArg"), 91 ('l', "list-uids", "Import-Keyring::Options::List-UIDs", "HasArg"), 92 ('n', "no-action", "Import-Keyring::Options::No-Action"), 93 ] 94 95 for i in ["help", "report-changes", "generate-users", 96 "import-ldap-users", "list-uids", "no-action"]: 97 key = "Import-Keyring::Options::%s" % i 98 if key not in cnf: 99 cnf[key] = "" 100 101 keyring_names = apt_pkg.parse_commandline(cnf.Cnf, Arguments, sys.argv) 102 103 ### Parse options 104 105 Options = cnf.subtree("Import-Keyring::Options") 106 107 if Options["Help"]: 108 usage() 109 110 ### Initialise 111 session = DBConn().session() 112 113 if Options["List-UIDs"]: 114 list_uids(session, Options["List-UIDs"]) 115 sys.exit(0) 116 117 if len(keyring_names) != 1: 118 usage(1) 119 120 ### Keep track of changes made 121 changes = [] # (uid, changes strings) 122 123 ### Cache all the existing fingerprint entries 124 db_fin_info = get_fingerprint_info(session) 125 126 ### Parse the keyring 127 128 keyringname = keyring_names[0] 129 keyring = get_keyring(keyringname, session) 130 if not keyring: 131 print("E: Can't load keyring %s from database" % keyringname) 132 sys.exit(1) 133 134 keyring.load_keys(keyringname) 135 136 ### Generate new uid entries if they're needed (from LDAP or the keyring) 137 if Options["Generate-Users"]: 138 format = Options["Generate-Users"] 139 (desuid_byname, desuid_byid) = keyring.generate_users_from_keyring(Options["Generate-Users"], session) 140 elif Options["Import-Ldap-Users"]: 141 (desuid_byname, desuid_byid) = keyring.import_users_from_ldap(session) 142 else: 143 (desuid_byname, desuid_byid) = ({}, {}) 144 145 ### Cache all the existing uid entries 146 (db_uid_byname, db_uid_byid) = get_uid_info(session) 147 148 ### Update full names of applicable users 149 for keyid in desuid_byid.keys(): 150 uid = (keyid, desuid_byid[keyid][0]) 151 name = desuid_byid[keyid][1] 152 oname = db_uid_byid[keyid][1] 153 if name and oname != name: 154 changes.append((uid[1], "Full name: %s" % (name))) 155 session.execute("UPDATE uid SET name = :name WHERE id = :keyid", 156 {'name': name, 'keyid': keyid}) 157 158 # The fingerprint table (fpr) points to a uid and a keyring. 159 # If the uid is being decided here (ldap/generate) we set it to it. 160 # Otherwise, if the fingerprint table already has a uid (which we've 161 # cached earlier), we preserve it. 162 # Otherwise we leave it as None 163 164 fpr = {} 165 for z in keyring.keys.keys(): 166 keyid = db_uid_byname.get(keyring.keys[z].get("uid", None), [None])[0] 167 if keyid is None: 168 keyid = db_fin_info.get(keyring.keys[z]["fingerprints"][0], [None])[0] 169 for y in keyring.keys[z]["fingerprints"]: 170 fpr[y] = (keyid, keyring.keyring_id) 171 172 # For any keys that used to be in this keyring, disassociate them. 173 # We don't change the uid, leaving that for historical info; if 174 # the id should change, it'll be set when importing another keyring. 175 176 for f, (u, fid, kr) in db_fin_info.items(): 177 if kr != keyring.keyring_id: 178 continue 179 180 if f in fpr: 181 continue 182 183 changes.append((db_uid_byid.get(u, [None])[0], "Removed key: %s" % (f))) 184 session.execute("""UPDATE fingerprint 185 SET keyring = NULL 186 WHERE id = :fprid""", {'fprid': fid}) 187 188 # For the keys in this keyring, add/update any fingerprints that've 189 # changed. 190 191 for f in fpr: 192 newuid = fpr[f][0] 193 newuiduid = db_uid_byid.get(newuid, [None])[0] 194 195 (olduid, oldfid, oldkid) = db_fin_info.get(f, [-1, -1, -1]) 196 197 if olduid is None: 198 olduid = -1 199 200 if oldkid is None: 201 oldkid = -1 202 203 if oldfid == -1: 204 changes.append((newuiduid, "Added key: %s" % (f))) 205 fp = Fingerprint() 206 fp.fingerprint = f 207 fp.keyring_id = keyring.keyring_id 208 if newuid: 209 fp.uid_id = newuid 210 211 session.add(fp) 212 session.flush() 213 214 else: 215 if newuid and olduid != newuid and olduid == -1: 216 changes.append((newuiduid, "Linked key: %s" % f)) 217 changes.append((newuiduid, " (formerly unowned)")) 218 session.execute("UPDATE fingerprint SET uid = :uid WHERE id = :fpr", 219 {'uid': newuid, 'fpr': oldfid}) 220 221 # Don't move a key from a keyring with a higher priority to a lower one 222 if oldkid != keyring.keyring_id: 223 movekey = False 224 if oldkid == -1: 225 movekey = True 226 else: 227 try: 228 oldkeyring = session.query(Keyring).filter_by(keyring_id=oldkid).one() 229 except NotFoundError: 230 print("ERROR: Cannot find old keyring with id %s" % oldkid) 231 sys.exit(1) 232 233 if oldkeyring.priority < keyring.priority: 234 movekey = True 235 236 # Only change the keyring if it won't result in a loss of permissions 237 if movekey: 238 session.execute("""UPDATE fingerprint 239 SET keyring = :keyring 240 WHERE id = :fpr""", 241 {'keyring': keyring.keyring_id, 242 'fpr': oldfid}) 243 244 session.flush() 245 246 else: 247 print("Key %s exists in both %s and %s keyrings. Not demoting." % (f, 248 oldkeyring.keyring_name, 249 keyring.keyring_name)) 250 251 # All done! 252 if Options["No-Action"]: 253 session.rollback() 254 else: 255 session.commit() 256 257 # Print a summary 258 changesd = {} 259 for (k, v) in changes: 260 if k not in changesd: 261 changesd[k] = "" 262 changesd[k] += " %s\n" % (v) 263 264 for k in sorted(changesd): 265 print("%s\n%s\n" % (k, changesd[k]))
266 267 ################################################################################ 268 269 270 if __name__ == '__main__': 271 main() 272