s4:objectclass_attrs.c - rework to support these special "description" constraints
authorMatthias Dieter Wallnöfer <mdw@samba.org>
Mon, 25 Oct 2010 11:56:14 +0000 (13:56 +0200)
committerMatthias Dieter Wallnöfer <mdw@samba.org>
Tue, 26 Oct 2010 18:12:00 +0000 (18:12 +0000)
Only the "description" attribute has this special restrictions.

source4/dsdb/samdb/ldb_modules/objectclass_attrs.c

index b3f7048a39045e76d33d4e676c6f5b3c227fb346..5d3f51fbf58cb62abe7344bbf65f6f849f7bbccd 100644 (file)
@@ -139,17 +139,47 @@ static int attr_handler(struct oc_context *ac)
                        }
                }
 
-               /* Multi-valued replace operations are generally denied but
-                * there do exist exceptions where attributes have the flag
-                * "FLAG_ATTR_REQ_PARTIAL_SET_MEMBER" set. */
+               /* "description" on AD is very special: it's nearly single-
+                * valued (only on add operations it isn't). */
                if ((ac->req->operation == LDB_MODIFY) &&
-                   (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) == LDB_FLAG_MOD_REPLACE) &&
-                   (msg->elements[i].num_values > 1) &&
-                   ((attr->systemFlags & DS_FLAG_ATTR_REQ_PARTIAL_SET_MEMBER) == 0)) {
-                       ldb_asprintf_errstring(ldb, "objectclass_attrs: attribute '%s' on entry '%s' is replaced multi-valued!",
-                                              msg->elements[i].name,
-                                              ldb_dn_get_linearized(msg->dn));
-                       return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
+                   (ldb_attr_cmp(attr->lDAPDisplayName, "description") == 0)) {
+                       /* Multi-valued add or replace operations are always
+                        * denied */
+                       if ((LDB_FLAG_MOD_TYPE(msg->elements[i].flags)
+                           != LDB_FLAG_MOD_DELETE) &&
+                           (msg->elements[i].num_values > 1)) {
+                               ldb_asprintf_errstring(ldb,
+                                                      "objectclass_attrs: attribute '%s' on entry '%s' is changed using a multi-valued add or replace operation!",
+                                                      msg->elements[i].name,
+                                                      ldb_dn_get_linearized(msg->dn));
+                               return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
+                       }
+
+                       /* Add operations are only allowed if no value exists */
+                       if (LDB_FLAG_MOD_TYPE(msg->elements[i].flags)
+                           == LDB_FLAG_MOD_ADD) {
+                               const char *attrs[] = { attr->lDAPDisplayName,
+                                                       NULL };
+                               struct ldb_result *res;
+                               struct ldb_message_element *el;
+
+                               ret = ldb_search(ldb, ac, &res, msg->dn,
+                                                LDB_SCOPE_BASE, attrs, NULL);
+                               if (ret != LDB_SUCCESS) {
+                                       return ret;
+                               }
+
+                               el = ldb_msg_find_element(res->msgs[0],
+                                                         attr->lDAPDisplayName);
+                               if (el != NULL) {
+                                       ldb_asprintf_errstring(ldb,
+                                                              "objectclass_attrs: attribute '%s' on entry '%s' is changed using an add operation, but there a value already exists!",
+                                                              msg->elements[i].name,
+                                                              ldb_dn_get_linearized(msg->dn));
+                                       return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
+                               }
+                               talloc_free(res);
+                       }
                }
 
                /* Substitute the attribute name to match in case */