Fixed a couple of const issues with the new code.
[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                 gid_t new_grp;
409  
410                 if (NT_STATUS_IS_OK(sid_to_gid(&ptok->user_sids[i], &new_grp))) {
411                         /*
412                          * Don't add the gid_t if it is already in the current group
413                          * list. Some UNIXen don't like the same group more than once.
414                          */
415                         int j;
416
417                         for (j = 0; j < current_n_groups; j++)
418                                 if (final_groups[j] == new_grp)
419                                         break;
420                 
421                         if ( j == current_n_groups) {
422                                 /* Group not already present. */
423                                 final_groups[current_n_groups++] = new_grp;
424                         }
425                 } else {
426                         /* SID didn't map. Copy to the new token to be saved. */
427                         sid_copy(&new_tok->user_sids[new_tok->num_sids++], &ptok->user_sids[i]);
428                 }
429         }
430  
431         SAFE_FREE(*pp_groups);
432         *pp_groups = final_groups;
433         *n_groups = current_n_groups;
434
435         /* Replace the old token with the truncated one. */
436         delete_nt_token(&ptok);
437         *pptok = new_tok;
438 }
439
440 /*****************************************************************
441  *THE CANONICAL* convert name to SID function.
442  Tries local lookup first - for local domains - then uses winbind.
443 *****************************************************************/  
444
445 BOOL lookup_name(const char *domain, const char *name, DOM_SID *psid, enum SID_NAME_USE *name_type)
446 {
447         fstring sid;
448         BOOL local_lookup = False;
449         
450         *name_type = SID_NAME_UNKNOWN;
451
452         /* If we are looking up a domain user, make sure it is
453            for the local machine only */
454         
455         if (strequal(global_myname(), domain)) {
456                 local_lookup = True;
457         } else if (lp_server_role() == ROLE_DOMAIN_PDC || 
458                    lp_server_role() == ROLE_DOMAIN_BDC) {
459                 if (strequal(domain, lp_workgroup())) {
460                         local_lookup = True;
461                 }
462         }
463                 
464         if (local_lookup) {
465                 if (local_lookup_name(name, psid, name_type)) {
466                         DEBUG(10,
467                               ("lookup_name: (local) [%s]\\[%s] -> SID %s (type %s: %u)\n",
468                                domain, name, sid_to_string(sid,psid),
469                                sid_type_lookup(*name_type), (unsigned int)*name_type));
470                         return True;
471                 }
472         } else {
473                 /* Remote */
474                 if (winbind_lookup_name(domain, name, psid, name_type)) {
475                         
476                         DEBUG(10,("lookup_name (winbindd): [%s]\\[%s] -> SID %s (type %u)\n",
477                                   domain, name, sid_to_string(sid, psid), 
478                                   (unsigned int)*name_type));
479                         return True;
480                 }
481         }
482         
483         DEBUG(10, ("lookup_name: %s lookup for [%s]\\[%s] failed\n", 
484                    local_lookup ? "local" : "winbind", domain, name));
485
486         return False;
487 }
488
489 /*****************************************************************
490  *THE CANONICAL* convert SID to name function.
491  Tries local lookup first - for local sids, then tries winbind.
492 *****************************************************************/  
493
494 BOOL lookup_sid(DOM_SID *sid, fstring dom_name, fstring name, enum SID_NAME_USE *name_type)
495 {
496         if (!name_type)
497                 return False;
498
499         *name_type = SID_NAME_UNKNOWN;
500
501         /* Check if this is our own sid.  This should perhaps be done by
502            winbind?  For the moment handle it here. */
503
504         if (sid->num_auths == 5) {
505                 DOM_SID tmp_sid;
506                 uint32 rid;
507
508                 sid_copy(&tmp_sid, sid);
509                 sid_split_rid(&tmp_sid, &rid);
510
511                 if (sid_equal(get_global_sam_sid(), &tmp_sid)) {
512
513                         return map_domain_sid_to_name(&tmp_sid, dom_name) &&
514                                 local_lookup_sid(sid, name, name_type);
515                 }
516         }
517
518         if (!winbind_lookup_sid(sid, dom_name, name, name_type)) {
519                 fstring sid_str;
520                 DOM_SID tmp_sid;
521                 uint32 rid;
522
523                 DEBUG(10,("lookup_sid: winbind lookup for SID %s failed - trying local.\n", sid_to_string(sid_str, sid) ));
524
525                 sid_copy(&tmp_sid, sid);
526                 sid_split_rid(&tmp_sid, &rid);
527                 return map_domain_sid_to_name(&tmp_sid, dom_name) &&
528                         lookup_known_rid(&tmp_sid, rid, name, name_type);
529         }
530         return True;
531 }
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, 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                         DEBUG(3,("fetch sid from uid cache %u -> %s\n",
577                                 (unsigned int)uid, sid_to_string(sid, psid)));
578                         DLIST_PROMOTE(uid_sid_cache_head, pc);
579                         return True;
580                 }
581         }
582         return False;
583 }
584
585 /*****************************************************************
586   Find a uid given a SID.
587 *****************************************************************/  
588
589 static BOOL fetch_uid_from_cache( uid_t *puid, const DOM_SID *psid )
590 {
591         struct uid_sid_cache *pc;
592
593         for (pc = uid_sid_cache_head; pc; pc = pc->next) {
594                 if (sid_compare(&pc->sid, psid) == 0) {
595                         fstring sid;
596                         *puid = pc->uid;
597                         DEBUG(3,("fetch uid from cache %u -> %s\n",
598                                 (unsigned int)*puid, sid_to_string(sid, psid)));
599                         DLIST_PROMOTE(uid_sid_cache_head, pc);
600                         return True;
601                 }
602         }
603         return False;
604 }
605
606 /*****************************************************************
607  Store uid to SID mapping in cache.
608 *****************************************************************/  
609
610 static void store_uid_sid_cache(const DOM_SID *psid, uid_t uid)
611 {
612         struct uid_sid_cache *pc;
613
614         if (n_uid_sid_cache >= MAX_UID_SID_CACHE_SIZE && n_uid_sid_cache > TURNOVER_UID_SID_CACHE_SIZE) {
615                 /* Delete the last TURNOVER_UID_SID_CACHE_SIZE entries. */
616                 struct uid_sid_cache *pc_next;
617                 size_t i;
618
619                 for (i = 0, pc = uid_sid_cache_head; i < (n_uid_sid_cache - TURNOVER_UID_SID_CACHE_SIZE); i++, pc = pc->next)
620                         ;
621                 for(; pc; pc = pc_next) {
622                         pc_next = pc->next;
623                         DLIST_REMOVE(uid_sid_cache_head,pc);
624                         SAFE_FREE(pc);
625                         n_uid_sid_cache--;
626                 }
627         }
628
629         pc = (struct uid_sid_cache *)malloc(sizeof(struct uid_sid_cache));
630         if (!pc)
631                 return;
632         pc->uid = uid;
633         sid_copy(&pc->sid, psid);
634         DLIST_ADD(uid_sid_cache_head, pc);
635         n_uid_sid_cache++;
636 }
637
638 /*****************************************************************
639   Find a SID given a gid.
640 *****************************************************************/  
641
642 static BOOL fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid)
643 {
644         struct gid_sid_cache *pc;
645
646         for (pc = gid_sid_cache_head; pc; pc = pc->next) {
647                 if (pc->gid == gid) {
648                         fstring sid;
649                         *psid = pc->sid;
650                         DEBUG(3,("fetch sid from gid cache %u -> %s\n",
651                                 (unsigned int)gid, sid_to_string(sid, psid)));
652                         DLIST_PROMOTE(gid_sid_cache_head, pc);
653                         return True;
654                 }
655         }
656         return False;
657 }
658
659 /*****************************************************************
660   Find a gid given a SID.
661 *****************************************************************/  
662
663 static BOOL fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid)
664 {
665         struct gid_sid_cache *pc;
666
667         for (pc = gid_sid_cache_head; pc; pc = pc->next) {
668                 if (sid_compare(&pc->sid, psid) == 0) {
669                         fstring sid;
670                         *pgid = pc->gid;
671                         DEBUG(3,("fetch uid from cache %u -> %s\n",
672                                 (unsigned int)*pgid, sid_to_string(sid, psid)));
673                         DLIST_PROMOTE(gid_sid_cache_head, pc);
674                         return True;
675                 }
676         }
677         return False;
678 }
679
680 /*****************************************************************
681  Store gid to SID mapping in cache.
682 *****************************************************************/  
683
684 static void store_gid_sid_cache(const DOM_SID *psid, gid_t gid)
685 {
686         struct gid_sid_cache *pc;
687
688         if (n_gid_sid_cache >= MAX_GID_SID_CACHE_SIZE && n_gid_sid_cache > TURNOVER_GID_SID_CACHE_SIZE) {
689                 /* Delete the last TURNOVER_GID_SID_CACHE_SIZE entries. */
690                 struct gid_sid_cache *pc_next;
691                 size_t i;
692
693                 for (i = 0, pc = gid_sid_cache_head; i < (n_gid_sid_cache - TURNOVER_GID_SID_CACHE_SIZE); i++, pc = pc->next)
694                         ;
695                 for(; pc; pc = pc_next) {
696                         pc_next = pc->next;
697                         DLIST_REMOVE(gid_sid_cache_head,pc);
698                         SAFE_FREE(pc);
699                         n_gid_sid_cache--;
700                 }
701         }
702
703         pc = (struct gid_sid_cache *)malloc(sizeof(struct gid_sid_cache));
704         if (!pc)
705                 return;
706         pc->gid = gid;
707         sid_copy(&pc->sid, psid);
708         DLIST_ADD(gid_sid_cache_head, pc);
709         n_gid_sid_cache++;
710 }
711
712 /*****************************************************************
713  *THE CANONICAL* convert uid_t to SID function.
714  check idmap if uid is in idmap range, otherwise falls back to
715  the legacy algorithmic mapping.
716  A special cache is used for uids that maps to Wellknown SIDs
717  Returns SID pointer.
718 *****************************************************************/  
719
720 NTSTATUS uid_to_sid(DOM_SID *psid, uid_t uid)
721 {
722         uid_t low, high;
723         fstring sid;
724
725         if (fetch_sid_from_uid_cache(psid, uid))
726                 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
727
728         if (lp_idmap_uid(&low, &high) && uid >= low && uid <= high) {
729                 if (winbind_uid_to_sid(psid, uid)) {
730
731                         DEBUG(10,("uid_to_sid: winbindd %u -> %s\n",
732                                 (unsigned int)uid, sid_to_string(sid, psid)));
733
734                         if (psid)
735                                 store_uid_sid_cache(psid, uid);
736                         return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
737                 }
738         }
739
740         local_uid_to_sid(psid, uid);
741         
742         DEBUG(10,("uid_to_sid: local %u -> %s\n", (unsigned int)uid, sid_to_string(sid, psid)));
743
744         if (psid)
745                 store_uid_sid_cache(psid, uid);
746
747         return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
748 }
749
750 /*****************************************************************
751  *THE CANONICAL* convert gid_t to SID function.
752  check idmap if gid is in idmap range, otherwise falls back to
753  the legacy algorithmic mapping.
754  Group mapping is used for gids that maps to Wellknown SIDs
755  Returns SID pointer.
756 *****************************************************************/  
757
758 NTSTATUS gid_to_sid(DOM_SID *psid, gid_t gid)
759 {
760         gid_t low, high;
761         fstring sid;
762
763         if (fetch_sid_from_gid_cache(psid, gid))
764                 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
765
766         if (lp_idmap_gid(&low, &high) && gid >= low && gid <= high) {
767                 if (winbind_gid_to_sid(psid, gid)) {
768
769                         DEBUG(10,("gid_to_sid: winbindd %u -> %s\n",
770                                 (unsigned int)gid, sid_to_string(sid, psid)));
771                         
772                         if (psid)
773                                 store_gid_sid_cache(psid, gid);
774                         return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
775                 }
776         }
777
778         local_gid_to_sid(psid, gid);
779         
780         DEBUG(10,("gid_to_sid: local %u -> %s\n", (unsigned int)gid, sid_to_string(sid, psid)));
781
782         if (psid)
783                 store_gid_sid_cache(psid, gid);
784
785         return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
786 }
787
788 /*****************************************************************
789  *THE CANONICAL* convert SID to uid function.
790  if it is a foreign sid or it is in idmap rid range check idmap,
791  otherwise falls back to the legacy algorithmic mapping.
792  A special cache is used for uids that maps to Wellknown SIDs
793  Returns True if this name is a user sid and the conversion
794  was done correctly, False if not.
795 *****************************************************************/  
796
797 NTSTATUS sid_to_uid(const DOM_SID *psid, uid_t *puid)
798 {
799         fstring dom_name, name, sid_str;
800         enum SID_NAME_USE name_type;
801         BOOL ret;
802
803         if (fetch_uid_from_cache(puid, psid))
804                 return NT_STATUS_OK;
805
806         /*
807          * First we must look up the name and decide if this is a user sid.
808          */
809
810         if ( (!winbind_lookup_sid(psid, dom_name, name, &name_type)) || (name_type != SID_NAME_USER) ) {
811                 DEBUG(10,("sid_to_uid: winbind lookup for sid %s failed - trying local.\n",
812                         sid_to_string(sid_str, psid) ));
813
814                 ret = local_sid_to_uid(puid, psid, &name_type);
815                 if (ret)
816                         store_uid_sid_cache(psid, *puid);
817                 return (ret ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL);
818         }
819
820         /*
821          * Ensure this is a user sid.
822          */
823
824         if (name_type != SID_NAME_USER) {
825                 DEBUG(10,("sid_to_uid: winbind lookup succeeded but SID is not a uid (%u)\n",
826                         (unsigned int)name_type ));
827                 return NT_STATUS_INVALID_PARAMETER;
828         }
829
830         /* query only first */
831         
832         if ( !winbind_sid_to_uid_query(puid, psid) ) 
833         {
834                 DEBUG(10,("sid_to_uid: winbind query for sid %s failed.\n",
835                         sid_to_string(sid_str, psid) ));
836                 
837                 /* see if we have a local mapping */
838                         
839                 if ( local_sid_to_uid(puid, psid, &name_type) ) {
840                         store_uid_sid_cache(psid, *puid);
841                         return NT_STATUS_OK;
842                 }
843                         
844                 /* Call back to winbind to allocate a new uid */
845
846                 if ( !winbind_sid_to_uid(puid, psid) ) {
847                         DEBUG(10,("sid_to_uid: winbind failed to allocate a new uid for sid %s\n",
848                                 sid_to_string(sid_str, psid) ));
849                         return NT_STATUS_UNSUCCESSFUL;
850                 }
851         }
852
853         DEBUG(10,("sid_to_uid: %s -> %u\n", sid_to_string(sid_str, psid),
854                 (unsigned int)*puid ));
855
856         store_uid_sid_cache(psid, *puid);
857         
858         return NT_STATUS_OK;
859 }
860 /*****************************************************************
861  *THE CANONICAL* convert SID to gid function.
862  if it is a foreign sid or it is in idmap rid range check idmap,
863  otherwise falls back to the legacy algorithmic mapping.
864  Group mapping is used for gids that maps to Wellknown SIDs
865  Returns True if this name is a user sid and the conversion
866  was done correctly, False if not.
867 *****************************************************************/  
868
869 NTSTATUS sid_to_gid(const DOM_SID *psid, gid_t *pgid)
870 {
871         fstring dom_name, name, sid_str;
872         enum SID_NAME_USE name_type;
873         BOOL ret;
874
875         if (fetch_gid_from_cache(pgid, psid))
876                 return NT_STATUS_OK;
877
878         /*
879          * First we must look up the name and decide if this is a group sid.
880          */
881
882         if (!winbind_lookup_sid(psid, dom_name, name, &name_type)) {
883                 DEBUG(10,("sid_to_gid: winbind lookup for sid %s failed - trying local.\n",
884                         sid_to_string(sid_str, psid) ));
885
886                 ret = local_sid_to_gid(pgid, psid, &name_type);
887                 if (ret)
888                         store_gid_sid_cache(psid, *pgid);
889                         
890                 return (ret ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL);
891         }
892
893         /*
894          * Ensure this is a group sid.
895          */
896
897         if ((name_type != SID_NAME_DOM_GRP) && (name_type != SID_NAME_ALIAS) && (name_type != SID_NAME_WKN_GRP)) {
898                 DEBUG(10,("sid_to_gid: winbind lookup succeeded but SID is not a known group (%u)\n",
899                         (unsigned int)name_type ));
900
901                 ret = local_sid_to_gid(pgid, psid,  &name_type);
902                 if (ret)
903                         store_gid_sid_cache(psid, *pgid);
904                 return (ret ? NT_STATUS_OK : NT_STATUS_INVALID_PARAMETER);
905         }
906
907         /* query only first */
908         
909         if ( !winbind_sid_to_gid_query(pgid, psid) ) 
910         {
911                 DEBUG(10,("sid_to_gid: winbind query for sid %s failed.\n",
912                         sid_to_string(sid_str, psid) ));
913                         
914                 /* see if we have a local mapping */
915                         
916                 if ( local_sid_to_gid(pgid, psid, &name_type) ) {
917                         store_gid_sid_cache(psid, *pgid);
918                         return NT_STATUS_OK;
919                 }
920                         
921                 /* Call back to winbind to allocate a new uid */
922
923                 if ( !winbind_sid_to_gid(pgid, psid) ) {
924                         DEBUG(10,("sid_to_uid: winbind failed to allocate a new gid for sid %s\n",
925                                 sid_to_string(sid_str, psid) ));
926                         return NT_STATUS_UNSUCCESSFUL;
927                 }
928                 else
929                         return NT_STATUS_UNSUCCESSFUL;
930         }
931
932         DEBUG(10,("sid_to_gid: %s -> %u\n", sid_to_string(sid_str, psid),
933                 (unsigned int)*pgid ));
934
935         store_gid_sid_cache(psid, *pgid);
936         
937         return NT_STATUS_OK;
938 }
939