2 Unix SMB/Netbios implementation.
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.
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)
35 static pstring home_dir;
37 pass = Get_Pwnam(user, False);
39 if (pass == NULL || pass->pw_dir == NULL) return(NULL);
41 pstrcpy(home_dir, pass->pw_dir);
42 DEBUG(10,("get_home_dir: returning %s for user %s\n", home_dir, user));
47 /*******************************************************************
48 map a username from a dos name to a unix name by looking in the username
49 map. Note that this modifies the name in place.
50 This is the main function that should be called *once* on
51 any incoming or new username - in order to canonicalize the name.
52 This is being done to de-couple the case conversions from the user mapping
53 function. Previously, the map_username was being called
54 every time Get_Pwnam was called.
55 Returns True if username was changed, false otherwise.
56 ********************************************************************/
57 BOOL map_username(char *user)
59 static BOOL initialised=False;
60 static fstring last_from,last_to;
62 char *mapfile = lp_username_map();
65 BOOL mapped_user = False;
74 *last_from = *last_to = 0;
78 if (strequal(user,last_to))
81 if (strequal(user,last_from)) {
82 DEBUG(3,("Mapped user %s to %s\n",user,last_to));
83 fstrcpy(user,last_to);
87 f = sys_fopen(mapfile,"r");
89 DEBUG(0,("can't open username map %s\n",mapfile));
93 DEBUG(4,("Scanning username map %s\n",mapfile));
95 while((s=fgets_slash(buf,sizeof(buf),f))!=NULL) {
97 char *dosname = strchr(unixname,'=');
98 BOOL return_if_mapped = False;
105 while (isspace(*unixname))
107 if ('!' == *unixname) {
108 return_if_mapped = True;
110 while (*unixname && isspace(*unixname))
114 if (!*unixname || strchr("#;",*unixname))
118 int l = strlen(unixname);
119 while (l && isspace(unixname[l-1])) {
125 if (strchr(dosname,'*') || user_in_list(user,dosname)) {
126 DEBUG(3,("Mapped user %s to %s\n",user,unixname));
128 fstrcpy(last_from,user);
129 sscanf(unixname,"%s",user);
130 fstrcpy(last_to,user);
131 if(return_if_mapped) {
141 * Setup the last_from and last_to as an optimization so
142 * that we don't scan the file again for the same user.
144 fstrcpy(last_from,user);
145 fstrcpy(last_to,user);
150 /****************************************************************************
152 ****************************************************************************/
153 static struct passwd *_Get_Pwnam(char *s)
160 #ifdef HAVE_GETPWANAM
161 struct passwd_adjunct *pwret;
162 pwret = getpwanam(s);
165 free(ret->pw_passwd);
166 ret->pw_passwd = pwret->pwa_passwd;
176 /****************************************************************************
177 a wrapper for getpwnam() that tries with all lower and all upper case
178 if the initial name fails. Also tried with first letter capitalised
179 Note that this can change user!
180 ****************************************************************************/
181 struct passwd *Get_Pwnam(char *user,BOOL allow_change)
185 int usernamelevel = lp_usernamelevel();
189 if (!user || !(*user))
192 StrnCpy(user2,user,sizeof(user2)-1);
198 ret = _Get_Pwnam(user);
199 if (ret) return(ret);
202 ret = _Get_Pwnam(user);
203 if (ret) return(ret);
206 ret = _Get_Pwnam(user);
207 if (ret) return(ret);
209 /* try with first letter capitalised */
210 if (strlen(user) > 1)
212 ret = _Get_Pwnam(user);
213 if (ret) return(ret);
215 /* try with last letter capitalised */
217 last_char = strlen(user)-1;
218 user[last_char] = toupper(user[last_char]);
219 ret = _Get_Pwnam(user);
220 if (ret) return(ret);
222 /* try all combinations up to usernamelevel */
224 ret = uname_string_combinations(user, _Get_Pwnam, usernamelevel);
225 if (ret) return(ret);
233 /****************************************************************************
234 check if a user is in a netgroup user list
235 ****************************************************************************/
236 static BOOL user_in_netgroup_list(char *user,char *ngname)
239 static char *mydomain = NULL;
240 if (mydomain == NULL)
241 yp_get_default_domain(&mydomain);
245 DEBUG(5,("Unable to get default yp domain\n"));
249 DEBUG(5,("looking for user %s of domain %s in netgroup %s\n",
250 user, mydomain, ngname));
251 DEBUG(5,("innetgr is %s\n",
252 innetgr(ngname, NULL, user, mydomain)
253 ? "TRUE" : "FALSE"));
255 if (innetgr(ngname, NULL, user, mydomain))
258 #endif /* HAVE_NETGROUP */
262 /****************************************************************************
263 check if a user is in a UNIX user list
264 ****************************************************************************/
265 static BOOL user_in_group_list(char *user,char *gname)
270 struct passwd *pass = Get_Pwnam(user,False);
274 gptr = getgrgid(pass->pw_gid);
275 if (gptr && strequal(gptr->gr_name,gname))
279 gptr = (struct group *)getgrnam(gname);
283 member = gptr->gr_mem;
284 while (member && *member)
286 if (strequal(*member,user))
291 #endif /* HAVE_GETGRNAM */
295 /****************************************************************************
296 check if a user is in a user list - can check combinations of UNIX
298 ****************************************************************************/
299 BOOL user_in_list(char *user,char *list)
304 while (next_token(&p,tok,LIST_SEP, sizeof(tok)))
307 * Check raw username.
309 if (strequal(user,tok))
313 * Now check to see if any combination
314 * of UNIX and netgroups has been specified.
320 * Old behaviour. Check netgroup list
321 * followed by UNIX list.
323 if(user_in_netgroup_list(user,&tok[1]))
325 if(user_in_group_list(user,&tok[1]))
328 else if (*tok == '+')
333 * Search UNIX list followed by netgroup.
335 if(user_in_group_list(user,&tok[2]))
337 if(user_in_netgroup_list(user,&tok[2]))
343 * Just search UNIX list.
345 if(user_in_group_list(user,&tok[1]))
349 else if (*tok == '&')
354 * Search netgroup list followed by UNIX list.
356 if(user_in_netgroup_list(user,&tok[2]))
358 if(user_in_group_list(user,&tok[2]))
364 * Just search netgroup list.
366 if(user_in_netgroup_list(user,&tok[1]))
374 /* The functions below have been taken from password.c and slightly modified */
375 /****************************************************************************
376 apply a function to upper/lower case combinations
377 of a string and return true if one of them returns true.
378 try all combinations with N uppercase letters.
379 offset is the first char to try and change (start with 0)
380 it assumes the string starts lowercased
381 ****************************************************************************/
382 static struct passwd *uname_string_combinations2(char *s,int offset,struct passwd *(*fn)(char *),int N)
388 #ifdef PASSWORD_LENGTH
389 len = MIN(len,PASSWORD_LENGTH);
392 if (N <= 0 || offset >= len)
396 for (i=offset;i<(len-(N-1));i++)
400 if (!islower(c)) continue;
402 ret = uname_string_combinations2(s,i+1,fn,N-1);
409 /****************************************************************************
410 apply a function to upper/lower case combinations
411 of a string and return true if one of them returns true.
412 try all combinations with up to N uppercase letters.
413 offset is the first char to try and change (start with 0)
414 it assumes the string starts lowercased
415 ****************************************************************************/
416 static struct passwd * uname_string_combinations(char *s,struct passwd * (*fn)(char *),int N)
423 ret = uname_string_combinations2(s,0,fn,n);