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-2007
11 * Copyright (C) Luke Howard 2001-2004
12 * Copyright (C) Michael Adam 2008,2010
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 3 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see <http://www.gnu.org/licenses/>.
30 #include "../libds/common/flags.h"
31 #include "winbindd_ads.h"
32 #include "libads/ldap_schema.h"
35 #include "../libcli/ldap/ldap_ndr.h"
36 #include "../libcli/security/security.h"
39 #define DBGC_CLASS DBGC_IDMAP
41 #define CHECK_ALLOC_DONE(mem) do { \
43 DEBUG(0, ("Out of memory!\n")); \
44 ret = NT_STATUS_NO_MEMORY; \
49 struct idmap_ad_context
{
51 struct posix_schema
*ad_schema
;
52 enum wb_posix_mapping ad_map_type
; /* WB_POSIX_MAP_UNKNOWN */
55 /************************************************************************
56 ***********************************************************************/
58 static ADS_STATUS
ad_idmap_cached_connection(struct idmap_domain
*dom
)
61 struct idmap_ad_context
* ctx
;
63 DEBUG(10, ("ad_idmap_cached_connection: called for domain '%s'\n",
66 ctx
= talloc_get_type(dom
->private_data
, struct idmap_ad_context
);
68 status
= ads_idmap_cached_connection(&ctx
->ads
, dom
->name
);
69 if (!ADS_ERR_OK(status
)) {
73 ctx
= talloc_get_type(dom
->private_data
, struct idmap_ad_context
);
75 /* if we have a valid ADS_STRUCT and the schema model is
76 defined, then we can return here. */
78 if ( ctx
->ad_schema
) {
82 /* Otherwise, set the schema model */
84 if ( (ctx
->ad_map_type
== WB_POSIX_MAP_SFU
) ||
85 (ctx
->ad_map_type
== WB_POSIX_MAP_SFU20
) ||
86 (ctx
->ad_map_type
== WB_POSIX_MAP_RFC2307
) )
88 status
= ads_check_posix_schema_mapping(
89 ctx
, ctx
->ads
, ctx
->ad_map_type
, &ctx
->ad_schema
);
90 if ( !ADS_ERR_OK(status
) ) {
91 DEBUG(2,("ad_idmap_cached_connection: Failed to obtain schema details!\n"));
99 * nss_info_{sfu,sfu20,rfc2307}
102 /************************************************************************
103 Initialize the {sfu,sfu20,rfc2307} state
104 ***********************************************************************/
106 static const char *wb_posix_map_unknown_string
= "WB_POSIX_MAP_UNKNOWN";
107 static const char *wb_posix_map_template_string
= "WB_POSIX_MAP_TEMPLATE";
108 static const char *wb_posix_map_sfu_string
= "WB_POSIX_MAP_SFU";
109 static const char *wb_posix_map_sfu20_string
= "WB_POSIX_MAP_SFU20";
110 static const char *wb_posix_map_rfc2307_string
= "WB_POSIX_MAP_RFC2307";
111 static const char *wb_posix_map_unixinfo_string
= "WB_POSIX_MAP_UNIXINFO";
113 static const char *ad_map_type_string(enum wb_posix_mapping map_type
)
116 case WB_POSIX_MAP_TEMPLATE
:
117 return wb_posix_map_template_string
;
118 case WB_POSIX_MAP_SFU
:
119 return wb_posix_map_sfu_string
;
120 case WB_POSIX_MAP_SFU20
:
121 return wb_posix_map_sfu20_string
;
122 case WB_POSIX_MAP_RFC2307
:
123 return wb_posix_map_rfc2307_string
;
124 case WB_POSIX_MAP_UNIXINFO
:
125 return wb_posix_map_unixinfo_string
;
127 return wb_posix_map_unknown_string
;
131 static NTSTATUS
nss_ad_generic_init(struct nss_domain_entry
*e
,
132 enum wb_posix_mapping new_ad_map_type
)
134 struct idmap_domain
*dom
;
135 struct idmap_ad_context
*ctx
;
137 if (e
->state
!= NULL
) {
138 dom
= talloc_get_type(e
->state
, struct idmap_domain
);
140 dom
= talloc_zero(e
, struct idmap_domain
);
142 DEBUG(0, ("Out of memory!\n"));
143 return NT_STATUS_NO_MEMORY
;
148 if (e
->domain
!= NULL
) {
149 dom
->name
= talloc_strdup(dom
, e
->domain
);
150 if (dom
->name
== NULL
) {
151 DEBUG(0, ("Out of memory!\n"));
152 return NT_STATUS_NO_MEMORY
;
156 if (dom
->private_data
!= NULL
) {
157 ctx
= talloc_get_type(dom
->private_data
,
158 struct idmap_ad_context
);
160 ctx
= talloc_zero(dom
, struct idmap_ad_context
);
162 DEBUG(0, ("Out of memory!\n"));
163 return NT_STATUS_NO_MEMORY
;
165 ctx
->ad_map_type
= WB_POSIX_MAP_RFC2307
;
166 dom
->private_data
= ctx
;
169 if ((ctx
->ad_map_type
!= WB_POSIX_MAP_UNKNOWN
) &&
170 (ctx
->ad_map_type
!= new_ad_map_type
))
172 DEBUG(2, ("nss_ad_generic_init: "
173 "Warning: overriding previously set posix map type "
174 "%s for domain %s with map type %s.\n",
175 ad_map_type_string(ctx
->ad_map_type
),
177 ad_map_type_string(new_ad_map_type
)));
180 ctx
->ad_map_type
= new_ad_map_type
;
185 static NTSTATUS
nss_sfu_init( struct nss_domain_entry
*e
)
187 return nss_ad_generic_init(e
, WB_POSIX_MAP_SFU
);
190 static NTSTATUS
nss_sfu20_init( struct nss_domain_entry
*e
)
192 return nss_ad_generic_init(e
, WB_POSIX_MAP_SFU20
);
195 static NTSTATUS
nss_rfc2307_init( struct nss_domain_entry
*e
)
197 return nss_ad_generic_init(e
, WB_POSIX_MAP_RFC2307
);
200 /**********************************************************************
201 *********************************************************************/
203 static NTSTATUS
nss_ad_map_to_alias(TALLOC_CTX
*mem_ctx
,
204 struct nss_domain_entry
*e
,
208 const char *attrs
[] = {NULL
, /* attr_uid */
211 LDAPMessage
*msg
= NULL
;
212 ADS_STATUS ads_status
= ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL
);
213 NTSTATUS nt_status
= NT_STATUS_UNSUCCESSFUL
;
214 struct idmap_domain
*dom
;
215 struct idmap_ad_context
*ctx
= NULL
;
217 /* Check incoming parameters */
219 if ( !e
|| !e
->domain
|| !name
|| !*alias
) {
220 nt_status
= NT_STATUS_INVALID_PARAMETER
;
224 /* Only do query if we are online */
226 if (idmap_is_offline()) {
227 nt_status
= NT_STATUS_FILE_IS_OFFLINE
;
231 dom
= talloc_get_type(e
->state
, struct idmap_domain
);
232 ctx
= talloc_get_type(dom
->private_data
, struct idmap_ad_context
);
234 ads_status
= ad_idmap_cached_connection(dom
);
235 if (!ADS_ERR_OK(ads_status
)) {
236 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
239 if (!ctx
->ad_schema
) {
240 nt_status
= NT_STATUS_OBJECT_PATH_NOT_FOUND
;
244 attrs
[0] = ctx
->ad_schema
->posix_uid_attr
;
246 filter
= talloc_asprintf(mem_ctx
,
247 "(sAMAccountName=%s)",
250 nt_status
= NT_STATUS_NO_MEMORY
;
254 ads_status
= ads_search_retry(ctx
->ads
, &msg
, filter
, attrs
);
255 if (!ADS_ERR_OK(ads_status
)) {
256 nt_status
= ads_ntstatus(ads_status
);
260 *alias
= ads_pull_string(ctx
->ads
, mem_ctx
, msg
, ctx
->ad_schema
->posix_uid_attr
);
263 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
266 nt_status
= NT_STATUS_OK
;
270 talloc_destroy(filter
);
273 ads_msgfree(ctx
->ads
, msg
);
279 /**********************************************************************
280 *********************************************************************/
282 static NTSTATUS
nss_ad_map_from_alias( TALLOC_CTX
*mem_ctx
,
283 struct nss_domain_entry
*e
,
287 const char *attrs
[] = {"sAMAccountName",
290 LDAPMessage
*msg
= NULL
;
291 ADS_STATUS ads_status
= ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL
);
292 NTSTATUS nt_status
= NT_STATUS_UNSUCCESSFUL
;
293 char *username
= NULL
;
294 struct idmap_domain
*dom
;
295 struct idmap_ad_context
*ctx
= NULL
;
297 /* Check incoming parameters */
299 if ( !alias
|| !name
) {
300 nt_status
= NT_STATUS_INVALID_PARAMETER
;
304 /* Only do query if we are online */
306 if (idmap_is_offline()) {
307 nt_status
= NT_STATUS_FILE_IS_OFFLINE
;
311 dom
= talloc_get_type(e
->state
, struct idmap_domain
);
312 ctx
= talloc_get_type(dom
->private_data
, struct idmap_ad_context
);
314 ads_status
= ad_idmap_cached_connection(dom
);
315 if (!ADS_ERR_OK(ads_status
)) {
316 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
319 if (!ctx
->ad_schema
) {
320 nt_status
= NT_STATUS_OBJECT_PATH_NOT_FOUND
;
324 filter
= talloc_asprintf(mem_ctx
,
326 ctx
->ad_schema
->posix_uid_attr
,
329 nt_status
= NT_STATUS_NO_MEMORY
;
333 ads_status
= ads_search_retry(ctx
->ads
, &msg
, filter
, attrs
);
334 if (!ADS_ERR_OK(ads_status
)) {
335 nt_status
= ads_ntstatus(ads_status
);
339 username
= ads_pull_string(ctx
->ads
, mem_ctx
, msg
,
342 nt_status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
346 *name
= talloc_asprintf(mem_ctx
, "%s\\%s",
350 nt_status
= NT_STATUS_NO_MEMORY
;
354 nt_status
= NT_STATUS_OK
;
357 TALLOC_FREE(username
);
360 ads_msgfree(ctx
->ads
, msg
);
366 /************************************************************************
367 Function dispatch tables for the idmap and nss plugins
368 ***********************************************************************/
370 /* The SFU and RFC2307 NSS plugins share everything but the init
371 function which sets the intended schema model to use */
373 static struct nss_info_methods nss_rfc2307_methods
= {
374 .init
= nss_rfc2307_init
,
375 .map_to_alias
= nss_ad_map_to_alias
,
376 .map_from_alias
= nss_ad_map_from_alias
,
379 static struct nss_info_methods nss_sfu_methods
= {
380 .init
= nss_sfu_init
,
381 .map_to_alias
= nss_ad_map_to_alias
,
382 .map_from_alias
= nss_ad_map_from_alias
,
385 static struct nss_info_methods nss_sfu20_methods
= {
386 .init
= nss_sfu20_init
,
387 .map_to_alias
= nss_ad_map_to_alias
,
388 .map_from_alias
= nss_ad_map_from_alias
,
393 /************************************************************************
394 Initialize the plugins
395 ***********************************************************************/
397 NTSTATUS
idmap_ad_nss_init(TALLOC_CTX
*mem_ctx
)
401 status
= smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION
,
402 "rfc2307", &nss_rfc2307_methods
);
403 if (!NT_STATUS_IS_OK(status
)) {
407 status
= smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION
,
408 "sfu", &nss_sfu_methods
);
409 if (!NT_STATUS_IS_OK(status
)) {
413 status
= smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION
,
414 "sfu20", &nss_sfu20_methods
);
415 if (!NT_STATUS_IS_OK(status
)) {