Windows: Allow the Library to pend a write request
[openafs.git] / src / WINNT / afsrdr / kernel / fs / AFSGeneric.cpp
1 /*
2  * Copyright (c) 2008, 2009, 2010, 2011 Kernel Drivers, LLC.
3  * Copyright (c) 2009, 2010, 2011 Your File System, Inc.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * - Redistributions of source code must retain the above copyright notice,
11  *   this list of conditions and the following disclaimer.
12  * - Redistributions in binary form must reproduce the above copyright
13  *   notice,
14  *   this list of conditions and the following disclaimer in the
15  *   documentation
16  *   and/or other materials provided with the distribution.
17  * - Neither the names of Kernel Drivers, LLC and Your File System, Inc.
18  *   nor the names of their contributors may be used to endorse or promote
19  *   products derived from this software without specific prior written
20  *   permission from Kernel Drivers, LLC and Your File System, Inc.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
25  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
26  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34
35 //
36 // File: AFSGeneric.cpp
37 //
38
39 #include "AFSCommon.h"
40
41 //
42 // Function: AFSExceptionFilter
43 //
44 // Description:
45 //
46 //      This function is the exception handler
47 //
48 // Return:
49 //
50 //      A status is returned for the function
51 //
52
53 ULONG
54 AFSExceptionFilter( IN CHAR *FunctionString,
55                     IN ULONG Code,
56                     IN PEXCEPTION_POINTERS ExceptPtrs)
57 {
58     UNREFERENCED_PARAMETER(Code);
59
60     PEXCEPTION_RECORD ExceptRec;
61     PCONTEXT Context;
62
63     __try
64     {
65
66         ExceptRec = ExceptPtrs->ExceptionRecord;
67
68         Context = ExceptPtrs->ContextRecord;
69
70         AFSDbgLogMsg( 0,
71                       0,
72                       "AFSExceptionFilter (Framework) - EXR %p CXR %p Function %s Code %08lX Address %p Routine %p\n",
73                       ExceptRec,
74                       Context,
75                       FunctionString,
76                       ExceptRec->ExceptionCode,
77                       ExceptRec->ExceptionAddress,
78                       (void *)AFSExceptionFilter);
79
80         DbgPrint("**** Exception Caught in AFS Redirector ****\n");
81
82         DbgPrint("\n\nPerform the following WnDbg Cmds:\n");
83         DbgPrint("\n\t.exr %p ;  .cxr %p\n\n", ExceptRec, Context);
84
85         DbgPrint("**** Exception Complete from AFS Redirector ****\n");
86
87         if( BooleanFlagOn( AFSDebugFlags, AFS_DBG_BUGCHECK_EXCEPTION))
88         {
89
90             KeBugCheck( (ULONG)-2);
91         }
92         else
93         {
94
95             AFSBreakPoint();
96         }
97     }
98     __except( EXCEPTION_EXECUTE_HANDLER)
99     {
100
101         NOTHING;
102     }
103
104     return EXCEPTION_EXECUTE_HANDLER;
105 }
106
107 //
108 // Function: AFSAcquireExcl()
109 //
110 // Purpose: Called to acquire a resource exclusive with optional wait
111 //
112 // Parameters:
113 //                PERESOURCE Resource - Resource to acquire
114 //                BOOLEAN Wait - Whether to block
115 //
116 // Return:
117 //                BOOLEAN - Whether the mask was acquired
118 //
119
120 BOOLEAN
121 AFSAcquireExcl( IN PERESOURCE Resource,
122                 IN BOOLEAN wait)
123 {
124
125     BOOLEAN bStatus = FALSE;
126
127     //
128     // Normal kernel APCs must be disabled before calling
129     // ExAcquireResourceExclusiveLite. Otherwise a bugcheck occurs.
130     //
131
132     KeEnterCriticalRegion();
133
134     bStatus = ExAcquireResourceExclusiveLite( Resource,
135                                               wait);
136
137     if( !bStatus)
138     {
139
140         KeLeaveCriticalRegion();
141     }
142
143     return bStatus;
144 }
145
146 BOOLEAN
147 AFSAcquireSharedStarveExclusive( IN PERESOURCE Resource,
148                                  IN BOOLEAN Wait)
149 {
150
151     BOOLEAN bStatus = FALSE;
152
153     KeEnterCriticalRegion();
154
155     bStatus = ExAcquireSharedStarveExclusive( Resource,
156                                               Wait);
157
158     if( !bStatus)
159     {
160
161         KeLeaveCriticalRegion();
162     }
163
164     return bStatus;
165 }
166
167 //
168 // Function: AFSAcquireShared()
169 //
170 // Purpose: Called to acquire a resource shared with optional wait
171 //
172 // Parameters:
173 //                PERESOURCE Resource - Resource to acquire
174 //                BOOLEAN Wait - Whether to block
175 //
176 // Return:
177 //                BOOLEAN - Whether the mask was acquired
178 //
179
180 BOOLEAN
181 AFSAcquireShared( IN PERESOURCE Resource,
182                   IN BOOLEAN wait)
183 {
184
185     BOOLEAN bStatus = FALSE;
186
187     KeEnterCriticalRegion();
188
189     bStatus = ExAcquireResourceSharedLite( Resource,
190                                            wait);
191
192     if( !bStatus)
193     {
194
195         KeLeaveCriticalRegion();
196     }
197
198     return bStatus;
199 }
200
201 //
202 // Function: AFSReleaseResource()
203 //
204 // Purpose: Called to release a resource
205 //
206 // Parameters:
207 //                PERESOURCE Resource - Resource to release
208 //
209 // Return:
210 //                None
211 //
212
213 void
214 AFSReleaseResource( IN PERESOURCE Resource)
215 {
216
217     if( Resource != &AFSDbgLogLock)
218     {
219
220         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
221                       AFS_TRACE_LEVEL_VERBOSE,
222                       "AFSReleaseResource Releasing lock %p Thread %08lX\n",
223                       Resource,
224                       PsGetCurrentThread());
225     }
226
227     ExReleaseResourceLite( Resource);
228
229     KeLeaveCriticalRegion();
230
231     return;
232 }
233
234 void
235 AFSConvertToShared( IN PERESOURCE Resource)
236 {
237
238     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
239                   AFS_TRACE_LEVEL_VERBOSE,
240                   "AFSConvertToShared Converting lock %p Thread %08lX\n",
241                   Resource,
242                   PsGetCurrentThread());
243
244     ExConvertExclusiveToSharedLite( Resource);
245
246     return;
247 }
248
249 //
250 // Function: AFSCompleteRequest
251 //
252 // Description:
253 //
254 //      This function completes irps
255 //
256 // Return:
257 //
258 //      A status is returned for the function
259 //
260
261 void
262 AFSCompleteRequest( IN PIRP Irp,
263                     IN ULONG Status)
264 {
265
266     Irp->IoStatus.Status = Status;
267
268     IoCompleteRequest( Irp,
269                        IO_NO_INCREMENT);
270
271     return;
272 }
273
274 NTSTATUS
275 AFSReadRegistry( IN PUNICODE_STRING RegistryPath)
276 {
277
278     NTSTATUS ntStatus        = STATUS_SUCCESS;
279     ULONG Default            = 0;
280     UNICODE_STRING paramPath;
281     ULONG Value                = 0;
282     RTL_QUERY_REGISTRY_TABLE paramTable[2];
283     UNICODE_STRING defaultUnicodeName;
284     WCHAR SubKeyString[]    = L"\\Parameters";
285
286     //
287     // Setup the paramPath buffer.
288     //
289
290     paramPath.MaximumLength = RegistryPath->Length + sizeof( SubKeyString);
291     paramPath.Buffer = (PWSTR)AFSExAllocatePoolWithTag( PagedPool,
292                                                         paramPath.MaximumLength,
293                                                         AFS_GENERIC_MEMORY_15_TAG);
294
295     RtlInitUnicodeString( &defaultUnicodeName,
296                           L"NO NAME");
297
298     //
299     // If it exists, setup the path.
300     //
301
302     if( paramPath.Buffer != NULL)
303     {
304
305         //
306         // Move in the paths
307         //
308
309         RtlCopyMemory( &paramPath.Buffer[ 0],
310                        &RegistryPath->Buffer[ 0],
311                        RegistryPath->Length);
312
313         RtlCopyMemory( &paramPath.Buffer[ RegistryPath->Length / 2],
314                        SubKeyString,
315                        sizeof( SubKeyString));
316
317         paramPath.Length = paramPath.MaximumLength;
318
319         RtlZeroMemory( paramTable,
320                        sizeof( paramTable));
321
322         Value = 0;
323
324         //
325         // Setup the table to query the registry for the needed value
326         //
327
328         paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
329         paramTable[0].Name = AFS_REG_DEBUG_FLAGS;
330         paramTable[0].EntryContext = &Value;
331
332         paramTable[0].DefaultType = REG_DWORD;
333         paramTable[0].DefaultData = &Default;
334         paramTable[0].DefaultLength = sizeof (ULONG) ;
335
336         //
337         // Query the registry
338         //
339
340         ntStatus = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
341                                            paramPath.Buffer,
342                                            paramTable,
343                                            NULL,
344                                            NULL);
345
346         if( NT_SUCCESS( ntStatus))
347         {
348
349             AFSDebugFlags = Value;
350         }
351
352         RtlZeroMemory( paramTable,
353                        sizeof( paramTable));
354
355         Value = 0;
356
357         //
358         // Setup the table to query the registry for the needed value
359         //
360
361         paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
362         paramTable[0].Name = AFS_REG_TRACE_SUBSYSTEM;
363         paramTable[0].EntryContext = &Value;
364
365         paramTable[0].DefaultType = REG_DWORD;
366         paramTable[0].DefaultData = &Default;
367         paramTable[0].DefaultLength = sizeof (ULONG) ;
368
369         //
370         // Query the registry
371         //
372
373         ntStatus = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
374                                            paramPath.Buffer,
375                                            paramTable,
376                                            NULL,
377                                            NULL);
378
379         if( NT_SUCCESS( ntStatus))
380         {
381
382             AFSTraceComponent = Value;
383         }
384
385         RtlZeroMemory( paramTable,
386                        sizeof( paramTable));
387
388         Value = 0;
389
390         //
391         // Setup the table to query the registry for the needed value
392         //
393
394         paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
395         paramTable[0].Name = AFS_REG_TRACE_BUFFER_LENGTH;
396         paramTable[0].EntryContext = &Value;
397
398         paramTable[0].DefaultType = REG_DWORD;
399         paramTable[0].DefaultData = &Default;
400         paramTable[0].DefaultLength = sizeof (ULONG);
401
402         //
403         // Query the registry
404         //
405
406         ntStatus = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
407                                            paramPath.Buffer,
408                                            paramTable,
409                                            NULL,
410                                            NULL);
411
412         if( NT_SUCCESS( ntStatus) &&
413             Value > 0)
414         {
415
416             AFSDbgBufferLength = Value;
417
418             //
419             // Let's limit things a bit ...
420             //
421
422             if( AFSDbgBufferLength > 10240)
423             {
424
425                 AFSDbgBufferLength = 1024;
426             }
427         }
428         else
429         {
430
431             AFSDbgBufferLength = 0;
432         }
433
434         //
435         // Make it bytes
436         //
437
438         AFSDbgBufferLength *= 1024;
439
440         //
441         // Now get ready to set up for MaxServerDirty
442         //
443
444         paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
445         paramTable[0].Name = AFS_REG_MAX_DIRTY;
446         paramTable[0].EntryContext = &Value;
447
448         paramTable[0].DefaultType = REG_DWORD;
449         paramTable[0].DefaultData = &Default;
450         paramTable[0].DefaultLength = sizeof (ULONG) ;
451
452         //
453         // Query the registry
454         //
455
456         ntStatus = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
457                                            paramPath.Buffer,
458                                            paramTable,
459                                            NULL,
460                                            NULL);
461
462         if( NT_SUCCESS( ntStatus))
463         {
464
465             AFSMaxDirtyFile = Value;
466         }
467
468         RtlZeroMemory( paramTable,
469                        sizeof( paramTable));
470
471         Value = 0;
472
473         //
474         // Setup the table to query the registry for the needed value
475         //
476
477         paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
478         paramTable[0].Name = AFS_REG_TRACE_LEVEL;
479         paramTable[0].EntryContext = &Value;
480
481         paramTable[0].DefaultType = REG_DWORD;
482         paramTable[0].DefaultData = &Default;
483         paramTable[0].DefaultLength = sizeof (ULONG) ;
484
485         //
486         // Query the registry
487         //
488
489         ntStatus = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
490                                            paramPath.Buffer,
491                                            paramTable,
492                                            NULL,
493                                            NULL);
494
495         if( NT_SUCCESS( ntStatus))
496         {
497
498             AFSTraceLevel = Value;
499         }
500
501         //
502         // MaxIO
503         //
504
505         paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
506         paramTable[0].Name = AFS_REG_MAX_IO;
507         paramTable[0].EntryContext = &Value;
508
509         paramTable[0].DefaultType = REG_DWORD;
510         paramTable[0].DefaultData = &Default;
511         paramTable[0].DefaultLength = sizeof (ULONG) ;
512
513         //
514         // Query the registry
515         //
516
517         ntStatus = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
518                                            paramPath.Buffer,
519                                            paramTable,
520                                            NULL,
521                                            NULL);
522
523         if( NT_SUCCESS( ntStatus))
524         {
525
526             AFSMaxDirectIo = Value;
527         }
528
529         //
530         // Now set up for ShutdownStatus query
531         //
532
533         paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
534         paramTable[0].Name = AFS_REG_SHUTDOWN_STATUS;
535         paramTable[0].EntryContext = &Value;
536
537         paramTable[0].DefaultType = REG_DWORD;
538         paramTable[0].DefaultData = &Default;
539         paramTable[0].DefaultLength = sizeof (ULONG) ;
540
541         //
542         // Query the registry
543         //
544
545         ntStatus = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
546                                            paramPath.Buffer,
547                                            paramTable,
548                                            NULL,
549                                            NULL);
550
551         if( !NT_SUCCESS( ntStatus) ||
552             Value != (ULONG)-1)
553         {
554
555             SetFlag( AFSDebugFlags, AFS_DBG_CLEAN_SHUTDOWN);
556         }
557
558         //
559         // Now set up for RequireCleanShutdown query
560         //
561
562         paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
563         paramTable[0].Name = AFS_REG_REQUIRE_CLEAN_SHUTDOWN;
564         paramTable[0].EntryContext = &Value;
565
566         paramTable[0].DefaultType = REG_DWORD;
567         paramTable[0].DefaultData = &Default;
568         paramTable[0].DefaultLength = sizeof (ULONG) ;
569
570         //
571         // Query the registry
572         //
573
574         ntStatus = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
575                                            paramPath.Buffer,
576                                            paramTable,
577                                            NULL,
578                                            NULL);
579
580         if( !NT_SUCCESS( ntStatus) ||
581             Value != 0L)
582         {
583
584             SetFlag( AFSDebugFlags, AFS_DBG_REQUIRE_CLEAN_SHUTDOWN);
585         }
586
587         //
588         // Free up the buffer
589         //
590
591         ExFreePool( paramPath.Buffer);
592
593         ntStatus = STATUS_SUCCESS;
594     }
595     else
596     {
597         ntStatus = STATUS_INSUFFICIENT_RESOURCES;
598     }
599
600     return ntStatus;
601 }
602
603 NTSTATUS
604 AFSUpdateRegistryParameter( IN PUNICODE_STRING ValueName,
605                             IN ULONG ValueType,
606                             IN void *ValueData,
607                             IN ULONG ValueDataLength)
608 {
609
610     NTSTATUS ntStatus        = STATUS_SUCCESS;
611     UNICODE_STRING paramPath, uniParamKey;
612     HANDLE hParameters = 0;
613     OBJECT_ATTRIBUTES stObjectAttributes;
614
615     __Enter
616     {
617
618         RtlInitUnicodeString( &uniParamKey,
619                               L"\\Parameters");
620
621         //
622         // Setup the paramPath buffer.
623         //
624
625         paramPath.MaximumLength = AFSRegistryPath.Length + uniParamKey.Length;
626         paramPath.Buffer = (PWSTR)AFSExAllocatePoolWithTag( PagedPool,
627                                                             paramPath.MaximumLength,
628                                                             AFS_GENERIC_MEMORY_16_TAG);
629
630         if( paramPath.Buffer == NULL)
631         {
632
633             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
634         }
635
636         //
637         // Move in the paths
638         //
639
640         RtlCopyMemory( paramPath.Buffer,
641                        AFSRegistryPath.Buffer,
642                        AFSRegistryPath.Length);
643
644         paramPath.Length = AFSRegistryPath.Length;
645
646         RtlCopyMemory( &paramPath.Buffer[ paramPath.Length / 2],
647                        uniParamKey.Buffer,
648                        uniParamKey.Length);
649
650         paramPath.Length += uniParamKey.Length;
651
652         InitializeObjectAttributes( &stObjectAttributes,
653                                     &paramPath,
654                                     OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
655                                     NULL,
656                                     NULL);
657
658         ntStatus = ZwOpenKey( &hParameters,
659                               KEY_ALL_ACCESS,
660                               &stObjectAttributes);
661
662         if( !NT_SUCCESS( ntStatus))
663         {
664
665             try_return( ntStatus);
666         }
667
668         //
669         // Set the value
670         //
671
672         ntStatus = ZwSetValueKey( hParameters,
673                                   ValueName,
674                                   0,
675                                   ValueType,
676                                   ValueData,
677                                   ValueDataLength);
678
679         ZwClose( hParameters);
680
681 try_exit:
682
683         if( paramPath.Buffer != NULL)
684         {
685
686             //
687             // Free up the buffer
688             //
689
690             ExFreePool( paramPath.Buffer);
691         }
692     }
693
694     return ntStatus;
695 }
696
697 NTSTATUS
698 AFSInitializeControlDevice()
699 {
700
701     NTSTATUS ntStatus = STATUS_SUCCESS;
702     AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSDeviceObject->DeviceExtension;
703
704     __Enter
705     {
706
707         //
708         // Initialize the comm pool resources
709         //
710
711         ExInitializeResourceLite( &pDeviceExt->Specific.Control.CommServiceCB.IrpPoolLock);
712
713         ExInitializeResourceLite( &pDeviceExt->Specific.Control.CommServiceCB.ResultPoolLock);
714
715         ExInitializeResourceLite( &pDeviceExt->Specific.Control.ExtentReleaseResource);
716
717         ExInitializeResourceLite( &pDeviceExt->Specific.Control.SysName32ListLock);
718
719         ExInitializeResourceLite( &pDeviceExt->Specific.Control.SysName64ListLock);
720
721         //
722         // And the events
723         //
724
725         KeInitializeEvent( &pDeviceExt->Specific.Control.CommServiceCB.IrpPoolHasEntries,
726                            SynchronizationEvent,
727                            FALSE);
728
729         KeInitializeEvent( &pDeviceExt->Specific.Control.CommServiceCB.IrpPoolHasReleaseEntries,
730                            SynchronizationEvent,
731                            FALSE);
732
733         KeInitializeEvent( &pDeviceExt->Specific.Control.ExtentReleaseEvent,
734                            NotificationEvent,
735                            FALSE);
736
737         pDeviceExt->Specific.Control.ExtentReleaseSequence = 0;
738
739         KeInitializeEvent( &pDeviceExt->Specific.Control.VolumeWorkerCloseEvent,
740                            NotificationEvent,
741                            TRUE);
742
743         //
744         // Library support information
745         //
746
747         KeInitializeEvent( &pDeviceExt->Specific.Control.LoadLibraryEvent,
748                            SynchronizationEvent,
749                            TRUE);
750
751         //
752         // Initialize the library queued as cancelled
753         //
754
755         pDeviceExt->Specific.Control.LibraryState = AFS_LIBRARY_QUEUE_CANCELLED;
756
757         ExInitializeResourceLite( &pDeviceExt->Specific.Control.LibraryStateLock);
758
759         pDeviceExt->Specific.Control.InflightLibraryRequests = 0;
760
761         KeInitializeEvent( &pDeviceExt->Specific.Control.InflightLibraryEvent,
762                            NotificationEvent,
763                            FALSE);
764
765         pDeviceExt->Specific.Control.ExtentCount = 0;
766         pDeviceExt->Specific.Control.ExtentsHeldLength = 0;
767
768         KeInitializeEvent( &pDeviceExt->Specific.Control.ExtentsHeldEvent,
769                            NotificationEvent,
770                            TRUE);
771
772         pDeviceExt->Specific.Control.OutstandingServiceRequestCount = 0;
773
774         KeInitializeEvent( &pDeviceExt->Specific.Control.OutstandingServiceRequestEvent,
775                            NotificationEvent,
776                            TRUE);
777
778         pDeviceExt->Specific.Control.WaitingForMemoryCount = 0;
779
780         KeInitializeEvent( &pDeviceExt->Specific.Control.MemoryAvailableEvent,
781                            NotificationEvent,
782                            TRUE);
783
784         ExInitializeResourceLite( &pDeviceExt->Specific.Control.LibraryQueueLock);
785
786         pDeviceExt->Specific.Control.LibraryQueueHead = NULL;
787
788         pDeviceExt->Specific.Control.LibraryQueueTail = NULL;
789
790         //
791         // Set the initial state of the irp pool
792         //
793
794         pDeviceExt->Specific.Control.CommServiceCB.IrpPoolControlFlag = POOL_INACTIVE;
795
796         //
797         // Initialize our process and sid tree information
798         //
799
800         ExInitializeResourceLite( &pDeviceExt->Specific.Control.ProcessTreeLock);
801
802         pDeviceExt->Specific.Control.ProcessTree.TreeLock = &pDeviceExt->Specific.Control.ProcessTreeLock;
803
804         pDeviceExt->Specific.Control.ProcessTree.TreeHead = NULL;
805
806         ExInitializeResourceLite( &pDeviceExt->Specific.Control.AuthGroupTreeLock);
807
808         pDeviceExt->Specific.Control.AuthGroupTree.TreeLock = &pDeviceExt->Specific.Control.AuthGroupTreeLock;
809
810         pDeviceExt->Specific.Control.AuthGroupTree.TreeHead = NULL;
811     }
812
813     return ntStatus;
814 }
815
816 NTSTATUS
817 AFSRemoveControlDevice()
818 {
819
820     NTSTATUS ntStatus = STATUS_SUCCESS;
821     AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSDeviceObject->DeviceExtension;
822
823     __Enter
824     {
825
826         //
827         // Initialize the comm pool resources
828         //
829
830         ExDeleteResourceLite( &pDeviceExt->Specific.Control.CommServiceCB.IrpPoolLock);
831
832         ExDeleteResourceLite( &pDeviceExt->Specific.Control.CommServiceCB.ResultPoolLock);
833
834         ExDeleteResourceLite( &pDeviceExt->Specific.Control.ExtentReleaseResource);
835
836         ExDeleteResourceLite( &pDeviceExt->Specific.Control.SysName32ListLock);
837
838         ExDeleteResourceLite( &pDeviceExt->Specific.Control.SysName64ListLock);
839
840         ExDeleteResourceLite( &pDeviceExt->Specific.Control.ProcessTreeLock);
841
842         if( pDeviceExt->Specific.Control.ProcessTree.TreeHead != NULL)
843         {
844             ExFreePool( pDeviceExt->Specific.Control.ProcessTree.TreeHead);
845         }
846
847         ExDeleteResourceLite( &pDeviceExt->Specific.Control.AuthGroupTreeLock);
848
849         ExDeleteResourceLite( &pDeviceExt->Specific.Control.LibraryStateLock);
850
851         ExDeleteResourceLite( &pDeviceExt->Specific.Control.LibraryQueueLock);
852     }
853
854     return ntStatus;
855 }
856
857 void
858 AFSInitServerStrings()
859 {
860
861     UNICODE_STRING uniFullName;
862     WCHAR wchBuffer[ 50];
863
864     //
865     // Add the server name into the list of resources
866     //
867
868     uniFullName.Length = (2 * sizeof( WCHAR)) + AFSServerName.Length;
869     uniFullName.MaximumLength = uniFullName.Length + sizeof( WCHAR);
870
871     uniFullName.Buffer = wchBuffer;
872
873     wchBuffer[ 0] = L'\\';
874     wchBuffer[ 1] = L'\\';
875
876     RtlCopyMemory( &wchBuffer[ 2],
877                    AFSServerName.Buffer,
878                    AFSServerName.Length);
879
880     AFSAddConnectionEx( &uniFullName,
881                         RESOURCEDISPLAYTYPE_SERVER,
882                         0);
883
884     //
885     // Add in the global share name
886     //
887
888     wchBuffer[ uniFullName.Length/sizeof( WCHAR)] = L'\\';
889
890     uniFullName.Length += sizeof( WCHAR);
891
892     RtlCopyMemory( &wchBuffer[ uniFullName.Length/sizeof( WCHAR)],
893                    AFSGlobalRootName.Buffer,
894                    AFSGlobalRootName.Length);
895
896     uniFullName.Length += AFSGlobalRootName.Length;
897
898     AFSAddConnectionEx( &uniFullName,
899                         RESOURCEDISPLAYTYPE_SHARE,
900                         AFS_CONNECTION_FLAG_GLOBAL_SHARE);
901
902     return;
903 }
904
905 NTSTATUS
906 AFSReadServerName()
907 {
908
909     NTSTATUS ntStatus        = STATUS_SUCCESS;
910     UNICODE_STRING paramPath;
911     RTL_QUERY_REGISTRY_TABLE paramTable[2];
912
913     __Enter
914     {
915
916         //
917         // Setup the paramPath buffer.
918         //
919
920         paramPath.MaximumLength = PAGE_SIZE;
921         paramPath.Buffer = (PWSTR)AFSExAllocatePoolWithTag( PagedPool,
922                                                             paramPath.MaximumLength,
923                                                             AFS_GENERIC_MEMORY_17_TAG);
924
925         //
926         // If it exists, setup the path.
927         //
928
929         if( paramPath.Buffer == NULL)
930         {
931
932             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
933         }
934
935         //
936         // Move in the paths
937         //
938
939         RtlZeroMemory( paramPath.Buffer,
940                        paramPath.MaximumLength);
941
942         RtlCopyMemory( &paramPath.Buffer[ 0],
943                        L"\\TransarcAFSDaemon\\Parameters",
944                        58);
945
946         paramPath.Length = 58;
947
948         RtlZeroMemory( paramTable,
949                        sizeof( paramTable));
950
951         //
952         // Setup the table to query the registry for the needed value
953         //
954
955         AFSServerName.Length = 0;
956         AFSServerName.MaximumLength = 0;
957         AFSServerName.Buffer = NULL;
958
959         paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
960         paramTable[0].Name = AFS_REG_NETBIOS_NAME;
961         paramTable[0].EntryContext = &AFSServerName;
962
963         paramTable[0].DefaultType = REG_NONE;
964         paramTable[0].DefaultData = NULL;
965         paramTable[0].DefaultLength = 0;
966
967         //
968         // Query the registry
969         //
970
971         ntStatus = RtlQueryRegistryValues( RTL_REGISTRY_SERVICES,
972                                            paramPath.Buffer,
973                                            paramTable,
974                                            NULL,
975                                            NULL);
976
977         //
978         // Free up the buffer
979         //
980
981         ExFreePool( paramPath.Buffer);
982
983 try_exit:
984
985         if( !NT_SUCCESS( ntStatus))
986         {
987
988             RtlInitUnicodeString( &AFSServerName,
989                                   L"AFS");
990         }
991     }
992
993     return ntStatus;
994 }
995
996 NTSTATUS
997 AFSReadMountRootName()
998 {
999
1000     NTSTATUS ntStatus        = STATUS_SUCCESS;
1001     UNICODE_STRING paramPath;
1002     RTL_QUERY_REGISTRY_TABLE paramTable[2];
1003
1004     __Enter
1005     {
1006
1007         //
1008         // Setup the paramPath buffer.
1009         //
1010
1011         paramPath.MaximumLength = PAGE_SIZE;
1012         paramPath.Buffer = (PWSTR)AFSExAllocatePoolWithTag( PagedPool,
1013                                                             paramPath.MaximumLength,
1014                                                             AFS_GENERIC_MEMORY_17_TAG);
1015
1016         //
1017         // If it exists, setup the path.
1018         //
1019
1020         if( paramPath.Buffer == NULL)
1021         {
1022
1023             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1024         }
1025
1026         //
1027         // Move in the paths
1028         //
1029
1030         RtlZeroMemory( paramPath.Buffer,
1031                        paramPath.MaximumLength);
1032
1033         RtlCopyMemory( &paramPath.Buffer[ 0],
1034                        L"\\TransarcAFSDaemon\\Parameters",
1035                        58);
1036
1037         paramPath.Length = 58;
1038
1039         RtlZeroMemory( paramTable,
1040                        sizeof( paramTable));
1041
1042         //
1043         // Setup the table to query the registry for the needed value
1044         //
1045
1046         AFSMountRootName.Length = 0;
1047         AFSMountRootName.MaximumLength = 0;
1048         AFSMountRootName.Buffer = NULL;
1049
1050         paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
1051         paramTable[0].Name = AFS_REG_MOUNT_ROOT;
1052         paramTable[0].EntryContext = &AFSMountRootName;
1053
1054         paramTable[0].DefaultType = REG_NONE;
1055         paramTable[0].DefaultData = NULL;
1056         paramTable[0].DefaultLength = 0;
1057
1058         //
1059         // Query the registry
1060         //
1061
1062         ntStatus = RtlQueryRegistryValues( RTL_REGISTRY_SERVICES,
1063                                            paramPath.Buffer,
1064                                            paramTable,
1065                                            NULL,
1066                                            NULL);
1067
1068         if ( NT_SUCCESS( ntStatus))
1069         {
1070             if ( AFSMountRootName.Buffer[0] == L'/')
1071             {
1072
1073                 AFSMountRootName.Buffer[0] = L'\\';
1074             }
1075         }
1076
1077         //
1078         // Free up the buffer
1079         //
1080
1081         ExFreePool( paramPath.Buffer);
1082
1083 try_exit:
1084
1085         if( !NT_SUCCESS( ntStatus))
1086         {
1087
1088             RtlInitUnicodeString( &AFSMountRootName,
1089                                   L"\\afs");
1090         }
1091     }
1092
1093     return ntStatus;
1094 }
1095
1096 NTSTATUS
1097 AFSSetSysNameInformation( IN AFSSysNameNotificationCB *SysNameInfo,
1098                           IN ULONG SysNameInfoBufferLength)
1099 {
1100     UNREFERENCED_PARAMETER(SysNameInfoBufferLength);
1101
1102     NTSTATUS         ntStatus = STATUS_SUCCESS;
1103     AFSDeviceExt    *pControlDevExt = (AFSDeviceExt *)AFSDeviceObject->DeviceExtension;
1104     AFSSysNameCB    *pSysName = NULL;
1105     ERESOURCE       *pSysNameLock = NULL;
1106     AFSSysNameCB   **pSysNameListHead = NULL, **pSysNameListTail = NULL;
1107     ULONG            ulIndex = 0;
1108     __Enter
1109     {
1110
1111         //
1112         // Depending on the architecture of the information, set up the lsit
1113         //
1114
1115         if( SysNameInfo->Architecture == AFS_SYSNAME_ARCH_32BIT)
1116         {
1117
1118             pSysNameLock = &pControlDevExt->Specific.Control.SysName32ListLock;
1119
1120             pSysNameListHead = &pControlDevExt->Specific.Control.SysName32ListHead;
1121
1122             pSysNameListTail = &pControlDevExt->Specific.Control.SysName32ListTail;
1123         }
1124         else
1125         {
1126
1127 #if defined(_WIN64)
1128
1129             pSysNameLock = &pControlDevExt->Specific.Control.SysName64ListLock;
1130
1131             pSysNameListHead = &pControlDevExt->Specific.Control.SysName64ListHead;
1132
1133             pSysNameListTail = &pControlDevExt->Specific.Control.SysName64ListTail;
1134
1135 #else
1136
1137             try_return( ntStatus = STATUS_INVALID_PARAMETER);
1138 #endif
1139         }
1140
1141         //
1142         // Process the request
1143         //
1144
1145         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1146                       AFS_TRACE_LEVEL_VERBOSE,
1147                       "AFSSetSysNameInformation Acquiring SysName lock %p EXCL %08lX\n",
1148                       pSysNameLock,
1149                       PsGetCurrentThread());
1150
1151         AFSAcquireExcl( pSysNameLock,
1152                         TRUE);
1153
1154         //
1155         // If we already have a list, then tear it down
1156         //
1157
1158         if( *pSysNameListHead != NULL)
1159         {
1160
1161             AFSResetSysNameList( *pSysNameListHead);
1162
1163             *pSysNameListHead = NULL;
1164         }
1165
1166         //
1167         // Loop through the entries adding in a node for each
1168         //
1169
1170         while( ulIndex < SysNameInfo->NumberOfNames)
1171         {
1172
1173             pSysName = (AFSSysNameCB *)AFSExAllocatePoolWithTag( PagedPool,
1174                                                                  sizeof( AFSSysNameCB) +
1175                                                                  SysNameInfo->SysNames[ ulIndex].Length +
1176                                                                  sizeof( WCHAR),
1177                                                                  AFS_SYS_NAME_NODE_TAG);
1178
1179             if( pSysName == NULL)
1180             {
1181
1182                 //
1183                 // Reset the current list
1184                 //
1185
1186                 AFSResetSysNameList( *pSysNameListHead);
1187
1188                 *pSysNameListHead = NULL;
1189
1190                 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1191             }
1192
1193             RtlZeroMemory( pSysName,
1194                            sizeof( AFSSysNameCB) +
1195                                    SysNameInfo->SysNames[ ulIndex].Length +
1196                                    sizeof( WCHAR));
1197
1198             pSysName->SysName.Length = (USHORT)SysNameInfo->SysNames[ ulIndex].Length;
1199
1200             pSysName->SysName.MaximumLength = pSysName->SysName.Length + sizeof( WCHAR);
1201
1202             pSysName->SysName.Buffer = (WCHAR *)((char *)pSysName + sizeof( AFSSysNameCB));
1203
1204             RtlCopyMemory( pSysName->SysName.Buffer,
1205                            SysNameInfo->SysNames[ ulIndex].String,
1206                            pSysName->SysName.Length);
1207
1208             if( *pSysNameListHead == NULL)
1209             {
1210
1211                 *pSysNameListHead = pSysName;
1212             }
1213             else
1214             {
1215
1216                 (*pSysNameListTail)->fLink = pSysName;
1217             }
1218
1219             *pSysNameListTail = pSysName;
1220
1221             ulIndex++;
1222         }
1223
1224 try_exit:
1225
1226         AFSReleaseResource( pSysNameLock);
1227     }
1228
1229     return ntStatus;
1230 }
1231
1232 void
1233 AFSResetSysNameList( IN AFSSysNameCB *SysNameList)
1234 {
1235
1236     AFSSysNameCB *pNextEntry = NULL, *pCurrentEntry = SysNameList;
1237
1238     while( pCurrentEntry != NULL)
1239     {
1240
1241         pNextEntry = pCurrentEntry->fLink;
1242
1243         ExFreePool( pCurrentEntry);
1244
1245         pCurrentEntry = pNextEntry;
1246     }
1247
1248     return;
1249 }
1250
1251 NTSTATUS
1252 AFSDefaultDispatch( IN PDEVICE_OBJECT DeviceObject,
1253                     IN PIRP Irp)
1254 {
1255     UNREFERENCED_PARAMETER(DeviceObject);
1256
1257     NTSTATUS            ntStatus = STATUS_INVALID_DEVICE_REQUEST;
1258
1259     AFSCompleteRequest( Irp,
1260                         ntStatus);
1261
1262     return ntStatus;
1263 }
1264
1265 NTSTATUS
1266 AFSSendDeviceIoControl( IN DEVICE_OBJECT *TargetDeviceObject,
1267                         IN ULONG IOControl,
1268                         IN void *InputBuffer,
1269                         IN ULONG InputBufferLength,
1270                         IN OUT void *OutputBuffer,
1271                         IN ULONG OutputBufferLength,
1272                         OUT ULONG *ResultLength)
1273 {
1274     UNREFERENCED_PARAMETER(OutputBuffer);
1275     UNREFERENCED_PARAMETER(OutputBufferLength);
1276
1277     NTSTATUS            ntStatus = STATUS_SUCCESS;
1278     PIRP                pIrp = NULL;
1279     KEVENT              kEvent;
1280     PIO_STACK_LOCATION  pIoStackLocation = NULL;
1281
1282     __Enter
1283     {
1284
1285         //
1286         // Initialize the event
1287         //
1288
1289         KeInitializeEvent( &kEvent,
1290                            SynchronizationEvent,
1291                            FALSE);
1292
1293         //
1294         // Allocate an irp for this request.  This could also come from a
1295         // private pool, for instance.
1296         //
1297
1298         pIrp = IoAllocateIrp( TargetDeviceObject->StackSize,
1299                               FALSE);
1300
1301         if( pIrp == NULL)
1302         {
1303
1304             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1305         }
1306
1307         //
1308         // Build the IRP's main body
1309         //
1310
1311         pIrp->RequestorMode = KernelMode;
1312
1313         //
1314         // Set up the I/O stack location.
1315         //
1316
1317         pIoStackLocation = IoGetNextIrpStackLocation( pIrp);
1318         pIoStackLocation->MajorFunction = IRP_MJ_DEVICE_CONTROL;
1319         pIoStackLocation->DeviceObject = TargetDeviceObject;
1320
1321         pIoStackLocation->Parameters.DeviceIoControl.IoControlCode = IOControl;
1322
1323         pIrp->AssociatedIrp.SystemBuffer = (void *)InputBuffer;
1324         pIoStackLocation->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength;
1325
1326         //
1327         // Set the completion routine.
1328         //
1329
1330         AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1331                       AFS_TRACE_LEVEL_VERBOSE,
1332                       "Setting AFSIrpComplete as IoCompletion Routine Irp %p\n",
1333                       pIrp);
1334
1335         IoSetCompletionRoutine( pIrp,
1336                                 AFSIrpComplete,
1337                                 &kEvent,
1338                                 TRUE,
1339                                 TRUE,
1340                                 TRUE);
1341
1342         //
1343         // Send it to the FSD
1344         //
1345
1346         ntStatus = IoCallDriver( TargetDeviceObject,
1347                                  pIrp);
1348
1349         if( NT_SUCCESS( ntStatus))
1350         {
1351
1352             //
1353             // Wait for the I/O
1354             //
1355
1356             ntStatus = KeWaitForSingleObject( &kEvent,
1357                                               Executive,
1358                                               KernelMode,
1359                                               FALSE,
1360                                               0);
1361
1362             if( NT_SUCCESS( ntStatus))
1363             {
1364
1365                 ntStatus = pIrp->IoStatus.Status;
1366
1367                 if( ResultLength != NULL)
1368                 {
1369                     *ResultLength = (ULONG)pIrp->IoStatus.Information;
1370                 }
1371             }
1372         }
1373
1374 try_exit:
1375
1376         if( pIrp != NULL)
1377         {
1378
1379             if( pIrp->MdlAddress != NULL)
1380             {
1381
1382                 if( FlagOn( pIrp->MdlAddress->MdlFlags, MDL_PAGES_LOCKED))
1383                 {
1384
1385                     MmUnlockPages( pIrp->MdlAddress);
1386                 }
1387
1388                 IoFreeMdl( pIrp->MdlAddress);
1389             }
1390
1391             pIrp->MdlAddress = NULL;
1392
1393             //
1394             // Free the Irp
1395             //
1396
1397             IoFreeIrp( pIrp);
1398         }
1399     }
1400
1401     return ntStatus;
1402 }
1403
1404 NTSTATUS
1405 AFSIrpComplete( IN PDEVICE_OBJECT DeviceObject,
1406                 IN PIRP           Irp,
1407                 IN PVOID          Context)
1408 {
1409     UNREFERENCED_PARAMETER(DeviceObject);
1410     UNREFERENCED_PARAMETER(Irp);
1411
1412     KEVENT *pEvent = (KEVENT *)Context;
1413
1414     KeSetEvent( pEvent,
1415                 0,
1416                 FALSE);
1417
1418     return STATUS_MORE_PROCESSING_REQUIRED;
1419 }
1420
1421 void *
1422 AFSExAllocatePoolWithTag( IN POOL_TYPE  PoolType,
1423                           IN SIZE_T  NumberOfBytes,
1424                           IN ULONG  Tag)
1425 {
1426
1427     AFSDeviceExt *pControlDevExt = NULL;
1428     void *pBuffer = NULL;
1429     BOOLEAN bTimeout = FALSE;
1430     LARGE_INTEGER liTimeout;
1431     NTSTATUS ntStatus;
1432
1433     //
1434     // Attempt to allocation memory from the system.  If the allocation fails
1435     // wait up to 30 seconds for the AFS redirector to free some memory.  As
1436     // long as the wait does not timeout, continue to retry the allocation.
1437     // If the wait does timeout, attempt to allocate one more time in case
1438     // memory was freed by another driver.  Otherwise, fail the request.
1439     //
1440
1441     if ( AFSDeviceObject)
1442     {
1443
1444         pControlDevExt = (AFSDeviceExt *)AFSDeviceObject->DeviceExtension;
1445     }
1446
1447     while( pBuffer == NULL)
1448     {
1449
1450         pBuffer = ExAllocatePoolWithTag( PoolType,
1451                                          NumberOfBytes,
1452                                          Tag);
1453
1454         if( pBuffer == NULL)
1455         {
1456
1457             if ( bTimeout || pControlDevExt == NULL)
1458             {
1459
1460                 AFSDbgLogMsg( 0,
1461                               0,
1462                               "AFSExAllocatePoolWithTag failure Type %08lX Size %08lX Tag %08lX %08lX\n",
1463                               PoolType,
1464                               NumberOfBytes,
1465                               Tag,
1466                               PsGetCurrentThread());
1467
1468                 switch ( Tag ) {
1469
1470                 case AFS_GENERIC_MEMORY_21_TAG:
1471                 case AFS_GENERIC_MEMORY_22_TAG:
1472                     // AFSDumpTraceFiles -- do nothing;
1473                     break;
1474
1475                 default:
1476                     AFSBreakPoint();
1477                 }
1478
1479                 break;
1480             }
1481
1482
1483             //
1484             // Wait up to 30 seconds for a memory deallocation
1485             //
1486
1487             liTimeout.QuadPart = -(30 *AFS_ONE_SECOND);
1488
1489             if( InterlockedIncrement( &pControlDevExt->Specific.Control.WaitingForMemoryCount) == 1)
1490             {
1491                 KeClearEvent( &pControlDevExt->Specific.Control.MemoryAvailableEvent);
1492             }
1493
1494             ntStatus = KeWaitForSingleObject( &pControlDevExt->Specific.Control.MemoryAvailableEvent,
1495                                               Executive,
1496                                               KernelMode,
1497                                               FALSE,
1498                                               &liTimeout);
1499
1500             if( ntStatus == STATUS_TIMEOUT)
1501             {
1502
1503                 bTimeout = TRUE;
1504             }
1505
1506             InterlockedDecrement( &pControlDevExt->Specific.Control.WaitingForMemoryCount);
1507         }
1508     }
1509
1510     return pBuffer;
1511 }
1512
1513 void
1514 AFSExFreePoolWithTag( IN void *Buffer, IN ULONG Tag)
1515 {
1516
1517     AFSDeviceExt *pControlDevExt = NULL;
1518
1519     if ( AFSDeviceObject)
1520     {
1521
1522         pControlDevExt = (AFSDeviceExt *)AFSDeviceObject->DeviceExtension;
1523     }
1524
1525     if ( Tag)
1526     {
1527
1528         ExFreePoolWithTag( Buffer, Tag);
1529     }
1530     else
1531     {
1532
1533         ExFreePool( Buffer);
1534     }
1535
1536     if ( pControlDevExt)
1537     {
1538
1539         KeSetEvent( &pControlDevExt->Specific.Control.MemoryAvailableEvent,
1540                     0,
1541                     FALSE);
1542     }
1543     return;
1544 }
1545
1546 NTSTATUS
1547 AFSShutdownRedirector()
1548 {
1549
1550     NTSTATUS ntStatus = STATUS_SUCCESS;
1551     AFSDeviceExt *pRDRDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
1552     AFSDeviceExt *pControlDevExt = (AFSDeviceExt *)AFSDeviceObject->DeviceExtension;
1553     LARGE_INTEGER liTimeout;
1554
1555     __Enter
1556     {
1557
1558         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1559                       AFS_TRACE_LEVEL_VERBOSE,
1560                       "%s Shutting down redirector Extent count %08lX Request count %08lX\n",
1561                       __FUNCTION__,
1562                       pControlDevExt->Specific.Control.ExtentCount,
1563                       pControlDevExt->Specific.Control.OutstandingServiceRequestCount);
1564
1565         //
1566         // Set the shutdown flag so the worker is more agressive in tearing down extents
1567         //
1568
1569         SetFlag( pRDRDevExt->DeviceFlags, AFS_DEVICE_FLAG_REDIRECTOR_SHUTDOWN);
1570
1571         //
1572         // Wait on any outstanding service requests
1573         //
1574
1575         liTimeout.QuadPart = -(30 *AFS_ONE_SECOND);
1576
1577         ntStatus = KeWaitForSingleObject( &pControlDevExt->Specific.Control.OutstandingServiceRequestEvent,
1578                                           Executive,
1579                                           KernelMode,
1580                                           FALSE,
1581                                           &liTimeout);
1582
1583         if( ntStatus == STATUS_TIMEOUT)
1584         {
1585
1586             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1587                           AFS_TRACE_LEVEL_WARNING,
1588                           "AFSShutdownRedirector Failed to complete all service requests Remaining count %08lX\n",
1589                           pControlDevExt->Specific.Control.OutstandingServiceRequestCount);
1590
1591             try_return( ntStatus = STATUS_UNSUCCESSFUL);
1592         }
1593
1594         AFSProcessQueuedResults( TRUE);
1595
1596         //
1597         // Wait for all extents to be released
1598         //
1599
1600         liTimeout.QuadPart = -(30 *AFS_ONE_SECOND);
1601
1602         ntStatus = KeWaitForSingleObject( &pControlDevExt->Specific.Control.ExtentsHeldEvent,
1603                                           Executive,
1604                                           KernelMode,
1605                                           FALSE,
1606                                           &liTimeout);
1607
1608         if( ntStatus == STATUS_TIMEOUT)
1609         {
1610
1611             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1612                           AFS_TRACE_LEVEL_WARNING,
1613                           "AFSShutdownRedirector Failed to purge all extents Remaining count %08lX\n",
1614                           pControlDevExt->Specific.Control.ExtentCount);
1615
1616             try_return( ntStatus = STATUS_UNSUCCESSFUL);
1617         }
1618
1619         ntStatus = AFSUnloadLibrary( TRUE);
1620
1621         if( !NT_SUCCESS( ntStatus))
1622         {
1623
1624             try_return( ntStatus);
1625         }
1626
1627 try_exit:
1628
1629         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1630                       AFS_TRACE_LEVEL_VERBOSE,
1631                       "%s Completed shut down of redirector Extent count %08lX Request count %08lX Status %08lX\n",
1632                       __FUNCTION__,
1633                       pControlDevExt->Specific.Control.ExtentCount,
1634                       pControlDevExt->Specific.Control.OutstandingServiceRequestCount,
1635                       ntStatus);
1636     }
1637
1638     return ntStatus;
1639 }
1640
1641 //
1642 // Cache manager callback routines
1643 //
1644
1645 BOOLEAN
1646 AFSAcquireFcbForLazyWrite( IN PVOID Fcb,
1647                            IN BOOLEAN Wait)
1648 {
1649
1650     BOOLEAN bStatus = FALSE;
1651     AFSFcb *pFcb = (AFSFcb *)Fcb;
1652     BOOLEAN bReleaseSectionObject = FALSE, bReleasePaging = FALSE;
1653
1654     //
1655     // Try and acquire the Fcb resource
1656     //
1657
1658     AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1659                   AFS_TRACE_LEVEL_VERBOSE,
1660                   "AFSAcquireFcbForLazyWrite Acquiring Fcb %p\n",
1661                   Fcb);
1662
1663     //
1664     // Try and grab the paging
1665     //
1666
1667     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1668                   AFS_TRACE_LEVEL_VERBOSE,
1669                   "AFSAcquireFcbForLazyWrite Attempt to acquire Fcb PagingIo lock %p SHARED %08lX\n",
1670                   &pFcb->NPFcb->PagingResource,
1671                   PsGetCurrentThread());
1672
1673     if( AFSAcquireShared( &pFcb->NPFcb->PagingResource,
1674                           Wait))
1675     {
1676
1677         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1678                       AFS_TRACE_LEVEL_VERBOSE,
1679                       "AFSAcquireFcbForLazyWrite Acquired Fcb PagingIo lock %p SHARED %08lX\n",
1680                       &pFcb->NPFcb->PagingResource,
1681                       PsGetCurrentThread());
1682
1683         bReleasePaging = TRUE;
1684
1685         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1686                       AFS_TRACE_LEVEL_VERBOSE,
1687                       "AFSAcquireFcbForLazyWrite Attempt to acquire Fcb SectionObject lock %p SHARED %08lX\n",
1688                       &pFcb->NPFcb->SectionObjectResource,
1689                       PsGetCurrentThread());
1690
1691         if( AFSAcquireShared( &pFcb->NPFcb->SectionObjectResource,
1692                               Wait))
1693         {
1694
1695             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1696                           AFS_TRACE_LEVEL_VERBOSE,
1697                           "AFSAcquireFcbForLazyWrite Acquired Fcb SectionObject lock %p SHARED %08lX\n",
1698                           &pFcb->NPFcb->SectionObjectResource,
1699                           PsGetCurrentThread());
1700
1701             bReleaseSectionObject = TRUE;
1702
1703             //
1704             // All is well ...
1705             //
1706
1707             bStatus = TRUE;
1708
1709             IoSetTopLevelIrp( (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
1710         }
1711     }
1712
1713     if( !bStatus)
1714     {
1715
1716         if( bReleaseSectionObject)
1717         {
1718
1719             AFSReleaseResource( &pFcb->NPFcb->SectionObjectResource);
1720         }
1721
1722         if( bReleasePaging)
1723         {
1724
1725             AFSReleaseResource( &pFcb->NPFcb->PagingResource);
1726         }
1727     }
1728
1729     return bStatus;
1730 }
1731
1732 VOID
1733 AFSReleaseFcbFromLazyWrite( IN PVOID Fcb)
1734 {
1735
1736     AFSFcb *pFcb = (AFSFcb *)Fcb;
1737
1738     AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1739                   AFS_TRACE_LEVEL_VERBOSE,
1740                   "AFSReleaseFcbFromLazyWrite Releasing Fcb %p\n",
1741                   Fcb);
1742
1743     IoSetTopLevelIrp( NULL);
1744
1745     AFSReleaseResource( &pFcb->NPFcb->SectionObjectResource);
1746
1747     AFSReleaseResource( &pFcb->NPFcb->PagingResource);
1748
1749     return;
1750 }
1751
1752 BOOLEAN
1753 AFSAcquireFcbForReadAhead( IN PVOID Fcb,
1754                            IN BOOLEAN Wait)
1755 {
1756
1757     BOOLEAN bStatus = FALSE;
1758     AFSFcb *pFcb = (AFSFcb *)Fcb;
1759
1760     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1761                   AFS_TRACE_LEVEL_VERBOSE,
1762                   "AFSAcquireFcbForReadAhead Attempt to acquire Fcb SectionObject lock %p SHARED %08lX\n",
1763                   &pFcb->NPFcb->SectionObjectResource,
1764                   PsGetCurrentThread());
1765
1766     if( AFSAcquireShared( &pFcb->NPFcb->SectionObjectResource,
1767                           Wait))
1768     {
1769
1770         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1771                       AFS_TRACE_LEVEL_VERBOSE,
1772                       "AFSAcquireFcbForReadAhead Acquired Fcb SectionObject lock %p SHARED %08lX\n",
1773                       &pFcb->NPFcb->SectionObjectResource,
1774                       PsGetCurrentThread());
1775
1776         bStatus = TRUE;
1777
1778         IoSetTopLevelIrp( (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
1779     }
1780
1781     return bStatus;
1782 }
1783
1784 VOID
1785 AFSReleaseFcbFromReadAhead( IN PVOID Fcb)
1786 {
1787
1788     AFSFcb *pFcb = (AFSFcb *)Fcb;
1789
1790     IoSetTopLevelIrp( NULL);
1791
1792     AFSReleaseResource( &pFcb->NPFcb->SectionObjectResource);
1793
1794     return;
1795 }
1796
1797 NTSTATUS
1798 AFSGetCallerSID( OUT UNICODE_STRING *SIDString, OUT BOOLEAN *pbImpersonation)
1799 {
1800
1801     NTSTATUS ntStatus = STATUS_SUCCESS;
1802     PACCESS_TOKEN hToken = NULL;
1803     TOKEN_USER *pTokenInfo = NULL;
1804     BOOLEAN bCopyOnOpen = FALSE;
1805     BOOLEAN bEffectiveOnly = FALSE;
1806     BOOLEAN bPrimaryToken = FALSE;
1807     SECURITY_IMPERSONATION_LEVEL stImpersonationLevel;
1808     UNICODE_STRING uniSIDString;
1809
1810     __Enter
1811     {
1812
1813         hToken = PsReferenceImpersonationToken( PsGetCurrentThread(),
1814                                                 &bCopyOnOpen,
1815                                                 &bEffectiveOnly,
1816                                                 &stImpersonationLevel);
1817
1818         if( hToken == NULL)
1819         {
1820
1821             hToken = PsReferencePrimaryToken( PsGetCurrentProcess());
1822
1823             if( hToken == NULL)
1824             {
1825
1826                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1827                               AFS_TRACE_LEVEL_ERROR,
1828                               "AFSGetCallerSID Failed to retrieve impersonation or primary token\n");
1829
1830                 try_return( ntStatus);
1831             }
1832
1833             bPrimaryToken = TRUE;
1834         }
1835
1836         ntStatus = SeQueryInformationToken( hToken,
1837                                             TokenUser,
1838                                             (PVOID *)&pTokenInfo);
1839
1840         if( !NT_SUCCESS( ntStatus))
1841         {
1842
1843             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1844                           AFS_TRACE_LEVEL_ERROR,
1845                           "AFSGetCallerSID Failed to retrieve information Status %08lX\n", ntStatus);
1846
1847             try_return( ntStatus);
1848         }
1849
1850         uniSIDString.Length = 0;
1851         uniSIDString.MaximumLength = 0;
1852         uniSIDString.Buffer = NULL;
1853
1854         ntStatus = RtlConvertSidToUnicodeString( &uniSIDString,
1855                                                  pTokenInfo->User.Sid,
1856                                                  TRUE);
1857
1858         if( !NT_SUCCESS( ntStatus))
1859         {
1860
1861             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1862                           AFS_TRACE_LEVEL_ERROR,
1863                           "AFSGetCallerSID Failed to convert sid to string Status %08lX\n", ntStatus);
1864
1865             try_return( ntStatus);
1866         }
1867
1868         *SIDString = uniSIDString;
1869
1870         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING | AFS_SUBSYSTEM_AUTHGROUP_PROCESSING,
1871                       AFS_TRACE_LEVEL_VERBOSE_2,
1872                       "AFSGetCallerSID Successfully retrieved SID %wZ\n",
1873                       SIDString);
1874
1875         if ( bPrimaryToken == FALSE &&
1876              pbImpersonation)
1877         {
1878             *pbImpersonation = TRUE;
1879         }
1880
1881 try_exit:
1882
1883         if( hToken != NULL)
1884         {
1885             if( bPrimaryToken)
1886             {
1887                 PsDereferencePrimaryToken( hToken);
1888             }
1889             else
1890             {
1891                 PsDereferenceImpersonationToken( hToken);
1892             }
1893         }
1894
1895         if( pTokenInfo != NULL)
1896         {
1897             ExFreePool( pTokenInfo);    // Allocated by SeQueryInformationToken
1898         }
1899     }
1900
1901     return ntStatus;
1902 }
1903
1904 ULONG
1905 AFSGetSessionId( IN HANDLE ProcessId, OUT BOOLEAN *pbImpersonation)
1906 {
1907     UNREFERENCED_PARAMETER(ProcessId);
1908
1909     NTSTATUS ntStatus = STATUS_SUCCESS;
1910     PACCESS_TOKEN hToken = NULL;
1911     ULONG ulSessionId = (ULONG)-1;
1912     BOOLEAN bCopyOnOpen = FALSE;
1913     BOOLEAN bEffectiveOnly = FALSE;
1914     BOOLEAN bPrimaryToken = FALSE;
1915     SECURITY_IMPERSONATION_LEVEL stImpersonationLevel;
1916
1917     __Enter
1918     {
1919
1920         hToken = PsReferenceImpersonationToken( PsGetCurrentThread(),
1921                                                 &bCopyOnOpen,
1922                                                 &bEffectiveOnly,
1923                                                 &stImpersonationLevel);
1924
1925         if( hToken == NULL)
1926         {
1927
1928             hToken = PsReferencePrimaryToken( PsGetCurrentProcess());
1929
1930             if( hToken == NULL)
1931             {
1932
1933                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1934                               AFS_TRACE_LEVEL_ERROR,
1935                               "AFSGetSessionId Failed to retrieve impersonation or primary token\n");
1936
1937                 try_return( ntStatus);
1938             }
1939
1940             bPrimaryToken = TRUE;
1941         }
1942
1943         ntStatus = SeQueryInformationToken( hToken,
1944                                             TokenSessionId,
1945                                             (PVOID *)&ulSessionId);
1946
1947         if( !NT_SUCCESS( ntStatus))
1948         {
1949             ulSessionId = (ULONG)-1;
1950
1951             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1952                           AFS_TRACE_LEVEL_ERROR,
1953                           "AFSGetSessionId Failed to retrieve session id Status %08lX\n",
1954                           ntStatus);
1955
1956             try_return( ntStatus);
1957         }
1958
1959         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING | AFS_SUBSYSTEM_AUTHGROUP_PROCESSING,
1960                       AFS_TRACE_LEVEL_VERBOSE_2,
1961                       "AFSGetSessionId found %08lX\n",
1962                       ulSessionId);
1963
1964         if ( bPrimaryToken == FALSE &&
1965              pbImpersonation)
1966         {
1967             *pbImpersonation = TRUE;
1968         }
1969
1970 try_exit:
1971
1972         if( hToken != NULL)
1973         {
1974             if( bPrimaryToken)
1975             {
1976                 PsDereferencePrimaryToken( hToken);
1977             }
1978             else
1979             {
1980                 PsDereferenceImpersonationToken( hToken);
1981             }
1982         }
1983     }
1984
1985     return ulSessionId;
1986 }
1987
1988 NTSTATUS
1989 AFSCheckThreadDacl( OUT GUID *AuthGroup)
1990 {
1991
1992     NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
1993     ULONG idx;
1994     PACCESS_TOKEN token = NULL;
1995     PTOKEN_DEFAULT_DACL defDacl = NULL;
1996     PACE_HEADER ace;
1997     PACCESS_ALLOWED_ACE adace;
1998     BOOLEAN bCopyOnOpen = FALSE, bEffectiveOnly = FALSE;
1999     SECURITY_IMPERSONATION_LEVEL stImpersonationLevel;
2000     BOOLEAN bLocatedACE = FALSE;
2001
2002     __Enter
2003     {
2004
2005         token = PsReferenceImpersonationToken( PsGetCurrentThread(),
2006                                                &bCopyOnOpen,
2007                                                &bEffectiveOnly,
2008                                                &stImpersonationLevel);
2009
2010         if( token == NULL)
2011         {
2012            try_return( ntStatus);
2013         }
2014
2015         ntStatus = SeQueryInformationToken( token,
2016                                             TokenDefaultDacl,
2017                                             (PVOID *)&defDacl);
2018
2019         if( ntStatus != STATUS_SUCCESS)
2020         {
2021            try_return( ntStatus);
2022         }
2023
2024         // scan through all ACEs in the DACL
2025         for (idx = 0, ace = (PACE_HEADER)((char *)defDacl->DefaultDacl + sizeof(ACL)); idx < defDacl->DefaultDacl->AceCount; idx++)
2026         {
2027            if (ace->AceType == ACCESS_ALLOWED_ACE_TYPE)
2028            {
2029               adace = (PACCESS_ALLOWED_ACE)ace;
2030
2031               if (adace->Header.AceSize == (FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + AFS_DACL_SID_LENGTH))
2032               {
2033                  if (RtlCompareMemory( RtlSubAuthoritySid((PSID)&adace->SidStart, 0), &AFSSidGuid, sizeof(GUID)) == sizeof(GUID))
2034                  {
2035
2036                     RtlCopyMemory( AuthGroup,
2037                                    RtlSubAuthoritySid((PSID)&adace->SidStart, 4),
2038                                    sizeof( GUID));
2039
2040                     bLocatedACE = TRUE;
2041
2042                     break;
2043                  }
2044               }
2045            }
2046
2047            // go to next ace
2048            ace = (PACE_HEADER)((char *)ace + ace->AceSize);
2049         }
2050
2051 try_exit:
2052
2053         if( token != NULL)
2054         {
2055             PsDereferenceImpersonationToken( token);
2056         }
2057
2058         if (defDacl != NULL)
2059         {
2060            ExFreePool(defDacl);
2061         }
2062
2063         if( !bLocatedACE)
2064         {
2065             ntStatus = STATUS_UNSUCCESSFUL;
2066         }
2067     }
2068
2069     return ntStatus;
2070 }
2071
2072 NTSTATUS
2073 AFSProcessSetProcessDacl( IN AFSProcessCB *ProcessCB)
2074 {
2075
2076     PTOKEN_DEFAULT_DACL defDacl = NULL;
2077     HANDLE hToken = NULL;
2078     PACE_HEADER ace = NULL;
2079     SID_IDENTIFIER_AUTHORITY sia = SECURITY_NT_AUTHORITY;
2080     PACCESS_ALLOWED_ACE aaace;
2081     ULONG bytesNeeded;
2082     ULONG bytesReturned;
2083     ULONG idx;
2084     PSID psid;
2085     NTSTATUS ntStatus = STATUS_SUCCESS;
2086
2087     __Enter
2088     {
2089
2090         ntStatus = ZwOpenProcessTokenEx( NtCurrentProcess(),
2091                                          GENERIC_ALL,
2092                                          OBJ_KERNEL_HANDLE,
2093                                          &hToken);
2094
2095         if( !NT_SUCCESS( ntStatus))
2096         {
2097             try_return( ntStatus);
2098         }
2099
2100         // get the size of the current DACL
2101         ntStatus = ZwQueryInformationToken( hToken,
2102                                             TokenDefaultDacl,
2103                                             NULL,
2104                                             0,
2105                                             &bytesNeeded);
2106
2107         // if we failed to get the buffer size needed
2108         if ((ntStatus != STATUS_SUCCESS) && (ntStatus != STATUS_BUFFER_TOO_SMALL))
2109         {
2110             try_return( ntStatus);
2111         }
2112
2113         // tack on enough space for our ACE if we need to add it...
2114         bytesNeeded += FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + AFS_DACL_SID_LENGTH;
2115
2116         // allocate space for the DACL
2117         defDacl = (PTOKEN_DEFAULT_DACL)ExAllocatePoolWithTag( PagedPool, bytesNeeded, AFS_GENERIC_MEMORY_26_TAG);
2118
2119         if (defDacl == NULL)
2120         {
2121            try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
2122         }
2123
2124         // get the DACL
2125         ntStatus = ZwQueryInformationToken( hToken,
2126                                             TokenDefaultDacl,
2127                                             defDacl,
2128                                             bytesNeeded,
2129                                             &bytesReturned);
2130
2131         if( ntStatus != STATUS_SUCCESS)
2132         {
2133             try_return( ntStatus);
2134         }
2135
2136         // scan through DACL to see if we have the SID set already...
2137         ace = (PACE_HEADER)((char *)defDacl->DefaultDacl + sizeof(ACL));
2138         for (idx = 0; idx < defDacl->DefaultDacl->AceCount; idx++)
2139         {
2140             if (ace->AceType == ACCESS_ALLOWED_ACE_TYPE)
2141             {
2142                 aaace = (PACCESS_ALLOWED_ACE)ace;
2143
2144                 if (aaace->Header.AceSize == (FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + AFS_DACL_SID_LENGTH))
2145                 {
2146                     // if the GUID part matches
2147                     if( RtlCompareMemory( RtlSubAuthoritySid((PSID)&aaace->SidStart, 0),
2148                                           &AFSSidGuid,
2149                                           sizeof(GUID)) == sizeof(GUID))
2150                     {
2151
2152                         if ( RtlCompareMemory( RtlSubAuthoritySid((PSID)&aaace->SidStart, 4),
2153                                                ProcessCB->ActiveAuthGroup,
2154                                                sizeof( GUID)) != sizeof( GUID))
2155                         {
2156
2157                             RtlCopyMemory( RtlSubAuthoritySid((PSID)&aaace->SidStart, 4),
2158                                            ProcessCB->ActiveAuthGroup,
2159                                            sizeof( GUID));
2160
2161                             if( AFSSetInformationToken != NULL)
2162                             {
2163                                 ntStatus = AFSSetInformationToken( hToken,
2164                                                                    TokenDefaultDacl,
2165                                                                    defDacl,
2166                                                                    bytesReturned);
2167                             }
2168                         }
2169
2170                         try_return( ntStatus);
2171                     }
2172                 }
2173             }
2174
2175             // go to next ace
2176             ace = (PACE_HEADER)((char *)ace + ace->AceSize);
2177         }
2178
2179         //
2180         // if we made it here we need to add a new ACE to the DACL
2181         //
2182
2183         aaace = (ACCESS_ALLOWED_ACE *)ace;
2184         aaace->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
2185         aaace->Header.AceFlags = 0;
2186         aaace->Mask = GENERIC_ALL;
2187         psid = (PSID)&aaace->SidStart;
2188         RtlInitializeSid( psid, &sia, 8);
2189
2190         RtlCopyMemory( RtlSubAuthoritySid(psid, 0),
2191                        &AFSSidGuid,
2192                        sizeof(GUID));
2193
2194         RtlCopyMemory( RtlSubAuthoritySid(psid, 4),
2195                        ProcessCB->ActiveAuthGroup,
2196                        sizeof( GUID));
2197
2198         aaace->Header.AceSize = (USHORT)(FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + RtlLengthSid( psid));
2199
2200         defDacl->DefaultDacl->AclSize += aaace->Header.AceSize;
2201         defDacl->DefaultDacl->AceCount++;
2202
2203         if( AFSSetInformationToken != NULL)
2204         {
2205             ntStatus = AFSSetInformationToken( hToken,
2206                                               TokenDefaultDacl,
2207                                               defDacl,
2208                                               defDacl->DefaultDacl->AclSize + sizeof(PTOKEN_DEFAULT_DACL));
2209         }
2210
2211 try_exit:
2212
2213         if( hToken != NULL)
2214         {
2215             ZwClose( hToken);
2216         }
2217
2218         if (defDacl != NULL)
2219         {
2220            ExFreePool( defDacl);
2221         }
2222     }
2223
2224     return ntStatus;
2225 }
2226
2227