2 * Unix SMB/CIFS implementation.
4 * Id mapping using LDAP records as defined in RFC 2307
6 * The SID<->uid/gid mapping is performed in two steps: 1) Query the
7 * AD server for the name<->sid mapping. 2) Query an LDAP server
8 * according to RFC 2307 for the name<->uid/gid mapping.
10 * Copyright (C) Christof Schmitt 2012,2013
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 3 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <http://www.gnu.org/licenses/>.
28 #include "winbindd_ads.h"
31 #include "nsswitch/winbind_client.h"
32 #include "lib/winbind_util.h"
33 #include "libcli/security/dom_sid.h"
34 #include "lib/global_contexts.h"
37 * Config and connection info per domain.
39 struct idmap_rfc2307_context
{
40 const char *bind_path_user
;
41 const char *bind_path_group
;
42 const char *ldap_domain
;
47 * Pointer to ldap struct in ads or smbldap_state, has to be
48 * updated after connecting to server
52 /* Optional function to check connection to server */
53 NTSTATUS (*check_connection
)(struct idmap_domain
*dom
);
55 /* Issue ldap query */
56 NTSTATUS (*search
)(struct idmap_rfc2307_context
*ctx
,
57 const char *bind_path
, const char *expr
,
58 const char **attrs
, LDAPMessage
**res
);
60 /* Access to LDAP in AD server */
63 /* Access to stand-alone LDAP server */
64 struct smbldap_state
*smbldap_state
;
68 * backend functions for LDAP queries through ADS
71 static NTSTATUS
idmap_rfc2307_ads_check_connection(struct idmap_domain
*dom
)
73 struct idmap_rfc2307_context
*ctx
;
74 const char *dom_name
= dom
->name
;
77 DEBUG(10, ("ad_idmap_cached_connection: called for domain '%s'\n",
80 ctx
= talloc_get_type(dom
->private_data
, struct idmap_rfc2307_context
);
81 dom_name
= ctx
->ldap_domain
? ctx
->ldap_domain
: dom
->name
;
83 status
= ads_idmap_cached_connection(dom_name
, ctx
, &ctx
->ads
);
84 if (ADS_ERR_OK(status
)) {
85 ctx
->ldap
= ctx
->ads
->ldap
.ld
;
87 DEBUG(1, ("Could not connect to domain %s: %s\n", dom
->name
,
91 return ads_ntstatus(status
);
94 static NTSTATUS
idmap_rfc2307_ads_search(struct idmap_rfc2307_context
*ctx
,
95 const char *bind_path
,
102 status
= ads_do_search_retry(ctx
->ads
, bind_path
,
103 LDAP_SCOPE_SUBTREE
, expr
, attrs
, result
);
105 if (!ADS_ERR_OK(status
)) {
106 return ads_ntstatus(status
);
109 ctx
->ldap
= ctx
->ads
->ldap
.ld
;
110 return ads_ntstatus(status
);
113 static NTSTATUS
idmap_rfc2307_init_ads(struct idmap_rfc2307_context
*ctx
,
114 const char *domain_name
)
116 const char *ldap_domain
;
118 ctx
->search
= idmap_rfc2307_ads_search
;
119 ctx
->check_connection
= idmap_rfc2307_ads_check_connection
;
121 ldap_domain
= idmap_config_const_string(domain_name
, "ldap_domain",
124 ctx
->ldap_domain
= talloc_strdup(ctx
, ldap_domain
);
125 if (ctx
->ldap_domain
== NULL
) {
126 return NT_STATUS_NO_MEMORY
;
134 * backend function for LDAP queries through stand-alone LDAP server
137 static NTSTATUS
idmap_rfc2307_ldap_search(struct idmap_rfc2307_context
*ctx
,
138 const char *bind_path
,
141 LDAPMessage
**result
)
145 ret
= smbldap_search(ctx
->smbldap_state
, bind_path
, LDAP_SCOPE_SUBTREE
,
146 expr
, attrs
, 0, result
);
147 ctx
->ldap
= smbldap_get_ldap(ctx
->smbldap_state
);
149 if (ret
== LDAP_SUCCESS
) {
153 return NT_STATUS_LDAP(ret
);
156 static bool idmap_rfc2307_get_uint32(LDAP
*ldap
, LDAPMessage
*entry
,
157 const char *field
, uint32_t *value
)
162 b
= smbldap_get_single_attribute(ldap
, entry
, field
, str
, sizeof(str
));
171 static NTSTATUS
idmap_rfc2307_init_ldap(struct idmap_rfc2307_context
*ctx
,
172 const char *domain_name
)
177 const char *ldap_url
, *user_dn
;
178 TALLOC_CTX
*mem_ctx
= ctx
;
180 ldap_url
= idmap_config_const_string(domain_name
, "ldap_url", NULL
);
182 DEBUG(1, ("ERROR: missing idmap ldap url\n"));
183 return NT_STATUS_UNSUCCESSFUL
;
186 url
= talloc_strdup(talloc_tos(), ldap_url
);
188 user_dn
= idmap_config_const_string(domain_name
, "ldap_user_dn", NULL
);
190 secret
= idmap_fetch_secret("ldap", domain_name
, user_dn
);
192 ret
= NT_STATUS_ACCESS_DENIED
;
197 /* assume anonymous if we don't have a specified user */
198 ret
= smbldap_init(mem_ctx
, global_event_context(), url
,
199 (user_dn
== NULL
), user_dn
, secret
,
200 &ctx
->smbldap_state
);
201 BURN_FREE_STR(secret
);
202 if (!NT_STATUS_IS_OK(ret
)) {
203 DEBUG(1, ("ERROR: smbldap_init (%s) failed!\n", url
));
207 ctx
->search
= idmap_rfc2307_ldap_search
;
215 * common code for stand-alone LDAP and ADS
218 static void idmap_rfc2307_map_sid_results(struct idmap_rfc2307_context
*ctx
,
222 const char *dom_name
,
223 const char **attrs
, int type
)
228 count
= ldap_count_entries(ctx
->ldap
, result
);
230 for (i
= 0; i
< count
; i
++) {
233 enum lsa_SidType lsa_type
;
239 entry
= ldap_first_entry(ctx
->ldap
, result
);
241 entry
= ldap_next_entry(ctx
->ldap
, entry
);
244 DEBUG(2, ("Unable to fetch entry.\n"));
248 name
= smbldap_talloc_single_attribute(ctx
->ldap
, entry
,
251 DEBUG(1, ("Could not get user name\n"));
255 b
= idmap_rfc2307_get_uint32(ctx
->ldap
, entry
, attrs
[1], &id
);
257 DEBUG(1, ("Could not pull id for record %s\n", name
));
261 map
= idmap_find_map_by_id(ids
, type
, id
);
263 DEBUG(1, ("Could not find id %d, name %s\n", id
, name
));
267 if (ctx
->realm
!= NULL
) {
268 /* Strip @realm from user or group name */
271 delim
= strchr(name
, '@');
277 /* by default calls to winbindd are disabled
278 the following call will not recurse so this is safe */
280 /* Lookup name from PDC using lsa_lookup_names() */
281 b
= winbind_lookup_name(dom_name
, name
, &sid
, &lsa_type
);
285 DEBUG(1, ("SID lookup failed for id %d, %s\n",
290 if (type
== ID_TYPE_UID
&& lsa_type
!= SID_NAME_USER
) {
291 DEBUG(1, ("Wrong type %d for user name %s\n",
296 if (type
== ID_TYPE_GID
&& lsa_type
!= SID_NAME_DOM_GRP
&&
297 lsa_type
!= SID_NAME_ALIAS
&&
298 lsa_type
!= SID_NAME_WKN_GRP
) {
299 DEBUG(1, ("Wrong type %d for group name %s\n",
304 map
->status
= ID_MAPPED
;
305 sid_copy(map
->sid
, &sid
);
310 * Map unixids to names and then to sids.
312 static NTSTATUS
idmap_rfc2307_unixids_to_sids(struct idmap_domain
*dom
,
315 struct idmap_rfc2307_context
*ctx
;
316 char *fltr_usr
= NULL
, *fltr_grp
= NULL
;
318 int cnt_usr
= 0, cnt_grp
= 0, idx
= 0, bidx
= 0;
319 LDAPMessage
*result
= NULL
;
322 ctx
= talloc_get_type(dom
->private_data
, struct idmap_rfc2307_context
);
323 mem_ctx
= talloc_new(ctx
);
325 return NT_STATUS_NO_MEMORY
;
328 if (ctx
->check_connection
) {
329 ret
= ctx
->check_connection(dom
);
330 if (!NT_STATUS_IS_OK(ret
)) {
339 /* prepare new user query, see getpwuid() in RFC2307 */
340 fltr_usr
= talloc_asprintf(mem_ctx
,
341 "(&(objectClass=posixAccount)(|");
345 /* prepare new group query, see getgrgid() in RFC2307 */
346 fltr_grp
= talloc_asprintf(mem_ctx
,
347 "(&(objectClass=posixGroup)(|");
350 if (!fltr_usr
|| !fltr_grp
) {
351 ret
= NT_STATUS_NO_MEMORY
;
355 while (cnt_usr
< IDMAP_LDAP_MAX_IDS
&&
356 cnt_grp
< IDMAP_LDAP_MAX_IDS
&& ids
[idx
]) {
358 switch (ids
[idx
]->xid
.type
) {
360 fltr_usr
= talloc_asprintf_append_buffer(fltr_usr
,
361 "(uidNumber=%d)", ids
[idx
]->xid
.id
);
365 fltr_grp
= talloc_asprintf_append_buffer(fltr_grp
,
366 "(gidNumber=%d)", ids
[idx
]->xid
.id
);
370 DEBUG(3, ("Error: unknown ID type %d\n",
371 ids
[idx
]->xid
.type
));
372 ret
= NT_STATUS_UNSUCCESSFUL
;
376 if (!fltr_usr
|| !fltr_grp
) {
377 ret
= NT_STATUS_NO_MEMORY
;
384 if (cnt_usr
== IDMAP_LDAP_MAX_IDS
|| (cnt_usr
!= 0 && !ids
[idx
])) {
385 const char *attrs
[] = { NULL
, /* uid or cn */
389 fltr_usr
= talloc_strdup_append(fltr_usr
, "))");
391 ret
= NT_STATUS_NO_MEMORY
;
395 attrs
[0] = ctx
->user_cn
? "cn" : "uid";
396 ret
= ctx
->search(ctx
, ctx
->bind_path_user
, fltr_usr
, attrs
,
398 if (!NT_STATUS_IS_OK(ret
)) {
402 idmap_rfc2307_map_sid_results(ctx
, mem_ctx
, &ids
[bidx
], result
,
403 dom
->name
, attrs
, ID_TYPE_UID
);
405 TALLOC_FREE(fltr_usr
);
408 if (cnt_grp
== IDMAP_LDAP_MAX_IDS
|| (cnt_grp
!= 0 && !ids
[idx
])) {
409 const char *attrs
[] = { "cn", "gidNumber", NULL
};
411 fltr_grp
= talloc_strdup_append(fltr_grp
, "))");
413 ret
= NT_STATUS_NO_MEMORY
;
416 ret
= ctx
->search(ctx
, ctx
->bind_path_group
, fltr_grp
, attrs
,
418 if (!NT_STATUS_IS_OK(ret
)) {
422 idmap_rfc2307_map_sid_results(ctx
, mem_ctx
, &ids
[bidx
], result
,
423 dom
->name
, attrs
, ID_TYPE_GID
);
425 TALLOC_FREE(fltr_grp
);
435 talloc_free(mem_ctx
);
439 struct idmap_rfc2307_map
{
446 * Lookup names for SIDS and store the data in the local mapping
449 static NTSTATUS
idmap_rfc_2307_sids_to_names(TALLOC_CTX
*mem_ctx
,
451 struct idmap_rfc2307_map
*maps
,
452 struct idmap_rfc2307_context
*ctx
)
456 for (i
= 0; ids
[i
]; i
++) {
457 const char *domain
, *name
;
458 enum lsa_SidType lsa_type
;
459 struct id_map
*id
= ids
[i
];
460 struct idmap_rfc2307_map
*map
= &maps
[i
];
461 struct dom_sid_buf buf
;
464 /* by default calls to winbindd are disabled
465 the following call will not recurse so this is safe */
467 b
= winbind_lookup_sid(mem_ctx
, ids
[i
]->sid
, &domain
, &name
,
472 DEBUG(1, ("Lookup sid %s failed.\n",
473 dom_sid_str_buf(ids
[i
]->sid
, &buf
)));
479 id
->xid
.type
= map
->type
= ID_TYPE_UID
;
480 if (ctx
->user_cn
&& ctx
->realm
!= NULL
) {
481 name
= talloc_asprintf(mem_ctx
, "%s@%s",
484 id
->xid
.type
= map
->type
= ID_TYPE_UID
;
487 case SID_NAME_DOM_GRP
:
489 case SID_NAME_WKN_GRP
:
490 if (ctx
->realm
!= NULL
) {
491 name
= talloc_asprintf(mem_ctx
, "%s@%s",
494 id
->xid
.type
= map
->type
= ID_TYPE_GID
;
498 DEBUG(1, ("Unknown lsa type %d for sid %s\n",
500 dom_sid_str_buf(id
->sid
, &buf
)));
501 id
->status
= ID_UNMAPPED
;
506 id
->status
= ID_UNKNOWN
;
507 map
->name
= strupper_talloc(mem_ctx
, name
);
510 return NT_STATUS_NO_MEMORY
;
518 * Find id_map entry by looking up the name in the internal
521 static struct id_map
* idmap_rfc2307_find_map(struct idmap_rfc2307_map
*maps
,
527 DEBUG(10, ("Looking for name %s, type %d\n", name
, type
));
529 for (i
= 0; maps
[i
].map
!= NULL
; i
++) {
530 DEBUG(10, ("Entry %d: name %s, type %d\n",
531 i
, maps
[i
].name
, maps
[i
].type
));
532 if (type
== maps
[i
].type
&& strcmp(name
, maps
[i
].name
) == 0) {
540 static void idmap_rfc2307_map_xid_results(struct idmap_rfc2307_context
*ctx
,
542 struct idmap_rfc2307_map
*maps
,
544 struct idmap_domain
*dom
,
545 const char **attrs
, enum id_type type
)
550 count
= ldap_count_entries(ctx
->ldap
, result
);
552 for (i
= 0; i
< count
; i
++) {
556 struct id_map
*id_map
;
559 entry
= ldap_first_entry(ctx
->ldap
, result
);
561 entry
= ldap_next_entry(ctx
->ldap
, entry
);
564 DEBUG(2, ("Unable to fetch entry.\n"));
568 name
= smbldap_talloc_single_attribute(ctx
->ldap
, entry
,
571 DEBUG(1, ("Could not get user name\n"));
575 b
= idmap_rfc2307_get_uint32(ctx
->ldap
, entry
, attrs
[1], &id
);
577 DEBUG(5, ("Could not pull id for record %s\n", name
));
581 if (!idmap_unix_id_is_in_range(id
, dom
)) {
582 DEBUG(5, ("Requested id (%u) out of range (%u - %u).\n",
583 id
, dom
->low_id
, dom
->high_id
));
587 if (!strupper_m(name
)) {
588 DEBUG(5, ("Could not convert %s to uppercase\n", name
));
591 id_map
= idmap_rfc2307_find_map(maps
, type
, name
);
593 DEBUG(0, ("Could not find mapping entry for name %s\n",
599 id_map
->status
= ID_MAPPED
;
604 * Map sids to names and then to unixids.
606 static NTSTATUS
idmap_rfc2307_sids_to_unixids(struct idmap_domain
*dom
,
609 struct idmap_rfc2307_context
*ctx
;
611 struct idmap_rfc2307_map
*int_maps
;
612 int cnt_usr
= 0, cnt_grp
= 0, idx
= 0;
613 char *fltr_usr
= NULL
, *fltr_grp
= NULL
;
617 ctx
= talloc_get_type(dom
->private_data
, struct idmap_rfc2307_context
);
618 mem_ctx
= talloc_new(talloc_tos());
620 return NT_STATUS_NO_MEMORY
;
623 if (ctx
->check_connection
) {
624 ret
= ctx
->check_connection(dom
);
625 if (!NT_STATUS_IS_OK(ret
)) {
630 for (i
= 0; ids
[i
]; i
++);
631 int_maps
= talloc_zero_array(mem_ctx
, struct idmap_rfc2307_map
, i
);
633 ret
= NT_STATUS_NO_MEMORY
;
637 ret
= idmap_rfc_2307_sids_to_names(mem_ctx
, ids
, int_maps
, ctx
);
638 if (!NT_STATUS_IS_OK(ret
)) {
644 /* prepare new user query, see getpwuid() in RFC2307 */
645 fltr_usr
= talloc_asprintf(mem_ctx
,
646 "(&(objectClass=posixAccount)(|");
650 /* prepare new group query, see getgrgid() in RFC2307 */
651 fltr_grp
= talloc_asprintf(mem_ctx
,
652 "(&(objectClass=posixGroup)(|");
655 if (!fltr_usr
|| !fltr_grp
) {
656 ret
= NT_STATUS_NO_MEMORY
;
660 while (cnt_usr
< IDMAP_LDAP_MAX_IDS
&&
661 cnt_grp
< IDMAP_LDAP_MAX_IDS
&& ids
[idx
]) {
662 struct id_map
*id
= ids
[idx
];
663 struct idmap_rfc2307_map
*map
= &int_maps
[idx
];
665 switch(id
->xid
.type
) {
667 fltr_usr
= talloc_asprintf_append_buffer(fltr_usr
,
668 "(%s=%s)", (ctx
->user_cn
? "cn" : "uid"),
674 fltr_grp
= talloc_asprintf_append_buffer(fltr_grp
,
675 "(cn=%s)", map
->name
);
683 if (!fltr_usr
|| !fltr_grp
) {
684 ret
= NT_STATUS_NO_MEMORY
;
691 if (cnt_usr
== IDMAP_LDAP_MAX_IDS
|| (cnt_usr
!= 0 && !ids
[idx
])) {
692 const char *attrs
[] = { NULL
, /* uid or cn */
697 fltr_usr
= talloc_strdup_append(fltr_usr
, "))");
699 ret
= NT_STATUS_NO_MEMORY
;
703 attrs
[0] = ctx
->user_cn
? "cn" : "uid";
704 ret
= ctx
->search(ctx
, ctx
->bind_path_user
, fltr_usr
, attrs
,
706 if (!NT_STATUS_IS_OK(ret
)) {
710 idmap_rfc2307_map_xid_results(ctx
, mem_ctx
, int_maps
,
711 result
, dom
, attrs
, ID_TYPE_UID
);
714 TALLOC_FREE(fltr_usr
);
717 if (cnt_grp
== IDMAP_LDAP_MAX_IDS
|| (cnt_grp
!= 0 && !ids
[idx
])) {
718 const char *attrs
[] = {"cn", "gidNumber", NULL
};
721 fltr_grp
= talloc_strdup_append(fltr_grp
, "))");
723 ret
= NT_STATUS_NO_MEMORY
;
727 ret
= ctx
->search(ctx
, ctx
->bind_path_group
, fltr_grp
, attrs
,
729 if (!NT_STATUS_IS_OK(ret
)) {
733 idmap_rfc2307_map_xid_results(ctx
, mem_ctx
, int_maps
, result
,
734 dom
, attrs
, ID_TYPE_GID
);
736 TALLOC_FREE(fltr_grp
);
746 talloc_free(mem_ctx
);
750 static int idmap_rfc2307_context_destructor(struct idmap_rfc2307_context
*ctx
)
752 TALLOC_FREE(ctx
->ads
);
754 if (ctx
->smbldap_state
!= NULL
) {
755 smbldap_free_struct(&ctx
->smbldap_state
);
761 static NTSTATUS
idmap_rfc2307_initialize(struct idmap_domain
*domain
)
763 struct idmap_rfc2307_context
*ctx
;
764 const char *bind_path_user
, *bind_path_group
, *ldap_server
, *realm
;
767 ctx
= talloc_zero(domain
, struct idmap_rfc2307_context
);
769 return NT_STATUS_NO_MEMORY
;
771 talloc_set_destructor(ctx
, idmap_rfc2307_context_destructor
);
773 bind_path_user
= idmap_config_const_string(
774 domain
->name
, "bind_path_user", NULL
);
775 if (bind_path_user
== NULL
) {
776 status
= NT_STATUS_INVALID_PARAMETER
;
779 ctx
->bind_path_user
= talloc_strdup(ctx
, bind_path_user
);
780 if (ctx
->bind_path_user
== NULL
) {
781 status
= NT_STATUS_NO_MEMORY
;
785 bind_path_group
= idmap_config_const_string(
786 domain
->name
, "bind_path_group", NULL
);
787 if (bind_path_group
== NULL
) {
788 status
= NT_STATUS_INVALID_PARAMETER
;
791 ctx
->bind_path_group
= talloc_strdup(ctx
, bind_path_group
);
792 if (ctx
->bind_path_group
== NULL
) {
793 status
= NT_STATUS_NO_MEMORY
;
797 ldap_server
= idmap_config_const_string(
798 domain
->name
, "ldap_server", NULL
);
800 status
= NT_STATUS_INVALID_PARAMETER
;
804 if (strcmp(ldap_server
, "stand-alone") == 0) {
805 status
= idmap_rfc2307_init_ldap(ctx
, domain
->name
);
807 } else if (strcmp(ldap_server
, "ad") == 0) {
808 status
= idmap_rfc2307_init_ads(ctx
, domain
->name
);
811 status
= NT_STATUS_INVALID_PARAMETER
;
814 if (!NT_STATUS_IS_OK(status
)) {
818 realm
= idmap_config_const_string(domain
->name
, "realm", NULL
);
820 ctx
->realm
= talloc_strdup(ctx
, realm
);
821 if (ctx
->realm
== NULL
) {
822 status
= NT_STATUS_NO_MEMORY
;
827 ctx
->user_cn
= idmap_config_bool(domain
->name
, "user_cn", false);
829 domain
->private_data
= ctx
;
837 static const struct idmap_methods rfc2307_methods
= {
838 .init
= idmap_rfc2307_initialize
,
839 .unixids_to_sids
= idmap_rfc2307_unixids_to_sids
,
840 .sids_to_unixids
= idmap_rfc2307_sids_to_unixids
,
844 NTSTATUS
idmap_rfc2307_init(TALLOC_CTX
*ctx
)
846 return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION
, "rfc2307",