source: trunk/samba/source/nsswitch/idmap.c @ 26

Last change on this file since 26 was 26, checked in by Paul Smedley, 14 years ago

Updated source to 3.0.25rc1

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