summaryrefslogtreecommitdiff
path: root/media.c
diff options
context:
space:
mode:
authortumagonx2017-08-08 10:54:53 +0700
committertumagonx2017-08-08 10:54:53 +0700
commit2acec63b2ed75bf4b71ad257db573c4b8f9639e7 (patch)
treea8bea139ddd26116d44ea182b0b8436f2162e6e3 /media.c
initial commit
Diffstat (limited to 'media.c')
-rw-r--r--media.c444
1 files changed, 444 insertions, 0 deletions
diff --git a/media.c b/media.c
new file mode 100644
index 0000000..813bf71
--- /dev/null
+++ b/media.c
@@ -0,0 +1,444 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * media.c
7 *
8 * Abstract:
9 *
10 * This module deals with removable media drives. Removable media drives can be made read-only
11 * or disabled altogether.
12 *
13 * Addition of removable drives is detected by monitoring the creation new drive symbolic links.
14 * Drive removal is detected by receiving Plug-and-Play notification.
15 *
16 * Note: Plug-and-Play notifications are not used to detect addition of removable drives since
17 * drive letters are not yet assigned when notifications arrive.
18 *
19 * Author:
20 *
21 * Eugene Tsyrklevich 02-Jun-2004
22 */
23
24
25#include <NTDDK.h>
26
27#undef DEFINE_GUID
28#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) const GUID name \
29 = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
30
31#include <ntddstor.h>
32#include <wdmguid.h>
33#include "media.h"
34#include "pathproc.h"
35#include "policy.h"
36
37
38#ifdef ALLOC_PRAGMA
39#pragma alloc_text (INIT, InitRemovableMediaHooks)
40#pragma alloc_text (PAGE, RemoveRemovableMediaHooks)
41#endif
42
43
44//XXX investigate IoRegisterFsRegistrationChange
45//reference: www.pulsetrainsw.com/articlesitem.asp?id=3
46
47PVOID DiskNotificationEntry = NULL, CdromNotificationEntry = NULL;
48
49/* removable media flags defined in drive.h (READONLY, etc) */
50UCHAR MediaRemovableFlags = 0;
51
52
53typedef struct _WORK_CONTEXT
54{
55 PIO_WORKITEM Item;
56 UNICODE_STRING SymbolicLinkName;
57
58} WORK_CONTEXT, *PWORK_CONTEXT;
59
60
61
62/*
63 * AddDrive()
64 *
65 * Description:
66 * Create policy access rules for removable drives as they are added at runtime.
67 *
68 * Parameters:
69 * pusDriveName - .
70 * DriveLetter - Letter of the drive being added.
71 *
72 * Returns:
73 * Nothing.
74 */
75
76VOID
77AddDrive(PUNICODE_STRING pusDriveName, CHAR DriveLetter)
78{
79 PDEVICE_OBJECT pDeviceObject;
80 PFILE_OBJECT fo;
81 NTSTATUS rc;
82
83
84 rc = IoGetDeviceObjectPointer(pusDriveName, FILE_READ_ATTRIBUTES, &fo, &pDeviceObject);
85 if (! NT_SUCCESS(rc))
86 {
87 LOG(LOG_SS_DRIVE, LOG_PRIORITY_VERBOSE, ("AddDrive: IoGetDeviceObjectPointer failed with status %x\n", rc));
88 return;
89 }
90
91
92 LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("AddDrive(%S): %d\n", pusDriveName->Buffer, pDeviceObject->Characteristics));
93
94
95 if (pDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
96 {
97 CHAR rule[MAX_PATH];
98
99
100 LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("AddDrive: removable drive! %c: %S\n", DriveLetter, pusDriveName->Buffer));
101
102
103 /* Create a new global policy rule */
104
105 if (IS_REMOVABLE_MEDIA_DISABLED())
106 {
107 sprintf(rule, "name match \"%c:\\*\" then %s", DriveLetter, "deny");
108
109 PolicyParseObjectRule(&gSecPolicy, RULE_FILE, "all", rule);
110
111 /* no need to process other rules, this one denies everything already */
112 return;
113 }
114
115 if (IS_REMOVABLE_MEDIA_READONLY() /*&& !(pDeviceObject->Characteristics & FILE_READ_ONLY_DEVICE)*/)
116 {
117 sprintf(rule, "name match \"%c:\\*\" then %s", DriveLetter, "deny");
118
119 PolicyParseObjectRule(&gSecPolicy, RULE_FILE, "write", rule);
120 }
121
122 if (IS_REMOVABLE_MEDIA_NOEXECUTE())
123 {
124 sprintf(rule, "name match \"%c:\\*\" then %s", DriveLetter, "deny");
125
126 PolicyParseObjectRule(&gSecPolicy, RULE_FILE, "execute", rule);
127 }
128 }
129
130
131 return;
132}
133
134
135
136/*
137 * RemoveDrive()
138 *
139 * Description:
140 * .
141 *
142 * Parameters:
143 * pusDriveName - .
144 *
145 * Returns:
146 * Nothing.
147 */
148
149VOID
150RemoveDrive(PUNICODE_STRING pusDriveName)
151{
152 PDEVICE_OBJECT pDeviceObject;
153 PFILE_OBJECT fo;
154 NTSTATUS rc;
155
156
157 rc = IoGetDeviceObjectPointer(pusDriveName, FILE_READ_ATTRIBUTES, &fo, &pDeviceObject);
158 if (! NT_SUCCESS(rc))
159 {
160 LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("RemoveDrive: IoGetDeviceObjectPointer failed with status %x\n", rc));
161 return;
162 }
163
164
165 if (pDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
166 LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("RemoveDrive: removable drive! %S\n", pusDriveName->Buffer));
167
168
169// rc = RtlVolumeDeviceToDosName(pDeviceObject, pusDriveName);
170// if (NT_SUCCESS(rc))
171// LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("RemoveDrive: IoVolumeDeviceToDosName returned %S\n", pusDriveName->Buffer));
172}
173
174
175
176/*
177 * MonitorDriveLinks()
178 *
179 * Description:
180 * This routine is called from HookedNtCreateSymbolicLinkObject whenever a new symbolic link is created.
181 * ProcessDriveLink is responsible for monitoring the creation of any new media drives. When a new removable
182 * media drive is added to a system, a new symbolic link "\GLOBAL??\X:" is created (where X is the
183 * assigned drive letter).
184 *
185 * Note: We are not interested in creation of "fake" drives (i.e. subst c: z:\) since those will be
186 * correctly resolved by symbolic link name resolution code (policy enforcement). "Fake" drives
187 * are added in userland and come up as "\??\X:".
188 *
189 * Parameters:
190 * Link - created symbolic link name.
191 *
192 * Returns:
193 * Nothing.
194 */
195
196VOID
197MonitorDriveLinks(const PCHAR Link)
198{
199 CHAR DriveLetter;
200 ANSI_STRING AnsiString;
201 UNICODE_STRING UnicodeString;
202 int len = strlen(Link);
203
204
205 /* match \GLOBAL??\Z: && \??\Z: drive references */
206 if (len == 12 && (strncmp(Link, "\\GLOBAL??\\", 10) == 0) && isalpha(Link[10]) && Link[11] == ':')
207 {
208 LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("MonitorDriveLinks: matched \\global??\\. letter %c\n", Link[10]));
209
210 DriveLetter = Link[10];
211 }
212 else if (len == 6 && (strncmp(Link, "\\??\\", 4) == 0) && isalpha(Link[4]) && Link[5] == ':')
213 {
214 LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("MonitorDriveLinks: matched \\??\\. letter %c\n", Link[4]));
215
216 DriveLetter = Link[4];
217 }
218 else
219 {
220 return;
221 }
222
223
224 RtlInitAnsiString(&AnsiString, Link);
225
226 if (NT_SUCCESS(RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, TRUE)))
227 {
228 AddDrive(&UnicodeString, DriveLetter);
229
230 RtlFreeUnicodeString(&UnicodeString);
231 }
232 else
233 {
234 LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("MonitorDriveLinks: failed to convert %s\n", Link));
235 }
236}
237
238
239
240/*
241 * PnpWorker()
242 *
243 * Description:
244 * A work item routine that runs at PASSIVE_LEVEL irql. The routine is scheduled by PnpCallback
245 * which is not allowed to block.
246 *
247 * PnpWorker calls RemoveDrive() with a drive name setup by PnpCallback.
248 *
249 * Parameters:
250 * pDeviceObject - .
251 * Context - .
252 *
253 * Returns:
254 * Nothing.
255 */
256
257VOID
258PnpWorker(IN PDEVICE_OBJECT pDeviceObject, IN PVOID Context)
259{
260 PWORK_CONTEXT WorkContext = (PWORK_CONTEXT) Context;
261
262
263 if (WorkContext == NULL)
264 {
265 LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("PnpWorker: WorkContext = NULL\n"));
266 return;
267 }
268
269 LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("PnpWorker: %S\n", WorkContext->SymbolicLinkName.Buffer));
270
271
272 RemoveDrive(&WorkContext->SymbolicLinkName);
273
274
275 IoFreeWorkItem(WorkContext->Item);
276
277 ExFreePoolWithTag(WorkContext, _POOL_TAG);
278}
279
280
281
282/*
283 * PnpCallback()
284 *
285 * Description:
286 * Plug-and-Play callback. Gets called when a p-n-p drive/cdrom interface is modified
287 * (i.e. when a removable drive is added or removed from the system).
288 *
289 * Parameters:
290 * NotificationStructure - DEVICE_INTERFACE_CHANGE_NOTIFICATION indicating which interface changed.
291 * Context - the driver's device context.
292 *
293 * Returns:
294 * STATUS_SUCCESS.
295 */
296
297NTSTATUS
298PnpCallback(IN PVOID NotificationStructure, IN PVOID Context)
299{
300 PDEVICE_INTERFACE_CHANGE_NOTIFICATION Notify = (PDEVICE_INTERFACE_CHANGE_NOTIFICATION) NotificationStructure;
301 PDEVICE_OBJECT pDeviceObject = (PDEVICE_OBJECT) Context;
302 PIO_WORKITEM WorkItem;
303 PWORK_CONTEXT WorkContext;
304
305
306 if (IsEqualGUID((LPGUID) &Notify->Event, (LPGUID) &GUID_DEVICE_INTERFACE_REMOVAL))
307 {
308 LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("GUID_DEVICE_INTERFACE_REMOVAL %S\n", Notify->SymbolicLinkName->Buffer));
309/*
310 }
311
312
313 if (IsEqualGUID((LPGUID) &Notify->Event, (LPGUID) &GUID_DEVICE_INTERFACE_ARRIVAL) ||
314 IsEqualGUID((LPGUID) &Notify->Event, (LPGUID) &GUID_DEVICE_INTERFACE_REMOVAL))
315 {
316 LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("GUID_DEVICE_INTERFACE_ARRIVAL %x %S\n", Notify->SymbolicLinkName, Notify->SymbolicLinkName->Buffer));
317*/
318
319 /*
320 * Schedule a work item to process this request. Cannot block in this callback function.
321 */
322
323 WorkItem = IoAllocateWorkItem(pDeviceObject);
324
325 WorkContext = (PWORK_CONTEXT) ExAllocatePoolWithTag(PagedPool,
326 sizeof(WORK_CONTEXT) + Notify->SymbolicLinkName->Length,
327 _POOL_TAG);
328 if (!WorkContext)
329 {
330 IoFreeWorkItem(WorkItem);
331 return(STATUS_SUCCESS);
332 }
333
334 WorkContext->SymbolicLinkName.Buffer = (PWSTR) ((PCHAR) &WorkContext->SymbolicLinkName + sizeof(UNICODE_STRING));
335 WorkContext->SymbolicLinkName.MaximumLength = Notify->SymbolicLinkName->Length;
336 WorkContext->SymbolicLinkName.Length = 0;
337
338 WorkContext->Item = WorkItem;
339 RtlCopyUnicodeString(&WorkContext->SymbolicLinkName, Notify->SymbolicLinkName);
340
341 IoQueueWorkItem(WorkItem, PnpWorker, DelayedWorkQueue, WorkContext);
342 }
343
344
345 return STATUS_SUCCESS;
346}
347
348
349
350/*
351 * InitRemovableMediaHooks()
352 *
353 * Description:
354 * Process any existing drives and register Plug-and-Play notifications for future drive additions/removals.
355 *
356 * NOTE: Called once during driver initialization (DriverEntry()).
357 *
358 * Parameters:
359 * None.
360 *
361 * Returns:
362 * TRUE to indicate success, FALSE if failed.
363 */
364
365BOOLEAN
366InitRemovableMediaHooks(IN PDRIVER_OBJECT pDriverObject, IN PDEVICE_OBJECT pDeviceObject)
367{
368 UNICODE_STRING Name;
369 WCHAR Buffer[MAX_PATH] = L"\\??\\A:";
370 NTSTATUS rc;
371 HANDLE hLink;
372 OBJECT_ATTRIBUTES oa;
373 char DriveLetter;
374
375
376 for (DriveLetter = 'A'; DriveLetter <= 'Z'; DriveLetter++)
377 {
378 Buffer[4] = DriveLetter;
379
380 RtlInitUnicodeString(&Name, Buffer);
381
382 AddDrive(&Name, DriveLetter);
383 }
384
385
386 rc = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange,
387 0,//PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
388 (LPGUID) &GUID_DEVINTERFACE_DISK,
389 pDriverObject,
390 PnpCallback,
391 pDeviceObject,
392 &DiskNotificationEntry);
393
394 if (! NT_SUCCESS(rc))
395 {
396 LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("InitRemovableMediaHooks: IoRegisterPlugPlayNotification failed with status %x\n", rc));
397 return FALSE;
398 }
399
400
401 rc = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange,
402 0,//PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
403 (LPGUID) &GUID_DEVINTERFACE_CDROM,
404 pDriverObject,
405 PnpCallback,
406 pDeviceObject,
407 &CdromNotificationEntry);
408
409 if (! NT_SUCCESS(rc))
410 {
411 LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("InitRemovableMediaHooks: IoRegisterPlugPlayNotification2 failed with status %x\n", rc));
412 return FALSE;
413 }
414
415
416 return TRUE;
417}
418
419
420
421/*
422 * RemoveRemovableMediaHooks()
423 *
424 * Description:
425 * Unregister Plug-and-Play notifications.
426 *
427 * Parameters:
428 * None.
429 *
430 * Returns:
431 * Nothing.
432 */
433
434VOID
435RemoveRemovableMediaHooks()
436{
437 if (DiskNotificationEntry)
438 if (! NT_SUCCESS(IoUnregisterPlugPlayNotification(DiskNotificationEntry)))
439 LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("RemoveRemovableMediaHooks: IoUnregisterPlugPlayNotification failed\n"));
440
441 if (CdromNotificationEntry)
442 if (! NT_SUCCESS(IoUnregisterPlugPlayNotification(CdromNotificationEntry)))
443 LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("RemoveRemovableMediaHooks: IoUnregisterPlugPlayNotification2 failed\n"));
444}