dsdb: Change acl module to look for instanceType flag rather than list of NCs
authorAndrew Bartlett <abartlet@samba.org>
Fri, 6 Sep 2013 03:48:29 +0000 (15:48 +1200)
committerAndrew Bartlett <abartlet@samba.org>
Sun, 31 Aug 2014 22:36:41 +0000 (00:36 +0200)
This avoids any DNs being a free pass beyond the ACL code, instead it is based on the CN=Partitions ACL.

Andrew Bartlett

Change-Id: Ib2f4abe0165e47fa4a71925d126c2eeec68df119
Signed-off-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
source4/dsdb/samdb/ldb_modules/acl.c
source4/dsdb/samdb/ldb_modules/instancetype.c

index b4f7cef13819bf47f711f1bae370f01c38bffcf6..2ba57b72cdb4accf0510b9f0ad15f54b27fc0bf2 100644 (file)
@@ -749,8 +749,9 @@ static int acl_add(struct ldb_module *module, struct ldb_request *req)
        struct ldb_context *ldb;
        const struct dsdb_schema *schema;
        const struct dsdb_class *objectclass;
-       struct ldb_dn *nc_root;
        struct ldb_control *as_system;
+       struct ldb_message_element *el;
+       unsigned int instanceType = 0;
 
        if (ldb_dn_is_special(req->op.add.message->dn)) {
                return ldb_next_request(module, req);
@@ -772,19 +773,6 @@ static int acl_add(struct ldb_module *module, struct ldb_request *req)
                return ldb_oom(ldb);
        }
 
-       /* Creating an NC. There is probably something we should do here,
-        * but we will establish that later */
-
-       ret = dsdb_find_nc_root(ldb, req, req->op.add.message->dn, &nc_root);
-       if (ret != LDB_SUCCESS) {
-               return ret;
-       }
-       if (ldb_dn_compare(nc_root, req->op.add.message->dn) == 0) {
-               talloc_free(nc_root);
-               return ldb_next_request(module, req);
-       }
-       talloc_free(nc_root);
-
        schema = dsdb_get_schema(ldb, req);
        if (!schema) {
                return ldb_operr(ldb);
@@ -793,15 +781,94 @@ static int acl_add(struct ldb_module *module, struct ldb_request *req)
        objectclass = dsdb_get_structural_oc_from_msg(schema, req->op.add.message);
        if (!objectclass) {
                ldb_asprintf_errstring(ldb_module_get_ctx(module),
-                                      "acl: unable to find or validate structrual objectClass on %s\n",
+                                      "acl: unable to find or validate structural objectClass on %s\n",
                                       ldb_dn_get_linearized(req->op.add.message->dn));
                return ldb_module_done(req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
        }
 
+       el = ldb_msg_find_element(req->op.add.message, "instanceType");
+       if ((el != NULL) && (el->num_values != 1)) {
+               ldb_set_errstring(ldb, "acl: the 'instanceType' attribute is single-valued!");
+               return LDB_ERR_UNWILLING_TO_PERFORM;
+       }
+
+       instanceType = ldb_msg_find_attr_as_uint(req->op.add.message,
+                                                "instanceType", 0);
+       if (instanceType & INSTANCE_TYPE_IS_NC_HEAD) {
+               static const char *no_attrs[] = { NULL };
+               struct ldb_result *partition_res;
+               struct ldb_dn *partitions_dn;
+
+               partitions_dn = samdb_partitions_dn(ldb, req);
+               if (!partitions_dn) {
+                       ldb_set_errstring(ldb, "acl: CN=partitions dn could not be generated!");
+                       return LDB_ERR_UNWILLING_TO_PERFORM;
+               }
+
+               ret = dsdb_module_search(module, req, &partition_res,
+                                        partitions_dn, LDB_SCOPE_ONELEVEL,
+                                        no_attrs,
+                                        DSDB_FLAG_NEXT_MODULE |
+                                        DSDB_FLAG_AS_SYSTEM |
+                                        DSDB_SEARCH_ONE_ONLY |
+                                        DSDB_SEARCH_SHOW_RECYCLED,
+                                        req,
+                                        "(&(nCName=%s)(objectClass=crossRef))",
+                                        ldb_dn_get_linearized(req->op.add.message->dn));
+
+               if (ret == LDB_SUCCESS) {
+                       /* Check that we can write to the crossRef object MS-ADTS 3.1.1.5.2.8.2 */
+                       ret = dsdb_module_check_access_on_dn(module, req, partition_res->msgs[0]->dn,
+                                                            SEC_ADS_WRITE_PROP,
+                                                            &objectclass->schemaIDGUID, req);
+                       if (ret != LDB_SUCCESS) {
+                               ldb_asprintf_errstring(ldb_module_get_ctx(module),
+                                                      "acl: ACL check failed on crossRef object %s: %s\n",
+                                                      ldb_dn_get_linearized(partition_res->msgs[0]->dn),
+                                                      ldb_errstring(ldb));
+                               return ret;
+                       }
+
+                       /*
+                        * TODO: Remaining checks, like if we are
+                        * the naming master etc need to be handled
+                        * in the instanceType module
+                        */
+                       return ldb_next_request(module, req);
+               }
+
+               /* Check that we can create a crossRef object MS-ADTS 3.1.1.5.2.8.2 */
+               ret = dsdb_module_check_access_on_dn(module, req, partitions_dn,
+                                                    SEC_ADS_CREATE_CHILD,
+                                                    &objectclass->schemaIDGUID, req);
+               if (ret == LDB_ERR_NO_SUCH_OBJECT &&
+                   ldb_request_get_control(req, LDB_CONTROL_RELAX_OID))
+               {
+                       /* Allow provision bootstrap */
+                       ret = LDB_SUCCESS;
+               }
+               if (ret != LDB_SUCCESS) {
+                       ldb_asprintf_errstring(ldb_module_get_ctx(module),
+                                              "acl: ACL check failed on CN=Partitions crossRef container %s: %s\n",
+                                              ldb_dn_get_linearized(partitions_dn), ldb_errstring(ldb));
+                       return ret;
+               }
+
+               /*
+                * TODO: Remaining checks, like if we are the naming
+                * master and adding the crossRef object need to be
+                * handled in the instanceType module
+                */
+               return ldb_next_request(module, req);
+       }
+
        ret = dsdb_module_check_access_on_dn(module, req, parent,
                                             SEC_ADS_CREATE_CHILD,
                                             &objectclass->schemaIDGUID, req);
        if (ret != LDB_SUCCESS) {
+               ldb_asprintf_errstring(ldb_module_get_ctx(module),
+                                      "acl: unable to find or validate structrual objectClass on %s\n",
+                                      ldb_dn_get_linearized(req->op.add.message->dn));
                return ret;
        }
        return ldb_next_request(module, req);
index c35f4b6a262309b91d5c04a5c83ba5452213d377..d700adf69ac583c6aef68a8416853cef6f18a043 100644 (file)
@@ -84,6 +84,11 @@ static int instancetype_add(struct ldb_module *module, struct ldb_request *req)
                                ldb_set_errstring(ldb, "instancetype: if TYPE_IS_NC_HEAD was set, then also TYPE_WRITE is requested!");
                                return LDB_ERR_UNWILLING_TO_PERFORM;
                        }
+                       /*
+                        * TODO: Confirm we are naming master or start
+                        * a remote call to the naming master to
+                        * create the crossRef object
+                        */
                }
 
                /* we did only tests, so proceed with the original request */