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