Only set sids when they're retrurned by the MySQL query
[Samba/gebeck_regimport.git] / source / sam / idmap_ldap.c
blob6122641718666dfe346ea6a027c0aac55e019f73
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 *********************************************************************/
107 static NTSTATUS ldap_next_rid(struct ldap_idmap_state *state, uint32 *rid,
108 int rid_type)
110 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
111 int rc;
112 LDAPMessage *domain_result = NULL;
113 LDAPMessage *entry = NULL;
114 char *dn;
115 LDAPMod **mods = NULL;
116 fstring old_rid_string;
117 fstring next_rid_string;
118 fstring algorithmic_rid_base_string;
119 uint32 next_rid;
120 uint32 alg_rid_base;
121 int attempts = 0;
122 char *ld_error = NULL;
124 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)))
129 return ret;
132 entry = ldap_first_entry(state->smbldap_state->ldap_struct, domain_result);
133 if (!entry) {
134 DEBUG(0, ("Could not get domain info entry\n"));
135 ldap_msgfree(domain_result);
136 return ret;
139 if ((dn = ldap_get_dn(state->smbldap_state->ldap_struct, entry)) == NULL) {
140 DEBUG(0, ("Could not get domain info DN\n"));
141 ldap_msgfree(domain_result);
142 return ret;
145 /* yes, we keep 3 seperate counters, one for rids between 1000 (BASE_RID) and
146 algorithmic_rid_base. The other two are to avoid stomping on the
147 different sets of algorithmic RIDs */
149 if (smbldap_get_single_attribute(state->smbldap_state->ldap_struct, entry,
150 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_ALGORITHMIC_RID_BASE),
151 algorithmic_rid_base_string))
154 alg_rid_base = (uint32)atol(algorithmic_rid_base_string);
155 } else {
156 alg_rid_base = algorithmic_rid_base();
157 /* Try to make the modification atomically by enforcing the
158 old value in the delete mod. */
159 slprintf(algorithmic_rid_base_string, sizeof(algorithmic_rid_base_string)-1, "%d", alg_rid_base);
160 smbldap_make_mod(state->smbldap_state->ldap_struct, entry, &mods,
161 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_ALGORITHMIC_RID_BASE),
162 algorithmic_rid_base_string);
165 next_rid = 0;
167 if (alg_rid_base > BASE_RID) {
168 /* we have a non-default 'algorithmic rid base', so we have 'low' rids that we
169 can allocate to new users */
170 if (smbldap_get_single_attribute(state->smbldap_state->ldap_struct, entry,
171 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_RID),
172 old_rid_string))
174 *rid = (uint32)atol(old_rid_string);
175 } else {
176 *rid = BASE_RID;
179 next_rid = *rid+1;
180 if (next_rid >= alg_rid_base) {
181 return NT_STATUS_UNSUCCESSFUL;
184 slprintf(next_rid_string, sizeof(next_rid_string)-1, "%d", next_rid);
186 /* Try to make the modification atomically by enforcing the
187 old value in the delete mod. */
188 smbldap_make_mod(state->smbldap_state->ldap_struct, entry, &mods,
189 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_RID),
190 next_rid_string);
193 if (!next_rid) { /* not got one already */
194 switch (rid_type) {
195 case USER_RID_TYPE:
196 if (smbldap_get_single_attribute(state->smbldap_state->ldap_struct, entry,
197 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_USERRID),
198 old_rid_string))
200 *rid = (uint32)atol(old_rid_string);
202 break;
203 case GROUP_RID_TYPE:
204 if (smbldap_get_single_attribute(state->smbldap_state->ldap_struct, entry,
205 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_GROUPRID),
206 old_rid_string))
208 *rid = (uint32)atol(old_rid_string);
210 break;
213 /* This is the core of the whole routine. If we had
214 scheme-style closures, there would be a *lot* less code
215 duplication... */
217 next_rid = *rid+RID_MULTIPLIER;
218 slprintf(next_rid_string, sizeof(next_rid_string)-1, "%d", next_rid);
220 switch (rid_type) {
221 case USER_RID_TYPE:
222 /* Try to make the modification atomically by enforcing the
223 old value in the delete mod. */
224 smbldap_make_mod(state->smbldap_state->ldap_struct, entry, &mods,
225 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_USERRID),
226 next_rid_string);
227 break;
229 case GROUP_RID_TYPE:
230 /* Try to make the modification atomically by enforcing the
231 old value in the delete mod. */
232 smbldap_make_mod(state->smbldap_state->ldap_struct, entry, &mods,
233 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_GROUPRID),
234 next_rid_string);
235 break;
239 if ((rc = ldap_modify_s(state->smbldap_state->ldap_struct, dn, mods)) == LDAP_SUCCESS) {
240 DOM_SID dom_sid;
241 DOM_SID sid;
242 pstring domain_sid_string;
243 int error = 0;
245 if (!smbldap_get_single_attribute(state->smbldap_state->ldap_struct, domain_result,
246 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOM_SID),
247 domain_sid_string))
249 ldap_mods_free(mods, True);
250 ldap_memfree(dn);
251 ldap_msgfree(domain_result);
252 return ret;
255 if (!string_to_sid(&dom_sid, domain_sid_string)) {
256 ldap_mods_free(mods, True);
257 ldap_memfree(dn);
258 ldap_msgfree(domain_result);
259 return ret;
262 ldap_mods_free(mods, True);
263 mods = NULL;
264 ldap_memfree(dn);
265 ldap_msgfree(domain_result);
267 sid_copy(&sid, &dom_sid);
268 sid_append_rid(&sid, *rid);
270 /* check RID is not in use */
271 if (sid_in_use(state, &sid, &error)) {
272 if (error) {
273 return ret;
275 continue;
278 return NT_STATUS_OK;
281 ld_error = NULL;
282 ldap_get_option(state->smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error);
283 DEBUG(2, ("Failed to modify rid: %s\n", ld_error ? ld_error : "(NULL"));
284 SAFE_FREE(ld_error);
286 ldap_mods_free(mods, True);
287 mods = NULL;
289 ldap_memfree(dn);
290 dn = NULL;
292 ldap_msgfree(domain_result);
293 domain_result = NULL;
296 /* Sleep for a random timeout */
297 unsigned sleeptime = (sys_random()*sys_getpid()*attempts);
298 attempts += 1;
300 sleeptime %= 100;
301 msleep(sleeptime);
305 DEBUG(0, ("Failed to set new RID\n"));
306 return ret;
310 /*****************************************************************************
311 Allocate a new RID
312 *****************************************************************************/
314 static NTSTATUS ldap_allocate_rid(uint32 *rid, int rid_type)
316 return ldap_next_rid( &ldap_state, rid, rid_type );
319 /*****************************************************************************
320 Allocate a new uid or gid
321 *****************************************************************************/
323 static NTSTATUS ldap_allocate_id(unid_t *id, int id_type)
325 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
326 int rc = LDAP_SERVER_DOWN;
327 int count = 0;
328 LDAPMessage *result = NULL;
329 LDAPMessage *entry = NULL;
330 pstring id_str, new_id_str;
331 LDAPMod **mods = NULL;
332 const char *type;
333 char *dn;
334 char **attr_list;
335 pstring filter;
336 uid_t luid, huid;
337 gid_t lgid, hgid;
340 type = (id_type & ID_USERID) ?
341 get_attr_key2string( idpool_attr_list, LDAP_ATTR_UIDNUMBER ) :
342 get_attr_key2string( idpool_attr_list, LDAP_ATTR_GIDNUMBER );
344 pstr_sprintf(filter, "(objectClass=%s)", LDAP_OBJ_IDPOOL);
346 attr_list = get_attr_list( idpool_attr_list );
348 rc = smbldap_search(ldap_state.smbldap_state, lp_ldap_idmap_suffix(),
349 LDAP_SCOPE_SUBTREE, filter,
350 attr_list, 0, &result);
351 free_attr_list( attr_list );
353 if (rc != LDAP_SUCCESS) {
354 DEBUG(0,("ldap_allocate_id: %s object not found\n", LDAP_OBJ_IDPOOL));
355 goto out;
358 count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
359 if (count != 1) {
360 DEBUG(0,("ldap_allocate_id: single %s object not found\n", LDAP_OBJ_IDPOOL));
361 goto out;
364 dn = ldap_get_dn(ldap_state.smbldap_state->ldap_struct, result);
365 entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
367 if (!smbldap_get_single_attribute(ldap_state.smbldap_state->ldap_struct, entry, type, id_str)) {
368 DEBUG(0,("ldap_allocate_id: %s attribute not found\n",
369 type));
370 goto out;
373 /* this must succeed or else we wouldn't have initialized */
375 lp_idmap_uid( &luid, &huid);
376 lp_idmap_gid( &lgid, &hgid);
378 /* make sure we still have room to grow */
380 if (id_type & ID_USERID) {
381 id->uid = strtoul(id_str, NULL, 10);
382 if (id->uid > huid ) {
383 DEBUG(0,("ldap_allocate_id: Cannot allocate uid above %lu!\n",
384 (unsigned long)huid));
385 goto out;
388 else {
389 id->gid = strtoul(id_str, NULL, 10);
390 if (id->gid > hgid ) {
391 DEBUG(0,("ldap_allocate_id: Cannot allocate gid above %lu!\n",
392 (unsigned long)hgid));
393 goto out;
397 pstr_sprintf(new_id_str, "%lu",
398 ((id_type & ID_USERID) ? (unsigned long)id->uid :
399 (unsigned long)id->gid) + 1);
401 smbldap_set_mod( &mods, LDAP_MOD_DELETE, type, id_str );
402 smbldap_set_mod( &mods, LDAP_MOD_ADD, type, new_id_str );
404 rc = ldap_modify_s(ldap_state.smbldap_state->ldap_struct, dn, mods);
406 ldap_memfree(dn);
407 ldap_mods_free( mods, True );
409 if (rc != LDAP_SUCCESS) {
410 DEBUG(0,("ldap_allocate_id: Failed to allocate new %s. ldap_modify() failed.\n",
411 type));
412 goto out;
415 ret = NT_STATUS_OK;
416 out:
417 return ret;
420 /*****************************************************************************
421 get a sid from an id
422 *****************************************************************************/
424 static NTSTATUS ldap_get_sid_from_id(DOM_SID *sid, unid_t id, int id_type)
426 LDAPMessage *result = NULL;
427 LDAPMessage *entry = NULL;
428 fstring id_str;
429 pstring sid_str;
430 pstring filter;
431 pstring suffix;
432 const char *type;
433 const char *obj_class;
434 int rc;
435 int count;
436 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
437 char **attr_list;
439 /* first we try for a samba user or group mapping */
441 if ( id_type & ID_USERID ) {
442 type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_UIDNUMBER );
443 obj_class = LDAP_OBJ_SAMBASAMACCOUNT;
444 fstr_sprintf(id_str, "%lu", (unsigned long)id.uid );
445 pstrcpy( suffix, lp_ldap_suffix());
447 else {
448 type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_GIDNUMBER );
449 obj_class = LDAP_OBJ_GROUPMAP;
450 fstr_sprintf(id_str, "%lu", (unsigned long)id.gid );
451 pstrcpy( suffix, lp_ldap_group_suffix() );
454 DEBUG(5,("ldap_get_sid_from_id: Searching \"%s\"\n", filter ));
456 attr_list = get_attr_list( sidmap_attr_list );
457 pstr_sprintf(filter, "(&(|(objectClass=%s)(objectClass=%s))(%s=%s))",
458 LDAP_OBJ_IDMAP_ENTRY, obj_class, type, id_str);
460 rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE,
461 filter, attr_list, 0, &result);
463 if (rc != LDAP_SUCCESS) {
464 DEBUG(3,("ldap_get_isd_from_id: Failure looking up entry (%s)\n",
465 ldap_err2string(rc) ));
466 goto out;
469 count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
471 if (count > 1) {
472 DEBUG(0,("ldap_get_sid_from_id: mapping returned [%d] entries!\n",
473 count));
474 goto out;
477 /* fall back to looking up an idmap entry if we didn't find and
478 actual user or group */
480 if (count == 0) {
481 ldap_msgfree(result);
482 result = NULL;
484 pstr_sprintf(filter, "(&(objectClass=%s)(%s=%lu))",
485 LDAP_OBJ_IDMAP_ENTRY, type,
486 ((id_type & ID_USERID) ? (unsigned long)id.uid :
487 (unsigned long)id.gid));
489 pstrcpy( suffix, lp_ldap_idmap_suffix() );
491 rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE,
492 filter, attr_list, 0, &result);
494 if (rc != LDAP_SUCCESS) {
495 DEBUG(3,("ldap_get_isd_from_id: Failure looking up entry (%s)\n",
496 ldap_err2string(rc) ));
497 goto out;
500 count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
502 if (count != 1) {
503 DEBUG(0,("ldap_get_sid_from_id: mapping not found for %s: %lu\n",
504 type, ((id_type & ID_USERID) ? (unsigned long)id.uid :
505 (unsigned long)id.gid)));
506 goto out;
510 entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
512 if ( !smbldap_get_single_attribute(ldap_state.smbldap_state->ldap_struct, entry, LDAP_ATTRIBUTE_SID, sid_str) )
513 goto out;
515 if (!string_to_sid(sid, sid_str))
516 goto out;
518 ret = NT_STATUS_OK;
519 out:
520 free_attr_list( attr_list );
522 if (result)
523 ldap_msgfree(result);
525 return ret;
528 /***********************************************************************
529 Get an id from a sid
530 ***********************************************************************/
532 static NTSTATUS ldap_get_id_from_sid(unid_t *id, int *id_type, const DOM_SID *sid)
534 LDAPMessage *result = NULL;
535 LDAPMessage *entry = NULL;
536 pstring sid_str;
537 pstring filter;
538 pstring id_str;
539 const char *suffix;
540 const char *type;
541 int rc;
542 int count;
543 char **attr_list;
544 char *dn = NULL;
545 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
547 sid_to_string(sid_str, sid);
549 DEBUG(8,("ldap_get_id_from_sid: %s (%s)\n", sid_str,
550 (*id_type & ID_GROUPID ? "group" : "user") ));
552 /* ahhh.... ok. We have to check users and groups in places other
553 than idmap (hint: we're a domain member of a Samba domain) */
555 if ( *id_type & ID_GROUPID ) {
557 type = get_attr_key2string( sidmap_attr_list, LDAP_ATTR_GIDNUMBER );
558 suffix = lp_ldap_group_suffix();
559 pstr_sprintf(filter, "(&(|(objectClass=%s)(objectClass=%s))(%s=%s))",
560 LDAP_OBJ_GROUPMAP, LDAP_OBJ_IDMAP_ENTRY,
561 get_attr_key2string( sidmap_attr_list, LDAP_ATTR_SID ),
562 sid_str);
565 else {
567 type = get_attr_key2string( sidmap_attr_list, LDAP_ATTR_UIDNUMBER );
568 suffix = lp_ldap_suffix();
569 pstr_sprintf(filter, "(&(|(&(objectClass=%s)(objectClass=%s))(objectClass=%s))(%s=%s))",
570 LDAP_OBJ_SAMBASAMACCOUNT, LDAP_OBJ_POSIXACCOUNT, LDAP_OBJ_IDMAP_ENTRY,
571 get_attr_key2string( sidmap_attr_list, LDAP_ATTR_SID ),
572 sid_str);
576 DEBUG(10,("ldap_get_id_from_sid: Searching for \"%s\"\n", filter));
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 group mapping (%s)\n",
586 ldap_err2string(rc) ));
587 goto out;
590 count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
592 if ( count > 1 ) {
593 DEBUG(3,("ldap_get_id_from_sid: search \"%s\" returned [%d] entries. Bailing...\n",
594 filter, count));
595 goto out;
598 /* see if we need to do a search here */
600 if ( count == 0 ) {
602 if ( result ) {
603 ldap_msgfree(result);
604 result = NULL;
607 /* look in idmap suffix */
609 suffix = lp_ldap_idmap_suffix();
610 pstr_sprintf(filter, "(&(objectClass=%s)(%s=%s))",
611 LDAP_OBJ_IDMAP_ENTRY, LDAP_ATTRIBUTE_SID, sid_str);
613 rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE,
614 filter, attr_list, 0, &result);
616 if (rc != LDAP_SUCCESS) {
617 DEBUG(3,("ldap_get_id_from_sid: Failure looking up idmap entry (%s)\n",
618 ldap_err2string(rc) ));
619 goto out;
622 /* check for the number of entries returned */
624 count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
626 if ( count > 1 ) {
627 DEBUG(0, ("ldap_get_id_from_sid: (2nd) search %s returned [%d] entries!\n",
628 filter, count));
629 goto out;
633 /* try to allocate a new id if we still haven't found one */
635 if ( (count==0) && !(*id_type & ID_QUERY_ONLY) ) {
636 int i;
638 DEBUG(8,("ldap_get_id_from_sid: Allocating new id\n"));
640 for (i = 0; i < LDAP_MAX_ALLOC_ID; i++) {
641 ret = ldap_allocate_id(id, *id_type);
642 if ( NT_STATUS_IS_OK(ret) )
643 break;
646 if ( !NT_STATUS_IS_OK(ret) ) {
647 DEBUG(0,("ldap_allocate_id: cannot acquire id lock!\n"));
648 goto out;
651 DEBUG(10,("ldap_get_id_from_sid: Allocated new %cid [%ul]\n",
652 (*id_type & ID_GROUPID ? 'g' : 'u'), (uint32)id->uid ));
654 ret = ldap_set_mapping(sid, *id, *id_type);
656 /* all done */
658 goto out;
662 DEBUG(10,("ldap_get_id_from_sid: success\n"));
664 entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
666 dn = ldap_get_dn(ldap_state.smbldap_state->ldap_struct, result);
668 DEBUG(10, ("Found mapping entry at dn=%s, looking for %s\n", dn, type));
670 if ( smbldap_get_single_attribute(ldap_state.smbldap_state->ldap_struct, entry, type, id_str) )
672 if ( (*id_type & ID_USERID) )
673 id->uid = strtoul(id_str, NULL, 10);
674 else
675 id->gid = strtoul(id_str, NULL, 10);
677 ret = NT_STATUS_OK;
678 goto out;
681 out:
682 free_attr_list( attr_list );
683 if (result)
684 ldap_msgfree(result);
685 if (dn)
686 ldap_memfree(dn);
688 return ret;
691 /***********************************************************************
692 This function cannot be called to modify a mapping, only set a new one
694 This takes a possible pointer to the existing entry for the UID or SID
695 involved.
696 ***********************************************************************/
698 static NTSTATUS ldap_set_mapping_internals(const DOM_SID *sid, unid_t id,
699 int id_type, const char *ldap_dn,
700 LDAPMessage *entry)
702 pstring dn;
703 pstring id_str;
704 fstring type;
705 LDAPMod **mods = NULL;
706 int rc = -1;
707 int ldap_op;
708 fstring sid_string;
709 char **values = NULL;
710 int i;
712 sid_to_string( sid_string, sid );
714 if (ldap_dn) {
715 DEBUG(10, ("Adding new IDMAP mapping on DN: %s", ldap_dn));
716 ldap_op = LDAP_MOD_REPLACE;
717 pstrcpy( dn, ldap_dn );
718 } else {
719 ldap_op = LDAP_MOD_ADD;
720 pstr_sprintf(dn, "%s=%s,%s", get_attr_key2string( sidmap_attr_list, LDAP_ATTR_SID),
721 sid_string, lp_ldap_idmap_suffix());
724 if ( id_type & ID_USERID )
725 fstrcpy( type, get_attr_key2string( sidmap_attr_list, LDAP_ATTR_UIDNUMBER ) );
726 else
727 fstrcpy( type, get_attr_key2string( sidmap_attr_list, LDAP_ATTR_GIDNUMBER ) );
729 pstr_sprintf(id_str, "%lu", ((id_type & ID_USERID) ? (unsigned long)id.uid :
730 (unsigned long)id.gid));
732 if (entry)
733 values = ldap_get_values(ldap_state.smbldap_state->ldap_struct, entry, "objectClass");
735 if (values) {
736 BOOL found_idmap = False;
737 for (i=0; values[i]; i++) {
738 if (StrCaseCmp(values[i], LDAP_OBJ_IDMAP_ENTRY) == 0) {
739 found_idmap = True;
740 break;
743 if (!found_idmap)
744 smbldap_set_mod( &mods, LDAP_MOD_ADD,
745 "objectClass", LDAP_OBJ_IDMAP_ENTRY );
746 } else {
747 smbldap_set_mod( &mods, LDAP_MOD_ADD,
748 "objectClass", LDAP_OBJ_IDMAP_ENTRY );
751 smbldap_make_mod( ldap_state.smbldap_state->ldap_struct,
752 entry, &mods, type, id_str );
754 smbldap_make_mod( ldap_state.smbldap_state->ldap_struct,
755 entry, &mods,
756 get_attr_key2string(sidmap_attr_list, LDAP_ATTR_SID),
757 sid_string );
759 /* There may well be nothing at all to do */
760 if (mods) {
761 switch(ldap_op)
763 case LDAP_MOD_ADD:
764 smbldap_set_mod( &mods, LDAP_MOD_ADD,
765 "objectClass", LDAP_OBJ_SID_ENTRY );
766 rc = smbldap_add(ldap_state.smbldap_state, dn, mods);
767 break;
768 case LDAP_MOD_REPLACE:
769 rc = smbldap_modify(ldap_state.smbldap_state, dn, mods);
770 break;
773 ldap_mods_free( mods, True );
774 } else {
775 rc = LDAP_SUCCESS;
778 if (rc != LDAP_SUCCESS) {
779 char *ld_error = NULL;
780 ldap_get_option(ldap_state.smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
781 &ld_error);
782 DEBUG(0,("ldap_set_mapping_internals: Failed to %s mapping from %s to %lu [%s]\n",
783 (ldap_op == LDAP_MOD_ADD) ? "add" : "replace",
784 sid_string, (unsigned long)((id_type & ID_USERID) ? id.uid : id.gid), type));
785 DEBUG(0, ("ldap_set_mapping_internals: Error was: %s (%s)\n", ld_error ? ld_error : "(NULL)", ldap_err2string (rc)));
786 return NT_STATUS_UNSUCCESSFUL;
789 DEBUG(10,("ldap_set_mapping: Successfully created mapping from %s to %lu [%s]\n",
790 sid_string, ((id_type & ID_USERID) ? (unsigned long)id.uid :
791 (unsigned long)id.gid), type));
793 return NT_STATUS_OK;
796 /***********************************************************************
797 This function cannot be called to modify a mapping, only set a new one
798 ***********************************************************************/
800 static NTSTATUS ldap_set_mapping(const DOM_SID *sid, unid_t id, int id_type)
802 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
803 char *dn = NULL;
804 LDAPMessage *result = NULL;
805 LDAPMessage *entry = NULL;
806 const char *type;
807 const char *obj_class;
808 const char *posix_obj_class;
809 const char *suffix;
810 fstring sid_str;
811 fstring id_str;
812 pstring filter;
813 char **attr_list;
814 int rc;
815 int count;
817 /* try for a samba user or group mapping (looking for an entry with a SID) */
818 if ( id_type & ID_USERID ) {
819 obj_class = LDAP_OBJ_SAMBASAMACCOUNT;
820 suffix = lp_ldap_suffix();
821 type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_UIDNUMBER );
822 posix_obj_class = LDAP_OBJ_POSIXACCOUNT;
823 fstr_sprintf(id_str, "%lu", (unsigned long)id.uid );
825 else {
826 obj_class = LDAP_OBJ_GROUPMAP;
827 suffix = lp_ldap_group_suffix();
828 type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_GIDNUMBER );
829 posix_obj_class = LDAP_OBJ_POSIXGROUP;
830 fstr_sprintf(id_str, "%lu", (unsigned long)id.gid );
833 sid_to_string(sid_str, sid);
834 pstr_sprintf(filter,
835 "(|"
836 "(&(|(objectClass=%s)(|(objectClass=%s)(objectClass=%s)))(%s=%s))"
837 "(&(objectClass=%s)(%s=%s))"
838 ")",
839 /* objectClasses that might contain a SID */
840 LDAP_OBJ_SID_ENTRY, LDAP_OBJ_IDMAP_ENTRY, obj_class,
841 get_attr_key2string( sidmap_attr_list, LDAP_ATTR_SID ),
842 sid_str,
844 /* objectClasses that might contain a Unix UID/GID */
845 posix_obj_class,
846 /* Unix UID/GID specifier*/
847 type,
848 /* actual ID */
849 id_str);
851 attr_list = get_attr_list( sidmap_attr_list );
852 rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE,
853 filter, attr_list, 0, &result);
854 free_attr_list( attr_list );
856 if (rc != LDAP_SUCCESS)
857 goto out;
859 count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
861 /* fall back to looking up an idmap entry if we didn't find anything under the idmap
862 user or group suffix */
864 if (count == 1) {
865 entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
867 dn = ldap_get_dn(ldap_state.smbldap_state->ldap_struct, result);
868 DEBUG(10, ("Found partial mapping entry at dn=%s, looking for %s\n", dn, type));
870 ret = ldap_set_mapping_internals(sid, id, id_type, dn, entry);
872 goto out;
873 } else if (count > 1) {
874 DEBUG(0, ("Too many entries trying to find DN to attach ldap \n"));
875 goto out;
878 ret = ldap_set_mapping_internals(sid, id, id_type, NULL, NULL);
880 out:
881 if (result)
882 ldap_msgfree(result);
883 if (dn)
884 ldap_memfree(dn);
886 return ret;
890 /**********************************************************************
891 Verify the sambaUnixIdPool entry in the directiry.
892 **********************************************************************/
894 static NTSTATUS verify_idpool( void )
896 fstring filter;
897 int rc;
898 char **attr_list;
899 LDAPMessage *result = NULL;
900 LDAPMod **mods = NULL;
901 int count;
903 fstr_sprintf( filter, "(objectclass=%s)", LDAP_OBJ_IDPOOL );
905 attr_list = get_attr_list( idpool_attr_list );
906 rc = smbldap_search(ldap_state.smbldap_state, lp_ldap_idmap_suffix(),
907 LDAP_SCOPE_SUBTREE, filter, attr_list, 0, &result);
908 free_attr_list ( attr_list );
910 if (rc != LDAP_SUCCESS)
911 return NT_STATUS_UNSUCCESSFUL;
913 count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
915 if ( count > 1 ) {
916 DEBUG(0,("ldap_idmap_init: multiple entries returned from %s (base == %s)\n",
917 filter, lp_ldap_idmap_suffix() ));
918 return NT_STATUS_UNSUCCESSFUL;
920 else if (count == 0) {
921 uid_t luid, huid;
922 gid_t lgid, hgid;
923 fstring uid_str, gid_str;
925 if ( !lp_idmap_uid(&luid, &huid) || !lp_idmap_gid( &lgid, &hgid ) ) {
926 DEBUG(0,("ldap_idmap_init: idmap uid/gid parameters not specified\n"));
927 return NT_STATUS_UNSUCCESSFUL;
930 fstr_sprintf( uid_str, "%lu", (unsigned long)luid );
931 fstr_sprintf( gid_str, "%lu", (unsigned long)lgid );
933 smbldap_set_mod( &mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_IDPOOL );
934 smbldap_set_mod( &mods, LDAP_MOD_ADD,
935 get_attr_key2string(idpool_attr_list, LDAP_ATTR_UIDNUMBER), uid_str );
936 smbldap_set_mod( &mods, LDAP_MOD_ADD,
937 get_attr_key2string(idpool_attr_list, LDAP_ATTR_GIDNUMBER), gid_str );
939 rc = smbldap_modify(ldap_state.smbldap_state, lp_ldap_idmap_suffix(), mods);
942 return ( rc==LDAP_SUCCESS ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
945 /*****************************************************************************
946 Initialise idmap database.
947 *****************************************************************************/
948 static NTSTATUS ldap_idmap_init( char *params )
950 NTSTATUS nt_status;
952 ldap_state.mem_ctx = talloc_init("idmap_ldap");
953 if (!ldap_state.mem_ctx) {
954 return NT_STATUS_NO_MEMORY;
957 /* assume location is the only parameter */
958 if (!NT_STATUS_IS_OK(nt_status =
959 smbldap_init(ldap_state.mem_ctx, params,
960 &ldap_state.smbldap_state))) {
961 talloc_destroy(ldap_state.mem_ctx);
962 return nt_status;
965 /* see if the idmap suffix and sub entries exists */
967 nt_status = verify_idpool();
968 if ( !NT_STATUS_IS_OK(nt_status) )
969 return nt_status;
971 return NT_STATUS_OK;
974 /*****************************************************************************
975 End the LDAP session
976 *****************************************************************************/
978 static NTSTATUS ldap_idmap_close(void)
981 smbldap_free_struct(&(ldap_state).smbldap_state);
982 talloc_destroy(ldap_state.mem_ctx);
984 DEBUG(5,("The connection to the LDAP server was closed\n"));
985 /* maybe free the results here --metze */
987 return NT_STATUS_OK;
991 /* This function doesn't make as much sense in an LDAP world since the calling
992 node doesn't really control the ID ranges */
993 static void ldap_idmap_status(void)
995 DEBUG(0, ("LDAP IDMAP Status not available\n"));
998 static struct idmap_methods ldap_methods = {
999 ldap_idmap_init,
1000 ldap_allocate_rid,
1001 ldap_allocate_id,
1002 ldap_get_sid_from_id,
1003 ldap_get_id_from_sid,
1004 ldap_set_mapping,
1005 ldap_idmap_close,
1006 ldap_idmap_status
1010 NTSTATUS idmap_ldap_init(void)
1012 return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "ldap", &ldap_methods);