VirtualBox

Changeset 29726 in vbox for trunk/src/VBox/Runtime/r3/win


Ignore:
Timestamp:
May 21, 2010 12:24:54 PM (15 years ago)
Author:
vboxsync
Message:

IPRT/process-win: Fixed some errors, added NT4 support, modularized a bit.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/r3/win/process-win.cpp

    r29718 r29726  
    3535#include <tlhelp32.h>
    3636#include <process.h>
     37#include <psapi.h>      /* For EnumProcesses(). */
    3738#include <errno.h>
    3839
     
    7475typedef FNWTSGETACTIVECONSOLESESSIONID *PFNWTSGETACTIVECONSOLESESSIONID;
    7576
    76 typedef BOOL WINAPI FNWTSQUERYUSERTOKEN(ULONG, PHANDLE);
    77 typedef FNWTSQUERYUSERTOKEN *PFNWTSQUERYUSERTOKEN;
     77typedef HANDLE WINAPI FNCREATETOOLHELP32SNAPSHOT(DWORD, DWORD);
     78typedef FNCREATETOOLHELP32SNAPSHOT *PFNCREATETOOLHELP32SNAPSHOT;
     79
     80typedef BOOL WINAPI FNPROCESS32FIRST(HANDLE, LPPROCESSENTRY32);
     81typedef FNPROCESS32FIRST *PFNPROCESS32FIRST;
     82
     83typedef BOOL WINAPI FNPROCESS32NEXT(HANDLE, LPPROCESSENTRY32);
     84typedef FNPROCESS32NEXT *PFNPROCESS32NEXT;
     85
     86typedef BOOL WINAPI FNENUMPROCESSES(DWORD*, DWORD, DWORD*);
     87typedef FNENUMPROCESSES *PFNENUMPROCESSES;
     88
     89typedef DWORD FNGETMODULEBASENAME(HANDLE, HMODULE, LPTSTR, DWORD);
     90typedef FNGETMODULEBASENAME *PFNGETMODULEBASENAME;
    7891
    7992
     
    242255
    243256
     257static int rtProcGetProcessHandle(DWORD dwPID, PSID pSID, PHANDLE phToken)
     258{
     259    AssertPtr(pSID);
     260    AssertPtr(phToken);
     261
     262    DWORD dwErr;
     263    BOOL fRc;
     264    BOOL fFound = FALSE;
     265    HANDLE hProc = OpenProcess(MAXIMUM_ALLOWED, TRUE, dwPID);
     266    if (hProc != NULL)
     267    {
     268        HANDLE hTokenProc;
     269        fRc = OpenProcessToken(hProc,
     270                               TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_DUPLICATE |
     271                               TOKEN_ASSIGN_PRIMARY | TOKEN_ADJUST_SESSIONID | TOKEN_READ | TOKEN_WRITE,
     272                               &hTokenProc);
     273        if (fRc)
     274        {
     275            DWORD dwSize = 0;
     276            fRc = GetTokenInformation(hTokenProc, TokenUser, NULL, 0, &dwSize);
     277            if (!fRc)
     278                dwErr = GetLastError();
     279            if (   !fRc
     280                && dwErr == ERROR_INSUFFICIENT_BUFFER
     281                && dwSize > 0)
     282            {
     283                PTOKEN_USER pTokenUser = (PTOKEN_USER)RTMemAlloc(dwSize);
     284                AssertPtrReturn(pTokenUser, VERR_NO_MEMORY);
     285                RT_ZERO(*pTokenUser);
     286                if (   GetTokenInformation(hTokenProc,
     287                                           TokenUser,
     288                                           (LPVOID)pTokenUser,
     289                                           dwSize,
     290                                           &dwSize)
     291                    && IsValidSid(pTokenUser->User.Sid)
     292                    && EqualSid(pTokenUser->User.Sid, pSID))
     293                {
     294                    if (DuplicateTokenEx(hTokenProc, MAXIMUM_ALLOWED,
     295                                         NULL, SecurityIdentification, TokenPrimary, phToken))
     296                    {
     297                        /*
     298                         * So we found a VBoxTray instance which belongs to the user we want to
     299                         * to run our new process under. This duplicated token will be used for
     300                         * the actual CreateProcessAsUserW() call then.
     301                         */
     302                        fFound = TRUE;                                                       
     303                    }
     304                    else
     305                        dwErr = GetLastError();
     306                }
     307                else
     308                    dwErr = GetLastError();
     309                RTMemFree(pTokenUser);
     310            }
     311            else
     312                dwErr = GetLastError();
     313            CloseHandle(hTokenProc);
     314        }
     315        else
     316            dwErr = GetLastError();
     317        CloseHandle(hProc);
     318    }
     319    else
     320        dwErr = GetLastError();
     321    if (fFound)
     322        return VINF_SUCCESS;
     323    return RTErrConvertFromWin32(dwErr);
     324}
     325
     326
     327static BOOL rtProcFindProcessByName(const char *pszName, PSID pSID, PHANDLE phToken)
     328{
     329    AssertPtr(pszName);
     330    AssertPtr(pSID);
     331    AssertPtr(phToken);
     332
     333    DWORD dwErr = NO_ERROR;
     334    BOOL fFound = FALSE;
     335
     336    /*
     337     * On modern systems (W2K+) try the Toolhelp32 API first; this is more stable
     338     * and reliable. Fallback to EnumProcess on NT4.
     339     */
     340    RTLDRMOD hKernel32;
     341    int rc = RTLdrLoad("Kernel32.dll", &hKernel32);
     342    if (RT_SUCCESS(rc))
     343    {
     344        PFNCREATETOOLHELP32SNAPSHOT pfnCreateToolhelp32Snapshot;
     345        rc = RTLdrGetSymbol(hKernel32, "CreateToolhelp32Snapshot", (void**)&pfnCreateToolhelp32Snapshot);
     346        if (RT_SUCCESS(rc))
     347        {
     348            PFNPROCESS32FIRST pfnProcess32First;
     349            rc = RTLdrGetSymbol(hKernel32, "Process32First", (void**)&pfnProcess32First);
     350            if (RT_SUCCESS(rc))
     351            {
     352                PFNPROCESS32NEXT pfnProcess32Next;
     353                rc = RTLdrGetSymbol(hKernel32, "Process32Next", (void**)&pfnProcess32Next);
     354                if (RT_SUCCESS(rc))
     355                {
     356                    HANDLE hSnap = pfnCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
     357                    if (hSnap != INVALID_HANDLE_VALUE)
     358                    {
     359                        PROCESSENTRY32 procEntry;
     360                        procEntry.dwSize = sizeof(PROCESSENTRY32);
     361                        if (pfnProcess32First(hSnap, &procEntry))
     362                        {       
     363                            do
     364                            {
     365                                if (   _stricmp(procEntry.szExeFile, pszName) == 0
     366                                    && RT_SUCCESS(rtProcGetProcessHandle(procEntry.th32ProcessID, pSID, phToken)))
     367                                {
     368                                    fFound = TRUE;
     369                                }
     370                            } while (pfnProcess32Next(hSnap, &procEntry) && !fFound);
     371                        }
     372                        else /* Process32First */
     373                            dwErr = GetLastError();
     374                        CloseHandle(hSnap);
     375                    }
     376                    else /* hSnap =! INVALID_HANDLE_VALUE */
     377                        dwErr = GetLastError();
     378                }
     379            }
     380        }
     381        else /* CreateToolhelp32Snapshot / Toolhelp32 API not available. */
     382        {
     383            /*
     384             * NT4 needs a copy of "PSAPI.dll" (redistributed by Microsoft and not
     385             * part of the OS) in order to get a lookup. If we don't have this DLL
     386             * we are not able to get a token and therefore no UI will be visible.
     387             */
     388            RTLDRMOD hPSAPI;
     389            int rc = RTLdrLoad("PSAPI.dll", &hPSAPI);
     390            if (RT_SUCCESS(rc))
     391            {
     392                PFNENUMPROCESSES pfnEnumProcesses;
     393                rc = RTLdrGetSymbol(hPSAPI, "EnumProcesses", (void**)&pfnEnumProcesses);
     394                if (RT_SUCCESS(rc))
     395                {
     396                    PFNGETMODULEBASENAME pfnGetModuleBaseName;
     397                    rc = RTLdrGetSymbol(hPSAPI, "GetModuleBaseName", (void**)&pfnGetModuleBaseName);
     398                    if (RT_SUCCESS(rc))
     399                    {           
     400                        /** @todo Retry if pBytesReturned equals cbBytes! */
     401                        DWORD dwPIDs[4096]; /* Should be sufficient for now. */
     402                        DWORD cbBytes = 0;
     403                        if (pfnEnumProcesses(dwPIDs, sizeof(dwPIDs), &cbBytes))
     404                        {
     405                            for (DWORD dwIdx = 0; dwIdx < cbBytes/sizeof(DWORD) && !fFound; dwIdx++)
     406                            {
     407                                HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
     408                                                           FALSE, dwPIDs[dwIdx]);
     409                                if (hProc)
     410                                {
     411                                    char *pszProcName = NULL;
     412                                    DWORD dwSize = 128;
     413                                    do
     414                                    {
     415                                        RTMemRealloc(pszProcName, dwSize);
     416                                        if (pfnGetModuleBaseName(hProc, 0, pszProcName, dwSize) == dwSize)
     417                                            dwSize += 128;
     418                                    } while (GetLastError() == ERROR_INSUFFICIENT_BUFFER);
     419               
     420                                    if (pszProcName)
     421                                    {
     422                                        if (   _stricmp(pszProcName, pszName) == 0
     423                                            && RT_SUCCESS(rtProcGetProcessHandle(dwPIDs[dwIdx], pSID, phToken)))
     424                                        {
     425                                            fFound = TRUE;
     426                                        }
     427                                    }
     428                                    if (pszProcName)
     429                                        RTStrFree(pszProcName);
     430                                    CloseHandle(hProc);
     431                                }
     432                            }
     433                        }
     434                        else
     435                            dwErr = GetLastError();
     436                    }
     437                }
     438            }
     439        }
     440        RTLdrClose(hKernel32);
     441    }
     442    Assert(dwErr == NO_ERROR);
     443    return fFound;
     444}
     445
     446
    244447static int rtProcCreateAsUserHlp(PRTUTF16 pwszUser, PRTUTF16 pwszPassword, PRTUTF16 pwszExec, PRTUTF16 pwszCmdLine,
    245448                                 PRTUTF16 pwszzBlock, DWORD dwCreationFlags,
     
    285488            RTLdrClose(hAdvAPI32);
    286489        }
    287     }
    288 
    289     /*
    290      * Get the session ID.
    291      */
    292     DWORD dwSessionID = 0; /* On W2K the session ID is always 0 (does not have fast user switching). */
    293     RTLDRMOD hKernel32;
    294     rc = RTLdrLoad("Kernel32.dll", &hKernel32);
    295     if (RT_SUCCESS(rc))
    296     {
    297         PFNWTSGETACTIVECONSOLESESSIONID pfnWTSGetActiveConsoleSessionId;
    298         rc = RTLdrGetSymbol(hKernel32, "WTSGetActiveConsoleSessionId", (void **)&pfnWTSGetActiveConsoleSessionId);
    299         if (RT_SUCCESS(rc))
    300         {
    301             /*
    302              * Console session means the session which the physical keyboard and mouse
    303              * is connected to. Due to FUS (fast user switching) starting with Windows XP
    304              * this can be a different session than 0.
    305              */
    306             dwSessionID = pfnWTSGetActiveConsoleSessionId(); /* Get active console session ID. */
    307         }
    308         RTLdrClose(hKernel32);
    309490    }
    310491
     
    342523         * We may fail here with ERROR_PRIVILEGE_NOT_HELD.
    343524         *
    344          ** @todo Deal with http://support.microsoft.com/kb/245683 for NULL domain names
    345          * on NT4 (ignored here by now). Passing FQDNs should work!
     525         * Because we have to deal with http://support.microsoft.com/kb/245683 for NULL domain names
     526         * on NT4 here, pass an empty string. However, passing FQDNs should work!
    346527         */
    347528        PHANDLE phToken = NULL;
    348529        HANDLE hTokenLogon = INVALID_HANDLE_VALUE;
    349530        fRc = LogonUserW(pwszUser,
    350                          NULL,
     531                         L"",
    351532                         pwszPassword,
    352533                         LOGON32_LOGON_INTERACTIVE,
     
    354535                         &hTokenLogon);
    355536
    356         BOOL bFound = FALSE;
     537        BOOL fFound = FALSE;
    357538        HANDLE hTokenVBoxTray = INVALID_HANDLE_VALUE;
    358539        if (fRc)
     
    382563   
    383564                    /** @todo No way to allocate a PRTUTF16 directly? */
    384                     char *pszDomainUtf8 = NULL;
    385565                    PRTUTF16 pwszDomain = NULL;
    386566                    if (cbDomain > 0)
    387567                    {
    388                         pszDomainUtf8 = RTStrAlloc(cbDomain);
    389                         rc = RTStrToUtf16(pszDomainUtf8, &pwszDomain);
    390                         AssertRCReturn(rc, rc);
    391                         RTStrFree(pszDomainUtf8);
     568                        pwszDomain = (PRTUTF16)RTMemAlloc(cbDomain * sizeof(RTUTF16));
     569                        AssertPtrReturn(pwszDomain, VERR_NO_MEMORY);
    392570                    }
    393571   
     
    402580                        && IsValidSid(pSID))
    403581                    {
    404                         HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    405                         if (hSnap != INVALID_HANDLE_VALUE)
    406                         {
    407                             PROCESSENTRY32 procEntry;
    408                             procEntry.dwSize = sizeof(PROCESSENTRY32);
    409                             if (Process32First(hSnap, &procEntry))
    410                             {       
    411                                 DWORD dwVBoxTrayPID = 0;
    412                                 DWORD dwCurSession = 0;
    413                                 do
    414                                 {
    415                                     if (   _stricmp(procEntry.szExeFile, "VBoxTray.exe") == 0
    416                                         && ProcessIdToSessionId(procEntry.th32ProcessID, &dwCurSession))
    417                                     {
    418                                         HANDLE hProc = OpenProcess(MAXIMUM_ALLOWED, TRUE, procEntry.th32ProcessID);
    419                                         if (hProc != NULL)
    420                                         {
    421                                             HANDLE hTokenProc;
    422                                             fRc = OpenProcessToken(hProc,
    423                                                                    TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_DUPLICATE |
    424                                                                    TOKEN_ASSIGN_PRIMARY | TOKEN_ADJUST_SESSIONID | TOKEN_READ | TOKEN_WRITE,
    425                                                                    &hTokenProc);
    426                                             if (fRc)
    427                                             {
    428                                                 DWORD dwSize = 0;
    429                                                 fRc = GetTokenInformation(hTokenProc, TokenUser, NULL, 0, &dwSize);
    430                                                 if (!fRc)
    431                                                     dwErr = GetLastError();
    432                                                 if (   !fRc
    433                                                     && dwErr == ERROR_INSUFFICIENT_BUFFER
    434                                                     && dwSize > 0)
    435                                                 {
    436                                                     PTOKEN_USER pTokenUser = (PTOKEN_USER)RTMemAlloc(dwSize);
    437                                                     AssertPtrBreak(pTokenUser);
    438                                                     RT_ZERO(*pTokenUser);
    439                                                     if (   GetTokenInformation(hTokenProc,
    440                                                                                TokenUser,
    441                                                                                (LPVOID)pTokenUser,
    442                                                                                dwSize,
    443                                                                                &dwSize)
    444                                                         && IsValidSid(pTokenUser->User.Sid)
    445                                                         && EqualSid(pTokenUser->User.Sid, pSID))
    446                                                     {
    447                                                         if (DuplicateTokenEx(hTokenProc, MAXIMUM_ALLOWED,
    448                                                                              NULL, SecurityIdentification, TokenPrimary, &hTokenVBoxTray))
    449                                                         {
    450                                                             /*
    451                                                              * So we found a VBoxTray instance which belongs to the user we want to
    452                                                              * to run our new process under. This duplicated token will be used for
    453                                                              * the actual CreateProcessAsUserW() call then.
    454                                                              */
    455                                                             bFound = TRUE;                                                       
    456                                                         }
    457                                                         else
    458                                                             dwErr = GetLastError();
    459                                                     }
    460                                                     else
    461                                                         dwErr = GetLastError();
    462                                                     RTMemFree(pTokenUser);
    463                                                 }
    464                                                 else
    465                                                     dwErr = GetLastError();
    466                                                 CloseHandle(hTokenProc);
    467                                             }
    468                                             else
    469                                                 dwErr = GetLastError();
    470                                             CloseHandle(hProc);
    471                                         }
    472                                         else
    473                                             dwErr = GetLastError();
    474                                     }
    475                                 } while (Process32Next(hSnap, &procEntry) && !bFound);
    476                             }
    477                             else /* Process32First */
    478                                 dwErr = GetLastError();
    479                             CloseHandle(hSnap);
    480                         }
    481                         else /* hSnap =! INVALID_HANDLE_VALUE */
    482                             dwErr = GetLastError();
     582                        fFound = rtProcFindProcessByName(
     583#ifdef VBOX
     584                                                         "VBoxTray.exe",
     585#else
     586                                                         "explorer.exe"
     587#endif
     588                                                         pSID, &hTokenVBoxTray);
    483589                    }
    484590                    else
     
    499605             * desktop interaction without UI.
    500606             */
    501             phToken = bFound ? &hTokenVBoxTray : &hTokenLogon;
     607            phToken = fFound ? &hTokenVBoxTray : &hTokenLogon;
    502608
    503609            /*
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette