From 4ad93416a84bfab3bdc76ebd088df0f97c70db32 Mon Sep 17 00:00:00 2001 From: Robert Shearman Date: Tue, 24 May 2005 12:32:18 +0000 Subject: [PATCH] Implement NtAccessCheck. --- dlls/ntdll/sec.c | 88 +++++++-- include/wine/server_protocol.h | 24 ++- server/protocol.def | 14 ++ server/request.h | 2 + server/token.c | 433 +++++++++++++++++++++++++++++++++++++++++ server/trace.c | 24 +++ 6 files changed, 571 insertions(+), 14 deletions(-) diff --git a/dlls/ntdll/sec.c b/dlls/ntdll/sec.c index f98636718f6..b85c0c862ff 100644 --- a/dlls/ntdll/sec.c +++ b/dlls/ntdll/sec.c @@ -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; } /****************************************************************************** diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 707ecd6c6bc..ddad0006897 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -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 */ diff --git a/server/protocol.def b/server/protocol.def index 2dd38c6a79d..bbf2213ed3b 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -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) diff --git a/server/request.h b/server/request.h index 29b53a09a0b..8172cdb60cf 100644 --- a/server/request.h +++ b/server/request.h @@ -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, diff --git a/server/token.c b/server/token.c index 1b94ec46a07..05c1af7382d 100644 --- a/server/token.c +++ b/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 ); + } +} diff --git a/server/trace.c b/server/trace.c index 912d4f98f92..a4bc23d67b3 100644 --- a/server/trace.c +++ b/server/trace.c @@ -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", -- 2.11.4.GIT