/src/samba/source3/lib/username.c
Line | Count | Source |
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 | | static struct passwd *getpwnam_alloc_cached(TALLOC_CTX *mem_ctx, const char *name) |
37 | 0 | { |
38 | 0 | struct passwd *pw, *for_cache; |
39 | |
|
40 | 0 | pw = (struct passwd *)memcache_lookup_talloc( |
41 | 0 | NULL, GETPWNAM_CACHE, data_blob_string_const_null(name)); |
42 | 0 | if (pw != NULL) { |
43 | 0 | return tcopy_passwd(mem_ctx, pw); |
44 | 0 | } |
45 | | |
46 | 0 | pw = getpwnam(name); |
47 | 0 | if (pw == NULL) { |
48 | 0 | return NULL; |
49 | 0 | } |
50 | | |
51 | 0 | for_cache = tcopy_passwd(talloc_tos(), pw); |
52 | 0 | if (for_cache == NULL) { |
53 | 0 | return NULL; |
54 | 0 | } |
55 | | |
56 | 0 | memcache_add_talloc(NULL, GETPWNAM_CACHE, |
57 | 0 | data_blob_string_const_null(name), &for_cache); |
58 | |
|
59 | 0 | return tcopy_passwd(mem_ctx, pw); |
60 | 0 | } |
61 | | |
62 | | /**************************************************************************** |
63 | | Flush all cached passwd structs. |
64 | | ****************************************************************************/ |
65 | | |
66 | | void flush_pwnam_cache(void) |
67 | 0 | { |
68 | 0 | memcache_flush(NULL, GETPWNAM_CACHE); |
69 | 0 | } |
70 | | |
71 | | /**************************************************************************** |
72 | | Get a users home directory. |
73 | | ****************************************************************************/ |
74 | | |
75 | | char *get_user_home_dir(TALLOC_CTX *mem_ctx, const char *user) |
76 | 0 | { |
77 | 0 | struct passwd *pass; |
78 | 0 | char *result; |
79 | | |
80 | | /* Ensure the user exists. */ |
81 | |
|
82 | 0 | pass = Get_Pwnam_alloc(mem_ctx, user); |
83 | |
|
84 | 0 | if (!pass) |
85 | 0 | return(NULL); |
86 | | |
87 | | /* Return home directory from struct passwd. */ |
88 | | |
89 | 0 | result = talloc_move(mem_ctx, &pass->pw_dir); |
90 | |
|
91 | 0 | TALLOC_FREE(pass); |
92 | 0 | return result; |
93 | 0 | } |
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 | | static struct passwd *Get_Pwnam_internals(TALLOC_CTX *mem_ctx, |
104 | | const char *user, char *user2) |
105 | 0 | { |
106 | 0 | struct passwd *ret = NULL; |
107 | |
|
108 | 0 | if (!user2 || !(*user2)) |
109 | 0 | return(NULL); |
110 | | |
111 | 0 | 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 | 0 | if (!strlower_m(user2)) { |
117 | 0 | DEBUG(5,("strlower_m %s failed\n", user2)); |
118 | 0 | goto done; |
119 | 0 | } |
120 | | |
121 | 0 | DEBUG(5,("Trying _Get_Pwnam(), username as lowercase is %s\n",user2)); |
122 | 0 | ret = getpwnam_alloc_cached(mem_ctx, user2); |
123 | 0 | if(ret) |
124 | 0 | goto done; |
125 | | |
126 | | /* Try as given, if username wasn't originally lowercase */ |
127 | 0 | if(strcmp(user, user2) != 0) { |
128 | 0 | DEBUG(5,("Trying _Get_Pwnam(), username as given is %s\n", |
129 | 0 | user)); |
130 | 0 | ret = getpwnam_alloc_cached(mem_ctx, user); |
131 | 0 | if(ret) |
132 | 0 | goto done; |
133 | 0 | } |
134 | | |
135 | | /* Try as uppercase, if username wasn't originally uppercase */ |
136 | 0 | if (!strupper_m(user2)) { |
137 | 0 | goto done; |
138 | 0 | } |
139 | | |
140 | 0 | if(strcmp(user, user2) != 0) { |
141 | 0 | DEBUG(5,("Trying _Get_Pwnam(), username as uppercase is %s\n", |
142 | 0 | user2)); |
143 | 0 | ret = getpwnam_alloc_cached(mem_ctx, user2); |
144 | 0 | if(ret) |
145 | 0 | goto done; |
146 | 0 | } |
147 | | |
148 | | /* Try all combinations up to usernamelevel */ |
149 | 0 | if (!strlower_m(user2)) { |
150 | 0 | DEBUG(5,("strlower_m %s failed\n", user2)); |
151 | 0 | goto done; |
152 | 0 | } |
153 | 0 | DEBUG(5,("Checking combinations of %d uppercase letters in %s\n", |
154 | 0 | lp_username_level(), user2)); |
155 | 0 | ret = uname_string_combinations(user2, mem_ctx, getpwnam_alloc_cached, |
156 | 0 | lp_username_level()); |
157 | |
|
158 | 0 | done: |
159 | 0 | DEBUG(5,("Get_Pwnam_internals %s find user [%s]!\n",ret ? |
160 | 0 | "did":"didn't", user)); |
161 | |
|
162 | 0 | return ret; |
163 | 0 | } |
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 | | struct passwd *Get_Pwnam_alloc(TALLOC_CTX *mem_ctx, const char *user) |
172 | 0 | { |
173 | 0 | fstring user2; |
174 | |
|
175 | 0 | if ( *user == '\0' ) { |
176 | 0 | DEBUG(10,("Get_Pwnam: empty username!\n")); |
177 | 0 | return NULL; |
178 | 0 | } |
179 | | |
180 | 0 | fstrcpy(user2, user); |
181 | |
|
182 | 0 | DEBUG(5,("Finding user %s\n", user)); |
183 | |
|
184 | 0 | return Get_Pwnam_internals(mem_ctx, user, user2); |
185 | 0 | } |
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 | | 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 | 0 | { |
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 | 0 | } |
218 | 0 | return(NULL); |
219 | 0 | } |
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 | | 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 | 0 | { |
233 | 0 | int n; |
234 | 0 | struct passwd *ret; |
235 | |
|
236 | 0 | 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 | 0 | } |
241 | 0 | return(NULL); |
242 | 0 | } |
243 | | |