ReactOS  0.4.15-dev-2721-g5912c11
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 
33 /* GLOBALS ****************************************************************/
34 
40 UUID_CACHED_VALUES_STRUCT ExpUuidCachedValues = {0ULL, 0xFFFFFFFF, {{0, 0, {0x80, 0x6E, 0x6F, 0x6E, 0x69, 0x63}}}};
43 LARGE_INTEGER ExpLuid = {{0x3e9, 0x0}};
44 
45 /* FUNCTIONS ****************************************************************/
46 
47 /*
48  * @implemented
49  */
50 CODE_SEG("INIT")
51 BOOLEAN
52 NTAPI
54 {
56 
59 
60  return TRUE;
61 }
62 
63 
64 /*
65  * @implemented
66  */
67 #define VALUE_BUFFER_SIZE 20
68 static NTSTATUS
70 {
71  UCHAR ValueBuffer[VALUE_BUFFER_SIZE];
78 
79  PAGED_CODE();
80 
81  RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\Software\\Microsoft\\Rpc");
82  RtlInitUnicodeString(&ValueName, L"UuidSequenceNumber");
83 
85  &KeyName,
87  NULL,
88  NULL);
90  if (!NT_SUCCESS(Status))
91  {
92  DPRINT("ZwOpenKey() failed (Status %lx)\n", Status);
93  return Status;
94  }
95 
96  ValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
97  Status = ZwQueryValueKey(KeyHandle,
98  &ValueName,
100  ValueBuffer,
102  &ValueLength);
104  if (!NT_SUCCESS(Status))
105  {
106  DPRINT("ZwQueryValueKey() failed (Status %lx)\n", Status);
107  return Status;
108  }
109 
110  if (ValueInfo->Type != REG_DWORD || ValueInfo->DataLength != sizeof(DWORD))
111  {
112  return STATUS_UNSUCCESSFUL;
113  }
114 
115  *Sequence = *((PULONG)ValueInfo->Data);
116 
117  DPRINT("Loaded sequence %lx\n", *Sequence);
118 
119  return STATUS_SUCCESS;
120 }
121 #undef VALUE_BUFFER_SIZE
122 
123 /*
124  * @implemented
125  */
126 static NTSTATUS
128 {
133 
134  PAGED_CODE();
135 
136  RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\Software\\Microsoft\\Rpc");
137  RtlInitUnicodeString(&ValueName, L"UuidSequenceNumber");
138 
140  &KeyName,
142  NULL,
143  NULL);
144  Status = ZwOpenKey(&KeyHandle,
147  if (!NT_SUCCESS(Status))
148  {
149  DPRINT("ZwOpenKey() failed (Status %lx)\n", Status);
150  return Status;
151  }
152 
153  Status = ZwSetValueKey(KeyHandle,
154  &ValueName,
155  0,
156  REG_DWORD,
157  Sequence,
158  sizeof(ULONG));
160  if (!NT_SUCCESS(Status))
161  {
162  DPRINT("ZwSetValueKey() failed (Status %lx)\n", Status);
163  }
164 
165  return Status;
166 }
167 
168 /*
169  * @implemented
170  * Warning! This function must be called
171  * with ExpUuidLock held!
172  */
173 static VOID
175 {
177 
178  PAGED_CODE();
179 
180  /* Only save sequence if it has to */
182  {
184  if (NT_SUCCESS(Status))
185  {
187  }
188  }
189 }
190 
191 /*
192  * @implemented
193  * Warning! This function must be called
194  * with ExpUuidLock held!
195  */
196 static NTSTATUS
198  PULONG Range,
199  PULONG Sequence)
200 {
202  LARGE_INTEGER Counter, Frequency, CurrentTime, TimeDiff, ClockDiff;
203 
204  PAGED_CODE();
205 
206  /* Initialize sequence number */
208  {
209  /* Try to load sequence number */
211  if (NT_SUCCESS(Status))
212  {
214  }
215  else
216  {
217  /* If we cannot, generate a "true" random */
220  }
221 
222  /* It's valid and to be saved */
225  }
226 
227  KeQuerySystemTime(&CurrentTime);
228  TimeDiff.QuadPart = CurrentTime.QuadPart - ExpUuidLastTimeAllocated.QuadPart;
229  /* If time went backwards, change sequence (see RFC example) */
230  if (TimeDiff.QuadPart < 0)
231  {
233  TimeDiff.QuadPart = 2 * TIME_FRAME;
234 
235  /* It's to be saved */
238  }
239 
240  if (TimeDiff.QuadPart == 0)
241  {
242  return STATUS_RETRY;
243  }
244 
245  /* If time diff > 0.1ms, squash it to reduce it to keep our clock resolution */
246  if (TimeDiff.HighPart > 0 || TimeDiff.QuadPart > TICKS_PER_CLOCK_TICK * TIME_FRAME)
247  {
249  }
250 
251  if (TimeDiff.HighPart < 0 || TimeDiff.QuadPart <= TIME_FRAME)
252  {
253  *Range = TimeDiff.QuadPart;
254  ClockDiff.QuadPart = 0LL;
255  }
256  else
257  {
258  *Range = TIME_FRAME;
259  ClockDiff.QuadPart = TimeDiff.QuadPart - TIME_FRAME;
260  --ClockDiff.HighPart;
261  }
262 
263  Time->QuadPart = CurrentTime.QuadPart - *Range - ClockDiff.QuadPart;
264  ExpUuidLastTimeAllocated.QuadPart = CurrentTime.QuadPart - ClockDiff.QuadPart;
265  *Sequence = ExpUuidSequenceNumber;
266 
267  return STATUS_SUCCESS;
268 }
269 
270 /*
271  * @implemented
272  * Warning! This function must be called
273  * with ExpUuidLock held!
274  */
275 static NTSTATUS
277 {
280  ULONG Range;
281  ULONG Sequence;
282 
283  PAGED_CODE();
284 
285  /* Allocate UUIDs */
286  Status = ExpAllocateUuids(&Time, &Range, &Sequence);
287  if (Status == STATUS_RETRY)
288  {
289  return Status;
290  }
291 
292  if (!NT_SUCCESS(Status))
293  {
294  return STATUS_NO_MEMORY;
295  }
296 
297  /* We need at least one UUID */
298  ASSERT(Range != 0);
299 
300  /* Set up our internal cache
301  * See format_uuid_v1 in RFC4122 for magic values
302  */
303  CachedValues->ClockSeqLow = Sequence;
304  CachedValues->ClockSeqHiAndReserved = (Sequence & 0x3F00) >> 8;
305  CachedValues->ClockSeqHiAndReserved |= 0x80;
306  CachedValues->AllocatedCount = Range;
307 
308  /*
309  * Time is relative to UUID time
310  * And we set last time range for all the possibly
311  * returnable UUID
312  */
314  CachedValues->Time = Time.QuadPart + (Range - 1);
315 
316  return STATUS_SUCCESS;
317 }
318 
319 /*
320  * @implemented
321  */
322 CODE_SEG("INIT")
323 BOOLEAN
324 NTAPI
326 {
327  return TRUE;
328 }
329 
330 /*
331  * @implemented
332  */
333 VOID
334 NTAPI
336 {
337  /* Atomically increment the luid */
338  *(LONG64*)LocallyUniqueId = InterlockedExchangeAdd64(&ExpLuid.QuadPart,
340 }
341 
342 
343 /*
344  * @implemented
345  */
346 NTSTATUS
347 NTAPI
349 {
351  PAGED_CODE();
352 
353  /* Probe if user mode */
355  if (PreviousMode != KernelMode)
356  {
357  _SEH2_TRY
358  {
359  ProbeForWrite(LocallyUniqueId,
360  sizeof(LUID),
361  sizeof(ULONG));
362  }
364  {
366  }
367  _SEH2_END;
368  }
369 
370  /* Do the allocation */
371  ExAllocateLocallyUniqueId(LocallyUniqueId);
372  return STATUS_SUCCESS;
373 }
374 
375 /*
376  * @implemented
377  */
378 NTSTATUS
379 NTAPI
381 {
383  LONG AllocatedCount;
385  BOOLEAN Valid;
386 
387  PAGED_CODE();
388 
390  /* Loop until we have an UUID to return */
391  while (TRUE)
392  {
393  /* Try to gather node values */
394  do
395  {
397 
398  RtlCopyMemory(Uuid->Data4,
400  sizeof(Uuid->Data4));
401 
402  Valid = ExpUuidCacheValid;
404  }
405  /* Loop till we can do it without being disturbed */
407 
408  /* We have more than an allocated UUID left, that's OK to return! */
409  if (AllocatedCount >= 0)
410  {
411  break;
412  }
413 
414  /*
415  * Here, we're out of UUIDs, we need to allocate more
416  * We need to be alone to do it, so lock the mutex
417  */
420  {
421  /* If allocation fails, bail out! */
423  if (Status != STATUS_SUCCESS)
424  {
426  return Status;
427  }
428 
429  /* Save our current sequence if changed */
431  }
433  }
434 
435  /*
436  * Once here, we've got an UUID to return
437  * But, if our init wasn't sane, then, make
438  * sure it's only used locally
439  */
440  if (!Valid)
441  {
443  }
444 
445  /* Set our timestamp - see RFC4211 */
446  Time.QuadPart -= AllocatedCount;
447  Uuid->Data1 = Time.LowPart;
448  Uuid->Data2 = Time.HighPart;
449  /* We also set the bit for GUIDv1 */
450  Uuid->Data3 = ((Time.HighPart >> 16) & 0x0FFF) | 0x1000;
451 
452  return Status;
453 }
454 
455 /*
456  * @implemented
457  */
458 NTSTATUS
459 NTAPI
461  OUT PULONG Range,
462  OUT PULONG Sequence,
463  OUT PUCHAR Seed)
464 {
465  ULARGE_INTEGER IntTime;
466  ULONG IntRange, IntSequence;
469 
470  PAGED_CODE();
471 
472  /* Probe if user mode */
474  if (PreviousMode != KernelMode)
475  {
476  _SEH2_TRY
477  {
479  sizeof(ULARGE_INTEGER),
480  sizeof(ULONG));
481 
483  sizeof(ULONG),
484  sizeof(ULONG));
485 
486  ProbeForWrite(Sequence,
487  sizeof(ULONG),
488  sizeof(ULONG));
489 
490  ProbeForWrite(Seed,
492  sizeof(UCHAR));
493  }
495  {
497  }
498  _SEH2_END;
499  }
500 
501  /* During allocation we must be alone */
503 
504  Status = ExpAllocateUuids(&IntTime,
505  &IntRange,
506  &IntSequence);
507  if (!NT_SUCCESS(Status))
508  {
510  return Status;
511  }
512 
513  /* If sequence number was changed, save it */
515 
516  /* Allocation done, so we can release */
518 
519  /* Write back UUIDs to caller */
520  _SEH2_TRY
521  {
522  Time->QuadPart = IntTime.QuadPart;
523  *Range = IntRange;
524  *Sequence = IntSequence;
525 
526  RtlCopyMemory(Seed,
529 
531  }
533  {
535  }
536  _SEH2_END;
537 
538  return Status;
539 }
540 
541 
542 /*
543  * @implemented
544  */
545 NTSTATUS
546 NTAPI
548 {
550  BOOLEAN GotContext;
553  LUID CallerLuid, SystemLuid = SYSTEM_LUID;
554 
555  PAGED_CODE();
556 
557  /* Should only be done by umode */
559 
560  /* No context to release */
561  GotContext = FALSE;
562  _SEH2_TRY
563  {
564  /* Get our caller context and remember to release it */
566  GotContext = TRUE;
567 
568  /* Get caller access token and its associated ID */
570  Status = SeQueryAuthenticationIdToken(Token, &CallerLuid);
571  if (!NT_SUCCESS(Status))
572  {
574  }
575 
576  /* This call is only allowed for SYSTEM */
577  if (!RtlEqualLuid(&CallerLuid, &SystemLuid))
578  {
580  }
581 
582  /* Check for buffer validity and then copy it to our seed */
583  ProbeForRead(Seed, SEED_BUFFER_SIZE, sizeof(UCHAR));
585 
586  /*
587  * According to RFC 4122, UUID seed is based on MAC addresses
588  * If it is randomly set, then, it must have its multicast be set
589  * to be valid and avoid collisions
590  * Reflect it here
591  */
592  ExpUuidCacheValid = ~(*Seed >> 7) & 1;
593 
595  }
597  {
599  }
600  _SEH2_END;
601 
602  /* Release context if required */
603  if (GotContext)
604  {
606  }
607 
608  return Status;
609 }
610 
611 /* EOF */
#define KeQuerySystemTime(t)
Definition: env_spec_w32.h:570
BOOLEAN NTAPI ExLuidInitialization(VOID)
Definition: uuid.c:325
VOID NTAPI SeCaptureSubjectContext(OUT PSECURITY_SUBJECT_CONTEXT SubjectContext)
Definition: access.c:301
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:35
#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
#define LL
Definition: tui.h:84
#define VALUE_BUFFER_SIZE
Definition: uuid.c:67
#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:41
NTSTATUS NTAPI NtAllocateLocallyUniqueId(OUT LUID *LocallyUniqueId)
Definition: uuid.c:348
#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:35
_SEH2_TRY
Definition: create.c:4226
uint32_t ULONG_PTR
Definition: typedefs.h:65
struct tagRange Range
NTSTATUS NTAPI SeQueryAuthenticationIdToken(IN PACCESS_TOKEN Token, OUT PLUID LogonId)
Definition: token.c:2188
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
BOOLEAN NTAPI ExpUuidInitialization(VOID)
Definition: uuid.c:53
LARGE_INTEGER ExpUuidLastTimeAllocated
Definition: uuid.c:36
unsigned char BOOLEAN
static VOID ExpUuidSaveSequenceNumberIf(VOID)
Definition: uuid.c:174
CODE_SEG("INIT")
Definition: Interface.c:1810
static NTSTATUS ExpUuidSaveSequenceNumber(PULONG Sequence)
Definition: uuid.c:127
#define TIME_FRAME
Definition: uuid.c:30
_Must_inspect_result_ _In_ WDFDEVICE _In_ PCUNICODE_STRING KeyName
Definition: wdfdevice.h:2697
#define ULL(a, b)
Definition: format_msg.c:27
#define TICKS_15_OCT_1582_TO_1601
Definition: uuid.c:27
Status
Definition: gdiplustypes.h:24
FAST_MUTEX
Definition: extypes.h:17
LARGE_INTEGER ExpLuid
Definition: uuid.c:43
int64_t LONG64
Definition: typedefs.h:68
_In_ KPROCESSOR_MODE PreviousMode
Definition: sefuncs.h:103
#define ASSERT(a)
Definition: mode.c:44
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
ULONG ExpUuidSequenceNumber
Definition: uuid.c:37
static NTSTATUS ExpUuidGetValues(PUUID_CACHED_VALUES_STRUCT CachedValues)
Definition: uuid.c:276
struct _KEY_VALUE_PARTIAL_INFORMATION * PKEY_VALUE_PARTIAL_INFORMATION
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
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
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING ValueName
Definition: wdfregistry.h:240
unsigned char UCHAR
Definition: xmlstorage.h:181
NTSTATUS NTAPI NtSetUuidSeed(IN PUCHAR Seed)
Definition: uuid.c:547
#define InterlockedExchangeAdd64
Definition: interlocked.h:186
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
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:39
VOID NTAPI ExAllocateLocallyUniqueId(OUT LUID *LocallyUniqueId)
Definition: uuid.c:335
static NTSTATUS ExpAllocateUuids(PULARGE_INTEGER Time, PULONG Range, PULONG Sequence)
Definition: uuid.c:197
UUID_CACHED_VALUES_STRUCT ExpUuidCachedValues
Definition: uuid.c:40
#define STATUS_NO_MEMORY
Definition: ntstatus.h:260
unsigned int * PULONG
Definition: retypes.h:1
#define NULL
Definition: types.h:112
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:69
NTSTATUS NTAPI NtAllocateUuids(OUT PULARGE_INTEGER Time, OUT PULONG Range, OUT PULONG Sequence, OUT PUCHAR Seed)
Definition: uuid.c:460
#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
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
BOOLEAN ExpUuidSequenceNumberValid
Definition: uuid.c:38
UCHAR ClockSeqHiAndReserved
Definition: ex.h:181
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:40
#define STATUS_SUCCESS
Definition: shellext.h:65
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:165
#define _SEH2_YIELD(__stmt)
Definition: pseh2_64.h:168
#define DPRINT
Definition: sndvol32.h:71
#define REG_DWORD
Definition: sdbapi.c:596
#define SEED_BUFFER_SIZE
Definition: uuid.c:17
NTSTATUS NTAPI ExUuidCreate(OUT UUID *Uuid)
Definition: uuid.c:380
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()
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _In_ ULONG ValueLength
Definition: wdfregistry.h:271
ULONG ExpLuidIncrement
Definition: uuid.c:42