1/*
2   Unix SMB/CIFS implementation.
3
4   idmap LDAP backend
5
6   Copyright (C) Tim Potter 		2000
7   Copyright (C) Jim McDonough <jmcd@us.ibm.com>	2003
8   Copyright (C) Simo Sorce 		2003
9   Copyright (C) Gerald Carter 		2003
10
11   This program is free software; you can redistribute it and/or modify
12   it under the terms of the GNU General Public License as published by
13   the Free Software Foundation; either version 2 of the License, or
14   (at your option) any later version.
15
16   This program is distributed in the hope that it will be useful,
17   but WITHOUT ANY WARRANTY; without even the implied warranty of
18   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19   GNU General Public License for more details.
20
21   You should have received a copy of the GNU General Public License
22   along with this program; if not, write to the Free Software
23   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24*/
25
26#include "includes.h"
27
28#undef DBGC_CLASS
29#define DBGC_CLASS DBGC_IDMAP
30
31
32#include <lber.h>
33#include <ldap.h>
34
35#include "smbldap.h"
36
37struct ldap_idmap_state {
38	struct smbldap_state *smbldap_state;
39	TALLOC_CTX *mem_ctx;
40};
41
42static struct ldap_idmap_state ldap_state;
43
44/* number tries while allocating new id */
45#define LDAP_MAX_ALLOC_ID 128
46
47
48/***********************************************************************
49 This function cannot be called to modify a mapping, only set a new one
50***********************************************************************/
51
52static NTSTATUS ldap_set_mapping(const DOM_SID *sid, unid_t id, int id_type)
53{
54	pstring dn;
55	pstring id_str;
56	fstring type;
57	LDAPMod **mods = NULL;
58	int rc = -1;
59	int ldap_op;
60	fstring sid_string;
61	LDAPMessage *entry = NULL;
62
63	sid_to_string( sid_string, sid );
64
65	ldap_op = LDAP_MOD_ADD;
66	pstr_sprintf(dn, "%s=%s,%s", get_attr_key2string( sidmap_attr_list, LDAP_ATTR_SID),
67		 sid_string, lp_ldap_idmap_suffix());
68
69	if ( id_type & ID_USERID )
70		fstrcpy( type, get_attr_key2string( sidmap_attr_list, LDAP_ATTR_UIDNUMBER ) );
71	else
72		fstrcpy( type, get_attr_key2string( sidmap_attr_list, LDAP_ATTR_GIDNUMBER ) );
73
74	pstr_sprintf(id_str, "%d", ((id_type & ID_USERID) ? id.uid : id.gid));
75
76	smbldap_set_mod( &mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_IDMAP_ENTRY );
77
78	smbldap_make_mod( ldap_state.smbldap_state->ldap_struct,
79			  entry, &mods, type, id_str );
80
81	smbldap_make_mod( ldap_state.smbldap_state->ldap_struct,
82			  entry, &mods,
83			  get_attr_key2string(sidmap_attr_list, LDAP_ATTR_SID),
84			  sid_string );
85
86	/* There may well be nothing at all to do */
87
88	if (mods) {
89		smbldap_set_mod( &mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_SID_ENTRY );
90		rc = smbldap_add(ldap_state.smbldap_state, dn, mods);
91		ldap_mods_free( mods, True );
92	} else {
93		rc = LDAP_SUCCESS;
94	}
95
96	if (rc != LDAP_SUCCESS) {
97		char *ld_error = NULL;
98		ldap_get_option(ldap_state.smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
99				&ld_error);
100		DEBUG(0,("ldap_set_mapping_internals: Failed to %s mapping from %s to %lu [%s]\n",
101			 (ldap_op == LDAP_MOD_ADD) ? "add" : "replace",
102			 sid_string, (unsigned long)((id_type & ID_USERID) ? id.uid : id.gid), type));
103		DEBUG(0, ("ldap_set_mapping_internals: Error was: %s (%s)\n",
104			ld_error ? ld_error : "(NULL)", ldap_err2string (rc)));
105		return NT_STATUS_UNSUCCESSFUL;
106	}
107
108	DEBUG(10,("ldap_set_mapping: Successfully created mapping from %s to %lu [%s]\n",
109		sid_string, ((id_type & ID_USERID) ? (unsigned long)id.uid :
110			     (unsigned long)id.gid), type));
111
112	return NT_STATUS_OK;
113}
114
115/**********************************************************************
116 Even if the sambaDomain attribute in LDAP tells us that this RID is
117 safe to use, always check before use.
118*********************************************************************/
119
120static BOOL sid_in_use(struct ldap_idmap_state *state,
121		       const DOM_SID *sid, int *error)
122{
123	fstring filter;
124	fstring sid_string;
125	LDAPMessage *result = NULL;
126	int rc;
127	const char *sid_attr[] = {LDAP_ATTRIBUTE_SID, NULL};
128
129	slprintf(filter, sizeof(filter)-1, "(%s=%s)", LDAP_ATTRIBUTE_SID, sid_to_string(sid_string, sid));
130
131	rc = smbldap_search_suffix(state->smbldap_state,
132				   filter, sid_attr, &result);
133
134	if (rc != LDAP_SUCCESS)	{
135		char *ld_error = NULL;
136		ldap_get_option(state->smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error);
137		DEBUG(2, ("Failed to check if sid %s is alredy in use: %s\n",
138			  sid_string, ld_error));
139		SAFE_FREE(ld_error);
140
141		*error = rc;
142		return True;
143	}
144
145	if ((ldap_count_entries(state->smbldap_state->ldap_struct, result)) > 0) {
146		DEBUG(3, ("Sid %s already in use - trying next RID\n",
147			  sid_string));
148		ldap_msgfree(result);
149		return True;
150	}
151
152	ldap_msgfree(result);
153
154	/* good, sid is not in use */
155	return False;
156}
157
158/**********************************************************************
159 Set the new nextRid attribute, and return one we can use.
160
161 This also checks that this RID is actually free - in case the admin
162 manually stole it :-).
163*********************************************************************/
164
165static NTSTATUS ldap_next_rid(struct ldap_idmap_state *state, uint32 *rid,
166                              int rid_type)
167{
168	NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
169	LDAPMessage *domain_result = NULL;
170	LDAPMessage *entry  = NULL;
171	char *dn;
172	LDAPMod **mods = NULL;
173	fstring old_rid_string;
174	fstring next_rid_string;
175	fstring algorithmic_rid_base_string;
176	uint32 next_rid;
177	uint32 alg_rid_base;
178	int attempts = 0;
179	char *ld_error = NULL;
180
181	while (attempts < 10) {
182		if (!NT_STATUS_IS_OK(ret = smbldap_search_domain_info(state->smbldap_state,
183				&domain_result, get_global_sam_name(), True))) {
184			return ret;
185		}
186
187		entry = ldap_first_entry(state->smbldap_state->ldap_struct, domain_result);
188		if (!entry) {
189			DEBUG(0, ("Could not get domain info entry\n"));
190			ldap_msgfree(domain_result);
191			return ret;
192		}
193
194		if ((dn = smbldap_get_dn(state->smbldap_state->ldap_struct, entry)) == NULL) {
195			DEBUG(0, ("Could not get domain info DN\n"));
196			ldap_msgfree(domain_result);
197			return ret;
198		}
199
200		/* yes, we keep 3 seperate counters, one for rids between 1000 (BASE_RID) and
201		   algorithmic_rid_base.  The other two are to avoid stomping on the
202		   different sets of algorithmic RIDs */
203
204		if (smbldap_get_single_pstring(state->smbldap_state->ldap_struct, entry,
205					 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_ALGORITHMIC_RID_BASE),
206					 algorithmic_rid_base_string)) {
207
208			alg_rid_base = (uint32)atol(algorithmic_rid_base_string);
209		} else {
210			alg_rid_base = algorithmic_rid_base();
211			/* Try to make the modification atomically by enforcing the
212			   old value in the delete mod. */
213			slprintf(algorithmic_rid_base_string, sizeof(algorithmic_rid_base_string)-1, "%d", alg_rid_base);
214			smbldap_make_mod(state->smbldap_state->ldap_struct, entry, &mods,
215					 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_ALGORITHMIC_RID_BASE),
216					 algorithmic_rid_base_string);
217		}
218
219		next_rid = 0;
220
221		if (alg_rid_base > BASE_RID) {
222			/* we have a non-default 'algorithmic rid base', so we have 'low' rids that we
223			   can allocate to new users */
224			if (smbldap_get_single_pstring(state->smbldap_state->ldap_struct, entry,
225						 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_RID),
226						 old_rid_string)) {
227				*rid = (uint32)atol(old_rid_string);
228			} else {
229				*rid = BASE_RID;
230			}
231
232			next_rid = *rid+1;
233			if (next_rid >= alg_rid_base) {
234				ldap_msgfree(domain_result);
235				return NT_STATUS_UNSUCCESSFUL;
236			}
237
238			slprintf(next_rid_string, sizeof(next_rid_string)-1, "%d", next_rid);
239
240			/* Try to make the modification atomically by enforcing the
241			   old value in the delete mod. */
242			smbldap_make_mod(state->smbldap_state->ldap_struct, entry, &mods,
243					 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_RID),
244					 next_rid_string);
245		}
246
247		if (!next_rid) { /* not got one already */
248			switch (rid_type) {
249			case USER_RID_TYPE:
250				if (smbldap_get_single_pstring(state->smbldap_state->ldap_struct, entry,
251							 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_USERRID),
252							 old_rid_string)) {
253					*rid = (uint32)atol(old_rid_string);
254				}
255				break;
256			case GROUP_RID_TYPE:
257				if (smbldap_get_single_pstring(state->smbldap_state->ldap_struct, entry,
258							 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_GROUPRID),
259							 old_rid_string)) {
260					*rid = (uint32)atol(old_rid_string);
261				}
262				break;
263			}
264
265			/* This is the core of the whole routine. If we had
266			   scheme-style closures, there would be a *lot* less code
267			   duplication... */
268
269			next_rid = *rid+RID_MULTIPLIER;
270			slprintf(next_rid_string, sizeof(next_rid_string)-1, "%d", next_rid);
271
272			switch (rid_type) {
273			case USER_RID_TYPE:
274				/* Try to make the modification atomically by enforcing the
275				   old value in the delete mod. */
276				smbldap_make_mod(state->smbldap_state->ldap_struct, entry, &mods,
277						 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_USERRID),
278						 next_rid_string);
279				break;
280
281			case GROUP_RID_TYPE:
282				/* Try to make the modification atomically by enforcing the
283				   old value in the delete mod. */
284				smbldap_make_mod(state->smbldap_state->ldap_struct, entry, &mods,
285						 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_GROUPRID),
286						 next_rid_string);
287				break;
288			}
289		}
290
291		if ((smbldap_modify(state->smbldap_state, dn, mods)) == LDAP_SUCCESS) {
292			DOM_SID dom_sid;
293			DOM_SID sid;
294			pstring domain_sid_string;
295			int error = 0;
296
297			if (!smbldap_get_single_pstring(state->smbldap_state->ldap_struct, domain_result,
298					get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOM_SID),
299					domain_sid_string)) {
300				ldap_mods_free(mods, True);
301				SAFE_FREE(dn);
302				ldap_msgfree(domain_result);
303				return ret;
304			}
305
306			if (!string_to_sid(&dom_sid, domain_sid_string)) {
307				ldap_mods_free(mods, True);
308				SAFE_FREE(dn);
309				ldap_msgfree(domain_result);
310				return ret;
311			}
312
313			ldap_mods_free(mods, True);
314			mods = NULL;
315			SAFE_FREE(dn);
316			ldap_msgfree(domain_result);
317
318			sid_copy(&sid, &dom_sid);
319			sid_append_rid(&sid, *rid);
320
321			/* check RID is not in use */
322			if (sid_in_use(state, &sid, &error)) {
323				if (error) {
324					return ret;
325				}
326				continue;
327			}
328
329			return NT_STATUS_OK;
330		}
331
332		ld_error = NULL;
333		ldap_get_option(state->smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error);
334		DEBUG(2, ("Failed to modify rid: %s\n", ld_error ? ld_error : "(NULL"));
335		SAFE_FREE(ld_error);
336
337		ldap_mods_free(mods, True);
338		mods = NULL;
339
340		SAFE_FREE(dn);
341
342		ldap_msgfree(domain_result);
343		domain_result = NULL;
344
345		{
346			/* Sleep for a random timeout */
347			unsigned sleeptime = (sys_random()*sys_getpid()*attempts);
348			attempts += 1;
349
350			sleeptime %= 100;
351			smb_msleep(sleeptime);
352		}
353	}
354
355	DEBUG(0, ("Failed to set new RID\n"));
356	return ret;
357}
358
359
360/*****************************************************************************
361 Allocate a new RID
362*****************************************************************************/
363
364static NTSTATUS ldap_allocate_rid(uint32 *rid, int rid_type)
365{
366	return ldap_next_rid( &ldap_state, rid, rid_type );
367}
368
369/*****************************************************************************
370 Allocate a new uid or gid
371*****************************************************************************/
372
373static NTSTATUS ldap_allocate_id(unid_t *id, int id_type)
374{
375	NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
376	int rc = LDAP_SERVER_DOWN;
377	int count = 0;
378	LDAPMessage *result = NULL;
379	LDAPMessage *entry = NULL;
380	pstring id_str, new_id_str;
381	LDAPMod **mods = NULL;
382	const char *type;
383	char *dn = NULL;
384	const char **attr_list;
385	pstring filter;
386	uid_t	luid, huid;
387	gid_t	lgid, hgid;
388
389
390	type = (id_type & ID_USERID) ?
391		get_attr_key2string( idpool_attr_list, LDAP_ATTR_UIDNUMBER ) :
392		get_attr_key2string( idpool_attr_list, LDAP_ATTR_GIDNUMBER );
393
394	pstr_sprintf(filter, "(objectClass=%s)", LDAP_OBJ_IDPOOL);
395
396	attr_list = get_attr_list( idpool_attr_list );
397
398	rc = smbldap_search(ldap_state.smbldap_state, lp_ldap_idmap_suffix(),
399			       LDAP_SCOPE_SUBTREE, filter,
400			       attr_list, 0, &result);
401	free_attr_list( attr_list );
402
403	if (rc != LDAP_SUCCESS) {
404		DEBUG(0,("ldap_allocate_id: %s object not found\n", LDAP_OBJ_IDPOOL));
405		goto out;
406	}
407
408	count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
409	if (count != 1) {
410		DEBUG(0,("ldap_allocate_id: single %s object not found\n", LDAP_OBJ_IDPOOL));
411		goto out;
412	}
413
414	dn = smbldap_get_dn(ldap_state.smbldap_state->ldap_struct, result);
415	if (!dn) {
416		goto out;
417	}
418	entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
419
420	if (!smbldap_get_single_pstring(ldap_state.smbldap_state->ldap_struct, entry, type, id_str)) {
421		DEBUG(0,("ldap_allocate_id: %s attribute not found\n",
422			 type));
423		goto out;
424	}
425
426	/* this must succeed or else we wouldn't have initialized */
427
428	lp_idmap_uid( &luid, &huid);
429	lp_idmap_gid( &lgid, &hgid);
430
431	/* make sure we still have room to grow */
432
433	if (id_type & ID_USERID) {
434		id->uid = strtoul(id_str, NULL, 10);
435		if (id->uid > huid ) {
436			DEBUG(0,("ldap_allocate_id: Cannot allocate uid above %lu!\n",
437				 (unsigned long)huid));
438			goto out;
439		}
440	}
441	else {
442		id->gid = strtoul(id_str, NULL, 10);
443		if (id->gid > hgid ) {
444			DEBUG(0,("ldap_allocate_id: Cannot allocate gid above %lu!\n",
445				 (unsigned long)hgid));
446			goto out;
447		}
448	}
449
450	pstr_sprintf(new_id_str, "%lu",
451		 ((id_type & ID_USERID) ? (unsigned long)id->uid :
452		  (unsigned long)id->gid) + 1);
453
454	smbldap_set_mod( &mods, LDAP_MOD_DELETE, type, id_str );
455	smbldap_set_mod( &mods, LDAP_MOD_ADD, type, new_id_str );
456
457	if (mods == NULL) {
458		DEBUG(0,("ldap_allocate_id: smbldap_set_mod() failed.\n"));
459		goto out;
460	}
461
462	rc = smbldap_modify(ldap_state.smbldap_state, dn, mods);
463
464	ldap_mods_free( mods, True );
465	if (rc != LDAP_SUCCESS) {
466		DEBUG(1,("ldap_allocate_id: Failed to allocate new %s.  ldap_modify() failed.\n",
467			type));
468		goto out;
469	}
470
471	ret = NT_STATUS_OK;
472out:
473	SAFE_FREE(dn);
474	if (result != NULL)
475		ldap_msgfree(result);
476
477	return ret;
478}
479
480/*****************************************************************************
481 get a sid from an id
482*****************************************************************************/
483
484static NTSTATUS ldap_get_sid_from_id(DOM_SID *sid, unid_t id, int id_type)
485{
486	LDAPMessage *result = NULL;
487	LDAPMessage *entry = NULL;
488	pstring sid_str;
489	pstring filter;
490	pstring suffix;
491	const char *type;
492	int rc;
493	int count;
494	NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
495	const char **attr_list;
496
497	if ( id_type & ID_USERID )
498		type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_UIDNUMBER );
499	else
500		type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_GIDNUMBER );
501
502	pstrcpy( suffix, lp_ldap_idmap_suffix() );
503	pstr_sprintf(filter, "(&(objectClass=%s)(%s=%d))",
504		LDAP_OBJ_IDMAP_ENTRY, type,
505		((id_type & ID_USERID) ? id.uid : id.gid));
506
507	attr_list = get_attr_list( sidmap_attr_list );
508	rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE,
509		filter, attr_list, 0, &result);
510
511	if (rc != LDAP_SUCCESS) {
512		DEBUG(3,("ldap_get_isd_from_id: Failure looking up entry (%s)\n",
513			ldap_err2string(rc) ));
514		goto out;
515	}
516
517	count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
518
519	if (count != 1) {
520		DEBUG(0,("ldap_get_sid_from_id: mapping not found for %s: %lu\n",
521			type, ((id_type & ID_USERID) ? (unsigned long)id.uid :
522			       (unsigned long)id.gid)));
523		goto out;
524	}
525
526	entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
527
528	if ( !smbldap_get_single_pstring(ldap_state.smbldap_state->ldap_struct, entry, LDAP_ATTRIBUTE_SID, sid_str) )
529		goto out;
530
531	if (!string_to_sid(sid, sid_str))
532		goto out;
533
534	ret = NT_STATUS_OK;
535out:
536	free_attr_list( attr_list );
537
538	if (result)
539		ldap_msgfree(result);
540
541	return ret;
542}
543
544/***********************************************************************
545 Get an id from a sid
546***********************************************************************/
547
548static NTSTATUS ldap_get_id_from_sid(unid_t *id, int *id_type, const DOM_SID *sid)
549{
550	LDAPMessage *result = NULL;
551	LDAPMessage *entry = NULL;
552	pstring sid_str;
553	pstring filter;
554	pstring id_str;
555	const char *suffix;
556	const char *type;
557	int rc;
558	int count;
559	const char **attr_list;
560	char *dn = NULL;
561	NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
562
563	sid_to_string(sid_str, sid);
564
565	DEBUG(8,("ldap_get_id_from_sid: %s (%s)\n", sid_str,
566		(*id_type & ID_GROUPID ? "group" : "user") ));
567
568	suffix = lp_ldap_idmap_suffix();
569	pstr_sprintf(filter, "(&(objectClass=%s)(%s=%s))",
570		LDAP_OBJ_IDMAP_ENTRY, LDAP_ATTRIBUTE_SID, sid_str);
571
572	if ( *id_type & ID_GROUPID )
573		type = get_attr_key2string( sidmap_attr_list, LDAP_ATTR_GIDNUMBER );
574	else
575		type = get_attr_key2string( sidmap_attr_list, LDAP_ATTR_UIDNUMBER );
576
577	/* do the search and check for errors */
578
579	attr_list = get_attr_list( sidmap_attr_list );
580	rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE,
581		filter, attr_list, 0, &result);
582
583	if (rc != LDAP_SUCCESS) {
584		DEBUG(3,("ldap_get_id_from_sid: Failure looking up idmap entry (%s)\n",
585			ldap_err2string(rc) ));
586		goto out;
587	}
588
589	/* check for the number of entries returned */
590
591	count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
592
593	if ( count > 1 ) {
594		DEBUG(0, ("ldap_get_id_from_sid: (2nd) search %s returned [%d] entries!\n",
595			filter, count));
596		goto out;
597	}
598
599	/* try to allocate a new id if we still haven't found one */
600
601	if ( !count ) {
602		int i;
603
604		if (*id_type & ID_QUERY_ONLY) {
605			DEBUG(5,("ldap_get_id_from_sid: No matching entry found and QUERY_ONLY flag set\n"));
606			goto out;
607		}
608
609		DEBUG(8,("ldap_get_id_from_sid: Allocating new id\n"));
610
611		for (i = 0; i < LDAP_MAX_ALLOC_ID; i++) {
612			ret = ldap_allocate_id(id, *id_type);
613			if ( NT_STATUS_IS_OK(ret) )
614				break;
615		}
616
617		if ( !NT_STATUS_IS_OK(ret) ) {
618			DEBUG(0,("ldap_allocate_id: cannot acquire id lock!\n"));
619			goto out;
620		}
621
622		DEBUG(10,("ldap_get_id_from_sid: Allocated new %cid [%ul]\n",
623			(*id_type & ID_GROUPID ? 'g' : 'u'), (uint32)id->uid ));
624
625		ret = ldap_set_mapping(sid, *id, *id_type);
626
627		/* all done */
628
629		goto out;
630	}
631
632	DEBUG(10,("ldap_get_id_from_sid: success\n"));
633
634	entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
635
636	dn = smbldap_get_dn(ldap_state.smbldap_state->ldap_struct, result);
637	if (!dn)
638		goto out;
639
640	DEBUG(10, ("Found mapping entry at dn=%s, looking for %s\n", dn, type));
641
642	if ( smbldap_get_single_pstring(ldap_state.smbldap_state->ldap_struct, entry, type, id_str) ) {
643		if ( (*id_type & ID_USERID) )
644			id->uid = strtoul(id_str, NULL, 10);
645		else
646			id->gid = strtoul(id_str, NULL, 10);
647
648		ret = NT_STATUS_OK;
649		goto out;
650	}
651
652out:
653	free_attr_list( attr_list );
654	if (result)
655		ldap_msgfree(result);
656	SAFE_FREE(dn);
657
658	return ret;
659}
660
661/**********************************************************************
662 Verify the sambaUnixIdPool entry in the directiry.
663**********************************************************************/
664
665static NTSTATUS verify_idpool( void )
666{
667	fstring filter;
668	int rc;
669	const char **attr_list;
670	LDAPMessage *result = NULL;
671	LDAPMod **mods = NULL;
672	int count;
673
674	fstr_sprintf( filter, "(objectclass=%s)", LDAP_OBJ_IDPOOL );
675
676	attr_list = get_attr_list( idpool_attr_list );
677	rc = smbldap_search(ldap_state.smbldap_state, lp_ldap_idmap_suffix(),
678		LDAP_SCOPE_SUBTREE, filter, attr_list, 0, &result);
679	free_attr_list ( attr_list );
680
681	if (rc != LDAP_SUCCESS)
682		return NT_STATUS_UNSUCCESSFUL;
683
684	count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
685
686	ldap_msgfree(result);
687
688	if ( count > 1 ) {
689		DEBUG(0,("ldap_idmap_init: multiple entries returned from %s (base == %s)\n",
690			filter, lp_ldap_idmap_suffix() ));
691		return NT_STATUS_UNSUCCESSFUL;
692	}
693	else if (count == 0) {
694		uid_t	luid, huid;
695		gid_t	lgid, hgid;
696		fstring uid_str, gid_str;
697
698		if ( !lp_idmap_uid(&luid, &huid) || !lp_idmap_gid( &lgid, &hgid ) ) {
699			DEBUG(0,("ldap_idmap_init: idmap uid/gid parameters not specified\n"));
700			return NT_STATUS_UNSUCCESSFUL;
701		}
702
703		fstr_sprintf( uid_str, "%d", luid );
704		fstr_sprintf( gid_str, "%d", lgid );
705
706		smbldap_set_mod( &mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_IDPOOL );
707		smbldap_set_mod( &mods, LDAP_MOD_ADD,
708			get_attr_key2string(idpool_attr_list, LDAP_ATTR_UIDNUMBER), uid_str );
709		smbldap_set_mod( &mods, LDAP_MOD_ADD,
710			get_attr_key2string(idpool_attr_list, LDAP_ATTR_GIDNUMBER), gid_str );
711		if (mods) {
712			rc = smbldap_modify(ldap_state.smbldap_state, lp_ldap_idmap_suffix(), mods);
713			ldap_mods_free( mods, True );
714		} else {
715			return NT_STATUS_UNSUCCESSFUL;
716		}
717	}
718
719	return ( rc==LDAP_SUCCESS ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
720}
721
722/*****************************************************************************
723 Initialise idmap database.
724*****************************************************************************/
725
726static NTSTATUS ldap_idmap_init( char *params )
727{
728	NTSTATUS nt_status;
729
730	ldap_state.mem_ctx = talloc_init("idmap_ldap");
731	if (!ldap_state.mem_ctx) {
732		return NT_STATUS_NO_MEMORY;
733	}
734
735	/* assume location is the only parameter */
736	if (!NT_STATUS_IS_OK(nt_status =
737			     smbldap_init(ldap_state.mem_ctx, params,
738					  &ldap_state.smbldap_state))) {
739		talloc_destroy(ldap_state.mem_ctx);
740		return nt_status;
741	}
742
743	/* see if the idmap suffix and sub entries exists */
744
745	nt_status = verify_idpool();
746	if ( !NT_STATUS_IS_OK(nt_status) )
747		return nt_status;
748
749	return NT_STATUS_OK;
750}
751
752/*****************************************************************************
753 End the LDAP session
754*****************************************************************************/
755
756static NTSTATUS ldap_idmap_close(void)
757{
758
759	smbldap_free_struct(&(ldap_state).smbldap_state);
760	talloc_destroy(ldap_state.mem_ctx);
761
762	DEBUG(5,("The connection to the LDAP server was closed\n"));
763	/* maybe free the results here --metze */
764
765	return NT_STATUS_OK;
766}
767
768
769/* This function doesn't make as much sense in an LDAP world since the calling
770   node doesn't really control the ID ranges */
771static void ldap_idmap_status(void)
772{
773	DEBUG(0, ("LDAP IDMAP Status not available\n"));
774}
775
776static struct idmap_methods ldap_methods = {
777	ldap_idmap_init,
778	ldap_allocate_rid,
779	ldap_allocate_id,
780	ldap_get_sid_from_id,
781	ldap_get_id_from_sid,
782	ldap_set_mapping,
783	ldap_idmap_close,
784	ldap_idmap_status
785
786};
787
788NTSTATUS idmap_ldap_init(void)
789{
790	return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "ldap", &ldap_methods);
791}
792