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 l = passwdAccessLDAP(LDAPServer, BaseDn, AdminUser)
62 # Locate the key of the user we are adding
63 SetKeyrings(["/org/keyring.debian.org/keyrings/debian-keyring.gpg"])
65 Foo = raw_input("Who are you going to add (for a GPG search)? ");
69 Keys = GPGKeySearch(Foo);
72 print "Sorry, that search did not turn up any keys."
73 print "Has it been added to the Debian keyring already?"
76 print "Sorry, more than one key was found, please specify the key to use by\nfingerprint:";
82 print "A matching key was found:"
83 GPGPrintKeyInfo(Keys[0]);
86 # Crack up the email address from the key into a best guess
87 # first/middle/last name
88 Addr = SplitEmail(Keys[0][2]);
89 (cn,mn,sn) = NameSplit(re.sub('["]','',Addr[0]))
90 email = Addr[1] + '@' + Addr[2];
94 gidNumber = str(DefaultGID);
97 # Decide if we should use IDEA encryption
99 while len(Keys[0][1]) < 40:
100 Res = raw_input("Use PGP2.x compatibility [No/yes]? ");
108 Attrs = l.search_s(BaseDn,ldap.SCOPE_ONELEVEL,"keyFingerPrint=" + Keys[0][1]);
110 print "*** This key already belongs to",GetAttr(Attrs[0],"uid");
111 account = GetAttr(Attrs[0],"uid");
114 # Try to get a uniq account name
117 Res = raw_input("Login account [" + account + "]? ");
120 Attrs = l.search_s(BaseDn,ldap.SCOPE_ONELEVEL,"uid=" + account);
122 privsub = "%s@debian.org"%(account);
124 Res = raw_input("That account already exists, update [No/yes]? ");
126 # Update mode, fetch the default values from the directory
128 privsub = GetAttr(Attrs[0],"privateSub");
129 gidNumber = GetAttr(Attrs[0],"gidNumber");
130 uidNumber = GetAttr(Attrs[0],"uidNumber");
131 email = GetAttr(Attrs[0],"emailForward");
132 cn = GetAttr(Attrs[0],"cn");
133 sn = GetAttr(Attrs[0],"sn");
134 mn = GetAttr(Attrs[0],"mn");
135 if privsub == None or privsub == "":
141 # Prompt for the first/last name and email address
142 Res = raw_input("First name [" + cn + "]? ");
145 Res = raw_input("Middle name [" + mn + "]? ");
148 Res = raw_input("Last name [" + sn + "]? ");
151 Res = raw_input("Email forwarding address [" + email + "]? ");
155 # Debian-Private subscription
156 Res = raw_input("Subscribe to debian-private (space is none) [" + privsub + "]? ");
161 Res = raw_input("Group ID Number [" + gidNumber + "]? ");
163 gidNumber = Group2GID(Res);
167 uidNumber = GetFreeID(l);
169 # Generate a random password
170 if Update == 0 or ForceMail == 1:
171 Password = raw_input("User's Password (Enter for random)? ");
174 print "Randomizing and encrypting password"
175 Password = GenPass();
176 Pass = HashPass(Password);
178 # Use GPG to encrypt it, pass the fingerprint to ID it
179 CryptedPass = GPGEncrypt("Your new password is '" + Password + "'\n",\
180 "0x"+Keys[0][1],UsePGP2);
182 if CryptedPass == None:
183 raise "Error","Password Encryption failed"
185 Pass = HashPass(Password);
186 CryptedPass = "Your password has been set to the previously agreed value.";
191 # Now we have all the bits of information.
193 FullName = "%s %s %s" % (cn,mn,sn);
195 FullName = "%s %s" % (cn,sn);
196 print "------------";
197 print "Final information collected:"
198 print " %s <%s@%s>:" % (FullName,account,EmailAppend);
199 print " Assigned UID:",uidNumber," GID:", gidNumber;
200 print " Email forwarded to:",email;
201 print " Private Subscription:",privsub;
202 print " GECOS Field: \"%s,,,,\"" % (FullName);
203 print " Login Shell: /bin/bash";
204 print " Key Fingerprint:",Keys[0][1];
205 Res = raw_input("Continue [No/yes]? ");
209 # Initialize the substitution Map
211 Subst["__REALNAME__"] = FullName;
212 Subst["__WHOAMI__"] = pwd.getpwuid(os.getuid())[0];
213 Subst["__DATE__"] = time.strftime("%a, %d %b %Y %H:%M:%S +0000",time.gmtime(time.time()));
214 Subst["__LOGIN__"] = account;
215 Subst["__PRIVATE__"] = privsub;
216 Subst["__EMAIL__"] = email;
217 Subst["__PASSWORD__"] = CryptedPass;
219 # Submit the modification request
220 Dn = "uid=" + account + "," + BaseDn;
221 print "Updating LDAP directory..",
226 Details = [("uid",account),
228 ("top","inetOrgPerson","debianAccount","shadowAccount","debianDeveloper")),
229 ("uidNumber",str(uidNumber)),
230 ("gidNumber",str(gidNumber)),
231 ("gecos",FullName+",,,,"),
232 ("loginShell","/bin/bash"),
233 ("keyFingerPrint",Keys[0][1]),
236 ("emailForward",email),
237 ("shadowLastChange",str(int(time.time()/24/60/60))),
239 ("shadowMax","99999"),
240 ("shadowWarning","7"),
241 ("userPassword","{crypt}"+Pass)];
243 Details.append(("mn",mn));
245 Details.append(("privateSub",privsub))
249 Rec = [(ldap.MOD_REPLACE,"uidNumber",str(uidNumber)),
250 (ldap.MOD_REPLACE,"gidNumber",str(gidNumber)),
251 (ldap.MOD_REPLACE,"gecos",FullName+",,,,"),
252 (ldap.MOD_REPLACE,"loginShell","/bin/bash"),
253 (ldap.MOD_REPLACE,"keyFingerPrint",Keys[0][1]),
254 (ldap.MOD_REPLACE,"cn",cn),
255 (ldap.MOD_REPLACE,"mn",mn),
256 (ldap.MOD_REPLACE,"sn",sn),
257 (ldap.MOD_REPLACE,"emailForward",email),
258 (ldap.MOD_REPLACE,"shadowLastChange",str(int(time.time()/24/60/60))),
259 (ldap.MOD_REPLACE,"shadowMin","0"),
260 (ldap.MOD_REPLACE,"shadowMax","99999"),
261 (ldap.MOD_REPLACE,"shadowWarning","7"),
262 (ldap.MOD_REPLACE,"shadowInactive",""),
263 (ldap.MOD_REPLACE,"shadowExpire","")];
265 Rec.append((ldap.MOD_REPLACE,"privateSub",privsub));
267 Rec.append((ldap.MOD_REPLACE,"userPassword","{crypt}"+Pass));
273 # Abort email sends for an update operation
274 if Update == 1 and ForceMail == 0:
275 print "Account is not new, Not sending mails"
278 # Send the Welcome message
279 print "Sending Welcome Email"
280 Reply = TemplateSubst(Subst,open(TemplatesDir+"/welcome-message-"+gidNumber,"r").read());
281 Child = os.popen("/usr/sbin/sendmail -t","w");
282 #Child = os.popen("cat","w");
284 if Child.close() != None:
285 raise Error, "Sendmail gave a non-zero return code";