Merge of new 2.2 code into HEAD (Gerald I hate you :-) :-). Allows new SAMR
[kai/samba.git] / source3 / smbd / uid.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    uid/user handling
5    Copyright (C) Andrew Tridgell 1992-1998
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
24 extern int DEBUGLEVEL;
25
26 /* what user is current? */
27 extern struct current_user current_user;
28
29 /****************************************************************************
30  Become the guest user.
31 ****************************************************************************/
32
33 BOOL become_guest(void)
34 {
35         static struct passwd *pass=NULL;
36         
37         if (!pass)
38                 pass = Get_Pwnam(lp_guestaccount(-1),True);
39         if (!pass)
40                 return(False);
41         
42 #ifdef AIX
43         /* MWW: From AIX FAQ patch to WU-ftpd: call initgroups before 
44            setting IDs */
45         initgroups(pass->pw_name, (gid_t)pass->pw_gid);
46 #endif
47         
48         set_sec_ctx(pass->pw_uid, pass->pw_gid, 0, NULL, NULL);
49         
50         current_user.conn = NULL;
51         current_user.vuid = UID_FIELD_INVALID;
52         
53         return True;
54 }
55
56 /*******************************************************************
57  Check if a username is OK.
58 ********************************************************************/
59
60 static BOOL check_user_ok(connection_struct *conn, user_struct *vuser,int snum)
61 {
62         int i;
63         for (i=0;i<conn->uid_cache.entries;i++)
64                 if (conn->uid_cache.list[i] == vuser->uid)
65                         return(True);
66
67         if (!user_ok(vuser->user.unix_name,snum))
68                 return(False);
69
70         i = conn->uid_cache.entries % UID_CACHE_SIZE;
71         conn->uid_cache.list[i] = vuser->uid;
72
73         if (conn->uid_cache.entries < UID_CACHE_SIZE)
74                 conn->uid_cache.entries++;
75
76         return(True);
77 }
78
79 /****************************************************************************
80  Become the user of a connection number.
81 ****************************************************************************/
82
83 BOOL become_user(connection_struct *conn, uint16 vuid)
84 {
85         user_struct *vuser = get_valid_user_struct(vuid);
86         int snum;
87         gid_t gid;
88         uid_t uid;
89         char group_c;
90         BOOL must_free_token = False;
91         NT_USER_TOKEN *token = NULL;
92
93         if (!conn) {
94                 DEBUG(2,("Connection not open\n"));
95                 return(False);
96         }
97
98         /*
99          * We need a separate check in security=share mode due to vuid
100          * always being UID_FIELD_INVALID. If we don't do this then
101          * in share mode security we are *always* changing uid's between
102          * SMB's - this hurts performance - Badly.
103          */
104
105         if((lp_security() == SEC_SHARE) && (current_user.conn == conn) &&
106            (current_user.uid == conn->uid)) {
107                 DEBUG(4,("Skipping become_user - already user\n"));
108                 return(True);
109         } else if ((current_user.conn == conn) && 
110                    (vuser != 0) && (current_user.vuid == vuid) && 
111                    (current_user.uid == vuser->uid)) {
112                 DEBUG(4,("Skipping become_user - already user\n"));
113                 return(True);
114         }
115
116         snum = SNUM(conn);
117
118         if((vuser != NULL) && !check_user_ok(conn, vuser, snum))
119                 return False;
120
121         if (conn->force_user || 
122                 conn->admin_user ||
123             lp_security() == SEC_SHARE ||
124             !(vuser) || (vuser->guest)) {
125                 uid = conn->uid;
126                 gid = conn->gid;
127                 current_user.groups = conn->groups;
128                 current_user.ngroups = conn->ngroups;
129                 token = conn->nt_user_token;
130         } else {
131                 if (!vuser) {
132                         DEBUG(2,("Invalid vuid used %d\n",vuid));
133                         return(False);
134                 }
135                 uid = vuser->uid;
136                 gid = vuser->gid;
137                 current_user.ngroups = vuser->n_groups;
138                 current_user.groups  = vuser->groups;
139                 token = vuser->nt_user_token;
140         }
141
142         /*
143          * See if we should force group for this service.
144          * If so this overrides any group set in the force
145          * user code.
146          */
147
148         if((group_c = *lp_force_group(snum))) {
149                 BOOL is_guest = False;
150
151                 if(group_c == '+') {
152
153                         /*
154                          * Only force group if the user is a member of
155                          * the service group. Check the group memberships for
156                          * this user (we already have this) to
157                          * see if we should force the group.
158                          */
159
160                         int i;
161                         for (i = 0; i < current_user.ngroups; i++) {
162                                 if (current_user.groups[i] == conn->gid) {
163                                         gid = conn->gid;
164                                         break;
165                                 }
166                         }
167                 } else {
168                         gid = conn->gid;
169                 }
170
171                 /*
172                  * We've changed the group list in the token - we must
173                  * re-create it.
174                  */
175
176                 if (vuser && vuser->guest)
177                         is_guest = True;
178
179                 token = create_nt_token(uid, gid, current_user.ngroups, current_user.groups, is_guest);
180                 must_free_token = True;
181         }
182         
183         set_sec_ctx(uid, gid, current_user.ngroups, current_user.groups, token);
184
185         /*
186          * Free the new token (as set_sec_ctx copies it).
187          */
188
189         if (must_free_token)
190                 delete_nt_token(&token);
191
192         current_user.conn = conn;
193         current_user.vuid = vuid;
194
195         DEBUG(5,("become_user uid=(%d,%d) gid=(%d,%d)\n",
196                  (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
197   
198         return(True);
199 }
200
201 /****************************************************************************
202  Unbecome the user of a connection number.
203 ****************************************************************************/
204
205 BOOL unbecome_user(void )
206 {
207         set_root_sec_ctx();
208
209         DEBUG(5,("unbecome_user now uid=(%d,%d) gid=(%d,%d)\n",
210                 (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
211
212         current_user.conn = NULL;
213         current_user.vuid = UID_FIELD_INVALID;
214
215         return(True);
216 }
217
218 /****************************************************************************
219  Become the user of an authenticated connected named pipe.
220  When this is called we are currently running as the connection
221  user.
222 ****************************************************************************/
223
224 BOOL become_authenticated_pipe_user(pipes_struct *p)
225 {
226         BOOL res = push_sec_ctx();
227
228         if (!res) {
229                 return False;
230         }
231
232         set_sec_ctx(p->pipe_user.uid, p->pipe_user.gid, 
233                     p->pipe_user.ngroups, p->pipe_user.groups, p->pipe_user.nt_user_token);
234
235         return True;
236 }
237
238 /****************************************************************************
239  Unbecome the user of an authenticated connected named pipe.
240  When this is called we are running as the authenticated pipe
241  user and need to go back to being the connection user.
242 ****************************************************************************/
243
244 BOOL unbecome_authenticated_pipe_user(pipes_struct *p)
245 {
246         return pop_sec_ctx();
247 }
248
249 /* Temporarily become a root user.  Must match with unbecome_root(). */
250
251 void become_root(void)
252 {
253         push_sec_ctx();
254         set_root_sec_ctx();
255 }
256
257 /* Unbecome the root user */
258
259 void unbecome_root(void)
260 {
261         pop_sec_ctx();
262 }
263
264 /*****************************************************************
265  *THE CANONICAL* convert name to SID function.
266  Tries winbind first - then uses local lookup.
267 *****************************************************************/  
268
269 BOOL lookup_name(char *name, DOM_SID *psid, enum SID_NAME_USE *name_type)
270 {
271         extern pstring global_myname;
272         extern fstring global_myworkgroup;
273         fstring sid;
274         char *sep = lp_winbind_separator();
275
276         if (!winbind_lookup_name(name, psid, name_type)) {
277                 BOOL ret;
278
279                 DEBUG(10, ("lookup_name: winbind lookup for %s failed - trying local\n", name));
280
281                 /* If we are looking up a domain user, make sure it is
282                    for the local machine only */
283
284                 if (strchr(name, sep[0]) || strchr(name, '\\')) {
285                         fstring domain, username;
286
287                         split_domain_name(name, domain, username);
288
289                         switch (lp_server_role()) {
290                                 case ROLE_DOMAIN_PDC:
291                                 case ROLE_DOMAIN_BDC:
292                                         if (strequal(domain, global_myworkgroup))
293                                                 fstrcpy(domain, global_myname);
294                                         /* No break is deliberate here. JRA. */
295                                 default:
296                                         if (strcasecmp(global_myname, domain) != 0) {
297                                                 DEBUG(5, ("domain %s is not local\n", domain));
298                                                 return False;
299                                         }
300                         }
301
302                         ret = local_lookup_name(domain, username, psid, 
303                                                 name_type);
304                 } else {
305
306                         ret = local_lookup_name(global_myname, name, psid, 
307                                                 name_type);
308                 }
309
310                 if (ret) {
311                         DEBUG(10,
312                               ("lookup_name: (local) %s -> SID %s (type %u)\n",
313                                name, sid_to_string(sid,psid),
314                                (unsigned int)*name_type ));
315                 } else {
316                         DEBUG(10,("lookup name: (local) %s failed.\n", name));
317                 }
318
319                 return ret;
320         }
321
322                 DEBUG(10,("lookup_name (winbindd): %s -> SID %s (type %u)\n",
323                           name, sid_to_string(sid, psid), 
324                           (unsigned int)*name_type));
325         return True;
326 }
327
328 /*****************************************************************
329  *THE CANONICAL* convert SID to name function.
330  Tries winbind first - then uses local lookup.
331 *****************************************************************/  
332
333 BOOL lookup_sid(DOM_SID *sid, fstring dom_name, fstring name, enum SID_NAME_USE *name_type)
334 {
335         if (!name_type)
336                 return False;
337
338         /* Check if this is our own sid.  This should perhaps be done by
339            winbind?  For the moment handle it here. */
340
341         if (sid->num_auths == 5) {
342                 DOM_SID tmp_sid;
343                 uint32 rid;
344
345                 sid_copy(&tmp_sid, sid);
346                 sid_split_rid(&tmp_sid, &rid);
347
348                 if (sid_equal(&global_sam_sid, &tmp_sid)) {
349
350                         return map_domain_sid_to_name(&tmp_sid, dom_name) &&
351                                 local_lookup_rid(rid, name, name_type);
352                 }
353         }
354
355         if (!winbind_lookup_sid(sid, dom_name, name, name_type)) {
356                 fstring sid_str;
357                 DOM_SID tmp_sid;
358                 uint32 rid;
359
360                 DEBUG(10,("lookup_sid: winbind lookup for SID %s failed - trying local.\n", sid_to_string(sid_str, sid) ));
361
362                 sid_copy(&tmp_sid, sid);
363                 sid_split_rid(&tmp_sid, &rid);
364                 return map_domain_sid_to_name(&tmp_sid, dom_name) &&
365                                 lookup_known_rid(&tmp_sid, rid, name, name_type);
366         }
367         return True;
368 }
369
370 /*****************************************************************
371  *THE CANONICAL* convert uid_t to SID function.
372  Tries winbind first - then uses local lookup.
373  Returns SID pointer.
374 *****************************************************************/  
375
376 DOM_SID *uid_to_sid(DOM_SID *psid, uid_t uid)
377 {
378         fstring sid;
379
380         if (!winbind_uid_to_sid(psid, uid)) {
381                 DEBUG(10,("uid_to_sid: winbind lookup for uid %u failed - trying local.\n", (unsigned int)uid ));
382
383                 return local_uid_to_sid(psid, uid);
384         }
385
386         DEBUG(10,("uid_to_sid: winbindd %u -> %s\n",
387                 (unsigned int)uid, sid_to_string(sid, psid) ));
388
389         return psid;
390 }
391
392 /*****************************************************************
393  *THE CANONICAL* convert gid_t to SID function.
394  Tries winbind first - then uses local lookup.
395  Returns SID pointer.
396 *****************************************************************/  
397
398 DOM_SID *gid_to_sid(DOM_SID *psid, gid_t gid)
399 {
400         fstring sid;
401
402         if (!winbind_gid_to_sid(psid, gid)) {
403                 DEBUG(10,("gid_to_sid: winbind lookup for gid %u failed - trying local.\n", (unsigned int)gid ));
404
405                 return local_gid_to_sid(psid, gid);
406         }
407
408         DEBUG(10,("gid_to_sid: winbindd %u -> %s\n",
409                 (unsigned int)gid, sid_to_string(sid,psid) ));
410
411         return psid;
412 }
413
414 /*****************************************************************
415  *THE CANONICAL* convert SID to uid function.
416  Tries winbind first - then uses local lookup.
417  Returns True if this name is a user sid and the conversion
418  was done correctly, False if not.
419 *****************************************************************/  
420
421 BOOL sid_to_uid(DOM_SID *psid, uid_t *puid, enum SID_NAME_USE *sidtype)
422 {
423         fstring dom_name, name, sid_str;
424         enum SID_NAME_USE name_type;
425
426         *sidtype = SID_NAME_UNKNOWN;
427
428         /*
429          * First we must look up the name and decide if this is a user sid.
430          */
431
432         if (!winbind_lookup_sid(psid, dom_name, name, &name_type)) {
433                 DEBUG(10,("sid_to_uid: winbind lookup for sid %s failed - trying local.\n",
434                                 sid_to_string(sid_str, psid) ));
435
436                 return local_sid_to_uid(puid, psid, sidtype);
437         }
438
439         /*
440          * Ensure this is a user sid.
441          */
442
443         if (name_type != SID_NAME_USER) {
444                 DEBUG(10,("sid_to_uid: winbind lookup succeeded but SID is not a uid (%u)\n",
445                                 (unsigned int)name_type ));
446                 return False;
447         }
448
449         *sidtype = SID_NAME_USER;
450
451         /*
452          * Get the uid for this SID.
453          */
454
455         if (!winbind_sid_to_uid(puid, psid)) {
456                 DEBUG(10,("sid_to_uid: winbind lookup for sid %s failed.\n",
457                                 sid_to_string(sid_str, psid) ));
458                 return False;
459         }
460
461         DEBUG(10,("sid_to_uid: winbindd %s -> %u\n",
462                 sid_to_string(sid_str, psid),
463                 (unsigned int)*puid ));
464
465         return True;
466 }
467
468 /*****************************************************************
469  *THE CANONICAL* convert SID to gid function.
470  Tries winbind first - then uses local lookup.
471  Returns True if this name is a user sid and the conversion
472  was done correctly, False if not.
473 *****************************************************************/  
474
475 BOOL sid_to_gid(DOM_SID *psid, gid_t *pgid, enum SID_NAME_USE *sidtype)
476 {
477         fstring dom_name, name, sid_str;
478         enum SID_NAME_USE name_type;
479
480         *sidtype = SID_NAME_UNKNOWN;
481
482         /*
483          * First we must look up the name and decide if this is a group sid.
484          */
485
486         if (!winbind_lookup_sid(psid, dom_name, name, &name_type)) {
487                 DEBUG(10,("sid_to_gid: winbind lookup for sid %s failed - trying local.\n",
488                                 sid_to_string(sid_str, psid) ));
489
490                 return local_sid_to_gid(pgid, psid, sidtype);
491         }
492
493         /*
494          * Ensure this is a group sid.
495          */
496
497         if ((name_type != SID_NAME_DOM_GRP) && (name_type != SID_NAME_ALIAS) && (name_type != SID_NAME_WKN_GRP)) {
498                 DEBUG(10,("sid_to_gid: winbind lookup succeeded but SID is not a known group (%u)\n",
499                                 (unsigned int)name_type ));
500
501                 return local_sid_to_gid(pgid, psid, sidtype);
502         }
503
504         *sidtype = name_type;
505
506         /*
507          * Get the gid for this SID.
508          */
509
510         if (!winbind_sid_to_gid(pgid, psid)) {
511                 DEBUG(10,("sid_to_gid: winbind lookup for sid %s failed.\n",
512                                 sid_to_string(sid_str, psid) ));
513                 return False;
514         }
515
516         DEBUG(10,("gid_to_uid: winbindd %s -> %u\n",
517                 sid_to_string(sid_str, psid),
518                 (unsigned int)*pgid ));
519
520         return True;
521 }