859 lines
19 KiB
C
859 lines
19 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1996 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
nmutil.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
Miscellaneous utility routines for the Node Manager component.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Mike Massa (mikemas) 26-Oct-1996
|
|||
|
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#define UNICODE 1
|
|||
|
|
|||
|
#include "service.h"
|
|||
|
#include "nmp.h"
|
|||
|
#include <ntlsa.h>
|
|||
|
#include <ntmsv1_0.h>
|
|||
|
|
|||
|
PVOID NmpClusterKey = NULL;
|
|||
|
DWORD NmpClusterKeyLength = 0;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
NmpQueryString(
|
|||
|
IN HDMKEY Key,
|
|||
|
IN LPCWSTR ValueName,
|
|||
|
IN DWORD ValueType,
|
|||
|
IN LPWSTR *StringBuffer,
|
|||
|
IN OUT LPDWORD StringBufferSize,
|
|||
|
OUT LPDWORD StringSize
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Reads a REG_SZ or REG_MULTI_SZ registry value. If the StringBuffer is
|
|||
|
not large enough to hold the data, it is reallocated.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Key - Open key for the value to be read.
|
|||
|
|
|||
|
ValueName - Unicode name of the value to be read.
|
|||
|
|
|||
|
ValueType - REG_SZ or REG_MULTI_SZ.
|
|||
|
|
|||
|
StringBuffer - Buffer into which to place the value data.
|
|||
|
|
|||
|
StringBufferSize - Pointer to the size of the StringBuffer. This parameter
|
|||
|
is updated if StringBuffer is reallocated.
|
|||
|
|
|||
|
StringSize - The size of the data returned in StringBuffer, including
|
|||
|
the terminating null character.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The status of the registry query.
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
To avoid deadlock with DM, must not be called with NM lock held.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
DWORD status;
|
|||
|
DWORD valueType;
|
|||
|
WCHAR *temp;
|
|||
|
DWORD oldBufferSize = *StringBufferSize;
|
|||
|
BOOL noBuffer = FALSE;
|
|||
|
|
|||
|
|
|||
|
if (*StringBufferSize == 0) {
|
|||
|
noBuffer = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
*StringSize = *StringBufferSize;
|
|||
|
|
|||
|
status = DmQueryValue( Key,
|
|||
|
ValueName,
|
|||
|
&valueType,
|
|||
|
(LPBYTE) *StringBuffer,
|
|||
|
StringSize
|
|||
|
);
|
|||
|
|
|||
|
if (status == NO_ERROR) {
|
|||
|
if (!noBuffer ) {
|
|||
|
if (valueType == ValueType) {
|
|||
|
return(NO_ERROR);
|
|||
|
}
|
|||
|
else {
|
|||
|
return(ERROR_INVALID_PARAMETER);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
status = ERROR_MORE_DATA;
|
|||
|
}
|
|||
|
|
|||
|
if (status == ERROR_MORE_DATA) {
|
|||
|
temp = MIDL_user_allocate(*StringSize);
|
|||
|
|
|||
|
if (temp == NULL) {
|
|||
|
*StringSize = 0;
|
|||
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|||
|
}
|
|||
|
|
|||
|
if (!noBuffer) {
|
|||
|
MIDL_user_free(*StringBuffer);
|
|||
|
}
|
|||
|
|
|||
|
*StringBuffer = temp;
|
|||
|
*StringBufferSize = *StringSize;
|
|||
|
|
|||
|
status = DmQueryValue( Key,
|
|||
|
ValueName,
|
|||
|
&valueType,
|
|||
|
(LPBYTE) *StringBuffer,
|
|||
|
StringSize
|
|||
|
);
|
|||
|
|
|||
|
if (status == NO_ERROR) {
|
|||
|
if (valueType == ValueType) {
|
|||
|
return(NO_ERROR);
|
|||
|
}
|
|||
|
else {
|
|||
|
*StringSize = 0;
|
|||
|
return(ERROR_INVALID_PARAMETER);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return(status);
|
|||
|
|
|||
|
} // NmpQueryString
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Routines to support the common network configuration code.
|
|||
|
//
|
|||
|
VOID
|
|||
|
ClNetPrint(
|
|||
|
IN ULONG LogLevel,
|
|||
|
IN PCHAR FormatString,
|
|||
|
...
|
|||
|
)
|
|||
|
{
|
|||
|
CHAR buffer[256];
|
|||
|
DWORD bytes;
|
|||
|
va_list argList;
|
|||
|
|
|||
|
va_start(argList, FormatString);
|
|||
|
|
|||
|
bytes = FormatMessageA(
|
|||
|
FORMAT_MESSAGE_FROM_STRING,
|
|||
|
FormatString,
|
|||
|
0,
|
|||
|
0,
|
|||
|
buffer,
|
|||
|
sizeof(buffer),
|
|||
|
&argList
|
|||
|
);
|
|||
|
|
|||
|
va_end(argList);
|
|||
|
|
|||
|
if (bytes != 0) {
|
|||
|
ClRtlLogPrint(LogLevel, "%1!hs!", buffer);
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
} // ClNetPrint
|
|||
|
|
|||
|
VOID
|
|||
|
ClNetLogEvent(
|
|||
|
IN DWORD LogLevel,
|
|||
|
IN DWORD MessageId
|
|||
|
)
|
|||
|
{
|
|||
|
CsLogEvent(LogLevel, MessageId);
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
} // ClNetLogEvent
|
|||
|
|
|||
|
VOID
|
|||
|
ClNetLogEvent1(
|
|||
|
IN DWORD LogLevel,
|
|||
|
IN DWORD MessageId,
|
|||
|
IN LPCWSTR Arg1
|
|||
|
)
|
|||
|
{
|
|||
|
CsLogEvent1(LogLevel, MessageId, Arg1);
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
} // ClNetLogEvent1
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
ClNetLogEvent2(
|
|||
|
IN DWORD LogLevel,
|
|||
|
IN DWORD MessageId,
|
|||
|
IN LPCWSTR Arg1,
|
|||
|
IN LPCWSTR Arg2
|
|||
|
)
|
|||
|
{
|
|||
|
CsLogEvent2(LogLevel, MessageId, Arg1, Arg2);
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
} // ClNetLogEvent2
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
ClNetLogEvent3(
|
|||
|
IN DWORD LogLevel,
|
|||
|
IN DWORD MessageId,
|
|||
|
IN LPCWSTR Arg1,
|
|||
|
IN LPCWSTR Arg2,
|
|||
|
IN LPCWSTR Arg3
|
|||
|
)
|
|||
|
{
|
|||
|
CsLogEvent3(LogLevel, MessageId, Arg1, Arg2, Arg3);
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
} // ClNetLogEvent3
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
NmpLockedEnterApi(
|
|||
|
NM_STATE RequiredState
|
|||
|
)
|
|||
|
{
|
|||
|
if (NmpState >= RequiredState) {
|
|||
|
NmpActiveThreadCount++;
|
|||
|
CL_ASSERT(NmpActiveThreadCount != 0);
|
|||
|
return(TRUE);
|
|||
|
}
|
|||
|
|
|||
|
return(FALSE);
|
|||
|
|
|||
|
} // NmpLockedEnterApi
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
NmpEnterApi(
|
|||
|
NM_STATE RequiredState
|
|||
|
)
|
|||
|
{
|
|||
|
BOOLEAN mayEnter;
|
|||
|
|
|||
|
|
|||
|
NmpAcquireLock();
|
|||
|
|
|||
|
mayEnter = NmpLockedEnterApi(RequiredState);
|
|||
|
|
|||
|
NmpReleaseLock();
|
|||
|
|
|||
|
return(mayEnter);
|
|||
|
|
|||
|
} // NmpEnterApi
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
NmpLockedLeaveApi(
|
|||
|
VOID
|
|||
|
)
|
|||
|
{
|
|||
|
CL_ASSERT(NmpActiveThreadCount > 0);
|
|||
|
|
|||
|
NmpActiveThreadCount--;
|
|||
|
|
|||
|
if ((NmpActiveThreadCount == 0) && (NmpState == NmStateOfflinePending)) {
|
|||
|
SetEvent(NmpShutdownEvent);
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
} // NmpLockedLeaveApi
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
NmpLeaveApi(
|
|||
|
VOID
|
|||
|
)
|
|||
|
{
|
|||
|
NmpAcquireLock();
|
|||
|
|
|||
|
NmpLockedLeaveApi();
|
|||
|
|
|||
|
NmpReleaseLock();
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
} // NmpLeaveApi
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Routines to provide a cluster shared key for signing and encrypting
|
|||
|
// data.
|
|||
|
//
|
|||
|
|
|||
|
DWORD
|
|||
|
NmpGetLogonId(
|
|||
|
OUT LUID * LogonId
|
|||
|
)
|
|||
|
{
|
|||
|
HANDLE tokenHandle = NULL;
|
|||
|
TOKEN_STATISTICS tokenInfo;
|
|||
|
DWORD bytesReturned;
|
|||
|
BOOL success = FALSE;
|
|||
|
DWORD status;
|
|||
|
|
|||
|
if (LogonId == NULL) {
|
|||
|
status = STATUS_UNSUCCESSFUL;
|
|||
|
goto error_exit;
|
|||
|
}
|
|||
|
|
|||
|
if (!OpenProcessToken(
|
|||
|
GetCurrentProcess(),
|
|||
|
TOKEN_QUERY,
|
|||
|
&tokenHandle
|
|||
|
)) {
|
|||
|
status = GetLastError();
|
|||
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|||
|
"[NM] Failed to open process token, status %1!u!.\n",
|
|||
|
status
|
|||
|
);
|
|||
|
goto error_exit;
|
|||
|
}
|
|||
|
|
|||
|
if (!GetTokenInformation(
|
|||
|
tokenHandle,
|
|||
|
TokenStatistics,
|
|||
|
&tokenInfo,
|
|||
|
sizeof(tokenInfo),
|
|||
|
&bytesReturned
|
|||
|
)) {
|
|||
|
status = GetLastError();
|
|||
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|||
|
"[NM] Failed to get token information, status %1!u!.\n",
|
|||
|
status
|
|||
|
);
|
|||
|
goto error_exit;
|
|||
|
}
|
|||
|
|
|||
|
RtlCopyMemory(LogonId, &(tokenInfo.AuthenticationId), sizeof(LUID));
|
|||
|
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
|
|||
|
error_exit:
|
|||
|
|
|||
|
if (tokenHandle != NULL) {
|
|||
|
CloseHandle(tokenHandle);
|
|||
|
}
|
|||
|
|
|||
|
return(status);
|
|||
|
|
|||
|
} // NmpGetLogonId
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
NmpGenerateClusterKey(
|
|||
|
IN PVOID MixingBytes,
|
|||
|
IN DWORD MixingBytesSize,
|
|||
|
OUT PVOID * Key,
|
|||
|
OUT DWORD * KeyLength
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Generate the cluster key using the cluster instance id
|
|||
|
as mixing bytes. Allocate a buffer for the key and
|
|||
|
return it.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Key - set to buffer containing key
|
|||
|
|
|||
|
KeyLength - length of resulting key
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
LUID logonId;
|
|||
|
|
|||
|
BOOLEAN wasEnabled = FALSE;
|
|||
|
BOOLEAN trusted = FALSE;
|
|||
|
|
|||
|
STRING name;
|
|||
|
|
|||
|
HANDLE lsaHandle = NULL;
|
|||
|
DWORD ignore;
|
|||
|
|
|||
|
DWORD packageId = 0;
|
|||
|
|
|||
|
DWORD requestSize;
|
|||
|
PMSV1_0_DERIVECRED_REQUEST request = NULL;
|
|||
|
DWORD responseSize;
|
|||
|
PMSV1_0_DERIVECRED_RESPONSE response = NULL;
|
|||
|
|
|||
|
PUCHAR key;
|
|||
|
DWORD keyLength;
|
|||
|
|
|||
|
DWORD status = STATUS_SUCCESS;
|
|||
|
DWORD subStatus = STATUS_SUCCESS;
|
|||
|
|
|||
|
status = NmpGetLogonId(&logonId);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
ClRtlLogPrint(
|
|||
|
LOG_UNUSUAL,
|
|||
|
"[NM] Failed to determine logon ID, status %1!u!.\n",
|
|||
|
status
|
|||
|
);
|
|||
|
goto error_exit;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Try to turn on TCB privilege if running in console mode.
|
|||
|
//
|
|||
|
// ISSUE-2001/04/30-daviddio
|
|||
|
// In normal operation, there is no need to enable the TCB privilege.
|
|||
|
// In fact, enabling the TCB privilege should usually fail since the
|
|||
|
// cluster service account is not given the TCB privilege during setup.
|
|||
|
// The fix for bug 337751 allows the cluster service account to issue
|
|||
|
// a MSV1_0_DERIVECRED_REQUEST even if it does not have a trusted
|
|||
|
// connection to LSA. The reason this code is left in is for
|
|||
|
// trouble-shooting. If the cluster service is run from the command
|
|||
|
// line (e.g. not via the SCM), then the fix for bug 337751 will not
|
|||
|
// apply, and a trusted connection to LSA will be required to generate
|
|||
|
// the cluster key.
|
|||
|
//
|
|||
|
if (CsRunningAsService) {
|
|||
|
status = RtlAdjustPrivilege(SE_TCB_PRIVILEGE, TRUE, FALSE, &wasEnabled);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
#if CLUSTER_BETA
|
|||
|
ClRtlLogPrint(LOG_NOISE,
|
|||
|
"[NM] Failed to turn on TCB privilege, status %1!u!.\n",
|
|||
|
LsaNtStatusToWinError(status)
|
|||
|
);
|
|||
|
#endif // CLUSTER_BETA
|
|||
|
trusted = FALSE;
|
|||
|
} else {
|
|||
|
#if CLUSTER_BETA
|
|||
|
ClRtlLogPrint(LOG_NOISE,
|
|||
|
"[NM] Turned on TCB privilege, wasEnabled = %1!ws!.\n",
|
|||
|
(wasEnabled) ? L"TRUE" : L"FALSE"
|
|||
|
);
|
|||
|
#endif // CLUSTER_BETA
|
|||
|
trusted = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Establish contact with LSA.
|
|||
|
//
|
|||
|
if (trusted) {
|
|||
|
RtlInitString(&name, "ClusSvcNM");
|
|||
|
status = LsaRegisterLogonProcess(&name, &lsaHandle, &ignore);
|
|||
|
|
|||
|
//
|
|||
|
// Turn off TCB privilege
|
|||
|
//
|
|||
|
if (!wasEnabled) {
|
|||
|
subStatus = RtlAdjustPrivilege(
|
|||
|
SE_TCB_PRIVILEGE,
|
|||
|
FALSE,
|
|||
|
FALSE,
|
|||
|
&wasEnabled
|
|||
|
);
|
|||
|
if (!NT_SUCCESS(subStatus)) {
|
|||
|
ClRtlLogPrint(
|
|||
|
LOG_UNUSUAL,
|
|||
|
"[NM] Failed to disable TCB privilege, "
|
|||
|
"status %1!u!.\n",
|
|||
|
subStatus
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
else {
|
|||
|
status = LsaConnectUntrusted(&lsaHandle);
|
|||
|
}
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
status = LsaNtStatusToWinError(status);
|
|||
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|||
|
"[NM] Failed to obtain LSA logon handle in %1!ws! mode, "
|
|||
|
"status %2!u!.\n",
|
|||
|
(trusted) ? L"trusted" : L"untrusted", status
|
|||
|
);
|
|||
|
goto error_exit;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Lookup the authentication package.
|
|||
|
//
|
|||
|
RtlInitString( &name, MSV1_0_PACKAGE_NAME );
|
|||
|
|
|||
|
status = LsaLookupAuthenticationPackage(lsaHandle, &name, &packageId);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
status = LsaNtStatusToWinError(status);
|
|||
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|||
|
"[NM] Failed to local authentication package with "
|
|||
|
"name %1!ws!, status %2!u!.\n",
|
|||
|
name.Buffer, status
|
|||
|
);
|
|||
|
goto error_exit;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Build the derive credentials request with the provided
|
|||
|
// mixing bytes.
|
|||
|
//
|
|||
|
requestSize = sizeof(MSV1_0_DERIVECRED_REQUEST) + MixingBytesSize;
|
|||
|
|
|||
|
request = LocalAlloc(LMEM_FIXED, requestSize);
|
|||
|
if (request == NULL) {
|
|||
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|||
|
"[NM] Failed to allocate LSA request of size %1!u! bytes.\n"
|
|||
|
);
|
|||
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
goto error_exit;
|
|||
|
}
|
|||
|
|
|||
|
request->MessageType = MsV1_0DeriveCredential;
|
|||
|
RtlCopyMemory(&(request->LogonId), &logonId, sizeof(logonId));
|
|||
|
request->DeriveCredType = MSV1_0_DERIVECRED_TYPE_SHA1;
|
|||
|
request->DeriveCredInfoLength = MixingBytesSize;
|
|||
|
RtlCopyMemory(
|
|||
|
&(request->DeriveCredSubmitBuffer[0]),
|
|||
|
MixingBytes,
|
|||
|
MixingBytesSize
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Make the call through LSA to the authentication package.
|
|||
|
//
|
|||
|
status = LsaCallAuthenticationPackage(
|
|||
|
lsaHandle,
|
|||
|
packageId,
|
|||
|
request,
|
|||
|
requestSize,
|
|||
|
&response,
|
|||
|
&responseSize,
|
|||
|
&subStatus
|
|||
|
);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
status = LsaNtStatusToWinError(status);
|
|||
|
subStatus = LsaNtStatusToWinError(subStatus);
|
|||
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|||
|
"[NM] DeriveCredential call to authentication "
|
|||
|
"package failed, status %1!u!, auth package "
|
|||
|
"status %2!u!.\n", status, subStatus
|
|||
|
);
|
|||
|
goto error_exit;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Allocate a non-LSA buffer to store the key.
|
|||
|
//
|
|||
|
keyLength = response->DeriveCredInfoLength;
|
|||
|
key = MIDL_user_allocate(keyLength);
|
|||
|
if (key == NULL) {
|
|||
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|||
|
"[NM] Failed to allocate buffer for cluster "
|
|||
|
"key of size %1!u!.\n",
|
|||
|
keyLength
|
|||
|
);
|
|||
|
goto error_exit;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Store the derived credentials in the key buffer.
|
|||
|
//
|
|||
|
RtlCopyMemory(key, &(response->DeriveCredReturnBuffer[0]), keyLength);
|
|||
|
|
|||
|
//
|
|||
|
// Zero the derived credential buffer to be extra paranoid.
|
|||
|
//
|
|||
|
RtlZeroMemory(
|
|||
|
&(response->DeriveCredReturnBuffer[0]),
|
|||
|
response->DeriveCredInfoLength
|
|||
|
);
|
|||
|
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
*Key = key;
|
|||
|
*KeyLength = keyLength;
|
|||
|
|
|||
|
error_exit:
|
|||
|
|
|||
|
if (lsaHandle != NULL) {
|
|||
|
LsaDeregisterLogonProcess(lsaHandle);
|
|||
|
lsaHandle = NULL;
|
|||
|
}
|
|||
|
|
|||
|
if (request != NULL) {
|
|||
|
LocalFree(request);
|
|||
|
request = NULL;
|
|||
|
}
|
|||
|
|
|||
|
if (response != NULL) {
|
|||
|
LsaFreeReturnBuffer(response);
|
|||
|
response = NULL;
|
|||
|
}
|
|||
|
|
|||
|
return(status);
|
|||
|
|
|||
|
} // NmpGenerateClusterKey
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
NmpGetClusterKey(
|
|||
|
OUT PVOID KeyBuffer,
|
|||
|
IN OUT DWORD * KeyBufferLength
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Copy the shared cluster key into the buffer provided.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
KeyBuffer - buffer to which key should be copied
|
|||
|
|
|||
|
KeyBufferLength - IN: length of KeyBuffer
|
|||
|
OUT: required buffer size, if input
|
|||
|
buffer length is insufficient
|
|||
|
|
|||
|
Return value:
|
|||
|
|
|||
|
ERROR_INSUFFICIENT_BUFFER if KeyBuffer is too small.
|
|||
|
ERROR_FILE_NOT_FOUND if NmpClusterKey has not yet been
|
|||
|
generated.
|
|||
|
ERROR_SUCCESS on success.
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
Acquires and releases NM lock. Since NM lock is
|
|||
|
implemented as a critical section, calling thread
|
|||
|
is permitted to already hold NM lock.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
DWORD status;
|
|||
|
|
|||
|
NmpAcquireLock();
|
|||
|
|
|||
|
if (NmpClusterKey == NULL) {
|
|||
|
status = ERROR_FILE_NOT_FOUND;
|
|||
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|||
|
"[NM] The cluster key has not yet been derived.\n"
|
|||
|
);
|
|||
|
} else{
|
|||
|
if (KeyBuffer == NULL || NmpClusterKeyLength > *KeyBufferLength) {
|
|||
|
status = ERROR_INSUFFICIENT_BUFFER;
|
|||
|
} else {
|
|||
|
RtlCopyMemory(KeyBuffer, NmpClusterKey, NmpClusterKeyLength);
|
|||
|
status = ERROR_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
*KeyBufferLength = NmpClusterKeyLength;
|
|||
|
}
|
|||
|
|
|||
|
NmpReleaseLock();
|
|||
|
|
|||
|
return(status);
|
|||
|
|
|||
|
} // NmpGetClusterKey
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
NmpRegenerateClusterKey(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Forces regeneration of cluster key.
|
|||
|
|
|||
|
Must be called during cluster initialization to generate
|
|||
|
cluster key the first time.
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
Acquires and releases NM lock.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
DWORD status;
|
|||
|
BOOLEAN lockAcquired;
|
|||
|
PVOID oldKey = NULL;
|
|||
|
DWORD oldKeyLength = 0;
|
|||
|
PVOID key = NULL;
|
|||
|
DWORD keyLength = 0;
|
|||
|
PVOID mixingBytes;
|
|||
|
DWORD mixingBytesSize;
|
|||
|
|
|||
|
NmpAcquireLock();
|
|||
|
lockAcquired = TRUE;
|
|||
|
|
|||
|
NmpLockedEnterApi(NmStateOnlinePending);
|
|||
|
|
|||
|
//
|
|||
|
// Form the mixing bytes.
|
|||
|
//
|
|||
|
if (NmpClusterInstanceId == NULL) {
|
|||
|
status = ERROR_INVALID_PARAMETER;
|
|||
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|||
|
"[NM] Need cluster instance id in order to derive "
|
|||
|
"cluster key, status %1!u!.\n",
|
|||
|
status
|
|||
|
);
|
|||
|
goto error_exit;
|
|||
|
}
|
|||
|
|
|||
|
mixingBytesSize = NM_WCSLEN(NmpClusterInstanceId);
|
|||
|
mixingBytes = MIDL_user_allocate(mixingBytesSize);
|
|||
|
if (mixingBytes == NULL) {
|
|||
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|||
|
"[NM] Failed to allocate buffer of size %1!u! "
|
|||
|
"for mixing bytes to derive cluster key.\n",
|
|||
|
mixingBytesSize
|
|||
|
);
|
|||
|
goto error_exit;
|
|||
|
}
|
|||
|
RtlCopyMemory(mixingBytes, NmpClusterInstanceId, mixingBytesSize);
|
|||
|
|
|||
|
//
|
|||
|
// Make a copy of the old key to detect changes.
|
|||
|
//
|
|||
|
if (NmpClusterKey != NULL) {
|
|||
|
|
|||
|
CL_ASSERT(NmpClusterKeyLength > 0);
|
|||
|
|
|||
|
oldKey = MIDL_user_allocate(NmpClusterKeyLength);
|
|||
|
if (oldKey == NULL) {
|
|||
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|||
|
"[NM] Failed to allocate buffer for cluster "
|
|||
|
"key copy.\n"
|
|||
|
);
|
|||
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
goto error_exit;
|
|||
|
}
|
|||
|
oldKeyLength = NmpClusterKeyLength;
|
|||
|
RtlCopyMemory(oldKey, NmpClusterKey, NmpClusterKeyLength);
|
|||
|
}
|
|||
|
|
|||
|
NmpReleaseLock();
|
|||
|
lockAcquired = FALSE;
|
|||
|
|
|||
|
status = NmpGenerateClusterKey(
|
|||
|
mixingBytes,
|
|||
|
mixingBytesSize,
|
|||
|
&key,
|
|||
|
&keyLength
|
|||
|
);
|
|||
|
if (status != ERROR_SUCCESS) {
|
|||
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|||
|
"[NM] Failed to generate cluster key, "
|
|||
|
"status %1!u!.\n",
|
|||
|
status
|
|||
|
);
|
|||
|
goto error_exit;
|
|||
|
}
|
|||
|
|
|||
|
NmpAcquireLock();
|
|||
|
lockAcquired = TRUE;
|
|||
|
|
|||
|
//
|
|||
|
// Make sure another thread didn't beat us in obtaining a key.
|
|||
|
// We replace the cluster key with the generated key if it is
|
|||
|
// not different from the old key (or somebody set it to NULL).
|
|||
|
//
|
|||
|
if (NmpClusterKey != NULL &&
|
|||
|
(oldKey == NULL ||
|
|||
|
NmpClusterKeyLength != oldKeyLength ||
|
|||
|
RtlCompareMemory(
|
|||
|
NmpClusterKey,
|
|||
|
oldKey,
|
|||
|
oldKeyLength
|
|||
|
) != oldKeyLength
|
|||
|
)
|
|||
|
) {
|
|||
|
|
|||
|
//
|
|||
|
// Keep the current NmpClusterKey.
|
|||
|
//
|
|||
|
} else {
|
|||
|
|
|||
|
MIDL_user_free(NmpClusterKey);
|
|||
|
NmpClusterKey = key;
|
|||
|
NmpClusterKeyLength = keyLength;
|
|||
|
key = NULL;
|
|||
|
}
|
|||
|
|
|||
|
error_exit:
|
|||
|
|
|||
|
if (lockAcquired) {
|
|||
|
NmpLockedLeaveApi();
|
|||
|
NmpReleaseLock();
|
|||
|
} else {
|
|||
|
NmpLeaveApi();
|
|||
|
}
|
|||
|
|
|||
|
if (key != NULL) {
|
|||
|
MIDL_user_free(key);
|
|||
|
key = NULL;
|
|||
|
}
|
|||
|
|
|||
|
if (mixingBytes != NULL) {
|
|||
|
MIDL_user_free(mixingBytes);
|
|||
|
mixingBytes = NULL;
|
|||
|
}
|
|||
|
|
|||
|
return(status);
|
|||
|
|
|||
|
} // NmpRegenerateClusterKey
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
NmpFreeClusterKey(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Called during NmShutdown.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
if (NmpClusterKey != NULL) {
|
|||
|
MIDL_user_free(NmpClusterKey);
|
|||
|
NmpClusterKey = NULL;
|
|||
|
NmpClusterKeyLength = 0;
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
} // NmpFreeClusterKey
|
|||
|
|