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 ****************************************************************************/
33 char *get_user_home_dir(char *user)
35 static struct passwd *pass;
37 pass = Get_Pwnam(user, False);
39 if (!pass) return(NULL);
44 /*******************************************************************
45 Map a username from a dos name to a unix name by looking in the username
46 map. Note that this modifies the name in place.
47 This is the main function that should be called *once* on
48 any incoming or new username - in order to canonicalize the name.
49 This is being done to de-couple the case conversions from the user mapping
50 function. Previously, the map_username was being called
51 every time Get_Pwnam was called.
52 Returns True if username was changed, false otherwise.
53 ********************************************************************/
55 BOOL map_username(char *user)
57 static BOOL initialised=False;
58 static fstring last_from,last_to;
60 char *mapfile = lp_username_map();
63 BOOL mapped_user = False;
72 *last_from = *last_to = 0;
76 if (strequal(user,last_to))
79 if (strequal(user,last_from)) {
80 DEBUG(3,("Mapped user %s to %s\n",user,last_to));
81 fstrcpy(user,last_to);
85 f = sys_fopen(mapfile,"r");
87 DEBUG(0,("can't open username map %s\n",mapfile));
91 DEBUG(4,("Scanning username map %s\n",mapfile));
93 while((s=fgets_slash(buf,sizeof(buf),f))!=NULL) {
95 char *dosname = strchr(unixname,'=');
96 BOOL return_if_mapped = False;
103 while (isspace(*unixname))
105 if ('!' == *unixname) {
106 return_if_mapped = True;
108 while (*unixname && isspace(*unixname))
112 if (!*unixname || strchr("#;",*unixname))
116 int l = strlen(unixname);
117 while (l && isspace(unixname[l-1])) {
123 if (strchr(dosname,'*') || user_in_list(user,dosname)) {
124 DEBUG(3,("Mapped user %s to %s\n",user,unixname));
126 fstrcpy(last_from,user);
127 sscanf(unixname,"%s",user);
128 fstrcpy(last_to,user);
129 if(return_if_mapped) {
139 * Setup the last_from and last_to as an optimization so
140 * that we don't scan the file again for the same user.
142 fstrcpy(last_from,user);
143 fstrcpy(last_to,user);
148 /****************************************************************************
150 ****************************************************************************/
152 static struct passwd *_Get_Pwnam(char *s)
156 ret = sys_getpwnam(s);
158 #ifdef HAVE_GETPWANAM
159 struct passwd_adjunct *pwret;
160 pwret = getpwanam(s);
161 if (pwret && pwret->pwa_passwd) {
162 pstrcpy(ret->pw_passwd,pwret->pwa_passwd);
171 /****************************************************************************
172 A wrapper for getpwnam() that tries with all lower and all upper case
173 if the initial name fails. Also tried with first letter capitalised
174 Note that this can change user!
175 ****************************************************************************/
177 struct passwd *Get_Pwnam(char *user,BOOL allow_change)
181 int usernamelevel = lp_usernamelevel();
185 if (!user || !(*user))
188 StrnCpy(user2,user,sizeof(user2)-1);
194 ret = _Get_Pwnam(user);
199 ret = _Get_Pwnam(user);
204 ret = _Get_Pwnam(user);
208 /* Try with first letter capitalised. */
209 if (strlen(user) > 1)
211 ret = _Get_Pwnam(user);
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);
223 /* Try all combinations up to usernamelevel. */
225 ret = uname_string_combinations(user, _Get_Pwnam, usernamelevel);
235 /****************************************************************************
236 Check if a user is in a netgroup user list.
237 ****************************************************************************/
239 static BOOL user_in_netgroup_list(char *user,char *ngname)
242 static char *mydomain = NULL;
243 if (mydomain == NULL)
244 yp_get_default_domain(&mydomain);
246 if(mydomain == NULL) {
247 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 winbind group.
264 ****************************************************************************/
266 static BOOL user_in_winbind_group_list(char *user,char *gname, BOOL *winbind_answered)
270 gid_t *groups = NULL;
274 *winbind_answered = False;
277 * Get the gid's that this user belongs to.
280 if ((num_groups = winbind_getgroups(user, 0, NULL)) == -1)
283 if (num_groups == 0) {
284 *winbind_answered = True;
288 if ((groups = (gid_t *)malloc(sizeof(gid_t) * num_groups )) == NULL) {
289 DEBUG(0,("user_in_winbind_group_list: malloc fail.\n"));
293 if ((num_groups = winbind_getgroups(user, num_groups, groups)) == -1) {
294 DEBUG(0,("user_in_winbind_group_list: second winbind_getgroups call \
295 failed with error %s\n", strerror(errno) ));
300 * Now we have the gid list for this user - convert the gname
301 * to a gid_t via winbind and do the comparison.
304 if (!winbind_nametogid(&gid, gname)) {
305 DEBUG(0,("user_in_winbind_group_list: winbind_lookup_name for group %s failed.\n",
310 for (i = 0; i < num_groups; i++) {
311 if (gid == groups[i]) {
317 *winbind_answered = True;
323 *winbind_answered = False;
328 /****************************************************************************
329 Check if a user is in a UNIX group.
330 ****************************************************************************/
332 static BOOL user_in_unix_group_list(char *user,char *gname)
336 struct passwd *pass = Get_Pwnam(user,False);
338 DEBUG(10,("user_in_unix_group_list: checking user %s in group %s\n", user, gname));
341 * We need to check the users primary group as this
342 * group is implicit and often not listed in the group database.
346 gptr = getgrgid(pass->pw_gid);
347 if (gptr && strequal(gptr->gr_name,gname)) {
348 DEBUG(10,("user_in_unix_group_list: group %s is primary group.\n", gname ));
353 if ((gptr = (struct group *)getgrnam(gname)) == NULL) {
354 DEBUG(10,("user_in_unix_group_list: no such group %s\n", gname ));
358 member = gptr->gr_mem;
359 while (member && *member) {
360 DEBUG(10,("user_in_unix_group_list: checking user %s against member %s\n", user, *member ));
361 if (strequal(*member,user)) {
370 /****************************************************************************
371 Check if a user is in a group list. Ask winbind first, then use UNIX.
372 ****************************************************************************/
374 BOOL user_in_group_list(char *user,char *gname)
376 BOOL winbind_answered = False;
377 BOOL ret = user_in_winbind_group_list(user, gname, &winbind_answered);
379 if (winbind_answered)
382 return user_in_unix_group_list(user, gname);
385 /****************************************************************************
386 Check if a user is in a user list - can check combinations of UNIX
388 ****************************************************************************/
390 BOOL user_in_list(char *user,char *list)
395 DEBUG(10,("user_in_list: checking user %s in list %s\n", user, list));
397 while (next_token(&p,tok,LIST_SEP, sizeof(tok))) {
399 * Check raw username.
401 if (strequal(user,tok))
405 * Now check to see if any combination
406 * of UNIX and netgroups has been specified.
411 * Old behaviour. Check netgroup list
412 * followed by UNIX list.
414 if(user_in_netgroup_list(user,&tok[1]))
416 if(user_in_group_list(user,&tok[1]))
418 } else if (*tok == '+') {
422 * Search UNIX list followed by netgroup.
424 if(user_in_group_list(user,&tok[2]))
426 if(user_in_netgroup_list(user,&tok[2]))
432 * Just search UNIX list.
435 if(user_in_group_list(user,&tok[1]))
439 } else if (*tok == '&') {
443 * Search netgroup list followed by UNIX list.
445 if(user_in_netgroup_list(user,&tok[2]))
447 if(user_in_group_list(user,&tok[2]))
451 * Just search netgroup list.
453 if(user_in_netgroup_list(user,&tok[1]))
461 /* The functions below have been taken from password.c and slightly modified */
462 /****************************************************************************
463 Apply a function to upper/lower case combinations
464 of a string and return true if one of them returns true.
465 Try all combinations with N uppercase letters.
466 offset is the first char to try and change (start with 0)
467 it assumes the string starts lowercased
468 ****************************************************************************/
470 static struct passwd *uname_string_combinations2(char *s,int offset,struct passwd *(*fn)(char *),int N)
472 ssize_t len = (ssize_t)strlen(s);
476 #ifdef PASSWORD_LENGTH
477 len = MIN(len,PASSWORD_LENGTH);
480 if (N <= 0 || offset >= len)
483 for (i=offset;i<(len-(N-1));i++) {
488 ret = uname_string_combinations2(s,i+1,fn,N-1);
496 /****************************************************************************
497 Apply a function to upper/lower case combinations
498 of a string and return true if one of them returns true.
499 Try all combinations with up to N uppercase letters.
500 offset is the first char to try and change (start with 0)
501 it assumes the string starts lowercased
502 ****************************************************************************/
504 static struct passwd * uname_string_combinations(char *s,struct passwd * (*fn)(char *),int N)
510 ret = uname_string_combinations2(s,0,fn,n);
518 /****************************************************************************
519 these wrappers allow appliance mode to work. In appliance mode the username
520 takes the form DOMAIN/user
521 ****************************************************************************/
522 struct passwd *smb_getpwnam(char *user, BOOL allow_change)
527 extern pstring global_myname;
529 pw = Get_Pwnam(user, allow_change);
532 /* if it is a domain qualified name and it isn't in our password
533 database but the domain portion matches our local machine name then
534 lookup just the username portion locally */
535 sep = lp_winbind_separator();
536 if (!sep || !*sep) sep = "\\";
537 p = strchr(user,*sep);
539 strncasecmp(global_myname, user, strlen(global_myname))==0) {
540 return Get_Pwnam(p+1, allow_change);