2 * idmap_ad: map between Active Directory and RFC 2307 or "Services for Unix" (SFU) Accounts
4 * Unix SMB/CIFS implementation.
6 * Winbind ADS backend functions
8 * Copyright (C) Andrew Tridgell 2001
9 * Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003
10 * Copyright (C) Gerald (Jerry) Carter 2004
11 * Copyright (C) Luke Howard 2001-2004
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31 #define DBGC_CLASS DBGC_IDMAP
33 #define WINBIND_CCACHE_NAME "MEMORY:winbind_ccache"
35 NTSTATUS init_module(void);
37 static ADS_STRUCT *ad_idmap_ads = NULL;
39 static char *attr_uidnumber = NULL;
40 static char *attr_gidnumber = NULL;
42 static ADS_STATUS ad_idmap_check_attr_mapping(ADS_STRUCT *ads)
45 enum wb_posix_mapping map_type;
47 if (attr_uidnumber != NULL && attr_gidnumber != NULL) {
48 return ADS_ERROR(LDAP_SUCCESS);
51 SMB_ASSERT(ads->server.workgroup);
53 map_type = get_nss_info(ads->server.workgroup);
55 if ((map_type == WB_POSIX_MAP_SFU) ||
56 (map_type == WB_POSIX_MAP_RFC2307)) {
58 status = ads_check_posix_schema_mapping(ads, map_type);
59 if (ADS_ERR_OK(status)) {
60 attr_uidnumber = SMB_STRDUP(ads->schema.posix_uidnumber_attr);
61 attr_gidnumber = SMB_STRDUP(ads->schema.posix_gidnumber_attr);
62 ADS_ERROR_HAVE_NO_MEMORY(attr_uidnumber);
63 ADS_ERROR_HAVE_NO_MEMORY(attr_gidnumber);
64 return ADS_ERROR(LDAP_SUCCESS);
66 DEBUG(0,("ads_check_posix_schema_mapping failed: %s\n", ads_errstr(status)));
71 /* fallback to XAD defaults */
72 attr_uidnumber = SMB_STRDUP("uidNumber");
73 attr_gidnumber = SMB_STRDUP("gidNumber");
74 ADS_ERROR_HAVE_NO_MEMORY(attr_uidnumber);
75 ADS_ERROR_HAVE_NO_MEMORY(attr_gidnumber);
77 return ADS_ERROR(LDAP_SUCCESS);
80 static ADS_STRUCT *ad_idmap_cached_connection(void)
86 if (ad_idmap_ads != NULL) {
89 /* check for a valid structure */
91 DEBUG(7, ("Current tickets expire at %d, time is now %d\n",
92 (uint32) ads->auth.expire, (uint32) time(NULL)));
93 if ( ads->config.realm && (ads->auth.expire > time(NULL))) {
96 /* we own this ADS_STRUCT so make sure it goes away */
99 ads_kdestroy(WINBIND_CCACHE_NAME);
105 /* we don't want this to affect the users ccache */
106 setenv("KRB5CCNAME", WINBIND_CCACHE_NAME, 1);
109 ads = ads_init(lp_realm(), lp_workgroup(), NULL);
111 DEBUG(1,("ads_init failed\n"));
115 /* the machine acct password might have change - fetch it every time */
116 SAFE_FREE(ads->auth.password);
117 ads->auth.password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
119 SAFE_FREE(ads->auth.realm);
120 ads->auth.realm = SMB_STRDUP(lp_realm());
122 status = ads_connect(ads);
123 if (!ADS_ERR_OK(status)) {
124 DEBUG(1, ("ad_idmap_init: failed to connect to AD\n"));
129 ads->is_mine = False;
131 status = ad_idmap_check_attr_mapping(ads);
132 if (!ADS_ERR_OK(status)) {
133 DEBUG(1, ("ad_idmap_init: failed to check attribute mapping\n"));
141 struct idmap_ad_context {
142 uint32_t filter_low_id, filter_high_id; /* Filter range */
145 /* Initialize and check conf is appropriate */
146 static NTSTATUS idmap_ad_initialize(struct idmap_domain *dom, const char *params)
148 struct idmap_ad_context *ctx;
153 /* verify AD is reachable (not critical, we may just be offline at start) */
154 ads = ad_idmap_cached_connection();
156 DEBUG(1, ("WARNING: Could not init an AD connection! Mapping might not work.\n"));
159 ctx = talloc_zero(dom, struct idmap_ad_context);
161 DEBUG(0, ("Out of memory!\n"));
162 return NT_STATUS_NO_MEMORY;
165 config_option = talloc_asprintf(ctx, "idmap config %s", dom->name);
166 if ( ! config_option) {
167 DEBUG(0, ("Out of memory!\n"));
169 return NT_STATUS_NO_MEMORY;
173 range = lp_parm_const_string(-1, config_option, "range", NULL);
174 if (range && range[0]) {
175 if ((sscanf(range, "%u - %u", &ctx->filter_low_id, &ctx->filter_high_id) != 2) ||
176 (ctx->filter_low_id > ctx->filter_high_id)) {
177 DEBUG(1, ("ERROR: invalid filter range [%s]", range));
178 ctx->filter_low_id = 0;
179 ctx->filter_high_id = 0;
183 /* idmap AD can work well only if it is the default module (trusts)
184 * with additional BUILTIN and alloc using TDB */
185 if ( ! dom->default_domain) {
186 DEBUG(1, ("WARNING: idmap_ad is not configured as the default domain.\n"
187 "For best results we suggest you to configure this module as\n"
188 "default and configure BULTIN to use idmap_tdb\n"
189 "ex: idmap domains = BUILTIN %s\n"
190 " idmap alloc config: range = 5000 - 9999\n"
191 " idmap config %s: default = yes\n"
192 " idmap config %s: backend = ad\n"
193 " idmap config %s: range = 10000 - 10000000 #this is optional\n"
194 "NOTE: make sure the ranges do not overlap\n",
195 dom->name, dom->name, dom->name, dom->name));
197 if ( ! dom->readonly) {
198 DEBUG(1, ("WARNING: forcing to readonly, as idmap_ad can't write on AD.\n"));
199 dom->readonly = true; /* force readonly */
202 dom->private_data = ctx;
204 talloc_free(config_option);
208 #define IDMAP_AD_MAX_IDS 30
209 #define CHECK_ALLOC_DONE(mem) do { if (!mem) { DEBUG(0, ("Out of memory!\n")); ret = NT_STATUS_NO_MEMORY; goto done; } } while (0)
211 /* this function searches up to IDMAP_AD_MAX_IDS entries in maps for a match */
212 static struct id_map *find_map_by_id(struct id_map **maps, enum id_type type, uint32_t id)
216 for (i = 0; i < IDMAP_AD_MAX_IDS; i++) {
217 if (maps[i] == NULL) { /* end of the run */
220 if ((maps[i]->xid.type == type) && (maps[i]->xid.id == id)) {
228 static NTSTATUS idmap_ad_unixids_to_sids(struct idmap_domain *dom, struct id_map **ids)
232 struct idmap_ad_context *ctx;
235 const char *attrs[] = { "sAMAccountType",
237 NULL, /* attr_uidnumber */
238 NULL, /* attr_gidnumber */
240 LDAPMessage *res = NULL;
248 ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
250 memctx = talloc_new(ctx);
252 DEBUG(0, ("Out of memory!\n"));
253 return NT_STATUS_NO_MEMORY;
256 ads = ad_idmap_cached_connection();
258 DEBUG(1, ("ADS uninitialized\n"));
259 ret = NT_STATUS_UNSUCCESSFUL;
263 /* attr_uidnumber and attr_gidnumber are surely successfully initialized now */
264 attrs[2] = attr_uidnumber;
265 attrs[3] = attr_gidnumber;
268 /* if we are requested just one mapping use the simple filter */
269 switch (ids[0]->xid.type) {
272 filter = talloc_asprintf(memctx,
273 "(&(|(sAMAccountType=%d)(sAMAccountType=%d)(sAMAccountType=%d))(%s=%lu))",
274 ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST, ATYPE_INTERDOMAIN_TRUST,
276 (unsigned long)ids[0]->xid.id);
280 filter = talloc_asprintf(memctx,
281 "(&(|(sAMAccountType=%d)(sAMAccountType=%d))(%s=%lu))",
282 ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_LOCAL_GROUP,
284 (unsigned long)ids[0]->xid.id);
287 DEBUG(3, ("Unknown ID type\n"));
288 ret = NT_STATUS_INVALID_PARAMETER;
291 CHECK_ALLOC_DONE(filter);
292 DEBUG(10, ("Filter: [%s]\n", filter));
294 /* multiple mappings */
300 char *u_filter = NULL;
301 char *g_filter = NULL;
304 for (i = 0; (i < IDMAP_AD_MAX_IDS) && ids[idx]; i++, idx++) {
305 switch (ids[idx]->xid.type) {
309 u_filter = talloc_asprintf(memctx, "(&(|"
310 "(sAMAccountType=%d)"
311 "(sAMAccountType=%d)"
312 "(sAMAccountType=%d))(|",
313 ATYPE_NORMAL_ACCOUNT,
314 ATYPE_WORKSTATION_TRUST,
315 ATYPE_INTERDOMAIN_TRUST);
317 u_filter = talloc_asprintf_append(u_filter, "(%s=%lu)",
319 (unsigned long)ids[idx]->xid.id);
320 CHECK_ALLOC_DONE(u_filter);
325 g_filter = talloc_asprintf(memctx, "(&(|"
326 "(sAMAccountType=%d)"
327 "(sAMAccountType=%d))(|",
328 ATYPE_SECURITY_GLOBAL_GROUP,
329 ATYPE_SECURITY_LOCAL_GROUP);
331 g_filter = talloc_asprintf_append(g_filter, "(%s=%lu)",
333 (unsigned long)ids[idx]->xid.id);
334 CHECK_ALLOC_DONE(g_filter);
338 DEBUG(3, ("Unknown ID type\n"));
339 ids[idx]->mapped = false;
343 filter = talloc_asprintf(memctx, "(|");
344 CHECK_ALLOC_DONE(filter);
346 filter = talloc_asprintf_append(filter, "%s))", u_filter);
347 CHECK_ALLOC_DONE(filter);
348 TALLOC_FREE(u_filter);
351 filter = talloc_asprintf_append(filter, "%s))", g_filter);
352 CHECK_ALLOC_DONE(filter);
353 TALLOC_FREE(g_filter);
355 filter = talloc_asprintf_append(filter, ")");
356 CHECK_ALLOC_DONE(filter);
357 DEBUG(10, ("Filter: [%s]\n", filter));
363 rc = ads_search_retry(ads, &res, filter, attrs);
364 if (!ADS_ERR_OK(rc)) {
365 DEBUG(1, ("ERROR: ads search returned: %s\n", ads_errstr(rc)));
366 ret = NT_STATUS_UNSUCCESSFUL;
370 count = ads_count_replies(ads, res);
372 DEBUG(10, ("No IDs found\n"));
375 for (i = 0; i < count; i++) {
376 LDAPMessage *entry = NULL;
383 if (i == 0) { /* first entry */
384 entry = ads_first_entry(ads, res);
385 } else { /* following ones */
386 entry = ads_next_entry(ads, entry);
389 DEBUG(2, ("ERROR: Unable to fetch ldap entries from results\n"));
393 /* first check if the SID is present */
394 if (!ads_pull_sid(ads, entry, "objectSid", &sid)) {
395 DEBUG(2, ("Could not retrieve SID from entry\n"));
400 if (!ads_pull_uint32(ads, entry, "sAMAccountType", &atype)) {
401 DEBUG(1, ("could not get SAM account type\n"));
405 switch (atype & 0xF0000000) {
406 case ATYPE_SECURITY_GLOBAL_GROUP:
407 case ATYPE_SECURITY_LOCAL_GROUP:
410 case ATYPE_NORMAL_ACCOUNT:
411 case ATYPE_WORKSTATION_TRUST:
412 case ATYPE_INTERDOMAIN_TRUST:
416 DEBUG(1, ("unrecognized SAM account type %08x\n", atype));
420 if (!ads_pull_uint32(ads, entry, (type==ID_TYPE_UID)?attr_uidnumber:attr_gidnumber, &id)) {
421 DEBUG(1, ("Could not get unix ID\n"));
425 (ctx->filter_low_id && (id < ctx->filter_low_id)) ||
426 (ctx->filter_high_id && (id > ctx->filter_high_id))) {
427 DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
428 id, ctx->filter_low_id, ctx->filter_high_id));
432 map = find_map_by_id(&ids[bidx], type, id);
434 DEBUG(2, ("WARNING: couldn't match result with requested ID\n"));
438 sid_copy(map->sid, &sid);
443 DEBUG(10, ("Mapped %s -> %lu (%d)\n",
444 sid_string_static(map->sid),
445 (unsigned long)map->xid.id,
450 ads_msgfree(ads, res);
453 if (multi && ids[idx]) { /* still some values to map */
463 /* this function searches up to IDMAP_AD_MAX_IDS entries in maps for a match */
464 static struct id_map *find_map_by_sid(struct id_map **maps, DOM_SID *sid)
468 for (i = 0; i < IDMAP_AD_MAX_IDS; i++) {
469 if (maps[i] == NULL) { /* end of the run */
472 if (sid_equal(maps[i]->sid, sid)) {
480 static NTSTATUS idmap_ad_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids)
484 struct idmap_ad_context *ctx;
487 const char *attrs[] = { "sAMAccountType",
489 NULL, /* attr_uidnumber */
490 NULL, /* attr_gidnumber */
492 LDAPMessage *res = NULL;
500 ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
502 memctx = talloc_new(ctx);
504 DEBUG(0, ("Out of memory!\n"));
505 return NT_STATUS_NO_MEMORY;
508 ads = ad_idmap_cached_connection();
510 DEBUG(1, ("ADS uninitialized\n"));
511 ret = NT_STATUS_UNSUCCESSFUL;
515 /* attr_uidnumber and attr_gidnumber are surely successfully initialized now */
516 attrs[2] = attr_uidnumber;
517 attrs[3] = attr_gidnumber;
521 /* if we are requested just one mapping use the simple filter */
524 sidstr = sid_binstring(ids[0]->sid);
525 filter = talloc_asprintf(memctx, "(&(objectSid=%s)(|" /* the requested Sid */
526 "(sAMAccountType=%d)(sAMAccountType=%d)(sAMAccountType=%d)" /* user account types */
527 "(sAMAccountType=%d)(sAMAccountType=%d)))", /* group account types */
529 ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST, ATYPE_INTERDOMAIN_TRUST,
530 ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_LOCAL_GROUP);
533 ret = NT_STATUS_NO_MEMORY;
536 CHECK_ALLOC_DONE(filter);
537 DEBUG(10, ("Filter: [%s]\n", filter));
539 /* multiple mappings */
547 filter = talloc_asprintf(memctx,
549 "(sAMAccountType=%d)(sAMAccountType=%d)(sAMAccountType=%d)" /* user account types */
550 "(sAMAccountType=%d)(sAMAccountType=%d)" /* group account types */
552 ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST, ATYPE_INTERDOMAIN_TRUST,
553 ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_LOCAL_GROUP);
555 CHECK_ALLOC_DONE(filter);
558 for (i = 0; (i < IDMAP_AD_MAX_IDS) && ids[idx]; i++, idx++) {
560 sidstr = sid_binstring(ids[idx]->sid);
561 filter = talloc_asprintf_append(filter, "(objectSid=%s)", sidstr);
564 CHECK_ALLOC_DONE(filter);
566 filter = talloc_asprintf_append(filter, "))");
567 CHECK_ALLOC_DONE(filter);
568 DEBUG(10, ("Filter: [%s]\n", filter));
574 rc = ads_search_retry(ads, &res, filter, attrs);
575 if (!ADS_ERR_OK(rc)) {
576 DEBUG(1, ("ERROR: ads search returned: %s\n", ads_errstr(rc)));
577 ret = NT_STATUS_UNSUCCESSFUL;
581 count = ads_count_replies(ads, res);
583 DEBUG(10, ("No IDs found\n"));
586 for (i = 0; i < count; i++) {
587 LDAPMessage *entry = NULL;
594 if (i == 0) { /* first entry */
595 entry = ads_first_entry(ads, res);
596 } else { /* following ones */
597 entry = ads_next_entry(ads, entry);
600 DEBUG(2, ("ERROR: Unable to fetch ldap entries from results\n"));
604 /* first check if the SID is present */
605 if (!ads_pull_sid(ads, entry, "objectSid", &sid)) {
606 DEBUG(2, ("Could not retrieve SID from entry\n"));
610 map = find_map_by_sid(&ids[bidx], &sid);
612 DEBUG(2, ("WARNING: couldn't match result with requested SID\n"));
617 if (!ads_pull_uint32(ads, entry, "sAMAccountType", &atype)) {
618 DEBUG(1, ("could not get SAM account type\n"));
622 switch (atype & 0xF0000000) {
623 case ATYPE_SECURITY_GLOBAL_GROUP:
624 case ATYPE_SECURITY_LOCAL_GROUP:
627 case ATYPE_NORMAL_ACCOUNT:
628 case ATYPE_WORKSTATION_TRUST:
629 case ATYPE_INTERDOMAIN_TRUST:
633 DEBUG(1, ("unrecognized SAM account type %08x\n", atype));
637 if (!ads_pull_uint32(ads, entry, (type==ID_TYPE_UID)?attr_uidnumber:attr_gidnumber, &id)) {
638 DEBUG(1, ("Could not get unix ID\n"));
642 (ctx->filter_low_id && (id < ctx->filter_low_id)) ||
643 (ctx->filter_high_id && (id > ctx->filter_high_id))) {
644 DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
645 id, ctx->filter_low_id, ctx->filter_high_id));
650 map->xid.type = type;
654 DEBUG(10, ("Mapped %s -> %lu (%d)\n",
655 sid_string_static(map->sid),
656 (unsigned long)map->xid.id,
661 ads_msgfree(ads, res);
664 if (multi && ids[idx]) { /* still some values to map */
674 static NTSTATUS idmap_ad_close(struct idmap_domain *dom)
676 ADS_STRUCT *ads = ad_idmap_ads;
679 /* we own this ADS_STRUCT so make sure it goes away */
685 SAFE_FREE(attr_uidnumber);
686 SAFE_FREE(attr_gidnumber);
691 static struct idmap_methods ad_methods = {
692 .init = idmap_ad_initialize,
693 .unixids_to_sids = idmap_ad_unixids_to_sids,
694 .sids_to_unixids = idmap_ad_sids_to_unixids,
695 .close_fn = idmap_ad_close
698 /* support for new authentication subsystem */
699 NTSTATUS idmap_ad_init(void)
701 return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "ad", &ad_methods);