ReactOS 0.4.17-dev-650-gd0e71de
smutil.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS Windows-Compatible Session Manager
3 * LICENSE: BSD 2-Clause License
4 * FILE: base/system/smss/smutil.c
5 * PURPOSE: Main SMSS Code
6 * PROGRAMMERS: Alex Ionescu
7 */
8
9/* INCLUDES *******************************************************************/
10
11#include "smss.h"
12
13#include <ndk/sefuncs.h>
14
15#define NDEBUG
16#include <debug.h>
17
18/* GLOBALS ********************************************************************/
19
21{
28
30
31/* FUNCTIONS ******************************************************************/
32
36 OUT PVOID *PrivilegeState)
37{
39 ULONG Size;
41
42 /* Assume failure */
43 *PrivilegeState = NULL;
44
45 /* Acquire the state structure to hold everything we need */
47 0,
48 sizeof(SMP_PRIVILEGE_STATE) +
49 sizeof(TOKEN_PRIVILEGES) +
50 sizeof(LUID_AND_ATTRIBUTES));
51 if (!State) return STATUS_NO_MEMORY;
52
53 /* Open our token */
56 &State->TokenHandle);
57 if (!NT_SUCCESS(Status))
58 {
59 /* Fail */
61 return Status;
62 }
63
64 /* Set one privilege in the enabled state */
65 State->NewPrivileges = &State->NewBuffer;
66 State->OldPrivileges = (PTOKEN_PRIVILEGES)&State->OldBuffer;
67 State->NewPrivileges->PrivilegeCount = 1;
68 State->NewPrivileges->Privileges[0].Luid = RtlConvertUlongToLuid(Privilege);
69 State->NewPrivileges->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
70
71 /* Adjust the privileges in the token */
72 Size = sizeof(State->OldBuffer);
74 FALSE,
75 State->NewPrivileges,
76 Size,
77 State->OldPrivileges,
78 &Size);
80 {
81 /* Our static buffer is not big enough, allocate a bigger one */
82 State->OldPrivileges = RtlAllocateHeap(SmpHeap, 0, Size);
83 if (!State->OldPrivileges)
84 {
85 /* Out of memory, fail */
87 goto Quickie;
88 }
89
90 /* Now try again */
92 FALSE,
93 State->NewPrivileges,
94 Size,
95 State->OldPrivileges,
96 &Size);
97 }
98
99 /* Normalize failure code and check for success */
101 if (NT_SUCCESS(Status))
102 {
103 /* We got the privilege, return */
104 *PrivilegeState = State;
105 return STATUS_SUCCESS;
106 }
107
108Quickie:
109 /* Check if we used a dynamic buffer */
110 if (State->OldPrivileges != (PTOKEN_PRIVILEGES)&State->OldBuffer)
111 {
112 /* Free it */
113 RtlFreeHeap(SmpHeap, 0, State->OldPrivileges);
114 }
115
116 /* Close the token handle and free the state structure */
117 NtClose(State->TokenHandle);
119 return Status;
120}
121
122VOID
123NTAPI
125{
127
128 /* Adjust the privileges in the token */
129 NtAdjustPrivilegesToken(State->TokenHandle,
130 FALSE,
131 State->OldPrivileges,
132 0,
133 NULL,
134 NULL);
135
136 /* Check if we used a dynamic buffer */
137 if (State->OldPrivileges != (PTOKEN_PRIVILEGES)&State->OldBuffer)
138 {
139 /* Free it */
140 RtlFreeHeap(SmpHeap, 0, State->OldPrivileges);
141 }
142
143 /* Close the token handle and free the state structure */
144 NtClose(State->TokenHandle);
146}
147
149NTAPI
151 IN BOOLEAN SecondPass,
153{
154 PWCHAR p, pp;
155 ULONG Length, TokenLength, InputLength;
156
157 /* Initialize to NULL to start with */
159
160 /* Save the input length */
161 InputLength = Input->Length;
162
163 /* If the input string is empty, just return */
164 if (InputLength == 0) return STATUS_SUCCESS;
165
166 /* Parse the buffer until the first character */
167 p = Input->Buffer;
168 Length = 0;
169 while (Length < InputLength)
170 {
171 if (*p > L' ') break;
172 ++p;
173 Length += sizeof(WCHAR);
174 }
175
176 /* Are we being called for argument pick-up? */
177 if (SecondPass)
178 {
179 /* Then assume everything else is an argument */
180 TokenLength = InputLength - Length * sizeof(WCHAR);
181 pp = (PWSTR)((ULONG_PTR)p + TokenLength);
182 }
183 else
184 {
185 /* No -- so loop until the next space */
186 pp = p;
187 while (Length < InputLength)
188 {
189 if (*pp <= L' ') break;
190 ++pp;
191 Length += sizeof(WCHAR);
192 }
193
194 /* Now compute how long this token is, and loop until the next char */
196 while (Length < InputLength)
197 {
198 if (*pp > L' ') break;
199 ++pp;
200 Length += sizeof(WCHAR);
201 }
202 }
203
204 /* Did we find a token? */
205 if (TokenLength)
206 {
207 /* Allocate a buffer for it */
208 Token->Buffer = RtlAllocateHeap(SmpHeap,
209 SmBaseTag,
210 TokenLength + sizeof(UNICODE_NULL));
211 if (!Token->Buffer) return STATUS_NO_MEMORY;
212
213 /* Fill in the unicode string to hold it */
214 Token->MaximumLength = (USHORT)(TokenLength + sizeof(UNICODE_NULL));
215 Token->Length = (USHORT)TokenLength;
216 RtlCopyMemory(Token->Buffer, p, TokenLength);
217 Token->Buffer[TokenLength / sizeof(WCHAR)] = UNICODE_NULL;
218 }
219
220 /* Modify the input string with the position of where the next token begins */
221 Input->Length -= (USHORT)((ULONG_PTR)pp - (ULONG_PTR)Input->Buffer);
222 Input->Buffer = pp;
223 return STATUS_SUCCESS;
224}
225
227NTAPI
232 OUT PUNICODE_STRING Arguments)
233{
235 UNICODE_STRING EnvString, PathString, CmdLineCopy, Token;
236 WCHAR PathBuffer[MAX_PATH];
237 PWCHAR FilePart;
239 UNICODE_STRING FullPathString;
240
241 /* Initialize output arguments to NULL */
243 RtlInitUnicodeString(Arguments, NULL);
245
246 /* Check if we haven't yet built a full default path or system root yet */
248 {
249 /* Initialize it based on shared user data string */
251
252 /* Allocate an empty string for the path */
254 sizeof(L"\\system32;");
255 RtlInitEmptyUnicodeString(&FullPathString,
257 (USHORT)Length);
258 if (FullPathString.Buffer)
259 {
260 /* Append the root, system32;, and then the current library path */
262 RtlAppendUnicodeToString(&FullPathString, L"\\system32;");
265 SmpDefaultLibPath = FullPathString;
266 }
267 }
268
269 /* Consume the command line */
270 CmdLineCopy = *CommandLine;
271 while (TRUE)
272 {
273 /* Parse the first token and check for modifiers/specifiers */
274 Status = SmpParseToken(&CmdLineCopy, FALSE, &Token);
275 if (!(NT_SUCCESS(Status)) || !(Token.Buffer)) return STATUS_UNSUCCESSFUL;
276 if (!Flags) break;
277
278 /* Debug requested? */
280 {
281 /* Convert into a flag */
283 }
285 {
286 /* Asynch requested, convert into a flag */
288 }
290 {
291 /* Autochk requested, convert into a flag */
293 }
294 else
295 {
296 /* No specifier found, keep going */
297 break;
298 }
299
300 /* Get rid of this token and get the next */
301 RtlFreeHeap(SmpHeap, 0, Token.Buffer);
302 }
303
304 /* Initialize a string to hold the current path */
305 RtlInitUnicodeString(&EnvString, L"Path");
307 RtlInitEmptyUnicodeString(&PathString,
309 (USHORT)Length);
310 if (!PathString.Buffer)
311 {
312 /* Fail if we have no memory for this */
313 RtlFreeHeap(SmpHeap, 0, Token.Buffer);
315 }
316
317 /* Query the path from the environment */
319 &EnvString,
320 &PathString);
322 {
323 /* Our buffer was too small, free it */
324 RtlFreeHeap(SmpHeap, 0, PathString.Buffer);
325
326 /* And allocate one big enough */
327 Length = PathString.Length + sizeof(UNICODE_NULL);
328 RtlInitEmptyUnicodeString(&PathString,
330 (USHORT)Length);
331 if (!PathString.Buffer)
332 {
333 /* Fail if we have no memory for this */
334 RtlFreeHeap(SmpHeap, 0, Token.Buffer);
336 }
337
338 /* Now try again, this should work */
340 &EnvString,
341 &PathString);
342 }
343 if (!NT_SUCCESS(Status))
344 {
345 /* Another failure means that the kernel hasn't passed the path correctly */
346 DPRINT1("SMSS: %wZ environment variable not defined.\n", &EnvString);
348 }
349 else
350 {
351 /* Check if the caller expects any flags out of here */
352 if (Flags)
353 {
354 /* We can return the image not found flag -- so does the image exist */
355 if (!(RtlDosSearchPath_U(PathString.Buffer,
356 Token.Buffer,
357 L".exe",
358 sizeof(PathBuffer),
359 PathBuffer,
360 &FilePart)) &&
362 Token.Buffer,
363 L".exe",
364 sizeof(PathBuffer),
365 PathBuffer,
366 &FilePart)))
367 {
368 /* It doesn't, let the caller know about it and exit */
370 *FileName = Token;
371 RtlFreeHeap(SmpHeap, 0, PathString.Buffer);
372 return STATUS_SUCCESS;
373 }
374 }
375 else
376 {
377 /* Caller doesn't want flags, probably wants the image itself */
378 RtlStringCbCopyW(PathBuffer, sizeof(PathBuffer), Token.Buffer);
379 }
380 }
381
382 /* Free tokens and such, all that's left is to convert the image name */
383 RtlFreeHeap(SmpHeap, 0, Token.Buffer);
384 RtlFreeHeap(SmpHeap, 0, PathString.Buffer);
385 if (!NT_SUCCESS(Status)) return Status;
386
387 /* Convert it and bail out if this failed */
389 {
390 DPRINT1("SMSS: Unable to translate %ws into an NT File Name\n",
391 &PathBuffer);
393 }
394 if (!NT_SUCCESS(Status)) return Status;
395
396 /* Finally, check if the caller also wanted the directory */
397 if (Directory)
398 {
399 /* Is the file a relative name with no directory? */
400 if (FilePart <= PathBuffer)
401 {
402 /* Clear it */
404 }
405 else
406 {
407 /* There is a directory, and a filename -- separate those two */
408 *--FilePart = UNICODE_NULL;
410 }
411 }
412
413 /* We are done -- move on to the second pass to get the arguments */
414 return SmpParseToken(&CmdLineCopy, TRUE, Arguments);
415}
416
418NTAPI
420 OUT PBOOLEAN ShutdownOkay)
421{
424 PVOID BootStatusDataHandle;
425
426 /* Assume failure */
427 *BootOkay = FALSE;
428 *ShutdownOkay = FALSE;
429
430 /* Lock the BSD and fail if we couldn't */
431 Status = RtlLockBootStatusData(&BootStatusDataHandle);
432 if (!NT_SUCCESS(Status)) return FALSE;
433
434 /* Read the old settings */
435 RtlGetSetBootStatusData(BootStatusDataHandle,
436 TRUE,
438 BootOkay,
439 sizeof(BOOLEAN),
440 NULL);
441 RtlGetSetBootStatusData(BootStatusDataHandle,
442 TRUE,
444 ShutdownOkay,
445 sizeof(BOOLEAN),
446 NULL);
447
448 /* Set new ones indicating we got at least this far */
449 RtlGetSetBootStatusData(BootStatusDataHandle,
450 FALSE,
452 &Value,
453 sizeof(Value),
454 NULL);
455 RtlGetSetBootStatusData(BootStatusDataHandle,
456 FALSE,
458 &Value,
459 sizeof(Value),
460 NULL);
461
462 /* Unlock the BSD and return */
463 RtlUnlockBootStatusData(BootStatusDataHandle);
464 return TRUE;
465}
466
467VOID
468NTAPI
470 IN BOOLEAN ShutdownOkay)
471{
473 PVOID BootState;
474
475 /* Lock the BSD */
476 Status = RtlLockBootStatusData(&BootState);
477 if (NT_SUCCESS(Status))
478 {
479 /* Write the bootokay and bootshutdown values */
480 RtlGetSetBootStatusData(BootState,
481 FALSE,
483 &BootOkay,
484 sizeof(BootOkay),
485 NULL);
486 RtlGetSetBootStatusData(BootState,
487 FALSE,
489 &ShutdownOkay,
490 sizeof(ShutdownOkay),
491 NULL);
492
493 /* Unlock the BSD and return */
494 RtlUnlockBootStatusData(BootState);
495 }
496}
#define STATUS_PRIVILEGE_NOT_HELD
Definition: DriverTester.h:9
unsigned char BOOLEAN
Definition: actypes.h:127
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
PVOID NTAPI RtlAllocateHeap(IN PVOID HeapHandle, IN ULONG Flags, IN SIZE_T Size)
Definition: heap.c:616
BOOLEAN NTAPI RtlFreeHeap(IN PVOID HeapHandle, IN ULONG Flags, IN PVOID HeapBase)
Definition: heap.c:634
NTSYSAPI BOOLEAN NTAPI RtlCreateUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
#define STATUS_NO_MEMORY
Definition: d3dkmdt.h:51
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
#define MAX_PATH
Definition: compat.h:34
#define L(x)
Definition: resources.c:13
#define ULONG_PTR
Definition: config.h:101
#define PAGE_SIZE
Definition: env_spec_w32.h:49
NTSTATUS RtlAppendUnicodeToString(IN PUNICODE_STRING Str1, IN PWSTR Str2)
Definition: string_lib.cpp:62
Status
Definition: gdiplustypes.h:24
GLfloat GLfloat p
Definition: glext.h:8902
NTSYSAPI ULONG NTAPI RtlDosSearchPath_U(_In_ PCWSTR Path, _In_ PCWSTR FileName, _In_ PCWSTR Extension, _In_ ULONG BufferSize, _Out_ PWSTR Buffer, _Out_ PWSTR *PartName)
_In_ BOOLEAN _In_ USHORT Directory
Definition: rtlfuncs.h:3962
NTSYSAPI NTSTATUS NTAPI RtlQueryEnvironmentVariable_U(_In_opt_ PWSTR Environment, _In_ PCUNICODE_STRING Name, _Out_ PUNICODE_STRING Value)
Definition: env.c:659
NTSYSAPI BOOLEAN NTAPI RtlDosPathNameToNtPathName_U(_In_opt_z_ PCWSTR DosPathName, _Out_ PUNICODE_STRING NtPathName, _Out_opt_ PCWSTR *NtFileNamePart, _Out_opt_ PRTL_RELATIVE_NAME_U DirectoryInfo)
@ RtlBsdItemBootShutdown
Definition: rtltypes.h:433
@ RtlBsdItemBootGood
Definition: rtltypes.h:432
NTSYSAPI NTSTATUS NTAPI RtlAppendUnicodeStringToString(PUNICODE_STRING Destination, PUNICODE_STRING Source)
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
NTSYSAPI BOOLEAN NTAPI RtlEqualUnicodeString(PUNICODE_STRING String1, PUNICODE_STRING String2, BOOLEAN CaseInSensitive)
#define NtCurrentProcess()
Definition: nt_native.h:1660
NTSTATUS NTAPI NtClose(IN HANDLE Handle)
Definition: obhandle.c:3419
#define UNICODE_NULL
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
NTSTATUS NTAPI NtOpenProcessToken(IN HANDLE ProcessHandle, IN ACCESS_MASK DesiredAccess, OUT PHANDLE TokenHandle)
Definition: security.c:350
#define STATUS_NOT_ALL_ASSIGNED
Definition: ntstatus.h:138
#define STATUS_OBJECT_PATH_INVALID
Definition: ntstatus.h:387
NTSTRSAFEAPI RtlStringCbCopyW(_Out_writes_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest, _In_ size_t cbDest, _In_ NTSTRSAFE_PCWSTR pszSrc)
Definition: ntstrsafe.h:174
short WCHAR
Definition: pedump.c:58
unsigned short USHORT
Definition: pedump.c:61
@ Input
Definition: arc.h:93
#define SharedUserData
NTSTATUS NTAPI RtlLockBootStatusData(_Out_ PHANDLE FileHandle)
Definition: bootdata.c:231
NTSTATUS NTAPI RtlGetSetBootStatusData(_In_ HANDLE FileHandle, _In_ BOOLEAN Read, _In_ RTL_BSD_ITEM_TYPE DataClass, _In_ PVOID Buffer, _In_ ULONG BufferSize, _Out_opt_ PULONG ReturnLength)
Definition: bootdata.c:161
NTSTATUS NTAPI RtlUnlockBootStatusData(_In_ HANDLE FileHandle)
Definition: bootdata.c:267
#define STATUS_SUCCESS
Definition: shellext.h:65
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:69
PVOID SmpHeap
Definition: sminit.c:25
ULONG SmBaseTag
Definition: sminit.c:26
UNICODE_STRING SmpDefaultLibPath
Definition: sminit.c:29
PWCHAR SmpDefaultEnvironment
Definition: sminit.c:28
UNICODE_STRING SmpSystemRoot
Definition: smss.c:20
#define SMP_AUTOCHK_FLAG
Definition: smss.h:46
#define SMP_DEBUG_FLAG
Definition: smss.h:44
#define SMP_INVALID_PATH
Definition: smss.h:48
#define SMP_ASYNC_FLAG
Definition: smss.h:45
NTSTATUS NTAPI SmpParseToken(IN PUNICODE_STRING Input, IN BOOLEAN SecondPass, OUT PUNICODE_STRING Token)
Definition: smutil.c:150
UNICODE_STRING SmpAutoChkKeyword
Definition: smutil.c:29
struct _SMP_PRIVILEGE_STATE * PSMP_PRIVILEGE_STATE
VOID NTAPI SmpReleasePrivilege(IN PVOID PrivState)
Definition: smutil.c:124
NTSTATUS NTAPI SmpParseCommandLine(IN PUNICODE_STRING CommandLine, OUT PULONG Flags, OUT PUNICODE_STRING FileName, OUT PUNICODE_STRING Directory, OUT PUNICODE_STRING Arguments)
Definition: smutil.c:228
UNICODE_STRING SmpDebugKeyword
Definition: smutil.c:29
struct _SMP_PRIVILEGE_STATE SMP_PRIVILEGE_STATE
NTSTATUS NTAPI SmpAcquirePrivilege(IN ULONG Privilege, OUT PVOID *PrivilegeState)
Definition: smutil.c:35
BOOLEAN NTAPI SmpSaveAndClearBootStatusData(OUT PBOOLEAN BootOkay, OUT PBOOLEAN ShutdownOkay)
Definition: smutil.c:419
UNICODE_STRING SmpASyncKeyword
Definition: smutil.c:29
VOID NTAPI SmpRestoreBootStatusData(IN BOOLEAN BootOkay, IN BOOLEAN ShutdownOkay)
Definition: smutil.c:469
int TokenLength(const char *pc)
Definition: spec2def.c:193
TOKEN_PRIVILEGES NewBuffer
Definition: smutil.c:26
PTOKEN_PRIVILEGES NewPrivileges
Definition: smutil.c:24
UCHAR OldBuffer[1024]
Definition: smutil.c:25
PTOKEN_PRIVILEGES OldPrivileges
Definition: smutil.c:23
HANDLE TokenHandle
Definition: smutil.c:22
USHORT MaximumLength
Definition: env_spec_w32.h:370
_Must_inspect_result_ __kernel_entry NTSTATUS NTAPI NtAdjustPrivilegesToken(_In_ HANDLE TokenHandle, _In_ BOOLEAN DisableAllPrivileges, _In_opt_ PTOKEN_PRIVILEGES NewState, _In_ ULONG BufferLength, _Out_writes_bytes_to_opt_(BufferLength, *ReturnLength) PTOKEN_PRIVILEGES PreviousState, _When_(PreviousState!=NULL, _Out_) PULONG ReturnLength)
Removes a certain amount of privileges of a token based upon the request by the caller.
Definition: tokenadj.c:451
uint16_t * PWSTR
Definition: typedefs.h:56
uint32_t * PULONG
Definition: typedefs.h:59
unsigned char UCHAR
Definition: typedefs.h:53
unsigned char * PBOOLEAN
Definition: typedefs.h:53
#define NTAPI
Definition: typedefs.h:36
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define IN
Definition: typedefs.h:39
uint16_t * PWCHAR
Definition: typedefs.h:56
uint32_t ULONG
Definition: typedefs.h:59
#define OUT
Definition: typedefs.h:40
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
#define STATUS_OBJECT_NAME_NOT_FOUND
Definition: udferr_usr.h:149
BOOL Privilege(LPTSTR pszPrivilege, BOOL bEnable)
Definition: user_lib.cpp:531
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_DEVICE_PROPERTY_DATA _In_ DEVPROPTYPE _In_ ULONG Size
Definition: wdfdevice.h:4539
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _Out_opt_ PUSHORT _Inout_opt_ PUNICODE_STRING Value
Definition: wdfregistry.h:413
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
FORCEINLINE LUID NTAPI_INLINE RtlConvertUlongToLuid(_In_ ULONG Val)
Definition: rtlfuncs.h:3558
#define TOKEN_ADJUST_PRIVILEGES
Definition: setypes.h:942
#define TOKEN_QUERY
Definition: setypes.h:940
struct _TOKEN_PRIVILEGES * PTOKEN_PRIVILEGES
#define SE_PRIVILEGE_ENABLED
Definition: setypes.h:63