r13678: Remove unneeded braces
[nivanova/samba-autobuild/.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    Copyright (C) Volker Lendecke         2005
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24
25 /*****************************************************************
26  Dissect a user-provided name into domain, name, sid and type.
27
28  If an explicit domain name was given in the form domain\user, it
29  has to try that. If no explicit domain name was given, we have
30  to do guesswork.
31 *****************************************************************/  
32
33 BOOL lookup_name(TALLOC_CTX *mem_ctx,
34                  const char *full_name, int flags,
35                  const char **ret_domain, const char **ret_name,
36                  DOM_SID *ret_sid, enum SID_NAME_USE *ret_type)
37 {
38         char *p;
39         const char *tmp;
40         const char *domain = NULL;
41         const char *name = NULL;
42         uint32 rid;
43         DOM_SID sid;
44         enum SID_NAME_USE type;
45         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
46
47         if (tmp_ctx == NULL) {
48                 DEBUG(0, ("talloc_new failed\n"));
49                 return False;
50         }
51
52         p = strchr_m(full_name, '\\');
53
54         if (p != NULL) {
55                 domain = talloc_strndup(tmp_ctx, full_name,
56                                         PTR_DIFF(p, full_name));
57                 name = talloc_strdup(tmp_ctx, p+1);
58         } else {
59                 domain = talloc_strdup(tmp_ctx, "");
60                 name = talloc_strdup(tmp_ctx, full_name);
61         }
62
63         if ((domain == NULL) || (name == NULL)) {
64                 DEBUG(0, ("talloc failed\n"));
65                 return False;
66         }
67
68         if (strequal(domain, get_global_sam_name())) {
69
70                 /* It's our own domain, lookup the name in passdb */
71                 if (lookup_global_sam_name(name, flags, &rid, &type)) {
72                         sid_copy(&sid, get_global_sam_sid());
73                         sid_append_rid(&sid, rid);
74                         goto ok;
75                 }
76                 goto failed;
77         }
78
79         if (strequal(domain, builtin_domain_name())) {
80
81                 /* Explicit request for a name in BUILTIN */
82                 if (lookup_builtin_name(name, &rid)) {
83                         sid_copy(&sid, &global_sid_Builtin);
84                         sid_append_rid(&sid, rid);
85                         type = SID_NAME_ALIAS;
86                         goto ok;
87                 }
88                 goto failed;
89         }
90
91         /* Try the explicit winbind lookup first, don't let it guess the
92          * domain yet at this point yet. This comes later. */
93
94         if ((domain[0] != '\0') &&
95             (winbind_lookup_name(domain, name, &sid, &type))) {
96                         goto ok;
97         }
98
99         if (strequal(domain, unix_users_domain_name())) {
100                 if (lookup_unix_user_name(name, &sid)) {
101                         type = SID_NAME_USER;
102                         goto ok;
103                 }
104                 goto failed;
105         }
106
107         if (strequal(domain, unix_groups_domain_name())) {
108                 if (lookup_unix_group_name(name, &sid)) {
109                         type = SID_NAME_DOM_GRP;
110                         goto ok;
111                 }
112                 goto failed;
113         }
114
115         if ((domain[0] == '\0') && (!(flags & LOOKUP_NAME_ISOLATED))) {
116                 goto failed;
117         }
118
119         /* Now the guesswork begins, we haven't been given an explicit
120          * domain. Try the sequence as documented on
121          * http://msdn.microsoft.com/library/en-us/secmgmt/security/lsalookupnames.asp
122          * November 27, 2005 */
123
124         /* 1. well-known names */
125
126         if (lookup_wellknown_name(tmp_ctx, name, &sid, &domain)) {
127                 type = SID_NAME_WKN_GRP;
128                 goto ok;
129         }
130
131         /* 2. Builtin domain as such */
132
133         if (strequal(name, builtin_domain_name())) {
134                 /* Swap domain and name */
135                 tmp = name; name = domain; domain = tmp;
136                 sid_copy(&sid, &global_sid_Builtin);
137                 type = SID_NAME_DOMAIN;
138                 goto ok;
139         }
140
141         /* 3. Account domain */
142
143         if (strequal(name, get_global_sam_name())) {
144                 if (!secrets_fetch_domain_sid(name, &sid)) {
145                         DEBUG(3, ("Could not fetch my SID\n"));
146                         goto failed;
147                 }
148                 /* Swap domain and name */
149                 tmp = name; name = domain; domain = tmp;
150                 type = SID_NAME_DOMAIN;
151                 goto ok;
152         }
153
154         /* 4. Primary domain */
155
156         if (!IS_DC && strequal(name, lp_workgroup())) {
157                 if (!secrets_fetch_domain_sid(name, &sid)) {
158                         DEBUG(3, ("Could not fetch the domain SID\n"));
159                         goto failed;
160                 }
161                 /* Swap domain and name */
162                 tmp = name; name = domain; domain = tmp;
163                 type = SID_NAME_DOMAIN;
164                 goto ok;
165         }
166
167         /* 5. Trusted domains as such, to me it looks as if members don't do
168               this, tested an XP workstation in a NT domain -- vl */
169
170         if (IS_DC && (secrets_fetch_trusted_domain_password(name, NULL,
171                                                             &sid, NULL))) {
172                 /* Swap domain and name */
173                 tmp = name; name = domain; domain = tmp;
174                 type = SID_NAME_DOMAIN;
175                 goto ok;
176         }
177
178         /* 6. Builtin aliases */        
179
180         if (lookup_builtin_name(name, &rid)) {
181                 domain = talloc_strdup(tmp_ctx, builtin_domain_name());
182                 sid_copy(&sid, &global_sid_Builtin);
183                 sid_append_rid(&sid, rid);
184                 type = SID_NAME_ALIAS;
185                 goto ok;
186         }
187
188         /* 7. Local systems' SAM (DCs don't have a local SAM) */
189         /* 8. Primary SAM (On members, this is the domain) */
190
191         /* Both cases are done by looking at our passdb */
192
193         if (lookup_global_sam_name(name, flags, &rid, &type)) {
194                 domain = talloc_strdup(tmp_ctx, get_global_sam_name());
195                 sid_copy(&sid, get_global_sam_sid());
196                 sid_append_rid(&sid, rid);
197                 goto ok;
198         }
199
200         /* Now our local possibilities are exhausted. */
201
202         if (!(flags & LOOKUP_NAME_REMOTE)) {
203                 goto failed;
204         }
205
206         /* If we are not a DC, we have to ask in our primary domain. Let
207          * winbind do that. */
208
209         if (!IS_DC &&
210             (winbind_lookup_name(lp_workgroup(), name, &sid, &type))) {
211                 domain = talloc_strdup(tmp_ctx, lp_workgroup());
212                 goto ok;
213         }
214
215         /* 9. Trusted domains */
216
217         /* If we're a DC we have to ask all trusted DC's. Winbind does not do
218          * that (yet), but give it a chance. */
219
220         if (IS_DC && winbind_lookup_name("", name, &sid, &type)) {
221                 DOM_SID dom_sid;
222                 uint32 tmp_rid;
223                 enum SID_NAME_USE domain_type;
224                 
225                 if (type == SID_NAME_DOMAIN) {
226                         /* Swap name and type */
227                         tmp = name; name = domain; domain = tmp;
228                         goto ok;
229                 }
230
231                 /* Here we have to cope with a little deficiency in the
232                  * winbind API: We have to ask it again for the name of the
233                  * domain it figured out itself. Maybe fix that later... */
234
235                 sid_copy(&dom_sid, &sid);
236                 sid_split_rid(&dom_sid, &tmp_rid);
237
238                 if (!winbind_lookup_sid(tmp_ctx, &dom_sid, &domain, NULL,
239                                         &domain_type) ||
240                     (domain_type != SID_NAME_DOMAIN)) {
241                         DEBUG(2, ("winbind could not find the domain's name "
242                                   "it just looked up for us\n"));
243                         goto failed;
244                 }
245                 goto ok;
246         }
247
248         /* 10. Don't translate */
249
250         /* 11. Ok, windows would end here. Samba has two more options:
251                Unmapped users and unmapped groups */
252
253         if (lookup_unix_user_name(name, &sid)) {
254                 domain = talloc_strdup(tmp_ctx, unix_users_domain_name());
255                 type = SID_NAME_USER;
256                 goto ok;
257         }
258
259         if (lookup_unix_group_name(name, &sid)) {
260                 domain = talloc_strdup(tmp_ctx, unix_groups_domain_name());
261                 type = SID_NAME_DOM_GRP;
262                 goto ok;
263         }
264
265  failed:
266         TALLOC_FREE(tmp_ctx);
267         return False;
268
269  ok:
270         if ((domain == NULL) || (name == NULL)) {
271                 DEBUG(0, ("talloc failed\n"));
272                 TALLOC_FREE(tmp_ctx);
273                 return False;
274         }
275
276         if (ret_name != NULL) {
277                 *ret_name = talloc_steal(mem_ctx, name);
278         }
279
280         if (ret_domain != NULL) {
281                 char *tmp_dom = talloc_strdup(tmp_ctx, domain);
282                 strupper_m(tmp_dom);
283                 *ret_domain = talloc_steal(mem_ctx, tmp_dom);
284         }
285
286         if (ret_sid != NULL) {
287                 sid_copy(ret_sid, &sid);
288         }
289
290         if (ret_type != NULL) {
291                 *ret_type = type;
292         }
293
294         TALLOC_FREE(tmp_ctx);
295         return True;
296 }
297
298 static BOOL winbind_lookup_rids(TALLOC_CTX *mem_ctx,
299                                 const DOM_SID *domain_sid,
300                                 int num_rids, uint32 *rids,
301                                 const char **domain_name,
302                                 const char **names, uint32 *types)
303 {
304         /* Unless the winbind interface is upgraded, fall back to ask for
305          * individual sids. I imagine introducing a lookuprids operation that
306          * directly proxies to lsa_lookupsids to the correct DC. -- vl */
307
308         int i;
309         for (i=0; i<num_rids; i++) {
310                 DOM_SID sid;
311
312                 sid_copy(&sid, domain_sid);
313                 sid_append_rid(&sid, rids[i]);
314
315                 if (winbind_lookup_sid(mem_ctx, &sid,
316                                        *domain_name == NULL ?
317                                        domain_name : NULL,
318                                        &names[i], &types[i])) {
319                         if ((names[i] == NULL) || ((*domain_name) == NULL)) {
320                                 return False;
321                         }
322                 } else {
323                         types[i] = SID_NAME_UNKNOWN;
324                 }
325         }
326         return True;
327 }
328
329 static BOOL lookup_rids(TALLOC_CTX *mem_ctx, const DOM_SID *domain_sid,
330                         int num_rids, uint32_t *rids,
331                         const char **domain_name,
332                         const char ***names, enum SID_NAME_USE **types)
333 {
334         int i;
335
336         *names = TALLOC_ARRAY(mem_ctx, const char *, num_rids);
337         *types = TALLOC_ARRAY(mem_ctx, enum SID_NAME_USE, num_rids);
338
339         if ((*names == NULL) || (*types == NULL)) {
340                 return False;
341         }
342
343         if (sid_check_is_domain(domain_sid)) {
344                 NTSTATUS result;
345
346                 if (*domain_name == NULL) {
347                         *domain_name = talloc_strdup(
348                                 mem_ctx, get_global_sam_name());
349                 }
350
351                 if (*domain_name == NULL) {
352                         return False;
353                 }
354
355                 become_root();
356                 result = pdb_lookup_rids(domain_sid, num_rids, rids,
357                                          *names, *types);
358                 unbecome_root();
359
360                 return (NT_STATUS_IS_OK(result) ||
361                         NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED) ||
362                         NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED));
363         }
364
365         if (sid_check_is_builtin(domain_sid)) {
366
367                 if (*domain_name == NULL) {
368                         *domain_name = talloc_strdup(
369                                 mem_ctx, builtin_domain_name());
370                 }
371
372                 if (*domain_name == NULL) {
373                         return False;
374                 }
375
376                 for (i=0; i<num_rids; i++) {
377                         if (lookup_builtin_rid(*names, rids[i],
378                                                &(*names)[i])) {
379                                 if ((*names)[i] == NULL) {
380                                         return False;
381                                 }
382                                 (*types)[i] = SID_NAME_ALIAS;
383                         } else {
384                                 (*types)[i] = SID_NAME_UNKNOWN;
385                         }
386                 }
387                 return True;
388         }
389
390         if (sid_check_is_wellknown_domain(domain_sid, NULL)) {
391                 for (i=0; i<num_rids; i++) {
392                         DOM_SID sid;
393                         sid_copy(&sid, domain_sid);
394                         sid_append_rid(&sid, rids[i]);
395                         if (lookup_wellknown_sid(mem_ctx, &sid,
396                                                  domain_name, &(*names)[i])) {
397                                 if ((*names)[i] == NULL) {
398                                         return False;
399                                 }
400                                 (*types)[i] = SID_NAME_WKN_GRP;
401                         } else {
402                                 (*types)[i] = SID_NAME_UNKNOWN;
403                         }
404                 }
405                 return True;
406         }
407
408         if (sid_check_is_unix_users(domain_sid)) {
409                 if (*domain_name == NULL) {
410                         *domain_name = talloc_strdup(
411                                 mem_ctx, unix_users_domain_name());
412                 }
413                 for (i=0; i<num_rids; i++) {
414                         (*names)[i] = talloc_strdup(
415                                 (*names), uidtoname(rids[i]));
416                         (*types)[i] = SID_NAME_USER;
417                 }
418                 return True;
419         }
420
421         if (sid_check_is_unix_groups(domain_sid)) {
422                 if (*domain_name == NULL) {
423                         *domain_name = talloc_strdup(
424                                 mem_ctx, unix_groups_domain_name());
425                 }
426                 for (i=0; i<num_rids; i++) {
427                         (*names)[i] = talloc_strdup(
428                                 (*names), gidtoname(rids[i]));
429                         (*types)[i] = SID_NAME_DOM_GRP;
430                 }
431                 return True;
432         }
433
434         return winbind_lookup_rids(mem_ctx, domain_sid, num_rids, rids,
435                                    domain_name, *names, *types);
436 }
437
438 /*
439  * Is the SID a domain as such? If yes, lookup its name.
440  */
441
442 static BOOL lookup_as_domain(const DOM_SID *sid, TALLOC_CTX *mem_ctx,
443                              const char **name)
444 {
445         const char *tmp;
446         enum SID_NAME_USE type;
447
448         if (sid_check_is_domain(sid)) {
449                 *name = talloc_strdup(mem_ctx, get_global_sam_name());
450                 return True;
451         }
452
453         if (sid_check_is_builtin(sid)) {
454                 *name = talloc_strdup(mem_ctx, builtin_domain_name());
455                 return True;
456         }
457
458         if (sid_check_is_wellknown_domain(sid, &tmp)) {
459                 *name = talloc_strdup(mem_ctx, tmp);
460                 return True;
461         }
462
463         if (sid->num_auths != 4) {
464                 /* This can't be a domain */
465                 return False;
466         }
467
468         if (IS_DC) {
469                 uint32 i, num_domains;
470                 struct trustdom_info **domains;
471
472                 /* This is relatively expensive, but it happens only on DCs
473                  * and for SIDs that have 4 sub-authorities and thus look like
474                  * domains */
475
476                 if (!NT_STATUS_IS_OK(secrets_trusted_domains(mem_ctx,
477                                                              &num_domains,
478                                                              &domains))) {
479                         return False;
480                 }
481
482                 for (i=0; i<num_domains; i++) {
483                         if (sid_equal(sid, &domains[i]->sid)) {
484                                 *name = talloc_strdup(mem_ctx,
485                                                       domains[i]->name);
486                                 return True;
487                         }
488                 }
489                 return False;
490         }
491
492         if (winbind_lookup_sid(mem_ctx, sid, &tmp, NULL, &type) &&
493             (type == SID_NAME_DOMAIN)) {
494                 *name = tmp;
495                 return True;
496         }
497
498         return False;
499 }
500
501 /*
502  * This tries to implement the rather weird rules for the lsa_lookup level
503  * parameter.
504  *
505  * This is as close as we can get to what W2k3 does. With this we survive the
506  * RPC-LSALOOKUP samba4 test as of 2006-01-08. NT4 as a PDC is a bit more
507  * different, but I assume that's just being too liberal. For example, W2k3
508  * replies to everything else but the levels 1-6 with INVALID_PARAMETER
509  * whereas NT4 does the same as level 1 (I think). I did not fully test that
510  * with NT4, this is what w2k3 does.
511  *
512  * Level 1: Ask everywhere
513  * Level 2: Ask domain and trusted domains, no builtin and wkn
514  * Level 3: Only ask domain
515  * Level 4: W2k3ad: Only ask AD trusts
516  * Level 5: Don't lookup anything
517  * Level 6: Like 4
518  */
519
520 static BOOL check_dom_sid_to_level(const DOM_SID *sid, int level)
521 {
522         int ret = False;
523
524         switch(level) {
525         case 1:
526                 ret = True;
527                 break;
528         case 2:
529                 ret = (!sid_check_is_builtin(sid) &&
530                        !sid_check_is_wellknown_domain(sid, NULL));
531                 break;
532         case 3:
533         case 4:
534         case 6:
535                 ret = sid_check_is_domain(sid);
536                 break;
537         case 5:
538                 ret = False;
539                 break;
540         }
541
542         DEBUG(10, ("%s SID %s in level %d\n",
543                    ret ? "Accepting" : "Rejecting",
544                    sid_string_static(sid), level));
545         return ret;
546 }
547
548 /*
549  * Lookup a bunch of SIDs. This is modeled after lsa_lookup_sids with
550  * references to domains, it is explicitly made for this.
551  *
552  * This attempts to be as efficient as possible: It collects all SIDs
553  * belonging to a domain and hands them in bulk to the appropriate lookup
554  * function. In particular pdb_lookup_rids with ldapsam_trusted benefits
555  * *hugely* from this. Winbind is going to be extended with a lookup_rids
556  * interface as well, so on a DC we can do a bulk lsa_lookuprids to the
557  * appropriate DC.
558  */
559
560 NTSTATUS lookup_sids(TALLOC_CTX *mem_ctx, int num_sids,
561                      const DOM_SID **sids, int level,
562                      struct lsa_dom_info **ret_domains,
563                      struct lsa_name_info **ret_names)
564 {
565         TALLOC_CTX *tmp_ctx;
566         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
567         struct lsa_name_info *name_infos;
568         struct lsa_dom_info *dom_infos;
569
570         int i, j;
571
572         tmp_ctx = talloc_new(mem_ctx);
573         if (tmp_ctx == NULL) {
574                 DEBUG(0, ("talloc_new failed\n"));
575                 return NT_STATUS_NO_MEMORY;
576         }
577
578         name_infos = TALLOC_ARRAY(tmp_ctx, struct lsa_name_info, num_sids);
579         dom_infos = TALLOC_ZERO_ARRAY(tmp_ctx, struct lsa_dom_info,
580                                       MAX_REF_DOMAINS);
581         if ((name_infos == NULL) || (dom_infos == NULL)) {
582                 result = NT_STATUS_NO_MEMORY;
583                 goto done;
584         }
585
586         /* First build up the data structures:
587          * 
588          * dom_infos is a list of domains referenced in the list of
589          * SIDs. Later we will walk the list of domains and look up the RIDs
590          * in bulk.
591          *
592          * name_infos is a shadow-copy of the SIDs array to collect the real
593          * data.
594          *
595          * dom_info->idxs is an index into the name_infos array. The
596          * difficulty we have here is that we need to keep the SIDs the client
597          * asked for in the same order for the reply
598          */
599
600         for (i=0; i<num_sids; i++) {
601                 DOM_SID sid;
602                 uint32 rid;
603                 const char *domain_name = NULL;
604
605                 sid_copy(&sid, sids[i]);
606                 name_infos[i].type = SID_NAME_USE_NONE;
607
608                 if (lookup_as_domain(&sid, name_infos, &domain_name)) {
609                         /* We can't push that through the normal lookup
610                          * process, as this would reference illegal
611                          * domains.
612                          *
613                          * For example S-1-5-32 would end up referencing
614                          * domain S-1-5- with RID 32 which is clearly wrong.
615                          */
616                         if (domain_name == NULL) {
617                                 result = NT_STATUS_NO_MEMORY;
618                                 goto done;
619                         }
620                                 
621                         name_infos[i].rid = 0;
622                         name_infos[i].type = SID_NAME_DOMAIN;
623                         name_infos[i].name = NULL;
624
625                         if (sid_check_is_builtin(&sid)) {
626                                 /* Yes, W2k3 returns "BUILTIN" both as domain
627                                  * and name here */
628                                 name_infos[i].name = talloc_strdup(
629                                         name_infos, builtin_domain_name());
630                                 if (name_infos[i].name == NULL) {
631                                         result = NT_STATUS_NO_MEMORY;
632                                         goto done;
633                                 }
634                         }
635                 } else {
636                         /* This is a normal SID with rid component */
637                         if (!sid_split_rid(&sid, &rid)) {
638                                 result = NT_STATUS_INVALID_PARAMETER;
639                                 goto done;
640                         }
641                 }
642
643                 if (!check_dom_sid_to_level(&sid, level)) {
644                         name_infos[i].rid = 0;
645                         name_infos[i].type = SID_NAME_UNKNOWN;
646                         name_infos[i].name = NULL;
647                         continue;
648                 }
649
650                 for (j=0; j<MAX_REF_DOMAINS; j++) {
651                         if (!dom_infos[j].valid) {
652                                 break;
653                         }
654                         if (sid_equal(&sid, &dom_infos[j].sid)) {
655                                 break;
656                         }
657                 }
658
659                 if (j == MAX_REF_DOMAINS) {
660                         /* TODO: What's the right error message here? */
661                         result = NT_STATUS_NONE_MAPPED;
662                         goto done;
663                 }
664
665                 if (!dom_infos[j].valid) {
666                         /* We found a domain not yet referenced, create a new
667                          * ref. */
668                         dom_infos[j].valid = True;
669                         sid_copy(&dom_infos[j].sid, &sid);
670
671                         if (domain_name != NULL) {
672                                 /* This name was being found above in the case
673                                  * when we found a domain SID */
674                                 dom_infos[j].name =
675                                         talloc_steal(dom_infos, domain_name);
676                         } else {
677                                 /* lookup_rids will take care of this */
678                                 dom_infos[j].name = NULL;
679                         }
680                 }
681
682                 name_infos[i].dom_idx = j;
683
684                 if (name_infos[i].type == SID_NAME_USE_NONE) {
685                         name_infos[i].rid = rid;
686
687                         ADD_TO_ARRAY(dom_infos, int, i, &dom_infos[j].idxs,
688                                      &dom_infos[j].num_idxs);
689
690                         if (dom_infos[j].idxs == NULL) {
691                                 result = NT_STATUS_NO_MEMORY;
692                                 goto done;
693                         }
694                 }
695         }
696
697         /* Iterate over the domains found */
698
699         for (i=0; i<MAX_REF_DOMAINS; i++) {
700                 uint32_t *rids;
701                 const char **names;
702                 enum SID_NAME_USE *types;
703                 struct lsa_dom_info *dom = &dom_infos[i];
704
705                 if (!dom->valid) {
706                         /* No domains left, we're done */
707                         break;
708                 }
709
710                 rids = TALLOC_ARRAY(tmp_ctx, uint32, dom->num_idxs);
711
712                 if (rids == NULL) {
713                         result = NT_STATUS_NO_MEMORY;
714                         goto done;
715                 }
716
717                 for (j=0; j<dom->num_idxs; j++) {
718                         rids[j] = name_infos[dom->idxs[j]].rid;
719                 }
720
721                 if (!lookup_rids(tmp_ctx, &dom->sid,
722                                  dom->num_idxs, rids, &dom->name,
723                                  &names, &types)) {
724                         result = NT_STATUS_NO_MEMORY;
725                         goto done;
726                 }
727
728                 talloc_steal(dom_infos, dom->name);
729
730                 for (j=0; j<dom->num_idxs; j++) {
731                         int idx = dom->idxs[j];
732                         name_infos[idx].type = types[j];
733                         if (types[j] != SID_NAME_UNKNOWN) {
734                                 name_infos[idx].name =
735                                         talloc_steal(name_infos, names[j]);
736                         } else {
737                                 name_infos[idx].name = NULL;
738                         }
739                 }
740         }
741
742         *ret_domains = talloc_steal(mem_ctx, dom_infos);
743         *ret_names = talloc_steal(mem_ctx, name_infos);
744         result = NT_STATUS_OK;
745
746  done:
747         TALLOC_FREE(tmp_ctx);
748         return result;
749 }
750
751 /*****************************************************************
752  *THE CANONICAL* convert SID to name function.
753 *****************************************************************/  
754
755 BOOL lookup_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
756                 const char **ret_domain, const char **ret_name,
757                 enum SID_NAME_USE *ret_type)
758 {
759         struct lsa_dom_info *domain;
760         struct lsa_name_info *name;
761         TALLOC_CTX *tmp_ctx;
762         BOOL ret = False;
763
764         tmp_ctx = talloc_new(mem_ctx);
765
766         if (tmp_ctx == NULL) {
767                 DEBUG(0, ("talloc_new failed\n"));
768                 return False;
769         }
770
771         if (!NT_STATUS_IS_OK(lookup_sids(tmp_ctx, 1, &sid, 1,
772                                          &domain, &name))) {
773                 goto done;
774         }
775
776         if (name->type == SID_NAME_UNKNOWN) {
777                 goto done;
778         }
779
780         if (ret_domain != NULL) {
781                 *ret_domain = talloc_steal(mem_ctx, domain->name);
782         }
783
784         if (ret_name != NULL) {
785                 *ret_name = talloc_steal(mem_ctx, name->name);
786         }
787
788         if (ret_type != NULL) {
789                 *ret_type = name->type;
790         }
791
792         ret = True;
793
794  done:
795         if (ret) {
796                 DEBUG(10, ("Sid %s -> %s\\%s(%d)\n",
797                            sid_string_static(sid), domain->name,
798                            name->name, name->type));
799         } else {
800                 DEBUG(10, ("failed to lookup sid %s\n",
801                            sid_string_static(sid)));
802         }
803         TALLOC_FREE(tmp_ctx);
804         return ret;
805 }
806
807 /*****************************************************************
808  Id mapping cache.  This is to avoid Winbind mappings already
809  seen by smbd to be queried too frequently, keeping winbindd
810  busy, and blocking smbd while winbindd is busy with other
811  stuff. Written by Michael Steffens <michael.steffens@hp.com>,
812  modified to use linked lists by jra.
813 *****************************************************************/  
814
815 #define MAX_UID_SID_CACHE_SIZE 100
816 #define TURNOVER_UID_SID_CACHE_SIZE 10
817 #define MAX_GID_SID_CACHE_SIZE 100
818 #define TURNOVER_GID_SID_CACHE_SIZE 10
819
820 static size_t n_uid_sid_cache = 0;
821 static size_t n_gid_sid_cache = 0;
822
823 static struct uid_sid_cache {
824         struct uid_sid_cache *next, *prev;
825         uid_t uid;
826         DOM_SID sid;
827         enum SID_NAME_USE sidtype;
828 } *uid_sid_cache_head;
829
830 static struct gid_sid_cache {
831         struct gid_sid_cache *next, *prev;
832         gid_t gid;
833         DOM_SID sid;
834         enum SID_NAME_USE sidtype;
835 } *gid_sid_cache_head;
836
837 /*****************************************************************
838   Find a SID given a uid.
839 *****************************************************************/  
840
841 static BOOL fetch_sid_from_uid_cache(DOM_SID *psid, uid_t uid)
842 {
843         struct uid_sid_cache *pc;
844
845         for (pc = uid_sid_cache_head; pc; pc = pc->next) {
846                 if (pc->uid == uid) {
847                         *psid = pc->sid;
848                         DEBUG(3,("fetch sid from uid cache %u -> %s\n",
849                                  (unsigned int)uid, sid_string_static(psid)));
850                         DLIST_PROMOTE(uid_sid_cache_head, pc);
851                         return True;
852                 }
853         }
854         return False;
855 }
856
857 /*****************************************************************
858   Find a uid given a SID.
859 *****************************************************************/  
860
861 static BOOL fetch_uid_from_cache( uid_t *puid, const DOM_SID *psid )
862 {
863         struct uid_sid_cache *pc;
864
865         for (pc = uid_sid_cache_head; pc; pc = pc->next) {
866                 if (sid_compare(&pc->sid, psid) == 0) {
867                         *puid = pc->uid;
868                         DEBUG(3,("fetch uid from cache %u -> %s\n",
869                                  (unsigned int)*puid, sid_string_static(psid)));
870                         DLIST_PROMOTE(uid_sid_cache_head, pc);
871                         return True;
872                 }
873         }
874         return False;
875 }
876
877 /*****************************************************************
878  Store uid to SID mapping in cache.
879 *****************************************************************/  
880
881 void store_uid_sid_cache(const DOM_SID *psid, uid_t uid)
882 {
883         struct uid_sid_cache *pc;
884
885         if (n_uid_sid_cache >= MAX_UID_SID_CACHE_SIZE && n_uid_sid_cache > TURNOVER_UID_SID_CACHE_SIZE) {
886                 /* Delete the last TURNOVER_UID_SID_CACHE_SIZE entries. */
887                 struct uid_sid_cache *pc_next;
888                 size_t i;
889
890                 for (i = 0, pc = uid_sid_cache_head; i < (n_uid_sid_cache - TURNOVER_UID_SID_CACHE_SIZE); i++, pc = pc->next)
891                         ;
892                 for(; pc; pc = pc_next) {
893                         pc_next = pc->next;
894                         DLIST_REMOVE(uid_sid_cache_head,pc);
895                         SAFE_FREE(pc);
896                         n_uid_sid_cache--;
897                 }
898         }
899
900         pc = SMB_MALLOC_P(struct uid_sid_cache);
901         if (!pc)
902                 return;
903         pc->uid = uid;
904         sid_copy(&pc->sid, psid);
905         DLIST_ADD(uid_sid_cache_head, pc);
906         n_uid_sid_cache++;
907 }
908
909 /*****************************************************************
910   Find a SID given a gid.
911 *****************************************************************/  
912
913 static BOOL fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid)
914 {
915         struct gid_sid_cache *pc;
916
917         for (pc = gid_sid_cache_head; pc; pc = pc->next) {
918                 if (pc->gid == gid) {
919                         *psid = pc->sid;
920                         DEBUG(3,("fetch sid from gid cache %u -> %s\n",
921                                  (unsigned int)gid, sid_string_static(psid)));
922                         DLIST_PROMOTE(gid_sid_cache_head, pc);
923                         return True;
924                 }
925         }
926         return False;
927 }
928
929 /*****************************************************************
930   Find a gid given a SID.
931 *****************************************************************/  
932
933 static BOOL fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid)
934 {
935         struct gid_sid_cache *pc;
936
937         for (pc = gid_sid_cache_head; pc; pc = pc->next) {
938                 if (sid_compare(&pc->sid, psid) == 0) {
939                         *pgid = pc->gid;
940                         DEBUG(3,("fetch gid from cache %u -> %s\n",
941                                  (unsigned int)*pgid, sid_string_static(psid)));
942                         DLIST_PROMOTE(gid_sid_cache_head, pc);
943                         return True;
944                 }
945         }
946         return False;
947 }
948
949 /*****************************************************************
950  Store gid to SID mapping in cache.
951 *****************************************************************/  
952
953 void store_gid_sid_cache(const DOM_SID *psid, gid_t gid)
954 {
955         struct gid_sid_cache *pc;
956
957         if (n_gid_sid_cache >= MAX_GID_SID_CACHE_SIZE && n_gid_sid_cache > TURNOVER_GID_SID_CACHE_SIZE) {
958                 /* Delete the last TURNOVER_GID_SID_CACHE_SIZE entries. */
959                 struct gid_sid_cache *pc_next;
960                 size_t i;
961
962                 for (i = 0, pc = gid_sid_cache_head; i < (n_gid_sid_cache - TURNOVER_GID_SID_CACHE_SIZE); i++, pc = pc->next)
963                         ;
964                 for(; pc; pc = pc_next) {
965                         pc_next = pc->next;
966                         DLIST_REMOVE(gid_sid_cache_head,pc);
967                         SAFE_FREE(pc);
968                         n_gid_sid_cache--;
969                 }
970         }
971
972         pc = SMB_MALLOC_P(struct gid_sid_cache);
973         if (!pc)
974                 return;
975         pc->gid = gid;
976         sid_copy(&pc->sid, psid);
977         DLIST_ADD(gid_sid_cache_head, pc);
978         n_gid_sid_cache++;
979 }
980
981 /*****************************************************************
982  *THE CANONICAL* convert uid_t to SID function.
983 *****************************************************************/  
984
985 void uid_to_sid(DOM_SID *psid, uid_t uid)
986 {
987         uid_t low, high;
988         uint32 rid;
989
990         ZERO_STRUCTP(psid);
991
992         if (fetch_sid_from_uid_cache(psid, uid))
993                 return;
994
995         if (lp_idmap_uid(&low, &high) && (uid >= low) && (uid <= high) &&
996             winbind_uid_to_sid(psid, uid)) {
997
998                 DEBUG(10,("uid_to_sid: winbindd %u -> %s\n",
999                           (unsigned int)uid, sid_string_static(psid)));
1000                 goto done;
1001         }
1002
1003         if (pdb_uid_to_rid(uid, &rid)) {
1004                 /* This is a mapped user */
1005                 sid_copy(psid, get_global_sam_sid());
1006                 sid_append_rid(psid, rid);
1007                 goto done;
1008         }
1009
1010         if (pdb_rid_algorithm() && (uid < max_algorithmic_uid())) {
1011                 sid_copy(psid, get_global_sam_sid());
1012                 sid_append_rid(psid, algorithmic_pdb_uid_to_user_rid(uid));
1013                 goto done;
1014         } else {
1015                 sid_copy(psid, &global_sid_Unix_Users);
1016                 sid_append_rid(psid, uid);
1017                 goto done;
1018         }
1019
1020  done:
1021         DEBUG(10,("uid_to_sid: local %u -> %s\n", (unsigned int)uid,
1022                   sid_string_static(psid)));
1023
1024         store_uid_sid_cache(psid, uid);
1025         return;
1026 }
1027
1028 /*****************************************************************
1029  *THE CANONICAL* convert gid_t to SID function.
1030 *****************************************************************/  
1031
1032 void gid_to_sid(DOM_SID *psid, gid_t gid)
1033 {
1034         gid_t low, high;
1035
1036         ZERO_STRUCTP(psid);
1037
1038         if (fetch_sid_from_gid_cache(psid, gid))
1039                 return;
1040
1041         if (lp_idmap_gid(&low, &high) && (gid >= low) && (gid <= high) &&
1042             winbind_gid_to_sid(psid, gid)) {
1043
1044                 DEBUG(10,("gid_to_sid: winbindd %u -> %s\n",
1045                           (unsigned int)gid, sid_string_static(psid)));
1046                 goto done;
1047         }
1048
1049         if (pdb_gid_to_sid(gid, psid)) {
1050                 /* This is a mapped group */
1051                 goto done;
1052         }
1053
1054         if (pdb_rid_algorithm() && (gid < max_algorithmic_gid())) {
1055                 sid_copy(psid, get_global_sam_sid());
1056                 sid_append_rid(psid, pdb_gid_to_group_rid(gid));
1057                 goto done;
1058         } else {
1059                 sid_copy(psid, &global_sid_Unix_Groups);
1060                 sid_append_rid(psid, gid);
1061                 goto done;
1062         }
1063
1064  done:
1065         DEBUG(10,("gid_to_sid: local %u -> %s\n", (unsigned int)gid,
1066                   sid_string_static(psid)));
1067
1068         store_gid_sid_cache(psid, gid);
1069         return;
1070 }
1071
1072 /*****************************************************************
1073  *THE CANONICAL* convert SID to uid function.
1074 *****************************************************************/  
1075
1076 BOOL sid_to_uid(const DOM_SID *psid, uid_t *puid)
1077 {
1078         enum SID_NAME_USE type;
1079         uint32 rid;
1080         gid_t gid;
1081
1082         if (fetch_uid_from_cache(puid, psid))
1083                 return True;
1084
1085         if (fetch_gid_from_cache(&gid, psid)) {
1086                 return False;
1087         }
1088
1089         if (sid_peek_check_rid(&global_sid_Unix_Users, psid, &rid)) {
1090                 uid_t uid = rid;
1091                 *puid = uid;
1092                 goto done;
1093         }
1094
1095         if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) {
1096                 union unid_t id;
1097
1098                 if (pdb_sid_to_id(psid, &id, &type)) {
1099                         if (type != SID_NAME_USER) {
1100                                 DEBUG(5, ("sid %s is a %s, expected a user\n",
1101                                           sid_string_static(psid),
1102                                           sid_type_lookup(type)));
1103                                 return False;
1104                         }
1105                         *puid = id.uid;
1106                         goto done;
1107                 }
1108                 if (pdb_rid_algorithm() &&
1109                     algorithmic_pdb_rid_is_user(rid)) {
1110                         *puid = algorithmic_pdb_user_rid_to_uid(rid);
1111                         goto done;
1112                 }
1113
1114                 /* This was ours, but it was neither mapped nor
1115                  * algorithmic. Fail */
1116                 return False;
1117         }
1118
1119         if (winbind_lookup_sid(NULL, psid, NULL, NULL, &type)) {
1120
1121                 if (type != SID_NAME_USER) {
1122                         DEBUG(10, ("sid_to_uid: sid %s is a %s\n",
1123                                    sid_string_static(psid),
1124                                    sid_type_lookup(type)));
1125                         return False;
1126                 }
1127
1128                 if (!winbind_sid_to_uid(puid, psid)) {
1129                         DEBUG(5, ("sid_to_uid: winbind failed to allocate a "
1130                                   "new uid for sid %s\n",
1131                                   sid_string_static(psid)));
1132                         return False;
1133                 }
1134                 goto done;
1135         }
1136
1137         /* TODO: Here would be the place to allocate both a gid and a uid for
1138          * the SID in question */
1139
1140         return False;
1141
1142  done:
1143         DEBUG(10,("sid_to_uid: %s -> %u\n", sid_string_static(psid),
1144                 (unsigned int)*puid ));
1145
1146         store_uid_sid_cache(psid, *puid);
1147         return True;
1148 }
1149
1150 /*****************************************************************
1151  *THE CANONICAL* convert SID to gid function.
1152  Group mapping is used for gids that maps to Wellknown SIDs
1153 *****************************************************************/  
1154
1155 BOOL sid_to_gid(const DOM_SID *psid, gid_t *pgid)
1156 {
1157         uint32 rid;
1158         GROUP_MAP map;
1159         union unid_t id;
1160         enum SID_NAME_USE type;
1161         uid_t uid;
1162
1163         if (fetch_gid_from_cache(pgid, psid))
1164                 return True;
1165
1166         if (fetch_uid_from_cache(&uid, psid))
1167                 return False;
1168
1169         if (sid_peek_check_rid(&global_sid_Unix_Groups, psid, &rid)) {
1170                 gid_t gid = rid;
1171                 *pgid = gid;
1172                 goto done;
1173         }
1174
1175         if (sid_check_is_in_builtin(psid) && pdb_getgrsid(&map, *psid)) {
1176                 *pgid = map.gid;
1177                 goto done;
1178         }
1179
1180         if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) {
1181                 if (pdb_sid_to_id(psid, &id, &type)) {
1182                         if ((type != SID_NAME_DOM_GRP) &&
1183                             (type != SID_NAME_ALIAS)) {
1184                                 DEBUG(5, ("sid %s is a %s, expected a group\n",
1185                                           sid_string_static(psid),
1186                                           sid_type_lookup(type)));
1187                                 return False;
1188                         }
1189                         *pgid = id.gid;
1190                         goto done;
1191                 }
1192                 if (pdb_rid_algorithm() &&
1193                     !algorithmic_pdb_rid_is_user(rid)) {
1194                         /* This must be a group, presented as alias */
1195                         *pgid = pdb_group_rid_to_gid(rid);
1196                         goto done;
1197                 }
1198                 /* This was ours, but it was neither mapped nor
1199                  * algorithmic. Fail. */
1200                 return False;
1201         }
1202         
1203         if (!winbind_lookup_sid(NULL, psid, NULL, NULL, &type)) {
1204                 DEBUG(11,("sid_to_gid: no one knows the SID %s (tried local, "
1205                           "then winbind)\n", sid_string_static(psid)));
1206                 
1207                 return False;
1208         }
1209
1210         /* winbindd knows it; Ensure this is a group sid */
1211
1212         if ((type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) &&
1213             (type != SID_NAME_WKN_GRP)) {
1214                 DEBUG(10,("sid_to_gid: winbind lookup succeeded but SID is "
1215                           "a %s\n", sid_type_lookup(type)));
1216                 return False;
1217         }
1218         
1219         /* winbindd knows it and it is a type of group; sid_to_gid must succeed
1220            or we are dead in the water */
1221
1222         if ( !winbind_sid_to_gid(pgid, psid) ) {
1223                 DEBUG(10,("sid_to_gid: winbind failed to allocate a new gid "
1224                           "for sid %s\n", sid_string_static(psid)));
1225                 return False;
1226         }
1227
1228  done:
1229         DEBUG(10,("sid_to_gid: %s -> %u\n", sid_string_static(psid),
1230                   (unsigned int)*pgid ));
1231
1232         store_gid_sid_cache(psid, *pgid);
1233         
1234         return True;
1235 }
1236