Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

727 lines
24 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. /* File: ntds.cpp
  3. Description: Contains definition for class NTDS.
  4. This class provides a simple wrapper around NT Directory Service
  5. name translation features. Currently, the Win32 functions to perform
  6. DS-sensitive name-to-SID translations are not present. These functions
  7. provide the same functionality.
  8. Revision History:
  9. Date Description Programmer
  10. -------- --------------------------------------------------- ----------
  11. 06/01/97 Initial creation. BrianAu
  12. 03/20/98 Reworked to use TranslateName rather than a combo BrianAu
  13. of DsBind and DsCrackNames. This ensures we're
  14. getting the proper info from the DS. It's slower
  15. because we have to re-bind to the DS for each call
  16. but I'd rather do that than bind incorrectly and
  17. not get the proper name information.
  18. */
  19. ///////////////////////////////////////////////////////////////////////////////
  20. #include "pch.h"
  21. #pragma hdrstop
  22. #include <lm.h> // For NetUserGetInfo and NetGetDCName.
  23. #include "ntds.h"
  24. //
  25. // REARCHITECT: These DS_NAME_FORMAT codes (ntdsapi.h> are not yet in the
  26. // corresponding EXTENDED_NAME_FORMAT enumeration in sspi.h.
  27. // Since TranslateName passes these codes on directly to DsCrackNames
  28. // I've defined these here so I can get the latest behavior until
  29. // Richard Ward updates TranslateNames and sspi.h.
  30. // Once he's updated that header, you can delete these three consts
  31. // and remove the "SSPI_" prefix from where they're used in the
  32. // code. [brianau - 3/19/98]
  33. //
  34. #define SSPI_NameUserPrincipal ((EXTENDED_NAME_FORMAT)8)
  35. #define SSPI_NameCanonicalEx ((EXTENDED_NAME_FORMAT)9)
  36. #define SSPI_NameServicePrincipal ((EXTENDED_NAME_FORMAT)10)
  37. //
  38. // Given an account name, find the account's SID and optionally the
  39. // account's container and display names.
  40. // The logon name may be either a DS "user principal" name or an
  41. // NT4-style SAM-compatible name.
  42. //
  43. // DS UPN = "[email protected]"
  44. // SAM compatible = "REDMOND\brianau"
  45. //
  46. HRESULT
  47. NTDS::LookupAccountByName(
  48. LPCTSTR pszSystem, // IN - optional. Can be NULL.
  49. LPCTSTR pszLogonName, // IN - "REDMOND\brianau" or "[email protected]"
  50. CString *pstrContainerName, // OUT - optional.
  51. CString *pstrDisplayName, // OUT - optional. Can be NULL.
  52. PSID pSid, // OUT
  53. LPDWORD pdwSid, // IN/OUT
  54. PSID_NAME_USE peUse // OUT
  55. )
  56. {
  57. DBGTRACE((DM_NTDS, DL_HIGH, TEXT("NTDS::LookupAccountByName")));
  58. DBGASSERT((NULL != pszLogonName));
  59. DBGASSERT((NULL != pSid));
  60. DBGASSERT((NULL != pdwSid));
  61. DBGASSERT((NULL != peUse));
  62. DBGPRINT((DM_NTDS, DL_HIGH, TEXT("Lookup \"%s\""), pszLogonName));
  63. HRESULT hr = NOERROR;
  64. //
  65. // Assume the presence of a '@' character means it's a UPN.
  66. //
  67. if (NULL != StrChr(pszLogonName, TEXT('@')))
  68. {
  69. hr = LookupDsAccountName(pszSystem,
  70. pszLogonName,
  71. pstrContainerName,
  72. pstrDisplayName,
  73. pSid,
  74. pdwSid,
  75. peUse);
  76. }
  77. else
  78. {
  79. hr = LookupSamAccountName(pszSystem,
  80. pszLogonName,
  81. pstrContainerName,
  82. pstrDisplayName,
  83. pSid,
  84. pdwSid,
  85. peUse);
  86. }
  87. return hr;
  88. }
  89. //
  90. // Given an account SID, optionally find the account's logon name,
  91. // container name and display name. If a DS UPN is available for the
  92. // user, the container name will be the canonical path to the user
  93. // object and the display name will come from the DS. If a
  94. // DS UPN is not available, or the account is an NT4 account,
  95. // the container returned is the NT4 domain name and the display name
  96. // is retrieved using NetUserGetInfo.
  97. //
  98. HRESULT
  99. NTDS::LookupAccountBySid(
  100. LPCTSTR pszSystem, // optional. Can be NULL.
  101. PSID pSid,
  102. CString *pstrContainerName, // optional. Can be NULL.
  103. CString *pstrLogonName, // optional. Can be NULL.
  104. CString *pstrDisplayName, // optional. Can be NULL.
  105. PSID_NAME_USE peUse
  106. )
  107. {
  108. DBGTRACE((DM_NTDS, DL_HIGH, TEXT("NTDS::LookupAccountBySid")));
  109. DBGASSERT((NULL != pSid));
  110. HRESULT hr = NOERROR;
  111. CString strSamUser;
  112. CString strSamDomain;
  113. CString strSamLogonName;
  114. //
  115. // Get the SAM-compatible domain\user name for the SID.
  116. //
  117. DBGPRINT((DM_NTDS, DL_LOW, TEXT("Calling ::LookupAccountSid")));
  118. hr = LookupAccountSidInternal(pszSystem,
  119. pSid,
  120. &strSamUser,
  121. &strSamDomain,
  122. peUse);
  123. if (FAILED(hr))
  124. return hr;
  125. //
  126. // No need to go further if caller doesn't want any name information in which
  127. // case all they're getting in return is an indication if the SID is for a known
  128. // account or not.
  129. //
  130. if (NULL != pstrLogonName || NULL != pstrContainerName || NULL != pstrDisplayName)
  131. {
  132. CString strFQDN;
  133. bool bUseSamCompatibleInfo = false;
  134. CreateSamLogonName(strSamDomain, strSamUser, &strSamLogonName);
  135. //
  136. // Start by getting the FQDN. Cracking is most efficient when the
  137. // FQDN is the starting point.
  138. //
  139. if (FAILED(TranslateNameInternal(strSamLogonName,
  140. NameSamCompatible,
  141. NameFullyQualifiedDN,
  142. &strFQDN)))
  143. {
  144. //
  145. // No FQDN available for this account. Must be an NT4
  146. // account. Return SAM-compatible info to the caller.
  147. //
  148. bUseSamCompatibleInfo = true;
  149. }
  150. if (NULL != pstrLogonName)
  151. {
  152. if (bUseSamCompatibleInfo)
  153. {
  154. *pstrLogonName = strSamLogonName;
  155. }
  156. else
  157. {
  158. //
  159. // Get the DS user principal name
  160. //
  161. pstrLogonName->Empty();
  162. if (FAILED(TranslateNameInternal(strFQDN,
  163. NameFullyQualifiedDN,
  164. SSPI_NameUserPrincipal,
  165. pstrLogonName)))
  166. {
  167. //
  168. // No UPN for this account.
  169. // Default to returning SAM-compatible info.
  170. //
  171. bUseSamCompatibleInfo = true;
  172. *pstrLogonName = strSamLogonName;
  173. }
  174. }
  175. }
  176. if (NULL != pstrContainerName)
  177. {
  178. if (bUseSamCompatibleInfo)
  179. {
  180. *pstrContainerName = strSamDomain;
  181. }
  182. else
  183. {
  184. pstrContainerName->Empty();
  185. if (SUCCEEDED(TranslateNameInternal(strFQDN,
  186. NameFullyQualifiedDN,
  187. NameCanonical,
  188. pstrContainerName)))
  189. {
  190. //
  191. // Trim off the trailing account name from the canonical path
  192. // so we're left with only the container name.
  193. //
  194. int iLastBS = pstrContainerName->Last(TEXT('/'));
  195. if (-1 != iLastBS)
  196. {
  197. *pstrContainerName = pstrContainerName->SubString(0, iLastBS);
  198. }
  199. }
  200. }
  201. }
  202. if (NULL != pstrDisplayName)
  203. {
  204. if (bUseSamCompatibleInfo || FAILED(GetDsAccountDisplayName(strFQDN, pstrDisplayName)))
  205. {
  206. GetSamAccountDisplayName(strSamLogonName, pstrDisplayName);
  207. }
  208. }
  209. }
  210. return hr;
  211. }
  212. //
  213. // Input is a SAM-compatible account name.
  214. // Retrieve the name information using the NT4-style methods.
  215. //
  216. HRESULT
  217. NTDS::LookupSamAccountName(
  218. LPCTSTR pszSystem,
  219. LPCTSTR pszLogonName, // IN - "REDMOND\brianau"
  220. CString *pstrContainerName, // OUT - optional.
  221. CString *pstrDisplayName, // OUT - optional. Can be NULL.
  222. PSID pSid, // OUT
  223. LPDWORD pdwSid, // IN/OUT
  224. PSID_NAME_USE peUse // OUT
  225. )
  226. {
  227. DBGTRACE((DM_NTDS, DL_MID, TEXT("NTDS::LookupSamAccountName")));
  228. DBGASSERT((NULL != pszLogonName));
  229. DBGASSERT((NULL != pdwSid));
  230. DBGASSERT((NULL != pSid));
  231. DBGASSERT((NULL != peUse));
  232. //
  233. // Get the SID using the SAM-compatible account name.
  234. //
  235. HRESULT hr = NOERROR;
  236. CString strDomain;
  237. hr = LookupAccountNameInternal(pszSystem,
  238. pszLogonName,
  239. pSid,
  240. pdwSid,
  241. &strDomain,
  242. peUse);
  243. if (SUCCEEDED(hr))
  244. {
  245. if (NULL != pstrContainerName)
  246. *pstrContainerName = strDomain;
  247. if (NULL != pstrDisplayName)
  248. GetSamAccountDisplayName(pszLogonName, pstrDisplayName);
  249. }
  250. return hr;
  251. }
  252. //
  253. // Returns:
  254. // S_OK = All information retrieved.
  255. // S_FALSE = Container name returned is for SAM-compatible account.
  256. // DS container information was not available.
  257. HRESULT
  258. NTDS::LookupDsAccountName(
  259. LPCTSTR pszSystem,
  260. LPCTSTR pszLogonName, // IN - "[email protected]"
  261. CString *pstrContainerName, // OUT - optional.
  262. CString *pstrDisplayName, // OUT - optional. Can be NULL.
  263. PSID pSid, // OUT
  264. LPDWORD pdwSid, // IN/OUT
  265. PSID_NAME_USE peUse // OUT
  266. )
  267. {
  268. DBGTRACE((DM_NTDS, DL_MID, TEXT("NTDS::LookupDsAccountName")));
  269. DBGASSERT((NULL != pszLogonName));
  270. DBGASSERT((NULL != pSid));
  271. DBGASSERT((NULL != pdwSid));
  272. DBGASSERT((NULL != peUse));
  273. //
  274. // Get the SID using the SAM-compatible account name.
  275. //
  276. HRESULT hr = S_OK;
  277. //
  278. // Translate the DS user principal name to FQDN format.
  279. // Starting with FQDN is the most efficient for name cracking so
  280. // we get it once and use it multiple times.
  281. //
  282. CString strFQDN;
  283. hr = TranslateNameInternal(pszLogonName,
  284. SSPI_NameUserPrincipal,
  285. NameFullyQualifiedDN,
  286. &strFQDN);
  287. if (FAILED(hr))
  288. return hr;
  289. CString strSamLogonName;
  290. hr = TranslateNameInternal(strFQDN,
  291. NameFullyQualifiedDN,
  292. NameSamCompatible,
  293. &strSamLogonName);
  294. if (FAILED(hr))
  295. return hr;
  296. CString strDomain;
  297. hr = LookupAccountNameInternal(pszSystem,
  298. strSamLogonName,
  299. pSid,
  300. pdwSid,
  301. &strDomain,
  302. peUse);
  303. if (FAILED(hr))
  304. return hr;
  305. bool bUseSamCompatibleInfo = false;
  306. if (NULL != pstrContainerName)
  307. {
  308. //
  309. // Get the DS container name for the account.
  310. //
  311. hr = TranslateNameInternal(strFQDN,
  312. NameFullyQualifiedDN,
  313. NameCanonical,
  314. pstrContainerName);
  315. if (SUCCEEDED(hr))
  316. {
  317. //
  318. // Trim off the trailing account name from the canonical path
  319. // so we're left with only the container name.
  320. //
  321. int iLastBS = pstrContainerName->Last(TEXT('/'));
  322. if (-1 != iLastBS)
  323. {
  324. *pstrContainerName = pstrContainerName->SubString(0, iLastBS);
  325. }
  326. }
  327. else
  328. {
  329. DBGERROR((TEXT("Using SAM-compatible name info")));
  330. //
  331. // Can't get DS container name so use the SAM domain name.
  332. //
  333. *pstrContainerName = strDomain;
  334. bUseSamCompatibleInfo = true;
  335. hr = S_FALSE;
  336. }
  337. }
  338. if (NULL != pstrDisplayName)
  339. {
  340. if (bUseSamCompatibleInfo || FAILED(GetDsAccountDisplayName(strFQDN, pstrDisplayName)))
  341. GetSamAccountDisplayName(strSamLogonName, pstrDisplayName);
  342. }
  343. return hr;
  344. }
  345. HRESULT
  346. NTDS::GetSamAccountDisplayName(
  347. LPCTSTR pszLogonName,
  348. CString *pstrDisplayName
  349. )
  350. {
  351. DBGTRACE((DM_NTDS, DL_MID, TEXT("NTDS::GetSamAccountDisplayName")));
  352. DBGASSERT((NULL != pszLogonName));
  353. DBGASSERT((NULL != pstrDisplayName));
  354. DBGPRINT((DM_NTDS, DL_MID, TEXT("Translating \"%s\""), pszLogonName));
  355. HRESULT hr = E_FAIL;
  356. LPTSTR pszComputerName = NULL;
  357. NET_API_STATUS status = NERR_Success;
  358. CString strLogonName(pszLogonName);
  359. CString strDomain;
  360. CString strUser;
  361. //
  362. // Separate the domain\account string into two separate strings.
  363. //
  364. int iBackslash = strLogonName.Last(TEXT('\\'));
  365. if (-1 != iBackslash)
  366. {
  367. strDomain = strLogonName.SubString(0, iBackslash);
  368. if (iBackslash < (strLogonName.Length() - 1))
  369. strUser = strLogonName.SubString(iBackslash + 1);
  370. }
  371. pstrDisplayName->Empty();
  372. DBGPRINT((DM_NTDS, DL_LOW, TEXT("Calling ::NetGetDCName for domain \"%s\""), strDomain.Cstr()));
  373. status = ::NetGetDCName(NULL, strDomain, (LPBYTE *)&pszComputerName);
  374. if (NERR_Success == status || NERR_DCNotFound == status)
  375. {
  376. struct _USER_INFO_2 *pui = NULL;
  377. DBGPRINT((DM_NTDS, DL_LOW, TEXT("Calling ::NetGetUserInfo for \"%s\" on \"%s\""), strUser.Cstr(), pszComputerName));
  378. status = ::NetUserGetInfo(pszComputerName, strUser, 2, (LPBYTE *)&pui);
  379. if (NERR_Success == status)
  380. {
  381. *pstrDisplayName = pui->usri2_full_name;
  382. DBGPRINT((DM_NTDS, DL_LOW, TEXT("Translated to \"%s\""), pstrDisplayName->Cstr()));
  383. NetApiBufferFree(pui);
  384. hr = NOERROR;
  385. }
  386. else
  387. {
  388. DBGERROR((TEXT("NetUserGetInfo failed with error 0x%08X for \"%s\" on \"%s\""),
  389. status, strUser.Cstr(), pszComputerName ? pszComputerName : TEXT("local machine")));
  390. hr = HRESULT_FROM_WIN32(status);
  391. }
  392. if (NULL != pszComputerName)
  393. NetApiBufferFree(pszComputerName);
  394. }
  395. else
  396. {
  397. DBGERROR((TEXT("NetGetDCName failed with error 0x%08X for domain \"%s\""),
  398. status, strDomain.Cstr()));
  399. hr = HRESULT_FROM_WIN32(status);
  400. }
  401. return hr;
  402. }
  403. HRESULT
  404. NTDS::GetDsAccountDisplayName(
  405. LPCTSTR pszFQDN,
  406. CString *pstrDisplayName
  407. )
  408. {
  409. DBGTRACE((DM_NTDS, DL_MID, TEXT("NTDS::GetDsAccountDisplayName")));
  410. DBGASSERT((NULL != pszFQDN));
  411. DBGASSERT((NULL != pstrDisplayName));
  412. //
  413. // Get the DS container name for the account.
  414. //
  415. pstrDisplayName->Empty();
  416. return TranslateNameInternal(pszFQDN,
  417. NameFullyQualifiedDN,
  418. NameDisplay,
  419. pstrDisplayName);
  420. }
  421. void
  422. NTDS::CreateSamLogonName(
  423. LPCTSTR pszSamDomain,
  424. LPCTSTR pszSamUser,
  425. CString *pstrSamLogonName
  426. )
  427. {
  428. DBGTRACE((DM_NTDS, DL_LOW, TEXT("NTDS::CreateSamLogonName")));
  429. DBGASSERT((NULL != pszSamDomain));
  430. DBGASSERT((NULL != pszSamUser));
  431. DBGASSERT((NULL != pstrSamLogonName));
  432. DBGPRINT((DM_NTDS, DL_LOW, TEXT("\tDomain.: \"%s\""), pszSamDomain));
  433. DBGPRINT((DM_NTDS, DL_LOW, TEXT("\tUser...: \"%s\""), pszSamUser));
  434. pstrSamLogonName->Format(TEXT("%1\\%2"), pszSamDomain, pszSamUser);
  435. DBGPRINT((DM_NTDS, DL_LOW, TEXT("\tAccount: \"%s\""), pstrSamLogonName->Cstr()));
  436. }
  437. HRESULT
  438. NTDS::TranslateFQDNsToLogonNames(
  439. const CArray<CString>& rgstrFQDNs,
  440. CArray<CString> *prgstrLogonNames
  441. )
  442. {
  443. HRESULT hr = NOERROR;
  444. prgstrLogonNames->Clear();
  445. int cItems = rgstrFQDNs.Count();
  446. CString strLogonName;
  447. for (int i = 0; i < cItems; i++)
  448. {
  449. if (FAILED(TranslateFQDNToLogonName(rgstrFQDNs[i], &strLogonName)))
  450. strLogonName.Empty();
  451. prgstrLogonNames->Append(strLogonName);
  452. }
  453. return hr;
  454. }
  455. HRESULT
  456. NTDS::TranslateFQDNToLogonName(
  457. LPCTSTR pszFQDN,
  458. CString *pstrLogonName
  459. )
  460. {
  461. DBGTRACE((DM_NTDS, DL_MID, TEXT("NTDS::TranslateFQDNToLogonName")));
  462. DBGASSERT((NULL != pszFQDN));
  463. DBGASSERT((NULL != pstrLogonName));
  464. HRESULT hr = NOERROR;
  465. hr = TranslateNameInternal(pszFQDN,
  466. NameFullyQualifiedDN,
  467. SSPI_NameUserPrincipal,
  468. pstrLogonName);
  469. if (FAILED(hr))
  470. {
  471. hr = TranslateNameInternal(pszFQDN,
  472. NameFullyQualifiedDN,
  473. NameSamCompatible,
  474. pstrLogonName);
  475. }
  476. return hr;
  477. }
  478. LPCTSTR
  479. NTDS::FindFQDNInADsPath(
  480. LPCTSTR pszADsPath
  481. )
  482. {
  483. DBGTRACE((DM_NTDS, DL_MID, TEXT("NTDS::FindFQDNInADsPath")));
  484. DBGASSERT((NULL != pszADsPath));
  485. DBGPRINT((DM_NTDS, DL_MID, TEXT("Checking \"%s\""), pszADsPath));
  486. const TCHAR szCN[] = TEXT("CN=");
  487. while(*pszADsPath && CSTR_EQUAL != CompareString(LOCALE_USER_DEFAULT,
  488. 0,
  489. pszADsPath,
  490. ARRAYSIZE(szCN) - 1,
  491. szCN,
  492. ARRAYSIZE(szCN) - 1))
  493. {
  494. pszADsPath = CharNext(pszADsPath);
  495. }
  496. DBGPRINT((DM_NTDS, DL_MID, TEXT("Found \"%s\""), pszADsPath ? pszADsPath : TEXT("<null>")));
  497. return (*pszADsPath ? pszADsPath : NULL);
  498. }
  499. LPCTSTR
  500. NTDS::FindSamAccountInADsPath(
  501. LPCTSTR pszADsPath
  502. )
  503. {
  504. DBGTRACE((DM_NTDS, DL_MID, TEXT("NTDS::FindSamAccountInADsPath")));
  505. DBGASSERT((NULL != pszADsPath));
  506. DBGPRINT((DM_NTDS, DL_MID, TEXT("Checking \"%s\""), pszADsPath));
  507. const TCHAR szPrefix[] = TEXT("WinNT://");
  508. if (0 == StrCmpN(pszADsPath, szPrefix, ARRAYSIZE(szPrefix)-1))
  509. {
  510. pszADsPath += (ARRAYSIZE(szPrefix) - 1);
  511. DBGPRINT((DM_NTDS, DL_MID, TEXT("Found \"%s\""), pszADsPath));
  512. }
  513. else
  514. {
  515. pszADsPath = NULL;
  516. }
  517. return pszADsPath;
  518. }
  519. //
  520. // Wrapper around sspi's TranslateName that automatically handles
  521. // the buffer sizing using a CString object.
  522. //
  523. HRESULT
  524. NTDS::TranslateNameInternal(
  525. LPCTSTR pszAccountName,
  526. EXTENDED_NAME_FORMAT AccountNameFormat,
  527. EXTENDED_NAME_FORMAT DesiredNameFormat,
  528. CString *pstrTranslatedName
  529. )
  530. {
  531. #if DBG
  532. //
  533. // These match up with the EXTENDED_NAME_FORMAT enumeration.
  534. // They're for debugger output only.
  535. //
  536. static const LPCTSTR rgpszFmt[] = {
  537. TEXT("NameUnknown"),
  538. TEXT("FullyQualifiedDN"),
  539. TEXT("NameSamCompatible"),
  540. TEXT("NameDisplay"),
  541. TEXT("NameDomainSimple"),
  542. TEXT("NameEnterpriseSimple"),
  543. TEXT("NameUniqueId"),
  544. TEXT("NameCanonical"),
  545. TEXT("NameUserPrincipal"),
  546. TEXT("NameCanonicalEx"),
  547. TEXT("NameServicePrincipal") };
  548. #endif // DBG
  549. DBGPRINT((DM_NTDS, DL_LOW, TEXT("Calling TranslateName for \"%s\""), pszAccountName));
  550. DBGPRINT((DM_NTDS, DL_LOW, TEXT("Translating %s -> %s"),
  551. rgpszFmt[AccountNameFormat], rgpszFmt[DesiredNameFormat]));
  552. HRESULT hr = NOERROR;
  553. //
  554. // WARNING: TranslateName doesn't properly set the required buffer size
  555. // in cchTrans if the buffer size is too small. I've notified
  556. // Richard B. Ward about it. Says he'll have the fix in
  557. // on 3/24/98. Should test with an initial value of 1
  558. // just to make sure he fixed it. [brianau - 03/20/98]
  559. //
  560. ULONG cchTrans = MAX_PATH;
  561. while(!::TranslateName(pszAccountName,
  562. AccountNameFormat,
  563. DesiredNameFormat,
  564. pstrTranslatedName->GetBuffer(cchTrans),
  565. &cchTrans))
  566. {
  567. DWORD dwErr = GetLastError();
  568. if (ERROR_INSUFFICIENT_BUFFER != dwErr)
  569. {
  570. DBGERROR((TEXT("::TranslateName failed with error %d"), dwErr));
  571. hr = HRESULT_FROM_WIN32(dwErr);
  572. break;
  573. }
  574. DBGPRINT((DM_NTDS, DL_LOW, TEXT("Resizing buffer to %d chars"), cchTrans));
  575. }
  576. pstrTranslatedName->ReleaseBuffer();
  577. return hr;
  578. }
  579. //
  580. // Wrapper around Win32's LookupAccountName that automatically handles
  581. // the domain buffer sizing using a CString object.
  582. //
  583. HRESULT
  584. NTDS::LookupAccountNameInternal(
  585. LPCTSTR pszSystemName,
  586. LPCTSTR pszAccountName,
  587. PSID pSid,
  588. LPDWORD pcbSid,
  589. CString *pstrReferencedDomainName,
  590. PSID_NAME_USE peUse
  591. )
  592. {
  593. DBGPRINT((DM_NTDS, DL_MID, TEXT("Calling ::LookupAccountName for \"%s\" on \"%s\""),
  594. pszAccountName, pszSystemName ? pszSystemName : TEXT("<local system>")));
  595. HRESULT hr = NOERROR;
  596. ULONG cchDomain = MAX_PATH;
  597. while(!::LookupAccountName(pszSystemName,
  598. pszAccountName,
  599. pSid,
  600. pcbSid,
  601. pstrReferencedDomainName->GetBuffer(cchDomain),
  602. &cchDomain,
  603. peUse))
  604. {
  605. DWORD dwErr = GetLastError();
  606. if (ERROR_INSUFFICIENT_BUFFER != dwErr)
  607. {
  608. DBGERROR((TEXT("::LookupAccountName failed with error %d"), dwErr));
  609. hr = HRESULT_FROM_WIN32(dwErr);
  610. break;
  611. }
  612. DBGPRINT((DM_NTDS, DL_LOW, TEXT("Resizing domain buffer to %d chars"), cchDomain));
  613. }
  614. pstrReferencedDomainName->ReleaseBuffer();
  615. return hr;
  616. }
  617. //
  618. // Wrapper around Win32's LookupAccountSid that automatically handles
  619. // the domain buffer sizing using a CString object.
  620. //
  621. HRESULT
  622. NTDS::LookupAccountSidInternal(
  623. LPCTSTR pszSystemName,
  624. PSID pSid,
  625. CString *pstrName,
  626. CString *pstrReferencedDomainName,
  627. PSID_NAME_USE peUse
  628. )
  629. {
  630. HRESULT hr = NOERROR;
  631. ULONG cchName = MAX_PATH;
  632. ULONG cchDomain = MAX_PATH;
  633. while(!::LookupAccountSid(pszSystemName,
  634. pSid,
  635. pstrName->GetBuffer(cchName),
  636. &cchName,
  637. pstrReferencedDomainName->GetBuffer(cchDomain),
  638. &cchDomain,
  639. peUse))
  640. {
  641. DWORD dwErr = GetLastError();
  642. if (ERROR_INSUFFICIENT_BUFFER != dwErr)
  643. {
  644. DBGERROR((TEXT("::LookupAccountSid failed with error %d"), dwErr));
  645. hr = HRESULT_FROM_WIN32(dwErr);
  646. break;
  647. }
  648. DBGPRINT((DM_NTDS, DL_LOW, TEXT("Resizing domain or name buffer")));
  649. }
  650. pstrName->ReleaseBuffer();
  651. pstrReferencedDomainName->ReleaseBuffer();
  652. return hr;
  653. }