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