Coverage Report

Created: 2026-10-28 06:54

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
WINPR_ATTR_MALLOC(free, 1)
100
static char* FindApplicationPath(char* application)
101
0
{
102
0
  const char pathName[] = "PATH";
103
104
0
  if (!application)
105
0
    return nullptr;
106
107
0
  if (application[0] == '/')
108
0
  {
109
0
    if (!winpr_PathFileExists(application))
110
0
      return nullptr;
111
0
    return _strdup(application);
112
0
  }
113
114
0
  const DWORD nSize = GetEnvironmentVariableA(pathName, nullptr, 0);
115
116
0
  if (!nSize)
117
0
    return _strdup(application);
118
119
0
  char* lpSystemPath = 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
  char* filename = nullptr;
131
0
  char* save = nullptr;
132
0
  char* 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
#if !defined(__EMSCRIPTEN__)
403
0
        else
404
0
        {
405
0
          initgroups(token->Username, (gid_t)token->GroupId);
406
0
        }
407
0
#endif
408
0
      }
409
410
0
      if (token->UserId)
411
0
      {
412
0
        int rc = setuid((uid_t)token->UserId);
413
0
        if (rc != 0)
414
0
          goto finish;
415
0
      }
416
0
    }
417
418
    /* TODO: add better cwd handling and error checking */
419
0
    if (lpCurrentDirectory && strlen(lpCurrentDirectory) > 0)
420
0
    {
421
0
      int rc = chdir(lpCurrentDirectory);
422
0
      if (rc != 0)
423
0
        goto finish;
424
0
    }
425
426
0
    if (execve(filename, pArgs, envp) < 0)
427
0
    {
428
      /* execve failed - end the process */
429
0
      _exit(1);
430
0
    }
431
0
  }
432
0
  else
433
0
  {
434
    /* parent process */
435
0
  }
436
437
0
  process = CreateProcessHandle(pid);
438
439
0
  if (!process)
440
0
  {
441
0
    goto finish;
442
0
  }
443
444
0
  thread = CreateNoneHandle();
445
446
0
  if (!thread)
447
0
  {
448
0
    ProcessHandleCloseHandle(process);
449
0
    free(process);
450
0
    goto finish;
451
0
  }
452
453
0
  lpProcessInformation->hProcess = process;
454
0
  lpProcessInformation->hThread = thread;
455
0
  lpProcessInformation->dwProcessId = (DWORD)pid;
456
0
  lpProcessInformation->dwThreadId = (DWORD)pid;
457
0
  ret = TRUE;
458
0
finish:
459
460
  /* restore caller's original signal mask */
461
0
  if (restoreSigMask)
462
0
    pthread_sigmask(SIG_SETMASK, &oldSigMask, nullptr);
463
464
0
  free(filename);
465
0
  free((void*)pArgs);
466
467
0
  if (lpszEnvironmentBlock)
468
0
    FreeEnvironmentStrings(lpszEnvironmentBlock);
469
470
0
  if (envp)
471
0
  {
472
0
    int i = 0;
473
474
0
    while (envp[i])
475
0
    {
476
0
      free(envp[i]);
477
0
      i++;
478
0
    }
479
480
0
    free((void*)envp);
481
0
  }
482
483
0
  return ret;
484
0
}
485
486
BOOL CreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine,
487
                    LPSECURITY_ATTRIBUTES lpProcessAttributes,
488
                    LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles,
489
                    DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory,
490
                    LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation)
491
0
{
492
0
  return CreateProcessExA(nullptr, 0, lpApplicationName, lpCommandLine, lpProcessAttributes,
493
0
                          lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,
494
0
                          lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
495
0
}
496
497
BOOL CreateProcessW(WINPR_ATTR_UNUSED LPCWSTR lpApplicationName,
498
                    WINPR_ATTR_UNUSED LPWSTR lpCommandLine,
499
                    WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpProcessAttributes,
500
                    WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpThreadAttributes,
501
                    WINPR_ATTR_UNUSED BOOL bInheritHandles, WINPR_ATTR_UNUSED DWORD dwCreationFlags,
502
                    WINPR_ATTR_UNUSED LPVOID lpEnvironment,
503
                    WINPR_ATTR_UNUSED LPCWSTR lpCurrentDirectory,
504
                    WINPR_ATTR_UNUSED LPSTARTUPINFOW lpStartupInfo,
505
                    WINPR_ATTR_UNUSED LPPROCESS_INFORMATION lpProcessInformation)
506
0
{
507
0
  WINPR_ASSERT(lpStartupInfo);
508
0
  WINPR_ASSERT(lpProcessInformation);
509
510
0
  LPSTR lpApplicationNameA = nullptr;
511
0
  LPSTR lpCommandLineA = nullptr;
512
0
  LPSTR lpCurrentDirectoryA = nullptr;
513
0
  STARTUPINFOA StartupInfoA = { .cb = sizeof(STARTUPINFOA),
514
0
                              .lpReserved = nullptr,
515
0
                              .lpDesktop = nullptr,
516
0
                              .lpTitle = nullptr,
517
0
                              .dwX = lpStartupInfo->dwX,
518
0
                              .dwY = lpStartupInfo->dwY,
519
0
                              .dwXSize = lpStartupInfo->dwXSize,
520
0
                              .dwYSize = lpStartupInfo->dwYSize,
521
0
                              .dwXCountChars = lpStartupInfo->dwXCountChars,
522
0
                              .dwYCountChars = lpStartupInfo->dwYCountChars,
523
0
                              .dwFillAttribute = lpStartupInfo->dwFillAttribute,
524
0
                              .dwFlags = lpStartupInfo->dwFlags,
525
0
                              .wShowWindow = lpStartupInfo->wShowWindow,
526
0
                              .cbReserved2 = lpStartupInfo->cbReserved2,
527
0
                              .lpReserved2 = lpStartupInfo->lpReserved2,
528
0
                              .hStdInput = lpStartupInfo->hStdInput,
529
0
                              .hStdOutput = lpStartupInfo->hStdOutput,
530
0
                              .hStdError = lpStartupInfo->hStdError };
531
532
0
  BOOL rc = FALSE;
533
0
  if (lpApplicationName)
534
0
  {
535
0
    lpApplicationNameA = ConvertWCharToUtf8Alloc(lpApplicationName, nullptr);
536
0
    if (!lpApplicationNameA)
537
0
      goto fail;
538
0
  }
539
0
  if (lpCommandLine)
540
0
  {
541
0
    lpCommandLineA = ConvertWCharToUtf8Alloc(lpCommandLine, nullptr);
542
0
    if (!lpCommandLineA)
543
0
      goto fail;
544
0
  }
545
0
  if (lpCurrentDirectory)
546
0
  {
547
0
    lpCurrentDirectoryA = ConvertWCharToUtf8Alloc(lpCurrentDirectory, nullptr);
548
0
    if (!lpCurrentDirectoryA)
549
0
      goto fail;
550
0
  }
551
0
  if (lpStartupInfo->lpReserved)
552
0
  {
553
0
    StartupInfoA.lpReserved = ConvertWCharToUtf8Alloc(lpStartupInfo->lpReserved, nullptr);
554
0
    if (!StartupInfoA.lpReserved)
555
0
      goto fail;
556
0
  }
557
0
  if (lpStartupInfo->lpDesktop)
558
0
  {
559
0
    StartupInfoA.lpDesktop = ConvertWCharToUtf8Alloc(lpStartupInfo->lpDesktop, nullptr);
560
0
    if (!StartupInfoA.lpDesktop)
561
0
      goto fail;
562
0
  }
563
0
  if (lpStartupInfo->lpTitle)
564
0
  {
565
0
    StartupInfoA.lpTitle = ConvertWCharToUtf8Alloc(lpStartupInfo->lpTitle, nullptr);
566
0
    if (!StartupInfoA.lpTitle)
567
0
      goto fail;
568
0
  }
569
570
0
  rc = CreateProcessA(lpApplicationNameA, lpCommandLineA, lpProcessAttributes, lpThreadAttributes,
571
0
                      bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectoryA,
572
0
                      &StartupInfoA, lpProcessInformation);
573
0
fail:
574
0
  free(lpApplicationNameA);
575
0
  free(lpCommandLineA);
576
0
  free(lpCurrentDirectoryA);
577
0
  free(StartupInfoA.lpDesktop);
578
0
  free(StartupInfoA.lpReserved);
579
0
  free(StartupInfoA.lpTitle);
580
0
  return rc;
581
0
}
582
583
BOOL CreateProcessAsUserA(HANDLE hToken, LPCSTR lpApplicationName, LPSTR lpCommandLine,
584
                          LPSECURITY_ATTRIBUTES lpProcessAttributes,
585
                          LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles,
586
                          DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory,
587
                          LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation)
588
0
{
589
0
  return CreateProcessExA(hToken, 0, lpApplicationName, lpCommandLine, lpProcessAttributes,
590
0
                          lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,
591
0
                          lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
592
0
}
593
594
BOOL CreateProcessAsUserW(WINPR_ATTR_UNUSED HANDLE hToken,
595
                          WINPR_ATTR_UNUSED LPCWSTR lpApplicationName,
596
                          WINPR_ATTR_UNUSED LPWSTR lpCommandLine,
597
                          WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpProcessAttributes,
598
                          WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpThreadAttributes,
599
                          WINPR_ATTR_UNUSED BOOL bInheritHandles,
600
                          WINPR_ATTR_UNUSED DWORD dwCreationFlags,
601
                          WINPR_ATTR_UNUSED LPVOID lpEnvironment,
602
                          WINPR_ATTR_UNUSED LPCWSTR lpCurrentDirectory,
603
                          WINPR_ATTR_UNUSED LPSTARTUPINFOW lpStartupInfo,
604
                          WINPR_ATTR_UNUSED LPPROCESS_INFORMATION lpProcessInformation)
605
0
{
606
0
  WLog_ERR("TODO", "TODO: implement");
607
0
  return FALSE;
608
0
}
609
610
BOOL CreateProcessWithLogonA(
611
    WINPR_ATTR_UNUSED LPCSTR lpUsername, WINPR_ATTR_UNUSED LPCSTR lpDomain,
612
    WINPR_ATTR_UNUSED LPCSTR lpPassword, WINPR_ATTR_UNUSED DWORD dwLogonFlags,
613
    WINPR_ATTR_UNUSED LPCSTR lpApplicationName, WINPR_ATTR_UNUSED LPSTR lpCommandLine,
614
    WINPR_ATTR_UNUSED DWORD dwCreationFlags, WINPR_ATTR_UNUSED LPVOID lpEnvironment,
615
    WINPR_ATTR_UNUSED LPCSTR lpCurrentDirectory, WINPR_ATTR_UNUSED LPSTARTUPINFOA lpStartupInfo,
616
    WINPR_ATTR_UNUSED LPPROCESS_INFORMATION lpProcessInformation)
617
0
{
618
0
  WLog_ERR("TODO", "TODO: implement");
619
0
  return FALSE;
620
0
}
621
622
BOOL CreateProcessWithLogonW(
623
    WINPR_ATTR_UNUSED LPCWSTR lpUsername, WINPR_ATTR_UNUSED LPCWSTR lpDomain,
624
    WINPR_ATTR_UNUSED LPCWSTR lpPassword, WINPR_ATTR_UNUSED DWORD dwLogonFlags,
625
    WINPR_ATTR_UNUSED LPCWSTR lpApplicationName, WINPR_ATTR_UNUSED LPWSTR lpCommandLine,
626
    WINPR_ATTR_UNUSED DWORD dwCreationFlags, WINPR_ATTR_UNUSED LPVOID lpEnvironment,
627
    WINPR_ATTR_UNUSED LPCWSTR lpCurrentDirectory, WINPR_ATTR_UNUSED LPSTARTUPINFOW lpStartupInfo,
628
    WINPR_ATTR_UNUSED LPPROCESS_INFORMATION lpProcessInformation)
629
0
{
630
0
  WLog_ERR("TODO", "TODO: implement");
631
0
  return FALSE;
632
0
}
633
634
BOOL CreateProcessWithTokenA(WINPR_ATTR_UNUSED HANDLE hToken, WINPR_ATTR_UNUSED DWORD dwLogonFlags,
635
                             LPCSTR lpApplicationName, LPSTR lpCommandLine, DWORD dwCreationFlags,
636
                             LPVOID lpEnvironment, LPCSTR lpCurrentDirectory,
637
                             LPSTARTUPINFOA lpStartupInfo,
638
                             LPPROCESS_INFORMATION lpProcessInformation)
639
0
{
640
0
  return CreateProcessExA(nullptr, 0, lpApplicationName, lpCommandLine, nullptr, nullptr, FALSE,
641
0
                          dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo,
642
0
                          lpProcessInformation);
643
0
}
644
645
BOOL CreateProcessWithTokenW(WINPR_ATTR_UNUSED HANDLE hToken, WINPR_ATTR_UNUSED DWORD dwLogonFlags,
646
                             WINPR_ATTR_UNUSED LPCWSTR lpApplicationName,
647
                             WINPR_ATTR_UNUSED LPWSTR lpCommandLine,
648
                             WINPR_ATTR_UNUSED DWORD dwCreationFlags,
649
                             WINPR_ATTR_UNUSED LPVOID lpEnvironment,
650
                             WINPR_ATTR_UNUSED LPCWSTR lpCurrentDirectory,
651
                             WINPR_ATTR_UNUSED LPSTARTUPINFOW lpStartupInfo,
652
                             WINPR_ATTR_UNUSED LPPROCESS_INFORMATION lpProcessInformation)
653
0
{
654
0
  WLog_ERR("TODO", "TODO: implement");
655
0
  return FALSE;
656
0
}
657
658
VOID ExitProcess(UINT uExitCode)
659
0
{
660
  // NOLINTNEXTLINE(concurrency-mt-unsafe)
661
0
  exit((int)uExitCode);
662
0
}
663
664
BOOL GetExitCodeProcess(HANDLE hProcess, LPDWORD lpExitCode)
665
0
{
666
0
  WINPR_PROCESS* process = nullptr;
667
668
0
  if (!hProcess)
669
0
    return FALSE;
670
671
0
  if (!lpExitCode)
672
0
    return FALSE;
673
674
0
  process = (WINPR_PROCESS*)hProcess;
675
0
  *lpExitCode = process->dwExitCode;
676
0
  return TRUE;
677
0
}
678
679
HANDLE _GetCurrentProcess(VOID)
680
0
{
681
0
  WLog_ERR("TODO", "TODO: implement");
682
0
  return nullptr;
683
0
}
684
685
DWORD GetCurrentProcessId(VOID)
686
14.6M
{
687
14.6M
  return ((DWORD)getpid());
688
14.6M
}
689
690
BOOL TerminateProcess(HANDLE hProcess, WINPR_ATTR_UNUSED UINT uExitCode)
691
0
{
692
0
  WINPR_PROCESS* process = nullptr;
693
0
  process = (WINPR_PROCESS*)hProcess;
694
695
0
  if (!process || (process->pid <= 0))
696
0
    return FALSE;
697
698
0
  if (kill(process->pid, SIGTERM))
699
0
    return FALSE;
700
701
0
  return TRUE;
702
0
}
703
704
static BOOL ProcessHandleCloseHandle(HANDLE handle)
705
0
{
706
0
  WINPR_PROCESS* process = (WINPR_PROCESS*)handle;
707
0
  WINPR_ASSERT(process);
708
0
  if (process->fd >= 0)
709
0
  {
710
0
    close(process->fd);
711
0
    process->fd = -1;
712
0
  }
713
0
  return TRUE;
714
0
}
715
716
static BOOL ProcessHandleIsHandle(HANDLE handle)
717
0
{
718
0
  return WINPR_HANDLE_IS_HANDLED(handle, HANDLE_TYPE_PROCESS, FALSE);
719
0
}
720
721
static int ProcessGetFd(HANDLE handle)
722
0
{
723
0
  WINPR_PROCESS* process = (WINPR_PROCESS*)handle;
724
725
0
  if (!ProcessHandleIsHandle(handle))
726
0
    return -1;
727
728
0
  return process->fd;
729
0
}
730
731
static DWORD ProcessCleanupHandle(HANDLE handle)
732
0
{
733
0
  WINPR_PROCESS* process = (WINPR_PROCESS*)handle;
734
735
0
  WINPR_ASSERT(process);
736
0
  if (process->fd > 0)
737
0
  {
738
0
    if (waitpid(process->pid, &process->status, WNOHANG) == process->pid)
739
0
    {
740
0
      if (WIFEXITED(process->status))
741
0
        process->dwExitCode = (DWORD)WEXITSTATUS(process->status);
742
0
      else if (WIFSIGNALED(process->status))
743
0
        process->dwExitCode = (DWORD)(128 + WTERMSIG(process->status));
744
0
      else
745
0
        process->dwExitCode = (DWORD)process->status;
746
0
    }
747
0
  }
748
0
  return WAIT_OBJECT_0;
749
0
}
750
751
static HANDLE_OPS ops = { ProcessHandleIsHandle,
752
                        ProcessHandleCloseHandle,
753
                        ProcessGetFd,
754
                        ProcessCleanupHandle, /* CleanupHandle */
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
                        nullptr,
771
                        nullptr };
772
773
static int pidfd_open(pid_t pid)
774
0
{
775
0
#ifdef __linux__
776
#if !defined(__NR_pidfd_open)
777
#define __NR_pidfd_open 434
778
#endif /* __NR_pidfd_open */
779
780
0
#ifndef PIDFD_NONBLOCK
781
0
#define PIDFD_NONBLOCK O_NONBLOCK
782
0
#endif /* PIDFD_NONBLOCK */
783
784
0
  long fd = syscall(__NR_pidfd_open, pid, PIDFD_NONBLOCK);
785
0
  if (fd < 0 && errno == EINVAL)
786
0
  {
787
    /* possibly PIDFD_NONBLOCK is not supported, let's try to create a pidfd and set it
788
     * non blocking afterward */
789
0
    int flags = 0;
790
0
    fd = syscall(__NR_pidfd_open, pid, 0);
791
0
    if ((fd < 0) || (fd > INT32_MAX))
792
0
      return -1;
793
794
0
    flags = fcntl((int)fd, F_GETFL);
795
0
    if ((flags < 0) || fcntl((int)fd, F_SETFL, flags | O_NONBLOCK) < 0)
796
0
    {
797
0
      close((int)fd);
798
0
      fd = -1;
799
0
    }
800
0
  }
801
0
  if ((fd < 0) || (fd > INT32_MAX))
802
0
    return -1;
803
0
  return (int)fd;
804
#else
805
  return -1;
806
#endif
807
0
}
808
809
HANDLE CreateProcessHandle(pid_t pid)
810
0
{
811
0
  WINPR_PROCESS* process = nullptr;
812
0
  process = (WINPR_PROCESS*)calloc(1, sizeof(WINPR_PROCESS));
813
814
0
  if (!process)
815
0
    return nullptr;
816
817
0
  process->pid = pid;
818
0
  process->common.Type = HANDLE_TYPE_PROCESS;
819
0
  process->common.ops = &ops;
820
0
  process->common.refCount = 1;
821
0
  process->fd = pidfd_open(pid);
822
0
  if (process->fd >= 0)
823
0
    process->common.Mode = WINPR_FD_READ;
824
0
  return (HANDLE)process;
825
0
}
826
827
#endif