mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
10194 lines
263 KiB
10194 lines
263 KiB
/*++
|
|
|
|
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;
|
|
|
|
}
|