windows-nt/Source/XPSP1/NT/admin/services/drizzle/utils/nt4thunks.cpp

881 lines
20 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/************************************************************************
Copyright (c) 2000 - 2001 Microsoft Corporation
Module Name :
nt4thunks.cpp
Abstract :
General helper functions to get BITS to work on NT4
Author :
Revision History :
***********************************************************************/
#include "qmgrlibp.h"
#include <bitsmsg.h>
#include <sddl.h>
#include <shlwapi.h>
#if !defined(BITS_V12_ON_NT4)
#include "nt4thunks.tmh"
#endif
#if defined( BITS_V12_ON_NT4 )
BOOL
BITSAltGetFileSizeEx(
HANDLE hFile, // handle to file
PLARGE_INTEGER lpFileSize // file size
)
{
DWORD HighPart;
DWORD Result =
GetFileSize( hFile, &HighPart );
if ( INVALID_FILE_SIZE == Result &&
GetLastError() != NO_ERROR )
return FALSE;
lpFileSize->HighPart = (LONG)HighPart;
lpFileSize->LowPart = Result;
return TRUE;
}
BOOL
BITSAltSetFilePointerEx(
HANDLE hFile, // handle to file
LARGE_INTEGER liDistanceToMove, // bytes to move pointer
PLARGE_INTEGER lpNewFilePointer, // new file pointer
DWORD dwMoveMethod // starting point
)
{
LONG DistanceToMoveHigh = liDistanceToMove.HighPart;
DWORD DistanceToMoveLow = liDistanceToMove.LowPart;
DWORD Result =
SetFilePointer(
hFile,
(LONG)DistanceToMoveLow,
&DistanceToMoveHigh,
dwMoveMethod );
if ( INVALID_SET_FILE_POINTER == Result &&
NO_ERROR != GetLastError() )
return FALSE;
if ( lpNewFilePointer )
{
lpNewFilePointer->HighPart = DistanceToMoveHigh;
lpNewFilePointer->LowPart = (DWORD)DistanceToMoveLow;
}
return TRUE;
}
//
// Local macros
//
#define STRING_GUID_LEN 36
#define STRING_GUID_SIZE ( STRING_GUID_LEN * sizeof( WCHAR ) )
#define SDDL_LEN_TAG( tagdef ) ( sizeof( tagdef ) / sizeof( WCHAR ) - 1 )
#define SDDL_SIZE_TAG( tagdef ) ( wcslen( tagdef ) * sizeof( WCHAR ) )
#define SDDL_SIZE_SEP( sep ) (sizeof( WCHAR ) )
#define SDDL_VALID_DACL 0x00000001
#define SDDL_VALID_SACL 0x00000002
ULONG
BITSAltSetLastNTError(
IN NTSTATUS Status
)
{
ULONG dwErrorCode;
dwErrorCode = RtlNtStatusToDosError( Status );
SetLastError( dwErrorCode );
return( dwErrorCode );
}
BOOL
BITSAltConvertSidToStringSidW(
IN PSID Sid,
OUT LPWSTR *StringSid
)
/*++
Routine Description:
This routine converts a SID into a string representation of a SID, suitable for framing or
display
Arguments:
Sid - SID to be converted.
StringSid - Where the converted SID is returned. Allocated via LocalAlloc and needs to
be freed via LocalFree.
Return Value:
TRUE - Success
FALSE - Failure
Extended error status is available using GetLastError.
--*/
{
NTSTATUS Status;
UNICODE_STRING UnicodeStringSid;
if ( NULL == Sid || NULL == StringSid ) {
//
// invalid parameter
//
SetLastError( ERROR_INVALID_PARAMETER );
return( FALSE );
}
//
// Convert using the Rtl functions
//
Status = RtlConvertSidToUnicodeString( &UnicodeStringSid, Sid, TRUE );
if ( !NT_SUCCESS( Status ) ) {
BITSAltSetLastNTError( Status );
return( FALSE );
}
//
// Convert it to the proper allocator
//
*StringSid = (LPWSTR)LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT,
UnicodeStringSid.Length + sizeof( WCHAR ) );
if ( *StringSid == NULL ) {
RtlFreeUnicodeString( &UnicodeStringSid );
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
return( FALSE );
}
RtlCopyMemory( *StringSid, UnicodeStringSid.Buffer, UnicodeStringSid.Length );
RtlFreeUnicodeString( &UnicodeStringSid );
SetLastError(ERROR_SUCCESS);
return( TRUE );
}
//
// Private functions
//
BOOL
LocalConvertStringSidToSid (
IN PWSTR StringSid,
OUT PSID *Sid,
OUT PWSTR *End
)
/*++
Routine Description:
This routine will convert a string representation of a SID back into
a sid. The expected format of the string is:
"S-1-5-32-549"
If a string in a different format or an incorrect or incomplete string
is given, the operation is failed.
The returned sid must be free via a call to LocalFree
Arguments:
StringSid - The string to be converted
Sid - Where the created SID is to be returned
End - Where in the string we stopped processing
Return Value:
TRUE - Success.
FALSE - Failure. Additional information returned from GetLastError(). Errors set are:
ERROR_SUCCESS indicates success
ERROR_NOT_ENOUGH_MEMORY indicates a memory allocation for the ouput sid
failed
ERROR_INVALID_SID indicates that the given string did not represent a sid
--*/
{
DWORD Err = ERROR_SUCCESS;
UCHAR Revision, Subs;
SID_IDENTIFIER_AUTHORITY IDAuth;
PULONG SubAuth = NULL;
PWSTR CurrEnd, Curr, Next;
WCHAR Stub, *StubPtr = NULL;
ULONG Index;
INT gBase=10;
INT lBase=10;
ULONG Auto;
if ( NULL == StringSid || NULL == Sid || NULL == End ) {
SetLastError( ERROR_INVALID_PARAMETER );
return( FALSE );
}
// if ( wcslen( StringSid ) < 2 || ( *StringSid != L'S' && *( StringSid + 1 ) != L'-' ) ) {
//
// no need to check length because StringSid is NULL
// and if the first char is NULL, it won't access the second char
//
if ( (*StringSid != L'S' && *StringSid != L's') ||
*( StringSid + 1 ) != L'-' ) {
//
// string sid should always start with S-
//
SetLastError( ERROR_INVALID_SID );
return( FALSE );
}
Curr = StringSid + 2;
if ( (*Curr == L'0') &&
( *(Curr+1) == L'x' ||
*(Curr+1) == L'X' ) ) {
gBase = 16;
}
Revision = ( UCHAR )wcstol( Curr, &CurrEnd, gBase );
if ( CurrEnd == Curr || *CurrEnd != L'-' || *(CurrEnd+1) == L'\0' ) {
//
// no revision is provided, or invalid delimeter
//
SetLastError( ERROR_INVALID_SID );
return( FALSE );
}
Curr = CurrEnd + 1;
//
// Count the number of characters in the indentifer authority...
//
Next = wcschr( Curr, L'-' );
/*
Length = 6 doesn't mean each digit is a id authority value, could be 0x...
if ( Next != NULL && (Next - Curr == 6) ) {
for ( Index = 0; Index < 6; Index++ ) {
// IDAuth.Value[Index] = (UCHAR)Next[Index]; what is this ???
IDAuth.Value[Index] = (BYTE) (Curr[Index]-L'0');
}
Curr +=6;
} else {
*/
if ( (*Curr == L'0') &&
( *(Curr+1) == L'x' ||
*(Curr+1) == L'X' ) ) {
lBase = 16;
} else {
lBase = gBase;
}
Auto = wcstoul( Curr, &CurrEnd, lBase );
if ( CurrEnd == Curr || *CurrEnd != L'-' || *(CurrEnd+1) == L'\0' ) {
//
// no revision is provided, or invalid delimeter
//
SetLastError( ERROR_INVALID_SID );
return( FALSE );
}
IDAuth.Value[0] = IDAuth.Value[1] = 0;
IDAuth.Value[5] = ( UCHAR )Auto & 0xFF;
IDAuth.Value[4] = ( UCHAR )(( Auto >> 8 ) & 0xFF );
IDAuth.Value[3] = ( UCHAR )(( Auto >> 16 ) & 0xFF );
IDAuth.Value[2] = ( UCHAR )(( Auto >> 24 ) & 0xFF );
Curr = CurrEnd;
// }
//
// Now, count the number of sub auths, at least one sub auth is required
//
Subs = 0;
Next = Curr;
//
// We'll have to count our sub authoritys one character at a time,
// since there are several deliminators that we can have...
//
while ( Next ) {
if ( *Next == L'-' && *(Next-1) != L'-') {
//
// do not allow two continuous '-'s
// We've found one!
//
Subs++;
if ( (*(Next+1) == L'0') &&
( *(Next+2) == L'x' ||
*(Next+2) == L'X' ) ) {
//
// this is hex indicator
//
Next += 2;
}
} else if ( *Next == SDDL_SEPERATORC || *Next == L'\0' ||
*Next == SDDL_ACE_ENDC || *Next == L' ' ||
( *(Next+1) == SDDL_DELIMINATORC &&
(*Next == L'G' || *Next == L'O' || *Next == L'S')) ) {
//
// space is a terminator too
//
if ( *( Next - 1 ) == L'-' ) {
//
// shouldn't allow a SID terminated with '-'
//
Err = ERROR_INVALID_SID;
Next--;
} else {
Subs++;
}
*End = Next;
break;
} else if ( !iswxdigit( *Next ) ) {
Err = ERROR_INVALID_SID;
*End = Next;
// Subs++;
break;
} else {
//
// Note: SID is also used as a owner or group
//
// Some of the tags (namely 'D' for Dacl) fall under the category of iswxdigit, so
// if the current character is a character we care about and the next one is a
// delminiator, we'll quit
//
if ( *Next == L'D' && *( Next + 1 ) == SDDL_DELIMINATORC ) {
//
// We'll also need to temporarily truncate the string to this length so
// we don't accidentally include the character in one of the conversions
//
Stub = *Next;
StubPtr = Next;
*StubPtr = UNICODE_NULL;
*End = Next;
Subs++;
break;
}
}
Next++;
}
if ( Err == ERROR_SUCCESS ) {
if ( Subs != 0 ) Subs--;
if ( Subs != 0 ) {
Curr++;
SubAuth = ( PULONG )LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, Subs * sizeof( ULONG ) );
if ( SubAuth == NULL ) {
Err = ERROR_NOT_ENOUGH_MEMORY;
} else {
for ( Index = 0; Index < Subs; Index++ ) {
if ( (*Curr == L'0') &&
( *(Curr+1) == L'x' ||
*(Curr+1) == L'X' ) ) {
lBase = 16;
} else {
lBase = gBase;
}
SubAuth[Index] = wcstoul( Curr, &CurrEnd, lBase );
Curr = CurrEnd + 1;
}
}
} else {
Err = ERROR_INVALID_SID;
}
}
//
// Now, create the SID
//
if ( Err == ERROR_SUCCESS ) {
*Sid = ( PSID )LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT,
sizeof( SID ) + Subs * sizeof( ULONG ) );
if ( *Sid == NULL ) {
Err = ERROR_NOT_ENOUGH_MEMORY;
} else {
PISID ISid = ( PISID )*Sid;
ISid->Revision = Revision;
ISid->SubAuthorityCount = Subs;
RtlCopyMemory( &( ISid->IdentifierAuthority ), &IDAuth,
sizeof( SID_IDENTIFIER_AUTHORITY ) );
RtlCopyMemory( ISid->SubAuthority, SubAuth, Subs * sizeof( ULONG ) );
}
}
LocalFree( SubAuth );
//
// Restore any character we may have stubbed out
//
if ( StubPtr ) {
*StubPtr = Stub;
}
SetLastError( Err );
return( Err == ERROR_SUCCESS );
}
BOOL
BITSAltConvertStringSidToSidW(
IN LPCWSTR StringSid,
OUT PSID *Sid
)
/*++
Routine Description:
This routine converts a stringized SID into a valid, functional SID
Arguments:
StringSid - SID to be converted.
Sid - Where the converted SID is returned. Buffer is allocated via LocalAlloc and should
be free via LocalFree.
Return Value:
TRUE - Success
FALSE - Failure
Extended error status is available using GetLastError.
ERROR_INVALID_PARAMETER - A NULL name was given
ERROR_INVALID_SID - The format of the given sid was incorrect
--*/
{
PWSTR End = NULL;
BOOL ReturnValue = FALSE;
PSID pSASid=NULL;
ULONG Len=0;
DWORD SaveCode=0;
DWORD Err=0;
if ( StringSid == NULL || Sid == NULL )
{
SetLastError( ERROR_INVALID_PARAMETER );
return ReturnValue;
}
ReturnValue = LocalConvertStringSidToSid( ( PWSTR )StringSid, Sid, &End );
if ( !ReturnValue )
{
SetLastError( ERROR_INVALID_PARAMETER );
return ReturnValue;
}
if ( ( ULONG )( End - StringSid ) != wcslen( StringSid ) ) {
SetLastError( ERROR_INVALID_SID );
LocalFree( *Sid );
*Sid = FALSE;
ReturnValue = FALSE;
} else {
SetLastError(ERROR_SUCCESS);
}
return ReturnValue;
}
BOOL
BITSAltCheckTokenMembership(
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))
{
BITSAltSetLastNTError(Status);
return(FALSE);
}
else
{
return(TRUE);
}
}
LPHANDLER_FUNCTION_EX g_BITSAltRegisterServiceFunc = NULL;
typedef SERVICE_STATUS_HANDLE (*REGISTER_FUNC_TYPE)(LPCTSTR, LPHANDLER_FUNCTION_EX, LPVOID lpContext);
VOID WINAPI
BITSAltRegisterServiceThunk(
DWORD dwControl // requested control code
)
{
(*g_BITSAltRegisterServiceFunc)( dwControl, 0, NULL, NULL );
return;
}
SERVICE_STATUS_HANDLE
BITSAltRegisterServiceCtrlHandlerExW(
LPCTSTR lpServiceName, // name of service
LPHANDLER_FUNCTION_EX lpHandlerProc, // handler function
LPVOID lpContext // user data
)
{
// First check if RegisterServerCtrlHandlerEx if available and use
// it, otherwise thunk the call.
HMODULE AdvapiHandle = LoadLibraryW( L"advapi32.dll" );
if ( !AdvapiHandle )
{
// Something is messed up, every machine should have this DLL.
return NULL;
}
SERVICE_STATUS_HANDLE ReturnValue;
FARPROC RegisterFunc = GetProcAddress( AdvapiHandle, "RegisterServiceCtrlHandlerExW" );
if ( RegisterFunc )
{
ReturnValue = (*(REGISTER_FUNC_TYPE)RegisterFunc)( lpServiceName, lpHandlerProc, lpContext );
}
else
{
if ( g_BITSAltRegisterServiceFunc || lpContext )
{
ReturnValue = 0;
SetLastError( ERROR_INVALID_PARAMETER );
}
else
{
g_BITSAltRegisterServiceFunc = lpHandlerProc;
ReturnValue = RegisterServiceCtrlHandler( lpServiceName, BITSAltRegisterServiceThunk );
if ( !ReturnValue)
g_BITSAltRegisterServiceFunc = NULL;
}
}
DWORD OldError = GetLastError();
FreeLibrary( AdvapiHandle );
SetLastError( OldError );
return ReturnValue;
}
#endif