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.

2045 lines
56 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. SecureZeroMemory(passwd, wcslen(passwd)*sizeof(WCHAR));
  308. FreeADsStr(passwd);
  309. }
  310. }
  311. if (pADsPrivObjectOptions) {
  312. pADsPrivObjectOptions->Release();
  313. }
  314. //
  315. // Always free the dn
  316. //
  317. if (dn) {
  318. FreeADsStr(dn);
  319. }
  320. if (pszDefaultServer) {
  321. FreeADsMem(pszDefaultServer);
  322. }
  323. RRETURN(hr);
  324. }
  325. #endif
  326. // Class CLDAPUser
  327. STDMETHODIMP
  328. CLDAPUser::get_AccountDisabled(THIS_ VARIANT_BOOL FAR* retval)
  329. {
  330. if ( retval == NULL )
  331. RRETURN( E_ADS_BAD_PARAMETER );
  332. LONG lUserAcctControl;
  333. HRESULT hr = get_LONG_Property( (IADsUser *)this,
  334. TEXT("userAccountControl"),
  335. &lUserAcctControl );
  336. if ( SUCCEEDED(hr))
  337. *retval = lUserAcctControl & UF_ACCOUNTDISABLE ?
  338. VARIANT_TRUE : VARIANT_FALSE;
  339. RRETURN(hr);
  340. }
  341. STDMETHODIMP
  342. CLDAPUser::put_AccountDisabled(THIS_ VARIANT_BOOL fAccountDisabled)
  343. {
  344. LONG lUserAcctControl;
  345. IADsObjOptPrivate * pADsPrivObjectOptions = NULL;
  346. BOOL fSet = FALSE;
  347. HRESULT hr = get_LONG_Property( (IADsUser *)this,
  348. TEXT("userAccountControl"),
  349. &lUserAcctControl );
  350. if ( SUCCEEDED(hr))
  351. {
  352. if ( fAccountDisabled )
  353. lUserAcctControl |= UF_ACCOUNTDISABLE;
  354. else
  355. lUserAcctControl &= ~UF_ACCOUNTDISABLE;
  356. hr = _pADs->QueryInterface(
  357. IID_IADsObjOptPrivate,
  358. (void **)&pADsPrivObjectOptions
  359. );
  360. if(SUCCEEDED(hr))
  361. {
  362. hr = pADsPrivObjectOptions->GetOption (
  363. LDAP_USERACCOUNTCONTROL,
  364. (void*)&fSet
  365. );
  366. }
  367. if(!fSet)
  368. {
  369. lUserAcctControl |= UF_LOCKOUT;
  370. }
  371. hr = put_LONG_Property( (IADsUser *)this,
  372. TEXT("userAccountControl"),
  373. lUserAcctControl );
  374. }
  375. if(pADsPrivObjectOptions)
  376. pADsPrivObjectOptions->Release();
  377. RRETURN(hr);
  378. }
  379. STDMETHODIMP
  380. CLDAPUser::get_AccountExpirationDate(THIS_ DATE FAR* retval)
  381. {
  382. GET_PROPERTY_FILETIME((IADsUser *)this, AccountExpirationDate);
  383. }
  384. STDMETHODIMP
  385. CLDAPUser::put_AccountExpirationDate(THIS_ DATE daAccountExpirationDate)
  386. {
  387. PUT_PROPERTY_FILETIME((IADsUser *)this, AccountExpirationDate);
  388. }
  389. STDMETHODIMP
  390. CLDAPUser::get_GraceLoginsAllowed(THIS_ long FAR* retval)
  391. {
  392. RRETURN(E_ADS_PROPERTY_NOT_SUPPORTED);
  393. }
  394. STDMETHODIMP
  395. CLDAPUser::put_GraceLoginsAllowed(THIS_ long lGraceLoginsAllowed)
  396. {
  397. RRETURN(E_ADS_PROPERTY_NOT_SUPPORTED);
  398. }
  399. STDMETHODIMP
  400. CLDAPUser::get_GraceLoginsRemaining(THIS_ long FAR* retval)
  401. {
  402. RRETURN(E_ADS_PROPERTY_NOT_SUPPORTED);
  403. }
  404. STDMETHODIMP
  405. CLDAPUser::put_GraceLoginsRemaining(THIS_ long lGraceLoginsRemaining)
  406. {
  407. RRETURN(E_ADS_PROPERTY_NOT_SUPPORTED);
  408. }
  409. STDMETHODIMP
  410. CLDAPUser::get_IsAccountLocked(THIS_ VARIANT_BOOL FAR* retval)
  411. {
  412. HRESULT hr = S_OK;
  413. VARIANT var;
  414. IADsLargeInteger *pLargeInt = NULL;
  415. LONG LowPart, HighPart;
  416. if ( retval == NULL )
  417. RRETURN( E_ADS_BAD_PARAMETER );
  418. VariantInit(&var);
  419. hr = _pADs->Get(TEXT("lockoutTime"), &var);
  420. if (SUCCEEDED(hr)) {
  421. //
  422. // There's a lockoutTime, we need to determine
  423. // if it equals 0 (== not locked-out).
  424. //
  425. ADsAssert(V_VT(&var) == VT_DISPATCH);
  426. if (V_VT(&var) != VT_DISPATCH) {
  427. BAIL_ON_FAILURE(hr = E_FAIL);
  428. }
  429. hr = V_DISPATCH(&var)->QueryInterface(IID_IADsLargeInteger,
  430. reinterpret_cast<void**>(&pLargeInt)
  431. );
  432. BAIL_ON_FAILURE(hr);
  433. hr = pLargeInt->get_LowPart(&LowPart);
  434. BAIL_ON_FAILURE(hr);
  435. hr = pLargeInt->get_HighPart(&HighPart);
  436. BAIL_ON_FAILURE(hr);
  437. if ( (LowPart != 0) || (HighPart != 0) ) {
  438. *retval = VARIANT_TRUE;
  439. }
  440. else {
  441. *retval = VARIANT_FALSE;
  442. }
  443. }
  444. else if (hr == E_ADS_PROPERTY_NOT_FOUND) {
  445. //
  446. // If there's no lockoutTime, the account is not
  447. // locked-out.
  448. //
  449. *retval = VARIANT_FALSE;
  450. hr = S_OK;
  451. }
  452. else {
  453. BAIL_ON_FAILURE(hr);
  454. }
  455. error:
  456. if (pLargeInt) {
  457. pLargeInt->Release();
  458. }
  459. VariantClear(&var);
  460. RRETURN(hr);
  461. }
  462. STDMETHODIMP
  463. CLDAPUser::put_IsAccountLocked(THIS_ VARIANT_BOOL fIsAccountLocked)
  464. {
  465. HRESULT hr = S_OK;
  466. if (fIsAccountLocked) {
  467. //
  468. // You cannot set an account to a locked state.
  469. //
  470. RRETURN(E_ADS_BAD_PARAMETER);
  471. }
  472. hr = put_LONG_Property( (IADsUser *)this,
  473. TEXT("lockoutTime"),
  474. 0 );
  475. RRETURN(hr);
  476. }
  477. STDMETHODIMP
  478. CLDAPUser::get_LoginHours(THIS_ VARIANT FAR* retval)
  479. {
  480. GET_PROPERTY_VARIANT((IADsUser *)this, LoginHours);
  481. }
  482. STDMETHODIMP
  483. CLDAPUser::put_LoginHours(THIS_ VARIANT vLoginHours)
  484. {
  485. PUT_PROPERTY_VARIANT((IADsUser *)this, LoginHours);
  486. }
  487. STDMETHODIMP
  488. CLDAPUser::get_LoginWorkstations(THIS_ VARIANT FAR* retval)
  489. {
  490. GET_PROPERTY_BSTRARRAY((IADsUser *)this,LoginWorkstations);
  491. }
  492. STDMETHODIMP
  493. CLDAPUser::put_LoginWorkstations(THIS_ VARIANT vLoginWorkstations)
  494. {
  495. PUT_PROPERTY_BSTRARRAY((IADsUser *)this,LoginWorkstations);
  496. }
  497. STDMETHODIMP
  498. CLDAPUser::get_MaxLogins(THIS_ long FAR* retval)
  499. {
  500. RRETURN(E_ADS_PROPERTY_NOT_SUPPORTED);
  501. }
  502. STDMETHODIMP
  503. CLDAPUser::put_MaxLogins(THIS_ long lMaxLogins)
  504. {
  505. RRETURN(E_ADS_PROPERTY_NOT_SUPPORTED);
  506. }
  507. STDMETHODIMP
  508. CLDAPUser::get_MaxStorage(THIS_ long FAR* retval)
  509. {
  510. GET_PROPERTY_LONG((IADsUser *)this, MaxStorage);
  511. }
  512. STDMETHODIMP
  513. CLDAPUser::put_MaxStorage(THIS_ long lMaxStorage)
  514. {
  515. PUT_PROPERTY_LONG((IADsUser *)this, MaxStorage);
  516. }
  517. STDMETHODIMP
  518. CLDAPUser::get_PasswordExpirationDate(THIS_ DATE FAR* retval)
  519. {
  520. GET_PROPERTY_DATE((IADsUser *)this, PasswordExpirationDate);
  521. }
  522. STDMETHODIMP
  523. CLDAPUser::put_PasswordExpirationDate(THIS_ DATE daPasswordExpirationDate)
  524. {
  525. PUT_PROPERTY_DATE((IADsUser *)this, PasswordExpirationDate);
  526. }
  527. STDMETHODIMP
  528. CLDAPUser::get_PasswordRequired(THIS_ VARIANT_BOOL FAR* retval)
  529. {
  530. if ( retval == NULL )
  531. RRETURN( E_ADS_BAD_PARAMETER );
  532. LONG lUserAcctControl;
  533. HRESULT hr = get_LONG_Property( (IADsUser *)this,
  534. TEXT("userAccountControl"),
  535. &lUserAcctControl );
  536. if ( SUCCEEDED(hr))
  537. *retval = lUserAcctControl & UF_PASSWD_NOTREQD ?
  538. VARIANT_FALSE: VARIANT_TRUE;
  539. RRETURN(hr);
  540. }
  541. STDMETHODIMP
  542. CLDAPUser::put_PasswordRequired(THIS_ VARIANT_BOOL fPasswordRequired)
  543. {
  544. LONG lUserAcctControl;
  545. IADsObjOptPrivate * pADsPrivObjectOptions = NULL;
  546. BOOL fSet = FALSE;
  547. HRESULT hr = get_LONG_Property( (IADsUser *)this,
  548. TEXT("userAccountControl"),
  549. &lUserAcctControl );
  550. if ( SUCCEEDED(hr))
  551. {
  552. if ( fPasswordRequired )
  553. lUserAcctControl &= ~UF_PASSWD_NOTREQD;
  554. else
  555. lUserAcctControl |= UF_PASSWD_NOTREQD;
  556. hr = _pADs->QueryInterface(
  557. IID_IADsObjOptPrivate,
  558. (void **)&pADsPrivObjectOptions
  559. );
  560. if(SUCCEEDED(hr))
  561. {
  562. hr = pADsPrivObjectOptions->GetOption (
  563. LDAP_USERACCOUNTCONTROL,
  564. (void*)&fSet
  565. );
  566. }
  567. if(!fSet)
  568. {
  569. lUserAcctControl |= UF_LOCKOUT;
  570. }
  571. hr = put_LONG_Property( (IADsUser *)this,
  572. TEXT("userAccountControl"),
  573. lUserAcctControl );
  574. }
  575. if(pADsPrivObjectOptions)
  576. pADsPrivObjectOptions->Release();
  577. RRETURN(hr);
  578. }
  579. STDMETHODIMP
  580. CLDAPUser::get_PasswordMinimumLength(THIS_ LONG FAR* retval)
  581. {
  582. GET_PROPERTY_LONG((IADsUser *)this, PasswordMinimumLength);
  583. }
  584. STDMETHODIMP
  585. CLDAPUser::put_PasswordMinimumLength(THIS_ LONG lPasswordMinimumLength)
  586. {
  587. PUT_PROPERTY_LONG((IADsUser *)this, PasswordMinimumLength);
  588. }
  589. STDMETHODIMP
  590. CLDAPUser::get_RequireUniquePassword(THIS_ VARIANT_BOOL FAR* retval)
  591. {
  592. GET_PROPERTY_VARIANT_BOOL((IADsUser *)this, RequireUniquePassword);
  593. }
  594. STDMETHODIMP
  595. CLDAPUser::put_RequireUniquePassword(THIS_ VARIANT_BOOL fRequireUniquePassword)
  596. {
  597. PUT_PROPERTY_VARIANT_BOOL((IADsUser *)this, RequireUniquePassword);
  598. }
  599. BOOLEAN
  600. _cdecl ServerCertCallback(
  601. PLDAP Connection,
  602. PCCERT_CONTEXT pServerCert
  603. )
  604. {
  605. //
  606. // After the secure connection is established, this function is called by
  607. // LDAP. This gives the client an opportunity to verify the server cert.
  608. // If, for some reason, the client doesn't approve it, it should return FALSE
  609. // and the connection will be terminated. Else, return TRUE
  610. //
  611. fprintf( stderr, "Server cert callback has been called...\n" );
  612. //
  613. // Use some way to verify the server certificate.
  614. //
  615. return TRUE;
  616. }
  617. STDMETHODIMP
  618. CLDAPUser::SetPassword(THIS_ BSTR bstrNewPassword)
  619. {
  620. HRESULT hr = E_FAIL;
  621. BOOLEAN bUseLDAP = FALSE;
  622. LPWSTR pszServer = NULL;
  623. LPWSTR pszHostName = NULL;
  624. DWORD dwLen = 0;
  625. int err = 0;
  626. BSTR bstrADsPath = NULL;
  627. LPWSTR szServerSSL = NULL;
  628. LPWSTR szDn = NULL;
  629. DWORD dwPortSSL = 0;
  630. PADSLDP pAdsLdpSSL = NULL;
  631. IADsObjOptPrivate * pADsPrivObjectOptions = NULL;
  632. PADSLDP pAdsLdp = NULL;
  633. LDAPMessage *pMsgResult = NULL;
  634. LDAPMessage *pMsgEntry = NULL;
  635. LDAP *pLdapCurrent = NULL;
  636. LPWSTR Attributes[] = {L"objectClass", NULL};
  637. VARIANT varSamAccount;
  638. DWORD dwServerPwdSupport = SERVER_STATUS_UNKNOWN;
  639. LPWSTR pszHostDomainName = NULL;
  640. SEC_WINNT_AUTH_IDENTITY AuthI;
  641. BOOLEAN fPasswordSet = FALSE;
  642. LPWSTR pszTempPwd = NULL;
  643. ULONG ulFlags = 0;
  644. VARIANT varGetInfoEx;
  645. BOOL fCachePrimed = FALSE;
  646. BOOL fImpersonating = FALSE;
  647. HANDLE hUserToken = INVALID_HANDLE_VALUE;
  648. IADsObjectOptions* pADsOpt = NULL;
  649. DWORD dwPasswordPort;
  650. DWORD dwPasswordMethod;
  651. VARIANT var;
  652. CCredentials cTempCred = _Credentials;
  653. //
  654. // Init params we will need to free later.
  655. //
  656. AuthI.User = NULL;
  657. AuthI.Domain = NULL;
  658. AuthI.Password = NULL;
  659. VariantInit(&varSamAccount);
  660. VariantInit(&varGetInfoEx);
  661. VariantInit(&var);
  662. //
  663. // Get the Ldap path of the user object
  664. //
  665. hr = _pADs->get_ADsPath( &bstrADsPath );
  666. BAIL_ON_FAILURE(hr);
  667. hr = BuildLDAPPathFromADsPath2(
  668. bstrADsPath,
  669. &szServerSSL,
  670. &szDn,
  671. &dwPortSSL
  672. );
  673. BAIL_ON_FAILURE(hr);
  674. //
  675. // Now do an LDAP Search with Referrals and get the handle to success
  676. // connection. This is where we can find the server the referred object
  677. // resides on
  678. //
  679. hr = _pADs->QueryInterface(
  680. IID_IADsObjOptPrivate,
  681. (void **)&pADsPrivObjectOptions
  682. );
  683. BAIL_ON_FAILURE(hr);
  684. hr = pADsPrivObjectOptions->GetOption (
  685. LDAP_SERVER,
  686. (void*)&pszHostName
  687. );
  688. BAIL_ON_FAILURE(hr);
  689. //
  690. // additional lengh 3 is for '\0' and "\\\\"
  691. //
  692. dwLen = STRING_LENGTH(pszHostName) + 3;
  693. pszServer = (LPWSTR) AllocADsMem( dwLen * sizeof(WCHAR) );
  694. if (!pszServer) {
  695. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  696. }
  697. wcscpy(pszServer,L"\\\\");
  698. wcscat(pszServer, pszHostName);
  699. // get the info of password port and password method (SSL or clear text)
  700. hr = _pADs->QueryInterface(
  701. IID_IADsObjectOptions,
  702. (void **)&pADsOpt
  703. );
  704. BAIL_ON_FAILURE(hr);
  705. hr = pADsOpt->GetOption(
  706. ADS_OPTION_PASSWORD_PORTNUMBER,
  707. &var
  708. );
  709. BAIL_ON_FAILURE(hr);
  710. dwPasswordPort = V_I4(&var);
  711. VariantClear(&var);
  712. hr = pADsOpt->GetOption(
  713. ADS_OPTION_PASSWORD_METHOD,
  714. &var
  715. );
  716. BAIL_ON_FAILURE(hr);
  717. dwPasswordMethod = V_I4(&var);
  718. if(dwPasswordMethod == ADS_PASSWORD_ENCODE_REQUIRE_SSL)
  719. {
  720. dwServerPwdSupport = ReadServerSupportsSSL(pszHostName);
  721. if (dwServerPwdSupport ==
  722. ( SERVER_STATUS_UNKNOWN
  723. | SERVER_DOES_NOT_SUPPORT_SSL
  724. | SERVER_DOES_NOT_SUPPORT_NETUSER
  725. | SERVER_DOES_NOT_SUPPORT_KERBEROS )
  726. )
  727. {
  728. //
  729. // All flags are set, we will reset and rebuild cache
  730. //
  731. UpdateServerSSLSupportStatus(
  732. pszHostName,
  733. SERVER_STATUS_UNKNOWN
  734. );
  735. dwServerPwdSupport = SERVER_STATUS_UNKNOWN;
  736. }
  737. if (dwServerPwdSupport == SERVER_STATUS_UNKNOWN
  738. || !(dwServerPwdSupport & SERVER_DOES_NOT_SUPPORT_SSL)) {
  739. //
  740. // Try to establish SSL connection for this Password Operation
  741. //
  742. // if NULL credential is passed in and auth flag does not contain secure auth, we need to make sure we keep
  743. // the default behavior: first try secure auth over SSL, then do anonymous bind over SSL
  744. if(cTempCred.IsNullCredentials() && !(cTempCred.GetAuthFlags() & ADS_SECURE_AUTHENTICATION))
  745. {
  746. cTempCred.SetAuthFlags(cTempCred.GetAuthFlags() | ADS_USE_SSL | ADS_SECURE_AUTHENTICATION);
  747. hr = LdapOpenObject(
  748. pszHostName,
  749. szDn,
  750. &pAdsLdpSSL,
  751. cTempCred,
  752. dwPasswordPort
  753. );
  754. // check ERROR_LOGON_FAILURE to be consistent witht the behavior of LdapOpenBindWithDefaultCredentials when
  755. // credential is null and auth flag is 0
  756. if (FAILED(hr) && hr != ERROR_LOGON_FAILURE)
  757. {
  758. cTempCred.SetAuthFlags(cTempCred.GetAuthFlags() & ~ADS_SECURE_AUTHENTICATION);
  759. hr = LdapOpenObject(
  760. pszHostName,
  761. szDn,
  762. &pAdsLdpSSL,
  763. cTempCred,
  764. dwPasswordPort
  765. );
  766. }
  767. }
  768. else
  769. {
  770. cTempCred.SetAuthFlags(cTempCred.GetAuthFlags() | ADS_USE_SSL);
  771. hr = LdapOpenObject(
  772. pszHostName,
  773. szDn,
  774. &pAdsLdpSSL,
  775. cTempCred,
  776. dwPasswordPort
  777. );
  778. }
  779. if (SUCCEEDED(hr)) {
  780. int retval;
  781. SecPkgContext_ConnectionInfo sslattr;
  782. retval = ldap_get_option( pAdsLdpSSL->LdapHandle, LDAP_OPT_SSL_INFO, &sslattr );
  783. if (retval == LDAP_SUCCESS) {
  784. //
  785. // If Channel is secure enough, enable LDAP Password Change
  786. //
  787. if (sslattr.dwCipherStrength >= 128) {
  788. bUseLDAP = TRUE;
  789. }
  790. }
  791. }
  792. //
  793. // Update the SSL support if appropriate
  794. //
  795. if (dwServerPwdSupport == SERVER_STATUS_UNKNOWN
  796. || !bUseLDAP) {
  797. //
  798. // Set the server does not support ssl bit if necessary
  799. //
  800. UpdateServerSSLSupportStatus(
  801. pszHostName,
  802. bUseLDAP ?
  803. dwServerPwdSupport :
  804. dwServerPwdSupport |= SERVER_DOES_NOT_SUPPORT_SSL
  805. );
  806. }
  807. }
  808. }
  809. else
  810. {
  811. cTempCred.SetAuthFlags(cTempCred.GetAuthFlags() & ~ADS_USE_SSL);
  812. hr = LdapOpenObject(
  813. pszHostName,
  814. szDn,
  815. &pAdsLdpSSL,
  816. cTempCred,
  817. dwPasswordPort
  818. );
  819. if(SUCCEEDED(hr))
  820. bUseLDAP = TRUE;
  821. }
  822. if (bUseLDAP) {
  823. //
  824. // LDAP Password Set
  825. //
  826. PLDAPModW prgMod[2];
  827. LDAPModW ModReplace;
  828. struct berval* rgBerVal[2];
  829. struct berval BerVal;
  830. int ipwdLen;
  831. prgMod[0] = &ModReplace;
  832. prgMod[1] = NULL;
  833. ModReplace.mod_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
  834. ModReplace.mod_type = L"unicodePwd";
  835. ModReplace.mod_bvalues = rgBerVal;
  836. rgBerVal[0] = &BerVal;
  837. rgBerVal[1] = NULL;
  838. //
  839. // 2 extra for "" to put the password in.
  840. //
  841. if (bstrNewPassword) {
  842. ipwdLen = (wcslen(bstrNewPassword) + 2) * sizeof(WCHAR);
  843. }
  844. else {
  845. ipwdLen = 2 * sizeof(WCHAR);
  846. }
  847. //
  848. // Add 1 for the \0.
  849. //
  850. pszTempPwd = (LPWSTR) AllocADsMem(ipwdLen + sizeof(WCHAR));
  851. if (!pszTempPwd) {
  852. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  853. }
  854. wcscpy(pszTempPwd, L"\"");
  855. if (bstrNewPassword) {
  856. wcscat(pszTempPwd, bstrNewPassword);
  857. }
  858. wcscat(pszTempPwd, L"\"");
  859. BerVal.bv_len = ipwdLen;
  860. BerVal.bv_val = (char*)pszTempPwd;
  861. hr = LdapModifyS(
  862. pAdsLdpSSL,
  863. szDn,
  864. prgMod
  865. );
  866. BAIL_ON_FAILURE(hr);
  867. //
  868. // Set flag so that we do not try any other methods.
  869. //
  870. fPasswordSet = TRUE;
  871. }
  872. //
  873. // Try kerberos setpassword if applicable
  874. //
  875. #if (!defined(WIN95))
  876. //
  877. // Only valid on Win2k
  878. //
  879. if (!fPasswordSet) {
  880. //
  881. // If we cached the server as not supporting Kerberos, most likely it
  882. // was because we were not mutually authenticated. Do a quick check to
  883. // see if that has changed, so that we can update our cached information
  884. // if necessary.
  885. //
  886. if (dwServerPwdSupport & SERVER_DOES_NOT_SUPPORT_KERBEROS) {
  887. hr = pADsPrivObjectOptions->GetOption (
  888. LDAP_MUTUAL_AUTH_STATUS,
  889. (void *) &ulFlags
  890. );
  891. BAIL_ON_FAILURE(hr);
  892. if ((ulFlags & KERB_SUPPORT_FLAGS)) {
  893. UpdateServerSSLSupportStatus(
  894. pszHostName,
  895. dwServerPwdSupport &= (~SERVER_DOES_NOT_SUPPORT_KERBEROS)
  896. );
  897. }
  898. }
  899. if (!(dwServerPwdSupport & SERVER_DOES_NOT_SUPPORT_KERBEROS)) {
  900. //
  901. // Kerberos set password
  902. //
  903. CredHandle secCredHandle = {0};
  904. SECURITY_STATUS SecStatus;
  905. DWORD dwStatus = 0;
  906. LPWSTR pszSamAccountArr[] = {L"sAMAccountName"};
  907. if (!fCachePrimed) {
  908. hr = ADsBuildVarArrayStr( pszSamAccountArr, 1, &varGetInfoEx );
  909. BAIL_ON_FAILURE(hr);
  910. hr = _pADs->GetInfoEx(varGetInfoEx, 0);
  911. BAIL_ON_FAILURE(hr);
  912. fCachePrimed = TRUE;
  913. }
  914. hr = _pADs->Get(L"sAMAccountName", &varSamAccount);
  915. BAIL_ON_FAILURE(hr);
  916. //
  917. // The AuthIdentity structure is ueful down the road.
  918. // This routine will fail if we were not bound using
  919. // kerberos to the server.
  920. //
  921. hr = GetAuthIdentityForCaller(
  922. _Credentials,
  923. _pADs,
  924. &AuthI,
  925. TRUE // enforce mutual auth.
  926. );
  927. if (FAILED(hr)) {
  928. UpdateServerSSLSupportStatus(
  929. pszHostName,
  930. dwServerPwdSupport |= SERVER_DOES_NOT_SUPPORT_KERBEROS
  931. );
  932. }
  933. else {
  934. //
  935. // Kerb really needs this handle.
  936. //
  937. hr = ConvertAuthIdentityToCredHandle(
  938. AuthI,
  939. &secCredHandle
  940. );
  941. if (FAILED(hr)) {
  942. UpdateServerSSLSupportStatus(
  943. pszHostName,
  944. dwServerPwdSupport |= SERVER_DOES_NOT_SUPPORT_KERBEROS
  945. );
  946. }
  947. if (SUCCEEDED(hr)) {
  948. //
  949. // Get the domain dns name for the user
  950. //
  951. hr = GetDomainDNSNameFromHost(
  952. pszHostName,
  953. AuthI,
  954. _Credentials,
  955. dwPortSSL,
  956. &pszHostDomainName
  957. );
  958. if (SUCCEEDED(hr)) {
  959. dwStatus = KerbSetPasswordUserEx(
  960. pszHostDomainName,
  961. V_BSTR(&varSamAccount),
  962. bstrNewPassword,
  963. &secCredHandle,
  964. pszHostName
  965. );
  966. if (dwStatus) {
  967. //
  968. // We should have got this to come in here.
  969. //
  970. hr = HRESULT_FROM_WIN32(ERROR_LOGON_FAILURE);
  971. }
  972. else {
  973. fPasswordSet = TRUE;
  974. }
  975. } // if domain dns name get succeeded.
  976. FreeCredentialsHandleWrapper(&secCredHandle);
  977. } // if GetCredentialsForCaller succeeded.
  978. } // if we could get authidentity succesfully
  979. } // if server supports kerberos
  980. } // if password not set.
  981. #endif
  982. //
  983. // At this point server status cannot be unknown, it
  984. // will atleast have info about ssl support.
  985. //
  986. if (!fPasswordSet) {
  987. if (!(dwServerPwdSupport & SERVER_DOES_NOT_SUPPORT_NETUSER)) {
  988. //
  989. // Password Set using NET APIs
  990. //
  991. NET_API_STATUS nasStatus;
  992. DWORD dwParmErr = 0;
  993. LPWSTR pszSamAccountArr[] = {L"sAMAccountName"};
  994. //
  995. // Get SamAccountName
  996. //
  997. VariantClear(&varSamAccount);
  998. VariantClear(&varGetInfoEx);
  999. if (!fCachePrimed) {
  1000. hr = ADsBuildVarArrayStr( pszSamAccountArr, 1, &varGetInfoEx );
  1001. BAIL_ON_FAILURE(hr);
  1002. hr = _pADs->GetInfoEx(varGetInfoEx, 0);
  1003. BAIL_ON_FAILURE(hr);
  1004. fCachePrimed = TRUE;
  1005. }
  1006. hr = _pADs->Get(L"sAMAccountName", &varSamAccount);
  1007. BAIL_ON_FAILURE(hr);
  1008. //
  1009. // Set the password
  1010. //
  1011. USER_INFO_1003 lpUserInfo1003 ;
  1012. lpUserInfo1003.usri1003_password = bstrNewPassword;
  1013. #ifndef Win95
  1014. //
  1015. // At this point if the user credentials are non NULL,
  1016. // we want to impersonate the user and then make this call.
  1017. // This will make sure the NetUserSetInfo call is made in the
  1018. // correct context.
  1019. //
  1020. if (!_Credentials.IsNullCredentials()) {
  1021. //
  1022. // Need to get the userName and password in the format
  1023. // usable by the logonUser call.
  1024. //
  1025. if ((AuthI.User == NULL)
  1026. && (AuthI.Domain == NULL)
  1027. && (AuthI.Password == NULL)
  1028. ) {
  1029. //
  1030. // Get teh Auth identity struct populate if necessary.
  1031. //
  1032. hr = GetAuthIdentityForCaller(
  1033. _Credentials,
  1034. _pADs,
  1035. &AuthI,
  1036. FALSE
  1037. );
  1038. }
  1039. BAIL_ON_FAILURE(hr);
  1040. //
  1041. // Note that if this code is backported, then we might
  1042. // need to change LOGON32_PROVIDER_WINNT50 to
  1043. // LOGON32_PROVIDER_DEFAULT as NT4 and below will support
  1044. // only that option. Also note that Win2k and below, do not
  1045. // allow all accounts to impersonate.
  1046. //
  1047. if (LogonUser(
  1048. AuthI.User,
  1049. AuthI.Domain,
  1050. AuthI.Password,
  1051. LOGON32_LOGON_NEW_CREDENTIALS,
  1052. LOGON32_PROVIDER_WINNT50,
  1053. &hUserToken
  1054. )
  1055. ) {
  1056. //
  1057. // Call succeeded so we should use this context.
  1058. //
  1059. if (ImpersonateLoggedOnUser(hUserToken)) {
  1060. fImpersonating = TRUE;
  1061. }
  1062. }
  1063. if (!fImpersonating) {
  1064. hr = HRESULT_FROM_WIN32(GetLastError());
  1065. }
  1066. BAIL_ON_FAILURE(hr);
  1067. } // if credentials are valid.
  1068. #endif
  1069. nasStatus = NetUserSetInfo(
  1070. pszServer,
  1071. V_BSTR(&varSamAccount),
  1072. 1003,
  1073. (LPBYTE)&lpUserInfo1003,
  1074. &dwParmErr
  1075. );
  1076. #ifndef Win95
  1077. if (fImpersonating) {
  1078. if (RevertToSelf()) {
  1079. fImpersonating = FALSE;
  1080. }
  1081. else {
  1082. ADsAssert(!"Revert to self failed.");
  1083. BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(GetLastError()));
  1084. }
  1085. }
  1086. #endif
  1087. if ( nasStatus == NERR_UserNotFound ) { // User not created yet
  1088. hr = E_ADS_OBJECT_UNBOUND;
  1089. BAIL_ON_FAILURE(hr);
  1090. }
  1091. hr = HRESULT_FROM_WIN32(nasStatus);
  1092. if (FAILED(hr) && (nasStatus == ERROR_LOGON_FAILURE)) {
  1093. //
  1094. // Was failure and ERROR_LOGON_FAILURE
  1095. //
  1096. UpdateServerSSLSupportStatus(
  1097. pszHostName,
  1098. dwServerPwdSupport |= SERVER_DOES_NOT_SUPPORT_NETUSER
  1099. );
  1100. //
  1101. // Need to free the variant as we will re-read in kerb
  1102. //
  1103. VariantClear(&varSamAccount);
  1104. }
  1105. else {
  1106. //
  1107. // password set succeed
  1108. //
  1109. fPasswordSet = TRUE;
  1110. }
  1111. }
  1112. } // if Password not set.
  1113. error:
  1114. if (bstrADsPath) {
  1115. ADsFreeString(bstrADsPath);
  1116. }
  1117. if (szServerSSL) {
  1118. FreeADsStr(szServerSSL);
  1119. }
  1120. if (szDn) {
  1121. FreeADsStr(szDn);
  1122. }
  1123. if (pAdsLdpSSL) {
  1124. LdapCloseObject(pAdsLdpSSL);
  1125. }
  1126. if (pADsPrivObjectOptions) {
  1127. pADsPrivObjectOptions->Release();
  1128. }
  1129. if (pADsOpt) {
  1130. pADsOpt->Release();
  1131. }
  1132. if (pMsgResult) {
  1133. LdapMsgFree(pMsgResult);
  1134. }
  1135. if (pszHostDomainName) {
  1136. FreeADsStr(pszHostDomainName);
  1137. }
  1138. if (AuthI.User) {
  1139. FreeADsStr(AuthI.User);
  1140. }
  1141. if (AuthI.Domain) {
  1142. FreeADsStr(AuthI.Domain);
  1143. }
  1144. if (AuthI.Password) {
  1145. SecureZeroMemory(AuthI.Password, AuthI.PasswordLength*sizeof(WCHAR));
  1146. FreeADsStr(AuthI.Password);
  1147. }
  1148. if (pszTempPwd) {
  1149. SecureZeroMemory(pszTempPwd, wcslen(pszTempPwd)*sizeof(WCHAR));
  1150. FreeADsMem(pszTempPwd);
  1151. }
  1152. if (pszHostName) {
  1153. FreeADsStr(pszHostName);
  1154. }
  1155. if (pszServer) {
  1156. FreeADsMem(pszServer);
  1157. }
  1158. #ifndef Win95
  1159. if (fImpersonating) {
  1160. //
  1161. // Try and call revert to self again
  1162. //
  1163. RevertToSelf();
  1164. }
  1165. #endif
  1166. if (hUserToken != INVALID_HANDLE_VALUE ) {
  1167. CloseHandle(hUserToken);
  1168. hUserToken = NULL;
  1169. }
  1170. VariantClear(&varSamAccount);
  1171. VariantClear(&varGetInfoEx);
  1172. VariantClear(&var);
  1173. RRETURN(hr);
  1174. }
  1175. STDMETHODIMP
  1176. CLDAPUser::ChangePassword(THIS_ BSTR bstrOldPassword, BSTR bstrNewPassword)
  1177. {
  1178. HRESULT hr = S_OK;
  1179. BOOLEAN bUseLDAP = FALSE;
  1180. LPWSTR pszServer = NULL;
  1181. LPWSTR pszHostName = NULL;
  1182. DWORD dwLen = 0;
  1183. int err = 0;
  1184. BSTR bstrADsPath = NULL;
  1185. LPWSTR szServerSSL = NULL;
  1186. LPWSTR szDn = NULL;
  1187. DWORD dwPortSSL = 0;
  1188. PADSLDP pAdsLdpSSL = NULL;
  1189. IADsObjOptPrivate * pADsPrivObjectOptions = NULL;
  1190. PADSLDP pAdsLdp = NULL;
  1191. LDAPMessage *pMsgResult = NULL;
  1192. LDAPMessage *pMsgEntry = NULL;
  1193. LDAP *pLdapCurrent = NULL;
  1194. LPWSTR Attributes[] = {L"objectClass", NULL};
  1195. VARIANT varSamAccount;
  1196. DWORD dwServerSSLSupport = 0;
  1197. LPWSTR pszNewPassword = NULL;
  1198. LPWSTR pszOldPassword = NULL;
  1199. VARIANT varGetInfoEx;
  1200. SEC_WINNT_AUTH_IDENTITY AuthI;
  1201. BOOL fImpersonating = FALSE;
  1202. HANDLE hUserToken = INVALID_HANDLE_VALUE;
  1203. IADsObjectOptions* pADsOpt = NULL;
  1204. DWORD dwPasswordPort;
  1205. DWORD dwPasswordMethod;
  1206. VARIANT var;
  1207. CCredentials cTempCred = _Credentials;
  1208. VariantInit(&varSamAccount);
  1209. VariantInit(&varGetInfoEx);
  1210. VariantInit(&var);
  1211. memset(&AuthI, 0, sizeof(SEC_WINNT_AUTH_IDENTITY));
  1212. //
  1213. // Get the Ldap path of the user object
  1214. //
  1215. hr = _pADs->get_ADsPath( &bstrADsPath );
  1216. BAIL_ON_FAILURE(hr);
  1217. hr = BuildLDAPPathFromADsPath2(
  1218. bstrADsPath,
  1219. &szServerSSL,
  1220. &szDn,
  1221. &dwPortSSL
  1222. );
  1223. BAIL_ON_FAILURE(hr);
  1224. //
  1225. // Now do an LDAP Search with Referrals and get the handle to success
  1226. // connection. This is where we can find the server the referred object
  1227. // resides on
  1228. //
  1229. hr = _pADs->QueryInterface(
  1230. IID_IADsObjOptPrivate,
  1231. (void **)&pADsPrivObjectOptions
  1232. );
  1233. BAIL_ON_FAILURE(hr);
  1234. hr = pADsPrivObjectOptions->GetOption (
  1235. LDAP_SERVER,
  1236. (void *)&pszHostName
  1237. );
  1238. BAIL_ON_FAILURE(hr);
  1239. //
  1240. // additional length 3 is for '\0' and "\\\\"
  1241. //
  1242. dwLen = STRING_LENGTH(pszHostName) + 3;
  1243. pszServer = (LPWSTR) AllocADsMem( dwLen * sizeof(WCHAR) );
  1244. if (!pszServer) {
  1245. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1246. }
  1247. wcscpy(pszServer,L"\\\\");
  1248. wcscat(pszServer, pszHostName);
  1249. // get the info of password port and password method (SSL or clear text)
  1250. hr = _pADs->QueryInterface(
  1251. IID_IADsObjectOptions,
  1252. (void **)&pADsOpt
  1253. );
  1254. BAIL_ON_FAILURE(hr);
  1255. hr = pADsOpt->GetOption(
  1256. ADS_OPTION_PASSWORD_PORTNUMBER,
  1257. &var
  1258. );
  1259. BAIL_ON_FAILURE(hr);
  1260. dwPasswordPort = V_I4(&var);
  1261. VariantClear(&var);
  1262. hr = pADsOpt->GetOption(
  1263. ADS_OPTION_PASSWORD_METHOD,
  1264. &var
  1265. );
  1266. BAIL_ON_FAILURE(hr);
  1267. dwPasswordMethod = V_I4(&var);
  1268. if(dwPasswordMethod == ADS_PASSWORD_ENCODE_REQUIRE_SSL)
  1269. {
  1270. dwServerSSLSupport = ReadServerSupportsSSL(pszHostName);
  1271. if (dwServerSSLSupport == SERVER_STATUS_UNKNOWN
  1272. || !(dwServerSSLSupport & SERVER_DOES_NOT_SUPPORT_SSL)) {
  1273. //
  1274. // Try to establish SSL connection for this Password Operation
  1275. //
  1276. // if NULL credential is passed in and auth flag does not contain secure auth, we need to make sure we keep
  1277. // the default behavior: first try secure auth over SSL, then do anonymous bind over SSL
  1278. if(cTempCred.IsNullCredentials() && !(cTempCred.GetAuthFlags() & ADS_SECURE_AUTHENTICATION))
  1279. {
  1280. cTempCred.SetAuthFlags(cTempCred.GetAuthFlags() | ADS_USE_SSL | ADS_SECURE_AUTHENTICATION);
  1281. hr = LdapOpenObject(
  1282. pszHostName,
  1283. szDn,
  1284. &pAdsLdpSSL,
  1285. cTempCred,
  1286. dwPasswordPort
  1287. );
  1288. // check ERROR_LOGON_FAILURE to be consistent witht the behavior of LdapOpenBindWithDefaultCredentials when
  1289. // credential is null and auth flag is 0
  1290. if (FAILED(hr) && hr != ERROR_LOGON_FAILURE)
  1291. {
  1292. cTempCred.SetAuthFlags(cTempCred.GetAuthFlags() & ~ADS_SECURE_AUTHENTICATION);
  1293. hr = LdapOpenObject(
  1294. pszHostName,
  1295. szDn,
  1296. &pAdsLdpSSL,
  1297. cTempCred,
  1298. dwPasswordPort
  1299. );
  1300. }
  1301. }
  1302. else
  1303. {
  1304. cTempCred.SetAuthFlags(cTempCred.GetAuthFlags() | ADS_USE_SSL);
  1305. hr = LdapOpenObject(
  1306. pszHostName,
  1307. szDn,
  1308. &pAdsLdpSSL,
  1309. cTempCred,
  1310. dwPasswordPort
  1311. );
  1312. }
  1313. if (SUCCEEDED(hr)) {
  1314. int retval;
  1315. SecPkgContext_ConnectionInfo sslattr;
  1316. retval = ldap_get_option( pAdsLdpSSL->LdapHandle, LDAP_OPT_SSL_INFO, &sslattr );
  1317. if (retval == LDAP_SUCCESS) {
  1318. //
  1319. // If Channel is secure enough, enable LDAP Password Change
  1320. //
  1321. if (sslattr.dwCipherStrength >= 128) {
  1322. bUseLDAP = TRUE;
  1323. }
  1324. }
  1325. }
  1326. //
  1327. // Update the SSL support if appropriate
  1328. //
  1329. if (dwServerSSLSupport == SERVER_STATUS_UNKNOWN
  1330. || !bUseLDAP) {
  1331. UpdateServerSSLSupportStatus(
  1332. pszHostName,
  1333. bUseLDAP ?
  1334. dwServerSSLSupport :
  1335. dwServerSSLSupport |= SERVER_DOES_NOT_SUPPORT_SSL
  1336. );
  1337. }
  1338. }
  1339. }
  1340. else
  1341. {
  1342. cTempCred.SetAuthFlags(cTempCred.GetAuthFlags() & ~ADS_USE_SSL);
  1343. hr = LdapOpenObject(
  1344. pszHostName,
  1345. szDn,
  1346. &pAdsLdpSSL,
  1347. cTempCred,
  1348. dwPasswordPort
  1349. );
  1350. if(SUCCEEDED(hr))
  1351. bUseLDAP = TRUE;
  1352. }
  1353. if (bUseLDAP) {
  1354. //
  1355. // LDAP Password Set
  1356. //
  1357. PLDAPModW prgMod[3];
  1358. LDAPModW ModDelete;
  1359. LDAPModW ModAdd;
  1360. int iOldPwdLen, iNewPwdLen;
  1361. struct berval* rgBerVal[2];
  1362. struct berval* rgBerVal2[2];
  1363. struct berval BerVal;
  1364. struct berval BerVal2;
  1365. prgMod[0] = &ModDelete;
  1366. prgMod[1] = &ModAdd;
  1367. prgMod[2] = NULL;
  1368. ModDelete.mod_op = LDAP_MOD_DELETE | LDAP_MOD_BVALUES;
  1369. ModDelete.mod_type = L"unicodePwd";
  1370. ModDelete.mod_bvalues = rgBerVal;
  1371. rgBerVal[0] = &BerVal;
  1372. rgBerVal[1] = NULL;
  1373. //
  1374. // Put old pwd in quotes.
  1375. //
  1376. if (bstrOldPassword) {
  1377. iOldPwdLen = (wcslen(bstrOldPassword) + 2) * sizeof(WCHAR);
  1378. }
  1379. else {
  1380. iOldPwdLen = 2 * sizeof(WCHAR);
  1381. }
  1382. pszOldPassword = (LPWSTR) AllocADsMem((iOldPwdLen+1) * sizeof(WCHAR));
  1383. if (!pszOldPassword) {
  1384. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1385. }
  1386. wcscpy(pszOldPassword, L"\"");
  1387. if (bstrOldPassword) {
  1388. wcscat(pszOldPassword, bstrOldPassword);
  1389. }
  1390. wcscat(pszOldPassword, L"\"");
  1391. BerVal.bv_len = iOldPwdLen;
  1392. BerVal.bv_val = (char*)pszOldPassword;
  1393. ModAdd.mod_op = LDAP_MOD_ADD | LDAP_MOD_BVALUES;
  1394. ModAdd.mod_type = L"unicodePwd";
  1395. ModAdd.mod_bvalues = rgBerVal2;
  1396. rgBerVal2[0] = &BerVal2;
  1397. rgBerVal2[1] = NULL;
  1398. //
  1399. // Put new password in ""
  1400. //
  1401. if (bstrNewPassword) {
  1402. iNewPwdLen = (wcslen(bstrNewPassword) + 2) * sizeof(WCHAR);
  1403. }
  1404. else {
  1405. iNewPwdLen = 2 * sizeof(WCHAR);
  1406. }
  1407. pszNewPassword = (LPWSTR) AllocADsMem(iNewPwdLen + sizeof(WCHAR));
  1408. if (!pszNewPassword) {
  1409. BAIL_ON_FAILURE(hr = E_FAIL);
  1410. }
  1411. wcscpy(pszNewPassword, L"\"");
  1412. if (bstrNewPassword) {
  1413. wcscat(pszNewPassword, bstrNewPassword);
  1414. }
  1415. wcscat(pszNewPassword, L"\"");
  1416. BerVal2.bv_len = iNewPwdLen;
  1417. BerVal2.bv_val = (char*)pszNewPassword;
  1418. hr = LdapModifyS(
  1419. pAdsLdpSSL,
  1420. szDn,
  1421. prgMod
  1422. );
  1423. BAIL_ON_FAILURE(hr);
  1424. }
  1425. else {
  1426. //
  1427. // Password Set using NET APIs
  1428. //
  1429. NET_API_STATUS nasStatus;
  1430. DWORD dwParmErr = 0;
  1431. LPWSTR pszSamAccountArr[] = {L"sAMAccountName"};
  1432. //
  1433. // Get SamAccountName
  1434. //
  1435. hr = ADsBuildVarArrayStr( pszSamAccountArr, 1, &varGetInfoEx );
  1436. BAIL_ON_FAILURE(hr);
  1437. hr = _pADs->GetInfoEx(varGetInfoEx, 0);
  1438. BAIL_ON_FAILURE(hr);
  1439. hr = _pADs->Get(L"sAMAccountName", &varSamAccount);
  1440. BAIL_ON_FAILURE(hr);
  1441. #ifndef Win95
  1442. //
  1443. // At this point if the user credentials are non NULL,
  1444. // we want to impersonate the user and then make this call.
  1445. // This will make sure the NetUserChangePassword call is made in the
  1446. // correct context.
  1447. //
  1448. if (!_Credentials.IsNullCredentials()) {
  1449. //
  1450. // Need to get the userName and password in the format
  1451. // usable by the logonUser call.
  1452. //
  1453. hr = GetAuthIdentityForCaller(
  1454. _Credentials,
  1455. _pADs,
  1456. &AuthI,
  1457. FALSE
  1458. );
  1459. if SUCCEEDED(hr) {
  1460. //
  1461. // Note that if this code is backported, then we might
  1462. // need to change LOGON32_PROVIDER_WINNT50 to
  1463. // LOGON32_PROVIDER_DEFAULT as NT4 and below will support
  1464. // only that option. Also note that Win2k and below, do not
  1465. // allow all accounts to impersonate.
  1466. //
  1467. if (LogonUser(
  1468. AuthI.User,
  1469. AuthI.Domain,
  1470. AuthI.Password,
  1471. LOGON32_LOGON_NEW_CREDENTIALS,
  1472. LOGON32_PROVIDER_DEFAULT,
  1473. &hUserToken
  1474. )
  1475. ) {
  1476. //
  1477. // Call succeeded so we should use this context.
  1478. //
  1479. if (ImpersonateLoggedOnUser(hUserToken)) {
  1480. fImpersonating = TRUE;
  1481. }
  1482. }
  1483. } // if we could successfully get the auth ident structure.
  1484. //
  1485. // We will continue to make the ChangePassword call even if
  1486. // we could not impersonate successfully.
  1487. //
  1488. } // if credentials are valid.
  1489. #endif
  1490. //
  1491. // Do the actual change password
  1492. //
  1493. nasStatus = NetUserChangePassword(
  1494. pszServer,
  1495. V_BSTR(&varSamAccount),
  1496. bstrOldPassword,
  1497. bstrNewPassword
  1498. );
  1499. #ifndef Win95
  1500. if (fImpersonating) {
  1501. if (RevertToSelf()) {
  1502. fImpersonating = FALSE;
  1503. }
  1504. else {
  1505. ADsAssert(!"Revert to self failed.");
  1506. BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(GetLastError()));
  1507. }
  1508. }
  1509. #endif
  1510. if ( nasStatus == NERR_UserNotFound ) // User not created yet
  1511. {
  1512. hr = E_ADS_OBJECT_UNBOUND;
  1513. BAIL_ON_FAILURE(hr);
  1514. }
  1515. hr = HRESULT_FROM_WIN32(nasStatus);
  1516. BAIL_ON_FAILURE(hr);
  1517. }
  1518. error:
  1519. if (bstrADsPath) {
  1520. ADsFreeString(bstrADsPath);
  1521. }
  1522. if (szServerSSL) {
  1523. FreeADsStr(szServerSSL);
  1524. }
  1525. if (szDn) {
  1526. FreeADsStr(szDn);
  1527. }
  1528. if (pAdsLdpSSL) {
  1529. LdapCloseObject(pAdsLdpSSL);
  1530. }
  1531. if (pADsPrivObjectOptions) {
  1532. pADsPrivObjectOptions->Release();
  1533. }
  1534. if (pADsOpt) {
  1535. pADsOpt->Release();
  1536. }
  1537. if (pMsgResult) {
  1538. LdapMsgFree(pMsgResult);
  1539. }
  1540. if (pszOldPassword) {
  1541. SecureZeroMemory(pszOldPassword, wcslen(pszOldPassword)*sizeof(WCHAR));
  1542. FreeADsMem(pszOldPassword);
  1543. }
  1544. if (pszNewPassword) {
  1545. SecureZeroMemory(pszNewPassword, wcslen(pszNewPassword)*sizeof(WCHAR));
  1546. FreeADsMem(pszNewPassword);
  1547. }
  1548. if (AuthI.User) {
  1549. FreeADsStr(AuthI.User);
  1550. }
  1551. if (AuthI.Domain) {
  1552. FreeADsStr(AuthI.Domain);
  1553. }
  1554. if (AuthI.Password) {
  1555. SecureZeroMemory(AuthI.Password, AuthI.PasswordLength*sizeof(WCHAR));
  1556. FreeADsStr(AuthI.Password);
  1557. }
  1558. if (pszHostName) {
  1559. FreeADsStr(pszHostName);
  1560. }
  1561. if (pszServer) {
  1562. FreeADsMem(pszServer);
  1563. }
  1564. #ifndef Win95
  1565. if (fImpersonating) {
  1566. //
  1567. // Try and call revert to self again
  1568. //
  1569. RevertToSelf();
  1570. }
  1571. #endif
  1572. if (hUserToken != INVALID_HANDLE_VALUE ) {
  1573. CloseHandle(hUserToken);
  1574. hUserToken = NULL;
  1575. }
  1576. VariantClear(&varSamAccount);
  1577. VariantClear(&varGetInfoEx);
  1578. VariantClear(&var);
  1579. RRETURN(hr);
  1580. }
  1581. //+---------------------------------------------------------------------------
  1582. //
  1583. // GetDomainDNSNameFromHost
  1584. //
  1585. // Given the domain dns name for a host, we need to get hold of the
  1586. // dns name for the domain.
  1587. //
  1588. // Arguments:
  1589. // [szHostName] - name of server.
  1590. // [Credentials] - Credentials to use for bind.
  1591. // [dwPort] - Port to connect to server on.
  1592. // [ppszHostName] - ptr to string for retval.
  1593. //
  1594. // Returns:
  1595. // S_OK - If operation succeeds.
  1596. // E_* - For other cases.
  1597. //
  1598. //----------------------------------------------------------------------------
  1599. HRESULT
  1600. GetDomainDNSNameFromHost(
  1601. LPWSTR szHostName,
  1602. SEC_WINNT_AUTH_IDENTITY& AuthI,
  1603. CCredentials& Credentials,
  1604. DWORD dwPort,
  1605. LPWSTR * ppszHostName
  1606. )
  1607. {
  1608. HRESULT hr = S_OK;
  1609. PADSLDP ld = NULL;
  1610. LPTSTR *aValuesNamingContext = NULL;
  1611. IADsNameTranslate *pNameTranslate = NULL;
  1612. BSTR bstrName = NULL;
  1613. int nCount = 0;
  1614. //
  1615. // Bind to the ROOTDSE of the server.
  1616. //
  1617. hr = LdapOpenObject(
  1618. szHostName,
  1619. NULL, // the DN.
  1620. &ld,
  1621. Credentials,
  1622. dwPort
  1623. );
  1624. BAIL_ON_FAILURE(hr);
  1625. //
  1626. // Now get the defaultNamingContext
  1627. //
  1628. hr = LdapReadAttributeFast(
  1629. ld,
  1630. NULL, // the DN.
  1631. LDAP_OPATT_DEFAULT_NAMING_CONTEXT_W,
  1632. &aValuesNamingContext,
  1633. &nCount
  1634. );
  1635. //
  1636. // Verify we actuall got back at least one value
  1637. //
  1638. if (SUCCEEDED(hr) && (nCount < 1)) {
  1639. hr = HRESULT_FROM_WIN32(ERROR_DS_NO_ATTRIBUTE_OR_VALUE);
  1640. }
  1641. BAIL_ON_FAILURE(hr);
  1642. //
  1643. // Create nametran object
  1644. //
  1645. hr = CoCreateInstance(
  1646. CLSID_NameTranslate,
  1647. NULL,
  1648. CLSCTX_ALL,
  1649. IID_IADsNameTranslate,
  1650. (void **) &pNameTranslate
  1651. );
  1652. BAIL_ON_FAILURE(hr);
  1653. //
  1654. // Init with defaultNamingContext and get transalte
  1655. //
  1656. hr = pNameTranslate->InitEx(
  1657. ADS_NAME_INITTYPE_SERVER,
  1658. szHostName,
  1659. AuthI.User,
  1660. AuthI.Domain,
  1661. AuthI.Password
  1662. );
  1663. BAIL_ON_FAILURE(hr);
  1664. hr = pNameTranslate->Set(
  1665. ADS_NAME_TYPE_1779,
  1666. aValuesNamingContext[0]
  1667. );
  1668. BAIL_ON_FAILURE(hr);
  1669. hr = pNameTranslate->Get(
  1670. ADS_NAME_TYPE_CANONICAL,
  1671. &bstrName
  1672. );
  1673. BAIL_ON_FAILURE(hr);
  1674. if (!bstrName) {
  1675. BAIL_ON_FAILURE(hr = E_FAIL);
  1676. }
  1677. *ppszHostName = AllocADsStr(bstrName);
  1678. if (!*ppszHostName) {
  1679. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1680. }
  1681. //
  1682. // Null terminate one place ahead so we can get rid of /
  1683. //
  1684. (*ppszHostName)[wcslen(bstrName)-1] = L'\0';
  1685. error :
  1686. if (ld) {
  1687. LdapCloseObject(ld);
  1688. }
  1689. if (pNameTranslate) {
  1690. pNameTranslate->Release();
  1691. }
  1692. if (bstrName) {
  1693. SysFreeString(bstrName);
  1694. }
  1695. if (aValuesNamingContext) {
  1696. LdapValueFree(aValuesNamingContext);
  1697. }
  1698. RRETURN(hr);
  1699. }