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.

5516 lines
174 KiB

  1. /*++
  2. Copyright (c) 1987-1996 Microsoft Corporation
  3. Module Name:
  4. lsrvutil.c
  5. Abstract:
  6. Utility functions for the netlogon service.
  7. Author:
  8. Ported from Lan Man 2.0
  9. Environment:
  10. User mode only.
  11. Contains NT-specific code.
  12. Requires ANSI C extensions: slash-slash comments, long external names.
  13. Revision History:
  14. 00-Jun-1989 (PradyM)
  15. modified lm10 code for new NETLOGON service
  16. 00-Feb-1990 (PradyM)
  17. bugfixes
  18. 00-Aug-1990 (t-RichE)
  19. added alerts for auth failure due to time slippage
  20. 11-Jul-1991 (cliffv)
  21. Ported to NT. Converted to NT style.
  22. 02-Jan-1992 (madana)
  23. added support for builtin/multidomain replication.
  24. --*/
  25. //
  26. // Common include files.
  27. //
  28. #include "logonsrv.h" // Include files common to entire service
  29. #pragma hdrstop
  30. //
  31. // Include files specific to this .c file
  32. //
  33. #include <accessp.h> // NetpAliasMemberToPriv
  34. #include <msgtext.h> // MTXT_* defines
  35. #include <netcan.h> // NetpwPathCompare()
  36. #include <ssiapi.h> // I_NetSamDeltas()
  37. /*lint -e740 */ /* don't complain about unusual cast */
  38. #define MAX_DC_AUTHENTICATION_WAIT (long) (45L*1000L) // 45 seconds
  39. //
  40. // We want to prevent too-frequent alerts from
  41. // being sent in case of Authentication failures.
  42. //
  43. #define MAX_ALERTS 10 // send one every 10 to 30 mins based on pulse
  44. VOID
  45. RaiseNetlogonAlert(
  46. IN DWORD alertNum,
  47. IN LPWSTR *AlertStrings,
  48. IN OUT DWORD *ptrAlertCount
  49. )
  50. /*++
  51. Routine Description:
  52. Raise an alert once per MAX_ALERTS occurances
  53. Arguments:
  54. alertNum -- RaiseAlert() alert number.
  55. AlertStrings -- RaiseAlert() arguments
  56. ptrAlertCount -- Points to the count of occurence of this particular
  57. alert. This routine increments it and will set it to that value
  58. modulo MAX_ALERTS.
  59. Return Value:
  60. NONE
  61. --*/
  62. {
  63. if (*ptrAlertCount == 0) {
  64. NetpRaiseAlert( SERVICE_NETLOGON, alertNum, AlertStrings);
  65. }
  66. (*ptrAlertCount)++;
  67. (*ptrAlertCount) %= MAX_ALERTS;
  68. }
  69. NTSTATUS
  70. NlOpenSecret(
  71. IN PCLIENT_SESSION ClientSession,
  72. IN ULONG DesiredAccess,
  73. OUT PLSAPR_HANDLE SecretHandle
  74. )
  75. /*++
  76. Routine Description:
  77. Open the Lsa Secret Object containing the password to be used for the
  78. specified client session.
  79. Arguments:
  80. ClientSession - Structure used to define the session.
  81. On Input, the following fields must be set:
  82. CsNetbiosDomainName
  83. CsSecureChannelType
  84. DesiredAccess - Access required to the secret.
  85. SecretHandle - Returns a handle to the secret.
  86. Return Value:
  87. Status of operation.
  88. --*/
  89. {
  90. NTSTATUS Status;
  91. UNICODE_STRING SecretNameString;
  92. NlAssert( ClientSession->CsReferenceCount > 0 );
  93. //
  94. // Only use secrets for workstation and BDC machine accounts.
  95. //
  96. switch ( ClientSession->CsSecureChannelType ) {
  97. case ServerSecureChannel:
  98. case WorkstationSecureChannel:
  99. RtlInitUnicodeString( &SecretNameString, SSI_SECRET_NAME );
  100. break;
  101. case TrustedDomainSecureChannel:
  102. case TrustedDnsDomainSecureChannel:
  103. default:
  104. Status = STATUS_INTERNAL_ERROR;
  105. NlPrint((NL_CRITICAL, "NlOpenSecret: Invalid account type\n"));
  106. return Status;
  107. }
  108. //
  109. // Get the Password of the account from LSA secret storage
  110. //
  111. Status = LsarOpenSecret(
  112. ClientSession->CsDomainInfo->DomLsaPolicyHandle,
  113. (PLSAPR_UNICODE_STRING)&SecretNameString,
  114. DesiredAccess,
  115. SecretHandle );
  116. return Status;
  117. }
  118. NTSTATUS
  119. NlGetOutgoingPassword(
  120. IN PCLIENT_SESSION ClientSession,
  121. OUT PUNICODE_STRING *CurrentValue,
  122. OUT PUNICODE_STRING *OldValue,
  123. OUT PDWORD CurrentVersionNumber,
  124. OUT PLARGE_INTEGER LastSetTime OPTIONAL
  125. )
  126. /*++
  127. Routine Description:
  128. Get the outgoing password to be used for the specified client session.
  129. Arguments:
  130. ClientSession - Structure used to define the session.
  131. On Input, the following fields must be set:
  132. CsNetbiosDomainName
  133. CsSecureChannelType
  134. CurrentValue - Current password for the client session.
  135. CurrentValue should be freed using LocalFree
  136. A NULL pointer is returned if there is no current password.
  137. OldValue - Previous password for the client session.
  138. OldValue should be freed using LocalFree
  139. A NULL pointer is returned if there is no old password.
  140. CurrentVersionNumber - Version number of the current password
  141. for interdomain trust account. Set to 0 on failure status
  142. or if this is not interdomain trust account.
  143. LastSetTime - Time when the password was last changed.
  144. Return Value:
  145. Status of operation.
  146. STATUS_NO_TRUST_LSA_SECRET: Secret object is not accessable
  147. STATUS_NO_MEMORY: Not enough memory to allocate password buffers
  148. --*/
  149. {
  150. NTSTATUS Status;
  151. LSAPR_HANDLE SecretHandle = NULL;
  152. PLSAPR_CR_CIPHER_VALUE CrCurrentPassword = NULL;
  153. PLSAPR_CR_CIPHER_VALUE CrOldPassword = NULL;
  154. PLSAPR_TRUSTED_DOMAIN_INFO TrustInfo = NULL;
  155. PLSAPR_AUTH_INFORMATION AuthInfo;
  156. PLSAPR_AUTH_INFORMATION OldAuthInfo;
  157. ULONG AuthInfoCount;
  158. ULONG i;
  159. BOOL PasswordFound = FALSE;
  160. BOOL PasswordVersionFound = FALSE;
  161. //
  162. // Initialization
  163. //
  164. *CurrentValue = NULL;
  165. *OldValue = NULL;
  166. *CurrentVersionNumber = 0;
  167. //
  168. // Workstation and BDC secure channels get their outgoing password from
  169. // an LSA secret.
  170. //
  171. switch ( ClientSession->CsSecureChannelType ) {
  172. case ServerSecureChannel:
  173. case WorkstationSecureChannel:
  174. //
  175. // Get the Password of the account from LSA secret storage
  176. //
  177. Status = NlOpenSecret( ClientSession, SECRET_QUERY_VALUE, &SecretHandle );
  178. if ( !NT_SUCCESS( Status ) ) {
  179. NlPrintCs((NL_CRITICAL, ClientSession,
  180. "NlGetOutgoingPassword: cannot NlOpenSecret 0x%lx\n",
  181. Status ));
  182. //
  183. // return more appropriate error.
  184. //
  185. if ( !NlpIsNtStatusResourceError( Status )) {
  186. Status = STATUS_NO_TRUST_LSA_SECRET;
  187. }
  188. goto Cleanup;
  189. }
  190. Status = LsarQuerySecret(
  191. SecretHandle,
  192. &CrCurrentPassword,
  193. LastSetTime,
  194. &CrOldPassword,
  195. NULL );
  196. if ( !NT_SUCCESS( Status ) ) {
  197. NlPrintCs((NL_CRITICAL, ClientSession,
  198. "NlGetOutgoingPassword: cannot LsaQuerySecret 0x%lx\n",
  199. Status ));
  200. //
  201. // return more appropriate error.
  202. //
  203. if ( !NlpIsNtStatusResourceError( Status )) {
  204. Status = STATUS_NO_TRUST_LSA_SECRET;
  205. }
  206. goto Cleanup;
  207. }
  208. //
  209. // Copy the current password back to the caller.
  210. //
  211. if ( CrCurrentPassword != NULL ) {
  212. *CurrentValue = LocalAlloc(0, sizeof(UNICODE_STRING)+CrCurrentPassword->Length+sizeof(WCHAR) );
  213. if ( *CurrentValue == NULL ) {
  214. Status = STATUS_NO_MEMORY;
  215. goto Cleanup;
  216. }
  217. (*CurrentValue)->Buffer = (LPWSTR)(((LPBYTE)(*CurrentValue))+sizeof(UNICODE_STRING));
  218. RtlCopyMemory( (*CurrentValue)->Buffer, CrCurrentPassword->Buffer, CrCurrentPassword->Length );
  219. (*CurrentValue)->Length = (USHORT)CrCurrentPassword->Length;
  220. (*CurrentValue)->MaximumLength = (USHORT)((*CurrentValue)->Length + sizeof(WCHAR));
  221. (*CurrentValue)->Buffer[(*CurrentValue)->Length/sizeof(WCHAR)] = L'\0';
  222. }
  223. //
  224. // Copy the Old password back to the caller.
  225. //
  226. if ( CrOldPassword != NULL ) {
  227. *OldValue = LocalAlloc(0, sizeof(UNICODE_STRING)+CrOldPassword->Length+sizeof(WCHAR) );
  228. if ( *OldValue == NULL ) {
  229. Status = STATUS_NO_MEMORY;
  230. goto Cleanup;
  231. }
  232. (*OldValue)->Buffer = (LPWSTR)(((LPBYTE)(*OldValue))+sizeof(UNICODE_STRING));
  233. RtlCopyMemory( (*OldValue)->Buffer, CrOldPassword->Buffer, CrOldPassword->Length );
  234. (*OldValue)->Length = (USHORT)CrOldPassword->Length;
  235. (*OldValue)->MaximumLength = (USHORT)((*OldValue)->Length + sizeof(WCHAR));
  236. (*OldValue)->Buffer[(*OldValue)->Length/sizeof(WCHAR)] = L'\0';
  237. }
  238. break;
  239. //
  240. // Trusted domain secure channels get their outgoing password from the trusted
  241. // domain object.
  242. //
  243. case TrustedDomainSecureChannel:
  244. case TrustedDnsDomainSecureChannel:
  245. //
  246. // Get the authentication information from the LSA.
  247. //
  248. Status = LsarQueryTrustedDomainInfoByName(
  249. ClientSession->CsDomainInfo->DomLsaPolicyHandle,
  250. (PLSAPR_UNICODE_STRING) ClientSession->CsTrustName,
  251. TrustedDomainAuthInformation,
  252. &TrustInfo );
  253. if (!NT_SUCCESS(Status)) {
  254. NlPrintCs((NL_CRITICAL, ClientSession,
  255. "NlGetOutgoingPassword: %wZ: cannot LsarQueryTrustedDomainInfoByName 0x%lx\n",
  256. ClientSession->CsTrustName,
  257. Status ));
  258. if ( !NlpIsNtStatusResourceError( Status )) {
  259. Status = STATUS_NO_TRUST_LSA_SECRET;
  260. }
  261. goto Cleanup;
  262. }
  263. AuthInfoCount = TrustInfo->TrustedAuthInfo.OutgoingAuthInfos;
  264. AuthInfo = TrustInfo->TrustedAuthInfo.OutgoingAuthenticationInformation;
  265. OldAuthInfo = TrustInfo->TrustedAuthInfo.OutgoingPreviousAuthenticationInformation;
  266. if (AuthInfoCount == 0 || AuthInfo == NULL) {
  267. NlPrintCs((NL_CRITICAL, ClientSession,
  268. "NlGetOutgoingPassword: %wZ: No auth info for this domain.\n",
  269. ClientSession->CsTrustName ));
  270. Status = STATUS_NO_TRUST_LSA_SECRET;
  271. goto Cleanup;
  272. }
  273. NlAssert( OldAuthInfo != NULL );
  274. //
  275. // Loop through the various auth infos looking for the cleartext password
  276. // and its version number.
  277. //
  278. for ( i=0; i<AuthInfoCount; i++ ) {
  279. //
  280. // Handle the cleartext password
  281. //
  282. if ( AuthInfo[i].AuthType == TRUST_AUTH_TYPE_CLEAR && !PasswordFound ) {
  283. //
  284. // Copy the current password back to the caller.
  285. //
  286. *CurrentValue = LocalAlloc(0, sizeof(UNICODE_STRING)+AuthInfo[i].AuthInfoLength+sizeof(WCHAR) );
  287. if ( *CurrentValue == NULL ) {
  288. Status = STATUS_NO_MEMORY;
  289. goto Cleanup;
  290. }
  291. (*CurrentValue)->Buffer = (LPWSTR)(((LPBYTE)(*CurrentValue))+sizeof(UNICODE_STRING));
  292. RtlCopyMemory( (*CurrentValue)->Buffer, AuthInfo[i].AuthInfo, AuthInfo[i].AuthInfoLength );
  293. (*CurrentValue)->Length = (USHORT)AuthInfo[i].AuthInfoLength;
  294. (*CurrentValue)->MaximumLength = (USHORT)((*CurrentValue)->Length + sizeof(WCHAR));
  295. (*CurrentValue)->Buffer[(*CurrentValue)->Length/sizeof(WCHAR)] = L'\0';
  296. //
  297. // Copy the password change time back to the caller.
  298. //
  299. if ( ARGUMENT_PRESENT( LastSetTime )) {
  300. *LastSetTime = AuthInfo[i].LastUpdateTime;
  301. }
  302. //
  303. // Only copy the old password if it is also clear.
  304. //
  305. if ( OldAuthInfo[i].AuthType == TRUST_AUTH_TYPE_CLEAR ) {
  306. //
  307. // Copy the Old password back to the caller.
  308. //
  309. *OldValue = LocalAlloc(0, sizeof(UNICODE_STRING)+OldAuthInfo[i].AuthInfoLength+sizeof(WCHAR) );
  310. if ( *OldValue == NULL ) {
  311. Status = STATUS_NO_MEMORY;
  312. goto Cleanup;
  313. }
  314. (*OldValue)->Buffer = (LPWSTR)(((LPBYTE)(*OldValue))+sizeof(UNICODE_STRING));
  315. RtlCopyMemory( (*OldValue)->Buffer, OldAuthInfo[i].AuthInfo, OldAuthInfo[i].AuthInfoLength );
  316. (*OldValue)->Length = (USHORT)OldAuthInfo[i].AuthInfoLength;
  317. (*OldValue)->MaximumLength = (USHORT)((*OldValue)->Length + sizeof(WCHAR));
  318. (*OldValue)->Buffer[(*OldValue)->Length/sizeof(WCHAR)] = L'\0';
  319. }
  320. PasswordFound = TRUE;
  321. if ( PasswordVersionFound ) {
  322. break;
  323. }
  324. //
  325. // Handle the version number of the cleartext password
  326. //
  327. } else if ( AuthInfo[i].AuthType == TRUST_AUTH_TYPE_VERSION && !PasswordVersionFound &&
  328. AuthInfo[i].AuthInfoLength == sizeof(*CurrentVersionNumber) ) {
  329. RtlCopyMemory( CurrentVersionNumber, AuthInfo[i].AuthInfo, AuthInfo[i].AuthInfoLength );
  330. PasswordVersionFound = TRUE;
  331. if ( PasswordFound ) {
  332. break;
  333. }
  334. }
  335. }
  336. //if ( i == AuthInfoCount ) {
  337. if ( !PasswordFound ) {
  338. NlPrintCs((NL_CRITICAL, ClientSession,
  339. "NlGetOutgoingPassword: %wZ: No clear password for this domain.\n",
  340. ClientSession->CsTrustName ));
  341. Status = STATUS_NO_TRUST_LSA_SECRET;
  342. goto Cleanup;
  343. }
  344. break;
  345. default:
  346. NlPrintCs((NL_CRITICAL, ClientSession,
  347. "NlGetOutgoingPassword: invalid secure channel type\n" ));
  348. Status = STATUS_NO_TRUST_LSA_SECRET;
  349. goto Cleanup;
  350. }
  351. Status = STATUS_SUCCESS;
  352. //
  353. // Free locally used resources.
  354. //
  355. Cleanup:
  356. if ( !NT_SUCCESS(Status) ) {
  357. if ( *CurrentValue != NULL ) {
  358. LocalFree( *CurrentValue );
  359. *CurrentValue = NULL;
  360. }
  361. if ( *OldValue != NULL ) {
  362. LocalFree( *OldValue );
  363. *OldValue = NULL;
  364. }
  365. *CurrentVersionNumber = 0;
  366. }
  367. if ( SecretHandle != NULL ) {
  368. (VOID) LsarClose( &SecretHandle );
  369. }
  370. if ( CrCurrentPassword != NULL ) {
  371. (VOID) LsaIFree_LSAPR_CR_CIPHER_VALUE ( CrCurrentPassword );
  372. }
  373. if ( CrOldPassword != NULL ) {
  374. (VOID) LsaIFree_LSAPR_CR_CIPHER_VALUE ( CrOldPassword );
  375. }
  376. if ( TrustInfo != NULL ) {
  377. LsaIFree_LSAPR_TRUSTED_DOMAIN_INFO( TrustedDomainAuthInformation,
  378. TrustInfo );
  379. }
  380. return Status;
  381. }
  382. NTSTATUS
  383. NlSetOutgoingPassword(
  384. IN PCLIENT_SESSION ClientSession,
  385. IN PUNICODE_STRING CurrentValue OPTIONAL,
  386. IN PUNICODE_STRING OldValue OPTIONAL,
  387. IN DWORD CurrentVersionNumber,
  388. IN DWORD OldVersionNumber
  389. )
  390. /*++
  391. Routine Description:
  392. Set the outgoing password to be used for the specified client session.
  393. Arguments:
  394. ClientSession - Structure used to define the session.
  395. CurrentValue - Current password for the client session.
  396. A NULL pointer indicates there is no current password (blank password)
  397. OldValue - Previous password for the client session.
  398. A NULL pointer indicates there is no old password (blank password)
  399. CurrentVersionNumber - The version number of the Current password.
  400. Ignored if this is not an interdomain trust account.
  401. OldVersionNumber - The version number of the Old password.
  402. Ignored if this is not an interdomain trust account.
  403. Return Value:
  404. Status of operation.
  405. --*/
  406. {
  407. NTSTATUS Status;
  408. LSAPR_HANDLE SecretHandle = NULL;
  409. UNICODE_STRING LocalNullPassword;
  410. LSAPR_CR_CIPHER_VALUE CrCurrentPassword;
  411. LSAPR_CR_CIPHER_VALUE CrOldPassword;
  412. LSAPR_TRUSTED_DOMAIN_INFO TrustInfo;
  413. LSAPR_AUTH_INFORMATION CurrentAuthInfo[2];
  414. LSAPR_AUTH_INFORMATION OldAuthInfo[2];
  415. //
  416. // Initialization
  417. //
  418. if ( CurrentValue == NULL ) {
  419. CurrentValue = &LocalNullPassword;
  420. RtlInitUnicodeString( &LocalNullPassword, NULL );
  421. }
  422. if ( OldValue == NULL ) {
  423. OldValue = &LocalNullPassword;
  424. RtlInitUnicodeString( &LocalNullPassword, NULL );
  425. }
  426. //
  427. // Workstation and BDC secure channels get their outgoing password from
  428. // an LSA secret.
  429. //
  430. switch ( ClientSession->CsSecureChannelType ) {
  431. case ServerSecureChannel:
  432. case WorkstationSecureChannel:
  433. //
  434. // Open the LSA secret to set.
  435. //
  436. Status = NlOpenSecret( ClientSession, SECRET_SET_VALUE, &SecretHandle );
  437. if ( !NT_SUCCESS( Status ) ) {
  438. NlPrintCs((NL_CRITICAL, ClientSession,
  439. "NlSetOutgoiningPassword: cannot NlOpenSecret 0x%lx\n",
  440. Status ));
  441. goto Cleanup;
  442. }
  443. //
  444. // Convert the current password to LSA'ese.
  445. //
  446. CrCurrentPassword.Buffer = (LPBYTE)CurrentValue->Buffer;
  447. CrCurrentPassword.Length = CurrentValue->Length;
  448. CrCurrentPassword.MaximumLength = CurrentValue->MaximumLength;
  449. //
  450. // Convert the old password to LSA'ese.
  451. //
  452. CrOldPassword.Buffer = (LPBYTE)OldValue->Buffer;
  453. CrOldPassword.Length = OldValue->Length;
  454. CrOldPassword.MaximumLength = OldValue->MaximumLength;
  455. Status = LsarSetSecret(
  456. SecretHandle,
  457. &CrCurrentPassword,
  458. &CrOldPassword );
  459. if ( !NT_SUCCESS( Status ) ) {
  460. NlPrintCs((NL_CRITICAL, ClientSession,
  461. "NlSetOutgoingPassword: cannot LsarSetSecret 0x%lx\n",
  462. Status ));
  463. goto Cleanup;
  464. }
  465. break;
  466. //
  467. // Trusted domain secure channels get their outgoing password from the trusted
  468. // domain object.
  469. //
  470. case TrustedDomainSecureChannel:
  471. case TrustedDnsDomainSecureChannel:
  472. //
  473. // Fill in the trust information.
  474. //
  475. RtlZeroMemory( &TrustInfo, sizeof(TrustInfo) );
  476. TrustInfo.TrustedAuthInfo.OutgoingAuthInfos = 2;
  477. TrustInfo.TrustedAuthInfo.OutgoingAuthenticationInformation =
  478. CurrentAuthInfo;
  479. TrustInfo.TrustedAuthInfo.OutgoingPreviousAuthenticationInformation =
  480. OldAuthInfo;
  481. //
  482. // Fill in the current authentication information.
  483. //
  484. NlQuerySystemTime( &CurrentAuthInfo[0].LastUpdateTime );
  485. CurrentAuthInfo[0].AuthType = TRUST_AUTH_TYPE_CLEAR;
  486. CurrentAuthInfo[0].AuthInfoLength = CurrentValue->Length;
  487. CurrentAuthInfo[0].AuthInfo = (LPBYTE)CurrentValue->Buffer;
  488. //
  489. // Fill in the current password version number
  490. //
  491. CurrentAuthInfo[1].LastUpdateTime = CurrentAuthInfo[0].LastUpdateTime;
  492. CurrentAuthInfo[1].AuthType = TRUST_AUTH_TYPE_VERSION;
  493. CurrentAuthInfo[1].AuthInfoLength = sizeof( CurrentVersionNumber );
  494. CurrentAuthInfo[1].AuthInfo = (LPBYTE) &CurrentVersionNumber;
  495. //
  496. // Fill in the old authentication information.
  497. //
  498. OldAuthInfo[0].LastUpdateTime = CurrentAuthInfo[0].LastUpdateTime;
  499. OldAuthInfo[0].AuthType = TRUST_AUTH_TYPE_CLEAR;
  500. OldAuthInfo[0].AuthInfoLength = OldValue->Length;
  501. OldAuthInfo[0].AuthInfo = (LPBYTE)OldValue->Buffer;
  502. //
  503. // Fill in the old password version number.
  504. //
  505. OldAuthInfo[1].LastUpdateTime = CurrentAuthInfo[0].LastUpdateTime;
  506. OldAuthInfo[1].AuthType = TRUST_AUTH_TYPE_VERSION;
  507. OldAuthInfo[1].AuthInfoLength = sizeof( OldVersionNumber );
  508. OldAuthInfo[1].AuthInfo = (LPBYTE) &OldVersionNumber;
  509. //
  510. // Get the authentication information from the LSA.
  511. //
  512. Status = LsarSetTrustedDomainInfoByName(
  513. ClientSession->CsDomainInfo->DomLsaPolicyHandle,
  514. (PLSAPR_UNICODE_STRING) ClientSession->CsTrustName,
  515. TrustedDomainAuthInformation,
  516. &TrustInfo );
  517. if (!NT_SUCCESS(Status)) {
  518. NlPrintCs((NL_CRITICAL, ClientSession,
  519. "NlSetOutgoingPassword: %wZ: cannot LsarSetTrustedDomainInfoByName 0x%lx\n",
  520. ClientSession->CsTrustName,
  521. Status ));
  522. if ( !NlpIsNtStatusResourceError( Status )) {
  523. Status = STATUS_NO_TRUST_LSA_SECRET;
  524. }
  525. goto Cleanup;
  526. }
  527. //
  528. // Be verbose
  529. //
  530. NlPrint(( NL_SESSION_SETUP, "NlSetOutgoingPassword: Current Clear Text Password is: " ));
  531. NlpDumpBuffer(NL_SESSION_SETUP, CurrentAuthInfo[0].AuthInfo, CurrentAuthInfo[0].AuthInfoLength );
  532. NlPrint(( NL_SESSION_SETUP, "NlSetOutgoingPassword: Current Clear Password Version Number is: 0x%lx\n",
  533. CurrentVersionNumber ));
  534. NlPrint(( NL_SESSION_SETUP, "NlSetOutgoingPassword: Previous Clear Text Password is: " ));
  535. NlpDumpBuffer(NL_SESSION_SETUP, OldAuthInfo[0].AuthInfo, OldAuthInfo[0].AuthInfoLength );
  536. NlPrint(( NL_SESSION_SETUP, "NlSetOutgoingPassword: Previous Clear Password Version Number is: 0x%lx\n",
  537. OldVersionNumber ));
  538. break;
  539. default:
  540. NlPrintCs((NL_CRITICAL, ClientSession,
  541. "NlSetOutgoingPassword: invalid secure channel type\n" ));
  542. Status = STATUS_NO_TRUST_LSA_SECRET;
  543. goto Cleanup;
  544. }
  545. Status = STATUS_SUCCESS;
  546. //
  547. // Free locally used resources.
  548. //
  549. Cleanup:
  550. if ( SecretHandle != NULL ) {
  551. (VOID) LsarClose( &SecretHandle );
  552. }
  553. return Status;
  554. }
  555. NTSTATUS
  556. NlGetIncomingPassword(
  557. IN PDOMAIN_INFO DomainInfo,
  558. IN LPCWSTR AccountName,
  559. IN NETLOGON_SECURE_CHANNEL_TYPE SecureChannelType,
  560. IN ULONG AllowableAccountControlBits,
  561. IN BOOL CheckAccountDisabled,
  562. OUT PNT_OWF_PASSWORD OwfPassword OPTIONAL,
  563. OUT PNT_OWF_PASSWORD OwfPreviousPassword OPTIONAL,
  564. OUT PULONG AccountRid OPTIONAL,
  565. OUT PULONG TrustAttributes OPTIONAL,
  566. OUT PBOOL IsDnsDomainTrustAccount OPTIONAL
  567. )
  568. /*++
  569. Routine Description:
  570. Get the incoming password for the specified AccountName and SecureChannelType
  571. Check the machine account:
  572. Ensure the SecureChannelType is valid,
  573. Verify that the account exists,
  574. Ensure the user account is the right account type.
  575. Arguments:
  576. DomainInfo - Emulated domain
  577. AccountName - Name of the account to authenticate with.
  578. SecureChannelType - The type of the account.
  579. Use NullSecureChannel if channel type is not known.
  580. AllowableAccountControlBits - The type of the account.
  581. Use 0 if AccountControlBits is not known.
  582. Typically only one of AllowableAccountControlBits or SecureChannelType
  583. will be specified.
  584. CheckAccountDisabled - TRUE if we should return an error if the account
  585. is disabled.
  586. OwfPassword - Returns the NT OWF of the incoming password for the named
  587. account. If NULL, the password is not returned.
  588. OwfPreviousPassword - Returns the NT OWF of the incoming previous password for
  589. the named interdomain trust account. If NULL, the password is not returned.
  590. If OwfPreviousPassword is not NULL, OwfPassword must not be NULL either;
  591. otherwise the function asserts. If OwfPreviousPassword is not NULL and the
  592. account is not interdomain, the function asserts. If both OwfPassword and
  593. OwfPreviousPassword are NULL, the account is only checked for validity.
  594. AccountRid - Returns the RID of AccountName
  595. TrustAttributes - Returns the TrustAttributes for the interdomain trust account.
  596. IsDnsDomainTrustAccount - Returns TRUE if the passed in account name is the
  597. DNS domain name of an uplevel domain trust. Set only if the account control
  598. bits (either passed directly or determined from the secure channel type)
  599. correspond to an interdomain trust account.
  600. Return Value:
  601. Status of operation.
  602. --*/
  603. {
  604. NTSTATUS Status;
  605. SAMPR_HANDLE UserHandle = NULL;
  606. PSAMPR_USER_INFO_BUFFER UserAllInfo = NULL;
  607. ULONG Length;
  608. PLSAPR_TRUSTED_DOMAIN_INFO TrustInfo = NULL;
  609. PLSAPR_AUTH_INFORMATION AuthInfo;
  610. ULONG AuthInfoCount;
  611. BOOL PasswordFound = FALSE;
  612. BOOL PreviousPasswordFound = FALSE;
  613. ULONG i;
  614. //
  615. // Initialization
  616. //
  617. if ( ARGUMENT_PRESENT(AccountRid) ) {
  618. *AccountRid = 0;
  619. }
  620. if ( ARGUMENT_PRESENT(TrustAttributes) ) {
  621. *TrustAttributes = 0;
  622. }
  623. if ( ARGUMENT_PRESENT(IsDnsDomainTrustAccount) ) {
  624. *IsDnsDomainTrustAccount = FALSE; // assume it's not and prove if otherwise
  625. }
  626. Length = wcslen( AccountName );
  627. if ( Length < 1 ) {
  628. return STATUS_INVALID_PARAMETER;
  629. }
  630. //
  631. // Convert the secure channel type to allowable account control bits.
  632. //
  633. switch (SecureChannelType) {
  634. case WorkstationSecureChannel:
  635. AllowableAccountControlBits |= USER_WORKSTATION_TRUST_ACCOUNT;
  636. break;
  637. case ServerSecureChannel:
  638. AllowableAccountControlBits |= USER_SERVER_TRUST_ACCOUNT;
  639. break;
  640. case TrustedDomainSecureChannel:
  641. AllowableAccountControlBits |= USER_INTERDOMAIN_TRUST_ACCOUNT;
  642. break;
  643. case TrustedDnsDomainSecureChannel:
  644. AllowableAccountControlBits |= USER_DNS_DOMAIN_TRUST_ACCOUNT;
  645. break;
  646. case NullSecureChannel:
  647. if ( AllowableAccountControlBits == 0 ) {
  648. NlPrintDom((NL_CRITICAL, DomainInfo,
  649. "NlGetIncomingPassword: Invalid AAC (%x) for %ws\n",
  650. AllowableAccountControlBits,
  651. AccountName ));
  652. return STATUS_INVALID_PARAMETER;
  653. }
  654. break;
  655. default:
  656. NlPrintDom((NL_CRITICAL, DomainInfo,
  657. "NlGetIncomingPassword: Invalid channel type (%x) for %ws\n",
  658. SecureChannelType,
  659. AccountName ));
  660. return STATUS_INVALID_PARAMETER;
  661. }
  662. //
  663. // If this is an interdomain trust account,
  664. // use an interdomain trust object.
  665. //
  666. if ( AllowableAccountControlBits == USER_DNS_DOMAIN_TRUST_ACCOUNT ||
  667. AllowableAccountControlBits == USER_INTERDOMAIN_TRUST_ACCOUNT ) {
  668. UNICODE_STRING AccountNameString;
  669. //
  670. // If this is a DNS trust account,
  671. // remove the optional . from the end of the account name.
  672. //
  673. RtlInitUnicodeString( &AccountNameString, AccountName );
  674. if ( AllowableAccountControlBits == USER_DNS_DOMAIN_TRUST_ACCOUNT ) {
  675. if ( Length != 0 && AccountName[Length-1] == '.' ) {
  676. AccountNameString.Length -= sizeof(WCHAR);
  677. }
  678. //
  679. // If this is an NT4-style interdomain trust,
  680. // remove the $ from the end of the account name.
  681. //
  682. } else {
  683. //
  684. // Ensure the account name has the correct postfix.
  685. //
  686. if ( Length <= SSI_ACCOUNT_NAME_POSTFIX_LENGTH ) {
  687. return STATUS_NO_SUCH_USER;
  688. }
  689. if ( _wcsicmp(&AccountName[Length - SSI_ACCOUNT_NAME_POSTFIX_LENGTH],
  690. SSI_ACCOUNT_NAME_POSTFIX) != 0 ) {
  691. return STATUS_NO_SUCH_USER;
  692. }
  693. AccountNameString.Length -= SSI_ACCOUNT_NAME_POSTFIX_LENGTH*sizeof(WCHAR);
  694. }
  695. //
  696. // Get the authentication information from the LSA.
  697. //
  698. Status = LsarQueryTrustedDomainInfoByName(
  699. DomainInfo->DomLsaPolicyHandle,
  700. (PLSAPR_UNICODE_STRING) &AccountNameString,
  701. TrustedDomainFullInformation,
  702. &TrustInfo );
  703. if (!NT_SUCCESS(Status)) {
  704. NlPrintDom((NL_CRITICAL, DomainInfo,
  705. "NlGetIncomingPassword: %wZ: cannot LsarQueryTrustedDomainInfoByName 0x%lx\n",
  706. &AccountNameString,
  707. Status ));
  708. if ( !NlpIsNtStatusResourceError( Status )) {
  709. Status = STATUS_NO_SUCH_USER;
  710. }
  711. goto Cleanup;
  712. }
  713. //
  714. // Ensure the attributes of the trust account are right.
  715. //
  716. if ( (TrustInfo->TrustedFullInfo.Information.TrustDirection & TRUST_DIRECTION_INBOUND) == 0 ) {
  717. NlPrintDom((NL_CRITICAL, DomainInfo,
  718. "NlGetIncomingPassword: %wZ: trust is not inbound\n",
  719. &AccountNameString ));
  720. Status = STATUS_NO_SUCH_USER;
  721. goto Cleanup;
  722. }
  723. if ( TrustInfo->TrustedFullInfo.Information.TrustType != TRUST_TYPE_DOWNLEVEL &&
  724. TrustInfo->TrustedFullInfo.Information.TrustType != TRUST_TYPE_UPLEVEL ) {
  725. NlPrintDom((NL_CRITICAL, DomainInfo,
  726. "NlGetIncomingPassword: %wZ: trust type doesn't match request type 0x%lx %ld\n",
  727. &AccountNameString,
  728. AllowableAccountControlBits,
  729. TrustInfo->TrustedFullInfo.Information.TrustType ));
  730. Status = STATUS_NO_SUCH_USER;
  731. goto Cleanup;
  732. }
  733. if ( TrustInfo->TrustedFullInfo.Information.TrustAttributes & TRUST_ATTRIBUTE_UPLEVEL_ONLY ) {
  734. NlPrintDom((NL_CRITICAL, DomainInfo,
  735. "NlGetIncomingPassword: %wZ: trust is KERB only\n",
  736. &AccountNameString ));
  737. Status = STATUS_NO_SUCH_USER;
  738. goto Cleanup;
  739. }
  740. //
  741. // Return the trust attributes to the caller
  742. //
  743. if ( ARGUMENT_PRESENT(TrustAttributes) ) {
  744. *TrustAttributes = TrustInfo->TrustedFullInfo.Information.TrustAttributes;
  745. }
  746. //
  747. // Determine whether the passed account is a DNS domain trust account
  748. //
  749. // Simply check if this is a uplevel trust and if the account name passed
  750. // is the Name of the trusted domain
  751. //
  752. if ( ARGUMENT_PRESENT(IsDnsDomainTrustAccount) ) {
  753. if ( TrustInfo->TrustedFullInfo.Information.TrustType == TRUST_TYPE_UPLEVEL &&
  754. TrustInfo->TrustedFullInfo.Information.Name.Length > 0 ) {
  755. LPWSTR DnsDomainNameString = NULL;
  756. DnsDomainNameString = LocalAlloc( 0,
  757. TrustInfo->TrustedFullInfo.Information.Name.Length + sizeof(WCHAR) );
  758. if ( DnsDomainNameString == NULL ) {
  759. Status = STATUS_NO_MEMORY;
  760. goto Cleanup;
  761. }
  762. RtlCopyMemory( DnsDomainNameString,
  763. TrustInfo->TrustedFullInfo.Information.Name.Buffer,
  764. TrustInfo->TrustedFullInfo.Information.Name.Length );
  765. DnsDomainNameString[ TrustInfo->TrustedFullInfo.Information.Name.Length/sizeof(WCHAR) ] = L'\0';
  766. //
  767. // Note that we don't have to remove the trailing dot
  768. // in AccountName if present because the DNS comprare
  769. // API ignores trailing dots.
  770. //
  771. *IsDnsDomainTrustAccount = NlEqualDnsName(DnsDomainNameString, AccountName);
  772. LocalFree( DnsDomainNameString );
  773. }
  774. }
  775. //
  776. // Only get the password if the caller really wants it.
  777. //
  778. if ( OwfPassword != NULL ) {
  779. AuthInfoCount = TrustInfo->TrustedFullInfo.AuthInformation.IncomingAuthInfos;
  780. AuthInfo = TrustInfo->TrustedFullInfo.AuthInformation.IncomingAuthenticationInformation;
  781. if (AuthInfoCount == 0 || AuthInfo == NULL) {
  782. NlPrintDom((NL_CRITICAL, DomainInfo,
  783. "NlGetIncomingPassword: %wZ: No auth info for this domain.\n",
  784. &AccountNameString ));
  785. Status = STATUS_NO_SUCH_USER;
  786. goto Cleanup;
  787. }
  788. //
  789. // Loop through the various auth infos looking for the cleartext password
  790. // or NT OWF password.
  791. //
  792. // If there is a clear text password, use it.
  793. // Otherwise, use the NT OWF password.
  794. //
  795. for ( i=0; i<AuthInfoCount; i++ ) {
  796. //
  797. // Handle an NT OWF password.
  798. //
  799. if ( AuthInfo[i].AuthType == TRUST_AUTH_TYPE_NT4OWF ) {
  800. //
  801. // Only use the OWF if it is valid
  802. //
  803. if ( AuthInfo[i].AuthInfoLength != sizeof(*OwfPassword) ) {
  804. NlPrintDom((NL_CRITICAL, DomainInfo,
  805. "NlGetIncomingPassword: %wZ: OWF password has bad length %ld\n",
  806. &AccountNameString,
  807. AuthInfo[i].AuthInfoLength ));
  808. } else {
  809. RtlCopyMemory( OwfPassword, AuthInfo[i].AuthInfo, sizeof(*OwfPassword) );
  810. PasswordFound = TRUE;
  811. }
  812. }
  813. //
  814. // Handle a cleartext password.
  815. //
  816. else if ( AuthInfo[i].AuthType == TRUST_AUTH_TYPE_CLEAR ) {
  817. UNICODE_STRING TempUnicodeString;
  818. TempUnicodeString.Buffer = (LPWSTR)AuthInfo[i].AuthInfo;
  819. TempUnicodeString.MaximumLength =
  820. TempUnicodeString.Length = (USHORT)AuthInfo[i].AuthInfoLength;
  821. NlPrint((NL_CHALLENGE_RES,"NlGetIncomingPassword: New Clear Password = " ));
  822. NlpDumpBuffer(NL_CHALLENGE_RES, TempUnicodeString.Buffer, TempUnicodeString.Length );
  823. NlpDumpTime( NL_CHALLENGE_RES, "NlGetIncomingPassword: New Password Changed: ", AuthInfo[i].LastUpdateTime );
  824. Status = RtlCalculateNtOwfPassword(&TempUnicodeString,
  825. OwfPassword);
  826. if ( !NT_SUCCESS(Status) ) {
  827. NlPrintDom((NL_CRITICAL, DomainInfo,
  828. "NlGetIncomingPassword: %wZ: cannot RtlCalculateNtOwfPassword 0x%lx\n",
  829. &AccountNameString,
  830. Status ));
  831. goto Cleanup;
  832. }
  833. PasswordFound = TRUE;
  834. //
  835. // Use this clear text password
  836. //
  837. break;
  838. }
  839. }
  840. }
  841. //
  842. // Only get the previous password if the caller really wants it.
  843. //
  844. if ( OwfPreviousPassword != NULL ) {
  845. // If OwfPreviousPassword is not NULL, OwfPassword must not be NULL either
  846. NlAssert( OwfPassword != NULL );
  847. AuthInfoCount = TrustInfo->TrustedFullInfo.AuthInformation.IncomingAuthInfos;
  848. AuthInfo = TrustInfo->TrustedFullInfo.AuthInformation.IncomingPreviousAuthenticationInformation;
  849. if (AuthInfoCount == 0 || AuthInfo == NULL) {
  850. NlPrintDom((NL_CRITICAL, DomainInfo,
  851. "NlGetIncomingPassword: %wZ: No previous auth info for this domain.\n",
  852. &AccountNameString ));
  853. Status = STATUS_NO_SUCH_USER;
  854. goto Cleanup;
  855. }
  856. //
  857. // Loop through the various auth infos looking for the previous cleartext password
  858. // or NT OWF password.
  859. //
  860. // If there is a clear text password, use it.
  861. // Otherwise, use the NT OWF password.
  862. //
  863. for ( i=0; i<AuthInfoCount; i++ ) {
  864. //
  865. // Handle an NT OWF password.
  866. //
  867. if ( AuthInfo[i].AuthType == TRUST_AUTH_TYPE_NT4OWF ) {
  868. //
  869. // Only use the OWF if it is valid
  870. //
  871. if ( AuthInfo[i].AuthInfoLength != sizeof(*OwfPreviousPassword) ) {
  872. NlPrintDom((NL_CRITICAL, DomainInfo,
  873. "NlGetIncomingPassword: %wZ: previous OWF password has bad length %ld\n",
  874. &AccountNameString,
  875. AuthInfo[i].AuthInfoLength ));
  876. } else {
  877. RtlCopyMemory( OwfPreviousPassword, AuthInfo[i].AuthInfo, sizeof(*OwfPreviousPassword) );
  878. PreviousPasswordFound = TRUE;
  879. }
  880. }
  881. //
  882. // Handle a cleartext password.
  883. //
  884. else if ( AuthInfo[i].AuthType == TRUST_AUTH_TYPE_CLEAR ) {
  885. UNICODE_STRING TempUnicodeString;
  886. TempUnicodeString.Buffer = (LPWSTR)AuthInfo[i].AuthInfo;
  887. TempUnicodeString.MaximumLength =
  888. TempUnicodeString.Length = (USHORT)AuthInfo[i].AuthInfoLength;
  889. NlPrint((NL_CHALLENGE_RES,"NlGetIncomingPassword: Old Clear Password = " ));
  890. NlpDumpBuffer(NL_CHALLENGE_RES, TempUnicodeString.Buffer, TempUnicodeString.Length );
  891. NlpDumpTime( NL_CHALLENGE_RES, "NlGetIncomingPassword: Old Password Changed: ", AuthInfo[i].LastUpdateTime );
  892. Status = RtlCalculateNtOwfPassword(&TempUnicodeString,
  893. OwfPreviousPassword);
  894. if ( !NT_SUCCESS(Status) ) {
  895. NlPrintDom((NL_CRITICAL, DomainInfo,
  896. "NlGetIncomingPassword: %wZ: cannot RtlCalculateNtOwfPassword 0x%lx\n",
  897. &AccountNameString,
  898. Status ));
  899. goto Cleanup;
  900. }
  901. PreviousPasswordFound = TRUE;
  902. //
  903. // Use this clear text password
  904. //
  905. break;
  906. }
  907. }
  908. }
  909. //
  910. // Only get the account RID if the caller really wants it.
  911. //
  912. if ( ARGUMENT_PRESENT( AccountRid) ) {
  913. PUNICODE_STRING FlatName;
  914. WCHAR SamAccountName[CNLEN+1+1];
  915. //
  916. // The name of the SAM account that corresponds to the inbound
  917. // trust is FlatName$.
  918. //
  919. FlatName = (PUNICODE_STRING) &TrustInfo->TrustedFullInfo.Information.FlatName;
  920. if ( FlatName->Length < sizeof(WCHAR) ||
  921. FlatName->Length > CNLEN * sizeof(WCHAR) ) {
  922. NlPrintDom((NL_CRITICAL, DomainInfo,
  923. "NlGetIncomingPassword: %wZ: Flat Name length is bad %ld\n",
  924. &AccountNameString,
  925. FlatName->Length ));
  926. } else {
  927. RtlCopyMemory( SamAccountName,
  928. FlatName->Buffer,
  929. FlatName->Length );
  930. SamAccountName[FlatName->Length/sizeof(WCHAR)] =
  931. SSI_ACCOUNT_NAME_POSTFIX_CHAR;
  932. SamAccountName[(FlatName->Length/sizeof(WCHAR))+1] = L'\0';
  933. //
  934. // Get the account RID from SAM.
  935. //
  936. // ??? This is a gross hack.
  937. // The LSA should return this RID to me directly.
  938. //
  939. Status = NlSamOpenNamedUser( DomainInfo, SamAccountName, NULL, AccountRid, NULL );
  940. if (!NT_SUCCESS(Status)) {
  941. NlPrintDom((NL_CRITICAL, DomainInfo,
  942. "NlGetIncomingPassword: Can't NlSamOpenNamedUser for %ws 0x%lx.\n",
  943. SamAccountName,
  944. Status ));
  945. goto Cleanup;
  946. }
  947. }
  948. }
  949. //
  950. // Othewise the account is a SAM user account.
  951. //
  952. } else {
  953. //
  954. // OwfPreviousPassword must be NULL for a SAM account
  955. //
  956. NlAssert( OwfPreviousPassword == NULL );
  957. //
  958. // Ensure the account name has the correct postfix.
  959. //
  960. if ( AllowableAccountControlBits == USER_SERVER_TRUST_ACCOUNT ||
  961. AllowableAccountControlBits == USER_WORKSTATION_TRUST_ACCOUNT ) {
  962. if ( Length <= SSI_ACCOUNT_NAME_POSTFIX_LENGTH ) {
  963. return STATUS_NO_SUCH_USER;
  964. }
  965. if ( _wcsicmp(&AccountName[Length - SSI_ACCOUNT_NAME_POSTFIX_LENGTH],
  966. SSI_ACCOUNT_NAME_POSTFIX) != 0 ) {
  967. return STATUS_NO_SUCH_USER;
  968. }
  969. }
  970. //
  971. // Open the user account.
  972. //
  973. Status = NlSamOpenNamedUser( DomainInfo, AccountName, &UserHandle, AccountRid, &UserAllInfo );
  974. if (!NT_SUCCESS(Status)) {
  975. NlPrintDom((NL_CRITICAL, DomainInfo,
  976. "NlGetIncomingPassword: Can't NlSamOpenNamedUser for %ws 0x%lx.\n",
  977. AccountName,
  978. Status ));
  979. goto Cleanup;
  980. }
  981. //
  982. // Ensure the Account type matches the account type on the account.
  983. //
  984. if ( (UserAllInfo->All.UserAccountControl &
  985. USER_ACCOUNT_TYPE_MASK &
  986. AllowableAccountControlBits ) == 0 ) {
  987. NlPrintDom((NL_CRITICAL, DomainInfo,
  988. "NlGetIncomingPassword: Invalid account type (%x) instead of %x for %ws\n",
  989. UserAllInfo->All.UserAccountControl & USER_ACCOUNT_TYPE_MASK,
  990. AllowableAccountControlBits,
  991. AccountName ));
  992. Status = STATUS_NO_SUCH_USER;
  993. goto Cleanup;
  994. }
  995. //
  996. // Check if the account is disabled.
  997. //
  998. if ( CheckAccountDisabled ) {
  999. if ( UserAllInfo->All.UserAccountControl & USER_ACCOUNT_DISABLED ) {
  1000. NlPrintDom((NL_CRITICAL, DomainInfo,
  1001. "NlGetIncomingPassword: %ws account is disabled\n",
  1002. AccountName ));
  1003. Status = STATUS_NO_SUCH_USER;
  1004. goto Cleanup;
  1005. }
  1006. }
  1007. //
  1008. // Return the password if the caller wants it.
  1009. //
  1010. if ( OwfPassword != NULL ) {
  1011. //
  1012. // Use the NT OWF Password,
  1013. //
  1014. if ( UserAllInfo->All.NtPasswordPresent &&
  1015. UserAllInfo->All.NtOwfPassword.Length == sizeof(*OwfPassword) ) {
  1016. RtlCopyMemory( OwfPassword,
  1017. UserAllInfo->All.NtOwfPassword.Buffer,
  1018. sizeof(*OwfPassword) );
  1019. PasswordFound = TRUE;
  1020. // Allow for the case that the account has no password at all.
  1021. } else if ( UserAllInfo->All.LmPasswordPresent ) {
  1022. NlPrint((NL_CRITICAL,
  1023. "NlGetIncomingPassword: No NT Password for %ws\n",
  1024. AccountName ));
  1025. Status = STATUS_ACCESS_DENIED;
  1026. goto Cleanup;
  1027. }
  1028. //
  1029. // Update the last time this account was used.
  1030. //
  1031. {
  1032. SAMPR_USER_INFO_BUFFER UserInfo;
  1033. NTSTATUS LogonStatus;
  1034. UserInfo.Internal2.StatisticsToApply = USER_LOGON_NET_SUCCESS_LOGON;
  1035. LogonStatus = SamrSetInformationUser(
  1036. UserHandle,
  1037. UserInternal2Information,
  1038. &UserInfo );
  1039. if ( !NT_SUCCESS(LogonStatus)) {
  1040. NlPrint((NL_CRITICAL,
  1041. "NlGetIncomingPassword: Cannot set last logon time %ws %lx\n",
  1042. AccountName,
  1043. LogonStatus ));
  1044. }
  1045. }
  1046. }
  1047. }
  1048. //
  1049. // If no password exists on the account,
  1050. // return a blank password.
  1051. //
  1052. if ( !PasswordFound && OwfPassword != NULL ) {
  1053. UNICODE_STRING TempUnicodeString;
  1054. RtlInitUnicodeString(&TempUnicodeString, NULL);
  1055. Status = RtlCalculateNtOwfPassword(&TempUnicodeString,
  1056. OwfPassword);
  1057. if ( !NT_SUCCESS(Status) ) {
  1058. NlPrintDom((NL_CRITICAL, DomainInfo,
  1059. "NlGetIncomingPassword: %ws: cannot RtlCalculateNtOwfPassword (NULL) 0x%lx\n",
  1060. AccountName,
  1061. Status ));
  1062. goto Cleanup;
  1063. }
  1064. }
  1065. //
  1066. // If no previous password exists on the account,
  1067. // return the current password.
  1068. //
  1069. if ( !PreviousPasswordFound && OwfPreviousPassword != NULL ) {
  1070. //
  1071. // If OwfPreviousPassword is not NULL, OwfPassword must not be NULL either.
  1072. //
  1073. NlAssert( OwfPassword != NULL );
  1074. //
  1075. // If previous password is not found, return the current one instead.
  1076. //
  1077. *OwfPreviousPassword = *OwfPassword;
  1078. }
  1079. Status = STATUS_SUCCESS;
  1080. //
  1081. // Free locally used resources.
  1082. //
  1083. Cleanup:
  1084. if ( UserAllInfo != NULL ) {
  1085. SamIFree_SAMPR_USER_INFO_BUFFER( UserAllInfo,
  1086. UserAllInformation);
  1087. }
  1088. if ( UserHandle != NULL ) {
  1089. SamrCloseHandle( &UserHandle );
  1090. }
  1091. if ( TrustInfo != NULL ) {
  1092. LsaIFree_LSAPR_TRUSTED_DOMAIN_INFO( TrustedDomainFullInformation,
  1093. TrustInfo );
  1094. }
  1095. return Status;
  1096. }
  1097. NTSTATUS
  1098. NlSetIncomingPassword(
  1099. IN PDOMAIN_INFO DomainInfo,
  1100. IN LPWSTR AccountName,
  1101. IN NETLOGON_SECURE_CHANNEL_TYPE SecureChannelType,
  1102. IN PUNICODE_STRING ClearTextPassword OPTIONAL,
  1103. IN DWORD ClearPasswordVersionNumber,
  1104. IN PNT_OWF_PASSWORD OwfPassword OPTIONAL
  1105. )
  1106. /*++
  1107. Routine Description:
  1108. Set the incoming password for the specified AccountName and SecureChannelType.
  1109. At the same time, update the previous password info.
  1110. Arguments:
  1111. DomainInfo - Emulated domain
  1112. AccountName - Name of the account to set the password on
  1113. SecureChannelType - The type of the account being used.
  1114. ClearTextPassword - The Clear text password for the named account.
  1115. ClearPasswordVersionNumber - The version number of the Clear text password.
  1116. Used only for interdomain trust account. Ignored if ClearTextPassword
  1117. is NULL.
  1118. OwfPassword - The NT OWF of the incoming password for the named
  1119. account. If both the clear text and OWF password are specified,
  1120. the OWF password is ignored.
  1121. Return Value:
  1122. Status of operation.
  1123. --*/
  1124. {
  1125. NTSTATUS Status;
  1126. UNICODE_STRING AccountNameString;
  1127. ULONG Length;
  1128. LSAPR_TRUSTED_DOMAIN_INFO TrustInfo;
  1129. PLSAPR_TRUSTED_DOMAIN_INFO TrustInfoOld = NULL;
  1130. LSAPR_AUTH_INFORMATION CurrentAuthInfo[3], PreviousAuthInfo[3], NoneAuthInfo;
  1131. ULONG iClear, iOWF, iVersion, i;
  1132. DWORD OldVersionNumber = 0;
  1133. //
  1134. // Workstation and BDC secure channels get their outgoing password from
  1135. // an LSA secret.
  1136. //
  1137. switch ( SecureChannelType ) {
  1138. case ServerSecureChannel:
  1139. case WorkstationSecureChannel:
  1140. NlPrint(( NL_SESSION_SETUP, "Setting Password of '%ws' to: ", AccountName ));
  1141. if ( ClearTextPassword != NULL ) {
  1142. NlpDumpBuffer( NL_SESSION_SETUP, ClearTextPassword->Buffer, ClearTextPassword->Length );
  1143. } else if (OwfPassword != NULL ) {
  1144. NlpDumpBuffer( NL_SESSION_SETUP, OwfPassword, sizeof(*OwfPassword) );
  1145. }
  1146. //
  1147. // Set the encrypted password in SAM.
  1148. //
  1149. Status = NlSamChangePasswordNamedUser( DomainInfo,
  1150. AccountName,
  1151. ClearTextPassword,
  1152. OwfPassword );
  1153. if ( !NT_SUCCESS(Status) ) {
  1154. NlPrintDom((NL_CRITICAL, DomainInfo,
  1155. "NlSetIncomingPassword: Cannot change password on local user account %lX\n",
  1156. Status));
  1157. goto Cleanup;
  1158. }
  1159. break;
  1160. //
  1161. // Trusted domain secure channels get their incoming password from the trusted
  1162. // domain object.
  1163. //
  1164. case TrustedDomainSecureChannel:
  1165. case TrustedDnsDomainSecureChannel:
  1166. //
  1167. // If this is a DNS trust account,
  1168. // remove the optional . from the end of the account name.
  1169. //
  1170. RtlInitUnicodeString( &AccountNameString, AccountName );
  1171. Length = AccountNameString.Length / sizeof(WCHAR);
  1172. if ( SecureChannelType == TrustedDnsDomainSecureChannel ) {
  1173. if ( Length != 0 && AccountName[Length-1] == '.' ) {
  1174. AccountNameString.Length -= sizeof(WCHAR);
  1175. }
  1176. //
  1177. // If this is an NT4-style interdomain trust,
  1178. // remove the $ from the end of the account name.
  1179. //
  1180. } else {
  1181. //
  1182. // Ensure the account name has the correct postfix.
  1183. //
  1184. if ( Length <= SSI_ACCOUNT_NAME_POSTFIX_LENGTH ) {
  1185. Status = STATUS_NO_SUCH_USER;
  1186. goto Cleanup;
  1187. }
  1188. if ( _wcsicmp(&AccountName[Length - SSI_ACCOUNT_NAME_POSTFIX_LENGTH],
  1189. SSI_ACCOUNT_NAME_POSTFIX) != 0 ) {
  1190. Status = STATUS_NO_SUCH_USER;
  1191. goto Cleanup;
  1192. }
  1193. AccountNameString.Length -= SSI_ACCOUNT_NAME_POSTFIX_LENGTH*sizeof(WCHAR);
  1194. }
  1195. //
  1196. // First get the current authentication information (that is old as far as
  1197. // the function is concerned) from the LSA.
  1198. //
  1199. Status = LsarQueryTrustedDomainInfoByName(
  1200. DomainInfo->DomLsaPolicyHandle,
  1201. (PLSAPR_UNICODE_STRING) &AccountNameString,
  1202. TrustedDomainAuthInformation,
  1203. &TrustInfoOld );
  1204. if (!NT_SUCCESS(Status)) {
  1205. NlPrintDom((NL_CRITICAL, DomainInfo,
  1206. "NlSetIncomingPassword: %wZ: cannot LsarQueryTrustedDomainInfoByName 0x%lx\n",
  1207. &AccountNameString,
  1208. Status ));
  1209. // if ( !NlpIsNtStatusResourceError( Status )) {
  1210. // Status = STATUS_NO_SUCH_USER;
  1211. // }
  1212. goto Cleanup;
  1213. }
  1214. //
  1215. // Fill in the trust information.
  1216. //
  1217. RtlZeroMemory( &TrustInfo, sizeof(TrustInfo) );
  1218. TrustInfo.TrustedAuthInfo.IncomingAuthInfos = 0;
  1219. TrustInfo.TrustedAuthInfo.IncomingAuthenticationInformation =
  1220. CurrentAuthInfo;
  1221. TrustInfo.TrustedAuthInfo.IncomingPreviousAuthenticationInformation =
  1222. PreviousAuthInfo;
  1223. //
  1224. // Fill in the current and previous authentication information.
  1225. //
  1226. NlQuerySystemTime( &CurrentAuthInfo[0].LastUpdateTime );
  1227. NlPrint(( NL_SESSION_SETUP, "Setting Password of '%ws' to: ", AccountName ));
  1228. if ( ClearTextPassword != NULL ) {
  1229. CurrentAuthInfo[0].AuthType = TRUST_AUTH_TYPE_CLEAR;
  1230. CurrentAuthInfo[0].AuthInfoLength = ClearTextPassword->Length;
  1231. CurrentAuthInfo[0].AuthInfo = (LPBYTE)ClearTextPassword->Buffer;
  1232. NlpDumpBuffer(NL_SESSION_SETUP, ClearTextPassword->Buffer, ClearTextPassword->Length );
  1233. CurrentAuthInfo[1].LastUpdateTime = CurrentAuthInfo[0].LastUpdateTime;
  1234. CurrentAuthInfo[1].AuthType = TRUST_AUTH_TYPE_VERSION;
  1235. CurrentAuthInfo[1].AuthInfoLength = sizeof(ClearPasswordVersionNumber);
  1236. CurrentAuthInfo[1].AuthInfo = (LPBYTE) &ClearPasswordVersionNumber;
  1237. NlPrint(( NL_SESSION_SETUP, "Password Version number is %lu\n",
  1238. ClearPasswordVersionNumber ));
  1239. } else {
  1240. CurrentAuthInfo[0].AuthType = TRUST_AUTH_TYPE_NT4OWF;
  1241. CurrentAuthInfo[0].AuthInfoLength = sizeof(*OwfPassword);
  1242. CurrentAuthInfo[0].AuthInfo = (LPBYTE)OwfPassword;
  1243. NlpDumpBuffer(NL_SESSION_SETUP, OwfPassword, sizeof(*OwfPassword) );
  1244. }
  1245. //
  1246. // The AuthType values of corresponding elements of IncomingAuthenticationInformation and
  1247. // IncomingPreviousAuthenticationInformation arrays must be the same for internal reasons.
  1248. // Thus, use NoneAuthInfo element to fill in missing counterparts in these arrays.
  1249. NoneAuthInfo.LastUpdateTime = CurrentAuthInfo[0].LastUpdateTime;
  1250. NoneAuthInfo.AuthType = TRUST_AUTH_TYPE_NONE;
  1251. NoneAuthInfo.AuthInfoLength = 0;
  1252. NoneAuthInfo.AuthInfo = NULL;
  1253. //
  1254. // Find first Clear and OWF passwords (if any) in the old password info.
  1255. //
  1256. for ( iClear = 0; iClear < TrustInfoOld->TrustedAuthInfo.IncomingAuthInfos; iClear++ ) {
  1257. if ( TrustInfoOld->TrustedAuthInfo.IncomingAuthenticationInformation[iClear].AuthType ==
  1258. TRUST_AUTH_TYPE_CLEAR ) {
  1259. break;
  1260. }
  1261. }
  1262. for ( iVersion = 0; iVersion < TrustInfoOld->TrustedAuthInfo.IncomingAuthInfos; iVersion++ ) {
  1263. if ( TrustInfoOld->TrustedAuthInfo.IncomingAuthenticationInformation[iVersion].AuthType ==
  1264. TRUST_AUTH_TYPE_VERSION &&
  1265. TrustInfoOld->TrustedAuthInfo.IncomingAuthenticationInformation[iVersion].AuthInfoLength ==
  1266. sizeof(OldVersionNumber) ) {
  1267. RtlCopyMemory( &OldVersionNumber,
  1268. TrustInfoOld->TrustedAuthInfo.IncomingAuthenticationInformation[iVersion].AuthInfo,
  1269. sizeof(OldVersionNumber) );
  1270. break;
  1271. }
  1272. }
  1273. for ( iOWF = 0; iOWF < TrustInfoOld->TrustedAuthInfo.IncomingAuthInfos; iOWF++ ) {
  1274. if ( TrustInfoOld->TrustedAuthInfo.IncomingAuthenticationInformation[iOWF].AuthType ==
  1275. TRUST_AUTH_TYPE_NT4OWF ) {
  1276. break;
  1277. }
  1278. }
  1279. //
  1280. // Update previous info using only first Clear and OWF passwords in the current info
  1281. // (that is old as far as this function is concerned). AuthTypes other than Clear,
  1282. // Version, and OWF are going to be lost.
  1283. //
  1284. if (ClearTextPassword != NULL) {
  1285. if (iClear < TrustInfoOld->TrustedAuthInfo.IncomingAuthInfos) {
  1286. PreviousAuthInfo[0] = TrustInfoOld->TrustedAuthInfo.IncomingAuthenticationInformation[iClear];
  1287. } else {
  1288. PreviousAuthInfo[0] = NoneAuthInfo;
  1289. }
  1290. //
  1291. // Preserve the old version number only if it is in accordance with the passed value
  1292. //
  1293. if ( iVersion < TrustInfoOld->TrustedAuthInfo.IncomingAuthInfos &&
  1294. ClearPasswordVersionNumber > 0 &&
  1295. OldVersionNumber == ClearPasswordVersionNumber - 1 ) {
  1296. PreviousAuthInfo[1] = TrustInfoOld->TrustedAuthInfo.IncomingAuthenticationInformation[iVersion];
  1297. } else {
  1298. PreviousAuthInfo[1] = NoneAuthInfo;
  1299. }
  1300. TrustInfo.TrustedAuthInfo.IncomingAuthInfos = 2;
  1301. //
  1302. // If there is a previous OWF password, preserve it
  1303. //
  1304. if (iOWF < TrustInfoOld->TrustedAuthInfo.IncomingAuthInfos) {
  1305. PreviousAuthInfo[2] = TrustInfoOld->TrustedAuthInfo.IncomingAuthenticationInformation[iOWF];
  1306. CurrentAuthInfo[2] = NoneAuthInfo;
  1307. TrustInfo.TrustedAuthInfo.IncomingAuthInfos = 3;
  1308. }
  1309. } else {
  1310. if (iOWF < TrustInfoOld->TrustedAuthInfo.IncomingAuthInfos) {
  1311. PreviousAuthInfo[0] = TrustInfoOld->TrustedAuthInfo.IncomingAuthenticationInformation[iOWF];
  1312. } else {
  1313. PreviousAuthInfo[0] = NoneAuthInfo;
  1314. }
  1315. TrustInfo.TrustedAuthInfo.IncomingAuthInfos = 1;
  1316. //
  1317. // If there is a previous clear text password, preserve it
  1318. //
  1319. if (iClear < TrustInfoOld->TrustedAuthInfo.IncomingAuthInfos) {
  1320. PreviousAuthInfo[1] = TrustInfoOld->TrustedAuthInfo.IncomingAuthenticationInformation[iClear];
  1321. CurrentAuthInfo[1] = NoneAuthInfo;
  1322. TrustInfo.TrustedAuthInfo.IncomingAuthInfos = 2;
  1323. }
  1324. //
  1325. // If there is a previous clear text password version number, preserve it
  1326. //
  1327. if (iVersion < TrustInfoOld->TrustedAuthInfo.IncomingAuthInfos) {
  1328. PreviousAuthInfo[2] = TrustInfoOld->TrustedAuthInfo.IncomingAuthenticationInformation[iVersion];
  1329. CurrentAuthInfo[2] = NoneAuthInfo;
  1330. TrustInfo.TrustedAuthInfo.IncomingAuthInfos = 3;
  1331. }
  1332. }
  1333. for ( i = 0; i < TrustInfo.TrustedAuthInfo.IncomingAuthInfos; i++ ) {
  1334. if ( CurrentAuthInfo[i].AuthType == TRUST_AUTH_TYPE_CLEAR) {
  1335. NlPrint(( NL_SESSION_SETUP, "Current Clear Text Password of '%ws' is: ", AccountName ));
  1336. NlpDumpBuffer(NL_SESSION_SETUP, CurrentAuthInfo[i].AuthInfo, CurrentAuthInfo[i].AuthInfoLength );
  1337. } else if ( CurrentAuthInfo[i].AuthType == TRUST_AUTH_TYPE_VERSION ) {
  1338. NlPrint(( NL_SESSION_SETUP, "Current Clear Password Version Number of '%ws' is: ", AccountName ));
  1339. NlpDumpBuffer(NL_SESSION_SETUP, CurrentAuthInfo[i].AuthInfo, CurrentAuthInfo[i].AuthInfoLength );
  1340. } else if ( CurrentAuthInfo[i].AuthType == TRUST_AUTH_TYPE_NT4OWF) {
  1341. NlPrint(( NL_SESSION_SETUP, "Current OWF Password of '%ws' is: ", AccountName ));
  1342. NlpDumpBuffer(NL_SESSION_SETUP, CurrentAuthInfo[i].AuthInfo, CurrentAuthInfo[i].AuthInfoLength );
  1343. } else if ( CurrentAuthInfo[i].AuthType == TRUST_AUTH_TYPE_NONE) {
  1344. NlPrint(( NL_SESSION_SETUP, "Current Auth Info entry for '%ws' has no type\n", AccountName ));
  1345. }
  1346. if ( PreviousAuthInfo[i].AuthType == TRUST_AUTH_TYPE_CLEAR) {
  1347. NlPrint(( NL_SESSION_SETUP, "Previous Clear Text Password of '%ws' is: ", AccountName ));
  1348. NlpDumpBuffer(NL_SESSION_SETUP, PreviousAuthInfo[i].AuthInfo, PreviousAuthInfo[i].AuthInfoLength );
  1349. } else if ( PreviousAuthInfo[i].AuthType == TRUST_AUTH_TYPE_VERSION ) {
  1350. NlPrint(( NL_SESSION_SETUP, "Previous Clear Password Version Number of '%ws' is: ", AccountName ));
  1351. NlpDumpBuffer(NL_SESSION_SETUP, PreviousAuthInfo[i].AuthInfo, PreviousAuthInfo[i].AuthInfoLength );
  1352. } else if ( PreviousAuthInfo[i].AuthType == TRUST_AUTH_TYPE_NT4OWF) {
  1353. NlPrint(( NL_SESSION_SETUP, "Previous OWF Text Password of '%ws' is: ", AccountName ));
  1354. NlpDumpBuffer(NL_SESSION_SETUP, PreviousAuthInfo[i].AuthInfo, PreviousAuthInfo[i].AuthInfoLength );
  1355. } else if ( PreviousAuthInfo[i].AuthType == TRUST_AUTH_TYPE_NONE) {
  1356. NlPrint(( NL_SESSION_SETUP, "Previous Auth Info entry for '%ws' has no type\n", AccountName ));
  1357. }
  1358. }
  1359. //
  1360. // Set the authentication information in the LSA.
  1361. //
  1362. Status = LsarSetTrustedDomainInfoByName(
  1363. DomainInfo->DomLsaPolicyHandle,
  1364. (PLSAPR_UNICODE_STRING) &AccountNameString,
  1365. TrustedDomainAuthInformation,
  1366. &TrustInfo );
  1367. if (!NT_SUCCESS(Status)) {
  1368. NlPrintDom((NL_CRITICAL, DomainInfo,
  1369. "NlSetIncomingPassword: %wZ: cannot LsarSetTrustedDomainInfoByName 0x%lx\n",
  1370. &AccountNameString,
  1371. Status ));
  1372. goto Cleanup;
  1373. }
  1374. break;
  1375. //
  1376. // We don't support any other secure channel type
  1377. //
  1378. default:
  1379. NlPrintDom((NL_CRITICAL, DomainInfo,
  1380. "NlSetIncomingPassword: %ws: invalid secure channel type: %ld\n",
  1381. AccountName,
  1382. SecureChannelType ));
  1383. Status = STATUS_ACCESS_DENIED;
  1384. goto Cleanup;
  1385. }
  1386. Status = STATUS_SUCCESS;
  1387. //
  1388. // Free locally used resources.
  1389. //
  1390. Cleanup:
  1391. if ( TrustInfoOld != NULL ) {
  1392. LsaIFree_LSAPR_TRUSTED_DOMAIN_INFO( TrustedDomainAuthInformation,
  1393. TrustInfoOld );
  1394. }
  1395. return Status;
  1396. }
  1397. BOOLEAN
  1398. NlTimeToRediscover(
  1399. IN PCLIENT_SESSION ClientSession,
  1400. BOOLEAN WithAccount
  1401. )
  1402. /*++
  1403. Routine Description:
  1404. Determine if it is time to rediscover this Client Session.
  1405. If a session setup failure happens to a discovered DC,
  1406. rediscover the DC if the discovery happened a long time ago (more than 5 minutes).
  1407. Arguments:
  1408. ClientSession - Structure used to define the session.
  1409. WithAccount - If TRUE, the caller is going to attempt the discovery "with account".
  1410. Return Value:
  1411. TRUE -- iff it is time to re-discover
  1412. --*/
  1413. {
  1414. BOOLEAN ReturnBoolean;
  1415. EnterCriticalSection( &NlGlobalDcDiscoveryCritSect );
  1416. //
  1417. // If the last discovery was longer than 5 minutes ago,
  1418. // it's fine to rediscover regardless of the rediscovery
  1419. // type (with or without account)
  1420. //
  1421. ReturnBoolean = NetpLogonTimeHasElapsed(
  1422. ClientSession->CsLastDiscoveryTime,
  1423. MAX_DC_REAUTHENTICATION_WAIT );
  1424. //
  1425. // If it turns out that the last rediscovery was recent but
  1426. // the caller is going to attempt the discovery "with account"
  1427. // perhaps the last rediscovery with account wasn't recent
  1428. //
  1429. if ( !ReturnBoolean && WithAccount ) {
  1430. ReturnBoolean = NetpLogonTimeHasElapsed(
  1431. ClientSession->CsLastDiscoveryWithAccountTime,
  1432. MAX_DC_REAUTHENTICATION_WAIT );
  1433. }
  1434. LeaveCriticalSection( &NlGlobalDcDiscoveryCritSect );
  1435. return ReturnBoolean;
  1436. }
  1437. NET_API_STATUS
  1438. NlCacheJoinDomainControllerInfo(
  1439. VOID
  1440. )
  1441. /*++
  1442. Routine Description:
  1443. This function reads from the registry and caches the DC information
  1444. that was previously written by the join process. This DC is bound
  1445. to have the correct password for this machine. If no info is
  1446. available in the registry, no action needs to be taken.
  1447. The join DC info is cached in the DsGetDcName cache. Netlogon will
  1448. then discover this DC and will set up a secure channel to it. Caching
  1449. the DC info in the DsGetDcName cache will ensure that not only Netlogon
  1450. but every other process will consistently talk to this DC.
  1451. Arguments:
  1452. None.
  1453. Return Value:
  1454. NO_ERROR - The DC info (if any) was read and the client session
  1455. strusture was successfully set.
  1456. Otherwise, some error occured during this operation.
  1457. --*/
  1458. {
  1459. ULONG WinError = ERROR_SUCCESS; // Registry reading errors
  1460. NET_API_STATUS NetStatus = NO_ERROR; // Netlogon API return codes
  1461. HKEY hJoinKey = NULL;
  1462. ULONG BytesRead = 0;
  1463. ULONG Type;
  1464. DWORD KerberosIsDone = 0;
  1465. LPWSTR DcName = NULL;
  1466. ULONG DcFlags = 0;
  1467. PDOMAIN_INFO DomainInfo = NULL;
  1468. PCLIENT_SESSION ClientSession = NULL;
  1469. PNL_DC_CACHE_ENTRY DcCacheEntry = NULL;
  1470. //
  1471. // Caching the join DC info is needed only for workstations
  1472. //
  1473. if ( !NlGlobalMemberWorkstation ) {
  1474. return NO_ERROR;
  1475. }
  1476. //
  1477. // Open the registry key
  1478. //
  1479. WinError = RegOpenKey( HKEY_LOCAL_MACHINE,
  1480. NETSETUPP_NETLOGON_JD_NAME,
  1481. &hJoinKey );
  1482. if ( WinError != ERROR_SUCCESS) {
  1483. goto Cleanup;
  1484. }
  1485. //
  1486. // Read DC name
  1487. //
  1488. WinError = RegQueryValueEx( hJoinKey,
  1489. NETSETUPP_NETLOGON_JD_DC,
  1490. 0,
  1491. &Type,
  1492. NULL,
  1493. &BytesRead);
  1494. if ( WinError != ERROR_SUCCESS ) {
  1495. goto Cleanup;
  1496. } else if ( Type != REG_SZ ) {
  1497. WinError = ERROR_DATATYPE_MISMATCH;
  1498. goto Cleanup;
  1499. }
  1500. DcName = LocalAlloc( LMEM_ZEROINIT, BytesRead );
  1501. if ( DcName == NULL ) {
  1502. WinError = ERROR_NOT_ENOUGH_MEMORY;
  1503. goto Cleanup;
  1504. }
  1505. WinError = RegQueryValueEx( hJoinKey,
  1506. NETSETUPP_NETLOGON_JD_DC,
  1507. 0,
  1508. &Type,
  1509. (PUCHAR) DcName,
  1510. &BytesRead);
  1511. if ( WinError != ERROR_SUCCESS) {
  1512. goto Cleanup;
  1513. }
  1514. //
  1515. // The name should include at least '\\' and one character
  1516. //
  1517. if ( wcslen(DcName) < 3 ) {
  1518. NlPrint(( NL_CRITICAL,
  1519. "NlCacheJoinDomainControllerInfo: DcName is too short.\n" ));
  1520. WinError = ERROR_DATATYPE_MISMATCH;
  1521. goto Cleanup;
  1522. }
  1523. //
  1524. // Read Flags
  1525. //
  1526. WinError = RegQueryValueEx( hJoinKey,
  1527. NETSETUPP_NETLOGON_JD_F,
  1528. 0,
  1529. &Type,
  1530. NULL,
  1531. &BytesRead);
  1532. if ( WinError != ERROR_SUCCESS ) {
  1533. goto Cleanup;
  1534. } else if ( Type != REG_DWORD ) {
  1535. WinError = ERROR_DATATYPE_MISMATCH;
  1536. goto Cleanup;
  1537. }
  1538. WinError = RegQueryValueEx( hJoinKey,
  1539. NETSETUPP_NETLOGON_JD_F,
  1540. 0,
  1541. &Type,
  1542. (PUCHAR)&DcFlags,
  1543. &BytesRead);
  1544. if ( WinError != ERROR_SUCCESS) {
  1545. goto Cleanup;
  1546. }
  1547. //
  1548. // If we've made it up to this point, the registry was successfully read
  1549. //
  1550. WinError = ERROR_SUCCESS;
  1551. NlPrint(( NL_INIT, "Join DC: %ws, Flags: 0x%lx\n", DcName, DcFlags ));
  1552. //
  1553. // If we are started right after a domain join,
  1554. // the browser has been notified about the
  1555. // domain rename by a change log worker.
  1556. // Wait until the change log worker exits.
  1557. // Otherwise, the browser will reject the
  1558. // datagram send when we pass the new emulated
  1559. // domain name. Do this even if we end up avoiding
  1560. // the ping in this routine (for NT4.0 DC) because
  1561. // we'll do the ping just a little bit later for
  1562. // the DC discovery.
  1563. //
  1564. NlWaitForChangeLogBrowserNotify();
  1565. //
  1566. // If this is not NT5 DC, avoid caching it since it's a PDC.
  1567. // We don't want to overload the PDC by having all clients
  1568. // talking to it after they join the domain. We will just
  1569. // delete the reg key here because Kerberos won't use NT4 DC
  1570. // anyway.
  1571. //
  1572. if ( (DcFlags & DS_DS_FLAG) == 0 ) {
  1573. ULONG WinErrorTmp = ERROR_SUCCESS;
  1574. HKEY hJoinKeyTmp = NULL;
  1575. NlPrint(( NL_INIT, "NlCacheJoinDomainControllerInfo: Join DC is not NT5, deleting it\n" ));
  1576. WinErrorTmp = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  1577. NETSETUPP_NETLOGON_JD_PATH,
  1578. 0,
  1579. KEY_ALL_ACCESS,
  1580. &hJoinKeyTmp );
  1581. if ( WinErrorTmp == ERROR_SUCCESS ) {
  1582. WinErrorTmp = RegDeleteKey( hJoinKeyTmp,
  1583. NETSETUPP_NETLOGON_JD );
  1584. if ( WinErrorTmp != ERROR_SUCCESS ) {
  1585. NlPrint(( NL_CRITICAL,
  1586. "NlCacheJoinDomainControllerInfo: Couldn't deleted JoinDomain 0x%lx\n",
  1587. WinErrorTmp ));
  1588. }
  1589. RegCloseKey( hJoinKeyTmp );
  1590. } else {
  1591. NlPrint(( NL_CRITICAL,
  1592. "NlCacheJoinDomainControllerInfo: RegOpenKeyEx failed 0x%lx\n",
  1593. WinErrorTmp ));
  1594. }
  1595. //
  1596. // Treat this as error
  1597. //
  1598. NetStatus = ERROR_INVALID_DATA;
  1599. goto Cleanup;
  1600. }
  1601. //
  1602. // Now get the client session to the primary domain
  1603. //
  1604. DomainInfo = NlFindNetbiosDomain( NULL, TRUE ); // Primary domain
  1605. if ( DomainInfo == NULL ) {
  1606. NlPrint(( NL_CRITICAL,
  1607. "NlCacheJoinDomainControllerInfo: Cannot NlFindNetbiosDomain\n" ));
  1608. NetStatus = ERROR_NO_SUCH_DOMAIN;
  1609. goto Cleanup;
  1610. }
  1611. ClientSession = NlRefDomClientSession( DomainInfo );
  1612. if ( ClientSession == NULL ) {
  1613. NlPrint(( NL_CRITICAL,
  1614. "NlCacheJoinDomainControllerInfo: Cannot NlRefDomClientSession\n" ));
  1615. NetStatus = ERROR_NO_SUCH_DOMAIN;
  1616. goto Cleanup;
  1617. }
  1618. //
  1619. // Finally ping the DC given this info. Cache the response.
  1620. //
  1621. NetStatus = NlPingDcName( ClientSession,
  1622. (DcFlags & DS_DNS_CONTROLLER_FLAG) ?
  1623. DS_PING_DNS_HOST :
  1624. DS_PING_NETBIOS_HOST,
  1625. TRUE, // Cache this DC
  1626. FALSE, // Do not require IP
  1627. TRUE, // Ensure the DC has our account
  1628. FALSE, // Do not refresh the session
  1629. DcName+2, // Skip '\\' in the name
  1630. &DcCacheEntry );
  1631. if ( NetStatus == NO_ERROR ) {
  1632. NlPrint(( NL_INIT, "Join DC cached successfully\n" ));
  1633. //
  1634. // Also set the site name
  1635. //
  1636. if ( DcCacheEntry->UnicodeClientSiteName != NULL ) {
  1637. NlSetDynamicSiteName( DcCacheEntry->UnicodeClientSiteName );
  1638. }
  1639. } else {
  1640. NlPrint(( NL_CRITICAL, "Failed to cache join DC: 0x%lx\n", NetStatus ));
  1641. }
  1642. Cleanup:
  1643. //
  1644. // Free up locally used resources
  1645. //
  1646. if ( DcName != NULL ) {
  1647. LocalFree( DcName );
  1648. }
  1649. if ( DcCacheEntry != NULL ) {
  1650. NetpDcDerefCacheEntry( DcCacheEntry );
  1651. }
  1652. if ( hJoinKey != NULL ) {
  1653. RegCloseKey( hJoinKey );
  1654. }
  1655. if ( ClientSession != NULL ) {
  1656. NlUnrefClientSession( ClientSession );
  1657. }
  1658. if ( DomainInfo != NULL ) {
  1659. NlDereferenceDomain( DomainInfo );
  1660. }
  1661. //
  1662. // If everything is successful return NO_ERROR.
  1663. // Otherwise, if Netlogon API failed, return its error code.
  1664. // Otherwise, return registry reading error.
  1665. //
  1666. if ( WinError == ERROR_SUCCESS && NetStatus == NO_ERROR ) {
  1667. return NO_ERROR;
  1668. } else if ( NetStatus != NO_ERROR ) {
  1669. return NetStatus;
  1670. } else {
  1671. return WinError;
  1672. }
  1673. }
  1674. NTSTATUS
  1675. NlGetPasswordFromPdc(
  1676. IN PDOMAIN_INFO DomainInfo,
  1677. IN LPWSTR AccountName,
  1678. IN NETLOGON_SECURE_CHANNEL_TYPE AccountType,
  1679. OUT PNT_OWF_PASSWORD NtOwfPassword
  1680. )
  1681. /*++
  1682. Routine Description:
  1683. This function is used to by a BDC to get a machine account password
  1684. from the PDC in the doamin.
  1685. Arguments:
  1686. DomainInfo - Identifies the domain the account is in.
  1687. AccountName -- Name of the account to get the password for.
  1688. AccountType -- The type of account being accessed.
  1689. EncryptedNtOwfPassword -- Returns the OWF password of the account.
  1690. Return Value:
  1691. NT status code.
  1692. --*/
  1693. {
  1694. NTSTATUS Status;
  1695. NETLOGON_AUTHENTICATOR OurAuthenticator;
  1696. NETLOGON_AUTHENTICATOR ReturnAuthenticator;
  1697. PCLIENT_SESSION ClientSession = NULL;
  1698. SESSION_INFO SessionInfo;
  1699. BOOLEAN FirstTry = TRUE;
  1700. BOOLEAN AmWriter = FALSE;
  1701. ENCRYPTED_LM_OWF_PASSWORD SessKeyEncrPassword;
  1702. NlPrintDom((NL_SESSION_SETUP, DomainInfo,
  1703. "NlGetPasswordFromPdc: Getting password for %ws from PDC.\n",
  1704. AccountName ));
  1705. //
  1706. // Reference the client session.
  1707. //
  1708. ClientSession = NlRefDomClientSession( DomainInfo );
  1709. if ( ClientSession == NULL ) {
  1710. NlPrintDom((NL_CRITICAL, DomainInfo,
  1711. "NlGetPasswordFromPdc: This BDC has no client session with the PDC.\n"));
  1712. Status = STATUS_NO_LOGON_SERVERS;
  1713. goto Cleanup;
  1714. }
  1715. //
  1716. // Become a Writer of the ClientSession.
  1717. //
  1718. if ( !NlTimeoutSetWriterClientSession( ClientSession, WRITER_WAIT_PERIOD ) ) {
  1719. NlPrintDom((NL_CRITICAL, DomainInfo,
  1720. "NlGetPasswordFromPdc: Can't become writer of client session.\n"));
  1721. Status = STATUS_NO_LOGON_SERVERS;
  1722. goto Cleanup;
  1723. }
  1724. AmWriter = TRUE;
  1725. //
  1726. // If the session isn't authenticated,
  1727. // do so now.
  1728. //
  1729. FirstTryFailed:
  1730. Status = NlEnsureSessionAuthenticated( ClientSession, 0 );
  1731. if ( !NT_SUCCESS(Status) ) {
  1732. goto Cleanup;
  1733. }
  1734. SessionInfo.SessionKey = ClientSession->CsSessionKey;
  1735. // SessionInfo.NegotiatedFlags = ClientSession->CsNegotiatedFlags;
  1736. //
  1737. // Build the Authenticator for this request to the PDC.
  1738. //
  1739. NlBuildAuthenticator(
  1740. &ClientSession->CsAuthenticationSeed,
  1741. &ClientSession->CsSessionKey,
  1742. &OurAuthenticator);
  1743. //
  1744. // Get the password from the PDC
  1745. //
  1746. NL_API_START( Status, ClientSession, TRUE ) {
  1747. NlAssert( ClientSession->CsUncServerName != NULL );
  1748. Status = I_NetServerPasswordGet( ClientSession->CsUncServerName,
  1749. AccountName,
  1750. AccountType,
  1751. ClientSession->CsDomainInfo->DomUnicodeComputerNameString.Buffer,
  1752. &OurAuthenticator,
  1753. &ReturnAuthenticator,
  1754. &SessKeyEncrPassword);
  1755. if ( !NT_SUCCESS(Status) ) {
  1756. NlPrintRpcDebug( "I_NetServerPasswordGet", Status );
  1757. }
  1758. // NOTE: This call may drop the secure channel behind our back
  1759. } NL_API_ELSE( Status, ClientSession, TRUE ) {
  1760. } NL_API_END;
  1761. //
  1762. // Now verify primary's authenticator and update our seed
  1763. //
  1764. if ( Status == STATUS_ACCESS_DENIED ||
  1765. !NlUpdateSeed( &ClientSession->CsAuthenticationSeed,
  1766. &ReturnAuthenticator.Credential,
  1767. &ClientSession->CsSessionKey) ) {
  1768. NlPrintCs(( NL_CRITICAL, ClientSession,
  1769. "NlGetPasswordFromPdc: denying access after status: 0x%lx\n",
  1770. Status ));
  1771. //
  1772. // Preserve any status indicating a communication error.
  1773. //
  1774. if ( NT_SUCCESS(Status) ) {
  1775. Status = STATUS_ACCESS_DENIED;
  1776. }
  1777. NlSetStatusClientSession( ClientSession, Status );
  1778. //
  1779. // Perhaps the netlogon service on the server has just restarted.
  1780. // Try just once to set up a session to the server again.
  1781. //
  1782. if ( FirstTry ) {
  1783. FirstTry = FALSE;
  1784. goto FirstTryFailed;
  1785. }
  1786. }
  1787. if ( !NT_SUCCESS(Status) ) {
  1788. goto Cleanup;
  1789. }
  1790. //
  1791. // Decrypt the password returned from the PDC.
  1792. //
  1793. Status = RtlDecryptNtOwfPwdWithNtOwfPwd(
  1794. &SessKeyEncrPassword,
  1795. (PNT_OWF_PASSWORD) &SessionInfo.SessionKey,
  1796. NtOwfPassword );
  1797. NlAssert( NT_SUCCESS(Status) );
  1798. //
  1799. // Common exit
  1800. //
  1801. Cleanup:
  1802. if ( ClientSession != NULL ) {
  1803. if ( AmWriter ) {
  1804. NlResetWriterClientSession( ClientSession );
  1805. }
  1806. NlUnrefClientSession( ClientSession );
  1807. }
  1808. if ( !NT_SUCCESS(Status) ) {
  1809. NlPrintDom((NL_CRITICAL, DomainInfo,
  1810. "NlGetPasswordFromPdc: %ws: failed %lX\n",
  1811. AccountName,
  1812. Status));
  1813. }
  1814. return Status;
  1815. }
  1816. NTSTATUS
  1817. NlSessionSetup(
  1818. IN OUT PCLIENT_SESSION ClientSession
  1819. )
  1820. /*++
  1821. Routine Description:
  1822. Verify that the requestor (this machine) has a valid account at
  1823. Primary Domain Controller (primary). The authentication
  1824. is done via an elaborate protocol. This routine will be
  1825. used only when NETLOGON service starts with role != primary.
  1826. The requestor (i.e. this machine) will generate a challenge
  1827. and send it to the Primary Domain Controller and will receive
  1828. a challenge from the primary in response. Now we will compute
  1829. credentials using primary's challenge and send it across and
  1830. wait for credentials, computed at primary using our initial
  1831. challenge, to be returned by PDC. Before computing credentials
  1832. a sessionkey will be built which uniquely identifies this
  1833. session and it will be returned to caller for future use.
  1834. If both machines authenticate then they keep the
  1835. ClientCredential and the session key for future use.
  1836. ?? If multiple domains are supported on a single DC, what mechanism
  1837. do I use to short circuit discovery? What mechanism do I use to short
  1838. circuit API calls (e.g., pass through authentication) to a DC in that
  1839. domain? Do Ihave to worry about lock contention across such API calls?
  1840. Can I avoid authentication/encryption acress such a secure channel?
  1841. Arguments:
  1842. ClientSession - Structure used to define the session.
  1843. On Input the following fields must be set:
  1844. CsState
  1845. CsNetbiosDomainName
  1846. CsUncServerName (May be NULL string depending on SecureChannelType)
  1847. CsAccountName
  1848. CsSecureChannelType
  1849. The caller must be a writer of the ClientSession.
  1850. On Output, the following fields will be set
  1851. CsConnectionStatus
  1852. CsState
  1853. CsSessionKey
  1854. CsAuthenticationSeed
  1855. Return Value:
  1856. Status of operation.
  1857. --*/
  1858. {
  1859. NTSTATUS Status;
  1860. NETLOGON_CREDENTIAL ServerChallenge;
  1861. NETLOGON_CREDENTIAL ClientChallenge;
  1862. NETLOGON_CREDENTIAL ComputedServerCredential;
  1863. NETLOGON_CREDENTIAL ReturnedServerCredential;
  1864. BOOLEAN WeDidDiscovery = FALSE;
  1865. BOOLEAN WeDidDiscoveryWithAccount = FALSE;
  1866. BOOLEAN ErrorFromDiscoveredServer = FALSE;
  1867. BOOLEAN SignOrSealError = FALSE;
  1868. BOOLEAN GotNonDsDc = FALSE;
  1869. BOOLEAN DomainDowngraded = FALSE;
  1870. NT_OWF_PASSWORD NtOwfPassword;
  1871. DWORD NegotiatedFlags;
  1872. PUNICODE_STRING NewPassword = NULL;
  1873. PUNICODE_STRING OldPassword = NULL;
  1874. LARGE_INTEGER PasswordChangeTime;
  1875. NT_OWF_PASSWORD NewOwfPassword;
  1876. PNT_OWF_PASSWORD PNewOwfPassword = NULL;
  1877. NT_OWF_PASSWORD OldOwfPassword;
  1878. PNT_OWF_PASSWORD POldOwfPassword = NULL;
  1879. NT_OWF_PASSWORD PdcOwfPassword;
  1880. ULONG i;
  1881. ULONG KeyStrength;
  1882. DWORD DummyPasswordVersionNumber;
  1883. //
  1884. // Used to indicate whether the current or the old password is being
  1885. // tried to access the DC.
  1886. // 0: implies the current password
  1887. // 1: implies the old password
  1888. // 2: implies both failed
  1889. //
  1890. DWORD State;
  1891. //
  1892. // Ensure we're a writer.
  1893. //
  1894. NlAssert( ClientSession->CsReferenceCount > 0 );
  1895. NlAssert( ClientSession->CsFlags & CS_WRITER );
  1896. NlPrintCs((NL_SESSION_SETUP, ClientSession,
  1897. "NlSessionSetup: Try Session setup\n" ));
  1898. //
  1899. // Start the WMI trace of secure channel setup
  1900. //
  1901. NlpTraceEvent( EVENT_TRACE_TYPE_START, NlpGuidSecureChannelSetup );
  1902. //
  1903. // If we're free to pick the DC which services our request,
  1904. // do so.
  1905. //
  1906. // Apparently there was a problem with the previously chosen DC
  1907. // so we pick again here. (There is a chance we'll pick the same server.)
  1908. //
  1909. NlPrint(( NL_SESSION_MORE, "NlSessionSetup: ClientSession->CsState = 0x%lx\n",
  1910. ClientSession->CsState));
  1911. if ( ClientSession->CsState == CS_IDLE ) {
  1912. NlAssert( ClientSession->CsUncServerName == NULL );
  1913. WeDidDiscovery = TRUE;
  1914. //
  1915. // Pick the name of a DC in the domain.
  1916. //
  1917. // On the first try do not specify the account in
  1918. // the discovery attempt as discoveries with account
  1919. // are much more costly than plain discoveries on the
  1920. // server side. If we fail session setup because the
  1921. // discovered server doesn't have our account, we will
  1922. // retry the discovery with account below.
  1923. //
  1924. Status = NlDiscoverDc( ClientSession,
  1925. DT_Synchronous,
  1926. FALSE,
  1927. FALSE ) ; // without account
  1928. if ( !NT_SUCCESS(Status) ) {
  1929. NlPrintCs((NL_CRITICAL, ClientSession,
  1930. "NlSessionSetup: Session setup: cannot pick trusted DC\n" ));
  1931. goto Cleanup;
  1932. }
  1933. }
  1934. NlAssert( ClientSession->CsState != CS_IDLE );
  1935. FirstTryFailed:
  1936. //
  1937. // If this is a workstation in an NT5 domain, we should not use NT4 DC.
  1938. // Indeed, Negotiate will not use an NT4 DC in a mixed mode domain to
  1939. // prevent a downgrade attack.
  1940. //
  1941. if ( NlGlobalMemberWorkstation &&
  1942. (ClientSession->CsDiscoveryFlags & CS_DISCOVERY_HAS_DS) == 0 &&
  1943. (ClientSession->CsFlags & CS_NT5_DOMAIN_TRUST) != 0 ) {
  1944. NET_API_STATUS NetStatus;
  1945. PDOMAIN_CONTROLLER_INFOW DomainControllerInfo = NULL;
  1946. GotNonDsDc = TRUE;
  1947. NlPrintCs(( NL_CRITICAL, ClientSession, "NlSessionSetup: Only downlevel DC available\n" ));
  1948. //
  1949. // Determine whether the domain has been downgraded (just to warn
  1950. // the user). To determine this, try to discover a PDC and if the
  1951. // PDC is available and it is NT4, the domain has been indeed
  1952. // downgraded. In such case, this workstation should rejoin the
  1953. // domain.
  1954. //
  1955. NetStatus = DsrGetDcNameEx2( NULL,
  1956. NULL,
  1957. 0,
  1958. NULL,
  1959. NULL,
  1960. NULL,
  1961. DS_PDC_REQUIRED | DS_FORCE_REDISCOVERY,
  1962. &DomainControllerInfo );
  1963. if ( NetStatus == NO_ERROR &&
  1964. (DomainControllerInfo->Flags & DS_DS_FLAG) == 0 ) {
  1965. DomainDowngraded = TRUE; // Domain has been downgraded (rejoin needed)
  1966. NlPrintCs(( NL_CRITICAL, ClientSession,
  1967. "NlSessionSetup: NT5 domain has been downgraded.\n" ));
  1968. }
  1969. if ( DomainControllerInfo != NULL ) {
  1970. NetApiBufferFree( DomainControllerInfo );
  1971. }
  1972. Status = STATUS_NO_LOGON_SERVERS;
  1973. ErrorFromDiscoveredServer = TRUE;
  1974. goto Cleanup;
  1975. }
  1976. //
  1977. // Prepare our challenge
  1978. //
  1979. NlComputeChallenge( &ClientChallenge );
  1980. NlPrint((NL_CHALLENGE_RES,"NlSessionSetup: ClientChallenge = " ));
  1981. NlpDumpBuffer(NL_CHALLENGE_RES, &ClientChallenge, sizeof(ClientChallenge) );
  1982. //
  1983. // Get the Password of the account from LSA secret storage
  1984. //
  1985. Status = NlGetOutgoingPassword( ClientSession,
  1986. &NewPassword,
  1987. &OldPassword,
  1988. &DummyPasswordVersionNumber,
  1989. &PasswordChangeTime );
  1990. if ( !NT_SUCCESS( Status ) ) {
  1991. NlPrintCs((NL_CRITICAL, ClientSession,
  1992. "NlSessionSetup: cannot NlGetOutgoingPassword 0x%lx\n",
  1993. Status ));
  1994. //
  1995. // return more appropriate error.
  1996. //
  1997. if ( !NlpIsNtStatusResourceError( Status )) {
  1998. Status = STATUS_NO_TRUST_LSA_SECRET;
  1999. }
  2000. goto Cleanup;
  2001. }
  2002. //
  2003. // Try setting up a secure channel first using the CurrentPassword.
  2004. // If that fails, try using the OldPassword
  2005. // If that fails, for interdomain trusts, try the password from our PDC
  2006. //
  2007. for ( State = 0; ; State++ ) {
  2008. //
  2009. // Use the right password for this iteration
  2010. //
  2011. if ( State == 0 ) {
  2012. //
  2013. // If the new password isn't present in the LSA,
  2014. // just ignore it.
  2015. //
  2016. if ( NewPassword == NULL ) {
  2017. continue;
  2018. }
  2019. //
  2020. // Compute the NT OWF password
  2021. //
  2022. Status = RtlCalculateNtOwfPassword( NewPassword,
  2023. &NewOwfPassword );
  2024. if ( !NT_SUCCESS( Status ) ) {
  2025. //
  2026. // return more appropriate error.
  2027. //
  2028. if ( !NlpIsNtStatusResourceError( Status )) {
  2029. Status = STATUS_NO_TRUST_LSA_SECRET;
  2030. }
  2031. goto Cleanup;
  2032. }
  2033. //
  2034. // Try this password
  2035. //
  2036. PNewOwfPassword = &NewOwfPassword;
  2037. NtOwfPassword = NewOwfPassword;
  2038. NlPrint((NL_CHALLENGE_RES,"NlSessionSetup: Clear New Password = " ));
  2039. NlpDumpBuffer(NL_CHALLENGE_RES, NewPassword->Buffer, NewPassword->Length );
  2040. NlpDumpTime( NL_CHALLENGE_RES, "NlSessionSetup: Password Changed: ", PasswordChangeTime );
  2041. //
  2042. // On the second iteration, use the old password
  2043. //
  2044. } else if ( State == 1 ) {
  2045. //
  2046. // If the old password isn't present in the LSA,
  2047. // just ignore it.
  2048. //
  2049. if ( OldPassword == NULL ) {
  2050. continue;
  2051. }
  2052. //
  2053. // Check if the old password is the same as the new one
  2054. //
  2055. if ( NewPassword != NULL && OldPassword != NULL &&
  2056. NewPassword->Length == OldPassword->Length &&
  2057. RtlEqualMemory( NewPassword->Buffer,
  2058. OldPassword->Buffer,
  2059. OldPassword->Length ) ) {
  2060. NlPrintCs((NL_CRITICAL, ClientSession,
  2061. "NlSessionSetup: new password is bad. Old password is same as new password.\n" ));
  2062. continue; // Try the password from our PDC
  2063. }
  2064. //
  2065. // Compute the NT OWF password
  2066. //
  2067. Status = RtlCalculateNtOwfPassword( OldPassword,
  2068. &OldOwfPassword );
  2069. if ( !NT_SUCCESS( Status ) ) {
  2070. //
  2071. // return more appropriate error.
  2072. //
  2073. if ( !NlpIsNtStatusResourceError( Status )) {
  2074. Status = STATUS_NO_TRUST_LSA_SECRET;
  2075. }
  2076. goto Cleanup;
  2077. }
  2078. //
  2079. // Try this password
  2080. //
  2081. POldOwfPassword = &OldOwfPassword;
  2082. NtOwfPassword = OldOwfPassword;
  2083. NlPrintCs((NL_CRITICAL, ClientSession,
  2084. "NlSessionSetup: new password is bad, try old one\n" ));
  2085. NlPrint((NL_CHALLENGE_RES,"NlSessionSetup: Clear Old Password = " ));
  2086. NlpDumpBuffer(NL_CHALLENGE_RES, OldPassword->Buffer, OldPassword->Length );
  2087. NlpDumpTime( NL_CHALLENGE_RES, "NlSessionSetup: Password Changed: ", PasswordChangeTime );
  2088. //
  2089. // On the third iteration, for an interdomain trust account,
  2090. // use the password from the PDC. We actually think this is
  2091. // useful only for NT4 trusted side that keeps only one
  2092. // password. For NT5 or later, one of the passwords above
  2093. // should work, but ...
  2094. //
  2095. } else if ( State == 2 &&
  2096. ClientSession->CsDomainInfo->DomRole == RoleBackup &&
  2097. IsDomainSecureChannelType(ClientSession->CsSecureChannelType) ) {
  2098. Status = NlGetPasswordFromPdc(
  2099. ClientSession->CsDomainInfo,
  2100. ClientSession->CsAccountName,
  2101. ClientSession->CsSecureChannelType,
  2102. &PdcOwfPassword );
  2103. if ( !NT_SUCCESS(Status) ) {
  2104. NlPrintDom(( NL_CRITICAL, ClientSession->CsDomainInfo,
  2105. "NlSessionSetup: Can't NlGetPasswordFromPdc %ws 0x%lx.\n",
  2106. ClientSession->CsAccountName,
  2107. Status ));
  2108. // Ignore the particular status from the PDC
  2109. Status = STATUS_ACCESS_DENIED;
  2110. goto Cleanup;
  2111. }
  2112. //
  2113. // Check if this password is the same as the new one we have
  2114. //
  2115. if ( PNewOwfPassword != NULL &&
  2116. RtlEqualNtOwfPassword(&PdcOwfPassword, PNewOwfPassword) ) {
  2117. NlPrintCs(( NL_CRITICAL, ClientSession,
  2118. "NlSessionSetup: PDC password is same as new password.\n" ));
  2119. Status = STATUS_ACCESS_DENIED;
  2120. goto Cleanup;
  2121. }
  2122. //
  2123. // Check if this password is the same as the old one we have
  2124. //
  2125. if ( POldOwfPassword != NULL &&
  2126. RtlEqualNtOwfPassword(&PdcOwfPassword, POldOwfPassword) ) {
  2127. NlPrintCs(( NL_CRITICAL, ClientSession,
  2128. "NlSessionSetup: PDC password is same as old password.\n" ));
  2129. Status = STATUS_ACCESS_DENIED;
  2130. goto Cleanup;
  2131. }
  2132. //
  2133. // Try this password
  2134. //
  2135. NtOwfPassword = PdcOwfPassword;
  2136. NlPrintCs((NL_CRITICAL, ClientSession,
  2137. "NlSessionSetup: try password from the PDC\n" ));
  2138. //
  2139. // We tried our best but nothing worked
  2140. //
  2141. } else {
  2142. Status = STATUS_ACCESS_DENIED;
  2143. goto Cleanup;
  2144. }
  2145. NlPrint((NL_CHALLENGE_RES,"NlSessionSetup: Password = " ));
  2146. NlpDumpBuffer(NL_CHALLENGE_RES, &NtOwfPassword, sizeof(NtOwfPassword) );
  2147. //
  2148. // Get the primary's challenge
  2149. //
  2150. NlAssert( ClientSession->CsState != CS_IDLE );
  2151. NL_API_START( Status, ClientSession, TRUE ) {
  2152. NlAssert( ClientSession->CsUncServerName != NULL );
  2153. Status = I_NetServerReqChallenge(ClientSession->CsUncServerName,
  2154. ClientSession->CsDomainInfo->DomUnicodeComputerNameString.Buffer,
  2155. &ClientChallenge,
  2156. &ServerChallenge );
  2157. if ( !NT_SUCCESS(Status) ) {
  2158. NlPrintRpcDebug( "I_NetServerReqChallenge", Status );
  2159. }
  2160. } NL_API_ELSE ( Status, ClientSession, FALSE ) {
  2161. NlPrintCs((NL_CRITICAL, ClientSession,
  2162. "NlSessionSetup: Session setup: "
  2163. "cannot FinishApiClientSession for I_NetServerReqChallenge 0x%lx\n",
  2164. Status ));
  2165. // Failure here indicates that the discovered server is really slow.
  2166. // Let the "ErrorFromDiscoveredServer" logic do the rediscovery.
  2167. if ( NT_SUCCESS(Status) ) {
  2168. // We're dropping the secure channel so
  2169. // ensure we don't use any successful status from the DC
  2170. Status = STATUS_NO_LOGON_SERVERS;
  2171. }
  2172. ErrorFromDiscoveredServer = TRUE;
  2173. goto Cleanup;
  2174. } NL_API_END;
  2175. if ( !NT_SUCCESS( Status ) ) {
  2176. NlPrintCs((NL_CRITICAL, ClientSession,
  2177. "NlSessionSetup: Session setup: "
  2178. "cannot I_NetServerReqChallenge 0x%lx\n",
  2179. Status ));
  2180. //
  2181. // If access is denied, it might be because we weren't able to
  2182. // authenticate with the new password, try the old password.
  2183. //
  2184. // Between NT 5 machines, we use Kerberos (and the machine account) to
  2185. // authenticate this machine.
  2186. if ( Status == STATUS_ACCESS_DENIED && State == 0 ) {
  2187. continue;
  2188. }
  2189. ErrorFromDiscoveredServer = TRUE;
  2190. goto Cleanup;
  2191. }
  2192. NlPrint((NL_CHALLENGE_RES,"NlSessionSetup: ServerChallenge = " ));
  2193. NlpDumpBuffer(NL_CHALLENGE_RES, &ServerChallenge, sizeof(ServerChallenge) );
  2194. //
  2195. // For NT 5 to NT 5,
  2196. // use a stronger session key.
  2197. //
  2198. if ( (ClientSession->CsDiscoveryFlags & CS_DISCOVERY_HAS_DS) != 0 ||
  2199. NlGlobalParameters.RequireStrongKey ) {
  2200. KeyStrength = NETLOGON_SUPPORTS_STRONG_KEY;
  2201. } else {
  2202. KeyStrength = 0;
  2203. }
  2204. //
  2205. // Actually compute the session key given the two challenges and the
  2206. // password.
  2207. //
  2208. Status = NlMakeSessionKey(
  2209. KeyStrength,
  2210. &NtOwfPassword,
  2211. &ClientChallenge,
  2212. &ServerChallenge,
  2213. &ClientSession->CsSessionKey );
  2214. if ( !NT_SUCCESS( Status ) ) {
  2215. NlPrintCs((NL_CRITICAL, ClientSession,
  2216. "NlSessionSetup: Session setup: cannot NlMakeSessionKey 0x%lx\n",
  2217. Status ));
  2218. goto Cleanup;
  2219. }
  2220. NlPrint((NL_CHALLENGE_RES,"NlSessionSetup: SessionKey = " ));
  2221. NlpDumpBuffer(NL_CHALLENGE_RES, &ClientSession->CsSessionKey, sizeof(ClientSession->CsSessionKey) );
  2222. //
  2223. // Prepare credentials using our challenge.
  2224. //
  2225. NlComputeCredentials( &ClientChallenge,
  2226. &ClientSession->CsAuthenticationSeed,
  2227. &ClientSession->CsSessionKey );
  2228. NlPrint((NL_CHALLENGE_RES,"NlSessionSetup: Authentication Seed = " ));
  2229. NlpDumpBuffer(NL_CHALLENGE_RES, &ClientSession->CsAuthenticationSeed, sizeof(ClientSession->CsAuthenticationSeed) );
  2230. //
  2231. // Send these credentials to primary. The primary will compute
  2232. // credentials using the challenge supplied by us and compare
  2233. // with these. If both match then it will compute credentials
  2234. // using its challenge and return it to us for verification
  2235. //
  2236. NL_API_START( Status, ClientSession, TRUE ) {
  2237. NegotiatedFlags = NETLOGON_SUPPORTS_MASK |
  2238. KeyStrength |
  2239. (NlGlobalParameters.AvoidSamRepl ? NETLOGON_SUPPORTS_AVOID_SAM_REPL : 0) |
  2240. #ifdef ENABLE_AUTH_RPC
  2241. ((NlGlobalParameters.SignSecureChannel||NlGlobalParameters.SealSecureChannel) ? (NETLOGON_SUPPORTS_AUTH_RPC|NETLOGON_SUPPORTS_LSA_AUTH_RPC) : 0) |
  2242. #endif // ENABLE_AUTH_RPC
  2243. (NlGlobalParameters.AvoidLsaRepl ? NETLOGON_SUPPORTS_AVOID_LSA_REPL : 0) |
  2244. (NlGlobalParameters.NeutralizeNt4Emulator ? NETLOGON_SUPPORTS_NT4EMULATOR_NEUTRALIZER : 0);
  2245. NlAssert( ClientSession->CsUncServerName != NULL );
  2246. ClientSession->CsNegotiatedFlags = NegotiatedFlags;
  2247. Status = I_NetServerAuthenticate3( ClientSession->CsUncServerName,
  2248. ClientSession->CsAccountName,
  2249. ClientSession->CsSecureChannelType,
  2250. ClientSession->CsDomainInfo->DomUnicodeComputerNameString.Buffer,
  2251. &ClientSession->CsAuthenticationSeed,
  2252. &ReturnedServerCredential,
  2253. &ClientSession->CsNegotiatedFlags,
  2254. &ClientSession->CsAccountRid );
  2255. //
  2256. // Releases older then NT 5.0 used older authentication API.
  2257. //
  2258. if ( Status == RPC_NT_PROCNUM_OUT_OF_RANGE ) {
  2259. NlPrint((NL_CRITICAL,"NlSessionSetup: Fall back to Authenticate2\n" ));
  2260. ClientSession->CsNegotiatedFlags = NegotiatedFlags;
  2261. ClientSession->CsAccountRid = 0;
  2262. Status = I_NetServerAuthenticate2( ClientSession->CsUncServerName,
  2263. ClientSession->CsAccountName,
  2264. ClientSession->CsSecureChannelType,
  2265. ClientSession->CsDomainInfo->DomUnicodeComputerNameString.Buffer,
  2266. &ClientSession->CsAuthenticationSeed,
  2267. &ReturnedServerCredential,
  2268. &ClientSession->CsNegotiatedFlags );
  2269. if ( Status == RPC_NT_PROCNUM_OUT_OF_RANGE ) {
  2270. ClientSession->CsNegotiatedFlags = 0;
  2271. Status = I_NetServerAuthenticate( ClientSession->CsUncServerName,
  2272. ClientSession->CsAccountName,
  2273. ClientSession->CsSecureChannelType,
  2274. ClientSession->CsDomainInfo->DomUnicodeComputerNameString.Buffer,
  2275. &ClientSession->CsAuthenticationSeed,
  2276. &ReturnedServerCredential );
  2277. if ( !NT_SUCCESS(Status) ) {
  2278. NlPrintRpcDebug( "I_NetServerAuthenticate", Status );
  2279. }
  2280. } else if ( !NT_SUCCESS(Status) ) {
  2281. NlPrintRpcDebug( "I_NetServerAuthenticate2", Status );
  2282. }
  2283. } else if ( !NT_SUCCESS(Status) ) {
  2284. NlPrintRpcDebug( "I_NetServerAuthenticate3", Status );
  2285. }
  2286. } NL_API_ELSE( Status, ClientSession, FALSE ) {
  2287. NlPrintCs((NL_CRITICAL, ClientSession,
  2288. "NlSessionSetup: Session setup: "
  2289. "cannot FinishApiClientSession for I_NetServerAuthenticate 0x%lx\n",
  2290. Status ));
  2291. // Failure here indicates that the discovered server is really slow.
  2292. // Let the "ErrorFromDiscoveredServer" logic do the rediscovery.
  2293. if ( NT_SUCCESS(Status) ) {
  2294. // We're dropping the secure channel so
  2295. // ensure we don't use any successful status from the DC
  2296. Status = STATUS_NO_LOGON_SERVERS;
  2297. }
  2298. ErrorFromDiscoveredServer = TRUE;
  2299. goto Cleanup;
  2300. } NL_API_END;
  2301. if ( !NT_SUCCESS( Status ) ) {
  2302. NlPrintCs((NL_CRITICAL, ClientSession,
  2303. "NlSessionSetup: Session setup: "
  2304. "cannot I_NetServerAuthenticate 0x%lx\n",
  2305. Status ));
  2306. //
  2307. // If access is denied, it might be because we weren't able to
  2308. // authenticate with the new password, try the old password
  2309. // or password from the PDC.
  2310. //
  2311. if ( Status == STATUS_ACCESS_DENIED && State < 2 ) {
  2312. continue;
  2313. }
  2314. ErrorFromDiscoveredServer = TRUE;
  2315. goto Cleanup;
  2316. }
  2317. NlPrint((NL_CHALLENGE_RES,"NlSessionSetup: ServerCredential GOT = " ));
  2318. NlpDumpBuffer(NL_CHALLENGE_RES, &ReturnedServerCredential, sizeof(ReturnedServerCredential) );
  2319. //
  2320. // The DC returned a server credential to us,
  2321. // ensure the server credential matches the one we would compute.
  2322. //
  2323. NlComputeCredentials( &ServerChallenge,
  2324. &ComputedServerCredential,
  2325. &ClientSession->CsSessionKey);
  2326. NlPrint((NL_CHALLENGE_RES,"NlSessionSetup: ServerCredential MADE = " ));
  2327. NlpDumpBuffer(NL_CHALLENGE_RES, &ComputedServerCredential, sizeof(ComputedServerCredential) );
  2328. if ( !RtlEqualMemory( &ReturnedServerCredential,
  2329. &ComputedServerCredential,
  2330. sizeof(ReturnedServerCredential)) ) {
  2331. Status = STATUS_ACCESS_DENIED;
  2332. NlPrintCs((NL_CRITICAL, ClientSession,
  2333. "NlSessionSetup: Session setup: "
  2334. "Servercredential don't match ours 0x%lx\n",
  2335. Status));
  2336. goto Cleanup;
  2337. }
  2338. //
  2339. // If we require signing or sealing and didn't negotiate it,
  2340. // fail now.
  2341. //
  2342. if ( NlGlobalParameters.RequireSignOrSeal &&
  2343. (ClientSession->CsNegotiatedFlags & NETLOGON_SUPPORTS_AUTH_RPC) == 0 ) {
  2344. NlPrintCs((NL_CRITICAL, ClientSession,
  2345. "NlSessionSetup: SignOrSeal required and DC doesn't support it\n" ));
  2346. SignOrSealError = TRUE;
  2347. Status = STATUS_ACCESS_DENIED;
  2348. ErrorFromDiscoveredServer = TRUE; // Highly unlikely that retrying will work, but ...
  2349. goto Cleanup;
  2350. }
  2351. //
  2352. // If we require signing or sealing and didn't negotiate it,
  2353. // fail now.
  2354. //
  2355. // We'll never really get this far. Since we used a strong key,
  2356. // we'll get ACCESS_DENIED above.
  2357. //
  2358. if ( NlGlobalParameters.RequireStrongKey &&
  2359. (ClientSession->CsNegotiatedFlags & NETLOGON_SUPPORTS_STRONG_KEY) == 0 ) {
  2360. NlPrintCs((NL_CRITICAL, ClientSession,
  2361. "NlSessionSetup: StrongKey required and DC doesn't support it\n" ));
  2362. SignOrSealError = TRUE;
  2363. Status = STATUS_ACCESS_DENIED;
  2364. ErrorFromDiscoveredServer = TRUE; // Highly unlikely that retrying will work, but ...
  2365. goto Cleanup;
  2366. }
  2367. //
  2368. // If we've made it this far, we've successfully authenticated
  2369. // with the DC, drop out of the loop.
  2370. //
  2371. break;
  2372. }
  2373. //
  2374. // If the new DC is an NT 5 DC,
  2375. // mark it so.
  2376. //
  2377. if ((ClientSession->CsNegotiatedFlags & NETLOGON_SUPPORTS_GENERIC_PASSTHRU) != 0 ) {
  2378. NlPrintCs(( NL_SESSION_MORE, ClientSession,
  2379. "NlSessionSetup: DC is an NT 5 DC: %ws\n",
  2380. ClientSession->CsUncServerName ));
  2381. //
  2382. // This flag would have been set during discovery if real discovery was
  2383. // done. However, if NlSetServerClientSession was called from anywhere
  2384. // else other than discovery, the flag may not yet be set.
  2385. //
  2386. EnterCriticalSection( &NlGlobalDcDiscoveryCritSect );
  2387. ClientSession->CsDiscoveryFlags |= CS_DISCOVERY_HAS_DS;
  2388. LeaveCriticalSection( &NlGlobalDcDiscoveryCritSect );
  2389. //
  2390. // This flag would be set during client session creation if the domain
  2391. // was an NT 5 domain at that time. If we happened to stumble on an
  2392. // NT 5 DC after the fact, mark it now.
  2393. //
  2394. if ( ClientSession->CsSecureChannelType == WorkstationSecureChannel ) {
  2395. LOCK_TRUST_LIST( ClientSession->CsDomainInfo );
  2396. ClientSession->CsFlags |= CS_NT5_DOMAIN_TRUST;
  2397. UNLOCK_TRUST_LIST( ClientSession->CsDomainInfo );
  2398. }
  2399. }
  2400. //
  2401. // If we used the old password to authenticate,
  2402. // update the DC to the current password ASAP.
  2403. //
  2404. // Note that we don't need to reset the scavenge event here to start
  2405. // the scavenging imeediately to change the password. On DCs, the
  2406. // scavenging will always happen within the scavenging interval.
  2407. // On workstations, one might worry that the scavenging may happen
  2408. // in the distant future at next password reset interval (which is
  2409. // long, 30 days by default). However, if this is the first session
  2410. // setup on service start, the scavenging will start immediately and
  2411. // it will be scheduled every scavenging interval until the password
  2412. // is set on the DC. Otherwise, if this is not the first session setup
  2413. // and password got into mismatch due a failed password change on the
  2414. // DC, the password change routine will schedule the scavenging to run
  2415. // within the scavenge period until the password is set, so we don't
  2416. // need to reset the timer here since it's alrteady scheduled properly.
  2417. //
  2418. if ( State == 1 ) {
  2419. NlPrintCs((NL_CRITICAL, ClientSession,
  2420. "NlSessionSetup: old password succeeded\n" ));
  2421. LOCK_TRUST_LIST( ClientSession->CsDomainInfo );
  2422. ClientSession->CsFlags |= CS_UPDATE_PASSWORD;
  2423. UNLOCK_TRUST_LIST( ClientSession->CsDomainInfo );
  2424. }
  2425. //
  2426. // Save the password for our own future reference.
  2427. //
  2428. RtlCopyMemory( &ClientSession->CsNtOwfPassword, &NtOwfPassword, sizeof( NtOwfPassword ));
  2429. //
  2430. // If this is a workstation,
  2431. // grab useful information about the domain.
  2432. //
  2433. NlSetStatusClientSession( ClientSession, STATUS_SUCCESS ); // Mark session as authenticated
  2434. if ( NlGlobalMemberWorkstation ) {
  2435. Status = NlUpdateDomainInfo( ClientSession );
  2436. if ( !NT_SUCCESS(Status) ) {
  2437. NlPrintCs((NL_CRITICAL, ClientSession,
  2438. "NlSessionSetup: NlUpdateDomainInfo failed 0x%lX\n",
  2439. Status ));
  2440. ErrorFromDiscoveredServer = TRUE;
  2441. goto Cleanup;
  2442. }
  2443. //
  2444. // If this is a DC,
  2445. // determine if we should get the FTinfo from the trusted domain.
  2446. //
  2447. } else {
  2448. PLSA_FOREST_TRUST_INFORMATION ForestTrustInfo;
  2449. //
  2450. // If this is the PDC,
  2451. // and the trusted domain is a cross forest trust,
  2452. // get the FTinfo from the trusted domain and write it to our TDO.
  2453. //
  2454. // Ignore failures.
  2455. //
  2456. if ( ClientSession->CsDomainInfo->DomRole == RolePrimary &&
  2457. (ClientSession->CsTrustAttributes & TRUST_ATTRIBUTE_FOREST_TRANSITIVE) != 0 ) {
  2458. Status = NlpGetForestTrustInfoHigher(
  2459. ClientSession,
  2460. DS_GFTI_UPDATE_TDO,
  2461. FALSE, // Don't impersonate caller
  2462. TRUE, // We set up the session
  2463. &ForestTrustInfo );
  2464. if ( !NT_SUCCESS(Status) ) {
  2465. NlPrintCs((NL_CRITICAL, ClientSession,
  2466. "NlSessionSetup: NlpGetForestTrustInfoHigher failed 0x%lX\n",
  2467. Status ));
  2468. ErrorFromDiscoveredServer = TRUE;
  2469. goto Cleanup;
  2470. } else {
  2471. NetApiBufferFree( ForestTrustInfo );
  2472. }
  2473. }
  2474. }
  2475. Status = STATUS_SUCCESS;
  2476. //
  2477. // Cleanup
  2478. //
  2479. Cleanup:
  2480. //
  2481. // Free locally used resources
  2482. //
  2483. if ( NewPassword != NULL ) {
  2484. LocalFree( NewPassword );
  2485. }
  2486. if ( OldPassword != NULL ) {
  2487. LocalFree( OldPassword );
  2488. }
  2489. //
  2490. // Upon success, save the status and reset counters.
  2491. //
  2492. if ( NT_SUCCESS(Status) ) {
  2493. NlSetStatusClientSession( ClientSession, Status );
  2494. ClientSession->CsAuthAlertCount = 0;
  2495. ClientSession->CsTimeoutCount = 0;
  2496. ClientSession->CsFastCallCount = 0;
  2497. #if NETLOGONDBG
  2498. if ( ClientSession->CsNegotiatedFlags != NegotiatedFlags ) {
  2499. NlPrintCs((NL_SESSION_SETUP, ClientSession,
  2500. "NlSessionSetup: negotiated %lx flags rather than %lx\n",
  2501. ClientSession->CsNegotiatedFlags,
  2502. NegotiatedFlags ));
  2503. }
  2504. #endif // NETLOGONDBG
  2505. //
  2506. // write event log and raise alert
  2507. //
  2508. } else {
  2509. BOOLEAN RetryDiscovery = FALSE;
  2510. BOOLEAN RetryDiscoveryWithAccount = FALSE;
  2511. WCHAR PreviouslyDiscoveredServer[NL_MAX_DNS_LENGTH+3];
  2512. LPWSTR MsgStrings[5];
  2513. //
  2514. // Save the name of the discovered server.
  2515. //
  2516. if ( ClientSession->CsUncServerName != NULL ) {
  2517. wcscpy( PreviouslyDiscoveredServer, ClientSession->CsUncServerName );
  2518. } else {
  2519. wcscpy( PreviouslyDiscoveredServer, L"<Unknown>" );
  2520. }
  2521. //
  2522. // If the failure came from the discovered server,
  2523. // decide whether we should retry the session setup
  2524. // to a different server
  2525. //
  2526. if ( ErrorFromDiscoveredServer ) {
  2527. //
  2528. // If we didn't do the plain discovery (without account) just now,
  2529. // try the discovery again and redo the session setup.
  2530. //
  2531. if ( !WeDidDiscovery && NlTimeToRediscover(ClientSession, FALSE) ) {
  2532. RetryDiscovery = TRUE;
  2533. }
  2534. //
  2535. // If we didn't do the discovery with account and
  2536. // the session setup failed because the server didn't have our account and
  2537. // we didn't try a discovery with account recently,
  2538. // try the discovery again (with account) and redo the session setup.
  2539. //
  2540. if ( !WeDidDiscoveryWithAccount &&
  2541. (Status == STATUS_NO_SUCH_USER || Status == STATUS_NO_TRUST_SAM_ACCOUNT) &&
  2542. NlTimeToRediscover(ClientSession, TRUE) ) {
  2543. RetryDiscoveryWithAccount = TRUE;
  2544. }
  2545. }
  2546. //
  2547. // If we are to retry the discovery, do so
  2548. //
  2549. if ( RetryDiscovery || RetryDiscoveryWithAccount ) {
  2550. NTSTATUS TempStatus;
  2551. NlPrintCs((NL_SESSION_SETUP, ClientSession,
  2552. "NlSessionSetup: Retry failed session setup (%s account) since discovery wasn't recent.\n",
  2553. (RetryDiscoveryWithAccount ? "with" : "without") ));
  2554. //
  2555. // Pick the name of a new DC in the domain.
  2556. //
  2557. NlSetStatusClientSession( ClientSession, STATUS_NO_LOGON_SERVERS );
  2558. TempStatus = NlDiscoverDc( ClientSession,
  2559. DT_Synchronous,
  2560. FALSE,
  2561. RetryDiscoveryWithAccount ); // retry with account as needed
  2562. if ( NT_SUCCESS(TempStatus) ) {
  2563. //
  2564. // Don't bother redoing the session setup if we picked the same DC.
  2565. // In particular, if we retried because the previously found DC
  2566. // didn't have our account, we retried the discovery with account
  2567. // above but may have got the same DC (shouldn't really happen, but...)
  2568. //
  2569. if ( _wcsicmp( ClientSession->CsUncServerName,
  2570. PreviouslyDiscoveredServer ) != 0 ) {
  2571. //
  2572. // We certainly did a discovery here,
  2573. // but it may or may not be with account
  2574. //
  2575. WeDidDiscovery = TRUE;
  2576. WeDidDiscoveryWithAccount = RetryDiscoveryWithAccount;
  2577. goto FirstTryFailed;
  2578. } else {
  2579. NlPrintCs((NL_SESSION_SETUP, ClientSession,
  2580. "NlSessionSetup: Skip retry failed session setup since same DC discovered.\n" ));
  2581. }
  2582. } else {
  2583. NlPrintCs((NL_CRITICAL, ClientSession,
  2584. "NlSessionSetup: Session setup: cannot re-pick trusted DC\n" ));
  2585. }
  2586. }
  2587. switch(Status) {
  2588. case STATUS_NO_TRUST_LSA_SECRET:
  2589. MsgStrings[0] = PreviouslyDiscoveredServer;
  2590. MsgStrings[1] = ClientSession->CsDebugDomainName;
  2591. MsgStrings[2] = ClientSession->CsDomainInfo->DomUnicodeComputerNameString.Buffer,
  2592. MsgStrings[3] = NULL; // RaiseNetlogonAlert
  2593. NlpWriteEventlog (NELOG_NetlogonAuthNoTrustLsaSecret,
  2594. EVENTLOG_ERROR_TYPE,
  2595. (LPBYTE) &Status,
  2596. sizeof(Status),
  2597. MsgStrings,
  2598. 3 );
  2599. RaiseNetlogonAlert( NELOG_NetlogonAuthNoTrustLsaSecret,
  2600. MsgStrings,
  2601. &ClientSession->CsAuthAlertCount);
  2602. break;
  2603. case STATUS_NO_TRUST_SAM_ACCOUNT:
  2604. MsgStrings[0] = PreviouslyDiscoveredServer;
  2605. MsgStrings[1] = ClientSession->CsDebugDomainName;
  2606. MsgStrings[2] = ClientSession->CsDomainInfo->DomUnicodeComputerNameString.Buffer;
  2607. MsgStrings[3] = ClientSession->CsAccountName;
  2608. MsgStrings[4] = NULL; // RaiseNetlogonAlert
  2609. NlpWriteEventlog (NELOG_NetlogonAuthNoTrustSamAccount,
  2610. EVENTLOG_ERROR_TYPE,
  2611. (LPBYTE) &Status,
  2612. sizeof(Status),
  2613. MsgStrings,
  2614. 4 );
  2615. RaiseNetlogonAlert( NELOG_NetlogonAuthNoTrustSamAccount,
  2616. MsgStrings,
  2617. &ClientSession->CsAuthAlertCount);
  2618. break;
  2619. case STATUS_ACCESS_DENIED:
  2620. if ( SignOrSealError ) {
  2621. MsgStrings[0] = PreviouslyDiscoveredServer;
  2622. MsgStrings[1] = ClientSession->CsDebugDomainName;
  2623. MsgStrings[2] = NULL; // RaiseNetlogonAlert
  2624. NlpWriteEventlog (NELOG_NetlogonRequireSignOrSealError,
  2625. EVENTLOG_ERROR_TYPE,
  2626. NULL,
  2627. 0,
  2628. MsgStrings,
  2629. 2 );
  2630. RaiseNetlogonAlert( NELOG_NetlogonRequireSignOrSealError,
  2631. MsgStrings,
  2632. &ClientSession->CsAuthAlertCount);
  2633. } else {
  2634. MsgStrings[0] = ClientSession->CsDebugDomainName;
  2635. MsgStrings[1] = PreviouslyDiscoveredServer;
  2636. MsgStrings[2] = NULL; // RaiseNetlogonAlert
  2637. NlpWriteEventlog (NELOG_NetlogonAuthDCFail,
  2638. EVENTLOG_ERROR_TYPE,
  2639. (LPBYTE) &Status,
  2640. sizeof(Status),
  2641. MsgStrings,
  2642. 2 );
  2643. RaiseNetlogonAlert( NELOG_NetlogonAuthDCFail,
  2644. MsgStrings,
  2645. &ClientSession->CsAuthAlertCount);
  2646. }
  2647. break;
  2648. case STATUS_NO_LOGON_SERVERS:
  2649. default:
  2650. MsgStrings[0] = ClientSession->CsDebugDomainName;
  2651. MsgStrings[1] = (LPWSTR) LongToPtr( Status );
  2652. // The order of checks is important
  2653. if ( DomainDowngraded ) {
  2654. NlpWriteEventlog (NELOG_NetlogonAuthDomainDowngraded,
  2655. EVENTLOG_ERROR_TYPE,
  2656. (LPBYTE) &Status,
  2657. sizeof(Status),
  2658. MsgStrings,
  2659. 2 | NETP_LAST_MESSAGE_IS_NTSTATUS );
  2660. } else if ( GotNonDsDc ) {
  2661. NlpWriteEventlog (NELOG_NetlogonAuthNoUplevelDomainController,
  2662. EVENTLOG_ERROR_TYPE,
  2663. (LPBYTE) &Status,
  2664. sizeof(Status),
  2665. MsgStrings,
  2666. 2 | NETP_LAST_MESSAGE_IS_NTSTATUS );
  2667. } else {
  2668. NlpWriteEventlog (NELOG_NetlogonAuthNoDomainController,
  2669. EVENTLOG_ERROR_TYPE,
  2670. (LPBYTE) &Status,
  2671. sizeof(Status),
  2672. MsgStrings,
  2673. 2 | NETP_LAST_MESSAGE_IS_NTSTATUS );
  2674. }
  2675. MsgStrings[0] = ClientSession->CsDebugDomainName;
  2676. MsgStrings[1] = PreviouslyDiscoveredServer;
  2677. MsgStrings[2] = NULL; // RaiseNetlogonAlert
  2678. RaiseNetlogonAlert( ALERT_NetlogonAuthDCFail,
  2679. MsgStrings,
  2680. &ClientSession->CsAuthAlertCount);
  2681. break;
  2682. }
  2683. //
  2684. // ??: Is this how to handle failure for all account types.
  2685. //
  2686. switch(Status) {
  2687. case STATUS_NO_TRUST_LSA_SECRET:
  2688. case STATUS_NO_TRUST_SAM_ACCOUNT:
  2689. case STATUS_ACCESS_DENIED:
  2690. NlSetStatusClientSession( ClientSession, Status );
  2691. break;
  2692. default:
  2693. NlSetStatusClientSession( ClientSession, STATUS_NO_LOGON_SERVERS );
  2694. break;
  2695. }
  2696. }
  2697. //
  2698. // Mark the time we last tried to authenticate.
  2699. //
  2700. // We need to do this after NlSetStatusClientSession which zeros
  2701. // CsLastAuthenticationTry.
  2702. //
  2703. EnterCriticalSection( &NlGlobalDcDiscoveryCritSect );
  2704. NlQuerySystemTime( &ClientSession->CsLastAuthenticationTry );
  2705. LeaveCriticalSection( &NlGlobalDcDiscoveryCritSect );
  2706. NlPrintCs((NL_SESSION_SETUP, ClientSession,
  2707. "NlSessionSetup: Session setup %s\n",
  2708. (NT_SUCCESS(ClientSession->CsConnectionStatus)) ? "Succeeded" : "Failed" ));
  2709. //
  2710. // End the WMI trace of secure channel setup
  2711. //
  2712. NlpTraceEvent( EVENT_TRACE_TYPE_END, NlpGuidSecureChannelSetup );
  2713. return Status;
  2714. }
  2715. BOOLEAN
  2716. NlTimeHasElapsedEx(
  2717. IN PLARGE_INTEGER StartTime,
  2718. IN PLARGE_INTEGER Period,
  2719. OUT PULONG TimeInterval OPTIONAL
  2720. )
  2721. /*++
  2722. Routine Description:
  2723. Determine if "Timeout" milliseconds has has elapsed since StartTime.
  2724. Arguments:
  2725. StartTime - Specifies an absolute time when the event started (100ns units).
  2726. Period - Specifies a relative time in 100ns units.
  2727. TimeInterval - If specified and time has elapsed, returns the amount of time
  2728. (in milliseconds) passed since the timeout. If specified and time
  2729. has not elapsed, returns the amount of time (in milliseconds) left until
  2730. Period elapses.
  2731. Return Value:
  2732. TRUE -- iff Period 100nano-seconds have elapsed since StartTime.
  2733. --*/
  2734. {
  2735. LARGE_INTEGER TimeNow;
  2736. LARGE_INTEGER ElapsedTime;
  2737. BOOLEAN Result = FALSE;
  2738. //
  2739. //
  2740. // Compute the elapsed time since we last authenticated
  2741. //
  2742. // NlpDumpTime( NL_MISC, "StartTime: ", *StartTime );
  2743. NlQuerySystemTime( &TimeNow );
  2744. // NlpDumpTime( NL_MISC, "TimeNow: ", TimeNow );
  2745. ElapsedTime.QuadPart = TimeNow.QuadPart - StartTime->QuadPart;
  2746. // NlpDumpTime( NL_MISC, "ElapsedTime: ", ElapsedTime );
  2747. // NlpDumpTime( NL_MISC, "Period: ", *Period );
  2748. //
  2749. // If the elapsed time is negative (totally bogus) or greater than the
  2750. // maximum allowed, indicate that enough time has passed.
  2751. //
  2752. //
  2753. if ( ElapsedTime.QuadPart < 0 ) {
  2754. if ( ARGUMENT_PRESENT( TimeInterval )) {
  2755. *TimeInterval = 0; // pretend it just elapsed
  2756. }
  2757. return TRUE;
  2758. }
  2759. if ( ElapsedTime.QuadPart > Period->QuadPart ) {
  2760. Result = TRUE;
  2761. } else {
  2762. Result = FALSE;
  2763. }
  2764. //
  2765. // If the caller want to know the amount of time left,
  2766. // compute it.
  2767. //
  2768. if ( ARGUMENT_PRESENT( TimeInterval )) {
  2769. LARGE_INTEGER TimeRemaining;
  2770. LARGE_INTEGER MillisecondsRemaining;
  2771. /*lint -e569 */ /* don't complain about 32-bit to 31-bit initialize */
  2772. LARGE_INTEGER BaseGetTickMagicDivisor = { 0xe219652c, 0xd1b71758 };
  2773. /*lint +e569 */ /* don't complain about 32-bit to 31-bit initialize */
  2774. CCHAR BaseGetTickMagicShiftCount = 13;
  2775. //
  2776. // Compute the Time remaining/passed on the timer.
  2777. //
  2778. if ( Result == FALSE ) {
  2779. TimeRemaining.QuadPart = Period->QuadPart - ElapsedTime.QuadPart;
  2780. } else {
  2781. TimeRemaining.QuadPart = ElapsedTime.QuadPart - Period->QuadPart;
  2782. }
  2783. // NlpDumpTime( NL_MISC, "TimeRemaining: ", TimeRemaining );
  2784. //
  2785. // Compute the number of milliseconds remaining/passed.
  2786. //
  2787. MillisecondsRemaining = RtlExtendedMagicDivide(
  2788. TimeRemaining,
  2789. BaseGetTickMagicDivisor,
  2790. BaseGetTickMagicShiftCount );
  2791. // NlpDumpTime( NL_MISC, "MillisecondsRemaining: ", MillisecondsRemaining );
  2792. //
  2793. // If the time is in the far distant future/past,
  2794. // round it down.
  2795. //
  2796. if ( MillisecondsRemaining.HighPart != 0 ||
  2797. MillisecondsRemaining.LowPart > TIMER_MAX_PERIOD ) {
  2798. *TimeInterval = TIMER_MAX_PERIOD;
  2799. } else {
  2800. *TimeInterval = MillisecondsRemaining.LowPart;
  2801. }
  2802. }
  2803. return Result;
  2804. }
  2805. BOOLEAN
  2806. NlTimeToReauthenticate(
  2807. IN PCLIENT_SESSION ClientSession
  2808. )
  2809. /*++
  2810. Routine Description:
  2811. Determine if it is time to reauthenticate this Client Session.
  2812. To reduce the number of re-authentication attempts, we try
  2813. to re-authenticate only on demand and then only at most every 45
  2814. seconds.
  2815. Arguments:
  2816. ClientSession - Structure used to define the session.
  2817. Return Value:
  2818. TRUE -- iff it is time to re-authenticate
  2819. --*/
  2820. {
  2821. BOOLEAN ReturnBoolean;
  2822. EnterCriticalSection( &NlGlobalDcDiscoveryCritSect );
  2823. ReturnBoolean = NetpLogonTimeHasElapsed(
  2824. ClientSession->CsLastAuthenticationTry,
  2825. MAX_DC_AUTHENTICATION_WAIT );
  2826. LeaveCriticalSection( &NlGlobalDcDiscoveryCritSect );
  2827. return ReturnBoolean;
  2828. }
  2829. NET_API_STATUS
  2830. NlCreateShare(
  2831. LPWSTR SharePath,
  2832. LPWSTR ShareName,
  2833. BOOLEAN AllowAuthenticatedUsers,
  2834. BOOL UpdateExclusiveShareAccess,
  2835. BOOL AllowExclusiveShareAccess
  2836. )
  2837. /*++
  2838. Routine Description:
  2839. Share the netlogon scripts directory.
  2840. Arguments:
  2841. SharePath - Path that the new share should be point to.
  2842. ShareName - Name of the share.
  2843. AllowAuthenticatedUsers - TRUE if AuthenticatedUsers should have
  2844. Full Control on this share.
  2845. UpdateExclusiveShareAccess - If TRUE, the exclusive share
  2846. access semantics will be updated as specified by
  2847. AllowExclusiveShareAccess.
  2848. AllowExclusiveShareAccess - If TRUE, the exclusive access to the
  2849. specified share will be granted. Otherwise, the exclusive
  2850. access to the specified share will not be granted. This
  2851. parameter is ignored if UpdateExclusiveShareAccess is FALSE.
  2852. Return Value:
  2853. TRUE: if successful
  2854. FALSE: if error (NlExit was called)
  2855. --*/
  2856. {
  2857. NTSTATUS Status;
  2858. NET_API_STATUS NetStatus;
  2859. SHARE_INFO_502 ShareInfo502;
  2860. PSHARE_INFO_1005 ShareInfo1005 = NULL;
  2861. DWORD CurrentFlags = 0;
  2862. WORD AnsiSize;
  2863. CHAR AnsiRemark[NNLEN+1];
  2864. TCHAR Remark[NNLEN+1];
  2865. ACE_DATA AceData[] = {
  2866. {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
  2867. GENERIC_EXECUTE | GENERIC_READ, &WorldSid},
  2868. {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
  2869. GENERIC_ALL, &AliasAdminsSid},
  2870. // Must be the last ACE
  2871. {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
  2872. GENERIC_ALL, &AuthenticatedUserSid}
  2873. };
  2874. ULONG AceCount = (sizeof(AceData)/sizeof(AceData[0]));
  2875. //
  2876. // If Authenticated Users shouldn't be allowed full control,
  2877. // remove the authenticated user ACE.
  2878. //
  2879. if ( !AllowAuthenticatedUsers ) {
  2880. AceCount --;
  2881. }
  2882. //
  2883. // Build the structure describing the share.
  2884. //
  2885. ShareInfo502.shi502_path = SharePath;
  2886. ShareInfo502.shi502_security_descriptor = NULL;
  2887. NlPrint((NL_INIT, "'%ws' share is to '%ws'\n",
  2888. ShareName,
  2889. SharePath));
  2890. NetStatus = (NET_API_STATUS) DosGetMessage(
  2891. NULL, // No insertion strings
  2892. 0, // No insertion strings
  2893. AnsiRemark,
  2894. sizeof(AnsiRemark),
  2895. MTXT_LOGON_SRV_SHARE_REMARK,
  2896. MESSAGE_FILENAME,
  2897. &AnsiSize );
  2898. if ( NetStatus == NERR_Success ) {
  2899. NetpCopyStrToTStr( Remark, AnsiRemark );
  2900. ShareInfo502.shi502_remark = Remark;
  2901. } else {
  2902. ShareInfo502.shi502_remark = TEXT( "" );
  2903. }
  2904. ShareInfo502.shi502_netname = ShareName;
  2905. ShareInfo502.shi502_type = STYPE_DISKTREE;
  2906. ShareInfo502.shi502_permissions = ACCESS_READ;
  2907. ShareInfo502.shi502_max_uses = 0xffffffff;
  2908. ShareInfo502.shi502_passwd = TEXT("");
  2909. //
  2910. // Set the security descriptor on the share
  2911. //
  2912. //
  2913. // Create a security descriptor containing the DACL.
  2914. //
  2915. Status = NetpCreateSecurityDescriptor(
  2916. AceData,
  2917. AceCount,
  2918. NULL, // Default the owner Sid
  2919. NULL, // Default the primary group
  2920. &ShareInfo502.shi502_security_descriptor );
  2921. if ( !NT_SUCCESS( Status ) ) {
  2922. NlPrint((NL_CRITICAL,
  2923. "'%ws' share: Cannot create security descriptor 0x%lx\n",
  2924. SharePath, Status ));
  2925. NetStatus = NetpNtStatusToApiStatus( Status );
  2926. return NetStatus;
  2927. }
  2928. //
  2929. // Create the share.
  2930. //
  2931. NetStatus = NetShareAdd(NULL, 502, (LPBYTE) &ShareInfo502, NULL);
  2932. if (NetStatus == NERR_DuplicateShare) {
  2933. PSHARE_INFO_2 ShareInfo2 = NULL;
  2934. NlPrint((NL_INIT, "'%ws' share already exists. \n", ShareName));
  2935. //
  2936. // check to see the shared path is same.
  2937. //
  2938. NetStatus = NetShareGetInfo( NULL,
  2939. ShareName,
  2940. 2,
  2941. (LPBYTE *) &ShareInfo2 );
  2942. if ( NetStatus == NERR_Success ) {
  2943. //
  2944. // compare path names.
  2945. //
  2946. // ShareName is path canonicalized already.
  2947. //
  2948. //
  2949. NlPrint((NL_INIT, "'%ws' share current path is %ws\n", ShareName, ShareInfo2->shi2_path));
  2950. if( NetpwPathCompare(
  2951. SharePath,
  2952. ShareInfo2->shi2_path, 0, 0 ) != 0 ) {
  2953. //
  2954. // delete share.
  2955. //
  2956. NetStatus = NetShareDel( NULL, ShareName, 0);
  2957. if( NetStatus == NERR_Success ) {
  2958. //
  2959. // Recreate share.
  2960. //
  2961. NetStatus = NetShareAdd(
  2962. NULL,
  2963. 502,
  2964. (LPBYTE) &ShareInfo502,
  2965. NULL);
  2966. if( NetStatus == NERR_Success ) {
  2967. NlPrint((NL_INIT,
  2968. "'%ws' share was recreated with new path %ws\n",
  2969. ShareName, SharePath ));
  2970. }
  2971. }
  2972. }
  2973. }
  2974. if( ShareInfo2 != NULL ) {
  2975. NetpMemoryFree( ShareInfo2 );
  2976. }
  2977. }
  2978. //
  2979. // Free the security descriptor
  2980. //
  2981. NetpMemoryFree( ShareInfo502.shi502_security_descriptor );
  2982. if ( NetStatus != NERR_Success ) {
  2983. NlPrint((NL_CRITICAL,
  2984. "'%ws' share: Error attempting to create-share: %ld\n",
  2985. ShareName,
  2986. NetStatus ));
  2987. return NetStatus;
  2988. }
  2989. //
  2990. // If we don't need to update the exclusing share access semantics,
  2991. // we are done
  2992. //
  2993. if ( !UpdateExclusiveShareAccess ) {
  2994. return NERR_Success;
  2995. }
  2996. //
  2997. // Set the exclusive share access semantics as appropriate
  2998. //
  2999. NetStatus = NetShareGetInfo( NULL, ShareName, 1005, (LPBYTE*)&ShareInfo1005 );
  3000. if ( NetStatus != NO_ERROR ) {
  3001. NlPrint(( NL_CRITICAL,
  3002. "NlCreateShare: NetShareGetInfo (1005) failed for share '%ws': %lu\n",
  3003. ShareName,
  3004. NetStatus ));
  3005. return NetStatus;
  3006. }
  3007. //
  3008. // Save the current flags
  3009. //
  3010. CurrentFlags = ShareInfo1005->shi1005_flags;
  3011. //
  3012. // If we allow the exclusive share access...
  3013. //
  3014. if ( AllowExclusiveShareAccess ) {
  3015. //
  3016. // If the current setting doesn't allow the exclusive access,
  3017. // update it
  3018. //
  3019. if ( ShareInfo1005->shi1005_flags & SHI1005_FLAGS_RESTRICT_EXCLUSIVE_OPENS ) {
  3020. ShareInfo1005->shi1005_flags &= ~SHI1005_FLAGS_RESTRICT_EXCLUSIVE_OPENS;
  3021. }
  3022. //
  3023. // If we disallow the exclusive share access...
  3024. //
  3025. } else {
  3026. //
  3027. // If the current setting allows the exclusive access,
  3028. // update it
  3029. //
  3030. if ( (ShareInfo1005->shi1005_flags & SHI1005_FLAGS_RESTRICT_EXCLUSIVE_OPENS) == 0 ) {
  3031. ShareInfo1005->shi1005_flags |= SHI1005_FLAGS_RESTRICT_EXCLUSIVE_OPENS;
  3032. }
  3033. }
  3034. //
  3035. // Update the share as needed
  3036. //
  3037. if ( CurrentFlags != ShareInfo1005->shi1005_flags ) {
  3038. NetStatus = NetShareSetInfo( NULL, ShareName, 1005, (LPBYTE)ShareInfo1005, NULL );
  3039. if ( NetStatus == NO_ERROR ) {
  3040. NlPrint(( NL_INIT,
  3041. "NlCreateShare: Share '%ws' updated successfully flags 0x%lx 0x%lx\n",
  3042. ShareName,
  3043. CurrentFlags,
  3044. ShareInfo1005->shi1005_flags ));
  3045. } else {
  3046. NlPrint(( NL_CRITICAL,
  3047. "NlCreateShare: Failed to update share '%ws' flags 0x%lx 0x%lx: 0x%lx\n",
  3048. ShareName,
  3049. CurrentFlags,
  3050. ShareInfo1005->shi1005_flags,
  3051. NetStatus ));
  3052. }
  3053. }
  3054. //
  3055. // Free the share info
  3056. //
  3057. if ( ShareInfo1005 != NULL ) {
  3058. NetApiBufferFree( ShareInfo1005 );
  3059. }
  3060. return NetStatus;
  3061. }
  3062. NTSTATUS
  3063. NlSamOpenNamedUser(
  3064. IN PDOMAIN_INFO DomainInfo,
  3065. IN LPCWSTR UserName,
  3066. OUT SAMPR_HANDLE *UserHandle OPTIONAL,
  3067. OUT PULONG UserId OPTIONAL,
  3068. OUT PSAMPR_USER_INFO_BUFFER *UserAllInfo OPTIONAL
  3069. )
  3070. /*++
  3071. Routine Description:
  3072. Utility routine to open a Sam user given the username.
  3073. Arguments:
  3074. DomainInfo - Domain the user is in.
  3075. UserName - Name of user to open
  3076. UserHandle - Optionally returns a handle to the opened user.
  3077. UserId - Optionally returns the relative ID of the opened user.
  3078. UserAllInfo - Optionally returns ALL of the information about the
  3079. named user. Free the returned information using
  3080. SamIFree_SAMPR_USER_INFO_BUFFER( UserAllInfo, UserAllInformation );
  3081. Return Value:
  3082. STATUS_NO_SUCH_USER: if the account doesn't exist
  3083. --*/
  3084. {
  3085. NTSTATUS Status;
  3086. UNICODE_STRING UserNameString;
  3087. PSAMPR_USER_INFO_BUFFER LocalUserAllInfo = NULL;
  3088. SID_AND_ATTRIBUTES_LIST ReverseMembership;
  3089. //
  3090. // Initialization.
  3091. //
  3092. if ( ARGUMENT_PRESENT( UserHandle) ) {
  3093. *UserHandle = NULL;
  3094. }
  3095. if ( ARGUMENT_PRESENT( UserAllInfo) ) {
  3096. *UserAllInfo = NULL;
  3097. }
  3098. //
  3099. // Get the info about the user.
  3100. //
  3101. // Use SamIGetUserLogonInformation instead of SamrLookupNamesInDomain and
  3102. // SamrOpen user. The former is more efficient (since it only does one
  3103. // DirSearch and doesn't lock the global SAM lock) and more powerful
  3104. // (since it returns UserAllInformation).
  3105. //
  3106. RtlInitUnicodeString( &UserNameString, UserName );
  3107. Status = SamIGetUserLogonInformation(
  3108. DomainInfo->DomSamAccountDomainHandle,
  3109. SAM_NO_MEMBERSHIPS, // Don't need group memberships
  3110. &UserNameString,
  3111. &LocalUserAllInfo,
  3112. &ReverseMembership,
  3113. UserHandle );
  3114. if ( !NT_SUCCESS(Status) ) {
  3115. if ( Status == STATUS_NOT_FOUND ) {
  3116. Status = STATUS_NO_SUCH_USER;
  3117. }
  3118. goto Cleanup;
  3119. }
  3120. //
  3121. // Return information to the caller.
  3122. //
  3123. if ( ARGUMENT_PRESENT(UserId) ) {
  3124. *UserId = LocalUserAllInfo->All.UserId;
  3125. }
  3126. if ( ARGUMENT_PRESENT( UserAllInfo) ) {
  3127. *UserAllInfo = LocalUserAllInfo;
  3128. LocalUserAllInfo = NULL;
  3129. }
  3130. //
  3131. // Free locally used resources.
  3132. //
  3133. Cleanup:
  3134. if ( LocalUserAllInfo != NULL ) {
  3135. SamIFree_SAMPR_USER_INFO_BUFFER( LocalUserAllInfo, UserAllInformation );
  3136. }
  3137. return Status;
  3138. }
  3139. NTSTATUS
  3140. NlSamChangePasswordNamedUser(
  3141. IN PDOMAIN_INFO DomainInfo,
  3142. IN LPCWSTR UserName,
  3143. IN PUNICODE_STRING ClearTextPassword OPTIONAL,
  3144. IN PNT_OWF_PASSWORD OwfPassword OPTIONAL
  3145. )
  3146. /*++
  3147. Routine Description:
  3148. Utility routine to set the OWF password on a user given the username.
  3149. Arguments:
  3150. DomainInfo - Domain the user is in.
  3151. UserName - Name of user to open
  3152. ClearTextPassword - Clear text password to set on the account
  3153. OwfPassword - OWF password to set on the account
  3154. Return Value:
  3155. --*/
  3156. {
  3157. NTSTATUS Status;
  3158. SAMPR_HANDLE UserHandle = NULL;
  3159. //
  3160. // Open the user that represents this server.
  3161. //
  3162. Status = NlSamOpenNamedUser( DomainInfo, UserName, &UserHandle, NULL, NULL );
  3163. if ( !NT_SUCCESS(Status) ) {
  3164. goto Cleanup;
  3165. }
  3166. //
  3167. // If Clear text password isn't NULL, use it.
  3168. // Otherwise use OWF password.
  3169. //
  3170. if ( ClearTextPassword != NULL ) {
  3171. UNICODE_STRING UserNameString;
  3172. RtlInitUnicodeString( &UserNameString, UserName );
  3173. Status = SamIChangePasswordForeignUser(
  3174. &UserNameString,
  3175. ClearTextPassword,
  3176. NULL,
  3177. 0 );
  3178. if ( !NT_SUCCESS(Status) ) {
  3179. NlPrint(( NL_CRITICAL,
  3180. "NlSamChangePasswordNamedUser: Can't SamIChangePasswordForeignUser %lX\n",
  3181. Status ));
  3182. goto Cleanup;
  3183. }
  3184. //
  3185. // Use the NT OWF Password,
  3186. //
  3187. } else if ( OwfPassword != NULL ) {
  3188. SAMPR_USER_INFO_BUFFER UserInfo;
  3189. UserInfo.Internal1.PasswordExpired = FALSE;
  3190. UserInfo.Internal1.LmPasswordPresent = FALSE;
  3191. UserInfo.Internal1.NtPasswordPresent = TRUE;
  3192. UserInfo.Internal1.EncryptedNtOwfPassword =
  3193. *((PENCRYPTED_NT_OWF_PASSWORD)(OwfPassword));
  3194. Status = SamrSetInformationUser(
  3195. UserHandle,
  3196. UserInternal1Information,
  3197. &UserInfo );
  3198. if (!NT_SUCCESS(Status)) {
  3199. NlPrint(( NL_CRITICAL,
  3200. "NlSamChangePasswordNamedUser: Can't SamrSetInformationUser %lX\n",
  3201. Status ));
  3202. goto Cleanup;
  3203. }
  3204. }
  3205. Cleanup:
  3206. if ( UserHandle != NULL ) {
  3207. (VOID) SamrCloseHandle( &UserHandle );
  3208. }
  3209. return Status;
  3210. }
  3211. NTSTATUS
  3212. NlChangePassword(
  3213. IN PCLIENT_SESSION ClientSession,
  3214. IN BOOLEAN ForcePasswordChange,
  3215. OUT PULONG RetCallAgainPeriod OPTIONAL
  3216. )
  3217. /*++
  3218. Routine Description:
  3219. Change this machine's password at the primary.
  3220. Also update password locally if the call succeeded.
  3221. To determine if the password of "machine account"
  3222. needs to be changed. If the password is older than
  3223. 7 days then it must be changed asap. We will defer
  3224. changing the password if we know before hand that
  3225. primary dc is down since our call will fail anyway.
  3226. Arguments:
  3227. ClientSession - Structure describing the session to change the password
  3228. for. The specified structure must be referenced.
  3229. ForcePasswordChange - TRUE if the password should be changed even if
  3230. the password hasn't expired yet.
  3231. RetCallAgainPeriod - Returns the amount of time (in milliseconds) that should elapse
  3232. before the caller should call this routine again.
  3233. 0: After a period of time determined by the caller.
  3234. MAILSLOT_WAIT_FOREVER: never
  3235. other: After at least this amount of time.
  3236. Return Value:
  3237. NT Status code
  3238. --*/
  3239. {
  3240. NTSTATUS Status;
  3241. NETLOGON_AUTHENTICATOR OurAuthenticator;
  3242. NETLOGON_AUTHENTICATOR ReturnAuthenticator;
  3243. LM_OWF_PASSWORD OwfPassword;
  3244. LARGE_INTEGER CurrentPasswordTime;
  3245. PUNICODE_STRING CurrentPassword = NULL;
  3246. PUNICODE_STRING OldPassword = NULL;
  3247. DWORD PasswordVersion;
  3248. WCHAR ClearTextPassword[LM20_PWLEN+1];
  3249. UNICODE_STRING NewPassword;
  3250. BOOL PasswordChangedOnServer = FALSE;
  3251. BOOL LsaSecretChanged = FALSE;
  3252. BOOL DefaultCurrentPasswordBeingChanged = FALSE;
  3253. BOOL DefaultOldPasswordBeingChanged = FALSE;
  3254. BOOLEAN AmWriter = FALSE;
  3255. ULONG CallAgainPeriod = 0;
  3256. //
  3257. // Initialization
  3258. //
  3259. NlAssert( ClientSession->CsReferenceCount > 0 );
  3260. //
  3261. // If the password change was refused by the DC,
  3262. // Don't ever try to change the password again (until the next reboot).
  3263. //
  3264. // This could have been written to try every MaximumPasswordAge. However,
  3265. // that gets complex if you take into consideration the CS_UPDATE_PASSWORD
  3266. // case where the time stamp on the LSA Secret doesn't get changed.
  3267. //
  3268. LOCK_TRUST_LIST( ClientSession->CsDomainInfo );
  3269. if ( ClientSession->CsFlags & CS_PASSWORD_REFUSED ) {
  3270. UNLOCK_TRUST_LIST( ClientSession->CsDomainInfo );
  3271. CallAgainPeriod = MAILSLOT_WAIT_FOREVER;
  3272. Status = STATUS_SUCCESS;
  3273. goto Cleanup;
  3274. }
  3275. UNLOCK_TRUST_LIST( ClientSession->CsDomainInfo );
  3276. //
  3277. // Become a writer of the ClientSession.
  3278. //
  3279. if ( !NlTimeoutSetWriterClientSession( ClientSession, WRITER_WAIT_PERIOD ) ) {
  3280. NlPrintCs((NL_CRITICAL, ClientSession,
  3281. "NlChangePassword: Can't become writer of client session.\n" ));
  3282. Status = STATUS_NO_LOGON_SERVERS;
  3283. goto Cleanup;
  3284. }
  3285. AmWriter = TRUE;
  3286. //
  3287. // Get the outgoing password and the time the password was last changed
  3288. //
  3289. Status = NlGetOutgoingPassword( ClientSession,
  3290. &CurrentPassword,
  3291. &OldPassword,
  3292. &PasswordVersion,
  3293. &CurrentPasswordTime );
  3294. if ( !NT_SUCCESS( Status ) ) {
  3295. NlPrintCs((NL_CRITICAL, ClientSession,
  3296. "NlChangePassword: Cannot NlGetOutgoingPassword %lX\n",
  3297. Status));
  3298. goto Cleanup;
  3299. }
  3300. //
  3301. // If the (old or new) password is still the default password
  3302. // (lower case computer name),
  3303. // or the password is null (a convenient default for domain trust),
  3304. // Flag that fact.
  3305. //
  3306. if ( CurrentPassword == NULL ||
  3307. CurrentPassword->Length == 0 ||
  3308. RtlEqualComputerName( &ClientSession->CsDomainInfo->DomUnicodeComputerNameString,
  3309. CurrentPassword ) ) {
  3310. DefaultCurrentPasswordBeingChanged = TRUE;
  3311. NlPrintCs((NL_SESSION_SETUP, ClientSession,
  3312. "NlChangePassword: New LsaSecret is default value.\n" ));
  3313. }
  3314. if ( OldPassword == NULL ||
  3315. OldPassword->Length == 0 ||
  3316. RtlEqualComputerName( &ClientSession->CsDomainInfo->DomUnicodeComputerNameString,
  3317. OldPassword ) ) {
  3318. DefaultOldPasswordBeingChanged = TRUE;
  3319. NlPrintCs((NL_SESSION_SETUP, ClientSession,
  3320. "NlChangePassword: Old LsaSecret is default value.\n" ));
  3321. }
  3322. //
  3323. // If the password has not yet expired,
  3324. // and the password is not the default,
  3325. // and the password change isn't forced,
  3326. // just return.
  3327. //
  3328. LOCK_TRUST_LIST( ClientSession->CsDomainInfo );
  3329. if ( (ClientSession->CsFlags & CS_UPDATE_PASSWORD) == 0 &&
  3330. !NlTimeHasElapsedEx( &CurrentPasswordTime,
  3331. &NlGlobalParameters.MaximumPasswordAge_100ns,
  3332. &CallAgainPeriod ) &&
  3333. !DefaultCurrentPasswordBeingChanged &&
  3334. !DefaultOldPasswordBeingChanged &&
  3335. !ForcePasswordChange ) {
  3336. //
  3337. // Note that, since NlTimeHasElapsedEx returned FALSE,
  3338. // CallAgainPeriod is the time left until the next
  3339. // password change.
  3340. //
  3341. UNLOCK_TRUST_LIST( ClientSession->CsDomainInfo );
  3342. Status = STATUS_SUCCESS;
  3343. goto Cleanup;
  3344. }
  3345. UNLOCK_TRUST_LIST( ClientSession->CsDomainInfo );
  3346. CallAgainPeriod = 0; // Let the caller determine the frequency for retries.
  3347. NlPrintCs((NL_SESSION_SETUP, ClientSession,
  3348. "NlChangePassword: Doing it.\n" ));
  3349. //
  3350. // If the session isn't authenticated,
  3351. // do so now.
  3352. //
  3353. // We're careful to not force this authentication unless the password
  3354. // needs to be changed.
  3355. //
  3356. // If this is the PDC changing its own password,
  3357. // there's no need to authenticate.
  3358. //
  3359. if ( ClientSession->CsState != CS_AUTHENTICATED &&
  3360. !( ClientSession->CsSecureChannelType == ServerSecureChannel &&
  3361. ClientSession->CsDomainInfo->DomRole == RolePrimary ) ) {
  3362. //
  3363. // If we've tried to authenticate recently,
  3364. // don't bother trying again.
  3365. //
  3366. if ( !NlTimeToReauthenticate( ClientSession ) ) {
  3367. Status = ClientSession->CsConnectionStatus;
  3368. goto Cleanup;
  3369. }
  3370. //
  3371. // Try to set up the session.
  3372. //
  3373. Status = NlSessionSetup( ClientSession );
  3374. if ( !NT_SUCCESS(Status) ) {
  3375. goto Cleanup;
  3376. }
  3377. }
  3378. //
  3379. // Once we change the password in LsaSecret storage,
  3380. // all future attempts to change the password should use the value
  3381. // from LsaSecret storage. The secure channel is using the old
  3382. // value of the password.
  3383. //
  3384. LOCK_TRUST_LIST( ClientSession->CsDomainInfo );
  3385. if (ClientSession->CsFlags & CS_UPDATE_PASSWORD) {
  3386. NlPrintCs((NL_SESSION_SETUP, ClientSession,
  3387. "NlChangePassword: Password already updated in secret\n" ));
  3388. if ( CurrentPassword == NULL ) {
  3389. RtlInitUnicodeString( &NewPassword, NULL );
  3390. } else {
  3391. NewPassword = *CurrentPassword;
  3392. }
  3393. //
  3394. // Handle the case where LsaSecret storage has not yet been updated.
  3395. //
  3396. } else {
  3397. ULONG i;
  3398. //
  3399. // Build a new clear text password using:
  3400. // Entirely random bits.
  3401. // Srvmgr later uses this password as a zero terminated unicode string
  3402. // so ensure there aren't any zero chars in the middle
  3403. //
  3404. if ( !NlGenerateRandomBits( (LPBYTE)ClearTextPassword, sizeof(ClearTextPassword))) {
  3405. NlPrint((NL_CRITICAL, "Can't NlGenerateRandomBits for clear password\n" ));
  3406. }
  3407. for (i = 0; i < sizeof(ClearTextPassword)/sizeof(WCHAR); i++) {
  3408. if ( ClearTextPassword[i] == '\0') {
  3409. ClearTextPassword[i] = 1;
  3410. }
  3411. }
  3412. ClearTextPassword[LM20_PWLEN] = L'\0';
  3413. RtlInitUnicodeString( &NewPassword, ClearTextPassword );
  3414. //
  3415. //
  3416. // Set the new outgoing password locally.
  3417. //
  3418. // Set the OldValue to the perviously obtained CurrentValue.
  3419. // Increment the password version number.
  3420. //
  3421. PasswordVersion++;
  3422. Status = NlSetOutgoingPassword(
  3423. ClientSession,
  3424. &NewPassword,
  3425. CurrentPassword,
  3426. PasswordVersion,
  3427. PasswordVersion-1 );
  3428. if ( !NT_SUCCESS( Status ) ) {
  3429. NlPrintCs((NL_CRITICAL, ClientSession,
  3430. "NlChangePassword: Cannot NlSetOutgoingPassword %lX\n",
  3431. Status));
  3432. UNLOCK_TRUST_LIST( ClientSession->CsDomainInfo );
  3433. goto Cleanup;
  3434. }
  3435. //
  3436. // Flag that we've updated the password in LsaSecret storage.
  3437. //
  3438. LsaSecretChanged = TRUE;
  3439. ClientSession->CsFlags |= CS_UPDATE_PASSWORD;
  3440. NlPrintCs((NL_SESSION_SETUP, ClientSession,
  3441. "NlChangePassword: Flag password changed in LsaSecret\n" ));
  3442. }
  3443. UNLOCK_TRUST_LIST( ClientSession->CsDomainInfo );
  3444. //
  3445. // Perform the initial encryption.
  3446. //
  3447. Status = RtlCalculateNtOwfPassword( &NewPassword, &OwfPassword);
  3448. if ( !NT_SUCCESS( Status )) {
  3449. NlPrintCs((NL_CRITICAL, ClientSession,
  3450. "NlChangePassword: Cannot RtlCalculateNtOwfPassword %lX\n",
  3451. Status));
  3452. goto Cleanup;
  3453. }
  3454. //
  3455. // If this is a PDC, all we need to do is change the local account password
  3456. //
  3457. if ( ClientSession->CsSecureChannelType == ServerSecureChannel &&
  3458. ClientSession->CsDomainInfo->DomRole == RolePrimary ) {
  3459. Status = NlSamChangePasswordNamedUser( ClientSession->CsDomainInfo,
  3460. ClientSession->CsAccountName,
  3461. &NewPassword,
  3462. &OwfPassword );
  3463. if ( NT_SUCCESS(Status) ) {
  3464. PasswordChangedOnServer = TRUE;
  3465. } else {
  3466. NlPrintCs((NL_CRITICAL, ClientSession,
  3467. "NlChangePassword: Cannot change password on PDC local user account 0x%lx\n",
  3468. Status));
  3469. }
  3470. goto Cleanup;
  3471. }
  3472. //
  3473. // Change the password on the PDC
  3474. //
  3475. Status = NlChangePasswordHigher( ClientSession,
  3476. ClientSession->CsAccountName,
  3477. ClientSession->CsSecureChannelType,
  3478. &OwfPassword,
  3479. &NewPassword,
  3480. &PasswordVersion );
  3481. if ( Status != STATUS_ACCESS_DENIED ) {
  3482. PasswordChangedOnServer = TRUE;
  3483. }
  3484. //
  3485. // If the server refused the change,
  3486. // put the lsa secret back the way it was.
  3487. // pretend the change was successful.
  3488. //
  3489. if ( Status == STATUS_WRONG_PASSWORD ) {
  3490. NlPrintCs((NL_SESSION_SETUP, ClientSession,
  3491. "NlChangePassword: PDC refused to change password\n" ));
  3492. //
  3493. // If we changed the LSA secret,
  3494. // put it back.
  3495. //
  3496. LOCK_TRUST_LIST( ClientSession->CsDomainInfo );
  3497. if ( LsaSecretChanged ) {
  3498. NlPrintCs((NL_SESSION_SETUP, ClientSession,
  3499. "NlChangePassword: undoing LSA secret change.\n" ));
  3500. PasswordVersion--;
  3501. Status = NlSetOutgoingPassword(
  3502. ClientSession,
  3503. CurrentPassword,
  3504. OldPassword,
  3505. PasswordVersion,
  3506. PasswordVersion > 0 ? PasswordVersion-1 : 0 );
  3507. if ( !NT_SUCCESS( Status ) ) {
  3508. NlPrintCs((NL_CRITICAL, ClientSession,
  3509. "NlChangePassword: Cannot undo NlSetOutgoingPassword %lX\n",
  3510. Status));
  3511. UNLOCK_TRUST_LIST( ClientSession->CsDomainInfo );
  3512. goto Cleanup;
  3513. }
  3514. //
  3515. // Undo what we've done above.
  3516. //
  3517. ClientSession->CsFlags &= ~CS_UPDATE_PASSWORD;
  3518. }
  3519. //
  3520. // Prevent us from trying too frequently.
  3521. //
  3522. ClientSession->CsFlags |= CS_PASSWORD_REFUSED;
  3523. CallAgainPeriod = MAILSLOT_WAIT_FOREVER;
  3524. UNLOCK_TRUST_LIST( ClientSession->CsDomainInfo );
  3525. //
  3526. // Avoid special cleanup below.
  3527. //
  3528. PasswordChangedOnServer = FALSE;
  3529. Status = STATUS_SUCCESS;
  3530. }
  3531. //
  3532. // Common exit
  3533. //
  3534. Cleanup:
  3535. if ( PasswordChangedOnServer ) {
  3536. //
  3537. // On success,
  3538. // Indicate that the password has now been updated on the
  3539. // PDC so the old password is no longer in use.
  3540. //
  3541. if ( NT_SUCCESS( Status ) ) {
  3542. LOCK_TRUST_LIST( ClientSession->CsDomainInfo );
  3543. ClientSession->CsFlags &= ~CS_UPDATE_PASSWORD;
  3544. NlPrintCs((NL_SESSION_SETUP, ClientSession,
  3545. "NlChangePassword: Flag password updated on PDC\n" ));
  3546. //
  3547. // If the default current password was changed,
  3548. // avoid leaving the default password around as the old
  3549. // password. Otherwise, a bogus DC could convince us to use
  3550. // the bogus DC via the default password. Set both current
  3551. // and old version numbers to the new value.
  3552. //
  3553. if ( DefaultCurrentPasswordBeingChanged ) {
  3554. NlPrintCs((NL_SESSION_SETUP, ClientSession,
  3555. "NlChangePassword: Setting LsaSecret old password to same as new password\n" ));
  3556. Status = NlSetOutgoingPassword(
  3557. ClientSession,
  3558. &NewPassword,
  3559. &NewPassword,
  3560. PasswordVersion,
  3561. PasswordVersion );
  3562. if ( !NT_SUCCESS( Status ) ) {
  3563. NlPrintCs((NL_CRITICAL, ClientSession,
  3564. "NlChangePassword: Cannot LsarSetSecret to set old password %lX\n",
  3565. Status));
  3566. UNLOCK_TRUST_LIST( ClientSession->CsDomainInfo );
  3567. goto Cleanup;
  3568. }
  3569. }
  3570. //
  3571. // Save the password for our own future reference.
  3572. //
  3573. // CsNtOwfPassword is the most recent known good password
  3574. //
  3575. RtlCopyMemory( &ClientSession->CsNtOwfPassword, &OwfPassword, sizeof( OwfPassword ));
  3576. UNLOCK_TRUST_LIST( ClientSession->CsDomainInfo );
  3577. //
  3578. // Indicate we don't need to call change the password again for awhile
  3579. //
  3580. if ( NlGlobalParameters.MaximumPasswordAge > (TIMER_MAX_PERIOD/NL_MILLISECONDS_PER_DAY) ) {
  3581. CallAgainPeriod = TIMER_MAX_PERIOD;
  3582. } else {
  3583. CallAgainPeriod = NlGlobalParameters.MaximumPasswordAge * NL_MILLISECONDS_PER_DAY;
  3584. }
  3585. //
  3586. // Notify the Admin that he'll have to manually set this server's
  3587. // password on both this server and the PDC.
  3588. //
  3589. } else {
  3590. LPWSTR MsgStrings[2];
  3591. //
  3592. // Drop the secure channel
  3593. //
  3594. NlSetStatusClientSession( ClientSession, Status );
  3595. //
  3596. // write event log
  3597. //
  3598. MsgStrings[0] = ClientSession->CsAccountName;
  3599. MsgStrings[1] = (LPWSTR) LongToPtr( Status );
  3600. NlpWriteEventlog (
  3601. NELOG_NetlogonPasswdSetFailed,
  3602. EVENTLOG_ERROR_TYPE,
  3603. (LPBYTE) & Status,
  3604. sizeof(Status),
  3605. MsgStrings,
  3606. 2 | NETP_LAST_MESSAGE_IS_NTSTATUS );
  3607. }
  3608. }
  3609. //
  3610. // Clean up locally used resources.
  3611. //
  3612. if ( CurrentPassword != NULL ) {
  3613. LocalFree( CurrentPassword );
  3614. }
  3615. if ( OldPassword != NULL ) {
  3616. LocalFree( OldPassword );
  3617. }
  3618. if ( AmWriter ) {
  3619. NlResetWriterClientSession( ClientSession );
  3620. }
  3621. //
  3622. // Tell the caller when he should call us again
  3623. //
  3624. if ( ARGUMENT_PRESENT( RetCallAgainPeriod) ) {
  3625. *RetCallAgainPeriod = CallAgainPeriod;
  3626. }
  3627. return Status;
  3628. }
  3629. NTSTATUS
  3630. NlRefreshClientSession(
  3631. IN PCLIENT_SESSION ClientSession
  3632. )
  3633. /*++
  3634. Routine Description:
  3635. Refresh the client session info. The info that we intend
  3636. to refresh is:
  3637. * Server name (the DC can be renamed in Whistler).
  3638. * Discovery flags, in particular whether the server
  3639. is still close.
  3640. * The server IP address.
  3641. We will also refresh our site name (on workstation).
  3642. The caller must be a writer of the ClientSession.
  3643. Arguments:
  3644. ClientSession - Structure describing the session.
  3645. Return Value:
  3646. NT Status code
  3647. --*/
  3648. {
  3649. NTSTATUS Status = STATUS_SUCCESS;
  3650. NET_API_STATUS NetStatus = NO_ERROR;
  3651. PNL_DC_CACHE_ENTRY NlDcCacheEntry = NULL;
  3652. BOOLEAN DcRediscovered = FALSE;
  3653. //
  3654. // If the client session is idle,
  3655. // there is nothing to refresh
  3656. //
  3657. if ( ClientSession->CsState == CS_IDLE ) {
  3658. Status = STATUS_SUCCESS;
  3659. goto Cleanup;
  3660. }
  3661. //
  3662. // If the server (DC) is NT4.0, there is no need for refresh.
  3663. // (The only info that can potentially change for NT4.0 DC
  3664. // is its IP address which is not worth refreshing)
  3665. //
  3666. if ( (ClientSession->CsDiscoveryFlags & CS_DISCOVERY_HAS_DS) == 0 ) {
  3667. Status = STATUS_SUCCESS;
  3668. goto Cleanup;
  3669. }
  3670. //
  3671. // If it's not yet time to refresh the info,
  3672. // we don't need to do anything
  3673. //
  3674. EnterCriticalSection( &NlGlobalDcDiscoveryCritSect );
  3675. if ( !NetpLogonTimeHasElapsed(ClientSession->CsLastRefreshTime,
  3676. MAX_DC_REFRESH_TIMEOUT) ) {
  3677. LeaveCriticalSection( &NlGlobalDcDiscoveryCritSect );
  3678. Status = STATUS_SUCCESS;
  3679. goto Cleanup;
  3680. }
  3681. LeaveCriticalSection( &NlGlobalDcDiscoveryCritSect );
  3682. //
  3683. // Get the up to date server info
  3684. //
  3685. Status = NlGetAnyDCName( ClientSession,
  3686. FALSE, // Do not require IP
  3687. FALSE, // Don't do with-account discovery
  3688. &NlDcCacheEntry,
  3689. &DcRediscovered );
  3690. if ( !NT_SUCCESS(Status) ) {
  3691. goto Cleanup;
  3692. }
  3693. //
  3694. // Use this opportunity to update our site on a workstation
  3695. //
  3696. if ( NlGlobalMemberWorkstation ) {
  3697. //
  3698. // Only Win2K or newer DCs undestand the site concept
  3699. //
  3700. if ( (NlDcCacheEntry->ReturnFlags & DS_DS_FLAG) != 0 ) {
  3701. NlSetDynamicSiteName( NlDcCacheEntry->UnicodeClientSiteName );
  3702. } else {
  3703. NlPrint(( NL_SITE,
  3704. "NlRefreshClientSession: NlGetAnyDCName returned NT4 DC\n" ));
  3705. }
  3706. }
  3707. Cleanup:
  3708. if ( NlDcCacheEntry != NULL ) {
  3709. NetpDcDerefCacheEntry( NlDcCacheEntry );
  3710. }
  3711. return Status;
  3712. }
  3713. NTSTATUS
  3714. NlEnsureSessionAuthenticated(
  3715. IN PCLIENT_SESSION ClientSession,
  3716. IN DWORD DesiredFlags
  3717. )
  3718. /*++
  3719. Routine Description:
  3720. Ensure there is an authenticated session for the specified ClientSession.
  3721. If the authenticated DC does not have the characteristics specified by
  3722. DesiredFlags, attempt to find a DC that does.
  3723. The caller must be a writer of the ClientSession.
  3724. Arguments:
  3725. ClientSession - Structure describing the session.
  3726. DesiredFlags - characteristics that the authenticated DC should have.
  3727. Can be one or more of the following:
  3728. CS_DISCOVERY_HAS_DS // Discovered DS has a DS
  3729. CS_DISCOVERY_IS_CLOSE // Discovered DS is in a close site
  3730. It is the callers responsibility to ensure that the DC really DOES
  3731. have those characteristics.
  3732. Return Value:
  3733. NT Status code
  3734. --*/
  3735. {
  3736. NTSTATUS Status;
  3737. //
  3738. // First refresh the client session
  3739. //
  3740. Status = NlRefreshClientSession( ClientSession );
  3741. if ( !NT_SUCCESS(Status) ) {
  3742. NlPrintCs(( NL_CRITICAL, ClientSession,
  3743. "NlpEnsureSessionAuthenticated: Can't refresh the session: 0x%lx\n",
  3744. Status ));
  3745. goto Cleanup;
  3746. }
  3747. //
  3748. // If this secure channel is from a BDC to the PDC,
  3749. // there is only ONE PDC so don't ask for special characteristics.
  3750. //
  3751. if ( ClientSession->CsSecureChannelType == ServerSecureChannel ) {
  3752. DesiredFlags = 0;
  3753. //
  3754. // If this secure channel isn't expected to have NT 5 DCs,
  3755. // don't try to find one.
  3756. //
  3757. } else if ((ClientSession->CsFlags & CS_NT5_DOMAIN_TRUST) == 0 ) {
  3758. DesiredFlags = 0;
  3759. //
  3760. // If we don't have a close DC,
  3761. // and it has been a long time since we've tried to find a close DC,
  3762. // do it now.
  3763. //
  3764. } else if ( (ClientSession->CsDiscoveryFlags & CS_DISCOVERY_IS_CLOSE) == 0 ) {
  3765. BOOLEAN ReturnBoolean;
  3766. EnterCriticalSection( &NlGlobalDcDiscoveryCritSect );
  3767. if ( NetpLogonTimeHasElapsed(
  3768. ClientSession->CsLastDiscoveryTime,
  3769. NlGlobalParameters.CloseSiteTimeout * 1000 ) ) {
  3770. DesiredFlags |= CS_DISCOVERY_IS_CLOSE;
  3771. }
  3772. LeaveCriticalSection( &NlGlobalDcDiscoveryCritSect );
  3773. }
  3774. //
  3775. // If a DC has already been detected,
  3776. // and the caller wants special characteristics,
  3777. // try for them now.
  3778. //
  3779. if ( ClientSession->CsState != CS_IDLE &&
  3780. DesiredFlags != 0 ) {
  3781. //
  3782. // If the DC doesn't have the required characteristics,
  3783. // try to find a new one now
  3784. //
  3785. EnterCriticalSection( &NlGlobalDcDiscoveryCritSect );
  3786. if ( (ClientSession->CsDiscoveryFlags & DesiredFlags) != DesiredFlags ) {
  3787. //
  3788. // Avoid discovery if we've done it recently.
  3789. //
  3790. // All discoveries prefer a DC that has all of the desired characteristics.
  3791. // So if we didn't find one, don't try again.
  3792. //
  3793. if ( NlTimeToRediscover(ClientSession, FALSE) ) { // we'll do discovery without account
  3794. NlPrintCs(( NL_SESSION_SETUP, ClientSession,
  3795. "NlpEnsureSessionAuthenticated: Try to find a better DC for this operation. 0x%lx\n", DesiredFlags ));
  3796. //
  3797. // Discovering a DC when the session is not idle tries to find a
  3798. // "better" DC.
  3799. //
  3800. // Ignore failures.
  3801. //
  3802. // Call without the any locks locked to prevent doing network I/O
  3803. // with the lock held.
  3804. //
  3805. // Don't ask for with-account discovery as it's too costly on the
  3806. // server side. If the discovered server doesn't have our account,
  3807. // the session setup logic will attempt with-account discovery.
  3808. //
  3809. LeaveCriticalSection( &NlGlobalDcDiscoveryCritSect );
  3810. Status = NlDiscoverDc ( ClientSession,
  3811. DT_Synchronous,
  3812. FALSE ,
  3813. FALSE ); // without account
  3814. EnterCriticalSection( &NlGlobalDcDiscoveryCritSect );
  3815. }
  3816. }
  3817. LeaveCriticalSection( &NlGlobalDcDiscoveryCritSect );
  3818. }
  3819. //
  3820. // If we haven't yet authenticated,
  3821. // do so now.
  3822. //
  3823. if ( ClientSession->CsState != CS_AUTHENTICATED ) {
  3824. //
  3825. // If we've tried to authenticate recently,
  3826. // don't bother trying again.
  3827. //
  3828. if ( !NlTimeToReauthenticate( ClientSession ) ) {
  3829. Status = ClientSession->CsConnectionStatus;
  3830. NlAssert( !NT_SUCCESS( Status ));
  3831. if ( NT_SUCCESS( Status )) {
  3832. Status = STATUS_NO_LOGON_SERVERS;
  3833. }
  3834. goto Cleanup;
  3835. }
  3836. //
  3837. // Try to set up the session.
  3838. //
  3839. Status = NlSessionSetup( ClientSession );
  3840. if ( !NT_SUCCESS(Status) ) {
  3841. goto Cleanup;
  3842. }
  3843. }
  3844. Status = STATUS_SUCCESS;
  3845. Cleanup:
  3846. return Status;
  3847. }
  3848. NTSTATUS
  3849. NlChangePasswordHigher(
  3850. IN PCLIENT_SESSION ClientSession,
  3851. IN LPWSTR AccountName,
  3852. IN NETLOGON_SECURE_CHANNEL_TYPE AccountType,
  3853. IN PLM_OWF_PASSWORD NewOwfPassword OPTIONAL,
  3854. IN PUNICODE_STRING NewClearPassword OPTIONAL,
  3855. IN PDWORD ClearPasswordVersionNumber OPTIONAL
  3856. )
  3857. /*++
  3858. Routine Description:
  3859. Pass the new password to the machine specified by the ClientSession.
  3860. The caller must be a writer of the ClientSession.
  3861. Arguments:
  3862. ClientSession - Structure describing the session to change the password
  3863. for. The specified structure must be referenced.
  3864. AccountName - Name of the account whose password is being changed.
  3865. AccountType - Type of account whose password is being changed.
  3866. NewOwfPassword - Owf password to pass to ClientSession
  3867. NewClearPassword - Clear password to pass to client session
  3868. ClearPasswordVersionNumber - Version number of the clear password. Must
  3869. be present if NewClearPassword is present.
  3870. Return Value:
  3871. NT Status code
  3872. --*/
  3873. {
  3874. NTSTATUS Status;
  3875. NETLOGON_AUTHENTICATOR OurAuthenticator;
  3876. NETLOGON_AUTHENTICATOR ReturnAuthenticator;
  3877. SESSION_INFO SessionInfo;
  3878. BOOLEAN FirstTry = TRUE;
  3879. //
  3880. // Initialization
  3881. //
  3882. NlAssert( ClientSession->CsReferenceCount > 0 );
  3883. NlAssert( ClientSession->CsFlags & CS_WRITER );
  3884. //
  3885. // If the session isn't authenticated,
  3886. // do so now.
  3887. //
  3888. // We're careful to not force this authentication unless the password
  3889. // needs to be changed.
  3890. //
  3891. FirstTryFailed:
  3892. Status = NlEnsureSessionAuthenticated( ClientSession, 0 );
  3893. if ( !NT_SUCCESS(Status) ) {
  3894. goto Cleanup;
  3895. }
  3896. SessionInfo.SessionKey = ClientSession->CsSessionKey;
  3897. SessionInfo.NegotiatedFlags = ClientSession->CsNegotiatedFlags;
  3898. //
  3899. // Build the Authenticator for this request to the PDC.
  3900. //
  3901. NlBuildAuthenticator(
  3902. &ClientSession->CsAuthenticationSeed,
  3903. &ClientSession->CsSessionKey,
  3904. &OurAuthenticator);
  3905. //
  3906. // If the other side will accept a clear text password,
  3907. // send it.
  3908. //
  3909. if ( NewClearPassword != NULL &&
  3910. (SessionInfo.NegotiatedFlags & NETLOGON_SUPPORTS_PASSWORD_SET_2) != 0 ) {
  3911. NL_TRUST_PASSWORD NlTrustPassword;
  3912. NL_PASSWORD_VERSION PasswordVersion;
  3913. //
  3914. // Copy the new password to the end of the buffer.
  3915. //
  3916. RtlCopyMemory( ((LPBYTE)NlTrustPassword.Buffer) +
  3917. NL_MAX_PASSWORD_LENGTH * sizeof(WCHAR) -
  3918. NewClearPassword->Length,
  3919. NewClearPassword->Buffer,
  3920. NewClearPassword->Length );
  3921. NlTrustPassword.Length = NewClearPassword->Length;
  3922. //
  3923. // For an interdomain trust account,
  3924. // indicate that we pass the password version number by prefixing
  3925. // a DWORD equal to PASSWORD_VERSION_NUMBER_PRESENT right before
  3926. // the password in NewClearPassword->Buffer. An old server (RC0)
  3927. // not supporting version numbers will simply ignore these bits.
  3928. // A server supporting version numbers will examine these bits
  3929. // and if they are equal to PASSWORD_VERSION_NUMBER_PRESENT then
  3930. // that will be an indication that a version number is passed. An
  3931. // old client not supporting version numbers will generate random
  3932. // bits in place of PASSWORD_VERSION_NUMBER_PRESENT. It is highly
  3933. // unlikely that an old client will generate random bits equal to
  3934. // PASSWORD_VERSION_NUMBER_PRESENT. The
  3935. // version number will be a DWORD preceeding the DWORD equal to
  3936. // PASSWORD_VERSION_NUMBER_PRESENT. Another DWORD equal to 0 will
  3937. // preceed the version number. Its purpose is to allow any future
  3938. // additions to the buffer. The value of this DWORD different from
  3939. // 0 will indicate without any uncertainty that some additional
  3940. // info is passed preceding this DWORD. The 3 new DWORDs are packed
  3941. // in a struct to avoid unalingment problems.
  3942. //
  3943. if ( IsDomainSecureChannelType( AccountType ) ) {
  3944. NlAssert( ClearPasswordVersionNumber != NULL );
  3945. NlAssert( NL_MAX_PASSWORD_LENGTH * sizeof(WCHAR) -
  3946. NewClearPassword->Length -
  3947. sizeof(PasswordVersion) > 0 );
  3948. PasswordVersion.ReservedField = 0;
  3949. PasswordVersion.PasswordVersionNumber = *ClearPasswordVersionNumber;
  3950. PasswordVersion.PasswordVersionPresent = PASSWORD_VERSION_NUMBER_PRESENT;
  3951. RtlCopyMemory( ((LPBYTE)NlTrustPassword.Buffer) +
  3952. NL_MAX_PASSWORD_LENGTH * sizeof(WCHAR) -
  3953. NewClearPassword->Length -
  3954. sizeof(PasswordVersion),
  3955. &PasswordVersion,
  3956. sizeof(PasswordVersion) );
  3957. }
  3958. //
  3959. // Fill the rest of the buffer with random bytes
  3960. //
  3961. if ( !NlGenerateRandomBits( (LPBYTE)NlTrustPassword.Buffer,
  3962. (NL_MAX_PASSWORD_LENGTH * sizeof(WCHAR)) -
  3963. NewClearPassword->Length -
  3964. sizeof(PasswordVersion) ) ) {
  3965. NlPrint((NL_CRITICAL, "Can't NlGenerateRandomBits for clear password prefix\n" ));
  3966. }
  3967. //
  3968. // Encrypt the whole buffer.
  3969. //
  3970. NlEncryptRC4( &NlTrustPassword,
  3971. sizeof( NlTrustPassword ),
  3972. &SessionInfo );
  3973. //
  3974. // Change the password on the machine our connection is to.
  3975. //
  3976. NL_API_START( Status, ClientSession, TRUE ) {
  3977. NlAssert( ClientSession->CsUncServerName != NULL );
  3978. Status = I_NetServerPasswordSet2( ClientSession->CsUncServerName,
  3979. AccountName,
  3980. AccountType,
  3981. ClientSession->CsDomainInfo->DomUnicodeComputerNameString.Buffer,
  3982. &OurAuthenticator,
  3983. &ReturnAuthenticator,
  3984. &NlTrustPassword);
  3985. if ( !NT_SUCCESS(Status) ) {
  3986. NlPrintRpcDebug( "I_NetServerPasswordSet2", Status );
  3987. }
  3988. // NOTE: This call may drop the secure channel behind our back
  3989. } NL_API_ELSE( Status, ClientSession, TRUE ) {
  3990. } NL_API_END;
  3991. //
  3992. // If the other side needs an OWF password,
  3993. // send it.
  3994. //
  3995. } else {
  3996. ENCRYPTED_LM_OWF_PASSWORD SessKeyEncrPassword;
  3997. LM_OWF_PASSWORD LocalOwfPassword;
  3998. //
  3999. // If the caller doesn't know the OWF password,
  4000. // compute the owf.
  4001. //
  4002. if ( NewOwfPassword == NULL ) {
  4003. //
  4004. // Perform the initial encryption.
  4005. //
  4006. Status = RtlCalculateNtOwfPassword( NewClearPassword, &LocalOwfPassword);
  4007. if ( !NT_SUCCESS( Status )) {
  4008. NlPrintCs((NL_CRITICAL, ClientSession,
  4009. "NlChangePasswordHigher: Cannot RtlCalculateNtOwfPassword %lX\n",
  4010. Status));
  4011. goto Cleanup;
  4012. }
  4013. NewOwfPassword = &LocalOwfPassword;
  4014. }
  4015. //
  4016. // Encrypt the password again with the session key.
  4017. // The PDC will decrypt it on the other side.
  4018. //
  4019. Status = RtlEncryptNtOwfPwdWithNtOwfPwd(
  4020. NewOwfPassword,
  4021. (PNT_OWF_PASSWORD) &ClientSession->CsSessionKey,
  4022. &SessKeyEncrPassword) ;
  4023. if ( !NT_SUCCESS( Status )) {
  4024. NlPrintCs((NL_CRITICAL, ClientSession,
  4025. "NlChangePasswordHigher: Cannot RtlEncryptNtOwfPwdWithNtOwfPwd %lX\n",
  4026. Status));
  4027. goto Cleanup;
  4028. }
  4029. //
  4030. // Change the password on the machine our connection is to.
  4031. //
  4032. NL_API_START( Status, ClientSession, TRUE ) {
  4033. NlAssert( ClientSession->CsUncServerName != NULL );
  4034. Status = I_NetServerPasswordSet( ClientSession->CsUncServerName,
  4035. AccountName,
  4036. AccountType,
  4037. ClientSession->CsDomainInfo->DomUnicodeComputerNameString.Buffer,
  4038. &OurAuthenticator,
  4039. &ReturnAuthenticator,
  4040. &SessKeyEncrPassword);
  4041. if ( !NT_SUCCESS(Status) ) {
  4042. NlPrintRpcDebug( "I_NetServerPasswordSet", Status );
  4043. }
  4044. // NOTE: This call may drop the secure channel behind our back
  4045. } NL_API_ELSE( Status, ClientSession, TRUE ) {
  4046. } NL_API_END;
  4047. }
  4048. //
  4049. // Now verify primary's authenticator and update our seed
  4050. //
  4051. if ( NlpDidDcFail( Status ) ||
  4052. !NlUpdateSeed( &ClientSession->CsAuthenticationSeed,
  4053. &ReturnAuthenticator.Credential,
  4054. &ClientSession->CsSessionKey) ) {
  4055. NlPrintCs(( NL_CRITICAL, ClientSession,
  4056. "NlChangePasswordHigher: denying access after status: 0x%lx\n",
  4057. Status ));
  4058. //
  4059. // Preserve any status indicating a communication error.
  4060. //
  4061. if ( NT_SUCCESS(Status) ) {
  4062. Status = STATUS_ACCESS_DENIED;
  4063. }
  4064. NlSetStatusClientSession( ClientSession, Status );
  4065. //
  4066. // Perhaps the netlogon service on the server has just restarted.
  4067. // Try just once to set up a session to the server again.
  4068. //
  4069. if ( FirstTry ) {
  4070. FirstTry = FALSE;
  4071. goto FirstTryFailed;
  4072. }
  4073. }
  4074. //
  4075. // Common exit
  4076. //
  4077. Cleanup:
  4078. if ( !NT_SUCCESS(Status) ) {
  4079. NlPrintCs((NL_CRITICAL, ClientSession,
  4080. "NlChangePasswordHigher: %ws: failed %lX\n",
  4081. AccountName,
  4082. Status));
  4083. }
  4084. return Status;
  4085. }
  4086. NTSTATUS
  4087. NlGetUserPriv(
  4088. IN PDOMAIN_INFO DomainInfo,
  4089. IN ULONG GroupCount,
  4090. IN PGROUP_MEMBERSHIP Groups,
  4091. IN ULONG UserRelativeId,
  4092. OUT LPDWORD Priv,
  4093. OUT LPDWORD AuthFlags
  4094. )
  4095. /*++
  4096. Routine Description:
  4097. Determines the Priv and AuthFlags for the specified user.
  4098. Arguments:
  4099. DomainInfo - Hosted domain the user account is in.
  4100. GroupCount - Number of groups this user is a member of
  4101. Groups - Array of groups this user is a member of.
  4102. UserRelativeId - Relative ID of the user to query.
  4103. Priv - Returns the Lanman 2.0 Privilege level for the specified user.
  4104. AuthFlags - Returns the Lanman 2.0 Authflags for the specified user.
  4105. Return Value:
  4106. Status of the operation.
  4107. --*/
  4108. {
  4109. NET_API_STATUS NetStatus;
  4110. NTSTATUS Status;
  4111. ULONG GroupIndex;
  4112. PSID *UserSids = NULL;
  4113. ULONG UserSidCount = 0;
  4114. SAMPR_PSID_ARRAY SamSidArray;
  4115. SAMPR_ULONG_ARRAY Aliases;
  4116. //
  4117. // Initialization
  4118. //
  4119. Aliases.Element = NULL;
  4120. //
  4121. // Allocate a buffer to point to the SIDs we're interested in
  4122. // alias membership for.
  4123. //
  4124. UserSids = (PSID *)
  4125. NetpMemoryAllocate( (GroupCount+1) * sizeof(PSID) );
  4126. if ( UserSids == NULL ) {
  4127. Status = STATUS_NO_MEMORY;
  4128. goto Cleanup;
  4129. }
  4130. //
  4131. // Add the User's Sid to the Array of Sids.
  4132. //
  4133. NetStatus = NetpDomainIdToSid( DomainInfo->DomAccountDomainId,
  4134. UserRelativeId,
  4135. &UserSids[0] );
  4136. if ( NetStatus != NERR_Success ) {
  4137. Status = NetpApiStatusToNtStatus( NetStatus );
  4138. goto Cleanup;
  4139. }
  4140. UserSidCount ++;
  4141. //
  4142. // Add each group the user is a member of to the array of Sids.
  4143. //
  4144. for ( GroupIndex = 0; GroupIndex < GroupCount; GroupIndex ++ ){
  4145. NetStatus = NetpDomainIdToSid( DomainInfo->DomAccountDomainId,
  4146. Groups[GroupIndex].RelativeId,
  4147. &UserSids[GroupIndex+1] );
  4148. if ( NetStatus != NERR_Success ) {
  4149. Status = NetpApiStatusToNtStatus( NetStatus );
  4150. goto Cleanup;
  4151. }
  4152. UserSidCount ++;
  4153. }
  4154. //
  4155. // Find out which aliases in the builtin domain this user is a member of.
  4156. //
  4157. SamSidArray.Count = UserSidCount;
  4158. SamSidArray.Sids = (PSAMPR_SID_INFORMATION) UserSids;
  4159. Status = SamrGetAliasMembership( DomainInfo->DomSamBuiltinDomainHandle,
  4160. &SamSidArray,
  4161. &Aliases );
  4162. if ( !NT_SUCCESS(Status) ) {
  4163. Aliases.Element = NULL;
  4164. NlPrint((NL_CRITICAL,
  4165. "NlGetUserPriv: SamGetAliasMembership returns %lX\n",
  4166. Status ));
  4167. goto Cleanup;
  4168. }
  4169. //
  4170. // Convert the alias membership to priv and auth flags
  4171. //
  4172. NetpAliasMemberToPriv(
  4173. Aliases.Count,
  4174. Aliases.Element,
  4175. Priv,
  4176. AuthFlags );
  4177. Status = STATUS_SUCCESS;
  4178. //
  4179. // Free Locally used resources.
  4180. //
  4181. Cleanup:
  4182. if ( Aliases.Element != NULL ) {
  4183. SamIFree_SAMPR_ULONG_ARRAY ( &Aliases );
  4184. }
  4185. if ( UserSids != NULL ) {
  4186. for ( GroupIndex = 0; GroupIndex < UserSidCount; GroupIndex ++ ) {
  4187. NetpMemoryFree( UserSids[GroupIndex] );
  4188. }
  4189. NetpMemoryFree( UserSids );
  4190. }
  4191. return Status;
  4192. }
  4193. /*lint +e740 */ /* don't complain about unusual cast */