CVE-2015-8467: samdb: Match MS15-096 behaviour for userAccountControl
authorAndrew Bartlett <abartlet@samba.org>
Wed, 18 Nov 2015 04:36:21 +0000 (17:36 +1300)
committerKarolin Seeger <kseeger@samba.org>
Thu, 10 Dec 2015 10:10:54 +0000 (11:10 +0100)
Swapping between account types is now restricted

Bug: https://bugzilla.samba.org/show_bug.cgi?id=11552

Signed-off-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
source4/dsdb/samdb/ldb_modules/samldb.c

index 2c8a0647ccd38b011d619b749758162f4eb10e5a..97934c747f8df749503c90455ffe781ab98d9461 100644 (file)
@@ -1468,12 +1468,15 @@ static int samldb_check_user_account_control_acl(struct samldb_ctx *ac,
        struct security_token *user_token;
        struct security_descriptor *domain_sd;
        struct ldb_dn *domain_dn = ldb_get_default_basedn(ldb_module_get_ctx(ac->module));
+       struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
        const struct uac_to_guid {
                uint32_t uac;
+               uint32_t priv_to_change_from;
                const char *oid;
                const char *guid;
                enum sec_privilege privilege;
                bool delete_is_privileged;
+               bool admin_required;
                const char *error_string;
        } map[] = {
                {
@@ -1501,6 +1504,16 @@ static int samldb_check_user_account_control_acl(struct samldb_ctx *ac,
                        .guid = GUID_DRS_DS_INSTALL_REPLICA,
                        .error_string = "Adding the UF_PARTIAL_SECRETS_ACCOUNT bit in userAccountControl requires the DS-Install-Replica right that was not given on the Domain object"
                },
+               {
+                       .uac = UF_WORKSTATION_TRUST_ACCOUNT,
+                       .priv_to_change_from = UF_NORMAL_ACCOUNT,
+                       .error_string = "Swapping UF_NORMAL_ACCOUNT to UF_WORKSTATION_TRUST_ACCOUNT requires the user to be a member of the domain admins group"
+               },
+               {
+                       .uac = UF_NORMAL_ACCOUNT,
+                       .priv_to_change_from = UF_WORKSTATION_TRUST_ACCOUNT,
+                       .error_string = "Swapping UF_WORKSTATION_TRUST_ACCOUNT to UF_NORMAL_ACCOUNT requires the user to be a member of the domain admins group"
+               },
                {
                        .uac = UF_INTERDOMAIN_TRUST_ACCOUNT,
                        .oid = DSDB_CONTROL_PERMIT_INTERDOMAIN_TRUST_UAC_OID,
@@ -1553,7 +1566,7 @@ static int samldb_check_user_account_control_acl(struct samldb_ctx *ac,
                return ldb_module_operr(ac->module);
        }
 
-       ret = dsdb_get_sd_from_ldb_message(ldb_module_get_ctx(ac->module),
+       ret = dsdb_get_sd_from_ldb_message(ldb,
                                           ac, res->msgs[0], &domain_sd);
 
        if (ret != LDB_SUCCESS) {
@@ -1580,12 +1593,19 @@ static int samldb_check_user_account_control_acl(struct samldb_ctx *ac,
                                if (have_priv == false) {
                                        ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
                                }
-                       } else {
+                       } else if (map[i].priv_to_change_from & user_account_control_old) {
+                               bool is_admin = security_token_has_builtin_administrators(user_token);
+                               if (is_admin == false) {
+                                       ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
+                               }
+                       } else if (map[i].guid) {
                                ret = acl_check_extended_right(ac, domain_sd,
                                                               user_token,
                                                               map[i].guid,
                                                               SEC_ADS_CONTROL_ACCESS,
                                                               sid);
+                       } else {
+                               ret = LDB_SUCCESS;
                        }
                        if (ret != LDB_SUCCESS) {
                                break;