• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/samba-3.5.8/source3/winbindd/
1/*
2 *  idmap_ad: map between Active Directory and RFC 2307 or "Services for Unix" (SFU) Accounts
3 *
4 * Unix SMB/CIFS implementation.
5 *
6 * Winbind ADS backend functions
7 *
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
13 *
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.
18 *
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.
23 *
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/>.
26 */
27
28#include "includes.h"
29#include "winbindd.h"
30
31#undef DBGC_CLASS
32#define DBGC_CLASS DBGC_IDMAP
33
34#define WINBIND_CCACHE_NAME "MEMORY:winbind_ccache"
35
36#define IDMAP_AD_MAX_IDS 30
37#define CHECK_ALLOC_DONE(mem) do { \
38     if (!mem) { \
39           DEBUG(0, ("Out of memory!\n")); \
40           ret = NT_STATUS_NO_MEMORY; \
41           goto done; \
42      } \
43} while (0)
44
45struct idmap_ad_context {
46	uint32_t filter_low_id;
47	uint32_t filter_high_id;
48	ADS_STRUCT *ads;
49	struct posix_schema *ad_schema;
50	enum wb_posix_mapping ad_map_type; /* WB_POSIX_MAP_UNKNOWN */
51};
52
53NTSTATUS init_module(void);
54
55/************************************************************************
56 ***********************************************************************/
57
58static ADS_STATUS ad_idmap_cached_connection_internal(struct idmap_domain *dom)
59{
60	ADS_STRUCT *ads;
61	ADS_STATUS status;
62	bool local = False;
63	fstring dc_name;
64	struct sockaddr_storage dc_ip;
65	struct idmap_ad_context *ctx;
66	char *ldap_server = NULL;
67	char *realm = NULL;
68	struct winbindd_domain *wb_dom;
69
70	DEBUG(10, ("ad_idmap_cached_connection: called for domain '%s'\n",
71		   dom->name));
72
73	ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
74
75	if (ctx->ads != NULL) {
76
77		time_t expire;
78		time_t now = time(NULL);
79
80		ads = ctx->ads;
81
82		expire = MIN(ads->auth.tgt_expire, ads->auth.tgs_expire);
83
84		/* check for a valid structure */
85		DEBUG(7, ("Current tickets expire in %d seconds (at %d, time is now %d)\n",
86			  (uint32)expire-(uint32)now, (uint32) expire, (uint32) now));
87
88		if ( ads->config.realm && (expire > time(NULL))) {
89			return ADS_SUCCESS;
90		} else {
91			/* we own this ADS_STRUCT so make sure it goes away */
92			DEBUG(7,("Deleting expired krb5 credential cache\n"));
93			ads->is_mine = True;
94			ads_destroy( &ads );
95			ads_kdestroy(WINBIND_CCACHE_NAME);
96			ctx->ads = NULL;
97			TALLOC_FREE( ctx->ad_schema );
98		}
99	}
100
101	if (!local) {
102		/* we don't want this to affect the users ccache */
103		setenv("KRB5CCNAME", WINBIND_CCACHE_NAME, 1);
104	}
105
106	/*
107	 * At this point we only have the NetBIOS domain name.
108	 * Check if we can get server nam and realm from SAF cache
109	 * and the domain list.
110	 */
111	ldap_server = saf_fetch(dom->name);
112	DEBUG(10, ("ldap_server from saf cache: '%s'\n", ldap_server?ldap_server:""));
113
114	wb_dom = find_domain_from_name_noinit(dom->name);
115	if (wb_dom == NULL) {
116		DEBUG(10, ("find_domain_from_name_noinit did not find domain '%s'\n",
117			   dom->name));
118		realm = NULL;
119	} else {
120		DEBUG(10, ("find_domain_from_name_noinit found realm '%s' for "
121			  " domain '%s'\n", wb_dom->alt_name, dom->name));
122		realm = wb_dom->alt_name;
123	}
124
125	if ( (ads = ads_init(realm, dom->name, ldap_server)) == NULL ) {
126		DEBUG(1,("ads_init failed\n"));
127		return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
128	}
129
130	/* the machine acct password might have change - fetch it every time */
131	SAFE_FREE(ads->auth.password);
132	ads->auth.password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
133
134	SAFE_FREE(ads->auth.realm);
135	ads->auth.realm = SMB_STRDUP(lp_realm());
136
137	/* setup server affinity */
138
139	get_dc_name(dom->name, realm, dc_name, &dc_ip );
140
141	status = ads_connect(ads);
142	if (!ADS_ERR_OK(status)) {
143		DEBUG(1, ("ad_idmap_init: failed to connect to AD\n"));
144		ads_destroy(&ads);
145		return status;
146	}
147
148	ads->is_mine = False;
149
150	ctx->ads = ads;
151
152	return ADS_SUCCESS;
153}
154
155/************************************************************************
156 ***********************************************************************/
157
158static ADS_STATUS ad_idmap_cached_connection(struct idmap_domain *dom)
159{
160	ADS_STATUS status;
161	struct idmap_ad_context * ctx;
162
163	status = ad_idmap_cached_connection_internal(dom);
164	if (!ADS_ERR_OK(status)) {
165		return status;
166	}
167
168	ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
169
170	/* if we have a valid ADS_STRUCT and the schema model is
171	   defined, then we can return here. */
172
173	if ( ctx->ad_schema ) {
174		return ADS_SUCCESS;
175	}
176
177	/* Otherwise, set the schema model */
178
179	if ( (ctx->ad_map_type ==  WB_POSIX_MAP_SFU) ||
180	     (ctx->ad_map_type ==  WB_POSIX_MAP_SFU20) ||
181	     (ctx->ad_map_type ==  WB_POSIX_MAP_RFC2307) )
182	{
183		status = ads_check_posix_schema_mapping(NULL, ctx->ads, ctx->ad_map_type, &ctx->ad_schema);
184		if ( !ADS_ERR_OK(status) ) {
185			DEBUG(2,("ad_idmap_cached_connection: Failed to obtain schema details!\n"));
186		}
187	}
188
189	return status;
190}
191
192/************************************************************************
193 ***********************************************************************/
194
195static NTSTATUS idmap_ad_initialize(struct idmap_domain *dom,
196				    const char *params)
197{
198	struct idmap_ad_context *ctx;
199	char *config_option;
200	const char *range = NULL;
201	const char *schema_mode = NULL;
202
203	if ( (ctx = TALLOC_ZERO_P(dom, struct idmap_ad_context)) == NULL ) {
204		DEBUG(0, ("Out of memory!\n"));
205		return NT_STATUS_NO_MEMORY;
206	}
207
208	if ( (config_option = talloc_asprintf(ctx, "idmap config %s", dom->name)) == NULL ) {
209		DEBUG(0, ("Out of memory!\n"));
210		talloc_free(ctx);
211		return NT_STATUS_NO_MEMORY;
212	}
213
214	/* load ranges */
215	range = lp_parm_const_string(-1, config_option, "range", NULL);
216	if (range && range[0]) {
217		if ((sscanf(range, "%u - %u", &ctx->filter_low_id, &ctx->filter_high_id) != 2) ||
218		    (ctx->filter_low_id > ctx->filter_high_id)) {
219			DEBUG(1, ("ERROR: invalid filter range [%s]", range));
220			ctx->filter_low_id = 0;
221			ctx->filter_high_id = 0;
222		}
223	}
224
225	/* default map type */
226	ctx->ad_map_type = WB_POSIX_MAP_RFC2307;
227
228	/* schema mode */
229	schema_mode = lp_parm_const_string(-1, config_option, "schema_mode", NULL);
230	if ( schema_mode && schema_mode[0] ) {
231		if ( strequal(schema_mode, "sfu") )
232			ctx->ad_map_type = WB_POSIX_MAP_SFU;
233		else if ( strequal(schema_mode, "sfu20" ) )
234			ctx->ad_map_type = WB_POSIX_MAP_SFU20;
235		else if ( strequal(schema_mode, "rfc2307" ) )
236			ctx->ad_map_type = WB_POSIX_MAP_RFC2307;
237		else
238			DEBUG(0,("idmap_ad_initialize: Unknown schema_mode (%s)\n",
239				 schema_mode));
240	}
241
242	dom->private_data = ctx;
243
244	talloc_free(config_option);
245
246	return NT_STATUS_OK;
247}
248
249/************************************************************************
250 Search up to IDMAP_AD_MAX_IDS entries in maps for a match.
251 ***********************************************************************/
252
253static struct id_map *find_map_by_id(struct id_map **maps, enum id_type type, uint32_t id)
254{
255	int i;
256
257	for (i = 0; maps[i] && i<IDMAP_AD_MAX_IDS; i++) {
258		if ((maps[i]->xid.type == type) && (maps[i]->xid.id == id)) {
259			return maps[i];
260		}
261	}
262
263	return NULL;
264}
265
266/************************************************************************
267 Search up to IDMAP_AD_MAX_IDS entries in maps for a match
268 ***********************************************************************/
269
270static struct id_map *find_map_by_sid(struct id_map **maps, DOM_SID *sid)
271{
272	int i;
273
274	for (i = 0; maps[i] && i<IDMAP_AD_MAX_IDS; i++) {
275		if (sid_equal(maps[i]->sid, sid)) {
276			return maps[i];
277		}
278	}
279
280	return NULL;
281}
282
283/************************************************************************
284 ***********************************************************************/
285
286static NTSTATUS idmap_ad_unixids_to_sids(struct idmap_domain *dom, struct id_map **ids)
287{
288	NTSTATUS ret;
289	TALLOC_CTX *memctx;
290	struct idmap_ad_context *ctx;
291	ADS_STATUS rc;
292	const char *attrs[] = { "sAMAccountType",
293				"objectSid",
294				NULL, /* uidnumber */
295				NULL, /* gidnumber */
296				NULL };
297	LDAPMessage *res = NULL;
298	LDAPMessage *entry = NULL;
299	char *filter = NULL;
300	int idx = 0;
301	int bidx = 0;
302	int count;
303	int i;
304	char *u_filter = NULL;
305	char *g_filter = NULL;
306
307	/* initialize the status to avoid suprise */
308	for (i = 0; ids[i]; i++) {
309		ids[i]->status = ID_UNKNOWN;
310	}
311
312	/* Only do query if we are online */
313	if (idmap_is_offline())	{
314		return NT_STATUS_FILE_IS_OFFLINE;
315	}
316
317	ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
318
319	if ( (memctx = talloc_new(ctx)) == NULL ) {
320		DEBUG(0, ("Out of memory!\n"));
321		return NT_STATUS_NO_MEMORY;
322	}
323
324	rc = ad_idmap_cached_connection(dom);
325	if (!ADS_ERR_OK(rc)) {
326		DEBUG(1, ("ADS uninitialized: %s\n", ads_errstr(rc)));
327		ret = NT_STATUS_UNSUCCESSFUL;
328		/* ret = ads_ntstatus(rc); */
329		goto done;
330	}
331
332	attrs[2] = ctx->ad_schema->posix_uidnumber_attr;
333	attrs[3] = ctx->ad_schema->posix_gidnumber_attr;
334
335again:
336	bidx = idx;
337	for (i = 0; (i < IDMAP_AD_MAX_IDS) && ids[idx]; i++, idx++) {
338		switch (ids[idx]->xid.type) {
339		case ID_TYPE_UID:
340			if ( ! u_filter) {
341				u_filter = talloc_asprintf(memctx, "(&(|"
342							   "(sAMAccountType=%d)"
343							   "(sAMAccountType=%d)"
344							   "(sAMAccountType=%d))(|",
345							   ATYPE_NORMAL_ACCOUNT,
346							   ATYPE_WORKSTATION_TRUST,
347							   ATYPE_INTERDOMAIN_TRUST);
348			}
349			u_filter = talloc_asprintf_append_buffer(u_filter, "(%s=%lu)",
350							  ctx->ad_schema->posix_uidnumber_attr,
351							  (unsigned long)ids[idx]->xid.id);
352			CHECK_ALLOC_DONE(u_filter);
353			break;
354
355		case ID_TYPE_GID:
356			if ( ! g_filter) {
357				g_filter = talloc_asprintf(memctx, "(&(|"
358							   "(sAMAccountType=%d)"
359							   "(sAMAccountType=%d))(|",
360							   ATYPE_SECURITY_GLOBAL_GROUP,
361							   ATYPE_SECURITY_LOCAL_GROUP);
362			}
363			g_filter = talloc_asprintf_append_buffer(g_filter, "(%s=%lu)",
364							  ctx->ad_schema->posix_gidnumber_attr,
365							  (unsigned long)ids[idx]->xid.id);
366			CHECK_ALLOC_DONE(g_filter);
367			break;
368
369		default:
370			DEBUG(3, ("Error: mapping requested but Unknown ID type\n"));
371			ids[idx]->status = ID_UNKNOWN;
372			continue;
373		}
374	}
375	filter = talloc_asprintf(memctx, "(|");
376	CHECK_ALLOC_DONE(filter);
377	if ( u_filter) {
378		filter = talloc_asprintf_append_buffer(filter, "%s))", u_filter);
379		CHECK_ALLOC_DONE(filter);
380			TALLOC_FREE(u_filter);
381	}
382	if ( g_filter) {
383		filter = talloc_asprintf_append_buffer(filter, "%s))", g_filter);
384		CHECK_ALLOC_DONE(filter);
385		TALLOC_FREE(g_filter);
386	}
387	filter = talloc_asprintf_append_buffer(filter, ")");
388	CHECK_ALLOC_DONE(filter);
389
390	rc = ads_search_retry(ctx->ads, &res, filter, attrs);
391	if (!ADS_ERR_OK(rc)) {
392		DEBUG(1, ("ERROR: ads search returned: %s\n", ads_errstr(rc)));
393		ret = NT_STATUS_UNSUCCESSFUL;
394		goto done;
395	}
396
397	if ( (count = ads_count_replies(ctx->ads, res)) == 0 ) {
398		DEBUG(10, ("No IDs found\n"));
399	}
400
401	entry = res;
402	for (i = 0; (i < count) && entry; i++) {
403		DOM_SID sid;
404		enum id_type type;
405		struct id_map *map;
406		uint32_t id;
407		uint32_t atype;
408
409		if (i == 0) { /* first entry */
410			entry = ads_first_entry(ctx->ads, entry);
411		} else { /* following ones */
412			entry = ads_next_entry(ctx->ads, entry);
413		}
414
415		if ( !entry ) {
416			DEBUG(2, ("ERROR: Unable to fetch ldap entries from results\n"));
417			break;
418		}
419
420		/* first check if the SID is present */
421		if (!ads_pull_sid(ctx->ads, entry, "objectSid", &sid)) {
422			DEBUG(2, ("Could not retrieve SID from entry\n"));
423			continue;
424		}
425
426		/* get type */
427		if (!ads_pull_uint32(ctx->ads, entry, "sAMAccountType", &atype)) {
428			DEBUG(1, ("could not get SAM account type\n"));
429			continue;
430		}
431
432		switch (atype & 0xF0000000) {
433		case ATYPE_SECURITY_GLOBAL_GROUP:
434		case ATYPE_SECURITY_LOCAL_GROUP:
435			type = ID_TYPE_GID;
436			break;
437		case ATYPE_NORMAL_ACCOUNT:
438		case ATYPE_WORKSTATION_TRUST:
439		case ATYPE_INTERDOMAIN_TRUST:
440			type = ID_TYPE_UID;
441			break;
442		default:
443			DEBUG(1, ("unrecognized SAM account type %08x\n", atype));
444			continue;
445		}
446
447		if (!ads_pull_uint32(ctx->ads, entry, (type==ID_TYPE_UID) ?
448				                 ctx->ad_schema->posix_uidnumber_attr :
449				                 ctx->ad_schema->posix_gidnumber_attr,
450				     &id))
451		{
452			DEBUG(1, ("Could not get unix ID\n"));
453			continue;
454		}
455
456		if ((id == 0) ||
457		    (ctx->filter_low_id && (id < ctx->filter_low_id)) ||
458		    (ctx->filter_high_id && (id > ctx->filter_high_id))) {
459			DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
460				id, ctx->filter_low_id, ctx->filter_high_id));
461			continue;
462		}
463
464		map = find_map_by_id(&ids[bidx], type, id);
465		if (!map) {
466			DEBUG(2, ("WARNING: couldn't match result with requested ID\n"));
467			continue;
468		}
469
470		sid_copy(map->sid, &sid);
471
472		/* mapped */
473		map->status = ID_MAPPED;
474
475		DEBUG(10, ("Mapped %s -> %lu (%d)\n", sid_string_dbg(map->sid),
476			   (unsigned long)map->xid.id,
477			   map->xid.type));
478	}
479
480	if (res) {
481		ads_msgfree(ctx->ads, res);
482	}
483
484	if (ids[idx]) { /* still some values to map */
485		goto again;
486	}
487
488	ret = NT_STATUS_OK;
489
490	/* mark all unknown/expired ones as unmapped */
491	for (i = 0; ids[i]; i++) {
492		if (ids[i]->status != ID_MAPPED)
493			ids[i]->status = ID_UNMAPPED;
494	}
495
496done:
497	talloc_free(memctx);
498	return ret;
499}
500
501/************************************************************************
502 ***********************************************************************/
503
504static NTSTATUS idmap_ad_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids)
505{
506	NTSTATUS ret;
507	TALLOC_CTX *memctx;
508	struct idmap_ad_context *ctx;
509	ADS_STATUS rc;
510	const char *attrs[] = { "sAMAccountType",
511				"objectSid",
512				NULL, /* attr_uidnumber */
513				NULL, /* attr_gidnumber */
514				NULL };
515	LDAPMessage *res = NULL;
516	LDAPMessage *entry = NULL;
517	char *filter = NULL;
518	int idx = 0;
519	int bidx = 0;
520	int count;
521	int i;
522	char *sidstr;
523
524	/* initialize the status to avoid suprise */
525	for (i = 0; ids[i]; i++) {
526		ids[i]->status = ID_UNKNOWN;
527	}
528
529	/* Only do query if we are online */
530	if (idmap_is_offline())	{
531		return NT_STATUS_FILE_IS_OFFLINE;
532	}
533
534	ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
535
536	if ( (memctx = talloc_new(ctx)) == NULL ) {
537		DEBUG(0, ("Out of memory!\n"));
538		return NT_STATUS_NO_MEMORY;
539	}
540
541	rc = ad_idmap_cached_connection(dom);
542	if (!ADS_ERR_OK(rc)) {
543		DEBUG(1, ("ADS uninitialized: %s\n", ads_errstr(rc)));
544		ret = NT_STATUS_UNSUCCESSFUL;
545		/* ret = ads_ntstatus(rc); */
546		goto done;
547	}
548
549	if (ctx->ad_schema == NULL) {
550		DEBUG(0, ("haven't got ctx->ad_schema ! \n"));
551		ret = NT_STATUS_UNSUCCESSFUL;
552		goto done;
553	}
554
555	attrs[2] = ctx->ad_schema->posix_uidnumber_attr;
556	attrs[3] = ctx->ad_schema->posix_gidnumber_attr;
557
558again:
559	filter = talloc_asprintf(memctx, "(&(|"
560				 "(sAMAccountType=%d)(sAMAccountType=%d)(sAMAccountType=%d)" /* user account types */
561				 "(sAMAccountType=%d)(sAMAccountType=%d)" /* group account types */
562				 ")(|",
563				 ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST, ATYPE_INTERDOMAIN_TRUST,
564				 ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_LOCAL_GROUP);
565
566	CHECK_ALLOC_DONE(filter);
567
568	bidx = idx;
569	for (i = 0; (i < IDMAP_AD_MAX_IDS) && ids[idx]; i++, idx++) {
570
571		ids[idx]->status = ID_UNKNOWN;
572
573		sidstr = sid_binstring(talloc_tos(), ids[idx]->sid);
574		filter = talloc_asprintf_append_buffer(filter, "(objectSid=%s)", sidstr);
575
576		TALLOC_FREE(sidstr);
577		CHECK_ALLOC_DONE(filter);
578	}
579	filter = talloc_asprintf_append_buffer(filter, "))");
580	CHECK_ALLOC_DONE(filter);
581	DEBUG(10, ("Filter: [%s]\n", filter));
582
583	rc = ads_search_retry(ctx->ads, &res, filter, attrs);
584	if (!ADS_ERR_OK(rc)) {
585		DEBUG(1, ("ERROR: ads search returned: %s\n", ads_errstr(rc)));
586		ret = NT_STATUS_UNSUCCESSFUL;
587		goto done;
588	}
589
590	if ( (count = ads_count_replies(ctx->ads, res)) == 0 ) {
591		DEBUG(10, ("No IDs found\n"));
592	}
593
594	entry = res;
595	for (i = 0; (i < count) && entry; i++) {
596		DOM_SID sid;
597		enum id_type type;
598		struct id_map *map;
599		uint32_t id;
600		uint32_t atype;
601
602		if (i == 0) { /* first entry */
603			entry = ads_first_entry(ctx->ads, entry);
604		} else { /* following ones */
605			entry = ads_next_entry(ctx->ads, entry);
606		}
607
608		if ( !entry ) {
609			DEBUG(2, ("ERROR: Unable to fetch ldap entries from results\n"));
610			break;
611		}
612
613		/* first check if the SID is present */
614		if (!ads_pull_sid(ctx->ads, entry, "objectSid", &sid)) {
615			DEBUG(2, ("Could not retrieve SID from entry\n"));
616			continue;
617		}
618
619		map = find_map_by_sid(&ids[bidx], &sid);
620		if (!map) {
621			DEBUG(2, ("WARNING: couldn't match result with requested SID\n"));
622			continue;
623		}
624
625		/* get type */
626		if (!ads_pull_uint32(ctx->ads, entry, "sAMAccountType", &atype)) {
627			DEBUG(1, ("could not get SAM account type\n"));
628			continue;
629		}
630
631		switch (atype & 0xF0000000) {
632		case ATYPE_SECURITY_GLOBAL_GROUP:
633		case ATYPE_SECURITY_LOCAL_GROUP:
634			type = ID_TYPE_GID;
635			break;
636		case ATYPE_NORMAL_ACCOUNT:
637		case ATYPE_WORKSTATION_TRUST:
638		case ATYPE_INTERDOMAIN_TRUST:
639			type = ID_TYPE_UID;
640			break;
641		default:
642			DEBUG(1, ("unrecognized SAM account type %08x\n", atype));
643			continue;
644		}
645
646		if (!ads_pull_uint32(ctx->ads, entry, (type==ID_TYPE_UID) ?
647				                 ctx->ad_schema->posix_uidnumber_attr :
648				                 ctx->ad_schema->posix_gidnumber_attr,
649				     &id))
650		{
651			DEBUG(1, ("Could not get unix ID\n"));
652			continue;
653		}
654		if ((id == 0) ||
655		    (ctx->filter_low_id && (id < ctx->filter_low_id)) ||
656		    (ctx->filter_high_id && (id > ctx->filter_high_id))) {
657			DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
658				id, ctx->filter_low_id, ctx->filter_high_id));
659			continue;
660		}
661
662		/* mapped */
663		map->xid.type = type;
664		map->xid.id = id;
665		map->status = ID_MAPPED;
666
667		DEBUG(10, ("Mapped %s -> %lu (%d)\n", sid_string_dbg(map->sid),
668			   (unsigned long)map->xid.id,
669			   map->xid.type));
670	}
671
672	if (res) {
673		ads_msgfree(ctx->ads, res);
674	}
675
676	if (ids[idx]) { /* still some values to map */
677		goto again;
678	}
679
680	ret = NT_STATUS_OK;
681
682	/* mark all unknwoni/expired ones as unmapped */
683	for (i = 0; ids[i]; i++) {
684		if (ids[i]->status != ID_MAPPED)
685			ids[i]->status = ID_UNMAPPED;
686	}
687
688done:
689	talloc_free(memctx);
690	return ret;
691}
692
693/************************************************************************
694 ***********************************************************************/
695
696static NTSTATUS idmap_ad_close(struct idmap_domain *dom)
697{
698	struct idmap_ad_context * ctx;
699
700	ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
701
702	if (ctx->ads != NULL) {
703		/* we own this ADS_STRUCT so make sure it goes away */
704		ctx->ads->is_mine = True;
705		ads_destroy( &ctx->ads );
706		ctx->ads = NULL;
707	}
708
709	TALLOC_FREE( ctx->ad_schema );
710
711	return NT_STATUS_OK;
712}
713
714/*
715 * nss_info_{sfu,sfu20,rfc2307}
716 */
717
718/************************************************************************
719 Initialize the {sfu,sfu20,rfc2307} state
720 ***********************************************************************/
721
722static const char *wb_posix_map_unknown_string = "WB_POSIX_MAP_UNKNOWN";
723static const char *wb_posix_map_template_string = "WB_POSIX_MAP_TEMPLATE";
724static const char *wb_posix_map_sfu_string = "WB_POSIX_MAP_SFU";
725static const char *wb_posix_map_sfu20_string = "WB_POSIX_MAP_SFU20";
726static const char *wb_posix_map_rfc2307_string = "WB_POSIX_MAP_RFC2307";
727static const char *wb_posix_map_unixinfo_string = "WB_POSIX_MAP_UNIXINFO";
728
729static const char *ad_map_type_string(enum wb_posix_mapping map_type)
730{
731	switch (map_type) {
732		case WB_POSIX_MAP_TEMPLATE:
733			return wb_posix_map_template_string;
734		case WB_POSIX_MAP_SFU:
735			return wb_posix_map_sfu_string;
736		case WB_POSIX_MAP_SFU20:
737			return wb_posix_map_sfu20_string;
738		case WB_POSIX_MAP_RFC2307:
739			return wb_posix_map_rfc2307_string;
740		case WB_POSIX_MAP_UNIXINFO:
741			return wb_posix_map_unixinfo_string;
742		default:
743			return wb_posix_map_unknown_string;
744	}
745}
746
747static NTSTATUS nss_ad_generic_init(struct nss_domain_entry *e,
748				    enum wb_posix_mapping new_ad_map_type)
749{
750	struct idmap_domain *dom;
751	struct idmap_ad_context *ctx;
752
753	if (e->state != NULL) {
754		dom = talloc_get_type(e->state, struct idmap_domain);
755	} else {
756		dom = TALLOC_ZERO_P(e, struct idmap_domain);
757		if (dom == NULL) {
758			DEBUG(0, ("Out of memory!\n"));
759			return NT_STATUS_NO_MEMORY;
760		}
761		e->state = dom;
762	}
763
764	if (e->domain != NULL) {
765		dom->name = talloc_strdup(dom, e->domain);
766		if (dom->name == NULL) {
767			DEBUG(0, ("Out of memory!\n"));
768			return NT_STATUS_NO_MEMORY;
769		}
770	}
771
772	if (dom->private_data != NULL) {
773		ctx = talloc_get_type(dom->private_data,
774				      struct idmap_ad_context);
775	} else {
776		ctx = TALLOC_ZERO_P(dom, struct idmap_ad_context);
777		if (ctx == NULL) {
778			DEBUG(0, ("Out of memory!\n"));
779			return NT_STATUS_NO_MEMORY;
780		}
781		ctx->ad_map_type = WB_POSIX_MAP_RFC2307;
782		dom->private_data = ctx;
783	}
784
785	if ((ctx->ad_map_type != WB_POSIX_MAP_UNKNOWN) &&
786	    (ctx->ad_map_type != new_ad_map_type))
787	{
788		DEBUG(2, ("nss_ad_generic_init: "
789			  "Warning: overriding previously set posix map type "
790			  "%s for domain %s with map type %s.\n",
791			  ad_map_type_string(ctx->ad_map_type),
792			  dom->name,
793			  ad_map_type_string(new_ad_map_type)));
794	}
795
796	ctx->ad_map_type = new_ad_map_type;
797
798	return NT_STATUS_OK;
799}
800
801static NTSTATUS nss_sfu_init( struct nss_domain_entry *e )
802{
803	return nss_ad_generic_init(e, WB_POSIX_MAP_SFU);
804}
805
806static NTSTATUS nss_sfu20_init( struct nss_domain_entry *e )
807{
808	return nss_ad_generic_init(e, WB_POSIX_MAP_SFU20);
809}
810
811static NTSTATUS nss_rfc2307_init( struct nss_domain_entry *e )
812{
813	return nss_ad_generic_init(e, WB_POSIX_MAP_RFC2307);
814}
815
816
817/************************************************************************
818 ***********************************************************************/
819
820static NTSTATUS nss_ad_get_info( struct nss_domain_entry *e,
821				  const DOM_SID *sid,
822				  TALLOC_CTX *mem_ctx,
823				  ADS_STRUCT *ads,
824				  LDAPMessage *msg,
825				  const char **homedir,
826				  const char **shell,
827				  const char **gecos,
828				  uint32 *gid )
829{
830	const char *attrs[] = {NULL, /* attr_homedir */
831			       NULL, /* attr_shell */
832			       NULL, /* attr_gecos */
833			       NULL, /* attr_gidnumber */
834			       NULL };
835	char *filter = NULL;
836	LDAPMessage *msg_internal = NULL;
837	ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
838	NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
839	char *sidstr = NULL;
840	struct idmap_domain *dom;
841	struct idmap_ad_context *ctx;
842
843	DEBUG(10, ("nss_ad_get_info called for sid [%s] in domain '%s'\n",
844		   sid_string_dbg(sid), e->domain?e->domain:"NULL"));
845
846	/* Only do query if we are online */
847	if (idmap_is_offline())	{
848		return NT_STATUS_FILE_IS_OFFLINE;
849	}
850
851	dom = talloc_get_type(e->state, struct idmap_domain);
852	ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
853
854	ads_status = ad_idmap_cached_connection(dom);
855	if (!ADS_ERR_OK(ads_status)) {
856		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
857	}
858
859	if (!ctx->ad_schema) {
860		DEBUG(10, ("nss_ad_get_info: no ad_schema configured!\n"));
861		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
862	}
863
864	if (!sid || !homedir || !shell || !gecos) {
865		return NT_STATUS_INVALID_PARAMETER;
866	}
867
868	/* See if we can use the ADS connection struct swe were given */
869
870	if (ads) {
871		DEBUG(10, ("nss_ad_get_info: using given ads connection and "
872			   "LDAP message (%p)\n", msg));
873
874		*homedir = ads_pull_string( ads, mem_ctx, msg, ctx->ad_schema->posix_homedir_attr );
875		*shell   = ads_pull_string( ads, mem_ctx, msg, ctx->ad_schema->posix_shell_attr );
876		*gecos   = ads_pull_string( ads, mem_ctx, msg, ctx->ad_schema->posix_gecos_attr );
877
878		if (gid) {
879			if ( !ads_pull_uint32(ads, msg, ctx->ad_schema->posix_gidnumber_attr, gid ) )
880				*gid = (uint32)-1;
881		}
882
883		nt_status = NT_STATUS_OK;
884		goto done;
885	}
886
887	/* Have to do our own query */
888
889	DEBUG(10, ("nss_ad_get_info: no ads connection given, doing our "
890		   "own query\n"));
891
892	attrs[0] = ctx->ad_schema->posix_homedir_attr;
893	attrs[1] = ctx->ad_schema->posix_shell_attr;
894	attrs[2] = ctx->ad_schema->posix_gecos_attr;
895	attrs[3] = ctx->ad_schema->posix_gidnumber_attr;
896
897	sidstr = sid_binstring(mem_ctx, sid);
898	filter = talloc_asprintf(mem_ctx, "(objectSid=%s)", sidstr);
899	TALLOC_FREE(sidstr);
900
901	if (!filter) {
902		nt_status = NT_STATUS_NO_MEMORY;
903		goto done;
904	}
905
906	ads_status = ads_search_retry(ctx->ads, &msg_internal, filter, attrs);
907	if (!ADS_ERR_OK(ads_status)) {
908		nt_status = ads_ntstatus(ads_status);
909		goto done;
910	}
911
912	*homedir = ads_pull_string(ctx->ads, mem_ctx, msg_internal, ctx->ad_schema->posix_homedir_attr);
913	*shell   = ads_pull_string(ctx->ads, mem_ctx, msg_internal, ctx->ad_schema->posix_shell_attr);
914	*gecos   = ads_pull_string(ctx->ads, mem_ctx, msg_internal, ctx->ad_schema->posix_gecos_attr);
915
916	if (gid) {
917		if (!ads_pull_uint32(ctx->ads, msg_internal, ctx->ad_schema->posix_gidnumber_attr, gid))
918			*gid = (uint32)-1;
919	}
920
921	nt_status = NT_STATUS_OK;
922
923done:
924	if (msg_internal) {
925		ads_msgfree(ctx->ads, msg_internal);
926	}
927
928	return nt_status;
929}
930
931/**********************************************************************
932 *********************************************************************/
933
934static NTSTATUS nss_ad_map_to_alias(TALLOC_CTX *mem_ctx,
935				    struct nss_domain_entry *e,
936				    const char *name,
937				    char **alias)
938{
939	const char *attrs[] = {NULL, /* attr_uid */
940			       NULL };
941	char *filter = NULL;
942	LDAPMessage *msg = NULL;
943	ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
944	NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
945	struct idmap_domain *dom;
946	struct idmap_ad_context *ctx = NULL;
947
948	/* Check incoming parameters */
949
950	if ( !e || !e->domain || !name || !*alias) {
951		nt_status = NT_STATUS_INVALID_PARAMETER;
952		goto done;
953	}
954
955	/* Only do query if we are online */
956
957	if (idmap_is_offline())	{
958		nt_status = NT_STATUS_FILE_IS_OFFLINE;
959		goto done;
960	}
961
962	dom = talloc_get_type(e->state, struct idmap_domain);
963	ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
964
965	ads_status = ad_idmap_cached_connection(dom);
966	if (!ADS_ERR_OK(ads_status)) {
967		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
968	}
969
970	if (!ctx->ad_schema) {
971		nt_status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
972		goto done;
973	}
974
975	attrs[0] = ctx->ad_schema->posix_uid_attr;
976
977	filter = talloc_asprintf(mem_ctx,
978				 "(sAMAccountName=%s)",
979				 name);
980	if (!filter) {
981		nt_status = NT_STATUS_NO_MEMORY;
982		goto done;
983	}
984
985	ads_status = ads_search_retry(ctx->ads, &msg, filter, attrs);
986	if (!ADS_ERR_OK(ads_status)) {
987		nt_status = ads_ntstatus(ads_status);
988		goto done;
989	}
990
991	*alias = ads_pull_string(ctx->ads, mem_ctx, msg, ctx->ad_schema->posix_uid_attr);
992
993	if (!*alias) {
994		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
995	}
996
997	nt_status = NT_STATUS_OK;
998
999done:
1000	if (filter) {
1001		talloc_destroy(filter);
1002	}
1003	if (msg) {
1004		ads_msgfree(ctx->ads, msg);
1005	}
1006
1007	return nt_status;
1008}
1009
1010/**********************************************************************
1011 *********************************************************************/
1012
1013static NTSTATUS nss_ad_map_from_alias( TALLOC_CTX *mem_ctx,
1014					     struct nss_domain_entry *e,
1015					     const char *alias,
1016					     char **name )
1017{
1018	const char *attrs[] = {"sAMAccountName",
1019			       NULL };
1020	char *filter = NULL;
1021	LDAPMessage *msg = NULL;
1022	ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
1023	NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
1024	char *username;
1025	struct idmap_domain *dom;
1026	struct idmap_ad_context *ctx = NULL;
1027
1028	/* Check incoming parameters */
1029
1030	if ( !alias || !name) {
1031		nt_status = NT_STATUS_INVALID_PARAMETER;
1032		goto done;
1033	}
1034
1035	/* Only do query if we are online */
1036
1037	if (idmap_is_offline())	{
1038		nt_status = NT_STATUS_FILE_IS_OFFLINE;
1039		goto done;
1040	}
1041
1042	dom = talloc_get_type(e->state, struct idmap_domain);
1043	ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
1044
1045	ads_status = ad_idmap_cached_connection(dom);
1046	if (!ADS_ERR_OK(ads_status)) {
1047		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1048	}
1049
1050	if (!ctx->ad_schema) {
1051		nt_status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
1052		goto done;
1053	}
1054
1055	filter = talloc_asprintf(mem_ctx,
1056				 "(%s=%s)",
1057				 ctx->ad_schema->posix_uid_attr,
1058				 alias);
1059	if (!filter) {
1060		nt_status = NT_STATUS_NO_MEMORY;
1061		goto done;
1062	}
1063
1064	ads_status = ads_search_retry(ctx->ads, &msg, filter, attrs);
1065	if (!ADS_ERR_OK(ads_status)) {
1066		nt_status = ads_ntstatus(ads_status);
1067		goto done;
1068	}
1069
1070	username = ads_pull_string(ctx->ads, mem_ctx, msg,
1071				   "sAMAccountName");
1072	if (!username) {
1073		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1074	}
1075
1076	*name = talloc_asprintf(mem_ctx, "%s\\%s",
1077				lp_workgroup(),
1078				username);
1079	if (!*name) {
1080		nt_status = NT_STATUS_NO_MEMORY;
1081		goto done;
1082	}
1083
1084	nt_status = NT_STATUS_OK;
1085
1086done:
1087	if (filter) {
1088		talloc_destroy(filter);
1089	}
1090	if (msg) {
1091		ads_msgfree(ctx->ads, msg);
1092	}
1093
1094	return nt_status;
1095}
1096
1097
1098/************************************************************************
1099 ***********************************************************************/
1100
1101static NTSTATUS nss_ad_close( void )
1102{
1103	/* nothing to do.  All memory is free()'d by the idmap close_fn() */
1104
1105	return NT_STATUS_OK;
1106}
1107
1108/************************************************************************
1109 Function dispatch tables for the idmap and nss plugins
1110 ***********************************************************************/
1111
1112static struct idmap_methods ad_methods = {
1113	.init            = idmap_ad_initialize,
1114	.unixids_to_sids = idmap_ad_unixids_to_sids,
1115	.sids_to_unixids = idmap_ad_sids_to_unixids,
1116	.close_fn        = idmap_ad_close
1117};
1118
1119/* The SFU and RFC2307 NSS plugins share everything but the init
1120   function which sets the intended schema model to use */
1121
1122static struct nss_info_methods nss_rfc2307_methods = {
1123	.init           = nss_rfc2307_init,
1124	.get_nss_info   = nss_ad_get_info,
1125	.map_to_alias   = nss_ad_map_to_alias,
1126	.map_from_alias = nss_ad_map_from_alias,
1127	.close_fn       = nss_ad_close
1128};
1129
1130static struct nss_info_methods nss_sfu_methods = {
1131	.init           = nss_sfu_init,
1132	.get_nss_info   = nss_ad_get_info,
1133	.map_to_alias   = nss_ad_map_to_alias,
1134	.map_from_alias = nss_ad_map_from_alias,
1135	.close_fn       = nss_ad_close
1136};
1137
1138static struct nss_info_methods nss_sfu20_methods = {
1139	.init           = nss_sfu20_init,
1140	.get_nss_info   = nss_ad_get_info,
1141	.map_to_alias   = nss_ad_map_to_alias,
1142	.map_from_alias = nss_ad_map_from_alias,
1143	.close_fn       = nss_ad_close
1144};
1145
1146
1147
1148/************************************************************************
1149 Initialize the plugins
1150 ***********************************************************************/
1151
1152NTSTATUS idmap_ad_init(void)
1153{
1154	static NTSTATUS status_idmap_ad = NT_STATUS_UNSUCCESSFUL;
1155	static NTSTATUS status_nss_rfc2307 = NT_STATUS_UNSUCCESSFUL;
1156	static NTSTATUS status_nss_sfu = NT_STATUS_UNSUCCESSFUL;
1157	static NTSTATUS status_nss_sfu20 = NT_STATUS_UNSUCCESSFUL;
1158
1159	/* Always register the AD method first in order to get the
1160	   idmap_domain interface called */
1161
1162	if ( !NT_STATUS_IS_OK(status_idmap_ad) ) {
1163		status_idmap_ad = smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION,
1164						     "ad", &ad_methods);
1165		if ( !NT_STATUS_IS_OK(status_idmap_ad) )
1166			return status_idmap_ad;
1167	}
1168
1169	if ( !NT_STATUS_IS_OK( status_nss_rfc2307 ) ) {
1170		status_nss_rfc2307 = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
1171							    "rfc2307",  &nss_rfc2307_methods );
1172		if ( !NT_STATUS_IS_OK(status_nss_rfc2307) )
1173			return status_nss_rfc2307;
1174	}
1175
1176	if ( !NT_STATUS_IS_OK( status_nss_sfu ) ) {
1177		status_nss_sfu = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
1178							"sfu",  &nss_sfu_methods );
1179		if ( !NT_STATUS_IS_OK(status_nss_sfu) )
1180			return status_nss_sfu;
1181	}
1182
1183	if ( !NT_STATUS_IS_OK( status_nss_sfu20 ) ) {
1184		status_nss_sfu20 = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
1185							"sfu20",  &nss_sfu20_methods );
1186		if ( !NT_STATUS_IS_OK(status_nss_sfu20) )
1187			return status_nss_sfu20;
1188	}
1189
1190	return NT_STATUS_OK;
1191}
1192
1193