597 lines
13 KiB
C++
597 lines
13 KiB
C++
|
/*++
|
|||
|
|
|||
|
Copyright (C) Microsoft Corporation, 1992 - 1999
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
dceuuid.cxx
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module contains the entry points for routines dealing with
|
|||
|
UUIDs. In particular, UuidCreate lives here.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Michael Montague (mikemon) 16-Jan-1992
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
Dave Steckler (davidst) 31-Mar-1992
|
|||
|
If NT, remote call to UuidGetValues.
|
|||
|
|
|||
|
Mario Goertzel (mariogo) 1-May-1994
|
|||
|
Added the rest of the DCE UUID APIs
|
|||
|
|
|||
|
Mario Goertzel (mariogo) 18-May-1994
|
|||
|
Changed algorithm and implementation. No longer based on RPC.
|
|||
|
Platform specific functions in uuidsup.cxx (win32) and
|
|||
|
dos\uuid16 (dos/win16).
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
|
|||
|
#include <precomp.hxx>
|
|||
|
#include <uuidsup.hxx>
|
|||
|
#include <rc4.h>
|
|||
|
#include <randlib.h>
|
|||
|
#include <crypt.h>
|
|||
|
|
|||
|
// Contain a cached block of uuids to reduce the
|
|||
|
// average cost of creating a uuid.
|
|||
|
|
|||
|
UUID_CACHED_VALUES_STRUCT UuidCachedValues;
|
|||
|
|
|||
|
#define CACHE_VALID 1
|
|||
|
#define CACHE_LOCAL_ONLY 2 // -> CACHE_VALID
|
|||
|
static unsigned char UuidCacheValid = CACHE_LOCAL_ONLY;
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS RPC_ENTRY
|
|||
|
I_UuidCreate(
|
|||
|
OUT UUID PAPI * Uuid
|
|||
|
)
|
|||
|
/*++
|
|||
|
Historically this function was used for cheap sometimes unique
|
|||
|
uuid's for context handles and such. Now it's just a wrapper
|
|||
|
for UuidCreate.
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_STATUS Status = UuidCreateSequential (Uuid);
|
|||
|
if (Status == RPC_S_UUID_LOCAL_ONLY)
|
|||
|
return(RPC_S_OK);
|
|||
|
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
#define RC4_REKEY_PARAM (500000)
|
|||
|
extern void *g_rc4SafeCtx;
|
|||
|
|
|||
|
RPC_STATUS GenerateRandomNumber(unsigned char *Buffer, int BufferSize)
|
|||
|
{
|
|||
|
unsigned int KeyEntry;
|
|||
|
unsigned int KeyBytesUsed = 0;
|
|||
|
|
|||
|
rc4_safe_select(g_rc4SafeCtx, &KeyEntry, &KeyBytesUsed);
|
|||
|
|
|||
|
if (KeyBytesUsed >= RC4_REKEY_PARAM)
|
|||
|
{
|
|||
|
BYTE newSeed[256];
|
|||
|
|
|||
|
if (!RtlGenRandom (newSeed, sizeof(newSeed)))
|
|||
|
{
|
|||
|
return RPC_S_OUT_OF_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
rc4_safe_key(g_rc4SafeCtx, KeyEntry, sizeof(newSeed), newSeed);
|
|||
|
}
|
|||
|
|
|||
|
// the rc4_safe fucntion is thread safe
|
|||
|
rc4_safe(g_rc4SafeCtx, KeyEntry, BufferSize, Buffer);
|
|||
|
|
|||
|
return RPC_S_OK;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS RPC_ENTRY
|
|||
|
UuidCreate (
|
|||
|
OUT UUID PAPI * Uuid
|
|||
|
)
|
|||
|
{
|
|||
|
RPC_STATUS RpcStatus;
|
|||
|
RPC_UUID_GENERATE PAPI * RpcUuid = (RPC_UUID_GENERATE PAPI *) Uuid;
|
|||
|
|
|||
|
RpcStatus = GenerateRandomNumber((unsigned char *)Uuid, 16);
|
|||
|
if (RpcStatus != RPC_S_OK)
|
|||
|
return RpcStatus;
|
|||
|
|
|||
|
// Overwriting some bits of the uuid
|
|||
|
RpcUuid->TimeHiAndVersion =
|
|||
|
(RpcUuid->TimeHiAndVersion & RPC_UUID_TIME_HIGH_MASK) | RPC_RAND_UUID_VERSION;
|
|||
|
RpcUuid->ClockSeqHiAndReserved =
|
|||
|
(RpcUuid->ClockSeqHiAndReserved & RPC_UUID_CLOCK_SEQ_HI_MASK) | RPC_UUID_RESERVED;
|
|||
|
|
|||
|
return RPC_S_OK;
|
|||
|
}
|
|||
|
|
|||
|
#define MAX_CACHED_UUID_TIME 10000 // 10 seconds
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS RPC_ENTRY
|
|||
|
UuidCreateSequential (
|
|||
|
OUT UUID PAPI * Uuid
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine will create a new UUID (or GUID) which is unique in
|
|||
|
time and space. We will try to guarantee that the UUID (or GUID)
|
|||
|
we generate is unique in time and space. This means that this
|
|||
|
routine may fail if we can not generate one which we can guarantee
|
|||
|
is unique in time and space.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Uuid - Returns the generated UUID (or GUID).
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - The operation completed successfully.
|
|||
|
|
|||
|
RPC_S_UUID_NO_ADDRESS - We were unable to obtain the ethernet or
|
|||
|
token ring address for this machine.
|
|||
|
|
|||
|
RPC_S_UUID_LOCAL_ONLY - On NT & Chicago if we can't get a
|
|||
|
network address. This is a warning to the user, the
|
|||
|
UUID is still valid, it just may not be unique on other machines.
|
|||
|
|
|||
|
RPC_S_OUT_OF_MEMORY - Returned as needed.
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_UUID_GENERATE PAPI * RpcUuid = (RPC_UUID_GENERATE PAPI *) Uuid;
|
|||
|
RPC_STATUS Status = RPC_S_OK;
|
|||
|
static DWORD LastTickCount = 0;
|
|||
|
|
|||
|
InitializeIfNecessary();
|
|||
|
|
|||
|
if (GetTickCount()-LastTickCount > MAX_CACHED_UUID_TIME)
|
|||
|
{
|
|||
|
UuidCachedValues.AllocatedCount = 0;
|
|||
|
LastTickCount = GetTickCount();
|
|||
|
}
|
|||
|
|
|||
|
ULARGE_INTEGER Time;
|
|||
|
long Delta;
|
|||
|
|
|||
|
for(;;)
|
|||
|
{
|
|||
|
Time.QuadPart = UuidCachedValues.Time.QuadPart;
|
|||
|
|
|||
|
// Copy the static info into the UUID. We can't do this later
|
|||
|
// because the clock sequence could be updated by another thread.
|
|||
|
|
|||
|
*(unsigned long *)&RpcUuid->ClockSeqHiAndReserved =
|
|||
|
*(unsigned long *)&UuidCachedValues.ClockSeqHiAndReserved;
|
|||
|
*(unsigned long *)&RpcUuid->NodeId[2] =
|
|||
|
*(unsigned long *)&UuidCachedValues.NodeId[2];
|
|||
|
|
|||
|
Delta = InterlockedDecrement(&UuidCachedValues.AllocatedCount);
|
|||
|
|
|||
|
if (Time.QuadPart != UuidCachedValues.Time.QuadPart)
|
|||
|
{
|
|||
|
// If our captured time doesn't match the cache then another
|
|||
|
// thread already took the lock and updated the cache. We'll
|
|||
|
// just loop and try again.
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
if (Delta >= 0)
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Allocate block of Uuids.
|
|||
|
//
|
|||
|
|
|||
|
Status = UuidGetValues( &UuidCachedValues );
|
|||
|
if (Status == RPC_S_OK)
|
|||
|
{
|
|||
|
UuidCacheValid = CACHE_VALID;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
UuidCacheValid = CACHE_LOCAL_ONLY;
|
|||
|
}
|
|||
|
|
|||
|
if (Status != RPC_S_OK
|
|||
|
&& Status != RPC_S_UUID_LOCAL_ONLY)
|
|||
|
{
|
|||
|
#ifdef DEBUGRPC
|
|||
|
if (Status != RPC_S_OUT_OF_MEMORY)
|
|||
|
PrintToDebugger("RPC: UuidGetValues returned or raised: %x\n", Status);
|
|||
|
#endif
|
|||
|
ASSERT( (Status == RPC_S_OUT_OF_MEMORY) );
|
|||
|
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
// Loop
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
Time.QuadPart -= Delta;
|
|||
|
|
|||
|
RpcUuid->TimeLow = (unsigned long) Time.LowPart;
|
|||
|
RpcUuid->TimeMid = (unsigned short) (Time.HighPart & 0x0000FFFF);
|
|||
|
RpcUuid->TimeHiAndVersion = (unsigned short)
|
|||
|
(( (unsigned short)(Time.HighPart >> 16)
|
|||
|
& RPC_UUID_TIME_HIGH_MASK) | RPC_UUID_VERSION);
|
|||
|
|
|||
|
ASSERT( Status == RPC_S_OK
|
|||
|
|| Status == RPC_S_UUID_LOCAL_ONLY);
|
|||
|
|
|||
|
if (UuidCacheValid == CACHE_LOCAL_ONLY)
|
|||
|
{
|
|||
|
return RPC_S_UUID_LOCAL_ONLY;
|
|||
|
}
|
|||
|
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
RPC_STATUS RPC_ENTRY
|
|||
|
UuidToString (
|
|||
|
IN UUID PAPI * Uuid,
|
|||
|
OUT unsigned short PAPI * PAPI * StringUuid
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine converts a UUID into its string representation.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Uuid - Supplies the UUID to be converted into string representation.
|
|||
|
|
|||
|
StringUuid - Returns the string representation of the UUID. The
|
|||
|
runtime will allocate the string. The caller is responsible for
|
|||
|
freeing the string using RpcStringFree.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - We successfully converted the UUID into its string
|
|||
|
representation.
|
|||
|
|
|||
|
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to allocate
|
|||
|
a string.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_CHAR PAPI * String;
|
|||
|
|
|||
|
InitializeIfNecessary();
|
|||
|
|
|||
|
// The string representation of a UUID is always 36 character long,
|
|||
|
// and we need one more for the terminating zero.
|
|||
|
|
|||
|
*StringUuid = (RPC_CHAR PAPI *) RpcpFarAllocate(sizeof(RPC_CHAR) * 37);
|
|||
|
if ( *StringUuid == 0 )
|
|||
|
{
|
|||
|
return(RPC_S_OUT_OF_MEMORY);
|
|||
|
}
|
|||
|
String = ((RPC_UUID PAPI *) Uuid)->ConvertToString(*StringUuid);
|
|||
|
*String = 0;
|
|||
|
|
|||
|
return(RPC_S_OK);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS RPC_ENTRY
|
|||
|
UuidFromString (
|
|||
|
IN unsigned short PAPI * StringUuid OPTIONAL,
|
|||
|
OUT UUID PAPI * Uuid
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
We convert a UUID from its string representation into the binary
|
|||
|
representation.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
StringUuid - Optionally supplies the string representation of the UUID;
|
|||
|
if the string is not supplied, then the Uuid is set to the NIL UUID.
|
|||
|
|
|||
|
Uuid - Returns the binary representation of the UUID.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - The string representation was successfully converted into
|
|||
|
the binary representation.
|
|||
|
|
|||
|
RPC_S_INVALID_STRING_UUID - The supplied string UUID is not correct.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_UUID RpcUuid;
|
|||
|
|
|||
|
if ( StringUuid == 0 )
|
|||
|
{
|
|||
|
((RPC_UUID PAPI *) Uuid)->SetToNullUuid();
|
|||
|
return(RPC_S_OK);
|
|||
|
}
|
|||
|
|
|||
|
if ( RpcUuid.ConvertFromString(StringUuid) != 0)
|
|||
|
{
|
|||
|
return(RPC_S_INVALID_STRING_UUID);
|
|||
|
}
|
|||
|
((RPC_UUID PAPI *) Uuid)->CopyUuid(&RpcUuid);
|
|||
|
return(RPC_S_OK);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
signed int RPC_ENTRY
|
|||
|
UuidCompare (
|
|||
|
IN UUID __RPC_FAR * Uuid1,
|
|||
|
IN UUID __RPC_FAR * Uuid2,
|
|||
|
OUT RPC_STATUS __RPC_FAR * Status
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
The supplied uuids are compared and their order is determined.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Uuid1, Uuid2 - Supplies the uuids to be compared. A value of NULL can
|
|||
|
be supplied to indicate the nil uuid.
|
|||
|
|
|||
|
Status - The status of the function. Currently always RPC_S_OK.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Returns the result of the comparison. Negative one (-1) will be returned
|
|||
|
if Uuid1 precedes Uuid2 in order, zero will be returned if Uuid1 is equal
|
|||
|
to Uuid2, and positive one (1) will be returned if Uuid1 follows Uuid2 in
|
|||
|
order. A nil uuid is the first uuid in order.
|
|||
|
|
|||
|
Note:
|
|||
|
|
|||
|
The algorithm for comparing uuids is specified by the DCE RPC Architecture.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
int Uuid1Nil, Uuid2Nil;
|
|||
|
RPC_STATUS RpcStatus;
|
|||
|
|
|||
|
Uuid1Nil = UuidIsNil(Uuid1, &RpcStatus);
|
|||
|
ASSERT(RpcStatus == RPC_S_OK);
|
|||
|
|
|||
|
Uuid2Nil = UuidIsNil(Uuid2, &RpcStatus);
|
|||
|
ASSERT(RpcStatus == RPC_S_OK);
|
|||
|
|
|||
|
*Status = RPC_S_OK;
|
|||
|
|
|||
|
if ( Uuid1Nil != 0 )
|
|||
|
{
|
|||
|
// Uuid1 is the nil uuid.
|
|||
|
|
|||
|
if ( Uuid2Nil != 0 )
|
|||
|
{
|
|||
|
// Uuid2 is the nil uuid.
|
|||
|
|
|||
|
return(0);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return(-1);
|
|||
|
}
|
|||
|
}
|
|||
|
else if ( Uuid2Nil != 0 )
|
|||
|
{
|
|||
|
// Uuid2 is the nil uuid.
|
|||
|
|
|||
|
return(1);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if ( Uuid1->Data1 == Uuid2->Data1 )
|
|||
|
{
|
|||
|
if ( Uuid1->Data2 == Uuid2->Data2 )
|
|||
|
{
|
|||
|
if ( Uuid1->Data3 == Uuid2->Data3 )
|
|||
|
{
|
|||
|
int compare = RpcpMemoryCompare(&Uuid1->Data4[0],
|
|||
|
&Uuid2->Data4[0],
|
|||
|
8);
|
|||
|
if (compare > 0)
|
|||
|
{
|
|||
|
return(1);
|
|||
|
}
|
|||
|
else if (compare < 0 )
|
|||
|
{
|
|||
|
return(-1);
|
|||
|
}
|
|||
|
return(0);
|
|||
|
}
|
|||
|
else if ( Uuid1->Data3 > Uuid2->Data3 )
|
|||
|
{
|
|||
|
return(1);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return(-1);
|
|||
|
}
|
|||
|
}
|
|||
|
else if ( Uuid1->Data2 > Uuid2->Data2 )
|
|||
|
{
|
|||
|
return(1);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return(-1);
|
|||
|
}
|
|||
|
}
|
|||
|
else if ( Uuid1->Data1 > Uuid2->Data1 )
|
|||
|
{
|
|||
|
return(1);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return(-1);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ASSERT(!"This is not reached");
|
|||
|
return(1);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS RPC_ENTRY
|
|||
|
UuidCreateNil (
|
|||
|
OUT UUID __RPC_FAR * NilUuid
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
NilUuid - Returns a nil uuid.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
((RPC_UUID __RPC_FAR *)NilUuid)->SetToNullUuid();
|
|||
|
|
|||
|
return(RPC_S_OK);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
int RPC_ENTRY
|
|||
|
UuidEqual (
|
|||
|
IN UUID __RPC_FAR * Uuid1,
|
|||
|
IN UUID __RPC_FAR * Uuid2,
|
|||
|
OUT RPC_STATUS __RPC_FAR * Status
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is used to determine if two uuids are equal.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Uuid1, Uuid2 - Supplies the uuids to compared for equality. A value of
|
|||
|
NULL can be supplied to indicate the nil uuid.
|
|||
|
|
|||
|
Status - Will always be set to RPC_S_OK.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Returns non-zero if Uuid1 equals Uuid2; otherwise, zero will be
|
|||
|
returned.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
*Status = RPC_S_OK;
|
|||
|
|
|||
|
if (Uuid1 == 0)
|
|||
|
{
|
|||
|
if ( (Uuid2 == 0)
|
|||
|
|| ((RPC_UUID __RPC_FAR *)Uuid2)->IsNullUuid())
|
|||
|
{
|
|||
|
return 1;
|
|||
|
}
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
if (Uuid2 == 0)
|
|||
|
{
|
|||
|
if (((RPC_UUID __RPC_FAR *)Uuid1)->IsNullUuid())
|
|||
|
{
|
|||
|
return 1;
|
|||
|
}
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
return( ((RPC_UUID __RPC_FAR *)Uuid1)->MatchUuid(
|
|||
|
(RPC_UUID __RPC_FAR *)Uuid2)
|
|||
|
== 0 );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
unsigned short RPC_ENTRY
|
|||
|
UuidHash (
|
|||
|
IN UUID __RPC_FAR * Uuid,
|
|||
|
OUT RPC_STATUS __RPC_FAR * Status
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
An application will use this routine to create a hash value for a uuid.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Uuid - Supplies the uuid for which we want to create a hash value. A
|
|||
|
value of NULL can be supplied to indicate the nil uuid.
|
|||
|
|
|||
|
Status - Will always be set to RPC_S_OK.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Returns the hash value.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
*Status = RPC_S_OK;
|
|||
|
|
|||
|
if ( Uuid == 0 )
|
|||
|
{
|
|||
|
return(0);
|
|||
|
}
|
|||
|
|
|||
|
return( ((RPC_UUID __RPC_FAR *)Uuid)->HashUuid() );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
int RPC_ENTRY
|
|||
|
UuidIsNil (
|
|||
|
IN UUID __RPC_FAR * Uuid,
|
|||
|
OUT RPC_STATUS __RPC_FAR * Status
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
We will determine if the supplied uuid is the nil uuid or not.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Uuid - Supplies the uuid to check. A value of NULL indicates the nil
|
|||
|
uuid.
|
|||
|
|
|||
|
Status - This will always be RPC_S_OK.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Returns non-zero if the supplied uuid is the nil uuid; otherwise, zero
|
|||
|
will be returned.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
*Status = RPC_S_OK;
|
|||
|
|
|||
|
if ( Uuid == 0 )
|
|||
|
{
|
|||
|
return(1);
|
|||
|
}
|
|||
|
|
|||
|
return ( ((RPC_UUID __RPC_FAR *) Uuid)->IsNullUuid() );
|
|||
|
}
|
|||
|
|