summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/lib/ldb/common/ldb_msg.c134
-rw-r--r--source4/lib/ldb/include/ldb.h12
-rw-r--r--source4/lib/ldb/tools/ldbedit.c7
3 files changed, 153 insertions, 0 deletions
diff --git a/source4/lib/ldb/common/ldb_msg.c b/source4/lib/ldb/common/ldb_msg.c
index 18859c86dd..3865e7afa9 100644
--- a/source4/lib/ldb/common/ldb_msg.c
+++ b/source4/lib/ldb/common/ldb_msg.c
@@ -228,6 +228,16 @@ int ldb_msg_element_compare(struct ldb_message_element *el1,
}
/*
+ compare two ldb_message_element structures
+ comparing by element name
+*/
+int ldb_msg_element_compare_name(struct ldb_message_element *el1,
+ struct ldb_message_element *el2)
+{
+ return ldb_attr_cmp(el1->name, el2->name);
+}
+
+/*
convenience functions to return common types from a message
these return the first value if the attribute is multi-valued
*/
@@ -305,3 +315,127 @@ const char *ldb_msg_find_string(const struct ldb_message *msg,
}
return v->data;
}
+
+
+/*
+ sort the elements of a message by name
+*/
+void ldb_msg_sort_elements(struct ldb_message *msg)
+{
+ qsort(msg->elements, msg->num_elements, sizeof(struct ldb_message_element),
+ (comparison_fn_t)ldb_msg_element_compare_name);
+}
+
+
+/*
+ free a message created using ldb_msg_copy
+*/
+void ldb_msg_free(struct ldb_context *ldb, struct ldb_message *msg)
+{
+ int i, j;
+
+ for (i=0;i<msg->num_elements;i++) {
+ struct ldb_message_element *el = &msg->elements[i];
+ for (j=0;j<el->num_values;j++) {
+ ldb_free(ldb, el->values[j].data);
+ }
+ if (el->values) ldb_free(ldb, el->values);
+ ldb_free(ldb, el->name);
+ }
+ if (msg->elements) ldb_free(ldb, msg->elements);
+ ldb_free(ldb, msg->dn);
+ ldb_free(ldb, msg);
+}
+
+/*
+ copy a message, allocating new memory for all parts
+*/
+struct ldb_message *ldb_msg_copy(struct ldb_context *ldb,
+ const struct ldb_message *msg)
+{
+ struct ldb_message *msg2;
+ int i, j;
+
+ msg2 = ldb_malloc_p(ldb, struct ldb_message);
+ if (msg2 == NULL) return NULL;
+
+ msg2->elements = NULL;
+ msg2->num_elements = 0;
+ msg2->private_data = NULL;
+
+ msg2->dn = ldb_strdup(ldb, msg->dn);
+ if (msg2->dn == NULL) goto failed;
+
+ msg2->elements = ldb_malloc_array_p(ldb, struct ldb_message_element, msg->num_elements);
+ if (msg2->elements == NULL) goto failed;
+
+ for (i=0;i<msg->num_elements;i++) {
+ struct ldb_message_element *el1 = &msg->elements[i];
+ struct ldb_message_element *el2 = &msg2->elements[i];
+
+ el2->flags = el1->flags;
+ el2->num_values = 0;
+ el2->values = NULL;
+ el2->name = ldb_strdup(ldb, el1->name);
+ if (el2->name == NULL) goto failed;
+ el2->values = ldb_malloc_array_p(ldb, struct ldb_val, el1->num_values);
+ for (j=0;j<el1->num_values;j++) {
+ el2->values[j] = ldb_val_dup(ldb, &el1->values[j]);
+ if (el2->values[j].data == NULL &&
+ el1->values[j].length != 0) {
+ goto failed;
+ }
+ el2->num_values++;
+ }
+
+ msg2->num_elements++;
+ }
+
+ return msg2;
+
+failed:
+ ldb_msg_free(ldb, msg2);
+ return NULL;
+}
+
+
+/*
+ canonicalise a message, merging elements of the same name
+*/
+struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb,
+ const struct ldb_message *msg)
+{
+ int i;
+ struct ldb_message *msg2;
+
+ msg2 = ldb_msg_copy(ldb, msg);
+ if (msg2 == NULL) return NULL;
+
+ ldb_msg_sort_elements(msg2);
+
+ for (i=1;i<msg2->num_elements;i++) {
+ struct ldb_message_element *el1 = &msg2->elements[i-1];
+ struct ldb_message_element *el2 = &msg2->elements[i];
+ if (ldb_msg_element_compare_name(el1, el2) == 0) {
+ el1->values = ldb_realloc_p(ldb, el1->values, struct ldb_val,
+ el1->num_values + el2->num_values);
+ if (el1->values == NULL) {
+ return NULL;
+ }
+ memcpy(el1->values + el1->num_values,
+ el2->values,
+ sizeof(struct ldb_val) * el2->num_values);
+ el1->num_values += el2->num_values;
+ ldb_free(ldb, el2->name);
+ ldb_free(ldb, el2->values);
+ if (i+1<msg2->num_elements) {
+ memmove(el2, el2+1, sizeof(struct ldb_message_element) *
+ (msg2->num_elements - (i+1)));
+ }
+ msg2->num_elements--;
+ i--;
+ }
+ }
+
+ return msg2;
+}
diff --git a/source4/lib/ldb/include/ldb.h b/source4/lib/ldb/include/ldb.h
index 03d0cc7a3b..9dff510417 100644
--- a/source4/lib/ldb/include/ldb.h
+++ b/source4/lib/ldb/include/ldb.h
@@ -293,6 +293,18 @@ double ldb_msg_find_double(const struct ldb_message *msg,
const char *ldb_msg_find_string(const struct ldb_message *msg,
const char *attr_name,
const char *default_value);
+
+void ldb_msg_sort_elements(struct ldb_message *msg);
+
+void ldb_msg_free(struct ldb_context *ldb, struct ldb_message *msg);
+
+struct ldb_message *ldb_msg_copy(struct ldb_context *ldb,
+ const struct ldb_message *msg);
+
+struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb,
+ const struct ldb_message *msg);
+
+
struct ldb_val ldb_val_dup(struct ldb_context *ldb,
const struct ldb_val *v);
diff --git a/source4/lib/ldb/tools/ldbedit.c b/source4/lib/ldb/tools/ldbedit.c
index f84d05440f..6cd6ef041b 100644
--- a/source4/lib/ldb/tools/ldbedit.c
+++ b/source4/lib/ldb/tools/ldbedit.c
@@ -69,6 +69,12 @@ static int modify_record(struct ldb_context *ldb,
mod.num_elements = 0;
mod.elements = NULL;
+ msg2 = ldb_msg_canonicalize(ldb, msg2);
+ if (msg2 == NULL) {
+ fprintf(stderr, "Failed to canonicalise msg2\n");
+ return -1;
+ }
+
/* look in msg2 to find elements that need to be added
or modified */
for (i=0;i<msg2->num_elements;i++) {
@@ -295,6 +301,7 @@ static void usage(void)
printf(" -b basedn choose baseDN\n");
printf(" -a edit all records (expression 'objectclass=*')\n");
printf(" -e editor choose editor (or $VISUAL or $EDITOR)\n");
+ printf(" -v verbose mode)\n");
exit(1);
}