Implementation of LDAP_SERVER_SD_FLAGS_OID on modify requests.
authorNadezhda Ivanova <nadezhda.ivanova@postpath.com>
Fri, 20 Nov 2009 11:25:13 +0000 (13:25 +0200)
committerNadezhda Ivanova <nadezhda.ivanova@postpath.com>
Fri, 20 Nov 2009 11:25:13 +0000 (13:25 +0200)
source4/dsdb/samdb/ldb_modules/descriptor.c
source4/lib/ldb/tests/python/sec_descriptor.py

index 6a5756031456b6e2e1b4c6727cc87d8a013f8125..98e54b19c17bd89ad1593cbed8b5ed6ba3fa41c4 100644 (file)
@@ -154,15 +154,85 @@ static struct dom_sid *get_default_group(TALLOC_CTX *mem_ctx,
        return NULL;
 }
 
+static struct security_descriptor *descr_handle_sd_flags(TALLOC_CTX *mem_ctx,
+                                                        struct security_descriptor *new_sd,
+                                                        struct security_descriptor *old_sd,
+                                                        uint32_t sd_flags)
+{
+       struct security_descriptor *final_sd; 
+       /* if there is no control or contlol == 0 modify everything */
+       if (!sd_flags) {
+               return new_sd;
+       }
+
+       final_sd = talloc_zero(mem_ctx, struct security_descriptor);
+       final_sd->revision = SECURITY_DESCRIPTOR_REVISION_1;
+       final_sd->type = SEC_DESC_SELF_RELATIVE;
+
+       if (sd_flags & (SECINFO_OWNER)) {
+               final_sd->owner_sid = talloc_memdup(mem_ctx, new_sd->owner_sid, sizeof(struct dom_sid));
+               final_sd->type |= new_sd->type & SEC_DESC_OWNER_DEFAULTED;
+       }
+       else if (old_sd) {
+               final_sd->owner_sid = talloc_memdup(mem_ctx, old_sd->owner_sid, sizeof(struct dom_sid));
+               final_sd->type |= old_sd->type & SEC_DESC_OWNER_DEFAULTED;
+       }
+
+       if (sd_flags & (SECINFO_GROUP)) {
+               final_sd->group_sid = talloc_memdup(mem_ctx, new_sd->group_sid, sizeof(struct dom_sid));
+               final_sd->type |= new_sd->type & SEC_DESC_GROUP_DEFAULTED;
+       } 
+       else if (old_sd) {
+               final_sd->group_sid = talloc_memdup(mem_ctx, old_sd->group_sid, sizeof(struct dom_sid));
+               final_sd->type |= old_sd->type & SEC_DESC_GROUP_DEFAULTED;
+       }
+
+       if (sd_flags & (SECINFO_SACL)) {
+               final_sd->sacl = security_acl_dup(mem_ctx,new_sd->sacl);
+               final_sd->type |= new_sd->type & (SEC_DESC_SACL_PRESENT |
+                       SEC_DESC_SACL_DEFAULTED|SEC_DESC_SACL_AUTO_INHERIT_REQ |
+                       SEC_DESC_SACL_AUTO_INHERITED|SEC_DESC_SACL_PROTECTED |
+                       SEC_DESC_SERVER_SECURITY);
+       } 
+       else if (old_sd) {
+               final_sd->sacl = security_acl_dup(mem_ctx,old_sd->sacl);
+               final_sd->type |= old_sd->type & (SEC_DESC_SACL_PRESENT |
+                       SEC_DESC_SACL_DEFAULTED|SEC_DESC_SACL_AUTO_INHERIT_REQ |
+                       SEC_DESC_SACL_AUTO_INHERITED|SEC_DESC_SACL_PROTECTED |
+                       SEC_DESC_SERVER_SECURITY);
+       }
+
+       if (sd_flags & (SECINFO_DACL)) {
+               final_sd->dacl = security_acl_dup(mem_ctx,new_sd->dacl);
+               final_sd->type |= new_sd->type & (SEC_DESC_DACL_PRESENT |
+                       SEC_DESC_DACL_DEFAULTED|SEC_DESC_DACL_AUTO_INHERIT_REQ |
+                       SEC_DESC_DACL_AUTO_INHERITED|SEC_DESC_DACL_PROTECTED |
+                       SEC_DESC_DACL_TRUSTED);
+       } 
+       else if (old_sd) {
+               final_sd->dacl = security_acl_dup(mem_ctx,old_sd->dacl);
+               final_sd->type |= old_sd->type & (SEC_DESC_DACL_PRESENT |
+                       SEC_DESC_DACL_DEFAULTED|SEC_DESC_DACL_AUTO_INHERIT_REQ |
+                       SEC_DESC_DACL_AUTO_INHERITED|SEC_DESC_DACL_PROTECTED |
+                       SEC_DESC_DACL_TRUSTED);
+       }
+       /* not so sure about this */
+       final_sd->type |= new_sd->type & SEC_DESC_RM_CONTROL_VALID;
+       return final_sd;
+}
+
 static DATA_BLOB *get_new_descriptor(struct ldb_module *module,
                                     struct ldb_dn *dn,
                                     TALLOC_CTX *mem_ctx,
                                     const struct dsdb_class *objectclass,
                                     const struct ldb_val *parent,
-                                    struct ldb_val *object)
+                                    struct ldb_val *object,
+                                    struct ldb_val *old_sd,
+                                    uint32_t sd_flags)
 {
        struct security_descriptor *user_descriptor = NULL, *parent_descriptor = NULL;
-       struct security_descriptor *new_sd;
+       struct security_descriptor *old_descriptor = NULL;
+       struct security_descriptor *new_sd, *final_sd;
        DATA_BLOB *linear_sd;
        enum ndr_err_code ndr_err;
        struct ldb_context *ldb = ldb_module_get_ctx(module);
@@ -175,13 +245,14 @@ static DATA_BLOB *get_new_descriptor(struct ldb_module *module,
 
        if (object) {
                user_descriptor = talloc(mem_ctx, struct security_descriptor);
-               if(!user_descriptor)
+               if (!user_descriptor) {
                        return NULL;
+               }
                ndr_err = ndr_pull_struct_blob(object, user_descriptor, NULL,
                                               user_descriptor,
                                               (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
 
-               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)){
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
                        talloc_free(user_descriptor);
                        return NULL;
                }
@@ -189,19 +260,36 @@ static DATA_BLOB *get_new_descriptor(struct ldb_module *module,
                user_descriptor = get_sd_unpacked(module, mem_ctx, objectclass);
        }
 
-       if (parent){
+       if (old_sd) {
+               old_descriptor = talloc(mem_ctx, struct security_descriptor);
+               if (!old_descriptor) {
+                       return NULL;
+               }
+               ndr_err = ndr_pull_struct_blob(old_sd, old_descriptor, NULL,
+                                              old_descriptor,
+                                              (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
+
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                       talloc_free(old_descriptor);
+                       return NULL;
+               }
+       }
+
+       if (parent) {
                parent_descriptor = talloc(mem_ctx, struct security_descriptor);
-               if(!parent_descriptor)
+               if (!parent_descriptor) {
                        return NULL;
+               }
                ndr_err = ndr_pull_struct_blob(parent, parent_descriptor, NULL,
                                               parent_descriptor,
                                               (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
 
-               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)){
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
                        talloc_free(parent_descriptor);
                        return NULL;
                }
        }
+
        default_owner = get_default_ag(mem_ctx, dn,
                                       session_info->security_token, ldb);
        default_group = get_default_group(mem_ctx, ldb, default_owner);
@@ -210,11 +298,15 @@ static DATA_BLOB *get_new_descriptor(struct ldb_module *module,
                                            session_info->security_token,
                                            default_owner, default_group,
                                            map_generic_rights_ds);
-       if (!new_sd)
+       if (!new_sd) {
                return NULL;
+       }
+       final_sd = descr_handle_sd_flags(mem_ctx, new_sd, old_descriptor, sd_flags);
 
-
-       sddl_sd = sddl_encode(mem_ctx, new_sd, domain_sid);
+       if (!final_sd) {
+               return NULL;
+       }
+       sddl_sd = sddl_encode(mem_ctx, final_sd, domain_sid);
        DEBUG(10, ("Object %s created with desriptor %s\n\n", ldb_dn_get_linearized(dn), sddl_sd));
 
        linear_sd = talloc(mem_ctx, DATA_BLOB);
@@ -224,7 +316,7 @@ static DATA_BLOB *get_new_descriptor(struct ldb_module *module,
 
        ndr_err = ndr_push_struct_blob(linear_sd, mem_ctx,
                                       lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
-                                      new_sd,
+                                      final_sd,
                                       (ndr_push_flags_fn_t)ndr_push_security_descriptor);
        if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
                return NULL;
@@ -383,12 +475,16 @@ static int descriptor_do_mod(struct descriptor_context *ac)
        struct ldb_context *ldb;
        const struct dsdb_schema *schema;
        struct ldb_request *mod_req;
-       struct ldb_message_element *objectclass_element, *tmp_element;
+       struct ldb_message_element *objectclass_element, *tmp_element, *oldsd_el;
+       struct ldb_val *oldsd_val = NULL;
        int ret;
        DATA_BLOB *sd;
        const struct dsdb_class *objectclass;
        struct ldb_message *msg;
+       struct ldb_control *sd_control;
+       struct ldb_control **saved_controls;
        int flags = 0;
+       uint32_t sd_flags = 0;
 
        ldb = ldb_module_get_ctx(ac->module);
        schema = dsdb_get_schema(ldb);
@@ -402,9 +498,21 @@ static int descriptor_do_mod(struct descriptor_context *ac)
                                       ldb_dn_get_linearized(ac->search_oc_res->message->dn));
                return LDB_ERR_OPERATIONS_ERROR;
        }
-
+       sd_control = ldb_request_get_control(ac->req, LDB_CONTROL_SD_FLAGS_OID);
+       if (sd_control) {
+               struct ldb_sd_flags_control *sdctr = (struct ldb_sd_flags_control *)sd_control->data;
+               sd_flags = sdctr->secinfo_flags;
+               /* we only care for the last 4 bits */
+               sd_flags = sd_flags & 0x0000000F;
+       }
+       if (sd_flags != 0) {
+               oldsd_el = ldb_msg_find_element(ac->search_oc_res->message, "nTSecurityDescriptor");
+               if (oldsd_el) {
+                       oldsd_val = oldsd_el->values;
+               }
+       }
        sd = get_new_descriptor(ac->module, msg->dn, ac, objectclass,
-                               ac->parentsd_val, ac->sd_val);
+                               ac->parentsd_val, ac->sd_val, oldsd_val, sd_flags);
        if (ac->sd_val) {
                tmp_element = ldb_msg_find_element(msg, "ntSecurityDescriptor");
                flags = tmp_element->flags;
@@ -427,6 +535,15 @@ static int descriptor_do_mod(struct descriptor_context *ac)
        if (ret != LDB_SUCCESS) {
                return ret;
        }
+       /* save it locally and remove it from the list */
+       /* we do not need to replace them later as we
+        * are keeping the original req intact */
+       if (sd_control) {
+               if (!save_controls(sd_control, mod_req, &saved_controls)) {
+                       return LDB_ERR_OPERATIONS_ERROR;
+               }
+       }
+
        return ldb_next_request(ac->module, mod_req);
 }
 
@@ -441,7 +558,7 @@ static int descriptor_do_add(struct descriptor_context *ac)
        int ret;
        DATA_BLOB *sd;
        const struct dsdb_class *objectclass;
-       static const char *const attrs[] = { "objectClass", NULL };
+       static const char *const attrs[] = { "objectClass", "nTSecurityDescriptor", NULL };
        struct ldb_request *search_req;
 
        ldb = ldb_module_get_ctx(ac->module);
@@ -491,7 +608,7 @@ static int descriptor_do_add(struct descriptor_context *ac)
        /* get the parent descriptor and the one provided. If not provided, get the default.*/
        /* convert to security descriptor and calculate */
                sd = get_new_descriptor(ac->module, msg->dn, mem_ctx, objectclass,
-                                       ac->parentsd_val, ac->sd_val);
+                                       ac->parentsd_val, ac->sd_val, NULL, 0);
                if (ac->sd_val) {
                        ldb_msg_remove_attr(msg, "nTSecurityDescriptor");
                }
index 2770176f898013e2a38d8565d6bfd74670f0a0ec..8763579dc06de32d13ea30327dd03f0bcd4e6fab 100755 (executable)
@@ -25,7 +25,8 @@ from samba.ndr import ndr_pack, ndr_unpack
 from samba.dcerpc import security
 
 from samba.auth import system_session
-from samba import Ldb, DS_DOMAIN_FUNCTION_2008
+from samba import Ldb, DS_DOMAIN_FUNCTION_2008, SECINFO_OWNER, \
+    SECINFO_GROUP, SECINFO_DACL, SECINFO_SACL
 from subunit import SubunitTestRunner
 import unittest
 
@@ -83,7 +84,7 @@ class DescriptorTests(unittest.TestCase):
     def get_users_domain_dn(self, name):
         return "CN=%s,CN=Users,%s" % (name, self.base_dn)
 
-    def modify_desc(self, _ldb, object_dn, desc):
+    def modify_desc(self, _ldb, object_dn, desc, controls=None):
         assert(isinstance(desc, str) or isinstance(desc, security.descriptor))
         mod = """
 dn: """ + object_dn + """
@@ -94,9 +95,9 @@ replace: nTSecurityDescriptor
             mod += "nTSecurityDescriptor: %s" % desc
         elif isinstance(desc, security.descriptor):
             mod += "nTSecurityDescriptor:: %s" % base64.b64encode(ndr_pack(desc))
-        _ldb.modify_ldif(mod)
+        _ldb.modify_ldif(mod, controls)
 
-    def create_domain_ou(self, _ldb, ou_dn, desc=None):
+    def create_domain_ou(self, _ldb, ou_dn, desc=None, controls=None):
         ldif = """
 dn: """ + ou_dn + """
 ou: """ + ou_dn.split(",")[0][3:] + """
@@ -109,7 +110,7 @@ url: www.example.com
                 ldif += "nTSecurityDescriptor: %s" % desc
             elif isinstance(desc, security.descriptor):
                 ldif += "nTSecurityDescriptor:: %s" % base64.b64encode(ndr_pack(desc))
-        _ldb.add_ldif(ldif)
+        _ldb.add_ldif(ldif, controls)
 
     def create_domain_user(self, _ldb, user_dn, desc=None):
         ldif = """
@@ -1683,6 +1684,105 @@ class DaclDescriptorTests(DescriptorTests):
 
     ########################################################################################
 
+
+class SdFlagsDescriptorTests(DescriptorTests):
+    def setUp(self):
+        DescriptorTests.setUp(self)
+        self.test_descr = "O:AUG:AUD:(D;;CC;;;LG)S:(OU;;WP;;;AU)"
+
+    def tearDown(self):
+        self.delete_force(self.ldb_admin, "OU=test_sdflags_ou," + self.base_dn)
+
+    def test_301(self):
+        """ Modify a descriptor with OWNER_SECURITY_INFORMATION set.
+            See that only the owner has been changed.
+        """
+        ou_dn = "OU=test_sdflags_ou," + self.base_dn
+        self.create_domain_ou(self.ldb_admin, ou_dn)
+        self.modify_desc(self.ldb_admin, ou_dn, self.test_descr, controls=["sd_flags:1:%d" % (SECINFO_OWNER)])
+        desc_sddl = self.get_desc_sddl(ou_dn)
+        # make sure we have modified the owner
+        self.assertTrue("O:AU" in desc_sddl)
+        # make sure nothing else has been modified
+        self.assertFalse("G:AU" in desc_sddl)
+        self.assertFalse("D:(D;;CC;;;LG)" in desc_sddl)
+        self.assertFalse("(OU;;WP;;;AU)" in desc_sddl)
+
+    def test_302(self):
+        """ Modify a descriptor with GROUP_SECURITY_INFORMATION set.
+            See that only the owner has been changed.
+        """
+        ou_dn = "OU=test_sdflags_ou," + self.base_dn
+        self.create_domain_ou(self.ldb_admin, ou_dn)
+        self.modify_desc(self.ldb_admin, ou_dn, self.test_descr, controls=["sd_flags:1:%d" % (SECINFO_GROUP)])
+        desc_sddl = self.get_desc_sddl(ou_dn)
+        # make sure we have modified the group
+        self.assertTrue("G:AU" in desc_sddl)
+        # make sure nothing else has been modified
+        self.assertFalse("O:AU" in desc_sddl)
+        self.assertFalse("D:(D;;CC;;;LG)" in desc_sddl)
+        self.assertFalse("(OU;;WP;;;AU)" in desc_sddl)
+
+    def test_303(self):
+        """ Modify a descriptor with SACL_SECURITY_INFORMATION set.
+            See that only the owner has been changed.
+        """
+        ou_dn = "OU=test_sdflags_ou," + self.base_dn
+        self.create_domain_ou(self.ldb_admin, ou_dn)
+        self.modify_desc(self.ldb_admin, ou_dn, self.test_descr, controls=["sd_flags:1:%d" % (SECINFO_DACL)])
+        desc_sddl = self.get_desc_sddl(ou_dn)
+        # make sure we have modified the DACL
+        self.assertTrue("(D;;CC;;;LG)" in desc_sddl)
+        # make sure nothing else has been modified
+        self.assertFalse("O:AU" in desc_sddl)
+        self.assertFalse("G:AU" in desc_sddl)
+        self.assertFalse("(OU;;WP;;;AU)" in desc_sddl)
+
+    def test_304(self):
+        """ Modify a descriptor with SACL_SECURITY_INFORMATION set.
+            See that only the owner has been changed.
+        """
+        ou_dn = "OU=test_sdflags_ou," + self.base_dn
+        self.create_domain_ou(self.ldb_admin, ou_dn)
+        self.modify_desc(self.ldb_admin, ou_dn, self.test_descr, controls=["sd_flags:1:%d" % (SECINFO_SACL)])
+        desc_sddl = self.get_desc_sddl(ou_dn)
+        # make sure we have modified the DACL
+        self.assertTrue("(OU;;WP;;;AU)" in desc_sddl)
+        # make sure nothing else has been modified
+        self.assertFalse("O:AU" in desc_sddl)
+        self.assertFalse("G:AU" in desc_sddl)
+        self.assertFalse("(D;;CC;;;LG)" in desc_sddl)
+
+    def test_305(self):
+        """ Modify a descriptor with 0x0 set.
+            Contrary to logic this is interpreted as no control,
+            which is the same as 0xF
+        """
+        ou_dn = "OU=test_sdflags_ou," + self.base_dn
+        self.create_domain_ou(self.ldb_admin, ou_dn)
+        self.modify_desc(self.ldb_admin, ou_dn, self.test_descr, controls=["sd_flags:1:0"])
+        desc_sddl = self.get_desc_sddl(ou_dn)
+        # make sure we have modified the DACL
+        self.assertTrue("(OU;;WP;;;AU)" in desc_sddl)
+        # make sure nothing else has been modified
+        self.assertTrue("O:AU" in desc_sddl)
+        self.assertTrue("G:AU" in desc_sddl)
+        self.assertTrue("(D;;CC;;;LG)" in desc_sddl)
+
+    def test_306(self):
+        """ Modify a descriptor with 0xF set.
+        """
+        ou_dn = "OU=test_sdflags_ou," + self.base_dn
+        self.create_domain_ou(self.ldb_admin, ou_dn)
+        self.modify_desc(self.ldb_admin, ou_dn, self.test_descr, controls=["sd_flags:1:15"])
+        desc_sddl = self.get_desc_sddl(ou_dn)
+        # make sure we have modified the DACL
+        self.assertTrue("(OU;;WP;;;AU)" in desc_sddl)
+        # make sure nothing else has been modified
+        self.assertTrue("O:AU" in desc_sddl)
+        self.assertTrue("G:AU" in desc_sddl)
+        self.assertTrue("(D;;CC;;;LG)" in desc_sddl)
+
 if not "://" in host:
     host = "ldap://%s" % host
 ldb = Ldb(host, credentials=creds, session_info=system_session(), lp=lp, options=["modules:paged_searches"])
@@ -1693,5 +1793,7 @@ if not runner.run(unittest.makeSuite(OwnerGroupDescriptorTests)).wasSuccessful()
     rc = 1
 if not runner.run(unittest.makeSuite(DaclDescriptorTests)).wasSuccessful():
     rc = 1
+if not runner.run(unittest.makeSuite(SdFlagsDescriptorTests)).wasSuccessful():
+    rc = 1
 
 sys.exit(rc)