Source code of Windows XP (NT5)
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.

723 lines
21 KiB

  1. #include "stdafx.h"
  2. #include "MsPwdMig.h"
  3. #include "PasswordMigration.h"
  4. #include <NtSecApi.h>
  5. #include <io.h>
  6. #include <winioctl.h>
  7. #include <lm.h>
  8. #include <eh.h>
  9. #include <ActiveDS.h>
  10. #include <Dsrole.h>
  11. #include "TReg.hpp"
  12. #include "pwdfuncs.h"
  13. #include "PWGen.hpp"
  14. #include "UString.hpp"
  15. #include "PwRpcUtl.h"
  16. #include "PwdSvc.h"
  17. #include "PwdSvc_c.c"
  18. #include "Error.h"
  19. #pragma comment(lib, "netapi32.lib")
  20. #pragma comment(lib, "adsiid.lib")
  21. #pragma comment(lib, "activeds.lib")
  22. #pragma comment(lib, "commonlib.lib")
  23. namespace
  24. {
  25. #define GET_BYTE_ARRAY_DATA(v) ((char*)((v).parray->pvData))
  26. #define GET_BYTE_ARRAY_SIZE(v) ((unsigned long)((v).parray->rgsabound[0].cElements))
  27. struct SSeException
  28. {
  29. SSeException(UINT uCode) :
  30. uCode(uCode)
  31. {
  32. }
  33. UINT uCode;
  34. };
  35. void SeTranslator(unsigned int u, EXCEPTION_POINTERS* pepExceptions)
  36. {
  37. throw SSeException(u);
  38. }
  39. }
  40. // namespace
  41. //---------------------------------------------------------------------------
  42. // CPasswordMigration
  43. //---------------------------------------------------------------------------
  44. // Constructor
  45. CPasswordMigration::CPasswordMigration() :
  46. m_bSessionEstablished(false)
  47. {
  48. }
  49. // Destructor
  50. CPasswordMigration::~CPasswordMigration()
  51. {
  52. }
  53. //
  54. // IPasswordMigration Implementation ----------------------------------------
  55. //
  56. // EstablishSession Method
  57. STDMETHODIMP CPasswordMigration::EstablishSession(BSTR bstrSourceServer, BSTR bstrTargetServer)
  58. {
  59. HRESULT hr = S_OK;
  60. USES_CONVERSION;
  61. try
  62. {
  63. m_bSessionEstablished = false;
  64. CheckPasswordDC(OLE2CW(bstrSourceServer), OLE2CW(bstrTargetServer));
  65. m_bSessionEstablished = true;
  66. }
  67. catch (_com_error& ce)
  68. {
  69. hr = SetError(ce, IDS_E_CANNOT_ESTABLISH_SESSION);
  70. }
  71. return hr;
  72. }
  73. // CopyPassword Method
  74. STDMETHODIMP CPasswordMigration::CopyPassword(BSTR bstrSourceAccount, BSTR bstrTargetAccount, BSTR bstrTargetPassword)
  75. {
  76. HRESULT hr = S_OK;
  77. USES_CONVERSION;
  78. try
  79. {
  80. // if session established then...
  81. if (m_bSessionEstablished)
  82. {
  83. // copy password
  84. CopyPasswordImpl(OLE2CT(bstrSourceAccount), OLE2CT(bstrTargetAccount), OLE2CT(bstrTargetPassword));
  85. }
  86. else
  87. {
  88. // else return error
  89. ThrowError(PM_E_SESSION_NOT_ESTABLISHED, IDS_E_SESSION_NOT_ESTABLISHED);
  90. }
  91. }
  92. catch (_com_error& ce)
  93. {
  94. hr = SetError(ce, IDS_E_CANNOT_COPY_PASSWORD);
  95. }
  96. return hr;
  97. }
  98. // GenerateKey Method
  99. STDMETHODIMP CPasswordMigration::GenerateKey(BSTR bstrSourceDomainFlatName, BSTR bstrKeyFilePath, BSTR bstrPassword)
  100. {
  101. HRESULT hr = S_OK;
  102. USES_CONVERSION;
  103. try
  104. {
  105. GenerateKeyImpl(OLE2CT(bstrSourceDomainFlatName), OLE2CT(bstrKeyFilePath), OLE2CT(bstrPassword));
  106. }
  107. catch (_com_error& ce)
  108. {
  109. hr = SetError(ce, IDS_E_CANNOT_GENERATE_KEY);
  110. }
  111. return hr;
  112. }
  113. //
  114. // Implementation -----------------------------------------------------------
  115. //
  116. // GenerateKeyImpl Method
  117. void CPasswordMigration::GenerateKeyImpl(LPCTSTR pszDomain, LPCTSTR pszFile, LPCTSTR pszPassword)
  118. {
  119. //
  120. // validate source domain name
  121. //
  122. if ((pszDomain == NULL) || (pszDomain[0] == NULL))
  123. {
  124. ThrowError(E_INVALIDARG, IDS_E_KEY_DOMAIN_NOT_SPECIFIED);
  125. }
  126. //
  127. // validate key file path
  128. //
  129. if ((pszFile == NULL) || (pszFile[0] == NULL))
  130. {
  131. ThrowError(E_INVALIDARG, IDS_E_KEY_FILE_NOT_SPECIFIED);
  132. }
  133. _TCHAR szDrive[_MAX_DRIVE];
  134. _TCHAR szExt[_MAX_EXT];
  135. _tsplitpath(pszFile, szDrive, NULL, NULL, szExt);
  136. // verify drive is a local drive
  137. _TCHAR szDrivePath[_MAX_PATH];
  138. _tmakepath(szDrivePath, szDrive, _T("\\"), NULL, NULL);
  139. if (GetDriveType(szDrivePath) == DRIVE_REMOTE)
  140. {
  141. ThrowError(E_INVALIDARG, IDS_E_KEY_FILE_NOT_LOCAL_DRIVE, pszFile);
  142. }
  143. // verify file extension is correct
  144. if (_tcsicmp(szExt, _T(".pes")) != 0)
  145. {
  146. ThrowError(E_INVALIDARG, IDS_E_KEY_FILE_EXTENSION_INVALID, szExt);
  147. }
  148. //
  149. // create encryption key and write to specified file
  150. //
  151. // create encryption key
  152. CTargetCrypt crypt;
  153. _variant_t vntKey = crypt.CreateEncryptionKey(pszDomain, pszPassword);
  154. // write encrypted key bytes to file
  155. HANDLE hFile = CreateFile(pszFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  156. if (hFile == INVALID_HANDLE_VALUE)
  157. {
  158. ThrowError(HRESULT_FROM_WIN32(GetLastError()), IDS_E_KEY_CANT_CREATE_FILE, pszFile);
  159. }
  160. DWORD dwWritten;
  161. BOOL bWritten = WriteFile(hFile, vntKey.parray->pvData, vntKey.parray->rgsabound[0].cElements, &dwWritten, NULL);
  162. CloseHandle(hFile);
  163. if (!bWritten)
  164. {
  165. ThrowError(HRESULT_FROM_WIN32(GetLastError()), IDS_E_KEY_CANT_WRITE_FILE, pszFile);
  166. }
  167. }
  168. #pragma optimize ("", off)
  169. /*********************************************************************
  170. * *
  171. * Written by: Paul Thompson *
  172. * Date: 15 DEC 2000 *
  173. * *
  174. * This function is a wrapper around a password DC "CheckConfig" *
  175. * call that can be used by the GUI and scripting to test the given *
  176. * DC. *
  177. * First we connect to a remote Lsa notification package dll, *
  178. * which should be installed on a DC in the source domain. The *
  179. * connect will be encrypted RPC. The configuration check, which *
  180. * establishes a temporary session for this check. *
  181. * We will also check anonymous user right access on the target *
  182. * domain. *
  183. * *
  184. * 2001-04-19 Mark Oluper - updated for client component *
  185. *********************************************************************/
  186. //BEGIN CheckPasswordDC
  187. void CPasswordMigration::CheckPasswordDC(LPCWSTR srcServer, LPCWSTR tgtServer)
  188. {
  189. /* local constants */
  190. const DWORD c_dwMinUC = 3;
  191. const DWORD c_dwMinLC = 3;
  192. const DWORD c_dwMinDigits = 3;
  193. const DWORD c_dwMinSpecial = 3;
  194. const DWORD c_dwMaxAlpha = 0;
  195. const DWORD c_dwMinLen = 14;
  196. /* local variables */
  197. DWORD rc = 0;
  198. WCHAR * sBinding = NULL;
  199. HANDLE hBinding = NULL;
  200. WCHAR testPwd[PASSWORD_BUFFER_SIZE];
  201. WCHAR tempPwd[PASSWORD_BUFFER_SIZE];
  202. _variant_t varSession;
  203. _variant_t varTestPwd;
  204. /* function body */
  205. // USES_CONVERSION;
  206. if ((srcServer == NULL) || (srcServer[0] == NULL))
  207. {
  208. ThrowError(E_INVALIDARG, IDS_E_SOURCE_SERVER_NOT_SPECIFIED);
  209. }
  210. if ((tgtServer == NULL) || (tgtServer[0] == NULL))
  211. {
  212. ThrowError(E_INVALIDARG, IDS_E_TARGET_SERVER_NOT_SPECIFIED);
  213. }
  214. //make sure the server names start with "\\"
  215. if ((srcServer[0] != L'\\') && (srcServer[1] != L'\\'))
  216. {
  217. m_strSourceServer = L"\\\\";
  218. m_strSourceServer += srcServer;
  219. }
  220. else
  221. m_strSourceServer = srcServer;
  222. if ((tgtServer[0] != L'\\') && (tgtServer[1] != L'\\'))
  223. {
  224. m_strTargetServer = L"\\\\";
  225. m_strTargetServer += tgtServer;
  226. }
  227. else
  228. m_strTargetServer = tgtServer;
  229. //get the password DC's domain NETBIOS name
  230. GetDomainName(m_strSourceServer, m_strSourceDomainDNS, m_strSourceDomainFlat);
  231. //get the target DC's domain DNS name
  232. GetDomainName(m_strTargetServer, m_strTargetDomainDNS, m_strTargetDomainFlat);
  233. //check if "Everyone" has been added to the "Pre-Windows 2000 Compatible
  234. //Access" group
  235. if (!IsEveryoneInPW2KCAGroup(m_strTargetDomainDNS))
  236. ThrowError(__uuidof(PasswordMigration), __uuidof(IPasswordMigration), PM_E_EVERYONE_NOT_MEMBEROF_COMPATIBILITY_GROUP, IDS_E_EVERYONE_NOT_MEMBEROF_GROUP, (LPCTSTR)m_strTargetDomainDNS);
  237. //check if anonymous user has been granted "Everyone" access, if the target
  238. //DC is Whistler or newer
  239. if (!DoesAnonymousHaveEveryoneAccess(m_strTargetServer))
  240. ThrowError(__uuidof(PasswordMigration), __uuidof(IPasswordMigration), PM_E_EVERYONE_DOES_NOT_INCLUDE_ANONYMOUS, IDS_E_EVERYONE_DOES_NOT_INCLUDE_ANONYMOUS, (LPCTSTR)m_strTargetServer);
  241. //if the high encryption pack has not been installed on this target
  242. //DC, then return that information
  243. try
  244. {
  245. m_pTargetCrypt = std::auto_ptr<CTargetCrypt>(new CTargetCrypt);
  246. }
  247. catch (_com_error& ce)
  248. {
  249. if (ce.Error() == 0x80090019)
  250. ThrowError(__uuidof(PasswordMigration), __uuidof(IPasswordMigration), PM_E_HIGH_ENCRYPTION_NOT_INSTALLED, IDS_E_HIGH_ENCRYPTION_NOT_INSTALLED);
  251. else
  252. throw;
  253. }
  254. rc = PwdBindCreate(m_strSourceServer,&hBinding,&sBinding,TRUE);
  255. if(rc != ERROR_SUCCESS)
  256. {
  257. _com_issue_error(HRESULT_FROM_WIN32(rc));
  258. }
  259. try
  260. {
  261. try
  262. {
  263. //create a session key that will be used to encrypt the user's
  264. //password for this set of accounts
  265. varSession = m_pTargetCrypt->CreateSession(m_strSourceDomainFlat);
  266. }
  267. catch (_com_error& ce)
  268. {
  269. if (ce.Error() == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
  270. {
  271. ThrowError(__uuidof(PasswordMigration), __uuidof(IPasswordMigration), PM_E_NO_ENCRYPTION_KEY_FOR_DOMAIN, IDS_E_NO_ENCRYPTION_KEY_FOR_DOMAIN, (LPCTSTR)m_strTargetServer, (LPCTSTR)m_strSourceDomainFlat);
  272. }
  273. else
  274. {
  275. ThrowError(ce, IDS_E_GENERATE_SESSION_KEY_FAILED);
  276. }
  277. }
  278. //now create a complex password used by the "CheckConfig" call in
  279. //a challenge response. If the returned password matches, then
  280. //the source DC has the proper encryption key.
  281. if (EaPasswordGenerate(c_dwMinUC, c_dwMinLC, c_dwMinDigits, c_dwMinSpecial, c_dwMaxAlpha, c_dwMinLen, testPwd, PASSWORD_BUFFER_SIZE))
  282. {
  283. ThrowError(__uuidof(PasswordMigration), __uuidof(IPasswordMigration), PM_E_GENERATE_SESSION_PASSWORD_FAILED, IDS_E_GENERATE_SESSION_PASSWORD_FAILED);
  284. }
  285. //encrypt the password with the session key
  286. try
  287. {
  288. varTestPwd = m_pTargetCrypt->Encrypt(_bstr_t(testPwd));
  289. }
  290. catch (...)
  291. {
  292. ThrowError(__uuidof(PasswordMigration), __uuidof(IPasswordMigration), PM_E_GENERATE_SESSION_PASSWORD_FAILED, IDS_E_GENERATE_SESSION_PASSWORD_FAILED);
  293. }
  294. _se_translator_function pfnSeTranslatorOld = _set_se_translator((_se_translator_function)SeTranslator);
  295. HRESULT hr;
  296. try
  297. {
  298. //check to see if the server-side DLL is ready to process
  299. //password migration requests
  300. hr = PwdcCheckConfig(
  301. hBinding,
  302. GET_BYTE_ARRAY_SIZE(varSession),
  303. GET_BYTE_ARRAY_DATA(varSession),
  304. GET_BYTE_ARRAY_SIZE(varTestPwd),
  305. GET_BYTE_ARRAY_DATA(varTestPwd),
  306. tempPwd
  307. );
  308. }
  309. catch (SSeException& e)
  310. {
  311. if (e.uCode == RPC_S_SERVER_UNAVAILABLE)
  312. ThrowError(__uuidof(PasswordMigration), __uuidof(IPasswordMigration), PM_E_PASSWORD_MIGRATION_NOT_RUNNING, IDS_E_PASSWORD_MIGRATION_NOT_RUNNING);
  313. else
  314. _com_issue_error(HRESULT_FROM_WIN32(e.uCode));
  315. }
  316. _set_se_translator(pfnSeTranslatorOld);
  317. if (SUCCEEDED(hr))
  318. {
  319. if (UStrICmp(tempPwd,testPwd))
  320. ThrowError(__uuidof(PasswordMigration), __uuidof(IPasswordMigration), PM_E_ENCRYPTION_KEYS_DO_NOT_MATCH, IDS_E_ENCRYPTION_KEYS_DO_NOT_MATCH);
  321. }
  322. else if (hr == PM_E_PASSWORD_MIGRATION_NOT_ENABLED)
  323. {
  324. ThrowError(__uuidof(PasswordMigration), __uuidof(IPasswordMigration), PM_E_PASSWORD_MIGRATION_NOT_ENABLED, IDS_E_PASSWORD_MIGRATION_NOT_ENABLED);
  325. }
  326. else
  327. {
  328. _com_issue_error(hr);
  329. }
  330. PwdBindDestroy(&hBinding,&sBinding);
  331. }
  332. catch (...)
  333. {
  334. PwdBindDestroy(&hBinding,&sBinding);
  335. throw;
  336. }
  337. }
  338. //END CheckPasswordDC
  339. #pragma optimize ("", on)
  340. //---------------------------------------------------------------------------
  341. // CopyPassword Method
  342. //
  343. // Copies password via password migration server component installed on a
  344. // password export server.
  345. //
  346. // 2001-04-19 Mark Oluper - re-wrote original written by Paul Thompson to
  347. // incorporate changes required for client component
  348. //---------------------------------------------------------------------------
  349. void CPasswordMigration::CopyPasswordImpl(LPCTSTR pszSourceAccount, LPCTSTR pszTargetAccount, LPCTSTR pszPassword)
  350. {
  351. if ((pszSourceAccount == NULL) || (pszSourceAccount[0] == NULL))
  352. {
  353. ThrowError(E_INVALIDARG, IDS_E_SOURCE_ACCOUNT_NOT_SPECIFIED);
  354. }
  355. if ((pszTargetAccount == NULL) || (pszTargetAccount[0] == NULL))
  356. {
  357. ThrowError(E_INVALIDARG, IDS_E_TARGET_ACCOUNT_NOT_SPECIFIED);
  358. }
  359. handle_t hBinding = 0;
  360. _TCHAR* sBinding = 0;
  361. try
  362. {
  363. // create binding to password export server
  364. DWORD dwError = PwdBindCreate(m_strSourceServer, &hBinding, &sBinding, TRUE);
  365. if (dwError != NO_ERROR)
  366. {
  367. _com_issue_error(HRESULT_FROM_WIN32(dwError));
  368. }
  369. // encrypt password
  370. _variant_t vntEncryptedPassword = m_pTargetCrypt->Encrypt(pszPassword);
  371. // copy password
  372. HRESULT hr = PwdcCopyPassword(
  373. hBinding,
  374. m_strTargetServer,
  375. pszSourceAccount,
  376. pszTargetAccount,
  377. GET_BYTE_ARRAY_SIZE(vntEncryptedPassword),
  378. GET_BYTE_ARRAY_DATA(vntEncryptedPassword)
  379. );
  380. if (FAILED(hr))
  381. {
  382. _com_issue_error(hr);
  383. }
  384. // destroy binding
  385. PwdBindDestroy(&hBinding, &sBinding);
  386. }
  387. catch (...)
  388. {
  389. if (hBinding)
  390. {
  391. PwdBindDestroy(&hBinding, &sBinding);
  392. }
  393. throw;
  394. }
  395. }
  396. //---------------------------------------------------------------------------
  397. // GetDomainName Function
  398. //
  399. // Retrieves both the domain DNS name if available and the domain flat or
  400. // NetBIOS name for the specified server.
  401. //
  402. // 2001-04-19 Mark Oluper - initial
  403. //---------------------------------------------------------------------------
  404. void CPasswordMigration::GetDomainName(LPCTSTR pszServer, _bstr_t& strNameDNS, _bstr_t& strNameFlat)
  405. {
  406. PDSROLE_PRIMARY_DOMAIN_INFO_BASIC ppdib;
  407. DWORD dwError = DsRoleGetPrimaryDomainInformation(pszServer, DsRolePrimaryDomainInfoBasic, (BYTE**)&ppdib);
  408. if (dwError != NO_ERROR)
  409. {
  410. ThrowError(HRESULT_FROM_WIN32(dwError), IDS_E_CANNOT_GET_DOMAIN_NAME, pszServer);
  411. }
  412. strNameDNS = ppdib->DomainNameDns;
  413. strNameFlat = ppdib->DomainNameFlat;
  414. DsRoleFreeMemory(ppdib);
  415. }
  416. /*********************************************************************
  417. * *
  418. * Written by: Paul Thompson *
  419. * Date: 6 APR 2001 *
  420. * *
  421. * This function is responsible for checking if "Everyone" has *
  422. * been added as a member of the "Pre-Windows 2000 Compatible Access"*
  423. * builtin group. If not then anonymous user will not be able to *
  424. * change a password on the target domain. This function is a helper*
  425. * function for "CheckPasswordDC". *
  426. * *
  427. *********************************************************************/
  428. //BEGIN IsEveryoneInPW2KCAGroup
  429. BOOL CPasswordMigration::IsEveryoneInPW2KCAGroup(LPCWSTR sTgtDomainDNS)
  430. {
  431. /* local constants */
  432. const LPWSTR sPreWindowsCont = L"CN=Pre-Windows 2000 Compatible Access,CN=Builtin";
  433. const LPWSTR sEveryOne = L"CN=S-1-1-0,CN=ForeignSecurityPrincipals";
  434. /* local variables */
  435. IADs * pAds = NULL;
  436. IADsGroup * pGroup = NULL;
  437. HRESULT hr;
  438. WCHAR sPath[1000];
  439. _variant_t varNC;
  440. BOOL bSuccess = TRUE;
  441. BOOL bContinue = FALSE;
  442. _bstr_t sRDN;
  443. /* function body */
  444. //get the RDN of the "Pre-Windows 2000 Compatible Access" group
  445. sRDN = GetPathToPreW2KCAGroup();
  446. if (sRDN.length() == 0)
  447. sRDN = sPreWindowsCont;
  448. //get the default naming context for this target domain
  449. wsprintf(sPath, L"LDAP://%s/rootDSE", (WCHAR*)sTgtDomainDNS);
  450. hr = ADsGetObject(sPath, IID_IADs, (void**)&pAds);
  451. if ( SUCCEEDED(hr) )
  452. {
  453. hr = pAds->Get(L"defaultNamingContext", &varNC);
  454. if ( SUCCEEDED(hr) )
  455. bContinue = TRUE;
  456. pAds->Release();
  457. }
  458. //if we got the naming context, try to connect to the
  459. //"Pre-Windows 2000 Compatible Access" group
  460. if (bContinue)
  461. {
  462. wsprintf(sPath, L"LDAP://%s/%s,%s", (WCHAR*)sTgtDomainDNS, (WCHAR*)sRDN, (WCHAR*) V_BSTR(&varNC));
  463. hr = ADsGetObject(sPath, IID_IADsGroup, (void**)&pGroup);
  464. if ( SUCCEEDED(hr) )
  465. {
  466. VARIANT_BOOL bIsMem = VARIANT_FALSE;
  467. //see if "Everyone" is a member
  468. wsprintf(sPath, L"LDAP://%s/%s,%s", (WCHAR*)sTgtDomainDNS, sEveryOne, (WCHAR*) V_BSTR(&varNC));
  469. hr = pGroup->IsMember(sPath, &bIsMem);
  470. if (( SUCCEEDED(hr) ) && (!bIsMem))
  471. {
  472. bSuccess = FALSE;
  473. }
  474. pGroup->Release();
  475. }
  476. }
  477. return bSuccess;
  478. }
  479. //END IsEveryoneInPW2KCAGroup
  480. /*********************************************************************
  481. * *
  482. * Written by: Paul Thompson *
  483. * Date: 12 APR 2001 *
  484. * *
  485. * This function is responsible for creating a path to the *
  486. * "Pre-Windows 2000 Compatible Access" builtin group from its well- *
  487. * known RID. This path will then be used by *
  488. * "IsEveryoneInPW2KCAGroup" to see if "Everyone" is in that group. *
  489. * *
  490. *********************************************************************/
  491. //BEGIN GetPathToPreW2KCAGroup
  492. _bstr_t CPasswordMigration::GetPathToPreW2KCAGroup()
  493. {
  494. /* local constants */
  495. const LPWSTR sPreWindowsCont = L",CN=Builtin";
  496. /* local variables */
  497. SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY;
  498. PSID psidPreW2KCAGroup;
  499. _bstr_t sPath = L"";
  500. WCHAR account[MAX_PATH];
  501. WCHAR domain[MAX_PATH];
  502. DWORD lenAccount = MAX_PATH;
  503. DWORD lenDomain = MAX_PATH;
  504. SID_NAME_USE snu;
  505. /* function body */
  506. //create the SID for the "Pre-Windows 2000 Compatible Access" group
  507. if (!AllocateAndInitializeSid(&siaNtAuthority,
  508. 2,
  509. SECURITY_BUILTIN_DOMAIN_RID,
  510. DOMAIN_ALIAS_RID_PREW2KCOMPACCESS,
  511. 0, 0, 0, 0, 0, 0,
  512. &psidPreW2KCAGroup))
  513. return sPath;
  514. //lookup the name attached to this SID
  515. if (!LookupAccountSid(NULL, psidPreW2KCAGroup, account, &lenAccount, domain, &lenDomain, &snu))
  516. return sPath;
  517. sPath = _bstr_t(L"CN=") + _bstr_t(account) + _bstr_t(sPreWindowsCont);
  518. FreeSid(psidPreW2KCAGroup); //free the SID
  519. return sPath;
  520. }
  521. //END GetPathToPreW2KCAGroup
  522. /*********************************************************************
  523. * *
  524. * Written by: Paul Thompson *
  525. * Date: 6 APR 2001 *
  526. * *
  527. * This function is responsible for checking if anonymous user *
  528. * has been granted Everyone access if the target domain is Whistler *
  529. * or newer. This function is a helper function for *
  530. * "CheckPasswordDC". *
  531. * If the "Let Everyone permissions apply to anonymous users" *
  532. * security option has been enabled, then the LSA registry value of *
  533. * "everyoneincludesanonymous" will be set to 0x1. We will check *
  534. * registry value. *
  535. * *
  536. *********************************************************************/
  537. //BEGIN DoesAnonymousHaveEveryoneAccess
  538. BOOL CPasswordMigration::DoesAnonymousHaveEveryoneAccess(LPCWSTR tgtServer)
  539. {
  540. /* local constants */
  541. const int WINDOWS_2000_BUILD_NUMBER = 2195;
  542. /* local variables */
  543. TRegKey verKey, lsaKey, regComputer;
  544. BOOL bAccess = TRUE;
  545. DWORD rc = 0;
  546. DWORD rval;
  547. WCHAR sBuildNum[MAX_PATH];
  548. /* function body */
  549. //connect to the DC's HKLM registry key
  550. rc = regComputer.Connect(HKEY_LOCAL_MACHINE, tgtServer);
  551. if (rc == ERROR_SUCCESS)
  552. {
  553. //see if this machine is running Windows XP or newer by checking the
  554. //build number in the registry. If not, then we don't need to check
  555. //for the new security option
  556. rc = verKey.OpenRead(L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",&regComputer);
  557. if (rc == ERROR_SUCCESS)
  558. {
  559. //get the CurrentBuildNumber string
  560. rc = verKey.ValueGetStr(L"CurrentBuildNumber", sBuildNum, MAX_PATH);
  561. if (rc == ERROR_SUCCESS)
  562. {
  563. int nBuild = _wtoi(sBuildNum);
  564. if (nBuild <= WINDOWS_2000_BUILD_NUMBER)
  565. return bAccess;
  566. }
  567. }
  568. //if Windows XP or greater, check for the option being enabled
  569. //open the LSA key
  570. rc = lsaKey.OpenRead(L"System\\CurrentControlSet\\Control\\Lsa",&regComputer);
  571. if (rc == ERROR_SUCCESS)
  572. {
  573. //get the value of the "everyoneincludesanonymous" value
  574. rc = lsaKey.ValueGetDWORD(L"everyoneincludesanonymous",&rval);
  575. if (rc == ERROR_SUCCESS)
  576. {
  577. if (rval == 0)
  578. bAccess = FALSE;
  579. }
  580. else
  581. bAccess = FALSE;
  582. }
  583. }
  584. return bAccess;
  585. }
  586. //END DoesAnonymousHaveEveryoneAccess