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
#include "exp.h"
00028
00029
00030
00031
00032
00033 #define CALLBACK_MODIFY_STATE 0x0001
00034
00035 #define CALLBACK_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|\
00036
CALLBACK_MODIFY_STATE )
00037
00038
00039
00040
00041
00042
00043 POBJECT_TYPE ExCallbackObjectType;
00044
00045
00046
00047
00048
00049 KEVENT ExpCallbackEvent;
00050
00051
00052
00053
00054
00055
00056 GENERIC_MAPPING
ExpCallbackMapping = {
00057 STANDARD_RIGHTS_READ ,
00058 STANDARD_RIGHTS_WRITE |
CALLBACK_MODIFY_STATE,
00059 STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE,
00060
CALLBACK_ALL_ACCESS
00061 };
00062
00063
00064
00065
00066
00067 typedef struct _CALLBACK_OBJECT {
00068 ULONG
Signature;
00069 KSPIN_LOCK
Lock;
00070 LIST_ENTRY
RegisteredCallbacks;
00071 BOOLEAN
AllowMultipleCallbacks;
00072 UCHAR
reserved[3];
00073 }
CALLBACK_OBJECT , *
PCALLBACK_OBJECT;
00074
00075
00076
00077
00078
00079 typedef struct _CALLBACK_REGISTRATION {
00080 LIST_ENTRY
Link;
00081 PCALLBACK_OBJECT CallbackObject;
00082 PCALLBACK_FUNCTION CallbackFunction;
00083 PVOID
CallbackContext;
00084 ULONG
Busy;
00085 BOOLEAN
UnregisterWaiting;
00086 }
CALLBACK_REGISTRATION , *
PCALLBACK_REGISTRATION;
00087
00088
00089
VOID
00090
ExpDeleteCallback (
00091 IN PCALLBACK_OBJECT CallbackObject
00092 );
00093
00094
#ifdef ALLOC_PRAGMA
00095
#pragma alloc_text(INIT, ExpInitializeCallbacks)
00096
#pragma alloc_text(PAGE, ExCreateCallback)
00097
#pragma alloc_text(PAGE, ExpDeleteCallback)
00098
#endif
00099
00100 BOOLEAN
00101 ExpInitializeCallbacks (
00102 )
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123 {
00124
OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
00125 OBJECT_ATTRIBUTES
ObjectAttributes;
00126
NTSTATUS Status;
00127 UNICODE_STRING unicodeString;
00128 ULONG i;
00129 HANDLE handle;
00130
00131
00132
00133
00134
00135
RtlInitUnicodeString(&unicodeString,
L"Callback");
00136
00137
00138
00139
00140
00141 RtlZeroMemory(&ObjectTypeInitializer,
sizeof(ObjectTypeInitializer));
00142 ObjectTypeInitializer.Length =
sizeof(ObjectTypeInitializer);
00143 ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK;
00144 ObjectTypeInitializer.GenericMapping =
ExpCallbackMapping;
00145 ObjectTypeInitializer.DeleteProcedure =
ExpDeleteCallback;
00146 ObjectTypeInitializer.PoolType =
NonPagedPool;
00147 ObjectTypeInitializer.ValidAccessMask =
CALLBACK_ALL_ACCESS;
00148
Status =
ObCreateObjectType(&unicodeString,
00149 &ObjectTypeInitializer,
00150 (PSECURITY_DESCRIPTOR)
NULL,
00151 &
ExCallbackObjectType);
00152
00153
if (!
NT_SUCCESS(
Status)) {
00154
return FALSE;
00155 }
00156
00157
RtlInitUnicodeString( &unicodeString,
ExpWstrCallback );
00158 InitializeObjectAttributes(
00159 &
ObjectAttributes,
00160 &unicodeString,
00161 OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
00162
NULL,
00163
SePublicDefaultSd
00164 );
00165
00166
Status =
NtCreateDirectoryObject(
00167 &handle,
00168 DIRECTORY_ALL_ACCESS,
00169 &
ObjectAttributes
00170 );
00171
00172
if (!
NT_SUCCESS(
Status)) {
00173
return FALSE;
00174 }
00175
00176
NtClose (handle);
00177
00178
00179
00180
00181
00182
00183
KeInitializeEvent (&
ExpCallbackEvent, NotificationEvent, 0);
00184
00185
00186
00187
00188
00189
for (i=0;
ExpInitializeCallback[i].
CallBackObject; i++) {
00190
00191
00192
00193
00194
00195
RtlInitUnicodeString(&unicodeString,
ExpInitializeCallback[i].CallbackName);
00196
00197
00198 InitializeObjectAttributes(
00199 &
ObjectAttributes,
00200 &unicodeString,
00201 OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
00202
NULL,
00203
NULL
00204 );
00205
00206
Status =
ExCreateCallback (
00207
ExpInitializeCallback[i].CallBackObject,
00208 &
ObjectAttributes,
00209
TRUE,
00210
TRUE
00211 );
00212
00213
if (!
NT_SUCCESS(
Status)) {
00214
return FALSE;
00215 }
00216 }
00217
00218
return TRUE;
00219 }
00220
00221
NTSTATUS
00222 ExCreateCallback (
00223 OUT PCALLBACK_OBJECT * CallbackObject,
00224 IN POBJECT_ATTRIBUTES ObjectAttributes,
00225 IN BOOLEAN Create,
00226 IN BOOLEAN AllowMultipleCallbacks
00227 )
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258 {
00259
PCALLBACK_OBJECT cbObject;
00260
NTSTATUS Status;
00261 HANDLE
Handle;
00262
00263
PAGED_CODE();
00264
00265
00266
00267
00268
00269
if (
ObjectAttributes->ObjectName) {
00270
Status =
ObOpenObjectByName(
ObjectAttributes,
00271
ExCallbackObjectType,
00272
KernelMode,
00273
NULL,
00274 0,
00275
NULL,
00276 &
Handle);
00277 }
else {
00278
Status = STATUS_UNSUCCESSFUL;
00279 }
00280
00281
00282
00283
00284
00285
if(!
NT_SUCCESS(
Status) &&
Create ) {
00286
Status =
ObCreateObject(
KernelMode,
00287
ExCallbackObjectType,
00288
ObjectAttributes,
00289
KernelMode,
00290
NULL,
00291
sizeof(
CALLBACK_OBJECT),
00292 0,
00293 0,
00294 (PVOID *)&cbObject );
00295
00296
if(
NT_SUCCESS(
Status)){
00297
00298
00299
00300
00301
00302 cbObject->Signature = 'llaC';
00303
00304
00305
00306
00307
00308
00309 cbObject->AllowMultipleCallbacks = AllowMultipleCallbacks;
00310
00311
00312
00313
00314
00315 InitializeListHead( &cbObject->RegisteredCallbacks );
00316
00317
00318
00319
00320
00321
KeInitializeSpinLock (&cbObject->Lock);
00322
00323
00324
00325
00326
00327
00328
Status =
ObInsertObject (
00329 cbObject,
00330
NULL,
00331 FILE_READ_DATA,
00332 0,
00333
NULL,
00334 &
Handle );
00335
00336 }
00337
00338 }
00339
00340
if(
NT_SUCCESS(
Status)){
00341
00342
00343
00344
00345
00346
Status =
ObReferenceObjectByHandle (
00347
Handle,
00348 0,
00349
ExCallbackObjectType,
00350
KernelMode,
00351 &cbObject,
00352
NULL
00353 );
00354
00355 ZwClose (
Handle);
00356 }
00357
00358
00359
00360
00361
00362
if (
NT_SUCCESS(
Status)) {
00363 *CallbackObject = cbObject;
00364 }
00365
00366
return Status;
00367 }
00368
00369
VOID
00370 ExpDeleteCallback (
00371 IN PCALLBACK_OBJECT CallbackObject
00372 )
00373 {
00374
ASSERT (IsListEmpty(&CallbackObject->RegisteredCallbacks));
00375 }
00376
00377 PVOID
00378 ExRegisterCallback (
00379 IN PCALLBACK_OBJECT CallbackObject,
00380 IN
PCALLBACK_FUNCTION CallbackFunction,
00381 IN PVOID CallbackContext
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
PCALLBACK_REGISTRATION CallbackRegistration;
00409 BOOLEAN Inserted;
00410 KIRQL OldIrql;
00411
NTSTATUS Status;
00412
00413
ASSERT (CallbackFunction);
00414
ASSERT (KeGetCurrentIrql() <
DISPATCH_LEVEL);
00415
00416
00417
00418
00419
00420
ObReferenceObject (CallbackObject);
00421
00422
00423
00424
00425
00426
00427 CallbackRegistration =
ExAllocatePoolWithTag(
00428
NonPagedPool,
00429
sizeof(
CALLBACK_REGISTRATION ),
00430 'eRBC'
00431 );
00432
00433
00434
if( !CallbackRegistration ) {
00435
ObDereferenceObject (CallbackObject);
00436
return NULL;
00437 }
00438
00439
00440
00441
00442
00443
00444 CallbackRegistration->
CallbackObject = CallbackObject;
00445 CallbackRegistration->
CallbackFunction = CallbackFunction;
00446 CallbackRegistration->
CallbackContext = CallbackContext;
00447 CallbackRegistration->
Busy = 0;
00448 CallbackRegistration->
UnregisterWaiting =
FALSE;
00449
00450
00451 Inserted =
FALSE;
00452
KeAcquireSpinLock (&CallbackObject->Lock, &OldIrql);
00453
00454
if( CallbackObject->AllowMultipleCallbacks ||
00455 IsListEmpty( &CallbackObject->RegisteredCallbacks ) ) {
00456
00457
00458
00459
00460
00461
00462 Inserted =
TRUE;
00463 InsertTailList( &CallbackObject->RegisteredCallbacks,
00464 &CallbackRegistration->
Link )
00465 }
00466
00467
KeReleaseSpinLock (&CallbackObject->Lock, OldIrql);
00468
00469
if (!Inserted) {
00470
ExFreePool (CallbackRegistration);
00471 CallbackRegistration =
NULL;
00472 }
00473
00474
return (PVOID) CallbackRegistration;
00475 }
00476
00477
00478
VOID
00479 ExUnregisterCallback (
00480 IN PVOID CbRegistration
00481 )
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500 {
00501
PCALLBACK_REGISTRATION CallbackRegistration;
00502
PCALLBACK_OBJECT CallbackObject;
00503 KIRQL OldIrql;
00504
00505
ASSERT (KeGetCurrentIrql() <
DISPATCH_LEVEL);
00506
00507 CallbackRegistration = (
PCALLBACK_REGISTRATION) CbRegistration;
00508 CallbackObject = CallbackRegistration->
CallbackObject;
00509
00510
KeAcquireSpinLock (&CallbackObject->
Lock, &OldIrql);
00511
00512
00513
00514
00515
00516
while (CallbackRegistration->
Busy) {
00517
00518
00519
00520
00521
00522
00523 CallbackRegistration->
UnregisterWaiting =
TRUE;
00524
KeClearEvent (&
ExpCallbackEvent);
00525
KeReleaseSpinLock (&CallbackObject->
Lock, OldIrql);
00526
00527
KeWaitForSingleObject (
00528 &
ExpCallbackEvent,
00529
Executive,
00530
KernelMode,
00531
FALSE,
00532
NULL
00533 );
00534
00535
00536
00537
00538
00539
KeAcquireSpinLock (&CallbackObject->
Lock, &OldIrql);
00540 }
00541
00542
00543
00544
00545
00546 RemoveEntryList (&CallbackRegistration->
Link);
00547
KeReleaseSpinLock (&CallbackObject->
Lock, OldIrql);
00548
00549
00550
00551
00552
00553
ExFreePool (CallbackRegistration);
00554
00555
00556
00557
00558
00559
ObDereferenceObject (CallbackObject);
00560 }
00561
00562
VOID
00563 ExNotifyCallback (
00564 IN PCALLBACK_OBJECT CallbackObject,
00565 IN PVOID Argument1,
00566 IN PVOID Argument2
00567 )
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590 {
00591 PLIST_ENTRY Link;
00592
PCALLBACK_REGISTRATION CallbackRegistration;
00593 KIRQL OldIrql;
00594
00595
if (CallbackObject ==
NULL) {
00596
return ;
00597 }
00598
00599
00600
00601
00602
00603
KeAcquireSpinLock (&CallbackObject->Lock, &OldIrql);
00604
00605
00606
00607
00608
00609
00610
if (OldIrql ==
DISPATCH_LEVEL) {
00611
00612
00613
00614
00615
00616
00617
for (Link = CallbackObject->RegisteredCallbacks.Flink;
00618 Link != &CallbackObject->RegisteredCallbacks;
00619 Link = Link->Flink) {
00620
00621
00622
00623
00624
00625 CallbackRegistration = CONTAINING_RECORD (Link,
00626
CALLBACK_REGISTRATION,
00627 Link);
00628
00629
00630
00631
00632
00633 CallbackRegistration->
CallbackFunction(
00634 CallbackRegistration->
CallbackContext,
00635 Argument1,
00636 Argument2
00637 );
00638
00639 }
00640
00641 }
else {
00642
00643
00644
00645
00646
00647
00648
00649
for (Link = CallbackObject->RegisteredCallbacks.Flink;
00650 Link != &CallbackObject->RegisteredCallbacks;
00651 Link = Link->Flink ) {
00652
00653
00654
00655
00656
00657 CallbackRegistration = CONTAINING_RECORD (Link,
00658
CALLBACK_REGISTRATION,
00659 Link);
00660
00661
00662
00663
00664
00665
if (!CallbackRegistration->
UnregisterWaiting) {
00666
00667
00668
00669
00670
00671 CallbackRegistration->
Busy += 1;
00672
00673
00674
00675
00676
00677
KeReleaseSpinLock (&CallbackObject->Lock, OldIrql);
00678
00679 CallbackRegistration->
CallbackFunction(
00680 CallbackRegistration->
CallbackContext,
00681 Argument1,
00682 Argument2
00683 );
00684
00685
00686
00687
00688
00689
KeAcquireSpinLock (&CallbackObject->Lock, &OldIrql);
00690
00691
00692
00693
00694
00695 CallbackRegistration->
Busy -= 1;
00696
00697
00698
00699
00700
00701
00702
if (CallbackRegistration->
UnregisterWaiting &&
00703 CallbackRegistration->
Busy == 0) {
00704
KeSetEvent (&
ExpCallbackEvent, 0,
FALSE);
00705 }
00706 }
00707 }
00708 }
00709
00710
00711
00712
00713
00714
00715
KeReleaseSpinLock (&CallbackObject->Lock, OldIrql);
00716 }