ctdb-tests: Update statd-callout tests to handle both modes
[samba4-gss.git] / source3 / winbindd / idmap_ad.c
blob38e902b82925ac54f9b84acf4709cd999af563e3
1 /*
2 * idmap_ad: map between Active Directory and RFC 2307 accounts
4 * Copyright (C) Volker Lendecke 2015
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "winbindd.h"
22 #include "libsmb/namequery.h"
23 #include "idmap.h"
24 #include "tldap.h"
25 #include "tldap_util.h"
26 #include "tldap_tls_connect.h"
27 #include "tldap_gensec_bind.h"
28 #include "passdb.h"
29 #include "lib/param/param.h"
30 #include "auth/gensec/gensec.h"
31 #include "librpc/gen_ndr/ndr_netlogon.h"
32 #include "libads/ldap_schema_oids.h"
33 #include "../libds/common/flags.h"
34 #include "libcli/ldap/ldap_ndr.h"
35 #include "libcli/security/dom_sid.h"
36 #include "source3/libads/sitename_cache.h"
37 #include "source3/libads/kerberos_proto.h"
38 #include "source3/librpc/gen_ndr/ads.h"
39 #include "source3/lib/global_contexts.h"
40 #include <ldb.h>
41 #include "source4/lib/tls/tls.h"
43 struct idmap_ad_schema_names;
45 struct idmap_ad_context {
46 struct idmap_domain *dom;
47 struct tldap_context *ld;
48 struct idmap_ad_schema_names *schema;
49 const char *default_nc;
51 bool unix_primary_group;
52 bool unix_nss_info;
54 struct ldb_context *ldb;
55 struct ldb_dn **deny_ous;
56 struct ldb_dn **allow_ous;
59 static NTSTATUS idmap_ad_get_context(struct idmap_domain *dom,
60 struct idmap_ad_context **pctx);
62 static char *get_schema_path(TALLOC_CTX *mem_ctx, struct tldap_context *ld)
64 struct tldap_message *rootdse;
66 rootdse = tldap_rootdse(ld);
67 if (rootdse == NULL) {
68 return NULL;
71 return tldap_talloc_single_attribute(rootdse, "schemaNamingContext",
72 mem_ctx);
75 static char *get_default_nc(TALLOC_CTX *mem_ctx, struct tldap_context *ld)
77 struct tldap_message *rootdse;
79 rootdse = tldap_rootdse(ld);
80 if (rootdse == NULL) {
81 return NULL;
84 return tldap_talloc_single_attribute(rootdse, "defaultNamingContext",
85 mem_ctx);
88 struct idmap_ad_schema_names {
89 char *name;
90 char *uid;
91 char *gid;
92 char *gecos;
93 char *dir;
94 char *shell;
97 static TLDAPRC get_attrnames_by_oids(struct tldap_context *ld,
98 TALLOC_CTX *mem_ctx,
99 const char *schema_path,
100 size_t num_oids,
101 const char **oids,
102 char **names)
104 char *filter;
105 const char *attrs[] = { "lDAPDisplayName", "attributeId" };
106 size_t i;
107 TLDAPRC rc;
108 struct tldap_message **msgs;
109 size_t num_msgs;
111 filter = talloc_strdup(mem_ctx, "(|");
113 for (i=0; i<num_oids; i++) {
114 talloc_asprintf_addbuf(&filter, "(attributeId=%s)", oids[i]);
116 talloc_asprintf_addbuf(&filter, ")");
118 if (filter == NULL) {
119 return TLDAP_NO_MEMORY;
122 rc = tldap_search(ld, schema_path, TLDAP_SCOPE_SUB, filter,
123 attrs, ARRAY_SIZE(attrs), 0, NULL, 0, NULL, 0,
124 0, 0, 0, mem_ctx, &msgs);;
125 TALLOC_FREE(filter);
126 if (!TLDAP_RC_IS_SUCCESS(rc)) {
127 return rc;
130 for (i=0; i<num_oids; i++) {
131 names[i] = NULL;
134 num_msgs = talloc_array_length(msgs);
136 for (i=0; i<num_msgs; i++) {
137 struct tldap_message *msg = msgs[i];
138 char *oid;
139 size_t j;
141 if (tldap_msg_type(msg) != TLDAP_RES_SEARCH_ENTRY) {
142 /* Could be a TLDAP_RES_SEARCH_REFERENCE */
143 continue;
146 oid = tldap_talloc_single_attribute(
147 msg, "attributeId", msg);
148 if (oid == NULL) {
149 continue;
152 for (j=0; j<num_oids; j++) {
153 if (strequal(oid, oids[j])) {
154 break;
157 TALLOC_FREE(oid);
159 if (j == num_oids) {
160 /* not found */
161 continue;
164 names[j] = tldap_talloc_single_attribute(
165 msg, "lDAPDisplayName", mem_ctx);
168 TALLOC_FREE(msgs);
169 for (i=0; i<num_oids; i++) {
170 if (names[i] == NULL) {
171 DBG_ERR("Failed to retrieve schema name for "
172 "oid [%s]. Schema mode is incorrect "
173 "for this domain.\n", oids[i]);
174 return TLDAP_FILTER_ERROR;
178 return TLDAP_SUCCESS;
181 static TLDAPRC get_posix_schema_names(struct tldap_context *ld,
182 const char *schema_mode,
183 TALLOC_CTX *mem_ctx,
184 struct idmap_ad_schema_names **pschema)
186 char *schema_path;
187 struct idmap_ad_schema_names *schema;
188 char *names[6];
189 const char *oids_sfu[] = {
190 ADS_ATTR_SFU_UIDNUMBER_OID,
191 ADS_ATTR_SFU_GIDNUMBER_OID,
192 ADS_ATTR_SFU_HOMEDIR_OID,
193 ADS_ATTR_SFU_SHELL_OID,
194 ADS_ATTR_SFU_GECOS_OID,
195 ADS_ATTR_SFU_UID_OID
197 const char *oids_sfu20[] = {
198 ADS_ATTR_SFU20_UIDNUMBER_OID,
199 ADS_ATTR_SFU20_GIDNUMBER_OID,
200 ADS_ATTR_SFU20_HOMEDIR_OID,
201 ADS_ATTR_SFU20_SHELL_OID,
202 ADS_ATTR_SFU20_GECOS_OID,
203 ADS_ATTR_SFU20_UID_OID
205 const char *oids_rfc2307[] = {
206 ADS_ATTR_RFC2307_UIDNUMBER_OID,
207 ADS_ATTR_RFC2307_GIDNUMBER_OID,
208 ADS_ATTR_RFC2307_HOMEDIR_OID,
209 ADS_ATTR_RFC2307_SHELL_OID,
210 ADS_ATTR_RFC2307_GECOS_OID,
211 ADS_ATTR_RFC2307_UID_OID
213 const char **oids;
215 TLDAPRC rc;
217 schema = talloc(mem_ctx, struct idmap_ad_schema_names);
218 if (schema == NULL) {
219 return TLDAP_NO_MEMORY;
222 schema_path = get_schema_path(schema, ld);
223 if (schema_path == NULL) {
224 TALLOC_FREE(schema);
225 return TLDAP_NO_MEMORY;
228 oids = oids_rfc2307;
230 if ((schema_mode != NULL) && (schema_mode[0] != '\0')) {
231 if (strequal(schema_mode, "sfu")) {
232 oids = oids_sfu;
233 } else if (strequal(schema_mode, "sfu20")) {
234 oids = oids_sfu20;
235 } else if (strequal(schema_mode, "rfc2307" )) {
236 oids = oids_rfc2307;
237 } else {
238 DBG_WARNING("Unknown schema mode %s\n", schema_mode);
242 rc = get_attrnames_by_oids(ld, schema, schema_path, 6, oids, names);
243 TALLOC_FREE(schema_path);
244 if (!TLDAP_RC_IS_SUCCESS(rc)) {
245 TALLOC_FREE(schema);
246 return rc;
249 schema->uid = names[0];
250 schema->gid = names[1];
251 schema->dir = names[2];
252 schema->shell = names[3];
253 schema->gecos = names[4];
254 schema->name = names[5];
256 *pschema = schema;
258 return TLDAP_SUCCESS;
261 static void PRINTF_ATTRIBUTE(3, 0) idmap_ad_tldap_debug(
262 void *log_private,
263 enum tldap_debug_level level,
264 const char *fmt,
265 va_list ap)
267 int samba_level = -1;
269 switch (level) {
270 case TLDAP_DEBUG_FATAL:
271 samba_level = DBGLVL_ERR;
272 break;
273 case TLDAP_DEBUG_ERROR:
274 samba_level = DBGLVL_ERR;
275 break;
276 case TLDAP_DEBUG_WARNING:
277 samba_level = DBGLVL_WARNING;
278 break;
279 case TLDAP_DEBUG_TRACE:
280 samba_level = DBGLVL_DEBUG;
281 break;
284 if (CHECK_DEBUGLVL(samba_level)) {
285 char *s = NULL;
286 int ret;
288 ret = vasprintf(&s, fmt, ap);
289 if (ret == -1) {
290 return;
292 DEBUG(samba_level, ("idmap_ad_tldap: %s", s));
293 free(s);
297 static NTSTATUS idmap_ad_get_tldap_ctx(TALLOC_CTX *mem_ctx,
298 const char *domname,
299 struct tldap_context **pld)
301 struct netr_DsRGetDCNameInfo *dcinfo;
302 struct sockaddr_storage dcaddr = {
303 .ss_family = AF_UNSPEC,
305 struct sockaddr_storage *pdcaddr = NULL;
306 struct winbindd_domain *creds_domain = NULL;
307 struct cli_credentials *creds;
308 struct loadparm_context *lp_ctx;
309 struct tldap_context *ld;
310 int tcp_port = 389;
311 bool use_tls = false;
312 bool use_starttls = false;
313 int wrap_flags = -1;
314 uint32_t gensec_features = 0;
315 char *sitename = NULL;
316 int fd;
317 NTSTATUS status;
318 bool ok;
319 TLDAPRC rc;
321 wrap_flags = lp_client_ldap_sasl_wrapping();
323 if (wrap_flags & ADS_AUTH_SASL_LDAPS) {
324 use_tls = true;
325 tcp_port = 636;
326 } else if (wrap_flags & ADS_AUTH_SASL_STARTTLS) {
327 use_tls = true;
328 use_starttls = true;
330 if (wrap_flags & ADS_AUTH_SASL_SEAL) {
331 gensec_features |= GENSEC_FEATURE_SEAL;
333 if (wrap_flags & ADS_AUTH_SASL_SIGN) {
334 gensec_features |= GENSEC_FEATURE_SIGN;
337 if (gensec_features != 0) {
338 gensec_features |= GENSEC_FEATURE_LDAP_STYLE;
341 status = wb_dsgetdcname_gencache_get(mem_ctx, domname, &dcinfo);
342 if (!NT_STATUS_IS_OK(status)) {
343 DBG_DEBUG("Could not get dcinfo for %s: %s\n", domname,
344 nt_errstr(status));
345 return status;
348 if (dcinfo->dc_unc == NULL) {
349 TALLOC_FREE(dcinfo);
350 return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
352 if (dcinfo->dc_unc[0] == '\\') {
353 dcinfo->dc_unc += 1;
355 if (dcinfo->dc_unc[0] == '\\') {
356 dcinfo->dc_unc += 1;
359 ok = resolve_name(dcinfo->dc_unc, &dcaddr, 0x20, true);
360 if (!ok) {
361 DBG_DEBUG("Could not resolve name %s\n", dcinfo->dc_unc);
362 TALLOC_FREE(dcinfo);
363 return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
366 sitename = sitename_fetch(talloc_tos(), lp_realm());
369 * create_local_private_krb5_conf_for_domain() can deal with
370 * sitename==NULL
372 if (strequal(domname, lp_realm()) || strequal(domname, lp_workgroup()))
374 pdcaddr = &dcaddr;
377 ok = create_local_private_krb5_conf_for_domain(
378 lp_realm(), lp_workgroup(), sitename, pdcaddr);
379 TALLOC_FREE(sitename);
380 if (!ok) {
381 DBG_DEBUG("Could not create private krb5.conf\n");
382 TALLOC_FREE(dcinfo);
383 return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
386 status = open_socket_out(&dcaddr, tcp_port, 10000, &fd);
387 if (!NT_STATUS_IS_OK(status)) {
388 DBG_DEBUG("open_socket_out failed: %s\n", nt_errstr(status));
389 TALLOC_FREE(dcinfo);
390 return status;
393 ld = tldap_context_create(dcinfo, fd);
394 if (ld == NULL) {
395 DBG_DEBUG("tldap_context_create failed\n");
396 close(fd);
397 TALLOC_FREE(dcinfo);
398 return NT_STATUS_NO_MEMORY;
400 tldap_set_debug(ld, idmap_ad_tldap_debug, NULL);
403 * Here we use or own machine account as
404 * we run as domain member.
406 creds_domain = find_our_domain();
407 if (creds_domain == NULL) {
408 DBG_ERR("find_our_domain() returned NULL\n");
409 TALLOC_FREE(dcinfo);
410 return NT_STATUS_INTERNAL_ERROR;
412 status = winbindd_get_trust_credentials(creds_domain,
413 dcinfo,
414 false, /* netlogon */
415 false, /* ipc_fallback */
416 &creds);
417 if (!NT_STATUS_IS_OK(status)) {
418 DBG_ERR("winbindd_get_trust_credentials(%s) failed - %s\n",
419 creds_domain->name, nt_errstr(status));
420 TALLOC_FREE(dcinfo);
421 return status;
424 lp_ctx = loadparm_init_s3(dcinfo, loadparm_s3_helpers());
425 if (lp_ctx == NULL) {
426 DBG_DEBUG("loadparm_init_s3 failed\n");
427 TALLOC_FREE(dcinfo);
428 return NT_STATUS_NO_MEMORY;
431 if (use_tls && !tldap_has_tls_tstream(ld)) {
432 struct tstream_tls_params *tls_params = NULL;
434 if (use_starttls) {
435 rc = tldap_extended(ld,
436 LDB_EXTENDED_START_TLS_OID,
437 NULL,
438 NULL,
440 NULL,
442 NULL,
443 NULL,
444 NULL);
445 if (!TLDAP_RC_IS_SUCCESS(rc)) {
446 DBG_ERR("tldap_extended(%s) failed: %s\n",
447 LDB_EXTENDED_START_TLS_OID,
448 tldap_errstr(talloc_tos(), ld, rc));
449 return NT_STATUS_LDAP(TLDAP_RC_V(rc));
453 status = tstream_tls_params_client_lpcfg(talloc_tos(),
454 lp_ctx,
455 dcinfo->dc_unc,
456 &tls_params);
457 if (!NT_STATUS_IS_OK(status)) {
458 DBG_ERR("tstream_tls_params_client_lpcfg failed: %s\n",
459 nt_errstr(status));
460 TALLOC_FREE(dcinfo);
461 return status;
464 rc = tldap_tls_connect(ld, tls_params);
465 if (!TLDAP_RC_IS_SUCCESS(rc)) {
466 DBG_ERR("tldap_gensec_bind(%s) failed: %s\n",
467 dcinfo->dc_unc,
468 tldap_errstr(dcinfo, ld, rc));
469 TALLOC_FREE(dcinfo);
470 return NT_STATUS_LDAP(TLDAP_RC_V(rc));
474 rc = tldap_gensec_bind(ld, creds, "ldap", dcinfo->dc_unc, NULL, lp_ctx,
475 gensec_features);
476 if (!TLDAP_RC_IS_SUCCESS(rc)) {
477 DBG_DEBUG("tldap_gensec_bind failed: %s\n",
478 tldap_errstr(dcinfo, ld, rc));
479 TALLOC_FREE(dcinfo);
480 return NT_STATUS_LDAP(TLDAP_RC_V(rc));
483 rc = tldap_fetch_rootdse(ld);
484 if (!TLDAP_RC_IS_SUCCESS(rc)) {
485 DBG_DEBUG("tldap_fetch_rootdse failed: %s\n",
486 tldap_errstr(dcinfo, ld, rc));
487 TALLOC_FREE(dcinfo);
488 return NT_STATUS_LDAP(TLDAP_RC_V(rc));
491 *pld = talloc_move(mem_ctx, &ld);
492 TALLOC_FREE(dcinfo);
493 return NT_STATUS_OK;
496 static int idmap_ad_context_destructor(struct idmap_ad_context *ctx)
498 if ((ctx->dom != NULL) && (ctx->dom->private_data == ctx)) {
499 ctx->dom->private_data = NULL;
501 return 0;
504 static struct ldb_dn **str_list_to_dns(TALLOC_CTX *mem_ctx,
505 const char *dbgmsg,
506 struct ldb_context *ldb,
507 const char **strlist)
509 size_t i, num_dns = str_list_length(strlist);
510 char *dbgstr = NULL;
511 struct ldb_dn **dns = NULL;
513 dns = talloc_array(mem_ctx, struct ldb_dn *, num_dns);
514 if (dns == NULL) {
515 TALLOC_FREE(dbgstr);
516 return NULL;
519 dbgstr = talloc_strdup(talloc_tos(), "");
521 for (i = 0; i < num_dns; i++) {
522 dns[i] = ldb_dn_new(dns, ldb, strlist[i]);
523 if (dns[i] == NULL) {
524 DBG_WARNING("ldb_dn_new(%s) failed\n", strlist[i]);
525 TALLOC_FREE(dns);
526 return NULL;
528 talloc_asprintf_addbuf(
529 &dbgstr,
530 "%s ",
531 ldb_dn_get_extended_linearized(dbgstr, dns[i], 1));
534 DBG_DEBUG("%s %s\n", dbgmsg, dbgstr);
535 TALLOC_FREE(dbgstr);
537 return dns;
540 static NTSTATUS idmap_ad_context_create(TALLOC_CTX *mem_ctx,
541 struct idmap_domain *dom,
542 const char *domname,
543 struct idmap_ad_context **pctx)
545 struct idmap_ad_context *ctx;
546 const char *schema_mode;
547 const char **allow = NULL;
548 const char **deny = NULL;
549 NTSTATUS status;
550 TLDAPRC rc;
552 ctx = talloc_zero(mem_ctx, struct idmap_ad_context);
553 if (ctx == NULL) {
554 return NT_STATUS_NO_MEMORY;
556 ctx->dom = dom;
558 talloc_set_destructor(ctx, idmap_ad_context_destructor);
560 status = idmap_ad_get_tldap_ctx(ctx, domname, &ctx->ld);
561 if (!NT_STATUS_IS_OK(status)) {
562 DBG_DEBUG("idmap_ad_get_tldap_ctx failed: %s\n",
563 nt_errstr(status));
564 TALLOC_FREE(ctx);
565 return status;
568 ctx->default_nc = get_default_nc(ctx, ctx->ld);
569 if (ctx->default_nc == NULL) {
570 DBG_DEBUG("No default nc\n");
571 TALLOC_FREE(ctx);
572 return status;
575 ctx->unix_primary_group = idmap_config_bool(
576 domname, "unix_primary_group", false);
577 ctx->unix_nss_info = idmap_config_bool(
578 domname, "unix_nss_info", false);
580 schema_mode = idmap_config_const_string(
581 domname, "schema_mode", "rfc2307");
583 rc = get_posix_schema_names(ctx->ld, schema_mode, ctx, &ctx->schema);
584 if (!TLDAP_RC_IS_SUCCESS(rc)) {
585 DBG_DEBUG("get_posix_schema_names failed: %s\n",
586 tldap_errstr(ctx, ctx->ld, rc));
587 TALLOC_FREE(ctx);
588 return NT_STATUS_LDAP(TLDAP_RC_V(rc));
591 deny = idmap_config_string_list(domname, "deny ous", NULL);
592 allow = idmap_config_string_list(domname, "allow ous", NULL);
594 if ((deny != NULL) || (allow != NULL)) {
595 int ret = ldb_global_init();
596 if (ret == -1) {
597 status = map_nt_error_from_unix(errno);
598 DBG_WARNING("ldb_global_init() failed: %s\n",
599 strerror(errno));
600 TALLOC_FREE(ctx);
601 return status;
604 ctx->ldb = ldb_init(ctx, global_event_context());
605 if (ctx->ldb == NULL) {
606 status = map_nt_error_from_unix(errno);
607 DBG_WARNING("ldb_init() failed: %s\n", strerror(errno));
608 TALLOC_FREE(ctx);
609 return status;
613 if (deny != NULL) {
614 ctx->deny_ous = str_list_to_dns(ctx, "Denying", ctx->ldb, deny);
615 if (ctx->deny_ous == NULL) {
616 DBG_DEBUG("str_list_to_dns failed\n");
617 TALLOC_FREE(ctx);
618 return NT_STATUS_NO_MEMORY;
622 if (allow != NULL) {
623 ctx->allow_ous =
624 str_list_to_dns(ctx, "Allowing", ctx->ldb, allow);
625 if (ctx->allow_ous == NULL) {
626 DBG_DEBUG("str_list_to_dns failed\n");
627 TALLOC_FREE(ctx);
628 return NT_STATUS_NO_MEMORY;
632 *pctx = ctx;
633 return NT_STATUS_OK;
636 static bool check_dn(struct ldb_dn **dns, struct ldb_dn *dn)
638 size_t i, num_dns = talloc_array_length(dns);
640 for (i = 0; i < num_dns; i++) {
641 struct ldb_dn *base = dns[i];
642 int ret = ldb_dn_compare_base(base, dn);
643 if (ret == 0) {
644 return true;
647 return false;
650 static bool idmap_ad_dn_filter(struct idmap_domain *dom, const char *dnstr)
652 struct idmap_ad_context *ctx = NULL;
653 struct ldb_dn *dn = NULL;
654 NTSTATUS status;
655 bool result = false;
657 status = idmap_ad_get_context(dom, &ctx);
658 if (!NT_STATUS_IS_OK(status)) {
659 DBG_DEBUG("idmap_ad_get_context failed: %s\n",
660 nt_errstr(status));
661 return false;
664 if ((ctx->allow_ous == NULL) && (ctx->deny_ous == NULL)) {
666 * Nothing to check
668 return true;
671 dn = ldb_dn_new(talloc_tos(), ctx->ldb, dnstr);
672 if (dn == NULL) {
673 DBG_DEBUG("ldb_dn_new(%s) failed\n", dnstr);
674 return false;
677 if (ctx->deny_ous != NULL) {
678 bool denied = check_dn(ctx->deny_ous, dn);
679 if (denied) {
680 DBG_WARNING("Denied %s\n", dnstr);
681 TALLOC_FREE(dn);
682 return false;
685 if (ctx->allow_ous == NULL) {
687 * Only a few denied OUs around, allow by
688 * default
690 result = true;
694 if (ctx->allow_ous != NULL) {
695 bool allowed = check_dn(ctx->allow_ous, dn);
696 if (allowed) {
697 return true;
699 DBG_WARNING("Did not allow %s\n", dnstr);
702 return result;
705 static NTSTATUS idmap_ad_query_user(struct idmap_domain *domain,
706 struct wbint_userinfo *info)
708 struct idmap_ad_context *ctx;
709 TLDAPRC rc;
710 NTSTATUS status;
711 char *sidstr, *filter;
712 const char *attrs[4];
713 size_t i, num_msgs;
714 struct tldap_message **msgs;
716 status = idmap_ad_get_context(domain, &ctx);
717 if (!NT_STATUS_IS_OK(status)) {
718 return status;
721 if (!(ctx->unix_primary_group || ctx->unix_nss_info)) {
722 return NT_STATUS_OK;
725 attrs[0] = ctx->schema->gid;
726 attrs[1] = ctx->schema->gecos;
727 attrs[2] = ctx->schema->dir;
728 attrs[3] = ctx->schema->shell;
730 sidstr = ldap_encode_ndr_dom_sid(talloc_tos(), &info->user_sid);
731 if (sidstr == NULL) {
732 return NT_STATUS_NO_MEMORY;
735 filter = talloc_asprintf(talloc_tos(), "(objectsid=%s)", sidstr);
736 TALLOC_FREE(sidstr);
737 if (filter == NULL) {
738 return NT_STATUS_NO_MEMORY;
741 DBG_DEBUG("Filter: [%s]\n", filter);
743 rc = tldap_search(ctx->ld, ctx->default_nc, TLDAP_SCOPE_SUB, filter,
744 attrs, ARRAY_SIZE(attrs), 0, NULL, 0, NULL, 0,
745 0, 0, 0, talloc_tos(), &msgs);
746 if (!TLDAP_RC_IS_SUCCESS(rc)) {
747 return NT_STATUS_LDAP(TLDAP_RC_V(rc));
750 TALLOC_FREE(filter);
752 num_msgs = talloc_array_length(msgs);
754 for (i=0; i<num_msgs; i++) {
755 struct tldap_message *msg = msgs[i];
756 char *dn = NULL;
757 bool ok;
759 if (tldap_msg_type(msg) != TLDAP_RES_SEARCH_ENTRY) {
760 continue;
762 ok = tldap_entry_dn(msg, &dn);
763 if (!ok) {
764 continue;
766 ok = idmap_ad_dn_filter(domain, dn);
767 if (!ok) {
768 DBG_DEBUG("%s filtered out\n", dn);
769 continue;
772 if (ctx->unix_primary_group) {
773 uint32_t gid;
775 ok = tldap_pull_uint32(msg, ctx->schema->gid, &gid);
776 if (ok) {
777 DBG_DEBUG("Setting primary group "
778 "to %"PRIu32" from attr %s\n",
779 gid, ctx->schema->gid);
780 info->primary_gid = gid;
784 if (ctx->unix_nss_info) {
785 char *attr;
787 attr = tldap_talloc_single_attribute(
788 msg, ctx->schema->dir, talloc_tos());
789 if (attr != NULL) {
790 info->homedir = talloc_move(info, &attr);
792 TALLOC_FREE(attr);
794 attr = tldap_talloc_single_attribute(
795 msg, ctx->schema->shell, talloc_tos());
796 if (attr != NULL) {
797 info->shell = talloc_move(info, &attr);
799 TALLOC_FREE(attr);
801 attr = tldap_talloc_single_attribute(
802 msg, ctx->schema->gecos, talloc_tos());
803 if (attr != NULL) {
804 info->full_name = talloc_move(info, &attr);
806 TALLOC_FREE(attr);
810 return NT_STATUS_OK;
813 static NTSTATUS idmap_ad_query_user_retry(struct idmap_domain *domain,
814 struct wbint_userinfo *info)
816 const NTSTATUS status_server_down =
817 NT_STATUS_LDAP(TLDAP_RC_V(TLDAP_SERVER_DOWN));
818 NTSTATUS status;
820 status = idmap_ad_query_user(domain, info);
822 if (NT_STATUS_EQUAL(status, status_server_down)) {
823 TALLOC_FREE(domain->private_data);
824 status = idmap_ad_query_user(domain, info);
827 return status;
830 static NTSTATUS idmap_ad_initialize(struct idmap_domain *dom)
832 dom->query_user = idmap_ad_query_user_retry;
833 dom->private_data = NULL;
834 return NT_STATUS_OK;
837 static NTSTATUS idmap_ad_get_context(struct idmap_domain *dom,
838 struct idmap_ad_context **pctx)
840 struct idmap_ad_context *ctx = NULL;
841 NTSTATUS status;
843 if (IS_AD_DC) {
845 * Make sure we never try to use LDAP against
846 * a trusted domain as AD_DC.
848 * This shouldn't be called currently,
849 * but you never know what happens in future.
851 return NT_STATUS_REQUEST_NOT_ACCEPTED;
854 if (dom->private_data != NULL) {
855 *pctx = talloc_get_type_abort(dom->private_data,
856 struct idmap_ad_context);
857 return NT_STATUS_OK;
860 status = idmap_ad_context_create(dom, dom, dom->name, &ctx);
861 if (!NT_STATUS_IS_OK(status)) {
862 DBG_DEBUG("idmap_ad_context_create failed: %s\n",
863 nt_errstr(status));
864 return status;
867 dom->private_data = ctx;
868 *pctx = ctx;
869 return NT_STATUS_OK;
872 static NTSTATUS idmap_ad_unixids_to_sids(struct idmap_domain *dom,
873 struct id_map **ids)
875 struct idmap_ad_context *ctx;
876 TLDAPRC rc;
877 NTSTATUS status;
878 struct tldap_message **msgs;
880 size_t i, num_msgs;
881 char *u_filter, *g_filter, *filter;
883 const char *attrs[] = {
884 "sAMAccountType",
885 "objectSid",
886 NULL, /* attr_uidnumber */
887 NULL, /* attr_gidnumber */
890 status = idmap_ad_get_context(dom, &ctx);
891 if (!NT_STATUS_IS_OK(status)) {
892 return status;
895 attrs[2] = ctx->schema->uid;
896 attrs[3] = ctx->schema->gid;
898 u_filter = talloc_strdup(talloc_tos(), "");
899 if (u_filter == NULL) {
900 return NT_STATUS_NO_MEMORY;
903 g_filter = talloc_strdup(talloc_tos(), "");
904 if (g_filter == NULL) {
905 return NT_STATUS_NO_MEMORY;
908 for (i=0; ids[i] != NULL; i++) {
909 struct id_map *id = ids[i];
911 id->status = ID_UNKNOWN;
913 switch (id->xid.type) {
914 case ID_TYPE_UID: {
915 u_filter = talloc_asprintf_append_buffer(
916 u_filter, "(%s=%ju)", ctx->schema->uid,
917 (uintmax_t)id->xid.id);
918 if (u_filter == NULL) {
919 return NT_STATUS_NO_MEMORY;
921 break;
924 case ID_TYPE_GID: {
925 g_filter = talloc_asprintf_append_buffer(
926 g_filter, "(%s=%ju)", ctx->schema->gid,
927 (uintmax_t)id->xid.id);
928 if (g_filter == NULL) {
929 return NT_STATUS_NO_MEMORY;
931 break;
934 default:
935 DBG_WARNING("Unknown id type: %u\n",
936 (unsigned)id->xid.type);
937 break;
941 filter = talloc_strdup(talloc_tos(), "(|");
942 if (filter == NULL) {
943 return NT_STATUS_NO_MEMORY;
946 if (*u_filter != '\0') {
947 filter = talloc_asprintf_append_buffer(
948 filter,
949 "(&(|(sAMAccountType=%d)(sAMAccountType=%d)"
950 "(sAMAccountType=%d))(|%s))",
951 ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST,
952 ATYPE_INTERDOMAIN_TRUST, u_filter);
953 if (filter == NULL) {
954 return NT_STATUS_NO_MEMORY;
957 TALLOC_FREE(u_filter);
959 if (*g_filter != '\0') {
960 filter = talloc_asprintf_append_buffer(
961 filter,
962 "(&(|(sAMAccountType=%d)(sAMAccountType=%d))(|%s))",
963 ATYPE_SECURITY_GLOBAL_GROUP,
964 ATYPE_SECURITY_LOCAL_GROUP,
965 g_filter);
966 if (filter == NULL) {
967 return NT_STATUS_NO_MEMORY;
970 TALLOC_FREE(g_filter);
972 filter = talloc_asprintf_append_buffer(filter, ")");
973 if (filter == NULL) {
974 return NT_STATUS_NO_MEMORY;
977 DBG_DEBUG("Filter: [%s]\n", filter);
979 rc = tldap_search(ctx->ld, ctx->default_nc, TLDAP_SCOPE_SUB, filter,
980 attrs, ARRAY_SIZE(attrs), 0, NULL, 0, NULL, 0,
981 0, 0, 0, talloc_tos(), &msgs);
982 if (!TLDAP_RC_IS_SUCCESS(rc)) {
983 return NT_STATUS_LDAP(TLDAP_RC_V(rc));
986 TALLOC_FREE(filter);
988 num_msgs = talloc_array_length(msgs);
990 for (i=0; i<num_msgs; i++) {
991 struct tldap_message *msg = msgs[i];
992 char *dn;
993 struct id_map *map;
994 struct dom_sid sid;
995 size_t j;
996 bool ok;
997 uint32_t atype, xid;
998 enum id_type type;
999 struct dom_sid_buf sidbuf;
1001 if (tldap_msg_type(msg) != TLDAP_RES_SEARCH_ENTRY) {
1002 continue;
1005 ok = tldap_entry_dn(msg, &dn);
1006 if (!ok) {
1007 DBG_DEBUG("No dn found in msg %zu\n", i);
1008 continue;
1011 ok = idmap_ad_dn_filter(dom, dn);
1012 if (!ok) {
1013 DBG_DEBUG("%s filtered out\n", dn);
1014 continue;
1017 ok = tldap_pull_uint32(msg, "sAMAccountType", &atype);
1018 if (!ok) {
1019 DBG_DEBUG("No atype in object %s\n", dn);
1020 continue;
1023 switch (atype & 0xF0000000) {
1024 case ATYPE_SECURITY_GLOBAL_GROUP:
1025 case ATYPE_SECURITY_LOCAL_GROUP:
1026 type = ID_TYPE_GID;
1027 break;
1028 case ATYPE_NORMAL_ACCOUNT:
1029 case ATYPE_WORKSTATION_TRUST:
1030 case ATYPE_INTERDOMAIN_TRUST:
1031 type = ID_TYPE_UID;
1032 break;
1033 default:
1034 DBG_WARNING("unrecognized SAM account type %08x\n",
1035 atype);
1036 continue;
1039 ok = tldap_pull_uint32(msg, (type == ID_TYPE_UID) ?
1040 ctx->schema->uid : ctx->schema->gid,
1041 &xid);
1042 if (!ok) {
1043 DBG_WARNING("No unix id in object %s\n", dn);
1044 continue;
1047 ok = tldap_pull_binsid(msg, "objectSid", &sid);
1048 if (!ok) {
1049 DBG_DEBUG("No objectSid in object %s\n", dn);
1050 continue;
1053 map = NULL;
1054 for (j=0; ids[j]; j++) {
1055 if ((type == ids[j]->xid.type) &&
1056 (xid == ids[j]->xid.id)) {
1057 map = ids[j];
1058 break;
1061 if (map == NULL) {
1062 DBG_DEBUG("Got unexpected sid %s from object %s\n",
1063 dom_sid_str_buf(&sid, &sidbuf),
1064 dn);
1065 continue;
1068 sid_copy(map->sid, &sid);
1069 map->status = ID_MAPPED;
1071 DBG_DEBUG("Mapped %s -> %ju (%d)\n",
1072 dom_sid_str_buf(map->sid, &sidbuf),
1073 (uintmax_t)map->xid.id, map->xid.type);
1076 TALLOC_FREE(msgs);
1078 return NT_STATUS_OK;
1081 static NTSTATUS idmap_ad_sids_to_unixids(struct idmap_domain *dom,
1082 struct id_map **ids)
1084 struct idmap_ad_context *ctx;
1085 TLDAPRC rc;
1086 NTSTATUS status;
1087 struct tldap_message **msgs;
1089 char *filter;
1090 size_t i, num_msgs;
1092 const char *attrs[] = {
1093 "sAMAccountType",
1094 "objectSid",
1095 NULL, /* attr_uidnumber */
1096 NULL, /* attr_gidnumber */
1099 status = idmap_ad_get_context(dom, &ctx);
1100 if (!NT_STATUS_IS_OK(status)) {
1101 return status;
1104 attrs[2] = ctx->schema->uid;
1105 attrs[3] = ctx->schema->gid;
1107 filter = talloc_asprintf(
1108 talloc_tos(),
1109 "(&(|(sAMAccountType=%d)(sAMAccountType=%d)(sAMAccountType=%d)"
1110 "(sAMAccountType=%d)(sAMAccountType=%d))(|",
1111 ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST,
1112 ATYPE_INTERDOMAIN_TRUST, ATYPE_SECURITY_GLOBAL_GROUP,
1113 ATYPE_SECURITY_LOCAL_GROUP);
1114 if (filter == NULL) {
1115 return NT_STATUS_NO_MEMORY;
1118 for (i=0; ids[i]; i++) {
1119 char *sidstr;
1121 ids[i]->status = ID_UNKNOWN;
1123 sidstr = ldap_encode_ndr_dom_sid(talloc_tos(), ids[i]->sid);
1124 if (sidstr == NULL) {
1125 return NT_STATUS_NO_MEMORY;
1128 filter = talloc_asprintf_append_buffer(
1129 filter, "(objectSid=%s)", sidstr);
1130 TALLOC_FREE(sidstr);
1131 if (filter == NULL) {
1132 return NT_STATUS_NO_MEMORY;
1136 filter = talloc_asprintf_append_buffer(filter, "))");
1137 if (filter == NULL) {
1138 return NT_STATUS_NO_MEMORY;
1141 DBG_DEBUG("Filter: [%s]\n", filter);
1143 rc = tldap_search(ctx->ld, ctx->default_nc, TLDAP_SCOPE_SUB, filter,
1144 attrs, ARRAY_SIZE(attrs), 0, NULL, 0, NULL, 0,
1145 0, 0, 0, talloc_tos(), &msgs);
1146 if (!TLDAP_RC_IS_SUCCESS(rc)) {
1147 return NT_STATUS_LDAP(TLDAP_RC_V(rc));
1150 TALLOC_FREE(filter);
1152 num_msgs = talloc_array_length(msgs);
1154 for (i=0; i<num_msgs; i++) {
1155 struct tldap_message *msg = msgs[i];
1156 char *dn;
1157 struct id_map *map;
1158 struct dom_sid sid;
1159 size_t j;
1160 bool ok;
1161 uint64_t account_type, xid;
1162 enum id_type type;
1163 struct dom_sid_buf buf;
1165 if (tldap_msg_type(msg) != TLDAP_RES_SEARCH_ENTRY) {
1166 continue;
1169 ok = tldap_entry_dn(msg, &dn);
1170 if (!ok) {
1171 DBG_DEBUG("No dn found in msg %zu\n", i);
1172 continue;
1175 ok = idmap_ad_dn_filter(dom, dn);
1176 if (!ok) {
1177 DBG_DEBUG("%s filtered out\n", dn);
1178 continue;
1181 ok = tldap_pull_binsid(msg, "objectSid", &sid);
1182 if (!ok) {
1183 DBG_DEBUG("No objectSid in object %s\n", dn);
1184 continue;
1187 map = NULL;
1188 for (j=0; ids[j]; j++) {
1189 if (dom_sid_equal(&sid, ids[j]->sid)) {
1190 map = ids[j];
1191 break;
1194 if (map == NULL) {
1195 DBG_DEBUG("Got unexpected sid %s from object %s\n",
1196 dom_sid_str_buf(&sid, &buf),
1197 dn);
1198 continue;
1201 ok = tldap_pull_uint64(msg, "sAMAccountType", &account_type);
1202 if (!ok) {
1203 DBG_DEBUG("No sAMAccountType in %s\n", dn);
1204 continue;
1207 switch (account_type & 0xF0000000) {
1208 case ATYPE_SECURITY_GLOBAL_GROUP:
1209 case ATYPE_SECURITY_LOCAL_GROUP:
1210 type = ID_TYPE_GID;
1211 break;
1212 case ATYPE_NORMAL_ACCOUNT:
1213 case ATYPE_WORKSTATION_TRUST:
1214 case ATYPE_INTERDOMAIN_TRUST:
1215 type = ID_TYPE_UID;
1216 break;
1217 default:
1218 DBG_WARNING("unrecognized SAM account type %"PRIu64"\n",
1219 account_type);
1220 continue;
1223 ok = tldap_pull_uint64(msg,
1224 type == ID_TYPE_UID ?
1225 ctx->schema->uid : ctx->schema->gid,
1226 &xid);
1227 if (!ok) {
1228 DBG_DEBUG("No xid in %s\n", dn);
1229 continue;
1232 /* mapped */
1233 map->xid.type = type;
1234 map->xid.id = xid;
1235 map->status = ID_MAPPED;
1237 DEBUG(10, ("Mapped %s -> %lu (%d)\n",
1238 dom_sid_str_buf(map->sid, &buf),
1239 (unsigned long)map->xid.id, map->xid.type));
1242 TALLOC_FREE(msgs);
1244 return NT_STATUS_OK;
1247 static NTSTATUS idmap_ad_unixids_to_sids_retry(struct idmap_domain *dom,
1248 struct id_map **ids)
1250 const NTSTATUS status_server_down =
1251 NT_STATUS_LDAP(TLDAP_RC_V(TLDAP_SERVER_DOWN));
1252 NTSTATUS status;
1254 status = idmap_ad_unixids_to_sids(dom, ids);
1256 if (NT_STATUS_EQUAL(status, status_server_down)) {
1257 TALLOC_FREE(dom->private_data);
1258 status = idmap_ad_unixids_to_sids(dom, ids);
1261 return status;
1264 static NTSTATUS idmap_ad_sids_to_unixids_retry(struct idmap_domain *dom,
1265 struct id_map **ids)
1267 const NTSTATUS status_server_down =
1268 NT_STATUS_LDAP(TLDAP_RC_V(TLDAP_SERVER_DOWN));
1269 NTSTATUS status;
1271 status = idmap_ad_sids_to_unixids(dom, ids);
1273 if (NT_STATUS_EQUAL(status, status_server_down)) {
1274 TALLOC_FREE(dom->private_data);
1275 status = idmap_ad_sids_to_unixids(dom, ids);
1278 return status;
1281 static const struct idmap_methods ad_methods = {
1282 .init = idmap_ad_initialize,
1283 .unixids_to_sids = idmap_ad_unixids_to_sids_retry,
1284 .sids_to_unixids = idmap_ad_sids_to_unixids_retry,
1287 static_decl_idmap;
1288 NTSTATUS idmap_ad_init(TALLOC_CTX *ctx)
1290 NTSTATUS status;
1292 status = smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION,
1293 "ad", &ad_methods);
1294 if (!NT_STATUS_IS_OK(status)) {
1295 return status;
1298 status = idmap_ad_nss_init(ctx);
1299 if (!NT_STATUS_IS_OK(status)) {
1300 return status;
1303 return NT_STATUS_OK;