Implement NtAccessCheck.
This commit is contained in:
parent
3889d950bc
commit
4ad93416a8
|
@ -1153,23 +1153,85 @@ RtlImpersonateSelf(SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
|
|||
/******************************************************************************
|
||||
* NtAccessCheck [NTDLL.@]
|
||||
* ZwAccessCheck [NTDLL.@]
|
||||
*
|
||||
* Checks that a user represented by a token is allowed to access an object
|
||||
* represented by a security descriptor.
|
||||
*
|
||||
* PARAMS
|
||||
* SecurityDescriptor [I] The security descriptor of the object to check.
|
||||
* ClientToken [I] Token of the user accessing the object.
|
||||
* DesiredAccess [I] The desired access to the object.
|
||||
* GenericMapping [I] Mapping used to transform access rights in the SD to their specific forms.
|
||||
* PrivilegeSet [I/O] Privileges used during the access check.
|
||||
* ReturnLength [O] Number of bytes stored into PrivilegeSet.
|
||||
* GrantedAccess [O] The actual access rights granted.
|
||||
* AccessStatus [O] The status of the access check.
|
||||
*
|
||||
* RETURNS
|
||||
* NTSTATUS code.
|
||||
*
|
||||
* NOTES
|
||||
* DesiredAccess may be MAXIMUM_ALLOWED, in which case the function determines
|
||||
* the maximum access rights allowed by the SD and returns them in
|
||||
* GrantedAccess.
|
||||
* The SecurityDescriptor must have a valid owner and groups present,
|
||||
* otherwise the function will fail.
|
||||
*/
|
||||
NTSTATUS WINAPI
|
||||
NtAccessCheck(
|
||||
IN PSECURITY_DESCRIPTOR SecurityDescriptor,
|
||||
IN HANDLE ClientToken,
|
||||
IN ACCESS_MASK DesiredAccess,
|
||||
IN PGENERIC_MAPPING GenericMapping,
|
||||
OUT PPRIVILEGE_SET PrivilegeSet,
|
||||
OUT PULONG ReturnLength,
|
||||
OUT PULONG GrantedAccess,
|
||||
OUT NTSTATUS *AccessStatus)
|
||||
PSECURITY_DESCRIPTOR SecurityDescriptor,
|
||||
HANDLE ClientToken,
|
||||
ACCESS_MASK DesiredAccess,
|
||||
PGENERIC_MAPPING GenericMapping,
|
||||
PPRIVILEGE_SET PrivilegeSet,
|
||||
PULONG ReturnLength,
|
||||
PULONG GrantedAccess,
|
||||
NTSTATUS *AccessStatus)
|
||||
{
|
||||
FIXME("(%p, %p, %08lx, %p, %p, %p, %p, %p), stub\n",
|
||||
SecurityDescriptor, ClientToken, DesiredAccess, GenericMapping,
|
||||
PrivilegeSet, ReturnLength, GrantedAccess, AccessStatus);
|
||||
*AccessStatus = STATUS_SUCCESS;
|
||||
return STATUS_SUCCESS;
|
||||
NTSTATUS status;
|
||||
|
||||
TRACE("(%p, %p, %08lx, %p, %p, %p, %p, %p), stub\n",
|
||||
SecurityDescriptor, ClientToken, DesiredAccess, GenericMapping,
|
||||
PrivilegeSet, ReturnLength, GrantedAccess, AccessStatus);
|
||||
|
||||
SERVER_START_REQ( access_check )
|
||||
{
|
||||
struct security_descriptor sd;
|
||||
const SECURITY_DESCRIPTOR * RealSD = (const SECURITY_DESCRIPTOR *)SecurityDescriptor;
|
||||
|
||||
req->handle = ClientToken;
|
||||
req->desired_access = DesiredAccess;
|
||||
req->mapping_read = GenericMapping->GenericRead;
|
||||
req->mapping_write = GenericMapping->GenericWrite;
|
||||
req->mapping_execute = GenericMapping->GenericExecute;
|
||||
req->mapping_all = GenericMapping->GenericAll;
|
||||
|
||||
/* marshal security descriptor */
|
||||
sd.control = RealSD->Control;
|
||||
sd.owner_len = RtlLengthSid( RealSD->Owner );
|
||||
sd.group_len = RtlLengthSid( RealSD->Group );
|
||||
sd.sacl_len = (RealSD->Sacl ? RealSD->Sacl->AclSize : 0);
|
||||
sd.dacl_len = (RealSD->Dacl ? RealSD->Dacl->AclSize : 0);
|
||||
wine_server_add_data( req, &sd, sizeof(sd) );
|
||||
wine_server_add_data( req, RealSD->Owner, sd.owner_len );
|
||||
wine_server_add_data( req, RealSD->Group, sd.group_len );
|
||||
wine_server_add_data( req, RealSD->Sacl, sd.sacl_len );
|
||||
wine_server_add_data( req, RealSD->Dacl, sd.dacl_len );
|
||||
|
||||
wine_server_set_reply( req, &PrivilegeSet->Privilege, *ReturnLength - FIELD_OFFSET( PRIVILEGE_SET, Privilege ) );
|
||||
|
||||
status = wine_server_call( req );
|
||||
|
||||
*ReturnLength = FIELD_OFFSET( PRIVILEGE_SET, Privilege ) + reply->privileges_len;
|
||||
PrivilegeSet->PrivilegeCount = reply->privileges_len / sizeof(LUID_AND_ATTRIBUTES);
|
||||
|
||||
if (status == STATUS_SUCCESS)
|
||||
*AccessStatus = reply->access_status;
|
||||
*GrantedAccess = reply->access_granted;
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
|
|
|
@ -3331,6 +3331,25 @@ struct duplicate_token_reply
|
|||
obj_handle_t new_handle;
|
||||
};
|
||||
|
||||
struct access_check_request
|
||||
{
|
||||
struct request_header __header;
|
||||
obj_handle_t handle;
|
||||
unsigned int desired_access;
|
||||
unsigned int mapping_read;
|
||||
unsigned int mapping_write;
|
||||
unsigned int mapping_execute;
|
||||
unsigned int mapping_all;
|
||||
/* VARARG(sd,security_descriptor); */
|
||||
};
|
||||
struct access_check_reply
|
||||
{
|
||||
struct reply_header __header;
|
||||
unsigned int access_granted;
|
||||
unsigned int access_status;
|
||||
unsigned int privileges_len;
|
||||
/* VARARG(privileges,LUID_AND_ATTRIBUTES); */
|
||||
};
|
||||
|
||||
|
||||
struct create_mailslot_request
|
||||
|
@ -3574,6 +3593,7 @@ enum request
|
|||
REQ_get_token_privileges,
|
||||
REQ_check_token_privileges,
|
||||
REQ_duplicate_token,
|
||||
REQ_access_check,
|
||||
REQ_create_mailslot,
|
||||
REQ_open_mailslot,
|
||||
REQ_set_mailslot_info,
|
||||
|
@ -3773,6 +3793,7 @@ union generic_request
|
|||
struct get_token_privileges_request get_token_privileges_request;
|
||||
struct check_token_privileges_request check_token_privileges_request;
|
||||
struct duplicate_token_request duplicate_token_request;
|
||||
struct access_check_request access_check_request;
|
||||
struct create_mailslot_request create_mailslot_request;
|
||||
struct open_mailslot_request open_mailslot_request;
|
||||
struct set_mailslot_info_request set_mailslot_info_request;
|
||||
|
@ -3970,11 +3991,12 @@ union generic_reply
|
|||
struct get_token_privileges_reply get_token_privileges_reply;
|
||||
struct check_token_privileges_reply check_token_privileges_reply;
|
||||
struct duplicate_token_reply duplicate_token_reply;
|
||||
struct access_check_reply access_check_reply;
|
||||
struct create_mailslot_reply create_mailslot_reply;
|
||||
struct open_mailslot_reply open_mailslot_reply;
|
||||
struct set_mailslot_info_reply set_mailslot_info_reply;
|
||||
};
|
||||
|
||||
#define SERVER_PROTOCOL_VERSION 175
|
||||
#define SERVER_PROTOCOL_VERSION 176
|
||||
|
||||
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
|
||||
|
|
|
@ -2344,6 +2344,20 @@ enum message_type
|
|||
obj_handle_t new_handle; /* duplicated handle */
|
||||
@END
|
||||
|
||||
@REQ(access_check)
|
||||
obj_handle_t handle; /* handle to the token */
|
||||
unsigned int desired_access; /* desired access to the object */
|
||||
unsigned int mapping_read; /* mapping from generic read to specific rights */
|
||||
unsigned int mapping_write; /* mapping from generic write to specific rights */
|
||||
unsigned int mapping_execute; /* mapping from generic execute to specific rights */
|
||||
unsigned int mapping_all; /* mapping from generic all to specific rights */
|
||||
VARARG(sd,security_descriptor); /* security descriptor to check */
|
||||
@REPLY
|
||||
unsigned int access_granted; /* access rights actually granted */
|
||||
unsigned int access_status; /* was access granted? */
|
||||
unsigned int privileges_len; /* length needed to store privileges */
|
||||
VARARG(privileges,LUID_AND_ATTRIBUTES); /* privileges used during access check */
|
||||
@END
|
||||
|
||||
/* Create a mailslot */
|
||||
@REQ(create_mailslot)
|
||||
|
|
|
@ -292,6 +292,7 @@ DECL_HANDLER(adjust_token_privileges);
|
|||
DECL_HANDLER(get_token_privileges);
|
||||
DECL_HANDLER(check_token_privileges);
|
||||
DECL_HANDLER(duplicate_token);
|
||||
DECL_HANDLER(access_check);
|
||||
DECL_HANDLER(create_mailslot);
|
||||
DECL_HANDLER(open_mailslot);
|
||||
DECL_HANDLER(set_mailslot_info);
|
||||
|
@ -490,6 +491,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
|
|||
(req_handler)req_get_token_privileges,
|
||||
(req_handler)req_check_token_privileges,
|
||||
(req_handler)req_duplicate_token,
|
||||
(req_handler)req_access_check,
|
||||
(req_handler)req_create_mailslot,
|
||||
(req_handler)req_open_mailslot,
|
||||
(req_handler)req_set_mailslot_info,
|
||||
|
|
433
server/token.c
433
server/token.c
|
@ -61,6 +61,7 @@ struct token
|
|||
{
|
||||
struct object obj; /* object header */
|
||||
struct list privileges; /* privileges available to the token */
|
||||
struct list groups; /* groups that the user of this token belongs to (sid_and_attributes) */
|
||||
SID *user; /* SID of user this token represents */
|
||||
};
|
||||
|
||||
|
@ -72,6 +73,19 @@ struct privilege
|
|||
unsigned def : 1; /* is the privilege enabled by default? */
|
||||
};
|
||||
|
||||
struct sid_and_attributes
|
||||
{
|
||||
struct list entry;
|
||||
int enabled : 1; /* is the sid currently enabled? */
|
||||
int def : 1; /* is the sid enabled by default? */
|
||||
int logon : 1; /* is this a logon sid? */
|
||||
int mandatory: 1; /* is this sid always enabled? */
|
||||
int owner : 1; /* can this sid be an owner of an object? */
|
||||
int resource : 1; /* is this a domain-local group? */
|
||||
int deny_only: 1; /* is this a sid that should be use for denying only? */
|
||||
SID sid;
|
||||
};
|
||||
|
||||
static void token_dump( struct object *obj, int verbose );
|
||||
static void token_destroy( struct object *obj );
|
||||
|
||||
|
@ -92,6 +106,7 @@ static const struct object_ops token_ops =
|
|||
static void token_dump( struct object *obj, int verbose )
|
||||
{
|
||||
fprintf( stderr, "Security token\n" );
|
||||
/* FIXME: dump token members */
|
||||
}
|
||||
|
||||
static SID *security_sid_alloc( const SID_IDENTIFIER_AUTHORITY *idauthority, int subauthcount, const unsigned int subauth[] )
|
||||
|
@ -113,6 +128,165 @@ static inline int security_equal_sid( const SID *sid1, const SID *sid2 )
|
|||
!memcmp( sid1, sid2, FIELD_OFFSET(SID, SubAuthority[sid1->SubAuthorityCount]) ));
|
||||
}
|
||||
|
||||
static const ACE_HEADER *ace_next( const ACE_HEADER *ace )
|
||||
{
|
||||
return (const ACE_HEADER *)((const char *)ace + ace->AceSize);
|
||||
}
|
||||
|
||||
static int acl_is_valid( const ACL *acl, size_t size )
|
||||
{
|
||||
ULONG i;
|
||||
const ACE_HEADER *ace;
|
||||
|
||||
if (size < sizeof(ACL))
|
||||
return FALSE;
|
||||
|
||||
size = min(size, MAX_ACL_LEN);
|
||||
|
||||
size -= sizeof(ACL);
|
||||
|
||||
ace = (const ACE_HEADER *)(acl + 1);
|
||||
for (i = 0; i < acl->AceCount; i++)
|
||||
{
|
||||
const SID *sid;
|
||||
|
||||
if (size < sizeof(ACE_HEADER))
|
||||
return FALSE;
|
||||
if (size < ace->AceSize)
|
||||
return FALSE;
|
||||
size -= ace->AceSize;
|
||||
switch (ace->AceType)
|
||||
{
|
||||
case ACCESS_DENIED_ACE_TYPE:
|
||||
sid = (const SID *)&((const ACCESS_DENIED_ACE *)ace)->SidStart;
|
||||
break;
|
||||
case ACCESS_ALLOWED_ACE_TYPE:
|
||||
sid = (const SID *)&((const ACCESS_ALLOWED_ACE *)ace)->SidStart;
|
||||
break;
|
||||
case SYSTEM_AUDIT_ACE_TYPE:
|
||||
sid = (const SID *)&((const SYSTEM_AUDIT_ACE *)ace)->SidStart;
|
||||
break;
|
||||
case SYSTEM_ALARM_ACE_TYPE:
|
||||
sid = (const SID *)&((const SYSTEM_ALARM_ACE *)ace)->SidStart;
|
||||
break;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
if (size < sizeof(SID) ||
|
||||
size < FIELD_OFFSET(SID, SubAuthority[sid->SubAuthorityCount]))
|
||||
return FALSE;
|
||||
ace = ace_next( ace );
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* gets the discretionary access control list from a security descriptor */
|
||||
static inline const ACL *sd_get_dacl( const struct security_descriptor *sd, int *present )
|
||||
{
|
||||
*present = (sd->control & SE_DACL_PRESENT ? TRUE : FALSE);
|
||||
|
||||
if (sd->dacl_len)
|
||||
return (const ACL *)((const char *)(sd + 1) +
|
||||
sd->owner_len + sd->group_len + sd->sacl_len);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* gets the system access control list from a security descriptor */
|
||||
static inline const ACL *sd_get_sacl( const struct security_descriptor *sd, int *present )
|
||||
{
|
||||
*present = (sd->control & SE_SACL_PRESENT ? TRUE : FALSE);
|
||||
|
||||
if (sd->sacl_len)
|
||||
return (const ACL *)((const char *)(sd + 1) +
|
||||
sd->owner_len + sd->group_len);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* gets the owner from a security descriptor */
|
||||
static inline const SID *sd_get_owner( const struct security_descriptor *sd )
|
||||
{
|
||||
if (sd->owner_len)
|
||||
return (const SID *)(sd + 1);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* gets the primary group from a security descriptor */
|
||||
static inline const SID *sd_get_group( const struct security_descriptor *sd )
|
||||
{
|
||||
if (sd->group_len)
|
||||
return (const SID *)((const char *)(sd + 1) + sd->owner_len);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* checks whether all members of a security descriptor fit inside the size
|
||||
* of memory specified */
|
||||
static int sd_is_valid( const struct security_descriptor *sd, size_t size )
|
||||
{
|
||||
size_t offset = sizeof(struct security_descriptor);
|
||||
const SID *group;
|
||||
const SID *owner;
|
||||
const ACL *sacl;
|
||||
const ACL *dacl;
|
||||
int dummy;
|
||||
|
||||
if (size < offset)
|
||||
return FALSE;
|
||||
|
||||
if ((sd->owner_len >= FIELD_OFFSET(SID, SubAuthority[255])) ||
|
||||
(offset + sd->owner_len > size))
|
||||
return FALSE;
|
||||
owner = sd_get_owner( sd );
|
||||
if (owner)
|
||||
{
|
||||
size_t needed_size = FIELD_OFFSET(SID, SubAuthority[owner->SubAuthorityCount]);
|
||||
if ((sd->owner_len < sizeof(SID)) || (needed_size > sd->owner_len))
|
||||
return FALSE;
|
||||
}
|
||||
offset += sd->owner_len;
|
||||
|
||||
if ((sd->group_len >= FIELD_OFFSET(SID, SubAuthority[255])) ||
|
||||
(offset + sd->group_len > size))
|
||||
return FALSE;
|
||||
group = sd_get_group( sd );
|
||||
if (group)
|
||||
{
|
||||
size_t needed_size = FIELD_OFFSET(SID, SubAuthority[group->SubAuthorityCount]);
|
||||
if ((sd->owner_len < sizeof(SID)) || (needed_size > sd->owner_len))
|
||||
return FALSE;
|
||||
}
|
||||
offset += sd->group_len;
|
||||
|
||||
if ((sd->sacl_len >= MAX_ACL_LEN) || (offset + sd->sacl_len > size))
|
||||
return FALSE;
|
||||
sacl = sd_get_sacl( sd, &dummy );
|
||||
if (sacl && !acl_is_valid( sacl, sd->sacl_len ))
|
||||
return FALSE;
|
||||
offset += sd->sacl_len;
|
||||
|
||||
if ((sd->dacl_len >= MAX_ACL_LEN) || (offset + sd->dacl_len > size))
|
||||
return FALSE;
|
||||
dacl = sd_get_dacl( sd, &dummy );
|
||||
if (dacl && !acl_is_valid( dacl, sd->dacl_len ))
|
||||
return FALSE;
|
||||
offset += sd->dacl_len;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* maps from generic rights to specific rights as given by a mapping */
|
||||
static inline void map_generic_mask(unsigned int *mask, const GENERIC_MAPPING *mapping)
|
||||
{
|
||||
if (*mask & GENERIC_READ) *mask |= mapping->GenericRead;
|
||||
if (*mask & GENERIC_WRITE) *mask |= mapping->GenericWrite;
|
||||
if (*mask & GENERIC_EXECUTE) *mask |= mapping->GenericExecute;
|
||||
if (*mask & GENERIC_ALL) *mask |= mapping->GenericAll;
|
||||
*mask &= 0x0FFFFFFF;
|
||||
}
|
||||
|
||||
static inline int is_equal_luid( const LUID *luid1, const LUID *luid2 )
|
||||
{
|
||||
return (luid1->LowPart == luid2->LowPart && luid1->HighPart == luid2->HighPart);
|
||||
|
@ -159,6 +333,13 @@ static void token_destroy( struct object *obj )
|
|||
struct privilege *privilege = LIST_ENTRY( cursor, struct privilege, entry );
|
||||
privilege_remove( privilege );
|
||||
}
|
||||
|
||||
LIST_FOR_EACH_SAFE( cursor, cursor_next, &token->groups )
|
||||
{
|
||||
struct sid_and_attributes *group = LIST_ENTRY( cursor, struct sid_and_attributes, entry );
|
||||
list_remove( &group->entry );
|
||||
free( group );
|
||||
}
|
||||
}
|
||||
|
||||
static struct token *create_token( const SID *user, const LUID_AND_ATTRIBUTES *privs, unsigned int priv_count )
|
||||
|
@ -168,6 +349,7 @@ static struct token *create_token( const SID *user, const LUID_AND_ATTRIBUTES *p
|
|||
{
|
||||
int i;
|
||||
list_init( &token->privileges );
|
||||
list_init( &token->groups );
|
||||
/* copy user */
|
||||
token->user = memdup( user, FIELD_OFFSET(SID, SubAuthority[user->SubAuthorityCount]) );
|
||||
if (!token->user)
|
||||
|
@ -175,6 +357,9 @@ static struct token *create_token( const SID *user, const LUID_AND_ATTRIBUTES *p
|
|||
release_object( token );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* FIXME: copy groups */
|
||||
|
||||
/* copy privileges */
|
||||
for (i = 0; i < priv_count; i++)
|
||||
{
|
||||
|
@ -328,6 +513,202 @@ int token_check_privileges( struct token *token, int all_required,
|
|||
return (enabled_count > 0);
|
||||
}
|
||||
|
||||
static int token_sid_present( struct token *token, const SID *sid, int deny )
|
||||
{
|
||||
struct sid_and_attributes *group;
|
||||
|
||||
if (security_equal_sid( token->user, sid )) return TRUE;
|
||||
|
||||
LIST_FOR_EACH_ENTRY( group, &token->groups, struct sid_and_attributes, entry )
|
||||
{
|
||||
if (!group->enabled) continue;
|
||||
if (group->deny_only && !deny) continue;
|
||||
|
||||
if (security_equal_sid( &group->sid, sid )) return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* checks access to a security descriptor. sd must have been validated by caller.
|
||||
* it returns STATUS_SUCCESS if access was granted to the object, or an error
|
||||
* status code if not, giving the reason. errors not relating to giving access
|
||||
* to the object are returned in the status parameter. granted_access and
|
||||
* status always have a valid value stored in them on return. */
|
||||
static unsigned int token_access_check( struct token *token,
|
||||
const struct security_descriptor *sd,
|
||||
unsigned int desired_access,
|
||||
LUID_AND_ATTRIBUTES *privs,
|
||||
unsigned int *priv_count,
|
||||
const GENERIC_MAPPING *mapping,
|
||||
unsigned int *granted_access,
|
||||
unsigned int *status )
|
||||
{
|
||||
unsigned int current_access = 0;
|
||||
unsigned int denied_access = 0;
|
||||
ULONG i;
|
||||
const ACL *dacl;
|
||||
int dacl_present;
|
||||
const ACE_HEADER *ace;
|
||||
const SID *owner;
|
||||
|
||||
/* assume success, but no access rights */
|
||||
*status = STATUS_SUCCESS;
|
||||
*granted_access = 0;
|
||||
|
||||
/* fail if desired_access contains generic rights */
|
||||
if (desired_access & (GENERIC_READ|GENERIC_WRITE|GENERIC_EXECUTE|GENERIC_ALL))
|
||||
{
|
||||
*priv_count = 0;
|
||||
*status = STATUS_GENERIC_NOT_MAPPED;
|
||||
return STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
dacl = sd_get_dacl( sd, &dacl_present );
|
||||
owner = sd_get_owner( sd );
|
||||
if (!owner || !sd_get_group( sd ))
|
||||
{
|
||||
*priv_count = 0;
|
||||
*status = STATUS_INVALID_SECURITY_DESCR;
|
||||
return STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
/* 1: Grant desired access if the object is unprotected */
|
||||
if (!dacl_present)
|
||||
{
|
||||
*priv_count = 0;
|
||||
*granted_access = desired_access;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
if (!dacl)
|
||||
{
|
||||
*priv_count = 0;
|
||||
return STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
/* 2: Check if caller wants access to system security part. Note: access
|
||||
* is only granted if specifically asked for */
|
||||
if (desired_access & ACCESS_SYSTEM_SECURITY)
|
||||
{
|
||||
const LUID_AND_ATTRIBUTES security_priv = { SeSecurityPrivilege, 0 };
|
||||
LUID_AND_ATTRIBUTES retpriv = security_priv;
|
||||
if (token_check_privileges( token, TRUE, &security_priv, 1, &retpriv ))
|
||||
{
|
||||
if (priv_count)
|
||||
{
|
||||
/* assumes that there will only be one privilege to return */
|
||||
if (*priv_count >= 1)
|
||||
{
|
||||
*priv_count = 1;
|
||||
*privs = retpriv;
|
||||
}
|
||||
else
|
||||
{
|
||||
*priv_count = 1;
|
||||
return STATUS_BUFFER_TOO_SMALL;
|
||||
}
|
||||
}
|
||||
current_access |= ACCESS_SYSTEM_SECURITY;
|
||||
if (desired_access == current_access)
|
||||
{
|
||||
*granted_access = current_access;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*priv_count = 0;
|
||||
return STATUS_PRIVILEGE_NOT_HELD;
|
||||
}
|
||||
}
|
||||
else if (priv_count) *priv_count = 0;
|
||||
|
||||
/* 3: Check whether the token is the owner */
|
||||
/* NOTE: SeTakeOwnershipPrivilege is not checked for here - it is instead
|
||||
* checked when a "set owner" call is made, overriding the access rights
|
||||
* determined here. */
|
||||
if (token_sid_present( token, owner, FALSE ))
|
||||
{
|
||||
current_access |= (READ_CONTROL | WRITE_DAC);
|
||||
if (desired_access == current_access)
|
||||
{
|
||||
*granted_access = current_access;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/* 4: Grant rights according to the DACL */
|
||||
ace = (const ACE_HEADER *)(dacl + 1);
|
||||
for (i = 0; i < dacl->AceCount; i++)
|
||||
{
|
||||
const ACCESS_ALLOWED_ACE *aa_ace;
|
||||
const ACCESS_DENIED_ACE *ad_ace;
|
||||
const SID *sid;
|
||||
switch (ace->AceType)
|
||||
{
|
||||
case ACCESS_DENIED_ACE_TYPE:
|
||||
ad_ace = (const ACCESS_DENIED_ACE *)ace;
|
||||
sid = (const SID *)&ad_ace->SidStart;
|
||||
if (token_sid_present( token, sid, TRUE ))
|
||||
{
|
||||
unsigned int access = ad_ace->Mask;
|
||||
map_generic_mask(&access, mapping);
|
||||
if (desired_access & MAXIMUM_ALLOWED)
|
||||
denied_access |= access;
|
||||
else
|
||||
{
|
||||
denied_access |= (access & ~current_access);
|
||||
if (desired_access & access)
|
||||
{
|
||||
*granted_access = 0;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ACCESS_ALLOWED_ACE_TYPE:
|
||||
aa_ace = (const ACCESS_ALLOWED_ACE *)ace;
|
||||
sid = (const SID *)&aa_ace->SidStart;
|
||||
if (token_sid_present( token, sid, FALSE ))
|
||||
{
|
||||
unsigned int access = aa_ace->Mask;
|
||||
map_generic_mask(&access, mapping);
|
||||
if (desired_access & MAXIMUM_ALLOWED)
|
||||
current_access |= access;
|
||||
else
|
||||
current_access |= (access & ~denied_access);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* don't bother carrying on checking if we've already got all of
|
||||
* rights we need */
|
||||
if (desired_access == *granted_access)
|
||||
break;
|
||||
|
||||
ace = ace_next( ace );
|
||||
}
|
||||
|
||||
if (desired_access & MAXIMUM_ALLOWED)
|
||||
{
|
||||
*granted_access = current_access & ~denied_access;
|
||||
if (*granted_access)
|
||||
return STATUS_SUCCESS;
|
||||
else
|
||||
return STATUS_ACCESS_DENIED;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((current_access & desired_access) == desired_access)
|
||||
{
|
||||
*granted_access = current_access & desired_access;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
else
|
||||
return STATUS_ACCESS_DENIED;
|
||||
}
|
||||
}
|
||||
|
||||
/* open a security token */
|
||||
DECL_HANDLER(open_token)
|
||||
{
|
||||
|
@ -485,3 +866,55 @@ DECL_HANDLER(check_token_privileges)
|
|||
release_object( token );
|
||||
}
|
||||
}
|
||||
|
||||
/* checks that a user represented by a token is allowed to access an object
|
||||
* represented by a security descriptor */
|
||||
DECL_HANDLER(access_check)
|
||||
{
|
||||
size_t sd_size = get_req_data_size();
|
||||
const struct security_descriptor *sd = get_req_data();
|
||||
struct token *token;
|
||||
|
||||
if (!sd_is_valid( sd, sd_size ))
|
||||
{
|
||||
set_error( STATUS_ACCESS_VIOLATION );
|
||||
return;
|
||||
}
|
||||
|
||||
if ((token = (struct token *)get_handle_obj( current->process, req->handle,
|
||||
TOKEN_QUERY,
|
||||
&token_ops )))
|
||||
{
|
||||
GENERIC_MAPPING mapping;
|
||||
unsigned int status;
|
||||
LUID_AND_ATTRIBUTES priv;
|
||||
unsigned int priv_count = 1;
|
||||
|
||||
memset(&priv, 0, sizeof(priv));
|
||||
|
||||
/* FIXME: check token is an impersonation token, if not return
|
||||
* STATUS_NO_IMPERSONATION_TOKEN */
|
||||
|
||||
mapping.GenericRead = req->mapping_read;
|
||||
mapping.GenericWrite = req->mapping_write;
|
||||
mapping.GenericExecute = req->mapping_execute;
|
||||
mapping.GenericAll = req->mapping_all;
|
||||
|
||||
reply->access_status = token_access_check(
|
||||
token, sd, req->desired_access, &priv, &priv_count, &mapping,
|
||||
&reply->access_granted, &status );
|
||||
|
||||
reply->privileges_len = priv_count*sizeof(LUID_AND_ATTRIBUTES);
|
||||
|
||||
if ((priv_count > 0) && (reply->privileges_len <= get_reply_max_size()))
|
||||
{
|
||||
LUID_AND_ATTRIBUTES *privs = set_reply_data_size( priv_count * sizeof(*privs) );
|
||||
memcpy( privs, &priv, sizeof(priv) );
|
||||
}
|
||||
|
||||
if (status != STATUS_SUCCESS)
|
||||
set_error( status );
|
||||
|
||||
release_object( token );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2872,6 +2872,27 @@ static void dump_duplicate_token_reply( const struct duplicate_token_reply *req
|
|||
fprintf( stderr, " new_handle=%p", req->new_handle );
|
||||
}
|
||||
|
||||
static void dump_access_check_request( const struct access_check_request *req )
|
||||
{
|
||||
fprintf( stderr, " handle=%p,", req->handle );
|
||||
fprintf( stderr, " desired_access=%08x,", req->desired_access );
|
||||
fprintf( stderr, " mapping_read=%08x,", req->mapping_read );
|
||||
fprintf( stderr, " mapping_write=%08x,", req->mapping_write );
|
||||
fprintf( stderr, " mapping_execute=%08x,", req->mapping_execute );
|
||||
fprintf( stderr, " mapping_all=%08x,", req->mapping_all );
|
||||
fprintf( stderr, " sd=" );
|
||||
dump_varargs_security_descriptor( cur_size );
|
||||
}
|
||||
|
||||
static void dump_access_check_reply( const struct access_check_reply *req )
|
||||
{
|
||||
fprintf( stderr, " access_granted=%08x,", req->access_granted );
|
||||
fprintf( stderr, " access_status=%08x,", req->access_status );
|
||||
fprintf( stderr, " privileges_len=%08x,", req->privileges_len );
|
||||
fprintf( stderr, " privileges=" );
|
||||
dump_varargs_LUID_AND_ATTRIBUTES( cur_size );
|
||||
}
|
||||
|
||||
static void dump_create_mailslot_request( const struct create_mailslot_request *req )
|
||||
{
|
||||
fprintf( stderr, " max_msgsize=%08x,", req->max_msgsize );
|
||||
|
@ -3105,6 +3126,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
|
|||
(dump_func)dump_get_token_privileges_request,
|
||||
(dump_func)dump_check_token_privileges_request,
|
||||
(dump_func)dump_duplicate_token_request,
|
||||
(dump_func)dump_access_check_request,
|
||||
(dump_func)dump_create_mailslot_request,
|
||||
(dump_func)dump_open_mailslot_request,
|
||||
(dump_func)dump_set_mailslot_info_request,
|
||||
|
@ -3300,6 +3322,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
|
|||
(dump_func)dump_get_token_privileges_reply,
|
||||
(dump_func)dump_check_token_privileges_reply,
|
||||
(dump_func)dump_duplicate_token_reply,
|
||||
(dump_func)dump_access_check_reply,
|
||||
(dump_func)dump_create_mailslot_reply,
|
||||
(dump_func)dump_open_mailslot_reply,
|
||||
(dump_func)dump_set_mailslot_info_reply,
|
||||
|
@ -3495,6 +3518,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
|
|||
"get_token_privileges",
|
||||
"check_token_privileges",
|
||||
"duplicate_token",
|
||||
"access_check",
|
||||
"create_mailslot",
|
||||
"open_mailslot",
|
||||
"set_mailslot_info",
|
||||
|
|
Loading…
Reference in New Issue