[NTOSKRNL] Rewrite/fix our UUID generation implementation
[reactos.git] / ntoskrnl / ex / uuid.c
index 2a6343f..1f41bdb 100644 (file)
@@ -3,9 +3,9 @@
  * PROJECT:         ReactOS kernel
  * FILE:            ntoskrnl/ex/uuid.c
  * PURPOSE:         UUID generator
- *
  * PROGRAMMERS:     Eric Kohl
-                    Thomas Weidenmueller
+ *                  Thomas Weidenmueller
+ *                  Pierre Schweitzer
  */
 
 /* INCLUDES *****************************************************************/
 #define SECS_15_OCT_1582_TO_1601  ((17 + 30 + 31 + 365 * 18 + 5) * SECSPERDAY)
 #define TICKS_15_OCT_1582_TO_1601 ((ULONGLONG)SECS_15_OCT_1582_TO_1601 * TICKSPERSEC)
 
+/* 10000 in 100-ns model = 0,1 microsecond */
+#define TIME_FRAME 10000
+
 #if defined (ALLOC_PRAGMA)
-#pragma alloc_text(INIT, ExpInitUuids)
+#pragma alloc_text(INIT, ExpUuidInitialization)
+#pragma alloc_text(INIT, ExLuidInitialization)
 #endif
 
 
 /* GLOBALS ****************************************************************/
 
-static FAST_MUTEX UuidMutex;
-static ULARGE_INTEGER UuidLastTime;
-static ULONG UuidSequence;
-static BOOLEAN UuidSequenceInitialized = FALSE;
-static BOOLEAN UuidSequenceChanged = FALSE;
-static UCHAR UuidSeed[SEED_BUFFER_SIZE];
-static ULONG UuidCount;
-static LARGE_INTEGER LuidIncrement;
-static LARGE_INTEGER LuidValue;
+FAST_MUTEX ExpUuidLock;
+LARGE_INTEGER ExpUuidLastTimeAllocated;
+ULONG ExpUuidSequenceNumber = 0;
+BOOLEAN ExpUuidSequenceNumberValid;
+BOOLEAN ExpUuidSequenceNumberNotSaved = FALSE;
+UUID_CACHED_VALUES_STRUCT ExpUuidCachedValues = {0ULL, 0xFFFFFFFF, 0, 0, { 0x80, 0x6E, 0x6F, 0x6E, 0x69, 0x63}};
+BOOLEAN ExpUuidCacheValid = FALSE;
+ULONG ExpLuidIncrement = 1;
+LARGE_INTEGER ExpLuid = {.LowPart = 0x3e9, .HighPart = 0x0};
 
 /* FUNCTIONS ****************************************************************/
 
-VOID
+/*
+ * @implemented
+ */
+BOOLEAN
 INIT_FUNCTION
 NTAPI
-ExpInitUuids(VOID)
+ExpUuidInitialization(VOID)
 {
-    ExInitializeFastMutex(&UuidMutex);
+    ExInitializeFastMutex(&ExpUuidLock);
 
-    KeQuerySystemTime((PLARGE_INTEGER)&UuidLastTime);
-    UuidLastTime.QuadPart += TICKS_15_OCT_1582_TO_1601;
+    ExpUuidSequenceNumberValid = FALSE;
+    KeQuerySystemTime(&ExpUuidLastTimeAllocated);
 
-    UuidCount = TICKS_PER_CLOCK_TICK;
-    RtlZeroMemory(UuidSeed, SEED_BUFFER_SIZE);
+    return TRUE;
 }
 
 
-#define VALUE_BUFFER_SIZE 256
-
+/*
+ * @implemented
+ */
+#define VALUE_BUFFER_SIZE 20
 static NTSTATUS
-ExpLoadUuidSequence(PULONG Sequence)
+ExpUuidLoadSequenceNumber(PULONG Sequence)
 {
     UCHAR ValueBuffer[VALUE_BUFFER_SIZE];
     PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
     OBJECT_ATTRIBUTES ObjectAttributes;
-    UNICODE_STRING Name;
+    UNICODE_STRING KeyName, ValueName;
     HANDLE KeyHandle;
     ULONG ValueLength;
     NTSTATUS Status;
 
-    RtlInitUnicodeString(&Name,
-        L"\\Registry\\Machine\\Software\\Microsoft\\Rpc");
+    PAGED_CODE();
+
+    RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\Software\\Microsoft\\Rpc");
+    RtlInitUnicodeString(&ValueName, L"UuidSequenceNumber");
+
     InitializeObjectAttributes(&ObjectAttributes,
-                               &Name,
-                               OBJ_CASE_INSENSITIVE,
+                               &KeyName,
+                               OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
                                NULL,
                                NULL);
-    Status = ZwOpenKey(&KeyHandle,
-                       KEY_QUERY_VALUE,
-                       &ObjectAttributes);
+    Status = ZwOpenKey(&KeyHandle, GENERIC_READ, &ObjectAttributes);
     if (!NT_SUCCESS(Status))
     {
         DPRINT("ZwOpenKey() failed (Status %lx)\n", Status);
         return Status;
     }
 
-    RtlInitUnicodeString(&Name, L"UuidSequenceNumber");
-
     ValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
     Status = ZwQueryValueKey(KeyHandle,
-                             &Name,
+                             &ValueName,
                              KeyValuePartialInformation,
                              ValueBuffer,
                              VALUE_BUFFER_SIZE,
@@ -105,6 +112,11 @@ ExpLoadUuidSequence(PULONG Sequence)
         return Status;
     }
 
+    if (ValueInfo->Type != REG_DWORD || ValueInfo->DataLength != sizeof(DWORD))
+    {
+        return STATUS_UNSUCCESSFUL;
+    }
+
     *Sequence = *((PULONG)ValueInfo->Data);
 
     DPRINT("Loaded sequence %lx\n", *Sequence);
@@ -113,24 +125,29 @@ ExpLoadUuidSequence(PULONG Sequence)
 }
 #undef VALUE_BUFFER_SIZE
 
-
+/*
+ * @implemented
+ */
 static NTSTATUS
-ExpSaveUuidSequence(PULONG Sequence)
+ExpUuidSaveSequenceNumber(PULONG Sequence)
 {
     OBJECT_ATTRIBUTES ObjectAttributes;
-    UNICODE_STRING Name;
+    UNICODE_STRING KeyName, ValueName;
     HANDLE KeyHandle;
     NTSTATUS Status;
 
-    RtlInitUnicodeString(&Name,
-        L"\\Registry\\Machine\\Software\\Microsoft\\Rpc");
+    PAGED_CODE();
+
+    RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\Software\\Microsoft\\Rpc");
+    RtlInitUnicodeString(&ValueName, L"UuidSequenceNumber");
+
     InitializeObjectAttributes(&ObjectAttributes,
-                               &Name,
-                               OBJ_CASE_INSENSITIVE,
+                               &KeyName,
+                               OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
                                NULL,
                                NULL);
     Status = ZwOpenKey(&KeyHandle,
-                       KEY_SET_VALUE,
+                       GENERIC_READ | GENERIC_WRITE,
                        &ObjectAttributes);
     if (!NT_SUCCESS(Status))
     {
@@ -138,9 +155,8 @@ ExpSaveUuidSequence(PULONG Sequence)
         return Status;
     }
 
-    RtlInitUnicodeString(&Name, L"UuidSequenceNumber");
     Status = ZwSetValueKey(KeyHandle,
-                           &Name,
+                           &ValueName,
                            0,
                            REG_DWORD,
                            Sequence,
@@ -154,118 +170,212 @@ ExpSaveUuidSequence(PULONG Sequence)
     return Status;
 }
 
-
+/*
+ * @implemented
+ * Warning! This function must be called
+ * with ExpUuidLock held!
+ */
 static VOID
-ExpGetRandomUuidSequence(PULONG Sequence)
+ExpUuidSaveSequenceNumberIf(VOID)
 {
-    LARGE_INTEGER Counter;
-    LARGE_INTEGER Frequency;
-    ULONG Value;
-
-    Counter = KeQueryPerformanceCounter(&Frequency);
-    Value = Counter.u.LowPart ^ Counter.u.HighPart;
+    NTSTATUS Status;
 
-    *Sequence = *Sequence ^ Value;
+    PAGED_CODE();
 
-    DPRINT("Sequence %lx\n", *Sequence);
+    /* Only save sequence if it has to */
+    if (ExpUuidSequenceNumberNotSaved == TRUE)
+    {
+        Status = ExpUuidSaveSequenceNumber(&ExpUuidSequenceNumber);
+        if (NT_SUCCESS(Status))
+        {
+            ExpUuidSequenceNumberNotSaved = FALSE;
+        }
+    }
 }
 
-
+/*
+ * @implemented
+ * Warning! This function must be called
+ * with ExpUuidLock held!
+ */
 static NTSTATUS
-ExpCreateUuids(PULARGE_INTEGER Time,
-               PULONG Range,
-               PULONG Sequence)
+ExpAllocateUuids(PULARGE_INTEGER Time,
+                 PULONG Range,
+                 PULONG Sequence)
 {
-    /*
-    * Generate time element of the UUID. Account for going faster
-    * than our clock as well as the clock going backwards.
-    */
-    while (1)
-    {
-        KeQuerySystemTime((PLARGE_INTEGER)Time);
-        Time->QuadPart += TICKS_15_OCT_1582_TO_1601;
+    NTSTATUS Status;
+    LARGE_INTEGER Counter, Frequency, CurrentTime, TimeDiff, ClockDiff;
 
-        if (Time->QuadPart > UuidLastTime.QuadPart)
-        {
-            UuidCount = 0;
-            break;
-        }
+    PAGED_CODE();
 
-        if (Time->QuadPart < UuidLastTime.QuadPart)
+    /* Initialize sequence number */
+    if (!ExpUuidSequenceNumberValid)
+    {
+        /* Try to load sequence number */
+        Status = ExpUuidLoadSequenceNumber(&ExpUuidSequenceNumber);
+        if (NT_SUCCESS(Status))
         {
-            (*Sequence)++;
-            UuidSequenceChanged = TRUE;
-            UuidCount = 0;
-            break;
+            ++ExpUuidSequenceNumber;
         }
-
-        if (UuidCount < TICKS_PER_CLOCK_TICK)
+        else
         {
-            UuidCount++;
-            break;
+            /* If we cannot, generate a "true" random */
+            Counter = KeQueryPerformanceCounter(&Frequency);
+            ExpUuidSequenceNumber ^= (ULONG_PTR)&Status ^ (ULONG_PTR)Sequence ^ Counter.LowPart ^ Counter.HighPart;
         }
+
+        /* It's valid and to be saved */
+        ExpUuidSequenceNumberValid = TRUE;
+        ExpUuidSequenceNumberNotSaved = TRUE;
+    }
+
+    KeQuerySystemTime(&CurrentTime);
+    TimeDiff.QuadPart = CurrentTime.QuadPart - ExpUuidLastTimeAllocated.QuadPart;
+    /* If time went backwards, change sequence (see RFC example) */
+    if (TimeDiff.QuadPart < 0)
+    {
+        ++ExpUuidSequenceNumber;
+        TimeDiff.QuadPart = 2 * TIME_FRAME;
+
+        /* It's to be saved */
+        ExpUuidSequenceNumberNotSaved = TRUE;
+        ExpUuidLastTimeAllocated.QuadPart = CurrentTime.QuadPart - 2 * TIME_FRAME;
+    }
+
+    if (TimeDiff.QuadPart == 0)
+    {
+        return STATUS_RETRY;
+    }
+
+    /* If time diff > 0,1ms, squash it to reduce it to keep our clock resolution */
+    if (TimeDiff.HighPart > 0 || TimeDiff.QuadPart > TICKS_PER_CLOCK_TICK * TIME_FRAME)
+    {
+        TimeDiff.QuadPart = TICKS_PER_CLOCK_TICK * TIME_FRAME;
     }
 
-    UuidLastTime.QuadPart = Time->QuadPart;
-    Time->QuadPart += UuidCount;
+    if (TimeDiff.HighPart < 0 || TimeDiff.QuadPart <= TIME_FRAME)
+    {
+        *Range = TimeDiff.QuadPart;
+        ClockDiff.QuadPart = 0LL;
+    }
+    else
+    {
+        *Range = TIME_FRAME;
+        ClockDiff.QuadPart -= TIME_FRAME;
+        --ClockDiff.HighPart;
+    }
 
-    *Range = 10000; /* What does this mean? Ticks per millisecond?*/
+    Time->QuadPart = CurrentTime.QuadPart - *Range - ClockDiff.QuadPart;
+    ExpUuidLastTimeAllocated.QuadPart = CurrentTime.QuadPart - ClockDiff.QuadPart;
+    *Sequence = ExpUuidSequenceNumber;
 
     return STATUS_SUCCESS;
 }
 
-VOID
-INIT_FUNCTION
-NTAPI
-ExpInitLuid(VOID)
+/*
+ * @implemented
+ * Warning! This function must be called
+ * with ExpUuidLock held!
+ */
+static NTSTATUS
+ExpUuidGetValues(PUUID_CACHED_VALUES_STRUCT CachedValues)
 {
-    LUID DummyLuidValue = SYSTEM_LUID;
+    NTSTATUS Status;
+    ULARGE_INTEGER Time;
+    ULONG Range;
+    ULONG Sequence;
 
-    LuidValue.u.HighPart = DummyLuidValue.HighPart;
-    LuidValue.u.LowPart = DummyLuidValue.LowPart;
-    LuidIncrement.QuadPart = 1;
+    PAGED_CODE();
+
+    /* Allocate UUIDs */
+    Status = ExpAllocateUuids(&Time, &Range, &Sequence);
+    if (Status == STATUS_RETRY)
+    {
+        return Status;
+    }
+
+    if (!NT_SUCCESS(Status))
+    {
+        return STATUS_NO_MEMORY;
+    }
+
+    /* We need at least one UUID */
+    ASSERT(Range != 0);
+
+    /* Set up our internal cache
+     * See format_uuid_v1 in RFC4122 for magic values
+     */
+    CachedValues->ClockSeqLow = Sequence;
+    CachedValues->ClockSeqHiAndReserved = (Sequence & 0x3F00) >> 8;
+    CachedValues->ClockSeqHiAndReserved |= 0x80;
+    CachedValues->AllocatedCount = Range;
+
+    /*
+     * Time is relative to UUID time
+     * And we set last time range for all the possibly
+     * returnable UUID
+     */
+    Time.QuadPart += TICKS_15_OCT_1582_TO_1601;
+    CachedValues->Time = Time.QuadPart + (Range - 1);
+
+    return STATUS_SUCCESS;
 }
 
+/*
+ * @implemented
+ */
+BOOLEAN
+INIT_FUNCTION
+NTAPI
+ExLuidInitialization(VOID)
+{
+    return TRUE;
+}
 
-NTSTATUS
+/*
+ * @implemented
+ */
+VOID
 NTAPI
-ExpAllocateLocallyUniqueId(OUT LUID *LocallyUniqueId)
+ExAllocateLocallyUniqueId(OUT LUID *LocallyUniqueId)
 {
-    LARGE_INTEGER NewLuid, PrevLuid;
+    LARGE_INTEGER PrevLuid;
+    LONGLONG NewLuid, CompLuid;
 
-    /* atomically increment the luid */
-    do
+    /* Atomically increment the luid */
+    PrevLuid.QuadPart = ExpLuid.QuadPart;
+    for (NewLuid = ExpLuid.QuadPart + ExpLuidIncrement; ;
+         NewLuid = PrevLuid.QuadPart + ExpLuidIncrement)
     {
-        PrevLuid = LuidValue;
-        NewLuid = RtlLargeIntegerAdd(PrevLuid,
-                                     LuidIncrement);
-    } while(ExInterlockedCompareExchange64(&LuidValue.QuadPart,
-                                           &NewLuid.QuadPart,
-                                           &PrevLuid.QuadPart,
-                                           NULL) != PrevLuid.QuadPart);
+        CompLuid = InterlockedCompareExchange64(&ExpLuid.QuadPart,
+                                                NewLuid,
+                                                PrevLuid.QuadPart);
+        if (CompLuid == PrevLuid.QuadPart)
+        {
+            break;
+        }
 
-    LocallyUniqueId->LowPart = NewLuid.u.LowPart;
-    LocallyUniqueId->HighPart = NewLuid.u.HighPart;
+        PrevLuid.QuadPart = CompLuid;
+    }
 
-    return STATUS_SUCCESS;
+    LocallyUniqueId->LowPart = PrevLuid.LowPart;
+    LocallyUniqueId->HighPart = PrevLuid.HighPart;
 }
 
 
 /*
  * @implemented
  */
-NTSTATUS NTAPI
+NTSTATUS
+NTAPI
 NtAllocateLocallyUniqueId(OUT LUID *LocallyUniqueId)
 {
-    LUID NewLuid;
     KPROCESSOR_MODE PreviousMode;
-    NTSTATUS Status;
-
     PAGED_CODE();
 
+    /* Probe if user mode */
     PreviousMode = ExGetPreviousMode();
-
-    if(PreviousMode != KernelMode)
+    if (PreviousMode != KernelMode)
     {
         _SEH2_TRY
         {
@@ -280,34 +390,92 @@ NtAllocateLocallyUniqueId(OUT LUID *LocallyUniqueId)
         _SEH2_END;
     }
 
-    Status = ExpAllocateLocallyUniqueId(&NewLuid);
-
-    _SEH2_TRY
-    {
-        *LocallyUniqueId = NewLuid;
-    }
-    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
-    {
-        Status = _SEH2_GetExceptionCode();
-    }
-    _SEH2_END;
-
-    return Status;
+    /* Do the allocation */
+    ExAllocateLocallyUniqueId(LocallyUniqueId);
+    return STATUS_SUCCESS;
 }
 
 /*
- * @unimplemented
+ * @implemented
  */
 NTSTATUS
 NTAPI
 ExUuidCreate(OUT UUID *Uuid)
 {
-    UNIMPLEMENTED;
-    return FALSE;
+    NTSTATUS Status;
+    LONG AllocatedCount;
+    LARGE_INTEGER Time;
+    BOOLEAN Valid;
+
+    PAGED_CODE();
+
+    Status = STATUS_SUCCESS;
+    /* Loop until we have an UUID to return */
+    while (TRUE)
+    {
+        /* Try to gather node values */
+        do
+        {
+            Time.QuadPart = ExpUuidCachedValues.Time;
+
+            RtlCopyMemory(&Uuid->Data4[0],
+                          &ExpUuidCachedValues.NodeId[0],
+                          SEED_BUFFER_SIZE);
+            Valid = ExpUuidCacheValid;
+            AllocatedCount = InterlockedDecrement(&ExpUuidCachedValues.AllocatedCount);
+        }
+        /* Loop till we can do it without being disturbed */
+        while (Time.QuadPart != ExpUuidCachedValues.Time);
+
+        /* We have more than an allocated UUID left, that's OK to return! */
+        if (AllocatedCount >= 0)
+        {
+            break;
+        }
+
+        /*
+         * Here, we're out of UUIDs, we need to allocate more
+         * We need to be alone to do it, so lock the mutex
+         */
+        ExAcquireFastMutex(&ExpUuidLock);
+        if (Time.QuadPart == ExpUuidCachedValues.Time)
+        {
+            /* If allocation fails, bail out! */
+            Status = ExpUuidGetValues(&ExpUuidCachedValues);
+            if (Status != STATUS_SUCCESS)
+            {
+                ExReleaseFastMutex(&ExpUuidLock);
+                return Status;
+            }
+
+            /* Save our current sequence if changed */
+            ExpUuidSaveSequenceNumberIf();
+        }
+        ExReleaseFastMutex(&ExpUuidLock);
+    }
+
+    /*
+     * Once here, we've got an UUID to return
+     * But, if our init wasn't sane, then, make
+     * sure it's only used locally
+     */
+    if (!Valid)
+    {
+        Status = RPC_NT_UUID_LOCAL_ONLY;
+    }
+
+    /* Set our timestamp - see RFC4211 */
+    Time.QuadPart -= AllocatedCount;
+    Uuid->Data1 = Time.LowPart;
+    Uuid->Data2 = Time.HighPart;
+    /* We also set the bit for GUIDv1 */
+    Uuid->Data3 = ((Time.HighPart >> 16) & 0x0FFF) | 0x1000;
+
+    return Status;
 }
 
 /*
- * @unimplemented
+ * @implemented
  */
 NTSTATUS
 NTAPI
@@ -317,56 +485,79 @@ NtAllocateUuids(OUT PULARGE_INTEGER Time,
                 OUT PUCHAR Seed)
 {
     ULARGE_INTEGER IntTime;
-    ULONG IntRange;
+    ULONG IntRange, IntSequence;
     NTSTATUS Status;
+    KPROCESSOR_MODE PreviousMode;
 
     PAGED_CODE();
 
-    ExAcquireFastMutex(&UuidMutex);
-
-    if (!UuidSequenceInitialized)
+    /* Probe if user mode */
+    PreviousMode = ExGetPreviousMode();
+    if (PreviousMode != KernelMode)
     {
-        Status = ExpLoadUuidSequence(&UuidSequence);
-        if (NT_SUCCESS(Status))
+        _SEH2_TRY
         {
-            UuidSequence++;
+            ProbeForWrite(Time,
+                          sizeof(ULARGE_INTEGER),
+                          sizeof(ULONG));
+
+            ProbeForWrite(Range,
+                          sizeof(ULONG),
+                          sizeof(ULONG));
+
+            ProbeForWrite(Sequence,
+                          sizeof(ULONG),
+                          sizeof(ULONG));
+
+            ProbeForWrite(Seed,
+                          SEED_BUFFER_SIZE,
+                          sizeof(UCHAR));
         }
-        else
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
         {
-            ExpGetRandomUuidSequence(&UuidSequence);
+            _SEH2_YIELD(return _SEH2_GetExceptionCode());
         }
-
-        UuidSequenceInitialized = TRUE;
-        UuidSequenceChanged = TRUE;
+        _SEH2_END;
     }
 
-    Status = ExpCreateUuids(&IntTime,
-                            &IntRange,
-                            &UuidSequence);
+    /* During allocation we must be alone */
+    ExAcquireFastMutex(&ExpUuidLock);
+
+    Status = ExpAllocateUuids(&IntTime,
+                              &IntRange,
+                              &IntSequence);
     if (!NT_SUCCESS(Status))
     {
-        ExReleaseFastMutex(&UuidMutex);
+        ExReleaseFastMutex(&ExpUuidLock);
         return Status;
     }
 
-    if (UuidSequenceChanged)
-    {
-        Status = ExpSaveUuidSequence(&UuidSequence);
-        if (NT_SUCCESS(Status))
-            UuidSequenceChanged = FALSE;
-    }
+    /* If sequence number was changed, save it */
+    ExpUuidSaveSequenceNumberIf();
 
-    ExReleaseFastMutex(&UuidMutex);
+    /* Allocation done, so we can release */
+    ExReleaseFastMutex(&ExpUuidLock);
 
-    Time->QuadPart = IntTime.QuadPart;
-    *Range = IntRange;
-    *Sequence = UuidSequence;
+    /* Write back UUIDs to caller */
+    _SEH2_TRY
+    {
+        Time->QuadPart = IntTime.QuadPart;
+        *Range = IntRange;
+        *Sequence = IntSequence;
 
-    RtlCopyMemory(Seed,
-                  UuidSeed,
-                  SEED_BUFFER_SIZE);
+        RtlCopyMemory(Seed,
+                      &ExpUuidCachedValues.NodeId[0],
+                      SEED_BUFFER_SIZE);
 
-    return STATUS_SUCCESS;
+        Status = STATUS_SUCCESS;
+    }
+    _SEH2_EXCEPT(ExSystemExceptionFilter())
+    {
+        Status = _SEH2_GetExceptionCode();
+    }
+    _SEH2_END;
+
+    return Status;
 }
 
 
@@ -377,12 +568,66 @@ NTSTATUS
 NTAPI
 NtSetUuidSeed(IN PUCHAR Seed)
 {
+    NTSTATUS Status;
+    BOOLEAN GotContext;
+    PACCESS_TOKEN Token;
+    SECURITY_SUBJECT_CONTEXT SubjectContext;
+    LUID CallerLuid, SystemLuid = SYSTEM_LUID;
+
     PAGED_CODE();
 
-    RtlCopyMemory(UuidSeed,
-                  Seed,
-                  SEED_BUFFER_SIZE);
-    return STATUS_SUCCESS;
+    /* Should only be done by umode */
+    ASSERT(KeGetPreviousMode() != KernelMode);
+
+    /* No context to release */
+    GotContext = FALSE;
+    _SEH2_TRY
+    {
+        /* Get our caller context and remember to release it */
+        SeCaptureSubjectContext(&SubjectContext);
+        GotContext = TRUE;
+
+        /* Get caller access token and its associated ID */
+        Token = SeQuerySubjectContextToken(&SubjectContext);
+        Status = SeQueryAuthenticationIdToken(Token, &CallerLuid);
+        if (!NT_SUCCESS(Status))
+        {
+            RtlRaiseStatus(Status);
+        }
+
+        /* This call is only allowed for SYSTEM */
+        if (!RtlEqualLuid(&CallerLuid, &SystemLuid))
+        {
+            RtlRaiseStatus(STATUS_ACCESS_DENIED);
+        }
+
+        /* Check for buffer validity and then copy it to our seed */
+        ProbeForRead(Seed, SEED_BUFFER_SIZE, sizeof(UCHAR));
+        RtlCopyMemory(&ExpUuidCachedValues.NodeId[0], Seed, SEED_BUFFER_SIZE);
+
+        /*
+         * According to RFC 4122, UUID seed is based on MAC addresses
+         * If it is randomly set, then, it must have its multicast be set
+         * to be valid and avoid collisions
+         * Reflect it here
+         */
+        ExpUuidCacheValid = ~(*Seed >> 7) & 1;
+
+        Status = STATUS_SUCCESS;
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        Status = _SEH2_GetExceptionCode();
+    }
+    _SEH2_END;
+
+    /* Release context if required */
+    if (GotContext)
+    {
+        SeReleaseSubjectContext(&SubjectContext);
+    }
+
+    return Status;
 }
 
 /* EOF */