Merge branch 'master' of ssh://jra@git.samba.org/data/git/samba
[ira/wip.git] / source4 / dsdb / samdb / ldb_modules / kludge_acl.c
index 6acbf45afd8653c7c526fa18b92cf6f4a6b52225..79309e82bf7b23ee90afdeda96bb5e2caf454939 100644 (file)
  */
 
 #include "includes.h"
-#include "ldb/include/ldb.h"
-#include "ldb/include/ldb_errors.h"
-#include "ldb/include/ldb_private.h"
+#include "ldb_module.h"
 #include "auth/auth.h"
 #include "libcli/security/security.h"
 #include "dsdb/samdb/samdb.h"
+#include "param/param.h"
 
 /* Kludge ACL rules:
  *
 
 struct kludge_private_data {
        const char **password_attrs;
+       bool acl_perform;
 };
 
 static enum security_user_level what_is_user(struct ldb_module *module) 
 {
+       struct ldb_context *ldb = ldb_module_get_ctx(module);
        struct auth_session_info *session_info
-               = (struct auth_session_info *)ldb_get_opaque(module->ldb, "sessionInfo");
+               = (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
        return security_session_user_level(session_info);
 }
 
 static const char *user_name(TALLOC_CTX *mem_ctx, struct ldb_module *module) 
 {
+       struct ldb_context *ldb = ldb_module_get_ctx(module);
        struct auth_session_info *session_info
-               = (struct auth_session_info *)ldb_get_opaque(module->ldb, "sessionInfo");
+               = (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
        if (!session_info) {
                return "UNKNOWN (NULL)";
        }
@@ -93,7 +95,7 @@ static int kludge_acl_allowedAttributes(struct ldb_context *ldb, struct ldb_mess
        struct ldb_message_element *allowedAttributes;
        const struct dsdb_schema *schema = dsdb_get_schema(ldb);
        TALLOC_CTX *mem_ctx;
-       char **objectclass_list, **attr_list;
+       const char **attr_list;
        int i, ret;
 
        /* If we don't have a schema yet, we can't do anything... */
@@ -118,19 +120,7 @@ static int kludge_acl_allowedAttributes(struct ldb_context *ldb, struct ldb_mess
           we alter the element array in ldb_msg_add_empty() */
        oc_el = ldb_msg_find_element(msg, "objectClass");
        
-       objectclass_list = talloc_array(mem_ctx, char *, oc_el->num_values + 1);
-       if (!objectclass_list) {
-               ldb_oom(ldb);
-               talloc_free(mem_ctx);
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-
-       for (i=0; oc_el && i < oc_el->num_values; i++) {
-               objectclass_list[i] = (char *)oc_el->values[i].data;
-       }
-       objectclass_list[i] = NULL;
-
-       attr_list = dsdb_full_attribute_list(mem_ctx, schema, (const char **)objectclass_list, DSDB_SCHEMA_ALL);
+       attr_list = dsdb_full_attribute_list(mem_ctx, schema, oc_el, DSDB_SCHEMA_ALL);
        if (!attr_list) {
                ldb_asprintf_errstring(ldb, "kludge_acl: Failed to get list of attributes create %s attribute", attrName);
                talloc_free(mem_ctx);
@@ -152,7 +142,7 @@ static int kludge_acl_childClasses(struct ldb_context *ldb, struct ldb_message *
        struct ldb_message_element *oc_el;
        struct ldb_message_element *allowedClasses;
        const struct dsdb_schema *schema = dsdb_get_schema(ldb);
-       const struct dsdb_class *class;
+       const struct dsdb_class *sclass;
        int i, j, ret;
 
        /* If we don't have a schema yet, we can't do anything... */
@@ -172,14 +162,14 @@ static int kludge_acl_childClasses(struct ldb_context *ldb, struct ldb_message *
        oc_el = ldb_msg_find_element(msg, "objectClass");
 
        for (i=0; oc_el && i < oc_el->num_values; i++) {
-               class = dsdb_class_by_lDAPDisplayName(schema, (const char *)oc_el->values[i].data);
-               if (!class) {
+               sclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &oc_el->values[i]);
+               if (!sclass) {
                        /* We don't know this class?  what is going on? */
                        continue;
                }
 
-               for (j=0; class->possibleInferiors && class->possibleInferiors[j]; j++) {
-                       ldb_msg_add_string(msg, attrName, class->possibleInferiors[j]);
+               for (j=0; sclass->possibleInferiors && sclass->possibleInferiors[j]; j++) {
+                       ldb_msg_add_string(msg, attrName, sclass->possibleInferiors[j]);
                }
        }
                
@@ -209,12 +199,14 @@ static int kludge_acl_childClasses(struct ldb_context *ldb, struct ldb_message *
 
 static int kludge_acl_callback(struct ldb_request *req, struct ldb_reply *ares)
 {
+       struct ldb_context *ldb;
        struct kludge_acl_context *ac;
        struct kludge_private_data *data;
        int i, ret;
 
        ac = talloc_get_type(req->context, struct kludge_acl_context);
-       data = talloc_get_type(ac->module->private_data, struct kludge_private_data);
+       data = talloc_get_type(ldb_module_get_private(ac->module), struct kludge_private_data);
+       ldb = ldb_module_get_ctx(ac->module);
 
        if (!ares) {
                return ldb_module_done(ac->req, NULL, NULL,
@@ -228,7 +220,7 @@ static int kludge_acl_callback(struct ldb_request *req, struct ldb_reply *ares)
        switch (ares->type) {
        case LDB_REPLY_ENTRY:
                if (ac->allowedAttributes) {
-                       ret = kludge_acl_allowedAttributes(ac->module->ldb,
+                       ret = kludge_acl_allowedAttributes(ldb,
                                                   ares->message,
                                                   "allowedAttributes");
                        if (ret != LDB_SUCCESS) {
@@ -236,7 +228,7 @@ static int kludge_acl_callback(struct ldb_request *req, struct ldb_reply *ares)
                        }
                }
                if (ac->allowedChildClasses) {
-                       ret = kludge_acl_childClasses(ac->module->ldb,
+                       ret = kludge_acl_childClasses(ldb,
                                                ares->message,
                                                "allowedChildClasses");
                        if (ret != LDB_SUCCESS) {
@@ -249,14 +241,14 @@ static int kludge_acl_callback(struct ldb_request *req, struct ldb_reply *ares)
                        switch (ac->user_type) {
                        case SECURITY_SYSTEM:
                                if (ac->allowedAttributesEffective) {
-                                       ret = kludge_acl_allowedAttributes(ac->module->ldb, ares->message,
+                                       ret = kludge_acl_allowedAttributes(ldb, ares->message,
                                                                        "allowedAttributesEffective");
                                        if (ret != LDB_SUCCESS) {
                                                return ldb_module_done(ac->req, NULL, NULL, ret);
                                        }
                                }
                                if (ac->allowedChildClassesEffective) {
-                                       ret = kludge_acl_childClasses(ac->module->ldb, ares->message,
+                                       ret = kludge_acl_childClasses(ldb, ares->message,
                                                                        "allowedChildClassesEffective");
                                        if (ret != LDB_SUCCESS) {
                                                return ldb_module_done(ac->req, NULL, NULL, ret);
@@ -266,14 +258,14 @@ static int kludge_acl_callback(struct ldb_request *req, struct ldb_reply *ares)
 
                        case SECURITY_ADMINISTRATOR:
                                if (ac->allowedAttributesEffective) {
-                                       ret = kludge_acl_allowedAttributes(ac->module->ldb, ares->message,
+                                       ret = kludge_acl_allowedAttributes(ldb, ares->message,
                                                                        "allowedAttributesEffective");
                                        if (ret != LDB_SUCCESS) {
                                                return ldb_module_done(ac->req, NULL, NULL, ret);
                                        }
                                }
                                if (ac->allowedChildClassesEffective) {
-                                       ret = kludge_acl_childClasses(ac->module->ldb, ares->message,
+                                       ret = kludge_acl_childClasses(ldb, ares->message,
                                                                        "allowedChildClassesEffective");
                                        if (ret != LDB_SUCCESS) {
                                                return ldb_module_done(ac->req, NULL, NULL, ret);
@@ -301,7 +293,7 @@ static int kludge_acl_callback(struct ldb_request *req, struct ldb_reply *ares)
                        }
                }
 
-               return ldb_module_send_entry(ac->req, ares->message);
+               return ldb_module_send_entry(ac->req, ares->message, ares->controls);
 
        case LDB_REPLY_REFERRAL:
                return ldb_module_send_referral(ac->req, ares->referral);
@@ -316,6 +308,7 @@ static int kludge_acl_callback(struct ldb_request *req, struct ldb_reply *ares)
 
 static int kludge_acl_search(struct ldb_module *module, struct ldb_request *req)
 {
+       struct ldb_context *ldb;
        struct kludge_acl_context *ac;
        struct ldb_request *down_req;
        struct kludge_private_data *data;
@@ -324,13 +317,18 @@ static int kludge_acl_search(struct ldb_module *module, struct ldb_request *req)
        struct ldb_control *sd_control;
        struct ldb_control **sd_saved_controls;
 
+       ldb = ldb_module_get_ctx(module);
+
        ac = talloc(req, struct kludge_acl_context);
        if (ac == NULL) {
-               ldb_oom(module->ldb);
+               ldb_oom(ldb);
                return LDB_ERR_OPERATIONS_ERROR;
        }
 
-       data = talloc_get_type(module->private_data, struct kludge_private_data);
+       data = talloc_get_type(ldb_module_get_private(module), struct kludge_private_data);
+
+       if (data && data->acl_perform)
+               return ldb_next_request(module, req);
 
        ac->module = module;
        ac->req = req;
@@ -372,7 +370,7 @@ static int kludge_acl_search(struct ldb_module *module, struct ldb_request *req)
        }
 
        ret = ldb_build_search_req_ex(&down_req,
-                                       module->ldb, ac,
+                                       ldb, ac,
                                        req->op.search.base,
                                        req->op.search.scope,
                                        req->op.search.tree,
@@ -381,7 +379,7 @@ static int kludge_acl_search(struct ldb_module *module, struct ldb_request *req)
                                        ac, kludge_acl_callback,
                                        req);
        if (ret != LDB_SUCCESS) {
-               return LDB_ERR_OPERATIONS_ERROR;
+               return ret;
        }
 
        /* check if there's an SD_FLAGS control */
@@ -402,13 +400,47 @@ static int kludge_acl_search(struct ldb_module *module, struct ldb_request *req)
 /* ANY change type */
 static int kludge_acl_change(struct ldb_module *module, struct ldb_request *req)
 {
+       struct ldb_context *ldb = ldb_module_get_ctx(module);
        enum security_user_level user_type = what_is_user(module);
+       struct kludge_private_data *data = talloc_get_type(ldb_module_get_private(module),
+                                                          struct kludge_private_data);
+
+       if (data->acl_perform)
+               return ldb_next_request(module, req);
+
        switch (user_type) {
        case SECURITY_SYSTEM:
        case SECURITY_ADMINISTRATOR:
                return ldb_next_request(module, req);
        default:
-               ldb_asprintf_errstring(module->ldb,
+               ldb_asprintf_errstring(ldb,
+                                      "kludge_acl_change: "
+                                      "attempted database modify not permitted. "
+                                      "User %s is not SYSTEM or an administrator",
+                                      user_name(req, module));
+               return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
+       }
+}
+
+static int kludge_acl_extended(struct ldb_module *module, struct ldb_request *req)
+{
+       struct ldb_context *ldb = ldb_module_get_ctx(module);
+       enum security_user_level user_type;
+
+       /* allow everybody to read the sequence number */
+       if (strcmp(req->op.extended.oid,
+                  LDB_EXTENDED_SEQUENCE_NUMBER) == 0) {
+               return ldb_next_request(module, req);
+       }
+
+       user_type = what_is_user(module);
+
+       switch (user_type) {
+       case SECURITY_SYSTEM:
+       case SECURITY_ADMINISTRATOR:
+               return ldb_next_request(module, req);
+       default:
+               ldb_asprintf_errstring(ldb,
                                       "kludge_acl_change: "
                                       "attempted database modify not permitted. "
                                       "User %s is not SYSTEM or an administrator",
@@ -419,6 +451,7 @@ static int kludge_acl_change(struct ldb_module *module, struct ldb_request *req)
 
 static int kludge_acl_init(struct ldb_module *module)
 {
+       struct ldb_context *ldb;
        int ret, i;
        TALLOC_CTX *mem_ctx = talloc_new(module);
        static const char *attrs[] = { "passwordAttribute", NULL };
@@ -428,22 +461,26 @@ static int kludge_acl_init(struct ldb_module *module)
 
        struct kludge_private_data *data;
 
+       ldb = ldb_module_get_ctx(module);
+
        data = talloc(module, struct kludge_private_data);
        if (data == NULL) {
-               ldb_oom(module->ldb);
+               ldb_oom(ldb);
                return LDB_ERR_OPERATIONS_ERROR;
        }
 
        data->password_attrs = NULL;
-       module->private_data = data;
+       data->acl_perform = lp_parm_bool(ldb_get_opaque(ldb, "loadparm"),
+                                        NULL, "acl", "perform", false);
+       ldb_module_set_private(module, data);
 
        if (!mem_ctx) {
-               ldb_oom(module->ldb);
+               ldb_oom(ldb);
                return LDB_ERR_OPERATIONS_ERROR;
        }
 
-       ret = ldb_search(module->ldb, mem_ctx, &res,
-                        ldb_dn_new(mem_ctx, module->ldb, "@KLUDGEACL"),
+       ret = ldb_search(ldb, mem_ctx, &res,
+                        ldb_dn_new(mem_ctx, ldb, "@KLUDGEACL"),
                         LDB_SCOPE_BASE, attrs, NULL);
        if (ret != LDB_SUCCESS) {
                goto done;
@@ -466,7 +503,7 @@ static int kludge_acl_init(struct ldb_module *module)
        data->password_attrs = talloc_array(data, const char *, password_attributes->num_values + 1);
        if (!data->password_attrs) {
                talloc_free(mem_ctx);
-               ldb_oom(module->ldb);
+               ldb_oom(ldb);
                return LDB_ERR_OPERATIONS_ERROR;
        }
        for (i=0; i < password_attributes->num_values; i++) {
@@ -477,8 +514,8 @@ static int kludge_acl_init(struct ldb_module *module)
 
        ret = ldb_mod_register_control(module, LDB_CONTROL_SD_FLAGS_OID);
        if (ret != LDB_SUCCESS) {
-               ldb_debug(module->ldb, LDB_DEBUG_ERROR,
-                       "partition: Unable to register control with rootdse!\n");
+               ldb_debug(ldb, LDB_DEBUG_ERROR,
+                       "kludge_acl: Unable to register control with rootdse!\n");
                return LDB_ERR_OPERATIONS_ERROR;
        }
 
@@ -494,6 +531,6 @@ _PUBLIC_ const struct ldb_module_ops ldb_kludge_acl_module_ops = {
        .modify            = kludge_acl_change,
        .del               = kludge_acl_change,
        .rename            = kludge_acl_change,
-       .extended          = kludge_acl_change,
+       .extended          = kludge_acl_extended,
        .init_context      = kludge_acl_init
 };