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