From ee44733f94864fb0a1ae15d48e3335c0705a82ae Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 3 Apr 2004 12:29:21 +0000 Subject: added the rest of the ldb_modify() code, which required a fairly large change in the ldb API. The API is now much closer to LDAP. (This used to be commit e9e85c464411c561c5073d262a2e3533fec175ca) --- source4/lib/ldb/Makefile.ldb | 5 +- source4/lib/ldb/common/ldb_ldif.c | 233 +++++++++++++++++++++++------ source4/lib/ldb/include/ldb.h | 29 +++- source4/lib/ldb/ldb_ldap/ldb_ldap.c | 96 ++++++------ source4/lib/ldb/ldb_tdb/ldb_index.c | 208 ++++++++++++++++++-------- source4/lib/ldb/ldb_tdb/ldb_match.c | 18 ++- source4/lib/ldb/ldb_tdb/ldb_pack.c | 94 ++++++++---- source4/lib/ldb/ldb_tdb/ldb_search.c | 52 +++++-- source4/lib/ldb/ldb_tdb/ldb_tdb.c | 263 +++++++++++++++++++++++++++++++-- source4/lib/ldb/ldb_tdb/ldbadd.c | 55 ------- source4/lib/ldb/ldb_tdb/ldbdel.c | 50 ------- source4/lib/ldb/ldb_tdb/ldbsearch.c | 73 --------- source4/lib/ldb/tests/test-generic.sh | 8 + source4/lib/ldb/tests/test-ldap.sh | 8 + source4/lib/ldb/tests/test-modify.ldif | 14 ++ source4/lib/ldb/tests/test-tdb.sh | 8 + source4/lib/ldb/tools/ldbadd.c | 17 ++- source4/lib/ldb/tools/ldbmodify.c | 85 +++++++++++ source4/lib/ldb/tools/ldbsearch.c | 11 +- 19 files changed, 922 insertions(+), 405 deletions(-) delete mode 100644 source4/lib/ldb/ldb_tdb/ldbadd.c delete mode 100644 source4/lib/ldb/ldb_tdb/ldbdel.c delete mode 100644 source4/lib/ldb/ldb_tdb/ldbsearch.c create mode 100644 source4/lib/ldb/tests/test-generic.sh create mode 100755 source4/lib/ldb/tests/test-ldap.sh create mode 100644 source4/lib/ldb/tests/test-modify.ldif create mode 100755 source4/lib/ldb/tests/test-tdb.sh create mode 100644 source4/lib/ldb/tools/ldbmodify.c diff --git a/source4/lib/ldb/Makefile.ldb b/source4/lib/ldb/Makefile.ldb index b983ca2c49..0610ccf19b 100644 --- a/source4/lib/ldb/Makefile.ldb +++ b/source4/lib/ldb/Makefile.ldb @@ -18,7 +18,7 @@ OBJS = $(COMMON_OBJ) $(LDB_TDB_OBJ) $(TDB_OBJ) $(LDB_LDAP_OBJ) LDB_LIB = lib/libldb.a -BINS = bin/ldbadd bin/ldbsearch bin/ldbdel +BINS = bin/ldbadd bin/ldbsearch bin/ldbdel bin/ldbmodify LIBS = $(LDB_LIB)($(OBJS)) @@ -43,6 +43,9 @@ bin/ldbsearch: tools/ldbsearch.o $(LIBS) bin/ldbdel: tools/ldbdel.o $(LIBS) $(CC) -o bin/ldbdel tools/ldbdel.o $(LIB_FLAGS) +bin/ldbmodify: tools/ldbmodify.o $(LIBS) + $(CC) -o bin/ldbmodify tools/ldbmodify.o $(LIB_FLAGS) + clean: rm -f */*.o *~ */*~ $(BINS) $(LDB_LIB) diff --git a/source4/lib/ldb/common/ldb_ldif.c b/source4/lib/ldb/common/ldb_ldif.c index 198c984823..b4c27c3369 100644 --- a/source4/lib/ldb/common/ldb_ldif.c +++ b/source4/lib/ldb/common/ldb_ldif.c @@ -32,6 +32,10 @@ * Author: Andrew Tridgell */ +/* + see RFC2849 for the LDIF format definition +*/ + #include "includes.h" @@ -176,40 +180,71 @@ static int base64_encode_f(int (*fprintf_fn)(void *, const char *, ...), void *p return ret; } + +static const struct { + const char *name; + enum ldb_changetype changetype; +} ldb_changetypes[] = { + {"add", LDB_CHANGETYPE_ADD}, + {"delete", LDB_CHANGETYPE_DELETE}, + {"modify", LDB_CHANGETYPE_MODIFY}, + {NULL, 0} +}; + /* write to ldif, using a caller supplied write method */ int ldif_write(int (*fprintf_fn)(void *, const char *, ...), void *private, - const struct ldb_message *msg) + const struct ldb_ldif *ldif) { - int i; + int i, j; int total=0, ret; + const struct ldb_message *msg; + + msg = &ldif->msg; ret = fprintf_fn(private, "dn: %s\n", msg->dn); CHECK_RET; + if (ldif->changetype != LDB_CHANGETYPE_NONE) { + for (i=0;ldb_changetypes[i].name;i++) { + if (ldb_changetypes[i].changetype == ldif->changetype) { + break; + } + } + if (!ldb_changetypes[i].name) { + fprintf(stderr,"Invalid changetype\n"); + return -1; + } + ret = fprintf_fn(private, "changetype: %s\n", ldb_changetypes[i].name); + CHECK_RET; + } + for (i=0;inum_elements;i++) { - if (ldb_should_b64_encode(&msg->elements[i].value)) { - ret = fprintf_fn(private, "%s:: ", msg->elements[i].name); - CHECK_RET; - ret = base64_encode_f(fprintf_fn, private, - msg->elements[i].value.data, - msg->elements[i].value.length, - strlen(msg->elements[i].name)+3); - CHECK_RET; - ret = fprintf_fn(private, "\n"); - CHECK_RET; - } else { - ret = fprintf_fn(private, "%s: ", msg->elements[i].name); - CHECK_RET; - ret = fold_string(fprintf_fn, private, - msg->elements[i].value.data, - msg->elements[i].value.length, - strlen(msg->elements[i].name)+2); - CHECK_RET; - ret = fprintf_fn(private, "\n"); - CHECK_RET; + for (j=0;jelements[i].num_values;j++) { + if (ldb_should_b64_encode(&msg->elements[i].values[j])) { + ret = fprintf_fn(private, "%s:: ", + msg->elements[i].name); + CHECK_RET; + ret = base64_encode_f(fprintf_fn, private, + msg->elements[i].values[j].data, + msg->elements[i].values[j].length, + strlen(msg->elements[i].name)+3); + CHECK_RET; + ret = fprintf_fn(private, "\n"); + CHECK_RET; + } else { + ret = fprintf_fn(private, "%s: ", msg->elements[i].name); + CHECK_RET; + ret = fold_string(fprintf_fn, private, + msg->elements[i].values[j].data, + msg->elements[i].values[j].length, + strlen(msg->elements[i].name)+2); + CHECK_RET; + ret = fprintf_fn(private, "\n"); + CHECK_RET; + } } } ret = fprintf_fn(private,"\n"); @@ -235,7 +270,7 @@ static char *next_chunk(int (*fgetc_fn)(void *), void *private) int in_comment = 0; while ((c = fgetc_fn(private)) != EOF) { - if (chunk_size == alloc_size) { + if (chunk_size+1 >= alloc_size) { char *c2; alloc_size += 1024; c2 = realloc_p(chunk, char, alloc_size); @@ -279,6 +314,10 @@ static char *next_chunk(int (*fgetc_fn)(void *), void *private) chunk[chunk_size++] = c; } + if (chunk) { + chunk[chunk_size] = 0; + } + return chunk; } @@ -289,6 +328,13 @@ static int next_attr(char **s, char **attr, struct ldb_val *value) char *p; int base64_encoded = 0; + if (strncmp(*s, "-\n", 2) == 0) { + value->length = 0; + *attr = "-"; + *s += 2; + return 0; + } + p = strchr(*s, ':'); if (!p) { return -1; @@ -336,26 +382,63 @@ static int next_attr(char **s, char **attr, struct ldb_val *value) /* free a message from a ldif_read */ -void ldif_read_free(struct ldb_message *msg) +void ldif_read_free(struct ldb_ldif *ldif) { + struct ldb_message *msg = &ldif->msg; + int i; + for (i=0;inum_elements;i++) { + if (msg->elements[i].values) free(msg->elements[i].values); + } if (msg->elements) free(msg->elements); if (msg->private) free(msg->private); - free(msg); + free(ldif); +} + +/* + add an empty element +*/ +static int msg_add_empty(struct ldb_message *msg, const char *name, unsigned flags) +{ + struct ldb_message_element *el2, *el; + + el2 = realloc_p(msg->elements, struct ldb_message_element, msg->num_elements+1); + if (!el2) { + errno = ENOMEM; + return -1; + } + + msg->elements = el2; + + el = &msg->elements[msg->num_elements]; + + el->name = name; + el->num_values = 0; + el->values = NULL; + el->flags = flags; + + msg->num_elements++; + + return 0; } /* read from a LDIF source, creating a ldb_message */ -struct ldb_message *ldif_read(int (*fgetc_fn)(void *), void *private) +struct ldb_ldif *ldif_read(int (*fgetc_fn)(void *), void *private) { + struct ldb_ldif *ldif; struct ldb_message *msg; char *attr=NULL, *chunk=NULL, *s; struct ldb_val value; + unsigned flags = 0; value.data = NULL; - msg = malloc_p(struct ldb_message); - if (!msg) return NULL; + ldif = malloc_p(struct ldb_ldif); + if (!ldif) return NULL; + + ldif->changetype = LDB_CHANGETYPE_NONE; + msg = &ldif->msg; msg->dn = NULL; msg->elements = NULL; @@ -383,22 +466,86 @@ struct ldb_message *ldif_read(int (*fgetc_fn)(void *), void *private) msg->dn = value.data; while (next_attr(&s, &attr, &value) == 0) { - msg->elements = realloc_p(msg->elements, - struct ldb_message_element, - msg->num_elements+1); - if (!msg->elements) { - goto failed; + struct ldb_message_element *el; + int empty = 0; + + if (strcmp(attr, "changetype") == 0) { + int i; + for (i=0;ldb_changetypes[i].name;i++) { + if (strcmp((char *)value.data, ldb_changetypes[i].name) == 0) { + ldif->changetype = ldb_changetypes[i].changetype; + break; + } + } + if (!ldb_changetypes[i].name) { + fprintf(stderr,"Bad changetype '%s'\n", + (char *)value.data); + } + flags = 0; + continue; + } + + if (strcmp(attr, "add") == 0) { + flags = LDB_FLAG_MOD_ADD; + empty = 1; + } + if (strcmp(attr, "delete") == 0) { + flags = LDB_FLAG_MOD_DELETE; + empty = 1; + } + if (strcmp(attr, "replace") == 0) { + flags = LDB_FLAG_MOD_REPLACE; + empty = 1; + } + if (strcmp(attr, "-") == 0) { + flags = 0; + continue; + } + + if (empty) { + if (msg_add_empty(msg, (char *)value.data, flags) != 0) { + goto failed; + } + continue; + } + + el = &msg->elements[msg->num_elements-1]; + + if (msg->num_elements > 0 && strcmp(attr, el->name) == 0 && + flags == el->flags) { + /* its a continuation */ + el->values = + realloc_p(el->values, struct ldb_val, el->num_values+1); + if (!el->values) { + goto failed; + } + el->values[el->num_values] = value; + el->num_values++; + } else { + /* its a new attribute */ + msg->elements = realloc_p(msg->elements, + struct ldb_message_element, + msg->num_elements+1); + if (!msg->elements) { + goto failed; + } + msg->elements[msg->num_elements].flags = flags; + msg->elements[msg->num_elements].name = attr; + el = &msg->elements[msg->num_elements]; + el->values = malloc_p(struct ldb_val); + if (!el->values) { + goto failed; + } + el->num_values = 1; + el->values[0] = value; + msg->num_elements++; } - msg->elements[msg->num_elements].flags = 0; - msg->elements[msg->num_elements].name = attr; - msg->elements[msg->num_elements].value = value; - msg->num_elements++; } - return msg; + return ldif; failed: - if (msg) ldif_read_free(msg); + if (ldif) ldif_read_free(ldif); return NULL; } @@ -417,7 +564,7 @@ static int fgetc_file(void *private) return fgetc(state->f); } -struct ldb_message *ldif_read_file(FILE *f) +struct ldb_ldif *ldif_read_file(FILE *f) { struct ldif_read_file_state state; state.f = f; @@ -441,7 +588,7 @@ static int fgetc_string(void *private) return EOF; } -struct ldb_message *ldif_read_string(const char *s) +struct ldb_ldif *ldif_read_string(const char *s) { struct ldif_read_string_state state; state.s = s; @@ -468,9 +615,9 @@ static int fprintf_file(void *private, const char *fmt, ...) return ret; } -int ldif_write_file(FILE *f, const struct ldb_message *msg) +int ldif_write_file(FILE *f, const struct ldb_ldif *ldif) { struct ldif_write_file_state state; state.f = f; - return ldif_write(fprintf_file, &state, msg); + return ldif_write(fprintf_file, &state, ldif); } diff --git a/source4/lib/ldb/include/ldb.h b/source4/lib/ldb/include/ldb.h index 35474d23c5..12064bbf75 100644 --- a/source4/lib/ldb/include/ldb.h +++ b/source4/lib/ldb/include/ldb.h @@ -73,7 +73,8 @@ struct ldb_val { struct ldb_message_element { unsigned int flags; char *name; - struct ldb_val value; + unsigned int num_values; + struct ldb_val *values; }; @@ -88,6 +89,20 @@ struct ldb_message { void *private; /* private to the backend */ }; +enum ldb_changetype { + LDB_CHANGETYPE_NONE=0, + LDB_CHANGETYPE_ADD, + LDB_CHANGETYPE_DELETE, + LDB_CHANGETYPE_MODIFY +}; + +/* + a ldif record - from ldif_read +*/ +struct ldb_ldif { + enum ldb_changetype changetype; + struct ldb_message msg; +}; enum ldb_scope {LDB_SCOPE_DEFAULT=-1, LDB_SCOPE_BASE=0, @@ -196,9 +211,9 @@ const char *ldb_errstring(struct ldb_context *ldb); */ int ldif_write(int (*fprintf_fn)(void *, const char *, ...), void *private, - const struct ldb_message *msg); -void ldif_read_free(struct ldb_message *msg); -struct ldb_message *ldif_read(int (*fgetc_fn)(void *), void *private); -struct ldb_message *ldif_read_file(FILE *f); -struct ldb_message *ldif_read_string(const char *s); -int ldif_write_file(FILE *f, const struct ldb_message *msg); + const struct ldb_ldif *ldif); +void ldif_read_free(struct ldb_ldif *); +struct ldb_ldif *ldif_read(int (*fgetc_fn)(void *), void *private); +struct ldb_ldif *ldif_read_file(FILE *f); +struct ldb_ldif *ldif_read_string(const char *s); +int ldif_write_file(FILE *f, const struct ldb_ldif *msg); diff --git a/source4/lib/ldb/ldb_ldap/ldb_ldap.c b/source4/lib/ldb/ldb_ldap/ldb_ldap.c index b2f7688497..e6cbb52cad 100644 --- a/source4/lib/ldb/ldb_ldap/ldb_ldap.c +++ b/source4/lib/ldb/ldb_ldap/ldb_ldap.c @@ -37,7 +37,7 @@ #if 0 /* - we don't need this right now, but will once we add more backend + we don't need this right now, but will once we add some backend options */ @@ -110,13 +110,16 @@ static int lldb_delete(struct ldb_context *ldb, const char *dn) */ static int lldb_msg_free(struct ldb_context *ldb, struct ldb_message *msg) { - int i; + int i, j; free(msg->dn); for (i=0;inum_elements;i++) { free(msg->elements[i].name); - if (msg->elements[i].value.data) { - free(msg->elements[i].value.data); + for (j=0;jelements[i].num_values;j++) { + if (msg->elements[i].values[j].data) { + free(msg->elements[i].values[j].data); + } } + free(msg->elements[i].values); } if (msg->elements) free(msg->elements); free(msg); @@ -155,7 +158,7 @@ static int lldb_add_msg_attr(struct ldb_message *msg, } el = realloc_p(msg->elements, struct ldb_message_element, - msg->num_elements + count); + msg->num_elements + 1); if (!el) { errno = ENOMEM; return -1; @@ -163,22 +166,34 @@ static int lldb_add_msg_attr(struct ldb_message *msg, msg->elements = el; + el = &msg->elements[msg->num_elements]; + + el->name = strdup(attr); + if (!el->name) { + errno = ENOMEM; + return -1; + } + el->flags = 0; + + el->num_values = 0; + el->values = malloc_array_p(struct ldb_val, count); + if (!el->values) { + errno = ENOMEM; + return -1; + } + for (i=0;ielements[msg->num_elements].name = strdup(attr); - if (!msg->elements[msg->num_elements].name) { + el->values[i].data = malloc(bval[i]->bv_len); + if (!el->values[i].data) { return -1; } - msg->elements[msg->num_elements].value.data = malloc(bval[i]->bv_len); - if (!msg->elements[msg->num_elements].value.data) { - free(msg->elements[msg->num_elements].name); - return -1; - } - memcpy(msg->elements[msg->num_elements].value.data, - bval[i]->bv_val, bval[i]->bv_len); - msg->elements[msg->num_elements].value.length = bval[i]->bv_len; - msg->num_elements++; + memcpy(el->values[i].data, bval[i]->bv_val, bval[i]->bv_len); + el->values[i].length = bval[i]->bv_len; + el->num_values++; } + msg->num_elements++; + return 0; } @@ -309,7 +324,7 @@ static void lldb_mods_free(LDAPMod **mods) static LDAPMod **lldb_msg_to_mods(const struct ldb_message *msg, int use_flags) { LDAPMod **mods; - int i, num_vals, num_mods = 0; + int i, j, num_mods = 0; /* allocate maximum number of elements needed */ mods = malloc_array_p(LDAPMod *, msg->num_elements+1); @@ -320,30 +335,7 @@ static LDAPMod **lldb_msg_to_mods(const struct ldb_message *msg, int use_flags) mods[0] = NULL; for (i=0;inum_elements;i++) { - - if (i > 0 && - (!use_flags || - (msg->elements[i].flags == msg->elements[i-1].flags)) && - strcmp(msg->elements[i].name, msg->elements[i-1].name) == 0) { - struct berval **b; - /* when attributes are repeated we need to extend the - existing bvals array */ - b = realloc_p(mods[num_mods-1]->mod_vals.modv_bvals, - struct berval *, num_vals+2); - if (!b) { - goto failed; - } - mods[num_mods-1]->mod_vals.modv_bvals = b; - b[num_vals+1] = NULL; - b[num_vals] = malloc_p(struct berval); - if (!b[num_vals]) goto failed; - b[num_vals]->bv_val = msg->elements[i].value.data; - b[num_vals]->bv_len = msg->elements[i].value.length; - num_vals++; - continue; - } - - num_vals = 1; + const struct ldb_message_element *el = &msg->elements[i]; mods[num_mods] = malloc_p(LDAPMod); if (!mods[num_mods]) { @@ -352,7 +344,7 @@ static LDAPMod **lldb_msg_to_mods(const struct ldb_message *msg, int use_flags) mods[num_mods+1] = NULL; mods[num_mods]->mod_op = LDAP_MOD_BVALUES; if (use_flags) { - switch (msg->elements[i].flags & LDB_FLAG_MOD_MASK) { + switch (el->flags & LDB_FLAG_MOD_MASK) { case LDB_FLAG_MOD_ADD: mods[num_mods]->mod_op |= LDAP_MOD_ADD; break; @@ -364,18 +356,22 @@ static LDAPMod **lldb_msg_to_mods(const struct ldb_message *msg, int use_flags) break; } } - mods[num_mods]->mod_type = msg->elements[i].name; - mods[num_mods]->mod_vals.modv_bvals = malloc_array_p(struct berval *, 2); + mods[num_mods]->mod_type = el->name; + mods[num_mods]->mod_vals.modv_bvals = malloc_array_p(struct berval *, + 1+el->num_values); if (!mods[num_mods]->mod_vals.modv_bvals) { goto failed; } - mods[num_mods]->mod_vals.modv_bvals[0] = malloc_p(struct berval); - if (!mods[num_mods]->mod_vals.modv_bvals[0]) { - goto failed; + + for (j=0;jnum_values;j++) { + mods[num_mods]->mod_vals.modv_bvals[j] = malloc_p(struct berval); + if (!mods[num_mods]->mod_vals.modv_bvals[j]) { + goto failed; + } + mods[num_mods]->mod_vals.modv_bvals[j]->bv_val = el->values[j].data; + mods[num_mods]->mod_vals.modv_bvals[j]->bv_len = el->values[j].length; } - mods[num_mods]->mod_vals.modv_bvals[0]->bv_val = msg->elements[i].value.data; - mods[num_mods]->mod_vals.modv_bvals[0]->bv_len = msg->elements[i].value.length; - mods[num_mods]->mod_vals.modv_bvals[1] = NULL; + mods[num_mods]->mod_vals.modv_bvals[j] = NULL; num_mods++; } diff --git a/source4/lib/ldb/ldb_tdb/ldb_index.c b/source4/lib/ldb/ldb_tdb/ldb_index.c index dda80a6b2a..8cda8abff8 100644 --- a/source4/lib/ldb/ldb_tdb/ldb_index.c +++ b/source4/lib/ldb/ldb_tdb/ldb_index.c @@ -74,13 +74,22 @@ static char *ldb_dn_key(const char *attr, const struct ldb_val *value) /* see if a attribute value is in the list of indexed attributes */ -static int ldb_msg_find_idx(const struct ldb_message *msg, const char *attr) +static int ldb_msg_find_idx(const struct ldb_message *msg, const char *attr, + int *v_idx) { - int i; + int i, j; for (i=0;inum_elements;i++) { - if (strcmp(msg->elements[i].name, "@IDXATTR") == 0 && - strcmp((char *)msg->elements[i].value.data, attr) == 0) { - return i; + if (strcmp(msg->elements[i].name, "@IDXATTR") == 0) { + const struct ldb_message_element *el = + &msg->elements[i]; + for (j=0;jnum_values;j++) { + if (strcmp((char *)el->values[j].data, attr) == 0) { + if (v_idx) { + *v_idx = j; + } + return i; + } + } } } return -1; @@ -95,7 +104,7 @@ static int ltdb_index_dn_simple(struct ldb_context *ldb, struct dn_list *list) { char *dn = NULL; - int ret, i; + int ret, i, j; struct ldb_message msg; list->count = 0; @@ -110,7 +119,7 @@ static int ltdb_index_dn_simple(struct ldb_context *ldb, /* if the attribute isn't in the list of indexed attributes then this node needs a full search */ - if (ldb_msg_find_idx(index_list, tree->u.simple.attr) == -1) { + if (ldb_msg_find_idx(index_list, tree->u.simple.attr, NULL) == -1) { return -1; } @@ -125,23 +134,30 @@ static int ltdb_index_dn_simple(struct ldb_context *ldb, return ret; } - list->dn = malloc_array_p(char *, msg.num_elements); - if (!list->dn) { - ltdb_search_dn1_free(ldb, &msg); - } - for (i=0;idn[list->count] = - strdup((char *)msg.elements[i].value.data); - if (!list->dn[list->count]) { - dn_list_free(list); - ltdb_search_dn1_free(ldb, &msg); - return -1; + + el = &msg.elements[i]; + + list->dn = malloc_array_p(char *, el->num_values); + if (!list->dn) { + break; + } + + for (j=0;jnum_values;j++) { + list->dn[list->count] = + strdup((char *)el->values[j].data); + if (!list->dn[list->count]) { + dn_list_free(list); + ltdb_search_dn1_free(ldb, &msg); + return -1; + } + list->count++; } - list->count++; } ltdb_search_dn1_free(ldb, &msg); @@ -470,18 +486,76 @@ int ltdb_search_indexed(struct ldb_context *ldb, return ret; } +/* + add a index element where this is the first indexed DN for this value +*/ +static int ltdb_index_add1_new(struct ldb_context *ldb, + struct ldb_message *msg, + struct ldb_message_element *el, + const char *dn) +{ + struct ldb_message_element *el2; + + /* add another entry */ + el2 = realloc_p(msg->elements, struct ldb_message_element, msg->num_elements+1); + if (!el2) { + return -1; + } + + msg->elements = el2; + msg->elements[msg->num_elements].name = "@IDX"; + msg->elements[msg->num_elements].num_values = 0; + msg->elements[msg->num_elements].values = malloc_p(struct ldb_val); + if (!msg->elements[msg->num_elements].values) { + return -1; + } + msg->elements[msg->num_elements].values[0].length = strlen(dn); + msg->elements[msg->num_elements].values[0].data = dn; + msg->elements[msg->num_elements].num_values = 1; + msg->num_elements++; + + return 0; +} + + +/* + add a index element where this is not the first indexed DN for this + value +*/ +static int ltdb_index_add1_add(struct ldb_context *ldb, + struct ldb_message *msg, + struct ldb_message_element *el, + int idx, + const char *dn) +{ + struct ldb_val *v2; + + v2 = realloc_p(msg->elements[idx].values, + struct ldb_val, + msg->elements[idx].num_values+1); + if (!v2) { + return -1; + } + msg->elements[idx].values = v2; + + msg->elements[idx].values[msg->elements[idx].num_values].length = strlen(dn); + msg->elements[idx].values[msg->elements[idx].num_values].data = dn; + msg->elements[idx].num_values++; + + return 0; +} + /* add an index entry for one message element */ static int ltdb_index_add1(struct ldb_context *ldb, const char *dn, - struct ldb_message_element *el) + struct ldb_message_element *el, int v_idx) { struct ldb_message msg; char *dn_key; - int ret; - struct ldb_message_element *el2; + int ret, i; - dn_key = ldb_dn_key(el->name, &el->value); + dn_key = ldb_dn_key(el->name, &el->values[v_idx]); if (!dn_key) { return -1; } @@ -493,36 +567,37 @@ static int ltdb_index_add1(struct ldb_context *ldb, const char *dn, } if (ret == 0) { - msg.dn = dn_key; + msg.dn = strdup(dn_key); + if (!msg.dn) { + free(dn_key); + errno = ENOMEM; + return -1; + } msg.num_elements = 0; msg.elements = NULL; msg.private = NULL; } - /* add another entry */ - el2 = realloc_p(msg.elements, struct ldb_message_element, msg.num_elements+1); - if (!el2) { - if (ret == 1) { - ltdb_search_dn1_free(ldb, &msg); + free(dn_key); + + for (i=0;inum_elements;i++) { - ret = ldb_msg_find_idx(&index_list, msg->elements[i].name); + ret = ldb_msg_find_idx(&index_list, msg->elements[i].name, NULL); if (ret == -1) { continue; } - ret = ltdb_index_add1(ldb, msg->dn, &msg->elements[i]); - if (ret == -1) { - ltdb_search_dn1_free(ldb, &index_list); - return -1; + for (j=0;jelements[i].num_values;j++) { + ret = ltdb_index_add1(ldb, msg->dn, &msg->elements[i], j); + if (ret == -1) { + ltdb_search_dn1_free(ldb, &index_list); + return -1; + } } } + ltdb_search_dn1_free(ldb, &index_list); + return 0; } @@ -562,13 +641,13 @@ int ltdb_index_add(struct ldb_context *ldb, const struct ldb_message *msg) delete an index entry for one message element */ static int ltdb_index_del1(struct ldb_context *ldb, const char *dn, - struct ldb_message_element *el) + struct ldb_message_element *el, int v_idx) { struct ldb_message msg; char *dn_key; - int ret, i; + int ret, i, j; - dn_key = ldb_dn_key(el->name, &el->value); + dn_key = ldb_dn_key(el->name, &el->values[v_idx]); if (!dn_key) { return -1; } @@ -586,19 +665,22 @@ static int ltdb_index_del1(struct ldb_context *ldb, const char *dn, return 0; } - i = ldb_msg_find_idx(&msg, dn); + i = ldb_msg_find_idx(&msg, dn, &j); if (i == -1) { /* it ain't there. hmmm */ ltdb_search_dn1_free(ldb, &msg); return 0; } - if (i != msg.num_elements - 1) { - memmove(&msg.elements[i], &msg.elements[i+1], sizeof(msg.elements[i])); + if (j != msg.elements[i].num_values - 1) { + memmove(&msg.elements[i].values[j], + &msg.elements[i].values[j+1], + (msg.elements[i].num_values-1) * + sizeof(msg.elements[i].values[0])); } - msg.num_elements--; + msg.elements[i].num_values--; - if (msg.num_elements == 0) { + if (msg.elements[i].num_values == 0) { ret = ltdb_delete_noindex(ldb, dn_key); } else { ret = ltdb_store(ldb, &msg, TDB_REPLACE); @@ -615,7 +697,7 @@ static int ltdb_index_del1(struct ldb_context *ldb, const char *dn, */ int ltdb_index_del(struct ldb_context *ldb, const struct ldb_message *msg) { - int ret, i; + int ret, i, j; struct ldb_message index_list; /* find the list of indexed fields */ @@ -626,14 +708,16 @@ int ltdb_index_del(struct ldb_context *ldb, const struct ldb_message *msg) } for (i=0;inum_elements;i++) { - ret = ldb_msg_find_idx(&index_list, msg->elements[i].name); + ret = ldb_msg_find_idx(&index_list, msg->elements[i].name, NULL); if (ret == -1) { continue; } - ret = ltdb_index_del1(ldb, msg->dn, &msg->elements[i]); - if (ret == -1) { - ltdb_search_dn1_free(ldb, &index_list); - return -1; + for (j=0;jelements[i].num_values;j++) { + ret = ltdb_index_del1(ldb, msg->dn, &msg->elements[i], j); + if (ret == -1) { + ltdb_search_dn1_free(ldb, &index_list); + return -1; + } } } diff --git a/source4/lib/ldb/ldb_tdb/ldb_match.c b/source4/lib/ldb/ldb_tdb/ldb_match.c index 89d204f56a..6f29726ee7 100644 --- a/source4/lib/ldb/ldb_tdb/ldb_match.c +++ b/source4/lib/ldb/ldb_tdb/ldb_match.c @@ -39,7 +39,7 @@ see if two ldb_val structures contain the same data return 1 for a match, 0 for a mis-match */ -static int ldb_val_equal(struct ldb_val *v1, struct ldb_val *v2) +int ldb_val_equal(const struct ldb_val *v1, const struct ldb_val *v2) { if (v1->length != v2->length) return 0; @@ -108,7 +108,7 @@ static int match_leaf(struct ldb_context *ldb, const char *base, enum ldb_scope scope) { - int i; + int i, j; if (!scope_match(msg->dn, base, scope)) { return 0; @@ -122,10 +122,16 @@ static int match_leaf(struct ldb_context *ldb, } for (i=0;inum_elements;i++) { - if (strcmp(msg->elements[i].name, tree->u.simple.attr) == 0 && - (strcmp(tree->u.simple.value.data, "*") == 0 || - ldb_val_equal(&msg->elements[i].value, &tree->u.simple.value))) { - return 1; + if (strcmp(msg->elements[i].name, tree->u.simple.attr) == 0) { + if (strcmp(tree->u.simple.value.data, "*") == 0) { + return 1; + } + for (j=0;jelements[i].num_values;j++) { + if (ldb_val_equal(&msg->elements[i].values[j], + &tree->u.simple.value)) { + return 1; + } + } } } diff --git a/source4/lib/ldb/ldb_tdb/ldb_pack.c b/source4/lib/ldb/ldb_tdb/ldb_pack.c index b0c825e8e2..1b0c8a1857 100644 --- a/source4/lib/ldb/ldb_tdb/ldb_pack.c +++ b/source4/lib/ldb/ldb_tdb/ldb_pack.c @@ -41,13 +41,16 @@ /* pack a ldb message into a linear buffer in a TDB_DATA + note that this routine avoids saving elements with zero values, + as these are equivalent to having no element + caller frees the data buffer after use */ int ltdb_pack_data(struct ldb_context *ctx, const struct ldb_message *message, struct TDB_DATA *data) { - int i; + int i, j; size_t size; char *p; @@ -55,8 +58,13 @@ int ltdb_pack_data(struct ldb_context *ctx, size = 8; for (i=0;inum_elements;i++) { - size += 1 + strlen(message->elements[i].name); - size += 4 + message->elements[i].value.length + 1; + if (message->elements[i].num_values == 0) { + continue; + } + size += 1 + strlen(message->elements[i].name) + 4; + for (j=0;jelements[i].num_values;j++) { + size += 4 + message->elements[i].values[j].length + 1; + } } /* allocate it */ @@ -73,28 +81,50 @@ int ltdb_pack_data(struct ldb_context *ctx, p += 8; for (i=0;inum_elements;i++) { - size_t len = strlen(message->elements[i].name); + size_t len; + if (message->elements[i].num_values == 0) { + continue; + } + len = strlen(message->elements[i].name); memcpy(p, message->elements[i].name, len+1); p += len + 1; - SIVAL(p, 0, message->elements[i].value.length); - memcpy(p+4, message->elements[i].value.data, - message->elements[i].value.length); - p[4+message->elements[i].value.length] = 0; - p += 4 + message->elements[i].value.length + 1; + SIVAL(p, 0, message->elements[i].num_values); + p += 4; + for (j=0;jelements[i].num_values;j++) { + SIVAL(p, 0, message->elements[i].values[j].length); + memcpy(p+4, message->elements[i].values[j].data, + message->elements[i].values[j].length); + p[4+message->elements[i].values[j].length] = 0; + p += 4 + message->elements[i].values[j].length + 1; + } } return 0; } +/* + free the memory allocated from a ltdb_unpack_data() +*/ +void ltdb_unpack_data_free(struct ldb_message *message) +{ + int i; + + for (i=0;inum_elements;i++) { + if (message->elements[i].values) free(message->elements[i].values); + } + if (message->elements) free(message->elements); +} + /* unpack a ldb message from a linear buffer in TDB_DATA note that this does not fill in the class and key elements - caller frees. Memory for the elements[] array is malloced, - but the memory for the elements is re-used from the TDB_DATA - data. This means the caller only has to free the elements array + caller frees. Memory for the elements[] and values[] arrays are + malloced, but the memory for the elements is re-used from the + TDB_DATA data. This means the caller only has to free the elements + and values arrays. This can be done with ltdb_unpack_data_free() */ int ltdb_unpack_data(struct ldb_context *ctx, const struct TDB_DATA *data, @@ -102,7 +132,7 @@ int ltdb_unpack_data(struct ldb_context *ctx, { char *p; unsigned int remaining; - int i; + int i, j; message->elements = NULL; @@ -145,30 +175,44 @@ int ltdb_unpack_data(struct ldb_context *ctx, for (i=0;inum_elements;i++) { size_t len; - if (remaining < 6) { + if (remaining < 10) { errno = EIO; goto failed; } len = strnlen(p, remaining-6); + message->elements[i].flags = 0; message->elements[i].name = p; remaining -= len + 1; p += len + 1; - len = IVAL(p, 0); - if (len > remaining-5) { - errno = EIO; - goto failed; + message->elements[i].num_values = IVAL(p, 0); + message->elements[i].values = NULL; + if (message->elements[i].num_values != 0) { + message->elements[i].values = malloc_array_p(struct ldb_val, + message->elements[i].num_values); + if (!message->elements[i].values) { + errno = ENOMEM; + goto failed; + } + } + p += 4; + for (j=0;jelements[i].num_values;j++) { + len = IVAL(p, 0); + if (len > remaining-5) { + errno = EIO; + goto failed; + } + + message->elements[i].values[j].length = len; + message->elements[i].values[j].data = p+4; + remaining -= len+4+1; + p += len+4+1; } - message->elements[i].value.length = len; - message->elements[i].value.data = p+4; - remaining -= len+4+1; - p += len+4+1; } return 0; failed: - if (message->elements) { - free(message->elements); - } + ltdb_unpack_data_free(message); + return -1; } diff --git a/source4/lib/ldb/ldb_tdb/ldb_search.c b/source4/lib/ldb/ldb_tdb/ldb_search.c index 952053c920..d7a7b7ffbd 100644 --- a/source4/lib/ldb/ldb_tdb/ldb_search.c +++ b/source4/lib/ldb/ldb_tdb/ldb_search.c @@ -40,11 +40,15 @@ */ static void msg_free_all_parts(struct ldb_message *msg) { - int i; + int i, j; if (msg->dn) free(msg->dn); for (i=0;inum_elements;i++) { if (msg->elements[i].name) free(msg->elements[i].name); - if (msg->elements[i].value.data) free(msg->elements[i].value.data); + for (j=0;jelements[i].num_values;j++) { + if (msg->elements[i].values[j].data) + free(msg->elements[i].values[j].data); + } + if (msg->elements[i].values) free(msg->elements[i].values); } free(msg->elements); free(msg); @@ -53,6 +57,7 @@ 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) @@ -69,7 +74,7 @@ int ldb_msg_find_attr(const struct ldb_message *msg, const char *attr) /* duplicate a ldb_val structure */ -static struct ldb_val ldb_val_dup(const struct ldb_val *v) +struct ldb_val ldb_val_dup(const struct ldb_val *v) { struct ldb_val v2; v2.length = v->length; @@ -98,7 +103,8 @@ static struct ldb_val ldb_val_dup(const struct ldb_val *v) */ static int msg_add_element(struct ldb_message *ret, const struct ldb_message_element *el) { - struct ldb_message_element *e2; + int i; + struct ldb_message_element *e2, *elnew; e2 = realloc_p(ret->elements, struct ldb_message_element, ret->num_elements+1); if (!e2) { @@ -106,15 +112,31 @@ static int msg_add_element(struct ldb_message *ret, const struct ldb_message_ele } ret->elements = e2; - e2[ret->num_elements].name = strdup(el->name); - if (!e2[ret->num_elements].name) { + elnew = &e2[ret->num_elements]; + + elnew->name = strdup(el->name); + if (!elnew->name) { return -1; } - e2[ret->num_elements].value = ldb_val_dup(&el->value); - if (e2[ret->num_elements].value.length != el->value.length) { - return -1; + + if (el->num_values) { + elnew->values = malloc_array_p(struct ldb_val, el->num_values); + if (!elnew->values) { + return -1; + } + } else { + elnew->values = NULL; } + for (i=0;inum_values;i++) { + elnew->values[i] = ldb_val_dup(&el->values[i]); + if (elnew->values[i].length != el->values[i].length) { + return -1; + } + } + + elnew->num_values = el->num_values; + ret->num_elements++; return 0; @@ -215,8 +237,12 @@ int ltdb_has_wildcard(const struct ldb_val *val) */ void ltdb_search_dn1_free(struct ldb_context *ldb, struct ldb_message *msg) { - free(msg->dn); - free(msg->private); + int i; + if (msg->dn) free(msg->dn); + if (msg->private) free(msg->private); + for (i=0;inum_elements;i++) { + if (msg->elements[i].values) free(msg->elements[i].values); + } if (msg->elements) free(msg->elements); } @@ -375,7 +401,7 @@ static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, voi /* see if it matches the given expression */ if (!ldb_message_match(sinfo->ldb, &msg, sinfo->tree, sinfo->base, sinfo->scope)) { - if (msg.elements) free(msg.elements); + ltdb_unpack_data_free(&msg); return 0; } @@ -385,7 +411,7 @@ static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, voi sinfo->failures++; } - if (msg.elements) free(msg.elements); + ltdb_unpack_data_free(&msg); return ret; } diff --git a/source4/lib/ldb/ldb_tdb/ldb_tdb.c b/source4/lib/ldb/ldb_tdb/ldb_tdb.c index 17931352f7..95dce498f1 100644 --- a/source4/lib/ldb/ldb_tdb/ldb_tdb.c +++ b/source4/lib/ldb/ldb_tdb/ldb_tdb.c @@ -58,6 +58,44 @@ struct TDB_DATA ltdb_key(const char *dn) return key; } +/* + lock the database for write - currently a single lock is used +*/ +static int ltdb_lock(struct ldb_context *ldb) +{ + struct ltdb_private *ltdb = ldb->private; + TDB_DATA key; + int ret; + + key = ltdb_key("LDBLOCK"); + if (!key.dptr) { + return -1; + } + + ret = tdb_chainlock(ltdb->tdb, key); + + free(key.dptr); + + return ret; +} + +/* + unlock the database after a ltdb_lock() +*/ +static void ltdb_unlock(struct ldb_context *ldb) +{ + struct ltdb_private *ltdb = ldb->private; + TDB_DATA key; + + key = ltdb_key("LDBLOCK"); + if (!key.dptr) { + return; + } + + tdb_chainunlock(ltdb->tdb, key); + + free(key.dptr); +} /* store a record into the db @@ -102,7 +140,17 @@ done: */ static int ltdb_add(struct ldb_context *ldb, const struct ldb_message *msg) { - return ltdb_store(ldb, msg, TDB_INSERT); + int ret; + + if (ltdb_lock(ldb) != 0) { + return -1; + } + + ret = ltdb_store(ldb, msg, TDB_INSERT); + + ltdb_unlock(ldb); + + return ret; } @@ -135,18 +183,22 @@ static int ltdb_delete(struct ldb_context *ldb, const char *dn) int ret; struct ldb_message msg; + if (ltdb_lock(ldb) != 0) { + return -1; + } + /* in case any attribute of the message was indexed, we need to fetch the old record */ ret = ltdb_search_dn1(ldb, dn, &msg); if (ret != 1) { /* not finding the old record is an error */ - return -1; + goto failed; } ret = ltdb_delete_noindex(ldb, dn); if (ret == -1) { ltdb_search_dn1_free(ldb, &msg); - return -1; + goto failed; } /* remove any indexed attributes */ @@ -154,57 +206,244 @@ static int ltdb_delete(struct ldb_context *ldb, const char *dn) ltdb_search_dn1_free(ldb, &msg); + ltdb_unlock(ldb); return ret; + +failed: + ltdb_unlock(ldb); + return -1; +} + + +/* + find an element by attribute name. At the moment this does a linear search, it should + be re-coded to use a binary search once all places that modify records guarantee + sorted order + + return the index of the first matching element if found, otherwise -1 +*/ +static int find_element(const struct ldb_message *msg, const char *name) +{ + int i; + for (i=0;inum_elements;i++) { + if (strcmp(msg->elements[i].name, name) == 0) { + return i; + } + } + return -1; +} + + +/* + add an element to an existing record. Assumes a elements array that we + can call re-alloc on, and assumed that we can re-use the data pointers from the + passed in additional values. Use with care! + + returns 0 on success, -1 on failure (and sets errno) +*/ +static int msg_add_element(struct ldb_message *msg, struct ldb_message_element *el) +{ + struct ldb_message_element *e2; + int i; + + e2 = realloc_p(msg->elements, struct ldb_message_element, + msg->num_elements+1); + if (!e2) { + errno = ENOMEM; + return -1; + } + + msg->elements = e2; + + e2 = &msg->elements[msg->num_elements]; + + e2->name = el->name; + e2->flags = el->flags; + e2->values = NULL; + if (el->num_values != 0) { + e2->values = malloc_array_p(struct ldb_val, el->num_values); + if (!e2->values) { + free(e2->name); + errno = ENOMEM; + return -1; + } + } + for (i=0;inum_values;i++) { + e2->values[i] = el->values[i]; + } + e2->num_values = el->num_values; + + msg->num_elements++; + + return 0; +} + +/* + delete all elements having a specified attribute name +*/ +static int msg_delete_attribute(struct ldb_message *msg, const char *name) +{ + int i, count=0; + struct ldb_message_element *el2; + + el2 = malloc_array_p(struct ldb_message_element, msg->num_elements); + if (!el2) { + errno = ENOMEM; + return -1; + } + + for (i=0;inum_elements;i++) { + if (strcmp(msg->elements[i].name, name) != 0) { + el2[count++] = msg->elements[i]; + } else { + if (msg->elements[i].values) free(msg->elements[i].values); + } + } + + msg->num_elements = count; + if (msg->elements) free(msg->elements); + msg->elements = el2; + + return 0; } +/* + delete all elements matching an attribute name/value + + return 0 on success, -1 on failure +*/ +static int msg_delete_element(struct ldb_message *msg, + const char *name, + const struct ldb_val *val) +{ + int i; + struct ldb_message_element *el; + + i = find_element(msg, name); + if (i == -1) { + return -1; + } + + el = &msg->elements[i]; + + for (i=0;inum_values;i++) { + if (ldb_val_equal(&el->values[i], val)) { + if (inum_values-1) { + memmove(&el->values[i], &el->values[i+1], + sizeof(el->values[i])*el->num_values-(i+1)); + } + el->num_values--; + return 0; + } + } + + return -1; +} /* modify a record + + yuck - this is O(n^2). Luckily n is usually small so we probably + get away with it, but if we ever have really large attribute lists + then we'll need to look at this again */ static int ltdb_modify(struct ldb_context *ldb, const struct ldb_message *msg) { struct ltdb_private *ltdb = ldb->private; TDB_DATA tdb_key, tdb_data; struct ldb_message msg2; - int ret; + int ret, i, j; + + if (ltdb_lock(ldb) != 0) { + return -1; + } tdb_key = ltdb_key(msg->dn); if (!tdb_key.dptr) { - return -1; + goto unlock_fail; } tdb_data = tdb_fetch(ltdb->tdb, tdb_key); if (!tdb_data.dptr) { free(tdb_key.dptr); - return -1; + goto unlock_fail; } ret = ltdb_unpack_data(ldb, &tdb_data, &msg2); if (ret == -1) { free(tdb_key.dptr); free(tdb_data.dptr); - return -1; + goto unlock_fail; } -#if 0 + msg2.dn = msg->dn; + for (i=0;inum_elements;i++) { switch (msg->elements[i].flags & LDB_FLAG_MOD_MASK) { + case LDB_FLAG_MOD_ADD: + /* add this element to the message. fail if it + already exists */ ret = find_element(&msg2, msg->elements[i].name); if (ret != -1) { errno = EEXIST; goto failed; } - + if (msg_add_element(&msg2, &msg->elements[i]) != 0) { + goto failed; + } + break; + + case LDB_FLAG_MOD_REPLACE: + /* replace all elements of this attribute name with the elements + listed */ + if (msg_delete_attribute(&msg2, msg->elements[i].name) != 0) { + goto failed; + } + /* add the replacement element */ + if (msg_add_element(&msg2, &msg->elements[i]) != 0) { + goto failed; + } + break; + + case LDB_FLAG_MOD_DELETE: + /* we could be being asked to delete all + values or just some values */ + if (msg->elements[i].num_values == 0) { + if (msg_delete_attribute(&msg2, + msg->elements[i].name) != 0) { + goto failed; + } + break; + } + for (j=0;jelements[i].num_values;j++) { + if (msg_delete_element(&msg2, + msg->elements[i].name, + &msg->elements[i].values[j]) != 0) { + goto failed; + } + } + break; } } -failed: -#endif + /* we've made all the mods - save the modified record back into the database */ + ret = ltdb_store(ldb, &msg2, TDB_MODIFY); + + free(tdb_key.dptr); + free(tdb_data.dptr); + ltdb_unpack_data_free(&msg2); + ltdb_unlock(ldb); + return ret; + +failed: free(tdb_key.dptr); free(tdb_data.dptr); - if (msg2.elements) free(msg2.elements); + ltdb_unpack_data_free(&msg2); + +unlock_fail: + ltdb_unlock(ldb); return -1; } diff --git a/source4/lib/ldb/ldb_tdb/ldbadd.c b/source4/lib/ldb/ldb_tdb/ldbadd.c deleted file mode 100644 index 3959a17525..0000000000 --- a/source4/lib/ldb/ldb_tdb/ldbadd.c +++ /dev/null @@ -1,55 +0,0 @@ - /* - Unix SMB/CIFS implementation. - - a utility to add elements to a ldb - - Copyright (C) Andrew Tridgell 2004 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - - int main(void) -{ - static struct ldb_context *ldb; - struct ldb_message *msg; - int ret; - int count=0, failures=0; - - ldb = ltdb_connect("tdb://test.ldb", 0, NULL); - - if (!ldb) { - perror("ldb_connect"); - exit(1); - } - - while ((msg = ldif_read(stdin))) { - ret = ldb->ops->add(ldb, msg); - if (ret != 0) { - fprintf(stderr, "Failed to add record '%s'\n", msg->dn); - failures++; - } else { - count++; - } - ldif_read_free(msg); - } - - ldb->ops->close(ldb); - - printf("Added %d records with %d failures\n", count, failures); - - return 0; -} diff --git a/source4/lib/ldb/ldb_tdb/ldbdel.c b/source4/lib/ldb/ldb_tdb/ldbdel.c deleted file mode 100644 index 8f8a03913f..0000000000 --- a/source4/lib/ldb/ldb_tdb/ldbdel.c +++ /dev/null @@ -1,50 +0,0 @@ - /* - Unix SMB/CIFS implementation. - - a utility to delete elements in a ldb - - Copyright (C) Andrew Tridgell 2004 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - - int main(int argc, const char *argv[]) -{ - static struct ldb_context *ldb; - int ret, i; - - if (argc < 2) { - printf("Usage: ldbdel \n"); - exit(1); - } - - ldb = ltdb_connect("tdb://test.ldb", 0, NULL); - if (!ldb) { - perror("ldb_connect"); - exit(1); - } - - for (i=1;iops->delete(ldb, argv[i]); - if (ret != 0) { - printf("delete of '%s' failed\n", argv[i]); - } - } - - ldb->ops->close(ldb); - return 0; -} diff --git a/source4/lib/ldb/ldb_tdb/ldbsearch.c b/source4/lib/ldb/ldb_tdb/ldbsearch.c deleted file mode 100644 index a6d63e78d5..0000000000 --- a/source4/lib/ldb/ldb_tdb/ldbsearch.c +++ /dev/null @@ -1,73 +0,0 @@ - /* - Unix SMB/CIFS implementation. - - simple ldb search tool - - Copyright (C) Andrew Tridgell 2004 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - - int main(int argc, const char *argv[]) -{ - static struct ldb_context *ldb; - struct ldb_message **msgs; - int ret, i; - const char *expression; - const char **attrs = NULL; - - if (argc < 2) { - printf("Usage: ldbsearch [attrs...]\n"); - exit(1); - } - - if (argc > 2) { - attrs = argv+2; - } - - expression = argv[1]; - - ldb = ltdb_connect("tdb://test.ldb", 0, NULL); - - if (!ldb) { - perror("ldb_connect"); - exit(1); - } - - ret = ldb->ops->search(ldb, expression, attrs, &msgs); - - if (ret == -1) { - printf("search failed\n"); - exit(1); - } - - printf("# returned %d records\n", ret); - - for (i=0;iops->search_free(ldb, msgs); - if (ret == -1) { - fprintf(stderr, "search_free failed\n"); - exit(1); - } - - ldb->ops->close(ldb); - return 0; -} diff --git a/source4/lib/ldb/tests/test-generic.sh b/source4/lib/ldb/tests/test-generic.sh new file mode 100644 index 0000000000..41f5707e9c --- /dev/null +++ b/source4/lib/ldb/tests/test-generic.sh @@ -0,0 +1,8 @@ +echo "Adding base elements" +bin/ldbadd < tests/test.ldif + +echo "Modifying elements" +bin/ldbmodify < tests/test-modify.ldif + +echo "Showing modified record" +bin/ldbsearch '(uid=uham)' diff --git a/source4/lib/ldb/tests/test-ldap.sh b/source4/lib/ldb/tests/test-ldap.sh new file mode 100755 index 0000000000..29b40ff455 --- /dev/null +++ b/source4/lib/ldb/tests/test-ldap.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +tests/init_slapd.sh +tests/start_slapd.sh + +export LDB_URL=`tests/ldapi_url.sh` + +. tests/test-generic.sh diff --git a/source4/lib/ldb/tests/test-modify.ldif b/source4/lib/ldb/tests/test-modify.ldif new file mode 100644 index 0000000000..521c6d8b56 --- /dev/null +++ b/source4/lib/ldb/tests/test-modify.ldif @@ -0,0 +1,14 @@ +dn: cn=Ursula Hampster,ou=Alumni Association,ou=People,o=University of Michiga + n,c=US +changetype: modify +add: drink +drink: mango lassi +- +delete: pager +- +replace: telephonenumber +telephonenumber: +61 2 6260 6012 +telephonenumber: +61 412 666 929 +- +delete: telephonenumber +telephonenumber: +61 2 6260 6012 diff --git a/source4/lib/ldb/tests/test-tdb.sh b/source4/lib/ldb/tests/test-tdb.sh new file mode 100755 index 0000000000..1e21accac5 --- /dev/null +++ b/source4/lib/ldb/tests/test-tdb.sh @@ -0,0 +1,8 @@ +#!/bin/sh + + +export LDB_URL="tdb://test.ldb" + +rm -f test.ldb + +. tests/test-generic.sh diff --git a/source4/lib/ldb/tools/ldbadd.c b/source4/lib/ldb/tools/ldbadd.c index 3eb7cb8de2..92ed29e6b8 100644 --- a/source4/lib/ldb/tools/ldbadd.c +++ b/source4/lib/ldb/tools/ldbadd.c @@ -37,7 +37,7 @@ int main(void) { static struct ldb_context *ldb; - struct ldb_message *msg; + struct ldb_ldif *ldif; int ret; int count=0, failures=0; const char *ldb_url; @@ -54,16 +54,23 @@ exit(1); } - while ((msg = ldif_read_file(stdin))) { - ret = ldb_add(ldb, msg); + while ((ldif = ldif_read_file(stdin))) { + + if (ldif->changetype != LDB_CHANGETYPE_ADD && + ldif->changetype != LDB_CHANGETYPE_NONE) { + fprintf(stderr, "Only CHANGETYPE_ADD records allowed\n"); + break; + } + + ret = ldb_add(ldb, &ldif->msg); if (ret != 0) { fprintf(stderr, "ERR: \"%s\" on DN %s\n", - ldb_errstring(ldb), msg->dn); + ldb_errstring(ldb), ldif->msg.dn); failures++; } else { count++; } - ldif_read_free(msg); + ldif_read_free(ldif); } ldb_close(ldb); diff --git a/source4/lib/ldb/tools/ldbmodify.c b/source4/lib/ldb/tools/ldbmodify.c new file mode 100644 index 0000000000..e1cff655db --- /dev/null +++ b/source4/lib/ldb/tools/ldbmodify.c @@ -0,0 +1,85 @@ +/* + 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" + + 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"; + } + + ldb = ldb_connect(ldb_url, 0, NULL); + + if (!ldb) { + perror("ldb_connect"); + exit(1); + } + + while ((ldif = ldif_read_file(stdin))) { + 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), ldif->msg.dn); + failures++; + } else { + count++; + } + ldif_read_free(ldif); + } + + ldb_close(ldb); + + printf("Modified %d records with %d failures\n", count, failures); + + return 0; +} diff --git a/source4/lib/ldb/tools/ldbsearch.c b/source4/lib/ldb/tools/ldbsearch.c index d7d3c83162..f4eb8f00db 100644 --- a/source4/lib/ldb/tools/ldbsearch.c +++ b/source4/lib/ldb/tools/ldbsearch.c @@ -45,7 +45,7 @@ const char *ldb_url; const char *basedn = NULL; int opt; - enum ldb_scope scope = LDB_SCOPE_DEFAULT; + enum ldb_scope scope = LDB_SCOPE_SUBTREE; ldb_url = getenv("LDB_URL"); if (!ldb_url) { @@ -98,15 +98,20 @@ ret = ldb_search(ldb, basedn, scope, expression, attrs, &msgs); if (ret == -1) { - printf("search failed\n"); + printf("search failed - %s\n", ldb_errstring(ldb)); exit(1); } printf("# returned %d records\n", ret); for (i=0;i 0) { -- cgit