VirtualBox

Changeset 34711 in vbox for trunk/src


Ignore:
Timestamp:
Dec 3, 2010 9:49:36 PM (14 years ago)
Author:
vboxsync
Message:

elevation on windows.

Location:
trunk/src/VBox/Main
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/ExtPackManagerImpl.cpp

    r34704 r34711  
    16581658            if (hPipeR != NIL_RTPIPE)
    16591659            {
    1660                 char    achBuf[16]; ///@todo 1024
     1660                char    achBuf[1024];
    16611661                size_t  cbRead;
    16621662                vrc = RTPipeReadBlocking(hPipeR, achBuf, sizeof(achBuf), &cbRead);
     
    17091709                 || hProcess != NIL_RTPROCESS);
    17101710
     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
    17111734        /*
    17121735         * Compose the status code and, on failure, error message.
    17131736         */
    1714         LogRel(("ExtPack: enmReason=%d iStatus=%d stderr='%s'\n",
    1715                 ProcStatus.enmReason, ProcStatus.iStatus, offStdErrBuf ? pszStdErrBuf : ""));
    1716 
    17171737        if (   ProcStatus.enmReason == RTPROCEXITREASON_NORMAL
    17181738            && ProcStatus.iStatus   == 0
  • trunk/src/VBox/Main/VBoxExtPackHelperApp.cpp

    r34608 r34711  
    4444#include <VBox/version.h>
    4545
     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
    4662
    4763/*******************************************************************************
    4864*   Defined Constants And Macros                                               *
    4965*******************************************************************************/
     66/* Enable elevation on windows and darwin. */
     67#if defined(RT_OS_WINDOWS)
     68# define WITH_ELEVATION
     69#endif
     70
    5071/** The maximum entry name length.
    5172 * Play short and safe. */
     
    278299        return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTManifestCreate failed: %Rrc", rc);
    279300
    280     RTEXITCODE    rcExit;
    281301    RTVFSIOSTREAM hVfsIos = RTVfsFileToIoStream(hManifestFile);
    282302    rc = RTManifestReadStandard(hTheirManifest, hVfsIos);
     
    13861406}
    13871407
    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 */
     1419static 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 */
     1456static 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 */
     1556static 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 */
     1646static 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 */
    13891725
    13901726int main(int argc, char **argv)
     
    14131749#define CMD_CLEANUP     1002
    14141750        { "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
    14151759    };
    14161760    RTGETOPTSTATE GetState;
     
    14181762    if (RT_FAILURE(rc))
    14191763        return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTGetOptInit failed: %Rrc\n", rc);
     1764    bool fElevated = IsElevated();
    14201765    for (;;)
    14211766    {
     
    14281773
    14291774            case CMD_INSTALL:
    1430                 return DoInstall(  argc - GetState.iNext, argv + GetState.iNext);
    1431 
    14321775            case CMD_UNINSTALL:
    1433                 return DoUninstall(argc - GetState.iNext, argv + GetState.iNext);
    1434 
    14351776            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
    14371838
    14381839            case 'h':
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