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
;
38 static char *ad_idmap_uri
= NULL
;
40 static char *attr_uidnumber
= NULL
;
41 static char *attr_gidnumber
= NULL
;
43 static ADS_STATUS
ad_idmap_check_attr_mapping(ADS_STRUCT
*ads
)
46 enum wb_posix_mapping map_type
;
48 if (attr_uidnumber
!= NULL
&& attr_gidnumber
!= NULL
) {
49 return ADS_ERROR(LDAP_SUCCESS
);
52 SMB_ASSERT(ads
->server
.workgroup
);
54 map_type
= get_nss_info(ads
->server
.workgroup
);
56 if ((map_type
== WB_POSIX_MAP_SFU
) ||
57 (map_type
== WB_POSIX_MAP_RFC2307
)) {
59 status
= ads_check_posix_schema_mapping(ads
, map_type
);
60 if (ADS_ERR_OK(status
)) {
61 attr_uidnumber
= SMB_STRDUP(ads
->schema
.posix_uidnumber_attr
);
62 attr_gidnumber
= SMB_STRDUP(ads
->schema
.posix_gidnumber_attr
);
63 ADS_ERROR_HAVE_NO_MEMORY(attr_uidnumber
);
64 ADS_ERROR_HAVE_NO_MEMORY(attr_gidnumber
);
65 return ADS_ERROR(LDAP_SUCCESS
);
67 DEBUG(0,("ads_check_posix_schema_mapping failed: %s\n", ads_errstr(status
)));
72 /* fallback to XAD defaults */
73 attr_uidnumber
= SMB_STRDUP("uidNumber");
74 attr_gidnumber
= SMB_STRDUP("gidNumber");
75 ADS_ERROR_HAVE_NO_MEMORY(attr_uidnumber
);
76 ADS_ERROR_HAVE_NO_MEMORY(attr_gidnumber
);
78 return ADS_ERROR(LDAP_SUCCESS
);
81 static ADS_STRUCT
*ad_idmap_cached_connection(void)
87 if (ad_idmap_ads
!= NULL
) {
90 /* check for a valid structure */
92 DEBUG(7, ("Current tickets expire at %d, time is now %d\n",
93 (uint32
) ads
->auth
.expire
, (uint32
) time(NULL
)));
94 if ( ads
->config
.realm
&& (ads
->auth
.expire
> time(NULL
))) {
97 /* we own this ADS_STRUCT so make sure it goes away */
100 ads_kdestroy(WINBIND_CCACHE_NAME
);
106 /* we don't want this to affect the users ccache */
107 setenv("KRB5CCNAME", WINBIND_CCACHE_NAME
, 1);
110 ads
= ads_init(lp_realm(), lp_workgroup(), NULL
);
112 DEBUG(1,("ads_init failed\n"));
116 /* the machine acct password might have change - fetch it every time */
117 SAFE_FREE(ads
->auth
.password
);
118 ads
->auth
.password
= secrets_fetch_machine_password(lp_workgroup(), NULL
, NULL
);
120 SAFE_FREE(ads
->auth
.realm
);
121 ads
->auth
.realm
= SMB_STRDUP(lp_realm());
123 status
= ads_connect(ads
);
124 if (!ADS_ERR_OK(status
)) {
125 DEBUG(1, ("ad_idmap_init: failed to connect to AD\n"));
130 ads
->is_mine
= False
;
132 status
= ad_idmap_check_attr_mapping(ads
);
133 if (!ADS_ERR_OK(status
)) {
134 DEBUG(1, ("ad_idmap_init: failed to check attribute mapping\n"));
142 static NTSTATUS
ad_idmap_init(char *uri
)
144 ad_idmap_uri
= SMB_STRDUP(uri
);
145 if (ad_idmap_uri
== NULL
) {
146 return NT_STATUS_NO_MEMORY
;
152 static NTSTATUS
ad_idmap_get_sid_from_id(DOM_SID
*sid
, unid_t unid
, int id_type
)
155 NTSTATUS status
= NT_STATUS_NONE_MAPPED
;
156 const char *attrs
[] = { "objectSid", NULL
};
165 return NT_STATUS_INVALID_PARAMETER
;
168 ads
= ad_idmap_cached_connection();
170 DEBUG(1, ("ad_idmap_get_id_from_sid ADS uninitialized\n"));
171 return NT_STATUS_NOT_SUPPORTED
;
174 switch (id_type
& ID_TYPEMASK
) {
176 if (asprintf(&expr
, "(&(|(sAMAccountType=%d)(sAMAccountType=%d)(sAMAccountType=%d))(%s=%d))",
177 ATYPE_NORMAL_ACCOUNT
, ATYPE_WORKSTATION_TRUST
, ATYPE_INTERDOMAIN_TRUST
,
178 ads
->schema
.posix_uidnumber_attr
, (int)unid
.uid
) == -1) {
179 return NT_STATUS_NO_MEMORY
;
183 if (asprintf(&expr
, "(&(|(sAMAccountType=%d)(sAMAccountType=%d))(%s=%d))",
184 ATYPE_SECURITY_GLOBAL_GROUP
, ATYPE_SECURITY_LOCAL_GROUP
,
185 ads
->schema
.posix_gidnumber_attr
, (int)unid
.gid
) == -1) {
186 return NT_STATUS_NO_MEMORY
;
190 return NT_STATUS_INVALID_PARAMETER
;
194 rc
= ads_search_retry(ads
, &res
, expr
, attrs
);
196 if (!ADS_ERR_OK(rc
)) {
197 DEBUG(1, ("ad_idmap_get_sid_from_id: ads_search: %s\n", ads_errstr(rc
)));
201 count
= ads_count_replies(ads
, res
);
203 DEBUG(1, ("ad_idmap_get_sid_from_id: ads_count_replies: no results\n"));
205 } else if (count
!= 1) {
206 DEBUG(1, ("ad_idmap_get_sid_from_id: ads_count_replies: incorrect cardinality\n"));
210 msg
= ads_first_entry(ads
, res
);
212 DEBUG(1, ("ad_idmap_get_sid_from_id: ads_first_entry: could not retrieve search result\n"));
216 if (!ads_pull_sid(ads
, msg
, "objectSid", sid
)) {
217 DEBUG(1, ("ad_idmap_get_sid_from_id: ads_pull_sid: could not retrieve SID from entry\n"));
221 status
= NT_STATUS_OK
;
222 DEBUG(1, ("ad_idmap_get_sid_from_id mapped POSIX %s %d to SID [%s]\n",
223 (id_type
== ID_GROUPID
) ? "GID" : "UID", (int)unid
.uid
,
224 sid_to_string(sid_string
, sid
)));
228 ads_msgfree(ads
, res
);
234 static NTSTATUS
ad_idmap_get_id_from_sid(unid_t
*unid
, int *id_type
, const DOM_SID
*sid
)
237 NTSTATUS status
= NT_STATUS_NONE_MAPPED
;
238 const char *attrs
[] = { "sAMAccountType", ADS_ATTR_SFU_UIDNUMBER_OID
,
239 ADS_ATTR_SFU_GIDNUMBER_OID
,
240 ADS_ATTR_RFC2307_UIDNUMBER_OID
,
241 ADS_ATTR_RFC2307_GIDNUMBER_OID
,
253 return NT_STATUS_INVALID_PARAMETER
;
256 ads
= ad_idmap_cached_connection();
258 DEBUG(1, ("ad_idmap_get_id_from_sid ADS uninitialized\n"));
259 return NT_STATUS_NOT_SUPPORTED
;
262 sidstr
= sid_binstring(sid
);
263 if (asprintf(&expr
, "(objectSid=%s)", sidstr
) == -1) {
265 return NT_STATUS_NO_MEMORY
;
268 rc
= ads_search_retry(ads
, &res
, expr
, attrs
);
271 if (!ADS_ERR_OK(rc
)) {
272 DEBUG(1, ("ad_idmap_get_id_from_sid: ads_search: %s\n", ads_errstr(rc
)));
276 count
= ads_count_replies(ads
, res
);
278 DEBUG(1, ("ad_idmap_get_id_from_sid: ads_count_replies: no results\n"));
280 } else if (count
!= 1) {
281 DEBUG(1, ("ad_idmap_get_id_from_sid: ads_count_replies: incorrect cardinality\n"));
285 msg
= ads_first_entry(ads
, res
);
287 DEBUG(1, ("ad_idmap_get_id_from_sid: ads_first_entry: could not retrieve search result\n"));
291 if (!ads_pull_uint32(ads
, msg
, "sAMAccountType", &atype
)) {
292 DEBUG(1, ("ad_idmap_get_id_from_sid: ads_pull_uint32: could not read SAM account type\n"));
296 switch (atype
& 0xF0000000) {
297 case ATYPE_SECURITY_GLOBAL_GROUP
:
298 case ATYPE_SECURITY_LOCAL_GROUP
:
299 *id_type
= ID_GROUPID
;
301 case ATYPE_NORMAL_ACCOUNT
:
302 case ATYPE_WORKSTATION_TRUST
:
303 case ATYPE_INTERDOMAIN_TRUST
:
304 *id_type
= ID_USERID
;
307 DEBUG(1, ("ad_idmap_get_id_from_sid: unrecognized SAM account type %08x\n", atype
));
312 if (!ads_pull_uint32(ads
, msg
, (*id_type
== ID_GROUPID
) ? attr_gidnumber
: attr_uidnumber
, &uid
)) {
313 DEBUG(1, ("ad_idmap_get_id_from_sid: ads_pull_uint32: could not read attribute '%s'\n",
314 (*id_type
== ID_GROUPID
) ? attr_gidnumber
: attr_uidnumber
));
318 unid
->uid
= (uid_t
)uid
;
320 status
= NT_STATUS_OK
;
321 DEBUG(1, ("ad_idmap_get_id_from_sid mapped SID [%s] to POSIX %s %d\n",
322 sid_to_string(sid_string
, sid
),
323 (*id_type
== ID_GROUPID
) ? "GID" : "UID", uid
));
327 ads_msgfree(ads
, res
);
334 static NTSTATUS
ad_idmap_set_mapping(const DOM_SID
*sid
, unid_t id
, int id_type
)
336 /* Not supported, and probably won't be... */
337 /* (It's not particularly feasible with a single-master model.) */
339 return NT_STATUS_NOT_IMPLEMENTED
;
342 static NTSTATUS
ad_idmap_close(void)
344 ADS_STRUCT
*ads
= ad_idmap_ads
;
347 /* we own this ADS_STRUCT so make sure it goes away */
353 SAFE_FREE(attr_uidnumber
);
354 SAFE_FREE(attr_gidnumber
);
359 static NTSTATUS
ad_idmap_allocate_id(unid_t
*id
, int id_type
)
361 return NT_STATUS_NOT_IMPLEMENTED
;
364 static void ad_idmap_status(void)
366 DEBUG(0, ("AD IDMAP Status not available\n"));
369 static struct idmap_methods ad_methods
= {
371 ad_idmap_allocate_id
,
372 ad_idmap_get_sid_from_id
,
373 ad_idmap_get_id_from_sid
,
374 ad_idmap_set_mapping
,
380 /* support for new authentication subsystem */
381 NTSTATUS
init_module(void)
383 return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION
, "ad", &ad_methods
);