/* GLOBALS ********************************************************************/
+#define STANDARD_DRIVE_LETTER_OFFSET 4
+
+#define SMP_PAGEFILE_CREATED 0x01
+#define SMP_PAGEFILE_DEFAULT 0x02
+#define SMP_PAGEFILE_SYSTEM_MANAGED 0x04
+#define SMP_PAGEFILE_WAS_TOO_BIG 0x08
+#define SMP_PAGEFILE_ON_ANY_DRIVE 0x10
+#define SMP_PAGEFILE_EMERGENCY 0x20
+#define SMP_PAGEFILE_DUMP_PROCESSED 0x40
+typedef struct _SMP_PAGEFILE_DESCRIPTOR
+{
+ LIST_ENTRY Entry;
+ UNICODE_STRING Name;
+ UNICODE_STRING Token;
+ LARGE_INTEGER MinSize;
+ LARGE_INTEGER MaxSize;
+ LARGE_INTEGER ActualMinSize;
+ LARGE_INTEGER ActualMaxSize;
+ ULONG Flags;
+} SMP_PAGEFILE_DESCRIPTOR, *PSMP_PAGEFILE_DESCRIPTOR;
+
LIST_ENTRY SmpPagingFileDescriptorList, SmpVolumeDescriptorList;
+BOOLEAN SmpRegistrySpecifierPresent;
+ULONG SmpNumberOfPagingFiles;
/* FUNCTIONS ******************************************************************/
NTAPI
SmpCreatePagingFileDescriptor(IN PUNICODE_STRING PageFileToken)
{
- DPRINT1("New pagefile data: %wZ\n", PageFileToken);
- return STATUS_SUCCESS;
+ NTSTATUS Status;
+ ULONG MinSize = 0, MaxSize = 0;
+ BOOLEAN SystemManaged = FALSE, ZeroSize = TRUE;
+ PSMP_PAGEFILE_DESCRIPTOR Descriptor, ListDescriptor;
+ ULONG i;
+ WCHAR c;
+ PWCHAR p, ArgBuffer;
+ PLIST_ENTRY NextEntry;
+ UNICODE_STRING PageFileName, Arguments;
+
+ /* Make sure we don't have too many */
+ if (SmpNumberOfPagingFiles >= 16)
+ {
+ DPRINT1("SMSS:PFILE: Too many paging files specified - %d\n",
+ SmpNumberOfPagingFiles);
+ return STATUS_TOO_MANY_PAGING_FILES;
+ }
+
+ /* Parse the specified and get the name and arguments out of it */
+ DPRINT1("SMSS:PFILE: Paging file specifier `%wZ' \n", PageFileToken);
+ Status = SmpParseCommandLine(PageFileToken,
+ NULL,
+ &PageFileName,
+ NULL,
+ &Arguments);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Fail */
+ DPRINT1("SMSS:PFILE: SmpParseCommandLine(%wZ) failed with status %X \n",
+ PageFileToken, Status);
+ return Status;
+ }
+
+ /* Set the variable to let everyone know we have a pagefile token */
+ SmpRegistrySpecifierPresent = TRUE;
+
+ /* Parse the arguments, if any */
+ if (Arguments.Buffer)
+ {
+ /* Parse the pagefile size */
+ for (i = 0; i < Arguments.Length / sizeof(WCHAR); i++)
+ {
+ /* Check if it's zero */
+ c = Arguments.Buffer[i];
+ if ((c != L' ') && (c != L'\t') && (c != L'0'))
+ {
+ /* It isn't, break out */
+ ZeroSize = FALSE;
+ break;
+ }
+ }
+ }
+
+ /* Was a pagefile not specified, or was it specified with no size? */
+ if ((Arguments.Buffer) || (ZeroSize))
+ {
+ /* In this case, the system will manage its size */
+ SystemManaged = TRUE;
+ }
+ else
+ {
+ /* We do have a size, so convert the arguments into a number */
+ Status = RtlUnicodeStringToInteger(&Arguments, 0, &MinSize);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Fail */
+ RtlFreeUnicodeString(&PageFileName);
+ RtlFreeUnicodeString(&Arguments);
+ return Status;
+ }
+
+ /* Now advance to the next argument */
+ ArgBuffer = Arguments.Buffer;
+ p = ArgBuffer;
+ while (*p++)
+ {
+ /* Which should be a space... */
+ if (*p == L' ')
+ {
+ /* And use the rest of the arguments as a maximum size */
+ Arguments.Length -= ((PCHAR)p - (PCHAR)ArgBuffer);
+ Arguments.Buffer = ArgBuffer;
+ Status = RtlUnicodeStringToInteger(&Arguments, 0, &MaxSize);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Fail */
+ RtlFreeUnicodeString(&PageFileName);
+ RtlFreeUnicodeString(&Arguments);
+ return Status;
+ }
+
+ /* We have both min and max, restore argument buffer */
+ Arguments.Buffer = ArgBuffer; // Actual Windows Bug in faillure case above.
+ break;
+ }
+ }
+ }
+
+ /* We are done parsing arguments */
+ RtlFreeUnicodeString(&Arguments);
+
+ /* Now we can allocate our descriptor */
+ Descriptor = RtlAllocateHeap(RtlGetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ sizeof(SMP_PAGEFILE_DESCRIPTOR));
+ if (!Descriptor)
+ {
+ /* Fail if we couldn't */
+ RtlFreeUnicodeString(&PageFileName);
+ return STATUS_NO_MEMORY;
+ }
+
+ /* Capture all our data into the descriptor */
+ Descriptor->Token = *PageFileToken;
+ Descriptor->Name = PageFileName;
+ Descriptor->MinSize.QuadPart = MinSize * 0x100000;
+ Descriptor->MaxSize.QuadPart = MaxSize * 0x100000;
+ if (SystemManaged) Descriptor->Flags |= SMP_PAGEFILE_SYSTEM_MANAGED;
+ Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET] =
+ RtlUpcaseUnicodeChar(Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET]);
+ if (Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET] == '?')
+ {
+ Descriptor->Flags |= SMP_PAGEFILE_ON_ANY_DRIVE;
+ }
+
+ /* Now loop the existing descriptors */
+ NextEntry = SmpPagingFileDescriptorList.Flink;
+ do
+ {
+ /* Are there none, or have we looped back to the beginning? */
+ if (NextEntry == &SmpPagingFileDescriptorList)
+ {
+ /* This means no duplicates exist, so insert our descriptor! */
+ InsertTailList(&SmpPagingFileDescriptorList, &Descriptor->Entry);
+ SmpNumberOfPagingFiles++;
+ DPRINT1("SMSS:PFILE: Created descriptor for `%wZ' (`%wZ') \n",
+ PageFileToken, &Descriptor->Name);
+ return STATUS_SUCCESS;
+ }
+
+ /* Keep going until we find a duplicate, unless we are in "any" mode */
+ ListDescriptor = CONTAINING_RECORD(NextEntry, SMP_PAGEFILE_DESCRIPTOR, Entry);
+ NextEntry = NextEntry->Flink;
+ } while (!(ListDescriptor->Flags & SMP_PAGEFILE_ON_ANY_DRIVE) ||
+ !(Descriptor->Flags & SMP_PAGEFILE_ON_ANY_DRIVE));
+
+ /* We found a duplicate, so skip this descriptor/pagefile and fail */
+ DPRINT1("SMSS:PFILE: Skipping duplicate specifier `%wZ' \n", PageFileToken);
+ RtlFreeUnicodeString(&PageFileName);
+ RtlFreeHeap(RtlGetProcessHeap(), 0, Descriptor);
+ return STATUS_INVALID_PARAMETER;
}
NTSTATUS
TOKEN_PRIVILEGES NewBuffer;
} SMP_PRIVILEGE_STATE, *PSMP_PRIVILEGE_STATE;
+UNICODE_STRING SmpDebugKeyword, SmpASyncKeyword, SmpAutoChkKeyword;
+
/* FUNCTIONS ******************************************************************/
NTSTATUS
/* Assume failure */
*PrivilegeState = NULL;
-
+
/* Acquire the state structure to hold everything we need */
- State = RtlAllocateHeap(RtlGetProcessHeap(),
+ State = RtlAllocateHeap(SmpHeap,
0,
sizeof(SMP_PRIVILEGE_STATE) +
sizeof(TOKEN_PRIVILEGES) +
if (!NT_SUCCESS(Status))
{
/* Fail */
- RtlFreeHeap(RtlGetProcessHeap(), 0, State);
+ RtlFreeHeap(SmpHeap, 0, State);
return Status;
}
if (Status == STATUS_BUFFER_TOO_SMALL)
{
/* Our static buffer is not big enough, allocate a bigger one */
- State->OldPrivileges = RtlAllocateHeap(RtlGetProcessHeap(), 0, Size);
+ State->OldPrivileges = RtlAllocateHeap(SmpHeap, 0, Size);
if (!State->OldPrivileges)
{
/* Out of memory, fail */
if (State->OldPrivileges != (PTOKEN_PRIVILEGES)&State->OldBuffer)
{
/* Free it */
- RtlFreeHeap(RtlGetProcessHeap(), 0, State->OldPrivileges);
+ RtlFreeHeap(SmpHeap, 0, State->OldPrivileges);
}
/* Close the token handle and free the state structure */
NtClose(State->TokenHandle);
- RtlFreeHeap(RtlGetProcessHeap(), 0, State);
+ RtlFreeHeap(SmpHeap, 0, State);
return Status;
}
SmpReleasePrivilege(IN PVOID PrivState)
{
PSMP_PRIVILEGE_STATE State = (PSMP_PRIVILEGE_STATE)PrivState;
-
+
/* Adjust the privileges in the token */
NtAdjustPrivilegesToken(State->TokenHandle,
FALSE,
if (State->OldPrivileges != (PTOKEN_PRIVILEGES)&State->OldBuffer)
{
/* Free it */
- RtlFreeHeap(RtlGetProcessHeap(), 0, State->OldPrivileges);
+ RtlFreeHeap(SmpHeap, 0, State->OldPrivileges);
}
/* Close the token handle and free the state structure */
NtClose(State->TokenHandle);
- RtlFreeHeap(RtlGetProcessHeap(), 0, State);
+ RtlFreeHeap(SmpHeap, 0, State);
+}
+
+NTSTATUS
+NTAPI
+SmpParseToken(IN PUNICODE_STRING Input,
+ IN BOOLEAN SecondPass,
+ OUT PUNICODE_STRING Token)
+{
+ PWCHAR p, pp;
+ ULONG Length, TokenLength, InputLength;
+
+ /* Initialize to NULL to start with */
+ RtlInitUnicodeString(Token, NULL);
+
+ /* Save the input length */
+ InputLength = Input->Length;
+
+ /* Parse the buffer until the first character */
+ p = Input->Buffer;
+ Length = 0;
+ while (Length < InputLength)
+ {
+ if (*p > L' ' ) break;
+ ++p;
+ Length += sizeof(WCHAR);
+ }
+
+ /* Are we being called for argument pick-up? */
+ if (SecondPass)
+ {
+ /* Then assume everything else is an argument */
+ TokenLength = InputLength - Length * sizeof(WCHAR);
+ pp = (PWSTR)((ULONG_PTR)p + TokenLength);
+ }
+ else
+ {
+ /* No -- so loop until the next space */
+ pp = p;
+ while (Length < InputLength)
+ {
+ if (*pp <= L' ' ) break;
+ ++pp;
+ Length += sizeof(WCHAR);
+ }
+
+ /* Now compute how long this token is, and loop until the next char */
+ TokenLength = (ULONG_PTR)pp - (ULONG_PTR)p;
+ while (Length < InputLength)
+ {
+ if (*pp > L' ' ) break;
+ ++pp;
+ Length += sizeof(WCHAR);
+ }
+ }
+
+ /* Did we find a token? */
+ if (TokenLength)
+ {
+ /* Allocate a buffer for it */
+ Token->Buffer = RtlAllocateHeap(SmpHeap,
+ SmBaseTag,
+ TokenLength + sizeof(UNICODE_NULL));
+ if (!Token->Buffer) return STATUS_NO_MEMORY;
+
+ /* Fill in the unicode string to hold it */
+ Token->MaximumLength = TokenLength + sizeof(UNICODE_NULL);
+ Token->Length = TokenLength;
+ RtlCopyMemory(Token->Buffer, p, TokenLength);
+ Token->Buffer[TokenLength / sizeof(WCHAR)] = UNICODE_NULL;
+ }
+
+ /* Modify the input string with the position of where the next token begins */
+ Input->Length -= (ULONG_PTR)pp - (ULONG_PTR)Input->Buffer;
+ Input->Buffer = pp;
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+SmpParseCommandLine(IN PUNICODE_STRING CommandLine,
+ OUT PULONG Flags,
+ OUT PUNICODE_STRING FileName,
+ OUT PUNICODE_STRING Directory,
+ OUT PUNICODE_STRING Arguments)
+{
+ ULONG Length;
+ UNICODE_STRING EnvString, PathString, CmdLineCopy, Token;
+ WCHAR PathBuffer[MAX_PATH];
+ PWCHAR FilePart;
+ NTSTATUS Status;
+ UNICODE_STRING FullPathString;
+
+ /* Initialize output arguments to NULL */
+ RtlInitUnicodeString(FileName, NULL);
+ RtlInitUnicodeString(Arguments, NULL);
+ if (Directory) RtlInitUnicodeString(Directory, NULL);
+
+ /* Check if we haven't yet built a full default path or system root yet */
+ if (!SmpSystemRoot.Length)
+ {
+ /* Initialize it based on shared user data string */
+ RtlInitUnicodeString(&SmpSystemRoot, SharedUserData->NtSystemRoot);
+
+ /* Allocate an empty string for the path */
+ Length = SmpDefaultLibPath.MaximumLength + SmpSystemRoot.MaximumLength +
+ sizeof(L"\\system32;");
+ RtlInitEmptyUnicodeString(&FullPathString,
+ RtlAllocateHeap(SmpHeap, SmBaseTag, Length),
+ Length);
+ if (FullPathString.Buffer)
+ {
+ /* Append the root, system32;, and then the current library path */
+ RtlAppendUnicodeStringToString(&FullPathString, &SmpSystemRoot);
+ RtlAppendUnicodeToString(&FullPathString, L"\\system32;");
+ RtlAppendUnicodeStringToString(&FullPathString, &SmpDefaultLibPath);
+ RtlFreeHeap(SmpHeap, 0, SmpDefaultLibPath.Buffer);
+ SmpDefaultLibPath = FullPathString;
+ }
+ }
+
+ /* Consume the command line */
+ CmdLineCopy = *CommandLine;
+ while (TRUE)
+ {
+ /* Parse the first token and check for modifiers/specifiers */
+ Status = SmpParseToken(&CmdLineCopy, FALSE, &Token);
+ if (!(NT_SUCCESS(Status)) || !(Token.Buffer)) return STATUS_UNSUCCESSFUL;
+ if (!Flags) break;
+
+ /* Debug requested? */
+ if (RtlEqualUnicodeString(&Token, &SmpDebugKeyword, TRUE))
+ {
+ /* Convert into a flag */
+ *Flags |= SMP_DEBUG_FLAG;
+ }
+ else if (RtlEqualUnicodeString(&Token, &SmpASyncKeyword, TRUE))
+ {
+ /* Asynch requested, convert into a flag */
+ *Flags |= SMP_ASYNC_FLAG;
+ }
+ else if (RtlEqualUnicodeString(&Token, &SmpAutoChkKeyword, TRUE))
+ {
+ /* Autochk requested, convert into a flag */
+ *Flags |= SMP_AUTOCHK_FLAG;
+ }
+ else
+ {
+ /* No specifier found, keep going */
+ break;
+ }
+
+ /* Get rid of this token and get the next */
+ RtlFreeHeap(SmpHeap, 0, Token.Buffer);
+ }
+
+ /* Initialize a string to hold the current path */
+ RtlInitUnicodeString(&EnvString, L"Path");
+ Length = PAGE_SIZE;
+ RtlInitEmptyUnicodeString(&PathString,
+ RtlAllocateHeap(SmpHeap, SmBaseTag, Length),
+ Length);
+ if (!PathString.Buffer)
+ {
+ /* Fail if we have no memory for this */
+ RtlFreeHeap(SmpHeap, 0, Token.Buffer);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ /* Query the path from the environment */
+ Status = RtlQueryEnvironmentVariable_U(SmpDefaultEnvironment,
+ &EnvString,
+ &PathString);
+ if (Status == STATUS_BUFFER_TOO_SMALL)
+ {
+ /* Our buffer was too small, free it */
+ RtlFreeHeap(SmpHeap, 0, PathString.Buffer);
+
+ /* And allocate one big enough */
+ Length = PathString.Length + sizeof(UNICODE_NULL);
+ RtlInitEmptyUnicodeString(&PathString,
+ RtlAllocateHeap(SmpHeap, SmBaseTag, Length),
+ Length);
+ if (!PathString.Buffer)
+ {
+ /* Fail if we have no memory for this */
+ RtlFreeHeap(SmpHeap, 0, Token.Buffer);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ /* Now try again, this should work */
+ Status = RtlQueryEnvironmentVariable_U(SmpDefaultEnvironment,
+ &EnvString,
+ &PathString);
+ }
+ if (!NT_SUCCESS(Status))
+ {
+ /* Another failure means that the kernel hasn't passed the path correctly */
+ DPRINT1("SMSS: %wZ environment variable not defined.\n", &EnvString);
+ Status = STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+ else
+ {
+ /* Check if the caller expects any flags out of here */
+ if (Flags)
+ {
+ /* We can return the image not found flag -- so does the image exist */
+ if (!(RtlDosSearchPath_U(PathString.Buffer,
+ Token.Buffer,
+ L".exe",
+ sizeof(PathBuffer),
+ PathBuffer,
+ &FilePart)) &&
+ !(RtlDosSearchPath_U(SmpDefaultLibPath.Buffer,
+ Token.Buffer,
+ L".exe",
+ sizeof(PathBuffer),
+ PathBuffer,
+ &FilePart)))
+ {
+ /* It doesn't, let the caller know about it and exit */
+ *Flags |= SMP_INVALID_PATH;
+ *FileName = Token;
+ RtlFreeHeap(SmpHeap, 0, PathString.Buffer);
+ return STATUS_SUCCESS;
+ }
+ }
+ else
+ {
+ /* Caller doesn't want flags, probably wants the image itself */
+ wcscpy(PathBuffer, Token.Buffer);
+ }
+ }
+
+ /* Free tokens and such, all that's left is to convert the image name */
+ RtlFreeHeap(SmpHeap, 0, Token.Buffer);
+ RtlFreeHeap(SmpHeap, 0, PathString.Buffer);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Convert it and bail out if this failed */
+ if (!RtlDosPathNameToNtPathName_U(PathBuffer, FileName, NULL, NULL))
+ {
+ DPRINT1("SMSS: Unable to translate %ws into an NT File Name\n",
+ &PathBuffer);
+ Status = STATUS_OBJECT_PATH_INVALID;
+ }
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Finally, check if the caller also wanted the directory */
+ if (Directory)
+ {
+ /* Is the file a relative name with no directory? */
+ if (FilePart <= PathBuffer)
+ {
+ /* Clear it */
+ RtlInitUnicodeString(Directory, NULL);
+ }
+ else
+ {
+ /* There is a directory, and a filename -- separate those two */
+ FilePart -= sizeof(UNICODE_NULL);
+ *FilePart = UNICODE_NULL;
+ RtlCreateUnicodeString(Directory, PathBuffer);
+ }
+ }
+
+ /* We are done -- move on to the second pass to get the arguments */
+ return SmpParseToken(&CmdLineCopy, TRUE, Arguments);
}