idmap_ad: Fix retrieving credentials from clustered secrets.tdb
[Samba.git] / source3 / winbindd / idmap_ad.c
blobc385cf0e5e7b13100e82977ca9b9ca64cc9a5a82
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 "idmap.h"
23 #include "tldap_gensec_bind.h"
24 #include "tldap_util.h"
25 #include "secrets.h"
26 #include "lib/param/param.h"
27 #include "utils/net.h"
28 #include "auth/gensec/gensec.h"
29 #include "librpc/gen_ndr/ndr_netlogon.h"
30 #include "libads/ldap_schema_oids.h"
31 #include "../libds/common/flags.h"
32 #include "libcli/ldap/ldap_ndr.h"
33 #include "libcli/security/dom_sid.h"
35 struct idmap_ad_schema_names;
37 struct idmap_ad_context {
38 struct idmap_domain *dom;
39 struct tldap_context *ld;
40 struct idmap_ad_schema_names *schema;
41 const char *default_nc;
44 static char *get_schema_path(TALLOC_CTX *mem_ctx, struct tldap_context *ld)
46 struct tldap_message *rootdse;
48 rootdse = tldap_rootdse(ld);
49 if (rootdse == NULL) {
50 return NULL;
53 return tldap_talloc_single_attribute(rootdse, "schemaNamingContext",
54 mem_ctx);
57 static char *get_default_nc(TALLOC_CTX *mem_ctx, struct tldap_context *ld)
59 struct tldap_message *rootdse;
61 rootdse = tldap_rootdse(ld);
62 if (rootdse == NULL) {
63 return NULL;
66 return tldap_talloc_single_attribute(rootdse, "defaultNamingContext",
67 mem_ctx);
70 struct idmap_ad_schema_names {
71 char *name;
72 char *uid;
73 char *gid;
74 char *gecos;
75 char *dir;
76 char *shell;
79 static TLDAPRC get_attrnames_by_oids(struct tldap_context *ld,
80 TALLOC_CTX *mem_ctx,
81 const char *schema_path,
82 size_t num_oids,
83 const char **oids,
84 char **names)
86 char *filter;
87 const char *attrs[] = { "lDAPDisplayName", "attributeId" };
88 size_t i;
89 TLDAPRC rc;
90 struct tldap_message **msgs;
91 size_t num_msgs;
93 filter = talloc_strdup(mem_ctx, "(|");
94 if (filter == NULL) {
95 return TLDAP_NO_MEMORY;
98 for (i=0; i<num_oids; i++) {
99 filter = talloc_asprintf_append_buffer(
100 filter, "(attributeId=%s)", oids[i]);
101 if (filter == NULL) {
102 return TLDAP_NO_MEMORY;
106 filter = talloc_asprintf_append_buffer(filter, ")");
107 if (filter == NULL) {
108 return TLDAP_NO_MEMORY;
111 rc = tldap_search(ld, schema_path, TLDAP_SCOPE_SUB, filter,
112 attrs, ARRAY_SIZE(attrs), 0, NULL, 0, NULL, 0,
113 0, 0, 0, mem_ctx, &msgs);;
114 TALLOC_FREE(filter);
115 if (!TLDAP_RC_IS_SUCCESS(rc)) {
116 return rc;
119 for (i=0; i<num_oids; i++) {
120 names[i] = NULL;
123 num_msgs = talloc_array_length(msgs);
125 for (i=0; i<num_msgs; i++) {
126 struct tldap_message *msg = msgs[i];
127 char *oid;
128 size_t j;
130 if (tldap_msg_type(msg) != TLDAP_RES_SEARCH_ENTRY) {
131 /* Could be a TLDAP_RES_SEARCH_REFERENCE */
132 continue;
135 oid = tldap_talloc_single_attribute(
136 msg, "attributeId", msg);
137 if (oid == NULL) {
138 continue;
141 for (j=0; j<num_oids; j++) {
142 if (strequal(oid, oids[j])) {
143 break;
146 TALLOC_FREE(oid);
148 if (j == num_oids) {
149 /* not found */
150 continue;
153 names[j] = tldap_talloc_single_attribute(
154 msg, "lDAPDisplayName", mem_ctx);
157 TALLOC_FREE(msgs);
159 return TLDAP_SUCCESS;
162 static TLDAPRC get_posix_schema_names(struct tldap_context *ld,
163 const char *schema_mode,
164 TALLOC_CTX *mem_ctx,
165 struct idmap_ad_schema_names **pschema)
167 char *schema_path;
168 struct idmap_ad_schema_names *schema;
169 char *names[6];
170 const char *oids_sfu[] = {
171 ADS_ATTR_SFU_UIDNUMBER_OID,
172 ADS_ATTR_SFU_GIDNUMBER_OID,
173 ADS_ATTR_SFU_HOMEDIR_OID,
174 ADS_ATTR_SFU_SHELL_OID,
175 ADS_ATTR_SFU_GECOS_OID,
176 ADS_ATTR_SFU_UID_OID
178 const char *oids_sfu20[] = {
179 ADS_ATTR_SFU20_UIDNUMBER_OID,
180 ADS_ATTR_SFU20_GIDNUMBER_OID,
181 ADS_ATTR_SFU20_HOMEDIR_OID,
182 ADS_ATTR_SFU20_SHELL_OID,
183 ADS_ATTR_SFU20_GECOS_OID,
184 ADS_ATTR_SFU20_UID_OID
186 const char *oids_rfc2307[] = {
187 ADS_ATTR_RFC2307_UIDNUMBER_OID,
188 ADS_ATTR_RFC2307_GIDNUMBER_OID,
189 ADS_ATTR_RFC2307_HOMEDIR_OID,
190 ADS_ATTR_RFC2307_SHELL_OID,
191 ADS_ATTR_RFC2307_GECOS_OID,
192 ADS_ATTR_RFC2307_UID_OID
194 const char **oids;
196 TLDAPRC rc;
198 schema = talloc(mem_ctx, struct idmap_ad_schema_names);
199 if (schema == NULL) {
200 return TLDAP_NO_MEMORY;
203 schema_path = get_schema_path(schema, ld);
204 if (schema_path == NULL) {
205 TALLOC_FREE(schema);
206 return TLDAP_NO_MEMORY;
209 oids = oids_rfc2307;
211 if ((schema_mode != NULL) && (schema_mode[0] != '\0')) {
212 if (strequal(schema_mode, "sfu")) {
213 oids = oids_sfu;
214 } else if (strequal(schema_mode, "sfu20")) {
215 oids = oids_sfu20;
216 } else if (strequal(schema_mode, "rfc2307" )) {
217 oids = oids_rfc2307;
218 } else {
219 DBG_WARNING("Unknown schema mode %s\n", schema_mode);
223 rc = get_attrnames_by_oids(ld, schema, schema_path, 6, oids, names);
224 TALLOC_FREE(schema_path);
225 if (!TLDAP_RC_IS_SUCCESS(rc)) {
226 TALLOC_FREE(schema);
227 return rc;
230 schema->uid = names[0];
231 schema->gid = names[1];
232 schema->dir = names[2];
233 schema->shell = names[3];
234 schema->gecos = names[4];
235 schema->name = names[5];
237 *pschema = schema;
239 return TLDAP_SUCCESS;
242 static NTSTATUS idmap_ad_get_tldap_ctx(TALLOC_CTX *mem_ctx,
243 const char *domname,
244 struct tldap_context **pld)
246 struct db_context *db_ctx;
247 struct netr_DsRGetDCNameInfo *dcinfo;
248 struct sockaddr_storage dcaddr;
249 struct cli_credentials *creds;
250 struct loadparm_context *lp_ctx;
251 struct tldap_context *ld;
252 int fd;
253 NTSTATUS status;
254 bool ok;
255 TLDAPRC rc;
257 status = wb_dsgetdcname_gencache_get(mem_ctx, domname, &dcinfo);
258 if (!NT_STATUS_IS_OK(status)) {
259 DBG_DEBUG("Could not get dcinfo for %s: %s\n", domname,
260 nt_errstr(status));
261 return status;
264 if (dcinfo->dc_unc == NULL) {
265 TALLOC_FREE(dcinfo);
266 return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
268 if (dcinfo->dc_unc[0] == '\\') {
269 dcinfo->dc_unc += 1;
271 if (dcinfo->dc_unc[0] == '\\') {
272 dcinfo->dc_unc += 1;
275 ok = resolve_name(dcinfo->dc_unc, &dcaddr, 0x20, true);
276 if (!ok) {
277 DBG_DEBUG("Could not resolve name %s\n", dcinfo->dc_unc);
278 TALLOC_FREE(dcinfo);
279 return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
282 status = open_socket_out(&dcaddr, 389, 10000, &fd);
283 if (!NT_STATUS_IS_OK(status)) {
284 DBG_DEBUG("open_socket_out failed: %s\n", nt_errstr(status));
285 TALLOC_FREE(dcinfo);
286 return status;
289 ld = tldap_context_create(dcinfo, fd);
290 if (ld == NULL) {
291 DBG_DEBUG("tldap_context_create failed\n");
292 close(fd);
293 TALLOC_FREE(dcinfo);
294 return NT_STATUS_NO_MEMORY;
297 creds = cli_credentials_init(dcinfo);
298 if (creds == NULL) {
299 DBG_DEBUG("cli_credentials_init failed\n");
300 TALLOC_FREE(dcinfo);
301 return NT_STATUS_NO_MEMORY;
304 lp_ctx = loadparm_init_s3(dcinfo, loadparm_s3_helpers());
305 if (lp_ctx == NULL) {
306 DBG_DEBUG("loadparm_init_s3 failed\n");
307 TALLOC_FREE(dcinfo);
308 return NT_STATUS_NO_MEMORY;
311 cli_credentials_set_conf(creds, lp_ctx);
313 db_ctx = secrets_db_ctx();
314 if (db_ctx == NULL) {
315 DBG_DEBUG("Failed to open secrets.tdb.\n");
316 return NT_STATUS_INTERNAL_ERROR;
319 status = cli_credentials_set_machine_account_db_ctx(creds, lp_ctx,
320 db_ctx);
321 if (!NT_STATUS_IS_OK(status)) {
322 DBG_DEBUG("cli_credentials_set_machine_account "
323 "failed: %s\n", nt_errstr(status));
324 TALLOC_FREE(dcinfo);
325 return status;
328 rc = tldap_gensec_bind(ld, creds, "ldap", dcinfo->dc_unc, NULL, lp_ctx,
329 GENSEC_FEATURE_SIGN | GENSEC_FEATURE_SEAL);
330 if (!TLDAP_RC_IS_SUCCESS(rc)) {
331 DBG_DEBUG("tldap_gensec_bind failed: %s\n",
332 tldap_errstr(dcinfo, ld, rc));
333 TALLOC_FREE(dcinfo);
334 return NT_STATUS_LDAP(TLDAP_RC_V(rc));
337 rc = tldap_fetch_rootdse(ld);
338 if (!TLDAP_RC_IS_SUCCESS(rc)) {
339 DBG_DEBUG("tldap_fetch_rootdse failed: %s\n",
340 tldap_errstr(dcinfo, ld, rc));
341 TALLOC_FREE(dcinfo);
342 return NT_STATUS_LDAP(TLDAP_RC_V(rc));
345 *pld = talloc_move(mem_ctx, &ld);
346 TALLOC_FREE(dcinfo);
347 return NT_STATUS_OK;
350 static int idmap_ad_context_destructor(struct idmap_ad_context *ctx)
352 if ((ctx->dom != NULL) && (ctx->dom->private_data == ctx)) {
353 ctx->dom->private_data = NULL;
355 return 0;
358 static NTSTATUS idmap_ad_context_create(TALLOC_CTX *mem_ctx,
359 struct idmap_domain *dom,
360 const char *domname,
361 struct idmap_ad_context **pctx)
363 struct idmap_ad_context *ctx;
364 char *schema_config_option;
365 const char *schema_mode;
366 NTSTATUS status;
367 TLDAPRC rc;
369 ctx = talloc(mem_ctx, struct idmap_ad_context);
370 if (ctx == NULL) {
371 return NT_STATUS_NO_MEMORY;
373 ctx->dom = dom;
375 talloc_set_destructor(ctx, idmap_ad_context_destructor);
377 status = idmap_ad_get_tldap_ctx(ctx, domname, &ctx->ld);
378 if (!NT_STATUS_IS_OK(status)) {
379 DBG_DEBUG("idmap_ad_get_tldap_ctx failed: %s\n",
380 nt_errstr(status));
381 TALLOC_FREE(ctx);
382 return status;
385 ctx->default_nc = get_default_nc(ctx, ctx->ld);
386 if (ctx->default_nc == NULL) {
387 DBG_DEBUG("No default nc\n");
388 TALLOC_FREE(ctx);
389 return status;
392 schema_config_option = talloc_asprintf(
393 ctx, "idmap config %s", domname);
394 if (schema_config_option == NULL) {
395 TALLOC_FREE(ctx);
396 return NT_STATUS_NO_MEMORY;
399 schema_mode = lp_parm_const_string(
400 -1, schema_config_option, "schema_mode", "rfc2307");
401 TALLOC_FREE(schema_config_option);
403 rc = get_posix_schema_names(ctx->ld, schema_mode, ctx, &ctx->schema);
404 if (!TLDAP_RC_IS_SUCCESS(rc)) {
405 DBG_DEBUG("get_posix_schema_names failed: %s\n",
406 tldap_errstr(ctx, ctx->ld, rc));
407 TALLOC_FREE(ctx);
408 return NT_STATUS_LDAP(TLDAP_RC_V(rc));
411 *pctx = ctx;
412 return NT_STATUS_OK;
415 static NTSTATUS idmap_ad_initialize(struct idmap_domain *dom)
417 dom->private_data = NULL;
418 return NT_STATUS_OK;
421 static NTSTATUS idmap_ad_get_context(struct idmap_domain *dom,
422 struct idmap_ad_context **pctx)
424 struct idmap_ad_context *ctx = NULL;
425 NTSTATUS status;
427 if (dom->private_data != NULL) {
428 *pctx = talloc_get_type_abort(dom->private_data,
429 struct idmap_ad_context);
430 return NT_STATUS_OK;
433 status = idmap_ad_context_create(dom, dom, dom->name, &ctx);
434 if (!NT_STATUS_IS_OK(status)) {
435 DBG_DEBUG("idmap_ad_context_create failed: %s\n",
436 nt_errstr(status));
437 return status;
440 dom->private_data = ctx;
441 *pctx = ctx;
442 return NT_STATUS_OK;
445 static NTSTATUS idmap_ad_unixids_to_sids(struct idmap_domain *dom,
446 struct id_map **ids)
448 struct idmap_ad_context *ctx;
449 TLDAPRC rc;
450 NTSTATUS status;
451 struct tldap_message **msgs;
453 size_t i, num_msgs;
454 char *u_filter, *g_filter, *filter;
456 const char *attrs[] = {
457 "sAMAccountType",
458 "objectSid",
459 NULL, /* attr_uidnumber */
460 NULL, /* attr_gidnumber */
463 status = idmap_ad_get_context(dom, &ctx);
464 if (!NT_STATUS_IS_OK(status)) {
465 return status;
468 attrs[2] = ctx->schema->uid;
469 attrs[3] = ctx->schema->gid;
471 u_filter = talloc_strdup(talloc_tos(), "");
472 if (u_filter == NULL) {
473 return NT_STATUS_NO_MEMORY;
476 g_filter = talloc_strdup(talloc_tos(), "");
477 if (g_filter == NULL) {
478 return NT_STATUS_NO_MEMORY;
481 for (i=0; ids[i] != NULL; i++) {
482 struct id_map *id = ids[i];
484 id->status = ID_UNKNOWN;
486 switch (id->xid.type) {
487 case ID_TYPE_UID: {
488 u_filter = talloc_asprintf_append_buffer(
489 u_filter, "(%s=%ju)", ctx->schema->uid,
490 (uintmax_t)id->xid.id);
491 if (u_filter == NULL) {
492 return NT_STATUS_NO_MEMORY;
494 break;
497 case ID_TYPE_GID: {
498 g_filter = talloc_asprintf_append_buffer(
499 g_filter, "(%s=%ju)", ctx->schema->gid,
500 (uintmax_t)id->xid.id);
501 if (g_filter == NULL) {
502 return NT_STATUS_NO_MEMORY;
504 break;
507 default:
508 DBG_WARNING("Unknown id type: %u\n",
509 (unsigned)id->xid.type);
510 break;
514 filter = talloc_strdup(talloc_tos(), "(|");
515 if (filter == NULL) {
516 return NT_STATUS_NO_MEMORY;
519 if (*u_filter != '\0') {
520 filter = talloc_asprintf_append_buffer(
521 filter,
522 "(&(|(sAMAccountType=%d)(sAMAccountType=%d)"
523 "(sAMAccountType=%d))(|%s))",
524 ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST,
525 ATYPE_INTERDOMAIN_TRUST, u_filter);
526 if (filter == NULL) {
527 return NT_STATUS_NO_MEMORY;
530 TALLOC_FREE(u_filter);
532 if (*g_filter != '\0') {
533 filter = talloc_asprintf_append_buffer(
534 filter,
535 "(&(|(sAMAccountType=%d)(sAMAccountType=%d))(|%s))",
536 ATYPE_SECURITY_GLOBAL_GROUP,
537 ATYPE_SECURITY_LOCAL_GROUP,
538 g_filter);
539 if (filter == NULL) {
540 return NT_STATUS_NO_MEMORY;
543 TALLOC_FREE(g_filter);
545 filter = talloc_asprintf_append_buffer(filter, ")");
546 if (filter == NULL) {
547 return NT_STATUS_NO_MEMORY;
550 DBG_DEBUG("Filter: [%s]\n", filter);
552 rc = tldap_search(ctx->ld, ctx->default_nc, TLDAP_SCOPE_SUB, filter,
553 attrs, ARRAY_SIZE(attrs), 0, NULL, 0, NULL, 0,
554 0, 0, 0, talloc_tos(), &msgs);
555 if (!TLDAP_RC_IS_SUCCESS(rc)) {
556 return NT_STATUS_LDAP(TLDAP_RC_V(rc));
559 TALLOC_FREE(filter);
561 num_msgs = talloc_array_length(msgs);
563 for (i=0; i<num_msgs; i++) {
564 struct tldap_message *msg = msgs[i];
565 char *dn;
566 struct id_map *map;
567 struct dom_sid sid;
568 size_t j;
569 bool ok;
570 uint32_t atype, xid;
571 enum id_type type;
573 if (tldap_msg_type(msg) != TLDAP_RES_SEARCH_ENTRY) {
574 continue;
577 ok = tldap_entry_dn(msg, &dn);
578 if (!ok) {
579 DBG_DEBUG("No dn found in msg %zu\n", i);
580 continue;
583 ok = tldap_pull_uint32(msg, "sAMAccountType", &atype);
584 if (!ok) {
585 DBG_DEBUG("No atype in object %s\n", dn);
586 continue;
589 switch (atype & 0xF0000000) {
590 case ATYPE_SECURITY_GLOBAL_GROUP:
591 case ATYPE_SECURITY_LOCAL_GROUP:
592 type = ID_TYPE_GID;
593 break;
594 case ATYPE_NORMAL_ACCOUNT:
595 case ATYPE_WORKSTATION_TRUST:
596 case ATYPE_INTERDOMAIN_TRUST:
597 type = ID_TYPE_UID;
598 break;
599 default:
600 DBG_WARNING("unrecognized SAM account type %08x\n",
601 atype);
602 continue;
605 ok = tldap_pull_uint32(msg, (type == ID_TYPE_UID) ?
606 ctx->schema->uid : ctx->schema->gid,
607 &xid);
608 if (!ok) {
609 DBG_WARNING("No unix id in object %s\n", dn);
610 continue;
613 ok = tldap_pull_binsid(msg, "objectSid", &sid);
614 if (!ok) {
615 DBG_DEBUG("No objectSid in object %s\n", dn);
616 continue;
619 map = NULL;
620 for (j=0; ids[j]; j++) {
621 if ((type == ids[j]->xid.type) &&
622 (xid == ids[j]->xid.id)) {
623 map = ids[j];
624 break;
627 if (map == NULL) {
628 DBG_DEBUG("Got unexpected sid %s from object %s\n",
629 sid_string_tos(&sid), dn);
630 continue;
633 sid_copy(map->sid, &sid);
634 map->status = ID_MAPPED;
636 DBG_DEBUG("Mapped %s -> %ju (%d)\n", sid_string_dbg(map->sid),
637 (uintmax_t)map->xid.id, map->xid.type);
640 TALLOC_FREE(msgs);
642 return NT_STATUS_OK;
645 static NTSTATUS idmap_ad_sids_to_unixids(struct idmap_domain *dom,
646 struct id_map **ids)
648 struct idmap_ad_context *ctx;
649 TLDAPRC rc;
650 NTSTATUS status;
651 struct tldap_message **msgs;
653 char *filter;
654 size_t i, num_msgs;
656 const char *attrs[] = {
657 "sAMAccountType",
658 "objectSid",
659 NULL, /* attr_uidnumber */
660 NULL, /* attr_gidnumber */
663 status = idmap_ad_get_context(dom, &ctx);
664 if (!NT_STATUS_IS_OK(status)) {
665 return status;
668 attrs[2] = ctx->schema->uid;
669 attrs[3] = ctx->schema->gid;
671 filter = talloc_asprintf(
672 talloc_tos(),
673 "(&(|(sAMAccountType=%d)(sAMAccountType=%d)(sAMAccountType=%d)"
674 "(sAMAccountType=%d)(sAMAccountType=%d))(|",
675 ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST,
676 ATYPE_INTERDOMAIN_TRUST, ATYPE_SECURITY_GLOBAL_GROUP,
677 ATYPE_SECURITY_LOCAL_GROUP);
678 if (filter == NULL) {
679 return NT_STATUS_NO_MEMORY;
682 for (i=0; ids[i]; i++) {
683 char *sidstr;
685 ids[i]->status = ID_UNKNOWN;
687 sidstr = ldap_encode_ndr_dom_sid(talloc_tos(), ids[i]->sid);
688 if (sidstr == NULL) {
689 return NT_STATUS_NO_MEMORY;
692 filter = talloc_asprintf_append_buffer(
693 filter, "(objectSid=%s)", sidstr);
694 TALLOC_FREE(sidstr);
695 if (filter == NULL) {
696 return NT_STATUS_NO_MEMORY;
700 filter = talloc_asprintf_append_buffer(filter, "))");
701 if (filter == NULL) {
702 return NT_STATUS_NO_MEMORY;
705 DBG_DEBUG("Filter: [%s]\n", filter);
707 rc = tldap_search(ctx->ld, ctx->default_nc, TLDAP_SCOPE_SUB, filter,
708 attrs, ARRAY_SIZE(attrs), 0, NULL, 0, NULL, 0,
709 0, 0, 0, talloc_tos(), &msgs);
710 if (!TLDAP_RC_IS_SUCCESS(rc)) {
711 return NT_STATUS_LDAP(TLDAP_RC_V(rc));
714 TALLOC_FREE(filter);
716 num_msgs = talloc_array_length(msgs);
718 for (i=0; i<num_msgs; i++) {
719 struct tldap_message *msg = msgs[i];
720 char *dn;
721 struct id_map *map;
722 struct dom_sid sid;
723 size_t j;
724 bool ok;
725 uint64_t account_type, xid;
726 enum id_type type;
728 if (tldap_msg_type(msg) != TLDAP_RES_SEARCH_ENTRY) {
729 continue;
732 ok = tldap_entry_dn(msg, &dn);
733 if (!ok) {
734 DBG_DEBUG("No dn found in msg %zu\n", i);
735 continue;
738 ok = tldap_pull_binsid(msg, "objectSid", &sid);
739 if (!ok) {
740 DBG_DEBUG("No objectSid in object %s\n", dn);
741 continue;
744 map = NULL;
745 for (j=0; ids[j]; j++) {
746 if (dom_sid_equal(&sid, ids[j]->sid)) {
747 map = ids[j];
748 break;
751 if (map == NULL) {
752 DBG_DEBUG("Got unexpected sid %s from object %s\n",
753 sid_string_tos(&sid), dn);
754 continue;
757 ok = tldap_pull_uint64(msg, "sAMAccountType", &account_type);
758 if (!ok) {
759 DBG_DEBUG("No sAMAccountType in %s\n", dn);
760 continue;
763 switch (account_type & 0xF0000000) {
764 case ATYPE_SECURITY_GLOBAL_GROUP:
765 case ATYPE_SECURITY_LOCAL_GROUP:
766 type = ID_TYPE_GID;
767 break;
768 case ATYPE_NORMAL_ACCOUNT:
769 case ATYPE_WORKSTATION_TRUST:
770 case ATYPE_INTERDOMAIN_TRUST:
771 type = ID_TYPE_UID;
772 break;
773 default:
774 DBG_WARNING("unrecognized SAM account type %"PRIu64"\n",
775 account_type);
776 continue;
779 ok = tldap_pull_uint64(msg,
780 type == ID_TYPE_UID ?
781 ctx->schema->uid : ctx->schema->gid,
782 &xid);
783 if (!ok) {
784 DBG_DEBUG("No xid in %s\n", dn);
785 continue;
788 /* mapped */
789 map->xid.type = type;
790 map->xid.id = xid;
791 map->status = ID_MAPPED;
793 DEBUG(10, ("Mapped %s -> %lu (%d)\n", sid_string_dbg(map->sid),
794 (unsigned long)map->xid.id, map->xid.type));
797 TALLOC_FREE(msgs);
799 return NT_STATUS_OK;
802 static NTSTATUS idmap_ad_unixids_to_sids_retry(struct idmap_domain *dom,
803 struct id_map **ids)
805 const NTSTATUS status_server_down =
806 NT_STATUS_LDAP(TLDAP_RC_V(TLDAP_SERVER_DOWN));
807 NTSTATUS status;
809 status = idmap_ad_unixids_to_sids(dom, ids);
811 if (NT_STATUS_EQUAL(status, status_server_down)) {
812 TALLOC_FREE(dom->private_data);
813 status = idmap_ad_unixids_to_sids(dom, ids);
816 return status;
819 static NTSTATUS idmap_ad_sids_to_unixids_retry(struct idmap_domain *dom,
820 struct id_map **ids)
822 const NTSTATUS status_server_down =
823 NT_STATUS_LDAP(TLDAP_RC_V(TLDAP_SERVER_DOWN));
824 NTSTATUS status;
826 status = idmap_ad_sids_to_unixids(dom, ids);
828 if (NT_STATUS_EQUAL(status, status_server_down)) {
829 TALLOC_FREE(dom->private_data);
830 status = idmap_ad_sids_to_unixids(dom, ids);
833 return status;
836 static struct idmap_methods ad_methods = {
837 .init = idmap_ad_initialize,
838 .unixids_to_sids = idmap_ad_unixids_to_sids_retry,
839 .sids_to_unixids = idmap_ad_sids_to_unixids_retry,
842 static_decl_idmap;
843 NTSTATUS idmap_ad_init(void)
845 NTSTATUS status;
847 status = smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION,
848 "ad", &ad_methods);
849 if (!NT_STATUS_IS_OK(status)) {
850 return status;
853 status = idmap_ad_nss_init();
854 if (!NT_STATUS_IS_OK(status)) {
855 return status;
858 return NT_STATUS_OK;