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.

1408 lines
44 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. // Got to have an impersonation level token in order to call ACH.
  349. // This check used to be in lsa, but moved here to enable
  350. // some S4Uproxy scenarios to work w/o tcb.
  351. //
  352. if (ClientInfo.ImpersonationLevel <= SecurityIdentification)
  353. {
  354. SspPrint((SSP_CRITICAL, "Trying to acquire credentials with an token no better than SecurityIdentification\n"));
  355. Status = SEC_E_NO_CREDENTIALS;
  356. goto Cleanup;
  357. }
  358. //
  359. // Copy over the authorization data into out address
  360. // space and make a local copy of the strings.
  361. //
  362. if (AuthorizationData != NULL)
  363. {
  364. SECPKG_CALL_INFO CallInfo ;
  365. SEC_WINNT_AUTH_IDENTITY32 Cred32 = {0};
  366. SEC_WINNT_AUTH_IDENTITY_EX32 CredEx32 ;
  367. if(!LsaFunctions->GetCallInfo( &CallInfo ))
  368. {
  369. Status = STATUS_INTERNAL_ERROR;
  370. SspPrint((SSP_CRITICAL,"SpAcquireCredentialsHandle, Error from LsaFunctions->GetCallInfo is 0x%lx\n", Status));
  371. goto Cleanup;
  372. }
  373. pAuthIdentityEx = (PSEC_WINNT_AUTH_IDENTITY_EXW) NtLmAllocate(sizeof(SEC_WINNT_AUTH_IDENTITY_EXW));
  374. if (pAuthIdentityEx != NULL)
  375. {
  376. if ( CallInfo.Attributes & SECPKG_CALL_WOWCLIENT )
  377. {
  378. Status = LsaFunctions->CopyFromClientBuffer(
  379. NULL,
  380. sizeof( Cred32 ),
  381. pAuthIdentityEx,
  382. AuthorizationData );
  383. if ( NT_SUCCESS( Status ) )
  384. {
  385. RtlCopyMemory( &Cred32, pAuthIdentityEx, sizeof( Cred32 ) );
  386. }
  387. }
  388. else
  389. {
  390. Status = LsaFunctions->CopyFromClientBuffer(
  391. NULL,
  392. sizeof(SEC_WINNT_AUTH_IDENTITY),
  393. pAuthIdentityEx,
  394. AuthorizationData);
  395. }
  396. if (!NT_SUCCESS(Status))
  397. {
  398. SspPrint((SSP_CRITICAL,"SpAcquireCredentialsHandle, Error from LsaFunctions->CopyFromClientBuffer is 0x%lx\n", Status));
  399. goto Cleanup;
  400. }
  401. }
  402. else
  403. {
  404. Status = STATUS_INSUFFICIENT_RESOURCES;
  405. SspPrint((SSP_CRITICAL,"SpAcquireCredentialsHandle, Error from NtLmAllocate is 0x%lx\n", Status));
  406. goto Cleanup;
  407. }
  408. //
  409. // Check for the ex version
  410. //
  411. if (pAuthIdentityEx->Version == SEC_WINNT_AUTH_IDENTITY_VERSION)
  412. {
  413. //
  414. // It's an EX structure.
  415. //
  416. if ( CallInfo.Attributes & SECPKG_CALL_WOWCLIENT )
  417. {
  418. Status = LsaFunctions->CopyFromClientBuffer(
  419. NULL,
  420. sizeof( CredEx32 ),
  421. &CredEx32,
  422. AuthorizationData );
  423. if ( NT_SUCCESS( Status ) )
  424. {
  425. pAuthIdentityEx->Version = CredEx32.Version ;
  426. pAuthIdentityEx->Length = (CredEx32.Length < sizeof( SEC_WINNT_AUTH_IDENTITY_EX ) ?
  427. (ULONG) sizeof( SEC_WINNT_AUTH_IDENTITY_EX ) : CredEx32.Length );
  428. pAuthIdentityEx->User = (PWSTR) UlongToPtr( CredEx32.User );
  429. pAuthIdentityEx->UserLength = CredEx32.UserLength ;
  430. pAuthIdentityEx->Domain = (PWSTR) UlongToPtr( CredEx32.Domain );
  431. pAuthIdentityEx->DomainLength = CredEx32.DomainLength ;
  432. pAuthIdentityEx->Password = (PWSTR) UlongToPtr( CredEx32.Password );
  433. pAuthIdentityEx->PasswordLength = CredEx32.PasswordLength ;
  434. pAuthIdentityEx->Flags = CredEx32.Flags ;
  435. pAuthIdentityEx->PackageList = (PWSTR) UlongToPtr( CredEx32.PackageList );
  436. pAuthIdentityEx->PackageListLength = CredEx32.PackageListLength ;
  437. }
  438. }
  439. else
  440. {
  441. Status = LsaFunctions->CopyFromClientBuffer(
  442. NULL,
  443. sizeof(SEC_WINNT_AUTH_IDENTITY_EXW),
  444. pAuthIdentityEx,
  445. AuthorizationData);
  446. }
  447. if (!NT_SUCCESS(Status))
  448. {
  449. SspPrint((SSP_CRITICAL,"SpAcquireCredentialsHandle, Error from LsaFunctions->CopyFromClientBuffer is 0x%lx\n", Status));
  450. goto Cleanup;
  451. }
  452. pAuthIdentity = (PSEC_WINNT_AUTH_IDENTITY) &pAuthIdentityEx->User;
  453. CredSize = pAuthIdentityEx->Length;
  454. Offset = FIELD_OFFSET(SEC_WINNT_AUTH_IDENTITY_EXW, User);
  455. }
  456. else
  457. {
  458. pAuthIdentity = (PSEC_WINNT_AUTH_IDENTITY_W) pAuthIdentityEx;
  459. if ( CallInfo.Attributes & SECPKG_CALL_WOWCLIENT )
  460. {
  461. pAuthIdentity->User = (PWSTR) UlongToPtr( Cred32.User );
  462. pAuthIdentity->UserLength = Cred32.UserLength ;
  463. pAuthIdentity->Domain = (PWSTR) UlongToPtr( Cred32.Domain );
  464. pAuthIdentity->DomainLength = Cred32.DomainLength ;
  465. pAuthIdentity->Password = (PWSTR) UlongToPtr( Cred32.Password );
  466. pAuthIdentity->PasswordLength = Cred32.PasswordLength ;
  467. pAuthIdentity->Flags = Cred32.Flags ;
  468. }
  469. CredSize = sizeof(SEC_WINNT_AUTH_IDENTITY_W);
  470. }
  471. if ((pAuthIdentity->Flags & SEC_WINNT_AUTH_IDENTITY_ANSI) != 0)
  472. {
  473. DoUnicode = FALSE;
  474. //
  475. // Turn off the marshalled flag because we don't support marshalling
  476. // with ansi.
  477. //
  478. pAuthIdentity->Flags &= ~SEC_WINNT_AUTH_IDENTITY_MARSHALLED;
  479. }
  480. else if ((pAuthIdentity->Flags & SEC_WINNT_AUTH_IDENTITY_UNICODE) == 0)
  481. {
  482. Status = SEC_E_INVALID_TOKEN;
  483. SspPrint((SSP_CRITICAL,"SpAcquireCredentialsHandle, Error from pAuthIdentity->Flags is 0x%lx\n", pAuthIdentity->Flags));
  484. goto Cleanup;
  485. }
  486. // This is the only place where we can figure out whether null
  487. // session was requested
  488. if ((pAuthIdentity->UserLength == 0) &&
  489. (pAuthIdentity->DomainLength == 0) &&
  490. (pAuthIdentity->PasswordLength == 0) &&
  491. (pAuthIdentity->User != NULL) &&
  492. (pAuthIdentity->Domain != NULL) &&
  493. (pAuthIdentity->Password != NULL))
  494. {
  495. NewCredentialUseFlags |= NTLM_CRED_NULLSESSION;
  496. }
  497. if(
  498. // UserName may include a marshalled credential > UNLEN
  499. pAuthIdentity->UserLength > 0xFFFC || // MAX_USHORT - NULL
  500. pAuthIdentity->PasswordLength > PWLEN ||
  501. pAuthIdentity->DomainLength > DNS_MAX_NAME_LENGTH ) {
  502. SspPrint((SSP_CRITICAL,"Supplied credentials illegal length.\n"));
  503. Status = STATUS_INVALID_PARAMETER;
  504. goto Cleanup;
  505. }
  506. //
  507. // Copy over the strings
  508. //
  509. if( (pAuthIdentity->Flags & SEC_WINNT_AUTH_IDENTITY_MARSHALLED) != 0 ) {
  510. ULONG TmpCredentialSize;
  511. ULONG_PTR EndOfCreds;
  512. ULONG_PTR TmpUser;
  513. ULONG_PTR TmpDomain;
  514. ULONG_PTR TmpPassword;
  515. //
  516. // The callers can set the length of field to n chars, but they
  517. // will really occupy n+1 chars (null-terminator).
  518. //
  519. TmpCredentialSize = CredSize +
  520. ( pAuthIdentity->UserLength +
  521. pAuthIdentity->DomainLength +
  522. pAuthIdentity->PasswordLength +
  523. (((pAuthIdentity->User != NULL) ? 1 : 0) +
  524. ((pAuthIdentity->Domain != NULL) ? 1 : 0) +
  525. ((pAuthIdentity->Password != NULL) ? 1 : 0)) ) * (ULONG) sizeof(WCHAR);
  526. EndOfCreds = (ULONG_PTR) AuthorizationData + TmpCredentialSize;
  527. //
  528. // Verify that all the offsets are valid and no overflow will happen
  529. //
  530. TmpUser = (ULONG_PTR) pAuthIdentity->User;
  531. if ((TmpUser != NULL) &&
  532. ( (TmpUser < (ULONG_PTR) AuthorizationData) ||
  533. (TmpUser > EndOfCreds) ||
  534. ((TmpUser + (pAuthIdentity->UserLength) * sizeof(WCHAR)) > EndOfCreds ) ||
  535. ((TmpUser + (pAuthIdentity->UserLength * sizeof(WCHAR))) < TmpUser)))
  536. {
  537. SspPrint((SSP_CRITICAL,"Username in supplied credentials has invalid pointer or length.\n"));
  538. Status = STATUS_INVALID_PARAMETER;
  539. goto Cleanup;
  540. }
  541. TmpDomain = (ULONG_PTR) pAuthIdentity->Domain;
  542. if ((TmpDomain != NULL) &&
  543. ( (TmpDomain < (ULONG_PTR) AuthorizationData) ||
  544. (TmpDomain > EndOfCreds) ||
  545. ((TmpDomain + (pAuthIdentity->DomainLength) * sizeof(WCHAR)) > EndOfCreds ) ||
  546. ((TmpDomain + (pAuthIdentity->DomainLength * sizeof(WCHAR))) < TmpDomain)))
  547. {
  548. SspPrint((SSP_CRITICAL,"Domainname in supplied credentials has invalid pointer or length.\n"));
  549. Status = STATUS_INVALID_PARAMETER;
  550. goto Cleanup;
  551. }
  552. TmpPassword = (ULONG_PTR) pAuthIdentity->Password;
  553. if ((TmpPassword != NULL) &&
  554. ( (TmpPassword < (ULONG_PTR) AuthorizationData) ||
  555. (TmpPassword > EndOfCreds) ||
  556. ((TmpPassword + (pAuthIdentity->PasswordLength) * sizeof(WCHAR)) > EndOfCreds ) ||
  557. ((TmpPassword + (pAuthIdentity->PasswordLength * sizeof(WCHAR))) < TmpPassword)))
  558. {
  559. SspPrint((SSP_CRITICAL,"Password in supplied credentials has invalid pointer or length.\n"));
  560. Status = STATUS_INVALID_PARAMETER;
  561. goto Cleanup;
  562. }
  563. //
  564. // Allocate a chunk of memory for the credentials
  565. //
  566. TmpCredentials = (PSEC_WINNT_AUTH_IDENTITY_W) NtLmAllocate(TmpCredentialSize - Offset);
  567. if (TmpCredentials == NULL)
  568. {
  569. Status = STATUS_INSUFFICIENT_RESOURCES;
  570. goto Cleanup;
  571. }
  572. //
  573. // Copy the credentials from the client
  574. //
  575. Status = LsaFunctions->CopyFromClientBuffer(
  576. NULL,
  577. TmpCredentialSize - Offset,
  578. TmpCredentials,
  579. (PUCHAR) AuthorizationData + Offset
  580. );
  581. if (!NT_SUCCESS(Status))
  582. {
  583. SspPrint((SSP_CRITICAL,"Failed to copy whole auth identity\n"));
  584. goto Cleanup;
  585. }
  586. //
  587. // Now convert all the offsets to pointers.
  588. //
  589. if (TmpCredentials->User != NULL)
  590. {
  591. USHORT cbUser;
  592. TmpCredentials->User = (LPWSTR) RtlOffsetToPointer(
  593. TmpCredentials->User,
  594. (PUCHAR) TmpCredentials - (PUCHAR) AuthorizationData - Offset
  595. );
  596. ASSERT( (TmpCredentials->UserLength*sizeof(WCHAR)) <= 0xFFFF );
  597. cbUser = (USHORT)(TmpCredentials->UserLength * sizeof(WCHAR));
  598. UserName.Buffer = (PWSTR)NtLmAllocate( cbUser );
  599. if (UserName.Buffer == NULL ) {
  600. Status = STATUS_INSUFFICIENT_RESOURCES;
  601. goto Cleanup;
  602. }
  603. CopyMemory( UserName.Buffer, TmpCredentials->User, cbUser );
  604. UserName.Length = cbUser;
  605. UserName.MaximumLength = cbUser;
  606. }
  607. if (TmpCredentials->Domain != NULL)
  608. {
  609. USHORT cbDomain;
  610. TmpCredentials->Domain = (LPWSTR) RtlOffsetToPointer(
  611. TmpCredentials->Domain,
  612. (PUCHAR) TmpCredentials - (PUCHAR) AuthorizationData - Offset
  613. );
  614. ASSERT( (TmpCredentials->DomainLength*sizeof(WCHAR)) <= 0xFFFF );
  615. cbDomain = (USHORT)(TmpCredentials->DomainLength * sizeof(WCHAR));
  616. DomainName.Buffer = (PWSTR)NtLmAllocate( cbDomain );
  617. if (DomainName.Buffer == NULL ) {
  618. Status = STATUS_INSUFFICIENT_RESOURCES;
  619. goto Cleanup;
  620. }
  621. CopyMemory( DomainName.Buffer, TmpCredentials->Domain, cbDomain );
  622. DomainName.Length = cbDomain;
  623. DomainName.MaximumLength = cbDomain;
  624. }
  625. if (TmpCredentials->Password != NULL)
  626. {
  627. USHORT cbPassword;
  628. TmpCredentials->Password = (LPWSTR) RtlOffsetToPointer(
  629. TmpCredentials->Password,
  630. (PUCHAR) TmpCredentials - (PUCHAR) AuthorizationData - Offset
  631. );
  632. ASSERT( (TmpCredentials->PasswordLength*sizeof(WCHAR)) <= 0xFFFF );
  633. cbPassword = (USHORT)(TmpCredentials->PasswordLength * sizeof(WCHAR));
  634. Password.Buffer = (PWSTR)NtLmAllocate( cbPassword );
  635. if (Password.Buffer == NULL ) {
  636. ZeroMemory( TmpCredentials->Password, cbPassword );
  637. Status = STATUS_INSUFFICIENT_RESOURCES;
  638. goto Cleanup;
  639. }
  640. CopyMemory( Password.Buffer, TmpCredentials->Password, cbPassword );
  641. Password.Length = cbPassword;
  642. Password.MaximumLength = cbPassword;
  643. ZeroMemory( TmpCredentials->Password, cbPassword );
  644. }
  645. } else {
  646. if (pAuthIdentity->Password != NULL)
  647. {
  648. Status = CopyClientString(
  649. pAuthIdentity->Password,
  650. pAuthIdentity->PasswordLength,
  651. DoUnicode,
  652. &Password
  653. );
  654. if (!NT_SUCCESS(Status))
  655. {
  656. SspPrint((SSP_CRITICAL,"SpAcquireCredentialsHandle, Error from CopyClientString is 0x%lx\n", Status));
  657. goto Cleanup;
  658. }
  659. }
  660. if (pAuthIdentity->User != NULL)
  661. {
  662. Status = CopyClientString(
  663. pAuthIdentity->User,
  664. pAuthIdentity->UserLength,
  665. DoUnicode,
  666. &UserName
  667. );
  668. if (!NT_SUCCESS(Status))
  669. {
  670. SspPrint((SSP_CRITICAL, "SpAcquireCredentialsHandle, Error from CopyClientString is 0x%lx\n", Status));
  671. goto Cleanup;
  672. }
  673. }
  674. if (pAuthIdentity->Domain != NULL)
  675. {
  676. Status = CopyClientString(
  677. pAuthIdentity->Domain,
  678. pAuthIdentity->DomainLength,
  679. DoUnicode,
  680. &DomainName
  681. );
  682. if (!NT_SUCCESS(Status))
  683. {
  684. SspPrint((SSP_CRITICAL, "SpAcquireCredentialsHandle, Error from CopyClientString is 0x%lx\n", Status));
  685. goto Cleanup;
  686. }
  687. //
  688. // Make sure that the domain name length is not greater
  689. // than the allowed dns domain name
  690. //
  691. if (DomainName.Length > DNS_MAX_NAME_LENGTH * sizeof(WCHAR))
  692. {
  693. SspPrint((SSP_CRITICAL, "SpAcquireCredentialsHandle: Invalid supplied domain name %wZ\n",
  694. &DomainName ));
  695. Status = SEC_E_UNKNOWN_CREDENTIALS;
  696. goto Cleanup;
  697. }
  698. }
  699. }
  700. } // AuthorizationData != NULL
  701. #if 0
  702. //
  703. // Handle UPN and composite NETBIOS syntax
  704. //
  705. {
  706. UNICODE_STRING User = UserName;
  707. UNICODE_STRING Domain = DomainName;
  708. Status =
  709. NtLmParseName(
  710. &User,
  711. &Domain,
  712. TRUE); // If successful, this will allocate and free buffers
  713. if(NT_SUCCESS(Status)){
  714. UserName = User;
  715. DomainName = Domain;
  716. }
  717. }
  718. #endif
  719. if( Password.Length != 0 )
  720. {
  721. UNICODE_STRING OldPassword = Password;
  722. Status = NtLmDuplicatePassword( &Password, &OldPassword );
  723. if(!NT_SUCCESS(Status))
  724. {
  725. goto Cleanup;
  726. }
  727. ZeroMemory( OldPassword.Buffer, OldPassword.Length );
  728. NtLmFree( OldPassword.Buffer );
  729. }
  730. Status = SsprAcquireCredentialHandle(
  731. LogonIdToUse,
  732. &ClientInfo,
  733. NewCredentialUseFlags,
  734. CredentialHandle,
  735. ExpirationTime,
  736. &DomainName,
  737. &UserName,
  738. &Password );
  739. if (!NT_SUCCESS(Status))
  740. {
  741. SspPrint((SSP_CRITICAL, "SpAcquireCredentialsHandle, Error from SsprAcquireCredentialsHandle is 0x%lx\n", Status));
  742. goto Cleanup;
  743. }
  744. // These will be kept in the Credential structure and freed
  745. // when the Credential structure is freed
  746. if (DomainName.Buffer != NULL)
  747. {
  748. DomainName.Buffer = NULL;
  749. }
  750. if (UserName.Buffer != NULL)
  751. {
  752. UserName.Buffer = NULL;
  753. }
  754. if (Password.Buffer != NULL)
  755. {
  756. Password.Buffer = NULL;
  757. }
  758. Cleanup:
  759. if (TmpCredentials != NULL)
  760. {
  761. NtLmFree(TmpCredentials);
  762. }
  763. if (DomainName.Buffer != NULL)
  764. {
  765. NtLmFree(DomainName.Buffer);
  766. }
  767. if (UserName.Buffer != NULL)
  768. {
  769. NtLmFree(UserName.Buffer);
  770. }
  771. if (Password.Buffer != NULL)
  772. {
  773. ZeroMemory(Password.Buffer, Password.Length);
  774. NtLmFree(Password.Buffer);
  775. }
  776. if (pAuthIdentityEx != NULL)
  777. {
  778. NtLmFree(pAuthIdentityEx);
  779. }
  780. SspPrint((SSP_API, "Leaving SpAcquireCredentialsHandle, Status is %d\n", Status));
  781. return(SspNtStatusToSecStatus(Status, SEC_E_INTERNAL_ERROR));
  782. }
  783. //+-------------------------------------------------------------------------
  784. //
  785. // Function: SpFreeCredentialsHandle
  786. //
  787. // Synopsis: Frees a credential created by AcquireCredentialsHandle.
  788. //
  789. // Effects: Unlinks the credential from the global list and the list
  790. // for this client.
  791. //
  792. // Arguments: CredentialHandle - Handle to the credential to free
  793. // (acquired through AcquireCredentialsHandle)
  794. //
  795. // Requires:
  796. //
  797. // Returns: STATUS_SUCCESS on success,
  798. // SEC_E_INVALID_HANDLE if the handle is not valid
  799. //
  800. // Notes:
  801. //
  802. //
  803. //--------------------------------------------------------------------------
  804. NTSTATUS NTAPI
  805. SpFreeCredentialsHandle(
  806. IN ULONG_PTR CredentialHandle
  807. )
  808. {
  809. SspPrint((SSP_API, "Entering SpFreeCredentialsHandle\n"));
  810. NTSTATUS Status = STATUS_SUCCESS;
  811. PSSP_CREDENTIAL Credential;
  812. //
  813. // Find the referenced credential and delink it.
  814. //
  815. Status = SspCredentialReferenceCredential(
  816. CredentialHandle,
  817. TRUE, // remove the instance of the credential
  818. &Credential );
  819. if ( !NT_SUCCESS( Status ) ) {
  820. SspPrint((SSP_CRITICAL, "SpFreeCredentialsHandle, Error from SspCredentialReferenceCredential is 0x%lx\n", Status));
  821. goto Cleanup;
  822. }
  823. //
  824. // Dereferencing the Credential will remove the client's reference
  825. // to it, causing it to be rundown if nobody else is using it.
  826. //
  827. SspCredentialDereferenceCredential( Credential );
  828. Cleanup:
  829. //
  830. // Catch spurious INVALID_HANDLE being returned to RPC.
  831. //
  832. ASSERT( NT_SUCCESS(Status) );
  833. SspPrint((SSP_API, "Leaving SpFreeCredentialsHandle\n"));
  834. return(SspNtStatusToSecStatus(Status, SEC_E_INTERNAL_ERROR));
  835. }
  836. NTSTATUS
  837. NTAPI
  838. SpQueryCredentialsAttributes(
  839. IN LSA_SEC_HANDLE CredentialHandle,
  840. IN ULONG CredentialAttribute,
  841. IN OUT PVOID Buffer
  842. )
  843. {
  844. PSSP_CREDENTIAL pCredential = NULL;
  845. SecPkgCredentials_NamesW Names;
  846. LUID LogonId;
  847. BOOLEAN bActiveLogonsAreLocked = FALSE;
  848. LPWSTR pszContextNames = NULL;
  849. LPWSTR pWhere;
  850. LPWSTR pszUserName = NULL;
  851. LPWSTR pszDomainName = NULL;
  852. DWORD cchUserName = 0;
  853. DWORD cchDomainName = 0;
  854. ULONG Length;
  855. BOOLEAN CalledLsaLookup = FALSE;
  856. PLSAPR_REFERENCED_DOMAIN_LIST ReferencedDomain = NULL;
  857. LSAPR_TRANSLATED_NAMES ReferencedUser;
  858. #if _WIN64
  859. SECPKG_CALL_INFO CallInfo;
  860. #endif
  861. NTSTATUS Status = STATUS_SUCCESS;
  862. SspPrint((SSP_API,"In SpQueryCredentialsAttributes\n"));
  863. Names.sUserName = NULL;
  864. if (CredentialAttribute != SECPKG_CRED_ATTR_NAMES)
  865. {
  866. SspPrint((SSP_MISC, "Asked for illegal info level in QueryCredAttr: %d\n",
  867. CredentialAttribute));
  868. Status = STATUS_INVALID_PARAMETER;
  869. goto Cleanup;
  870. }
  871. Status = SspCredentialReferenceCredential(
  872. CredentialHandle,
  873. FALSE,
  874. &pCredential );
  875. if ( !NT_SUCCESS( Status ) ) {
  876. SspPrint((SSP_CRITICAL, "SpQueryCredentialsAttributes, Error from SspCredentialReferenceCredential is 0x%lx\n", Status));
  877. goto Cleanup;
  878. }
  879. #if _WIN64
  880. if(!LsaFunctions->GetCallInfo( &CallInfo ))
  881. {
  882. Status = STATUS_INTERNAL_ERROR;
  883. SspPrint((SSP_CRITICAL, "SpQueryCredentialsAttributes, failed to get callinfo 0x%lx\n", Status));
  884. goto Cleanup;
  885. }
  886. #endif
  887. //
  888. // The logon id of the credential is constant, so it is o.k.
  889. // to use it without locking the credential
  890. //
  891. LogonId = pCredential->LogonId;
  892. //
  893. // credentials were either specified when cred built, or, they were defaulted.
  894. //
  895. if ( pCredential->UserName.Buffer == NULL &&
  896. pCredential->DomainName.Buffer == NULL )
  897. {
  898. PACTIVE_LOGON pActiveLogon = NULL;
  899. //
  900. // defaulted creds: pickup info from active logon table.
  901. //
  902. NlpLockActiveLogonsRead();
  903. bActiveLogonsAreLocked = TRUE;
  904. pActiveLogon = NlpFindActiveLogon(&LogonId);
  905. if (pActiveLogon)
  906. {
  907. //
  908. // found an active logon entry.
  909. //
  910. pszUserName = pActiveLogon->UserName.Buffer;
  911. cchUserName = pActiveLogon->UserName.Length / sizeof(WCHAR);
  912. pszDomainName = pActiveLogon->LogonDomainName.Buffer;
  913. cchDomainName = pActiveLogon->LogonDomainName.Length / sizeof(WCHAR);
  914. }
  915. else
  916. {
  917. PTOKEN_USER pTokenInfo;
  918. BYTE FastBuffer[ 256 ];
  919. DWORD cbTokenInfo;
  920. HANDLE ClientTokenHandle;
  921. BOOL fSuccess = FALSE;
  922. NlpUnlockActiveLogons();
  923. bActiveLogonsAreLocked = FALSE;
  924. //
  925. // get a token associated with the logon session.
  926. //
  927. Status = LsaFunctions->OpenTokenByLogonId(
  928. &LogonId,
  929. &ClientTokenHandle
  930. );
  931. if (!NT_SUCCESS(Status))
  932. {
  933. SspPrint(( SSP_CRITICAL,
  934. "SpQueryCredentialsAttributes: "
  935. "Could not open client token 0x%lx\n",
  936. Status ));
  937. goto Cleanup;
  938. }
  939. //
  940. // get Sid associated with credential.
  941. //
  942. cbTokenInfo = sizeof(FastBuffer);
  943. pTokenInfo = (PTOKEN_USER)FastBuffer;
  944. fSuccess = GetTokenInformation(
  945. ClientTokenHandle,
  946. TokenUser,
  947. pTokenInfo,
  948. cbTokenInfo,
  949. &cbTokenInfo
  950. );
  951. CloseHandle( ClientTokenHandle );
  952. if ( fSuccess )
  953. {
  954. LSAPR_SID_ENUM_BUFFER SidEnumBuffer;
  955. LSAPR_SID_INFORMATION SidInfo;
  956. ULONG MappedCount;
  957. SidEnumBuffer.Entries = 1;
  958. SidEnumBuffer.SidInfo = &SidInfo;
  959. SidInfo.Sid = (LSAPR_SID*)pTokenInfo->User.Sid;
  960. ZeroMemory( &ReferencedUser, sizeof(ReferencedUser) );
  961. CalledLsaLookup = TRUE;
  962. Status = LsarLookupSids(
  963. NtLmGlobalPolicyHandle,
  964. &SidEnumBuffer,
  965. &ReferencedDomain,
  966. &ReferencedUser,
  967. LsapLookupWksta,
  968. &MappedCount
  969. );
  970. if ( !NT_SUCCESS( Status ) ||
  971. (MappedCount == 0) ||
  972. (ReferencedUser.Entries == 0) ||
  973. (ReferencedDomain == NULL) ||
  974. (ReferencedDomain->Entries == 0)
  975. )
  976. {
  977. fSuccess = FALSE;
  978. }
  979. else
  980. {
  981. LONG Index = ReferencedUser.Names->DomainIndex;
  982. pszUserName = ReferencedUser.Names->Name.Buffer;
  983. cchUserName = ReferencedUser.Names->Name.Length / sizeof(WCHAR);
  984. pszDomainName = ReferencedDomain->Domains[Index].Name.Buffer;
  985. cchDomainName = ReferencedDomain->Domains[Index].Name.Length / sizeof(WCHAR);
  986. }
  987. }
  988. if ( !fSuccess )
  989. {
  990. Status = STATUS_NO_SUCH_LOGON_SESSION;
  991. SspPrint(( SSP_CRITICAL, "SpQueryCredentialsAtributes, NlpFindActiveLogon returns FALSE\n"));
  992. goto Cleanup;
  993. }
  994. }
  995. }
  996. else
  997. {
  998. //
  999. // specified creds.
  1000. //
  1001. pszUserName = pCredential->UserName.Buffer;
  1002. cchUserName = pCredential->UserName.Length / sizeof(WCHAR);
  1003. pszDomainName = pCredential->DomainName.Buffer;
  1004. cchDomainName = pCredential->DomainName.Length / sizeof(WCHAR);
  1005. }
  1006. Length = (cchUserName + 1 + cchDomainName + 1) * sizeof(WCHAR);
  1007. pszContextNames = (LPWSTR)NtLmAllocate( Length );
  1008. if ( pszContextNames == NULL )
  1009. {
  1010. goto Cleanup;
  1011. }
  1012. pWhere = pszContextNames;
  1013. if ( pszDomainName)
  1014. {
  1015. RtlCopyMemory( pszContextNames, pszDomainName, cchDomainName * sizeof(WCHAR) );
  1016. pszContextNames[ cchDomainName ] = L'\\';
  1017. pWhere += (cchDomainName+1);
  1018. }
  1019. if ( pszUserName )
  1020. {
  1021. RtlCopyMemory( pWhere, pszUserName, cchUserName * sizeof(WCHAR) );
  1022. }
  1023. pWhere[ cchUserName ] = L'\0';
  1024. if (bActiveLogonsAreLocked)
  1025. {
  1026. NlpUnlockActiveLogons();
  1027. bActiveLogonsAreLocked = FALSE;
  1028. }
  1029. //
  1030. // Allocate memory in the client's address space
  1031. //
  1032. Status = LsaFunctions->AllocateClientBuffer(
  1033. NULL,
  1034. Length,
  1035. (PVOID *) &Names.sUserName
  1036. );
  1037. if (!NT_SUCCESS(Status))
  1038. {
  1039. goto Cleanup;
  1040. }
  1041. //
  1042. // Copy the string there
  1043. //
  1044. Status = LsaFunctions->CopyToClientBuffer(
  1045. NULL,
  1046. Length,
  1047. Names.sUserName,
  1048. pszContextNames
  1049. );
  1050. if (!NT_SUCCESS(Status))
  1051. {
  1052. goto Cleanup;
  1053. }
  1054. //
  1055. // Now copy the address of the string there
  1056. //
  1057. #if _WIN64
  1058. if ( CallInfo.Attributes & SECPKG_CALL_WOWCLIENT )
  1059. {
  1060. Status = LsaFunctions->CopyToClientBuffer(
  1061. NULL,
  1062. sizeof(ULONG),
  1063. Buffer,
  1064. &Names
  1065. );
  1066. }
  1067. else
  1068. {
  1069. Status = LsaFunctions->CopyToClientBuffer(
  1070. NULL,
  1071. sizeof(Names),
  1072. Buffer,
  1073. &Names
  1074. );
  1075. }
  1076. #else
  1077. Status = LsaFunctions->CopyToClientBuffer(
  1078. NULL,
  1079. sizeof(Names),
  1080. Buffer,
  1081. &Names
  1082. );
  1083. #endif
  1084. if (!NT_SUCCESS(Status))
  1085. {
  1086. goto Cleanup;
  1087. }
  1088. Cleanup:
  1089. if (bActiveLogonsAreLocked)
  1090. {
  1091. NlpUnlockActiveLogons();
  1092. }
  1093. if ( pCredential != NULL )
  1094. {
  1095. SspCredentialDereferenceCredential( pCredential );
  1096. }
  1097. if ( CalledLsaLookup )
  1098. {
  1099. if ( ReferencedDomain )
  1100. {
  1101. LsaIFree_LSAPR_REFERENCED_DOMAIN_LIST( ReferencedDomain );
  1102. }
  1103. LsaIFree_LSAPR_TRANSLATED_NAMES( &ReferencedUser );
  1104. }
  1105. if (!NT_SUCCESS(Status))
  1106. {
  1107. if (Names.sUserName != NULL)
  1108. {
  1109. (VOID) LsaFunctions->FreeClientBuffer(
  1110. NULL,
  1111. Names.sUserName
  1112. );
  1113. }
  1114. }
  1115. if ( pszContextNames )
  1116. {
  1117. NtLmFree( pszContextNames );
  1118. }
  1119. SspPrint((SSP_API, "Leaving SpQueryCredentialsAttributes\n"));
  1120. return (SspNtStatusToSecStatus(Status, SEC_E_INTERNAL_ERROR));
  1121. }
  1122. NTSTATUS NTAPI
  1123. SpSaveCredentials(
  1124. IN ULONG_PTR CredentialHandle,
  1125. IN PSecBuffer Credentials
  1126. )
  1127. {
  1128. UNREFERENCED_PARAMETER(CredentialHandle);
  1129. UNREFERENCED_PARAMETER(Credentials);
  1130. SspPrint((SSP_API,"In SpSaveCredentials\n"));
  1131. return(SEC_E_UNSUPPORTED_FUNCTION);
  1132. }
  1133. NTSTATUS NTAPI
  1134. SpGetCredentials(
  1135. IN ULONG_PTR CredentialHandle,
  1136. IN OUT PSecBuffer Credentials
  1137. )
  1138. {
  1139. UNREFERENCED_PARAMETER(CredentialHandle);
  1140. UNREFERENCED_PARAMETER(Credentials);
  1141. SspPrint((SSP_API,"In SpGetCredentials\n"));
  1142. return(SEC_E_UNSUPPORTED_FUNCTION);
  1143. }
  1144. NTSTATUS NTAPI
  1145. SpDeleteCredentials(
  1146. IN ULONG_PTR CredentialHandle,
  1147. IN PSecBuffer Key
  1148. )
  1149. {
  1150. UNREFERENCED_PARAMETER(CredentialHandle);
  1151. UNREFERENCED_PARAMETER(Key);
  1152. SspPrint((SSP_API,"In SpDeleteCredentials\n"));
  1153. return(SEC_E_UNSUPPORTED_FUNCTION);
  1154. }