More GUID->struct uuid changes.
[Samba/gebeck_regimport.git] / source / sam / idmap_ldap.c
blob72fcb47b039d24a07eb772c7b4d9848b1ef5416b
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 #define IDMAP_GROUP_SUFFIX "ou=idmap group"
38 #define IDMAP_USER_SUFFIX "ou=idmap people"
41 struct ldap_idmap_state {
42 struct smbldap_state *smbldap_state;
43 TALLOC_CTX *mem_ctx;
46 #define LDAP_MAX_ALLOC_ID 128 /* number tries while allocating
47 new id */
49 static struct ldap_idmap_state ldap_state;
51 static NTSTATUS ldap_set_mapping(const DOM_SID *sid, unid_t id, int id_type);
52 static NTSTATUS ldap_set_mapping_internals(const DOM_SID *sid, unid_t id, int id_type,
53 const char *ldap_dn, LDAPMessage *entry);
54 static NTSTATUS ldap_idmap_close(void);
57 /**********************************************************************
58 Even if the sambaDomain attribute in LDAP tells us that this RID is
59 safe to use, always check before use.
60 *********************************************************************/
62 static BOOL sid_in_use(struct ldap_idmap_state *state,
63 const DOM_SID *sid, int *error)
65 fstring filter;
66 fstring sid_string;
67 LDAPMessage *result = NULL;
68 int count;
69 int rc;
70 char *sid_attr[] = {LDAP_ATTRIBUTE_SID, NULL};
72 slprintf(filter, sizeof(filter)-1, "(%s=%s)", LDAP_ATTRIBUTE_SID, sid_to_string(sid_string, sid));
74 rc = smbldap_search_suffix(state->smbldap_state,
75 filter, sid_attr, &result);
77 if (rc != LDAP_SUCCESS) {
78 char *ld_error = NULL;
79 ldap_get_option(state->smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error);
80 DEBUG(2, ("Failed to check if sid %s is alredy in use: %s\n",
81 sid_string, ld_error));
82 SAFE_FREE(ld_error);
84 *error = rc;
85 return True;
88 if ((count = ldap_count_entries(state->smbldap_state->ldap_struct, result)) > 0) {
89 DEBUG(3, ("Sid %s already in use - trying next RID\n",
90 sid_string));
91 ldap_msgfree(result);
92 return True;
95 ldap_msgfree(result);
97 /* good, sid is not in use */
98 return False;
101 /**********************************************************************
102 Set the new nextRid attribute, and return one we can use.
104 This also checks that this RID is actually free - in case the admin
105 manually stole it :-).
106 *********************************************************************/
108 static NTSTATUS ldap_next_rid(struct ldap_idmap_state *state, uint32 *rid,
109 int rid_type)
111 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
112 int rc;
113 LDAPMessage *domain_result = NULL;
114 LDAPMessage *entry = NULL;
115 char *dn;
116 LDAPMod **mods = NULL;
117 fstring old_rid_string;
118 fstring next_rid_string;
119 fstring algorithmic_rid_base_string;
120 uint32 next_rid;
121 uint32 alg_rid_base;
122 int attempts = 0;
123 char *ld_error = NULL;
125 while (attempts < 10) {
126 if (!NT_STATUS_IS_OK(ret = smbldap_search_domain_info(state->smbldap_state,
127 &domain_result, get_global_sam_name(), True))) {
128 return ret;
131 entry = ldap_first_entry(state->smbldap_state->ldap_struct, domain_result);
132 if (!entry) {
133 DEBUG(0, ("Could not get domain info entry\n"));
134 ldap_msgfree(domain_result);
135 return ret;
138 if ((dn = smbldap_get_dn(state->smbldap_state->ldap_struct, entry)) == NULL) {
139 DEBUG(0, ("Could not get domain info DN\n"));
140 ldap_msgfree(domain_result);
141 return ret;
144 /* yes, we keep 3 seperate counters, one for rids between 1000 (BASE_RID) and
145 algorithmic_rid_base. The other two are to avoid stomping on the
146 different sets of algorithmic RIDs */
148 if (smbldap_get_single_attribute(state->smbldap_state->ldap_struct, entry,
149 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_ALGORITHMIC_RID_BASE),
150 algorithmic_rid_base_string)) {
152 alg_rid_base = (uint32)atol(algorithmic_rid_base_string);
153 } else {
154 alg_rid_base = algorithmic_rid_base();
155 /* Try to make the modification atomically by enforcing the
156 old value in the delete mod. */
157 slprintf(algorithmic_rid_base_string, sizeof(algorithmic_rid_base_string)-1, "%d", alg_rid_base);
158 smbldap_make_mod(state->smbldap_state->ldap_struct, entry, &mods,
159 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_ALGORITHMIC_RID_BASE),
160 algorithmic_rid_base_string);
163 next_rid = 0;
165 if (alg_rid_base > BASE_RID) {
166 /* we have a non-default 'algorithmic rid base', so we have 'low' rids that we
167 can allocate to new users */
168 if (smbldap_get_single_attribute(state->smbldap_state->ldap_struct, entry,
169 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_RID),
170 old_rid_string)) {
171 *rid = (uint32)atol(old_rid_string);
172 } else {
173 *rid = BASE_RID;
176 next_rid = *rid+1;
177 if (next_rid >= alg_rid_base) {
178 return NT_STATUS_UNSUCCESSFUL;
181 slprintf(next_rid_string, sizeof(next_rid_string)-1, "%d", next_rid);
183 /* Try to make the modification atomically by enforcing the
184 old value in the delete mod. */
185 smbldap_make_mod(state->smbldap_state->ldap_struct, entry, &mods,
186 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_RID),
187 next_rid_string);
190 if (!next_rid) { /* not got one already */
191 switch (rid_type) {
192 case USER_RID_TYPE:
193 if (smbldap_get_single_attribute(state->smbldap_state->ldap_struct, entry,
194 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_USERRID),
195 old_rid_string)) {
196 *rid = (uint32)atol(old_rid_string);
198 break;
199 case GROUP_RID_TYPE:
200 if (smbldap_get_single_attribute(state->smbldap_state->ldap_struct, entry,
201 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_GROUPRID),
202 old_rid_string)) {
203 *rid = (uint32)atol(old_rid_string);
205 break;
208 /* This is the core of the whole routine. If we had
209 scheme-style closures, there would be a *lot* less code
210 duplication... */
212 next_rid = *rid+RID_MULTIPLIER;
213 slprintf(next_rid_string, sizeof(next_rid_string)-1, "%d", next_rid);
215 switch (rid_type) {
216 case USER_RID_TYPE:
217 /* Try to make the modification atomically by enforcing the
218 old value in the delete mod. */
219 smbldap_make_mod(state->smbldap_state->ldap_struct, entry, &mods,
220 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_USERRID),
221 next_rid_string);
222 break;
224 case GROUP_RID_TYPE:
225 /* Try to make the modification atomically by enforcing the
226 old value in the delete mod. */
227 smbldap_make_mod(state->smbldap_state->ldap_struct, entry, &mods,
228 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_GROUPRID),
229 next_rid_string);
230 break;
234 if ((rc = smbldap_modify(state->smbldap_state, dn, mods)) == LDAP_SUCCESS) {
235 DOM_SID dom_sid;
236 DOM_SID sid;
237 pstring domain_sid_string;
238 int error = 0;
240 if (!smbldap_get_single_attribute(state->smbldap_state->ldap_struct, domain_result,
241 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOM_SID),
242 domain_sid_string)) {
243 ldap_mods_free(mods, True);
244 SAFE_FREE(dn);
245 ldap_msgfree(domain_result);
246 return ret;
249 if (!string_to_sid(&dom_sid, domain_sid_string)) {
250 ldap_mods_free(mods, True);
251 SAFE_FREE(dn);
252 ldap_msgfree(domain_result);
253 return ret;
256 ldap_mods_free(mods, True);
257 mods = NULL;
258 SAFE_FREE(dn);
259 ldap_msgfree(domain_result);
261 sid_copy(&sid, &dom_sid);
262 sid_append_rid(&sid, *rid);
264 /* check RID is not in use */
265 if (sid_in_use(state, &sid, &error)) {
266 if (error) {
267 return ret;
269 continue;
272 return NT_STATUS_OK;
275 ld_error = NULL;
276 ldap_get_option(state->smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error);
277 DEBUG(2, ("Failed to modify rid: %s\n", ld_error ? ld_error : "(NULL"));
278 SAFE_FREE(ld_error);
280 ldap_mods_free(mods, True);
281 mods = NULL;
283 SAFE_FREE(dn);
285 ldap_msgfree(domain_result);
286 domain_result = NULL;
289 /* Sleep for a random timeout */
290 unsigned sleeptime = (sys_random()*sys_getpid()*attempts);
291 attempts += 1;
293 sleeptime %= 100;
294 msleep(sleeptime);
298 DEBUG(0, ("Failed to set new RID\n"));
299 return ret;
303 /*****************************************************************************
304 Allocate a new RID
305 *****************************************************************************/
307 static NTSTATUS ldap_allocate_rid(uint32 *rid, int rid_type)
309 return ldap_next_rid( &ldap_state, rid, rid_type );
312 /*****************************************************************************
313 Allocate a new uid or gid
314 *****************************************************************************/
316 static NTSTATUS ldap_allocate_id(unid_t *id, int id_type)
318 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
319 int rc = LDAP_SERVER_DOWN;
320 int count = 0;
321 LDAPMessage *result = NULL;
322 LDAPMessage *entry = NULL;
323 pstring id_str, new_id_str;
324 LDAPMod **mods = NULL;
325 const char *type;
326 char *dn;
327 char **attr_list;
328 pstring filter;
329 uid_t luid, huid;
330 gid_t lgid, hgid;
333 type = (id_type & ID_USERID) ?
334 get_attr_key2string( idpool_attr_list, LDAP_ATTR_UIDNUMBER ) :
335 get_attr_key2string( idpool_attr_list, LDAP_ATTR_GIDNUMBER );
337 pstr_sprintf(filter, "(objectClass=%s)", LDAP_OBJ_IDPOOL);
339 attr_list = get_attr_list( idpool_attr_list );
341 rc = smbldap_search(ldap_state.smbldap_state, lp_ldap_idmap_suffix(),
342 LDAP_SCOPE_SUBTREE, filter,
343 attr_list, 0, &result);
344 free_attr_list( attr_list );
346 if (rc != LDAP_SUCCESS) {
347 DEBUG(0,("ldap_allocate_id: %s object not found\n", LDAP_OBJ_IDPOOL));
348 goto out;
351 count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
352 if (count != 1) {
353 DEBUG(0,("ldap_allocate_id: single %s object not found\n", LDAP_OBJ_IDPOOL));
354 goto out;
357 dn = smbldap_get_dn(ldap_state.smbldap_state->ldap_struct, result);
358 if (!dn) {
359 goto out;
361 entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
363 if (!smbldap_get_single_attribute(ldap_state.smbldap_state->ldap_struct, entry, type, id_str)) {
364 DEBUG(0,("ldap_allocate_id: %s attribute not found\n",
365 type));
366 goto out;
369 /* this must succeed or else we wouldn't have initialized */
371 lp_idmap_uid( &luid, &huid);
372 lp_idmap_gid( &lgid, &hgid);
374 /* make sure we still have room to grow */
376 if (id_type & ID_USERID) {
377 id->uid = strtoul(id_str, NULL, 10);
378 if (id->uid > huid ) {
379 DEBUG(0,("ldap_allocate_id: Cannot allocate uid above %lu!\n",
380 (unsigned long)huid));
381 goto out;
384 else {
385 id->gid = strtoul(id_str, NULL, 10);
386 if (id->gid > hgid ) {
387 DEBUG(0,("ldap_allocate_id: Cannot allocate gid above %lu!\n",
388 (unsigned long)hgid));
389 goto out;
393 pstr_sprintf(new_id_str, "%lu",
394 ((id_type & ID_USERID) ? (unsigned long)id->uid :
395 (unsigned long)id->gid) + 1);
397 smbldap_set_mod( &mods, LDAP_MOD_DELETE, type, id_str );
398 smbldap_set_mod( &mods, LDAP_MOD_ADD, type, new_id_str );
400 rc = smbldap_modify(ldap_state.smbldap_state, dn, mods);
402 SAFE_FREE(dn);
403 ldap_mods_free( mods, True );
405 if (rc != LDAP_SUCCESS) {
406 DEBUG(0,("ldap_allocate_id: Failed to allocate new %s. ldap_modify() failed.\n",
407 type));
408 goto out;
411 ret = NT_STATUS_OK;
412 out:
413 return ret;
416 /*****************************************************************************
417 get a sid from an id
418 *****************************************************************************/
420 static NTSTATUS ldap_get_sid_from_id(DOM_SID *sid, unid_t id, int id_type)
422 LDAPMessage *result = NULL;
423 LDAPMessage *entry = NULL;
424 fstring id_str;
425 pstring sid_str;
426 pstring filter;
427 pstring suffix;
428 const char *type;
429 const char *obj_class;
430 int rc;
431 int count;
432 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
433 char **attr_list;
435 /* first we try for a samba user or group mapping */
437 if ( id_type & ID_USERID ) {
438 type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_UIDNUMBER );
439 obj_class = LDAP_OBJ_SAMBASAMACCOUNT;
440 fstr_sprintf(id_str, "%lu", (unsigned long)id.uid );
441 pstrcpy( suffix, lp_ldap_suffix());
443 else {
444 type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_GIDNUMBER );
445 obj_class = LDAP_OBJ_GROUPMAP;
446 fstr_sprintf(id_str, "%lu", (unsigned long)id.gid );
447 pstrcpy( suffix, lp_ldap_group_suffix() );
450 DEBUG(5,("ldap_get_sid_from_id: Searching \"%s\"\n", filter ));
452 attr_list = get_attr_list( sidmap_attr_list );
453 pstr_sprintf(filter, "(&(|(objectClass=%s)(objectClass=%s))(%s=%s))",
454 LDAP_OBJ_IDMAP_ENTRY, obj_class, type, id_str);
456 rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE,
457 filter, attr_list, 0, &result);
459 if (rc != LDAP_SUCCESS) {
460 DEBUG(3,("ldap_get_isd_from_id: Failure looking up entry (%s)\n",
461 ldap_err2string(rc) ));
462 goto out;
465 count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
467 if (count > 1) {
468 DEBUG(0,("ldap_get_sid_from_id: mapping returned [%d] entries!\n",
469 count));
470 goto out;
473 /* fall back to looking up an idmap entry if we didn't find and
474 actual user or group */
476 if (count == 0) {
477 ldap_msgfree(result);
478 result = NULL;
480 pstr_sprintf(filter, "(&(objectClass=%s)(%s=%lu))",
481 LDAP_OBJ_IDMAP_ENTRY, type,
482 ((id_type & ID_USERID) ? (unsigned long)id.uid :
483 (unsigned long)id.gid));
485 pstrcpy( suffix, lp_ldap_idmap_suffix() );
487 rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE,
488 filter, attr_list, 0, &result);
490 if (rc != LDAP_SUCCESS) {
491 DEBUG(3,("ldap_get_isd_from_id: Failure looking up entry (%s)\n",
492 ldap_err2string(rc) ));
493 goto out;
496 count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
498 if (count != 1) {
499 DEBUG(0,("ldap_get_sid_from_id: mapping not found for %s: %lu\n",
500 type, ((id_type & ID_USERID) ? (unsigned long)id.uid :
501 (unsigned long)id.gid)));
502 goto out;
506 entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
508 if ( !smbldap_get_single_attribute(ldap_state.smbldap_state->ldap_struct, entry, LDAP_ATTRIBUTE_SID, sid_str) )
509 goto out;
511 if (!string_to_sid(sid, sid_str))
512 goto out;
514 ret = NT_STATUS_OK;
515 out:
516 free_attr_list( attr_list );
518 if (result)
519 ldap_msgfree(result);
521 return ret;
524 /***********************************************************************
525 Get an id from a sid
526 ***********************************************************************/
528 static NTSTATUS ldap_get_id_from_sid(unid_t *id, int *id_type, const DOM_SID *sid)
530 LDAPMessage *result = NULL;
531 LDAPMessage *entry = NULL;
532 pstring sid_str;
533 pstring filter;
534 pstring id_str;
535 const char *suffix;
536 const char *type;
537 int rc;
538 int count;
539 char **attr_list;
540 char *dn = NULL;
541 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
543 sid_to_string(sid_str, sid);
545 DEBUG(8,("ldap_get_id_from_sid: %s (%s)\n", sid_str,
546 (*id_type & ID_GROUPID ? "group" : "user") ));
548 /* ahhh.... ok. We have to check users and groups in places other
549 than idmap (hint: we're a domain member of a Samba domain) */
551 if ( *id_type & ID_GROUPID ) {
553 type = get_attr_key2string( sidmap_attr_list, LDAP_ATTR_GIDNUMBER );
554 suffix = lp_ldap_group_suffix();
555 pstr_sprintf(filter, "(&(|(objectClass=%s)(objectClass=%s))(%s=%s))",
556 LDAP_OBJ_GROUPMAP, LDAP_OBJ_IDMAP_ENTRY,
557 get_attr_key2string( sidmap_attr_list, LDAP_ATTR_SID ),
558 sid_str);
561 else {
563 type = get_attr_key2string( sidmap_attr_list, LDAP_ATTR_UIDNUMBER );
564 suffix = lp_ldap_suffix();
565 pstr_sprintf(filter, "(&(|(&(objectClass=%s)(objectClass=%s))(objectClass=%s))(%s=%s))",
566 LDAP_OBJ_SAMBASAMACCOUNT, LDAP_OBJ_POSIXACCOUNT, LDAP_OBJ_IDMAP_ENTRY,
567 get_attr_key2string( sidmap_attr_list, LDAP_ATTR_SID ),
568 sid_str);
572 DEBUG(10,("ldap_get_id_from_sid: Searching for \"%s\"\n", filter));
574 /* do the search and check for errors */
576 attr_list = get_attr_list( sidmap_attr_list );
577 rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE,
578 filter, attr_list, 0, &result);
580 if ( rc != LDAP_SUCCESS ) {
581 DEBUG(3,("ldap_get_id_from_sid: Failure looking up group mapping (%s)\n",
582 ldap_err2string(rc) ));
583 goto out;
586 count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
588 if ( count > 1 ) {
589 DEBUG(3,("ldap_get_id_from_sid: search \"%s\" returned [%d] entries. Bailing...\n",
590 filter, count));
591 goto out;
594 /* see if we need to do a search here */
596 if ( count == 0 ) {
598 if ( result ) {
599 ldap_msgfree(result);
600 result = NULL;
603 /* look in idmap suffix */
605 suffix = lp_ldap_idmap_suffix();
606 pstr_sprintf(filter, "(&(objectClass=%s)(%s=%s))",
607 LDAP_OBJ_IDMAP_ENTRY, LDAP_ATTRIBUTE_SID, sid_str);
609 rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE,
610 filter, attr_list, 0, &result);
612 if (rc != LDAP_SUCCESS) {
613 DEBUG(3,("ldap_get_id_from_sid: Failure looking up idmap entry (%s)\n",
614 ldap_err2string(rc) ));
615 goto out;
618 /* check for the number of entries returned */
620 count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
622 if ( count > 1 ) {
623 DEBUG(0, ("ldap_get_id_from_sid: (2nd) search %s returned [%d] entries!\n",
624 filter, count));
625 goto out;
629 /* try to allocate a new id if we still haven't found one */
631 if ( (count==0) && !(*id_type & ID_QUERY_ONLY) ) {
632 int i;
634 DEBUG(8,("ldap_get_id_from_sid: Allocating new id\n"));
636 for (i = 0; i < LDAP_MAX_ALLOC_ID; i++) {
637 ret = ldap_allocate_id(id, *id_type);
638 if ( NT_STATUS_IS_OK(ret) )
639 break;
642 if ( !NT_STATUS_IS_OK(ret) ) {
643 DEBUG(0,("ldap_allocate_id: cannot acquire id lock!\n"));
644 goto out;
647 DEBUG(10,("ldap_get_id_from_sid: Allocated new %cid [%ul]\n",
648 (*id_type & ID_GROUPID ? 'g' : 'u'), (uint32)id->uid ));
650 ret = ldap_set_mapping(sid, *id, *id_type);
652 /* all done */
654 goto out;
658 DEBUG(10,("ldap_get_id_from_sid: success\n"));
660 entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
662 dn = smbldap_get_dn(ldap_state.smbldap_state->ldap_struct, result);
663 if (!dn)
664 goto out;
666 DEBUG(10, ("Found mapping entry at dn=%s, looking for %s\n", dn, type));
668 if ( smbldap_get_single_attribute(ldap_state.smbldap_state->ldap_struct, entry, type, id_str) ) {
669 if ( (*id_type & ID_USERID) )
670 id->uid = strtoul(id_str, NULL, 10);
671 else
672 id->gid = strtoul(id_str, NULL, 10);
674 ret = NT_STATUS_OK;
675 goto out;
678 out:
679 free_attr_list( attr_list );
680 if (result)
681 ldap_msgfree(result);
682 SAFE_FREE(dn);
684 return ret;
687 /***********************************************************************
688 This function cannot be called to modify a mapping, only set a new one
690 This takes a possible pointer to the existing entry for the UID or SID
691 involved.
692 ***********************************************************************/
694 static NTSTATUS ldap_set_mapping_internals(const DOM_SID *sid, unid_t id,
695 int id_type, const char *ldap_dn,
696 LDAPMessage *entry)
698 pstring dn;
699 pstring id_str;
700 fstring type;
701 LDAPMod **mods = NULL;
702 int rc = -1;
703 int ldap_op;
704 fstring sid_string;
705 char **values = NULL;
706 int i;
708 sid_to_string( sid_string, sid );
710 if (ldap_dn) {
711 DEBUG(10, ("Adding new IDMAP mapping on DN: %s", ldap_dn));
712 ldap_op = LDAP_MOD_REPLACE;
713 pstrcpy( dn, ldap_dn );
714 } else {
715 ldap_op = LDAP_MOD_ADD;
716 pstr_sprintf(dn, "%s=%s,%s", get_attr_key2string( sidmap_attr_list, LDAP_ATTR_SID),
717 sid_string, lp_ldap_idmap_suffix());
720 if ( id_type & ID_USERID )
721 fstrcpy( type, get_attr_key2string( sidmap_attr_list, LDAP_ATTR_UIDNUMBER ) );
722 else
723 fstrcpy( type, get_attr_key2string( sidmap_attr_list, LDAP_ATTR_GIDNUMBER ) );
725 pstr_sprintf(id_str, "%lu", ((id_type & ID_USERID) ? (unsigned long)id.uid :
726 (unsigned long)id.gid));
728 if (entry)
729 values = ldap_get_values(ldap_state.smbldap_state->ldap_struct, entry, "objectClass");
731 if (values) {
732 BOOL found_idmap = False;
733 for (i=0; values[i]; i++) {
734 if (StrCaseCmp(values[i], LDAP_OBJ_IDMAP_ENTRY) == 0) {
735 found_idmap = True;
736 break;
739 if (!found_idmap)
740 smbldap_set_mod( &mods, LDAP_MOD_ADD,
741 "objectClass", LDAP_OBJ_IDMAP_ENTRY );
742 } else {
743 smbldap_set_mod( &mods, LDAP_MOD_ADD,
744 "objectClass", LDAP_OBJ_IDMAP_ENTRY );
747 smbldap_make_mod( ldap_state.smbldap_state->ldap_struct,
748 entry, &mods, type, id_str );
750 smbldap_make_mod( ldap_state.smbldap_state->ldap_struct,
751 entry, &mods,
752 get_attr_key2string(sidmap_attr_list, LDAP_ATTR_SID),
753 sid_string );
755 /* There may well be nothing at all to do */
756 if (mods) {
757 switch(ldap_op)
759 case LDAP_MOD_ADD:
760 smbldap_set_mod( &mods, LDAP_MOD_ADD,
761 "objectClass", LDAP_OBJ_SID_ENTRY );
762 rc = smbldap_add(ldap_state.smbldap_state, dn, mods);
763 break;
764 case LDAP_MOD_REPLACE:
765 rc = smbldap_modify(ldap_state.smbldap_state, dn, mods);
766 break;
769 ldap_mods_free( mods, True );
770 } else {
771 rc = LDAP_SUCCESS;
774 if (rc != LDAP_SUCCESS) {
775 char *ld_error = NULL;
776 ldap_get_option(ldap_state.smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
777 &ld_error);
778 DEBUG(0,("ldap_set_mapping_internals: Failed to %s mapping from %s to %lu [%s]\n",
779 (ldap_op == LDAP_MOD_ADD) ? "add" : "replace",
780 sid_string, (unsigned long)((id_type & ID_USERID) ? id.uid : id.gid), type));
781 DEBUG(0, ("ldap_set_mapping_internals: Error was: %s (%s)\n", ld_error ? ld_error : "(NULL)", ldap_err2string (rc)));
782 return NT_STATUS_UNSUCCESSFUL;
785 DEBUG(10,("ldap_set_mapping: Successfully created mapping from %s to %lu [%s]\n",
786 sid_string, ((id_type & ID_USERID) ? (unsigned long)id.uid :
787 (unsigned long)id.gid), type));
789 return NT_STATUS_OK;
792 /***********************************************************************
793 This function cannot be called to modify a mapping, only set a new one
794 ***********************************************************************/
796 static NTSTATUS ldap_set_mapping(const DOM_SID *sid, unid_t id, int id_type)
798 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
799 char *dn = NULL;
800 LDAPMessage *result = NULL;
801 LDAPMessage *entry = NULL;
802 const char *type;
803 const char *obj_class;
804 const char *posix_obj_class;
805 const char *suffix;
806 fstring sid_str;
807 fstring id_str;
808 pstring filter;
809 char **attr_list;
810 int rc;
811 int count;
813 /* try for a samba user or group mapping (looking for an entry with a SID) */
814 if ( id_type & ID_USERID ) {
815 obj_class = LDAP_OBJ_SAMBASAMACCOUNT;
816 suffix = lp_ldap_suffix();
817 type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_UIDNUMBER );
818 posix_obj_class = LDAP_OBJ_POSIXACCOUNT;
819 fstr_sprintf(id_str, "%lu", (unsigned long)id.uid );
821 else {
822 obj_class = LDAP_OBJ_GROUPMAP;
823 suffix = lp_ldap_group_suffix();
824 type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_GIDNUMBER );
825 posix_obj_class = LDAP_OBJ_POSIXGROUP;
826 fstr_sprintf(id_str, "%lu", (unsigned long)id.gid );
829 sid_to_string(sid_str, sid);
830 pstr_sprintf(filter,
831 "(|"
832 "(&(|(objectClass=%s)(|(objectClass=%s)(objectClass=%s)))(%s=%s))"
833 "(&(objectClass=%s)(%s=%s))"
834 ")",
835 /* objectClasses that might contain a SID */
836 LDAP_OBJ_SID_ENTRY, LDAP_OBJ_IDMAP_ENTRY, obj_class,
837 get_attr_key2string( sidmap_attr_list, LDAP_ATTR_SID ),
838 sid_str,
840 /* objectClasses that might contain a Unix UID/GID */
841 posix_obj_class,
842 /* Unix UID/GID specifier*/
843 type,
844 /* actual ID */
845 id_str);
847 attr_list = get_attr_list( sidmap_attr_list );
848 rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE,
849 filter, attr_list, 0, &result);
850 free_attr_list( attr_list );
852 if (rc != LDAP_SUCCESS)
853 goto out;
855 count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
857 /* fall back to looking up an idmap entry if we didn't find anything under the idmap
858 user or group suffix */
860 if (count == 1) {
861 entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
863 dn = smbldap_get_dn(ldap_state.smbldap_state->ldap_struct, result);
864 if (!dn)
865 goto out;
866 DEBUG(10, ("Found partial mapping entry at dn=%s, looking for %s\n", dn, type));
868 ret = ldap_set_mapping_internals(sid, id, id_type, dn, entry);
870 goto out;
871 } else if (count > 1) {
872 DEBUG(0, ("Too many entries trying to find DN to attach ldap \n"));
873 goto out;
876 ret = ldap_set_mapping_internals(sid, id, id_type, NULL, NULL);
878 out:
879 if (result)
880 ldap_msgfree(result);
881 SAFE_FREE(dn);
883 return ret;
887 /**********************************************************************
888 Verify the sambaUnixIdPool entry in the directiry.
889 **********************************************************************/
891 static NTSTATUS verify_idpool( void )
893 fstring filter;
894 int rc;
895 char **attr_list;
896 LDAPMessage *result = NULL;
897 LDAPMod **mods = NULL;
898 int count;
900 fstr_sprintf( filter, "(objectclass=%s)", LDAP_OBJ_IDPOOL );
902 attr_list = get_attr_list( idpool_attr_list );
903 rc = smbldap_search(ldap_state.smbldap_state, lp_ldap_idmap_suffix(),
904 LDAP_SCOPE_SUBTREE, filter, attr_list, 0, &result);
905 free_attr_list ( attr_list );
907 if (rc != LDAP_SUCCESS)
908 return NT_STATUS_UNSUCCESSFUL;
910 count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
912 if ( count > 1 ) {
913 DEBUG(0,("ldap_idmap_init: multiple entries returned from %s (base == %s)\n",
914 filter, lp_ldap_idmap_suffix() ));
915 return NT_STATUS_UNSUCCESSFUL;
917 else if (count == 0) {
918 uid_t luid, huid;
919 gid_t lgid, hgid;
920 fstring uid_str, gid_str;
922 if ( !lp_idmap_uid(&luid, &huid) || !lp_idmap_gid( &lgid, &hgid ) ) {
923 DEBUG(0,("ldap_idmap_init: idmap uid/gid parameters not specified\n"));
924 return NT_STATUS_UNSUCCESSFUL;
927 fstr_sprintf( uid_str, "%lu", (unsigned long)luid );
928 fstr_sprintf( gid_str, "%lu", (unsigned long)lgid );
930 smbldap_set_mod( &mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_IDPOOL );
931 smbldap_set_mod( &mods, LDAP_MOD_ADD,
932 get_attr_key2string(idpool_attr_list, LDAP_ATTR_UIDNUMBER), uid_str );
933 smbldap_set_mod( &mods, LDAP_MOD_ADD,
934 get_attr_key2string(idpool_attr_list, LDAP_ATTR_GIDNUMBER), gid_str );
936 rc = smbldap_modify(ldap_state.smbldap_state, lp_ldap_idmap_suffix(), mods);
939 return ( rc==LDAP_SUCCESS ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
942 /*****************************************************************************
943 Initialise idmap database.
944 *****************************************************************************/
946 static NTSTATUS ldap_idmap_init( char *params )
948 NTSTATUS nt_status;
950 ldap_state.mem_ctx = talloc_init("idmap_ldap");
951 if (!ldap_state.mem_ctx) {
952 return NT_STATUS_NO_MEMORY;
955 /* assume location is the only parameter */
956 if (!NT_STATUS_IS_OK(nt_status =
957 smbldap_init(ldap_state.mem_ctx, params,
958 &ldap_state.smbldap_state))) {
959 talloc_destroy(ldap_state.mem_ctx);
960 return nt_status;
963 /* see if the idmap suffix and sub entries exists */
965 nt_status = verify_idpool();
966 if ( !NT_STATUS_IS_OK(nt_status) )
967 return nt_status;
969 return NT_STATUS_OK;
972 /*****************************************************************************
973 End the LDAP session
974 *****************************************************************************/
976 static NTSTATUS ldap_idmap_close(void)
979 smbldap_free_struct(&(ldap_state).smbldap_state);
980 talloc_destroy(ldap_state.mem_ctx);
982 DEBUG(5,("The connection to the LDAP server was closed\n"));
983 /* maybe free the results here --metze */
985 return NT_STATUS_OK;
989 /* This function doesn't make as much sense in an LDAP world since the calling
990 node doesn't really control the ID ranges */
991 static void ldap_idmap_status(void)
993 DEBUG(0, ("LDAP IDMAP Status not available\n"));
996 static struct idmap_methods ldap_methods = {
997 ldap_idmap_init,
998 ldap_allocate_rid,
999 ldap_allocate_id,
1000 ldap_get_sid_from_id,
1001 ldap_get_id_from_sid,
1002 ldap_set_mapping,
1003 ldap_idmap_close,
1004 ldap_idmap_status
1008 NTSTATUS idmap_ldap_init(void)
1010 return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "ldap", &ldap_methods);