270
* Map some important or much used Windows error codes
271
* to our error codes.
273
* @return Mapped IPRT status code.
274
* @param dwError Windows error code to map to IPRT code.
276
static int rtProcMapErrorCodes(DWORD dwError)
282
case ERROR_PRIVILEGE_NOT_HELD:
283
rc = VERR_PERMISSION_DENIED;
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;
293
/* Could trigger a debug assertion! */
294
rc = RTErrConvertFromWin32(dwError);
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.
305
* @returns IPRT status code.
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.
256
312
static int rtProcGetProcessHandle(DWORD dwPID, PSID pSID, PHANDLE phToken)
359
425
HANDLE hSnap = pfnCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
360
426
if (hSnap != INVALID_HANDLE_VALUE)
362
PROCESSENTRY32 procEntry;
363
procEntry.dwSize = sizeof(PROCESSENTRY32);
364
if (pfnProcess32First(hSnap, &procEntry))
428
for (size_t i = 0; papszNames[i] && !fFound; i++)
430
PROCESSENTRY32 procEntry;
431
procEntry.dwSize = sizeof(PROCESSENTRY32);
432
if (pfnProcess32First(hSnap, &procEntry))
368
if ( _stricmp(procEntry.szExeFile, pszName) == 0
369
&& RT_SUCCESS(rtProcGetProcessHandle(procEntry.th32ProcessID, pSID, phToken)))
373
} while (pfnProcess32Next(hSnap, &procEntry) && !fFound);
436
if ( _stricmp(procEntry.szExeFile, papszNames[i]) == 0
437
&& RT_SUCCESS(rtProcGetProcessHandle(procEntry.th32ProcessID, pSID, phToken)))
442
} while (pfnProcess32Next(hSnap, &procEntry));
444
else /* Process32First */
445
dwErr = GetLastError();
375
else /* Process32First */
376
dwErr = GetLastError();
377
449
CloseHandle(hSnap);
379
else /* hSnap =! INVALID_HANDLE_VALUE */
451
else /* hSnap == INVALID_HANDLE_VALUE */
380
452
dwErr = GetLastError();
401
473
if (RT_SUCCESS(rc))
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))
408
for (DWORD dwIdx = 0; dwIdx < cbBytes/sizeof(DWORD) && !fFound; dwIdx++)
480
for (size_t i = 0; papszNames[i] && !fFound; i++)
410
HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
411
FALSE, dwPIDs[dwIdx]);
482
for (DWORD dwIdx = 0; dwIdx < cbBytes/sizeof(DWORD) && !fFound; dwIdx++)
414
char *pszProcName = NULL;
484
HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
485
FALSE, adwPIDs[dwIdx]);
418
RTMemRealloc(pszProcName, dwSize);
419
if (pfnGetModuleBaseName(hProc, 0, pszProcName, dwSize) == dwSize)
421
} while (GetLastError() == ERROR_INSUFFICIENT_BUFFER);
488
char *pszProcName = NULL;
492
RTMemRealloc(pszProcName, dwSize);
493
if (pfnGetModuleBaseName(hProc, 0, pszProcName, dwSize) == dwSize)
495
if (dwSize > _4K) /* Play safe. */
497
} while (GetLastError() == ERROR_INSUFFICIENT_BUFFER);
425
if ( _stricmp(pszProcName, pszName) == 0
426
&& RT_SUCCESS(rtProcGetProcessHandle(dwPIDs[dwIdx], pSID, phToken)))
501
if ( _stricmp(pszProcName, papszNames[i]) == 0
502
&& RT_SUCCESS(rtProcGetProcessHandle(adwPIDs[dwIdx], pSID, phToken)))
508
RTStrFree(pszProcName);
432
RTStrFree(pszProcName);
528
* Logs on a specified user and returns its primary token.
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.
537
static int rtProcUserLogon(PRTUTF16 pwszUser, PRTUTF16 pwszPassword, PRTUTF16 pwszDomain, HANDLE *phToken)
539
/** @todo Add domain support! */
540
BOOL fRc = LogonUserW(pwszUser,
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!
546
((DWORD)(LOBYTE(LOWORD(GetVersion()))) < 5) /* < Windows 2000. */
547
? L"" /* NT4 and older. */
548
: NULL, /* Windows 2000 and up. */
550
LOGON32_LOGON_INTERACTIVE,
551
LOGON32_PROVIDER_DEFAULT,
554
return rtProcMapErrorCodes(GetLastError());
560
* Logs off a user, specified by the given token.
562
* @param hToken The token (=user) to log off.
564
static void rtProcUserLogoff(HANDLE hToken)
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.
574
* @return IPRT status code.
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.
580
static int rtProcEnvironmentCreateInternal(VOID *pvBlock, RTENV hEnv, PRTUTF16 *ppwszBlock)
582
int rc = VINF_SUCCESS;
584
rc = RTEnvClone(&hEnvTemp, hEnv);
587
PRTUTF16 pBlock = (PRTUTF16)pvBlock;
593
rc = RTUtf16ToUtf8(pBlock, &pszEntry);
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);
604
/* 32k should be the maximum the environment block can have on Windows. */
605
if (FAILED(StringCbLengthW((LPCWSTR)pBlock, _32K * sizeof(RTUTF16), &l)))
607
pBlock += l / sizeof(RTUTF16);
608
if (pBlock[1] == '\0') /* Did we reach the double zero termination (\0\0)? */
610
pBlock++; /* Skip zero termination of current string and advance to next string ... */
614
rc = RTEnvQueryUtf16Block(hEnvTemp, ppwszBlock);
615
RTEnvDestroy(hEnvTemp);
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().
627
* @return IPRT status code.
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.
633
static int rtProcEnvironmentCreateFromToken(HANDLE hToken, RTENV hEnv, PRTUTF16 *ppwszBlock)
636
int rc = RTLdrLoad("Userenv.dll", &hUserenv);
639
PFNCREATEENVIRONMENTBLOCK pfnCreateEnvironmentBlock;
640
rc = RTLdrGetSymbol(hUserenv, "CreateEnvironmentBlock", (void**)&pfnCreateEnvironmentBlock);
643
PFNPFNDESTROYENVIRONMENTBLOCK pfnDestroyEnvironmentBlock;
644
rc = RTLdrGetSymbol(hUserenv, "DestroyEnvironmentBlock", (void**)&pfnDestroyEnvironmentBlock);
647
LPVOID pEnvBlockProfile = NULL;
648
if (pfnCreateEnvironmentBlock(&pEnvBlockProfile, hToken, FALSE /* Don't inherit from parent. */))
650
rc = rtProcEnvironmentCreateInternal(pEnvBlockProfile, hEnv, ppwszBlock);
651
pfnDestroyEnvironmentBlock(pEnvBlockProfile);
654
rc = RTErrConvertFromWin32(GetLastError());
657
RTLdrClose(hUserenv);
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. */
662
rc = RTEnvQueryUtf16Block(hEnv, ppwszBlock);
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().
673
* @return IPRT status code.
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.
681
static int rtProcEnvironmentCreateFromAccount(PRTUTF16 pwszUser, PRTUTF16 pwszPassword, PRTUTF16 pwszDomain,
682
RTENV hEnv, PRTUTF16 *ppwszBlock)
685
int rc = rtProcUserLogon(pwszUser, pwszPassword, pwszDomain, &hToken);
688
rc = rtProcEnvironmentCreateFromToken(hToken, hEnv, ppwszBlock);
689
rtProcUserLogoff(hToken);
696
* Destroys an environment block formerly created by rtProcEnvironmentCreateInternal(),
697
* rtProcEnvironmentCreateFromToken() or rtProcEnvironmentCreateFromAccount().
699
* @param ppwszBlock Environment block to destroy.
701
static void rtProcEnvironmentDestroy(PRTUTF16 ppwszBlock)
703
RTEnvFreeUtf16Block(ppwszBlock);
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)
454
711
int rc = VINF_SUCCESS;
614
869
phToken = fFound ? &hTokenUserDesktop : &hTokenLogon;
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/
622
fRc = CreateProcessAsUserW(*phToken,
625
NULL, /* pProcessAttributes */
626
NULL, /* pThreadAttributes */
627
TRUE, /* fInheritHandles */
630
NULL, /* pCurrentDirectory */
636
dwErr = GetLastError(); /* CreateProcessAsUserW() failed. */
872
int rc = RTLdrLoad("Userenv.dll", &hUserenv);
875
PFNLOADUSERPROFILEW pfnLoadUserProfileW;
876
rc = RTLdrGetSymbol(hUserenv, "LoadUserProfileW", (void**)&pfnLoadUserProfileW);
879
PFNUNLOADUSERPROFILE pfnUnloadUserProfile;
880
rc = RTLdrGetSymbol(hUserenv, "UnloadUserProfile", (void**)&pfnUnloadUserProfile);
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. */
889
if (pfnLoadUserProfileW(*phToken, &profileInfo))
892
rc = rtProcEnvironmentCreateFromToken(*phToken, hEnv, &pwszzBlock);
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/
901
fRc = CreateProcessAsUserW(*phToken,
904
NULL, /* pProcessAttributes */
905
NULL, /* pThreadAttributes */
906
TRUE, /* fInheritHandles */
909
NULL, /* pCurrentDirectory */
915
dwErr = GetLastError(); /* CreateProcessAsUserW() failed. */
916
rtProcEnvironmentDestroy(pwszzBlock);
920
pfnUnloadUserProfile(*phToken, profileInfo.hProfile);
923
dwErr = GetLastError(); /* LoadUserProfileW() failed. */
926
RTLdrClose(hUserenv);
638
928
if (hTokenUserDesktop != INVALID_HANDLE_VALUE)
639
929
CloseHandle(hTokenUserDesktop);
640
CloseHandle(hTokenLogon);
930
rtProcUserLogoff(hTokenLogon);
643
dwErr = GetLastError(); /* LogonUserW() failed. */
646
if (dwErr != NO_ERROR)
935
&& dwErr != NO_ERROR)
649
* Map some important or much used Windows error codes
650
* to our error codes.
655
case ERROR_PRIVILEGE_NOT_HELD:
656
rc = VERR_PERMISSION_DENIED;
659
case ERROR_PASSWORD_EXPIRED:
660
case ERROR_ACCOUNT_RESTRICTION: /* See: http://support.microsoft.com/kb/303846/ */
661
rc = VERR_LOGON_FAILURE;
665
/* Could trigger a debug assertion! */
666
rc = RTErrConvertFromWin32(dwErr);
937
rc = rtProcMapErrorCodes(dwErr);