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.

1815 lines
46 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1995
  5. //
  6. // File: cuar.cxx
  7. //
  8. // Contents: Account Restrictions Propset for the User object
  9. //
  10. // History: 11-1-95 krishnag Created.
  11. //
  12. // PROPERTY_RW(AccountDisabled, boolean, 1) I
  13. // PROPERTY_RW(AccountExpirationDate, DATE, 2) I
  14. // PROPERTY_RO(AccountCanExpire, boolean, 3) I
  15. // PROPERTY_RO(PasswordCanExpire, boolean, 4) I
  16. // PROPERTY_RW(GraceLoginsAllowed, long, 5) NI
  17. // PROPERTY_RW(GraceLoginsRemaining, long, 6) NI
  18. // PROPERTY_RW(IsAccountLocked, boolean, 7) I
  19. // PROPERTY_RW(IsAdmin, boolean, 8) I
  20. // PROPERTY_RW(LoginHours, VARIANT, 9) I
  21. // PROPERTY_RW(LoginWorkstations, VARIANT, 10) I
  22. // PROPERTY_RW(MaxLogins, long, 11) I
  23. // PROPERTY_RW(MaxStorage, long, 12) I
  24. // PROPERTY_RW(PasswordExpirationDate, DATE, 13) I
  25. // PROPERTY_RW(PasswordRequired, boolean, 14) I
  26. // PROPERTY_RW(RequireUniquePassword,boolean, 15) I
  27. //
  28. //
  29. //----------------------------------------------------------------------------
  30. #include "ldap.hxx"
  31. #pragma hdrstop
  32. #include <lm.h>
  33. #include <winldap.h>
  34. #include "..\ldapc\ldpcache.hxx"
  35. #include "..\ldapc\ldaputil.hxx"
  36. #include "..\ldapc\parse.hxx"
  37. #include <dsgetdc.h>
  38. #include <sspi.h>
  39. HRESULT
  40. BuildLDAPPathFromADsPath2(
  41. LPWSTR szADsPathName,
  42. LPWSTR *pszLDAPServer,
  43. LPWSTR *pszLDAPDn,
  44. DWORD * pdwPort
  45. );
  46. DWORD
  47. GetDefaultServer(
  48. DWORD dwPort,
  49. BOOL fVerify,
  50. LPWSTR szDomainDnsName,
  51. LPWSTR szServerName,
  52. BOOL fWriteable
  53. );
  54. HRESULT
  55. GetDomainDNSNameFromHost(
  56. LPWSTR szHostName,
  57. SEC_WINNT_AUTH_IDENTITY& AuthI,
  58. CCredentials &Credentials,
  59. DWORD dwPort,
  60. LPWSTR * ppszHostName
  61. );
  62. //
  63. // The list of server entries - detailing SSL support
  64. //
  65. PSERVSSLENTRY gpServerSSLList = NULL;
  66. //
  67. // Critical Section and support routines to protect list
  68. //
  69. CRITICAL_SECTION g_ServerListCritSect;
  70. //
  71. // Flag that indicates if kerberos is being used.
  72. //
  73. const unsigned long KERB_SUPPORT_FLAGS = ISC_RET_MUTUAL_AUTH ;
  74. //
  75. // Routines that support cacheing server SSL info for perf
  76. //
  77. #define STRING_LENGTH(p) ( p ? wcslen(p) : 0)
  78. //
  79. // Get the status of SSL support on the server pszServerName
  80. // 0 indicates that the server was not in our list.
  81. //
  82. DWORD ReadServerSupportsSSL( LPWSTR pszServerName)
  83. {
  84. ENTER_SERVERLIST_CRITICAL_SECTION();
  85. PSERVSSLENTRY pServerList = gpServerSSLList;
  86. DWORD dwRetVal = 0;
  87. //
  88. // Keep going through the list until we hit the end or
  89. // we find an entry that matches.
  90. //
  91. while ((pServerList != NULL) && (dwRetVal == 0)) {
  92. #ifdef WIN95
  93. if (!(_wcsicmp(pszServerName, pServerList->pszServerName))) {
  94. #else
  95. if (CompareStringW(
  96. LOCALE_SYSTEM_DEFAULT,
  97. NORM_IGNORECASE,
  98. pszServerName,
  99. -1,
  100. pServerList->pszServerName,
  101. -1
  102. ) == CSTR_EQUAL ) {
  103. #endif
  104. dwRetVal = pServerList->dwFlags;
  105. }
  106. pServerList = pServerList->pNext;
  107. }
  108. LEAVE_SERVERLIST_CRITICAL_SECTION();
  109. return dwRetVal;
  110. }
  111. HRESULT UpdateServerSSLSupportStatus(
  112. PWSTR pszServerName,
  113. DWORD dwFlags
  114. )
  115. {
  116. HRESULT hr = S_OK;
  117. PSERVSSLENTRY pServEntry = NULL;
  118. ENTER_SERVERLIST_CRITICAL_SECTION()
  119. PSERVSSLENTRY pServerList = gpServerSSLList;
  120. DWORD dwRetVal = 0;
  121. ADsAssert(pszServerName && *pszServerName);
  122. //
  123. // Keep going through the list until we hit the end or
  124. // we find an entry that matches.
  125. //
  126. while ((pServerList != NULL) && (dwRetVal == 0)) {
  127. #ifdef WIN95
  128. if (!(_wcsicmp(pszServerName, pServerList->pszServerName))) {
  129. #else
  130. if (CompareStringW(
  131. LOCALE_SYSTEM_DEFAULT,
  132. NORM_IGNORECASE,
  133. pszServerName,
  134. -1,
  135. pServerList->pszServerName,
  136. -1
  137. ) == CSTR_EQUAL ) {
  138. #endif
  139. pServerList->dwFlags = dwFlags;
  140. LEAVE_SERVERLIST_CRITICAL_SECTION()
  141. RRETURN(S_OK);
  142. }
  143. pServerList = pServerList->pNext;
  144. }
  145. pServEntry = (PSERVSSLENTRY) AllocADsMem(sizeof(SERVSSLENTRY));
  146. if (!pServEntry) {
  147. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  148. }
  149. pServEntry->pszServerName = AllocADsStr(pszServerName);
  150. if (!pServEntry->pszServerName) {
  151. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  152. }
  153. pServEntry->dwFlags = dwFlags;
  154. pServEntry->pNext = gpServerSSLList;
  155. gpServerSSLList = pServEntry;
  156. error:
  157. if (FAILED(hr) && pServEntry) {
  158. //
  159. // Free only pServEntry as the string cannot have
  160. // a value in the error case
  161. //
  162. FreeADsMem(pServEntry);
  163. }
  164. LEAVE_SERVERLIST_CRITICAL_SECTION();
  165. RRETURN(hr);
  166. }
  167. void FreeServerSSLSupportList()
  168. {
  169. PSERVSSLENTRY pList = gpServerSSLList;
  170. PSERVSSLENTRY pPrevEntry = NULL;
  171. while (pList) {
  172. pPrevEntry = pList;
  173. FreeADsStr(pList->pszServerName);
  174. pList = pList->pNext;
  175. FreeADsMem(pPrevEntry);
  176. }
  177. }
  178. #if (!defined(WIN95))
  179. //
  180. // Take a AuthI struct and return a cred handle.
  181. //
  182. HRESULT
  183. ConvertAuthIdentityToCredHandle(
  184. SEC_WINNT_AUTH_IDENTITY& AuthI,
  185. OUT PCredHandle CredentialsHandle
  186. )
  187. {
  188. SECURITY_STATUS secStatus = SEC_E_OK;
  189. TimeStamp Lifetime;
  190. secStatus = AcquireCredentialsHandleWrapper(
  191. NULL, // New principal
  192. MICROSOFT_KERBEROS_NAME_W,
  193. SECPKG_CRED_OUTBOUND,
  194. NULL,
  195. &AuthI,
  196. NULL,
  197. NULL,
  198. CredentialsHandle,
  199. &Lifetime
  200. );
  201. if (secStatus != SEC_E_OK) {
  202. RRETURN(E_FAIL);
  203. } else {
  204. RRETURN(S_OK);
  205. }
  206. }
  207. //
  208. // ***** Caller must free the strings put in the ****
  209. // ***** AuthIdentity struct later. ****
  210. //
  211. HRESULT
  212. GetAuthIdentityForCaller(
  213. CCredentials& Credentials,
  214. IADs * pIADs,
  215. OUT SEC_WINNT_AUTH_IDENTITY *pAuthI,
  216. BOOL fEnforceMutualAuth
  217. )
  218. {
  219. HRESULT hr = S_OK;
  220. LPWSTR pszNTLMUser = NULL;
  221. LPWSTR pszNTLMDomain = NULL;
  222. LPWSTR pszDefaultServer = NULL;
  223. LPWSTR dn = NULL;
  224. LPWSTR passwd = NULL;
  225. IADsObjOptPrivate * pADsPrivObjectOptions = NULL;
  226. ULONG ulFlags = 0;
  227. if (fEnforceMutualAuth) {
  228. hr = pIADs->QueryInterface(
  229. IID_IADsObjOptPrivate,
  230. (void **)&pADsPrivObjectOptions
  231. );
  232. BAIL_ON_FAILURE(hr);
  233. hr = pADsPrivObjectOptions->GetOption (
  234. LDAP_MUTUAL_AUTH_STATUS,
  235. (void *) &ulFlags
  236. );
  237. BAIL_ON_FAILURE(hr);
  238. if (!(ulFlags & KERB_SUPPORT_FLAGS)) {
  239. BAIL_ON_FAILURE(hr = E_FAIL);
  240. }
  241. }
  242. hr = Credentials.GetUserName(&dn);
  243. BAIL_ON_FAILURE(hr);
  244. hr = Credentials.GetPassword(&passwd);
  245. BAIL_ON_FAILURE(hr);
  246. //
  247. // Get the userName and password into the auth struct.
  248. //
  249. hr = LdapCrackUserDNtoNTLMUser2(
  250. dn,
  251. &pszNTLMUser,
  252. &pszNTLMDomain
  253. );
  254. if (FAILED(hr)) {
  255. hr = LdapCrackUserDNtoNTLMUser(
  256. dn,
  257. &pszNTLMUser,
  258. &pszNTLMDomain
  259. );
  260. BAIL_ON_FAILURE(hr);
  261. }
  262. //
  263. // If the domain name is NULL and enforceMutualAuth is false,
  264. // then we need to throw in the defaultDomainName. This will
  265. // be needed subsequently for the LogonUser call.
  266. //
  267. if (!fEnforceMutualAuth && !pszNTLMDomain) {
  268. //
  269. // Call GetDefaultServer.
  270. //
  271. pszDefaultServer = (LPWSTR) AllocADsMem(sizeof(WCHAR) * MAX_PATH);
  272. if (!pszDefaultServer) {
  273. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  274. }
  275. pszNTLMDomain = (LPWSTR) AllocADsMem(sizeof(WCHAR) * MAX_PATH);
  276. if (!pszNTLMDomain) {
  277. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  278. }
  279. hr = GetDefaultServer(
  280. -1, // this will use the default ldap port
  281. FALSE,
  282. pszNTLMDomain,
  283. pszDefaultServer,
  284. TRUE
  285. );
  286. BAIL_ON_FAILURE(hr);
  287. }
  288. pAuthI->User = (PWCHAR)pszNTLMUser;
  289. pAuthI->UserLength = (pszNTLMUser == NULL)? 0: wcslen(pszNTLMUser);
  290. pAuthI->Domain = (PWCHAR)pszNTLMDomain;
  291. pAuthI->DomainLength = (pszNTLMDomain == NULL)? 0: wcslen(pszNTLMDomain);
  292. pAuthI->Password = (PWCHAR)passwd;
  293. pAuthI->PasswordLength = (passwd == NULL)? 0: wcslen(passwd);
  294. pAuthI->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
  295. error:
  296. if (FAILED(hr)) {
  297. //
  298. // Free the strings
  299. //
  300. if (pszNTLMUser) {
  301. FreeADsStr(pszNTLMUser);
  302. }
  303. if (pszNTLMDomain) {
  304. FreeADsStr(pszNTLMDomain);
  305. }
  306. if (passwd) {
  307. FreeADsStr(passwd);
  308. }
  309. }
  310. if (pADsPrivObjectOptions) {
  311. pADsPrivObjectOptions->Release();
  312. }
  313. //
  314. // Always free the dn
  315. //
  316. if (dn) {
  317. FreeADsStr(dn);
  318. }
  319. if (pszDefaultServer) {
  320. FreeADsMem(pszDefaultServer);
  321. }
  322. RRETURN(hr);
  323. }
  324. #endif
  325. // Class CLDAPUser
  326. STDMETHODIMP
  327. CLDAPUser::get_AccountDisabled(THIS_ VARIANT_BOOL FAR* retval)
  328. {
  329. if ( retval == NULL )
  330. RRETURN( E_ADS_BAD_PARAMETER );
  331. LONG lUserAcctControl;
  332. HRESULT hr = get_LONG_Property( (IADsUser *)this,
  333. TEXT("userAccountControl"),
  334. &lUserAcctControl );
  335. if ( SUCCEEDED(hr))
  336. *retval = lUserAcctControl & UF_ACCOUNTDISABLE ?
  337. VARIANT_TRUE : VARIANT_FALSE;
  338. RRETURN(hr);
  339. }
  340. STDMETHODIMP
  341. CLDAPUser::put_AccountDisabled(THIS_ VARIANT_BOOL fAccountDisabled)
  342. {
  343. LONG lUserAcctControl;
  344. HRESULT hr = get_LONG_Property( (IADsUser *)this,
  345. TEXT("userAccountControl"),
  346. &lUserAcctControl );
  347. if ( SUCCEEDED(hr))
  348. {
  349. if ( fAccountDisabled )
  350. lUserAcctControl |= UF_ACCOUNTDISABLE;
  351. else
  352. lUserAcctControl &= ~UF_ACCOUNTDISABLE;
  353. hr = put_LONG_Property( (IADsUser *)this,
  354. TEXT("userAccountControl"),
  355. lUserAcctControl );
  356. }
  357. RRETURN(hr);
  358. }
  359. STDMETHODIMP
  360. CLDAPUser::get_AccountExpirationDate(THIS_ DATE FAR* retval)
  361. {
  362. GET_PROPERTY_FILETIME((IADsUser *)this, AccountExpirationDate);
  363. }
  364. STDMETHODIMP
  365. CLDAPUser::put_AccountExpirationDate(THIS_ DATE daAccountExpirationDate)
  366. {
  367. PUT_PROPERTY_FILETIME((IADsUser *)this, AccountExpirationDate);
  368. }
  369. STDMETHODIMP
  370. CLDAPUser::get_GraceLoginsAllowed(THIS_ long FAR* retval)
  371. {
  372. RRETURN(E_ADS_PROPERTY_NOT_SUPPORTED);
  373. }
  374. STDMETHODIMP
  375. CLDAPUser::put_GraceLoginsAllowed(THIS_ long lGraceLoginsAllowed)
  376. {
  377. RRETURN(E_ADS_PROPERTY_NOT_SUPPORTED);
  378. }
  379. STDMETHODIMP
  380. CLDAPUser::get_GraceLoginsRemaining(THIS_ long FAR* retval)
  381. {
  382. RRETURN(E_ADS_PROPERTY_NOT_SUPPORTED);
  383. }
  384. STDMETHODIMP
  385. CLDAPUser::put_GraceLoginsRemaining(THIS_ long lGraceLoginsRemaining)
  386. {
  387. RRETURN(E_ADS_PROPERTY_NOT_SUPPORTED);
  388. }
  389. STDMETHODIMP
  390. CLDAPUser::get_IsAccountLocked(THIS_ VARIANT_BOOL FAR* retval)
  391. {
  392. HRESULT hr = S_OK;
  393. VARIANT var;
  394. IADsLargeInteger *pLargeInt = NULL;
  395. LONG LowPart, HighPart;
  396. if ( retval == NULL )
  397. RRETURN( E_ADS_BAD_PARAMETER );
  398. VariantInit(&var);
  399. hr = _pADs->Get(TEXT("lockoutTime"), &var);
  400. if (SUCCEEDED(hr)) {
  401. //
  402. // There's a lockoutTime, we need to determine
  403. // if it equals 0 (== not locked-out).
  404. //
  405. ADsAssert(V_VT(&var) == VT_DISPATCH);
  406. if (V_VT(&var) != VT_DISPATCH) {
  407. BAIL_ON_FAILURE(hr = E_FAIL);
  408. }
  409. hr = V_DISPATCH(&var)->QueryInterface(IID_IADsLargeInteger,
  410. reinterpret_cast<void**>(&pLargeInt)
  411. );
  412. BAIL_ON_FAILURE(hr);
  413. hr = pLargeInt->get_LowPart(&LowPart);
  414. BAIL_ON_FAILURE(hr);
  415. hr = pLargeInt->get_HighPart(&HighPart);
  416. BAIL_ON_FAILURE(hr);
  417. if ( (LowPart != 0) || (HighPart != 0) ) {
  418. *retval = VARIANT_TRUE;
  419. }
  420. else {
  421. *retval = VARIANT_FALSE;
  422. }
  423. }
  424. else if (hr == E_ADS_PROPERTY_NOT_FOUND) {
  425. //
  426. // If there's no lockoutTime, the account is not
  427. // locked-out.
  428. //
  429. *retval = VARIANT_FALSE;
  430. hr = S_OK;
  431. }
  432. else {
  433. BAIL_ON_FAILURE(hr);
  434. }
  435. error:
  436. if (pLargeInt) {
  437. pLargeInt->Release();
  438. }
  439. VariantClear(&var);
  440. RRETURN(hr);
  441. }
  442. STDMETHODIMP
  443. CLDAPUser::put_IsAccountLocked(THIS_ VARIANT_BOOL fIsAccountLocked)
  444. {
  445. HRESULT hr = S_OK;
  446. if (fIsAccountLocked) {
  447. //
  448. // You cannot set an account to a locked state.
  449. //
  450. RRETURN(E_ADS_BAD_PARAMETER);
  451. }
  452. hr = put_LONG_Property( (IADsUser *)this,
  453. TEXT("lockoutTime"),
  454. 0 );
  455. RRETURN(hr);
  456. }
  457. STDMETHODIMP
  458. CLDAPUser::get_LoginHours(THIS_ VARIANT FAR* retval)
  459. {
  460. GET_PROPERTY_VARIANT((IADsUser *)this, LoginHours);
  461. }
  462. STDMETHODIMP
  463. CLDAPUser::put_LoginHours(THIS_ VARIANT vLoginHours)
  464. {
  465. PUT_PROPERTY_VARIANT((IADsUser *)this, LoginHours);
  466. }
  467. STDMETHODIMP
  468. CLDAPUser::get_LoginWorkstations(THIS_ VARIANT FAR* retval)
  469. {
  470. GET_PROPERTY_BSTRARRAY((IADsUser *)this,LoginWorkstations);
  471. }
  472. STDMETHODIMP
  473. CLDAPUser::put_LoginWorkstations(THIS_ VARIANT vLoginWorkstations)
  474. {
  475. PUT_PROPERTY_BSTRARRAY((IADsUser *)this,LoginWorkstations);
  476. }
  477. STDMETHODIMP
  478. CLDAPUser::get_MaxLogins(THIS_ long FAR* retval)
  479. {
  480. RRETURN(E_ADS_PROPERTY_NOT_SUPPORTED);
  481. }
  482. STDMETHODIMP
  483. CLDAPUser::put_MaxLogins(THIS_ long lMaxLogins)
  484. {
  485. RRETURN(E_ADS_PROPERTY_NOT_SUPPORTED);
  486. }
  487. STDMETHODIMP
  488. CLDAPUser::get_MaxStorage(THIS_ long FAR* retval)
  489. {
  490. GET_PROPERTY_LONG((IADsUser *)this, MaxStorage);
  491. }
  492. STDMETHODIMP
  493. CLDAPUser::put_MaxStorage(THIS_ long lMaxStorage)
  494. {
  495. PUT_PROPERTY_LONG((IADsUser *)this, MaxStorage);
  496. }
  497. STDMETHODIMP
  498. CLDAPUser::get_PasswordExpirationDate(THIS_ DATE FAR* retval)
  499. {
  500. GET_PROPERTY_DATE((IADsUser *)this, PasswordExpirationDate);
  501. }
  502. STDMETHODIMP
  503. CLDAPUser::put_PasswordExpirationDate(THIS_ DATE daPasswordExpirationDate)
  504. {
  505. PUT_PROPERTY_DATE((IADsUser *)this, PasswordExpirationDate);
  506. }
  507. STDMETHODIMP
  508. CLDAPUser::get_PasswordRequired(THIS_ VARIANT_BOOL FAR* retval)
  509. {
  510. if ( retval == NULL )
  511. RRETURN( E_ADS_BAD_PARAMETER );
  512. LONG lUserAcctControl;
  513. HRESULT hr = get_LONG_Property( (IADsUser *)this,
  514. TEXT("userAccountControl"),
  515. &lUserAcctControl );
  516. if ( SUCCEEDED(hr))
  517. *retval = lUserAcctControl & UF_PASSWD_NOTREQD ?
  518. VARIANT_FALSE: VARIANT_TRUE;
  519. RRETURN(hr);
  520. }
  521. STDMETHODIMP
  522. CLDAPUser::put_PasswordRequired(THIS_ VARIANT_BOOL fPasswordRequired)
  523. {
  524. LONG lUserAcctControl;
  525. HRESULT hr = get_LONG_Property( (IADsUser *)this,
  526. TEXT("userAccountControl"),
  527. &lUserAcctControl );
  528. if ( SUCCEEDED(hr))
  529. {
  530. if ( fPasswordRequired )
  531. lUserAcctControl &= ~UF_PASSWD_NOTREQD;
  532. else
  533. lUserAcctControl |= UF_PASSWD_NOTREQD;
  534. hr = put_LONG_Property( (IADsUser *)this,
  535. TEXT("userAccountControl"),
  536. lUserAcctControl );
  537. }
  538. RRETURN(hr);
  539. }
  540. STDMETHODIMP
  541. CLDAPUser::get_PasswordMinimumLength(THIS_ LONG FAR* retval)
  542. {
  543. GET_PROPERTY_LONG((IADsUser *)this, PasswordMinimumLength);
  544. }
  545. STDMETHODIMP
  546. CLDAPUser::put_PasswordMinimumLength(THIS_ LONG lPasswordMinimumLength)
  547. {
  548. PUT_PROPERTY_LONG((IADsUser *)this, PasswordMinimumLength);
  549. }
  550. STDMETHODIMP
  551. CLDAPUser::get_RequireUniquePassword(THIS_ VARIANT_BOOL FAR* retval)
  552. {
  553. GET_PROPERTY_VARIANT_BOOL((IADsUser *)this, RequireUniquePassword);
  554. }
  555. STDMETHODIMP
  556. CLDAPUser::put_RequireUniquePassword(THIS_ VARIANT_BOOL fRequireUniquePassword)
  557. {
  558. PUT_PROPERTY_VARIANT_BOOL((IADsUser *)this, RequireUniquePassword);
  559. }
  560. BOOLEAN
  561. _cdecl ServerCertCallback(
  562. PLDAP Connection,
  563. PCCERT_CONTEXT pServerCert
  564. )
  565. {
  566. //
  567. // After the secure connection is established, this function is called by
  568. // LDAP. This gives the client an opportunity to verify the server cert.
  569. // If, for some reason, the client doesn't approve it, it should return FALSE
  570. // and the connection will be terminated. Else, return TRUE
  571. //
  572. fprintf( stderr, "Server cert callback has been called...\n" );
  573. //
  574. // Use some way to verify the server certificate.
  575. //
  576. return TRUE;
  577. }
  578. STDMETHODIMP
  579. CLDAPUser::SetPassword(THIS_ BSTR bstrNewPassword)
  580. {
  581. HRESULT hr = E_FAIL;
  582. BOOLEAN bUseLDAP = FALSE;
  583. LPWSTR pszServer = NULL;
  584. LPWSTR pszHostName = NULL;
  585. DWORD dwLen = 0;
  586. int err = 0;
  587. BSTR bstrADsPath = NULL;
  588. LPWSTR szServerSSL = NULL;
  589. LPWSTR szDn = NULL;
  590. DWORD dwPortSSL = 0;
  591. PADSLDP pAdsLdpSSL = NULL;
  592. IADsObjOptPrivate * pADsPrivObjectOptions = NULL;
  593. PADSLDP pAdsLdp = NULL;
  594. LDAPMessage *pMsgResult = NULL;
  595. LDAPMessage *pMsgEntry = NULL;
  596. LDAP *pLdapCurrent = NULL;
  597. LPWSTR Attributes[] = {L"objectClass", NULL};
  598. VARIANT varSamAccount;
  599. DWORD dwServerPwdSupport = SERVER_STATUS_UNKNOWN;
  600. LPWSTR pszHostDomainName = NULL;
  601. SEC_WINNT_AUTH_IDENTITY AuthI;
  602. BOOLEAN fPasswordSet = FALSE;
  603. LPWSTR pszTempPwd = NULL;
  604. ULONG ulFlags = 0;
  605. VARIANT varGetInfoEx;
  606. BOOL fCachePrimed = FALSE;
  607. BOOL fImpersonating = FALSE;
  608. HANDLE hUserToken = INVALID_HANDLE_VALUE;
  609. //
  610. // Init params we will need to free later.
  611. //
  612. AuthI.User = NULL;
  613. AuthI.Domain = NULL;
  614. AuthI.Password = NULL;
  615. VariantInit(&varSamAccount);
  616. VariantInit(&varGetInfoEx);
  617. //
  618. // Get the Ldap path of the user object
  619. //
  620. hr = _pADs->get_ADsPath( &bstrADsPath );
  621. BAIL_ON_FAILURE(hr);
  622. hr = BuildLDAPPathFromADsPath2(
  623. bstrADsPath,
  624. &szServerSSL,
  625. &szDn,
  626. &dwPortSSL
  627. );
  628. BAIL_ON_FAILURE(hr);
  629. //
  630. // Now do an LDAP Search with Referrals and get the handle to success
  631. // connection. This is where we can find the server the referred object
  632. // resides on
  633. //
  634. hr = _pADs->QueryInterface(
  635. IID_IADsObjOptPrivate,
  636. (void **)&pADsPrivObjectOptions
  637. );
  638. BAIL_ON_FAILURE(hr);
  639. hr = pADsPrivObjectOptions->GetOption (
  640. LDAP_SERVER,
  641. (void*)&pszHostName
  642. );
  643. BAIL_ON_FAILURE(hr);
  644. //
  645. // additional lengh 3 is for '\0' and "\\\\"
  646. //
  647. dwLen = STRING_LENGTH(pszHostName) + 3;
  648. pszServer = (LPWSTR) AllocADsMem( dwLen * sizeof(WCHAR) );
  649. if (!pszServer) {
  650. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  651. }
  652. wcscpy(pszServer,L"\\\\");
  653. wcscat(pszServer, pszHostName);
  654. dwServerPwdSupport = ReadServerSupportsSSL(pszHostName);
  655. if (dwServerPwdSupport ==
  656. ( SERVER_STATUS_UNKNOWN
  657. | SERVER_DOES_NOT_SUPPORT_SSL
  658. | SERVER_DOES_NOT_SUPPORT_NETUSER
  659. | SERVER_DOES_NOT_SUPPORT_KERBEROS )
  660. ) {
  661. //
  662. // All flags are set, we will reset and rebuild cache
  663. //
  664. UpdateServerSSLSupportStatus(
  665. pszHostName,
  666. SERVER_STATUS_UNKNOWN
  667. );
  668. dwServerPwdSupport = SERVER_STATUS_UNKNOWN;
  669. }
  670. if (dwServerPwdSupport == SERVER_STATUS_UNKNOWN
  671. || !(dwServerPwdSupport & SERVER_DOES_NOT_SUPPORT_SSL)) {
  672. //
  673. // Try to establish SSL connection for this Password Operation
  674. //
  675. hr = LdapOpenObject(
  676. pszHostName,
  677. szDn,
  678. &pAdsLdpSSL,
  679. _Credentials,
  680. 636
  681. );
  682. if (SUCCEEDED(hr)) {
  683. int retval;
  684. SecPkgContext_ConnectionInfo sslattr;
  685. retval = ldap_get_option( pAdsLdpSSL->LdapHandle, LDAP_OPT_SSL_INFO, &sslattr );
  686. if (retval == LDAP_SUCCESS) {
  687. //
  688. // If Channel is secure enough, enable LDAP Password Change
  689. //
  690. if (sslattr.dwCipherStrength >= 128) {
  691. bUseLDAP = TRUE;
  692. }
  693. }
  694. }
  695. //
  696. // Update the SSL support if appropriate
  697. //
  698. if (dwServerPwdSupport == SERVER_STATUS_UNKNOWN
  699. || !bUseLDAP) {
  700. //
  701. // Set the server does not support ssl bit if necessary
  702. //
  703. UpdateServerSSLSupportStatus(
  704. pszHostName,
  705. bUseLDAP ?
  706. dwServerPwdSupport :
  707. dwServerPwdSupport |= SERVER_DOES_NOT_SUPPORT_SSL
  708. );
  709. }
  710. }
  711. if (bUseLDAP) {
  712. //
  713. // LDAP Password Set
  714. //
  715. PLDAPModW prgMod[2];
  716. LDAPModW ModReplace;
  717. struct berval* rgBerVal[2];
  718. struct berval BerVal;
  719. int ipwdLen;
  720. prgMod[0] = &ModReplace;
  721. prgMod[1] = NULL;
  722. ModReplace.mod_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
  723. ModReplace.mod_type = L"unicodePwd";
  724. ModReplace.mod_bvalues = rgBerVal;
  725. rgBerVal[0] = &BerVal;
  726. rgBerVal[1] = NULL;
  727. //
  728. // 2 extra for "" to put the password in.
  729. //
  730. if (bstrNewPassword) {
  731. ipwdLen = (wcslen(bstrNewPassword) + 2) * sizeof(WCHAR);
  732. }
  733. else {
  734. ipwdLen = 2 * sizeof(WCHAR);
  735. }
  736. //
  737. // Add 1 for the \0.
  738. //
  739. pszTempPwd = (LPWSTR) AllocADsMem(ipwdLen + sizeof(WCHAR));
  740. if (!pszTempPwd) {
  741. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  742. }
  743. wcscpy(pszTempPwd, L"\"");
  744. if (bstrNewPassword) {
  745. wcscat(pszTempPwd, bstrNewPassword);
  746. }
  747. wcscat(pszTempPwd, L"\"");
  748. BerVal.bv_len = ipwdLen;
  749. BerVal.bv_val = (char*)pszTempPwd;
  750. hr = LdapModifyS(
  751. pAdsLdpSSL,
  752. szDn,
  753. prgMod
  754. );
  755. BAIL_ON_FAILURE(hr);
  756. //
  757. // Set flag so that we do not try any other methods.
  758. //
  759. fPasswordSet = TRUE;
  760. }
  761. //
  762. // Try kerberos setpassword if applicable
  763. //
  764. #if (!defined(WIN95))
  765. //
  766. // Only valid on Win2k
  767. //
  768. if (!fPasswordSet) {
  769. //
  770. // If we cached the server as not supporting Kerberos, most likely it
  771. // was because we were not mutually authenticated. Do a quick check to
  772. // see if that has changed, so that we can update our cached information
  773. // if necessary.
  774. //
  775. if (dwServerPwdSupport & SERVER_DOES_NOT_SUPPORT_KERBEROS) {
  776. hr = pADsPrivObjectOptions->GetOption (
  777. LDAP_MUTUAL_AUTH_STATUS,
  778. (void *) &ulFlags
  779. );
  780. BAIL_ON_FAILURE(hr);
  781. if ((ulFlags & KERB_SUPPORT_FLAGS)) {
  782. UpdateServerSSLSupportStatus(
  783. pszHostName,
  784. dwServerPwdSupport &= (~SERVER_DOES_NOT_SUPPORT_KERBEROS)
  785. );
  786. }
  787. }
  788. if (!(dwServerPwdSupport & SERVER_DOES_NOT_SUPPORT_KERBEROS)) {
  789. //
  790. // Kerberos set password
  791. //
  792. CredHandle secCredHandle = {0};
  793. SECURITY_STATUS SecStatus;
  794. DWORD dwStatus = 0;
  795. LPWSTR pszSamAccountArr[] = {L"sAMAccountName"};
  796. if (!fCachePrimed) {
  797. hr = ADsBuildVarArrayStr( pszSamAccountArr, 1, &varGetInfoEx );
  798. BAIL_ON_FAILURE(hr);
  799. hr = _pADs->GetInfoEx(varGetInfoEx, 0);
  800. BAIL_ON_FAILURE(hr);
  801. fCachePrimed = TRUE;
  802. }
  803. hr = _pADs->Get(L"sAMAccountName", &varSamAccount);
  804. BAIL_ON_FAILURE(hr);
  805. //
  806. // The AuthIdentity structure is ueful down the road.
  807. // This routine will fail if we were not bound using
  808. // kerberos to the server.
  809. //
  810. hr = GetAuthIdentityForCaller(
  811. _Credentials,
  812. _pADs,
  813. &AuthI,
  814. TRUE // enforce mutual auth.
  815. );
  816. if (FAILED(hr)) {
  817. UpdateServerSSLSupportStatus(
  818. pszHostName,
  819. dwServerPwdSupport |= SERVER_DOES_NOT_SUPPORT_KERBEROS
  820. );
  821. }
  822. else {
  823. //
  824. // Kerb really needs this handle.
  825. //
  826. hr = ConvertAuthIdentityToCredHandle(
  827. AuthI,
  828. &secCredHandle
  829. );
  830. if (FAILED(hr)) {
  831. UpdateServerSSLSupportStatus(
  832. pszHostName,
  833. dwServerPwdSupport |= SERVER_DOES_NOT_SUPPORT_KERBEROS
  834. );
  835. }
  836. if (SUCCEEDED(hr)) {
  837. //
  838. // Get the domain dns name for the user
  839. //
  840. hr = GetDomainDNSNameFromHost(
  841. pszHostName,
  842. AuthI,
  843. _Credentials,
  844. dwPortSSL,
  845. &pszHostDomainName
  846. );
  847. if (SUCCEEDED(hr)) {
  848. dwStatus = KerbSetPasswordUserEx(
  849. pszHostDomainName,
  850. V_BSTR(&varSamAccount),
  851. bstrNewPassword,
  852. &secCredHandle,
  853. pszHostName
  854. );
  855. if (dwStatus) {
  856. //
  857. // We should have got this to come in here.
  858. //
  859. hr = HRESULT_FROM_WIN32(ERROR_LOGON_FAILURE);
  860. }
  861. else {
  862. fPasswordSet = TRUE;
  863. }
  864. } // if domain dns name get succeeded.
  865. FreeCredentialsHandleWrapper(&secCredHandle);
  866. } // if GetCredentialsForCaller succeeded.
  867. } // if we could get authidentity succesfully
  868. } // if server supports kerberos
  869. } // if password not set.
  870. #endif
  871. //
  872. // At this point server status cannot be unknown, it
  873. // will atleast have info about ssl support.
  874. //
  875. if (!fPasswordSet) {
  876. if (!(dwServerPwdSupport & SERVER_DOES_NOT_SUPPORT_NETUSER)) {
  877. //
  878. // Password Set using NET APIs
  879. //
  880. NET_API_STATUS nasStatus;
  881. DWORD dwParmErr = 0;
  882. LPWSTR pszSamAccountArr[] = {L"sAMAccountName"};
  883. //
  884. // Get SamAccountName
  885. //
  886. VariantClear(&varSamAccount);
  887. VariantClear(&varGetInfoEx);
  888. if (!fCachePrimed) {
  889. hr = ADsBuildVarArrayStr( pszSamAccountArr, 1, &varGetInfoEx );
  890. BAIL_ON_FAILURE(hr);
  891. hr = _pADs->GetInfoEx(varGetInfoEx, 0);
  892. BAIL_ON_FAILURE(hr);
  893. fCachePrimed = TRUE;
  894. }
  895. hr = _pADs->Get(L"sAMAccountName", &varSamAccount);
  896. BAIL_ON_FAILURE(hr);
  897. //
  898. // Set the password
  899. //
  900. USER_INFO_1003 lpUserInfo1003 ;
  901. lpUserInfo1003.usri1003_password = bstrNewPassword;
  902. #ifndef Win95
  903. //
  904. // At this point if the user credentials are non NULL,
  905. // we want to impersonate the user and then make this call.
  906. // This will make sure the NetUserSetInfo call is made in the
  907. // correct context.
  908. //
  909. if (!_Credentials.IsNullCredentials()) {
  910. //
  911. // Need to get the userName and password in the format
  912. // usable by the logonUser call.
  913. //
  914. if ((AuthI.User == NULL)
  915. && (AuthI.Domain == NULL)
  916. && (AuthI.Password == NULL)
  917. ) {
  918. //
  919. // Get teh Auth identity struct populate if necessary.
  920. //
  921. hr = GetAuthIdentityForCaller(
  922. _Credentials,
  923. _pADs,
  924. &AuthI,
  925. FALSE
  926. );
  927. }
  928. BAIL_ON_FAILURE(hr);
  929. //
  930. // Note that if this code is backported, then we might
  931. // need to change LOGON32_PROVIDER_WINNT50 to
  932. // LOGON32_PROVIDER_DEFAULT as NT4 and below will support
  933. // only that option. Also note that Win2k and below, do not
  934. // allow all accounts to impersonate.
  935. //
  936. if (LogonUser(
  937. AuthI.User,
  938. AuthI.Domain,
  939. AuthI.Password,
  940. LOGON32_LOGON_NEW_CREDENTIALS,
  941. LOGON32_PROVIDER_WINNT50,
  942. &hUserToken
  943. )
  944. ) {
  945. //
  946. // Call succeeded so we should use this context.
  947. //
  948. if (ImpersonateLoggedOnUser(hUserToken)) {
  949. fImpersonating = TRUE;
  950. }
  951. }
  952. if (!fImpersonating) {
  953. hr = HRESULT_FROM_WIN32(GetLastError());
  954. }
  955. BAIL_ON_FAILURE(hr);
  956. } // if credentials are valid.
  957. #endif
  958. nasStatus = NetUserSetInfo(
  959. pszServer,
  960. V_BSTR(&varSamAccount),
  961. 1003,
  962. (LPBYTE)&lpUserInfo1003,
  963. &dwParmErr
  964. );
  965. #ifndef Win95
  966. if (fImpersonating) {
  967. if (RevertToSelf()) {
  968. fImpersonating = FALSE;
  969. }
  970. else {
  971. ADsAssert(!"Revert to self failed.");
  972. BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(GetLastError()));
  973. }
  974. }
  975. #endif
  976. if ( nasStatus == NERR_UserNotFound ) { // User not created yet
  977. hr = E_ADS_OBJECT_UNBOUND;
  978. BAIL_ON_FAILURE(hr);
  979. }
  980. hr = HRESULT_FROM_WIN32(nasStatus);
  981. if (FAILED(hr) && (nasStatus == ERROR_LOGON_FAILURE)) {
  982. //
  983. // Was failure and ERROR_LOGON_FAILURE
  984. //
  985. UpdateServerSSLSupportStatus(
  986. pszHostName,
  987. dwServerPwdSupport |= SERVER_DOES_NOT_SUPPORT_NETUSER
  988. );
  989. //
  990. // Need to free the variant as we will re-read in kerb
  991. //
  992. VariantClear(&varSamAccount);
  993. }
  994. else {
  995. //
  996. // password set succeed
  997. //
  998. fPasswordSet = TRUE;
  999. }
  1000. }
  1001. } // if Password not set.
  1002. error:
  1003. if (bstrADsPath) {
  1004. ADsFreeString(bstrADsPath);
  1005. }
  1006. if (szServerSSL) {
  1007. FreeADsStr(szServerSSL);
  1008. }
  1009. if (szDn) {
  1010. FreeADsStr(szDn);
  1011. }
  1012. if (pAdsLdpSSL) {
  1013. LdapCloseObject(pAdsLdpSSL);
  1014. }
  1015. if (pADsPrivObjectOptions) {
  1016. pADsPrivObjectOptions->Release();
  1017. }
  1018. if (pMsgResult) {
  1019. LdapMsgFree(pMsgResult);
  1020. }
  1021. if (pszHostDomainName) {
  1022. FreeADsStr(pszHostDomainName);
  1023. }
  1024. if (AuthI.User) {
  1025. FreeADsStr(AuthI.User);
  1026. }
  1027. if (AuthI.Domain) {
  1028. FreeADsStr(AuthI.Domain);
  1029. }
  1030. if (AuthI.Password) {
  1031. FreeADsStr(AuthI.Password);
  1032. }
  1033. if (pszTempPwd) {
  1034. FreeADsMem(pszTempPwd);
  1035. }
  1036. if (pszHostName) {
  1037. FreeADsStr(pszHostName);
  1038. }
  1039. if (pszServer) {
  1040. FreeADsMem(pszServer);
  1041. }
  1042. #ifndef Win95
  1043. if (fImpersonating) {
  1044. //
  1045. // Try and call revert to self again
  1046. //
  1047. RevertToSelf();
  1048. }
  1049. #endif
  1050. if (hUserToken != INVALID_HANDLE_VALUE ) {
  1051. CloseHandle(hUserToken);
  1052. hUserToken = NULL;
  1053. }
  1054. VariantClear(&varSamAccount);
  1055. VariantClear(&varGetInfoEx);
  1056. RRETURN(hr);
  1057. }
  1058. STDMETHODIMP
  1059. CLDAPUser::ChangePassword(THIS_ BSTR bstrOldPassword, BSTR bstrNewPassword)
  1060. {
  1061. HRESULT hr = S_OK;
  1062. BOOLEAN bUseLDAP = FALSE;
  1063. LPWSTR pszServer = NULL;
  1064. LPWSTR pszHostName = NULL;
  1065. DWORD dwLen = 0;
  1066. int err = 0;
  1067. BSTR bstrADsPath = NULL;
  1068. LPWSTR szServerSSL = NULL;
  1069. LPWSTR szDn = NULL;
  1070. DWORD dwPortSSL = 0;
  1071. PADSLDP pAdsLdpSSL = NULL;
  1072. IADsObjOptPrivate * pADsPrivObjectOptions = NULL;
  1073. PADSLDP pAdsLdp = NULL;
  1074. LDAPMessage *pMsgResult = NULL;
  1075. LDAPMessage *pMsgEntry = NULL;
  1076. LDAP *pLdapCurrent = NULL;
  1077. LPWSTR Attributes[] = {L"objectClass", NULL};
  1078. VARIANT varSamAccount;
  1079. DWORD dwServerSSLSupport = 0;
  1080. LPWSTR pszNewPassword = NULL;
  1081. LPWSTR pszOldPassword = NULL;
  1082. VARIANT varGetInfoEx;
  1083. SEC_WINNT_AUTH_IDENTITY AuthI;
  1084. BOOL fImpersonating = FALSE;
  1085. HANDLE hUserToken = INVALID_HANDLE_VALUE;
  1086. VariantInit(&varSamAccount);
  1087. VariantInit(&varGetInfoEx);
  1088. memset(&AuthI, 0, sizeof(SEC_WINNT_AUTH_IDENTITY));
  1089. //
  1090. // Get the Ldap path of the user object
  1091. //
  1092. hr = _pADs->get_ADsPath( &bstrADsPath );
  1093. BAIL_ON_FAILURE(hr);
  1094. hr = BuildLDAPPathFromADsPath2(
  1095. bstrADsPath,
  1096. &szServerSSL,
  1097. &szDn,
  1098. &dwPortSSL
  1099. );
  1100. BAIL_ON_FAILURE(hr);
  1101. //
  1102. // Now do an LDAP Search with Referrals and get the handle to success
  1103. // connection. This is where we can find the server the referred object
  1104. // resides on
  1105. //
  1106. hr = _pADs->QueryInterface(
  1107. IID_IADsObjOptPrivate,
  1108. (void **)&pADsPrivObjectOptions
  1109. );
  1110. BAIL_ON_FAILURE(hr);
  1111. hr = pADsPrivObjectOptions->GetOption (
  1112. LDAP_SERVER,
  1113. (void *)&pszHostName
  1114. );
  1115. BAIL_ON_FAILURE(hr);
  1116. //
  1117. // additional length 3 is for '\0' and "\\\\"
  1118. //
  1119. dwLen = STRING_LENGTH(pszHostName) + 3;
  1120. pszServer = (LPWSTR) AllocADsMem( dwLen * sizeof(WCHAR) );
  1121. if (!pszServer) {
  1122. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1123. }
  1124. wcscpy(pszServer,L"\\\\");
  1125. wcscat(pszServer, pszHostName);
  1126. dwServerSSLSupport = ReadServerSupportsSSL(pszHostName);
  1127. if (dwServerSSLSupport == SERVER_STATUS_UNKNOWN
  1128. || !(dwServerSSLSupport & SERVER_DOES_NOT_SUPPORT_SSL)) {
  1129. //
  1130. // Try to establish SSL connection for this Password Operation
  1131. //
  1132. hr = LdapOpenObject(
  1133. pszHostName,
  1134. szDn,
  1135. &pAdsLdpSSL,
  1136. _Credentials,
  1137. 636
  1138. );
  1139. if (SUCCEEDED(hr)) {
  1140. int retval;
  1141. SecPkgContext_ConnectionInfo sslattr;
  1142. retval = ldap_get_option( pAdsLdpSSL->LdapHandle, LDAP_OPT_SSL_INFO, &sslattr );
  1143. if (retval == LDAP_SUCCESS) {
  1144. //
  1145. // If Channel is secure enough, enable LDAP Password Change
  1146. //
  1147. if (sslattr.dwCipherStrength >= 128) {
  1148. bUseLDAP = TRUE;
  1149. }
  1150. }
  1151. }
  1152. //
  1153. // Update the SSL support if appropriate
  1154. //
  1155. if (dwServerSSLSupport == SERVER_STATUS_UNKNOWN
  1156. || !bUseLDAP) {
  1157. UpdateServerSSLSupportStatus(
  1158. pszHostName,
  1159. bUseLDAP ?
  1160. dwServerSSLSupport :
  1161. dwServerSSLSupport |= SERVER_DOES_NOT_SUPPORT_SSL
  1162. );
  1163. }
  1164. }
  1165. if (bUseLDAP) {
  1166. //
  1167. // LDAP Password Set
  1168. //
  1169. PLDAPModW prgMod[3];
  1170. LDAPModW ModDelete;
  1171. LDAPModW ModAdd;
  1172. int iOldPwdLen, iNewPwdLen;
  1173. struct berval* rgBerVal[2];
  1174. struct berval* rgBerVal2[2];
  1175. struct berval BerVal;
  1176. struct berval BerVal2;
  1177. prgMod[0] = &ModDelete;
  1178. prgMod[1] = &ModAdd;
  1179. prgMod[2] = NULL;
  1180. ModDelete.mod_op = LDAP_MOD_DELETE | LDAP_MOD_BVALUES;
  1181. ModDelete.mod_type = L"unicodePwd";
  1182. ModDelete.mod_bvalues = rgBerVal;
  1183. rgBerVal[0] = &BerVal;
  1184. rgBerVal[1] = NULL;
  1185. //
  1186. // Put old pwd in quotes.
  1187. //
  1188. if (bstrOldPassword) {
  1189. iOldPwdLen = (wcslen(bstrOldPassword) + 2) * sizeof(WCHAR);
  1190. }
  1191. else {
  1192. iOldPwdLen = 2 * sizeof(WCHAR);
  1193. }
  1194. pszOldPassword = (LPWSTR) AllocADsMem((iOldPwdLen+1) * sizeof(WCHAR));
  1195. if (!pszOldPassword) {
  1196. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1197. }
  1198. wcscpy(pszOldPassword, L"\"");
  1199. if (bstrOldPassword) {
  1200. wcscat(pszOldPassword, bstrOldPassword);
  1201. }
  1202. wcscat(pszOldPassword, L"\"");
  1203. BerVal.bv_len = iOldPwdLen;
  1204. BerVal.bv_val = (char*)pszOldPassword;
  1205. ModAdd.mod_op = LDAP_MOD_ADD | LDAP_MOD_BVALUES;
  1206. ModAdd.mod_type = L"unicodePwd";
  1207. ModAdd.mod_bvalues = rgBerVal2;
  1208. rgBerVal2[0] = &BerVal2;
  1209. rgBerVal2[1] = NULL;
  1210. //
  1211. // Put new password in ""
  1212. //
  1213. if (bstrNewPassword) {
  1214. iNewPwdLen = (wcslen(bstrNewPassword) + 2) * sizeof(WCHAR);
  1215. }
  1216. else {
  1217. iNewPwdLen = 2 * sizeof(WCHAR);
  1218. }
  1219. pszNewPassword = (LPWSTR) AllocADsMem(iNewPwdLen + sizeof(WCHAR));
  1220. if (!pszNewPassword) {
  1221. BAIL_ON_FAILURE(hr = E_FAIL);
  1222. }
  1223. wcscpy(pszNewPassword, L"\"");
  1224. if (bstrNewPassword) {
  1225. wcscat(pszNewPassword, bstrNewPassword);
  1226. }
  1227. wcscat(pszNewPassword, L"\"");
  1228. BerVal2.bv_len = iNewPwdLen;
  1229. BerVal2.bv_val = (char*)pszNewPassword;
  1230. hr = LdapModifyS(
  1231. pAdsLdpSSL,
  1232. szDn,
  1233. prgMod
  1234. );
  1235. BAIL_ON_FAILURE(hr);
  1236. }
  1237. else {
  1238. //
  1239. // Password Set using NET APIs
  1240. //
  1241. NET_API_STATUS nasStatus;
  1242. DWORD dwParmErr = 0;
  1243. LPWSTR pszSamAccountArr[] = {L"sAMAccountName"};
  1244. //
  1245. // Get SamAccountName
  1246. //
  1247. hr = ADsBuildVarArrayStr( pszSamAccountArr, 1, &varGetInfoEx );
  1248. BAIL_ON_FAILURE(hr);
  1249. hr = _pADs->GetInfoEx(varGetInfoEx, 0);
  1250. BAIL_ON_FAILURE(hr);
  1251. hr = _pADs->Get(L"sAMAccountName", &varSamAccount);
  1252. BAIL_ON_FAILURE(hr);
  1253. #ifndef Win95
  1254. //
  1255. // At this point if the user credentials are non NULL,
  1256. // we want to impersonate the user and then make this call.
  1257. // This will make sure the NetUserChangePassword call is made in the
  1258. // correct context.
  1259. //
  1260. if (!_Credentials.IsNullCredentials()) {
  1261. //
  1262. // Need to get the userName and password in the format
  1263. // usable by the logonUser call.
  1264. //
  1265. hr = GetAuthIdentityForCaller(
  1266. _Credentials,
  1267. _pADs,
  1268. &AuthI,
  1269. FALSE
  1270. );
  1271. if SUCCEEDED(hr) {
  1272. //
  1273. // Note that if this code is backported, then we might
  1274. // need to change LOGON32_PROVIDER_WINNT50 to
  1275. // LOGON32_PROVIDER_DEFAULT as NT4 and below will support
  1276. // only that option. Also note that Win2k and below, do not
  1277. // allow all accounts to impersonate.
  1278. //
  1279. if (LogonUser(
  1280. AuthI.User,
  1281. AuthI.Domain,
  1282. AuthI.Password,
  1283. LOGON32_LOGON_NEW_CREDENTIALS,
  1284. LOGON32_PROVIDER_DEFAULT,
  1285. &hUserToken
  1286. )
  1287. ) {
  1288. //
  1289. // Call succeeded so we should use this context.
  1290. //
  1291. if (ImpersonateLoggedOnUser(hUserToken)) {
  1292. fImpersonating = TRUE;
  1293. }
  1294. }
  1295. } // if we could successfully get the auth ident structure.
  1296. //
  1297. // We will continue to make the ChangePassword call even if
  1298. // we could not impersonate successfully.
  1299. //
  1300. } // if credentials are valid.
  1301. #endif
  1302. //
  1303. // Do the actual change password
  1304. //
  1305. nasStatus = NetUserChangePassword(
  1306. pszServer,
  1307. V_BSTR(&varSamAccount),
  1308. bstrOldPassword,
  1309. bstrNewPassword
  1310. );
  1311. #ifndef Win95
  1312. if (fImpersonating) {
  1313. if (RevertToSelf()) {
  1314. fImpersonating = FALSE;
  1315. }
  1316. else {
  1317. ADsAssert(!"Revert to self failed.");
  1318. BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(GetLastError()));
  1319. }
  1320. }
  1321. #endif
  1322. if ( nasStatus == NERR_UserNotFound ) // User not created yet
  1323. {
  1324. hr = E_ADS_OBJECT_UNBOUND;
  1325. BAIL_ON_FAILURE(hr);
  1326. }
  1327. hr = HRESULT_FROM_WIN32(nasStatus);
  1328. BAIL_ON_FAILURE(hr);
  1329. }
  1330. error:
  1331. if (bstrADsPath) {
  1332. ADsFreeString(bstrADsPath);
  1333. }
  1334. if (szServerSSL) {
  1335. FreeADsStr(szServerSSL);
  1336. }
  1337. if (szDn) {
  1338. FreeADsStr(szDn);
  1339. }
  1340. if (pAdsLdpSSL) {
  1341. LdapCloseObject(pAdsLdpSSL);
  1342. }
  1343. if (pADsPrivObjectOptions) {
  1344. pADsPrivObjectOptions->Release();
  1345. }
  1346. if (pMsgResult) {
  1347. LdapMsgFree(pMsgResult);
  1348. }
  1349. if (pszOldPassword) {
  1350. FreeADsMem(pszOldPassword);
  1351. }
  1352. if (pszNewPassword) {
  1353. FreeADsMem(pszNewPassword);
  1354. }
  1355. if (AuthI.User) {
  1356. FreeADsStr(AuthI.User);
  1357. }
  1358. if (AuthI.Domain) {
  1359. FreeADsStr(AuthI.Domain);
  1360. }
  1361. if (AuthI.Password) {
  1362. FreeADsStr(AuthI.Password);
  1363. }
  1364. if (pszHostName) {
  1365. FreeADsStr(pszHostName);
  1366. }
  1367. if (pszServer) {
  1368. FreeADsMem(pszServer);
  1369. }
  1370. #ifndef Win95
  1371. if (fImpersonating) {
  1372. //
  1373. // Try and call revert to self again
  1374. //
  1375. RevertToSelf();
  1376. }
  1377. #endif
  1378. if (hUserToken != INVALID_HANDLE_VALUE ) {
  1379. CloseHandle(hUserToken);
  1380. hUserToken = NULL;
  1381. }
  1382. VariantClear(&varSamAccount);
  1383. VariantClear(&varGetInfoEx);
  1384. RRETURN(hr);
  1385. }
  1386. //+---------------------------------------------------------------------------
  1387. //
  1388. // GetDomainDNSNameFromHost
  1389. //
  1390. // Given the domain dns name for a host, we need to get hold of the
  1391. // dns name for the domain.
  1392. //
  1393. // Arguments:
  1394. // [szHostName] - name of server.
  1395. // [Credentials] - Credentials to use for bind.
  1396. // [dwPort] - Port to connect to server on.
  1397. // [ppszHostName] - ptr to string for retval.
  1398. //
  1399. // Returns:
  1400. // S_OK - If operation succeeds.
  1401. // E_* - For other cases.
  1402. //
  1403. //----------------------------------------------------------------------------
  1404. HRESULT
  1405. GetDomainDNSNameFromHost(
  1406. LPWSTR szHostName,
  1407. SEC_WINNT_AUTH_IDENTITY& AuthI,
  1408. CCredentials& Credentials,
  1409. DWORD dwPort,
  1410. LPWSTR * ppszHostName
  1411. )
  1412. {
  1413. HRESULT hr = S_OK;
  1414. PADSLDP ld = NULL;
  1415. LPTSTR *aValuesNamingContext = NULL;
  1416. IADsNameTranslate *pNameTranslate = NULL;
  1417. BSTR bstrName = NULL;
  1418. int nCount = 0;
  1419. //
  1420. // Bind to the ROOTDSE of the server.
  1421. //
  1422. hr = LdapOpenObject(
  1423. szHostName,
  1424. NULL, // the DN.
  1425. &ld,
  1426. Credentials,
  1427. dwPort
  1428. );
  1429. BAIL_ON_FAILURE(hr);
  1430. //
  1431. // Now get the defaultNamingContext
  1432. //
  1433. hr = LdapReadAttributeFast(
  1434. ld,
  1435. NULL, // the DN.
  1436. LDAP_OPATT_DEFAULT_NAMING_CONTEXT_W,
  1437. &aValuesNamingContext,
  1438. &nCount
  1439. );
  1440. //
  1441. // Verify we actuall got back at least one value
  1442. //
  1443. if (SUCCEEDED(hr) && (nCount < 1)) {
  1444. hr = HRESULT_FROM_WIN32(ERROR_DS_NO_ATTRIBUTE_OR_VALUE);
  1445. }
  1446. BAIL_ON_FAILURE(hr);
  1447. //
  1448. // Create nametran object
  1449. //
  1450. hr = CoCreateInstance(
  1451. CLSID_NameTranslate,
  1452. NULL,
  1453. CLSCTX_ALL,
  1454. IID_IADsNameTranslate,
  1455. (void **) &pNameTranslate
  1456. );
  1457. BAIL_ON_FAILURE(hr);
  1458. //
  1459. // Init with defaultNamingContext and get transalte
  1460. //
  1461. hr = pNameTranslate->InitEx(
  1462. ADS_NAME_INITTYPE_SERVER,
  1463. szHostName,
  1464. AuthI.User,
  1465. AuthI.Domain,
  1466. AuthI.Password
  1467. );
  1468. BAIL_ON_FAILURE(hr);
  1469. hr = pNameTranslate->Set(
  1470. ADS_NAME_TYPE_1779,
  1471. aValuesNamingContext[0]
  1472. );
  1473. BAIL_ON_FAILURE(hr);
  1474. hr = pNameTranslate->Get(
  1475. ADS_NAME_TYPE_CANONICAL,
  1476. &bstrName
  1477. );
  1478. BAIL_ON_FAILURE(hr);
  1479. if (!bstrName) {
  1480. BAIL_ON_FAILURE(hr = E_FAIL);
  1481. }
  1482. *ppszHostName = AllocADsStr(bstrName);
  1483. if (!*ppszHostName) {
  1484. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1485. }
  1486. //
  1487. // Null terminate one place ahead so we can get rid of /
  1488. //
  1489. (*ppszHostName)[wcslen(bstrName)-1] = L'\0';
  1490. error :
  1491. if (ld) {
  1492. LdapCloseObject(ld);
  1493. }
  1494. if (pNameTranslate) {
  1495. pNameTranslate->Release();
  1496. }
  1497. if (bstrName) {
  1498. SysFreeString(bstrName);
  1499. }
  1500. if (aValuesNamingContext) {
  1501. LdapValueFree(aValuesNamingContext);
  1502. }
  1503. RRETURN(hr);
  1504. }