Description: CVE-2013-0172
   Samba 4.0.0beta2 as an AD DC may provide authenticated users with write access
   to LDAP directory objects.

   In AD, Access Control Entries can be assigned based on the objectClass
   of the object.  If a user or a group the user is a member of has any
   access based on the objectClass, then that user has write access to that
   object.

   Additionally, if a user has write access to any attribute on the object,
   they may have access to write to all attributes.

   An important mitigation is that anonymous access is totally disabled by
   default.  The second important mitigation is that normal users are
   typically only given the problematic per-objectClass right via the
   "pre-windows 2000 compatible access" group, and Samba 4.0.0 incorrectly
   does not make "authenticated users" part of this group.

 .
 samba4 (4.0.0~beta2+dfsg1-3.1) UNRELEASED; urgency=low
 .
   * Non-maintainer upload.
   * Fix CVE-2013-0172 Samba 4.0.0 as an AD DC may provide authenticated users with write access
     to LDAP directory objects
Author: Andrew Bartlett <abartlet@samba.org>

---
The information above should follow the Patch Tagging Guidelines, please
checkout http://dep.debian.net/deps/dep3/ to learn about the format. Here
are templates for supplementary fields that you might want to add:

Origin: upstream, http://samba.org/samba/ftp/patches/patch-4.0.0-4.0.1.diffs.gz
Bug: https://bugzilla.samba.org/show_bug.cgi?id=9554
Bug-Debian: http://bugs.debian.org/699188
Forwarded: not-needed
Reviewed-By: Andrew Bartlett <abartlet@samba.org>
Last-Update: <2013-02-12>

--- samba4-4.0.0~beta2+dfsg1.orig/libcli/security/object_tree.c
+++ samba4-4.0.0~beta2+dfsg1/libcli/security/object_tree.c
@@ -53,6 +53,7 @@ bool insert_in_object_tree(TALLOC_CTX *m
 			return false;
 		}
 		(*root)->guid = *guid;
+		(*root)->remaining_access = init_access;
 		*new_node = *root;
 		return true;
 	}
--- samba4-4.0.0~beta2+dfsg1.orig/source4/dsdb/samdb/ldb_modules/acl.c
+++ samba4-4.0.0~beta2+dfsg1/source4/dsdb/samdb/ldb_modules/acl.c
@@ -935,8 +935,6 @@ static int acl_modify(struct ldb_module
 	unsigned int i;
 	const struct GUID *guid;
 	uint32_t access_granted;
-	struct object_tree *root = NULL;
-	struct object_tree *new_node = NULL;
 	NTSTATUS status;
 	struct ldb_result *acl_res;
 	struct security_descriptor *sd;
@@ -999,12 +997,6 @@ static int acl_modify(struct ldb_module
 				 "acl_modify: Error retrieving object class GUID.");
 	}
 	sid = samdb_result_dom_sid(req, acl_res->msgs[0], "objectSid");
-	if (!insert_in_object_tree(tmp_ctx, guid, SEC_ADS_WRITE_PROP,
-				   &root, &new_node)) {
-		talloc_free(tmp_ctx);
-		return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
-				 "acl_modify: Error adding new node in object tree.");
-	}
 	for (i=0; i < req->op.mod.message->num_elements; i++){
 		const struct dsdb_attribute *attr;
 		attr = dsdb_attribute_by_lDAPDisplayName(schema,
@@ -1072,6 +1064,8 @@ static int acl_modify(struct ldb_module
 				goto fail;
 			}
 		} else {
+			struct object_tree *root = NULL;
+			struct object_tree *new_node = NULL;
 
 		/* This basic attribute existence check with the right errorcode
 		 * is needed since this module is the first one which requests
@@ -1086,6 +1080,14 @@ static int acl_modify(struct ldb_module
 				ret =  LDB_ERR_NO_SUCH_ATTRIBUTE;
 				goto fail;
 			}
+
+			if (!insert_in_object_tree(tmp_ctx, guid, SEC_ADS_WRITE_PROP,
+						   &root, &new_node)) {
+				talloc_free(tmp_ctx);
+				return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
+						 "acl_modify: Error adding new node in object tree.");
+			}
+
 			if (!insert_in_object_tree(tmp_ctx,
 						   &attr->attributeSecurityGUID, SEC_ADS_WRITE_PROP,
 						   &new_node, &new_node)) {
@@ -1102,27 +1104,24 @@ static int acl_modify(struct ldb_module
 				ret = LDB_ERR_OPERATIONS_ERROR;
 				goto fail;
 			}
-		}
-	}
-
-	if (root->num_of_children > 0) {
-		status = sec_access_check_ds(sd, acl_user_token(module),
-					     SEC_ADS_WRITE_PROP,
-					     &access_granted,
-					     root,
-					     sid);
 
-		if (!NT_STATUS_IS_OK(status)) {
-			ldb_asprintf_errstring(ldb_module_get_ctx(module),
-					       "Object %s has no write property access\n",
-					       ldb_dn_get_linearized(req->op.mod.message->dn));
-			dsdb_acl_debug(sd,
-				       acl_user_token(module),
-				       req->op.mod.message->dn,
-				       true,
-				       10);
-			ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
-			goto fail;
+			status = sec_access_check_ds(sd, acl_user_token(module),
+						     SEC_ADS_WRITE_PROP,
+						     &access_granted,
+						     root,
+						     sid);
+			if (!NT_STATUS_IS_OK(status)) {
+				ldb_asprintf_errstring(ldb_module_get_ctx(module),
+						       "Object %s has no write property access\n",
+						       ldb_dn_get_linearized(req->op.mod.message->dn));
+				dsdb_acl_debug(sd,
+					       acl_user_token(module),
+					       req->op.mod.message->dn,
+					       true,
+					       10);
+				ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
+				goto fail;
+			}
 		}
 	}
 
--- samba4-4.0.0~beta2+dfsg1.orig/source4/dsdb/tests/python/acl.py
+++ samba4-4.0.0~beta2+dfsg1/source4/dsdb/tests/python/acl.py
@@ -389,6 +389,21 @@ url: www.samba.org"""
         else:
             # This 'modify' operation should always throw ERR_INSUFFICIENT_ACCESS_RIGHTS
             self.fail()
+        # Modify on attribute you do not have rights for granted while also modifying something you do have rights for
+        ldif = """
+dn: CN=test_modify_group1,CN=Users,""" + self.base_dn + """
+changetype: modify
+replace: url
+url: www.samba.org
+replace: displayName
+displayName: test_changed"""
+        try:
+            self.ldb_user.modify_ldif(ldif)
+        except LdbError, (num, _):
+            self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
+        else:
+            # This 'modify' operation should always throw ERR_INSUFFICIENT_ACCESS_RIGHTS
+            self.fail()
         # Second test object -- Organizational Unit
         print "Testing modify on OU object"
         self.ldb_admin.create_ou("OU=test_modify_ou1," + self.base_dn)
