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