a78a344eb89d47d5ddc4a340d6b74163597115c4
[bbaumbach/samba-autobuild/.git] / source3 / lib / username.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Username handling
5    Copyright (C) Andrew Tridgell 1992-1997
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 2 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 extern int DEBUGLEVEL;
24
25 /* internal functions - modified versions of the ones in password.c */
26 static struct passwd *uname_string_combinations(char *s, struct passwd * (*fn) (), int N);
27 static struct passwd *uname_string_combinations2(char *s, int offset, struct passwd * (*fn) (), int N);
28
29 /****************************************************************************
30 get a users home directory. tries as-is then lower case
31 ****************************************************************************/
32 char *get_home_dir(char *user)
33 {
34   static struct passwd *pass;
35
36   pass = Get_Pwnam(user,False);
37
38   if (!pass) return(NULL);
39   return(pass->pw_dir);      
40 }
41
42
43 /*******************************************************************
44 map a username from a dos name to a unix name by looking in the username
45 map
46 ********************************************************************/
47 void map_username(char *user)
48 {
49   static int depth=0;
50   static BOOL initialised=False;
51   static fstring last_from,last_to;
52   FILE *f;
53   char *s;
54   char *mapfile = lp_username_map();
55   if (!*mapfile || depth) return;
56
57   if (!*user) return;
58
59   if (!initialised) {
60     *last_from = *last_to = 0;
61     initialised = True;
62   }
63
64   if (strequal(user,last_to)) return;
65
66   if (strequal(user,last_from)) {
67     DEBUG(3,("Mapped user %s to %s\n",user,last_to));
68     strcpy(user,last_to);
69     return;
70   }
71   
72   f = fopen(mapfile,"r");
73   if (!f) {
74     DEBUG(0,("can't open username map %s\n",mapfile));
75     return;
76   }
77
78   DEBUG(4,("Scanning username map %s\n",mapfile));
79
80   depth++;
81
82   for (; (s=fgets_slash(NULL,80,f)); free(s)) {
83     char *unixname = s;
84     char *dosname = strchr(unixname,'=');
85
86     if (!dosname) continue;
87     *dosname++ = 0;
88
89     while (isspace(*unixname)) unixname++;
90     if (!*unixname || strchr("#;",*unixname)) continue;
91
92     {
93       int l = strlen(unixname);
94       while (l && isspace(unixname[l-1])) {
95         unixname[l-1] = 0;
96         l--;
97       }
98     }
99
100     if (strchr(dosname,'*') || user_in_list(user,dosname)) {
101       DEBUG(3,("Mapped user %s to %s\n",user,unixname));
102       StrnCpy(last_from,user,sizeof(last_from)-1);
103       sscanf(unixname,"%s",user);
104       StrnCpy(last_to,user,sizeof(last_to)-1);
105     }
106   }
107
108   fclose(f);
109
110   depth--;
111 }
112
113 /****************************************************************************
114 internals of Get_Pwnam wrapper
115 ****************************************************************************/
116 static struct passwd *_Get_Pwnam(char *s)
117 {
118   struct passwd *ret;
119
120   ret = getpwnam(s);
121   if (ret)
122     {
123 #ifdef GETPWANAM
124       struct passwd_adjunct *pwret;
125       pwret = getpwanam(s);
126       if (pwret)
127         {
128           free(ret->pw_passwd);
129           ret->pw_passwd = pwret->pwa_passwd;
130         }
131 #endif
132
133     }
134
135   return(ret);
136 }
137
138
139 /****************************************************************************
140 a wrapper for getpwnam() that tries with all lower and all upper case 
141 if the initial name fails. Also tried with first letter capitalised
142 Note that this changes user!
143 ****************************************************************************/
144 struct passwd *Get_Pwnam(char *user,BOOL allow_change)
145 {
146   fstring user2;
147   int last_char;
148   int usernamelevel = lp_usernamelevel();
149
150   struct passwd *ret;  
151
152   if (!user || !(*user))
153     return(NULL);
154
155   StrnCpy(user2,user,sizeof(user2)-1);
156
157   if (!allow_change) {
158     user = &user2[0];
159   }
160
161   map_username(user);
162
163   ret = _Get_Pwnam(user);
164   if (ret) return(ret);
165
166   strlower(user);
167   ret = _Get_Pwnam(user);
168   if (ret)  return(ret);
169
170   strupper(user);
171   ret = _Get_Pwnam(user);
172   if (ret) return(ret);
173
174   /* try with first letter capitalised */
175   if (strlen(user) > 1)
176     strlower(user+1);  
177   ret = _Get_Pwnam(user);
178   if (ret) return(ret);
179
180   /* try with last letter capitalised */
181   strlower(user);
182   last_char = strlen(user)-1;
183   user[last_char] = toupper(user[last_char]);
184   DEBUG(3, ("Trying username %s\n", user));
185   ret = _Get_Pwnam(user);
186   if (ret) return(ret);
187
188   /* try all combinations up to usernamelevel */
189   strlower(user);
190   ret = uname_string_combinations(user, _Get_Pwnam, usernamelevel);
191   if (ret) return(ret);
192
193   if (allow_change)
194     strcpy(user,user2);
195
196   return(NULL);
197 }
198
199
200 /****************************************************************************
201 check if a user is in a user list
202 ****************************************************************************/
203 BOOL user_in_list(char *user,char *list)
204 {
205   pstring tok;
206   char *p=list;
207
208   while (next_token(&p,tok,LIST_SEP))
209     {
210       if (strequal(user,tok))
211         return(True);
212
213 #ifdef NETGROUP
214       if (*tok == '@')
215         {
216           static char *mydomain = NULL;
217           if (mydomain == 0)
218             yp_get_default_domain(&mydomain);
219
220           if(mydomain == 0)
221             {
222               DEBUG(5,("Unable to get default yp domain\n"));
223             }
224           else
225             {
226           
227               DEBUG(5,("looking for user %s of domain %s in netgroup %s\n",
228                    user, mydomain, &tok[1]));
229               DEBUG(5,("innetgr is %s\n",
230                    innetgr(&tok[1], (char *) 0, user, mydomain)
231                    ? "TRUE" : "FALSE"));
232           
233               if (innetgr(&tok[1], (char *)0, user, mydomain))
234                 return (True);
235             }
236         }
237 #endif
238
239
240 #if HAVE_GETGRNAM 
241       if (*tok == '@')
242         {
243           struct group *gptr;
244           char **member;  
245           struct passwd *pass = Get_Pwnam(user,False);
246
247           if (pass) { 
248             gptr = getgrgid(pass->pw_gid);
249             if (gptr && strequal(gptr->gr_name,&tok[1]))
250               return(True); 
251           } 
252
253           gptr = (struct group *)getgrnam(&tok[1]);
254
255           if (gptr)
256             {
257               member = gptr->gr_mem;
258               while (member && *member)
259                 {
260                   if (strequal(*member,user))
261                     return(True);
262                   member++;
263                 }
264             }
265         }             
266 #endif
267     }
268   return(False);
269 }
270
271 /* The functions below have been taken from password.c and slightly modified */
272 /****************************************************************************
273 apply a function to upper/lower case combinations
274 of a string and return true if one of them returns true.
275 try all combinations with N uppercase letters.
276 offset is the first char to try and change (start with 0)
277 it assumes the string starts lowercased
278 ****************************************************************************/
279 static struct passwd *uname_string_combinations2(char *s,int offset,struct passwd *(*fn)(),int N)
280 {
281   int len = strlen(s);
282   int i;
283   struct passwd *ret;
284
285 #ifdef PASSWORD_LENGTH
286   len = MIN(len,PASSWORD_LENGTH);
287 #endif
288
289   if (N <= 0 || offset >= len)
290     return(fn(s));
291
292
293   for (i=offset;i<(len-(N-1));i++)
294
295     {
296       char c = s[i];
297       if (!islower(c)) continue;
298       s[i] = toupper(c);
299       ret = uname_string_combinations2(s,i+1,fn,N-1);
300       if(ret) return(ret);
301       s[i] = c;
302     }
303   return(NULL);
304 }
305
306 /****************************************************************************
307 apply a function to upper/lower case combinations
308 of a string and return true if one of them returns true.
309 try all combinations with up to N uppercase letters.
310 offset is the first char to try and change (start with 0)
311 it assumes the string starts lowercased
312 ****************************************************************************/
313 static struct passwd * uname_string_combinations(char *s,struct passwd * (*fn)(),int N)
314 {
315   int n;
316   struct passwd *ret;
317
318   for (n=1;n<=N;n++)
319   {
320     ret = uname_string_combinations2(s,0,fn,n);
321     if(ret) return(ret);
322   }
323   return(NULL);
324 }