mirror of https://github.com/lianthony/NT4.0
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.
1592 lines
40 KiB
1592 lines
40 KiB
/*++
|
|
|
|
Copyright (c) 1994 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
uuidsup.c
|
|
|
|
Abstract:
|
|
|
|
Implements system dependent functions used in creating Uuids.
|
|
|
|
This file is for Win32 (NT and Chicago) systems.
|
|
|
|
External functions are:
|
|
UuidGlobalMutexRequest
|
|
UuidGlobalMutexClear
|
|
GetNodeId
|
|
UuidGetValues
|
|
|
|
|
|
|
|
Note:
|
|
|
|
WARNING:
|
|
|
|
Everything in this file is only called from within UuidCreate()
|
|
which is already holding the global mutex. Therefore none of
|
|
this code is multithread safe. For example, access to the global
|
|
Uuid HKEY's is not protected.
|
|
|
|
Author:
|
|
|
|
Mario Goertzel (MarioGo) May 23, 1994
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <precomp.hxx>
|
|
#include<nb30.h> // for ADAPTER_STATUS
|
|
#ifdef NTENV
|
|
#include<tdi.h>
|
|
#endif
|
|
#include <uuidsup.hxx>
|
|
|
|
|
|
//
|
|
// We store both persistent and volatile values in the registry.
|
|
// These keys are opened as needed and closed by UuidGetValues()
|
|
//
|
|
|
|
#ifndef KERNEL_UUIDS
|
|
static HKEY PersistentKey = 0;
|
|
|
|
// The clock sequence and time persist between boots.
|
|
static const char *RPC_UUID_PERSISTENT_DATA
|
|
= "Software\\Description\\Microsoft\\Rpc\\UuidPersistentData";
|
|
static const char *CLOCK_SEQUENCE = "ClockSequence";
|
|
static const char *LAST_TIME_ALLOCATED = "LastTimeAllocated";
|
|
|
|
static const char *UuidGlobalMutexName = "Microsoft RPC UUID Mutex";
|
|
static HANDLE UuidGlobalMutex = 0;
|
|
#endif
|
|
|
|
// The node id should not persist between boots.
|
|
static HKEY VolatileKey = 0;
|
|
static const char *RPC_UUID_TEMPORARY_DATA
|
|
= "Software\\Description\\Microsoft\\Rpc\\UuidTemporaryData";
|
|
static const char *NETWORK_ADDRESS = "NetworkAddress";
|
|
static const char *NETWORK_ADDRESS_LOCAL = "NetworkAddressLocal";
|
|
|
|
|
|
#ifdef DOSWIN32RPC
|
|
|
|
typedef unsigned char (*NETBIOS_FN_T)(NCB *);
|
|
|
|
static NETBIOS_FN_T NetbiosFn = NULL;
|
|
|
|
#endif
|
|
|
|
#ifndef KERNEL_UUIDS
|
|
|
|
RPC_STATUS __RPC_API
|
|
UuidGlobalMutexRequest(void)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will open a handle to the global named uuid mutex
|
|
if necessary. It always waits for ownership of the mutex.
|
|
An error will always be returned if we were unable to take
|
|
ownership of the mutex.
|
|
|
|
Win32 Only.
|
|
|
|
Arguments:
|
|
|
|
n/a
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK - The mutex exists and is now owned by this thread.
|
|
|
|
RPC_S_OUT_OF_MEMORY - We were unable to create the global mutex.
|
|
|
|
RPC_S_UUID_NO_ADDRESS - Rather than deadlock the system we timeout
|
|
after ten minutes. It's not clear what
|
|
the right thing to do is.
|
|
|
|
--*/
|
|
{
|
|
SECURITY_ATTRIBUTES SecurityAttributes;
|
|
SECURITY_DESCRIPTOR SecurityDescriptor;
|
|
RPC_STATUS Status = RPC_S_OK;
|
|
BOOL Bool;
|
|
|
|
if (UuidGlobalMutex == 0)
|
|
{
|
|
|
|
Bool =
|
|
InitializeSecurityDescriptor(
|
|
&SecurityDescriptor,
|
|
SECURITY_DESCRIPTOR_REVISION
|
|
);
|
|
|
|
if (Bool == FALSE)
|
|
{
|
|
ASSERT(GetLastError() == ERROR_OUTOFMEMORY);
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
Bool =
|
|
SetSecurityDescriptorDacl(
|
|
&SecurityDescriptor,
|
|
TRUE, // Dacl Present
|
|
NULL, // NULL Dacl
|
|
FALSE); // Not defaulted
|
|
|
|
if (Bool == FALSE)
|
|
{
|
|
ASSERT(GetLastError() == ERROR_OUTOFMEMORY);
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
SecurityAttributes.nLength = sizeof(SecurityAttributes);
|
|
SecurityAttributes.lpSecurityDescriptor = &SecurityDescriptor;
|
|
SecurityAttributes.bInheritHandle = FALSE;
|
|
|
|
UuidGlobalMutex = CreateMutex(&SecurityAttributes, // Security
|
|
FALSE, // Initial Owner
|
|
(LPCTSTR)UuidGlobalMutexName); // Name
|
|
|
|
if (UuidGlobalMutex == 0)
|
|
{
|
|
Status = GetLastError();
|
|
#ifdef DEBUGRPC
|
|
PrintToDebugger("RPC: CreateMutex - %x\n", Status);
|
|
#endif
|
|
ASSERT( (Status == ERROR_OUTOFMEMORY) );
|
|
|
|
Status = RPC_S_OUT_OF_MEMORY;
|
|
}
|
|
}
|
|
|
|
if (Status == RPC_S_OK)
|
|
{
|
|
Status =
|
|
WaitForSingleObject(UuidGlobalMutex, 10 * 60 * 1000);
|
|
|
|
if ( Status != WAIT_OBJECT_0 )
|
|
{
|
|
#ifdef DEBUGRPC
|
|
PrintToDebugger("RPC: Wait failed - %x\n", Status);
|
|
#endif
|
|
ASSERT( (Status == WAIT_ABANDONED) || (Status == WAIT_TIMEOUT) );
|
|
Status = RPC_S_UUID_NO_ADDRESS;
|
|
}
|
|
else
|
|
{
|
|
Status = RPC_S_OK;
|
|
}
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
void __RPC_API
|
|
UuidGlobalMutexClear()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will release the uuid global mutex.
|
|
|
|
Arguments:
|
|
|
|
n/a
|
|
|
|
Return Value:
|
|
|
|
n/a
|
|
--*/
|
|
{
|
|
BOOL Status;
|
|
|
|
ASSERT(UuidGlobalMutex);
|
|
|
|
Status = ReleaseMutex(UuidGlobalMutex);
|
|
|
|
ASSERT(Status == TRUE);
|
|
}
|
|
|
|
#endif // KERNEL_UUIDS
|
|
|
|
|
|
int OpenUuidKeysIfNecessary()
|
|
/*++
|
|
|
|
|
|
Return Value:
|
|
|
|
The return value indicates the status of both keys.
|
|
|
|
FALSE - Unable to open the keys
|
|
TRUE - Opened or created both keys.
|
|
|
|
--*/
|
|
{
|
|
RPC_STATUS Status;
|
|
ULONG Disposition;
|
|
|
|
#ifndef KERNEL_UUIDS
|
|
if (PersistentKey == 0)
|
|
{
|
|
Status =
|
|
RegCreateKeyEx(HKEY_LOCAL_MACHINE,
|
|
(LPCTSTR)RPC_UUID_PERSISTENT_DATA,
|
|
0,
|
|
(LPTSTR)"",
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_SET_VALUE | KEY_QUERY_VALUE,
|
|
0,
|
|
&PersistentKey,
|
|
&Disposition);
|
|
|
|
if (Status != ERROR_SUCCESS)
|
|
{
|
|
#ifdef DEBUGRPC
|
|
if (Status != ERROR_NOT_ENOUGH_MEMORY &&
|
|
Status != ERROR_OUTOFMEMORY)
|
|
{
|
|
PrintToDebugger("RPC UUID: RegCreateKeyEx - %x\n", Status);
|
|
}
|
|
#endif
|
|
ASSERT(Status == ERROR_OUTOFMEMORY ||
|
|
Status == ERROR_NOT_ENOUGH_MEMORY);
|
|
return(FALSE);
|
|
}
|
|
|
|
ASSERT( (Disposition == REG_CREATED_NEW_KEY)
|
|
|| (Disposition == REG_OPENED_EXISTING_KEY) );
|
|
}
|
|
#endif // ! KERNEL_UUIDS
|
|
|
|
if (VolatileKey == 0)
|
|
{
|
|
Status =
|
|
RegCreateKeyEx(HKEY_LOCAL_MACHINE,
|
|
(LPCTSTR)RPC_UUID_TEMPORARY_DATA,
|
|
0,
|
|
(LPTSTR)"",
|
|
REG_OPTION_VOLATILE,
|
|
KEY_SET_VALUE | KEY_QUERY_VALUE,
|
|
0,
|
|
&VolatileKey,
|
|
&Disposition);
|
|
|
|
if (Status != ERROR_SUCCESS)
|
|
{
|
|
#ifdef DEBUGRPC
|
|
if (Status != ERROR_NOT_ENOUGH_MEMORY &&
|
|
Status != ERROR_OUTOFMEMORY)
|
|
{
|
|
PrintToDebugger("RPC UUID: RegCreateKeyEx - 0x%x\n", Status);
|
|
}
|
|
#endif
|
|
ASSERT( (Status == ERROR_OUTOFMEMORY)
|
|
|| (Status == ERROR_NOT_ENOUGH_MEMORY) );
|
|
#ifndef KERNEL_UUIDS
|
|
RegCloseKey(PersistentKey);
|
|
PersistentKey = 0;
|
|
#endif
|
|
return(FALSE);
|
|
}
|
|
|
|
ASSERT( (Disposition == REG_CREATED_NEW_KEY)
|
|
|| (Disposition == REG_OPENED_EXISTING_KEY) );
|
|
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
void
|
|
CloseUuidKeys()
|
|
{
|
|
RPC_STATUS Status;
|
|
|
|
#ifndef KERNEL_UUIDS
|
|
if (PersistentKey)
|
|
{
|
|
Status = RegCloseKey(PersistentKey);
|
|
ASSERT(Status == ERROR_SUCCESS);
|
|
PersistentKey = 0;
|
|
}
|
|
#endif
|
|
|
|
if (VolatileKey)
|
|
{
|
|
Status = RegCloseKey(VolatileKey);
|
|
ASSERT(Status == ERROR_SUCCESS);
|
|
VolatileKey = 0;
|
|
}
|
|
}
|
|
|
|
|
|
RPC_STATUS __RPC_API
|
|
GetNodeIdFromRegistry(
|
|
OUT unsigned char *NodeId
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine loads the node id from the registry. If there is
|
|
a saved node id there is returns that.
|
|
|
|
Arguments:
|
|
|
|
NodeId - Will be set to the hardware address (6 bytes) if
|
|
this returns RPC_S_OK.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK - Normally if you've got a saved NodeId.
|
|
|
|
RPC_S_UUID_LOCAL_ONLY - Local only NodeId saved in registry.
|
|
|
|
RPC_S_UUID_NO_ADDRESS - On any error.
|
|
|
|
--*/
|
|
{
|
|
RPC_STATUS Status;
|
|
ULONG Length;
|
|
DWORD Local;
|
|
|
|
if (OpenUuidKeysIfNecessary() == 0)
|
|
{
|
|
return(RPC_S_UUID_NO_ADDRESS);
|
|
}
|
|
|
|
Length = 6;
|
|
Status =
|
|
RegQueryValueEx(VolatileKey,
|
|
(LPTSTR)NETWORK_ADDRESS,
|
|
0,
|
|
0,
|
|
(LPBYTE)NodeId,
|
|
&Length);
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Length = 4;
|
|
|
|
Status =
|
|
RegQueryValueEx(VolatileKey,
|
|
(LPTSTR)NETWORK_ADDRESS_LOCAL,
|
|
0,
|
|
0,
|
|
(LPBYTE)&Local,
|
|
&Length);
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
ASSERT(Local == 0 || Local == 1);
|
|
if (Local)
|
|
{
|
|
return(RPC_S_UUID_LOCAL_ONLY);
|
|
}
|
|
else
|
|
{
|
|
return(RPC_S_OK);
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUGRPC
|
|
if (Status != ERROR_NOT_ENOUGH_MEMORY &&
|
|
Status != ERROR_OUTOFMEMORY &&
|
|
Status != ERROR_CANTREAD &&
|
|
Status != ERROR_FILE_NOT_FOUND)
|
|
{
|
|
PrintToDebugger("RPC UUID: RegQueryValueEx - %x\n", Status);
|
|
}
|
|
#endif
|
|
ASSERT( (Status == ERROR_OUTOFMEMORY)
|
|
|| (Status == ERROR_NOT_ENOUGH_MEMORY)
|
|
|| (Status == ERROR_CANTREAD)
|
|
|| (Status == ERROR_FILE_NOT_FOUND) );
|
|
|
|
return(RPC_S_UUID_NO_ADDRESS);
|
|
}
|
|
|
|
|
|
void __RPC_API
|
|
SaveNodeIdInRegistry(
|
|
IN unsigned char *NodeId,
|
|
IN DWORD LocalOnly
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This saves the NodeId parameter into a volatile section of the
|
|
registry. This will save loading DHCP and possibly Netbios in
|
|
future applications.
|
|
|
|
Note: Only true IEEE 802 addresses should be saved.
|
|
|
|
Since this is just a cache, failure is ignored.
|
|
|
|
Arguments:
|
|
|
|
NodeId - Contains the IEEE 802 address to save.
|
|
|
|
LocalOnly - Contains 1 if the address was cooked up. 0 if it's
|
|
a real IEEE 802 address.
|
|
|
|
Return Value:
|
|
|
|
n/a
|
|
|
|
--*/
|
|
{
|
|
RPC_STATUS Status;
|
|
|
|
if (VolatileKey == 0)
|
|
{
|
|
// Means OpenUuidKeys failed and we won't bother trying to save it now.
|
|
return;
|
|
}
|
|
|
|
Status =
|
|
RegSetValueEx(VolatileKey,
|
|
(LPCTSTR)NETWORK_ADDRESS,
|
|
0,
|
|
REG_BINARY,
|
|
(LPBYTE)NodeId,
|
|
6 );
|
|
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status =
|
|
RegSetValueEx(VolatileKey,
|
|
(LPCTSTR)NETWORK_ADDRESS_LOCAL,
|
|
0,
|
|
REG_DWORD,
|
|
(LPBYTE)&LocalOnly,
|
|
4
|
|
);
|
|
}
|
|
|
|
#ifdef DEBUGRPC
|
|
if (Status != ERROR_NOT_ENOUGH_MEMORY &&
|
|
Status != ERROR_OUTOFMEMORY &&
|
|
Status != ERROR_SUCCESS)
|
|
{
|
|
PrintToDebugger("RPC UUID: RegSetValueEx - %x\n", Status);
|
|
}
|
|
#endif
|
|
ASSERT( (Status == ERROR_OUTOFMEMORY)
|
|
|| (Status == ERROR_NOT_ENOUGH_MEMORY)
|
|
|| (Status == ERROR_SUCCESS));
|
|
}
|
|
|
|
#ifdef NTENV
|
|
|
|
|
|
static const RPC_CHAR *BINDINGS_LINKAGE
|
|
= RPC_CONST_STRING("SYSTEM\\CurrentControlSet\\Services\\LanmanWorkstation\\Linkage");
|
|
static const RPC_CHAR *BINDINGS_NAME = RPC_CONST_STRING("Bind");
|
|
|
|
RPC_CHAR * __RPC_API
|
|
ReadBindings()
|
|
{
|
|
HKEY hKey;
|
|
ULONG Type;
|
|
ULONG Size;
|
|
RPC_STATUS Status;
|
|
UCHAR *pBuffer;
|
|
|
|
Status =
|
|
RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
|
(PWSTR)BINDINGS_LINKAGE,
|
|
0,
|
|
KEY_READ,
|
|
&hKey);
|
|
|
|
if (Status != ERROR_SUCCESS)
|
|
{
|
|
#ifdef DEBUGRPC
|
|
if (Status != ERROR_NOT_ENOUGH_MEMORY &&
|
|
Status != ERROR_OUTOFMEMORY &&
|
|
Status != ERROR_FILE_NOT_FOUND)
|
|
{
|
|
PrintToDebugger("RPC UUID: RegOpenKeyEx - %x\n", Status);
|
|
}
|
|
#endif
|
|
ASSERT( (Status == ERROR_OUTOFMEMORY)
|
|
|| (Status == ERROR_NOT_ENOUGH_MEMORY)
|
|
|| (Status == ERROR_CANTREAD)
|
|
|| (Status == ERROR_FILE_NOT_FOUND) );
|
|
return(0);
|
|
}
|
|
|
|
Status =
|
|
RegQueryValueExW(hKey,
|
|
(PWSTR)BINDINGS_NAME,
|
|
0,
|
|
&Type,
|
|
0, // no buffer yet
|
|
&Size);
|
|
|
|
#ifdef DEBUGRPC
|
|
if (Status != ERROR_SUCCESS &&
|
|
Status != ERROR_NOT_ENOUGH_MEMORY &&
|
|
Status != ERROR_OUTOFMEMORY &&
|
|
Status != ERROR_FILE_NOT_FOUND)
|
|
{
|
|
PrintToDebugger("RPC UUID: RegCreateKeyEx - %x\n", Status);
|
|
}
|
|
#endif
|
|
ASSERT( (Status == ERROR_SUCCESS)
|
|
|| (Status == ERROR_CANTREAD)
|
|
|| (Status == ERROR_NOT_ENOUGH_MEMORY)
|
|
|| (Status == ERROR_FILE_NOT_FOUND) );
|
|
|
|
if ( (Status != ERROR_SUCCESS)
|
|
|| (Size <= 2) )
|
|
{
|
|
RegCloseKey(hKey);
|
|
return(0);
|
|
}
|
|
|
|
pBuffer = new UCHAR[Size];
|
|
|
|
Status =
|
|
RegQueryValueExW(hKey,
|
|
(PWSTR)BINDINGS_NAME,
|
|
0,
|
|
&Type,
|
|
pBuffer,
|
|
&Size);
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
#ifdef DEBUGRPC
|
|
if (Status != ERROR_SUCCESS &&
|
|
Status != ERROR_NOT_ENOUGH_MEMORY &&
|
|
Status != ERROR_OUTOFMEMORY)
|
|
{
|
|
PrintToDebugger("RPC UUID: RegCreateKeyEx - %x\n", Status);
|
|
}
|
|
#endif
|
|
ASSERT( ( (Status == ERROR_SUCCESS) && (Type == REG_MULTI_SZ) )
|
|
|| (Status == ERROR_OUTOFMEMORY)
|
|
|| (Status == ERROR_NOT_ENOUGH_MEMORY) );
|
|
|
|
if (Status != ERROR_SUCCESS)
|
|
{
|
|
delete pBuffer;
|
|
return(0);
|
|
}
|
|
|
|
return((RPC_CHAR *)pBuffer);
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
#if !defined(_MIPS_) && !defined(_ALPHA_) && !defined(_PPC_)
|
|
#define UNALIGNED
|
|
#else
|
|
#define UNALIGNED __unaligned
|
|
#endif
|
|
|
|
// Macro used to make sure a NodeId isn't zero. It evaluates
|
|
// to RPC_S_OK if the NodeId is non-zero, RPC_S_UUID_NO_ADDRESS otherwise.
|
|
|
|
#define CHECK_NON_ZERO(id) ( ( *(unsigned long UNALIGNED *)&((id)[0]) |\
|
|
*(unsigned short UNALIGNED *)&((id)[4]) ) ? RPC_S_OK : RPC_S_UUID_NO_ADDRESS)
|
|
|
|
|
|
#ifdef NTENV
|
|
// A REG_MULTI_SZ is a buffer containing zero terminated strings. The last
|
|
// string in the buffer has two terminators. This helper returns a pointer to
|
|
// the next string or a pointer to NULL when the list is empty.
|
|
|
|
static inline RPC_CHAR *NextMultiSz(RPC_CHAR *p)
|
|
{
|
|
while(*p) p++; // points to first null
|
|
p++; // points to next string or second null
|
|
return(p);
|
|
}
|
|
|
|
|
|
RPC_STATUS __RPC_API
|
|
GetNodeIdFromNetbios(
|
|
OUT unsigned char *NodeId)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine loads the bindings from the registry and querys them for an
|
|
adapter status. (This is very similar to sumitting a NCB ASTAT).
|
|
Much of this is borrowed from nbtstat/netbios.
|
|
|
|
Arguments:
|
|
|
|
NodeId - Will be set to the hardware (IEEE 802) address if
|
|
this returns RPC_S_OK.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK - Normally.
|
|
|
|
RPC_S_UUID_NO_ADDRESS - On any error.
|
|
|
|
--*/
|
|
{
|
|
#define ADAPTER_STATUS_BLOCK_SIZE (384)
|
|
HANDLE hDevice;
|
|
CHAR Buffer[ADAPTER_STATUS_BLOCK_SIZE];
|
|
RPC_CHAR *pDeviceNames;
|
|
RPC_CHAR *pCurrentDevice;
|
|
TDI_REQUEST_QUERY_INFORMATION QueryInfo;
|
|
OBJECT_ATTRIBUTES oa;
|
|
IO_STATUS_BLOCK iosb;
|
|
UNICODE_STRING ucDevice;
|
|
NTSTATUS NtStatus;
|
|
RPC_STATUS Status;
|
|
|
|
// First thing, read the device names we want to query from the registry.
|
|
// This pointer will point to a RPC_CHAR REG_MULTI_SZ buffer.
|
|
|
|
pDeviceNames = ReadBindings();
|
|
|
|
if (pDeviceNames == 0)
|
|
return(RPC_S_UUID_NO_ADDRESS);
|
|
|
|
ASSERT(pDeviceNames);
|
|
|
|
// Each string in pDeviceNames is another device to try.
|
|
|
|
for(pCurrentDevice = pDeviceNames ;
|
|
pCurrentDevice[0] != 0 ;
|
|
pCurrentDevice = NextMultiSz(pCurrentDevice)
|
|
)
|
|
{
|
|
|
|
//
|
|
// Open the device.
|
|
//
|
|
|
|
RtlInitUnicodeString(&ucDevice, pCurrentDevice);
|
|
|
|
InitializeObjectAttributes(
|
|
&oa,
|
|
&ucDevice,
|
|
OBJ_CASE_INSENSITIVE,
|
|
(HANDLE) 0,
|
|
(PSECURITY_DESCRIPTOR) 0
|
|
);
|
|
|
|
NtStatus =
|
|
NtCreateFile(
|
|
&hDevice, // Handle
|
|
SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA, // AccessMask
|
|
&oa, // ObjectAttributs
|
|
&iosb, // IoStatusBlock
|
|
0, // AllocationSize
|
|
FILE_ATTRIBUTE_NORMAL, // FileAttributes
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE, // SharedAccess
|
|
FILE_OPEN_IF, // CreateDisposition
|
|
0, // CreateOptions
|
|
NULL, // EaBuffer
|
|
0); // EaLength
|
|
|
|
if (!NT_SUCCESS(NtStatus))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Query the device.
|
|
//
|
|
|
|
QueryInfo.QueryType = TDI_QUERY_ADAPTER_STATUS;
|
|
|
|
NtStatus =
|
|
NtDeviceIoControlFile(
|
|
hDevice, // Handle
|
|
NULL, // Event
|
|
NULL, // ApcRoutine
|
|
NULL, // ApcContext
|
|
&iosb, // IoStatusBlock
|
|
IOCTL_TDI_QUERY_INFORMATION, // IoControlCode
|
|
(void *)&QueryInfo, // InputBuffer
|
|
sizeof(QueryInfo), // InputBufferSize
|
|
Buffer, // OutputBuffer
|
|
sizeof(Buffer) // OutputBufferSize
|
|
);
|
|
|
|
if (NtStatus == STATUS_PENDING)
|
|
{
|
|
NtStatus =
|
|
NtWaitForSingleObject(
|
|
hDevice, // Handle
|
|
FALSE, // Alertable
|
|
NULL); // Timeout
|
|
}
|
|
|
|
if (NT_SUCCESS(NtStatus))
|
|
{
|
|
// If it is zero, we should keep trying.
|
|
|
|
RpcpMemoryCopy(NodeId, Buffer, 6);
|
|
|
|
Status = CHECK_NON_ZERO(NodeId);
|
|
|
|
if (Status == RPC_S_OK)
|
|
{
|
|
delete pDeviceNames;
|
|
NtClose(hDevice);
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
ASSERT(Status == RPC_S_UUID_NO_ADDRESS);
|
|
}
|
|
|
|
NtClose(hDevice);
|
|
}
|
|
|
|
|
|
// None of the devices worked, bummer dude.
|
|
delete pDeviceNames;
|
|
return(RPC_S_UUID_NO_ADDRESS);
|
|
}
|
|
#endif
|
|
|
|
#ifdef DOSWIN32RPC
|
|
RPC_STATUS __RPC_API
|
|
GetNodeIdFromNetbios(
|
|
OUT unsigned char PAPI * NodeId
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine retrieves the node id from netbios. This submits a
|
|
synchronous adapter status ncb which returns a 384 byte status block
|
|
(well, astat can return more, but we only care about the first
|
|
6 bytes anyways and we must get at least 384 bytes back). See the
|
|
IBM LAN Technical reference for more information about the NCB.STATUS
|
|
command.
|
|
|
|
Note that this returns info for only lana 0.
|
|
|
|
Arguments:
|
|
|
|
Pointer to where to place the node id.
|
|
|
|
Return Value:
|
|
|
|
UUID_S_OK - Everything went ok
|
|
UUID_S_NO_ADDRESS - Couldn't retrieve some information
|
|
|
|
--*/
|
|
|
|
{
|
|
int i;
|
|
NCB AnNcb;
|
|
HINSTANCE hNetapiDll;
|
|
|
|
struct {
|
|
ADAPTER_STATUS AdapterStatus;
|
|
NAME_BUFFER NameBuffer[32];
|
|
} AdapterStatusBlock;
|
|
|
|
// LoadLibrary is used so to avoid bringing in NETAPI32.DLL everytime
|
|
// RPCRT4.DLL is loaded.
|
|
|
|
if (NetbiosFn == NULL) {
|
|
hNetapiDll = LoadLibrary("NETAPI32.DLL");
|
|
if (hNetapiDll == NULL) {
|
|
return (RPC_S_UUID_NO_ADDRESS);
|
|
}
|
|
NetbiosFn = (NETBIOS_FN_T) GetProcAddress(hNetapiDll, "Netbios");
|
|
if (NetbiosFn == NULL) {
|
|
return (RPC_S_UUID_NO_ADDRESS);
|
|
}
|
|
}
|
|
|
|
ASSERT(NetbiosFn != NULL);
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
AnNcb.ncb_command = NCBASTAT;
|
|
AnNcb.ncb_buffer = (unsigned char *)&AdapterStatusBlock;
|
|
AnNcb.ncb_length = sizeof(AdapterStatusBlock);
|
|
AnNcb.ncb_callname[0] = '*'; // '*' -> local netbios
|
|
AnNcb.ncb_callname[1] = '\0';
|
|
AnNcb.ncb_lana_num = i;
|
|
|
|
(*NetbiosFn)( &AnNcb );
|
|
if (AnNcb.ncb_retcode == NRC_GOODRET) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == 8) {
|
|
#ifdef DEBUGRPC
|
|
PrintToDebugger("Unable to obtain ethernet address from NetBIOS\n");
|
|
#endif
|
|
return (RPC_S_UUID_NO_ADDRESS);
|
|
}
|
|
|
|
RpcpMemoryCopy(NodeId,
|
|
AdapterStatusBlock.AdapterStatus.adapter_address, 6);
|
|
|
|
return (RPC_S_OK);
|
|
}
|
|
|
|
RPC_STATUS __RPC_API
|
|
GetNodeIdFromIPX(
|
|
OUT unsigned char PAPI * NodeId
|
|
)
|
|
{
|
|
HANDLE VxDHandle;
|
|
DWORD IpxCmd;
|
|
char lpvOutBuffer[10];
|
|
DWORD cbInBuffer = sizeof(DWORD);
|
|
DWORD cbOutBuffer = 10;
|
|
ULONG cbOutReturned;
|
|
LPOVERLAPPED lpvOverLapped=NULL;
|
|
|
|
VxDHandle = CreateFile( "\\\\.\\NWLINK",
|
|
GENERIC_WRITE,
|
|
FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL );
|
|
|
|
if ( VxDHandle == INVALID_HANDLE_VALUE ) {
|
|
return (RPC_S_UUID_NO_ADDRESS);
|
|
}
|
|
|
|
IpxCmd = 9; // GetInternetAddress
|
|
|
|
if ( !DeviceIoControl(
|
|
VxDHandle,
|
|
0x100, // NWLINK_SUBMIT_IPX_CMD
|
|
&IpxCmd,
|
|
cbInBuffer,
|
|
lpvOutBuffer,
|
|
cbOutBuffer,
|
|
&cbOutReturned,
|
|
lpvOverLapped)) {
|
|
CloseHandle( VxDHandle );
|
|
return (RPC_S_UUID_NO_ADDRESS);
|
|
}
|
|
|
|
RpcpMemoryCopy(NodeId, &lpvOutBuffer[4], 6);
|
|
|
|
CloseHandle( VxDHandle );
|
|
|
|
return (RPC_S_OK);
|
|
}
|
|
#endif
|
|
|
|
|
|
RPC_STATUS __RPC_API
|
|
CookupNodeId(unsigned char *NodeId)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called when all else fails. Here we mix a bunch of
|
|
system parameters together for a 47bit node ID.
|
|
|
|
Arguments:
|
|
|
|
NodeId - Will be set to a value unlikly to be duplicated on another
|
|
machine. It is not guaranteed to be unique even on this machine.
|
|
But since UUIDs are (time + sequence) this is okay for
|
|
a local UUID.
|
|
|
|
It will be composed of:
|
|
The computer name.
|
|
The value of the performance counter.
|
|
The system memory status.
|
|
The total bytes and free bytes on C:
|
|
The stack pointer (value).
|
|
An LUID (locally unique ID)
|
|
Plus whatever random stuff was in the NodeId to begin with.
|
|
|
|
The NodeId returned is explicity made into a Multicast IEEE 802
|
|
address so that it will not conflict with a 'real' IEEE 802
|
|
based UUID.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_UUID_LOCAL_ONLY - Always.
|
|
|
|
--*/
|
|
{
|
|
unsigned char LocalNodeId[6]; // NOT initialized.
|
|
unsigned char ComputerName[MAX_COMPUTERNAME_LENGTH + 1];
|
|
BOOL BoolResult;
|
|
ULONG i = MAX_COMPUTERNAME_LENGTH+1;
|
|
LARGE_INTEGER largeInt;
|
|
LUID luid;
|
|
ULONG UNALIGNED *NodeIdPart1 = (ULONG *)&LocalNodeId[0]; // Bytes 0 - 3
|
|
ULONG UNALIGNED *NodeIdPart2 = (ULONG *)&LocalNodeId[2]; // Bytes 2 - 5
|
|
MEMORYSTATUS memStatus;
|
|
ULONG SectorsPerCluster;
|
|
ULONG BytesPerSector;
|
|
ULONG TotalClusters;
|
|
ULONG FreeClusters;
|
|
|
|
// The computer name is xor'ed in until it runs out.
|
|
|
|
BoolResult =
|
|
GetComputerNameA((CHAR *)ComputerName, &i);
|
|
|
|
if (BoolResult)
|
|
{
|
|
unsigned char *p = ComputerName;
|
|
i = 0;
|
|
while(*p)
|
|
{
|
|
*( ((unsigned char *)LocalNodeId) + i) ^= *p++;
|
|
if (++i > 6)
|
|
{
|
|
i = 0;
|
|
}
|
|
}
|
|
}
|
|
#ifdef DEBGURPC
|
|
else
|
|
{
|
|
PrintToDebugger("RPC: GetComputerName failed - %d\n", GetLastError());
|
|
ASSERT(!"RPC: GetComputerName failed\n");
|
|
}
|
|
#endif
|
|
|
|
// The performance counter is xor'ed into the LocalNodeId.
|
|
|
|
BoolResult =
|
|
QueryPerformanceCounter(&largeInt);
|
|
|
|
if (BoolResult)
|
|
{
|
|
*NodeIdPart2 ^= largeInt.HighPart ^ largeInt.LowPart;
|
|
*NodeIdPart1 ^= largeInt.HighPart ^ largeInt.LowPart;
|
|
}
|
|
#ifdef DEBUGRPC
|
|
else
|
|
{
|
|
PrintToDebugger("QueryPreformanceCount failed - %d\n", GetLastError());
|
|
ASSERT(!"RPC: QueryPerformanceCounter failed.\n");
|
|
}
|
|
#endif
|
|
|
|
// The current SP is xor'ed into both parts of the LocalNodeId.
|
|
|
|
*NodeIdPart1 ^= (ULONG)&LocalNodeId;
|
|
*NodeIdPart2 ^= (ULONG)&LocalNodeId;
|
|
|
|
// The memory status is Xor's into the LocalNodeId.
|
|
memStatus.dwLength = sizeof(MEMORYSTATUS);
|
|
|
|
GlobalMemoryStatus(&memStatus);
|
|
|
|
*NodeIdPart1 ^= memStatus.dwMemoryLoad;
|
|
*NodeIdPart2 ^= memStatus.dwTotalPhys;
|
|
*NodeIdPart1 ^= memStatus.dwAvailPhys;
|
|
*NodeIdPart1 ^= memStatus.dwTotalPageFile;
|
|
*NodeIdPart2 ^= memStatus.dwAvailPageFile;
|
|
*NodeIdPart2 ^= memStatus.dwTotalVirtual;
|
|
*NodeIdPart1 ^= memStatus.dwAvailVirtual;
|
|
|
|
// LUID's are good on this machine during this boot only.
|
|
|
|
BoolResult =
|
|
AllocateLocallyUniqueId(&luid);
|
|
|
|
if (BoolResult)
|
|
{
|
|
*NodeIdPart1 ^= luid.LowPart;
|
|
*NodeIdPart2 ^= luid.HighPart;
|
|
}
|
|
#ifdef DEBGURPC
|
|
else
|
|
{
|
|
PrintToDebugger("Status %d\n", GetLastError());
|
|
ASSERT(!"RPC: AllocateLocallyUniqueId failed.\n");
|
|
}
|
|
#endif
|
|
|
|
// Disk parameters and free space
|
|
|
|
BoolResult =
|
|
GetDiskFreeSpaceA("c:\\",
|
|
&SectorsPerCluster,
|
|
&BytesPerSector,
|
|
&FreeClusters,
|
|
&TotalClusters
|
|
);
|
|
|
|
if (BoolResult)
|
|
{
|
|
*NodeIdPart2 ^= TotalClusters * SectorsPerCluster * BytesPerSector;
|
|
*NodeIdPart1 ^= FreeClusters * SectorsPerCluster * BytesPerSector;
|
|
}
|
|
#ifdef DEBUGRPC
|
|
else
|
|
{
|
|
PrintToDebugger("RPC dceuuid.cxx: GetDiskFreeSpace failed - %d\n", GetLastError());
|
|
}
|
|
#endif
|
|
|
|
// Or in the 'multicast' bit to distinguish this NodeId
|
|
// from all other possible IEEE 802 addresses.
|
|
|
|
LocalNodeId[0] |= 0x80;
|
|
|
|
#if 0
|
|
PrintToDebugger("RPC cooked up the following NodeId: ");
|
|
for(i = 0; i < 6; i++)
|
|
{
|
|
PrintToDebugger("%02x", (unsigned int)LocalNodeId[i]);
|
|
}
|
|
PrintToDebugger("\n");
|
|
#endif
|
|
|
|
RpcpMemoryCopy(NodeId, LocalNodeId, 6);
|
|
|
|
return(RPC_S_UUID_LOCAL_ONLY);
|
|
}
|
|
|
|
|
|
RPC_STATUS __RPC_API
|
|
GetNodeId(unsigned char *NodeId)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine finds a NodeId (IEEE 802 address) for Windows NT
|
|
or Chicago machine. If it can't find a NodeId, or if the NodeId
|
|
is zero, it will 'cookup' a NodeId.
|
|
|
|
Note:
|
|
|
|
THIS ROUTINE SHOULD ONLY BE CALLED BY A SINGLE THREAD AT A TIME.
|
|
|
|
Arguments:
|
|
|
|
NodeId - Will be set to the hardware (IEEE 802) (6 bytes) if
|
|
this returns RPC_S_OK.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK - Normally.
|
|
|
|
RPC_S_UUID_LOCAL_ONLY - If we had to 'cookup' a NodeId.
|
|
|
|
--*/
|
|
{
|
|
RPC_STATUS Status;
|
|
BOOL GotLocalId = 0;
|
|
|
|
// Try looking up the NodeId in the registry. Querying the system for
|
|
// the network address is expensive in both time and size.
|
|
|
|
Status = GetNodeIdFromRegistry(NodeId);
|
|
|
|
if (Status == RPC_S_UUID_LOCAL_ONLY)
|
|
{
|
|
// We'll try to get a real address, if that fails then we'll
|
|
// use the local id in the registry.
|
|
GotLocalId = 1;
|
|
}
|
|
|
|
if (Status == RPC_S_OK)
|
|
return(Status);
|
|
|
|
ASSERT( Status == RPC_S_UUID_NO_ADDRESS
|
|
|| Status == RPC_S_UUID_LOCAL_ONLY);
|
|
|
|
Status = GetNodeIdFromNetbios(NodeId);
|
|
|
|
if (Status == RPC_S_OK)
|
|
Status = CHECK_NON_ZERO(NodeId);
|
|
|
|
if (Status == RPC_S_OK)
|
|
{
|
|
#ifdef DEBUGRPC
|
|
if (GotLocalId)
|
|
{
|
|
PrintToDebugger("RPC: Network address found (network started)\n");
|
|
}
|
|
#endif
|
|
SaveNodeIdInRegistry(NodeId, 0);
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
#ifdef DOSWIN32RPC
|
|
Status = GetNodeIdFromIPX(NodeId);
|
|
if (Status == RPC_S_OK)
|
|
Status = CHECK_NON_ZERO(NodeId);
|
|
|
|
if (Status == RPC_S_OK)
|
|
{
|
|
#ifdef DEBUGRPC
|
|
if (GotLocalId)
|
|
{
|
|
PrintToDebugger("RPC: Network address found (network started)\n");
|
|
}
|
|
#endif
|
|
SaveNodeIdInRegistry(NodeId, 0);
|
|
return(RPC_S_OK);
|
|
}
|
|
#endif
|
|
|
|
ASSERT(Status == RPC_S_UUID_NO_ADDRESS);
|
|
|
|
if (GotLocalId == 1)
|
|
{
|
|
// We found a local id from the registry, and we don't have a real address
|
|
// so we'll use it.
|
|
return(RPC_S_UUID_LOCAL_ONLY);
|
|
}
|
|
|
|
#ifdef DEBUGRPC
|
|
PrintToDebugger("RPC: No network address found.\n");
|
|
#endif
|
|
|
|
Status = CookupNodeId(NodeId);
|
|
|
|
ASSERT( (Status == RPC_S_UUID_LOCAL_ONLY) );
|
|
|
|
// Save cooked ID but mark it as being local. This way we'll generate
|
|
// at most 1 cooked ID/boot.
|
|
|
|
SaveNodeIdInRegistry(NodeId, 1);
|
|
|
|
return (Status);
|
|
}
|
|
|
|
#ifndef KERNEL_UUIDS
|
|
|
|
void __RPC_API
|
|
UuidTime(
|
|
OUT UUIDTIME __RPC_FAR *pTime)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine determines a 64bit time value. This is system dependent.
|
|
This should be 100ns ticks since Oct 15, 1582 AD.
|
|
|
|
Note: The UUID only uses the lower 60 bits of this time.
|
|
This means we'll run into problems in around 5200 AD.
|
|
|
|
Arguments:
|
|
|
|
pTime - Pointer to a UUIDTIME 64bit system dependent time structure.
|
|
|
|
Return Value:
|
|
|
|
n/a
|
|
--*/
|
|
{
|
|
|
|
#ifdef NTENV
|
|
NTSTATUS Status;
|
|
Status = NtQuerySystemTime((LARGE_INTEGER *)pTime);
|
|
ASSERT( (Status == STATUS_SUCCESS) );
|
|
#endif
|
|
|
|
#ifdef DOSWIN32RPC
|
|
SYSTEMTIME SystemTime;
|
|
GetLocalTime(&SystemTime);
|
|
if (SystemTimeToFileTime(&SystemTime, (LPFILETIME)pTime) == FALSE)
|
|
{
|
|
#ifdef DEBUGRPC
|
|
PrintToDebugger("LastError: %d\n", GetLastError());
|
|
#endif
|
|
ASSERT(!"SystemTimeToFileTimeFailed")
|
|
}
|
|
#endif
|
|
|
|
// Win32 system time is based on 1-Jan-1601, and DCE wants time based
|
|
// on 15-Oct-1582. We add in an appropriate number of days worth ticks.
|
|
|
|
// 17 Days left in Oct, 30 (Nov), 31 (Dec), 18 years and 5 leap days.
|
|
|
|
pTime->QuadPart += (unsigned __int64) (1000 * 1000 * 10) // seconds
|
|
* (unsigned __int64) (60 * 60 * 24) // days
|
|
* (unsigned __int64) (17+30+31+365*18+5); // # of days
|
|
}
|
|
|
|
|
|
RPC_STATUS __RPC_API
|
|
LoadUuidValues(
|
|
OUT UUIDTIME __RPC_FAR *pTime,
|
|
OUT unsigned long __RPC_FAR *pClockSeq)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine loads the time and clock sequence stored in the registry.
|
|
|
|
Note: It is up to the caller to remember to call UuidCloseKeys() at some
|
|
point after this function returns.
|
|
|
|
Arguments:
|
|
|
|
pTime - Pointer to a UUIDTIME structure. It's value will be
|
|
loaded from the registry. If either the time or clock seq
|
|
is not in the registry, it is initalized to a maximum value.
|
|
|
|
pClockSeq - The clock sequence will be loaded from the registry. If
|
|
it does not exist in the registry it is initialized to a random
|
|
number _not_ based on the IEEE 802 address of the machine.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK - Everything went okay.
|
|
|
|
RPC_S_OUT_OF_MEMORY - An error occured and the parameters are not set.
|
|
|
|
--*/
|
|
{
|
|
RPC_STATUS Status;
|
|
DWORD Length;
|
|
|
|
// Assume we won't find the time.
|
|
pTime->LowPart = ~0UL;
|
|
pTime->HighPart = ~0UL;
|
|
|
|
if (OpenUuidKeysIfNecessary() == 0)
|
|
{
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
Length = sizeof(*pClockSeq);
|
|
Status =
|
|
RegQueryValueEx(PersistentKey,
|
|
(LPTSTR)CLOCK_SEQUENCE,
|
|
0,
|
|
0,
|
|
(LPBYTE)pClockSeq,
|
|
&Length);
|
|
|
|
if (Status == ERROR_FILE_NOT_FOUND || Status == ERROR_CANTREAD)
|
|
{
|
|
// The 14bit ClockSeq should start as a random number, as per the AES.
|
|
|
|
*pClockSeq = (((ULONG)&pClockSeq) ^ GetTickCount()) % (1<<14);
|
|
}
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Length = sizeof(*pTime);
|
|
Status =
|
|
RegQueryValueEx(PersistentKey,
|
|
(LPTSTR)LAST_TIME_ALLOCATED,
|
|
0,
|
|
0,
|
|
(LPBYTE)pTime,
|
|
&Length);
|
|
}
|
|
|
|
if (Status != ERROR_SUCCESS)
|
|
{
|
|
#ifdef DEBUGRPC
|
|
if (Status != ERROR_NOT_ENOUGH_MEMORY &&
|
|
Status != ERROR_OUTOFMEMORY &&
|
|
Status != ERROR_FILE_NOT_FOUND)
|
|
{
|
|
PrintToDebugger("RPC UUID: RegCreateKeyEx - %x\n", Status);
|
|
}
|
|
#endif
|
|
ASSERT( (Status == ERROR_OUTOFMEMORY)
|
|
|| (Status == ERROR_NOT_ENOUGH_MEMORY)
|
|
|| (Status == ERROR_CANTREAD)
|
|
|| (Status == ERROR_FILE_NOT_FOUND) );
|
|
|
|
if (!(Status == ERROR_FILE_NOT_FOUND || Status == ERROR_CANTREAD))
|
|
{
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
// Newly created key, just return OK with the 'max' value
|
|
}
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
RPC_STATUS __RPC_API
|
|
SaveUuidValues(
|
|
IN UUIDTIME __RPC_FAR *pTime,
|
|
IN unsigned long __RPC_FAR *pClockSeq)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine saves the time and clock sequence stored in the registry.
|
|
|
|
Note: This routine assumes the that Uuid keys have already been opened
|
|
and are valid.
|
|
|
|
Arguments:
|
|
|
|
pTime - Pointer to a UUIDTIME structure. It will be saved in the
|
|
registry in volatile storage.
|
|
|
|
pClockSeq - The clock sequence will be saved in the registry
|
|
is persistent stroage.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK - Values have been saved.
|
|
|
|
RPC_S_OUT_OF_MEMORY - All other errors.
|
|
|
|
--*/
|
|
{
|
|
RPC_STATUS Status;
|
|
|
|
ASSERT( PersistentKey
|
|
&& VolatileKey);
|
|
|
|
Status =
|
|
RegSetValueEx(PersistentKey,
|
|
(LPTSTR)CLOCK_SEQUENCE,
|
|
0,
|
|
REG_DWORD,
|
|
(LPBYTE)pClockSeq,
|
|
sizeof(*pClockSeq));
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status =
|
|
RegSetValueEx(PersistentKey,
|
|
(LPTSTR)LAST_TIME_ALLOCATED,
|
|
0,
|
|
REG_BINARY,
|
|
(LPBYTE)pTime,
|
|
sizeof(UUIDTIME) );
|
|
}
|
|
|
|
if (Status != ERROR_SUCCESS)
|
|
{
|
|
#ifdef DEBUGRPC
|
|
if (Status != ERROR_NOT_ENOUGH_MEMORY &&
|
|
Status != ERROR_OUTOFMEMORY)
|
|
{
|
|
PrintToDebugger("RPC UUID: RegCreateKeyEx - %x\n", Status);
|
|
}
|
|
#endif
|
|
ASSERT( (Status == ERROR_OUTOFMEMORY)
|
|
|| (Status == ERROR_NOT_ENOUGH_MEMORY) );
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
RPC_STATUS __RPC_API
|
|
UuidGetValues(
|
|
OUT UUID_CACHED_VALUES_STRUCT __RPC_FAR *Values
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine allocates a block of uuids for UuidCreate
|
|
to handout.
|
|
|
|
Note:
|
|
|
|
THIS ROUTINE SHOULD ONLY BE CALLED BY A SINGLE THREAD AT A TIME.
|
|
|
|
Arguments:
|
|
|
|
Values - Set to contain everything needed to allocate a block of uuids.
|
|
The following fields will be updated here:
|
|
|
|
NextTimeLow - Together with LastTimeLow, this denotes the boundaries
|
|
of a block of Uuids. The values between NextTimeLow
|
|
and LastTimeLow are used in a sequence of Uuids returned
|
|
by UuidCreate().
|
|
|
|
LastTimeLow - See NextTimeLow.
|
|
|
|
ClockSequence - Clock sequence field in the uuid. This is changed
|
|
when the clock is set backward.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK - We successfully allocated a block of uuids.
|
|
|
|
RPC_S_OUT_OF_MEMORY - As needed.
|
|
--*/
|
|
{
|
|
RPC_STATUS Status;
|
|
UUIDTIME currentTime;
|
|
UUIDTIME persistentTime;
|
|
unsigned long persistentClockSequence;
|
|
|
|
UuidTime(¤tTime);
|
|
|
|
Status =
|
|
LoadUuidValues(&persistentTime, &persistentClockSequence);
|
|
|
|
if (Status != RPC_S_OK)
|
|
{
|
|
CloseUuidKeys();
|
|
ASSERT(Status == RPC_S_OUT_OF_MEMORY);
|
|
return (RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
// Has the clock been set backwards?
|
|
|
|
if (currentTime.QuadPart < persistentTime.QuadPart)
|
|
{
|
|
persistentTime.QuadPart = currentTime.QuadPart;
|
|
persistentClockSequence++;
|
|
if (persistentClockSequence >= (1<<14))
|
|
persistentClockSequence = 0;
|
|
}
|
|
|
|
ASSERT(persistentClockSequence < (1<<14));
|
|
|
|
while (currentTime.QuadPart < persistentTime.QuadPart + 10)
|
|
{
|
|
// It hasn't even been a microsecond since the last block of
|
|
// uuids was allocated! This will normally only happen when the
|
|
// clock has been set backwards.
|
|
|
|
Sleep(0);
|
|
UuidTime(¤tTime);
|
|
}
|
|
|
|
// We'll use whatever the difference is between the currentTime
|
|
// and the persistentTime as the range to cache. If this is
|
|
// greater than one second, we'll only give out 1 second.
|
|
// This avoids problems with rebooting and running a different OS.
|
|
|
|
if (currentTime.QuadPart > persistentTime.QuadPart + 10000000)
|
|
{
|
|
persistentTime.QuadPart = currentTime.QuadPart - 10000000;
|
|
}
|
|
|
|
Values->NextTime.QuadPart = persistentTime.QuadPart;
|
|
Values->LastTime.QuadPart = currentTime.QuadPart;
|
|
Values->ClockSequence = (unsigned short)persistentClockSequence;
|
|
|
|
persistentTime.QuadPart = currentTime.QuadPart;
|
|
|
|
Status =
|
|
SaveUuidValues(&persistentTime,
|
|
&persistentClockSequence);
|
|
|
|
CloseUuidKeys();
|
|
|
|
if (Status != RPC_S_OK)
|
|
{
|
|
ASSERT(Status == RPC_S_OUT_OF_MEMORY);
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
ASSERT(Values->NextTime.QuadPart < Values->LastTime.QuadPart);
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
#endif // KERNEL_UUIDS
|
|
|
|
#ifdef KERNEL_UUIDS
|
|
RPC_STATUS __RPC_API
|
|
UuidGetValues(
|
|
OUT UUID_CACHED_VALUES_STRUCT __RPC_FAR *Values
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine allocates a block of uuids for UuidCreate to handout.
|
|
|
|
Arguments:
|
|
|
|
Values - Set to contain everything needed to allocate a block of uuids.
|
|
The following fields will be updated here:
|
|
|
|
NextTimeLow - Together with LastTimeLow, this denotes the boundaries
|
|
of a block of Uuids. The values between NextTimeLow
|
|
and LastTimeLow are used in a sequence of Uuids returned
|
|
by UuidCreate().
|
|
|
|
LastTimeLow - See NextTimeLow.
|
|
|
|
ClockSequence - Clock sequence field in the uuid. This is changed
|
|
when the clock is set backward.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK - We successfully allocated a block of uuids.
|
|
|
|
RPC_S_OUT_OF_MEMORY - As needed.
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus;
|
|
ULARGE_INTEGER Time;
|
|
ULONG Range;
|
|
ULONG Sequence;
|
|
int Tries = 0;
|
|
|
|
CloseUuidKeys();
|
|
|
|
do {
|
|
NtStatus = NtAllocateUuids(&Time, &Range, &Sequence);
|
|
|
|
if (NtStatus == STATUS_RETRY)
|
|
{
|
|
Sleep(1);
|
|
}
|
|
|
|
Tries++;
|
|
|
|
if (Tries == 20)
|
|
{
|
|
#ifdef DEBUGRPC
|
|
PrintToDebugger("Rpc: NtAllocateUuids retried 20 times!\n");
|
|
ASSERT(Tries < 20);
|
|
#endif
|
|
NtStatus = STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
} while(NtStatus == STATUS_RETRY);
|
|
|
|
if (!NT_SUCCESS(NtStatus))
|
|
{
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
// NtAllocateUuids keeps time in SYSTEM_TIME format which is 100ns ticks since
|
|
// Jan 1, 1601. UUIDs use time in 100ns ticks since Oct 15, 1582.
|
|
|
|
// 17 Days in Oct + 30 (Nov) + 31 (Dec) + 18 years and 5 leap days.
|
|
|
|
Time.QuadPart += (unsigned __int64) (1000*1000*10) // seconds
|
|
* (unsigned __int64) (60 * 60 * 24) // days
|
|
* (unsigned __int64) (17+30+31+365*18+5); // # of days
|
|
|
|
ASSERT(Range);
|
|
|
|
Values->NextTime.QuadPart = Time.QuadPart;
|
|
Values->LastTime.QuadPart = Time.QuadPart + (Range - 1);
|
|
Values->ClockSequence = (unsigned short)(Sequence & 0x3FFFUL);
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
#endif // KERNEL_UUIDS
|