ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

smutil.c
Go to the documentation of this file.
00001 /*
00002  * PROJECT:         ReactOS Windows-Compatible Session Manager
00003  * LICENSE:         BSD 2-Clause License
00004  * FILE:            base/system/smss/smss.c
00005  * PURPOSE:         Main SMSS Code
00006  * PROGRAMMERS:     Alex Ionescu
00007  */
00008 
00009 /* INCLUDES *******************************************************************/
00010 
00011 #include "smss.h"
00012 #define NDEBUG
00013 #include "debug.h"
00014 
00015 /* GLOBALS ********************************************************************/
00016 
00017 //
00018 // Taken from an ASSERT
00019 //
00020 #define VALUE_BUFFER_SIZE (sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 512)
00021 
00022 typedef struct _SMP_PRIVILEGE_STATE
00023 {
00024     HANDLE TokenHandle;
00025     PTOKEN_PRIVILEGES OldPrivileges;
00026     PTOKEN_PRIVILEGES NewPrivileges;
00027     UCHAR OldBuffer[1024];
00028     TOKEN_PRIVILEGES NewBuffer;
00029 } SMP_PRIVILEGE_STATE, *PSMP_PRIVILEGE_STATE;
00030 
00031 UNICODE_STRING SmpDebugKeyword, SmpASyncKeyword, SmpAutoChkKeyword;
00032 
00033 /* FUNCTIONS ******************************************************************/
00034 
00035 NTSTATUS
00036 NTAPI
00037 SmpAcquirePrivilege(IN ULONG Privilege,
00038                     OUT PVOID *PrivilegeState)
00039 {
00040     PSMP_PRIVILEGE_STATE State;
00041     ULONG Size;
00042     NTSTATUS Status;
00043 
00044     /* Assume failure */
00045     *PrivilegeState = NULL;
00046 
00047     /* Acquire the state structure to hold everything we need */
00048     State = RtlAllocateHeap(SmpHeap,
00049                             0,
00050                             sizeof(SMP_PRIVILEGE_STATE) +
00051                             sizeof(TOKEN_PRIVILEGES) +
00052                             sizeof(LUID_AND_ATTRIBUTES));
00053     if (!State) return STATUS_NO_MEMORY;
00054 
00055     /* Open our token */
00056     Status = NtOpenProcessToken(NtCurrentProcess(),
00057                                 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
00058                                 &State->TokenHandle);
00059     if (!NT_SUCCESS(Status))
00060     {
00061         /* Fail */
00062         RtlFreeHeap(SmpHeap, 0, State);
00063         return Status;
00064     }
00065 
00066     /* Set one privilege in the enabled state */
00067     State->NewPrivileges = &State->NewBuffer;
00068     State->OldPrivileges = (PTOKEN_PRIVILEGES)&State->OldBuffer;
00069     State->NewPrivileges->PrivilegeCount = 1;
00070     State->NewPrivileges->Privileges[0].Luid = RtlConvertUlongToLuid(Privilege);
00071     State->NewPrivileges->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
00072 
00073     /* Adjust the privileges in the token */
00074     Size = sizeof(State->OldBuffer);
00075     Status = NtAdjustPrivilegesToken(State->TokenHandle,
00076                                      FALSE,
00077                                      State->NewPrivileges,
00078                                      Size,
00079                                      State->OldPrivileges,
00080                                      &Size);
00081     if (Status == STATUS_BUFFER_TOO_SMALL)
00082     {
00083         /* Our static buffer is not big enough, allocate a bigger one */
00084         State->OldPrivileges = RtlAllocateHeap(SmpHeap, 0, Size);
00085         if (!State->OldPrivileges)
00086         {
00087             /* Out of memory, fail */
00088             Status = STATUS_NO_MEMORY;
00089             goto Quickie;
00090         }
00091 
00092         /* Now try again */
00093         Status = NtAdjustPrivilegesToken(State->TokenHandle,
00094                                          FALSE,
00095                                          State->NewPrivileges,
00096                                          Size,
00097                                          State->OldPrivileges,
00098                                          &Size);
00099     }
00100 
00101     /* Normalize failure code and check for success */
00102     if (Status == STATUS_NOT_ALL_ASSIGNED) Status = STATUS_PRIVILEGE_NOT_HELD;
00103     if (NT_SUCCESS(Status))
00104     {
00105         /* We got the privilege, return */
00106         *PrivilegeState = State;
00107         return STATUS_SUCCESS;
00108     }
00109 
00110 Quickie:
00111     /* Check if we used a dynamic buffer */
00112     if (State->OldPrivileges != (PTOKEN_PRIVILEGES)&State->OldBuffer)
00113     {
00114         /* Free it */
00115         RtlFreeHeap(SmpHeap, 0, State->OldPrivileges);
00116     }
00117 
00118     /* Close the token handle and free the state structure */
00119     NtClose(State->TokenHandle);
00120     RtlFreeHeap(SmpHeap, 0, State);
00121     return Status;
00122 }
00123 
00124 VOID
00125 NTAPI
00126 SmpReleasePrivilege(IN PVOID PrivState)
00127 {
00128     PSMP_PRIVILEGE_STATE State = (PSMP_PRIVILEGE_STATE)PrivState;
00129 
00130     /* Adjust the privileges in the token */
00131     NtAdjustPrivilegesToken(State->TokenHandle,
00132                             FALSE,
00133                             State->OldPrivileges,
00134                             0,
00135                             NULL,
00136                             NULL);
00137 
00138     /* Check if we used a dynamic buffer */
00139     if (State->OldPrivileges != (PTOKEN_PRIVILEGES)&State->OldBuffer)
00140     {
00141         /* Free it */
00142         RtlFreeHeap(SmpHeap, 0, State->OldPrivileges);
00143     }
00144 
00145     /* Close the token handle and free the state structure */
00146     NtClose(State->TokenHandle);
00147     RtlFreeHeap(SmpHeap, 0, State);
00148 }
00149 
00150 NTSTATUS
00151 NTAPI
00152 SmpParseToken(IN PUNICODE_STRING Input,
00153               IN BOOLEAN SecondPass,
00154               OUT PUNICODE_STRING Token)
00155 {
00156     PWCHAR p, pp;
00157     ULONG Length, TokenLength, InputLength;
00158 
00159     /* Initialize to NULL to start with */
00160     RtlInitUnicodeString(Token, NULL);
00161 
00162     /* Save the input length */
00163     InputLength = Input->Length;
00164 
00165     /* Parse the buffer until the first character */
00166     p = Input->Buffer;
00167     Length = 0;
00168     while (Length < InputLength)
00169     {
00170         if (*p > L' ' ) break;
00171         ++p;
00172         Length += sizeof(WCHAR);
00173     }
00174 
00175     /* Are we being called for argument pick-up? */
00176     if (SecondPass)
00177     {
00178         /* Then assume everything else is an argument */
00179         TokenLength = InputLength - Length * sizeof(WCHAR);
00180         pp = (PWSTR)((ULONG_PTR)p + TokenLength);
00181     }
00182     else
00183     {
00184         /* No -- so loop until the next space */
00185         pp = p;
00186         while (Length < InputLength)
00187         {
00188             if (*pp <= L' ' ) break;
00189             ++pp;
00190             Length += sizeof(WCHAR);
00191         }
00192 
00193         /* Now compute how long this token is, and loop until the next char */
00194         TokenLength = (ULONG_PTR)pp - (ULONG_PTR)p;
00195         while (Length < InputLength)
00196         {
00197             if (*pp > L' ' ) break;
00198             ++pp;
00199             Length += sizeof(WCHAR);
00200         }
00201     }
00202 
00203     /* Did we find a token? */
00204     if (TokenLength)
00205     {
00206         /* Allocate a buffer for it */
00207         Token->Buffer = RtlAllocateHeap(SmpHeap,
00208                                         SmBaseTag,
00209                                         TokenLength + sizeof(UNICODE_NULL));
00210         if (!Token->Buffer) return STATUS_NO_MEMORY;
00211 
00212         /* Fill in the unicode string to hold it */
00213         Token->MaximumLength = TokenLength + sizeof(UNICODE_NULL);
00214         Token->Length = TokenLength;
00215         RtlCopyMemory(Token->Buffer, p, TokenLength);
00216         Token->Buffer[TokenLength / sizeof(WCHAR)] = UNICODE_NULL;
00217     }
00218 
00219     /* Modify the input string with the position of where the next token begins */
00220     Input->Length -= (ULONG_PTR)pp - (ULONG_PTR)Input->Buffer;
00221     Input->Buffer = pp;
00222     return STATUS_SUCCESS;
00223 }
00224 
00225 NTSTATUS
00226 NTAPI
00227 SmpParseCommandLine(IN PUNICODE_STRING CommandLine,
00228                     OUT PULONG Flags,
00229                     OUT PUNICODE_STRING FileName,
00230                     OUT PUNICODE_STRING Directory,
00231                     OUT PUNICODE_STRING Arguments)
00232 {
00233     ULONG Length;
00234     UNICODE_STRING EnvString, PathString, CmdLineCopy, Token;
00235     WCHAR PathBuffer[MAX_PATH];
00236     PWCHAR FilePart;
00237     NTSTATUS Status;
00238     UNICODE_STRING FullPathString;
00239 
00240     /* Initialize output arguments to NULL */
00241     RtlInitUnicodeString(FileName, NULL);
00242     RtlInitUnicodeString(Arguments, NULL);
00243     if (Directory) RtlInitUnicodeString(Directory, NULL);
00244 
00245     /* Check if we haven't yet built a full default path or system root yet */
00246     if (!SmpSystemRoot.Length)
00247     {
00248         /* Initialize it based on shared user data string */
00249         RtlInitUnicodeString(&SmpSystemRoot, SharedUserData->NtSystemRoot);
00250 
00251         /* Allocate an empty string for the path */
00252         Length = SmpDefaultLibPath.MaximumLength + SmpSystemRoot.MaximumLength +
00253                  sizeof(L"\\system32;");
00254         RtlInitEmptyUnicodeString(&FullPathString,
00255                                   RtlAllocateHeap(SmpHeap, SmBaseTag, Length),
00256                                   Length);
00257         if (FullPathString.Buffer)
00258         {
00259             /* Append the root, system32;, and then the current library path */
00260             RtlAppendUnicodeStringToString(&FullPathString, &SmpSystemRoot);
00261             RtlAppendUnicodeToString(&FullPathString, L"\\system32;");
00262             RtlAppendUnicodeStringToString(&FullPathString, &SmpDefaultLibPath);
00263             RtlFreeHeap(SmpHeap, 0, SmpDefaultLibPath.Buffer);
00264             SmpDefaultLibPath = FullPathString;
00265         }
00266     }
00267 
00268     /* Consume the command line */
00269     CmdLineCopy = *CommandLine;
00270     while (TRUE)
00271     {
00272         /* Parse the first token and check for modifiers/specifiers */
00273         Status = SmpParseToken(&CmdLineCopy, FALSE, &Token);
00274         if (!(NT_SUCCESS(Status)) || !(Token.Buffer)) return STATUS_UNSUCCESSFUL;
00275         if (!Flags) break;
00276 
00277         /* Debug requested? */
00278         if (RtlEqualUnicodeString(&Token, &SmpDebugKeyword, TRUE))
00279         {
00280             /* Convert into a flag */
00281             *Flags |= SMP_DEBUG_FLAG;
00282         }
00283         else if (RtlEqualUnicodeString(&Token, &SmpASyncKeyword, TRUE))
00284         {
00285             /* Asynch requested, convert into a flag */
00286             *Flags |= SMP_ASYNC_FLAG;
00287         }
00288         else if (RtlEqualUnicodeString(&Token, &SmpAutoChkKeyword, TRUE))
00289         {
00290             /* Autochk requested, convert into a flag */
00291             *Flags |= SMP_AUTOCHK_FLAG;
00292         }
00293         else
00294         {
00295             /* No specifier found, keep going */
00296             break;
00297         }
00298 
00299         /* Get rid of this token and get the next */
00300         RtlFreeHeap(SmpHeap, 0, Token.Buffer);
00301     }
00302 
00303     /* Initialize a string to hold the current path */
00304     RtlInitUnicodeString(&EnvString, L"Path");
00305     Length = PAGE_SIZE;
00306     RtlInitEmptyUnicodeString(&PathString,
00307                               RtlAllocateHeap(SmpHeap, SmBaseTag, Length),
00308                               Length);
00309     if (!PathString.Buffer)
00310     {
00311         /* Fail if we have no memory for this */
00312         RtlFreeHeap(SmpHeap, 0, Token.Buffer);
00313         return STATUS_INSUFFICIENT_RESOURCES;
00314     }
00315 
00316     /* Query the path from the environment */
00317     Status = RtlQueryEnvironmentVariable_U(SmpDefaultEnvironment,
00318                                            &EnvString,
00319                                            &PathString);
00320     if (Status == STATUS_BUFFER_TOO_SMALL)
00321     {
00322         /* Our buffer was too small, free it */
00323         RtlFreeHeap(SmpHeap, 0, PathString.Buffer);
00324 
00325         /* And allocate one big enough */
00326         Length = PathString.Length + sizeof(UNICODE_NULL);
00327         RtlInitEmptyUnicodeString(&PathString,
00328                                   RtlAllocateHeap(SmpHeap, SmBaseTag, Length),
00329                                   Length);
00330         if (!PathString.Buffer)
00331         {
00332             /* Fail if we have no memory for this */
00333             RtlFreeHeap(SmpHeap, 0, Token.Buffer);
00334             return STATUS_INSUFFICIENT_RESOURCES;
00335         }
00336 
00337         /* Now try again, this should work */
00338         Status = RtlQueryEnvironmentVariable_U(SmpDefaultEnvironment,
00339                                                &EnvString,
00340                                                &PathString);
00341     }
00342     if (!NT_SUCCESS(Status))
00343     {
00344         /* Another failure means that the kernel hasn't passed the path correctly */
00345         DPRINT1("SMSS: %wZ environment variable not defined.\n", &EnvString);
00346         Status = STATUS_OBJECT_NAME_NOT_FOUND;
00347     }
00348     else
00349     {
00350         /* Check if the caller expects any flags out of here */
00351         if (Flags)
00352         {
00353             /* We can return the image not found flag -- so does the image exist */
00354             if (!(RtlDosSearchPath_U(PathString.Buffer,
00355                                      Token.Buffer,
00356                                      L".exe",
00357                                      sizeof(PathBuffer),
00358                                      PathBuffer,
00359                                      &FilePart)) &&
00360                 !(RtlDosSearchPath_U(SmpDefaultLibPath.Buffer,
00361                                      Token.Buffer,
00362                                      L".exe",
00363                                      sizeof(PathBuffer),
00364                                      PathBuffer,
00365                                      &FilePart)))
00366             {
00367                 /* It doesn't, let the caller know about it and exit */
00368                 *Flags |= SMP_INVALID_PATH;
00369                 *FileName = Token;
00370                 RtlFreeHeap(SmpHeap, 0, PathString.Buffer);
00371                 return STATUS_SUCCESS;
00372             }
00373         }
00374         else
00375         {
00376             /* Caller doesn't want flags, probably wants the image itself */
00377             wcscpy(PathBuffer, Token.Buffer);
00378         }
00379     }
00380 
00381     /* Free tokens and such, all that's left is to convert the image name */
00382     RtlFreeHeap(SmpHeap, 0, Token.Buffer);
00383     RtlFreeHeap(SmpHeap, 0, PathString.Buffer);
00384     if (!NT_SUCCESS(Status)) return Status;
00385 
00386     /* Convert it and bail out if this failed */
00387     if (!RtlDosPathNameToNtPathName_U(PathBuffer, FileName, NULL, NULL))
00388     {
00389         DPRINT1("SMSS: Unable to translate %ws into an NT File Name\n",
00390                 &PathBuffer);
00391         Status = STATUS_OBJECT_PATH_INVALID;
00392     }
00393     if (!NT_SUCCESS(Status)) return Status;
00394 
00395     /* Finally, check if the caller also wanted the directory */
00396     if (Directory)
00397     {
00398         /* Is the file a relative name with no directory? */
00399         if (FilePart <= PathBuffer)
00400         {
00401             /* Clear it */
00402             RtlInitUnicodeString(Directory, NULL);
00403         }
00404         else
00405         {
00406             /* There is a directory, and a filename -- separate those two */
00407             *--FilePart = UNICODE_NULL;
00408             RtlCreateUnicodeString(Directory, PathBuffer);
00409         }
00410     }
00411 
00412     /* We are done -- move on to the second pass to get the arguments */
00413     return SmpParseToken(&CmdLineCopy, TRUE, Arguments);
00414 }
00415 
00416 BOOLEAN
00417 NTAPI
00418 SmpQueryRegistrySosOption(VOID)
00419 {
00420     NTSTATUS Status;
00421     UNICODE_STRING KeyName, ValueName;
00422     OBJECT_ATTRIBUTES ObjectAttributes;
00423     HANDLE KeyHandle;
00424     WCHAR ValueBuffer[VALUE_BUFFER_SIZE];
00425     PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = (PVOID)ValueBuffer;
00426     ULONG Length;
00427 
00428     /* Open the key */
00429     RtlInitUnicodeString(&KeyName,
00430                          L"\\Registry\\Machine\\System\\CurrentControlSet\\Control");
00431     InitializeObjectAttributes(&ObjectAttributes,
00432                                &KeyName,
00433                                OBJ_CASE_INSENSITIVE,
00434                                NULL,
00435                                NULL);
00436     Status = NtOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
00437     if (!NT_SUCCESS(Status))
00438     {
00439         DPRINT1("SMSS: can't open control key: 0x%x\n", Status);
00440         return FALSE;
00441     }
00442 
00443     /* Query the value */
00444     RtlInitUnicodeString(&ValueName, L"SystemStartOptions");
00445     Status = NtQueryValueKey(KeyHandle,
00446                              &ValueName,
00447                              KeyValuePartialInformation,
00448                              PartialInfo,
00449                              sizeof(ValueBuffer),
00450                              &Length);
00451     ASSERT(Length < VALUE_BUFFER_SIZE);
00452     NtClose(KeyHandle);
00453     if (!NT_SUCCESS(Status))
00454     {
00455         DPRINT1("SMSS: can't query value key: 0x%x\n", Status);
00456         return FALSE;
00457     }
00458 
00459     /* Check if it's set to SOS or sos */
00460     if (!(wcsstr((PWCHAR)PartialInfo->Data, L"SOS")) ||
00461          (wcsstr((PWCHAR)PartialInfo->Data, L"sos")))
00462     {
00463         /* It's not set, return FALSE */
00464         return FALSE;
00465     }
00466 
00467     /* It's set, return TRUE */
00468     return TRUE;
00469 }
00470 
00471 BOOLEAN
00472 NTAPI
00473 SmpSaveAndClearBootStatusData(OUT PBOOLEAN BootOkay,
00474                               OUT PBOOLEAN ShutdownOkay)
00475 {
00476     NTSTATUS Status;
00477     BOOLEAN Value = TRUE;
00478     PVOID BootStatusDataHandle;
00479 
00480     /* Assume failure */
00481     *BootOkay = FALSE;
00482     *ShutdownOkay = FALSE;
00483 
00484     /* Lock the BSD and fail if we couldn't */
00485     Status = RtlLockBootStatusData(&BootStatusDataHandle);
00486     if (!NT_SUCCESS(Status)) return FALSE;
00487 
00488     /* Read the old settings */
00489     RtlGetSetBootStatusData(BootStatusDataHandle,
00490                             TRUE,
00491                             RtlBsdItemBootGood,
00492                             BootOkay,
00493                             sizeof(BOOLEAN),
00494                             NULL);
00495     RtlGetSetBootStatusData(BootStatusDataHandle,
00496                             TRUE,
00497                             RtlBsdItemBootShutdown,
00498                             ShutdownOkay,
00499                             sizeof(BOOLEAN),
00500                             NULL);
00501 
00502     /* Set new ones indicating we got at least this far */
00503     RtlGetSetBootStatusData(BootStatusDataHandle,
00504                             FALSE,
00505                             RtlBsdItemBootGood,
00506                             &Value,
00507                             sizeof(Value),
00508                             NULL);
00509     RtlGetSetBootStatusData(BootStatusDataHandle,
00510                             FALSE,
00511                             RtlBsdItemBootShutdown,
00512                             &Value,
00513                             sizeof(Value),
00514                             NULL);
00515 
00516     /* Unlock the BSD and return */
00517     RtlUnlockBootStatusData(BootStatusDataHandle);
00518     return TRUE;
00519 }
00520 
00521 VOID
00522 NTAPI
00523 SmpRestoreBootStatusData(IN BOOLEAN BootOkay,
00524                          IN BOOLEAN ShutdownOkay)
00525 {
00526     NTSTATUS Status;
00527     PVOID BootState;
00528 
00529     /* Lock the BSD */
00530     Status = RtlLockBootStatusData(&BootState);
00531     if (NT_SUCCESS(Status))
00532     {
00533         /* Write the bootokay and bootshudown values */
00534         RtlGetSetBootStatusData(BootState,
00535                                 FALSE,
00536                                 RtlBsdItemBootGood,
00537                                 &BootOkay,
00538                                 sizeof(BootOkay),
00539                                 NULL);
00540         RtlGetSetBootStatusData(BootState,
00541                                 FALSE,
00542                                 RtlBsdItemBootShutdown,
00543                                 &ShutdownOkay,
00544                                 sizeof(ShutdownOkay),
00545                                 NULL);
00546 
00547         /* Unlock the BSD and return */
00548         RtlUnlockBootStatusData(BootState);
00549     }
00550 }

Generated on Sun May 27 2012 04:18:53 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.