r7415: * big change -- volker's new async winbindd from trunk
[Samba/gbeck.git] / source / sam / idmap_ldap.c
blobb4a8c8a75285cf217fc92e485f4b4e2322d8a7ce
1 /*
2 Unix SMB/CIFS implementation.
4 idmap LDAP backend
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
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.
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.
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.
26 #include "includes.h"
28 #undef DBGC_CLASS
29 #define DBGC_CLASS DBGC_IDMAP
32 #include <lber.h>
33 #include <ldap.h>
35 #include "smbldap.h"
37 struct ldap_idmap_state {
38 struct smbldap_state *smbldap_state;
39 TALLOC_CTX *mem_ctx;
42 static struct ldap_idmap_state ldap_state;
44 /* number tries while allocating new id */
45 #define LDAP_MAX_ALLOC_ID 128
48 /***********************************************************************
49 This function cannot be called to modify a mapping, only set a new one
50 ***********************************************************************/
52 static NTSTATUS ldap_set_mapping(const DOM_SID *sid, unid_t id, int id_type)
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;
63 sid_to_string( sid_string, sid );
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());
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 ) );
74 pstr_sprintf(id_str, "%lu", ((id_type & ID_USERID) ? (unsigned long)id.uid :
75 (unsigned long)id.gid));
77 smbldap_set_mod( &mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_IDMAP_ENTRY );
79 smbldap_make_mod( ldap_state.smbldap_state->ldap_struct,
80 entry, &mods, type, id_str );
82 smbldap_make_mod( ldap_state.smbldap_state->ldap_struct,
83 entry, &mods,
84 get_attr_key2string(sidmap_attr_list, LDAP_ATTR_SID),
85 sid_string );
87 /* There may well be nothing at all to do */
89 if (mods) {
90 smbldap_set_mod( &mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_SID_ENTRY );
91 rc = smbldap_add(ldap_state.smbldap_state, dn, mods);
92 ldap_mods_free( mods, True );
93 } else {
94 rc = LDAP_SUCCESS;
97 if (rc != LDAP_SUCCESS) {
98 char *ld_error = NULL;
99 ldap_get_option(ldap_state.smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
100 &ld_error);
101 DEBUG(0,("ldap_set_mapping_internals: Failed to %s mapping from %s to %lu [%s]\n",
102 (ldap_op == LDAP_MOD_ADD) ? "add" : "replace",
103 sid_string, (unsigned long)((id_type & ID_USERID) ? id.uid : id.gid), type));
104 DEBUG(0, ("ldap_set_mapping_internals: Error was: %s (%s)\n",
105 ld_error ? ld_error : "(NULL)", ldap_err2string (rc)));
106 return NT_STATUS_UNSUCCESSFUL;
109 DEBUG(10,("ldap_set_mapping: Successfully created mapping from %s to %lu [%s]\n",
110 sid_string, ((id_type & ID_USERID) ? (unsigned long)id.uid :
111 (unsigned long)id.gid), type));
113 return NT_STATUS_OK;
116 /**********************************************************************
117 Even if the sambaDomain attribute in LDAP tells us that this RID is
118 safe to use, always check before use.
119 *********************************************************************/
121 static BOOL sid_in_use(struct ldap_idmap_state *state,
122 const DOM_SID *sid, int *error)
124 fstring filter;
125 fstring sid_string;
126 LDAPMessage *result = NULL;
127 int rc;
128 const char *sid_attr[] = {LDAP_ATTRIBUTE_SID, NULL};
130 slprintf(filter, sizeof(filter)-1, "(%s=%s)", LDAP_ATTRIBUTE_SID, sid_to_string(sid_string, sid));
132 rc = smbldap_search_suffix(state->smbldap_state,
133 filter, sid_attr, &result);
135 if (rc != LDAP_SUCCESS) {
136 char *ld_error = NULL;
137 ldap_get_option(state->smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error);
138 DEBUG(2, ("Failed to check if sid %s is alredy in use: %s\n",
139 sid_string, ld_error));
140 SAFE_FREE(ld_error);
142 *error = rc;
143 return True;
146 if ((ldap_count_entries(state->smbldap_state->ldap_struct, result)) > 0) {
147 DEBUG(3, ("Sid %s already in use - trying next RID\n",
148 sid_string));
149 ldap_msgfree(result);
150 return True;
153 ldap_msgfree(result);
155 /* good, sid is not in use */
156 return False;
159 /**********************************************************************
160 Set the new nextRid attribute, and return one we can use.
162 This also checks that this RID is actually free - in case the admin
163 manually stole it :-).
164 *********************************************************************/
166 static NTSTATUS ldap_next_rid(struct ldap_idmap_state *state, uint32 *rid,
167 int rid_type)
169 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
170 LDAPMessage *domain_result = NULL;
171 LDAPMessage *entry = NULL;
172 char *dn;
173 LDAPMod **mods = NULL;
174 fstring old_rid_string;
175 fstring next_rid_string;
176 fstring algorithmic_rid_base_string;
177 uint32 next_rid;
178 uint32 alg_rid_base;
179 int attempts = 0;
180 char *ld_error = NULL;
182 while (attempts < 10) {
183 if (!NT_STATUS_IS_OK(ret = smbldap_search_domain_info(state->smbldap_state,
184 &domain_result, get_global_sam_name(), True))) {
185 return ret;
188 entry = ldap_first_entry(state->smbldap_state->ldap_struct, domain_result);
189 if (!entry) {
190 DEBUG(0, ("Could not get domain info entry\n"));
191 ldap_msgfree(domain_result);
192 return ret;
195 if ((dn = smbldap_get_dn(state->smbldap_state->ldap_struct, entry)) == NULL) {
196 DEBUG(0, ("Could not get domain info DN\n"));
197 ldap_msgfree(domain_result);
198 return ret;
201 /* yes, we keep 3 seperate counters, one for rids between 1000 (BASE_RID) and
202 algorithmic_rid_base. The other two are to avoid stomping on the
203 different sets of algorithmic RIDs */
205 if (smbldap_get_single_pstring(state->smbldap_state->ldap_struct, entry,
206 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_ALGORITHMIC_RID_BASE),
207 algorithmic_rid_base_string)) {
209 alg_rid_base = (uint32)atol(algorithmic_rid_base_string);
210 } else {
211 alg_rid_base = algorithmic_rid_base();
212 /* Try to make the modification atomically by enforcing the
213 old value in the delete mod. */
214 slprintf(algorithmic_rid_base_string, sizeof(algorithmic_rid_base_string)-1, "%d", alg_rid_base);
215 smbldap_make_mod(state->smbldap_state->ldap_struct, entry, &mods,
216 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_ALGORITHMIC_RID_BASE),
217 algorithmic_rid_base_string);
220 next_rid = 0;
222 if (alg_rid_base > BASE_RID) {
223 /* we have a non-default 'algorithmic rid base', so we have 'low' rids that we
224 can allocate to new users */
225 if (smbldap_get_single_pstring(state->smbldap_state->ldap_struct, entry,
226 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_RID),
227 old_rid_string)) {
228 *rid = (uint32)atol(old_rid_string);
229 } else {
230 *rid = BASE_RID;
233 next_rid = *rid+1;
234 if (next_rid >= alg_rid_base) {
235 ldap_msgfree(domain_result);
236 return NT_STATUS_UNSUCCESSFUL;
239 slprintf(next_rid_string, sizeof(next_rid_string)-1, "%d", next_rid);
241 /* Try to make the modification atomically by enforcing the
242 old value in the delete mod. */
243 smbldap_make_mod(state->smbldap_state->ldap_struct, entry, &mods,
244 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_RID),
245 next_rid_string);
248 if (!next_rid) { /* not got one already */
249 switch (rid_type) {
250 case USER_RID_TYPE:
251 if (smbldap_get_single_pstring(state->smbldap_state->ldap_struct, entry,
252 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_USERRID),
253 old_rid_string)) {
254 *rid = (uint32)atol(old_rid_string);
256 break;
257 case GROUP_RID_TYPE:
258 if (smbldap_get_single_pstring(state->smbldap_state->ldap_struct, entry,
259 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_GROUPRID),
260 old_rid_string)) {
261 *rid = (uint32)atol(old_rid_string);
263 break;
266 /* This is the core of the whole routine. If we had
267 scheme-style closures, there would be a *lot* less code
268 duplication... */
270 next_rid = *rid+RID_MULTIPLIER;
271 slprintf(next_rid_string, sizeof(next_rid_string)-1, "%d", next_rid);
273 switch (rid_type) {
274 case USER_RID_TYPE:
275 /* Try to make the modification atomically by enforcing the
276 old value in the delete mod. */
277 smbldap_make_mod(state->smbldap_state->ldap_struct, entry, &mods,
278 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_USERRID),
279 next_rid_string);
280 break;
282 case GROUP_RID_TYPE:
283 /* Try to make the modification atomically by enforcing the
284 old value in the delete mod. */
285 smbldap_make_mod(state->smbldap_state->ldap_struct, entry, &mods,
286 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_GROUPRID),
287 next_rid_string);
288 break;
292 if ((smbldap_modify(state->smbldap_state, dn, mods)) == LDAP_SUCCESS) {
293 DOM_SID dom_sid;
294 DOM_SID sid;
295 pstring domain_sid_string;
296 int error = 0;
298 if (!smbldap_get_single_pstring(state->smbldap_state->ldap_struct, domain_result,
299 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOM_SID),
300 domain_sid_string)) {
301 ldap_mods_free(mods, True);
302 SAFE_FREE(dn);
303 ldap_msgfree(domain_result);
304 return ret;
307 if (!string_to_sid(&dom_sid, domain_sid_string)) {
308 ldap_mods_free(mods, True);
309 SAFE_FREE(dn);
310 ldap_msgfree(domain_result);
311 return ret;
314 ldap_mods_free(mods, True);
315 mods = NULL;
316 SAFE_FREE(dn);
317 ldap_msgfree(domain_result);
319 sid_copy(&sid, &dom_sid);
320 sid_append_rid(&sid, *rid);
322 /* check RID is not in use */
323 if (sid_in_use(state, &sid, &error)) {
324 if (error) {
325 return ret;
327 continue;
330 return NT_STATUS_OK;
333 ld_error = NULL;
334 ldap_get_option(state->smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error);
335 DEBUG(2, ("Failed to modify rid: %s\n", ld_error ? ld_error : "(NULL"));
336 SAFE_FREE(ld_error);
338 ldap_mods_free(mods, True);
339 mods = NULL;
341 SAFE_FREE(dn);
343 ldap_msgfree(domain_result);
344 domain_result = NULL;
347 /* Sleep for a random timeout */
348 unsigned sleeptime = (sys_random()*sys_getpid()*attempts);
349 attempts += 1;
351 sleeptime %= 100;
352 smb_msleep(sleeptime);
356 DEBUG(0, ("Failed to set new RID\n"));
357 return ret;
361 /*****************************************************************************
362 Allocate a new RID
363 *****************************************************************************/
365 static NTSTATUS ldap_allocate_rid(uint32 *rid, int rid_type)
367 return ldap_next_rid( &ldap_state, rid, rid_type );
370 /*****************************************************************************
371 Allocate a new uid or gid
372 *****************************************************************************/
374 static NTSTATUS ldap_allocate_id(unid_t *id, int id_type)
376 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
377 int rc = LDAP_SERVER_DOWN;
378 int count = 0;
379 LDAPMessage *result = NULL;
380 LDAPMessage *entry = NULL;
381 pstring id_str, new_id_str;
382 LDAPMod **mods = NULL;
383 const char *type;
384 char *dn = NULL;
385 const char **attr_list;
386 pstring filter;
387 uid_t luid, huid;
388 gid_t lgid, hgid;
391 type = (id_type & ID_USERID) ?
392 get_attr_key2string( idpool_attr_list, LDAP_ATTR_UIDNUMBER ) :
393 get_attr_key2string( idpool_attr_list, LDAP_ATTR_GIDNUMBER );
395 pstr_sprintf(filter, "(objectClass=%s)", LDAP_OBJ_IDPOOL);
397 attr_list = get_attr_list( idpool_attr_list );
399 rc = smbldap_search(ldap_state.smbldap_state, lp_ldap_idmap_suffix(),
400 LDAP_SCOPE_SUBTREE, filter,
401 attr_list, 0, &result);
402 free_attr_list( attr_list );
404 if (rc != LDAP_SUCCESS) {
405 DEBUG(0,("ldap_allocate_id: %s object not found\n", LDAP_OBJ_IDPOOL));
406 goto out;
409 count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
410 if (count != 1) {
411 DEBUG(0,("ldap_allocate_id: single %s object not found\n", LDAP_OBJ_IDPOOL));
412 goto out;
415 dn = smbldap_get_dn(ldap_state.smbldap_state->ldap_struct, result);
416 if (!dn) {
417 goto out;
419 entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
421 if (!smbldap_get_single_pstring(ldap_state.smbldap_state->ldap_struct, entry, type, id_str)) {
422 DEBUG(0,("ldap_allocate_id: %s attribute not found\n",
423 type));
424 goto out;
427 /* this must succeed or else we wouldn't have initialized */
429 lp_idmap_uid( &luid, &huid);
430 lp_idmap_gid( &lgid, &hgid);
432 /* make sure we still have room to grow */
434 if (id_type & ID_USERID) {
435 id->uid = strtoul(id_str, NULL, 10);
436 if (id->uid > huid ) {
437 DEBUG(0,("ldap_allocate_id: Cannot allocate uid above %lu!\n",
438 (unsigned long)huid));
439 goto out;
442 else {
443 id->gid = strtoul(id_str, NULL, 10);
444 if (id->gid > hgid ) {
445 DEBUG(0,("ldap_allocate_id: Cannot allocate gid above %lu!\n",
446 (unsigned long)hgid));
447 goto out;
451 pstr_sprintf(new_id_str, "%lu",
452 ((id_type & ID_USERID) ? (unsigned long)id->uid :
453 (unsigned long)id->gid) + 1);
455 smbldap_set_mod( &mods, LDAP_MOD_DELETE, type, id_str );
456 smbldap_set_mod( &mods, LDAP_MOD_ADD, type, new_id_str );
458 if (mods == NULL) {
459 DEBUG(0,("ldap_allocate_id: smbldap_set_mod() failed.\n"));
460 goto out;
463 rc = smbldap_modify(ldap_state.smbldap_state, dn, mods);
465 ldap_mods_free( mods, True );
466 if (rc != LDAP_SUCCESS) {
467 DEBUG(1,("ldap_allocate_id: Failed to allocate new %s. ldap_modify() failed.\n",
468 type));
469 goto out;
472 ret = NT_STATUS_OK;
473 out:
474 SAFE_FREE(dn);
475 if (result != NULL)
476 ldap_msgfree(result);
478 return ret;
481 /*****************************************************************************
482 get a sid from an id
483 *****************************************************************************/
485 static NTSTATUS ldap_get_sid_from_id(DOM_SID *sid, unid_t id, int id_type)
487 LDAPMessage *result = NULL;
488 LDAPMessage *entry = NULL;
489 pstring sid_str;
490 pstring filter;
491 pstring suffix;
492 const char *type;
493 int rc;
494 int count;
495 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
496 const char **attr_list;
498 if ( id_type & ID_USERID )
499 type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_UIDNUMBER );
500 else
501 type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_GIDNUMBER );
503 pstrcpy( suffix, lp_ldap_idmap_suffix() );
504 pstr_sprintf(filter, "(&(objectClass=%s)(%s=%lu))",
505 LDAP_OBJ_IDMAP_ENTRY, type,
506 ((id_type & ID_USERID) ? (unsigned long)id.uid : (unsigned long)id.gid));
508 attr_list = get_attr_list( sidmap_attr_list );
509 rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE,
510 filter, attr_list, 0, &result);
512 if (rc != LDAP_SUCCESS) {
513 DEBUG(3,("ldap_get_isd_from_id: Failure looking up entry (%s)\n",
514 ldap_err2string(rc) ));
515 goto out;
518 count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
520 if (count != 1) {
521 DEBUG(0,("ldap_get_sid_from_id: mapping not found for %s: %lu\n",
522 type, ((id_type & ID_USERID) ? (unsigned long)id.uid :
523 (unsigned long)id.gid)));
524 goto out;
527 entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
529 if ( !smbldap_get_single_pstring(ldap_state.smbldap_state->ldap_struct, entry, LDAP_ATTRIBUTE_SID, sid_str) )
530 goto out;
532 if (!string_to_sid(sid, sid_str))
533 goto out;
535 ret = NT_STATUS_OK;
536 out:
537 free_attr_list( attr_list );
539 if (result)
540 ldap_msgfree(result);
542 return ret;
545 /***********************************************************************
546 Get an id from a sid
547 ***********************************************************************/
549 static NTSTATUS ldap_get_id_from_sid(unid_t *id, int *id_type, const DOM_SID *sid)
551 LDAPMessage *result = NULL;
552 LDAPMessage *entry = NULL;
553 pstring sid_str;
554 pstring filter;
555 pstring id_str;
556 const char *suffix;
557 const char *type;
558 int rc;
559 int count;
560 const char **attr_list;
561 char *dn = NULL;
562 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
564 sid_to_string(sid_str, sid);
566 DEBUG(8,("ldap_get_id_from_sid: %s (%s)\n", sid_str,
567 (*id_type & ID_GROUPID ? "group" : "user") ));
569 suffix = lp_ldap_idmap_suffix();
570 pstr_sprintf(filter, "(&(objectClass=%s)(%s=%s))",
571 LDAP_OBJ_IDMAP_ENTRY, LDAP_ATTRIBUTE_SID, sid_str);
573 if ( *id_type & ID_GROUPID )
574 type = get_attr_key2string( sidmap_attr_list, LDAP_ATTR_GIDNUMBER );
575 else
576 type = get_attr_key2string( sidmap_attr_list, LDAP_ATTR_UIDNUMBER );
578 /* do the search and check for errors */
580 attr_list = get_attr_list( sidmap_attr_list );
581 rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE,
582 filter, attr_list, 0, &result);
584 if (rc != LDAP_SUCCESS) {
585 DEBUG(3,("ldap_get_id_from_sid: Failure looking up idmap entry (%s)\n",
586 ldap_err2string(rc) ));
587 goto out;
590 /* check for the number of entries returned */
592 count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
594 if ( count > 1 ) {
595 DEBUG(0, ("ldap_get_id_from_sid: (2nd) search %s returned [%d] entries!\n",
596 filter, count));
597 goto out;
600 /* try to allocate a new id if we still haven't found one */
602 if ( !count ) {
603 int i;
605 if (*id_type & ID_QUERY_ONLY) {
606 DEBUG(5,("ldap_get_id_from_sid: No matching entry found and QUERY_ONLY flag set\n"));
607 goto out;
610 DEBUG(8,("ldap_get_id_from_sid: Allocating new id\n"));
612 for (i = 0; i < LDAP_MAX_ALLOC_ID; i++) {
613 ret = ldap_allocate_id(id, *id_type);
614 if ( NT_STATUS_IS_OK(ret) )
615 break;
618 if ( !NT_STATUS_IS_OK(ret) ) {
619 DEBUG(0,("ldap_allocate_id: cannot acquire id lock!\n"));
620 goto out;
623 DEBUG(10,("ldap_get_id_from_sid: Allocated new %cid [%ul]\n",
624 (*id_type & ID_GROUPID ? 'g' : 'u'), (uint32)id->uid ));
626 ret = ldap_set_mapping(sid, *id, *id_type);
628 /* all done */
630 goto out;
633 DEBUG(10,("ldap_get_id_from_sid: success\n"));
635 entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
637 dn = smbldap_get_dn(ldap_state.smbldap_state->ldap_struct, result);
638 if (!dn)
639 goto out;
641 DEBUG(10, ("Found mapping entry at dn=%s, looking for %s\n", dn, type));
643 if ( smbldap_get_single_pstring(ldap_state.smbldap_state->ldap_struct, entry, type, id_str) ) {
644 if ( (*id_type & ID_USERID) )
645 id->uid = strtoul(id_str, NULL, 10);
646 else
647 id->gid = strtoul(id_str, NULL, 10);
649 ret = NT_STATUS_OK;
650 goto out;
653 out:
654 free_attr_list( attr_list );
655 if (result)
656 ldap_msgfree(result);
657 SAFE_FREE(dn);
659 return ret;
662 /**********************************************************************
663 Verify the sambaUnixIdPool entry in the directiry.
664 **********************************************************************/
666 static NTSTATUS verify_idpool( void )
668 fstring filter;
669 int rc;
670 const char **attr_list;
671 LDAPMessage *result = NULL;
672 LDAPMod **mods = NULL;
673 int count;
675 fstr_sprintf( filter, "(objectclass=%s)", LDAP_OBJ_IDPOOL );
677 attr_list = get_attr_list( idpool_attr_list );
678 rc = smbldap_search(ldap_state.smbldap_state, lp_ldap_idmap_suffix(),
679 LDAP_SCOPE_SUBTREE, filter, attr_list, 0, &result);
680 free_attr_list ( attr_list );
682 if (rc != LDAP_SUCCESS)
683 return NT_STATUS_UNSUCCESSFUL;
685 count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
687 ldap_msgfree(result);
689 if ( count > 1 ) {
690 DEBUG(0,("ldap_idmap_init: multiple entries returned from %s (base == %s)\n",
691 filter, lp_ldap_idmap_suffix() ));
692 return NT_STATUS_UNSUCCESSFUL;
694 else if (count == 0) {
695 uid_t luid, huid;
696 gid_t lgid, hgid;
697 fstring uid_str, gid_str;
699 if ( !lp_idmap_uid(&luid, &huid) || !lp_idmap_gid( &lgid, &hgid ) ) {
700 DEBUG(0,("ldap_idmap_init: idmap uid/gid parameters not specified\n"));
701 return NT_STATUS_UNSUCCESSFUL;
704 fstr_sprintf( uid_str, "%lu", (unsigned long)luid );
705 fstr_sprintf( gid_str, "%lu", (unsigned long)lgid );
707 smbldap_set_mod( &mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_IDPOOL );
708 smbldap_set_mod( &mods, LDAP_MOD_ADD,
709 get_attr_key2string(idpool_attr_list, LDAP_ATTR_UIDNUMBER), uid_str );
710 smbldap_set_mod( &mods, LDAP_MOD_ADD,
711 get_attr_key2string(idpool_attr_list, LDAP_ATTR_GIDNUMBER), gid_str );
712 if (mods) {
713 rc = smbldap_modify(ldap_state.smbldap_state, lp_ldap_idmap_suffix(), mods);
714 ldap_mods_free( mods, True );
715 } else {
716 return NT_STATUS_UNSUCCESSFUL;
720 return ( rc==LDAP_SUCCESS ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
723 /*****************************************************************************
724 Initialise idmap database.
725 *****************************************************************************/
727 static NTSTATUS ldap_idmap_init( char *params )
729 NTSTATUS nt_status;
731 ldap_state.mem_ctx = talloc_init("idmap_ldap");
732 if (!ldap_state.mem_ctx) {
733 return NT_STATUS_NO_MEMORY;
736 /* assume location is the only parameter */
737 if (!NT_STATUS_IS_OK(nt_status =
738 smbldap_init(ldap_state.mem_ctx, params,
739 &ldap_state.smbldap_state))) {
740 talloc_destroy(ldap_state.mem_ctx);
741 return nt_status;
744 /* see if the idmap suffix and sub entries exists */
746 nt_status = verify_idpool();
747 if ( !NT_STATUS_IS_OK(nt_status) )
748 return nt_status;
750 return NT_STATUS_OK;
753 /*****************************************************************************
754 End the LDAP session
755 *****************************************************************************/
757 static NTSTATUS ldap_idmap_close(void)
760 smbldap_free_struct(&(ldap_state).smbldap_state);
761 talloc_destroy(ldap_state.mem_ctx);
763 DEBUG(5,("The connection to the LDAP server was closed\n"));
764 /* maybe free the results here --metze */
766 return NT_STATUS_OK;
770 /* This function doesn't make as much sense in an LDAP world since the calling
771 node doesn't really control the ID ranges */
772 static void ldap_idmap_status(void)
774 DEBUG(0, ("LDAP IDMAP Status not available\n"));
777 static struct idmap_methods ldap_methods = {
778 ldap_idmap_init,
779 ldap_allocate_rid,
780 ldap_allocate_id,
781 ldap_get_sid_from_id,
782 ldap_get_id_from_sid,
783 ldap_set_mapping,
784 ldap_idmap_close,
785 ldap_idmap_status
789 NTSTATUS idmap_ldap_init(void)
791 return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "ldap", &ldap_methods);