r23784: use the GPLv3 boilerplate as recommended by the FSF and the license text
[tprouty/samba.git] / source / 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    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22
23 /* internal functions */
24 static struct passwd *uname_string_combinations(char *s, TALLOC_CTX *mem_ctx,
25                                                 struct passwd * (*fn) (TALLOC_CTX *mem_ctx, const char *),
26                                                 int N);
27 static struct passwd *uname_string_combinations2(char *s, TALLOC_CTX *mem_ctx, int offset,
28                                                  struct passwd * (*fn) (TALLOC_CTX *mem_ctx, const char *),
29                                                  int N);
30
31 /****************************************************************************
32  Get a users home directory.
33 ****************************************************************************/
34
35 char *get_user_home_dir(const char *user)
36 {
37         static struct passwd *pass;
38
39         /* Ensure the user exists. */
40
41         pass = Get_Pwnam(user);
42
43         if (!pass)
44                 return(NULL);
45         /* Return home directory from struct passwd. */
46
47         return(pass->pw_dir);      
48 }
49
50 /****************************************************************************
51  * A wrapper for sys_getpwnam().  The following variations are tried:
52  *   - as transmitted
53  *   - in all lower case if this differs from transmitted
54  *   - in all upper case if this differs from transmitted
55  *   - using lp_usernamelevel() for permutations.
56 ****************************************************************************/
57
58 static struct passwd *Get_Pwnam_ret = NULL;
59
60 static struct passwd *Get_Pwnam_internals(TALLOC_CTX *mem_ctx,
61                                           const char *user, char *user2)
62 {
63         struct passwd *ret = NULL;
64
65         if (!user2 || !(*user2))
66                 return(NULL);
67
68         if (!user || !(*user))
69                 return(NULL);
70
71         /* Try in all lower case first as this is the most 
72            common case on UNIX systems */
73         strlower_m(user2);
74         DEBUG(5,("Trying _Get_Pwnam(), username as lowercase is %s\n",user2));
75         ret = getpwnam_alloc(mem_ctx, user2);
76         if(ret)
77                 goto done;
78
79         /* Try as given, if username wasn't originally lowercase */
80         if(strcmp(user, user2) != 0) {
81                 DEBUG(5,("Trying _Get_Pwnam(), username as given is %s\n",
82                          user));
83                 ret = getpwnam_alloc(mem_ctx, user);
84                 if(ret)
85                         goto done;
86         }
87
88         /* Try as uppercase, if username wasn't originally uppercase */
89         strupper_m(user2);
90         if(strcmp(user, user2) != 0) {
91                 DEBUG(5,("Trying _Get_Pwnam(), username as uppercase is %s\n",
92                          user2));
93                 ret = getpwnam_alloc(mem_ctx, user2);
94                 if(ret)
95                         goto done;
96         }
97
98         /* Try all combinations up to usernamelevel */
99         strlower_m(user2);
100         DEBUG(5,("Checking combinations of %d uppercase letters in %s\n",
101                  lp_usernamelevel(), user2));
102         ret = uname_string_combinations(user2, mem_ctx, getpwnam_alloc,
103                                         lp_usernamelevel());
104
105 done:
106         DEBUG(5,("Get_Pwnam_internals %s find user [%s]!\n",ret ?
107                  "did":"didn't", user));
108
109         return ret;
110 }
111
112 /****************************************************************************
113  Get_Pwnam wrapper without modification.
114   NOTE: This with NOT modify 'user'! 
115   This will return an allocated structure
116 ****************************************************************************/
117
118 struct passwd *Get_Pwnam_alloc(TALLOC_CTX *mem_ctx, const char *user)
119 {
120         fstring user2;
121         struct passwd *ret;
122
123         if ( *user == '\0' ) {
124                 DEBUG(10,("Get_Pwnam: empty username!\n"));
125                 return NULL;
126         }
127
128         fstrcpy(user2, user);
129
130         DEBUG(5,("Finding user %s\n", user));
131
132         ret = Get_Pwnam_internals(mem_ctx, user, user2);
133         
134         return ret;  
135 }
136
137 /****************************************************************************
138  Get_Pwnam wrapper without modification.
139   NOTE: This with NOT modify 'user'! 
140 ****************************************************************************/
141
142 struct passwd *Get_Pwnam(const char *user)
143 {
144         struct passwd *ret;
145
146         ret = Get_Pwnam_alloc(NULL, user);
147         
148         /* This call used to just return the 'passwd' static buffer.
149            This could then have accidental reuse implications, so 
150            we now malloc a copy, and free it in the next use.
151
152            This should cause the (ab)user to segfault if it 
153            uses an old struct. 
154            
155            This is better than useing the wrong data in security
156            critical operations.
157
158            The real fix is to make the callers free the returned 
159            malloc'ed data.
160         */
161
162         if (Get_Pwnam_ret) {
163                 TALLOC_FREE(Get_Pwnam_ret);
164         }
165         
166         Get_Pwnam_ret = ret;
167
168         return ret;  
169 }
170
171 /* The functions below have been taken from password.c and slightly modified */
172 /****************************************************************************
173  Apply a function to upper/lower case combinations
174  of a string and return true if one of them returns true.
175  Try all combinations with N uppercase letters.
176  offset is the first char to try and change (start with 0)
177  it assumes the string starts lowercased
178 ****************************************************************************/
179
180 static struct passwd *uname_string_combinations2(char *s, TALLOC_CTX *mem_ctx,
181                                                  int offset,
182                                                  struct passwd *(*fn)(TALLOC_CTX *mem_ctx, const char *),
183                                                  int N)
184 {
185         ssize_t len = (ssize_t)strlen(s);
186         int i;
187         struct passwd *ret;
188
189         if (N <= 0 || offset >= len)
190                 return(fn(mem_ctx, s));
191
192         for (i=offset;i<(len-(N-1));i++) {
193                 char c = s[i];
194                 if (!islower_ascii((int)c))
195                         continue;
196                 s[i] = toupper_ascii(c);
197                 ret = uname_string_combinations2(s, mem_ctx, i+1, fn, N-1);
198                 if(ret)
199                         return(ret);
200                 s[i] = c;
201         }
202         return(NULL);
203 }
204
205 /****************************************************************************
206  Apply a function to upper/lower case combinations
207  of a string and return true if one of them returns true.
208  Try all combinations with up to N uppercase letters.
209  offset is the first char to try and change (start with 0)
210  it assumes the string starts lowercased
211 ****************************************************************************/
212
213 static struct passwd * uname_string_combinations(char *s, TALLOC_CTX *mem_ctx,
214                                                  struct passwd * (*fn)(TALLOC_CTX *mem_ctx, const char *),
215                                                  int N)
216 {
217         int n;
218         struct passwd *ret;
219
220         for (n=1;n<=N;n++) {
221                 ret = uname_string_combinations2(s,mem_ctx,0,fn,n);
222                 if(ret)
223                         return(ret);
224         }  
225         return(NULL);
226 }
227