The branch, master has been updated
       via  496b67b dsdb-tests: Clarify that accounts really do fall back to 
UF_NORMAL_ACCOUNT if no account set
       via  daeedb0 dsdb-samldb: Clarify userAccountControl manipulation code 
by always using UF_ flags
       via  1279d5e dsdb-samldb: Clarify that accounts really do fall back to 
UF_NORMAL_ACCOUNT if no account set
       via  49485ab dsdb-samldb: Only allow known and settable 
userAccountControl bits to be set
       via  ad98c0e dsdb-tests: Show that we can not change the primaryGroupID 
of a DC
       via  2a43275 s4:dsdb/samldb: let samldb_prim_group_change() protect 
DOMAIN_RID_{READONLY_,}DCS
       via  735605a dsdb: Improve userAccountControl handling
       via  bf99abb dsdb-tests: Add new test samba4.user_account_control.python
       via  b995ef3 dsdb: Default to UF_NORMAL_ACCOUNT when no account type is 
specified
       via  412b602 libds: UF_PARTIAL_SECRETS_ACCOUNT is a flag, not an account 
type
       via  7e41bcf dsdb-tests: Align sam.py with Windows 2012R2 and uncomment 
userAccountControl tests
      from  cde5d38 vfs:glusterfs: whitespace fix.

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 496b67b27ab9856017a07b2fbcc5ba465f1945b3
Author: Andrew Bartlett <abart...@samba.org>
Date:   Tue Jan 6 16:49:14 2015 +1300

    dsdb-tests: Clarify that accounts really do fall back to UF_NORMAL_ACCOUNT 
if no account set
    
    Also confirm what bits have to be ignored, or otherwise processed
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=10993
    
    Pair-programmed-with: Garming Sam <garm...@catalyst.net.nz>
    Signed-off-by: Garming Sam <garm...@catalyst.net.nz>
    Signed-off-by: Andrew Bartlett <abart...@samba.org>
    
    Autobuild-User(master): Andrew Bartlett <abart...@samba.org>
    Autobuild-Date(master): Thu Jan 22 10:16:42 CET 2015 on sn-devel-104

commit daeedb030fc019091332cbf3e8f6a2cc5d0d5273
Author: Andrew Bartlett <abart...@samba.org>
Date:   Tue Jan 6 16:48:40 2015 +1300

    dsdb-samldb: Clarify userAccountControl manipulation code by always using 
UF_ flags
    
    The use of ACB_ flags was required before 
msDS-User-Account-Control-Computed was implemented
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=10993
    
    Signed-off-by: Andrew Bartlett <abart...@samba.org>
    Reviewed-by: Garming Sam <garm...@catalyst.net.nz>
    Reviewed-by: Stefan Metzmacher <me...@samba.org>

commit 1279d5e863d51fb03d84bfec51e9dc6a632fabd4
Author: Andrew Bartlett <abart...@samba.org>
Date:   Tue Jan 6 16:47:36 2015 +1300

    dsdb-samldb: Clarify that accounts really do fall back to UF_NORMAL_ACCOUNT 
if no account set
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=10993
    
    Signed-off-by: Andrew Bartlett <abart...@samba.org>
    Reviewed-by: Garming Sam <garm...@catalyst.net.nz>
    Reviewed-by: Stefan Metzmacher <me...@samba.org>

commit 49485ab9782b7abc32581f29c35d862bb9a7058c
Author: Andrew Bartlett <abart...@samba.org>
Date:   Tue Jan 6 16:43:37 2015 +1300

    dsdb-samldb: Only allow known and settable userAccountControl bits to be set
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=10993
    
    Signed-off-by: Andrew Bartlett <abart...@samba.org>
    Signed-off-by: Garming Sam <garm...@catalyst.net.nz>
    Pair-programmed-with: Garming Sam <garm...@catalyst.net.nz>
    Reviewed-by: Stefan Metzmacher <me...@samba.org>

commit ad98c0e1755e3fdc6efd8551590c1781b318a04f
Author: Andrew Bartlett <abart...@samba.org>
Date:   Wed Dec 10 15:54:11 2014 +1300

    dsdb-tests: Show that we can not change the primaryGroupID of a DC
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=10993
    
    Signed-off-by: Garming Sam <garm...@catalyst.net.nz>
    Pair-programmed-with: Garming Sam <garm...@catalyst.net.nz>
    Signed-off-by: Andrew Bartlett <abart...@samba.org>
    Reviewed-by: Stefan Metzmacher <me...@samba.org>

commit 2a432752c0eb8ef1ae395004ee1f0ba9b8ad88ba
Author: Stefan Metzmacher <me...@samba.org>
Date:   Tue Apr 1 19:22:35 2014 +0200

    s4:dsdb/samldb: let samldb_prim_group_change() protect 
DOMAIN_RID_{READONLY_,}DCS
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=10993
    
    Signed-off-by: Stefan Metzmacher <me...@samba.org>
    Signed-off-by: Andrew Bartlett <abart...@samba.org>
    Reviewed-by: Garming Sam <garm...@catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>
    Reviewed-by: Stefan Metzmacher <me...@samba.org>

commit 735605a6b0ad3ed98d46d1df920e64879a8c69cc
Author: Andrew Bartlett <abart...@samba.org>
Date:   Wed Dec 10 14:15:54 2014 +1300

    dsdb: Improve userAccountControl handling
    
    We now always check the ACL and invarient rules using the same function
    
    The change to libds is because UF_PARTIAL_SECRETS_ACCOUNT is a flag,
    not an account type
    
    This list should only be of the account exclusive account type bits.
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=10993
    
    Pair-programmed-with: Garming Sam <garm...@catalyst.net.nz>
    Signed-off-by: Garming Sam <garm...@catalyst.net.nz>
    Signed-off-by: Andrew Bartlett <abart...@samba.org>
    Reviewed-by: Stefan Metzmacher <me...@samba.org>

commit bf99abb5db91839d8e3589722fe9be000f857691
Author: Andrew Bartlett <abart...@samba.org>
Date:   Mon Dec 8 15:07:59 2014 +1300

    dsdb-tests: Add new test samba4.user_account_control.python
    
    This confirms security behaviour of the userAccountControl attribute
    as well as the behaviour on ADD as well as MODIFY, for every
    userAccountControl bit.
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=10993
    
    Change-Id: I8cd0e0b3c8d40e8b8aea844189703c756cc372f0
    Pair-programmed-with: Garming Sam <garm...@catalyst.net.nz>
    Signed-off-by: Andrew Bartlett <abart...@samba.org>
    Signed-off-by: Garming Sam <garm...@catalyst.net.nz>
    Reviewed-by: Stefan Metzmacher <me...@samba.org>

commit b995ef3795511fadae3556e706e77abb39f8791c
Author: Andrew Bartlett <abart...@samba.org>
Date:   Wed Dec 10 14:26:28 2014 +1300

    dsdb: Default to UF_NORMAL_ACCOUNT when no account type is specified
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=10993
    
    Signed-off-by: Andrew Bartlett <abart...@samba.org>
    Reviewed-by: Garming Sam <garm...@catalyst.net.nz>
    Reviewed-by: Stefan Metzmacher <me...@samba.org>

commit 412b602314e1174824d86940eacd74fb76774aba
Author: Andrew Bartlett <abart...@samba.org>
Date:   Wed Dec 10 14:15:54 2014 +1300

    libds: UF_PARTIAL_SECRETS_ACCOUNT is a flag, not an account type
    
    This list should only be of the account exclusive account type bits.
    
    Note, this corrects the behaviour in samldb modifies of
    userAccountControl.
    
    This reverts 6cb91a8f33516a33210a25e4019f3f3fbbfe61f2
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=10993
    
    Pair-programmed-with: Garming Sam <garm...@catalyst.net.nz>
    Signed-off-by: Andrew Bartlett <abart...@samba.org>
    Signed-off-by: Garming Sam <garm...@catalyst.net.nz>
    Reviewed-by: Stefan Metzmacher <me...@samba.org>

commit 7e41bcf3053e147a6511071bd61f45db8e055165
Author: Andrew Bartlett <abart...@samba.org>
Date:   Mon Dec 8 14:31:42 2014 +1300

    dsdb-tests: Align sam.py with Windows 2012R2 and uncomment 
userAccountControl tests
    
    These tests now pass against Samba and Windows 2012R2.
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=10993
    
    Change-Id: I1d7ba5e6a720b8da88c667bbbf3a4302c54642f4
    Pair-programmed-with: Garming Sam <garm...@catalyst.net.nz>
    Signed-off-by: Andrew Bartlett <abart...@samba.org>
    Signed-off-by: Garming Sam <garm...@catalyst.net.nz>
    Reviewed-by: Stefan Metzmacher <me...@samba.org>

-----------------------------------------------------------------------

Summary of changes:
 libds/common/flags.h                              |  20 +-
 source4/dsdb/samdb/ldb_modules/samldb.c           | 253 ++++++--
 source4/dsdb/tests/python/sam.py                  | 150 +++--
 source4/dsdb/tests/python/user_account_control.py | 699 ++++++++++++++++++++++
 source4/selftest/tests.py                         |   1 +
 5 files changed, 983 insertions(+), 140 deletions(-)
 create mode 100644 source4/dsdb/tests/python/user_account_control.py


Changeset truncated at 500 lines:

diff --git a/libds/common/flags.h b/libds/common/flags.h
index 4975024..f821e17 100644
--- a/libds/common/flags.h
+++ b/libds/common/flags.h
@@ -64,17 +64,21 @@
                UF_NORMAL_ACCOUNT |\
                UF_INTERDOMAIN_TRUST_ACCOUNT |\
                UF_WORKSTATION_TRUST_ACCOUNT |\
-               UF_SERVER_TRUST_ACCOUNT |\
-               UF_PARTIAL_SECRETS_ACCOUNT \
+               UF_SERVER_TRUST_ACCOUNT \
                 )
 
+/*
+ * MS-SAMR 2.2.1.13 UF_FLAG Codes states that some bits are ignored by
+ * clients and servers.  Other flags (like UF_LOCKOUT have special
+ * behaviours, but are not set in the traditional sense).
+ *
+ * See the samldb module for the use of this define.
+ */
+
 #define UF_SETTABLE_BITS (\
-               UF_SCRIPT |\
                UF_ACCOUNTDISABLE |\
                UF_HOMEDIR_REQUIRED  |\
-               UF_LOCKOUT |\
                UF_PASSWD_NOTREQD |\
-               UF_PASSWD_CANT_CHANGE |\
                UF_ACCOUNT_TYPE_MASK | \
                UF_DONT_EXPIRE_PASSWD | \
                UF_MNS_LOGON_ACCOUNT |\
@@ -83,7 +87,11 @@
                UF_TRUSTED_FOR_DELEGATION |\
                UF_NOT_DELEGATED |\
                UF_USE_DES_KEY_ONLY  |\
-               UF_DONT_REQUIRE_PREAUTH \
+               UF_DONT_REQUIRE_PREAUTH |\
+               UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION |\
+               UF_NO_AUTH_DATA_REQUIRED |\
+               UF_PARTIAL_SECRETS_ACCOUNT |\
+               UF_USE_AES_KEYS \
                )
 
 /* Group flags for "groupType" */
diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c 
b/source4/dsdb/samdb/ldb_modules/samldb.c
index 54e2e5e..ade7c9a 100644
--- a/source4/dsdb/samdb/ldb_modules/samldb.c
+++ b/source4/dsdb/samdb/ldb_modules/samldb.c
@@ -945,10 +945,10 @@ static int samldb_schema_info_update(struct samldb_ctx 
*ac)
 }
 
 static int samldb_prim_group_tester(struct samldb_ctx *ac, uint32_t rid);
-static int samldb_check_user_account_control_acl(struct samldb_ctx *ac,
-                                                struct dom_sid *sid,
-                                                uint32_t user_account_control,
-                                                uint32_t 
user_account_control_old);
+static int samldb_check_user_account_control_rules(struct samldb_ctx *ac,
+                                                  struct dom_sid *sid,
+                                                  uint32_t 
user_account_control,
+                                                  uint32_t 
user_account_control_old);
 
 /*
  * "Objectclass" trigger (MS-SAMR 3.1.1.8.1)
@@ -1048,9 +1048,13 @@ static int samldb_objectclass_trigger(struct samldb_ctx 
*ac)
                        user_account_control = 
ldb_msg_find_attr_as_uint(ac->msg,
                                                                         
"userAccountControl",
                                                                         0);
-                       /* "userAccountControl" = 0 means "UF_NORMAL_ACCOUNT" */
-                       if (user_account_control == 0) {
-                               user_account_control = UF_NORMAL_ACCOUNT;
+                       /*
+                        * "userAccountControl" = 0 or missing one of
+                        * the types means "UF_NORMAL_ACCOUNT".  See
+                        * MS-SAMR 3.1.1.8.10 point 8
+                        */
+                       if ((user_account_control & UF_ACCOUNT_TYPE_MASK) == 0) 
{
+                               user_account_control = UF_NORMAL_ACCOUNT | 
user_account_control;
                                uac_generated = true;
                        }
 
@@ -1066,9 +1070,10 @@ static int samldb_objectclass_trigger(struct samldb_ctx 
*ac)
                                uac_generated = true;
                        }
 
-                       /* Temporary duplicate accounts aren't allowed */
-                       if ((user_account_control & UF_TEMP_DUPLICATE_ACCOUNT) 
!= 0) {
-                               return LDB_ERR_OTHER;
+                       ret = samldb_check_user_account_control_rules(ac, NULL,
+                                                                     
user_account_control, 0);
+                       if (ret != LDB_SUCCESS) {
+                               return ret;
                        }
 
                        /* Workstation and (read-only) DC objects do need 
objectclass "computer" */
@@ -1160,11 +1165,6 @@ static int samldb_objectclass_trigger(struct samldb_ctx 
*ac)
                                }
                        }
 
-                       ret = samldb_check_user_account_control_acl(ac, NULL,
-                                                                   
user_account_control, 0);
-                       if (ret != LDB_SUCCESS) {
-                               return ret;
-                       }
                }
                break;
        }
@@ -1289,11 +1289,15 @@ static int samldb_prim_group_set(struct samldb_ctx *ac)
 static int samldb_prim_group_change(struct samldb_ctx *ac)
 {
        struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
-       const char * const attrs[] = { "primaryGroupID", "memberOf", NULL };
+       const char * const attrs[] = {
+               "primaryGroupID",
+               "memberOf",
+               "userAccountControl",
+               NULL };
        struct ldb_result *res, *group_res;
        struct ldb_message_element *el;
        struct ldb_message *msg;
-       uint32_t prev_rid, new_rid;
+       uint32_t prev_rid, new_rid, uac;
        struct dom_sid *prev_sid, *new_sid;
        struct ldb_dn *prev_prim_group_dn, *new_prim_group_dn;
        int ret;
@@ -1314,6 +1318,8 @@ static int samldb_prim_group_change(struct samldb_ctx *ac)
                return ret;
        }
 
+       uac = ldb_msg_find_attr_as_uint(res->msgs[0], "userAccountControl", 0);
+
        /* Finds out the DN of the old primary group */
 
        prev_rid = ldb_msg_find_attr_as_uint(res->msgs[0], "primaryGroupID",
@@ -1353,6 +1359,24 @@ static int samldb_prim_group_change(struct samldb_ctx 
*ac)
                return LDB_SUCCESS;
        }
 
+       if ((uac & UF_SERVER_TRUST_ACCOUNT) && new_rid != DOMAIN_RID_DCS) {
+               ldb_asprintf_errstring(ldb,
+                       "%08X: samldb: UF_SERVER_TRUST_ACCOUNT requires "
+                       "primaryGroupID=%u!",
+                       W_ERROR_V(WERR_DS_CANT_MOD_PRIMARYGROUPID),
+                       DOMAIN_RID_DCS);
+               return LDB_ERR_UNWILLING_TO_PERFORM;
+       }
+
+       if ((uac & UF_PARTIAL_SECRETS_ACCOUNT) && new_rid != 
DOMAIN_RID_READONLY_DCS) {
+               ldb_asprintf_errstring(ldb,
+                       "%08X: samldb: UF_PARTIAL_SECRETS_ACCOUNT requires "
+                       "primaryGroupID=%u!",
+                       W_ERROR_V(WERR_DS_CANT_MOD_PRIMARYGROUPID),
+                       DOMAIN_RID_READONLY_DCS);
+               return LDB_ERR_UNWILLING_TO_PERFORM;
+       }
+
        ret = dsdb_module_search(ac->module, ac, &group_res,
                                 ldb_get_default_basedn(ldb),
                                 LDB_SCOPE_SUBTREE,
@@ -1452,6 +1476,110 @@ static int samldb_prim_group_trigger(struct samldb_ctx 
*ac)
        return ret;
 }
 
+static int samldb_check_user_account_control_invariants(struct samldb_ctx *ac,
+                                                   uint32_t 
user_account_control)
+{
+       int i, ret = 0;
+       bool need_check = false;
+       const struct uac_to_guid {
+               uint32_t uac;
+               bool never;
+               uint32_t needs;
+               uint32_t not_with;
+               const char *error_string;
+       } map[] = {
+               {
+                       .uac = UF_TEMP_DUPLICATE_ACCOUNT,
+                       .never = true,
+                       .error_string = "Updating the UF_TEMP_DUPLICATE_ACCOUNT 
flag is never allowed"
+               },
+               {
+                       .uac = UF_PARTIAL_SECRETS_ACCOUNT,
+                       .needs = UF_WORKSTATION_TRUST_ACCOUNT,
+                       .error_string = "Setting UF_PARTIAL_SECRETS_ACCOUNT 
only permitted with UF_WORKSTATION_TRUST_ACCOUNT"
+               },
+               {
+                       .uac = UF_TRUSTED_FOR_DELEGATION,
+                       .not_with = UF_PARTIAL_SECRETS_ACCOUNT,
+                       .error_string = "Setting UF_TRUSTED_FOR_DELEGATION not 
allowed with UF_PARTIAL_SECRETS_ACCOUNT"
+               },
+               {
+                       .uac = UF_NORMAL_ACCOUNT,
+                       .not_with = UF_ACCOUNT_TYPE_MASK & ~UF_NORMAL_ACCOUNT,
+                       .error_string = "Setting more than one account type not 
permitted"
+               },
+               {
+                       .uac = UF_WORKSTATION_TRUST_ACCOUNT,
+                       .not_with = UF_ACCOUNT_TYPE_MASK & 
~UF_WORKSTATION_TRUST_ACCOUNT,
+                       .error_string = "Setting more than one account type not 
permitted"
+               },
+               {
+                       .uac = UF_INTERDOMAIN_TRUST_ACCOUNT,
+                       .not_with = UF_ACCOUNT_TYPE_MASK & 
~UF_INTERDOMAIN_TRUST_ACCOUNT,
+                       .error_string = "Setting more than one account type not 
permitted"
+               },
+               {
+                       .uac = UF_SERVER_TRUST_ACCOUNT,
+                       .not_with = UF_ACCOUNT_TYPE_MASK & 
~UF_SERVER_TRUST_ACCOUNT,
+                       .error_string = "Setting more than one account type not 
permitted"
+               },
+               {
+                       .uac = UF_TRUSTED_FOR_DELEGATION,
+                       .not_with = UF_PARTIAL_SECRETS_ACCOUNT,
+                       .error_string = "Setting UF_TRUSTED_FOR_DELEGATION not 
allowed with UF_PARTIAL_SECRETS_ACCOUNT"
+               }
+       };
+
+       for (i = 0; i < ARRAY_SIZE(map); i++) {
+               if (user_account_control & map[i].uac) {
+                       need_check = true;
+                       break;
+               }
+       }
+       if (need_check == false) {
+               return LDB_SUCCESS;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(map); i++) {
+               uint32_t this_uac = user_account_control & map[i].uac;
+               if (this_uac != 0) {
+                       if (map[i].never) {
+                               ret = LDB_ERR_OTHER;
+                               break;
+                       } else if (map[i].needs != 0) {
+                               if ((map[i].needs & user_account_control) == 0) 
{
+                                       ret = LDB_ERR_OTHER;
+                                       break;
+                               }
+                       } else if (map[i].not_with != 0) {
+                               if ((map[i].not_with & user_account_control) != 
0) {
+                                       ret = LDB_ERR_OTHER;
+                                       break;
+                               }
+                       }
+               }
+       }
+       if (ret != LDB_SUCCESS) {
+               switch (ac->req->operation) {
+               case LDB_ADD:
+                       ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
+                                              "Failed to add %s: %s",
+                                              
ldb_dn_get_linearized(ac->msg->dn),
+                                              map[i].error_string);
+                       break;
+               case LDB_MODIFY:
+                       ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
+                                              "Failed to modify %s: %s",
+                                              
ldb_dn_get_linearized(ac->msg->dn),
+                                              map[i].error_string);
+                       break;
+               default:
+                       return ldb_module_operr(ac->module);
+               }
+       }
+       return ret;
+}
+
 /**
  * Validate that the restriction in point 5 of MS-SAMR 3.1.1.8.10 
userAccountControl is honoured
  *
@@ -1619,6 +1747,24 @@ static int samldb_check_user_account_control_acl(struct 
samldb_ctx *ac,
        return ret;
 }
 
+static int samldb_check_user_account_control_rules(struct samldb_ctx *ac,
+                                                  struct dom_sid *sid,
+                                                  uint32_t 
user_account_control,
+                                                  uint32_t 
user_account_control_old)
+{
+       int ret;
+       ret = samldb_check_user_account_control_invariants(ac, 
user_account_control);
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+       ret = samldb_check_user_account_control_acl(ac, sid, 
user_account_control, user_account_control_old);
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+       return ret;
+}
+
+
 /**
  * This function is called on LDB modify operations. It performs some 
additions/
  * replaces on the current LDB message when "userAccountControl" changes.
@@ -1631,9 +1777,8 @@ static int samldb_user_account_control_change(struct 
samldb_ctx *ac)
        uint32_t raw_uac;
        uint32_t old_ufa;
        uint32_t new_ufa;
-       uint32_t old_acb;
-       uint32_t new_acb;
-       uint32_t clear_acb;
+       uint32_t old_uac_computed;
+       uint32_t clear_uac;
        uint32_t old_atype;
        uint32_t new_atype;
        uint32_t old_pgrid;
@@ -1680,15 +1825,19 @@ static int samldb_user_account_control_change(struct 
samldb_ctx *ac)
        raw_uac = ldb_msg_find_attr_as_uint(tmp_msg,
                                            "userAccountControl",
                                            0);
-       new_acb = samdb_result_acct_flags(tmp_msg, NULL);
        talloc_free(tmp_msg);
        /*
-        * UF_LOCKOUT and UF_PASSWORD_EXPIRED are only generated
-        * and not stored. We ignore them almost completely.
+        * UF_LOCKOUT, UF_PASSWD_CANT_CHANGE and UF_PASSWORD_EXPIRED
+        * are only generated and not stored. We ignore them almost
+        * completely, along with unknown bits and UF_SCRIPT.
         *
-        * The only exception is the resulting ACB_AUTOLOCK in clear_acb.
+        * The only exception is ACB_AUTOLOCK, which features in
+        * clear_acb when the bit is cleared in this modify operation.
+        *
+        * MS-SAMR 2.2.1.13 UF_FLAG Codes states that some bits are
+        * ignored by clients and servers
         */
-       new_uac = raw_uac & ~(UF_LOCKOUT|UF_PASSWORD_EXPIRED);
+       new_uac = raw_uac & UF_SETTABLE_BITS;
 
        /* Fetch the old "userAccountControl" and "objectClass" */
        ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn, attrs,
@@ -1700,8 +1849,8 @@ static int samldb_user_account_control_change(struct 
samldb_ctx *ac)
        if (old_uac == 0) {
                return ldb_operr(ldb);
        }
-       old_acb = samdb_result_acct_flags(res->msgs[0],
-                                         "msDS-User-Account-Control-Computed");
+       old_uac_computed = ldb_msg_find_attr_as_uint(res->msgs[0],
+                                                    
"msDS-User-Account-Control-Computed", 0);
        old_lockoutTime = ldb_msg_find_attr_as_int64(res->msgs[0],
                                                     "lockoutTime", 0);
        old_is_critical = ldb_msg_find_attr_as_bool(res->msgs[0],
@@ -1724,16 +1873,27 @@ static int samldb_user_account_control_change(struct 
samldb_ctx *ac)
        new_ufa = new_uac & UF_ACCOUNT_TYPE_MASK;
        if (new_ufa == 0) {
                /*
-                * When there is no account type embedded in 
"userAccountControl"
-                * fall back to the old.
+                * "userAccountControl" = 0 or missing one of the
+                * types means "UF_NORMAL_ACCOUNT".  See MS-SAMR
+                * 3.1.1.8.10 point 8
                 */
-               new_ufa = old_ufa;
+               new_ufa = UF_NORMAL_ACCOUNT;
                new_uac |= new_ufa;
        }
+       sid = samdb_result_dom_sid(res, res->msgs[0], "objectSid");
+       if (sid == NULL) {
+               return ldb_module_operr(ac->module);
+       }
+
+       ret = samldb_check_user_account_control_rules(ac, sid, new_uac, 
old_uac);
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+
        new_atype = ds_uf2atype(new_ufa);
        new_pgrid = ds_uf2prim_group_rid(new_uac);
 
-       clear_acb = old_acb & ~new_acb;
+       clear_uac = (old_uac | old_uac_computed) & ~raw_uac;
 
        switch (new_ufa) {
        case UF_NORMAL_ACCOUNT:
@@ -1746,17 +1906,16 @@ static int samldb_user_account_control_change(struct 
samldb_ctx *ac)
 
        case UF_WORKSTATION_TRUST_ACCOUNT:
                new_is_critical = false;
-               break;
-
-       case (UF_WORKSTATION_TRUST_ACCOUNT|UF_PARTIAL_SECRETS_ACCOUNT):
-               if (!is_computer) {
-                       ldb_asprintf_errstring(ldb,
-                               "%08X: samldb: UF_PARTIAL_SECRETS_ACCOUNT "
-                               "requires objectclass 'computer'!",
-                               
W_ERROR_V(WERR_DS_MACHINE_ACCOUNT_CREATED_PRENT4));
-                       return LDB_ERR_UNWILLING_TO_PERFORM;
+               if (new_uac & UF_PARTIAL_SECRETS_ACCOUNT) {
+                       if (!is_computer) {
+                               ldb_asprintf_errstring(ldb,
+                                                      "%08X: samldb: 
UF_PARTIAL_SECRETS_ACCOUNT "
+                                                      "requires objectclass 
'computer'!",
+                                                      
W_ERROR_V(WERR_DS_MACHINE_ACCOUNT_CREATED_PRENT4));
+                               return LDB_ERR_UNWILLING_TO_PERFORM;
+                       }
+                       new_is_critical = true;
                }
-               new_is_critical = true;
                break;
 
        case UF_SERVER_TRUST_ACCOUNT:
@@ -1788,7 +1947,7 @@ static int samldb_user_account_control_change(struct 
samldb_ctx *ac)
        }
 
        /* As per MS-SAMR 3.1.1.8.10 these flags have not to be set */
-       if ((clear_acb & ACB_AUTOLOCK) && (old_lockoutTime != 0)) {
+       if ((clear_uac & UF_LOCKOUT) && (old_lockoutTime != 0)) {
                /* "pwdLastSet" reset as password expiration has been forced  */
                ldb_msg_remove_attr(ac->msg, "lockoutTime");
                ret = samdb_msg_add_uint64(ldb, ac->msg, ac->msg, "lockoutTime",
@@ -1849,16 +2008,6 @@ static int samldb_user_account_control_change(struct 
samldb_ctx *ac)
                ldb_msg_remove_attr(ac->msg, "userAccountControl");
        }
 
-       sid = samdb_result_dom_sid(res, res->msgs[0], "objectSid");
-       if (sid == NULL) {
-               return ldb_module_operr(ac->module);
-       }
-
-       ret = samldb_check_user_account_control_acl(ac, sid, new_uac, old_uac);
-       if (ret != LDB_SUCCESS) {
-               return ret;
-       }
-
        return LDB_SUCCESS;
 }
 
diff --git a/source4/dsdb/tests/python/sam.py b/source4/dsdb/tests/python/sam.py
index 31b5a39..25da8f9 100755
--- a/source4/dsdb/tests/python/sam.py
+++ b/source4/dsdb/tests/python/sam.py
@@ -22,12 +22,14 @@ from ldb import ERR_OTHER, ERR_NO_SUCH_ATTRIBUTE
 from ldb import ERR_OBJECT_CLASS_VIOLATION
 from ldb import ERR_CONSTRAINT_VIOLATION
 from ldb import ERR_UNDEFINED_ATTRIBUTE_TYPE
+from ldb import ERR_INSUFFICIENT_ACCESS_RIGHTS
 from ldb import Message, MessageElement, Dn
 from ldb import FLAG_MOD_ADD, FLAG_MOD_REPLACE, FLAG_MOD_DELETE
 from samba.samdb import SamDB
 from samba.dsdb import (UF_NORMAL_ACCOUNT, UF_ACCOUNTDISABLE,
     UF_WORKSTATION_TRUST_ACCOUNT, UF_SERVER_TRUST_ACCOUNT,
     UF_PARTIAL_SECRETS_ACCOUNT, UF_TEMP_DUPLICATE_ACCOUNT,
+    UF_INTERDOMAIN_TRUST_ACCOUNT,
     UF_PASSWD_NOTREQD, UF_LOCKOUT, UF_PASSWORD_EXPIRED, ATYPE_NORMAL_ACCOUNT,
     GTYPE_SECURITY_BUILTIN_LOCAL_GROUP, GTYPE_SECURITY_DOMAIN_LOCAL_GROUP,
     GTYPE_SECURITY_GLOBAL_GROUP, GTYPE_SECURITY_UNIVERSAL_GROUP,
@@ -1440,16 +1442,11 @@ class SamTests(samba.tests.TestCase):
         self.assertTrue(int(res1[0]["userAccountControl"][0]) & 
UF_PASSWD_NOTREQD == 0)
         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
 
-# This has to wait until s4 supports it (needs a password module change)
-#        try:
-#            ldb.add({
-#                "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
-#                "objectclass": "user",
-#                "userAccountControl": str(UF_NORMAL_ACCOUNT)})
-#            self.fail()
-#        except LdbError, (num, _):
-#            self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
-#        delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
+        ldb.add({
+            "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
+            "objectclass": "user",
+            "userAccountControl": str(UF_NORMAL_ACCOUNT)})
+        delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
 
         ldb.add({
             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
@@ -1519,16 +1516,15 @@ class SamTests(samba.tests.TestCase):
             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
 
-# This isn't supported yet in s4 - needs ACL module adaption
-#        try:
-#            ldb.add({
-#                "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
-#                "objectclass": "user",
-#                "userAccountControl": str(UF_INTERDOMAIN_TRUST_ACCOUNT)})
-#            self.fail()
-#        except LdbError, (num, _):
-#            self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
-#        delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
+        try:
+            ldb.add({
+                "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
+                "objectclass": "user",
+                "userAccountControl": str(UF_INTERDOMAIN_TRUST_ACCOUNT)})
+            self.fail()
+        except LdbError, (num, _):
+            self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
+        delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
 
         # Modify operation
 
@@ -1561,16 +1557,15 @@ class SamTests(samba.tests.TestCase):
         except LdbError, (num, _):
             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
 
-# This has to wait until s4 supports it (needs a password module change)
-#        try:


-- 
Samba Shared Repository

Reply via email to