ud-generate: deal with users without loginShell
[mirror/userdir-ldap.git] / ud-useradd
index 003f28c..0dee8c4 100755 (executable)
@@ -28,6 +28,7 @@ from userdir_ldap import *;
 from userdir_gpg import *;
 
 HavePrivateList = getattr(ConfModule, "haveprivatelist", True)
+DefaultGroup = getattr(ConfModule, "defaultgroup", 'users')
 
 # This tries to search for a free UID. There are two possible ways to do
 # this, one is to fetch all the entires and pick the highest, the other
@@ -35,24 +36,38 @@ HavePrivateList = getattr(ConfModule, "haveprivatelist", True)
 # Regrettably ldap doesn't have an integer attribute comparision function
 # so we can only cut the search down slightly
 
+def ShouldIgnoreID(uid):
+   for i in IgnoreUsersForUIDNumberGen:
+      try:
+         if i.search(uid) is not None:
+            return True
+      except AttributeError:
+         if uid == i:
+            return True
+
+   return False
+
 # [JT] This is broken with Woody LDAP and the Schema; for now just
 #      search through all UIDs.
 def GetFreeID(l):
-   Attrs = l.search_s(BaseDn,ldap.SCOPE_ONELEVEL,
-                      "uidNumber=*",["uidNumber", "gidNumber"]);
+   Attrs = l.search_s(BaseBaseDn,ldap.SCOPE_SUBTREE,
+                      "(|(uidNumber=*)(gidNumber=*))",["uidNumber", "gidNumber", "uid"]);
    HighestUID = 0;
    gids = [];
+   uids = [];
    for I in Attrs:
       ID = int(GetAttr(I,"uidNumber","0"));
+      uids.append(ID)
       gids.append(int(GetAttr(I, "gidNumber","0")))
-      if ID > HighestUID:
+      uid = GetAttr(I, "uid", None)
+      if ID > HighestUID and not uid is None and not ShouldIgnoreID(uid):
          HighestUID = ID;
 
-   resGID = HighestUID + 1;
-   while resGID in gids:
-      resGID += 1
+   resUID = HighestUID + 1;
+   while resUID in uids or resUID in gids:
+      resUID += 1
 
-   return (HighestUID + 1, resGID);
+   return (resUID, resUID)
 
 # Main starts here
 AdminUser = pwd.getpwuid(os.getuid())[0];
@@ -72,7 +87,7 @@ for (switch, val) in options:
       print "        -u=<user>  Admin user (defaults to current username)"
       print "        -m         Force mail (for updates)"
       print "        -a         Use old keyrings instead (??)"
-      print "        -n         Do not automatically assign UID/GIDs (useful for usergroups or non-default group membership"
+      print "        -n         Do not automatically assign UID/GIDs"
       print "        -g         Add a guest account"
       sys.exit(0)
    elif (switch == '-u'):
@@ -165,7 +180,7 @@ while 1:
       cn = GetAttr(Attrs[0],"cn");
       sn = GetAttr(Attrs[0],"sn");
       mn = GetAttr(Attrs[0],"mn");
-      if privsub == None or privsub == "":
+      if privsub is None or privsub == "":
          privsub = " ";
       break;
    else:
@@ -195,14 +210,12 @@ if HavePrivateList and not GuestAccount:
 else:
    privsub = " "
 
-if not gidNumber:
-   if not GuestAccount:
-      gidNumber = DefaultGID
-   else:
-      gidNumber = DebianGroups['guest']
 
 (uidNumber, generatedGID) = GetFreeID(l)
-UserGroup = 0
+if not gidNumber:
+   gidNumber = generatedGID
+
+UserGroup = 1
 if NoAutomaticIDs:
    # UID
    if not Update:
@@ -211,15 +224,20 @@ if NoAutomaticIDs:
          uidNumber = Res;
    
    # GID
-   Res = raw_input("Group ID Number (default group is %s, new usergroup %s) [%s]" % (DefaultGID, generatedGID, gidNumber));
+   Res = raw_input("Group ID Number (new usergroup is %s) [%s]" % (generatedGID, gidNumber));
    if Res != "":
       if Res.isdigit():
          gidNumber = int(Res);
       else:
          gidNumber = Group2GID(l, Res);
    
-   if gidNumber == generatedGID:
-      UserGroup = 1
+   if gidNumber != generatedGID:
+      UserGroup = 0
+
+if GuestAccount:
+  supplementaryGid = 'guest'
+else:
+  supplementaryGid = DefaultGroup
 
 shadowExpire = None
 hostacl = []
@@ -231,7 +249,7 @@ if GuestAccount:
       shadowExpire = int(time.time() / 3600 / 24) + exp
    res = raw_input("Hosts to grant access to: ")
    for h in res.split():
-      if not '.' in h: h = h + '.' + HostDomain
+      if '.' not in h: h = h + '.' + HostDomain
       if exp > 0: h = h + " " + datetime.datetime.fromtimestamp( time.time() + exp * 24*3600 ).strftime("%Y%m%d")
       hostacl.append(h)
 
@@ -249,8 +267,8 @@ if Update == 0 or ForceMail == 1:
       CryptedPass = GPGEncrypt("Your new password is '" + Password + "'\n",\
                                "0x"+Keys[0][1],UsePGP2);
       Password = None;
-      if CryptedPass == None:
-        raise "Error","Password Encryption failed"
+      if CryptedPass is None:
+        raise Exception("Password Encryption failed")
    else:
       Pass = HashPass(Password);
       CryptedPass = "Your password has been set to the previously agreed value.";
@@ -267,6 +285,7 @@ print "------------";
 print "Final information collected:"
 print " %s <%s@%s>:" % (FullName,account,EmailAppend);
 print "   Assigned UID:",uidNumber," GID:", gidNumber;
+print "   supplementary group:",supplementaryGid
 print "   Email forwarded to:",emailaddr
 if HavePrivateList:
    print "   Private Subscription:",privsub;
@@ -311,6 +330,7 @@ if Update == 0:
               ("objectClass", UserObjectClasses),
               ("uidNumber",str(uidNumber)),
               ("gidNumber",str(gidNumber)),
+              ("supplementaryGid",supplementaryGid),
               ("gecos",FullName+",,,,"),
               ("loginShell","/bin/bash"),
               ("keyFingerPrint",Keys[0][1]),
@@ -356,7 +376,7 @@ else:
           (ldap.MOD_REPLACE,"shadowExpire","")];
    if privsub != " ":
       Rec.append((ldap.MOD_REPLACE,"privateSub",privsub));
-   if Pass != None:
+   if Pass is not None:
       Rec.append((ldap.MOD_REPLACE,"userPassword","{crypt}"+Pass));
    # Do it
    l.modify_s(Dn,Rec);
@@ -370,15 +390,15 @@ if Update == 1 and ForceMail == 0:
 
 # Send the Welcome message
 print "Sending Welcome Email"
-templatepath = TemplatesDir + "/welcome-message-%d" % int(gidNumber)
+templatepath = TemplatesDir + "/welcome-message-%s" % supplementaryGid
 if not os.path.exists(templatepath):
    templatepath = TemplatesDir + "/welcome-message"
 Reply = TemplateSubst(Subst,open(templatepath, "r").read())
 Child = os.popen("/usr/sbin/sendmail -t","w");
 #Child = os.popen("cat","w");
 Child.write(Reply);
-if Child.close() != None:
-   raise Error, "Sendmail gave a non-zero return code";
+if Child.close() is not None:
+   raise Exception("Sendmail gave a non-zero return code")
 
 # vim:set et:
 # vim:set ts=3: