don't list the IPC$ share in directory listings (it causes infinite
[Samba/gbeck.git] / source / lib / username.c
blobf56f7efce2efc0ade7ac071bb3a8e29a8c7075b7
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 Username handling
5 Copyright (C) Andrew Tridgell 1992-1998
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 2 of the License, or
10 (at your option) any later version.
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.
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.
22 #include "includes.h"
23 extern int DEBUGLEVEL;
25 /* internal functions */
26 static struct passwd *uname_string_combinations(char *s, struct passwd * (*fn) (char *), int N);
27 static struct passwd *uname_string_combinations2(char *s, int offset, struct passwd * (*fn) (char *), int N);
29 /****************************************************************************
30 get a users home directory.
31 ****************************************************************************/
32 char *get_home_dir(char *user)
34 static struct passwd *pass;
36 pass = Get_Pwnam(user, False);
38 if (!pass) return(NULL);
39 return(pass->pw_dir);
43 /*******************************************************************
44 map a username from a dos name to a unix name by looking in the username
45 map. Note that this modifies the name in place.
46 This is the main function that should be called *once* on
47 any incoming or new username - in order to canonicalize the name.
48 This is being done to de-couple the case conversions from the user mapping
49 function. Previously, the map_username was being called
50 every time Get_Pwnam was called.
51 Returns True if username was changed, false otherwise.
52 ********************************************************************/
53 BOOL map_username(char *user)
55 static BOOL initialised=False;
56 static fstring last_from,last_to;
57 FILE *f;
58 char *mapfile = lp_username_map();
59 char *s;
60 pstring buf;
61 BOOL mapped_user = False;
63 if (!*user)
64 return False;
66 if (!*mapfile)
67 return False;
69 if (!initialised) {
70 *last_from = *last_to = 0;
71 initialised = True;
74 if (strequal(user,last_to))
75 return False;
77 if (strequal(user,last_from)) {
78 DEBUG(3,("Mapped user %s to %s\n",user,last_to));
79 fstrcpy(user,last_to);
80 return True;
83 f = fopen(mapfile,"r");
84 if (!f) {
85 DEBUG(0,("can't open username map %s\n",mapfile));
86 return False;
89 DEBUG(4,("Scanning username map %s\n",mapfile));
91 while((s=fgets_slash(buf,sizeof(buf),f))!=NULL) {
92 char *unixname = s;
93 char *dosname = strchr(unixname,'=');
94 BOOL return_if_mapped = False;
96 if (!dosname)
97 continue;
99 *dosname++ = 0;
101 while (isspace(*unixname))
102 unixname++;
103 if ('!' == *unixname) {
104 return_if_mapped = True;
105 unixname++;
106 while (*unixname && isspace(*unixname))
107 unixname++;
110 if (!*unixname || strchr("#;",*unixname))
111 continue;
114 int l = strlen(unixname);
115 while (l && isspace(unixname[l-1])) {
116 unixname[l-1] = 0;
117 l--;
121 if (strchr(dosname,'*') || user_in_list(user,dosname)) {
122 DEBUG(3,("Mapped user %s to %s\n",user,unixname));
123 mapped_user = True;
124 fstrcpy(last_from,user);
125 sscanf(unixname,"%s",user);
126 fstrcpy(last_to,user);
127 if(return_if_mapped) {
128 fclose(f);
129 return True;
134 fclose(f);
137 * Setup the last_from and last_to as an optimization so
138 * that we don't scan the file again for the same user.
140 fstrcpy(last_from,user);
141 fstrcpy(last_to,user);
143 return mapped_user;
146 /****************************************************************************
147 Get_Pwnam wrapper
148 ****************************************************************************/
149 static struct passwd *_Get_Pwnam(char *s)
151 struct passwd *ret;
153 ret = getpwnam(s);
154 if (ret)
156 #ifdef HAVE_GETPWANAM
157 struct passwd_adjunct *pwret;
158 pwret = getpwanam(s);
159 if (pwret)
161 free(ret->pw_passwd);
162 ret->pw_passwd = pwret->pwa_passwd;
164 #endif
168 return(ret);
172 /****************************************************************************
173 a wrapper for getpwnam() that tries with all lower and all upper case
174 if the initial name fails. Also tried with first letter capitalised
175 Note that this can change user!
176 ****************************************************************************/
177 struct passwd *Get_Pwnam(char *user,BOOL allow_change)
179 fstring user2;
180 int last_char;
181 int usernamelevel = lp_usernamelevel();
183 struct passwd *ret;
185 if (!user || !(*user))
186 return(NULL);
188 StrnCpy(user2,user,sizeof(user2)-1);
190 if (!allow_change) {
191 user = &user2[0];
194 ret = _Get_Pwnam(user);
195 if (ret) return(ret);
197 strlower(user);
198 ret = _Get_Pwnam(user);
199 if (ret) return(ret);
201 strupper(user);
202 ret = _Get_Pwnam(user);
203 if (ret) return(ret);
205 /* try with first letter capitalised */
206 if (strlen(user) > 1)
207 strlower(user+1);
208 ret = _Get_Pwnam(user);
209 if (ret) return(ret);
211 /* try with last letter capitalised */
212 strlower(user);
213 last_char = strlen(user)-1;
214 user[last_char] = toupper(user[last_char]);
215 ret = _Get_Pwnam(user);
216 if (ret) return(ret);
218 /* try all combinations up to usernamelevel */
219 strlower(user);
220 ret = uname_string_combinations(user, _Get_Pwnam, usernamelevel);
221 if (ret) return(ret);
223 if (allow_change)
224 fstrcpy(user,user2);
226 return(NULL);
229 /****************************************************************************
230 check if a user is in a netgroup user list
231 ****************************************************************************/
232 static BOOL user_in_netgroup_list(char *user,char *ngname)
234 #ifdef HAVE_NETGROUP
235 static char *mydomain = NULL;
236 if (mydomain == NULL)
237 yp_get_default_domain(&mydomain);
239 if(mydomain == NULL)
241 DEBUG(5,("Unable to get default yp domain\n"));
243 else
245 DEBUG(5,("looking for user %s of domain %s in netgroup %s\n",
246 user, mydomain, ngname));
247 DEBUG(5,("innetgr is %s\n",
248 innetgr(ngname, NULL, user, mydomain)
249 ? "TRUE" : "FALSE"));
251 if (innetgr(ngname, NULL, user, mydomain))
252 return (True);
254 #endif /* HAVE_NETGROUP */
255 return False;
258 /****************************************************************************
259 check if a user is in a UNIX user list
260 ****************************************************************************/
261 static BOOL user_in_group_list(char *user,char *gname)
263 #ifdef HAVE_GETGRNAM
264 struct group *gptr;
265 char **member;
266 struct passwd *pass = Get_Pwnam(user,False);
268 if (pass)
270 gptr = getgrgid(pass->pw_gid);
271 if (gptr && strequal(gptr->gr_name,gname))
272 return(True);
275 gptr = (struct group *)getgrnam(gname);
277 if (gptr)
279 member = gptr->gr_mem;
280 while (member && *member)
282 if (strequal(*member,user))
283 return(True);
284 member++;
287 #endif /* HAVE_GETGRNAM */
288 return False;
291 /****************************************************************************
292 check if a user is in a user list - can check combinations of UNIX
293 and netgroup lists.
294 ****************************************************************************/
295 BOOL user_in_list(char *user,char *list)
297 pstring tok;
298 char *p=list;
300 while (next_token(&p,tok,LIST_SEP, sizeof(tok)))
303 * Check raw username.
305 if (strequal(user,tok))
306 return(True);
309 * Now check to see if any combination
310 * of UNIX and netgroups has been specified.
313 if(*tok == '@')
316 * Old behaviour. Check netgroup list
317 * followed by UNIX list.
319 if(user_in_netgroup_list(user,&tok[1]))
320 return True;
321 if(user_in_group_list(user,&tok[1]))
322 return True;
324 else if (*tok == '+')
326 if(tok[1] == '&')
329 * Search UNIX list followed by netgroup.
331 if(user_in_group_list(user,&tok[2]))
332 return True;
333 if(user_in_netgroup_list(user,&tok[2]))
334 return True;
336 else
339 * Just search UNIX list.
341 if(user_in_group_list(user,&tok[1]))
342 return True;
345 else if (*tok == '&')
347 if(tok[1] == '&')
350 * Search netgroup list followed by UNIX list.
352 if(user_in_netgroup_list(user,&tok[2]))
353 return True;
354 if(user_in_group_list(user,&tok[2]))
355 return True;
357 else
360 * Just search netgroup list.
362 if(user_in_netgroup_list(user,&tok[1]))
363 return True;
367 return(False);
370 /* The functions below have been taken from password.c and slightly modified */
371 /****************************************************************************
372 apply a function to upper/lower case combinations
373 of a string and return true if one of them returns true.
374 try all combinations with N uppercase letters.
375 offset is the first char to try and change (start with 0)
376 it assumes the string starts lowercased
377 ****************************************************************************/
378 static struct passwd *uname_string_combinations2(char *s,int offset,struct passwd *(*fn)(char *),int N)
380 int len = strlen(s);
381 int i;
382 struct passwd *ret;
384 #ifdef PASSWORD_LENGTH
385 len = MIN(len,PASSWORD_LENGTH);
386 #endif
388 if (N <= 0 || offset >= len)
389 return(fn(s));
392 for (i=offset;i<(len-(N-1));i++)
395 char c = s[i];
396 if (!islower(c)) continue;
397 s[i] = toupper(c);
398 ret = uname_string_combinations2(s,i+1,fn,N-1);
399 if(ret) return(ret);
400 s[i] = c;
402 return(NULL);
405 /****************************************************************************
406 apply a function to upper/lower case combinations
407 of a string and return true if one of them returns true.
408 try all combinations with up to N uppercase letters.
409 offset is the first char to try and change (start with 0)
410 it assumes the string starts lowercased
411 ****************************************************************************/
412 static struct passwd * uname_string_combinations(char *s,struct passwd * (*fn)(char *),int N)
414 int n;
415 struct passwd *ret;
417 for (n=1;n<=N;n++)
419 ret = uname_string_combinations2(s,0,fn,n);
420 if(ret) return(ret);
422 return(NULL);