Changeset 59817 in vbox
- Timestamp:
- Feb 25, 2016 4:38:19 PM (9 years ago)
- File:
-
- 1 edited
-
trunk/src/VBox/Runtime/r3/win/process-win.cpp (modified) (10 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/r3/win/process-win.cpp
r59781 r59817 5 5 6 6 /* 7 * Copyright (C) 2006-201 5Oracle Corporation7 * Copyright (C) 2006-2016 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 38 38 #include <errno.h> 39 39 #include <Strsafe.h> 40 #ifndef IPRT_TARGET_NT4 41 # include <LsaLookup.h> 42 #endif 40 43 #include <Lmcons.h> 44 45 #ifndef IPRT_TARGET_NT4 46 # define _NTDEF_ /* Prevents redefining (P)UNICODE_STRING. */ 47 # include <Ntsecapi.h> 48 #endif 41 49 42 50 #include <iprt/process.h> … … 79 87 typedef BOOL (WINAPI *PFNCREATEPROCESSWITHLOGON)(LPCWSTR, LPCWSTR, LPCWSTR, DWORD, LPCWSTR, LPWSTR, DWORD, 80 88 LPVOID, LPCWSTR, LPSTARTUPINFOW, LPPROCESS_INFORMATION); 89 typedef NTSTATUS (NTAPI *PFNLSALOOKUPNAMES2)(LSA_HANDLE, ULONG, ULONG, PLSA_UNICODE_STRING, 90 PLSA_REFERENCED_DOMAIN_LIST*, PLSA_TRANSLATED_SID2*); 81 91 82 92 /* userenv.dll: */ … … 106 116 HANDLE hProcess; 107 117 } *g_paProcesses; 118 119 /** Structure for storing a user's account info. 120 * Must be free'd with rtProcWinFreeAccountInfo(). */ 121 typedef 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; 108 128 109 129 /** @name userenv.dll imports (we don't unload it). … … 124 144 /* advapi32.dll: */ 125 145 static PFNCREATEPROCESSWITHLOGON g_pfnCreateProcessWithLogonW = NULL; 146 static PFNLSALOOKUPNAMES2 g_pfnLsaLookupNames2 = NULL; 126 147 /* userenv.dll: */ 127 148 static PFNCREATEENVIRONMENTBLOCK g_pfnCreateEnvironmentBlock = NULL; … … 323 344 * advapi32.dll APIs. 324 345 */ 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 } 326 357 327 358 /* … … 1270 1301 1271 1302 /** 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 */ 1311 static 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 1368 static 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 /** 1272 1388 * Method \#2. 1273 1389 */ … … 1320 1436 if (fFlags & RTPROC_FLAGS_SERVICE) 1321 1437 { 1438 PSID pSid = NULL; 1439 1322 1440 /* 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; 1326 1444 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)) 1336 1462 { 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) 1339 1470 { 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) 1341 1488 { 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) 1344 1498 { 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 } 1352 1513 } 1353 1514 else 1354 1515 { 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; 1357 1519 } 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); 1358 1534 } 1359 1535 else 1360 1536 { 1361 dwErr = GetLastError(); 1537 dwErr = LsaNtStatusToWinError(ntSts); 1538 LogRelFunc(("LsaOpenPolicy failed with: %ld\n", dwErr)); 1362 1539 rc = dwErr != NO_ERROR ? RTErrConvertFromWin32(dwErr) : VERR_INTERNAL_ERROR_3; 1363 1540 } 1364 RTMemFree(pwszDomain); 1541 1542 /* Note: pSid will be free'd down below. */ 1365 1543 } 1366 1544 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 } 1368 1605 1369 1606 RTMemFree(pSid); 1370 1607 } 1371 else1372 rc = VERR_NO_MEMORY;1373 1608 } 1374 1609 /* else: !RTPROC_FLAGS_SERVICE: Nothing to do here right now. */ … … 1505 1740 LogRelFunc(("dwErr=%u (%#x), rc=%Rrc\n", dwErr, dwErr, rc)); 1506 1741 } 1742 1507 1743 return rc; 1508 1744 } … … 1724 1960 rc = RTErrConvertFromWin32(dwErr); 1725 1961 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", 1727 1963 g_pfnCreateProcessWithLogonW, dwErr, dwErr, rc)); 1728 1964 }
Note:
See TracChangeset
for help on using the changeset viewer.

