r12714: Fix segfault in pdb_nds.c.
[metze/samba/wip.git] / source3 / passdb / lookup_sid.c
1 /* 
2    Unix SMB/CIFS implementation.
3    uid/user handling
4    Copyright (C) Andrew Tridgell         1992-1998
5    Copyright (C) Gerald (Jerry) Carter   2003
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23
24 /*****************************************************************
25  Dissect a user-provided name into domain, name, sid and type.
26
27  If an explicit domain name was given in the form domain\user, it
28  has to try that. If no explicit domain name was given, we have
29  to do guesswork.
30 *****************************************************************/  
31
32 BOOL lookup_name(TALLOC_CTX *mem_ctx,
33                  const char *full_name, int flags,
34                  const char **ret_domain, const char **ret_name,
35                  DOM_SID *ret_sid, enum SID_NAME_USE *ret_type)
36 {
37         char *p;
38         const char *tmp;
39         const char *domain = NULL;
40         const char *name = NULL;
41         uint32 rid;
42         DOM_SID sid;
43         enum SID_NAME_USE type;
44         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
45
46         if (tmp_ctx == NULL) {
47                 DEBUG(0, ("talloc_new failed\n"));
48                 return False;
49         }
50
51         p = strchr_m(full_name, '\\');
52
53         if (p != NULL) {
54                 domain = talloc_strndup(tmp_ctx, full_name,
55                                         PTR_DIFF(p, full_name));
56                 name = talloc_strdup(tmp_ctx, p+1);
57         } else {
58                 domain = talloc_strdup(tmp_ctx, "");
59                 name = talloc_strdup(tmp_ctx, full_name);
60         }
61
62         if ((domain == NULL) || (name == NULL)) {
63                 DEBUG(0, ("talloc failed\n"));
64                 return False;
65         }
66
67         if (strequal(domain, get_global_sam_name())) {
68
69                 /* It's our own domain, lookup the name in passdb */
70                 if (lookup_global_sam_name(name, &rid, &type)) {
71                         sid_copy(&sid, get_global_sam_sid());
72                         sid_append_rid(&sid, rid);
73                         goto ok;
74                 }
75                 goto failed;
76         }
77
78         if (strequal(domain, builtin_domain_name())) {
79
80                 /* Explicit request for a name in BUILTIN */
81                 if (lookup_builtin_name(name, &rid)) {
82                         sid_copy(&sid, &global_sid_Builtin);
83                         sid_append_rid(&sid, rid);
84                         type = SID_NAME_ALIAS;
85                         goto ok;
86                 }
87                 goto failed;
88         }
89
90         if (domain[0] != '\0') {
91                 /* An explicit domain name was given, here our last resort is
92                  * winbind. */
93                 if (winbind_lookup_name(domain, name, &sid, &type)) {
94                         goto ok;
95                 }
96                 goto failed;
97         }
98
99         if (!(flags & LOOKUP_NAME_ISOLATED)) {
100                 goto failed;
101         }
102
103         /* Now the guesswork begins, we haven't been given an explicit
104          * domain. Try the sequence as documented on
105          * http://msdn.microsoft.com/library/en-us/secmgmt/security/lsalookupnames.asp
106          * November 27, 2005 */
107
108         /* 1. well-known names */
109
110         {
111                 if (lookup_wellknown_name(tmp_ctx, name, &sid, &domain)) {
112                         type = SID_NAME_WKN_GRP;
113                         goto ok;
114                 }
115         }
116
117         /* 2. Builtin domain as such */
118
119         if (strequal(name, builtin_domain_name())) {
120                 /* Swap domain and name */
121                 tmp = name; name = domain; domain = tmp;
122                 sid_copy(&sid, &global_sid_Builtin);
123                 type = SID_NAME_DOMAIN;
124                 goto ok;
125         }
126
127         /* 3. Account domain */
128
129         if (strequal(name, get_global_sam_name())) {
130                 if (!secrets_fetch_domain_sid(name, &sid)) {
131                         DEBUG(3, ("Could not fetch my SID\n"));
132                         goto failed;
133                 }
134                 /* Swap domain and name */
135                 tmp = name; name = domain; domain = tmp;
136                 type = SID_NAME_DOMAIN;
137                 goto ok;
138         }
139
140         /* 4. Primary domain */
141
142         if (!IS_DC && strequal(name, lp_workgroup())) {
143                 if (!secrets_fetch_domain_sid(name, &sid)) {
144                         DEBUG(3, ("Could not fetch the domain SID\n"));
145                         goto failed;
146                 }
147                 /* Swap domain and name */
148                 tmp = name; name = domain; domain = tmp;
149                 type = SID_NAME_DOMAIN;
150                 goto ok;
151         }
152
153         /* 5. Trusted domains as such, to me it looks as if members don't do
154               this, tested an XP workstation in a NT domain -- vl */
155
156         if (IS_DC && (secrets_fetch_trusted_domain_password(name, NULL,
157                                                             &sid, NULL))) {
158                 /* Swap domain and name */
159                 tmp = name; name = domain; domain = tmp;
160                 type = SID_NAME_DOMAIN;
161                 goto ok;
162         }
163
164         /* 6. Builtin aliases */        
165
166         if (lookup_builtin_name(name, &rid)) {
167                 domain = talloc_strdup(tmp_ctx, builtin_domain_name());
168                 sid_copy(&sid, &global_sid_Builtin);
169                 sid_append_rid(&sid, rid);
170                 type = SID_NAME_ALIAS;
171                 goto ok;
172         }
173
174         /* 7. Local systems' SAM (DCs don't have a local SAM) */
175         /* 8. Primary SAM (On members, this is the domain) */
176
177         /* Both cases are done by looking at our passdb */
178
179         if (lookup_global_sam_name(name, &rid, &type)) {
180                 domain = talloc_strdup(tmp_ctx, get_global_sam_name());
181                 sid_copy(&sid, get_global_sam_sid());
182                 sid_append_rid(&sid, rid);
183                 goto ok;
184         }
185
186         /* Now our local possibilities are exhausted. */
187
188         if (!(flags & LOOKUP_NAME_REMOTE)) {
189                 goto failed;
190         }
191
192         /* If we are not a DC, we have to ask in our primary domain. Let
193          * winbind do that. */
194
195         if (!IS_DC &&
196             (winbind_lookup_name(lp_workgroup(), name, &sid, &type))) {
197                 domain = talloc_strdup(tmp_ctx, lp_workgroup());
198                 goto ok;
199         }
200
201         /* 9. Trusted domains */
202
203         /* If we're a DC we have to ask all trusted DC's. Winbind does not do
204          * that (yet), but give it a chance. */
205
206         if (IS_DC && winbind_lookup_name("", name, &sid, &type)) {
207                 DOM_SID dom_sid;
208                 uint32 tmp_rid;
209                 enum SID_NAME_USE domain_type;
210                 
211                 if (type == SID_NAME_DOMAIN) {
212                         /* Swap name and type */
213                         tmp = name; name = domain; domain = tmp;
214                         goto ok;
215                 }
216
217                 /* Here we have to cope with a little deficiency in the
218                  * winbind API: We have to ask it again for the name of the
219                  * domain it figured out itself. Maybe fix that later... */
220
221                 sid_copy(&dom_sid, &sid);
222                 sid_split_rid(&dom_sid, &tmp_rid);
223
224                 if (!winbind_lookup_sid(tmp_ctx, &dom_sid, &domain, NULL,
225                                         &domain_type) ||
226                     (domain_type != SID_NAME_DOMAIN)) {
227                         DEBUG(2, ("winbind could not find the domain's name "
228                                   "it just looked up for us\n"));
229                         goto failed;
230                 }
231                 goto ok;
232         }
233
234         /* 10. Don't translate */
235  failed:
236         talloc_free(tmp_ctx);
237         return False;
238
239  ok:
240         if ((domain == NULL) || (name == NULL)) {
241                 DEBUG(0, ("talloc failed\n"));
242                 talloc_free(tmp_ctx);
243                 return False;
244         }
245
246         if (ret_name != NULL) {
247                 *ret_name = talloc_steal(mem_ctx, name);
248         }
249
250         if (ret_domain != NULL) {
251                 char *tmp_dom = talloc_strdup(tmp_ctx, domain);
252                 strupper_m(tmp_dom);
253                 *ret_domain = talloc_steal(mem_ctx, tmp_dom);
254         }
255
256         if (ret_sid != NULL) {
257                 sid_copy(ret_sid, &sid);
258         }
259
260         if (ret_type != NULL) {
261                 *ret_type = type;
262         }
263
264         talloc_free(tmp_ctx);
265         return True;
266 }
267
268 /*****************************************************************
269  *THE CANONICAL* convert SID to name function.
270  Tries local lookup first - for local sids, then tries winbind.
271 *****************************************************************/  
272
273 BOOL lookup_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
274                 const char **ret_domain, const char **ret_name,
275                 enum SID_NAME_USE *ret_type)
276 {
277         const char *domain = NULL;
278         const char *name = NULL;
279         enum SID_NAME_USE type;
280         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
281
282         /* Check if this is our own sid.  This should perhaps be done by
283            winbind?  For the moment handle it here. */
284
285         if (tmp_ctx == NULL) {
286                 DEBUG(0, ("talloc_new failed\n"));
287                 return False;
288         }
289
290         if (sid_check_is_domain(sid)) {
291                 domain = talloc_strdup(tmp_ctx, get_global_sam_name());
292                 name = talloc_strdup(tmp_ctx, "");
293                 type = SID_NAME_DOMAIN;
294                 goto ok;
295         }
296
297         if (sid_check_is_in_our_domain(sid)) {
298                 uint32 rid;
299                 SMB_ASSERT(sid_peek_rid(sid, &rid));
300
301                 /* For our own domain passdb is responsible */
302                 if (!lookup_global_sam_rid(tmp_ctx, rid, &name, &type)) {
303                         goto failed;
304                 }
305
306                 domain = talloc_strdup(tmp_ctx, get_global_sam_name());
307                 goto ok;
308         }
309
310         if (sid_check_is_builtin(sid)) {
311
312                 domain = talloc_strdup(tmp_ctx, builtin_domain_name());
313
314                 /* Yes, W2k3 returns "BUILTIN" both as domain and name here */
315                 name = talloc_strdup(tmp_ctx, builtin_domain_name());
316                 type = SID_NAME_DOMAIN;
317                 goto ok;
318         }
319
320         if (sid_check_is_in_builtin(sid)) {
321                 uint32 rid;
322
323                 SMB_ASSERT(sid_peek_rid(sid, &rid));
324
325                 if (!lookup_builtin_rid(tmp_ctx, rid, &name)) {
326                         goto failed;
327                 }
328
329                 /* There's only aliases in S-1-5-32 */
330                 type = SID_NAME_ALIAS;
331                 domain = talloc_strdup(tmp_ctx, builtin_domain_name());
332
333                 goto ok;
334         }
335
336         if (winbind_lookup_sid(tmp_ctx, sid, &domain, &name, &type)) {
337                 goto ok;
338         }
339
340         DEBUG(10,("lookup_sid: winbind lookup for SID %s failed - trying "
341                   "special SIDs.\n", sid_string_static(sid)));
342
343         if (lookup_wellknown_sid(tmp_ctx, sid, &domain, &name)) {
344                 type = SID_NAME_WKN_GRP;
345                 goto ok;
346         }
347
348  failed:
349         DEBUG(10, ("Failed to lookup sid %s\n", sid_string_static(sid)));
350         talloc_free(tmp_ctx);
351         return False;
352
353  ok:
354
355         if ((domain == NULL) || (name == NULL)) {
356                 DEBUG(0, ("talloc failed\n"));
357                 talloc_free(tmp_ctx);
358                 return False;
359         }
360
361         if (ret_domain != NULL) {
362                 *ret_domain = talloc_steal(mem_ctx, domain);
363         }
364
365         if (ret_name != NULL) {
366                 *ret_name = talloc_steal(mem_ctx, name);
367         }
368
369         if (ret_type != NULL) {
370                 *ret_type = type;
371         }
372
373         talloc_free(tmp_ctx);
374         return True;
375 }
376
377 /*****************************************************************
378  Id mapping cache.  This is to avoid Winbind mappings already
379  seen by smbd to be queried too frequently, keeping winbindd
380  busy, and blocking smbd while winbindd is busy with other
381  stuff. Written by Michael Steffens <michael.steffens@hp.com>,
382  modified to use linked lists by jra.
383 *****************************************************************/  
384
385 #define MAX_UID_SID_CACHE_SIZE 100
386 #define TURNOVER_UID_SID_CACHE_SIZE 10
387 #define MAX_GID_SID_CACHE_SIZE 100
388 #define TURNOVER_GID_SID_CACHE_SIZE 10
389
390 static size_t n_uid_sid_cache = 0;
391 static size_t n_gid_sid_cache = 0;
392
393 static struct uid_sid_cache {
394         struct uid_sid_cache *next, *prev;
395         uid_t uid;
396         DOM_SID sid;
397         enum SID_NAME_USE sidtype;
398 } *uid_sid_cache_head;
399
400 static struct gid_sid_cache {
401         struct gid_sid_cache *next, *prev;
402         gid_t gid;
403         DOM_SID sid;
404         enum SID_NAME_USE sidtype;
405 } *gid_sid_cache_head;
406
407 /*****************************************************************
408   Find a SID given a uid.
409 *****************************************************************/  
410
411 static BOOL fetch_sid_from_uid_cache(DOM_SID *psid, uid_t uid)
412 {
413         struct uid_sid_cache *pc;
414
415         for (pc = uid_sid_cache_head; pc; pc = pc->next) {
416                 if (pc->uid == uid) {
417                         *psid = pc->sid;
418                         DEBUG(3,("fetch sid from uid cache %u -> %s\n",
419                                  (unsigned int)uid, sid_string_static(psid)));
420                         DLIST_PROMOTE(uid_sid_cache_head, pc);
421                         return True;
422                 }
423         }
424         return False;
425 }
426
427 /*****************************************************************
428   Find a uid given a SID.
429 *****************************************************************/  
430
431 static BOOL fetch_uid_from_cache( uid_t *puid, const DOM_SID *psid )
432 {
433         struct uid_sid_cache *pc;
434
435         for (pc = uid_sid_cache_head; pc; pc = pc->next) {
436                 if (sid_compare(&pc->sid, psid) == 0) {
437                         *puid = pc->uid;
438                         DEBUG(3,("fetch uid from cache %u -> %s\n",
439                                  (unsigned int)*puid, sid_string_static(psid)));
440                         DLIST_PROMOTE(uid_sid_cache_head, pc);
441                         return True;
442                 }
443         }
444         return False;
445 }
446
447 /*****************************************************************
448  Store uid to SID mapping in cache.
449 *****************************************************************/  
450
451 static void store_uid_sid_cache(const DOM_SID *psid, uid_t uid)
452 {
453         struct uid_sid_cache *pc;
454
455         if (n_uid_sid_cache >= MAX_UID_SID_CACHE_SIZE && n_uid_sid_cache > TURNOVER_UID_SID_CACHE_SIZE) {
456                 /* Delete the last TURNOVER_UID_SID_CACHE_SIZE entries. */
457                 struct uid_sid_cache *pc_next;
458                 size_t i;
459
460                 for (i = 0, pc = uid_sid_cache_head; i < (n_uid_sid_cache - TURNOVER_UID_SID_CACHE_SIZE); i++, pc = pc->next)
461                         ;
462                 for(; pc; pc = pc_next) {
463                         pc_next = pc->next;
464                         DLIST_REMOVE(uid_sid_cache_head,pc);
465                         SAFE_FREE(pc);
466                         n_uid_sid_cache--;
467                 }
468         }
469
470         pc = SMB_MALLOC_P(struct uid_sid_cache);
471         if (!pc)
472                 return;
473         pc->uid = uid;
474         sid_copy(&pc->sid, psid);
475         DLIST_ADD(uid_sid_cache_head, pc);
476         n_uid_sid_cache++;
477 }
478
479 /*****************************************************************
480   Find a SID given a gid.
481 *****************************************************************/  
482
483 static BOOL fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid)
484 {
485         struct gid_sid_cache *pc;
486
487         for (pc = gid_sid_cache_head; pc; pc = pc->next) {
488                 if (pc->gid == gid) {
489                         *psid = pc->sid;
490                         DEBUG(3,("fetch sid from gid cache %u -> %s\n",
491                                  (unsigned int)gid, sid_string_static(psid)));
492                         DLIST_PROMOTE(gid_sid_cache_head, pc);
493                         return True;
494                 }
495         }
496         return False;
497 }
498
499 /*****************************************************************
500   Find a gid given a SID.
501 *****************************************************************/  
502
503 static BOOL fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid)
504 {
505         struct gid_sid_cache *pc;
506
507         for (pc = gid_sid_cache_head; pc; pc = pc->next) {
508                 if (sid_compare(&pc->sid, psid) == 0) {
509                         *pgid = pc->gid;
510                         DEBUG(3,("fetch gid from cache %u -> %s\n",
511                                  (unsigned int)*pgid, sid_string_static(psid)));
512                         DLIST_PROMOTE(gid_sid_cache_head, pc);
513                         return True;
514                 }
515         }
516         return False;
517 }
518
519 /*****************************************************************
520  Store gid to SID mapping in cache.
521 *****************************************************************/  
522
523 static void store_gid_sid_cache(const DOM_SID *psid, gid_t gid)
524 {
525         struct gid_sid_cache *pc;
526
527         if (n_gid_sid_cache >= MAX_GID_SID_CACHE_SIZE && n_gid_sid_cache > TURNOVER_GID_SID_CACHE_SIZE) {
528                 /* Delete the last TURNOVER_GID_SID_CACHE_SIZE entries. */
529                 struct gid_sid_cache *pc_next;
530                 size_t i;
531
532                 for (i = 0, pc = gid_sid_cache_head; i < (n_gid_sid_cache - TURNOVER_GID_SID_CACHE_SIZE); i++, pc = pc->next)
533                         ;
534                 for(; pc; pc = pc_next) {
535                         pc_next = pc->next;
536                         DLIST_REMOVE(gid_sid_cache_head,pc);
537                         SAFE_FREE(pc);
538                         n_gid_sid_cache--;
539                 }
540         }
541
542         pc = SMB_MALLOC_P(struct gid_sid_cache);
543         if (!pc)
544                 return;
545         pc->gid = gid;
546         sid_copy(&pc->sid, psid);
547         DLIST_ADD(gid_sid_cache_head, pc);
548         n_gid_sid_cache++;
549 }
550
551 /*****************************************************************
552  *THE CANONICAL* convert uid_t to SID function.
553 *****************************************************************/  
554
555 NTSTATUS uid_to_sid(DOM_SID *psid, uid_t uid)
556 {
557         uid_t low, high;
558
559         ZERO_STRUCTP(psid);
560
561         if (fetch_sid_from_uid_cache(psid, uid))
562                 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
563
564         /* DC's never use winbindd to resolve users outside the 
565            defined idmap range */
566
567         if ( lp_server_role()==ROLE_DOMAIN_MEMBER 
568                 || (lp_idmap_uid(&low, &high) && uid >= low && uid <= high) ) 
569         {
570                 if (winbind_uid_to_sid(psid, uid)) {
571
572                         DEBUG(10,("uid_to_sid: winbindd %u -> %s\n",
573                                   (unsigned int)uid, sid_string_static(psid)));
574
575                         if (psid)
576                                 store_uid_sid_cache(psid, uid);
577                         return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
578                 }
579         }
580
581         if (!local_uid_to_sid(psid, uid)) {
582                 DEBUG(10,("uid_to_sid: local %u failed to map to sid\n", (unsigned int)uid ));
583                 return NT_STATUS_UNSUCCESSFUL;
584         }
585         
586         DEBUG(10,("uid_to_sid: local %u -> %s\n", (unsigned int)uid,
587                   sid_string_static(psid)));
588
589         store_uid_sid_cache(psid, uid);
590         return NT_STATUS_OK;
591 }
592
593 /*****************************************************************
594  *THE CANONICAL* convert gid_t to SID function.
595 *****************************************************************/  
596
597 NTSTATUS gid_to_sid(DOM_SID *psid, gid_t gid)
598 {
599         gid_t low, high;
600
601         ZERO_STRUCTP(psid);
602
603         if (fetch_sid_from_gid_cache(psid, gid))
604                 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
605
606         /* DC's never use winbindd to resolve groups outside the
607            defined idmap range */
608
609         if ( lp_server_role()==ROLE_DOMAIN_MEMBER
610                 || (lp_idmap_gid(&low, &high) && gid >= low && gid <= high) )
611         {
612                 if (winbind_gid_to_sid(psid, gid)) {
613
614                         DEBUG(10,("gid_to_sid: winbindd %u -> %s\n",
615                                   (unsigned int)gid, sid_string_static(psid)));
616                         
617                         if (psid)
618                                 store_gid_sid_cache(psid, gid);
619                         return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
620                 }
621         }
622
623         if (!local_gid_to_sid(psid, gid)) {
624                 DEBUG(10,("gid_to_sid: local %u failed to map to sid\n", (unsigned int)gid ));
625                 return NT_STATUS_UNSUCCESSFUL;
626         }
627         
628         DEBUG(10,("gid_to_sid: local %u -> %s\n", (unsigned int)gid,
629                   sid_string_static(psid)));
630
631         store_gid_sid_cache(psid, gid);
632         return NT_STATUS_OK;
633 }
634
635 /*****************************************************************
636  *THE CANONICAL* convert SID to uid function.
637 *****************************************************************/  
638
639 NTSTATUS sid_to_uid(const DOM_SID *psid, uid_t *puid)
640 {
641         enum SID_NAME_USE name_type;
642
643         if (fetch_uid_from_cache(puid, psid))
644                 return NT_STATUS_OK;
645
646         /* if this is our SID then go straight to a local lookup */
647         
648         if ( sid_compare_domain(get_global_sam_sid(), psid) == 0 ) {
649                 DEBUG(10,("sid_to_uid: my domain (%s) - trying local.\n",
650                         sid_string_static(psid) ));
651                 
652                 if ( local_sid_to_uid(puid, psid, &name_type) )
653                         goto success;
654                         
655                 DEBUG(10,("sid_to_uid: local lookup failed\n"));
656                 
657                 return NT_STATUS_UNSUCCESSFUL;
658         }
659         
660         /* If it is not our local domain, only hope is winbindd */
661
662         if ( !winbind_lookup_sid(NULL, psid, NULL, NULL, &name_type) ) {
663                 DEBUG(10,("sid_to_uid: winbind lookup for non-local sid %s failed\n",
664                         sid_string_static(psid) ));
665                         
666                 return NT_STATUS_UNSUCCESSFUL;
667         }
668
669         /* If winbindd does know the SID, ensure this is a user */
670
671         if (name_type != SID_NAME_USER) {
672                 DEBUG(10,("sid_to_uid: winbind lookup succeeded but SID is not a user (%u)\n",
673                         (unsigned int)name_type ));
674                 return NT_STATUS_INVALID_PARAMETER;
675         }
676
677         /* get the uid.  Has to work or else we are dead in the water */
678
679         if ( !winbind_sid_to_uid(puid, psid) ) {
680                 DEBUG(10,("sid_to_uid: winbind failed to allocate a new uid for sid %s\n",
681                           sid_string_static(psid)));
682                 return NT_STATUS_UNSUCCESSFUL;
683         }
684
685 success:
686         DEBUG(10,("sid_to_uid: %s -> %u\n", sid_string_static(psid),
687                 (unsigned int)*puid ));
688
689         store_uid_sid_cache(psid, *puid);
690         
691         return NT_STATUS_OK;
692 }
693 /*****************************************************************
694  *THE CANONICAL* convert SID to gid function.
695  Group mapping is used for gids that maps to Wellknown SIDs
696 *****************************************************************/  
697
698 NTSTATUS sid_to_gid(const DOM_SID *psid, gid_t *pgid)
699 {
700         enum SID_NAME_USE name_type;
701
702         if (fetch_gid_from_cache(pgid, psid))
703                 return NT_STATUS_OK;
704
705         /*
706          * First we must look up the name and decide if this is a group sid.
707          * Group mapping can deal with foreign SIDs
708          */
709
710         if ( local_sid_to_gid(pgid, psid, &name_type) )
711                 goto success;
712         
713         if (!winbind_lookup_sid(NULL, psid, NULL, NULL, &name_type)) {
714                 DEBUG(10,("sid_to_gid: no one knows the SID %s (tried local, then "
715                           "winbind)\n", sid_string_static(psid)));
716                 
717                 return NT_STATUS_UNSUCCESSFUL;
718         }
719
720         /* winbindd knows it; Ensure this is a group sid */
721
722         if ((name_type != SID_NAME_DOM_GRP) && (name_type != SID_NAME_ALIAS) 
723                 && (name_type != SID_NAME_WKN_GRP)) 
724         {
725                 DEBUG(10,("sid_to_gid: winbind lookup succeeded but SID is not a known group (%u)\n",
726                         (unsigned int)name_type ));
727
728                 /* winbindd is running and knows about this SID.  Just the wrong type.
729                    Don't fallback to a local lookup here */
730                    
731                 return NT_STATUS_INVALID_PARAMETER;
732         }
733         
734         /* winbindd knows it and it is a type of group; sid_to_gid must succeed
735            or we are dead in the water */
736
737         if ( !winbind_sid_to_gid(pgid, psid) ) {
738                 DEBUG(10,("sid_to_gid: winbind failed to allocate a new gid for sid %s\n",
739                           sid_string_static(psid)));
740                 return NT_STATUS_UNSUCCESSFUL;
741         }
742
743 success:
744         DEBUG(10,("sid_to_gid: %s -> %u\n", sid_string_static(psid),
745                   (unsigned int)*pgid ));
746
747         store_gid_sid_cache(psid, *pgid);
748         
749         return NT_STATUS_OK;
750 }
751