- Timestamp:
- Dec 3, 2010 9:49:36 PM (14 years ago)
- Location:
- trunk/src/VBox/Main
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/ExtPackManagerImpl.cpp
r34704 r34711 1658 1658 if (hPipeR != NIL_RTPIPE) 1659 1659 { 1660 char achBuf[1 6]; ///@todo 10241660 char achBuf[1024]; 1661 1661 size_t cbRead; 1662 1662 vrc = RTPipeReadBlocking(hPipeR, achBuf, sizeof(achBuf), &cbRead); … … 1709 1709 || hProcess != NIL_RTPROCESS); 1710 1710 1711 LogRel(("ExtPack: enmReason=%d iStatus=%d stderr='%s'\n", 1712 ProcStatus.enmReason, ProcStatus.iStatus, offStdErrBuf ? pszStdErrBuf : "")); 1713 1714 /* 1715 * Look for rcExit=RTEXITCODE_SUCCESS at the end of the error output, 1716 * cut it as it is only there to attest the success. 1717 */ 1718 if (offStdErrBuf > 0) 1719 { 1720 RTStrStripR(pszStdErrBuf); 1721 offStdErrBuf = strlen(pszStdErrBuf); 1722 } 1723 1724 if ( offStdErrBuf > 0 1725 && !strcmp(pszStdErrBuf, "rcExit=RTEXITCODE_SUCCESS")) 1726 { 1727 *pszStdErrBuf = '\0'; 1728 offStdErrBuf = 0; 1729 } 1730 else if ( ProcStatus.enmReason == RTPROCEXITREASON_NORMAL 1731 && ProcStatus.iStatus == 0) 1732 ProcStatus.iStatus = 666; 1733 1711 1734 /* 1712 1735 * Compose the status code and, on failure, error message. 1713 1736 */ 1714 LogRel(("ExtPack: enmReason=%d iStatus=%d stderr='%s'\n",1715 ProcStatus.enmReason, ProcStatus.iStatus, offStdErrBuf ? pszStdErrBuf : ""));1716 1717 1737 if ( ProcStatus.enmReason == RTPROCEXITREASON_NORMAL 1718 1738 && ProcStatus.iStatus == 0 -
trunk/src/VBox/Main/VBoxExtPackHelperApp.cpp
r34608 r34711 44 44 #include <VBox/version.h> 45 45 46 #if defined(RT_OS_DARWIN) 47 # include <sys/types.h> 48 # include <unistd.h> /* geteuid */ 49 #endif 50 51 #ifdef RT_OS_WINDOWS 52 # define _WIN32_WINNT 0x0501 53 # include <Objbase.h> /* CoInitializeEx */ 54 # include <Windows.h> /* ShellExecuteEx, ++ */ 55 #endif 56 57 #if defined(RT_OS_DARWIN) || defined(RT_OS_WINDOWS) 58 # include <stdio.h> 59 # include <errno.h> 60 #endif 61 46 62 47 63 /******************************************************************************* 48 64 * Defined Constants And Macros * 49 65 *******************************************************************************/ 66 /* Enable elevation on windows and darwin. */ 67 #if defined(RT_OS_WINDOWS) 68 # define WITH_ELEVATION 69 #endif 70 50 71 /** The maximum entry name length. 51 72 * Play short and safe. */ … … 278 299 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTManifestCreate failed: %Rrc", rc); 279 300 280 RTEXITCODE rcExit;281 301 RTVFSIOSTREAM hVfsIos = RTVfsFileToIoStream(hManifestFile); 282 302 rc = RTManifestReadStandard(hTheirManifest, hVfsIos); … … 1386 1406 } 1387 1407 1388 1408 #ifdef WITH_ELEVATION 1409 1410 /** 1411 * Copies the content of a file to a stream. 1412 * 1413 * @param hSrc The source file. 1414 * @param pDst The destination stream. 1415 * @param fComplain Whether to complain about errors (i.e. is this 1416 * stderr, if not keep the trap shut because it 1417 * may be missing when running under VBoxSVC.) 1418 */ 1419 static void CopyFileToStdXxx(RTFILE hSrc, PRTSTREAM pDst, bool fComplain) 1420 { 1421 int rc; 1422 for (;;) 1423 { 1424 char abBuf[0x1000]; 1425 size_t cbRead; 1426 rc = RTFileRead(hSrc, abBuf, sizeof(abBuf), &cbRead); 1427 if (RT_FAILURE(rc)) 1428 { 1429 RTMsgError("RTFileRead failed: %Rrc", rc); 1430 break; 1431 } 1432 if (!cbRead) 1433 break; 1434 rc = RTStrmWrite(pDst, abBuf, cbRead); 1435 if (RT_FAILURE(rc)) 1436 { 1437 if (fComplain) 1438 RTMsgError("RTStrmWrite failed: %Rrc", rc); 1439 break; 1440 } 1441 } 1442 rc = RTStrmFlush(pDst); 1443 if (RT_FAILURE(rc) && fComplain) 1444 RTMsgError("RTStrmFlush failed: %Rrc", rc); 1445 } 1446 1447 1448 /** 1449 * Relaunches ourselves as a elevated process using platform specific facilities. 1450 * 1451 * @returns Program exit code. 1452 * @param pszExecPath The executable path. 1453 * @param cArgs The number of arguments. 1454 * @param papszArgs The arguments. 1455 */ 1456 static RTEXITCODE RelaunchElevatedNative(const char *pszExecPath, int cArgs, const char * const *papszArgs) 1457 { 1458 RTEXITCODE rcExit = RTEXITCODE_FAILURE; 1459 #ifdef RT_OS_WINDOWS 1460 1461 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); 1462 1463 SHELLEXECUTEINFOW Info; 1464 1465 Info.cbSize = sizeof(Info); 1466 Info.fMask = SEE_MASK_NOCLOSEPROCESS /*| SEE_MASK_NOASYNC*/; 1467 Info.hwnd = NULL; 1468 Info.lpVerb = L"runas"; 1469 int rc = RTStrToUtf16(pszExecPath, (PRTUTF16 *)&Info.lpFile); 1470 if (RT_SUCCESS(rc)) 1471 { 1472 char *pszCmdLine; 1473 rc = RTGetOptArgvToString(&pszCmdLine, &papszArgs[1], RTGETOPTARGV_CNV_QUOTE_MS_CRT); 1474 if (RT_SUCCESS(rc)) 1475 { 1476 rc = RTStrToUtf16(pszCmdLine, (PRTUTF16 *)&Info.lpParameters); 1477 if (RT_SUCCESS(rc)) 1478 { 1479 Info.lpDirectory = NULL; 1480 Info.nShow = SW_SHOWDEFAULT; 1481 Info.hInstApp = NULL; 1482 Info.lpIDList = NULL; 1483 Info.lpClass = NULL; 1484 Info.hkeyClass = NULL; 1485 Info.dwHotKey = 0; 1486 Info.hIcon = INVALID_HANDLE_VALUE; 1487 Info.hProcess = INVALID_HANDLE_VALUE; 1488 1489 if (ShellExecuteExW(&Info)) 1490 { 1491 if (Info.hProcess != INVALID_HANDLE_VALUE) 1492 { 1493 /* 1494 * Wait for the process, make sure the deal with messages. 1495 */ 1496 for (;;) 1497 { 1498 DWORD dwRc = MsgWaitForMultipleObjects(1, &Info.hProcess, FALSE, 5000/*ms*/, QS_ALLEVENTS); 1499 if (dwRc == WAIT_OBJECT_0) 1500 break; 1501 if ( dwRc != WAIT_TIMEOUT 1502 && dwRc != WAIT_OBJECT_0 + 1) 1503 { 1504 RTMsgError("MsgWaitForMultipleObjects returned: %#x (%d), err=%u", dwRc, dwRc, GetLastError()); 1505 break; 1506 } 1507 MSG Msg; 1508 while (PeekMessageW(&Msg, NULL, 0, 0, PM_REMOVE)) 1509 { 1510 TranslateMessage(&Msg); 1511 DispatchMessageW(&Msg); 1512 } 1513 } 1514 1515 DWORD dwExitCode; 1516 if (GetExitCodeProcess(Info.hProcess, &dwExitCode)) 1517 { 1518 if (dwExitCode >= 0 && dwExitCode < 128) 1519 rcExit = (RTEXITCODE)dwExitCode; 1520 else 1521 rcExit = RTEXITCODE_FAILURE; 1522 } 1523 CloseHandle(Info.hProcess); 1524 } 1525 else 1526 RTMsgError("ShellExecuteExW return INVALID_HANDLE_VALUE as Info.hProcess"); 1527 } 1528 else 1529 RTMsgError("ShellExecuteExW failed: %u (%#x)", GetLastError(), GetLastError()); 1530 1531 1532 RTUtf16Free((PRTUTF16)Info.lpParameters); 1533 } 1534 RTStrFree(pszCmdLine); 1535 } 1536 1537 RTUtf16Free((PRTUTF16)Info.lpFile); 1538 } 1539 else 1540 RTMsgError("RTStrToUtf16 failed: %Rc", rc); 1541 1542 #else 1543 # error "PORT ME" 1544 #endif 1545 return rcExit; 1546 } 1547 1548 1549 /** 1550 * Relaunches ourselves as a elevated process using platform specific facilities. 1551 * 1552 * @returns Program exit code. 1553 * @param argc The number of arguments. 1554 * @param argv The arguments. 1555 */ 1556 static RTEXITCODE RelaunchElevated(int argc, char **argv) 1557 { 1558 /* 1559 * We need the executable name later, so get it now when it's easy to quit. 1560 */ 1561 char szExecPath[RTPATH_MAX]; 1562 if (!RTProcGetExecutablePath(szExecPath,sizeof(szExecPath))) 1563 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTProcGetExecutablePath failed"); 1564 1565 /* 1566 * Create a couple of temporary files for stderr and stdout. 1567 */ 1568 char szTempDir[RTPATH_MAX - sizeof("/stderr")]; 1569 int rc = RTPathTemp(szTempDir, sizeof(szTempDir)); 1570 if (RT_FAILURE(rc)) 1571 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTPathTemp failed: %Rrc", rc); 1572 rc = RTPathAppend(szTempDir, sizeof(szTempDir), "VBoxExtPackHelper-XXXXXX"); 1573 if (RT_FAILURE(rc)) 1574 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTPathAppend failed: %Rrc", rc); 1575 rc = RTDirCreateTemp(szTempDir); 1576 if (RT_FAILURE(rc)) 1577 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTDirCreateTemp failed: %Rrc", rc); 1578 1579 RTEXITCODE rcExit = RTEXITCODE_FAILURE; 1580 char szStdOut[RTPATH_MAX]; 1581 char szStdErr[RTPATH_MAX]; 1582 rc = RTPathJoin(szStdOut, sizeof(szStdOut), szTempDir, "stdout"); 1583 if (RT_SUCCESS(rc)) 1584 rc = RTPathJoin(szStdErr, sizeof(szStdErr), szTempDir, "stderr"); 1585 if (RT_SUCCESS(rc)) 1586 { 1587 RTFILE hStdOut; 1588 rc = RTFileOpen(&hStdOut, szStdOut, RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_NONE 1589 | (0600 << RTFILE_O_CREATE_MODE_SHIFT)); 1590 if (RT_SUCCESS(rc)) 1591 { 1592 RTFILE hStdErr; 1593 rc = RTFileOpen(&hStdErr, szStdErr, RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_NONE 1594 | (0600 << RTFILE_O_CREATE_MODE_SHIFT)); 1595 if (RT_SUCCESS(rc)) 1596 { 1597 /* 1598 * Insert the --elevated and stdout/err names into the argument 1599 * list. 1600 */ 1601 int cArgs = argc + 5 + 1; 1602 char const **papszArgs = (char const **)RTMemTmpAllocZ((cArgs + 1) * sizeof(const char *)); 1603 if (papszArgs) 1604 { 1605 papszArgs[0] = argv[0]; 1606 papszArgs[1] = "--elevated"; 1607 papszArgs[2] = "--stdout"; 1608 papszArgs[3] = szStdOut; 1609 papszArgs[4] = "--stderr"; 1610 papszArgs[5] = szStdErr; 1611 for (int i = 1; i <= argc; i++) 1612 papszArgs[i + 5] = argv[i]; 1613 1614 /* 1615 * Do the platform specific process execution (waiting included). 1616 */ 1617 rcExit = RelaunchElevatedNative(szExecPath, cArgs, papszArgs); 1618 1619 /* 1620 * Copy the standard files to our standard handles. 1621 */ 1622 CopyFileToStdXxx(hStdErr, g_pStdErr, true /*fComplain*/); 1623 CopyFileToStdXxx(hStdOut, g_pStdOut, false); 1624 1625 RTMemTmpFree(papszArgs); 1626 } 1627 1628 RTFileClose(hStdErr); 1629 RTFileDelete(szStdErr); 1630 } 1631 RTFileClose(hStdOut); 1632 RTFileDelete(szStdOut); 1633 } 1634 } 1635 RTDirRemove(szTempDir); 1636 1637 return rcExit; 1638 } 1639 1640 1641 /** 1642 * Checks if the process is elevated or not. 1643 * 1644 * @returns true/false. 1645 */ 1646 static bool IsElevated(void) 1647 { 1648 # if defined(RT_OS_WINDOWS) 1649 /* 1650 * Check if we are elevated. 1651 */ 1652 /** @todo This should probably check if UAC is diabled and if we are 1653 * Administrator first. Also needs to check for Vista+ first, probably. 1654 */ 1655 HANDLE hToken; 1656 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &hToken)) 1657 { 1658 RTMsgError("OpenProcessToken failed: %u (%#x)", GetLastError(), GetLastError()); 1659 return false; 1660 } 1661 1662 bool fElevated = true; 1663 DWORD cb; 1664 DWORD TokenIsElevated = 0; 1665 if (GetTokenInformation(hToken, (TOKEN_INFORMATION_CLASS)/*TokenElevation*/ 20, &TokenIsElevated, sizeof(TokenIsElevated), &cb)) 1666 { 1667 fElevated = TokenIsElevated != 0; 1668 if (fElevated) 1669 { 1670 enum 1671 { 1672 MY_TokenElevationTypeDefault = 1, 1673 MY_TokenElevationTypeFull, 1674 MY_TokenElevationTypeLimited 1675 } enmType; 1676 if (GetTokenInformation(hToken, (TOKEN_INFORMATION_CLASS)/*TokenElevationType*/ 18, &enmType, sizeof(enmType), &cb)) 1677 { 1678 fElevated = enmType == MY_TokenElevationTypeFull; 1679 } 1680 else 1681 { 1682 RTMsgError("GetTokenInformation failed: %u (%#x)", GetLastError(), GetLastError()); 1683 fElevated = false; 1684 } 1685 } 1686 } 1687 else if ( GetLastError() != ERROR_INVALID_PARAMETER 1688 && GetLastError() != ERROR_NOT_SUPPORTED) 1689 { 1690 RTMsgError("GetTokenInformation failed: %u (%#x)", GetLastError(), GetLastError()); 1691 fElevated = false; 1692 } 1693 CloseHandle(hToken); 1694 1695 return fElevated; 1696 1697 # else 1698 /* 1699 * On Unixy systems, we check if the executable and the current user is 1700 * the same. This heuristic works fine for both hardened and development 1701 * builds. 1702 */ 1703 char szExecPath[RTPATH_MAX]; 1704 int rc = RTProcGetExecutablePath(szExecPath,sizeof(szExecPath)); 1705 if (RT_FAILURE(rc)) 1706 { 1707 RTMsgError("RTProcGetExecutablePath failed: %Rrc", rc); 1708 return false; 1709 } 1710 1711 RTFSOBJINFO ObjInfo; 1712 rc = RTPathQueryInfoEx(szExecPath, &ObjInfo, RTFSOBJATTRADD_UNIX, RTPATH_F_ON_LINK); 1713 if (RT_FAILURE(rc) 1714 { 1715 RTMsgError("RTProcGetExecutablePath failed: %Rrc", rc); 1716 return false; 1717 } 1718 1719 RTUID uid = geteuid(); 1720 return uid == ObjInfo.Attr.u.Unix.Uid; 1721 # endif 1722 } 1723 1724 #endif /* WITH_ELEVATION */ 1389 1725 1390 1726 int main(int argc, char **argv) … … 1413 1749 #define CMD_CLEANUP 1002 1414 1750 { "cleanup", CMD_CLEANUP, RTGETOPT_REQ_NOTHING }, 1751 #ifdef WITH_ELEVATION 1752 # define OPT_ELEVATED 1090 1753 { "--elevated", OPT_ELEVATED, RTGETOPT_REQ_NOTHING }, 1754 # define OPT_STDOUT 1091 1755 { "--stdout", OPT_STDOUT, RTGETOPT_REQ_STRING }, 1756 # define OPT_STDERR 1092 1757 { "--stderr", OPT_STDERR, RTGETOPT_REQ_STRING }, 1758 #endif 1415 1759 }; 1416 1760 RTGETOPTSTATE GetState; … … 1418 1762 if (RT_FAILURE(rc)) 1419 1763 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTGetOptInit failed: %Rrc\n", rc); 1764 bool fElevated = IsElevated(); 1420 1765 for (;;) 1421 1766 { … … 1428 1773 1429 1774 case CMD_INSTALL: 1430 return DoInstall( argc - GetState.iNext, argv + GetState.iNext);1431 1432 1775 case CMD_UNINSTALL: 1433 return DoUninstall(argc - GetState.iNext, argv + GetState.iNext);1434 1435 1776 case CMD_CLEANUP: 1436 return DoCleanup( argc - GetState.iNext, argv + GetState.iNext); 1777 { 1778 #ifdef WITH_ELEVATION 1779 if (!fElevated) 1780 return RelaunchElevated(argc, argv); 1781 #endif 1782 RTEXITCODE rcExit; 1783 int cCmdargs = argc - GetState.iNext; 1784 char **papszCmdArgs = argv + GetState.iNext; 1785 switch (ch) 1786 { 1787 case CMD_INSTALL: 1788 rcExit = DoInstall( cCmdargs, papszCmdArgs); 1789 break; 1790 case CMD_UNINSTALL: 1791 rcExit = DoUninstall(cCmdargs, papszCmdArgs); 1792 break; 1793 case CMD_CLEANUP: 1794 rcExit = DoCleanup( cCmdargs, papszCmdArgs); 1795 break; 1796 default: 1797 AssertReleaseFailedReturn(RTEXITCODE_FAILURE); 1798 } 1799 1800 /* 1801 * Standard error should end with rcExit=RTEXITCODE_SUCCESS on 1802 * success since the exit code may otherwise get lost in the 1803 * process elevation fun. 1804 */ 1805 RTStrmFlush(g_pStdOut); 1806 RTStrmFlush(g_pStdErr); 1807 switch (rcExit) 1808 { 1809 case RTEXITCODE_SUCCESS: 1810 RTStrmPrintf(g_pStdErr, "rcExit=RTEXITCODE_SUCCESS\n"); 1811 break; 1812 default: 1813 RTStrmPrintf(g_pStdErr, "rcExit=%d\n", rcExit); 1814 break; 1815 } 1816 RTStrmFlush(g_pStdErr); 1817 RTStrmFlush(g_pStdOut); 1818 return rcExit; 1819 } 1820 1821 #ifdef WITH_ELEVATION 1822 case OPT_ELEVATED: 1823 fElevated = true; 1824 break; 1825 1826 case OPT_STDERR: 1827 case OPT_STDOUT: 1828 { 1829 FILE *pFile = freopen(ValueUnion.psz, "r+", ch == OPT_STDOUT ? stdout : stderr); 1830 if (!pFile) 1831 { 1832 rc = RTErrConvertFromErrno(errno); 1833 return RTMsgErrorExit(RTEXITCODE_FAILURE, "freopen on '%s': %Rrc", ValueUnion.psz, rc); 1834 } 1835 break; 1836 } 1837 #endif 1437 1838 1438 1839 case 'h':
Note:
See TracChangeset
for help on using the changeset viewer.