3 * smapiexec.c - SM_API_EXECUTE_PROGRAM
5 * Reactos Session Manager
7 * --------------------------------------------------------------------
9 * This software is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
14 * This software is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this software; see the file COPYING.LIB. If not, write
21 * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
24 * --------------------------------------------------------------------
31 /**********************************************************************
32 * SmCreateUserProcess/5
37 * ImagePath: bsolute path of the image to run;
38 * CommandLine: arguments and options for ImagePath;
39 * WaitForIt: TRUE for boot time processes and FALSE for
40 * subsystems bootstrapping;
41 * Timeout: optional: used if WaitForIt==TRUE;
42 * ProcessHandle: optional: a duplicated handle for
43 the child process (storage provided by the caller).
50 SmCreateUserProcess (LPWSTR ImagePath
,
53 PLARGE_INTEGER Timeout OPTIONAL
,
54 PRTL_PROCESS_INFO UserProcessInfo OPTIONAL
)
56 UNICODE_STRING ImagePathString
= {0};
57 UNICODE_STRING CommandLineString
= {0};
58 PRTL_USER_PROCESS_PARAMETERS ProcessParameters
= NULL
;
59 RTL_PROCESS_INFO ProcessInfo
= {0};
60 PRTL_PROCESS_INFO pProcessInfo
= & ProcessInfo
;
61 NTSTATUS Status
= STATUS_SUCCESS
;
63 DPRINT("SM: %s called\n", __FUNCTION__
);
65 if (NULL
!= UserProcessInfo
)
67 pProcessInfo
= UserProcessInfo
;
70 RtlInitUnicodeString (& ImagePathString
, ImagePath
);
71 RtlInitUnicodeString (& CommandLineString
, CommandLine
);
73 RtlCreateProcessParameters(& ProcessParameters
,
84 Status
= RtlCreateUserProcess (& ImagePathString
,
95 RtlDestroyProcessParameters (ProcessParameters
);
97 if (!NT_SUCCESS(Status
))
99 DPRINT1("SM: %s: Running \"%S\" failed (Status=0x%08lx)\n",
100 __FUNCTION__
, ImagePathString
.Buffer
, Status
);
104 * It the caller is *not* interested in the child info,
105 * resume it immediately.
107 if (NULL
== UserProcessInfo
)
109 Status
= NtResumeThread (ProcessInfo
.ThreadHandle
, NULL
);
110 if(!NT_SUCCESS(Status
))
112 DPRINT1("SM: %s: NtResumeThread failed (Status=0x%08lx)\n",
113 __FUNCTION__
, Status
);
118 HANDLE DupProcessHandle
= (HANDLE
) 0;
120 Status
= NtDuplicateObject (NtCurrentProcess(),
121 pProcessInfo
->ProcessHandle
,
126 if(!NT_SUCCESS(Status
))
128 DPRINT1("SM: %s: NtDuplicateObject failed (Status=0x%08lx)\n",
129 __FUNCTION__
, Status
);
131 pProcessInfo
->ProcessHandle
= DupProcessHandle
;
135 /* Wait for process termination */
138 Status
= NtWaitForSingleObject (pProcessInfo
->ProcessHandle
,
141 if (!NT_SUCCESS(Status
))
143 DPRINT1("SM: %s: NtWaitForSingleObject failed with Status=0x%08lx\n",
144 __FUNCTION__
, Status
);
151 /**********************************************************************
153 * SmLookupSubsystem/5
156 * Read from the registry key
157 * \Registry\SYSTEM\CurrentControlSet\Control\Session Manager\Subsystems
158 * the value which name is Name.
161 * Name: name of the program to run, that is a value's name in
162 * the SM registry key Subsystems;
163 * Data: what the registry gave back for Name;
164 * DataLength: how much Data the registry returns;
165 * DataType: what is Data?
166 * Expand: set it TRUE if you want this function to use the env
167 * to possibly expand Data before giving it back.
170 SmLookupSubsystem (IN PWSTR Name
,
172 IN OUT PULONG DataLength
,
173 IN OUT PULONG DataType
,
176 NTSTATUS Status
= STATUS_SUCCESS
;
177 UNICODE_STRING usKeyName
= {0};
178 OBJECT_ATTRIBUTES Oa
= {0};
179 HANDLE hKey
= (HANDLE
) 0;
181 DPRINT("SM: %s(Name='%S') called\n", __FUNCTION__
, Name
);
183 * Prepare the key name to scan and
184 * related object attributes.
186 RtlInitUnicodeString (& usKeyName
,
187 L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\SubSystems");
189 InitializeObjectAttributes (& Oa
,
191 OBJ_CASE_INSENSITIVE
,
195 * Open the key. This MUST NOT fail, if the
196 * request is for a legitimate subsystem.
198 Status
= NtOpenKey (& hKey
,
201 if(NT_SUCCESS(Status
))
203 UNICODE_STRING usValueName
= {0};
204 WCHAR KeyValueInformation
[1024] = {L
'\0'};
205 ULONG ResultLength
= 0L;
206 PKEY_VALUE_PARTIAL_INFORMATION
207 kvpi
= (PKEY_VALUE_PARTIAL_INFORMATION
) KeyValueInformation
;
210 RtlInitUnicodeString (& usValueName
, Name
);
211 Status
= NtQueryValueKey (hKey
,
213 KeyValuePartialInformation
,
215 sizeof KeyValueInformation
,
217 if(NT_SUCCESS(Status
))
219 DPRINT("nkvpi.TitleIndex = %ld\n", kvpi
->TitleIndex
);
220 DPRINT("kvpi.Type = %ld\n", kvpi
->Type
);
221 DPRINT("kvpi.DataLength = %ld\n", kvpi
->DataLength
);
223 if((NULL
!= Data
) && (NULL
!= DataLength
) && (NULL
!= DataType
))
225 *DataType
= kvpi
->Type
;
226 if((Expand
) && (REG_EXPAND_SZ
== *DataType
))
228 UNICODE_STRING Source
;
229 WCHAR DestinationBuffer
[2048] = {0};
230 UNICODE_STRING Destination
;
233 DPRINT("SM: %s: value will be expanded\n", __FUNCTION__
);
235 Source
.Length
= kvpi
->DataLength
;
236 Source
.MaximumLength
= kvpi
->DataLength
;
237 Source
.Buffer
= (PWCHAR
) & kvpi
->Data
;
239 Destination
.Length
= 0;
240 Destination
.MaximumLength
= sizeof DestinationBuffer
;
241 Destination
.Buffer
= DestinationBuffer
;
243 Status
= RtlExpandEnvironmentStrings_U (SmSystemEnvironment
,
247 if(NT_SUCCESS(Status
))
249 *DataLength
= min(*DataLength
, Destination
.Length
);
250 RtlCopyMemory (Data
, Destination
.Buffer
, *DataLength
);
254 DPRINT("SM: %s: value won't be expanded\n", __FUNCTION__
);
255 *DataLength
= min(*DataLength
, kvpi
->DataLength
);
256 RtlCopyMemory (Data
, & kvpi
->Data
, *DataLength
);
258 *DataType
= kvpi
->Type
;
260 DPRINT1("SM: %s: Data or DataLength or DataType is NULL!\n", __FUNCTION__
);
261 Status
= STATUS_INVALID_PARAMETER
;
264 DPRINT1("%s: NtQueryValueKey failed (Status=0x%08lx)\n", __FUNCTION__
, Status
);
268 DPRINT1("%s: NtOpenKey failed (Status=0x%08lx)\n", __FUNCTION__
, Status
);
274 /**********************************************************************
279 PSM_PORT_MESSAGE_EXECPGM ExecPgm
= NULL
;
280 WCHAR Name
[SM_EXEXPGM_MAX_LENGTH
+ 1];
281 NTSTATUS Status
= STATUS_SUCCESS
;
283 DPRINT("SM: %s called\n",__FUNCTION__
);
287 DPRINT1("SM: %s: Request == NULL!\n", __FUNCTION__
);
288 return STATUS_INVALID_PARAMETER
;
290 DPRINT("SM: %s called from CID(%lx|%lx)\n",
291 __FUNCTION__
, Request
->Header
.ClientId
.UniqueProcess
,
292 Request
->Header
.ClientId
.UniqueThread
);
293 ExecPgm
= & Request
->Request
.ExecPgm
;
294 /* Check if the name lenght is valid */
295 if((ExecPgm
->NameLength
> 0) &&
296 (ExecPgm
->NameLength
<= SM_EXEXPGM_MAX_LENGTH
) &&
297 TRUE
/* TODO: check LPC payload size */)
299 WCHAR Data
[MAX_PATH
+ 1] = {0};
300 ULONG DataLength
= sizeof Data
;
301 ULONG DataType
= REG_EXPAND_SZ
;
304 RtlZeroMemory (Name
, sizeof Name
);
307 (sizeof ExecPgm
->Name
[0] * ExecPgm
->NameLength
));
308 DPRINT("SM: %s: Name='%S'\n", __FUNCTION__
, Name
);
309 /* Lookup Name in the registry */
310 Status
= SmLookupSubsystem (Name
,
315 if(NT_SUCCESS(Status
))
317 /* Is the subsystem definition non-empty? */
318 if (DataLength
> sizeof Data
[0])
320 WCHAR ImagePath
[MAX_PATH
+ 1] = {0};
321 PWCHAR CommandLine
= ImagePath
;
322 RTL_PROCESS_INFO ProcessInfo
= {0};
324 wcscpy (ImagePath
, L
"\\??\\");
325 wcscat (ImagePath
, Data
);
327 * Look for the beginning of the command line.
329 for (; (*CommandLine
!= L
'\0') && (*CommandLine
!= L
' ');
331 for (; *CommandLine
== L
' '; CommandLine
++)
333 *CommandLine
= L
'\0';
336 * Create a native process (suspended).
338 ProcessInfo
.Size
= sizeof ProcessInfo
;
339 Request
->SmHeader
.Status
=
340 SmCreateUserProcess(ImagePath
,
345 if (NT_SUCCESS(Request
->SmHeader
.Status
))
347 Status
= SmCreateClient (& ProcessInfo
, Name
);
348 if (NT_SUCCESS(Status
))
350 Status
= NtResumeThread (ProcessInfo
.ThreadHandle
, NULL
);
351 if (!NT_SUCCESS(Status
))
353 //Status = SmDestroyClient TODO
356 DPRINT1("SM: %s: SmCreateClient failed (Status=0x%08lx)\n",
357 __FUNCTION__
, Status
);
364 * OK, the definition is empty, but check
365 * if it is the name of an embedded subsystem.
367 if(0 == _wcsicmp(L
"DEBUG", Name
))
370 * Initialize the embedded DBGSS.
372 Request
->SmHeader
.Status
= SmInitializeDbgSs();
377 * Badly defined subsystem. Check the registry!
379 Request
->SmHeader
.Status
= STATUS_NOT_FOUND
;
383 /* It couldn't lookup the Name! */
384 Request
->SmHeader
.Status
= Status
;