Line data Source code
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 : Copyright (C) Michael Adam 2010
9 :
10 : This program is free software; you can redistribute it and/or modify
11 : it under the terms of the GNU General Public License as published by
12 : the Free Software Foundation; either version 3 of the License, or
13 : (at your option) any later version.
14 :
15 : This program is distributed in the hope that it will be useful,
16 : but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : GNU General Public License for more details.
19 :
20 : You should have received a copy of the GNU General Public License
21 : along with this program. If not, see <http://www.gnu.org/licenses/>.
22 : */
23 :
24 : #include "includes.h"
25 : #include "winbindd.h"
26 : #include "idmap.h"
27 : #include "lib/util_sid_passdb.h"
28 : #include "libcli/security/dom_sid.h"
29 : #include "passdb.h"
30 :
31 : #undef DBGC_CLASS
32 : #define DBGC_CLASS DBGC_IDMAP
33 :
34 : static_decl_idmap;
35 :
36 : /**
37 : * Pointer to the backend methods. Modules register themselves here via
38 : * smb_register_idmap.
39 : */
40 :
41 : struct idmap_backend {
42 : const char *name;
43 : const struct idmap_methods *methods;
44 : struct idmap_backend *prev, *next;
45 : };
46 : static struct idmap_backend *backends = NULL;
47 :
48 : /**
49 : * Default idmap domain configured via "idmap backend".
50 : */
51 : static struct idmap_domain *default_idmap_domain;
52 :
53 : /**
54 : * Passdb idmap domain, not configurable. winbind must always give passdb a
55 : * chance to map ids.
56 : */
57 : static struct idmap_domain *passdb_idmap_domain;
58 :
59 : /**
60 : * List of specially configured idmap domains. This list is filled on demand
61 : * in the winbind idmap child when the parent winbind figures out via the
62 : * special range parameter or via the domain SID that a special "idmap config
63 : * domain" configuration is present.
64 : */
65 : static struct idmap_domain **idmap_domains = NULL;
66 : static int num_domains = 0;
67 :
68 : static struct idmap_domain *idmap_init_named_domain(TALLOC_CTX *mem_ctx,
69 : const char *domname);
70 : static struct idmap_domain *idmap_init_domain(TALLOC_CTX *mem_ctx,
71 : const char *domainname,
72 : const char *modulename,
73 : bool check_range);
74 :
75 : struct lp_scan_idmap_domains_state {
76 : bool (*fn)(const char *domname, void *private_data);
77 : void *private_data;
78 : };
79 :
80 : static bool lp_scan_idmap_found_domain(
81 : const char *string, regmatch_t matches[], void *private_data);
82 :
83 45 : bool lp_scan_idmap_domains(bool (*fn)(const char *domname,
84 : void *private_data),
85 : void *private_data)
86 : {
87 45 : struct lp_scan_idmap_domains_state state = {
88 : .fn = fn, .private_data = private_data };
89 0 : int ret;
90 :
91 45 : ret = lp_wi_scan_global_parametrics(
92 : "idmapconfig\\(.*\\):backend", 2,
93 : lp_scan_idmap_found_domain, &state);
94 45 : if (ret != 0) {
95 0 : DBG_WARNING("wi_scan_global_parametrics returned %d\n", ret);
96 0 : return false;
97 : }
98 :
99 45 : return true;
100 : }
101 :
102 55 : static bool lp_scan_idmap_found_domain(
103 : const char *string, regmatch_t matches[], void *private_data)
104 : {
105 0 : bool ok;
106 :
107 55 : if (matches[1].rm_so == -1) {
108 0 : DBG_WARNING("Found match, but no name??\n");
109 0 : return false;
110 : }
111 55 : if (matches[1].rm_eo <= matches[1].rm_so) {
112 0 : DBG_WARNING("Invalid match\n");
113 0 : return false;
114 : }
115 :
116 55 : {
117 55 : struct lp_scan_idmap_domains_state *state = private_data;
118 55 : regoff_t len = matches[1].rm_eo - matches[1].rm_so;
119 55 : char domname[len+1];
120 :
121 55 : memcpy(domname, string + matches[1].rm_so, len);
122 55 : domname[len] = '\0';
123 :
124 55 : DBG_DEBUG("Found idmap domain \"%s\"\n", domname);
125 :
126 55 : ok = state->fn(domname, state->private_data);
127 : }
128 :
129 55 : return ok;
130 : }
131 :
132 : static bool idmap_found_domain_backend(const char *domname,
133 : void *private_data);
134 :
135 0 : static bool idmap_init(void)
136 : {
137 0 : static bool initialized;
138 0 : bool ok;
139 :
140 0 : if (initialized) {
141 0 : return true;
142 : }
143 :
144 0 : DEBUG(10, ("idmap_init(): calling static_init_idmap\n"));
145 :
146 0 : static_init_idmap(NULL);
147 :
148 0 : initialized = true;
149 :
150 0 : if (!pdb_is_responsible_for_everything_else()) {
151 0 : default_idmap_domain = idmap_init_named_domain(NULL, "*");
152 0 : if (default_idmap_domain == NULL) {
153 0 : return false;
154 : }
155 : }
156 :
157 0 : passdb_idmap_domain = idmap_init_domain(
158 : NULL, get_global_sam_name(), "passdb", false);
159 0 : if (passdb_idmap_domain == NULL) {
160 0 : TALLOC_FREE(default_idmap_domain);
161 0 : return false;
162 : }
163 :
164 0 : idmap_domains = talloc_array(NULL, struct idmap_domain *, 0);
165 0 : if (idmap_domains == NULL) {
166 0 : TALLOC_FREE(passdb_idmap_domain);
167 0 : TALLOC_FREE(default_idmap_domain);
168 0 : return false;
169 : }
170 :
171 0 : ok = lp_scan_idmap_domains(idmap_found_domain_backend, NULL);
172 0 : if (!ok) {
173 0 : DBG_WARNING("lp_scan_idmap_domains failed\n");
174 0 : return false;
175 : }
176 :
177 0 : return true;
178 : }
179 :
180 110 : static int idmap_config_name(const char *domname, char *buf, size_t buflen)
181 : {
182 110 : int len = snprintf(buf, buflen, "idmap config %s", domname);
183 110 : SMB_ASSERT(len > 0);
184 110 : return len + 1;
185 : }
186 :
187 55 : const char *idmap_config_const_string(const char *domname, const char *option,
188 : const char *def)
189 55 : {
190 55 : int len = idmap_config_name(domname, NULL, 0);
191 55 : char config_option[len];
192 55 : idmap_config_name(domname, config_option, sizeof(config_option));
193 :
194 55 : return lp_parm_const_string(-1, config_option, option, def);
195 : }
196 :
197 0 : bool idmap_config_bool(const char *domname, const char *option, bool def)
198 0 : {
199 0 : int len = idmap_config_name(domname, NULL, 0);
200 0 : char config_option[len];
201 0 : idmap_config_name(domname, config_option, sizeof(config_option));
202 :
203 0 : return lp_parm_bool(-1, config_option, option, def);
204 : }
205 :
206 0 : int idmap_config_int(const char *domname, const char *option, int def)
207 0 : {
208 0 : int len = idmap_config_name(domname, NULL, 0);
209 0 : char config_option[len];
210 0 : idmap_config_name(domname, config_option, sizeof(config_option));
211 :
212 0 : return lp_parm_int(-1, config_option, option, def);
213 : }
214 :
215 0 : const char **idmap_config_string_list(const char *domname,
216 : const char *option,
217 : const char **def)
218 0 : {
219 0 : int len = idmap_config_name(domname, NULL, 0);
220 0 : char config_option[len];
221 0 : idmap_config_name(domname, config_option, sizeof(config_option));
222 :
223 0 : return lp_parm_string_list(-1, config_option, option, def);
224 : }
225 :
226 0 : bool domain_has_idmap_config(const char *domname)
227 : {
228 0 : int i;
229 0 : const char *range = NULL;
230 0 : const char *backend = NULL;
231 0 : bool ok;
232 :
233 0 : ok = idmap_init();
234 0 : if (!ok) {
235 0 : return false;
236 : }
237 :
238 0 : for (i=0; i<num_domains; i++) {
239 0 : if (strequal(idmap_domains[i]->name, domname)) {
240 0 : return true;
241 : }
242 : }
243 :
244 : /* fallback: also check loadparm */
245 :
246 0 : range = idmap_config_const_string(domname, "range", NULL);
247 0 : backend = idmap_config_const_string(domname, "backend", NULL);
248 0 : if (range != NULL && backend != NULL) {
249 0 : DEBUG(5, ("idmap configuration specified for domain '%s'\n",
250 : domname));
251 0 : return true;
252 : }
253 :
254 0 : return false;
255 : }
256 :
257 0 : static bool idmap_found_domain_backend(const char *domname,
258 : void *private_data)
259 : {
260 0 : struct idmap_domain *dom, **tmp;
261 :
262 0 : DBG_DEBUG("Found idmap domain \"%s\"\n", domname);
263 :
264 0 : if (strcmp(domname, "*") == 0) {
265 0 : return false;
266 : }
267 :
268 0 : dom = idmap_init_named_domain(idmap_domains, domname);
269 0 : if (dom == NULL) {
270 0 : DBG_NOTICE("Could not init idmap domain %s\n", domname);
271 0 : return false;
272 : }
273 :
274 0 : tmp = talloc_realloc(idmap_domains, idmap_domains,
275 : struct idmap_domain *, num_domains + 1);
276 0 : if (tmp == NULL) {
277 0 : DBG_WARNING("talloc_realloc failed\n");
278 0 : TALLOC_FREE(dom);
279 0 : return false;
280 : }
281 0 : idmap_domains = tmp;
282 0 : idmap_domains[num_domains] = dom;
283 0 : num_domains += 1;
284 :
285 0 : return false;
286 : }
287 :
288 0 : static const struct idmap_methods *get_methods(const char *name)
289 : {
290 0 : struct idmap_backend *b;
291 :
292 0 : for (b = backends; b; b = b->next) {
293 0 : if (strequal(b->name, name)) {
294 0 : return b->methods;
295 : }
296 : }
297 :
298 0 : return NULL;
299 : }
300 :
301 0 : bool idmap_is_offline(void)
302 : {
303 0 : return ( lp_winbind_offline_logon() &&
304 0 : get_global_winbindd_state_offline() );
305 : }
306 :
307 : /**********************************************************************
308 : Allow a module to register itself as a method.
309 : **********************************************************************/
310 :
311 0 : NTSTATUS smb_register_idmap(int version, const char *name,
312 : const struct idmap_methods *methods)
313 : {
314 0 : struct idmap_backend *entry;
315 :
316 0 : if ((version != SMB_IDMAP_INTERFACE_VERSION)) {
317 0 : DEBUG(0, ("Failed to register idmap module.\n"
318 : "The module was compiled against "
319 : "SMB_IDMAP_INTERFACE_VERSION %d,\n"
320 : "current SMB_IDMAP_INTERFACE_VERSION is %d.\n"
321 : "Please recompile against the current version "
322 : "of samba!\n",
323 : version, SMB_IDMAP_INTERFACE_VERSION));
324 0 : return NT_STATUS_OBJECT_TYPE_MISMATCH;
325 : }
326 :
327 0 : if (!name || !name[0] || !methods) {
328 0 : DEBUG(0,("Called with NULL pointer or empty name!\n"));
329 0 : return NT_STATUS_INVALID_PARAMETER;
330 : }
331 :
332 0 : for (entry = backends; entry != NULL; entry = entry->next) {
333 0 : if (strequal(entry->name, name)) {
334 0 : DEBUG(5,("Idmap module %s already registered!\n",
335 : name));
336 0 : return NT_STATUS_OBJECT_NAME_COLLISION;
337 : }
338 : }
339 :
340 0 : entry = talloc(NULL, struct idmap_backend);
341 0 : if ( ! entry) {
342 0 : DEBUG(0,("Out of memory!\n"));
343 0 : TALLOC_FREE(entry);
344 0 : return NT_STATUS_NO_MEMORY;
345 : }
346 0 : entry->name = talloc_strdup(entry, name);
347 0 : if ( ! entry->name) {
348 0 : DEBUG(0,("Out of memory!\n"));
349 0 : TALLOC_FREE(entry);
350 0 : return NT_STATUS_NO_MEMORY;
351 : }
352 0 : entry->methods = methods;
353 :
354 0 : DLIST_ADD(backends, entry);
355 0 : DEBUG(5, ("Successfully added idmap backend '%s'\n", name));
356 0 : return NT_STATUS_OK;
357 : }
358 :
359 : /**
360 : * Initialize a domain structure
361 : * @param[in] mem_ctx memory context for the result
362 : * @param[in] domainname which domain is this for
363 : * @param[in] modulename which backend module
364 : * @param[in] check_range whether range checking should be done
365 : * @result The initialized structure
366 : */
367 0 : static struct idmap_domain *idmap_init_domain(TALLOC_CTX *mem_ctx,
368 : const char *domainname,
369 : const char *modulename,
370 : bool check_range)
371 : {
372 0 : struct idmap_domain *result;
373 0 : NTSTATUS status;
374 0 : const char *range;
375 0 : unsigned low_id = 0;
376 0 : unsigned high_id = 0;
377 :
378 0 : result = talloc_zero(mem_ctx, struct idmap_domain);
379 0 : if (result == NULL) {
380 0 : DEBUG(0, ("talloc failed\n"));
381 0 : return NULL;
382 : }
383 :
384 0 : result->name = talloc_strdup(result, domainname);
385 0 : if (result->name == NULL) {
386 0 : DEBUG(0, ("talloc failed\n"));
387 0 : goto fail;
388 : }
389 :
390 : /*
391 : * Check whether the requested backend module exists and
392 : * load the methods.
393 : */
394 :
395 0 : result->methods = get_methods(modulename);
396 0 : if (result->methods == NULL) {
397 0 : DEBUG(3, ("idmap backend %s not found\n", modulename));
398 :
399 0 : status = smb_probe_module("idmap", modulename);
400 0 : if (!NT_STATUS_IS_OK(status)) {
401 0 : DEBUG(3, ("Could not probe idmap module %s\n",
402 : modulename));
403 0 : goto fail;
404 : }
405 :
406 0 : result->methods = get_methods(modulename);
407 : }
408 0 : if (result->methods == NULL) {
409 0 : DEBUG(1, ("idmap backend %s not found\n", modulename));
410 0 : goto fail;
411 : }
412 :
413 : /*
414 : * load ranges and read only information from the config
415 : */
416 :
417 0 : result->read_only = idmap_config_bool(result->name, "read only", false);
418 0 : range = idmap_config_const_string(result->name, "range", NULL);
419 :
420 0 : if (range == NULL) {
421 0 : if (check_range) {
422 0 : DEBUG(1, ("idmap range not specified for domain %s\n",
423 : result->name));
424 0 : goto fail;
425 : }
426 0 : } else if (sscanf(range, "%u - %u", &low_id, &high_id) != 2)
427 : {
428 0 : DEBUG(1, ("invalid range '%s' specified for domain "
429 : "'%s'\n", range, result->name));
430 0 : if (check_range) {
431 0 : goto fail;
432 : }
433 0 : } else if (low_id > high_id) {
434 0 : DEBUG(1, ("Error: invalid idmap range detected: %u - %u\n",
435 : low_id, high_id));
436 0 : if (check_range) {
437 0 : goto fail;
438 : }
439 : }
440 :
441 0 : result->low_id = low_id;
442 0 : result->high_id = high_id;
443 :
444 0 : status = result->methods->init(result);
445 0 : if (!NT_STATUS_IS_OK(status)) {
446 0 : DEBUG(1, ("idmap initialization returned %s\n",
447 : nt_errstr(status)));
448 0 : goto fail;
449 : }
450 :
451 0 : return result;
452 :
453 0 : fail:
454 0 : TALLOC_FREE(result);
455 0 : return NULL;
456 : }
457 :
458 : /**
459 : * Initialize a named domain structure
460 : * @param[in] mem_ctx memory context for the result
461 : * @param[in] domname the domain name
462 : * @result The default domain structure
463 : *
464 : * This routine looks at the "idmap config <domname>" parameters to figure out
465 : * the configuration.
466 : */
467 :
468 0 : static struct idmap_domain *idmap_init_named_domain(TALLOC_CTX *mem_ctx,
469 : const char *domname)
470 : {
471 0 : struct idmap_domain *result = NULL;
472 0 : const char *backend;
473 0 : bool ok;
474 :
475 0 : ok = idmap_init();
476 0 : if (!ok) {
477 0 : return NULL;
478 : }
479 :
480 0 : backend = idmap_config_const_string(domname, "backend", NULL);
481 0 : if (backend == NULL) {
482 0 : DEBUG(10, ("no idmap backend configured for domain '%s'\n",
483 : domname));
484 0 : goto fail;
485 : }
486 :
487 0 : result = idmap_init_domain(mem_ctx, domname, backend, true);
488 0 : if (result == NULL) {
489 0 : goto fail;
490 : }
491 :
492 0 : return result;
493 :
494 0 : fail:
495 0 : TALLOC_FREE(result);
496 0 : return NULL;
497 : }
498 :
499 : /**
500 : * Find a domain struct according to a domain name
501 : * @param[in] domname Domain name to get the config for
502 : * @result The default domain structure that fits
503 : *
504 : * This is the central routine in the winbindd-idmap child to pick the correct
505 : * domain for looking up IDs. If domname is NULL or empty, we use the default
506 : * domain. If it contains something, we try to use idmap_init_named_domain()
507 : * to fetch the correct backend.
508 : *
509 : * The choice about "domname" is being made by the winbind parent, look at the
510 : * "have_idmap_config" of "struct winbindd_domain" which is set in
511 : * add_trusted_domain.
512 : */
513 :
514 0 : struct idmap_domain *idmap_find_domain(const char *domname)
515 : {
516 0 : bool ok;
517 0 : int i;
518 :
519 0 : DEBUG(10, ("idmap_find_domain called for domain '%s'\n",
520 : domname?domname:"NULL"));
521 :
522 0 : ok = idmap_init();
523 0 : if (!ok) {
524 0 : return NULL;
525 : }
526 :
527 0 : if ((domname == NULL) || (domname[0] == '\0')) {
528 0 : return default_idmap_domain;
529 : }
530 :
531 0 : for (i=0; i<num_domains; i++) {
532 0 : if (strequal(idmap_domains[i]->name, domname)) {
533 0 : return idmap_domains[i];
534 : }
535 : }
536 :
537 0 : return default_idmap_domain;
538 : }
539 :
540 0 : struct idmap_domain *idmap_find_domain_with_sid(const char *domname,
541 : const struct dom_sid *sid)
542 : {
543 0 : bool ok;
544 :
545 0 : ok = idmap_init();
546 0 : if (!ok) {
547 0 : return NULL;
548 : }
549 :
550 0 : if (sid_check_is_for_passdb(sid)) {
551 0 : return passdb_idmap_domain;
552 : }
553 :
554 0 : return idmap_find_domain(domname);
555 : }
556 :
557 45 : void idmap_close(void)
558 : {
559 45 : TALLOC_FREE(default_idmap_domain);
560 45 : TALLOC_FREE(passdb_idmap_domain);
561 45 : TALLOC_FREE(idmap_domains);
562 45 : num_domains = 0;
563 45 : }
564 :
565 : /**************************************************************************
566 : idmap allocator interface functions
567 : **************************************************************************/
568 :
569 0 : static NTSTATUS idmap_allocate_unixid(struct unixid *id)
570 : {
571 0 : struct idmap_domain *dom;
572 0 : NTSTATUS ret;
573 :
574 0 : dom = idmap_find_domain(NULL);
575 :
576 0 : if (dom == NULL) {
577 0 : return NT_STATUS_UNSUCCESSFUL;
578 : }
579 :
580 0 : if (dom->methods->allocate_id == NULL) {
581 0 : return NT_STATUS_NOT_IMPLEMENTED;
582 : }
583 :
584 0 : ret = dom->methods->allocate_id(dom, id);
585 :
586 0 : return ret;
587 : }
588 :
589 :
590 0 : NTSTATUS idmap_allocate_uid(struct unixid *id)
591 : {
592 0 : id->type = ID_TYPE_UID;
593 0 : return idmap_allocate_unixid(id);
594 : }
595 :
596 0 : NTSTATUS idmap_allocate_gid(struct unixid *id)
597 : {
598 0 : id->type = ID_TYPE_GID;
599 0 : return idmap_allocate_unixid(id);
600 : }
601 :
602 0 : NTSTATUS idmap_backend_unixids_to_sids(struct id_map **maps,
603 : const char *domain_name,
604 : struct dom_sid domain_sid)
605 : {
606 0 : struct idmap_domain *dom = NULL;
607 0 : NTSTATUS status;
608 0 : bool ok;
609 :
610 0 : ok = idmap_init();
611 0 : if (!ok) {
612 0 : return NT_STATUS_NONE_MAPPED;
613 : }
614 :
615 0 : if (strequal(domain_name, get_global_sam_name())) {
616 0 : dom = passdb_idmap_domain;
617 : }
618 0 : if (dom == NULL) {
619 0 : dom = idmap_find_domain(domain_name);
620 : }
621 0 : if (dom == NULL) {
622 0 : return NT_STATUS_NONE_MAPPED;
623 : }
624 :
625 0 : dom->dom_sid = domain_sid;
626 0 : status = dom->methods->unixids_to_sids(dom, maps);
627 :
628 0 : DBG_DEBUG("unixid_to_sids for domain %s returned %s\n",
629 : domain_name, nt_errstr(status));
630 :
631 0 : return status;
632 : }
|