r5015: (based on abartlet's original patch to restrict password changes)
authorGerald Carter <jerry@samba.org>
Wed, 26 Jan 2005 20:36:44 +0000 (20:36 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 15:55:12 +0000 (10:55 -0500)
* added SE_PRIV checks to access_check_samr_object() in order
  to deal with the run-time security descriptor and their
  interaction with user rights

* Reordered original patch in _samr_set_userinfo[2] to still
  allow root/administrative password changes for users and machines.
(This used to be commit f9f9e6039bd9443d54445e41c3783a2be18925fb)

source3/include/rpc_secdes.h
source3/lib/privileges.c
source3/passdb/pdb_get_set.c
source3/rpc_server/srv_samr_nt.c

index 56145ac024c6454171993be3af92652c5f4ada8c..1279007220cff85b8aeefddfa5d466fda9bbe72d 100644 (file)
@@ -401,7 +401,10 @@ typedef struct standard_mapping {
 #define GENERIC_RIGHTS_USER_WRITE \
                (STANDARD_RIGHTS_WRITE_ACCESS   | \
                SA_RIGHT_USER_CHANGE_PASSWORD   | \
-               SA_RIGHT_USER_SET_LOC_COM)      /* 0x00020044 */
+               SA_RIGHT_USER_SET_LOC_COM       | \
+               SA_RIGHT_USER_SET_ATTRIBUTES    | \
+               SA_RIGHT_USER_SET_PASSWORD      | \
+               SA_RIGHT_USER_CHANGE_GROUP_MEM) /* 0x000204e4 */
 
 #define GENERIC_RIGHTS_USER_EXECUTE \
                (STANDARD_RIGHTS_EXECUTE_ACCESS | \
index ea81f9fce0b7a2c6d4468257dfd386f1a6d573ad..4feb730feebaa8597433521f18788e9bdfba8393 100644 (file)
@@ -114,7 +114,7 @@ BOOL se_priv_copy( SE_PRIV *dst, const SE_PRIV *src )
  combine 2 SE_PRIV structures and store the resulting set in mew_mask
 ****************************************************************************/
 
-static void se_priv_add( SE_PRIV *mask, const SE_PRIV *addpriv )
+void se_priv_add( SE_PRIV *mask, const SE_PRIV *addpriv )
 {
        int i;
 
@@ -128,7 +128,7 @@ static void se_priv_add( SE_PRIV *mask, const SE_PRIV *addpriv )
  in mew_mask
 ****************************************************************************/
 
-static void se_priv_remove( SE_PRIV *mask, const SE_PRIV *removepriv )
+void se_priv_remove( SE_PRIV *mask, const SE_PRIV *removepriv )
 {      
        int i;
 
@@ -159,6 +159,23 @@ static BOOL se_priv_equal( const SE_PRIV *mask1, const SE_PRIV *mask2 )
        return ( memcmp(mask1, mask2, sizeof(SE_PRIV)) == 0 );
 }
 
+/***************************************************************************
+ check if a SE_PRIV has any assigned privileges
+****************************************************************************/
+
+static BOOL se_priv_empty( const SE_PRIV *mask )
+{
+       SE_PRIV p1;
+       int i;
+       
+       se_priv_copy( &p1, mask );
+
+       for ( i=0; i<SE_PRIV_MASKSIZE; i++ ) {
+               p1.mask[i] &= se_priv_all.mask[i];
+       }
+       
+       return se_priv_equal( &p1, &se_priv_none );
+}
 
 /***************************************************************************
  dump an SE_PRIV structure to the log files
@@ -252,13 +269,20 @@ static BOOL set_privileges( const DOM_SID *sid, SE_PRIV *mask )
  check if the privilege is in the privilege list
 ****************************************************************************/
 
-static BOOL is_privilege_assigned( SE_PRIV *privileges, SE_PRIV *check )
+static BOOL is_privilege_assigned( SE_PRIV *privileges, const SE_PRIV *check )
 {
        SE_PRIV p1, p2;
 
        if ( !privileges || !check )
                return False;
        
+       /* everyone has privileges if you aren't checking for any */
+       
+       if ( se_priv_empty( check ) ) {
+               DEBUG(1,("is_privilege_assigned: no privileges in check_mask!\n"));
+               return True;
+       }
+       
        se_priv_copy( &p1, check );
        
        /* invert the SE_PRIV we want to check for and remove that from the 
@@ -272,6 +296,39 @@ static BOOL is_privilege_assigned( SE_PRIV *privileges, SE_PRIV *check )
        return se_priv_equal( &p2, check );
 }
 
+/****************************************************************************
+ check if the privilege is in the privilege list
+****************************************************************************/
+
+static BOOL is_any_privilege_assigned( SE_PRIV *privileges, const SE_PRIV *check )
+{
+       SE_PRIV p1, p2;
+
+       if ( !privileges || !check )
+               return False;
+       
+       /* everyone has privileges if you aren't checking for any */
+       
+       if ( se_priv_empty( check ) ) {
+               DEBUG(1,("is_any_privilege_assigned: no privileges in check_mask!\n"));
+               return True;
+       }
+       
+       se_priv_copy( &p1, check );
+       
+       /* invert the SE_PRIV we want to check for and remove that from the 
+          original set.  If we are left with the SE_PRIV we are checking 
+          for then return True */
+          
+       se_priv_invert( &p1, check );
+       se_priv_copy( &p2, privileges );
+       se_priv_remove( &p2, &p1 );
+       
+       /* see if we have any bits left */
+       
+       return !se_priv_empty( &p2 );
+}
+
 /****************************************************************************
  add a privilege to a privilege array
  ****************************************************************************/
@@ -633,7 +690,7 @@ NTSTATUS dup_luid_attr(TALLOC_CTX *mem_ctx, LUID_ATTR **new_la, LUID_ATTR *old_l
  at a time here.
 *****************************************************************************/
 
-BOOL user_has_privileges(NT_USER_TOKEN *token, SE_PRIV *privilege)
+BOOL user_has_privileges(NT_USER_TOKEN *token, const SE_PRIV *privilege)
 {
        if ( !token )
                return False;
@@ -641,6 +698,19 @@ BOOL user_has_privileges(NT_USER_TOKEN *token, SE_PRIV *privilege)
        return is_privilege_assigned( &token->privileges, privilege );
 }
 
+/****************************************************************************
+ Does the user have any of the specified privileges ?  We only deal with one privilege
+ at a time here.
+*****************************************************************************/
+
+BOOL user_has_any_privilege(NT_USER_TOKEN *token, const SE_PRIV *privilege)
+{
+       if ( !token )
+               return False;
+
+       return is_any_privilege_assigned( &token->privileges, privilege );
+}
+
 /****************************************************************************
  Convert a LUID to a named string
 ****************************************************************************/
index 3430969e7171235ee9e374ba63b177ce751a5c2e..e0fc0ef280229b017339506fc03be34c92311282 100644 (file)
@@ -514,7 +514,7 @@ BOOL pdb_set_init_flags (SAM_ACCOUNT *sampass, enum pdb_elements element, enum p
                                DEBUG(0,("Can't set flag: %d in set_flags.\n",element));
                                return False;
                        }
-                       DEBUG(10, ("element %d -> now SET\n", element)); 
+                       DEBUG(11, ("element %d -> now SET\n", element)); 
                        break;
                case PDB_DEFAULT:
                default:
index 122bde1be59d191f7b14dd9d19a963b08d24a94b..6815c7147ccaf4f3eb10cb7817b846843058a54a 100644 (file)
@@ -68,31 +68,240 @@ struct generic_mapping usr_generic_mapping = {GENERIC_RIGHTS_USER_READ, GENERIC_
 struct generic_mapping grp_generic_mapping = {GENERIC_RIGHTS_GROUP_READ, GENERIC_RIGHTS_GROUP_WRITE, GENERIC_RIGHTS_GROUP_EXECUTE, GENERIC_RIGHTS_GROUP_ALL_ACCESS};
 struct generic_mapping ali_generic_mapping = {GENERIC_RIGHTS_ALIAS_READ, GENERIC_RIGHTS_ALIAS_WRITE, GENERIC_RIGHTS_ALIAS_EXECUTE, GENERIC_RIGHTS_ALIAS_ALL_ACCESS};
 
-static NTSTATUS samr_make_dom_obj_sd(TALLOC_CTX *ctx, SEC_DESC **psd, size_t *sd_size);
+/*******************************************************************
+ samr_make_dom_obj_sd
+ ********************************************************************/
+
+static NTSTATUS samr_make_dom_obj_sd(TALLOC_CTX *ctx, SEC_DESC **psd, size_t *sd_size)
+{
+       extern DOM_SID global_sid_World;
+       DOM_SID adm_sid, act_sid, domadmin_sid;
+       SEC_ACE ace[4];
+       SEC_ACCESS mask;
+       size_t i = 0;
+
+       SEC_ACL *psa = NULL;
+
+       sid_copy(&adm_sid, &global_sid_Builtin);
+       sid_append_rid(&adm_sid, BUILTIN_ALIAS_RID_ADMINS);
+
+       sid_copy(&act_sid, &global_sid_Builtin);
+       sid_append_rid(&act_sid, BUILTIN_ALIAS_RID_ACCOUNT_OPS);
+
+       /*basic access for every one*/
+       init_sec_access(&mask, GENERIC_RIGHTS_DOMAIN_EXECUTE | GENERIC_RIGHTS_DOMAIN_READ);
+       init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+
+       /*full access for builtin aliases Administrators and Account Operators*/
+       
+       init_sec_access(&mask, GENERIC_RIGHTS_DOMAIN_ALL_ACCESS);
+       
+       init_sec_ace(&ace[i++], &adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+       init_sec_ace(&ace[i++], &act_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+       
+       /* add domain admins if we are a DC */
+       
+       if ( IS_DC ) {
+               sid_copy( &domadmin_sid, get_global_sam_sid() );
+               sid_append_rid( &domadmin_sid, DOMAIN_GROUP_RID_ADMINS );
+               init_sec_ace(&ace[i++], &domadmin_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+       }
+
+       if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, i, ace)) == NULL)
+               return NT_STATUS_NO_MEMORY;
+
+       if ((*psd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL, psa, sd_size)) == NULL)
+               return NT_STATUS_NO_MEMORY;
+
+       return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ samr_make_usr_obj_sd
+ ********************************************************************/
+
+static NTSTATUS samr_make_usr_obj_sd(TALLOC_CTX *ctx, SEC_DESC **psd, size_t *sd_size, DOM_SID *usr_sid)
+{
+       extern DOM_SID global_sid_World;
+       DOM_SID adm_sid, act_sid, domadmin_sid;
+       size_t i = 0;
+
+       SEC_ACE ace[5];
+       SEC_ACCESS mask;
+
+       SEC_ACL *psa = NULL;
+
+       sid_copy(&adm_sid, &global_sid_Builtin);
+       sid_append_rid(&adm_sid, BUILTIN_ALIAS_RID_ADMINS);
+
+       sid_copy(&act_sid, &global_sid_Builtin);
+       sid_append_rid(&act_sid, BUILTIN_ALIAS_RID_ACCOUNT_OPS);
+
+       /*basic access for every one*/
+       
+       init_sec_access(&mask, GENERIC_RIGHTS_USER_EXECUTE | GENERIC_RIGHTS_USER_READ);
+       init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+
+       /*full access for builtin aliases Administrators and Account Operators*/
+       
+       init_sec_access(&mask, GENERIC_RIGHTS_USER_ALL_ACCESS);
+       init_sec_ace(&ace[i++], &adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+       init_sec_ace(&ace[i++], &act_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+
+       /* add domain admins if we are a DC */
+       
+       if ( IS_DC ) {
+               sid_copy( &domadmin_sid, get_global_sam_sid() );
+               sid_append_rid( &domadmin_sid, DOMAIN_GROUP_RID_ADMINS );
+               init_sec_ace(&ace[i++], &domadmin_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+       }
+
+       /*extended access for the user*/
+       
+       init_sec_access(&mask,READ_CONTROL_ACCESS | SA_RIGHT_USER_CHANGE_PASSWORD | SA_RIGHT_USER_SET_LOC_COM);
+       init_sec_ace(&ace[i++], usr_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+
+       if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, 4, ace)) == NULL)
+               return NT_STATUS_NO_MEMORY;
+
+       if ((*psd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL, psa, sd_size)) == NULL)
+               return NT_STATUS_NO_MEMORY;
+
+       return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ samr_make_grp_obj_sd
+ ********************************************************************/
+
+static NTSTATUS samr_make_grp_obj_sd(TALLOC_CTX *ctx, SEC_DESC **psd, size_t *sd_size)
+{
+       extern DOM_SID global_sid_World;
+       DOM_SID adm_sid;
+       DOM_SID act_sid;
+
+       SEC_ACE ace[3];
+       SEC_ACCESS mask;
+
+       SEC_ACL *psa = NULL;
+
+       sid_copy(&adm_sid, &global_sid_Builtin);
+       sid_append_rid(&adm_sid, BUILTIN_ALIAS_RID_ADMINS);
+
+       sid_copy(&act_sid, &global_sid_Builtin);
+       sid_append_rid(&act_sid, BUILTIN_ALIAS_RID_ACCOUNT_OPS);
+
+       /*basic access for every one*/
+       init_sec_access(&mask, GENERIC_RIGHTS_GROUP_EXECUTE | GENERIC_RIGHTS_GROUP_READ);
+       init_sec_ace(&ace[0], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+
+       /*full access for builtin aliases Administrators and Account Operators*/
+       init_sec_access(&mask, GENERIC_RIGHTS_GROUP_ALL_ACCESS);
+       init_sec_ace(&ace[1], &adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+       init_sec_ace(&ace[2], &act_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+
+       if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, 3, ace)) == NULL)
+               return NT_STATUS_NO_MEMORY;
+
+       if ((*psd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL, psa, sd_size)) == NULL)
+               return NT_STATUS_NO_MEMORY;
+
+       return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ samr_make_ali_obj_sd
+ ********************************************************************/
+
+static NTSTATUS samr_make_ali_obj_sd(TALLOC_CTX *ctx, SEC_DESC **psd, size_t *sd_size)
+{
+       extern DOM_SID global_sid_World;
+       DOM_SID adm_sid;
+       DOM_SID act_sid;
+
+       SEC_ACE ace[3];
+       SEC_ACCESS mask;
+
+       SEC_ACL *psa = NULL;
+
+       sid_copy(&adm_sid, &global_sid_Builtin);
+       sid_append_rid(&adm_sid, BUILTIN_ALIAS_RID_ADMINS);
+
+       sid_copy(&act_sid, &global_sid_Builtin);
+       sid_append_rid(&act_sid, BUILTIN_ALIAS_RID_ACCOUNT_OPS);
+
+       /*basic access for every one*/
+       init_sec_access(&mask, GENERIC_RIGHTS_ALIAS_EXECUTE | GENERIC_RIGHTS_ALIAS_READ);
+       init_sec_ace(&ace[0], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+
+       /*full access for builtin aliases Administrators and Account Operators*/
+       init_sec_access(&mask, GENERIC_RIGHTS_ALIAS_ALL_ACCESS);
+       init_sec_ace(&ace[1], &adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+       init_sec_ace(&ace[2], &act_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+
+       if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, 3, ace)) == NULL)
+               return NT_STATUS_NO_MEMORY;
+
+       if ((*psd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL, psa, sd_size)) == NULL)
+               return NT_STATUS_NO_MEMORY;
+
+       return NT_STATUS_OK;
+}
 
 /*******************************************************************
  Checks if access to an object should be granted, and returns that
  level of access for further checks.
 ********************************************************************/
 
-static NTSTATUS access_check_samr_object(SEC_DESC *psd, NT_USER_TOKEN *nt_user_token, uint32 des_access, 
-                                 uint32 *acc_granted, const char *debug) 
+static NTSTATUS access_check_samr_object( SEC_DESC *psd, NT_USER_TOKEN *token, 
+                                          SE_PRIV *rights, uint32 rights_mask,
+                                          uint32 des_access, uint32 *acc_granted, 
+                                         const char *debug )
 {
        NTSTATUS status = NT_STATUS_ACCESS_DENIED;
+       uint32 saved_mask = 0;
 
-       if (!se_access_check(psd, nt_user_token, des_access, acc_granted, &status)) {
+       /* check privileges; certain SAM access bits should be overridden 
+          by privileges (mostly having to do with creating/modifying/deleting 
+          users and groups) */
+       
+       if ( rights && user_has_any_privilege( token, rights ) ) {
+       
+               saved_mask = (des_access & rights_mask);
+               des_access &= ~saved_mask;
+               
+               DEBUG(4,("access_check_samr_object: user rights saved access mask [0x%x]\n",
+                       saved_mask));
+       }
+               
+       
+       /* check the security descriptor first */
+       
+       if ( se_access_check(psd, token, des_access, acc_granted, &status) )
+               goto done;
+       
+       /* give root a free pass */
+       
+       if ( geteuid() == sec_initial_uid() ) {
+       
+               DEBUG(4,("%s: ACCESS should be DENIED  (requested: %#010x)\n", debug, des_access));
+               DEBUGADD(4,("but overritten by euid == sec_initial_uid()\n"));
+               
                *acc_granted = des_access;
-               if (geteuid() == sec_initial_uid()) {
-                       DEBUG(4,("%s: ACCESS should be DENIED  (requested: %#010x)\n",
-                               debug, des_access));
-                       DEBUGADD(4,("but overritten by euid == sec_initial_uid()\n"));
-                       status = NT_STATUS_OK;
-               }
-               else {
-                       DEBUG(2,("%s: ACCESS DENIED  (requested: %#010x)\n",
-                               debug, des_access));
-               }
+               
+               status = NT_STATUS_OK;
+               goto done;
        }
+       
+       
+       DEBUG(2,("%s: ACCESS DENIED  (requested: %#010x)\n", debug, des_access));
+       
+done:
+       /* add in any bits saved during the privilege check (only 
+          matters is syayus is ok) */
+       
+       *acc_granted |= saved_mask;
+       
        return status;
 }
 
@@ -102,20 +311,29 @@ static NTSTATUS access_check_samr_object(SEC_DESC *psd, NT_USER_TOKEN *nt_user_t
 
 static NTSTATUS access_check_samr_function(uint32 acc_granted, uint32 acc_required, const char *debug)
 {
-       DEBUG(5,("%s: access check ((granted: %#010x;  required: %#010x)\n",
-                       debug, acc_granted, acc_required));
-       if ((acc_granted & acc_required) != acc_required) {
-               if (geteuid() == sec_initial_uid()) {
-                       DEBUG(4,("%s: ACCESS should be DENIED (granted: %#010x;  required: %#010x)\n",
-                               debug, acc_granted, acc_required));
-                       DEBUGADD(4,("but overwritten by euid == 0\n"));
-                       return NT_STATUS_OK;
-               }
-               DEBUG(2,("%s: ACCESS DENIED (granted: %#010x;  required: %#010x)\n",
+       DEBUG(5,("%s: access check ((granted: %#010x;  required: %#010x)\n",  
+               debug, acc_granted, acc_required));
+
+       /* check the security descriptor first */
+       
+       if ( (acc_granted&acc_required) == acc_required )
+               return NT_STATUS_OK;
+               
+       /* give root a free pass */
+
+       if (geteuid() == sec_initial_uid()) {
+       
+               DEBUG(4,("%s: ACCESS should be DENIED (granted: %#010x;  required: %#010x)\n",
                        debug, acc_granted, acc_required));
-               return NT_STATUS_ACCESS_DENIED;
+               DEBUGADD(4,("but overwritten by euid == 0\n"));
+               
+               return NT_STATUS_OK;
        }
-       return NT_STATUS_OK;
+       
+       DEBUG(2,("%s: ACCESS DENIED (granted: %#010x;  required: %#010x)\n", 
+               debug, acc_granted, acc_required));
+               
+       return NT_STATUS_ACCESS_DENIED;
 }
 
 
@@ -355,281 +573,126 @@ static NTSTATUS load_group_domain_entries(struct samr_info *info, DOM_SID *sid)
        return NT_STATUS_OK;
 }
 
-
-/*******************************************************************
- _samr_close_hnd
- ********************************************************************/
-
-NTSTATUS _samr_close_hnd(pipes_struct *p, SAMR_Q_CLOSE_HND *q_u, SAMR_R_CLOSE_HND *r_u)
-{
-       r_u->status = NT_STATUS_OK;
-
-       /* close the policy handle */
-       if (!close_policy_hnd(p, &q_u->pol))
-               return NT_STATUS_OBJECT_NAME_INVALID;
-
-       DEBUG(5,("samr_reply_close_hnd: %d\n", __LINE__));
-
-       return r_u->status;
-}
-
-/*******************************************************************
- samr_reply_open_domain
- ********************************************************************/
-
-NTSTATUS _samr_open_domain(pipes_struct *p, SAMR_Q_OPEN_DOMAIN *q_u, SAMR_R_OPEN_DOMAIN *r_u)
-{
-       struct    samr_info *info;
-       SEC_DESC *psd = NULL;
-       uint32    acc_granted;
-       uint32    des_access = q_u->flags;
-       size_t    sd_size;
-       NTSTATUS  status;
-
-       r_u->status = NT_STATUS_OK;
-
-       /* find the connection policy handle. */
-       if (!find_policy_by_hnd(p, &q_u->pol, (void**)&info))
-               return NT_STATUS_INVALID_HANDLE;
-
-       if (!NT_STATUS_IS_OK(status = access_check_samr_function(info->acc_granted, SA_RIGHT_SAM_OPEN_DOMAIN,"_samr_open_domain"))) {
-               return status;
-       }
-
-       /*check if access can be granted as requested by client. */
-       samr_make_dom_obj_sd(p->mem_ctx, &psd, &sd_size);
-       se_map_generic(&des_access,&dom_generic_mapping);
-
-       if (!NT_STATUS_IS_OK(status = 
-                            access_check_samr_object(psd, p->pipe_user.nt_user_token, 
-                                                     des_access, &acc_granted, "_samr_open_domain"))) {
-               return status;
-       }
-
-       /* associate the domain SID with the (unique) handle. */
-       if ((info = get_samr_info_by_sid(&q_u->dom_sid.sid))==NULL)
-               return NT_STATUS_NO_MEMORY;
-       info->acc_granted = acc_granted;
-
-       /* get a (unique) handle.  open a policy on it. */
-       if (!create_policy_hnd(p, &r_u->domain_pol, free_samr_info, (void *)info))
-               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
-
-       DEBUG(5,("samr_open_domain: %d\n", __LINE__));
-
-       return r_u->status;
-}
-
-/*******************************************************************
- _samr_get_usrdom_pwinfo
- ********************************************************************/
-
-NTSTATUS _samr_get_usrdom_pwinfo(pipes_struct *p, SAMR_Q_GET_USRDOM_PWINFO *q_u, SAMR_R_GET_USRDOM_PWINFO *r_u)
-{
-       struct samr_info *info = NULL;
-
-       r_u->status = NT_STATUS_OK;
-
-       /* find the policy handle.  open a policy on it. */
-       if (!find_policy_by_hnd(p, &q_u->user_pol, (void **)&info))
-               return NT_STATUS_INVALID_HANDLE;
-
-       if (!sid_check_is_in_our_domain(&info->sid))
-               return NT_STATUS_OBJECT_TYPE_MISMATCH;
-
-       init_samr_r_get_usrdom_pwinfo(r_u, NT_STATUS_OK);
-
-       DEBUG(5,("_samr_get_usrdom_pwinfo: %d\n", __LINE__));
-
-       /* 
-        * NT sometimes return NT_STATUS_ACCESS_DENIED
-        * I don't know yet why.
-        */
-
-       return r_u->status;
-}
-
-/*******************************************************************
- samr_make_dom_obj_sd
- ********************************************************************/
-
-static NTSTATUS samr_make_dom_obj_sd(TALLOC_CTX *ctx, SEC_DESC **psd, size_t *sd_size)
-{
-       extern DOM_SID global_sid_World;
-       DOM_SID adm_sid, act_sid, domadmin_sid;
-       SEC_ACE ace[4];
-       SEC_ACCESS mask;
-       size_t i = 0;
-
-       SEC_ACL *psa = NULL;
-
-       sid_copy(&adm_sid, &global_sid_Builtin);
-       sid_append_rid(&adm_sid, BUILTIN_ALIAS_RID_ADMINS);
-
-       sid_copy(&act_sid, &global_sid_Builtin);
-       sid_append_rid(&act_sid, BUILTIN_ALIAS_RID_ACCOUNT_OPS);
-
-       /*basic access for every one*/
-       init_sec_access(&mask, GENERIC_RIGHTS_DOMAIN_EXECUTE | GENERIC_RIGHTS_DOMAIN_READ);
-       init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
-
-       /*full access for builtin aliases Administrators and Account Operators*/
-       
-       init_sec_access(&mask, GENERIC_RIGHTS_DOMAIN_ALL_ACCESS);
-       
-       init_sec_ace(&ace[i++], &adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
-       init_sec_ace(&ace[i++], &act_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
-       
-       /* add domain admins if we are a DC */
-       
-       if ( IS_DC ) {
-               sid_copy( &domadmin_sid, get_global_sam_sid() );
-               sid_append_rid( &domadmin_sid, DOMAIN_GROUP_RID_ADMINS );
-               init_sec_ace(&ace[i++], &domadmin_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
-       }
-
-       if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, i, ace)) == NULL)
-               return NT_STATUS_NO_MEMORY;
-
-       if ((*psd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL, psa, sd_size)) == NULL)
-               return NT_STATUS_NO_MEMORY;
-
-       return NT_STATUS_OK;
-}
-
-/*******************************************************************
- samr_make_usr_obj_sd
- ********************************************************************/
-
-static NTSTATUS samr_make_usr_obj_sd(TALLOC_CTX *ctx, SEC_DESC **psd, size_t *sd_size, DOM_SID *usr_sid)
-{
-       extern DOM_SID global_sid_World;
-       DOM_SID adm_sid, act_sid, domadmin_sid;
-       size_t i = 0;
-
-       SEC_ACE ace[5];
-       SEC_ACCESS mask;
-
-       SEC_ACL *psa = NULL;
-
-       sid_copy(&adm_sid, &global_sid_Builtin);
-       sid_append_rid(&adm_sid, BUILTIN_ALIAS_RID_ADMINS);
-
-       sid_copy(&act_sid, &global_sid_Builtin);
-       sid_append_rid(&act_sid, BUILTIN_ALIAS_RID_ACCOUNT_OPS);
-
-       /*basic access for every one*/
-       
-       init_sec_access(&mask, GENERIC_RIGHTS_USER_EXECUTE | GENERIC_RIGHTS_USER_READ);
-       init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
-
-       /*full access for builtin aliases Administrators and Account Operators*/
-       
-       init_sec_access(&mask, GENERIC_RIGHTS_USER_ALL_ACCESS);
-       init_sec_ace(&ace[i++], &adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
-       init_sec_ace(&ace[i++], &act_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
-
-       /* add domain admins if we are a DC */
-       
-       if ( IS_DC ) {
-               sid_copy( &domadmin_sid, get_global_sam_sid() );
-               sid_append_rid( &domadmin_sid, DOMAIN_GROUP_RID_ADMINS );
-               init_sec_ace(&ace[i++], &domadmin_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
-       }
-
-       /*extended access for the user*/
-       
-       init_sec_access(&mask,READ_CONTROL_ACCESS | SA_RIGHT_USER_CHANGE_PASSWORD | SA_RIGHT_USER_SET_LOC_COM);
-       init_sec_ace(&ace[i++], usr_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
-
-       if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, 4, ace)) == NULL)
-               return NT_STATUS_NO_MEMORY;
-
-       if ((*psd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL, psa, sd_size)) == NULL)
-               return NT_STATUS_NO_MEMORY;
-
-       return NT_STATUS_OK;
-}
-
+
 /*******************************************************************
samr_make_grp_obj_sd
_samr_close_hnd
  ********************************************************************/
 
-static NTSTATUS samr_make_grp_obj_sd(TALLOC_CTX *ctx, SEC_DESC **psd, size_t *sd_size)
+NTSTATUS _samr_close_hnd(pipes_struct *p, SAMR_Q_CLOSE_HND *q_u, SAMR_R_CLOSE_HND *r_u)
 {
-       extern DOM_SID global_sid_World;
-       DOM_SID adm_sid;
-       DOM_SID act_sid;
+       r_u->status = NT_STATUS_OK;
 
-       SEC_ACE ace[3];
-       SEC_ACCESS mask;
+       /* close the policy handle */
+       if (!close_policy_hnd(p, &q_u->pol))
+               return NT_STATUS_OBJECT_NAME_INVALID;
 
-       SEC_ACL *psa = NULL;
+       DEBUG(5,("samr_reply_close_hnd: %d\n", __LINE__));
 
-       sid_copy(&adm_sid, &global_sid_Builtin);
-       sid_append_rid(&adm_sid, BUILTIN_ALIAS_RID_ADMINS);
+       return r_u->status;
+}
 
-       sid_copy(&act_sid, &global_sid_Builtin);
-       sid_append_rid(&act_sid, BUILTIN_ALIAS_RID_ACCOUNT_OPS);
+/*******************************************************************
+ samr_reply_open_domain
+ ********************************************************************/
 
-       /*basic access for every one*/
-       init_sec_access(&mask, GENERIC_RIGHTS_GROUP_EXECUTE | GENERIC_RIGHTS_GROUP_READ);
-       init_sec_ace(&ace[0], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+NTSTATUS _samr_open_domain(pipes_struct *p, SAMR_Q_OPEN_DOMAIN *q_u, SAMR_R_OPEN_DOMAIN *r_u)
+{
+       struct    samr_info *info;
+       SEC_DESC *psd = NULL;
+       uint32    acc_granted;
+       uint32    des_access = q_u->flags;
+       size_t    sd_size;
+       NTSTATUS  status;
+       SE_PRIV se_rights;
 
-       /*full access for builtin aliases Administrators and Account Operators*/
-       init_sec_access(&mask, GENERIC_RIGHTS_GROUP_ALL_ACCESS);
-       init_sec_ace(&ace[1], &adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
-       init_sec_ace(&ace[2], &act_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+       r_u->status = NT_STATUS_OK;
 
-       if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, 3, ace)) == NULL)
-               return NT_STATUS_NO_MEMORY;
+       /* find the connection policy handle. */
+       
+       if ( !find_policy_by_hnd(p, &q_u->pol, (void**)&info) )
+               return NT_STATUS_INVALID_HANDLE;
 
-       if ((*psd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL, psa, sd_size)) == NULL)
+       status = access_check_samr_function( info->acc_granted, 
+               SA_RIGHT_SAM_OPEN_DOMAIN, "_samr_open_domain" );
+               
+       if ( !NT_STATUS_IS_OK(status) )
+               return status;
+
+       /*check if access can be granted as requested by client. */
+       
+       samr_make_dom_obj_sd( p->mem_ctx, &psd, &sd_size );
+       se_map_generic( &des_access, &dom_generic_mapping );
+       
+       se_priv_copy( &se_rights, &se_machine_account );
+       se_priv_add( &se_rights, &se_add_users );
+
+       status = access_check_samr_object( psd, p->pipe_user.nt_user_token, 
+               &se_rights, GENERIC_RIGHTS_DOMAIN_WRITE, des_access, 
+               &acc_granted, "_samr_open_domain" );
+               
+       if ( !NT_STATUS_IS_OK(status) )
+               return status;
+
+       /* associate the domain SID with the (unique) handle. */
+       if ((info = get_samr_info_by_sid(&q_u->dom_sid.sid))==NULL)
                return NT_STATUS_NO_MEMORY;
+       info->acc_granted = acc_granted;
 
-       return NT_STATUS_OK;
+       /* get a (unique) handle.  open a policy on it. */
+       if (!create_policy_hnd(p, &r_u->domain_pol, free_samr_info, (void *)info))
+               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+
+       DEBUG(5,("samr_open_domain: %d\n", __LINE__));
+
+       return r_u->status;
 }
 
 /*******************************************************************
- samr_make_ali_obj_sd
+ _samr_get_usrdom_pwinfo
  ********************************************************************/
 
-static NTSTATUS samr_make_ali_obj_sd(TALLOC_CTX *ctx, SEC_DESC **psd, size_t *sd_size)
+NTSTATUS _samr_get_usrdom_pwinfo(pipes_struct *p, SAMR_Q_GET_USRDOM_PWINFO *q_u, SAMR_R_GET_USRDOM_PWINFO *r_u)
 {
-       extern DOM_SID global_sid_World;
-       DOM_SID adm_sid;
-       DOM_SID act_sid;
+       struct samr_info *info = NULL;
 
-       SEC_ACE ace[3];
-       SEC_ACCESS mask;
+       r_u->status = NT_STATUS_OK;
 
-       SEC_ACL *psa = NULL;
+       /* find the policy handle.  open a policy on it. */
+       if (!find_policy_by_hnd(p, &q_u->user_pol, (void **)&info))
+               return NT_STATUS_INVALID_HANDLE;
 
-       sid_copy(&adm_sid, &global_sid_Builtin);
-       sid_append_rid(&adm_sid, BUILTIN_ALIAS_RID_ADMINS);
+       if (!sid_check_is_in_our_domain(&info->sid))
+               return NT_STATUS_OBJECT_TYPE_MISMATCH;
 
-       sid_copy(&act_sid, &global_sid_Builtin);
-       sid_append_rid(&act_sid, BUILTIN_ALIAS_RID_ACCOUNT_OPS);
+       init_samr_r_get_usrdom_pwinfo(r_u, NT_STATUS_OK);
 
-       /*basic access for every one*/
-       init_sec_access(&mask, GENERIC_RIGHTS_ALIAS_EXECUTE | GENERIC_RIGHTS_ALIAS_READ);
-       init_sec_ace(&ace[0], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+       DEBUG(5,("_samr_get_usrdom_pwinfo: %d\n", __LINE__));
 
-       /*full access for builtin aliases Administrators and Account Operators*/
-       init_sec_access(&mask, GENERIC_RIGHTS_ALIAS_ALL_ACCESS);
-       init_sec_ace(&ace[1], &adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
-       init_sec_ace(&ace[2], &act_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+       /* 
+        * NT sometimes return NT_STATUS_ACCESS_DENIED
+        * I don't know yet why.
+        */
 
-       if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, 3, ace)) == NULL)
-               return NT_STATUS_NO_MEMORY;
+       return r_u->status;
+}
 
-       if ((*psd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL, psa, sd_size)) == NULL)
-               return NT_STATUS_NO_MEMORY;
 
-       return NT_STATUS_OK;
+/*******************************************************************
+ _samr_set_sec_obj
+ ********************************************************************/
+
+NTSTATUS _samr_set_sec_obj(pipes_struct *p, SAMR_Q_SET_SEC_OBJ *q_u, SAMR_R_SET_SEC_OBJ *r_u)
+{
+       DEBUG(0,("_samr_set_sec_obj: Not yet implemented!\n"));
+       return NT_STATUS_NOT_IMPLEMENTED;
 }
 
-static BOOL get_lsa_policy_samr_sid(pipes_struct *p, POLICY_HND *pol, DOM_SID *sid, uint32 *acc_granted)
+
+/*******************************************************************
+********************************************************************/
+
+static BOOL get_lsa_policy_samr_sid( pipes_struct *p, POLICY_HND *pol, 
+                                     DOM_SID *sid, uint32 *acc_granted)
 {
        struct samr_info *info = NULL;
 
@@ -645,17 +708,6 @@ static BOOL get_lsa_policy_samr_sid(pipes_struct *p, POLICY_HND *pol, DOM_SID *s
        return True;
 }
 
-/*******************************************************************
- _samr_set_sec_obj
- ********************************************************************/
-
-NTSTATUS _samr_set_sec_obj(pipes_struct *p, SAMR_Q_SET_SEC_OBJ *q_u, SAMR_R_SET_SEC_OBJ *r_u)
-{
-       DEBUG(0,("_samr_set_sec_obj: Not yet implemented!\n"));
-       return NT_STATUS_NOT_IMPLEMENTED;
-}
-
-
 /*******************************************************************
  _samr_query_sec_obj
  ********************************************************************/
@@ -1646,34 +1698,45 @@ NTSTATUS _samr_open_user(pipes_struct *p, SAMR_Q_OPEN_USER *q_u, SAMR_R_OPEN_USE
        size_t    sd_size;
        BOOL ret;
        NTSTATUS nt_status;
+       SE_PRIV se_rights;
 
        r_u->status = NT_STATUS_OK;
 
        /* find the domain policy handle and get domain SID / access bits in the domain policy. */
-       if (!get_lsa_policy_samr_sid(p, &domain_pol, &sid, &acc_granted))
+       
+       if ( !get_lsa_policy_samr_sid(p, &domain_pol, &sid, &acc_granted) )
                return NT_STATUS_INVALID_HANDLE;
        
-       if (!NT_STATUS_IS_OK(nt_status = access_check_samr_function(acc_granted, SA_RIGHT_DOMAIN_OPEN_ACCOUNT, "_samr_open_user"))) {
+       nt_status = access_check_samr_function( acc_granted, 
+               SA_RIGHT_DOMAIN_OPEN_ACCOUNT, "_samr_open_user" );
+               
+       if ( !NT_STATUS_IS_OK(nt_status) )
                return nt_status;
-       }
 
        nt_status = pdb_init_sam_talloc(p->mem_ctx, &sampass);
-       if (!NT_STATUS_IS_OK(nt_status)) {
+       
+       if (!NT_STATUS_IS_OK(nt_status))
                return nt_status;
-       }
 
        /* append the user's RID to it */
+       
        if (!sid_append_rid(&sid, q_u->user_rid))
                return NT_STATUS_NO_SUCH_USER;
        
        /* check if access can be granted as requested by client. */
+       
        samr_make_usr_obj_sd(p->mem_ctx, &psd, &sd_size, &sid);
        se_map_generic(&des_access, &usr_generic_mapping);
-       if (!NT_STATUS_IS_OK(nt_status = 
-                            access_check_samr_object(psd, p->pipe_user.nt_user_token, 
-                                                     des_access, &acc_granted, "_samr_open_user"))) {
+       
+       se_priv_copy( &se_rights, &se_machine_account );
+       se_priv_add( &se_rights, &se_add_users );
+       
+       nt_status = access_check_samr_object(psd, p->pipe_user.nt_user_token, 
+               &se_rights, GENERIC_RIGHTS_USER_WRITE, des_access, 
+               &acc_granted, "_samr_open_user");
+               
+       if ( !NT_STATUS_IS_OK(nt_status) )
                return nt_status;
-       }
 
        become_root();
        ret=pdb_getsampwsid(sampass, &sid);
@@ -2396,7 +2459,8 @@ NTSTATUS _samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, SAMR_R_CREA
        se_map_generic(&des_access, &usr_generic_mapping);
        
        nt_status = access_check_samr_object(psd, p->pipe_user.nt_user_token, 
-               des_access, &acc_granted, "_samr_create_user");
+               &se_rights, GENERIC_RIGHTS_USER_WRITE, des_access, 
+               &acc_granted, "_samr_create_user");
                
        if ( !NT_STATUS_IS_OK(nt_status) ) {
                return nt_status;
@@ -2494,11 +2558,12 @@ NTSTATUS _samr_connect(pipes_struct *p, SAMR_Q_CONNECT *q_u, SAMR_R_CONNECT *r_u
 
        samr_make_sam_obj_sd(p->mem_ctx, &psd, &sd_size);
        se_map_generic(&des_access, &sam_generic_mapping);
-       if (!NT_STATUS_IS_OK(nt_status = 
-                            access_check_samr_object(psd, p->pipe_user.nt_user_token, 
-                                                     des_access, &acc_granted, "_samr_connect"))) {
+       
+       nt_status = access_check_samr_object(psd, p->pipe_user.nt_user_token, 
+               NULL, 0, des_access, &acc_granted, "_samr_connect");
+       
+       if ( !NT_STATUS_IS_OK(nt_status) ) 
                return nt_status;
-       }
 
        r_u->status = NT_STATUS_OK;
 
@@ -2544,11 +2609,12 @@ NTSTATUS _samr_connect4(pipes_struct *p, SAMR_Q_CONNECT4 *q_u, SAMR_R_CONNECT4 *
 
        samr_make_sam_obj_sd(p->mem_ctx, &psd, &sd_size);
        se_map_generic(&des_access, &sam_generic_mapping);
-       if (!NT_STATUS_IS_OK(nt_status = 
-                            access_check_samr_object(psd, p->pipe_user.nt_user_token, 
-                                                     des_access, &acc_granted, "_samr_connect"))) {
+       
+       nt_status = access_check_samr_object(psd, p->pipe_user.nt_user_token, 
+               NULL, 0, des_access, &acc_granted, "_samr_connect4");
+       
+       if ( !NT_STATUS_IS_OK(nt_status) ) 
                return nt_status;
-       }
 
        r_u->status = NT_STATUS_OK;
 
@@ -2693,29 +2759,40 @@ NTSTATUS _samr_open_alias(pipes_struct *p, SAMR_Q_OPEN_ALIAS *q_u, SAMR_R_OPEN_A
        uint32    des_access = q_u->access_mask;
        size_t    sd_size;
        NTSTATUS  status;
+       SE_PRIV se_rights;
 
        r_u->status = NT_STATUS_OK;
 
        /* find the domain policy and get the SID / access bits stored in the domain policy */
-       if (!get_lsa_policy_samr_sid(p, &domain_pol, &sid, &acc_granted))
+       
+       if ( !get_lsa_policy_samr_sid(p, &domain_pol, &sid, &acc_granted) )
                return NT_STATUS_INVALID_HANDLE;
+       
+       status = access_check_samr_function(acc_granted, 
+               SA_RIGHT_DOMAIN_OPEN_ACCOUNT, "_samr_open_alias");
                
-       if (!NT_STATUS_IS_OK(status = access_check_samr_function(acc_granted, SA_RIGHT_DOMAIN_OPEN_ACCOUNT, "_samr_open_alias"))) {
+       if ( !NT_STATUS_IS_OK(status) ) 
                return status;
-       }
 
        /* append the alias' RID to it */
+       
        if (!sid_append_rid(&sid, alias_rid))
                return NT_STATUS_NO_SUCH_USER;
                
        /*check if access can be granted as requested by client. */
+       
        samr_make_ali_obj_sd(p->mem_ctx, &psd, &sd_size);
        se_map_generic(&des_access,&ali_generic_mapping);
-       if (!NT_STATUS_IS_OK(status = 
-                            access_check_samr_object(psd, p->pipe_user.nt_user_token, 
-                                                     des_access, &acc_granted, "_samr_open_alias"))) {
+       
+       se_priv_add( &se_rights, &se_add_users );
+       
+       
+       status = access_check_samr_object(psd, p->pipe_user.nt_user_token, 
+               &se_rights, GENERIC_RIGHTS_ALIAS_WRITE, des_access, 
+               &acc_granted, "_samr_open_alias");
+               
+       if ( !NT_STATUS_IS_OK(status) )
                return status;
-       }
 
        /*
         * we should check if the rid really exist !!!
@@ -2739,20 +2816,8 @@ NTSTATUS _samr_open_alias(pipes_struct *p, SAMR_Q_OPEN_ALIAS *q_u, SAMR_R_OPEN_A
  set_user_info_10
  ********************************************************************/
 
-static BOOL set_user_info_10(const SAM_USER_INFO_10 *id10, DOM_SID *sid)
+static BOOL set_user_info_10(const SAM_USER_INFO_10 *id10, SAM_ACCOUNT *pwd)
 {
-       SAM_ACCOUNT *pwd =NULL;
-       BOOL ret;
-       
-       pdb_init_sam(&pwd);
-       
-       ret = pdb_getsampwsid(pwd, sid);
-       
-       if(ret==False) {
-               pdb_free_sam(&pwd);
-               return False;
-       }
-
        if (id10 == NULL) {
                DEBUG(5, ("set_user_info_10: NULL id10\n"));
                pdb_free_sam(&pwd);
@@ -2779,16 +2844,8 @@ static BOOL set_user_info_10(const SAM_USER_INFO_10 *id10, DOM_SID *sid)
  set_user_info_12
  ********************************************************************/
 
-static BOOL set_user_info_12(SAM_USER_INFO_12 *id12, DOM_SID *sid)
+static BOOL set_user_info_12(SAM_USER_INFO_12 *id12, SAM_ACCOUNT *pwd)
 {
-       SAM_ACCOUNT *pwd = NULL;
-
-       pdb_init_sam(&pwd);
-
-       if(!pdb_getsampwsid(pwd, sid)) {
-               pdb_free_sam(&pwd);
-               return False;
-       }
 
        if (id12 == NULL) {
                DEBUG(2, ("set_user_info_12: id12 is NULL\n"));
@@ -2858,22 +2915,13 @@ static BOOL set_unix_primary_group(SAM_ACCOUNT *sampass)
  set_user_info_20
  ********************************************************************/
 
-static BOOL set_user_info_20(SAM_USER_INFO_20 *id20, DOM_SID *sid)
+static BOOL set_user_info_20(SAM_USER_INFO_20 *id20, SAM_ACCOUNT *pwd)
 {
-       SAM_ACCOUNT *pwd = NULL;
        if (id20 == NULL) {
                DEBUG(5, ("set_user_info_20: NULL id20\n"));
                return False;
        }
  
-       pdb_init_sam(&pwd);
-       if (!pdb_getsampwsid(pwd, sid)) {
-               pdb_free_sam(&pwd);
-               return False;
-       }
        copy_id20_to_sam_passwd(pwd, id20);
 
        /* write the change out */
@@ -2890,22 +2938,14 @@ static BOOL set_user_info_20(SAM_USER_INFO_20 *id20, DOM_SID *sid)
  set_user_info_21
  ********************************************************************/
 
-static BOOL set_user_info_21(SAM_USER_INFO_21 *id21, DOM_SID *sid)
+static BOOL set_user_info_21(SAM_USER_INFO_21 *id21, SAM_ACCOUNT *pwd)
 {
-       SAM_ACCOUNT *pwd = NULL;
  
        if (id21 == NULL) {
                DEBUG(5, ("set_user_info_21: NULL id21\n"));
                return False;
        }
  
-       pdb_init_sam(&pwd);
-       if (!pdb_getsampwsid(pwd, sid)) {
-               pdb_free_sam(&pwd);
-               return False;
-       }
        copy_id21_to_sam_passwd(pwd, id21);
  
        /*
@@ -2933,9 +2973,8 @@ static BOOL set_user_info_21(SAM_USER_INFO_21 *id21, DOM_SID *sid)
  set_user_info_23
  ********************************************************************/
 
-static BOOL set_user_info_23(SAM_USER_INFO_23 *id23, DOM_SID *sid)
+static BOOL set_user_info_23(SAM_USER_INFO_23 *id23, SAM_ACCOUNT *pwd)
 {
-       SAM_ACCOUNT *pwd = NULL;
        pstring plaintext_buf;
        uint32 len;
        uint16 acct_ctrl;
@@ -2945,13 +2984,6 @@ static BOOL set_user_info_23(SAM_USER_INFO_23 *id23, DOM_SID *sid)
                return False;
        }
  
-       pdb_init_sam(&pwd);
-       if (!pdb_getsampwsid(pwd, sid)) {
-               pdb_free_sam(&pwd);
-               return False;
-       }
-
        DEBUG(5, ("Attempting administrator password change (level 23) for user %s\n",
                  pdb_get_username(pwd)));
 
@@ -3008,20 +3040,12 @@ static BOOL set_user_info_23(SAM_USER_INFO_23 *id23, DOM_SID *sid)
  set_user_info_pw
  ********************************************************************/
 
-static BOOL set_user_info_pw(char *pass, DOM_SID *sid)
+static BOOL set_user_info_pw(char *pass, SAM_ACCOUNT *pwd)
 {
-       SAM_ACCOUNT *pwd = NULL;
        uint32 len;
        pstring plaintext_buf;
        uint16 acct_ctrl;
  
-       pdb_init_sam(&pwd);
-       if (!pdb_getsampwsid(pwd, sid)) {
-               pdb_free_sam(&pwd);
-               return False;
-       }
-       
        DEBUG(5, ("Attempting administrator password change for user %s\n",
                  pdb_get_username(pwd)));
 
@@ -3080,14 +3104,16 @@ static BOOL set_user_info_pw(char *pass, DOM_SID *sid)
 
 NTSTATUS _samr_set_userinfo(pipes_struct *p, SAMR_Q_SET_USERINFO *q_u, SAMR_R_SET_USERINFO *r_u)
 {
+       SAM_ACCOUNT *pwd = NULL;
        DOM_SID sid;
        POLICY_HND *pol = &q_u->pol;
        uint16 switch_value = q_u->switch_value;
        SAM_USERINFO_CTR *ctr = q_u->ctr;
        uint32 acc_granted;
        uint32 acc_required;
-       BOOL can_add_machines;
-       SE_PRIV se_machineop = SE_MACHINE_ACCOUNT;
+       BOOL ret;
+       BOOL has_enough_rights;
+       SE_PRIV se_rights;
 
        DEBUG(5, ("_samr_set_userinfo: %d\n", __LINE__));
 
@@ -3118,24 +3144,42 @@ NTSTATUS _samr_set_userinfo(pipes_struct *p, SAMR_Q_SET_USERINFO *q_u, SAMR_R_SE
                DEBUG(5, ("_samr_set_userinfo: NULL info level\n"));
                return NT_STATUS_INVALID_INFO_CLASS;
        }
+       
+       pdb_init_sam(&pwd);     
+       
+       become_root();
+       ret = pdb_getsampwsid(pwd, &sid);
+       unbecome_root();
+       
+       if ( !ret ) {
+               pdb_free_sam(&pwd);
+               return NT_STATUS_NO_SUCH_USER;
+       }
+       
+       /* deal with machine password changes differently from userinfo changes */
+       
+       if ( pdb_get_acct_ctrl(pwd) & ACB_WSTRUST )
+               se_priv_copy( &se_rights, &se_machine_account );
+       else
+               se_priv_copy( &se_rights, &se_add_users );
 
-       /* check to see if we are a domain admin */
+       /* check to see if we have the sufficient rights */
        
-       can_add_machines = user_has_privileges( p->pipe_user.nt_user_token, &se_machineop );
+       has_enough_rights = user_has_privileges( p->pipe_user.nt_user_token, &se_rights );
        
-       DEBUG(5, ("_samr_set_userinfo: %s is%s a member of the Domain Admins group\n",
-               p->pipe_user_name, can_add_machines ? "" : " not"));
+       DEBUG(5, ("_samr_set_userinfo: %s does%s possess sufficient rights\n",
+               p->pipe_user_name, has_enough_rights ? "" : " not"));
 
        /* ================ BEGIN SeMachineAccountPrivilege BLOCK ================ */
        
-       if ( can_add_machines )                         
-               become_root();
-
+       if ( has_enough_rights )                                
+               become_root(); 
+       
        /* ok!  user info levels (lots: see MSDEV help), off we go... */
 
        switch (switch_value) {
-               case 0x12:
-                       if (!set_user_info_12(ctr->info.id12, &sid))
+               case 18:
+                       if (!set_user_info_12(ctr->info.id12, pwd))
                                r_u->status = NT_STATUS_ACCESS_DENIED;
                        break;
 
@@ -3147,7 +3191,7 @@ NTSTATUS _samr_set_userinfo(pipes_struct *p, SAMR_Q_SET_USERINFO *q_u, SAMR_R_SE
 
                        dump_data(100, (char *)ctr->info.id24->pass, 516);
 
-                       if (!set_user_info_pw((char *)ctr->info.id24->pass, &sid))
+                       if (!set_user_info_pw((char *)ctr->info.id24->pass, pwd))
                                r_u->status = NT_STATUS_ACCESS_DENIED;
                        break;
 
@@ -3183,7 +3227,7 @@ NTSTATUS _samr_set_userinfo(pipes_struct *p, SAMR_Q_SET_USERINFO *q_u, SAMR_R_SE
 
                        dump_data(100, (char *)ctr->info.id23->pass, 516);
 
-                       if (!set_user_info_23(ctr->info.id23, &sid))
+                       if (!set_user_info_23(ctr->info.id23, pwd))
                                r_u->status = NT_STATUS_ACCESS_DENIED;
                        break;
 
@@ -3192,7 +3236,7 @@ NTSTATUS _samr_set_userinfo(pipes_struct *p, SAMR_Q_SET_USERINFO *q_u, SAMR_R_SE
        }
 
        
-       if ( can_add_machines )                         
+       if ( has_enough_rights )                                
                unbecome_root();
                
        /* ================ END SeMachineAccountPrivilege BLOCK ================ */
@@ -3206,14 +3250,16 @@ NTSTATUS _samr_set_userinfo(pipes_struct *p, SAMR_Q_SET_USERINFO *q_u, SAMR_R_SE
 
 NTSTATUS _samr_set_userinfo2(pipes_struct *p, SAMR_Q_SET_USERINFO2 *q_u, SAMR_R_SET_USERINFO2 *r_u)
 {
+       SAM_ACCOUNT *pwd = NULL;
        DOM_SID sid;
        SAM_USERINFO_CTR *ctr = q_u->ctr;
        POLICY_HND *pol = &q_u->pol;
        uint16 switch_value = q_u->switch_value;
        uint32 acc_granted;
        uint32 acc_required;
-       BOOL can_add_machines;
-       SE_PRIV se_machineop = SE_MACHINE_ACCOUNT;
+       BOOL ret;
+       BOOL has_enough_rights;
+       SE_PRIV se_rights;
 
        DEBUG(5, ("samr_reply_set_userinfo2: %d\n", __LINE__));
 
@@ -3237,43 +3283,61 @@ NTSTATUS _samr_set_userinfo2(pipes_struct *p, SAMR_Q_SET_USERINFO2 *q_u, SAMR_R_
 
        switch_value=ctr->switch_value;
 
-       /* check to see if we are a domain admin */
+       pdb_init_sam(&pwd);     
+       
+       become_root();
+       ret = pdb_getsampwsid(pwd, &sid);
+       unbecome_root();
+       
+       if ( !ret ) {
+               pdb_free_sam(&pwd);
+               return NT_STATUS_NO_SUCH_USER;
+       }
+       
+       /* deal with machine password changes differently from userinfo changes */
+       
+       if ( pdb_get_acct_ctrl(pwd) & ACB_WSTRUST )
+               se_priv_copy( &se_rights, &se_machine_account );
+       else
+               se_priv_copy( &se_rights, &se_add_users );
+
+       /* check to see if we have the sufficient rights */
        
-       can_add_machines = user_has_privileges( p->pipe_user.nt_user_token, &se_machineop );
+       has_enough_rights = user_has_privileges( p->pipe_user.nt_user_token, &se_rights );
        
-       DEBUG(5, ("_samr_create_user: %s is%s a member of the Domain Admins group\n",
-               p->pipe_user_name, can_add_machines ? "" : " not"));
+       DEBUG(5, ("_samr_set_userinfo: %s does%s possess sufficient rights\n",
+               p->pipe_user_name, has_enough_rights ? "" : " not"));
 
        /* ================ BEGIN SeMachineAccountPrivilege BLOCK ================ */
        
-       if ( can_add_machines )                         
-               become_root();
-               
+       if ( has_enough_rights )                                
+               become_root(); 
+       
        /* ok!  user info levels (lots: see MSDEV help), off we go... */
        
        switch (switch_value) {
                case 21:
-                       if (!set_user_info_21(ctr->info.id21, &sid))
+                       if (!set_user_info_21(ctr->info.id21, pwd))
                                return NT_STATUS_ACCESS_DENIED;
                        break;
                case 20:
-                       if (!set_user_info_20(ctr->info.id20, &sid))
+                       if (!set_user_info_20(ctr->info.id20, pwd))
                                r_u->status = NT_STATUS_ACCESS_DENIED;
                        break;
                case 16:
-                       if (!set_user_info_10(ctr->info.id10, &sid))
+                       if (!set_user_info_10(ctr->info.id10, pwd))
                                r_u->status = NT_STATUS_ACCESS_DENIED;
                        break;
                case 18:
                        /* Used by AS/U JRA. */
-                       if (!set_user_info_12(ctr->info.id12, &sid))
+                       if (!set_user_info_12(ctr->info.id12, pwd))
                                r_u->status = NT_STATUS_ACCESS_DENIED;
                        break;
                default:
                        r_u->status = NT_STATUS_INVALID_INFO_CLASS;
        }
 
-       if ( can_add_machines )                         
+       if ( has_enough_rights )                                
                unbecome_root();
                
        /* ================ END SeMachineAccountPrivilege BLOCK ================ */
@@ -4413,25 +4477,32 @@ NTSTATUS _samr_open_group(pipes_struct *p, SAMR_Q_OPEN_GROUP *q_u, SAMR_R_OPEN_G
        NTSTATUS          status;
        fstring sid_string;
        BOOL ret;
+       SE_PRIV se_rights;
 
        if (!get_lsa_policy_samr_sid(p, &q_u->domain_pol, &sid, &acc_granted)) 
                return NT_STATUS_INVALID_HANDLE;
        
-       if (!NT_STATUS_IS_OK(status = access_check_samr_function(acc_granted, SA_RIGHT_DOMAIN_OPEN_ACCOUNT, "_samr_open_group"))) {
+       status = access_check_samr_function(acc_granted, 
+               SA_RIGHT_DOMAIN_OPEN_ACCOUNT, "_samr_open_group");
+               
+       if ( !NT_STATUS_IS_OK(status) )
                return status;
-       }
                
        /*check if access can be granted as requested by client. */
        samr_make_grp_obj_sd(p->mem_ctx, &psd, &sd_size);
        se_map_generic(&des_access,&grp_generic_mapping);
-       if (!NT_STATUS_IS_OK(status = 
-                            access_check_samr_object(psd, p->pipe_user.nt_user_token, 
-                                                     des_access, &acc_granted, "_samr_open_group"))) {
-               return status;
-       }
 
+       se_priv_copy( &se_rights, &se_add_users );
+
+       status = access_check_samr_object(psd, p->pipe_user.nt_user_token, 
+               &se_rights, GENERIC_RIGHTS_GROUP_WRITE, des_access, 
+               &acc_granted, "_samr_open_group");
+               
+       if ( !NT_STATUS_IS_OK(status) ) 
+               return status;
 
        /* this should not be hard-coded like this */
+       
        if (!sid_equal(&sid, get_global_sam_sid()))
                return NT_STATUS_ACCESS_DENIED;