diff options
author | Andrew Tridgell <tridge@samba.org> | 2006-09-24 02:49:04 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 12:14:36 -0500 |
commit | 3e2c696e45b24b0192ab7b1ddaf1dd4d79571609 (patch) | |
tree | 9c4423bdb006f7c183fea0c87331d23e7043d0b1 /source3/lib/ldb/tools | |
parent | 0c3194816b513e3743ddcacd1eca2b683ca39b88 (diff) | |
download | samba-3e2c696e45b24b0192ab7b1ddaf1dd4d79571609.tar.gz samba-3e2c696e45b24b0192ab7b1ddaf1dd4d79571609.tar.bz2 samba-3e2c696e45b24b0192ab7b1ddaf1dd4d79571609.zip |
r18866: Jeremy and Volker have given the go-ahead on the group mapping ldb
code. Yay!
This first commit copies lib/ldb/ from Samba4. A huge congratulations
should go to Simo on this - he has put an enormous amount of work into
ldb, and it's great to see it go into the Samba3 tree.
(This used to be commit bbedf2e34315f5c420a3a05dfe22b1d5cf79f042)
Diffstat (limited to 'source3/lib/ldb/tools')
-rw-r--r-- | source3/lib/ldb/tools/ad2oLschema.c | 630 | ||||
-rw-r--r-- | source3/lib/ldb/tools/cmdline.c | 747 | ||||
-rw-r--r-- | source3/lib/ldb/tools/cmdline.h | 54 | ||||
-rw-r--r-- | source3/lib/ldb/tools/convert.c | 166 | ||||
-rw-r--r-- | source3/lib/ldb/tools/convert.h | 10 | ||||
-rw-r--r-- | source3/lib/ldb/tools/ldbadd.c | 120 | ||||
-rw-r--r-- | source3/lib/ldb/tools/ldbdel.c | 119 | ||||
-rw-r--r-- | source3/lib/ldb/tools/ldbedit.c | 333 | ||||
-rw-r--r-- | source3/lib/ldb/tools/ldbmodify.c | 124 | ||||
-rw-r--r-- | source3/lib/ldb/tools/ldbrename.c | 85 | ||||
-rw-r--r-- | source3/lib/ldb/tools/ldbsearch.c | 321 | ||||
-rw-r--r-- | source3/lib/ldb/tools/ldbtest.c | 410 | ||||
-rw-r--r-- | source3/lib/ldb/tools/oLschema2ldif.c | 608 |
13 files changed, 3727 insertions, 0 deletions
diff --git a/source3/lib/ldb/tools/ad2oLschema.c b/source3/lib/ldb/tools/ad2oLschema.c new file mode 100644 index 0000000000..8b1203bff0 --- /dev/null +++ b/source3/lib/ldb/tools/ad2oLschema.c @@ -0,0 +1,630 @@ +/* + ldb database library + + Copyright (C) Andrew Bartlett 2006 + + ** 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 2 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, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* + * Name: ldb + * + * Component: ad2oLschema + * + * Description: utility to convert an AD schema into the format required by OpenLDAP + * + * Author: Andrew Tridgell + */ + +#include "includes.h" +#include "ldb/include/includes.h" +#include "system/locale.h" +#include "ldb/tools/cmdline.h" +#include "ldb/tools/convert.h" + +struct schema_conv { + int count; + int skipped; + int failures; +}; + +enum convert_target { + TARGET_OPENLDAP, + TARGET_FEDORA_DS +}; + + +static void usage(void) +{ + printf("Usage: ad2oLschema <options>\n"); + printf("\nConvert AD-like LDIF to OpenLDAP schema format\n\n"); + printf("Options:\n"); + printf(" -I inputfile inputfile of mapped OIDs and skipped attributes/ObjectClasses"); + printf(" -H url LDB or LDAP server to read schmea from\n"); + printf(" -O outputfile outputfile otherwise STDOUT\n"); + printf(" -o options pass options like modules to activate\n"); + printf(" e.g: -o modules:timestamps\n"); + printf("\n"); + printf("Converts records from an AD-like LDIF schema into an openLdap formatted schema\n\n"); + exit(1); +} + +static int fetch_attrs_schema(struct ldb_context *ldb, struct ldb_dn *schemadn, + TALLOC_CTX *mem_ctx, + struct ldb_result **attrs_res) +{ + TALLOC_CTX *local_ctx = talloc_new(mem_ctx); + int ret; + const char *attrs[] = { + "lDAPDisplayName", + "isSingleValued", + "attributeID", + "attributeSyntax", + "description", + NULL + }; + + if (!local_ctx) { + return LDB_ERR_OPERATIONS_ERROR; + } + + /* Downlaod schema */ + ret = ldb_search(ldb, schemadn, LDB_SCOPE_SUBTREE, + "objectClass=attributeSchema", + attrs, attrs_res); + if (ret != LDB_SUCCESS) { + printf("Search failed: %s\n", ldb_errstring(ldb)); + return LDB_ERR_OPERATIONS_ERROR; + } + + return ret; +} + +static const char *oc_attrs[] = { + "lDAPDisplayName", + "mayContain", + "mustContain", + "systemMayContain", + "systemMustContain", + "objectClassCategory", + "governsID", + "description", + "subClassOf", + NULL +}; + +static int fetch_oc_recursive(struct ldb_context *ldb, struct ldb_dn *schemadn, + TALLOC_CTX *mem_ctx, + struct ldb_result *search_from, + struct ldb_result *res_list) +{ + int i; + int ret = 0; + for (i=0; i < search_from->count; i++) { + struct ldb_result *res; + const char *name = ldb_msg_find_attr_as_string(search_from->msgs[i], + "lDAPDisplayname", NULL); + char *filter = talloc_asprintf(mem_ctx, "(&(&(objectClass=classSchema)(subClassOf=%s))(!(lDAPDisplayName=%s)))", + name, name); + + ret = ldb_search(ldb, schemadn, LDB_SCOPE_SUBTREE, + filter, + oc_attrs, &res); + talloc_free(filter); + if (ret != LDB_SUCCESS) { + printf("Search failed: %s\n", ldb_errstring(ldb)); + return ret; + } + + talloc_steal(mem_ctx, res); + + res_list->msgs = talloc_realloc(res_list, res_list->msgs, + struct ldb_message *, res_list->count + 2); + if (!res_list->msgs) { + return LDB_ERR_OPERATIONS_ERROR; + } + res_list->msgs[res_list->count] = talloc_move(res_list, + &search_from->msgs[i]); + res_list->count++; + res_list->msgs[res_list->count] = NULL; + + if (res->count > 0) { + ret = fetch_oc_recursive(ldb, schemadn, mem_ctx, res, res_list); + } + if (ret != LDB_SUCCESS) { + return ret; + } + } + return ret; +} + +static int fetch_objectclass_schema(struct ldb_context *ldb, struct ldb_dn *schemadn, + TALLOC_CTX *mem_ctx, + struct ldb_result **objectclasses_res) +{ + TALLOC_CTX *local_ctx = talloc_new(mem_ctx); + struct ldb_result *top_res, *ret_res; + int ret; + if (!local_ctx) { + return LDB_ERR_OPERATIONS_ERROR; + } + + /* Downlaod 'top' */ + ret = ldb_search(ldb, schemadn, LDB_SCOPE_SUBTREE, + "(&(objectClass=classSchema)(lDAPDisplayName=top))", + oc_attrs, &top_res); + if (ret != LDB_SUCCESS) { + printf("Search failed: %s\n", ldb_errstring(ldb)); + return LDB_ERR_OPERATIONS_ERROR; + } + + talloc_steal(local_ctx, top_res); + + if (top_res->count != 1) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ret_res = talloc_zero(local_ctx, struct ldb_result); + if (!ret_res) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = fetch_oc_recursive(ldb, schemadn, local_ctx, top_res, ret_res); + + if (ret != LDB_SUCCESS) { + printf("Search failed: %s\n", ldb_errstring(ldb)); + return LDB_ERR_OPERATIONS_ERROR; + } + + *objectclasses_res = talloc_move(mem_ctx, &ret_res); + return ret; +} + +static struct ldb_dn *find_schema_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx) +{ + const char *rootdse_attrs[] = {"schemaNamingContext", NULL}; + struct ldb_dn *schemadn; + struct ldb_dn *basedn = ldb_dn_explode(mem_ctx, ""); + struct ldb_result *rootdse_res; + int ldb_ret; + if (!basedn) { + return NULL; + } + + /* Search for rootdse */ + ldb_ret = ldb_search(ldb, basedn, LDB_SCOPE_BASE, NULL, rootdse_attrs, &rootdse_res); + if (ldb_ret != LDB_SUCCESS) { + printf("Search failed: %s\n", ldb_errstring(ldb)); + return NULL; + } + + talloc_steal(mem_ctx, rootdse_res); + + if (rootdse_res->count != 1) { + printf("Failed to find rootDSE"); + return NULL; + } + + /* Locate schema */ + schemadn = ldb_msg_find_attr_as_dn(mem_ctx, rootdse_res->msgs[0], "schemaNamingContext"); + if (!schemadn) { + return NULL; + } + + talloc_free(rootdse_res); + return schemadn; +} + +#define IF_NULL_FAIL_RET(x) do { \ + if (!x) { \ + ret.failures++; \ + return ret; \ + } \ + } while (0) + + +static struct schema_conv process_convert(struct ldb_context *ldb, enum convert_target target, FILE *in, FILE *out) +{ + /* Read list of attributes to skip, OIDs to map */ + TALLOC_CTX *mem_ctx = talloc_new(ldb); + char *line; + const char **attrs_skip = NULL; + int num_skip = 0; + struct oid_map { + char *old_oid; + char *new_oid; + } *oid_map = NULL; + int num_maps = 0; + struct ldb_result *attrs_res, *objectclasses_res; + struct ldb_dn *schemadn; + struct schema_conv ret; + + int ldb_ret, i; + + ret.count = 0; + ret.skipped = 0; + ret.failures = 0; + + while ((line = afdgets(fileno(in), mem_ctx, 0))) { + /* Blank Line */ + if (line[0] == '\0') { + continue; + } + /* Comment */ + if (line[0] == '#') { + continue; + } + if (isdigit(line[0])) { + char *p = strchr(line, ':'); + IF_NULL_FAIL_RET(p); + if (!p) { + ret.failures = 1; + return ret; + } + p[0] = '\0'; + p++; + oid_map = talloc_realloc(mem_ctx, oid_map, struct oid_map, num_maps + 2); + trim_string(line, " ", " "); + oid_map[num_maps].old_oid = talloc_move(oid_map, &line); + trim_string(p, " ", " "); + oid_map[num_maps].new_oid = p; + num_maps++; + oid_map[num_maps].old_oid = NULL; + } else { + attrs_skip = talloc_realloc(mem_ctx, attrs_skip, const char *, num_skip + 2); + trim_string(line, " ", " "); + attrs_skip[num_skip] = talloc_move(attrs_skip, &line); + num_skip++; + attrs_skip[num_skip] = NULL; + } + } + + schemadn = find_schema_dn(ldb, mem_ctx); + if (!schemadn) { + printf("Failed to find schema DN: %s\n", ldb_errstring(ldb)); + ret.failures = 1; + return ret; + } + + ldb_ret = fetch_attrs_schema(ldb, schemadn, mem_ctx, &attrs_res); + if (ldb_ret != LDB_SUCCESS) { + printf("Failed to fetch attribute schema: %s\n", ldb_errstring(ldb)); + ret.failures = 1; + return ret; + } + + switch (target) { + case TARGET_OPENLDAP: + break; + case TARGET_FEDORA_DS: + fprintf(out, "dn: cn=schema\n"); + break; + } + + for (i=0; i < attrs_res->count; i++) { + struct ldb_message *msg = attrs_res->msgs[i]; + + const char *name = ldb_msg_find_attr_as_string(msg, "lDAPDisplayName", NULL); + const char *description = ldb_msg_find_attr_as_string(msg, "description", NULL); + const char *oid = ldb_msg_find_attr_as_string(msg, "attributeID", NULL); + const char *syntax = ldb_msg_find_attr_as_string(msg, "attributeSyntax", NULL); + BOOL single_value = ldb_msg_find_attr_as_bool(msg, "isSingleValued", False); + const struct syntax_map *map = find_syntax_map_by_ad_oid(syntax); + char *schema_entry = NULL; + int j; + + /* We have been asked to skip some attributes/objectClasses */ + if (str_list_check_ci(attrs_skip, name)) { + ret.skipped++; + continue; + } + + /* We might have been asked to remap this oid, due to a conflict */ + for (j=0; oid && oid_map[j].old_oid; j++) { + if (strcmp(oid, oid_map[j].old_oid) == 0) { + oid = oid_map[j].new_oid; + break; + } + } + + switch (target) { + case TARGET_OPENLDAP: + schema_entry = talloc_asprintf(mem_ctx, + "attributetype (\n" + " %s\n", oid); + break; + case TARGET_FEDORA_DS: + schema_entry = talloc_asprintf(mem_ctx, + "attributeTypes: (\n" + " %s\n", oid); + break; + } + IF_NULL_FAIL_RET(schema_entry); + + schema_entry = talloc_asprintf_append(schema_entry, + " NAME '%s'\n", name); + IF_NULL_FAIL_RET(schema_entry); + + if (description) { + schema_entry = talloc_asprintf_append(schema_entry, + " DESC %s\n", description); + IF_NULL_FAIL_RET(schema_entry); + } + + if (map) { + const char *syntax_oid; + if (map->equality) { + schema_entry = talloc_asprintf_append(schema_entry, + " EQUALITY %s\n", map->equality); + IF_NULL_FAIL_RET(schema_entry); + } + if (map->substring) { + schema_entry = talloc_asprintf_append(schema_entry, + " SUBSTR %s\n", map->substring); + IF_NULL_FAIL_RET(schema_entry); + } + syntax_oid = map->Standard_OID; + /* We might have been asked to remap this oid, + * due to a conflict, or lack of + * implementation */ + for (j=0; syntax_oid && oid_map[j].old_oid; j++) { + if (strcmp(syntax_oid, oid_map[j].old_oid) == 0) { + syntax_oid = oid_map[j].new_oid; + break; + } + } + schema_entry = talloc_asprintf_append(schema_entry, + " SYNTAX %s\n", syntax_oid); + IF_NULL_FAIL_RET(schema_entry); + } + + if (single_value) { + schema_entry = talloc_asprintf_append(schema_entry, + " SINGLE-VALUE\n"); + IF_NULL_FAIL_RET(schema_entry); + } + + schema_entry = talloc_asprintf_append(schema_entry, + " )"); + + switch (target) { + case TARGET_OPENLDAP: + fprintf(out, "%s\n\n", schema_entry); + break; + case TARGET_FEDORA_DS: + fprintf(out, "%s\n", schema_entry); + break; + } + ret.count++; + } + + ldb_ret = fetch_objectclass_schema(ldb, schemadn, mem_ctx, &objectclasses_res); + if (ldb_ret != LDB_SUCCESS) { + printf("Failed to fetch objectClass schema elements: %s\n", ldb_errstring(ldb)); + ret.failures = 1; + return ret; + } + + for (i=0; i < objectclasses_res->count; i++) { + struct ldb_message *msg = objectclasses_res->msgs[i]; + const char *name = ldb_msg_find_attr_as_string(msg, "lDAPDisplayName", NULL); + const char *description = ldb_msg_find_attr_as_string(msg, "description", NULL); + const char *oid = ldb_msg_find_attr_as_string(msg, "governsID", NULL); + const char *subClassOf = ldb_msg_find_attr_as_string(msg, "subClassOf", NULL); + int objectClassCategory = ldb_msg_find_attr_as_int(msg, "objectClassCategory", 0); + struct ldb_message_element *must = ldb_msg_find_element(msg, "mustContain"); + struct ldb_message_element *sys_must = ldb_msg_find_element(msg, "systemMustContain"); + struct ldb_message_element *may = ldb_msg_find_element(msg, "mayContain"); + struct ldb_message_element *sys_may = ldb_msg_find_element(msg, "systemMayContain"); + char *schema_entry = NULL; + int j; + + /* We have been asked to skip some attributes/objectClasses */ + if (str_list_check_ci(attrs_skip, name)) { + ret.skipped++; + continue; + } + + /* We might have been asked to remap this oid, due to a conflict */ + for (j=0; oid_map[j].old_oid; j++) { + if (strcmp(oid, oid_map[j].old_oid) == 0) { + oid = oid_map[j].new_oid; + break; + } + } + + switch (target) { + case TARGET_OPENLDAP: + schema_entry = talloc_asprintf(mem_ctx, + "objectclass (\n" + " %s\n", oid); + break; + case TARGET_FEDORA_DS: + schema_entry = talloc_asprintf(mem_ctx, + "objectClasses: (\n" + " %s\n", oid); + break; + } + IF_NULL_FAIL_RET(schema_entry); + if (!schema_entry) { + ret.failures++; + break; + } + + schema_entry = talloc_asprintf_append(schema_entry, + " NAME '%s'\n", name); + IF_NULL_FAIL_RET(schema_entry); + + if (!schema_entry) return ret; + + if (description) { + schema_entry = talloc_asprintf_append(schema_entry, + " DESC %s\n", description); + IF_NULL_FAIL_RET(schema_entry); + } + + if (subClassOf) { + schema_entry = talloc_asprintf_append(schema_entry, + " SUP %s\n", subClassOf); + IF_NULL_FAIL_RET(schema_entry); + } + + switch (objectClassCategory) { + case 1: + schema_entry = talloc_asprintf_append(schema_entry, + " STRUCTURAL\n"); + IF_NULL_FAIL_RET(schema_entry); + break; + case 2: + schema_entry = talloc_asprintf_append(schema_entry, + " ABSTRACT\n"); + IF_NULL_FAIL_RET(schema_entry); + break; + case 3: + schema_entry = talloc_asprintf_append(schema_entry, + " AUXILIARY\n"); + IF_NULL_FAIL_RET(schema_entry); + break; + } + +#define APPEND_ATTRS(attributes) \ + do { \ + int k; \ + for (k=0; attributes && k < attributes->num_values; k++) { \ + schema_entry = talloc_asprintf_append(schema_entry, \ + " %s", \ + (const char *)attributes->values[k].data); \ + IF_NULL_FAIL_RET(schema_entry); \ + if (k != (attributes->num_values - 1)) { \ + schema_entry = talloc_asprintf_append(schema_entry, \ + " $"); \ + IF_NULL_FAIL_RET(schema_entry); \ + if (target == TARGET_OPENLDAP && ((k+1)%5 == 0)) { \ + schema_entry = talloc_asprintf_append(schema_entry, \ + "\n "); \ + IF_NULL_FAIL_RET(schema_entry); \ + } \ + } \ + } \ + } while (0) + + if (must || sys_must) { + schema_entry = talloc_asprintf_append(schema_entry, + " MUST ("); + IF_NULL_FAIL_RET(schema_entry); + + APPEND_ATTRS(must); + if (must && sys_must) { + schema_entry = talloc_asprintf_append(schema_entry, \ + " $"); \ + } + APPEND_ATTRS(sys_must); + + schema_entry = talloc_asprintf_append(schema_entry, + " )\n"); + IF_NULL_FAIL_RET(schema_entry); + } + + if (may || sys_may) { + schema_entry = talloc_asprintf_append(schema_entry, + " MAY ("); + IF_NULL_FAIL_RET(schema_entry); + + APPEND_ATTRS(may); + if (may && sys_may) { + schema_entry = talloc_asprintf_append(schema_entry, \ + " $"); \ + } + APPEND_ATTRS(sys_may); + + schema_entry = talloc_asprintf_append(schema_entry, + " )\n"); + IF_NULL_FAIL_RET(schema_entry); + } + + schema_entry = talloc_asprintf_append(schema_entry, + " )"); + + switch (target) { + case TARGET_OPENLDAP: + fprintf(out, "%s\n\n", schema_entry); + break; + case TARGET_FEDORA_DS: + fprintf(out, "%s\n", schema_entry); + break; + } + ret.count++; + } + + return ret; +} + + int main(int argc, const char **argv) +{ + TALLOC_CTX *ctx; + struct ldb_cmdline *options; + FILE *in = stdin; + FILE *out = stdout; + struct ldb_context *ldb; + struct schema_conv ret; + const char *target_str; + enum convert_target target; + + ldb_global_init(); + + ctx = talloc_new(NULL); + ldb = ldb_init(ctx); + + options = ldb_cmdline_process(ldb, argc, argv, usage); + + if (options->input) { + in = fopen(options->input, "r"); + if (!in) { + perror(options->input); + exit(1); + } + } + if (options->output) { + out = fopen(options->output, "w"); + if (!out) { + perror(options->output); + exit(1); + } + } + + target_str = lp_parm_string(-1, "convert", "target"); + + if (!target_str || strcasecmp(target_str, "openldap") == 0) { + target = TARGET_OPENLDAP; + } else if (strcasecmp(target_str, "fedora-ds") == 0) { + target = TARGET_FEDORA_DS; + } else { + printf("Unsupported target: %s\n", target_str); + exit(1); + } + + ret = process_convert(ldb, target, in, out); + + fclose(in); + fclose(out); + + printf("Converted %d records (skipped %d) with %d failures\n", ret.count, ret.skipped, ret.failures); + + return 0; +} diff --git a/source3/lib/ldb/tools/cmdline.c b/source3/lib/ldb/tools/cmdline.c new file mode 100644 index 0000000000..09bb99c096 --- /dev/null +++ b/source3/lib/ldb/tools/cmdline.c @@ -0,0 +1,747 @@ +/* + 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 2 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, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "includes.h" +#include "ldb/include/includes.h" +#include "ldb/tools/cmdline.h" + +#if (_SAMBA_BUILD_ >= 4) +#include "lib/cmdline/popt_common.h" +#include "lib/ldb/samba/ldif_handlers.h" +#include "auth/auth.h" +#include "db_wrap.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 }, + { "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 }, + { "sasl-mechanism", 0, POPT_ARG_STRING, &options.sasl_mechanism, 0, "choose SASL mechanism", "MECHANISM" }, + { "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_VERSION +#endif + { NULL } + }; + + ldb_global_init(); + +#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(); + + if (ldb_set_opaque(ldb, "sessionInfo", system_session(ldb))) { + goto failed; + } + if (ldb_set_opaque(ldb, "credentials", cmdline_credentials)) { + goto failed; + } + ldb_set_utf8_fns(ldb, NULL, wrap_casefold); +#endif + + /* 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; +} + +struct ldb_control **parse_controls(void *mem_ctx, char **control_strings) +{ + int i; + struct ldb_control **ctrl; + + if (control_strings == NULL || control_strings[0] == NULL) + return NULL; + + for (i = 0; control_strings[i]; i++); + + ctrl = talloc_array(mem_ctx, struct ldb_control *, i + 1); + + for (i = 0; control_strings[i]; i++) { + if (strncmp(control_strings[i], "vlv:", 4) == 0) { + struct ldb_vlv_req_control *control; + const char *p; + char attr[1024]; + char ctxid[1024]; + int crit, bc, ac, os, cc, ret; + + attr[0] = '\0'; + ctxid[0] = '\0'; + p = &(control_strings[i][4]); + ret = sscanf(p, "%d:%d:%d:%d:%d:%1023[^$]", &crit, &bc, &ac, &os, &cc, ctxid); + if (ret < 5) { + ret = sscanf(p, "%d:%d:%d:%1023[^:]:%1023[^$]", &crit, &bc, &ac, attr, ctxid); + } + + if ((ret < 4) || (crit < 0) || (crit > 1)) { + fprintf(stderr, "invalid server_sort control syntax\n"); + fprintf(stderr, " syntax: crit(b):bc(n):ac(n):<os(n):cc(n)|attr(s)>[:ctxid(o)]\n"); + fprintf(stderr, " note: b = boolean, n = number, s = string, o = b64 binary blob\n"); + return NULL; + } + ctrl[i] = talloc(ctrl, struct ldb_control); + ctrl[i]->oid = LDB_CONTROL_VLV_REQ_OID; + ctrl[i]->critical = crit; + control = talloc(ctrl[i], struct ldb_vlv_req_control); + control->beforeCount = bc; + control->afterCount = ac; + if (attr[0]) { + control->type = 1; + control->match.gtOrEq.value = talloc_strdup(control, attr); + control->match.gtOrEq.value_len = strlen(attr); + } else { + control->type = 0; + control->match.byOffset.offset = os; + control->match.byOffset.contentCount = cc; + } + if (ctxid[0]) { + control->ctxid_len = ldb_base64_decode(ctxid); + control->contextId = (char *)talloc_memdup(control, ctxid, control->ctxid_len); + } else { + control->ctxid_len = 0; + control->contextId = NULL; + } + ctrl[i]->data = control; + + continue; + } + + if (strncmp(control_strings[i], "dirsync:", 8) == 0) { + struct ldb_dirsync_control *control; + const char *p; + char cookie[1024]; + int crit, flags, max_attrs, ret; + + cookie[0] = '\0'; + p = &(control_strings[i][8]); + ret = sscanf(p, "%d:%d:%d:%1023[^$]", &crit, &flags, &max_attrs, cookie); + + if ((ret < 3) || (crit < 0) || (crit > 1) || (flags < 0) || (max_attrs < 0)) { + fprintf(stderr, "invalid dirsync control syntax\n"); + fprintf(stderr, " syntax: crit(b):flags(n):max_attrs(n)[:cookie(o)]\n"); + fprintf(stderr, " note: b = boolean, n = number, o = b64 binary blob\n"); + return NULL; + } + + /* w2k3 seems to ignore the parameter, + * but w2k sends a wrong cookie when this value is to small + * this would cause looping forever, while getting + * the same data and same cookie forever + */ + if (max_attrs == 0) max_attrs = 0x0FFFFFFF; + + ctrl[i] = talloc(ctrl, struct ldb_control); + ctrl[i]->oid = LDB_CONTROL_DIRSYNC_OID; + ctrl[i]->critical = crit; + control = talloc(ctrl[i], struct ldb_dirsync_control); + control->flags = flags; + control->max_attributes = max_attrs; + if (*cookie) { + control->cookie_len = ldb_base64_decode(cookie); + control->cookie = (char *)talloc_memdup(control, cookie, control->cookie_len); + } else { + control->cookie = NULL; + control->cookie_len = 0; + } + ctrl[i]->data = control; + + continue; + } + + if (strncmp(control_strings[i], "asq:", 4) == 0) { + struct ldb_asq_control *control; + const char *p; + char attr[256]; + int crit, ret; + + attr[0] = '\0'; + p = &(control_strings[i][4]); + ret = sscanf(p, "%d:%255[^$]", &crit, attr); + if ((ret != 2) || (crit < 0) || (crit > 1) || (attr[0] == '\0')) { + fprintf(stderr, "invalid asq control syntax\n"); + fprintf(stderr, " syntax: crit(b):attr(s)\n"); + fprintf(stderr, " note: b = boolean, s = string\n"); + return NULL; + } + + ctrl[i] = talloc(ctrl, struct ldb_control); + ctrl[i]->oid = LDB_CONTROL_ASQ_OID; + ctrl[i]->critical = crit; + control = talloc(ctrl[i], struct ldb_asq_control); + control->request = 1; + control->source_attribute = talloc_strdup(control, attr); + control->src_attr_len = strlen(attr); + ctrl[i]->data = control; + + continue; + } + + if (strncmp(control_strings[i], "extended_dn:", 12) == 0) { + struct ldb_extended_dn_control *control; + const char *p; + int crit, type, ret; + + p = &(control_strings[i][12]); + ret = sscanf(p, "%d:%d", &crit, &type); + if ((ret != 2) || (crit < 0) || (crit > 1) || (type < 0) || (type > 1)) { + fprintf(stderr, "invalid extended_dn control syntax\n"); + fprintf(stderr, " syntax: crit(b):type(b)\n"); + fprintf(stderr, " note: b = boolean\n"); + return NULL; + } + + ctrl[i] = talloc(ctrl, struct ldb_control); + ctrl[i]->oid = LDB_CONTROL_EXTENDED_DN_OID; + ctrl[i]->critical = crit; + control = talloc(ctrl[i], struct ldb_extended_dn_control); + control->type = type; + ctrl[i]->data = control; + + continue; + } + + if (strncmp(control_strings[i], "sd_flags:", 9) == 0) { + struct ldb_sd_flags_control *control; + const char *p; + int crit, ret; + unsigned secinfo_flags; + + p = &(control_strings[i][9]); + ret = sscanf(p, "%d:%u", &crit, &secinfo_flags); + if ((ret != 2) || (crit < 0) || (crit > 1) || (secinfo_flags < 0) || (secinfo_flags > 0xF)) { + fprintf(stderr, "invalid sd_flags control syntax\n"); + fprintf(stderr, " syntax: crit(b):secinfo_flags(n)\n"); + fprintf(stderr, " note: b = boolean, n = number\n"); + return NULL; + } + + ctrl[i] = talloc(ctrl, struct ldb_control); + ctrl[i]->oid = LDB_CONTROL_SD_FLAGS_OID; + ctrl[i]->critical = crit; + control = talloc(ctrl[i], struct ldb_sd_flags_control); + control->secinfo_flags = secinfo_flags; + ctrl[i]->data = control; + + continue; + } + + if (strncmp(control_strings[i], "search_options:", 15) == 0) { + struct ldb_search_options_control *control; + const char *p; + int crit, ret; + unsigned search_options; + + p = &(control_strings[i][15]); + ret = sscanf(p, "%d:%u", &crit, &search_options); + if ((ret != 2) || (crit < 0) || (crit > 1) || (search_options < 0) || (search_options > 0xF)) { + fprintf(stderr, "invalid search_options control syntax\n"); + fprintf(stderr, " syntax: crit(b):search_options(n)\n"); + fprintf(stderr, " note: b = boolean, n = number\n"); + return NULL; + } + + ctrl[i] = talloc(ctrl, struct ldb_control); + ctrl[i]->oid = LDB_CONTROL_SEARCH_OPTIONS_OID; + ctrl[i]->critical = crit; + control = talloc(ctrl[i], struct ldb_search_options_control); + control->search_options = search_options; + ctrl[i]->data = control; + + continue; + } + + if (strncmp(control_strings[i], "domain_scope:", 13) == 0) { + const char *p; + int crit, ret; + + p = &(control_strings[i][13]); + ret = sscanf(p, "%d", &crit); + if ((ret != 1) || (crit < 0) || (crit > 1)) { + fprintf(stderr, "invalid domain_scope control syntax\n"); + fprintf(stderr, " syntax: crit(b)\n"); + fprintf(stderr, " note: b = boolean\n"); + return NULL; + } + + ctrl[i] = talloc(ctrl, struct ldb_control); + ctrl[i]->oid = LDB_CONTROL_DOMAIN_SCOPE_OID; + ctrl[i]->critical = crit; + ctrl[i]->data = NULL; + + continue; + } + + if (strncmp(control_strings[i], "paged_results:", 14) == 0) { + struct ldb_paged_control *control; + const char *p; + int crit, size, ret; + + p = &(control_strings[i][14]); + ret = sscanf(p, "%d:%d", &crit, &size); + + if ((ret != 2) || (crit < 0) || (crit > 1) || (size < 0)) { + fprintf(stderr, "invalid paged_results control syntax\n"); + fprintf(stderr, " syntax: crit(b):size(n)\n"); + fprintf(stderr, " note: b = boolean, n = number\n"); + return NULL; + } + + ctrl[i] = talloc(ctrl, struct ldb_control); + ctrl[i]->oid = LDB_CONTROL_PAGED_RESULTS_OID; + ctrl[i]->critical = crit; + control = talloc(ctrl[i], struct ldb_paged_control); + control->size = size; + control->cookie = NULL; + control->cookie_len = 0; + ctrl[i]->data = control; + + continue; + } + + if (strncmp(control_strings[i], "server_sort:", 12) == 0) { + struct ldb_server_sort_control **control; + const char *p; + char attr[256]; + char rule[128]; + int crit, rev, ret; + + attr[0] = '\0'; + rule[0] = '\0'; + p = &(control_strings[i][12]); + ret = sscanf(p, "%d:%d:%255[^:]:%127[^:]", &crit, &rev, attr, rule); + if ((ret < 3) || (crit < 0) || (crit > 1) || (rev < 0 ) || (rev > 1) ||attr[0] == '\0') { + fprintf(stderr, "invalid server_sort control syntax\n"); + fprintf(stderr, " syntax: crit(b):rev(b):attr(s)[:rule(s)]\n"); + fprintf(stderr, " note: b = boolean, s = string\n"); + return NULL; + } + ctrl[i] = talloc(ctrl, struct ldb_control); + ctrl[i]->oid = LDB_CONTROL_SERVER_SORT_OID; + ctrl[i]->critical = crit; + control = talloc_array(ctrl[i], struct ldb_server_sort_control *, 2); + control[0] = talloc(control, struct ldb_server_sort_control); + control[0]->attributeName = talloc_strdup(control, attr); + if (rule[0]) + control[0]->orderingRule = talloc_strdup(control, rule); + else + control[0]->orderingRule = NULL; + control[0]->reverse = rev; + control[1] = NULL; + ctrl[i]->data = control; + + continue; + } + + if (strncmp(control_strings[i], "notification:", 13) == 0) { + const char *p; + int crit, ret; + + p = &(control_strings[i][13]); + ret = sscanf(p, "%d", &crit); + if ((ret != 1) || (crit < 0) || (crit > 1)) { + fprintf(stderr, "invalid notification control syntax\n"); + fprintf(stderr, " syntax: crit(b)\n"); + fprintf(stderr, " note: b = boolean\n"); + return NULL; + } + + ctrl[i] = talloc(ctrl, struct ldb_control); + ctrl[i]->oid = LDB_CONTROL_NOTIFICATION_OID; + ctrl[i]->critical = crit; + ctrl[i]->data = NULL; + + continue; + } + + if (strncmp(control_strings[i], "show_deleted:", 13) == 0) { + const char *p; + int crit, ret; + + p = &(control_strings[i][13]); + ret = sscanf(p, "%d", &crit); + if ((ret != 1) || (crit < 0) || (crit > 1)) { + fprintf(stderr, "invalid show_deleted control syntax\n"); + fprintf(stderr, " syntax: crit(b)\n"); + fprintf(stderr, " note: b = boolean\n"); + return NULL; + } + + ctrl[i] = talloc(ctrl, struct ldb_control); + ctrl[i]->oid = LDB_CONTROL_SHOW_DELETED_OID; + ctrl[i]->critical = crit; + ctrl[i]->data = NULL; + + continue; + } + + if (strncmp(control_strings[i], "permissive_modify:", 18) == 0) { + const char *p; + int crit, ret; + + p = &(control_strings[i][18]); + ret = sscanf(p, "%d", &crit); + if ((ret != 1) || (crit < 0) || (crit > 1)) { + fprintf(stderr, "invalid permissive_modify control syntax\n"); + fprintf(stderr, " syntax: crit(b)\n"); + fprintf(stderr, " note: b = boolean\n"); + return NULL; + } + + ctrl[i] = talloc(ctrl, struct ldb_control); + ctrl[i]->oid = LDB_CONTROL_PERMISSIVE_MODIFY_OID; + ctrl[i]->critical = crit; + ctrl[i]->data = NULL; + + continue; + } + + /* no controls matched, throw an error */ + fprintf(stderr, "Invalid control name: '%s'\n", control_strings[i]); + return NULL; + } + + ctrl[i] = NULL; + + return ctrl; +} + + +/* 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/source3/lib/ldb/tools/cmdline.h b/source3/lib/ldb/tools/cmdline.h new file mode 100644 index 0000000000..0855f77575 --- /dev/null +++ b/source3/lib/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 2 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, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <popt.h> + +struct ldb_cmdline { + const char *url; + enum ldb_scope scope; + const char *basedn; + 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/source3/lib/ldb/tools/convert.c b/source3/lib/ldb/tools/convert.c new file mode 100644 index 0000000000..2320970030 --- /dev/null +++ b/source3/lib/ldb/tools/convert.c @@ -0,0 +1,166 @@ +/* + ldb database library + + Copyright (C) Simo Sorce 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 2 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, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "convert.h" +#include "includes.h" +#include "ldb/include/includes.h" + +/* Shared map for converting syntax between formats */ +static const struct syntax_map syntax_map[] = { + { + .Standard_OID = "1.3.6.1.4.1.1466.115.121.1.12", + .AD_OID = "2.5.5.1", + .equality = "distinguishedNameMatch", + .comment = "Object(DS-DN) == a DN" + }, + { + .Standard_OID = "1.3.6.1.4.1.1466.115.121.1.38", + .AD_OID = "2.5.5.2", + .equality = "objectIdentifierMatch", + .comment = "OID String" + }, + { + .Standard_OID = "1.2.840.113556.1.4.905", + .AD_OID = "2.5.5.4", + .equality = "caseIgnoreMatch", + .substring = "caseIgnoreSubstringsMatch", + .comment = "Case Insensitive String" + }, + { + .Standard_OID = "1.3.6.1.4.1.1466.115.121.1.26", + .AD_OID = "2.5.5.5", + .equality = "caseExactIA5Match", + .comment = "Printable String" + }, + { + .Standard_OID = "1.3.6.1.4.1.1466.115.121.1.36", + .AD_OID = "2.5.5.6", + .equality = "numericStringMatch", + .substring = "numericStringSubstringsMatch", + .comment = "Numeric String" + }, + { + .Standard_OID = "1.2.840.113556.1.4.903", + .AD_OID = "2.5.5.7", + .equality = "distinguishedNameMatch", + .comment = "OctetString: Binary+DN" + }, + { + .Standard_OID = "1.3.6.1.4.1.1466.115.121.1.7", + .AD_OID = "2.5.5.8", + .equality = "booleanMatch", + .comment = "Boolean" + }, + { + .Standard_OID = "1.3.6.1.4.1.1466.115.121.1.27", + .AD_OID = "2.5.5.9", + .equality = "integerMatch", + .comment = "Integer" + }, + { + .Standard_OID = "1.3.6.1.4.1.1466.115.121.1.40", + .AD_OID = "2.5.5.10", + .equality = "octetStringMatch", + .comment = "Octet String" + }, + { + .Standard_OID = "1.3.6.1.4.1.1466.115.121.1.24", + .AD_OID = "2.5.5.11", + .equality = "generalizedTimeMatch", + .comment = "Generalized Time" + }, + { + .Standard_OID = "1.3.6.1.4.1.1466.115.121.1.53", + .AD_OID = "2.5.5.11", + .equality = "generalizedTimeMatch", + .comment = "UTC Time" + }, + { + .Standard_OID = "1.3.6.1.4.1.1466.115.121.1.15", + .AD_OID = "2.5.5.12", + .equality = "caseIgnoreMatch", + .substring = "caseIgnoreSubstringsMatch", + .comment = "Directory String" + }, + { + .Standard_OID = "1.3.6.1.4.1.1466.115.121.1.43", + .AD_OID = "2.5.5.13", + .comment = "Presentation Address" + }, + { + .Standard_OID = "Not Found Yet", + .AD_OID = "2.5.5.14", + .equality = "distinguishedNameMatch", + .comment = "OctetString: String+DN" + }, + { + .Standard_OID = "1.2.840.113556.1.4.907", + .AD_OID = "2.5.5.15", + .equality = "octetStringMatch", + .comment = "NT Security Descriptor" + }, + { + .Standard_OID = "1.2.840.113556.1.4.906", + .AD_OID = "2.5.5.16", + .equality = "integerMatch", + .comment = "Large Integer" + }, + { + .Standard_OID = "1.3.6.1.4.1.1466.115.121.1.40", + .AD_OID = "2.5.5.17", + .equality = "octetStringMatch", + .comment = "Octet String - Security Identifier (SID)" + }, + { + .Standard_OID = "1.3.6.1.4.1.1466.115.121.1.26", + .AD_OID = "2.5.5.5", + .equality = "caseExactIA5Match", + .comment = "IA5 String" + }, + { .Standard_OID = NULL + } +}; + + +const struct syntax_map *find_syntax_map_by_ad_oid(const char *ad_oid) +{ + int i; + for (i=0; syntax_map[i].Standard_OID; i++) { + if (strcasecmp(ad_oid, syntax_map[i].AD_OID) == 0) { + return &syntax_map[i]; + } + } + return NULL; +} + +const struct syntax_map *find_syntax_map_by_standard_oid(const char *standard_oid) +{ + int i; + for (i=0; syntax_map[i].Standard_OID; i++) { + if (strcasecmp(standard_oid, syntax_map[i].Standard_OID) == 0) { + return &syntax_map[i]; + } + } + return NULL; +} diff --git a/source3/lib/ldb/tools/convert.h b/source3/lib/ldb/tools/convert.h new file mode 100644 index 0000000000..de379343a6 --- /dev/null +++ b/source3/lib/ldb/tools/convert.h @@ -0,0 +1,10 @@ +struct syntax_map { + const char *Standard_OID; + const char *AD_OID; + const char *equality; + const char *substring; + const char *comment; +}; + +const struct syntax_map *find_syntax_map_by_ad_oid(const char *ad_oid); +const struct syntax_map *find_syntax_map_by_standard_oid(const char *standard_oid); diff --git a/source3/lib/ldb/tools/ldbadd.c b/source3/lib/ldb/tools/ldbadd.c new file mode 100644 index 0000000000..6a0f510244 --- /dev/null +++ b/source3/lib/ldb/tools/ldbadd.c @@ -0,0 +1,120 @@ +/* + 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 2 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, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* + * Name: ldb + * + * Component: ldbadd + * + * Description: utility to add records - modelled on ldapadd + * + * Author: Andrew Tridgell + */ + +#include "includes.h" +#include "ldb/include/includes.h" +#include "ldb/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) +{ + struct ldb_ldif *ldif; + int ret, count=0; + + 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_linearize(ldb, ldif->msg->dn)); + failures++; + } else { + count++; + } + ldb_ldif_read_free(ldb, ldif); + } + + return count; +} + + + +int main(int argc, const char **argv) +{ + struct ldb_context *ldb; + int i, count=0; + struct ldb_cmdline *options; + + ldb_global_init(); + + ldb = ldb_init(NULL); + + options = ldb_cmdline_process(ldb, argc, argv, usage); + + if (options->argc == 0) { + count += process_file(ldb, stdin); + } 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); + } + count += process_file(ldb, f); + fclose(f); + } + } + + talloc_free(ldb); + + printf("Added %d records with %d failures\n", count, failures); + + return 0; +} diff --git a/source3/lib/ldb/tools/ldbdel.c b/source3/lib/ldb/tools/ldbdel.c new file mode 100644 index 0000000000..aee911efaf --- /dev/null +++ b/source3/lib/ldb/tools/ldbdel.c @@ -0,0 +1,119 @@ +/* + 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 2 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, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* + * Name: ldb + * + * Component: ldbdel + * + * Description: utility to delete records - modelled on ldapdelete + * + * Author: Andrew Tridgell + */ + +#include "includes.h" +#include "ldb/include/includes.h" +#include "ldb/tools/cmdline.h" + +static int ldb_delete_recursive(struct ldb_context *ldb, const 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, i; + struct ldb_cmdline *options; + + ldb_global_init(); + + ldb = ldb_init(NULL); + + options = ldb_cmdline_process(ldb, argc, argv, usage); + + if (options->argc < 1) { + usage(); + exit(1); + } + + for (i=0;i<options->argc;i++) { + const struct ldb_dn *dn; + + dn = ldb_dn_explode(ldb, options->argv[i]); + if (dn == NULL) { + 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_linearize(ldb, dn), + ldb_errstring(ldb)); + } + } + + talloc_free(ldb); + + return 0; +} diff --git a/source3/lib/ldb/tools/ldbedit.c b/source3/lib/ldb/tools/ldbedit.c new file mode 100644 index 0000000000..17ade152b7 --- /dev/null +++ b/source3/lib/ldb/tools/ldbedit.c @@ -0,0 +1,333 @@ +/* + 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 2 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, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* + * Name: ldb + * + * Component: ldbedit + * + * Description: utility for ldb database editing + * + * Author: Andrew Tridgell + */ + +#include "includes.h" +#include "ldb/include/includes.h" +#include "ldb/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_linearize(ldb, 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, + const struct ldb_dn *dn) +{ + int i; + for (i=0;i<count;i++) { + if (ldb_dn_compare(ldb, 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_linearize(ldb, 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_linearize(ldb, 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_global_init(); + + ldb = ldb_init(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_explode(ldb, options->basedn); + if (basedn == NULL) { + 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/source3/lib/ldb/tools/ldbmodify.c b/source3/lib/ldb/tools/ldbmodify.c new file mode 100644 index 0000000000..24f9386266 --- /dev/null +++ b/source3/lib/ldb/tools/ldbmodify.c @@ -0,0 +1,124 @@ +/* + 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 2 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, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* + * Name: ldb + * + * Component: ldbmodify + * + * Description: utility to modify records - modelled on ldapmodify + * + * Author: Andrew Tridgell + */ + +#include "includes.h" +#include "ldb/include/includes.h" +#include "ldb/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) +{ + struct ldb_ldif *ldif; + int ret = -1, count = 0; + + 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 != 0) { + fprintf(stderr, "ERR: \"%s\" on DN %s\n", + ldb_errstring(ldb), ldb_dn_linearize(ldb, ldif->msg->dn)); + failures++; + } else { + count++; + } + ldb_ldif_read_free(ldb, ldif); + } + + return count; +} + +int main(int argc, const char **argv) +{ + struct ldb_context *ldb; + int count=0; + int i; + struct ldb_cmdline *options; + + ldb_global_init(); + + ldb = ldb_init(NULL); + + options = ldb_cmdline_process(ldb, argc, argv, usage); + + if (options->argc == 0) { + count += process_file(ldb, stdin); + } 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); + } + count += process_file(ldb, f); + } + } + + talloc_free(ldb); + + printf("Modified %d records with %d failures\n", count, failures); + + if (failures != 0) { + return -1; + } + + return 0; +} diff --git a/source3/lib/ldb/tools/ldbrename.c b/source3/lib/ldb/tools/ldbrename.c new file mode 100644 index 0000000000..9c0870721d --- /dev/null +++ b/source3/lib/ldb/tools/ldbrename.c @@ -0,0 +1,85 @@ +/* + 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 2 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, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* + * Name: ldb + * + * Component: ldbrename + * + * Description: utility to rename records - modelled on ldapmodrdn + * + * Author: Andrew Tridgell + * Author: Stefan Metzmacher + */ + +#include "includes.h" +#include "ldb/include/includes.h" +#include "ldb/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; + const struct ldb_dn *dn1, *dn2; + + ldb_global_init(); + + ldb = ldb_init(NULL); + + options = ldb_cmdline_process(ldb, argc, argv, usage); + + if (options->argc < 2) { + usage(); + } + + dn1 = ldb_dn_explode(ldb, options->argv[0]); + dn2 = ldb_dn_explode(ldb, options->argv[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/source3/lib/ldb/tools/ldbsearch.c b/source3/lib/ldb/tools/ldbsearch.c new file mode 100644 index 0000000000..23d8115c20 --- /dev/null +++ b/source3/lib/ldb/tools/ldbsearch.c @@ -0,0 +1,321 @@ +/* + 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 2 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, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* + * Name: ldb + * + * Component: ldbsearch + * + * Description: utility for ldb search - modelled on ldapsearch + * + * Author: Andrew Tridgell + */ + +#include "includes.h" +#include "ldb/include/includes.h" +#include "ldb/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) +{ + struct ldb_context *ldb = talloc_get_type(opaque, struct ldb_context); + return ldb_dn_compare(ldb, (*el1)->dn, (*el2)->dn); +} + +struct search_context { + struct ldb_control **req_ctrls; + + int sort; + int num_stored; + struct ldb_message **store; + 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 + 2); + if (!sctx->refs_store) { + fprintf(stderr, "talloc_realloc failed while storing referrals\n"); + return -1; + } + + sctx->refs_store[sctx->refs] = talloc_move(sctx->refs_store, &referral); + sctx->refs++; + sctx->refs_store[sctx->refs] = 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, + const 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->store = NULL; + sctx->req_ctrls = parse_controls(ldb, options->controls); + if (options->controls != NULL && sctx->req_ctrls== NULL) 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(ldb, 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) { + int i; + + ldb_qsort(sctx->store, ret, sizeof(struct ldb_message *), + ldb, (ldb_qsort_cmp_fn_t)do_compare_msg); + + if (ret != 0) { + fprintf(stderr, "An error occurred while sorting messages\n"); + exit(1); + } + + for (i = 0; i < sctx->num_stored; i++) { + display_message(ldb, sctx->store[i], sctx); + } + + for (i = 0; i < sctx->refs; 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_global_init(); + + ldb = ldb_init(NULL); + + 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_explode(ldb, options->basedn); + if (basedn == NULL) { + 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/source3/lib/ldb/tools/ldbtest.c b/source3/lib/ldb/tools/ldbtest.c new file mode 100644 index 0000000000..6cc8dfe19b --- /dev/null +++ b/source3/lib/ldb/tools/ldbtest.c @@ -0,0 +1,410 @@ +/* + 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 2 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, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* + * Name: ldb + * + * Component: ldbtest + * + * Description: utility to test ldb + * + * Author: Andrew Tridgell + */ + +#include "includes.h" +#include "ldb/include/includes.h" +#include "ldb/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, + const 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_build_child(tmp_ctx, "cn", name, basedn); + 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); + 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, + const 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_build_child(tmp_ctx, "cn", name, basedn); + + 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, + const 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_build_child(name, "cn", name, basedn); + + printf("Deleting uid Test%d\r", i); + fflush(stdout); + + if (ldb_delete(ldb, dn) != 0) { + printf("Delete of %s failed - %s\n", ldb_dn_linearize(ldb, 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_explode(ldb, options->basedn); + + 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_explode(NULL, "@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_linearize(*ldb, msg->dn), ldb_errstring(*ldb)); + exit(1); + } + + basedn = ldb_dn_explode(NULL, options->basedn); + + memset(msg, 0, sizeof(*msg)); + msg->dn = ldb_dn_build_child(msg, "cn", "test", basedn); + 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_linearize(*ldb, 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); + + ret = ldb_connect(*ldb, options->url, flags, NULL); + if (ret != 0) { + printf("failed to connect to %s\n", options->url); + exit(1); + } + + 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); + } + + 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_global_init(); + + ldb = ldb_init(mem_ctx); + + 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; +} diff --git a/source3/lib/ldb/tools/oLschema2ldif.c b/source3/lib/ldb/tools/oLschema2ldif.c new file mode 100644 index 0000000000..a9e157e323 --- /dev/null +++ b/source3/lib/ldb/tools/oLschema2ldif.c @@ -0,0 +1,608 @@ +/* + ldb database library + + Copyright (C) Simo Sorce 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 2 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, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* + * Name: ldb + * + * Component: oLschema2ldif + * + * Description: utility to convert an OpenLDAP schema into AD LDIF + * + * Author: Simo Sorce + */ + +#include "includes.h" +#include "ldb/include/includes.h" +#include "ldb/tools/cmdline.h" +#include "ldb/tools/convert.h" + +#define SCHEMA_UNKNOWN 0 +#define SCHEMA_NAME 1 +#define SCHEMA_SUP 2 +#define SCHEMA_STRUCTURAL 3 +#define SCHEMA_ABSTRACT 4 +#define SCHEMA_AUXILIARY 5 +#define SCHEMA_MUST 6 +#define SCHEMA_MAY 7 +#define SCHEMA_SINGLE_VALUE 8 +#define SCHEMA_EQUALITY 9 +#define SCHEMA_ORDERING 10 +#define SCHEMA_SUBSTR 11 +#define SCHEMA_SYNTAX 12 +#define SCHEMA_DESC 13 + +struct schema_conv { + int count; + int failures; +}; + +struct schema_token { + int type; + char *value; +}; + +struct ldb_context *ldb_ctx; +struct ldb_dn *basedn; + +static int check_braces(const char *string) +{ + int b; + char *c; + + b = 0; + if ((c = strchr(string, '(')) == NULL) { + return -1; + } + b++; + c++; + while (b) { + c = strpbrk(c, "()"); + if (c == NULL) return 1; + if (*c == '(') b++; + if (*c == ')') b--; + c++; + } + return 0; +} + +static char *skip_spaces(char *string) { + return (string + strspn(string, " \t\n")); +} + +static int add_multi_string(struct ldb_message *msg, const char *attr, char *values) +{ + char *c; + char *s; + int n; + + c = skip_spaces(values); + while (*c) { + n = strcspn(c, " \t$"); + s = talloc_strndup(msg, c, n); + if (ldb_msg_add_string(msg, attr, s) != 0) { + return -1; + } + c += n; + c += strspn(c, " \t$"); + } + + return 0; +} + +#define MSG_ADD_STRING(a, v) do { if (ldb_msg_add_string(msg, a, v) != 0) goto failed; } while(0) +#define MSG_ADD_M_STRING(a, v) do { if (add_multi_string(msg, a, v) != 0) goto failed; } while(0) + +static char *get_def_value(TALLOC_CTX *ctx, char **string) +{ + char *c = *string; + char *value; + int n; + + if (*c == '\'') { + c++; + n = strcspn(c, "\'"); + value = talloc_strndup(ctx, c, n); + c += n; + c++; /* skip closing \' */ + } else { + n = strcspn(c, " \t\n"); + value = talloc_strndup(ctx, c, n); + c += n; + } + *string = c; + + return value; +} + +static struct schema_token *get_next_schema_token(TALLOC_CTX *ctx, char **string) +{ + char *c = skip_spaces(*string); + char *type; + struct schema_token *token; + int n; + + token = talloc(ctx, struct schema_token); + + n = strcspn(c, " \t\n"); + type = talloc_strndup(token, c, n); + c += n; + c = skip_spaces(c); + + if (strcasecmp("NAME", type) == 0) { + talloc_free(type); + token->type = SCHEMA_NAME; + /* we do not support aliases so we get only the first name given and skip others */ + if (*c == '(') { + char *s = strchr(c, ')'); + if (s == NULL) return NULL; + s = skip_spaces(s); + *string = s; + + c++; + c = skip_spaces(c); + } + + token->value = get_def_value(ctx, &c); + + if (*string < c) { /* single name */ + c = skip_spaces(c); + *string = c; + } + return token; + } + if (strcasecmp("SUP", type) == 0) { + talloc_free(type); + token->type = SCHEMA_SUP; + + if (*c == '(') { + c++; + n = strcspn(c, ")"); + token->value = talloc_strndup(ctx, c, n); + c += n; + c++; + } else { + token->value = get_def_value(ctx, &c); + } + + c = skip_spaces(c); + *string = c; + return token; + } + + if (strcasecmp("STRUCTURAL", type) == 0) { + talloc_free(type); + token->type = SCHEMA_STRUCTURAL; + *string = c; + return token; + } + + if (strcasecmp("ABSTRACT", type) == 0) { + talloc_free(type); + token->type = SCHEMA_ABSTRACT; + *string = c; + return token; + } + + if (strcasecmp("AUXILIARY", type) == 0) { + talloc_free(type); + token->type = SCHEMA_AUXILIARY; + *string = c; + return token; + } + + if (strcasecmp("MUST", type) == 0) { + talloc_free(type); + token->type = SCHEMA_MUST; + + if (*c == '(') { + c++; + n = strcspn(c, ")"); + token->value = talloc_strndup(ctx, c, n); + c += n; + c++; + } else { + token->value = get_def_value(ctx, &c); + } + + c = skip_spaces(c); + *string = c; + return token; + } + + if (strcasecmp("MAY", type) == 0) { + talloc_free(type); + token->type = SCHEMA_MAY; + + if (*c == '(') { + c++; + n = strcspn(c, ")"); + token->value = talloc_strndup(ctx, c, n); + c += n; + c++; + } else { + token->value = get_def_value(ctx, &c); + } + + c = skip_spaces(c); + *string = c; + return token; + } + + if (strcasecmp("SINGLE-VALUE", type) == 0) { + talloc_free(type); + token->type = SCHEMA_SINGLE_VALUE; + *string = c; + return token; + } + + if (strcasecmp("EQUALITY", type) == 0) { + talloc_free(type); + token->type = SCHEMA_EQUALITY; + + token->value = get_def_value(ctx, &c); + + c = skip_spaces(c); + *string = c; + return token; + } + + if (strcasecmp("ORDERING", type) == 0) { + talloc_free(type); + token->type = SCHEMA_ORDERING; + + token->value = get_def_value(ctx, &c); + + c = skip_spaces(c); + *string = c; + return token; + } + + if (strcasecmp("SUBSTR", type) == 0) { + talloc_free(type); + token->type = SCHEMA_SUBSTR; + + token->value = get_def_value(ctx, &c); + + c = skip_spaces(c); + *string = c; + return token; + } + + if (strcasecmp("SYNTAX", type) == 0) { + talloc_free(type); + token->type = SCHEMA_SYNTAX; + + token->value = get_def_value(ctx, &c); + + c = skip_spaces(c); + *string = c; + return token; + } + + if (strcasecmp("DESC", type) == 0) { + talloc_free(type); + token->type = SCHEMA_DESC; + + token->value = get_def_value(ctx, &c); + + c = skip_spaces(c); + *string = c; + return token; + } + + token->type = SCHEMA_UNKNOWN; + token->value = type; + if (*c == ')') { + *string = c; + return token; + } + if (*c == '\'') { + c = strchr(++c, '\''); + c++; + } else { + c += strcspn(c, " \t\n"); + } + c = skip_spaces(c); + *string = c; + + return token; +} + +static struct ldb_message *process_entry(TALLOC_CTX *mem_ctx, const char *entry) +{ + TALLOC_CTX *ctx; + struct ldb_message *msg; + struct schema_token *token; + char *c, *s; + int n; + + ctx = talloc_new(mem_ctx); + msg = ldb_msg_new(ctx); + + ldb_msg_add_string(msg, "objectClass", "top"); + + c = talloc_strdup(ctx, entry); + if (!c) return NULL; + + c = skip_spaces(c); + + switch (*c) { + case 'a': + if (strncmp(c, "attributetype", 13) == 0) { + c += 13; + MSG_ADD_STRING("objectClass", "attributeSchema"); + break; + } + goto failed; + case 'o': + if (strncmp(c, "objectclass", 11) == 0) { + c += 11; + MSG_ADD_STRING("objectClass", "classSchema"); + break; + } + goto failed; + default: + goto failed; + } + + c = strchr(c, '('); + if (c == NULL) goto failed; + c++; + + c = skip_spaces(c); + + /* get attributeID */ + n = strcspn(c, " \t"); + s = talloc_strndup(msg, c, n); + MSG_ADD_STRING("attributeID", s); + c += n; + c = skip_spaces(c); + + while (*c != ')') { + token = get_next_schema_token(msg, &c); + if (!token) goto failed; + + switch (token->type) { + case SCHEMA_NAME: + MSG_ADD_STRING("cn", token->value); + MSG_ADD_STRING("name", token->value); + MSG_ADD_STRING("lDAPDisplayName", token->value); + msg->dn = ldb_dn_string_compose(msg, basedn, + "CN=%s,CN=Schema,CN=Configuration", + token->value); + break; + + case SCHEMA_SUP: + MSG_ADD_M_STRING("subClassOf", token->value); + break; + + case SCHEMA_STRUCTURAL: + MSG_ADD_STRING("objectClassCategory", "1"); + break; + + case SCHEMA_ABSTRACT: + MSG_ADD_STRING("objectClassCategory", "2"); + break; + + case SCHEMA_AUXILIARY: + MSG_ADD_STRING("objectClassCategory", "3"); + break; + + case SCHEMA_MUST: + MSG_ADD_M_STRING("mustContain", token->value); + break; + + case SCHEMA_MAY: + MSG_ADD_M_STRING("mayContain", token->value); + break; + + case SCHEMA_SINGLE_VALUE: + MSG_ADD_STRING("isSingleValued", "TRUE"); + break; + + case SCHEMA_EQUALITY: + /* TODO */ + break; + + case SCHEMA_ORDERING: + /* TODO */ + break; + + case SCHEMA_SUBSTR: + /* TODO */ + break; + + case SCHEMA_SYNTAX: + { + const struct syntax_map *map = + find_syntax_map_by_standard_oid(token->value); + if (!map) { + break; + } + MSG_ADD_STRING("attributeSyntax", map->AD_OID); + break; + } + case SCHEMA_DESC: + MSG_ADD_STRING("description", token->value); + break; + + default: + fprintf(stderr, "Unknown Definition: %s\n", token->value); + } + } + + talloc_steal(mem_ctx, msg); + talloc_free(ctx); + return msg; + +failed: + talloc_free(ctx); + return NULL; +} + +static struct schema_conv process_file(FILE *in, FILE *out) +{ + TALLOC_CTX *ctx; + struct schema_conv ret; + char *entry; + int c, t, line; + struct ldb_ldif ldif; + + ldif.changetype = LDB_CHANGETYPE_NONE; + + ctx = talloc_new(NULL); + + ret.count = 0; + ret.failures = 0; + line = 0; + + while ((c = fgetc(in)) != EOF) { + line++; + /* fprintf(stderr, "Parsing line %d\n", line); */ + if (c == '#') { + do { + c = fgetc(in); + } while (c != EOF && c != '\n'); + continue; + } + if (c == '\n') { + continue; + } + + t = 0; + entry = talloc_array(ctx, char, 1024); + if (entry == NULL) exit(-1); + + do { + if (c == '\n') { + entry[t] = '\0'; + if (check_braces(entry) == 0) { + ret.count++; + ldif.msg = process_entry(ctx, entry); + if (ldif.msg == NULL) { + ret.failures++; + fprintf(stderr, "No valid msg from entry \n[%s]\n at line %d\n", entry, line); + break; + } + ldb_ldif_write_file(ldb_ctx, out, &ldif); + break; + } + line++; + } else { + entry[t] = c; + t++; + } + if ((t % 1023) == 0) { + entry = talloc_realloc(ctx, entry, char, t + 1024); + if (entry == NULL) exit(-1); + } + } while ((c = fgetc(in)) != EOF); + + if (c != '\n') { + entry[t] = '\0'; + if (check_braces(entry) == 0) { + ret.count++; + ldif.msg = process_entry(ctx, entry); + if (ldif.msg == NULL) { + ret.failures++; + fprintf(stderr, "No valid msg from entry \n[%s]\n at line %d\n", entry, line); + break; + } + ldb_ldif_write_file(ldb_ctx, out, &ldif); + } else { + fprintf(stderr, "malformed entry on line %d\n", line); + ret.failures++; + } + } + + if (c == EOF) break; + } + + return ret; +} + +static void usage(void) +{ + printf("Usage: oLschema2ldif -H NONE <options>\n"); + printf("\nConvert OpenLDAP schema to AD-like LDIF format\n\n"); + printf("Options:\n"); + printf(" -I inputfile inputfile of OpenLDAP style schema otherwise STDIN\n"); + printf(" -O outputfile outputfile otherwise STDOUT\n"); + printf(" -o options pass options like modules to activate\n"); + printf(" e.g: -o modules:timestamps\n"); + printf("\n"); + printf("Converts records from an openLdap formatted schema to an ldif schema\n\n"); + exit(1); +} + + int main(int argc, const char **argv) +{ + TALLOC_CTX *ctx; + struct schema_conv ret; + struct ldb_cmdline *options; + FILE *in = stdin; + FILE *out = stdout; + ldb_global_init(); + + ctx = talloc_new(NULL); + ldb_ctx = ldb_init(ctx); + + setenv("LDB_URL", "NONE", 1); + options = ldb_cmdline_process(ldb_ctx, argc, argv, usage); + + if (options->basedn == NULL) { + perror("Base DN not specified"); + exit(1); + } else { + basedn = ldb_dn_explode(ctx, options->basedn); + if (basedn == NULL) { + perror("Malformed Base DN"); + exit(1); + } + } + + if (options->input) { + in = fopen(options->input, "r"); + if (!in) { + perror(options->input); + exit(1); + } + } + if (options->output) { + out = fopen(options->output, "w"); + if (!out) { + perror(options->output); + exit(1); + } + } + + ret = process_file(in, out); + + fclose(in); + fclose(out); + + printf("Converted %d records with %d failures\n", ret.count, ret.failures); + + return 0; +} |