WDK Mini Filter Example
nccreate.c
Go to the documentation of this file.
1 /*++
2 
3 Copyright (c) 1999 - 2002 Microsoft Corporation
4 
5 Module Name:
6 
7  nccreate.c
8 
9 Abstract:
10 
11  Contains routines to process user-initiated creates. We need to
12  detect if these need to be redirected to a new physical location,
13  and redirect as appropriate.
14 
15 Environment:
16 
17  Kernel mode
18 
19 --*/
20 
21 #include "nc.h"
22 
23 #ifdef ALLOC_PRAGMA
24 #pragma alloc_text(PAGE, NcPreCreate)
25 #endif
26 
27 
28 FLT_PREOP_CALLBACK_STATUS
30  _Inout_ PFLT_CALLBACK_DATA Data,
31  _In_ PCFLT_RELATED_OBJECTS FltObjects,
32  _Flt_CompletionContext_Outptr_ PVOID *CompletionContext
33  )
34 /*++
35 
36 Routine Description:
37 
38  Routine is invoked when a create is issued by a user.
39 
40 
41 Arguments:
42 
43  Data - Pointer to the filter CallbackData that is passed to us.
44 
45  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
46  opaque handles to this filter, instance, its associated volume and
47  file object.
48 
49  CompletionContext - The context for the completion routine for this
50  operation.
51 
52 Return Value:
53 
54  The return value is the Status of the operation.
55 
56 Logic:
57 
58  1) If file is opened by ID or is a Paging File, etc.
59  A) return FLT_PREOP_SUCCESS_NO_CALLBACK
60  2) Get the opened name and calculate overlap
61  3) If File is Delete On close
62  A) If the file is an ancestor of either mapping
63  a) Fail Open
64  4) If the path is in the real mapping
65  A) Fail the Open
66  5) If the path is in user mapping
67  A) Recalculate the full name (without SL_OPEN_TARGET_DIRECTORY)
68  B) Munge Name to Real Mapping
69  C) Switch name
70  D) Passthrough with callback.
71  6) Else
72  A) Return Passthrough No callback
73 --*/
74 {
75 
76 
77  NTSTATUS Status;
78  FLT_PREOP_CALLBACK_STATUS ReturnValue = FLT_PREOP_SUCCESS_NO_CALLBACK;
79  PFLT_FILE_NAME_INFORMATION FileNameInformation = NULL;
80  PFLT_FILE_NAME_INFORMATION FullFileNameInformation = NULL;
81  PNC_INSTANCE_CONTEXT InstanceContext = NULL;
82  NC_PATH_OVERLAP RealOverlap, UserOverlap, FullOverlap;
83  UNICODE_STRING Remainder;
84  UNICODE_STRING MungedName = EMPTY_UNICODE_STRING;
85  BOOLEAN IgnoreCase = !BooleanFlagOn( Data->Iopb->OperationFlags, SL_CASE_SENSITIVE );
86  UCHAR CreateDisposition = (UCHAR)(Data->Iopb->Parameters.Create.Options >> 24);
87 
88  PAGED_CODE();
89 
90  UNREFERENCED_PARAMETER( CompletionContext );
91 
92  FLT_ASSERT( IoGetTopLevelIrp() == NULL );
93 
94  //
95  // Check if this open is to the paging file.
96  // We are not going to handle munging the namespace for paging files.
97  //
98 
99  if (FlagOn( Data->Iopb->OperationFlags, SL_OPEN_PAGING_FILE )) {
100 
101  ReturnValue = FLT_PREOP_SUCCESS_NO_CALLBACK;
102  goto NcPreCreateCleanup;
103  }
104 
105  //
106  // Check if this is a volume open.
107  // Volume opens do not affect the namespace of the volume so we don't care.
108  //
109 
110  if (FlagOn( Data->Iopb->TargetFileObject->Flags, FO_VOLUME_OPEN )) {
111 
112  ReturnValue = FLT_PREOP_SUCCESS_NO_CALLBACK;
113  goto NcPreCreateCleanup;
114  }
115 
116  //
117  // Check if this open is by ID.
118  // Opens by file ID are name agnostic. Thus we do not care about this open.
119  //
120 
121  if (FlagOn( Data->Iopb->Parameters.Create.Options, FILE_OPEN_BY_FILE_ID )) {
122 
123  ReturnValue = FLT_PREOP_SUCCESS_NO_CALLBACK;
124  goto NcPreCreateCleanup;
125  }
126 
127  //
128  // Get opened name.
129  // This is pre-create so this is the name which will be opened if allowed
130  // to continue. Note that unlike most other paths, we do not call
131  // ourselves here; doing so would munge the "real" name into the "user"
132  // name, which would prevent us from detecting access via the "real"
133  // name. Because this request is not being sent to us, we need to ensure
134  // we don't poison the cache of below filters (allowing the user visible
135  // mapping to be cached beneath us.)
136  //
137 
138  Status = NcGetFileNameInformation( Data,
139  NULL,
140  NULL,
141  FLT_FILE_NAME_OPENED |
142  FLT_FILE_NAME_QUERY_DEFAULT |
143  FLT_FILE_NAME_DO_NOT_CACHE,
144  &FileNameInformation );
145 
146  if (!NT_SUCCESS( Status )) {
147 
148  ReturnValue = FLT_PREOP_COMPLETE;
149  goto NcPreCreateCleanup;
150  }
151 
152  Status = FltParseFileNameInformation( FileNameInformation );
153 
154  if (!NT_SUCCESS( Status )) {
155 
156  ReturnValue = FLT_PREOP_COMPLETE;
157  goto NcPreCreateCleanup;
158  }
159 
160  //
161  // Get the instance context.
162  //
163 
164  Status = FltGetInstanceContext( FltObjects->Instance,
165  &InstanceContext );
166 
167  if (!NT_SUCCESS( Status )) {
168 
169  ReturnValue = FLT_PREOP_COMPLETE;
170  goto NcPreCreateCleanup;
171  }
172 
173  FLT_ASSERT( InstanceContext != NULL );
174 
175  //
176  // Get the open path's relation to the mapping paths.
177  //
178 
179  NcComparePath( &FileNameInformation->Name,
180  &InstanceContext->Mapping.RealMapping,
181  NULL,
182  IgnoreCase,
183  TRUE,
184  &RealOverlap );
185 
186  NcComparePath( &FileNameInformation->Name,
187  &InstanceContext->Mapping.UserMapping,
188  &Remainder,
189  IgnoreCase,
190  TRUE,
191  &UserOverlap );
192 
193  //
194  // Name changer uses the opened name of a file as an indicator that the
195  // file has been munged. Because of this we have to deny opens down the
196  // real mapping in order to disambiguate whether it was opened via the
197  // munging operation. We thus disallow opens down the real mapping path.
198  //
199 
200  if (RealOverlap.Match) {
201 
202  //
203  // When opening the mapping itself, we have virtualized its
204  // nonexistence to the caller. Therefore, any attempt to open
205  // should return a not found code, and any conditional open/create
206  // is effectively a create and should be failed with a code
207  // appropriate for that.
208  //
209 
210  ReturnValue = FLT_PREOP_COMPLETE;
211  switch (CreateDisposition) {
212  case FILE_OPEN:
213  case FILE_OVERWRITE:
214  Status = STATUS_OBJECT_NAME_NOT_FOUND;
215  goto NcPreCreateCleanup;
216  case FILE_CREATE:
217  case FILE_OPEN_IF:
218  case FILE_OVERWRITE_IF:
219  case FILE_SUPERSEDE:
220  Status = STATUS_ACCESS_DENIED;
221  goto NcPreCreateCleanup;
222  }
223 
224  FLT_ASSERT( FALSE );
225  Status = STATUS_ACCESS_DENIED;
226  goto NcPreCreateCleanup;
227 
228  } else if (RealOverlap.InMapping) {
229 
230  Status = STATUS_OBJECT_PATH_NOT_FOUND;
231  ReturnValue = FLT_PREOP_COMPLETE;
232  goto NcPreCreateCleanup;
233  }
234 
235  //
236  // Short names around the mapping cause a problem for namechanger.
237  // This is because the filesystem will generate new shortnames which are
238  // not told to fltmgr. Finding out the names accurately is not reliable
239  // because the name can change while fltmgr is querying the name.
240  //
241  // One solution to this problem is to protect the mapping. We prevent
242  // users from renaming or deleting the mapping paths so that we know the
243  // short names do not change.
244  //
245  // In create we need to make sure that the FILE_DELETE_ON_CLOSE flag is
246  // not set if the user is opening the real mapping or an ancestor of it.
247  //
248 
249  if (FlagOn( Data->Iopb->Parameters.Create.Options, FILE_DELETE_ON_CLOSE )) {
250 
251  if (RealOverlap.Ancestor || UserOverlap.Ancestor) {
252 
253  Status = STATUS_ACCESS_DENIED;
254  ReturnValue = FLT_PREOP_COMPLETE;
255  goto NcPreCreateCleanup;
256  }
257  }
258 
259  //
260  // Name changer munges opens which occur down the user mapping path.
261  // Here we check to see if this is a name we want to change.
262  //
263 
264  if (UserOverlap.InMapping) {
265 
266  //
267  // This open is targeted inside the user mapping.
268  // This means that we need to munge the open name
269  // to the real mapping.
270  //
271 
272  //
273  // Constructing a new path for the file has a quirk because of
274  // SL_OPEN_TARGET_DIRECTORY. If it is set, then the name has the
275  // following components: /device/ancestors/parent/final_component.
276  // If the flag is set, then fltmgr stripped of the final component
277  // (leaving /device/ancestors/parent) when we called
278  // FltGetFileNameInformation.
279  //
280  // File systems assume that file objects for use as a target directory
281  // in rename operations are opened with SL_OPEN_TARGET_DIRECTORY.
282  // This means that unlike the related file object, which can be just
283  // cleared, opens with SL_OPEN_TARGET_DIRECTORY need to be propogated
284  // with the flag always.
285  //
286  // This means that opens which get munged and have
287  // SL_OPEN_TARGET_DIRECTORY need to be calculated with the final
288  // component in the name string.
289  //
290 
291  if (FlagOn( Data->Iopb->OperationFlags, SL_OPEN_TARGET_DIRECTORY )) {
292 
293  //
294  // Clear the flag so we can get the full name.
295  //
296 
297  ClearFlag( Data->Iopb->OperationFlags, SL_OPEN_TARGET_DIRECTORY );
298 
299  //
300  // Get the name with the final component.
301  //
302 
303  Status = NcGetFileNameInformation( Data,
304  NULL,
305  NULL,
306  FLT_FILE_NAME_OPENED | FLT_FILE_NAME_QUERY_FILESYSTEM_ONLY,
307  &FullFileNameInformation );
308 
309  if (!NT_SUCCESS( Status )) {
310 
311  ReturnValue = FLT_PREOP_COMPLETE;
312  goto NcPreCreateCleanup;
313  }
314 
315  Status = FltParseFileNameInformation( FullFileNameInformation );
316 
317  if (!NT_SUCCESS( Status )) {
318 
319  ReturnValue = FLT_PREOP_COMPLETE;
320  goto NcPreCreateCleanup;
321  }
322 
323  FLT_ASSERT( FullFileNameInformation != NULL );
324 
325  //
326  // Now that we have the full path, lets put the
327  // flag back on the file object.
328  //
329 
330  SetFlag( Data->Iopb->OperationFlags, SL_OPEN_TARGET_DIRECTORY );
331 
332  //
333  // We need to re-calculate the Remainder so we can
334  // construct the new name.
335  //
336 
337  NcComparePath( &FullFileNameInformation->Name,
338  &InstanceContext->Mapping.UserMapping,
339  &Remainder,
340  IgnoreCase,
341  TRUE,
342  &FullOverlap );
343 
344  //
345  // Since we were dealing with a path further down
346  // the mapping, lets make sure that we are now
347  // even further down the mapping.
348  //
349 
350  FLT_ASSERT( FullOverlap.InMapping );
351 
352  }
353 
354  //
355  // Generate new name
356  //
357 
358  Status = NcConstructPath( &InstanceContext->Mapping.RealMapping,
359  &Remainder,
360  FALSE,
361  &MungedName );
362 
363  if (!NT_SUCCESS( Status )) {
364 
365  ReturnValue = FLT_PREOP_COMPLETE;
366  goto NcPreCreateCleanup;
367  }
368 
369  //
370  // Replace open name in the file object.
371  //
372 
373  Status = NcReplaceFileObjectName( Data->Iopb->TargetFileObject,
374  MungedName.Buffer,
375  MungedName.Length );
376 
377  if (!NT_SUCCESS(Status)) {
378 
379  ReturnValue = FLT_PREOP_COMPLETE;
380  goto NcPreCreateCleanup;
381  }
382 
383  //
384  // Because we calculate our own full path, the
385  // RelatedFileObject is not needed on munged creates.
386  // Make sure that we don't send it below us.
387  //
388 
389  FltObjects->FileObject->RelatedFileObject = NULL;
390 
391  //
392  // Pass the create below us.
393  //
394 
395  ReturnValue = FLT_PREOP_SUCCESS_NO_CALLBACK;
396  goto NcPreCreateCleanup;
397 
398  } //end if for in mapping
399 
400  //
401  // If we got here then we are not interested in this open.
402  // Passthrough no callback.
403  //
404 
405  ReturnValue = FLT_PREOP_SUCCESS_NO_CALLBACK;
406  goto NcPreCreateCleanup;
407 
408 NcPreCreateCleanup:
409 
410  //
411  // Check if we care going to fail the open.
412  //
413 
414  if (ReturnValue == FLT_PREOP_COMPLETE) {
415 
416  //
417  // If we get here, then Status must be a failure code.
418  //
419 
420  FLT_ASSERT( !NT_SUCCESS( Status ) );
421 
422  Data->IoStatus.Status = Status;
423  }
424 
425  //
426  // Clean up variables
427  //
428 
429  if (FileNameInformation != NULL) {
430 
431  FltReleaseFileNameInformation( FileNameInformation );
432  }
433 
434  if (FullFileNameInformation != NULL) {
435 
436  FltReleaseFileNameInformation( FullFileNameInformation );
437  }
438 
439  if (MungedName.Buffer != NULL) {
440 
441  ExFreePoolWithTag( MungedName.Buffer, NC_TAG );
442  }
443 
444  if (InstanceContext != NULL) {
445 
446  FltReleaseContext( InstanceContext );
447  }
448 
449  return ReturnValue;
450 }
451 
#define EMPTY_UNICODE_STRING
Definition: nc.h:33
NC_MAPPING_ENTRY RealMapping
Definition: nc.h:186
NC_REPLACE_FILEOBJECT_NAME_TYPE NcReplaceFileObjectName
Definition: nccompat.c:78
FLT_ASSERT(IS_MY_CONTROL_DEVICE_OBJECT(DeviceObject))
return TRUE
NC_MAPPING Mapping
Definition: nc.h:233
NC_MAPPING_ENTRY UserMapping
Definition: nc.h:187
_In_opt_ PFILE_OBJECT _In_opt_ PFLT_INSTANCE _In_ FLT_FILE_NAME_OPTIONS _Outptr_ PFLT_FILE_NAME_INFORMATION * FileNameInformation
Definition: nc.h:493
#define FlagOn(_F, _SF)
Definition: minispy.h:247
int Ancestor
Definition: nc.h:217
UNREFERENCED_PARAMETER(FileObject)
NcLoadRegistryStringRetry NULL
Definition: ncinit.c:53
int InMapping
Definition: nc.h:220
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
NcLoadRegistryStringCleanup NC_TAG
Definition: ncinit.c:170
FLT_PREOP_CALLBACK_STATUS NcPreCreate(_Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _Flt_CompletionContext_Outptr_ PVOID *CompletionContext)
Definition: nccreate.c:29

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