Move the checking of single valued attributes back into the tdb backend.
authorAndrew Tridgell <tridge@samba.org>
Thu, 4 Nov 2010 09:02:16 +0000 (20:02 +1100)
committerAndrew Tridgell <tridge@samba.org>
Thu, 4 Nov 2010 09:35:44 +0000 (20:35 +1100)
The backend is the only place that can do this properly. It makes no
sense to do it anywhere else. As a result of it moving out of the
backend we ended up with some bugs causing multiple values in single
valued attributes (eg. isDeleted), which can really damage the
inregrity of the database.

For the override of single valued values needed for deleted linked
attributes we should use attribute flags.

This reverts commit 1949864417f3d10fb8996df7db259649eb777271.

source4/dsdb/samdb/ldb_modules/objectclass_attrs.c
source4/lib/ldb/ldb_tdb/ldb_tdb.c

index 62bc9ae8b27f3ad554356b58db51100383e50eea..ed193491d1af1f3f9c0eadff7aef921f0e604474 100644 (file)
@@ -296,18 +296,6 @@ static int attr_handler2(struct oc_context *ac)
                        return ldb_operr(ldb);
                }
 
-               /* Check if they're single-valued if this is requested */
-               if ((msg->elements[i].num_values > 1) && (attr->isSingleValued)) {
-                       ldb_asprintf_errstring(ldb, "objectclass_attrs: attribute '%s' on entry '%s' is single-valued!",
-                                              msg->elements[i].name,
-                                              ldb_dn_get_linearized(msg->dn));
-                       if (ac->req->operation == LDB_ADD) {
-                               return LDB_ERR_CONSTRAINT_VIOLATION;
-                       } else {
-                               return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
-                       }
-               }
-
                /* We can use "str_list_check" with "strcmp" here since the
                 * attribute informations from the schema are always equal
                 * up-down-cased. */
index d9547c98c4645f3d0e2a9696f6e43ed711988def..b7432ab4d225193730c82d61566f0e389a25532c 100644 (file)
@@ -294,12 +294,20 @@ static int ltdb_add_internal(struct ldb_module *module,
 
        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 specified more than once",
+                                                      el->name, ldb_dn_get_linearized(msg->dn));
+                               return LDB_ERR_CONSTRAINT_VIOLATION;
+                       }
+               }
        }
 
        ret = ltdb_store(module, msg, TDB_INSERT);
@@ -650,6 +658,7 @@ int ltdb_modify_internal(struct ldb_module *module,
        for (i=0; i<msg->num_elements; i++) {
                struct ldb_message_element *el = &msg->elements[i], *el2;
                struct ldb_val *vals;
+               const struct ldb_schema_attribute *a = ldb_schema_attribute_by_name(ldb, el->name);
                const char *dn;
 
                switch (msg->elements[i].flags & LDB_FLAG_MOD_MASK) {
@@ -686,6 +695,15 @@ int ltdb_modify_internal(struct ldb_module *module,
                                }
                        }
 
+                       if (a && a->flags & LDB_ATTR_FLAG_SINGLE_VALUE) {
+                               if (el->num_values > 1) {
+                                       ldb_asprintf_errstring(ldb, "SINGLE-VALUE attribute %s on %s specified more than once",
+                                                              el->name, ldb_dn_get_linearized(msg2->dn));
+                                       ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
+                                       goto done;
+                               }
+                       }
+
                        /* Checks if element already exists */
                        idx = find_element(msg2, el->name);
                        if (idx == -1) {
@@ -702,6 +720,15 @@ int ltdb_modify_internal(struct ldb_module *module,
                                j = (unsigned int) idx;
                                el2 = &(msg2->elements[j]);
 
+                               /* We cannot add another value on a existing one
+                                  if the attribute is single-valued */
+                               if (a && a->flags & LDB_ATTR_FLAG_SINGLE_VALUE) {
+                                       ldb_asprintf_errstring(ldb, "SINGLE-VALUE attribute %s on %s specified more than once",
+                                                              el->name, ldb_dn_get_linearized(msg2->dn));
+                                       ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
+                                       goto done;
+                               }
+
                                /* Check that values don't exist yet on multi-
                                   valued attributes or aren't provided twice */
                                for (j = 0; j < el->num_values; j++) {
@@ -761,6 +788,23 @@ int ltdb_modify_internal(struct ldb_module *module,
 
                case LDB_FLAG_MOD_REPLACE:
 
+                       if (a && a->flags & LDB_ATTR_FLAG_SINGLE_VALUE) {
+                               /* the RELAX control overrides this
+                                  check for replace. This is needed as
+                                  DRS replication can produce multiple
+                                  values here for a single valued
+                                  attribute when the values are deleted
+                                  links
+                               */
+                               if (el->num_values > 1 &&
+                                   (!req || !ldb_request_get_control(req, LDB_CONTROL_RELAX_OID))) {
+                                       ldb_asprintf_errstring(ldb, "SINGLE-VALUE attribute %s on %s specified more than once",
+                                                              el->name, ldb_dn_get_linearized(msg2->dn));
+                                       ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
+                                       goto done;
+                               }
+                       }
+
                        /* TODO: This is O(n^2) - replace with more efficient check */
                        for (j=0; j<el->num_values; j++) {
                                if (ldb_msg_find_val(el, &el->values[j]) != &el->values[j]) {