Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1392 lines
42 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) Microsoft Corporation 1992 - 1996
  6. //
  7. // File: credapi.cxx
  8. //
  9. // Contents: Code for credentials APIs for the NtLm package
  10. // Main entry points into this dll:
  11. // SpAcceptCredentials
  12. // SpAcquireCredentialsHandle
  13. // SpFreeCredentialsHandle
  14. // SpQueryCredentialsAttributes
  15. // SpSaveCredentials
  16. // SpGetCredentials
  17. // SpDeleteCredentials
  18. //
  19. // Helper functions:
  20. // CopyClientString
  21. //
  22. // History: ChandanS 26-Jul-1996 Stolen from kerberos\client2\credapi.cxx
  23. //
  24. //------------------------------------------------------------------------
  25. #define NTLM_CREDAPI
  26. #include <global.h>
  27. extern "C"
  28. {
  29. #include <nlp.h>
  30. }
  31. //+-------------------------------------------------------------------------
  32. //
  33. // Function: CopyClientString
  34. //
  35. // Synopsis: copies a client string to local memory, including
  36. // allocating space for it locally.
  37. //
  38. // Arguments:
  39. // SourceString - Could be Oem or Wchar in client process
  40. // SourceLength - bytes
  41. // DoUnicode - whether the string is Wchar
  42. //
  43. // Returns:
  44. // DestinationString - Unicode String in Lsa Process
  45. //
  46. // Notes:
  47. //
  48. //--------------------------------------------------------------------------
  49. HRESULT
  50. CopyClientString(
  51. IN PWSTR SourceString,
  52. IN ULONG SourceLength,
  53. IN BOOLEAN DoUnicode,
  54. OUT PUNICODE_STRING DestinationString
  55. )
  56. {
  57. SspPrint((SSP_API_MORE,"Entering CopyClientString\n"));
  58. NTSTATUS Status = STATUS_SUCCESS;
  59. STRING TemporaryString;
  60. ULONG SourceSize = 0;
  61. ULONG CharacterSize = sizeof(CHAR);
  62. //
  63. // First initialize the string to zero, in case the source is a null
  64. // string
  65. //
  66. DestinationString->Length = DestinationString->MaximumLength = 0;
  67. DestinationString->Buffer = NULL;
  68. TemporaryString.Buffer = NULL;
  69. if (SourceString != NULL)
  70. {
  71. //
  72. // If the length is zero, allocate one byte for a "\0" terminator
  73. //
  74. if (SourceLength == 0)
  75. {
  76. DestinationString->Buffer = (LPWSTR) NtLmAllocate(sizeof(WCHAR));
  77. if (DestinationString->Buffer == NULL)
  78. {
  79. SspPrint((SSP_CRITICAL,"CopyClientString, Error from NtLmAllocate is 0x%lx\n", Status));
  80. Status = STATUS_NO_MEMORY;
  81. goto Cleanup;
  82. }
  83. DestinationString->MaximumLength = sizeof(WCHAR);
  84. *DestinationString->Buffer = L'\0';
  85. }
  86. else
  87. {
  88. //
  89. // Allocate a temporary buffer to hold the client string. We may
  90. // then create a buffer for the unicode version. The length
  91. // is the length in characters, so possible expand to hold unicode
  92. // characters and a null terminator.
  93. //
  94. if (DoUnicode)
  95. {
  96. CharacterSize = sizeof(WCHAR);
  97. }
  98. SourceSize = (SourceLength + 1) * CharacterSize;
  99. //
  100. // insure no overflow aggainst UNICODE_STRING
  101. //
  102. if ( (SourceSize > 0xFFFF) ||
  103. ((SourceSize - CharacterSize) > 0xFFFF)
  104. )
  105. {
  106. Status = STATUS_INVALID_PARAMETER;
  107. SspPrint((SSP_CRITICAL,"CopyClientString, SourceSize is too large\n"));
  108. goto Cleanup;
  109. }
  110. TemporaryString.Buffer = (LPSTR) NtLmAllocate(SourceSize);
  111. if (TemporaryString.Buffer == NULL)
  112. {
  113. Status = STATUS_NO_MEMORY;
  114. SspPrint((SSP_CRITICAL,"CopyClientString, Error from NtLmAllocate is 0x%lx\n", Status));
  115. goto Cleanup;
  116. }
  117. TemporaryString.Length = (USHORT) (SourceSize - CharacterSize);
  118. TemporaryString.MaximumLength = (USHORT) SourceSize;
  119. //
  120. // Finally copy the string from the client
  121. //
  122. Status = LsaFunctions->CopyFromClientBuffer(
  123. NULL,
  124. SourceSize - CharacterSize,
  125. TemporaryString.Buffer,
  126. SourceString
  127. );
  128. if (!NT_SUCCESS(Status))
  129. {
  130. SspPrint((SSP_CRITICAL,"CopyClientString, Error from LsaFunctions->CopyFromClientBuffer is 0x%lx\n", Status));
  131. goto Cleanup;
  132. }
  133. //
  134. // If we are doing unicode, finish up now
  135. //
  136. if (DoUnicode)
  137. {
  138. DestinationString->Buffer = (LPWSTR) TemporaryString.Buffer;
  139. DestinationString->Length = (USHORT) (SourceSize - CharacterSize);
  140. DestinationString->MaximumLength = (USHORT) SourceSize;
  141. TemporaryString.Buffer = NULL;
  142. }
  143. else
  144. {
  145. //
  146. // allocate enough space based on the size of the original Unicode input.
  147. // required so that we can use our own allocation scheme.
  148. //
  149. DestinationString->Buffer = (LPWSTR)NtLmAllocate( SourceSize*sizeof(WCHAR) );
  150. if( DestinationString->Buffer == NULL )
  151. {
  152. Status = STATUS_NO_MEMORY;
  153. SspPrint((SSP_CRITICAL,"Error from NtLmAllocate\n"));
  154. goto Cleanup;
  155. }
  156. DestinationString->Length = (USHORT)(SourceSize - CharacterSize);
  157. DestinationString->MaximumLength = (USHORT)SourceSize * sizeof(WCHAR);
  158. Status = RtlOemStringToUnicodeString(
  159. DestinationString,
  160. &TemporaryString,
  161. FALSE
  162. );
  163. if (!NT_SUCCESS(Status))
  164. {
  165. SspPrint((SSP_CRITICAL,"CopyClientString, Error from RtlOemStringToUnicodeString is 0x%lx\n", Status));
  166. // set to STATUS_NO_MEMORY, as it's unlikely that locale error code would be useful.
  167. Status = STATUS_NO_MEMORY;
  168. goto Cleanup;
  169. }
  170. }
  171. }
  172. }
  173. Cleanup:
  174. if (TemporaryString.Buffer != NULL)
  175. {
  176. NtLmFree(TemporaryString.Buffer);
  177. }
  178. SspPrint((SSP_API_MORE,"Leaving CopyClientString\n"));
  179. return(Status);
  180. }
  181. //+-------------------------------------------------------------------------
  182. //
  183. // Function: SpAcceptCredentials
  184. //
  185. // Synopsis: This routine is called after another package has logged
  186. // a user on. The other package provides a user name and
  187. // password and the NtLm package will create a logon
  188. // session for this user.
  189. //
  190. // Effects: Creates a logon session
  191. //
  192. // Arguments: LogonType - Type of logon, such as network or interactive
  193. // Accountname - Name of the account that logged on
  194. // PrimaryCredentials - Primary credentials for the account,
  195. // containing a domain name, password, SID, etc.
  196. // SupplementalCredentials - NtLm -Specific blob of
  197. // supplemental credentials.
  198. //
  199. // Returns: None
  200. //
  201. // Notes:
  202. //
  203. //--------------------------------------------------------------------------
  204. NTSTATUS NTAPI
  205. SpAcceptCredentials(
  206. IN SECURITY_LOGON_TYPE LogonType,
  207. IN PUNICODE_STRING AccountName,
  208. IN PSECPKG_PRIMARY_CRED PrimaryCredentials,
  209. IN PSECPKG_SUPPLEMENTAL_CRED SupplementalCredentials
  210. )
  211. {
  212. NTSTATUS Status = S_OK;
  213. SspPrint((SSP_API,"Entering SpAcceptCredentials\n"));
  214. Status = SspAcceptCredentials(
  215. LogonType,
  216. PrimaryCredentials,
  217. SupplementalCredentials
  218. );
  219. SspPrint((SSP_API,"Leaving SpAcceptCredentials\n"));
  220. return(SspNtStatusToSecStatus(Status, SEC_E_INTERNAL_ERROR));
  221. UNREFERENCED_PARAMETER( AccountName );
  222. }
  223. //+-------------------------------------------------------------------------
  224. //
  225. // Function: SpAcquireCredentialsHandle
  226. //
  227. // Synopsis: Contains NtLm Code for AcquireCredentialsHandle which
  228. // creates a Credential associated with a logon session.
  229. //
  230. // Effects: Creates a SSP_CREDENTIAL
  231. //
  232. // Arguments: PrincipalName - Name of logon session for which to create credential
  233. // CredentialUseFlags - Flags indicating whether the credentials
  234. // is for inbound or outbound use.
  235. // LogonId - The logon ID of logon session for which to create
  236. // a credential.
  237. // AuthorizationData - Unused blob of NtLm-specific data
  238. // GetKeyFunction - Unused function to retrieve a session key
  239. // GetKeyArgument - Argument for GetKeyFunction
  240. // CredentialHandle - Receives handle to new credential
  241. // ExpirationTime - Receives expiration time for credential
  242. //
  243. // Returns:
  244. // STATUS_SUCCESS -- Call completed successfully
  245. // SEC_E_NO_SPM -- Security Support Provider is not running
  246. // SEC_E_PACKAGE_UNKNOWN -- Package being queried is not this package
  247. // SEC_E_PRINCIPAL_UNKNOWN -- No such principal
  248. // SEC_E_NOT_OWNER -- caller does not own the specified credentials
  249. // SEC_E_INSUFFICIENT_MEMORY -- Not enough memory
  250. //
  251. // Notes:
  252. //
  253. //--------------------------------------------------------------------------
  254. NTSTATUS NTAPI
  255. SpAcquireCredentialsHandle(
  256. IN OPTIONAL PUNICODE_STRING PrincipalName,
  257. IN ULONG CredentialUseFlags,
  258. IN OPTIONAL PLUID LogonId,
  259. IN PVOID AuthorizationData,
  260. IN PVOID GetKeyFunction,
  261. IN PVOID GetKeyArgument,
  262. OUT PULONG_PTR CredentialHandle,
  263. OUT PTimeStamp ExpirationTime
  264. )
  265. {
  266. SspPrint((SSP_API,"Entering SpAcquireCredentialsHandle\n"));
  267. NTSTATUS Status = STATUS_SUCCESS;
  268. UNICODE_STRING UserName;
  269. UNICODE_STRING DomainName;
  270. UNICODE_STRING Password;
  271. ULONG NewCredentialUseFlags = CredentialUseFlags;
  272. PSEC_WINNT_AUTH_IDENTITY pAuthIdentity = NULL;
  273. BOOLEAN DoUnicode = TRUE;
  274. PSEC_WINNT_AUTH_IDENTITY_EXW pAuthIdentityEx = NULL;
  275. PSEC_WINNT_AUTH_IDENTITY_W TmpCredentials = NULL;
  276. ULONG CredSize = 0;
  277. ULONG Offset = 0;
  278. //
  279. // Initialization
  280. //
  281. RtlInitUnicodeString(
  282. &UserName,
  283. NULL);
  284. RtlInitUnicodeString(
  285. &DomainName,
  286. NULL);
  287. RtlInitUnicodeString(
  288. &Password,
  289. NULL);
  290. //
  291. // Validate the arguments
  292. //
  293. if ( (CredentialUseFlags & (SECPKG_CRED_OUTBOUND |SECPKG_CRED_INBOUND)) == 0)
  294. {
  295. Status = SEC_E_INVALID_CREDENTIAL_USE;
  296. goto Cleanup;
  297. }
  298. if ( ARGUMENT_PRESENT(GetKeyFunction) ) {
  299. Status = SEC_E_UNSUPPORTED_FUNCTION;
  300. SspPrint((SSP_CRITICAL,"Error from SpAquireCredentialsHandle is 0x%lx\n", Status));
  301. goto Cleanup;
  302. }
  303. // RDR2 passes in a 1 while talking to down level clients
  304. if ( ARGUMENT_PRESENT(GetKeyArgument) && (GetKeyArgument != (PVOID) 1)) {
  305. Status = SEC_E_UNSUPPORTED_FUNCTION;
  306. SspPrint((SSP_CRITICAL,"Error from SpAquireCredentialsHandle is 0x%lx\n", Status));
  307. goto Cleanup;
  308. }
  309. //
  310. // First get information about the caller.
  311. //
  312. SECPKG_CLIENT_INFO ClientInfo;
  313. PLUID LogonIdToUse;
  314. Status = LsaFunctions->GetClientInfo(&ClientInfo);
  315. if (!NT_SUCCESS(Status))
  316. {
  317. SspPrint((SSP_CRITICAL,"SpAcquireCredentialsHandle, Error from LsaFunctions->GetClientInfo is 0x%lx\n", Status));
  318. goto Cleanup;
  319. }
  320. //
  321. // If the caller supplied a logon ID, and it doesn't match the caller,
  322. // they must have the TCB privilege
  323. //
  324. if (ARGUMENT_PRESENT(LogonId) &&
  325. ((LogonId->LowPart != 0) || (LogonId->HighPart != 0)) &&
  326. !RtlEqualLuid( LogonId, &ClientInfo.LogonId)
  327. )
  328. {
  329. if (!ClientInfo.HasTcbPrivilege)
  330. {
  331. Status = STATUS_PRIVILEGE_NOT_HELD;
  332. SspPrint((SSP_CRITICAL,"SpAcquireCredentialsHandle, Error from ClientInfo.HasTcbPrivilege is 0x%lx\n", Status));
  333. goto Cleanup;
  334. }
  335. LogonIdToUse = LogonId;
  336. // note: there is a special case where the LogonIdToUse specifies
  337. // the SYSTEM token, and there may not be a credential (and access token)
  338. // for that Luid yet. This special case is handled in SsprAcquireCredentialsHandle()
  339. }
  340. else
  341. {
  342. //
  343. // Use the callers logon id.
  344. //
  345. LogonIdToUse = &ClientInfo.LogonId;
  346. }
  347. //
  348. // Copy over the authorization data into out address
  349. // space and make a local copy of the strings.
  350. //
  351. if (AuthorizationData != NULL)
  352. {
  353. SECPKG_CALL_INFO CallInfo ;
  354. SEC_WINNT_AUTH_IDENTITY32 Cred32 ;
  355. SEC_WINNT_AUTH_IDENTITY_EX32 CredEx32 ;
  356. if(!LsaFunctions->GetCallInfo( &CallInfo ))
  357. {
  358. Status = STATUS_INTERNAL_ERROR;
  359. SspPrint((SSP_CRITICAL,"SpAcquireCredentialsHandle, Error from LsaFunctions->GetCallInfo is 0x%lx\n", Status));
  360. goto Cleanup;
  361. }
  362. pAuthIdentityEx = (PSEC_WINNT_AUTH_IDENTITY_EXW) NtLmAllocate(sizeof(SEC_WINNT_AUTH_IDENTITY_EXW));
  363. if (pAuthIdentityEx != NULL)
  364. {
  365. if ( CallInfo.Attributes & SECPKG_CALL_WOWCLIENT )
  366. {
  367. Status = LsaFunctions->CopyFromClientBuffer(
  368. NULL,
  369. sizeof( Cred32 ),
  370. pAuthIdentityEx,
  371. AuthorizationData );
  372. if ( NT_SUCCESS( Status ) )
  373. {
  374. RtlCopyMemory( &Cred32, pAuthIdentityEx, sizeof( Cred32 ) );
  375. }
  376. }
  377. else
  378. {
  379. Status = LsaFunctions->CopyFromClientBuffer(
  380. NULL,
  381. sizeof(SEC_WINNT_AUTH_IDENTITY),
  382. pAuthIdentityEx,
  383. AuthorizationData);
  384. }
  385. if (!NT_SUCCESS(Status))
  386. {
  387. SspPrint((SSP_CRITICAL,"SpAcquireCredentialsHandle, Error from LsaFunctions->CopyFromClientBuffer is 0x%lx\n", Status));
  388. goto Cleanup;
  389. }
  390. }
  391. else
  392. {
  393. Status = STATUS_INSUFFICIENT_RESOURCES;
  394. SspPrint((SSP_CRITICAL,"SpAcquireCredentialsHandle, Error from NtLmAllocate is 0x%lx\n", Status));
  395. goto Cleanup;
  396. }
  397. //
  398. // Check for the ex version
  399. //
  400. if (pAuthIdentityEx->Version == SEC_WINNT_AUTH_IDENTITY_VERSION)
  401. {
  402. //
  403. // It's an EX structure.
  404. //
  405. if ( CallInfo.Attributes & SECPKG_CALL_WOWCLIENT )
  406. {
  407. Status = LsaFunctions->CopyFromClientBuffer(
  408. NULL,
  409. sizeof( CredEx32 ),
  410. &CredEx32,
  411. AuthorizationData );
  412. if ( NT_SUCCESS( Status ) )
  413. {
  414. pAuthIdentityEx->Version = CredEx32.Version ;
  415. pAuthIdentityEx->Length = (CredEx32.Length < sizeof( SEC_WINNT_AUTH_IDENTITY_EX ) ?
  416. sizeof( SEC_WINNT_AUTH_IDENTITY_EX ) : CredEx32.Length );
  417. pAuthIdentityEx->User = (PWSTR) UlongToPtr( CredEx32.User );
  418. pAuthIdentityEx->UserLength = CredEx32.UserLength ;
  419. pAuthIdentityEx->Domain = (PWSTR) UlongToPtr( CredEx32.Domain );
  420. pAuthIdentityEx->DomainLength = CredEx32.DomainLength ;
  421. pAuthIdentityEx->Password = (PWSTR) UlongToPtr( CredEx32.Password );
  422. pAuthIdentityEx->PasswordLength = CredEx32.PasswordLength ;
  423. pAuthIdentityEx->Flags = CredEx32.Flags ;
  424. pAuthIdentityEx->PackageList = (PWSTR) UlongToPtr( CredEx32.PackageList );
  425. pAuthIdentityEx->PackageListLength = CredEx32.PackageListLength ;
  426. }
  427. }
  428. else
  429. {
  430. Status = LsaFunctions->CopyFromClientBuffer(
  431. NULL,
  432. sizeof(SEC_WINNT_AUTH_IDENTITY_EXW),
  433. pAuthIdentityEx,
  434. AuthorizationData);
  435. }
  436. if (!NT_SUCCESS(Status))
  437. {
  438. SspPrint((SSP_CRITICAL,"SpAcquireCredentialsHandle, Error from LsaFunctions->CopyFromClientBuffer is 0x%lx\n", Status));
  439. goto Cleanup;
  440. }
  441. pAuthIdentity = (PSEC_WINNT_AUTH_IDENTITY) &pAuthIdentityEx->User;
  442. CredSize = pAuthIdentityEx->Length;
  443. Offset = FIELD_OFFSET(SEC_WINNT_AUTH_IDENTITY_EXW, User);
  444. }
  445. else
  446. {
  447. pAuthIdentity = (PSEC_WINNT_AUTH_IDENTITY_W) pAuthIdentityEx;
  448. if ( CallInfo.Attributes & SECPKG_CALL_WOWCLIENT )
  449. {
  450. pAuthIdentity->User = (PWSTR) UlongToPtr( Cred32.User );
  451. pAuthIdentity->UserLength = Cred32.UserLength ;
  452. pAuthIdentity->Domain = (PWSTR) UlongToPtr( Cred32.Domain );
  453. pAuthIdentity->DomainLength = Cred32.DomainLength ;
  454. pAuthIdentity->Password = (PWSTR) UlongToPtr( Cred32.Password );
  455. pAuthIdentity->PasswordLength = Cred32.PasswordLength ;
  456. pAuthIdentity->Flags = Cred32.Flags ;
  457. }
  458. CredSize = sizeof(SEC_WINNT_AUTH_IDENTITY_W);
  459. }
  460. if ((pAuthIdentity->Flags & SEC_WINNT_AUTH_IDENTITY_ANSI) != 0)
  461. {
  462. DoUnicode = FALSE;
  463. //
  464. // Turn off the marshalled flag because we don't support marshalling
  465. // with ansi.
  466. //
  467. pAuthIdentity->Flags &= ~SEC_WINNT_AUTH_IDENTITY_MARSHALLED;
  468. }
  469. else if ((pAuthIdentity->Flags & SEC_WINNT_AUTH_IDENTITY_UNICODE) == 0)
  470. {
  471. Status = SEC_E_INVALID_TOKEN;
  472. SspPrint((SSP_CRITICAL,"SpAcquireCredentialsHandle, Error from pAuthIdentity->Flags is 0x%lx\n", pAuthIdentity->Flags));
  473. goto Cleanup;
  474. }
  475. // This is the only place where we can figure out whether null
  476. // session was requested
  477. if ((pAuthIdentity->UserLength == 0) &&
  478. (pAuthIdentity->DomainLength == 0) &&
  479. (pAuthIdentity->PasswordLength == 0) &&
  480. (pAuthIdentity->User != NULL) &&
  481. (pAuthIdentity->Domain != NULL) &&
  482. (pAuthIdentity->Password != NULL))
  483. {
  484. NewCredentialUseFlags |= NTLM_CRED_NULLSESSION;
  485. }
  486. //
  487. // Copy over the strings
  488. //
  489. if( (pAuthIdentity->Flags & SEC_WINNT_AUTH_IDENTITY_MARSHALLED) != 0 ) {
  490. ULONG TmpCredentialSize;
  491. ULONG_PTR EndOfCreds;
  492. ULONG_PTR TmpUser;
  493. ULONG_PTR TmpDomain;
  494. ULONG_PTR TmpPassword;
  495. if( pAuthIdentity->UserLength > UNLEN ||
  496. pAuthIdentity->PasswordLength > PWLEN ||
  497. pAuthIdentity->DomainLength > DNS_MAX_NAME_LENGTH ) {
  498. SspPrint((SSP_CRITICAL,"Supplied credentials illegal length.\n"));
  499. Status = STATUS_INVALID_PARAMETER;
  500. goto Cleanup;
  501. }
  502. //
  503. // The callers can set the length of field to n chars, but they
  504. // will really occupy n+1 chars (null-terminator).
  505. //
  506. TmpCredentialSize = CredSize +
  507. ( pAuthIdentity->UserLength +
  508. pAuthIdentity->DomainLength +
  509. pAuthIdentity->PasswordLength +
  510. (((pAuthIdentity->User != NULL) ? 1 : 0) +
  511. ((pAuthIdentity->Domain != NULL) ? 1 : 0) +
  512. ((pAuthIdentity->Password != NULL) ? 1 : 0)) ) * sizeof(WCHAR);
  513. EndOfCreds = (ULONG_PTR) AuthorizationData + TmpCredentialSize;
  514. //
  515. // Verify that all the offsets are valid and no overflow will happen
  516. //
  517. TmpUser = (ULONG_PTR) pAuthIdentity->User;
  518. if ((TmpUser != NULL) &&
  519. ( (TmpUser < (ULONG_PTR) AuthorizationData) ||
  520. (TmpUser > EndOfCreds) ||
  521. ((TmpUser + (pAuthIdentity->UserLength) * sizeof(WCHAR)) > EndOfCreds ) ||
  522. ((TmpUser + (pAuthIdentity->UserLength * sizeof(WCHAR))) < TmpUser)))
  523. {
  524. SspPrint((SSP_CRITICAL,"Username in supplied credentials has invalid pointer or length.\n"));
  525. Status = STATUS_INVALID_PARAMETER;
  526. goto Cleanup;
  527. }
  528. TmpDomain = (ULONG_PTR) pAuthIdentity->Domain;
  529. if ((TmpDomain != NULL) &&
  530. ( (TmpDomain < (ULONG_PTR) AuthorizationData) ||
  531. (TmpDomain > EndOfCreds) ||
  532. ((TmpDomain + (pAuthIdentity->DomainLength) * sizeof(WCHAR)) > EndOfCreds ) ||
  533. ((TmpDomain + (pAuthIdentity->DomainLength * sizeof(WCHAR))) < TmpDomain)))
  534. {
  535. SspPrint((SSP_CRITICAL,"Domainname in supplied credentials has invalid pointer or length.\n"));
  536. Status = STATUS_INVALID_PARAMETER;
  537. goto Cleanup;
  538. }
  539. TmpPassword = (ULONG_PTR) pAuthIdentity->Password;
  540. if ((TmpPassword != NULL) &&
  541. ( (TmpPassword < (ULONG_PTR) AuthorizationData) ||
  542. (TmpPassword > EndOfCreds) ||
  543. ((TmpPassword + (pAuthIdentity->PasswordLength) * sizeof(WCHAR)) > EndOfCreds ) ||
  544. ((TmpPassword + (pAuthIdentity->PasswordLength * sizeof(WCHAR))) < TmpPassword)))
  545. {
  546. SspPrint((SSP_CRITICAL,"Password in supplied credentials has invalid pointer or length.\n"));
  547. Status = STATUS_INVALID_PARAMETER;
  548. goto Cleanup;
  549. }
  550. //
  551. // Allocate a chunk of memory for the credentials
  552. //
  553. TmpCredentials = (PSEC_WINNT_AUTH_IDENTITY_W) NtLmAllocate(TmpCredentialSize - Offset);
  554. if (TmpCredentials == NULL)
  555. {
  556. Status = STATUS_INSUFFICIENT_RESOURCES;
  557. goto Cleanup;
  558. }
  559. //
  560. // Copy the credentials from the client
  561. //
  562. Status = LsaFunctions->CopyFromClientBuffer(
  563. NULL,
  564. TmpCredentialSize - Offset,
  565. TmpCredentials,
  566. (PUCHAR) AuthorizationData + Offset
  567. );
  568. if (!NT_SUCCESS(Status))
  569. {
  570. SspPrint((SSP_CRITICAL,"Failed to copy whole auth identity\n"));
  571. goto Cleanup;
  572. }
  573. //
  574. // Now convert all the offsets to pointers.
  575. //
  576. if (TmpCredentials->User != NULL)
  577. {
  578. USHORT cbUser;
  579. TmpCredentials->User = (LPWSTR) RtlOffsetToPointer(
  580. TmpCredentials->User,
  581. (PUCHAR) TmpCredentials - (PUCHAR) AuthorizationData - Offset
  582. );
  583. ASSERT( (TmpCredentials->UserLength*sizeof(WCHAR)) <= 0xFFFF );
  584. cbUser = (USHORT)(TmpCredentials->UserLength * sizeof(WCHAR));
  585. UserName.Buffer = (PWSTR)NtLmAllocate( cbUser );
  586. if (UserName.Buffer == NULL ) {
  587. Status = STATUS_INSUFFICIENT_RESOURCES;
  588. goto Cleanup;
  589. }
  590. CopyMemory( UserName.Buffer, TmpCredentials->User, cbUser );
  591. UserName.Length = cbUser;
  592. UserName.MaximumLength = cbUser;
  593. }
  594. if (TmpCredentials->Domain != NULL)
  595. {
  596. USHORT cbDomain;
  597. TmpCredentials->Domain = (LPWSTR) RtlOffsetToPointer(
  598. TmpCredentials->Domain,
  599. (PUCHAR) TmpCredentials - (PUCHAR) AuthorizationData - Offset
  600. );
  601. ASSERT( (TmpCredentials->DomainLength*sizeof(WCHAR)) <= 0xFFFF );
  602. cbDomain = (USHORT)(TmpCredentials->DomainLength * sizeof(WCHAR));
  603. DomainName.Buffer = (PWSTR)NtLmAllocate( cbDomain );
  604. if (DomainName.Buffer == NULL ) {
  605. Status = STATUS_INSUFFICIENT_RESOURCES;
  606. goto Cleanup;
  607. }
  608. CopyMemory( DomainName.Buffer, TmpCredentials->Domain, cbDomain );
  609. DomainName.Length = cbDomain;
  610. DomainName.MaximumLength = cbDomain;
  611. }
  612. if (TmpCredentials->Password != NULL)
  613. {
  614. USHORT cbPassword;
  615. TmpCredentials->Password = (LPWSTR) RtlOffsetToPointer(
  616. TmpCredentials->Password,
  617. (PUCHAR) TmpCredentials - (PUCHAR) AuthorizationData - Offset
  618. );
  619. ASSERT( (TmpCredentials->PasswordLength*sizeof(WCHAR)) <= 0xFFFF );
  620. cbPassword = (USHORT)(TmpCredentials->PasswordLength * sizeof(WCHAR));
  621. Password.Buffer = (PWSTR)NtLmAllocate( cbPassword );
  622. if (Password.Buffer == NULL ) {
  623. ZeroMemory( TmpCredentials->Password, cbPassword );
  624. Status = STATUS_INSUFFICIENT_RESOURCES;
  625. goto Cleanup;
  626. }
  627. CopyMemory( Password.Buffer, TmpCredentials->Password, cbPassword );
  628. Password.Length = cbPassword;
  629. Password.MaximumLength = cbPassword;
  630. ZeroMemory( TmpCredentials->Password, cbPassword );
  631. }
  632. } else {
  633. if (pAuthIdentity->Password != NULL)
  634. {
  635. Status = CopyClientString(
  636. pAuthIdentity->Password,
  637. pAuthIdentity->PasswordLength,
  638. DoUnicode,
  639. &Password
  640. );
  641. if (!NT_SUCCESS(Status))
  642. {
  643. SspPrint((SSP_CRITICAL,"SpAcquireCredentialsHandle, Error from CopyClientString is 0x%lx\n", Status));
  644. goto Cleanup;
  645. }
  646. }
  647. if (pAuthIdentity->User != NULL)
  648. {
  649. Status = CopyClientString(
  650. pAuthIdentity->User,
  651. pAuthIdentity->UserLength,
  652. DoUnicode,
  653. &UserName
  654. );
  655. if (!NT_SUCCESS(Status))
  656. {
  657. SspPrint((SSP_CRITICAL, "SpAcquireCredentialsHandle, Error from CopyClientString is 0x%lx\n", Status));
  658. goto Cleanup;
  659. }
  660. }
  661. if (pAuthIdentity->Domain != NULL)
  662. {
  663. Status = CopyClientString(
  664. pAuthIdentity->Domain,
  665. pAuthIdentity->DomainLength,
  666. DoUnicode,
  667. &DomainName
  668. );
  669. if (!NT_SUCCESS(Status))
  670. {
  671. SspPrint((SSP_CRITICAL, "SpAcquireCredentialsHandle, Error from CopyClientString is 0x%lx\n", Status));
  672. goto Cleanup;
  673. }
  674. //
  675. // Make sure that the domain name length is not greater
  676. // than the allowed dns domain name
  677. //
  678. if (DomainName.Length > DNS_MAX_NAME_LENGTH * sizeof(WCHAR))
  679. {
  680. SspPrint((SSP_CRITICAL, "SpAcquireCredentialsHandle: Invalid supplied domain name %wZ\n",
  681. &DomainName ));
  682. Status = SEC_E_UNKNOWN_CREDENTIALS;
  683. goto Cleanup;
  684. }
  685. }
  686. }
  687. } // AuthorizationData != NULL
  688. #if 0
  689. //
  690. // Handle UPN and composite NETBIOS syntax
  691. //
  692. {
  693. UNICODE_STRING User = UserName;
  694. UNICODE_STRING Domain = DomainName;
  695. Status =
  696. NtLmParseName(
  697. &User,
  698. &Domain,
  699. TRUE); // If successful, this will allocate and free buffers
  700. if(NT_SUCCESS(Status)){
  701. UserName = User;
  702. DomainName = Domain;
  703. }
  704. }
  705. #endif
  706. if( Password.Length != 0 )
  707. {
  708. UNICODE_STRING OldPassword = Password;
  709. Status = NtLmDuplicatePassword( &Password, &OldPassword );
  710. if(!NT_SUCCESS(Status))
  711. {
  712. goto Cleanup;
  713. }
  714. ZeroMemory( OldPassword.Buffer, OldPassword.Length );
  715. NtLmFree( OldPassword.Buffer );
  716. }
  717. Status = SsprAcquireCredentialHandle(
  718. LogonIdToUse,
  719. &ClientInfo,
  720. NewCredentialUseFlags,
  721. CredentialHandle,
  722. ExpirationTime,
  723. &DomainName,
  724. &UserName,
  725. &Password );
  726. if (!NT_SUCCESS(Status))
  727. {
  728. SspPrint((SSP_CRITICAL, "SpAcquireCredentialsHandle, Error from SsprAcquireCredentialsHandle is 0x%lx\n", Status));
  729. goto Cleanup;
  730. }
  731. // These will be kept in the Credential structure and freed
  732. // when the Credential structure is freed
  733. if (DomainName.Buffer != NULL)
  734. {
  735. DomainName.Buffer = NULL;
  736. }
  737. if (UserName.Buffer != NULL)
  738. {
  739. UserName.Buffer = NULL;
  740. }
  741. if (Password.Buffer != NULL)
  742. {
  743. Password.Buffer = NULL;
  744. }
  745. Cleanup:
  746. if (TmpCredentials != NULL)
  747. {
  748. NtLmFree(TmpCredentials);
  749. }
  750. if (DomainName.Buffer != NULL)
  751. {
  752. NtLmFree(DomainName.Buffer);
  753. }
  754. if (UserName.Buffer != NULL)
  755. {
  756. NtLmFree(UserName.Buffer);
  757. }
  758. if (Password.Buffer != NULL)
  759. {
  760. ZeroMemory(Password.Buffer, Password.Length);
  761. NtLmFree(Password.Buffer);
  762. }
  763. if (pAuthIdentityEx != NULL)
  764. {
  765. NtLmFree(pAuthIdentityEx);
  766. }
  767. SspPrint((SSP_API, "Leaving SpAcquireCredentialsHandle, Status is %d\n", Status));
  768. return(SspNtStatusToSecStatus(Status, SEC_E_INTERNAL_ERROR));
  769. }
  770. //+-------------------------------------------------------------------------
  771. //
  772. // Function: SpFreeCredentialsHandle
  773. //
  774. // Synopsis: Frees a credential created by AcquireCredentialsHandle.
  775. //
  776. // Effects: Unlinks the credential from the global list and the list
  777. // for this client.
  778. //
  779. // Arguments: CredentialHandle - Handle to the credential to free
  780. // (acquired through AcquireCredentialsHandle)
  781. //
  782. // Requires:
  783. //
  784. // Returns: STATUS_SUCCESS on success,
  785. // SEC_E_INVALID_HANDLE if the handle is not valid
  786. //
  787. // Notes:
  788. //
  789. //
  790. //--------------------------------------------------------------------------
  791. NTSTATUS NTAPI
  792. SpFreeCredentialsHandle(
  793. IN ULONG_PTR CredentialHandle
  794. )
  795. {
  796. SspPrint((SSP_API, "Entering SpFreeCredentialsHandle\n"));
  797. NTSTATUS Status = STATUS_SUCCESS;
  798. PSSP_CREDENTIAL Credential;
  799. //
  800. // Find the referenced credential and delink it.
  801. //
  802. Status = SspCredentialReferenceCredential(
  803. CredentialHandle,
  804. TRUE, // remove the instance of the credential
  805. &Credential );
  806. if ( !NT_SUCCESS( Status ) ) {
  807. SspPrint((SSP_CRITICAL, "SpFreeCredentialsHandle, Error from SspCredentialReferenceCredential is 0x%lx\n", Status));
  808. goto Cleanup;
  809. }
  810. //
  811. // Dereferencing the Credential will remove the client's reference
  812. // to it, causing it to be rundown if nobody else is using it.
  813. //
  814. SspCredentialDereferenceCredential( Credential );
  815. Cleanup:
  816. //
  817. // Catch spurious INVALID_HANDLE being returned to RPC.
  818. //
  819. ASSERT( NT_SUCCESS(Status) );
  820. SspPrint((SSP_API, "Leaving SpFreeCredentialsHandle\n"));
  821. return(SspNtStatusToSecStatus(Status, SEC_E_INTERNAL_ERROR));
  822. }
  823. NTSTATUS
  824. NTAPI
  825. SpQueryCredentialsAttributes(
  826. IN LSA_SEC_HANDLE CredentialHandle,
  827. IN ULONG CredentialAttribute,
  828. IN OUT PVOID Buffer
  829. )
  830. {
  831. PSSP_CREDENTIAL Credential = NULL;
  832. SecPkgCredentials_NamesW Names;
  833. LUID LogonId;
  834. BOOLEAN ActiveLogonsAreLocked = FALSE;
  835. LPWSTR ContextNames = NULL;
  836. LPWSTR Where;
  837. LPWSTR UserName = NULL;
  838. LPWSTR DomainName = NULL;
  839. DWORD cchUserName;
  840. DWORD cchDomainName;
  841. ULONG Length;
  842. BOOLEAN CalledLsaLookup = FALSE;
  843. PLSAPR_REFERENCED_DOMAIN_LIST ReferencedDomain = NULL;
  844. LSAPR_TRANSLATED_NAMES ReferencedUser;
  845. #if _WIN64
  846. SECPKG_CALL_INFO CallInfo;
  847. #endif
  848. NTSTATUS Status = STATUS_SUCCESS;
  849. SspPrint((SSP_API,"In SpQueryCredentialsAttributes\n"));
  850. Names.sUserName = NULL;
  851. if (CredentialAttribute != SECPKG_CRED_ATTR_NAMES)
  852. {
  853. SspPrint((SSP_MISC, "Asked for illegal info level in QueryCredAttr: %d\n",
  854. CredentialAttribute));
  855. Status = STATUS_INVALID_PARAMETER;
  856. goto Cleanup;
  857. }
  858. Status = SspCredentialReferenceCredential(
  859. CredentialHandle,
  860. FALSE,
  861. &Credential );
  862. if ( !NT_SUCCESS( Status ) ) {
  863. SspPrint((SSP_CRITICAL, "SpQueryCredentialsAttributes, Error from SspCredentialReferenceCredential is 0x%lx\n", Status));
  864. goto Cleanup;
  865. }
  866. #if _WIN64
  867. if(!LsaFunctions->GetCallInfo( &CallInfo ))
  868. {
  869. Status = STATUS_INTERNAL_ERROR;
  870. SspPrint((SSP_CRITICAL, "SpQueryCredentialsAttributes, failed to get callinfo 0x%lx\n", Status));
  871. goto Cleanup;
  872. }
  873. #endif
  874. //
  875. // The logon id of the credential is constant, so it is o.k.
  876. // to use it without locking the credential
  877. //
  878. LogonId = Credential->LogonId;
  879. //
  880. // credentials were either specified when cred built, or, they were defaulted.
  881. //
  882. if( Credential->UserName.Buffer == NULL &&
  883. Credential->DomainName.Buffer == NULL )
  884. {
  885. PACTIVE_LOGON *ActiveLogon, Logon = NULL;
  886. //
  887. // defaulted creds: pickup info from active logon table.
  888. //
  889. NlpLockActiveLogonsRead();
  890. ActiveLogonsAreLocked = TRUE;
  891. if (NlpFindActiveLogon (
  892. &LogonId,
  893. &ActiveLogon))
  894. {
  895. //
  896. // found an active logon entry.
  897. //
  898. Logon = *ActiveLogon;
  899. UserName = Logon->UserName.Buffer;
  900. cchUserName = Logon->UserName.Length / sizeof(WCHAR);
  901. DomainName = Logon->LogonDomainName.Buffer;
  902. cchDomainName = Logon->LogonDomainName.Length / sizeof(WCHAR);
  903. } else {
  904. PTOKEN_USER pTokenInfo;
  905. BYTE FastBuffer[ 256 ];
  906. DWORD cbTokenInfo;
  907. SID_NAME_USE snu;
  908. HANDLE ClientTokenHandle;
  909. BOOL fSuccess = FALSE;
  910. NlpUnlockActiveLogons();
  911. ActiveLogonsAreLocked = FALSE;
  912. //
  913. // get a token associated with the logon session.
  914. //
  915. Status = LsaFunctions->OpenTokenByLogonId(
  916. &LogonId,
  917. &ClientTokenHandle
  918. );
  919. if(!NT_SUCCESS(Status))
  920. {
  921. SspPrint(( SSP_CRITICAL,
  922. "SpQueryCredentialsAttributes: "
  923. "Could not open client token 0x%lx\n",
  924. Status ));
  925. goto Cleanup;
  926. }
  927. //
  928. // get Sid associated with credential.
  929. //
  930. cbTokenInfo = sizeof(FastBuffer);
  931. pTokenInfo = (PTOKEN_USER)FastBuffer;
  932. fSuccess = GetTokenInformation(
  933. ClientTokenHandle,
  934. TokenUser,
  935. pTokenInfo,
  936. cbTokenInfo,
  937. &cbTokenInfo
  938. );
  939. CloseHandle( ClientTokenHandle );
  940. if( fSuccess ) {
  941. LSAPR_SID_ENUM_BUFFER SidEnumBuffer;
  942. LSAPR_SID_INFORMATION SidInfo;
  943. ULONG MappedCount;
  944. SidEnumBuffer.Entries = 1;
  945. SidEnumBuffer.SidInfo = &SidInfo;
  946. SidInfo.Sid = (LSAPR_SID*)pTokenInfo->User.Sid;
  947. ZeroMemory( &ReferencedUser, sizeof(ReferencedUser) );
  948. CalledLsaLookup = TRUE;
  949. Status = LsarLookupSids(
  950. NtLmGlobalPolicyHandle,
  951. &SidEnumBuffer,
  952. &ReferencedDomain,
  953. &ReferencedUser,
  954. LsapLookupWksta,
  955. &MappedCount
  956. );
  957. if( !NT_SUCCESS( Status ) ||
  958. (MappedCount == 0) ||
  959. (ReferencedUser.Entries == 0) ||
  960. (ReferencedDomain == NULL) ||
  961. (ReferencedDomain->Entries == 0)
  962. ) {
  963. fSuccess = FALSE;
  964. } else {
  965. LONG Index = ReferencedUser.Names->DomainIndex;
  966. UserName = ReferencedUser.Names->Name.Buffer;
  967. cchUserName = ReferencedUser.Names->Name.Length / sizeof(WCHAR);
  968. DomainName = ReferencedDomain->Domains[Index].Name.Buffer;
  969. cchDomainName = ReferencedDomain->Domains[Index].Name.Length / sizeof(WCHAR);
  970. }
  971. }
  972. if( !fSuccess )
  973. {
  974. Status = STATUS_NO_SUCH_LOGON_SESSION;
  975. SspPrint(( SSP_CRITICAL, "SpQueryCredentialsAtributes, NlpFindActiveLogon returns FALSE\n"));
  976. goto Cleanup;
  977. }
  978. }
  979. } else {
  980. //
  981. // specified creds.
  982. //
  983. UserName = Credential->UserName.Buffer;
  984. cchUserName = Credential->UserName.Length / sizeof(WCHAR);
  985. DomainName = Credential->DomainName.Buffer;
  986. cchDomainName = Credential->DomainName.Length / sizeof(WCHAR);
  987. }
  988. Length = (cchUserName + 1 + cchDomainName + 1) * sizeof(WCHAR);
  989. ContextNames = (LPWSTR)NtLmAllocate( Length );
  990. if( ContextNames == NULL ) {
  991. goto Cleanup;
  992. }
  993. Where = ContextNames;
  994. if( DomainName) {
  995. RtlCopyMemory( ContextNames, DomainName, cchDomainName * sizeof(WCHAR) );
  996. ContextNames[ cchDomainName ] = L'\\';
  997. Where += (cchDomainName+1);
  998. }
  999. if( UserName ) {
  1000. RtlCopyMemory( Where, UserName, cchUserName * sizeof(WCHAR) );
  1001. }
  1002. Where[ cchUserName ] = L'\0';
  1003. if (ActiveLogonsAreLocked)
  1004. {
  1005. NlpUnlockActiveLogons();
  1006. ActiveLogonsAreLocked = FALSE;
  1007. }
  1008. //
  1009. // Allocate memory in the client's address space
  1010. //
  1011. Status = LsaFunctions->AllocateClientBuffer(
  1012. NULL,
  1013. Length,
  1014. (PVOID *) &Names.sUserName
  1015. );
  1016. if (!NT_SUCCESS(Status))
  1017. {
  1018. goto Cleanup;
  1019. }
  1020. //
  1021. // Copy the string there
  1022. //
  1023. Status = LsaFunctions->CopyToClientBuffer(
  1024. NULL,
  1025. Length,
  1026. Names.sUserName,
  1027. ContextNames
  1028. );
  1029. if (!NT_SUCCESS(Status))
  1030. {
  1031. goto Cleanup;
  1032. }
  1033. //
  1034. // Now copy the address of the string there
  1035. //
  1036. #if _WIN64
  1037. if( CallInfo.Attributes & SECPKG_CALL_WOWCLIENT )
  1038. {
  1039. Status = LsaFunctions->CopyToClientBuffer(
  1040. NULL,
  1041. sizeof(ULONG),
  1042. Buffer,
  1043. &Names
  1044. );
  1045. } else {
  1046. Status = LsaFunctions->CopyToClientBuffer(
  1047. NULL,
  1048. sizeof(Names),
  1049. Buffer,
  1050. &Names
  1051. );
  1052. }
  1053. #else
  1054. Status = LsaFunctions->CopyToClientBuffer(
  1055. NULL,
  1056. sizeof(Names),
  1057. Buffer,
  1058. &Names
  1059. );
  1060. #endif
  1061. if (!NT_SUCCESS(Status))
  1062. {
  1063. goto Cleanup;
  1064. }
  1065. Cleanup:
  1066. if (ActiveLogonsAreLocked)
  1067. {
  1068. NlpUnlockActiveLogons();
  1069. }
  1070. if( Credential != NULL ) {
  1071. SspCredentialDereferenceCredential( Credential );
  1072. }
  1073. if( CalledLsaLookup ) {
  1074. if( ReferencedDomain ) {
  1075. LsaIFree_LSAPR_REFERENCED_DOMAIN_LIST( ReferencedDomain );
  1076. }
  1077. LsaIFree_LSAPR_TRANSLATED_NAMES( &ReferencedUser );
  1078. }
  1079. if (!NT_SUCCESS(Status))
  1080. {
  1081. if (Names.sUserName != NULL)
  1082. {
  1083. (VOID) LsaFunctions->FreeClientBuffer(
  1084. NULL,
  1085. Names.sUserName
  1086. );
  1087. }
  1088. }
  1089. if( ContextNames ) {
  1090. NtLmFree( ContextNames );
  1091. }
  1092. SspPrint((SSP_API, "Leaving SpQueryCredentialsAttributes\n"));
  1093. return(SspNtStatusToSecStatus(Status, SEC_E_INTERNAL_ERROR));
  1094. }
  1095. NTSTATUS NTAPI
  1096. SpSaveCredentials(
  1097. IN ULONG_PTR CredentialHandle,
  1098. IN PSecBuffer Credentials
  1099. )
  1100. {
  1101. UNREFERENCED_PARAMETER(CredentialHandle);
  1102. UNREFERENCED_PARAMETER(Credentials);
  1103. SspPrint((SSP_API,"In SpSaveCredentials\n"));
  1104. return(SEC_E_UNSUPPORTED_FUNCTION);
  1105. }
  1106. NTSTATUS NTAPI
  1107. SpGetCredentials(
  1108. IN ULONG_PTR CredentialHandle,
  1109. IN OUT PSecBuffer Credentials
  1110. )
  1111. {
  1112. UNREFERENCED_PARAMETER(CredentialHandle);
  1113. UNREFERENCED_PARAMETER(Credentials);
  1114. SspPrint((SSP_API,"In SpGetCredentials\n"));
  1115. return(SEC_E_UNSUPPORTED_FUNCTION);
  1116. }
  1117. NTSTATUS NTAPI
  1118. SpDeleteCredentials(
  1119. IN ULONG_PTR CredentialHandle,
  1120. IN PSecBuffer Key
  1121. )
  1122. {
  1123. UNREFERENCED_PARAMETER(CredentialHandle);
  1124. UNREFERENCED_PARAMETER(Key);
  1125. SspPrint((SSP_API,"In SpDeleteCredentials\n"));
  1126. return(SEC_E_UNSUPPORTED_FUNCTION);
  1127. }