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
11 * Copyright (C) Luke Howard 2001-2004
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31 #define DBGC_CLASS DBGC_IDMAP
33 #define WINBIND_CCACHE_NAME "MEMORY:winbind_ccache"
35 NTSTATUS
init_module(void);
37 static ADS_STRUCT
*ad_idmap_ads
= NULL
;
39 static char *attr_uidnumber
= NULL
;
40 static char *attr_gidnumber
= NULL
;
42 static ADS_STATUS
ad_idmap_check_attr_mapping(ADS_STRUCT
*ads
)
45 enum wb_posix_mapping map_type
;
47 if (attr_uidnumber
!= NULL
&& attr_gidnumber
!= NULL
) {
48 return ADS_ERROR(LDAP_SUCCESS
);
51 SMB_ASSERT(ads
->server
.workgroup
);
53 map_type
= get_nss_info(ads
->server
.workgroup
);
55 if ((map_type
== WB_POSIX_MAP_SFU
) ||
56 (map_type
== WB_POSIX_MAP_RFC2307
)) {
58 status
= ads_check_posix_schema_mapping(ads
, map_type
);
59 if (ADS_ERR_OK(status
)) {
60 attr_uidnumber
= SMB_STRDUP(ads
->schema
.posix_uidnumber_attr
);
61 attr_gidnumber
= SMB_STRDUP(ads
->schema
.posix_gidnumber_attr
);
62 ADS_ERROR_HAVE_NO_MEMORY(attr_uidnumber
);
63 ADS_ERROR_HAVE_NO_MEMORY(attr_gidnumber
);
64 return ADS_ERROR(LDAP_SUCCESS
);
66 DEBUG(0,("ads_check_posix_schema_mapping failed: %s\n", ads_errstr(status
)));
71 /* fallback to XAD defaults */
72 attr_uidnumber
= SMB_STRDUP("uidNumber");
73 attr_gidnumber
= SMB_STRDUP("gidNumber");
74 ADS_ERROR_HAVE_NO_MEMORY(attr_uidnumber
);
75 ADS_ERROR_HAVE_NO_MEMORY(attr_gidnumber
);
77 return ADS_ERROR(LDAP_SUCCESS
);
80 static ADS_STRUCT
*ad_idmap_cached_connection(void)
86 if (ad_idmap_ads
!= NULL
) {
89 /* check for a valid structure */
91 DEBUG(7, ("Current tickets expire at %d, time is now %d\n",
92 (uint32
) ads
->auth
.expire
, (uint32
) time(NULL
)));
93 if ( ads
->config
.realm
&& (ads
->auth
.expire
> time(NULL
))) {
96 /* we own this ADS_STRUCT so make sure it goes away */
99 ads_kdestroy(WINBIND_CCACHE_NAME
);
105 /* we don't want this to affect the users ccache */
106 setenv("KRB5CCNAME", WINBIND_CCACHE_NAME
, 1);
109 ads
= ads_init(lp_realm(), lp_workgroup(), NULL
);
111 DEBUG(1,("ads_init failed\n"));
115 /* the machine acct password might have change - fetch it every time */
116 SAFE_FREE(ads
->auth
.password
);
117 ads
->auth
.password
= secrets_fetch_machine_password(lp_workgroup(), NULL
, NULL
);
119 SAFE_FREE(ads
->auth
.realm
);
120 ads
->auth
.realm
= SMB_STRDUP(lp_realm());
122 status
= ads_connect(ads
);
123 if (!ADS_ERR_OK(status
)) {
124 DEBUG(1, ("ad_idmap_init: failed to connect to AD\n"));
129 ads
->is_mine
= False
;
131 status
= ad_idmap_check_attr_mapping(ads
);
132 if (!ADS_ERR_OK(status
)) {
133 DEBUG(1, ("ad_idmap_init: failed to check attribute mapping\n"));
142 static NTSTATUS
ad_idmap_init(const char *uri
)
147 static NTSTATUS
ad_idmap_get_sid_from_id(DOM_SID
*sid
, unid_t unid
, enum idmap_type id_type
, int flags
)
150 NTSTATUS status
= NT_STATUS_NONE_MAPPED
;
151 const char *attrs
[] = { "objectSid", NULL
};
152 LDAPMessage
*res
= NULL
;
153 LDAPMessage
*msg
= NULL
;
160 return NT_STATUS_INVALID_PARAMETER
;
163 ads
= ad_idmap_cached_connection();
165 DEBUG(1, ("ad_idmap_get_id_from_sid ADS uninitialized\n"));
166 return NT_STATUS_NOT_SUPPORTED
;
171 if (asprintf(&expr
, "(&(|(sAMAccountType=%d)(sAMAccountType=%d)(sAMAccountType=%d))(%s=%d))",
172 ATYPE_NORMAL_ACCOUNT
, ATYPE_WORKSTATION_TRUST
, ATYPE_INTERDOMAIN_TRUST
,
173 ads
->schema
.posix_uidnumber_attr
, (int)unid
.uid
) == -1) {
174 return NT_STATUS_NO_MEMORY
;
178 if (asprintf(&expr
, "(&(|(sAMAccountType=%d)(sAMAccountType=%d))(%s=%d))",
179 ATYPE_SECURITY_GLOBAL_GROUP
, ATYPE_SECURITY_LOCAL_GROUP
,
180 ads
->schema
.posix_gidnumber_attr
, (int)unid
.gid
) == -1) {
181 return NT_STATUS_NO_MEMORY
;
185 return NT_STATUS_INVALID_PARAMETER
;
189 rc
= ads_search_retry(ads
, &res
, expr
, attrs
);
191 if (!ADS_ERR_OK(rc
)) {
192 DEBUG(1, ("ad_idmap_get_sid_from_id: ads_search: %s\n", ads_errstr(rc
)));
196 count
= ads_count_replies(ads
, res
);
198 DEBUG(1, ("ad_idmap_get_sid_from_id: ads_count_replies: no results\n"));
200 } else if (count
!= 1) {
201 DEBUG(1, ("ad_idmap_get_sid_from_id: ads_count_replies: incorrect cardinality\n"));
205 msg
= ads_first_entry(ads
, res
);
207 DEBUG(1, ("ad_idmap_get_sid_from_id: ads_first_entry: could not retrieve search result\n"));
211 if (!ads_pull_sid(ads
, msg
, "objectSid", sid
)) {
212 DEBUG(1, ("ad_idmap_get_sid_from_id: ads_pull_sid: could not retrieve SID from entry\n"));
216 status
= NT_STATUS_OK
;
217 DEBUG(1, ("ad_idmap_get_sid_from_id mapped POSIX %s %d to SID [%s]\n",
218 (id_type
== ID_GROUPID
) ? "GID" : "UID", (int)unid
.uid
,
219 sid_to_string(sid_string
, sid
)));
223 ads_msgfree(ads
, res
);
229 static NTSTATUS
ad_idmap_get_id_from_sid(unid_t
*unid
, enum idmap_type
*id_type
, const DOM_SID
*sid
, int flags
)
232 NTSTATUS status
= NT_STATUS_NONE_MAPPED
;
233 const char *attrs
[] = { "sAMAccountType", ADS_ATTR_SFU_UIDNUMBER_OID
,
234 ADS_ATTR_SFU_GIDNUMBER_OID
,
235 ADS_ATTR_RFC2307_UIDNUMBER_OID
,
236 ADS_ATTR_RFC2307_GIDNUMBER_OID
,
238 LDAPMessage
*res
= NULL
;
239 LDAPMessage
*msg
= NULL
;
248 return NT_STATUS_INVALID_PARAMETER
;
251 ads
= ad_idmap_cached_connection();
253 DEBUG(1, ("ad_idmap_get_id_from_sid ADS uninitialized\n"));
254 return NT_STATUS_NOT_SUPPORTED
;
257 sidstr
= sid_binstring(sid
);
258 if (asprintf(&expr
, "(objectSid=%s)", sidstr
) == -1) {
260 return NT_STATUS_NO_MEMORY
;
263 rc
= ads_search_retry(ads
, &res
, expr
, attrs
);
266 if (!ADS_ERR_OK(rc
)) {
267 DEBUG(1, ("ad_idmap_get_id_from_sid: ads_search: %s\n", ads_errstr(rc
)));
271 count
= ads_count_replies(ads
, res
);
273 DEBUG(1, ("ad_idmap_get_id_from_sid: ads_count_replies: no results\n"));
275 } else if (count
!= 1) {
276 DEBUG(1, ("ad_idmap_get_id_from_sid: ads_count_replies: incorrect cardinality\n"));
280 msg
= ads_first_entry(ads
, res
);
282 DEBUG(1, ("ad_idmap_get_id_from_sid: ads_first_entry: could not retrieve search result\n"));
286 if (!ads_pull_uint32(ads
, msg
, "sAMAccountType", &atype
)) {
287 DEBUG(1, ("ad_idmap_get_id_from_sid: ads_pull_uint32: could not read SAM account type\n"));
291 switch (atype
& 0xF0000000) {
292 case ATYPE_SECURITY_GLOBAL_GROUP
:
293 case ATYPE_SECURITY_LOCAL_GROUP
:
294 *id_type
= ID_GROUPID
;
296 case ATYPE_NORMAL_ACCOUNT
:
297 case ATYPE_WORKSTATION_TRUST
:
298 case ATYPE_INTERDOMAIN_TRUST
:
299 *id_type
= ID_USERID
;
302 DEBUG(1, ("ad_idmap_get_id_from_sid: unrecognized SAM account type %08x\n", atype
));
307 if (!ads_pull_uint32(ads
, msg
, (*id_type
== ID_GROUPID
) ? attr_gidnumber
: attr_uidnumber
, &uid
)) {
308 DEBUG(1, ("ad_idmap_get_id_from_sid: ads_pull_uint32: could not read attribute '%s'\n",
309 (*id_type
== ID_GROUPID
) ? attr_gidnumber
: attr_uidnumber
));
313 unid
->uid
= (uid_t
)uid
;
315 status
= NT_STATUS_OK
;
316 DEBUG(1, ("ad_idmap_get_id_from_sid mapped SID [%s] to POSIX %s %d\n",
317 sid_to_string(sid_string
, sid
),
318 (*id_type
== ID_GROUPID
) ? "GID" : "UID", uid
));
322 ads_msgfree(ads
, res
);
329 static NTSTATUS
ad_idmap_set_mapping(const DOM_SID
*sid
, unid_t id
, enum idmap_type id_type
)
331 /* Not supported, and probably won't be... */
332 /* (It's not particularly feasible with a single-master model.) */
334 return NT_STATUS_NOT_IMPLEMENTED
;
337 static NTSTATUS
ad_idmap_close(void)
339 ADS_STRUCT
*ads
= ad_idmap_ads
;
342 /* we own this ADS_STRUCT so make sure it goes away */
348 SAFE_FREE(attr_uidnumber
);
349 SAFE_FREE(attr_gidnumber
);
354 static NTSTATUS
ad_idmap_allocate_id(unid_t
*id
, enum idmap_type id_type
)
356 return NT_STATUS_NOT_IMPLEMENTED
;
359 static void ad_idmap_status(void)
361 DEBUG(0, ("AD IDMAP Status not available\n"));
364 static struct idmap_methods ad_methods
= {
366 ad_idmap_allocate_id
,
367 ad_idmap_get_sid_from_id
,
368 ad_idmap_get_id_from_sid
,
369 ad_idmap_set_mapping
,
375 /* support for new authentication subsystem */
376 NTSTATUS
idmap_ad_init(void)
378 return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION
, "ad", &ad_methods
);