summaryrefslogtreecommitdiff
path: root/pathproc.c
diff options
context:
space:
mode:
authortumagonx2017-08-08 10:54:53 +0700
committertumagonx2017-08-08 10:54:53 +0700
commit2acec63b2ed75bf4b71ad257db573c4b8f9639e7 (patch)
treea8bea139ddd26116d44ea182b0b8436f2162e6e3 /pathproc.c
initial commit
Diffstat (limited to 'pathproc.c')
-rw-r--r--pathproc.c1093
1 files changed, 1093 insertions, 0 deletions
diff --git a/pathproc.c b/pathproc.c
new file mode 100644
index 0000000..8778868
--- /dev/null
+++ b/pathproc.c
@@ -0,0 +1,1093 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * pathproc.c
7 *
8 * Abstract:
9 *
10 * This module implements various pathname handling routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 19-Feb-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#include "pathproc.h"
23#include "procname.h"
24#include "policy.h"
25#include "learn.h"
26#include "log.h"
27
28
29/*
30 * ResolveFilename() XXX rewrite
31 *
32 * Description:
33 * Get canonical name for a file by resolving symbolic links.
34 *
35 * Parameters:
36 * szFileName - filename to resolve.
37 * szResult - output buffer.
38 * szResultSize - size of an output buffer.
39 *
40 * Returns:
41 * TRUE to indicate success, FALSE if failed.
42 */
43
44BOOLEAN
45ResolveFilename(IN PCHAR szFileName, OUT PCHAR szResult, IN USHORT szResultSize)
46{
47 CHAR *p, c;
48 OBJECT_ATTRIBUTES oa;
49 ANSI_STRING FileNameAnsi;
50 UNICODE_STRING FileNameUnicode;
51 HANDLE hLink;
52 NTSTATUS rc;
53 int NumberOfLinks = 0;
54 WCHAR buffer[chMAX_PATH];
55 CHAR buffer2[chMAX_PATH];
56
57
58restart:
59
60 *szResult = '\0';
61
62 if (szFileName[0] == '\\' && szFileName[1] == '\\')
63 szFileName++;
64
65 /* move to the end of the object name */
66 for (p = szFileName; *p != '\0'; p++)
67 ;
68
69 /* process the object name from end to the beginning */
70 while (p != szFileName)
71 {
72 /* find the last slash */
73 if (*p != '\\' && *p != '\0')
74 {
75 p--;
76 continue;
77 }
78
79 c = *p;
80 *p = '\0';
81
82
83 RtlInitAnsiString(&FileNameAnsi, szFileName);
84 RtlAnsiStringToUnicodeString(&FileNameUnicode, &FileNameAnsi, TRUE);
85
86 InitializeObjectAttributes(&oa, &FileNameUnicode, OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE, NULL, NULL);
87
88 rc = ZwOpenSymbolicLinkObject(&hLink, GENERIC_READ, &oa);
89
90 if (NT_SUCCESS(rc))
91 {
92 UNICODE_STRING target;
93 ANSI_STRING targeta;
94
95
96 target.Buffer = buffer;
97 target.MaximumLength = bMAX_PATH;
98 target.Length = 0;
99
100 rc = ZwQuerySymbolicLinkObject(hLink, &target, NULL);
101
102 ZwClose(hLink);
103
104
105 if (NT_SUCCESS(rc))
106 {
107 targeta.Length = 0;
108 targeta.MaximumLength = szResultSize;
109 targeta.Buffer = szResult;
110
111 RtlUnicodeStringToAnsiString(&targeta, &target, FALSE);
112 targeta.Buffer[targeta.Length] = '\0';
113
114//XXX szResultSize -= targeta.Length;
115
116 RtlFreeUnicodeString(&FileNameUnicode);
117 *p = c;
118
119//XXX can we have circular links?
120 if (NumberOfLinks++ < MAX_NUMBER_OF_LINKS)
121 {
122 strncat(szResult, p, szResultSize);
123
124// if (NumberOfLinks > 1)
125// LOG(LOG_SS_PATHPROC, LOG_PRIORITY_DEBUG, ("ResolveFilename: NumberOfLinks=%d. Resolved %s to %s. Restarting.\n", NumberOfLinks, szFileName, szResult));
126
127 /*
128 * switch szFileName to a different buffer. we cannot reuse szFileName buffer
129 * since the resolved link might end up being longer than the original buffer
130 */
131
132 szFileName = (PCHAR) buffer2;
133 strcpy(szFileName, szResult);
134
135 goto restart;
136 }
137
138 LOG(LOG_SS_PATHPROC, LOG_PRIORITY_DEBUG, ("ResolveFilename: NumberOfLinks=%d. bailing out. %s\n", NumberOfLinks, szResult));
139
140 break;
141 }
142 }
143
144 RtlFreeUnicodeString(&FileNameUnicode);
145
146 *p-- = c;
147 }
148
149 strncat(szResult, p, szResultSize);
150
151
152// LOG(LOG_SS_PATHPROC, LOG_PRIORITY_VERBOSE, ("ResolveFilename: name=%s number of links=%d\n", szResult, NumberOfLinks));
153
154
155 return TRUE;
156}
157
158
159
160BOOLEAN
161ResolveFilenameW(IN PUNICODE_STRING szFileName, OUT PCHAR szResult, IN USHORT szResultSize)
162{
163 WCHAR *p, c;
164 OBJECT_ATTRIBUTES oa;
165 ANSI_STRING FileNameAnsi;
166 UNICODE_STRING FileNameUnicode;
167 HANDLE hLink;
168 NTSTATUS rc;
169 int NumberOfLinks = 0;
170 WCHAR buffer[chMAX_PATH];
171 USHORT OriginalLength;
172 UNICODE_STRING target;
173 ANSI_STRING targeta;
174
175
176
177 ASSERT(szFileName);
178 ASSERT(szResult);
179
180 OriginalLength = szFileName->Length;
181
182
183restart:
184
185 *szResult = '\0';
186
187 /* move to the end of the object name */
188 p = (PWCHAR) ((PCHAR)szFileName->Buffer + szFileName->Length);
189
190 /* process the object name from end to the beginning */
191 while (p != szFileName->Buffer)
192 {
193 /* find the last slash */
194// p = wcsrchr(p, L'\\');
195/*
196 if (p == NULL)
197 {
198 p = szFileName->Buffer;
199 break;
200 }
201*/
202 if (*p != L'\\' && *p != L'\0')
203 {
204 p--;
205 continue;
206 }
207
208
209 c = *p;
210 *p = L'\0';
211// szFileName->Length = OriginalLength - (p - szFileName->Buffer);
212
213
214// RtlInitAnsiString(&FileNameAnsi, szFileName);
215// RtlAnsiStringToUnicodeString(&FileNameUnicode, &FileNameAnsi, TRUE);
216// InitializeObjectAttributes(&oa, &FileNameUnicode, OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE, NULL, NULL);
217
218 InitializeObjectAttributes(&oa, szFileName, OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE, NULL, NULL);
219
220 rc = ZwOpenSymbolicLinkObject(&hLink, GENERIC_READ, &oa);
221
222 if (! NT_SUCCESS(rc))
223 {
224 *p-- = c;
225 continue;
226 }
227
228 target.Buffer = buffer;
229 target.MaximumLength = bMAX_PATH;
230 target.Length = 0;
231
232 rc = ZwQuerySymbolicLinkObject(hLink, &target, NULL);
233
234 ZwClose(hLink);
235
236
237 if (! NT_SUCCESS(rc))
238 {
239 *p-- = c;
240 continue;
241 }
242
243
244 *p = c;
245
246
247//XXX can we have circular links?
248 if (NumberOfLinks++ < MAX_NUMBER_OF_LINKS)
249 {
250 wcscat(buffer, p);
251 RtlInitUnicodeString(szFileName, buffer);
252
253 goto restart;
254 }
255
256 LOG(LOG_SS_PATHPROC, LOG_PRIORITY_DEBUG, ("ResolveFilename: NumberOfLinks=%d. bailing out. %s\n", NumberOfLinks, szResult));
257
258 break;
259 }
260
261
262// wcscat(szResult, p);
263
264
265// LOG(LOG_SS_PATHPROC, LOG_PRIORITY_VERBOSE, ("ResolveFilename: name=%s number of links=%d\n", szResult, NumberOfLinks));
266
267
268 return TRUE;
269}
270
271
272
273/*
274 * GetPathFromOA()
275 *
276 * Description:
277 * Resolve an object handle to an object name.
278 *
279 * Parameters:
280 * ObjectAttributes - opaque structure describing an object handle.
281 * OutBuffer - output buffer where an object name will be saved to.
282 * OutBufferSize - size of an output buffer.
283 * ResolveLinks - do symbolic links need to be resolved?
284 *
285 * Returns:
286 * TRUE to indicate success, FALSE if failed.
287 */
288
289#define FINISH_GetPathFromOA(msg) \
290 do { \
291 LOG(LOG_SS_PATHPROC, LOG_PRIORITY_DEBUG, msg); \
292 return FALSE; \
293 } while(0)
294
295BOOLEAN
296GetPathFromOA(IN POBJECT_ATTRIBUTES ObjectAttributes, OUT PCHAR OutBuffer, IN USHORT OutBufferSize, IN BOOLEAN ResolveLinks)
297{
298 NTSTATUS rc;
299 PVOID Object = NULL;
300 ULONG len;
301 CHAR Buffer[sizeof(OBJECT_NAME_INFORMATION) + bMAX_PATH];
302 POBJECT_NAME_INFORMATION pONI = (POBJECT_NAME_INFORMATION) Buffer;
303 BOOLEAN ret = FALSE;
304 UNICODE_STRING ObjectName;
305
306 PUNICODE_STRING pusFilename = NULL;
307 ANSI_STRING name;
308
309
310 if (! ARGUMENT_PRESENT(ObjectAttributes) || OutBuffer == NULL)
311
312 return(FALSE);
313
314
315 try
316 {
317 if (KeGetPreviousMode() != KernelMode)
318
319 ProbeForRead(ObjectAttributes, sizeof(OBJECT_ATTRIBUTES), sizeof(ULONG));
320
321
322 if (ObjectAttributes->Length != sizeof(OBJECT_ATTRIBUTES))
323
324 FINISH_GetPathFromOA(("GetPathFromOA: Invalid ObjectAttributes length %d\n", ObjectAttributes->Length));
325
326
327 if (! ARGUMENT_PRESENT(ObjectAttributes->ObjectName) )
328
329 return FALSE;
330
331
332 if (KeGetPreviousMode() != KernelMode)
333 {
334 ProbeForRead(ObjectAttributes->ObjectName, sizeof(UNICODE_STRING), sizeof(ULONG));
335
336 ObjectName = ProbeAndReadUnicodeString(ObjectAttributes->ObjectName);
337 }
338 else
339 {
340 ObjectName = *ObjectAttributes->ObjectName;
341 }
342
343
344 if (ObjectName.Length == 0)
345
346 return FALSE;
347
348
349 if (((ObjectName.Length & (sizeof(WCHAR) - 1)) != 0) ||
350 (ObjectName.Length > bMAX_PATH - sizeof(WCHAR)) )
351
352 FINISH_GetPathFromOA(("GetPathFromOA: invalid wchar string length = %d\n", ObjectName.Length));
353
354
355 if (KeGetPreviousMode() != KernelMode)
356
357 ProbeForRead(ObjectName.Buffer, ObjectName.Length, sizeof(WCHAR));
358 }
359
360 except(EXCEPTION_EXECUTE_HANDLER)
361 {
362 NTSTATUS status = GetExceptionCode();
363
364 LOG(LOG_SS_PATHPROC, LOG_PRIORITY_DEBUG, ("GetPathFromOA(): caught an exception. status = 0x%x\n", status));
365
366 return FALSE;
367 }
368
369
370 pusFilename = &ObjectName;
371
372
373 /*
374 * is the filename referenced in relation to some directory?
375 * if so, append the filename to a specified directory name
376 */
377
378 if (ARGUMENT_PRESENT(ObjectAttributes->RootDirectory))
379 {
380 if (! NT_SUCCESS( ObReferenceObjectByHandle(ObjectAttributes->RootDirectory, 0, 0,
381 KernelMode, &Object, NULL) ))
382 {
383 FINISH_GetPathFromOA(("GetPathFromOA(): ObReferenceObjectByHandle() failed. Object = %x\n", Object));
384 }
385
386 if (Object == NULL)
387 {
388 FINISH_GetPathFromOA(("GetPathFromOA(): Object = NULL\n"));
389 }
390
391
392 if (! NT_SUCCESS( ObQueryNameString(Object, pONI, bMAX_PATH, &len) ))
393 {
394 ObDereferenceObject(Object);
395 FINISH_GetPathFromOA(("GetPathFromOA(): ObQueryNameString() failed\n"));
396 }
397
398
399 ObDereferenceObject(Object);
400 Object = NULL;
401
402
403 /* extracted directory name */
404 pusFilename = &pONI->Name;
405
406
407 /* is the directory name too long? */
408
409 if (pusFilename->Length >= bMAX_PATH - sizeof(WCHAR))
410 FINISH_GetPathFromOA(("GetPathFromOA(): directory name is too long\n"));
411
412
413 /*
414 * pusFilename points to a buffer of MAX_PATH size, ObQueryNameString() sets MaximumLength to the length
415 * of the directory name, we need to reset this back to MAX_PATH to be able to append a filename
416 * (reusing the same buffer)
417 */
418 pusFilename->MaximumLength = bMAX_PATH;
419
420
421 if (pusFilename->Buffer[ (pusFilename->Length / sizeof(WCHAR)) - 1 ] != L'\\')
422 {
423 pusFilename->Buffer[ pusFilename->Length / sizeof(WCHAR) ] = L'\\';
424 pusFilename->Length += sizeof(WCHAR);
425 }
426
427 if (RtlAppendUnicodeStringToString(pusFilename, ObjectAttributes->ObjectName) == STATUS_BUFFER_TOO_SMALL)
428 {
429 LOG(LOG_SS_PATHPROC, LOG_PRIORITY_VERBOSE, ("GetPathFromOA: 1 %S\n", pusFilename->Buffer));
430 LOG(LOG_SS_PATHPROC, LOG_PRIORITY_VERBOSE, ("GetPathFromOA: 2 %S\n", ObjectAttributes->ObjectName->Buffer));
431 FINISH_GetPathFromOA(("GetPathFromOA(): RtlAppendUnicodeStringToString() = STATUS_BUFFER_TOO_SMALL\n"));
432 }
433 }
434
435
436 if (NT_SUCCESS(RtlUnicodeStringToAnsiString(&name, pusFilename, TRUE)))
437 {
438 if (ResolveLinks == TRUE)
439 {
440 ret = ResolveFilename(name.Buffer, OutBuffer, OutBufferSize);
441 }
442 else
443 {
444 if (name.Length >= OutBufferSize - 1)
445 {
446 LOG(LOG_SS_PATHPROC, LOG_PRIORITY_DEBUG, ("GetPathFromOA: Pathname too long %d\n", name.Length));
447
448 OutBuffer[0] = 0;
449
450 ret = FALSE;
451 }
452 else
453 {
454 strcpy(OutBuffer, name.Buffer);
455
456 ret = TRUE;
457 }
458 }
459
460 RtlFreeAnsiString(&name);
461 }
462
463
464// LOG(LOG_SS_PATHPROC, LOG_PRIORITY_VERBOSE, ("%d GetPathFromOA: %s (%S)\n", (ULONG) PsGetCurrentProcessId(), OutBuffer, pusFilename->Buffer));
465
466
467 return ret;
468}
469
470
471
472
473BOOLEAN
474GetPathFromOAW(IN POBJECT_ATTRIBUTES ObjectAttributes, OUT PCHAR OutBuffer, IN USHORT OutBufferSize, IN BOOLEAN ResolveLinks)
475{
476 NTSTATUS rc;
477 PVOID Object = NULL;
478 ULONG len;
479 CHAR Buffer[sizeof(OBJECT_NAME_INFORMATION) + bMAX_PATH];
480 POBJECT_NAME_INFORMATION pONI = (POBJECT_NAME_INFORMATION) Buffer;
481 BOOLEAN ret = FALSE;
482 UNICODE_STRING ObjectName;
483
484 PUNICODE_STRING pusFilename = NULL;
485 ANSI_STRING name;
486
487
488 if (! ARGUMENT_PRESENT(ObjectAttributes) || OutBuffer == NULL)
489
490 return(FALSE);
491
492
493 try
494 {
495 if (KeGetPreviousMode() != KernelMode)
496
497 ProbeForRead(ObjectAttributes, sizeof(OBJECT_ATTRIBUTES), sizeof(ULONG));
498
499
500 if (ObjectAttributes->Length != sizeof(OBJECT_ATTRIBUTES))
501
502 FINISH_GetPathFromOA(("GetPathFromOA: Invalid ObjectAttributes length %d\n", ObjectAttributes->Length));
503
504
505 if (! ARGUMENT_PRESENT(ObjectAttributes->ObjectName) )
506
507 return FALSE;
508
509
510 if (KeGetPreviousMode() != KernelMode)
511 {
512 ProbeForRead(ObjectAttributes->ObjectName, sizeof(UNICODE_STRING), sizeof(ULONG));
513
514 ObjectName = ProbeAndReadUnicodeString(ObjectAttributes->ObjectName);
515 }
516 else
517 {
518 ObjectName = *ObjectAttributes->ObjectName;
519 }
520
521
522 if (ObjectName.Length == 0)
523
524 return FALSE;
525
526
527 if (((ObjectName.Length & (sizeof(WCHAR) - 1)) != 0) ||
528 (ObjectName.Length > bMAX_PATH - sizeof(WCHAR)) )
529
530 FINISH_GetPathFromOA(("GetPathFromOA: invalid wchar string length = %d\n", ObjectName.Length));
531
532
533 if (KeGetPreviousMode() != KernelMode)
534
535 ProbeForRead(ObjectName.Buffer, ObjectName.Length, sizeof(WCHAR));
536 }
537
538 except(EXCEPTION_EXECUTE_HANDLER)
539 {
540 NTSTATUS status = GetExceptionCode();
541
542 LOG(LOG_SS_PATHPROC, LOG_PRIORITY_DEBUG, ("GetPathFromOA(): caught an exception. status = 0x%x\n", status));
543
544 return FALSE;
545 }
546
547
548 pusFilename = &ObjectName;
549
550
551 /*
552 * is the filename referenced in relation to some directory?
553 * if so, append the filename to a specified directory name
554 */
555
556 if (ARGUMENT_PRESENT(ObjectAttributes->RootDirectory))
557 {
558 if (! NT_SUCCESS( ObReferenceObjectByHandle(ObjectAttributes->RootDirectory, 0, 0,
559 KernelMode, &Object, NULL) ))
560 {
561 ObDereferenceObject(Object);
562 FINISH_GetPathFromOA(("GetPathFromOA(): ObReferenceObjectByHandle() failed\n"));
563 }
564
565
566 if (Object == NULL)
567 {
568 ObDereferenceObject(Object);
569 FINISH_GetPathFromOA(("GetPathFromOA(): Object = NULL\n"));
570 }
571
572
573 if (! NT_SUCCESS( ObQueryNameString(Object, pONI, bMAX_PATH, &len) ))
574 {
575 ObDereferenceObject(Object);
576 FINISH_GetPathFromOA(("GetPathFromOA(): ObQueryNameString() failed\n"));
577 }
578
579
580 ObDereferenceObject(Object);
581 Object = NULL;
582
583
584 /* extracted directory name */
585 pusFilename = &pONI->Name;
586
587
588 /* is the directory name too long? */
589
590 if (pusFilename->Length >= bMAX_PATH - sizeof(WCHAR))
591 FINISH_GetPathFromOA(("GetPathFromOA(): directory name is too long\n"));
592
593
594 /*
595 * pusFilename points to a buffer of MAX_PATH size, ObQueryNameString() sets MaximumLength to the length
596 * of the directory name, we need to reset this back to MAX_PATH to be able to append a filename
597 * (reusing the same buffer)
598 */
599 pusFilename->MaximumLength = bMAX_PATH;
600
601
602 pusFilename->Buffer[ pusFilename->Length / sizeof(WCHAR) ] = L'\\';
603 pusFilename->Length += sizeof(WCHAR);
604
605
606 if (RtlAppendUnicodeStringToString(pusFilename, ObjectAttributes->ObjectName) == STATUS_BUFFER_TOO_SMALL)
607 {
608 LOG(LOG_SS_PATHPROC, LOG_PRIORITY_VERBOSE, ("GetPathFromOA: 1 %S\n", pusFilename->Buffer));
609 LOG(LOG_SS_PATHPROC, LOG_PRIORITY_VERBOSE, ("GetPathFromOA: 2 %S\n", ObjectAttributes->ObjectName->Buffer));
610 FINISH_GetPathFromOA(("GetPathFromOA(): RtlAppendUnicodeStringToString() = STATUS_BUFFER_TOO_SMALL\n"));
611 }
612 }
613
614
615 if (ResolveLinks == TRUE)
616 {
617 ret = ResolveFilenameW(pusFilename, OutBuffer, OutBufferSize);
618 }
619
620//XXX
621 if (NT_SUCCESS(RtlUnicodeStringToAnsiString(&name, pusFilename, TRUE)))
622 {
623 if (ResolveLinks == TRUE)
624 {
625 ret = ResolveFilename(name.Buffer, OutBuffer, OutBufferSize);
626 }
627 else
628 {
629 if (name.Length >= OutBufferSize - 1)
630 {
631 LOG(LOG_SS_PATHPROC, LOG_PRIORITY_DEBUG, ("GetPathFromOA: Pathname too long %d\n", name.Length));
632
633 OutBuffer[0] = 0;
634
635 ret = FALSE;
636 }
637 else
638 {
639 strcpy(OutBuffer, name.Buffer);
640
641 ret = TRUE;
642 }
643 }
644
645 RtlFreeAnsiString(&name);
646 }
647
648
649// LOG(LOG_SS_PATHPROC, LOG_PRIORITY_VERBOSE, ("%d GetPathFromOA: %s (%S)\n", (ULONG) PsGetCurrentProcessId(), OutBuffer, pusFilename->Buffer));
650
651
652 return ret;
653}
654
655
656/*
657 * ConvertLongFileNameToShort()
658 *
659 * Description:
660 * Converts long windows filenames to their DOS short equivalent filenames
661 * (i.e. c:\program files to c:\progra~1).
662 *
663 * Parameters:
664 * LongFileName - long filename buffer.
665 * ShortFileName - output buffer where a short filename is written to.
666 * ShortFileNameSize - size of an output buffer (in bytes).
667 *
668 * Returns:
669 * TRUE to indicate success, FALSE if failed.
670 */
671
672#if 0
673
674BOOLEAN
675ConvertLongFileNameToShort(IN PCHAR LongFileName, OUT PCHAR ShortFileName, IN USHORT ShortFileNameSize)
676{
677 int LongFileNameIndex = 0, ShortFileNameIndex = 0, CurrentFileNameLength, TotalLength, ExtensionLength, NumberOfSpaces;
678 BOOLEAN ProcessingExtension = FALSE;
679 CHAR ch, Extension[3];
680
681
682 if (LongFileName == NULL)
683 return FALSE;
684
685 TotalLength = strlen(LongFileName);
686
687
688 /* if the filename does not start with X:\ then assume \device\blah\ format and skip over the first 2 slashes */
689 if (LongFileName[0] == '\\')
690 {
691 int Slashes = 0;
692
693 do
694 {
695 if ( (ch = ShortFileName[ShortFileNameIndex++] = LongFileName[LongFileNameIndex++]) == '\0') return TRUE;
696 if (ch == '\\') ++Slashes;
697 } while (Slashes != 3);
698 }
699
700 for (NumberOfSpaces = ExtensionLength = CurrentFileNameLength = 0; ; LongFileNameIndex++)
701 {
702 /* if we finished traversing the entire directory path or reached a '\' then process the filename (append the extension if necessary) */
703 if (LongFileNameIndex == TotalLength || LongFileName[LongFileNameIndex] == '\\')
704 {
705 /*
706 * if the filename is longer than 8 chars or extension is longer than 3 chars then we need
707 * to create a 6 char filename followed by a '~1' and the first 3 chars of the last extension
708 */
709
710 if (CurrentFileNameLength > 8 || ExtensionLength > 3 || NumberOfSpaces > 0)
711 {
712 CurrentFileNameLength -= NumberOfSpaces;
713
714 if (CurrentFileNameLength > 7)
715 {
716 ShortFileName[ShortFileNameIndex - 2] = '~';
717 ShortFileName[ShortFileNameIndex - 1] = '1';
718 }
719 else if (CurrentFileNameLength == 7)
720 {
721 ShortFileName[ShortFileNameIndex - 1] = '~';
722 ShortFileName[ShortFileNameIndex++] = '1';
723 }
724 else
725 {
726 ShortFileName[ShortFileNameIndex++] = '~';
727 ShortFileName[ShortFileNameIndex++] = '1';
728 }
729 }
730
731 if (ExtensionLength > 0)
732 {
733 ShortFileName[ShortFileNameIndex++] = '.';
734 ShortFileName[ShortFileNameIndex++] = Extension[0];
735
736 if (ExtensionLength > 1)
737 {
738 ShortFileName[ShortFileNameIndex++] = Extension[1];
739
740 if (ExtensionLength > 2)
741 ShortFileName[ShortFileNameIndex++] = Extension[2];
742 }
743
744 ExtensionLength = 0;
745 ProcessingExtension = FALSE;
746 }
747
748 /* if we are done traversing the entire path than we can bail */
749 if (LongFileNameIndex == TotalLength)
750 break;
751
752 ShortFileName[ShortFileNameIndex++] = '\\';
753 NumberOfSpaces = CurrentFileNameLength = 0;
754
755 continue;
756 }
757
758 if (LongFileName[LongFileNameIndex] == '.')
759 {
760 ProcessingExtension = TRUE;
761 ExtensionLength = 0;
762 continue;
763 }
764
765 if (ProcessingExtension == TRUE)
766 {
767 if (ExtensionLength++ < 3)
768 Extension[ExtensionLength - 1] = LongFileName[LongFileNameIndex];
769
770 continue;
771 }
772
773 if (((CurrentFileNameLength++) - NumberOfSpaces) < 8)
774 {
775 if (LongFileName[LongFileNameIndex] != ' ')
776 ShortFileName[ShortFileNameIndex++] = LongFileName[LongFileNameIndex];
777 else
778 ++NumberOfSpaces;
779 }
780 }
781
782
783 ShortFileName[ShortFileNameIndex++] = 0;
784
785
786 return TRUE;
787}
788
789#endif
790
791
792
793/*
794 * GetNameFromHandle()
795 *
796 * Description:
797 * Resolve an object handle to an object name.
798 *
799 * Parameters:
800 * ObjectHandle - handle of an object whose name we are trying to obtain.
801 * OutBuffer - output buffer where an object name will be saved to.
802 * OutBufferSize - size of an output buffer (in bytes).
803 *
804 * Returns:
805 * TRUE to indicate success, FALSE if failed.
806 */
807
808PWSTR
809GetNameFromHandle(IN HANDLE ObjectHandle, OUT PWSTR OutBuffer, IN USHORT OutBufferSize)
810{
811 PVOID Object = NULL;
812 NTSTATUS rc;
813 POBJECT_NAME_INFORMATION pONI = (POBJECT_NAME_INFORMATION) OutBuffer;
814 ULONG len;
815
816
817 rc = ObReferenceObjectByHandle(ObjectHandle, GENERIC_READ, NULL, KernelMode, &Object, NULL);
818 if (! NT_SUCCESS(rc))
819 {
820 LOG(LOG_SS_PATHPROC, LOG_PRIORITY_DEBUG, ("%d GetNameFromHandle: ObReferenceObjectByHandle failed\n", (ULONG) PsGetCurrentProcessId()));
821 return NULL;
822 }
823
824
825 rc = ObQueryNameString(Object, pONI, OutBufferSize - sizeof(OBJECT_NAME_INFORMATION)*sizeof(WCHAR), &len);
826 if (! NT_SUCCESS(rc))
827 {
828 LOG(LOG_SS_PATHPROC, LOG_PRIORITY_VERBOSE, ("%d GetNameFromHandle: ObQueryNameString failed\n", (ULONG) PsGetCurrentProcessId()));
829 return NULL;
830 }
831
832
833// _snprintf(OutBuffer, OutBufferSize, "%S", pONI->Name.Buffer);
834// OutBuffer[OutBufferSize - 1] = 0;
835
836// LOG(LOG_SS_PATHPROC, LOG_PRIORITY_DEBUG, ("%S (%s)\n", pONI->Name.Buffer, OutBuffer));
837
838
839 ObDereferenceObject(Object);
840
841
842 return pONI->Name.Buffer;
843// return TRUE;
844}
845
846
847
848/*
849 * StripFileMacros()
850 *
851 * Description:
852 * Strip file names of %SystemRoot% and %SystemDrive% macros as well as any specifications.
853 *
854 * Parameters:
855 * Path - ASCII file path to parse.
856 * Buffer - pointer to an Object where the final result will be saved.
857 * BufferSize - size of the output Buffer.
858 *
859 * Returns:
860 * Pointer to a stripped ASCII path.
861 */
862
863PCHAR
864StripFileMacros(IN PCHAR Path, OUT PCHAR Buffer, IN USHORT BufferSize)
865{
866 if (_strnicmp(Path, "%systemdrive%:", 14) == 0)
867 {
868 return Path + 14;
869 }
870
871
872 if (_strnicmp(Path, "%systemroot%\\", 13) == 0)
873 {
874 if (_snprintf(Buffer, MAX_PATH, "%s%s", SystemRootUnresolved, Path + 12) < 0)
875 return NULL;
876
877 Path = Buffer;
878 }
879
880
881 if (Path[1] == ':' && Path[2] == '\\' && (isalpha(Path[0]) || Path[0] == '?' || Path[0] == '*'))
882 {
883 Path += 2;
884 }
885
886
887 return Path;
888}
889
890
891
892/*
893 * FixupFilename()
894 *
895 * Description:
896 * Get canonical name for a file (without the drive specification, i.e. \windows\blah.exe)
897 *
898 * Parameters:
899 * szFileName - filename to resolve.
900 * szResult - output buffer.
901 * szResultSize - size of an output buffer.
902 *
903 * Returns:
904 * TRUE to indicate success, FALSE if failed.
905 */
906
907BOOLEAN
908FixupFilename(IN PCHAR szFileName, OUT PCHAR szResult, IN USHORT szResultSize)
909{
910 /* skip over \??\ */
911 if (_strnicmp(szFileName, "\\??\\", 4) == 0)
912 {
913 szFileName += 4;
914 }
915
916
917 /* replace "\SystemRoot" references with the actual system root directory */
918 if (_strnicmp(szFileName, "\\SystemRoot\\", 12) == 0)
919 {
920 _snprintf(szResult, szResultSize, "%s\\%s", SystemRootDirectory, szFileName + 12);
921 szResult[ szResultSize - 1 ] = 0;
922
923 return TRUE;
924 }
925
926
927 /* skip over X: drive specifications */
928 if (isalpha(szFileName[0]) && szFileName[1] == ':' && szFileName[2] == '\\')
929 {
930 szFileName += 2;
931 }
932
933
934 strncpy(szResult, szFileName, szResultSize);
935 szResult[ szResultSize - 1 ] = 0;
936
937
938 return TRUE;
939}
940
941
942
943/*
944 * AreMalformedExtensionsAllowed()
945 *
946 * Description:
947 * Check whether the current process is allowed to run binaries with malformed file extensions.
948 *
949 * Parameters:
950 * None.
951 *
952 * Returns:
953 * FALSE if binaries with malformed extensions are not allowed to run. TRUE otherwise.
954 */
955
956BOOLEAN
957AreMalformedExtensionsAllowed()
958{
959 PIMAGE_PID_ENTRY CurrentProcess;
960 BOOLEAN MalformedExtensionsAllowed = FALSE;
961
962
963 /* check the global policy first */
964 if (! IS_EXTENSION_PROTECTION_ON(gSecPolicy))
965 return TRUE;
966
967
968 /* now check the process specific policy */
969 CurrentProcess = FindImagePidEntry(CURRENT_PROCESS_PID, 0);
970
971 if (CurrentProcess != NULL)
972 {
973 MalformedExtensionsAllowed = ! IS_EXTENSION_PROTECTION_ON(CurrentProcess->SecPolicy);
974 }
975 else
976 {
977 LOG(LOG_SS_PATHPROC, LOG_PRIORITY_DEBUG, ("%d AreMalformedExtensionsAllowed: CurrentProcess = NULL!\n", (ULONG) PsGetCurrentProcessId()));
978 }
979
980
981 return MalformedExtensionsAllowed;
982}
983
984
985
986/*
987 * VerifyExecutableName()
988 *
989 * Description:
990 * Make sure the executed binary does not have a funny filename.
991 * Look out for non-standard extensions (.exe, etc) and double
992 * extensions that are commonly "ab"used by malware.
993 *
994 * Parameters:
995 * szFileName - filename to verify.
996 *
997 * Returns:
998 * TRUE to indicate success, FALSE if failed.
999 */
1000
1001#define CHECK_LEARNING_MODE() \
1002 if (LearningMode == TRUE) \
1003 { \
1004 TURN_EXTENSION_PROTECTION_OFF(NewPolicy); \
1005 return TRUE; \
1006 }
1007
1008BOOLEAN
1009VerifyExecutableName(IN PCHAR szFileName)
1010{
1011 SHORT i, len;
1012 BOOLEAN FirstExtension = TRUE;
1013
1014
1015 if (LearningMode == FALSE && AreMalformedExtensionsAllowed() == TRUE)
1016 {
1017 /* no need to check anything further, malformed extensions are allowed */
1018 return TRUE;
1019 }
1020
1021
1022 if ((len = (SHORT) strlen(szFileName)) == 0)
1023 return TRUE;
1024
1025
1026 for (i = len - 1; i >= 0; i--)
1027 {
1028 /* bail out once we reach the end of the filename */
1029 if (szFileName[i] == '\\')
1030 break;
1031
1032 if (szFileName[i] == '.')
1033 {
1034 if (FirstExtension == FALSE)
1035 {
1036 CHECK_LEARNING_MODE();
1037
1038 LOG(LOG_SS_PATHPROC, LOG_PRIORITY_DEBUG, ("VerifyExecutableName: Executing a binary with more than one extension '%s'\n", szFileName));
1039
1040 LogAlert(ALERT_SS_PROCESS, OP_PROC_EXECUTE, ALERT_RULE_PROCESS_EXEC_2EXTS, ACTION_LOG, ALERT_PRIORITY_HIGH, NULL, 0, szFileName);
1041
1042 return FALSE;
1043 }
1044
1045 if (len - i != 4)
1046 {
1047 CHECK_LEARNING_MODE();
1048
1049 LOG(LOG_SS_PATHPROC, LOG_PRIORITY_DEBUG, ("VerifyExecutableName: Executing a binary with an unknown extension '%s'\n", szFileName));
1050
1051 LogAlert(ALERT_SS_PROCESS, OP_PROC_EXECUTE, ALERT_RULE_PROCESS_EXEC_UNKNOWN, ACTION_LOG, ALERT_PRIORITY_HIGH, NULL, 0, szFileName);
1052
1053 return FALSE;
1054 }
1055 else
1056 {
1057 if (_stricmp(szFileName + i + 1, "exe") != 0 &&
1058 _stricmp(szFileName + i + 1, "com") != 0 &&
1059 _stricmp(szFileName + i + 1, "bat") != 0 &&
1060 _stricmp(szFileName + i + 1, "scr") != 0 &&
1061 _stricmp(szFileName + i + 1, "dir") != 0 &&
1062 _stricmp(szFileName + i + 1, "tmp") != 0 &&
1063 _stricmp(szFileName + i + 1, "_mp") != 0)
1064 {
1065 CHECK_LEARNING_MODE();
1066
1067 LOG(LOG_SS_PATHPROC, LOG_PRIORITY_DEBUG, ("VerifyExecutableName: Executing a binary with an unknown extension '%s'\n", szFileName));
1068
1069 LogAlert(ALERT_SS_PROCESS, OP_PROC_EXECUTE, ALERT_RULE_PROCESS_EXEC_UNKNOWN, ACTION_LOG, ALERT_PRIORITY_HIGH, NULL, 0, szFileName);
1070
1071 return FALSE;
1072 }
1073 }
1074
1075 FirstExtension = FALSE;
1076 }
1077 }
1078
1079
1080 if (FirstExtension == TRUE)
1081 {
1082 CHECK_LEARNING_MODE();
1083
1084 LOG(LOG_SS_PATHPROC, LOG_PRIORITY_DEBUG, ("VerifyExecutableName: Executing binary without an extension '%s'\n", szFileName));
1085
1086 LogAlert(ALERT_SS_PROCESS, OP_PROC_EXECUTE, ALERT_RULE_PROCESS_EXEC_NOEXT, ACTION_LOG, ALERT_PRIORITY_HIGH, NULL, 0, szFileName);
1087
1088 return FALSE;
1089 }
1090
1091
1092 return TRUE;
1093}