Changeset 59542 in vbox
- Timestamp:
- Feb 1, 2016 1:27:36 PM (9 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/r3/win/process-win.cpp
r59519 r59542 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 #include <LsaLookup.h> 40 41 #include <Lmcons.h> 42 43 #define _NTDEF_ /* Prevents redefining (P)UNICODE_STRING. */ 44 #include <Ntsecapi.h> 41 45 42 46 #include <iprt/process.h> … … 106 110 HANDLE hProcess; 107 111 } *g_paProcesses; 112 113 /** Strucutre for storing a user's account info. 114 * Must be free'd with rtProcWinFreeAccountInfo(). */ 115 typedef struct RTPROCWINACCOUNTINFO 116 { 117 /** User name. */ 118 PRTUTF16 pwszUserName; 119 /** Domain this account is tied to. Can be NULL if no domain is being used. */ 120 PRTUTF16 pwszDomain; 121 } RTPROCWINACCOUNTINFO, *PRTPROCWINACCOUNTINFO; 108 122 109 123 /** @name userenv.dll imports (we don't unload it). … … 1270 1284 1271 1285 /** 1286 * Extracts the user name + domain from a given UPN (User Principal Name, [email protected]) or 1287 * Down-Level Logon Name format (example.com\joedoe) string. 1288 * 1289 * @return IPRT status code. 1290 * @param pwszString Pointer to string to extract the account info from. 1291 * @param pAccountInfo Where to store the parsed account info. 1292 * Must be free'd with rtProcWinFreeAccountInfo(). 1293 */ 1294 static int rtProcWinParseAccountInfo(PRTUTF16 pwszString, PRTPROCWINACCOUNTINFO pAccountInfo) 1295 { 1296 AssertPtrReturn(pwszString, VERR_INVALID_POINTER); 1297 AssertPtrReturn(pAccountInfo, VERR_INVALID_POINTER); 1298 1299 /* 1300 * Note: UPN handling is defined in RFC 822. We only implement very rudimentary parsing for the user 1301 * name and domain fields though. 1302 */ 1303 char *pszString; 1304 int rc = RTUtf16ToUtf8(pwszString, &pszString); 1305 if (RT_SUCCESS(rc)) 1306 { 1307 do 1308 { 1309 /* UPN or FQDN handling needed? */ 1310 /** @todo Add more validation here as needed. Regular expressions would be nice. */ 1311 char *pszDelim = strchr(pszString, '@'); 1312 if (pszDelim) /* UPN name? */ 1313 { 1314 rc = RTStrToUtf16Ex(pszString, pszDelim - pszString, &pAccountInfo->pwszUserName, 0, NULL); 1315 if (RT_FAILURE(rc)) 1316 break; 1317 1318 rc = RTStrToUtf16Ex(pszDelim + 1, RTSTR_MAX, &pAccountInfo->pwszDomain, 0, NULL); 1319 if (RT_FAILURE(rc)) 1320 break; 1321 } 1322 else if (pszDelim = strchr(pszString, '\\')) /* FQDN name? */ 1323 { 1324 rc = RTStrToUtf16Ex(pszString, pszDelim - pszString, &pAccountInfo->pwszDomain, 0, NULL); 1325 if (RT_FAILURE(rc)) 1326 break; 1327 1328 rc = RTStrToUtf16Ex(pszDelim + 1, RTSTR_MAX, &pAccountInfo->pwszUserName, 0, NULL); 1329 if (RT_FAILURE(rc)) 1330 break; 1331 } 1332 else 1333 rc = VERR_INVALID_PARAMETER; 1334 1335 } while (0); 1336 1337 RTStrFree(pszString); 1338 } 1339 1340 #ifdef DEBUG 1341 LogRelFunc(("Name : %ls\n", pAccountInfo->pwszUserName)); 1342 LogRelFunc(("Domain: %ls\n", pAccountInfo->pwszDomain)); 1343 #endif 1344 1345 if (RT_FAILURE(rc)) 1346 LogRelFunc(("Parsing \"%ls\" failed with rc=%Rrc\n", pwszString, rc)); 1347 return rc; 1348 } 1349 1350 1351 static void rtProcWinFreeAccountInfo(PRTPROCWINACCOUNTINFO pAccountInfo) 1352 { 1353 if (!pAccountInfo) 1354 return; 1355 1356 if (pAccountInfo->pwszUserName) 1357 { 1358 RTUtf16Free(pAccountInfo->pwszUserName); 1359 pAccountInfo->pwszUserName = NULL; 1360 } 1361 1362 if (pAccountInfo->pwszDomain) 1363 { 1364 RTUtf16Free(pAccountInfo->pwszDomain); 1365 pAccountInfo->pwszDomain = NULL; 1366 } 1367 } 1368 1369 1370 /** 1272 1371 * Method \#2. 1273 1372 */ … … 1320 1419 if (fFlags & RTPROC_FLAGS_SERVICE) 1321 1420 { 1421 PSID pSid = NULL; 1422 1322 1423 /* Try query the SID and domain sizes first. */ 1323 DWORD 1324 DWORD 1325 SID_NAME_USE 1424 DWORD cbSid = 0; /* Must be zero to query size! */ 1425 DWORD cwcDomain = 0; 1426 SID_NAME_USE SidNameUse = SidTypeUser; 1326 1427 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) 1428 if (!fRc) 1429 { 1430 dwErr = GetLastError(); 1431 1432 /* 1433 * The errors ERROR_TRUSTED_DOMAIN_FAILURE and ERROR_TRUSTED_RELATIONSHIP_FAILURE 1434 * can happen if an ADC (Active Domain Controller) is offline or not reachable. 1435 * 1436 * Try to handle these errors gracefully by asking the local LSA cache of the 1437 * client OS instead then. For this to work, the desired user must have at 1438 * least logged in once at that client -- otherwise there will be no cached 1439 * authentication available and this fallback will fail. 1440 */ 1441 if ( dwErr == ERROR_TRUSTED_DOMAIN_FAILURE 1442 || dwErr == ERROR_TRUSTED_RELATIONSHIP_FAILURE) 1336 1443 { 1337 /* Note: Just pass in the UPN (User Principal Name), e.g. [email protected] */ 1338 if (LookupAccountNameW(NULL /*lpSystemName*/, pwszUser, pSid, &cbSid, pwszDomain, &cwcDomain, &SidNameUse)) 1444 LSA_OBJECT_ATTRIBUTES objAttr; 1445 RT_ZERO(objAttr); 1446 objAttr.Length = sizeof(LSA_OBJECT_ATTRIBUTES); 1447 1448 LSA_HANDLE lsahPolicy; 1449 NTSTATUS ntSts = LsaOpenPolicy(NULL, &objAttr, POLICY_LOOKUP_NAMES, &lsahPolicy); 1450 if (ntSts == STATUS_SUCCESS) 1339 1451 { 1340 if (IsValidSid(pSid)) 1452 RTPROCWINACCOUNTINFO accountInfo; 1453 RT_ZERO(accountInfo); 1454 rc = rtProcWinParseAccountInfo(pwszUser, &accountInfo); 1455 AssertRC(rc); 1456 AssertPtr(accountInfo.pwszUserName); 1457 1458 LSA_UNICODE_STRING lsaUser; 1459 lsaUser.Buffer = accountInfo.pwszUserName; 1460 lsaUser.Length = RTUtf16Len(accountInfo.pwszUserName) * sizeof(WCHAR); 1461 lsaUser.MaximumLength = lsaUser.Length; 1462 1463 PLSA_REFERENCED_DOMAIN_LIST pDomainList = NULL; 1464 PLSA_TRANSLATED_SID2 pTranslatedSids = NULL; 1465 ntSts = LsaLookupNames2(lsahPolicy, 0 /* Flags */, 1466 1 /* Number of users to lookup */, &lsaUser, &pDomainList, &pTranslatedSids); 1467 if (ntSts == STATUS_SUCCESS) 1341 1468 { 1342 /* Array of process names we want to look for. */ 1343 static const char * const s_papszProcNames[] = 1469 AssertPtr(pDomainList); 1470 AssertPtr(pTranslatedSids); 1471 LogRelFunc(("LsaLookupNames2: cDomains=%u, DomainIndex=%ld, SidUse=%ld\n", 1472 pDomainList->Entries, pTranslatedSids[0].DomainIndex, pTranslatedSids[0].Use)); 1473 Assert(pTranslatedSids[0].Use == SidTypeUser); 1474 1475 if (pDomainList->Entries) 1344 1476 { 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); 1477 AssertPtr(pDomainList->Domains); 1478 LogRelFunc(("LsaLookupNames2: Domain=%ls\n", 1479 pDomainList->Domains[pTranslatedSids[0].DomainIndex].Name.Buffer)); 1480 } 1481 1482 cbSid = GetLengthSid(pTranslatedSids->Sid) + 16; 1483 Assert(cbSid); 1484 pSid = (PSID)RTMemAllocZ(cbSid); 1485 if (!CopySid(cbSid, pSid, pTranslatedSids->Sid)) 1486 { 1487 dwErr = GetLastError(); 1488 LogRelFunc(("CopySid failed with: %ld\n", dwErr)); 1489 rc = dwErr != NO_ERROR ? RTErrConvertFromWin32(dwErr) : VERR_INTERNAL_ERROR_2; 1490 } 1352 1491 } 1353 1492 else 1354 1493 { 1355 dwErr = GetLastError(); 1356 rc = dwErr != NO_ERROR ? RTErrConvertFromWin32(dwErr) : VERR_INTERNAL_ERROR_4; 1494 dwErr = LsaNtStatusToWinError(ntSts); 1495 LogRelFunc(("LsaLookupNames2 failed with: %ld\n", dwErr)); 1496 rc = dwErr != NO_ERROR ? RTErrConvertFromWin32(dwErr) : VERR_INTERNAL_ERROR_2; 1357 1497 } 1498 1499 if (pDomainList) 1500 { 1501 LsaFreeMemory(pDomainList); 1502 pDomainList = NULL; 1503 } 1504 if (pTranslatedSids) 1505 { 1506 LsaFreeMemory(pTranslatedSids); 1507 pTranslatedSids = NULL; 1508 } 1509 #ifndef DEBUG 1510 # error "FOOOO!!!" 1511 #endif 1512 rtProcWinFreeAccountInfo(&accountInfo); 1513 LsaClose(lsahPolicy); 1358 1514 } 1359 1515 else 1360 1516 { 1361 dwErr = GetLastError(); 1517 dwErr = LsaNtStatusToWinError(ntSts); 1518 LogRelFunc(("LsaOpenPolicy failed with: %ld\n", dwErr)); 1362 1519 rc = dwErr != NO_ERROR ? RTErrConvertFromWin32(dwErr) : VERR_INTERNAL_ERROR_3; 1363 1520 } 1364 RTMemFree(pwszDomain); 1521 1522 /* Note: pSid will be free'd down below. */ 1523 } 1524 else if (dwErr == ERROR_INSUFFICIENT_BUFFER) 1525 { 1526 /* Allocate memory for the LookupAccountNameW output buffers and do it for real. */ 1527 cbSid = fRc && cbSid != 0 ? cbSid + 16 : _1K; 1528 pSid = (PSID)RTMemAllocZ(cbSid); 1529 if (pSid) 1530 { 1531 cwcDomain = fRc ? cwcDomain + 2 : _4K; 1532 PRTUTF16 pwszDomain = (PRTUTF16)RTMemAllocZ(cwcDomain * sizeof(RTUTF16)); 1533 if (pwszDomain) 1534 { 1535 /* Note: Just pass in the UPN (User Principal Name), e.g. [email protected] */ 1536 if (!LookupAccountNameW(NULL /*lpSystemName*/, pwszUser, pSid, &cbSid, pwszDomain, &cwcDomain, 1537 &SidNameUse)) 1538 { 1539 dwErr = GetLastError(); 1540 LogRelFunc(("LookupAccountNameW(2) failed with: %ld\n", dwErr)); 1541 rc = dwErr != NO_ERROR ? RTErrConvertFromWin32(dwErr) : VERR_INTERNAL_ERROR_4; 1542 } 1543 1544 RTMemFree(pwszDomain); 1545 } 1546 else 1547 rc = VERR_NO_MEMORY; 1548 1549 /* Note: pSid will be free'd down below. */ 1550 } 1551 else 1552 rc = VERR_NO_MEMORY; 1365 1553 } 1366 1554 else 1367 rc = VERR_NO_MEMORY; 1555 { 1556 LogRelFunc(("LookupAccountNameW(1) failed with: %ld\n", dwErr)); 1557 rc = dwErr != NO_ERROR ? RTErrConvertFromWin32(dwErr) : VERR_INTERNAL_ERROR_2; 1558 } 1559 } 1560 1561 if (pSid) 1562 { 1563 if (IsValidSid(pSid)) 1564 { 1565 /* Array of process names we want to look for. */ 1566 static const char * const s_papszProcNames[] = 1567 { 1568 #ifdef VBOX /* The explorer entry is a fallback in case GA aren't installed. */ 1569 { "VBoxTray.exe" }, 1570 #endif 1571 { "explorer.exe" }, 1572 NULL 1573 }; 1574 fFound = rtProcWinFindTokenByProcess(s_papszProcNames, pSid, &hTokenUserDesktop); 1575 dwErr = 0; 1576 } 1577 else 1578 { 1579 dwErr = GetLastError(); 1580 LogRelFunc(("SID is invalid: %ld\n", dwErr)); 1581 rc = dwErr != NO_ERROR ? RTErrConvertFromWin32(dwErr) : VERR_INTERNAL_ERROR_3; 1582 } 1368 1583 1369 1584 RTMemFree(pSid); 1370 1585 } 1371 else1372 rc = VERR_NO_MEMORY;1373 1586 } 1374 1587 /* else: !RTPROC_FLAGS_SERVICE: Nothing to do here right now. */ … … 1505 1718 LogRelFunc(("dwErr=%u (%#x), rc=%Rrc\n", dwErr, dwErr, rc)); 1506 1719 } 1720 1721 LogRelFunc(("dwErr=%u (%#x), rc=%Rrc\n", dwErr, dwErr, rc)); 1507 1722 return rc; 1508 1723 }
Note:
See TracChangeset
for help on using the changeset viewer.