fixes
[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 #ifdef WITH_IDMAP
726         unid_t id;
727
728         DEBUG(10,("uid_to_sid: uid = [%d]\n", uid));
729
730         id.uid = uid;
731         if (NT_STATUS_IS_OK(idmap_get_sid_from_id(psid, id, ID_USERID))) {
732                 DEBUG(10, ("uid_to_sid: sid = [%s]\n", sid_string_static(psid)));
733                 return psid;
734         }
735
736         /* If mapping is not found in idmap try with traditional method,
737            then stores the result in idmap.
738            We may add a switch in future to allow smooth migrations to
739            idmap-only db  ---Simo */    
740
741         become_root();
742         psid = local_uid_to_sid(psid, uid);
743         unbecome_root();
744
745         DEBUG(10,("uid_to_sid: algorithmic %u -> %s\n", (unsigned int)uid, sid_string_static(psid)));
746         if (psid)
747                 idmap_set_mapping(psid, id, ID_USERID);
748
749         return psid;
750         
751 #else
752         uid_t low, high;
753         enum SID_NAME_USE sidtype;
754         fstring sid;
755
756         if (fetch_sid_from_uid_cache(psid, &sidtype, uid))
757                 return psid;
758
759         if (lp_idmap_uid(&low, &high) && uid >= low && uid <= high) {
760                 if (winbind_uid_to_sid(psid, uid)) {
761
762                         DEBUG(10,("uid_to_sid: winbindd %u -> %s\n",
763                                 (unsigned int)uid, sid_to_string(sid, psid)));
764
765                         if (psid)
766                                 store_uid_sid_cache(psid, SID_NAME_USER, uid);
767                         return psid;
768                 }
769         }
770         
771         /* Make sure we report failure, (when psid == NULL) */
772         become_root();
773         psid = local_uid_to_sid(psid, uid);
774         unbecome_root();
775
776         DEBUG(10,("uid_to_sid: local %u -> %s\n", (unsigned int)uid, sid_to_string(sid, psid)));
777         if (psid)
778                 store_uid_sid_cache(psid, SID_NAME_USER, uid);
779
780         return psid;
781 #endif
782 }
783
784 /*****************************************************************
785  *THE CANONICAL* convert gid_t to SID function.
786  Tries winbind first - then uses local lookup.
787  Returns SID pointer.
788 *****************************************************************/  
789
790 DOM_SID *gid_to_sid(DOM_SID *psid, gid_t gid)
791 {
792 #ifdef WITH_IDMAP
793         unid_t id;
794
795         DEBUG(10,("gid_to_sid: gid = [%d]\n", gid));
796
797                 id.gid = gid;
798         if (NT_STATUS_IS_OK(idmap_get_sid_from_id(psid, id, ID_GROUPID))) {
799                 DEBUG(10, ("gid_to_sid: sid = [%s]\n", sid_string_static(psid)));
800                 return psid;
801         }
802
803         /* If mapping is not found in idmap try with traditional method,
804            then stores the result in idmap.
805            We may add a switch in future to allow smooth migrations to
806            idmap-only db  ---Simo */    
807
808         become_root();
809         psid = local_gid_to_sid(psid, gid);
810         unbecome_root();
811
812         DEBUG(10,("gid_to_sid: algorithmic %u -> %s\n", (unsigned int)gid, sid_string_static(psid)));
813         if (psid)
814                 idmap_set_mapping(psid, id, ID_GROUPID);
815
816         return psid;
817         
818 #else
819         gid_t low, high;
820         enum SID_NAME_USE sidtype;
821         fstring sid;
822
823         if (fetch_sid_from_gid_cache(psid, &sidtype, gid))
824                 return psid;
825
826         if (lp_idmap_gid(&low, &high) && gid >= low && gid <= high) {
827                 if (winbind_gid_to_sid(psid, gid)) {
828
829                         DEBUG(10,("gid_to_sid: winbindd %u -> %s\n",
830                                 (unsigned int)gid, sid_to_string(sid, psid)));
831                         
832                         if (psid)
833                                 store_gid_sid_cache(psid, SID_NAME_DOM_GRP, gid);
834                         return psid;
835                 }
836         }
837
838         /* Make sure we report failure, (when psid == NULL) */
839         become_root();
840         psid = local_gid_to_sid(psid, gid);
841         unbecome_root();
842         DEBUG(10,("gid_to_sid: local %u -> %s\n", (unsigned int)gid, sid_to_string(sid, psid)));
843         if (psid)
844                 store_gid_sid_cache(psid, SID_NAME_DOM_GRP, gid);
845
846         return psid;
847 #endif
848 }
849
850 /*****************************************************************
851  *THE CANONICAL* convert SID to uid function.
852  Tries winbind first - then uses local lookup.
853  Returns True if this name is a user sid and the conversion
854  was done correctly, False if not. sidtype is set by this function.
855 *****************************************************************/  
856
857 BOOL sid_to_uid(const DOM_SID *psid, uid_t *puid, enum SID_NAME_USE *sidtype)
858 {
859 #ifdef WITH_IDMAP
860         unid_t id;
861         int type;
862
863         DEBUG(10,("sid_to_uid: sid = [%s]\n", sid_string_static(psid)));
864
865         *sidtype = SID_NAME_USER;
866
867         type = ID_USERID;
868         if (NT_STATUS_IS_OK(idmap_get_id_from_sid(&id, &type, psid))) {
869                 DEBUG(10,("sid_to_uid: uid = [%d]\n", id.uid));
870                 *puid = id.uid;
871                 return True;
872         }
873
874         if (sid_compare_domain(get_global_sam_sid(), psid) == 0) {
875                 BOOL result;
876
877                 DEBUG(10,("sid_to_uid: sid is local [%s]\n", sid_string_static(get_global_sam_sid())));
878                 become_root();
879                 result = local_sid_to_uid(puid, psid, sidtype);
880                 unbecome_root();
881                 if (result) {
882                         id.uid = *puid;
883                         DEBUG(10,("sid_to_uid: uid = [%d]\n", id.uid));
884                         idmap_set_mapping(psid, id, ID_USERID);
885                         return True;
886                 }
887         }
888         return False;
889 #else
890         fstring sid_str;
891
892         if (fetch_uid_from_cache(puid, psid, *sidtype))
893                 return True;
894
895         /* if we know its local then don't try winbindd */
896         if (sid_compare_domain(get_global_sam_sid(), psid) == 0) {
897                 BOOL result;
898                 become_root();
899                 result = local_sid_to_uid(puid, psid, sidtype);
900                 unbecome_root();
901                 if (result)
902                         store_uid_sid_cache(psid, *sidtype, *puid);
903                 return result;
904         }
905
906 /* (tridge) I commented out the slab of code below in order to support foreign SIDs
907    Do we really need to validate the type of SID we have in this case? 
908 */
909 #if 0
910         fstring dom_name, name;
911         enum SID_NAME_USE name_type;
912
913         *sidtype = SID_NAME_UNKNOWN;
914         /*
915          * First we must look up the name and decide if this is a user sid.
916          */
917
918         if ( (!winbind_lookup_sid(psid, dom_name, name, &name_type)) || (name_type != SID_NAME_USER) ) {
919                 BOOL result;
920                 DEBUG(10,("sid_to_uid: winbind lookup for sid %s failed - trying local.\n",
921                                 sid_to_string(sid_str, psid) ));
922
923                 become_root();
924                 result = local_sid_to_uid(puid, psid, sidtype);
925                 unbecome_root();
926                 return result;
927         }
928
929         /*
930          * Ensure this is a user sid.
931          */
932
933         if (name_type != SID_NAME_USER) {
934                 DEBUG(10,("sid_to_uid: winbind lookup succeeded but SID is not a uid (%u)\n",
935                                 (unsigned int)name_type ));
936                 return False;
937         }
938 #endif
939         *sidtype = SID_NAME_USER;
940
941         /*
942          * Get the uid for this SID.
943          */
944
945         if (!winbind_sid_to_uid(puid, psid)) {
946                 BOOL result;
947                 DEBUG(10,("sid_to_uid: winbind lookup for sid %s failed.\n",
948                                 sid_to_string(sid_str, psid) ));
949                 become_root();
950                 result = local_sid_to_uid(puid, psid, sidtype);
951                 unbecome_root();
952                 if (result)
953                         store_uid_sid_cache(psid, *sidtype, *puid);
954                 return result;
955         }
956
957         DEBUG(10,("sid_to_uid: winbindd %s -> %u\n",
958                 sid_to_string(sid_str, psid),
959                 (unsigned int)*puid ));
960
961         store_uid_sid_cache(psid, *sidtype, *puid);
962         return True;
963 #endif
964 }
965
966 /*****************************************************************
967  *THE CANONICAL* convert SID to gid function.
968  Tries winbind first - then uses local lookup.
969  Returns True if this name is a user sid and the conversion
970  was done correctly, False if not.
971 *****************************************************************/  
972
973 BOOL sid_to_gid(const DOM_SID *psid, gid_t *pgid, enum SID_NAME_USE *sidtype)
974 {
975 #ifdef WITH_IDMAP
976         unid_t id;
977         int type;
978
979         DEBUG(10,("sid_to_gid: sid = [%s]\n", sid_string_static(psid)));
980
981         *sidtype = SID_NAME_ALIAS;
982
983         type = ID_GROUPID;
984         if (NT_STATUS_IS_OK(idmap_get_id_from_sid(&id, &type, psid))) {
985                 DEBUG(10,("sid_to_gid: gid = [%d]\n", id.gid));
986                 *pgid = id.gid;
987                 return True;
988         }
989
990         if (sid_compare_domain(get_global_sam_sid(), psid) == 0) {
991                 BOOL result;
992                 become_root();
993                 result = local_sid_to_gid(pgid, psid, sidtype);
994                 unbecome_root();
995                 if (result) {
996                         id.gid = *pgid;
997                         DEBUG(10,("sid_to_gid: gid = [%d]\n", id.gid));
998                         idmap_set_mapping(psid, id, ID_GROUPID);
999                         return True;
1000                 }
1001         }
1002
1003         return False;
1004
1005 #else
1006         fstring dom_name, name, sid_str;
1007         enum SID_NAME_USE name_type;
1008
1009         *sidtype = SID_NAME_UNKNOWN;
1010
1011         if (fetch_gid_from_cache(pgid, psid, *sidtype))
1012                 return True;
1013
1014         /*
1015          * First we must look up the name and decide if this is a group sid.
1016          */
1017
1018         /* if we know its local then don't try winbindd */
1019         if (sid_compare_domain(get_global_sam_sid(), psid) == 0) {
1020                 BOOL result;
1021                 become_root();
1022                 result = local_sid_to_gid(pgid, psid, sidtype);
1023                 unbecome_root();
1024                 if (result)
1025                         store_gid_sid_cache(psid, *sidtype, *pgid);
1026                 return result;
1027         }
1028
1029         if (!winbind_lookup_sid(psid, dom_name, name, &name_type)) {
1030                 DEBUG(10,("sid_to_gid: winbind lookup for sid %s failed.\n",
1031                                 sid_to_string(sid_str, psid) ));
1032                 /* this was probably a foreign sid - assume its a group rid 
1033                    and continue */
1034                 name_type = SID_NAME_DOM_GRP;
1035         }
1036
1037         /*
1038          * Ensure this is a group sid.
1039          */
1040
1041         if ((name_type != SID_NAME_DOM_GRP) && (name_type != SID_NAME_ALIAS) && (name_type != SID_NAME_WKN_GRP)) {
1042                 DEBUG(10,("sid_to_gid: winbind lookup succeeded but SID is not a known group (%u)\n",
1043                                 (unsigned int)name_type ));
1044
1045                 return False;
1046         }
1047
1048         *sidtype = name_type;
1049
1050         /*
1051          * Get the gid for this SID.
1052          */
1053
1054         if (!winbind_sid_to_gid(pgid, psid)) {
1055                 DEBUG(10,("sid_to_gid: winbind lookup for sid %s failed.\n",
1056                                 sid_to_string(sid_str, psid) ));
1057                 return False;
1058         }
1059
1060         DEBUG(10,("sid_to_gid: winbindd %s -> %u\n",
1061                 sid_to_string(sid_str, psid),
1062                 (unsigned int)*pgid ));
1063
1064         store_gid_sid_cache(psid, *sidtype, *pgid);
1065         return True;
1066 #endif
1067 }
1068