Implement NtAccessCheck.
diff --git a/dlls/ntdll/sec.c b/dlls/ntdll/sec.c
index f986367..b85c0c8 100644
--- a/dlls/ntdll/sec.c
+++ b/dlls/ntdll/sec.c
@@ -1153,23 +1153,85 @@
/******************************************************************************
* 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;
}
/******************************************************************************
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index 707ecd6..ddad000 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -3331,6 +3331,25 @@
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 @@
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 @@
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 @@
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 */
diff --git a/server/protocol.def b/server/protocol.def
index 2dd38c6..bbf2213 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -2344,6 +2344,20 @@
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)
diff --git a/server/request.h b/server/request.h
index 29b53a0..8172cdb 100644
--- a/server/request.h
+++ b/server/request.h
@@ -292,6 +292,7 @@
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 @@
(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,
diff --git a/server/token.c b/server/token.c
index 1b94ec4..05c1af7 100644
--- a/server/token.c
+++ b/server/token.c
@@ -61,6 +61,7 @@
{
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 @@
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 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 @@
!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 @@
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 @@
{
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 @@
release_object( token );
return NULL;
}
+
+ /* FIXME: copy groups */
+
/* copy privileges */
for (i = 0; i < priv_count; i++)
{
@@ -328,6 +513,202 @@
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 @@
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 );
+ }
+}
diff --git a/server/trace.c b/server/trace.c
index 912d4f9..a4bc23d 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -2872,6 +2872,27 @@
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 @@
(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 @@
(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 @@
"get_token_privileges",
"check_token_privileges",
"duplicate_token",
+ "access_check",
"create_mailslot",
"open_mailslot",
"set_mailslot_info",