Two problems with my first commit:
[mirror/userdir-ldap.git] / ud-gpgimport
1 #!/usr/bin/env python
2 # -*- mode: python -*-
3
4 #   Copyright (c) 1999-2000  Jason Gunthorpe <jgg@debian.org>
5 #   Copyright (c) 2004       Joey Schulze <joey@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., 675 Mass Ave, Cambridge, MA 02139, USA.
20
21 # This script tries to match key fingerprints from a keyring with user
22 # name in a directory. When an unassigned key is found a heuristic match
23 # against the keys given cn/sn and the directory is performed to try to get
24 # a matching. Generally this works about 90% of the time, matching is fairly
25 # strict. In the event a non-match a fuzzy sounds-alike search is performed
26 # and the results printed to aide the user.
27 #
28 # GPG is automatically invoked with the correct magic special options,
29 # pass the names of all the valid key rings on the command line.
30 #
31 # The output report will list what actions were taken. Keys that are present
32 # in the directory but not in the key ring will be removed from the 
33 # directory. 
34
35 import re, time, ldap, getopt, sys, pwd, os;
36 from userdir_ldap import *;
37 from userdir_gpg import *;
38
39 # This map deals with people who put the wrong sort of stuff in their pgp
40 # key entries
41 UnknownMap = {};
42 NoAct = 1;
43
44 # Read the override file into the unknown map. The override file is a list
45 # of colon delimited entires mapping PGP email addresess to local users
46 def LoadOverride(File):
47    List = open(File,"r");
48    while(1):
49       Line = List.readline();
50       if Line == "":
51          break;
52       Split = re.split("[:\n]",Line);
53       UnknownMap[Split[0]] = Split[1].strip()
54
55 # Process options
56 AdminUser = pwd.getpwuid(os.getuid())[0];
57 (options, arguments) = getopt.getopt(sys.argv[1:], "au:m:n")
58 for (switch, val) in options:
59    if (switch == '-u'):
60       AdminUser = val
61    elif (switch == '-m'):
62        LoadOverride(val);
63    elif (switch == '-a'):
64        NoAct = 0;
65
66
67 # Main program starts here
68
69 # Connect to the ldap server
70 if NoAct == 0:
71    l = passwdAccessLDAP(BaseDn, AdminUser)
72 else:
73    l = connectLDAP()
74    l.simple_bind_s("","");
75
76 # Download the existing key list and put it into a map
77 print "Fetching key list..",
78 sys.stdout.flush();
79 Attrs = l.search_s(BaseDn,ldap.SCOPE_ONELEVEL,"keyFingerPrint=*",["keyFingerPrint","uid"]);
80 KeyMap = {};
81 KeyCount = {};
82 for x in Attrs:
83   try:
84      # Sense a bad fingerprint.. Slapd has problems, it will store a null
85      # value that ldapsearch doesn't show up.. detect and remove
86      if len(x[1]["keyFingerPrint"]) == 0 or x[1]["keyFingerPrint"][0] == "":
87        print;
88        print "Fixing bad fingerprint for",x[1]["uid"][0],
89        sys.stdout.flush();
90        if NoAct == 0:
91          l.modify_s("uid="+x[1]["uid"][0]+","+BaseDn,\
92                      [(ldap.MOD_DELETE,"keyFingerPrint",None)]);
93      else:
94        for I in x[1]["keyFingerPrint"]:
95          KeyMap[I] = [x[1]["uid"][0],0];
96          if KeyCount.has_key(x[1]["uid"][0]):
97             KeyCount[x[1]["uid"][0]] = KeyCount[x[1]["uid"][0]] + 1;
98          else:
99             KeyCount[x[1]["uid"][0]] = 1;
100   except:
101      continue;
102 Attrs = None;
103 print;
104
105 # Popen GPG with the correct magic special options
106 ClearKeyrings()
107 if len(arguments) == 0:
108    print "Using default keyrings: %s"%ConfModule.add_keyrings;
109    SetKeyrings(ConfModule.add_keyrings.split(":"))
110 for x in arguments:
111    if x.find("/") == -1:
112       x= "./"+x
113    SetKeyrings( [x] )
114
115 Args = [GPGPath] + GPGBasicOptions + GPGKeyRings + GPGSearchOptions + [" 2> /dev/null"]
116 Keys = os.popen(" ".join(Args),"r");
117
118 # Loop over the GPG key file
119 Outstanding = 0;
120 Ignored = 0;
121 SeenKeys = {};
122 while(1):
123    Line = Keys.readline();
124    if Line == "":
125       break;
126    
127    Split = Line.split(":")
128    if len(Split) < 8 or Split[0] != "pub":
129       continue;
130
131    while (1):
132        Line2 = Keys.readline();
133        if Line2 == "":
134           break;
135        Split2 = Line2.split(":");
136        if len(Split2) < 11 or Split2[0] != "fpr":
137           continue;
138        break;
139    if Line2 == "":
140       break;
141
142    if SeenKeys.has_key(Split2[9]):
143       print "Dup key 0x",Split2[9],"belonging to",KeyMap[Split2[9]][0];
144       continue;
145    SeenKeys[Split2[9]] = None;
146
147    if KeyMap.has_key(Split2[9]):
148       Ignored = Ignored + 1;
149       # print "Ignoring keyID",Split2[9],"belonging to",KeyMap[Split2[9]][0];
150       KeyMap[Split2[9]][1] = 1;
151       continue;
152       
153    UID = GetUID(l,SplitEmail(Split[9]),UnknownMap);
154    if UID[0] == None:
155       print "None for",SplitEmail(Split[9]),"'%s'"%(Split[9]);
156       if UID[1] != None: 
157          for x in UID[1]: print x;
158       print "MISSING 0x" + Split2[9];
159       continue;
160
161    UID = UID[0]
162    Rec = [(ldap.MOD_ADD,"keyFingerPrint",Split2[9])];
163    Dn = "uid=" + UID + "," + BaseDn;
164    print "Adding key 0x"+Split2[9],"to",UID;
165    if KeyCount.has_key(UID):
166       KeyCount[UID] = KeyCount[UID] + 1;
167    else:
168       KeyCount[UID] = 1;
169    
170    if NoAct == 1:
171       continue;
172
173    # Send the modify request
174    l.modify(Dn,Rec);
175    Outstanding = Outstanding + 1;
176    Outstanding = FlushOutstanding(l,Outstanding,1);
177    sys.stdout.flush();
178
179 if NoAct == 0:
180    FlushOutstanding(l,Outstanding);
181
182 if Keys.close() != None:
183    raise "Error","GPG failed"
184
185 print Ignored,"keys already in the directory (ignored)";
186
187 # Look for unmatched keys
188 for x in KeyMap.keys():
189    if KeyMap[x][1] == 0:
190       print "key 0x%s belonging to %s removed"%(x,KeyMap[x][0]);
191       if KeyCount.has_key(KeyMap[x][0]) :
192          KeyCount[KeyMap[x][0]] = KeyCount[KeyMap[x][0]] - 1
193          if KeyCount[KeyMap[x][0]] <= 0:
194             print "**",KeyMap[x][0],"no longer has any keys";
195       if NoAct == 0:
196          l.modify_s("uid="+KeyMap[x][0]+","+BaseDn,\
197                      [(ldap.MOD_DELETE,"keyFingerPrint",x)]);
198