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.

2687 lines
69 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. nlp.c
  5. Abstract:
  6. This file is the contains private routines which support
  7. for the LAN Manager portions of the MSV1_0 authentication package.
  8. Author:
  9. Cliff Van Dyke 29-Apr-1991
  10. Revision History:
  11. Chandana Surlu 21-Jul-96 Stolen from \\kernel\razzle3\src\security\msv1_0\nlp.c
  12. --*/
  13. #include <global.h>
  14. #include "msp.h"
  15. #include "nlp.h"
  16. #include "nlpcache.h"
  17. #include <wincrypt.h>
  18. #include "msvwow.h"
  19. DWORD
  20. NlpCopyDomainRelativeSid(
  21. OUT PSID TargetSid,
  22. IN PSID DomainId,
  23. IN ULONG RelativeId
  24. );
  25. VOID
  26. NlpPutString(
  27. IN PUNICODE_STRING OutString,
  28. IN PUNICODE_STRING InString,
  29. IN PUCHAR *Where
  30. )
  31. /*++
  32. Routine Description:
  33. This routine copies the InString string to the memory pointed to by
  34. the Where parameter, and fixes the OutString string to point to that
  35. new copy.
  36. Parameters:
  37. OutString - A pointer to a destination NT string
  38. InString - A pointer to an NT string to be copied
  39. Where - A pointer to space to put the actual string for the
  40. OutString. The pointer is adjusted to point to the first byte
  41. following the copied string.
  42. Return Values:
  43. None.
  44. --*/
  45. {
  46. ASSERT( OutString != NULL );
  47. ASSERT( InString != NULL );
  48. ASSERT( Where != NULL && *Where != NULL);
  49. ASSERT( *Where == ROUND_UP_POINTER( *Where, sizeof(WCHAR) ) );
  50. #ifdef notdef
  51. KdPrint(("NlpPutString: %ld %Z\n", InString->Length, InString ));
  52. KdPrint((" InString: %lx %lx OutString: %lx Where: %lx\n", InString,
  53. InString->Buffer, OutString, *Where ));
  54. #endif
  55. if ( InString->Length > 0 ) {
  56. OutString->Buffer = (PWCH) *Where;
  57. OutString->MaximumLength = (USHORT)(InString->Length + sizeof(WCHAR));
  58. RtlCopyUnicodeString( OutString, InString );
  59. *Where += InString->Length;
  60. // *((WCHAR *)(*Where)) = L'\0';
  61. *(*Where) = '\0';
  62. *(*Where + 1) = '\0';
  63. *Where += 2;
  64. } else {
  65. RtlInitUnicodeString(OutString, NULL);
  66. }
  67. #ifdef notdef
  68. KdPrint((" OutString: %ld %lx\n", OutString->Length, OutString->Buffer));
  69. #endif
  70. return;
  71. }
  72. VOID
  73. NlpInitClientBuffer(
  74. OUT PCLIENT_BUFFER_DESC ClientBufferDesc,
  75. IN PLSA_CLIENT_REQUEST ClientRequest
  76. )
  77. /*++
  78. Routine Description:
  79. This routine initializes a ClientBufferDescriptor to known values.
  80. This routine must be called before any of the other routines that use
  81. the ClientBufferDescriptor.
  82. Parameters:
  83. ClientBufferDesc - Descriptor of a buffer allocated in the client's
  84. address space.
  85. ClientRequest - Is a pointer to an opaque data structure
  86. representing the client's request.
  87. Return Values:
  88. None.
  89. --*/
  90. {
  91. //
  92. // Fill in a pointer to the ClientRequest and zero the rest.
  93. //
  94. ClientBufferDesc->ClientRequest = ClientRequest;
  95. ClientBufferDesc->UserBuffer = NULL;
  96. ClientBufferDesc->MsvBuffer = NULL;
  97. ClientBufferDesc->StringOffset = 0;
  98. ClientBufferDesc->TotalSize = 0;
  99. }
  100. NTSTATUS
  101. NlpAllocateClientBuffer(
  102. IN OUT PCLIENT_BUFFER_DESC ClientBufferDesc,
  103. IN ULONG FixedSize,
  104. IN ULONG TotalSize
  105. )
  106. /*++
  107. Routine Description:
  108. This routine allocates a buffer in the clients address space.
  109. It also allocates a mirror buffer in MSV's address space.
  110. The data will be constructed in the MSV's address space then 'flushed'
  111. into the client's address space.
  112. Parameters:
  113. ClientBufferDesc - Descriptor of a buffer allocated in the client's
  114. address space.
  115. FixedSize - The size in bytes of the fixed portion of the buffer.
  116. TotalSize - The size in bytes of the entire buffer.
  117. Return Values:
  118. Status of the operation.
  119. --*/
  120. {
  121. NTSTATUS Status = STATUS_SUCCESS;
  122. //
  123. // Allocate the Mirror buffer.
  124. //
  125. ASSERT( ClientBufferDesc->MsvBuffer == NULL );
  126. ClientBufferDesc->MsvBuffer = I_NtLmAllocate( TotalSize );
  127. if ( ClientBufferDesc->MsvBuffer == NULL ) {
  128. return STATUS_NO_MEMORY;
  129. }
  130. //
  131. // Allocate the client's buffer
  132. //
  133. ASSERT( ClientBufferDesc->UserBuffer == NULL );
  134. if ((ClientBufferDesc->ClientRequest == (PLSA_CLIENT_REQUEST) (-1)))
  135. {
  136. ClientBufferDesc->UserBuffer = (*(Lsa.AllocateLsaHeap))(TotalSize);
  137. }
  138. else
  139. {
  140. Status = (*Lsa.AllocateClientBuffer)(
  141. ClientBufferDesc->ClientRequest,
  142. TotalSize,
  143. (PVOID *)&ClientBufferDesc->UserBuffer );
  144. }
  145. if ((ClientBufferDesc->ClientRequest == (PLSA_CLIENT_REQUEST) (-1)))
  146. {
  147. if (ClientBufferDesc->UserBuffer == NULL)
  148. {
  149. NlpFreeClientBuffer( ClientBufferDesc );
  150. return STATUS_NO_MEMORY;
  151. }
  152. }
  153. else
  154. {
  155. if ( !NT_SUCCESS( Status ) ) {
  156. ClientBufferDesc->UserBuffer = NULL;
  157. NlpFreeClientBuffer( ClientBufferDesc );
  158. return Status;
  159. }
  160. }
  161. //
  162. // Return
  163. //
  164. ClientBufferDesc->StringOffset = FixedSize;
  165. ClientBufferDesc->TotalSize = TotalSize;
  166. return STATUS_SUCCESS;
  167. }
  168. NTSTATUS
  169. NlpFlushClientBuffer(
  170. IN OUT PCLIENT_BUFFER_DESC ClientBufferDesc,
  171. OUT PVOID* UserBuffer
  172. )
  173. /*++
  174. Routine Description:
  175. Copy the Mirror Buffer into the Client's address space.
  176. Parameters:
  177. ClientBufferDesc - Descriptor of a buffer allocated in the client's
  178. address space.
  179. UserBuffer - If successful, returns a pointer to the user's buffer.
  180. (The caller is now resposible for deallocating the buffer.)
  181. Return Values:
  182. Status of the operation.
  183. --*/
  184. {
  185. NTSTATUS Status = STATUS_SUCCESS;
  186. //
  187. // Copy the data to the client's address space.
  188. //
  189. if ((ClientBufferDesc->ClientRequest == (PLSA_CLIENT_REQUEST) (-1)))
  190. {
  191. RtlCopyMemory(
  192. ClientBufferDesc->UserBuffer,
  193. ClientBufferDesc->MsvBuffer,
  194. ClientBufferDesc->TotalSize);
  195. }
  196. else
  197. {
  198. Status = (*Lsa.CopyToClientBuffer)(
  199. ClientBufferDesc->ClientRequest,
  200. ClientBufferDesc->TotalSize,
  201. ClientBufferDesc->UserBuffer,
  202. ClientBufferDesc->MsvBuffer );
  203. }
  204. if ( !NT_SUCCESS( Status ) ) {
  205. return Status;
  206. }
  207. //
  208. // Mark that we're no longer responsible for the client's buffer.
  209. //
  210. *UserBuffer = (PVOID) ClientBufferDesc->UserBuffer;
  211. ClientBufferDesc->UserBuffer = NULL;
  212. //
  213. // Free the mirror buffer
  214. //
  215. NlpFreeClientBuffer( ClientBufferDesc );
  216. return STATUS_SUCCESS;
  217. }
  218. VOID
  219. NlpFreeClientBuffer(
  220. IN OUT PCLIENT_BUFFER_DESC ClientBufferDesc
  221. )
  222. /*++
  223. Routine Description:
  224. Free any Mirror Buffer or Client buffer.
  225. Parameters:
  226. ClientBufferDesc - Descriptor of a buffer allocated in the client's
  227. address space.
  228. Return Values:
  229. None
  230. --*/
  231. {
  232. //
  233. // Free the mirror buffer.
  234. //
  235. if ( ClientBufferDesc->MsvBuffer != NULL ) {
  236. I_NtLmFree( ClientBufferDesc->MsvBuffer );
  237. ClientBufferDesc->MsvBuffer = NULL;
  238. }
  239. //
  240. // Free the Client's buffer
  241. //
  242. if ((ClientBufferDesc->ClientRequest == (PLSA_CLIENT_REQUEST) (-1)))
  243. {
  244. if ( ClientBufferDesc->UserBuffer != NULL ) {
  245. (*Lsa.FreeLsaHeap)(ClientBufferDesc->UserBuffer);
  246. ClientBufferDesc->UserBuffer = NULL;
  247. }
  248. }
  249. else
  250. {
  251. if ( ClientBufferDesc->UserBuffer != NULL ) {
  252. (VOID) (*Lsa.FreeClientBuffer)( ClientBufferDesc->ClientRequest,
  253. ClientBufferDesc->UserBuffer );
  254. ClientBufferDesc->UserBuffer = NULL;
  255. }
  256. }
  257. }
  258. VOID
  259. NlpPutClientString(
  260. IN OUT PCLIENT_BUFFER_DESC ClientBufferDesc,
  261. IN PUNICODE_STRING OutString,
  262. IN PUNICODE_STRING InString
  263. )
  264. /*++
  265. Routine Description:
  266. This routine copies the InString string to the memory pointed to by
  267. ClientBufferDesc->StringOffset, and fixes the OutString string to point
  268. to that new copy.
  269. Parameters:
  270. ClientBufferDesc - Descriptor of a buffer allocated in the client's
  271. address space.
  272. InString - A pointer to an NT string to be copied
  273. OutString - A pointer to a destination NT string. This string structure
  274. is in the "Mirror" allocated buffer.
  275. Return Status:
  276. STATUS_SUCCESS - Indicates the service completed successfully.
  277. --*/
  278. {
  279. //
  280. // Ensure our caller passed good data.
  281. //
  282. ASSERT( OutString != NULL );
  283. ASSERT( InString != NULL );
  284. ASSERT( COUNT_IS_ALIGNED( ClientBufferDesc->StringOffset, sizeof(WCHAR)) );
  285. ASSERT( (LPBYTE)OutString >= ClientBufferDesc->MsvBuffer );
  286. ASSERT( (LPBYTE)OutString <
  287. ClientBufferDesc->MsvBuffer + ClientBufferDesc->TotalSize - sizeof(UNICODE_STRING) );
  288. ASSERT( ClientBufferDesc->StringOffset + InString->Length + sizeof(WCHAR) <=
  289. ClientBufferDesc->TotalSize );
  290. #ifdef notdef
  291. KdPrint(("NlpPutClientString: %ld %Z\n", InString->Length, InString ));
  292. KdPrint((" Orig: UserBuffer: %lx Offset: 0x%lx TotalSize: 0x%lx\n",
  293. ClientBufferDesc->UserBuffer,
  294. ClientBufferDesc->StringOffset,
  295. ClientBufferDesc->TotalSize ));
  296. #endif
  297. //
  298. // Build a string structure and copy the text to the Mirror buffer.
  299. //
  300. if ( InString->Length > 0 ) {
  301. //
  302. // Copy the string (Add a zero character)
  303. //
  304. RtlCopyMemory(
  305. ClientBufferDesc->MsvBuffer + ClientBufferDesc->StringOffset,
  306. InString->Buffer,
  307. InString->Length );
  308. // Do one byte at a time since some callers don't pass in an even
  309. // InString->Length
  310. *(ClientBufferDesc->MsvBuffer + ClientBufferDesc->StringOffset +
  311. InString->Length) = '\0';
  312. *(ClientBufferDesc->MsvBuffer + ClientBufferDesc->StringOffset +
  313. InString->Length+1) = '\0';
  314. //
  315. // Build the string structure to point to the data in the client's
  316. // address space.
  317. //
  318. OutString->Buffer = (PWSTR)(ClientBufferDesc->UserBuffer +
  319. ClientBufferDesc->StringOffset);
  320. OutString->Length = InString->Length;
  321. OutString->MaximumLength = OutString->Length + sizeof(WCHAR);
  322. //
  323. // Adjust the offset to past the newly copied string.
  324. //
  325. ClientBufferDesc->StringOffset += OutString->MaximumLength;
  326. } else {
  327. RtlInitUnicodeString(OutString, NULL);
  328. }
  329. #ifdef notdef
  330. KdPrint((" New: Offset: 0x%lx StringStart: %lx\n",
  331. ClientBufferDesc->StringOffset,
  332. OutString->Buffer ));
  333. #endif
  334. return;
  335. }
  336. VOID
  337. NlpMakeRelativeString(
  338. IN PUCHAR BaseAddress,
  339. IN OUT PUNICODE_STRING String
  340. )
  341. /*++
  342. Routine Description:
  343. This routine converts the buffer address in the specified string to
  344. be a byte offset from BaseAddress.
  345. Parameters:
  346. BaseAddress - A pointer to make the destination address relative to.
  347. String - A pointer to a NT string to make relative.
  348. Return Values:
  349. None.
  350. --*/
  351. {
  352. ASSERT( BaseAddress != NULL );
  353. ASSERT( String != NULL );
  354. ASSERT( sizeof(ULONG_PTR) == sizeof(String->Buffer) );
  355. if ( String->Buffer != NULL ) {
  356. *((PULONG_PTR)(&String->Buffer)) =
  357. (ULONG_PTR)((PUCHAR)String->Buffer - (PUCHAR)BaseAddress);
  358. }
  359. return;
  360. }
  361. VOID
  362. NlpRelativeToAbsolute(
  363. IN PVOID BaseAddress,
  364. IN OUT PULONG_PTR RelativeValue
  365. )
  366. /*++
  367. Routine Description:
  368. This routine converts the byte offset from BaseAddress to be an
  369. absolute address.
  370. Parameters:
  371. BaseAddress - A pointer the destination address is relative to.
  372. RelativeValue - A pointer to a relative value to make absolute.
  373. Return Values:
  374. None.
  375. --*/
  376. {
  377. ASSERT( BaseAddress != NULL );
  378. ASSERT( RelativeValue != NULL );
  379. if ( *((PUCHAR *)RelativeValue) != NULL ) {
  380. *RelativeValue = (ULONG_PTR)((PUCHAR)BaseAddress + (*RelativeValue));
  381. }
  382. return;
  383. }
  384. ACTIVE_LOGON*
  385. NlpFindActiveLogon(
  386. IN LUID* pLogonId
  387. )
  388. /*++
  389. Routine Description:
  390. This routine finds the specified Logon Id in the ActiveLogon table.
  391. It returns a boolean indicating whether the Logon Id exists in the
  392. ActiveLogon Table. If so, this routine also returns a pointer to a
  393. pointer to the appropriate entry in the table. If not, this routine
  394. returns a pointer to where such an entry would be inserted in the table.
  395. This routine must be called with the NlpActiveLogonLock locked.
  396. Parameters:
  397. pLogonId - The LogonId of the logon to find in the table.
  398. Return Values:
  399. ACTIVE_LOGON, NULL if not found
  400. --*/
  401. {
  402. LIST_ENTRY* pScan = NULL;
  403. ACTIVE_LOGON* pActiveLogon = NULL;
  404. //
  405. // Loop through the table looking for this particular LogonId.
  406. //
  407. for ( pScan = NlpActiveLogonListAnchor.Flink;
  408. pScan != &NlpActiveLogonListAnchor;
  409. pScan = pScan->Flink )
  410. {
  411. pActiveLogon = CONTAINING_RECORD(pScan, ACTIVE_LOGON, ListEntry);
  412. if ( RtlCompareMemory(&pActiveLogon->LogonId, pLogonId, sizeof(LUID)) == sizeof(LUID) )
  413. {
  414. return pActiveLogon;
  415. }
  416. }
  417. return NULL;
  418. }
  419. ULONG
  420. NlpCountActiveLogon(
  421. IN PUNICODE_STRING pLogonDomainName,
  422. IN PUNICODE_STRING pUserName
  423. )
  424. /*++
  425. Routine Description:
  426. This routine counts the number of time a particular user is logged on
  427. in the Active Logon Table.
  428. Parameters:
  429. pLogonDomainName - Domain in which this user account is defined.
  430. pUserName - The user name to count the active logons for.
  431. Return Values:
  432. The count of active logons for the specified user.
  433. --*/
  434. {
  435. LIST_ENTRY* pScan = NULL;
  436. ACTIVE_LOGON* pActiveLogon = NULL;
  437. ULONG LogonCount = 0;
  438. //
  439. // Loop through the table looking for this particular LogonId.
  440. //
  441. NlpLockActiveLogonsRead();
  442. for ( pScan = NlpActiveLogonListAnchor.Flink;
  443. pScan != &NlpActiveLogonListAnchor;
  444. pScan = pScan->Flink )
  445. {
  446. pActiveLogon = CONTAINING_RECORD(pScan, ACTIVE_LOGON, ListEntry);
  447. if (RtlEqualUnicodeString(pUserName, &pActiveLogon->UserName, (BOOLEAN) TRUE) &&
  448. RtlEqualDomainName(pLogonDomainName,&pActiveLogon->LogonDomainName))
  449. {
  450. LogonCount ++;
  451. }
  452. }
  453. NlpUnlockActiveLogons();
  454. return LogonCount;
  455. }
  456. NTSTATUS
  457. NlpAllocateInteractiveProfile (
  458. IN PLSA_CLIENT_REQUEST ClientRequest,
  459. OUT PMSV1_0_INTERACTIVE_PROFILE *ProfileBuffer,
  460. OUT PULONG ProfileBufferSize,
  461. IN PNETLOGON_VALIDATION_SAM_INFO4 NlpUser
  462. )
  463. /*++
  464. Routine Description:
  465. This allocates and fills in the clients interactive profile.
  466. Arguments:
  467. ClientRequest - Is a pointer to an opaque data structure
  468. representing the client's request.
  469. ProfileBuffer - Is used to return the address of the profile
  470. buffer in the client process. This routine is
  471. responsible for allocating and returning the profile buffer
  472. within the client process. However, if the caller subsequently
  473. encounters an error which prevents a successful logon, then
  474. then it will take care of deallocating the buffer. This
  475. buffer is allocated with the AllocateClientBuffer() service.
  476. ProfileBufferSize - Receives the Size (in bytes) of the
  477. returned profile buffer.
  478. NlpUser - Contains the validation information which is
  479. to be copied in the ProfileBuffer.
  480. Return Value:
  481. STATUS_SUCCESS - Indicates the service completed successfully.
  482. STATUS_QUOTA_EXCEEDED - This error indicates that the logon
  483. could not be completed because the client does not have
  484. sufficient quota to allocate the return buffer.
  485. --*/
  486. {
  487. NTSTATUS Status;
  488. CLIENT_BUFFER_DESC ClientBufferDesc;
  489. PMSV1_0_INTERACTIVE_PROFILE LocalProfileBuffer;
  490. #if _WIN64
  491. if( ClientRequest != (PLSA_CLIENT_REQUEST)( -1 ) )
  492. {
  493. SECPKG_CALL_INFO CallInfo;
  494. //
  495. // if the call originated outproc, need to check if wow64.
  496. //
  497. if(!LsaFunctions->GetCallInfo(&CallInfo))
  498. {
  499. Status = STATUS_INTERNAL_ERROR;
  500. goto Cleanup;
  501. }
  502. if (CallInfo.Attributes & SECPKG_CALL_WOWCLIENT)
  503. {
  504. return MsvAllocateInteractiveWOWProfile (
  505. ClientRequest,
  506. ProfileBuffer,
  507. ProfileBufferSize,
  508. NlpUser
  509. );
  510. }
  511. }
  512. #endif // _WIN64
  513. //
  514. // Alocate the profile buffer to return to the client
  515. //
  516. NlpInitClientBuffer( &ClientBufferDesc, ClientRequest );
  517. *ProfileBuffer = NULL;
  518. *ProfileBufferSize = sizeof(MSV1_0_INTERACTIVE_PROFILE) +
  519. NlpUser->LogonScript.Length + sizeof(WCHAR) +
  520. NlpUser->HomeDirectory.Length + sizeof(WCHAR) +
  521. NlpUser->HomeDirectoryDrive.Length + sizeof(WCHAR) +
  522. NlpUser->FullName.Length + sizeof(WCHAR) +
  523. NlpUser->ProfilePath.Length + sizeof(WCHAR) +
  524. NlpUser->LogonServer.Length + sizeof(WCHAR);
  525. Status = NlpAllocateClientBuffer( &ClientBufferDesc,
  526. sizeof(MSV1_0_INTERACTIVE_PROFILE),
  527. *ProfileBufferSize );
  528. if ( !NT_SUCCESS( Status ) ) {
  529. goto Cleanup;
  530. }
  531. LocalProfileBuffer = (PMSV1_0_INTERACTIVE_PROFILE) ClientBufferDesc.MsvBuffer;
  532. //
  533. // Copy the scalar fields into the profile buffer.
  534. //
  535. LocalProfileBuffer->MessageType = MsV1_0InteractiveProfile;
  536. LocalProfileBuffer->LogonCount = NlpUser->LogonCount;
  537. LocalProfileBuffer->BadPasswordCount= NlpUser->BadPasswordCount;
  538. OLD_TO_NEW_LARGE_INTEGER( NlpUser->LogonTime,
  539. LocalProfileBuffer->LogonTime );
  540. OLD_TO_NEW_LARGE_INTEGER( NlpUser->LogoffTime,
  541. LocalProfileBuffer->LogoffTime );
  542. OLD_TO_NEW_LARGE_INTEGER( NlpUser->KickOffTime,
  543. LocalProfileBuffer->KickOffTime );
  544. OLD_TO_NEW_LARGE_INTEGER( NlpUser->PasswordLastSet,
  545. LocalProfileBuffer->PasswordLastSet );
  546. OLD_TO_NEW_LARGE_INTEGER( NlpUser->PasswordCanChange,
  547. LocalProfileBuffer->PasswordCanChange );
  548. OLD_TO_NEW_LARGE_INTEGER( NlpUser->PasswordMustChange,
  549. LocalProfileBuffer->PasswordMustChange );
  550. LocalProfileBuffer->UserFlags = NlpUser->UserFlags;
  551. //
  552. // Copy the Unicode strings into the profile buffer.
  553. //
  554. NlpPutClientString( &ClientBufferDesc,
  555. &LocalProfileBuffer->LogonScript,
  556. &NlpUser->LogonScript );
  557. NlpPutClientString( &ClientBufferDesc,
  558. &LocalProfileBuffer->HomeDirectory,
  559. &NlpUser->HomeDirectory );
  560. NlpPutClientString( &ClientBufferDesc,
  561. &LocalProfileBuffer->HomeDirectoryDrive,
  562. &NlpUser->HomeDirectoryDrive );
  563. NlpPutClientString( &ClientBufferDesc,
  564. &LocalProfileBuffer->FullName,
  565. &NlpUser->FullName );
  566. NlpPutClientString( &ClientBufferDesc,
  567. &LocalProfileBuffer->ProfilePath,
  568. &NlpUser->ProfilePath );
  569. NlpPutClientString( &ClientBufferDesc,
  570. &LocalProfileBuffer->LogonServer,
  571. &NlpUser->LogonServer );
  572. //
  573. // Flush the buffer to the client's address space.
  574. //
  575. Status = NlpFlushClientBuffer( &ClientBufferDesc,
  576. (PVOID *) ProfileBuffer );
  577. Cleanup:
  578. //
  579. // If the copy wasn't successful,
  580. // cleanup resources we would have returned to the caller.
  581. //
  582. if ( !NT_SUCCESS(Status) ) {
  583. NlpFreeClientBuffer( &ClientBufferDesc );
  584. }
  585. return Status;
  586. }
  587. NTSTATUS
  588. NlpAllocateNetworkProfile (
  589. IN PLSA_CLIENT_REQUEST ClientRequest,
  590. OUT PMSV1_0_LM20_LOGON_PROFILE *ProfileBuffer,
  591. OUT PULONG ProfileBufferSize,
  592. IN PNETLOGON_VALIDATION_SAM_INFO4 NlpUser,
  593. IN ULONG ParameterControl
  594. )
  595. /*++
  596. Routine Description:
  597. This allocates and fills in the clients network profile.
  598. Arguments:
  599. ClientRequest - Is a pointer to an opaque data structure
  600. representing the client's request.
  601. ProfileBuffer - Is used to return the address of the profile
  602. buffer in the client process. This routine is
  603. responsible for allocating and returning the profile buffer
  604. within the client process. However, if the caller subsequently
  605. encounters an error which prevents a successful logon, then
  606. then it will take care of deallocating the buffer. This
  607. buffer is allocated with the AllocateClientBuffer() service.
  608. ProfileBufferSize - Receives the Size (in bytes) of the
  609. returned profile buffer.
  610. NlpUser - Contains the validation information which is
  611. to be copied in the ProfileBuffer. Will be NULL to indicate a
  612. NULL session.
  613. Return Value:
  614. STATUS_SUCCESS - Indicates the service completed successfully.
  615. STATUS_QUOTA_EXCEEDED - This error indicates that the logon
  616. could not be completed because the client does not have
  617. sufficient quota to allocate the return buffer.
  618. --*/
  619. {
  620. NTSTATUS Status;
  621. NTSTATUS SubAuthStatus = STATUS_SUCCESS;
  622. CLIENT_BUFFER_DESC ClientBufferDesc;
  623. PMSV1_0_LM20_LOGON_PROFILE LocalProfile;
  624. #if _WIN64
  625. if( ClientRequest != (PLSA_CLIENT_REQUEST)( -1 ) )
  626. {
  627. SECPKG_CALL_INFO CallInfo;
  628. //
  629. // if the call originated outproc, need to check if wow64.
  630. //
  631. if(!LsaFunctions->GetCallInfo(&CallInfo))
  632. {
  633. Status = STATUS_INTERNAL_ERROR;
  634. goto Cleanup;
  635. }
  636. if (CallInfo.Attributes & SECPKG_CALL_WOWCLIENT)
  637. {
  638. return MsvAllocateNetworkWOWProfile (
  639. ClientRequest,
  640. ProfileBuffer,
  641. ProfileBufferSize,
  642. NlpUser,
  643. ParameterControl
  644. );
  645. }
  646. }
  647. #endif // _WIN64
  648. //
  649. // Alocate the profile buffer to return to the client
  650. //
  651. NlpInitClientBuffer( &ClientBufferDesc, ClientRequest );
  652. *ProfileBuffer = NULL;
  653. *ProfileBufferSize = sizeof(MSV1_0_LM20_LOGON_PROFILE);
  654. if ( NlpUser != NULL ) {
  655. *ProfileBufferSize += NlpUser->LogonDomainName.Length + sizeof(WCHAR) +
  656. NlpUser->LogonServer.Length + sizeof(WCHAR) +
  657. NlpUser->HomeDirectoryDrive.Length + sizeof(WCHAR);
  658. }
  659. Status = NlpAllocateClientBuffer( &ClientBufferDesc,
  660. sizeof(MSV1_0_LM20_LOGON_PROFILE),
  661. *ProfileBufferSize );
  662. if ( !NT_SUCCESS( Status ) ) {
  663. goto Cleanup;
  664. }
  665. LocalProfile = (PMSV1_0_LM20_LOGON_PROFILE) ClientBufferDesc.MsvBuffer;
  666. LocalProfile->MessageType = MsV1_0Lm20LogonProfile;
  667. //
  668. // For a NULL session, return a constant profile buffer
  669. //
  670. if ( NlpUser == NULL ) {
  671. LocalProfile->KickOffTime.HighPart = 0x7FFFFFFF;
  672. LocalProfile->KickOffTime.LowPart = 0xFFFFFFFF;
  673. LocalProfile->LogoffTime.HighPart = 0x7FFFFFFF;
  674. LocalProfile->LogoffTime.LowPart = 0xFFFFFFFF;
  675. LocalProfile->UserFlags = 0;
  676. RtlZeroMemory( LocalProfile->UserSessionKey,
  677. sizeof(LocalProfile->UserSessionKey));
  678. RtlZeroMemory( LocalProfile->LanmanSessionKey,
  679. sizeof(LocalProfile->LanmanSessionKey));
  680. RtlInitUnicodeString( &LocalProfile->LogonDomainName, NULL );
  681. RtlInitUnicodeString( &LocalProfile->LogonServer, NULL );
  682. RtlInitUnicodeString( &LocalProfile->UserParameters, NULL );
  683. //
  684. // For non-null sessions,
  685. // fill in the profile buffer.
  686. //
  687. } else {
  688. //
  689. // Copy the individual scalar fields into the profile buffer.
  690. //
  691. if ((ParameterControl & MSV1_0_RETURN_PASSWORD_EXPIRY) != 0) {
  692. OLD_TO_NEW_LARGE_INTEGER( NlpUser->PasswordMustChange,
  693. LocalProfile->LogoffTime);
  694. } else {
  695. OLD_TO_NEW_LARGE_INTEGER( NlpUser->LogoffTime,
  696. LocalProfile->LogoffTime);
  697. }
  698. OLD_TO_NEW_LARGE_INTEGER( NlpUser->KickOffTime,
  699. LocalProfile->KickOffTime);
  700. LocalProfile->UserFlags = NlpUser->UserFlags;
  701. RtlCopyMemory( LocalProfile->UserSessionKey,
  702. &NlpUser->UserSessionKey,
  703. sizeof(LocalProfile->UserSessionKey) );
  704. ASSERT( SAMINFO_LM_SESSION_KEY_SIZE ==
  705. sizeof(LocalProfile->LanmanSessionKey) );
  706. RtlCopyMemory(
  707. LocalProfile->LanmanSessionKey,
  708. &NlpUser->ExpansionRoom[SAMINFO_LM_SESSION_KEY],
  709. SAMINFO_LM_SESSION_KEY_SIZE );
  710. // We need to extract the true status sent back for subauth users,
  711. // but not by a sub auth package
  712. SubAuthStatus = NlpUser->ExpansionRoom[SAMINFO_SUBAUTH_STATUS];
  713. //
  714. // Copy the Unicode strings into the profile buffer.
  715. //
  716. NlpPutClientString( &ClientBufferDesc,
  717. &LocalProfile->LogonDomainName,
  718. &NlpUser->LogonDomainName );
  719. NlpPutClientString( &ClientBufferDesc,
  720. &LocalProfile->LogonServer,
  721. &NlpUser->LogonServer );
  722. //
  723. // Kludge: Pass back UserParameters in HomeDirectoryDrive since we
  724. // can't change the NETLOGON_VALIDATION_SAM_INFO structure between
  725. // releases NT 1.0 and NT 1.0A. HomeDirectoryDrive was NULL for release 1.0A
  726. // so we'll use that field.
  727. //
  728. NlpPutClientString( &ClientBufferDesc,
  729. &LocalProfile->UserParameters,
  730. &NlpUser->HomeDirectoryDrive );
  731. }
  732. //
  733. // Flush the buffer to the client's address space.
  734. //
  735. Status = NlpFlushClientBuffer( &ClientBufferDesc,
  736. ProfileBuffer );
  737. Cleanup:
  738. //
  739. // If the copy wasn't successful,
  740. // cleanup resources we would have returned to the caller.
  741. //
  742. if ( !NT_SUCCESS(Status) ) {
  743. NlpFreeClientBuffer( &ClientBufferDesc );
  744. }
  745. // Save the status for subauth logons
  746. if (NT_SUCCESS(Status) && !NT_SUCCESS(SubAuthStatus))
  747. {
  748. Status = SubAuthStatus;
  749. }
  750. return Status;
  751. }
  752. PSID
  753. NlpMakeDomainRelativeSid(
  754. IN PSID DomainId,
  755. IN ULONG RelativeId
  756. )
  757. /*++
  758. Routine Description:
  759. Given a domain Id and a relative ID create the corresponding SID allocated
  760. from the LSA heap.
  761. Arguments:
  762. DomainId - The template SID to use.
  763. RelativeId - The relative Id to append to the DomainId.
  764. Return Value:
  765. Sid - Returns a pointer to a buffer allocated from the LsaHeap
  766. containing the resultant Sid.
  767. --*/
  768. {
  769. UCHAR DomainIdSubAuthorityCount;
  770. ULONG Size;
  771. PSID Sid;
  772. //
  773. // Allocate a Sid which has one more sub-authority than the domain ID.
  774. //
  775. DomainIdSubAuthorityCount = *(RtlSubAuthorityCountSid( DomainId ));
  776. Size = RtlLengthRequiredSid(DomainIdSubAuthorityCount+1);
  777. if ((Sid = (*Lsa.AllocateLsaHeap)( Size )) == NULL ) {
  778. return NULL;
  779. }
  780. //
  781. // Initialize the new SID to have the same inital value as the
  782. // domain ID.
  783. //
  784. if ( !NT_SUCCESS( RtlCopySid( Size, Sid, DomainId ) ) ) {
  785. (*Lsa.FreeLsaHeap)( Sid );
  786. return NULL;
  787. }
  788. //
  789. // Adjust the sub-authority count and
  790. // add the relative Id unique to the newly allocated SID
  791. //
  792. (*(RtlSubAuthorityCountSid( Sid ))) ++;
  793. *RtlSubAuthoritySid( Sid, DomainIdSubAuthorityCount ) = RelativeId;
  794. return Sid;
  795. }
  796. PSID
  797. NlpCopySid(
  798. IN PSID * Sid
  799. )
  800. /*++
  801. Routine Description:
  802. Given a SID allocatees space for a new SID from the LSA heap and copies
  803. the original SID.
  804. Arguments:
  805. Sid - The original SID.
  806. Return Value:
  807. Sid - Returns a pointer to a buffer allocated from the LsaHeap
  808. containing the resultant Sid.
  809. --*/
  810. {
  811. PSID NewSid;
  812. ULONG Size;
  813. Size = RtlLengthSid( Sid );
  814. if ((NewSid = (*Lsa.AllocateLsaHeap)( Size )) == NULL ) {
  815. return NULL;
  816. }
  817. if ( !NT_SUCCESS( RtlCopySid( Size, NewSid, Sid ) ) ) {
  818. (*Lsa.FreeLsaHeap)( NewSid );
  819. return NULL;
  820. }
  821. return NewSid;
  822. }
  823. //+-------------------------------------------------------------------------
  824. //
  825. // Function: NlpMakeTokenInformationV2
  826. //
  827. // Synopsis: This routine makes copies of all the pertinent
  828. // information from the UserInfo and generates a
  829. // LSA_TOKEN_INFORMATION_V2 data structure.
  830. //
  831. // Effects:
  832. //
  833. // Arguments:
  834. //
  835. // UserInfo - Contains the validation information which is
  836. // to be copied into the TokenInformation.
  837. //
  838. // TokenInformation - Returns a pointer to a properly Version 1 token
  839. // information structures. The structure and individual fields are
  840. // allocated properly as described in ntlsa.h.
  841. //
  842. // Requires:
  843. //
  844. // Returns: STATUS_SUCCESS - Indicates the service completed successfully.
  845. //
  846. // STATUS_INSUFFICIENT_RESOURCES - This error indicates that
  847. // the logon could not be completed because the client
  848. // does not have sufficient quota to allocate the return
  849. // buffer.
  850. //
  851. // Notes: stolen back from from kerberos\client2\krbtoken.cxx.c:KerbMakeTokenInformationV1
  852. //
  853. //
  854. //--------------------------------------------------------------------------
  855. NTSTATUS
  856. NlpMakeTokenInformationV2(
  857. IN PNETLOGON_VALIDATION_SAM_INFO4 ValidationInfo,
  858. OUT PLSA_TOKEN_INFORMATION_V2 *TokenInformation
  859. )
  860. {
  861. PNETLOGON_VALIDATION_SAM_INFO3 UserInfo = (PNETLOGON_VALIDATION_SAM_INFO3) ValidationInfo;
  862. NTSTATUS Status;
  863. PLSA_TOKEN_INFORMATION_V2 V2 = NULL;
  864. ULONG Size, i;
  865. DWORD NumGroups = 0;
  866. PBYTE CurrentSid = NULL;
  867. ULONG SidLength = 0;
  868. //
  869. // Allocate the structure itself
  870. //
  871. Size = (ULONG)sizeof(LSA_TOKEN_INFORMATION_V2);
  872. //
  873. // Allocate an array to hold the groups
  874. //
  875. Size += sizeof(TOKEN_GROUPS);
  876. // Add room for groups passed as RIDS
  877. NumGroups = UserInfo->GroupCount;
  878. if(UserInfo->GroupCount)
  879. {
  880. Size += UserInfo->GroupCount * (RtlLengthSid(UserInfo->LogonDomainId) + sizeof(ULONG));
  881. }
  882. //
  883. // If there are extra SIDs, add space for them
  884. //
  885. if (UserInfo->UserFlags & LOGON_EXTRA_SIDS) {
  886. ULONG i = 0;
  887. NumGroups += UserInfo->SidCount;
  888. // Add room for the sid's themselves
  889. for(i=0; i < UserInfo->SidCount; i++)
  890. {
  891. Size += RtlLengthSid(UserInfo->ExtraSids[i].Sid);
  892. }
  893. }
  894. //
  895. // If there are resource groups, add space for them
  896. //
  897. if (UserInfo->UserFlags & LOGON_RESOURCE_GROUPS) {
  898. NumGroups += UserInfo->ResourceGroupCount;
  899. if ((UserInfo->ResourceGroupCount != 0) &&
  900. ((UserInfo->ResourceGroupIds == NULL) ||
  901. (UserInfo->ResourceGroupDomainSid == NULL)))
  902. {
  903. Status = STATUS_INVALID_PARAMETER;
  904. goto Cleanup;
  905. }
  906. // Allocate space for the sids
  907. if(UserInfo->ResourceGroupCount)
  908. {
  909. Size += UserInfo->ResourceGroupCount * (RtlLengthSid(UserInfo->ResourceGroupDomainSid) + sizeof(ULONG));
  910. }
  911. }
  912. if( UserInfo->UserId )
  913. {
  914. // Size of the user sid and the primary group sid.
  915. Size += 2*(RtlLengthSid(UserInfo->LogonDomainId) + sizeof(ULONG));
  916. }
  917. else
  918. {
  919. if ( UserInfo->SidCount <= 0 ) {
  920. Status = STATUS_INSUFFICIENT_LOGON_INFO;
  921. goto Cleanup;
  922. }
  923. // Size of the primary group sid.
  924. Size += (RtlLengthSid(UserInfo->LogonDomainId) + sizeof(ULONG));
  925. }
  926. Size += (NumGroups - ANYSIZE_ARRAY)*sizeof(SID_AND_ATTRIBUTES);
  927. V2 = (PLSA_TOKEN_INFORMATION_V2) (*Lsa.AllocateLsaHeap)( Size );
  928. if ( V2 == NULL ) {
  929. return STATUS_INSUFFICIENT_RESOURCES;
  930. }
  931. RtlZeroMemory(
  932. V2,
  933. Size
  934. );
  935. V2->Groups = (PTOKEN_GROUPS)(V2+1);
  936. V2->Groups->GroupCount = 0;
  937. CurrentSid = (PBYTE)&V2->Groups->Groups[NumGroups];
  938. OLD_TO_NEW_LARGE_INTEGER( UserInfo->KickOffTime, V2->ExpirationTime );
  939. //
  940. // If the UserId is non-zero, then it contians the users RID.
  941. //
  942. if ( UserInfo->UserId ) {
  943. V2->User.User.Sid = (PSID)CurrentSid;
  944. CurrentSid += NlpCopyDomainRelativeSid((PSID)CurrentSid, UserInfo->LogonDomainId, UserInfo->UserId);
  945. }
  946. //
  947. // Make a copy of the primary group (a required field).
  948. //
  949. V2->PrimaryGroup.PrimaryGroup = (PSID)CurrentSid;
  950. CurrentSid += NlpCopyDomainRelativeSid((PSID)CurrentSid, UserInfo->LogonDomainId, UserInfo->PrimaryGroupId );
  951. //
  952. // Copy over all the groups passed as RIDs
  953. //
  954. for ( i=0; i < UserInfo->GroupCount; i++ ) {
  955. V2->Groups->Groups[V2->Groups->GroupCount].Attributes = UserInfo->GroupIds[i].Attributes;
  956. V2->Groups->Groups[V2->Groups->GroupCount].Sid = (PSID)CurrentSid;
  957. CurrentSid += NlpCopyDomainRelativeSid((PSID)CurrentSid, UserInfo->LogonDomainId, UserInfo->GroupIds[i].RelativeId);
  958. V2->Groups->GroupCount++;
  959. }
  960. //
  961. // Add in the extra SIDs
  962. //
  963. if (UserInfo->UserFlags & LOGON_EXTRA_SIDS) {
  964. ULONG index = 0;
  965. //
  966. // If the user SID wasn't passed as a RID, it is the first
  967. // SID.
  968. //
  969. if ( !V2->User.User.Sid ) {
  970. V2->User.User.Sid = (PSID)CurrentSid;
  971. SidLength = RtlLengthSid(UserInfo->ExtraSids[index].Sid);
  972. RtlCopySid(SidLength, (PSID)CurrentSid, UserInfo->ExtraSids[index].Sid);
  973. CurrentSid += SidLength;
  974. index++;
  975. }
  976. //
  977. // Copy over all additional SIDs as groups.
  978. //
  979. for ( ; index < UserInfo->SidCount; index++ ) {
  980. V2->Groups->Groups[V2->Groups->GroupCount].Attributes =
  981. UserInfo->ExtraSids[index].Attributes;
  982. V2->Groups->Groups[V2->Groups->GroupCount].Sid= (PSID)CurrentSid;
  983. SidLength = RtlLengthSid(UserInfo->ExtraSids[index].Sid);
  984. RtlCopySid(SidLength, (PSID)CurrentSid, UserInfo->ExtraSids[index].Sid);
  985. CurrentSid += SidLength;
  986. V2->Groups->GroupCount++;
  987. }
  988. }
  989. //
  990. // Check to see if any resouce groups exist
  991. //
  992. if (UserInfo->UserFlags & LOGON_RESOURCE_GROUPS) {
  993. for ( i=0; i < UserInfo->ResourceGroupCount; i++ ) {
  994. V2->Groups->Groups[V2->Groups->GroupCount].Attributes = UserInfo->ResourceGroupIds[i].Attributes;
  995. V2->Groups->Groups[V2->Groups->GroupCount].Sid= (PSID)CurrentSid;
  996. CurrentSid += NlpCopyDomainRelativeSid((PSID)CurrentSid, UserInfo->ResourceGroupDomainSid, UserInfo->ResourceGroupIds[i].RelativeId);
  997. V2->Groups->GroupCount++;
  998. }
  999. }
  1000. ASSERT( ((PBYTE)V2 + Size) == CurrentSid );
  1001. if (!V2->User.User.Sid) {
  1002. Status = STATUS_INSUFFICIENT_LOGON_INFO;
  1003. goto Cleanup;
  1004. }
  1005. //
  1006. // There are no default privileges supplied.
  1007. // We don't have an explicit owner SID.
  1008. // There is no default DACL.
  1009. //
  1010. V2->Privileges = NULL;
  1011. V2->Owner.Owner = NULL;
  1012. V2->DefaultDacl.DefaultDacl = NULL;
  1013. //
  1014. // Return the Validation Information to the caller.
  1015. //
  1016. *TokenInformation = V2;
  1017. return STATUS_SUCCESS;
  1018. //
  1019. // Deallocate any memory we've allocated
  1020. //
  1021. Cleanup:
  1022. (*Lsa.FreeLsaHeap)( V2 );
  1023. return Status;
  1024. }
  1025. VOID
  1026. NlpPutOwfsInPrimaryCredential(
  1027. IN PUNICODE_STRING pPassword,
  1028. IN BOOLEAN bIsOwfPassword,
  1029. OUT PMSV1_0_PRIMARY_CREDENTIAL pCredential
  1030. )
  1031. /*++
  1032. Routine Description:
  1033. This routine puts the OWFs for the specified clear password into
  1034. the passed in Credential structure.
  1035. Arguments:
  1036. pPassword - User's password.
  1037. bIsOwfPassword - whether CleartextPassword is actually an OWF password
  1038. pCredential - A pointer to the credential to update.
  1039. Return Value:
  1040. STATUS_SUCCESS - Indicates the service completed successfully.
  1041. STATUS_QUOTA_EXCEEDED - This error indicates that the logon
  1042. could not be completed because the client does not have
  1043. sufficient quota to allocate the return buffer.
  1044. --*/
  1045. {
  1046. NTSTATUS Status;
  1047. //
  1048. // Compute the Ansi version to the Cleartext password.
  1049. //
  1050. // The Ansi version of the Cleartext password is at most 14 bytes long,
  1051. // exists in a trailing zero filled 15 byte buffer,
  1052. // is uppercased.
  1053. //
  1054. pCredential->LmPasswordPresent = FALSE;
  1055. pCredential->NtPasswordPresent = FALSE;
  1056. pCredential->ShaPasswordPresent = FALSE;
  1057. if (!bIsOwfPassword)
  1058. {
  1059. if ( pPassword->Length <= (LM20_PWLEN * sizeof(WCHAR)) )
  1060. {
  1061. CHAR LmPassword[LM20_PWLEN+1];
  1062. STRING AnsiCleartextPassword;
  1063. AnsiCleartextPassword.Buffer = LmPassword;
  1064. AnsiCleartextPassword.Length = sizeof(LmPassword);
  1065. AnsiCleartextPassword.MaximumLength = AnsiCleartextPassword.Length;
  1066. Status = RtlUpcaseUnicodeStringToOemString(
  1067. &AnsiCleartextPassword,
  1068. pPassword,
  1069. (BOOLEAN) FALSE );
  1070. if ( NT_SUCCESS( Status ) )
  1071. {
  1072. //
  1073. // Save the OWF encrypted versions of the passwords.
  1074. //
  1075. Status = RtlCalculateLmOwfPassword( LmPassword,
  1076. &pCredential->LmOwfPassword );
  1077. ASSERT( NT_SUCCESS(Status) );
  1078. pCredential->LmPasswordPresent = TRUE;
  1079. }
  1080. //
  1081. // Don't leave passwords around in the pagefile
  1082. //
  1083. RtlZeroMemory( LmPassword, sizeof(LmPassword) );
  1084. }
  1085. Status = RtlCalculateNtOwfPassword( pPassword,
  1086. &pCredential->NtOwfPassword );
  1087. ASSERT( NT_SUCCESS(Status) );
  1088. pCredential->NtPasswordPresent = TRUE;
  1089. Status = RtlCalculateShaOwfPassword( pPassword,
  1090. &pCredential->ShaOwfPassword );
  1091. ASSERT( NT_SUCCESS(Status) );
  1092. pCredential->ShaPasswordPresent = TRUE;
  1093. }
  1094. else
  1095. {
  1096. SspPrint((SSP_CRED, "NlpPutOwfsInPrimaryCredential handling MSV1_0_SUPPLEMENTAL_CREDENTIAL\n"));
  1097. if (pPassword->Length >= sizeof(MSV1_0_SUPPLEMENTAL_CREDENTIAL))
  1098. {
  1099. MSV1_0_SUPPLEMENTAL_CREDENTIAL SupCred;
  1100. RtlCopyMemory(&SupCred, pPassword->Buffer, sizeof(SupCred)); // make a local copy so that data is aligned properly
  1101. if (SupCred.Version != MSV1_0_CRED_VERSION)
  1102. {
  1103. SspPrint((SSP_CRITICAL, "NlpPutOwfsInPrimaryCredential failed to accept MSV1_0_SUPPLEMENTAL_CREDENTIAL, version %#x\n", SupCred.Version));
  1104. return;
  1105. }
  1106. if (SupCred.Flags & MSV1_0_CRED_NT_PRESENT)
  1107. {
  1108. pCredential->NtPasswordPresent = TRUE;
  1109. RtlCopyMemory(
  1110. &pCredential->NtOwfPassword,
  1111. SupCred.NtPassword,
  1112. MSV1_0_OWF_PASSWORD_LENGTH
  1113. );
  1114. }
  1115. if (SupCred.Flags & MSV1_0_CRED_LM_PRESENT)
  1116. {
  1117. pCredential->LmPasswordPresent = TRUE;
  1118. RtlCopyMemory(
  1119. &pCredential->LmOwfPassword,
  1120. SupCred.LmPassword,
  1121. MSV1_0_OWF_PASSWORD_LENGTH
  1122. );
  1123. }
  1124. }
  1125. else
  1126. {
  1127. SspPrint((SSP_CRITICAL, "NlpPutOwfsInPrimaryCredential failed to accept MSV1_0_SUPPLEMENTAL_CREDENTIAL, length %#x\n", pPassword->Length));
  1128. }
  1129. }
  1130. }
  1131. NTSTATUS
  1132. NlpMakePrimaryCredential(
  1133. IN PUNICODE_STRING LogonDomainName,
  1134. IN PUNICODE_STRING UserName,
  1135. IN PUNICODE_STRING CleartextPassword,
  1136. OUT PMSV1_0_PRIMARY_CREDENTIAL *CredentialBuffer,
  1137. OUT PULONG CredentialSize
  1138. )
  1139. /*++
  1140. Routine Description:
  1141. This routine makes a primary credential for the given user nam and
  1142. password.
  1143. Arguments:
  1144. LogonDomainName - Is a string representing the domain in which the user's
  1145. account is defined.
  1146. UserName - Is a string representing the user's account name. The
  1147. name may be up to 255 characters long. The name is treated case
  1148. insensitive.
  1149. CleartextPassword - Is a string containing the user's cleartext password.
  1150. The password may be up to 255 characters long and contain any
  1151. UNICODE value.
  1152. CredentialBuffer - Returns a pointer to the specified credential allocated
  1153. on the LsaHeap. It is the callers responsibility to deallocate
  1154. this credential.
  1155. CredentialSize - the size of the allocated credential buffer (in bytes).
  1156. Return Value:
  1157. STATUS_SUCCESS - Indicates the service completed successfully.
  1158. STATUS_QUOTA_EXCEEDED - This error indicates that the logon
  1159. could not be completed because the client does not have
  1160. sufficient quota to allocate the return buffer.
  1161. --*/
  1162. {
  1163. PMSV1_0_PRIMARY_CREDENTIAL Credential;
  1164. PUCHAR Where;
  1165. ULONG PaddingLength;
  1166. //
  1167. // Build the credential
  1168. //
  1169. *CredentialSize = sizeof(MSV1_0_PRIMARY_CREDENTIAL) +
  1170. LogonDomainName->Length + sizeof(WCHAR) +
  1171. UserName->Length + sizeof(WCHAR);
  1172. //
  1173. // add padding for memory encryption interface.
  1174. //
  1175. PaddingLength = DESX_BLOCKLEN - (*CredentialSize % DESX_BLOCKLEN);
  1176. if( PaddingLength == DESX_BLOCKLEN )
  1177. {
  1178. PaddingLength = 0;
  1179. }
  1180. *CredentialSize += PaddingLength;
  1181. Credential = (*Lsa.AllocateLsaHeap)( *CredentialSize );
  1182. if ( Credential == NULL ) {
  1183. KdPrint(("MSV1_0: NlpMakePrimaryCredential: No memory %ld\n",
  1184. *CredentialSize ));
  1185. return STATUS_QUOTA_EXCEEDED;
  1186. }
  1187. //
  1188. // Put the LogonDomainName into the Credential Buffer.
  1189. //
  1190. Where = (PUCHAR)(Credential + 1);
  1191. NlpPutString( &Credential->LogonDomainName, LogonDomainName, &Where );
  1192. //
  1193. // Put the UserName into the Credential Buffer.
  1194. //
  1195. NlpPutString( &Credential->UserName, UserName, &Where );
  1196. //
  1197. // Put the OWF passwords into the newly allocated credential.
  1198. //
  1199. NlpPutOwfsInPrimaryCredential( CleartextPassword, FALSE, Credential );
  1200. //
  1201. // Return the credential to the caller.
  1202. //
  1203. *CredentialBuffer = Credential;
  1204. return STATUS_SUCCESS;
  1205. }
  1206. NTSTATUS
  1207. NlpMakePrimaryCredentialFromMsvCredential(
  1208. IN PUNICODE_STRING LogonDomainName,
  1209. IN PUNICODE_STRING UserName,
  1210. IN PMSV1_0_SUPPLEMENTAL_CREDENTIAL MsvCredential,
  1211. OUT PMSV1_0_PRIMARY_CREDENTIAL *CredentialBuffer,
  1212. OUT PULONG CredentialSize
  1213. )
  1214. /*++
  1215. Routine Description:
  1216. This routine makes a primary credential for the given user nam and
  1217. password.
  1218. Arguments:
  1219. LogonDomainName - Is a string representing the domain in which the user's
  1220. account is defined.
  1221. UserName - Is a string representing the user's account name. The
  1222. name may be up to 255 characters long. The name is treated case
  1223. insensitive.
  1224. SupplementalCred - The credentials retrieved from the user's account on
  1225. the domain controller.
  1226. CredentialBuffer - Returns a pointer to the specified credential allocated
  1227. on the LsaHeap. It is the callers responsibility to deallocate
  1228. this credential.
  1229. CredentialSize - the size of the allocated credential buffer (in bytes).
  1230. Return Value:
  1231. STATUS_SUCCESS - Indicates the service completed successfully.
  1232. STATUS_QUOTA_EXCEEDED - This error indicates that the logon
  1233. could not be completed because the client does not have
  1234. sufficient quota to allocate the return buffer.
  1235. --*/
  1236. {
  1237. PMSV1_0_PRIMARY_CREDENTIAL Credential;
  1238. PUCHAR Where;
  1239. ULONG PaddingLength;
  1240. //
  1241. // Build the credential
  1242. //
  1243. *CredentialSize = sizeof(MSV1_0_PRIMARY_CREDENTIAL) +
  1244. LogonDomainName->Length + sizeof(WCHAR) +
  1245. UserName->Length + sizeof(WCHAR);
  1246. //
  1247. // add padding for memory encryption interface.
  1248. //
  1249. PaddingLength = DESX_BLOCKLEN - (*CredentialSize % DESX_BLOCKLEN);
  1250. if( PaddingLength == DESX_BLOCKLEN )
  1251. {
  1252. PaddingLength = 0;
  1253. }
  1254. *CredentialSize += PaddingLength;
  1255. Credential = (*Lsa.AllocateLsaHeap)( *CredentialSize );
  1256. if ( Credential == NULL ) {
  1257. KdPrint(("MSV1_0: NlpMakePrimaryCredential: No memory %ld\n",
  1258. *CredentialSize ));
  1259. return STATUS_QUOTA_EXCEEDED;
  1260. }
  1261. RtlZeroMemory(
  1262. Credential,
  1263. *CredentialSize
  1264. );
  1265. //
  1266. // Put the LogonDomainName into the Credential Buffer.
  1267. //
  1268. Where = (PUCHAR)(Credential + 1);
  1269. NlpPutString( &Credential->LogonDomainName, LogonDomainName, &Where );
  1270. //
  1271. // Put the UserName into the Credential Buffer.
  1272. //
  1273. NlpPutString( &Credential->UserName, UserName, &Where );
  1274. //
  1275. // Save the OWF encrypted versions of the passwords.
  1276. //
  1277. if (MsvCredential->Flags & MSV1_0_CRED_NT_PRESENT) {
  1278. RtlCopyMemory(
  1279. &Credential->NtOwfPassword,
  1280. MsvCredential->NtPassword,
  1281. MSV1_0_OWF_PASSWORD_LENGTH
  1282. );
  1283. Credential->NtPasswordPresent = TRUE;
  1284. } else {
  1285. #if 0
  1286. RtlCopyMemory(
  1287. &Credential->NtOwfPassword,
  1288. &NlpNullNtOwfPassword,
  1289. MSV1_0_OWF_PASSWORD_LENGTH
  1290. );
  1291. Credential->NtPasswordPresent = TRUE;
  1292. #endif
  1293. Credential->NtPasswordPresent = FALSE;
  1294. }
  1295. if (MsvCredential->Flags & MSV1_0_CRED_LM_PRESENT) {
  1296. RtlCopyMemory(
  1297. &Credential->LmOwfPassword,
  1298. MsvCredential->LmPassword,
  1299. MSV1_0_OWF_PASSWORD_LENGTH
  1300. );
  1301. Credential->LmPasswordPresent = TRUE;
  1302. } else {
  1303. #if 0
  1304. RtlCopyMemory(
  1305. &Credential->LmOwfPassword,
  1306. &NlpNullLmOwfPassword,
  1307. MSV1_0_OWF_PASSWORD_LENGTH
  1308. );
  1309. Credential->LmPasswordPresent = TRUE;
  1310. #endif
  1311. Credential->LmPasswordPresent = FALSE;
  1312. }
  1313. //
  1314. // Return the credential to the caller.
  1315. //
  1316. *CredentialBuffer = Credential;
  1317. return STATUS_SUCCESS;
  1318. }
  1319. NTSTATUS
  1320. NlpAddPrimaryCredential(
  1321. IN PLUID LogonId,
  1322. IN PMSV1_0_PRIMARY_CREDENTIAL Credential,
  1323. IN ULONG CredentialSize
  1324. )
  1325. /*++
  1326. Routine Description:
  1327. This routine sets a primary credential for the given LogonId.
  1328. Arguments:
  1329. LogonId - The LogonId of the LogonSession to set the Credentials
  1330. for.
  1331. Credential - Specifies a pointer to the credential.
  1332. Return Value:
  1333. STATUS_SUCCESS - Indicates the service completed successfully.
  1334. STATUS_QUOTA_EXCEEDED - This error indicates that the logon
  1335. could not be completed because the client does not have
  1336. sufficient quota to allocate the return buffer.
  1337. --*/
  1338. {
  1339. NTSTATUS Status;
  1340. STRING CredentialString;
  1341. STRING PrimaryKeyValue;
  1342. //
  1343. // Make all pointers in the credential relative.
  1344. //
  1345. NlpMakeRelativeString( (PUCHAR)Credential, &Credential->UserName );
  1346. NlpMakeRelativeString( (PUCHAR)Credential, &Credential->LogonDomainName );
  1347. //
  1348. // Add the credential to the logon session.
  1349. //
  1350. RtlInitString( &PrimaryKeyValue, MSV1_0_PRIMARY_KEY );
  1351. CredentialString.Buffer = (PCHAR) Credential;
  1352. CredentialString.Length = (USHORT) CredentialSize;
  1353. CredentialString.MaximumLength = CredentialString.Length;
  1354. //
  1355. // encrypt input credential.
  1356. //
  1357. (*Lsa.LsaProtectMemory)( CredentialString.Buffer, (ULONG)CredentialString.Length );
  1358. Status = (*Lsa.AddCredential)(
  1359. LogonId,
  1360. MspAuthenticationPackageId,
  1361. &PrimaryKeyValue,
  1362. &CredentialString );
  1363. if ( !NT_SUCCESS( Status ) ) {
  1364. KdPrint(( "NlpAddPrimaryCredential: error from AddCredential %lX\n",
  1365. Status));
  1366. }
  1367. return Status;
  1368. }
  1369. NTSTATUS
  1370. NlpGetPrimaryCredentialByUserSid(
  1371. IN PSID pUserSid,
  1372. OUT PMSV1_0_PRIMARY_CREDENTIAL *CredentialBuffer,
  1373. OUT PULONG CredentialSize OPTIONAL
  1374. )
  1375. {
  1376. LUID LogonId;
  1377. BOOLEAN Match = FALSE;
  1378. LIST_ENTRY* pScan = NULL;
  1379. ACTIVE_LOGON* pActiveLogon = NULL;
  1380. if (!pUserSid)
  1381. {
  1382. return STATUS_INVALID_PARAMETER;
  1383. }
  1384. NlpLockActiveLogonsRead();
  1385. for ( pScan = NlpActiveLogonListAnchor.Flink;
  1386. pScan != &NlpActiveLogonListAnchor;
  1387. pScan = pScan->Flink )
  1388. {
  1389. pActiveLogon = CONTAINING_RECORD(pScan, ACTIVE_LOGON, ListEntry);
  1390. if (RtlEqualSid(pUserSid, pActiveLogon->UserSid))
  1391. {
  1392. Match = TRUE;
  1393. RtlCopyMemory(&LogonId, &pActiveLogon->LogonId, sizeof(LogonId));
  1394. break;
  1395. }
  1396. }
  1397. NlpUnlockActiveLogons();
  1398. if (!Match)
  1399. {
  1400. return STATUS_NO_SUCH_LOGON_SESSION;
  1401. }
  1402. return NlpGetPrimaryCredential(&LogonId, CredentialBuffer, CredentialSize);
  1403. }
  1404. NTSTATUS
  1405. NlpGetPrimaryCredential(
  1406. IN PLUID LogonId,
  1407. OUT PMSV1_0_PRIMARY_CREDENTIAL *CredentialBuffer,
  1408. OUT PULONG CredentialSize OPTIONAL
  1409. )
  1410. /*++
  1411. Routine Description:
  1412. This routine gets a primary credential for the given LogonId.
  1413. Arguments:
  1414. LogonId - The LogonId of the LogonSession to retrieve the Credentials
  1415. for.
  1416. CredentialBuffer - Returns a pointer to the specified credential allocated
  1417. on the LsaHeap. It is the callers responsibility to deallocate
  1418. this credential.
  1419. CredentialSize - Optionally returns the size of the credential buffer.
  1420. Return Value:
  1421. STATUS_SUCCESS - Indicates the service completed successfully.
  1422. STATUS_QUOTA_EXCEEDED - This error indicates that the logon
  1423. could not be completed because the client does not have
  1424. sufficient quota to allocate the return buffer.
  1425. --*/
  1426. {
  1427. NTSTATUS Status;
  1428. ULONG QueryContext = 0;
  1429. ULONG PrimaryKeyLength;
  1430. STRING PrimaryKeyValue;
  1431. STRING CredentialString;
  1432. PMSV1_0_PRIMARY_CREDENTIAL Credential = NULL;
  1433. RtlInitString( &PrimaryKeyValue, MSV1_0_PRIMARY_KEY );
  1434. Status = (*Lsa.GetCredentials)( LogonId,
  1435. MspAuthenticationPackageId,
  1436. &QueryContext,
  1437. (BOOLEAN) FALSE, // Just retrieve primary
  1438. &PrimaryKeyValue,
  1439. &PrimaryKeyLength,
  1440. &CredentialString );
  1441. if ( !NT_SUCCESS( Status ) ) {
  1442. return Status;
  1443. }
  1444. //
  1445. // Make all pointers in the credential absolute.
  1446. //
  1447. Credential = (PMSV1_0_PRIMARY_CREDENTIAL) CredentialString.Buffer;
  1448. //
  1449. // decrypt credential.
  1450. //
  1451. (*Lsa.LsaUnprotectMemory)( CredentialString.Buffer, (ULONG)CredentialString.Length );
  1452. NlpRelativeToAbsolute( Credential,
  1453. (PULONG_PTR)&Credential->UserName.Buffer );
  1454. NlpRelativeToAbsolute( Credential,
  1455. (PULONG_PTR)&Credential->LogonDomainName.Buffer );
  1456. *CredentialBuffer = Credential;
  1457. if ( CredentialSize != NULL ) {
  1458. *CredentialSize = CredentialString.Length;
  1459. }
  1460. return STATUS_SUCCESS;
  1461. }
  1462. NTSTATUS
  1463. NlpDeletePrimaryCredential(
  1464. IN PLUID LogonId
  1465. )
  1466. /*++
  1467. Routine Description:
  1468. This routine deletes the credential for the given LogonId.
  1469. Arguments:
  1470. LogonId - The LogonId of the LogonSession to delete the Credentials for.
  1471. Return Value:
  1472. STATUS_SUCCESS - Indicates the service completed successfully.
  1473. STATUS_QUOTA_EXCEEDED - This error indicates that the logon
  1474. could not be completed because the client does not have
  1475. sufficient quota to allocate the return buffer.
  1476. --*/
  1477. {
  1478. NTSTATUS Status;
  1479. STRING PrimaryKeyValue;
  1480. RtlInitString( &PrimaryKeyValue, MSV1_0_PRIMARY_KEY );
  1481. Status = (*Lsa.DeleteCredential)( LogonId,
  1482. MspAuthenticationPackageId,
  1483. &PrimaryKeyValue );
  1484. return Status;
  1485. }
  1486. NTSTATUS
  1487. NlpChangePassword(
  1488. IN BOOLEAN Validated,
  1489. IN PUNICODE_STRING pDomainName,
  1490. IN PUNICODE_STRING pUserName,
  1491. IN PUNICODE_STRING pPassword
  1492. )
  1493. /*++
  1494. Routine Description:
  1495. Change the password for the specified user in all currently stored
  1496. credentials.
  1497. Arguments:
  1498. pDomainName - The Netbios name of the domain in which the account exists.
  1499. pUserName - The name of the account whose password is to be changed.
  1500. pPassword - The new password.
  1501. Return Value:
  1502. STATUS_SUCCESS - If the operation was successful.
  1503. --*/
  1504. {
  1505. NTSTATUS Status = STATUS_NOT_FOUND;
  1506. MSV1_0_PRIMARY_CREDENTIAL TempCredential;
  1507. LUID FastLogonIds[ 32 ];
  1508. PLUID pSlowLogonIds = NULL;
  1509. ULONG AllocatedLogonIds;
  1510. PLUID LogonIds;
  1511. ULONG cLogonIds;
  1512. UNICODE_STRING NetBiosLogonDomainName = {0};
  1513. UNICODE_STRING DnsDomainName = {0};
  1514. UNICODE_STRING* pNetBiosLogonDomainName = NULL;
  1515. ACTIVE_LOGON* pActiveLogon = NULL;
  1516. LIST_ENTRY* pScan = NULL;
  1517. cLogonIds = 0;
  1518. LogonIds = FastLogonIds;
  1519. AllocatedLogonIds = sizeof(FastLogonIds) / sizeof(LUID);
  1520. //
  1521. // we call NlpChangeCachePassword here to ensure that non-trusted service
  1522. // callers do not change cached passwords that do not belong to themselves
  1523. //
  1524. // it is understood that NlpChangeCachePassword can be called again later
  1525. // for the same request
  1526. //
  1527. //
  1528. // Compute the OWFs of the password.
  1529. //
  1530. NlpPutOwfsInPrimaryCredential( pPassword, FALSE, &TempCredential );
  1531. Status = NlpChangeCachePassword(
  1532. Validated,
  1533. pDomainName,
  1534. pUserName,
  1535. &TempCredential.LmOwfPassword,
  1536. &TempCredential.NtOwfPassword
  1537. );
  1538. RtlSecureZeroMemory( &TempCredential, sizeof(TempCredential) );
  1539. //
  1540. // STATUS_PRIVILEGE_NOT_HELD means the caller is not allowed to change
  1541. // cached passwords, if so bail out now
  1542. //
  1543. if (STATUS_PRIVILEGE_NOT_HELD == Status)
  1544. {
  1545. goto Cleanup;
  1546. }
  1547. Status = LsaIGetNbAndDnsDomainNames( pDomainName, &DnsDomainName, &NetBiosLogonDomainName );
  1548. if (NT_SUCCESS(Status) && NetBiosLogonDomainName.Length != 0)
  1549. {
  1550. pNetBiosLogonDomainName = &NetBiosLogonDomainName;
  1551. }
  1552. else
  1553. {
  1554. pNetBiosLogonDomainName = pDomainName;
  1555. }
  1556. //
  1557. // Loop through the table looking for this particular UserName/DomainName.
  1558. //
  1559. NlpLockActiveLogonsRead();
  1560. for ( pScan = NlpActiveLogonListAnchor.Flink;
  1561. pScan != &NlpActiveLogonListAnchor;
  1562. pScan = pScan->Flink )
  1563. {
  1564. pActiveLogon = CONTAINING_RECORD(pScan, ACTIVE_LOGON, ListEntry);
  1565. if (!RtlEqualUnicodeString( pUserName, &pActiveLogon->UserName, (BOOLEAN) TRUE ))
  1566. {
  1567. continue;
  1568. }
  1569. if (!RtlEqualDomainName( pNetBiosLogonDomainName, &pActiveLogon->LogonDomainName ))
  1570. {
  1571. continue;
  1572. }
  1573. SspPrint((SSP_UPDATES, "NlpChangePassword matched LogonId=%lx.%lx\n",
  1574. pActiveLogon->LogonId.LowPart, pActiveLogon->LogonId.HighPart));
  1575. //
  1576. // if we don't have space to store the new entry, allocate a new
  1577. // buffer, copy the existing buffer, and keep going.
  1578. //
  1579. if (AllocatedLogonIds < (cLogonIds + 1))
  1580. {
  1581. PLUID OldLogonIds = pSlowLogonIds;
  1582. AllocatedLogonIds *= 2;
  1583. pSlowLogonIds = I_NtLmAllocate( AllocatedLogonIds * sizeof(LUID) );
  1584. if ( pSlowLogonIds == NULL )
  1585. {
  1586. break;
  1587. }
  1588. CopyMemory( pSlowLogonIds, LogonIds, cLogonIds * sizeof(LUID) );
  1589. LogonIds = pSlowLogonIds;
  1590. if ( OldLogonIds != NULL )
  1591. {
  1592. I_NtLmFree( OldLogonIds );
  1593. }
  1594. }
  1595. LogonIds[ cLogonIds ] = pActiveLogon->LogonId;
  1596. cLogonIds++;
  1597. }
  1598. NlpUnlockActiveLogons();
  1599. //
  1600. // Pass the change back to the LSA. Note - this only changes it for the
  1601. // last element in the list.
  1602. //
  1603. if (cLogonIds != 0)
  1604. {
  1605. SECPKG_PRIMARY_CRED PrimaryCredentials;
  1606. ULONG Index;
  1607. RtlZeroMemory(
  1608. &PrimaryCredentials,
  1609. sizeof(SECPKG_PRIMARY_CRED)
  1610. );
  1611. PrimaryCredentials.Password = *pPassword;
  1612. PrimaryCredentials.Flags = PRIMARY_CRED_UPDATE | PRIMARY_CRED_CLEAR_PASSWORD;
  1613. //
  1614. // update each instance of the credential that matches.
  1615. // Multiple logon session can legally reference the same creds,
  1616. // eg: Terminal Services, RunAs, etc.
  1617. //
  1618. for ( Index = 0 ; Index < cLogonIds ; Index++ )
  1619. {
  1620. PrimaryCredentials.LogonId = LogonIds[ Index ];
  1621. (VOID) LsaFunctions->UpdateCredentials(
  1622. &PrimaryCredentials,
  1623. NULL // no supplemental credentials
  1624. );
  1625. }
  1626. Status = STATUS_SUCCESS;
  1627. }
  1628. else
  1629. {
  1630. Status = STATUS_NOT_FOUND;
  1631. }
  1632. Cleanup:
  1633. if (pSlowLogonIds)
  1634. {
  1635. I_NtLmFree(pSlowLogonIds);
  1636. }
  1637. if (NetBiosLogonDomainName.Buffer)
  1638. {
  1639. LsaIFreeHeap(NetBiosLogonDomainName.Buffer);
  1640. }
  1641. if (DnsDomainName.Buffer)
  1642. {
  1643. LsaIFreeHeap(DnsDomainName.Buffer);
  1644. }
  1645. return Status;
  1646. }
  1647. NTSTATUS
  1648. NlpChangePwdCredByLogonId(
  1649. IN PLUID pLogonId,
  1650. IN PMSV1_0_PRIMARY_CREDENTIAL pNewCredential,
  1651. IN BOOL bNotify
  1652. )
  1653. /*++
  1654. Routine Description:
  1655. Change the password for the specified user in all currently stored
  1656. credentials.
  1657. Arguments:
  1658. pLogonId - Logon ID of user whose password changed.
  1659. pNewCredential - New credential.
  1660. bNotify - Whether to notify password changes
  1661. Return Value:
  1662. STATUS_SUCCESS - If the operation was successful.
  1663. --*/
  1664. {
  1665. NTSTATUS Status = STATUS_SUCCESS;
  1666. PMSV1_0_PRIMARY_CREDENTIAL pCredential = NULL;
  1667. ULONG CredentialSize;
  1668. LIST_ENTRY* pScan = NULL;
  1669. ACTIVE_LOGON* pActiveLogon = NULL;
  1670. //
  1671. // Loop through the table looking for this particular UserName/DomainName.
  1672. //
  1673. // conservative: take the full write lock up front.
  1674. NlpLockActiveLogonsWrite();
  1675. for ( pScan = NlpActiveLogonListAnchor.Flink;
  1676. pScan != &NlpActiveLogonListAnchor;
  1677. pScan = pScan->Flink )
  1678. {
  1679. pActiveLogon = CONTAINING_RECORD(pScan, ACTIVE_LOGON, ListEntry);
  1680. if (!RtlEqualLuid( pLogonId, &pActiveLogon->LogonId))
  1681. {
  1682. continue;
  1683. }
  1684. SspPrint((SSP_UPDATES, "NlpChangePwdCredByLogonId LogonId %#x:%#x for %wZ\\%wZ\n",
  1685. pLogonId->HighPart, pLogonId->LowPart, &pNewCredential->LogonDomainName, &pNewCredential->UserName));
  1686. //
  1687. // Get the current credential for this logonid.
  1688. //
  1689. Status = NlpGetPrimaryCredential( &pActiveLogon->LogonId,
  1690. &pCredential,
  1691. &CredentialSize );
  1692. if ( !NT_SUCCESS(Status) )
  1693. {
  1694. break;
  1695. }
  1696. //
  1697. // check if this upate is fake
  1698. //
  1699. if (RtlEqualMemory(
  1700. &pCredential->NtOwfPassword,
  1701. &pNewCredential->NtOwfPassword,
  1702. sizeof(NT_OWF_PASSWORD)
  1703. ))
  1704. {
  1705. SspPrint((SSP_UPDATES, "NlpChangePwdCredByLogonId skip fake update for %#x:%#x\n",
  1706. pLogonId->HighPart, pLogonId->LowPart));
  1707. break;
  1708. }
  1709. //
  1710. // Notify DPAPI that the user password has been changed. DPAPI will take
  1711. // this opportunity to re-synchronize its master keys if necessary.
  1712. //
  1713. if (bNotify)
  1714. {
  1715. #if 0
  1716. BYTE BufferIn[8] = {0};
  1717. DATA_BLOB DataIn = {0};
  1718. DATA_BLOB DataOut = {0};
  1719. DataIn.pbData = BufferIn;
  1720. DataIn.cbData = sizeof(BufferIn);
  1721. SspPrint((SSP_UPDATES, "NlpChangePwdCredByLogonId %#x:%#x for %wZ\\%wZ notifying DPAPI\n",
  1722. pLogonId->HighPart, pLogonId->LowPart, &pNewCredential->LogonDomainName, &pNewCredential->UserName));
  1723. CryptProtectData(
  1724. &DataIn,
  1725. NULL,
  1726. NULL,
  1727. NULL,
  1728. NULL,
  1729. CRYPTPROTECT_CRED_SYNC,
  1730. &DataOut
  1731. );
  1732. #endif
  1733. }
  1734. //
  1735. // Delete it from the LSA
  1736. //
  1737. Status = NlpDeletePrimaryCredential( &pActiveLogon->LogonId );
  1738. if ( !NT_SUCCESS(Status) )
  1739. {
  1740. LsaFunctions->FreeLsaHeap( pCredential );
  1741. break;
  1742. }
  1743. //
  1744. // Change the passwords in it
  1745. //
  1746. pCredential->LmOwfPassword = pNewCredential->LmOwfPassword;
  1747. pCredential->NtOwfPassword = pNewCredential->NtOwfPassword;
  1748. pCredential->ShaOwfPassword = pNewCredential->ShaOwfPassword;
  1749. pCredential->LmPasswordPresent = pNewCredential->LmPasswordPresent;
  1750. pCredential->NtPasswordPresent = pNewCredential->NtPasswordPresent;
  1751. pCredential->ShaPasswordPresent = pNewCredential->ShaPasswordPresent;
  1752. //
  1753. // Add it back to the LSA.
  1754. //
  1755. Status = NlpAddPrimaryCredential(
  1756. &pActiveLogon->LogonId,
  1757. pCredential,
  1758. CredentialSize
  1759. );
  1760. LsaFunctions->FreeLsaHeap( pCredential );
  1761. if ( !NT_SUCCESS(Status) )
  1762. {
  1763. break;
  1764. }
  1765. //
  1766. // Pass the new password on to the logon cache
  1767. //
  1768. (VOID) NlpChangeCachePassword(
  1769. TRUE, // called only by SpAcceptCredentials, where the password is validated
  1770. &pActiveLogon->LogonDomainName,
  1771. &pActiveLogon->UserName,
  1772. &pNewCredential->LmOwfPassword,
  1773. &pNewCredential->NtOwfPassword
  1774. );
  1775. break;
  1776. }
  1777. NlpUnlockActiveLogons();
  1778. return Status;
  1779. }
  1780. VOID
  1781. NlpGetAccountNames(
  1782. IN PNETLOGON_LOGON_IDENTITY_INFO LogonInfo,
  1783. IN PNETLOGON_VALIDATION_SAM_INFO4 NlpUser,
  1784. OUT PUNICODE_STRING SamAccountName,
  1785. OUT PUNICODE_STRING NetbiosDomainName,
  1786. OUT PUNICODE_STRING DnsDomainName,
  1787. OUT PUNICODE_STRING Upn
  1788. )
  1789. /*++
  1790. Routine Description:
  1791. Get the sundry account names from the LogonInfo and NlpUser
  1792. Arguments:
  1793. LogonInfo - pointer to NETLOGON_INTERACTIVE_INFO structure which contains
  1794. the domain name, user name and password for this user. These
  1795. are what the user typed to WinLogon
  1796. NlpUser - pointer to NETLOGON_VALIDATION_SAM_INFO4 structure which
  1797. contains this user's specific interactive logon information
  1798. SamAccountName - Returns the SamAccountName of the logged on user.
  1799. The returned buffer is within the LogonInfo or NlpUser.
  1800. NetbiosDomainName - Returns the NetbiosDomainName of the logged on user.
  1801. The returned buffer is within the LogonInfo or NlpUser.
  1802. DnsDomainName - Returns the DnsDomainName of the logged on user.
  1803. The returned buffer is within the LogonInfo or NlpUser.
  1804. The returned length will be zero if DnsDomainName is not known.
  1805. UPN - Returns the UPN of the logged on user.
  1806. The returned buffer is within the LogonInfo or NlpUser.
  1807. The returned length will be zero if UPN is not known.
  1808. Return Value:
  1809. None.
  1810. --*/
  1811. {
  1812. //
  1813. // Return the SamAccountName and Netbios Domain Name
  1814. //
  1815. *SamAccountName = NlpUser->EffectiveName;
  1816. *NetbiosDomainName = NlpUser->LogonDomainName;
  1817. //
  1818. // Return the DNS domain name.
  1819. //
  1820. *DnsDomainName = NlpUser->DnsLogonDomainName;
  1821. //
  1822. // Determine the UPN of the account
  1823. //
  1824. // If the caller passed in a UPN
  1825. // use it.
  1826. // else
  1827. // use the UPN returned from the DC
  1828. //
  1829. // The caller passed in a UPN if all of the following are true:
  1830. // There is no domain name.
  1831. // The passed in user name isn't the one returned from the DC.
  1832. // The passed in user name has an @ in it.
  1833. //
  1834. //
  1835. RtlZeroMemory(Upn, sizeof(*Upn));
  1836. if ( LogonInfo->LogonDomainName.Length == 0 &&
  1837. !RtlEqualUnicodeString( &LogonInfo->UserName, &NlpUser->EffectiveName, (BOOLEAN) TRUE ) ) {
  1838. ULONG i;
  1839. for ( i=0; i<LogonInfo->UserName.Length/sizeof(WCHAR); i++) {
  1840. if ( LogonInfo->UserName.Buffer[i] == L'@') {
  1841. *Upn = LogonInfo->UserName;
  1842. break;
  1843. }
  1844. }
  1845. }
  1846. if ( Upn->Length == 0 ) {
  1847. *Upn = NlpUser->Upn;
  1848. }
  1849. }
  1850. //+-------------------------------------------------------------------------
  1851. //
  1852. // Function: NlpCopyDomainRelativeSid
  1853. //
  1854. // Synopsis: Given a domain Id and a relative ID create the corresponding
  1855. // SID at the location indicated by TargetSid
  1856. //
  1857. // Effects:
  1858. //
  1859. // Arguments: TargetSid - target memory location
  1860. // DomainId - The template SID to use.
  1861. //
  1862. // RelativeId - The relative Id to append to the DomainId.
  1863. //
  1864. // Requires:
  1865. //
  1866. // Returns: Size - Size of the sid copied
  1867. //
  1868. // Notes:
  1869. //
  1870. //
  1871. //--------------------------------------------------------------------------
  1872. DWORD
  1873. NlpCopyDomainRelativeSid(
  1874. OUT PSID TargetSid,
  1875. IN PSID DomainId,
  1876. IN ULONG RelativeId
  1877. )
  1878. {
  1879. UCHAR DomainIdSubAuthorityCount;
  1880. ULONG Size;
  1881. //
  1882. // Allocate a Sid which has one more sub-authority than the domain ID.
  1883. //
  1884. DomainIdSubAuthorityCount = *(RtlSubAuthorityCountSid( DomainId ));
  1885. Size = RtlLengthRequiredSid(DomainIdSubAuthorityCount+1);
  1886. //
  1887. // Initialize the new SID to have the same inital value as the
  1888. // domain ID.
  1889. //
  1890. if ( !NT_SUCCESS( RtlCopySid( Size, TargetSid, DomainId ) ) ) {
  1891. return 0;
  1892. }
  1893. //
  1894. // Adjust the sub-authority count and
  1895. // add the relative Id unique to the newly allocated SID
  1896. //
  1897. (*(RtlSubAuthorityCountSid( TargetSid ))) ++;
  1898. *RtlSubAuthoritySid( TargetSid, DomainIdSubAuthorityCount ) = RelativeId;
  1899. return Size;
  1900. }
  1901. //
  1902. // temporary home for this function.
  1903. //
  1904. NTSTATUS
  1905. RtlCalculateShaOwfPassword(
  1906. IN PSHA_PASSWORD ShaPassword,
  1907. OUT PSHA_OWF_PASSWORD ShaOwfPassword
  1908. )
  1909. /*++
  1910. Routine Description:
  1911. Takes the passed ShaPassword and performs a one-way-function on it.
  1912. Uses the FIPS approved SHA-1 function
  1913. Arguments:
  1914. ShaPassword - The password to perform the one-way-function on.
  1915. ShaOwfPassword - The hashed password is returned here
  1916. Return Values:
  1917. STATUS_SUCCESS - The function was completed successfully. The hashed
  1918. password is in ShaOwfPassword.
  1919. --*/
  1920. {
  1921. A_SHA_CTX SHA_Context;
  1922. A_SHAInit(&SHA_Context);
  1923. A_SHAUpdate(&SHA_Context, (PUCHAR) ShaPassword->Buffer, ShaPassword->Length);
  1924. A_SHAFinal(&SHA_Context, (PUCHAR) ShaOwfPassword);
  1925. return(STATUS_SUCCESS);
  1926. }