s3:lib: implement serverid_equal() as macro of server_id_equal()
[kai/samba.git] / source3 / lib / username.c
index 3dcf9e18cc40ce2117912e2b9abf93d78144ad8a..665fbb42536c1038a15321d621fa23b311bbdd7e 100644 (file)
@@ -3,23 +3,26 @@
    Username handling
    Copyright (C) Andrew Tridgell 1992-1998
    Copyright (C) Jeremy Allison 1997-2001.
-   
+   Copyright (C) Andrew Bartlett 2002
+
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
-   
+
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
-   
+
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
+#include "system/passwd.h"
+#include "memcache.h"
+#include "../lib/util/util_pw.h"
 
 /* internal functions */
 static struct passwd *uname_string_combinations(char *s, TALLOC_CTX *mem_ctx,
@@ -29,35 +32,73 @@ static struct passwd *uname_string_combinations2(char *s, TALLOC_CTX *mem_ctx, i
                                                 struct passwd * (*fn) (TALLOC_CTX *mem_ctx, const char *),
                                                 int N);
 
+static struct passwd *getpwnam_alloc_cached(TALLOC_CTX *mem_ctx, const char *name)
+{
+       struct passwd *pw, *for_cache;
+
+       pw = (struct passwd *)memcache_lookup_talloc(
+               NULL, GETPWNAM_CACHE, data_blob_string_const_null(name));
+       if (pw != NULL) {
+               return tcopy_passwd(mem_ctx, pw);
+       }
+
+       pw = getpwnam(name);
+       if (pw == NULL) {
+               return NULL;
+       }
+
+       for_cache = tcopy_passwd(talloc_tos(), pw);
+       if (for_cache == NULL) {
+               return NULL;
+       }
+
+       memcache_add_talloc(NULL, GETPWNAM_CACHE,
+                       data_blob_string_const_null(name), &for_cache);
+
+       return tcopy_passwd(mem_ctx, pw);
+}
+
+/****************************************************************************
+ Flush all cached passwd structs.
+****************************************************************************/
+
+void flush_pwnam_cache(void)
+{
+        memcache_flush(NULL, GETPWNAM_CACHE);
+}
+
 /****************************************************************************
  Get a users home directory.
 ****************************************************************************/
 
-char *get_user_home_dir(const char *user)
+char *get_user_home_dir(TALLOC_CTX *mem_ctx, const char *user)
 {
-       static struct passwd *pass;
+       struct passwd *pass;
+       char *result;
 
        /* Ensure the user exists. */
 
-       pass = Get_Pwnam(user);
+       pass = Get_Pwnam_alloc(mem_ctx, user);
 
        if (!pass)
                return(NULL);
+
        /* Return home directory from struct passwd. */
 
-       return(pass->pw_dir);      
+       result = talloc_move(mem_ctx, &pass->pw_dir);
+
+       TALLOC_FREE(pass);
+       return result;
 }
 
 /****************************************************************************
- * A wrapper for sys_getpwnam().  The following variations are tried:
+ * A wrapper for getpwnam().  The following variations are tried:
  *   - as transmitted
  *   - in all lower case if this differs from transmitted
  *   - in all upper case if this differs from transmitted
  *   - using lp_usernamelevel() for permutations.
 ****************************************************************************/
 
-static struct passwd *Get_Pwnam_ret = NULL;
-
 static struct passwd *Get_Pwnam_internals(TALLOC_CTX *mem_ctx,
                                          const char *user, char *user2)
 {
@@ -71,9 +112,13 @@ static struct passwd *Get_Pwnam_internals(TALLOC_CTX *mem_ctx,
 
        /* Try in all lower case first as this is the most 
           common case on UNIX systems */
-       strlower_m(user2);
+       if (!strlower_m(user2)) {
+               DEBUG(5,("strlower_m %s failed\n", user2));
+               goto done;
+       }
+
        DEBUG(5,("Trying _Get_Pwnam(), username as lowercase is %s\n",user2));
-       ret = getpwnam_alloc(mem_ctx, user2);
+       ret = getpwnam_alloc_cached(mem_ctx, user2);
        if(ret)
                goto done;
 
@@ -81,26 +126,32 @@ static struct passwd *Get_Pwnam_internals(TALLOC_CTX *mem_ctx,
        if(strcmp(user, user2) != 0) {
                DEBUG(5,("Trying _Get_Pwnam(), username as given is %s\n",
                         user));
-               ret = getpwnam_alloc(mem_ctx, user);
+               ret = getpwnam_alloc_cached(mem_ctx, user);
                if(ret)
                        goto done;
        }
 
        /* Try as uppercase, if username wasn't originally uppercase */
-       strupper_m(user2);
+       if (!strupper_m(user2)) {
+               goto done;
+       }
+
        if(strcmp(user, user2) != 0) {
                DEBUG(5,("Trying _Get_Pwnam(), username as uppercase is %s\n",
                         user2));
-               ret = getpwnam_alloc(mem_ctx, user2);
+               ret = getpwnam_alloc_cached(mem_ctx, user2);
                if(ret)
                        goto done;
        }
 
        /* Try all combinations up to usernamelevel */
-       strlower_m(user2);
+       if (!strlower_m(user2)) {
+               DEBUG(5,("strlower_m %s failed\n", user2));
+               goto done;
+       }
        DEBUG(5,("Checking combinations of %d uppercase letters in %s\n",
                 lp_usernamelevel(), user2));
-       ret = uname_string_combinations(user2, mem_ctx, getpwnam_alloc,
+       ret = uname_string_combinations(user2, mem_ctx, getpwnam_alloc_cached,
                                        lp_usernamelevel());
 
 done:
@@ -119,7 +170,6 @@ done:
 struct passwd *Get_Pwnam_alloc(TALLOC_CTX *mem_ctx, const char *user)
 {
        fstring user2;
-       struct passwd *ret;
 
        if ( *user == '\0' ) {
                DEBUG(10,("Get_Pwnam: empty username!\n"));
@@ -130,43 +180,7 @@ struct passwd *Get_Pwnam_alloc(TALLOC_CTX *mem_ctx, const char *user)
 
        DEBUG(5,("Finding user %s\n", user));
 
-       ret = Get_Pwnam_internals(mem_ctx, user, user2);
-       
-       return ret;  
-}
-
-/****************************************************************************
- Get_Pwnam wrapper without modification.
-  NOTE: This with NOT modify 'user'! 
-****************************************************************************/
-
-struct passwd *Get_Pwnam(const char *user)
-{
-       struct passwd *ret;
-
-       ret = Get_Pwnam_alloc(NULL, user);
-       
-       /* This call used to just return the 'passwd' static buffer.
-          This could then have accidental reuse implications, so 
-          we now malloc a copy, and free it in the next use.
-
-          This should cause the (ab)user to segfault if it 
-          uses an old struct. 
-          
-          This is better than useing the wrong data in security
-          critical operations.
-
-          The real fix is to make the callers free the returned 
-          malloc'ed data.
-       */
-
-       if (Get_Pwnam_ret) {
-               TALLOC_FREE(Get_Pwnam_ret);
-       }
-       
-       Get_Pwnam_ret = ret;
-
-       return ret;  
+       return Get_Pwnam_internals(mem_ctx, user, user2);
 }
 
 /* The functions below have been taken from password.c and slightly modified */
@@ -192,9 +206,9 @@ static struct passwd *uname_string_combinations2(char *s, TALLOC_CTX *mem_ctx,
 
        for (i=offset;i<(len-(N-1));i++) {
                char c = s[i];
-               if (!islower_ascii((int)c))
+               if (!islower_m((int)c))
                        continue;
-               s[i] = toupper_ascii(c);
+               s[i] = toupper_m(c);
                ret = uname_string_combinations2(s, mem_ctx, i+1, fn, N-1);
                if(ret)
                        return(ret);