Reactos
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
24EXTERN_C int wmain(int argc, WCHAR *argv[]);
25
26void
27LoadAndPrintString(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
40void
41PrintErrorText(_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
56DWORD
57SetDriverLoadPrivilege()
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
92void
93LoadFilter(_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
111void
112UnloadFilter(_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
130void
131PrintFilterInfo(_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
205void
206PrintVolumeInfo(_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
264void
265ListFilters()
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
334void
335ListVolumes()
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
378int 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}