s3:idmap_ldap: add my (C)
[kai/samba.git] / source3 / winbindd / idmap_ldap.c
index a980d54bbe9ec6de30302cd51c6732b2250fc974..995471f2b804103a138a93375699edb056f3592c 100644 (file)
@@ -7,6 +7,7 @@
    Copyright (C) Jim McDonough <jmcd@us.ibm.com>       2003
    Copyright (C) Gerald Carter                 2003
    Copyright (C) Simo Sorce            2003-2007
+   Copyright (C) Michael Adam          2010
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -24,6 +25,7 @@
 
 #include "includes.h"
 #include "winbindd.h"
+#include "secrets.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_IDMAP
 
 #include "smbldap.h"
 
-struct idmap_ldap_context {
+static char *idmap_fetch_secret(const char *backend, bool alloc,
+                               const char *domain, const char *identity)
+{
+       char *tmp, *ret;
+       int r;
+
+       if (alloc) {
+               r = asprintf(&tmp, "IDMAP_ALLOC_%s", backend);
+       } else {
+               r = asprintf(&tmp, "IDMAP_%s_%s", backend, domain);
+       }
+
+       if (r < 0)
+               return NULL;
+
+       strupper_m(tmp); /* make sure the key is case insensitive */
+       ret = secrets_fetch_generic(tmp, identity);
+
+       SAFE_FREE(tmp);
+
+       return ret;
+}
+
+struct idmap_ldap_alloc_context {
        struct smbldap_state *smbldap_state;
        char *url;
        char *suffix;
        char *user_dn;
-       uint32_t filter_low_id, filter_high_id;         /* Filter range */
-       bool anon;
 };
 
-struct idmap_ldap_alloc_context {
+struct idmap_ldap_context {
        struct smbldap_state *smbldap_state;
        char *url;
        char *suffix;
        char *user_dn;
-       uid_t low_uid, high_uid;      /* Range of uids */
-       gid_t low_gid, high_gid;      /* Range of gids */
-
+       bool anon;
+       struct idmap_ldap_alloc_context *alloc;
 };
 
 #define CHECK_ALLOC_DONE(mem) do { \
@@ -63,8 +85,6 @@ struct idmap_ldap_alloc_context {
  IDMAP ALLOC TDB BACKEND
 **********************************************************************/
 
-static struct idmap_ldap_alloc_context *idmap_alloc_ldap;
-
 /*********************************************************************
  ********************************************************************/
 
@@ -108,6 +128,7 @@ static NTSTATUS get_credentials( TALLOC_CTX *mem_ctx,
                        DEBUG(2, ("get_credentials: Failed to lookup ldap "
                                  "bind creds. Using anonymous connection.\n"));
                        anon = True;
+                       *dn = NULL;
                } else {
                        *dn = talloc_strdup(mem_ctx, user_dn);
                        SAFE_FREE( user_dn );
@@ -129,35 +150,38 @@ done:
  Verify the sambaUnixIdPool entry in the directory.
 **********************************************************************/
 
-static NTSTATUS verify_idpool(void)
+static NTSTATUS verify_idpool(struct idmap_domain *dom)
 {
        NTSTATUS ret;
-       TALLOC_CTX *ctx;
+       TALLOC_CTX *mem_ctx;
        LDAPMessage *result = NULL;
        LDAPMod **mods = NULL;
        const char **attr_list;
        char *filter;
        int count;
        int rc;
+       struct idmap_ldap_context *ctx;
 
-       if ( ! idmap_alloc_ldap) {
+       ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context);
+
+       if (!ctx->alloc) {
                return NT_STATUS_UNSUCCESSFUL;
        }
 
-       ctx = talloc_new(idmap_alloc_ldap);
-       if ( ! ctx) {
+       mem_ctx = talloc_new(ctx->alloc);
+       if (mem_ctx == NULL) {
                DEBUG(0, ("Out of memory!\n"));
                return NT_STATUS_NO_MEMORY;
        }
 
-       filter = talloc_asprintf(ctx, "(objectclass=%s)", LDAP_OBJ_IDPOOL);
+       filter = talloc_asprintf(mem_ctx, "(objectclass=%s)", LDAP_OBJ_IDPOOL);
        CHECK_ALLOC_DONE(filter);
 
-       attr_list = get_attr_list(ctx, idpool_attr_list);
+       attr_list = get_attr_list(mem_ctx, idpool_attr_list);
        CHECK_ALLOC_DONE(attr_list);
 
-       rc = smbldap_search(idmap_alloc_ldap->smbldap_state,
-                               idmap_alloc_ldap->suffix,
+       rc = smbldap_search(ctx->alloc->smbldap_state,
+                               ctx->alloc->suffix,
                                LDAP_SCOPE_SUBTREE,
                                filter,
                                attr_list,
@@ -170,24 +194,24 @@ static NTSTATUS verify_idpool(void)
                return NT_STATUS_UNSUCCESSFUL;
        }
 
-       count = ldap_count_entries(idmap_alloc_ldap->smbldap_state->ldap_struct,
+       count = ldap_count_entries(ctx->alloc->smbldap_state->ldap_struct,
                                   result);
 
        ldap_msgfree(result);
 
        if ( count > 1 ) {
                DEBUG(0,("Multiple entries returned from %s (base == %s)\n",
-                       filter, idmap_alloc_ldap->suffix));
+                       filter, ctx->alloc->suffix));
                ret = NT_STATUS_UNSUCCESSFUL;
                goto done;
        }
        else if (count == 0) {
                char *uid_str, *gid_str;
 
-               uid_str = talloc_asprintf(ctx, "%lu",
-                               (unsigned long)idmap_alloc_ldap->low_uid);
-               gid_str = talloc_asprintf(ctx, "%lu",
-                               (unsigned long)idmap_alloc_ldap->low_gid);
+               uid_str = talloc_asprintf(mem_ctx, "%lu",
+                               (unsigned long)dom->low_id);
+               gid_str = talloc_asprintf(mem_ctx, "%lu",
+                               (unsigned long)dom->low_id);
 
                smbldap_set_mod(&mods, LDAP_MOD_ADD,
                                "objectClass", LDAP_OBJ_IDPOOL);
@@ -200,8 +224,8 @@ static NTSTATUS verify_idpool(void)
                                                    LDAP_ATTR_GIDNUMBER),
                                gid_str);
                if (mods) {
-                       rc = smbldap_modify(idmap_alloc_ldap->smbldap_state,
-                                               idmap_alloc_ldap->suffix,
+                       rc = smbldap_modify(ctx->alloc->smbldap_state,
+                                               ctx->alloc->suffix,
                                                mods);
                        ldap_mods_free(mods, True);
                } else {
@@ -212,7 +236,7 @@ static NTSTATUS verify_idpool(void)
 
        ret = (rc == LDAP_SUCCESS)?NT_STATUS_OK:NT_STATUS_UNSUCCESSFUL;
 done:
-       talloc_free(ctx);
+       talloc_free(mem_ctx);
        return ret;
 }
 
@@ -220,78 +244,34 @@ done:
  Initialise idmap database.
 *****************************************************************************/
 
-static NTSTATUS idmap_ldap_alloc_init(const char *params)
+static int idmap_ldap_alloc_close_destructor(struct idmap_ldap_alloc_context *ctx)
+{
+       smbldap_free_struct(&ctx->smbldap_state);
+       DEBUG(5,("The connection to the LDAP server was closed\n"));
+       /* maybe free the results here --metze */
+       return 0;
+}
+
+static NTSTATUS idmap_ldap_alloc_init(struct idmap_domain *dom,
+                                     const char *params)
 {
        NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
-       const char *range;
        const char *tmp;
-       uid_t low_uid = 0;
-       uid_t high_uid = 0;
-       gid_t low_gid = 0;
-       gid_t high_gid = 0;
+       struct idmap_ldap_context *ctx;
 
        /* Only do init if we are online */
        if (idmap_is_offline()) {
                return NT_STATUS_FILE_IS_OFFLINE;
        }
 
-       idmap_alloc_ldap = TALLOC_ZERO_P(NULL, struct idmap_ldap_alloc_context);
-        CHECK_ALLOC_DONE( idmap_alloc_ldap );
-
-       /* load ranges */
-
-       idmap_alloc_ldap->low_uid = 0;
-       idmap_alloc_ldap->high_uid = 0;
-       idmap_alloc_ldap->low_gid = 0;
-       idmap_alloc_ldap->high_gid = 0;
-
-       range = lp_parm_const_string(-1, "idmap alloc config", "range", NULL);
-       if (range && range[0]) {
-               unsigned low_id, high_id;
-
-               if (sscanf(range, "%u - %u", &low_id, &high_id) == 2) {
-                       if (low_id < high_id) {
-                               idmap_alloc_ldap->low_gid = low_id;
-                               idmap_alloc_ldap->low_uid = low_id;
-                               idmap_alloc_ldap->high_gid = high_id;
-                               idmap_alloc_ldap->high_uid = high_id;
-                       } else {
-                               DEBUG(1, ("ERROR: invalid idmap alloc range "
-                                         "[%s]", range));
-                       }
-               } else {
-                       DEBUG(1, ("ERROR: invalid syntax for idmap alloc "
-                                 "config:range [%s]", range));
-               }
-       }
-
-       if (lp_idmap_uid(&low_uid, &high_uid)) {
-               idmap_alloc_ldap->low_uid = low_uid;
-               idmap_alloc_ldap->high_uid = high_uid;
-       }
-
-       if (lp_idmap_gid(&low_gid, &high_gid)) {
-               idmap_alloc_ldap->low_gid = low_gid;
-               idmap_alloc_ldap->high_gid= high_gid;
-       }
-
-       if (idmap_alloc_ldap->high_uid <= idmap_alloc_ldap->low_uid) {
-               DEBUG(1, ("idmap uid range missing or invalid\n"));
-               DEBUGADD(1, ("idmap will be unable to map foreign SIDs\n"));
-               ret = NT_STATUS_UNSUCCESSFUL;
-               goto done;
-       }
+       ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context);
 
-       if (idmap_alloc_ldap->high_gid <= idmap_alloc_ldap->low_gid) {
-               DEBUG(1, ("idmap gid range missing or invalid\n"));
-               DEBUGADD(1, ("idmap will be unable to map foreign SIDs\n"));
-               ret = NT_STATUS_UNSUCCESSFUL;
-               goto done;
-       }
+       ctx->alloc = talloc_zero(ctx, struct idmap_ldap_alloc_context);
+        CHECK_ALLOC_DONE(ctx->alloc);
 
        if (params && *params) {
                /* assume location is the only parameter */
-               idmap_alloc_ldap->url = talloc_strdup(idmap_alloc_ldap, params);
+               ctx->alloc->url = talloc_strdup(ctx->alloc, params);
        } else {
                tmp = lp_parm_const_string(-1, "idmap alloc config",
                                           "ldap_url", NULL);
@@ -302,9 +282,11 @@ static NTSTATUS idmap_ldap_alloc_init(const char *params)
                        goto done;
                }
 
-               idmap_alloc_ldap->url = talloc_strdup(idmap_alloc_ldap, tmp);
+               ctx->alloc->url = talloc_strdup(ctx->alloc, tmp);
        }
-       CHECK_ALLOC_DONE( idmap_alloc_ldap->url );
+       CHECK_ALLOC_DONE(ctx->alloc->url);
+
+       trim_char(ctx->alloc->url, '\"', '\"');
 
        tmp = lp_parm_const_string(-1, "idmap alloc config",
                                   "ldap_base_dn", NULL);
@@ -317,22 +299,24 @@ static NTSTATUS idmap_ldap_alloc_init(const char *params)
                }
        }
 
-       idmap_alloc_ldap->suffix = talloc_strdup(idmap_alloc_ldap, tmp);
-       CHECK_ALLOC_DONE( idmap_alloc_ldap->suffix );
+       ctx->alloc->suffix = talloc_strdup(ctx->alloc, tmp);
+       CHECK_ALLOC_DONE(ctx->alloc->suffix);
 
-       ret = smbldap_init(idmap_alloc_ldap, winbind_event_context(),
-                          idmap_alloc_ldap->url,
-                          &idmap_alloc_ldap->smbldap_state);
+       ret = smbldap_init(ctx->alloc, winbind_event_context(),
+                          ctx->alloc->url,
+                          &ctx->alloc->smbldap_state);
        if (!NT_STATUS_IS_OK(ret)) {
                DEBUG(1, ("ERROR: smbldap_init (%s) failed!\n",
-                         idmap_alloc_ldap->url));
+                         ctx->alloc->url));
                goto done;
        }
 
-        ret = get_credentials( idmap_alloc_ldap,
-                              idmap_alloc_ldap->smbldap_state,
-                              "idmap alloc config", NULL,
-                              &idmap_alloc_ldap->user_dn );
+       talloc_set_destructor(ctx->alloc, idmap_ldap_alloc_close_destructor);
+
+       ret = get_credentials(ctx->alloc,
+                             ctx->alloc->smbldap_state,
+                             "idmap alloc config", NULL,
+                             &ctx->alloc->user_dn);
        if ( !NT_STATUS_IS_OK(ret) ) {
                DEBUG(1,("idmap_ldap_alloc_init: Failed to get connection "
                         "credentials (%s)\n", nt_errstr(ret)));
@@ -341,11 +325,11 @@ static NTSTATUS idmap_ldap_alloc_init(const char *params)
 
        /* see if the idmap suffix and sub entries exists */
 
-       ret = verify_idpool();
+       ret = verify_idpool(dom);
 
  done:
        if ( !NT_STATUS_IS_OK( ret ) )
-               TALLOC_FREE( idmap_alloc_ldap );
+               TALLOC_FREE(ctx->alloc);
 
        return ret;
 }
@@ -354,9 +338,10 @@ static NTSTATUS idmap_ldap_alloc_init(const char *params)
  Allocate a new uid or gid
 ********************************/
 
-static NTSTATUS idmap_ldap_allocate_id(struct unixid *xid)
+static NTSTATUS idmap_ldap_allocate_id(struct idmap_domain *dom,
+                                      struct unixid *xid)
 {
-       TALLOC_CTX *ctx;
+       TALLOC_CTX *mem_ctx;
        NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
        int rc = LDAP_SERVER_DOWN;
        int count = 0;
@@ -369,18 +354,21 @@ static NTSTATUS idmap_ldap_allocate_id(struct unixid *xid)
        const char *dn = NULL;
        const char **attr_list;
        const char *type;
+       struct idmap_ldap_context *ctx;
 
        /* Only do query if we are online */
        if (idmap_is_offline()) {
                return NT_STATUS_FILE_IS_OFFLINE;
        }
 
-       if ( ! idmap_alloc_ldap) {
+       ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context);
+
+       if (!ctx->alloc) {
                return NT_STATUS_UNSUCCESSFUL;
        }
 
-       ctx = talloc_new(idmap_alloc_ldap);
-       if ( ! ctx) {
+       mem_ctx = talloc_new(ctx->alloc);
+       if (!mem_ctx) {
                DEBUG(0, ("Out of memory!\n"));
                return NT_STATUS_NO_MEMORY;
        }
@@ -403,16 +391,16 @@ static NTSTATUS idmap_ldap_allocate_id(struct unixid *xid)
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       filter = talloc_asprintf(ctx, "(objectClass=%s)", LDAP_OBJ_IDPOOL);
+       filter = talloc_asprintf(mem_ctx, "(objectClass=%s)", LDAP_OBJ_IDPOOL);
        CHECK_ALLOC_DONE(filter);
 
-       attr_list = get_attr_list(ctx, idpool_attr_list);
+       attr_list = get_attr_list(mem_ctx, idpool_attr_list);
        CHECK_ALLOC_DONE(attr_list);
 
        DEBUG(10, ("Search of the id pool (filter: %s)\n", filter));
 
-       rc = smbldap_search(idmap_alloc_ldap->smbldap_state,
-                               idmap_alloc_ldap->suffix,
+       rc = smbldap_search(ctx->alloc->smbldap_state,
+                               ctx->alloc->suffix,
                               LDAP_SCOPE_SUBTREE, filter,
                               attr_list, 0, &result);
 
@@ -421,33 +409,31 @@ static NTSTATUS idmap_ldap_allocate_id(struct unixid *xid)
                goto done;
        }
 
-       talloc_autofree_ldapmsg(ctx, result);
+       talloc_autofree_ldapmsg(mem_ctx, result);
 
-       count = ldap_count_entries(idmap_alloc_ldap->smbldap_state->ldap_struct,
+       count = ldap_count_entries(ctx->alloc->smbldap_state->ldap_struct,
                                   result);
        if (count != 1) {
                DEBUG(0,("Single %s object not found\n", LDAP_OBJ_IDPOOL));
                goto done;
        }
 
-       entry = ldap_first_entry(idmap_alloc_ldap->smbldap_state->ldap_struct,
+       entry = ldap_first_entry(ctx->alloc->smbldap_state->ldap_struct,
                                 result);
 
-       dn = smbldap_talloc_dn(ctx,
-                              idmap_alloc_ldap->smbldap_state->ldap_struct,
+       dn = smbldap_talloc_dn(mem_ctx,
+                              ctx->alloc->smbldap_state->ldap_struct,
                               entry);
        if ( ! dn) {
                goto done;
        }
 
-       if ( ! (id_str = smbldap_talloc_single_attribute(idmap_alloc_ldap->smbldap_state->ldap_struct,
-                               entry, type, ctx))) {
+       id_str = smbldap_talloc_single_attribute(
+                               ctx->alloc->smbldap_state->ldap_struct,
+                               entry, type, mem_ctx);
+       if (id_str == NULL) {
                DEBUG(0,("%s attribute not found\n", type));
-               goto done;
-       }
-       if ( ! id_str) {
-               DEBUG(0,("Out of memory\n"));
-               ret = NT_STATUS_NO_MEMORY;
+               ret = NT_STATUS_UNSUCCESSFUL;
                goto done;
        }
 
@@ -457,17 +443,17 @@ static NTSTATUS idmap_ldap_allocate_id(struct unixid *xid)
 
        switch (xid->type) {
        case ID_TYPE_UID:
-               if (xid->id > idmap_alloc_ldap->high_uid) {
+               if (xid->id > dom->high_id) {
                        DEBUG(0,("Cannot allocate uid above %lu!\n",
-                                (unsigned long)idmap_alloc_ldap->high_uid));
+                                (unsigned long)dom->high_id));
                        goto done;
                }
                break;
 
        case ID_TYPE_GID:
-               if (xid->id > idmap_alloc_ldap->high_gid) {
+               if (xid->id > dom->high_id) {
                        DEBUG(0,("Cannot allocate gid above %lu!\n",
-                                (unsigned long)idmap_alloc_ldap->high_uid));
+                                (unsigned long)dom->high_id));
                        goto done;
                }
                break;
@@ -477,7 +463,7 @@ static NTSTATUS idmap_ldap_allocate_id(struct unixid *xid)
                goto done;
        }
 
-       new_id_str = talloc_asprintf(ctx, "%lu", (unsigned long)xid->id + 1);
+       new_id_str = talloc_asprintf(mem_ctx, "%lu", (unsigned long)xid->id + 1);
        if ( ! new_id_str) {
                DEBUG(0,("Out of memory\n"));
                ret = NT_STATUS_NO_MEMORY;
@@ -495,7 +481,7 @@ static NTSTATUS idmap_ldap_allocate_id(struct unixid *xid)
        DEBUG(10, ("Try to atomically increment the id (%s -> %s)\n",
                   id_str, new_id_str));
 
-       rc = smbldap_modify(idmap_alloc_ldap->smbldap_state, dn, mods);
+       rc = smbldap_modify(ctx->alloc->smbldap_state, dn, mods);
 
        ldap_mods_free(mods, True);
 
@@ -508,357 +494,312 @@ static NTSTATUS idmap_ldap_allocate_id(struct unixid *xid)
        ret = NT_STATUS_OK;
 
 done:
-       talloc_free(ctx);
+       talloc_free(mem_ctx);
        return ret;
 }
 
-/**********************************
- Get current highest id.
-**********************************/
+/**
+ * Allocate a new unix-ID.
+ * For now this is for the default idmap domain only.
+ * Should be extended later on.
+ */
+static NTSTATUS idmap_ldap_get_new_id(struct idmap_domain *dom,
+                                     struct unixid *id)
+{
+       NTSTATUS ret;
+
+       if (!strequal(dom->name, "*")) {
+               DEBUG(3, ("idmap_ldap_get_new_id: "
+                         "Refusing allocation of a new unixid for domain'%s'. "
+                         "Currently only supported for the default "
+                         "domain \"*\".\n",
+                          dom->name));
+               return NT_STATUS_NOT_IMPLEMENTED;
+       }
 
-static NTSTATUS idmap_ldap_get_hwm(struct unixid *xid)
+       ret = idmap_ldap_allocate_id(dom, id);
+
+       return ret;
+}
+
+
+/**********************************************************************
+ IDMAP MAPPING LDAP BACKEND
+**********************************************************************/
+
+static int idmap_ldap_close_destructor(struct idmap_ldap_context *ctx)
 {
-       TALLOC_CTX *memctx;
-       NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
-       int rc = LDAP_SERVER_DOWN;
-       int count = 0;
-       LDAPMessage *result = NULL;
-       LDAPMessage *entry = NULL;
-       char *id_str;
-       char *filter = NULL;
-       const char **attr_list;
-       const char *type;
+       smbldap_free_struct(&ctx->smbldap_state);
+       DEBUG(5,("The connection to the LDAP server was closed\n"));
+       /* maybe free the results here --metze */
 
-       /* Only do query if we are online */
+       return 0;
+}
+
+/********************************
+ Initialise idmap database.
+********************************/
+
+static NTSTATUS idmap_ldap_db_init(struct idmap_domain *dom,
+                                  const char *params)
+{
+       NTSTATUS ret;
+       struct idmap_ldap_context *ctx = NULL;
+       char *config_option = NULL;
+       const char *tmp = NULL;
+
+       /* Only do init if we are online */
        if (idmap_is_offline()) {
                return NT_STATUS_FILE_IS_OFFLINE;
        }
 
-       if ( ! idmap_alloc_ldap) {
-               return NT_STATUS_UNSUCCESSFUL;
-       }
-
-       memctx = talloc_new(idmap_alloc_ldap);
-       if ( ! memctx) {
+       ctx = TALLOC_ZERO_P(dom, struct idmap_ldap_context);
+       if ( ! ctx) {
                DEBUG(0, ("Out of memory!\n"));
                return NT_STATUS_NO_MEMORY;
        }
 
-       /* get type */
-       switch (xid->type) {
+       if (strequal(dom->name, "*")) {
+               /* more specific configuration can go here */
+       } else {
+               config_option = talloc_asprintf(ctx, "idmap config %s", dom->name);
+               if ( ! config_option) {
+                       DEBUG(0, ("Out of memory!\n"));
+                       ret = NT_STATUS_NO_MEMORY;
+                       goto done;
+               }
+       }
 
-       case ID_TYPE_UID:
-               type = get_attr_key2string(idpool_attr_list,
-                                          LDAP_ATTR_UIDNUMBER);
-               break;
+       if (params != NULL) {
+               /* assume location is the only parameter */
+               ctx->url = talloc_strdup(ctx, params);
+       } else {
+               tmp = lp_parm_const_string(-1, config_option, "ldap_url", NULL);
 
-       case ID_TYPE_GID:
-               type = get_attr_key2string(idpool_attr_list,
-                                          LDAP_ATTR_GIDNUMBER);
-               break;
+               if ( ! tmp) {
+                       DEBUG(1, ("ERROR: missing idmap ldap url\n"));
+                       ret = NT_STATUS_UNSUCCESSFUL;
+                       goto done;
+               }
 
-       default:
-               DEBUG(2, ("Invalid ID type (0x%x)\n", xid->type));
-               return NT_STATUS_INVALID_PARAMETER;
+               ctx->url = talloc_strdup(ctx, tmp);
        }
+       CHECK_ALLOC_DONE(ctx->url);
 
-       filter = talloc_asprintf(memctx, "(objectClass=%s)", LDAP_OBJ_IDPOOL);
-       CHECK_ALLOC_DONE(filter);
+       trim_char(ctx->url, '\"', '\"');
 
-       attr_list = get_attr_list(memctx, idpool_attr_list);
-       CHECK_ALLOC_DONE(attr_list);
+       tmp = lp_parm_const_string(-1, config_option, "ldap_base_dn", NULL);
+       if ( ! tmp || ! *tmp) {
+               tmp = lp_ldap_idmap_suffix();
+               if ( ! tmp) {
+                       DEBUG(1, ("ERROR: missing idmap ldap suffix\n"));
+                       ret = NT_STATUS_UNSUCCESSFUL;
+                       goto done;
+               }
+       }
 
-       rc = smbldap_search(idmap_alloc_ldap->smbldap_state,
-                               idmap_alloc_ldap->suffix,
-                              LDAP_SCOPE_SUBTREE, filter,
-                              attr_list, 0, &result);
+       ctx->suffix = talloc_strdup(ctx, tmp);
+       CHECK_ALLOC_DONE(ctx->suffix);
 
-       if (rc != LDAP_SUCCESS) {
-               DEBUG(0,("%s object not found\n", LDAP_OBJ_IDPOOL));
+       ret = smbldap_init(ctx, winbind_event_context(), ctx->url,
+                          &ctx->smbldap_state);
+       if (!NT_STATUS_IS_OK(ret)) {
+               DEBUG(1, ("ERROR: smbldap_init (%s) failed!\n", ctx->url));
                goto done;
        }
 
-       talloc_autofree_ldapmsg(memctx, result);
-
-       count = ldap_count_entries(idmap_alloc_ldap->smbldap_state->ldap_struct,
-                                  result);
-       if (count != 1) {
-               DEBUG(0,("Single %s object not found\n", LDAP_OBJ_IDPOOL));
+       ret = get_credentials( ctx, ctx->smbldap_state, config_option,
+                              dom, &ctx->user_dn );
+       if ( !NT_STATUS_IS_OK(ret) ) {
+               DEBUG(1,("idmap_ldap_db_init: Failed to get connection "
+                        "credentials (%s)\n", nt_errstr(ret)));
                goto done;
        }
 
-       entry = ldap_first_entry(idmap_alloc_ldap->smbldap_state->ldap_struct,
-                                result);
+       /* set the destructor on the context, so that resource are properly
+          freed if the contexts is released */
 
-       id_str = smbldap_talloc_single_attribute(idmap_alloc_ldap->smbldap_state->ldap_struct,
-                       entry, type, memctx);
-       if ( ! id_str) {
-               DEBUG(0,("%s attribute not found\n", type));
-               goto done;
-       }
-       if ( ! id_str) {
-               DEBUG(0,("Out of memory\n"));
-               ret = NT_STATUS_NO_MEMORY;
+       talloc_set_destructor(ctx, idmap_ldap_close_destructor);
+
+       dom->private_data = ctx;
+
+       ret = idmap_ldap_alloc_init(dom, params);
+       if (!NT_STATUS_IS_OK(ret)) {
+               DEBUG(1, ("idmap_ldap_db_init: Failed to initialize alloc "
+                         "subsystem: %s\n", nt_errstr(ret)));
                goto done;
        }
 
-       xid->id = strtoul(id_str, NULL, 10);
+       talloc_free(config_option);
+       return NT_STATUS_OK;
 
-       ret = NT_STATUS_OK;
+/*failed */
 done:
-       talloc_free(memctx);
+       talloc_free(ctx);
        return ret;
 }
-/**********************************
- Set highest id.
-**********************************/
 
-static NTSTATUS idmap_ldap_set_hwm(struct unixid *xid)
+/**
+ * set a mapping.
+ */
+
+/* TODO: change this:  This function cannot be called to modify a mapping,
+ * only set a new one */
+
+static NTSTATUS idmap_ldap_set_mapping(struct idmap_domain *dom,
+                                      const struct id_map *map)
 {
-       TALLOC_CTX *ctx;
-       NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
-       int rc = LDAP_SERVER_DOWN;
-       int count = 0;
-       LDAPMessage *result = NULL;
+       NTSTATUS ret;
+       TALLOC_CTX *memctx;
+       struct idmap_ldap_context *ctx;
        LDAPMessage *entry = NULL;
        LDAPMod **mods = NULL;
-       char *new_id_str;
-       char *filter = NULL;
-       const char *dn = NULL;
-       const char **attr_list;
        const char *type;
+       char *id_str;
+       char *sid;
+       char *dn;
+       int rc = -1;
 
        /* Only do query if we are online */
        if (idmap_is_offline()) {
                return NT_STATUS_FILE_IS_OFFLINE;
        }
 
-       if ( ! idmap_alloc_ldap) {
-               return NT_STATUS_UNSUCCESSFUL;
-       }
-
-       ctx = talloc_new(idmap_alloc_ldap);
-       if ( ! ctx) {
-               DEBUG(0, ("Out of memory!\n"));
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       /* get type */
-       switch (xid->type) {
+       ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context);
 
+       switch(map->xid.type) {
        case ID_TYPE_UID:
-               type = get_attr_key2string(idpool_attr_list,
+               type = get_attr_key2string(sidmap_attr_list,
                                           LDAP_ATTR_UIDNUMBER);
-               break;
+               break;
 
        case ID_TYPE_GID:
-               type = get_attr_key2string(idpool_attr_list,
+               type = get_attr_key2string(sidmap_attr_list,
                                           LDAP_ATTR_GIDNUMBER);
                break;
 
        default:
-               DEBUG(2, ("Invalid ID type (0x%x)\n", xid->type));
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       filter = talloc_asprintf(ctx, "(objectClass=%s)", LDAP_OBJ_IDPOOL);
-       CHECK_ALLOC_DONE(filter);
-
-       attr_list = get_attr_list(ctx, idpool_attr_list);
-       CHECK_ALLOC_DONE(attr_list);
+       memctx = talloc_new(ctx);
+       if ( ! memctx) {
+               DEBUG(0, ("Out of memory!\n"));
+               return NT_STATUS_NO_MEMORY;
+       }
 
-       rc = smbldap_search(idmap_alloc_ldap->smbldap_state,
-                               idmap_alloc_ldap->suffix,
-                              LDAP_SCOPE_SUBTREE, filter,
-                              attr_list, 0, &result);
+       id_str = talloc_asprintf(memctx, "%lu", (unsigned long)map->xid.id);
+       CHECK_ALLOC_DONE(id_str);
 
-       if (rc != LDAP_SUCCESS) {
-               DEBUG(0,("%s object not found\n", LDAP_OBJ_IDPOOL));
-               goto done;
-       }
+       sid = talloc_strdup(memctx, sid_string_talloc(memctx, map->sid));
+       CHECK_ALLOC_DONE(sid);
 
-       talloc_autofree_ldapmsg(ctx, result);
+       dn = talloc_asprintf(memctx, "%s=%s,%s",
+                       get_attr_key2string(sidmap_attr_list, LDAP_ATTR_SID),
+                       sid,
+                       ctx->suffix);
+       CHECK_ALLOC_DONE(dn);
 
-       count = ldap_count_entries(idmap_alloc_ldap->smbldap_state->ldap_struct,
-                                  result);
-       if (count != 1) {
-               DEBUG(0,("Single %s object not found\n", LDAP_OBJ_IDPOOL));
-               goto done;
-       }
+       smbldap_set_mod(&mods, LDAP_MOD_ADD,
+                       "objectClass", LDAP_OBJ_IDMAP_ENTRY);
 
-       entry = ldap_first_entry(idmap_alloc_ldap->smbldap_state->ldap_struct,
-                                result);
+       smbldap_make_mod(ctx->smbldap_state->ldap_struct,
+                        entry, &mods, type, id_str);
 
-       dn = smbldap_talloc_dn(ctx,
-                               idmap_alloc_ldap->smbldap_state->ldap_struct,
-                               entry);
-       if ( ! dn) {
-               goto done;
-       }
+       smbldap_make_mod(ctx->smbldap_state->ldap_struct, entry, &mods,
+                        get_attr_key2string(sidmap_attr_list, LDAP_ATTR_SID),
+                        sid);
 
-       new_id_str = talloc_asprintf(ctx, "%lu", (unsigned long)xid->id);
-       if ( ! new_id_str) {
-               DEBUG(0,("Out of memory\n"));
-               ret = NT_STATUS_NO_MEMORY;
+       if ( ! mods) {
+               DEBUG(2, ("ERROR: No mods?\n"));
+               ret = NT_STATUS_UNSUCCESSFUL;
                goto done;
        }
 
-       smbldap_set_mod(&mods, LDAP_MOD_REPLACE, type, new_id_str);
+       /* TODO: remove conflicting mappings! */
 
-       if (mods == NULL) {
-               DEBUG(0,("smbldap_set_mod() failed.\n"));
-               goto done;
-       }
+       smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_SID_ENTRY);
 
-       rc = smbldap_modify(idmap_alloc_ldap->smbldap_state, dn, mods);
+       DEBUG(10, ("Set DN %s (%s -> %s)\n", dn, sid, id_str));
 
+       rc = smbldap_add(ctx->smbldap_state, dn, mods);
        ldap_mods_free(mods, True);
 
        if (rc != LDAP_SUCCESS) {
-               DEBUG(1,("Failed to allocate new %s. "
-                        "smbldap_modify() failed.\n", type));
+               char *ld_error = NULL;
+               ldap_get_option(ctx->smbldap_state->ldap_struct,
+                               LDAP_OPT_ERROR_STRING, &ld_error);
+               DEBUG(0,("ldap_set_mapping_internals: Failed to add %s to %lu "
+                        "mapping [%s]\n", sid,
+                        (unsigned long)map->xid.id, type));
+               DEBUG(0, ("ldap_set_mapping_internals: Error was: %s (%s)\n",
+                       ld_error ? ld_error : "(NULL)", ldap_err2string (rc)));
+               if (ld_error) {
+                       ldap_memfree(ld_error);
+               }
+               ret = NT_STATUS_UNSUCCESSFUL;
                goto done;
        }
 
+       DEBUG(10,("ldap_set_mapping: Successfully created mapping from %s to "
+                 "%lu [%s]\n", sid, (unsigned long)map->xid.id, type));
+
        ret = NT_STATUS_OK;
 
 done:
-       talloc_free(ctx);
+       talloc_free(memctx);
        return ret;
 }
 
-/**********************************
- Close idmap ldap alloc
-**********************************/
-
-static NTSTATUS idmap_ldap_alloc_close(void)
-{
-       if (idmap_alloc_ldap) {
-               smbldap_free_struct(&idmap_alloc_ldap->smbldap_state);
-               DEBUG(5,("The connection to the LDAP server was closed\n"));
-               /* maybe free the results here --metze */
-               TALLOC_FREE(idmap_alloc_ldap);
-       }
-       return NT_STATUS_OK;
-}
-
-
-/**********************************************************************
- IDMAP MAPPING LDAP BACKEND
-**********************************************************************/
-
-static int idmap_ldap_close_destructor(struct idmap_ldap_context *ctx)
-{
-       smbldap_free_struct(&ctx->smbldap_state);
-       DEBUG(5,("The connection to the LDAP server was closed\n"));
-       /* maybe free the results here --metze */
-
-       return 0;
-}
-
-/********************************
- Initialise idmap database.
-********************************/
-
-static NTSTATUS idmap_ldap_db_init(struct idmap_domain *dom)
+/**
+ * Create a new mapping for an unmapped SID, also allocating a new ID.
+ * If possible, this should be run inside a transaction to make the
+ * action atomic.
+ */
+static NTSTATUS idmap_ldap_new_mapping(struct idmap_domain *dom, struct id_map *map)
 {
        NTSTATUS ret;
-       struct idmap_ldap_context *ctx = NULL;
-       char *config_option = NULL;
-       const char *range = NULL;
-       const char *tmp = NULL;
-
-       /* Only do init if we are online */
-       if (idmap_is_offline()) {
-               return NT_STATUS_FILE_IS_OFFLINE;
-       }
 
-       ctx = TALLOC_ZERO_P(dom, struct idmap_ldap_context);
-       if ( ! ctx) {
-               DEBUG(0, ("Out of memory!\n"));
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       config_option = talloc_asprintf(ctx, "idmap config %s", dom->name);
-       if ( ! config_option) {
-               DEBUG(0, ("Out of memory!\n"));
-               ret = NT_STATUS_NO_MEMORY;
+       if (map == NULL) {
+               ret = NT_STATUS_INVALID_PARAMETER;
                goto done;
        }
 
-       /* load ranges */
-       range = lp_parm_const_string(-1, config_option, "range", NULL);
-       if (range && range[0]) {
-               if ((sscanf(range, "%u - %u", &ctx->filter_low_id,
-                                               &ctx->filter_high_id) != 2) ||
-                   (ctx->filter_low_id > ctx->filter_high_id)) {
-                       DEBUG(1, ("ERROR: invalid filter range [%s]", range));
-                       ctx->filter_low_id = 0;
-                       ctx->filter_high_id = 0;
-               }
-       }
-
-       if (dom->params && *(dom->params)) {
-               /* assume location is the only parameter */
-               ctx->url = talloc_strdup(ctx, dom->params);
-       } else {
-               tmp = lp_parm_const_string(-1, config_option, "ldap_url", NULL);
-
-               if ( ! tmp) {
-                       DEBUG(1, ("ERROR: missing idmap ldap url\n"));
-                       ret = NT_STATUS_UNSUCCESSFUL;
-                       goto done;
-               }
-
-               ctx->url = talloc_strdup(ctx, tmp);
+       if ((map->xid.type != ID_TYPE_UID) && (map->xid.type != ID_TYPE_GID)) {
+               ret = NT_STATUS_INVALID_PARAMETER;
+               goto done;
        }
-       CHECK_ALLOC_DONE(ctx->url);
 
-        tmp = lp_parm_const_string(-1, config_option, "ldap_base_dn", NULL);
-        if ( ! tmp || ! *tmp) {
-                tmp = lp_ldap_idmap_suffix();
-                if ( ! tmp) {
-                        DEBUG(1, ("ERROR: missing idmap ldap suffix\n"));
-                        ret = NT_STATUS_UNSUCCESSFUL;
-                        goto done;
-               }
-        }
-
-       ctx->suffix = talloc_strdup(ctx, tmp);
-       CHECK_ALLOC_DONE(ctx->suffix);
-
-       ret = smbldap_init(ctx, winbind_event_context(), ctx->url,
-                          &ctx->smbldap_state);
-       if (!NT_STATUS_IS_OK(ret)) {
-               DEBUG(1, ("ERROR: smbldap_init (%s) failed!\n", ctx->url));
+       if (map->sid == NULL) {
+               ret = NT_STATUS_INVALID_PARAMETER;
                goto done;
        }
 
-        ret = get_credentials( ctx, ctx->smbldap_state, config_option,
-                              dom, &ctx->user_dn );
-       if ( !NT_STATUS_IS_OK(ret) ) {
-               DEBUG(1,("idmap_ldap_db_init: Failed to get connection "
-                        "credentials (%s)\n", nt_errstr(ret)));
+       ret = idmap_ldap_get_new_id(dom, &map->xid);
+       if (!NT_STATUS_IS_OK(ret)) {
+               DEBUG(3, ("Could not allocate id: %s\n", nt_errstr(ret)));
                goto done;
        }
 
-       /* set the destructor on the context, so that resource are properly
-          freed if the contexts is released */
-
-       talloc_set_destructor(ctx, idmap_ldap_close_destructor);
+       DEBUG(10, ("Setting mapping: %s <-> %s %lu\n",
+                  sid_string_dbg(map->sid),
+                  (map->xid.type == ID_TYPE_UID) ? "UID" : "GID",
+                  (unsigned long)map->xid.id));
 
-       dom->private_data = ctx;
-       dom->initialized = True;
+       map->status = ID_MAPPED;
 
-       talloc_free(config_option);
-       return NT_STATUS_OK;
+       /* store the mapping */
+       ret = idmap_ldap_set_mapping(dom, map);
+       if (!NT_STATUS_IS_OK(ret)) {
+               DEBUG(3, ("Could not store the new mapping: %s\n",
+                         nt_errstr(ret)));
+       }
 
-/*failed */
 done:
-       talloc_free(ctx);
        return ret;
 }
 
+
 /* max number of ids requested per batch query */
 #define IDMAP_LDAP_MAX_IDS 30
 
@@ -893,6 +834,7 @@ static NTSTATUS idmap_ldap_unixids_to_sids(struct idmap_domain *dom,
        TALLOC_CTX *memctx;
        struct idmap_ldap_context *ctx;
        LDAPMessage *result = NULL;
+       LDAPMessage *entry = NULL;
        const char *uidNumber;
        const char *gidNumber;
        const char **attr_list;
@@ -909,14 +851,6 @@ static NTSTATUS idmap_ldap_unixids_to_sids(struct idmap_domain *dom,
                return NT_STATUS_FILE_IS_OFFLINE;
        }
 
-       /* Initilization my have been deferred because we were offline */
-       if ( ! dom->initialized) {
-               ret = idmap_ldap_db_init(dom);
-               if ( ! NT_STATUS_IS_OK(ret)) {
-                       return ret;
-               }
-       }
-
        ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context);
 
        memctx = talloc_new(ctx);
@@ -944,6 +878,10 @@ static NTSTATUS idmap_ldap_unixids_to_sids(struct idmap_domain *dom,
                multi = True;
        }
 
+       for (i = 0; ids[i]; i++) {
+               ids[i]->status = ID_UNKNOWN;
+       }
+
 again:
        if (multi) {
 
@@ -984,9 +922,8 @@ again:
        }
 
        for (i = 0; i < count; i++) {
-               LDAPMessage *entry = NULL;
                char *sidstr = NULL;
-               char *tmp = NULL;
+               char *tmp = NULL;
                enum id_type type;
                struct id_map *map;
                uint32_t id;
@@ -1035,12 +972,10 @@ again:
                }
 
                id = strtoul(tmp, NULL, 10);
-               if ((id == 0) ||
-                   (ctx->filter_low_id && (id < ctx->filter_low_id)) ||
-                   (ctx->filter_high_id && (id > ctx->filter_high_id))) {
+               if (!idmap_unix_id_is_in_range(id, dom)) {
                        DEBUG(5, ("Requested id (%u) out of range (%u - %u). "
                                  "Filtered!\n", id,
-                                 ctx->filter_low_id, ctx->filter_high_id));
+                                 dom->low_id, dom->high_id));
                        TALLOC_FREE(sidstr);
                        TALLOC_FREE(tmp);
                        continue;
@@ -1060,13 +995,20 @@ again:
                        TALLOC_FREE(sidstr);
                        continue;
                }
+
+               if (map->status == ID_MAPPED) {
+                       DEBUG(1, ("WARNING: duplicate %s mapping in LDAP. "
+                             "overwriting mapping %u -> %s with %u -> %s\n",
+                             (type == ID_TYPE_UID) ? "UID" : "GID",
+                             id, sid_string_dbg(map->sid), id, sidstr));
+               }
+
                TALLOC_FREE(sidstr);
 
                /* mapped */
                map->status = ID_MAPPED;
 
-               DEBUG(10, ("Mapped %s -> %lu (%d)\n",
-                          sid_string_static(map->sid),
+               DEBUG(10, ("Mapped %s -> %lu (%d)\n", sid_string_dbg(map->sid),
                           (unsigned long)map->xid.id, map->xid.type));
        }
 
@@ -1099,7 +1041,7 @@ done:
 
 /* this function searches up to IDMAP_LDAP_MAX_IDS entries
  * in maps for a match */
-static struct id_map *find_map_by_sid(struct id_map **maps, DOM_SID *sid)
+static struct id_map *find_map_by_sid(struct id_map **maps, struct dom_sid *sid)
 {
        int i;
 
@@ -1118,7 +1060,7 @@ static struct id_map *find_map_by_sid(struct id_map **maps, DOM_SID *sid)
 static NTSTATUS idmap_ldap_sids_to_unixids(struct idmap_domain *dom,
                                           struct id_map **ids)
 {
-               LDAPMessage *entry = NULL;
+       LDAPMessage *entry = NULL;
        NTSTATUS ret;
        TALLOC_CTX *memctx;
        struct idmap_ldap_context *ctx;
@@ -1139,14 +1081,6 @@ static NTSTATUS idmap_ldap_sids_to_unixids(struct idmap_domain *dom,
                return NT_STATUS_FILE_IS_OFFLINE;
        }
 
-       /* Initilization my have been deferred because we were offline */
-       if ( ! dom->initialized) {
-               ret = idmap_ldap_db_init(dom);
-               if ( ! NT_STATUS_IS_OK(ret)) {
-                       return ret;
-               }
-       }
-
        ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context);
 
        memctx = talloc_new(ctx);
@@ -1166,7 +1100,7 @@ static NTSTATUS idmap_ldap_sids_to_unixids(struct idmap_domain *dom,
                filter = talloc_asprintf(memctx, "(&(objectClass=%s)(%s=%s))",
                                LDAP_OBJ_IDMAP_ENTRY,
                                LDAP_ATTRIBUTE_SID,
-                               sid_string_static(ids[0]->sid));
+                               sid_string_talloc(memctx, ids[0]->sid));
                CHECK_ALLOC_DONE(filter);
                DEBUG(10, ("Filter: [%s]\n", filter));
        } else {
@@ -1174,6 +1108,10 @@ static NTSTATUS idmap_ldap_sids_to_unixids(struct idmap_domain *dom,
                multi = True;
        }
 
+       for (i = 0; ids[i]; i++) {
+               ids[i]->status = ID_UNKNOWN;
+       }
+
 again:
        if (multi) {
 
@@ -1187,7 +1125,8 @@ again:
                for (i = 0; (i < IDMAP_LDAP_MAX_IDS) && ids[idx]; i++, idx++) {
                        filter = talloc_asprintf_append_buffer(filter, "(%s=%s)",
                                        LDAP_ATTRIBUTE_SID,
-                                       sid_string_static(ids[idx]->sid));
+                                       sid_string_talloc(memctx,
+                                                         ids[idx]->sid));
                        CHECK_ALLOC_DONE(filter);
                }
                filter = talloc_asprintf_append_buffer(filter, "))");
@@ -1219,7 +1158,7 @@ again:
                char *tmp = NULL;
                enum id_type type;
                struct id_map *map;
-               DOM_SID sid;
+               struct dom_sid sid;
                uint32_t id;
 
                if (i == 0) { /* first entry */
@@ -1258,8 +1197,6 @@ again:
                        continue;
                }
 
-               TALLOC_FREE(sidstr);
-
                /* now try to see if it is a uid, if not try with a gid
                 * (gid is more common, but in case both uidNumber and
                 * gidNumber are returned the SID is mapped to the uid
@@ -1277,28 +1214,36 @@ again:
                if ( ! tmp) { /* no ids ?? */
                        DEBUG(5, ("no uidNumber, "
                                  "nor gidNumber attributes found\n"));
+                       TALLOC_FREE(sidstr);
                        continue;
                }
 
                id = strtoul(tmp, NULL, 10);
-               if ((id == 0) ||
-                   (ctx->filter_low_id && (id < ctx->filter_low_id)) ||
-                   (ctx->filter_high_id && (id > ctx->filter_high_id))) {
+               if (!idmap_unix_id_is_in_range(id, dom)) {
                        DEBUG(5, ("Requested id (%u) out of range (%u - %u). "
                                  "Filtered!\n", id,
-                                 ctx->filter_low_id, ctx->filter_high_id));
+                                 dom->low_id, dom->high_id));
+                       TALLOC_FREE(sidstr);
                        TALLOC_FREE(tmp);
                        continue;
                }
                TALLOC_FREE(tmp);
 
+               if (map->status == ID_MAPPED) {
+                       DEBUG(1, ("WARNING: duplicate %s mapping in LDAP. "
+                             "overwriting mapping %s -> %u with %s -> %u\n",
+                             (type == ID_TYPE_UID) ? "UID" : "GID",
+                             sidstr, map->xid.id, sidstr, id));
+               }
+
+               TALLOC_FREE(sidstr);
+
                /* mapped */
                map->xid.type = type;
                map->xid.id = id;
                map->status = ID_MAPPED;
 
-               DEBUG(10, ("Mapped %s -> %lu (%d)\n",
-                          sid_string_static(map->sid),
+               DEBUG(10, ("Mapped %s -> %lu (%d)\n", sid_string_dbg(map->sid),
                           (unsigned long)map->xid.id, map->xid.type));
        }
 
@@ -1312,132 +1257,21 @@ again:
                goto again;
        }
 
-       ret = NT_STATUS_OK;
-
-       /* mark all unknwon/expired ones as unmapped */
+       /*
+        *  try to create new mappings for unmapped sids
+        */
        for (i = 0; ids[i]; i++) {
-               if (ids[i]->status != ID_MAPPED)
+               if (ids[i]->status != ID_MAPPED) {
                        ids[i]->status = ID_UNMAPPED;
-       }
-
-done:
-       talloc_free(memctx);
-       return ret;
-}
-
-/**********************************
- set a mapping.
-**********************************/
-
-/* TODO: change this:  This function cannot be called to modify a mapping,
- * only set a new one */
-
-static NTSTATUS idmap_ldap_set_mapping(struct idmap_domain *dom,
-                                      const struct id_map *map)
-{
-       NTSTATUS ret;
-       TALLOC_CTX *memctx;
-       struct idmap_ldap_context *ctx;
-       LDAPMessage *entry = NULL;
-       LDAPMod **mods = NULL;
-       const char *type;
-       char *id_str;
-       char *sid;
-       char *dn;
-       int rc = -1;
-
-       /* Only do query if we are online */
-       if (idmap_is_offline()) {
-               return NT_STATUS_FILE_IS_OFFLINE;
-       }
-
-       /* Initilization my have been deferred because we were offline */
-       if ( ! dom->initialized) {
-               ret = idmap_ldap_db_init(dom);
-               if ( ! NT_STATUS_IS_OK(ret)) {
-                       return ret;
-               }
-       }
-
-       ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context);
-
-       switch(map->xid.type) {
-       case ID_TYPE_UID:
-               type = get_attr_key2string(sidmap_attr_list,
-                                          LDAP_ATTR_UIDNUMBER);
-               break;
-
-       case ID_TYPE_GID:
-               type = get_attr_key2string(sidmap_attr_list,
-                                          LDAP_ATTR_GIDNUMBER);
-               break;
-
-       default:
-               return NT_STATUS_INVALID_PARAMETER;
-       }
-
-       memctx = talloc_new(ctx);
-       if ( ! memctx) {
-               DEBUG(0, ("Out of memory!\n"));
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       id_str = talloc_asprintf(memctx, "%lu", (unsigned long)map->xid.id);
-       CHECK_ALLOC_DONE(id_str);
-
-       sid = talloc_strdup(memctx, sid_string_static(map->sid));
-       CHECK_ALLOC_DONE(sid);
-
-       dn = talloc_asprintf(memctx, "%s=%s,%s",
-                       get_attr_key2string(sidmap_attr_list, LDAP_ATTR_SID),
-                       sid,
-                       ctx->suffix);
-       CHECK_ALLOC_DONE(dn);
-
-       smbldap_set_mod(&mods, LDAP_MOD_ADD,
-                       "objectClass", LDAP_OBJ_IDMAP_ENTRY);
-
-       smbldap_make_mod(ctx->smbldap_state->ldap_struct,
-                        entry, &mods, type, id_str);
-
-       smbldap_make_mod(ctx->smbldap_state->ldap_struct, entry, &mods,
-                        get_attr_key2string(sidmap_attr_list, LDAP_ATTR_SID),
-                        sid);
-
-       if ( ! mods) {
-               DEBUG(2, ("ERROR: No mods?\n"));
-               ret = NT_STATUS_UNSUCCESSFUL;
-               goto done;
-       }
-
-       /* TODO: remove conflicting mappings! */
-
-       smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_SID_ENTRY);
-
-       DEBUG(10, ("Set DN %s (%s -> %s)\n", dn, sid, id_str));
-
-       rc = smbldap_add(ctx->smbldap_state, dn, mods);
-       ldap_mods_free(mods, True);
-
-       if (rc != LDAP_SUCCESS) {
-               char *ld_error = NULL;
-               ldap_get_option(ctx->smbldap_state->ldap_struct,
-                               LDAP_OPT_ERROR_STRING, &ld_error);
-               DEBUG(0,("ldap_set_mapping_internals: Failed to add %s to %lu "
-                        "mapping [%s]\n", sid,
-                        (unsigned long)map->xid.id, type));
-               DEBUG(0, ("ldap_set_mapping_internals: Error was: %s (%s)\n",
-                       ld_error ? ld_error : "(NULL)", ldap_err2string (rc)));
-               if (ld_error) {
-                       ldap_memfree(ld_error);
+                       if (ids[i]->sid != NULL) {
+                               ret = idmap_ldap_new_mapping(dom, ids[i]);
+                               if (!NT_STATUS_IS_OK(ret)) {
+                                       goto done;
+                               }
+                       }
                }
-               ret = NT_STATUS_UNSUCCESSFUL;
-               goto done;
        }
 
-       DEBUG(10,("ldap_set_mapping: Successfully created mapping from %s to "
-                 "%lu [%s]\n", sid, (unsigned long)map->xid.id, type));
-
        ret = NT_STATUS_OK;
 
 done:
@@ -1469,36 +1303,13 @@ static struct idmap_methods idmap_ldap_methods = {
        .init = idmap_ldap_db_init,
        .unixids_to_sids = idmap_ldap_unixids_to_sids,
        .sids_to_unixids = idmap_ldap_sids_to_unixids,
-       .set_mapping = idmap_ldap_set_mapping,
+       .allocate_id = idmap_ldap_get_new_id,
        .close_fn = idmap_ldap_close
 };
 
-static struct idmap_alloc_methods idmap_ldap_alloc_methods = {
-
-       .init = idmap_ldap_alloc_init,
-       .allocate_id = idmap_ldap_allocate_id,
-       .get_id_hwm = idmap_ldap_get_hwm,
-       .set_id_hwm = idmap_ldap_set_hwm,
-       .close_fn = idmap_ldap_alloc_close,
-       /* .dump_data = TODO */
-};
-
-NTSTATUS idmap_alloc_ldap_init(void)
-{
-       return smb_register_idmap_alloc(SMB_IDMAP_INTERFACE_VERSION, "ldap",
-                                       &idmap_ldap_alloc_methods);
-}
-
+NTSTATUS idmap_ldap_init(void);
 NTSTATUS idmap_ldap_init(void)
 {
-       NTSTATUS ret;
-
-       /* FIXME: bad hack to actually register also the alloc_ldap module
-        * without changining configure.in */
-       ret = idmap_alloc_ldap_init();
-       if (! NT_STATUS_IS_OK(ret)) {
-               return ret;
-       }
        return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "ldap",
                                  &idmap_ldap_methods);
 }