process-win.cpp revision 760446f710619a9daa6cedc7f0601f49e4ea3442
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/* $Id$ */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/** @file
5b281ba489ca18f0380d7efc7a5108b606cce449vboxsync * IPRT - Process, Windows.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/*
e64031e20c39650a7bc902a3e1aba613b9415deevboxsync * Copyright (C) 2006-2010 Oracle Corporation
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync *
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * available from http://www.virtualbox.org. This file is free software;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * you can redistribute it and/or modify it under the terms of the GNU
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * General Public License (GPL) as published by the Free Software
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync *
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * The contents of this file may alternatively be used under the terms
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * of the Common Development and Distribution License Version 1.0
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * VirtualBox OSE distribution, in which case the provisions of the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * CDDL are applicable instead of those of the GPL.
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync *
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * You may elect to license modified versions of this file under the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * terms and conditions of either the GPL or the CDDL or both.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/*******************************************************************************
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync* Header Files *
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync*******************************************************************************/
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#define LOG_GROUP RTLOGGROUP_PROCESS
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync#include <Userenv.h>
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync#include <Windows.h>
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#include <tlhelp32.h>
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#include <process.h>
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#include <errno.h>
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#include <iprt/process.h>
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#include "internal/iprt.h"
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#include <iprt/assert.h>
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#include <iprt/critsect.h>
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#include <iprt/file.h>
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#include <iprt/err.h>
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#include <iprt/env.h>
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#include <iprt/getopt.h>
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#include <iprt/initterm.h>
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync#include <iprt/ldr.h>
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#include <iprt/mem.h>
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#include <iprt/once.h>
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#include <iprt/pipe.h>
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#include <iprt/string.h>
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#include <iprt/socket.h>
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/*******************************************************************************
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync* Structures and Typedefs *
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync*******************************************************************************/
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsynctypedef WINADVAPI BOOL WINAPI FNCREATEPROCESSWITHLOGON(LPCWSTR,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync LPCWSTR,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync LPCWSTR,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync DWORD,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync LPCWSTR,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync LPWSTR,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync DWORD,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync LPVOID,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync LPCWSTR,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync LPSTARTUPINFOW,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync LPPROCESS_INFORMATION);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsynctypedef FNCREATEPROCESSWITHLOGON *PFNCREATEPROCESSWITHLOGON;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsynctypedef DWORD WINAPI FNWTSGETACTIVECONSOLESESSIONID();
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsynctypedef FNWTSGETACTIVECONSOLESESSIONID *PFNWTSGETACTIVECONSOLESESSIONID;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsynctypedef HANDLE WINAPI FNCREATETOOLHELP32SNAPSHOT(DWORD, DWORD);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsynctypedef FNCREATETOOLHELP32SNAPSHOT *PFNCREATETOOLHELP32SNAPSHOT;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsynctypedef BOOL WINAPI FNPROCESS32FIRST(HANDLE, LPPROCESSENTRY32);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsynctypedef FNPROCESS32FIRST *PFNPROCESS32FIRST;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsynctypedef BOOL WINAPI FNPROCESS32NEXT(HANDLE, LPPROCESSENTRY32);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsynctypedef FNPROCESS32NEXT *PFNPROCESS32NEXT;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsynctypedef BOOL WINAPI FNENUMPROCESSES(DWORD*, DWORD, DWORD*);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsynctypedef FNENUMPROCESSES *PFNENUMPROCESSES;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsynctypedef DWORD FNGETMODULEBASENAME(HANDLE, HMODULE, LPTSTR, DWORD);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsynctypedef FNGETMODULEBASENAME *PFNGETMODULEBASENAME;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/*******************************************************************************
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync* Global Variables *
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync*******************************************************************************/
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/** Init once structure. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic RTONCE g_rtProcWinInitOnce = RTONCE_INITIALIZER;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/** Critical section protecting the process array. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic RTCRITSECT g_CritSect;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/** The number of processes in the array. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic uint32_t g_cProcesses;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/** The current allocation size. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic uint32_t g_cProcessesAlloc;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/** Array containing the live or non-reaped child processes. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic struct RTPROCWINENTRY
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /** The process ID. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync ULONG_PTR pid;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /** The process handle. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync HANDLE hProcess;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync} *g_paProcesses;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/**
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Clean up the globals.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync *
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @param enmReason Ignored.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @param iStatus Ignored.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @param pvUser Ignored.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic DECLCALLBACK(void) rtProcWinTerm(RTTERMREASON enmReason, int32_t iStatus, void *pvUser)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync NOREF(pvUser); NOREF(iStatus); NOREF(enmReason);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTCritSectDelete(&g_CritSect);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync size_t i = g_cProcesses;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync while (i-- > 0)
cf3aad827eee194a3e6e68796710074b44164371vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync CloseHandle(g_paProcesses[i].hProcess);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync g_paProcesses[i].hProcess = NULL;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTMemFree(g_paProcesses);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync g_paProcesses = NULL;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync g_cProcesses = 0;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync g_cProcessesAlloc = 0;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync}
c58c758d3642ac45d3f12356c406c631fcd8f538vboxsync
c58c758d3642ac45d3f12356c406c631fcd8f538vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/**
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Initialize the globals.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync *
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @returns IPRT status code.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @param pvUser1 Ignored.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @param pvUser2 Ignored.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic DECLCALLBACK(int32_t) rtProcWinInitOnce(void *pvUser1, void *pvUser2)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync NOREF(pvUser1); NOREF(pvUser2);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync g_cProcesses = 0;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync g_cProcessesAlloc = 0;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync g_paProcesses = NULL;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync int rc = RTCritSectInit(&g_CritSect);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (RT_SUCCESS(rc))
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /** @todo init once, terminate once - this is a generic thing which should
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * have some kind of static and simpler setup! */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync rc = RTTermRegisterCallback(rtProcWinTerm, NULL);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (RT_SUCCESS(rc))
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return rc;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTCritSectDelete(&g_CritSect);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return rc;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync}
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/**
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Gets the process handle for a process from g_paProcesses.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync *
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @returns Process handle if found, NULL if not.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @param pid The process to remove (pid).
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic HANDLE rtProcWinFindPid(RTPROCESS pid)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync HANDLE hProcess = NULL;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTCritSectEnter(&g_CritSect);
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync uint32_t i = g_cProcesses;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync while (i-- > 0)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (g_paProcesses[i].pid == pid)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync hProcess = g_paProcesses[i].hProcess;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync break;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTCritSectLeave(&g_CritSect);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return hProcess;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync}
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/**
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Removes a process from g_paProcesses.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync *
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync * @param pid The process to remove (pid).
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic void rtProcWinRemovePid(RTPROCESS pid)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTCritSectEnter(&g_CritSect);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync uint32_t i = g_cProcesses;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync while (i-- > 0)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (g_paProcesses[i].pid == pid)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync g_cProcesses--;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync uint32_t cToMove = g_cProcesses - i;
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync if (cToMove)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync memmove(&g_paProcesses[i], &g_paProcesses[i + 1], cToMove * sizeof(g_paProcesses[0]));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync break;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTCritSectLeave(&g_CritSect);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync}
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/**
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Adds a process to g_paProcesses.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync *
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @returns IPRT status code.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @param pid The process id.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @param hProcess The process handle.
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync */
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsyncstatic int rtProcWinAddPid(RTPROCESS pid, HANDLE hProcess)
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync{
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync RTCritSectEnter(&g_CritSect);
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync uint32_t i = g_cProcesses;
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync if (i >= g_cProcessesAlloc)
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync {
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync void *pvNew = RTMemRealloc(g_paProcesses, (i + 16) * sizeof(g_paProcesses[0]));
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync if (RT_UNLIKELY(!pvNew))
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync {
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync RTCritSectLeave(&g_CritSect);
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync return VERR_NO_MEMORY;
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync }
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync g_paProcesses = (struct RTPROCWINENTRY *)pvNew;
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync g_cProcessesAlloc = i + 16;
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync }
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync g_paProcesses[i].pid = pid;
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync g_paProcesses[i].hProcess = hProcess;
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync g_cProcesses = i + 1;
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTCritSectLeave(&g_CritSect);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return VINF_SUCCESS;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync}
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncRTR3DECL(int) RTProcCreate(const char *pszExec, const char * const *papszArgs, RTENV Env, unsigned fFlags, PRTPROCESS pProcess)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return RTProcCreateEx(pszExec, papszArgs, Env, fFlags,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync NULL, NULL, NULL, /* standard handles */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync NULL /*pszAsUser*/, NULL /* pszPassword*/,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pProcess);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync}
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic int rtProcGetProcessHandle(DWORD dwPID, PSID pSID, PHANDLE phToken)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync AssertPtr(pSID);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync AssertPtr(phToken);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync DWORD dwErr;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync BOOL fRc;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync BOOL fFound = FALSE;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync HANDLE hProc = OpenProcess(MAXIMUM_ALLOWED, TRUE, dwPID);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (hProc != NULL)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync HANDLE hTokenProc;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync fRc = OpenProcessToken(hProc,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_DUPLICATE |
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync TOKEN_ASSIGN_PRIMARY | TOKEN_ADJUST_SESSIONID | TOKEN_READ | TOKEN_WRITE,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync &hTokenProc);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (fRc)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync DWORD dwSize = 0;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync fRc = GetTokenInformation(hTokenProc, TokenUser, NULL, 0, &dwSize);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (!fRc)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync dwErr = GetLastError();
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if ( !fRc
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync && dwErr == ERROR_INSUFFICIENT_BUFFER
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync && dwSize > 0)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync PTOKEN_USER pTokenUser = (PTOKEN_USER)RTMemAlloc(dwSize);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync AssertPtrReturn(pTokenUser, VERR_NO_MEMORY);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RT_ZERO(*pTokenUser);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if ( GetTokenInformation(hTokenProc,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync TokenUser,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync (LPVOID)pTokenUser,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync dwSize,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync &dwSize))
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if ( IsValidSid(pTokenUser->User.Sid)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync && EqualSid(pTokenUser->User.Sid, pSID))
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (DuplicateTokenEx(hTokenProc, MAXIMUM_ALLOWED,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync NULL, SecurityIdentification, TokenPrimary, phToken))
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /*
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * So we found the process instance which belongs to the user we want to
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * to run our new process under. This duplicated token will be used for
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * the actual CreateProcessAsUserW() call then.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync fFound = TRUE;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync else
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync dwErr = GetLastError();
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync else
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync dwErr = GetLastError();
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTMemFree(pTokenUser);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync else
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync dwErr = GetLastError();
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync CloseHandle(hTokenProc);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync else
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync dwErr = GetLastError();
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync CloseHandle(hProc);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync else
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync dwErr = GetLastError();
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (fFound)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return VINF_SUCCESS;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (dwErr != NO_ERROR)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return RTErrConvertFromWin32(dwErr);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return VERR_NOT_FOUND; /* No error occured, but we didn't find the right process. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync}
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic BOOL rtProcFindProcessByName(const char *pszName, PSID pSID, PHANDLE phToken)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync AssertPtr(pszName);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync AssertPtr(pSID);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync AssertPtr(phToken);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync DWORD dwErr = NO_ERROR;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync BOOL fFound = FALSE;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /*
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * On modern systems (W2K+) try the Toolhelp32 API first; this is more stable
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * and reliable. Fallback to EnumProcess on NT4.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTLDRMOD hKernel32;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync int rc = RTLdrLoad("Kernel32.dll", &hKernel32);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (RT_SUCCESS(rc))
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync PFNCREATETOOLHELP32SNAPSHOT pfnCreateToolhelp32Snapshot;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync rc = RTLdrGetSymbol(hKernel32, "CreateToolhelp32Snapshot", (void**)&pfnCreateToolhelp32Snapshot);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (RT_SUCCESS(rc))
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync PFNPROCESS32FIRST pfnProcess32First;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync rc = RTLdrGetSymbol(hKernel32, "Process32First", (void**)&pfnProcess32First);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (RT_SUCCESS(rc))
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync PFNPROCESS32NEXT pfnProcess32Next;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync rc = RTLdrGetSymbol(hKernel32, "Process32Next", (void**)&pfnProcess32Next);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (RT_SUCCESS(rc))
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync HANDLE hSnap = pfnCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (hSnap != INVALID_HANDLE_VALUE)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync PROCESSENTRY32 procEntry;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync procEntry.dwSize = sizeof(PROCESSENTRY32);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (pfnProcess32First(hSnap, &procEntry))
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync do
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if ( _stricmp(procEntry.szExeFile, pszName) == 0
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync && RT_SUCCESS(rtProcGetProcessHandle(procEntry.th32ProcessID, pSID, phToken)))
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync fFound = TRUE;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync } while (pfnProcess32Next(hSnap, &procEntry) && !fFound);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync else /* Process32First */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync dwErr = GetLastError();
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync CloseHandle(hSnap);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync else /* hSnap =! INVALID_HANDLE_VALUE */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync dwErr = GetLastError();
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync else /* CreateToolhelp32Snapshot / Toolhelp32 API not available. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /*
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * NT4 needs a copy of "PSAPI.dll" (redistributed by Microsoft and not
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * part of the OS) in order to get a lookup. If we don't have this DLL
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * we are not able to get a token and therefore no UI will be visible.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTLDRMOD hPSAPI;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync int rc = RTLdrLoad("PSAPI.dll", &hPSAPI);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (RT_SUCCESS(rc))
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync PFNENUMPROCESSES pfnEnumProcesses;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync rc = RTLdrGetSymbol(hPSAPI, "EnumProcesses", (void**)&pfnEnumProcesses);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (RT_SUCCESS(rc))
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync PFNGETMODULEBASENAME pfnGetModuleBaseName;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync rc = RTLdrGetSymbol(hPSAPI, "GetModuleBaseName", (void**)&pfnGetModuleBaseName);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (RT_SUCCESS(rc))
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /** @todo Retry if pBytesReturned equals cbBytes! */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync DWORD dwPIDs[4096]; /* Should be sufficient for now. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync DWORD cbBytes = 0;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (pfnEnumProcesses(dwPIDs, sizeof(dwPIDs), &cbBytes))
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync for (DWORD dwIdx = 0; dwIdx < cbBytes/sizeof(DWORD) && !fFound; dwIdx++)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync FALSE, dwPIDs[dwIdx]);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (hProc)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync char *pszProcName = NULL;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync DWORD dwSize = 128;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync do
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTMemRealloc(pszProcName, dwSize);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (pfnGetModuleBaseName(hProc, 0, pszProcName, dwSize) == dwSize)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync dwSize += 128;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync } while (GetLastError() == ERROR_INSUFFICIENT_BUFFER);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (pszProcName)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if ( _stricmp(pszProcName, pszName) == 0
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync && RT_SUCCESS(rtProcGetProcessHandle(dwPIDs[dwIdx], pSID, phToken)))
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync fFound = TRUE;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (pszProcName)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTStrFree(pszProcName);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync CloseHandle(hProc);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync else
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync dwErr = GetLastError();
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTLdrClose(hKernel32);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync Assert(dwErr == NO_ERROR);
c58c758d3642ac45d3f12356c406c631fcd8f538vboxsync return fFound;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync}
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic int rtProcCreateAsUserHlp(PRTUTF16 pwszUser, PRTUTF16 pwszPassword, PRTUTF16 pwszExec, PRTUTF16 pwszCmdLine,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync PRTUTF16 pwszzBlock, DWORD dwCreationFlags,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync STARTUPINFOW *pStartupInfo, PROCESS_INFORMATION *pProcInfo, uint32_t fFlags)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync int rc = VINF_SUCCESS;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync BOOL fRc = FALSE;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync DWORD dwErr = NO_ERROR;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /*
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * If we run as a service CreateProcessWithLogon will fail,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * so don't even try it (because of Local System context).
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (!(fFlags & RTPROC_FLAGS_SERVICE))
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTLDRMOD hAdvAPI32;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync rc = RTLdrLoad("Advapi32.dll", &hAdvAPI32);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (RT_SUCCESS(rc))
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /*
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * This may fail on too old (NT4) platforms or if the calling process
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * is running on a SYSTEM account (like a service, ERROR_ACCESS_DENIED) on newer
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * platforms (however, this works on W2K!).
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync PFNCREATEPROCESSWITHLOGON pfnCreateProcessWithLogonW;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync rc = RTLdrGetSymbol(hAdvAPI32, "CreateProcessWithLogonW", (void**)&pfnCreateProcessWithLogonW);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (RT_SUCCESS(rc))
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync fRc = pfnCreateProcessWithLogonW(pwszUser,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync NULL, /* lpDomain*/
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pwszPassword,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync 1 /*LOGON_WITH_PROFILE*/, /* dwLogonFlags */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pwszExec,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pwszCmdLine,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync dwCreationFlags,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pwszzBlock,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync NULL, /* pCurrentDirectory */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pStartupInfo,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pProcInfo);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (!fRc)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync dwErr = GetLastError();
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTLdrClose(hAdvAPI32);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /*
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Did the API call above fail because we're running on a too old OS (NT4) or
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * we're running as a Windows service?
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if ( RT_FAILURE(rc)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync || (fFlags & RTPROC_FLAGS_SERVICE))
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /*
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync * So if we want to start a process from a service (RTPROC_FLAGS_SERVICE),
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * we have to do the following:
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * - Check the credentials supplied and get the user SID.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * - If valid get the correct Explorer/VBoxTray instance corresponding to that
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * user. This of course is only possible if that user is logged in (over
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * physical console or terminal services).
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * - If we found the user's Explorer/VBoxTray app, use and modify the token to
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * use it in order to allow the newly started process acess the user's
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * desktop. If there's no Explorer/VBoxTray app we cannot display the started
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * process (but run it without UI).
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync *
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * The following restrictions apply:
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * - A process only can show its UI when the user the process should run
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * under is logged in (has a desktop).
cf3aad827eee194a3e6e68796710074b44164371vboxsync * - We do not want to display a process of user A run on the desktop
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * of user B on multi session systems.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync *
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * The following rights are needed in order to use LogonUserW and
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * CreateProcessAsUserW, so the local policy has to be modified to:
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * - SE_TCB_NAME = Act as part of the operating system
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * - SE_ASSIGNPRIMARYTOKEN_NAME = Create/replace a token object
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * - SE_INCREASE_QUOTA_NAME
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync *
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * We may fail here with ERROR_PRIVILEGE_NOT_HELD.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync PHANDLE phToken = NULL;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync HANDLE hTokenLogon = INVALID_HANDLE_VALUE;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync fRc = LogonUserW(pwszUser,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /*
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Because we have to deal with http://support.microsoft.com/kb/245683
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * for NULL domain names when running on NT4 here, pass an empty string if so.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * However, passing FQDNs should work!
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync ((DWORD)(LOBYTE(LOWORD(GetVersion()))) < 5) /* < Windows 2000. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync ? L"" /* NT4 and older. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync : NULL, /* Windows 2000 and up. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pwszPassword,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync LOGON32_LOGON_INTERACTIVE,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync LOGON32_PROVIDER_DEFAULT,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync &hTokenLogon);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync BOOL fFound = FALSE;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync HANDLE hTokenUserDesktop = INVALID_HANDLE_VALUE;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (fRc)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (fFlags & RTPROC_FLAGS_SERVICE)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync DWORD cbName = 0; /* Must be zero to query size! */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync DWORD cbDomain = 0;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync SID_NAME_USE sidNameUse = SidTypeUser;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync fRc = LookupAccountNameW(NULL,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pwszUser,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync NULL,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync &cbName,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync NULL,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync &cbDomain,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync &sidNameUse);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (!fRc)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync dwErr = GetLastError();
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if ( !fRc
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync && dwErr == ERROR_INSUFFICIENT_BUFFER
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync && cbName > 0)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync dwErr = NO_ERROR;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync PSID pSID = (PSID)RTMemAlloc(cbName * sizeof(wchar_t));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync AssertPtrReturn(pSID, VERR_NO_MEMORY);
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /** @todo No way to allocate a PRTUTF16 directly? */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync PRTUTF16 pwszDomain = NULL;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (cbDomain > 0)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pwszDomain = (PRTUTF16)RTMemAlloc(cbDomain * sizeof(RTUTF16));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync AssertPtrReturn(pwszDomain, VERR_NO_MEMORY);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /* Note: Also supports FQDNs! */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if ( LookupAccountNameW(NULL, /* lpSystemName */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pwszUser,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pSID,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync &cbName,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pwszDomain,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync &cbDomain,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync &sidNameUse)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync && IsValidSid(pSID))
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync fFound = rtProcFindProcessByName(
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#ifdef VBOX
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync "VBoxTray.exe",
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#else
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync "explorer.exe"
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#endif
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pSID, &hTokenUserDesktop);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync else
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync dwErr = GetLastError(); /* LookupAccountNameW() failed. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTMemFree(pSID);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (pwszDomain != NULL)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTUtf16Free(pwszDomain);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync else /* !RTPROC_FLAGS_SERVICE */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /* Nothing to do here right now. */
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /*
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * If we didn't find a matching VBoxTray, just use the token we got
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * above from LogonUserW(). This enables us to at least run processes with
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * desktop interaction without UI.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync phToken = fFound ? &hTokenUserDesktop : &hTokenLogon;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /*
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Useful KB articles:
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * http://support.microsoft.com/kb/165194/
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * http://support.microsoft.com/kb/184802/
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * http://support.microsoft.com/kb/327618/
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync fRc = CreateProcessAsUserW(*phToken,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pwszExec,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pwszCmdLine,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync NULL, /* pProcessAttributes */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync NULL, /* pThreadAttributes */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync TRUE, /* fInheritHandles */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync dwCreationFlags,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pwszzBlock,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync NULL, /* pCurrentDirectory */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pStartupInfo,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pProcInfo);
c58c758d3642ac45d3f12356c406c631fcd8f538vboxsync if (fRc)
c58c758d3642ac45d3f12356c406c631fcd8f538vboxsync dwErr = NO_ERROR;
c58c758d3642ac45d3f12356c406c631fcd8f538vboxsync else
c58c758d3642ac45d3f12356c406c631fcd8f538vboxsync dwErr = GetLastError(); /* CreateProcessAsUserW() failed. */
c58c758d3642ac45d3f12356c406c631fcd8f538vboxsync
c58c758d3642ac45d3f12356c406c631fcd8f538vboxsync if (hTokenUserDesktop != INVALID_HANDLE_VALUE)
c58c758d3642ac45d3f12356c406c631fcd8f538vboxsync CloseHandle(hTokenUserDesktop);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync CloseHandle(hTokenLogon);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync else
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync dwErr = GetLastError(); /* LogonUserW() failed. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
6c2750d8e30830bf114880ca33922b108ab3e942vboxsync if (dwErr != NO_ERROR)
6c2750d8e30830bf114880ca33922b108ab3e942vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /*
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Map some important or much used Windows error codes
6c2750d8e30830bf114880ca33922b108ab3e942vboxsync * to our error codes.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
6c2750d8e30830bf114880ca33922b108ab3e942vboxsync switch (dwErr)
6c2750d8e30830bf114880ca33922b108ab3e942vboxsync {
6c2750d8e30830bf114880ca33922b108ab3e942vboxsync case ERROR_NOACCESS:
6c2750d8e30830bf114880ca33922b108ab3e942vboxsync case ERROR_PRIVILEGE_NOT_HELD:
6c2750d8e30830bf114880ca33922b108ab3e942vboxsync rc = VERR_PERMISSION_DENIED;
6c2750d8e30830bf114880ca33922b108ab3e942vboxsync break;
6c2750d8e30830bf114880ca33922b108ab3e942vboxsync
6c2750d8e30830bf114880ca33922b108ab3e942vboxsync case ERROR_PASSWORD_EXPIRED:
6c2750d8e30830bf114880ca33922b108ab3e942vboxsync case ERROR_ACCOUNT_RESTRICTION: /* See: http://support.microsoft.com/kb/303846/ */
6c2750d8e30830bf114880ca33922b108ab3e942vboxsync rc = VERR_LOGON_FAILURE;
6c2750d8e30830bf114880ca33922b108ab3e942vboxsync break;
6c2750d8e30830bf114880ca33922b108ab3e942vboxsync
6c2750d8e30830bf114880ca33922b108ab3e942vboxsync default:
6c2750d8e30830bf114880ca33922b108ab3e942vboxsync /* Could trigger a debug assertion! */
6c2750d8e30830bf114880ca33922b108ab3e942vboxsync rc = RTErrConvertFromWin32(dwErr);
6c2750d8e30830bf114880ca33922b108ab3e942vboxsync break;
6c2750d8e30830bf114880ca33922b108ab3e942vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync else
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync rc = VINF_SUCCESS;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return rc;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync}
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncRTR3DECL(int) RTProcCreateEx(const char *pszExec, const char * const *papszArgs, RTENV hEnv, uint32_t fFlags,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync PCRTHANDLE phStdIn, PCRTHANDLE phStdOut, PCRTHANDLE phStdErr, const char *pszAsUser,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync const char *pszPassword, PRTPROCESS phProcess)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
35327b0d3e16d29246883d9ffe93d54cb3a47e36vboxsync /*
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Input validation
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync AssertPtrReturn(pszExec, VERR_INVALID_POINTER);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync AssertReturn(*pszExec, VERR_INVALID_PARAMETER);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync AssertReturn(!(fFlags & ~(RTPROC_FLAGS_DAEMONIZE_DEPRECATED | RTPROC_FLAGS_DETACHED | RTPROC_FLAGS_SERVICE)), VERR_INVALID_PARAMETER);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync AssertReturn(!(fFlags & RTPROC_FLAGS_DETACHED) || !phProcess, VERR_INVALID_PARAMETER);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync AssertReturn(hEnv != NIL_RTENV, VERR_INVALID_PARAMETER);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync AssertPtrReturn(papszArgs, VERR_INVALID_PARAMETER);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync AssertPtrNullReturn(pszAsUser, VERR_INVALID_POINTER);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync AssertReturn(!pszAsUser || *pszAsUser, VERR_INVALID_PARAMETER);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync AssertReturn(!pszPassword || pszAsUser, VERR_INVALID_PARAMETER);
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync AssertPtrNullReturn(pszPassword, VERR_INVALID_POINTER);
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync /** @todo search the PATH (add flag for this). */
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync /*
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync * Initialize the globals.
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync */
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync int rc = RTOnce(&g_rtProcWinInitOnce, rtProcWinInitOnce, NULL, NULL);
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync AssertRCReturn(rc, rc);
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync /*
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync * Get the file descriptors for the handles we've been passed.
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync *
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync * It seems there is no point in trying to convince a child process's CRT
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * that any of the standard file handles is non-TEXT. So, we don't...
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync STARTUPINFOW StartupInfo;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RT_ZERO(StartupInfo);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync StartupInfo.cb = sizeof(StartupInfo);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync StartupInfo.dwFlags = STARTF_USESTDHANDLES;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#if 1 /* The CRT should keep the standard handles up to date. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync StartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
StartupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
StartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
#else
StartupInfo.hStdInput = _get_osfhandle(0);
StartupInfo.hStdOutput = _get_osfhandle(1);
StartupInfo.hStdError = _get_osfhandle(2);
#endif
PCRTHANDLE paHandles[3] = { phStdIn, phStdOut, phStdErr };
HANDLE *aphStds[3] = { &StartupInfo.hStdInput, &StartupInfo.hStdOutput, &StartupInfo.hStdError };
DWORD afInhStds[3] = { 0xffffffff, 0xffffffff, 0xffffffff };
for (int i = 0; i < 3; i++)
{
if (paHandles[i])
{
AssertPtrReturn(paHandles[i], VERR_INVALID_POINTER);
switch (paHandles[i]->enmType)
{
case RTHANDLETYPE_FILE:
*aphStds[i] = paHandles[i]->u.hFile != NIL_RTFILE
? (HANDLE)RTFileToNative(paHandles[i]->u.hFile)
: INVALID_HANDLE_VALUE;
break;
case RTHANDLETYPE_PIPE:
*aphStds[i] = paHandles[i]->u.hPipe != NIL_RTPIPE
? (HANDLE)RTPipeToNative(paHandles[i]->u.hPipe)
: INVALID_HANDLE_VALUE;
break;
case RTHANDLETYPE_SOCKET:
*aphStds[i] = paHandles[i]->u.hSocket != NIL_RTSOCKET
? (HANDLE)RTSocketToNative(paHandles[i]->u.hSocket)
: INVALID_HANDLE_VALUE;
break;
default:
AssertMsgFailedReturn(("%d: %d\n", i, paHandles[i]->enmType), VERR_INVALID_PARAMETER);
}
/* Get the inheritability of the handle. */
if (*aphStds[i] != INVALID_HANDLE_VALUE)
{
if (!GetHandleInformation(*aphStds[i], &afInhStds[i]))
{
rc = RTErrConvertFromWin32(GetLastError());
AssertMsgFailedReturn(("%Rrc %p\n", rc, *aphStds[i]), rc);
}
}
}
}
/*
* Set the inheritability any handles we're handing the child.
*/
rc = VINF_SUCCESS;
for (int i = 0; i < 3; i++)
if ( (afInhStds[i] != 0xffffffff)
&& !(afInhStds[i] & HANDLE_FLAG_INHERIT))
{
if (!SetHandleInformation(*aphStds[i], HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT))
{
rc = RTErrConvertFromWin32(GetLastError());
AssertMsgFailedBreak(("%Rrc %p\n", rc, *aphStds[i]));
}
}
/*
* Create the environment block, command line and convert the executable
* name.
*/
PRTUTF16 pwszzBlock;
if (RT_SUCCESS(rc))
rc = RTEnvQueryUtf16Block(hEnv, &pwszzBlock);
if (RT_SUCCESS(rc))
{
PRTUTF16 pwszCmdLine;
rc = RTGetOptArgvToUtf16String(&pwszCmdLine, papszArgs, RTGETOPTARGV_CNV_QUOTE_MS_CRT);
if (RT_SUCCESS(rc))
{
PRTUTF16 pwszExec;
rc = RTStrToUtf16(pszExec, &pwszExec);
if (RT_SUCCESS(rc))
{
/*
* Get going...
*/
DWORD dwCreationFlags = CREATE_UNICODE_ENVIRONMENT;
if (fFlags & RTPROC_FLAGS_DETACHED)
dwCreationFlags |= DETACHED_PROCESS;
PROCESS_INFORMATION ProcInfo;
RT_ZERO(ProcInfo);
/*
* Only use the normal CreateProcess stuff if we have no user name
* and we are not running from a (Windows) service. Otherwise use
* the more advanced version in rtProcCreateAsUserHlp().
*/
if ( pszAsUser == NULL
&& !(fFlags & RTPROC_FLAGS_SERVICE))
{
if (CreateProcessW(pwszExec,
pwszCmdLine,
NULL, /* pProcessAttributes */
NULL, /* pThreadAttributes */
TRUE, /* fInheritHandles */
dwCreationFlags,
pwszzBlock,
NULL, /* pCurrentDirectory */
&StartupInfo,
&ProcInfo))
rc = VINF_SUCCESS;
else
rc = RTErrConvertFromWin32(GetLastError());
}
else
{
/*
* Convert the additional parameters and use a helper
* function to do the actual work.
*/
PRTUTF16 pwszUser;
rc = RTStrToUtf16(pszAsUser, &pwszUser);
if (RT_SUCCESS(rc))
{
PRTUTF16 pwszPassword;
rc = RTStrToUtf16(pszPassword ? pszPassword : "", &pwszPassword);
if (RT_SUCCESS(rc))
{
rc = rtProcCreateAsUserHlp(pwszUser, pwszPassword,
pwszExec, pwszCmdLine, pwszzBlock, dwCreationFlags,
&StartupInfo, &ProcInfo, fFlags);
RTUtf16Free(pwszPassword);
}
RTUtf16Free(pwszUser);
}
}
if (RT_SUCCESS(rc))
{
CloseHandle(ProcInfo.hThread);
if (phProcess)
{
/*
* Add the process to the child process list so
* RTProcWait can reuse and close the process handle.
*/
rtProcWinAddPid(ProcInfo.dwProcessId, ProcInfo.hProcess);
*phProcess = ProcInfo.dwProcessId;
}
else
CloseHandle(ProcInfo.hProcess);
rc = VINF_SUCCESS;
}
RTUtf16Free(pwszExec);
}
RTUtf16Free(pwszCmdLine);
}
RTEnvFreeUtf16Block(pwszzBlock);
}
/* Undo any handle inherit changes. */
for (int i = 0; i < 3; i++)
if ( (afInhStds[i] != 0xffffffff)
&& !(afInhStds[i] & HANDLE_FLAG_INHERIT))
{
if (!SetHandleInformation(*aphStds[i], HANDLE_FLAG_INHERIT, 0))
AssertMsgFailed(("%Rrc %p\n", RTErrConvertFromWin32(GetLastError()), *aphStds[i]));
}
return rc;
}
RTR3DECL(int) RTProcWait(RTPROCESS Process, unsigned fFlags, PRTPROCSTATUS pProcStatus)
{
AssertReturn(!(fFlags & ~(RTPROCWAIT_FLAGS_BLOCK | RTPROCWAIT_FLAGS_NOBLOCK)), VERR_INVALID_PARAMETER);
int rc = RTOnce(&g_rtProcWinInitOnce, rtProcWinInitOnce, NULL, NULL);
AssertRCReturn(rc, rc);
/*
* Try find the process among the ones we've spawned, otherwise, attempt
* opening the specified process.
*/
HANDLE hProcess = rtProcWinFindPid(Process);
if (hProcess == NULL)
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, Process);
if (hProcess != NULL)
{
/*
* Wait for it to terminate.
*/
DWORD Millies = fFlags == RTPROCWAIT_FLAGS_BLOCK ? INFINITE : 0;
DWORD WaitRc = WaitForSingleObjectEx(hProcess, Millies, TRUE);
while (WaitRc == WAIT_IO_COMPLETION)
WaitRc = WaitForSingleObjectEx(hProcess, Millies, TRUE);
switch (WaitRc)
{
/*
* It has terminated.
*/
case WAIT_OBJECT_0:
{
DWORD dwExitCode;
if (GetExitCodeProcess(hProcess, &dwExitCode))
{
/** @todo the exit code can be special statuses. */
if (pProcStatus)
{
pProcStatus->enmReason = RTPROCEXITREASON_NORMAL;
pProcStatus->iStatus = (int)dwExitCode;
}
rtProcWinRemovePid(Process);
return VINF_SUCCESS;
}
break;
}
/*
* It hasn't terminated just yet.
*/
case WAIT_TIMEOUT:
return VERR_PROCESS_RUNNING;
/*
* Something went wrong...
*/
case WAIT_FAILED:
break;
case WAIT_ABANDONED:
AssertFailed();
return VERR_GENERAL_FAILURE;
default:
AssertMsgFailed(("WaitRc=%RU32\n", WaitRc));
return VERR_GENERAL_FAILURE;
}
}
DWORD dwErr = GetLastError();
if (dwErr == ERROR_INVALID_PARAMETER)
return VERR_PROCESS_NOT_FOUND;
return RTErrConvertFromWin32(dwErr);
}
RTR3DECL(int) RTProcWaitNoResume(RTPROCESS Process, unsigned fFlags, PRTPROCSTATUS pProcStatus)
{
/** @todo this isn't quite right. */
return RTProcWait(Process, fFlags, pProcStatus);
}
RTR3DECL(int) RTProcTerminate(RTPROCESS Process)
{
int rc = VINF_SUCCESS;
HANDLE hProcess = rtProcWinFindPid(Process);
if (hProcess != NULL)
{
if (!TerminateProcess(hProcess, 127))
rc = RTErrConvertFromWin32(GetLastError());
}
else
{
hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, Process);
if (hProcess != NULL)
{
BOOL fRc = TerminateProcess(hProcess, 127);
DWORD dwErr = GetLastError();
CloseHandle(hProcess);
if (!fRc)
rc = RTErrConvertFromWin32(dwErr);
}
}
return rc;
}
RTR3DECL(uint64_t) RTProcGetAffinityMask(void)
{
DWORD_PTR dwProcessAffinityMask = 0xffffffff;
DWORD_PTR dwSystemAffinityMask;
BOOL fRc = GetProcessAffinityMask(GetCurrentProcess(), &dwProcessAffinityMask, &dwSystemAffinityMask);
Assert(fRc);
return dwProcessAffinityMask;
}