ReactOS  0.4.15-dev-2106-g6de3300
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 /* GLOBALS ****************************************************************/
33 
39 UUID_CACHED_VALUES_STRUCT ExpUuidCachedValues = {0ULL, 0xFFFFFFFF, {{0, 0, {0x80, 0x6E, 0x6F, 0x6E, 0x69, 0x63}}}};
42 LARGE_INTEGER ExpLuid = {{0x3e9, 0x0}};
43 
44 /* FUNCTIONS ****************************************************************/
45 
46 /*
47  * @implemented
48  */
49 CODE_SEG("INIT")
50 BOOLEAN
51 NTAPI
53 {
55 
58 
59  return TRUE;
60 }
61 
62 
63 /*
64  * @implemented
65  */
66 #define VALUE_BUFFER_SIZE 20
67 static NTSTATUS
69 {
70  UCHAR ValueBuffer[VALUE_BUFFER_SIZE];
77 
78  PAGED_CODE();
79 
80  RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\Software\\Microsoft\\Rpc");
81  RtlInitUnicodeString(&ValueName, L"UuidSequenceNumber");
82 
84  &KeyName,
86  NULL,
87  NULL);
89  if (!NT_SUCCESS(Status))
90  {
91  DPRINT("ZwOpenKey() failed (Status %lx)\n", Status);
92  return Status;
93  }
94 
95  ValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
96  Status = ZwQueryValueKey(KeyHandle,
97  &ValueName,
99  ValueBuffer,
101  &ValueLength);
103  if (!NT_SUCCESS(Status))
104  {
105  DPRINT("ZwQueryValueKey() failed (Status %lx)\n", Status);
106  return Status;
107  }
108 
109  if (ValueInfo->Type != REG_DWORD || ValueInfo->DataLength != sizeof(DWORD))
110  {
111  return STATUS_UNSUCCESSFUL;
112  }
113 
114  *Sequence = *((PULONG)ValueInfo->Data);
115 
116  DPRINT("Loaded sequence %lx\n", *Sequence);
117 
118  return STATUS_SUCCESS;
119 }
120 #undef VALUE_BUFFER_SIZE
121 
122 /*
123  * @implemented
124  */
125 static NTSTATUS
127 {
132 
133  PAGED_CODE();
134 
135  RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\Software\\Microsoft\\Rpc");
136  RtlInitUnicodeString(&ValueName, L"UuidSequenceNumber");
137 
139  &KeyName,
141  NULL,
142  NULL);
143  Status = ZwOpenKey(&KeyHandle,
146  if (!NT_SUCCESS(Status))
147  {
148  DPRINT("ZwOpenKey() failed (Status %lx)\n", Status);
149  return Status;
150  }
151 
152  Status = ZwSetValueKey(KeyHandle,
153  &ValueName,
154  0,
155  REG_DWORD,
156  Sequence,
157  sizeof(ULONG));
159  if (!NT_SUCCESS(Status))
160  {
161  DPRINT("ZwSetValueKey() failed (Status %lx)\n", Status);
162  }
163 
164  return Status;
165 }
166 
167 /*
168  * @implemented
169  * Warning! This function must be called
170  * with ExpUuidLock held!
171  */
172 static VOID
174 {
176 
177  PAGED_CODE();
178 
179  /* Only save sequence if it has to */
181  {
183  if (NT_SUCCESS(Status))
184  {
186  }
187  }
188 }
189 
190 /*
191  * @implemented
192  * Warning! This function must be called
193  * with ExpUuidLock held!
194  */
195 static NTSTATUS
197  PULONG Range,
198  PULONG Sequence)
199 {
201  LARGE_INTEGER Counter, Frequency, CurrentTime, TimeDiff, ClockDiff;
202 
203  PAGED_CODE();
204 
205  /* Initialize sequence number */
207  {
208  /* Try to load sequence number */
210  if (NT_SUCCESS(Status))
211  {
213  }
214  else
215  {
216  /* If we cannot, generate a "true" random */
219  }
220 
221  /* It's valid and to be saved */
224  }
225 
226  KeQuerySystemTime(&CurrentTime);
227  TimeDiff.QuadPart = CurrentTime.QuadPart - ExpUuidLastTimeAllocated.QuadPart;
228  /* If time went backwards, change sequence (see RFC example) */
229  if (TimeDiff.QuadPart < 0)
230  {
232  TimeDiff.QuadPart = 2 * TIME_FRAME;
233 
234  /* It's to be saved */
237  }
238 
239  if (TimeDiff.QuadPart == 0)
240  {
241  return STATUS_RETRY;
242  }
243 
244  /* If time diff > 0.1ms, squash it to reduce it to keep our clock resolution */
245  if (TimeDiff.HighPart > 0 || TimeDiff.QuadPart > TICKS_PER_CLOCK_TICK * TIME_FRAME)
246  {
248  }
249 
250  if (TimeDiff.HighPart < 0 || TimeDiff.QuadPart <= TIME_FRAME)
251  {
252  *Range = TimeDiff.QuadPart;
253  ClockDiff.QuadPart = 0LL;
254  }
255  else
256  {
257  *Range = TIME_FRAME;
258  ClockDiff.QuadPart = TimeDiff.QuadPart - TIME_FRAME;
259  --ClockDiff.HighPart;
260  }
261 
262  Time->QuadPart = CurrentTime.QuadPart - *Range - ClockDiff.QuadPart;
263  ExpUuidLastTimeAllocated.QuadPart = CurrentTime.QuadPart - ClockDiff.QuadPart;
264  *Sequence = ExpUuidSequenceNumber;
265 
266  return STATUS_SUCCESS;
267 }
268 
269 /*
270  * @implemented
271  * Warning! This function must be called
272  * with ExpUuidLock held!
273  */
274 static NTSTATUS
276 {
279  ULONG Range;
280  ULONG Sequence;
281 
282  PAGED_CODE();
283 
284  /* Allocate UUIDs */
285  Status = ExpAllocateUuids(&Time, &Range, &Sequence);
286  if (Status == STATUS_RETRY)
287  {
288  return Status;
289  }
290 
291  if (!NT_SUCCESS(Status))
292  {
293  return STATUS_NO_MEMORY;
294  }
295 
296  /* We need at least one UUID */
297  ASSERT(Range != 0);
298 
299  /* Set up our internal cache
300  * See format_uuid_v1 in RFC4122 for magic values
301  */
302  CachedValues->ClockSeqLow = Sequence;
303  CachedValues->ClockSeqHiAndReserved = (Sequence & 0x3F00) >> 8;
304  CachedValues->ClockSeqHiAndReserved |= 0x80;
305  CachedValues->AllocatedCount = Range;
306 
307  /*
308  * Time is relative to UUID time
309  * And we set last time range for all the possibly
310  * returnable UUID
311  */
313  CachedValues->Time = Time.QuadPart + (Range - 1);
314 
315  return STATUS_SUCCESS;
316 }
317 
318 /*
319  * @implemented
320  */
321 CODE_SEG("INIT")
322 BOOLEAN
323 NTAPI
325 {
326  return TRUE;
327 }
328 
329 /*
330  * @implemented
331  */
332 VOID
333 NTAPI
335 {
336  /* Atomically increment the luid */
337  *(LONG64*)LocallyUniqueId = InterlockedExchangeAdd64(&ExpLuid.QuadPart,
339 }
340 
341 
342 /*
343  * @implemented
344  */
345 NTSTATUS
346 NTAPI
348 {
350  PAGED_CODE();
351 
352  /* Probe if user mode */
354  if (PreviousMode != KernelMode)
355  {
356  _SEH2_TRY
357  {
358  ProbeForWrite(LocallyUniqueId,
359  sizeof(LUID),
360  sizeof(ULONG));
361  }
363  {
365  }
366  _SEH2_END;
367  }
368 
369  /* Do the allocation */
370  ExAllocateLocallyUniqueId(LocallyUniqueId);
371  return STATUS_SUCCESS;
372 }
373 
374 /*
375  * @implemented
376  */
377 NTSTATUS
378 NTAPI
380 {
382  LONG AllocatedCount;
384  BOOLEAN Valid;
385 
386  PAGED_CODE();
387 
389  /* Loop until we have an UUID to return */
390  while (TRUE)
391  {
392  /* Try to gather node values */
393  do
394  {
396 
397  RtlCopyMemory(Uuid->Data4,
399  sizeof(Uuid->Data4));
400 
401  Valid = ExpUuidCacheValid;
403  }
404  /* Loop till we can do it without being disturbed */
406 
407  /* We have more than an allocated UUID left, that's OK to return! */
408  if (AllocatedCount >= 0)
409  {
410  break;
411  }
412 
413  /*
414  * Here, we're out of UUIDs, we need to allocate more
415  * We need to be alone to do it, so lock the mutex
416  */
419  {
420  /* If allocation fails, bail out! */
422  if (Status != STATUS_SUCCESS)
423  {
425  return Status;
426  }
427 
428  /* Save our current sequence if changed */
430  }
432  }
433 
434  /*
435  * Once here, we've got an UUID to return
436  * But, if our init wasn't sane, then, make
437  * sure it's only used locally
438  */
439  if (!Valid)
440  {
442  }
443 
444  /* Set our timestamp - see RFC4211 */
445  Time.QuadPart -= AllocatedCount;
446  Uuid->Data1 = Time.LowPart;
447  Uuid->Data2 = Time.HighPart;
448  /* We also set the bit for GUIDv1 */
449  Uuid->Data3 = ((Time.HighPart >> 16) & 0x0FFF) | 0x1000;
450 
451  return Status;
452 }
453 
454 /*
455  * @implemented
456  */
457 NTSTATUS
458 NTAPI
460  OUT PULONG Range,
461  OUT PULONG Sequence,
462  OUT PUCHAR Seed)
463 {
464  ULARGE_INTEGER IntTime;
465  ULONG IntRange, IntSequence;
468 
469  PAGED_CODE();
470 
471  /* Probe if user mode */
473  if (PreviousMode != KernelMode)
474  {
475  _SEH2_TRY
476  {
478  sizeof(ULARGE_INTEGER),
479  sizeof(ULONG));
480 
482  sizeof(ULONG),
483  sizeof(ULONG));
484 
485  ProbeForWrite(Sequence,
486  sizeof(ULONG),
487  sizeof(ULONG));
488 
489  ProbeForWrite(Seed,
491  sizeof(UCHAR));
492  }
494  {
496  }
497  _SEH2_END;
498  }
499 
500  /* During allocation we must be alone */
502 
503  Status = ExpAllocateUuids(&IntTime,
504  &IntRange,
505  &IntSequence);
506  if (!NT_SUCCESS(Status))
507  {
509  return Status;
510  }
511 
512  /* If sequence number was changed, save it */
514 
515  /* Allocation done, so we can release */
517 
518  /* Write back UUIDs to caller */
519  _SEH2_TRY
520  {
521  Time->QuadPart = IntTime.QuadPart;
522  *Range = IntRange;
523  *Sequence = IntSequence;
524 
525  RtlCopyMemory(Seed,
528 
530  }
532  {
534  }
535  _SEH2_END;
536 
537  return Status;
538 }
539 
540 
541 /*
542  * @implemented
543  */
544 NTSTATUS
545 NTAPI
547 {
549  BOOLEAN GotContext;
552  LUID CallerLuid, SystemLuid = SYSTEM_LUID;
553 
554  PAGED_CODE();
555 
556  /* Should only be done by umode */
558 
559  /* No context to release */
560  GotContext = FALSE;
561  _SEH2_TRY
562  {
563  /* Get our caller context and remember to release it */
565  GotContext = TRUE;
566 
567  /* Get caller access token and its associated ID */
569  Status = SeQueryAuthenticationIdToken(Token, &CallerLuid);
570  if (!NT_SUCCESS(Status))
571  {
573  }
574 
575  /* This call is only allowed for SYSTEM */
576  if (!RtlEqualLuid(&CallerLuid, &SystemLuid))
577  {
579  }
580 
581  /* Check for buffer validity and then copy it to our seed */
582  ProbeForRead(Seed, SEED_BUFFER_SIZE, sizeof(UCHAR));
584 
585  /*
586  * According to RFC 4122, UUID seed is based on MAC addresses
587  * If it is randomly set, then, it must have its multicast be set
588  * to be valid and avoid collisions
589  * Reflect it here
590  */
591  ExpUuidCacheValid = ~(*Seed >> 7) & 1;
592 
594  }
596  {
598  }
599  _SEH2_END;
600 
601  /* Release context if required */
602  if (GotContext)
603  {
605  }
606 
607  return Status;
608 }
609 
610 /* EOF */
#define KeQuerySystemTime(t)
Definition: env_spec_w32.h:570
BOOLEAN NTAPI ExLuidInitialization(VOID)
Definition: uuid.c:324
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:66
#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:40
NTSTATUS NTAPI NtAllocateLocallyUniqueId(OUT LUID *LocallyUniqueId)
Definition: uuid.c:347
#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:34
_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:1809
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:52
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
LARGE_INTEGER ExpUuidLastTimeAllocated
Definition: uuid.c:35
unsigned char BOOLEAN
static VOID ExpUuidSaveSequenceNumberIf(VOID)
Definition: uuid.c:173
static NTSTATUS ExpUuidSaveSequenceNumber(PULONG Sequence)
Definition: uuid.c:126
#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:42
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 ASSERT(a)
Definition: mode.c:45
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
ULONG ExpUuidSequenceNumber
Definition: uuid.c:36
static NTSTATUS ExpUuidGetValues(PUUID_CACHED_VALUES_STRUCT CachedValues)
Definition: uuid.c:275
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
CODE_SEG("INIT")
Definition: fsrtlpc.c:19
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:546
#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:38
VOID NTAPI ExAllocateLocallyUniqueId(OUT LUID *LocallyUniqueId)
Definition: uuid.c:334
static NTSTATUS ExpAllocateUuids(PULARGE_INTEGER Time, PULONG Range, PULONG Sequence)
Definition: uuid.c:196
UUID_CACHED_VALUES_STRUCT ExpUuidCachedValues
Definition: uuid.c:39
#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:68
NTSTATUS NTAPI NtAllocateUuids(OUT PULARGE_INTEGER Time, OUT PULONG Range, OUT PULONG Sequence, OUT PUCHAR Seed)
Definition: uuid.c:459
#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:37
UCHAR ClockSeqHiAndReserved
Definition: ex.h:176
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:6
#define STATUS_SUCCESS
Definition: shellext.h:65
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:12
#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:379
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:41