00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
#include "exp.h"
00040
00041
00042
00043
00044
00045
00046
00047
00048 #define RPC_SEQUENCE_NUMBER_PATH L"\\Registry\\Machine\\Software\\Microsoft\\Rpc"
00049 #define RPC_SEQUENCE_NUMBER_NAME L"UuidSequenceNumber"
00050
00051
00052 #define UUID_TIME_HIGH_MASK 0x0FFF
00053 #define UUID_VERSION 0x1000
00054 #define UUID_RESERVED 0x80
00055 #define UUID_CLOCK_SEQ_HI_MASK 0x3F
00056
00057
00058 #define CACHE_LOCAL_ONLY 0
00059 #define CACHE_VALID 1
00060
00061
00062
00063
00064
00065
00066 typedef struct _UUID_GENERATE {
00067 ULONG
TimeLow;
00068 USHORT TimeMid;
00069 USHORT TimeHiAndVersion;
00070 UCHAR
ClockSeqHiAndReserved;
00071 UCHAR
ClockSeqLow;
00072 UCHAR
NodeId[6];
00073 }
UUID_GENERATE;
00074
00075
00076 typedef struct _UUID_CACHED_VALUES_STRUCT {
00077 ULONGLONG
Time;
00078 LONG
AllocatedCount;
00079 UCHAR
ClockSeqHiAndReserved;
00080 UCHAR
ClockSeqLow;
00081 UCHAR
NodeId[6];
00082 }
UUID_CACHED_VALUES_STRUCT;
00083
00084
00085
00086
00087
00088
00089
00090 LARGE_INTEGER
ExpUuidLastTimeAllocated;
00091 BOOLEAN
ExpUuidCacheValid =
CACHE_LOCAL_ONLY;
00092
00093
00094
00095 UUID_CACHED_VALUES_STRUCT ExpUuidCachedValues = { 0, -1, 0, 0, { 0x80,
'm',
'a',
'r',
'i',
'o' }};
00096
00097
00098 ULONG
ExpUuidSequenceNumber;
00099 BOOLEAN
ExpUuidSequenceNumberValid;
00100 BOOLEAN
ExpUuidSequenceNumberNotSaved;
00101
00102
00103 FAST_MUTEX ExpUuidLock;
00104
00105
00106
00107
00108
00109
extern NTSTATUS ExpUuidLoadSequenceNumber(
00110 OUT PULONG
00111 );
00112
00113
extern NTSTATUS ExpUuidSaveSequenceNumber(
00114 IN ULONG
00115 );
00116
00117
extern NTSTATUS ExpUuidSaveSequenceNumberIf ();
00118
00119
extern NTSTATUS ExpUuidGetValues(
00120 OUT
UUID_CACHED_VALUES_STRUCT *Values
00121 );
00122
00123
00124
#ifdef ALLOC_PRAGMA
00125
#pragma alloc_text(PAGE, ExpUuidLoadSequenceNumber)
00126
#pragma alloc_text(PAGE, ExpUuidSaveSequenceNumber)
00127
#pragma alloc_text(PAGE, ExpUuidSaveSequenceNumberIf)
00128
#pragma alloc_text(INIT, ExpUuidInitialization)
00129
#pragma alloc_text(PAGE, NtAllocateUuids)
00130
#pragma alloc_text(PAGE, NtSetUuidSeed)
00131
#pragma alloc_text(PAGE, ExpUuidGetValues)
00132
#pragma alloc_text(PAGE, ExUuidCreate)
00133
#endif
00134
00135
00136
NTSTATUS
00137 ExpUuidLoadSequenceNumber(
00138 OUT PULONG Sequence
00139 )
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162 {
00163
NTSTATUS Status;
00164 OBJECT_ATTRIBUTES
ObjectAttributes;
00165 UNICODE_STRING
KeyPath,
KeyName;
00166 HANDLE
Key;
00167
CHAR KeyValueBuffer[
sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
sizeof(ULONG)];
00168 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
00169 ULONG ResultLength;
00170
00171
PAGED_CODE();
00172
00173 KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)KeyValueBuffer;
00174
00175
RtlInitUnicodeString(&
KeyPath,
RPC_SEQUENCE_NUMBER_PATH);
00176
RtlInitUnicodeString(&
KeyName,
RPC_SEQUENCE_NUMBER_NAME);
00177
00178 InitializeObjectAttributes( &
ObjectAttributes,
00179 &
KeyPath,
00180 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
00181
NULL,
00182
NULL
00183 );
00184
00185
Status =
00186 ZwOpenKey( &
Key,
00187 GENERIC_READ,
00188 &
ObjectAttributes
00189 );
00190
00191
if (
NT_SUCCESS(
Status)) {
00192
Status =
00193 ZwQueryValueKey(
Key,
00194 &
KeyName,
00195 KeyValuePartialInformation,
00196 KeyValueInformation,
00197
sizeof(KeyValueBuffer),
00198 &ResultLength
00199 );
00200
00201 ZwClose(
Key );
00202 }
00203
00204
if (
NT_SUCCESS(
Status)) {
00205
if ( KeyValueInformation->Type == REG_DWORD &&
00206 KeyValueInformation->DataLength ==
sizeof(ULONG)
00207 ) {
00208 *Sequence = *(PULONG)KeyValueInformation->Data;
00209 }
00210
else {
00211
Status = STATUS_UNSUCCESSFUL;
00212 }
00213 }
00214
00215
return(
Status);
00216 }
00217
00218
00219
NTSTATUS
00220 ExpUuidSaveSequenceNumber(
00221 IN ULONG Sequence
00222 )
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244 {
00245
NTSTATUS Status;
00246 OBJECT_ATTRIBUTES
ObjectAttributes;
00247 UNICODE_STRING
KeyPath,
KeyName;
00248 HANDLE
Key;
00249
00250
PAGED_CODE();
00251
00252
RtlInitUnicodeString(&
KeyPath,
RPC_SEQUENCE_NUMBER_PATH);
00253
RtlInitUnicodeString(&
KeyName,
RPC_SEQUENCE_NUMBER_NAME);
00254
00255 InitializeObjectAttributes( &
ObjectAttributes,
00256 &
KeyPath,
00257 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
00258
NULL,
00259
NULL
00260 );
00261
00262
Status =
00263 ZwOpenKey( &
Key,
00264 GENERIC_READ | GENERIC_WRITE,
00265 &
ObjectAttributes
00266 );
00267
00268
if (
NT_SUCCESS(
Status)) {
00269
Status =
00270 ZwSetValueKey(
Key,
00271 &
KeyName,
00272 0,
00273 REG_DWORD,
00274 &Sequence,
00275
sizeof(ULONG)
00276 );
00277
00278 ZwClose(
Key );
00279 }
00280
00281
return(
Status);
00282 }
00283
00284
00285
00286
NTSTATUS
00287 ExpUuidSaveSequenceNumberIf ()
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310 {
00311
NTSTATUS Status = STATUS_SUCCESS;
00312
00313
PAGED_CODE();
00314
00315
00316
if (
ExpUuidSequenceNumberNotSaved ==
TRUE) {
00317
00318
00319
00320
00321 KdPrint((
"Uuid: Saving new sequence number.\n"));
00322
00323
00324
00325
Status =
ExpUuidSaveSequenceNumber(
ExpUuidSequenceNumber);
00326
00327
00328
if (
NT_SUCCESS(
Status)) {
00329
ExpUuidSequenceNumberNotSaved =
FALSE;
00330 }
00331 }
00332
00333
return(
Status );
00334 }
00335
00336
00337
00338
00339 BOOLEAN
00340 ExpUuidInitialization (
00341 VOID
00342 )
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360 {
00361
NTSTATUS Status;
00362
00363
PAGED_CODE();
00364
00365
ExInitializeFastMutex(&
ExpUuidLock);
00366
00367
ExpUuidSequenceNumberValid =
FALSE;
00368
00369
00370
00371
KeQuerySystemTime(&
ExpUuidLastTimeAllocated);
00372
00373
return TRUE;
00374 }
00375
00376
00377
NTSTATUS
00378 ExpAllocateUuids (
00379 OUT PLARGE_INTEGER Time,
00380 OUT PULONG Range,
00381 OUT PULONG Sequence
00382 )
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421 {
00422
NTSTATUS Status;
00423 LARGE_INTEGER CurrentTime;
00424 LARGE_INTEGER AvailableTime;
00425
00426
PAGED_CODE();
00427
00428
00429
00430
00431
00432
if (
ExpUuidSequenceNumberValid ==
FALSE) {
00433
00434
Status =
ExpUuidLoadSequenceNumber(&
ExpUuidSequenceNumber);
00435
00436
if (!
NT_SUCCESS(
Status)) {
00437
00438
00439 LARGE_INTEGER PerfCounter;
00440 LARGE_INTEGER PerfFrequency;
00441
00442
00443
00444
00445 KdPrint((
"Uuid: Generating first sequence number.\n"));
00446
00447 PerfCounter =
KeQueryPerformanceCounter(&PerfFrequency);
00448
00449
ExpUuidSequenceNumber ^= (ULONG)((ULONG_PTR)&
Status) ^ PerfCounter.LowPart ^
00450 PerfCounter.HighPart ^ (ULONG)((ULONG_PTR)Sequence);
00451 }
00452
else {
00453
00454
ExpUuidSequenceNumber++;
00455 }
00456
00457
ExpUuidSequenceNumberValid =
TRUE;
00458
ExpUuidSequenceNumberNotSaved =
TRUE;
00459
00460 }
00461
00462
00463
00464
00465
00466
00467
00468
KeQuerySystemTime(&CurrentTime);
00469
00470 AvailableTime.QuadPart = CurrentTime.QuadPart -
ExpUuidLastTimeAllocated.QuadPart;
00471
00472
if (AvailableTime.QuadPart < 0) {
00473
00474
00475
00476
00477
00478
ExpUuidSequenceNumberNotSaved =
TRUE;
00479
ExpUuidSequenceNumber++;
00480
00481
00482
00483
00484
00485
ExpUuidLastTimeAllocated.QuadPart = CurrentTime.QuadPart - 20000;
00486 AvailableTime.QuadPart = 20000;
00487 }
00488
00489
if (AvailableTime.QuadPart == 0) {
00490
00491
return(STATUS_RETRY);
00492 }
00493
00494
00495
00496
00497
00498
if (AvailableTime.QuadPart > 10*1000*1000) {
00499
00500 AvailableTime.QuadPart = 10*1000*1000;
00501 }
00502
00503
if (AvailableTime.QuadPart > 10*1000) {
00504
00505
00506 *Range = 10*1000;
00507 AvailableTime.QuadPart -= 10*1000;
00508 }
00509
else {
00510
00511 *Range = (ULONG)AvailableTime.QuadPart;
00512 AvailableTime.QuadPart = 0;
00513 }
00514
00515
Time->QuadPart = CurrentTime.QuadPart - (*Range + AvailableTime.QuadPart);
00516
00517
ExpUuidLastTimeAllocated.QuadPart =
Time->QuadPart + *Range;
00518
00519
00520
00521
00522 *Sequence =
ExpUuidSequenceNumber;
00523
00524
00525
return(STATUS_SUCCESS);
00526 }
00527
00528 #define SEED_SIZE 6 * sizeof(CHAR)
00529
00530
00531
NTSTATUS
00532 NtSetUuidSeed (
00533 IN PCHAR Seed
00534 )
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556 {
00557
NTSTATUS Status;
00558 LUID AuthenticationId;
00559
SECURITY_SUBJECT_CONTEXT SubjectContext;
00560 LUID SystemLuid = SYSTEM_LUID;
00561 BOOLEAN CapturedSubjectContext =
FALSE;
00562
00563
PAGED_CODE();
00564
00565
ASSERT(KeGetPreviousMode() !=
KernelMode);
00566
00567
try {
00568
00569
00570
00571
SeCaptureSubjectContext(&SubjectContext);
00572 CapturedSubjectContext =
TRUE;
00573
00574
Status =
SeQueryAuthenticationIdToken(
00575
SeQuerySubjectContextToken(&SubjectContext),
00576 &AuthenticationId);
00577
if (!
NT_SUCCESS(
Status)) {
00578
ExRaiseStatus(
Status);
00579 }
00580
00581
if (RtlCompareMemory(&AuthenticationId, &SystemLuid,
sizeof(LUID)) !=
sizeof(LUID)) {
00582
ExRaiseStatus(STATUS_ACCESS_DENIED);
00583 }
00584
00585
00586
00587
00588
ProbeForRead(
Seed,
SEED_SIZE,
sizeof(
CHAR));
00589 RtlCopyMemory(&
ExpUuidCachedValues.
NodeId[0],
Seed,
SEED_SIZE);
00590
00591
if ((
Seed[0] & 0x80) == 0)
00592 {
00593
00594
00595
ExpUuidCacheValid =
CACHE_VALID;
00596 }
00597
else
00598 {
00599
ExpUuidCacheValid =
CACHE_LOCAL_ONLY;
00600 }
00601
00602
Status = STATUS_SUCCESS;
00603 }
00604 except (
EXCEPTION_EXECUTE_HANDLER) {
00605
Status = GetExceptionCode();
00606 }
00607
00608
if (CapturedSubjectContext) {
00609
SeReleaseSubjectContext( &SubjectContext );
00610 }
00611
00612
return Status;
00613 }
00614
00615
00616
NTSTATUS
00617 NtAllocateUuids (
00618 OUT PULARGE_INTEGER Time,
00619 OUT PULONG Range,
00620 OUT PULONG Sequence,
00621 OUT PCHAR Seed
00622 )
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667 {
00668
00669
KPROCESSOR_MODE PreviousMode;
00670
NTSTATUS Status;
00671
00672 LARGE_INTEGER OutputTime;
00673 ULONG OutputRange;
00674 ULONG OutputSequence;
00675
00676
PAGED_CODE();
00677
00678
00679
00680
00681
00682
00683
00684
00685
try {
00686
00687
00688
00689
00690
00691 PreviousMode = KeGetPreviousMode();
00692
if (PreviousMode !=
KernelMode) {
00693
ProbeForWrite((PVOID)
Time,
sizeof(LARGE_INTEGER),
sizeof(ULONG));
00694
ProbeForWrite((PVOID)Range,
sizeof(ULONG),
sizeof(ULONG));
00695
ProbeForWrite((PVOID)Sequence,
sizeof(ULONG),
sizeof(ULONG));
00696
ProbeForWrite((PVOID)
Seed,
SEED_SIZE,
sizeof(
CHAR));
00697 }
00698 }
00699 except (
ExSystemExceptionFilter()) {
00700
return GetExceptionCode();
00701 }
00702
00703
00704
00705
KeEnterCriticalRegion();
00706
ExAcquireFastMutexUnsafe(&
ExpUuidLock);
00707
00708
00709
00710
00711
Status =
ExpAllocateUuids( &OutputTime, &OutputRange, &OutputSequence );
00712
00713
if( !
NT_SUCCESS(
Status) ) {
00714
ExReleaseFastMutexUnsafe(&
ExpUuidLock);
00715
KeLeaveCriticalRegion();
00716
return(
Status );
00717 }
00718
00719
00720
00721
00722
ExpUuidSaveSequenceNumberIf();
00723
00724
00725
ExReleaseFastMutexUnsafe(&
ExpUuidLock);
00726
KeLeaveCriticalRegion();
00727
00728
00729
00730
00731
00732
00733
00734
try {
00735
Time->QuadPart = OutputTime.QuadPart;
00736 *Range = OutputRange;
00737 *Sequence = OutputSequence;
00738 RtlCopyMemory((PVOID)
Seed, &
ExpUuidCachedValues.
NodeId[0],
SEED_SIZE);
00739 }
00740 except (
ExSystemExceptionFilter()) {
00741
return GetExceptionCode();
00742 }
00743
00744
return(STATUS_SUCCESS);
00745 }
00746
00747
00748
00749
00750
NTSTATUS
00751 ExpUuidGetValues(
00752 OUT
UUID_CACHED_VALUES_STRUCT *Values
00753 )
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789 {
00790
NTSTATUS Status;
00791 LARGE_INTEGER
Time;
00792 ULONG Range;
00793 ULONG Sequence;
00794
00795
PAGED_CODE();
00796
00797
00798
00799
Status =
ExpAllocateUuids(&
Time, &Range, &Sequence);
00800
00801
if (STATUS_RETRY ==
Status) {
00802
return(
Status);
00803 }
00804
00805
else if (!
NT_SUCCESS(
Status)) {
00806
return(STATUS_NO_MEMORY);
00807 }
00808
00809
00810
00811
00812
00813
00814
Time.QuadPart += (ULONGLONG) (1000*1000*10)
00815 * (ULONGLONG) (60 * 60 * 24)
00816 * (ULONGLONG) (17+30+31+365*18+5);
00817
00818
ASSERT(Range);
00819
00820 Values->ClockSeqHiAndReserved =
00821
UUID_RESERVED | (((UCHAR) (Sequence >> 8))
00822 & (UCHAR)
UUID_CLOCK_SEQ_HI_MASK);
00823
00824 Values->ClockSeqLow = (UCHAR) (Sequence & 0x00FF);
00825
00826
00827
00828
00829
00830
00831
00832 Values->Time =
Time.QuadPart + (Range - 1);
00833 Values->AllocatedCount = Range;
00834
00835
return(STATUS_SUCCESS);
00836 }
00837
00838
00839
00840
NTSTATUS
00841 ExUuidCreate(
00842 OUT
UUID *Uuid
00843 )
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866 {
00867
NTSTATUS Status = STATUS_SUCCESS;
00868
00869
UUID_GENERATE *UuidGen = (
UUID_GENERATE *) Uuid;
00870 ULONGLONG
Time;
00871 LONG Delta;
00872
00873
PAGED_CODE();
00874
00875
00876
00877
00878
00879
00880
for(;;) {
00881
00882
00883
00884
Time =
ExpUuidCachedValues.
Time;
00885
00886
00887
00888
00889 *(PULONG)&UuidGen->
ClockSeqHiAndReserved =
00890 *(PULONG)&
ExpUuidCachedValues.
ClockSeqHiAndReserved;
00891 *(PULONG)&UuidGen->
NodeId[2] =
00892 *(PULONG)&
ExpUuidCachedValues.
NodeId[2];
00893
00894
00895 Delta = InterlockedDecrement(&
ExpUuidCachedValues.
AllocatedCount);
00896
00897
if (
Time !=
ExpUuidCachedValues.
Time) {
00898
00899
00900
00901
00902
continue;
00903 }
00904
00905
00906
00907
if (Delta >= 0) {
00908
break;
00909 }
00910
00911
00912
00913
00914
00915
00916
KeEnterCriticalRegion();
00917
ExAcquireFastMutexUnsafe(&
ExpUuidLock);
00918
00919
00920
if (
Time !=
ExpUuidCachedValues.
Time) {
00921
00922
ExReleaseFastMutexUnsafe(&
ExpUuidLock);
00923
KeLeaveCriticalRegion();
00924
continue;
00925 }
00926
00927
00928
Status =
ExpUuidGetValues( &
ExpUuidCachedValues );
00929
00930
if (
Status != STATUS_SUCCESS) {
00931
00932
ExReleaseFastMutexUnsafe(&
ExpUuidLock);
00933
KeLeaveCriticalRegion();
00934
return(
Status);
00935 }
00936
00937
00938
00939
00940
00941
ExpUuidSaveSequenceNumberIf();
00942
00943
00944
ExReleaseFastMutexUnsafe(&
ExpUuidLock);
00945
KeLeaveCriticalRegion();
00946
00947
00948 }
00949
00950
00951
Time -= Delta;
00952
00953
00954
00955 UuidGen->
TimeLow = (ULONG)
Time;
00956 UuidGen->
TimeMid = (
USHORT) (
Time >> 32);
00957 UuidGen->
TimeHiAndVersion = (
USHORT)
00958 (( (
USHORT)(
Time >> (32+16))
00959 &
UUID_TIME_HIGH_MASK) |
UUID_VERSION);
00960
00961
ASSERT(
Status == STATUS_SUCCESS);
00962
00963
if (
ExpUuidCacheValid ==
CACHE_LOCAL_ONLY) {
00964
Status = RPC_NT_UUID_LOCAL_ONLY;
00965 }
00966
00967
return(
Status);
00968 }