Source code of Windows XP (NT5)
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.

596 lines
13 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1992 - 1999
  3. Module Name:
  4. dceuuid.cxx
  5. Abstract:
  6. This module contains the entry points for routines dealing with
  7. UUIDs. In particular, UuidCreate lives here.
  8. Author:
  9. Michael Montague (mikemon) 16-Jan-1992
  10. Revision History:
  11. Dave Steckler (davidst) 31-Mar-1992
  12. If NT, remote call to UuidGetValues.
  13. Mario Goertzel (mariogo) 1-May-1994
  14. Added the rest of the DCE UUID APIs
  15. Mario Goertzel (mariogo) 18-May-1994
  16. Changed algorithm and implementation. No longer based on RPC.
  17. Platform specific functions in uuidsup.cxx (win32) and
  18. dos\uuid16 (dos/win16).
  19. --*/
  20. #include <precomp.hxx>
  21. #include <uuidsup.hxx>
  22. #include <rc4.h>
  23. #include <randlib.h>
  24. #include <crypt.h>
  25. // Contain a cached block of uuids to reduce the
  26. // average cost of creating a uuid.
  27. UUID_CACHED_VALUES_STRUCT UuidCachedValues;
  28. #define CACHE_VALID 1
  29. #define CACHE_LOCAL_ONLY 2 // -> CACHE_VALID
  30. static unsigned char UuidCacheValid = CACHE_LOCAL_ONLY;
  31. RPC_STATUS RPC_ENTRY
  32. I_UuidCreate(
  33. OUT UUID PAPI * Uuid
  34. )
  35. /*++
  36. Historically this function was used for cheap sometimes unique
  37. uuid's for context handles and such. Now it's just a wrapper
  38. for UuidCreate.
  39. --*/
  40. {
  41. RPC_STATUS Status = UuidCreateSequential (Uuid);
  42. if (Status == RPC_S_UUID_LOCAL_ONLY)
  43. return(RPC_S_OK);
  44. return(Status);
  45. }
  46. #define RC4_REKEY_PARAM (500000)
  47. extern void *g_rc4SafeCtx;
  48. RPC_STATUS GenerateRandomNumber(unsigned char *Buffer, int BufferSize)
  49. {
  50. unsigned int KeyEntry;
  51. unsigned int KeyBytesUsed = 0;
  52. rc4_safe_select(g_rc4SafeCtx, &KeyEntry, &KeyBytesUsed);
  53. if (KeyBytesUsed >= RC4_REKEY_PARAM)
  54. {
  55. BYTE newSeed[256];
  56. if (!RtlGenRandom (newSeed, sizeof(newSeed)))
  57. {
  58. return RPC_S_OUT_OF_MEMORY;
  59. }
  60. rc4_safe_key(g_rc4SafeCtx, KeyEntry, sizeof(newSeed), newSeed);
  61. }
  62. // the rc4_safe fucntion is thread safe
  63. rc4_safe(g_rc4SafeCtx, KeyEntry, BufferSize, Buffer);
  64. return RPC_S_OK;
  65. }
  66. RPC_STATUS RPC_ENTRY
  67. UuidCreate (
  68. OUT UUID PAPI * Uuid
  69. )
  70. {
  71. RPC_STATUS RpcStatus;
  72. RPC_UUID_GENERATE PAPI * RpcUuid = (RPC_UUID_GENERATE PAPI *) Uuid;
  73. RpcStatus = GenerateRandomNumber((unsigned char *)Uuid, 16);
  74. if (RpcStatus != RPC_S_OK)
  75. return RpcStatus;
  76. // Overwriting some bits of the uuid
  77. RpcUuid->TimeHiAndVersion =
  78. (RpcUuid->TimeHiAndVersion & RPC_UUID_TIME_HIGH_MASK) | RPC_RAND_UUID_VERSION;
  79. RpcUuid->ClockSeqHiAndReserved =
  80. (RpcUuid->ClockSeqHiAndReserved & RPC_UUID_CLOCK_SEQ_HI_MASK) | RPC_UUID_RESERVED;
  81. return RPC_S_OK;
  82. }
  83. #define MAX_CACHED_UUID_TIME 10000 // 10 seconds
  84. RPC_STATUS RPC_ENTRY
  85. UuidCreateSequential (
  86. OUT UUID PAPI * Uuid
  87. )
  88. /*++
  89. Routine Description:
  90. This routine will create a new UUID (or GUID) which is unique in
  91. time and space. We will try to guarantee that the UUID (or GUID)
  92. we generate is unique in time and space. This means that this
  93. routine may fail if we can not generate one which we can guarantee
  94. is unique in time and space.
  95. Arguments:
  96. Uuid - Returns the generated UUID (or GUID).
  97. Return Value:
  98. RPC_S_OK - The operation completed successfully.
  99. RPC_S_UUID_NO_ADDRESS - We were unable to obtain the ethernet or
  100. token ring address for this machine.
  101. RPC_S_UUID_LOCAL_ONLY - On NT & Chicago if we can't get a
  102. network address. This is a warning to the user, the
  103. UUID is still valid, it just may not be unique on other machines.
  104. RPC_S_OUT_OF_MEMORY - Returned as needed.
  105. --*/
  106. {
  107. RPC_UUID_GENERATE PAPI * RpcUuid = (RPC_UUID_GENERATE PAPI *) Uuid;
  108. RPC_STATUS Status = RPC_S_OK;
  109. static DWORD LastTickCount = 0;
  110. InitializeIfNecessary();
  111. if (GetTickCount()-LastTickCount > MAX_CACHED_UUID_TIME)
  112. {
  113. UuidCachedValues.AllocatedCount = 0;
  114. LastTickCount = GetTickCount();
  115. }
  116. ULARGE_INTEGER Time;
  117. long Delta;
  118. for(;;)
  119. {
  120. Time.QuadPart = UuidCachedValues.Time.QuadPart;
  121. // Copy the static info into the UUID. We can't do this later
  122. // because the clock sequence could be updated by another thread.
  123. *(unsigned long *)&RpcUuid->ClockSeqHiAndReserved =
  124. *(unsigned long *)&UuidCachedValues.ClockSeqHiAndReserved;
  125. *(unsigned long *)&RpcUuid->NodeId[2] =
  126. *(unsigned long *)&UuidCachedValues.NodeId[2];
  127. Delta = InterlockedDecrement(&UuidCachedValues.AllocatedCount);
  128. if (Time.QuadPart != UuidCachedValues.Time.QuadPart)
  129. {
  130. // If our captured time doesn't match the cache then another
  131. // thread already took the lock and updated the cache. We'll
  132. // just loop and try again.
  133. continue;
  134. }
  135. if (Delta >= 0)
  136. {
  137. break;
  138. }
  139. //
  140. // Allocate block of Uuids.
  141. //
  142. Status = UuidGetValues( &UuidCachedValues );
  143. if (Status == RPC_S_OK)
  144. {
  145. UuidCacheValid = CACHE_VALID;
  146. }
  147. else
  148. {
  149. UuidCacheValid = CACHE_LOCAL_ONLY;
  150. }
  151. if (Status != RPC_S_OK
  152. && Status != RPC_S_UUID_LOCAL_ONLY)
  153. {
  154. #ifdef DEBUGRPC
  155. if (Status != RPC_S_OUT_OF_MEMORY)
  156. PrintToDebugger("RPC: UuidGetValues returned or raised: %x\n", Status);
  157. #endif
  158. ASSERT( (Status == RPC_S_OUT_OF_MEMORY) );
  159. return Status;
  160. }
  161. // Loop
  162. }
  163. Time.QuadPart -= Delta;
  164. RpcUuid->TimeLow = (unsigned long) Time.LowPart;
  165. RpcUuid->TimeMid = (unsigned short) (Time.HighPart & 0x0000FFFF);
  166. RpcUuid->TimeHiAndVersion = (unsigned short)
  167. (( (unsigned short)(Time.HighPart >> 16)
  168. & RPC_UUID_TIME_HIGH_MASK) | RPC_UUID_VERSION);
  169. ASSERT( Status == RPC_S_OK
  170. || Status == RPC_S_UUID_LOCAL_ONLY);
  171. if (UuidCacheValid == CACHE_LOCAL_ONLY)
  172. {
  173. return RPC_S_UUID_LOCAL_ONLY;
  174. }
  175. return(Status);
  176. }
  177. RPC_STATUS RPC_ENTRY
  178. UuidToString (
  179. IN UUID PAPI * Uuid,
  180. OUT unsigned short PAPI * PAPI * StringUuid
  181. )
  182. /*++
  183. Routine Description:
  184. This routine converts a UUID into its string representation.
  185. Arguments:
  186. Uuid - Supplies the UUID to be converted into string representation.
  187. StringUuid - Returns the string representation of the UUID. The
  188. runtime will allocate the string. The caller is responsible for
  189. freeing the string using RpcStringFree.
  190. Return Value:
  191. RPC_S_OK - We successfully converted the UUID into its string
  192. representation.
  193. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to allocate
  194. a string.
  195. --*/
  196. {
  197. RPC_CHAR PAPI * String;
  198. InitializeIfNecessary();
  199. // The string representation of a UUID is always 36 character long,
  200. // and we need one more for the terminating zero.
  201. *StringUuid = (RPC_CHAR PAPI *) RpcpFarAllocate(sizeof(RPC_CHAR) * 37);
  202. if ( *StringUuid == 0 )
  203. {
  204. return(RPC_S_OUT_OF_MEMORY);
  205. }
  206. String = ((RPC_UUID PAPI *) Uuid)->ConvertToString(*StringUuid);
  207. *String = 0;
  208. return(RPC_S_OK);
  209. }
  210. RPC_STATUS RPC_ENTRY
  211. UuidFromString (
  212. IN unsigned short PAPI * StringUuid OPTIONAL,
  213. OUT UUID PAPI * Uuid
  214. )
  215. /*++
  216. Routine Description:
  217. We convert a UUID from its string representation into the binary
  218. representation.
  219. Arguments:
  220. StringUuid - Optionally supplies the string representation of the UUID;
  221. if the string is not supplied, then the Uuid is set to the NIL UUID.
  222. Uuid - Returns the binary representation of the UUID.
  223. Return Value:
  224. RPC_S_OK - The string representation was successfully converted into
  225. the binary representation.
  226. RPC_S_INVALID_STRING_UUID - The supplied string UUID is not correct.
  227. --*/
  228. {
  229. RPC_UUID RpcUuid;
  230. if ( StringUuid == 0 )
  231. {
  232. ((RPC_UUID PAPI *) Uuid)->SetToNullUuid();
  233. return(RPC_S_OK);
  234. }
  235. if ( RpcUuid.ConvertFromString(StringUuid) != 0)
  236. {
  237. return(RPC_S_INVALID_STRING_UUID);
  238. }
  239. ((RPC_UUID PAPI *) Uuid)->CopyUuid(&RpcUuid);
  240. return(RPC_S_OK);
  241. }
  242. signed int RPC_ENTRY
  243. UuidCompare (
  244. IN UUID __RPC_FAR * Uuid1,
  245. IN UUID __RPC_FAR * Uuid2,
  246. OUT RPC_STATUS __RPC_FAR * Status
  247. )
  248. /*++
  249. Routine Description:
  250. The supplied uuids are compared and their order is determined.
  251. Arguments:
  252. Uuid1, Uuid2 - Supplies the uuids to be compared. A value of NULL can
  253. be supplied to indicate the nil uuid.
  254. Status - The status of the function. Currently always RPC_S_OK.
  255. Return Value:
  256. Returns the result of the comparison. Negative one (-1) will be returned
  257. if Uuid1 precedes Uuid2 in order, zero will be returned if Uuid1 is equal
  258. to Uuid2, and positive one (1) will be returned if Uuid1 follows Uuid2 in
  259. order. A nil uuid is the first uuid in order.
  260. Note:
  261. The algorithm for comparing uuids is specified by the DCE RPC Architecture.
  262. --*/
  263. {
  264. int Uuid1Nil, Uuid2Nil;
  265. RPC_STATUS RpcStatus;
  266. Uuid1Nil = UuidIsNil(Uuid1, &RpcStatus);
  267. ASSERT(RpcStatus == RPC_S_OK);
  268. Uuid2Nil = UuidIsNil(Uuid2, &RpcStatus);
  269. ASSERT(RpcStatus == RPC_S_OK);
  270. *Status = RPC_S_OK;
  271. if ( Uuid1Nil != 0 )
  272. {
  273. // Uuid1 is the nil uuid.
  274. if ( Uuid2Nil != 0 )
  275. {
  276. // Uuid2 is the nil uuid.
  277. return(0);
  278. }
  279. else
  280. {
  281. return(-1);
  282. }
  283. }
  284. else if ( Uuid2Nil != 0 )
  285. {
  286. // Uuid2 is the nil uuid.
  287. return(1);
  288. }
  289. else
  290. {
  291. if ( Uuid1->Data1 == Uuid2->Data1 )
  292. {
  293. if ( Uuid1->Data2 == Uuid2->Data2 )
  294. {
  295. if ( Uuid1->Data3 == Uuid2->Data3 )
  296. {
  297. int compare = RpcpMemoryCompare(&Uuid1->Data4[0],
  298. &Uuid2->Data4[0],
  299. 8);
  300. if (compare > 0)
  301. {
  302. return(1);
  303. }
  304. else if (compare < 0 )
  305. {
  306. return(-1);
  307. }
  308. return(0);
  309. }
  310. else if ( Uuid1->Data3 > Uuid2->Data3 )
  311. {
  312. return(1);
  313. }
  314. else
  315. {
  316. return(-1);
  317. }
  318. }
  319. else if ( Uuid1->Data2 > Uuid2->Data2 )
  320. {
  321. return(1);
  322. }
  323. else
  324. {
  325. return(-1);
  326. }
  327. }
  328. else if ( Uuid1->Data1 > Uuid2->Data1 )
  329. {
  330. return(1);
  331. }
  332. else
  333. {
  334. return(-1);
  335. }
  336. }
  337. ASSERT(!"This is not reached");
  338. return(1);
  339. }
  340. RPC_STATUS RPC_ENTRY
  341. UuidCreateNil (
  342. OUT UUID __RPC_FAR * NilUuid
  343. )
  344. /*++
  345. Arguments:
  346. NilUuid - Returns a nil uuid.
  347. --*/
  348. {
  349. ((RPC_UUID __RPC_FAR *)NilUuid)->SetToNullUuid();
  350. return(RPC_S_OK);
  351. }
  352. int RPC_ENTRY
  353. UuidEqual (
  354. IN UUID __RPC_FAR * Uuid1,
  355. IN UUID __RPC_FAR * Uuid2,
  356. OUT RPC_STATUS __RPC_FAR * Status
  357. )
  358. /*++
  359. Routine Description:
  360. This routine is used to determine if two uuids are equal.
  361. Arguments:
  362. Uuid1, Uuid2 - Supplies the uuids to compared for equality. A value of
  363. NULL can be supplied to indicate the nil uuid.
  364. Status - Will always be set to RPC_S_OK.
  365. Return Value:
  366. Returns non-zero if Uuid1 equals Uuid2; otherwise, zero will be
  367. returned.
  368. --*/
  369. {
  370. *Status = RPC_S_OK;
  371. if (Uuid1 == 0)
  372. {
  373. if ( (Uuid2 == 0)
  374. || ((RPC_UUID __RPC_FAR *)Uuid2)->IsNullUuid())
  375. {
  376. return 1;
  377. }
  378. return 0;
  379. }
  380. if (Uuid2 == 0)
  381. {
  382. if (((RPC_UUID __RPC_FAR *)Uuid1)->IsNullUuid())
  383. {
  384. return 1;
  385. }
  386. return 0;
  387. }
  388. return( ((RPC_UUID __RPC_FAR *)Uuid1)->MatchUuid(
  389. (RPC_UUID __RPC_FAR *)Uuid2)
  390. == 0 );
  391. }
  392. unsigned short RPC_ENTRY
  393. UuidHash (
  394. IN UUID __RPC_FAR * Uuid,
  395. OUT RPC_STATUS __RPC_FAR * Status
  396. )
  397. /*++
  398. Routine Description:
  399. An application will use this routine to create a hash value for a uuid.
  400. Arguments:
  401. Uuid - Supplies the uuid for which we want to create a hash value. A
  402. value of NULL can be supplied to indicate the nil uuid.
  403. Status - Will always be set to RPC_S_OK.
  404. Return Value:
  405. Returns the hash value.
  406. --*/
  407. {
  408. *Status = RPC_S_OK;
  409. if ( Uuid == 0 )
  410. {
  411. return(0);
  412. }
  413. return( ((RPC_UUID __RPC_FAR *)Uuid)->HashUuid() );
  414. }
  415. int RPC_ENTRY
  416. UuidIsNil (
  417. IN UUID __RPC_FAR * Uuid,
  418. OUT RPC_STATUS __RPC_FAR * Status
  419. )
  420. /*++
  421. Routine Description:
  422. We will determine if the supplied uuid is the nil uuid or not.
  423. Arguments:
  424. Uuid - Supplies the uuid to check. A value of NULL indicates the nil
  425. uuid.
  426. Status - This will always be RPC_S_OK.
  427. Return Value:
  428. Returns non-zero if the supplied uuid is the nil uuid; otherwise, zero
  429. will be returned.
  430. --*/
  431. {
  432. *Status = RPC_S_OK;
  433. if ( Uuid == 0 )
  434. {
  435. return(1);
  436. }
  437. return ( ((RPC_UUID __RPC_FAR *) Uuid)->IsNullUuid() );
  438. }