windows-nt/Source/XPSP1/NT/mergedcomponents/advapi32/security.c
2020-09-26 16:20:57 +08:00

10195 lines
263 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
security.c
Abstract:
This module implements Object Security APIs for Win32
Author:
Jim Anderson (JimA) 01-Jul-1991
Robert Reichel (RobertRe) 01-Jan-92
Revision History:
--*/
#include "advapi.h"
#include <ntlsa.h>
#include <rpc.h>
#include <rpcndr.h>
#include <stdio.h>
#define LSADEFINED
/////////////////////////////////////////////////////////////////////////////
// //
// Private Routine Prototypes //
// //
/////////////////////////////////////////////////////////////////////////////
VOID
SepFormatAccountSid(
PSID iSid,
LPWSTR OutputBuffer
);
/////////////////////////////////////////////////////////////////////////////
// //
// Exported Routines //
// //
/////////////////////////////////////////////////////////////////////////////
BOOL
APIENTRY
DuplicateToken(
HANDLE ExistingTokenHandle,
SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
PHANDLE DuplicateTokenHandle
)
/*++
Routine Description:
Create a new token that is a duplicate of an existing token. The
new token will be an impersonation token of the supplied level.
Arguments:
ExistingTokenHandle - Is a handle to a token already open for
TOKEN_DUPLICATE access.
ImpersonationLevel - Supplies the impersonation level of the new
token.
DuplicateTokenHandle - Returns the handle to the new token. The
handle will have TOKEN_IMPERSONATE and TOKEN_QUERY access to
the new token.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
return( DuplicateTokenEx( ExistingTokenHandle,
TOKEN_IMPERSONATE | TOKEN_QUERY,
NULL,
ImpersonationLevel,
TokenImpersonation,
DuplicateTokenHandle
) );
}
BOOL
APIENTRY
DuplicateTokenEx(
HANDLE hExistingToken,
DWORD dwDesiredAccess,
LPSECURITY_ATTRIBUTES lpTokenAttributes,
SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
TOKEN_TYPE TokenType,
PHANDLE phNewToken)
/*++
Routine Description:
Create a new token that is a duplicate of an existing token. This API
more fully exposes NtDuplicateToken .
Arguments:
hExistingToken - Is a handle to a token already open for
TOKEN_DUPLICATE access.
dwDesiredAccess - desired access rights to the new token, e.g.
TOKEN_DUPLICATE, TOKEN_IMPERSONATE, etc.
lpTokenAttributes - Desired security attributes for the new token.
ImpersonationLevel - Supplies the impersonation level of the new token.
TokenType - One of TokenImpersonation or TokenPrimary.
phNewToken - Returns the handle to the new token.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
OBJECT_ATTRIBUTES ObjA;
SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
PSECURITY_DESCRIPTOR SecurityDescriptor;
NTSTATUS Status;
ULONG Attributes;
SecurityQualityOfService.Length = sizeof( SECURITY_QUALITY_OF_SERVICE );
SecurityQualityOfService.ImpersonationLevel = ImpersonationLevel;
SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
SecurityQualityOfService.EffectiveOnly = FALSE;
if (lpTokenAttributes)
{
SecurityDescriptor = lpTokenAttributes->lpSecurityDescriptor;
if (lpTokenAttributes->bInheritHandle)
{
Attributes = OBJ_INHERIT;
}
else
{
Attributes = 0;
}
}
else
{
SecurityDescriptor = NULL;
Attributes = 0;
}
InitializeObjectAttributes(
&ObjA,
NULL,
Attributes,
NULL,
SecurityDescriptor
);
ObjA.SecurityQualityOfService = &SecurityQualityOfService;
Status = NtDuplicateToken(
hExistingToken,
dwDesiredAccess,
&ObjA,
FALSE,
TokenType,
phNewToken
);
if ( !NT_SUCCESS( Status ) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return( TRUE );
}
BOOL
APIENTRY
AllocateLocallyUniqueId(
PLUID Luid
)
/*++
Routine Description:
Allocates a locally unique ID (LUID).
Arguments:
Luid - Supplies a pointer used to return the LUID.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{ NTSTATUS Status;
Status = NtAllocateLocallyUniqueId( Luid );
if ( !NT_SUCCESS( Status )) {
BaseSetLastNTError( Status );
return( FALSE );
}
return( TRUE );
}
BOOL
APIENTRY
AccessCheck (
PSECURITY_DESCRIPTOR pSecurityDescriptor,
HANDLE ClientToken,
DWORD DesiredAccess,
PGENERIC_MAPPING GenericMapping,
PPRIVILEGE_SET PrivilegeSet,
LPDWORD PrivilegeSetLength,
LPDWORD GrantedAccess,
LPBOOL AccessStatus
)
/*++
Routine Description:
This routine compares the input Security Descriptor against the
input token and indicates by its return value if access is granted
or denied. If access is granted then the desired access mask
becomes the granted access mask for the object.
The semantics of the access check routine is described in the DSA
Security Architecture workbook. Note that during an access check
only the discretionary ACL is examined.
Arguments:
SecurityDescriptor - Supplies the security descriptor protecting the object
being accessed
ClientToken - Supplies the handle of the user's token.
DesiredAccess - Supplies the desired access mask.
GenericMapping - Supplies the generic mapping associated with this
object type.
PrivilegeSet - A pointer to a buffer that upon return will contain
any privileges that were used to perform the access validation.
If no privileges were used, the buffer will contain a privilege
set consisting of zero privileges.
PrivilegeSetLength - The size of the PrivilegeSet buffer in bytes.
GrantedAccess - Returns an access mask describing the granted access.
AccessStatus - Status value that may be returned indicating the
reason why access was denied. Routines should avoid hardcoding a
return value of STATUS_ACCESS_DENIED so that a different value can
be returned when mandatory access control is implemented.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
NTSTATUS RealStatus;
Status = NtAccessCheck (
pSecurityDescriptor,
ClientToken,
DesiredAccess,
GenericMapping,
PrivilegeSet,
PrivilegeSetLength,
GrantedAccess,
&RealStatus
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
if ( !NT_SUCCESS( RealStatus ) ) {
BaseSetLastNTError( RealStatus );
*AccessStatus = FALSE;
return( TRUE );
}
*AccessStatus = TRUE;
return TRUE;
}
BOOL
APIENTRY
AccessCheckByType (
PSECURITY_DESCRIPTOR pSecurityDescriptor,
PSID PrincipalSelfSid,
HANDLE ClientToken,
DWORD DesiredAccess,
POBJECT_TYPE_LIST ObjectTypeList,
DWORD ObjectTypeListLength,
PGENERIC_MAPPING GenericMapping,
PPRIVILEGE_SET PrivilegeSet,
LPDWORD PrivilegeSetLength,
LPDWORD GrantedAccess,
LPBOOL AccessStatus
)
/*++
Routine Description:
This routine compares the input Security Descriptor against the
input token and indicates by its return value if access is granted
or denied. If access is granted then the desired access mask
becomes the granted access mask for the object.
The semantics of the access check routine is described in the DSA
Security Architecture workbook. Note that during an access check
only the discretionary ACL is examined.
Arguments:
SecurityDescriptor - Supplies the security descriptor protecting the object
being accessed
PrincipalSelfSid - If the object being access checked is an object which
represents a principal (e.g., a user object), this parameter should
be the SID of the object. Any ACE containing the constant
PRINCIPAL_SELF_SID is replaced by this SID.
The parameter should be NULL if the object does not represent a principal.
ClientToken - Supplies the handle of the user's token.
DesiredAccess - Supplies the desired access mask.
ObjectTypeList - Supplies a list of GUIDs representing the object (and
sub-objects) being accessed. If no list is present, AccessCheckByType
behaves identically to AccessCheck.
ObjectTypeListLength - Specifies the number of elements in the ObjectTypeList.
GenericMapping - Supplies the generic mapping associated with this
object type.
PrivilegeSet - A pointer to a buffer that upon return will contain
any privileges that were used to perform the access validation.
If no privileges were used, the buffer will contain a privilege
set consisting of zero privileges.
PrivilegeSetLength - The size of the PrivilegeSet buffer in bytes.
GrantedAccess - Returns an access mask describing the granted access.
AccessStatus - Status value that may be returned indicating the
reason why access was denied. Routines should avoid hardcoding a
return value of STATUS_ACCESS_DENIED so that a different value can
be returned when mandatory access control is implemented.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
NTSTATUS RealStatus;
Status = NtAccessCheckByType (
pSecurityDescriptor,
PrincipalSelfSid,
ClientToken,
DesiredAccess,
ObjectTypeList,
ObjectTypeListLength,
GenericMapping,
PrivilegeSet,
PrivilegeSetLength,
GrantedAccess,
&RealStatus
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
if ( !NT_SUCCESS( RealStatus ) ) {
BaseSetLastNTError( RealStatus );
*AccessStatus = FALSE;
return( TRUE );
}
*AccessStatus = TRUE;
return TRUE;
}
BOOL
APIENTRY
AccessCheckByTypeResultList (
PSECURITY_DESCRIPTOR pSecurityDescriptor,
PSID PrincipalSelfSid,
HANDLE ClientToken,
DWORD DesiredAccess,
POBJECT_TYPE_LIST ObjectTypeList,
DWORD ObjectTypeListLength,
PGENERIC_MAPPING GenericMapping,
PPRIVILEGE_SET PrivilegeSet,
LPDWORD PrivilegeSetLength,
LPDWORD GrantedAccessList,
LPDWORD AccessStatusList
)
/*++
Routine Description:
This routine compares the input Security Descriptor against the
input token and indicates by its return value if access is granted
or denied. If access is granted then the desired access mask
becomes the granted access mask for the object.
The semantics of the access check routine is described in the DSA
Security Architecture workbook. Note that during an access check
only the discretionary ACL is examined.
Arguments:
SecurityDescriptor - Supplies the security descriptor protecting the object
being accessed
PrincipalSelfSid - If the object being access checked is an object which
represents a principal (e.g., a user object), this parameter should
be the SID of the object. Any ACE containing the constant
PRINCIPAL_SELF_SID is replaced by this SID.
The parameter should be NULL if the object does not represent a principal.
ClientToken - Supplies the handle of the user's token.
DesiredAccess - Supplies the desired access mask.
ObjectTypeList - Supplies a list of GUIDs representing the object (and
sub-objects) being accessed. If no list is present, AccessCheckByType
behaves identically to AccessCheck.
ObjectTypeListLength - Specifies the number of elements in the ObjectTypeList.
GenericMapping - Supplies the generic mapping associated with this
object type.
PrivilegeSet - A pointer to a buffer that upon return will contain
any privileges that were used to perform the access validation.
If no privileges were used, the buffer will contain a privilege
set consisting of zero privileges.
PrivilegeSetLength - The size of the PrivilegeSet buffer in bytes.
GrantedAccessList - Returns an access mask describing the granted access.
AccessStatusList - Status value that may be returned indicating the
reason why access was denied. Routines should avoid hardcoding a
return value of STATUS_ACCESS_DENIED so that a different value can
be returned when mandatory access control is implemented.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
NTSTATUS RealStatus;
ULONG i;
ASSERT (sizeof(NTSTATUS) == sizeof(DWORD) );
Status = NtAccessCheckByTypeResultList (
pSecurityDescriptor,
PrincipalSelfSid,
ClientToken,
DesiredAccess,
ObjectTypeList,
ObjectTypeListLength,
GenericMapping,
PrivilegeSet,
PrivilegeSetLength,
GrantedAccessList,
(PNTSTATUS)AccessStatusList
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
//
// Loop converting the array of NT status codes to WIN status codes.
//
for ( i=0; i<ObjectTypeListLength; i++ ) {
if ( AccessStatusList[i] == STATUS_SUCCESS ) {
AccessStatusList[i] = NO_ERROR;
} else {
AccessStatusList[i] = RtlNtStatusToDosError( AccessStatusList[i] );
}
}
return TRUE;
}
BOOL
APIENTRY
OpenProcessToken (
HANDLE ProcessHandle,
DWORD DesiredAccess,
PHANDLE TokenHandle
)
/*++
Routine Description:
Open a token object associated with a process and return a handle
that may be used to access that token.
Arguments:
ProcessHandle - Specifies the process whose token is to be
opened.
DesiredAccess - Is an access mask indicating which access types
are desired to the token. These access types are reconciled
with the Discretionary Access Control list of the token to
determine whether the accesses will be granted or denied.
TokenHandle - Receives the handle of the newly opened token.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = NtOpenProcessToken (
ProcessHandle,
DesiredAccess,
TokenHandle
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
OpenThreadToken (
HANDLE ThreadHandle,
DWORD DesiredAccess,
BOOL OpenAsSelf,
PHANDLE TokenHandle
)
/*++
Routine Description:
Open a token object associated with a thread and return a handle that
may be used to access that token.
Arguments:
ThreadHandle - Specifies the thread whose token is to be opened.
DesiredAccess - Is an access mask indicating which access types
are desired to the token. These access types are reconciled
with the Discretionary Access Control list of the token to
determine whether the accesses will be granted or denied.
OpenAsSelf - Is a boolean value indicating whether the access should
be made using the calling thread's current security context, which
may be that of a client if impersonating, or using the caller's
process-level security context. A value of FALSE indicates the
caller's current context should be used un-modified. A value of
TRUE indicates the request should be fulfilled using the process
level security context.
This parameter is necessary to allow a server process to open
a client's token when the client specified IDENTIFICATION level
impersonation. In this case, the caller would not be able to
open the client's token using the client's context (because you
can't create executive level objects using IDENTIFICATION level
impersonation).
TokenHandle - Receives the handle of the newly opened token.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = NtOpenThreadToken (
ThreadHandle,
DesiredAccess,
(BOOLEAN)OpenAsSelf,
TokenHandle
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
GetTokenInformation (
HANDLE TokenHandle,
TOKEN_INFORMATION_CLASS TokenInformationClass,
PVOID TokenInformation,
DWORD TokenInformationLength,
PDWORD ReturnLength
)
/*++
Routine Description:
Retrieve information about a specified token.
Arguments:
TokenHandle - Provides a handle to the token to operate on.
TokenInformationClass - The token information class about which
to retrieve information.
TokenInformation - The buffer to receive the requested class of
information. The buffer must be aligned on at least a
longword boundary. The actual structures returned are
dependent upon the information class requested, as defined in
the TokenInformationClass parameter description.
TokenInformation Format By Information Class:
TokenUser => TOKEN_USER data structure. TOKEN_QUERY
access is needed to retrieve this information about a
token.
TokenGroups => TOKEN_GROUPS data structure. TOKEN_QUERY
access is needed to retrieve this information about a
token.
TokenPrivileges => TOKEN_PRIVILEGES data structure.
TOKEN_QUERY access is needed to retrieve this information
about a token.
TokenOwner => TOKEN_OWNER data structure. TOKEN_QUERY
access is needed to retrieve this information about a
token.
TokenPrimaryGroup => TOKEN_PRIMARY_GROUP data structure.
TOKEN_QUERY access is needed to retrieve this information
about a token.
TokenDefaultDacl => TOKEN_DEFAULT_DACL data structure.
TOKEN_QUERY access is needed to retrieve this information
about a token.
TokenSource => TOKEN_SOURCE data structure.
TOKEN_QUERY_SOURCE access is needed to retrieve this
information about a token.
TokenType => TOKEN_TYPE data structure.
TOKEN_QUERY access is needed to retrieve this information
about a token.
TokenStatistics => TOKEN_STATISTICS data structure.
TOKEN_QUERY access is needed to retrieve this
information about a token.
TokenInformationLength - Indicates the length, in bytes, of the
TokenInformation buffer.
ReturnLength - This parameter receives the actual length of the
requested information. If this value is larger than that
provided by the TokenInformationLength parameter, then the
buffer provided to receive the requested information is not
large enough to hold that data and no data is returned.
If the queried class is TokenDefaultDacl and there is no
default Dacl established for the token, then the return
length will be returned as zero, and no data will be returned.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = NtQueryInformationToken (
TokenHandle,
TokenInformationClass,
TokenInformation,
TokenInformationLength,
ReturnLength
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
SetTokenInformation (
HANDLE TokenHandle,
TOKEN_INFORMATION_CLASS TokenInformationClass,
PVOID TokenInformation,
DWORD TokenInformationLength
)
/*++
Routine Description:
Modify information in a specified token.
Arguments:
TokenHandle - Provides a handle to the token to operate on.
TokenInformationClass - The token information class being set.
TokenInformation - The buffer containing the new values for the
specified class of information. The buffer must be aligned
on at least a longword boundary. The actual structures
provided are dependent upon the information class specified,
as defined in the TokenInformationClass parameter
description.
TokenInformation Format By Information Class:
TokenUser => This value is not a valid value for this API.
The User ID may not be replaced.
TokenGroups => This value is not a valid value for this
API. The Group IDs may not be replaced. However, groups
may be enabled and disabled using NtAdjustGroupsToken().
TokenPrivileges => This value is not a valid value for
this API. Privilege information may not be replaced.
However, privileges may be explicitly enabled and disabled
using the NtAdjustPrivilegesToken API.
TokenOwner => TOKEN_OWNER data structure.
TOKEN_ADJUST_DEFAULT access is needed to replace this
information in a token. The owner values that may be
specified are restricted to the user and group IDs with an
attribute indicating they may be assigned as the owner of
objects.
TokenPrimaryGroup => TOKEN_PRIMARY_GROUP data structure.
TOKEN_ADJUST_DEFAULT access is needed to replace this
information in a token. The primary group values that may
be specified are restricted to be one of the group IDs
already in the token.
TokenDefaultDacl => TOKEN_DEFAULT_DACL data structure.
TOKEN_ADJUST_DEFAULT access is needed to replace this
information in a token. The ACL provided as a new default
discretionary ACL is not validated for structural
correctness or consistency.
TokenSource => This value is not a valid value for this
API. The source name and context handle may not be
replaced.
TokenStatistics => This value is not a valid value for this
API. The statistics of a token are read-only.
TokenInformationLength - Indicates the length, in bytes, of the
TokenInformation buffer. This is only the length of the primary
buffer. All extensions of the primary buffer are self describing.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = NtSetInformationToken (
TokenHandle,
TokenInformationClass,
TokenInformation,
TokenInformationLength
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
AdjustTokenPrivileges (
HANDLE TokenHandle,
BOOL DisableAllPrivileges,
PTOKEN_PRIVILEGES NewState,
DWORD BufferLength,
PTOKEN_PRIVILEGES PreviousState,
PDWORD ReturnLength
)
/*++
Routine Description:
This routine is used to disable or enable privileges in the
specified token. The absence of some of the privileges listed to
be changed won't effect the successful modification of the
privileges that are in the token. The previous enabled/disabled
state of changed privileges may optionally be capture (for
resetting later).
TOKEN_ADJUST_PRIVILEGES access is required to enable or disable
privileges in a token.
Arguments:
TokenHandle - Provides a handle to the token to operate on.
DisableAllPrivileges - This boolean parameter may be
used to disable all privileges assigned to the token. If
this parameter is specified as TRUE, then the NewState parameter is
ignored.
NewState - This (optional) parameter points to a TOKEN_PRIVILEGES
data structure containing the privileges whose states are to
be adjusted (disabled or enabled). Only the Enabled flag of
the attributes associated with each privilege is used. It
provides the new value that is to be assigned to the privilege
in the token.
BufferLength - This optional parameter indicates the length (in
bytes) of the PreviousState buffer. This value must be
provided if the PreviousState parameter is provided.
PreviousState - This (optional) parameter points to a buffer to
receive the state of any privileges actually changed by this
request. This information is formated as a TOKEN_PRIVILEGES
data structure which may be passed as the NewState parameter
in a subsequent call to this routine to restore the original
state of those privilges. TOKEN_QUERY access is needed to use
this parameter.
If this buffer does not contain enough space to receive the
complete list of modified privileges, then no privilege
states are changed and STATUS_BUFFER_TOO_SMALL is returned.
In this case, the ReturnLength OUT parameter will
contain the actual number of bytes needed to hold the
information.
ReturnLength - Indicates the actual number of bytes needed to
contain the previous privilege state information. This
parameter is ignored if the PreviousState argument is not
passed.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = NtAdjustPrivilegesToken (
TokenHandle,
(BOOLEAN)DisableAllPrivileges,
NewState,
BufferLength,
PreviousState,
ReturnLength
);
//
// We need to set last error even for success because that
// is the only way to tell if the api successfully assigned
// all privileges. That is, STATUS_NOT_ALL_ASSIGNED is a
// Success severity level.
//
BaseSetLastNTError(Status);
if ( !NT_SUCCESS(Status) ) {
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
AdjustTokenGroups (
HANDLE TokenHandle,
BOOL ResetToDefault,
PTOKEN_GROUPS NewState,
DWORD BufferLength,
PTOKEN_GROUPS PreviousState,
PDWORD ReturnLength
)
/*++
Routine Description:
This routine is used to disable or enable groups in the specified
token. The absence of some of the groups listed to be changed
won't effect the successful modification of the groups that are in
the token. The previous enabled/disabled state of changed groups
may optionally be capture (for resetting later).
TOKEN_ADJUST_GROUPS access is required to enable or disable groups
in a token
Note that mandatory groups can not be disabled. An attempt
disable any mandatory groups will cause the call to fail, leaving
the state of all groups unchanged.
Arguments:
TokenHandle - Provides a handle to the token to operate on.
ResetToDefault - The parameter indicates whether all the groups
in the token are to be reset to their default enabled/disabled
state.
NewState - This parameter points to a TOKEN_GROUPS data structure
containing the groups whose states are to be adjusted
(disabled or enabled). Only the Enabled flag of the
attributes associated with each group is used. It provides
the new value that is to be assigned to the group in the
token. If the ResetToDefault argument is specified as TRUE,
then this argument is ignored. Otherwise, it must be passed.
BufferLength - This optional parameter indicates the length (in
bytes) of the PreviousState buffer. This value must be
provided if the PreviousState parameter is provided.
PreviousState - This (optional) parameter points to a buffer to
receive the state of any groups actually changed by this
request. This information is formated as a TOKEN_GROUPS data
structure which may be passed as the NewState parameter in a
subsequent call to NtAdjustGroups to restore the original state
of those groups. TOKEN_QUERY access is needed to use this
parameter.
If this buffer does not contain enough space to receive the
complete list of modified groups, then no group states are
changed and STATUS_BUFFER_TOO_SMALL is returned. In this
case, the ReturnLength return parameter will contain the
actual number of bytes needed to hold the information.
ReturnLength - Indicates the actual number of bytes needed to
contain the previous group state information.
This parameter is ignored if the PreviousState argument is not
passed.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = NtAdjustGroupsToken (
TokenHandle,
(BOOLEAN)ResetToDefault,
NewState,
BufferLength,
PreviousState,
ReturnLength
);
//
// We need to set last error even for success because that
// is the only way to tell if the api successfully assigned
// all groups. That is, STATUS_NOT_ALL_ASSIGNED is a
// Success severity level.
//
BaseSetLastNTError(Status);
if ( !NT_SUCCESS(Status) ) {
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
PrivilegeCheck (
HANDLE ClientToken,
PPRIVILEGE_SET RequiredPrivileges,
LPBOOL pfResult
)
/*++
Routine Description:
This routine tests the caller's client's security context to see if it
contains the specified privileges.
This API requires the caller have SeSecurityPrivilege privilege.
The test for this privilege is always against the primary token of
the calling process, not the impersonation token of the thread.
Arguments:
ClientToken - A handle to a token object representing a client
attempting access. This handle must be obtained from a
communication session layer, such as from an LPC Port or Local
Named Pipe, to prevent possible security policy violations.
RequiredPrivileges - Points to a set of privileges. The client's
security context is to be checked to see which of the specified
privileges are present. The results will be indicated in the
attributes associated with each privilege. Note that
flags in this parameter indicate whether all the privileges listed
are needed, or any of the privileges.
pfResult - Receives a boolean flag indicating whether the client
has all the specified privileges or not. A value of TRUE
indicates the client has all the specified privileges.
Otherwise a value of FALSE is returned.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
BOOLEAN Result;
Status = NtPrivilegeCheck (
ClientToken,
RequiredPrivileges,
&Result
);
*pfResult = Result;
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
AccessCheckAndAuditAlarmW(
LPCWSTR SubsystemName,
PVOID HandleId,
LPWSTR ObjectTypeName,
LPWSTR ObjectName,
PSECURITY_DESCRIPTOR SecurityDescriptor,
DWORD DesiredAccess,
PGENERIC_MAPPING GenericMapping,
BOOL ObjectCreation,
LPDWORD GrantedAccess,
LPBOOL AccessStatus,
LPBOOL pfGenerateOnClose
)
/*++
Routine Description:
This routine compares the input Security Descriptor against the
caller's impersonation token and indicates if access is granted or
denied. If access is granted then the desired access mask becomes
the granted access mask for the object. The semantics of the
access check routine is described in the DSA Security Architecture
workbook.
This routine will also generate any necessary audit messages as a
result of the access attempt.
Arguments:
SubsystemName - Supplies a name string identifying the subsystem
calling the routine.
HandleId - A unique value that will be used to represent the client's
handle to the object. This value is ignored (and may be re-used)
if the access is denied.
ObjectTypeName - Supplies the name of the type of the object being
created or accessed.
ObjectName - Supplies the name of the object being created or accessed.
SecurityDescriptor - A pointer to the Security Descriptor against which
acccess is to be checked.
DesiredAccess - The desired acccess mask. This mask must have been
previously mapped to contain no generic accesses.
GenericMapping - Supplies a pointer to the generic mapping associated
with this object type.
ObjectCreation - A boolean flag indicated whether the access will
result in a new object being created if granted. A value of TRUE
indicates an object will be created, FALSE indicates an existing
object will be opened.
GrantedAccess - Receives a masking indicating which accesses have been
granted (only valid on success).
AccessStatus - Receives an indication of the success or failure of the
access check. If access is granted, STATUS_SUCCESS is returned.
If access is denied, a value appropriate for return to the client
is returned. This will be STATUS_ACCESS_DENIED or, when mandatory
access controls are implemented, STATUS_OBJECT_NOT_FOUND.
pfGenerateOnClose - Points to a boolean that is set by the audity
generation routine and must be passed to ObjectCloseAuditAlarm
when the object handle is closed.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
NTSTATUS RealAccessStatus;
BOOLEAN GenerateOnClose = FALSE;
UNICODE_STRING Subsystem;
UNICODE_STRING ObjectType;
UNICODE_STRING Object;
RtlInitUnicodeString(
&Subsystem,
SubsystemName
);
RtlInitUnicodeString(
&ObjectType,
ObjectTypeName
);
RtlInitUnicodeString(
&Object,
ObjectName
);
Status = NtAccessCheckAndAuditAlarm (
&Subsystem,
HandleId,
&ObjectType,
&Object,
SecurityDescriptor,
DesiredAccess,
GenericMapping,
(BOOLEAN)ObjectCreation,
GrantedAccess,
&RealAccessStatus,
&GenerateOnClose
);
*pfGenerateOnClose = (BOOL)GenerateOnClose;
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
if ( !NT_SUCCESS( RealAccessStatus )) {
*AccessStatus = FALSE;
BaseSetLastNTError( RealAccessStatus );
return( TRUE );
}
*AccessStatus = TRUE;
return TRUE;
}
BOOL
APIENTRY
AccessCheckByTypeAndAuditAlarmW (
LPCWSTR SubsystemName,
LPVOID HandleId,
LPCWSTR ObjectTypeName,
LPCWSTR ObjectName,
PSECURITY_DESCRIPTOR SecurityDescriptor,
PSID PrincipalSelfSid,
DWORD DesiredAccess,
AUDIT_EVENT_TYPE AuditType,
DWORD Flags,
POBJECT_TYPE_LIST ObjectTypeList,
DWORD ObjectTypeListLength,
PGENERIC_MAPPING GenericMapping,
BOOL ObjectCreation,
LPDWORD GrantedAccess,
LPBOOL AccessStatus,
LPBOOL pfGenerateOnClose
)
/*++
Routine Description:
This routine compares the input Security Descriptor against the
caller's impersonation token and indicates if access is granted or
denied. If access is granted then the desired access mask becomes
the granted access mask for the object. The semantics of the
access check routine is described in the DSA Security Architecture
workbook.
This routine will also generate any necessary audit messages as a
result of the access attempt.
Arguments:
SubsystemName - Supplies a name string identifying the subsystem
calling the routine.
HandleId - A unique value that will be used to represent the client's
handle to the object. This value is ignored (and may be re-used)
if the access is denied.
ObjectTypeName - Supplies the name of the type of the object being
created or accessed.
ObjectName - Supplies the name of the object being created or accessed.
SecurityDescriptor - A pointer to the Security Descriptor against which
acccess is to be checked.
PrincipalSelfSid - If the object being access checked is an object which
represents a principal (e.g., a user object), this parameter should
be the SID of the object. Any ACE containing the constant
PRINCIPAL_SELF_SID is replaced by this SID.
The parameter should be NULL if the object does not represent a principal.
DesiredAccess - The desired acccess mask. This mask must have been
previously mapped to contain no generic accesses.
AuditType - Specifies the type of audit to be generated. Valid values
are: AuditEventObjectAccess and AuditEventDirectoryServiceAccess.
Flags - Flags modifying the execution of the API:
AUDIT_ALLOW_NO_PRIVILEGE - If the caller does not have AuditPrivilege,
the call will silently continue to check access and will
generate no audit.
ObjectTypeList - Supplies a list of GUIDs representing the object (and
sub-objects) being accessed. If no list is present, AccessCheckByType
behaves identically to AccessCheck.
ObjectTypeListLength - Specifies the number of elements in the ObjectTypeList.
GenericMapping - Supplies a pointer to the generic mapping associated
with this object type.
ObjectCreation - A boolean flag indicated whether the access will
result in a new object being created if granted. A value of TRUE
indicates an object will be created, FALSE indicates an existing
object will be opened.
GrantedAccess - Receives a masking indicating which accesses have been
granted (only valid on success).
AccessStatus - Receives an indication of the success or failure of the
access check. If access is granted, STATUS_SUCCESS is returned.
If access is denied, a value appropriate for return to the client
is returned. This will be STATUS_ACCESS_DENIED or, when mandatory
access controls are implemented, STATUS_OBJECT_NOT_FOUND.
pfGenerateOnClose - Points to a boolean that is set by the audity
generation routine and must be passed to ObjectCloseAuditAlarm
when the object handle is closed.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
NTSTATUS RealAccessStatus;
BOOLEAN GenerateOnClose = FALSE;
UNICODE_STRING Subsystem;
UNICODE_STRING ObjectType;
UNICODE_STRING Object;
RtlInitUnicodeString(
&Subsystem,
SubsystemName
);
RtlInitUnicodeString(
&ObjectType,
ObjectTypeName
);
RtlInitUnicodeString(
&Object,
ObjectName
);
Status = NtAccessCheckByTypeAndAuditAlarm (
&Subsystem,
HandleId,
&ObjectType,
&Object,
SecurityDescriptor,
PrincipalSelfSid,
DesiredAccess,
AuditType,
Flags,
ObjectTypeList,
ObjectTypeListLength,
GenericMapping,
(BOOLEAN)ObjectCreation,
GrantedAccess,
&RealAccessStatus,
&GenerateOnClose
);
*pfGenerateOnClose = (BOOL)GenerateOnClose;
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
if ( !NT_SUCCESS( RealAccessStatus )) {
*AccessStatus = FALSE;
BaseSetLastNTError( RealAccessStatus );
return( TRUE );
}
*AccessStatus = TRUE;
return TRUE;
}
BOOL
APIENTRY
AccessCheckByTypeResultListAndAuditAlarmW (
LPCWSTR SubsystemName,
LPVOID HandleId,
LPCWSTR ObjectTypeName,
LPCWSTR ObjectName,
PSECURITY_DESCRIPTOR SecurityDescriptor,
PSID PrincipalSelfSid,
DWORD DesiredAccess,
AUDIT_EVENT_TYPE AuditType,
DWORD Flags,
POBJECT_TYPE_LIST ObjectTypeList,
DWORD ObjectTypeListLength,
PGENERIC_MAPPING GenericMapping,
BOOL ObjectCreation,
LPDWORD GrantedAccessList,
LPDWORD AccessStatusList,
LPBOOL pfGenerateOnClose
)
/*++
Routine Description:
This routine compares the input Security Descriptor against the
caller's impersonation token and indicates if access is granted or
denied. If access is granted then the desired access mask becomes
the granted access mask for the object. The semantics of the
access check routine is described in the DSA Security Architecture
workbook.
This routine will also generate any necessary audit messages as a
result of the access attempt.
Arguments:
SubsystemName - Supplies a name string identifying the subsystem
calling the routine.
HandleId - A unique value that will be used to represent the client's
handle to the object. This value is ignored (and may be re-used)
if the access is denied.
ObjectTypeName - Supplies the name of the type of the object being
created or accessed.
ObjectName - Supplies the name of the object being created or accessed.
SecurityDescriptor - A pointer to the Security Descriptor against which
acccess is to be checked.
PrincipalSelfSid - If the object being access checked is an object which
represents a principal (e.g., a user object), this parameter should
be the SID of the object. Any ACE containing the constant
PRINCIPAL_SELF_SID is replaced by this SID.
The parameter should be NULL if the object does not represent a principal.
DesiredAccess - The desired acccess mask. This mask must have been
previously mapped to contain no generic accesses.
AuditType - Specifies the type of audit to be generated. Valid values
are: AuditEventObjectAccess and AuditEventDirectoryServiceAccess.
Flags - Flags modifying the execution of the API:
AUDIT_ALLOW_NO_PRIVILEGE - If the called does not have AuditPrivilege,
the call will silently continue to check access and will
generate no audit.
ObjectTypeList - Supplies a list of GUIDs representing the object (and
sub-objects) being accessed. If no list is present, AccessCheckByType
behaves identically to AccessCheck.
ObjectTypeListLength - Specifies the number of elements in the ObjectTypeList.
GenericMapping - Supplies a pointer to the generic mapping associated
with this object type.
ObjectCreation - A boolean flag indicated whether the access will
result in a new object being created if granted. A value of TRUE
indicates an object will be created, FALSE indicates an existing
object will be opened.
GrantedAccessList - Returns an access mask describing the granted access.
AccessStatusList - Status value that may be returned indicating the
reason why access was denied. Routines should avoid hardcoding a
return value of STATUS_ACCESS_DENIED so that a different value can
be returned when mandatory access control is implemented.
pfGenerateOnClose - Points to a boolean that is set by the audity
generation routine and must be passed to ObjectCloseAuditAlarm
when the object handle is closed.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
NTSTATUS RealAccessStatus;
BOOLEAN GenerateOnClose = FALSE;
UNICODE_STRING Subsystem;
UNICODE_STRING ObjectType;
UNICODE_STRING Object;
ULONG i;
RtlInitUnicodeString(
&Subsystem,
SubsystemName
);
RtlInitUnicodeString(
&ObjectType,
ObjectTypeName
);
RtlInitUnicodeString(
&Object,
ObjectName
);
Status = NtAccessCheckByTypeResultListAndAuditAlarm (
&Subsystem,
HandleId,
&ObjectType,
&Object,
SecurityDescriptor,
PrincipalSelfSid,
DesiredAccess,
AuditType,
Flags,
ObjectTypeList,
ObjectTypeListLength,
GenericMapping,
(BOOLEAN)ObjectCreation,
GrantedAccessList,
AccessStatusList,
&GenerateOnClose
);
*pfGenerateOnClose = (BOOL)GenerateOnClose;
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
//
// Loop converting the array of NT status codes to WIN status codes.
//
for ( i=0; i<ObjectTypeListLength; i++ ) {
if ( AccessStatusList[i] == STATUS_SUCCESS ) {
AccessStatusList[i] = NO_ERROR;
} else {
AccessStatusList[i] = RtlNtStatusToDosError( AccessStatusList[i] );
}
}
return TRUE;
}
BOOL
APIENTRY
AccessCheckByTypeResultListAndAuditAlarmByHandleW (
LPCWSTR SubsystemName,
LPVOID HandleId,
HANDLE ClientToken,
LPCWSTR ObjectTypeName,
LPCWSTR ObjectName,
PSECURITY_DESCRIPTOR SecurityDescriptor,
PSID PrincipalSelfSid,
DWORD DesiredAccess,
AUDIT_EVENT_TYPE AuditType,
DWORD Flags,
POBJECT_TYPE_LIST ObjectTypeList,
DWORD ObjectTypeListLength,
PGENERIC_MAPPING GenericMapping,
BOOL ObjectCreation,
LPDWORD GrantedAccessList,
LPDWORD AccessStatusList,
LPBOOL pfGenerateOnClose
)
/*++
Routine Description:
This routine compares the input Security Descriptor against the
caller's impersonation token and indicates if access is granted or
denied. If access is granted then the desired access mask becomes
the granted access mask for the object. The semantics of the
access check routine is described in the DSA Security Architecture
workbook.
This routine will also generate any necessary audit messages as a
result of the access attempt.
Arguments:
SubsystemName - Supplies a name string identifying the subsystem
calling the routine.
HandleId - A unique value that will be used to represent the client's
handle to the object. This value is ignored (and may be re-used)
if the access is denied.
ClientToken - A handle to a token object representing the client that
requested the operation. This handle must be obtained from a
communication session layer, such as from an LPC Port or Local
Named Pipe, to prevent possible security policy violations.
ObjectTypeName - Supplies the name of the type of the object being
created or accessed.
ObjectName - Supplies the name of the object being created or accessed.
SecurityDescriptor - A pointer to the Security Descriptor against which
acccess is to be checked.
PrincipalSelfSid - If the object being access checked is an object which
represents a principal (e.g., a user object), this parameter should
be the SID of the object. Any ACE containing the constant
PRINCIPAL_SELF_SID is replaced by this SID.
The parameter should be NULL if the object does not represent a principal.
DesiredAccess - The desired acccess mask. This mask must have been
previously mapped to contain no generic accesses.
AuditType - Specifies the type of audit to be generated. Valid values
are: AuditEventObjectAccess and AuditEventDirectoryServiceAccess.
Flags - Flags modifying the execution of the API:
AUDIT_ALLOW_NO_PRIVILEGE - If the called does not have AuditPrivilege,
the call will silently continue to check access and will
generate no audit.
ObjectTypeList - Supplies a list of GUIDs representing the object (and
sub-objects) being accessed. If no list is present, AccessCheckByType
behaves identically to AccessCheck.
ObjectTypeListLength - Specifies the number of elements in the ObjectTypeList.
GenericMapping - Supplies a pointer to the generic mapping associated
with this object type.
ObjectCreation - A boolean flag indicated whether the access will
result in a new object being created if granted. A value of TRUE
indicates an object will be created, FALSE indicates an existing
object will be opened.
GrantedAccessList - Returns an access mask describing the granted access.
AccessStatusList - Status value that may be returned indicating the
reason why access was denied. Routines should avoid hardcoding a
return value of STATUS_ACCESS_DENIED so that a different value can
be returned when mandatory access control is implemented.
pfGenerateOnClose - Points to a boolean that is set by the audity
generation routine and must be passed to ObjectCloseAuditAlarm
when the object handle is closed.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
NTSTATUS RealAccessStatus;
BOOLEAN GenerateOnClose = FALSE;
UNICODE_STRING Subsystem;
UNICODE_STRING ObjectType;
UNICODE_STRING Object;
ULONG i;
RtlInitUnicodeString(
&Subsystem,
SubsystemName
);
RtlInitUnicodeString(
&ObjectType,
ObjectTypeName
);
RtlInitUnicodeString(
&Object,
ObjectName
);
Status = NtAccessCheckByTypeResultListAndAuditAlarmByHandle (
&Subsystem,
HandleId,
ClientToken,
&ObjectType,
&Object,
SecurityDescriptor,
PrincipalSelfSid,
DesiredAccess,
AuditType,
Flags,
ObjectTypeList,
ObjectTypeListLength,
GenericMapping,
(BOOLEAN)ObjectCreation,
GrantedAccessList,
AccessStatusList,
&GenerateOnClose
);
*pfGenerateOnClose = (BOOL)GenerateOnClose;
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
//
// Loop converting the array of NT status codes to WIN status codes.
//
for ( i=0; i<ObjectTypeListLength; i++ ) {
if ( AccessStatusList[i] == STATUS_SUCCESS ) {
AccessStatusList[i] = NO_ERROR;
} else {
AccessStatusList[i] = RtlNtStatusToDosError( AccessStatusList[i] );
}
}
return TRUE;
}
BOOL
APIENTRY
AccessCheckAndAuditAlarmA (
LPCSTR SubsystemName,
PVOID HandleId,
LPSTR ObjectTypeName,
LPSTR ObjectName,
PSECURITY_DESCRIPTOR SecurityDescriptor,
DWORD DesiredAccess,
PGENERIC_MAPPING GenericMapping,
BOOL ObjectCreation,
LPDWORD GrantedAccess,
LPBOOL AccessStatus,
LPBOOL pfGenerateOnClose
)
/*++
Routine Description:
ANSI Thunk to AccessCheckAndAuditAlarmW
--*/
{
PUNICODE_STRING ObjectNameW;
ANSI_STRING AnsiString;
UNICODE_STRING SubsystemNameW;
UNICODE_STRING ObjectTypeNameW;
NTSTATUS Status;
BOOL RVal;
ObjectNameW = &NtCurrentTeb()->StaticUnicodeString;
RtlInitAnsiString(&AnsiString,SubsystemName);
Status = RtlAnsiStringToUnicodeString(&SubsystemNameW,&AnsiString,TRUE);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
RtlInitAnsiString(&AnsiString,ObjectTypeName);
Status = RtlAnsiStringToUnicodeString(&ObjectTypeNameW,&AnsiString,TRUE);
if ( !NT_SUCCESS(Status) ) {
RtlFreeUnicodeString( &SubsystemNameW );
BaseSetLastNTError(Status);
return FALSE;
}
//
// Convert the object name string, but don't allocate memory to
// do it, since we've got the space in the TEB available.
//
RtlInitAnsiString(&AnsiString,ObjectName);
Status = RtlAnsiStringToUnicodeString(ObjectNameW,&AnsiString,FALSE);
if ( !NT_SUCCESS(Status) ) {
RtlFreeUnicodeString( &SubsystemNameW );
RtlFreeUnicodeString( &ObjectTypeNameW );
BaseSetLastNTError(Status);
return FALSE;
}
RVal = AccessCheckAndAuditAlarmW (
(LPCWSTR)SubsystemNameW.Buffer,
HandleId,
ObjectTypeNameW.Buffer,
ObjectNameW->Buffer,
SecurityDescriptor,
DesiredAccess,
GenericMapping,
ObjectCreation,
GrantedAccess,
AccessStatus,
pfGenerateOnClose
);
RtlFreeUnicodeString( &SubsystemNameW );
RtlFreeUnicodeString( &ObjectTypeNameW );
return( RVal );
}
BOOL
APIENTRY
AccessCheckByTypeAndAuditAlarmA (
LPCSTR SubsystemName,
PVOID HandleId,
LPCSTR ObjectTypeName,
LPCSTR ObjectName,
PSECURITY_DESCRIPTOR SecurityDescriptor,
PSID PrincipalSelfSid,
DWORD DesiredAccess,
AUDIT_EVENT_TYPE AuditType,
DWORD Flags,
POBJECT_TYPE_LIST ObjectTypeList,
DWORD ObjectTypeListLength,
PGENERIC_MAPPING GenericMapping,
BOOL ObjectCreation,
LPDWORD GrantedAccess,
LPBOOL AccessStatus,
LPBOOL pfGenerateOnClose
)
/*++
Routine Description:
ANSI Thunk to AccessCheckByTypeAndAuditAlarmW
--*/
{
PUNICODE_STRING ObjectNameW;
ANSI_STRING AnsiString;
UNICODE_STRING SubsystemNameW;
UNICODE_STRING ObjectTypeNameW;
NTSTATUS Status;
BOOL RVal;
ObjectNameW = &NtCurrentTeb()->StaticUnicodeString;
RtlInitAnsiString(&AnsiString,SubsystemName);
Status = RtlAnsiStringToUnicodeString(&SubsystemNameW,&AnsiString,TRUE);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
RtlInitAnsiString(&AnsiString,ObjectTypeName);
Status = RtlAnsiStringToUnicodeString(&ObjectTypeNameW,&AnsiString,TRUE);
if ( !NT_SUCCESS(Status) ) {
RtlFreeUnicodeString( &SubsystemNameW );
BaseSetLastNTError(Status);
return FALSE;
}
//
// Convert the object name string, but don't allocate memory to
// do it, since we've got the space in the TEB available.
//
RtlInitAnsiString(&AnsiString,ObjectName);
Status = RtlAnsiStringToUnicodeString(ObjectNameW,&AnsiString,FALSE);
if ( !NT_SUCCESS(Status) ) {
RtlFreeUnicodeString( &SubsystemNameW );
RtlFreeUnicodeString( &ObjectTypeNameW );
BaseSetLastNTError(Status);
return FALSE;
}
RVal = AccessCheckByTypeAndAuditAlarmW (
(LPCWSTR)SubsystemNameW.Buffer,
HandleId,
ObjectTypeNameW.Buffer,
ObjectNameW->Buffer,
SecurityDescriptor,
PrincipalSelfSid,
DesiredAccess,
AuditType,
Flags,
ObjectTypeList,
ObjectTypeListLength,
GenericMapping,
ObjectCreation,
GrantedAccess,
AccessStatus,
pfGenerateOnClose
);
RtlFreeUnicodeString( &SubsystemNameW );
RtlFreeUnicodeString( &ObjectTypeNameW );
return( RVal );
}
WINADVAPI
BOOL
WINAPI
AccessCheckByTypeResultListAndAuditAlarmA (
LPCSTR SubsystemName,
LPVOID HandleId,
LPCSTR ObjectTypeName,
LPCSTR ObjectName,
PSECURITY_DESCRIPTOR SecurityDescriptor,
PSID PrincipalSelfSid,
DWORD DesiredAccess,
AUDIT_EVENT_TYPE AuditType,
DWORD Flags,
POBJECT_TYPE_LIST ObjectTypeList,
DWORD ObjectTypeListLength,
PGENERIC_MAPPING GenericMapping,
BOOL ObjectCreation,
LPDWORD GrantedAccess,
LPDWORD AccessStatusList,
LPBOOL pfGenerateOnClose
)
/*++
Routine Description:
ANSI Thunk to AccessCheckByTypeResultListAndAuditAlarmW
--*/
{
PUNICODE_STRING ObjectNameW;
ANSI_STRING AnsiString;
UNICODE_STRING SubsystemNameW;
UNICODE_STRING ObjectTypeNameW;
NTSTATUS Status;
BOOL RVal;
ObjectNameW = &NtCurrentTeb()->StaticUnicodeString;
RtlInitAnsiString(&AnsiString,SubsystemName);
Status = RtlAnsiStringToUnicodeString(&SubsystemNameW,&AnsiString,TRUE);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
RtlInitAnsiString(&AnsiString,ObjectTypeName);
Status = RtlAnsiStringToUnicodeString(&ObjectTypeNameW,&AnsiString,TRUE);
if ( !NT_SUCCESS(Status) ) {
RtlFreeUnicodeString( &SubsystemNameW );
BaseSetLastNTError(Status);
return FALSE;
}
//
// Convert the object name string, but don't allocate memory to
// do it, since we've got the space in the TEB available.
//
RtlInitAnsiString(&AnsiString,ObjectName);
Status = RtlAnsiStringToUnicodeString(ObjectNameW,&AnsiString,FALSE);
if ( !NT_SUCCESS(Status) ) {
RtlFreeUnicodeString( &SubsystemNameW );
RtlFreeUnicodeString( &ObjectTypeNameW );
BaseSetLastNTError(Status);
return FALSE;
}
RVal = AccessCheckByTypeResultListAndAuditAlarmW (
(LPCWSTR)SubsystemNameW.Buffer,
HandleId,
ObjectTypeNameW.Buffer,
ObjectNameW->Buffer,
SecurityDescriptor,
PrincipalSelfSid,
DesiredAccess,
AuditType,
Flags,
ObjectTypeList,
ObjectTypeListLength,
GenericMapping,
ObjectCreation,
GrantedAccess,
AccessStatusList,
pfGenerateOnClose
);
RtlFreeUnicodeString( &SubsystemNameW );
RtlFreeUnicodeString( &ObjectTypeNameW );
return( RVal );
}
WINADVAPI
BOOL
WINAPI
AccessCheckByTypeResultListAndAuditAlarmByHandleA (
LPCSTR SubsystemName,
LPVOID HandleId,
HANDLE ClientToken,
LPCSTR ObjectTypeName,
LPCSTR ObjectName,
PSECURITY_DESCRIPTOR SecurityDescriptor,
PSID PrincipalSelfSid,
DWORD DesiredAccess,
AUDIT_EVENT_TYPE AuditType,
DWORD Flags,
POBJECT_TYPE_LIST ObjectTypeList,
DWORD ObjectTypeListLength,
PGENERIC_MAPPING GenericMapping,
BOOL ObjectCreation,
LPDWORD GrantedAccess,
LPDWORD AccessStatusList,
LPBOOL pfGenerateOnClose
)
/*++
Routine Description:
ANSI Thunk to AccessCheckByTypeResultListAndAuditAlarmW
--*/
{
PUNICODE_STRING ObjectNameW;
ANSI_STRING AnsiString;
UNICODE_STRING SubsystemNameW;
UNICODE_STRING ObjectTypeNameW;
NTSTATUS Status;
BOOL RVal;
ObjectNameW = &NtCurrentTeb()->StaticUnicodeString;
RtlInitAnsiString(&AnsiString,SubsystemName);
Status = RtlAnsiStringToUnicodeString(&SubsystemNameW,&AnsiString,TRUE);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
RtlInitAnsiString(&AnsiString,ObjectTypeName);
Status = RtlAnsiStringToUnicodeString(&ObjectTypeNameW,&AnsiString,TRUE);
if ( !NT_SUCCESS(Status) ) {
RtlFreeUnicodeString( &SubsystemNameW );
BaseSetLastNTError(Status);
return FALSE;
}
//
// Convert the object name string, but don't allocate memory to
// do it, since we've got the space in the TEB available.
//
RtlInitAnsiString(&AnsiString,ObjectName);
Status = RtlAnsiStringToUnicodeString(ObjectNameW,&AnsiString,FALSE);
if ( !NT_SUCCESS(Status) ) {
RtlFreeUnicodeString( &SubsystemNameW );
RtlFreeUnicodeString( &ObjectTypeNameW );
BaseSetLastNTError(Status);
return FALSE;
}
RVal = AccessCheckByTypeResultListAndAuditAlarmByHandleW (
(LPCWSTR)SubsystemNameW.Buffer,
HandleId,
ClientToken,
ObjectTypeNameW.Buffer,
ObjectNameW->Buffer,
SecurityDescriptor,
PrincipalSelfSid,
DesiredAccess,
AuditType,
Flags,
ObjectTypeList,
ObjectTypeListLength,
GenericMapping,
ObjectCreation,
GrantedAccess,
AccessStatusList,
pfGenerateOnClose
);
RtlFreeUnicodeString( &SubsystemNameW );
RtlFreeUnicodeString( &ObjectTypeNameW );
return( RVal );
}
BOOL
APIENTRY
ObjectOpenAuditAlarmA (
LPCSTR SubsystemName,
PVOID HandleId,
LPSTR ObjectTypeName,
LPSTR ObjectName,
PSECURITY_DESCRIPTOR pSecurityDescriptor,
HANDLE ClientToken,
DWORD DesiredAccess,
DWORD GrantedAccess,
PPRIVILEGE_SET Privileges OPTIONAL,
BOOL ObjectCreation,
BOOL AccessGranted,
LPBOOL GenerateOnClose
)
/*++
Routine Description:
ANSI Thunk to ObjectOpenAuditAlarmW
--*/
{
PUNICODE_STRING ObjectNameW;
ANSI_STRING AnsiString;
UNICODE_STRING SubsystemNameW;
UNICODE_STRING ObjectTypeNameW;
NTSTATUS Status;
BOOL RVal;
ObjectNameW = &NtCurrentTeb()->StaticUnicodeString;
RtlInitAnsiString(&AnsiString,SubsystemName);
Status = RtlAnsiStringToUnicodeString(&SubsystemNameW,&AnsiString,TRUE);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
RtlInitAnsiString(&AnsiString,ObjectTypeName);
Status = RtlAnsiStringToUnicodeString(&ObjectTypeNameW,&AnsiString,TRUE);
if ( !NT_SUCCESS(Status) ) {
RtlFreeUnicodeString( &SubsystemNameW );
BaseSetLastNTError(Status);
return FALSE;
}
//
// Convert the object name string, but don't allocate memory to
// do it, since we've got the space in the TEB available.
//
RtlInitAnsiString(&AnsiString,ObjectName);
Status = RtlAnsiStringToUnicodeString(ObjectNameW,&AnsiString,FALSE);
if ( !NT_SUCCESS(Status) ) {
RtlFreeUnicodeString( &SubsystemNameW );
RtlFreeUnicodeString( &ObjectTypeNameW );
BaseSetLastNTError(Status);
return FALSE;
}
RVal = ObjectOpenAuditAlarmW (
(LPCWSTR)SubsystemNameW.Buffer,
HandleId,
ObjectTypeNameW.Buffer,
ObjectNameW->Buffer,
pSecurityDescriptor,
ClientToken,
DesiredAccess,
GrantedAccess,
Privileges,
ObjectCreation,
AccessGranted,
GenerateOnClose
);
RtlFreeUnicodeString( &SubsystemNameW );
RtlFreeUnicodeString( &ObjectTypeNameW );
return( RVal );
}
BOOL
APIENTRY
ObjectOpenAuditAlarmW (
LPCWSTR SubsystemName,
PVOID HandleId,
LPWSTR ObjectTypeName,
LPWSTR ObjectName,
PSECURITY_DESCRIPTOR pSecurityDescriptor,
HANDLE ClientToken,
DWORD DesiredAccess,
DWORD GrantedAccess,
PPRIVILEGE_SET Privileges OPTIONAL,
BOOL ObjectCreation,
BOOL AccessGranted,
LPBOOL GenerateOnClose
)
/*++
Routine Description:
This routine is used to generate audit and alarm messages when an
attempt is made to access an existing protected subsystem object or
create a new one. This routine may result in several messages being
generated and sent to Port objects. This may result in a significant
latency before returning. Design of routines that must call this
routine must take this potential latency into account. This may have
an impact on the approach taken for data structure mutex locking, for
example.
This routine may not be able to generate a complete audit record
due to memory restrictions.
This API requires the caller have SeSecurityPrivilege privilege.
The test for this privilege is always against the primary token of
the calling process, not the impersonation token of the thread.
Arguments:
SubsystemName - Supplies a name string identifying the
subsystem calling the routine.
HandleId - A unique value representing the client's handle to the
object. If the access attempt was not successful (AccessGranted is
FALSE), then this parameter is ignored.
ObjectTypeName - Supplies the name of the type of object being
accessed.
ObjectName - Supplies the name of the object the client
accessed or attempted to access.
pSecurityDescriptor - An optional pointer to the security
descriptor of the object being accessed.
ClientToken - A handle to a token object representing the client that
requested the operation. This handle must be obtained from a
communication session layer, such as from an LPC Port or Local
Named Pipe, to prevent possible security policy violations.
DesiredAccess - The desired access mask. This mask must have been
previously mapped to contain no generic accesses.
GrantedAccess - The mask of accesses that were actually granted.
Privileges - Optionally points to a set of privileges that were
required for the access attempt. Those privileges that were held
by the subject are marked using the UsedForAccess flag of the
attributes associated with each privilege.
ObjectCreation - A boolean flag indicating whether the access will
result in a new object being created if granted. A value of TRUE
indicates an object will be created, FALSE indicates an existing
object will be opened.
AccessGranted - Indicates whether the requested access was granted or
not. A value of TRUE indicates the access was granted. A value of
FALSE indicates the access was not granted.
GenerateOnClose - Points to a boolean that is set by the audit
generation routine and must be passed to NtCloseObjectAuditAlarm()
when the object handle is closed.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
UNICODE_STRING Subsystem;
UNICODE_STRING ObjectType;
UNICODE_STRING Object;
RtlInitUnicodeString(
&Subsystem,
SubsystemName
);
RtlInitUnicodeString(
&ObjectType,
ObjectTypeName
);
RtlInitUnicodeString(
&Object,
ObjectName
);
Status = NtOpenObjectAuditAlarm (
&Subsystem,
&HandleId,
&ObjectType,
&Object,
pSecurityDescriptor,
ClientToken,
DesiredAccess,
GrantedAccess,
Privileges,
(BOOLEAN)ObjectCreation,
(BOOLEAN)AccessGranted,
(PBOOLEAN)GenerateOnClose
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
ObjectPrivilegeAuditAlarmA (
LPCSTR SubsystemName,
PVOID HandleId,
HANDLE ClientToken,
DWORD DesiredAccess,
PPRIVILEGE_SET Privileges,
BOOL AccessGranted
)
/*++
Routine Description:
ANSI Thunk to ObjectPrivilegeAuditAlarmW
--*/
{
PUNICODE_STRING SubsystemNameW;
ANSI_STRING AnsiString;
NTSTATUS Status;
BOOL RVal;
SubsystemNameW = &NtCurrentTeb()->StaticUnicodeString;
//
// Convert the object name string, but don't allocate memory to
// do it, since we've got the space in the TEB available.
//
RtlInitAnsiString(&AnsiString,SubsystemName);
Status = RtlAnsiStringToUnicodeString(SubsystemNameW,&AnsiString,FALSE);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
RVal = ObjectPrivilegeAuditAlarmW (
(LPCWSTR)SubsystemNameW->Buffer,
HandleId,
ClientToken,
DesiredAccess,
Privileges,
AccessGranted
);
return( RVal );
}
BOOL
APIENTRY
ObjectPrivilegeAuditAlarmW (
LPCWSTR SubsystemName,
PVOID HandleId,
HANDLE ClientToken,
DWORD DesiredAccess,
PPRIVILEGE_SET Privileges,
BOOL AccessGranted
)
/*++
Routine Description:
This routine is used to generate audit and alarm messages when an
attempt is made to perform privileged operations on a protected
subsystem object after the object is already opened. This routine
may result in several messages being generated and sent to Port
objects. This may result in a significant latency before
returning. Design of routines that must call this routine must
take this potential latency into account. This may have an impact
on the approach taken for data structure mutex locking, for
example.
This API requires the caller have SeSecurityPrivilege privilege.
The test for this privilege is always against the primary token of
the calling process, allowing the caller to be impersonating a
client during the call with no ill effects.
Arguments:
SubsystemName - Supplies a name string identifying the subsystem
calling the routine.
HandleId - A unique value representing the client's handle to the
object.
ClientToken - A handle to a token object representing the client that
requested the operation. This handle must be obtained from a
communication session layer, such as from an LPC Port or Local
Named Pipe, to prevent possible security policy violations.
DesiredAccess - The desired access mask. This mask must have been
previously mapped to contain no generic accesses.
Privileges - The set of privileges required for the requested
operation. Those privileges that were held by the subject are
marked using the UsedForAccess flag of the attributes
associated with each privilege.
AccessGranted - Indicates whether the requested access was granted or
not. A value of TRUE indicates the access was granted. A value of
FALSE indicates the access was not granted.
Return value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
UNICODE_STRING Subsystem;
RtlInitUnicodeString(
&Subsystem,
SubsystemName
);
Status = NtPrivilegeObjectAuditAlarm (
&Subsystem,
HandleId,
ClientToken,
DesiredAccess,
Privileges,
(BOOLEAN)AccessGranted
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
ObjectCloseAuditAlarmA (
LPCSTR SubsystemName,
PVOID HandleId,
BOOL GenerateOnClose
)
/*++
Routine Description:
ANSI Thunk to ObjectCloseAuditAlarmW
--*/
{
PUNICODE_STRING SubsystemNameW;
NTSTATUS Status;
ANSI_STRING AnsiString;
SubsystemNameW = &NtCurrentTeb()->StaticUnicodeString;
//
// Convert the object name string, but don't allocate memory to
// do it, since we've got the space in the TEB available.
//
RtlInitAnsiString(&AnsiString,SubsystemName);
Status = RtlAnsiStringToUnicodeString(SubsystemNameW,&AnsiString,FALSE);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return ObjectCloseAuditAlarmW (
(LPCWSTR)SubsystemNameW->Buffer,
HandleId,
GenerateOnClose
);
}
BOOL
APIENTRY
ObjectCloseAuditAlarmW (
LPCWSTR SubsystemName,
PVOID HandleId,
BOOL GenerateOnClose
)
/*++
Routine Description:
This routine is used to generate audit and alarm messages when a handle
to a protected subsystem object is deleted. This routine may result in
several messages being generated and sent to Port objects. This may
result in a significant latency before returning. Design of routines
that must call this routine must take this potential latency into
account. This may have an impact on the approach taken for data
structure mutex locking, for example.
This API requires the caller have SeSecurityPrivilege privilege. The test
for this privilege is always against the primary token of the calling
process, allowing the caller to be impersonating a client during the
call with no ill effects.
Arguments:
SubsystemName - Supplies a name string identifying the subsystem
calling the routine.
HandleId - A unique value representing the client's handle to the
object.
GenerateOnClose - Is a boolean value returned from a corresponding
AccessCheckAndAuditAlarm() call or ObjectOpenAuditAlarm() call
when the object handle was created.
Return value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
UNICODE_STRING Subsystem;
RtlInitUnicodeString( &Subsystem, SubsystemName );
Status = NtCloseObjectAuditAlarm (
&Subsystem,
HandleId,
(BOOLEAN)GenerateOnClose
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
ObjectDeleteAuditAlarmA (
LPCSTR SubsystemName,
PVOID HandleId,
BOOL GenerateOnClose
)
/*++
Routine Description:
ANSI Thunk to ObjectDeleteAuditAlarmW
--*/
{
PUNICODE_STRING SubsystemNameW;
NTSTATUS Status;
ANSI_STRING AnsiString;
SubsystemNameW = &NtCurrentTeb()->StaticUnicodeString;
//
// Convert the object name string, but don't allocate memory to
// do it, since we've got the space in the TEB available.
//
RtlInitAnsiString(&AnsiString,SubsystemName);
Status = RtlAnsiStringToUnicodeString(SubsystemNameW,&AnsiString,FALSE);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return ObjectDeleteAuditAlarmW (
(LPCWSTR)SubsystemNameW->Buffer,
HandleId,
GenerateOnClose
);
}
BOOL
APIENTRY
ObjectDeleteAuditAlarmW (
LPCWSTR SubsystemName,
PVOID HandleId,
BOOL GenerateOnClose
)
/*++
Routine Description:
This routine is used to generate audit and alarm messages when an object
in a protected subsystem is deleted. This routine may result in
several messages being generated and sent to Port objects. This may
result in a significant latency before returning. Design of routines
that must call this routine must take this potential latency into
account. This may have an impact on the approach taken for data
structure mutex locking, for example.
This API requires the caller have SeSecurityPrivilege privilege. The test
for this privilege is always against the primary token of the calling
process, allowing the caller to be impersonating a client during the
call with no ill effects.
Arguments:
SubsystemName - Supplies a name string identifying the subsystem
calling the routine.
HandleId - A unique value representing the client's handle to the
object.
GenerateOnClose - Is a boolean value returned from a corresponding
AccessCheckAndAuditAlarm() call or ObjectOpenAuditAlarm() call
when the object handle was created.
Return value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
UNICODE_STRING Subsystem;
RtlInitUnicodeString( &Subsystem, SubsystemName );
Status = NtDeleteObjectAuditAlarm (
&Subsystem,
HandleId,
(BOOLEAN)GenerateOnClose
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
PrivilegedServiceAuditAlarmA (
LPCSTR SubsystemName,
LPCSTR ServiceName,
HANDLE ClientToken,
PPRIVILEGE_SET Privileges,
BOOL AccessGranted
)
/*++
Routine Description:
ANSI Thunk to PrivilegedServiceAuditAlarmW
--*/
{
PUNICODE_STRING ServiceNameW;
UNICODE_STRING SubsystemNameW;
ANSI_STRING AnsiString;
NTSTATUS Status;
BOOL RVal;
ServiceNameW = &NtCurrentTeb()->StaticUnicodeString;
//
// Convert the object name string, but don't allocate memory to
// do it, since we've got the space in the TEB available.
//
RtlInitAnsiString(&AnsiString,ServiceName);
Status = RtlAnsiStringToUnicodeString(ServiceNameW,&AnsiString,FALSE);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
RtlInitAnsiString(&AnsiString,SubsystemName);
Status = RtlAnsiStringToUnicodeString(&SubsystemNameW,&AnsiString,TRUE);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
RVal = PrivilegedServiceAuditAlarmW (
(LPCWSTR)SubsystemNameW.Buffer,
(LPCWSTR)ServiceNameW->Buffer,
ClientToken,
Privileges,
AccessGranted
);
RtlFreeUnicodeString( &SubsystemNameW );
return( RVal );
}
BOOL
APIENTRY
PrivilegedServiceAuditAlarmW (
LPCWSTR SubsystemName,
LPCWSTR ServiceName,
HANDLE ClientToken,
PPRIVILEGE_SET Privileges,
BOOL AccessGranted
)
/*++
Routine Description:
This routine is used to generate audit and alarm messages when an
attempt is made to perform privileged system service operations. This
routine may result in several messages being generated and sent to Port
objects. This may result in a significant latency before returning.
Design of routines that must call this routine must take this potential
latency into account. This may have an impact on the approach taken
for data structure mutex locking, for example.
This API requires the caller have SeSecurityPrivilege privilege. The test
for this privilege is always against the primary token of the calling
process, allowing the caller to be impersonating a client during the
call with no ill effects
Arguments:
SubsystemName - Supplies a name string identifying the subsystem
calling the routine.
ServiceName - Supplies a name of the privileged subsystem service. For
example, "RESET RUNTIME LOCAL SECURITY POLICY" might be specified
by a Local Security Authority service used to update the local
security policy database.
ClientToken - A handle to a token object representing the client that
requested the operation. This handle must be obtained from a
communication session layer, such as from an LPC Port or Local
Named Pipe, to prevent possible security policy violations.
Privileges - Points to a set of privileges required to perform the
privileged operation. Those privileges that were held by the
subject are marked using the UsedForAccess flag of the
attributes associated with each privilege.
AccessGranted - Indicates whether the requested access was granted or
not. A value of TRUE indicates the access was granted. A value of
FALSE indicates the access was not granted.
Return value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
UNICODE_STRING Subsystem;
UNICODE_STRING Service;
RtlInitUnicodeString( &Subsystem, SubsystemName );
RtlInitUnicodeString( &Service, ServiceName );
Status = NtPrivilegedServiceAuditAlarm (
&Subsystem,
&Service,
ClientToken,
Privileges,
(BOOLEAN)AccessGranted
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
IsValidSid (
PSID pSid
)
/*++
Routine Description:
This procedure validates an SID's structure.
Arguments:
pSid - Pointer to the SID structure to validate.
Return Value:
BOOLEAN - TRUE if the structure of pSid is valid.
--*/
{
if ( !RtlValidSid ( pSid ) ) {
SetLastError(ERROR_INVALID_SID);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
EqualSid (
PSID pSid1,
PSID pSid2
)
/*++
Routine Description:
This procedure tests two SID values for equality.
Arguments:
pSid1, pSid2 - Supply pointers to the two SID values to compare.
The SID structures are assumed to be valid.
Return Value:
BOOLEAN - TRUE if the value of pSid1 is equal to pSid2, and FALSE
otherwise.
--*/
{
SetLastError(0);
return (BOOL) RtlEqualSid (
pSid1,
pSid2
);
}
BOOL
APIENTRY
EqualPrefixSid (
PSID pSid1,
PSID pSid2
)
/*++
Routine Description:
This procedure tests two SID prefix values for equality.
An SID prefix is the entire SID except for the last sub-authority
value.
Arguments:
pSid1, pSid2 - Supply pointers to the two SID values to compare.
The SID structures are assumed to be valid.
Return Value:
BOOLEAN - TRUE if the prefix value of pSid1 is equal to pSid2, and
FALSE otherwise.
--*/
{
SetLastError(0);
return (BOOL) RtlEqualPrefixSid (
pSid1,
pSid2
);
}
DWORD
APIENTRY
GetSidLengthRequired (
UCHAR nSubAuthorityCount
)
/*++
Routine Description:
This routine returns the length, in bytes, required to store an SID
with the specified number of Sub-Authorities.
Arguments:
nSubAuthorityCount - The number of sub-authorities to be stored in
the SID.
Return Value:
DWORD - The length, in bytes, required to store the SID.
--*/
{
return RtlLengthRequiredSid (
nSubAuthorityCount
);
}
BOOL
APIENTRY
InitializeSid (
PSID Sid,
PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority,
BYTE nSubAuthorityCount
)
/*++
Routine Description:
This function initializes an SID data structure. It does not,
however, set the sub-authority values. This must be done
separately.
Arguments:
Sid - Pointer to the SID data structure to initialize.
pIdentifierAuthority - Pointer to the Identifier Authority value
to set in the SID.
nSubAuthorityCount - The number of sub-authorities that will be
placed in the SID (a separate action).
Return Value:
None
--*/
{
NTSTATUS Status;
Status = RtlInitializeSid (
Sid,
pIdentifierAuthority,
nSubAuthorityCount
);
if ( !NT_SUCCESS( Status )) {
BaseSetLastNTError( Status );
return( FALSE );
}
return( TRUE );
}
PVOID
APIENTRY
FreeSid(
PSID pSid
)
/*++
Routine Description:
This function is used to free a SID previously allocated using
AllocateAndInitializeSid().
Arguments:
Sid - Pointer to the SID to free.
Return Value:
None.
--*/
{
return(RtlFreeSid( pSid ));
}
BOOL
APIENTRY
AllocateAndInitializeSid (
PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority,
BYTE nSubAuthorityCount,
DWORD nSubAuthority0,
DWORD nSubAuthority1,
DWORD nSubAuthority2,
DWORD nSubAuthority3,
DWORD nSubAuthority4,
DWORD nSubAuthority5,
DWORD nSubAuthority6,
DWORD nSubAuthority7,
PSID *pSid
)
/*++
Routine Description:
This function allocates and initializes a sid with the specified
number of sub-authorities (up to 8). A sid allocated with this
routine must be freed using FreeSid().
Arguments:
pIdentifierAuthority - Pointer to the Identifier Authority value to
set in the SID.
nSubAuthorityCount - The number of sub-authorities to place in the SID.
This also identifies how many of the SubAuthorityN parameters
have meaningful values. This must contain a value from 0 through
8.
nSubAuthority0-7 - Provides the corresponding sub-authority value to
place in the SID. For example, a SubAuthorityCount value of 3
indicates that SubAuthority0, SubAuthority1, and SubAuthority0
have meaningful values and the rest are to be ignored.
Sid - Receives a pointer to the allocated and initialized SID data
structure.
Return Value:
ERROR_NO_MEMORY - The attempt to allocate memory for the SID
failed.
ERROR_INVALID_SID - The number of sub-authorities specified did
not fall in the valid range for this api (0 through 8).
--*/
{
NTSTATUS Status;
Status = RtlAllocateAndInitializeSid (
pIdentifierAuthority,
(UCHAR)nSubAuthorityCount,
(ULONG)nSubAuthority0,
(ULONG)nSubAuthority1,
(ULONG)nSubAuthority2,
(ULONG)nSubAuthority3,
(ULONG)nSubAuthority4,
(ULONG)nSubAuthority5,
(ULONG)nSubAuthority6,
(ULONG)nSubAuthority7,
pSid
);
if ( !NT_SUCCESS( Status )) {
BaseSetLastNTError( Status );
return( FALSE );
}
return( TRUE );
}
PSID_IDENTIFIER_AUTHORITY
GetSidIdentifierAuthority (
PSID pSid
)
/*++
Routine Description:
This function returns the address of an SID's IdentifierAuthority field.
Arguments:
Sid - Pointer to the SID data structure.
Return Value:
Address of an SID's Identifier Authority field.
--*/
{
SetLastError(0);
return RtlIdentifierAuthoritySid (
pSid
);
}
PDWORD
GetSidSubAuthority (
PSID pSid,
DWORD nSubAuthority
)
/*++
Routine Description:
This function returns the address of a sub-authority array element of
an SID.
Arguments:
pSid - Pointer to the SID data structure.
nSubAuthority - An index indicating which sub-authority is being
specified. This value is not compared against the number of
sub-authorities in the SID for validity.
Return Value:
Address of a relative ID within the SID.
--*/
{
SetLastError(0);
return RtlSubAuthoritySid (
pSid,
nSubAuthority
);
}
PUCHAR
GetSidSubAuthorityCount (
PSID pSid
)
/*++
Routine Description:
This function returns the address of the sub-authority count field of
an SID.
Arguments:
pSid - Pointer to the SID data structure.
Return Value:
Address of the sub-authority count field of an SID.
--*/
{
SetLastError(0);
return RtlSubAuthorityCountSid (
pSid
);
}
DWORD
APIENTRY
GetLengthSid (
PSID pSid
)
/*++
Routine Description:
This routine returns the length, in bytes, of a structurally valid SID.
Arguments:
pSid - Points to the SID whose length is to be returned. The
SID's structure is assumed to be valid.
Return Value:
DWORD - The length, in bytes, of the SID.
--*/
{
SetLastError(0);
return RtlLengthSid (
pSid
);
}
BOOL
APIENTRY
CopySid (
DWORD nDestinationSidLength,
PSID pDestinationSid,
PSID pSourceSid
)
/*++
Routine Description:
This routine copies the value of the source SID to the destination
SID.
Arguments:
nDestinationSidLength - Indicates the length, in bytes, of the
destination SID buffer.
pDestinationSid - Pointer to a buffer to receive a copy of the
source Sid value.
pSourceSid - Supplies the Sid value to be copied.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = RtlCopySid (
nDestinationSidLength,
pDestinationSid,
pSourceSid
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
AreAllAccessesGranted (
DWORD GrantedAccess,
DWORD DesiredAccess
)
/*++
Routine Description:
This routine is used to check a desired access mask against a
granted access mask.
Arguments:
GrantedAccess - Specifies the granted access mask.
DesiredAccess - Specifies the desired access mask.
Return Value:
BOOL - TRUE if the GrantedAccess mask has all the bits set that
the DesiredAccess mask has set. That is, TRUE is returned if
all of the desired accesses have been granted.
--*/
{
return (BOOL) RtlAreAllAccessesGranted (
GrantedAccess,
DesiredAccess
);
}
BOOL
APIENTRY
AreAnyAccessesGranted (
DWORD GrantedAccess,
DWORD DesiredAccess
)
/*++
Routine Description:
This routine is used to test whether any of a set of desired
accesses are granted by a granted access mask.
Arguments:
GrantedAccess - Specifies the granted access mask.
DesiredAccess - Specifies the desired access mask.
Return Value:
BOOL - TRUE if the GrantedAccess mask contains any of the bits
specified in the DesiredAccess mask. That is, if any of the
desired accesses have been granted, TRUE is returned.
--*/
{
return (BOOL) RtlAreAnyAccessesGranted (
GrantedAccess,
DesiredAccess
);
}
VOID
APIENTRY
MapGenericMask (
PDWORD AccessMask,
PGENERIC_MAPPING GenericMapping
)
/*++
Routine Description:
This routine maps all generic accesses in the provided access mask
to specific and standard accesses according to the provided
GenericMapping. The resulting mask will not have any of the
generic bits set (GenericRead, GenericWrite, GenericExecute, or
GenericAll) or any undefined bits set, but may have any other bit
set. If bits other than the generic bits are provided on input,
they will not be cleared bt the mapping.
Arguments:
AccessMask - Points to the access mask to be mapped.
GenericMapping - The mapping of generic to specific and standard
access types.
Return Value:
None.
--*/
{
RtlMapGenericMask (
AccessMask,
GenericMapping
);
}
BOOL
APIENTRY
IsValidAcl (
PACL pAcl
)
/*++
Routine Description:
This procedure validates an ACL.
This involves validating the revision level of the ACL and ensuring
that the number of ACEs specified in the AceCount fit in the space
specified by the AclSize field of the ACL header.
Arguments:
pAcl - Pointer to the ACL structure to validate.
Return Value:
BOOLEAN - TRUE if the structure of Acl is valid.
--*/
{
if ( !RtlValidAcl( pAcl ) ) {
SetLastError(ERROR_INVALID_ACL);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
InitializeAcl (
PACL pAcl,
DWORD nAclLength,
DWORD dwAclRevision
)
/*++
Routine Description:
InitializeAcl creates a new ACL in the caller supplied memory
buffer. The ACL contains zero ACEs; therefore, it is an empty ACL
as opposed to a nonexistent ACL. That is, if the ACL is now set
to an object it will implicitly deny access to everyone.
Arguments:
pAcl - Supplies the buffer containing the ACL being initialized
nAclLength - Supplies the length of the ace buffer in bytes
dwAclRevision - Supplies the revision for this Acl
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = RtlCreateAcl (
pAcl,
nAclLength,
dwAclRevision
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
GetAclInformation (
PACL pAcl,
PVOID pAclInformation,
DWORD nAclInformationLength,
ACL_INFORMATION_CLASS dwAclInformationClass
)
/*++
Routine Description:
This routine returns to the caller information about an ACL. The requested
information can be AclRevisionInformation, or AclSizeInformation.
Arguments:
pAcl - Supplies the Acl being examined
pAclInformation - Supplies the buffer to receive the information
being requested
nAclInformationLength - Supplies the length of the AclInformation
buffer in bytes
dwAclInformationClass - Supplies the type of information being
requested
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = RtlQueryInformationAcl (
pAcl,
pAclInformation,
nAclInformationLength,
dwAclInformationClass
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
SetAclInformation (
PACL pAcl,
PVOID pAclInformation,
DWORD nAclInformationLength,
ACL_INFORMATION_CLASS dwAclInformationClass
)
/*++
Routine Description:
This routine sets the state of an ACL. For now only the revision
level can be set and for now only a revision level of 1 is accepted
so this procedure is rather simple
Arguments:
pAcl - Supplies the Acl being altered
pAclInformation - Supplies the buffer containing the information
being set
nAclInformationLength - Supplies the length of the Acl information
buffer
dwAclInformationClass - Supplies the type of information begin set
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = RtlSetInformationAcl (
pAcl,
pAclInformation,
nAclInformationLength,
dwAclInformationClass
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
AddAce (
PACL pAcl,
DWORD dwAceRevision,
DWORD dwStartingAceIndex,
PVOID pAceList,
DWORD nAceListLength
)
/*++
Routine Description:
This routine adds a string of ACEs to an ACL.
Arguments:
pAcl - Supplies the Acl being modified
dwAceRevision - Supplies the Acl/Ace revision of the ACE being
added
dwStartingAceIndex - Supplies the ACE index which will be the
index of the first ace inserted in the acl. 0 for the
beginning of the list and MAXULONG for the end of the list.
pAceList - Supplies the list of Aces to be added to the Acl
nAceListLength - Supplies the size, in bytes, of the AceList
buffer
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = RtlAddAce (
pAcl,
dwAceRevision,
dwStartingAceIndex,
pAceList,
nAceListLength
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
DeleteAce (
PACL pAcl,
DWORD dwAceIndex
)
/*++
Routine Description:
This routine deletes one ACE from an ACL.
Arguments:
pAcl - Supplies the Acl being modified
dwAceIndex - Supplies the index of the Ace to delete.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = RtlDeleteAce (
pAcl,
dwAceIndex
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
GetAce (
PACL pAcl,
DWORD dwAceIndex,
PVOID *pAce
)
/*++
Routine Description:
This routine returns a pointer to an ACE in an ACl referenced by
ACE index
Arguments:
pAcl - Supplies the ACL being queried
dwAceIndex - Supplies the Ace index to locate
pAce - Receives the address of the ACE within the ACL
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = RtlGetAce (
pAcl,
dwAceIndex,
pAce
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
AddAccessAllowedAce (
PACL pAcl,
DWORD dwAceRevision,
DWORD AccessMask,
PSID pSid
)
/*++
Routine Description:
This routine adds an ACCESS_ALLOWED ACE to an ACL. This is
expected to be a common form of ACL modification.
A very bland ACE header is placed in the ACE. It provides no
inheritance and no ACE flags.
Arguments:
PAcl - Supplies the Acl being modified
dwAceRevision - Supplies the Acl/Ace revision of the ACE being added
AccessMask - The mask of accesses to be granted to the specified SID.
pSid - Pointer to the SID being granted access.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = RtlAddAccessAllowedAce (
pAcl,
dwAceRevision,
AccessMask,
pSid
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
AddAccessAllowedAceEx (
PACL pAcl,
DWORD dwAceRevision,
DWORD AceFlags,
DWORD AccessMask,
PSID pSid
)
/*++
Routine Description:
This routine adds an ACCESS_ALLOWED ACE to an ACL. This is
expected to be a common form of ACL modification.
A very bland ACE header is placed in the ACE. The AceFlags and
inheritance are specified by the AceFlags parameter.
Arguments:
PAcl - Supplies the Acl being modified
dwAceRevision - Supplies the Acl/Ace revision of the ACE being added
AceFlags - Supplies the inherit flags for the ACE.
AccessMask - The mask of accesses to be granted to the specified SID.
pSid - Pointer to the SID being granted access.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = RtlAddAccessAllowedAceEx (
pAcl,
dwAceRevision,
AceFlags,
AccessMask,
pSid
);
if ( !NT_SUCCESS(Status) ) {
if ( Status == STATUS_INVALID_PARAMETER ) {
SetLastError( ERROR_INVALID_FLAGS );
} else {
BaseSetLastNTError(Status);
}
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
AddAccessDeniedAce (
PACL pAcl,
DWORD dwAceRevision,
DWORD AccessMask,
PSID pSid
)
/*++
Routine Description:
This routine adds an ACCESS_DENIED ACE to an ACL. This is
expected to be a common form of ACL modification.
A very bland ACE header is placed in the ACE. It provides no
inheritance and no ACE flags.
Arguments:
pAcl - Supplies the Acl being modified
dwAceRevision - Supplies the Acl/Ace revision of the ACE being added
AccessMask - The mask of accesses to be denied to the specified SID.
pSid - Pointer to the SID being denied access.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = RtlAddAccessDeniedAce (
pAcl,
dwAceRevision,
AccessMask,
pSid
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
AddAccessDeniedAceEx (
PACL pAcl,
DWORD dwAceRevision,
DWORD AceFlags,
DWORD AccessMask,
PSID pSid
)
/*++
Routine Description:
This routine adds an ACCESS_DENIED ACE to an ACL. This is
expected to be a common form of ACL modification.
A very bland ACE header is placed in the ACE. The AceFlags and
inheritance are specified by the AceFlags parameter.
Arguments:
pAcl - Supplies the Acl being modified
dwAceRevision - Supplies the Acl/Ace revision of the ACE being added
AceFlags - Supplies the inherit flags for the ACE.
AccessMask - The mask of accesses to be denied to the specified SID.
pSid - Pointer to the SID being denied access.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = RtlAddAccessDeniedAceEx (
pAcl,
dwAceRevision,
AceFlags,
AccessMask,
pSid
);
if ( !NT_SUCCESS(Status) ) {
if ( Status == STATUS_INVALID_PARAMETER ) {
SetLastError( ERROR_INVALID_FLAGS );
} else {
BaseSetLastNTError(Status);
}
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
AddAuditAccessAce(
PACL pAcl,
DWORD dwAceRevision,
DWORD dwAccessMask,
PSID pSid,
BOOL bAuditSuccess,
BOOL bAuditFailure
)
/*++
Routine Description:
This routine adds a SYSTEM_AUDIT ACE to an ACL. This is
expected to be a common form of ACL modification.
A very bland ACE header is placed in the ACE. It provides no
inheritance.
Parameters are used to indicate whether auditing is to be performed
on success, failure, or both.
Arguments:
pAcl - Supplies the Acl being modified
dwAceRevision - Supplies the Acl/Ace revision of the ACE being added
dwAccessMask - The mask of accesses to be denied to the specified SID.
pSid - Pointer to the SID to be audited.
bAuditSuccess - If TRUE, indicates successful access attempts are to be
audited.
bAuditFailure - If TRUE, indicated failed access attempts are to be
audited.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = RtlAddAuditAccessAce (
pAcl,
dwAceRevision,
dwAccessMask,
pSid,
(BOOLEAN)bAuditSuccess,
(BOOLEAN)bAuditFailure
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
AddAuditAccessAceEx(
PACL pAcl,
DWORD dwAceRevision,
DWORD AceFlags,
DWORD dwAccessMask,
PSID pSid,
BOOL bAuditSuccess,
BOOL bAuditFailure
)
/*++
Routine Description:
This routine adds a SYSTEM_AUDIT ACE to an ACL. This is
expected to be a common form of ACL modification.
A very bland ACE header is placed in the ACE. The AceFlags and
inheritance are specified by the AceFlags parameter.
Parameters are used to indicate whether auditing is to be performed
on success, failure, or both.
Arguments:
pAcl - Supplies the Acl being modified
dwAceRevision - Supplies the Acl/Ace revision of the ACE being added
AceFlags - Supplies the inherit flags for the ACE.
dwAccessMask - The mask of accesses to be denied to the specified SID.
pSid - Pointer to the SID to be audited.
bAuditSuccess - If TRUE, indicates successful access attempts are to be
audited.
bAuditFailure - If TRUE, indicated failed access attempts are to be
audited.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = RtlAddAuditAccessAceEx (
pAcl,
dwAceRevision,
AceFlags,
dwAccessMask,
pSid,
(BOOLEAN)bAuditSuccess,
(BOOLEAN)bAuditFailure
);
if ( !NT_SUCCESS(Status) ) {
if ( Status == STATUS_INVALID_PARAMETER ) {
SetLastError( ERROR_INVALID_FLAGS );
} else {
BaseSetLastNTError(Status);
}
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
AddAccessAllowedObjectAce (
PACL pAcl,
DWORD dwAceRevision,
DWORD AceFlags,
DWORD AccessMask,
GUID *ObjectTypeGuid,
GUID *InheritedObjectTypeGuid,
PSID pSid
)
/*++
Routine Description:
This routine adds an ACCESS_ALLOWED_OBJECT ACE to an ACL. This is
expected to be a common form of ACL modification.
A very bland ACE header is placed in the ACE.
Arguments:
PAcl - Supplies the Acl being modified
dwAceRevision - Supplies the Acl/Ace revision of the ACE being added
AceFlags - Supplies the inherit flags for the ACE.
AccessMask - The mask of accesses to be granted to the specified SID.
ObjectTypeGuid - Supplies the GUID of the object this ACE applies to.
If NULL, no object type GUID is placed in the ACE.
InheritedObjectTypeGuid - Supplies the GUID of the object type that will
inherit this ACE. If NULL, no inherited object type GUID is placed in
the ACE.
pSid - Pointer to the SID being granted access.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = RtlAddAccessAllowedObjectAce (
pAcl,
dwAceRevision,
AceFlags,
AccessMask,
ObjectTypeGuid,
InheritedObjectTypeGuid,
pSid
);
if ( !NT_SUCCESS(Status) ) {
if ( Status == STATUS_INVALID_PARAMETER ) {
SetLastError( ERROR_INVALID_FLAGS );
} else {
BaseSetLastNTError(Status);
}
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
AddAccessDeniedObjectAce (
PACL pAcl,
DWORD dwAceRevision,
DWORD AceFlags,
DWORD AccessMask,
GUID *ObjectTypeGuid,
GUID *InheritedObjectTypeGuid,
PSID pSid
)
/*++
Routine Description:
This routine adds an ACCESS_DENIED_OBJECT ACE to an ACL. This is
expected to be a common form of ACL modification.
A very bland ACE header is placed in the ACE.
Arguments:
PAcl - Supplies the Acl being modified
dwAceRevision - Supplies the Acl/Ace revision of the ACE being added
AceFlags - Supplies the inherit flags for the ACE.
AccessMask - The mask of accesses to be granted to the specified SID.
ObjectTypeGuid - Supplies the GUID of the object this ACE applies to.
If NULL, no object type GUID is placed in the ACE.
InheritedObjectTypeGuid - Supplies the GUID of the object type that will
inherit this ACE. If NULL, no inherited object type GUID is placed in
the ACE.
pSid - Pointer to the SID being denied access.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = RtlAddAccessDeniedObjectAce (
pAcl,
dwAceRevision,
AceFlags,
AccessMask,
ObjectTypeGuid,
InheritedObjectTypeGuid,
pSid
);
if ( !NT_SUCCESS(Status) ) {
if ( Status == STATUS_INVALID_PARAMETER ) {
SetLastError( ERROR_INVALID_FLAGS );
} else {
BaseSetLastNTError(Status);
}
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
AddAuditAccessObjectAce(
PACL pAcl,
DWORD dwAceRevision,
DWORD AceFlags,
DWORD dwAccessMask,
GUID *ObjectTypeGuid,
GUID *InheritedObjectTypeGuid,
PSID pSid,
BOOL bAuditSuccess,
BOOL bAuditFailure
)
/*++
Routine Description:
This routine adds a SYSTEM_AUDIT_OBJECT_ACE to an ACL. This is
expected to be a common form of ACL modification.
A very bland ACE header is placed in the ACE. The AceFlags and
inheritance are specified by the AceFlags parameter.
Parameters are used to indicate whether auditing is to be performed
on success, failure, or both.
Arguments:
pAcl - Supplies the Acl being modified
dwAceRevision - Supplies the Acl/Ace revision of the ACE being added
AceFlags - Supplies the inherit flags for the ACE.
dwAccessMask - The mask of accesses to be denied to the specified SID.
ObjectTypeGuid - Supplies the GUID of the object this ACE applies to.
If NULL, no object type GUID is placed in the ACE.
InheritedObjectTypeGuid - Supplies the GUID of the object type that will
inherit this ACE. If NULL, no inherited object type GUID is placed in
the ACE.
pSid - Pointer to the SID to be audited.
bAuditSuccess - If TRUE, indicates successful access attempts are to be
audited.
bAuditFailure - If TRUE, indicated failed access attempts are to be
audited.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = RtlAddAuditAccessObjectAce (
pAcl,
dwAceRevision,
AceFlags,
dwAccessMask,
ObjectTypeGuid,
InheritedObjectTypeGuid,
pSid,
(BOOLEAN)bAuditSuccess,
(BOOLEAN)bAuditFailure
);
if ( !NT_SUCCESS(Status) ) {
if ( Status == STATUS_INVALID_PARAMETER ) {
SetLastError( ERROR_INVALID_FLAGS );
} else {
BaseSetLastNTError(Status);
}
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
FindFirstFreeAce (
PACL pAcl,
PVOID *pAce
)
/*++
Routine Description:
This routine returns a pointer to the first free byte in an Acl
or NULL if the acl is ill-formed. If the Acl is full then the
return pointer is to the byte immediately following the acl, and
TRUE will be returned.
Arguments:
pAcl - Supplies a pointer to the Acl to examine
pAce - Receives a pointer to the first free position in the Acl
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
if ( !RtlFirstFreeAce( pAcl, pAce ) ) {
SetLastError(ERROR_INVALID_ACL);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
InitializeSecurityDescriptor (
PSECURITY_DESCRIPTOR pSecurityDescriptor,
DWORD dwRevision
)
/*++
Routine Description:
This procedure initializes a new "absolute format" security descriptor.
After the procedure call the security descriptor is initialized with no
system ACL, no discretionary ACL, no owner, no primary group and
all control flags set to false (null).
Arguments:
pSecurityDescriptor - Supplies the security descriptor to
initialize.
dwRevision - Provides the revision level to assign to the security
descriptor. This should be one (1) for this release.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = RtlCreateSecurityDescriptor (
pSecurityDescriptor,
dwRevision
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
IsValidSecurityDescriptor (
PSECURITY_DESCRIPTOR pSecurityDescriptor
)
/*++
Routine Description:
This procedure validates a SecurityDescriptor's structure. This
involves validating the revision levels of each component of the
security descriptor.
Arguments:
pSecurityDescriptor - Pointer to the SECURITY_DESCRIPTOR structure
to validate.
Return Value:
BOOL - TRUE if the structure of SecurityDescriptor is valid.
--*/
{
if (!RtlValidSecurityDescriptor ( pSecurityDescriptor )) {
BaseSetLastNTError( STATUS_INVALID_SECURITY_DESCR );
return( FALSE );
}
return( TRUE );
}
DWORD
APIENTRY
GetSecurityDescriptorLength (
PSECURITY_DESCRIPTOR pSecurityDescriptor
)
/*++
Routine Description:
This routine returns the length, in bytes, necessary to capture a
structurally valid SECURITY_DESCRIPTOR. The length includes the length
of all associated data structures (like SIDs and ACLs). The length also
takes into account the alignment requirements of each component.
The minimum length of a security descriptor (one which has no associated
SIDs or ACLs) is SECURITY_DESCRIPTOR_MIN_LENGTH.
Arguments:
pSecurityDescriptor - Points to the SECURITY_DESCRIPTOR whose
length is to be returned. The SECURITY_DESCRIPTOR's structure
is assumed to be valid.
Return Value:
DWORD - The length, in bytes, of the SECURITY_DESCRIPTOR.
--*/
{
return RtlLengthSecurityDescriptor (
pSecurityDescriptor
);
}
BOOL
APIENTRY
GetSecurityDescriptorControl (
PSECURITY_DESCRIPTOR pSecurityDescriptor,
PSECURITY_DESCRIPTOR_CONTROL pControl,
LPDWORD lpdwRevision
)
/*++
Routine Description:
This procedure retrieves the control information from a security descriptor.
Arguments:
pSecurityDescriptor - Supplies the security descriptor.
pControl - Receives the control information.
lpdwRevision - Receives the revision of the security descriptor.
This value will always be returned, even if an error is
returned by this routine.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = RtlGetControlSecurityDescriptor (
pSecurityDescriptor,
pControl,
lpdwRevision
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
SetSecurityDescriptorControl (
PSECURITY_DESCRIPTOR pSecurityDescriptor,
SECURITY_DESCRIPTOR_CONTROL ControlBitsOfInterest,
SECURITY_DESCRIPTOR_CONTROL ControlBitsToSet
)
/*++
Routine Description:
This procedure sets the control information in a security descriptor.
For instance,
SetSecurityDescriptorControl( &SecDesc,
SE_DACL_PROTECTED,
SE_DACL_PROTECTED );
marks the DACL on the security descriptor as protected. And
SetSecurityDescriptorControl( &SecDesc,
SE_DACL_PROTECTED,
0 );
marks the DACL as not protected.
Arguments:
pSecurityDescriptor - Supplies the security descriptor.
ControlBitsOfInterest - A mask of the control bits being changed, set,
or reset by this call. The mask is the logical OR of one or more of
the following flags:
SE_DACL_UNTRUSTED
SE_SERVER_SECURITY
SE_DACL_AUTO_INHERIT_REQ
SE_SACL_AUTO_INHERIT_REQ
SE_DACL_AUTO_INHERITED
SE_SACL_AUTO_INHERITED
SE_DACL_PROTECTED
SE_SACL_PROTECTED
ControlBitsToSet - A mask indicating what the bits specified by ControlBitsOfInterest
should be set to.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = RtlSetControlSecurityDescriptor (
pSecurityDescriptor,
ControlBitsOfInterest,
ControlBitsToSet );
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
SetSecurityDescriptorDacl (
PSECURITY_DESCRIPTOR pSecurityDescriptor,
BOOL bDaclPresent,
PACL pDacl OPTIONAL,
BOOL bDaclDefaulted OPTIONAL
)
/*++
Routine Description:
This procedure sets the discretionary ACL information of an absolute
format security descriptor. If there is already a discretionary ACL
present in the security descriptor, it is superseded.
Arguments:
pSecurityDescriptor - Supplies the security descriptor to be which
the discretionary ACL is to be added.
bDaclPresent - If FALSE, indicates the DaclPresent flag in the
security descriptor should be set to FALSE. In this case, the
remaining optional parameters are ignored. Otherwise, the
DaclPresent control flag in the security descriptor is set to
TRUE and the remaining optional parameters are not ignored.
pDacl - Supplies the discretionary ACL for the security
descriptor. If this optional parameter is not passed, then a
null ACL is assigned to the security descriptor. A null
discretionary ACL unconditionally grants access. The ACL is
referenced by, not copied into, by the security descriptor.
bDaclDefaulted - When set, indicates the discretionary ACL was
picked up from some default mechanism (rather than explicitly
specified by a user). This value is set in the DaclDefaulted
control flag in the security descriptor. If this optional
parameter is not passed, then the DaclDefaulted flag will be
cleared.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = RtlSetDaclSecurityDescriptor (
pSecurityDescriptor,
(BOOLEAN)bDaclPresent,
pDacl,
(BOOLEAN)bDaclDefaulted
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
GetSecurityDescriptorDacl (
PSECURITY_DESCRIPTOR pSecurityDescriptor,
LPBOOL lpbDaclPresent,
PACL *pDacl,
LPBOOL lpbDaclDefaulted
)
/*++
Routine Description:
This procedure retrieves the discretionary ACL information of a
security descriptor.
Arguments:
pSecurityDescriptor - Supplies the security descriptor.
lpbDaclPresent - If TRUE, indicates that the security descriptor
does contain a discretionary ACL. In this case, the
remaining OUT parameters will receive valid values.
Otherwise, the security descriptor does not contain a
discretionary ACL and the remaining OUT parameters will not
receive valid values.
pDacl - This value is returned only if the value returned for the
DaclPresent flag is TRUE. In this case, the Dacl parameter
receives the address of the security descriptor's
discretionary ACL. If this value is returned as null, then
the security descriptor has a null discretionary ACL.
lpbDaclDefaulted - This value is returned only if the value
returned for the DaclPresent flag is TRUE. In this case, the
DaclDefaulted parameter receives the value of the security
descriptor's DaclDefaulted control flag.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
BOOLEAN DaclPresent, DaclDefaulted;
Status = RtlGetDaclSecurityDescriptor (
pSecurityDescriptor,
&DaclPresent,
pDacl,
&DaclDefaulted
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
} else {
*lpbDaclPresent = (BOOL)DaclPresent;
*lpbDaclDefaulted = (BOOL)DaclDefaulted;
}
return TRUE;
}
BOOL
APIENTRY
SetSecurityDescriptorSacl (
PSECURITY_DESCRIPTOR pSecurityDescriptor,
BOOL bSaclPresent,
PACL pSacl OPTIONAL,
BOOL bSaclDefaulted
)
/*++
Routine Description:
This procedure sets the system ACL information of an absolute security
descriptor. If there is already a system ACL present in the
security descriptor, it is superseded.
Arguments:
pSecurityDescriptor - Supplies the security descriptor to be which
the system ACL is to be added.
bSaclPresent - If FALSE, indicates the SaclPresent flag in the
security descriptor should be set to FALSE. In this case,
the remaining optional parameters are ignored. Otherwise,
the SaclPresent control flag in the security descriptor is
set to TRUE and the remaining optional parameters are not
ignored.
pSacl - Supplies the system ACL for the security descriptor. If
this optional parameter is not passed, then a null ACL is
assigned to the security descriptor. The ACL is referenced
by, not copied into, by the security descriptor.
bSaclDefaulted - When set, indicates the system ACL was picked up
from some default mechanism (rather than explicitly specified
by a user). This value is set in the SaclDefaulted control
flag in the security descriptor. If this optional parameter
is not passed, then the SaclDefaulted flag will be cleared.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = RtlSetSaclSecurityDescriptor (
pSecurityDescriptor,
(BOOLEAN)bSaclPresent,
pSacl,
(BOOLEAN)bSaclDefaulted
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
GetSecurityDescriptorSacl (
PSECURITY_DESCRIPTOR pSecurityDescriptor,
LPBOOL lpbSaclPresent,
PACL *pSacl,
LPBOOL lpbSaclDefaulted
)
/*++
Routine Description:
This procedure retrieves the system ACL information of a security
descriptor.
Arguments:
pSecurityDescriptor - Supplies the security descriptor.
lpbSaclPresent - If TRUE, indicates that the security descriptor
does contain a system ACL. In this case, the remaining OUT
parameters will receive valid values. Otherwise, the
security descriptor does not contain a system ACL and the
remaining OUT parameters will not receive valid values.
pSacl - This value is returned only if the value returned for the
SaclPresent flag is TRUE. In this case, the Sacl parameter
receives the address of the security descriptor's system ACL.
If this value is returned as null, then the security
descriptor has a null system ACL.
lpbSaclDefaulted - This value is returned only if the value
returned for the SaclPresent flag is TRUE. In this case, the
SaclDefaulted parameter receives the value of the security
descriptor's SaclDefaulted control flag.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
BOOLEAN SaclPresent, SaclDefaulted;
Status = RtlGetSaclSecurityDescriptor (
pSecurityDescriptor,
&SaclPresent,
pSacl,
&SaclDefaulted
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
} else {
*lpbSaclPresent = (BOOL)SaclPresent;
*lpbSaclDefaulted = (BOOL)SaclDefaulted;
}
return TRUE;
}
BOOL
APIENTRY
SetSecurityDescriptorOwner (
PSECURITY_DESCRIPTOR pSecurityDescriptor,
PSID pOwner OPTIONAL,
BOOL bOwnerDefaulted OPTIONAL
)
/*++
Routine Description:
This procedure sets the owner information of an absolute security
descriptor. If there is already an owner present in the security
descriptor, it is superseded.
Arguments:
pSecurityDescriptor - Supplies the security descriptor in which
the owner is to be set. If the security descriptor already
includes an owner, it will be superseded by the new owner.
pOwner - Supplies the owner SID for the security descriptor. If
this optional parameter is not passed, then the owner is
cleared (indicating the security descriptor has no owner).
The SID is referenced by, not copied into, the security
descriptor.
bOwnerDefaulted - When set, indicates the owner was picked up from
some default mechanism (rather than explicitly specified by a
user). This value is set in the OwnerDefaulted control flag
in the security descriptor. If this optional parameter is
not passed, then the SaclDefaulted flag will be cleared.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = RtlSetOwnerSecurityDescriptor (
pSecurityDescriptor,
pOwner,
(BOOLEAN)bOwnerDefaulted
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
GetSecurityDescriptorOwner (
PSECURITY_DESCRIPTOR pSecurityDescriptor,
PSID *pOwner,
LPBOOL lpbOwnerDefaulted
)
/*++
Routine Description:
This procedure retrieves the owner information of a security
descriptor.
Arguments:
pSecurityDescriptor - Supplies the security descriptor.
pOwner - Receives a pointer to the owner SID. If the security
descriptor does not currently contain an owner, then this
value will be returned as null. In this case, the remaining
OUT parameters are not given valid return values. Otherwise,
this parameter points to an SID and the remaining OUT
parameters are provided valid return values.
lpbOwnerDefaulted - This value is returned only if the value
returned for the Owner parameter is not null. In this case,
the OwnerDefaulted parameter receives the value of the
security descriptor's OwnerDefaulted control flag.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
BOOLEAN OwnerDefaulted;
Status = RtlGetOwnerSecurityDescriptor (
pSecurityDescriptor,
pOwner,
&OwnerDefaulted
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
} else {
*lpbOwnerDefaulted = (BOOL)OwnerDefaulted;
}
return TRUE;
}
BOOL
APIENTRY
SetSecurityDescriptorGroup (
PSECURITY_DESCRIPTOR pSecurityDescriptor,
PSID pGroup OPTIONAL,
BOOL bGroupDefaulted OPTIONAL
)
/*++
Routine Description:
This procedure sets the primary group information of an absolute security
descriptor. If there is already an primary group present in the
security descriptor, it is superseded.
Arguments:
pSecurityDescriptor - Supplies the security descriptor in which
the primary group is to be set. If the security descriptor
already includes a primary group, it will be superseded by
the new group.
pGroup - Supplies the primary group SID for the security
descriptor. If this optional parameter is not passed, then
the primary group is cleared (indicating the security
descriptor has no primary group). The SID is referenced by,
not copied into, the security descriptor.
bGroupDefaulted - When set, indicates the owner was picked up from
some default mechanism (rather than explicitly specified by a
user). This value is set in the OwnerDefaulted control flag
in the security descriptor. If this optional parameter is
not passed, then the SaclDefaulted flag will be cleared.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = RtlSetGroupSecurityDescriptor (
pSecurityDescriptor,
pGroup,
(BOOLEAN)bGroupDefaulted
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
GetSecurityDescriptorGroup (
PSECURITY_DESCRIPTOR pSecurityDescriptor,
PSID *pGroup,
LPBOOL lpbGroupDefaulted
)
/*++
Routine Description:
This procedure retrieves the primary group information of a
security descriptor.
Arguments:
pSecurityDescriptor - Supplies the security descriptor.
pGroup - Receives a pointer to the primary group SID. If the
security descriptor does not currently contain a primary
group, then this value will be returned as null. In this
case, the remaining OUT parameters are not given valid return
values. Otherwise, this parameter points to an SID and the
remaining OUT parameters are provided valid return values.
lpbGroupDefaulted - This value is returned only if the value
returned for the Group parameter is not null. In this case,
the GroupDefaulted parameter receives the value of the
security descriptor's GroupDefaulted control flag.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
BOOLEAN GroupDefaulted;
Status = RtlGetGroupSecurityDescriptor (
pSecurityDescriptor,
pGroup,
&GroupDefaulted
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
} else {
*lpbGroupDefaulted = GroupDefaulted;
}
return TRUE;
}
BOOL
APIENTRY
CreatePrivateObjectSecurity (
PSECURITY_DESCRIPTOR ParentDescriptor OPTIONAL,
PSECURITY_DESCRIPTOR CreatorDescriptor OPTIONAL,
PSECURITY_DESCRIPTOR * NewDescriptor,
BOOL IsDirectoryObject,
HANDLE Token,
PGENERIC_MAPPING GenericMapping
)
/*++
Routine Description:
The procedure is used to allocpate and initialize a self-relative
Security Descriptor for a new protected server's object. It is called
when a new protected server object is being created. The generated
security descriptor will be in self-relative form.
This procedure, called only from user mode, is used to establish a
security descriptor for a new protected server's object. When no
longer needed, this descriptor must be freed using
DestroyPrivateObjectSecurity().
Arguments:
ParentDescriptor - Supplies the Security Descriptor for the parent
directory under which a new object is being created. If there is
no parent directory, then this argument is specified as NULL.
CreatorDescriptor - (Optionally) Points to a security descriptor
presented by the creator of the object. If the creator of the
object did not explicitly pass security information for the new
object, then a null pointer should be passed.
NewDescriptor - Points to a pointer that is to be made to point to the
newly allocated self-relative security descriptor.
IsDirectoryObject - Specifies if the new object is going to be a
directory object. A value of TRUE indicates the object is a
container of other objects.
Token - Supplies the token for the client on whose behalf the
object is being created. If it is an impersonation token,
then it must be at SecurityIdentification level or higher. If
it is not an impersonation token, the operation proceeds
normally.
A client token is used to retrieve default security
information for the new object, such as default owner, primary
group, and discretionary access control. The token must be
open for TOKEN_QUERY access.
GenericMapping - Supplies a pointer to a generic mapping array denoting
the mapping between each generic right to specific rights.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = RtlNewSecurityObject (
ParentDescriptor,
CreatorDescriptor,
NewDescriptor,
(BOOLEAN)IsDirectoryObject,
Token,
GenericMapping
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
ConvertToAutoInheritPrivateObjectSecurity(
PSECURITY_DESCRIPTOR ParentDescriptor OPTIONAL,
PSECURITY_DESCRIPTOR CurrentSecurityDescriptor,
PSECURITY_DESCRIPTOR *NewSecurityDescriptor,
GUID *ObjectType,
BOOLEAN IsDirectoryObject,
PGENERIC_MAPPING GenericMapping
)
/*++
Routine Description:
This is a converts a security descriptor whose ACLs are not marked
as AutoInherit to a security descriptor whose ACLs are marked as
AutoInherit.
The resultant security descriptor has appropriate ACEs marked as
INHERITED_ACE if the ACE was apparently inherited from the ParentDescriptor.
If the ACL is apparently not inherited from the ParentDescriptor, the
ACL in the resultant security descriptor is marked as SE_xACL_PROTECTED.
This routine takes into account the various mechanisms for creating an
inherited ACL:
1) It was inherited via NT 3.x or 4.x ACL inheritance when the
object was created.
2) The subsequent parent or child ACL was re-written by the ACL editor
(which perversely modifies the ACL to a semantically equivalent but
different form).
3) It was inherited by asking the ACL editor (File Manager/Explorer) to
"Replace permissions on existing files/directories".
4) It was inherited via cacls.exe.
If the ACLs in the resultant security descriptor are not marked as protected, the
resultant ACL is composed of two sets of ACEs: the non-inherited ACEs followed by the
inherited ACEs. The inherited ACEs are computed by called CreatePrivateObjectSecurityEx
using the ParentDescriptor. The non-inherited ACEs are those ACEs (or parts of ACEs)
from the original CurrentSecurityDescriptor that were not inherited from the parent.
When building the resultant NewSecurityDescriptor, care is taken to not change the
semantics of the security descriptor. As such, allow and deny ACEs are never moved
in relation to one another. If such movement is needed (for instance to place all
non-inherited ACEs at the front of an ACL), the ACL is marked as protected to prevent
the semantic change.
ACEs in the original CurrentSecurityDescriptor are matched with ACEs in a computed
inherited security descriptor to determine which ACEs were inherited. During the
comparision there is no requirement of a one to one match. For instance, one ACL
might use separate ACEs to grant a user read and write access while the other ACL
might use only one ACE to grant the same access. Or one ACL might grant the user
the same access twice and the other might grant the user that access only once. Or
one ACL might combine the container inherit and object inherit ACE into a single ACE.
In all these case, equivalent ACE combinations are deemed equivalent.
No security checks are made in this routine. The resultant security descriptor
is equivalent to the new security descriptor, so the caller needs no permission to
update the security descriptor to the new form.
The Owner and Group field of the CurrentSecurityDescriptor is maintained.
This routine support revision 2 and revision 4 ACLs. It does not support compound
ACEs.
Arguments:
ParentDescriptor - Supplies the Security Descriptor for the parent
directory under which a object exists. If there is
no parent directory, then this argument is specified as NULL.
CurrentSecurityDescriptor - Supplies a pointer to the objects security descriptor
that is going to be altered by this procedure.
NewSecurityDescriptor Points to a pointer that is to be made to point to the
newly allocated self-relative security descriptor. When no
longer needed, this descriptor must be freed using
DestroyPrivateObjectSecurity().
ObjectType - GUID of the object type being created. If the object being
created has no GUID associated with it, then this argument is
specified as NULL.
IsDirectoryObject - Specifies if the object is a
directory object. A value of TRUE indicates the object is a
container of other objects.
GenericMapping - Supplies a pointer to a generic mapping array denoting
the mapping between each generic right to specific rights.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = RtlConvertToAutoInheritSecurityObject(
ParentDescriptor,
CurrentSecurityDescriptor,
NewSecurityDescriptor,
ObjectType,
IsDirectoryObject,
GenericMapping ) ;
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
CreatePrivateObjectSecurityEx (
PSECURITY_DESCRIPTOR ParentDescriptor,
PSECURITY_DESCRIPTOR CreatorDescriptor,
PSECURITY_DESCRIPTOR * NewDescriptor,
GUID *ObjectType,
BOOL IsContainerObject,
ULONG AutoInheritFlags,
HANDLE Token,
PGENERIC_MAPPING GenericMapping
)
/*++
Routine Description:
The procedure is used to allocate and initialize a self-relative
Security Descriptor for a new protected server's object. It is called
when a new protected server object is being created. The generated
security descriptor will be in self-relative form.
This procedure, called only from user mode, is used to establish a
security descriptor for a new protected server's object.
Arguments:
ParentDescriptor - Supplies the Security Descriptor for the parent
directory under which a new object is being created. If there is
no parent directory, then this argument is specified as NULL.
CreatorDescriptor - (Optionally) Points to a security descriptor
presented by the creator of the object. If the creator of the
object did not explicitly pass security information for the new
object, then a null pointer should be passed.
NewDescriptor - Points to a pointer that is to be made to point to the
newly allocated self-relative security descriptor. When no
longer needed, this descriptor must be freed using
DestroyPrivateObjectSecurity().
ObjectType - GUID of the object type being created. If the object being
created has no GUID associated with it, then this argument is
specified as NULL.
IsContainerObject - Specifies if the new object is going to be a
container object. A value of TRUE indicates the object is a
container of other objects.
AutoInheritFlags - Controls automatic inheritance of ACES from the Parent
Descriptor. Valid values are a bits mask of the logical OR of
one or more of the following bits:
SEF_DACL_AUTO_INHERIT - If set, inherit ACEs from the
DACL ParentDescriptor are inherited to NewDescriptor in addition
to any explicit ACEs specified by the CreatorDescriptor.
SEF_SACL_AUTO_INHERIT - If set, inherit ACEs from the
SACL ParentDescriptor are inherited to NewDescriptor in addition
to any explicit ACEs specified by the CreatorDescriptor.
SEF_DEFAULT_DESCRIPTOR_FOR_OBJECT - If set, the CreatorDescriptor
is the default descriptor for ObjectType. As such, the
CreatorDescriptor will be ignored if any ObjectType specific
ACEs are inherited from the parent. If not such ACEs are inherited,
the CreatorDescriptor is handled as though this flag were not
specified.
SEF_AVOID_PRIVILEGE_CHECK - If set, no privilege checking is done by this
routine. This flag is useful while implementing automatic inheritance
to avoid checking privileges on each child updated.
SEF_AVOID_OWNER_CHECK - If set, no owner checking is done by this routine.
SEF_DEFAULT_OWNER_FROM_PARENT - If set, the owner of NewDescriptor will
default to the owner from ParentDescriptor. If not set, the owner
of NewDescriptor will default to the user specified in Token.
In either case, the owner of NewDescriptor is set to the owner from
the CreatorDescriptor if that field is specified.
SEF_DEFAULT_GROUP_FROM_PARENT - If set, the group of NewDescriptor will
default to the group from ParentDescriptor. If not set, the group
of NewDescriptor will default to the group specified in Token.
In either case, the group of NewDescriptor is set to the group from
the CreatorDescriptor if that field is specified.
Token - Supplies the token for the client on whose behalf the
object is being created. If it is an impersonation token,
then it must be at SecurityIdentification level or higher. If
it is not an impersonation token, the operation proceeds
normally.
A client token is used to retrieve default security
information for the new object, such as default owner, primary
group, and discretionary access control. The token must be
open for TOKEN_QUERY access.
GenericMapping - Supplies a pointer to a generic mapping array denoting
the mapping between each generic right to specific rights.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = RtlNewSecurityObjectEx (
ParentDescriptor,
CreatorDescriptor,
NewDescriptor,
ObjectType,
(BOOLEAN)IsContainerObject,
AutoInheritFlags,
Token,
GenericMapping
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
CreatePrivateObjectSecurityWithMultipleInheritance (
PSECURITY_DESCRIPTOR ParentDescriptor,
PSECURITY_DESCRIPTOR CreatorDescriptor,
PSECURITY_DESCRIPTOR * NewDescriptor,
GUID **ObjectTypes,
ULONG GuidCount,
BOOL IsContainerObject,
ULONG AutoInheritFlags,
HANDLE Token,
PGENERIC_MAPPING GenericMapping
)
/*++
Routine Description:
The procedure is used to allocate and initialize a self-relative
Security Descriptor for a new protected server's object. It is called
when a new protected server object is being created. The generated
security descriptor will be in self-relative form.
This procedure, called only from user mode, is used to establish a
security descriptor for a new protected server's object.
Arguments:
ParentDescriptor - Supplies the Security Descriptor for the parent
directory under which a new object is being created. If there is
no parent directory, then this argument is specified as NULL.
CreatorDescriptor - (Optionally) Points to a security descriptor
presented by the creator of the object. If the creator of the
object did not explicitly pass security information for the new
object, then a null pointer should be passed.
NewDescriptor - Points to a pointer that is to be made to point to the
newly allocated self-relative security descriptor. When no
longer needed, this descriptor must be freed using
DestroyPrivateObjectSecurity().
ObjectTypes - List of GUIDs of the object type being created. If the object being
created has no GUID associated with it, then this argument is
specified as NULL.
GuidCount - Number of guids present in the list.
IsContainerObject - Specifies if the new object is going to be a
container object. A value of TRUE indicates the object is a
container of other objects.
AutoInheritFlags - Controls automatic inheritance of ACES from the Parent
Descriptor. Valid values are a bits mask of the logical OR of
one or more of the following bits:
SEF_DACL_AUTO_INHERIT - If set, inherit ACEs from the
DACL ParentDescriptor are inherited to NewDescriptor in addition
to any explicit ACEs specified by the CreatorDescriptor.
SEF_SACL_AUTO_INHERIT - If set, inherit ACEs from the
SACL ParentDescriptor are inherited to NewDescriptor in addition
to any explicit ACEs specified by the CreatorDescriptor.
SEF_DEFAULT_DESCRIPTOR_FOR_OBJECT - If set, the CreatorDescriptor
is the default descriptor for ObjectType. As such, the
CreatorDescriptor will be ignored if any ObjectType specific
ACEs are inherited from the parent. If not such ACEs are inherited,
the CreatorDescriptor is handled as though this flag were not
specified.
SEF_AVOID_PRIVILEGE_CHECK - If set, no privilege checking is done by this
routine. This flag is useful while implementing automatic inheritance
to avoid checking privileges on each child updated.
SEF_AVOID_OWNER_CHECK - If set, no owner checking is done by this routine.
SEF_DEFAULT_OWNER_FROM_PARENT - If set, the owner of NewDescriptor will
default to the owner from ParentDescriptor. If not set, the owner
of NewDescriptor will default to the user specified in Token.
In either case, the owner of NewDescriptor is set to the owner from
the CreatorDescriptor if that field is specified.
SEF_DEFAULT_GROUP_FROM_PARENT - If set, the group of NewDescriptor will
default to the group from ParentDescriptor. If not set, the group
of NewDescriptor will default to the group specified in Token.
In either case, the group of NewDescriptor is set to the group from
the CreatorDescriptor if that field is specified.
Token - Supplies the token for the client on whose behalf the
object is being created. If it is an impersonation token,
then it must be at SecurityIdentification level or higher. If
it is not an impersonation token, the operation proceeds
normally.
A client token is used to retrieve default security
information for the new object, such as default owner, primary
group, and discretionary access control. The token must be
open for TOKEN_QUERY access.
GenericMapping - Supplies a pointer to a generic mapping array denoting
the mapping between each generic right to specific rights.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = RtlNewSecurityObjectWithMultipleInheritance (
ParentDescriptor,
CreatorDescriptor,
NewDescriptor,
ObjectTypes,
GuidCount,
(BOOLEAN)IsContainerObject,
AutoInheritFlags,
Token,
GenericMapping
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
SetPrivateObjectSecurity (
SECURITY_INFORMATION SecurityInformation,
PSECURITY_DESCRIPTOR ModificationDescriptor,
PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,
PGENERIC_MAPPING GenericMapping,
HANDLE Token OPTIONAL
)
/*++
Routine Description:
Modify an object's existing self-relative form security descriptor.
This procedure, called only from user mode, is used to update a
security descriptor on an existing protected server's object. It
applies changes requested by a new security descriptor to the existing
security descriptor. If necessary, this routine will allocate
additional memory to produce a larger security descriptor. All access
checking is expected to be done before calling this routine. This
includes checking for WRITE_OWNER, WRITE_DAC, and privilege to assign a
system ACL as appropriate.
The caller of this routine must not be impersonating a client.
Arguments:
SecurityInformation - Indicates which security information is
to be applied to the object. The value(s) to be assigned are
passed in the ModificationDescriptor parameter.
ModificationDescriptor - Supplies the input security descriptor to be
applied to the object. The caller of this routine is expected
to probe and capture the passed security descriptor before calling
and release it after calling.
ObjectsSecurityDescriptor - Supplies the address of a pointer to
the objects security descriptor that is going to be altered by
this procedure. This security descriptor must be in self-
relative form or an error will be returned.
GenericMapping - This argument provides the mapping of generic to
specific/standard access types for the object being accessed.
This mapping structure is expected to be safe to access
(i.e., captured if necessary) prior to be passed to this routine.
Token - (optionally) Supplies the token for the client on whose
behalf the security is being modified. This parameter is only
required to ensure that the client has provided a legitimate
value for a new owner SID. The token must be open for
TOKEN_QUERY access.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = RtlSetSecurityObject (
SecurityInformation,
ModificationDescriptor,
ObjectsSecurityDescriptor,
GenericMapping,
Token
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
SetPrivateObjectSecurityEx (
SECURITY_INFORMATION SecurityInformation,
PSECURITY_DESCRIPTOR ModificationDescriptor,
PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,
ULONG AutoInheritFlags,
PGENERIC_MAPPING GenericMapping,
HANDLE Token OPTIONAL
)
/*++
Routine Description:
Modify an object's existing self-relative form security descriptor.
This procedure, called only from user mode, is used to update a
security descriptor on an existing protected server's object. It
applies changes requested by a new security descriptor to the existing
security descriptor. If necessary, this routine will allocate
additional memory to produce a larger security descriptor. All access
checking is expected to be done before calling this routine. This
includes checking for WRITE_OWNER, WRITE_DAC, and privilege to assign a
system ACL as appropriate.
The caller of this routine must not be impersonating a client.
Arguments:
SecurityInformation - Indicates which security information is
to be applied to the object. The value(s) to be assigned are
passed in the ModificationDescriptor parameter.
ModificationDescriptor - Supplies the input security descriptor to be
applied to the object. The caller of this routine is expected
to probe and capture the passed security descriptor before calling
and release it after calling.
ObjectsSecurityDescriptor - Supplies the address of a pointer to
the objects security descriptor that is going to be altered by
this procedure. This security descriptor must be in self-
relative form or an error will be returned.
AutoInheritFlags - Controls automatic inheritance of ACES.
Valid values are a bits mask of the logical OR of
one or more of the following bits:
SEF_DACL_AUTO_INHERIT - If set, inherited ACEs from the
DACL in the ObjectsSecurityDescriptor are preserved and inherited ACEs from
the ModificationDescriptor are ignored. Inherited ACEs are not supposed
to be modified; so preserving them across this call is appropriate.
If a protected server does not itself implement auto inheritance, it should
not set this bit. The caller of the protected server may implement
auto inheritance and my indeed be modifying inherited ACEs.
SEF_SACL_AUTO_INHERIT - If set, inherited ACEs from the
SACL in the ObjectsSecurityDescriptor are preserved and inherited ACEs from
the ModificationDescriptor are ignored. Inherited ACEs are not supposed
to be modified; so preserving them across this call is appropriate.
If a protected server does not itself implement auto inheritance, it should
not set this bit. The caller of the protected server may implement
auto inheritance and my indeed be modifying inherited ACEs.
GenericMapping - This argument provides the mapping of generic to
specific/standard access types for the object being accessed.
This mapping structure is expected to be safe to access
(i.e., captured if necessary) prior to be passed to this routine.
Token - (optionally) Supplies the token for the client on whose
behalf the security is being modified. This parameter is only
required to ensure that the client has provided a legitimate
value for a new owner SID. The token must be open for
TOKEN_QUERY access.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = RtlSetSecurityObjectEx (
SecurityInformation,
ModificationDescriptor,
ObjectsSecurityDescriptor,
AutoInheritFlags,
GenericMapping,
Token
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
GetPrivateObjectSecurity (
PSECURITY_DESCRIPTOR ObjectDescriptor,
SECURITY_INFORMATION SecurityInformation,
PSECURITY_DESCRIPTOR ResultantDescriptor,
DWORD DescriptorLength,
PDWORD ReturnLength
)
/*++
Routine Description:
Query information from a protected server object's existing security
descriptor.
This procedure, called only from user mode, is used to retrieve
information from a security descriptor on an existing protected
server's object. All access checking is expected to be done before
calling this routine. This includes checking for READ_CONTROL, and
privilege to read a system ACL as appropriate.
Arguments:
ObjectDescriptor - Points to a pointer to a security descriptor to be
queried.
SecurityInformation - Identifies the security information being
requested.
ResultantDescriptor - Points to buffer to receive the resultant
security descriptor. The resultant security descriptor will
contain all information requested by the SecurityInformation
parameter.
DescriptorLength - Is an unsigned integer which indicates the length,
in bytes, of the buffer provided to receive the resultant
descriptor.
ReturnLength - Receives an unsigned integer indicating the actual
number of bytes needed in the ResultantDescriptor to store the
requested information. If the value returned is greater than the
value passed via the DescriptorLength parameter, then
STATUS_BUFFER_TOO_SMALL is returned and no information is returned.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = RtlQuerySecurityObject (
ObjectDescriptor,
SecurityInformation,
ResultantDescriptor,
DescriptorLength,
ReturnLength
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
DestroyPrivateObjectSecurity (
PSECURITY_DESCRIPTOR * ObjectDescriptor
)
/*++
Routine Description:
Delete a protected server object's security descriptor.
This procedure, called only from user mode, is used to delete a
security descriptor associated with a protected server's object. This
routine will normally be called by a protected server during object
deletion. The input descriptor is expected to be one created via
a call to CreatePrivateObjectSecurity.
Arguments:
ObjectDescriptor - Points to a pointer to a security descriptor to be
deleted.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = RtlDeleteSecurityObject (
ObjectDescriptor
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
MakeSelfRelativeSD (
PSECURITY_DESCRIPTOR pAbsoluteSecurityDescriptor,
PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor,
LPDWORD lpdwBufferLength
)
/*++
Routine Description:
Converts a security descriptor in absolute form to one in self-relative
form.
Arguments:
pAbsoluteSecurityDescriptor - Pointer to an absolute format
security descriptor. This descriptor will not be modified.
pSelfRelativeSecurityDescriptor - Pointer to a buffer that will
contain the returned self-relative security descriptor.
lpdwBufferLength - Supplies the length of the buffer. If the
supplied buffer is not large enough to hold the self-relative
security descriptor, an error will be returned, and this field
will return the minimum size required.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = RtlAbsoluteToSelfRelativeSD (
pAbsoluteSecurityDescriptor,
pSelfRelativeSecurityDescriptor,
lpdwBufferLength
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
MakeAbsoluteSD (
PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor,
PSECURITY_DESCRIPTOR pAbsoluteSecurityDescriptor,
LPDWORD lpdwAbsoluteSecurityDescriptorSize,
PACL pDacl,
LPDWORD lpdwDaclSize,
PACL pSacl,
LPDWORD lpdwSaclSize,
PSID pOwner,
LPDWORD lpdwOwnerSize,
PSID pPrimaryGroup,
LPDWORD lpdwPrimaryGroupSize
)
/*++
Routine Description:
Converts a security descriptor from self-relative format to absolute
format
Arguments:
pSecurityDescriptor - Supplies a pointer to a security descriptor
in Self-Relative format
pAbsoluteSecurityDescriptor - A pointer to a buffer in which will
be placed the main body of the Absolute format security
descriptor.
lpdwAbsoluteSecurityDescriptorSize - The size in bytes of the
buffer pointed to by pAbsoluteSecurityDescriptor.
pDacl - Supplies a pointer to a buffer that will contain the Dacl
of the output descriptor. This pointer will be referenced by,
not copied into, the output descriptor.
lpdwDaclSize - Supplies the size of the buffer pointed to by Dacl.
In case of error, it will return the minimum size necessary to
contain the Dacl.
pSacl - Supplies a pointer to a buffer that will contain the Sacl
of the output descriptor. This pointer will be referenced by,
not copied into, the output descriptor.
lpdwSaclSize - Supplies the size of the buffer pointed to by Sacl.
In case of error, it will return the minimum size necessary to
contain the Sacl.
pOwner - Supplies a pointer to a buffer that will contain the
Owner of the output descriptor. This pointer will be
referenced by, not copied into, the output descriptor.
lpdwOwnerSize - Supplies the size of the buffer pointed to by
Owner. In case of error, it will return the minimum size
necessary to contain the Owner.
pPrimaryGroup - Supplies a pointer to a buffer that will contain
the PrimaryGroup of the output descriptor. This pointer will
be referenced by, not copied into, the output descriptor.
lpdwPrimaryGroupSize - Supplies the size of the buffer pointed to
by PrimaryGroup. In case of error, it will return the minimum
size necessary to contain the PrimaryGroup.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = RtlSelfRelativeToAbsoluteSD (
pSelfRelativeSecurityDescriptor,
pAbsoluteSecurityDescriptor,
lpdwAbsoluteSecurityDescriptorSize,
pDacl,
lpdwDaclSize,
pSacl,
lpdwSaclSize,
pOwner,
lpdwOwnerSize,
pPrimaryGroup,
lpdwPrimaryGroupSize
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
VOID
SetSecurityAccessMask(
IN SECURITY_INFORMATION SecurityInformation,
OUT LPDWORD DesiredAccess
)
/*++
Routine Description:
This routine builds an access mask representing the accesses necessary
to set the object security information specified in the SecurityInformation
parameter. While it is not difficult to determine this information,
the use of a single routine to generate it will ensure minimal impact
when the security information associated with an object is extended in
the future (to include mandatory access control information).
Arguments:
SecurityInformation - Identifies the object's security information to be
modified.
DesiredAccess - Points to an access mask to be set to represent the
accesses necessary to modify the information specified in the
SecurityInformation parameter.
Return Value:
None.
--*/
{
//
// Figure out accesses needed to perform the indicated operation(s).
//
(*DesiredAccess) = 0;
if ((SecurityInformation & OWNER_SECURITY_INFORMATION) ||
(SecurityInformation & GROUP_SECURITY_INFORMATION) ) {
(*DesiredAccess) |= WRITE_OWNER;
}
if (SecurityInformation & DACL_SECURITY_INFORMATION) {
(*DesiredAccess) |= WRITE_DAC;
}
if (SecurityInformation & SACL_SECURITY_INFORMATION) {
(*DesiredAccess) |= ACCESS_SYSTEM_SECURITY;
}
return;
}
VOID
QuerySecurityAccessMask(
IN SECURITY_INFORMATION SecurityInformation,
OUT LPDWORD DesiredAccess
)
/*++
Routine Description:
This routine builds an access mask representing the accesses necessary
to query the object security information specified in the
SecurityInformation parameter. While it is not difficult to determine
this information, the use of a single routine to generate it will ensure
minimal impact when the security information associated with an object is
extended in the future (to include mandatory access control information).
Arguments:
SecurityInformation - Identifies the object's security information to be
queried.
DesiredAccess - Points to an access mask to be set to represent the
accesses necessary to query the information specified in the
SecurityInformation parameter.
Return Value:
None.
--*/
{
//
// Figure out accesses needed to perform the indicated operation(s).
//
(*DesiredAccess) = 0;
if ((SecurityInformation & OWNER_SECURITY_INFORMATION) ||
(SecurityInformation & GROUP_SECURITY_INFORMATION) ||
(SecurityInformation & DACL_SECURITY_INFORMATION)) {
(*DesiredAccess) |= READ_CONTROL;
}
if ((SecurityInformation & SACL_SECURITY_INFORMATION)) {
(*DesiredAccess) |= ACCESS_SYSTEM_SECURITY;
}
return;
}
BOOL
APIENTRY
SetFileSecurityW(
LPCWSTR lpFileName,
SECURITY_INFORMATION SecurityInformation,
PSECURITY_DESCRIPTOR pSecurityDescriptor
)
/*++
Routine Description:
This API can be used to set the security of a file or directory
(process, file, event, etc.). This call is only successful if the
following conditions are met:
o If the object's owner or group is to be set, the caller must
have WRITE_OWNER permission or have SeTakeOwnershipPrivilege.
o If the object's DACL is to be set, the caller must have
WRITE_DAC permission or be the object's owner.
o If the object's SACL is to be set, the caller must have
SeSecurityPrivilege.
Arguments:
lpFileName - Supplies the file name of the file to open. Depending on
the value of the FailIfExists parameter, this name may or may
not already exist.
SecurityInformation - A pointer to information describing the
contents of the Security Descriptor.
pSecurityDescriptor - A pointer to a well formed Security
Descriptor.
Return Value:
TRUE - The operation was successful.
FALSE/NULL - The operation failed. Extended error status is available
using GetLastError.
--*/
{
NTSTATUS Status;
HANDLE FileHandle;
ACCESS_MASK DesiredAccess;
OBJECT_ATTRIBUTES Obja;
UNICODE_STRING FileName;
BOOLEAN TranslationStatus;
RTL_RELATIVE_NAME RelativeName;
IO_STATUS_BLOCK IoStatusBlock;
PVOID FreeBuffer;
SetSecurityAccessMask(
SecurityInformation,
&DesiredAccess
);
TranslationStatus = RtlDosPathNameToNtPathName_U(
lpFileName,
&FileName,
NULL,
&RelativeName
);
if ( !TranslationStatus ) {
BaseSetLastNTError(STATUS_OBJECT_NAME_INVALID);
return FALSE;
}
FreeBuffer = FileName.Buffer;
if ( RelativeName.RelativeName.Length ) {
FileName = *(PUNICODE_STRING)&RelativeName.RelativeName;
}
else {
RelativeName.ContainingDirectory = NULL;
}
InitializeObjectAttributes(
&Obja,
&FileName,
OBJ_CASE_INSENSITIVE,
RelativeName.ContainingDirectory,
NULL
);
//
// Notice that FILE_OPEN_REPARSE_POINT inhibits the reparse behavior. Thus, the
// security will always be set, as before, in the file denoted by the name.
//
Status = NtOpenFile(
&FileHandle,
DesiredAccess,
&Obja,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_OPEN_REPARSE_POINT
);
//
// Back-level file systems may not support the FILE_OPEN_REPARSE_POINT
// flag. We treat this case explicitly.
//
if ( Status == STATUS_INVALID_PARAMETER ) {
//
// Open without inhibiting the reparse behavior.
//
Status = NtOpenFile(
&FileHandle,
DesiredAccess,
&Obja,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
0
);
}
RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
if ( !NT_SUCCESS( Status ) ) {
BaseSetLastNTError( Status );
return FALSE;
}
Status = NtSetSecurityObject(
FileHandle,
SecurityInformation,
pSecurityDescriptor
);
NtClose(FileHandle);
if (!NT_SUCCESS(Status)) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
SetFileSecurityA(
LPCSTR lpFileName,
SECURITY_INFORMATION SecurityInformation,
PSECURITY_DESCRIPTOR pSecurityDescriptor
)
/*++
Routine Description:
ANSI thunk to SetFileSecurityW
--*/
{
PUNICODE_STRING Unicode;
ANSI_STRING AnsiString;
NTSTATUS Status;
Unicode = &NtCurrentTeb()->StaticUnicodeString;
RtlInitAnsiString(&AnsiString,lpFileName);
if (AreFileApisANSI()) {
Status = RtlAnsiStringToUnicodeString(Unicode,&AnsiString,FALSE);
} else {
Status = RtlOemStringToUnicodeString(Unicode,&AnsiString,FALSE);
}
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return ( SetFileSecurityW( (LPCWSTR)Unicode->Buffer,
SecurityInformation,
pSecurityDescriptor
)
);
}
BOOL
APIENTRY
GetFileSecurityW(
LPCWSTR lpFileName,
SECURITY_INFORMATION RequestedInformation,
PSECURITY_DESCRIPTOR pSecurityDescriptor,
DWORD nLength,
LPDWORD lpnLengthNeeded
)
/*++
Routine Description:
This API returns top the caller a copy of the security descriptor
protecting a file or directory. Based on the caller's access
rights and privileges, this procedure will return a security
descriptor containing the requested security descriptor fields.
To read the handle's security descriptor the caller must be
granted READ_CONTROL access or be the owner of the object. In
addition, the caller must have SeSecurityPrivilege privilege to
read the system ACL.
Arguments:
lpFileName - Represents the name of the file or directory whose
security is being retrieved.
RequestedInformation - A pointer to the security information being
requested.
pSecurityDescriptor - A pointer to the buffer to receive a copy of
the secrity descriptor protecting the object that the caller
has the rigth to view. The security descriptor is returned in
self-relative format.
nLength - The size, in bytes, of the security descriptor buffer.
lpnLengthNeeded - A pointer to the variable to receive the number
of bytes needed to store the complete secruity descriptor. If
returned number of bytes is less than or equal to nLength then
the entire security descriptor is returned in the output
buffer, otherwise none of the descriptor is returned.
Return Value:
TRUE is returned for success, FALSE if access is denied or if the
buffer is too small to hold the security descriptor.
--*/
{
NTSTATUS Status;
HANDLE FileHandle;
ACCESS_MASK DesiredAccess;
OBJECT_ATTRIBUTES Obja;
UNICODE_STRING FileName;
BOOLEAN TranslationStatus;
RTL_RELATIVE_NAME RelativeName;
IO_STATUS_BLOCK IoStatusBlock;
PVOID FreeBuffer;
QuerySecurityAccessMask(
RequestedInformation,
&DesiredAccess
);
TranslationStatus = RtlDosPathNameToNtPathName_U(
lpFileName,
&FileName,
NULL,
&RelativeName
);
if ( !TranslationStatus ) {
BaseSetLastNTError(STATUS_OBJECT_NAME_INVALID);
return FALSE;
}
FreeBuffer = FileName.Buffer;
if ( RelativeName.RelativeName.Length ) {
FileName = *(PUNICODE_STRING)&RelativeName.RelativeName;
}
else {
RelativeName.ContainingDirectory = NULL;
}
InitializeObjectAttributes(
&Obja,
&FileName,
OBJ_CASE_INSENSITIVE,
RelativeName.ContainingDirectory,
NULL
);
//
// Notice that FILE_OPEN_REPARSE_POINT inhibits the reparse behavior. Thus, the
// security will always be set, as before, in the file denoted by the name.
//
Status = NtOpenFile(
&FileHandle,
DesiredAccess,
&Obja,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_OPEN_REPARSE_POINT
);
//
// Back-level file systems may not support the FILE_OPEN_REPARSE_POINT
// flag. We treat this case explicitly.
//
if ( Status == STATUS_INVALID_PARAMETER ) {
//
// Open without inhibiting the reparse behavior.
//
Status = NtOpenFile(
&FileHandle,
DesiredAccess,
&Obja,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
0
);
}
RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
if (NT_SUCCESS(Status)) {
Status = NtQuerySecurityObject(
FileHandle,
RequestedInformation,
pSecurityDescriptor,
nLength,
lpnLengthNeeded
);
NtClose(FileHandle);
}
if (!NT_SUCCESS(Status)) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
GetFileSecurityA(
LPCSTR lpFileName,
SECURITY_INFORMATION RequestedInformation,
PSECURITY_DESCRIPTOR pSecurityDescriptor,
DWORD nLength,
LPDWORD lpnLengthNeeded
)
/*++
Routine Description:
ANSI thunk to GetFileSecurityW
--*/
{
PUNICODE_STRING Unicode;
ANSI_STRING AnsiString;
NTSTATUS Status;
Unicode = &NtCurrentTeb()->StaticUnicodeString;
RtlInitAnsiString(&AnsiString,lpFileName);
if (AreFileApisANSI()) {
Status = RtlAnsiStringToUnicodeString(Unicode,&AnsiString,FALSE);
} else {
Status = RtlOemStringToUnicodeString(Unicode,&AnsiString,FALSE);
}
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return ( GetFileSecurityW( (LPCWSTR)Unicode->Buffer,
RequestedInformation,
pSecurityDescriptor,
nLength,
lpnLengthNeeded
)
);
}
BOOL
APIENTRY
SetKernelObjectSecurity (
HANDLE Handle,
SECURITY_INFORMATION SecurityInformation,
PSECURITY_DESCRIPTOR SecurityDescriptor
)
/*++
Routine Description:
This API can be used to set the security of a kernel object
(process, file, event, etc.). This call is only successful if the
following conditions are met:
o If the object's owner or group is to be set, the caller must
have WRITE_OWNER permission or have SeTakeOwnershipPrivilege.
o If the object's DACL is to be set, the caller must have
WRITE_DAC permission or be the object's owner.
o If the object's SACL is to be set, the caller must have
SeSecurityPrivilege.
Arguments:
Handle - Represents a handle of a kernel object.
SecurityInformation - A pointer to information describing the
contents of the Security Descriptor.
pSecurityDescriptor - A pointer to a well formed Security
Descriptor.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = NtSetSecurityObject(
Handle,
SecurityInformation,
SecurityDescriptor
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
GetKernelObjectSecurity (
HANDLE Handle,
SECURITY_INFORMATION RequestedInformation,
PSECURITY_DESCRIPTOR pSecurityDescriptor,
DWORD nLength,
LPDWORD lpnLengthNeeded
)
/*++
Routine Description:
This API returns top the caller a copy of the security descriptor
protecting a kernel object. Based on the caller's access rights
and privileges, this procedure will return a security descriptor
containing the requested security descriptor fields. To read the
handle's security descriptor the caller must be granted
READ_CONTROL access or be the owner of the object. In addition,
the caller must have SeSecurityPrivilege privilege to read the
system ACL.
Arguments:
Handle - Represents a handle of a kernel object.
RequestedInformation - A pointer to the security information being
requested.
pSecurityDescriptor - A pointer to the buffer to receive a copy of
the secrity descriptor protecting the object that the caller
has the rigth to view. The security descriptor is returned in
self-relative format.
nLength - The size, in bytes, of the security descriptor buffer.
lpnLengthNeeded - A pointer to the variable to receive the number
of bytes needed to store the complete secruity descriptor. If
returned number of bytes is less than or equal to nLength then
the entire security descriptor is returned in the output
buffer, otherwise none of the descriptor is returned.
Return Value:
return-value - Description of conditions needed to return value. - or -
None.
--*/
{
NTSTATUS Status;
Status = NtQuerySecurityObject(
Handle,
RequestedInformation,
pSecurityDescriptor,
nLength,
lpnLengthNeeded
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
ImpersonateNamedPipeClient(
IN HANDLE hNamedPipe
)
/*++
Routine Description:
Impersonate a named pipe client application.
Arguments:
hNamedPipe - Handle to a named pipe.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
IO_STATUS_BLOCK IoStatusBlock;
Status = NtFsControlFile(
hNamedPipe,
NULL,
NULL,
NULL,
&IoStatusBlock,
FSCTL_PIPE_IMPERSONATE,
NULL,
0,
NULL,
0
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
ImpersonateSelf(
SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
)
/*++
Routine Description:
This routine may be used to obtain an Impersonation token representing
your own process's context. This may be useful for enabling a privilege
for a single thread rather than for the entire process; or changing
the default DACL for a single thread.
The token is assigned to the callers thread.
Arguments:
ImpersonationLevel - The level to make the impersonation token.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = RtlImpersonateSelf( ImpersonationLevel );
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
RevertToSelf (
VOID
)
/*++
Routine Description:
Terminate impersonation of a named pipe client application.
Arguments:
None.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
HANDLE NewToken;
NTSTATUS Status;
NewToken = NULL;
Status = NtSetInformationThread(
NtCurrentThread(),
ThreadImpersonationToken,
(PVOID)&NewToken,
(ULONG)sizeof(HANDLE)
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
SetThreadToken (
PHANDLE Thread,
HANDLE Token
)
/*++
Routine Description:
Assigns the specified impersonation token to the specified
thread.
Arguments:
Thread - Specifies the thread whose token is to be assigned.
If NULL is specified, then the caller's thread is assumed.
Token - The token to assign. Must be open for TOKEN_IMPERSONATE
access. If null, then causes the specified thread to stop
impersonating.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
HANDLE TargetThread;
if (ARGUMENT_PRESENT(Thread)) {
TargetThread = (*Thread);
} else {
TargetThread = NtCurrentThread();
}
Status = NtSetInformationThread(
TargetThread,
ThreadImpersonationToken,
(PVOID)&Token,
(ULONG)sizeof(HANDLE)
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
LookupAccountNameInternal(
LPCWSTR lpSystemName,
LPCWSTR lpAccountName,
PSID Sid,
LPDWORD cbSid,
LPWSTR ReferencedDomainName,
LPDWORD cbReferencedDomainName,
PSID_NAME_USE peUse,
BOOL fUnicode
)
/*++
Routine Description:
Translates a passed name into an account SID. It will also return
the name and SID of the first domain in which this name was found.
Arguments:
lpSystemName - Supplies the name of the system at which the lookup
is to be performed. If the null string is provided, the local
system is assumed.
lpAccountName - Supplies the account name.
Sid - Returns the SID corresponding to the passed account name.
cbSid - Supplies the size of the buffer passed in for Sid. If
the buffer size is not big enough, this parameter will
return the size necessary to hold the output Sid.
ReferencedDomainName - Returns the name of the domain in which the
name was found.
cbReferencedDomainName - Supplies the size (in Wide characters) of the
ReferencedDomainName buffer. If the buffer size is not large
enough, this parameter will return the size necessary to hold
the null-terminated output domain name. If the buffer size is
large enough, tis parameter will return the size (in Ansi characters,
excluding the terminating null) of the Referenced Domain name.
peUse - Returns an enumerated type inidicating the type of the
account.
fUnicode - indicates whether the caller wants a count of unicode or
ansi characters.
Return Value:
BOOL - TRUE is returned if successful, else FALSE.
--*/
{
SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
OBJECT_ATTRIBUTES ObjectAttributes;
LSA_HANDLE PolicyHandle;
NTSTATUS Status;
NTSTATUS TmpStatus;
UNICODE_STRING Name;
PLSA_REFERENCED_DOMAIN_LIST ReferencedDomains = NULL;
PLSA_TRANSLATED_SID2 TranslatedSid = NULL;
PSID ReturnedDomainSid;
UCHAR nSubAuthorities;
UNICODE_STRING TmpString;
DWORD ReturnedDomainNameSize;
DWORD SidLengthRequired;
BOOL Rc;
UNICODE_STRING SystemName;
PUNICODE_STRING pSystemName = NULL;
SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
SecurityQualityOfService.EffectiveOnly = FALSE;
//
// Set up the object attributes prior to opening the LSA.
//
InitializeObjectAttributes(
&ObjectAttributes,
NULL,
0L,
NULL,
NULL
);
//
// The InitializeObjectAttributes macro presently stores NULL for
// the SecurityQualityOfService field, so we must manually copy that
// structure for now.
//
ObjectAttributes.SecurityQualityOfService = &SecurityQualityOfService;
if ( ARGUMENT_PRESENT( lpSystemName )) {
RtlInitUnicodeString( &SystemName, lpSystemName );
pSystemName = &SystemName;
}
//
// Open the LSA Policy Database for the target system. This is the
// starting point for the Name Lookup operation.
//
Status = LsaOpenPolicy(
pSystemName,
&ObjectAttributes,
POLICY_LOOKUP_NAMES,
&PolicyHandle
);
if ( !NT_SUCCESS( Status )) {
BaseSetLastNTError( Status );
return( FALSE );
}
RtlInitUnicodeString( &Name, lpAccountName );
//
// Attempt to translate the Name to a Sid.
//
Status = LsaLookupNames2(
PolicyHandle,
0, // Flags
1,
&Name,
&ReferencedDomains,
&TranslatedSid
);
#if DBG
//
// This code is useful for tracking down components that call Lookup code
// before the system is initialized
//
// ASSERT( Status != STATUS_INVALID_SERVER_STATE );
if ( Status == STATUS_INVALID_SERVER_STATE ) {
DbgPrint( "Process: %lu, Thread: %lu\n", GetCurrentProcessId(), GetCurrentThreadId() );
}
#endif
//
// Close the Policy Handle, which is not needed after here.
//
TmpStatus = LsaClose( PolicyHandle );
// ASSERT( NT_SUCCESS( TmpStatus ));
//
// If an error was returned, check specifically for STATUS_NONE_MAPPED.
// In this case, we may need to dispose of the returned Referenced Domain
// List and Translated Sid structures. For all other errors,
// LsaLookupNames() frees these structures prior to exit.
//
if ( !NT_SUCCESS( Status )) {
if (Status == STATUS_NONE_MAPPED) {
if (ReferencedDomains != NULL) {
TmpStatus = LsaFreeMemory( ReferencedDomains );
ASSERT( NT_SUCCESS( TmpStatus ));
}
if (TranslatedSid != NULL) {
TmpStatus = LsaFreeMemory( TranslatedSid );
ASSERT( NT_SUCCESS( TmpStatus ));
}
}
BaseSetLastNTError( Status );
return( FALSE );
}
//
// The Name was successfully translated. There should be exactly
// one Referenced Domain and its DomainIndex should be zero.
//
ASSERT ( TranslatedSid->DomainIndex == 0 );
ASSERT ( ReferencedDomains != NULL);
ASSERT ( ReferencedDomains->Domains != NULL );
//
// Calculate the lengths of the returned Sid and Domain Name (in Wide
// Characters, excluding null).
//
if ( !fUnicode ) {
RtlUnicodeToMultiByteSize(&ReturnedDomainNameSize,
ReferencedDomains->Domains->Name.Buffer,
ReferencedDomains->Domains->Name.Length);
} else {
ReturnedDomainNameSize = (ReferencedDomains->Domains->Name.Length / sizeof(WCHAR));
}
SidLengthRequired = RtlLengthSid( TranslatedSid->Sid );
//
// Check if buffer sizes are too small. For the returned domain,
// the size in Wide characters provided must allow for the null
// terminator that will be appended to the returned name.
//
if ( (SidLengthRequired > *cbSid) ||
(ReturnedDomainNameSize + 1 > *cbReferencedDomainName)
) {
//
// One or both buffers are too small. Return sizes required for
// both buffers.
//
*cbSid = SidLengthRequired;
*cbReferencedDomainName = ReturnedDomainNameSize + 1;
BaseSetLastNTError( STATUS_BUFFER_TOO_SMALL );
Rc = FALSE;
} else {
//
// The provided buffers are large enough.
//
CopySid( *cbSid, Sid, TranslatedSid->Sid );
//
// Copy the Domain Name into the return buffer and NULL terminate it.
//
TmpString.Buffer = ReferencedDomainName;
TmpString.Length = 0;
//
// Watch for overflow of 16-bit name length
//
if (*cbReferencedDomainName < (DWORD) 32767) {
TmpString.MaximumLength = (USHORT)((*cbReferencedDomainName) * sizeof(WCHAR));
} else {
TmpString.MaximumLength = (USHORT) 65534;
}
RtlCopyUnicodeString( &TmpString, &ReferencedDomains->Domains->Name );
TmpString.Buffer[TmpString.Length/sizeof(WCHAR)] = (WCHAR) 0;
//
// Copy the Sid Use field.
//
*peUse = TranslatedSid->Use;
//
// Return the size (in Wide Characters, excluding the terminating
// null) of the returned Referenced Domain Name.
//
*cbReferencedDomainName = ReturnedDomainNameSize;
Rc = TRUE;
}
//
// If necessary, free the structures returned by the LsaLookupNames()
// function.
//
if (ReferencedDomains != NULL) {
Status = LsaFreeMemory( ReferencedDomains );
ASSERT( NT_SUCCESS( Status ));
}
if (TranslatedSid != NULL) {
Status = LsaFreeMemory( TranslatedSid );
ASSERT( NT_SUCCESS( Status ));
}
return( Rc );
}
BOOL
APIENTRY
LookupAccountNameA(
LPCSTR lpSystemName,
LPCSTR lpAccountName,
PSID Sid,
LPDWORD cbSid,
LPSTR ReferencedDomainName,
LPDWORD cbReferencedDomainName,
PSID_NAME_USE peUse
)
/*++
Routine Description:
ANSI Thunk to LookupAccountNameW
Arguments:
lpSystemName - Supplies the name of the system at which the lookup
is to be performed. If the null string is provided, the local
system is assumed.
lpAccountName - Supplies the account name.
Sid - Returns the SID corresponding to the passed account name.
cbSid - Supplies the size of the buffer passed in for Sid. If
the buffer size is not big enough, this parameter will
return the size necessary to hold the output Sid.
ReferencedDomainName - Returns the name of the domain in which the
name was found.
cbReferencedDomainName - Supplies the size (in Ansi characters) of the
ReferencedDomainName buffer. If the buffer size is not large
enough, this parameter will return the size necessary to hold
the null-terminated output domain name. If the buffer size is
large enough, tis parameter will return the size (in Ansi characters,
excluding the terminating null) of the Referenced Domain name.
peUse - Returns an enumerated type indicating the type of the
account.
Return Value:
BOOL - TRUE is returned if successful, else FALSE.
--*/
{
UNICODE_STRING Unicode;
UNICODE_STRING TmpUnicode;
ANSI_STRING AnsiString;
PWSTR WReferencedDomainName = NULL;
UNICODE_STRING SystemName;
PWSTR pSystemName = NULL;
NTSTATUS Status;
BOOL rc = TRUE;
DWORD cbInitReferencedDomainName;
Unicode.Buffer = NULL;
SystemName.Buffer = NULL;
//
// Save the original buffer size
//
cbInitReferencedDomainName = *cbReferencedDomainName;
//
// Convert the passed lpAccountName to a WCHAR string to be
// passed to the ..W routine. Note that we cannot use the
// StaticUnicodeString in the Thread Environment Block because
// this is used by LdrpWalkImportDescriptor, called from the
// client RPC stub code of the LsaOpenPolicy() call in
// LookupAccountNameW.
//
RtlInitAnsiString( &AnsiString, lpAccountName );
Status = RtlAnsiStringToUnicodeString( &Unicode, &AnsiString, TRUE );
if (!NT_SUCCESS(Status)) {
rc = FALSE;
}
//
// Allocate a temporary buffer for ReferencedDomainName that
// is twice as large as what was passed to adjust for the
// intermediate conversion to a WCHAR string.
//
if (rc) {
WReferencedDomainName = LocalAlloc(
LMEM_FIXED,
sizeof(WCHAR) * (*cbReferencedDomainName)
);
if (WReferencedDomainName == NULL) {
Status = STATUS_NO_MEMORY;
rc = FALSE;
}
}
//
// If the target system name is non NULL, convert it to Unicode
//
if (rc) {
if ( ARGUMENT_PRESENT( lpSystemName ) ) {
RtlInitAnsiString( &AnsiString, lpSystemName );
Status = RtlAnsiStringToUnicodeString( &SystemName, &AnsiString, TRUE );
if (!NT_SUCCESS(Status)) {
rc = FALSE;
}
pSystemName = SystemName.Buffer;
}
}
//
// Lookup the Account Sid and obtain its Unicode Account Name.
//
if (rc) {
rc = LookupAccountNameInternal(
(LPCWSTR)pSystemName,
(LPCWSTR)Unicode.Buffer,
Sid,
cbSid,
WReferencedDomainName,
cbReferencedDomainName,
peUse,
FALSE // not unicode
);
}
if ( SystemName.Buffer != NULL ) {
RtlFreeUnicodeString( &SystemName );
}
//
// Convert the returned null-terminated WCHAR string
// back to a null-terminated CHAR string.
//
if (rc) {
RtlInitUnicodeString( &TmpUnicode, WReferencedDomainName );
AnsiString.Buffer = ReferencedDomainName;
//
// Watch for 16-bit overflow of MaximumLength
//
if (cbInitReferencedDomainName <= (DWORD) 65535) {
AnsiString.MaximumLength = (USHORT) cbInitReferencedDomainName;
} else {
AnsiString.MaximumLength = (USHORT) 65535;
}
Status = RtlUnicodeStringToAnsiString( &AnsiString, &TmpUnicode, FALSE );
if ( NT_SUCCESS( Status )) {
ReferencedDomainName[AnsiString.Length] = 0;
} else {
rc = FALSE;
}
}
if ( WReferencedDomainName != NULL) {
LocalFree( WReferencedDomainName );
}
if (Unicode.Buffer != NULL) {
RtlFreeUnicodeString(&Unicode);
}
if (!NT_SUCCESS(Status)) {
BaseSetLastNTError( Status );
}
return( rc );
}
BOOL
APIENTRY
LookupAccountNameW(
LPCWSTR lpSystemName,
LPCWSTR lpAccountName,
PSID Sid,
LPDWORD cbSid,
LPWSTR ReferencedDomainName,
LPDWORD cbReferencedDomainName,
PSID_NAME_USE peUse
)
/*++
Routine Description:
Translates a passed name into an account SID. It will also return
the name and SID of the first domain in which this name was found.
Arguments:
lpSystemName - Supplies the name of the system at which the lookup
is to be performed. If the null string is provided, the local
system is assumed.
lpAccountName - Supplies the account name.
Sid - Returns the SID corresponding to the passed account name.
cbSid - Supplies the size of the buffer passed in for Sid. If
the buffer size is not big enough, this parameter will
return the size necessary to hold the output Sid.
ReferencedDomainName - Returns the name of the domain in which the
name was found.
cbReferencedDomainName - Supplies the size (in Wide characters) of the
ReferencedDomainName buffer. If the buffer size is not large
enough, this parameter will return the size necessary to hold
the null-terminated output domain name. If the buffer size is
large enough, tis parameter will return the size (in Ansi characters,
excluding the terminating null) of the Referenced Domain name.
peUse - Returns an enumerated type inidicating the type of the
account.
Return Value:
BOOL - TRUE is returned if successful, else FALSE.
--*/
{
return(LookupAccountNameInternal( lpSystemName,
lpAccountName,
Sid,
cbSid,
ReferencedDomainName,
cbReferencedDomainName,
peUse,
TRUE // Unicode
) );
}
BOOL
APIENTRY
LookupAccountSidInternal(
LPCWSTR lpSystemName,
PSID lpSid,
LPWSTR lpName,
LPDWORD cbName,
LPWSTR lpReferencedDomainName,
LPDWORD cbReferencedDomainName,
PSID_NAME_USE peUse,
BOOL fUnicode
)
/*++
Routine Description:
Translates a passed SID into an account name. It will also return
the name and SID of the first domain in which this SID was found.
Arguments:
lpSystemName - Supplies the name of the system at which the lookup
is to be performed. If the null string is provided, the local
system is assumed.
lpSid - Supplies the account Sid.
lpName - Returns the name corresponding to the passed account SID.
cbName - Supplies the size (in Wide characters) of the buffer passed in for
lpName. This size must allow one character for the null terminator
that will be appended to the returned name. If the buffer size is not
large enough, this parameter will return the size necessary to hold
the null-terminated output name. If the buffer size is large enough,
this parameter will return the size (in Ansi characters, excluding
the null terminator) of the name returned.
lpReferencedDomainName - Returns the name of the domain in which the
name was found.
cbReferencedDomainName - Supplies the size (in Wide characters) of the
ReferencedDomainName buffer. This size must allow one charcter for the
null terminator that will be appended to the returned name. If the
buffer size is not large enough, this parameter will return the size
necessary to hold the output null-terminated domain name. If the
buffer size is large enough, the size of the returned name, excluding
the terminating null will be returned.
peUse - Returns an enumerated type inidicating the type of the
account.
fUnicode - indicates whether the caller wants a count of unicode or
ansi characters.
Return Value:
BOOL - TRUE if successful, else FALSE.
--*/
{
PLSA_TRANSLATED_NAME Names;
OBJECT_ATTRIBUTES ObjectAttributes;
LSA_HANDLE PolicyHandle;
PLSA_REFERENCED_DOMAIN_LIST ReferencedDomains;
DWORD ReturnedDomainNameSize;
DWORD ReturnedNameSize;
SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
NTSTATUS Status;
UNICODE_STRING TmpString;
NTSTATUS TmpStatus;
UNICODE_STRING SystemName;
PUNICODE_STRING pSystemName = NULL;
BOOLEAN Rc = FALSE;
SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
SecurityQualityOfService.EffectiveOnly = FALSE;
//
// Set up the object attributes prior to opening the LSA.
//
InitializeObjectAttributes(
&ObjectAttributes,
NULL,
0L,
NULL,
NULL
);
//
// The InitializeObjectAttributes macro presently stores NULL for
// the SecurityQualityOfService field, so we must manually copy that
// structure for now.
//
ObjectAttributes.SecurityQualityOfService = &SecurityQualityOfService;
if ( ARGUMENT_PRESENT( lpSystemName )) {
RtlInitUnicodeString( &SystemName, lpSystemName );
pSystemName = &SystemName;
}
Status = LsaOpenPolicy(
pSystemName,
&ObjectAttributes,
POLICY_LOOKUP_NAMES,
&PolicyHandle
);
if ( !NT_SUCCESS( Status )) {
BaseSetLastNTError( Status );
return( FALSE );
}
Status = LsaLookupSids(
PolicyHandle,
1,
&lpSid,
&ReferencedDomains,
&Names
);
#if DBG
//
// This code is useful for tracking down components that call Lookup code
// before the system is initialized
//
// ASSERT( Status != STATUS_INVALID_SERVER_STATE );
if ( Status == STATUS_INVALID_SERVER_STATE ) {
DbgPrint( "Process: %lu, Thread: %lu\n", GetCurrentProcessId(), GetCurrentThreadId() );
}
#endif
TmpStatus = LsaClose( PolicyHandle );
//
// If an error was returned, check specifically for STATUS_NONE_MAPPED.
// In this case, we may need to dispose of the returned Referenced Domain
// List and Names structures. For all other errors, LsaLookupSids()
// frees these structures prior to exit.
//
if ( !NT_SUCCESS( Status )) {
if (Status == STATUS_NONE_MAPPED) {
if (ReferencedDomains != NULL) {
TmpStatus = LsaFreeMemory( ReferencedDomains );
ASSERT( NT_SUCCESS( TmpStatus ));
}
if (Names != NULL) {
TmpStatus = LsaFreeMemory( Names );
ASSERT( NT_SUCCESS( TmpStatus ));
}
}
BaseSetLastNTError( Status );
return( FALSE );
}
//
// The Sid was successfully translated. There should be exactly
// one Referenced Domain and its DomainIndex should be zero.
//
ASSERT(Names->DomainIndex == 0);
ASSERT(ReferencedDomains != NULL);
ASSERT(ReferencedDomains->Domains != NULL);
if ( ! fUnicode ) {
RtlUnicodeToMultiByteSize(&ReturnedNameSize,
Names->Name.Buffer,
Names->Name.Length);
RtlUnicodeToMultiByteSize(&ReturnedDomainNameSize,
ReferencedDomains->Domains->Name.Buffer,
ReferencedDomains->Domains->Name.Length);
} else {
ReturnedNameSize = (Names->Name.Length / sizeof(WCHAR));
ReturnedDomainNameSize = (ReferencedDomains->Domains->Name.Length / sizeof(WCHAR));
}
//
// Check if buffer sizes for the Name and Referenced Domain Name are too
// small. The sizes in Wide characters provided must allow for the null
// terminator that will be appended to the returned names.
//
if ((ReturnedNameSize + 1 > *cbName) ||
(ReturnedDomainNameSize + 1 > *cbReferencedDomainName)) {
//
// One or both buffers are too small. Return sizes required for
// both buffers, allowing one character for the null terminator.
//
*cbReferencedDomainName = ReturnedDomainNameSize + 1;
*cbName = ReturnedNameSize + 1;
BaseSetLastNTError( STATUS_BUFFER_TOO_SMALL );
Rc = FALSE;
} else {
//
// Both buffers are of sufficient size. Copy in the Name
// information and add NULL terminators.
//
TmpString.Buffer = lpName;
TmpString.Length = 0;
//
// Watch for 16-bit overflow on buffer size. Clamp size to
// 16 bits if necessary.
//
if (*cbName <= 32766) {
TmpString.MaximumLength = (USHORT)((*cbName) * sizeof(WCHAR));
} else {
TmpString.MaximumLength = (USHORT) 65532;
}
if ((*cbName) > 0) {
RtlCopyUnicodeString( &TmpString, &Names->Name );
TmpString.Buffer[TmpString.Length/sizeof(WCHAR)] = (WCHAR) 0;
}
//
// Copy in the Referenced Domain information.
//
TmpString.Buffer = lpReferencedDomainName;
TmpString.Length = 0;
//
// Watch for 16-bit overflow on buffer size. Clamp size to
// 16 bits if necessary.
//
if (*cbReferencedDomainName <= 32767) {
TmpString.MaximumLength = (USHORT)((*cbReferencedDomainName) * sizeof(WCHAR));
} else {
TmpString.MaximumLength = (USHORT) 65534;
}
RtlCopyUnicodeString( &TmpString, &ReferencedDomains->Domains->Name );
TmpString.Buffer[TmpString.Length/sizeof(WCHAR)] = (WCHAR) 0;
//
// Return the sizes (in Wide Characters, excluding the terminating
// null) of the name and domain name.
//
*cbReferencedDomainName = ReturnedDomainNameSize;
*cbName = ReturnedNameSize;
// Copy in the Use field.
//
*peUse = Names->Use;
Rc = TRUE;
}
//
// If necessary, free output buffers returned by LsaLookupSids
//
if (Names != NULL) {
Status = LsaFreeMemory( Names );
ASSERT( NT_SUCCESS( Status ));
}
if (ReferencedDomains != NULL) {
Status = LsaFreeMemory( ReferencedDomains );
ASSERT( NT_SUCCESS( Status ));
}
return(Rc);
}
BOOL
APIENTRY
LookupAccountSidA(
LPCSTR lpSystemName,
PSID lpSid,
LPSTR lpName,
LPDWORD cbName,
LPSTR lpReferencedDomainName,
LPDWORD cbReferencedDomainName,
PSID_NAME_USE peUse
)
/*++
Routine Description:
ANSI Thunk to LookupAccountSidW
Arguments:
lpSystemName - Supplies the name of the system at which the lookup
is to be performed. If the null string is provided, the local
system is assumed.
lpSid - Supplies the account Sid.
lpName - Returns the name corresponding to the passed account SID.
cbName - Supplies the size (in Ansi characters) of the buffer passed in for
lpName. This size must allow one character for the null terminator
that will be appended to the returned name. If the buffer size is not
large enough, this parameter will return the size necessary to hold
the null-terminated output name. If the buffer size is large enough,
this parameter will return the size (in Ansi characters, excluding
the null terminator) of the name returned.
lpReferencedDomainName - Returns the name of the domain in which the
name was found.
cbReferencedDomainName - Supplies the size (in Ansi characters) of the
ReferencedDomainName buffer. This size must allow one charcter for the
null terminator that will be appended to the returned name. If the
buffer size is not large enough, this parameter will return the size
necessary to hold the output null-terminated domain name. If the
buffer size is large enough, the size of the returned name, excluding
the terminating null will be returned.
peUse - Returns an enumerated type indicating the type of the
account.
Return Value:
BOOL - TRUE if successful, else FALSE.
--*/
{
NTSTATUS Status;
LPWSTR WName = NULL;
LPWSTR WReferencedDomainName = NULL;
BOOL BoolStatus;
ANSI_STRING AnsiString;
UNICODE_STRING UnicodeString;
UNICODE_STRING SystemName;
PWSTR pSystemName = NULL;
DWORD cbInitName, cbInitReferencedDomainName;
//
// Save the original buffer sizes specified for the returned account Name
// and Referenced Domain Name.
//
cbInitName = *cbName;
cbInitReferencedDomainName = *cbReferencedDomainName;
//
// Construct temporary buffers for the Name and Domain information
// that are twice the size of those passed in to adjust for the
// intermediate conversion to WCHAR strings.
//
if ( *cbName > 0 ) {
WName = LocalAlloc( LMEM_FIXED, (*cbName) * sizeof(WCHAR));
if ( !WName )
{
SetLastError( ERROR_OUTOFMEMORY );
return FALSE ;
}
}
if ( *cbReferencedDomainName > 0 ) {
WReferencedDomainName =
LocalAlloc( LMEM_FIXED, (*cbReferencedDomainName) * sizeof(WCHAR));
if ( !WReferencedDomainName )
{
if ( WName )
{
LocalFree( WName );
}
SetLastError( ERROR_OUTOFMEMORY );
return FALSE ;
}
}
if ( ARGUMENT_PRESENT( lpSystemName ) ) {
RtlInitAnsiString( &AnsiString, lpSystemName );
RtlAnsiStringToUnicodeString( &SystemName, &AnsiString, TRUE );
pSystemName = SystemName.Buffer;
}
BoolStatus = LookupAccountSidInternal(
(LPCWSTR)pSystemName,
lpSid,
WName,
cbName,
WReferencedDomainName,
cbReferencedDomainName,
peUse,
FALSE // not unicode
);
if ( ARGUMENT_PRESENT( lpSystemName ) ) {
RtlFreeUnicodeString( &SystemName );
}
if ( BoolStatus ) {
//
// Copy the Name and DomainName information into the passed CHAR
// buffers.
//
if ( ARGUMENT_PRESENT(lpName) ) {
AnsiString.Buffer = lpName;
//
// Watch for 16-bit overflow on buffer size. Clamp size to
// 16 bits if necessary.
//
if (cbInitName <= (DWORD) 65535) {
AnsiString.MaximumLength = (USHORT) cbInitName;
} else {
AnsiString.MaximumLength = (USHORT) 65535;
}
RtlInitUnicodeString( &UnicodeString, WName );
Status = RtlUnicodeStringToAnsiString( &AnsiString,
&UnicodeString,
FALSE );
ASSERT(NT_SUCCESS(Status));
AnsiString.Buffer[AnsiString.Length] = 0;
}
if ( ARGUMENT_PRESENT(lpReferencedDomainName) ) {
AnsiString.Buffer = lpReferencedDomainName;
//
// Watch for 16-bit overflow on buffer size. Clamp size to
// 16 bits if necessary.
//
if (cbInitReferencedDomainName <= (DWORD) 65535) {
AnsiString.MaximumLength = (USHORT) cbInitReferencedDomainName;
} else {
AnsiString.MaximumLength = (USHORT) 65535;
}
RtlInitUnicodeString( &UnicodeString, WReferencedDomainName );
Status = RtlUnicodeStringToAnsiString( &AnsiString,
&UnicodeString,
FALSE );
ASSERT(NT_SUCCESS(Status));
AnsiString.Buffer[AnsiString.Length] = 0;
}
}
if (ARGUMENT_PRESENT(WName)) {
LocalFree( WName );
}
if (ARGUMENT_PRESENT(WReferencedDomainName)) {
LocalFree( WReferencedDomainName );
}
return( BoolStatus );
}
BOOL
APIENTRY
LookupAccountSidW(
LPCWSTR lpSystemName,
PSID lpSid,
LPWSTR lpName,
LPDWORD cbName,
LPWSTR lpReferencedDomainName,
LPDWORD cbReferencedDomainName,
PSID_NAME_USE peUse
)
/*++
Routine Description:
Translates a passed SID into an account name. It will also return
the name and SID of the first domain in which this SID was found.
Arguments:
lpSystemName - Supplies the name of the system at which the lookup
is to be performed. If the null string is provided, the local
system is assumed.
lpSid - Supplies the account Sid.
lpName - Returns the name corresponding to the passed account SID.
cbName - Supplies the size (in Wide characters) of the buffer passed in for
lpName. This size must allow one character for the null terminator
that will be appended to the returned name. If the buffer size is not
large enough, this parameter will return the size necessary to hold
the null-terminated output name. If the buffer size is large enough,
this parameter will return the size (in Ansi characters, excluding
the null terminator) of the name returned.
lpReferencedDomainName - Returns the name of the domain in which the
name was found.
cbReferencedDomainName - Supplies the size (in Wide characters) of the
ReferencedDomainName buffer. This size must allow one charcter for the
null terminator that will be appended to the returned name. If the
buffer size is not large enough, this parameter will return the size
necessary to hold the output null-terminated domain name. If the
buffer size is large enough, the size of the returned name, excluding
the terminating null will be returned.
peUse - Returns an enumerated type inidicating the type of the
account.
Return Value:
BOOL - TRUE if successful, else FALSE.
--*/
{
return(LookupAccountSidInternal(
lpSystemName,
lpSid,
lpName,
cbName,
lpReferencedDomainName,
cbReferencedDomainName,
peUse,
TRUE // Unicode
));
}
BOOL
APIENTRY
LookupPrivilegeValueA(
LPCSTR lpSystemName,
LPCSTR lpName,
PLUID lpLuid
)
/*++
Routine Description:
ANSI Thunk to LookupPrivilegeValueW().
Arguments:
Return Value:
--*/
{
NTSTATUS Status;
UNICODE_STRING USystemName, UName;
ANSI_STRING ASystemName, AName;
BOOL bool;
RtlInitAnsiString( &ASystemName, lpSystemName );
RtlInitAnsiString( &AName, lpName );
USystemName.Buffer = NULL;
UName.Buffer = NULL;
Status = RtlAnsiStringToUnicodeString( &USystemName, &ASystemName, TRUE );
if (NT_SUCCESS(Status)) {
Status = RtlAnsiStringToUnicodeString( &UName, &AName, TRUE );
if (NT_SUCCESS(Status)) {
bool = LookupPrivilegeValueW( (LPCWSTR)USystemName.Buffer,
(LPCWSTR)UName.Buffer,
lpLuid
);
RtlFreeUnicodeString( &UName );
}
RtlFreeUnicodeString( &USystemName );
}
if (!NT_SUCCESS(Status)) {
BaseSetLastNTError( Status );
return( FALSE );
}
return(bool);
}
BOOL
APIENTRY
LookupPrivilegeValueW(
LPCWSTR lpSystemName,
LPCWSTR lpName,
PLUID lpLuid
)
/*++
Routine Description:
This function retrieves the value used on the target system
to locally represent the specified privilege. The privilege
is specified by programmatic name.
Arguments:
lpSystemName - Supplies the name of the system at which the lookup
is to be performed. If the null string is provided, the local
system is assumed.
lpName - provides the privilege's programmatic name.
lpLuid - Receives the locally unique ID the privilege is known by on the
target machine.
Return Value:
--*/
{
NTSTATUS Status,
TmpStatus;
LSA_HANDLE PolicyHandle;
OBJECT_ATTRIBUTES ObjectAttributes;
SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
UNICODE_STRING USystemName,
UName;
PUNICODE_STRING SystemName = NULL;
SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
SecurityQualityOfService.EffectiveOnly = FALSE;
//
// Set up the object attributes prior to opening the LSA.
//
InitializeObjectAttributes( &ObjectAttributes, NULL, 0L, NULL, NULL );
ObjectAttributes.SecurityQualityOfService = &SecurityQualityOfService;
if ( ARGUMENT_PRESENT( lpSystemName )) {
RtlInitUnicodeString( &USystemName, lpSystemName );
SystemName = &USystemName;
}
Status = LsaOpenPolicy(
SystemName,
&ObjectAttributes,
POLICY_LOOKUP_NAMES,
&PolicyHandle
);
if ( !NT_SUCCESS( Status )) {
BaseSetLastNTError( Status );
return( FALSE );
}
RtlInitUnicodeString( &UName, lpName );
Status = LsaLookupPrivilegeValue( PolicyHandle, &UName, lpLuid );
TmpStatus = LsaClose( PolicyHandle );
// ASSERT( NT_SUCCESS( TmpStatus ));
if ( !NT_SUCCESS( Status )) {
BaseSetLastNTError( Status );
return( FALSE );
}
return(TRUE);
}
BOOL
APIENTRY
LookupPrivilegeNameA(
LPCSTR lpSystemName,
PLUID lpLuid,
LPSTR lpName,
LPDWORD cchName
)
/*++
Routine Description:
ANSI Thunk to LookupPrivilegeValueW().
Arguments:
Return Value:
--*/
{
NTSTATUS Status;
ANSI_STRING AnsiName;
LPWSTR UnicodeBuffer;
UNICODE_STRING UnicodeString;
ANSI_STRING AnsiSystemName;
UNICODE_STRING UnicodeSystemName;
DWORD LengthRequired;
//
// Convert the passed SystemName to Unicode. Let the Rtl function
// allocate the memory we need.
//
RtlInitAnsiString( &AnsiSystemName, lpSystemName );
Status = RtlAnsiStringToUnicodeString( &UnicodeSystemName, &AnsiSystemName, TRUE );
if (!NT_SUCCESS( Status )) {
BaseSetLastNTError( Status );
return( FALSE );
}
//
// Make sure we don't exceed the limits of a unicode string.
//
if (*cchName > 0xFFFC) {
*cchName = 0xFFFC;
}
UnicodeBuffer = RtlAllocateHeap( RtlProcessHeap(), 0, *cchName * sizeof(WCHAR) );
if (UnicodeBuffer == NULL) {
RtlFreeUnicodeString( &UnicodeSystemName );
BaseSetLastNTError( STATUS_NO_MEMORY );
return( FALSE );
}
//
// Don't pass in cchName, since it will be overwritten by LookupPrivilegeNameW,
// and we need it later.
//
LengthRequired = *cchName;
if (!LookupPrivilegeNameW( (LPCWSTR)UnicodeSystemName.Buffer,
lpLuid,
UnicodeBuffer,
&LengthRequired
)) {
RtlFreeHeap( RtlProcessHeap(), 0, UnicodeBuffer );
RtlFreeUnicodeString( &UnicodeSystemName );
*cchName = LengthRequired;
return(FALSE);
}
//
// Now convert back to ANSI for the caller
//
RtlInitUnicodeString(&UnicodeString, UnicodeBuffer);
AnsiName.Buffer = lpName;
AnsiName.Length = 0;
AnsiName.MaximumLength = (USHORT)*cchName;
Status = RtlUnicodeStringToAnsiString(&AnsiName, &UnicodeString, FALSE);
ASSERT( NT_SUCCESS( Status ));
*cchName = AnsiName.Length;
RtlFreeHeap( RtlProcessHeap(), 0, UnicodeBuffer );
RtlFreeUnicodeString( &UnicodeSystemName );
return(TRUE);
}
BOOL
APIENTRY
LookupPrivilegeNameW(
LPCWSTR lpSystemName,
PLUID lpLuid,
LPWSTR lpName,
LPDWORD cchName
)
/*++
Routine Description:
This function returns the programmatic name corresponding to
the privilege represented on the target system by the provided
LUID.
Arguments:
lpSystemName - Supplies the name of the system at which the lookup
is to be performed. If the null string is provided, the local
system is assumed.
lpLuid - is the locally unique ID the privilege is known by on the
target machine.
lpName - Receives the privilege's programmatic name.
cchName - indicates how large the buffer is (in characters). This
count does not include the null-terminator that is added at the
end of the string.
Return Value:
--*/
{
NTSTATUS Status,
TmpStatus;
LSA_HANDLE PolicyHandle;
OBJECT_ATTRIBUTES ObjectAttributes;
SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
UNICODE_STRING USystemName;
PUNICODE_STRING SystemName,
UName;
SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
SecurityQualityOfService.EffectiveOnly = FALSE;
//
// Set up the object attributes prior to opening the LSA.
//
InitializeObjectAttributes( &ObjectAttributes, NULL, 0L, NULL, NULL );
ObjectAttributes.SecurityQualityOfService = &SecurityQualityOfService;
SystemName = NULL;
if ( ARGUMENT_PRESENT( lpSystemName )) {
RtlInitUnicodeString( &USystemName, lpSystemName );
SystemName = &USystemName;
}
Status = LsaOpenPolicy(
SystemName,
&ObjectAttributes,
POLICY_LOOKUP_NAMES,
&PolicyHandle
);
if ( !NT_SUCCESS( Status )) {
BaseSetLastNTError( Status );
return( FALSE );
}
UName = NULL;
Status = LsaLookupPrivilegeName( PolicyHandle,lpLuid, &UName );
if (NT_SUCCESS(Status) ) {
if ((DWORD)UName->Length + sizeof( WCHAR) > (*cchName) * sizeof( WCHAR )) {
Status = STATUS_BUFFER_TOO_SMALL;
(*cchName) = ( UName->Length + sizeof( WCHAR) ) / sizeof( WCHAR );
} else {
RtlMoveMemory( lpName, UName->Buffer, UName->Length );
lpName[UName->Length/sizeof(WCHAR)] = 0; // NULL terminate it
(*cchName) = UName->Length / sizeof( WCHAR );
}
LsaFreeMemory( UName->Buffer );
LsaFreeMemory( UName );
}
TmpStatus = LsaClose( PolicyHandle );
// ASSERT( NT_SUCCESS( TmpStatus ));
if ( !NT_SUCCESS( Status )) {
BaseSetLastNTError( Status );
return( FALSE );
}
return(TRUE);
}
BOOL
APIENTRY
LookupPrivilegeDisplayNameA(
LPCSTR lpSystemName,
LPCSTR lpName,
LPSTR lpDisplayName,
LPDWORD cchDisplayName,
LPDWORD lpLanguageId
)
/*++
Routine Description:
ANSI Thunk to LookupPrivilegeValueW().
Arguments:
Return Value:
--*/
{
NTSTATUS Status;
UNICODE_STRING UnicodeSystemName;
UNICODE_STRING UnicodeString;
UNICODE_STRING UnicodeName;
ANSI_STRING AnsiSystemName;
ANSI_STRING AnsiDisplayName;
ANSI_STRING AnsiName;
LPWSTR UnicodeBuffer;
DWORD RequiredLength;
RtlInitAnsiString( &AnsiSystemName, lpSystemName );
Status = RtlAnsiStringToUnicodeString( &UnicodeSystemName, &AnsiSystemName, TRUE );
if (!NT_SUCCESS( Status )) {
BaseSetLastNTError( Status );
return( FALSE );
}
//
// Make sure we don't exceed that limits of a unicode string.
//
if (*cchDisplayName > 0xFFFC) {
*cchDisplayName = 0xFFFC;
}
UnicodeBuffer = RtlAllocateHeap( RtlProcessHeap(), 0, *cchDisplayName * sizeof(WCHAR));
if (UnicodeBuffer == NULL) {
RtlFreeUnicodeString( &UnicodeSystemName );
BaseSetLastNTError( STATUS_NO_MEMORY );
return( FALSE );
}
RtlInitAnsiString( &AnsiName, lpName );
Status = RtlAnsiStringToUnicodeString( &UnicodeName, &AnsiName, TRUE );
if (!NT_SUCCESS( Status )) {
RtlFreeUnicodeString( &UnicodeSystemName );
RtlFreeHeap( RtlProcessHeap(), 0, UnicodeBuffer );
BaseSetLastNTError( Status );
return( FALSE );
}
RequiredLength = *cchDisplayName;
if (! LookupPrivilegeDisplayNameW( (LPCWSTR)UnicodeSystemName.Buffer,
(LPCWSTR)UnicodeName.Buffer,
UnicodeBuffer,
&RequiredLength,
lpLanguageId
)) {
//
// No need to set last error here, we can assume the W routine did so.
//
*cchDisplayName = RequiredLength;
RtlFreeUnicodeString( &UnicodeSystemName );
RtlFreeUnicodeString( &UnicodeName );
RtlFreeHeap( RtlProcessHeap(), 0, UnicodeBuffer );
return( FALSE );
}
//
// Now convert back to ANSI for the caller
//
RtlInitUnicodeString( &UnicodeString, UnicodeBuffer );
AnsiDisplayName.Buffer = lpDisplayName;
AnsiDisplayName.Length = 0;
AnsiDisplayName.MaximumLength = (USHORT)(*cchDisplayName);
Status = RtlUnicodeStringToAnsiString( &AnsiDisplayName, &UnicodeString, FALSE );
ASSERT( NT_SUCCESS( Status ));
*cchDisplayName = AnsiDisplayName.Length;
RtlFreeUnicodeString( &UnicodeSystemName );
RtlFreeUnicodeString( &UnicodeName );
RtlFreeHeap( RtlProcessHeap(), 0, UnicodeBuffer );
return( TRUE );
}
BOOL
APIENTRY
LookupPrivilegeDisplayNameW(
LPCWSTR lpSystemName,
LPCWSTR lpName,
LPWSTR lpDisplayName,
LPDWORD cchDisplayName,
LPDWORD lpLanguageId
)
/*++
Routine Description:
This function retrieves a displayable name representing the
specified privilege.
Arguments:
lpSystemName - Supplies the name of the system at which the lookup
is to be performed. If the null string is provided, the local
system is assumed.
lpName - provides the privilege's programmatic name.
lpDisplayName - Receives the privilege's displayable name.
cchDisplayName - indicates how large the buffer is (in characters). This
count does not include the null-terminator that is added at the
end of the string.
lpLanguageId - Receives the language of the returned displayable
name.
Return Value:
--*/
{
NTSTATUS Status,
TmpStatus;
LSA_HANDLE PolicyHandle;
OBJECT_ATTRIBUTES ObjectAttributes;
SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
UNICODE_STRING USystemName,
UName;
PUNICODE_STRING SystemName,
UDisplayName;
SHORT LanguageId;
SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
SecurityQualityOfService.EffectiveOnly = FALSE;
//
// Set up the object attributes prior to opening the LSA.
//
InitializeObjectAttributes( &ObjectAttributes, NULL, 0L, NULL, NULL );
ObjectAttributes.SecurityQualityOfService = &SecurityQualityOfService;
SystemName = NULL;
if ( ARGUMENT_PRESENT( lpSystemName )) {
RtlInitUnicodeString( &USystemName, lpSystemName );
SystemName = &USystemName;
}
Status = LsaOpenPolicy(
SystemName,
&ObjectAttributes,
POLICY_LOOKUP_NAMES,
&PolicyHandle
);
if ( !NT_SUCCESS( Status )) {
BaseSetLastNTError( Status );
return( FALSE );
}
RtlInitUnicodeString( &UName, lpName );
UDisplayName = NULL;
Status = LsaLookupPrivilegeDisplayName( PolicyHandle,
&UName,
&UDisplayName,
&LanguageId
);
(*lpLanguageId) = LanguageId;
if (NT_SUCCESS(Status)) {
if (UDisplayName->Length + sizeof(WCHAR) > (*cchDisplayName) * sizeof(WCHAR)) {
Status = STATUS_BUFFER_TOO_SMALL;
(*cchDisplayName) = (UDisplayName->Length + sizeof( WCHAR )) / sizeof( WCHAR );
} else {
RtlMoveMemory( lpDisplayName,
UDisplayName->Buffer,
UDisplayName->Length
);
lpDisplayName[UDisplayName->Length/sizeof(WCHAR)] = 0; // Null terminate it.
(*cchDisplayName) = UDisplayName->Length / sizeof( WCHAR );
}
LsaFreeMemory( UDisplayName->Buffer );
LsaFreeMemory( UDisplayName );
}
TmpStatus = LsaClose( PolicyHandle );
// ASSERT( NT_SUCCESS( TmpStatus ));
if ( !NT_SUCCESS( Status )) {
BaseSetLastNTError( Status );
return( FALSE );
}
return(TRUE);
}
BOOL
APIENTRY
ImpersonateAnonymousToken(
IN HANDLE ThreadHandle
)
/*++
Routine Description:
Win32 wrapper for NtImpersonateAnonymousToken();
Impersonates the system's anonymous logon token on this thread.
Arguments:
ThreadHandle - Handle to the thread to do the impersonation.
Return Value:
TRUE for success, FALSE for failure.
Call GetLastError() for more information.
--*/
{
NTSTATUS Status;
Status = NtImpersonateAnonymousToken(
ThreadHandle
);
if ( !NT_SUCCESS( Status )) {
BaseSetLastNTError( Status );
return( FALSE );
} else {
return( TRUE );
}
}
/////////////////////////////////////////////////////////////////////////////
// //
// Private Routines //
// //
/////////////////////////////////////////////////////////////////////////////
VOID
SepFormatAccountSid(
PSID Sid,
LPWSTR OutputBuffer
)
{
UCHAR Buffer[128];
UCHAR TmpBuffer[128];
ANSI_STRING AccountName;
UCHAR i;
ULONG Tmp;
UNICODE_STRING OutputString;
PISID iSid;
NTSTATUS Status;
//
// Do everything as ANSI for the time being, and then
// convert to wide-char at the bottom.
//
// We need to do this until we have more complete c-runtime support
// for w-char strings.
//
iSid = (PISID) Sid;
OutputString.Buffer = OutputBuffer;
OutputString.MaximumLength = 127;
Buffer[0] = 0;
TmpBuffer[0] = 0;
AccountName.MaximumLength = 127;
AccountName.Length = (USHORT)((GetLengthSid( Sid ) > MAXUSHORT) ? MAXUSHORT : GetLengthSid( Sid ));
AccountName.Buffer = Buffer;
sprintf(TmpBuffer, "S-%u-", (USHORT)iSid->Revision );
lstrcpy(Buffer, TmpBuffer);
if ( (iSid->IdentifierAuthority.Value[0] != 0) ||
(iSid->IdentifierAuthority.Value[1] != 0) ){
sprintf(TmpBuffer, "0x%02hx%02hx%02hx%02hx%02hx%02hx",
(USHORT)iSid->IdentifierAuthority.Value[0],
(USHORT)iSid->IdentifierAuthority.Value[1],
(USHORT)iSid->IdentifierAuthority.Value[2],
(USHORT)iSid->IdentifierAuthority.Value[3],
(USHORT)iSid->IdentifierAuthority.Value[4],
(USHORT)iSid->IdentifierAuthority.Value[5] );
lstrcat(Buffer, TmpBuffer);
} else {
Tmp = (ULONG)iSid->IdentifierAuthority.Value[5] +
(ULONG)(iSid->IdentifierAuthority.Value[4] << 8) +
(ULONG)(iSid->IdentifierAuthority.Value[3] << 16) +
(ULONG)(iSid->IdentifierAuthority.Value[2] << 24);
sprintf(TmpBuffer, "%lu", Tmp);
lstrcat(Buffer, TmpBuffer);
}
for (i=0;i<iSid->SubAuthorityCount ;i++ ) {
sprintf(TmpBuffer, "-%lu", iSid->SubAuthority[i]);
lstrcat(Buffer, TmpBuffer);
}
Status = RtlAnsiStringToUnicodeString( &OutputString, &AccountName, FALSE );
ASSERT( NT_SUCCESS( Status ));
return;
}
BOOL
APIENTRY
CreateRestrictedToken(
IN HANDLE ExistingTokenHandle,
IN DWORD Flags,
IN DWORD DisableSidCount,
IN PSID_AND_ATTRIBUTES SidsToDisable OPTIONAL,
IN DWORD DeletePrivilegeCount,
IN PLUID_AND_ATTRIBUTES PrivilegesToDelete OPTIONAL,
IN DWORD RestrictedSidCount,
IN PSID_AND_ATTRIBUTES SidsToRestrict OPTIONAL,
OUT PHANDLE NewTokenHandle
)
{
NTSTATUS Status;
PTOKEN_GROUPS DisabledSids = NULL;
PTOKEN_PRIVILEGES DeletedPrivileges = NULL;
PTOKEN_GROUPS RestrictedSids = NULL;
//
// Convert the input parameters into the native NT format
//
if (DisableSidCount != 0) {
if (SidsToDisable == NULL) {
Status = STATUS_INVALID_PARAMETER;
goto Cleanup;
}
DisabledSids = (PTOKEN_GROUPS) LocalAlloc(0,sizeof(TOKEN_GROUPS) +
(DisableSidCount - 1) * sizeof(SID_AND_ATTRIBUTES) );
if (DisabledSids == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
DisabledSids->GroupCount = DisableSidCount;
RtlCopyMemory(
DisabledSids->Groups,
SidsToDisable,
DisableSidCount * sizeof(SID_AND_ATTRIBUTES)
);
}
if (DeletePrivilegeCount != 0) {
if (PrivilegesToDelete == NULL) {
Status = STATUS_INVALID_PARAMETER;
goto Cleanup;
}
DeletedPrivileges = (PTOKEN_PRIVILEGES) LocalAlloc(0,sizeof(TOKEN_PRIVILEGES) +
(DeletePrivilegeCount - 1) * sizeof(LUID_AND_ATTRIBUTES) );
if (DeletedPrivileges == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
DeletedPrivileges->PrivilegeCount = DeletePrivilegeCount;
RtlCopyMemory(
DeletedPrivileges->Privileges,
PrivilegesToDelete,
DeletePrivilegeCount * sizeof(LUID_AND_ATTRIBUTES)
);
}
if (RestrictedSidCount != 0) {
if (SidsToRestrict == NULL) {
Status = STATUS_INVALID_PARAMETER;
goto Cleanup;
}
RestrictedSids = (PTOKEN_GROUPS) LocalAlloc(0,sizeof(TOKEN_GROUPS) +
(RestrictedSidCount - 1) * sizeof(SID_AND_ATTRIBUTES) );
if (RestrictedSids == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
RestrictedSids->GroupCount = RestrictedSidCount;
RtlCopyMemory(
RestrictedSids->Groups,
SidsToRestrict,
RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES)
);
}
Status = NtFilterToken(
ExistingTokenHandle,
Flags,
DisabledSids,
DeletedPrivileges,
RestrictedSids,
NewTokenHandle
);
Cleanup:
if (DisabledSids != NULL) {
LocalFree(DisabledSids);
}
if (DeletedPrivileges != NULL) {
LocalFree(DeletedPrivileges);
}
if (RestrictedSids != NULL) {
LocalFree(RestrictedSids);
}
if (!NT_SUCCESS(Status)) {
BaseSetLastNTError( Status );
return(FALSE);
}
return(TRUE);
}
BOOL
APIENTRY
IsTokenRestricted(
IN HANDLE TokenHandle
)
{
PTOKEN_GROUPS RestrictedSids = NULL;
ULONG ReturnLength;
NTSTATUS Status;
BOOL Result = FALSE;
Status = NtQueryInformationToken(
TokenHandle,
TokenRestrictedSids,
NULL,
0,
&ReturnLength
);
if (Status != STATUS_BUFFER_TOO_SMALL)
{
BaseSetLastNTError(Status);
return(FALSE);
}
RestrictedSids = (PTOKEN_GROUPS) LocalAlloc(0, ReturnLength);
if (RestrictedSids == NULL)
{
SetLastError(ERROR_OUTOFMEMORY);
return(FALSE);
}
Status = NtQueryInformationToken(
TokenHandle,
TokenRestrictedSids,
RestrictedSids,
ReturnLength,
&ReturnLength
);
if (NT_SUCCESS(Status))
{
if (RestrictedSids->GroupCount != 0)
{
Result = TRUE;
}
}
else
{
BaseSetLastNTError(Status);
}
LocalFree(RestrictedSids);
return(Result);
}
BOOL
APIENTRY
CheckTokenMembership(
IN HANDLE TokenHandle OPTIONAL,
IN PSID SidToCheck,
OUT PBOOL IsMember
)
/*++
Routine Description:
This function checks to see whether the specified sid is enabled in
the specified token.
Arguments:
TokenHandle - If present, this token is checked for the sid. If not
present then the current effective token will be used. This must
be an impersonation token.
SidToCheck - The sid to check for presence in the token
IsMember - If the sid is enabled in the token, contains TRUE otherwise
false.
Return Value:
TRUE - The API completed successfully. It does not indicate that the
sid is a member of the token.
FALSE - The API failed. A more detailed status code can be retrieved
via GetLastError()
--*/
{
HANDLE ProcessToken = NULL;
HANDLE EffectiveToken = NULL;
NTSTATUS Status = STATUS_SUCCESS;
PISECURITY_DESCRIPTOR SecDesc = NULL;
ULONG SecurityDescriptorSize;
GENERIC_MAPPING GenericMapping = {
STANDARD_RIGHTS_READ,
STANDARD_RIGHTS_EXECUTE,
STANDARD_RIGHTS_WRITE,
STANDARD_RIGHTS_ALL };
//
// The size of the privilege set needs to contain the set itself plus
// any privileges that may be used. The privileges that are used
// are SeTakeOwnership and SeSecurity, plus one for good measure
//
BYTE PrivilegeSetBuffer[sizeof(PRIVILEGE_SET) + 3*sizeof(LUID_AND_ATTRIBUTES)];
PPRIVILEGE_SET PrivilegeSet = (PPRIVILEGE_SET) PrivilegeSetBuffer;
ULONG PrivilegeSetLength = sizeof(PrivilegeSetBuffer);
ACCESS_MASK AccessGranted = 0;
NTSTATUS AccessStatus = 0;
PACL Dacl = NULL;
#define MEMBER_ACCESS 1
*IsMember = FALSE;
//
// Get a handle to the token
//
if (ARGUMENT_PRESENT(TokenHandle))
{
EffectiveToken = TokenHandle;
}
else
{
Status = NtOpenThreadToken(
NtCurrentThread(),
TOKEN_QUERY,
FALSE, // don't open as self
&EffectiveToken
);
//
// if there is no thread token, try the process token
//
if (Status == STATUS_NO_TOKEN)
{
Status = NtOpenProcessToken(
NtCurrentProcess(),
TOKEN_QUERY | TOKEN_DUPLICATE,
&ProcessToken
);
//
// If we have a process token, we need to convert it to an
// impersonation token
//
if (NT_SUCCESS(Status))
{
BOOL Result;
Result = DuplicateToken(
ProcessToken,
SecurityImpersonation,
&EffectiveToken
);
CloseHandle(ProcessToken);
if (!Result)
{
return(FALSE);
}
}
}
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
}
//
// Construct a security descriptor to pass to access check
//
//
// The size is equal to the size of an SD + twice the length of the SID
// (for owner and group) + size of the DACL = sizeof ACL + size of the
// ACE, which is an ACE + length of
// ths SID.
//
SecurityDescriptorSize = sizeof(SECURITY_DESCRIPTOR) +
sizeof(ACCESS_ALLOWED_ACE) +
sizeof(ACL) +
3 * RtlLengthSid(SidToCheck);
SecDesc = (PISECURITY_DESCRIPTOR) LocalAlloc(LMEM_ZEROINIT, SecurityDescriptorSize );
if (SecDesc == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
Dacl = (PACL) (SecDesc + 1);
RtlCreateSecurityDescriptor(
SecDesc,
SECURITY_DESCRIPTOR_REVISION
);
//
// Fill in fields of security descriptor
//
RtlSetOwnerSecurityDescriptor(
SecDesc,
SidToCheck,
FALSE
);
RtlSetGroupSecurityDescriptor(
SecDesc,
SidToCheck,
FALSE
);
Status = RtlCreateAcl(
Dacl,
SecurityDescriptorSize - sizeof(SECURITY_DESCRIPTOR),
ACL_REVISION
);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
Status = RtlAddAccessAllowedAce(
Dacl,
ACL_REVISION,
MEMBER_ACCESS,
SidToCheck
);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
//
// Set the DACL on the security descriptor
//
Status = RtlSetDaclSecurityDescriptor(
SecDesc,
TRUE, // DACL present
Dacl,
FALSE // not defaulted
);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
Status = NtAccessCheck(
SecDesc,
EffectiveToken,
MEMBER_ACCESS,
&GenericMapping,
PrivilegeSet,
&PrivilegeSetLength,
&AccessGranted,
&AccessStatus
);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
//
// if the access check failed, then the sid is not a member of the
// token
//
if ((AccessStatus == STATUS_SUCCESS) && (AccessGranted == MEMBER_ACCESS))
{
*IsMember = TRUE;
}
Cleanup:
if (!ARGUMENT_PRESENT(TokenHandle) && (EffectiveToken != NULL))
{
(VOID) NtClose(EffectiveToken);
}
if (SecDesc != NULL)
{
LocalFree(SecDesc);
}
if (!NT_SUCCESS(Status))
{
BaseSetLastNTError(Status);
return(FALSE);
}
else
{
return(TRUE);
}
}
BOOL
APIENTRY
MakeAbsoluteSD2 (
PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor,
LPDWORD lpdwBufferSize
)
/*++
Routine Description:
Converts a security descriptor from self-relative format to absolute
format
Arguments:
pSelfRelativeSecurityDescriptor - Supplies a pointer to a security descriptor
in Self-Relative format
lpdwBufferSize - The size in bytes of the
buffer pointed to by pSelfRelativeSecurityDescriptor.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = RtlSelfRelativeToAbsoluteSD2 (
pSelfRelativeSecurityDescriptor,
lpdwBufferSize
);
//
// MakeAbsoluteSD2() has the same prototype as
// RtlSelfRelativeToAbsoluteSD2() so the parameters check
// returns the same parameter order if the caller passes invalid parameter.
//
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
} // MakeAbsoluteSD2()
DWORD
APIENTRY
GetSecurityDescriptorRMControl(
IN PSECURITY_DESCRIPTOR SecurityDescriptor,
OUT PUCHAR RMControl
)
/*++
Routine Description:
This procedure returns the RM Control flags from a SecurityDescriptor if
SE_RM_CONTROL_VALID flags is present in the control field.
Arguments:
SecurityDescriptor - Pointer to the SECURITY_DESCRIPTOR structure
RMControl - Returns the flags in the SecurityDescriptor if
SE_RM_CONTROL_VALID is set in the control bits of the
SecurityDescriptor.
Return Value:
ERROR_INVALID_DATA if the SE_RM_CONTROL_VALID flag is not present in
the security descriptor
ERROR_SUCCESS otherwise
--*/
{
BOOLEAN Result;
Result = RtlGetSecurityDescriptorRMControl(
SecurityDescriptor,
RMControl
);
if (FALSE == Result)
{
return ERROR_INVALID_DATA;
}
return ERROR_SUCCESS;
}
DWORD
APIENTRY
SetSecurityDescriptorRMControl(
IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
IN PUCHAR RMControl OPTIONAL
)
/*++
Routine Description:
This procedure sets the RM Control flag in the control field of
SecurityDescriptor and sets Sbz1 to the the byte to which RMContol point
If RMControl is NULL then the bits are cleared.
Arguments:
SecurityDescriptor - Pointer to the SECURITY_DESCRIPTOR structure
RMControl - Pointer to the flags to set. If NULL then the bits
are cleared.
Return Value: ERROR_SUCCESS
--*/
{
RtlSetSecurityDescriptorRMControl(
SecurityDescriptor,
RMControl
);
return ERROR_SUCCESS;
}
//
// Datatypes for identifying and constructing well known sids
//
//
// N.B When adding a new well known security principal, all that is
// necessary is to update one of the domain tables below. For example,
// if adding a new domain group, add an entry to AccountDomainSids
// with the new RID and the new WELL_KNOWN_SID_TYPE enumeration.
//
#define NELEMENTS(x) sizeof(x)/sizeof((x)[0])
typedef struct
{
ULONG Rid;
WELL_KNOWN_SID_TYPE Type;
} WELL_KNOWN_RID_ARRAY;
WELL_KNOWN_RID_ARRAY NullAuthoritySids[] =
{
{SECURITY_NULL_RID, WinNullSid}
};
WELL_KNOWN_RID_ARRAY WorldAuthoritySids[] =
{
{SECURITY_WORLD_RID, WinWorldSid}
};
WELL_KNOWN_RID_ARRAY LocalAuthoritySids[] =
{
{SECURITY_LOCAL_RID, WinLocalSid}
};
WELL_KNOWN_RID_ARRAY CreatorOwnerAuthoritySids[] =
{
{SECURITY_CREATOR_OWNER_RID, WinCreatorOwnerSid},
{SECURITY_CREATOR_GROUP_RID, WinCreatorGroupSid},
{SECURITY_CREATOR_OWNER_SERVER_RID, WinCreatorOwnerServerSid},
{SECURITY_CREATOR_GROUP_SERVER_RID, WinCreatorGroupServerSid}
};
WELL_KNOWN_RID_ARRAY NtAuthoritySids[] =
{
{SECURITY_DIALUP_RID, WinDialupSid},
{SECURITY_NETWORK_RID, WinNetworkSid},
{SECURITY_BATCH_RID, WinBatchSid},
{SECURITY_INTERACTIVE_RID, WinInteractiveSid},
{SECURITY_SERVICE_RID, WinServiceSid},
{SECURITY_ANONYMOUS_LOGON_RID, WinAnonymousSid},
{SECURITY_PROXY_RID, WinProxySid},
{SECURITY_ENTERPRISE_CONTROLLERS_RID, WinEnterpriseControllersSid},
{SECURITY_PRINCIPAL_SELF_RID, WinSelfSid},
{SECURITY_AUTHENTICATED_USER_RID, WinAuthenticatedUserSid},
{SECURITY_RESTRICTED_CODE_RID, WinRestrictedCodeSid},
{SECURITY_TERMINAL_SERVER_RID, WinTerminalServerSid},
{SECURITY_REMOTE_LOGON_RID, WinRemoteLogonIdSid},
//
// N.B. The Logon IDs SID is special in that it has three subauth's.
// IsWellKnownSid() special cases this, CreateWellKnownSid doesn't accept
// WinLogonIdsSid
//
// {SECURITY_LOGON_IDS_RID, WinLogonIdsSid},
{SECURITY_LOCAL_SYSTEM_RID, WinLocalSystemSid},
{SECURITY_LOCAL_SERVICE_RID, WinLocalServiceSid},
{SECURITY_NETWORK_SERVICE_RID, WinNetworkServiceSid},
{SECURITY_BUILTIN_DOMAIN_RID, WinBuiltinDomainSid},
};
WELL_KNOWN_RID_ARRAY BuiltinDomainSids[] =
{
{DOMAIN_ALIAS_RID_ADMINS, WinBuiltinAdministratorsSid},
{DOMAIN_ALIAS_RID_USERS, WinBuiltinUsersSid},
{DOMAIN_ALIAS_RID_GUESTS, WinBuiltinGuestsSid},
{DOMAIN_ALIAS_RID_POWER_USERS, WinBuiltinPowerUsersSid},
{DOMAIN_ALIAS_RID_ACCOUNT_OPS, WinBuiltinAccountOperatorsSid},
{DOMAIN_ALIAS_RID_SYSTEM_OPS, WinBuiltinSystemOperatorsSid},
{DOMAIN_ALIAS_RID_PRINT_OPS, WinBuiltinPrintOperatorsSid},
{DOMAIN_ALIAS_RID_BACKUP_OPS, WinBuiltinBackupOperatorsSid},
{DOMAIN_ALIAS_RID_REPLICATOR, WinBuiltinReplicatorSid},
{DOMAIN_ALIAS_RID_PREW2KCOMPACCESS, WinBuiltinPreWindows2000CompatibleAccessSid},
{DOMAIN_ALIAS_RID_REMOTE_DESKTOP_USERS, WinBuiltinRemoteDesktopUsersSid},
{DOMAIN_ALIAS_RID_NETWORK_CONFIGURATION_OPS, WinBuiltinNetworkConfigurationOperatorsSid},
};
WELL_KNOWN_RID_ARRAY AccountDomainSids[] =
{
{DOMAIN_USER_RID_ADMIN, WinAccountAdministratorSid},
{DOMAIN_USER_RID_GUEST, WinAccountGuestSid},
{DOMAIN_USER_RID_KRBTGT, WinAccountKrbtgtSid},
{DOMAIN_GROUP_RID_ADMINS, WinAccountDomainAdminsSid},
{DOMAIN_GROUP_RID_USERS, WinAccountDomainUsersSid},
{DOMAIN_GROUP_RID_GUESTS, WinAccountDomainGuestsSid},
{DOMAIN_GROUP_RID_COMPUTERS, WinAccountComputersSid},
{DOMAIN_GROUP_RID_CONTROLLERS, WinAccountControllersSid},
{DOMAIN_GROUP_RID_CERT_ADMINS, WinAccountCertAdminsSid},
{DOMAIN_GROUP_RID_SCHEMA_ADMINS, WinAccountSchemaAdminsSid},
{DOMAIN_GROUP_RID_ENTERPRISE_ADMINS, WinAccountEnterpriseAdminsSid},
{DOMAIN_GROUP_RID_POLICY_ADMINS, WinAccountPolicyAdminsSid},
{DOMAIN_ALIAS_RID_RAS_SERVERS, WinAccountRasAndIasServersSid},
};
typedef struct
{
SID_IDENTIFIER_AUTHORITY Authority;
WELL_KNOWN_RID_ARRAY* WellKnownRids;
ULONG Count;
} WELL_KNOWN_AUTHORITIES_TYPE;
//
// WARNING! Do not change the numbering here without changing the order
// of the KnownAuthoritiesAndDomains table. There should never be a reason
// to change the ordering.
//
#define AUTHORITY_INDEX_START 0
#define NULL_AUTHORITY_INDEX 0
#define WORLD_AUTHORITY_INDEX 1
#define LOCAL_AUTHORITY_INDEX 2
#define CREATOR_OWNER_AUTHORITY_INDEX 3
#define NT_AUTHORITY_INDEX 4
#define AUTHORITY_INDEX_SENTINEL 5
#define BUILTIN_DOMAIN_INDEX 5
#define ACCOUNT_DOMAIN_INDEX 6
WELL_KNOWN_AUTHORITIES_TYPE KnownAuthoritiesAndDomains[] =
{
{SECURITY_NULL_SID_AUTHORITY, NullAuthoritySids, NELEMENTS(NullAuthoritySids)},
{SECURITY_WORLD_SID_AUTHORITY, WorldAuthoritySids, NELEMENTS(WorldAuthoritySids)},
{SECURITY_LOCAL_SID_AUTHORITY, LocalAuthoritySids, NELEMENTS(LocalAuthoritySids)},
{SECURITY_CREATOR_SID_AUTHORITY, CreatorOwnerAuthoritySids, NELEMENTS(CreatorOwnerAuthoritySids)},
{SECURITY_NT_AUTHORITY, NtAuthoritySids, NELEMENTS(NtAuthoritySids)},
{SECURITY_NT_AUTHORITY, BuiltinDomainSids, NELEMENTS(BuiltinDomainSids)},
{SECURITY_NT_AUTHORITY, AccountDomainSids, NELEMENTS(AccountDomainSids)},
};
WINADVAPI
BOOL
WINAPI
IsWellKnownSid (
IN PSID pSid,
IN WELL_KNOWN_SID_TYPE WellKnownSidType
)
/*++
Routine Description:
This routine determines is pSID is the well known SID specified.
It is purely runtime routine (that is, it makes no network or kernel
calls).
Parameters:
pSid -- the SID to inspect
WellKnownSidType - the well known SID to check for
Return Values
TRUE is the SID matches the well known SID,
FALSE otherwise
--*/
{
ULONG i;
BOOL fFound = FALSE;
WELL_KNOWN_SID_TYPE Type;
SID_IDENTIFIER_AUTHORITY *pAuthority = NULL;
WELL_KNOWN_RID_ARRAY *RidArray = NULL;
UCHAR SubAuthCount = 0;
ULONG RidArrayCount;
#define IS_EQUAL_AUTHORITY(x, y) \
RtlEqualMemory((x),(y),sizeof(SID_IDENTIFIER_AUTHORITY))
//
// Guard against bad parameters
//
if (!RtlValidSid(pSid)) {
return FALSE;
}
pAuthority = GetSidIdentifierAuthority(pSid);
if (NULL == pAuthority) {
return FALSE;
}
SubAuthCount = *RtlSubAuthorityCountSid(pSid);
if (SubAuthCount == 0) {
//
// Only one such known sid -- the Nt Authority domain sid has no
// sub auth's
//
if ( IS_EQUAL_AUTHORITY(pAuthority,
&KnownAuthoritiesAndDomains[NT_AUTHORITY_INDEX].Authority) ) {
fFound = TRUE;
Type = WinNtAuthoritySid;
}
} else if (SubAuthCount == 1) {
//
// Try the known authorities that aren't domains
//
for ( i = AUTHORITY_INDEX_START; i < AUTHORITY_INDEX_SENTINEL; i++) {
if (IS_EQUAL_AUTHORITY(pAuthority,
&KnownAuthoritiesAndDomains[i].Authority)) {
RidArray = KnownAuthoritiesAndDomains[i].WellKnownRids;
RidArrayCount = KnownAuthoritiesAndDomains[i].Count;
break;
}
}
} else if (SubAuthCount > 1) {
//
// Try the domains (builtin and account)
//
if ( IS_EQUAL_AUTHORITY(pAuthority,
&KnownAuthoritiesAndDomains[NT_AUTHORITY_INDEX].Authority) ) {
ULONG FirstSubAuth = *RtlSubAuthoritySid(pSid, 0);
if ( (FirstSubAuth == SECURITY_BUILTIN_DOMAIN_RID)
&& (SubAuthCount == 2) ) {
// Builtin domain sids always have 2 sub auth's: the builtin
// RID and the principal RID
RidArray = BuiltinDomainSids;
RidArrayCount = NELEMENTS(BuiltinDomainSids);
} else if ((FirstSubAuth == SECURITY_NT_NON_UNIQUE)
&& (SubAuthCount == SECURITY_NT_NON_UNIQUE_SUB_AUTH_COUNT+2)){
// These account domains have
// 1 subauth for the SECURITY_NT_NON_UNIQUE,
// 1 for the principal and
// SECURITY_NT_NON_UNIQUE_SUB_AUTH_COUNT for the domain portion
RidArray = AccountDomainSids;
RidArrayCount = NELEMENTS(AccountDomainSids);
} else if ( (FirstSubAuth == SECURITY_LOGON_IDS_RID)
&& (SubAuthCount == SECURITY_LOGON_IDS_RID_COUNT)) {
//
// This is the special LogonId sid S-1-5-5-X-Y
//
fFound = TRUE;
Type = WinLogonIdsSid;
}
}
}
//
// If we matched for authority or domain, try to match RID
//
if ( RidArray ) {
ULONG Rid;
ASSERT(SubAuthCount > 0);
Rid = *RtlSubAuthoritySid(pSid, SubAuthCount - 1);
for (i = 0; i < RidArrayCount; i++) {
if (Rid == RidArray[i].Rid) {
fFound = TRUE;
Type = RidArray[i].Type;
break;
}
}
}
if (fFound && (Type == WellKnownSidType)) {
fFound = TRUE;
} else {
fFound = FALSE;
}
return fFound;
}
WINADVAPI
BOOL
WINAPI
CreateWellKnownSid(
IN WELL_KNOWN_SID_TYPE WellKnownSidType,
IN PSID pDomainSid OPTIONAL,
OUT PSID pSid,
IN OUT DWORD *cbSid
)
/*++
Routine Description:
This routines creates the SID of a well known principal.
Parameters:
WellKnownSidType - the well known account sid that the caller desires
pDomainSid - if the WellKnownSidType is an SID from an Account domain, this
value can be set; if not set and the WellKnownSidType is from
an Account domain, the local account domain will be used - this
may result in an ACCESS_DENIED if the caller doesn't have
access to read the local account domain sid. If the
WellKnownSidType is not from an Account domain, this parameter
is ignored.
pSID - a client allocated buffer
cbSid - the number of bytes pointed to by pSID
Return Values
TRUE if WellKnownSidType is understood and pSID points to a buffer large
enough to hold the SID
FALSE otherwise
--*/
{
BOOL fFound = FALSE;
ULONG Rid;
ULONG i, j;
ULONG SizeRequired;
NTSTATUS Status;
UCHAR SubAuthCount;
if (pDomainSid && !RtlValidSid(pDomainSid)) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (IsBadWritePtr(cbSid, sizeof(*cbSid))) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
// special case -- can't create this one
if (WinLogonIdsSid == WellKnownSidType) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
//
// Find the requested type
//
for (i = 0; i < NELEMENTS(KnownAuthoritiesAndDomains); i++) {
for (j = 0; j < KnownAuthoritiesAndDomains[i].Count; j++) {
if (WellKnownSidType == KnownAuthoritiesAndDomains[i].WellKnownRids[j].Type){
Rid = KnownAuthoritiesAndDomains[i].WellKnownRids[j].Rid;
fFound = TRUE;
break;
}
}
if (fFound) {
break;
}
}
// special case since the NtAuthority domain doesn't have any sub auth's
if (!fFound && (WellKnownSidType == WinNtAuthoritySid)) {
i = NT_AUTHORITY_INDEX;
fFound = TRUE;
}
if (!fFound) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
//
// Determine how much space we need
//
switch (i) {
case NULL_AUTHORITY_INDEX:
case WORLD_AUTHORITY_INDEX:
case LOCAL_AUTHORITY_INDEX:
case CREATOR_OWNER_AUTHORITY_INDEX:
case NT_AUTHORITY_INDEX:
if (WellKnownSidType == WinNtAuthoritySid) {
SubAuthCount = 0;
} else {
SubAuthCount = 1;
}
break;
case BUILTIN_DOMAIN_INDEX:
SubAuthCount = 2;
break;
case ACCOUNT_DOMAIN_INDEX:
if (NULL == pDomainSid) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
SubAuthCount = *RtlSubAuthorityCountSid(pDomainSid);
if (SubAuthCount == SID_MAX_SUB_AUTHORITIES) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
// Add for the RID
SubAuthCount++;
break;
default:
ASSERT(!"Invalid index");
}
//
// Make sure we have enough space
//
SizeRequired = GetSidLengthRequired(SubAuthCount);
if (*cbSid < SizeRequired) {
*cbSid = SizeRequired;
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
*cbSid = SizeRequired;
if (IsBadWritePtr(pSid, SizeRequired)) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
//
// Fill the sid in
//
switch (i) {
case ACCOUNT_DOMAIN_INDEX:
Status = RtlCopySid(*cbSid, pSid, pDomainSid);
if (NT_SUCCESS(Status)) {
(*RtlSubAuthorityCountSid(pSid))++;
}
break;
case BUILTIN_DOMAIN_INDEX:
case NULL_AUTHORITY_INDEX:
case WORLD_AUTHORITY_INDEX:
case LOCAL_AUTHORITY_INDEX:
case CREATOR_OWNER_AUTHORITY_INDEX:
case NT_AUTHORITY_INDEX:
Status = RtlInitializeSid(pSid,
&KnownAuthoritiesAndDomains[i].Authority,
SubAuthCount);
if (NT_SUCCESS(Status) && (i == BUILTIN_DOMAIN_INDEX)) {
ASSERT(SubAuthCount > 1);
*RtlSubAuthoritySid(pSid, 0) = SECURITY_BUILTIN_DOMAIN_RID;
}
break;
default:
ASSERT(!"Invalid index");
}
if (!NT_SUCCESS(Status)) {
BaseSetLastNTError(Status);
return FALSE;
}
//
// Append the Rid
//
if (SubAuthCount > 0) {
*RtlSubAuthoritySid(pSid, SubAuthCount-1) = Rid;
}
return TRUE;
}
WINADVAPI
BOOL
WINAPI
GetWindowsAccountDomainSid(
IN PSID pSid,
IN OUT PSID pDomainSid OPTIONAL,
OUT DWORD* cbDomainSid
)
/*++
Routine Description:
This routine returns the domain portion of pSid, if any if the SID is
from an account domain. If the SID is not from an account domain, then
ERROR_NON_ACCOUNT_SID is returned.
Parameters:
pSid -- the SID from which to extract the domain portion
pDomainSid -- the domain portion of pSid; caller must allocate buffer
cbDomainSid -- the number of bytes pointed to by pDomainSid; if
insufficient, this value will be set to the number of
bytes required.
Return Values
TRUE if a domain portion could be extracted and placed into pDomainSid
FALSE otherwise; win32 errors are
ERROR_INVALID_SID
ERROR_INVALID_PARAMETER
ERROR_NON_ACCOUNT_SID
ERROR_INSUFFICIENT_BUFFER
--*/
{
NTSTATUS Status;
ULONG SizeRequired;
UCHAR SubAuthCount;
UCHAR DomainSubAuthCount = 0;
BOOL fRecognized = FALSE;
ULONG i;
if (!RtlValidSid(pSid)) {
SetLastError(ERROR_INVALID_SID);
return FALSE;
}
if (cbDomainSid == NULL) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if ( IS_EQUAL_AUTHORITY(RtlIdentifierAuthoritySid(pSid),
&KnownAuthoritiesAndDomains[NT_AUTHORITY_INDEX].Authority)) {
SubAuthCount = *RtlSubAuthorityCountSid(pSid);
if (SubAuthCount > SECURITY_NT_NON_UNIQUE_SUB_AUTH_COUNT) {
ULONG FirstSubAuth;
FirstSubAuth = *RtlSubAuthoritySid(pSid, 0);
if ( (SECURITY_NT_NON_UNIQUE == FirstSubAuth) ) {
// This is an NT Account Domain
DomainSubAuthCount = SECURITY_NT_NON_UNIQUE_SUB_AUTH_COUNT+1;
fRecognized = TRUE;
}
}
}
if (!fRecognized) {
SetLastError(ERROR_NON_ACCOUNT_SID);
return FALSE;
}
SizeRequired = RtlLengthRequiredSid(DomainSubAuthCount);
if (*cbDomainSid < SizeRequired) {
*cbDomainSid = SizeRequired;
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
*cbDomainSid = SizeRequired;
if (IsBadWritePtr(pDomainSid, SizeRequired)) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
Status = RtlInitializeSid(pDomainSid,
RtlIdentifierAuthoritySid(pSid),
DomainSubAuthCount);
if (!NT_SUCCESS(Status)) {
BaseSetLastNTError(Status);
return FALSE;
}
for (i = 0; i < DomainSubAuthCount; i++) {
*RtlSubAuthoritySid(pDomainSid, i) = *RtlSubAuthoritySid(pSid,i);
}
return TRUE;
}
WINADVAPI
BOOL
WINAPI
EqualDomainSid(
IN PSID pSid1,
IN PSID pSid2,
OUT BOOL *pfEqual
)
/*++
Routine Description:
This routine determines if either
1) Both sids are the same domain SID
2) One SID is from the other SID's domain
The "domains" recognized are BUILTIN and NT account domains
Parameters:
pSid1 -- the first SID
pSid2 -- the second SID
pfEqual -- on success, set to TRUE if the domain portions are equal
Return Values
TRUE if the SID's are recognized (are either from an account domain or
the BUILTIN domain).
FALSE otherwise
Win32 Errors:
ERROR_NON_DOMAIN_SID
ERROR_REVISION_MISMATCH
ERROR_INVALID_PARAMETER
ERROR_INVALID_SID
--*/
{
ULONG i;
SID *ISid1 = pSid1;
SID *ISid2 = pSid2;
BYTE Buffer1[SECURITY_MAX_SID_SIZE];
PSID BuiltinDomainSid = (PSID) Buffer1;
BYTE Buffer2[SECURITY_MAX_SID_SIZE];
PSID pDomainSid1 = (PSID) Buffer2;
BYTE Buffer3[SECURITY_MAX_SID_SIZE];
PSID pDomainSid2 = (PSID) Buffer3;
ULONG Size;
if ( !RtlValidSid(pSid1) || !RtlValidSid(pSid2) ) {
SetLastError(ERROR_INVALID_SID);
return FALSE;
}
if (NULL == pfEqual) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if ( ISid1->Revision != ISid2->Revision ) {
SetLastError(ERROR_REVISION_MISMATCH);
return FALSE;
}
// Create the builtin SID
Size = sizeof(Buffer1);
if (!CreateWellKnownSid(WinBuiltinDomainSid, NULL, BuiltinDomainSid, &Size)) {
// LastError is set
return FALSE;
}
// Extract the first SID's domain portion if any
Size = sizeof(Buffer2);
if (!GetWindowsAccountDomainSid(pSid1, pDomainSid1, &Size)) {
// The SID is not an account domain SID -- try for builtin
pDomainSid1 = NULL;
if ( (IS_EQUAL_AUTHORITY(RtlIdentifierAuthoritySid(pSid1), &KnownAuthoritiesAndDomains[NT_AUTHORITY_INDEX].Authority))
&& (*RtlSubAuthorityCountSid(pSid1) > 0)
&& (*RtlSubAuthoritySid(pSid1, 0) == SECURITY_BUILTIN_DOMAIN_RID)) {
pDomainSid1 = BuiltinDomainSid;
}
}
if (NULL == pDomainSid1) {
SetLastError(ERROR_NON_DOMAIN_SID);
return FALSE;
}
Size = sizeof(Buffer3);
if (!GetWindowsAccountDomainSid(pSid2, pDomainSid2, &Size)) {
// The SID is not an account domain SID -- try for builtin
pDomainSid2 = NULL;
if ( (IS_EQUAL_AUTHORITY(RtlIdentifierAuthoritySid(pSid2), &KnownAuthoritiesAndDomains[NT_AUTHORITY_INDEX].Authority))
&& (*RtlSubAuthorityCountSid(pSid2) > 0)
&& (*RtlSubAuthoritySid(pSid2, 0) == SECURITY_BUILTIN_DOMAIN_RID)) {
pDomainSid2 = BuiltinDomainSid;
}
}
if (NULL == pDomainSid2) {
SetLastError(ERROR_NON_DOMAIN_SID);
return FALSE;
}
*pfEqual = EqualSid(pDomainSid1, pDomainSid2);
return TRUE;
}