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.
2514 lines
54 KiB
2514 lines
54 KiB
/*++
|
|
|
|
Copyright (c) 2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
util.cxx
|
|
|
|
Abstract:
|
|
|
|
Utility routines
|
|
|
|
Author:
|
|
|
|
Cliff Van Dyke (cliffv) 11-Apr-2001
|
|
|
|
--*/
|
|
|
|
|
|
#include "pch.hxx"
|
|
#include <dispex.h>
|
|
|
|
#if DBG
|
|
//
|
|
// List of all allocated blocks
|
|
// AccessSerialized by AzGlAllocatorCritSect
|
|
LIST_ENTRY AzGlAllocatedBlocks;
|
|
SAFE_CRITICAL_SECTION AzGlAllocatorCritSect;
|
|
|
|
//
|
|
// Force C++ to use our allocator
|
|
//
|
|
|
|
void * __cdecl operator new(size_t s) {
|
|
return AzpAllocateHeap( s, "UTILNEW" );
|
|
}
|
|
|
|
void __cdecl operator delete(void *pv) {
|
|
AzpFreeHeap( pv );
|
|
}
|
|
|
|
#endif // DBG
|
|
|
|
|
|
|
|
DWORD
|
|
AzpGetCurrentToken(
|
|
OUT PHANDLE hToken
|
|
)
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Returns the effective token on the thread.
|
|
|
|
Arguments
|
|
|
|
hToken - To return the handle to the effective token.
|
|
|
|
Return Value
|
|
|
|
DWORD error value.
|
|
|
|
--*/
|
|
{
|
|
DWORD WinStatus;
|
|
|
|
//
|
|
// First open the thread token.
|
|
//
|
|
|
|
if ( OpenThreadToken(
|
|
GetCurrentThread(),
|
|
TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
|
|
TRUE,
|
|
hToken ) ) {
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
WinStatus = GetLastError();
|
|
|
|
//
|
|
// If we failed because of any error other than thread not impersonating,
|
|
// give up and return the error.
|
|
//
|
|
|
|
if ( WinStatus != ERROR_NO_TOKEN ) {
|
|
return WinStatus;
|
|
}
|
|
|
|
//
|
|
// We are not impersonating. Open the process token instead.
|
|
//
|
|
|
|
if ( OpenProcessToken(
|
|
GetCurrentProcess(),
|
|
TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
|
|
hToken ) ) {
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
return GetLastError();
|
|
}
|
|
|
|
DWORD
|
|
AzpChangeSinglePrivilege(
|
|
IN DWORD PrivilegeValue,
|
|
IN HANDLE hToken,
|
|
IN PTOKEN_PRIVILEGES NewPrivilegeState,
|
|
OUT PTOKEN_PRIVILEGES OldPrivilegeState OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
This routine has two functions:
|
|
1. Enable a given privilege and return the Old state of the privilege in
|
|
the token.
|
|
2. Revert back to the original state once the operation for which we had
|
|
enabled the privilege has been performed.
|
|
|
|
Arguments
|
|
|
|
PrivilegeValue - The privilege to enable. This is ignored when
|
|
OldPrivilegesState is NULL.
|
|
|
|
hToken - Token to adjust.
|
|
|
|
NewPrivilegeState - The new value for the privilege.
|
|
|
|
OldPrivilegeState - Buffer to hold the Old privilege state. The size of this
|
|
is assumed to be sizeof(TOKEN_PRIVILEGES) and is sufficient to hold the
|
|
Old state since we are only adjusting a single privilege.
|
|
When this is NULL, we are reverting.
|
|
|
|
Return Value
|
|
|
|
Returns a pointer to the allocated memory.
|
|
NULL - Not enough memory
|
|
|
|
--*/
|
|
{
|
|
|
|
DWORD BufferSize = 0;
|
|
|
|
//
|
|
// When there is no Old state, we enable the privilege supplied.
|
|
// When there is Old state we set it back.
|
|
//
|
|
|
|
if ( ARGUMENT_PRESENT( OldPrivilegeState ) ) {
|
|
NewPrivilegeState->PrivilegeCount = 1;
|
|
NewPrivilegeState->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
|
NewPrivilegeState->Privileges[0].Luid = RtlConvertLongToLuid( PrivilegeValue );
|
|
} else if ( NewPrivilegeState->PrivilegeCount == 0) {
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
//
|
|
// Adjust the token to change the privilege state.
|
|
//
|
|
|
|
AdjustTokenPrivileges (
|
|
hToken,
|
|
FALSE,
|
|
NewPrivilegeState,
|
|
sizeof(TOKEN_PRIVILEGES),
|
|
OldPrivilegeState,
|
|
&BufferSize );
|
|
|
|
return GetLastError();
|
|
}
|
|
|
|
|
|
PVOID
|
|
AzpAllocateHeap(
|
|
IN SIZE_T Size,
|
|
IN LPSTR pDescr OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Memory allocator. The pDescr field is ignored for Free builds
|
|
|
|
Arguments
|
|
|
|
Size - Size (in bytes) to allocate
|
|
|
|
pDescr - Optional string identifying the block of not more than 8 chars.
|
|
|
|
Return Value
|
|
|
|
Returns a pointer to the allocated memory.
|
|
NULL - Not enough memory
|
|
|
|
--*/
|
|
{
|
|
|
|
DBG_UNREFERENCED_PARAMETER( pDescr ); //ignore
|
|
|
|
#if DBG
|
|
ULONG HeaderSize;
|
|
ULONG DescrSize = sizeof(DWORD) * 2;
|
|
|
|
PLIST_ENTRY RealBlock;
|
|
|
|
HeaderSize = ROUND_UP_COUNT( sizeof(LIST_ENTRY) + DescrSize,
|
|
ALIGN_WORST );
|
|
//
|
|
// Allocate a block with a header
|
|
//
|
|
|
|
RealBlock = (PLIST_ENTRY) LocalAlloc( 0, HeaderSize + Size );
|
|
|
|
if ( RealBlock == NULL ) {
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Link the block since we're nosey.
|
|
//
|
|
|
|
ASSERT( pDescr != NULL );
|
|
RtlZeroMemory( ((LPBYTE)RealBlock)+sizeof(LIST_ENTRY), DescrSize );
|
|
if ( pDescr != NULL ) {
|
|
|
|
memcpy( ((LPBYTE)RealBlock)+sizeof(LIST_ENTRY),
|
|
(LPBYTE)pDescr,
|
|
DescrSize
|
|
);
|
|
}
|
|
|
|
SafeEnterCriticalSection( &AzGlAllocatorCritSect );
|
|
InsertHeadList( &AzGlAllocatedBlocks, RealBlock );
|
|
SafeLeaveCriticalSection( &AzGlAllocatorCritSect );
|
|
|
|
return (PVOID)(((LPBYTE)RealBlock)+HeaderSize);
|
|
|
|
#else // DBG
|
|
return LocalAlloc( 0, Size );
|
|
#endif // DBG
|
|
}
|
|
|
|
PVOID
|
|
AzpAllocateHeapSafe(
|
|
IN SIZE_T Size
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Memory allocator for SafeAlloca. Calls
|
|
AzpAllocateHeap in return
|
|
|
|
Arguments:
|
|
|
|
Size - Size of block to be allocated
|
|
|
|
Return Values:
|
|
|
|
Returns a pointer to the allocated memory.
|
|
NULL - Not enough memory
|
|
|
|
--*/
|
|
{
|
|
|
|
return AzpAllocateHeap( Size, "UTILSAFE" );
|
|
}
|
|
|
|
VOID
|
|
AzpFreeHeap(
|
|
IN PVOID Buffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Memory de-allocator.
|
|
|
|
Arguments
|
|
|
|
Buffer - address of buffer to free
|
|
|
|
Return Value
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
|
|
if ( Buffer == NULL ) {
|
|
return;
|
|
}
|
|
|
|
#if DBG
|
|
ULONG HeaderSize;
|
|
|
|
ULONG DescrSize = sizeof(DWORD) * 2;
|
|
|
|
PLIST_ENTRY RealBlock;
|
|
|
|
HeaderSize = ROUND_UP_COUNT( sizeof(LIST_ENTRY) + DescrSize,
|
|
ALIGN_WORST );
|
|
|
|
RealBlock = (PLIST_ENTRY)(((LPBYTE)Buffer)-HeaderSize);
|
|
|
|
SafeEnterCriticalSection( &AzGlAllocatorCritSect );
|
|
RemoveEntryList( RealBlock );
|
|
SafeLeaveCriticalSection( &AzGlAllocatorCritSect );
|
|
|
|
LocalFree( RealBlock );
|
|
#else // DBG
|
|
LocalFree( Buffer );
|
|
#endif // DBG
|
|
|
|
}
|
|
|
|
PVOID
|
|
AzpAvlAllocate(
|
|
IN PRTL_GENERIC_TABLE Table,
|
|
IN CLONG ByteSize
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
This routine will allocate space to hold an entry in a generic AVL table.
|
|
|
|
Arguments:
|
|
|
|
IN PRTL_GENERIC_TABLE Table - Supplies the table to allocate entries for.
|
|
IN CLONG ByteSize - Supplies the number of bytes to allocate for the entry.
|
|
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
return AzpAllocateHeap( ByteSize, "UTILAVL" );
|
|
UNREFERENCED_PARAMETER(Table);
|
|
}
|
|
|
|
VOID
|
|
AzpAvlFree(
|
|
IN PRTL_GENERIC_TABLE Table,
|
|
IN PVOID Buffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will free an entry in a AVL generic table
|
|
|
|
Arguments:
|
|
|
|
IN PRTL_GENERIC_TABLE Table - Supplies the table to allocate entries for.
|
|
IN PVOID Buffer - Supplies the buffer to free.
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
AzpFreeHeap( Buffer );
|
|
UNREFERENCED_PARAMETER(Table);
|
|
}
|
|
|
|
|
|
VOID
|
|
AzpInitString(
|
|
OUT PAZP_STRING AzpString,
|
|
IN LPCWSTR String OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Initialize our private string structure to point to a passed in string.
|
|
|
|
Arguments
|
|
|
|
AzpString - Initialized string
|
|
|
|
String - zero terminated string to be reference
|
|
If NULL, AzpString will be initialized to empty.
|
|
|
|
Return Value
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Initialization
|
|
//
|
|
|
|
if ( String == NULL ) {
|
|
AzpString->String = NULL;
|
|
AzpString->StringSize = 0;
|
|
} else {
|
|
AzpString->String = (LPWSTR)String;
|
|
AzpString->StringSize = (ULONG) ((wcslen(String)+1)*sizeof(WCHAR));
|
|
}
|
|
AzpString->IsSid = FALSE;
|
|
|
|
}
|
|
|
|
DWORD
|
|
AzpCaptureString(
|
|
OUT PAZP_STRING AzpString,
|
|
IN LPCWSTR String,
|
|
IN ULONG MaximumLength,
|
|
IN BOOLEAN NullOk
|
|
)
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Capture the passed in string.
|
|
|
|
Arguments
|
|
|
|
AzpString - Captured copy of the passed in string.
|
|
On success, string must be freed using AzpFreeString
|
|
|
|
String - zero terminated string to capture
|
|
|
|
MaximumLength - Maximum length of the string (in characters).
|
|
|
|
NullOk - if TRUE, a NULL string or zero length string is OK.
|
|
|
|
pDescr - An optional description string
|
|
|
|
Return Value
|
|
|
|
NO_ERROR - The operation was successful
|
|
ERROR_NOT_ENOUGH_MEMORY - not enough memory
|
|
Other exception status codes
|
|
|
|
--*/
|
|
{
|
|
ULONG WinStatus;
|
|
ULONG StringSize;
|
|
|
|
//
|
|
// Initialization
|
|
//
|
|
|
|
AzpInitString( AzpString, NULL );
|
|
|
|
if ( String == NULL ) {
|
|
if ( !NullOk ) {
|
|
AzPrint(( AZD_INVPARM, "AzpCaptureString: NULL not ok\n" ));
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
return NO_ERROR;
|
|
}
|
|
|
|
__try {
|
|
|
|
//
|
|
// Validate a passed in LPWSTR
|
|
//
|
|
|
|
ULONG StringLength;
|
|
|
|
StringLength = (ULONG) wcslen( String );
|
|
|
|
if ( StringLength == 0 ) {
|
|
if ( !NullOk ) {
|
|
AzPrint(( AZD_INVPARM, "AzpCaptureString: zero length not ok\n" ));
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
return NO_ERROR;
|
|
}
|
|
|
|
if ( StringLength > MaximumLength ) {
|
|
AzPrint(( AZD_INVPARM, "AzpCaptureString: string too long %ld %ld %ws\n", StringLength, MaximumLength, String ));
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
StringSize = (StringLength+1)*sizeof(WCHAR);
|
|
|
|
|
|
//
|
|
// Allocate and copy the string
|
|
//
|
|
|
|
AzpString->String = (LPWSTR) AzpAllocateHeap( StringSize, "UTILSTR" );
|
|
|
|
if ( AzpString->String == NULL ) {
|
|
WinStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|
} else {
|
|
|
|
RtlCopyMemory( AzpString->String,
|
|
String,
|
|
StringSize );
|
|
|
|
AzpString->StringSize = StringSize;
|
|
AzpString->IsSid = FALSE;
|
|
|
|
WinStatus = NO_ERROR;
|
|
}
|
|
|
|
} __except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
|
|
WinStatus = RtlNtStatusToDosError( GetExceptionCode());
|
|
|
|
AzpFreeString( AzpString );
|
|
}
|
|
|
|
return WinStatus;
|
|
}
|
|
|
|
VOID
|
|
AzpInitSid(
|
|
OUT PAZP_STRING AzpString,
|
|
IN PSID Sid
|
|
)
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Initialize an AZ_STRING structure to point to a sid
|
|
|
|
Arguments
|
|
|
|
AzpString - String structure to initialize
|
|
|
|
Sid - Sid to capture
|
|
|
|
Return Value
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
// Initialization
|
|
//
|
|
|
|
AzpString->String = (LPWSTR)Sid;
|
|
AzpString->StringSize = RtlLengthSid( Sid );
|
|
AzpString->IsSid = TRUE;
|
|
|
|
}
|
|
|
|
DWORD
|
|
AzpCaptureSid(
|
|
OUT PAZP_STRING AzpString,
|
|
IN PSID Sid
|
|
)
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Capture the passed in SID
|
|
|
|
Arguments
|
|
|
|
AzpString - Captured copy of the passed in sid.
|
|
On success, string must be freed using AzpFreeString
|
|
|
|
Sid - Sid to capture
|
|
|
|
Return Value
|
|
|
|
NO_ERROR - The operation was successful
|
|
ERROR_NOT_ENOUGH_MEMORY - not enough memory
|
|
Other exception status codes
|
|
|
|
--*/
|
|
{
|
|
ULONG WinStatus;
|
|
ULONG StringSize;
|
|
|
|
//
|
|
// Initialization
|
|
//
|
|
|
|
AzpInitString( AzpString, NULL );
|
|
|
|
|
|
__try {
|
|
|
|
//
|
|
// Validate a passed in SID
|
|
//
|
|
|
|
if ( !RtlValidSid( Sid ) ) {
|
|
AzPrint(( AZD_INVPARM, "AzpCaptureString: SID not valid\n" ));
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
StringSize = RtlLengthSid( Sid );
|
|
|
|
//
|
|
// Allocate and copy the SID
|
|
//
|
|
|
|
AzpString->String = (LPWSTR) AzpAllocateHeap( StringSize, "UTILSID" );
|
|
|
|
if ( AzpString->String == NULL ) {
|
|
WinStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|
} else {
|
|
|
|
RtlCopyMemory( AzpString->String,
|
|
Sid,
|
|
StringSize );
|
|
|
|
AzpString->StringSize = StringSize;
|
|
AzpString->IsSid = TRUE;
|
|
|
|
WinStatus = NO_ERROR;
|
|
}
|
|
|
|
} __except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
|
|
WinStatus = RtlNtStatusToDosError( GetExceptionCode());
|
|
|
|
AzpFreeString( AzpString );
|
|
}
|
|
|
|
return WinStatus;
|
|
}
|
|
|
|
DWORD
|
|
AzpCaptureLong(
|
|
IN PVOID PropertyValue,
|
|
OUT PLONG UlongValue
|
|
)
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Support routine for the SetProperty API.
|
|
Capture a parameter for the user application.
|
|
|
|
Arguments
|
|
|
|
PropertyValue - Specifies a pointer to the property.
|
|
|
|
UlongValue - Value to return to make a copy of.
|
|
|
|
Return Value
|
|
NO_ERROR - The operation was successful
|
|
Other exception status codes
|
|
|
|
|
|
--*/
|
|
{
|
|
DWORD WinStatus;
|
|
|
|
__try {
|
|
*UlongValue = *(PULONG)PropertyValue;
|
|
WinStatus = NO_ERROR;
|
|
} __except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
WinStatus = RtlNtStatusToDosError( GetExceptionCode());
|
|
}
|
|
|
|
return WinStatus;
|
|
}
|
|
|
|
DWORD
|
|
AzpDuplicateString(
|
|
OUT PAZP_STRING AzpOutString,
|
|
IN PAZP_STRING AzpInString
|
|
)
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Make a duplicate of the passed in string
|
|
|
|
Arguments
|
|
|
|
AzpOutString - Returns a copy of the passed in string.
|
|
On success, string must be freed using AzpFreeString.
|
|
|
|
AzpInString - Specifies a string to make a copy of.
|
|
|
|
Return Value
|
|
|
|
NO_ERROR - The operation was successful
|
|
ERROR_NOT_ENOUGH_MEMORY - not enough memory
|
|
|
|
--*/
|
|
{
|
|
ULONG WinStatus;
|
|
|
|
//
|
|
// Initialization
|
|
//
|
|
|
|
AzpInitString( AzpOutString, NULL );
|
|
|
|
//
|
|
// Handle an empty string
|
|
//
|
|
|
|
if ( AzpInString->StringSize == 0 || AzpInString->String == NULL ) {
|
|
|
|
WinStatus = NO_ERROR;
|
|
|
|
//
|
|
// Allocate and copy the string
|
|
//
|
|
|
|
} else {
|
|
AzpOutString->String = (LPWSTR) AzpAllocateHeap( AzpInString->StringSize, "UTILDUP" );
|
|
|
|
if ( AzpOutString->String == NULL ) {
|
|
WinStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|
} else {
|
|
|
|
RtlCopyMemory( AzpOutString->String,
|
|
AzpInString->String,
|
|
AzpInString->StringSize );
|
|
|
|
AzpOutString->StringSize = AzpInString->StringSize;
|
|
AzpOutString->IsSid = AzpInString->IsSid;
|
|
|
|
WinStatus = NO_ERROR;
|
|
}
|
|
}
|
|
|
|
return WinStatus;
|
|
}
|
|
|
|
BOOL
|
|
AzpEqualStrings(
|
|
IN PAZP_STRING AzpString1,
|
|
IN PAZP_STRING AzpString2
|
|
)
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Does a case insensitive comparison of two strings
|
|
|
|
Arguments
|
|
|
|
AzpString1 - First string to compare
|
|
|
|
AzpString2 - Second string to compare
|
|
|
|
Return Value
|
|
|
|
TRUE: the strings are equal
|
|
FALSE: the strings are not equal
|
|
|
|
--*/
|
|
{
|
|
|
|
//
|
|
// Simply compare the strings
|
|
//
|
|
|
|
return (AzpCompareStrings( AzpString1, AzpString2 ) == CSTR_EQUAL);
|
|
|
|
}
|
|
|
|
LONG
|
|
AzpCompareSidWorker(
|
|
IN PSID Sid1,
|
|
IN ULONG Sid1Size,
|
|
IN PSID Sid2,
|
|
IN ULONG Sid2Size
|
|
)
|
|
/*++
|
|
|
|
Routine description:
|
|
|
|
SID comparison routine for non-equality
|
|
|
|
Arguments:
|
|
|
|
Sid1 - First Sid to compare
|
|
|
|
Sid1Size - Size (in bytes) of Sid1
|
|
|
|
Sid2 - Second Sid to compare
|
|
|
|
Sid2Size - Size (in bytes) of Sid2
|
|
|
|
Returns:
|
|
|
|
CSTR_LESS_THAN: String 1 is less than string 2
|
|
CSTR_EQUAL: String 1 is equal to string 2
|
|
CSTR_GREATER_THAN: String 1 is greater than string 2
|
|
|
|
this is the same code as RtlEqualSid, except it returns
|
|
CSTR_*
|
|
|
|
--*/
|
|
{
|
|
LONG Result;
|
|
ULONG i;
|
|
|
|
ASSERT( Sid1 && RtlValidSid( (PSID)(Sid1) ));
|
|
ASSERT( Sid2 && RtlValidSid( (PSID)(Sid2) ));
|
|
|
|
//
|
|
// First compare lengths
|
|
//
|
|
|
|
if ( Sid1Size < Sid2Size ) {
|
|
return CSTR_LESS_THAN;
|
|
}
|
|
|
|
if ( Sid1Size > Sid2Size ) {
|
|
return CSTR_GREATER_THAN;
|
|
}
|
|
|
|
|
|
//
|
|
// Compare the individual bytes
|
|
//
|
|
|
|
ASSERT( (Sid1Size % 4) == 0 );
|
|
|
|
Result = CSTR_EQUAL;
|
|
|
|
for ( i = 0; i < (Sid1Size/4); i++ ) {
|
|
|
|
const ULONG& b1 = ((PULONG)Sid1)[i];
|
|
const ULONG& b2 = ((PULONG)Sid2)[i];
|
|
|
|
if ( b1 == b2 ) {
|
|
|
|
continue;
|
|
|
|
} else if ( b1 < b2 ) {
|
|
|
|
Result = CSTR_LESS_THAN;
|
|
|
|
} else {
|
|
|
|
Result = CSTR_GREATER_THAN;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
LONG
|
|
AzpCompareSid(
|
|
IN PSID Sid1,
|
|
IN PSID Sid2
|
|
)
|
|
/*++
|
|
|
|
Routine description:
|
|
|
|
SID comparison routine for non-equality
|
|
|
|
Arguments:
|
|
|
|
Sid1 - First Sid to compare
|
|
|
|
Sid2 - Second Sid to compare
|
|
|
|
Returns:
|
|
|
|
CSTR_LESS_THAN: String 1 is less than string 2
|
|
CSTR_EQUAL: String 1 is equal to string 2
|
|
CSTR_GREATER_THAN: String 1 is greater than string 2
|
|
|
|
this is the same code as RtlEqualSid, except it returns
|
|
CSTR_*
|
|
|
|
--*/
|
|
{
|
|
|
|
//
|
|
// Call the worker routine
|
|
//
|
|
|
|
return AzpCompareSidWorker(
|
|
Sid1,
|
|
RtlLengthSid(Sid1),
|
|
Sid2,
|
|
RtlLengthSid(Sid2) );
|
|
|
|
}
|
|
|
|
LONG
|
|
AzpCompareSidString(
|
|
IN PAZP_STRING AzpString1,
|
|
IN PAZP_STRING AzpString2
|
|
)
|
|
/*++
|
|
|
|
Routine description:
|
|
|
|
SID comparison routine for non-equality
|
|
|
|
Arguments:
|
|
|
|
AzpString1 - First string to compare
|
|
|
|
AzpString2 - Second string to compare
|
|
|
|
Returns:
|
|
|
|
CSTR_LESS_THAN: String 1 is less than string 2
|
|
CSTR_EQUAL: String 1 is equal to string 2
|
|
CSTR_GREATER_THAN: String 1 is greater than string 2
|
|
|
|
this is the same code as RtlEqualSid, except it returns
|
|
CSTR_*
|
|
|
|
--*/
|
|
{
|
|
|
|
//
|
|
// Call the worker routine
|
|
//
|
|
|
|
return AzpCompareSidWorker(
|
|
AzpString1->String,
|
|
AzpString1->StringSize,
|
|
AzpString2->String,
|
|
AzpString2->StringSize );
|
|
}
|
|
|
|
|
|
LONG
|
|
AzpCompareStrings(
|
|
IN PAZP_STRING AzpString1,
|
|
IN PAZP_STRING AzpString2
|
|
)
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Does a case insensitive comparison of two strings
|
|
|
|
Arguments
|
|
|
|
AzpString1 - First string to compare
|
|
|
|
AzpString2 - Second string to compare
|
|
|
|
Return Value
|
|
|
|
0: An error ocurred. Call GetLastError();
|
|
CSTR_LESS_THAN: String 1 is less than string 2
|
|
CSTR_EQUAL: String 1 is equal to string 2
|
|
CSTR_GREATER_THAN: String 1 is greater than string 2
|
|
|
|
--*/
|
|
{
|
|
LONG Result;
|
|
|
|
//
|
|
// Handle NULL
|
|
//
|
|
ASSERT( (AzpString1->IsSid && AzpString2->IsSid) || (!AzpString1->IsSid && !AzpString2->IsSid) );
|
|
if ( AzpString1->String == NULL ) {
|
|
if ( AzpString2->String == NULL ) {
|
|
return CSTR_EQUAL;
|
|
}else {
|
|
return CSTR_LESS_THAN;
|
|
}
|
|
} else {
|
|
if ( AzpString2->String == NULL ) {
|
|
return CSTR_GREATER_THAN;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Compare the sids
|
|
//
|
|
|
|
if ( AzpString1->IsSid ) {
|
|
|
|
Result = AzpCompareSidString( AzpString1, AzpString2 );
|
|
|
|
//
|
|
// Compare the Unicode strings
|
|
// Don't compare the trailing zero character.
|
|
// (Some callers pass in strings where the trailing character isn't a zero.)
|
|
//
|
|
|
|
} else {
|
|
Result = CompareStringW( LOCALE_SYSTEM_DEFAULT,
|
|
NORM_IGNORECASE,
|
|
AzpString1->String,
|
|
(AzpString1->StringSize/sizeof(WCHAR))-1,
|
|
AzpString2->String,
|
|
(AzpString2->StringSize/sizeof(WCHAR))-1 );
|
|
}
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
VOID
|
|
AzpSwapStrings(
|
|
IN OUT PAZP_STRING AzpString1,
|
|
IN OUT PAZP_STRING AzpString2
|
|
)
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Swap two strings
|
|
|
|
Arguments
|
|
|
|
AzpString1 - First string to swap
|
|
|
|
AzpString2 - Second string to swap
|
|
|
|
Return Value
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
AZP_STRING TempString;
|
|
|
|
TempString = *AzpString1;
|
|
*AzpString1 = *AzpString2;
|
|
*AzpString2 = TempString;
|
|
|
|
}
|
|
|
|
VOID
|
|
AzpFreeString(
|
|
IN PAZP_STRING AzpString
|
|
)
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Free the specified string
|
|
|
|
Arguments
|
|
|
|
AzpString - String to be freed.
|
|
|
|
pDescr - An optional description string
|
|
|
|
Return Value
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
if ( AzpString->String != NULL ) {
|
|
AzpFreeHeap( AzpString->String );
|
|
}
|
|
|
|
AzpInitString( AzpString, NULL );
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
AzpBsearchPtr (
|
|
IN PAZP_PTR_ARRAY AzpPtrArray,
|
|
IN PVOID Key,
|
|
IN LONG (*Compare)(const void *, const void *),
|
|
OUT PULONG InsertionPoint OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine does a binary search on the array of pointers
|
|
|
|
Code stolen from the libc bsearch() routine
|
|
|
|
Arguments:
|
|
|
|
AzpPtrArray - Array that the pointer will be searched for
|
|
|
|
Key - Pointer to be searched for
|
|
|
|
Compare - Pointer to a routine to do the comparison. Routine returns
|
|
CSTR_LESS_THAN: String 1 is less than string 2
|
|
CSTR_EQUAL: String 1 is equal to string 2
|
|
CSTR_GREATER_THAN: String 1 is greater than string 2
|
|
|
|
InsertionPoint - On FALSE, returns the point where one would insert the named object.
|
|
On TRUE, returns an index to the object.
|
|
|
|
Return Value:
|
|
|
|
TRUE - Object was found
|
|
FALSE - Object was not found
|
|
|
|
--*/
|
|
{
|
|
LONG lo = 0;
|
|
LONG num = AzpPtrArray->UsedCount;
|
|
LONG hi = num - 1;
|
|
LONG mid;
|
|
LONG half;
|
|
LONG result;
|
|
LONG TempInsertionPoint = 0;
|
|
|
|
while (lo <= hi) {
|
|
ASSERT( num == hi-lo+1 );
|
|
|
|
// Handle more than one element left
|
|
half = num / 2;
|
|
|
|
if ( half ) {
|
|
|
|
// Compare key to element in the middle of the array left
|
|
mid = lo + (num & 1 ? half : (half - 1));
|
|
|
|
result = (*Compare)( Key, AzpPtrArray->Array[mid] );
|
|
|
|
// We lucked out and hit it right on the nose
|
|
if ( result == CSTR_EQUAL ) {
|
|
*InsertionPoint = mid;
|
|
return TRUE;
|
|
|
|
// Key is in the first half
|
|
} else if ( result == CSTR_LESS_THAN ) {
|
|
hi = mid - 1;
|
|
num = num & 1 ? half : half-1;
|
|
TempInsertionPoint = mid;
|
|
|
|
// Key is in the second half
|
|
} else {
|
|
lo = mid+1;
|
|
num = half;
|
|
TempInsertionPoint = mid+1;
|
|
}
|
|
|
|
// Handle exactly one element left
|
|
} else if (num) {
|
|
ASSERT( hi == lo );
|
|
ASSERT( num == 1 );
|
|
|
|
result = (*Compare)( Key, AzpPtrArray->Array[lo] );
|
|
|
|
if ( result == CSTR_EQUAL ) {
|
|
*InsertionPoint = lo;
|
|
return TRUE;
|
|
|
|
} else if ( result == CSTR_LESS_THAN ) {
|
|
TempInsertionPoint = lo;
|
|
break;
|
|
|
|
} else {
|
|
TempInsertionPoint = lo+1;
|
|
break;
|
|
}
|
|
|
|
// Handle exactly zero elements left
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
*InsertionPoint = TempInsertionPoint;
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
DWORD
|
|
AzpAddPtr(
|
|
IN PAZP_PTR_ARRAY AzpPtrArray,
|
|
IN PVOID Pointer,
|
|
IN ULONG Index
|
|
)
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Inserts a pointer into the array of pointers.
|
|
|
|
The array will be automatically expanded to be large enough to contain the new pointer.
|
|
All existing pointers from slot # 'Index' through the end of the existing array will
|
|
be shifted to later slots.
|
|
|
|
Arguments
|
|
|
|
AzpPtrArray - Array that the pointer will be inserted into.
|
|
|
|
Pointer - Pointer to be inserted.
|
|
|
|
Index - Index into the array where the 'Pointer' will be inserted
|
|
If Index is larger than the current size of the array or AZP_ADD_ENDOFLIST,
|
|
'Pointer' will be inserted after the existing elements of the array.
|
|
|
|
Return Value
|
|
|
|
NO_ERROR - The operation was successful
|
|
ERROR_NOT_ENOUGH_MEMORY - not enough memory
|
|
|
|
--*/
|
|
{
|
|
|
|
//
|
|
// Ensure Index isn't too large
|
|
//
|
|
|
|
if ( Index > AzpPtrArray->UsedCount ) {
|
|
Index = AzpPtrArray->UsedCount;
|
|
}
|
|
|
|
//
|
|
// If the array isn't large enough, make it bigger
|
|
//
|
|
|
|
if ( AzpPtrArray->UsedCount >= AzpPtrArray->AllocatedCount ) {
|
|
PVOID *TempArray;
|
|
|
|
//
|
|
// Allocate a new array
|
|
//
|
|
|
|
TempArray = (PVOID *) AzpAllocateHeap(
|
|
(AzpPtrArray->AllocatedCount + AZP_PTR_ARRAY_INCREMENT) * sizeof(PVOID),
|
|
"UTILADD" );
|
|
|
|
if ( TempArray == NULL ) {
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
//
|
|
// Copy the data into the new array and free the old array
|
|
//
|
|
|
|
if ( AzpPtrArray->Array != NULL ) {
|
|
|
|
RtlCopyMemory( TempArray,
|
|
AzpPtrArray->Array,
|
|
AzpPtrArray->AllocatedCount * sizeof(PVOID) );
|
|
|
|
AzpFreeHeap( AzpPtrArray->Array );
|
|
AzPrint(( AZD_OBJLIST, "0x%lx: 0x%lx: Free old array\n", AzpPtrArray, AzpPtrArray->Array ));
|
|
}
|
|
|
|
//
|
|
// Grab the pointer to the new array and clear the new part of the array
|
|
//
|
|
|
|
AzpPtrArray->Array = TempArray;
|
|
AzPrint(( AZD_OBJLIST, "0x%lx: 0x%lx: Allocate array\n", AzpPtrArray, AzpPtrArray->Array ));
|
|
|
|
RtlZeroMemory( &TempArray[AzpPtrArray->UsedCount],
|
|
AZP_PTR_ARRAY_INCREMENT * sizeof(PVOID) );
|
|
|
|
AzpPtrArray->AllocatedCount += AZP_PTR_ARRAY_INCREMENT;
|
|
|
|
}
|
|
|
|
//
|
|
// Shift any old data
|
|
//
|
|
|
|
if ( Index != AzpPtrArray->UsedCount ) {
|
|
|
|
RtlMoveMemory( &(AzpPtrArray->Array[Index+1]),
|
|
&(AzpPtrArray->Array[Index]),
|
|
(AzpPtrArray->UsedCount-Index) * sizeof(PVOID) );
|
|
}
|
|
|
|
//
|
|
// Insert the new element
|
|
//
|
|
|
|
AzpPtrArray->Array[Index] = Pointer;
|
|
AzpPtrArray->UsedCount ++;
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
VOID
|
|
AzpRemovePtrByIndex(
|
|
IN PAZP_PTR_ARRAY AzpPtrArray,
|
|
IN ULONG Index
|
|
)
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Remove a pointer from the array of pointers.
|
|
|
|
All existing pointers from slot # 'Index' through the end of the existing array will
|
|
be shifted to earlier slots.
|
|
|
|
Arguments
|
|
|
|
AzpPtrArray - Array that the pointer will be removed into.
|
|
|
|
Index - Index into the array where the 'Pointer' will be removed from.
|
|
|
|
|
|
Return Value
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
|
|
//
|
|
// Ensure Index isn't too large
|
|
//
|
|
|
|
ASSERT( Index < AzpPtrArray->UsedCount );
|
|
|
|
|
|
//
|
|
// Shift any old data
|
|
//
|
|
|
|
if ( Index+1 != AzpPtrArray->UsedCount ) {
|
|
|
|
RtlMoveMemory( &(AzpPtrArray->Array[Index]),
|
|
&(AzpPtrArray->Array[Index+1]),
|
|
(AzpPtrArray->UsedCount-Index-1) * sizeof(PVOID) );
|
|
}
|
|
|
|
//
|
|
// Clear the last element
|
|
//
|
|
|
|
AzpPtrArray->UsedCount--;
|
|
AzpPtrArray->Array[AzpPtrArray->UsedCount] = NULL;
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
AzpRemovePtrByPtr(
|
|
IN PAZP_PTR_ARRAY AzpPtrArray,
|
|
IN PVOID Pointer
|
|
)
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Removes a pointer from the array of pointers.
|
|
|
|
All existing pointers following the specified pointer will
|
|
be shifted to earlier slots.
|
|
|
|
Arguments
|
|
|
|
AzpPtrArray - Array that the pointer will be removed into.
|
|
|
|
Pointer - Pointer to be removed
|
|
|
|
|
|
Return Value
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
ULONG i;
|
|
BOOLEAN FoundIt = FALSE;
|
|
|
|
for ( i=0; i<AzpPtrArray->UsedCount; i++ ) {
|
|
|
|
if ( Pointer == AzpPtrArray->Array[i] ) {
|
|
AzpRemovePtrByIndex( AzpPtrArray, i );
|
|
FoundIt = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
ASSERT( FoundIt );
|
|
|
|
}
|
|
|
|
|
|
|
|
PVOID
|
|
AzpGetStringProperty(
|
|
IN PAZP_STRING AzpString
|
|
)
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Support routine for the GetProperty API. Convert an AzpString to the form
|
|
supported by GetProperty.
|
|
|
|
Empty string are returned as Zero length string instead of NULL
|
|
|
|
Arguments
|
|
|
|
AzpString - Specifies a string to make a copy of.
|
|
|
|
Return Value
|
|
|
|
Pointer to allocated string.
|
|
String should be freed using AzFreeMemory.
|
|
NULL - Not enough memory was available to allocate the string
|
|
|
|
--*/
|
|
{
|
|
LPWSTR String;
|
|
ULONG AllocatedSize;
|
|
|
|
//
|
|
// Allocate and copy the string
|
|
//
|
|
|
|
AllocatedSize = AzpString->StringSize ? AzpString->StringSize : (ULONG)sizeof(WCHAR);
|
|
String = (LPWSTR) AzpAllocateHeap( AllocatedSize, "UTILGSTR" );
|
|
|
|
if ( String != NULL ) {
|
|
|
|
//
|
|
// Convert NULL strings to zero length strings
|
|
//
|
|
|
|
if ( AzpString->StringSize == 0 ) {
|
|
*String = L'\0';
|
|
|
|
} else {
|
|
|
|
RtlCopyMemory( String,
|
|
AzpString->String,
|
|
AzpString->StringSize );
|
|
}
|
|
|
|
}
|
|
|
|
return String;
|
|
}
|
|
|
|
PVOID
|
|
AzpGetUlongProperty(
|
|
IN ULONG UlongValue
|
|
)
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Support routine for the GetProperty API. Convert a ULONG to the form
|
|
supported by GetProperty.
|
|
|
|
Arguments
|
|
|
|
UlongValue - Value to return to make a copy of.
|
|
|
|
Return Value
|
|
|
|
Pointer to allocated string.
|
|
String should be freed using AzFreeMemory.
|
|
NULL - Not enough memory was available to allocate the string
|
|
|
|
--*/
|
|
{
|
|
PULONG RetValue;
|
|
|
|
//
|
|
// Allocate and copy the string
|
|
//
|
|
|
|
RetValue = (PULONG) AzpAllocateHeap( sizeof(ULONG), "UTILGLNG" );
|
|
|
|
if ( RetValue != NULL ) {
|
|
|
|
*RetValue = UlongValue;
|
|
|
|
}
|
|
|
|
return RetValue;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
AzpTimeHasElapsed(
|
|
IN PLARGE_INTEGER StartTime,
|
|
IN DWORD Timeout
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determine if "Timeout" milliseconds has has elapsed since StartTime.
|
|
|
|
Arguments:
|
|
|
|
StartTime - Specifies an absolute time when the event started (100ns units).
|
|
|
|
Timeout - Specifies a relative time in milliseconds. 0xFFFFFFFF indicates
|
|
that the time will never expire.
|
|
|
|
Return Value:
|
|
|
|
TRUE -- iff Timeout milliseconds have elapsed since StartTime.
|
|
|
|
--*/
|
|
{
|
|
LARGE_INTEGER TimeNow;
|
|
LARGE_INTEGER ElapsedTime;
|
|
LARGE_INTEGER Period;
|
|
|
|
//
|
|
// If the period to too large to handle (i.e., 0xffffffff is forever),
|
|
// just indicate that the timer has not expired.
|
|
//
|
|
// (0xffffffff is a little over 48 days).
|
|
//
|
|
|
|
if ( Timeout == 0xffffffff ) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Compute the elapsed time since we last authenticated
|
|
//
|
|
|
|
GetSystemTimeAsFileTime( (PFILETIME)&TimeNow );
|
|
ElapsedTime.QuadPart = TimeNow.QuadPart - StartTime->QuadPart;
|
|
|
|
//
|
|
// Compute Period from milliseconds into 100ns units.
|
|
//
|
|
|
|
Period.QuadPart = UInt32x32To64( Timeout, 10000 );
|
|
|
|
|
|
//
|
|
// If the elapsed time is negative (totally bogus) or greater than the
|
|
// maximum allowed, indicate that enough time has passed.
|
|
//
|
|
|
|
if ( ElapsedTime.QuadPart < 0 || ElapsedTime.QuadPart > Period.QuadPart ) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
DWORD
|
|
AzpHresultToWinStatus(
|
|
HRESULT hr
|
|
)
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Convert an Hresult to a WIN 32 status code
|
|
|
|
Arguments
|
|
|
|
hr - Hresult to convert
|
|
|
|
Return Value
|
|
|
|
--*/
|
|
{
|
|
DWORD WinStatus = ERROR_INTERNAL_ERROR;
|
|
|
|
//
|
|
// Success is still success
|
|
//
|
|
|
|
if ( hr == NO_ERROR ) {
|
|
WinStatus = NO_ERROR;
|
|
|
|
//
|
|
// If the facility is WIN32,
|
|
// the translation is easy.
|
|
//
|
|
|
|
} else if ((HRESULT_FACILITY(hr) == FACILITY_WIN32) && (FAILED(hr))) {
|
|
|
|
WinStatus = HRESULT_CODE(hr);
|
|
|
|
if ( WinStatus == ERROR_SUCCESS ) {
|
|
WinStatus = ERROR_INTERNAL_ERROR;
|
|
}
|
|
|
|
//
|
|
// All others should be left intact
|
|
//
|
|
|
|
} else {
|
|
|
|
WinStatus = hr;
|
|
}
|
|
|
|
return WinStatus;
|
|
}
|
|
|
|
DWORD
|
|
AzpSafeArrayPointerFromVariant(
|
|
IN VARIANT* Variant,
|
|
IN BOOLEAN NullOk,
|
|
OUT SAFEARRAY **retSafeArray
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine takes a pointer to a variant and returns a pointer to a SafeArray.
|
|
Any levels of VT_BYREF are skipped.
|
|
|
|
This routine also requires that the array be unidimensional and be an array of variants.
|
|
|
|
VBScript has two syntaxes for calling dispinterfaces:
|
|
|
|
1. obj.Method (arg)
|
|
2. obj.Method arg
|
|
|
|
The first syntax will pass arg by value, which our dispinterfaces will
|
|
be able to handle. If Method takes a BSTR argument, the VARIANT that
|
|
arrives at Method will be of type VT_BSTR.
|
|
|
|
The second syntax will pass arg by reference. In this case Method will
|
|
receive a VARIANT of type (VT_VARIANT | VT_BYREF). The VARIANT that is
|
|
referenced will be of type VT_BSTR.
|
|
|
|
This function will canoicalizes the two cases.
|
|
|
|
Optionally, VT_EMPTY, VT_NULL and VT_ERROR variants are allowed.
|
|
|
|
Arguments:
|
|
|
|
Variant - Variant to check
|
|
|
|
NullOk - TRUE if VT_EMPTY, VT_NULL and VT_ERROR variants are to be allowed. If TRUE,
|
|
and Variant is such a null variant, the retSafeArray returns a NULL pointer.
|
|
|
|
retSafeArray - Returns a pointer to the SafeArray.
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR - The function was successful
|
|
ERROR_INVALID_PARAMETER - The parameter is invalid
|
|
|
|
--*/
|
|
{
|
|
SAFEARRAY *SafeArray;
|
|
VARTYPE Vartype;
|
|
HRESULT hr;
|
|
|
|
//
|
|
// Skip over any pointers to variant.
|
|
//
|
|
|
|
*retSafeArray = NULL;
|
|
while ((Variant != NULL) && (V_VT(Variant) == (VT_VARIANT | VT_BYREF))) {
|
|
Variant = V_VARIANTREF(Variant);
|
|
}
|
|
|
|
//
|
|
// If null parameters are OK,
|
|
// allow them
|
|
//
|
|
// EMPTY is uninitialized
|
|
// NULL is explicitly null
|
|
// ERROR is unspecified optional parameter
|
|
//
|
|
|
|
if ( Variant == NULL || V_VT(Variant) == VT_EMPTY || V_VT(Variant) == VT_NULL || V_VT(Variant) == VT_ERROR ) {
|
|
return NullOk ? NO_ERROR : ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
|
|
//
|
|
// Ensure this is an array.
|
|
//
|
|
|
|
if ( !V_ISARRAY(Variant) ) {
|
|
AzPrint(( AZD_INVPARM, "AzpSafeArrayPointerFromVariant: parameter is not an array 0x%lx.\n", V_VT(Variant) ));
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Get the pointer to the safe array
|
|
//
|
|
|
|
if ( V_ISBYREF( Variant) ) {
|
|
SafeArray = *(SAFEARRAY **)V_BYREF( Variant );
|
|
} else {
|
|
SafeArray = V_ARRAY( Variant );
|
|
}
|
|
|
|
//
|
|
// Handle NULL safe array
|
|
//
|
|
if ( SafeArray == NULL ) {
|
|
return NullOk ? NO_ERROR : ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
|
|
//
|
|
// Array must have one dimension
|
|
//
|
|
|
|
if ( SafeArrayGetDim( SafeArray ) != 1 ) {
|
|
AzPrint(( AZD_INVPARM, "AzpSafeArrayPointerFromVariant: Array %lx isn't single dimension array\n", SafeArrayGetDim( SafeArray ) ));
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// The type of the values array must be variant
|
|
//
|
|
|
|
hr = SafeArrayGetVartype( SafeArray, &Vartype );
|
|
|
|
if ( FAILED(hr) || Vartype != VT_VARIANT ) {
|
|
AzPrint(( AZD_INVPARM, "AzpSafeArrayPointerFromVariant: Array isn't array of VARIANT 0x%lx %lx\n", hr, Vartype ));
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
*retSafeArray = SafeArray;
|
|
return NO_ERROR;
|
|
|
|
|
|
}
|
|
|
|
DWORD
|
|
AzpConvertAbsoluteSDToSelfRelative(
|
|
IN PSECURITY_DESCRIPTOR pAbsoluteSD,
|
|
OUT PSECURITY_DESCRIPTOR *ppSelfRelativeSD
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns a self-relative SD for a passed
|
|
in absolute form SD. The returned SD needs to be freed using
|
|
LocalFree routine.
|
|
|
|
Arguments:
|
|
|
|
pAbsoluteSD - Passed in absolute form SD
|
|
|
|
ppSelfRelativeSD - Returned self-relative form SD
|
|
|
|
Return Values:
|
|
|
|
NO_ERROR - The self-relative form SD was created successfully
|
|
Other status codes
|
|
--*/
|
|
{
|
|
|
|
DWORD WinStatus = 0;
|
|
|
|
DWORD dSelfRelativeSDLen = 0;
|
|
|
|
//
|
|
// Figure out the size needed for the self relatiVe SD
|
|
//
|
|
|
|
|
|
if ( !MakeSelfRelativeSD(
|
|
pAbsoluteSD,
|
|
NULL,
|
|
&dSelfRelativeSDLen
|
|
) ) {
|
|
|
|
WinStatus = GetLastError();
|
|
|
|
if ( WinStatus == ERROR_INSUFFICIENT_BUFFER ) {
|
|
|
|
WinStatus = NO_ERROR;
|
|
|
|
//
|
|
// The required length is returned on insufficient buffer failure
|
|
//
|
|
|
|
*ppSelfRelativeSD = (PSECURITY_DESCRIPTOR) AzpAllocateHeap( dSelfRelativeSDLen, "UTILSD2" );
|
|
|
|
if ( *ppSelfRelativeSD == NULL ) {
|
|
|
|
WinStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ( !MakeSelfRelativeSD(
|
|
pAbsoluteSD,
|
|
*ppSelfRelativeSD,
|
|
&dSelfRelativeSDLen
|
|
) ) {
|
|
|
|
WinStatus = GetLastError();
|
|
}
|
|
}
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
if ( WinStatus != NO_ERROR ) {
|
|
|
|
if ( *ppSelfRelativeSD != NULL ) {
|
|
|
|
LocalFree( *ppSelfRelativeSD );
|
|
*ppSelfRelativeSD = NULL;
|
|
}
|
|
}
|
|
|
|
return WinStatus;
|
|
}
|
|
|
|
DWORD
|
|
AzpADSetDefaultLdapOptions (
|
|
IN OUT PLDAP pHandleLdap,
|
|
IN PCWSTR pDomainName OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets our default common ldap binding options.
|
|
|
|
Arguments:
|
|
|
|
pHandle - a valid (already initialized) LDAP handle
|
|
|
|
pDomainName - an optional domain name
|
|
|
|
Return Values:
|
|
|
|
NO_ERROR if all set correctly.
|
|
Other error status codes in case of errors. These error codes
|
|
have already been converted from ldap error codes to win status codes.
|
|
|
|
--*/
|
|
{
|
|
LONG LdapOption = 0;
|
|
ULONG LdapStatus = 0;
|
|
DWORD dwStatus = NO_ERROR;
|
|
|
|
//
|
|
// Don't chase referals
|
|
//
|
|
|
|
LdapOption = PtrToLong( LDAP_OPT_OFF );
|
|
|
|
LdapStatus = ldap_set_option( pHandleLdap,
|
|
LDAP_OPT_REFERRALS,
|
|
&LdapOption );
|
|
|
|
if ( LdapStatus != LDAP_SUCCESS ) {
|
|
|
|
dwStatus = LdapMapErrorToWin32( LdapStatus );
|
|
AzPrint(( AZD_AD,
|
|
"AzpADSetDefaultLdapOptions: ldap_set_option LDAP_OPT_REFERRALS"
|
|
" failed: %ld\n",
|
|
dwStatus
|
|
));
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Set the option telling LDAP that I passed it an explicit DC name and
|
|
// that it can avoid the DsGetDcName.
|
|
//
|
|
|
|
LdapOption = PtrToLong( LDAP_OPT_ON );
|
|
|
|
LdapStatus = ldap_set_option( pHandleLdap,
|
|
LDAP_OPT_AREC_EXCLUSIVE,
|
|
&LdapOption );
|
|
|
|
if ( LdapStatus != LDAP_SUCCESS ) {
|
|
|
|
dwStatus = LdapMapErrorToWin32( LdapStatus );
|
|
AzPrint(( AZD_AD,
|
|
"AzpADSetDefaultLdapOptions: ldap_set_option LDAP_OPT_AREC_EXCLUSIVE"
|
|
" failed: %ld\n",
|
|
dwStatus
|
|
));
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// We will encrypt our ldap communication, so turn on the encrypt option
|
|
//
|
|
|
|
LdapOption = PtrToLong( LDAP_OPT_ON );
|
|
LdapStatus = ldap_set_option( pHandleLdap,
|
|
LDAP_OPT_ENCRYPT,
|
|
&LdapOption
|
|
);
|
|
|
|
if ( LdapStatus != LDAP_SUCCESS ) {
|
|
|
|
dwStatus = LdapMapErrorToWin32( LdapStatus );
|
|
AzPrint(( AZD_AD,
|
|
"AzpADSetDefaultLdapOptions: ldap_set_option LDAP_OPT_ENCRYPT"
|
|
" failed: %ld\n",
|
|
dwStatus
|
|
));
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ( pDomainName != NULL ) {
|
|
|
|
//
|
|
// We need to set the option to enforce mutual authentication with the DC
|
|
//
|
|
|
|
LdapStatus = ldap_set_option( pHandleLdap,
|
|
LDAP_OPT_DNSDOMAIN_NAME,
|
|
&pDomainName
|
|
);
|
|
|
|
if ( LdapStatus != LDAP_SUCCESS ) {
|
|
|
|
dwStatus = LdapMapErrorToWin32( LdapStatus );
|
|
AzPrint(( AZD_AD,
|
|
"AzpADSetDefaultLdapOptions: ldap_set_option LDAP_OPT_DNSDOMAIN_NAME"
|
|
" failed: %ld\n",
|
|
dwStatus
|
|
));
|
|
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
return dwStatus;
|
|
}
|
|
|
|
HRESULT AzpGetSafearrayFromArrayObject (
|
|
IN VARIANT varSAorObj,
|
|
OUT SAFEARRAY** ppsaData)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine converts a JScript style Array object to safearray.
|
|
|
|
Arguments:
|
|
|
|
varSAorObj - The VARIANT that holds a IDispatchEx object.
|
|
|
|
ppsaData - Receives the safearray.
|
|
|
|
Return Values:
|
|
|
|
Success: S_OK
|
|
Failures: various error code
|
|
|
|
Note:
|
|
JScript doesn't use safearrays. Instead, it uses its own intrinsic object
|
|
Array for arrays. For clients that uses such object for arrays, we need
|
|
special handling because our routines expect safearray.
|
|
|
|
--*/
|
|
{
|
|
if (ppsaData == NULL)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
*ppsaData = NULL;
|
|
|
|
if (varSAorObj.vt != VT_DISPATCH)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
CComPtr<IDispatchEx> srpDispEx;
|
|
HRESULT hr = varSAorObj.pdispVal->QueryInterface(IID_IDispatchEx, (void**)&srpDispEx);
|
|
DISPID id = DISPID_STARTENUM;
|
|
|
|
//
|
|
// It's sad that we can't use vectors. EH causes compiler errors once we use <vector>
|
|
// So, we have to go two passes. The first is to find the count.
|
|
//
|
|
|
|
ULONG uCount = 0;
|
|
while (S_OK == hr)
|
|
{
|
|
hr = srpDispEx->GetNextDispID(fdexEnumAll, id, &id);
|
|
if (S_OK == hr)
|
|
{
|
|
++uCount;
|
|
}
|
|
}
|
|
|
|
//
|
|
// now we know the count, we can create the safearray
|
|
//
|
|
|
|
UINT i;
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
SAFEARRAYBOUND rgsaBound[1];
|
|
rgsaBound[0].lLbound = 0; //array index from 0
|
|
rgsaBound[0].cElements = uCount;
|
|
|
|
SAFEARRAY *psa = SafeArrayCreate( VT_VARIANT, 1, rgsaBound );
|
|
if (psa == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
else
|
|
{
|
|
long lArrayIndex[1];
|
|
lArrayIndex[0] = 0;
|
|
|
|
//
|
|
// put each element into the safearray
|
|
//
|
|
|
|
id = DISPID_STARTENUM;
|
|
DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
|
|
|
|
for (i = 0; i < uCount; ++i)
|
|
{
|
|
hr = srpDispEx->GetNextDispID(fdexEnumAll, id, &id);
|
|
|
|
//
|
|
// GetNextDispID will return S_FALSE when there is no more
|
|
//
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
//
|
|
// We have to get the property by invoking the IDispatchEx.
|
|
//
|
|
|
|
CComVariant var;
|
|
hr = srpDispEx->Invoke( id,
|
|
IID_NULL,
|
|
LOCALE_USER_DEFAULT,
|
|
DISPATCH_PROPERTYGET,
|
|
&dispparamsNoArgs,
|
|
&var,
|
|
NULL,
|
|
NULL
|
|
);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = SafeArrayPutElement( psa, lArrayIndex, &var );
|
|
++(lArrayIndex[0]);
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
//
|
|
// This is an error that shouldn't happen.
|
|
//
|
|
|
|
AZASSERT(FALSE);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// hr may be S_FALSE if no more items are found
|
|
//
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*ppsaData = psa;
|
|
}
|
|
else
|
|
{
|
|
SafeArrayDestroy(psa);
|
|
}
|
|
}
|
|
|
|
return SUCCEEDED(hr) ? S_OK : hr;
|
|
}
|
|
|
|
DWORD
|
|
AzpRetrieveApplicationSequenceNumber(
|
|
IN AZ_HANDLE AzAppHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns the sequence number of an AzApplication object
|
|
that can be used to determine if a certain COM handle is valid or not
|
|
after the AzApplication object has been closed
|
|
|
|
Arguments:
|
|
|
|
AzAppHandle - Handle to the application object whose sequence number needs to
|
|
be retrieved
|
|
|
|
Return Values:
|
|
|
|
The value of the sequence number
|
|
|
|
--*/
|
|
{
|
|
AzpLockResourceShared(&AzGlResource);
|
|
DWORD dwSN = ((PAZP_APPLICATION)AzAppHandle)->AppSequenceNumber;
|
|
AzpUnlockResource(&AzGlResource);
|
|
return dwSN;
|
|
}
|
|
|
|
//
|
|
// Debugging support
|
|
//
|
|
#ifdef AZROLESDBG
|
|
#include <stdio.h>
|
|
SAFE_CRITICAL_SECTION AzGlLogFileCritSect;
|
|
ULONG AzGlDbFlag;
|
|
// HANDLE AzGlLogFile;
|
|
|
|
#define MAX_PRINTF_LEN 1024 // Arbitrary.
|
|
|
|
VOID
|
|
AzpDumpGuid(
|
|
IN DWORD DebugFlag,
|
|
IN GUID *Guid OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dumps a GUID to the debugger output.
|
|
|
|
Arguments:
|
|
|
|
DebugFlag: Debug flag to pass on to AzPrintRoutine
|
|
|
|
Guid: Guid to print
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
{
|
|
RPC_STATUS RpcStatus;
|
|
unsigned char *StringGuid;
|
|
|
|
//
|
|
// If we aren't debugging this functionality, just return.
|
|
//
|
|
if ( DebugFlag != 0 && (AzGlDbFlag & DebugFlag) == 0 ) {
|
|
return;
|
|
}
|
|
|
|
|
|
if ( Guid == NULL ) {
|
|
AzPrint(( DebugFlag, "(null)" ));
|
|
} else {
|
|
RpcStatus = UuidToStringA( Guid, &StringGuid );
|
|
|
|
if ( RpcStatus != RPC_S_OK ) {
|
|
return;
|
|
}
|
|
|
|
AzPrint(( DebugFlag, "%s", StringGuid ));
|
|
|
|
RpcStringFreeA( &StringGuid );
|
|
}
|
|
|
|
}
|
|
|
|
VOID
|
|
AzpDumpGoRef(
|
|
IN LPSTR Text,
|
|
IN struct _GENERIC_OBJECT *GenericObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dumps the ref count for a generic object
|
|
|
|
Arguments:
|
|
|
|
Text - Description of why the ref count is changing
|
|
|
|
GenericObject - a pointer to the object being ref counted
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
{
|
|
LPWSTR StringSid = NULL;
|
|
LPWSTR StringToPrint;
|
|
|
|
//
|
|
// If we aren't debugging this functionality, just return.
|
|
//
|
|
if ( (AzGlDbFlag & AZD_REF) == 0 ) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Convert the sid to a string
|
|
//
|
|
if ( GenericObject->ObjectName == NULL ) {
|
|
StringToPrint = NULL;
|
|
|
|
} else if ( GenericObject->ObjectName->ObjectName.IsSid ) {
|
|
if ( ConvertSidToStringSid( (PSID)GenericObject->ObjectName->ObjectName.String, &StringSid)) {
|
|
StringToPrint = StringSid;
|
|
} else {
|
|
StringToPrint = L"<Invalid Sid>";
|
|
}
|
|
} else {
|
|
StringToPrint = GenericObject->ObjectName->ObjectName.String;
|
|
}
|
|
|
|
|
|
AzPrint(( AZD_REF, "0x%lx %ld (%ld) %ws: %s\n", GenericObject, GenericObject->ObjectType, GenericObject->ReferenceCount, StringToPrint, Text ));
|
|
|
|
if ( StringSid != NULL ) {
|
|
LocalFree( StringSid );
|
|
}
|
|
|
|
}
|
|
|
|
VOID
|
|
AzpPrintRoutineV(
|
|
IN DWORD DebugFlag,
|
|
IN LPSTR Format,
|
|
va_list arglist
|
|
)
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Debug routine for azroles
|
|
|
|
Arguments
|
|
|
|
DebugFlag - Flag to indicating the functionality being debugged
|
|
|
|
--- Other printf parameters
|
|
|
|
Return Value
|
|
|
|
--*/
|
|
|
|
{
|
|
static LPSTR AzGlLogFileOutputBuffer = NULL;
|
|
ULONG length;
|
|
int lengthTmp;
|
|
// DWORD BytesWritten;
|
|
static BeginningOfLine = TRUE;
|
|
static LineCount = 0;
|
|
static TruncateLogFileInProgress = FALSE;
|
|
static LogProblemWarned = FALSE;
|
|
|
|
//
|
|
// If we aren't debugging this functionality, just return.
|
|
//
|
|
if ( DebugFlag != 0 && (AzGlDbFlag & DebugFlag) == 0 ) {
|
|
return;
|
|
}
|
|
|
|
|
|
//
|
|
// Allocate a buffer to build the line in.
|
|
// If there isn't already one.
|
|
//
|
|
|
|
length = 0;
|
|
|
|
if ( AzGlLogFileOutputBuffer == NULL ) {
|
|
AzGlLogFileOutputBuffer = (LPSTR) LocalAlloc( 0, MAX_PRINTF_LEN + 1 );
|
|
|
|
if ( AzGlLogFileOutputBuffer == NULL ) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Handle the beginning of a new line.
|
|
//
|
|
//
|
|
|
|
if ( BeginningOfLine ) {
|
|
|
|
//
|
|
// Never print empty lines.
|
|
//
|
|
|
|
if ( Format[0] == '\n' && Format[1] == '\0' ) {
|
|
return;
|
|
}
|
|
|
|
#if 0
|
|
//
|
|
// If the log file is getting huge,
|
|
// truncate it.
|
|
//
|
|
|
|
if ( AzGlLogFile != INVALID_HANDLE_VALUE &&
|
|
!TruncateLogFileInProgress ) {
|
|
|
|
//
|
|
// Only check every 50 lines,
|
|
//
|
|
|
|
LineCount++;
|
|
if ( LineCount >= 50 ) {
|
|
DWORD FileSize;
|
|
LineCount = 0;
|
|
|
|
//
|
|
// Is the log file too big?
|
|
//
|
|
|
|
FileSize = GetFileSize( AzGlLogFile, NULL );
|
|
if ( FileSize == 0xFFFFFFFF ) {
|
|
(void) DbgPrint( "[NETLOGON] Cannot GetFileSize %ld\n",
|
|
GetLastError );
|
|
} else if ( FileSize > AzGlParameters.LogFileMaxSize ) {
|
|
TruncateLogFileInProgress = TRUE;
|
|
SafeLeaveCriticalSection( &AzGlLogFileCritSect );
|
|
NlOpenDebugFile( TRUE );
|
|
NlPrint(( NL_MISC,
|
|
"Logfile truncated because it was larger than %ld bytes\n",
|
|
AzGlParameters.LogFileMaxSize ));
|
|
SafeEnterCriticalSection( &AzGlLogFileCritSect );
|
|
TruncateLogFileInProgress = FALSE;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we're writing to the debug terminal,
|
|
// indicate this is a azroles message.
|
|
//
|
|
|
|
if ( AzGlLogFile == INVALID_HANDLE_VALUE ) {
|
|
length += (ULONG) sprintf( &AzGlLogFileOutputBuffer[length], "[AZROLES] " );
|
|
}
|
|
|
|
//
|
|
// Put the timestamp at the begining of the line.
|
|
//
|
|
{
|
|
SYSTEMTIME SystemTime;
|
|
GetLocalTime( &SystemTime );
|
|
length += (ULONG) sprintf( &AzGlLogFileOutputBuffer[length],
|
|
"%02u/%02u %02u:%02u:%02u ",
|
|
SystemTime.wMonth,
|
|
SystemTime.wDay,
|
|
SystemTime.wHour,
|
|
SystemTime.wMinute,
|
|
SystemTime.wSecond );
|
|
}
|
|
#endif // 0
|
|
|
|
//
|
|
// Indicate the type of message on the line
|
|
//
|
|
{
|
|
char *Text;
|
|
|
|
switch (DebugFlag) {
|
|
case AZD_HANDLE:
|
|
Text = "HANDLE"; break;
|
|
case AZD_OBJLIST:
|
|
Text = "OBJLIST"; break;
|
|
case AZD_INVPARM:
|
|
Text = "INVPARM"; break;
|
|
case AZD_PERSIST:
|
|
case AZD_PERSIST_MORE:
|
|
Text = "PERSIST"; break;
|
|
case AZD_REF:
|
|
Text = "OBJREF"; break;
|
|
case AZD_DISPATCH:
|
|
Text = "DISPATCH"; break;
|
|
case AZD_ACCESS:
|
|
case AZD_ACCESS_MORE:
|
|
Text = "ACCESS"; break;
|
|
case AZD_DOMREF:
|
|
Text = "DOMREF"; break;
|
|
case AZD_XML:
|
|
Text = "XML"; break;
|
|
case AZD_AD:
|
|
Text = "AD"; break;
|
|
case AZD_SCRIPT:
|
|
case AZD_SCRIPT_MORE:
|
|
Text = "SCRIPT"; break;
|
|
case AZD_CRITICAL:
|
|
Text = "CRITICAL"; break;
|
|
default:
|
|
Text = "UNKNOWN"; break;
|
|
|
|
case 0:
|
|
Text = NULL;
|
|
}
|
|
if ( Text != NULL ) {
|
|
length += (ULONG) sprintf( &AzGlLogFileOutputBuffer[length], "[%s] ", Text );
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Put a the information requested by the caller onto the line
|
|
//
|
|
|
|
lengthTmp = (ULONG) _vsnprintf( &AzGlLogFileOutputBuffer[length],
|
|
MAX_PRINTF_LEN - length - 1,
|
|
Format,
|
|
arglist );
|
|
|
|
if ( lengthTmp < 0 ) {
|
|
length = MAX_PRINTF_LEN - 1;
|
|
// always end the line which cannot fit into the buffer
|
|
AzGlLogFileOutputBuffer[length-1] = '\n';
|
|
} else {
|
|
length += lengthTmp;
|
|
}
|
|
|
|
BeginningOfLine = (length > 0 && AzGlLogFileOutputBuffer[length-1] == '\n' );
|
|
if ( BeginningOfLine ) {
|
|
AzGlLogFileOutputBuffer[length-1] = '\r';
|
|
AzGlLogFileOutputBuffer[length] = '\n';
|
|
AzGlLogFileOutputBuffer[length+1] = '\0';
|
|
length++;
|
|
}
|
|
|
|
|
|
#if 0
|
|
//
|
|
// If the log file isn't open,
|
|
// just output to the debug terminal
|
|
//
|
|
|
|
if ( AzGlLogFile == INVALID_HANDLE_VALUE ) {
|
|
#if DBG
|
|
if ( !LogProblemWarned ) {
|
|
(void) DbgPrint( "[NETLOGON] Cannot write to log file [Invalid Handle]\n" );
|
|
LogProblemWarned = TRUE;
|
|
}
|
|
#endif // DBG
|
|
|
|
//
|
|
// Write the debug info to the log file.
|
|
//
|
|
|
|
} else {
|
|
if ( !WriteFile( AzGlLogFile,
|
|
AzGlLogFileOutputBuffer,
|
|
length,
|
|
&BytesWritten,
|
|
NULL ) ) {
|
|
#if DBG
|
|
if ( !LogProblemWarned ) {
|
|
(void) DbgPrint( "[NETLOGON] Cannot write to log file %ld\n", GetLastError() );
|
|
LogProblemWarned = TRUE;
|
|
}
|
|
#endif // DBG
|
|
}
|
|
|
|
}
|
|
#else // 0
|
|
printf( "%s", AzGlLogFileOutputBuffer );
|
|
#endif // 0
|
|
|
|
}
|
|
|
|
VOID
|
|
AzpPrintRoutine(
|
|
IN DWORD DebugFlag,
|
|
IN LPSTR Format,
|
|
...
|
|
)
|
|
|
|
{
|
|
va_list arglist;
|
|
|
|
//
|
|
// vsprintf isn't multithreaded + we don't want to intermingle output
|
|
// from different threads.
|
|
//
|
|
|
|
SafeEnterCriticalSection( &AzGlLogFileCritSect );
|
|
|
|
//
|
|
// Simply change arguments to va_list form and call NlPrintRoutineV
|
|
//
|
|
|
|
va_start(arglist, Format);
|
|
|
|
AzpPrintRoutineV( DebugFlag, Format, arglist );
|
|
|
|
va_end(arglist);
|
|
|
|
SafeLeaveCriticalSection( &AzGlLogFileCritSect );
|
|
|
|
} // AzPrintRoutine
|
|
#endif // AZROLESDBG
|