s4:ldb/ldif: add support for "modrdn"
authorStefan Metzmacher <metze@samba.org>
Tue, 5 Apr 2011 12:41:27 +0000 (14:41 +0200)
committerStefan Metzmacher <metze@samba.org>
Thu, 21 Apr 2011 12:41:12 +0000 (14:41 +0200)
This add a ldb_ldif_parse_modrdn() helper function to parse
the information out of a ldb_message structure.

Signed-off-by: Simo Sorce <idra@samba.org>
metze

source4/lib/ldb/common/ldb_ldif.c
source4/lib/ldb/include/ldb.h

index f837012e69eff74fb4314b3e9f11313bd963c2f3..63b797c4f3d97ddd2283c06511531a3ccf7340dd 100644 (file)
@@ -261,6 +261,8 @@ static const struct {
        {"add",    LDB_CHANGETYPE_ADD},
        {"delete", LDB_CHANGETYPE_DELETE},
        {"modify", LDB_CHANGETYPE_MODIFY},
+       {"modrdn", LDB_CHANGETYPE_MODRDN},
+       {"moddn",  LDB_CHANGETYPE_MODRDN},
        {NULL, 0}
 };
 
@@ -526,6 +528,193 @@ void ldb_ldif_read_free(struct ldb_context *ldb, struct ldb_ldif *ldif)
        talloc_free(ldif);
 }
 
+int ldb_ldif_parse_modrdn(struct ldb_context *ldb,
+                         const struct ldb_ldif *ldif,
+                         TALLOC_CTX *mem_ctx,
+                         struct ldb_dn **_olddn,
+                         struct ldb_dn **_newrdn,
+                         bool *_deleteoldrdn,
+                         struct ldb_dn **_newsuperior,
+                         struct ldb_dn **_newdn)
+{
+       struct ldb_message *msg = ldif->msg;
+       struct ldb_val *newrdn_val = NULL;
+       struct ldb_val *deleteoldrdn_val = NULL;
+       struct ldb_val *newsuperior_val = NULL;
+       struct ldb_dn *olddn = NULL;
+       struct ldb_dn *newrdn = NULL;
+       bool deleteoldrdn = true;
+       struct ldb_dn *newsuperior = NULL;
+       struct ldb_dn *newdn = NULL;
+       struct ldb_val tmp_false;
+       struct ldb_val tmp_true;
+       bool ok;
+       TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+
+       if (tmp_ctx == NULL) {
+               ldb_debug(ldb, LDB_DEBUG_FATAL,
+                         "Error: talloc_new() failed");
+               goto err_op;
+       }
+
+       if (ldif->changetype != LDB_CHANGETYPE_MODRDN) {
+               ldb_debug(ldb, LDB_DEBUG_ERROR,
+                         "Error: invalid changetype '%d'",
+                         ldif->changetype);
+               goto err_other;
+       }
+
+       if (msg->num_elements < 2) {
+               ldb_debug(ldb, LDB_DEBUG_ERROR,
+                         "Error: num_elements[%u] < 2",
+                         msg->num_elements);
+               goto err_other;
+       }
+
+       if (msg->num_elements > 3) {
+               ldb_debug(ldb, LDB_DEBUG_ERROR,
+                         "Error: num_elements[%u] > 3",
+                         msg->num_elements);
+               goto err_other;
+       }
+
+#define CHECK_ELEMENT(i, _name, v, needed) do { \
+       v = NULL; \
+       if (msg->num_elements < (i + 1)) { \
+               if (needed) { \
+                       ldb_debug(ldb, LDB_DEBUG_ERROR, \
+                                 "Error: num_elements[%u] < (%u + 1)", \
+                                 msg->num_elements, i); \
+                       goto err_other; \
+               } \
+       } else if (ldb_attr_cmp(msg->elements[i].name, _name) != 0) { \
+               ldb_debug(ldb, LDB_DEBUG_ERROR, \
+                         "Error: elements[%u].name[%s] != [%s]", \
+                         i, msg->elements[i].name, _name); \
+               goto err_other; \
+       } else if (msg->elements[i].flags != 0) { \
+               ldb_debug(ldb, LDB_DEBUG_ERROR, \
+                         "Error: elements[%u].flags[0x%X} != [0x0]", \
+                         i, msg->elements[i].flags); \
+               goto err_other; \
+       } else if (msg->elements[i].num_values != 1) { \
+               ldb_debug(ldb, LDB_DEBUG_ERROR, \
+                         "Error: elements[%u].num_values[%u] != 1", \
+                         i, msg->elements[i].num_values); \
+               goto err_other; \
+       } else { \
+               v = &msg->elements[i].values[0]; \
+       } \
+} while (0)
+
+       CHECK_ELEMENT(0, "newrdn", newrdn_val, true);
+       CHECK_ELEMENT(1, "deleteoldrdn", deleteoldrdn_val, true);
+       CHECK_ELEMENT(2, "newsuperior", newsuperior_val, false);
+
+#undef CHECK_ELEMENT
+
+       olddn = ldb_dn_copy(tmp_ctx, msg->dn);
+       if (olddn == NULL) {
+               ldb_debug(ldb, LDB_DEBUG_ERROR,
+                         "Error: failed to copy olddn '%s'",
+                         ldb_dn_get_linearized(msg->dn));
+               goto err_op;
+       }
+
+       newrdn = ldb_dn_from_ldb_val(tmp_ctx, ldb, newrdn_val);
+       if (!ldb_dn_validate(newrdn)) {
+               ldb_debug(ldb, LDB_DEBUG_ERROR,
+                         "Error: Unable to parse dn '%s'",
+                         (char *)newrdn_val->data);
+               goto err_dn;
+       }
+
+       tmp_false.length = 1;
+       tmp_false.data = discard_const_p(uint8_t, "0");
+       tmp_true.length = 1;
+       tmp_true.data = discard_const_p(uint8_t, "1");
+       if (ldb_val_equal_exact(deleteoldrdn_val, &tmp_false) == 1) {
+               deleteoldrdn = false;
+       } else if (ldb_val_equal_exact(deleteoldrdn_val, &tmp_true) == 1) {
+               deleteoldrdn = true;
+       } else {
+               ldb_debug(ldb, LDB_DEBUG_ERROR,
+                         "Error: deleteoldrdn value invalid '%s' not '0'/'1'",
+                         (char *)deleteoldrdn_val->data);
+               goto err_attr;
+       }
+
+       if (newsuperior_val) {
+               newsuperior = ldb_dn_from_ldb_val(tmp_ctx, ldb, newsuperior_val);
+               if (!ldb_dn_validate(newsuperior)) {
+                       ldb_debug(ldb, LDB_DEBUG_ERROR,
+                                 "Error: Unable to parse dn '%s'",
+                                 (char *)newsuperior_val->data);
+                       goto err_dn;
+               }
+       } else {
+               newsuperior = ldb_dn_get_parent(tmp_ctx, msg->dn);
+               if (newsuperior == NULL) {
+                       ldb_debug(ldb, LDB_DEBUG_ERROR,
+                                 "Error: Unable to get parent dn '%s'",
+                                 ldb_dn_get_linearized(msg->dn));
+                       goto err_dn;
+               }
+       }
+
+       newdn = ldb_dn_copy(tmp_ctx, newrdn);
+       if (newdn == NULL) {
+               ldb_debug(ldb, LDB_DEBUG_ERROR,
+                         "Error: failed to copy newrdn '%s'",
+                         ldb_dn_get_linearized(newrdn));
+               goto err_op;
+       }
+
+       ok = ldb_dn_add_base(newdn, newsuperior);
+       if (!ok) {
+               ldb_debug(ldb, LDB_DEBUG_ERROR,
+                         "Error: failed to base '%s' to newdn '%s'",
+                         ldb_dn_get_linearized(newsuperior),
+                         ldb_dn_get_linearized(newdn));
+               goto err_op;
+       }
+
+       if (_olddn) {
+               *_olddn = talloc_move(mem_ctx, &olddn);
+       }
+       if (_newrdn) {
+               *_newrdn = talloc_move(mem_ctx, &newrdn);
+       }
+       if (_deleteoldrdn) {
+               *_deleteoldrdn = deleteoldrdn;
+       }
+       if (_newsuperior) {
+               if (newsuperior_val) {
+                       *_newrdn = talloc_move(mem_ctx, &newrdn);
+               } else {
+                       *_newrdn = NULL;
+               }
+       }
+       if (_newdn) {
+               *_newdn = talloc_move(mem_ctx, &newdn);
+       }
+
+       talloc_free(tmp_ctx);
+       return LDB_SUCCESS;
+err_other:
+       talloc_free(tmp_ctx);
+       return LDB_ERR_OTHER;
+err_op:
+       talloc_free(tmp_ctx);
+       return LDB_ERR_OPERATIONS_ERROR;
+err_attr:
+       talloc_free(tmp_ctx);
+       return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+err_dn:
+       talloc_free(tmp_ctx);
+       return LDB_ERR_INVALID_DN_SYNTAX;
+}
+
 /*
  read from a LDIF source, creating a ldb_message
 */
@@ -682,6 +871,16 @@ struct ldb_ldif *ldb_ldif_read(struct ldb_context *ldb,
                }
        }
 
+       if (ldif->changetype == LDB_CHANGETYPE_MODRDN) {
+               int ret;
+
+               ret = ldb_ldif_parse_modrdn(ldb, ldif, ldif,
+                                           NULL, NULL, NULL, NULL, NULL);
+               if (ret != LDB_SUCCESS) {
+                       goto failed;
+               }
+       }
+
        return ldif;
 
 failed:
index f5d5940ae3d928ad2f628781efb563858c7cba51..d745f377b619c8c85f90bdb5afee34f039bb2821 100644 (file)
@@ -183,7 +183,8 @@ enum ldb_changetype {
        LDB_CHANGETYPE_NONE=0,
        LDB_CHANGETYPE_ADD,
        LDB_CHANGETYPE_DELETE,
-       LDB_CHANGETYPE_MODIFY
+       LDB_CHANGETYPE_MODIFY,
+       LDB_CHANGETYPE_MODRDN
 };
 
 /**
@@ -1620,6 +1621,31 @@ struct ldb_ldif *ldb_ldif_read_file(struct ldb_context *ldb, FILE *f);
 */
 struct ldb_ldif *ldb_ldif_read_string(struct ldb_context *ldb, const char **s);
 
+/**
+   Parse a modrdn LDIF message from a struct ldb_message
+
+   \param ldb the ldb context (from ldb_init())
+   \param ldif the preparsed LDIF chunk (from ldb_ldif_read())
+
+   \param mem_ctx the memory context that's used for return values
+
+   \param olddn the old dn as struct ldb_dn, if not needed pass NULL
+   \param newrdn the new rdn as struct ldb_dn, if not needed pass NULL
+   \param deleteoldrdn the deleteoldrdn value as bool, if not needed pass NULL
+   \param newsuperior the newsuperior dn as struct ldb_dn, if not needed pass NULL
+                      *newsuperior can be NULL as it is optional in the LDIF
+   \param newdn the full constructed new dn as struct ldb_dn, if not needed pass NULL
+
+*/
+int ldb_ldif_parse_modrdn(struct ldb_context *ldb,
+                         const struct ldb_ldif *ldif,
+                         TALLOC_CTX *mem_ctx,
+                         struct ldb_dn **olddn,
+                         struct ldb_dn **newrdn,
+                         bool *deleteoldrdn,
+                         struct ldb_dn **newsuperior,
+                         struct ldb_dn **newdn);
+
 /**
    Write an LDIF message to a file