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 string, 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"]);
39 ID = int(GetAttr(I,"uidNumber","0"));
42 return HighestUID + 1;
45 AdminUser = pwd.getpwuid(os.getuid())[0];
49 OldGPGKeyRings = GPGKeyRings;
50 userdir_gpg.GPGKeyRings = [];
51 (options, arguments) = getopt.getopt(sys.argv[1:], "u:ma")
52 for (switch, val) in options:
55 elif (switch == '-m'):
57 elif (switch == '-a'):
58 userdir_gpg.GPGKeyRings = OldGPGKeyRings;
60 print "Accessing LDAP directory as '" + AdminUser + "'";
62 Password = getpass(AdminUser + "'s password: ");
64 if len(Password) == 0:
67 l = ldap.open(LDAPServer);
68 UserDn = "uid=" + AdminUser + "," + BaseDn;
70 # Connect to the ldap server
72 l.simple_bind_s(UserDn,Password);
73 except ldap.INVALID_CREDENTIALS:
77 # Locate the key of the user we are adding
78 SetKeyrings(["/org/keyring.debian.org/keyrings/debian-keyring.gpg"])
80 Foo = raw_input("Who are you going to add (for a GPG search)? ");
84 Keys = GPGKeySearch(Foo);
87 print "Sorry, that search did not turn up any keys."
88 print "Has it been added to the Debian keyring already?"
91 print "Sorry, more than one key was found, please specify the key to use by\nfingerprint:";
97 print "A matching key was found:"
98 GPGPrintKeyInfo(Keys[0]);
101 # Crack up the email address from the key into a best guess
102 # first/middle/last name
103 Addr = SplitEmail(Keys[0][2]);
104 (cn,mn,sn) = NameSplit(re.sub('["]','',Addr[0]))
105 email = Addr[1] + '@' + Addr[2];
109 gidNumber = str(DefaultGID);
112 # Decide if we should use IDEA encryption
114 while len(Keys[0][1]) < 40:
115 Res = raw_input("Use PGP2.x compatibility [no]? ");
123 Attrs = l.search_s(BaseDn,ldap.SCOPE_ONELEVEL,"keyFingerPrint=" + Keys[0][1]);
125 print "*** This key already belongs to",GetAttr(Attrs[0],"uid");
126 account = GetAttr(Attrs[0],"uid");
129 # Try to get a uniq account name
132 Res = raw_input("Login account [" + account + "]? ");
135 Attrs = l.search_s(BaseDn,ldap.SCOPE_ONELEVEL,"uid=" + account);
137 privsub = "%s@debian.org"%(account);
139 Res = raw_input("That account already exists, update [No/yes]? ");
141 # Update mode, fetch the default values from the directory
143 privsub = GetAttr(Attrs[0],"privateSub");
144 gidNumber = GetAttr(Attrs[0],"gidNumber");
145 uidNumber = GetAttr(Attrs[0],"uidNumber");
146 email = GetAttr(Attrs[0],"emailForward");
147 cn = GetAttr(Attrs[0],"cn");
148 sn = GetAttr(Attrs[0],"sn");
149 mn = GetAttr(Attrs[0],"mn");
150 if privsub == None or privsub == "":
156 # Prompt for the first/last name and email address
157 Res = raw_input("First name [" + cn + "]? ");
160 Res = raw_input("Middle name [" + mn + "]? ");
163 Res = raw_input("Last name [" + sn + "]? ");
166 Res = raw_input("Email forwarding address [" + email + "]? ");
170 # Debian-Private subscription
171 Res = raw_input("Subscribe to debian-private (space is none) [" + privsub + "]? ");
176 Res = raw_input("Group ID Number [" + gidNumber + "]? ");
178 gidNumber = Group2GID(Res);
182 uidNumber = GetFreeID(l);
184 # Generate a random password
185 if Update == 0 or ForceMail == 1:
186 Password = raw_input("User's Password (Enter for random)? ");
189 print "Randomizing and encrypting password"
190 Password = GenPass();
191 Pass = HashPass(Password);
193 # Use GPG to encrypt it, pass the fingerprint to ID it
194 CryptedPass = GPGEncrypt("Your new password is '" + Password + "'\n",\
195 "0x"+Keys[0][1],UsePGP2);
197 if CryptedPass == None:
198 raise "Error","Password Encryption failed"
200 Pass = HashPass(Password);
201 CryptedPass = "Your password has been set to the previously agreed value.";
206 # Now we have all the bits of information.
208 FullName = "%s %s %s" % (cn,mn,sn);
210 FullName = "%s %s" % (cn,sn);
211 print "------------";
212 print "Final information collected:"
213 print " %s <%s@%s>:" % (FullName,account,EmailAppend);
214 print " Assigned UID:",uidNumber," GID:", gidNumber;
215 print " Email forwarded to:",email;
216 print " Private Subscription:",privsub;
217 print " GECOS Field: \"%s,,,,\"" % (FullName);
218 print " Login Shell: /bin/bash";
219 print " Key Fingerprint:",Keys[0][1];
220 Res = raw_input("Continue [No/yes]? ");
224 # Initialize the substitution Map
226 Subst["__REALNAME__"] = FullName;
227 Subst["__WHOAMI__"] = pwd.getpwuid(os.getuid())[0];
228 Subst["__DATE__"] = time.strftime("%a, %d %b %Y %H:%M:%S +0000",time.gmtime(time.time()));
229 Subst["__LOGIN__"] = account;
230 Subst["__PRIVATE__"] = privsub;
231 Subst["__EMAIL__"] = email;
232 Subst["__PASSWORD__"] = CryptedPass;
234 # Submit the modification request
235 Dn = "uid=" + account + "," + BaseDn;
236 print "Updating LDAP directory..",
241 Details = [("uid",account),
243 ("top","inetOrgPerson","debianAccount","shadowAccount","debianDeveloper")),
244 ("uidNumber",str(uidNumber)),
245 ("gidNumber",str(gidNumber)),
246 ("gecos",FullName+",,,,"),
247 ("loginShell","/bin/bash"),
248 ("keyFingerPrint",Keys[0][1]),
251 ("emailForward",email),
252 ("shadowLastChange",str(int(time.time()/24/60/60))),
254 ("shadowMax","99999"),
255 ("shadowWarning","7"),
256 ("userPassword","{crypt}"+Pass)];
258 Details.append(("mn",mn));
260 Details.append(("privateSub",privsub))
264 Rec = [(ldap.MOD_REPLACE,"uidNumber",str(uidNumber)),
265 (ldap.MOD_REPLACE,"gidNumber",str(gidNumber)),
266 (ldap.MOD_REPLACE,"gecos",FullName+",,,,"),
267 (ldap.MOD_REPLACE,"loginShell","/bin/bash"),
268 (ldap.MOD_REPLACE,"keyFingerPrint",Keys[0][1]),
269 (ldap.MOD_REPLACE,"cn",cn),
270 (ldap.MOD_REPLACE,"mn",mn),
271 (ldap.MOD_REPLACE,"sn",sn),
272 (ldap.MOD_REPLACE,"emailForward",email),
273 (ldap.MOD_REPLACE,"shadowLastChange",str(int(time.time()/24/60/60))),
274 (ldap.MOD_REPLACE,"shadowMin","0"),
275 (ldap.MOD_REPLACE,"shadowMax","99999"),
276 (ldap.MOD_REPLACE,"shadowWarning","7"),
277 (ldap.MOD_REPLACE,"shadowInactive",""),
278 (ldap.MOD_REPLACE,"shadowExpire","")];
280 Rec.append((ldap.MOD_REPLACE,"privateSub",privsub));
282 Rec.append((ldap.MOD_REPLACE,"userPassword","{crypt}"+Pass));
288 # Abort email sends for an update operation
289 if Update == 1 and ForceMail == 0:
290 print "Account is not new, Not sending mails"
293 # Send the Welcome message
294 print "Sending Welcome Email"
295 Reply = TemplateSubst(Subst,open(TemplatesDir+"/welcome-message-"+gidNumber,"r").read());
296 Child = os.popen("/usr/sbin/sendmail -t","w");
297 #Child = os.popen("cat","w");
299 if Child.close() != None:
300 raise Error, "Sendmail gave a non-zero return code";