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/>.
31 #include "nsswitch/winbind_client.h"
32 #include "lib/winbind_util.h"
35 * Config and connection info per domain.
37 struct idmap_rfc2307_context
{
38 const char *bind_path_user
;
39 const char *bind_path_group
;
40 const char *ldap_domain
;
46 * Pointer to ldap struct in ads or smbldap_state, has to be
47 * updated after connecting to server
51 /* Optional function to check connection to server */
52 NTSTATUS (*check_connection
)(struct idmap_domain
*dom
);
54 /* Issue ldap query */
55 NTSTATUS (*search
)(struct idmap_rfc2307_context
*ctx
,
56 const char *bind_path
, const char *expr
,
57 const char **attrs
, LDAPMessage
**res
);
59 /* Access to LDAP in AD server */
62 /* Access to stand-alone LDAP server */
63 struct smbldap_state
*smbldap_state
;
67 * backend functions for LDAP queries through ADS
70 static NTSTATUS
idmap_rfc2307_ads_check_connection(struct idmap_domain
*dom
)
72 struct idmap_rfc2307_context
*ctx
;
73 const char *dom_name
= dom
->name
;
76 DEBUG(10, ("ad_idmap_cached_connection: called for domain '%s'\n",
79 ctx
= talloc_get_type(dom
->private_data
, struct idmap_rfc2307_context
);
80 dom_name
= ctx
->ldap_domain
? ctx
->ldap_domain
: dom
->name
;
82 status
= ads_idmap_cached_connection(&ctx
->ads
, dom_name
);
83 if (ADS_ERR_OK(status
)) {
84 ctx
->ldap
= ctx
->ads
->ldap
.ld
;
86 ctx
->realm
= ctx
->ads
->server
.realm
;
89 DEBUG(1, ("Could not connect to domain %s: %s\n", dom
->name
,
93 return ads_ntstatus(status
);
96 static NTSTATUS
idmap_rfc2307_ads_search(struct idmap_rfc2307_context
*ctx
,
97 const char *bind_path
,
100 LDAPMessage
**result
)
104 status
= ads_do_search_retry(ctx
->ads
, bind_path
,
105 LDAP_SCOPE_SUBTREE
, expr
, attrs
, result
);
106 ctx
->ldap
= ctx
->ads
->ldap
.ld
;
107 return ads_ntstatus(status
);
110 static NTSTATUS
idmap_rfc2307_init_ads(struct idmap_rfc2307_context
*ctx
,
113 const char *ldap_domain
;
115 ctx
->search
= idmap_rfc2307_ads_search
;
116 ctx
->check_connection
= idmap_rfc2307_ads_check_connection
;
118 ldap_domain
= lp_parm_const_string(-1, cfg_opt
, "ldap_domain",
121 ctx
->ldap_domain
= talloc_strdup(ctx
, ldap_domain
);
122 if (ctx
->ldap_domain
== NULL
) {
123 return NT_STATUS_NO_MEMORY
;
131 * backend function for LDAP queries through stand-alone LDAP server
134 static NTSTATUS
idmap_rfc2307_ldap_search(struct idmap_rfc2307_context
*ctx
,
135 const char *bind_path
,
138 LDAPMessage
**result
)
142 ret
= smbldap_search(ctx
->smbldap_state
, bind_path
, LDAP_SCOPE_SUBTREE
,
143 expr
, attrs
, 0, result
);
144 ctx
->ldap
= ctx
->smbldap_state
->ldap_struct
;
146 if (ret
== LDAP_SUCCESS
) {
150 return NT_STATUS_LDAP(ret
);
153 static bool idmap_rfc2307_get_uint32(LDAP
*ldap
, LDAPMessage
*entry
,
154 const char *field
, uint32_t *value
)
159 b
= smbldap_get_single_attribute(ldap
, entry
, field
, str
, sizeof(str
));
168 static NTSTATUS
idmap_rfc2307_init_ldap(struct idmap_rfc2307_context
*ctx
,
169 struct idmap_domain
*dom
,
170 const char *config_option
)
175 const char *ldap_url
, *user_dn
, *ldap_realm
;
176 TALLOC_CTX
*mem_ctx
= ctx
;
178 ldap_url
= lp_parm_const_string(-1, config_option
, "ldap_url", NULL
);
180 DEBUG(1, ("ERROR: missing idmap ldap url\n"));
181 return NT_STATUS_UNSUCCESSFUL
;
184 url
= talloc_strdup(talloc_tos(), ldap_url
);
186 user_dn
= lp_parm_const_string(-1, config_option
, "ldap_user_dn", NULL
);
188 secret
= idmap_fetch_secret("ldap", dom
->name
, user_dn
);
190 ret
= NT_STATUS_ACCESS_DENIED
;
195 /* assume anonymous if we don't have a specified user */
196 ret
= smbldap_init(mem_ctx
, winbind_event_context(), url
,
197 (user_dn
== NULL
), user_dn
, secret
,
198 &ctx
->smbldap_state
);
200 if (!NT_STATUS_IS_OK(ret
)) {
201 DEBUG(1, ("ERROR: smbldap_init (%s) failed!\n", url
));
205 ctx
->search
= idmap_rfc2307_ldap_search
;
208 ldap_realm
= lp_parm_const_string(-1, config_option
,
211 DEBUG(1, ("ERROR: cn_realm set, "
212 "but ldap_realm is missing\n"));
213 ret
= NT_STATUS_UNSUCCESSFUL
;
216 ctx
->realm
= talloc_strdup(mem_ctx
, ldap_realm
);
218 ret
= NT_STATUS_NO_MEMORY
;
228 * common code for stand-alone LDAP and ADS
231 static void idmap_rfc2307_map_sid_results(struct idmap_rfc2307_context
*ctx
,
235 const char *dom_name
,
236 const char **attrs
, int type
)
241 count
= ldap_count_entries(ctx
->ldap
, result
);
243 for (i
= 0; i
< count
; i
++) {
245 enum lsa_SidType lsa_type
;
251 entry
= ldap_first_entry(ctx
->ldap
, result
);
253 entry
= ldap_next_entry(ctx
->ldap
, result
);
256 DEBUG(2, ("Unable to fetch entry.\n"));
260 name
= smbldap_talloc_single_attribute(ctx
->ldap
, entry
,
263 DEBUG(1, ("Could not get user name\n"));
267 b
= idmap_rfc2307_get_uint32(ctx
->ldap
, entry
, attrs
[1], &id
);
269 DEBUG(1, ("Could not pull id for record %s\n", name
));
273 map
= idmap_find_map_by_id(ids
, type
, id
);
275 DEBUG(1, ("Could not find id %d, name %s\n", id
, name
));
280 /* Strip @realm from user or group name */
283 delim
= strchr(name
, '@');
289 /* by default calls to winbindd are disabled
290 the following call will not recurse so this is safe */
292 /* Lookup name from PDC using lsa_lookup_names() */
293 b
= winbind_lookup_name(dom_name
, name
, map
->sid
, &lsa_type
);
297 DEBUG(1, ("SID lookup failed for id %d, %s\n",
302 if (type
== ID_TYPE_UID
&& lsa_type
!= SID_NAME_USER
) {
303 DEBUG(1, ("Wrong type %d for user name %s\n",
308 if (type
== ID_TYPE_GID
&& lsa_type
!= SID_NAME_DOM_GRP
&&
309 lsa_type
!= SID_NAME_ALIAS
&&
310 lsa_type
!= SID_NAME_WKN_GRP
) {
311 DEBUG(1, ("Wrong type %d for group name %s\n",
316 map
->status
= ID_MAPPED
;
321 * Map unixids to names and then to sids.
323 static NTSTATUS
idmap_rfc2307_unixids_to_sids(struct idmap_domain
*dom
,
326 struct idmap_rfc2307_context
*ctx
;
327 char *fltr_usr
= NULL
, *fltr_grp
= NULL
;
329 int cnt_usr
= 0, cnt_grp
= 0, idx
= 0, bidx
= 0;
330 LDAPMessage
*result
= NULL
;
333 ctx
= talloc_get_type(dom
->private_data
, struct idmap_rfc2307_context
);
334 mem_ctx
= talloc_new(ctx
);
336 return NT_STATUS_NO_MEMORY
;
339 if (ctx
->check_connection
) {
340 ret
= ctx
->check_connection(dom
);
341 if (!NT_STATUS_IS_OK(ret
)) {
350 /* prepare new user query, see getpwuid() in RFC2307 */
351 fltr_usr
= talloc_asprintf(mem_ctx
,
352 "(&(objectClass=posixAccount)(|");
356 /* prepare new group query, see getgrgid() in RFC2307 */
357 fltr_grp
= talloc_asprintf(mem_ctx
,
358 "(&(objectClass=posixGroup)(|");
361 if (!fltr_usr
|| !fltr_grp
) {
362 ret
= NT_STATUS_NO_MEMORY
;
366 while (cnt_usr
< IDMAP_LDAP_MAX_IDS
&&
367 cnt_grp
< IDMAP_LDAP_MAX_IDS
&& ids
[idx
]) {
369 switch (ids
[idx
]->xid
.type
) {
371 fltr_usr
= talloc_asprintf_append_buffer(fltr_usr
,
372 "(uidNumber=%d)", ids
[idx
]->xid
.id
);
376 fltr_grp
= talloc_asprintf_append_buffer(fltr_grp
,
377 "(gidNumber=%d))", ids
[idx
]->xid
.id
);
381 DEBUG(3, ("Error: unknown ID type %d\n",
382 ids
[idx
]->xid
.type
));
383 ret
= NT_STATUS_UNSUCCESSFUL
;
387 if (!fltr_usr
|| !fltr_grp
) {
388 ret
= NT_STATUS_NO_MEMORY
;
395 if (cnt_usr
== IDMAP_LDAP_MAX_IDS
|| (cnt_usr
!= 0 && !ids
[idx
])) {
396 const char *attrs
[] = { NULL
, /* uid or cn */
400 fltr_usr
= talloc_strdup_append(fltr_usr
, "))");
402 ret
= NT_STATUS_NO_MEMORY
;
406 attrs
[0] = ctx
->user_cn
? "cn" : "uid";
407 ret
= ctx
->search(ctx
, ctx
->bind_path_user
, fltr_usr
, attrs
,
409 if (!NT_STATUS_IS_OK(ret
)) {
413 idmap_rfc2307_map_sid_results(ctx
, mem_ctx
, &ids
[bidx
], result
,
414 dom
->name
, attrs
, ID_TYPE_UID
);
416 TALLOC_FREE(fltr_usr
);
419 if (cnt_grp
== IDMAP_LDAP_MAX_IDS
|| (cnt_grp
!= 0 && !ids
[idx
])) {
420 const char *attrs
[] = { "cn", "gidNumber", NULL
};
422 fltr_grp
= talloc_strdup_append(fltr_grp
, "))");
424 ret
= NT_STATUS_NO_MEMORY
;
427 ret
= ctx
->search(ctx
, ctx
->bind_path_group
, fltr_grp
, attrs
,
429 if (!NT_STATUS_IS_OK(ret
)) {
433 idmap_rfc2307_map_sid_results(ctx
, mem_ctx
, &ids
[bidx
], result
,
434 dom
->name
, attrs
, ID_TYPE_GID
);
436 TALLOC_FREE(fltr_grp
);
446 talloc_free(mem_ctx
);
450 struct idmap_rfc2307_map
{
457 * Lookup names for SIDS and store the data in the local mapping
460 static NTSTATUS
idmap_rfc_2307_sids_to_names(TALLOC_CTX
*mem_ctx
,
462 struct idmap_rfc2307_map
*maps
,
463 struct idmap_rfc2307_context
*ctx
)
467 for (i
= 0; ids
[i
]; i
++) {
468 const char *domain
, *name
;
469 enum lsa_SidType lsa_type
;
470 struct id_map
*id
= ids
[i
];
471 struct idmap_rfc2307_map
*map
= &maps
[i
];
474 /* by default calls to winbindd are disabled
475 the following call will not recurse so this is safe */
477 b
= winbind_lookup_sid(mem_ctx
, ids
[i
]->sid
, &domain
, &name
,
482 DEBUG(1, ("Lookup sid %s failed.\n",
483 sid_string_dbg(ids
[i
]->sid
)));
489 id
->xid
.type
= map
->type
= ID_TYPE_UID
;
490 if (ctx
->user_cn
&& ctx
->cn_realm
) {
491 name
= talloc_asprintf(mem_ctx
, "%s@%s",
494 id
->xid
.type
= map
->type
= ID_TYPE_UID
;
497 case SID_NAME_DOM_GRP
:
499 case SID_NAME_WKN_GRP
:
501 name
= talloc_asprintf(mem_ctx
, "%s@%s",
504 id
->xid
.type
= map
->type
= ID_TYPE_GID
;
508 DEBUG(1, ("Unknown lsa type %d for sid %s\n",
509 lsa_type
, sid_string_dbg(id
->sid
)));
510 id
->status
= ID_UNMAPPED
;
515 id
->status
= ID_UNKNOWN
;
516 map
->name
= strupper_talloc(mem_ctx
, name
);
519 return NT_STATUS_NO_MEMORY
;
527 * Find id_map entry by looking up the name in the internal
530 static struct id_map
* idmap_rfc2307_find_map(struct idmap_rfc2307_map
*maps
,
536 DEBUG(10, ("Looking for name %s, type %d\n", name
, type
));
538 for (i
= 0; i
< IDMAP_LDAP_MAX_IDS
; i
++) {
539 if (maps
[i
].map
== NULL
) { /* end of the run */
542 DEBUG(10, ("Entry %d: name %s, type %d\n",
543 i
, maps
[i
].name
, maps
[i
].type
));
544 if (type
== maps
[i
].type
&& strcmp(name
, maps
[i
].name
) == 0) {
552 static void idmap_rfc2307_map_xid_results(struct idmap_rfc2307_context
*ctx
,
554 struct idmap_rfc2307_map
*maps
,
556 struct idmap_domain
*dom
,
557 const char **attrs
, enum id_type type
)
562 count
= ldap_count_entries(ctx
->ldap
, result
);
564 for (i
= 0; i
< count
; i
++) {
568 struct id_map
*id_map
;
571 entry
= ldap_first_entry(ctx
->ldap
, result
);
573 entry
= ldap_next_entry(ctx
->ldap
, result
);
576 DEBUG(2, ("Unable to fetch entry.\n"));
580 name
= smbldap_talloc_single_attribute(ctx
->ldap
, entry
,
583 DEBUG(1, ("Could not get user name\n"));
587 b
= idmap_rfc2307_get_uint32(ctx
->ldap
, entry
, attrs
[1], &id
);
589 DEBUG(5, ("Could not pull id for record %s\n", name
));
593 if (!idmap_unix_id_is_in_range(id
, dom
)) {
594 DEBUG(5, ("Requested id (%u) out of range (%u - %u).\n",
595 id
, dom
->low_id
, dom
->high_id
));
599 if (!strupper_m(name
)) {
600 DEBUG(5, ("Could not convert %s to uppercase\n", name
));
603 id_map
= idmap_rfc2307_find_map(maps
, type
, name
);
605 DEBUG(0, ("Could not find mapping entry for name %s\n",
611 id_map
->status
= ID_MAPPED
;
616 * Map sids to names and then to unixids.
618 static NTSTATUS
idmap_rfc2307_sids_to_unixids(struct idmap_domain
*dom
,
621 struct idmap_rfc2307_context
*ctx
;
623 struct idmap_rfc2307_map
*int_maps
;
624 int cnt_usr
= 0, cnt_grp
= 0, idx
= 0;
625 char *fltr_usr
= NULL
, *fltr_grp
= NULL
;
629 ctx
= talloc_get_type(dom
->private_data
, struct idmap_rfc2307_context
);
630 mem_ctx
= talloc_new(talloc_tos());
632 return NT_STATUS_NO_MEMORY
;
635 if (ctx
->check_connection
) {
636 ret
= ctx
->check_connection(dom
);
637 if (!NT_STATUS_IS_OK(ret
)) {
642 for (i
= 0; ids
[i
]; i
++);
643 int_maps
= talloc_zero_array(mem_ctx
, struct idmap_rfc2307_map
, i
);
645 ret
= NT_STATUS_NO_MEMORY
;
649 ret
= idmap_rfc_2307_sids_to_names(mem_ctx
, ids
, int_maps
, ctx
);
650 if (!NT_STATUS_IS_OK(ret
)) {
656 /* prepare new user query, see getpwuid() in RFC2307 */
657 fltr_usr
= talloc_asprintf(mem_ctx
,
658 "(&(objectClass=posixAccount)(|");
662 /* prepare new group query, see getgrgid() in RFC2307 */
663 fltr_grp
= talloc_asprintf(mem_ctx
,
664 "(&(objectClass=posixGroup)(|");
667 if (!fltr_usr
|| !fltr_grp
) {
668 ret
= NT_STATUS_NO_MEMORY
;
672 while (cnt_usr
< IDMAP_LDAP_MAX_IDS
&&
673 cnt_grp
< IDMAP_LDAP_MAX_IDS
&& ids
[idx
]) {
674 struct id_map
*id
= ids
[idx
];
675 struct idmap_rfc2307_map
*map
= &int_maps
[idx
];
677 switch(id
->xid
.type
) {
679 fltr_usr
= talloc_asprintf_append_buffer(fltr_usr
,
680 "(%s=%s)", (ctx
->user_cn
? "cn" : "uid"),
686 fltr_grp
= talloc_asprintf_append_buffer(fltr_grp
,
687 "(cn=%s)", map
->name
);
692 DEBUG(10, ("Nothing to do for SID %s, "
693 "previous name lookup failed\n",
694 sid_string_dbg(map
->map
->sid
)));
697 if (!fltr_usr
|| !fltr_grp
) {
698 ret
= NT_STATUS_NO_MEMORY
;
705 if (cnt_usr
== IDMAP_LDAP_MAX_IDS
|| (cnt_usr
!= 0 && !ids
[idx
])) {
706 const char *attrs
[] = { NULL
, /* uid or cn */
711 fltr_usr
= talloc_strdup_append(fltr_usr
, "))");
713 ret
= NT_STATUS_NO_MEMORY
;
717 attrs
[0] = ctx
->user_cn
? "cn" : "uid";
718 ret
= ctx
->search(ctx
, ctx
->bind_path_user
, fltr_usr
, attrs
,
720 if (!NT_STATUS_IS_OK(ret
)) {
724 idmap_rfc2307_map_xid_results(ctx
, mem_ctx
, int_maps
,
725 result
, dom
, attrs
, ID_TYPE_UID
);
728 TALLOC_FREE(fltr_usr
);
731 if (cnt_grp
== IDMAP_LDAP_MAX_IDS
|| (cnt_grp
!= 0 && !ids
[idx
])) {
732 const char *attrs
[] = {"cn", "gidNumber", NULL
};
735 fltr_grp
= talloc_strdup_append(fltr_grp
, "))");
737 ret
= NT_STATUS_NO_MEMORY
;
741 ret
= ctx
->search(ctx
, ctx
->bind_path_group
, fltr_grp
, attrs
,
743 if (!NT_STATUS_IS_OK(ret
)) {
747 idmap_rfc2307_map_xid_results(ctx
, mem_ctx
, int_maps
, result
,
748 dom
, attrs
, ID_TYPE_GID
);
750 TALLOC_FREE(fltr_grp
);
760 talloc_free(mem_ctx
);
764 static int idmap_rfc2307_context_destructor(struct idmap_rfc2307_context
*ctx
)
766 if (ctx
->ads
!= NULL
) {
767 /* we own this ADS_STRUCT so make sure it goes away */
768 ctx
->ads
->is_mine
= True
;
769 ads_destroy( &ctx
->ads
);
773 if (ctx
->smbldap_state
!= NULL
) {
774 smbldap_free_struct(&ctx
->smbldap_state
);
780 static NTSTATUS
idmap_rfc2307_initialize(struct idmap_domain
*domain
)
782 struct idmap_rfc2307_context
*ctx
;
784 const char *bind_path_user
, *bind_path_group
, *ldap_server
;
787 ctx
= talloc_zero(domain
, struct idmap_rfc2307_context
);
789 return NT_STATUS_NO_MEMORY
;
791 talloc_set_destructor(ctx
, idmap_rfc2307_context_destructor
);
793 cfg_opt
= talloc_asprintf(ctx
, "idmap config %s", domain
->name
);
794 if (cfg_opt
== NULL
) {
795 status
= NT_STATUS_NO_MEMORY
;
799 bind_path_user
= lp_parm_const_string(-1, cfg_opt
, "bind_path_user",
801 if (bind_path_user
) {
802 ctx
->bind_path_user
= talloc_strdup(ctx
, bind_path_user
);
803 if (ctx
->bind_path_user
== NULL
) {
804 status
= NT_STATUS_NO_MEMORY
;
808 status
= NT_STATUS_INVALID_PARAMETER
;
812 bind_path_group
= lp_parm_const_string(-1, cfg_opt
, "bind_path_group",
814 if (bind_path_group
) {
815 ctx
->bind_path_group
= talloc_strdup(ctx
, bind_path_group
);
816 if (ctx
->bind_path_group
== NULL
) {
817 status
= NT_STATUS_NO_MEMORY
;
821 status
= NT_STATUS_INVALID_PARAMETER
;
825 ldap_server
= lp_parm_const_string(-1, cfg_opt
, "ldap_server", NULL
);
827 status
= NT_STATUS_INVALID_PARAMETER
;
831 if (strcmp(ldap_server
, "stand-alone") == 0) {
832 status
= idmap_rfc2307_init_ldap(ctx
, domain
, cfg_opt
);
834 } else if (strcmp(ldap_server
, "ad") == 0) {
835 status
= idmap_rfc2307_init_ads(ctx
, cfg_opt
);
838 status
= NT_STATUS_INVALID_PARAMETER
;
841 if (!NT_STATUS_IS_OK(status
)) {
845 ctx
->cn_realm
= lp_parm_bool(-1, cfg_opt
, "cn_realm", false);
846 ctx
->user_cn
= lp_parm_bool(-1, cfg_opt
, "user_cn", false);
848 domain
->private_data
= ctx
;
849 talloc_free(cfg_opt
);
853 talloc_free(cfg_opt
);
858 static struct idmap_methods rfc2307_methods
= {
859 .init
= idmap_rfc2307_initialize
,
860 .unixids_to_sids
= idmap_rfc2307_unixids_to_sids
,
861 .sids_to_unixids
= idmap_rfc2307_sids_to_unixids
,
864 NTSTATUS
idmap_rfc2307_init(void)
866 return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION
, "rfc2307",