2 * PROJECT: ReactOS Windows-Compatible Session Manager
3 * LICENSE: BSD 2-Clause License
4 * FILE: base/system/smss/smss.c
5 * PURPOSE: Main SMSS Code
6 * PROGRAMMERS: Alex Ionescu
9 /* INCLUDES *******************************************************************/
15 /* GLOBALS ********************************************************************/
18 // Taken from an ASSERT
20 #define VALUE_BUFFER_SIZE (sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 512)
22 typedef struct _SMP_PRIVILEGE_STATE
25 PTOKEN_PRIVILEGES OldPrivileges
;
26 PTOKEN_PRIVILEGES NewPrivileges
;
27 UCHAR OldBuffer
[1024];
28 TOKEN_PRIVILEGES NewBuffer
;
29 } SMP_PRIVILEGE_STATE
, *PSMP_PRIVILEGE_STATE
;
31 UNICODE_STRING SmpDebugKeyword
, SmpASyncKeyword
, SmpAutoChkKeyword
;
33 /* FUNCTIONS ******************************************************************/
37 SmpAcquirePrivilege(IN ULONG Privilege
,
38 OUT PVOID
*PrivilegeState
)
40 PSMP_PRIVILEGE_STATE State
;
45 *PrivilegeState
= NULL
;
47 /* Acquire the state structure to hold everything we need */
48 State
= RtlAllocateHeap(SmpHeap
,
50 sizeof(SMP_PRIVILEGE_STATE
) +
51 sizeof(TOKEN_PRIVILEGES
) +
52 sizeof(LUID_AND_ATTRIBUTES
));
53 if (!State
) return STATUS_NO_MEMORY
;
56 Status
= NtOpenProcessToken(NtCurrentProcess(),
57 TOKEN_ADJUST_PRIVILEGES
| TOKEN_QUERY
,
59 if (!NT_SUCCESS(Status
))
62 RtlFreeHeap(SmpHeap
, 0, State
);
66 /* Set one privilege in the enabled state */
67 State
->NewPrivileges
= &State
->NewBuffer
;
68 State
->OldPrivileges
= (PTOKEN_PRIVILEGES
)&State
->OldBuffer
;
69 State
->NewPrivileges
->PrivilegeCount
= 1;
70 State
->NewPrivileges
->Privileges
[0].Luid
= RtlConvertUlongToLuid(Privilege
);
71 State
->NewPrivileges
->Privileges
[0].Attributes
= SE_PRIVILEGE_ENABLED
;
73 /* Adjust the privileges in the token */
74 Size
= sizeof(State
->OldBuffer
);
75 Status
= NtAdjustPrivilegesToken(State
->TokenHandle
,
81 if (Status
== STATUS_BUFFER_TOO_SMALL
)
83 /* Our static buffer is not big enough, allocate a bigger one */
84 State
->OldPrivileges
= RtlAllocateHeap(SmpHeap
, 0, Size
);
85 if (!State
->OldPrivileges
)
87 /* Out of memory, fail */
88 Status
= STATUS_NO_MEMORY
;
93 Status
= NtAdjustPrivilegesToken(State
->TokenHandle
,
101 /* Normalize failure code and check for success */
102 if (Status
== STATUS_NOT_ALL_ASSIGNED
) Status
= STATUS_PRIVILEGE_NOT_HELD
;
103 if (NT_SUCCESS(Status
))
105 /* We got the privilege, return */
106 *PrivilegeState
= State
;
107 return STATUS_SUCCESS
;
111 /* Check if we used a dynamic buffer */
112 if (State
->OldPrivileges
!= (PTOKEN_PRIVILEGES
)&State
->OldBuffer
)
115 RtlFreeHeap(SmpHeap
, 0, State
->OldPrivileges
);
118 /* Close the token handle and free the state structure */
119 NtClose(State
->TokenHandle
);
120 RtlFreeHeap(SmpHeap
, 0, State
);
126 SmpReleasePrivilege(IN PVOID PrivState
)
128 PSMP_PRIVILEGE_STATE State
= (PSMP_PRIVILEGE_STATE
)PrivState
;
130 /* Adjust the privileges in the token */
131 NtAdjustPrivilegesToken(State
->TokenHandle
,
133 State
->OldPrivileges
,
138 /* Check if we used a dynamic buffer */
139 if (State
->OldPrivileges
!= (PTOKEN_PRIVILEGES
)&State
->OldBuffer
)
142 RtlFreeHeap(SmpHeap
, 0, State
->OldPrivileges
);
145 /* Close the token handle and free the state structure */
146 NtClose(State
->TokenHandle
);
147 RtlFreeHeap(SmpHeap
, 0, State
);
152 SmpParseToken(IN PUNICODE_STRING Input
,
153 IN BOOLEAN SecondPass
,
154 OUT PUNICODE_STRING Token
)
157 ULONG Length
, TokenLength
, InputLength
;
159 /* Initialize to NULL to start with */
160 RtlInitUnicodeString(Token
, NULL
);
162 /* Save the input length */
163 InputLength
= Input
->Length
;
165 /* Parse the buffer until the first character */
168 while (Length
< InputLength
)
170 if (*p
> L
' ' ) break;
172 Length
+= sizeof(WCHAR
);
175 /* Are we being called for argument pick-up? */
178 /* Then assume everything else is an argument */
179 TokenLength
= InputLength
- Length
* sizeof(WCHAR
);
180 pp
= (PWSTR
)((ULONG_PTR
)p
+ TokenLength
);
184 /* No -- so loop until the next space */
186 while (Length
< InputLength
)
188 if (*pp
<= L
' ' ) break;
190 Length
+= sizeof(WCHAR
);
193 /* Now compute how long this token is, and loop until the next char */
194 TokenLength
= (ULONG_PTR
)pp
- (ULONG_PTR
)p
;
195 while (Length
< InputLength
)
197 if (*pp
> L
' ' ) break;
199 Length
+= sizeof(WCHAR
);
203 /* Did we find a token? */
206 /* Allocate a buffer for it */
207 Token
->Buffer
= RtlAllocateHeap(SmpHeap
,
209 TokenLength
+ sizeof(UNICODE_NULL
));
210 if (!Token
->Buffer
) return STATUS_NO_MEMORY
;
212 /* Fill in the unicode string to hold it */
213 Token
->MaximumLength
= TokenLength
+ sizeof(UNICODE_NULL
);
214 Token
->Length
= TokenLength
;
215 RtlCopyMemory(Token
->Buffer
, p
, TokenLength
);
216 Token
->Buffer
[TokenLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
219 /* Modify the input string with the position of where the next token begins */
220 Input
->Length
-= (ULONG_PTR
)pp
- (ULONG_PTR
)Input
->Buffer
;
222 return STATUS_SUCCESS
;
227 SmpParseCommandLine(IN PUNICODE_STRING CommandLine
,
229 OUT PUNICODE_STRING FileName
,
230 OUT PUNICODE_STRING Directory
,
231 OUT PUNICODE_STRING Arguments
)
234 UNICODE_STRING EnvString
, PathString
, CmdLineCopy
, Token
;
235 WCHAR PathBuffer
[MAX_PATH
];
238 UNICODE_STRING FullPathString
;
240 /* Initialize output arguments to NULL */
241 RtlInitUnicodeString(FileName
, NULL
);
242 RtlInitUnicodeString(Arguments
, NULL
);
243 if (Directory
) RtlInitUnicodeString(Directory
, NULL
);
245 /* Check if we haven't yet built a full default path or system root yet */
246 if (!SmpSystemRoot
.Length
)
248 /* Initialize it based on shared user data string */
249 RtlInitUnicodeString(&SmpSystemRoot
, SharedUserData
->NtSystemRoot
);
251 /* Allocate an empty string for the path */
252 Length
= SmpDefaultLibPath
.MaximumLength
+ SmpSystemRoot
.MaximumLength
+
253 sizeof(L
"\\system32;");
254 RtlInitEmptyUnicodeString(&FullPathString
,
255 RtlAllocateHeap(SmpHeap
, SmBaseTag
, Length
),
257 if (FullPathString
.Buffer
)
259 /* Append the root, system32;, and then the current library path */
260 RtlAppendUnicodeStringToString(&FullPathString
, &SmpSystemRoot
);
261 RtlAppendUnicodeToString(&FullPathString
, L
"\\system32;");
262 RtlAppendUnicodeStringToString(&FullPathString
, &SmpDefaultLibPath
);
263 RtlFreeHeap(SmpHeap
, 0, SmpDefaultLibPath
.Buffer
);
264 SmpDefaultLibPath
= FullPathString
;
268 /* Consume the command line */
269 CmdLineCopy
= *CommandLine
;
272 /* Parse the first token and check for modifiers/specifiers */
273 Status
= SmpParseToken(&CmdLineCopy
, FALSE
, &Token
);
274 if (!(NT_SUCCESS(Status
)) || !(Token
.Buffer
)) return STATUS_UNSUCCESSFUL
;
277 /* Debug requested? */
278 if (RtlEqualUnicodeString(&Token
, &SmpDebugKeyword
, TRUE
))
280 /* Convert into a flag */
281 *Flags
|= SMP_DEBUG_FLAG
;
283 else if (RtlEqualUnicodeString(&Token
, &SmpASyncKeyword
, TRUE
))
285 /* Asynch requested, convert into a flag */
286 *Flags
|= SMP_ASYNC_FLAG
;
288 else if (RtlEqualUnicodeString(&Token
, &SmpAutoChkKeyword
, TRUE
))
290 /* Autochk requested, convert into a flag */
291 *Flags
|= SMP_AUTOCHK_FLAG
;
295 /* No specifier found, keep going */
299 /* Get rid of this token and get the next */
300 RtlFreeHeap(SmpHeap
, 0, Token
.Buffer
);
303 /* Initialize a string to hold the current path */
304 RtlInitUnicodeString(&EnvString
, L
"Path");
306 RtlInitEmptyUnicodeString(&PathString
,
307 RtlAllocateHeap(SmpHeap
, SmBaseTag
, Length
),
309 if (!PathString
.Buffer
)
311 /* Fail if we have no memory for this */
312 RtlFreeHeap(SmpHeap
, 0, Token
.Buffer
);
313 return STATUS_INSUFFICIENT_RESOURCES
;
316 /* Query the path from the environment */
317 Status
= RtlQueryEnvironmentVariable_U(SmpDefaultEnvironment
,
320 if (Status
== STATUS_BUFFER_TOO_SMALL
)
322 /* Our buffer was too small, free it */
323 RtlFreeHeap(SmpHeap
, 0, PathString
.Buffer
);
325 /* And allocate one big enough */
326 Length
= PathString
.Length
+ sizeof(UNICODE_NULL
);
327 RtlInitEmptyUnicodeString(&PathString
,
328 RtlAllocateHeap(SmpHeap
, SmBaseTag
, Length
),
330 if (!PathString
.Buffer
)
332 /* Fail if we have no memory for this */
333 RtlFreeHeap(SmpHeap
, 0, Token
.Buffer
);
334 return STATUS_INSUFFICIENT_RESOURCES
;
337 /* Now try again, this should work */
338 Status
= RtlQueryEnvironmentVariable_U(SmpDefaultEnvironment
,
342 if (!NT_SUCCESS(Status
))
344 /* Another failure means that the kernel hasn't passed the path correctly */
345 DPRINT1("SMSS: %wZ environment variable not defined.\n", &EnvString
);
346 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
350 /* Check if the caller expects any flags out of here */
353 /* We can return the image not found flag -- so does the image exist */
354 if (!(RtlDosSearchPath_U(PathString
.Buffer
,
360 !(RtlDosSearchPath_U(SmpDefaultLibPath
.Buffer
,
367 /* It doesn't, let the caller know about it and exit */
368 *Flags
|= SMP_INVALID_PATH
;
370 RtlFreeHeap(SmpHeap
, 0, PathString
.Buffer
);
371 return STATUS_SUCCESS
;
376 /* Caller doesn't want flags, probably wants the image itself */
377 wcscpy(PathBuffer
, Token
.Buffer
);
381 /* Free tokens and such, all that's left is to convert the image name */
382 RtlFreeHeap(SmpHeap
, 0, Token
.Buffer
);
383 RtlFreeHeap(SmpHeap
, 0, PathString
.Buffer
);
384 if (!NT_SUCCESS(Status
)) return Status
;
386 /* Convert it and bail out if this failed */
387 if (!RtlDosPathNameToNtPathName_U(PathBuffer
, FileName
, NULL
, NULL
))
389 DPRINT1("SMSS: Unable to translate %ws into an NT File Name\n",
391 Status
= STATUS_OBJECT_PATH_INVALID
;
393 if (!NT_SUCCESS(Status
)) return Status
;
395 /* Finally, check if the caller also wanted the directory */
398 /* Is the file a relative name with no directory? */
399 if (FilePart
<= PathBuffer
)
402 RtlInitUnicodeString(Directory
, NULL
);
406 /* There is a directory, and a filename -- separate those two */
407 *--FilePart
= UNICODE_NULL
;
408 RtlCreateUnicodeString(Directory
, PathBuffer
);
412 /* We are done -- move on to the second pass to get the arguments */
413 return SmpParseToken(&CmdLineCopy
, TRUE
, Arguments
);
418 SmpQueryRegistrySosOption(VOID
)
421 UNICODE_STRING KeyName
, ValueName
;
422 OBJECT_ATTRIBUTES ObjectAttributes
;
424 WCHAR ValueBuffer
[VALUE_BUFFER_SIZE
];
425 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo
= (PVOID
)ValueBuffer
;
429 RtlInitUnicodeString(&KeyName
,
430 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control");
431 InitializeObjectAttributes(&ObjectAttributes
,
433 OBJ_CASE_INSENSITIVE
,
436 Status
= NtOpenKey(&KeyHandle
, KEY_READ
, &ObjectAttributes
);
437 if (!NT_SUCCESS(Status
))
439 DPRINT1("SMSS: can't open control key: 0x%x\n", Status
);
443 /* Query the value */
444 RtlInitUnicodeString(&ValueName
, L
"SystemStartOptions");
445 Status
= NtQueryValueKey(KeyHandle
,
447 KeyValuePartialInformation
,
451 ASSERT(Length
< VALUE_BUFFER_SIZE
);
453 if (!NT_SUCCESS(Status
))
455 DPRINT1("SMSS: can't query value key: 0x%x\n", Status
);
459 /* Check if it's set to SOS or sos */
460 if (!(wcsstr((PWCHAR
)PartialInfo
->Data
, L
"SOS")) ||
461 (wcsstr((PWCHAR
)PartialInfo
->Data
, L
"sos")))
463 /* It's not set, return FALSE */
467 /* It's set, return TRUE */
473 SmpSaveAndClearBootStatusData(OUT PBOOLEAN BootOkay
,
474 OUT PBOOLEAN ShutdownOkay
)
477 BOOLEAN Value
= TRUE
;
478 PVOID BootStatusDataHandle
;
482 *ShutdownOkay
= FALSE
;
484 /* Lock the BSD and fail if we couldn't */
485 Status
= RtlLockBootStatusData(&BootStatusDataHandle
);
486 if (!NT_SUCCESS(Status
)) return FALSE
;
488 /* Read the old settings */
489 RtlGetSetBootStatusData(BootStatusDataHandle
,
495 RtlGetSetBootStatusData(BootStatusDataHandle
,
497 RtlBsdItemBootShutdown
,
502 /* Set new ones indicating we got at least this far */
503 RtlGetSetBootStatusData(BootStatusDataHandle
,
509 RtlGetSetBootStatusData(BootStatusDataHandle
,
511 RtlBsdItemBootShutdown
,
516 /* Unlock the BSD and return */
517 RtlUnlockBootStatusData(BootStatusDataHandle
);
523 SmpRestoreBootStatusData(IN BOOLEAN BootOkay
,
524 IN BOOLEAN ShutdownOkay
)
530 Status
= RtlLockBootStatusData(&BootState
);
531 if (NT_SUCCESS(Status
))
533 /* Write the bootokay and bootshudown values */
534 RtlGetSetBootStatusData(BootState
,
540 RtlGetSetBootStatusData(BootState
,
542 RtlBsdItemBootShutdown
,
544 sizeof(ShutdownOkay
),
547 /* Unlock the BSD and return */
548 RtlUnlockBootStatusData(BootState
);