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