ctdb-tool: Fix "ctdb -Y ifaces" output to have trailing delimiters
[Samba.git] / source3 / winbindd / idmap_ldap.c
blob0520f213ef6d0c9fefc3e3260c29b8cbd4efb7cb
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) Gerald Carter 2003
9 Copyright (C) Simo Sorce 2003-2007
10 Copyright (C) Michael Adam 2010
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 3 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 #include "includes.h"
27 #include "winbindd.h"
28 #include "secrets.h"
29 #include "idmap.h"
30 #include "idmap_rw.h"
31 #include "../libcli/security/security.h"
33 #undef DBGC_CLASS
34 #define DBGC_CLASS DBGC_IDMAP
36 #include <lber.h>
37 #include <ldap.h>
39 #include "smbldap.h"
40 #include "passdb/pdb_ldap_schema.h"
42 struct idmap_ldap_context {
43 struct smbldap_state *smbldap_state;
44 char *url;
45 char *suffix;
46 char *user_dn;
47 bool anon;
48 struct idmap_rw_ops *rw_ops;
51 #define CHECK_ALLOC_DONE(mem) do { \
52 if (!mem) { \
53 DEBUG(0, ("Out of memory!\n")); \
54 ret = NT_STATUS_NO_MEMORY; \
55 goto done; \
56 } } while (0)
58 /**********************************************************************
59 IDMAP ALLOC TDB BACKEND
60 **********************************************************************/
62 /*********************************************************************
63 ********************************************************************/
65 static NTSTATUS get_credentials( TALLOC_CTX *mem_ctx,
66 struct smbldap_state *ldap_state,
67 const char *config_option,
68 struct idmap_domain *dom,
69 char **dn )
71 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
72 char *secret = NULL;
73 const char *tmp = NULL;
74 char *user_dn = NULL;
75 bool anon = False;
77 /* assume anonymous if we don't have a specified user */
79 tmp = lp_parm_const_string(-1, config_option, "ldap_user_dn", NULL);
81 if ( tmp ) {
82 if (!dom) {
83 DEBUG(0, ("get_credentials: Invalid domain 'NULL' "
84 "encountered for user DN %s\n",
85 tmp));
86 ret = NT_STATUS_UNSUCCESSFUL;
87 goto done;
88 } else {
89 secret = idmap_fetch_secret("ldap", dom->name, tmp);
92 if (!secret) {
93 DEBUG(0, ("get_credentials: Unable to fetch "
94 "auth credentials for %s in %s\n",
95 tmp, (dom==NULL)?"ALLOC":dom->name));
96 ret = NT_STATUS_ACCESS_DENIED;
97 goto done;
99 *dn = talloc_strdup(mem_ctx, tmp);
100 CHECK_ALLOC_DONE(*dn);
101 } else {
102 if (!fetch_ldap_pw(&user_dn, &secret)) {
103 DEBUG(2, ("get_credentials: Failed to lookup ldap "
104 "bind creds. Using anonymous connection.\n"));
105 anon = True;
106 *dn = NULL;
107 } else {
108 *dn = talloc_strdup(mem_ctx, user_dn);
109 SAFE_FREE( user_dn );
110 CHECK_ALLOC_DONE(*dn);
114 smbldap_set_creds(ldap_state, anon, *dn, secret);
115 ret = NT_STATUS_OK;
117 done:
118 SAFE_FREE(secret);
120 return ret;
124 /**********************************************************************
125 Verify the sambaUnixIdPool entry in the directory.
126 **********************************************************************/
128 static NTSTATUS verify_idpool(struct idmap_domain *dom)
130 NTSTATUS ret;
131 TALLOC_CTX *mem_ctx;
132 LDAPMessage *result = NULL;
133 LDAPMod **mods = NULL;
134 const char **attr_list;
135 char *filter;
136 int count;
137 int rc;
138 struct idmap_ldap_context *ctx;
140 ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context);
142 mem_ctx = talloc_new(ctx);
143 if (mem_ctx == NULL) {
144 DEBUG(0, ("Out of memory!\n"));
145 return NT_STATUS_NO_MEMORY;
148 filter = talloc_asprintf(mem_ctx, "(objectclass=%s)", LDAP_OBJ_IDPOOL);
149 CHECK_ALLOC_DONE(filter);
151 attr_list = get_attr_list(mem_ctx, idpool_attr_list);
152 CHECK_ALLOC_DONE(attr_list);
154 rc = smbldap_search(ctx->smbldap_state,
155 ctx->suffix,
156 LDAP_SCOPE_SUBTREE,
157 filter,
158 attr_list,
160 &result);
162 if (rc != LDAP_SUCCESS) {
163 DEBUG(1, ("Unable to verify the idpool, "
164 "cannot continue initialization!\n"));
165 return NT_STATUS_UNSUCCESSFUL;
168 count = ldap_count_entries(ctx->smbldap_state->ldap_struct, result);
170 ldap_msgfree(result);
172 if ( count > 1 ) {
173 DEBUG(0,("Multiple entries returned from %s (base == %s)\n",
174 filter, ctx->suffix));
175 ret = NT_STATUS_UNSUCCESSFUL;
176 goto done;
178 else if (count == 0) {
179 char *uid_str, *gid_str;
181 uid_str = talloc_asprintf(mem_ctx, "%lu",
182 (unsigned long)dom->low_id);
183 gid_str = talloc_asprintf(mem_ctx, "%lu",
184 (unsigned long)dom->low_id);
186 smbldap_set_mod(&mods, LDAP_MOD_ADD,
187 "objectClass", LDAP_OBJ_IDPOOL);
188 smbldap_set_mod(&mods, LDAP_MOD_ADD,
189 get_attr_key2string(idpool_attr_list,
190 LDAP_ATTR_UIDNUMBER),
191 uid_str);
192 smbldap_set_mod(&mods, LDAP_MOD_ADD,
193 get_attr_key2string(idpool_attr_list,
194 LDAP_ATTR_GIDNUMBER),
195 gid_str);
196 if (mods) {
197 rc = smbldap_modify(ctx->smbldap_state,
198 ctx->suffix,
199 mods);
200 ldap_mods_free(mods, True);
201 } else {
202 ret = NT_STATUS_UNSUCCESSFUL;
203 goto done;
207 ret = (rc == LDAP_SUCCESS)?NT_STATUS_OK:NT_STATUS_UNSUCCESSFUL;
208 done:
209 talloc_free(mem_ctx);
210 return ret;
213 /********************************
214 Allocate a new uid or gid
215 ********************************/
217 static NTSTATUS idmap_ldap_allocate_id_internal(struct idmap_domain *dom,
218 struct unixid *xid)
220 TALLOC_CTX *mem_ctx;
221 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
222 int rc = LDAP_SERVER_DOWN;
223 int count = 0;
224 LDAPMessage *result = NULL;
225 LDAPMessage *entry = NULL;
226 LDAPMod **mods = NULL;
227 char *id_str;
228 char *new_id_str;
229 char *filter = NULL;
230 const char *dn = NULL;
231 const char **attr_list;
232 const char *type;
233 struct idmap_ldap_context *ctx;
235 /* Only do query if we are online */
236 if (idmap_is_offline()) {
237 return NT_STATUS_FILE_IS_OFFLINE;
240 ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context);
242 mem_ctx = talloc_new(ctx);
243 if (!mem_ctx) {
244 DEBUG(0, ("Out of memory!\n"));
245 return NT_STATUS_NO_MEMORY;
248 /* get type */
249 switch (xid->type) {
251 case ID_TYPE_UID:
252 type = get_attr_key2string(idpool_attr_list,
253 LDAP_ATTR_UIDNUMBER);
254 break;
256 case ID_TYPE_GID:
257 type = get_attr_key2string(idpool_attr_list,
258 LDAP_ATTR_GIDNUMBER);
259 break;
261 default:
262 DEBUG(2, ("Invalid ID type (0x%x)\n", xid->type));
263 return NT_STATUS_INVALID_PARAMETER;
266 filter = talloc_asprintf(mem_ctx, "(objectClass=%s)", LDAP_OBJ_IDPOOL);
267 CHECK_ALLOC_DONE(filter);
269 attr_list = get_attr_list(mem_ctx, idpool_attr_list);
270 CHECK_ALLOC_DONE(attr_list);
272 DEBUG(10, ("Search of the id pool (filter: %s)\n", filter));
274 rc = smbldap_search(ctx->smbldap_state,
275 ctx->suffix,
276 LDAP_SCOPE_SUBTREE, filter,
277 attr_list, 0, &result);
279 if (rc != LDAP_SUCCESS) {
280 DEBUG(0,("%s object not found\n", LDAP_OBJ_IDPOOL));
281 goto done;
284 smbldap_talloc_autofree_ldapmsg(mem_ctx, result);
286 count = ldap_count_entries(ctx->smbldap_state->ldap_struct, result);
287 if (count != 1) {
288 DEBUG(0,("Single %s object not found\n", LDAP_OBJ_IDPOOL));
289 goto done;
292 entry = ldap_first_entry(ctx->smbldap_state->ldap_struct, result);
294 dn = smbldap_talloc_dn(mem_ctx,
295 ctx->smbldap_state->ldap_struct,
296 entry);
297 if ( ! dn) {
298 goto done;
301 id_str = smbldap_talloc_single_attribute(
302 ctx->smbldap_state->ldap_struct,
303 entry, type, mem_ctx);
304 if (id_str == NULL) {
305 DEBUG(0,("%s attribute not found\n", type));
306 ret = NT_STATUS_UNSUCCESSFUL;
307 goto done;
310 xid->id = strtoul(id_str, NULL, 10);
312 /* make sure we still have room to grow */
314 switch (xid->type) {
315 case ID_TYPE_UID:
316 if (xid->id > dom->high_id) {
317 DEBUG(0,("Cannot allocate uid above %lu!\n",
318 (unsigned long)dom->high_id));
319 goto done;
321 break;
323 case ID_TYPE_GID:
324 if (xid->id > dom->high_id) {
325 DEBUG(0,("Cannot allocate gid above %lu!\n",
326 (unsigned long)dom->high_id));
327 goto done;
329 break;
331 default:
332 /* impossible */
333 goto done;
336 new_id_str = talloc_asprintf(mem_ctx, "%lu", (unsigned long)xid->id + 1);
337 if ( ! new_id_str) {
338 DEBUG(0,("Out of memory\n"));
339 ret = NT_STATUS_NO_MEMORY;
340 goto done;
343 smbldap_set_mod(&mods, LDAP_MOD_DELETE, type, id_str);
344 smbldap_set_mod(&mods, LDAP_MOD_ADD, type, new_id_str);
346 if (mods == NULL) {
347 DEBUG(0,("smbldap_set_mod() failed.\n"));
348 goto done;
351 DEBUG(10, ("Try to atomically increment the id (%s -> %s)\n",
352 id_str, new_id_str));
354 rc = smbldap_modify(ctx->smbldap_state, dn, mods);
356 ldap_mods_free(mods, True);
358 if (rc != LDAP_SUCCESS) {
359 DEBUG(1,("Failed to allocate new %s. "
360 "smbldap_modify() failed.\n", type));
361 goto done;
364 ret = NT_STATUS_OK;
366 done:
367 talloc_free(mem_ctx);
368 return ret;
372 * Allocate a new unix-ID.
373 * For now this is for the default idmap domain only.
374 * Should be extended later on.
376 static NTSTATUS idmap_ldap_allocate_id(struct idmap_domain *dom,
377 struct unixid *id)
379 NTSTATUS ret;
381 if (!strequal(dom->name, "*")) {
382 DEBUG(3, ("idmap_ldap_allocate_id: "
383 "Refusing allocation of a new unixid for domain'%s'. "
384 "This is only supported for the default "
385 "domain \"*\".\n",
386 dom->name));
387 return NT_STATUS_NOT_IMPLEMENTED;
390 ret = idmap_ldap_allocate_id_internal(dom, id);
392 return ret;
396 /**********************************************************************
397 IDMAP MAPPING LDAP BACKEND
398 **********************************************************************/
400 static int idmap_ldap_close_destructor(struct idmap_ldap_context *ctx)
402 smbldap_free_struct(&ctx->smbldap_state);
403 DEBUG(5,("The connection to the LDAP server was closed\n"));
404 /* maybe free the results here --metze */
406 return 0;
409 /********************************
410 Initialise idmap database.
411 ********************************/
413 static NTSTATUS idmap_ldap_set_mapping(struct idmap_domain *dom,
414 const struct id_map *map);
416 static NTSTATUS idmap_ldap_db_init(struct idmap_domain *dom)
418 NTSTATUS ret;
419 struct idmap_ldap_context *ctx = NULL;
420 char *config_option = NULL;
421 const char *tmp = NULL;
423 /* Only do init if we are online */
424 if (idmap_is_offline()) {
425 return NT_STATUS_FILE_IS_OFFLINE;
428 ctx = talloc_zero(dom, struct idmap_ldap_context);
429 if ( ! ctx) {
430 DEBUG(0, ("Out of memory!\n"));
431 return NT_STATUS_NO_MEMORY;
434 config_option = talloc_asprintf(ctx, "idmap config %s", dom->name);
435 if (!config_option) {
436 DEBUG(0, ("Out of memory!\n"));
437 ret = NT_STATUS_NO_MEMORY;
438 goto done;
441 tmp = lp_parm_const_string(-1, config_option, "ldap_url", NULL);
443 if ( ! tmp) {
444 DEBUG(1, ("ERROR: missing idmap ldap url\n"));
445 ret = NT_STATUS_UNSUCCESSFUL;
446 goto done;
449 ctx->url = talloc_strdup(ctx, tmp);
451 trim_char(ctx->url, '\"', '\"');
453 tmp = lp_parm_const_string(-1, config_option, "ldap_base_dn", NULL);
454 if ( ! tmp || ! *tmp) {
455 tmp = lp_ldap_idmap_suffix(talloc_tos());
456 if ( ! tmp) {
457 DEBUG(1, ("ERROR: missing idmap ldap suffix\n"));
458 ret = NT_STATUS_UNSUCCESSFUL;
459 goto done;
463 ctx->suffix = talloc_strdup(ctx, tmp);
464 CHECK_ALLOC_DONE(ctx->suffix);
466 ctx->rw_ops = talloc_zero(ctx, struct idmap_rw_ops);
467 CHECK_ALLOC_DONE(ctx->rw_ops);
469 ctx->rw_ops->get_new_id = idmap_ldap_allocate_id_internal;
470 ctx->rw_ops->set_mapping = idmap_ldap_set_mapping;
472 /* get_credentials deals with setting up creds */
474 ret = smbldap_init(ctx, winbind_event_context(), ctx->url,
475 false, NULL, NULL, &ctx->smbldap_state);
476 if (!NT_STATUS_IS_OK(ret)) {
477 DEBUG(1, ("ERROR: smbldap_init (%s) failed!\n", ctx->url));
478 goto done;
481 ret = get_credentials( ctx, ctx->smbldap_state, config_option,
482 dom, &ctx->user_dn );
483 if ( !NT_STATUS_IS_OK(ret) ) {
484 DEBUG(1,("idmap_ldap_db_init: Failed to get connection "
485 "credentials (%s)\n", nt_errstr(ret)));
486 goto done;
490 * Set the destructor on the context, so that resources are
491 * properly freed when the context is released.
493 talloc_set_destructor(ctx, idmap_ldap_close_destructor);
495 dom->private_data = ctx;
497 ret = verify_idpool(dom);
498 if (!NT_STATUS_IS_OK(ret)) {
499 DEBUG(1, ("idmap_ldap_db_init: failed to verify ID pool (%s)\n",
500 nt_errstr(ret)));
501 goto done;
504 talloc_free(config_option);
505 return NT_STATUS_OK;
507 /*failed */
508 done:
509 talloc_free(ctx);
510 return ret;
514 * set a mapping.
517 /* TODO: change this: This function cannot be called to modify a mapping,
518 * only set a new one */
520 static NTSTATUS idmap_ldap_set_mapping(struct idmap_domain *dom,
521 const struct id_map *map)
523 NTSTATUS ret;
524 TALLOC_CTX *memctx;
525 struct idmap_ldap_context *ctx;
526 LDAPMessage *entry = NULL;
527 LDAPMod **mods = NULL;
528 const char *type;
529 char *id_str;
530 char *sid;
531 char *dn;
532 int rc = -1;
534 /* Only do query if we are online */
535 if (idmap_is_offline()) {
536 return NT_STATUS_FILE_IS_OFFLINE;
539 ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context);
541 switch(map->xid.type) {
542 case ID_TYPE_UID:
543 type = get_attr_key2string(sidmap_attr_list,
544 LDAP_ATTR_UIDNUMBER);
545 break;
547 case ID_TYPE_GID:
548 type = get_attr_key2string(sidmap_attr_list,
549 LDAP_ATTR_GIDNUMBER);
550 break;
552 default:
553 return NT_STATUS_INVALID_PARAMETER;
556 memctx = talloc_new(ctx);
557 if ( ! memctx) {
558 DEBUG(0, ("Out of memory!\n"));
559 return NT_STATUS_NO_MEMORY;
562 id_str = talloc_asprintf(memctx, "%lu", (unsigned long)map->xid.id);
563 CHECK_ALLOC_DONE(id_str);
565 sid = talloc_strdup(memctx, sid_string_talloc(memctx, map->sid));
566 CHECK_ALLOC_DONE(sid);
568 dn = talloc_asprintf(memctx, "%s=%s,%s",
569 get_attr_key2string(sidmap_attr_list, LDAP_ATTR_SID),
570 sid,
571 ctx->suffix);
572 CHECK_ALLOC_DONE(dn);
574 smbldap_set_mod(&mods, LDAP_MOD_ADD,
575 "objectClass", LDAP_OBJ_IDMAP_ENTRY);
577 smbldap_make_mod(ctx->smbldap_state->ldap_struct,
578 entry, &mods, type, id_str);
580 smbldap_make_mod(ctx->smbldap_state->ldap_struct, entry, &mods,
581 get_attr_key2string(sidmap_attr_list, LDAP_ATTR_SID),
582 sid);
584 if ( ! mods) {
585 DEBUG(2, ("ERROR: No mods?\n"));
586 ret = NT_STATUS_UNSUCCESSFUL;
587 goto done;
590 /* TODO: remove conflicting mappings! */
592 smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_SID_ENTRY);
594 DEBUG(10, ("Set DN %s (%s -> %s)\n", dn, sid, id_str));
596 rc = smbldap_add(ctx->smbldap_state, dn, mods);
597 ldap_mods_free(mods, True);
599 if (rc != LDAP_SUCCESS) {
600 char *ld_error = NULL;
601 ldap_get_option(ctx->smbldap_state->ldap_struct,
602 LDAP_OPT_ERROR_STRING, &ld_error);
603 DEBUG(0,("ldap_set_mapping_internals: Failed to add %s to %lu "
604 "mapping [%s]\n", sid,
605 (unsigned long)map->xid.id, type));
606 DEBUG(0, ("ldap_set_mapping_internals: Error was: %s (%s)\n",
607 ld_error ? ld_error : "(NULL)", ldap_err2string (rc)));
608 if (ld_error) {
609 ldap_memfree(ld_error);
611 ret = NT_STATUS_UNSUCCESSFUL;
612 goto done;
615 DEBUG(10,("ldap_set_mapping: Successfully created mapping from %s to "
616 "%lu [%s]\n", sid, (unsigned long)map->xid.id, type));
618 ret = NT_STATUS_OK;
620 done:
621 talloc_free(memctx);
622 return ret;
626 * Create a new mapping for an unmapped SID, also allocating a new ID.
627 * If possible, this should be run inside a transaction to make the
628 * action atomic.
630 static NTSTATUS idmap_ldap_new_mapping(struct idmap_domain *dom, struct id_map *map)
632 NTSTATUS ret;
633 struct idmap_ldap_context *ctx;
635 ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context);
637 ret = idmap_rw_new_mapping(dom, ctx->rw_ops, map);
639 return ret;
642 /**********************************
643 lookup a set of unix ids.
644 **********************************/
646 static NTSTATUS idmap_ldap_unixids_to_sids(struct idmap_domain *dom,
647 struct id_map **ids)
649 NTSTATUS ret;
650 TALLOC_CTX *memctx;
651 struct idmap_ldap_context *ctx;
652 LDAPMessage *result = NULL;
653 LDAPMessage *entry = NULL;
654 const char *uidNumber;
655 const char *gidNumber;
656 const char **attr_list;
657 char *filter = NULL;
658 bool multi = False;
659 int idx = 0;
660 int bidx = 0;
661 int count;
662 int rc;
663 int i;
665 /* Only do query if we are online */
666 if (idmap_is_offline()) {
667 return NT_STATUS_FILE_IS_OFFLINE;
670 ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context);
672 memctx = talloc_new(ctx);
673 if ( ! memctx) {
674 DEBUG(0, ("Out of memory!\n"));
675 return NT_STATUS_NO_MEMORY;
678 uidNumber = get_attr_key2string(idpool_attr_list, LDAP_ATTR_UIDNUMBER);
679 gidNumber = get_attr_key2string(idpool_attr_list, LDAP_ATTR_GIDNUMBER);
681 attr_list = get_attr_list(memctx, sidmap_attr_list);
683 if ( ! ids[1]) {
684 /* if we are requested just one mapping use the simple filter */
686 filter = talloc_asprintf(memctx, "(&(objectClass=%s)(%s=%lu))",
687 LDAP_OBJ_IDMAP_ENTRY,
688 (ids[0]->xid.type==ID_TYPE_UID)?uidNumber:gidNumber,
689 (unsigned long)ids[0]->xid.id);
690 CHECK_ALLOC_DONE(filter);
691 DEBUG(10, ("Filter: [%s]\n", filter));
692 } else {
693 /* multiple mappings */
694 multi = True;
697 for (i = 0; ids[i]; i++) {
698 ids[i]->status = ID_UNKNOWN;
701 again:
702 if (multi) {
704 talloc_free(filter);
705 filter = talloc_asprintf(memctx,
706 "(&(objectClass=%s)(|",
707 LDAP_OBJ_IDMAP_ENTRY);
708 CHECK_ALLOC_DONE(filter);
710 bidx = idx;
711 for (i = 0; (i < IDMAP_LDAP_MAX_IDS) && ids[idx]; i++, idx++) {
712 filter = talloc_asprintf_append_buffer(filter, "(%s=%lu)",
713 (ids[idx]->xid.type==ID_TYPE_UID)?uidNumber:gidNumber,
714 (unsigned long)ids[idx]->xid.id);
715 CHECK_ALLOC_DONE(filter);
717 filter = talloc_asprintf_append_buffer(filter, "))");
718 CHECK_ALLOC_DONE(filter);
719 DEBUG(10, ("Filter: [%s]\n", filter));
720 } else {
721 bidx = 0;
722 idx = 1;
725 rc = smbldap_search(ctx->smbldap_state, ctx->suffix, LDAP_SCOPE_SUBTREE,
726 filter, attr_list, 0, &result);
728 if (rc != LDAP_SUCCESS) {
729 DEBUG(3,("Failure looking up ids (%s)\n", ldap_err2string(rc)));
730 ret = NT_STATUS_UNSUCCESSFUL;
731 goto done;
734 count = ldap_count_entries(ctx->smbldap_state->ldap_struct, result);
736 if (count == 0) {
737 DEBUG(10, ("NO SIDs found\n"));
740 for (i = 0; i < count; i++) {
741 char *sidstr = NULL;
742 char *tmp = NULL;
743 enum id_type type;
744 struct id_map *map;
745 uint32_t id;
747 if (i == 0) { /* first entry */
748 entry = ldap_first_entry(ctx->smbldap_state->ldap_struct,
749 result);
750 } else { /* following ones */
751 entry = ldap_next_entry(ctx->smbldap_state->ldap_struct,
752 entry);
754 if ( ! entry) {
755 DEBUG(2, ("ERROR: Unable to fetch ldap entries "
756 "from results\n"));
757 break;
760 /* first check if the SID is present */
761 sidstr = smbldap_talloc_single_attribute(
762 ctx->smbldap_state->ldap_struct,
763 entry, LDAP_ATTRIBUTE_SID, memctx);
764 if ( ! sidstr) { /* no sid, skip entry */
765 DEBUG(2, ("WARNING SID not found on entry\n"));
766 continue;
769 /* now try to see if it is a uid, if not try with a gid
770 * (gid is more common, but in case both uidNumber and
771 * gidNumber are returned the SID is mapped to the uid
772 *not the gid) */
773 type = ID_TYPE_UID;
774 tmp = smbldap_talloc_single_attribute(
775 ctx->smbldap_state->ldap_struct,
776 entry, uidNumber, memctx);
777 if ( ! tmp) {
778 type = ID_TYPE_GID;
779 tmp = smbldap_talloc_single_attribute(
780 ctx->smbldap_state->ldap_struct,
781 entry, gidNumber, memctx);
783 if ( ! tmp) { /* wow very strange entry, how did it match ? */
784 DEBUG(5, ("Unprobable match on (%s), no uidNumber, "
785 "nor gidNumber returned\n", sidstr));
786 TALLOC_FREE(sidstr);
787 continue;
790 id = strtoul(tmp, NULL, 10);
791 if (!idmap_unix_id_is_in_range(id, dom)) {
792 DEBUG(5, ("Requested id (%u) out of range (%u - %u). "
793 "Filtered!\n", id,
794 dom->low_id, dom->high_id));
795 TALLOC_FREE(sidstr);
796 TALLOC_FREE(tmp);
797 continue;
799 TALLOC_FREE(tmp);
801 map = idmap_find_map_by_id(&ids[bidx], type, id);
802 if (!map) {
803 DEBUG(2, ("WARNING: couldn't match sid (%s) "
804 "with requested ids\n", sidstr));
805 TALLOC_FREE(sidstr);
806 continue;
809 if ( ! string_to_sid(map->sid, sidstr)) {
810 DEBUG(2, ("ERROR: Invalid SID on entry\n"));
811 TALLOC_FREE(sidstr);
812 continue;
815 if (map->status == ID_MAPPED) {
816 DEBUG(1, ("WARNING: duplicate %s mapping in LDAP. "
817 "overwriting mapping %u -> %s with %u -> %s\n",
818 (type == ID_TYPE_UID) ? "UID" : "GID",
819 id, sid_string_dbg(map->sid), id, sidstr));
822 TALLOC_FREE(sidstr);
824 /* mapped */
825 map->status = ID_MAPPED;
827 DEBUG(10, ("Mapped %s -> %lu (%d)\n", sid_string_dbg(map->sid),
828 (unsigned long)map->xid.id, map->xid.type));
831 /* free the ldap results */
832 if (result) {
833 ldap_msgfree(result);
834 result = NULL;
837 if (multi && ids[idx]) { /* still some values to map */
838 goto again;
841 ret = NT_STATUS_OK;
843 /* mark all unknwon/expired ones as unmapped */
844 for (i = 0; ids[i]; i++) {
845 if (ids[i]->status != ID_MAPPED)
846 ids[i]->status = ID_UNMAPPED;
849 done:
850 talloc_free(memctx);
851 return ret;
854 /**********************************
855 lookup a set of sids.
856 **********************************/
858 static NTSTATUS idmap_ldap_sids_to_unixids(struct idmap_domain *dom,
859 struct id_map **ids)
861 LDAPMessage *entry = NULL;
862 NTSTATUS ret;
863 TALLOC_CTX *memctx;
864 struct idmap_ldap_context *ctx;
865 LDAPMessage *result = NULL;
866 const char *uidNumber;
867 const char *gidNumber;
868 const char **attr_list;
869 char *filter = NULL;
870 bool multi = False;
871 int idx = 0;
872 int bidx = 0;
873 int count;
874 int rc;
875 int i;
877 /* Only do query if we are online */
878 if (idmap_is_offline()) {
879 return NT_STATUS_FILE_IS_OFFLINE;
882 ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context);
884 memctx = talloc_new(ctx);
885 if ( ! memctx) {
886 DEBUG(0, ("Out of memory!\n"));
887 return NT_STATUS_NO_MEMORY;
890 uidNumber = get_attr_key2string(idpool_attr_list, LDAP_ATTR_UIDNUMBER);
891 gidNumber = get_attr_key2string(idpool_attr_list, LDAP_ATTR_GIDNUMBER);
893 attr_list = get_attr_list(memctx, sidmap_attr_list);
895 if ( ! ids[1]) {
896 /* if we are requested just one mapping use the simple filter */
898 filter = talloc_asprintf(memctx, "(&(objectClass=%s)(%s=%s))",
899 LDAP_OBJ_IDMAP_ENTRY,
900 LDAP_ATTRIBUTE_SID,
901 sid_string_talloc(memctx, ids[0]->sid));
902 CHECK_ALLOC_DONE(filter);
903 DEBUG(10, ("Filter: [%s]\n", filter));
904 } else {
905 /* multiple mappings */
906 multi = True;
909 for (i = 0; ids[i]; i++) {
910 ids[i]->status = ID_UNKNOWN;
913 again:
914 if (multi) {
916 TALLOC_FREE(filter);
917 filter = talloc_asprintf(memctx,
918 "(&(objectClass=%s)(|",
919 LDAP_OBJ_IDMAP_ENTRY);
920 CHECK_ALLOC_DONE(filter);
922 bidx = idx;
923 for (i = 0; (i < IDMAP_LDAP_MAX_IDS) && ids[idx]; i++, idx++) {
924 filter = talloc_asprintf_append_buffer(filter, "(%s=%s)",
925 LDAP_ATTRIBUTE_SID,
926 sid_string_talloc(memctx,
927 ids[idx]->sid));
928 CHECK_ALLOC_DONE(filter);
930 filter = talloc_asprintf_append_buffer(filter, "))");
931 CHECK_ALLOC_DONE(filter);
932 DEBUG(10, ("Filter: [%s]", filter));
933 } else {
934 bidx = 0;
935 idx = 1;
938 rc = smbldap_search(ctx->smbldap_state, ctx->suffix, LDAP_SCOPE_SUBTREE,
939 filter, attr_list, 0, &result);
941 if (rc != LDAP_SUCCESS) {
942 DEBUG(3,("Failure looking up sids (%s)\n",
943 ldap_err2string(rc)));
944 ret = NT_STATUS_UNSUCCESSFUL;
945 goto done;
948 count = ldap_count_entries(ctx->smbldap_state->ldap_struct, result);
950 if (count == 0) {
951 DEBUG(10, ("NO SIDs found\n"));
954 for (i = 0; i < count; i++) {
955 char *sidstr = NULL;
956 char *tmp = NULL;
957 enum id_type type;
958 struct id_map *map;
959 struct dom_sid sid;
960 uint32_t id;
962 if (i == 0) { /* first entry */
963 entry = ldap_first_entry(ctx->smbldap_state->ldap_struct,
964 result);
965 } else { /* following ones */
966 entry = ldap_next_entry(ctx->smbldap_state->ldap_struct,
967 entry);
969 if ( ! entry) {
970 DEBUG(2, ("ERROR: Unable to fetch ldap entries "
971 "from results\n"));
972 break;
975 /* first check if the SID is present */
976 sidstr = smbldap_talloc_single_attribute(
977 ctx->smbldap_state->ldap_struct,
978 entry, LDAP_ATTRIBUTE_SID, memctx);
979 if ( ! sidstr) { /* no sid ??, skip entry */
980 DEBUG(2, ("WARNING SID not found on entry\n"));
981 continue;
984 if ( ! string_to_sid(&sid, sidstr)) {
985 DEBUG(2, ("ERROR: Invalid SID on entry\n"));
986 TALLOC_FREE(sidstr);
987 continue;
990 map = idmap_find_map_by_sid(&ids[bidx], &sid);
991 if (!map) {
992 DEBUG(2, ("WARNING: couldn't find entry sid (%s) "
993 "in ids", sidstr));
994 TALLOC_FREE(sidstr);
995 continue;
998 /* now try to see if it is a uid, if not try with a gid
999 * (gid is more common, but in case both uidNumber and
1000 * gidNumber are returned the SID is mapped to the uid
1001 * not the gid) */
1002 type = ID_TYPE_UID;
1003 tmp = smbldap_talloc_single_attribute(
1004 ctx->smbldap_state->ldap_struct,
1005 entry, uidNumber, memctx);
1006 if ( ! tmp) {
1007 type = ID_TYPE_GID;
1008 tmp = smbldap_talloc_single_attribute(
1009 ctx->smbldap_state->ldap_struct,
1010 entry, gidNumber, memctx);
1012 if ( ! tmp) { /* no ids ?? */
1013 DEBUG(5, ("no uidNumber, "
1014 "nor gidNumber attributes found\n"));
1015 TALLOC_FREE(sidstr);
1016 continue;
1019 id = strtoul(tmp, NULL, 10);
1020 if (!idmap_unix_id_is_in_range(id, dom)) {
1021 DEBUG(5, ("Requested id (%u) out of range (%u - %u). "
1022 "Filtered!\n", id,
1023 dom->low_id, dom->high_id));
1024 TALLOC_FREE(sidstr);
1025 TALLOC_FREE(tmp);
1026 continue;
1028 TALLOC_FREE(tmp);
1030 if (map->status == ID_MAPPED) {
1031 DEBUG(1, ("WARNING: duplicate %s mapping in LDAP. "
1032 "overwriting mapping %s -> %u with %s -> %u\n",
1033 (type == ID_TYPE_UID) ? "UID" : "GID",
1034 sidstr, map->xid.id, sidstr, id));
1037 TALLOC_FREE(sidstr);
1039 /* mapped */
1040 map->xid.type = type;
1041 map->xid.id = id;
1042 map->status = ID_MAPPED;
1044 DEBUG(10, ("Mapped %s -> %lu (%d)\n", sid_string_dbg(map->sid),
1045 (unsigned long)map->xid.id, map->xid.type));
1048 /* free the ldap results */
1049 if (result) {
1050 ldap_msgfree(result);
1051 result = NULL;
1054 if (multi && ids[idx]) { /* still some values to map */
1055 goto again;
1059 * try to create new mappings for unmapped sids
1061 for (i = 0; ids[i]; i++) {
1062 if (ids[i]->status != ID_MAPPED) {
1063 ids[i]->status = ID_UNMAPPED;
1064 if (ids[i]->sid != NULL) {
1065 ret = idmap_ldap_new_mapping(dom, ids[i]);
1066 if (!NT_STATUS_IS_OK(ret)) {
1067 goto done;
1073 ret = NT_STATUS_OK;
1075 done:
1076 talloc_free(memctx);
1077 return ret;
1080 /**********************************
1081 Close the idmap ldap instance
1082 **********************************/
1084 static struct idmap_methods idmap_ldap_methods = {
1086 .init = idmap_ldap_db_init,
1087 .unixids_to_sids = idmap_ldap_unixids_to_sids,
1088 .sids_to_unixids = idmap_ldap_sids_to_unixids,
1089 .allocate_id = idmap_ldap_allocate_id,
1092 NTSTATUS idmap_ldap_init(void);
1093 NTSTATUS idmap_ldap_init(void)
1095 return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "ldap",
1096 &idmap_ldap_methods);