xref: /reactos/dll/win32/kernel32/client/utils.c (revision 39f11249)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS system libraries
4  * FILE:            dll/win32/kernel32/client/utils.c
5  * PURPOSE:         Utility and Support Functions
6  * PROGRAMMER:      Alex Ionescu (alex@relsoft.net)
7  *                  Pierre Schweitzer (pierre.schweitzer@reactos.org)
8  */
9 
10 /* INCLUDES ******************************************************************/
11 
12 #include <k32.h>
13 #ifdef _M_IX86
14 #include "i386/ketypes.h"
15 #elif defined _M_AMD64
16 #include "amd64/ketypes.h"
17 #endif
18 
19 #define NDEBUG
20 #include <debug.h>
21 
22 /* GLOBALS ********************************************************************/
23 
24 UNICODE_STRING Restricted = RTL_CONSTANT_STRING(L"Restricted");
25 BOOL bIsFileApiAnsi = TRUE; // set the file api to ansi or oem
26 PRTL_CONVERT_STRING Basep8BitStringToUnicodeString = RtlAnsiStringToUnicodeString;
27 PRTL_CONVERT_STRINGA BasepUnicodeStringTo8BitString = RtlUnicodeStringToAnsiString;
28 PRTL_COUNT_STRING BasepUnicodeStringTo8BitSize = BasepUnicodeStringToAnsiSize;
29 PRTL_COUNT_STRINGA Basep8BitStringToUnicodeSize = BasepAnsiStringToUnicodeSize;
30 
31 /* FUNCTIONS ******************************************************************/
32 
33 ULONG
34 NTAPI
BasepUnicodeStringToOemSize(IN PUNICODE_STRING String)35 BasepUnicodeStringToOemSize(IN PUNICODE_STRING String)
36 {
37     return RtlUnicodeStringToOemSize(String);
38 }
39 
40 ULONG
41 NTAPI
BasepOemStringToUnicodeSize(IN PANSI_STRING String)42 BasepOemStringToUnicodeSize(IN PANSI_STRING String)
43 {
44     return RtlOemStringToUnicodeSize(String);
45 }
46 
47 ULONG
48 NTAPI
BasepUnicodeStringToAnsiSize(IN PUNICODE_STRING String)49 BasepUnicodeStringToAnsiSize(IN PUNICODE_STRING String)
50 {
51     return RtlUnicodeStringToAnsiSize(String);
52 }
53 
54 ULONG
55 NTAPI
BasepAnsiStringToUnicodeSize(IN PANSI_STRING String)56 BasepAnsiStringToUnicodeSize(IN PANSI_STRING String)
57 {
58     return RtlAnsiStringToUnicodeSize(String);
59 }
60 
61 HANDLE
62 WINAPI
BaseGetNamedObjectDirectory(VOID)63 BaseGetNamedObjectDirectory(VOID)
64 {
65     OBJECT_ATTRIBUTES ObjectAttributes;
66     NTSTATUS Status;
67     HANDLE DirHandle, BnoHandle, Token, NewToken;
68 
69     if (BaseNamedObjectDirectory) return BaseNamedObjectDirectory;
70 
71     if (NtCurrentTeb()->IsImpersonating)
72     {
73         Status = NtOpenThreadToken(NtCurrentThread(),
74                                    TOKEN_IMPERSONATE,
75                                    TRUE,
76                                    &Token);
77         if (!NT_SUCCESS(Status)) return BaseNamedObjectDirectory;
78 
79         NewToken = NULL;
80         Status = NtSetInformationThread(NtCurrentThread(),
81                                         ThreadImpersonationToken,
82                                         &NewToken,
83                                         sizeof(HANDLE));
84         if (!NT_SUCCESS (Status))
85         {
86             NtClose(Token);
87             return BaseNamedObjectDirectory;
88         }
89     }
90     else
91     {
92         Token = NULL;
93     }
94 
95     RtlAcquirePebLock();
96     if (BaseNamedObjectDirectory) goto Quickie;
97 
98     InitializeObjectAttributes(&ObjectAttributes,
99                                &BaseStaticServerData->NamedObjectDirectory,
100                                OBJ_CASE_INSENSITIVE,
101                                NULL,
102                                NULL);
103 
104     Status = NtOpenDirectoryObject(&BnoHandle,
105                                    DIRECTORY_QUERY |
106                                    DIRECTORY_TRAVERSE |
107                                    DIRECTORY_CREATE_OBJECT |
108                                    DIRECTORY_CREATE_SUBDIRECTORY,
109                                    &ObjectAttributes);
110     if (!NT_SUCCESS(Status))
111     {
112         Status = NtOpenDirectoryObject(&DirHandle,
113                                        DIRECTORY_TRAVERSE,
114                                        &ObjectAttributes);
115 
116         if (NT_SUCCESS(Status))
117         {
118             InitializeObjectAttributes(&ObjectAttributes,
119                                        (PUNICODE_STRING)&Restricted,
120                                        OBJ_CASE_INSENSITIVE,
121                                        DirHandle,
122                                        NULL);
123 
124             Status = NtOpenDirectoryObject(&BnoHandle,
125                                            DIRECTORY_QUERY |
126                                            DIRECTORY_TRAVERSE |
127                                            DIRECTORY_CREATE_OBJECT |
128                                            DIRECTORY_CREATE_SUBDIRECTORY,
129                                            &ObjectAttributes);
130             NtClose(DirHandle);
131 
132         }
133     }
134 
135     if (NT_SUCCESS(Status)) BaseNamedObjectDirectory = BnoHandle;
136 
137 Quickie:
138 
139     RtlReleasePebLock();
140 
141     if (Token)
142     {
143         NtSetInformationThread(NtCurrentThread(),
144                                ThreadImpersonationToken,
145                                &Token,
146                                sizeof(Token));
147 
148         NtClose(Token);
149     }
150 
151     return BaseNamedObjectDirectory;
152 }
153 
154 VOID
155 NTAPI
BasepLocateExeLdrEntry(IN PLDR_DATA_TABLE_ENTRY Entry,IN PVOID Context,OUT BOOLEAN * StopEnumeration)156 BasepLocateExeLdrEntry(IN PLDR_DATA_TABLE_ENTRY Entry,
157                        IN PVOID Context,
158                        OUT BOOLEAN *StopEnumeration)
159 {
160     /* Make sure we get Entry, Context and valid StopEnumeration pointer */
161     ASSERT(Entry);
162     ASSERT(Context);
163     ASSERT(StopEnumeration);
164 
165     /* If entry is already found - signal to stop */
166     if (BasepExeLdrEntry)
167     {
168         *StopEnumeration = TRUE;
169         return;
170     }
171 
172     /* Otherwise keep enumerating until we find a match */
173     if (Entry->DllBase == Context)
174     {
175         /* It matches, so remember the ldr entry */
176         BasepExeLdrEntry = Entry;
177 
178         /* And stop enumeration */
179         *StopEnumeration = TRUE;
180     }
181 }
182 
183 /*
184  * Converts an ANSI or OEM String to the TEB StaticUnicodeString
185  */
186 PUNICODE_STRING
187 WINAPI
Basep8BitStringToStaticUnicodeString(IN LPCSTR String)188 Basep8BitStringToStaticUnicodeString(IN LPCSTR String)
189 {
190     PUNICODE_STRING StaticString = &(NtCurrentTeb()->StaticUnicodeString);
191     ANSI_STRING AnsiString;
192     NTSTATUS Status;
193 
194     /* Initialize an ANSI String */
195     Status = RtlInitAnsiStringEx(&AnsiString, String);
196     if (!NT_SUCCESS(Status))
197     {
198         Status = STATUS_BUFFER_OVERFLOW;
199     }
200     else
201     {
202         /* Convert it */
203         Status = Basep8BitStringToUnicodeString(StaticString, &AnsiString, FALSE);
204     }
205 
206     if (NT_SUCCESS(Status)) return StaticString;
207 
208     if (Status == STATUS_BUFFER_OVERFLOW)
209     {
210         SetLastError(ERROR_FILENAME_EXCED_RANGE);
211     }
212     else
213     {
214         BaseSetLastNTError(Status);
215     }
216 
217     return NULL;
218 }
219 
220 /*
221  * Allocates space from the Heap and converts an Unicode String into it
222  */
223 BOOLEAN
224 WINAPI
Basep8BitStringToDynamicUnicodeString(OUT PUNICODE_STRING UnicodeString,IN LPCSTR String)225 Basep8BitStringToDynamicUnicodeString(OUT PUNICODE_STRING UnicodeString,
226                                       IN LPCSTR String)
227 {
228     ANSI_STRING AnsiString;
229     NTSTATUS Status;
230 
231     /* Initialize an ANSI String */
232     Status = RtlInitAnsiStringEx(&AnsiString, String);
233     if (!NT_SUCCESS(Status))
234     {
235         Status = STATUS_BUFFER_OVERFLOW;
236     }
237     else
238     {
239         /* Convert it */
240         Status = Basep8BitStringToUnicodeString(UnicodeString, &AnsiString, TRUE);
241     }
242 
243     if (NT_SUCCESS(Status)) return TRUE;
244 
245     if (Status == STATUS_BUFFER_OVERFLOW)
246     {
247         SetLastError(ERROR_FILENAME_EXCED_RANGE);
248     }
249     else
250     {
251         BaseSetLastNTError(Status);
252     }
253 
254     return FALSE;
255 }
256 
257 /*
258  * Allocates space from the Heap and converts an Ansi String into it
259  */
260  /*NOTE: API IS A HACK */
261 VOID
262 WINAPI
BasepAnsiStringToHeapUnicodeString(IN LPCSTR AnsiString,OUT LPWSTR * UnicodeString)263 BasepAnsiStringToHeapUnicodeString(IN LPCSTR AnsiString,
264                                    OUT LPWSTR* UnicodeString)
265 {
266     ANSI_STRING AnsiTemp;
267     UNICODE_STRING UnicodeTemp;
268 
269     DPRINT("BasepAnsiStringToHeapUnicodeString\n");
270 
271     /* First create the ANSI_STRING */
272     RtlInitAnsiString(&AnsiTemp, AnsiString);
273 
274     if (NT_SUCCESS(RtlAnsiStringToUnicodeString(&UnicodeTemp,
275                                                 &AnsiTemp,
276                                                 TRUE)))
277     {
278         *UnicodeString = UnicodeTemp.Buffer;
279     }
280     else
281     {
282         *UnicodeString = NULL;
283     }
284 }
285 
286 PLARGE_INTEGER
287 WINAPI
BaseFormatTimeOut(OUT PLARGE_INTEGER Timeout,IN DWORD dwMilliseconds)288 BaseFormatTimeOut(OUT PLARGE_INTEGER Timeout,
289                   IN DWORD dwMilliseconds)
290 {
291     /* Check if this is an infinite wait, which means no timeout argument */
292     if (dwMilliseconds == INFINITE) return NULL;
293 
294     /* Otherwise, convert the time to NT Format */
295     Timeout->QuadPart = dwMilliseconds * -10000LL;
296     return Timeout;
297 }
298 
299 /*
300  * Converts lpSecurityAttributes + Object Name into ObjectAttributes.
301  */
302 POBJECT_ATTRIBUTES
303 WINAPI
BaseFormatObjectAttributes(OUT POBJECT_ATTRIBUTES ObjectAttributes,IN PSECURITY_ATTRIBUTES SecurityAttributes OPTIONAL,IN PUNICODE_STRING ObjectName)304 BaseFormatObjectAttributes(OUT POBJECT_ATTRIBUTES ObjectAttributes,
305                            IN PSECURITY_ATTRIBUTES SecurityAttributes OPTIONAL,
306                            IN PUNICODE_STRING ObjectName)
307 {
308     ULONG Attributes;
309     HANDLE RootDirectory;
310     PVOID SecurityDescriptor;
311     DPRINT("BaseFormatObjectAttributes. Security: %p, Name: %p\n",
312             SecurityAttributes, ObjectName);
313 
314     /* Get the attributes if present */
315     if (SecurityAttributes)
316     {
317         Attributes = SecurityAttributes->bInheritHandle ? OBJ_INHERIT : 0;
318         SecurityDescriptor = SecurityAttributes->lpSecurityDescriptor;
319     }
320     else
321     {
322         if (!ObjectName) return NULL;
323         Attributes = 0;
324         SecurityDescriptor = NULL;
325     }
326 
327     if (ObjectName)
328     {
329         Attributes |= OBJ_OPENIF;
330         RootDirectory = BaseGetNamedObjectDirectory();
331     }
332     else
333     {
334         RootDirectory = NULL;
335     }
336 
337     /* Create the Object Attributes */
338     InitializeObjectAttributes(ObjectAttributes,
339                                ObjectName,
340                                Attributes,
341                                RootDirectory,
342                                SecurityDescriptor);
343     DPRINT("Attributes: %lx, RootDirectory: %p, SecurityDescriptor: %p\n",
344             Attributes, RootDirectory, SecurityDescriptor);
345     return ObjectAttributes;
346 }
347 
348 /*
349  * Creates a stack for a thread or fiber.
350  * NOTE: Adapted from sdk/lib/rtl/thread.c:RtlpCreateUserStack().
351  */
352 NTSTATUS
353 WINAPI
BaseCreateStack(_In_ HANDLE hProcess,_In_opt_ SIZE_T StackCommit,_In_opt_ SIZE_T StackReserve,_Out_ PINITIAL_TEB InitialTeb)354 BaseCreateStack(
355     _In_ HANDLE hProcess,
356     _In_opt_ SIZE_T StackCommit,
357     _In_opt_ SIZE_T StackReserve,
358     _Out_ PINITIAL_TEB InitialTeb)
359 {
360     NTSTATUS Status;
361     PIMAGE_NT_HEADERS Headers;
362     ULONG_PTR Stack;
363     BOOLEAN UseGuard;
364     ULONG PageSize, AllocationGranularity, Dummy;
365     SIZE_T MinimumStackCommit, GuardPageSize;
366 
367     DPRINT("BaseCreateStack(hProcess: 0x%p, Max: 0x%lx, Current: 0x%lx)\n",
368             hProcess, StackReserve, StackCommit);
369 
370     /* Read page size */
371     PageSize = BaseStaticServerData->SysInfo.PageSize;
372     AllocationGranularity = BaseStaticServerData->SysInfo.AllocationGranularity;
373 
374     /* Get the Image Headers */
375     Headers = RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress);
376     if (!Headers) return STATUS_INVALID_IMAGE_FORMAT;
377 
378     if (StackReserve == 0)
379         StackReserve = Headers->OptionalHeader.SizeOfStackReserve;
380 
381     if (StackCommit == 0)
382     {
383         StackCommit = Headers->OptionalHeader.SizeOfStackCommit;
384     }
385     /* Check if the commit is higher than the reserve */
386     else if (StackCommit >= StackReserve)
387     {
388         /* Grow the reserve beyond the commit, up to 1MB alignment */
389         StackReserve = ROUND_UP(StackCommit, 1024 * 1024);
390     }
391 
392     /* Align everything to Page Size */
393     StackCommit = ROUND_UP(StackCommit, PageSize);
394     StackReserve = ROUND_UP(StackReserve, AllocationGranularity);
395 
396     MinimumStackCommit = NtCurrentPeb()->MinimumStackCommit;
397     if ((MinimumStackCommit != 0) && (StackCommit < MinimumStackCommit))
398     {
399         StackCommit = MinimumStackCommit;
400     }
401 
402     /* Check if the commit is higher than the reserve */
403     if (StackCommit >= StackReserve)
404     {
405         /* Grow the reserve beyond the commit, up to 1MB alignment */
406         StackReserve = ROUND_UP(StackCommit, 1024 * 1024);
407     }
408 
409     /* Align everything to Page Size */
410     StackCommit = ROUND_UP(StackCommit, PageSize);
411     StackReserve = ROUND_UP(StackReserve, AllocationGranularity);
412 
413     /* Reserve memory for the stack */
414     Stack = 0;
415     Status = NtAllocateVirtualMemory(hProcess,
416                                      (PVOID*)&Stack,
417                                      0,
418                                      &StackReserve,
419                                      MEM_RESERVE,
420                                      PAGE_READWRITE);
421     if (!NT_SUCCESS(Status))
422     {
423         DPRINT1("Failure to reserve stack: %lx\n", Status);
424         return Status;
425     }
426 
427     /* Now set up some basic Initial TEB Parameters */
428     InitialTeb->AllocatedStackBase = (PVOID)Stack;
429     InitialTeb->StackBase = (PVOID)(Stack + StackReserve);
430     InitialTeb->PreviousStackBase = NULL;
431     InitialTeb->PreviousStackLimit = NULL;
432 
433     /* Update the stack position */
434     Stack += StackReserve - StackCommit;
435 
436     /* Check if we can add a guard page */
437     if (StackReserve >= StackCommit + PageSize)
438     {
439         Stack -= PageSize;
440         StackCommit += PageSize;
441         UseGuard = TRUE;
442     }
443     else
444     {
445         UseGuard = FALSE;
446     }
447 
448     /* Allocate memory for the stack */
449     Status = NtAllocateVirtualMemory(hProcess,
450                                      (PVOID*)&Stack,
451                                      0,
452                                      &StackCommit,
453                                      MEM_COMMIT,
454                                      PAGE_READWRITE);
455     if (!NT_SUCCESS(Status))
456     {
457         DPRINT1("Failure to allocate stack\n");
458         GuardPageSize = 0;
459         NtFreeVirtualMemory(hProcess, (PVOID*)&Stack, &GuardPageSize, MEM_RELEASE);
460         return Status;
461     }
462 
463     /* Now set the current Stack Limit */
464     InitialTeb->StackLimit = (PVOID)Stack;
465 
466     /* Create a guard page if needed */
467     if (UseGuard)
468     {
469         GuardPageSize = PageSize;
470         Status = NtProtectVirtualMemory(hProcess,
471                                         (PVOID*)&Stack,
472                                         &GuardPageSize,
473                                         PAGE_GUARD | PAGE_READWRITE,
474                                         &Dummy);
475         if (!NT_SUCCESS(Status))
476         {
477             DPRINT1("Failure to set guard page\n");
478             return Status;
479         }
480 
481         /* Update the Stack Limit keeping in mind the Guard Page */
482         InitialTeb->StackLimit = (PVOID)((ULONG_PTR)InitialTeb->StackLimit +
483                                          GuardPageSize);
484     }
485 
486     /* We are done! */
487     return STATUS_SUCCESS;
488 }
489 
490 /*
491  * NOTE: Adapted from sdk/lib/rtl/thread.c:RtlpFreeUserStack().
492  */
493 VOID
494 WINAPI
BaseFreeThreadStack(_In_ HANDLE hProcess,_In_ PINITIAL_TEB InitialTeb)495 BaseFreeThreadStack(
496     _In_ HANDLE hProcess,
497     _In_ PINITIAL_TEB InitialTeb)
498 {
499     SIZE_T Dummy = 0;
500 
501     /* Free the Stack */
502     NtFreeVirtualMemory(hProcess,
503                         &InitialTeb->AllocatedStackBase,
504                         &Dummy,
505                         MEM_RELEASE);
506 }
507 
508 /*
509  * Creates the Initial Context for a Thread or Fiber
510  */
511 VOID
512 WINAPI
BaseInitializeContext(IN PCONTEXT Context,IN PVOID Parameter,IN PVOID StartAddress,IN PVOID StackAddress,IN ULONG ContextType)513 BaseInitializeContext(IN PCONTEXT Context,
514                       IN PVOID Parameter,
515                       IN PVOID StartAddress,
516                       IN PVOID StackAddress,
517                       IN ULONG ContextType)
518 {
519 #ifdef _M_IX86
520     ULONG ContextFlags;
521     DPRINT("BaseInitializeContext: %p\n", Context);
522 
523     /* Setup the Initial Win32 Thread Context */
524     Context->Eax = (ULONG)StartAddress;
525     Context->Ebx = (ULONG)Parameter;
526     Context->Esp = (ULONG)StackAddress;
527     /* The other registers are undefined */
528 
529     /* Setup the Segments */
530     Context->SegFs = KGDT_R3_TEB;
531     Context->SegEs = KGDT_R3_DATA;
532     Context->SegDs = KGDT_R3_DATA;
533     Context->SegCs = KGDT_R3_CODE;
534     Context->SegSs = KGDT_R3_DATA;
535     Context->SegGs = 0;
536 
537     /* Set the Context Flags */
538     ContextFlags = Context->ContextFlags;
539     Context->ContextFlags = CONTEXT_FULL;
540 
541     /* Give it some room for the Parameter */
542     Context->Esp -= sizeof(PVOID);
543 
544     /* Set the EFLAGS */
545     Context->EFlags = 0x3000; /* IOPL 3 */
546 
547     /* What kind of context is being created? */
548     if (ContextType == 1)
549     {
550         /* For Threads */
551         Context->Eip = (ULONG)BaseThreadStartupThunk;
552     }
553     else if (ContextType == 2)
554     {
555         /* This is a fiber: make space for the return address */
556         Context->Esp -= sizeof(PVOID);
557         *((PVOID*)Context->Esp) = BaseFiberStartup;
558 
559         /* Is FPU state required? */
560         Context->ContextFlags |= ContextFlags;
561         if ((ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT)
562         {
563             /* Set an initial state */
564             Context->FloatSave.ControlWord = 0x27F;
565             Context->FloatSave.StatusWord = 0;
566             Context->FloatSave.TagWord = 0xFFFF;
567             Context->FloatSave.ErrorOffset = 0;
568             Context->FloatSave.ErrorSelector = 0;
569             Context->FloatSave.DataOffset = 0;
570             Context->FloatSave.DataSelector = 0;
571             if (SharedUserData->ProcessorFeatures[PF_XMMI_INSTRUCTIONS_AVAILABLE])
572                 Context->Dr6 = 0x1F80;
573         }
574     }
575     else
576     {
577         /* For first thread in a Process */
578         Context->Eip = (ULONG)BaseProcessStartThunk;
579     }
580 
581 #elif defined(_M_AMD64)
582     DPRINT("BaseInitializeContext: %p\n", Context);
583     ASSERT(((ULONG_PTR)StackAddress & 15) == 0);
584 
585     RtlZeroMemory(Context, sizeof(*Context));
586 
587     /* Setup the Initial Win32 Thread Context */
588     Context->Rcx = (ULONG_PTR)StartAddress;
589     Context->Rdx = (ULONG_PTR)Parameter;
590     Context->Rsp = (ULONG_PTR)StackAddress - 5 * sizeof(PVOID);
591 
592     /* Setup the Segments */
593     Context->SegGs = KGDT64_R3_DATA | RPL_MASK;
594     Context->SegEs = KGDT64_R3_DATA | RPL_MASK;
595     Context->SegDs = KGDT64_R3_DATA | RPL_MASK;
596     Context->SegCs = KGDT64_R3_CODE | RPL_MASK;
597     Context->SegSs = KGDT64_R3_DATA | RPL_MASK;
598     Context->SegFs = KGDT64_R3_CMTEB | RPL_MASK;
599 
600     /* Set the EFLAGS */
601     Context->EFlags = 0x3000 | EFLAGS_INTERRUPT_MASK; /* IOPL 3 */
602 
603     /* Set MXCSR */
604     Context->MxCsr = INITIAL_MXCSR;
605 
606     if (ContextType == 1)      /* For Threads */
607     {
608         Context->Rip = (ULONG_PTR)BaseThreadStartup;
609     }
610     else if (ContextType == 2) /* For Fibers */
611     {
612         Context->Rip = (ULONG_PTR)BaseFiberStartup;
613     }
614     else                       /* For first thread in a Process */
615     {
616         Context->Rip = (ULONG_PTR)BaseProcessStartup;
617     }
618 
619     /* Set the Context Flags */
620     Context->ContextFlags = CONTEXT_FULL;
621 #elif defined(_M_ARM)
622     DPRINT("BaseInitializeContext: %p\n", Context);
623 
624     // FIXME: check if this is correct!
625     /* Setup the Initial Win32 Thread Context */
626     Context->R0 = (ULONG_PTR)StartAddress;
627     Context->R1 = (ULONG_PTR)Parameter;
628     Context->Sp = (ULONG_PTR)StackAddress;
629 
630     if (ContextType == 1)      /* For Threads */
631     {
632         Context->Pc = (ULONG_PTR)BaseThreadStartupThunk;
633     }
634     else if (ContextType == 2) /* For Fibers */
635     {
636         Context->Pc = (ULONG_PTR)BaseFiberStartup;
637     }
638     else                       /* For first thread in a Process */
639     {
640         Context->Pc = (ULONG_PTR)BaseProcessStartThunk;
641     }
642 
643     /* Set the Context Flags */
644     Context->ContextFlags = CONTEXT_FULL;
645 
646     /* Give it some room for the Parameter */
647     Context->Sp -= sizeof(PVOID);
648 #else
649 #warning Unknown architecture
650     UNIMPLEMENTED;
651     DbgBreakPoint();
652 #endif
653 }
654 
655 /*
656  * Checks if the privilege for Real-Time Priority is there
657  * Beware about this function behavior:
658  * - In case Keep is set to FALSE, then the function will only check
659  * whether real time is allowed and won't grant the privilege. In that case
660  * it will return TRUE if allowed, FALSE otherwise. Not a state!
661  * It means you don't have to release privilege when calling with FALSE.
662  */
663 PVOID
664 WINAPI
BasepIsRealtimeAllowed(IN BOOLEAN Keep)665 BasepIsRealtimeAllowed(IN BOOLEAN Keep)
666 {
667     ULONG Privilege = SE_INC_BASE_PRIORITY_PRIVILEGE;
668     PVOID State;
669     NTSTATUS Status;
670 
671     Status = RtlAcquirePrivilege(&Privilege, 1, 0, &State);
672     if (!NT_SUCCESS(Status)) return NULL;
673 
674     if (!Keep)
675     {
676         RtlReleasePrivilege(State);
677         State = (PVOID)TRUE;
678     }
679 
680     return State;
681 }
682 
683 /*
684  * Maps an image file into a section
685  */
686 NTSTATUS
687 WINAPI
BasepMapFile(IN LPCWSTR lpApplicationName,OUT PHANDLE hSection,IN PUNICODE_STRING ApplicationName)688 BasepMapFile(IN LPCWSTR lpApplicationName,
689              OUT PHANDLE hSection,
690              IN PUNICODE_STRING ApplicationName)
691 {
692     RTL_RELATIVE_NAME_U RelativeName;
693     OBJECT_ATTRIBUTES ObjectAttributes;
694     NTSTATUS Status;
695     HANDLE hFile = NULL;
696     IO_STATUS_BLOCK IoStatusBlock;
697 
698     DPRINT("BasepMapFile\n");
699 
700     /* Zero out the Relative Directory */
701     RelativeName.ContainingDirectory = NULL;
702 
703     /* Find the application name */
704     if (!RtlDosPathNameToNtPathName_U(lpApplicationName,
705                                       ApplicationName,
706                                       NULL,
707                                       &RelativeName))
708     {
709         return STATUS_OBJECT_PATH_NOT_FOUND;
710     }
711 
712     DPRINT("ApplicationName %wZ\n", ApplicationName);
713     DPRINT("RelativeName %wZ\n", &RelativeName.RelativeName);
714 
715     /* Did we get a relative name? */
716     if (RelativeName.RelativeName.Length)
717     {
718         ApplicationName = &RelativeName.RelativeName;
719     }
720 
721     /* Initialize the Object Attributes */
722     InitializeObjectAttributes(&ObjectAttributes,
723                                ApplicationName,
724                                OBJ_CASE_INSENSITIVE,
725                                RelativeName.ContainingDirectory,
726                                NULL);
727 
728     /* Try to open the executable */
729     Status = NtOpenFile(&hFile,
730                         SYNCHRONIZE | FILE_EXECUTE | FILE_READ_DATA,
731                         &ObjectAttributes,
732                         &IoStatusBlock,
733                         FILE_SHARE_DELETE | FILE_SHARE_READ,
734                         FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE);
735     if (!NT_SUCCESS(Status))
736     {
737         DPRINT1("Failed to open file\n");
738         BaseSetLastNTError(Status);
739         return Status;
740     }
741 
742     /* Create a section for this file */
743     Status = NtCreateSection(hSection,
744                              SECTION_ALL_ACCESS,
745                              NULL,
746                              NULL,
747                              PAGE_EXECUTE,
748                              SEC_IMAGE,
749                              hFile);
750     NtClose(hFile);
751 
752     /* Return status */
753     DPRINT("Section: %p for file: %p\n", *hSection, hFile);
754     return Status;
755 }
756 
757 /*
758  * @implemented
759  */
760 BOOLEAN
761 WINAPI
Wow64EnableWow64FsRedirection(IN BOOLEAN Wow64EnableWow64FsRedirection)762 Wow64EnableWow64FsRedirection(IN BOOLEAN Wow64EnableWow64FsRedirection)
763 {
764     NTSTATUS Status;
765     BOOL Result;
766 
767     Status = RtlWow64EnableFsRedirection(Wow64EnableWow64FsRedirection);
768     if (NT_SUCCESS(Status))
769     {
770         Result = TRUE;
771     }
772     else
773     {
774         BaseSetLastNTError(Status);
775         Result = FALSE;
776     }
777     return Result;
778 }
779 
780 /*
781  * @implemented
782  */
783 BOOL
784 WINAPI
Wow64DisableWow64FsRedirection(IN PVOID * OldValue)785 Wow64DisableWow64FsRedirection(IN PVOID *OldValue)
786 {
787     NTSTATUS Status;
788     BOOL Result;
789 
790     Status = RtlWow64EnableFsRedirectionEx((PVOID)TRUE, OldValue);
791     if (NT_SUCCESS(Status))
792     {
793         Result = TRUE;
794     }
795     else
796     {
797         BaseSetLastNTError(Status);
798         Result = FALSE;
799     }
800     return Result;
801 }
802 
803 /*
804  * @implemented
805  */
806 BOOL
807 WINAPI
Wow64RevertWow64FsRedirection(IN PVOID OldValue)808 Wow64RevertWow64FsRedirection(IN PVOID OldValue)
809 {
810     NTSTATUS Status;
811     BOOL Result;
812 
813     Status = RtlWow64EnableFsRedirectionEx(OldValue, &OldValue);
814     if (NT_SUCCESS(Status))
815     {
816         Result = TRUE;
817     }
818     else
819     {
820         BaseSetLastNTError(Status);
821         Result = FALSE;
822     }
823     return Result;
824 }
825 
826 /*
827  * @implemented
828  */
829 VOID
830 WINAPI
SetFileApisToOEM(VOID)831 SetFileApisToOEM(VOID)
832 {
833     /* Set the correct Base Api */
834     Basep8BitStringToUnicodeString = (PRTL_CONVERT_STRING)RtlOemStringToUnicodeString;
835     BasepUnicodeStringTo8BitString = RtlUnicodeStringToOemString;
836     BasepUnicodeStringTo8BitSize = BasepUnicodeStringToOemSize;
837     Basep8BitStringToUnicodeSize = BasepOemStringToUnicodeSize;
838 
839     /* FIXME: Old, deprecated way */
840     bIsFileApiAnsi = FALSE;
841 }
842 
843 
844 /*
845  * @implemented
846  */
847 VOID
848 WINAPI
SetFileApisToANSI(VOID)849 SetFileApisToANSI(VOID)
850 {
851     /* Set the correct Base Api */
852     Basep8BitStringToUnicodeString = RtlAnsiStringToUnicodeString;
853     BasepUnicodeStringTo8BitString = RtlUnicodeStringToAnsiString;
854     BasepUnicodeStringTo8BitSize = BasepUnicodeStringToAnsiSize;
855     Basep8BitStringToUnicodeSize = BasepAnsiStringToUnicodeSize;
856 
857     /* FIXME: Old, deprecated way */
858     bIsFileApiAnsi = TRUE;
859 }
860 
861 /*
862  * @implemented
863  */
864 BOOL
865 WINAPI
AreFileApisANSI(VOID)866 AreFileApisANSI(VOID)
867 {
868    return Basep8BitStringToUnicodeString == RtlAnsiStringToUnicodeString;
869 }
870 
871 /*
872  * @implemented
873  */
874 VOID
875 WINAPI
BaseMarkFileForDelete(IN HANDLE FileHandle,IN ULONG FileAttributes)876 BaseMarkFileForDelete(IN HANDLE FileHandle,
877                       IN ULONG FileAttributes)
878 {
879     IO_STATUS_BLOCK IoStatusBlock;
880     FILE_BASIC_INFORMATION FileBasicInfo;
881     FILE_DISPOSITION_INFORMATION FileDispositionInfo;
882 
883     /* If no attributes were given, get them */
884     if (!FileAttributes)
885     {
886         FileBasicInfo.FileAttributes = 0;
887         NtQueryInformationFile(FileHandle,
888                                &IoStatusBlock,
889                                &FileBasicInfo,
890                                sizeof(FileBasicInfo),
891                                FileBasicInformation);
892         FileAttributes = FileBasicInfo.FileAttributes;
893     }
894 
895     /* If file is marked as RO, reset its attributes */
896     if (FileAttributes & FILE_ATTRIBUTE_READONLY)
897     {
898         RtlZeroMemory(&FileBasicInfo, sizeof(FileBasicInfo));
899         FileBasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
900         NtSetInformationFile(FileHandle,
901                              &IoStatusBlock,
902                              &FileBasicInfo,
903                              sizeof(FileBasicInfo),
904                              FileBasicInformation);
905     }
906 
907     /* Finally, mark the file for deletion */
908     FileDispositionInfo.DeleteFile = TRUE;
909     NtSetInformationFile(FileHandle,
910                          &IoStatusBlock,
911                          &FileDispositionInfo,
912                          sizeof(FileDispositionInfo),
913                          FileDispositionInformation);
914 }
915 
916 /*
917  * @unimplemented
918  */
919 NTSTATUS
920 WINAPI
BasepCheckWinSaferRestrictions(IN HANDLE UserToken,IN LPWSTR ApplicationName,IN HANDLE FileHandle,OUT PBOOLEAN InJob,OUT PHANDLE NewToken,OUT PHANDLE JobHandle)921 BasepCheckWinSaferRestrictions(IN HANDLE UserToken,
922                                IN LPWSTR ApplicationName,
923                                IN HANDLE FileHandle,
924                                OUT PBOOLEAN InJob,
925                                OUT PHANDLE NewToken,
926                                OUT PHANDLE JobHandle)
927 {
928     NTSTATUS Status;
929 
930     /* Validate that there's a name */
931     if ((ApplicationName) && *(ApplicationName))
932     {
933         /* Validate that the required output parameters are there */
934         if ((InJob) && (NewToken) && (JobHandle))
935         {
936             /* Do the work (one day...) */
937             DPRINT("BasepCheckWinSaferRestrictions is UNIMPLEMENTED\n");
938             Status = STATUS_SUCCESS;
939         }
940         else
941         {
942             /* Act as if SEH hit this */
943             Status = STATUS_ACCESS_VIOLATION;
944         }
945     }
946     else
947     {
948         /* Input is invalid */
949         Status = STATUS_INVALID_PARAMETER;
950     }
951 
952     /* Return the status */
953     return Status;
954 }
955