Coverage Report

Created: 2026-05-16 06:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/FreeRDP/winpr/libwinpr/thread/process.c
Line
Count
Source
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
#include <winpr/wlog.h>
28
29
/**
30
 * CreateProcessA
31
 * CreateProcessW
32
 * CreateProcessAsUserA
33
 * CreateProcessAsUserW
34
 * ExitProcess
35
 * GetCurrentProcess
36
 * GetCurrentProcessId
37
 * GetExitCodeProcess
38
 * GetProcessHandleCount
39
 * GetProcessId
40
 * GetProcessIdOfThread
41
 * GetProcessMitigationPolicy
42
 * GetProcessTimes
43
 * GetProcessVersion
44
 * OpenProcess
45
 * OpenProcessToken
46
 * ProcessIdToSessionId
47
 * SetProcessAffinityUpdateMode
48
 * SetProcessMitigationPolicy
49
 * SetProcessShutdownParameters
50
 * TerminateProcess
51
 */
52
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
84
/**
85
 * If the file name does not contain a directory path, the system searches for the executable file
86
 * in the following sequence:
87
 *
88
 * 1) The directory from which the application loaded.
89
 * 2) The current directory for the parent process.
90
 * 3) The 32-bit Windows system directory. Use the GetSystemDirectory function to get the path of
91
 * this directory. 4) The 16-bit Windows system directory. There is no function that obtains the
92
 * path of this directory, but it is searched. The name of this directory is System. 5) The Windows
93
 * directory. Use the GetWindowsDirectory function to get the path of this directory. 6) The
94
 * directories that are listed in the PATH environment variable. Note that this function does not
95
 * search the per-application path specified by the App Paths registry key. To include this
96
 * per-application path in the search sequence, use the ShellExecute function.
97
 */
98
99
static char* FindApplicationPath(char* application)
100
0
{
101
0
  LPCSTR pathName = "PATH";
102
0
  char* path = nullptr;
103
0
  char* save = nullptr;
104
0
  DWORD nSize = 0;
105
0
  LPSTR lpSystemPath = nullptr;
106
0
  char* filename = nullptr;
107
108
0
  if (!application)
109
0
    return nullptr;
110
111
0
  if (application[0] == '/')
112
0
    return _strdup(application);
113
114
0
  nSize = GetEnvironmentVariableA(pathName, nullptr, 0);
115
116
0
  if (!nSize)
117
0
    return _strdup(application);
118
119
0
  lpSystemPath = (LPSTR)malloc(nSize);
120
121
0
  if (!lpSystemPath)
122
0
    return nullptr;
123
124
0
  if (GetEnvironmentVariableA(pathName, lpSystemPath, nSize) != nSize - 1)
125
0
  {
126
0
    free(lpSystemPath);
127
0
    return nullptr;
128
0
  }
129
130
0
  save = nullptr;
131
0
  path = strtok_s(lpSystemPath, ":", &save);
132
133
0
  while (path)
134
0
  {
135
0
    filename = GetCombinedPath(path, application);
136
137
0
    if (winpr_PathFileExists(filename))
138
0
    {
139
0
      break;
140
0
    }
141
142
0
    free(filename);
143
0
    filename = nullptr;
144
0
    path = strtok_s(nullptr, ":", &save);
145
0
  }
146
147
0
  free(lpSystemPath);
148
0
  return filename;
149
0
}
150
151
static HANDLE CreateProcessHandle(pid_t pid);
152
static BOOL ProcessHandleCloseHandle(HANDLE handle);
153
154
static 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
0
{
163
0
  pid_t pid = 0;
164
0
  int numArgs = 0;
165
0
  LPSTR* pArgs = nullptr;
166
0
  char** envp = nullptr;
167
0
  char* filename = nullptr;
168
0
  HANDLE thread = nullptr;
169
0
  HANDLE process = nullptr;
170
0
  WINPR_ACCESS_TOKEN* token = nullptr;
171
0
  LPTCH lpszEnvironmentBlock = nullptr;
172
0
  BOOL ret = FALSE;
173
0
  sigset_t oldSigMask;
174
0
  sigset_t newSigMask;
175
0
  BOOL restoreSigMask = FALSE;
176
0
  numArgs = 0;
177
0
  lpszEnvironmentBlock = nullptr;
178
  /* https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa
179
   */
180
181
0
  if (lpCommandLine && lpApplicationName)
182
0
  {
183
0
    char* str = nullptr;
184
0
    size_t len = 0;
185
0
    winpr_asprintf(&str, &len, "%s %s", lpApplicationName, lpCommandLine);
186
0
    if (!str)
187
0
      return FALSE;
188
0
    pArgs = CommandLineToArgvA(str, &numArgs);
189
0
    free(str);
190
0
  }
191
0
  else if (lpCommandLine)
192
0
    pArgs = CommandLineToArgvA(lpCommandLine, &numArgs);
193
0
  else
194
0
    pArgs = CommandLineToArgvA(lpApplicationName, &numArgs);
195
196
0
  if (!pArgs)
197
0
    return FALSE;
198
199
0
  token = (WINPR_ACCESS_TOKEN*)hToken;
200
201
0
  if (lpEnvironment)
202
0
  {
203
0
    envp = EnvironmentBlockToEnvpA(lpEnvironment);
204
0
  }
205
0
  else
206
0
  {
207
0
    lpszEnvironmentBlock = GetEnvironmentStrings();
208
209
0
    if (!lpszEnvironmentBlock)
210
0
      goto finish;
211
212
0
    envp = EnvironmentBlockToEnvpA(lpszEnvironmentBlock);
213
0
  }
214
215
0
  if (!envp)
216
0
    goto finish;
217
218
0
  filename = FindApplicationPath(pArgs[0]);
219
220
0
  if (nullptr == filename)
221
0
    goto finish;
222
223
  /* block all signals so that the child can safely reset the caller's handlers */
224
0
  sigfillset(&newSigMask);
225
0
  restoreSigMask = !pthread_sigmask(SIG_SETMASK, &newSigMask, &oldSigMask);
226
  /* fork and exec */
227
0
  pid = fork();
228
229
0
  if (pid < 0)
230
0
  {
231
    /* fork failure */
232
0
    goto finish;
233
0
  }
234
235
0
  if (pid == 0)
236
0
  {
237
    /* child process */
238
0
#ifndef __sun
239
0
    int maxfd = 0;
240
0
#endif
241
0
    sigset_t set = WINPR_C_ARRAY_INIT;
242
0
    struct sigaction act = WINPR_C_ARRAY_INIT;
243
    /* set default signal handlers */
244
0
    act.sa_handler = SIG_DFL;
245
0
    act.sa_flags = 0;
246
0
    sigemptyset(&act.sa_mask);
247
248
0
    for (int sig = 1; sig < NSIG; sig++)
249
0
      sigaction(sig, &act, nullptr);
250
251
    /* unblock all signals */
252
0
    sigfillset(&set);
253
0
    pthread_sigmask(SIG_UNBLOCK, &set, nullptr);
254
255
0
    if (lpStartupInfo)
256
0
    {
257
0
      int handle_fd = 0;
258
0
      handle_fd = winpr_Handle_getFd(lpStartupInfo->hStdOutput);
259
260
0
      if (handle_fd != -1)
261
0
        dup2(handle_fd, STDOUT_FILENO);
262
263
0
      handle_fd = winpr_Handle_getFd(lpStartupInfo->hStdError);
264
265
0
      if (handle_fd != -1)
266
0
        dup2(handle_fd, STDERR_FILENO);
267
268
0
      handle_fd = winpr_Handle_getFd(lpStartupInfo->hStdInput);
269
270
0
      if (handle_fd != -1)
271
0
        dup2(handle_fd, STDIN_FILENO);
272
0
    }
273
274
#ifdef __sun
275
    closefrom(3);
276
#else
277
#ifdef F_MAXFD // on some BSD derivates
278
    maxfd = fcntl(0, F_MAXFD);
279
#else
280
0
    {
281
0
      const long rc = sysconf(_SC_OPEN_MAX);
282
0
      if ((rc < INT32_MIN) || (rc > INT32_MAX))
283
0
        goto finish;
284
0
      maxfd = (int)rc;
285
0
    }
286
0
#endif
287
288
0
    for (int fd = 3; fd < maxfd; fd++)
289
0
      close(fd);
290
291
0
#endif // __sun
292
293
0
    if (token)
294
0
    {
295
0
      if (token->GroupId)
296
0
      {
297
0
        int rc = setgid((gid_t)token->GroupId);
298
299
0
        if (rc < 0)
300
0
        {
301
0
        }
302
0
        else
303
0
        {
304
0
          initgroups(token->Username, (gid_t)token->GroupId);
305
0
        }
306
0
      }
307
308
0
      if (token->UserId)
309
0
      {
310
0
        int rc = setuid((uid_t)token->UserId);
311
0
        if (rc != 0)
312
0
          goto finish;
313
0
      }
314
0
    }
315
316
    /* TODO: add better cwd handling and error checking */
317
0
    if (lpCurrentDirectory && strlen(lpCurrentDirectory) > 0)
318
0
    {
319
0
      int rc = chdir(lpCurrentDirectory);
320
0
      if (rc != 0)
321
0
        goto finish;
322
0
    }
323
324
0
    if (execve(filename, pArgs, envp) < 0)
325
0
    {
326
      /* execve failed - end the process */
327
0
      _exit(1);
328
0
    }
329
0
  }
330
0
  else
331
0
  {
332
    /* parent process */
333
0
  }
334
335
0
  process = CreateProcessHandle(pid);
336
337
0
  if (!process)
338
0
  {
339
0
    goto finish;
340
0
  }
341
342
0
  thread = CreateNoneHandle();
343
344
0
  if (!thread)
345
0
  {
346
0
    ProcessHandleCloseHandle(process);
347
0
    goto finish;
348
0
  }
349
350
0
  lpProcessInformation->hProcess = process;
351
0
  lpProcessInformation->hThread = thread;
352
0
  lpProcessInformation->dwProcessId = (DWORD)pid;
353
0
  lpProcessInformation->dwThreadId = (DWORD)pid;
354
0
  ret = TRUE;
355
0
finish:
356
357
  /* restore caller's original signal mask */
358
0
  if (restoreSigMask)
359
0
    pthread_sigmask(SIG_SETMASK, &oldSigMask, nullptr);
360
361
0
  free(filename);
362
0
  free((void*)pArgs);
363
364
0
  if (lpszEnvironmentBlock)
365
0
    FreeEnvironmentStrings(lpszEnvironmentBlock);
366
367
0
  if (envp)
368
0
  {
369
0
    int i = 0;
370
371
0
    while (envp[i])
372
0
    {
373
0
      free(envp[i]);
374
0
      i++;
375
0
    }
376
377
0
    free((void*)envp);
378
0
  }
379
380
0
  return ret;
381
0
}
382
383
BOOL CreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine,
384
                    LPSECURITY_ATTRIBUTES lpProcessAttributes,
385
                    LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles,
386
                    DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory,
387
                    LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation)
388
0
{
389
0
  return CreateProcessExA(nullptr, 0, lpApplicationName, lpCommandLine, lpProcessAttributes,
390
0
                          lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,
391
0
                          lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
392
0
}
393
394
BOOL CreateProcessW(WINPR_ATTR_UNUSED LPCWSTR lpApplicationName,
395
                    WINPR_ATTR_UNUSED LPWSTR lpCommandLine,
396
                    WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpProcessAttributes,
397
                    WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpThreadAttributes,
398
                    WINPR_ATTR_UNUSED BOOL bInheritHandles, WINPR_ATTR_UNUSED DWORD dwCreationFlags,
399
                    WINPR_ATTR_UNUSED LPVOID lpEnvironment,
400
                    WINPR_ATTR_UNUSED LPCWSTR lpCurrentDirectory,
401
                    WINPR_ATTR_UNUSED LPSTARTUPINFOW lpStartupInfo,
402
                    WINPR_ATTR_UNUSED LPPROCESS_INFORMATION lpProcessInformation)
403
0
{
404
0
  WINPR_ASSERT(lpStartupInfo);
405
0
  WINPR_ASSERT(lpProcessInformation);
406
407
0
  LPSTR lpApplicationNameA = nullptr;
408
0
  LPSTR lpCommandLineA = nullptr;
409
0
  LPSTR lpCurrentDirectoryA = nullptr;
410
0
  STARTUPINFOA StartupInfoA = { .cb = sizeof(STARTUPINFOA),
411
0
                              .lpReserved = nullptr,
412
0
                              .lpDesktop = nullptr,
413
0
                              .lpTitle = nullptr,
414
0
                              .dwX = lpStartupInfo->dwX,
415
0
                              .dwY = lpStartupInfo->dwY,
416
0
                              .dwXSize = lpStartupInfo->dwXSize,
417
0
                              .dwYSize = lpStartupInfo->dwYSize,
418
0
                              .dwXCountChars = lpStartupInfo->dwXCountChars,
419
0
                              .dwYCountChars = lpStartupInfo->dwYCountChars,
420
0
                              .dwFillAttribute = lpStartupInfo->dwFillAttribute,
421
0
                              .dwFlags = lpStartupInfo->dwFlags,
422
0
                              .wShowWindow = lpStartupInfo->wShowWindow,
423
0
                              .cbReserved2 = lpStartupInfo->cbReserved2,
424
0
                              .lpReserved2 = lpStartupInfo->lpReserved2,
425
0
                              .hStdInput = lpStartupInfo->hStdInput,
426
0
                              .hStdOutput = lpStartupInfo->hStdOutput,
427
0
                              .hStdError = lpStartupInfo->hStdError };
428
429
0
  BOOL rc = FALSE;
430
0
  if (lpApplicationName)
431
0
  {
432
0
    lpApplicationNameA = ConvertWCharToUtf8Alloc(lpApplicationName, nullptr);
433
0
    if (!lpApplicationNameA)
434
0
      goto fail;
435
0
  }
436
0
  if (lpCommandLine)
437
0
  {
438
0
    lpCommandLineA = ConvertWCharToUtf8Alloc(lpCommandLine, nullptr);
439
0
    if (!lpCommandLineA)
440
0
      goto fail;
441
0
  }
442
0
  if (lpCurrentDirectory)
443
0
  {
444
0
    lpCurrentDirectoryA = ConvertWCharToUtf8Alloc(lpCurrentDirectory, nullptr);
445
0
    if (!lpCurrentDirectoryA)
446
0
      goto fail;
447
0
  }
448
0
  if (lpStartupInfo->lpReserved)
449
0
  {
450
0
    StartupInfoA.lpReserved = ConvertWCharToUtf8Alloc(lpStartupInfo->lpReserved, nullptr);
451
0
    if (!StartupInfoA.lpReserved)
452
0
      goto fail;
453
0
  }
454
0
  if (lpStartupInfo->lpDesktop)
455
0
  {
456
0
    StartupInfoA.lpDesktop = ConvertWCharToUtf8Alloc(lpStartupInfo->lpDesktop, nullptr);
457
0
    if (!StartupInfoA.lpDesktop)
458
0
      goto fail;
459
0
  }
460
0
  if (lpStartupInfo->lpTitle)
461
0
  {
462
0
    StartupInfoA.lpTitle = ConvertWCharToUtf8Alloc(lpStartupInfo->lpTitle, nullptr);
463
0
    if (!StartupInfoA.lpTitle)
464
0
      goto fail;
465
0
  }
466
467
0
  rc = CreateProcessA(lpApplicationNameA, lpCommandLineA, lpProcessAttributes, lpThreadAttributes,
468
0
                      bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectoryA,
469
0
                      &StartupInfoA, lpProcessInformation);
470
0
fail:
471
0
  free(lpApplicationNameA);
472
0
  free(lpCommandLineA);
473
0
  free(lpCurrentDirectoryA);
474
0
  free(StartupInfoA.lpDesktop);
475
0
  free(StartupInfoA.lpReserved);
476
0
  free(StartupInfoA.lpTitle);
477
0
  return rc;
478
0
}
479
480
BOOL CreateProcessAsUserA(HANDLE hToken, LPCSTR lpApplicationName, LPSTR lpCommandLine,
481
                          LPSECURITY_ATTRIBUTES lpProcessAttributes,
482
                          LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles,
483
                          DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory,
484
                          LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation)
485
0
{
486
0
  return CreateProcessExA(hToken, 0, lpApplicationName, lpCommandLine, lpProcessAttributes,
487
0
                          lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,
488
0
                          lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
489
0
}
490
491
BOOL CreateProcessAsUserW(WINPR_ATTR_UNUSED HANDLE hToken,
492
                          WINPR_ATTR_UNUSED LPCWSTR lpApplicationName,
493
                          WINPR_ATTR_UNUSED LPWSTR lpCommandLine,
494
                          WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpProcessAttributes,
495
                          WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpThreadAttributes,
496
                          WINPR_ATTR_UNUSED BOOL bInheritHandles,
497
                          WINPR_ATTR_UNUSED DWORD dwCreationFlags,
498
                          WINPR_ATTR_UNUSED LPVOID lpEnvironment,
499
                          WINPR_ATTR_UNUSED LPCWSTR lpCurrentDirectory,
500
                          WINPR_ATTR_UNUSED LPSTARTUPINFOW lpStartupInfo,
501
                          WINPR_ATTR_UNUSED LPPROCESS_INFORMATION lpProcessInformation)
502
0
{
503
0
  WLog_ERR("TODO", "TODO: implement");
504
0
  return FALSE;
505
0
}
506
507
BOOL CreateProcessWithLogonA(
508
    WINPR_ATTR_UNUSED LPCSTR lpUsername, WINPR_ATTR_UNUSED LPCSTR lpDomain,
509
    WINPR_ATTR_UNUSED LPCSTR lpPassword, WINPR_ATTR_UNUSED DWORD dwLogonFlags,
510
    WINPR_ATTR_UNUSED LPCSTR lpApplicationName, WINPR_ATTR_UNUSED LPSTR lpCommandLine,
511
    WINPR_ATTR_UNUSED DWORD dwCreationFlags, WINPR_ATTR_UNUSED LPVOID lpEnvironment,
512
    WINPR_ATTR_UNUSED LPCSTR lpCurrentDirectory, WINPR_ATTR_UNUSED LPSTARTUPINFOA lpStartupInfo,
513
    WINPR_ATTR_UNUSED LPPROCESS_INFORMATION lpProcessInformation)
514
0
{
515
0
  WLog_ERR("TODO", "TODO: implement");
516
0
  return FALSE;
517
0
}
518
519
BOOL CreateProcessWithLogonW(
520
    WINPR_ATTR_UNUSED LPCWSTR lpUsername, WINPR_ATTR_UNUSED LPCWSTR lpDomain,
521
    WINPR_ATTR_UNUSED LPCWSTR lpPassword, WINPR_ATTR_UNUSED DWORD dwLogonFlags,
522
    WINPR_ATTR_UNUSED LPCWSTR lpApplicationName, WINPR_ATTR_UNUSED LPWSTR lpCommandLine,
523
    WINPR_ATTR_UNUSED DWORD dwCreationFlags, WINPR_ATTR_UNUSED LPVOID lpEnvironment,
524
    WINPR_ATTR_UNUSED LPCWSTR lpCurrentDirectory, WINPR_ATTR_UNUSED LPSTARTUPINFOW lpStartupInfo,
525
    WINPR_ATTR_UNUSED LPPROCESS_INFORMATION lpProcessInformation)
526
0
{
527
0
  WLog_ERR("TODO", "TODO: implement");
528
0
  return FALSE;
529
0
}
530
531
BOOL CreateProcessWithTokenA(WINPR_ATTR_UNUSED HANDLE hToken, WINPR_ATTR_UNUSED DWORD dwLogonFlags,
532
                             LPCSTR lpApplicationName, LPSTR lpCommandLine, DWORD dwCreationFlags,
533
                             LPVOID lpEnvironment, LPCSTR lpCurrentDirectory,
534
                             LPSTARTUPINFOA lpStartupInfo,
535
                             LPPROCESS_INFORMATION lpProcessInformation)
536
0
{
537
0
  return CreateProcessExA(nullptr, 0, lpApplicationName, lpCommandLine, nullptr, nullptr, FALSE,
538
0
                          dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo,
539
0
                          lpProcessInformation);
540
0
}
541
542
BOOL CreateProcessWithTokenW(WINPR_ATTR_UNUSED HANDLE hToken, WINPR_ATTR_UNUSED DWORD dwLogonFlags,
543
                             WINPR_ATTR_UNUSED LPCWSTR lpApplicationName,
544
                             WINPR_ATTR_UNUSED LPWSTR lpCommandLine,
545
                             WINPR_ATTR_UNUSED DWORD dwCreationFlags,
546
                             WINPR_ATTR_UNUSED LPVOID lpEnvironment,
547
                             WINPR_ATTR_UNUSED LPCWSTR lpCurrentDirectory,
548
                             WINPR_ATTR_UNUSED LPSTARTUPINFOW lpStartupInfo,
549
                             WINPR_ATTR_UNUSED LPPROCESS_INFORMATION lpProcessInformation)
550
0
{
551
0
  WLog_ERR("TODO", "TODO: implement");
552
0
  return FALSE;
553
0
}
554
555
VOID ExitProcess(UINT uExitCode)
556
0
{
557
  // NOLINTNEXTLINE(concurrency-mt-unsafe)
558
0
  exit((int)uExitCode);
559
0
}
560
561
BOOL GetExitCodeProcess(HANDLE hProcess, LPDWORD lpExitCode)
562
0
{
563
0
  WINPR_PROCESS* process = nullptr;
564
565
0
  if (!hProcess)
566
0
    return FALSE;
567
568
0
  if (!lpExitCode)
569
0
    return FALSE;
570
571
0
  process = (WINPR_PROCESS*)hProcess;
572
0
  *lpExitCode = process->dwExitCode;
573
0
  return TRUE;
574
0
}
575
576
HANDLE _GetCurrentProcess(VOID)
577
0
{
578
0
  WLog_ERR("TODO", "TODO: implement");
579
0
  return nullptr;
580
0
}
581
582
DWORD GetCurrentProcessId(VOID)
583
9.06M
{
584
9.06M
  return ((DWORD)getpid());
585
9.06M
}
586
587
BOOL TerminateProcess(HANDLE hProcess, WINPR_ATTR_UNUSED UINT uExitCode)
588
0
{
589
0
  WINPR_PROCESS* process = nullptr;
590
0
  process = (WINPR_PROCESS*)hProcess;
591
592
0
  if (!process || (process->pid <= 0))
593
0
    return FALSE;
594
595
0
  if (kill(process->pid, SIGTERM))
596
0
    return FALSE;
597
598
0
  return TRUE;
599
0
}
600
601
static BOOL ProcessHandleCloseHandle(HANDLE handle)
602
0
{
603
0
  WINPR_PROCESS* process = (WINPR_PROCESS*)handle;
604
0
  WINPR_ASSERT(process);
605
0
  if (process->fd >= 0)
606
0
  {
607
0
    close(process->fd);
608
0
    process->fd = -1;
609
0
  }
610
0
  free(process);
611
0
  return TRUE;
612
0
}
613
614
static BOOL ProcessHandleIsHandle(HANDLE handle)
615
0
{
616
0
  return WINPR_HANDLE_IS_HANDLED(handle, HANDLE_TYPE_PROCESS, FALSE);
617
0
}
618
619
static int ProcessGetFd(HANDLE handle)
620
0
{
621
0
  WINPR_PROCESS* process = (WINPR_PROCESS*)handle;
622
623
0
  if (!ProcessHandleIsHandle(handle))
624
0
    return -1;
625
626
0
  return process->fd;
627
0
}
628
629
static DWORD ProcessCleanupHandle(HANDLE handle)
630
0
{
631
0
  WINPR_PROCESS* process = (WINPR_PROCESS*)handle;
632
633
0
  WINPR_ASSERT(process);
634
0
  if (process->fd > 0)
635
0
  {
636
0
    if (waitpid(process->pid, &process->status, WNOHANG) == process->pid)
637
0
    {
638
0
      if (WIFEXITED(process->status))
639
0
        process->dwExitCode = (DWORD)WEXITSTATUS(process->status);
640
0
      else if (WIFSIGNALED(process->status))
641
0
        process->dwExitCode = (DWORD)(128 + WTERMSIG(process->status));
642
0
      else
643
0
        process->dwExitCode = (DWORD)process->status;
644
0
    }
645
0
  }
646
0
  return WAIT_OBJECT_0;
647
0
}
648
649
static HANDLE_OPS ops = { ProcessHandleIsHandle,
650
                        ProcessHandleCloseHandle,
651
                        ProcessGetFd,
652
                        ProcessCleanupHandle, /* CleanupHandle */
653
                        nullptr,
654
                        nullptr,
655
                        nullptr,
656
                        nullptr,
657
                        nullptr,
658
                        nullptr,
659
                        nullptr,
660
                        nullptr,
661
                        nullptr,
662
                        nullptr,
663
                        nullptr,
664
                        nullptr,
665
                        nullptr,
666
                        nullptr,
667
                        nullptr,
668
                        nullptr,
669
                        nullptr };
670
671
static int pidfd_open(pid_t pid)
672
0
{
673
0
#ifdef __linux__
674
#if !defined(__NR_pidfd_open)
675
#define __NR_pidfd_open 434
676
#endif /* __NR_pidfd_open */
677
678
0
#ifndef PIDFD_NONBLOCK
679
0
#define PIDFD_NONBLOCK O_NONBLOCK
680
0
#endif /* PIDFD_NONBLOCK */
681
682
0
  long fd = syscall(__NR_pidfd_open, pid, PIDFD_NONBLOCK);
683
0
  if (fd < 0 && errno == EINVAL)
684
0
  {
685
    /* possibly PIDFD_NONBLOCK is not supported, let's try to create a pidfd and set it
686
     * non blocking afterward */
687
0
    int flags = 0;
688
0
    fd = syscall(__NR_pidfd_open, pid, 0);
689
0
    if ((fd < 0) || (fd > INT32_MAX))
690
0
      return -1;
691
692
0
    flags = fcntl((int)fd, F_GETFL);
693
0
    if ((flags < 0) || fcntl((int)fd, F_SETFL, flags | O_NONBLOCK) < 0)
694
0
    {
695
0
      close((int)fd);
696
0
      fd = -1;
697
0
    }
698
0
  }
699
0
  if ((fd < 0) || (fd > INT32_MAX))
700
0
    return -1;
701
0
  return (int)fd;
702
#else
703
  return -1;
704
#endif
705
0
}
706
707
HANDLE CreateProcessHandle(pid_t pid)
708
0
{
709
0
  WINPR_PROCESS* process = nullptr;
710
0
  process = (WINPR_PROCESS*)calloc(1, sizeof(WINPR_PROCESS));
711
712
0
  if (!process)
713
0
    return nullptr;
714
715
0
  process->pid = pid;
716
0
  process->common.Type = HANDLE_TYPE_PROCESS;
717
0
  process->common.ops = &ops;
718
0
  process->fd = pidfd_open(pid);
719
0
  if (process->fd >= 0)
720
0
    process->common.Mode = WINPR_FD_READ;
721
0
  return (HANDLE)process;
722
0
}
723
724
#endif