ReactOS  0.4.15-dev-1184-g23e04ae
uuid.c
Go to the documentation of this file.
1 /*
2  * COPYRIGHT: See COPYING in the top level directory
3  * PROJECT: ReactOS kernel
4  * FILE: ntoskrnl/ex/uuid.c
5  * PURPOSE: UUID generator
6  * PROGRAMMERS: Eric Kohl
7  * Thomas Weidenmueller
8  * Pierre Schweitzer
9  */
10 
11 /* INCLUDES *****************************************************************/
12 
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <debug.h>
16 
17 #define SEED_BUFFER_SIZE 6
18 
19 /* Number of 100ns ticks per clock tick. To be safe, assume that the clock
20  resolution is at least 1000 * 100 * (1/1000000) = 1/10 of a second */
21 #define TICKS_PER_CLOCK_TICK 1000
22 #define SECSPERDAY 86400
23 #define TICKSPERSEC 10000000
24 
25 /* UUID system time starts at October 15, 1582 */
26 #define SECS_15_OCT_1582_TO_1601 ((17 + 30 + 31 + 365 * 18 + 5) * SECSPERDAY)
27 #define TICKS_15_OCT_1582_TO_1601 ((ULONGLONG)SECS_15_OCT_1582_TO_1601 * TICKSPERSEC)
28 
29 /* 10000 in 100-ns model = 0.1 microsecond */
30 #define TIME_FRAME 10000
31 
32 #if defined (ALLOC_PRAGMA)
33 #pragma alloc_text(INIT, ExpUuidInitialization)
34 #pragma alloc_text(INIT, ExLuidInitialization)
35 #endif
36 
37 
38 /* GLOBALS ****************************************************************/
39 
45 UUID_CACHED_VALUES_STRUCT ExpUuidCachedValues = {0ULL, 0xFFFFFFFF, {{0, 0, {0x80, 0x6E, 0x6F, 0x6E, 0x69, 0x63}}}};
48 LARGE_INTEGER ExpLuid = {{0x3e9, 0x0}};
49 
50 /* FUNCTIONS ****************************************************************/
51 
52 /*
53  * @implemented
54  */
55 INIT_FUNCTION
56 BOOLEAN
57 NTAPI
59 {
61 
64 
65  return TRUE;
66 }
67 
68 
69 /*
70  * @implemented
71  */
72 #define VALUE_BUFFER_SIZE 20
73 static NTSTATUS
75 {
76  UCHAR ValueBuffer[VALUE_BUFFER_SIZE];
83 
84  PAGED_CODE();
85 
86  RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\Software\\Microsoft\\Rpc");
87  RtlInitUnicodeString(&ValueName, L"UuidSequenceNumber");
88 
90  &KeyName,
92  NULL,
93  NULL);
95  if (!NT_SUCCESS(Status))
96  {
97  DPRINT("ZwOpenKey() failed (Status %lx)\n", Status);
98  return Status;
99  }
100 
101  ValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
102  Status = ZwQueryValueKey(KeyHandle,
103  &ValueName,
105  ValueBuffer,
107  &ValueLength);
109  if (!NT_SUCCESS(Status))
110  {
111  DPRINT("ZwQueryValueKey() failed (Status %lx)\n", Status);
112  return Status;
113  }
114 
115  if (ValueInfo->Type != REG_DWORD || ValueInfo->DataLength != sizeof(DWORD))
116  {
117  return STATUS_UNSUCCESSFUL;
118  }
119 
120  *Sequence = *((PULONG)ValueInfo->Data);
121 
122  DPRINT("Loaded sequence %lx\n", *Sequence);
123 
124  return STATUS_SUCCESS;
125 }
126 #undef VALUE_BUFFER_SIZE
127 
128 /*
129  * @implemented
130  */
131 static NTSTATUS
133 {
138 
139  PAGED_CODE();
140 
141  RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\Software\\Microsoft\\Rpc");
142  RtlInitUnicodeString(&ValueName, L"UuidSequenceNumber");
143 
145  &KeyName,
147  NULL,
148  NULL);
149  Status = ZwOpenKey(&KeyHandle,
152  if (!NT_SUCCESS(Status))
153  {
154  DPRINT("ZwOpenKey() failed (Status %lx)\n", Status);
155  return Status;
156  }
157 
158  Status = ZwSetValueKey(KeyHandle,
159  &ValueName,
160  0,
161  REG_DWORD,
162  Sequence,
163  sizeof(ULONG));
165  if (!NT_SUCCESS(Status))
166  {
167  DPRINT("ZwSetValueKey() failed (Status %lx)\n", Status);
168  }
169 
170  return Status;
171 }
172 
173 /*
174  * @implemented
175  * Warning! This function must be called
176  * with ExpUuidLock held!
177  */
178 static VOID
180 {
182 
183  PAGED_CODE();
184 
185  /* Only save sequence if it has to */
187  {
189  if (NT_SUCCESS(Status))
190  {
192  }
193  }
194 }
195 
196 /*
197  * @implemented
198  * Warning! This function must be called
199  * with ExpUuidLock held!
200  */
201 static NTSTATUS
203  PULONG Range,
204  PULONG Sequence)
205 {
207  LARGE_INTEGER Counter, Frequency, CurrentTime, TimeDiff, ClockDiff;
208 
209  PAGED_CODE();
210 
211  /* Initialize sequence number */
213  {
214  /* Try to load sequence number */
216  if (NT_SUCCESS(Status))
217  {
219  }
220  else
221  {
222  /* If we cannot, generate a "true" random */
225  }
226 
227  /* It's valid and to be saved */
230  }
231 
232  KeQuerySystemTime(&CurrentTime);
233  TimeDiff.QuadPart = CurrentTime.QuadPart - ExpUuidLastTimeAllocated.QuadPart;
234  /* If time went backwards, change sequence (see RFC example) */
235  if (TimeDiff.QuadPart < 0)
236  {
238  TimeDiff.QuadPart = 2 * TIME_FRAME;
239 
240  /* It's to be saved */
243  }
244 
245  if (TimeDiff.QuadPart == 0)
246  {
247  return STATUS_RETRY;
248  }
249 
250  /* If time diff > 0.1ms, squash it to reduce it to keep our clock resolution */
251  if (TimeDiff.HighPart > 0 || TimeDiff.QuadPart > TICKS_PER_CLOCK_TICK * TIME_FRAME)
252  {
254  }
255 
256  if (TimeDiff.HighPart < 0 || TimeDiff.QuadPart <= TIME_FRAME)
257  {
258  *Range = TimeDiff.QuadPart;
259  ClockDiff.QuadPart = 0LL;
260  }
261  else
262  {
263  *Range = TIME_FRAME;
264  ClockDiff.QuadPart = TimeDiff.QuadPart - TIME_FRAME;
265  --ClockDiff.HighPart;
266  }
267 
268  Time->QuadPart = CurrentTime.QuadPart - *Range - ClockDiff.QuadPart;
269  ExpUuidLastTimeAllocated.QuadPart = CurrentTime.QuadPart - ClockDiff.QuadPart;
270  *Sequence = ExpUuidSequenceNumber;
271 
272  return STATUS_SUCCESS;
273 }
274 
275 /*
276  * @implemented
277  * Warning! This function must be called
278  * with ExpUuidLock held!
279  */
280 static NTSTATUS
282 {
285  ULONG Range;
286  ULONG Sequence;
287 
288  PAGED_CODE();
289 
290  /* Allocate UUIDs */
291  Status = ExpAllocateUuids(&Time, &Range, &Sequence);
292  if (Status == STATUS_RETRY)
293  {
294  return Status;
295  }
296 
297  if (!NT_SUCCESS(Status))
298  {
299  return STATUS_NO_MEMORY;
300  }
301 
302  /* We need at least one UUID */
303  ASSERT(Range != 0);
304 
305  /* Set up our internal cache
306  * See format_uuid_v1 in RFC4122 for magic values
307  */
308  CachedValues->ClockSeqLow = Sequence;
309  CachedValues->ClockSeqHiAndReserved = (Sequence & 0x3F00) >> 8;
310  CachedValues->ClockSeqHiAndReserved |= 0x80;
311  CachedValues->AllocatedCount = Range;
312 
313  /*
314  * Time is relative to UUID time
315  * And we set last time range for all the possibly
316  * returnable UUID
317  */
319  CachedValues->Time = Time.QuadPart + (Range - 1);
320 
321  return STATUS_SUCCESS;
322 }
323 
324 /*
325  * @implemented
326  */
327 INIT_FUNCTION
328 BOOLEAN
329 NTAPI
331 {
332  return TRUE;
333 }
334 
335 /*
336  * @implemented
337  */
338 VOID
339 NTAPI
341 {
342  /* Atomically increment the luid */
343  *(LONG64*)LocallyUniqueId = InterlockedExchangeAdd64(&ExpLuid.QuadPart,
345 }
346 
347 
348 /*
349  * @implemented
350  */
351 NTSTATUS
352 NTAPI
354 {
356  PAGED_CODE();
357 
358  /* Probe if user mode */
360  if (PreviousMode != KernelMode)
361  {
362  _SEH2_TRY
363  {
364  ProbeForWrite(LocallyUniqueId,
365  sizeof(LUID),
366  sizeof(ULONG));
367  }
369  {
371  }
372  _SEH2_END;
373  }
374 
375  /* Do the allocation */
376  ExAllocateLocallyUniqueId(LocallyUniqueId);
377  return STATUS_SUCCESS;
378 }
379 
380 /*
381  * @implemented
382  */
383 NTSTATUS
384 NTAPI
386 {
388  LONG AllocatedCount;
390  BOOLEAN Valid;
391 
392  PAGED_CODE();
393 
395  /* Loop until we have an UUID to return */
396  while (TRUE)
397  {
398  /* Try to gather node values */
399  do
400  {
402 
403  C_ASSERT(sizeof(ExpUuidCachedValues.GuidInit) == sizeof(Uuid->Data4));
404  RtlCopyMemory(Uuid->Data4,
406  sizeof(Uuid->Data4));
407 
408  Valid = ExpUuidCacheValid;
410  }
411  /* Loop till we can do it without being disturbed */
413 
414  /* We have more than an allocated UUID left, that's OK to return! */
415  if (AllocatedCount >= 0)
416  {
417  break;
418  }
419 
420  /*
421  * Here, we're out of UUIDs, we need to allocate more
422  * We need to be alone to do it, so lock the mutex
423  */
426  {
427  /* If allocation fails, bail out! */
429  if (Status != STATUS_SUCCESS)
430  {
432  return Status;
433  }
434 
435  /* Save our current sequence if changed */
437  }
439  }
440 
441  /*
442  * Once here, we've got an UUID to return
443  * But, if our init wasn't sane, then, make
444  * sure it's only used locally
445  */
446  if (!Valid)
447  {
449  }
450 
451  /* Set our timestamp - see RFC4211 */
452  Time.QuadPart -= AllocatedCount;
453  Uuid->Data1 = Time.LowPart;
454  Uuid->Data2 = Time.HighPart;
455  /* We also set the bit for GUIDv1 */
456  Uuid->Data3 = ((Time.HighPart >> 16) & 0x0FFF) | 0x1000;
457 
458  return Status;
459 }
460 
461 /*
462  * @implemented
463  */
464 NTSTATUS
465 NTAPI
467  OUT PULONG Range,
468  OUT PULONG Sequence,
469  OUT PUCHAR Seed)
470 {
471  ULARGE_INTEGER IntTime;
472  ULONG IntRange, IntSequence;
475 
476  PAGED_CODE();
477 
478  /* Probe if user mode */
480  if (PreviousMode != KernelMode)
481  {
482  _SEH2_TRY
483  {
485  sizeof(ULARGE_INTEGER),
486  sizeof(ULONG));
487 
489  sizeof(ULONG),
490  sizeof(ULONG));
491 
492  ProbeForWrite(Sequence,
493  sizeof(ULONG),
494  sizeof(ULONG));
495 
496  ProbeForWrite(Seed,
498  sizeof(UCHAR));
499  }
501  {
503  }
504  _SEH2_END;
505  }
506 
507  /* During allocation we must be alone */
509 
510  Status = ExpAllocateUuids(&IntTime,
511  &IntRange,
512  &IntSequence);
513  if (!NT_SUCCESS(Status))
514  {
516  return Status;
517  }
518 
519  /* If sequence number was changed, save it */
521 
522  /* Allocation done, so we can release */
524 
525  /* Write back UUIDs to caller */
526  _SEH2_TRY
527  {
528  Time->QuadPart = IntTime.QuadPart;
529  *Range = IntRange;
530  *Sequence = IntSequence;
531 
532  RtlCopyMemory(Seed,
535 
537  }
539  {
541  }
542  _SEH2_END;
543 
544  return Status;
545 }
546 
547 
548 /*
549  * @implemented
550  */
551 NTSTATUS
552 NTAPI
554 {
556  BOOLEAN GotContext;
559  LUID CallerLuid, SystemLuid = SYSTEM_LUID;
560 
561  PAGED_CODE();
562 
563  /* Should only be done by umode */
565 
566  /* No context to release */
567  GotContext = FALSE;
568  _SEH2_TRY
569  {
570  /* Get our caller context and remember to release it */
572  GotContext = TRUE;
573 
574  /* Get caller access token and its associated ID */
576  Status = SeQueryAuthenticationIdToken(Token, &CallerLuid);
577  if (!NT_SUCCESS(Status))
578  {
580  }
581 
582  /* This call is only allowed for SYSTEM */
583  if (!RtlEqualLuid(&CallerLuid, &SystemLuid))
584  {
586  }
587 
588  /* Check for buffer validity and then copy it to our seed */
589  ProbeForRead(Seed, SEED_BUFFER_SIZE, sizeof(UCHAR));
591 
592  /*
593  * According to RFC 4122, UUID seed is based on MAC addresses
594  * If it is randomly set, then, it must have its multicast be set
595  * to be valid and avoid collisions
596  * Reflect it here
597  */
598  ExpUuidCacheValid = ~(*Seed >> 7) & 1;
599 
601  }
603  {
605  }
606  _SEH2_END;
607 
608  /* Release context if required */
609  if (GotContext)
610  {
612  }
613 
614  return Status;
615 }
616 
617 /* EOF */
#define KeQuerySystemTime(t)
Definition: env_spec_w32.h:570
VOID NTAPI SeCaptureSubjectContext(OUT PSECURITY_SUBJECT_CONTEXT SubjectContext)
Definition: access.c:301
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:35
_Must_inspect_result_ _Out_ PNDIS_STATUS _In_ NDIS_HANDLE _In_ ULONG _Out_ PNDIS_STRING KeyName
Definition: ndis.h:4711
#define IN
Definition: typedefs.h:39
DECLSPEC_NORETURN NTSYSAPI VOID NTAPI RtlRaiseStatus(_In_ NTSTATUS Status)
_Inout_ PLIST_ENTRY _In_ PVOID _In_ PSTRING _In_ BOOLEAN _In_ BOOLEAN _In_ ULONG _In_ PFLT_CALLBACK_DATA _In_opt_ PCHECK_FOR_TRAVERSE_ACCESS _In_opt_ PSECURITY_SUBJECT_CONTEXT SubjectContext
Definition: fltkernel.h:2239
VOID NTAPI SeReleaseSubjectContext(IN PSECURITY_SUBJECT_CONTEXT SubjectContext)
Definition: access.c:360
LARGE_INTEGER NTAPI KeQueryPerformanceCounter(IN PLARGE_INTEGER PerformanceFreq)
Definition: timer.c:138
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
#define LL
Definition: tui.h:84
#define VALUE_BUFFER_SIZE
Definition: uuid.c:72
#define OBJ_CASE_INSENSITIVE
Definition: winternl.h:228
_Must_inspect_result_ _Out_ PNDIS_STATUS _In_ NDIS_HANDLE _In_ ULONG _Out_ PNDIS_STRING _Out_ PNDIS_HANDLE KeyHandle
Definition: ndis.h:4711
#define TRUE
Definition: types.h:120
NTSYSAPI NTSTATUS NTAPI ZwClose(_In_ HANDLE Handle)
unsigned char * PUCHAR
Definition: retypes.h:3
#define KeGetPreviousMode()
Definition: ketypes.h:1107
LONG NTSTATUS
Definition: precomp.h:26
_IRQL_requires_same_ _In_ PLSA_STRING _In_ SECURITY_LOGON_TYPE _In_ ULONG _In_ ULONG _In_opt_ PTOKEN_GROUPS _In_ PTOKEN_SOURCE _Out_ PVOID _Out_ PULONG _Inout_ PLUID _Out_ PHANDLE Token
KPROCESSOR_MODE NTAPI ExGetPreviousMode(VOID)
Definition: sysinfo.c:3066
BOOLEAN ExpUuidCacheValid
Definition: uuid.c:46
NTSTATUS NTAPI NtAllocateLocallyUniqueId(OUT LUID *LocallyUniqueId)
Definition: uuid.c:353
#define OBJ_KERNEL_HANDLE
Definition: winternl.h:231
VOID FASTCALL ExReleaseFastMutex(IN PFAST_MUTEX FastMutex)
Definition: fmutex.c:31
VOID NTAPI ProbeForWrite(IN PVOID Address, IN SIZE_T Length, IN ULONG Alignment)
Definition: exintrin.c:143
FAST_MUTEX ExpUuidLock
Definition: uuid.c:40
_SEH2_TRY
Definition: create.c:4226
INIT_FUNCTION BOOLEAN NTAPI ExLuidInitialization(VOID)
Definition: uuid.c:330
uint32_t ULONG_PTR
Definition: typedefs.h:65
struct tagRange Range
INIT_FUNCTION BOOLEAN NTAPI ExpUuidInitialization(VOID)
Definition: uuid.c:58
NTSTATUS NTAPI SeQueryAuthenticationIdToken(IN PACCESS_TOKEN Token, OUT PLUID LogonId)
Definition: token.c:1752
_In_ PUNICODE_STRING ValueName
Definition: cmfuncs.h:264
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
ULONGLONG QuadPart
Definition: ms-dtyp.idl:185
#define FALSE
Definition: types.h:117
#define RtlEqualLuid(Luid1, Luid2)
Definition: rtlfuncs.h:301
long LONG
Definition: pedump.c:60
#define GENERIC_WRITE
Definition: nt_native.h:90
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
LARGE_INTEGER ExpUuidLastTimeAllocated
Definition: uuid.c:41
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
void DPRINT(...)
Definition: polytest.cpp:61
static VOID ExpUuidSaveSequenceNumberIf(VOID)
Definition: uuid.c:179
#define C_ASSERT(e)
Definition: intsafe.h:71
static NTSTATUS ExpUuidSaveSequenceNumber(PULONG Sequence)
Definition: uuid.c:132
#define TIME_FRAME
Definition: uuid.c:30
#define ULL(a, b)
Definition: format_msg.c:27
#define TICKS_15_OCT_1582_TO_1601
Definition: uuid.c:27
FAST_MUTEX
Definition: extypes.h:17
LARGE_INTEGER ExpLuid
Definition: uuid.c:48
int64_t LONG64
Definition: typedefs.h:68
_In_ KPROCESSOR_MODE PreviousMode
Definition: sefuncs.h:103
#define _SEH2_YIELD(STMT_)
Definition: pseh2_64.h:8
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
ULONG ExpUuidSequenceNumber
Definition: uuid.c:42
static NTSTATUS ExpUuidGetValues(PUUID_CACHED_VALUES_STRUCT CachedValues)
Definition: uuid.c:281
struct _KEY_VALUE_PARTIAL_INFORMATION * PKEY_VALUE_PARTIAL_INFORMATION
FORCEINLINE VOID ExInitializeFastMutex(_Out_ PFAST_MUTEX FastMutex)
Definition: exfuncs.h:274
unsigned long DWORD
Definition: ntddk_ex.h:95
#define STATUS_ACCESS_DENIED
Definition: udferr_usr.h:145
CCHAR KPROCESSOR_MODE
Definition: ketypes.h:7
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
unsigned char UCHAR
Definition: xmlstorage.h:181
NTSTATUS NTAPI NtSetUuidSeed(IN PUCHAR Seed)
Definition: uuid.c:553
#define InterlockedExchangeAdd64
Definition: interlocked.h:186
Status
Definition: gdiplustypes.h:24
VOID NTAPI ProbeForRead(IN CONST VOID *Address, IN SIZE_T Length, IN ULONG Alignment)
Definition: exintrin.c:102
static const WCHAR L[]
Definition: oid.c:1250
#define InterlockedDecrement
Definition: armddk.h:52
_In_ GUID _In_ PVOID _In_ ULONG ValueLength
Definition: hubbusif.h:311
ULONG LowPart
Definition: typedefs.h:106
#define GENERIC_READ
Definition: compat.h:135
Definition: range.c:39
#define SeQuerySubjectContextToken(SubjectContext)
Definition: sefuncs.h:583
#define SYSTEM_LUID
Definition: setypes.h:672
_SEH2_END
Definition: create.c:4400
#define TICKS_PER_CLOCK_TICK
Definition: uuid.c:21
LONG NTAPI ExSystemExceptionFilter(VOID)
Definition: harderr.c:351
VOID FASTCALL ExAcquireFastMutex(IN PFAST_MUTEX FastMutex)
Definition: fmutex.c:23
BOOLEAN ExpUuidSequenceNumberNotSaved
Definition: uuid.c:44
VOID NTAPI ExAllocateLocallyUniqueId(OUT LUID *LocallyUniqueId)
Definition: uuid.c:340
static NTSTATUS ExpAllocateUuids(PULARGE_INTEGER Time, PULONG Range, PULONG Sequence)
Definition: uuid.c:202
UUID_CACHED_VALUES_STRUCT ExpUuidCachedValues
Definition: uuid.c:45
#define STATUS_NO_MEMORY
Definition: ntstatus.h:260
unsigned int * PULONG
Definition: retypes.h:1
static LARGE_INTEGER Frequency
Definition: clock.c:41
static LARGE_INTEGER Counter
Definition: clock.c:43
#define STATUS_RETRY
Definition: udferr_usr.h:182
static NTSTATUS ExpUuidLoadSequenceNumber(PULONG Sequence)
Definition: uuid.c:74
NTSTATUS NTAPI NtAllocateUuids(OUT PULARGE_INTEGER Time, OUT PULONG Range, OUT PULONG Sequence, OUT PUCHAR Seed)
Definition: uuid.c:466
#define OUT
Definition: typedefs.h:40
unsigned int ULONG
Definition: retypes.h:1
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
#define ULONG_PTR
Definition: config.h:101
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
BOOLEAN ExpUuidSequenceNumberValid
Definition: uuid.c:43
UCHAR ClockSeqHiAndReserved
Definition: ex.h:178
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:6
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:12
return STATUS_SUCCESS
Definition: btrfs.c:3014
#define REG_DWORD
Definition: sdbapi.c:596
#define SEED_BUFFER_SIZE
Definition: uuid.c:17
NTSTATUS NTAPI ExUuidCreate(OUT UUID *Uuid)
Definition: uuid.c:385
static PLARGE_INTEGER Time
Definition: time.c:105
#define RPC_NT_UUID_LOCAL_ONLY
Definition: ntstatus.h:174
LONGLONG QuadPart
Definition: typedefs.h:114
#define PAGED_CODE()
ULONG ExpLuidIncrement
Definition: uuid.c:47