- changed smb_getpwnam() to use winbind style usernames
[kai/samba.git] / source / lib / username.c
index 4237a42078c05b66e6c2bbc75baf3718be09f88e..2620d74eba3e7bb7fe9f1a04827ddb2cf2e5b62a 100644 (file)
@@ -27,9 +27,10 @@ static struct passwd *uname_string_combinations(char *s, struct passwd * (*fn) (
 static struct passwd *uname_string_combinations2(char *s, int offset, struct passwd * (*fn) (char *), int N);
 
 /****************************************************************************
-get a users home directory.
+ Get a users home directory.
 ****************************************************************************/
-char *get_home_dir(char *user)
+
+char *get_user_home_dir(char *user)
 {
   static struct passwd *pass;
 
@@ -41,15 +42,16 @@ char *get_home_dir(char *user)
 
 
 /*******************************************************************
-map a username from a dos name to a unix name by looking in the username
-map. Note that this modifies the name in place.
-This is the main function that should be called *once* on
-any incoming or new username - in order to canonicalize the name.
-This is being done to de-couple the case conversions from the user mapping
-function. Previously, the map_username was being called
-every time Get_Pwnam was called.
-Returns True if username was changed, false otherwise.
+ Map a username from a dos name to a unix name by looking in the username
+ map. Note that this modifies the name in place.
+ This is the main function that should be called *once* on
+ any incoming or new username - in order to canonicalize the name.
+ This is being done to de-couple the case conversions from the user mapping
+ function. Previously, the map_username was being called
+ every time Get_Pwnam was called.
+ Returns True if username was changed, false otherwise.
 ********************************************************************/
+
 BOOL map_username(char *user)
 {
   static BOOL initialised=False;
@@ -58,6 +60,7 @@ BOOL map_username(char *user)
   char *mapfile = lp_username_map();
   char *s;
   pstring buf;
+  BOOL mapped_user = False;
 
   if (!*user)
     return False;
@@ -79,7 +82,7 @@ BOOL map_username(char *user)
     return True;
   }
   
-  f = fopen(mapfile,"r");
+  f = sys_fopen(mapfile,"r");
   if (!f) {
     DEBUG(0,("can't open username map %s\n",mapfile));
     return False;
@@ -119,6 +122,7 @@ BOOL map_username(char *user)
 
     if (strchr(dosname,'*') || user_in_list(user,dosname)) {
       DEBUG(3,("Mapped user %s to %s\n",user,unixname));
+      mapped_user = True;
       fstrcpy(last_from,user);
       sscanf(unixname,"%s",user);
       fstrcpy(last_to,user);
@@ -132,47 +136,44 @@ BOOL map_username(char *user)
   fclose(f);
 
   /*
-   * Username wasn't mapped. Setup the last_from and last_to
-   * as an optimization so that we don't scan the file again
-   * for the same user.
+   * Setup the last_from and last_to as an optimization so 
+   * that we don't scan the file again for the same user.
    */
   fstrcpy(last_from,user);
   fstrcpy(last_to,user);
 
-  return False;
+  return mapped_user;
 }
 
 /****************************************************************************
-Get_Pwnam wrapper
+ Get_Pwnam wrapper
 ****************************************************************************/
+
 static struct passwd *_Get_Pwnam(char *s)
 {
   struct passwd *ret;
 
-  ret = getpwnam(s);
-  if (ret)
-    {
-#ifdef GETPWANAM
-      struct passwd_adjunct *pwret;
-      pwret = getpwanam(s);
-      if (pwret)
-       {
-         free(ret->pw_passwd);
-         ret->pw_passwd = pwret->pwa_passwd;
-       }
-#endif
-
+  ret = sys_getpwnam(s);
+  if (ret) {
+#ifdef HAVE_GETPWANAM
+    struct passwd_adjunct *pwret;
+    pwret = getpwanam(s);
+    if (pwret && pwret->pwa_passwd) {
+      pstrcpy(ret->pw_passwd,pwret->pwa_passwd);
     }
+#endif
+  }
 
   return(ret);
 }
 
 
 /****************************************************************************
-a wrapper for getpwnam() that tries with all lower and all upper case 
-if the initial name fails. Also tried with first letter capitalised
-Note that this can change user!
+ A wrapper for getpwnam() that tries with all lower and all upper case 
+ if the initial name fails. Also tried with first letter capitalised
+ Note that this can change user!
 ****************************************************************************/
+
 struct passwd *Get_Pwnam(char *user,BOOL allow_change)
 {
   fstring user2;
@@ -191,34 +192,39 @@ struct passwd *Get_Pwnam(char *user,BOOL allow_change)
   }
 
   ret = _Get_Pwnam(user);
-  if (ret) return(ret);
+  if (ret)
+    return(ret);
 
   strlower(user);
   ret = _Get_Pwnam(user);
-  if (ret)  return(ret);
+  if (ret)
+    return(ret);
 
   strupper(user);
   ret = _Get_Pwnam(user);
-  if (ret) return(ret);
+  if (ret)
+    return(ret);
 
-  /* try with first letter capitalised */
+  /* Try with first letter capitalised. */
   if (strlen(user) > 1)
     strlower(user+1);  
   ret = _Get_Pwnam(user);
-  if (ret) return(ret);
+  if (ret)
+    return(ret);
 
   /* try with last letter capitalised */
   strlower(user);
   last_char = strlen(user)-1;
   user[last_char] = toupper(user[last_char]);
-  DEBUG(3, ("Trying username %s\n", user));
   ret = _Get_Pwnam(user);
-  if (ret) return(ret);
+  if (ret)
+    return(ret);
 
-  /* try all combinations up to usernamelevel */
+  /* Try all combinations up to usernamelevel. */
   strlower(user);
   ret = uname_string_combinations(user, _Get_Pwnam, usernamelevel);
-  if (ret) return(ret);
+  if (ret)
+    return(ret);
 
   if (allow_change)
     fstrcpy(user,user2);
@@ -227,21 +233,19 @@ struct passwd *Get_Pwnam(char *user,BOOL allow_change)
 }
 
 /****************************************************************************
-check if a user is in a netgroup user list
+ Check if a user is in a netgroup user list.
 ****************************************************************************/
+
 static BOOL user_in_netgroup_list(char *user,char *ngname)
 {
-#ifdef NETGROUP
+#ifdef HAVE_NETGROUP
   static char *mydomain = NULL;
   if (mydomain == NULL)
     yp_get_default_domain(&mydomain);
 
-  if(mydomain == NULL)
-  {
+  if(mydomain == NULL) {
     DEBUG(5,("Unable to get default yp domain\n"));
-  }
-  else
-  {
+  } else {
     DEBUG(5,("looking for user %s of domain %s in netgroup %s\n",
           user, mydomain, ngname));
     DEBUG(5,("innetgr is %s\n",
@@ -251,54 +255,56 @@ static BOOL user_in_netgroup_list(char *user,char *ngname)
     if (innetgr(ngname, NULL, user, mydomain))
       return (True);
   }
-#endif /* NETGROUP */
+#endif /* HAVE_NETGROUP */
   return False;
 }
 
 /****************************************************************************
-check if a user is in a UNIX user list
+ Check if a user is in a UNIX user list.
 ****************************************************************************/
+
 static BOOL user_in_group_list(char *user,char *gname)
 {
-#if HAVE_GETGRNAM 
-  struct group *gptr;
-  char **member;  
-  struct passwd *pass = Get_Pwnam(user,False);
-
-  if (pass)
-  { 
-    gptr = getgrgid(pass->pw_gid);
-    if (gptr && strequal(gptr->gr_name,gname))
-      return(True); 
-  } 
-
-  gptr = (struct group *)getgrnam(gname);
-
-  if (gptr)
-  {
-    member = gptr->gr_mem;
-    while (member && *member)
-    {
-      if (strequal(*member,user))
-        return(True);
-      member++;
-    }
-  }
+#ifdef HAVE_GETGRENT
+       struct group *gptr;
+       char **member;  
+       struct passwd *pass = Get_Pwnam(user,False);
+
+       if (pass) { 
+               gptr = getgrgid(pass->pw_gid);
+               if (gptr && strequal(gptr->gr_name,gname))
+                       return(True); 
+       } 
+
+       while ((gptr = (struct group *)getgrent())) {
+               if (!strequal(gptr->gr_name,gname))
+                       continue;
+               member = gptr->gr_mem;
+               while (member && *member) {
+                       if (strequal(*member,user)) {
+                               endgrent();
+                               return(True);
+                       }
+                       member++;
+               }
+       }
+
+       endgrent();
 #endif /* HAVE_GETGRNAM */
-  return False;
+       return False;
 }            
 
 /****************************************************************************
-check if a user is in a user list - can check combinations of UNIX
-and netgroup lists.
+ Check if a user is in a user list - can check combinations of UNIX
+ and netgroup lists.
 ****************************************************************************/
+
 BOOL user_in_list(char *user,char *list)
 {
   pstring tok;
   char *p=list;
 
-  while (next_token(&p,tok,LIST_SEP))
-  {
+  while (next_token(&p,tok,LIST_SEP, sizeof(tok))) {
     /*
      * Check raw username.
      */
@@ -310,8 +316,7 @@ BOOL user_in_list(char *user,char *list)
      * of UNIX and netgroups has been specified.
      */
 
-    if(*tok == '@')
-    {
+    if(*tok == '@') {
       /*
        * Old behaviour. Check netgroup list
        * followed by UNIX list.
@@ -320,11 +325,9 @@ BOOL user_in_list(char *user,char *list)
         return True;
       if(user_in_group_list(user,&tok[1]))
         return True;
-    }
-    else if (*tok == '+')
-    {
-      if(tok[1] == '&')
-      {
+    } else if (*tok == '+') {
+
+      if(tok[1] == '&') {
         /*
          * Search UNIX list followed by netgroup.
          */
@@ -332,20 +335,20 @@ BOOL user_in_list(char *user,char *list)
           return True;
         if(user_in_netgroup_list(user,&tok[2]))
           return True;
-      }
-      else
-      {
+
+      } else {
+
         /*
          * Just search UNIX list.
          */
+
         if(user_in_group_list(user,&tok[1]))
           return True;
       }
-    }
-    else if (*tok == '&')
-    {
-      if(tok[1] == '&')
-      {
+
+    } else if (*tok == '&') {
+
+      if(tok[1] == '+') {
         /*
          * Search netgroup list followed by UNIX list.
          */
@@ -353,9 +356,7 @@ BOOL user_in_list(char *user,char *list)
           return True;
         if(user_in_group_list(user,&tok[2]))
           return True;
-      }
-      else
-      {
+      } else {
         /*
          * Just search netgroup list.
          */
@@ -369,15 +370,16 @@ BOOL user_in_list(char *user,char *list)
 
 /* The functions below have been taken from password.c and slightly modified */
 /****************************************************************************
-apply a function to upper/lower case combinations
-of a string and return true if one of them returns true.
-try all combinations with N uppercase letters.
-offset is the first char to try and change (start with 0)
-it assumes the string starts lowercased
+ Apply a function to upper/lower case combinations
+ of a string and return true if one of them returns true.
+ Try all combinations with N uppercase letters.
+ offset is the first char to try and change (start with 0)
+ it assumes the string starts lowercased
 ****************************************************************************/
+
 static struct passwd *uname_string_combinations2(char *s,int offset,struct passwd *(*fn)(char *),int N)
 {
-  int len = strlen(s);
+  ssize_t len = (ssize_t)strlen(s);
   int i;
   struct passwd *ret;
 
@@ -388,36 +390,70 @@ static struct passwd *uname_string_combinations2(char *s,int offset,struct passw
   if (N <= 0 || offset >= len)
     return(fn(s));
 
-
-  for (i=offset;i<(len-(N-1));i++)
-
-    {
-      char c = s[i];
-      if (!islower(c)) continue;
-      s[i] = toupper(c);
-      ret = uname_string_combinations2(s,i+1,fn,N-1);
-      if(ret) return(ret);
-      s[i] = c;
-    }
+  for (i=offset;i<(len-(N-1));i++) {
+    char c = s[i];
+    if (!islower(c))
+      continue;
+    s[i] = toupper(c);
+    ret = uname_string_combinations2(s,i+1,fn,N-1);
+    if(ret)
+      return(ret);
+    s[i] = c;
+  }
   return(NULL);
 }
 
 /****************************************************************************
-apply a function to upper/lower case combinations
-of a string and return true if one of them returns true.
-try all combinations with up to N uppercase letters.
-offset is the first char to try and change (start with 0)
-it assumes the string starts lowercased
+ Apply a function to upper/lower case combinations
+ of a string and return true if one of them returns true.
+ Try all combinations with up to N uppercase letters.
+ offset is the first char to try and change (start with 0)
+ it assumes the string starts lowercased
 ****************************************************************************/
+
 static struct passwd * uname_string_combinations(char *s,struct passwd * (*fn)(char *),int N)
 {
   int n;
   struct passwd *ret;
 
-  for (n=1;n<=N;n++)
-  {
+  for (n=1;n<=N;n++) {
     ret = uname_string_combinations2(s,0,fn,n);
-    if(ret) return(ret);
+    if(ret)
+      return(ret);
   }
   return(NULL);
 }
+
+
+/****************************************************************************
+these wrappers allow appliance mode to work. In appliance mode the username
+takes the form DOMAIN/user
+****************************************************************************/
+struct passwd *smb_getpwnam(char *user, BOOL allow_change)
+{
+       struct passwd *pw;
+       char *p;
+
+       pw = Get_Pwnam(user, allow_change);
+       if (pw) return pw;
+
+       p = strchr(user,'/');
+       if (p) return Get_Pwnam(p+1, allow_change);
+
+       return NULL;
+}
+
+int smb_initgroups(char *user, char *domain, gid_t group)
+{
+       fstring userdom;
+       int ret;
+
+       ret = initgroups(user, group);
+       if (ret==0 || !domain || !*domain) return ret;
+
+       slprintf(userdom, sizeof(userdom), "%s/%s", domain, user);
+
+       DEBUG(4,("smb_initgroups trying userdom %s\n", userdom));
+
+       return initgroups(userdom, group);
+}