s3:idmap_rid: force mapping type to ID_TYPE_BOTH for sid->unixid mapping
[Samba.git] / source3 / winbindd / idmap_ldap.c
blob0c58bf4236cefad1db0f877f585a187641cb25ff
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 static char *idmap_fetch_secret(const char *backend,
43 const char *domain, const char *identity)
45 char *tmp, *ret;
46 int r;
48 r = asprintf(&tmp, "IDMAP_%s_%s", backend, domain);
50 if (r < 0)
51 return NULL;
53 /* make sure the key is case insensitive */
54 if (!strupper_m(tmp)) {
55 SAFE_FREE(tmp);
56 return NULL;
59 ret = secrets_fetch_generic(tmp, identity);
61 SAFE_FREE(tmp);
63 return ret;
66 struct idmap_ldap_context {
67 struct smbldap_state *smbldap_state;
68 char *url;
69 char *suffix;
70 char *user_dn;
71 bool anon;
72 struct idmap_rw_ops *rw_ops;
75 #define CHECK_ALLOC_DONE(mem) do { \
76 if (!mem) { \
77 DEBUG(0, ("Out of memory!\n")); \
78 ret = NT_STATUS_NO_MEMORY; \
79 goto done; \
80 } } while (0)
82 /**********************************************************************
83 IDMAP ALLOC TDB BACKEND
84 **********************************************************************/
86 /*********************************************************************
87 ********************************************************************/
89 static NTSTATUS get_credentials( TALLOC_CTX *mem_ctx,
90 struct smbldap_state *ldap_state,
91 const char *config_option,
92 struct idmap_domain *dom,
93 char **dn )
95 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
96 char *secret = NULL;
97 const char *tmp = NULL;
98 char *user_dn = NULL;
99 bool anon = False;
101 /* assume anonymous if we don't have a specified user */
103 tmp = lp_parm_const_string(-1, config_option, "ldap_user_dn", NULL);
105 if ( tmp ) {
106 if (!dom) {
107 DEBUG(0, ("get_credentials: Invalid domain 'NULL' "
108 "encountered for user DN %s\n",
109 tmp));
110 ret = NT_STATUS_UNSUCCESSFUL;
111 goto done;
112 } else {
113 secret = idmap_fetch_secret("ldap", dom->name, tmp);
116 if (!secret) {
117 DEBUG(0, ("get_credentials: Unable to fetch "
118 "auth credentials for %s in %s\n",
119 tmp, (dom==NULL)?"ALLOC":dom->name));
120 ret = NT_STATUS_ACCESS_DENIED;
121 goto done;
123 *dn = talloc_strdup(mem_ctx, tmp);
124 CHECK_ALLOC_DONE(*dn);
125 } else {
126 if (!fetch_ldap_pw(&user_dn, &secret)) {
127 DEBUG(2, ("get_credentials: Failed to lookup ldap "
128 "bind creds. Using anonymous connection.\n"));
129 anon = True;
130 *dn = NULL;
131 } else {
132 *dn = talloc_strdup(mem_ctx, user_dn);
133 SAFE_FREE( user_dn );
134 CHECK_ALLOC_DONE(*dn);
138 smbldap_set_creds(ldap_state, anon, *dn, secret);
139 ret = NT_STATUS_OK;
141 done:
142 SAFE_FREE(secret);
144 return ret;
148 /**********************************************************************
149 Verify the sambaUnixIdPool entry in the directory.
150 **********************************************************************/
152 static NTSTATUS verify_idpool(struct idmap_domain *dom)
154 NTSTATUS ret;
155 TALLOC_CTX *mem_ctx;
156 LDAPMessage *result = NULL;
157 LDAPMod **mods = NULL;
158 const char **attr_list;
159 char *filter;
160 int count;
161 int rc;
162 struct idmap_ldap_context *ctx;
164 ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context);
166 mem_ctx = talloc_new(ctx);
167 if (mem_ctx == NULL) {
168 DEBUG(0, ("Out of memory!\n"));
169 return NT_STATUS_NO_MEMORY;
172 filter = talloc_asprintf(mem_ctx, "(objectclass=%s)", LDAP_OBJ_IDPOOL);
173 CHECK_ALLOC_DONE(filter);
175 attr_list = get_attr_list(mem_ctx, idpool_attr_list);
176 CHECK_ALLOC_DONE(attr_list);
178 rc = smbldap_search(ctx->smbldap_state,
179 ctx->suffix,
180 LDAP_SCOPE_SUBTREE,
181 filter,
182 attr_list,
184 &result);
186 if (rc != LDAP_SUCCESS) {
187 DEBUG(1, ("Unable to verify the idpool, "
188 "cannot continue initialization!\n"));
189 return NT_STATUS_UNSUCCESSFUL;
192 count = ldap_count_entries(ctx->smbldap_state->ldap_struct, result);
194 ldap_msgfree(result);
196 if ( count > 1 ) {
197 DEBUG(0,("Multiple entries returned from %s (base == %s)\n",
198 filter, ctx->suffix));
199 ret = NT_STATUS_UNSUCCESSFUL;
200 goto done;
202 else if (count == 0) {
203 char *uid_str, *gid_str;
205 uid_str = talloc_asprintf(mem_ctx, "%lu",
206 (unsigned long)dom->low_id);
207 gid_str = talloc_asprintf(mem_ctx, "%lu",
208 (unsigned long)dom->low_id);
210 smbldap_set_mod(&mods, LDAP_MOD_ADD,
211 "objectClass", LDAP_OBJ_IDPOOL);
212 smbldap_set_mod(&mods, LDAP_MOD_ADD,
213 get_attr_key2string(idpool_attr_list,
214 LDAP_ATTR_UIDNUMBER),
215 uid_str);
216 smbldap_set_mod(&mods, LDAP_MOD_ADD,
217 get_attr_key2string(idpool_attr_list,
218 LDAP_ATTR_GIDNUMBER),
219 gid_str);
220 if (mods) {
221 rc = smbldap_modify(ctx->smbldap_state,
222 ctx->suffix,
223 mods);
224 ldap_mods_free(mods, True);
225 } else {
226 ret = NT_STATUS_UNSUCCESSFUL;
227 goto done;
231 ret = (rc == LDAP_SUCCESS)?NT_STATUS_OK:NT_STATUS_UNSUCCESSFUL;
232 done:
233 talloc_free(mem_ctx);
234 return ret;
237 /********************************
238 Allocate a new uid or gid
239 ********************************/
241 static NTSTATUS idmap_ldap_allocate_id_internal(struct idmap_domain *dom,
242 struct unixid *xid)
244 TALLOC_CTX *mem_ctx;
245 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
246 int rc = LDAP_SERVER_DOWN;
247 int count = 0;
248 LDAPMessage *result = NULL;
249 LDAPMessage *entry = NULL;
250 LDAPMod **mods = NULL;
251 char *id_str;
252 char *new_id_str;
253 char *filter = NULL;
254 const char *dn = NULL;
255 const char **attr_list;
256 const char *type;
257 struct idmap_ldap_context *ctx;
259 /* Only do query if we are online */
260 if (idmap_is_offline()) {
261 return NT_STATUS_FILE_IS_OFFLINE;
264 ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context);
266 mem_ctx = talloc_new(ctx);
267 if (!mem_ctx) {
268 DEBUG(0, ("Out of memory!\n"));
269 return NT_STATUS_NO_MEMORY;
272 /* get type */
273 switch (xid->type) {
275 case ID_TYPE_UID:
276 type = get_attr_key2string(idpool_attr_list,
277 LDAP_ATTR_UIDNUMBER);
278 break;
280 case ID_TYPE_GID:
281 type = get_attr_key2string(idpool_attr_list,
282 LDAP_ATTR_GIDNUMBER);
283 break;
285 default:
286 DEBUG(2, ("Invalid ID type (0x%x)\n", xid->type));
287 return NT_STATUS_INVALID_PARAMETER;
290 filter = talloc_asprintf(mem_ctx, "(objectClass=%s)", LDAP_OBJ_IDPOOL);
291 CHECK_ALLOC_DONE(filter);
293 attr_list = get_attr_list(mem_ctx, idpool_attr_list);
294 CHECK_ALLOC_DONE(attr_list);
296 DEBUG(10, ("Search of the id pool (filter: %s)\n", filter));
298 rc = smbldap_search(ctx->smbldap_state,
299 ctx->suffix,
300 LDAP_SCOPE_SUBTREE, filter,
301 attr_list, 0, &result);
303 if (rc != LDAP_SUCCESS) {
304 DEBUG(0,("%s object not found\n", LDAP_OBJ_IDPOOL));
305 goto done;
308 smbldap_talloc_autofree_ldapmsg(mem_ctx, result);
310 count = ldap_count_entries(ctx->smbldap_state->ldap_struct, result);
311 if (count != 1) {
312 DEBUG(0,("Single %s object not found\n", LDAP_OBJ_IDPOOL));
313 goto done;
316 entry = ldap_first_entry(ctx->smbldap_state->ldap_struct, result);
318 dn = smbldap_talloc_dn(mem_ctx,
319 ctx->smbldap_state->ldap_struct,
320 entry);
321 if ( ! dn) {
322 goto done;
325 id_str = smbldap_talloc_single_attribute(
326 ctx->smbldap_state->ldap_struct,
327 entry, type, mem_ctx);
328 if (id_str == NULL) {
329 DEBUG(0,("%s attribute not found\n", type));
330 ret = NT_STATUS_UNSUCCESSFUL;
331 goto done;
334 xid->id = strtoul(id_str, NULL, 10);
336 /* make sure we still have room to grow */
338 switch (xid->type) {
339 case ID_TYPE_UID:
340 if (xid->id > dom->high_id) {
341 DEBUG(0,("Cannot allocate uid above %lu!\n",
342 (unsigned long)dom->high_id));
343 goto done;
345 break;
347 case ID_TYPE_GID:
348 if (xid->id > dom->high_id) {
349 DEBUG(0,("Cannot allocate gid above %lu!\n",
350 (unsigned long)dom->high_id));
351 goto done;
353 break;
355 default:
356 /* impossible */
357 goto done;
360 new_id_str = talloc_asprintf(mem_ctx, "%lu", (unsigned long)xid->id + 1);
361 if ( ! new_id_str) {
362 DEBUG(0,("Out of memory\n"));
363 ret = NT_STATUS_NO_MEMORY;
364 goto done;
367 smbldap_set_mod(&mods, LDAP_MOD_DELETE, type, id_str);
368 smbldap_set_mod(&mods, LDAP_MOD_ADD, type, new_id_str);
370 if (mods == NULL) {
371 DEBUG(0,("smbldap_set_mod() failed.\n"));
372 goto done;
375 DEBUG(10, ("Try to atomically increment the id (%s -> %s)\n",
376 id_str, new_id_str));
378 rc = smbldap_modify(ctx->smbldap_state, dn, mods);
380 ldap_mods_free(mods, True);
382 if (rc != LDAP_SUCCESS) {
383 DEBUG(1,("Failed to allocate new %s. "
384 "smbldap_modify() failed.\n", type));
385 goto done;
388 ret = NT_STATUS_OK;
390 done:
391 talloc_free(mem_ctx);
392 return ret;
396 * Allocate a new unix-ID.
397 * For now this is for the default idmap domain only.
398 * Should be extended later on.
400 static NTSTATUS idmap_ldap_allocate_id(struct idmap_domain *dom,
401 struct unixid *id)
403 NTSTATUS ret;
405 if (!strequal(dom->name, "*")) {
406 DEBUG(3, ("idmap_ldap_allocate_id: "
407 "Refusing allocation of a new unixid for domain'%s'. "
408 "This is only supported for the default "
409 "domain \"*\".\n",
410 dom->name));
411 return NT_STATUS_NOT_IMPLEMENTED;
414 ret = idmap_ldap_allocate_id_internal(dom, id);
416 return ret;
420 /**********************************************************************
421 IDMAP MAPPING LDAP BACKEND
422 **********************************************************************/
424 static int idmap_ldap_close_destructor(struct idmap_ldap_context *ctx)
426 smbldap_free_struct(&ctx->smbldap_state);
427 DEBUG(5,("The connection to the LDAP server was closed\n"));
428 /* maybe free the results here --metze */
430 return 0;
433 /********************************
434 Initialise idmap database.
435 ********************************/
437 static NTSTATUS idmap_ldap_set_mapping(struct idmap_domain *dom,
438 const struct id_map *map);
440 static NTSTATUS idmap_ldap_db_init(struct idmap_domain *dom)
442 NTSTATUS ret;
443 struct idmap_ldap_context *ctx = NULL;
444 char *config_option = NULL;
445 const char *tmp = NULL;
447 /* Only do init if we are online */
448 if (idmap_is_offline()) {
449 return NT_STATUS_FILE_IS_OFFLINE;
452 ctx = talloc_zero(dom, struct idmap_ldap_context);
453 if ( ! ctx) {
454 DEBUG(0, ("Out of memory!\n"));
455 return NT_STATUS_NO_MEMORY;
458 config_option = talloc_asprintf(ctx, "idmap config %s", dom->name);
459 if (!config_option) {
460 DEBUG(0, ("Out of memory!\n"));
461 ret = NT_STATUS_NO_MEMORY;
462 goto done;
465 tmp = lp_parm_const_string(-1, config_option, "ldap_url", NULL);
467 if ( ! tmp) {
468 DEBUG(1, ("ERROR: missing idmap ldap url\n"));
469 ret = NT_STATUS_UNSUCCESSFUL;
470 goto done;
473 ctx->url = talloc_strdup(ctx, tmp);
475 trim_char(ctx->url, '\"', '\"');
477 tmp = lp_parm_const_string(-1, config_option, "ldap_base_dn", NULL);
478 if ( ! tmp || ! *tmp) {
479 tmp = lp_ldap_idmap_suffix(talloc_tos());
480 if ( ! tmp) {
481 DEBUG(1, ("ERROR: missing idmap ldap suffix\n"));
482 ret = NT_STATUS_UNSUCCESSFUL;
483 goto done;
487 ctx->suffix = talloc_strdup(ctx, tmp);
488 CHECK_ALLOC_DONE(ctx->suffix);
490 ctx->rw_ops = talloc_zero(ctx, struct idmap_rw_ops);
491 CHECK_ALLOC_DONE(ctx->rw_ops);
493 ctx->rw_ops->get_new_id = idmap_ldap_allocate_id_internal;
494 ctx->rw_ops->set_mapping = idmap_ldap_set_mapping;
496 /* get_credentials deals with setting up creds */
498 ret = smbldap_init(ctx, winbind_event_context(), ctx->url,
499 false, NULL, NULL, &ctx->smbldap_state);
500 if (!NT_STATUS_IS_OK(ret)) {
501 DEBUG(1, ("ERROR: smbldap_init (%s) failed!\n", ctx->url));
502 goto done;
505 ret = get_credentials( ctx, ctx->smbldap_state, config_option,
506 dom, &ctx->user_dn );
507 if ( !NT_STATUS_IS_OK(ret) ) {
508 DEBUG(1,("idmap_ldap_db_init: Failed to get connection "
509 "credentials (%s)\n", nt_errstr(ret)));
510 goto done;
514 * Set the destructor on the context, so that resources are
515 * properly freed when the context is released.
517 talloc_set_destructor(ctx, idmap_ldap_close_destructor);
519 dom->private_data = ctx;
521 ret = verify_idpool(dom);
522 if (!NT_STATUS_IS_OK(ret)) {
523 DEBUG(1, ("idmap_ldap_db_init: failed to verify ID pool (%s)\n",
524 nt_errstr(ret)));
525 goto done;
528 talloc_free(config_option);
529 return NT_STATUS_OK;
531 /*failed */
532 done:
533 talloc_free(ctx);
534 return ret;
538 * set a mapping.
541 /* TODO: change this: This function cannot be called to modify a mapping,
542 * only set a new one */
544 static NTSTATUS idmap_ldap_set_mapping(struct idmap_domain *dom,
545 const struct id_map *map)
547 NTSTATUS ret;
548 TALLOC_CTX *memctx;
549 struct idmap_ldap_context *ctx;
550 LDAPMessage *entry = NULL;
551 LDAPMod **mods = NULL;
552 const char *type;
553 char *id_str;
554 char *sid;
555 char *dn;
556 int rc = -1;
558 /* Only do query if we are online */
559 if (idmap_is_offline()) {
560 return NT_STATUS_FILE_IS_OFFLINE;
563 ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context);
565 switch(map->xid.type) {
566 case ID_TYPE_UID:
567 type = get_attr_key2string(sidmap_attr_list,
568 LDAP_ATTR_UIDNUMBER);
569 break;
571 case ID_TYPE_GID:
572 type = get_attr_key2string(sidmap_attr_list,
573 LDAP_ATTR_GIDNUMBER);
574 break;
576 default:
577 return NT_STATUS_INVALID_PARAMETER;
580 memctx = talloc_new(ctx);
581 if ( ! memctx) {
582 DEBUG(0, ("Out of memory!\n"));
583 return NT_STATUS_NO_MEMORY;
586 id_str = talloc_asprintf(memctx, "%lu", (unsigned long)map->xid.id);
587 CHECK_ALLOC_DONE(id_str);
589 sid = talloc_strdup(memctx, sid_string_talloc(memctx, map->sid));
590 CHECK_ALLOC_DONE(sid);
592 dn = talloc_asprintf(memctx, "%s=%s,%s",
593 get_attr_key2string(sidmap_attr_list, LDAP_ATTR_SID),
594 sid,
595 ctx->suffix);
596 CHECK_ALLOC_DONE(dn);
598 smbldap_set_mod(&mods, LDAP_MOD_ADD,
599 "objectClass", LDAP_OBJ_IDMAP_ENTRY);
601 smbldap_make_mod(ctx->smbldap_state->ldap_struct,
602 entry, &mods, type, id_str);
604 smbldap_make_mod(ctx->smbldap_state->ldap_struct, entry, &mods,
605 get_attr_key2string(sidmap_attr_list, LDAP_ATTR_SID),
606 sid);
608 if ( ! mods) {
609 DEBUG(2, ("ERROR: No mods?\n"));
610 ret = NT_STATUS_UNSUCCESSFUL;
611 goto done;
614 /* TODO: remove conflicting mappings! */
616 smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_SID_ENTRY);
618 DEBUG(10, ("Set DN %s (%s -> %s)\n", dn, sid, id_str));
620 rc = smbldap_add(ctx->smbldap_state, dn, mods);
621 ldap_mods_free(mods, True);
623 if (rc != LDAP_SUCCESS) {
624 char *ld_error = NULL;
625 ldap_get_option(ctx->smbldap_state->ldap_struct,
626 LDAP_OPT_ERROR_STRING, &ld_error);
627 DEBUG(0,("ldap_set_mapping_internals: Failed to add %s to %lu "
628 "mapping [%s]\n", sid,
629 (unsigned long)map->xid.id, type));
630 DEBUG(0, ("ldap_set_mapping_internals: Error was: %s (%s)\n",
631 ld_error ? ld_error : "(NULL)", ldap_err2string (rc)));
632 if (ld_error) {
633 ldap_memfree(ld_error);
635 ret = NT_STATUS_UNSUCCESSFUL;
636 goto done;
639 DEBUG(10,("ldap_set_mapping: Successfully created mapping from %s to "
640 "%lu [%s]\n", sid, (unsigned long)map->xid.id, type));
642 ret = NT_STATUS_OK;
644 done:
645 talloc_free(memctx);
646 return ret;
650 * Create a new mapping for an unmapped SID, also allocating a new ID.
651 * If possible, this should be run inside a transaction to make the
652 * action atomic.
654 static NTSTATUS idmap_ldap_new_mapping(struct idmap_domain *dom, struct id_map *map)
656 NTSTATUS ret;
657 struct idmap_ldap_context *ctx;
659 ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context);
661 ret = idmap_rw_new_mapping(dom, ctx->rw_ops, map);
663 return ret;
667 /* max number of ids requested per batch query */
668 #define IDMAP_LDAP_MAX_IDS 30
670 /**********************************
671 lookup a set of unix ids.
672 **********************************/
674 /* this function searches up to IDMAP_LDAP_MAX_IDS entries
675 * in maps for a match */
676 static struct id_map *find_map_by_id(struct id_map **maps,
677 enum id_type type,
678 uint32_t id)
680 int i;
682 for (i = 0; i < IDMAP_LDAP_MAX_IDS; i++) {
683 if (maps[i] == NULL) { /* end of the run */
684 return NULL;
686 if ((maps[i]->xid.type == type) && (maps[i]->xid.id == id)) {
687 return maps[i];
691 return NULL;
694 static NTSTATUS idmap_ldap_unixids_to_sids(struct idmap_domain *dom,
695 struct id_map **ids)
697 NTSTATUS ret;
698 TALLOC_CTX *memctx;
699 struct idmap_ldap_context *ctx;
700 LDAPMessage *result = NULL;
701 LDAPMessage *entry = NULL;
702 const char *uidNumber;
703 const char *gidNumber;
704 const char **attr_list;
705 char *filter = NULL;
706 bool multi = False;
707 int idx = 0;
708 int bidx = 0;
709 int count;
710 int rc;
711 int i;
713 /* Only do query if we are online */
714 if (idmap_is_offline()) {
715 return NT_STATUS_FILE_IS_OFFLINE;
718 ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context);
720 memctx = talloc_new(ctx);
721 if ( ! memctx) {
722 DEBUG(0, ("Out of memory!\n"));
723 return NT_STATUS_NO_MEMORY;
726 uidNumber = get_attr_key2string(idpool_attr_list, LDAP_ATTR_UIDNUMBER);
727 gidNumber = get_attr_key2string(idpool_attr_list, LDAP_ATTR_GIDNUMBER);
729 attr_list = get_attr_list(memctx, sidmap_attr_list);
731 if ( ! ids[1]) {
732 /* if we are requested just one mapping use the simple filter */
734 filter = talloc_asprintf(memctx, "(&(objectClass=%s)(%s=%lu))",
735 LDAP_OBJ_IDMAP_ENTRY,
736 (ids[0]->xid.type==ID_TYPE_UID)?uidNumber:gidNumber,
737 (unsigned long)ids[0]->xid.id);
738 CHECK_ALLOC_DONE(filter);
739 DEBUG(10, ("Filter: [%s]\n", filter));
740 } else {
741 /* multiple mappings */
742 multi = True;
745 for (i = 0; ids[i]; i++) {
746 ids[i]->status = ID_UNKNOWN;
749 again:
750 if (multi) {
752 talloc_free(filter);
753 filter = talloc_asprintf(memctx,
754 "(&(objectClass=%s)(|",
755 LDAP_OBJ_IDMAP_ENTRY);
756 CHECK_ALLOC_DONE(filter);
758 bidx = idx;
759 for (i = 0; (i < IDMAP_LDAP_MAX_IDS) && ids[idx]; i++, idx++) {
760 filter = talloc_asprintf_append_buffer(filter, "(%s=%lu)",
761 (ids[idx]->xid.type==ID_TYPE_UID)?uidNumber:gidNumber,
762 (unsigned long)ids[idx]->xid.id);
763 CHECK_ALLOC_DONE(filter);
765 filter = talloc_asprintf_append_buffer(filter, "))");
766 CHECK_ALLOC_DONE(filter);
767 DEBUG(10, ("Filter: [%s]\n", filter));
768 } else {
769 bidx = 0;
770 idx = 1;
773 rc = smbldap_search(ctx->smbldap_state, ctx->suffix, LDAP_SCOPE_SUBTREE,
774 filter, attr_list, 0, &result);
776 if (rc != LDAP_SUCCESS) {
777 DEBUG(3,("Failure looking up ids (%s)\n", ldap_err2string(rc)));
778 ret = NT_STATUS_UNSUCCESSFUL;
779 goto done;
782 count = ldap_count_entries(ctx->smbldap_state->ldap_struct, result);
784 if (count == 0) {
785 DEBUG(10, ("NO SIDs found\n"));
788 for (i = 0; i < count; i++) {
789 char *sidstr = NULL;
790 char *tmp = NULL;
791 enum id_type type;
792 struct id_map *map;
793 uint32_t id;
795 if (i == 0) { /* first entry */
796 entry = ldap_first_entry(ctx->smbldap_state->ldap_struct,
797 result);
798 } else { /* following ones */
799 entry = ldap_next_entry(ctx->smbldap_state->ldap_struct,
800 entry);
802 if ( ! entry) {
803 DEBUG(2, ("ERROR: Unable to fetch ldap entries "
804 "from results\n"));
805 break;
808 /* first check if the SID is present */
809 sidstr = smbldap_talloc_single_attribute(
810 ctx->smbldap_state->ldap_struct,
811 entry, LDAP_ATTRIBUTE_SID, memctx);
812 if ( ! sidstr) { /* no sid, skip entry */
813 DEBUG(2, ("WARNING SID not found on entry\n"));
814 continue;
817 /* now try to see if it is a uid, if not try with a gid
818 * (gid is more common, but in case both uidNumber and
819 * gidNumber are returned the SID is mapped to the uid
820 *not the gid) */
821 type = ID_TYPE_UID;
822 tmp = smbldap_talloc_single_attribute(
823 ctx->smbldap_state->ldap_struct,
824 entry, uidNumber, memctx);
825 if ( ! tmp) {
826 type = ID_TYPE_GID;
827 tmp = smbldap_talloc_single_attribute(
828 ctx->smbldap_state->ldap_struct,
829 entry, gidNumber, memctx);
831 if ( ! tmp) { /* wow very strange entry, how did it match ? */
832 DEBUG(5, ("Unprobable match on (%s), no uidNumber, "
833 "nor gidNumber returned\n", sidstr));
834 TALLOC_FREE(sidstr);
835 continue;
838 id = strtoul(tmp, NULL, 10);
839 if (!idmap_unix_id_is_in_range(id, dom)) {
840 DEBUG(5, ("Requested id (%u) out of range (%u - %u). "
841 "Filtered!\n", id,
842 dom->low_id, dom->high_id));
843 TALLOC_FREE(sidstr);
844 TALLOC_FREE(tmp);
845 continue;
847 TALLOC_FREE(tmp);
849 map = find_map_by_id(&ids[bidx], type, id);
850 if (!map) {
851 DEBUG(2, ("WARNING: couldn't match sid (%s) "
852 "with requested ids\n", sidstr));
853 TALLOC_FREE(sidstr);
854 continue;
857 if ( ! string_to_sid(map->sid, sidstr)) {
858 DEBUG(2, ("ERROR: Invalid SID on entry\n"));
859 TALLOC_FREE(sidstr);
860 continue;
863 if (map->status == ID_MAPPED) {
864 DEBUG(1, ("WARNING: duplicate %s mapping in LDAP. "
865 "overwriting mapping %u -> %s with %u -> %s\n",
866 (type == ID_TYPE_UID) ? "UID" : "GID",
867 id, sid_string_dbg(map->sid), id, sidstr));
870 TALLOC_FREE(sidstr);
872 /* mapped */
873 map->status = ID_MAPPED;
875 DEBUG(10, ("Mapped %s -> %lu (%d)\n", sid_string_dbg(map->sid),
876 (unsigned long)map->xid.id, map->xid.type));
879 /* free the ldap results */
880 if (result) {
881 ldap_msgfree(result);
882 result = NULL;
885 if (multi && ids[idx]) { /* still some values to map */
886 goto again;
889 ret = NT_STATUS_OK;
891 /* mark all unknwon/expired ones as unmapped */
892 for (i = 0; ids[i]; i++) {
893 if (ids[i]->status != ID_MAPPED)
894 ids[i]->status = ID_UNMAPPED;
897 done:
898 talloc_free(memctx);
899 return ret;
902 /**********************************
903 lookup a set of sids.
904 **********************************/
906 /* this function searches up to IDMAP_LDAP_MAX_IDS entries
907 * in maps for a match */
908 static struct id_map *find_map_by_sid(struct id_map **maps, struct dom_sid *sid)
910 int i;
912 for (i = 0; i < IDMAP_LDAP_MAX_IDS; i++) {
913 if (maps[i] == NULL) { /* end of the run */
914 return NULL;
916 if (dom_sid_equal(maps[i]->sid, sid)) {
917 return maps[i];
921 return NULL;
924 static NTSTATUS idmap_ldap_sids_to_unixids(struct idmap_domain *dom,
925 struct id_map **ids)
927 LDAPMessage *entry = NULL;
928 NTSTATUS ret;
929 TALLOC_CTX *memctx;
930 struct idmap_ldap_context *ctx;
931 LDAPMessage *result = NULL;
932 const char *uidNumber;
933 const char *gidNumber;
934 const char **attr_list;
935 char *filter = NULL;
936 bool multi = False;
937 int idx = 0;
938 int bidx = 0;
939 int count;
940 int rc;
941 int i;
943 /* Only do query if we are online */
944 if (idmap_is_offline()) {
945 return NT_STATUS_FILE_IS_OFFLINE;
948 ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context);
950 memctx = talloc_new(ctx);
951 if ( ! memctx) {
952 DEBUG(0, ("Out of memory!\n"));
953 return NT_STATUS_NO_MEMORY;
956 uidNumber = get_attr_key2string(idpool_attr_list, LDAP_ATTR_UIDNUMBER);
957 gidNumber = get_attr_key2string(idpool_attr_list, LDAP_ATTR_GIDNUMBER);
959 attr_list = get_attr_list(memctx, sidmap_attr_list);
961 if ( ! ids[1]) {
962 /* if we are requested just one mapping use the simple filter */
964 filter = talloc_asprintf(memctx, "(&(objectClass=%s)(%s=%s))",
965 LDAP_OBJ_IDMAP_ENTRY,
966 LDAP_ATTRIBUTE_SID,
967 sid_string_talloc(memctx, ids[0]->sid));
968 CHECK_ALLOC_DONE(filter);
969 DEBUG(10, ("Filter: [%s]\n", filter));
970 } else {
971 /* multiple mappings */
972 multi = True;
975 for (i = 0; ids[i]; i++) {
976 ids[i]->status = ID_UNKNOWN;
979 again:
980 if (multi) {
982 TALLOC_FREE(filter);
983 filter = talloc_asprintf(memctx,
984 "(&(objectClass=%s)(|",
985 LDAP_OBJ_IDMAP_ENTRY);
986 CHECK_ALLOC_DONE(filter);
988 bidx = idx;
989 for (i = 0; (i < IDMAP_LDAP_MAX_IDS) && ids[idx]; i++, idx++) {
990 filter = talloc_asprintf_append_buffer(filter, "(%s=%s)",
991 LDAP_ATTRIBUTE_SID,
992 sid_string_talloc(memctx,
993 ids[idx]->sid));
994 CHECK_ALLOC_DONE(filter);
996 filter = talloc_asprintf_append_buffer(filter, "))");
997 CHECK_ALLOC_DONE(filter);
998 DEBUG(10, ("Filter: [%s]", filter));
999 } else {
1000 bidx = 0;
1001 idx = 1;
1004 rc = smbldap_search(ctx->smbldap_state, ctx->suffix, LDAP_SCOPE_SUBTREE,
1005 filter, attr_list, 0, &result);
1007 if (rc != LDAP_SUCCESS) {
1008 DEBUG(3,("Failure looking up sids (%s)\n",
1009 ldap_err2string(rc)));
1010 ret = NT_STATUS_UNSUCCESSFUL;
1011 goto done;
1014 count = ldap_count_entries(ctx->smbldap_state->ldap_struct, result);
1016 if (count == 0) {
1017 DEBUG(10, ("NO SIDs found\n"));
1020 for (i = 0; i < count; i++) {
1021 char *sidstr = NULL;
1022 char *tmp = NULL;
1023 enum id_type type;
1024 struct id_map *map;
1025 struct dom_sid sid;
1026 uint32_t id;
1028 if (i == 0) { /* first entry */
1029 entry = ldap_first_entry(ctx->smbldap_state->ldap_struct,
1030 result);
1031 } else { /* following ones */
1032 entry = ldap_next_entry(ctx->smbldap_state->ldap_struct,
1033 entry);
1035 if ( ! entry) {
1036 DEBUG(2, ("ERROR: Unable to fetch ldap entries "
1037 "from results\n"));
1038 break;
1041 /* first check if the SID is present */
1042 sidstr = smbldap_talloc_single_attribute(
1043 ctx->smbldap_state->ldap_struct,
1044 entry, LDAP_ATTRIBUTE_SID, memctx);
1045 if ( ! sidstr) { /* no sid ??, skip entry */
1046 DEBUG(2, ("WARNING SID not found on entry\n"));
1047 continue;
1050 if ( ! string_to_sid(&sid, sidstr)) {
1051 DEBUG(2, ("ERROR: Invalid SID on entry\n"));
1052 TALLOC_FREE(sidstr);
1053 continue;
1056 map = find_map_by_sid(&ids[bidx], &sid);
1057 if (!map) {
1058 DEBUG(2, ("WARNING: couldn't find entry sid (%s) "
1059 "in ids", sidstr));
1060 TALLOC_FREE(sidstr);
1061 continue;
1064 /* now try to see if it is a uid, if not try with a gid
1065 * (gid is more common, but in case both uidNumber and
1066 * gidNumber are returned the SID is mapped to the uid
1067 * not the gid) */
1068 type = ID_TYPE_UID;
1069 tmp = smbldap_talloc_single_attribute(
1070 ctx->smbldap_state->ldap_struct,
1071 entry, uidNumber, memctx);
1072 if ( ! tmp) {
1073 type = ID_TYPE_GID;
1074 tmp = smbldap_talloc_single_attribute(
1075 ctx->smbldap_state->ldap_struct,
1076 entry, gidNumber, memctx);
1078 if ( ! tmp) { /* no ids ?? */
1079 DEBUG(5, ("no uidNumber, "
1080 "nor gidNumber attributes found\n"));
1081 TALLOC_FREE(sidstr);
1082 continue;
1085 id = strtoul(tmp, NULL, 10);
1086 if (!idmap_unix_id_is_in_range(id, dom)) {
1087 DEBUG(5, ("Requested id (%u) out of range (%u - %u). "
1088 "Filtered!\n", id,
1089 dom->low_id, dom->high_id));
1090 TALLOC_FREE(sidstr);
1091 TALLOC_FREE(tmp);
1092 continue;
1094 TALLOC_FREE(tmp);
1096 if (map->status == ID_MAPPED) {
1097 DEBUG(1, ("WARNING: duplicate %s mapping in LDAP. "
1098 "overwriting mapping %s -> %u with %s -> %u\n",
1099 (type == ID_TYPE_UID) ? "UID" : "GID",
1100 sidstr, map->xid.id, sidstr, id));
1103 TALLOC_FREE(sidstr);
1105 /* mapped */
1106 map->xid.type = type;
1107 map->xid.id = id;
1108 map->status = ID_MAPPED;
1110 DEBUG(10, ("Mapped %s -> %lu (%d)\n", sid_string_dbg(map->sid),
1111 (unsigned long)map->xid.id, map->xid.type));
1114 /* free the ldap results */
1115 if (result) {
1116 ldap_msgfree(result);
1117 result = NULL;
1120 if (multi && ids[idx]) { /* still some values to map */
1121 goto again;
1125 * try to create new mappings for unmapped sids
1127 for (i = 0; ids[i]; i++) {
1128 if (ids[i]->status != ID_MAPPED) {
1129 ids[i]->status = ID_UNMAPPED;
1130 if (ids[i]->sid != NULL) {
1131 ret = idmap_ldap_new_mapping(dom, ids[i]);
1132 if (!NT_STATUS_IS_OK(ret)) {
1133 goto done;
1139 ret = NT_STATUS_OK;
1141 done:
1142 talloc_free(memctx);
1143 return ret;
1146 /**********************************
1147 Close the idmap ldap instance
1148 **********************************/
1150 static struct idmap_methods idmap_ldap_methods = {
1152 .init = idmap_ldap_db_init,
1153 .unixids_to_sids = idmap_ldap_unixids_to_sids,
1154 .sids_to_unixids = idmap_ldap_sids_to_unixids,
1155 .allocate_id = idmap_ldap_allocate_id,
1158 NTSTATUS idmap_ldap_init(void);
1159 NTSTATUS idmap_ldap_init(void)
1161 return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "ldap",
1162 &idmap_ldap_methods);