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 */ 9 10 /* INCLUDES *****************************************************************/ 11 12 #include <ntoskrnl.h> 13 #define NDEBUG 14 #include <debug.h> 15 16 #define SEED_BUFFER_SIZE 6 17 18 /* Number of 100ns ticks per clock tick. To be safe, assume that the clock 19 resolution is at least 1000 * 100 * (1/1000000) = 1/10 of a second */ 20 #define TICKS_PER_CLOCK_TICK 1000 21 #define SECSPERDAY 86400 22 #define TICKSPERSEC 10000000 23 24 /* UUID system time starts at October 15, 1582 */ 25 #define SECS_15_OCT_1582_TO_1601 ((17 + 30 + 31 + 365 * 18 + 5) * SECSPERDAY) 26 #define TICKS_15_OCT_1582_TO_1601 ((ULONGLONG)SECS_15_OCT_1582_TO_1601 * TICKSPERSEC) 27 28 #if defined (ALLOC_PRAGMA) 29 #pragma alloc_text(INIT, ExpInitUuids) 30 #endif 31 32 33 /* GLOBALS ****************************************************************/ 34 35 static FAST_MUTEX UuidMutex; 36 static ULARGE_INTEGER UuidLastTime; 37 static ULONG UuidSequence; 38 static BOOLEAN UuidSequenceInitialized = FALSE; 39 static BOOLEAN UuidSequenceChanged = FALSE; 40 static UCHAR UuidSeed[SEED_BUFFER_SIZE]; 41 static ULONG UuidCount; 42 static LARGE_INTEGER LuidIncrement; 43 static LARGE_INTEGER LuidValue; 44 45 /* FUNCTIONS ****************************************************************/ 46 47 VOID 48 INIT_FUNCTION 49 NTAPI 50 ExpInitUuids(VOID) 51 { 52 ExInitializeFastMutex(&UuidMutex); 53 54 KeQuerySystemTime((PLARGE_INTEGER)&UuidLastTime); 55 UuidLastTime.QuadPart += TICKS_15_OCT_1582_TO_1601; 56 57 UuidCount = TICKS_PER_CLOCK_TICK; 58 RtlZeroMemory(UuidSeed, SEED_BUFFER_SIZE); 59 } 60 61 62 #define VALUE_BUFFER_SIZE 256 63 64 static NTSTATUS 65 ExpLoadUuidSequence(PULONG Sequence) 66 { 67 UCHAR ValueBuffer[VALUE_BUFFER_SIZE]; 68 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo; 69 OBJECT_ATTRIBUTES ObjectAttributes; 70 UNICODE_STRING Name; 71 HANDLE KeyHandle; 72 ULONG ValueLength; 73 NTSTATUS Status; 74 75 RtlInitUnicodeString(&Name, 76 L"\\Registry\\Machine\\Software\\Microsoft\\Rpc"); 77 InitializeObjectAttributes(&ObjectAttributes, 78 &Name, 79 OBJ_CASE_INSENSITIVE, 80 NULL, 81 NULL); 82 Status = ZwOpenKey(&KeyHandle, 83 KEY_QUERY_VALUE, 84 &ObjectAttributes); 85 if (!NT_SUCCESS(Status)) 86 { 87 DPRINT("ZwOpenKey() failed (Status %lx)\n", Status); 88 return Status; 89 } 90 91 RtlInitUnicodeString(&Name, L"UuidSequenceNumber"); 92 93 ValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer; 94 Status = ZwQueryValueKey(KeyHandle, 95 &Name, 96 KeyValuePartialInformation, 97 ValueBuffer, 98 VALUE_BUFFER_SIZE, 99 &ValueLength); 100 ZwClose(KeyHandle); 101 if (!NT_SUCCESS(Status)) 102 { 103 DPRINT("ZwQueryValueKey() failed (Status %lx)\n", Status); 104 return Status; 105 } 106 107 *Sequence = *((PULONG)ValueInfo->Data); 108 109 DPRINT("Loaded sequence %lx\n", *Sequence); 110 111 return STATUS_SUCCESS; 112 } 113 #undef VALUE_BUFFER_SIZE 114 115 116 static NTSTATUS 117 ExpSaveUuidSequence(PULONG Sequence) 118 { 119 OBJECT_ATTRIBUTES ObjectAttributes; 120 UNICODE_STRING Name; 121 HANDLE KeyHandle; 122 NTSTATUS Status; 123 124 RtlInitUnicodeString(&Name, 125 L"\\Registry\\Machine\\Software\\Microsoft\\Rpc"); 126 InitializeObjectAttributes(&ObjectAttributes, 127 &Name, 128 OBJ_CASE_INSENSITIVE, 129 NULL, 130 NULL); 131 Status = ZwOpenKey(&KeyHandle, 132 KEY_SET_VALUE, 133 &ObjectAttributes); 134 if (!NT_SUCCESS(Status)) 135 { 136 DPRINT("ZwOpenKey() failed (Status %lx)\n", Status); 137 return Status; 138 } 139 140 RtlInitUnicodeString(&Name, L"UuidSequenceNumber"); 141 Status = ZwSetValueKey(KeyHandle, 142 &Name, 143 0, 144 REG_DWORD, 145 Sequence, 146 sizeof(ULONG)); 147 ZwClose(KeyHandle); 148 if (!NT_SUCCESS(Status)) 149 { 150 DPRINT("ZwSetValueKey() failed (Status %lx)\n", Status); 151 } 152 153 return Status; 154 } 155 156 157 static VOID 158 ExpGetRandomUuidSequence(PULONG Sequence) 159 { 160 LARGE_INTEGER Counter; 161 LARGE_INTEGER Frequency; 162 ULONG Value; 163 164 Counter = KeQueryPerformanceCounter(&Frequency); 165 Value = Counter.u.LowPart ^ Counter.u.HighPart; 166 167 *Sequence = *Sequence ^ Value; 168 169 DPRINT("Sequence %lx\n", *Sequence); 170 } 171 172 173 static NTSTATUS 174 ExpCreateUuids(PULARGE_INTEGER Time, 175 PULONG Range, 176 PULONG Sequence) 177 { 178 /* 179 * Generate time element of the UUID. Account for going faster 180 * than our clock as well as the clock going backwards. 181 */ 182 while (1) 183 { 184 KeQuerySystemTime((PLARGE_INTEGER)Time); 185 Time->QuadPart += TICKS_15_OCT_1582_TO_1601; 186 187 if (Time->QuadPart > UuidLastTime.QuadPart) 188 { 189 UuidCount = 0; 190 break; 191 } 192 193 if (Time->QuadPart < UuidLastTime.QuadPart) 194 { 195 (*Sequence)++; 196 UuidSequenceChanged = TRUE; 197 UuidCount = 0; 198 break; 199 } 200 201 if (UuidCount < TICKS_PER_CLOCK_TICK) 202 { 203 UuidCount++; 204 break; 205 } 206 } 207 208 UuidLastTime.QuadPart = Time->QuadPart; 209 Time->QuadPart += UuidCount; 210 211 *Range = 10000; /* What does this mean? Ticks per millisecond?*/ 212 213 return STATUS_SUCCESS; 214 } 215 216 VOID 217 INIT_FUNCTION 218 NTAPI 219 ExpInitLuid(VOID) 220 { 221 LUID DummyLuidValue = SYSTEM_LUID; 222 223 LuidValue.u.HighPart = DummyLuidValue.HighPart; 224 LuidValue.u.LowPart = DummyLuidValue.LowPart; 225 LuidIncrement.QuadPart = 1; 226 } 227 228 229 VOID 230 NTAPI 231 ExAllocateLocallyUniqueId(OUT LUID *LocallyUniqueId) 232 { 233 LARGE_INTEGER NewLuid, PrevLuid; 234 235 /* atomically increment the luid */ 236 do 237 { 238 PrevLuid = LuidValue; 239 NewLuid = RtlLargeIntegerAdd(PrevLuid, 240 LuidIncrement); 241 } while(ExInterlockedCompareExchange64(&LuidValue.QuadPart, 242 &NewLuid.QuadPart, 243 &PrevLuid.QuadPart, 244 NULL) != PrevLuid.QuadPart); 245 246 LocallyUniqueId->LowPart = NewLuid.u.LowPart; 247 LocallyUniqueId->HighPart = NewLuid.u.HighPart; 248 } 249 250 251 /* 252 * @implemented 253 */ 254 NTSTATUS 255 NTAPI 256 NtAllocateLocallyUniqueId(OUT LUID *LocallyUniqueId) 257 { 258 LUID NewLuid; 259 KPROCESSOR_MODE PreviousMode; 260 NTSTATUS Status; 261 PAGED_CODE(); 262 263 /* Probe if user mode */ 264 PreviousMode = ExGetPreviousMode(); 265 if (PreviousMode != KernelMode) 266 { 267 _SEH2_TRY 268 { 269 ProbeForWrite(LocallyUniqueId, 270 sizeof(LUID), 271 sizeof(ULONG)); 272 } 273 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 274 { 275 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 276 } 277 _SEH2_END; 278 } 279 280 /* Do the allocation */ 281 ExAllocateLocallyUniqueId(&NewLuid); 282 Status = STATUS_SUCCESS; 283 284 /* Write back LUID to caller */ 285 _SEH2_TRY 286 { 287 *LocallyUniqueId = NewLuid; 288 } 289 _SEH2_EXCEPT(ExSystemExceptionFilter()) 290 { 291 Status = _SEH2_GetExceptionCode(); 292 } 293 _SEH2_END; 294 return Status; 295 } 296 297 /* 298 * @unimplemented 299 */ 300 NTSTATUS 301 NTAPI 302 ExUuidCreate(OUT UUID *Uuid) 303 { 304 UNIMPLEMENTED; 305 return FALSE; 306 } 307 308 /* 309 * @unimplemented 310 */ 311 NTSTATUS 312 NTAPI 313 NtAllocateUuids(OUT PULARGE_INTEGER Time, 314 OUT PULONG Range, 315 OUT PULONG Sequence, 316 OUT PUCHAR Seed) 317 { 318 ULARGE_INTEGER IntTime; 319 ULONG IntRange; 320 NTSTATUS Status; 321 KPROCESSOR_MODE PreviousMode; 322 323 PAGED_CODE(); 324 325 /* Probe if user mode */ 326 PreviousMode = ExGetPreviousMode(); 327 if (PreviousMode != KernelMode) 328 { 329 _SEH2_TRY 330 { 331 ProbeForWrite(Time, 332 sizeof(ULARGE_INTEGER), 333 sizeof(ULONG)); 334 335 ProbeForWrite(Range, 336 sizeof(ULONG), 337 sizeof(ULONG)); 338 339 ProbeForWrite(Sequence, 340 sizeof(ULONG), 341 sizeof(ULONG)); 342 343 ProbeForWrite(Seed, 344 SEED_BUFFER_SIZE, 345 sizeof(UCHAR)); 346 } 347 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 348 { 349 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 350 } 351 _SEH2_END; 352 } 353 354 ExAcquireFastMutex(&UuidMutex); 355 356 if (!UuidSequenceInitialized) 357 { 358 Status = ExpLoadUuidSequence(&UuidSequence); 359 if (NT_SUCCESS(Status)) 360 { 361 UuidSequence++; 362 } 363 else 364 { 365 ExpGetRandomUuidSequence(&UuidSequence); 366 } 367 368 UuidSequenceInitialized = TRUE; 369 UuidSequenceChanged = TRUE; 370 } 371 372 Status = ExpCreateUuids(&IntTime, 373 &IntRange, 374 &UuidSequence); 375 if (!NT_SUCCESS(Status)) 376 { 377 ExReleaseFastMutex(&UuidMutex); 378 return Status; 379 } 380 381 if (UuidSequenceChanged) 382 { 383 Status = ExpSaveUuidSequence(&UuidSequence); 384 if (NT_SUCCESS(Status)) 385 UuidSequenceChanged = FALSE; 386 } 387 388 ExReleaseFastMutex(&UuidMutex); 389 390 /* Write back UUIDs to caller */ 391 _SEH2_TRY 392 { 393 Time->QuadPart = IntTime.QuadPart; 394 *Range = IntRange; 395 *Sequence = UuidSequence; 396 397 RtlCopyMemory(Seed, 398 UuidSeed, 399 SEED_BUFFER_SIZE); 400 401 Status = STATUS_SUCCESS; 402 } 403 _SEH2_EXCEPT(ExSystemExceptionFilter()) 404 { 405 Status = _SEH2_GetExceptionCode(); 406 } 407 _SEH2_END; 408 409 return Status; 410 } 411 412 413 /* 414 * @implemented 415 */ 416 NTSTATUS 417 NTAPI 418 NtSetUuidSeed(IN PUCHAR Seed) 419 { 420 NTSTATUS Status; 421 BOOLEAN GotContext; 422 PACCESS_TOKEN Token; 423 SECURITY_SUBJECT_CONTEXT SubjectContext; 424 LUID CallerLuid, SystemLuid = SYSTEM_LUID; 425 426 PAGED_CODE(); 427 428 /* Should only be done by umode */ 429 ASSERT(KeGetPreviousMode() != KernelMode); 430 431 /* No context to release */ 432 GotContext = FALSE; 433 _SEH2_TRY 434 { 435 /* Get our caller context and remember to release it */ 436 SeCaptureSubjectContext(&SubjectContext); 437 GotContext = TRUE; 438 439 /* Get caller access token and its associated ID */ 440 Token = SeQuerySubjectContextToken(&SubjectContext); 441 Status = SeQueryAuthenticationIdToken(Token, &CallerLuid); 442 if (!NT_SUCCESS(Status)) 443 { 444 RtlRaiseStatus(Status); 445 } 446 447 /* This call is only allowed for SYSTEM */ 448 if (!RtlEqualLuid(&CallerLuid, &SystemLuid)) 449 { 450 RtlRaiseStatus(STATUS_ACCESS_DENIED); 451 } 452 453 /* Check for buffer validity and then copy it to our seed */ 454 ProbeForRead(Seed, SEED_BUFFER_SIZE, sizeof(UCHAR)); 455 RtlCopyMemory(UuidSeed, Seed, SEED_BUFFER_SIZE); 456 457 Status = STATUS_SUCCESS; 458 } 459 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 460 { 461 Status = _SEH2_GetExceptionCode(); 462 } 463 _SEH2_END; 464 465 /* Release context if required */ 466 if (GotContext) 467 { 468 SeReleaseSubjectContext(&SubjectContext); 469 } 470 471 return Status; 472 } 473 474 /* EOF */ 475