Coverage Report

Created: 2026-09-01 06:34

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 <fcntl.h>
63
#include <signal.h>
64
#include <sys/types.h>
65
#include <sys/wait.h>
66
67
#ifdef __linux__
68
#include <sys/syscall.h>
69
#include <errno.h>
70
#endif /* __linux__ */
71
72
#include "thread.h"
73
74
#include "../handle/handle.h"
75
#include "../security/security.h"
76
77
#ifndef NSIG
78
#ifdef SIGMAX
79
#define NSIG SIGMAX
80
#else
81
#define NSIG 64
82
#endif
83
#endif
84
85
/**
86
 * If the file name does not contain a directory path, the system searches for the executable file
87
 * in the following sequence:
88
 *
89
 * 1) The directory from which the application loaded.
90
 * 2) The current directory for the parent process.
91
 * 3) The 32-bit Windows system directory. Use the GetSystemDirectory function to get the path of
92
 * this directory. 4) The 16-bit Windows system directory. There is no function that obtains the
93
 * path of this directory, but it is searched. The name of this directory is System. 5) The Windows
94
 * directory. Use the GetWindowsDirectory function to get the path of this directory. 6) The
95
 * directories that are listed in the PATH environment variable. Note that this function does not
96
 * search the per-application path specified by the App Paths registry key. To include this
97
 * per-application path in the search sequence, use the ShellExecute function.
98
 */
99
100
static char* FindApplicationPath(char* application)
101
0
{
102
0
  LPCSTR pathName = "PATH";
103
0
  char* path = nullptr;
104
0
  char* save = nullptr;
105
0
  DWORD nSize = 0;
106
0
  LPSTR lpSystemPath = nullptr;
107
0
  char* filename = nullptr;
108
109
0
  if (!application)
110
0
    return nullptr;
111
112
0
  if (application[0] == '/')
113
0
    return _strdup(application);
114
115
0
  nSize = GetEnvironmentVariableA(pathName, nullptr, 0);
116
117
0
  if (!nSize)
118
0
    return _strdup(application);
119
120
0
  lpSystemPath = (LPSTR)malloc(nSize);
121
122
0
  if (!lpSystemPath)
123
0
    return nullptr;
124
125
0
  if (GetEnvironmentVariableA(pathName, lpSystemPath, nSize) != nSize - 1)
126
0
  {
127
0
    free(lpSystemPath);
128
0
    return nullptr;
129
0
  }
130
131
0
  save = nullptr;
132
0
  path = strtok_s(lpSystemPath, ":", &save);
133
134
0
  while (path)
135
0
  {
136
0
    filename = GetCombinedPath(path, application);
137
138
0
    if (winpr_PathFileExists(filename))
139
0
    {
140
0
      break;
141
0
    }
142
143
0
    free(filename);
144
0
    filename = nullptr;
145
0
    path = strtok_s(nullptr, ":", &save);
146
0
  }
147
148
0
  free(lpSystemPath);
149
0
  return filename;
150
0
}
151
152
static HANDLE CreateProcessHandle(pid_t pid);
153
static BOOL ProcessHandleCloseHandle(HANDLE handle);
154
155
static BOOL CreateProcessExA(HANDLE hToken, WINPR_ATTR_UNUSED DWORD dwLogonFlags,
156
                             LPCSTR lpApplicationName, WINPR_ATTR_UNUSED LPSTR lpCommandLine,
157
                             WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpProcessAttributes,
158
                             WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpThreadAttributes,
159
                             BOOL bInheritHandles, 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
  /* Windows validates a PROC_THREAD_ATTRIBUTE_HANDLE_LIST's handles are still open before
224
   * creating the process at all, failing the whole call with ERROR_INVALID_PARAMETER if one
225
   * isn't (confirmed empirically: a handle CloseHandle()'d before this call, still listed here,
226
   * makes real CreateProcess fail this way rather than silently omitting it) */
227
0
  if (bInheritHandles && lpStartupInfo && (dwCreationFlags & EXTENDED_STARTUPINFO_PRESENT))
228
0
  {
229
0
    const STARTUPINFOEXA* exInfo = (const STARTUPINFOEXA*)lpStartupInfo;
230
0
    const struct WINPR_PROC_THREAD_ATTRIBUTE_LIST* list = exInfo->lpAttributeList;
231
232
0
    for (DWORD i = 0; list && (i < list->count); i++)
233
0
    {
234
0
      const WINPR_PROC_THREAD_ATTRIBUTE_ENTRY* entry = &list->entries[i];
235
0
      if (entry->Attribute != PROC_THREAD_ATTRIBUTE_HANDLE_LIST)
236
0
        continue;
237
238
0
      const HANDLE* handles = (const HANDLE*)entry->lpValue;
239
0
      const size_t count = entry->cbSize / sizeof(HANDLE);
240
0
      for (size_t h = 0; h < count; h++)
241
0
      {
242
0
        if (winpr_Handle_getFd(handles[h]) < 0)
243
0
        {
244
0
          SetLastError(ERROR_INVALID_PARAMETER);
245
0
          goto finish;
246
0
        }
247
0
      }
248
0
    }
249
0
  }
250
251
  /* block all signals so that the child can safely reset the caller's handlers */
252
0
  sigfillset(&newSigMask);
253
0
  restoreSigMask = !pthread_sigmask(SIG_SETMASK, &newSigMask, &oldSigMask);
254
  /* fork and exec */
255
0
  pid = fork();
256
257
0
  if (pid < 0)
258
0
  {
259
    /* fork failure */
260
0
    goto finish;
261
0
  }
262
263
0
  if (pid == 0)
264
0
  {
265
    /* child process */
266
0
#ifndef __sun
267
0
    int maxfd = 0;
268
0
#endif
269
0
    sigset_t set = WINPR_C_ARRAY_INIT;
270
0
    struct sigaction act = WINPR_C_ARRAY_INIT;
271
272
    /* resolve an explicit PROC_THREAD_ATTRIBUTE_HANDLE_LIST, if the caller opted into one
273
     * via a STARTUPINFOEX + EXTENDED_STARTUPINFO_PRESENT. Per documented Windows behavior:
274
     *  - bInheritHandles == FALSE: nothing is inherited, full stop - a handle list (if any)
275
     *    is ignored too, it can only narrow inheritance, never expand it.
276
     *  - bInheritHandles == TRUE and a handle list is present: it becomes the *exclusive*
277
     *    source of truth for which extra fds survive into this child - only the listed
278
     *    handles are inherited, even other handles independently marked inheritable are not.
279
     *  - bInheritHandles == TRUE and no handle list: every fd not marked close-on-exec is
280
     *    inherited, exactly like real Windows inheriting every handle marked inheritable -
281
     *    including ones WinPR doesn't know about (e.g. opened by a linked library), since
282
     *    Windows itself has no concept of "handles the runtime knows about" either. */
283
0
#define WINPR_MAX_INHERITED_HANDLES 64
284
0
    int keepFds[WINPR_MAX_INHERITED_HANDLES] = { -1 };
285
0
    size_t nKeepFds = 0;
286
0
    BOOL haveHandleList = FALSE;
287
288
0
    if (bInheritHandles && lpStartupInfo && (dwCreationFlags & EXTENDED_STARTUPINFO_PRESENT))
289
0
    {
290
0
      const STARTUPINFOEXA* exInfo = (const STARTUPINFOEXA*)lpStartupInfo;
291
0
      const struct WINPR_PROC_THREAD_ATTRIBUTE_LIST* list = exInfo->lpAttributeList;
292
293
0
      for (DWORD i = 0; list && (i < list->count); i++)
294
0
      {
295
0
        const WINPR_PROC_THREAD_ATTRIBUTE_ENTRY* entry = &list->entries[i];
296
0
        if (entry->Attribute != PROC_THREAD_ATTRIBUTE_HANDLE_LIST)
297
0
          continue;
298
299
0
        haveHandleList = TRUE;
300
0
        const HANDLE* handles = (const HANDLE*)entry->lpValue;
301
0
        const size_t count = entry->cbSize / sizeof(HANDLE);
302
0
        for (size_t h = 0; (h < count) && (nKeepFds < WINPR_MAX_INHERITED_HANDLES); h++)
303
0
        {
304
0
          const int fd = winpr_Handle_getFd(handles[h]);
305
0
          if (fd >= 0)
306
0
            keepFds[nKeepFds++] = fd;
307
0
        }
308
0
      }
309
0
    }
310
311
    /* set default signal handlers */
312
0
    act.sa_handler = SIG_DFL;
313
0
    act.sa_flags = 0;
314
0
    sigemptyset(&act.sa_mask);
315
316
0
    for (int sig = 1; sig < NSIG; sig++)
317
0
      sigaction(sig, &act, nullptr);
318
319
    /* unblock all signals */
320
0
    sigfillset(&set);
321
0
    pthread_sigmask(SIG_UNBLOCK, &set, nullptr);
322
323
0
    if (lpStartupInfo)
324
0
    {
325
0
      int handle_fd = 0;
326
0
      handle_fd = winpr_Handle_getFd(lpStartupInfo->hStdOutput);
327
328
0
      if (handle_fd != -1)
329
0
        dup2(handle_fd, STDOUT_FILENO);
330
331
0
      handle_fd = winpr_Handle_getFd(lpStartupInfo->hStdError);
332
333
0
      if (handle_fd != -1)
334
0
        dup2(handle_fd, STDERR_FILENO);
335
336
0
      handle_fd = winpr_Handle_getFd(lpStartupInfo->hStdInput);
337
338
0
      if (handle_fd != -1)
339
0
        dup2(handle_fd, STDIN_FILENO);
340
0
    }
341
342
#ifdef __sun
343
    if (!bInheritHandles || !haveHandleList)
344
      closefrom(3);
345
    /* else: Solaris has no per-fd enumeration primitive as cheap as the loop below, and a
346
     * handle list is a narrow/rare case there - fall through without closing anything
347
     * rather than silently ignoring the caller's explicit allowlist. */
348
#else
349
#ifdef F_MAXFD // on some BSD derivates
350
    maxfd = fcntl(0, F_MAXFD);
351
#else
352
0
    {
353
0
      const long rc = sysconf(_SC_OPEN_MAX);
354
0
      if ((rc < INT32_MIN) || (rc > INT32_MAX))
355
0
        goto finish;
356
0
      maxfd = (int)rc;
357
0
    }
358
0
#endif
359
360
    /* - bInheritHandles == FALSE: keep stays FALSE for every fd, close everything.
361
     * - bInheritHandles == TRUE, handle list present: exclusive allowlist (see above).
362
     * - bInheritHandles == TRUE, no handle list: inherit everything not close-on-exec. */
363
0
    for (int fd = 3; fd < maxfd; fd++)
364
0
    {
365
0
      BOOL keep = FALSE;
366
367
0
      if (bInheritHandles)
368
0
      {
369
0
        if (haveHandleList)
370
0
        {
371
0
          for (size_t k = 0; k < nKeepFds; k++)
372
0
          {
373
0
            if (keepFds[k] == fd)
374
0
            {
375
0
              keep = TRUE;
376
0
              break;
377
0
            }
378
0
          }
379
0
        }
380
0
        else
381
0
        {
382
0
          const int flags = fcntl(fd, F_GETFD);
383
0
          keep = (flags >= 0) && !(flags & FD_CLOEXEC);
384
0
        }
385
0
      }
386
387
0
      if (!keep)
388
0
        close(fd);
389
0
    }
390
391
0
#endif // __sun
392
393
0
    if (token)
394
0
    {
395
0
      if (token->GroupId)
396
0
      {
397
0
        int rc = setgid((gid_t)token->GroupId);
398
399
0
        if (rc < 0)
400
0
        {
401
0
        }
402
0
        else
403
0
        {
404
0
          initgroups(token->Username, (gid_t)token->GroupId);
405
0
        }
406
0
      }
407
408
0
      if (token->UserId)
409
0
      {
410
0
        int rc = setuid((uid_t)token->UserId);
411
0
        if (rc != 0)
412
0
          goto finish;
413
0
      }
414
0
    }
415
416
    /* TODO: add better cwd handling and error checking */
417
0
    if (lpCurrentDirectory && strlen(lpCurrentDirectory) > 0)
418
0
    {
419
0
      int rc = chdir(lpCurrentDirectory);
420
0
      if (rc != 0)
421
0
        goto finish;
422
0
    }
423
424
0
    if (execve(filename, pArgs, envp) < 0)
425
0
    {
426
      /* execve failed - end the process */
427
0
      _exit(1);
428
0
    }
429
0
  }
430
0
  else
431
0
  {
432
    /* parent process */
433
0
  }
434
435
0
  process = CreateProcessHandle(pid);
436
437
0
  if (!process)
438
0
  {
439
0
    goto finish;
440
0
  }
441
442
0
  thread = CreateNoneHandle();
443
444
0
  if (!thread)
445
0
  {
446
0
    ProcessHandleCloseHandle(process);
447
0
    free(process);
448
0
    goto finish;
449
0
  }
450
451
0
  lpProcessInformation->hProcess = process;
452
0
  lpProcessInformation->hThread = thread;
453
0
  lpProcessInformation->dwProcessId = (DWORD)pid;
454
0
  lpProcessInformation->dwThreadId = (DWORD)pid;
455
0
  ret = TRUE;
456
0
finish:
457
458
  /* restore caller's original signal mask */
459
0
  if (restoreSigMask)
460
0
    pthread_sigmask(SIG_SETMASK, &oldSigMask, nullptr);
461
462
0
  free(filename);
463
0
  free((void*)pArgs);
464
465
0
  if (lpszEnvironmentBlock)
466
0
    FreeEnvironmentStrings(lpszEnvironmentBlock);
467
468
0
  if (envp)
469
0
  {
470
0
    int i = 0;
471
472
0
    while (envp[i])
473
0
    {
474
0
      free(envp[i]);
475
0
      i++;
476
0
    }
477
478
0
    free((void*)envp);
479
0
  }
480
481
0
  return ret;
482
0
}
483
484
BOOL CreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine,
485
                    LPSECURITY_ATTRIBUTES lpProcessAttributes,
486
                    LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles,
487
                    DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory,
488
                    LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation)
489
0
{
490
0
  return CreateProcessExA(nullptr, 0, lpApplicationName, lpCommandLine, lpProcessAttributes,
491
0
                          lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,
492
0
                          lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
493
0
}
494
495
BOOL CreateProcessW(WINPR_ATTR_UNUSED LPCWSTR lpApplicationName,
496
                    WINPR_ATTR_UNUSED LPWSTR lpCommandLine,
497
                    WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpProcessAttributes,
498
                    WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpThreadAttributes,
499
                    WINPR_ATTR_UNUSED BOOL bInheritHandles, WINPR_ATTR_UNUSED DWORD dwCreationFlags,
500
                    WINPR_ATTR_UNUSED LPVOID lpEnvironment,
501
                    WINPR_ATTR_UNUSED LPCWSTR lpCurrentDirectory,
502
                    WINPR_ATTR_UNUSED LPSTARTUPINFOW lpStartupInfo,
503
                    WINPR_ATTR_UNUSED LPPROCESS_INFORMATION lpProcessInformation)
504
0
{
505
0
  WINPR_ASSERT(lpStartupInfo);
506
0
  WINPR_ASSERT(lpProcessInformation);
507
508
0
  LPSTR lpApplicationNameA = nullptr;
509
0
  LPSTR lpCommandLineA = nullptr;
510
0
  LPSTR lpCurrentDirectoryA = nullptr;
511
0
  STARTUPINFOA StartupInfoA = { .cb = sizeof(STARTUPINFOA),
512
0
                              .lpReserved = nullptr,
513
0
                              .lpDesktop = nullptr,
514
0
                              .lpTitle = nullptr,
515
0
                              .dwX = lpStartupInfo->dwX,
516
0
                              .dwY = lpStartupInfo->dwY,
517
0
                              .dwXSize = lpStartupInfo->dwXSize,
518
0
                              .dwYSize = lpStartupInfo->dwYSize,
519
0
                              .dwXCountChars = lpStartupInfo->dwXCountChars,
520
0
                              .dwYCountChars = lpStartupInfo->dwYCountChars,
521
0
                              .dwFillAttribute = lpStartupInfo->dwFillAttribute,
522
0
                              .dwFlags = lpStartupInfo->dwFlags,
523
0
                              .wShowWindow = lpStartupInfo->wShowWindow,
524
0
                              .cbReserved2 = lpStartupInfo->cbReserved2,
525
0
                              .lpReserved2 = lpStartupInfo->lpReserved2,
526
0
                              .hStdInput = lpStartupInfo->hStdInput,
527
0
                              .hStdOutput = lpStartupInfo->hStdOutput,
528
0
                              .hStdError = lpStartupInfo->hStdError };
529
530
0
  BOOL rc = FALSE;
531
0
  if (lpApplicationName)
532
0
  {
533
0
    lpApplicationNameA = ConvertWCharToUtf8Alloc(lpApplicationName, nullptr);
534
0
    if (!lpApplicationNameA)
535
0
      goto fail;
536
0
  }
537
0
  if (lpCommandLine)
538
0
  {
539
0
    lpCommandLineA = ConvertWCharToUtf8Alloc(lpCommandLine, nullptr);
540
0
    if (!lpCommandLineA)
541
0
      goto fail;
542
0
  }
543
0
  if (lpCurrentDirectory)
544
0
  {
545
0
    lpCurrentDirectoryA = ConvertWCharToUtf8Alloc(lpCurrentDirectory, nullptr);
546
0
    if (!lpCurrentDirectoryA)
547
0
      goto fail;
548
0
  }
549
0
  if (lpStartupInfo->lpReserved)
550
0
  {
551
0
    StartupInfoA.lpReserved = ConvertWCharToUtf8Alloc(lpStartupInfo->lpReserved, nullptr);
552
0
    if (!StartupInfoA.lpReserved)
553
0
      goto fail;
554
0
  }
555
0
  if (lpStartupInfo->lpDesktop)
556
0
  {
557
0
    StartupInfoA.lpDesktop = ConvertWCharToUtf8Alloc(lpStartupInfo->lpDesktop, nullptr);
558
0
    if (!StartupInfoA.lpDesktop)
559
0
      goto fail;
560
0
  }
561
0
  if (lpStartupInfo->lpTitle)
562
0
  {
563
0
    StartupInfoA.lpTitle = ConvertWCharToUtf8Alloc(lpStartupInfo->lpTitle, nullptr);
564
0
    if (!StartupInfoA.lpTitle)
565
0
      goto fail;
566
0
  }
567
568
0
  rc = CreateProcessA(lpApplicationNameA, lpCommandLineA, lpProcessAttributes, lpThreadAttributes,
569
0
                      bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectoryA,
570
0
                      &StartupInfoA, lpProcessInformation);
571
0
fail:
572
0
  free(lpApplicationNameA);
573
0
  free(lpCommandLineA);
574
0
  free(lpCurrentDirectoryA);
575
0
  free(StartupInfoA.lpDesktop);
576
0
  free(StartupInfoA.lpReserved);
577
0
  free(StartupInfoA.lpTitle);
578
0
  return rc;
579
0
}
580
581
BOOL CreateProcessAsUserA(HANDLE hToken, LPCSTR lpApplicationName, LPSTR lpCommandLine,
582
                          LPSECURITY_ATTRIBUTES lpProcessAttributes,
583
                          LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles,
584
                          DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory,
585
                          LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation)
586
0
{
587
0
  return CreateProcessExA(hToken, 0, lpApplicationName, lpCommandLine, lpProcessAttributes,
588
0
                          lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,
589
0
                          lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
590
0
}
591
592
BOOL CreateProcessAsUserW(WINPR_ATTR_UNUSED HANDLE hToken,
593
                          WINPR_ATTR_UNUSED LPCWSTR lpApplicationName,
594
                          WINPR_ATTR_UNUSED LPWSTR lpCommandLine,
595
                          WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpProcessAttributes,
596
                          WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpThreadAttributes,
597
                          WINPR_ATTR_UNUSED BOOL bInheritHandles,
598
                          WINPR_ATTR_UNUSED DWORD dwCreationFlags,
599
                          WINPR_ATTR_UNUSED LPVOID lpEnvironment,
600
                          WINPR_ATTR_UNUSED LPCWSTR lpCurrentDirectory,
601
                          WINPR_ATTR_UNUSED LPSTARTUPINFOW lpStartupInfo,
602
                          WINPR_ATTR_UNUSED LPPROCESS_INFORMATION lpProcessInformation)
603
0
{
604
0
  WLog_ERR("TODO", "TODO: implement");
605
0
  return FALSE;
606
0
}
607
608
BOOL CreateProcessWithLogonA(
609
    WINPR_ATTR_UNUSED LPCSTR lpUsername, WINPR_ATTR_UNUSED LPCSTR lpDomain,
610
    WINPR_ATTR_UNUSED LPCSTR lpPassword, WINPR_ATTR_UNUSED DWORD dwLogonFlags,
611
    WINPR_ATTR_UNUSED LPCSTR lpApplicationName, WINPR_ATTR_UNUSED LPSTR lpCommandLine,
612
    WINPR_ATTR_UNUSED DWORD dwCreationFlags, WINPR_ATTR_UNUSED LPVOID lpEnvironment,
613
    WINPR_ATTR_UNUSED LPCSTR lpCurrentDirectory, WINPR_ATTR_UNUSED LPSTARTUPINFOA lpStartupInfo,
614
    WINPR_ATTR_UNUSED LPPROCESS_INFORMATION lpProcessInformation)
615
0
{
616
0
  WLog_ERR("TODO", "TODO: implement");
617
0
  return FALSE;
618
0
}
619
620
BOOL CreateProcessWithLogonW(
621
    WINPR_ATTR_UNUSED LPCWSTR lpUsername, WINPR_ATTR_UNUSED LPCWSTR lpDomain,
622
    WINPR_ATTR_UNUSED LPCWSTR lpPassword, WINPR_ATTR_UNUSED DWORD dwLogonFlags,
623
    WINPR_ATTR_UNUSED LPCWSTR lpApplicationName, WINPR_ATTR_UNUSED LPWSTR lpCommandLine,
624
    WINPR_ATTR_UNUSED DWORD dwCreationFlags, WINPR_ATTR_UNUSED LPVOID lpEnvironment,
625
    WINPR_ATTR_UNUSED LPCWSTR lpCurrentDirectory, WINPR_ATTR_UNUSED LPSTARTUPINFOW lpStartupInfo,
626
    WINPR_ATTR_UNUSED LPPROCESS_INFORMATION lpProcessInformation)
627
0
{
628
0
  WLog_ERR("TODO", "TODO: implement");
629
0
  return FALSE;
630
0
}
631
632
BOOL CreateProcessWithTokenA(WINPR_ATTR_UNUSED HANDLE hToken, WINPR_ATTR_UNUSED DWORD dwLogonFlags,
633
                             LPCSTR lpApplicationName, LPSTR lpCommandLine, DWORD dwCreationFlags,
634
                             LPVOID lpEnvironment, LPCSTR lpCurrentDirectory,
635
                             LPSTARTUPINFOA lpStartupInfo,
636
                             LPPROCESS_INFORMATION lpProcessInformation)
637
0
{
638
0
  return CreateProcessExA(nullptr, 0, lpApplicationName, lpCommandLine, nullptr, nullptr, FALSE,
639
0
                          dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo,
640
0
                          lpProcessInformation);
641
0
}
642
643
BOOL CreateProcessWithTokenW(WINPR_ATTR_UNUSED HANDLE hToken, WINPR_ATTR_UNUSED DWORD dwLogonFlags,
644
                             WINPR_ATTR_UNUSED LPCWSTR lpApplicationName,
645
                             WINPR_ATTR_UNUSED LPWSTR lpCommandLine,
646
                             WINPR_ATTR_UNUSED DWORD dwCreationFlags,
647
                             WINPR_ATTR_UNUSED LPVOID lpEnvironment,
648
                             WINPR_ATTR_UNUSED LPCWSTR lpCurrentDirectory,
649
                             WINPR_ATTR_UNUSED LPSTARTUPINFOW lpStartupInfo,
650
                             WINPR_ATTR_UNUSED LPPROCESS_INFORMATION lpProcessInformation)
651
0
{
652
0
  WLog_ERR("TODO", "TODO: implement");
653
0
  return FALSE;
654
0
}
655
656
VOID ExitProcess(UINT uExitCode)
657
0
{
658
  // NOLINTNEXTLINE(concurrency-mt-unsafe)
659
0
  exit((int)uExitCode);
660
0
}
661
662
BOOL GetExitCodeProcess(HANDLE hProcess, LPDWORD lpExitCode)
663
0
{
664
0
  WINPR_PROCESS* process = nullptr;
665
666
0
  if (!hProcess)
667
0
    return FALSE;
668
669
0
  if (!lpExitCode)
670
0
    return FALSE;
671
672
0
  process = (WINPR_PROCESS*)hProcess;
673
0
  *lpExitCode = process->dwExitCode;
674
0
  return TRUE;
675
0
}
676
677
HANDLE _GetCurrentProcess(VOID)
678
0
{
679
0
  WLog_ERR("TODO", "TODO: implement");
680
0
  return nullptr;
681
0
}
682
683
DWORD GetCurrentProcessId(VOID)
684
3.69k
{
685
3.69k
  return ((DWORD)getpid());
686
3.69k
}
687
688
BOOL TerminateProcess(HANDLE hProcess, WINPR_ATTR_UNUSED UINT uExitCode)
689
0
{
690
0
  WINPR_PROCESS* process = nullptr;
691
0
  process = (WINPR_PROCESS*)hProcess;
692
693
0
  if (!process || (process->pid <= 0))
694
0
    return FALSE;
695
696
0
  if (kill(process->pid, SIGTERM))
697
0
    return FALSE;
698
699
0
  return TRUE;
700
0
}
701
702
static BOOL ProcessHandleCloseHandle(HANDLE handle)
703
0
{
704
0
  WINPR_PROCESS* process = (WINPR_PROCESS*)handle;
705
0
  WINPR_ASSERT(process);
706
0
  if (process->fd >= 0)
707
0
  {
708
0
    close(process->fd);
709
0
    process->fd = -1;
710
0
  }
711
0
  return TRUE;
712
0
}
713
714
static BOOL ProcessHandleIsHandle(HANDLE handle)
715
0
{
716
0
  return WINPR_HANDLE_IS_HANDLED(handle, HANDLE_TYPE_PROCESS, FALSE);
717
0
}
718
719
static int ProcessGetFd(HANDLE handle)
720
0
{
721
0
  WINPR_PROCESS* process = (WINPR_PROCESS*)handle;
722
723
0
  if (!ProcessHandleIsHandle(handle))
724
0
    return -1;
725
726
0
  return process->fd;
727
0
}
728
729
static DWORD ProcessCleanupHandle(HANDLE handle)
730
0
{
731
0
  WINPR_PROCESS* process = (WINPR_PROCESS*)handle;
732
733
0
  WINPR_ASSERT(process);
734
0
  if (process->fd > 0)
735
0
  {
736
0
    if (waitpid(process->pid, &process->status, WNOHANG) == process->pid)
737
0
    {
738
0
      if (WIFEXITED(process->status))
739
0
        process->dwExitCode = (DWORD)WEXITSTATUS(process->status);
740
0
      else if (WIFSIGNALED(process->status))
741
0
        process->dwExitCode = (DWORD)(128 + WTERMSIG(process->status));
742
0
      else
743
0
        process->dwExitCode = (DWORD)process->status;
744
0
    }
745
0
  }
746
0
  return WAIT_OBJECT_0;
747
0
}
748
749
static HANDLE_OPS ops = { ProcessHandleIsHandle,
750
                        ProcessHandleCloseHandle,
751
                        ProcessGetFd,
752
                        ProcessCleanupHandle, /* CleanupHandle */
753
                        nullptr,
754
                        nullptr,
755
                        nullptr,
756
                        nullptr,
757
                        nullptr,
758
                        nullptr,
759
                        nullptr,
760
                        nullptr,
761
                        nullptr,
762
                        nullptr,
763
                        nullptr,
764
                        nullptr,
765
                        nullptr,
766
                        nullptr,
767
                        nullptr,
768
                        nullptr,
769
                        nullptr };
770
771
static int pidfd_open(pid_t pid)
772
0
{
773
0
#ifdef __linux__
774
#if !defined(__NR_pidfd_open)
775
#define __NR_pidfd_open 434
776
#endif /* __NR_pidfd_open */
777
778
0
#ifndef PIDFD_NONBLOCK
779
0
#define PIDFD_NONBLOCK O_NONBLOCK
780
0
#endif /* PIDFD_NONBLOCK */
781
782
0
  long fd = syscall(__NR_pidfd_open, pid, PIDFD_NONBLOCK);
783
0
  if (fd < 0 && errno == EINVAL)
784
0
  {
785
    /* possibly PIDFD_NONBLOCK is not supported, let's try to create a pidfd and set it
786
     * non blocking afterward */
787
0
    int flags = 0;
788
0
    fd = syscall(__NR_pidfd_open, pid, 0);
789
0
    if ((fd < 0) || (fd > INT32_MAX))
790
0
      return -1;
791
792
0
    flags = fcntl((int)fd, F_GETFL);
793
0
    if ((flags < 0) || fcntl((int)fd, F_SETFL, flags | O_NONBLOCK) < 0)
794
0
    {
795
0
      close((int)fd);
796
0
      fd = -1;
797
0
    }
798
0
  }
799
0
  if ((fd < 0) || (fd > INT32_MAX))
800
0
    return -1;
801
0
  return (int)fd;
802
#else
803
  return -1;
804
#endif
805
0
}
806
807
HANDLE CreateProcessHandle(pid_t pid)
808
0
{
809
0
  WINPR_PROCESS* process = nullptr;
810
0
  process = (WINPR_PROCESS*)calloc(1, sizeof(WINPR_PROCESS));
811
812
0
  if (!process)
813
0
    return nullptr;
814
815
0
  process->pid = pid;
816
0
  process->common.Type = HANDLE_TYPE_PROCESS;
817
0
  process->common.ops = &ops;
818
0
  process->common.refCount = 1;
819
0
  process->fd = pidfd_open(pid);
820
0
  if (process->fd >= 0)
821
0
    process->common.Mode = WINPR_FD_READ;
822
0
  return (HANDLE)process;
823
0
}
824
825
#endif