Fix ud-useradd.
[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 string, 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]] = string.strip(Split[1]);
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 if len(arguments) == 0:
66    print "Give some keyrings to probe";
67    sys.exit(0);
68
69 # Main program starts here
70
71 # Connect to the ldap server
72 if NoAct == 0:
73    l = passwdAccessLDAP(LDAPServer, BaseDn, AdminUser)
74 else:
75    l = ldap.open(LDAPServer);
76    l.simple_bind_s("","");
77
78 # Download the existing key list and put it into a map
79 print "Fetching key list..",
80 sys.stdout.flush();
81 Attrs = l.search_s(BaseDn,ldap.SCOPE_ONELEVEL,"keyFingerPrint=*",["keyFingerPrint","uid"]);
82 KeyMap = {};
83 KeyCount = {};
84 for x in Attrs:
85   try:
86      # Sense a bad fingerprint.. Slapd has problems, it will store a null
87      # value that ldapsearch doesn't show up.. detect and remove
88      if len(x[1]["keyFingerPrint"]) == 0 or x[1]["keyFingerPrint"][0] == "":
89        print;
90        print "Fixing bad fingerprint for",x[1]["uid"][0],
91        sys.stdout.flush();
92        if NoAct == 0:
93          l.modify_s("uid="+x[1]["uid"][0]+","+BaseDn,\
94                      [(ldap.MOD_DELETE,"keyFingerPrint",None)]);
95      else:
96        for I in x[1]["keyFingerPrint"]:
97          KeyMap[I] = [x[1]["uid"][0],0];
98          if KeyCount.has_key(x[1]["uid"][0]):
99             KeyCount[x[1]["uid"][0]] = KeyCount[x[1]["uid"][0]] + 1;
100          else:
101             KeyCount[x[1]["uid"][0]] = 1;
102   except:
103      continue;
104 Attrs = None;
105 print;
106
107 # Popen GPG with the correct magic special options
108 Args = [GPGPath] + GPGBasicOptions;
109 for x in arguments:
110    Args.append("--keyring");
111    if string.find(x,"/") == -1:
112       Args.append("./"+x);
113    else:
114       Args.append(x);
115 Args = Args + GPGSearchOptions + [" 2> /dev/null"]
116 Keys = os.popen(string.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 = string.split(Line,":");
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 = string.split(Line2,":");
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