FreeRDP
Loading...
Searching...
No Matches
process.c
1
21#include <winpr/config.h>
22
23#include <winpr/handle.h>
24#include "../handle/nonehandle.h"
25
26#include <winpr/thread.h>
27#include <winpr/wlog.h>
28
53#ifndef _WIN32
54
55#include <winpr/assert.h>
56#include <winpr/crt.h>
57#include <winpr/path.h>
58#include <winpr/environment.h>
59
60#include <grp.h>
61
62#include <signal.h>
63#include <sys/types.h>
64#include <sys/wait.h>
65
66#ifdef __linux__
67#include <sys/syscall.h>
68#include <fcntl.h>
69#include <errno.h>
70#endif /* __linux__ */
71
72#include "thread.h"
73
74#include "../security/security.h"
75
76#ifndef NSIG
77#ifdef SIGMAX
78#define NSIG SIGMAX
79#else
80#define NSIG 64
81#endif
82#endif
83
99static char* FindApplicationPath(char* application)
100{
101 LPCSTR pathName = "PATH";
102 char* path = NULL;
103 char* save = NULL;
104 DWORD nSize = 0;
105 LPSTR lpSystemPath = NULL;
106 char* filename = NULL;
107
108 if (!application)
109 return NULL;
110
111 if (application[0] == '/')
112 return _strdup(application);
113
114 nSize = GetEnvironmentVariableA(pathName, NULL, 0);
115
116 if (!nSize)
117 return _strdup(application);
118
119 lpSystemPath = (LPSTR)malloc(nSize);
120
121 if (!lpSystemPath)
122 return NULL;
123
124 if (GetEnvironmentVariableA(pathName, lpSystemPath, nSize) != nSize - 1)
125 {
126 free(lpSystemPath);
127 return NULL;
128 }
129
130 save = NULL;
131 path = strtok_s(lpSystemPath, ":", &save);
132
133 while (path)
134 {
135 filename = GetCombinedPath(path, application);
136
137 if (winpr_PathFileExists(filename))
138 {
139 break;
140 }
141
142 free(filename);
143 filename = NULL;
144 path = strtok_s(NULL, ":", &save);
145 }
146
147 free(lpSystemPath);
148 return filename;
149}
150
151static HANDLE CreateProcessHandle(pid_t pid);
152static BOOL ProcessHandleCloseHandle(HANDLE handle);
153
154static BOOL CreateProcessExA(HANDLE hToken, WINPR_ATTR_UNUSED DWORD dwLogonFlags,
155 LPCSTR lpApplicationName, WINPR_ATTR_UNUSED LPSTR lpCommandLine,
156 WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpProcessAttributes,
157 WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpThreadAttributes,
158 WINPR_ATTR_UNUSED BOOL bInheritHandles,
159 WINPR_ATTR_UNUSED DWORD dwCreationFlags, LPVOID lpEnvironment,
160 LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo,
161 LPPROCESS_INFORMATION lpProcessInformation)
162{
163 pid_t pid = 0;
164 int numArgs = 0;
165 LPSTR* pArgs = NULL;
166 char** envp = NULL;
167 char* filename = NULL;
168 HANDLE thread = NULL;
169 HANDLE process = NULL;
170 WINPR_ACCESS_TOKEN* token = NULL;
171 LPTCH lpszEnvironmentBlock = NULL;
172 BOOL ret = FALSE;
173 sigset_t oldSigMask;
174 sigset_t newSigMask;
175 BOOL restoreSigMask = FALSE;
176 numArgs = 0;
177 lpszEnvironmentBlock = NULL;
178 /* https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa
179 */
180 if (lpCommandLine)
181 pArgs = CommandLineToArgvA(lpCommandLine, &numArgs);
182 else
183 pArgs = CommandLineToArgvA(lpApplicationName, &numArgs);
184
185 if (!pArgs)
186 return FALSE;
187
188 token = (WINPR_ACCESS_TOKEN*)hToken;
189
190 if (lpEnvironment)
191 {
192 envp = EnvironmentBlockToEnvpA(lpEnvironment);
193 }
194 else
195 {
196 lpszEnvironmentBlock = GetEnvironmentStrings();
197
198 if (!lpszEnvironmentBlock)
199 goto finish;
200
201 envp = EnvironmentBlockToEnvpA(lpszEnvironmentBlock);
202 }
203
204 if (!envp)
205 goto finish;
206
207 filename = FindApplicationPath(pArgs[0]);
208
209 if (NULL == filename)
210 goto finish;
211
212 /* block all signals so that the child can safely reset the caller's handlers */
213 sigfillset(&newSigMask);
214 restoreSigMask = !pthread_sigmask(SIG_SETMASK, &newSigMask, &oldSigMask);
215 /* fork and exec */
216 pid = fork();
217
218 if (pid < 0)
219 {
220 /* fork failure */
221 goto finish;
222 }
223
224 if (pid == 0)
225 {
226 /* child process */
227#ifndef __sun
228 int maxfd = 0;
229#endif
230 sigset_t set = { 0 };
231 struct sigaction act = { 0 };
232 /* set default signal handlers */
233 act.sa_handler = SIG_DFL;
234 act.sa_flags = 0;
235 sigemptyset(&act.sa_mask);
236
237 for (int sig = 1; sig < NSIG; sig++)
238 sigaction(sig, &act, NULL);
239
240 /* unblock all signals */
241 sigfillset(&set);
242 pthread_sigmask(SIG_UNBLOCK, &set, NULL);
243
244 if (lpStartupInfo)
245 {
246 int handle_fd = 0;
247 handle_fd = winpr_Handle_getFd(lpStartupInfo->hStdOutput);
248
249 if (handle_fd != -1)
250 dup2(handle_fd, STDOUT_FILENO);
251
252 handle_fd = winpr_Handle_getFd(lpStartupInfo->hStdError);
253
254 if (handle_fd != -1)
255 dup2(handle_fd, STDERR_FILENO);
256
257 handle_fd = winpr_Handle_getFd(lpStartupInfo->hStdInput);
258
259 if (handle_fd != -1)
260 dup2(handle_fd, STDIN_FILENO);
261 }
262
263#ifdef __sun
264 closefrom(3);
265#else
266#ifdef F_MAXFD // on some BSD derivates
267 maxfd = fcntl(0, F_MAXFD);
268#else
269 {
270 const long rc = sysconf(_SC_OPEN_MAX);
271 if ((rc < INT32_MIN) || (rc > INT32_MAX))
272 goto finish;
273 maxfd = (int)rc;
274 }
275#endif
276
277 for (int fd = 3; fd < maxfd; fd++)
278 close(fd);
279
280#endif // __sun
281
282 if (token)
283 {
284 if (token->GroupId)
285 {
286 int rc = setgid((gid_t)token->GroupId);
287
288 if (rc < 0)
289 {
290 }
291 else
292 {
293 initgroups(token->Username, (gid_t)token->GroupId);
294 }
295 }
296
297 if (token->UserId)
298 {
299 int rc = setuid((uid_t)token->UserId);
300 if (rc != 0)
301 goto finish;
302 }
303 }
304
305 /* TODO: add better cwd handling and error checking */
306 if (lpCurrentDirectory && strlen(lpCurrentDirectory) > 0)
307 {
308 int rc = chdir(lpCurrentDirectory);
309 if (rc != 0)
310 goto finish;
311 }
312
313 if (execve(filename, pArgs, envp) < 0)
314 {
315 /* execve failed - end the process */
316 _exit(1);
317 }
318 }
319 else
320 {
321 /* parent process */
322 }
323
324 process = CreateProcessHandle(pid);
325
326 if (!process)
327 {
328 goto finish;
329 }
330
331 thread = CreateNoneHandle();
332
333 if (!thread)
334 {
335 ProcessHandleCloseHandle(process);
336 goto finish;
337 }
338
339 lpProcessInformation->hProcess = process;
340 lpProcessInformation->hThread = thread;
341 lpProcessInformation->dwProcessId = (DWORD)pid;
342 lpProcessInformation->dwThreadId = (DWORD)pid;
343 ret = TRUE;
344finish:
345
346 /* restore caller's original signal mask */
347 if (restoreSigMask)
348 pthread_sigmask(SIG_SETMASK, &oldSigMask, NULL);
349
350 free(filename);
351 free((void*)pArgs);
352
353 if (lpszEnvironmentBlock)
354 FreeEnvironmentStrings(lpszEnvironmentBlock);
355
356 if (envp)
357 {
358 int i = 0;
359
360 while (envp[i])
361 {
362 free(envp[i]);
363 i++;
364 }
365
366 free((void*)envp);
367 }
368
369 return ret;
370}
371
372BOOL CreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine,
373 LPSECURITY_ATTRIBUTES lpProcessAttributes,
374 LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles,
375 DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory,
376 LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation)
377{
378 return CreateProcessExA(NULL, 0, lpApplicationName, lpCommandLine, lpProcessAttributes,
379 lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,
380 lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
381}
382
383BOOL CreateProcessW(WINPR_ATTR_UNUSED LPCWSTR lpApplicationName,
384 WINPR_ATTR_UNUSED LPWSTR lpCommandLine,
385 WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpProcessAttributes,
386 WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpThreadAttributes,
387 WINPR_ATTR_UNUSED BOOL bInheritHandles, WINPR_ATTR_UNUSED DWORD dwCreationFlags,
388 WINPR_ATTR_UNUSED LPVOID lpEnvironment,
389 WINPR_ATTR_UNUSED LPCWSTR lpCurrentDirectory,
390 WINPR_ATTR_UNUSED LPSTARTUPINFOW lpStartupInfo,
391 WINPR_ATTR_UNUSED LPPROCESS_INFORMATION lpProcessInformation)
392{
393 WLog_ERR("TODO", "TODO: implement");
394 return FALSE;
395}
396
397BOOL CreateProcessAsUserA(HANDLE hToken, LPCSTR lpApplicationName, LPSTR lpCommandLine,
398 LPSECURITY_ATTRIBUTES lpProcessAttributes,
399 LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles,
400 DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory,
401 LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation)
402{
403 return CreateProcessExA(hToken, 0, lpApplicationName, lpCommandLine, lpProcessAttributes,
404 lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,
405 lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
406}
407
408BOOL CreateProcessAsUserW(WINPR_ATTR_UNUSED HANDLE hToken,
409 WINPR_ATTR_UNUSED LPCWSTR lpApplicationName,
410 WINPR_ATTR_UNUSED LPWSTR lpCommandLine,
411 WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpProcessAttributes,
412 WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpThreadAttributes,
413 WINPR_ATTR_UNUSED BOOL bInheritHandles,
414 WINPR_ATTR_UNUSED DWORD dwCreationFlags,
415 WINPR_ATTR_UNUSED LPVOID lpEnvironment,
416 WINPR_ATTR_UNUSED LPCWSTR lpCurrentDirectory,
417 WINPR_ATTR_UNUSED LPSTARTUPINFOW lpStartupInfo,
418 WINPR_ATTR_UNUSED LPPROCESS_INFORMATION lpProcessInformation)
419{
420 WLog_ERR("TODO", "TODO: implement");
421 return FALSE;
422}
423
424BOOL CreateProcessWithLogonA(
425 WINPR_ATTR_UNUSED LPCSTR lpUsername, WINPR_ATTR_UNUSED LPCSTR lpDomain,
426 WINPR_ATTR_UNUSED LPCSTR lpPassword, WINPR_ATTR_UNUSED DWORD dwLogonFlags,
427 WINPR_ATTR_UNUSED LPCSTR lpApplicationName, WINPR_ATTR_UNUSED LPSTR lpCommandLine,
428 WINPR_ATTR_UNUSED DWORD dwCreationFlags, WINPR_ATTR_UNUSED LPVOID lpEnvironment,
429 WINPR_ATTR_UNUSED LPCSTR lpCurrentDirectory, WINPR_ATTR_UNUSED LPSTARTUPINFOA lpStartupInfo,
430 WINPR_ATTR_UNUSED LPPROCESS_INFORMATION lpProcessInformation)
431{
432 WLog_ERR("TODO", "TODO: implement");
433 return FALSE;
434}
435
436BOOL CreateProcessWithLogonW(
437 WINPR_ATTR_UNUSED LPCWSTR lpUsername, WINPR_ATTR_UNUSED LPCWSTR lpDomain,
438 WINPR_ATTR_UNUSED LPCWSTR lpPassword, WINPR_ATTR_UNUSED DWORD dwLogonFlags,
439 WINPR_ATTR_UNUSED LPCWSTR lpApplicationName, WINPR_ATTR_UNUSED LPWSTR lpCommandLine,
440 WINPR_ATTR_UNUSED DWORD dwCreationFlags, WINPR_ATTR_UNUSED LPVOID lpEnvironment,
441 WINPR_ATTR_UNUSED LPCWSTR lpCurrentDirectory, WINPR_ATTR_UNUSED LPSTARTUPINFOW lpStartupInfo,
442 WINPR_ATTR_UNUSED LPPROCESS_INFORMATION lpProcessInformation)
443{
444 WLog_ERR("TODO", "TODO: implement");
445 return FALSE;
446}
447
448BOOL CreateProcessWithTokenA(WINPR_ATTR_UNUSED HANDLE hToken, WINPR_ATTR_UNUSED DWORD dwLogonFlags,
449 LPCSTR lpApplicationName, LPSTR lpCommandLine, DWORD dwCreationFlags,
450 LPVOID lpEnvironment, LPCSTR lpCurrentDirectory,
451 LPSTARTUPINFOA lpStartupInfo,
452 LPPROCESS_INFORMATION lpProcessInformation)
453{
454 return CreateProcessExA(NULL, 0, lpApplicationName, lpCommandLine, NULL, NULL, FALSE,
455 dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo,
456 lpProcessInformation);
457}
458
459BOOL CreateProcessWithTokenW(WINPR_ATTR_UNUSED HANDLE hToken, WINPR_ATTR_UNUSED DWORD dwLogonFlags,
460 WINPR_ATTR_UNUSED LPCWSTR lpApplicationName,
461 WINPR_ATTR_UNUSED LPWSTR lpCommandLine,
462 WINPR_ATTR_UNUSED DWORD dwCreationFlags,
463 WINPR_ATTR_UNUSED LPVOID lpEnvironment,
464 WINPR_ATTR_UNUSED LPCWSTR lpCurrentDirectory,
465 WINPR_ATTR_UNUSED LPSTARTUPINFOW lpStartupInfo,
466 WINPR_ATTR_UNUSED LPPROCESS_INFORMATION lpProcessInformation)
467{
468 WLog_ERR("TODO", "TODO: implement");
469 return FALSE;
470}
471
472VOID ExitProcess(UINT uExitCode)
473{
474 // NOLINTNEXTLINE(concurrency-mt-unsafe)
475 exit((int)uExitCode);
476}
477
478BOOL GetExitCodeProcess(HANDLE hProcess, LPDWORD lpExitCode)
479{
480 WINPR_PROCESS* process = NULL;
481
482 if (!hProcess)
483 return FALSE;
484
485 if (!lpExitCode)
486 return FALSE;
487
488 process = (WINPR_PROCESS*)hProcess;
489 *lpExitCode = process->dwExitCode;
490 return TRUE;
491}
492
493HANDLE _GetCurrentProcess(VOID)
494{
495 WLog_ERR("TODO", "TODO: implement");
496 return NULL;
497}
498
499DWORD GetCurrentProcessId(VOID)
500{
501 return ((DWORD)getpid());
502}
503
504BOOL TerminateProcess(HANDLE hProcess, WINPR_ATTR_UNUSED UINT uExitCode)
505{
506 WINPR_PROCESS* process = NULL;
507 process = (WINPR_PROCESS*)hProcess;
508
509 if (!process || (process->pid <= 0))
510 return FALSE;
511
512 if (kill(process->pid, SIGTERM))
513 return FALSE;
514
515 return TRUE;
516}
517
518static BOOL ProcessHandleCloseHandle(HANDLE handle)
519{
520 WINPR_PROCESS* process = (WINPR_PROCESS*)handle;
521 WINPR_ASSERT(process);
522 if (process->fd >= 0)
523 {
524 close(process->fd);
525 process->fd = -1;
526 }
527 free(process);
528 return TRUE;
529}
530
531static BOOL ProcessHandleIsHandle(HANDLE handle)
532{
533 return WINPR_HANDLE_IS_HANDLED(handle, HANDLE_TYPE_PROCESS, FALSE);
534}
535
536static int ProcessGetFd(HANDLE handle)
537{
538 WINPR_PROCESS* process = (WINPR_PROCESS*)handle;
539
540 if (!ProcessHandleIsHandle(handle))
541 return -1;
542
543 return process->fd;
544}
545
546static DWORD ProcessCleanupHandle(HANDLE handle)
547{
548 WINPR_PROCESS* process = (WINPR_PROCESS*)handle;
549
550 WINPR_ASSERT(process);
551 if (process->fd > 0)
552 {
553 if (waitpid(process->pid, &process->status, WNOHANG) == process->pid)
554 process->dwExitCode = (DWORD)process->status;
555 }
556 return WAIT_OBJECT_0;
557}
558
559static HANDLE_OPS ops = { ProcessHandleIsHandle,
560 ProcessHandleCloseHandle,
561 ProcessGetFd,
562 ProcessCleanupHandle, /* CleanupHandle */
563 NULL,
564 NULL,
565 NULL,
566 NULL,
567 NULL,
568 NULL,
569 NULL,
570 NULL,
571 NULL,
572 NULL,
573 NULL,
574 NULL,
575 NULL,
576 NULL,
577 NULL,
578 NULL,
579 NULL };
580
581static int pidfd_open(pid_t pid)
582{
583#ifdef __linux__
584#if !defined(__NR_pidfd_open)
585#define __NR_pidfd_open 434
586#endif /* __NR_pidfd_open */
587
588#ifndef PIDFD_NONBLOCK
589#define PIDFD_NONBLOCK O_NONBLOCK
590#endif /* PIDFD_NONBLOCK */
591
592 long fd = syscall(__NR_pidfd_open, pid, PIDFD_NONBLOCK);
593 if (fd < 0 && errno == EINVAL)
594 {
595 /* possibly PIDFD_NONBLOCK is not supported, let's try to create a pidfd and set it
596 * non blocking afterward */
597 int flags = 0;
598 fd = syscall(__NR_pidfd_open, pid, 0);
599 if ((fd < 0) || (fd > INT32_MAX))
600 return -1;
601
602 flags = fcntl((int)fd, F_GETFL);
603 if ((flags < 0) || fcntl((int)fd, F_SETFL, flags | O_NONBLOCK) < 0)
604 {
605 close((int)fd);
606 fd = -1;
607 }
608 }
609 if ((fd < 0) || (fd > INT32_MAX))
610 return -1;
611 return (int)fd;
612#else
613 return -1;
614#endif
615}
616
617HANDLE CreateProcessHandle(pid_t pid)
618{
619 WINPR_PROCESS* process = NULL;
620 process = (WINPR_PROCESS*)calloc(1, sizeof(WINPR_PROCESS));
621
622 if (!process)
623 return NULL;
624
625 process->pid = pid;
626 process->common.Type = HANDLE_TYPE_PROCESS;
627 process->common.ops = &ops;
628 process->fd = pidfd_open(pid);
629 if (process->fd >= 0)
630 process->common.Mode = WINPR_FD_READ;
631 return (HANDLE)process;
632}
633
634#endif