1 /*
2 * PROJECT: ReactOS fltmc utility
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/applications/fltmc/fltmc.c
5 * PURPOSE: Control utility for file system filter drivers
6 * PROGRAMMERS: Copyright 2016 Ged Murphy (gedmurphy@gmail.com)
7 */
8
9 // Please leave this temporary hack in place
10 // it's used to keep VS2015 happy for development.
11 #ifdef __REACTOS__
12 #include <stdarg.h>
13 #include <windef.h>
14 #include <winbase.h>
15 #include <wchar.h>
16 #else
17 #include <Windows.h>
18 #endif
19 #include <fltuser.h>
20 #include <atlstr.h>
21 #include <strsafe.h>
22 #include "resource.h"
23
24 EXTERN_C int wmain(int argc, WCHAR *argv[]);
25
26 void
LoadAndPrintString(ULONG MessageId,...)27 LoadAndPrintString(ULONG MessageId, ...)
28 {
29 va_list args;
30
31 CAtlStringW Message;
32 if (Message.LoadStringW(MessageId))
33 {
34 va_start(args, MessageId);
35 vwprintf(Message.GetBuffer(), args);
36 va_end(args);
37 }
38 }
39
40 void
PrintErrorText(_In_ ULONG ErrorCode)41 PrintErrorText(_In_ ULONG ErrorCode)
42 {
43 WCHAR Buffer[256];
44 if (FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM,
45 0,
46 ErrorCode,
47 0,
48 Buffer,
49 256,
50 0))
51 {
52 wprintf(L"%s\n", Buffer);
53 }
54 }
55
56 DWORD
SetDriverLoadPrivilege()57 SetDriverLoadPrivilege()
58 {
59 TOKEN_PRIVILEGES TokenPrivileges;
60 HANDLE hToken;
61 LUID luid;
62 BOOL bSuccess;
63 DWORD dwError = ERROR_SUCCESS;
64
65 bSuccess = OpenProcessToken(GetCurrentProcess(),
66 TOKEN_ADJUST_PRIVILEGES,
67 &hToken);
68 if (bSuccess == FALSE)
69 return GetLastError();
70
71 if (!LookupPrivilegeValueW(NULL, SE_LOAD_DRIVER_NAME, &luid))
72 return GetLastError();
73
74 TokenPrivileges.PrivilegeCount = 1;
75 TokenPrivileges.Privileges[0].Luid = luid;
76 TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
77
78 bSuccess = AdjustTokenPrivileges(hToken,
79 FALSE,
80 &TokenPrivileges,
81 sizeof(TOKEN_PRIVILEGES),
82 NULL,
83 NULL);
84 if (bSuccess == FALSE)
85 dwError = GetLastError();
86
87 CloseHandle(hToken);
88
89 return dwError;
90 }
91
92 void
LoadFilter(_In_ LPWSTR FilterName)93 LoadFilter(_In_ LPWSTR FilterName)
94 {
95 DWORD dwError;
96 dwError = SetDriverLoadPrivilege();
97 if (dwError != ERROR_SUCCESS)
98 {
99 LoadAndPrintString(IDS_ERROR_PRIV, HRESULT_FROM_WIN32(dwError));
100 return;
101 }
102
103 HRESULT hr = FilterLoad(FilterName);
104 if (hr != S_OK)
105 {
106 LoadAndPrintString(IDS_ERROR_LOAD, hr);
107 PrintErrorText(hr);
108 }
109 }
110
111 void
UnloadFilter(_In_ LPWSTR FilterName)112 UnloadFilter(_In_ LPWSTR FilterName)
113 {
114 DWORD dwError;
115 dwError = SetDriverLoadPrivilege();
116 if (dwError != ERROR_SUCCESS)
117 {
118 LoadAndPrintString(IDS_ERROR_PRIV, HRESULT_FROM_WIN32(dwError));
119 return;
120 }
121
122 HRESULT hr = FilterUnload(FilterName);
123 if (hr != S_OK)
124 {
125 LoadAndPrintString(IDS_ERROR_UNLOAD, hr);
126 PrintErrorText(hr);
127 }
128 }
129
130 void
PrintFilterInfo(_In_ PVOID Buffer,_In_ BOOL IsNewStyle)131 PrintFilterInfo(_In_ PVOID Buffer,
132 _In_ BOOL IsNewStyle)
133 {
134 WCHAR FilterName[128] = { 0 };
135 WCHAR NumOfInstances[16] = { 0 };
136 WCHAR Altitude[64] = { 0 };
137 WCHAR Frame[16] = { 0 };
138
139 if (IsNewStyle)
140 {
141 PFILTER_AGGREGATE_STANDARD_INFORMATION FilterAggInfo;
142 FilterAggInfo = (PFILTER_AGGREGATE_STANDARD_INFORMATION)Buffer;
143
144 if (FilterAggInfo->Flags & FLTFL_ASI_IS_MINIFILTER)
145 {
146 if (FilterAggInfo->Type.MiniFilter.FilterNameLength < 128)
147 {
148 CopyMemory(FilterName,
149 (PCHAR)FilterAggInfo + FilterAggInfo->Type.MiniFilter.FilterNameBufferOffset,
150 FilterAggInfo->Type.MiniFilter.FilterNameLength);
151 FilterName[FilterAggInfo->Type.MiniFilter.FilterNameLength] = UNICODE_NULL;
152 }
153
154 StringCchPrintfW(NumOfInstances, 16, L"%lu", FilterAggInfo->Type.MiniFilter.NumberOfInstances);
155
156 if (FilterAggInfo->Type.MiniFilter.FilterAltitudeLength < 64)
157 {
158 CopyMemory(Altitude,
159 (PCHAR)FilterAggInfo + FilterAggInfo->Type.MiniFilter.FilterAltitudeBufferOffset,
160 FilterAggInfo->Type.MiniFilter.FilterAltitudeLength);
161 FilterName[FilterAggInfo->Type.MiniFilter.FilterAltitudeLength] = UNICODE_NULL;
162 }
163
164 StringCchPrintfW(Frame, 16, L"%lu", FilterAggInfo->Type.MiniFilter.FrameID);
165 }
166 else if (FilterAggInfo->Flags & FLTFL_ASI_IS_LEGACYFILTER)
167 {
168 if (FilterAggInfo->Type.LegacyFilter.FilterNameLength < 128)
169 {
170 CopyMemory(FilterName,
171 (PCHAR)FilterAggInfo + FilterAggInfo->Type.LegacyFilter.FilterNameBufferOffset,
172 FilterAggInfo->Type.LegacyFilter.FilterNameLength);
173 FilterName[FilterAggInfo->Type.LegacyFilter.FilterNameLength] = UNICODE_NULL;
174 }
175
176 StringCchCopyW(Frame, 16, L"<Legacy>"); //Fixme: is this localized?
177 }
178
179 wprintf(L"%-38s %-10s %-10s %3s\n",
180 FilterName,
181 NumOfInstances,
182 Altitude,
183 Frame);
184 }
185 else
186 {
187 PFILTER_FULL_INFORMATION FilterInfo;
188 FilterInfo = (PFILTER_FULL_INFORMATION)Buffer;
189
190 if (FilterInfo->FilterNameLength < 128)
191 {
192 CopyMemory(FilterName,
193 FilterInfo->FilterNameBuffer,
194 FilterInfo->FilterNameLength);
195 FilterName[FilterInfo->FilterNameLength] = UNICODE_NULL;
196 }
197
198 wprintf(L"%-38s %-10lu %-10lu\n",
199 FilterName,
200 FilterInfo->NumberOfInstances,
201 FilterInfo->FrameID);
202 }
203 }
204
205 void
PrintVolumeInfo(_In_ PVOID Buffer)206 PrintVolumeInfo(_In_ PVOID Buffer)
207 {
208 PFILTER_VOLUME_STANDARD_INFORMATION FilterVolInfo;
209 WCHAR DosName[16] = { 0 };
210 WCHAR VolName[128] = { 0 };
211 WCHAR FileSystem[32] = { 0 };
212
213 FilterVolInfo = (PFILTER_VOLUME_STANDARD_INFORMATION)Buffer;
214
215 if (FilterVolInfo->FilterVolumeNameLength < 128)
216 {
217 CopyMemory(VolName,
218 (PCHAR)FilterVolInfo->FilterVolumeName,
219 FilterVolInfo->FilterVolumeNameLength);
220 VolName[FilterVolInfo->FilterVolumeNameLength] = UNICODE_NULL;
221 }
222
223 if (!SUCCEEDED(FilterGetDosName(VolName, DosName, _countof(DosName))))
224 DosName[0] = L'\0';
225
226 switch (FilterVolInfo->FileSystemType)
227 {
228 case FLT_FSTYPE_MUP:
229 StringCchCopyW(FileSystem, 32, L"Remote");
230 break;
231
232 case FLT_FSTYPE_NTFS:
233 StringCchCopyW(FileSystem, 32, L"NTFS");
234 break;
235
236 case FLT_FSTYPE_FAT:
237 StringCchCopyW(FileSystem, 32, L"FAT");
238 break;
239
240 case FLT_FSTYPE_EXFAT:
241 StringCchCopyW(FileSystem, 32, L"exFAT");
242 break;
243
244 case FLT_FSTYPE_NPFS:
245 StringCchCopyW(FileSystem, 32, L"NamedPipe");
246 break;
247
248 case FLT_FSTYPE_MSFS:
249 StringCchCopyW(FileSystem, 32, L"Mailslot");
250 break;
251
252 case FLT_FSTYPE_UNKNOWN:
253 default:
254 StringCchCopyW(FileSystem, 32, L"<Unknown>");
255 break;
256 }
257
258 wprintf(L"%-31s %-40s %-10s\n",
259 DosName,
260 VolName,
261 FileSystem);
262 }
263
264 void
ListFilters()265 ListFilters()
266 {
267 HANDLE FindHandle;
268 BYTE Buffer[1024];
269 ULONG BytesReturned;
270 BOOL IsNewStyle = TRUE;
271 HRESULT hr;
272
273 hr = FilterFindFirst(FilterAggregateStandardInformation,
274 Buffer,
275 sizeof(Buffer),
276 &BytesReturned,
277 &FindHandle);
278 if (!SUCCEEDED(hr))
279 {
280 IsNewStyle = FALSE;
281 hr = FilterFindFirst(FilterFullInformation,
282 Buffer,
283 sizeof(Buffer),
284 &BytesReturned,
285 &FindHandle);
286 }
287
288 if (!SUCCEEDED(hr))
289 {
290 LoadAndPrintString(IDS_ERROR_FILTERS, hr);
291 PrintErrorText(hr);
292 return;
293 }
294
295 if (IsNewStyle)
296 {
297 LoadAndPrintString(IDS_DISPLAY_FILTERS1);
298 wprintf(L"------------------------------ ------------- ------------ -----\n");
299 }
300 else
301 {
302 LoadAndPrintString(IDS_DISPLAY_FILTERS2);
303 wprintf(L"------------------------------ ------------- -----\n");
304 }
305
306 PrintFilterInfo(Buffer, IsNewStyle);
307
308 do
309 {
310 hr = FilterFindNext(FindHandle,
311 IsNewStyle ? FilterAggregateStandardInformation : FilterFullInformation,
312 Buffer,
313 sizeof(Buffer),
314 &BytesReturned);
315 if (SUCCEEDED(hr))
316 {
317 PrintFilterInfo(Buffer, IsNewStyle);
318 }
319 else if (hr != HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS))
320 {
321 LoadAndPrintString(IDS_ERROR_FILTERS, hr);
322 PrintErrorText(hr);
323 }
324 } while (SUCCEEDED(hr));
325
326 hr = FilterFindClose(FindHandle);
327 if (!SUCCEEDED(hr))
328 {
329 LoadAndPrintString(IDS_ERROR_FILTERS, hr);
330 PrintErrorText(hr);
331 }
332 }
333
334 void
ListVolumes()335 ListVolumes()
336 {
337 HANDLE FindHandle;
338 BYTE Buffer[1024];
339 ULONG BytesReturned;
340 HRESULT hr;
341
342 hr = FilterVolumeFindFirst(FilterVolumeStandardInformation,
343 Buffer,
344 1024,
345 &BytesReturned,
346 &FindHandle);
347 if (SUCCEEDED(hr))
348 {
349 LoadAndPrintString(IDS_DISPLAY_VOLUMES);
350 wprintf(L"------------------------------ --------------------------------------- ---------- --------\n");
351
352 PrintVolumeInfo(Buffer);
353
354 do
355 {
356 hr = FilterVolumeFindNext(FindHandle,
357 FilterVolumeStandardInformation,
358 Buffer,
359 1024,
360 &BytesReturned);
361 if (SUCCEEDED(hr))
362 {
363 PrintVolumeInfo(Buffer);
364 }
365
366 } while (SUCCEEDED(hr));
367
368 FilterVolumeFindClose(FindHandle);
369 }
370
371 if (!SUCCEEDED(hr) && hr != HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS))
372 {
373 LoadAndPrintString(IDS_ERROR_VOLUMES, hr);
374 PrintErrorText(hr);
375 }
376 }
377
wmain(int argc,WCHAR * argv[])378 int wmain(int argc, WCHAR *argv[])
379 {
380 wprintf(L"\n");
381
382 if ((argc < 2) || (!_wcsicmp(argv[1], L"filters")))
383 {
384 if (argc < 3)
385 {
386 ListFilters();
387 }
388 else
389 {
390 LoadAndPrintString(IDS_USAGE_FILTERS);
391 wprintf(L"fltmc.exe filters\n\n");
392 }
393 }
394 else if (!_wcsicmp(argv[1], L"help"))
395 {
396 LoadAndPrintString(IDS_USAGE);
397 }
398 else if (!_wcsicmp(argv[1], L"load"))
399 {
400 if (argc == 3)
401 {
402 LoadFilter(argv[2]);
403 }
404 else
405 {
406 LoadAndPrintString(IDS_USAGE_LOAD);
407 wprintf(L"fltmc.exe load [name]\n\n");
408 }
409 }
410 else if (!_wcsicmp(argv[1], L"unload"))
411 {
412 if (argc == 3)
413 {
414 UnloadFilter(argv[2]);
415 }
416 else
417 {
418 LoadAndPrintString(IDS_USAGE_UNLOAD);
419 wprintf(L"fltmc.exe unload [name]\n\n");
420 }
421 }
422 else if (!_wcsicmp(argv[1], L"volumes"))
423 {
424 if (argc == 2)
425 {
426 ListVolumes();
427 }
428 else
429 {
430 LoadAndPrintString(IDS_USAGE_VOLUMES);
431 wprintf(L"fltmc.exe volumes\n\n");
432 }
433 }
434
435 return 0;
436 }
437