コード例 #1
0
ファイル: uid.c プロジェクト: AIdrifter/samba
static uint32_t create_share_access_mask(int snum,
				bool readonly_share,
				const struct security_token *token)
{
	uint32_t share_access = 0;

	share_access_check(token,
			lp_servicename(talloc_tos(), snum),
			MAXIMUM_ALLOWED_ACCESS,
			&share_access);

	if (readonly_share) {
		share_access &=
			~(SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA |
			  SEC_FILE_WRITE_EA | SEC_FILE_WRITE_ATTRIBUTE |
			  SEC_DIR_DELETE_CHILD );
	}

	if (security_token_has_privilege(token, SEC_PRIV_SECURITY)) {
		share_access |= SEC_FLAG_SYSTEM_SECURITY;
	}
	if (security_token_has_privilege(token, SEC_PRIV_RESTORE)) {
		share_access |= SEC_RIGHTS_PRIV_RESTORE;
	}
	if (security_token_has_privilege(token, SEC_PRIV_BACKUP)) {
		share_access |= SEC_RIGHTS_PRIV_BACKUP;
	}
	if (security_token_has_privilege(token, SEC_PRIV_TAKE_OWNERSHIP)) {
		share_access |= SEC_STD_WRITE_OWNER;
	}

	return share_access;
}
コード例 #2
0
ファイル: srv_fss_agent.c プロジェクト: Distrotech/samba
/*
 * Determine whether to process an FSRVP operation from connected user @p.
 * Windows checks for Administrators or Backup Operators group membership. We
 * also allow for the SEC_PRIV_BACKUP privilege.
 */
static bool fss_permitted(struct pipes_struct *p)
{
	if (p->session_info->unix_token->uid == sec_initial_uid()) {
		DEBUG(6, ("Granting FSRVP op, user started smbd\n"));
		return true;
	}

	if (nt_token_check_sid(&global_sid_Builtin_Administrators,
			       p->session_info->security_token)) {
		DEBUG(6, ("Granting FSRVP op, administrators group member\n"));
		return true;
	}
	if (nt_token_check_sid(&global_sid_Builtin_Backup_Operators,
			       p->session_info->security_token)) {
		DEBUG(6, ("Granting FSRVP op, backup operators group member\n"));
		return true;
	}
	if (security_token_has_privilege(p->session_info->security_token,
					 SEC_PRIV_BACKUP)) {
		DEBUG(6, ("Granting FSRVP op, backup privilege present\n"));
		return true;
	}

	DEBUG(2, ("FSRVP operation blocked due to lack of backup privilege "
		  "or Administrators/Backup Operators group membership\n"));

	return false;
}
コード例 #3
0
static bool smbconf_reg_access_check(const char *keyname, uint32_t requested,
				     uint32_t *granted,
				     const struct security_token *token)
{
	if (!security_token_has_privilege(token, SEC_PRIV_DISK_OPERATOR)) {
		return False;
	}

	*granted = REG_KEY_ALL;
	return True;
}
コード例 #4
0
ファイル: access_check.c プロジェクト: 0x24bin/winexe-1
/*
  perform a SEC_FLAG_MAXIMUM_ALLOWED access check
*/
static uint32_t access_check_max_allowed(const struct security_descriptor *sd, 
					 const struct security_token *token)
{
	uint32_t denied = 0, granted = 0;
	unsigned i;
	
	if (security_token_has_sid(token, sd->owner_sid)) {
		granted |= SEC_STD_WRITE_DAC | SEC_STD_READ_CONTROL | SEC_STD_DELETE;
	} else if (security_token_has_privilege(token, SEC_PRIV_RESTORE)) {
		granted |= SEC_STD_DELETE;
	}

	if (sd->dacl == NULL) {
		return granted & ~denied;
	}
	
	for (i = 0;i<sd->dacl->num_aces; i++) {
		struct security_ace *ace = &sd->dacl->aces[i];

		if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
			continue;
		}

		if (!security_token_has_sid(token, &ace->trustee)) {
			continue;
		}

		switch (ace->type) {
		case SEC_ACE_TYPE_ACCESS_ALLOWED:
			granted |= ace->access_mask;
			break;
		case SEC_ACE_TYPE_ACCESS_DENIED:
		case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT:
			denied |= ace->access_mask;
			break;
		default:	/* Other ACE types not handled/supported */
			break;
		}
	}

	return granted & ~denied;
}
コード例 #5
0
ファイル: srv_wkssvc_nt.c プロジェクト: Arkhont/samba
WERROR _wkssvc_NetrUnjoinDomain2(struct pipes_struct *p,
				 struct wkssvc_NetrUnjoinDomain2 *r)
{
	struct libnet_UnjoinCtx *u = NULL;
	char *cleartext_pwd = NULL;
	char *admin_domain = NULL;
	char *admin_account = NULL;
	WERROR werr;
	struct security_token *token = p->session_info->security_token;

	if (!r->in.account || !r->in.encrypted_password) {
		return WERR_INVALID_PARAM;
	}

	if (!security_token_has_privilege(token, SEC_PRIV_MACHINE_ACCOUNT) &&
	    !nt_token_check_domain_rid(token, DOMAIN_RID_ADMINS) &&
	    !nt_token_check_sid(&global_sid_Builtin_Administrators, token)) {
		DEBUG(5,("_wkssvc_NetrUnjoinDomain2: account doesn't have "
			"sufficient privileges\n"));
		return WERR_ACCESS_DENIED;
	}

	werr = decode_wkssvc_join_password_buffer(
		p->mem_ctx, r->in.encrypted_password,
		&p->session_info->session_key, &cleartext_pwd);
	if (!W_ERROR_IS_OK(werr)) {
		return werr;
	}

	split_domain_user(p->mem_ctx,
			  r->in.account,
			  &admin_domain,
			  &admin_account);

	werr = libnet_init_UnjoinCtx(p->mem_ctx, &u);
	if (!W_ERROR_IS_OK(werr)) {
		return werr;
	}

	u->in.domain_name	= lp_realm();
	u->in.unjoin_flags	= r->in.unjoin_flags |
				  WKSSVC_JOIN_FLAGS_JOIN_TYPE;
	u->in.admin_account	= admin_account;
	u->in.admin_password	= cleartext_pwd;
	u->in.debug		= true;
	u->in.modify_config     = lp_config_backend_is_registry();
	u->in.msg_ctx		= p->msg_ctx;

	become_root();
	werr = libnet_Unjoin(p->mem_ctx, u);
	unbecome_root();

	if (!W_ERROR_IS_OK(werr)) {
		DEBUG(5,("_wkssvc_NetrUnjoinDomain2: libnet_Unjoin failed with: %s\n",
			u->out.error_string ? u->out.error_string :
			win_errstr(werr)));
	}

	TALLOC_FREE(u);
	return werr;
}
コード例 #6
0
NTSTATUS sec_access_check_ds(const struct security_descriptor *sd,
			     const struct security_token *token,
			     uint32_t access_desired,
			     uint32_t *access_granted,
			     struct object_tree *tree,
			     struct dom_sid *replace_sid)
{
	uint32_t i;
	uint32_t bits_remaining;
	struct object_tree *node;
	const struct GUID *type;
	struct dom_sid self_sid;

	dom_sid_parse(SID_NT_SELF, &self_sid);

	*access_granted = access_desired;
	bits_remaining = access_desired;

	/* handle the maximum allowed flag */
	if (access_desired & SEC_FLAG_MAXIMUM_ALLOWED) {
		access_desired |= access_check_max_allowed(sd, token);
		access_desired &= ~SEC_FLAG_MAXIMUM_ALLOWED;
		*access_granted = access_desired;
		bits_remaining = access_desired;
	}

	if (access_desired & SEC_FLAG_SYSTEM_SECURITY) {
		if (security_token_has_privilege(token, SEC_PRIV_SECURITY)) {
			bits_remaining &= ~SEC_FLAG_SYSTEM_SECURITY;
		} else {
			return NT_STATUS_PRIVILEGE_NOT_HELD;
		}
	}

	/* the owner always gets SEC_STD_WRITE_DAC and SEC_STD_READ_CONTROL */
	if ((bits_remaining & (SEC_STD_WRITE_DAC|SEC_STD_READ_CONTROL)) &&
	    security_token_has_sid(token, sd->owner_sid)) {
		bits_remaining &= ~(SEC_STD_WRITE_DAC|SEC_STD_READ_CONTROL);
	}

	/* TODO: remove this, as it is file server specific */
	if ((bits_remaining & SEC_RIGHTS_PRIV_RESTORE) &&
	    security_token_has_privilege(token, SEC_PRIV_RESTORE)) {
		bits_remaining &= ~(SEC_RIGHTS_PRIV_RESTORE);
	}
	if ((bits_remaining & SEC_RIGHTS_PRIV_BACKUP) &&
	    security_token_has_privilege(token, SEC_PRIV_BACKUP)) {
		bits_remaining &= ~(SEC_RIGHTS_PRIV_BACKUP);
	}

	/* a NULL dacl allows access */
	if ((sd->type & SEC_DESC_DACL_PRESENT) && sd->dacl == NULL) {
		*access_granted = access_desired;
		return NT_STATUS_OK;
	}

	if (sd->dacl == NULL) {
		goto done;
	}

	/* check each ace in turn. */
	for (i=0; bits_remaining && i < sd->dacl->num_aces; i++) {
		struct dom_sid *trustee;
		struct security_ace *ace = &sd->dacl->aces[i];

		if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
			continue;
		}

		if (dom_sid_equal(&ace->trustee, &self_sid) && replace_sid) {
			trustee = replace_sid;
		} else {
			trustee = &ace->trustee;
		}

		if (!security_token_has_sid(token, trustee)) {
			continue;
		}

		switch (ace->type) {
		case SEC_ACE_TYPE_ACCESS_ALLOWED:
			if (tree) {
				object_tree_modify_access(tree, ace->access_mask);
			}

			bits_remaining &= ~ace->access_mask;
			break;
		case SEC_ACE_TYPE_ACCESS_DENIED:
			if (bits_remaining & ace->access_mask) {
				return NT_STATUS_ACCESS_DENIED;
			}
			break;
		case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT:
		case SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT:
			/*
			 * check only in case we have provided a tree,
			 * the ACE has an object type and that type
			 * is in the tree
			 */
			type = get_ace_object_type(ace);

			if (!tree) {
				continue;
			}

			if (!type) {
				node = tree;
			} else {
				if (!(node = get_object_tree_by_GUID(tree, type))) {
					continue;
				}
			}

			if (ace->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT) {
				object_tree_modify_access(node, ace->access_mask);
				if (node->remaining_access == 0) {
					return NT_STATUS_OK;
				}
			} else {
				if (node->remaining_access & ace->access_mask){
					return NT_STATUS_ACCESS_DENIED;
				}
			}
			break;
		default:	/* Other ACE types not handled/supported */
			break;
		}
	}

done:
	if (bits_remaining != 0) {
		return NT_STATUS_ACCESS_DENIED;
	}

	return NT_STATUS_OK;
}
コード例 #7
0
/*
  The main entry point for access checking FOR THE FILE SERVER ONLY !
  If returning ACCESS_DENIED this function returns the denied bits in
  the uint32_t pointed to by the access_granted pointer.
*/
NTSTATUS se_file_access_check(const struct security_descriptor *sd,
			  const struct security_token *token,
			  bool priv_open_requested,
			  uint32_t access_desired,
			  uint32_t *access_granted)
{
	uint32_t bits_remaining;
	NTSTATUS status;

	if (!priv_open_requested) {
		/* Fall back to generic se_access_check(). */
		return se_access_check(sd,
				token,
				access_desired,
				access_granted);
	}

	/*
	 * We need to handle the maximum allowed flag
	 * outside of se_access_check(), as we need to
	 * add in the access allowed by the privileges
	 * as well.
	 */

	if (access_desired & SEC_FLAG_MAXIMUM_ALLOWED) {
		uint32_t orig_access_desired = access_desired;

		access_desired |= access_check_max_allowed(sd, token);
		access_desired &= ~SEC_FLAG_MAXIMUM_ALLOWED;

		if (security_token_has_privilege(token, SEC_PRIV_BACKUP)) {
			access_desired |= SEC_RIGHTS_PRIV_BACKUP;
		}

		if (security_token_has_privilege(token, SEC_PRIV_RESTORE)) {
			access_desired |= SEC_RIGHTS_PRIV_RESTORE;
		}

		DEBUG(10,("se_file_access_check: MAX desired = 0x%x "
			"mapped to 0x%x\n",
			orig_access_desired,
			access_desired));
	}

	status = se_access_check(sd,
				token,
				access_desired,
				access_granted);

	if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
		return status;
	}

	bits_remaining = *access_granted;

	/* Check if we should override with privileges. */
	if ((bits_remaining & SEC_RIGHTS_PRIV_BACKUP) &&
	    security_token_has_privilege(token, SEC_PRIV_BACKUP)) {
		bits_remaining &= ~(SEC_RIGHTS_PRIV_BACKUP);
	}
	if ((bits_remaining & SEC_RIGHTS_PRIV_RESTORE) &&
	    security_token_has_privilege(token, SEC_PRIV_RESTORE)) {
		bits_remaining &= ~(SEC_RIGHTS_PRIV_RESTORE);
	}
	if (bits_remaining != 0) {
		*access_granted = bits_remaining;
		return NT_STATUS_ACCESS_DENIED;
	}

	return NT_STATUS_OK;
}
コード例 #8
0
/*
  The main entry point for access checking. If returning ACCESS_DENIED
  this function returns the denied bits in the uint32_t pointed
  to by the access_granted pointer.
*/
NTSTATUS se_access_check(const struct security_descriptor *sd,
			  const struct security_token *token,
			  uint32_t access_desired,
			  uint32_t *access_granted)
{
	uint32_t i;
	uint32_t bits_remaining;
	uint32_t explicitly_denied_bits = 0;
	/*
	 * Up until Windows Server 2008, owner always had these rights. Now
	 * we have to use Owner Rights perms if they are on the file.
	 *
	 * In addition we have to accumulate these bits and apply them
	 * correctly. See bug #8795
	 */
	uint32_t owner_rights_allowed = 0;
	uint32_t owner_rights_denied = 0;
	bool owner_rights_default = true;

	*access_granted = access_desired;
	bits_remaining = access_desired;

	/* handle the maximum allowed flag */
	if (access_desired & SEC_FLAG_MAXIMUM_ALLOWED) {
		uint32_t orig_access_desired = access_desired;

		access_desired |= access_check_max_allowed(sd, token);
		access_desired &= ~SEC_FLAG_MAXIMUM_ALLOWED;
		*access_granted = access_desired;
		bits_remaining = access_desired;

		DEBUG(10,("se_access_check: MAX desired = 0x%x, granted = 0x%x, remaining = 0x%x\n",
			orig_access_desired,
			*access_granted,
			bits_remaining));
	}

	/* a NULL dacl allows access */
	if ((sd->type & SEC_DESC_DACL_PRESENT) && sd->dacl == NULL) {
		*access_granted = access_desired;
		return NT_STATUS_OK;
	}

	if (sd->dacl == NULL) {
		goto done;
	}

	/* check each ace in turn. */
	for (i=0; bits_remaining && i < sd->dacl->num_aces; i++) {
		struct security_ace *ace = &sd->dacl->aces[i];

		if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
			continue;
		}

		/*
		 * We need the Owner Rights permissions to ensure we
		 * give or deny the correct permissions to the owner. Replace
		 * owner_rights with the perms here if it is present.
		 *
		 * We don't care if we are not the owner because that is taken
		 * care of below when we check if our token has the owner SID.
		 *
		 */
		if (dom_sid_equal(&ace->trustee, &global_sid_Owner_Rights)) {
			if (ace->type == SEC_ACE_TYPE_ACCESS_ALLOWED) {
				owner_rights_allowed |= ace->access_mask;
				owner_rights_default = false;
			} else if (ace->type == SEC_ACE_TYPE_ACCESS_DENIED) {
				owner_rights_denied |= ace->access_mask;
				owner_rights_default = false;
			}
			continue;
		}

		if (!security_token_has_sid(token, &ace->trustee)) {
			continue;
		}

		switch (ace->type) {
		case SEC_ACE_TYPE_ACCESS_ALLOWED:
			bits_remaining &= ~ace->access_mask;
			break;
		case SEC_ACE_TYPE_ACCESS_DENIED:
		case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT:
			explicitly_denied_bits |= (bits_remaining & ace->access_mask);
			break;
		default:	/* Other ACE types not handled/supported */
			break;
		}
	}

	/* Explicitly denied bits always override */
	bits_remaining |= explicitly_denied_bits;

	/* The owner always gets owner rights as defined above. */
	if (security_token_has_sid(token, sd->owner_sid)) {
		if (owner_rights_default) {
			/*
			 * Just remove them, no need to check if they are
			 * there.
			 */
			bits_remaining &= ~(SEC_STD_WRITE_DAC |
						SEC_STD_READ_CONTROL);
		} else {
			bits_remaining &= ~owner_rights_allowed;
			bits_remaining |= owner_rights_denied;
		}
	}

	/*
	 * We check privileges here because they override even DENY entries.
	 */

	/* Does the user have the privilege to gain SEC_PRIV_SECURITY? */
	if (bits_remaining & SEC_FLAG_SYSTEM_SECURITY) {
		if (security_token_has_privilege(token, SEC_PRIV_SECURITY)) {
			bits_remaining &= ~SEC_FLAG_SYSTEM_SECURITY;
		} else {
			return NT_STATUS_PRIVILEGE_NOT_HELD;
		}
	}

	if ((bits_remaining & SEC_STD_WRITE_OWNER) &&
	     security_token_has_privilege(token, SEC_PRIV_TAKE_OWNERSHIP)) {
		bits_remaining &= ~(SEC_STD_WRITE_OWNER);
	}

done:
	if (bits_remaining != 0) {
		*access_granted = bits_remaining;
		return NT_STATUS_ACCESS_DENIED;
	}

	return NT_STATUS_OK;
}
コード例 #9
0
ファイル: access_check.c プロジェクト: 0x24bin/winexe-1
/*
  the main entry point for access checking. 
*/
NTSTATUS sec_access_check(const struct security_descriptor *sd, 
			  const struct security_token *token,
			  uint32_t access_desired,
			  uint32_t *access_granted)
{
	int i;
	uint32_t bits_remaining;

	*access_granted = access_desired;
	bits_remaining = access_desired;

	/* handle the maximum allowed flag */
	if (access_desired & SEC_FLAG_MAXIMUM_ALLOWED) {
		access_desired |= access_check_max_allowed(sd, token);
		access_desired &= ~SEC_FLAG_MAXIMUM_ALLOWED;
		*access_granted = access_desired;
		bits_remaining = access_desired & ~SEC_STD_DELETE;
	}

	if (access_desired & SEC_FLAG_SYSTEM_SECURITY) {
		if (security_token_has_privilege(token, SEC_PRIV_SECURITY)) {
			bits_remaining &= ~SEC_FLAG_SYSTEM_SECURITY;
		} else {
			return NT_STATUS_PRIVILEGE_NOT_HELD;
		}
	}

	/* a NULL dacl allows access */
	if ((sd->type & SEC_DESC_DACL_PRESENT) && sd->dacl == NULL) {
		*access_granted = access_desired;
		return NT_STATUS_OK;
	}

	/* the owner always gets SEC_STD_WRITE_DAC, SEC_STD_READ_CONTROL and SEC_STD_DELETE */
	if ((bits_remaining & (SEC_STD_WRITE_DAC|SEC_STD_READ_CONTROL|SEC_STD_DELETE)) &&
	    security_token_has_sid(token, sd->owner_sid)) {
		bits_remaining &= ~(SEC_STD_WRITE_DAC|SEC_STD_READ_CONTROL|SEC_STD_DELETE);
	}
	if ((bits_remaining & SEC_RIGHTS_PRIV_RESTORE) &&
	    security_token_has_privilege(token, SEC_PRIV_RESTORE)) {
		bits_remaining &= ~(SEC_RIGHTS_PRIV_RESTORE);
	}
	if ((bits_remaining & SEC_RIGHTS_PRIV_BACKUP) &&
	    security_token_has_privilege(token, SEC_PRIV_BACKUP)) {
		bits_remaining &= ~(SEC_RIGHTS_PRIV_BACKUP);
	}

	if (sd->dacl == NULL) {
		goto done;
	}

	/* check each ace in turn. */
	for (i=0; bits_remaining && i < sd->dacl->num_aces; i++) {
		struct security_ace *ace = &sd->dacl->aces[i];

		if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
			continue;
		}

		if (!security_token_has_sid(token, &ace->trustee)) {
			continue;
		}

		switch (ace->type) {
		case SEC_ACE_TYPE_ACCESS_ALLOWED:
			bits_remaining &= ~ace->access_mask;
			break;
		case SEC_ACE_TYPE_ACCESS_DENIED:
		case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT:
			if (bits_remaining & ace->access_mask) {
				return NT_STATUS_ACCESS_DENIED;
			}
			break;
		default:	/* Other ACE types not handled/supported */
			break;
		}
	}

done:
	if (bits_remaining != 0) {
		return NT_STATUS_ACCESS_DENIED;
	}

	return NT_STATUS_OK;
}
コード例 #10
0
NTSTATUS access_check_object( struct security_descriptor *psd, struct security_token *token,
			      enum sec_privilege needed_priv_1, enum sec_privilege needed_priv_2,
			      uint32 rights_mask,
			      uint32 des_access, uint32 *acc_granted,
			      const char *debug )
{
	NTSTATUS status = NT_STATUS_ACCESS_DENIED;
	uint32 saved_mask = 0;
	bool priv_granted = false;

	/* check privileges; certain SAM access bits should be overridden
	   by privileges (mostly having to do with creating/modifying/deleting
	   users and groups) */

	if ((needed_priv_1 != SEC_PRIV_INVALID && security_token_has_privilege(token, needed_priv_1)) ||
	    (needed_priv_2 != SEC_PRIV_INVALID && security_token_has_privilege(token, needed_priv_2))) {
		priv_granted = true;
		saved_mask = (des_access & rights_mask);
		des_access &= ~saved_mask;

		DEBUG(4,("access_check_object: user rights access mask [0x%x]\n",
			rights_mask));
	}


	/* check the security descriptor first */

	status = se_access_check(psd, token, des_access, acc_granted);
	if (NT_STATUS_IS_OK(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"));

		priv_granted = true;
		*acc_granted = des_access;

		status = NT_STATUS_OK;
		goto done;
	}


done:
	if (priv_granted) {
		/* add in any bits saved during the privilege check (only
		   matters if status is ok) */

		*acc_granted |= rights_mask;
	}

	DEBUG(4,("%s: access %s (requested: 0x%08x, granted: 0x%08x)\n",
		debug, NT_STATUS_IS_OK(status) ? "GRANTED" : "DENIED",
		des_access, *acc_granted));

	return status;
}
コード例 #11
0
ファイル: access_check.c プロジェクト: Arkhont/samba
/*
  The main entry point for access checking. If returning ACCESS_DENIED
  this function returns the denied bits in the uint32_t pointed
  to by the access_granted pointer.
*/
NTSTATUS se_access_check(const struct security_descriptor *sd,
			  const struct security_token *token,
			  uint32_t access_desired,
			  uint32_t *access_granted)
{
	uint32_t i;
	uint32_t bits_remaining;

	*access_granted = access_desired;
	bits_remaining = access_desired;

	/* handle the maximum allowed flag */
	if (access_desired & SEC_FLAG_MAXIMUM_ALLOWED) {
		uint32_t orig_access_desired = access_desired;

		access_desired |= access_check_max_allowed(sd, token);
		access_desired &= ~SEC_FLAG_MAXIMUM_ALLOWED;
		*access_granted = access_desired;
		bits_remaining = access_desired;

		DEBUG(10,("se_access_check: MAX desired = 0x%x, granted = 0x%x, remaining = 0x%x\n",
			orig_access_desired,
			*access_granted,
			bits_remaining));
	}

	/* s3 had this with #if 0 previously. To be sure the merge
	   doesn't change any behaviour, we have the above #if check
	   on _SAMBA_BUILD_. */
	if (access_desired & SEC_FLAG_SYSTEM_SECURITY) {
		if (security_token_has_privilege(token, SEC_PRIV_SECURITY)) {
			bits_remaining &= ~SEC_FLAG_SYSTEM_SECURITY;
		} else {
			return NT_STATUS_PRIVILEGE_NOT_HELD;
		}
	}

	/* the owner always gets SEC_STD_WRITE_DAC and SEC_STD_READ_CONTROL */
	if ((bits_remaining & (SEC_STD_WRITE_DAC|SEC_STD_READ_CONTROL)) &&
	    security_token_has_sid(token, sd->owner_sid)) {
		bits_remaining &= ~(SEC_STD_WRITE_DAC|SEC_STD_READ_CONTROL);
	}

	/* TODO: remove this, as it is file server specific */
	if ((bits_remaining & SEC_RIGHTS_PRIV_RESTORE) &&
	    security_token_has_privilege(token, SEC_PRIV_RESTORE)) {
		bits_remaining &= ~(SEC_RIGHTS_PRIV_RESTORE);
	}
	if ((bits_remaining & SEC_RIGHTS_PRIV_BACKUP) &&
	    security_token_has_privilege(token, SEC_PRIV_BACKUP)) {
		bits_remaining &= ~(SEC_RIGHTS_PRIV_BACKUP);
	}

	/* a NULL dacl allows access */
	if ((sd->type & SEC_DESC_DACL_PRESENT) && sd->dacl == NULL) {
		*access_granted = access_desired;
		return NT_STATUS_OK;
	}

	if (sd->dacl == NULL) {
		goto done;
	}

	/* check each ace in turn. */
	for (i=0; bits_remaining && i < sd->dacl->num_aces; i++) {
		struct security_ace *ace = &sd->dacl->aces[i];

		if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
			continue;
		}

		if (!security_token_has_sid(token, &ace->trustee)) {
			continue;
		}

		switch (ace->type) {
		case SEC_ACE_TYPE_ACCESS_ALLOWED:
			bits_remaining &= ~ace->access_mask;
			break;
		case SEC_ACE_TYPE_ACCESS_DENIED:
		case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT:
			if (bits_remaining & ace->access_mask) {
				return NT_STATUS_ACCESS_DENIED;
			}
			break;
		default:	/* Other ACE types not handled/supported */
			break;
		}
	}

done:
	if (bits_remaining != 0) {
		*access_granted = bits_remaining;
		return NT_STATUS_ACCESS_DENIED;
	}

	return NT_STATUS_OK;
}