-/* $Id$\r
- *\r
- * smapiexec.c - SM_API_EXECUTE_PROGRAM\r
- *\r
- * Reactos Session Manager\r
- *\r
- * --------------------------------------------------------------------\r
- *\r
- * This software is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU General Public License as\r
- * published by the Free Software Foundation; either version 2 of the\r
- * License, or (at your option) any later version.\r
- *\r
- * This software is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
- * General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this software; see the file COPYING.LIB. If not, write\r
- * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,\r
- * MA 02139, USA. \r
- *\r
- * --------------------------------------------------------------------\r
- */\r
-#include "smss.h"\r
-\r
-#define NDEBUG\r
-#include <debug.h>\r
-\r
-/**********************************************************************\r
- * SmCreateUserProcess/5\r
- *\r
- */\r
-NTSTATUS STDCALL\r
-SmCreateUserProcess (LPWSTR ImagePath,\r
- LPWSTR CommandLine,\r
- BOOLEAN WaitForIt,\r
- PLARGE_INTEGER Timeout OPTIONAL,\r
- BOOLEAN TerminateIt,\r
- PRTL_PROCESS_INFO UserProcessInfo OPTIONAL\r
- )\r
-{\r
- UNICODE_STRING ImagePathString = {0};\r
- UNICODE_STRING CommandLineString = {0};\r
- PRTL_USER_PROCESS_PARAMETERS ProcessParameters = NULL;\r
- RTL_PROCESS_INFO ProcessInfo = {0};\r
- PRTL_PROCESS_INFO pProcessInfo = & ProcessInfo;\r
- NTSTATUS Status = STATUS_SUCCESS;\r
-\r
-\r
- DPRINT("SM: %s called\n",__FUNCTION__);\r
-\r
- RtlInitUnicodeString (& ImagePathString, ImagePath);\r
- RtlInitUnicodeString (& CommandLineString, CommandLine);\r
-\r
- RtlCreateProcessParameters(& ProcessParameters,\r
- & ImagePathString,\r
- NULL,\r
- NULL,\r
- & CommandLineString,\r
- SmSystemEnvironment,\r
- NULL,\r
- NULL,\r
- NULL,\r
- NULL);\r
-\r
- if(NULL != UserProcessInfo)\r
- {\r
- /* Use caller provided storage */\r
- pProcessInfo = UserProcessInfo;\r
- }\r
-\r
- Status = RtlCreateUserProcess (& ImagePathString,\r
- OBJ_CASE_INSENSITIVE,\r
- ProcessParameters,\r
- NULL,\r
- NULL,\r
- NULL,\r
- FALSE,\r
- NULL,\r
- NULL,\r
- pProcessInfo);\r
- if (!NT_SUCCESS(Status))\r
- {\r
- CHAR AnsiBuffer [MAX_PATH];\r
- INT i = 0;\r
- for(i=0;ImagePathString.Buffer[i];i++)\r
- {\r
- /* raw U -> A */\r
- AnsiBuffer [i] = (CHAR) (ImagePathString.Buffer[i] & 0xff);\r
- }\r
-\r
- DPRINT1("SM: %s: Running \"%s\" failed (Status=0x%08lx)\n",\r
- AnsiBuffer, __FUNCTION__, Status);\r
- return Status;\r
- }\r
-\r
- RtlDestroyProcessParameters (ProcessParameters);\r
-\r
- /* Wait for process termination */\r
- if(WaitForIt)\r
- {\r
- NtWaitForSingleObject (pProcessInfo->ProcessHandle,\r
- FALSE,\r
- Timeout);\r
- }\r
-\r
- /* Terminate process */\r
- if(TerminateIt)\r
- {\r
- NtClose(pProcessInfo->ThreadHandle);\r
- NtClose(pProcessInfo->ProcessHandle);\r
- }\r
- return STATUS_SUCCESS;\r
-}\r
-\r
-/**********************************************************************\r
- * NAME\r
- * SmLookupSubsystem/5\r
- *\r
- * DESCRIPTION\r
- * Read from the registry key\r
- * \Registry\SYSTEM\CurrentControlSet\Control\Session Manager\Subsystems\r
- * the value which name is Name.\r
- *\r
- * ARGUMENTS\r
- * Name: name of the program to run, that is a value's name in\r
- * the SM registry key Subsystems;\r
- * Data: what the registry gave back for Name;\r
- * DataLength: how much Data the registry returns;\r
- * DataType: what is Data?\r
- * Expand: set it TRUE if you want this function to use the env\r
- * to possibly expand Data before giving it back.\r
- */\r
-NTSTATUS STDCALL\r
-SmLookupSubsystem (IN PWSTR Name,\r
- IN OUT PWSTR Data,\r
- IN OUT PULONG DataLength,\r
- IN OUT PULONG DataType,\r
- IN BOOLEAN Expand)\r
-{\r
- NTSTATUS Status = STATUS_SUCCESS;\r
- UNICODE_STRING usKeyName = {0};\r
- OBJECT_ATTRIBUTES Oa = {0};\r
- HANDLE hKey = (HANDLE) 0;\r
-\r
- DPRINT("SM: %s called\n", __FUNCTION__);\r
- /*\r
- * Prepare the key name to scan and\r
- * related object attributes.\r
- */\r
- RtlInitUnicodeString (& usKeyName,\r
- L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\SubSystems");\r
-\r
- InitializeObjectAttributes (& Oa,\r
- & usKeyName,\r
- OBJ_CASE_INSENSITIVE,\r
- NULL,\r
- NULL);\r
- /*\r
- * Open the key. This MUST NOT fail, if the\r
- * request is for a legitimate subsystem.\r
- */\r
- Status = NtOpenKey (& hKey,\r
- MAXIMUM_ALLOWED,\r
- & Oa);\r
- if(NT_SUCCESS(Status))\r
- {\r
- UNICODE_STRING usValueName = {0};\r
- WCHAR KeyValueInformation [1024] = {L'\0'};\r
- ULONG ResultLength = 0L;\r
- PKEY_VALUE_PARTIAL_INFORMATION\r
- kvpi = (PKEY_VALUE_PARTIAL_INFORMATION) KeyValueInformation;\r
-\r
- \r
- RtlInitUnicodeString (& usValueName, Name);\r
- Status = NtQueryValueKey (hKey,\r
- & usValueName,\r
- KeyValuePartialInformation,\r
- KeyValueInformation,\r
- sizeof KeyValueInformation,\r
- & ResultLength);\r
- if(NT_SUCCESS(Status))\r
- {\r
- DPRINT("nkvpi.TitleIndex = %ld\n", kvpi->TitleIndex);\r
- DPRINT("kvpi.Type = %ld\n", kvpi->Type);\r
- DPRINT("kvpi.DataLength = %ld\n", kvpi->DataLength);\r
-\r
- if((NULL != Data) && (NULL != DataLength) && (NULL != DataType))\r
- {\r
- *DataType = kvpi->Type;\r
- if((Expand) && (REG_EXPAND_SZ == *DataType))\r
- {\r
- UNICODE_STRING Source;\r
- WCHAR DestinationBuffer [2048] = {0};\r
- UNICODE_STRING Destination;\r
- ULONG Length = 0;\r
-\r
- DPRINT("SM: %s: value will be expanded\n", __FUNCTION__);\r
-\r
- Source.Length = kvpi->DataLength;\r
- Source.MaximumLength = kvpi->DataLength;\r
- Source.Buffer = (PWCHAR) & kvpi->Data;\r
-\r
- Destination.Length = 0;\r
- Destination.MaximumLength = sizeof DestinationBuffer;\r
- Destination.Buffer = DestinationBuffer;\r
-\r
- Status = RtlExpandEnvironmentStrings_U (SmSystemEnvironment,\r
- & Source,\r
- & Destination,\r
- & Length);\r
- if(NT_SUCCESS(Status))\r
- {\r
- *DataLength = min(*DataLength, Destination.Length);\r
- RtlCopyMemory (Data, Destination.Buffer, *DataLength); \r
- }\r
- \r
- }else{\r
- DPRINT("SM: %s: value won't be expanded\n", __FUNCTION__);\r
- *DataLength = min(*DataLength, kvpi->DataLength);\r
- RtlCopyMemory (Data, & kvpi->Data, *DataLength);\r
- }\r
- *DataType = kvpi->Type;\r
- }else{\r
- DPRINT1("SM: %s: Data or DataLength or DataType is NULL!\n", __FUNCTION__);\r
- Status = STATUS_INVALID_PARAMETER;\r
- }\r
- }else{\r
- DPRINT1("%s: NtQueryValueKey failed (Status=0x%08lx)\n", __FUNCTION__, Status);\r
- }\r
- NtClose (hKey);\r
- }else{\r
- DPRINT1("%s: NtOpenKey failed (Status=0x%08lx)\n", __FUNCTION__, Status);\r
- }\r
- return Status;\r
-}\r
-\r
-\r
-/**********************************************************************\r
- * SmExecPgm/1 API\r
- */\r
-SMAPI(SmExecPgm)\r
-{\r
- PSM_PORT_MESSAGE_EXECPGM ExecPgm = NULL;\r
- WCHAR Name [SM_EXEXPGM_MAX_LENGTH + 1];\r
- NTSTATUS Status = STATUS_SUCCESS;\r
-\r
- DPRINT("SM: %s called\n",__FUNCTION__);\r
-\r
- if(NULL == Request)\r
- {\r
- DPRINT1("SM: %s: Request == NULL!\n", __FUNCTION__);\r
- return STATUS_INVALID_PARAMETER;\r
- }\r
- DPRINT("SM: %s called from CID(%lx|%lx)\n",\r
- __FUNCTION__, Request->Header.ClientId.UniqueProcess,\r
- Request->Header.ClientId.UniqueThread);\r
- ExecPgm = & Request->ExecPgm;\r
- /* Check if the name lenght is valid */\r
- if((ExecPgm->NameLength > 0) &&\r
- (ExecPgm->NameLength <= SM_EXEXPGM_MAX_LENGTH) &&\r
- TRUE /* TODO: check LPC payload size */)\r
- {\r
- \r
- RtlZeroMemory (Name, sizeof Name);\r
- RtlCopyMemory (Name,\r
- ExecPgm->Name,\r
- (sizeof ExecPgm->Name[0] * ExecPgm->NameLength));\r
- DPRINT("SM: %s: Name=[%wZ]\n", __FUNCTION__, Name);\r
- /*\r
- * Check if program name is internal\r
- * (Is this correct? Debug is in the registry too)\r
- */\r
- if(0 == _wcsicmp(L"DEBUG", Name))\r
- {\r
- /*\r
- * Initialize DBGSS.\r
- * NOTE: probably in early prototypes it was an\r
- * independent process; now it is embedded in the\r
- * SM for performance or security.\r
- */\r
- Request->Status = SmInitializeDbgSs();\r
- }\r
- else\r
- {\r
- WCHAR ImagePath [1024] = {0};\r
- ULONG ImagePathLength = sizeof ImagePath;\r
- ULONG ImagePathType = REG_EXPAND_SZ;\r
-\r
- /* Lookup Name in the registry */\r
- Status = SmLookupSubsystem (Name,\r
- ImagePath,\r
- & ImagePathLength,\r
- & ImagePathType,\r
- TRUE); /* expand */\r
- if(NT_SUCCESS(Status))\r
- {\r
- /* Create native process */\r
- Request->Status = SmCreateUserProcess(ImagePath,\r
- L"", /* FIXME */\r
- FALSE, /* wait */\r
- NULL,\r
- FALSE, /* terminate */\r
- NULL);\r
- }else{\r
- Request->Status = Status;\r
- }\r
- }\r
- }\r
- else\r
- {\r
- Request->Status = Status = STATUS_INVALID_PARAMETER;\r
- }\r
- return Status;\r
-}\r
-\r
-/* EOF */\r
+/* $Id$
+ *
+ * smapiexec.c - SM_API_EXECUTE_PROGRAM
+ *
+ * Reactos Session Manager
+ *
+ * --------------------------------------------------------------------
+ *
+ * This software is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING.LIB. If not, write
+ * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
+ * MA 02139, USA.
+ *
+ * --------------------------------------------------------------------
+ */
+#include "smss.h"
+
+#define NDEBUG
+#include <debug.h>
+
+/**********************************************************************
+ * SmCreateUserProcess/5
+ *
+ * DESCRIPTION
+ *
+ * ARGUMENTS
+ * ImagePath: absolute path of the image to run;
+ * CommandLine: arguments and options for ImagePath;
+ * WaitForIt: TRUE for boot time processes and FALSE for
+ * subsystems bootstrapping;
+ * Timeout: optional: used if WaitForIt==TRUE;
+ * ProcessHandle: optional: a duplicated handle for
+ the child process (storage provided by the caller).
+ *
+ * RETURN VALUE
+ * NTSTATUS:
+ *
+ */
+NTSTATUS STDCALL
+SmCreateUserProcess (LPWSTR ImagePath,
+ LPWSTR CommandLine,
+ BOOLEAN WaitForIt,
+ PLARGE_INTEGER Timeout OPTIONAL,
+ PRTL_USER_PROCESS_INFORMATION UserProcessInfo OPTIONAL)
+{
+ UNICODE_STRING ImagePathString = {0};
+ UNICODE_STRING CommandLineString = {0};
+ PRTL_USER_PROCESS_PARAMETERS ProcessParameters = NULL;
+ RTL_USER_PROCESS_INFORMATION ProcessInfo = {0};
+ PRTL_USER_PROCESS_INFORMATION pProcessInfo = & ProcessInfo;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ DPRINT("SM: %s called\n", __FUNCTION__);
+
+ if (NULL != UserProcessInfo)
+ {
+ pProcessInfo = UserProcessInfo;
+ }
+
+ RtlInitUnicodeString (& ImagePathString, ImagePath);
+ RtlInitUnicodeString (& CommandLineString, CommandLine);
+
+ RtlCreateProcessParameters(& ProcessParameters,
+ & ImagePathString,
+ NULL,
+ NULL,
+ & CommandLineString,
+ SmSystemEnvironment,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+
+ Status = RtlCreateUserProcess (& ImagePathString,
+ OBJ_CASE_INSENSITIVE,
+ ProcessParameters,
+ NULL,
+ NULL,
+ NULL,
+ FALSE,
+ NULL,
+ NULL,
+ pProcessInfo);
+
+ RtlDestroyProcessParameters (ProcessParameters);
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("SM: %s: Running \"%S\" failed (Status=0x%08lx)\n",
+ __FUNCTION__, ImagePathString.Buffer, Status);
+ return Status;
+ }
+ /*
+ * It the caller is *not* interested in the child info,
+ * resume it immediately.
+ */
+ if (NULL == UserProcessInfo)
+ {
+ Status = NtResumeThread (ProcessInfo.ThreadHandle, NULL);
+ if(!NT_SUCCESS(Status))
+ {
+ DPRINT1("SM: %s: NtResumeThread failed (Status=0x%08lx)\n",
+ __FUNCTION__, Status);
+ }
+ }
+
+ /* Wait for process termination */
+ if (WaitForIt)
+ {
+ Status = NtWaitForSingleObject (pProcessInfo->ProcessHandle,
+ FALSE,
+ Timeout);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("SM: %s: NtWaitForSingleObject failed with Status=0x%08lx\n",
+ __FUNCTION__, Status);
+ }
+
+ }
+ if (NULL == UserProcessInfo)
+ {
+ NtClose(pProcessInfo->ProcessHandle);
+ NtClose(pProcessInfo->ThreadHandle);
+ }
+ return Status;
+}
+
+
+/**********************************************************************
+ * SmExecPgm/1 API
+ */
+SMAPI(SmExecPgm)
+{
+ PSM_PORT_MESSAGE_EXECPGM ExecPgm = NULL;
+ WCHAR Name [SM_EXEXPGM_MAX_LENGTH + 1];
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ DPRINT("SM: %s called\n",__FUNCTION__);
+
+ if(NULL == Request)
+ {
+ DPRINT1("SM: %s: Request == NULL!\n", __FUNCTION__);
+ return STATUS_INVALID_PARAMETER;
+ }
+ DPRINT("SM: %s called from CID(%lx|%lx)\n",
+ __FUNCTION__, Request->Header.ClientId.UniqueProcess,
+ Request->Header.ClientId.UniqueThread);
+ ExecPgm = & Request->Request.ExecPgm;
+ /* Check if the name lenght is valid */
+ if((ExecPgm->NameLength > 0) &&
+ (ExecPgm->NameLength <= SM_EXEXPGM_MAX_LENGTH) &&
+ TRUE /* TODO: check LPC payload size */)
+ {
+ WCHAR Data [MAX_PATH + 1] = {0};
+ ULONG DataLength = sizeof Data;
+ ULONG DataType = REG_EXPAND_SZ;
+
+
+ RtlZeroMemory (Name, sizeof Name);
+ RtlCopyMemory (Name,
+ ExecPgm->Name,
+ (sizeof ExecPgm->Name[0] * ExecPgm->NameLength));
+ DPRINT("SM: %s: Name='%S'\n", __FUNCTION__, Name);
+ /* Lookup Name in the registry */
+ Status = SmLookupSubsystem (Name,
+ Data,
+ & DataLength,
+ & DataType,
+ SmSystemEnvironment /* expand */);
+ if(NT_SUCCESS(Status))
+ {
+ /* Is the subsystem definition non-empty? */
+ if (DataLength > sizeof Data[0])
+ {
+ WCHAR ImagePath [MAX_PATH + 1] = {0};
+ PWCHAR CommandLine = ImagePath;
+ RTL_USER_PROCESS_INFORMATION ProcessInfo = {0};
+
+ wcscpy (ImagePath, L"\\??\\");
+ wcscat (ImagePath, Data);
+ /*
+ * Look for the beginning of the command line.
+ */
+ for (; (*CommandLine != L'\0') && (*CommandLine != L' ');
+ CommandLine ++);
+ for (; *CommandLine == L' '; CommandLine ++)
+ {
+ *CommandLine = L'\0';
+ }
+ /*
+ * Create a native process (suspended).
+ */
+ ProcessInfo.Size = sizeof ProcessInfo;
+ Request->SmHeader.Status =
+ SmCreateUserProcess(ImagePath,
+ CommandLine,
+ FALSE, /* wait */
+ NULL, /* timeout */
+ & ProcessInfo);
+ if (NT_SUCCESS(Request->SmHeader.Status))
+ {
+ Status = SmCreateClient (& ProcessInfo, Name);
+ if (NT_SUCCESS(Status))
+ {
+ Status = NtResumeThread (ProcessInfo.ThreadHandle, NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("SM: %s: NtResumeThread failed (Status=0x%08lx)\n",
+ __FUNCTION__, Status);
+ //Status = SmDestroyClient TODO
+ }
+ } else {
+ DPRINT1("SM: %s: SmCreateClient failed (Status=0x%08lx)\n",
+ __FUNCTION__, Status);
+ }
+ }
+ }
+ else
+ {
+ /*
+ * OK, the definition is empty, but check
+ * if it is the name of an embedded subsystem.
+ */
+ if(0 == _wcsicmp(L"DEBUG", Name))
+ {
+ /*
+ * Initialize the embedded DBGSS.
+ */
+ Request->SmHeader.Status = SmInitializeDbgSs();
+ }
+ else
+ {
+ /*
+ * Badly defined subsystem. Check the registry!
+ */
+ Request->SmHeader.Status = STATUS_NOT_FOUND;
+ }
+ }
+ } else {
+ /* It couldn't lookup the Name! */
+ Request->SmHeader.Status = Status;
+ }
+ }
+ return Status;
+}
+
+/* EOF */