diff options
author | Andrew Bartlett <abartlet@samba.org> | 2011-07-05 10:01:32 +1000 |
---|---|---|
committer | Andrew Bartlett <abartlet@samba.org> | 2011-07-05 17:24:47 +1000 |
commit | 8420a36dc7fe72fb665e065b8673fa44ff1bbf21 (patch) | |
tree | 5350041c1de4cdc73a813949f7cd154c423b3ec5 /lib/ldb/tools | |
parent | c9a6dd56e42beafd297f4aefeb4e00ef9a09073a (diff) | |
download | samba-8420a36dc7fe72fb665e065b8673fa44ff1bbf21.tar.gz samba-8420a36dc7fe72fb665e065b8673fa44ff1bbf21.tar.bz2 samba-8420a36dc7fe72fb665e065b8673fa44ff1bbf21.zip |
ldb: make ldb a top level library for Samba 4.0
Signed-off-by: Andrew Tridgell <tridge@samba.org>
Diffstat (limited to 'lib/ldb/tools')
-rw-r--r-- | lib/ldb/tools/cmdline.c | 469 | ||||
-rw-r--r-- | lib/ldb/tools/cmdline.h | 56 | ||||
-rw-r--r-- | lib/ldb/tools/ldbadd.c | 154 | ||||
-rw-r--r-- | lib/ldb/tools/ldbdel.c | 135 | ||||
-rw-r--r-- | lib/ldb/tools/ldbedit.c | 372 | ||||
-rw-r--r-- | lib/ldb/tools/ldbmodify.c | 156 | ||||
-rw-r--r-- | lib/ldb/tools/ldbrename.c | 84 | ||||
-rw-r--r-- | lib/ldb/tools/ldbsearch.c | 317 | ||||
-rw-r--r-- | lib/ldb/tools/ldbtest.c | 434 | ||||
-rw-r--r-- | lib/ldb/tools/ldbutil.c | 219 | ||||
-rw-r--r-- | lib/ldb/tools/ldbutil.h | 46 |
11 files changed, 2442 insertions, 0 deletions
diff --git a/lib/ldb/tools/cmdline.c b/lib/ldb/tools/cmdline.c new file mode 100644 index 0000000000..a06445fc0f --- /dev/null +++ b/lib/ldb/tools/cmdline.c @@ -0,0 +1,469 @@ +/* + ldb database library - command line handling for ldb tools + + Copyright (C) Andrew Tridgell 2005 + + ** NOTE! The following LGPL license applies to the ldb + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ + +#include "replace.h" +#include "system/filesys.h" +#include "system/time.h" +#include "ldb.h" +#include "ldb_module.h" +#include "tools/cmdline.h" + +static struct ldb_cmdline options; /* needs to be static for older compilers */ + +enum ldb_cmdline_options { CMDLINE_RELAX=1 }; + +static struct poptOption builtin_popt_options[] = { + POPT_AUTOHELP + { "url", 'H', POPT_ARG_STRING, &options.url, 0, "database URL", "URL" }, + { "basedn", 'b', POPT_ARG_STRING, &options.basedn, 0, "base DN", "DN" }, + { "editor", 'e', POPT_ARG_STRING, &options.editor, 0, "external editor", "PROGRAM" }, + { "scope", 's', POPT_ARG_STRING, NULL, 's', "search scope", "SCOPE" }, + { "verbose", 'v', POPT_ARG_NONE, NULL, 'v', "increase verbosity", NULL }, + { "trace", 0, POPT_ARG_NONE, &options.tracing, 0, "enable tracing", NULL }, + { "interactive", 'i', POPT_ARG_NONE, &options.interactive, 0, "input from stdin", NULL }, + { "recursive", 'r', POPT_ARG_NONE, &options.recursive, 0, "recursive delete", NULL }, + { "modules-path", 0, POPT_ARG_STRING, &options.modules_path, 0, "modules path", "PATH" }, + { "num-searches", 0, POPT_ARG_INT, &options.num_searches, 0, "number of test searches", NULL }, + { "num-records", 0, POPT_ARG_INT, &options.num_records, 0, "number of test records", NULL }, + { "all", 'a', POPT_ARG_NONE, &options.all_records, 0, "(|(objectClass=*)(distinguishedName=*))", NULL }, + { "nosync", 0, POPT_ARG_NONE, &options.nosync, 0, "non-synchronous transactions", NULL }, + { "sorted", 'S', POPT_ARG_NONE, &options.sorted, 0, "sort attributes", NULL }, + { NULL, 'o', POPT_ARG_STRING, NULL, 'o', "ldb_connect option", "OPTION" }, + { "controls", 0, POPT_ARG_STRING, NULL, 'c', "controls", NULL }, + { "show-binary", 0, POPT_ARG_NONE, &options.show_binary, 0, "display binary LDIF", NULL }, + { "paged", 0, POPT_ARG_NONE, NULL, 'P', "use a paged search", NULL }, + { "show-deleted", 0, POPT_ARG_NONE, NULL, 'D', "show deleted objects", NULL }, + { "show-recycled", 0, POPT_ARG_NONE, NULL, 'R', "show recycled objects", NULL }, + { "show-deactivated-link", 0, POPT_ARG_NONE, NULL, 'd', "show deactivated links", NULL }, + { "reveal", 0, POPT_ARG_NONE, NULL, 'r', "reveal ldb internals", NULL }, + { "relax", 0, POPT_ARG_NONE, NULL, CMDLINE_RELAX, "pass relax control", NULL }, + { "cross-ncs", 0, POPT_ARG_NONE, NULL, 'N', "search across NC boundaries", NULL }, + { "extended-dn", 0, POPT_ARG_NONE, NULL, 'E', "show extended DNs", NULL }, + { NULL } +}; + +void ldb_cmdline_help(struct ldb_context *ldb, const char *cmdname, FILE *f) +{ + poptContext pc; + struct poptOption **popt_options = ldb_module_popt_options(ldb); + pc = poptGetContext(cmdname, 0, NULL, *popt_options, + POPT_CONTEXT_KEEP_FIRST); + poptPrintHelp(pc, f, 0); +} + +/* + add a control to the options structure + */ +static bool add_control(TALLOC_CTX *mem_ctx, const char *control) +{ + unsigned int i; + + /* count how many controls we already have */ + for (i=0; options.controls && options.controls[i]; i++) ; + + options.controls = talloc_realloc(mem_ctx, options.controls, const char *, i + 2); + if (options.controls == NULL) { + return false; + } + options.controls[i] = control; + options.controls[i+1] = NULL; + return true; +} + +/** + process command line options +*/ +struct ldb_cmdline *ldb_cmdline_process(struct ldb_context *ldb, + int argc, const char **argv, + void (*usage)(struct ldb_context *)) +{ + struct ldb_cmdline *ret=NULL; + poptContext pc; + int num_options = 0; + int opt; + unsigned int flags = 0; + int rc; + struct poptOption **popt_options; + + /* make the ldb utilities line buffered */ + setlinebuf(stdout); + + ret = talloc_zero(ldb, struct ldb_cmdline); + if (ret == NULL) { + fprintf(stderr, "Out of memory!\n"); + goto failed; + } + + options = *ret; + + /* pull in URL */ + options.url = getenv("LDB_URL"); + + /* and editor (used by ldbedit) */ + options.editor = getenv("VISUAL"); + if (!options.editor) { + options.editor = getenv("EDITOR"); + } + if (!options.editor) { + options.editor = "vi"; + } + + options.scope = LDB_SCOPE_DEFAULT; + + popt_options = ldb_module_popt_options(ldb); + (*popt_options) = builtin_popt_options; + + rc = ldb_modules_hook(ldb, LDB_MODULE_HOOK_CMDLINE_OPTIONS); + if (rc != LDB_SUCCESS) { + fprintf(stderr, "ldb: failed to run command line hooks : %s\n", ldb_strerror(rc)); + goto failed; + } + + pc = poptGetContext(argv[0], argc, argv, *popt_options, + POPT_CONTEXT_KEEP_FIRST); + + while((opt = poptGetNextOpt(pc)) != -1) { + switch (opt) { + case 's': { + const char *arg = poptGetOptArg(pc); + if (strcmp(arg, "base") == 0) { + options.scope = LDB_SCOPE_BASE; + } else if (strcmp(arg, "sub") == 0) { + options.scope = LDB_SCOPE_SUBTREE; + } else if (strcmp(arg, "one") == 0) { + options.scope = LDB_SCOPE_ONELEVEL; + } else { + fprintf(stderr, "Invalid scope '%s'\n", arg); + goto failed; + } + break; + } + + case 'v': + options.verbose++; + break; + + case 'o': + options.options = talloc_realloc(ret, options.options, + const char *, num_options+3); + if (options.options == NULL) { + fprintf(stderr, "Out of memory!\n"); + goto failed; + } + options.options[num_options] = poptGetOptArg(pc); + options.options[num_options+1] = NULL; + num_options++; + break; + + case 'c': { + const char *cs = poptGetOptArg(pc); + const char *p; + + for (p = cs; p != NULL; ) { + const char *t, *c; + + t = strchr(p, ','); + if (t == NULL) { + c = talloc_strdup(options.controls, p); + p = NULL; + } else { + c = talloc_strndup(options.controls, p, t-p); + p = t + 1; + } + if (c == NULL || !add_control(ret, c)) { + fprintf(stderr, __location__ ": out of memory\n"); + goto failed; + } + } + + break; + } + case 'P': + if (!add_control(ret, "paged_results:1:1024")) { + fprintf(stderr, __location__ ": out of memory\n"); + goto failed; + } + break; + case 'D': + if (!add_control(ret, "show_deleted:1")) { + fprintf(stderr, __location__ ": out of memory\n"); + goto failed; + } + break; + case 'R': + if (!add_control(ret, "show_recycled:0")) { + fprintf(stderr, __location__ ": out of memory\n"); + goto failed; + } + break; + case 'd': + if (!add_control(ret, "show_deactivated_link:0")) { + fprintf(stderr, __location__ ": out of memory\n"); + goto failed; + } + break; + case 'r': + if (!add_control(ret, "reveal_internals:0")) { + fprintf(stderr, __location__ ": out of memory\n"); + goto failed; + } + break; + case CMDLINE_RELAX: + if (!add_control(ret, "relax:0")) { + fprintf(stderr, __location__ ": out of memory\n"); + goto failed; + } + break; + case 'N': + if (!add_control(ret, "search_options:1:2")) { + fprintf(stderr, __location__ ": out of memory\n"); + goto failed; + } + break; + case 'E': + if (!add_control(ret, "extended_dn:1:1")) { + fprintf(stderr, __location__ ": out of memory\n"); + goto failed; + } + break; + default: + fprintf(stderr, "Invalid option %s: %s\n", + poptBadOption(pc, 0), poptStrerror(opt)); + if (usage) usage(ldb); + goto failed; + } + } + + /* setup the remaining options for the main program to use */ + options.argv = poptGetArgs(pc); + if (options.argv) { + options.argv++; + while (options.argv[options.argc]) options.argc++; + } + + *ret = options; + + /* all utils need some option */ + if (ret->url == NULL) { + fprintf(stderr, "You must supply a url with -H or with $LDB_URL\n"); + if (usage) usage(ldb); + goto failed; + } + + if (strcmp(ret->url, "NONE") == 0) { + return ret; + } + + if (options.nosync) { + flags |= LDB_FLG_NOSYNC; + } + + if (options.show_binary) { + flags |= LDB_FLG_SHOW_BINARY; + } + + if (options.tracing) { + flags |= LDB_FLG_ENABLE_TRACING; + } + + if (options.modules_path != NULL) { + ldb_set_modules_dir(ldb, options.modules_path); + } + + rc = ldb_modules_hook(ldb, LDB_MODULE_HOOK_CMDLINE_PRECONNECT); + if (rc != LDB_SUCCESS) { + fprintf(stderr, "ldb: failed to run preconnect hooks : %s\n", ldb_strerror(rc)); + goto failed; + } + + /* now connect to the ldb */ + if (ldb_connect(ldb, ret->url, flags, ret->options) != LDB_SUCCESS) { + fprintf(stderr, "Failed to connect to %s - %s\n", + ret->url, ldb_errstring(ldb)); + goto failed; + } + + rc = ldb_modules_hook(ldb, LDB_MODULE_HOOK_CMDLINE_POSTCONNECT); + if (rc != LDB_SUCCESS) { + fprintf(stderr, "ldb: failed to run post connect hooks : %s\n", ldb_strerror(rc)); + goto failed; + } + + return ret; + +failed: + talloc_free(ret); + exit(LDB_ERR_OPERATIONS_ERROR); + return NULL; +} + +/* this function check controls reply and determines if more + * processing is needed setting up the request controls correctly + * + * returns: + * -1 error + * 0 all ok + * 1 all ok, more processing required + */ +int handle_controls_reply(struct ldb_control **reply, struct ldb_control **request) +{ + unsigned int i, j; + int ret = 0; + + if (reply == NULL || request == NULL) return -1; + + for (i = 0; reply[i]; i++) { + if (strcmp(LDB_CONTROL_VLV_RESP_OID, reply[i]->oid) == 0) { + struct ldb_vlv_resp_control *rep_control; + + rep_control = talloc_get_type(reply[i]->data, struct ldb_vlv_resp_control); + + /* check we have a matching control in the request */ + for (j = 0; request[j]; j++) { + if (strcmp(LDB_CONTROL_VLV_REQ_OID, request[j]->oid) == 0) + break; + } + if (! request[j]) { + fprintf(stderr, "Warning VLV reply received but no request have been made\n"); + continue; + } + + /* check the result */ + if (rep_control->vlv_result != 0) { + fprintf(stderr, "Warning: VLV not performed with error: %d\n", rep_control->vlv_result); + } else { + fprintf(stderr, "VLV Info: target position = %d, content count = %d\n", rep_control->targetPosition, rep_control->contentCount); + } + + continue; + } + + if (strcmp(LDB_CONTROL_ASQ_OID, reply[i]->oid) == 0) { + struct ldb_asq_control *rep_control; + + rep_control = talloc_get_type(reply[i]->data, struct ldb_asq_control); + + /* check the result */ + if (rep_control->result != 0) { + fprintf(stderr, "Warning: ASQ not performed with error: %d\n", rep_control->result); + } + + continue; + } + + if (strcmp(LDB_CONTROL_PAGED_RESULTS_OID, reply[i]->oid) == 0) { + struct ldb_paged_control *rep_control, *req_control; + + rep_control = talloc_get_type(reply[i]->data, struct ldb_paged_control); + if (rep_control->cookie_len == 0) /* we are done */ + break; + + /* more processing required */ + /* let's fill in the request control with the new cookie */ + + for (j = 0; request[j]; j++) { + if (strcmp(LDB_CONTROL_PAGED_RESULTS_OID, request[j]->oid) == 0) + break; + } + /* if there's a reply control we must find a request + * control matching it */ + if (! request[j]) return -1; + + req_control = talloc_get_type(request[j]->data, struct ldb_paged_control); + + if (req_control->cookie) + talloc_free(req_control->cookie); + req_control->cookie = (char *)talloc_memdup( + req_control, rep_control->cookie, + rep_control->cookie_len); + req_control->cookie_len = rep_control->cookie_len; + + ret = 1; + + continue; + } + + if (strcmp(LDB_CONTROL_SORT_RESP_OID, reply[i]->oid) == 0) { + struct ldb_sort_resp_control *rep_control; + + rep_control = talloc_get_type(reply[i]->data, struct ldb_sort_resp_control); + + /* check we have a matching control in the request */ + for (j = 0; request[j]; j++) { + if (strcmp(LDB_CONTROL_SERVER_SORT_OID, request[j]->oid) == 0) + break; + } + if (! request[j]) { + fprintf(stderr, "Warning Server Sort reply received but no request found\n"); + continue; + } + + /* check the result */ + if (rep_control->result != 0) { + fprintf(stderr, "Warning: Sorting not performed with error: %d\n", rep_control->result); + } + + continue; + } + + if (strcmp(LDB_CONTROL_DIRSYNC_OID, reply[i]->oid) == 0) { + struct ldb_dirsync_control *rep_control, *req_control; + char *cookie; + + rep_control = talloc_get_type(reply[i]->data, struct ldb_dirsync_control); + if (rep_control->cookie_len == 0) /* we are done */ + break; + + /* more processing required */ + /* let's fill in the request control with the new cookie */ + + for (j = 0; request[j]; j++) { + if (strcmp(LDB_CONTROL_DIRSYNC_OID, request[j]->oid) == 0) + break; + } + /* if there's a reply control we must find a request + * control matching it */ + if (! request[j]) return -1; + + req_control = talloc_get_type(request[j]->data, struct ldb_dirsync_control); + + if (req_control->cookie) + talloc_free(req_control->cookie); + req_control->cookie = (char *)talloc_memdup( + req_control, rep_control->cookie, + rep_control->cookie_len); + req_control->cookie_len = rep_control->cookie_len; + + cookie = ldb_base64_encode(req_control, rep_control->cookie, rep_control->cookie_len); + printf("# DIRSYNC cookie returned was:\n# %s\n", cookie); + + continue; + } + + /* no controls matched, throw a warning */ + fprintf(stderr, "Unknown reply control oid: %s\n", reply[i]->oid); + } + + return ret; +} + diff --git a/lib/ldb/tools/cmdline.h b/lib/ldb/tools/cmdline.h new file mode 100644 index 0000000000..416bf51d22 --- /dev/null +++ b/lib/ldb/tools/cmdline.h @@ -0,0 +1,56 @@ +/* + ldb database library - command line handling for ldb tools + + Copyright (C) Andrew Tridgell 2005 + + ** NOTE! The following LGPL license applies to the ldb + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ + +#include <popt.h> + +struct ldb_cmdline { + const char *url; + enum ldb_scope scope; + const char *basedn; + const char *modules_path; + int interactive; + int sorted; + const char *editor; + int verbose; + int recursive; + int all_records; + int nosync; + const char **options; + int argc; + const char **argv; + int num_records; + int num_searches; + const char *sasl_mechanism; + const char **controls; + int show_binary; + int tracing; +}; + +struct ldb_cmdline *ldb_cmdline_process(struct ldb_context *ldb, int argc, + const char **argv, + void (*usage)(struct ldb_context *)); + + +int handle_controls_reply(struct ldb_control **reply, struct ldb_control **request); +void ldb_cmdline_help(struct ldb_context *ldb, const char *cmdname, FILE *f); + diff --git a/lib/ldb/tools/ldbadd.c b/lib/ldb/tools/ldbadd.c new file mode 100644 index 0000000000..47fd261841 --- /dev/null +++ b/lib/ldb/tools/ldbadd.c @@ -0,0 +1,154 @@ +/* + ldb database library + + Copyright (C) Andrew Tridgell 2004 + + ** NOTE! The following LGPL license applies to the ldb + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ + +/* + * Name: ldb + * + * Component: ldbadd + * + * Description: utility to add records - modelled on ldapadd + * + * Author: Andrew Tridgell + */ + +#include "ldb.h" +#include "tools/cmdline.h" +#include "ldbutil.h" + +static unsigned int failures; +static struct ldb_cmdline *options; + +static void usage(struct ldb_context *ldb) +{ + printf("Usage: ldbadd <options> <ldif...>\n"); + printf("Adds records to a ldb, reading ldif the specified list of files\n\n"); + ldb_cmdline_help(ldb, "ldbadd", stdout); + exit(LDB_ERR_OPERATIONS_ERROR); +} + + +/* + add records from an opened file +*/ +static int process_file(struct ldb_context *ldb, FILE *f, unsigned int *count) +{ + struct ldb_ldif *ldif; + int fun_ret = LDB_SUCCESS, ret; + struct ldb_control **req_ctrls = ldb_parse_control_strings(ldb, ldb, (const char **)options->controls); + if (options->controls != NULL && req_ctrls== NULL) { + printf("parsing controls failed: %s\n", ldb_errstring(ldb)); + return LDB_ERR_OPERATIONS_ERROR; + } + + + while ((ldif = ldb_ldif_read_file(ldb, f))) { + if (ldif->changetype != LDB_CHANGETYPE_ADD && + ldif->changetype != LDB_CHANGETYPE_NONE) { + fprintf(stderr, "Only CHANGETYPE_ADD records allowed\n"); + break; + } + + ret = ldb_msg_normalize(ldb, ldif, ldif->msg, &ldif->msg); + if (ret != LDB_SUCCESS) { + fprintf(stderr, + "ERR: Message canonicalize failed - %s\n", + ldb_strerror(ret)); + failures++; + fun_ret = ret; + ldb_ldif_read_free(ldb, ldif); + continue; + } + + ret = ldb_add_ctrl(ldb, ldif->msg,req_ctrls); + if (ret != LDB_SUCCESS) { + fprintf(stderr, "ERR: %s : \"%s\" on DN %s\n", + ldb_strerror(ret), ldb_errstring(ldb), + ldb_dn_get_linearized(ldif->msg->dn)); + failures++; + fun_ret = ret; + } else { + (*count)++; + if (options->verbose) { + printf("Added %s\n", ldb_dn_get_linearized(ldif->msg->dn)); + } + } + ldb_ldif_read_free(ldb, ldif); + } + + return fun_ret; +} + + + +int main(int argc, const char **argv) +{ + struct ldb_context *ldb; + unsigned int i, count = 0; + int ret = LDB_SUCCESS; + TALLOC_CTX *mem_ctx = talloc_new(NULL); + + ldb = ldb_init(mem_ctx, NULL); + if (ldb == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + options = ldb_cmdline_process(ldb, argc, argv, usage); + + ret = ldb_transaction_start(ldb); + if (ret != LDB_SUCCESS) { + printf("Failed to start transaction: %s\n", ldb_errstring(ldb)); + return ret; + } + + if (options->argc == 0) { + ret = process_file(ldb, stdin, &count); + } else { + for (i=0;i<options->argc;i++) { + const char *fname = options->argv[i]; + FILE *f; + f = fopen(fname, "r"); + if (!f) { + perror(fname); + return LDB_ERR_OPERATIONS_ERROR; + } + ret = process_file(ldb, f, &count); + fclose(f); + } + } + + if (count != 0) { + ret = ldb_transaction_commit(ldb); + if (ret != LDB_SUCCESS) { + printf("Failed to commit transaction: %s\n", ldb_errstring(ldb)); + return ret; + } + } else { + ldb_transaction_cancel(ldb); + } + + talloc_free(mem_ctx); + + printf("Added %u records with %u failures\n", count, failures); + + return ret; +} diff --git a/lib/ldb/tools/ldbdel.c b/lib/ldb/tools/ldbdel.c new file mode 100644 index 0000000000..8036d09a70 --- /dev/null +++ b/lib/ldb/tools/ldbdel.c @@ -0,0 +1,135 @@ +/* + ldb database library + + Copyright (C) Andrew Tridgell 2004 + + ** NOTE! The following LGPL license applies to the ldb + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ + +/* + * Name: ldb + * + * Component: ldbdel + * + * Description: utility to delete records - modelled on ldapdelete + * + * Author: Andrew Tridgell + */ + +#include "replace.h" +#include "ldb.h" +#include "tools/cmdline.h" +#include "ldbutil.h" + +static int dn_cmp(struct ldb_message **msg1, struct ldb_message **msg2) +{ + return ldb_dn_compare((*msg1)->dn, (*msg2)->dn); +} + +static int ldb_delete_recursive(struct ldb_context *ldb, struct ldb_dn *dn,struct ldb_control **req_ctrls) +{ + int ret; + unsigned int i, total=0; + const char *attrs[] = { NULL }; + struct ldb_result *res; + + ret = ldb_search(ldb, ldb, &res, dn, LDB_SCOPE_SUBTREE, attrs, "distinguishedName=*"); + if (ret != LDB_SUCCESS) return ret; + + /* sort the DNs, deepest first */ + TYPESAFE_QSORT(res->msgs, res->count, dn_cmp); + + for (i = 0; i < res->count; i++) { + if (ldb_delete_ctrl(ldb, res->msgs[i]->dn,req_ctrls) == LDB_SUCCESS) { + total++; + } else { + printf("Failed to delete '%s' - %s\n", + ldb_dn_get_linearized(res->msgs[i]->dn), + ldb_errstring(ldb)); + } + } + + talloc_free(res); + + if (total == 0) { + return LDB_ERR_OPERATIONS_ERROR; + } + printf("Deleted %u records\n", total); + return LDB_SUCCESS; +} + +static void usage(struct ldb_context *ldb) +{ + printf("Usage: ldbdel <options> <DN...>\n"); + printf("Deletes records from a ldb\n\n"); + ldb_cmdline_help(ldb, "ldbdel", stdout); + exit(LDB_ERR_OPERATIONS_ERROR); +} + +int main(int argc, const char **argv) +{ + struct ldb_control **req_ctrls; + struct ldb_cmdline *options; + struct ldb_context *ldb; + int ret = 0, i; + TALLOC_CTX *mem_ctx = talloc_new(NULL); + + ldb = ldb_init(mem_ctx, NULL); + if (ldb == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + options = ldb_cmdline_process(ldb, argc, argv, usage); + + if (options->argc < 1) { + usage(ldb); + } + + req_ctrls = ldb_parse_control_strings(ldb, ldb, (const char **)options->controls); + if (options->controls != NULL && req_ctrls== NULL) { + printf("parsing controls failed: %s\n", ldb_errstring(ldb)); + return LDB_ERR_OPERATIONS_ERROR; + } + + for (i=0;i<options->argc;i++) { + struct ldb_dn *dn; + + dn = ldb_dn_new(ldb, ldb, options->argv[i]); + if (dn == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + if (options->recursive) { + ret = ldb_delete_recursive(ldb, dn,req_ctrls); + } else { + ret = ldb_delete_ctrl(ldb, dn,req_ctrls); + if (ret == LDB_SUCCESS) { + printf("Deleted 1 record\n"); + } + } + if (ret != LDB_SUCCESS) { + printf("delete of '%s' failed - (%s) %s\n", + ldb_dn_get_linearized(dn), + ldb_strerror(ret), + ldb_errstring(ldb)); + } + } + + talloc_free(mem_ctx); + + return ret; +} diff --git a/lib/ldb/tools/ldbedit.c b/lib/ldb/tools/ldbedit.c new file mode 100644 index 0000000000..aaf6d80352 --- /dev/null +++ b/lib/ldb/tools/ldbedit.c @@ -0,0 +1,372 @@ +/* + ldb database library + + Copyright (C) Andrew Tridgell 2004 + + ** NOTE! The following LGPL license applies to the ldb + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ + +/* + * Name: ldb + * + * Component: ldbedit + * + * Description: utility for ldb database editing + * + * Author: Andrew Tridgell + */ + +#include "replace.h" +#include "system/filesys.h" +#include "system/time.h" +#include "system/filesys.h" +#include "ldb.h" +#include "tools/cmdline.h" +#include "tools/ldbutil.h" + +static struct ldb_cmdline *options; + +/* + debug routine +*/ +static void ldif_write_msg(struct ldb_context *ldb, + FILE *f, + enum ldb_changetype changetype, + struct ldb_message *msg) +{ + struct ldb_ldif ldif; + ldif.changetype = changetype; + ldif.msg = msg; + ldb_ldif_write_file(ldb, f, &ldif); +} + +/* + modify a database record so msg1 becomes msg2 + returns the number of modified elements +*/ +static int modify_record(struct ldb_context *ldb, + struct ldb_message *msg1, + struct ldb_message *msg2, + struct ldb_control **req_ctrls) +{ + int ret; + struct ldb_message *mod; + + if (ldb_msg_difference(ldb, ldb, msg1, msg2, &mod) != LDB_SUCCESS) { + fprintf(stderr, "Failed to calculate message differences\n"); + return -1; + } + + ret = mod->num_elements; + if (ret == 0) { + goto done; + } + + if (options->verbose > 0) { + ldif_write_msg(ldb, stdout, LDB_CHANGETYPE_MODIFY, mod); + } + + if (ldb_modify_ctrl(ldb, mod, req_ctrls) != LDB_SUCCESS) { + fprintf(stderr, "failed to modify %s - %s\n", + ldb_dn_get_linearized(msg1->dn), ldb_errstring(ldb)); + ret = -1; + goto done; + } + +done: + talloc_free(mod); + return ret; +} + +/* + find dn in msgs[] +*/ +static struct ldb_message *msg_find(struct ldb_context *ldb, + struct ldb_message **msgs, + unsigned int count, + struct ldb_dn *dn) +{ + unsigned int i; + for (i=0;i<count;i++) { + if (ldb_dn_compare(dn, msgs[i]->dn) == 0) { + return msgs[i]; + } + } + return NULL; +} + +/* + merge the changes in msgs2 into the messages from msgs1 +*/ +static int merge_edits(struct ldb_context *ldb, + struct ldb_message **msgs1, unsigned int count1, + struct ldb_message **msgs2, unsigned int count2) +{ + unsigned int i; + struct ldb_message *msg; + int ret; + unsigned int adds=0, modifies=0, deletes=0; + struct ldb_control **req_ctrls = ldb_parse_control_strings(ldb, ldb, (const char **)options->controls); + if (options->controls != NULL && req_ctrls == NULL) { + fprintf(stderr, "parsing controls failed: %s\n", ldb_errstring(ldb)); + return -1; + } + + if (ldb_transaction_start(ldb) != LDB_SUCCESS) { + fprintf(stderr, "Failed to start transaction: %s\n", ldb_errstring(ldb)); + return -1; + } + + /* do the adds and modifies */ + for (i=0;i<count2;i++) { + msg = msg_find(ldb, msgs1, count1, msgs2[i]->dn); + if (!msg) { + if (options->verbose > 0) { + ldif_write_msg(ldb, stdout, LDB_CHANGETYPE_ADD, msgs2[i]); + } + if (ldb_add_ctrl(ldb, msgs2[i], req_ctrls) != LDB_SUCCESS) { + fprintf(stderr, "failed to add %s - %s\n", + ldb_dn_get_linearized(msgs2[i]->dn), + ldb_errstring(ldb)); + ldb_transaction_cancel(ldb); + return -1; + } + adds++; + } else { + ret = modify_record(ldb, msg, msgs2[i], req_ctrls); + if (ret != -1) { + modifies += (unsigned int) ret; + } else { + return -1; + } + } + } + + /* do the deletes */ + for (i=0;i<count1;i++) { + msg = msg_find(ldb, msgs2, count2, msgs1[i]->dn); + if (!msg) { + if (options->verbose > 0) { + ldif_write_msg(ldb, stdout, LDB_CHANGETYPE_DELETE, msgs1[i]); + } + if (ldb_delete_ctrl(ldb, msgs1[i]->dn, req_ctrls) != LDB_SUCCESS) { + fprintf(stderr, "failed to delete %s - %s\n", + ldb_dn_get_linearized(msgs1[i]->dn), + ldb_errstring(ldb)); + ldb_transaction_cancel(ldb); + return -1; + } + deletes++; + } + } + + if (ldb_transaction_commit(ldb) != LDB_SUCCESS) { + fprintf(stderr, "Failed to commit transaction: %s\n", ldb_errstring(ldb)); + return -1; + } + + printf("# %u adds %u modifies %u deletes\n", adds, modifies, deletes); + + return 0; +} + +/* + save a set of messages as ldif to a file +*/ +static int save_ldif(struct ldb_context *ldb, + FILE *f, struct ldb_message **msgs, unsigned int count) +{ + unsigned int i; + + fprintf(f, "# editing %u records\n", count); + + for (i=0;i<count;i++) { + struct ldb_ldif ldif; + fprintf(f, "# record %u\n", i+1); + + ldif.changetype = LDB_CHANGETYPE_NONE; + ldif.msg = msgs[i]; + + ldb_ldif_write_file(ldb, f, &ldif); + } + + return 0; +} + + +/* + edit the ldb search results in msgs using the user selected editor +*/ +static int do_edit(struct ldb_context *ldb, struct ldb_message **msgs1, + unsigned int count1, const char *editor) +{ + int fd, ret; + FILE *f; + char file_template[] = "/tmp/ldbedit.XXXXXX"; + char *cmd; + struct ldb_ldif *ldif; + struct ldb_message **msgs2 = NULL; + unsigned int count2 = 0; + + /* write out the original set of messages to a temporary + file */ + fd = mkstemp(file_template); + + if (fd == -1) { + perror(file_template); + return -1; + } + + f = fdopen(fd, "r+"); + + if (!f) { + perror("fopen"); + close(fd); + unlink(file_template); + return -1; + } + + if (save_ldif(ldb, f, msgs1, count1) != 0) { + return -1; + } + + fclose(f); + + cmd = talloc_asprintf(ldb, "%s %s", editor, file_template); + + if (!cmd) { + unlink(file_template); + fprintf(stderr, "out of memory\n"); + return -1; + } + + /* run the editor */ + ret = system(cmd); + talloc_free(cmd); + + if (ret != 0) { + unlink(file_template); + fprintf(stderr, "edit with %s failed\n", editor); + return -1; + } + + /* read the resulting ldif into msgs2 */ + f = fopen(file_template, "r"); + if (!f) { + perror(file_template); + return -1; + } + + while ((ldif = ldb_ldif_read_file(ldb, f))) { + msgs2 = talloc_realloc(ldb, msgs2, struct ldb_message *, count2+1); + if (!msgs2) { + fprintf(stderr, "out of memory"); + return -1; + } + msgs2[count2++] = ldif->msg; + } + + /* the feof() test works here, even for the last line of the + * file, as we parse ldif files character by character, and + * feof() is only true if we have failed to read a character + * from the file. So if the last line is bad, we don't get + * feof() set, so we know the record was bad. Only if we + * attempt to go to the next record will we get feof() and + * thus consider that the ldif has ended without errors + */ + if (!feof(f)) { + fprintf(stderr, "Error parsing ldif - aborting\n"); + fclose(f); + unlink(file_template); + return -1; + } + + fclose(f); + unlink(file_template); + + return merge_edits(ldb, msgs1, count1, msgs2, count2); +} + +static void usage(struct ldb_context *ldb) +{ + printf("Usage: ldbedit <options> <expression> <attributes ...>\n"); + ldb_cmdline_help(ldb, "ldbedit", stdout); + exit(LDB_ERR_OPERATIONS_ERROR); +} + +int main(int argc, const char **argv) +{ + struct ldb_context *ldb; + struct ldb_result *result = NULL; + struct ldb_dn *basedn = NULL; + int ret; + const char *expression = "(|(objectClass=*)(distinguishedName=*))"; + const char * const * attrs = NULL; + TALLOC_CTX *mem_ctx = talloc_new(NULL); + struct ldb_control **req_ctrls; + + ldb = ldb_init(mem_ctx, NULL); + if (ldb == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + options = ldb_cmdline_process(ldb, argc, argv, usage); + + /* the check for '=' is for compatibility with ldapsearch */ + if (options->argc > 0 && + strchr(options->argv[0], '=')) { + expression = options->argv[0]; + options->argv++; + options->argc--; + } + + if (options->argc > 0) { + attrs = (const char * const *)(options->argv); + } + + if (options->basedn != NULL) { + basedn = ldb_dn_new(ldb, ldb, options->basedn); + if (basedn == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + } + + req_ctrls = ldb_parse_control_strings(ldb, ldb, (const char **)options->controls); + if (options->controls != NULL && req_ctrls== NULL) { + printf("parsing controls failed: %s\n", ldb_errstring(ldb)); + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ldb_search_ctrl(ldb, ldb, &result, basedn, options->scope, attrs, req_ctrls, "%s", expression); + if (ret != LDB_SUCCESS) { + printf("search failed - %s\n", ldb_errstring(ldb)); + return ret; + } + + if (result->count == 0) { + printf("no matching records - cannot edit\n"); + talloc_free(mem_ctx); + return LDB_SUCCESS; + } + + ret = do_edit(ldb, result->msgs, result->count, options->editor); + + talloc_free(mem_ctx); + + return ret == 0 ? LDB_SUCCESS : LDB_ERR_OPERATIONS_ERROR; +} diff --git a/lib/ldb/tools/ldbmodify.c b/lib/ldb/tools/ldbmodify.c new file mode 100644 index 0000000000..2ca7b62b2c --- /dev/null +++ b/lib/ldb/tools/ldbmodify.c @@ -0,0 +1,156 @@ +/* + ldb database library + + Copyright (C) Andrew Tridgell 2004 + + ** NOTE! The following LGPL license applies to the ldb + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ + +/* + * Name: ldb + * + * Component: ldbmodify + * + * Description: utility to modify records - modelled on ldapmodify + * + * Author: Andrew Tridgell + */ + +#include "ldb.h" +#include "tools/cmdline.h" +#include "ldbutil.h" + +static unsigned int failures; +static struct ldb_cmdline *options; + +static void usage(struct ldb_context *ldb) +{ + printf("Usage: ldbmodify <options> <ldif...>\n"); + printf("Modifies a ldb based upon ldif change records\n\n"); + ldb_cmdline_help(ldb, "ldbmodify", stdout); + exit(LDB_ERR_OPERATIONS_ERROR); +} + +/* + process modifies for one file +*/ +static int process_file(struct ldb_context *ldb, FILE *f, unsigned int *count) +{ + struct ldb_ldif *ldif; + int fun_ret = LDB_SUCCESS, ret; + struct ldb_control **req_ctrls = ldb_parse_control_strings(ldb, ldb, (const char **)options->controls); + + if (options->controls != NULL && req_ctrls== NULL) { + printf("parsing controls failed: %s\n", ldb_errstring(ldb)); + exit(LDB_ERR_OPERATIONS_ERROR); + } + + while ((ldif = ldb_ldif_read_file(ldb, f))) { + struct ldb_dn *olddn; + bool deleteoldrdn = false; + struct ldb_dn *newdn; + const char *errstr = NULL; + + switch (ldif->changetype) { + case LDB_CHANGETYPE_NONE: + case LDB_CHANGETYPE_ADD: + ret = ldb_add_ctrl(ldb, ldif->msg,req_ctrls); + break; + case LDB_CHANGETYPE_DELETE: + ret = ldb_delete_ctrl(ldb, ldif->msg->dn,req_ctrls); + break; + case LDB_CHANGETYPE_MODIFY: + ret = ldb_modify_ctrl(ldb, ldif->msg,req_ctrls); + break; + case LDB_CHANGETYPE_MODRDN: + ret = ldb_ldif_parse_modrdn(ldb, ldif, ldif, &olddn, + NULL, &deleteoldrdn, + NULL, &newdn); + if (ret == LDB_SUCCESS) { + if (deleteoldrdn) { + ret = ldb_rename(ldb, olddn, newdn); + } else { + errstr = "modrdn: deleteoldrdn=0 " + "not supported."; + ret = LDB_ERR_CONSTRAINT_VIOLATION; + } + } + break; + } + if (ret != LDB_SUCCESS) { + if (errstr == NULL) { + errstr = ldb_errstring(ldb); + } + fprintf(stderr, "ERR: (%s) \"%s\" on DN %s\n", + ldb_strerror(ret), + errstr, ldb_dn_get_linearized(ldif->msg->dn)); + failures++; + fun_ret = ret; + } else { + (*count)++; + if (options->verbose) { + printf("Modified %s\n", ldb_dn_get_linearized(ldif->msg->dn)); + } + } + ldb_ldif_read_free(ldb, ldif); + } + + if (!feof(f)) { + fprintf(stderr, "Failed to parse ldif\n"); + fun_ret = LDB_ERR_OPERATIONS_ERROR; + } + + return fun_ret; +} + +int main(int argc, const char **argv) +{ + struct ldb_context *ldb; + unsigned int i, count = 0; + int ret = LDB_SUCCESS; + TALLOC_CTX *mem_ctx = talloc_new(NULL); + + ldb = ldb_init(mem_ctx, NULL); + if (ldb == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + options = ldb_cmdline_process(ldb, argc, argv, usage); + + if (options->argc == 0) { + ret = process_file(ldb, stdin, &count); + } else { + for (i=0;i<options->argc;i++) { + const char *fname = options->argv[i]; + FILE *f; + f = fopen(fname, "r"); + if (!f) { + perror(fname); + return LDB_ERR_OPERATIONS_ERROR; + } + ret = process_file(ldb, f, &count); + fclose(f); + } + } + + talloc_free(mem_ctx); + + printf("Modified %u records with %u failures\n", count, failures); + + return ret; +} diff --git a/lib/ldb/tools/ldbrename.c b/lib/ldb/tools/ldbrename.c new file mode 100644 index 0000000000..9bbd1f06b1 --- /dev/null +++ b/lib/ldb/tools/ldbrename.c @@ -0,0 +1,84 @@ +/* + ldb database library + + Copyright (C) Andrew Tridgell 2004 + Copyright (C) Stefan Metzmacher 2004 + + ** NOTE! The following LGPL license applies to the ldb + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ + +/* + * Name: ldb + * + * Component: ldbrename + * + * Description: utility to rename records - modelled on ldapmodrdn + * + * Author: Andrew Tridgell + * Author: Stefan Metzmacher + */ + +#include "ldb.h" +#include "tools/cmdline.h" + +static void usage(struct ldb_context *ldb) +{ + printf("Usage: ldbrename [<options>] <olddn> <newdn>\n"); + printf("Renames records in a ldb\n\n"); + ldb_cmdline_help(ldb, "ldbmodify", stdout); + exit(LDB_ERR_OPERATIONS_ERROR); +} + + +int main(int argc, const char **argv) +{ + struct ldb_context *ldb; + int ret; + struct ldb_cmdline *options; + struct ldb_dn *dn1, *dn2; + TALLOC_CTX *mem_ctx = talloc_new(NULL); + + ldb = ldb_init(mem_ctx, NULL); + if (ldb == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + options = ldb_cmdline_process(ldb, argc, argv, usage); + + if (options->argc < 2) { + usage(ldb); + } + + dn1 = ldb_dn_new(ldb, ldb, options->argv[0]); + dn2 = ldb_dn_new(ldb, ldb, options->argv[1]); + if ((dn1 == NULL) || (dn2 == NULL)) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ldb_rename(ldb, dn1, dn2); + if (ret == LDB_SUCCESS) { + printf("Renamed 1 record\n"); + } else { + printf("rename of '%s' to '%s' failed - %s\n", + options->argv[0], options->argv[1], ldb_errstring(ldb)); + } + + talloc_free(mem_ctx); + + return ret; +} diff --git a/lib/ldb/tools/ldbsearch.c b/lib/ldb/tools/ldbsearch.c new file mode 100644 index 0000000000..d10b9650da --- /dev/null +++ b/lib/ldb/tools/ldbsearch.c @@ -0,0 +1,317 @@ +/* + ldb database library + + Copyright (C) Andrew Tridgell 2004 + + ** NOTE! The following LGPL license applies to the ldb + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ + +/* + * Name: ldb + * + * Component: ldbsearch + * + * Description: utility for ldb search - modelled on ldapsearch + * + * Author: Andrew Tridgell + */ + +#include "replace.h" +#include "system/filesys.h" +#include "system/time.h" +#include "ldb.h" +#include "tools/cmdline.h" + +static void usage(struct ldb_context *ldb) +{ + printf("Usage: ldbsearch <options> <expression> <attrs...>\n"); + ldb_cmdline_help(ldb, "ldbsearch", stdout); + exit(LDB_ERR_OPERATIONS_ERROR); +} + +static int do_compare_msg(struct ldb_message **el1, + struct ldb_message **el2, + void *opaque) +{ + return ldb_dn_compare((*el1)->dn, (*el2)->dn); +} + +struct search_context { + struct ldb_context *ldb; + struct ldb_control **req_ctrls; + + int sort; + unsigned int num_stored; + struct ldb_message **store; + unsigned int refs_stored; + char **refs_store; + + unsigned int entries; + unsigned int refs; + + unsigned int pending; + int status; +}; + +static int store_message(struct ldb_message *msg, struct search_context *sctx) { + + sctx->store = talloc_realloc(sctx, sctx->store, struct ldb_message *, sctx->num_stored + 2); + if (!sctx->store) { + fprintf(stderr, "talloc_realloc failed while storing messages\n"); + return -1; + } + + sctx->store[sctx->num_stored] = talloc_move(sctx->store, &msg); + sctx->num_stored++; + sctx->store[sctx->num_stored] = NULL; + + return 0; +} + +static int store_referral(char *referral, struct search_context *sctx) { + + sctx->refs_store = talloc_realloc(sctx, sctx->refs_store, char *, sctx->refs_stored + 2); + if (!sctx->refs_store) { + fprintf(stderr, "talloc_realloc failed while storing referrals\n"); + return -1; + } + + sctx->refs_store[sctx->refs_stored] = talloc_move(sctx->refs_store, &referral); + sctx->refs_stored++; + sctx->refs_store[sctx->refs_stored] = NULL; + + return 0; +} + +static int display_message(struct ldb_message *msg, struct search_context *sctx) { + struct ldb_ldif ldif; + + sctx->entries++; + printf("# record %d\n", sctx->entries); + + ldif.changetype = LDB_CHANGETYPE_NONE; + ldif.msg = msg; + + if (sctx->sort) { + /* + * Ensure attributes are always returned in the same + * order. For testing, this makes comparison of old + * vs. new much easier. + */ + ldb_msg_sort_elements(ldif.msg); + } + + ldb_ldif_write_file(sctx->ldb, stdout, &ldif); + + return 0; +} + +static int display_referral(char *referral, struct search_context *sctx) +{ + + sctx->refs++; + printf("# Referral\nref: %s\n\n", referral); + + return 0; +} + +static int search_callback(struct ldb_request *req, struct ldb_reply *ares) +{ + struct search_context *sctx; + int ret = LDB_SUCCESS; + + sctx = talloc_get_type(req->context, struct search_context); + + if (!ares) { + return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR); + } + if (ares->error != LDB_SUCCESS) { + return ldb_request_done(req, ares->error); + } + + switch (ares->type) { + case LDB_REPLY_ENTRY: + if (sctx->sort) { + ret = store_message(ares->message, sctx); + } else { + ret = display_message(ares->message, sctx); + } + break; + + case LDB_REPLY_REFERRAL: + if (sctx->sort) { + ret = store_referral(ares->referral, sctx); + } else { + ret = display_referral(ares->referral, sctx); + } + if (ret) { + return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR); + } + break; + + case LDB_REPLY_DONE: + if (ares->controls) { + if (handle_controls_reply(ares->controls, sctx->req_ctrls) == 1) + sctx->pending = 1; + } + talloc_free(ares); + return ldb_request_done(req, LDB_SUCCESS); + } + + talloc_free(ares); + if (ret != LDB_SUCCESS) { + return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR); + } + + return LDB_SUCCESS; +} + +static int do_search(struct ldb_context *ldb, + struct ldb_dn *basedn, + struct ldb_cmdline *options, + const char *expression, + const char * const *attrs) +{ + struct ldb_request *req; + struct search_context *sctx; + int ret; + + req = NULL; + + sctx = talloc_zero(ldb, struct search_context); + if (!sctx) return LDB_ERR_OPERATIONS_ERROR; + + sctx->ldb = ldb; + sctx->sort = options->sorted; + sctx->req_ctrls = ldb_parse_control_strings(ldb, sctx, (const char **)options->controls); + if (options->controls != NULL && sctx->req_ctrls== NULL) { + printf("parsing controls failed: %s\n", ldb_errstring(ldb)); + return LDB_ERR_OPERATIONS_ERROR; + } + + if (basedn == NULL) { + basedn = ldb_get_default_basedn(ldb); + } + +again: + /* free any previous requests */ + if (req) talloc_free(req); + + ret = ldb_build_search_req(&req, ldb, ldb, + basedn, options->scope, + expression, attrs, + sctx->req_ctrls, + sctx, search_callback, + NULL); + if (ret != LDB_SUCCESS) { + talloc_free(sctx); + printf("allocating request failed: %s\n", ldb_errstring(ldb)); + return ret; + } + + sctx->pending = 0; + + ret = ldb_request(ldb, req); + if (ret != LDB_SUCCESS) { + printf("search failed - %s\n", ldb_errstring(ldb)); + return ret; + } + + ret = ldb_wait(req->handle, LDB_WAIT_ALL); + if (ret != LDB_SUCCESS) { + printf("search error - %s\n", ldb_errstring(ldb)); + return ret; + } + + if (sctx->pending) + goto again; + + if (sctx->sort && (sctx->num_stored != 0 || sctx->refs != 0)) { + unsigned int i; + + if (sctx->num_stored) { + LDB_TYPESAFE_QSORT(sctx->store, sctx->num_stored, ldb, do_compare_msg); + } + for (i = 0; i < sctx->num_stored; i++) { + display_message(sctx->store[i], sctx); + } + + for (i = 0; i < sctx->refs_stored; i++) { + display_referral(sctx->refs_store[i], sctx); + } + } + + printf("# returned %u records\n# %u entries\n# %u referrals\n", + sctx->entries + sctx->refs, sctx->entries, sctx->refs); + + talloc_free(sctx); + talloc_free(req); + + return LDB_SUCCESS; +} + +int main(int argc, const char **argv) +{ + struct ldb_context *ldb; + struct ldb_dn *basedn = NULL; + const char * const * attrs = NULL; + struct ldb_cmdline *options; + int ret = -1; + const char *expression = "(|(objectClass=*)(distinguishedName=*))"; + TALLOC_CTX *mem_ctx = talloc_new(NULL); + + ldb = ldb_init(mem_ctx, NULL); + if (ldb == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + options = ldb_cmdline_process(ldb, argc, argv, usage); + + /* the check for '=' is for compatibility with ldapsearch */ + if (!options->interactive && + options->argc > 0 && + strchr(options->argv[0], '=')) { + expression = options->argv[0]; + options->argv++; + options->argc--; + } + + if (options->argc > 0) { + attrs = (const char * const *)(options->argv); + } + + if (options->basedn != NULL) { + basedn = ldb_dn_new(ldb, ldb, options->basedn); + if (basedn == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + } + + if (options->interactive) { + char line[1024]; + while (fgets(line, sizeof(line), stdin)) { + ret = do_search(ldb, basedn, options, line, attrs); + } + } else { + ret = do_search(ldb, basedn, options, expression, attrs); + } + + talloc_free(mem_ctx); + + return ret; +} diff --git a/lib/ldb/tools/ldbtest.c b/lib/ldb/tools/ldbtest.c new file mode 100644 index 0000000000..4e181af9d5 --- /dev/null +++ b/lib/ldb/tools/ldbtest.c @@ -0,0 +1,434 @@ +/* + ldb database library + + Copyright (C) Andrew Tridgell 2004 + + ** NOTE! The following LGPL license applies to the ldb + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ + +/* + * Name: ldb + * + * Component: ldbtest + * + * Description: utility to test ldb + * + * Author: Andrew Tridgell + */ + +#include "replace.h" +#include "system/filesys.h" +#include "system/time.h" +#include "ldb.h" +#include "tools/cmdline.h" + +static struct timespec tp1,tp2; +static struct ldb_cmdline *options; + +static void _start_timer(void) +{ + if (clock_gettime(CUSTOM_CLOCK_MONOTONIC, &tp1) != 0) { + clock_gettime(CLOCK_REALTIME, &tp1); + } +} + +static double _end_timer(void) +{ + if (clock_gettime(CUSTOM_CLOCK_MONOTONIC, &tp2) != 0) { + clock_gettime(CLOCK_REALTIME, &tp2); + } + return((tp2.tv_sec - tp1.tv_sec) + + (tp2.tv_nsec - tp1.tv_nsec)*1.0e-9); +} + +static void add_records(struct ldb_context *ldb, + struct ldb_dn *basedn, + unsigned int count) +{ + struct ldb_message msg; + unsigned int i; + +#if 0 + if (ldb_lock(ldb, "transaction") != 0) { + printf("transaction lock failed\n"); + exit(LDB_ERR_OPERATIONS_ERROR); + } +#endif + for (i=0;i<count;i++) { + struct ldb_message_element el[6]; + struct ldb_val vals[6][1]; + char *name; + TALLOC_CTX *tmp_ctx = talloc_new(ldb); + + name = talloc_asprintf(tmp_ctx, "Test%d", i); + + msg.dn = ldb_dn_copy(tmp_ctx, basedn); + ldb_dn_add_child_fmt(msg.dn, "cn=%s", name); + msg.num_elements = 6; + msg.elements = el; + + el[0].flags = 0; + el[0].name = talloc_strdup(tmp_ctx, "cn"); + el[0].num_values = 1; + el[0].values = vals[0]; + vals[0][0].data = (uint8_t *)name; + vals[0][0].length = strlen(name); + + el[1].flags = 0; + el[1].name = "title"; + el[1].num_values = 1; + el[1].values = vals[1]; + vals[1][0].data = (uint8_t *)talloc_asprintf(tmp_ctx, "The title of %s", name); + vals[1][0].length = strlen((char *)vals[1][0].data); + + el[2].flags = 0; + el[2].name = talloc_strdup(tmp_ctx, "uid"); + el[2].num_values = 1; + el[2].values = vals[2]; + vals[2][0].data = (uint8_t *)ldb_casefold(ldb, tmp_ctx, name, strlen(name)); + vals[2][0].length = strlen((char *)vals[2][0].data); + + el[3].flags = 0; + el[3].name = talloc_strdup(tmp_ctx, "mail"); + el[3].num_values = 1; + el[3].values = vals[3]; + vals[3][0].data = (uint8_t *)talloc_asprintf(tmp_ctx, "%s@example.com", name); + vals[3][0].length = strlen((char *)vals[3][0].data); + + el[4].flags = 0; + el[4].name = talloc_strdup(tmp_ctx, "objectClass"); + el[4].num_values = 1; + el[4].values = vals[4]; + vals[4][0].data = (uint8_t *)talloc_strdup(tmp_ctx, "OpenLDAPperson"); + vals[4][0].length = strlen((char *)vals[4][0].data); + + el[5].flags = 0; + el[5].name = talloc_strdup(tmp_ctx, "sn"); + el[5].num_values = 1; + el[5].values = vals[5]; + vals[5][0].data = (uint8_t *)name; + vals[5][0].length = strlen((char *)vals[5][0].data); + + ldb_delete(ldb, msg.dn); + + if (ldb_add(ldb, &msg) != LDB_SUCCESS) { + printf("Add of %s failed - %s\n", name, ldb_errstring(ldb)); + exit(LDB_ERR_OPERATIONS_ERROR); + } + + printf("adding uid %s\r", name); + fflush(stdout); + + talloc_free(tmp_ctx); + } +#if 0 + if (ldb_unlock(ldb, "transaction") != 0) { + printf("transaction unlock failed\n"); + exit(LDB_ERR_OPERATIONS_ERROR); + } +#endif + printf("\n"); +} + +static void modify_records(struct ldb_context *ldb, + struct ldb_dn *basedn, + unsigned int count) +{ + struct ldb_message msg; + unsigned int i; + + for (i=0;i<count;i++) { + struct ldb_message_element el[3]; + struct ldb_val vals[3]; + char *name; + TALLOC_CTX *tmp_ctx = talloc_new(ldb); + + name = talloc_asprintf(tmp_ctx, "Test%d", i); + msg.dn = ldb_dn_copy(tmp_ctx, basedn); + ldb_dn_add_child_fmt(msg.dn, "cn=%s", name); + + msg.num_elements = 3; + msg.elements = el; + + el[0].flags = LDB_FLAG_MOD_DELETE; + el[0].name = talloc_strdup(tmp_ctx, "mail"); + el[0].num_values = 0; + + el[1].flags = LDB_FLAG_MOD_ADD; + el[1].name = talloc_strdup(tmp_ctx, "mail"); + el[1].num_values = 1; + el[1].values = &vals[1]; + vals[1].data = (uint8_t *)talloc_asprintf(tmp_ctx, "%s@other.example.com", name); + vals[1].length = strlen((char *)vals[1].data); + + el[2].flags = LDB_FLAG_MOD_REPLACE; + el[2].name = talloc_strdup(tmp_ctx, "mail"); + el[2].num_values = 1; + el[2].values = &vals[2]; + vals[2].data = (uint8_t *)talloc_asprintf(tmp_ctx, "%s@other2.example.com", name); + vals[2].length = strlen((char *)vals[2].data); + + if (ldb_modify(ldb, &msg) != LDB_SUCCESS) { + printf("Modify of %s failed - %s\n", name, ldb_errstring(ldb)); + exit(LDB_ERR_OPERATIONS_ERROR); + } + + printf("Modifying uid %s\r", name); + fflush(stdout); + + talloc_free(tmp_ctx); + } + + printf("\n"); +} + + +static void delete_records(struct ldb_context *ldb, + struct ldb_dn *basedn, + unsigned int count) +{ + unsigned int i; + + for (i=0;i<count;i++) { + struct ldb_dn *dn; + char *name = talloc_asprintf(ldb, "Test%d", i); + dn = ldb_dn_copy(name, basedn); + ldb_dn_add_child_fmt(dn, "cn=%s", name); + + printf("Deleting uid Test%d\r", i); + fflush(stdout); + + if (ldb_delete(ldb, dn) != LDB_SUCCESS) { + printf("Delete of %s failed - %s\n", ldb_dn_get_linearized(dn), ldb_errstring(ldb)); + exit(LDB_ERR_OPERATIONS_ERROR); + } + talloc_free(name); + } + + printf("\n"); +} + +static void search_uid(struct ldb_context *ldb, struct ldb_dn *basedn, + unsigned int nrecords, unsigned int nsearches) +{ + unsigned int i; + + for (i=0;i<nsearches;i++) { + int uid = (i * 700 + 17) % (nrecords * 2); + char *expr; + struct ldb_result *res = NULL; + int ret; + + expr = talloc_asprintf(ldb, "(uid=TEST%d)", uid); + ret = ldb_search(ldb, ldb, &res, basedn, LDB_SCOPE_SUBTREE, NULL, "%s", expr); + + if (ret != LDB_SUCCESS || (uid < nrecords && res->count != 1)) { + printf("Failed to find %s - %s\n", expr, ldb_errstring(ldb)); + exit(LDB_ERR_OPERATIONS_ERROR); + } + + if (uid >= nrecords && res->count > 0) { + printf("Found %s !? - %d\n", expr, ret); + exit(LDB_ERR_OPERATIONS_ERROR); + } + + printf("Testing uid %d/%d - %d \r", i, uid, res->count); + fflush(stdout); + + talloc_free(res); + talloc_free(expr); + } + + printf("\n"); +} + +static void start_test(struct ldb_context *ldb, unsigned int nrecords, + unsigned int nsearches) +{ + struct ldb_dn *basedn; + + basedn = ldb_dn_new(ldb, ldb, options->basedn); + if ( ! ldb_dn_validate(basedn)) { + printf("Invalid base DN format\n"); + exit(LDB_ERR_INVALID_DN_SYNTAX); + } + + printf("Adding %d records\n", nrecords); + add_records(ldb, basedn, nrecords); + + printf("Starting search on uid\n"); + _start_timer(); + search_uid(ldb, basedn, nrecords, nsearches); + printf("uid search took %.2f seconds\n", _end_timer()); + + printf("Modifying records\n"); + modify_records(ldb, basedn, nrecords); + + printf("Deleting records\n"); + delete_records(ldb, basedn, nrecords); +} + + +/* + 2) Store an @indexlist record + + 3) Store a record that contains fields that should be index according +to @index + + 4) disconnection from database + + 5) connect to same database + + 6) search for record added in step 3 using a search key that should +be indexed +*/ +static void start_test_index(struct ldb_context **ldb) +{ + struct ldb_message *msg; + struct ldb_result *res = NULL; + struct ldb_dn *indexlist; + struct ldb_dn *basedn; + int ret; + unsigned int flags = 0; + const char *specials; + + specials = getenv("LDB_SPECIALS"); + if (specials && atoi(specials) == 0) { + printf("LDB_SPECIALS disabled - skipping index test\n"); + return; + } + + if (options->nosync) { + flags |= LDB_FLG_NOSYNC; + } + + printf("Starting index test\n"); + + indexlist = ldb_dn_new(*ldb, *ldb, "@INDEXLIST"); + + ldb_delete(*ldb, indexlist); + + msg = ldb_msg_new(NULL); + + msg->dn = indexlist; + ldb_msg_add_string(msg, "@IDXATTR", strdup("uid")); + + if (ldb_add(*ldb, msg) != 0) { + printf("Add of %s failed - %s\n", ldb_dn_get_linearized(msg->dn), ldb_errstring(*ldb)); + exit(LDB_ERR_OPERATIONS_ERROR); + } + + basedn = ldb_dn_new(*ldb, *ldb, options->basedn); + + memset(msg, 0, sizeof(*msg)); + msg->dn = ldb_dn_copy(msg, basedn); + ldb_dn_add_child_fmt(msg->dn, "cn=test"); + ldb_msg_add_string(msg, "cn", strdup("test")); + ldb_msg_add_string(msg, "sn", strdup("test")); + ldb_msg_add_string(msg, "uid", strdup("test")); + ldb_msg_add_string(msg, "objectClass", strdup("OpenLDAPperson")); + + if (ldb_add(*ldb, msg) != LDB_SUCCESS) { + printf("Add of %s failed - %s\n", ldb_dn_get_linearized(msg->dn), ldb_errstring(*ldb)); + exit(LDB_ERR_OPERATIONS_ERROR); + } + + if (talloc_free(*ldb) != 0) { + printf("failed to free/close ldb database"); + exit(LDB_ERR_OPERATIONS_ERROR); + } + + (*ldb) = ldb_init(options, NULL); + + ret = ldb_connect(*ldb, options->url, flags, NULL); + if (ret != LDB_SUCCESS) { + printf("failed to connect to %s\n", options->url); + exit(LDB_ERR_OPERATIONS_ERROR); + } + + basedn = ldb_dn_new(*ldb, *ldb, options->basedn); + msg->dn = basedn; + ldb_dn_add_child_fmt(msg->dn, "cn=test"); + + ret = ldb_search(*ldb, *ldb, &res, basedn, LDB_SCOPE_SUBTREE, NULL, "uid=test"); + if (ret != LDB_SUCCESS) { + printf("Search with (uid=test) filter failed!\n"); + exit(LDB_ERR_OPERATIONS_ERROR); + } + if(res->count != 1) { + printf("Should have found 1 record - found %d\n", res->count); + exit(LDB_ERR_OPERATIONS_ERROR); + } + + indexlist = ldb_dn_new(*ldb, *ldb, "@INDEXLIST"); + + if (ldb_delete(*ldb, msg->dn) != 0 || + ldb_delete(*ldb, indexlist) != 0) { + printf("cleanup failed - %s\n", ldb_errstring(*ldb)); + exit(LDB_ERR_OPERATIONS_ERROR); + } + + printf("Finished index test\n"); +} + + +static void usage(struct ldb_context *ldb) +{ + printf("Usage: ldbtest <options>\n"); + printf("Options:\n"); + printf(" -H ldb_url choose the database (or $LDB_URL)\n"); + printf(" --num-records nrecords database size to use\n"); + printf(" --num-searches nsearches number of searches to do\n"); + printf("\n"); + printf("tests ldb API\n\n"); + exit(LDB_ERR_OPERATIONS_ERROR); +} + +int main(int argc, const char **argv) +{ + TALLOC_CTX *mem_ctx = talloc_new(NULL); + struct ldb_context *ldb; + + ldb = ldb_init(mem_ctx, NULL); + if (ldb == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + options = ldb_cmdline_process(ldb, argc, argv, usage); + + talloc_steal(mem_ctx, options); + + if (options->basedn == NULL) { + options->basedn = "ou=Ldb Test,ou=People,o=University of Michigan,c=TEST"; + } + + srandom(1); + + printf("Testing with num-records=%d and num-searches=%d\n", + options->num_records, options->num_searches); + + start_test(ldb, + (unsigned int) options->num_records, + (unsigned int) options->num_searches); + + start_test_index(&ldb); + + talloc_free(mem_ctx); + + return LDB_SUCCESS; +} diff --git a/lib/ldb/tools/ldbutil.c b/lib/ldb/tools/ldbutil.c new file mode 100644 index 0000000000..26f252704c --- /dev/null +++ b/lib/ldb/tools/ldbutil.c @@ -0,0 +1,219 @@ +/* + ldb database library utility + + Copyright (C) Matthieu Patou 2009 + + ** NOTE! The following LGPL license applies to the ldb + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ + +/* + * Name: ldb + * + * Description: Common function used by ldb_add/ldb_modify/ldb_delete + * + * Author: Matthieu Patou + */ + +#include "ldb.h" +#include "ldb_module.h" +#include "ldbutil.h" + + +/* autostarts a transacion if none active */ +static int ldb_do_autotransaction(struct ldb_context *ldb, + struct ldb_request *req) +{ + int ret; + + ret = ldb_transaction_start(ldb); + if (ret != LDB_SUCCESS) { + return ret; + } + + ret = ldb_request(ldb, req); + if (ret == LDB_SUCCESS) { + ret = ldb_wait(req->handle, LDB_WAIT_ALL); + } + + if (ret == LDB_SUCCESS) { + return ldb_transaction_commit(ldb); + } + ldb_transaction_cancel(ldb); + + if (ldb_errstring(ldb) == NULL) { + /* no error string was setup by the backend */ + ldb_asprintf_errstring(ldb, "%s (%d)", ldb_strerror(ret), ret); + } + + return ret; +} +/* + Same as ldb_add but accept control +*/ +int ldb_add_ctrl(struct ldb_context *ldb, + const struct ldb_message *message, + struct ldb_control **controls) +{ + struct ldb_request *req; + int ret; + + ret = ldb_msg_sanity_check(ldb, message); + if (ret != LDB_SUCCESS) { + return ret; + } + + ret = ldb_build_add_req(&req, ldb, ldb, + message, + controls, + NULL, + ldb_op_default_callback, + NULL); + + if (ret != LDB_SUCCESS) return ret; + + /* do request and autostart a transaction */ + ret = ldb_do_autotransaction(ldb, req); + + talloc_free(req); + return ret; +} + +/* + same as ldb_delete but accept control +*/ +int ldb_delete_ctrl(struct ldb_context *ldb, struct ldb_dn *dn, + struct ldb_control **controls) +{ + struct ldb_request *req; + int ret; + + ret = ldb_build_del_req(&req, ldb, ldb, + dn, + controls, + NULL, + ldb_op_default_callback, + NULL); + + if (ret != LDB_SUCCESS) return ret; + + /* do request and autostart a transaction */ + ret = ldb_do_autotransaction(ldb, req); + + talloc_free(req); + return ret; +} + + +/* + same as ldb_modify, but accepts controls +*/ +int ldb_modify_ctrl(struct ldb_context *ldb, + const struct ldb_message *message, + struct ldb_control **controls) +{ + struct ldb_request *req; + int ret; + + ret = ldb_msg_sanity_check(ldb, message); + if (ret != LDB_SUCCESS) { + return ret; + } + + ret = ldb_build_mod_req(&req, ldb, ldb, + message, + controls, + NULL, + ldb_op_default_callback, + NULL); + + if (ret != LDB_SUCCESS) return ret; + + /* do request and autostart a transaction */ + ret = ldb_do_autotransaction(ldb, req); + + talloc_free(req); + return ret; +} + + +/* + ldb_search with controls +*/ +int ldb_search_ctrl(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, + struct ldb_result **result, struct ldb_dn *base, + enum ldb_scope scope, const char * const *attrs, + struct ldb_control **controls, + const char *exp_fmt, ...) +{ + struct ldb_request *req; + struct ldb_result *res; + char *expression; + va_list ap; + int ret; + + expression = NULL; + *result = NULL; + req = NULL; + + res = talloc_zero(mem_ctx, struct ldb_result); + if (!res) { + return LDB_ERR_OPERATIONS_ERROR; + } + + if (exp_fmt) { + va_start(ap, exp_fmt); + expression = talloc_vasprintf(mem_ctx, exp_fmt, ap); + va_end(ap); + + if (!expression) { + talloc_free(res); + return LDB_ERR_OPERATIONS_ERROR; + } + } + + ret = ldb_build_search_req(&req, ldb, mem_ctx, + base?base:ldb_get_default_basedn(ldb), + scope, + expression, + attrs, + controls, + res, + ldb_search_default_callback, + NULL); + ldb_req_set_location(req, "ldb_search_ctrl"); + + if (ret != LDB_SUCCESS) goto done; + + ret = ldb_request(ldb, req); + + if (ret == LDB_SUCCESS) { + ret = ldb_wait(req->handle, LDB_WAIT_ALL); + } + +done: + if (ret != LDB_SUCCESS) { + talloc_free(res); + res = NULL; + } + + talloc_free(expression); + talloc_free(req); + + *result = res; + return ret; +} diff --git a/lib/ldb/tools/ldbutil.h b/lib/ldb/tools/ldbutil.h new file mode 100644 index 0000000000..f8d3f3a210 --- /dev/null +++ b/lib/ldb/tools/ldbutil.h @@ -0,0 +1,46 @@ +/* + ldb database library utility header file + + Copyright (C) Matthieu Patou 2009 + + ** NOTE! The following LGPL license applies to the ldb + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ + +/* + * Name: ldb + * + * Description: Common function used by ldb_add/ldb_modify/ldb_delete + * + * Author: Matthieu Patou + */ + +#include "ldb.h" + +int ldb_add_ctrl(struct ldb_context *ldb, + const struct ldb_message *message, + struct ldb_control **controls); +int ldb_delete_ctrl(struct ldb_context *ldb, struct ldb_dn *dn, + struct ldb_control **controls); +int ldb_modify_ctrl(struct ldb_context *ldb, + const struct ldb_message *message, + struct ldb_control **controls); +int ldb_search_ctrl(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, + struct ldb_result **result, struct ldb_dn *base, + enum ldb_scope scope, const char * const *attrs, + struct ldb_control **controls, + const char *exp_fmt, ...); |