s4:ldb Add 'single-value' support to LDB.
authorAndrew Bartlett <abartlet@samba.org>
Tue, 22 Sep 2009 02:26:59 +0000 (19:26 -0700)
committerAndrew Bartlett <abartlet@samba.org>
Tue, 22 Sep 2009 03:50:26 +0000 (20:50 -0700)
This is currently only triggered via Samba4's schema code.

source4/dsdb/schema/schema_init.c
source4/lib/ldb/include/ldb.h
source4/lib/ldb/ldb_tdb/ldb_tdb.c

index fa1953a14fd9969ce6dfd75d1baa2106995c8e72..8bb54f47f4e7510ff9df19301232519f40b9c391 100644 (file)
@@ -653,6 +653,10 @@ static int dsdb_schema_setup_ldb_schema_attribute(struct ldb_context *ldb,
        if (dsdb_schema_unique_attribute(a->name)) {
                a->flags |= LDB_ATTR_FLAG_UNIQUE_INDEX;
        }
+       if (attr->isSingleValued) {
+               a->flags |= LDB_ATTR_FLAG_SINGLE_VALUE;
+       }
+       
        
        return LDB_SUCCESS;
 }
index 0378697f4b086635656b34c17a12969a2cc9e6bf..fa531b26f27b60c6738fa4f52779c1a585e8964b 100644 (file)
@@ -392,6 +392,11 @@ const struct ldb_dn_extended_syntax *ldb_dn_extended_syntax_by_name(struct ldb_c
  */
 #define LDB_ATTR_FLAG_UNIQUE_INDEX (1<<3)
 
+/*
+  when this is set, attempts to create two attribute values for this attribute on a single DN will return LDB_ERR_CONSTRAINT_VIOLATION
+ */
+#define LDB_ATTR_FLAG_SINGLE_VALUE (1<<4)
+
 /**
   LDAP attribute syntax for a DN
 
index d4f7b452cb4c22a1743d103be5b053051d2cd9b3..e569a5a2a89815fe8442cfd9cc48341746166ba3 100644 (file)
@@ -254,7 +254,7 @@ static int ltdb_add_internal(struct ldb_module *module,
                             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) {
@@ -265,6 +265,24 @@ static int ltdb_add_internal(struct ldb_module *module,
                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 speicified, but with 0 values (illigal)", 
+                                              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) {
@@ -602,15 +620,28 @@ int ltdb_modify_internal(struct ldb_module *module,
                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) {
 
                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;
@@ -618,6 +649,13 @@ int ltdb_modify_internal(struct ldb_module *module,
                                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,
@@ -657,6 +695,13 @@ int ltdb_modify_internal(struct ldb_module *module,
                        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);