s3:winbind:idmap: remove idmap_alloc_context from idmap.c
[metze/samba/wip.git] / source3 / winbindd / idmap.c
1 /*
2    Unix SMB/CIFS implementation.
3    ID Mapping
4    Copyright (C) Tim Potter 2000
5    Copyright (C) Jim McDonough <jmcd@us.ibm.com>        2003
6    Copyright (C) Simo Sorce 2003-2007
7    Copyright (C) Jeremy Allison 2006
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "winbindd.h"
25
26 #undef DBGC_CLASS
27 #define DBGC_CLASS DBGC_IDMAP
28
29 static_decl_idmap;
30
31 /**
32  * Pointer to the backend methods. Modules register themselves here via
33  * smb_register_idmap.
34  */
35
36 struct idmap_backend {
37         const char *name;
38         struct idmap_methods *methods;
39         struct idmap_backend *prev, *next;
40 };
41 static struct idmap_backend *backends = NULL;
42
43 /**
44  * Default idmap domain configured via "idmap backend".
45  */
46 static struct idmap_domain *default_idmap_domain;
47
48 /**
49  * Passdb idmap domain, not configurable. winbind must always give passdb a
50  * chance to map ids.
51  */
52 static struct idmap_domain *passdb_idmap_domain;
53
54 /**
55  * List of specially configured idmap domains. This list is filled on demand
56  * in the winbind idmap child when the parent winbind figures out via the
57  * special range parameter or via the domain SID that a special "idmap config
58  * domain" configuration is present.
59  */
60 static struct idmap_domain **idmap_domains = NULL;
61 static int num_domains = 0;
62
63 static struct idmap_methods *get_methods(const char *name)
64 {
65         struct idmap_backend *b;
66
67         for (b = backends; b; b = b->next) {
68                 if (strequal(b->name, name)) {
69                         return b->methods;
70                 }
71         }
72
73         return NULL;
74 }
75
76 bool idmap_is_offline(void)
77 {
78         return ( lp_winbind_offline_logon() &&
79              get_global_winbindd_state_offline() );
80 }
81
82 bool idmap_is_online(void)
83 {
84         return !idmap_is_offline();
85 }
86
87 /**********************************************************************
88  Allow a module to register itself as a method.
89 **********************************************************************/
90
91 NTSTATUS smb_register_idmap(int version, const char *name,
92                             struct idmap_methods *methods)
93 {
94         struct idmap_backend *entry;
95
96         if ((version != SMB_IDMAP_INTERFACE_VERSION)) {
97                 DEBUG(0, ("Failed to register idmap module.\n"
98                           "The module was compiled against "
99                           "SMB_IDMAP_INTERFACE_VERSION %d,\n"
100                           "current SMB_IDMAP_INTERFACE_VERSION is %d.\n"
101                           "Please recompile against the current version "
102                           "of samba!\n",
103                           version, SMB_IDMAP_INTERFACE_VERSION));
104                 return NT_STATUS_OBJECT_TYPE_MISMATCH;
105         }
106
107         if (!name || !name[0] || !methods) {
108                 DEBUG(0,("Called with NULL pointer or empty name!\n"));
109                 return NT_STATUS_INVALID_PARAMETER;
110         }
111
112         for (entry = backends; entry != NULL; entry = entry->next) {
113                 if (strequal(entry->name, name)) {
114                         DEBUG(0,("Idmap module %s already registered!\n",
115                                  name));
116                         return NT_STATUS_OBJECT_NAME_COLLISION;
117                 }
118         }
119
120         entry = talloc(NULL, struct idmap_backend);
121         if ( ! entry) {
122                 DEBUG(0,("Out of memory!\n"));
123                 TALLOC_FREE(entry);
124                 return NT_STATUS_NO_MEMORY;
125         }
126         entry->name = talloc_strdup(entry, name);
127         if ( ! entry->name) {
128                 DEBUG(0,("Out of memory!\n"));
129                 TALLOC_FREE(entry);
130                 return NT_STATUS_NO_MEMORY;
131         }
132         entry->methods = methods;
133
134         DLIST_ADD(backends, entry);
135         DEBUG(5, ("Successfully added idmap backend '%s'\n", name));
136         return NT_STATUS_OK;
137 }
138
139 static int close_domain_destructor(struct idmap_domain *dom)
140 {
141         NTSTATUS ret;
142
143         ret = dom->methods->close_fn(dom);
144         if (!NT_STATUS_IS_OK(ret)) {
145                 DEBUG(3, ("Failed to close idmap domain [%s]!\n", dom->name));
146         }
147
148         return 0;
149 }
150
151 static bool parse_idmap_module(TALLOC_CTX *mem_ctx, const char *param,
152                                char **pmodulename, char **pargs)
153 {
154         char *modulename;
155         char *args;
156
157         if (strncmp(param, "idmap_", 6) == 0) {
158                 param += 6;
159                 DEBUG(1, ("idmap_init: idmap backend uses deprecated "
160                           "'idmap_' prefix.  Please replace 'idmap_%s' by "
161                           "'%s'\n", param, param));
162         }
163
164         modulename = talloc_strdup(mem_ctx, param);
165         if (modulename == NULL) {
166                 return false;
167         }
168
169         args = strchr(modulename, ':');
170         if (args == NULL) {
171                 *pmodulename = modulename;
172                 *pargs = NULL;
173                 return true;
174         }
175
176         *args = '\0';
177
178         args = talloc_strdup(mem_ctx, args+1);
179         if (args == NULL) {
180                 TALLOC_FREE(modulename);
181                 return false;
182         }
183
184         *pmodulename = modulename;
185         *pargs = args;
186         return true;
187 }
188
189 /**
190  * Initialize a domain structure
191  * @param[in] mem_ctx           memory context for the result
192  * @param[in] domainname        which domain is this for
193  * @param[in] modulename        which backend module
194  * @param[in] params            parameter to pass to the init function
195  * @result The initialized structure
196  */
197 static struct idmap_domain *idmap_init_domain(TALLOC_CTX *mem_ctx,
198                                               const char *domainname,
199                                               const char *modulename,
200                                               const char *params)
201 {
202         struct idmap_domain *result;
203         NTSTATUS status;
204
205         result = talloc_zero(mem_ctx, struct idmap_domain);
206         if (result == NULL) {
207                 DEBUG(0, ("talloc failed\n"));
208                 return NULL;
209         }
210
211         result->name = talloc_strdup(result, domainname);
212         if (result->name == NULL) {
213                 DEBUG(0, ("talloc failed\n"));
214                 goto fail;
215         }
216
217         result->methods = get_methods(modulename);
218         if (result->methods == NULL) {
219                 DEBUG(3, ("idmap backend %s not found\n", modulename));
220
221                 status = smb_probe_module("idmap", modulename);
222                 if (!NT_STATUS_IS_OK(status)) {
223                         DEBUG(3, ("Could not probe idmap module %s\n",
224                                   modulename));
225                         goto fail;
226                 }
227
228                 result->methods = get_methods(modulename);
229         }
230         if (result->methods == NULL) {
231                 DEBUG(1, ("idmap backend %s not found\n", modulename));
232                 goto fail;
233         }
234
235         status = result->methods->init(result, params);
236         if (!NT_STATUS_IS_OK(status)) {
237                 DEBUG(1, ("idmap initialization returned %s\n",
238                           nt_errstr(status)));
239                 goto fail;
240         }
241
242         talloc_set_destructor(result, close_domain_destructor);
243
244         return result;
245
246 fail:
247         TALLOC_FREE(result);
248         return NULL;
249 }
250
251 /**
252  * Initialize the default domain structure
253  * @param[in] mem_ctx           memory context for the result
254  * @result The default domain structure
255  *
256  * This routine takes the module name from the "idmap backend" parameter,
257  * passing a possible parameter like ldap:ldap://ldap-url/ to the module.
258  */
259
260 static struct idmap_domain *idmap_init_default_domain(TALLOC_CTX *mem_ctx)
261 {
262         struct idmap_domain *result;
263         char *modulename;
264         char *params;
265
266         DEBUG(10, ("idmap_init_default_domain: calling static_init_idmap\n"));
267
268         static_init_idmap;
269
270         if (!parse_idmap_module(talloc_tos(), lp_idmap_backend(), &modulename,
271                                 &params)) {
272                 DEBUG(1, ("parse_idmap_module failed\n"));
273                 return NULL;
274         }
275
276         DEBUG(3, ("idmap_init: using '%s' as remote backend\n", modulename));
277
278         result = idmap_init_domain(mem_ctx, "*", modulename, params);
279         if (result == NULL) {
280                 goto fail;
281         }
282
283         TALLOC_FREE(modulename);
284         TALLOC_FREE(params);
285         return result;
286
287 fail:
288         TALLOC_FREE(modulename);
289         TALLOC_FREE(params);
290         TALLOC_FREE(result);
291         return NULL;
292 }
293
294 /**
295  * Initialize a named domain structure
296  * @param[in] mem_ctx           memory context for the result
297  * @param[in] domname           the domain name
298  * @result The default domain structure
299  *
300  * This routine looks at the "idmap config <domname>" parameters to figure out
301  * the configuration.
302  */
303
304 static struct idmap_domain *idmap_init_named_domain(TALLOC_CTX *mem_ctx,
305                                                     const char *domname)
306 {
307         struct idmap_domain *result = NULL;
308         char *config_option;
309         const char *backend;
310
311         config_option = talloc_asprintf(talloc_tos(), "idmap config %s",
312                                         domname);
313         if (config_option == NULL) {
314                 DEBUG(0, ("talloc failed\n"));
315                 goto fail;
316         }
317
318         backend = lp_parm_const_string(-1, config_option, "backend", NULL);
319         if (backend == NULL) {
320                 DEBUG(1, ("no backend defined for %s\n", config_option));
321                 goto fail;
322         }
323
324         result = idmap_init_domain(mem_ctx, domname, backend, NULL);
325         if (result == NULL) {
326                 goto fail;
327         }
328
329         TALLOC_FREE(config_option);
330         return result;
331
332 fail:
333         TALLOC_FREE(config_option);
334         TALLOC_FREE(result);
335         return NULL;
336 }
337
338 /**
339  * Initialize the passdb domain structure
340  * @param[in] mem_ctx           memory context for the result
341  * @result The default domain structure
342  *
343  * No config, passdb has its own configuration.
344  */
345
346 static struct idmap_domain *idmap_init_passdb_domain(TALLOC_CTX *mem_ctx)
347 {
348         if (passdb_idmap_domain != NULL) {
349                 return passdb_idmap_domain;
350         }
351
352         passdb_idmap_domain = idmap_init_domain(NULL, get_global_sam_name(),
353                                                 "passdb", NULL);
354         if (passdb_idmap_domain == NULL) {
355                 DEBUG(1, ("Could not init passdb idmap domain\n"));
356         }
357
358         return passdb_idmap_domain;
359 }
360
361 /**
362  * Find a domain struct according to a domain name
363  * @param[in] domname           Domain name to get the config for
364  * @result The default domain structure that fits
365  *
366  * This is the central routine in the winbindd-idmap child to pick the correct
367  * domain for looking up IDs. If domname is NULL or empty, we use the default
368  * domain. If it contains something, we try to use idmap_init_named_domain()
369  * to fetch the correct backend.
370  *
371  * The choice about "domname" is being made by the winbind parent, look at the
372  * "have_idmap_config" of "struct winbindd_domain" which is set in
373  * add_trusted_domain.
374  */
375
376 static struct idmap_domain *idmap_find_domain(const char *domname)
377 {
378         struct idmap_domain *result;
379         int i;
380
381         DEBUG(10, ("idmap_find_domain called for domain '%s'\n",
382                    domname?domname:"NULL"));
383
384         /*
385          * Always init the default domain, we can't go without one
386          */
387         if (default_idmap_domain == NULL) {
388                 default_idmap_domain = idmap_init_default_domain(NULL);
389         }
390         if (default_idmap_domain == NULL) {
391                 return NULL;
392         }
393
394         if ((domname == NULL) || (domname[0] == '\0')) {
395                 return default_idmap_domain;
396         }
397
398         for (i=0; i<num_domains; i++) {
399                 if (strequal(idmap_domains[i]->name, domname)) {
400                         return idmap_domains[i];
401                 }
402         }
403
404         if (idmap_domains == NULL) {
405                 /*
406                  * talloc context for all idmap domains
407                  */
408                 idmap_domains = TALLOC_ARRAY(NULL, struct idmap_domain *, 1);
409         }
410
411         if (idmap_domains == NULL) {
412                 DEBUG(0, ("talloc failed\n"));
413                 return NULL;
414         }
415
416         result = idmap_init_named_domain(idmap_domains, domname);
417         if (result == NULL) {
418                 /*
419                  * Could not init that domain -- try the default one
420                  */
421                 return default_idmap_domain;
422         }
423
424         ADD_TO_ARRAY(idmap_domains, struct idmap_domain *, result,
425                      &idmap_domains, &num_domains);
426         return result;
427 }
428
429 void idmap_close(void)
430 {
431         TALLOC_FREE(default_idmap_domain);
432         TALLOC_FREE(passdb_idmap_domain);
433         TALLOC_FREE(idmap_domains);
434         num_domains = 0;
435 }
436
437 /**************************************************************************
438  idmap allocator interface functions
439 **************************************************************************/
440
441 static NTSTATUS idmap_allocate_unixid(struct unixid *id)
442 {
443         struct idmap_domain *dom;
444         struct id_map *maps[2];
445         struct id_map map;
446
447         dom = idmap_find_domain(NULL);
448
449         if (dom == NULL) {
450                 return NT_STATUS_UNSUCCESSFUL;
451         }
452
453         map.sid = NULL;
454         map.status = ID_UNKNOWN;
455         map.xid = *id;
456
457         maps[0] = &map;
458         maps[1] = NULL;
459
460         return dom->methods->sids_to_unixids(dom, maps);
461 }
462
463
464 NTSTATUS idmap_allocate_uid(struct unixid *id)
465 {
466         id->type = ID_TYPE_UID;
467         return idmap_allocate_unixid(id);
468 }
469
470 NTSTATUS idmap_allocate_gid(struct unixid *id)
471 {
472         id->type = ID_TYPE_GID;
473         return idmap_allocate_unixid(id);
474 }
475
476 NTSTATUS idmap_backends_unixid_to_sid(const char *domname, struct id_map *id)
477 {
478         struct idmap_domain *dom;
479         struct id_map *maps[2];
480
481          DEBUG(10, ("idmap_backend_unixid_to_sid: domain = '%s', xid = %d "
482                     "(type %d)\n",
483                     domname?domname:"NULL", id->xid.id, id->xid.type));
484
485         maps[0] = id;
486         maps[1] = NULL;
487
488         /*
489          * Always give passdb a chance first
490          */
491
492         dom = idmap_init_passdb_domain(NULL);
493         if ((dom != NULL)
494             && NT_STATUS_IS_OK(dom->methods->unixids_to_sids(dom, maps))
495             && id->status == ID_MAPPED) {
496                 return NT_STATUS_OK;
497         }
498
499         dom = idmap_find_domain(domname);
500         if (dom == NULL) {
501                 return NT_STATUS_NONE_MAPPED;
502         }
503
504         return dom->methods->unixids_to_sids(dom, maps);
505 }
506
507 NTSTATUS idmap_backends_sid_to_unixid(const char *domain, struct id_map *id)
508 {
509         struct idmap_domain *dom;
510         struct id_map *maps[2];
511
512          DEBUG(10, ("idmap_backends_sid_to_unixid: domain = '%s', sid = [%s]\n",
513                     domain?domain:"NULL", sid_string_dbg(id->sid)));
514
515         maps[0] = id;
516         maps[1] = NULL;
517
518         if (sid_check_is_in_builtin(id->sid)
519             || (sid_check_is_in_our_domain(id->sid))) {
520
521                 dom = idmap_init_passdb_domain(NULL);
522                 if (dom == NULL) {
523                         return NT_STATUS_NONE_MAPPED;
524                 }
525                 return dom->methods->sids_to_unixids(dom, maps);
526         }
527
528         dom = idmap_find_domain(domain);
529         if (dom == NULL) {
530                 return NT_STATUS_NONE_MAPPED;
531         }
532
533         return dom->methods->sids_to_unixids(dom, maps);
534 }