const struct ldb_message *msg)
{
struct ldb_context *ldb = ldb_module_get_ctx(module);
- int ret;
+ int ret, i;
ret = ltdb_check_special_dn(module, msg);
if (ret != LDB_SUCCESS) {
return LDB_ERR_OPERATIONS_ERROR;
}
+ for (i=0;i<msg->num_elements;i++) {
+ struct ldb_message_element *el = &msg->elements[i];
+ const struct ldb_schema_attribute *a = ldb_schema_attribute_by_name(ldb, el->name);
+
+ if (el->num_values == 0) {
+ ldb_asprintf_errstring(ldb, "attribute %s on %s specified, but with 0 values (illegal)",
+ el->name, ldb_dn_get_linearized(msg->dn));
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+ if (a && a->flags & LDB_ATTR_FLAG_SINGLE_VALUE) {
+ if (el->num_values > 1) {
+ ldb_asprintf_errstring(ldb, "SINGLE-VALUE attribute %s on %s speicified more than once",
+ el->name, ldb_dn_get_linearized(msg->dn));
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+ }
+ }
+
ret = ltdb_store(module, msg, TDB_INSERT);
if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
struct ldb_message_element *el2;
struct ldb_val *vals;
const char *dn;
+ const struct ldb_schema_attribute *a = ldb_schema_attribute_by_name(ldb, el->name);
- switch (msg->elements[i].flags & LDB_FLAG_MOD_MASK) {
+ if (ldb_attr_cmp(el->name, "distinguishedName") == 0) {
+ ldb_asprintf_errstring(ldb, "it is not permitted to perform a modify on distinguishedName (use rename instead): %s",
+ ldb_dn_get_linearized(msg->dn));
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+ 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 */
idx = find_element(msg2, el->name);
+ if (el->num_values == 0) {
+ ldb_asprintf_errstring(ldb, "attribute %s on %s speicified, but with 0 values (illigal)",
+ el->name, ldb_dn_get_linearized(msg->dn));
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
if (idx == -1) {
+ if (a && a->flags & LDB_ATTR_FLAG_SINGLE_VALUE) {
+ if (el->num_values > 1) {
+ ldb_asprintf_errstring(ldb, "SINGLE-VALUE attribute %s on %s speicified more than once",
+ el->name, ldb_dn_get_linearized(msg->dn));
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+ }
if (msg_add_element(ldb, msg2, el) != 0) {
ret = LDB_ERR_OTHER;
goto failed;
continue;
}
+ /* If this is an add, then if it already
+ * exists in the object, then we violoate the
+ * single-value rule */
+ if (a && a->flags & LDB_ATTR_FLAG_SINGLE_VALUE) {
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+
el2 = &msg2->elements[idx];
/* An attribute with this name already exists,
break;
case LDB_FLAG_MOD_REPLACE:
+ if (a && a->flags & LDB_ATTR_FLAG_SINGLE_VALUE) {
+ if (el->num_values > 1) {
+ ldb_asprintf_errstring(ldb, "SINGLE-VALUE attribute %s on %s speicified more than once",
+ el->name, ldb_dn_get_linearized(msg->dn));
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+ }
/* replace all elements of this attribute name with the elements
listed. The attribute not existing is not an error */
msg_delete_attribute(module, ldb, msg2, el->name);
return LDB_ERR_OPERATIONS_ERROR;
}
- if (ldb_dn_compare(req->op.rename.olddn, req->op.rename.newdn) == 0) {
- /* The rename operation is apparently only changing case -
- the DNs are the same. Delete the old DN before adding
- the new one to avoid a TDB_ERR_EXISTS error.
-
- The only drawback to this is that if the delete
- succeeds but the add fails, we rely on the
- transaction to roll this all back. */
- tret = ltdb_delete_internal(module, req->op.rename.olddn);
- if (tret != LDB_SUCCESS) {
- return tret;
- }
-
- tret = ltdb_add_internal(module, msg);
- if (tret != LDB_SUCCESS) {
- return tret;
- }
- } else {
- /* The rename operation is changing DNs. Try to add the new
- DN first to avoid clobbering another DN not related to
- this rename operation. */
- tret = ltdb_add_internal(module, msg);
- if (tret != LDB_SUCCESS) {
- return tret;
- }
+ /* Always delete first then add, to avoid conflicts with
+ * unique indexes. We rely on the transaction to make this
+ * atomic
+ */
+ tret = ltdb_delete_internal(module, req->op.rename.olddn);
+ if (tret != LDB_SUCCESS) {
+ return tret;
+ }
- tret = ltdb_delete_internal(module, req->op.rename.olddn);
- if (tret != LDB_SUCCESS) {
- ltdb_delete_internal(module, req->op.rename.newdn);
- return LDB_ERR_OPERATIONS_ERROR;
- }
+ tret = ltdb_add_internal(module, msg);
+ if (tret != LDB_SUCCESS) {
+ return tret;
}
return LDB_SUCCESS;
ldb_get_create_perms(ldb), ldb);
if (!ltdb->tdb) {
ldb_debug(ldb, LDB_DEBUG_ERROR,
- "Unable to open tdb '%s'\n", path);
+ "Unable to open tdb '%s'", path);
talloc_free(ltdb);
return -1;
}