~ubuntu-branches/ubuntu/raring/virtualbox-ose/raring

« back to all changes in this revision

Viewing changes to src/VBox/Runtime/r3/win/process-win.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Felix Geyer
  • Date: 2011-01-30 23:27:25 UTC
  • mfrom: (0.3.12 upstream)
  • Revision ID: james.westby@ubuntu.com-20110130232725-2ouajjd2ggdet0zd
Tags: 4.0.2-dfsg-1ubuntu1
* Merge from Debian unstable, remaining changes:
  - Add Apport hook.
    - debian/virtualbox-ose.files/source_virtualbox-ose.py
    - debian/virtualbox-ose.install
  - Drop *-source packages.
* Drop ubuntu-01-fix-build-gcc45.patch, fixed upstream.
* Drop ubuntu-02-as-needed.patch, added to the Debian package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* $Id: process-win.cpp $ */
 
1
/* $Id: process-win.cpp 34708 2010-12-03 17:30:45Z vboxsync $ */
2
2
/** @file
3
3
 * IPRT - Process, Windows.
4
4
 */
35
35
#include <tlhelp32.h>
36
36
#include <process.h>
37
37
#include <errno.h>
 
38
#include <Strsafe.h>
38
39
 
39
40
#include <iprt/process.h>
40
41
#include "internal/iprt.h"
88
89
typedef DWORD FNGETMODULEBASENAME(HANDLE, HMODULE, LPTSTR, DWORD);
89
90
typedef FNGETMODULEBASENAME *PFNGETMODULEBASENAME;
90
91
 
 
92
typedef BOOL WINAPI FNCREATEENVIRONMENTBLOCK(LPVOID *, HANDLE, BOOL);
 
93
typedef FNCREATEENVIRONMENTBLOCK *PFNCREATEENVIRONMENTBLOCK;
 
94
 
 
95
typedef BOOL WINAPI FNPFNDESTROYENVIRONMENTBLOCK(LPVOID);
 
96
typedef FNPFNDESTROYENVIRONMENTBLOCK *PFNPFNDESTROYENVIRONMENTBLOCK;
 
97
 
 
98
typedef BOOL WINAPI FNLOADUSERPROFILEW(HANDLE, LPPROFILEINFOW);
 
99
typedef FNLOADUSERPROFILEW *PFNLOADUSERPROFILEW;
 
100
 
 
101
typedef BOOL WINAPI FNUNLOADUSERPROFILE(HANDLE, HANDLE);
 
102
typedef FNUNLOADUSERPROFILE *PFNUNLOADUSERPROFILE;
 
103
 
91
104
 
92
105
/*******************************************************************************
93
106
*   Global Variables                                                           *
253
266
}
254
267
 
255
268
 
 
269
/**
 
270
 * Map some important or much used Windows error codes
 
271
 * to our error codes.
 
272
 *
 
273
 * @return  Mapped IPRT status code.
 
274
 * @param   dwError                         Windows error code to map to IPRT code.
 
275
 */
 
276
static int rtProcMapErrorCodes(DWORD dwError)
 
277
{
 
278
    int rc;
 
279
    switch (dwError)
 
280
    {
 
281
        case ERROR_NOACCESS:
 
282
        case ERROR_PRIVILEGE_NOT_HELD:
 
283
            rc = VERR_PERMISSION_DENIED;
 
284
            break;
 
285
 
 
286
        case ERROR_PASSWORD_EXPIRED:
 
287
        case ERROR_ACCOUNT_RESTRICTION: /* See: http://support.microsoft.com/kb/303846/ */
 
288
        case ERROR_PASSWORD_RESTRICTION:
 
289
            rc = VERR_AUTHENTICATION_FAILURE;
 
290
            break;
 
291
 
 
292
        default:
 
293
            /* Could trigger a debug assertion! */
 
294
            rc = RTErrConvertFromWin32(dwError);
 
295
            break;
 
296
    }
 
297
    return rc;
 
298
}
 
299
 
 
300
 
 
301
/**
 
302
 * Get the process token (not the process handle like the name might indicate)
 
303
 * of the process indicated by @a dwPID if the @a pSID matches.
 
304
 *
 
305
 * @returns IPRT status code.
 
306
 *
 
307
 * @param   dwPID           The process identifier.
 
308
 * @param   pSID            The secure identifier of the user.
 
309
 * @param   phToken         Where to return the token handle - duplicate,
 
310
 *                          caller closes it on success.
 
311
 */
256
312
static int rtProcGetProcessHandle(DWORD dwPID, PSID pSID, PHANDLE phToken)
257
313
{
258
314
    AssertPtr(pSID);
260
316
 
261
317
    DWORD dwErr;
262
318
    BOOL fRc;
263
 
    BOOL fFound = FALSE;
 
319
    bool fFound = false;
264
320
    HANDLE hProc = OpenProcess(MAXIMUM_ALLOWED, TRUE, dwPID);
265
321
    if (hProc != NULL)
266
322
    {
267
323
        HANDLE hTokenProc;
268
324
        fRc = OpenProcessToken(hProc,
269
 
                               TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_DUPLICATE |
270
 
                               TOKEN_ASSIGN_PRIMARY | TOKEN_ADJUST_SESSIONID | TOKEN_READ | TOKEN_WRITE,
 
325
                               TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_DUPLICATE
 
326
                               | TOKEN_ASSIGN_PRIMARY | TOKEN_ADJUST_SESSIONID | TOKEN_READ | TOKEN_WRITE,
271
327
                               &hTokenProc);
272
328
        if (fRc)
273
329
        {
299
355
                             * to run our new process under. This duplicated token will be used for
300
356
                             * the actual CreateProcessAsUserW() call then.
301
357
                             */
302
 
                            fFound = TRUE;
 
358
                            fFound = true;
303
359
                        }
304
360
                        else
305
361
                            dwErr = GetLastError();
323
379
        return VINF_SUCCESS;
324
380
    if (dwErr != NO_ERROR)
325
381
        return RTErrConvertFromWin32(dwErr);
326
 
    return VERR_NOT_FOUND; /* No error occured, but we didn't find the right process. */
 
382
    return VERR_NOT_FOUND; /* No error occurred, but we didn't find the right process. */
327
383
}
328
384
 
329
385
 
330
 
static BOOL rtProcFindProcessByName(const char *pszName, PSID pSID, PHANDLE phToken)
 
386
/**
 
387
 * Finds a one of the processes in @a papszNames running with user @a pSID and
 
388
 * returns a duplicate handle to its token.
 
389
 *
 
390
 * @returns Success indicator.
 
391
 * @param   papszNames      The process candidates, in prioritized order.
 
392
 * @param   pSID            The secure identifier of the user.
 
393
 * @param   phToken         Where to return the token handle - duplicate,
 
394
 *                          caller closes it on success.
 
395
 */
 
396
static bool rtProcFindProcessByName(const char * const *papszNames, PSID pSID, PHANDLE phToken)
331
397
{
332
 
    AssertPtr(pszName);
 
398
    AssertPtr(papszNames);
333
399
    AssertPtr(pSID);
334
400
    AssertPtr(phToken);
335
401
 
336
402
    DWORD dwErr = NO_ERROR;
337
 
    BOOL fFound = FALSE;
 
403
    bool fFound = false;
338
404
 
339
405
    /*
340
406
     * On modern systems (W2K+) try the Toolhelp32 API first; this is more stable
359
425
                    HANDLE hSnap = pfnCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
360
426
                    if (hSnap != INVALID_HANDLE_VALUE)
361
427
                    {
362
 
                        PROCESSENTRY32 procEntry;
363
 
                        procEntry.dwSize = sizeof(PROCESSENTRY32);
364
 
                        if (pfnProcess32First(hSnap, &procEntry))
 
428
                        for (size_t i = 0; papszNames[i] && !fFound; i++)
365
429
                        {
366
 
                            do
 
430
                            PROCESSENTRY32 procEntry;
 
431
                            procEntry.dwSize = sizeof(PROCESSENTRY32);
 
432
                            if (pfnProcess32First(hSnap, &procEntry))
367
433
                            {
368
 
                                if (   _stricmp(procEntry.szExeFile, pszName) == 0
369
 
                                    && RT_SUCCESS(rtProcGetProcessHandle(procEntry.th32ProcessID, pSID, phToken)))
 
434
                                do
370
435
                                {
371
 
                                    fFound = TRUE;
372
 
                                }
373
 
                            } while (pfnProcess32Next(hSnap, &procEntry) && !fFound);
 
436
                                    if (   _stricmp(procEntry.szExeFile, papszNames[i]) == 0
 
437
                                        && RT_SUCCESS(rtProcGetProcessHandle(procEntry.th32ProcessID, pSID, phToken)))
 
438
                                    {
 
439
                                        fFound = true;
 
440
                                        break;
 
441
                                    }
 
442
                                } while (pfnProcess32Next(hSnap, &procEntry));
 
443
                            }
 
444
                            else /* Process32First */
 
445
                                dwErr = GetLastError();
 
446
                            if (FAILED(dwErr))
 
447
                                break;
374
448
                        }
375
 
                        else /* Process32First */
376
 
                            dwErr = GetLastError();
377
449
                        CloseHandle(hSnap);
378
450
                    }
379
 
                    else /* hSnap =! INVALID_HANDLE_VALUE */
 
451
                    else /* hSnap == INVALID_HANDLE_VALUE */
380
452
                        dwErr = GetLastError();
381
453
                }
382
454
            }
401
473
                    if (RT_SUCCESS(rc))
402
474
                    {
403
475
                        /** @todo Retry if pBytesReturned equals cbBytes! */
404
 
                        DWORD dwPIDs[4096]; /* Should be sufficient for now. */
 
476
                        DWORD adwPIDs[4096]; /* Should be sufficient for now. */
405
477
                        DWORD cbBytes = 0;
406
 
                        if (pfnEnumProcesses(dwPIDs, sizeof(dwPIDs), &cbBytes))
 
478
                        if (pfnEnumProcesses(adwPIDs, sizeof(adwPIDs), &cbBytes))
407
479
                        {
408
 
                            for (DWORD dwIdx = 0; dwIdx < cbBytes/sizeof(DWORD) && !fFound; dwIdx++)
 
480
                            for (size_t i = 0; papszNames[i] && !fFound; i++)
409
481
                            {
410
 
                                HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
411
 
                                                           FALSE, dwPIDs[dwIdx]);
412
 
                                if (hProc)
 
482
                                for (DWORD dwIdx = 0; dwIdx < cbBytes/sizeof(DWORD) && !fFound; dwIdx++)
413
483
                                {
414
 
                                    char *pszProcName = NULL;
415
 
                                    DWORD dwSize = 128;
416
 
                                    do
 
484
                                    HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
 
485
                                                               FALSE, adwPIDs[dwIdx]);
 
486
                                    if (hProc)
417
487
                                    {
418
 
                                        RTMemRealloc(pszProcName, dwSize);
419
 
                                        if (pfnGetModuleBaseName(hProc, 0, pszProcName, dwSize) == dwSize)
420
 
                                            dwSize += 128;
421
 
                                    } while (GetLastError() == ERROR_INSUFFICIENT_BUFFER);
 
488
                                        char *pszProcName = NULL;
 
489
                                        DWORD dwSize = 128;
 
490
                                        do
 
491
                                        {
 
492
                                            RTMemRealloc(pszProcName, dwSize);
 
493
                                            if (pfnGetModuleBaseName(hProc, 0, pszProcName, dwSize) == dwSize)
 
494
                                                dwSize += 128;
 
495
                                            if (dwSize > _4K) /* Play safe. */
 
496
                                                break;
 
497
                                        } while (GetLastError() == ERROR_INSUFFICIENT_BUFFER);
422
498
 
423
 
                                    if (pszProcName)
424
 
                                    {
425
 
                                        if (   _stricmp(pszProcName, pszName) == 0
426
 
                                            && RT_SUCCESS(rtProcGetProcessHandle(dwPIDs[dwIdx], pSID, phToken)))
 
499
                                        if (pszProcName)
427
500
                                        {
428
 
                                            fFound = TRUE;
 
501
                                            if (   _stricmp(pszProcName, papszNames[i]) == 0
 
502
                                                && RT_SUCCESS(rtProcGetProcessHandle(adwPIDs[dwIdx], pSID, phToken)))
 
503
                                            {
 
504
                                                fFound = true;
 
505
                                            }
429
506
                                        }
 
507
                                        if (pszProcName)
 
508
                                            RTStrFree(pszProcName);
 
509
                                        CloseHandle(hProc);
430
510
                                    }
431
 
                                    if (pszProcName)
432
 
                                        RTStrFree(pszProcName);
433
 
                                    CloseHandle(hProc);
434
511
                                }
435
512
                            }
436
513
                        }
447
524
}
448
525
 
449
526
 
 
527
/**
 
528
 * Logs on a specified user and returns its primary token.
 
529
 *
 
530
 * @return  int
 
531
 *
 
532
 * @param   pwszUser            User name.
 
533
 * @param   pwszPassword        Password.
 
534
 * @param   pwszDomain          Domain (not used at the moment).
 
535
 * @param   phToken             Pointer to store the logon token.
 
536
 */
 
537
static int rtProcUserLogon(PRTUTF16 pwszUser, PRTUTF16 pwszPassword, PRTUTF16 pwszDomain, HANDLE *phToken)
 
538
{
 
539
    /** @todo Add domain support! */
 
540
    BOOL fRc = LogonUserW(pwszUser,
 
541
                          /*
 
542
                           * Because we have to deal with http://support.microsoft.com/kb/245683
 
543
                           * for NULL domain names when running on NT4 here, pass an empty string if so.
 
544
                           * However, passing FQDNs should work!
 
545
                           */
 
546
                          ((DWORD)(LOBYTE(LOWORD(GetVersion()))) < 5)  /* < Windows 2000. */
 
547
                          ? L""   /* NT4 and older. */
 
548
                          : NULL, /* Windows 2000 and up. */
 
549
                          pwszPassword,
 
550
                          LOGON32_LOGON_INTERACTIVE,
 
551
                          LOGON32_PROVIDER_DEFAULT,
 
552
                          phToken);
 
553
    if (!fRc)
 
554
        return rtProcMapErrorCodes(GetLastError());
 
555
    return VINF_SUCCESS;
 
556
}
 
557
 
 
558
 
 
559
/**
 
560
 * Logs off a user, specified by the given token.
 
561
 *
 
562
 * @param   hToken      The token (=user) to log off.
 
563
 */
 
564
static void rtProcUserLogoff(HANDLE hToken)
 
565
{
 
566
    CloseHandle(hToken);
 
567
}
 
568
 
 
569
 
 
570
/**
 
571
 * Creates an environment block out of a handed in Unicode and RTENV block.
 
572
 * The RTENV block can overwrite entries already present in the Unicode block.
 
573
 *
 
574
 * @return  IPRT status code.
 
575
 *
 
576
 * @param   pvBlock         Unicode block (array) of environment entries; name=value
 
577
 * @param   hEnv            Handle of an existing RTENV block to use.
 
578
 * @param   ppwszBlock      Pointer to the final output.
 
579
 */
 
580
static int rtProcEnvironmentCreateInternal(VOID *pvBlock, RTENV hEnv, PRTUTF16 *ppwszBlock)
 
581
{
 
582
    int rc = VINF_SUCCESS;
 
583
    RTENV hEnvTemp;
 
584
    rc = RTEnvClone(&hEnvTemp, hEnv);
 
585
    if (RT_SUCCESS(rc))
 
586
    {
 
587
        PRTUTF16 pBlock = (PRTUTF16)pvBlock;
 
588
        while (   pBlock
 
589
               && pBlock != '\0'
 
590
               && RT_SUCCESS(rc))
 
591
        {
 
592
            char *pszEntry;
 
593
            rc = RTUtf16ToUtf8(pBlock, &pszEntry);
 
594
            if (RT_SUCCESS(rc))
 
595
            {
 
596
                /* Don't overwrite values which we already have set to a custom value
 
597
                 * specified in hEnv ... */
 
598
                if (!RTEnvExistEx(hEnv, pszEntry))
 
599
                    rc = RTEnvPutEx(hEnvTemp, pszEntry);
 
600
                RTStrFree(pszEntry);
 
601
            }
 
602
 
 
603
            size_t l;
 
604
            /* 32k should be the maximum the environment block can have on Windows. */
 
605
            if (FAILED(StringCbLengthW((LPCWSTR)pBlock, _32K * sizeof(RTUTF16), &l)))
 
606
                break;
 
607
            pBlock += l / sizeof(RTUTF16);
 
608
            if (pBlock[1] == '\0') /* Did we reach the double zero termination (\0\0)? */
 
609
                break;
 
610
            pBlock++; /* Skip zero termination of current string and advance to next string ... */
 
611
        }
 
612
 
 
613
        if (RT_SUCCESS(rc))
 
614
            rc = RTEnvQueryUtf16Block(hEnvTemp, ppwszBlock);
 
615
        RTEnvDestroy(hEnvTemp);
 
616
    }
 
617
    return rc;
 
618
}
 
619
 
 
620
 
 
621
/**
 
622
 * Builds up the environment block for a specified user (identified by a token),
 
623
 * whereas hEnv is an additional set of environment variables which overwrite existing
 
624
 * values of the user profile.  ppwszBlock needs to be destroyed after usage
 
625
 * calling rtProcEnvironmentDestroy().
 
626
 *
 
627
 * @return  IPRT status code.
 
628
 *
 
629
 * @param   hToken          Token of the user to use.
 
630
 * @param   hEnv            Own environment block to extend/overwrite the profile's data with.
 
631
 * @param   ppwszBlock      Pointer to a pointer of the final UTF16 environment block.
 
632
 */
 
633
static int rtProcEnvironmentCreateFromToken(HANDLE hToken, RTENV hEnv, PRTUTF16 *ppwszBlock)
 
634
{
 
635
    RTLDRMOD hUserenv;
 
636
    int rc = RTLdrLoad("Userenv.dll", &hUserenv);
 
637
    if (RT_SUCCESS(rc))
 
638
    {
 
639
        PFNCREATEENVIRONMENTBLOCK pfnCreateEnvironmentBlock;
 
640
        rc = RTLdrGetSymbol(hUserenv, "CreateEnvironmentBlock", (void**)&pfnCreateEnvironmentBlock);
 
641
        if (RT_SUCCESS(rc))
 
642
        {
 
643
            PFNPFNDESTROYENVIRONMENTBLOCK pfnDestroyEnvironmentBlock;
 
644
            rc = RTLdrGetSymbol(hUserenv, "DestroyEnvironmentBlock", (void**)&pfnDestroyEnvironmentBlock);
 
645
            if (RT_SUCCESS(rc))
 
646
            {
 
647
                LPVOID pEnvBlockProfile = NULL;
 
648
                if (pfnCreateEnvironmentBlock(&pEnvBlockProfile, hToken, FALSE /* Don't inherit from parent. */))
 
649
                {
 
650
                    rc = rtProcEnvironmentCreateInternal(pEnvBlockProfile, hEnv, ppwszBlock);
 
651
                    pfnDestroyEnvironmentBlock(pEnvBlockProfile);
 
652
                }
 
653
                else
 
654
                    rc = RTErrConvertFromWin32(GetLastError());
 
655
            }
 
656
        }
 
657
        RTLdrClose(hUserenv);
 
658
    }
 
659
    /* If we don't have the Userenv-API for whatever reason or something with the
 
660
     * native environment block failed, try to return at least our own environment block. */
 
661
    if (RT_FAILURE(rc))
 
662
        rc = RTEnvQueryUtf16Block(hEnv, ppwszBlock);
 
663
    return rc;
 
664
}
 
665
 
 
666
 
 
667
/**
 
668
 * Builds up the environment block for a specified user (identified by user name, password
 
669
 * and domain), whereas hEnv is an additional set of environment variables which overwrite
 
670
 * existing values of the user profile.  ppwszBlock needs to be destroyed after usage
 
671
 * calling rtProcEnvironmentDestroy().
 
672
 *
 
673
 * @return  IPRT status code.
 
674
 *
 
675
 * @param   pwszUser        User name.
 
676
 * @param   pwszPassword    Password.
 
677
 * @param   pwszDomain      Domain.
 
678
 * @param   hEnv            Own environment block to extend/overwrite the profile's data with.
 
679
 * @param   ppwszBlock      Pointer to a pointer of the final UTF16 environment block.
 
680
 */
 
681
static int rtProcEnvironmentCreateFromAccount(PRTUTF16 pwszUser, PRTUTF16 pwszPassword, PRTUTF16 pwszDomain,
 
682
                                              RTENV hEnv, PRTUTF16 *ppwszBlock)
 
683
{
 
684
    HANDLE hToken;
 
685
    int rc = rtProcUserLogon(pwszUser, pwszPassword, pwszDomain, &hToken);
 
686
    if (RT_SUCCESS(rc))
 
687
    {
 
688
        rc = rtProcEnvironmentCreateFromToken(hToken, hEnv, ppwszBlock);
 
689
        rtProcUserLogoff(hToken);
 
690
    }
 
691
    return rc;
 
692
}
 
693
 
 
694
 
 
695
/**
 
696
 * Destroys an environment block formerly created by rtProcEnvironmentCreateInternal(),
 
697
 * rtProcEnvironmentCreateFromToken() or rtProcEnvironmentCreateFromAccount().
 
698
 *
 
699
 * @param   ppwszBlock      Environment block to destroy.
 
700
 */
 
701
static void rtProcEnvironmentDestroy(PRTUTF16 ppwszBlock)
 
702
{
 
703
    RTEnvFreeUtf16Block(ppwszBlock);
 
704
}
 
705
 
 
706
 
450
707
static int rtProcCreateAsUserHlp(PRTUTF16 pwszUser, PRTUTF16 pwszPassword, PRTUTF16 pwszExec, PRTUTF16 pwszCmdLine,
451
 
                                 PRTUTF16 pwszzBlock, DWORD dwCreationFlags,
 
708
                                 RTENV hEnv, DWORD dwCreationFlags,
452
709
                                 STARTUPINFOW *pStartupInfo, PROCESS_INFORMATION *pProcInfo, uint32_t fFlags)
453
710
{
454
711
    int rc = VINF_SUCCESS;
474
731
            rc = RTLdrGetSymbol(hAdvAPI32, "CreateProcessWithLogonW", (void**)&pfnCreateProcessWithLogonW);
475
732
            if (RT_SUCCESS(rc))
476
733
            {
477
 
                fRc = pfnCreateProcessWithLogonW(pwszUser,
478
 
                                                 NULL,                       /* lpDomain*/
479
 
                                                 pwszPassword,
480
 
                                                 1 /*LOGON_WITH_PROFILE*/,   /* dwLogonFlags */
481
 
                                                 pwszExec,
482
 
                                                 pwszCmdLine,
483
 
                                                 dwCreationFlags,
484
 
                                                 pwszzBlock,
485
 
                                                 NULL,                       /* pCurrentDirectory */
486
 
                                                 pStartupInfo,
487
 
                                                 pProcInfo);
488
 
                if (!fRc)
489
 
                    dwErr = GetLastError();
 
734
                PRTUTF16 pwszzBlock;
 
735
                rc = rtProcEnvironmentCreateFromAccount(pwszUser, pwszPassword, NULL /* Domain */,
 
736
                                                        hEnv, &pwszzBlock);
 
737
                if (RT_SUCCESS(rc))
 
738
                {
 
739
                    fRc = pfnCreateProcessWithLogonW(pwszUser,
 
740
                                                     NULL,                       /* lpDomain*/
 
741
                                                     pwszPassword,
 
742
                                                     1 /*LOGON_WITH_PROFILE*/,   /* dwLogonFlags */
 
743
                                                     pwszExec,
 
744
                                                     pwszCmdLine,
 
745
                                                     dwCreationFlags,
 
746
                                                     pwszzBlock,
 
747
                                                     NULL,                       /* pCurrentDirectory */
 
748
                                                     pStartupInfo,
 
749
                                                     pProcInfo);
 
750
                    if (!fRc)
 
751
                        dwErr = GetLastError();
 
752
                    rtProcEnvironmentDestroy(pwszzBlock);
 
753
                }
490
754
            }
491
755
            RTLdrClose(hAdvAPI32);
492
756
        }
507
771
         *   user. This of course is only possible if that user is logged in (over
508
772
         *   physical console or terminal services).
509
773
         * - If we found the user's Explorer/VBoxTray app, use and modify the token to
510
 
         *   use it in order to allow the newly started process acess the user's
 
774
         *   use it in order to allow the newly started process to access the user's
511
775
         *   desktop. If there's no Explorer/VBoxTray app we cannot display the started
512
776
         *   process (but run it without UI).
513
777
         *
527
791
         */
528
792
        PHANDLE phToken = NULL;
529
793
        HANDLE hTokenLogon = INVALID_HANDLE_VALUE;
530
 
        fRc = LogonUserW(pwszUser,
531
 
                         /*
532
 
                          * Because we have to deal with http://support.microsoft.com/kb/245683
533
 
                          * for NULL domain names when running on NT4 here, pass an empty string if so.
534
 
                          * However, passing FQDNs should work!
535
 
                          */
536
 
                         ((DWORD)(LOBYTE(LOWORD(GetVersion()))) < 5)  /* < Windows 2000. */
537
 
                         ? L""   /* NT4 and older. */
538
 
                         : NULL, /* Windows 2000 and up. */
539
 
                         pwszPassword,
540
 
                         LOGON32_LOGON_INTERACTIVE,
541
 
                         LOGON32_PROVIDER_DEFAULT,
542
 
                         &hTokenLogon);
 
794
        rc = rtProcUserLogon(pwszUser, pwszPassword, NULL /* Domain */, &hTokenLogon);
 
795
        if (RT_SUCCESS(rc))
 
796
        {
 
797
            bool fFound = false;
 
798
            HANDLE hTokenUserDesktop = INVALID_HANDLE_VALUE;
543
799
 
544
 
        BOOL fFound = FALSE;
545
 
        HANDLE hTokenUserDesktop = INVALID_HANDLE_VALUE;
546
 
        if (fRc)
547
 
        {
548
800
            if (fFlags & RTPROC_FLAGS_SERVICE)
549
801
            {
550
802
                DWORD cbName = 0; /* Must be zero to query size! */
586
838
                                              &sidNameUse)
587
839
                        && IsValidSid(pSID))
588
840
                    {
589
 
                        fFound = rtProcFindProcessByName(
590
 
#ifdef VBOX
591
 
                                                         "VBoxTray.exe",
592
 
#else
593
 
                                                         "explorer.exe"
 
841
                        /* Array of process names we want to look for. */
 
842
                        static const char * const s_papszProcNames[] =
 
843
                        {
 
844
#ifdef VBOX                 /* The explorer entry is a fallback in case GA aren't installed. */
 
845
                            { "VBoxTray.exe" },
594
846
#endif
595
 
                                                         pSID, &hTokenUserDesktop);
 
847
                            { "explorer.exe" },
 
848
                            NULL
 
849
                        };
 
850
                        fFound = rtProcFindProcessByName(s_papszProcNames, pSID, &hTokenUserDesktop);
596
851
                    }
597
852
                    else
598
853
                        dwErr = GetLastError(); /* LookupAccountNameW() failed. */
613
868
             */
614
869
            phToken = fFound ? &hTokenUserDesktop : &hTokenLogon;
615
870
 
616
 
            /*
617
 
             * Useful KB articles:
618
 
             * http://support.microsoft.com/kb/165194/
619
 
             * http://support.microsoft.com/kb/184802/
620
 
             * http://support.microsoft.com/kb/327618/
621
 
             */
622
 
            fRc = CreateProcessAsUserW(*phToken,
623
 
                                       pwszExec,
624
 
                                       pwszCmdLine,
625
 
                                       NULL,         /* pProcessAttributes */
626
 
                                       NULL,         /* pThreadAttributes */
627
 
                                       TRUE,         /* fInheritHandles */
628
 
                                       dwCreationFlags,
629
 
                                       pwszzBlock,
630
 
                                       NULL,         /* pCurrentDirectory */
631
 
                                       pStartupInfo,
632
 
                                       pProcInfo);
633
 
            if (fRc)
634
 
                dwErr = NO_ERROR;
635
 
            else
636
 
                dwErr = GetLastError(); /* CreateProcessAsUserW() failed. */
 
871
            RTLDRMOD hUserenv;
 
872
            int rc = RTLdrLoad("Userenv.dll", &hUserenv);
 
873
            if (RT_SUCCESS(rc))
 
874
            {
 
875
                PFNLOADUSERPROFILEW pfnLoadUserProfileW;
 
876
                rc = RTLdrGetSymbol(hUserenv, "LoadUserProfileW", (void**)&pfnLoadUserProfileW);
 
877
                if (RT_SUCCESS(rc))
 
878
                {
 
879
                    PFNUNLOADUSERPROFILE pfnUnloadUserProfile;
 
880
                    rc = RTLdrGetSymbol(hUserenv, "UnloadUserProfile", (void**)&pfnUnloadUserProfile);
 
881
                    if (RT_SUCCESS(rc))
 
882
                    {
 
883
                        PROFILEINFOW profileInfo;
 
884
                        ZeroMemory(&profileInfo, sizeof(profileInfo));
 
885
                        profileInfo.dwSize = sizeof(profileInfo);
 
886
                        profileInfo.lpUserName = pwszUser;
 
887
                        profileInfo.dwFlags = PI_NOUI; /* Prevents the display of profile error messages. */
637
888
 
 
889
                        if (pfnLoadUserProfileW(*phToken, &profileInfo))
 
890
                        {
 
891
                            PRTUTF16 pwszzBlock;
 
892
                            rc = rtProcEnvironmentCreateFromToken(*phToken, hEnv, &pwszzBlock);
 
893
                            if (RT_SUCCESS(rc))
 
894
                            {
 
895
                                /*
 
896
                                 * Useful KB articles:
 
897
                                 *      http://support.microsoft.com/kb/165194/
 
898
                                 *      http://support.microsoft.com/kb/184802/
 
899
                                 *      http://support.microsoft.com/kb/327618/
 
900
                                 */
 
901
                                fRc = CreateProcessAsUserW(*phToken,
 
902
                                                           pwszExec,
 
903
                                                           pwszCmdLine,
 
904
                                                           NULL,         /* pProcessAttributes */
 
905
                                                           NULL,         /* pThreadAttributes */
 
906
                                                           TRUE,         /* fInheritHandles */
 
907
                                                           dwCreationFlags,
 
908
                                                           pwszzBlock,
 
909
                                                           NULL,         /* pCurrentDirectory */
 
910
                                                           pStartupInfo,
 
911
                                                           pProcInfo);
 
912
                                if (fRc)
 
913
                                    dwErr = NO_ERROR;
 
914
                                else
 
915
                                    dwErr = GetLastError(); /* CreateProcessAsUserW() failed. */
 
916
                                rtProcEnvironmentDestroy(pwszzBlock);
 
917
                            }
 
918
                            else
 
919
                                dwErr = rc;
 
920
                            pfnUnloadUserProfile(*phToken, profileInfo.hProfile);
 
921
                        }
 
922
                        else
 
923
                            dwErr = GetLastError(); /* LoadUserProfileW() failed. */
 
924
                    }
 
925
                }
 
926
                RTLdrClose(hUserenv);
 
927
            }
638
928
            if (hTokenUserDesktop != INVALID_HANDLE_VALUE)
639
929
                CloseHandle(hTokenUserDesktop);
640
 
            CloseHandle(hTokenLogon);
 
930
            rtProcUserLogoff(hTokenLogon);
641
931
        }
642
 
        else
643
 
            dwErr = GetLastError(); /* LogonUserW() failed. */
644
932
    }
645
933
 
646
 
    if (dwErr != NO_ERROR)
 
934
    if (   RT_SUCCESS(rc)
 
935
        && dwErr != NO_ERROR)
647
936
    {
648
 
        /*
649
 
         * Map some important or much used Windows error codes
650
 
         * to our error codes.
651
 
         */
652
 
        switch (dwErr)
653
 
        {
654
 
            case ERROR_NOACCESS:
655
 
            case ERROR_PRIVILEGE_NOT_HELD:
656
 
                rc = VERR_PERMISSION_DENIED;
657
 
                break;
658
 
 
659
 
            case ERROR_PASSWORD_EXPIRED:
660
 
            case ERROR_ACCOUNT_RESTRICTION: /* See: http://support.microsoft.com/kb/303846/ */
661
 
                rc = VERR_LOGON_FAILURE;
662
 
                break;
663
 
 
664
 
            default:
665
 
                /* Could trigger a debug assertion! */
666
 
                rc = RTErrConvertFromWin32(dwErr);
667
 
                break;
668
 
        }
 
937
        rc = rtProcMapErrorCodes(dwErr);
669
938
    }
670
 
    else
671
 
        rc = VINF_SUCCESS;
672
939
    return rc;
673
940
}
674
941
 
681
948
     */
682
949
    AssertPtrReturn(pszExec, VERR_INVALID_POINTER);
683
950
    AssertReturn(*pszExec, VERR_INVALID_PARAMETER);
684
 
    AssertReturn(!(fFlags & ~(RTPROC_FLAGS_DAEMONIZE_DEPRECATED | RTPROC_FLAGS_DETACHED | RTPROC_FLAGS_SERVICE)), VERR_INVALID_PARAMETER);
 
951
    AssertReturn(!(fFlags & ~(RTPROC_FLAGS_DETACHED | RTPROC_FLAGS_HIDDEN |RTPROC_FLAGS_SERVICE)), VERR_INVALID_PARAMETER);
685
952
    AssertReturn(!(fFlags & RTPROC_FLAGS_DETACHED) || !phProcess, VERR_INVALID_PARAMETER);
686
953
    AssertReturn(hEnv != NIL_RTENV, VERR_INVALID_PARAMETER);
687
954
    AssertPtrReturn(papszArgs, VERR_INVALID_PARAMETER);
716
983
    StartupInfo.hStdOutput = _get_osfhandle(1);
717
984
    StartupInfo.hStdError  = _get_osfhandle(2);
718
985
#endif
 
986
    /* If we want to have a hidden process (e.g. not visible to
 
987
     * to the user) use the STARTUPINFO flags. */
 
988
    if (fFlags & RTPROC_FLAGS_HIDDEN)
 
989
    {
 
990
        StartupInfo.dwFlags |= STARTF_USESHOWWINDOW;
 
991
        StartupInfo.wShowWindow = SW_HIDE;
 
992
    }
 
993
 
719
994
    PCRTHANDLE  paHandles[3] = { phStdIn, phStdOut, phStdErr };
720
995
    HANDLE     *aphStds[3]   = { &StartupInfo.hStdInput, &StartupInfo.hStdOutput, &StartupInfo.hStdError };
721
996
    DWORD       afInhStds[3] = { 0xffffffff, 0xffffffff, 0xffffffff };
795
1070
                /*
796
1071
                 * Get going...
797
1072
                 */
 
1073
                PROCESS_INFORMATION ProcInfo;
 
1074
                RT_ZERO(ProcInfo);
798
1075
                DWORD               dwCreationFlags = CREATE_UNICODE_ENVIRONMENT;
799
1076
                if (fFlags & RTPROC_FLAGS_DETACHED)
800
1077
                    dwCreationFlags |= DETACHED_PROCESS;
801
1078
 
802
 
                PROCESS_INFORMATION ProcInfo;
803
 
                RT_ZERO(ProcInfo);
804
 
 
805
1079
                /*
806
1080
                 * Only use the normal CreateProcess stuff if we have no user name
807
1081
                 * and we are not running from a (Windows) service. Otherwise use
839
1113
                        if (RT_SUCCESS(rc))
840
1114
                        {
841
1115
                            rc = rtProcCreateAsUserHlp(pwszUser, pwszPassword,
842
 
                                                       pwszExec, pwszCmdLine, pwszzBlock, dwCreationFlags,
 
1116
                                                       pwszExec, pwszCmdLine, hEnv, dwCreationFlags,
843
1117
                                                       &StartupInfo, &ProcInfo, fFlags);
844
1118
 
845
1119
                            RTUtf16Free(pwszPassword);
963
1237
 
964
1238
RTR3DECL(int) RTProcTerminate(RTPROCESS Process)
965
1239
{
966
 
    int     rc       = VINF_SUCCESS;
967
 
    HANDLE  hProcess = rtProcWinFindPid(Process);
 
1240
    int rc = RTOnce(&g_rtProcWinInitOnce, rtProcWinInitOnce, NULL, NULL);
 
1241
    AssertRCReturn(rc, rc);
 
1242
 
 
1243
    /*
 
1244
     * Try find the process among the ones we've spawned, otherwise, attempt
 
1245
     * opening the specified process.
 
1246
     */
 
1247
    HANDLE hProcess = rtProcWinFindPid(Process);
968
1248
    if (hProcess != NULL)
969
1249
    {
970
1250
        if (!TerminateProcess(hProcess, 127))