diff options
Diffstat (limited to 'ldb/tools')
-rw-r--r-- | ldb/tools/cmdline.c | 397 | ||||
-rw-r--r-- | ldb/tools/cmdline.h | 54 | ||||
-rw-r--r-- | ldb/tools/config.mk | 90 | ||||
-rw-r--r-- | ldb/tools/ldbadd.c | 116 | ||||
-rw-r--r-- | ldb/tools/ldbdel.c | 115 | ||||
-rw-r--r-- | ldb/tools/ldbedit.c | 329 | ||||
-rw-r--r-- | ldb/tools/ldbmodify.c | 116 | ||||
-rw-r--r-- | ldb/tools/ldbrename.c | 90 | ||||
-rw-r--r-- | ldb/tools/ldbsearch.c | 320 | ||||
-rw-r--r-- | ldb/tools/ldbtest.c | 418 |
10 files changed, 2045 insertions, 0 deletions
diff --git a/ldb/tools/cmdline.c b/ldb/tools/cmdline.c new file mode 100644 index 00000000..765d8b9e --- /dev/null +++ b/ldb/tools/cmdline.c @@ -0,0 +1,397 @@ +/* + 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 "ldb_includes.h" +#include "tools/cmdline.h" + +#if (_SAMBA_BUILD_ >= 4) +#include "includes.h" +#include "lib/cmdline/popt_common.h" +#include "lib/ldb-samba/ldif_handlers.h" +#include "auth/gensec/gensec.h" +#include "auth/auth.h" +#include "ldb_wrap.h" +#include "param/param.h" +#endif + + + +/** + process command line options +*/ +struct ldb_cmdline *ldb_cmdline_process(struct ldb_context *ldb, + int argc, const char **argv, + void (*usage)(void)) +{ + static struct ldb_cmdline options; /* needs to be static for older compilers */ + struct ldb_cmdline *ret=NULL; + poptContext pc; +#if (_SAMBA_BUILD_ >= 4) + int r; +#endif + int num_options = 0; + int opt; + int flags = 0; + + struct poptOption 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 }, + { "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 }, + { "input", 'I', POPT_ARG_STRING, &options.input, 0, "Input File", "Input" }, + { "output", 'O', POPT_ARG_STRING, &options.output, 0, "Output File", "Output" }, + { NULL, 'o', POPT_ARG_STRING, NULL, 'o', "ldb_connect option", "OPTION" }, + { "controls", 0, POPT_ARG_STRING, NULL, 'c', "controls", NULL }, +#if (_SAMBA_BUILD_ >= 4) + POPT_COMMON_SAMBA + POPT_COMMON_CREDENTIALS + POPT_COMMON_CONNECTION + POPT_COMMON_VERSION +#endif + { NULL } + }; + +#if (_SAMBA_BUILD_ >= 4) + r = ldb_register_samba_handlers(ldb); + if (r != 0) { + goto failed; + } + +#endif + + ret = talloc_zero(ldb, struct ldb_cmdline); + if (ret == NULL) { + ldb_oom(ldb); + 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; + + 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) { + ldb_oom(ldb); + 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, *q; + int cc; + + for (p = cs, cc = 1; (q = strchr(p, ',')); cc++, p = q + 1) ; + + options.controls = talloc_array(ret, char *, cc + 1); + if (options.controls == NULL) { + ldb_oom(ldb); + goto failed; + } + for (p = cs, cc = 0; p != NULL; cc++) { + const char *t; + + t = strchr(p, ','); + if (t == NULL) { + options.controls[cc] = talloc_strdup(options.controls, p); + p = NULL; + } else { + options.controls[cc] = talloc_strndup(options.controls, p, t-p); + p = t + 1; + } + } + options.controls[cc] = NULL; + + break; + } + default: + fprintf(stderr, "Invalid option %s: %s\n", + poptBadOption(pc, 0), poptStrerror(opt)); + if (usage) usage(); + 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(); + goto failed; + } + + if (strcmp(ret->url, "NONE") == 0) { + return ret; + } + + if (options.nosync) { + flags |= LDB_FLG_NOSYNC; + } + +#if (_SAMBA_BUILD_ >= 4) + /* Must be after we have processed command line options */ + gensec_init(cmdline_lp_ctx); + + if (ldb_set_opaque(ldb, "sessionInfo", system_session(ldb, cmdline_lp_ctx))) { + goto failed; + } + if (ldb_set_opaque(ldb, "credentials", cmdline_credentials)) { + goto failed; + } + if (ldb_set_opaque(ldb, "loadparm", cmdline_lp_ctx)) { + goto failed; + } + + ldb_set_utf8_fns(ldb, NULL, wrap_casefold); +#endif + + if (options.modules_path != NULL) { + ldb_set_modules_dir(ldb, options.modules_path); + } else if (getenv("LDB_MODULES_PATH") != NULL) { + ldb_set_modules_dir(ldb, getenv("LDB_MODULES_PATH")); + } + + /* now connect to the ldb */ + if (ldb_connect(ldb, ret->url, flags, ret->options) != 0) { + fprintf(stderr, "Failed to connect to %s - %s\n", + ret->url, ldb_errstring(ldb)); + goto failed; + } + + return ret; + +failed: + talloc_free(ret); + exit(1); + 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) +{ + 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/ldb/tools/cmdline.h b/ldb/tools/cmdline.h new file mode 100644 index 00000000..3473d62a --- /dev/null +++ b/ldb/tools/cmdline.h @@ -0,0 +1,54 @@ +/* + 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 *input; + const char *output; + char **controls; +}; + +struct ldb_cmdline *ldb_cmdline_process(struct ldb_context *ldb, int argc, const char **argv, + void (*usage)(void)); + + +struct ldb_control **parse_controls(void *mem_ctx, char **control_strings); +int handle_controls_reply(struct ldb_control **reply, struct ldb_control **request); diff --git a/ldb/tools/config.mk b/ldb/tools/config.mk new file mode 100644 index 00000000..6b57929d --- /dev/null +++ b/ldb/tools/config.mk @@ -0,0 +1,90 @@ +################################################ +# Start SUBSYSTEM LIBLDB_CMDLINE +[SUBSYSTEM::LIBLDB_CMDLINE] +CFLAGS = -I$(ldbsrcdir) -I$(ldbsrcdir)/include +PUBLIC_DEPENDENCIES = LIBLDB LIBPOPT +PRIVATE_DEPENDENCIES = LIBSAMBA-UTIL POPT_SAMBA POPT_CREDENTIALS gensec +# End SUBSYSTEM LIBLDB_CMDLINE +################################################ + +LIBLDB_CMDLINE_OBJ_FILES = $(ldbsrcdir)/tools/cmdline.o + +################################################ +# Start BINARY ldbadd +[BINARY::ldbadd] +INSTALLDIR = BINDIR +PRIVATE_DEPENDENCIES = \ + LIBLDB_CMDLINE LIBCLI_RESOLVE +# End BINARY ldbadd +################################################ + + +ldbadd_OBJ_FILES = $(ldbsrcdir)/tools/ldbadd.o + +MANPAGES += $(ldbsrcdir)/man/ldbadd.1 + +################################################ +# Start BINARY ldbdel +[BINARY::ldbdel] +INSTALLDIR = BINDIR +PRIVATE_DEPENDENCIES = \ + LIBLDB_CMDLINE +# End BINARY ldbdel +################################################ + +ldbdel_OBJ_FILES = $(ldbsrcdir)/tools/ldbdel.o + +MANPAGES += $(ldbsrcdir)/man/ldbdel.1 + +################################################ +# Start BINARY ldbmodify +[BINARY::ldbmodify] +INSTALLDIR = BINDIR +PRIVATE_DEPENDENCIES = \ + LIBLDB_CMDLINE +# End BINARY ldbmodify +################################################ + +ldbmodify_OBJ_FILES = $(ldbsrcdir)/tools/ldbmodify.o +MANPAGES += $(ldbsrcdir)/man/ldbmodify.1 + +################################################ +# Start BINARY ldbsearch +[BINARY::ldbsearch] +INSTALLDIR = BINDIR +PRIVATE_DEPENDENCIES = \ + LIBLDB_CMDLINE +# End BINARY ldbsearch +################################################ + +ldbsearch_OBJ_FILES = $(ldbsrcdir)/tools/ldbsearch.o + +MANPAGES += $(ldbsrcdir)/man/ldbsearch.1 + +################################################ +# Start BINARY ldbedit +[BINARY::ldbedit] +INSTALLDIR = BINDIR +PRIVATE_DEPENDENCIES = \ + LIBLDB_CMDLINE +# End BINARY ldbedit +################################################ + +ldbedit_OBJ_FILES = $(ldbsrcdir)/tools/ldbedit.o + +MANPAGES += $(ldbsrcdir)/man/ldbedit.1 + +################################################ +# Start BINARY ldbrename +[BINARY::ldbrename] +INSTALLDIR = BINDIR +PRIVATE_DEPENDENCIES = \ + LIBLDB_CMDLINE +# End BINARY ldbrename +################################################ + +ldbrename_OBJ_FILES = $(ldbsrcdir)/tools/ldbrename.o + +MANPAGES += $(ldbsrcdir)/man/ldbrename.1 + + diff --git a/ldb/tools/ldbadd.c b/ldb/tools/ldbadd.c new file mode 100644 index 00000000..15376e73 --- /dev/null +++ b/ldb/tools/ldbadd.c @@ -0,0 +1,116 @@ +/* + 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_includes.h" +#include "tools/cmdline.h" + +static int failures; + +static void usage(void) +{ + printf("Usage: ldbadd <options> <ldif...>\n"); + printf("Options:\n"); + printf(" -H ldb_url choose the database (or $LDB_URL)\n"); + printf(" -o options pass options like modules to activate\n"); + printf(" e.g: -o modules:timestamps\n"); + printf("\n"); + printf("Adds records to a ldb, reading ldif the specified list of files\n\n"); + exit(1); +} + + +/* + add records from an opened file +*/ +static int process_file(struct ldb_context *ldb, FILE *f, int *count) +{ + struct ldb_ldif *ldif; + int ret = LDB_SUCCESS; + + 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; + } + + ldif->msg = ldb_msg_canonicalize(ldb, ldif->msg); + + ret = ldb_add(ldb, ldif->msg); + if (ret != LDB_SUCCESS) { + fprintf(stderr, "ERR: \"%s\" on DN %s\n", + ldb_errstring(ldb), ldb_dn_get_linearized(ldif->msg->dn)); + failures++; + } else { + (*count)++; + } + ldb_ldif_read_free(ldb, ldif); + } + + return ret; +} + + + +int main(int argc, const char **argv) +{ + struct ldb_context *ldb; + int i, ret=0, count=0; + struct ldb_cmdline *options; + + ldb = ldb_init(NULL, NULL); + + 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); + exit(1); + } + ret = process_file(ldb, f, &count); + fclose(f); + } + } + + talloc_free(ldb); + + printf("Added %d records with %d failures\n", count, failures); + + return ret; +} diff --git a/ldb/tools/ldbdel.c b/ldb/tools/ldbdel.c new file mode 100644 index 00000000..e66d4fb9 --- /dev/null +++ b/ldb/tools/ldbdel.c @@ -0,0 +1,115 @@ +/* + 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 "ldb_includes.h" +#include "tools/cmdline.h" + +static int ldb_delete_recursive(struct ldb_context *ldb, struct ldb_dn *dn) +{ + int ret, i, total=0; + const char *attrs[] = { NULL }; + struct ldb_result *res; + + ret = ldb_search(ldb, dn, LDB_SCOPE_SUBTREE, "distinguishedName=*", attrs, &res); + if (ret != LDB_SUCCESS) return -1; + + for (i = 0; i < res->count; i++) { + if (ldb_delete(ldb, res->msgs[i]->dn) == 0) { + total++; + } + } + + talloc_free(res); + + if (total == 0) { + return -1; + } + printf("Deleted %d records\n", total); + return 0; +} + +static void usage(void) +{ + printf("Usage: ldbdel <options> <DN...>\n"); + printf("Options:\n"); + printf(" -r recursively delete the given subtree\n"); + printf(" -H ldb_url choose the database (or $LDB_URL)\n"); + printf(" -o options pass options like modules to activate\n"); + printf(" e.g: -o modules:timestamps\n"); + printf("\n"); + printf("Deletes records from a ldb\n\n"); + exit(1); +} + +int main(int argc, const char **argv) +{ + struct ldb_context *ldb; + int ret = 0, i; + struct ldb_cmdline *options; + + ldb = ldb_init(NULL, NULL); + + options = ldb_cmdline_process(ldb, argc, argv, usage); + + if (options->argc < 1) { + usage(); + exit(1); + } + + for (i=0;i<options->argc;i++) { + struct ldb_dn *dn; + + dn = ldb_dn_new(ldb, ldb, options->argv[i]); + if ( ! ldb_dn_validate(dn)) { + printf("Invalid DN format\n"); + exit(1); + } + if (options->recursive) { + ret = ldb_delete_recursive(ldb, dn); + } else { + ret = ldb_delete(ldb, dn); + if (ret == 0) { + printf("Deleted 1 record\n"); + } + } + if (ret != 0) { + printf("delete of '%s' failed - %s\n", + ldb_dn_get_linearized(dn), + ldb_errstring(ldb)); + } + } + + talloc_free(ldb); + + return ret; +} diff --git a/ldb/tools/ldbedit.c b/ldb/tools/ldbedit.c new file mode 100644 index 00000000..e58a5a27 --- /dev/null +++ b/ldb/tools/ldbedit.c @@ -0,0 +1,329 @@ +/* + 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 "ldb_includes.h" +#include "tools/cmdline.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_message *mod; + + mod = ldb_msg_diff(ldb, msg1, msg2); + if (mod == NULL) { + fprintf(stderr, "Failed to calculate message differences\n"); + return -1; + } + + if (mod->num_elements == 0) { + return 0; + } + + if (options->verbose > 0) { + ldif_write_msg(ldb, stdout, LDB_CHANGETYPE_MODIFY, mod); + } + + if (ldb_modify(ldb, mod) != 0) { + fprintf(stderr, "failed to modify %s - %s\n", + ldb_dn_get_linearized(msg1->dn), ldb_errstring(ldb)); + return -1; + } + + return mod->num_elements; +} + +/* + find dn in msgs[] +*/ +static struct ldb_message *msg_find(struct ldb_context *ldb, + struct ldb_message **msgs, + int count, + struct ldb_dn *dn) +{ + 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, int count1, + struct ldb_message **msgs2, int count2) +{ + int i; + struct ldb_message *msg; + int ret = 0; + int adds=0, modifies=0, deletes=0; + + /* 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(ldb, msgs2[i]) != 0) { + fprintf(stderr, "failed to add %s - %s\n", + ldb_dn_get_linearized(msgs2[i]->dn), + ldb_errstring(ldb)); + return -1; + } + adds++; + } else { + if (modify_record(ldb, msg, msgs2[i]) > 0) { + modifies++; + } + } + } + + /* 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(ldb, msgs1[i]->dn) != 0) { + fprintf(stderr, "failed to delete %s - %s\n", + ldb_dn_get_linearized(msgs1[i]->dn), + ldb_errstring(ldb)); + return -1; + } + deletes++; + } + } + + printf("# %d adds %d modifies %d deletes\n", adds, modifies, deletes); + + return ret; +} + +/* + save a set of messages as ldif to a file +*/ +static int save_ldif(struct ldb_context *ldb, + FILE *f, struct ldb_message **msgs, int count) +{ + int i; + + fprintf(f, "# editing %d records\n", count); + + for (i=0;i<count;i++) { + struct ldb_ldif ldif; + fprintf(f, "# record %d\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, 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; + 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; + } + + fclose(f); + unlink(file_template); + + return merge_edits(ldb, msgs1, count1, msgs2, count2); +} + +static void usage(void) +{ + printf("Usage: ldbedit <options> <expression> <attributes ...>\n"); + printf("Options:\n"); + printf(" -H ldb_url choose the database (or $LDB_URL)\n"); + printf(" -s base|sub|one choose search scope\n"); + printf(" -b basedn choose baseDN\n"); + printf(" -a edit all records (expression 'objectclass=*')\n"); + printf(" -e editor choose editor (or $VISUAL or $EDITOR)\n"); + printf(" -v verbose mode\n"); + exit(1); +} + +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; + + ldb = ldb_init(NULL, NULL); + + 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 ( ! ldb_dn_validate(basedn)) { + printf("Invalid Base DN format\n"); + exit(1); + } + } + + ret = ldb_search(ldb, basedn, options->scope, expression, attrs, &result); + if (ret != LDB_SUCCESS) { + printf("search failed - %s\n", ldb_errstring(ldb)); + exit(1); + } + + if (result->count == 0) { + printf("no matching records - cannot edit\n"); + return 0; + } + + do_edit(ldb, result->msgs, result->count, options->editor); + + if (result) { + ret = talloc_free(result); + if (ret == -1) { + fprintf(stderr, "talloc_free failed\n"); + exit(1); + } + } + + talloc_free(ldb); + return 0; +} diff --git a/ldb/tools/ldbmodify.c b/ldb/tools/ldbmodify.c new file mode 100644 index 00000000..6e355a10 --- /dev/null +++ b/ldb/tools/ldbmodify.c @@ -0,0 +1,116 @@ +/* + 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_includes.h" +#include "tools/cmdline.h" + +static int failures; + +static void usage(void) +{ + printf("Usage: ldbmodify <options> <ldif...>\n"); + printf("Options:\n"); + printf(" -H ldb_url choose the database (or $LDB_URL)\n"); + printf(" -o options pass options like modules to activate\n"); + printf(" e.g: -o modules:timestamps\n"); + printf("\n"); + printf("Modifies a ldb based upon ldif change records\n\n"); + exit(1); +} + +/* + process modifies for one file +*/ +static int process_file(struct ldb_context *ldb, FILE *f, int *count) +{ + struct ldb_ldif *ldif; + int ret = LDB_SUCCESS; + + while ((ldif = ldb_ldif_read_file(ldb, f))) { + switch (ldif->changetype) { + case LDB_CHANGETYPE_NONE: + case LDB_CHANGETYPE_ADD: + ret = ldb_add(ldb, ldif->msg); + break; + case LDB_CHANGETYPE_DELETE: + ret = ldb_delete(ldb, ldif->msg->dn); + break; + case LDB_CHANGETYPE_MODIFY: + ret = ldb_modify(ldb, ldif->msg); + break; + } + if (ret != LDB_SUCCESS) { + fprintf(stderr, "ERR: \"%s\" on DN %s\n", + ldb_errstring(ldb), ldb_dn_get_linearized(ldif->msg->dn)); + failures++; + } else { + (*count)++; + } + ldb_ldif_read_free(ldb, ldif); + } + + return ret; +} + +int main(int argc, const char **argv) +{ + struct ldb_context *ldb; + int count=0; + int i, ret=LDB_SUCCESS; + struct ldb_cmdline *options; + + ldb = ldb_init(NULL, NULL); + + 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); + exit(1); + } + ret = process_file(ldb, f, &count); + } + } + + talloc_free(ldb); + + printf("Modified %d records with %d failures\n", count, failures); + + return ret; +} diff --git a/ldb/tools/ldbrename.c b/ldb/tools/ldbrename.c new file mode 100644 index 00000000..a5feb7a0 --- /dev/null +++ b/ldb/tools/ldbrename.c @@ -0,0 +1,90 @@ +/* + 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_includes.h" +#include "tools/cmdline.h" + +static void usage(void) +{ + printf("Usage: ldbrename [<options>] <olddn> <newdn>\n"); + printf("Options:\n"); + printf(" -H ldb_url choose the database (or $LDB_URL)\n"); + printf(" -o options pass options like modules to activate\n"); + printf(" e.g: -o modules:timestamps\n"); + printf("\n"); + printf("Renames records in a ldb\n\n"); + exit(1); +} + + +int main(int argc, const char **argv) +{ + struct ldb_context *ldb; + int ret; + struct ldb_cmdline *options; + struct ldb_dn *dn1, *dn2; + + ldb = ldb_init(NULL, NULL); + + options = ldb_cmdline_process(ldb, argc, argv, usage); + + if (options->argc < 2) { + usage(); + } + + dn1 = ldb_dn_new(ldb, ldb, options->argv[0]); + dn2 = ldb_dn_new(ldb, ldb, options->argv[1]); + + if ( ! ldb_dn_validate(dn1)) { + printf("Invalid DN1: %s\n", options->argv[0]); + return -1; + } + if ( ! ldb_dn_validate(dn2)) { + printf("Invalid DN2: %s\n", options->argv[1]); + return -1; + } + + ret = ldb_rename(ldb, dn1, dn2); + if (ret == 0) { + 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(ldb); + + return ret; +} diff --git a/ldb/tools/ldbsearch.c b/ldb/tools/ldbsearch.c new file mode 100644 index 00000000..b3d1f934 --- /dev/null +++ b/ldb/tools/ldbsearch.c @@ -0,0 +1,320 @@ +/* + 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 "ldb_includes.h" +#include "tools/cmdline.h" + +static void usage(void) +{ + printf("Usage: ldbsearch <options> <expression> <attrs...>\n"); + printf("Options:\n"); + printf(" -H ldb_url choose the database (or $LDB_URL)\n"); + printf(" -s base|sub|one choose search scope\n"); + printf(" -b basedn choose baseDN\n"); + printf(" -i read search expressions from stdin\n"); + printf(" -S sort returned attributes\n"); + printf(" -o options pass options like modules to activate\n"); + printf(" e.g: -o modules:timestamps\n"); + exit(1); +} + +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_control **req_ctrls; + + int sort; + int num_stored; + struct ldb_message **store; + int refs_stored; + char **refs_store; + + int entries; + int refs; + + 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_context *ldb, 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(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_context *ldb, void *context, struct ldb_reply *ares) +{ + struct search_context *sctx = talloc_get_type(context, struct search_context); + int ret; + + switch (ares->type) { + + case LDB_REPLY_ENTRY: + if (sctx->sort) { + ret = store_message(ares->message, sctx); + } else { + ret = display_message(ldb, ares->message, sctx); + } + break; + + case LDB_REPLY_REFERRAL: + if (sctx->sort) { + ret = store_referral(ares->referral, sctx); + } else { + ret = display_referral(ares->referral, sctx); + } + break; + + case LDB_REPLY_DONE: + if (ares->controls) { + if (handle_controls_reply(ares->controls, sctx->req_ctrls) == 1) + sctx->pending = 1; + } + ret = 0; + break; + + default: + fprintf(stderr, "unknown Reply Type\n"); + return LDB_ERR_OTHER; + } + + if (talloc_free(ares) == -1) { + fprintf(stderr, "talloc_free failed\n"); + sctx->pending = 0; + return LDB_ERR_OPERATIONS_ERROR; + } + + if (ret) { + return 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 = talloc(ldb, struct ldb_request); + if (!req) return -1; + + sctx = talloc(req, struct search_context); + if (!sctx) return -1; + + sctx->sort = options->sorted; + sctx->num_stored = 0; + sctx->refs_stored = 0; + sctx->store = NULL; + 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 -1; + } + sctx->entries = 0; + sctx->refs = 0; + + if (basedn == NULL) { + basedn = ldb_get_default_basedn(ldb); + } + + req->operation = LDB_SEARCH; + req->op.search.base = basedn; + req->op.search.scope = options->scope; + req->op.search.tree = ldb_parse_tree(req, expression); + if (req->op.search.tree == NULL) return -1; + req->op.search.attrs = attrs; + req->controls = sctx->req_ctrls; + req->context = sctx; + req->callback = &search_callback; + ldb_set_timeout(ldb, req, 0); /* TODO: make this settable by command line */ + +again: + sctx->pending = 0; + + ret = ldb_request(ldb, req); + if (ret != LDB_SUCCESS) { + printf("search failed - %s\n", ldb_errstring(ldb)); + return -1; + } + + ret = ldb_wait(req->handle, LDB_WAIT_ALL); + if (ret != LDB_SUCCESS) { + printf("search error - %s\n", ldb_errstring(ldb)); + return -1; + } + + if (sctx->pending) + goto again; + + if (sctx->sort && (sctx->num_stored != 0 || sctx->refs != 0)) { + int i; + + if (sctx->num_stored) { + ldb_qsort(sctx->store, sctx->num_stored, sizeof(struct ldb_message *), + ldb, (ldb_qsort_cmp_fn_t)do_compare_msg); + } + for (i = 0; i < sctx->num_stored; i++) { + display_message(ldb, sctx->store[i], sctx); + } + + for (i = 0; i < sctx->refs_stored; i++) { + display_referral(sctx->refs_store[i], sctx); + } + } + + printf("# returned %d records\n# %d entries\n# %d referrals\n", + sctx->entries + sctx->refs, sctx->entries, sctx->refs); + + talloc_free(req); + + return 0; +} + +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=*))"; + + ldb = ldb_init(NULL, NULL); + if (ldb == NULL) { + return -1; + } + + 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 ( ! ldb_dn_validate(basedn)) { + fprintf(stderr, "Invalid Base DN format\n"); + exit(1); + } + } + + if (options->interactive) { + char line[1024]; + while (fgets(line, sizeof(line), stdin)) { + if (do_search(ldb, basedn, options, line, attrs) == -1) { + ret = -1; + } + } + } else { + ret = do_search(ldb, basedn, options, expression, attrs); + } + + talloc_free(ldb); + return ret; +} diff --git a/ldb/tools/ldbtest.c b/ldb/tools/ldbtest.c new file mode 100644 index 00000000..169ff02d --- /dev/null +++ b/ldb/tools/ldbtest.c @@ -0,0 +1,418 @@ +/* + 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 "ldb_includes.h" +#include "tools/cmdline.h" + +static struct timeval tp1,tp2; +static struct ldb_cmdline *options; + +static void _start_timer(void) +{ + gettimeofday(&tp1,NULL); +} + +static double _end_timer(void) +{ + gettimeofday(&tp2,NULL); + return((tp2.tv_sec - tp1.tv_sec) + + (tp2.tv_usec - tp1.tv_usec)*1.0e-6); +} + +static void add_records(struct ldb_context *ldb, + struct ldb_dn *basedn, + int count) +{ + struct ldb_message msg; + int i; + +#if 0 + if (ldb_lock(ldb, "transaction") != 0) { + printf("transaction lock failed\n"); + exit(1); + } +#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) != 0) { + printf("Add of %s failed - %s\n", name, ldb_errstring(ldb)); + exit(1); + } + + 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(1); + } +#endif + printf("\n"); +} + +static void modify_records(struct ldb_context *ldb, + struct ldb_dn *basedn, + int count) +{ + struct ldb_message msg; + 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) != 0) { + printf("Modify of %s failed - %s\n", name, ldb_errstring(ldb)); + exit(1); + } + + 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, + int count) +{ + 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) != 0) { + printf("Delete of %s failed - %s\n", ldb_dn_get_linearized(dn), ldb_errstring(ldb)); + exit(1); + } + talloc_free(name); + } + + printf("\n"); +} + +static void search_uid(struct ldb_context *ldb, struct ldb_dn *basedn, int nrecords, int nsearches) +{ + 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, basedn, LDB_SCOPE_SUBTREE, expr, NULL, &res); + + if (ret != LDB_SUCCESS || (uid < nrecords && res->count != 1)) { + printf("Failed to find %s - %s\n", expr, ldb_errstring(ldb)); + exit(1); + } + + if (uid >= nrecords && res->count > 0) { + printf("Found %s !? - %d\n", expr, ret); + exit(1); + } + + 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, int nrecords, int nsearches) +{ + struct ldb_dn *basedn; + + basedn = ldb_dn_new(ldb, ldb, options->basedn); + if ( ! ldb_dn_validate(basedn)) { + printf("Invalid base DN\n"); + exit(1); + } + + 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; + 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(1); + } + + 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) != 0) { + printf("Add of %s failed - %s\n", ldb_dn_get_linearized(msg->dn), ldb_errstring(*ldb)); + exit(1); + } + + if (talloc_free(*ldb) != 0) { + printf("failed to free/close ldb database"); + exit(1); + } + + (*ldb) = ldb_init(options, NULL); + + ret = ldb_connect(*ldb, options->url, flags, NULL); + if (ret != 0) { + printf("failed to connect to %s\n", options->url); + exit(1); + } + + basedn = ldb_dn_new(*ldb, *ldb, options->basedn); + + ret = ldb_search(*ldb, basedn, LDB_SCOPE_SUBTREE, "uid=test", NULL, &res); + if (ret != LDB_SUCCESS) { + printf("Search with (uid=test) filter failed!\n"); + exit(1); + } + if(res->count != 1) { + printf("Should have found 1 record - found %d\n", res->count); + exit(1); + } + + 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(1); + } + + printf("Finished index test\n"); +} + + +static void usage(void) +{ + 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(1); +} + +int main(int argc, const char **argv) +{ + TALLOC_CTX *mem_ctx = talloc_new(NULL); + struct ldb_context *ldb; + + ldb = ldb_init(mem_ctx, NULL); + + 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, options->num_records, options->num_searches); + + start_test_index(&ldb); + + talloc_free(mem_ctx); + + return 0; +} |