[CMAKE]
[reactos.git] / base / system / smss / smapiexec.c
1 /*
2 * PROJECT: ReactOS Session Manager
3 * LICENSE: GPL v2 or later - See COPYING in the top level directory
4 * FILE: base/system/smss/smapiexec.c
5 * PURPOSE: SM_API_EXECUTE_PROGRAM.
6 * PROGRAMMERS: ReactOS Development Team
7 */
8
9 /* INCLUDES ******************************************************************/
10 #include "smss.h"
11
12 #define NDEBUG
13 #include <debug.h>
14
15 static const WCHAR szSystemDirectory[] = L"\\System32";
16
17 /**********************************************************************
18 * SmCreateUserProcess/5
19 *
20 * DESCRIPTION
21 *
22 * ARGUMENTS
23 * ImagePath: absolute path of the image to run;
24 * CommandLine: arguments and options for ImagePath;
25 * Flags: Wait flag: Set for boot time processes and unset for
26 * subsystems bootstrapping;
27 * 1Mb reserve flag: Set for subsystems, unset for everything
28 * else
29 * Timeout: optional: used if WaitForIt==TRUE;
30 * ProcessHandle: optional: a duplicated handle for
31 the child process (storage provided by the caller).
32 *
33 * RETURN VALUE
34 * NTSTATUS:
35 *
36 */
37 NTSTATUS NTAPI
38 SmCreateUserProcess (LPWSTR ImagePath,
39 LPWSTR CommandLine,
40 ULONG Flags,
41 PLARGE_INTEGER Timeout OPTIONAL,
42 PRTL_USER_PROCESS_INFORMATION UserProcessInfo OPTIONAL)
43 {
44 UNICODE_STRING ImagePathString = { 0, 0, NULL };
45 UNICODE_STRING CommandLineString = { 0, 0, NULL };
46 UNICODE_STRING SystemDirectory = { 0, 0, NULL };
47 PRTL_USER_PROCESS_PARAMETERS ProcessParameters = NULL;
48 RTL_USER_PROCESS_INFORMATION ProcessInfo = {0};
49 PRTL_USER_PROCESS_INFORMATION pProcessInfo = & ProcessInfo;
50 NTSTATUS Status = STATUS_SUCCESS;
51
52 DPRINT("SM: %s called\n", __FUNCTION__);
53
54 if (NULL != UserProcessInfo)
55 {
56 pProcessInfo = UserProcessInfo;
57 }
58
59 RtlInitUnicodeString (& ImagePathString, ImagePath);
60 RtlInitUnicodeString (& CommandLineString, CommandLine);
61
62 SystemDirectory.MaximumLength = (wcslen(SharedUserData->NtSystemRoot) * sizeof(WCHAR)) + sizeof(szSystemDirectory);
63 SystemDirectory.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
64 0,
65 SystemDirectory.MaximumLength);
66 if (SystemDirectory.Buffer == NULL)
67 {
68 Status = STATUS_NO_MEMORY;
69 DPRINT1("SM: %s: Allocating system directory string failed (Status=0x%08lx)\n",
70 __FUNCTION__, Status);
71 return Status;
72 }
73
74 Status = RtlAppendUnicodeToString(& SystemDirectory,
75 SharedUserData->NtSystemRoot);
76 if (!NT_SUCCESS(Status))
77 {
78 goto FailProcParams;
79 }
80
81 Status = RtlAppendUnicodeToString(& SystemDirectory,
82 szSystemDirectory);
83 if (!NT_SUCCESS(Status))
84 {
85 goto FailProcParams;
86 }
87
88
89 Status = RtlCreateProcessParameters(& ProcessParameters,
90 & ImagePathString,
91 NULL,
92 & SystemDirectory,
93 & CommandLineString,
94 SmSystemEnvironment,
95 NULL,
96 NULL,
97 NULL,
98 NULL);
99
100 RtlFreeHeap(RtlGetProcessHeap(),
101 0,
102 SystemDirectory.Buffer);
103
104 if (!NT_SUCCESS(Status))
105 {
106 FailProcParams:
107 DPRINT1("SM: %s: Creating process parameters failed (Status=0x%08lx)\n",
108 __FUNCTION__, Status);
109 return Status;
110 }
111
112 /* Reserve lower 1Mb, if requested */
113 if (Flags & SM_CREATE_FLAG_RESERVE_1MB)
114 ProcessParameters->Flags |= RTL_USER_PROCESS_PARAMETERS_RESERVE_1MB;
115
116 /* Create the user process */
117 Status = RtlCreateUserProcess (& ImagePathString,
118 OBJ_CASE_INSENSITIVE,
119 ProcessParameters,
120 NULL,
121 NULL,
122 NULL,
123 FALSE,
124 NULL,
125 NULL,
126 pProcessInfo);
127
128 RtlDestroyProcessParameters (ProcessParameters);
129
130 if (!NT_SUCCESS(Status))
131 {
132 DPRINT1("SM: %s: Running \"%S\" failed (Status=0x%08lx)\n",
133 __FUNCTION__, ImagePathString.Buffer, Status);
134 return Status;
135 }
136 /*
137 * It the caller is *not* interested in the child info,
138 * resume it immediately.
139 */
140 if (NULL == UserProcessInfo)
141 {
142 Status = NtResumeThread (ProcessInfo.ThreadHandle, NULL);
143 if(!NT_SUCCESS(Status))
144 {
145 DPRINT1("SM: %s: NtResumeThread failed (Status=0x%08lx)\n",
146 __FUNCTION__, Status);
147 }
148 }
149
150 /* Wait for process termination */
151 if (Flags & SM_CREATE_FLAG_WAIT)
152 {
153 Status = NtWaitForSingleObject (pProcessInfo->ProcessHandle,
154 FALSE,
155 Timeout);
156 if (!NT_SUCCESS(Status))
157 {
158 DPRINT1("SM: %s: NtWaitForSingleObject failed with Status=0x%08lx\n",
159 __FUNCTION__, Status);
160 }
161 }
162
163 if (NULL == UserProcessInfo)
164 {
165 NtClose(pProcessInfo->ProcessHandle);
166 NtClose(pProcessInfo->ThreadHandle);
167 }
168 return Status;
169 }
170
171
172 /**********************************************************************
173 * SmExecPgm/1 API
174 */
175 SMAPI(SmExecPgm)
176 {
177 PSM_PORT_MESSAGE_EXECPGM ExecPgm = NULL;
178 WCHAR Name [SM_EXEXPGM_MAX_LENGTH + 1];
179 NTSTATUS Status = STATUS_SUCCESS;
180
181 DPRINT("SM: %s called\n",__FUNCTION__);
182
183 if(NULL == Request)
184 {
185 DPRINT1("SM: %s: Request == NULL!\n", __FUNCTION__);
186 return STATUS_INVALID_PARAMETER;
187 }
188 DPRINT("SM: %s called from CID(%p|%p)\n",
189 __FUNCTION__, Request->Header.ClientId.UniqueProcess,
190 Request->Header.ClientId.UniqueThread);
191 ExecPgm = & Request->Request.ExecPgm;
192 /* Check if the name lenght is valid */
193 if((ExecPgm->NameLength > 0) &&
194 (ExecPgm->NameLength <= SM_EXEXPGM_MAX_LENGTH) &&
195 TRUE /* TODO: check LPC payload size */)
196 {
197 WCHAR Data [MAX_PATH + 1] = {0};
198 ULONG DataLength = sizeof Data;
199 ULONG DataType = REG_EXPAND_SZ;
200
201
202 RtlZeroMemory (Name, sizeof Name);
203 RtlCopyMemory (Name,
204 ExecPgm->Name,
205 (sizeof ExecPgm->Name[0] * ExecPgm->NameLength));
206 DPRINT("SM: %s: Name='%S'\n", __FUNCTION__, Name);
207 /* Lookup Name in the registry */
208 Status = SmLookupSubsystem (Name,
209 Data,
210 & DataLength,
211 & DataType,
212 SmSystemEnvironment /* expand */);
213 if(NT_SUCCESS(Status))
214 {
215 /* Is the subsystem definition non-empty? */
216 if (DataLength > sizeof Data[0])
217 {
218 WCHAR ImagePath [MAX_PATH + 1] = {0};
219 PWCHAR CommandLine = ImagePath;
220 RTL_USER_PROCESS_INFORMATION ProcessInfo = {0};
221
222 wcscpy (ImagePath, L"\\??\\");
223 wcscat (ImagePath, Data);
224 /*
225 * Look for the beginning of the command line.
226 */
227 for (; (*CommandLine != L'\0') && (*CommandLine != L' ');
228 CommandLine ++);
229 for (; *CommandLine == L' '; CommandLine ++)
230 {
231 *CommandLine = L'\0';
232 }
233 /*
234 * Create a native process (suspended).
235 */
236 ProcessInfo.Size = sizeof ProcessInfo;
237 Request->SmHeader.Status =
238 SmCreateUserProcess(ImagePath,
239 CommandLine,
240 SM_CREATE_FLAG_RESERVE_1MB,
241 NULL, /* timeout */
242 & ProcessInfo);
243 if (NT_SUCCESS(Request->SmHeader.Status))
244 {
245 Status = SmCreateClient (& ProcessInfo, Name);
246 if (NT_SUCCESS(Status))
247 {
248 Status = NtResumeThread (ProcessInfo.ThreadHandle, NULL);
249 if (!NT_SUCCESS(Status))
250 {
251 DPRINT1("SM: %s: NtResumeThread failed (Status=0x%08lx)\n",
252 __FUNCTION__, Status);
253 //Status = SmDestroyClient TODO
254 }
255 } else {
256 DPRINT1("SM: %s: SmCreateClient failed (Status=0x%08lx)\n",
257 __FUNCTION__, Status);
258 }
259 NtClose(ProcessInfo.ThreadHandle);
260 NtClose(ProcessInfo.ProcessHandle);
261 }
262 }
263 else
264 {
265 /*
266 * OK, the definition is empty, but check
267 * if it is the name of an embedded subsystem.
268 */
269 if(0 == _wcsicmp(L"DEBUG", Name))
270 {
271 /*
272 * Initialize the embedded DBGSS.
273 */
274 Request->SmHeader.Status = SmInitializeDbgSs();
275 }
276 else
277 {
278 /*
279 * Badly defined subsystem. Check the registry!
280 */
281 Request->SmHeader.Status = STATUS_NOT_FOUND;
282 }
283 }
284 } else {
285 /* It couldn't lookup the Name! */
286 Request->SmHeader.Status = Status;
287 }
288 }
289 return Status;
290 }
291
292 /* EOF */