mirror of
https://github.com/samba-team/samba.git
synced 2024-12-27 03:21:53 +03:00
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 commit is contained in:
parent
3355fec421
commit
e9e85c4644
@ -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)
|
||||
|
||||
|
@ -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;i<msg->num_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;j<msg->elements[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;i<msg->num_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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;i<msg->num_elements;i++) {
|
||||
free(msg->elements[i].name);
|
||||
if (msg->elements[i].value.data) {
|
||||
free(msg->elements[i].value.data);
|
||||
for (j=0;j<msg->elements[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,21 +166,33 @@ static int lldb_add_msg_attr(struct ldb_message *msg,
|
||||
|
||||
msg->elements = el;
|
||||
|
||||
for (i=0;i<count;i++) {
|
||||
msg->elements[msg->num_elements].name = strdup(attr);
|
||||
if (!msg->elements[msg->num_elements].name) {
|
||||
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++;
|
||||
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;i<count;i++) {
|
||||
el->values[i].data = malloc(bval[i]->bv_len);
|
||||
if (!el->values[i].data) {
|
||||
return -1;
|
||||
}
|
||||
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;i<msg->num_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;j<el->num_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++;
|
||||
}
|
||||
|
||||
|
@ -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;i<msg->num_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;j<el->num_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;i<msg.num_elements;i++) {
|
||||
struct ldb_message_element *el;
|
||||
|
||||
if (strcmp(msg.elements[i].name, "@IDX") != 0) {
|
||||
continue;
|
||||
}
|
||||
list->dn[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;j<el->num_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;i<msg.num_elements;i++) {
|
||||
if (strcmp("@IDX", msg.elements[i].name) == 0) {
|
||||
break;
|
||||
}
|
||||
free(dn_key);
|
||||
return -1;
|
||||
}
|
||||
|
||||
msg.elements = el2;
|
||||
msg.elements[msg.num_elements].name = "@IDX";
|
||||
msg.elements[msg.num_elements].value.length = strlen(dn);
|
||||
msg.elements[msg.num_elements].value.data = dn;
|
||||
msg.num_elements++;
|
||||
|
||||
ret = ltdb_store(ldb, &msg, TDB_REPLACE);
|
||||
|
||||
if (msg.num_elements == 1) {
|
||||
free(msg.elements);
|
||||
if (i == msg.num_elements) {
|
||||
ret = ltdb_index_add1_new(ldb, &msg, el, dn);
|
||||
} else {
|
||||
ltdb_search_dn1_free(ldb, &msg);
|
||||
ret = ltdb_index_add1_add(ldb, &msg, el, i, dn);
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
ret = ltdb_store(ldb, &msg, TDB_REPLACE);
|
||||
}
|
||||
|
||||
ltdb_search_dn1_free(ldb, &msg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -532,7 +607,7 @@ static int ltdb_index_add1(struct ldb_context *ldb, const char *dn,
|
||||
*/
|
||||
int ltdb_index_add(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 */
|
||||
@ -543,17 +618,21 @@ int ltdb_index_add(struct ldb_context *ldb, const struct ldb_message *msg)
|
||||
}
|
||||
|
||||
for (i=0;i<msg->num_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;j<msg->elements[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;i<msg->num_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;j<msg->elements[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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;i<msg->num_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;j<msg->elements[i].num_values;j++) {
|
||||
if (ldb_val_equal(&msg->elements[i].values[j],
|
||||
&tree->u.simple.value)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;i<message->num_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;j<message->elements[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;i<message->num_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;j<message->elements[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;i<message->num_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;i<message->num_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;j<message->elements[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;
|
||||
}
|
||||
|
@ -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;i<msg->num_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;j<msg->elements[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;i<el->num_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;i<msg->num_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;
|
||||
}
|
||||
|
@ -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;i<msg->num_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;i<el->num_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;i<msg->num_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;i<el->num_values;i++) {
|
||||
if (ldb_val_equal(&el->values[i], val)) {
|
||||
if (i<el->num_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;i<msg->num_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;j<msg->elements[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);
|
||||
if (msg2.elements) free(msg2.elements);
|
||||
ltdb_unpack_data_free(&msg2);
|
||||
ltdb_unlock(ldb);
|
||||
|
||||
return ret;
|
||||
|
||||
failed:
|
||||
free(tdb_key.dptr);
|
||||
free(tdb_data.dptr);
|
||||
ltdb_unpack_data_free(&msg2);
|
||||
|
||||
unlock_fail:
|
||||
ltdb_unlock(ldb);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
@ -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 <dn...>\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ldb = ltdb_connect("tdb://test.ldb", 0, NULL);
|
||||
if (!ldb) {
|
||||
perror("ldb_connect");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (i=1;i<argc;i++) {
|
||||
ret = ldb->ops->delete(ldb, argv[i]);
|
||||
if (ret != 0) {
|
||||
printf("delete of '%s' failed\n", argv[i]);
|
||||
}
|
||||
}
|
||||
|
||||
ldb->ops->close(ldb);
|
||||
return 0;
|
||||
}
|
@ -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 <expression> [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;i<ret;i++) {
|
||||
printf("# record %d\n", i+1);
|
||||
ldif_write(stdout, msgs[i]);
|
||||
}
|
||||
|
||||
ret = ldb->ops->search_free(ldb, msgs);
|
||||
if (ret == -1) {
|
||||
fprintf(stderr, "search_free failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ldb->ops->close(ldb);
|
||||
return 0;
|
||||
}
|
8
source/lib/ldb/tests/test-generic.sh
Normal file
8
source/lib/ldb/tests/test-generic.sh
Normal file
@ -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)'
|
8
source/lib/ldb/tests/test-ldap.sh
Executable file
8
source/lib/ldb/tests/test-ldap.sh
Executable file
@ -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
|
14
source/lib/ldb/tests/test-modify.ldif
Normal file
14
source/lib/ldb/tests/test-modify.ldif
Normal file
@ -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
|
8
source/lib/ldb/tests/test-tdb.sh
Executable file
8
source/lib/ldb/tests/test-tdb.sh
Executable file
@ -0,0 +1,8 @@
|
||||
#!/bin/sh
|
||||
|
||||
|
||||
export LDB_URL="tdb://test.ldb"
|
||||
|
||||
rm -f test.ldb
|
||||
|
||||
. tests/test-generic.sh
|
@ -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);
|
||||
|
85
source/lib/ldb/tools/ldbmodify.c
Normal file
85
source/lib/ldb/tools/ldbmodify.c
Normal file
@ -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;
|
||||
}
|
@ -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<ret;i++) {
|
||||
struct ldb_ldif ldif;
|
||||
printf("# record %d\n", i+1);
|
||||
ldif_write_file(stdout, msgs[i]);
|
||||
|
||||
ldif.changetype = LDB_CHANGETYPE_NONE;
|
||||
ldif.msg = *msgs[i];
|
||||
|
||||
ldif_write_file(stdout, &ldif);
|
||||
}
|
||||
|
||||
if (ret > 0) {
|
||||
|
Loading…
Reference in New Issue
Block a user