r7527: - added a ldb_search_bytree() interface, which takes a ldb_parse_tree
[samba.git] / source4 / lib / ldb / ldb_ldap / ldb_ldap.c
index 5b682a493a054f195a0f69ea3b0fb3057011d763..fceaf0219617281888f7a4b0972c585b9a5c1987 100644 (file)
@@ -33,6 +33,8 @@
  */
 
 #include "includes.h"
+#include "ldb/include/ldb.h"
+#include "ldb/include/ldb_private.h"
 #include "ldb/ldb_ldap/ldb_ldap.h"
 
 #if 0
@@ -65,48 +67,23 @@ static const char *lldb_option_find(const struct lldb_private *lldb, const char
 }
 #endif
 
-/*
-  close/free the connection
-*/
-static int lldb_close(struct ldb_context *ldb)
-{
-       int i, ret = 0;
-       struct lldb_private *lldb = ldb->private_data;
-
-       if (ldap_unbind(lldb->ldap) != LDAP_SUCCESS) {
-               ret = -1;
-       }
-
-       ldb_set_alloc(ldb, NULL, NULL);
-
-       if (lldb->options) {
-               for (i=0;lldb->options[i];i++) {
-                       ldb_free(ldb, lldb->options[i]);
-               }
-               ldb_free(ldb, lldb->options);
-       }
-       ldb_free(ldb, lldb);
-       free(ldb);
-
-       return ret;
-}
-
 /*
   rename a record
 */
-static int lldb_rename(struct ldb_context *ldb, const char *olddn, const char *newdn)
+static int lldb_rename(struct ldb_module *module, const char *olddn, const char *newdn)
 {
-       struct lldb_private *lldb = ldb->private_data;
+       struct lldb_private *lldb = module->private_data;
        int ret = 0;
        char *newrdn, *p;
        const char *parentdn = "";
+       TALLOC_CTX *mem_ctx = talloc_new(lldb);
 
        /* ignore ltdb specials */
        if (olddn[0] == '@' ||newdn[0] == '@') {
                return 0;
        }
 
-       newrdn = ldb_strdup(ldb, newdn);
+       newrdn = talloc_strdup(mem_ctx, newdn);
        if (!newrdn) {
                return -1;
        }
@@ -118,20 +95,21 @@ static int lldb_rename(struct ldb_context *ldb, const char *olddn, const char *n
        }
 
        lldb->last_rc = ldap_rename_s(lldb->ldap, olddn, newrdn, parentdn, 1, NULL, NULL);
-       ldb_free(ldb, newrdn);
        if (lldb->last_rc != LDAP_SUCCESS) {
                ret = -1;
        }
 
+       talloc_free(mem_ctx);
+
        return ret;
 }
 
 /*
   delete a record
 */
-static int lldb_delete(struct ldb_context *ldb, const char *dn)
+static int lldb_delete(struct ldb_module *module, const char *dn)
 {
-       struct lldb_private *lldb = ldb->private_data;
+       struct lldb_private *lldb = module->private_data;
        int ret = 0;
 
        /* ignore ltdb specials */
@@ -147,43 +125,6 @@ static int lldb_delete(struct ldb_context *ldb, const char *dn)
        return ret;
 }
 
-/*
-  free a search message
-*/
-static int lldb_msg_free(struct ldb_context *ldb, struct ldb_message *msg)
-{
-       unsigned int i, j;
-       ldb_free(ldb, msg->dn);
-       for (i=0;i<msg->num_elements;i++) {
-               ldb_free(ldb, msg->elements[i].name);
-               for (j=0;j<msg->elements[i].num_values;j++) {
-                       if (msg->elements[i].values[j].data) {
-                               ldb_free(ldb, msg->elements[i].values[j].data);
-                       }
-               }
-               ldb_free(ldb, msg->elements[i].values);
-       }
-       if (msg->elements) ldb_free(ldb, msg->elements);
-       ldb_free(ldb, msg);
-       return 0;
-}
-
-/*
-  free a search result
-*/
-static int lldb_search_free(struct ldb_context *ldb, struct ldb_message **res)
-{
-       int i;
-       for (i=0;res[i];i++) {
-               if (lldb_msg_free(ldb, res[i]) != 0) {
-                       return -1;
-               }
-       }
-       ldb_free(ldb, res);
-       return 0;
-}
-
-
 /*
   add a single set of ldap message values to a ldb_message
 */
@@ -200,8 +141,8 @@ static int lldb_add_msg_attr(struct ldb_context *ldb,
                return -1;
        }
 
-       el = ldb_realloc_p(ldb, msg->elements, struct ldb_message_element, 
-                          msg->num_elements + 1);
+       el = talloc_realloc(msg, msg->elements, struct ldb_message_element, 
+                             msg->num_elements + 1);
        if (!el) {
                errno = ENOMEM;
                return -1;
@@ -211,7 +152,7 @@ static int lldb_add_msg_attr(struct ldb_context *ldb,
 
        el = &msg->elements[msg->num_elements];
 
-       el->name = ldb_strdup(ldb, attr);
+       el->name = talloc_strdup(msg->elements, attr);
        if (!el->name) {
                errno = ENOMEM;
                return -1;
@@ -219,18 +160,17 @@ static int lldb_add_msg_attr(struct ldb_context *ldb,
        el->flags = 0;
 
        el->num_values = 0;
-       el->values = ldb_malloc_array_p(ldb, struct ldb_val, count);
+       el->values = talloc_array(msg->elements, struct ldb_val, count);
        if (!el->values) {
                errno = ENOMEM;
                return -1;
        }
 
        for (i=0;i<count;i++) {
-               el->values[i].data = ldb_malloc(ldb, bval[i]->bv_len);
+               el->values[i].data = talloc_memdup(el->values, bval[i]->bv_val, bval[i]->bv_len);
                if (!el->values[i].data) {
                        return -1;
                }
-               memcpy(el->values[i].data, bval[i]->bv_val, bval[i]->bv_len);
                el->values[i].length = bval[i]->bv_len;
                el->num_values++;
        }
@@ -243,16 +183,23 @@ static int lldb_add_msg_attr(struct ldb_context *ldb,
 /*
   search for matching records
 */
-static int lldb_search(struct ldb_context *ldb, const char *base,
+static int lldb_search(struct ldb_module *module, const char *base,
                       enum ldb_scope scope, const char *expression,
                       const char * const *attrs, struct ldb_message ***res)
 {
-       struct lldb_private *lldb = ldb->private_data;
+       struct ldb_context *ldb = module->ldb;
+       struct lldb_private *lldb = module->private_data;
        int count, msg_count;
        LDAPMessage *ldapres, *msg;
 
+       if (base == NULL) {
+               base = "";
+       }
+
        lldb->last_rc = ldap_search_s(lldb->ldap, base, (int)scope, 
-                                     expression, attrs, 0, &ldapres);
+                                     expression, 
+                                     discard_const_p(char *, attrs), 
+                                     0, &ldapres);
        if (lldb->last_rc != LDAP_SUCCESS) {
                return -1;
        }
@@ -263,7 +210,7 @@ static int lldb_search(struct ldb_context *ldb, const char *base,
                return count;
        }
 
-       (*res) = ldb_malloc_array_p(ldb, struct ldb_message *, count+1);
+       (*res) = talloc_array(lldb, struct ldb_message *, count+1);
        if (! *res) {
                ldap_msgfree(ldapres);
                errno = ENOMEM;
@@ -287,7 +234,7 @@ static int lldb_search(struct ldb_context *ldb, const char *base,
                        break;
                }
 
-               (*res)[msg_count] = ldb_malloc_p(ldb, struct ldb_message);
+               (*res)[msg_count] = talloc(*res, struct ldb_message);
                if (!(*res)[msg_count]) {
                        goto failed;
                }
@@ -298,7 +245,7 @@ static int lldb_search(struct ldb_context *ldb, const char *base,
                        goto failed;
                }
 
-               (*res)[msg_count]->dn = ldb_strdup(ldb, dn);
+               (*res)[msg_count]->dn = talloc_strdup((*res)[msg_count], dn);
                ldap_memfree(dn);
                if (!(*res)[msg_count]->dn) {
                        goto failed;
@@ -333,30 +280,29 @@ static int lldb_search(struct ldb_context *ldb, const char *base,
        return msg_count;
 
 failed:
-       if (*res) lldb_search_free(ldb, *res);
+       if (*res) talloc_free(*res);
        return -1;
 }
 
 
 /*
-  free a set of mods from lldb_msg_to_mods()
+  search for matching records using a ldb_parse_tree
 */
-static void lldb_mods_free(struct ldb_context *ldb, LDAPMod **mods)
+static int lldb_search_bytree(struct ldb_module *module, const char *base,
+                             enum ldb_scope scope, struct ldb_parse_tree *tree,
+                             const char * const *attrs, struct ldb_message ***res)
 {
-       int i, j;
-
-       if (!mods) return;
+       struct lldb_private *lldb = module->private_data;
+       char *expression;
+       int ret;
 
-       for (i=0;mods[i];i++) {
-               if (mods[i]->mod_vals.modv_bvals) {
-                       for (j=0;mods[i]->mod_vals.modv_bvals[j];j++) {
-                               ldb_free(ldb, mods[i]->mod_vals.modv_bvals[j]);
-                       }
-                       ldb_free(ldb, mods[i]->mod_vals.modv_bvals);
-               }
-               ldb_free(ldb, mods[i]);
+       expression = ldb_filter_from_tree(lldb, tree);
+       if (expression == NULL) {
+               return -1;
        }
-       ldb_free(ldb, mods);
+       ret = lldb_search(module, base, scope, expression, attrs, res);
+       talloc_free(expression);
+       return ret;
 }
 
 
@@ -372,7 +318,7 @@ static LDAPMod **lldb_msg_to_mods(struct ldb_context *ldb,
        int num_mods = 0;
 
        /* allocate maximum number of elements needed */
-       mods = ldb_malloc_array_p(ldb, LDAPMod *, msg->num_elements+1);
+       mods = talloc_array(ldb, LDAPMod *, msg->num_elements+1);
        if (!mods) {
                errno = ENOMEM;
                return NULL;
@@ -382,7 +328,7 @@ static LDAPMod **lldb_msg_to_mods(struct ldb_context *ldb,
        for (i=0;i<msg->num_elements;i++) {
                const struct ldb_message_element *el = &msg->elements[i];
 
-               mods[num_mods] = ldb_malloc_p(ldb, LDAPMod);
+               mods[num_mods] = talloc(ldb, LDAPMod);
                if (!mods[num_mods]) {
                        goto failed;
                }
@@ -402,15 +348,16 @@ static LDAPMod **lldb_msg_to_mods(struct ldb_context *ldb,
                        }
                }
                mods[num_mods]->mod_type = el->name;
-               mods[num_mods]->mod_vals.modv_bvals = ldb_malloc_array_p(ldb
-                                                                        struct berval *,
-                                                                        1+el->num_values);
+               mods[num_mods]->mod_vals.modv_bvals = talloc_array(mods[num_mods]
+                                                                    struct berval *,
+                                                                    1+el->num_values);
                if (!mods[num_mods]->mod_vals.modv_bvals) {
                        goto failed;
                }
 
                for (j=0;j<el->num_values;j++) {
-                       mods[num_mods]->mod_vals.modv_bvals[j] = ldb_malloc_p(ldb, struct berval);
+                       mods[num_mods]->mod_vals.modv_bvals[j] = talloc(mods[num_mods]->mod_vals.modv_bvals,
+                                                                         struct berval);
                        if (!mods[num_mods]->mod_vals.modv_bvals[j]) {
                                goto failed;
                        }
@@ -424,7 +371,7 @@ static LDAPMod **lldb_msg_to_mods(struct ldb_context *ldb,
        return mods;
 
 failed:
-       lldb_mods_free(ldb, mods);
+       talloc_free(mods);
        return NULL;
 }
 
@@ -432,9 +379,10 @@ failed:
 /*
   add a record
 */
-static int lldb_add(struct ldb_context *ldb, const struct ldb_message *msg)
+static int lldb_add(struct ldb_module *module, const struct ldb_message *msg)
 {
-       struct lldb_private *lldb = ldb->private_data;
+       struct ldb_context *ldb = module->ldb;
+       struct lldb_private *lldb = module->private_data;
        LDAPMod **mods;
        int ret = 0;
 
@@ -450,7 +398,7 @@ static int lldb_add(struct ldb_context *ldb, const struct ldb_message *msg)
                ret = -1;
        }
 
-       lldb_mods_free(ldb, mods);
+       talloc_free(mods);
 
        return ret;
 }
@@ -459,9 +407,10 @@ static int lldb_add(struct ldb_context *ldb, const struct ldb_message *msg)
 /*
   modify a record
 */
-static int lldb_modify(struct ldb_context *ldb, const struct ldb_message *msg)
+static int lldb_modify(struct ldb_module *module, const struct ldb_message *msg)
 {
-       struct lldb_private *lldb = ldb->private_data;
+       struct ldb_context *ldb = module->ldb;
+       struct lldb_private *lldb = module->private_data;
        LDAPMod **mods;
        int ret = 0;
 
@@ -477,34 +426,68 @@ static int lldb_modify(struct ldb_context *ldb, const struct ldb_message *msg)
                ret = -1;
        }
 
-       lldb_mods_free(ldb, mods);
+       talloc_free(mods);
 
        return ret;
 }
 
+static int lldb_lock(struct ldb_module *module, const char *lockname)
+{
+       int ret = 0;
+
+       if (lockname == NULL) {
+               return -1;
+       }
+
+       /* TODO implement a local locking mechanism here */
+
+       return ret;
+}
+
+static int lldb_unlock(struct ldb_module *module, const char *lockname)
+{
+       int ret = 0;
+
+       if (lockname == NULL) {
+               return -1;
+       }
+
+       /* TODO implement a local unlocking mechanism here */
+
+       return ret;
+}
 
 /*
   return extended error information
 */
-static const char *lldb_errstring(struct ldb_context *ldb)
+static const char *lldb_errstring(struct ldb_module *module)
 {
-       struct lldb_private *lldb = ldb->private_data;
+       struct lldb_private *lldb = module->private_data;
        return ldap_err2string(lldb->last_rc);
 }
 
 
-static const struct ldb_backend_ops lldb_ops = {
-       lldb_close, 
-       lldb_search,
-       lldb_search_free,
-       lldb_add,
-       lldb_modify,
-       lldb_delete,
-       lldb_rename,
-       lldb_errstring
+static const struct ldb_module_ops lldb_ops = {
+       .name          = "ldap",
+       .search        = lldb_search,
+       .search_bytree = lldb_search_bytree,
+       .add_record    = lldb_add,
+       .modify_record = lldb_modify,
+       .delete_record = lldb_delete,
+       .rename_record = lldb_rename,
+       .named_lock    = lldb_lock,
+       .named_unlock  = lldb_unlock,
+       .errstring     = lldb_errstring
 };
 
 
+static int lldb_destructor(void *p)
+{
+       struct lldb_private *lldb = p;
+       ldap_unbind(lldb->ldap);
+       return 0;
+}
+
 /*
   connect to the database
 */
@@ -516,15 +499,16 @@ struct ldb_context *lldb_connect(const char *url,
        struct lldb_private *lldb = NULL;
        int i, version = 3;
 
-       ldb = calloc(1, sizeof(struct ldb_context));
+       ldb = talloc(NULL, struct ldb_context);
        if (!ldb) {
                errno = ENOMEM;
                goto failed;
        }
 
-       lldb = ldb_malloc_p(ldb, struct lldb_private);
+       ldb->debug_ops.debug = NULL;
+
+       lldb = talloc(ldb, struct lldb_private);
        if (!lldb) {
-               ldb_free(ldb, ldb);
                errno = ENOMEM;
                goto failed;
        }
@@ -537,27 +521,36 @@ struct ldb_context *lldb_connect(const char *url,
                goto failed;
        }
 
+       talloc_set_destructor(lldb, lldb_destructor);
+
        lldb->last_rc = ldap_set_option(lldb->ldap, LDAP_OPT_PROTOCOL_VERSION, &version);
        if (lldb->last_rc != LDAP_SUCCESS) {
                goto failed;
        }
 
-       ldb->ops = &lldb_ops;
-       ldb->private_data = lldb;
+       ldb->modules = talloc(ldb, struct ldb_module);
+       if (!ldb->modules) {
+               errno = ENOMEM;
+               goto failed;
+       }
+       ldb->modules->ldb = ldb;
+       ldb->modules->prev = ldb->modules->next = NULL;
+       ldb->modules->private_data = lldb;
+       ldb->modules->ops = &lldb_ops;
 
        if (options) {
                /* take a copy of the options array, so we don't have to rely
                   on the caller keeping it around (it might be dynamic) */
                for (i=0;options[i];i++) ;
 
-               lldb->options = ldb_malloc_array_p(ldb, char *, i+1);
+               lldb->options = talloc_array(lldb, char *, i+1);
                if (!lldb->options) {
                        goto failed;
                }
                
                for (i=0;options[i];i++) {
                        lldb->options[i+1] = NULL;
-                       lldb->options[i] = ldb_strdup(ldb, options[i]);
+                       lldb->options[i] = talloc_strdup(lldb->options, options[i]);
                        if (!lldb->options[i]) {
                                goto failed;
                        }
@@ -567,17 +560,7 @@ struct ldb_context *lldb_connect(const char *url,
        return ldb;
 
 failed:
-       if (lldb && lldb->options) {
-               for (i=0;lldb->options[i];i++) {
-                       ldb_free(ldb, lldb->options[i]);
-               }
-               ldb_free(ldb, lldb->options);
-       }
-       if (lldb && lldb->ldap) {
-               ldap_unbind(lldb->ldap);
-       }
-       ldb_free(ldb, lldb);
-       if (ldb) free(ldb);
+       talloc_free(ldb);
        return NULL;
 }