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