This commit was manufactured by cvs2svn to create branch 'SAMBA_3_0'.
[tprouty/samba.git] / source / smbd / uid.c
1 /* 
2    Unix SMB/CIFS implementation.
3    uid/user handling
4    Copyright (C) Andrew Tridgell 1992-1998
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22
23 /* what user is current? */
24 extern struct current_user current_user;
25
26 /****************************************************************************
27  Become the guest user without changing the security context stack.
28 ****************************************************************************/
29
30 BOOL change_to_guest(void)
31 {
32         static struct passwd *pass=NULL;
33
34         if (!pass) {
35                 /* Don't need to free() this as its stored in a static */
36                 pass = getpwnam_alloc(lp_guestaccount());
37                 if (!pass)
38                         return(False);
39         }
40         
41 #ifdef AIX
42         /* MWW: From AIX FAQ patch to WU-ftpd: call initgroups before 
43            setting IDs */
44         initgroups(pass->pw_name, pass->pw_gid);
45 #endif
46         
47         set_sec_ctx(pass->pw_uid, pass->pw_gid, 0, NULL, NULL);
48         
49         current_user.conn = NULL;
50         current_user.vuid = UID_FIELD_INVALID;
51         
52         passwd_free(&pass);
53
54         return True;
55 }
56
57 /*******************************************************************
58  Check if a username is OK.
59 ********************************************************************/
60
61 static BOOL check_user_ok(connection_struct *conn, user_struct *vuser,int snum)
62 {
63         unsigned i;
64         for (i=0;i<conn->vuid_cache.entries && i< VUID_CACHE_SIZE;i++)
65                 if (conn->vuid_cache.list[i] == vuser->vuid)
66                         return(True);
67
68         if ((conn->force_user || conn->force_group) 
69             && (conn->vuid != vuser->vuid)) {
70                 return False;
71         }
72         
73         if (!user_ok(vuser->user.unix_name,snum, vuser->groups, vuser->n_groups))
74                 return(False);
75
76         if (!share_access_check(conn, snum, vuser, conn->read_only ? FILE_READ_DATA : FILE_WRITE_DATA)) {
77                 return False;
78         }
79
80         i = conn->vuid_cache.entries % VUID_CACHE_SIZE;
81         conn->vuid_cache.list[i] = vuser->vuid;
82
83         conn->vuid_cache.entries++;
84
85         return(True);
86 }
87
88 /****************************************************************************
89  Become the user of a connection number without changing the security context
90  stack, but modify the currnet_user entries.
91 ****************************************************************************/
92
93 BOOL change_to_user(connection_struct *conn, uint16 vuid)
94 {
95         user_struct *vuser = get_valid_user_struct(vuid);
96         int snum;
97         gid_t gid;
98         uid_t uid;
99         char group_c;
100         BOOL must_free_token = False;
101         NT_USER_TOKEN *token = NULL;
102
103         if (!conn) {
104                 DEBUG(2,("change_to_user: Connection not open\n"));
105                 return(False);
106         }
107
108         /*
109          * We need a separate check in security=share mode due to vuid
110          * always being UID_FIELD_INVALID. If we don't do this then
111          * in share mode security we are *always* changing uid's between
112          * SMB's - this hurts performance - Badly.
113          */
114
115         if((lp_security() == SEC_SHARE) && (current_user.conn == conn) &&
116            (current_user.uid == conn->uid)) {
117                 DEBUG(4,("change_to_user: Skipping user change - already user\n"));
118                 return(True);
119         } else if ((current_user.conn == conn) && 
120                    (vuser != 0) && (current_user.vuid == vuid) && 
121                    (current_user.uid == vuser->uid)) {
122                 DEBUG(4,("change_to_user: Skipping user change - already user\n"));
123                 return(True);
124         }
125
126         snum = SNUM(conn);
127
128         if (conn->force_user) /* security = share sets this too */ {
129                 uid = conn->uid;
130                 gid = conn->gid;
131                 current_user.groups = conn->groups;
132                 current_user.ngroups = conn->ngroups;
133                 token = conn->nt_user_token;
134         } else if ((vuser) && check_user_ok(conn, vuser, snum)) {
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         } else {
141                 DEBUG(2,("change_to_user: Invalid vuid used %d or vuid not permitted access to share.\n",vuid));
142                 return False;
143         }
144
145         /*
146          * See if we should force group for this service.
147          * If so this overrides any group set in the force
148          * user code.
149          */
150
151         if((group_c = *lp_force_group(snum))) {
152                 BOOL is_guest = False;
153
154                 if(group_c == '+') {
155
156                         /*
157                          * Only force group if the user is a member of
158                          * the service group. Check the group memberships for
159                          * this user (we already have this) to
160                          * see if we should force the group.
161                          */
162
163                         int i;
164                         for (i = 0; i < current_user.ngroups; i++) {
165                                 if (current_user.groups[i] == conn->gid) {
166                                         gid = conn->gid;
167                                         break;
168                                 }
169                         }
170                 } else {
171                         gid = conn->gid;
172                 }
173
174                 /*
175                  * We've changed the group list in the token - we must
176                  * re-create it.
177                  */
178
179                 if (vuser && vuser->guest)
180                         is_guest = True;
181
182                 token = create_nt_token(uid, gid, current_user.ngroups, current_user.groups, is_guest);
183                 if (!token) {
184                         DEBUG(1, ("change_to_user: create_nt_token failed!\n"));
185                         return False;
186                 }
187                 must_free_token = True;
188         }
189         
190         set_sec_ctx(uid, gid, current_user.ngroups, current_user.groups, token);
191
192         /*
193          * Free the new token (as set_sec_ctx copies it).
194          */
195
196         if (must_free_token)
197                 delete_nt_token(&token);
198
199         current_user.conn = conn;
200         current_user.vuid = vuid;
201
202         DEBUG(5,("change_to_user uid=(%d,%d) gid=(%d,%d)\n",
203                  (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
204   
205         return(True);
206 }
207
208 /****************************************************************************
209  Go back to being root without changing the security context stack,
210  but modify the current_user entries.
211 ****************************************************************************/
212
213 BOOL change_to_root_user(void)
214 {
215         set_root_sec_ctx();
216
217         DEBUG(5,("change_to_root_user: now uid=(%d,%d) gid=(%d,%d)\n",
218                 (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
219
220         current_user.conn = NULL;
221         current_user.vuid = UID_FIELD_INVALID;
222
223         return(True);
224 }
225
226 /****************************************************************************
227  Become the user of an authenticated connected named pipe.
228  When this is called we are currently running as the connection
229  user. Doesn't modify current_user.
230 ****************************************************************************/
231
232 BOOL become_authenticated_pipe_user(pipes_struct *p)
233 {
234         if (!push_sec_ctx())
235                 return False;
236
237         set_sec_ctx(p->pipe_user.uid, p->pipe_user.gid, 
238                     p->pipe_user.ngroups, p->pipe_user.groups, p->pipe_user.nt_user_token);
239
240         return True;
241 }
242
243 /****************************************************************************
244  Unbecome the user of an authenticated connected named pipe.
245  When this is called we are running as the authenticated pipe
246  user and need to go back to being the connection user. Doesn't modify
247  current_user.
248 ****************************************************************************/
249
250 BOOL unbecome_authenticated_pipe_user(void)
251 {
252         return pop_sec_ctx();
253 }
254
255 /****************************************************************************
256  Utility functions used by become_xxx/unbecome_xxx.
257 ****************************************************************************/
258
259 struct conn_ctx {
260         connection_struct *conn;
261         uint16 vuid;
262 };
263  
264 /* A stack of current_user connection contexts. */
265  
266 static struct conn_ctx conn_ctx_stack[MAX_SEC_CTX_DEPTH];
267 static int conn_ctx_stack_ndx;
268
269 static void push_conn_ctx(void)
270 {
271         struct conn_ctx *ctx_p;
272  
273         /* Check we don't overflow our stack */
274  
275         if (conn_ctx_stack_ndx == MAX_SEC_CTX_DEPTH) {
276                 DEBUG(0, ("Connection context stack overflow!\n"));
277                 smb_panic("Connection context stack overflow!\n");
278         }
279  
280         /* Store previous user context */
281         ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
282  
283         ctx_p->conn = current_user.conn;
284         ctx_p->vuid = current_user.vuid;
285  
286         DEBUG(3, ("push_conn_ctx(%u) : conn_ctx_stack_ndx = %d\n",
287                 (unsigned int)ctx_p->vuid, conn_ctx_stack_ndx ));
288
289         conn_ctx_stack_ndx++;
290 }
291
292 static void pop_conn_ctx(void)
293 {
294         struct conn_ctx *ctx_p;
295  
296         /* Check for stack underflow. */
297
298         if (conn_ctx_stack_ndx == 0) {
299                 DEBUG(0, ("Connection context stack underflow!\n"));
300                 smb_panic("Connection context stack underflow!\n");
301         }
302
303         conn_ctx_stack_ndx--;
304         ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
305
306         current_user.conn = ctx_p->conn;
307         current_user.vuid = ctx_p->vuid;
308
309         ctx_p->conn = NULL;
310         ctx_p->vuid = UID_FIELD_INVALID;
311 }
312
313 void init_conn_ctx(void)
314 {
315     int i;
316  
317     /* Initialise connection context stack */
318         for (i = 0; i < MAX_SEC_CTX_DEPTH; i++) {
319                 conn_ctx_stack[i].conn = NULL;
320                 conn_ctx_stack[i].vuid = UID_FIELD_INVALID;
321     }
322 }
323
324 /****************************************************************************
325  Temporarily become a root user.  Must match with unbecome_root(). Saves and
326  restores the connection context.
327 ****************************************************************************/
328
329 void become_root(void)
330 {
331         push_sec_ctx();
332         push_conn_ctx();
333         set_root_sec_ctx();
334 }
335
336 /* Unbecome the root user */
337
338 void unbecome_root(void)
339 {
340         pop_sec_ctx();
341         pop_conn_ctx();
342 }
343
344 /****************************************************************************
345  Push the current security context then force a change via change_to_user().
346  Saves and restores the connection context.
347 ****************************************************************************/
348
349 BOOL become_user(connection_struct *conn, uint16 vuid)
350 {
351         if (!push_sec_ctx())
352                 return False;
353
354         push_conn_ctx();
355
356         if (!change_to_user(conn, vuid)) {
357                 pop_sec_ctx();
358                 pop_conn_ctx();
359                 return False;
360         }
361
362         return True;
363 }
364
365 BOOL unbecome_user(void)
366 {
367         pop_sec_ctx();
368         pop_conn_ctx();
369         return True;
370 }
371
372 /*****************************************************************
373  Convert the suplimentary SIDs returned in a netlogon into UNIX
374  group gid_t's. Add to the total group array.
375 *****************************************************************/
376  
377 void add_supplementary_nt_login_groups(int *n_groups, gid_t **pp_groups, NT_USER_TOKEN **pptok)
378 {
379         int total_groups;
380         int current_n_groups = *n_groups;
381         gid_t *final_groups = NULL;
382         size_t i;
383         NT_USER_TOKEN *ptok = *pptok;
384         NT_USER_TOKEN *new_tok = NULL;
385  
386         if (!ptok || (ptok->num_sids == 0))
387                 return;
388
389         new_tok = dup_nt_token(ptok);
390         if (!new_tok) {
391                 DEBUG(0,("add_supplementary_nt_login_groups: Failed to malloc new token\n"));
392                 return;
393         }
394         /* Leave the allocated space but empty the number of SIDs. */
395         new_tok->num_sids = 0;
396
397         total_groups = current_n_groups + ptok->num_sids;
398  
399         final_groups = (gid_t *)malloc(total_groups * sizeof(gid_t));
400         if (!final_groups) {
401                 DEBUG(0,("add_supplementary_nt_login_groups: Failed to malloc new groups.\n"));
402                 delete_nt_token(&new_tok);
403                 return;
404         }
405  
406         memcpy(final_groups, *pp_groups, current_n_groups * sizeof(gid_t));
407         for (i = 0; i < ptok->num_sids; i++) {
408                 enum SID_NAME_USE sid_type;
409                 gid_t new_grp;
410  
411                 if (sid_to_gid(&ptok->user_sids[i], &new_grp, &sid_type)) {
412                         /*
413                          * Don't add the gid_t if it is already in the current group
414                          * list. Some UNIXen don't like the same group more than once.
415                          */
416                         int j;
417
418                         for (j = 0; j < current_n_groups; j++)
419                                 if (final_groups[j] == new_grp)
420                                         break;
421                 
422                         if ( j == current_n_groups) {
423                                 /* Group not already present. */
424                                 final_groups[current_n_groups++] = new_grp;
425                         }
426                 } else {
427                         /* SID didn't map. Copy to the new token to be saved. */
428                         sid_copy(&new_tok->user_sids[new_tok->num_sids++], &ptok->user_sids[i]);
429                 }
430         }
431  
432         SAFE_FREE(*pp_groups);
433         *pp_groups = final_groups;
434         *n_groups = current_n_groups;
435
436         /* Replace the old token with the truncated one. */
437         delete_nt_token(&ptok);
438         *pptok = new_tok;
439 }
440
441 /*****************************************************************
442  *THE CANONICAL* convert name to SID function.
443  Tries local lookup first - for local domains - then uses winbind.
444 *****************************************************************/  
445
446 BOOL lookup_name(const char *domain, const char *name, DOM_SID *psid, enum SID_NAME_USE *name_type)
447 {
448         fstring sid;
449         BOOL local_lookup = False;
450         
451         *name_type = SID_NAME_UNKNOWN;
452
453         /* If we are looking up a domain user, make sure it is
454            for the local machine only */
455         
456         if (strequal(global_myname(), domain)) {
457                 local_lookup = True;
458         } else if (lp_server_role() == ROLE_DOMAIN_PDC || 
459                    lp_server_role() == ROLE_DOMAIN_BDC) {
460                 if (strequal(domain, lp_workgroup())) {
461                         local_lookup = True;
462                 }
463         }
464                 
465         if (local_lookup) {
466                 if (local_lookup_name(name, psid, name_type)) {
467                         DEBUG(10,
468                               ("lookup_name: (local) [%s]\\[%s] -> SID %s (type %s: %u)\n",
469                                domain, name, sid_to_string(sid,psid),
470                                sid_type_lookup(*name_type), (unsigned int)*name_type));
471                         return True;
472                 }
473         } else {
474                 /* Remote */
475                 if (winbind_lookup_name(domain, name, psid, name_type)) {
476                         
477                         DEBUG(10,("lookup_name (winbindd): [%s]\\[%s] -> SID %s (type %u)\n",
478                                   domain, name, sid_to_string(sid, psid), 
479                                   (unsigned int)*name_type));
480                         return True;
481                 }
482         }
483         
484         DEBUG(10, ("lookup_name: %s lookup for [%s]\\[%s] failed\n", 
485                    local_lookup ? "local" : "winbind", domain, name));
486
487         return False;
488 }
489
490 /*****************************************************************
491  *THE CANONICAL* convert SID to name function.
492  Tries local lookup first - for local sids, then tries winbind.
493 *****************************************************************/  
494
495 BOOL lookup_sid(DOM_SID *sid, fstring dom_name, fstring name, enum SID_NAME_USE *name_type)
496 {
497         if (!name_type)
498                 return False;
499
500         *name_type = SID_NAME_UNKNOWN;
501
502         /* Check if this is our own sid.  This should perhaps be done by
503            winbind?  For the moment handle it here. */
504
505         if (sid->num_auths == 5) {
506                 DOM_SID tmp_sid;
507                 uint32 rid;
508
509                 sid_copy(&tmp_sid, sid);
510                 sid_split_rid(&tmp_sid, &rid);
511
512                 if (sid_equal(get_global_sam_sid(), &tmp_sid)) {
513
514                         return map_domain_sid_to_name(&tmp_sid, dom_name) &&
515                                 local_lookup_sid(sid, name, name_type);
516                 }
517         }
518
519         if (!winbind_lookup_sid(sid, dom_name, name, name_type)) {
520                 fstring sid_str;
521                 DOM_SID tmp_sid;
522                 uint32 rid;
523
524                 DEBUG(10,("lookup_sid: winbind lookup for SID %s failed - trying local.\n", sid_to_string(sid_str, sid) ));
525
526                 sid_copy(&tmp_sid, sid);
527                 sid_split_rid(&tmp_sid, &rid);
528                 return map_domain_sid_to_name(&tmp_sid, dom_name) &&
529                         lookup_known_rid(&tmp_sid, rid, name, name_type);
530         }
531         return True;
532 }
533
534 /*****************************************************************
535  Id mapping cache.  This is to avoid Winbind mappings already
536  seen by smbd to be queried too frequently, keeping winbindd
537  busy, and blocking smbd while winbindd is busy with other
538  stuff. Written by Michael Steffens <michael.steffens@hp.com>,
539  modified to use linked lists by jra.
540 *****************************************************************/  
541
542 #define MAX_UID_SID_CACHE_SIZE 100
543 #define TURNOVER_UID_SID_CACHE_SIZE 10
544 #define MAX_GID_SID_CACHE_SIZE 100
545 #define TURNOVER_GID_SID_CACHE_SIZE 10
546
547 static size_t n_uid_sid_cache = 0;
548 static size_t n_gid_sid_cache = 0;
549
550 static struct uid_sid_cache {
551         struct uid_sid_cache *next, *prev;
552         uid_t uid;
553         DOM_SID sid;
554         enum SID_NAME_USE sidtype;
555 } *uid_sid_cache_head;
556
557 static struct gid_sid_cache {
558         struct gid_sid_cache *next, *prev;
559         gid_t gid;
560         DOM_SID sid;
561         enum SID_NAME_USE sidtype;
562 } *gid_sid_cache_head;
563
564 /*****************************************************************
565   Find a SID given a uid.
566 *****************************************************************/  
567
568 static BOOL fetch_sid_from_uid_cache(DOM_SID *psid, enum SID_NAME_USE *psidtype, uid_t uid)
569 {
570         struct uid_sid_cache *pc;
571
572         for (pc = uid_sid_cache_head; pc; pc = pc->next) {
573                 if (pc->uid == uid) {
574                         fstring sid;
575                         *psid = pc->sid;
576                         *psidtype = pc->sidtype;
577                         DEBUG(3,("fetch sid from uid cache %u -> %s\n",
578                                 (unsigned int)uid, sid_to_string(sid, psid)));
579                         DLIST_PROMOTE(uid_sid_cache_head, pc);
580                         return True;
581                 }
582         }
583         return False;
584 }
585
586 /*****************************************************************
587   Find a uid given a SID.
588 *****************************************************************/  
589
590 static BOOL fetch_uid_from_cache(uid_t *puid, const DOM_SID *psid, enum SID_NAME_USE sidtype)
591 {
592         struct uid_sid_cache *pc;
593
594         for (pc = uid_sid_cache_head; pc; pc = pc->next) {
595                 if (sid_compare(&pc->sid, psid) == 0) {
596                         fstring sid;
597                         *puid = pc->uid;
598                         DEBUG(3,("fetch uid from cache %u -> %s\n",
599                                 (unsigned int)*puid, sid_to_string(sid, psid)));
600                         DLIST_PROMOTE(uid_sid_cache_head, pc);
601                         return True;
602                 }
603         }
604         return False;
605 }
606
607 /*****************************************************************
608  Store uid to SID mapping in cache.
609 *****************************************************************/  
610
611 static void store_uid_sid_cache(const DOM_SID *psid, const enum SID_NAME_USE sidtype, uid_t uid)
612 {
613         struct uid_sid_cache *pc;
614
615         if (n_uid_sid_cache >= MAX_UID_SID_CACHE_SIZE && n_uid_sid_cache > TURNOVER_UID_SID_CACHE_SIZE) {
616                 /* Delete the last TURNOVER_UID_SID_CACHE_SIZE entries. */
617                 struct uid_sid_cache *pc_next;
618                 size_t i;
619
620                 for (i = 0, pc = uid_sid_cache_head; i < (n_uid_sid_cache - TURNOVER_UID_SID_CACHE_SIZE); i++, pc = pc->next)
621                         ;
622                 for(; pc; pc = pc_next) {
623                         pc_next = pc->next;
624                         DLIST_REMOVE(uid_sid_cache_head,pc);
625                         SAFE_FREE(pc);
626                         n_uid_sid_cache--;
627                 }
628         }
629
630         pc = (struct uid_sid_cache *)malloc(sizeof(struct uid_sid_cache));
631         if (!pc)
632                 return;
633         pc->uid = uid;
634         sid_copy(&pc->sid, psid);
635         pc->sidtype = sidtype;
636         DLIST_ADD(uid_sid_cache_head, pc);
637         n_uid_sid_cache++;
638 }
639
640 /*****************************************************************
641   Find a SID given a gid.
642 *****************************************************************/  
643
644 static BOOL fetch_sid_from_gid_cache(DOM_SID *psid, enum SID_NAME_USE *psidtype, gid_t gid)
645 {
646         struct gid_sid_cache *pc;
647
648         for (pc = gid_sid_cache_head; pc; pc = pc->next) {
649                 if (pc->gid == gid) {
650                         fstring sid;
651                         *psid = pc->sid;
652                         *psidtype = pc->sidtype;
653                         DEBUG(3,("fetch sid from gid cache %u -> %s\n",
654                                 (unsigned int)gid, sid_to_string(sid, psid)));
655                         DLIST_PROMOTE(gid_sid_cache_head, pc);
656                         return True;
657                 }
658         }
659         return False;
660 }
661
662 /*****************************************************************
663   Find a gid given a SID.
664 *****************************************************************/  
665
666 static BOOL fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid, enum SID_NAME_USE sidtype)
667 {
668         struct gid_sid_cache *pc;
669
670         for (pc = gid_sid_cache_head; pc; pc = pc->next) {
671                 if (sid_compare(&pc->sid, psid) == 0) {
672                         fstring sid;
673                         *pgid = pc->gid;
674                         DEBUG(3,("fetch uid from cache %u -> %s\n",
675                                 (unsigned int)*pgid, sid_to_string(sid, psid)));
676                         DLIST_PROMOTE(gid_sid_cache_head, pc);
677                         return True;
678                 }
679         }
680         return False;
681 }
682
683 /*****************************************************************
684  Store gid to SID mapping in cache.
685 *****************************************************************/  
686
687 static void store_gid_sid_cache(const DOM_SID *psid, const enum SID_NAME_USE sidtype, gid_t gid)
688 {
689         struct gid_sid_cache *pc;
690
691         if (n_gid_sid_cache >= MAX_GID_SID_CACHE_SIZE && n_gid_sid_cache > TURNOVER_GID_SID_CACHE_SIZE) {
692                 /* Delete the last TURNOVER_GID_SID_CACHE_SIZE entries. */
693                 struct gid_sid_cache *pc_next;
694                 size_t i;
695
696                 for (i = 0, pc = gid_sid_cache_head; i < (n_gid_sid_cache - TURNOVER_GID_SID_CACHE_SIZE); i++, pc = pc->next)
697                         ;
698                 for(; pc; pc = pc_next) {
699                         pc_next = pc->next;
700                         DLIST_REMOVE(gid_sid_cache_head,pc);
701                         SAFE_FREE(pc);
702                         n_gid_sid_cache--;
703                 }
704         }
705
706         pc = (struct gid_sid_cache *)malloc(sizeof(struct gid_sid_cache));
707         if (!pc)
708                 return;
709         pc->gid = gid;
710         sid_copy(&pc->sid, psid);
711         pc->sidtype = sidtype;
712         DLIST_ADD(gid_sid_cache_head, pc);
713         n_gid_sid_cache++;
714 }
715
716
717 /*****************************************************************
718  *THE CANONICAL* convert uid_t to SID function.
719  Tries winbind first - then uses local lookup.
720  Returns SID pointer.
721 *****************************************************************/  
722
723 DOM_SID *uid_to_sid(DOM_SID *psid, uid_t uid)
724 {
725         uid_t low, high;
726         enum SID_NAME_USE sidtype;
727         fstring sid;
728
729         if (fetch_sid_from_uid_cache(psid, &sidtype, uid))
730                 return psid;
731
732         if (lp_winbind_uid(&low, &high) && uid >= low && uid <= high) {
733                 if (winbind_uid_to_sid(psid, uid)) {
734
735                         DEBUG(10,("uid_to_sid: winbindd %u -> %s\n",
736                                 (unsigned int)uid, sid_to_string(sid, psid)));
737
738                         if (psid)
739                                 store_uid_sid_cache(psid, SID_NAME_USER, uid);
740                         return psid;
741                 }
742         }
743         
744         /* Make sure we report failure, (when psid == NULL) */
745         become_root();
746         psid = local_uid_to_sid(psid, uid);
747         unbecome_root();
748
749         DEBUG(10,("uid_to_sid: local %u -> %s\n", (unsigned int)uid, sid_to_string(sid, psid)));
750         if (psid)
751                 store_uid_sid_cache(psid, SID_NAME_USER, uid);
752
753         return psid;
754 }
755
756 /*****************************************************************
757  *THE CANONICAL* convert gid_t to SID function.
758  Tries winbind first - then uses local lookup.
759  Returns SID pointer.
760 *****************************************************************/  
761
762 DOM_SID *gid_to_sid(DOM_SID *psid, gid_t gid)
763 {
764         gid_t low, high;
765         enum SID_NAME_USE sidtype;
766         fstring sid;
767
768         if (fetch_sid_from_gid_cache(psid, &sidtype, gid))
769                 return psid;
770
771         if (lp_winbind_gid(&low, &high) && gid >= low && gid <= high) {
772                 if (winbind_gid_to_sid(psid, gid)) {
773
774                         DEBUG(10,("gid_to_sid: winbindd %u -> %s\n",
775                                 (unsigned int)gid, sid_to_string(sid, psid)));
776                         
777                         if (psid)
778                                 store_gid_sid_cache(psid, SID_NAME_DOM_GRP, gid);
779                         return psid;
780                 }
781         }
782
783         /* Make sure we report failure, (when psid == NULL) */
784         become_root();
785         psid = local_gid_to_sid(psid, gid);
786         unbecome_root();
787         DEBUG(10,("gid_to_sid: local %u -> %s\n", (unsigned int)gid, sid_to_string(sid, psid)));
788         if (psid)
789                 store_gid_sid_cache(psid, SID_NAME_DOM_GRP, gid);
790
791         return psid;
792 }
793
794 /*****************************************************************
795  *THE CANONICAL* convert SID to uid function.
796  Tries winbind first - then uses local lookup.
797  Returns True if this name is a user sid and the conversion
798  was done correctly, False if not. sidtype is set by this function.
799 *****************************************************************/  
800
801 BOOL sid_to_uid(const DOM_SID *psid, uid_t *puid, enum SID_NAME_USE *sidtype)
802 {
803         fstring sid_str;
804
805         if (fetch_uid_from_cache(puid, psid, *sidtype))
806                 return True;
807
808         /* if we know its local then don't try winbindd */
809         if (sid_compare_domain(get_global_sam_sid(), psid) == 0) {
810                 BOOL result;
811                 become_root();
812                 result = local_sid_to_uid(puid, psid, sidtype);
813                 unbecome_root();
814                 if (result)
815                         store_uid_sid_cache(psid, *sidtype, *puid);
816                 return result;
817         }
818
819 /* (tridge) I commented out the slab of code below in order to support foreign SIDs
820    Do we really need to validate the type of SID we have in this case? 
821 */
822 #if 0
823         fstring dom_name, name;
824         enum SID_NAME_USE name_type;
825
826         *sidtype = SID_NAME_UNKNOWN;
827         /*
828          * First we must look up the name and decide if this is a user sid.
829          */
830
831         if ( (!winbind_lookup_sid(psid, dom_name, name, &name_type)) || (name_type != SID_NAME_USER) ) {
832                 BOOL result;
833                 DEBUG(10,("sid_to_uid: winbind lookup for sid %s failed - trying local.\n",
834                                 sid_to_string(sid_str, psid) ));
835
836                 become_root();
837                 result = local_sid_to_uid(puid, psid, sidtype);
838                 unbecome_root();
839                 return result;
840         }
841
842         /*
843          * Ensure this is a user sid.
844          */
845
846         if (name_type != SID_NAME_USER) {
847                 DEBUG(10,("sid_to_uid: winbind lookup succeeded but SID is not a uid (%u)\n",
848                                 (unsigned int)name_type ));
849                 return False;
850         }
851 #endif
852         *sidtype = SID_NAME_USER;
853
854         /*
855          * Get the uid for this SID.
856          */
857
858         if (!winbind_sid_to_uid(puid, psid)) {
859                 BOOL result;
860                 DEBUG(10,("sid_to_uid: winbind lookup for sid %s failed.\n",
861                                 sid_to_string(sid_str, psid) ));
862                 become_root();
863                 result = local_sid_to_uid(puid, psid, sidtype);
864                 unbecome_root();
865                 if (result)
866                         store_uid_sid_cache(psid, *sidtype, *puid);
867                 return result;
868         }
869
870         DEBUG(10,("sid_to_uid: winbindd %s -> %u\n",
871                 sid_to_string(sid_str, psid),
872                 (unsigned int)*puid ));
873
874         store_uid_sid_cache(psid, *sidtype, *puid);
875         return True;
876 }
877
878 /*****************************************************************
879  *THE CANONICAL* convert SID to gid function.
880  Tries winbind first - then uses local lookup.
881  Returns True if this name is a user sid and the conversion
882  was done correctly, False if not.
883 *****************************************************************/  
884
885 BOOL sid_to_gid(const DOM_SID *psid, gid_t *pgid, enum SID_NAME_USE *sidtype)
886 {
887         fstring dom_name, name, sid_str;
888         enum SID_NAME_USE name_type;
889
890         *sidtype = SID_NAME_UNKNOWN;
891
892         if (fetch_gid_from_cache(pgid, psid, *sidtype))
893                 return True;
894
895         /*
896          * First we must look up the name and decide if this is a group sid.
897          */
898
899         /* if we know its local then don't try winbindd */
900         if (sid_compare_domain(get_global_sam_sid(), psid) == 0) {
901                 BOOL result;
902                 become_root();
903                 result = local_sid_to_gid(pgid, psid, sidtype);
904                 unbecome_root();
905                 if (result)
906                         store_gid_sid_cache(psid, *sidtype, *pgid);
907                 return result;
908         }
909
910         if (!winbind_lookup_sid(psid, dom_name, name, &name_type)) {
911                 DEBUG(10,("sid_to_gid: winbind lookup for sid %s failed.\n",
912                                 sid_to_string(sid_str, psid) ));
913                 /* this was probably a foreign sid - assume its a group rid 
914                    and continue */
915                 name_type = SID_NAME_DOM_GRP;
916         }
917
918         /*
919          * Ensure this is a group sid.
920          */
921
922         if ((name_type != SID_NAME_DOM_GRP) && (name_type != SID_NAME_ALIAS) && (name_type != SID_NAME_WKN_GRP)) {
923                 DEBUG(10,("sid_to_gid: winbind lookup succeeded but SID is not a known group (%u)\n",
924                                 (unsigned int)name_type ));
925
926                 return False;
927         }
928
929         *sidtype = name_type;
930
931         /*
932          * Get the gid for this SID.
933          */
934
935         if (!winbind_sid_to_gid(pgid, psid)) {
936                 DEBUG(10,("sid_to_gid: winbind lookup for sid %s failed.\n",
937                                 sid_to_string(sid_str, psid) ));
938                 return False;
939         }
940
941         DEBUG(10,("sid_to_gid: winbindd %s -> %u\n",
942                 sid_to_string(sid_str, psid),
943                 (unsigned int)*pgid ));
944
945         store_gid_sid_cache(psid, *sidtype, *pgid);
946         return True;
947 }
948