r22173: BUG 4491, 4501: Additional fixes for protecting against
[kai/samba.git] / source3 / nsswitch / idmap.c
1 /* 
2    Unix SMB/CIFS implementation.
3    ID Mapping
4    Copyright (C) Tim Potter 2000
5    Copyright (C) Jim McDonough <jmcd@us.ibm.com>        2003
6    Copyright (C) Simo Sorce 2003
7    Copyright (C) Jeremy Allison 2006
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25 #include "winbindd.h"
26
27 #undef DBGC_CLASS
28 #define DBGC_CLASS DBGC_IDMAP
29
30 static_decl_idmap;
31
32 struct idmap_backend {
33         const char *name;
34         struct idmap_methods *methods;
35         struct idmap_backend *prev, *next;
36 };
37
38 struct idmap_alloc_backend {
39         const char *name;
40         struct idmap_alloc_methods *methods;
41         struct idmap_alloc_backend *prev, *next;
42 };
43
44 struct idmap_cache_ctx;
45
46 static TALLOC_CTX *idmap_ctx = NULL;
47 static struct idmap_cache_ctx *idmap_cache;
48
49 static struct idmap_backend *backends = NULL;
50 static struct idmap_domain **idmap_domains = NULL;
51 static int num_domains = 0;
52 static int pdb_dom_num = -1;
53 static int def_dom_num = -1;
54
55 static struct idmap_alloc_backend *alloc_backends = NULL;
56 static struct idmap_alloc_methods *alloc_methods = NULL;
57
58 #define IDMAP_CHECK_RET(ret) do { if ( ! NT_STATUS_IS_OK(ret)) { DEBUG(2, ("ERROR: NTSTATUS = 0x%08x\n", NT_STATUS_V(ret))); goto done; } } while(0)
59 #define IDMAP_CHECK_ALLOC(mem) do { if (!mem) { DEBUG(0, ("Out of memory!\n")); ret = NT_STATUS_NO_MEMORY; goto done; } } while(0)
60
61 static struct idmap_methods *get_methods(struct idmap_backend *be, const char *name)
62 {
63         struct idmap_backend *b;
64
65         for (b = be; b; b = b->next) {
66                 if (strequal(b->name, name)) {
67                         return b->methods;
68                 }
69         }
70
71         return NULL;
72 }
73
74 static struct idmap_alloc_methods *get_alloc_methods(struct idmap_alloc_backend *be, const char *name)
75 {
76         struct idmap_alloc_backend *b;
77
78         for (b = be; b; b = b->next) {
79                 if (strequal(b->name, name)) {
80                         return b->methods;
81                 }
82         }
83
84         return NULL;
85 }
86
87 /**********************************************************************
88  Allow a module to register itself as a method.
89 **********************************************************************/
90
91 NTSTATUS smb_register_idmap(int version, const char *name, struct idmap_methods *methods)
92 {
93         struct idmap_methods *test;
94         struct idmap_backend *entry;
95
96         if (!idmap_ctx) {
97                 return NT_STATUS_INTERNAL_DB_ERROR;
98         }
99
100         if ((version != SMB_IDMAP_INTERFACE_VERSION)) {
101                 DEBUG(0, ("Failed to register idmap module.\n"
102                           "The module was compiled against SMB_IDMAP_INTERFACE_VERSION %d,\n"
103                           "current SMB_IDMAP_INTERFACE_VERSION is %d.\n"
104                           "Please recompile against the current version of samba!\n",  
105                           version, SMB_IDMAP_INTERFACE_VERSION));
106                 return NT_STATUS_OBJECT_TYPE_MISMATCH;
107         }
108
109         if (!name || !name[0] || !methods) {
110                 DEBUG(0,("Called with NULL pointer or empty name!\n"));
111                 return NT_STATUS_INVALID_PARAMETER;
112         }
113
114         test = get_methods(backends, name);
115         if (test) {
116                 DEBUG(0,("Idmap module %s already registered!\n", name));
117                 return NT_STATUS_OBJECT_NAME_COLLISION;
118         }
119
120         entry = talloc(idmap_ctx, struct idmap_backend);
121         if ( ! entry) {
122                 DEBUG(0,("Out of memory!\n"));
123                 return NT_STATUS_NO_MEMORY;
124         }
125         entry->name = talloc_strdup(idmap_ctx, name);
126         if ( ! entry->name) {
127                 DEBUG(0,("Out of memory!\n"));
128                 return NT_STATUS_NO_MEMORY;
129         }
130         entry->methods = methods;
131
132         DLIST_ADD(backends, entry);
133         DEBUG(5, ("Successfully added idmap backend '%s'\n", name));
134         return NT_STATUS_OK;
135 }
136
137 /**********************************************************************
138  Allow a module to register itself as a method.
139 **********************************************************************/
140
141 NTSTATUS smb_register_idmap_alloc(int version, const char *name, struct idmap_alloc_methods *methods)
142 {
143         struct idmap_alloc_methods *test;
144         struct idmap_alloc_backend *entry;
145
146         if (!idmap_ctx) {
147                 return NT_STATUS_INTERNAL_DB_ERROR;
148         }
149
150         if ((version != SMB_IDMAP_INTERFACE_VERSION)) {
151                 DEBUG(0, ("Failed to register idmap alloc module.\n"
152                           "The module was compiled against SMB_IDMAP_INTERFACE_VERSION %d,\n"
153                           "current SMB_IDMAP_INTERFACE_VERSION is %d.\n"
154                           "Please recompile against the current version of samba!\n",  
155                           version, SMB_IDMAP_INTERFACE_VERSION));
156                 return NT_STATUS_OBJECT_TYPE_MISMATCH;
157         }
158
159         if (!name || !name[0] || !methods) {
160                 DEBUG(0,("Called with NULL pointer or empty name!\n"));
161                 return NT_STATUS_INVALID_PARAMETER;
162         }
163
164         test = get_alloc_methods(alloc_backends, name);
165         if (test) {
166                 DEBUG(0,("idmap_alloc module %s already registered!\n", name));
167                 return NT_STATUS_OBJECT_NAME_COLLISION;
168         }
169
170         entry = talloc(idmap_ctx, struct idmap_alloc_backend);
171         if ( ! entry) {
172                 DEBUG(0,("Out of memory!\n"));
173                 return NT_STATUS_NO_MEMORY;
174         }
175         entry->name = talloc_strdup(idmap_ctx, name);
176         if ( ! entry->name) {
177                 DEBUG(0,("Out of memory!\n"));
178                 return NT_STATUS_NO_MEMORY;
179         }
180         entry->methods = methods;
181
182         DLIST_ADD(alloc_backends, entry);
183         DEBUG(5, ("Successfully added idmap alloc backend '%s'\n", name));
184         return NT_STATUS_OK;
185 }
186
187 static int close_domain_destructor(struct idmap_domain *dom)
188 {
189         NTSTATUS ret;
190
191         ret = dom->methods->close_fn(dom);
192         if (!NT_STATUS_IS_OK(ret)) {
193                 DEBUG(3, ("Failed to close idmap domain [%s]!\n", dom->name));
194         }
195
196         return 0;
197 }
198
199 /**************************************************************************
200  Shutdown.
201 **************************************************************************/
202
203 NTSTATUS idmap_close(void)
204 {
205         /* close the alloc backend first before freeing idmap_ctx */
206         if (alloc_methods) {
207                 alloc_methods->close_fn();
208                 alloc_methods = NULL;
209         }
210         alloc_backends = NULL;
211
212         /* this talloc_free call will fire the talloc destructors
213          * that will free all active backends resources */
214         TALLOC_FREE(idmap_ctx);
215         idmap_cache = NULL;
216         idmap_domains = NULL;
217         backends = NULL;
218
219         return NT_STATUS_OK;
220 }
221
222 /**********************************************************************
223  Initialise idmap cache and a remote backend (if configured).
224 **********************************************************************/
225
226 static const char *idmap_default_domain[] = { "default domain", NULL };
227
228 /****************************************************************************
229  ****************************************************************************/
230
231 NTSTATUS idmap_init_cache(void)
232 {       
233         /* Always initialize the cache.  We'll have to delay initialization
234            of backends if we are offline */
235
236         if ( idmap_ctx ) {
237                 return NT_STATUS_OK;
238         }       
239         
240         if ( (idmap_ctx = talloc_named_const(NULL, 0, "idmap_ctx")) == NULL ) {
241                 return NT_STATUS_NO_MEMORY;
242         }
243
244         if ( (idmap_cache = idmap_cache_init(idmap_ctx)) == NULL ) {
245                 return NT_STATUS_UNSUCCESSFUL;
246         }
247
248         return NT_STATUS_OK;
249 }
250
251 /****************************************************************************
252  ****************************************************************************/
253
254 NTSTATUS idmap_init(void)
255 {       
256         NTSTATUS ret;
257         static NTSTATUS backend_init_status = NT_STATUS_UNSUCCESSFUL;   
258         struct idmap_domain *dom;
259         char *compat_backend = NULL;
260         char *compat_params = NULL;
261         const char **dom_list = NULL;
262         char *alloc_backend = NULL;
263         BOOL default_already_defined = False;
264         BOOL pri_dom_is_in_list = False;
265         int compat = 0;
266         int i;
267
268         /* Always initialize the cache.  We'll have to delay initialization
269            of backends if we are offline */
270
271         ret = idmap_init_cache();
272         if ( !NT_STATUS_IS_OK(ret) )
273                 return ret;
274
275         if ( NT_STATUS_IS_OK(backend_init_status) ) {
276                 return NT_STATUS_OK;
277         }
278         
279         /* We can't reliably call intialization code here unless 
280            we are online */
281
282         if ( get_global_winbindd_state_offline() ) {
283                 backend_init_status = NT_STATUS_FILE_IS_OFFLINE;
284                 return backend_init_status;             
285         }
286
287         static_init_idmap;
288
289         dom_list = lp_idmap_domains();
290         
291         if ( dom_list && lp_idmap_backend() ) {
292                 DEBUG(0, ("WARNING: idmap backend and idmap domains are "
293                           "mutually excusive!\n"));
294                 DEBUGADD(0,("idmap backend option will be IGNORED!\n"));
295         } else if ( lp_idmap_backend() ) {
296                 const char **compat_list = lp_idmap_backend();
297                 char *p = NULL;
298                 const char *q = NULL;           
299
300                 compat = 1;
301
302                 if ( (compat_backend = talloc_strdup( idmap_ctx, *compat_list )) == NULL ) {
303                         ret = NT_STATUS_NO_MEMORY;
304                         goto done;                      
305                 }
306                 
307                 /* strip any leading idmap_ prefix of */
308                 if (strncmp(*compat_list, "idmap_", 6) == 0 ) {
309                         q = *compat_list += 6;
310                         DEBUG(0, ("WARNING: idmap backend uses obsolete and "
311                                   "deprecated 'idmap_' prefix.\n"
312                                   "Please replace 'idmap_%s' by '%s' in %s\n", 
313                                   q, q, dyn_CONFIGFILE));
314                         compat_backend = talloc_strdup( idmap_ctx, q);
315                 } else {
316                         compat_backend = talloc_strdup( idmap_ctx, *compat_list);
317                 }
318                         
319                 /* separate the backend and module arguements */
320                 if ((p = strchr(compat_backend, ':')) != NULL) {
321                         *p = '\0';                      
322                         compat_params = p + 1;
323                 }
324         }
325
326         if ( ! dom_list) {
327                 dom_list = idmap_default_domain;
328         }
329         
330         /***************************
331          * initialize idmap domains
332          */
333         DEBUG(1, ("Initializing idmap domains\n"));
334
335         for (i = 0; dom_list[i]; i++) {
336                 const char *parm_backend;
337                 char *config_option;
338
339                 /* ignore BUILTIN and local MACHINE domains */
340                 if ( strequal(dom_list[i], "BUILTIN") 
341                      || strequal(dom_list[i], get_global_sam_name() ) ) 
342                 {
343                         DEBUG(0,("idmap_init: Ignoring invalid domain %s\n", 
344                                  dom_list[i]));
345                         continue;
346                 }
347
348                 if (strequal(dom_list[i], lp_workgroup())) {
349                         pri_dom_is_in_list = True;
350                 }
351                 /* init domain */
352                 
353                 dom = talloc_zero(idmap_ctx, struct idmap_domain);
354                 IDMAP_CHECK_ALLOC(dom);
355
356                 dom->name = talloc_strdup(dom, dom_list[i]);
357                 IDMAP_CHECK_ALLOC(dom->name);
358
359                 config_option = talloc_asprintf(dom, "idmap config %s", dom->name);
360                 IDMAP_CHECK_ALLOC(config_option);
361
362                 /* default or specific ? */
363
364                 dom->default_domain = lp_parm_bool(-1, config_option, "default", False);
365
366                 if (dom->default_domain ||
367                     strequal(dom_list[i], idmap_default_domain[0])) {
368
369                         /* make sure this is set even when we match idmap_default_domain[0] */
370                         dom->default_domain = True;
371
372                         if (default_already_defined) {
373                                 DEBUG(1, ("ERROR: Multiple domains defined as default!\n"));
374                                 ret = NT_STATUS_INVALID_PARAMETER;
375                                 goto done;
376                         }
377
378                         default_already_defined = True;
379
380                 } 
381
382                 dom->readonly = lp_parm_bool(-1, config_option, "readonly", False);
383
384                 /* find associated backend (default: tdb) */
385                 if (compat) {
386                         parm_backend = talloc_strdup(idmap_ctx, compat_backend);
387                 } else {
388                         parm_backend = talloc_strdup(idmap_ctx,
389                                                      lp_parm_const_string(-1, config_option, "backend", "tdb"));
390                 }
391                 IDMAP_CHECK_ALLOC(parm_backend);
392
393                 /* get the backend methods for this domain */
394                 dom->methods = get_methods(backends, parm_backend);
395
396                 if ( ! dom->methods) {
397                         ret = smb_probe_module("idmap", parm_backend);
398                         if (NT_STATUS_IS_OK(ret)) {
399                                 dom->methods = get_methods(backends, parm_backend);
400                         }
401                 }
402                 if ( ! dom->methods) {
403                         DEBUG(0, ("ERROR: Could not get methods for backend %s\n", parm_backend));
404                         ret = NT_STATUS_UNSUCCESSFUL;
405                         goto done;
406                 }
407
408                 /* check the set_mapping function exists otherwise mark the module as readonly */
409                 if ( ! dom->methods->set_mapping) {
410                         DEBUG(5, ("Forcing to readonly, as ithis module can't store arbitrary mappings.\n"));
411                         dom->readonly = True;
412                 }
413
414                 /* now that we have methods, set the destructor for this domain */
415                 talloc_set_destructor(dom, close_domain_destructor);
416
417                 /* Finally instance a backend copy for this domain */
418                 ret = dom->methods->init(dom, compat_params);
419                 if ( ! NT_STATUS_IS_OK(ret)) {
420                         DEBUG(0, ("ERROR: Initialization failed for backend %s (domain %s)\n",
421                                                 parm_backend, dom->name));
422                         ret = NT_STATUS_UNSUCCESSFUL;
423                         goto done;
424                 }
425                 idmap_domains = talloc_realloc(idmap_ctx, idmap_domains, struct idmap_domain *, i+1);
426                 if ( ! idmap_domains) {
427                         DEBUG(0, ("Out of memory!\n"));
428                         ret = NT_STATUS_NO_MEMORY;
429                         goto done;
430                 }
431                 idmap_domains[i] = dom;
432
433                 if (dom->default_domain) { /* save default domain position for future uses */
434                         def_dom_num = i;
435                 }
436
437                 DEBUG(10, ("Domain %s - Backend %s - %sdefault - %sreadonly\n",
438                                 dom->name, parm_backend,
439                                 dom->default_domain?"":"not ", dom->readonly?"":"not "));
440
441                 talloc_free(config_option);
442         }
443
444         /* save the number of domains we have */
445         num_domains = i;
446
447         /* automatically add idmap_nss backend if needed */
448         if ((lp_server_role() == ROLE_DOMAIN_MEMBER) &&
449             ( ! pri_dom_is_in_list) &&
450             lp_winbind_trusted_domains_only()) {
451
452                 dom = talloc_zero(idmap_ctx, struct idmap_domain);
453                 IDMAP_CHECK_ALLOC(dom);
454
455                 dom->name = talloc_strdup(dom, lp_workgroup());
456                 IDMAP_CHECK_ALLOC(dom->name);
457
458                 dom->default_domain = False;
459                 dom->readonly = True;
460
461                 /* get the backend methods for passdb */
462                 dom->methods = get_methods(backends, "nss");
463
464                 /* (the nss module is always statically linked) */
465                 if ( ! dom->methods) {
466                         DEBUG(0, ("ERROR: Could not get methods for idmap_nss ?!\n"));
467                         ret = NT_STATUS_UNSUCCESSFUL;
468                         goto done;
469                 }
470
471                 /* now that we have methods, set the destructor for this domain */
472                 talloc_set_destructor(dom, close_domain_destructor);
473
474                 /* Finally instance a backend copy for this domain */
475                 ret = dom->methods->init(dom, compat_params);
476                 if ( ! NT_STATUS_IS_OK(ret)) {
477                         DEBUG(0, ("ERROR: Initialization failed for idmap_nss ?!\n"));
478                         ret = NT_STATUS_UNSUCCESSFUL;
479                         goto done;
480                 }
481
482                 idmap_domains = talloc_realloc(idmap_ctx, idmap_domains, struct idmap_domain *, num_domains+1);
483                 if ( ! idmap_domains) {
484                         DEBUG(0, ("Out of memory!\n"));
485                         ret = NT_STATUS_NO_MEMORY;
486                         goto done;
487                 }
488                 idmap_domains[num_domains] = dom;
489
490                 DEBUG(10, ("Domain %s - Backend nss - not default - readonly\n", dom->name ));
491
492                 num_domains++;
493         }
494
495         /**** automatically add idmap_passdb backend ****/
496         dom = talloc_zero(idmap_ctx, struct idmap_domain);
497         IDMAP_CHECK_ALLOC(dom);
498
499         dom->name = talloc_strdup(dom, get_global_sam_name());
500         IDMAP_CHECK_ALLOC(dom->name);
501
502         dom->default_domain = False;
503         dom->readonly = True;
504
505         /* get the backend methods for passdb */
506         dom->methods = get_methods(backends, "passdb");
507
508         /* (the passdb module is always statically linked) */
509         if ( ! dom->methods) {
510                 DEBUG(0, ("ERROR: Could not get methods for idmap_passdb ?!\n"));
511                 ret = NT_STATUS_UNSUCCESSFUL;
512                 goto done;
513         }
514
515         /* now that we have methods, set the destructor for this domain */
516         talloc_set_destructor(dom, close_domain_destructor);
517
518         /* Finally instance a backend copy for this domain */
519         ret = dom->methods->init(dom, compat_params);
520         if ( ! NT_STATUS_IS_OK(ret)) {
521                 DEBUG(0, ("ERROR: Initialization failed for idmap_passdb ?!\n"));
522                 ret = NT_STATUS_UNSUCCESSFUL;
523                 goto done;
524         }
525
526         idmap_domains = talloc_realloc(idmap_ctx, idmap_domains, struct idmap_domain *, num_domains+1);
527         if ( ! idmap_domains) {
528                 DEBUG(0, ("Out of memory!\n"));
529                 ret = NT_STATUS_NO_MEMORY;
530                 goto done;
531         }
532         idmap_domains[num_domains] = dom;
533
534         /* needed to handle special BUILTIN and wellknown SIDs cases */
535         pdb_dom_num = num_domains;
536
537         DEBUG(10, ("Domain %s - Backend passdb - not default - readonly\n", dom->name));
538
539         num_domains++;
540         /**** finished adding idmap_passdb backend ****/
541
542         /* sort domains so that the default is the last one */
543         /* don't sort if no default domain defined */
544         if (def_dom_num != -1 && def_dom_num != num_domains-1) { /* default is not last, move it */
545                 struct idmap_domain *tmp;
546
547                 if (pdb_dom_num > def_dom_num) {
548                         pdb_dom_num --;
549
550                 } else if (pdb_dom_num == def_dom_num) { /* ?? */
551                         pdb_dom_num = num_domains - 1;
552                 }
553
554                 tmp = idmap_domains[def_dom_num];
555
556                 for (i = def_dom_num; i < num_domains-1; i++) {
557                         idmap_domains[i] = idmap_domains[i+1];
558                 }
559                 idmap_domains[i] = tmp;
560                 def_dom_num = i;
561         }
562
563
564         /* Initialize alloc module */
565
566         DEBUG(3, ("Initializing idmap alloc module\n"));
567
568         alloc_backend = NULL;
569         if (compat) {
570                 alloc_backend = talloc_strdup(idmap_ctx, compat_backend);
571         } else {
572                 char *ab = lp_idmap_alloc_backend();
573                 
574                 if (ab && (ab[0] != '\0')) {
575                         alloc_backend = talloc_strdup(idmap_ctx, lp_idmap_alloc_backend());
576                 }
577         }
578
579         if ( alloc_backend ) {
580
581                 alloc_methods = get_alloc_methods(alloc_backends, alloc_backend);
582                 if ( ! alloc_methods) {
583                         ret = smb_probe_module("idmap", alloc_backend);
584                         if (NT_STATUS_IS_OK(ret)) {
585                                 alloc_methods = get_alloc_methods(alloc_backends, alloc_backend);
586                         }
587                 }
588                 if ( alloc_methods) {
589                         ret = alloc_methods->init(compat_params);
590                         if ( ! NT_STATUS_IS_OK(ret)) {
591                                 DEBUG(0, ("idmap_init: Initialization failed for alloc "
592                                           "backend %s\n", alloc_backend));
593                                 ret = NT_STATUS_UNSUCCESSFUL;
594                                 goto done;
595                 }
596                 } else {
597                         DEBUG(2, ("idmap_init: Unable to get methods for alloc backend %s\n", 
598                                   alloc_backend));
599                         /* certain compat backends are just readonly */
600                         if ( compat )
601                                 ret = NT_STATUS_OK;
602                         else
603                                 ret = NT_STATUS_UNSUCCESSFUL;
604                 }
605         }
606         
607         /* cleanpu temporary strings */
608         TALLOC_FREE( compat_backend );
609         
610         backend_init_status = NT_STATUS_OK;
611         
612         return ret;
613
614 done:
615         DEBUG(0, ("Aborting IDMAP Initialization ...\n"));
616         idmap_close();
617
618         /* save the init status for later checks */
619         backend_init_status = ret;
620         
621         return ret;
622 }
623
624 /**************************************************************************
625  idmap allocator interface functions
626 **************************************************************************/
627
628 NTSTATUS idmap_allocate_uid(struct unixid *id)
629 {
630         NTSTATUS ret;
631
632         if (! NT_STATUS_IS_OK(ret = idmap_init())) {
633                 return ret;
634         }
635
636         if ( !alloc_methods )
637                 return NT_STATUS_NOT_SUPPORTED; 
638
639         id->type = ID_TYPE_UID;
640         return alloc_methods->allocate_id(id);
641 }
642
643 NTSTATUS idmap_allocate_gid(struct unixid *id)
644 {
645         NTSTATUS ret;
646
647         if (! NT_STATUS_IS_OK(ret = idmap_init())) {
648                 return ret;
649         }
650
651         if ( !alloc_methods )
652                 return NT_STATUS_NOT_SUPPORTED; 
653
654         id->type = ID_TYPE_GID;
655         return alloc_methods->allocate_id(id);
656 }
657
658 NTSTATUS idmap_set_uid_hwm(struct unixid *id)
659 {
660         NTSTATUS ret;
661
662         if (! NT_STATUS_IS_OK(ret = idmap_init())) {
663                 return ret;
664         }
665
666         if ( !alloc_methods )
667                 return NT_STATUS_NOT_SUPPORTED; 
668
669         id->type = ID_TYPE_UID;
670         return alloc_methods->set_id_hwm(id);
671 }
672
673 NTSTATUS idmap_set_gid_hwm(struct unixid *id)
674 {
675         NTSTATUS ret;
676
677         if (! NT_STATUS_IS_OK(ret = idmap_init())) {
678                 return ret;
679         }
680
681         if ( !alloc_methods )
682                 return NT_STATUS_NOT_SUPPORTED; 
683
684         id->type = ID_TYPE_GID;
685         return alloc_methods->set_id_hwm(id);
686 }
687
688 /******************************************************************************
689  Lookup an idmap_domain give a full user or group SID
690  ******************************************************************************/
691
692 static struct idmap_domain* find_idmap_domain_from_sid( DOM_SID *account_sid )
693 {
694         DOM_SID domain_sid;
695         uint32 rid;
696         struct winbindd_domain *domain = NULL;
697         int i;
698         
699         /* 1. Handle BUILTIN or Special SIDs and prevent them from
700            falling into the default domain space (if we have a
701            configured passdb backend. */
702
703         if ( (pdb_dom_num != -1) && 
704              (sid_check_is_in_builtin(account_sid) ||
705               sid_check_is_in_wellknown_domain(account_sid) ||
706               sid_check_is_in_unix_groups(account_sid) ||
707               sid_check_is_in_unix_users(account_sid)) ) 
708         {
709                 return idmap_domains[pdb_dom_num];
710         }
711
712         /* 2. Lookup the winbindd_domain from the account_sid */
713
714         sid_copy( &domain_sid, account_sid );
715         sid_split_rid( &domain_sid, &rid );     
716         domain = find_domain_from_sid_noinit( &domain_sid );    
717
718         for (i = 0; domain && i < num_domains; i++) {
719                 if ( strequal( idmap_domains[i]->name, domain->name ) ) {
720                         return idmap_domains[i];
721                 }
722         }
723
724         /* 3. Fall back to the default domain */
725
726         if ( def_dom_num != -1 ) {
727                 return idmap_domains[def_dom_num];
728         }
729
730         return NULL;
731 }
732
733 /******************************************************************************
734  Lookup an index given an idmap_domain pointer
735  ******************************************************************************/
736
737 static uint32 find_idmap_domain_index( struct idmap_domain *id_domain)
738 {
739         int i;
740         
741         for (i = 0; i < num_domains; i++) {
742                 if ( idmap_domains[i] == id_domain )
743                         return i;               
744         }
745
746         return -1;      
747 }
748
749
750 /*********************************************************
751  Check if creating a mapping is permitted for the domain
752 *********************************************************/
753
754 static NTSTATUS idmap_can_map(const struct id_map *map, struct idmap_domain **ret_dom)
755 {
756         struct idmap_domain *dom;
757
758         /* Check we do not create mappings for our own local domain, or BUILTIN or special SIDs */
759         if ((sid_compare_domain(map->sid, get_global_sam_sid()) == 0) ||
760             sid_check_is_in_builtin(map->sid) ||
761             sid_check_is_in_wellknown_domain(map->sid)) {
762                 DEBUG(10, ("We are not supposed to create mappings for our own domains (local, builtin, specials)\n"));
763                 return NT_STATUS_UNSUCCESSFUL;
764         }
765
766         /* Special check for trusted domain only = Yes */
767         if (lp_winbind_trusted_domains_only()) {
768                 struct winbindd_domain *wdom = find_our_domain();
769                 if (wdom && (sid_compare_domain(map->sid, &wdom->sid) == 0)) {
770                         DEBUG(10, ("We are not supposed to create mappings for our primary domain when <trusted domain only> is True\n"));
771                         DEBUGADD(10, ("Leave [%s] unmapped\n", sid_string_static(map->sid)));
772                         return NT_STATUS_UNSUCCESSFUL;
773                 }
774         }
775
776         if ( (dom = find_idmap_domain_from_sid( map->sid )) == NULL ) {
777                 /* huh, couldn't find a suitable domain, let's just leave it unmapped */
778                 DEBUG(10, ("Could not find idmap backend for SID %s", sid_string_static(map->sid)));
779                 return NT_STATUS_NO_SUCH_DOMAIN;
780         }
781
782         if (dom->readonly) {
783                 /* ouch the domain is read only, let's just leave it unmapped */
784                 DEBUG(10, ("idmap backend for SID %s is READONLY!\n", sid_string_static(map->sid)));
785                 return NT_STATUS_UNSUCCESSFUL;
786         }
787
788         *ret_dom = dom;
789         return NT_STATUS_OK;
790 }
791
792 static NTSTATUS idmap_new_mapping(TALLOC_CTX *ctx, struct id_map *map)
793 {
794         NTSTATUS ret;
795         struct idmap_domain *dom;
796         const char *domname, *name;
797         enum lsa_SidType sid_type;
798         BOOL wbret;
799
800         ret = idmap_can_map(map, &dom);
801         if ( ! NT_STATUS_IS_OK(ret)) {
802                 return NT_STATUS_NONE_MAPPED;
803         }
804         
805         /* by default calls to winbindd are disabled
806            the following call will not recurse so this is safe */
807         winbind_on();
808         wbret = winbind_lookup_sid(ctx, map->sid, &domname, &name, &sid_type);
809         winbind_off();
810
811         /* check if this is a valid SID and then map it */
812         if (wbret) {
813                 switch (sid_type) {
814                 case SID_NAME_USER:
815                         ret = idmap_allocate_uid(&map->xid);
816                         if ( ! NT_STATUS_IS_OK(ret)) {
817                                 /* can't allocate id, let's just leave it unmapped */
818                                 DEBUG(2, ("uid allocation failed! Can't create mapping\n"));
819                                 return NT_STATUS_NONE_MAPPED;
820                         }
821                         break;
822                 case SID_NAME_DOM_GRP:
823                 case SID_NAME_ALIAS:
824                 case SID_NAME_WKN_GRP:
825                         ret = idmap_allocate_gid(&map->xid);
826                         if ( ! NT_STATUS_IS_OK(ret)) {
827                                 /* can't allocate id, let's just leave it unmapped */
828                                 DEBUG(2, ("gid allocation failed! Can't create mapping\n"));
829                                 return NT_STATUS_NONE_MAPPED;
830                         }
831                         break;
832                 default:
833                         /* invalid sid, let's just leave it unmapped */
834                         DEBUG(10, ("SID %s is UNKNOWN, skip mapping\n", sid_string_static(map->sid)));
835                         return NT_STATUS_NONE_MAPPED;
836                 }
837
838                 /* ok, got a new id, let's set a mapping */
839                 map->status = ID_MAPPED;
840
841                 DEBUG(10, ("Setting mapping: %s <-> %s %lu\n",
842                            sid_string_static(map->sid),
843                            (map->xid.type == ID_TYPE_UID) ? "UID" : "GID",
844                            (unsigned long)map->xid.id));
845                 ret = dom->methods->set_mapping(dom, map);
846
847                 if ( ! NT_STATUS_IS_OK(ret)) {
848                         /* something wrong here :-( */
849                         DEBUG(2, ("Failed to commit mapping\n!"));
850
851                         /* TODO: would it make sense to have an "unalloc_id function?" */
852
853                         return NT_STATUS_NONE_MAPPED;
854                 }
855         } else {
856                 DEBUG(2,("Invalid SID, not mapping %s (type %d)\n",
857                                 sid_string_static(map->sid), sid_type));
858                 return NT_STATUS_NONE_MAPPED;
859         }
860
861         return NT_STATUS_OK;
862 }
863
864 static NTSTATUS idmap_backends_set_mapping(const struct id_map *map)
865 {
866         struct idmap_domain *dom;
867         NTSTATUS ret;
868
869         DEBUG(10, ("Setting mapping %s <-> %s %lu\n",
870                    sid_string_static(map->sid),
871                    (map->xid.type == ID_TYPE_UID) ? "UID" : "GID",
872                    (unsigned long)map->xid.id));
873
874         ret = idmap_can_map(map, &dom);
875         if ( ! NT_STATUS_IS_OK(ret)) {
876                 return ret;
877         }
878
879         DEBUG(10,("set_mapping for domain %s\n", dom->name ));  
880
881         return dom->methods->set_mapping(dom, map);
882 }
883
884 static NTSTATUS idmap_backends_unixids_to_sids(struct id_map **ids)
885 {
886         struct idmap_domain *dom;
887         struct id_map **unmapped;
888         struct id_map **_ids;
889         TALLOC_CTX *ctx;
890         NTSTATUS ret;
891         int i, u, n;
892
893         if (!ids || !*ids) {
894                 DEBUG(1, ("Invalid list of maps\n"));
895                 return NT_STATUS_INVALID_PARAMETER;
896         }
897
898         ctx = talloc_named_const(NULL, 0, "idmap_backends_unixids_to_sids ctx");
899         if ( ! ctx) {
900                 DEBUG(0, ("Out of memory!\n"));
901                 return NT_STATUS_NO_MEMORY;
902         }
903
904         DEBUG(10, ("Query backends to map ids->sids\n"));
905
906         /* start from the default (the last one) and then if there are still
907          * unmapped entries cycle through the others */
908
909         _ids = ids;
910
911         /* make sure all maps are marked as in UNKNOWN status */
912         for (i = 0; _ids[i]; i++) {
913                 _ids[i]->status = ID_UNKNOWN;
914         }
915
916         unmapped = NULL;
917         for (n = num_domains-1; n >= 0; n--) { /* cycle backwards */
918
919                 dom = idmap_domains[n];
920
921                 DEBUG(10, ("Query sids from domain %s\n", dom->name));
922                 
923                 ret = dom->methods->unixids_to_sids(dom, _ids);
924                 IDMAP_CHECK_RET(ret);
925
926                 unmapped = NULL;
927
928                 for (i = 0, u = 0; _ids[i]; i++) {
929                         if (_ids[i]->status == ID_UNKNOWN || _ids[i]->status == ID_UNMAPPED) {
930                                 unmapped = talloc_realloc(ctx, unmapped, struct id_map *, u + 2);
931                                 IDMAP_CHECK_ALLOC(unmapped);
932                                 unmapped[u] = _ids[i];
933                                 u++;
934                         }
935                 }
936                 if (unmapped) {
937                         /* terminate the unmapped list */
938                         unmapped[u] = NULL;
939                 } else { /* no more entries, get out */
940                         break;
941                 }
942
943                 _ids = unmapped;
944                 
945         }
946
947         if (unmapped) {
948                 /* there are still unmapped ids, map them to the unix users/groups domains */
949                 for (i = 0; unmapped[i]; i++) {
950                         switch (unmapped[i]->xid.type) {
951                         case ID_TYPE_UID:
952                                 uid_to_unix_users_sid((uid_t)unmapped[i]->xid.id, unmapped[i]->sid);
953                                 unmapped[i]->status = ID_MAPPED;
954                                 break;
955                         case ID_TYPE_GID:
956                                 gid_to_unix_groups_sid((gid_t)unmapped[i]->xid.id, unmapped[i]->sid);
957                                 unmapped[i]->status = ID_MAPPED;
958                                 break;
959                         default: /* what?! */
960                                 unmapped[i]->status = ID_UNKNOWN;
961                                 break;
962                         }
963                 }
964         }
965
966         ret = NT_STATUS_OK;
967
968 done:
969         talloc_free(ctx);
970         return ret;
971 }       
972
973 static NTSTATUS idmap_backends_sids_to_unixids(struct id_map **ids)
974 {
975         struct id_map ***dom_ids;
976         struct idmap_domain *dom;
977         TALLOC_CTX *ctx;
978         NTSTATUS ret;
979         int i, *counters;
980
981         if ( (ctx = talloc_named_const(NULL, 0, "be_sids_to_ids")) == NULL ) {
982                 DEBUG(1, ("failed to allocate talloc context, OOM?\n"));
983                 return NT_STATUS_NO_MEMORY;
984         }
985
986         DEBUG(10, ("Query backends to map sids->ids\n"));
987
988         /* split list per domain */
989
990         dom_ids = talloc_zero_array(ctx, struct id_map **, num_domains);
991         IDMAP_CHECK_ALLOC(dom_ids);
992         counters = talloc_zero_array(ctx, int, num_domains);
993
994         /* partition the requests by domain */
995
996         for (i = 0; ids[i]; i++) {
997                 uint32 idx;             
998
999                 /* make sure they are unknown to start off */
1000                 ids[i]->status = ID_UNKNOWN;
1001
1002                 if ( (dom = find_idmap_domain_from_sid( ids[i]->sid )) == NULL ) {
1003                         /* no vailable idmap_domain.  Move on */
1004                         continue;
1005                 }
1006
1007                 DEBUG(10,("SID %s is being handled by %s\n", 
1008                           sid_string_static(ids[i]->sid),  
1009                           dom ? dom->name : "none" ));
1010
1011                 idx = find_idmap_domain_index( dom );
1012                 SMB_ASSERT( idx != -1 );
1013                 
1014                 dom_ids[idx] = talloc_realloc(ctx, dom_ids[idx], 
1015                                               struct id_map *, counters[idx] + 2);
1016                 IDMAP_CHECK_ALLOC(dom_ids[idx]);
1017
1018                 dom_ids[idx][counters[idx]] = ids[i];
1019                 counters[idx]++;
1020                 dom_ids[idx][counters[idx]] = NULL;
1021         }
1022
1023         /* All the ids have been dispatched in the right queues.
1024            Let's cycle through the filled ones */
1025
1026         for (i = 0; i < num_domains; i++) {
1027                 if (dom_ids[i]) {
1028                         dom = idmap_domains[i];
1029                         DEBUG(10, ("Query ids from domain %s\n", dom->name));
1030                         ret = dom->methods->sids_to_unixids(dom, dom_ids[i]);
1031                         IDMAP_CHECK_RET(ret);
1032                 }
1033         }
1034
1035         /* ok all the backends have been contacted at this point */
1036         /* let's see if we have any unmapped SID left and act accordingly */
1037
1038         for (i = 0; ids[i]; i++) {
1039                 if (ids[i]->status == ID_UNKNOWN || ids[i]->status == ID_UNMAPPED) {
1040                         /* ok this is an unmapped one, see if we can map it */
1041                         ret = idmap_new_mapping(ctx, ids[i]);
1042                         if (NT_STATUS_IS_OK(ret)) {
1043                                 /* successfully mapped */
1044                                 ids[i]->status = ID_MAPPED;
1045                         } else if (NT_STATUS_EQUAL(ret, NT_STATUS_NONE_MAPPED)) {
1046                                 /* could not map it */
1047                                 ids[i]->status = ID_UNMAPPED;
1048                         } else {
1049                                 /* Something very bad happened down there */
1050                                 ids[i]->status = ID_UNKNOWN;
1051                         }
1052                 }
1053         }
1054
1055         ret = NT_STATUS_OK;
1056
1057 done:
1058         talloc_free(ctx);
1059         return ret;
1060 }       
1061
1062 /**************************************************************************
1063  idmap interface functions
1064 **************************************************************************/
1065
1066 NTSTATUS idmap_unixids_to_sids(struct id_map **ids)
1067 {
1068         TALLOC_CTX *ctx;
1069         NTSTATUS ret;
1070         struct id_map **bids;
1071         int i, bi;
1072         int bn = 0;
1073
1074         if (! NT_STATUS_IS_OK(ret = idmap_init())) {
1075                 return ret;
1076         }
1077
1078         if (!ids || !*ids) {
1079                 DEBUG(1, ("Invalid list of maps\n"));
1080                 return NT_STATUS_INVALID_PARAMETER;
1081         }
1082
1083         ctx = talloc_named_const(NULL, 0, "idmap_unixids_to_sids ctx");
1084         if ( ! ctx) {
1085                 DEBUG(1, ("failed to allocate talloc context, OOM?\n"));
1086                 return NT_STATUS_NO_MEMORY;
1087         }
1088
1089         /* no ids to be asked to the backends by default */
1090         bids = NULL;
1091         bi = 0;
1092         
1093         for (i = 0; ids[i]; i++) {
1094
1095                 if ( ! ids[i]->sid) {
1096                         DEBUG(1, ("invalid null SID in id_map array"));
1097                         talloc_free(ctx);
1098                         return NT_STATUS_INVALID_PARAMETER;
1099                 }
1100
1101                 ret = idmap_cache_map_id(idmap_cache, ids[i]);
1102
1103                 if ( ! NT_STATUS_IS_OK(ret)) {
1104
1105                         if ( ! bids) {
1106                                 /* alloc space for ids to be resolved by backends (realloc ten by ten) */
1107                                 bids = talloc_array(ctx, struct id_map *, 10);
1108                                 if ( ! bids) {
1109                                         DEBUG(1, ("Out of memory!\n"));
1110                                         talloc_free(ctx);
1111                                         return NT_STATUS_NO_MEMORY;
1112                                 }
1113                                 bn = 10;
1114                         }
1115
1116                         /* add this id to the ones to be retrieved from the backends */
1117                         bids[bi] = ids[i];
1118                         bi++;
1119         
1120                         /* check if we need to allocate new space on the rids array */
1121                         if (bi == bn) {
1122                                 bn += 10;
1123                                 bids = talloc_realloc(ctx, bids, struct id_map *, bn);
1124                                 if ( ! bids) {
1125                                         DEBUG(1, ("Out of memory!\n"));
1126                                         talloc_free(ctx);
1127                                         return NT_STATUS_NO_MEMORY;
1128                                 }
1129                         }
1130
1131                         /* make sure the last element is NULL */
1132                         bids[bi] = NULL;
1133                 }
1134         }
1135
1136         /* let's see if there is any id mapping to be retieved from the backends */
1137         if (bi) {
1138                 /* Only do query if we are online */
1139                 if ( lp_winbind_offline_logon() &&
1140                      get_global_winbindd_state_offline() )
1141                 {
1142                         ret = NT_STATUS_FILE_IS_OFFLINE;
1143                         goto done;
1144                 }
1145
1146                 ret = idmap_backends_unixids_to_sids(bids);
1147                 IDMAP_CHECK_RET(ret);
1148
1149                 /* update the cache */
1150                 for (i = 0; i < bi; i++) {
1151                         if (bids[i]->status == ID_MAPPED) {
1152                                 ret = idmap_cache_set(idmap_cache, bids[i]);
1153                         } else if (bids[i]->status == ID_UNKNOWN) {
1154                                 /* return an expired entry in the cache or an unknown */
1155                                 /* this handles a previous NT_STATUS_SYNCHRONIZATION_REQUIRED
1156                                  * for disconnected mode */
1157                                 idmap_cache_map_id(idmap_cache, ids[i]);
1158                         } else { /* unmapped */
1159                                 ret = idmap_cache_set_negative_id(idmap_cache, bids[i]);
1160                         }
1161                         IDMAP_CHECK_RET(ret);
1162                 }
1163         }
1164
1165         ret = NT_STATUS_OK;
1166 done:
1167         talloc_free(ctx);
1168         return ret;
1169 }
1170
1171 NTSTATUS idmap_sids_to_unixids(struct id_map **ids)
1172 {
1173         TALLOC_CTX *ctx;
1174         NTSTATUS ret;
1175         struct id_map **bids;
1176         int i, bi;
1177         int bn = 0;
1178
1179         if (! NT_STATUS_IS_OK(ret = idmap_init())) {
1180                 return ret;
1181         }
1182
1183         if (!ids || !*ids) {
1184                 DEBUG(1, ("Invalid list of maps\n"));
1185                 return NT_STATUS_INVALID_PARAMETER;
1186         }
1187
1188         ctx = talloc_named_const(NULL, 0, "idmap_sids_to_unixids ctx");
1189         if ( ! ctx) {
1190                 DEBUG(1, ("failed to allocate talloc context, OOM?\n"));
1191                 return NT_STATUS_NO_MEMORY;
1192         }
1193
1194         /* no ids to be asked to the backends by default */
1195         bids = NULL;
1196         bi = 0;
1197         
1198         for (i = 0; ids[i]; i++) {
1199
1200                 if ( ! ids[i]->sid) {
1201                         DEBUG(1, ("invalid null SID in id_map array\n"));
1202                         talloc_free(ctx);
1203                         return NT_STATUS_INVALID_PARAMETER;
1204                 }
1205
1206                 ret = idmap_cache_map_sid(idmap_cache, ids[i]);
1207
1208                 if ( ! NT_STATUS_IS_OK(ret)) {
1209
1210                         if ( ! bids) {
1211                                 /* alloc space for ids to be resolved
1212                                    by backends (realloc ten by ten) */
1213                                 bids = talloc_array(ctx, struct id_map *, 10);
1214                                 if ( ! bids) {
1215                                         DEBUG(1, ("Out of memory!\n"));
1216                                         talloc_free(ctx);
1217                                         return NT_STATUS_NO_MEMORY;
1218                                 }
1219                                 bn = 10;
1220                         }
1221
1222                         /* add this id to the ones to be retrieved from the backends */
1223                         bids[bi] = ids[i];
1224                         bi++;
1225
1226                         /* check if we need to allocate new space on the ids array */
1227                         if (bi == bn) {
1228                                 bn += 10;
1229                                 bids = talloc_realloc(ctx, bids, struct id_map *, bn);
1230                                 if ( ! bids) {
1231                                         DEBUG(1, ("Out of memory!\n"));
1232                                         talloc_free(ctx);
1233                                         return NT_STATUS_NO_MEMORY;
1234                                 }
1235                         }
1236
1237                         /* make sure the last element is NULL */
1238                         bids[bi] = NULL;
1239                 }
1240         }
1241
1242         /* let's see if there is any id mapping to be retieved from the backends */
1243         if (bids) {
1244                 /* Only do query if we are online */
1245                 if ( lp_winbind_offline_logon() &&
1246                      get_global_winbindd_state_offline() )
1247                 {
1248                         ret = NT_STATUS_FILE_IS_OFFLINE;
1249                         goto done;
1250                 }
1251                 
1252                 ret = idmap_backends_sids_to_unixids(bids);
1253                 IDMAP_CHECK_RET(ret);
1254
1255                 /* update the cache */
1256                 for (i = 0; bids[i]; i++) {
1257                         if (bids[i]->status == ID_MAPPED) {
1258                                 ret = idmap_cache_set(idmap_cache, bids[i]);
1259                         } else if (bids[i]->status == ID_UNKNOWN) {
1260                                 /* return an expired entry in the cache or an unknown */
1261                                 /* this handles a previous NT_STATUS_SYNCHRONIZATION_REQUIRED
1262                                  * for disconnected mode */
1263                                 idmap_cache_map_id(idmap_cache, ids[i]);
1264                         } else {
1265                                 ret = idmap_cache_set_negative_sid(idmap_cache, bids[i]);
1266                         }
1267                         IDMAP_CHECK_RET(ret);
1268                 }
1269         }
1270
1271         ret = NT_STATUS_OK;
1272 done:
1273         talloc_free(ctx);
1274         return ret;
1275 }
1276
1277 NTSTATUS idmap_set_mapping(const struct id_map *id)
1278 {
1279         TALLOC_CTX *ctx;
1280         NTSTATUS ret;
1281
1282         if (! NT_STATUS_IS_OK(ret = idmap_init())) {
1283                 return ret;
1284         }
1285
1286         /* sanity checks */
1287         if ((id->sid == NULL) || (id->status != ID_MAPPED)) {
1288                 DEBUG(1, ("NULL SID or unmapped entry\n"));
1289                 return NT_STATUS_INVALID_PARAMETER;
1290         }
1291
1292         /* TODO: check uid/gid range ? */
1293
1294         ctx = talloc_named_const(NULL, 0, "idmap_set_mapping ctx");
1295         if ( ! ctx) {
1296                 DEBUG(1, ("failed to allocate talloc context, OOM?\n"));
1297                 return NT_STATUS_NO_MEMORY;
1298         }
1299
1300         /* set the new mapping */
1301         ret = idmap_backends_set_mapping(id);
1302         IDMAP_CHECK_RET(ret);
1303
1304         /* set the mapping in the cache */
1305         ret = idmap_cache_set(idmap_cache, id);
1306         IDMAP_CHECK_RET(ret);
1307
1308 done:
1309         talloc_free(ctx);
1310         return ret;
1311 }
1312
1313 /**************************************************************************
1314  Dump backend status.
1315 **************************************************************************/
1316
1317 void idmap_dump_maps(char *logfile)
1318 {
1319         NTSTATUS ret;
1320         struct unixid allid;
1321         struct id_map *maps;
1322         int num_maps;
1323         FILE *dump;
1324         int i;
1325
1326         if (! NT_STATUS_IS_OK(ret = idmap_init())) {
1327                 return;
1328         }
1329
1330         dump = fopen(logfile, "w");
1331         if ( ! dump) {
1332                 DEBUG(0, ("Unable to open open stream for file [%s], errno: %d\n", logfile, errno));
1333                 return;
1334         }
1335
1336         if ( alloc_methods ) {          
1337                 allid.type = ID_TYPE_UID;
1338                 allid.id = 0;
1339                 alloc_methods->get_id_hwm(&allid);
1340                 fprintf(dump, "USER HWM %lu\n", (unsigned long)allid.id);
1341                 
1342                 allid.type = ID_TYPE_GID;
1343                 allid.id = 0;
1344                 alloc_methods->get_id_hwm(&allid);
1345                 fprintf(dump, "GROUP HWM %lu\n", (unsigned long)allid.id);
1346         }
1347         
1348         maps = talloc(idmap_ctx, struct id_map);
1349         num_maps = 0;
1350
1351         for (i = 0; i < num_domains; i++) {
1352                 if (idmap_domains[i]->methods->dump_data) {
1353                         idmap_domains[i]->methods->dump_data(idmap_domains[i], &maps, &num_maps);
1354                 }
1355         }
1356
1357         for (i = 0; i < num_maps; i++) {
1358                 switch (maps[i].xid.type) {
1359                 case ID_TYPE_UID:
1360                         fprintf(dump, "UID %lu %s\n",
1361                                 (unsigned long)maps[i].xid.id,
1362                                 sid_string_static(maps[i].sid));
1363                         break;
1364                 case ID_TYPE_GID:
1365                         fprintf(dump, "GID %lu %s\n",
1366                                 (unsigned long)maps[i].xid.id,
1367                                 sid_string_static(maps[i].sid));
1368                         break;
1369                 }
1370         }
1371
1372         fflush(dump);
1373         fclose(dump);
1374 }
1375
1376 char *idmap_fetch_secret(const char *backend, bool alloc,
1377                                const char *domain, const char *identity)
1378 {
1379         char *tmp, *ret;
1380         int r;
1381
1382         if (alloc) {
1383                 r = asprintf(&tmp, "IDMAP_ALLOC_%s", backend);
1384         } else {
1385                 r = asprintf(&tmp, "IDMAP_%s_%s", backend, domain);
1386         }
1387
1388         if (r < 0) 
1389                 return NULL;
1390
1391         strupper_m(tmp); /* make sure the key is case insensitive */
1392         ret = secrets_fetch_generic(tmp, identity);
1393
1394         SAFE_FREE( tmp );       
1395
1396         return ret;
1397 }