4 # Copyright (c) 1999-2000 Jason Gunthorpe <jgg@debian.org>
5 # Copyright (c) 2001-2003 James Troup <troup@debian.org>
6 # Copyright (c) 2004 Joey Schulze <joey@infodrom.org>
8 # This program is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 2 of the License, or
11 # (at your option) any later version.
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with this program; if not, write to the Free Software
20 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 import re, time, ldap, getopt, sys, os, pwd;
23 from userdir_ldap import *;
24 from userdir_gpg import *;
26 # This tries to search for a free UID. There are two possible ways to do
27 # this, one is to fetch all the entires and pick the highest, the other
28 # is to randomly guess uids until one is free. This uses the former.
29 # Regrettably ldap doesn't have an integer attribute comparision function
30 # so we can only cut the search down slightly
32 # [JT] This is broken with Woody LDAP and the Schema; for now just
33 # search through all UIDs.
35 Attrs = l.search_s(BaseDn,ldap.SCOPE_ONELEVEL,
36 "uidNumber=*",["uidNumber", "gidNumber"]);
40 ID = int(GetAttr(I,"uidNumber","0"));
41 gids.append(int(GetAttr(I, "gidNumber","0")))
45 resGID = HighestUID + 1;
49 return (HighestUID + 1, resGID);
52 AdminUser = pwd.getpwuid(os.getuid())[0];
57 OldGPGKeyRings = GPGKeyRings;
58 userdir_gpg.GPGKeyRings = [];
59 (options, arguments) = getopt.getopt(sys.argv[1:], "u:man")
60 for (switch, val) in options:
63 elif (switch == '-m'):
65 elif (switch == '-a'):
66 userdir_gpg.GPGKeyRings = OldGPGKeyRings;
67 elif (switch == '-n'):
70 l = passwdAccessLDAP(LDAPServer, BaseDn, AdminUser)
72 # Locate the key of the user we are adding
73 SetKeyrings(ConfModule.add_keyrings.split(":"))
75 Foo = raw_input("Who are you going to add (for a GPG search)? ");
79 Keys = GPGKeySearch(Foo);
82 print "Sorry, that search did not turn up any keys."
83 print "Has it been added to the Debian keyring already?"
86 print "Sorry, more than one key was found, please specify the key to use by\nfingerprint:";
92 print "A matching key was found:"
93 GPGPrintKeyInfo(Keys[0]);
96 # Crack up the email address from the key into a best guess
97 # first/middle/last name
98 Addr = SplitEmail(Keys[0][2]);
99 (cn,mn,sn) = NameSplit(re.sub('["]','',Addr[0]))
100 email = Addr[1] + '@' + Addr[2];
107 # Decide if we should use IDEA encryption
109 while len(Keys[0][1]) < 40:
110 Res = raw_input("Use PGP2.x compatibility [No/yes]? ");
118 Attrs = l.search_s(BaseDn,ldap.SCOPE_ONELEVEL,"keyFingerPrint=" + Keys[0][1]);
120 print "*** This key already belongs to",GetAttr(Attrs[0],"uid");
121 account = GetAttr(Attrs[0],"uid");
124 # Try to get a uniq account name
127 Res = raw_input("Login account [" + account + "]? ");
130 Attrs = l.search_s(BaseDn,ldap.SCOPE_ONELEVEL,"uid=" + account);
132 privsub = "%s@debian.org"%(account);
134 Res = raw_input("That account already exists, update [No/yes]? ");
136 # Update mode, fetch the default values from the directory
138 privsub = GetAttr(Attrs[0],"privateSub");
139 gidNumber = GetAttr(Attrs[0],"gidNumber");
140 uidNumber = GetAttr(Attrs[0],"uidNumber");
141 email = GetAttr(Attrs[0],"emailForward");
142 cn = GetAttr(Attrs[0],"cn");
143 sn = GetAttr(Attrs[0],"sn");
144 mn = GetAttr(Attrs[0],"mn");
145 if privsub == None or privsub == "":
151 # Prompt for the first/last name and email address
152 Res = raw_input("First name [" + cn + "]? ");
155 Res = raw_input("Middle name [" + mn + "]? ");
158 Res = raw_input("Last name [" + sn + "]? ");
161 Res = raw_input("Email forwarding address [" + email + "]? ");
165 # Debian-Private subscription
166 Res = raw_input("Subscribe to debian-private (space is none) [" + privsub + "]? ");
170 (uidNumber, generatedGID) = GetFreeID(l)
172 gidNumber = DefaultGID
178 Res = raw_input("User ID Number [%s]? " % (uidNumber));
183 Res = raw_input("Group ID Number (default group is %s, new usergroup %s) [%s]" % (DefaultGID, generatedGID, gidNumber));
188 gidNumber = Group2GID(l, Res);
190 if gidNumber == generatedGID:
193 # Generate a random password
194 if Update == 0 or ForceMail == 1:
195 Password = raw_input("User's Password (Enter for random)? ");
198 print "Randomizing and encrypting password"
199 Password = GenPass();
200 Pass = HashPass(Password);
202 # Use GPG to encrypt it, pass the fingerprint to ID it
203 CryptedPass = GPGEncrypt("Your new password is '" + Password + "'\n",\
204 "0x"+Keys[0][1],UsePGP2);
206 if CryptedPass == None:
207 raise "Error","Password Encryption failed"
209 Pass = HashPass(Password);
210 CryptedPass = "Your password has been set to the previously agreed value.";
215 # Now we have all the bits of information.
217 FullName = "%s %s %s" % (cn,mn,sn);
219 FullName = "%s %s" % (cn,sn);
220 print "------------";
221 print "Final information collected:"
222 print " %s <%s@%s>:" % (FullName,account,EmailAppend);
223 print " Assigned UID:",uidNumber," GID:", gidNumber;
224 print " Email forwarded to:",email;
225 print " Private Subscription:",privsub;
226 print " GECOS Field: \"%s,,,,\"" % (FullName);
227 print " Login Shell: /bin/bash";
228 print " Key Fingerprint:",Keys[0][1];
229 Res = raw_input("Continue [No/yes]? ");
233 # Initialize the substitution Map
235 Subst["__REALNAME__"] = FullName;
236 Subst["__WHOAMI__"] = pwd.getpwuid(os.getuid())[0];
237 Subst["__DATE__"] = time.strftime("%a, %d %b %Y %H:%M:%S +0000",time.gmtime(time.time()));
238 Subst["__LOGIN__"] = account;
239 Subst["__PRIVATE__"] = privsub;
240 Subst["__EMAIL__"] = email;
241 Subst["__PASSWORD__"] = CryptedPass;
243 # Submit the modification request
244 Dn = "uid=" + account + "," + BaseDn;
245 print "Updating LDAP directory..",
250 Details = [("uid",account),
251 ("objectClass", UserObjectClasses),
252 ("uidNumber",str(uidNumber)),
253 ("gidNumber",str(gidNumber)),
254 ("gecos",FullName+",,,,"),
255 ("loginShell","/bin/bash"),
256 ("keyFingerPrint",Keys[0][1]),
259 ("emailForward",email),
260 ("shadowLastChange",str(int(time.time()/24/60/60))),
262 ("shadowMax","99999"),
263 ("shadowWarning","7"),
264 ("userPassword","{crypt}"+Pass)];
266 Details.append(("mn",mn));
268 Details.append(("privateSub",privsub))
270 #Add user group if needed, then the actual user:
272 Dn = "gid=" + account + "," + BaseDn;
273 l.add_s(Dn,[("gid",account), ("gidNumber",str(gidNumber)), ("objectClass", GroupObjectClasses)])
278 Rec = [(ldap.MOD_REPLACE,"uidNumber",str(uidNumber)),
279 (ldap.MOD_REPLACE,"gidNumber",str(gidNumber)),
280 (ldap.MOD_REPLACE,"gecos",FullName+",,,,"),
281 (ldap.MOD_REPLACE,"loginShell","/bin/bash"),
282 (ldap.MOD_REPLACE,"keyFingerPrint",Keys[0][1]),
283 (ldap.MOD_REPLACE,"cn",cn),
284 (ldap.MOD_REPLACE,"mn",mn),
285 (ldap.MOD_REPLACE,"sn",sn),
286 (ldap.MOD_REPLACE,"emailForward",email),
287 (ldap.MOD_REPLACE,"shadowLastChange",str(int(time.time()/24/60/60))),
288 (ldap.MOD_REPLACE,"shadowMin","0"),
289 (ldap.MOD_REPLACE,"shadowMax","99999"),
290 (ldap.MOD_REPLACE,"shadowWarning","7"),
291 (ldap.MOD_REPLACE,"shadowInactive",""),
292 (ldap.MOD_REPLACE,"shadowExpire","")];
294 Rec.append((ldap.MOD_REPLACE,"privateSub",privsub));
296 Rec.append((ldap.MOD_REPLACE,"userPassword","{crypt}"+Pass));
302 # Abort email sends for an update operation
303 if Update == 1 and ForceMail == 0:
304 print "Account is not new, Not sending mails"
307 # Send the Welcome message
308 print "Sending Welcome Email"
309 Reply = TemplateSubst(Subst,open(TemplatesDir + "/welcome-message-%d" % gidNumber, "r").read())
310 Child = os.popen("/usr/sbin/sendmail -t","w");
311 #Child = os.popen("cat","w");
313 if Child.close() != None:
314 raise Error, "Sendmail gave a non-zero return code";