python:tests: Store keys as bytes rather than as lists of ints
[samba.git] / source3 / lib / username.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Username handling
4    Copyright (C) Andrew Tridgell 1992-1998
5    Copyright (C) Jeremy Allison 1997-2001.
6    Copyright (C) Andrew Bartlett 2002
7
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 3 of the License, or
11    (at your option) any later version.
12
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.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "system/passwd.h"
24 #include "../lib/util/memcache.h"
25 #include "../lib/util/util_pw.h"
26
27 /* internal functions */
28 static struct passwd *uname_string_combinations(char *s, TALLOC_CTX *mem_ctx,
29                                                 struct passwd * (*fn) (TALLOC_CTX *mem_ctx, const char *),
30                                                 int N);
31 static struct passwd *uname_string_combinations2(char *s, TALLOC_CTX *mem_ctx, int offset,
32                                                  struct passwd * (*fn) (TALLOC_CTX *mem_ctx, const char *),
33                                                  int N);
34
35 static struct passwd *getpwnam_alloc_cached(TALLOC_CTX *mem_ctx, const char *name)
36 {
37         struct passwd *pw, *for_cache;
38
39         pw = (struct passwd *)memcache_lookup_talloc(
40                 NULL, GETPWNAM_CACHE, data_blob_string_const_null(name));
41         if (pw != NULL) {
42                 return tcopy_passwd(mem_ctx, pw);
43         }
44
45         pw = getpwnam(name);
46         if (pw == NULL) {
47                 return NULL;
48         }
49
50         for_cache = tcopy_passwd(talloc_tos(), pw);
51         if (for_cache == NULL) {
52                 return NULL;
53         }
54
55         memcache_add_talloc(NULL, GETPWNAM_CACHE,
56                         data_blob_string_const_null(name), &for_cache);
57
58         return tcopy_passwd(mem_ctx, pw);
59 }
60
61 /****************************************************************************
62  Flush all cached passwd structs.
63 ****************************************************************************/
64
65 void flush_pwnam_cache(void)
66 {
67         memcache_flush(NULL, GETPWNAM_CACHE);
68 }
69
70 /****************************************************************************
71  Get a users home directory.
72 ****************************************************************************/
73
74 char *get_user_home_dir(TALLOC_CTX *mem_ctx, const char *user)
75 {
76         struct passwd *pass;
77         char *result;
78
79         /* Ensure the user exists. */
80
81         pass = Get_Pwnam_alloc(mem_ctx, user);
82
83         if (!pass)
84                 return(NULL);
85
86         /* Return home directory from struct passwd. */
87
88         result = talloc_move(mem_ctx, &pass->pw_dir);
89
90         TALLOC_FREE(pass);
91         return result;
92 }
93
94 /****************************************************************************
95  * A wrapper for getpwnam().  The following variations are tried:
96  *   - as transmitted
97  *   - in all lower case if this differs from transmitted
98  *   - in all upper case if this differs from transmitted
99  *   - using lp_username_level() for permutations.
100 ****************************************************************************/
101
102 static struct passwd *Get_Pwnam_internals(TALLOC_CTX *mem_ctx,
103                                           const char *user, char *user2)
104 {
105         struct passwd *ret = NULL;
106
107         if (!user2 || !(*user2))
108                 return(NULL);
109
110         if (!user || !(*user))
111                 return(NULL);
112
113         /* Try in all lower case first as this is the most 
114            common case on UNIX systems */
115         if (!strlower_m(user2)) {
116                 DEBUG(5,("strlower_m %s failed\n", user2));
117                 goto done;
118         }
119
120         DEBUG(5,("Trying _Get_Pwnam(), username as lowercase is %s\n",user2));
121         ret = getpwnam_alloc_cached(mem_ctx, user2);
122         if(ret)
123                 goto done;
124
125         /* Try as given, if username wasn't originally lowercase */
126         if(strcmp(user, user2) != 0) {
127                 DEBUG(5,("Trying _Get_Pwnam(), username as given is %s\n",
128                          user));
129                 ret = getpwnam_alloc_cached(mem_ctx, user);
130                 if(ret)
131                         goto done;
132         }
133
134         /* Try as uppercase, if username wasn't originally uppercase */
135         if (!strupper_m(user2)) {
136                 goto done;
137         }
138
139         if(strcmp(user, user2) != 0) {
140                 DEBUG(5,("Trying _Get_Pwnam(), username as uppercase is %s\n",
141                          user2));
142                 ret = getpwnam_alloc_cached(mem_ctx, user2);
143                 if(ret)
144                         goto done;
145         }
146
147         /* Try all combinations up to usernamelevel */
148         if (!strlower_m(user2)) {
149                 DEBUG(5,("strlower_m %s failed\n", user2));
150                 goto done;
151         }
152         DEBUG(5,("Checking combinations of %d uppercase letters in %s\n",
153                  lp_username_level(), user2));
154         ret = uname_string_combinations(user2, mem_ctx, getpwnam_alloc_cached,
155                                         lp_username_level());
156
157 done:
158         DEBUG(5,("Get_Pwnam_internals %s find user [%s]!\n",ret ?
159                  "did":"didn't", user));
160
161         return ret;
162 }
163
164 /****************************************************************************
165  Get_Pwnam wrapper without modification.
166   NOTE: This with NOT modify 'user'! 
167   This will return an allocated structure
168 ****************************************************************************/
169
170 struct passwd *Get_Pwnam_alloc(TALLOC_CTX *mem_ctx, const char *user)
171 {
172         fstring user2;
173
174         if ( *user == '\0' ) {
175                 DEBUG(10,("Get_Pwnam: empty username!\n"));
176                 return NULL;
177         }
178
179         fstrcpy(user2, user);
180
181         DEBUG(5,("Finding user %s\n", user));
182
183         return Get_Pwnam_internals(mem_ctx, user, user2);
184 }
185
186 /* The functions below have been taken from password.c and slightly modified */
187 /****************************************************************************
188  Apply a function to upper/lower case combinations
189  of a string and return true if one of them returns true.
190  Try all combinations with N uppercase letters.
191  offset is the first char to try and change (start with 0)
192  it assumes the string starts lowercased
193 ****************************************************************************/
194
195 static struct passwd *uname_string_combinations2(char *s, TALLOC_CTX *mem_ctx,
196                                                  int offset,
197                                                  struct passwd *(*fn)(TALLOC_CTX *mem_ctx, const char *),
198                                                  int N)
199 {
200         ssize_t len = (ssize_t)strlen(s);
201         int i;
202         struct passwd *ret;
203
204         if (N <= 0 || offset >= len)
205                 return(fn(mem_ctx, s));
206
207         for (i=offset;i<(len-(N-1));i++) {
208                 char c = s[i];
209                 if (!islower_m((int)c))
210                         continue;
211                 s[i] = toupper_m(c);
212                 ret = uname_string_combinations2(s, mem_ctx, i+1, fn, N-1);
213                 if(ret)
214                         return(ret);
215                 s[i] = c;
216         }
217         return(NULL);
218 }
219
220 /****************************************************************************
221  Apply a function to upper/lower case combinations
222  of a string and return true if one of them returns true.
223  Try all combinations with up to N uppercase letters.
224  offset is the first char to try and change (start with 0)
225  it assumes the string starts lowercased
226 ****************************************************************************/
227
228 static struct passwd * uname_string_combinations(char *s, TALLOC_CTX *mem_ctx,
229                                                  struct passwd * (*fn)(TALLOC_CTX *mem_ctx, const char *),
230                                                  int N)
231 {
232         int n;
233         struct passwd *ret;
234
235         for (n=1;n<=N;n++) {
236                 ret = uname_string_combinations2(s,mem_ctx,0,fn,n);
237                 if(ret)
238                         return(ret);
239         }  
240         return(NULL);
241 }
242