diff options
Diffstat (limited to 'source4/lib/ldb')
-rw-r--r-- | source4/lib/ldb/Makefile.ldb | 8 | ||||
-rw-r--r-- | source4/lib/ldb/common/ldb.c | 2 | ||||
-rw-r--r-- | source4/lib/ldb/common/ldb_ldif.c | 22 | ||||
-rw-r--r-- | source4/lib/ldb/common/ldb_msg.c | 133 | ||||
-rw-r--r-- | source4/lib/ldb/common/util.c | 6 | ||||
-rw-r--r-- | source4/lib/ldb/config.m4 | 46 | ||||
-rw-r--r-- | source4/lib/ldb/include/includes.h | 3 | ||||
-rw-r--r-- | source4/lib/ldb/include/ldb.h | 2 | ||||
-rw-r--r-- | source4/lib/ldb/ldb_ldap/ldb_ldap.c | 5 | ||||
-rw-r--r-- | source4/lib/ldb/ldb_tdb/ldb_pack.c | 2 | ||||
-rw-r--r-- | source4/lib/ldb/ldb_tdb/ldb_search.c | 36 | ||||
-rw-r--r-- | source4/lib/ldb/ldb_tdb/ldb_tdb.c | 2 | ||||
-rw-r--r-- | source4/lib/ldb/ldb_tdb/ldb_tdb.h | 4 | ||||
-rw-r--r-- | source4/lib/ldb/tools/ldbadd.c | 99 | ||||
-rw-r--r-- | source4/lib/ldb/tools/ldbdel.c | 41 | ||||
-rw-r--r-- | source4/lib/ldb/tools/ldbedit.c | 365 | ||||
-rw-r--r-- | source4/lib/ldb/tools/ldbmodify.c | 100 | ||||
-rw-r--r-- | source4/lib/ldb/tools/ldbsearch.c | 32 |
18 files changed, 803 insertions, 105 deletions
diff --git a/source4/lib/ldb/Makefile.ldb b/source4/lib/ldb/Makefile.ldb index 0610ccf19b..2a41629852 100644 --- a/source4/lib/ldb/Makefile.ldb +++ b/source4/lib/ldb/Makefile.ldb @@ -12,13 +12,14 @@ LDB_TDB_OBJ=ldb_tdb/ldb_match.o ldb_tdb/ldb_tdb.o \ LDB_LDAP_OBJ=ldb_ldap/ldb_ldap.o -COMMON_OBJ=common/ldb.o common/ldb_ldif.o common/util.o common/ldb_parse.o +COMMON_OBJ=common/ldb.o common/ldb_ldif.o common/util.o \ + common/ldb_parse.o common/ldb_msg.o OBJS = $(COMMON_OBJ) $(LDB_TDB_OBJ) $(TDB_OBJ) $(LDB_LDAP_OBJ) LDB_LIB = lib/libldb.a -BINS = bin/ldbadd bin/ldbsearch bin/ldbdel bin/ldbmodify +BINS = bin/ldbadd bin/ldbsearch bin/ldbdel bin/ldbmodify bin/ldbedit LIBS = $(LDB_LIB)($(OBJS)) @@ -46,6 +47,9 @@ bin/ldbdel: tools/ldbdel.o $(LIBS) bin/ldbmodify: tools/ldbmodify.o $(LIBS) $(CC) -o bin/ldbmodify tools/ldbmodify.o $(LIB_FLAGS) +bin/ldbedit: tools/ldbedit.o $(LIBS) + $(CC) -o bin/ldbedit tools/ldbedit.o $(LIB_FLAGS) + clean: rm -f */*.o *~ */*~ $(BINS) $(LDB_LIB) diff --git a/source4/lib/ldb/common/ldb.c b/source4/lib/ldb/common/ldb.c index 3ba4434e07..146745043f 100644 --- a/source4/lib/ldb/common/ldb.c +++ b/source4/lib/ldb/common/ldb.c @@ -80,7 +80,7 @@ int ldb_search(struct ldb_context *ldb, const char *base, enum ldb_scope scope, const char *expression, - const char *attrs[], struct ldb_message ***res) + char * const attrs[], struct ldb_message ***res) { return ldb->ops->search(ldb, base, scope, expression, attrs, res); } diff --git a/source4/lib/ldb/common/ldb_ldif.c b/source4/lib/ldb/common/ldb_ldif.c index b4c27c3369..5f2fccfebc 100644 --- a/source4/lib/ldb/common/ldb_ldif.c +++ b/source4/lib/ldb/common/ldb_ldif.c @@ -90,7 +90,7 @@ char *ldb_base64_encode(const char *buf, int len) { const char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; int bit_offset, byte_offset, idx, i; - unsigned char *d = (unsigned char *)buf; + const unsigned char *d = (const unsigned char *)buf; int bytes = (len*8 + 5)/6; char *out; @@ -222,6 +222,23 @@ int ldif_write(int (*fprintf_fn)(void *, const char *, ...), } for (i=0;i<msg->num_elements;i++) { + if (ldif->changetype == LDB_CHANGETYPE_MODIFY) { + switch (msg->elements[i].flags & LDB_FLAG_MOD_MASK) { + case LDB_FLAG_MOD_ADD: + fprintf_fn(private, "add: %s\n", + msg->elements[i].name); + break; + case LDB_FLAG_MOD_DELETE: + fprintf_fn(private, "delete: %s\n", + msg->elements[i].name); + break; + case LDB_FLAG_MOD_REPLACE: + fprintf_fn(private, "replace: %s\n", + msg->elements[i].name); + break; + } + } + for (j=0;j<msg->elements[i].num_values;j++) { if (ldb_should_b64_encode(&msg->elements[i].values[j])) { ret = fprintf_fn(private, "%s:: ", @@ -246,6 +263,9 @@ int ldif_write(int (*fprintf_fn)(void *, const char *, ...), CHECK_RET; } } + if (ldif->changetype == LDB_CHANGETYPE_MODIFY) { + fprintf_fn(private, "-\n"); + } } ret = fprintf_fn(private,"\n"); CHECK_RET; diff --git a/source4/lib/ldb/common/ldb_msg.c b/source4/lib/ldb/common/ldb_msg.c new file mode 100644 index 0000000000..633cc91f2c --- /dev/null +++ b/source4/lib/ldb/common/ldb_msg.c @@ -0,0 +1,133 @@ +/* + 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: ldb message component utility functions + * + * Description: functions for manipulating ldb_message structures + * + * Author: Andrew Tridgell + */ + +#include "includes.h" + + +/* + find an element in a message by attribute name +*/ +struct ldb_message_element *ldb_msg_find_element(const struct ldb_message *msg, + const char *attr_name) +{ + int i; + for (i=0;i<msg->num_elements;i++) { + if (strcmp(msg->elements[i].name, attr_name) == 0) { + return &msg->elements[i]; + } + } + return NULL; +} + + +/* + find a value in an element +*/ +struct ldb_val *ldb_msg_find_val(const struct ldb_message_element *el, + struct ldb_val *val) +{ + int i; + for (i=0;i<el->num_values;i++) { + if (ldb_val_equal(val, &el->values[i])) { + return &el->values[i]; + } + } + return NULL; +} + + +/* + add an empty element to a message +*/ +int ldb_msg_add_empty(struct ldb_message *msg, const char *attr_name, int flags) +{ + struct ldb_message_element *els; + + els = realloc_p(msg->elements, struct ldb_message_element, msg->num_elements+1); + if (!els) { + errno = ENOMEM; + return -1; + } + + els[msg->num_elements].values = NULL; + els[msg->num_elements].num_values = 0; + els[msg->num_elements].flags = flags; + els[msg->num_elements].name = strdup(attr_name); + if (!els[msg->num_elements].name) { + return -1; + } + + msg->elements = els; + msg->num_elements++; + + return 0; +} + +/* + add an empty element to a message +*/ +int ldb_msg_add(struct ldb_message *msg, + const struct ldb_message_element *el, + int flags) +{ + if (ldb_msg_add_empty(msg, el->name, flags) != 0) { + return -1; + } + + msg->elements[msg->num_elements-1] = *el; + msg->elements[msg->num_elements-1].flags = flags; + + return 0; +} + +/* + compare two ldb_message_element structures +*/ +int ldb_msg_element_compare(struct ldb_message_element *el1, + struct ldb_message_element *el2) +{ + int i; + + if (el1->num_values != el2->num_values) { + return el1->num_values - el2->num_values; + } + + for (i=0;i<el1->num_values;i++) { + if (!ldb_msg_find_val(el2, &el1->values[i])) { + return -1; + } + } + + return 0; +} diff --git a/source4/lib/ldb/common/util.c b/source4/lib/ldb/common/util.c index d198a1ad92..e1a7ada1c6 100644 --- a/source4/lib/ldb/common/util.c +++ b/source4/lib/ldb/common/util.c @@ -77,11 +77,11 @@ int list_find(const void *needle, int r; test_i = (min_i + max_i) / 2; - r = comp_fn(needle, *(void **)(base_p + (size * test_i))); + r = comp_fn(needle, *(void * const *)(base_p + (size * test_i))); if (r == 0) { /* scan back for first element */ while (test_t > 0 && - comp_fn(needle, *(void **)(base_p + (size * (test_i-1)))) == 0) { + comp_fn(needle, *(void * const *)(base_p + (size * (test_i-1)))) == 0) { test_i--; } return test_i; @@ -94,7 +94,7 @@ int list_find(const void *needle, } } - if (comp_fn(needle, *(void **)(base_p + (size * min_i))) == 0) { + if (comp_fn(needle, *(void * const *)(base_p + (size * min_i))) == 0) { return min_i; } diff --git a/source4/lib/ldb/config.m4 b/source4/lib/ldb/config.m4 index 6fdfcf526a..7c4749ab02 100644 --- a/source4/lib/ldb/config.m4 +++ b/source4/lib/ldb/config.m4 @@ -1,17 +1,37 @@ - -SMB_MODULE(libldb_tdb,LIBLDB,STATIC, - [lib/ldb/ldb_tdb/ldb_tdb.o \ - lib/ldb/ldb_tdb/ldb_pack.o \ +SMB_SUBSYSTEM(LIBLDB,[lib/ldb/common/ldb.o], + [lib/ldb/common/ldb_ldif.o \ + lib/ldb/common/ldb_parse.o \ + lib/ldb/common/ldb_msg.o \ + lib/ldb/common/util.o \ lib/ldb/ldb_tdb/ldb_search.o \ + lib/ldb/ldb_tdb/ldb_tdb.o \ + lib/ldb/ldb_tdb/ldb_pack.o \ lib/ldb/ldb_tdb/ldb_index.o \ - lib/ldb/ldb_tdb/ldb_match.o]) + lib/ldb/ldb_tdb/ldb_match.o \ + lib/ldb/ldb_ldap/ldb_ldap.o], + lib/ldb/include/ldb.h) -if test x"$with_ldap_support" = x"yes"; then - SMB_MODULE_DEFAULT(libldb_ldap,STATIC) -fi -SMB_MODULE(libldb_ldap,LIBLDB,NOT,[lib/ldb/ldb_ldap/ldb_ldap.o]) +SMB_SUBSYSTEM(LDBADD,[], + [lib/ldb/tools/ldbadd.o \ + \$(LIBBASIC_OBJS) \$(LIBSMB_OBJS) \$(CONFIG_OBJS) \$(LIBLDB_OBJS)], + lib/ldb/include/proto.h) -SMB_SUBSYSTEM(LIBLDB,[lib/ldb/common/ldb.o], - [lib/ldb/common/ldb_ldif.o \ - lib/ldb/common/ldb_parse.o \ - lib/ldb/common/util.o]) +SMB_SUBSYSTEM(LDBDEL,[], + [lib/ldb/tools/ldbdel.o \ + \$(LIBBASIC_OBJS) \$(LIBSMB_OBJS) \$(CONFIG_OBJS) \$(LIBLDB_OBJS)], + lib/ldb/include/proto.h) + +SMB_SUBSYSTEM(LDBMODIFY,[], + [lib/ldb/tools/ldbmodify.o \ + \$(LIBBASIC_OBJS) \$(LIBSMB_OBJS) \$(CONFIG_OBJS) \$(LIBLDB_OBJS)], + lib/ldb/include/proto.h) + +SMB_SUBSYSTEM(LDBSEARCH,[], + [lib/ldb/tools/ldbsearch.o \ + \$(LIBBASIC_OBJS) \$(LIBSMB_OBJS) \$(CONFIG_OBJS) \$(LIBLDB_OBJS)], + lib/ldb/include/proto.h) + +SMB_SUBSYSTEM(LDBEDIT,[], + [lib/ldb/tools/ldbedit.o \ + \$(LIBBASIC_OBJS) \$(LIBSMB_OBJS) \$(CONFIG_OBJS) \$(LIBLDB_OBJS)], + lib/ldb/include/proto.h) diff --git a/source4/lib/ldb/include/includes.h b/source4/lib/ldb/include/includes.h index ea8540d330..70ad1f3588 100644 --- a/source4/lib/ldb/include/includes.h +++ b/source4/lib/ldb/include/includes.h @@ -2,7 +2,9 @@ a temporary includes file until I work on the ldb build system */ +#ifndef _GNU_SOURCE #define _GNU_SOURCE +#endif #include <stdio.h> #include <string.h> #include <stdlib.h> @@ -11,6 +13,7 @@ #include <fcntl.h> #include <stdarg.h> #include <signal.h> +#include <unistd.h> #include "ldb.h" #include "ldb_parse.h" diff --git a/source4/lib/ldb/include/ldb.h b/source4/lib/ldb/include/ldb.h index 12064bbf75..dc1b1d7732 100644 --- a/source4/lib/ldb/include/ldb.h +++ b/source4/lib/ldb/include/ldb.h @@ -174,7 +174,7 @@ int ldb_search(struct ldb_context *ldb, const char *base, enum ldb_scope scope, const char *expression, - const char *attrs[], struct ldb_message ***res); + char * const attrs[], struct ldb_message ***res); /* free a set of messages returned by ldb_search diff --git a/source4/lib/ldb/ldb_ldap/ldb_ldap.c b/source4/lib/ldb/ldb_ldap/ldb_ldap.c index 25dad914da..25af43c569 100644 --- a/source4/lib/ldb/ldb_ldap/ldb_ldap.c +++ b/source4/lib/ldb/ldb_ldap/ldb_ldap.c @@ -33,8 +33,7 @@ */ #include "includes.h" -#if HAVE_LDAP -#include "ldb_ldap.h" +#include "ldb/ldb_ldap/ldb_ldap.h" #if 0 /* @@ -519,4 +518,4 @@ failed: if (ldb) free(ldb); return NULL; } -#endif /*HAVE_LDAP*/ + diff --git a/source4/lib/ldb/ldb_tdb/ldb_pack.c b/source4/lib/ldb/ldb_tdb/ldb_pack.c index 5964e0751d..1196e561a2 100644 --- a/source4/lib/ldb/ldb_tdb/ldb_pack.c +++ b/source4/lib/ldb/ldb_tdb/ldb_pack.c @@ -33,7 +33,7 @@ */ #include "includes.h" -#include "ldb_tdb.h" +#include "ldb/ldb_tdb/ldb_tdb.h" /* change this if the data format ever changes */ #define LTDB_PACKING_FORMAT 0x26011966 diff --git a/source4/lib/ldb/ldb_tdb/ldb_search.c b/source4/lib/ldb/ldb_tdb/ldb_search.c index 5905231b32..9cb5853c94 100644 --- a/source4/lib/ldb/ldb_tdb/ldb_search.c +++ b/source4/lib/ldb/ldb_tdb/ldb_search.c @@ -33,7 +33,7 @@ */ #include "includes.h" -#include "ldb_tdb.h" +#include "ldb/ldb_tdb/ldb_tdb.h" /* free a message that has all parts separately allocated @@ -56,22 +56,6 @@ static void msg_free_all_parts(struct ldb_message *msg) /* - TODO: this should take advantage of the sorted nature of the message - - return index of the attribute, or -1 if not found -*/ -int ldb_msg_find_attr(const struct ldb_message *msg, const char *attr) -{ - int i; - for (i=0;i<msg->num_elements;i++) { - if (strcmp(msg->elements[i].name, attr) == 0) { - return i; - } - } - return -1; -} - -/* duplicate a ldb_val structure */ struct ldb_val ldb_val_dup(const struct ldb_val *v) @@ -193,7 +177,7 @@ static struct ldb_message *ltdb_pull_attrs(struct ldb_context *ldb, } for (i=0;attrs[i];i++) { - int j; + struct ldb_message_element *el; if (strcmp(attrs[i], "*") == 0) { if (msg_add_all_elements(ret, msg) != 0) { @@ -202,17 +186,15 @@ static struct ldb_message *ltdb_pull_attrs(struct ldb_context *ldb, } continue; } - j = ldb_msg_find_attr(msg, attrs[i]); - if (j == -1) { + + el = ldb_msg_find_element(msg, attrs[i]); + if (!el) { continue; } - do { - if (msg_add_element(ret, &msg->elements[j]) != 0) { - msg_free_all_parts(ret); - return NULL; - } - } while (++j < msg->num_elements && - strcmp(attrs[i], msg->elements[j].name) == 0); + if (msg_add_element(ret, el) != 0) { + msg_free_all_parts(ret); + return NULL; + } } return ret; diff --git a/source4/lib/ldb/ldb_tdb/ldb_tdb.c b/source4/lib/ldb/ldb_tdb/ldb_tdb.c index ec90eec03f..b28d73cbea 100644 --- a/source4/lib/ldb/ldb_tdb/ldb_tdb.c +++ b/source4/lib/ldb/ldb_tdb/ldb_tdb.c @@ -33,7 +33,7 @@ */ #include "includes.h" -#include "ldb_tdb.h" +#include "ldb/ldb_tdb/ldb_tdb.h" /* form a TDB_DATA for a record key diff --git a/source4/lib/ldb/ldb_tdb/ldb_tdb.h b/source4/lib/ldb/ldb_tdb/ldb_tdb.h index 30afe223ea..efb0af1c9c 100644 --- a/source4/lib/ldb/ldb_tdb/ldb_tdb.h +++ b/source4/lib/ldb/ldb_tdb/ldb_tdb.h @@ -5,7 +5,9 @@ struct ltdb_private { unsigned int connect_flags; }; -#ifdef STANDALONE +#ifndef IVAL #define IVAL(p, ofs) (((unsigned *)((char *)(p) + (ofs)))[0]) +#endif +#ifndef SIVAL #define SIVAL(p, ofs, v) do { IVAL(p, ofs) = (v); } while (0) #endif diff --git a/source4/lib/ldb/tools/ldbadd.c b/source4/lib/ldb/tools/ldbadd.c index 92ed29e6b8..446c0d80f9 100644 --- a/source4/lib/ldb/tools/ldbadd.c +++ b/source4/lib/ldb/tools/ldbadd.c @@ -34,28 +34,28 @@ #include "includes.h" - int main(void) -{ - static struct ldb_context *ldb; - struct ldb_ldif *ldif; - int ret; - int count=0, failures=0; - const char *ldb_url; - - ldb_url = getenv("LDB_URL"); - if (!ldb_url) { - ldb_url = "tdb://test.ldb"; - } +static int failures; - ldb = ldb_connect(ldb_url, 0, NULL); +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("\n"); + printf("Adds records to a ldb, reading ldif the specified list of files\n\n"); + exit(1); +} - if (!ldb) { - perror("ldb_connect"); - exit(1); - } - while ((ldif = ldif_read_file(stdin))) { +/* + 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 = ldif_read_file(f))) { if (ldif->changetype != LDB_CHANGETYPE_ADD && ldif->changetype != LDB_CHANGETYPE_NONE) { fprintf(stderr, "Only CHANGETYPE_ADD records allowed\n"); @@ -73,6 +73,69 @@ ldif_read_free(ldif); } + return count; +} + + + + int main(int argc, char * const argv[]) +{ + struct ldb_context *ldb; + int count=0; + const char *ldb_url; + int opt, i; + + ldb_url = getenv("LDB_URL"); + + while ((opt = getopt(argc, argv, "hH:")) != EOF) { + switch (opt) { + case 'H': + ldb_url = optarg; + break; + + case 'h': + default: + usage(); + break; + } + } + + if (!ldb_url) { + fprintf(stderr, "You must specify a ldb URL\n"); + exit(1); + } + + argc -= optind; + argv += optind; + + ldb = ldb_connect(ldb_url, 0, NULL); + + if (!ldb) { + perror("ldb_connect"); + exit(1); + } + + if (argc == 0) { + usage(); + } + + for (i=0;i<argc;i++) { + FILE *f; + if (strcmp(argv[i],"-") == 0) { + f = stdin; + } else { + f = fopen(argv[i], "r"); + } + if (!f) { + perror(argv[i]); + exit(1); + } + count += process_file(ldb, f); + if (f != stdin) { + fclose(f); + } + } + ldb_close(ldb); printf("Added %d records with %d failures\n", count, failures); diff --git a/source4/lib/ldb/tools/ldbdel.c b/source4/lib/ldb/tools/ldbdel.c index 177279d47a..0e50a68532 100644 --- a/source4/lib/ldb/tools/ldbdel.c +++ b/source4/lib/ldb/tools/ldbdel.c @@ -34,20 +34,48 @@ #include "includes.h" - int main(int argc, const char *argv[]) +static void usage(void) { - static struct ldb_context *ldb; + printf("Usage: ldbdel <options> <DN...>\n"); + printf("Options:\n"); + printf(" -H ldb_url choose the database (or $LDB_URL)\n"); + printf("\n"); + printf("Deletes records from a ldb\n\n"); + exit(1); +} + + int main(int argc, char * const argv[]) +{ + struct ldb_context *ldb; int ret, i; const char *ldb_url; + int opt; ldb_url = getenv("LDB_URL"); + + while ((opt = getopt(argc, argv, "hH:")) != EOF) { + switch (opt) { + case 'H': + ldb_url = optarg; + break; + + case 'h': + default: + usage(); + break; + } + } + if (!ldb_url) { - ldb_url = "tdb://test.ldb"; + fprintf(stderr, "You must specify a ldb URL\n"); + exit(1); } + argc -= optind; + argv += optind; - if (argc < 2) { - printf("Usage: ldbdel <dn...>\n"); + if (argc < 1) { + usage(); exit(1); } @@ -57,7 +85,7 @@ exit(1); } - for (i=1;i<argc;i++) { + for (i=0;i<argc;i++) { ret = ldb_delete(ldb, argv[i]); if (ret != 0) { printf("delete of '%s' failed\n", argv[i]); @@ -65,5 +93,6 @@ } ldb_close(ldb); + return 0; } diff --git a/source4/lib/ldb/tools/ldbedit.c b/source4/lib/ldb/tools/ldbedit.c new file mode 100644 index 0000000000..c5eb1349dd --- /dev/null +++ b/source4/lib/ldb/tools/ldbedit.c @@ -0,0 +1,365 @@ +/* + 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 editing + * + * Author: Andrew Tridgell + */ + +#include "includes.h" + +/* + modify a database record so msg1 becomes msg2 +*/ +static int modify_record(struct ldb_context *ldb, + struct ldb_message *msg1, + struct ldb_message *msg2) +{ + struct ldb_message mod; + struct ldb_message_element *el; + int i; + + mod.dn = msg1->dn; + mod.num_elements = 0; + mod.elements = NULL; + + /* look in msg2 to find elements that need to be added + or modified */ + for (i=0;i<msg2->num_elements;i++) { + el = ldb_msg_find_element(msg1, msg2->elements[i].name); + + if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) { + continue; + } + + if (ldb_msg_add(&mod, + &msg2->elements[i], + el?LDB_FLAG_MOD_REPLACE:LDB_FLAG_MOD_ADD) != 0) { + return -1; + } + } + + /* look in msg1 to find elements that need to be deleted */ + for (i=0;i<msg1->num_elements;i++) { + el = ldb_msg_find_element(msg2, msg1->elements[i].name); + if (!el) { + if (ldb_msg_add_empty(&mod, + msg1->elements[i].name, + LDB_FLAG_MOD_DELETE) != 0) { + return -1; + } + } + } + + if (mod.num_elements == 0) { + return 0; + } + + if (ldb_modify(ldb, &mod) != 0) { + fprintf(stderr, "failed to modify %s\n", msg1->dn); + return -1; + } + + return 0; +} + +/* + find dn in msgs[] +*/ +static struct ldb_message *msg_find(struct ldb_message **msgs, int count, + const char *dn) +{ + int i; + for (i=0;i<count;i++) { + if (strcmp(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; + + /* do the adds and modifies */ + for (i=0;i<count2;i++) { + msg = msg_find(msgs1, count1, msgs2[i]->dn); + if (!msg) { + if (ldb_add(ldb, msgs2[i]) != 0) { + fprintf(stderr, "failed to add %s\n", + msgs2[i]->dn); + return -1; + } + } else { + modify_record(ldb, msg, msgs2[i]); + } + } + + /* do the deletes */ + for (i=0;i<count1;i++) { + msg = msg_find(msgs2, count2, msgs1[i]->dn); + if (!msg) { + if (ldb_delete(ldb, msgs1[i]->dn) != 0) { + fprintf(stderr, "failed to delete %s\n", + msgs1[i]->dn); + return -1; + } + } + } + + return ret; +} + +/* + save a set of messages as ldif to a file +*/ +static int save_ldif(FILE *f, struct ldb_message **msgs, int count) +{ + int i; + + fprintf(f, "# returned %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]; + + ldif_write_file(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 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(template); + + if (fd == -1) { + perror(template); + return -1; + } + + f = fdopen(fd, "r+"); + + if (!f) { + perror("fopen"); + close(fd); + unlink(template); + return -1; + } + + if (save_ldif(f, msgs1, count1) != 0) { + return -1; + } + + fclose(f); + + asprintf(&cmd, "%s %s", editor, template); + + if (!cmd) { + unlink(template); + fprintf(stderr, "out of memory\n"); + return -1; + } + + /* run the editor */ + ret = system(cmd); + free(cmd); + + if (ret != 0) { + unlink(template); + fprintf(stderr, "edit with %s failed\n", editor); + return -1; + } + + /* read the resulting ldif into msgs2 */ + f = fopen(template, "r"); + if (!f) { + perror(template); + return -1; + } + + while ((ldif = ldif_read_file(f))) { + msgs2 = realloc_p(msgs2, struct ldb_message *, count2+1); + if (!msgs2) { + fprintf(stderr, "out of memory"); + return -1; + } + msgs2[count2++] = &ldif->msg; + } + + fclose(f); + unlink(template); + + return merge_edits(ldb, msgs1, count1, msgs2, count2); +} + +static void usage(void) +{ + printf("Usage: ldbedit <options> <expression>\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 'dn=*')\n"); + printf(" -e editor choose editor (or $VISUAL or $EDITOR)\n"); + exit(1); +} + + int main(int argc, char * const argv[]) +{ + struct ldb_context *ldb; + struct ldb_message **msgs; + int ret; + const char *expression = NULL; + const char *ldb_url; + const char *basedn = NULL; + int opt; + enum ldb_scope scope = LDB_SCOPE_SUBTREE; + const char *editor; + + ldb_url = getenv("LDB_URL"); + + /* build the editor command to run - + use the same editor priorities as vipw */ + editor = getenv("VISUAL"); + if (!editor) { + editor = getenv("EDITOR"); + } + if (!editor) { + editor = "vi"; + } + + while ((opt = getopt(argc, argv, "ab:e:H:s:")) != EOF) { + switch (opt) { + case 'b': + basedn = optarg; + break; + + case 'H': + ldb_url = optarg; + break; + + case 's': + if (strcmp(optarg, "base") == 0) { + scope = LDB_SCOPE_BASE; + } else if (strcmp(optarg, "sub") == 0) { + scope = LDB_SCOPE_SUBTREE; + } else if (strcmp(optarg, "one") == 0) { + scope = LDB_SCOPE_ONELEVEL; + } + break; + + case 'e': + editor = optarg; + break; + + case 'a': + expression = "dn=*"; + break; + + case 'h': + default: + usage(); + break; + } + } + + if (!ldb_url) { + fprintf(stderr, "You must specify a ldb URL\n"); + exit(1); + } + + argc -= optind; + argv += optind; + + if (!expression) { + if (argc == 0) { + usage(); + } + expression = argv[0]; + } + + ldb = ldb_connect(ldb_url, 0, NULL); + + if (!ldb) { + perror("ldb_connect"); + exit(1); + } + + ret = ldb_search(ldb, basedn, scope, expression, NULL, &msgs); + + if (ret == -1) { + printf("search failed - %s\n", ldb_errstring(ldb)); + exit(1); + } + + if (ret == 0) { + printf("no matching records - cannot edit\n"); + return 0; + } + + do_edit(ldb, msgs, ret, editor); + + if (ret > 0) { + ret = ldb_search_free(ldb, msgs); + if (ret == -1) { + fprintf(stderr, "search_free failed\n"); + exit(1); + } + } + + ldb_close(ldb); + return 0; +} diff --git a/source4/lib/ldb/tools/ldbmodify.c b/source4/lib/ldb/tools/ldbmodify.c index e1cff655db..a93c710a7a 100644 --- a/source4/lib/ldb/tools/ldbmodify.c +++ b/source4/lib/ldb/tools/ldbmodify.c @@ -34,27 +34,27 @@ #include "includes.h" - int main(void) -{ - static struct ldb_context *ldb; - struct ldb_ldif *ldif; - int ret; - int count=0, failures=0; - const char *ldb_url; - - ldb_url = getenv("LDB_URL"); - if (!ldb_url) { - ldb_url = "tdb://test.ldb"; - } +static int failures; - ldb = ldb_connect(ldb_url, 0, NULL); - - if (!ldb) { - perror("ldb_connect"); - exit(1); - } +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("\n"); + printf("Modifies a ldb based upon ldif change records\n\n"); + exit(1); +} - while ((ldif = ldif_read_file(stdin))) { +/* + process modifies for one file +*/ +static int process_file(struct ldb_context *ldb, FILE *f) +{ + struct ldb_ldif *ldif; + int ret, count = 0; + + while ((ldif = ldif_read_file(f))) { switch (ldif->changetype) { case LDB_CHANGETYPE_NONE: case LDB_CHANGETYPE_ADD: @@ -77,6 +77,68 @@ ldif_read_free(ldif); } + return count; +} + + int main(int argc, char * const argv[]) +{ + struct ldb_context *ldb; + int count=0; + const char *ldb_url; + int opt, i; + + ldb_url = getenv("LDB_URL"); + + while ((opt = getopt(argc, argv, "hH:")) != EOF) { + switch (opt) { + case 'H': + ldb_url = optarg; + break; + + case 'h': + default: + usage(); + break; + } + } + + if (!ldb_url) { + fprintf(stderr, "You must specify a ldb URL\n"); + exit(1); + } + + argc -= optind; + argv += optind; + + ldb = ldb_connect(ldb_url, 0, NULL); + + if (!ldb) { + perror("ldb_connect"); + exit(1); + } + + if (argc == 0) { + usage(); + exit(1); + } + + for (i=0;i<argc;i++) { + FILE *f; + if (strcmp(argv[i],"-") == 0) { + f = stdin; + } else { + f = fopen(argv[i], "r"); + } + if (!f) { + perror(argv[i]); + exit(1); + } + count += process_file(ldb, f); + if (f != stdin) { + fclose(f); + } + } + ldb_close(ldb); printf("Modified %d records with %d failures\n", count, failures); diff --git a/source4/lib/ldb/tools/ldbsearch.c b/source4/lib/ldb/tools/ldbsearch.c index f4eb8f00db..327feb28ef 100644 --- a/source4/lib/ldb/tools/ldbsearch.c +++ b/source4/lib/ldb/tools/ldbsearch.c @@ -33,26 +33,32 @@ */ #include "includes.h" -#include <getopt.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"); + exit(1); +} int main(int argc, char * const argv[]) { - static struct ldb_context *ldb; + struct ldb_context *ldb; struct ldb_message **msgs; int ret, i; const char *expression; - const char * const *attrs = NULL; + char * const *attrs = NULL; const char *ldb_url; const char *basedn = NULL; int opt; enum ldb_scope scope = LDB_SCOPE_SUBTREE; ldb_url = getenv("LDB_URL"); - if (!ldb_url) { - ldb_url = "tdb://test.ldb"; - } - while ((opt = getopt(argc, argv, "b:H:s:")) != EOF) { + while ((opt = getopt(argc, argv, "b:H:s:h")) != EOF) { switch (opt) { case 'b': basedn = optarg; @@ -71,14 +77,24 @@ scope = LDB_SCOPE_ONELEVEL; } break; + + case 'h': + default: + usage(); + break; } } + if (!ldb_url) { + fprintf(stderr, "You must specify a ldb URL\n"); + exit(1); + } + argc -= optind; argv += optind; if (argc < 1) { - printf("Usage: ldbsearch <expression> [attrs...]\n"); + usage(); exit(1); } |