Changeset 29726 in vbox for trunk/src/VBox/Runtime/r3/win
- Timestamp:
- May 21, 2010 12:24:54 PM (15 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/r3/win/process-win.cpp
r29718 r29726 35 35 #include <tlhelp32.h> 36 36 #include <process.h> 37 #include <psapi.h> /* For EnumProcesses(). */ 37 38 #include <errno.h> 38 39 … … 74 75 typedef FNWTSGETACTIVECONSOLESESSIONID *PFNWTSGETACTIVECONSOLESESSIONID; 75 76 76 typedef BOOL WINAPI FNWTSQUERYUSERTOKEN(ULONG, PHANDLE); 77 typedef FNWTSQUERYUSERTOKEN *PFNWTSQUERYUSERTOKEN; 77 typedef HANDLE WINAPI FNCREATETOOLHELP32SNAPSHOT(DWORD, DWORD); 78 typedef FNCREATETOOLHELP32SNAPSHOT *PFNCREATETOOLHELP32SNAPSHOT; 79 80 typedef BOOL WINAPI FNPROCESS32FIRST(HANDLE, LPPROCESSENTRY32); 81 typedef FNPROCESS32FIRST *PFNPROCESS32FIRST; 82 83 typedef BOOL WINAPI FNPROCESS32NEXT(HANDLE, LPPROCESSENTRY32); 84 typedef FNPROCESS32NEXT *PFNPROCESS32NEXT; 85 86 typedef BOOL WINAPI FNENUMPROCESSES(DWORD*, DWORD, DWORD*); 87 typedef FNENUMPROCESSES *PFNENUMPROCESSES; 88 89 typedef DWORD FNGETMODULEBASENAME(HANDLE, HMODULE, LPTSTR, DWORD); 90 typedef FNGETMODULEBASENAME *PFNGETMODULEBASENAME; 78 91 79 92 … … 242 255 243 256 257 static 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 327 static 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 244 447 static int rtProcCreateAsUserHlp(PRTUTF16 pwszUser, PRTUTF16 pwszPassword, PRTUTF16 pwszExec, PRTUTF16 pwszCmdLine, 245 448 PRTUTF16 pwszzBlock, DWORD dwCreationFlags, … … 285 488 RTLdrClose(hAdvAPI32); 286 489 } 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 mouse303 * is connected to. Due to FUS (fast user switching) starting with Windows XP304 * this can be a different session than 0.305 */306 dwSessionID = pfnWTSGetActiveConsoleSessionId(); /* Get active console session ID. */307 }308 RTLdrClose(hKernel32);309 490 } 310 491 … … 342 523 * We may fail here with ERROR_PRIVILEGE_NOT_HELD. 343 524 * 344 * * @todo Deal with http://support.microsoft.com/kb/245683 for NULL domain names345 * 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! 346 527 */ 347 528 PHANDLE phToken = NULL; 348 529 HANDLE hTokenLogon = INVALID_HANDLE_VALUE; 349 530 fRc = LogonUserW(pwszUser, 350 NULL,531 L"", 351 532 pwszPassword, 352 533 LOGON32_LOGON_INTERACTIVE, … … 354 535 &hTokenLogon); 355 536 356 BOOL bFound = FALSE;537 BOOL fFound = FALSE; 357 538 HANDLE hTokenVBoxTray = INVALID_HANDLE_VALUE; 358 539 if (fRc) … … 382 563 383 564 /** @todo No way to allocate a PRTUTF16 directly? */ 384 char *pszDomainUtf8 = NULL;385 565 PRTUTF16 pwszDomain = NULL; 386 566 if (cbDomain > 0) 387 567 { 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); 392 570 } 393 571 … … 402 580 && IsValidSid(pSID)) 403 581 { 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); 483 589 } 484 590 else … … 499 605 * desktop interaction without UI. 500 606 */ 501 phToken = bFound ? &hTokenVBoxTray : &hTokenLogon;607 phToken = fFound ? &hTokenVBoxTray : &hTokenLogon; 502 608 503 609 /*
Note:
See TracChangeset
for help on using the changeset viewer.