2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ex/uuid.c
5 * PURPOSE: UUID generator
7 * PROGRAMMERS: Eric Kohl
11 /* INCLUDES *****************************************************************/
17 #define SEED_BUFFER_SIZE 6
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
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)
29 #if defined (ALLOC_PRAGMA)
30 #pragma alloc_text(INIT, ExpInitUuids)
34 /* GLOBALS ****************************************************************/
36 static FAST_MUTEX UuidMutex
;
37 static ULARGE_INTEGER UuidLastTime
;
38 static ULONG UuidSequence
;
39 static BOOLEAN UuidSequenceInitialized
= FALSE
;
40 static BOOLEAN UuidSequenceChanged
= FALSE
;
41 static UCHAR UuidSeed
[SEED_BUFFER_SIZE
];
42 static ULONG UuidCount
;
43 static LARGE_INTEGER LuidIncrement
;
44 static LARGE_INTEGER LuidValue
;
46 /* FUNCTIONS ****************************************************************/
53 ExInitializeFastMutex(&UuidMutex
);
55 KeQuerySystemTime((PLARGE_INTEGER
)&UuidLastTime
);
56 UuidLastTime
.QuadPart
+= TICKS_15_OCT_1582_TO_1601
;
58 UuidCount
= TICKS_PER_CLOCK_TICK
;
59 RtlZeroMemory(UuidSeed
, SEED_BUFFER_SIZE
);
63 #define VALUE_BUFFER_SIZE 256
66 ExpLoadUuidSequence(PULONG Sequence
)
68 UCHAR ValueBuffer
[VALUE_BUFFER_SIZE
];
69 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
;
70 OBJECT_ATTRIBUTES ObjectAttributes
;
76 RtlInitUnicodeString(&Name
,
77 L
"\\Registry\\Machine\\Software\\Microsoft\\Rpc");
78 InitializeObjectAttributes(&ObjectAttributes
,
83 Status
= ZwOpenKey(&KeyHandle
,
86 if (!NT_SUCCESS(Status
))
88 DPRINT("ZwOpenKey() failed (Status %lx)\n", Status
);
92 RtlInitUnicodeString(&Name
, L
"UuidSequenceNumber");
94 ValueInfo
= (PKEY_VALUE_PARTIAL_INFORMATION
)ValueBuffer
;
95 Status
= ZwQueryValueKey(KeyHandle
,
97 KeyValuePartialInformation
,
102 if (!NT_SUCCESS(Status
))
104 DPRINT("ZwQueryValueKey() failed (Status %lx)\n", Status
);
108 *Sequence
= *((PULONG
)ValueInfo
->Data
);
110 DPRINT("Loaded sequence %lx\n", *Sequence
);
112 return STATUS_SUCCESS
;
114 #undef VALUE_BUFFER_SIZE
118 ExpSaveUuidSequence(PULONG Sequence
)
120 OBJECT_ATTRIBUTES ObjectAttributes
;
125 RtlInitUnicodeString(&Name
,
126 L
"\\Registry\\Machine\\Software\\Microsoft\\Rpc");
127 InitializeObjectAttributes(&ObjectAttributes
,
129 OBJ_CASE_INSENSITIVE
,
132 Status
= ZwOpenKey(&KeyHandle
,
135 if (!NT_SUCCESS(Status
))
137 DPRINT("ZwOpenKey() failed (Status %lx)\n", Status
);
141 RtlInitUnicodeString(&Name
, L
"UuidSequenceNumber");
142 Status
= ZwSetValueKey(KeyHandle
,
149 if (!NT_SUCCESS(Status
))
151 DPRINT("ZwSetValueKey() failed (Status %lx)\n", Status
);
159 ExpGetRandomUuidSequence(PULONG Sequence
)
161 LARGE_INTEGER Counter
;
162 LARGE_INTEGER Frequency
;
165 Counter
= KeQueryPerformanceCounter(&Frequency
);
166 Value
= Counter
.u
.LowPart
^ Counter
.u
.HighPart
;
168 *Sequence
= *Sequence
^ Value
;
170 DPRINT("Sequence %lx\n", *Sequence
);
175 ExpCreateUuids(PULARGE_INTEGER Time
,
180 * Generate time element of the UUID. Account for going faster
181 * than our clock as well as the clock going backwards.
185 KeQuerySystemTime((PLARGE_INTEGER
)Time
);
186 Time
->QuadPart
+= TICKS_15_OCT_1582_TO_1601
;
188 if (Time
->QuadPart
> UuidLastTime
.QuadPart
)
194 if (Time
->QuadPart
< UuidLastTime
.QuadPart
)
197 UuidSequenceChanged
= TRUE
;
202 if (UuidCount
< TICKS_PER_CLOCK_TICK
)
209 UuidLastTime
.QuadPart
= Time
->QuadPart
;
210 Time
->QuadPart
+= UuidCount
;
212 *Range
= 10000; /* What does this mean? Ticks per millisecond?*/
214 return STATUS_SUCCESS
;
222 LUID DummyLuidValue
= SYSTEM_LUID
;
224 LuidValue
.u
.HighPart
= DummyLuidValue
.HighPart
;
225 LuidValue
.u
.LowPart
= DummyLuidValue
.LowPart
;
226 LuidIncrement
.QuadPart
= 1;
232 ExAllocateLocallyUniqueId(OUT LUID
*LocallyUniqueId
)
234 LARGE_INTEGER NewLuid
, PrevLuid
;
236 /* atomically increment the luid */
239 PrevLuid
= LuidValue
;
240 NewLuid
= RtlLargeIntegerAdd(PrevLuid
,
242 } while(ExInterlockedCompareExchange64(&LuidValue
.QuadPart
,
245 NULL
) != PrevLuid
.QuadPart
);
247 LocallyUniqueId
->LowPart
= NewLuid
.u
.LowPart
;
248 LocallyUniqueId
->HighPart
= NewLuid
.u
.HighPart
;
257 NtAllocateLocallyUniqueId(OUT LUID
*LocallyUniqueId
)
260 KPROCESSOR_MODE PreviousMode
;
264 /* Probe if user mode */
265 PreviousMode
= ExGetPreviousMode();
266 if (PreviousMode
!= KernelMode
)
270 ProbeForWrite(LocallyUniqueId
,
274 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
276 _SEH2_YIELD(return _SEH2_GetExceptionCode());
281 /* Do the allocation */
282 ExAllocateLocallyUniqueId(&NewLuid
);
283 Status
= STATUS_SUCCESS
;
285 /* Write back LUID to caller */
288 *LocallyUniqueId
= NewLuid
;
290 _SEH2_EXCEPT(ExSystemExceptionFilter())
292 Status
= _SEH2_GetExceptionCode();
303 ExUuidCreate(OUT UUID
*Uuid
)
314 NtAllocateUuids(OUT PULARGE_INTEGER Time
,
319 ULARGE_INTEGER IntTime
;
322 KPROCESSOR_MODE PreviousMode
;
326 /* Probe if user mode */
327 PreviousMode
= ExGetPreviousMode();
328 if (PreviousMode
!= KernelMode
)
333 sizeof(ULARGE_INTEGER
),
340 ProbeForWrite(Sequence
,
348 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
350 _SEH2_YIELD(return _SEH2_GetExceptionCode());
355 ExAcquireFastMutex(&UuidMutex
);
357 if (!UuidSequenceInitialized
)
359 Status
= ExpLoadUuidSequence(&UuidSequence
);
360 if (NT_SUCCESS(Status
))
366 ExpGetRandomUuidSequence(&UuidSequence
);
369 UuidSequenceInitialized
= TRUE
;
370 UuidSequenceChanged
= TRUE
;
373 Status
= ExpCreateUuids(&IntTime
,
376 if (!NT_SUCCESS(Status
))
378 ExReleaseFastMutex(&UuidMutex
);
382 if (UuidSequenceChanged
)
384 Status
= ExpSaveUuidSequence(&UuidSequence
);
385 if (NT_SUCCESS(Status
))
386 UuidSequenceChanged
= FALSE
;
389 ExReleaseFastMutex(&UuidMutex
);
391 /* Write back LUID to caller */
394 Time
->QuadPart
= IntTime
.QuadPart
;
396 *Sequence
= UuidSequence
;
402 _SEH2_EXCEPT(ExSystemExceptionFilter())
404 Status
= _SEH2_GetExceptionCode();
408 return STATUS_SUCCESS
;
417 NtSetUuidSeed(IN PUCHAR Seed
)
422 SECURITY_SUBJECT_CONTEXT SubjectContext
;
423 LUID CallerLuid
, SystemLuid
= SYSTEM_LUID
;
427 /* Should only be done by umode */
428 ASSERT(KeGetPreviousMode() != KernelMode
);
430 /* No context to release */
434 /* Get our caller context and remember to release it */
435 SeCaptureSubjectContext(&SubjectContext
);
438 /* Get caller access token and its associated ID */
439 Token
= SeQuerySubjectContextToken(&SubjectContext
);
440 Status
= SeQueryAuthenticationIdToken(Token
, &CallerLuid
);
441 if (!NT_SUCCESS(Status
))
443 RtlRaiseStatus(Status
);
446 /* This call is only allowed for SYSTEM */
447 if (!RtlEqualLuid(&CallerLuid
, &SystemLuid
))
449 RtlRaiseStatus(STATUS_ACCESS_DENIED
);
452 /* Check for buffer validity and then copy it to our seed */
453 ProbeForRead(Seed
, SEED_BUFFER_SIZE
, 1);
454 RtlCopyMemory(UuidSeed
, Seed
, SEED_BUFFER_SIZE
);
456 Status
= STATUS_SUCCESS
;
458 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
460 Status
= _SEH2_GetExceptionCode();
464 /* Release context if required */
467 SeReleaseSubjectContext(&SubjectContext
);