/src/FreeRDP/winpr/libwinpr/thread/process.c
Line  | Count  | Source (jump to first uncovered line)  | 
1  |  | /**  | 
2  |  |  * WinPR: Windows Portable Runtime  | 
3  |  |  * Process Thread Functions  | 
4  |  |  *  | 
5  |  |  * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>  | 
6  |  |  * Copyright 2014 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>  | 
7  |  |  *  | 
8  |  |  * Licensed under the Apache License, Version 2.0 (the "License");  | 
9  |  |  * you may not use this file except in compliance with the License.  | 
10  |  |  * You may obtain a copy of the License at  | 
11  |  |  *  | 
12  |  |  *     http://www.apache.org/licenses/LICENSE-2.0  | 
13  |  |  *  | 
14  |  |  * Unless required by applicable law or agreed to in writing, software  | 
15  |  |  * distributed under the License is distributed on an "AS IS" BASIS,  | 
16  |  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  | 
17  |  |  * See the License for the specific language governing permissions and  | 
18  |  |  * limitations under the License.  | 
19  |  |  */  | 
20  |  |  | 
21  |  | #include <winpr/config.h>  | 
22  |  |  | 
23  |  | #include <winpr/handle.h>  | 
24  |  | #include "../handle/nonehandle.h"  | 
25  |  |  | 
26  |  | #include <winpr/thread.h>  | 
27  |  |  | 
28  |  | /**  | 
29  |  |  * CreateProcessA  | 
30  |  |  * CreateProcessW  | 
31  |  |  * CreateProcessAsUserA  | 
32  |  |  * CreateProcessAsUserW  | 
33  |  |  * ExitProcess  | 
34  |  |  * GetCurrentProcess  | 
35  |  |  * GetCurrentProcessId  | 
36  |  |  * GetExitCodeProcess  | 
37  |  |  * GetProcessHandleCount  | 
38  |  |  * GetProcessId  | 
39  |  |  * GetProcessIdOfThread  | 
40  |  |  * GetProcessMitigationPolicy  | 
41  |  |  * GetProcessTimes  | 
42  |  |  * GetProcessVersion  | 
43  |  |  * OpenProcess  | 
44  |  |  * OpenProcessToken  | 
45  |  |  * ProcessIdToSessionId  | 
46  |  |  * SetProcessAffinityUpdateMode  | 
47  |  |  * SetProcessMitigationPolicy  | 
48  |  |  * SetProcessShutdownParameters  | 
49  |  |  * TerminateProcess  | 
50  |  |  */  | 
51  |  |  | 
52  |  | #ifndef _WIN32  | 
53  |  |  | 
54  |  | #include <winpr/assert.h>  | 
55  |  | #include <winpr/crt.h>  | 
56  |  | #include <winpr/path.h>  | 
57  |  | #include <winpr/environment.h>  | 
58  |  |  | 
59  |  | #include <grp.h>  | 
60  |  |  | 
61  |  | #include <signal.h>  | 
62  |  | #include <sys/types.h>  | 
63  |  | #include <sys/wait.h>  | 
64  |  |  | 
65  |  | #ifdef __linux__  | 
66  |  | #include <sys/syscall.h>  | 
67  |  | #include <fcntl.h>  | 
68  |  | #include <errno.h>  | 
69  |  | #endif /* __linux__ */  | 
70  |  |  | 
71  |  | #include "thread.h"  | 
72  |  |  | 
73  |  | #include "../security/security.h"  | 
74  |  |  | 
75  |  | #ifndef NSIG  | 
76  |  | #ifdef SIGMAX  | 
77  |  | #define NSIG SIGMAX  | 
78  |  | #else  | 
79  |  | #define NSIG 64  | 
80  |  | #endif  | 
81  |  | #endif  | 
82  |  |  | 
83  |  | /**  | 
84  |  |  * If the file name does not contain a directory path, the system searches for the executable file  | 
85  |  |  * in the following sequence:  | 
86  |  |  *  | 
87  |  |  * 1) The directory from which the application loaded.  | 
88  |  |  * 2) The current directory for the parent process.  | 
89  |  |  * 3) The 32-bit Windows system directory. Use the GetSystemDirectory function to get the path of  | 
90  |  |  * this directory. 4) The 16-bit Windows system directory. There is no function that obtains the  | 
91  |  |  * path of this directory, but it is searched. The name of this directory is System. 5) The Windows  | 
92  |  |  * directory. Use the GetWindowsDirectory function to get the path of this directory. 6) The  | 
93  |  |  * directories that are listed in the PATH environment variable. Note that this function does not  | 
94  |  |  * search the per-application path specified by the App Paths registry key. To include this  | 
95  |  |  * per-application path in the search sequence, use the ShellExecute function.  | 
96  |  |  */  | 
97  |  |  | 
98  |  | static char* FindApplicationPath(char* application)  | 
99  | 0  | { | 
100  | 0  |   LPCSTR pathName = "PATH";  | 
101  | 0  |   char* path = NULL;  | 
102  | 0  |   char* save = NULL;  | 
103  | 0  |   DWORD nSize = 0;  | 
104  | 0  |   LPSTR lpSystemPath = NULL;  | 
105  | 0  |   char* filename = NULL;  | 
106  |  | 
  | 
107  | 0  |   if (!application)  | 
108  | 0  |     return NULL;  | 
109  |  |  | 
110  | 0  |   if (application[0] == '/')  | 
111  | 0  |     return _strdup(application);  | 
112  |  |  | 
113  | 0  |   nSize = GetEnvironmentVariableA(pathName, NULL, 0);  | 
114  |  | 
  | 
115  | 0  |   if (!nSize)  | 
116  | 0  |     return _strdup(application);  | 
117  |  |  | 
118  | 0  |   lpSystemPath = (LPSTR)malloc(nSize);  | 
119  |  | 
  | 
120  | 0  |   if (!lpSystemPath)  | 
121  | 0  |     return NULL;  | 
122  |  |  | 
123  | 0  |   if (GetEnvironmentVariableA(pathName, lpSystemPath, nSize) != nSize - 1)  | 
124  | 0  |   { | 
125  | 0  |     free(lpSystemPath);  | 
126  | 0  |     return NULL;  | 
127  | 0  |   }  | 
128  |  |  | 
129  | 0  |   save = NULL;  | 
130  | 0  |   path = strtok_s(lpSystemPath, ":", &save);  | 
131  |  | 
  | 
132  | 0  |   while (path)  | 
133  | 0  |   { | 
134  | 0  |     filename = GetCombinedPath(path, application);  | 
135  |  | 
  | 
136  | 0  |     if (winpr_PathFileExists(filename))  | 
137  | 0  |     { | 
138  | 0  |       break;  | 
139  | 0  |     }  | 
140  |  |  | 
141  | 0  |     free(filename);  | 
142  | 0  |     filename = NULL;  | 
143  | 0  |     path = strtok_s(NULL, ":", &save);  | 
144  | 0  |   }  | 
145  |  | 
  | 
146  | 0  |   free(lpSystemPath);  | 
147  | 0  |   return filename;  | 
148  | 0  | }  | 
149  |  |  | 
150  |  | static HANDLE CreateProcessHandle(pid_t pid);  | 
151  |  | static BOOL ProcessHandleCloseHandle(HANDLE handle);  | 
152  |  |  | 
153  |  | static BOOL CreateProcessExA(HANDLE hToken, DWORD dwLogonFlags, LPCSTR lpApplicationName,  | 
154  |  |                              LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes,  | 
155  |  |                              LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles,  | 
156  |  |                              DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory,  | 
157  |  |                              LPSTARTUPINFOA lpStartupInfo,  | 
158  |  |                              LPPROCESS_INFORMATION lpProcessInformation)  | 
159  | 0  | { | 
160  | 0  |   pid_t pid = 0;  | 
161  | 0  |   int numArgs = 0;  | 
162  | 0  |   LPSTR* pArgs = NULL;  | 
163  | 0  |   char** envp = NULL;  | 
164  | 0  |   char* filename = NULL;  | 
165  | 0  |   HANDLE thread = NULL;  | 
166  | 0  |   HANDLE process = NULL;  | 
167  | 0  |   WINPR_ACCESS_TOKEN* token = NULL;  | 
168  | 0  |   LPTCH lpszEnvironmentBlock = NULL;  | 
169  | 0  |   BOOL ret = FALSE;  | 
170  | 0  |   sigset_t oldSigMask;  | 
171  | 0  |   sigset_t newSigMask;  | 
172  | 0  |   BOOL restoreSigMask = FALSE;  | 
173  | 0  |   numArgs = 0;  | 
174  | 0  |   lpszEnvironmentBlock = NULL;  | 
175  |  |   /* https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa  | 
176  |  |    */  | 
177  | 0  |   if (lpCommandLine)  | 
178  | 0  |     pArgs = CommandLineToArgvA(lpCommandLine, &numArgs);  | 
179  | 0  |   else  | 
180  | 0  |     pArgs = CommandLineToArgvA(lpApplicationName, &numArgs);  | 
181  |  | 
  | 
182  | 0  |   if (!pArgs)  | 
183  | 0  |     return FALSE;  | 
184  |  |  | 
185  | 0  |   token = (WINPR_ACCESS_TOKEN*)hToken;  | 
186  |  | 
  | 
187  | 0  |   if (lpEnvironment)  | 
188  | 0  |   { | 
189  | 0  |     envp = EnvironmentBlockToEnvpA(lpEnvironment);  | 
190  | 0  |   }  | 
191  | 0  |   else  | 
192  | 0  |   { | 
193  | 0  |     lpszEnvironmentBlock = GetEnvironmentStrings();  | 
194  |  | 
  | 
195  | 0  |     if (!lpszEnvironmentBlock)  | 
196  | 0  |       goto finish;  | 
197  |  |  | 
198  | 0  |     envp = EnvironmentBlockToEnvpA(lpszEnvironmentBlock);  | 
199  | 0  |   }  | 
200  |  |  | 
201  | 0  |   if (!envp)  | 
202  | 0  |     goto finish;  | 
203  |  |  | 
204  | 0  |   filename = FindApplicationPath(pArgs[0]);  | 
205  |  | 
  | 
206  | 0  |   if (NULL == filename)  | 
207  | 0  |     goto finish;  | 
208  |  |  | 
209  |  |   /* block all signals so that the child can safely reset the caller's handlers */  | 
210  | 0  |   sigfillset(&newSigMask);  | 
211  | 0  |   restoreSigMask = !pthread_sigmask(SIG_SETMASK, &newSigMask, &oldSigMask);  | 
212  |  |   /* fork and exec */  | 
213  | 0  |   pid = fork();  | 
214  |  | 
  | 
215  | 0  |   if (pid < 0)  | 
216  | 0  |   { | 
217  |  |     /* fork failure */  | 
218  | 0  |     goto finish;  | 
219  | 0  |   }  | 
220  |  |  | 
221  | 0  |   if (pid == 0)  | 
222  | 0  |   { | 
223  |  |     /* child process */  | 
224  | 0  | #ifndef __sun  | 
225  | 0  |     int maxfd = 0;  | 
226  | 0  | #endif  | 
227  | 0  |     sigset_t set = { 0 }; | 
228  | 0  |     struct sigaction act = { 0 }; | 
229  |  |     /* set default signal handlers */  | 
230  | 0  |     act.sa_handler = SIG_DFL;  | 
231  | 0  |     act.sa_flags = 0;  | 
232  | 0  |     sigemptyset(&act.sa_mask);  | 
233  |  | 
  | 
234  | 0  |     for (int sig = 1; sig < NSIG; sig++)  | 
235  | 0  |       sigaction(sig, &act, NULL);  | 
236  |  |  | 
237  |  |     /* unblock all signals */  | 
238  | 0  |     sigfillset(&set);  | 
239  | 0  |     pthread_sigmask(SIG_UNBLOCK, &set, NULL);  | 
240  |  | 
  | 
241  | 0  |     if (lpStartupInfo)  | 
242  | 0  |     { | 
243  | 0  |       int handle_fd = 0;  | 
244  | 0  |       handle_fd = winpr_Handle_getFd(lpStartupInfo->hStdOutput);  | 
245  |  | 
  | 
246  | 0  |       if (handle_fd != -1)  | 
247  | 0  |         dup2(handle_fd, STDOUT_FILENO);  | 
248  |  | 
  | 
249  | 0  |       handle_fd = winpr_Handle_getFd(lpStartupInfo->hStdError);  | 
250  |  | 
  | 
251  | 0  |       if (handle_fd != -1)  | 
252  | 0  |         dup2(handle_fd, STDERR_FILENO);  | 
253  |  | 
  | 
254  | 0  |       handle_fd = winpr_Handle_getFd(lpStartupInfo->hStdInput);  | 
255  |  | 
  | 
256  | 0  |       if (handle_fd != -1)  | 
257  | 0  |         dup2(handle_fd, STDIN_FILENO);  | 
258  | 0  |     }  | 
259  |  | 
  | 
260  |  | #ifdef __sun  | 
261  |  |     closefrom(3);  | 
262  |  | #else  | 
263  |  | #ifdef F_MAXFD // on some BSD derivates  | 
264  |  |     maxfd = fcntl(0, F_MAXFD);  | 
265  |  | #else  | 
266  | 0  |     maxfd = sysconf(_SC_OPEN_MAX);  | 
267  | 0  | #endif  | 
268  |  | 
  | 
269  | 0  |     for (int fd = 3; fd < maxfd; fd++)  | 
270  | 0  |       close(fd);  | 
271  |  | 
  | 
272  | 0  | #endif // __sun  | 
273  |  | 
  | 
274  | 0  |     if (token)  | 
275  | 0  |     { | 
276  | 0  |       if (token->GroupId)  | 
277  | 0  |       { | 
278  | 0  |         int rc = setgid((gid_t)token->GroupId);  | 
279  |  | 
  | 
280  | 0  |         if (rc < 0)  | 
281  | 0  |         { | 
282  | 0  |         }  | 
283  | 0  |         else  | 
284  | 0  |         { | 
285  | 0  |           initgroups(token->Username, (gid_t)token->GroupId);  | 
286  | 0  |         }  | 
287  | 0  |       }  | 
288  |  | 
  | 
289  | 0  |       if (token->UserId)  | 
290  | 0  |       { | 
291  | 0  |         int rc = setuid((uid_t)token->UserId);  | 
292  | 0  |         if (rc != 0)  | 
293  | 0  |           goto finish;  | 
294  | 0  |       }  | 
295  | 0  |     }  | 
296  |  |  | 
297  |  |     /* TODO: add better cwd handling and error checking */  | 
298  | 0  |     if (lpCurrentDirectory && strlen(lpCurrentDirectory) > 0)  | 
299  | 0  |     { | 
300  | 0  |       int rc = chdir(lpCurrentDirectory);  | 
301  | 0  |       if (rc != 0)  | 
302  | 0  |         goto finish;  | 
303  | 0  |     }  | 
304  |  |  | 
305  | 0  |     if (execve(filename, pArgs, envp) < 0)  | 
306  | 0  |     { | 
307  |  |       /* execve failed - end the process */  | 
308  | 0  |       _exit(1);  | 
309  | 0  |     }  | 
310  | 0  |   }  | 
311  | 0  |   else  | 
312  | 0  |   { | 
313  |  |     /* parent process */  | 
314  | 0  |   }  | 
315  |  |  | 
316  | 0  |   process = CreateProcessHandle(pid);  | 
317  |  | 
  | 
318  | 0  |   if (!process)  | 
319  | 0  |   { | 
320  | 0  |     goto finish;  | 
321  | 0  |   }  | 
322  |  |  | 
323  | 0  |   thread = CreateNoneHandle();  | 
324  |  | 
  | 
325  | 0  |   if (!thread)  | 
326  | 0  |   { | 
327  | 0  |     ProcessHandleCloseHandle(process);  | 
328  | 0  |     goto finish;  | 
329  | 0  |   }  | 
330  |  |  | 
331  | 0  |   lpProcessInformation->hProcess = process;  | 
332  | 0  |   lpProcessInformation->hThread = thread;  | 
333  | 0  |   lpProcessInformation->dwProcessId = (DWORD)pid;  | 
334  | 0  |   lpProcessInformation->dwThreadId = (DWORD)pid;  | 
335  | 0  |   ret = TRUE;  | 
336  | 0  | finish:  | 
337  |  |  | 
338  |  |   /* restore caller's original signal mask */  | 
339  | 0  |   if (restoreSigMask)  | 
340  | 0  |     pthread_sigmask(SIG_SETMASK, &oldSigMask, NULL);  | 
341  |  | 
  | 
342  | 0  |   free(filename);  | 
343  | 0  |   free(pArgs);  | 
344  |  | 
  | 
345  | 0  |   if (lpszEnvironmentBlock)  | 
346  | 0  |     FreeEnvironmentStrings(lpszEnvironmentBlock);  | 
347  |  | 
  | 
348  | 0  |   if (envp)  | 
349  | 0  |   { | 
350  | 0  |     int i = 0;  | 
351  |  | 
  | 
352  | 0  |     while (envp[i])  | 
353  | 0  |     { | 
354  | 0  |       free(envp[i]);  | 
355  | 0  |       i++;  | 
356  | 0  |     }  | 
357  |  | 
  | 
358  | 0  |     free(envp);  | 
359  | 0  |   }  | 
360  |  | 
  | 
361  | 0  |   return ret;  | 
362  | 0  | }  | 
363  |  |  | 
364  |  | BOOL CreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine,  | 
365  |  |                     LPSECURITY_ATTRIBUTES lpProcessAttributes,  | 
366  |  |                     LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles,  | 
367  |  |                     DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory,  | 
368  |  |                     LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation)  | 
369  | 0  | { | 
370  | 0  |   return CreateProcessExA(NULL, 0, lpApplicationName, lpCommandLine, lpProcessAttributes,  | 
371  | 0  |                           lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,  | 
372  | 0  |                           lpCurrentDirectory, lpStartupInfo, lpProcessInformation);  | 
373  | 0  | }  | 
374  |  |  | 
375  |  | BOOL CreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine,  | 
376  |  |                     LPSECURITY_ATTRIBUTES lpProcessAttributes,  | 
377  |  |                     LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles,  | 
378  |  |                     DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory,  | 
379  |  |                     LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation)  | 
380  | 0  | { | 
381  | 0  |   return FALSE;  | 
382  | 0  | }  | 
383  |  |  | 
384  |  | BOOL CreateProcessAsUserA(HANDLE hToken, LPCSTR lpApplicationName, LPSTR lpCommandLine,  | 
385  |  |                           LPSECURITY_ATTRIBUTES lpProcessAttributes,  | 
386  |  |                           LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles,  | 
387  |  |                           DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory,  | 
388  |  |                           LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation)  | 
389  | 0  | { | 
390  | 0  |   return CreateProcessExA(hToken, 0, lpApplicationName, lpCommandLine, lpProcessAttributes,  | 
391  | 0  |                           lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,  | 
392  | 0  |                           lpCurrentDirectory, lpStartupInfo, lpProcessInformation);  | 
393  | 0  | }  | 
394  |  |  | 
395  |  | BOOL CreateProcessAsUserW(HANDLE hToken, LPCWSTR lpApplicationName, LPWSTR lpCommandLine,  | 
396  |  |                           LPSECURITY_ATTRIBUTES lpProcessAttributes,  | 
397  |  |                           LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles,  | 
398  |  |                           DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory,  | 
399  |  |                           LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation)  | 
400  | 0  | { | 
401  | 0  |   return FALSE;  | 
402  | 0  | }  | 
403  |  |  | 
404  |  | BOOL CreateProcessWithLogonA(LPCSTR lpUsername, LPCSTR lpDomain, LPCSTR lpPassword,  | 
405  |  |                              DWORD dwLogonFlags, LPCSTR lpApplicationName, LPSTR lpCommandLine,  | 
406  |  |                              DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory,  | 
407  |  |                              LPSTARTUPINFOA lpStartupInfo,  | 
408  |  |                              LPPROCESS_INFORMATION lpProcessInformation)  | 
409  | 0  | { | 
410  | 0  |   return FALSE;  | 
411  | 0  | }  | 
412  |  |  | 
413  |  | BOOL CreateProcessWithLogonW(LPCWSTR lpUsername, LPCWSTR lpDomain, LPCWSTR lpPassword,  | 
414  |  |                              DWORD dwLogonFlags, LPCWSTR lpApplicationName, LPWSTR lpCommandLine,  | 
415  |  |                              DWORD dwCreationFlags, LPVOID lpEnvironment,  | 
416  |  |                              LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo,  | 
417  |  |                              LPPROCESS_INFORMATION lpProcessInformation)  | 
418  | 0  | { | 
419  | 0  |   return FALSE;  | 
420  | 0  | }  | 
421  |  |  | 
422  |  | BOOL CreateProcessWithTokenA(HANDLE hToken, DWORD dwLogonFlags, LPCSTR lpApplicationName,  | 
423  |  |                              LPSTR lpCommandLine, DWORD dwCreationFlags, LPVOID lpEnvironment,  | 
424  |  |                              LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo,  | 
425  |  |                              LPPROCESS_INFORMATION lpProcessInformation)  | 
426  | 0  | { | 
427  | 0  |   return CreateProcessExA(NULL, 0, lpApplicationName, lpCommandLine, NULL, NULL, FALSE,  | 
428  | 0  |                           dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo,  | 
429  | 0  |                           lpProcessInformation);  | 
430  | 0  | }  | 
431  |  |  | 
432  |  | BOOL CreateProcessWithTokenW(HANDLE hToken, DWORD dwLogonFlags, LPCWSTR lpApplicationName,  | 
433  |  |                              LPWSTR lpCommandLine, DWORD dwCreationFlags, LPVOID lpEnvironment,  | 
434  |  |                              LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo,  | 
435  |  |                              LPPROCESS_INFORMATION lpProcessInformation)  | 
436  | 0  | { | 
437  | 0  |   return FALSE;  | 
438  | 0  | }  | 
439  |  |  | 
440  |  | VOID ExitProcess(UINT uExitCode)  | 
441  | 0  | { | 
442  | 0  |   exit((int)uExitCode);  | 
443  | 0  | }  | 
444  |  |  | 
445  |  | BOOL GetExitCodeProcess(HANDLE hProcess, LPDWORD lpExitCode)  | 
446  | 0  | { | 
447  | 0  |   WINPR_PROCESS* process = NULL;  | 
448  |  | 
  | 
449  | 0  |   if (!hProcess)  | 
450  | 0  |     return FALSE;  | 
451  |  |  | 
452  | 0  |   if (!lpExitCode)  | 
453  | 0  |     return FALSE;  | 
454  |  |  | 
455  | 0  |   process = (WINPR_PROCESS*)hProcess;  | 
456  | 0  |   *lpExitCode = process->dwExitCode;  | 
457  | 0  |   return TRUE;  | 
458  | 0  | }  | 
459  |  |  | 
460  |  | HANDLE _GetCurrentProcess(VOID)  | 
461  | 0  | { | 
462  | 0  |   return NULL;  | 
463  | 0  | }  | 
464  |  |  | 
465  |  | DWORD GetCurrentProcessId(VOID)  | 
466  | 8.11M  | { | 
467  | 8.11M  |   return ((DWORD)getpid());  | 
468  | 8.11M  | }  | 
469  |  |  | 
470  |  | BOOL TerminateProcess(HANDLE hProcess, UINT uExitCode)  | 
471  | 0  | { | 
472  | 0  |   WINPR_PROCESS* process = NULL;  | 
473  | 0  |   process = (WINPR_PROCESS*)hProcess;  | 
474  |  | 
  | 
475  | 0  |   if (!process || (process->pid <= 0))  | 
476  | 0  |     return FALSE;  | 
477  |  |  | 
478  | 0  |   if (kill(process->pid, SIGTERM))  | 
479  | 0  |     return FALSE;  | 
480  |  |  | 
481  | 0  |   return TRUE;  | 
482  | 0  | }  | 
483  |  |  | 
484  |  | static BOOL ProcessHandleCloseHandle(HANDLE handle)  | 
485  | 0  | { | 
486  | 0  |   WINPR_PROCESS* process = (WINPR_PROCESS*)handle;  | 
487  | 0  |   WINPR_ASSERT(process);  | 
488  | 0  |   if (process->fd >= 0)  | 
489  | 0  |   { | 
490  | 0  |     close(process->fd);  | 
491  | 0  |     process->fd = -1;  | 
492  | 0  |   }  | 
493  | 0  |   free(process);  | 
494  | 0  |   return TRUE;  | 
495  | 0  | }  | 
496  |  |  | 
497  |  | static BOOL ProcessHandleIsHandle(HANDLE handle)  | 
498  | 0  | { | 
499  | 0  |   return WINPR_HANDLE_IS_HANDLED(handle, HANDLE_TYPE_PROCESS, FALSE);  | 
500  | 0  | }  | 
501  |  |  | 
502  |  | static int ProcessGetFd(HANDLE handle)  | 
503  | 0  | { | 
504  | 0  |   WINPR_PROCESS* process = (WINPR_PROCESS*)handle;  | 
505  |  | 
  | 
506  | 0  |   if (!ProcessHandleIsHandle(handle))  | 
507  | 0  |     return -1;  | 
508  |  |  | 
509  | 0  |   return process->fd;  | 
510  | 0  | }  | 
511  |  |  | 
512  |  | static DWORD ProcessCleanupHandle(HANDLE handle)  | 
513  | 0  | { | 
514  | 0  |   WINPR_PROCESS* process = (WINPR_PROCESS*)handle;  | 
515  |  | 
  | 
516  | 0  |   WINPR_ASSERT(process);  | 
517  | 0  |   if (process->fd > 0)  | 
518  | 0  |   { | 
519  | 0  |     if (waitpid(process->pid, &process->status, WNOHANG) == process->pid)  | 
520  | 0  |       process->dwExitCode = (DWORD)process->status;  | 
521  | 0  |   }  | 
522  | 0  |   return WAIT_OBJECT_0;  | 
523  | 0  | }  | 
524  |  |  | 
525  |  | static HANDLE_OPS ops = { ProcessHandleIsHandle, | 
526  |  |                         ProcessHandleCloseHandle,  | 
527  |  |                         ProcessGetFd,  | 
528  |  |                         ProcessCleanupHandle, /* CleanupHandle */  | 
529  |  |                         NULL,  | 
530  |  |                         NULL,  | 
531  |  |                         NULL,  | 
532  |  |                         NULL,  | 
533  |  |                         NULL,  | 
534  |  |                         NULL,  | 
535  |  |                         NULL,  | 
536  |  |                         NULL,  | 
537  |  |                         NULL,  | 
538  |  |                         NULL,  | 
539  |  |                         NULL,  | 
540  |  |                         NULL,  | 
541  |  |                         NULL,  | 
542  |  |                         NULL,  | 
543  |  |                         NULL,  | 
544  |  |                         NULL,  | 
545  |  |                         NULL };  | 
546  |  |  | 
547  |  | static int pidfd_open(pid_t pid)  | 
548  | 0  | { | 
549  | 0  | #ifdef __linux__  | 
550  |  | #if !defined(__NR_pidfd_open)  | 
551  |  | #define __NR_pidfd_open 434  | 
552  |  | #endif /* __NR_pidfd_open */  | 
553  |  | 
  | 
554  | 0  | #ifndef PIDFD_NONBLOCK  | 
555  | 0  | #define PIDFD_NONBLOCK O_NONBLOCK  | 
556  | 0  | #endif /* PIDFD_NONBLOCK */  | 
557  |  | 
  | 
558  | 0  |   int fd = syscall(__NR_pidfd_open, pid, PIDFD_NONBLOCK);  | 
559  | 0  |   if (fd < 0 && errno == EINVAL)  | 
560  | 0  |   { | 
561  |  |     /* possibly PIDFD_NONBLOCK is not supported, let's try to create a pidfd and set it  | 
562  |  |      * non blocking afterward */  | 
563  | 0  |     int flags = 0;  | 
564  | 0  |     fd = syscall(__NR_pidfd_open, pid, 0);  | 
565  | 0  |     if (fd < 0)  | 
566  | 0  |       return -1;  | 
567  |  |  | 
568  | 0  |     flags = fcntl(fd, F_GETFL);  | 
569  | 0  |     if (flags < 0 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0)  | 
570  | 0  |     { | 
571  | 0  |       close(fd);  | 
572  | 0  |       fd = -1;  | 
573  | 0  |     }  | 
574  | 0  |   }  | 
575  | 0  |   return fd;  | 
576  |  | #else  | 
577  |  |   return -1;  | 
578  |  | #endif  | 
579  | 0  | }  | 
580  |  |  | 
581  |  | HANDLE CreateProcessHandle(pid_t pid)  | 
582  | 0  | { | 
583  | 0  |   WINPR_PROCESS* process = NULL;  | 
584  | 0  |   process = (WINPR_PROCESS*)calloc(1, sizeof(WINPR_PROCESS));  | 
585  |  | 
  | 
586  | 0  |   if (!process)  | 
587  | 0  |     return NULL;  | 
588  |  |  | 
589  | 0  |   process->pid = pid;  | 
590  | 0  |   process->common.Type = HANDLE_TYPE_PROCESS;  | 
591  | 0  |   process->common.ops = &ops;  | 
592  | 0  |   process->fd = pidfd_open(pid);  | 
593  | 0  |   if (process->fd >= 0)  | 
594  | 0  |     process->common.Mode = WINPR_FD_READ;  | 
595  | 0  |   return (HANDLE)process;  | 
596  | 0  | }  | 
597  |  |  | 
598  |  | #endif  |