VirtualBox

Changeset 59817 in vbox


Ignore:
Timestamp:
Feb 25, 2016 4:38:19 PM (9 years ago)
Author:
vboxsync
Message:

IPRT/r3/win/process-win.cpp: re-applied the process-win.cpp changes which were backed-out at r105657 and resolve LsaLookupNames2() dynamically as it's not supported on systems < Windows XP

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/r3/win/process-win.cpp

    r59781 r59817  
    55
    66/*
    7  * Copyright (C) 2006-2015 Oracle Corporation
     7 * Copyright (C) 2006-2016 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    3838#include <errno.h>
    3939#include <Strsafe.h>
     40#ifndef IPRT_TARGET_NT4
     41# include <LsaLookup.h>
     42#endif
    4043#include <Lmcons.h>
     44
     45#ifndef IPRT_TARGET_NT4
     46# define _NTDEF_ /* Prevents redefining (P)UNICODE_STRING. */
     47# include <Ntsecapi.h>
     48#endif
    4149
    4250#include <iprt/process.h>
     
    7987typedef BOOL    (WINAPI *PFNCREATEPROCESSWITHLOGON)(LPCWSTR, LPCWSTR, LPCWSTR, DWORD, LPCWSTR, LPWSTR, DWORD,
    8088                                                    LPVOID, LPCWSTR, LPSTARTUPINFOW, LPPROCESS_INFORMATION);
     89typedef NTSTATUS (NTAPI *PFNLSALOOKUPNAMES2)(LSA_HANDLE, ULONG, ULONG, PLSA_UNICODE_STRING,
     90                                             PLSA_REFERENCED_DOMAIN_LIST*, PLSA_TRANSLATED_SID2*);
    8191
    8292/* userenv.dll: */
     
    106116    HANDLE          hProcess;
    107117}                  *g_paProcesses;
     118
     119/** Structure for storing a user's account info.
     120 *  Must be free'd with rtProcWinFreeAccountInfo(). */
     121typedef struct RTPROCWINACCOUNTINFO
     122{
     123    /** User name. */
     124    PRTUTF16        pwszUserName;
     125    /** Domain this account is tied to. Can be NULL if no domain is being used. */
     126    PRTUTF16        pwszDomain;
     127} RTPROCWINACCOUNTINFO, *PRTPROCWINACCOUNTINFO;
    108128
    109129/** @name userenv.dll imports (we don't unload it).
     
    124144/* advapi32.dll: */
    125145static PFNCREATEPROCESSWITHLOGON        g_pfnCreateProcessWithLogonW    = NULL;
     146static PFNLSALOOKUPNAMES2               g_pfnLsaLookupNames2            = NULL;
    126147/* userenv.dll: */
    127148static PFNCREATEENVIRONMENTBLOCK        g_pfnCreateEnvironmentBlock     = NULL;
     
    323344     * advapi32.dll APIs.
    324345     */
    325     g_pfnCreateProcessWithLogonW    = (PFNCREATEPROCESSWITHLOGON)RTLdrGetSystemSymbol("advapi32.dll", "CreateProcessWithLogonW");
     346    rc = RTLdrLoadSystem("advapi32.dll", true /*fNoUnload*/, &hMod);
     347    if (RT_SUCCESS(rc))
     348    {
     349        rc = RTLdrGetSymbol(hMod, "CreateProcessWithLogonW", (void **)&g_pfnCreateProcessWithLogonW);
     350        AssertStmt(RT_SUCCESS(rc), g_pfnCreateProcessWithLogonW = NULL);
     351
     352        rc = RTLdrGetSymbol(hMod, "LsaLookupNames2", (void **)&g_pfnLsaLookupNames2);
     353        AssertStmt(RT_SUCCESS(rc), g_pfnLsaLookupNames2 = NULL);
     354
     355        RTLdrClose(hMod);
     356    }
    326357
    327358    /*
     
    12701301
    12711302/**
     1303 * Extracts the user name + domain from a given UPN (User Principal Name, "joedoe@example.com") or
     1304 * Down-Level Logon Name format ("example.com\\joedoe") string.
     1305 *
     1306 * @return  IPRT status code.
     1307 * @param   pwszString      Pointer to string to extract the account info from.
     1308 * @param   pAccountInfo    Where to store the parsed account info.
     1309 *                          Must be free'd with rtProcWinFreeAccountInfo().
     1310 */
     1311static int rtProcWinParseAccountInfo(PRTUTF16 pwszString, PRTPROCWINACCOUNTINFO pAccountInfo)
     1312{
     1313    AssertPtrReturn(pwszString,   VERR_INVALID_POINTER);
     1314    AssertPtrReturn(pAccountInfo, VERR_INVALID_POINTER);
     1315
     1316    /*
     1317     * Note: UPN handling is defined in RFC 822. We only implement very rudimentary parsing for the user
     1318     *       name and domain fields though.
     1319     */
     1320    char *pszString;
     1321    int rc = RTUtf16ToUtf8(pwszString, &pszString);
     1322    if (RT_SUCCESS(rc))
     1323    {
     1324        do
     1325        {
     1326            /* UPN or FQDN handling needed? */
     1327            /** @todo Add more validation here as needed. Regular expressions would be nice. */
     1328            char *pszDelim = strchr(pszString, '@');
     1329            if (pszDelim) /* UPN name? */
     1330            {
     1331                rc = RTStrToUtf16Ex(pszString, pszDelim - pszString, &pAccountInfo->pwszUserName, 0, NULL);
     1332                if (RT_FAILURE(rc))
     1333                    break;
     1334
     1335                rc = RTStrToUtf16Ex(pszDelim + 1, RTSTR_MAX, &pAccountInfo->pwszDomain, 0, NULL);
     1336                if (RT_FAILURE(rc))
     1337                    break;
     1338            }
     1339            else if (pszDelim = strchr(pszString, '\\')) /* FQDN name? */
     1340            {
     1341                rc = RTStrToUtf16Ex(pszString, pszDelim - pszString, &pAccountInfo->pwszDomain, 0, NULL);
     1342                if (RT_FAILURE(rc))
     1343                    break;
     1344
     1345                rc = RTStrToUtf16Ex(pszDelim + 1, RTSTR_MAX, &pAccountInfo->pwszUserName, 0, NULL);
     1346                if (RT_FAILURE(rc))
     1347                    break;
     1348            }
     1349            else
     1350                rc = VERR_NOT_SUPPORTED;
     1351
     1352        } while (0);
     1353
     1354        RTStrFree(pszString);
     1355    }
     1356
     1357#ifdef DEBUG
     1358    LogRelFunc(("Name  : %ls\n", pAccountInfo->pwszUserName));
     1359    LogRelFunc(("Domain: %ls\n", pAccountInfo->pwszDomain));
     1360#endif
     1361
     1362    if (RT_FAILURE(rc))
     1363        LogRelFunc(("Parsing \"%ls\" failed with rc=%Rrc\n", pwszString, rc));
     1364    return rc;
     1365}
     1366
     1367
     1368static void rtProcWinFreeAccountInfo(PRTPROCWINACCOUNTINFO pAccountInfo)
     1369{
     1370    if (!pAccountInfo)
     1371        return;
     1372
     1373    if (pAccountInfo->pwszUserName)
     1374    {
     1375        RTUtf16Free(pAccountInfo->pwszUserName);
     1376        pAccountInfo->pwszUserName = NULL;
     1377    }
     1378
     1379    if (pAccountInfo->pwszDomain)
     1380    {
     1381        RTUtf16Free(pAccountInfo->pwszDomain);
     1382        pAccountInfo->pwszDomain = NULL;
     1383    }
     1384}
     1385
     1386
     1387/**
    12721388 * Method \#2.
    12731389 */
     
    13201436        if (fFlags & RTPROC_FLAGS_SERVICE)
    13211437        {
     1438            PSID pSid = NULL;
     1439
    13221440            /* Try query the SID and domain sizes first. */
    1323             DWORD           cbSid      = 0; /* Must be zero to query size! */
    1324             DWORD           cwcDomain  = 0;
    1325             SID_NAME_USE    SidNameUse = SidTypeUser;
     1441            DWORD        cbSid      = 0; /* Must be zero to query size! */
     1442            DWORD        cwcDomain  = 0;
     1443            SID_NAME_USE SidNameUse = SidTypeUser;
    13261444            fRc = LookupAccountNameW(NULL, pwszUser, NULL, &cbSid, NULL, &cwcDomain, &SidNameUse);
    1327 
    1328             /* Allocate memory for the LookupAccountNameW output buffers and do it for real. */
    1329             cbSid = fRc && cbSid != 0 ? cbSid + 16 : _1K;
    1330             PSID pSid = (PSID)RTMemAllocZ(cbSid);
    1331             if (pSid)
    1332             {
    1333                 cwcDomain = fRc ? cwcDomain + 2 : _4K;
    1334                 PRTUTF16 pwszDomain = (PRTUTF16)RTMemAllocZ(cwcDomain * sizeof(RTUTF16));
    1335                 if (pwszDomain)
     1445            if (!fRc)
     1446            {
     1447                dwErr = GetLastError();
     1448
     1449#ifndef IPRT_TARGET_NT4
     1450                /*
     1451                 * The errors ERROR_TRUSTED_DOMAIN_FAILURE and ERROR_TRUSTED_RELATIONSHIP_FAILURE
     1452                 * can happen if an ADC (Active Domain Controller) is offline or not reachable.
     1453                 *
     1454                 * Try to handle these errors gracefully by asking the local LSA cache of the
     1455                 * client OS instead then. For this to work, the desired user must have at
     1456                 * least logged in once at that client -- otherwise there will be no cached
     1457                 * authentication available and this fallback will fail.
     1458                 */
     1459                if (   g_pfnLsaLookupNames2 /* >= Windows XP */
     1460                    && (   dwErr == ERROR_TRUSTED_DOMAIN_FAILURE
     1461                        || dwErr == ERROR_TRUSTED_RELATIONSHIP_FAILURE))
    13361462                {
    1337                     /* Note: Just pass in the UPN (User Principal Name), e.g. someone@example.com */
    1338                     if (LookupAccountNameW(NULL /*lpSystemName*/, pwszUser, pSid, &cbSid, pwszDomain, &cwcDomain, &SidNameUse))
     1463                    LSA_OBJECT_ATTRIBUTES objAttr;
     1464                    RT_ZERO(objAttr);
     1465                    objAttr.Length = sizeof(LSA_OBJECT_ATTRIBUTES);
     1466
     1467                    LSA_HANDLE lsahPolicy;
     1468                    NTSTATUS ntSts = LsaOpenPolicy(NULL, &objAttr, POLICY_LOOKUP_NAMES, &lsahPolicy);
     1469                    if (ntSts == STATUS_SUCCESS)
    13391470                    {
    1340                         if (IsValidSid(pSid))
     1471                        RTPROCWINACCOUNTINFO accountInfo;
     1472                        RT_ZERO(accountInfo);
     1473                        rc = rtProcWinParseAccountInfo(pwszUser, &accountInfo);
     1474                        AssertRC(rc);
     1475                        AssertPtr(accountInfo.pwszUserName);
     1476
     1477                        LSA_UNICODE_STRING lsaUser;
     1478                        lsaUser.Buffer        = accountInfo.pwszUserName;
     1479                        lsaUser.Length        = (USHORT)(RTUtf16Len(accountInfo.pwszUserName) * sizeof(WCHAR));
     1480                        lsaUser.MaximumLength = lsaUser.Length;
     1481
     1482                        PLSA_REFERENCED_DOMAIN_LIST pDomainList     = NULL;
     1483                        PLSA_TRANSLATED_SID2        pTranslatedSids = NULL;
     1484                        ntSts = g_pfnLsaLookupNames2(lsahPolicy, 0 /* Flags */,
     1485                                                     1 /* Number of users to lookup */,
     1486                                                     &lsaUser, &pDomainList, &pTranslatedSids);
     1487                        if (ntSts == STATUS_SUCCESS)
    13411488                        {
    1342                             /* Array of process names we want to look for. */
    1343                             static const char * const s_papszProcNames[] =
     1489                            AssertPtr(pDomainList);
     1490                            AssertPtr(pTranslatedSids);
     1491# ifdef DEBUG
     1492                            LogRelFunc(("LsaLookupNames2: cDomains=%u, DomainIndex=%ld, SidUse=%ld\n",
     1493                                        pDomainList->Entries, pTranslatedSids[0].DomainIndex, pTranslatedSids[0].Use));
     1494# endif
     1495                            Assert(pTranslatedSids[0].Use == SidTypeUser);
     1496
     1497                            if (pDomainList->Entries)
    13441498                            {
    1345 #ifdef VBOX                     /* The explorer entry is a fallback in case GA aren't installed. */
    1346                                 { "VBoxTray.exe" },
    1347 #endif
    1348                                 { "explorer.exe" },
    1349                                 NULL
    1350                             };
    1351                             fFound = rtProcWinFindTokenByProcess(s_papszProcNames, pSid, &hTokenUserDesktop);
     1499                                AssertPtr(pDomainList->Domains);
     1500                                LogRelFunc(("LsaLookupNames2: Domain=%ls\n",
     1501                                            pDomainList->Domains[pTranslatedSids[0].DomainIndex].Name.Buffer));
     1502                            }
     1503
     1504                            cbSid = GetLengthSid(pTranslatedSids->Sid) + 16;
     1505                            Assert(cbSid);
     1506                            pSid = (PSID)RTMemAllocZ(cbSid);
     1507                            if (!CopySid(cbSid, pSid, pTranslatedSids->Sid))
     1508                            {
     1509                                dwErr = GetLastError();
     1510                                LogRelFunc(("CopySid failed with: %ld\n", dwErr));
     1511                                rc = dwErr != NO_ERROR ? RTErrConvertFromWin32(dwErr) : VERR_INTERNAL_ERROR_2;
     1512                            }
    13521513                        }
    13531514                        else
    13541515                        {
    1355                             dwErr = GetLastError();
    1356                             rc = dwErr != NO_ERROR ? RTErrConvertFromWin32(dwErr) : VERR_INTERNAL_ERROR_4;
     1516                            dwErr = LsaNtStatusToWinError(ntSts);
     1517                            LogRelFunc(("LsaLookupNames2 failed with: %ld\n", dwErr));
     1518                            rc = dwErr != NO_ERROR ? RTErrConvertFromWin32(dwErr) : VERR_INTERNAL_ERROR_2;
    13571519                        }
     1520
     1521                        if (pDomainList)
     1522                        {
     1523                            LsaFreeMemory(pDomainList);
     1524                            pDomainList = NULL;
     1525                        }
     1526                        if (pTranslatedSids)
     1527                        {
     1528                            LsaFreeMemory(pTranslatedSids);
     1529                            pTranslatedSids = NULL;
     1530                        }
     1531
     1532                        rtProcWinFreeAccountInfo(&accountInfo);
     1533                        LsaClose(lsahPolicy);
    13581534                    }
    13591535                    else
    13601536                    {
    1361                         dwErr = GetLastError();
     1537                        dwErr = LsaNtStatusToWinError(ntSts);
     1538                        LogRelFunc(("LsaOpenPolicy failed with: %ld\n", dwErr));
    13621539                        rc = dwErr != NO_ERROR ? RTErrConvertFromWin32(dwErr) : VERR_INTERNAL_ERROR_3;
    13631540                    }
    1364                     RTMemFree(pwszDomain);
     1541
     1542                    /* Note: pSid will be free'd down below. */
    13651543                }
    13661544                else
    1367                     rc = VERR_NO_MEMORY;
     1545#endif /* !IPRT_TARGET_NT4 */
     1546                if (dwErr == ERROR_INSUFFICIENT_BUFFER)
     1547                {
     1548                    /* Allocate memory for the LookupAccountNameW output buffers and do it for real. */
     1549                    cbSid = fRc && cbSid != 0 ? cbSid + 16 : _1K;
     1550                    pSid = (PSID)RTMemAllocZ(cbSid);
     1551                    if (pSid)
     1552                    {
     1553                        cwcDomain = fRc ? cwcDomain + 2 : _4K;
     1554                        PRTUTF16 pwszDomain = (PRTUTF16)RTMemAllocZ(cwcDomain * sizeof(RTUTF16));
     1555                        if (pwszDomain)
     1556                        {
     1557                            /* Note: Just pass in the UPN (User Principal Name), e.g. someone@example.com */
     1558                            if (!LookupAccountNameW(NULL /*lpSystemName*/, pwszUser, pSid, &cbSid, pwszDomain, &cwcDomain,
     1559                                                    &SidNameUse))
     1560                            {
     1561                                dwErr = GetLastError();
     1562                                LogRelFunc(("LookupAccountNameW(2) failed with: %ld\n", dwErr));
     1563                                rc = dwErr != NO_ERROR ? RTErrConvertFromWin32(dwErr) : VERR_INTERNAL_ERROR_4;
     1564                            }
     1565
     1566                            RTMemFree(pwszDomain);
     1567                        }
     1568                        else
     1569                            rc = VERR_NO_MEMORY;
     1570
     1571                        /* Note: pSid will be free'd down below. */
     1572                    }
     1573                    else
     1574                        rc = VERR_NO_MEMORY;
     1575                }
     1576                else
     1577                {
     1578                    LogRelFunc(("LookupAccountNameW(1) failed with: %ld\n", dwErr));
     1579                    rc = dwErr != NO_ERROR ? RTErrConvertFromWin32(dwErr) : VERR_INTERNAL_ERROR_2;
     1580                }
     1581            }
     1582
     1583            if (pSid)
     1584            {
     1585                if (IsValidSid(pSid))
     1586                {
     1587                    /* Array of process names we want to look for. */
     1588                    static const char * const s_papszProcNames[] =
     1589                    {
     1590#ifdef VBOX             /* The explorer entry is a fallback in case GA aren't installed. */
     1591                        { "VBoxTray.exe" },
     1592#endif
     1593                        { "explorer.exe" },
     1594                        NULL
     1595                    };
     1596                    fFound = rtProcWinFindTokenByProcess(s_papszProcNames, pSid, &hTokenUserDesktop);
     1597                    dwErr  = 0;
     1598                }
     1599                else
     1600                {
     1601                    dwErr = GetLastError();
     1602                    LogRelFunc(("SID is invalid: %ld\n", dwErr));
     1603                    rc = dwErr != NO_ERROR ? RTErrConvertFromWin32(dwErr) : VERR_INTERNAL_ERROR_3;
     1604                }
    13681605
    13691606                RTMemFree(pSid);
    13701607            }
    1371             else
    1372                 rc = VERR_NO_MEMORY;
    13731608        }
    13741609        /* else: !RTPROC_FLAGS_SERVICE: Nothing to do here right now. */
     
    15051740            LogRelFunc(("dwErr=%u (%#x), rc=%Rrc\n", dwErr, dwErr, rc));
    15061741    }
     1742
    15071743    return rc;
    15081744}
     
    17241960            rc = RTErrConvertFromWin32(dwErr);
    17251961            if (rc == VERR_UNRESOLVED_ERROR)
    1726                 LogRelFunc(("g_pfnCreateProcessWithLogonW (%p) failed: dwErr=%u (%#x), rc=%Rrc\n",
     1962                LogRelFunc(("CreateProcessWithLogonW (%p) failed: dwErr=%u (%#x), rc=%Rrc\n",
    17271963                            g_pfnCreateProcessWithLogonW, dwErr, dwErr, rc));
    17281964        }
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