s4:security Change struct security_token->sids from struct dom_sid * to struct dom_sid
[sfrench/samba-autobuild/.git] / source4 / dsdb / samdb / ldb_modules / acl.c
index 2b0b19c726406cfd8c94a00b28ea5b87110f12a1..826884f8118420ebd5272a3da04620114e22d917 100644 (file)
@@ -64,14 +64,6 @@ struct acl_context {
        struct dsdb_schema *schema;
 };
 
-bool is_root_base_dn(struct ldb_context *ldb, struct ldb_dn *dn_to_check)
-{
-       int result;
-       struct ldb_dn *root_base_dn = ldb_get_root_basedn(ldb);
-       result = ldb_dn_compare(root_base_dn,dn_to_check);
-       return (result==0);
-}
-
 static struct security_token *acl_user_token(struct ldb_module *module)
 {
        struct ldb_context *ldb = ldb_module_get_ctx(module);
@@ -129,7 +121,7 @@ static int acl_module_init(struct ldb_module *module)
        struct ldb_context *ldb;
        struct acl_private *data;
        int ret, i;
-       TALLOC_CTX *mem_ctx = talloc_new(module);
+       TALLOC_CTX *mem_ctx;
        static const char *attrs[] = { "passwordAttribute", NULL };
        struct ldb_result *res;
        struct ldb_message *msg;
@@ -150,10 +142,11 @@ static int acl_module_init(struct ldb_module *module)
        }
 
        data->password_attrs = NULL;
-       data->acl_perform = lp_parm_bool(ldb_get_opaque(ldb, "loadparm"),
+       data->acl_perform = lpcfg_parm_bool(ldb_get_opaque(ldb, "loadparm"),
                                         NULL, "acl", "perform", false);
        ldb_module_set_private(module, data);
 
+       mem_ctx = talloc_new(module);
        if (!mem_ctx) {
                return ldb_oom(ldb);
        }
@@ -630,8 +623,7 @@ static int acl_add(struct ldb_module *module, struct ldb_request *req)
        /* FIXME: this has to be made dynamic at some point */
        if ((ldb_dn_compare(req->op.add.message->dn, (ldb_get_schema_basedn(ldb))) == 0) ||
            (ldb_dn_compare(req->op.add.message->dn, (ldb_get_config_basedn(ldb))) == 0) ||
-           (ldb_dn_compare(req->op.add.message->dn, (ldb_get_default_basedn(ldb))) == 0) ||
-           (ldb_dn_compare(req->op.add.message->dn, (ldb_get_root_basedn(ldb))) == 0)) {
+           (ldb_dn_compare(req->op.add.message->dn, (ldb_get_default_basedn(ldb))) == 0)) {
                return ldb_next_request(module, req);
        }
 
@@ -717,7 +709,9 @@ static int acl_check_self_membership(TALLOC_CTX *mem_ctx,
                return LDB_SUCCESS;
        }
        /* if we are adding/deleting ourselves, check for self membership */
-       ret = dsdb_find_dn_by_sid(ldb, mem_ctx, acl_user_token(module)->user_sid, &user_dn);
+       ret = dsdb_find_dn_by_sid(ldb, mem_ctx, 
+                                 &acl_user_token(module)->sids[PRIMARY_USER_SID_INDEX], 
+                                 &user_dn);
        if (ret != LDB_SUCCESS) {
                return ret;
        }
@@ -759,8 +753,8 @@ static int acl_check_password_rights(TALLOC_CTX *mem_ctx,
        unsigned int del_attr_cnt = 0, add_attr_cnt = 0, rep_attr_cnt = 0;
        struct ldb_message_element *el;
        struct ldb_message *msg;
-       const char *passwordAttrs[] = { "userPassword", "unicodePwd",
-                                       "clearTextPassword", NULL }, **l;
+       const char *passwordAttrs[] = { "userPassword", "clearTextPassword",
+                                       "unicodePwd", "dBCSPwd", NULL }, **l;
        TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
 
        msg = ldb_msg_copy_shallow(tmp_ctx, req->op.mod.message);
@@ -769,13 +763,13 @@ static int acl_check_password_rights(TALLOC_CTX *mem_ctx,
        }
        for (l = passwordAttrs; *l != NULL; l++) {
                while ((el = ldb_msg_find_element(msg, *l)) != NULL) {
-                       if (el->flags == LDB_FLAG_MOD_DELETE) {
+                       if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
                                ++del_attr_cnt;
                        }
-                       if (el->flags == LDB_FLAG_MOD_ADD) {
+                       if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_ADD) {
                                ++add_attr_cnt;
                        }
-                       if (el->flags == LDB_FLAG_MOD_REPLACE) {
+                       if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
                                ++rep_attr_cnt;
                        }
                        ldb_msg_remove_element(msg, el);
@@ -787,7 +781,21 @@ static int acl_check_password_rights(TALLOC_CTX *mem_ctx,
                talloc_free(tmp_ctx);
                return LDB_SUCCESS;
        }
-       if (rep_attr_cnt > 0 || (add_attr_cnt != del_attr_cnt)) {
+
+       if (ldb_request_get_control(req,
+                                   DSDB_CONTROL_PASSWORD_CHANGE_OID) != NULL) {
+               /* The "DSDB_CONTROL_PASSWORD_CHANGE_OID" control means that we
+                * have a user password change and not a set as the message
+                * looks like. In it's value blob it contains the NT and/or LM
+                * hash of the old password specified by the user.
+                * This control is used by the SAMR and "kpasswd" password
+                * change mechanisms. */
+               ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module),
+                                              GUID_DRS_USER_CHANGE_PASSWORD,
+                                              SEC_ADS_CONTROL_ACCESS,
+                                              sid);
+       }
+       else if (rep_attr_cnt > 0 || (add_attr_cnt != del_attr_cnt)) {
                ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module),
                                               GUID_DRS_FORCE_CHANGE_PASSWORD,
                                               SEC_ADS_CONTROL_ACCESS,
@@ -1032,8 +1040,7 @@ static int acl_delete(struct ldb_module *module, struct ldb_request *req)
        /* FIXME: this has to be made dynamic at some point */
        if ((ldb_dn_compare(req->op.del.dn, (ldb_get_schema_basedn(ldb))) == 0) ||
            (ldb_dn_compare(req->op.del.dn, (ldb_get_config_basedn(ldb))) == 0) ||
-           (ldb_dn_compare(req->op.del.dn, (ldb_get_default_basedn(ldb))) == 0) ||
-           (ldb_dn_compare(req->op.del.dn, (ldb_get_root_basedn(ldb))) == 0)) {
+           (ldb_dn_compare(req->op.del.dn, (ldb_get_default_basedn(ldb))) == 0)) {
                DEBUG(10,("acl:deleting an NC\n"));
                return ldb_module_done(req, NULL, NULL, LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS);
        }
@@ -1160,8 +1167,7 @@ static int acl_rename(struct ldb_module *module, struct ldb_request *req)
        /* FIXME: this has to be made dynamic at some point */
        if ((ldb_dn_compare(req->op.rename.newdn, (ldb_get_schema_basedn(ldb))) == 0) ||
            (ldb_dn_compare(req->op.rename.newdn, (ldb_get_config_basedn(ldb))) == 0) ||
-           (ldb_dn_compare(req->op.rename.newdn, (ldb_get_default_basedn(ldb))) == 0) ||
-           (ldb_dn_compare(req->op.rename.newdn, (ldb_get_root_basedn(ldb))) == 0)) {
+           (ldb_dn_compare(req->op.rename.newdn, (ldb_get_default_basedn(ldb))) == 0)) {
                DEBUG(10,("acl:moving as an NC\n"));
                return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
        }
@@ -1345,6 +1351,44 @@ static int acl_search(struct ldb_module *module, struct ldb_request *req)
        return ldb_next_request(module, down_req);
 }
 
+static const char *acl_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(ldb, "sessionInfo");
+       if (!session_info) {
+               return "UNKNOWN (NULL)";
+       }
+
+       return talloc_asprintf(mem_ctx, "%s\\%s",
+                              session_info->server_info->domain_name,
+                              session_info->server_info->account_name);
+}
+
+static int acl_extended(struct ldb_module *module, struct ldb_request *req)
+{
+       struct ldb_context *ldb = ldb_module_get_ctx(module);
+       struct ldb_control *as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
+
+       /* allow everybody to read the sequence number */
+       if (strcmp(req->op.extended.oid,
+                  LDB_EXTENDED_SEQUENCE_NUMBER) == 0) {
+               return ldb_next_request(module, req);
+       }
+
+       if (dsdb_module_am_system(module) ||
+           dsdb_module_am_administrator(module) || as_system) {
+               return ldb_next_request(module, req);
+       } else {
+               ldb_asprintf_errstring(ldb,
+                                      "acl_extended: "
+                                      "attempted database modify not permitted. "
+                                      "User %s is not SYSTEM or an administrator",
+                                      acl_user_name(req, module));
+               return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
+       }
+}
+
 _PUBLIC_ const struct ldb_module_ops ldb_acl_module_ops = {
        .name              = "acl",
        .search            = acl_search,
@@ -1352,5 +1396,6 @@ _PUBLIC_ const struct ldb_module_ops ldb_acl_module_ops = {
        .modify            = acl_modify,
        .del               = acl_delete,
        .rename            = acl_rename,
+       .extended          = acl_extended,
        .init_context      = acl_module_init
 };