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;
24 extern DOM_SID global_machine_sid;
26 /* internal functions */
27 static struct passwd *uname_string_combinations(char *s, struct passwd * (*fn) (char *), int N);
28 static struct passwd *uname_string_combinations2(char *s, int offset, struct passwd * (*fn) (char *), int N);
30 /****************************************************************************
31 get a users home directory.
32 ****************************************************************************/
33 char *get_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 ********************************************************************/
54 BOOL map_username(char *user)
56 static BOOL initialised=False;
57 static fstring last_from,last_to;
59 char *mapfile = lp_username_map();
70 *last_from = *last_to = 0;
74 if (strequal(user,last_to))
77 if (strequal(user,last_from)) {
78 DEBUG(3,("Mapped user %s to %s\n",user,last_to));
79 fstrcpy(user,last_to);
83 f = fopen(mapfile,"r");
85 DEBUG(0,("can't open username map %s\n",mapfile));
89 DEBUG(4,("Scanning username map %s\n",mapfile));
91 while((s=fgets_slash(buf,sizeof(buf),f))!=NULL) {
93 char *dosname = strchr(unixname,'=');
94 BOOL return_if_mapped = False;
101 while (isspace(*unixname))
103 if ('!' == *unixname) {
104 return_if_mapped = True;
106 while (*unixname && isspace(*unixname))
110 if (!*unixname || strchr("#;",*unixname))
114 int l = strlen(unixname);
115 while (l && isspace(unixname[l-1])) {
121 if (strchr(dosname,'*') || user_in_list(user,dosname)) {
122 DEBUG(3,("Mapped user %s to %s\n",user,unixname));
123 fstrcpy(last_from,user);
124 sscanf(unixname,"%s",user);
125 fstrcpy(last_to,user);
126 if(return_if_mapped) {
136 * Username wasn't mapped. Setup the last_from and last_to
137 * as an optimization so that we don't scan the file again
140 fstrcpy(last_from,user);
141 fstrcpy(last_to,user);
146 /****************************************************************************
148 ****************************************************************************/
149 static struct passwd *_Get_Pwnam(char *s)
157 struct passwd_adjunct *pwret;
158 pwret = getpwanam(s);
161 free(ret->pw_passwd);
162 ret->pw_passwd = pwret->pwa_passwd;
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)
181 int usernamelevel = lp_usernamelevel();
185 if (!user || !(*user))
188 StrnCpy(user2,user,sizeof(user2)-1);
194 ret = _Get_Pwnam(user);
195 if (ret) return(ret);
198 ret = _Get_Pwnam(user);
199 if (ret) return(ret);
202 ret = _Get_Pwnam(user);
203 if (ret) return(ret);
205 /* try with first letter capitalised */
206 if (strlen(user) > 1)
208 ret = _Get_Pwnam(user);
209 if (ret) return(ret);
211 /* try with last letter capitalised */
213 last_char = strlen(user)-1;
214 user[last_char] = toupper(user[last_char]);
215 DEBUG(3, ("Trying username %s\n", user));
216 ret = _Get_Pwnam(user);
217 if (ret) return(ret);
219 /* try all combinations up to usernamelevel */
221 ret = uname_string_combinations(user, _Get_Pwnam, usernamelevel);
222 if (ret) return(ret);
230 /****************************************************************************
231 check if a user is in a user list
232 ****************************************************************************/
233 BOOL user_in_list(char *user,char *list)
238 while (next_token(&p,tok,LIST_SEP))
240 if (strequal(user,tok))
246 static char *mydomain = NULL;
248 yp_get_default_domain(&mydomain);
252 DEBUG(5,("Unable to get default yp domain\n"));
257 DEBUG(5,("looking for user %s of domain %s in netgroup %s\n",
258 user, mydomain, &tok[1]));
259 DEBUG(5,("innetgr is %s\n",
260 innetgr(&tok[1], (char *) 0, user, mydomain)
261 ? "TRUE" : "FALSE"));
263 if (innetgr(&tok[1], (char *)0, user, mydomain))
275 struct passwd *pass = Get_Pwnam(user,False);
278 gptr = getgrgid(pass->pw_gid);
279 if (gptr && strequal(gptr->gr_name,&tok[1]))
283 gptr = (struct group *)getgrnam(&tok[1]);
287 member = gptr->gr_mem;
288 while (member && *member)
290 if (strequal(*member,user))
301 /* The functions below have been taken from password.c and slightly modified */
302 /****************************************************************************
303 apply a function to upper/lower case combinations
304 of a string and return true if one of them returns true.
305 try all combinations with N uppercase letters.
306 offset is the first char to try and change (start with 0)
307 it assumes the string starts lowercased
308 ****************************************************************************/
309 static struct passwd *uname_string_combinations2(char *s,int offset,struct passwd *(*fn)(char *),int N)
315 #ifdef PASSWORD_LENGTH
316 len = MIN(len,PASSWORD_LENGTH);
319 if (N <= 0 || offset >= len)
323 for (i=offset;i<(len-(N-1));i++)
327 if (!islower(c)) continue;
329 ret = uname_string_combinations2(s,i+1,fn,N-1);
336 /****************************************************************************
337 apply a function to upper/lower case combinations
338 of a string and return true if one of them returns true.
339 try all combinations with up to N uppercase letters.
340 offset is the first char to try and change (start with 0)
341 it assumes the string starts lowercased
342 ****************************************************************************/
343 static struct passwd * uname_string_combinations(char *s,struct passwd * (*fn)(char *),int N)
350 ret = uname_string_combinations2(s,0,fn,n);
357 /* JRATEST - under construction. */
358 /**************************************************************************
359 Groupname map functionality. The code loads a groupname map file and
360 (currently) loads it into a linked list. This is slow and memory
361 hungry, but can be changed into a more efficient storage format
362 if the demands on it become excessive.
363 ***************************************************************************/
365 typedef struct groupname_map {
372 } groupname_map_entry;
374 static ubi_slList groupname_map_list;
376 /**************************************************************************
377 Delete all the entries in the groupname map list.
378 ***************************************************************************/
380 static void delete_groupname_map_list(void)
382 groupname_map_entry *gmep;
384 while((gmep = (groupname_map_entry *)ubi_slRemHead( groupname_map_list )) != NULL) {
385 if(gmep->windows_name)
386 free(gmep->windows_name);
388 free(gmep->unix_name);
393 /**************************************************************************
394 Load a groupname map file. Sets last accessed timestamp.
395 ***************************************************************************/
397 void load_groupname_map(void)
399 static time_t groupmap_file_last_modified = (time_t)0;
400 static BOOL initialized = False;
401 char *groupname_map_file = lp_groupname_map();
408 ubi_slInsert( &groupname_map_list );
412 if (!*groupname_map_file)
415 if(stat(groupname_map_file, &st) != 0) {
416 DEBUG(0, ("load_groupname_map: Unable to stat file %s. Error was %s\n",
417 groupname_map_file, strerror(errno) ));
422 * Check if file has changed.
424 if( st.st_mtime <= groupmap_file_last_modified)
427 groupmap_file_last_modified = st.st_mtime;
433 fp = fopen(groupname_map_file,"r");
435 DEBUG(0,("load_groupname_map: can't open groupname map %s. Error was %s\n",
436 mapfile, strerror(errno)));
441 * Throw away any previous list.
443 delete_groupname_map_list();
445 DEBUG(4,("load_groupname_map: Scanning groupname map %s\n",groupname_map_file));
447 while((s=fgets_slash(buf,sizeof(buf),fp))!=NULL) {
449 pstring windows_name;
453 DEBUG(10,("load_groupname_map: Read line |%s|\n", s);
455 if (!*s || strchr("#;",*s))
458 if(!next_token(&s,unixname, "\t\n\r="))
461 if(!next_token(&s,windows_name, "\t\n\r="))
464 trim_string(unixname, " ", " ");
465 trim_string(windows_name, " ", " ");
474 * Attempt to get the unix gid_t for this name.
477 DEBUG(5,("load_groupname_map: Attempting to find unix group %s.\n",
480 if((gptr = (struct group *)getgrnam(unixname)) == NULL) {
481 DEBUG(0,("load_groupname_map: getgrnam for group %s failed.\
482 Error was %s.\n", unixname, strerror(errno) ));
487 * Now map to an NT SID.
490 if(!lookup_wellknown_sid_from_name(windows_name, &tmp_sid)) {
492 * It's not a well known name, convert the UNIX gid_t
493 * to a rid within this domain SID.
495 tmp_sid = global_machine_sid;
496 tmp_sid.sub_auths[tmp_sid.num_auths++] =
497 pdb_gid_to_group_rid((gid_t)gptr->gr_gid);
501 * Create the list entry and add it onto the list.