Implement NtAccessCheck.

This commit is contained in:
Robert Shearman 2005-05-24 12:32:18 +00:00 committed by Alexandre Julliard
parent 3889d950bc
commit 4ad93416a8
6 changed files with 571 additions and 14 deletions

View File

@ -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;
}
/******************************************************************************

View File

@ -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 */

View File

@ -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)

View File

@ -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,

View File

@ -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 );
}
}

View File

@ -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",