4 import string, re, time, ldap, getopt, sys, os, pwd;
5 from userdir_ldap import *;
6 from userdir_gpg import *;
8 # This tries to search for a free UID. There are two possible ways to do
9 # this, one is to fetch all the entires and pick the highest, the other
10 # is to randomly guess uids until one is free. This uses the former.
11 # Regrettably ldap doesn't have an integer attribute comparision function
12 # so we can only cut the search down slightly
14 # [JT] This is broken with Woody LDAP and the Schema; for now just
15 # search through all UIDs.
17 Attrs = l.search_s(BaseDn,ldap.SCOPE_ONELEVEL,
18 "uidNumber=*",["uidNumber"]);
21 ID = int(GetAttr(I,"uidNumber","0"));
24 return HighestUID + 1;
27 AdminUser = pwd.getpwuid(os.getuid())[0];
31 OldGPGKeyRings = GPGKeyRings;
32 userdir_gpg.GPGKeyRings = [];
33 (options, arguments) = getopt.getopt(sys.argv[1:], "u:ma")
34 for (switch, val) in options:
37 elif (switch == '-m'):
39 elif (switch == '-a'):
40 userdir_gpg.GPGKeyRings = OldGPGKeyRings;
42 print "Accessing LDAP directory as '" + AdminUser + "'";
44 Password = getpass(AdminUser + "'s password: ");
46 if len(Password) == 0:
49 l = ldap.open(LDAPServer);
50 UserDn = "uid=" + AdminUser + "," + BaseDn;
52 # Connect to the ldap server
54 l.simple_bind_s(UserDn,Password);
55 except ldap.INVALID_CREDENTIALS:
59 # Locate the key of the user we are adding
60 SetKeyrings(["/org/keyring.debian.org/keyrings/debian-keyring.gpg"])
62 Foo = raw_input("Who are you going to add (for a GPG search)? ");
66 Keys = GPGKeySearch(Foo);
69 print "Sorry, that search did not turn up any keys."
70 print "Has it been added to the Debian keyring already?"
73 print "Sorry, more than one key was found, please specify the key to use by\nfingerprint:";
79 print "A matching key was found:"
80 GPGPrintKeyInfo(Keys[0]);
83 # Crack up the email address from the key into a best guess
84 # first/middle/last name
85 Addr = SplitEmail(Keys[0][2]);
86 (cn,mn,sn) = NameSplit(re.sub('["]','',Addr[0]))
87 email = Addr[1] + '@' + Addr[2];
91 gidNumber = str(DefaultGID);
94 # Decide if we should use IDEA encryption
96 while len(Keys[0][1]) < 40:
97 Res = raw_input("Use PGP2.x compatibility [no]? ");
104 Attrs = l.search_s(BaseDn,ldap.SCOPE_ONELEVEL,"keyFingerPrint=" + Keys[0][1]);
106 print "*** This key already belongs to",GetAttr(Attrs[0],"uid");
107 account = GetAttr(Attrs[0],"uid");
109 # Try to get a uniq account name
112 Res = raw_input("Login account [" + account + "]? ");
115 Attrs = l.search_s(BaseDn,ldap.SCOPE_ONELEVEL,"uid=" + account);
117 privsub = "%s@debian.org"%(account);
119 Res = raw_input("That account already exists, update [No/yes]? ");
121 # Update mode, fetch the default values from the directory
123 privsub = GetAttr(Attrs[0],"privateSub");
124 gidNumber = GetAttr(Attrs[0],"gidNumber");
125 uidNumber = GetAttr(Attrs[0],"uidNumber");
126 email = GetAttr(Attrs[0],"emailForward");
127 cn = GetAttr(Attrs[0],"cn");
128 sn = GetAttr(Attrs[0],"sn");
129 mn = GetAttr(Attrs[0],"mn");
130 if privsub == None or privsub == "":
134 # Prompt for the first/last name and email address
135 Res = raw_input("First name [" + cn + "]? ");
138 Res = raw_input("Middle name [" + mn + "]? ");
141 Res = raw_input("Last name [" + sn + "]? ");
144 Res = raw_input("Email forwarding address [" + email + "]? ");
148 # Debian-Private subscription
149 Res = raw_input("Subscribe to debian-private (space is none) [" + privsub + "]? ");
154 Res = raw_input("Group ID Number [" + gidNumber + "]? ");
160 uidNumber = GetFreeID(l);
162 # Generate a random password
163 if Update == 0 or ForceMail == 1:
164 Password = raw_input("User's Password (Enter for random)? ");
167 print "Randomizing and encrypting password"
168 Password = GenPass();
169 Pass = HashPass(Password);
171 # Use GPG to encrypt it, pass the fingerprint to ID it
172 CryptedPass = GPGEncrypt("Your new password is '" + Password + "'\n",\
173 "0x"+Keys[0][1],UsePGP2);
175 if CryptedPass == None:
176 raise "Error","Password Encryption failed"
178 Pass = HashPass(Password);
179 CryptedPass = "Your password has been set to the previously agreed value.";
184 # Now we have all the bits of information.
186 FullName = "%s %s %s" % (cn,mn,sn);
188 FullName = "%s %s" % (cn,sn);
189 print "------------";
190 print "Final information collected:"
191 print " %s <%s@%s>:" % (FullName,account,EmailAppend);
192 print " Assigned UID:",uidNumber," GID:", gidNumber;
193 print " Email forwarded to:",email;
194 print " Private Subscription:",privsub;
195 print " GECOS Field: \"%s,,,,\"" % (FullName);
196 print " Login Shell: /bin/bash";
197 print " Key Fingerprint:",Keys[0][1];
198 Res = raw_input("Continue [No/yes]? ");
202 # Initialize the substitution Map
204 Subst["__REALNAME__"] = FullName;
205 Subst["__WHOAMI__"] = pwd.getpwuid(os.getuid())[0];
206 Subst["__DATE__"] = time.strftime("%a, %d %b %Y %H:%M:%S +0000",time.gmtime(time.time()));
207 Subst["__LOGIN__"] = account;
208 Subst["__PRIVATE__"] = privsub;
209 Subst["__EMAIL__"] = email;
210 Subst["__PASSWORD__"] = CryptedPass;
212 # Submit the modification request
213 Dn = "uid=" + account + "," + BaseDn;
214 print "Updating LDAP directory..",
219 Details = [("uid",account),
221 ("top","inetOrgPerson","debianAccount","shadowAccount","debianDeveloper")),
222 ("uidNumber",str(uidNumber)),
223 ("gidNumber",str(gidNumber)),
224 ("gecos",FullName+",,,,"),
225 ("loginShell","/bin/bash"),
226 ("keyFingerPrint",Keys[0][1]),
229 ("emailForward",email),
230 ("shadowLastChange",str(int(time.time()/24/60/60))),
232 ("shadowMax","99999"),
233 ("shadowWarning","7"),
234 ("privateSub",privsub),
235 ("userPassword","{crypt}"+Pass)];
237 Details.append(("mn",mn));
241 Rec = [(ldap.MOD_REPLACE,"uidNumber",str(uidNumber)),
242 (ldap.MOD_REPLACE,"gidNumber",str(gidNumber)),
243 (ldap.MOD_REPLACE,"gecos",FullName+",,,,"),
244 (ldap.MOD_REPLACE,"loginShell","/bin/bash"),
245 (ldap.MOD_REPLACE,"keyFingerPrint",Keys[0][1]),
246 (ldap.MOD_REPLACE,"cn",cn),
247 (ldap.MOD_REPLACE,"mn",mn),
248 (ldap.MOD_REPLACE,"sn",sn),
249 (ldap.MOD_REPLACE,"emailForward",email),
250 (ldap.MOD_REPLACE,"shadowLastChange",str(int(time.time()/24/60/60))),
251 (ldap.MOD_REPLACE,"shadowMin","0"),
252 (ldap.MOD_REPLACE,"shadowMax","99999"),
253 (ldap.MOD_REPLACE,"shadowWarning","7"),
254 (ldap.MOD_REPLACE,"shadowInactive",""),
255 (ldap.MOD_REPLACE,"shadowExpire","")];
257 Rec.append((ldap.MOD_REPLACE,"privateSub",privsub));
259 Rec.append((ldap.MOD_REPLACE,"userPassword","{crypt}"+Pass));
265 # Abort email sends for an update operation
266 if Update == 1 and ForceMail == 0:
267 print "Account is not new, Not sending mails"
270 # Send the Welcome message
271 print "Sending Welcome Email"
272 Reply = TemplateSubst(Subst,open(TemplatesDir+"/welcome-message-"+gidNumber,"r").read());
273 Child = os.popen("/usr/sbin/sendmail -t","w");
274 #Child = os.popen("cat","w");
276 if Child.close() != None:
277 raise Error, "Sendmail gave a non-zero return code";