WDK Mini Filter Example
ncnameprov.c
Go to the documentation of this file.
1 
2 #include "nc.h"
3 
4 #ifdef ALLOC_PRAGMA
5 #pragma alloc_text(PAGE, NcGenerateFileName)
6 #pragma alloc_text(PAGE, NcNormalizeNameComponentEx)
7 #endif
8 
9 NTSTATUS
11  _In_ PFLT_INSTANCE Instance,
12  _In_ PFILE_OBJECT FileObject,
13  _In_opt_ PFLT_CALLBACK_DATA Data,
14  _In_ FLT_FILE_NAME_OPTIONS NameOptions,
15  _Out_ PBOOLEAN CacheFileNameInformation,
16  _Inout_ PFLT_NAME_CONTROL OutputNameControl
17  )
18 {
19  //
20  // Status vars
21  //
22 
23  NTSTATUS Status;
24 
25  //
26  // State lookup vars
27  //
28 
29  BOOLEAN Opened = (BOOLEAN)(FileObject->FsContext != NULL); // True if file object is opened.
30  BOOLEAN ReturnShortName = (BOOLEAN)(FltGetFileNameFormat(NameOptions) == FLT_FILE_NAME_SHORT); // True if the user is requesting short name
31  BOOLEAN ReturnOpenedName = (BOOLEAN)(FltGetFileNameFormat(NameOptions) == FLT_FILE_NAME_OPENED); // True if user is requesting opened name.
32  BOOLEAN ReturnNormalizedName = (BOOLEAN)(FltGetFileNameFormat(NameOptions) == FLT_FILE_NAME_NORMALIZED); // True if user is requesting normalized name.
33  BOOLEAN IgnoreCase;
34  FLT_FILE_NAME_OPTIONS NameQueryMethod = FltGetFileNameQueryMethod( NameOptions );
35  FLT_FILE_NAME_OPTIONS NameFlags = FLT_VALID_FILE_NAME_FLAGS & NameOptions;
36 
37  //
38  // File name information
39  //
40 
41  PFLT_FILE_NAME_INFORMATION LowerNameInfo = NULL; // File name as reported by lower name provider. Will always be down real mapping.
42  PFLT_FILE_NAME_INFORMATION ShortInfo = NULL; // We will use ShortInfo to store the short name if needed.
43 
44  //
45  // Contexts
46  //
47 
48  PNC_INSTANCE_CONTEXT InstanceContext = NULL;
49 
50  //
51  // Overlap
52  //
53 
54  NC_PATH_OVERLAP RealOverlap;
55  UNICODE_STRING RealRemainder = EMPTY_UNICODE_STRING;
56 
57  //
58  // Temp storage
59  //
60 
61  UNICODE_STRING MungedName = EMPTY_UNICODE_STRING;
62 
63  //
64  // Temp pointer
65  //
66 
67  PUNICODE_STRING Name = NULL; // Pointer to the name we are going to use.
68 
69  PAGED_CODE();
70 
71  FLT_ASSERT( IoGetTopLevelIrp() == NULL );
72 
73  //
74  // This should never happen, but let's be safe.
75  //
76 
77  if (!ReturnShortName &&
78  !ReturnOpenedName &&
79  !ReturnNormalizedName) {
80 
81  FLT_ASSERT( FALSE );
82  Status = STATUS_NOT_SUPPORTED;
83  goto NcGenerateFileNameCleanup;
84  }
85 
86  RealOverlap.EntireFlags = 0;
87 
88  //
89  // To prevent infinite recursion, calls to FltGetFileNameInformation
90  // from generate file name callbacks should not target current provider.
91  //
92 
93  ClearFlag( NameFlags, FLT_FILE_NAME_REQUEST_FROM_CURRENT_PROVIDER );
94 
95  //
96  // Fetch the instance context.
97  //
98 
99  Status = FltGetInstanceContext( Instance, &InstanceContext );
100 
101  if (!NT_SUCCESS( Status )) {
102 
103  goto NcGenerateFileNameCleanup;
104  }
105 
106  //
107  // We need to know what the name provider under us thinks the file is called.
108  // If the caller wants the normalized name we query that, otherwise we query
109  // the opened name because we have to compare the full path of the file vs.
110  // the real mapping to determine if the file is mapped.
111  //
112 
113  Status = NcGetFileNameInformation( Data,
114  FileObject,
115  Instance,
116  (ReturnNormalizedName ? FLT_FILE_NAME_NORMALIZED
117  : FLT_FILE_NAME_OPENED) |
118  NameQueryMethod |
119  NameFlags,
120  &LowerNameInfo );
121 
122  if (!NT_SUCCESS( Status )) {
123 
124  goto NcGenerateFileNameCleanup;
125  }
126 
127  Status = FltParseFileNameInformation( LowerNameInfo );
128 
129  if (!NT_SUCCESS( Status )) {
130 
131  goto NcGenerateFileNameCleanup;
132  }
133 
134  //
135  // Issues With Pre-open path:
136  //
137  // 1) Poison name cache below name provider:
138  // If a filter above a name provider calls FltGetFileNameInformation on a
139  // file object in his precreate callback, fltmgr will call the name
140  // provider's generate name callback before the name provider's pre create
141  // callback is invoked. Name providers by their nature change names in their
142  // pre-create. Because the name provider has not had the opportunity to
143  // modify the name yet, we need to make sure that fltmgr does not cache the name we
144  // return below us, so we set the FLT_FILE_NAME_DO_NOT_CACHE flag.
145  // //TODO: TRY TO GET ACROSS THAT THIS IS A NAME CHANGER PROBLEM, NOT ALL NAME PROVIDERS NEED TO.
146  //
147 
148  if (!Opened) {
149 
150  SetFlag( NameFlags, FLT_FILE_NAME_DO_NOT_CACHE );
151 
152  if (Data) {
153 
154  //
155  // NT supports case sensitive and non-case sensitive naming in file systems.
156  // This is handled on a per-open basis. Weather an open is case senstive is
157  // determined by the FO_OPENED_CASE_SENSITIVE flag on the file object.
158  // In pre-create the SL_CASE_SENSITIVE flag on the create IRP specifies the mode.
159  //
160  // If this is on an unopened FileObject, it had better be pre-create so we know
161  // how to process the operation. If we are queried on an unopened FileObject
162  // at any other time we have no way to handle the request.
163  //
164 
165  FLT_ASSERT( Data->Iopb->MajorFunction == IRP_MJ_CREATE ||
166  Data->Iopb->MajorFunction == IRP_MJ_NETWORK_QUERY_OPEN );
167 
168  IgnoreCase = !BooleanFlagOn( Data->Iopb->OperationFlags, SL_CASE_SENSITIVE );
169 
170  } else {
171 
172  //
173  // If people do unsafe queries on preopened IOs, we cannot
174  // determine if the open is case sensitive or not.
175  // So we cannot determine if this open is down the mapping.
176  // fail.
177  //
178 
179  FLT_ASSERT( FALSE );
180  Status = STATUS_INVALID_PARAMETER;
181  goto NcGenerateFileNameCleanup;
182 
183  }
184 
185  } else {
186 
187  //
188  // After a file has been opened, the case sensitivity is stored in the file object.
189  //
190 
191  IgnoreCase = !BooleanFlagOn( FileObject->Flags, FO_OPENED_CASE_SENSITIVE );
192  }
193 
194  //
195  // Calculate the overlap with the real mapping.
196  //
197 
198  NcComparePath( &LowerNameInfo->Name,
199  &InstanceContext->Mapping.RealMapping,
200  &RealRemainder,
201  IgnoreCase,
202  TRUE,
203  &RealOverlap );
204 
205  //
206  // Whether we munge depends on what name is requested.
207  //
208 
209  if (ReturnOpenedName ||
210  ReturnNormalizedName) {
211 
212  if (Opened &&
213  RealOverlap.InMapping) {
214 
215  //
216  // We munge the opened name if it overlaps with the real mapping.
217  // The returned path will be down the user mapping.
218  //
219 
220  Status = NcConstructPath( &InstanceContext->Mapping.UserMapping,
221  &RealRemainder,
222  TRUE,
223  &MungedName);
224 
225  if (!NT_SUCCESS( Status )) {
226 
227  goto NcGenerateFileNameCleanup;
228  }
229 
230  Name = &MungedName;
231 
232  } else {
233 
234  //
235  // We return the queried result if the path is not in the
236  // mapping.
237  //
238 
239  Name = &LowerNameInfo->Name;
240 
241  }
242 
243  } else if (ReturnShortName) {
244 
245  //
246  // Note that unlike opened names, a query for a shortname only returns
247  // the final component, not the full path.
248  //
249 
250  // TODO: Assert not preopen
251 
252  if (RealOverlap.Match) {
253 
254  //
255  // The opened path is the mapping path.
256  // This means that if we queried the filesystem
257  // he would return the wrong path.
258  //
259  // Luckily, we can just use the mapping.
260  //
261 
262  Name = &InstanceContext->Mapping.UserMapping.ShortNamePath.FinalComponentName;
263 
264  } else {
265 
266  //
267  // We have to query below us to get the short name.
268  //
269 
270  Status = NcGetFileNameInformation( Data,
271  FileObject,
272  Instance,
273  FLT_FILE_NAME_SHORT |
274  NameQueryMethod |
275  NameFlags,
276  &ShortInfo );
277 
278  if (!NT_SUCCESS( Status )) {
279 
280  goto NcGenerateFileNameCleanup;
281  }
282 
283  Status = FltParseFileNameInformation( ShortInfo );
284 
285  if (!NT_SUCCESS(Status)) {
286 
287  goto NcGenerateFileNameCleanup;
288  }
289 
290  //
291  // Set name to returned name.
292  //
293 
294  Name = &ShortInfo->Name;
295  }
296  }
297 
298  FLT_ASSERT( Name != NULL );
299 
300  //
301  // Try to grow the namechanger's record to accommodate the result.
302  //
303 
304  Status = FltCheckAndGrowNameControl( OutputNameControl, Name->Length );
305 
306  if (NT_SUCCESS( Status )) {
307 
308  //
309  // Copy the new name into the buffer.
310  //
311 
312  RtlCopyUnicodeString( &OutputNameControl->Name, Name );
313  *CacheFileNameInformation = TRUE;
314  }
315 
316 NcGenerateFileNameCleanup:
317 
318  if (LowerNameInfo != NULL) {
319 
320  FltReleaseFileNameInformation( LowerNameInfo );
321  }
322 
323  if (ShortInfo != NULL) {
324 
325  FltReleaseFileNameInformation( ShortInfo );
326  }
327 
328  if (InstanceContext != NULL) {
329 
330  FltReleaseContext( InstanceContext );
331  }
332 
333  if (MungedName.Buffer != NULL) {
334 
335  ExFreePoolWithTag( MungedName.Buffer, NC_GENERATE_NAME_TAG );
336  }
337 
338  return Status;
339 }
340 
341 NTSTATUS
343  _In_ PFLT_INSTANCE Instance,
344  _In_opt_ PFILE_OBJECT FileObject,
345  _In_ PCUNICODE_STRING ParentDirectory,
346  _In_ USHORT DeviceNameLength,
347  _In_ PCUNICODE_STRING Component,
348  _Out_writes_bytes_(ExpandComponentNameLength) PFILE_NAMES_INFORMATION ExpandComponentName,
349  _In_ ULONG ExpandComponentNameLength,
350  _In_ FLT_NORMALIZE_NAME_FLAGS Flags,
351  _Inout_ PVOID *NormalizationContext
352  )
353 {
354 
355  NTSTATUS Status;
356  PNC_INSTANCE_CONTEXT InstanceContext = NULL;
357  NC_PATH_OVERLAP ParentOverlap; //overlap between the parent path and the user mapping.
358  UNICODE_STRING Remainder;
359  UNICODE_STRING MungedParentPath; // Path we are going to open for query
360  PCUNICODE_STRING MungedComponent; // File name to enumerate
361  PWSTR MungedBuffer = NULL;
362  ULONG MungedBufferLength;
363 
364  IO_STATUS_BLOCK ParentStatusBlock;
365  OBJECT_ATTRIBUTES ParentAttributes;
366  HANDLE ParentHandle = 0;
367  PFILE_OBJECT ParentFileObject = NULL;
368  BOOLEAN IgnoreCase = !BooleanFlagOn( Flags, FLTFL_NORMALIZE_NAME_CASE_SENSITIVE );
369 
370  PAGED_CODE();
371 
372  FLT_ASSERT( IoGetTopLevelIrp() == NULL );
373 
374  UNREFERENCED_PARAMETER( NormalizationContext );
375  UNREFERENCED_PARAMETER( DeviceNameLength );
376  UNREFERENCED_PARAMETER( FileObject );
377 
378  Status = FltGetInstanceContext( Instance,
379  &InstanceContext );
380 
381  if (!NT_SUCCESS( Status )) {
382 
383  goto NcNormalizeNameComponentExCleanup;
384  }
385 
386  //
387  // Default to enumerating the component specified by the
388  // caller.
389  //
390 
391  MungedComponent = Component;
392 
393  NcComparePath( ParentDirectory,
394  &InstanceContext->Mapping.UserMapping,
395  &Remainder,
396  IgnoreCase,
397  TRUE,
398  &ParentOverlap );
399 
400  //
401  // We need to figure out which path we are going to open.
402  //
403 
404  if (ParentOverlap.InMapping) {
405 
406  //
407  // The parent is in the mapping, so it has to be
408  // munged in order to be opened.
409  //
410 
411  MungedBufferLength = Remainder.Length + InstanceContext->Mapping.RealMapping.LongNamePath.FullPath.Length;
412 
413  MungedBuffer = ExAllocatePoolWithTag( PagedPool, MungedBufferLength, NC_NORMALIZE_NAME_TAG );
414 
415  if (MungedBuffer == NULL) {
416 
417  Status = STATUS_INSUFFICIENT_RESOURCES;
418  goto NcNormalizeNameComponentExCleanup;
419  }
420 
421  //
422  // Construct munged name.
423  //
424 
425  MungedParentPath.Buffer = MungedBuffer;
426  MungedParentPath.Length = 0;
427  MungedParentPath.MaximumLength = (USHORT) MungedBufferLength;
428 
429  RtlCopyUnicodeString( &MungedParentPath,
430  &InstanceContext->Mapping.RealMapping.LongNamePath.FullPath );
431 
432  RtlAppendUnicodeStringToString( &MungedParentPath,
433  &Remainder);
434 
435  } else if (ParentOverlap.Parent) {
436 
437  //
438  // The parent is the parent of the user mapping.
439  // That means we need to see if the final component is
440  // the mapping path itself.
441  //
442 
443  if( RtlCompareUnicodeString( Component,
445  IgnoreCase) == 0 ||
446  RtlCompareUnicodeString( Component,
448  IgnoreCase) == 0) {
449 
450  //
451  // The requested final component is the mapping itself.
452  // Hence the real mapping is the munged name.
453  //
454 
455  MungedParentPath = InstanceContext->Mapping.RealMapping.LongNamePath.ParentPath;
456  MungedComponent = &InstanceContext->Mapping.RealMapping.LongNamePath.FinalComponentName;
457 
458  } else {
459 
460  //
461  // The system is requesting another path in the user mapping's parent.
462  // Go ahead and open the given path.
463  //
464 
465  MungedParentPath = *ParentDirectory;
466  }
467 
468  } else { //ParentOverlap is not within or parent of mapping.
469 
470  MungedParentPath = *ParentDirectory;
471  }
472 
473  //
474  // We should open MungedParentPath and enumerate it.
475  //
476 
477  InitializeObjectAttributes( &ParentAttributes,
478  &MungedParentPath,
479  OBJ_KERNEL_HANDLE | (IgnoreCase?OBJ_CASE_INSENSITIVE:0),
480  NULL,
481  NULL);
482 
484  Instance,
485  &ParentHandle,
486  &ParentFileObject,
487  FILE_LIST_DIRECTORY | FILE_TRAVERSE,
488  &ParentAttributes,
489  &ParentStatusBlock,
490  0,
491  FILE_ATTRIBUTE_NORMAL,
492  0,
493  FILE_OPEN,
494  FILE_DIRECTORY_FILE,
495  NULL,
496  0,
497  IO_IGNORE_SHARE_ACCESS_CHECK,
498  FileObject );
499 
500  if (!NT_SUCCESS( Status )) {
501 
502  goto NcNormalizeNameComponentExCleanup;
503  }
504 
505  Status = NcQueryDirectoryFile( Instance,
506  ParentFileObject,
507  ExpandComponentName,
508  ExpandComponentNameLength,
509  FileNamesInformation,
510  TRUE,
511  (PUNICODE_STRING) MungedComponent,
512  TRUE,
513  NULL );
514 
515  if (!NT_SUCCESS( Status )) {
516 
517  goto NcNormalizeNameComponentExCleanup;
518  }
519 
520  //
521  // The object exists. Now we need to return the correct
522  // final name.
523  //
524 
525  if (Component != MungedComponent) {
526 
527  ULONG SizeRequired;
528 
529  SizeRequired = FIELD_OFFSET( FILE_NAMES_INFORMATION, FileName ) +
530  InstanceContext->Mapping.UserMapping.LongNamePath.FinalComponentName.Length;
531 
532  if (ExpandComponentNameLength < SizeRequired) {
533 
534  Status = STATUS_BUFFER_OVERFLOW;
535  goto NcNormalizeNameComponentExCleanup;
536  }
537 
538  FLT_ASSERT( ExpandComponentName->NextEntryOffset == 0 );
539  ExpandComponentName->NextEntryOffset = 0;
540  ExpandComponentName->FileIndex = 0;
541  ExpandComponentName->FileNameLength = InstanceContext->Mapping.UserMapping.LongNamePath.FinalComponentName.Length;
542  RtlCopyMemory( ExpandComponentName->FileName,
543  InstanceContext->Mapping.UserMapping.LongNamePath.FinalComponentName.Buffer,
544  InstanceContext->Mapping.UserMapping.LongNamePath.FinalComponentName.Length );
545 
546  }
547 
548  //TODO THIS NEEDS TO
549 
550 NcNormalizeNameComponentExCleanup:
551 
552  if (InstanceContext != NULL) {
553 
554  FltReleaseContext( InstanceContext );
555  }
556 
557  if (MungedBuffer != NULL) {
558 
559  ExFreePoolWithTag( MungedBuffer, NC_NORMALIZE_NAME_TAG );
560  }
561 
562  if (ParentHandle != 0) {
563 
564  FltClose( ParentHandle );
565  }
566 
567  if (ParentFileObject != NULL) {
568 
569  ObDereferenceObject( ParentFileObject );
570 
571  }
572 
573  //TODO THERE ARE ONLY TWO VALID ERROR CODES: STATUS_NO_SUCH_FILE, STATUS_SUCCESS if you want the name construction to continue.
574  //any other code will stop the query.
575  return Status;
576 }
#define EMPTY_UNICODE_STRING
Definition: nc.h:33
UNICODE_STRING FinalComponentName
Definition: nc.h:159
UNICODE_STRING FullPath
Definition: nc.h:156
NC_MAPPING_ENTRY RealMapping
Definition: nc.h:186
RtlCopyMemory(OutputStringBuffer, TempMappingBuffer->Data, OutputString->MaximumLength)
NTSTATUS NcNormalizeNameComponentEx(_In_ PFLT_INSTANCE Instance, _In_opt_ PFILE_OBJECT FileObject, _In_ PCUNICODE_STRING ParentDirectory, _In_ USHORT DeviceNameLength, _In_ PCUNICODE_STRING Component, _Out_writes_bytes_(ExpandComponentNameLength) PFILE_NAMES_INFORMATION ExpandComponentName, _In_ ULONG ExpandComponentNameLength, _In_ FLT_NORMALIZE_NAME_FLAGS Flags, _Inout_ PVOID *NormalizationContext)
Definition: ncnameprov.c:342
#define IRP_MJ_NETWORK_QUERY_OPEN
Definition: minispy.h:37
_In_opt_ PFILE_OBJECT _In_opt_ PFLT_INSTANCE Instance
Definition: nc.h:493
NC_MAPPING_PATH ShortNamePath
Definition: nc.h:176
NC_MAPPING_PATH LongNamePath
Definition: nc.h:173
FLT_ASSERT(IS_MY_CONTROL_DEVICE_OBJECT(DeviceObject))
#define NC_NORMALIZE_NAME_TAG
Definition: nc.h:18
return TRUE
NC_MAPPING Mapping
Definition: nc.h:233
_In_opt_ PFILE_OBJECT _In_opt_ PFLT_INSTANCE _In_ FLT_FILE_NAME_OPTIONS NameOptions
Definition: nc.h:493
NTSTATUS NcGenerateFileName(_In_ PFLT_INSTANCE Instance, _In_ PFILE_OBJECT FileObject, _In_opt_ PFLT_CALLBACK_DATA Data, _In_ FLT_FILE_NAME_OPTIONS NameOptions, _Out_ PBOOLEAN CacheFileNameInformation, _Inout_ PFLT_NAME_CONTROL OutputNameControl)
Definition: ncnameprov.c:10
NC_MAPPING_ENTRY UserMapping
Definition: nc.h:187
_In_ PLARGE_INTEGER _In_ ULONG _In_ ULONG _Out_writes_bytes_(Length)
NC_QUERY_DIRECTORY_FILE_TYPE NcQueryDirectoryFile
Definition: nccompat.c:79
UNREFERENCED_PARAMETER(FileObject)
NcLoadRegistryStringRetry NULL
Definition: ncinit.c:53
int InMapping
Definition: nc.h:220
UNICODE_STRING ParentPath
Definition: nc.h:158
ULONG EntireFlags
Definition: nc.h:215
int Match
Definition: nc.h:219
BOOLEAN NcComparePath(_In_ PCUNICODE_STRING Name, _In_ PNC_MAPPING_ENTRY Mapping, _Out_opt_ PUNICODE_STRING Remainder, _In_ BOOLEAN IgnoreCase, _In_ BOOLEAN ContainsDevice, _Out_ PNC_PATH_OVERLAP Overlap)
Definition: ncpath.c:13
PAGED_CODE()
IoStatus Status
NC_GLOBAL_DATA NcGlobalData
Definition: nc.c:335
NTSTATUS NcCreateFileHelper(_In_ PFLT_FILTER Filter, _In_opt_ PFLT_INSTANCE Instance, _Out_ PHANDLE FileHandle, _Outptr_opt_ PFILE_OBJECT *FileObject, _In_ ACCESS_MASK DesiredAccess, _In_ POBJECT_ATTRIBUTES ObjectAttributes, _Out_ PIO_STATUS_BLOCK IoStatusBlock, _In_opt_ PLARGE_INTEGER AllocationSize, _In_ ULONG FileAttributes, _In_ ULONG ShareAccess, _In_ ULONG CreateDisposition, _In_ ULONG CreateOptions, _In_reads_bytes_opt_(EaLength) PVOID EaBuffer, _In_ ULONG EaLength, _In_ ULONG Flags, _In_opt_ PFILE_OBJECT ParentFileObject)
Definition: nchelper.c:195
#define NC_GENERATE_NAME_TAG
Definition: nc.h:17
int Parent
Definition: nc.h:218
PFLT_FILTER FilterHandle
Definition: nc.h:475
_In_opt_ PFILE_OBJECT FileObject
Definition: nc.h:493
#define IRP_MJ_CREATE
Definition: mspyLog.h:284

Social Network


Services Overview

Architect, implement and test file system filter drivers for a wide range of functionality. We can offer several levels of assistance to meet your specific.

Contact Us

You are welcome to contact us for salse or partnership.

Sales: sales@easefilter.com
Support: support@easefilter.com
Info: info@easefilter.com