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