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.

1248 lines
31 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. credhand.cxx
  5. Abstract:
  6. API and support routines for handling credential handles.
  7. Author:
  8. Cliff Van Dyke (CliffV) 26-Jun-1993
  9. Revision History:
  10. ChandanS 03-Aug-1996 Stolen from net\svcdlls\ntlmssp\common\credhand.c
  11. --*/
  12. //
  13. // Common include files.
  14. //
  15. #include <global.h>
  16. #include <align.h> // ALIGN_WCHAR
  17. extern "C"
  18. {
  19. #include <nlp.h>
  20. }
  21. //
  22. // Crit Sect to protect various globals in this module.
  23. //
  24. RTL_RESOURCE SspCredentialCritSect;
  25. LIST_ENTRY SspCredentialList;
  26. // This is the definition of a null session string.
  27. // Change this if the definition changes
  28. #define IsNullSessionString(x) (((x)->Length == 0) && \
  29. ((x)->Buffer != NULL))
  30. BOOLEAN
  31. AlterRtlEqualUnicodeString(
  32. IN PUNICODE_STRING String1,
  33. IN PUNICODE_STRING String2,
  34. IN BOOLEAN CaseInSensitive
  35. )
  36. /*++
  37. This is here to catch cases that RtlEqualUnicodeString does not.
  38. For e.g, if String1 is (NULL,0,0) and String2 is ("",0,2),
  39. RtlEqualUnicodeString returned TRUE but we really want it to return FALSE
  40. --*/
  41. {
  42. BOOL fRet = RtlEqualUnicodeString(String1, String2, CaseInSensitive);
  43. if (fRet && (IsNullSessionString(String1) != IsNullSessionString(String2)))
  44. {
  45. fRet = FALSE;
  46. }
  47. return (fRet != 0);
  48. }
  49. NTSTATUS
  50. SspCredentialReferenceCredential(
  51. IN ULONG_PTR CredentialHandle,
  52. IN BOOLEAN DereferenceCredential,
  53. OUT PSSP_CREDENTIAL * UserCredential
  54. )
  55. /*++
  56. Routine Description:
  57. This routine checks to see if the Credential is from a currently
  58. active client, and references the Credential if it is valid.
  59. The caller may optionally request that the client's Credential be
  60. removed from the list of valid Credentials - preventing future
  61. requests from finding this Credential.
  62. For a client's Credential to be valid, the Credential value
  63. must be on our list of active Credentials.
  64. Arguments:
  65. CredentialHandle - Points to the CredentialHandle of the Credential
  66. to be referenced.
  67. DereferenceCredential - This boolean value indicates that that a call
  68. a single instance of this credential handle should be freed. If there
  69. are multiple instances, they should still continue to work.
  70. Return Value:
  71. NULL - the Credential was not found.
  72. Otherwise - returns a pointer to the referenced credential.
  73. --*/
  74. {
  75. PSSP_CREDENTIAL Credential = NULL;
  76. SECPKG_CALL_INFO CallInfo;
  77. ULONG DereferenceCount;
  78. *UserCredential = NULL ;
  79. if (LsaFunctions->GetCallInfo(&CallInfo))
  80. {
  81. DereferenceCount = CallInfo.CallCount;
  82. } else {
  83. ASSERT( (STATUS_INTERNAL_ERROR == STATUS_SUCCESS) );
  84. return STATUS_INTERNAL_ERROR;
  85. }
  86. if( CallInfo.Attributes & SECPKG_CALL_CLEANUP )
  87. {
  88. CallInfo.Attributes |= SECPKG_CALL_IS_TCB;
  89. SspPrint(( SSP_LEAK_TRACK, "SspCredentialReferenceCredential: pid: 0x%lx handle: %p refcount: %lu\n",
  90. CallInfo.ProcessId, CredentialHandle, DereferenceCount));
  91. }
  92. //
  93. // Acquire exclusive access to the Credential list
  94. //
  95. RtlAcquireResourceShared( &SspCredentialCritSect, TRUE );
  96. __try {
  97. Credential = (PSSP_CREDENTIAL)CredentialHandle;
  98. while( Credential->CredentialTag == SSP_CREDENTIAL_TAG_ACTIVE )
  99. {
  100. // Make sure we have the privilege of accessing
  101. // this handle
  102. if (((CallInfo.Attributes & SECPKG_CALL_IS_TCB) == 0) &&
  103. (Credential->ClientProcessID != CallInfo.ProcessId)
  104. )
  105. {
  106. break;
  107. }
  108. if (!DereferenceCredential) {
  109. InterlockedIncrement( (PLONG)&Credential->References );
  110. } else {
  111. LONG References;
  112. //
  113. // Decremenent the credential references, indicating
  114. // that a call to free
  115. ASSERT((DereferenceCount > 0));
  116. //
  117. // NOTE: subtract one off the deref count,
  118. // avoids an extra interlocked operation, since DerefCred will
  119. // decrement and check for refcnt == 0.
  120. //
  121. DereferenceCount--;
  122. if( DereferenceCount == 1 )
  123. {
  124. References = InterlockedDecrement( (PLONG)&Credential->References );
  125. ASSERT( (References > 0) );
  126. } else if( DereferenceCount > 1 )
  127. {
  128. //
  129. // there is no equivalent to InterlockedSubtract.
  130. // so, turn it into an Add with some signed magic.
  131. //
  132. LONG DecrementToIncrement = 0 - DereferenceCount;
  133. References = InterlockedExchangeAdd( (PLONG)&Credential->References, DecrementToIncrement );
  134. ASSERT( ((References+DecrementToIncrement) > 0) );
  135. }
  136. }
  137. *UserCredential = Credential ;
  138. RtlReleaseResource( &SspCredentialCritSect );
  139. return STATUS_SUCCESS ;
  140. }
  141. } __except (EXCEPTION_EXECUTE_HANDLER)
  142. {
  143. SspPrint(( SSP_CRITICAL, "Tried to reference invalid Credential %p\n",
  144. Credential ));
  145. }
  146. RtlReleaseResource( &SspCredentialCritSect );
  147. //
  148. // No match found
  149. //
  150. SspPrint(( SSP_API_MORE, "Tried to reference unknown Credential %p\n",
  151. CredentialHandle ));
  152. return STATUS_INVALID_HANDLE ;
  153. }
  154. NTSTATUS
  155. SspCredentialGetPassword(
  156. IN PSSP_CREDENTIAL Credential,
  157. OUT PUNICODE_STRING Password
  158. )
  159. /*++
  160. Routine Description:
  161. This routine copies the password out of credential.
  162. NOTE: Locking is no longer required, because the caller is expected
  163. to NtLmDuplicateUnicodeString() the cipher text Password prior to
  164. passing it to this routine. This change allows the following advantages:
  165. 1. Avoid taking Credential list lock.
  166. 2. Avoid having to avoid having to Re-hide the password after reveal.
  167. 3. Avoid having to take locks elsewhere associated with hiding/revealing.
  168. Arguments:
  169. Credential - Credential record to retrieve the password from.
  170. Password - UNICODE_STRING to store the password in.
  171. Return Value:
  172. STATUS_NO_MEMORY - there was not enough memory to copy
  173. the password.
  174. --*/
  175. {
  176. NTSTATUS Status = STATUS_SUCCESS;
  177. if ( Credential->Password.Buffer != NULL ) {
  178. Status = NtLmDuplicatePassword(
  179. Password,
  180. &Credential->Password
  181. );
  182. } else {
  183. RtlInitUnicodeString(
  184. Password,
  185. NULL
  186. );
  187. }
  188. return(Status);
  189. }
  190. PSSP_CREDENTIAL
  191. SspCredentialLookupCredential(
  192. IN PLUID LogonId,
  193. IN ULONG CredentialUseFlags,
  194. IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
  195. IN PUNICODE_STRING UserName,
  196. IN PUNICODE_STRING DomainName,
  197. IN PUNICODE_STRING Password
  198. )
  199. /*++
  200. Routine Description:
  201. This routine walks the list of credentials for this client looking
  202. for one that has the same supplemental credentials as those passed
  203. in. If it is found, its reference count is increased and a pointer
  204. to it is returned.
  205. Arguments:
  206. UserName - User name to match.
  207. DomainName - Domain name to match.
  208. Password - Password to match.
  209. Return Value:
  210. NULL - the Credential was not found.
  211. Otherwise - returns a pointer to the referenced credential.
  212. --*/
  213. {
  214. SspPrint((SSP_API_MORE, "Entering SspCredentialLookupCredential\n"));
  215. NTSTATUS Status;
  216. PLIST_ENTRY ListEntry;
  217. PSSP_CREDENTIAL Credential = NULL;
  218. PSSP_CREDENTIAL CredentialResult = NULL;
  219. PLIST_ENTRY ListHead;
  220. SECPKG_CALL_INFO CallInfo ;
  221. UNICODE_STRING EncryptedPassword;
  222. if ( !LsaFunctions->GetCallInfo( &CallInfo ) )
  223. {
  224. SspPrint(( SSP_CRITICAL, "SspCredentialLookupCredential: GetCallInfo returned FALSE\n" ));
  225. return NULL ;
  226. }
  227. ZeroMemory(&EncryptedPassword, sizeof(EncryptedPassword));
  228. Status = NtLmDuplicatePassword(&EncryptedPassword, Password);
  229. if(!NT_SUCCESS( Status ))
  230. {
  231. SspPrint(( SSP_CRITICAL, "SspCredentialLookupCredential: DuplicatePassword failed\n" ));
  232. return NULL;
  233. }
  234. SspHidePassword( &EncryptedPassword );
  235. //
  236. // Acquire exclusive access to the Credential list
  237. //
  238. RtlAcquireResourceShared( &SspCredentialCritSect, TRUE );
  239. ListHead = &SspCredentialList;
  240. //
  241. // Now walk the list of Credentials looking for a match.
  242. //
  243. for ( ListEntry = ListHead->Flink;
  244. ListEntry != ListHead;
  245. ListEntry = ListEntry->Flink )
  246. {
  247. Credential = CONTAINING_RECORD( ListEntry, SSP_CREDENTIAL, Next );
  248. //
  249. // we now allow matching and pooling of INBOUND creds, too.
  250. //
  251. //
  252. // We only want credentials from the same caller
  253. //
  254. if (Credential->ClientProcessID != CallInfo.ProcessId) {
  255. continue;
  256. }
  257. //
  258. // don't share creds across impersonation levels.
  259. //
  260. if (Credential->ImpersonationLevel != ImpersonationLevel)
  261. {
  262. continue;
  263. }
  264. //
  265. // if the caller is from kernel mode, only return creds
  266. // granted to kernel mode
  267. //
  268. if ( ( CallInfo.Attributes & SECPKG_CALL_KERNEL_MODE ) != 0 )
  269. {
  270. if ( !Credential->KernelClient )
  271. {
  272. continue;
  273. }
  274. }
  275. //
  276. // Check for a match
  277. //
  278. // The credential use check was added because null session
  279. // credentials were being returned when default credentials
  280. // were being asked. This happened becuase RtlEqualUnicodeString
  281. // for NULL,0,0 and "",0,2 is TRUE
  282. if ( (CredentialUseFlags != Credential->CredentialUseFlags) )
  283. {
  284. continue;
  285. }
  286. if(!RtlEqualLuid(
  287. LogonId,
  288. &Credential->LogonId
  289. ))
  290. {
  291. continue;
  292. }
  293. if(!AlterRtlEqualUnicodeString(
  294. UserName,
  295. &Credential->UserName,
  296. FALSE
  297. ))
  298. {
  299. continue;
  300. }
  301. if(!AlterRtlEqualUnicodeString(
  302. DomainName,
  303. &Credential->DomainName,
  304. FALSE
  305. ))
  306. {
  307. continue;
  308. }
  309. //
  310. // password is stored encrypted in list -- we're comparing
  311. // a one-time encrypted version of candidate. advantages:
  312. // 1. passwords not revealed in memory.
  313. // 2. only need encrypt candidate single time.
  314. //
  315. if(!AlterRtlEqualUnicodeString(
  316. &Credential->Password,
  317. &EncryptedPassword,
  318. FALSE
  319. ))
  320. {
  321. continue;
  322. }
  323. //
  324. // Found a match - reference the credential
  325. //
  326. //
  327. // Reference the credential and indicate that
  328. // it is in use as two different handles to the caller
  329. // (who may call FreeCredentialsHandle twice)
  330. //
  331. InterlockedIncrement( (PLONG)&Credential->References );
  332. CredentialResult = Credential;
  333. break;
  334. }
  335. RtlReleaseResource( &SspCredentialCritSect );
  336. if( EncryptedPassword.Buffer != NULL ) {
  337. ZeroMemory( EncryptedPassword.Buffer, EncryptedPassword.Length );
  338. NtLmFree( EncryptedPassword.Buffer );
  339. }
  340. if( CredentialResult == NULL )
  341. {
  342. SspPrint(( SSP_API_MORE, "Tried to reference unknown Credential\n" ));
  343. }
  344. SspPrint((SSP_API_MORE, "Leaving SspCredentialLookupCredential\n"));
  345. return CredentialResult;
  346. }
  347. VOID
  348. SspCredentialDereferenceCredential(
  349. IN PSSP_CREDENTIAL Credential
  350. )
  351. /*++
  352. Routine Description:
  353. This routine decrements the specified Credential's reference count.
  354. If the reference count drops to zero, then the Credential is deleted
  355. Arguments:
  356. Credential - Points to the Credential to be dereferenced.
  357. Return Value:
  358. None.
  359. --*/
  360. {
  361. LONG References;
  362. //
  363. // Decrement the reference count
  364. //
  365. References = InterlockedDecrement( (PLONG)&Credential->References );
  366. ASSERT( References >= 0 );
  367. //
  368. // If the count dropped to zero, then run-down the Credential
  369. //
  370. if ( References == 0 )
  371. {
  372. if (!Credential->Unlinked) {
  373. RtlAcquireResourceExclusive(&SspCredentialCritSect, TRUE);
  374. if( Credential->References != 0 )
  375. {
  376. RtlReleaseResource( &SspCredentialCritSect );
  377. return;
  378. }
  379. RemoveEntryList( &Credential->Next );
  380. Credential->Unlinked = TRUE;
  381. Credential->CredentialTag = SSP_CREDENTIAL_TAG_DELETE;
  382. RtlReleaseResource( &SspCredentialCritSect );
  383. }
  384. SspPrint(( SSP_API_MORE, "Deleting Credential 0x%lx\n",
  385. Credential ));
  386. if ( Credential->Password.Buffer ) {
  387. ZeroMemory( Credential->Password.Buffer, Credential->Password.MaximumLength );
  388. (VOID) NtLmFree( Credential->Password.Buffer );
  389. }
  390. if ( Credential->DomainName.Buffer ) {
  391. (VOID) NtLmFree( Credential->DomainName.Buffer );
  392. }
  393. if ( Credential->UserName.Buffer ) {
  394. (VOID) NtLmFree( Credential->UserName.Buffer );
  395. }
  396. ZeroMemory( Credential, sizeof(SSP_CREDENTIAL) );
  397. (VOID) NtLmFree( Credential );
  398. }
  399. return;
  400. }
  401. BOOLEAN
  402. SsprCheckMachineLogon(
  403. IN PUNICODE_STRING UserName,
  404. IN PUNICODE_STRING DomainName,
  405. IN PUNICODE_STRING Password,
  406. IN OUT PLUID pLogonId,
  407. IN OUT ULONG *pCredFlags
  408. )
  409. /*++
  410. Routine Description:
  411. This routine determines if the input credential matches a special
  412. machine account logon over-ride.
  413. This routine also checks if the caller is the NetworkService account,
  414. specifying default credentials, in a downlevel domain. This will cause
  415. a credential over-ride to LocalSystem, for backwards compatibility.
  416. NT4 did not understand machine account authentication, so outbound authentication
  417. from networkservice as machine account cannot succeed -- downgrade to the old
  418. LocalSystem default.
  419. Return Value:
  420. TRUE - the intput credential was the special machine account logon over-ride.
  421. the pLogonId is updated to utilize the machine credential.
  422. --*/
  423. {
  424. UNICODE_STRING MachineAccountName;
  425. static LUID LogonIdAnonymous = ANONYMOUS_LOGON_LUID;
  426. static LUID LogonIdSystem = SYSTEM_LUID;
  427. static LUID LogonIdNetworkService = NETWORKSERVICE_LUID;
  428. BOOLEAN fMachineLogon = FALSE;
  429. MachineAccountName.Buffer = NULL;
  430. //
  431. // if caller is NetworkService with default cred, for downlevel domains
  432. // use anonymous
  433. //
  434. if (RtlEqualLuid( pLogonId, &LogonIdNetworkService ))
  435. {
  436. if ( UserName->Buffer == NULL &&
  437. DomainName->Buffer == NULL &&
  438. Password->Buffer == NULL )
  439. {
  440. BOOL MixedMode = FALSE;
  441. NTSTATUS Status;
  442. if ( !NlpNetlogonInitialized )
  443. {
  444. Status = NlWaitForNetlogon( NETLOGON_STARTUP_TIME );
  445. if ( NT_SUCCESS(Status) )
  446. {
  447. NlpNetlogonInitialized = TRUE;
  448. }
  449. }
  450. if (NlpNetlogonInitialized)
  451. {
  452. ASSERT(NlpNetLogonMixedDomain && L"NlpNetLogonMixedDomain must be non null");
  453. Status = (*NlpNetLogonMixedDomain)(&MixedMode);
  454. if (!NT_SUCCESS(Status))
  455. {
  456. SspPrint((SSP_CRITICAL, "SsprCheckMachineLogon call to I_NetLogonMixedDomain failed %#x\n", Status));
  457. MixedMode = FALSE;
  458. }
  459. }
  460. if (MixedMode)
  461. {
  462. SspPrint((SSP_WARNING, "SsprCheckMachineLogon using anonymous connection for networkservices\n"));
  463. *pLogonId = LogonIdAnonymous; // use anonymous
  464. *pCredFlags |= SSP_CREDENTIAL_FLAG_WAS_NETWORK_SERVICE;
  465. // return FALSE;
  466. }
  467. else
  468. {
  469. return TRUE;
  470. }
  471. }
  472. return FALSE;
  473. }
  474. //
  475. // check if caller was system, and requested machine credential
  476. // eg: user=computername$, domain=NULL, password=NULL
  477. //
  478. if ( !RtlEqualLuid( pLogonId, &LogonIdSystem ) )
  479. {
  480. return FALSE;
  481. }
  482. if( UserName->Buffer == NULL )
  483. {
  484. return FALSE;
  485. }
  486. if( DomainName->Buffer != NULL )
  487. {
  488. return FALSE;
  489. }
  490. if( Password->Buffer != NULL )
  491. {
  492. return FALSE;
  493. }
  494. RtlAcquireResourceShared (&NtLmGlobalCritSect, TRUE);
  495. MachineAccountName.Length = NtLmGlobalUnicodeComputerNameString.Length + sizeof(WCHAR);
  496. if( MachineAccountName.Length == UserName->Length )
  497. {
  498. MachineAccountName.MaximumLength = MachineAccountName.Length;
  499. MachineAccountName.Buffer = (PWSTR)NtLmAllocate( MachineAccountName.Length );
  500. if( MachineAccountName.Buffer != NULL )
  501. {
  502. RtlCopyMemory( MachineAccountName.Buffer,
  503. NtLmGlobalUnicodeComputerNameString.Buffer,
  504. NtLmGlobalUnicodeComputerNameString.Length
  505. );
  506. MachineAccountName.Buffer[ (MachineAccountName.Length / sizeof(WCHAR)) - 1 ] = L'$';
  507. }
  508. }
  509. RtlReleaseResource (&NtLmGlobalCritSect);
  510. if( MachineAccountName.Buffer == NULL )
  511. {
  512. goto Cleanup;
  513. }
  514. if( RtlEqualUnicodeString( &MachineAccountName, UserName, TRUE ) )
  515. {
  516. //
  517. // yes, it's a machine account logon request, update the
  518. // requested LogonId to match our mapped logon session.
  519. //
  520. *pLogonId = NtLmGlobalLuidMachineLogon;
  521. fMachineLogon = TRUE;
  522. }
  523. Cleanup:
  524. if( MachineAccountName.Buffer )
  525. {
  526. NtLmFree( MachineAccountName.Buffer );
  527. }
  528. return fMachineLogon;
  529. }
  530. NTSTATUS
  531. SsprAcquireCredentialHandle(
  532. IN PLUID LogonId,
  533. IN PSECPKG_CLIENT_INFO ClientInfo,
  534. IN ULONG CredentialUseFlags,
  535. OUT PLSA_SEC_HANDLE CredentialHandle,
  536. OUT PTimeStamp Lifetime,
  537. IN OPTIONAL PUNICODE_STRING DomainName,
  538. IN OPTIONAL PUNICODE_STRING UserName,
  539. IN OPTIONAL PUNICODE_STRING Password
  540. )
  541. /*++
  542. Routine Description:
  543. This API allows applications to acquire a handle to pre-existing
  544. credentials associated with the user on whose behalf the call is made
  545. i.e. under the identity this application is running. These pre-existing
  546. credentials have been established through a system logon not described
  547. here. Note that this is different from "login to the network" and does
  548. not imply gathering of credentials.
  549. This API returns a handle to the credentials of a principal (user, client)
  550. as used by a specific security package. This handle can then be used
  551. in subsequent calls to the Context APIs. This API will not let a
  552. process obtain a handle to credentials that are not related to the
  553. process; i.e. we won't allow a process to grab the credentials of
  554. another user logged into the same machine. There is no way for us
  555. to determine if a process is a trojan horse or not, if it is executed
  556. by the user.
  557. Arguments:
  558. CredentialUseFlags - Flags indicating the way with which these
  559. credentials will be used.
  560. #define CRED_INBOUND 0x00000001
  561. #define CRED_OUTBOUND 0x00000002
  562. #define CRED_BOTH 0x00000003
  563. The credentials created with CRED_INBOUND option can only be used
  564. for (validating incoming calls and can not be used for making accesses.
  565. CredentialHandle - Returned credential handle.
  566. Lifetime - Time that these credentials expire. The value returned in
  567. this field depends on the security package.
  568. DomainName, DomainNameSize, UserName, UserNameSize, Password, PasswordSize -
  569. Optional credentials for this user.
  570. Return Value:
  571. STATUS_SUCCESS -- Call completed successfully
  572. SEC_E_PRINCIPAL_UNKNOWN -- No such principal
  573. SEC_E_NOT_OWNER -- caller does not own the specified credentials
  574. STATUS_NO_MEMORY -- Not enough memory
  575. --*/
  576. {
  577. SspPrint((SSP_API_MORE, "Entering SsprAcquireCredentialHandle\n"));
  578. NTSTATUS Status = STATUS_SUCCESS;
  579. PSSP_CREDENTIAL Credential = NULL;
  580. ULONG CredFlags = 0; // ntlm specific cred use flags
  581. if ((CredentialUseFlags & SECPKG_CRED_OUTBOUND) != 0) {
  582. //
  583. // check if machine account logon over-ride.
  584. // this has the side-effect of updating LogonId if over-ride was
  585. // requsted.
  586. //
  587. SsprCheckMachineLogon(
  588. UserName,
  589. DomainName,
  590. Password,
  591. LogonId,
  592. &CredFlags
  593. );
  594. }
  595. //
  596. // Look to see if we have already created one with this set of credentials.
  597. // Note - this leaves the credential referenced, so if we fail further down
  598. // we need to dereference the credential.
  599. //
  600. Credential = SspCredentialLookupCredential(
  601. LogonId,
  602. CredentialUseFlags,
  603. ClientInfo->ImpersonationLevel,
  604. UserName,
  605. DomainName,
  606. Password
  607. );
  608. //
  609. // If we're using a common set of data, free the captured stuff
  610. //
  611. if ( Credential )
  612. {
  613. if ( (UserName) && (UserName->Buffer) )
  614. {
  615. NtLmFree( UserName->Buffer );
  616. UserName->Buffer = NULL ;
  617. }
  618. if ( ( DomainName ) && (DomainName->Buffer) )
  619. {
  620. NtLmFree( DomainName->Buffer );
  621. DomainName->Buffer = NULL ;
  622. }
  623. if ( ( Password ) && ( Password->Buffer ) )
  624. {
  625. ZeroMemory( Password->Buffer, Password->Length );
  626. NtLmFree( Password->Buffer );
  627. Password->Buffer = NULL ;
  628. }
  629. Credential->MutableCredFlags = CredFlags; // atomic
  630. }
  631. //
  632. // If we didn't just find a credential, create one now.
  633. //
  634. if (Credential == NULL) {
  635. SECPKG_CALL_INFO CallInfo ;
  636. if ( !LsaFunctions->GetCallInfo( &CallInfo ) )
  637. {
  638. SspPrint((SSP_CRITICAL, "SsprAcquireCredentialHandle failed to GetCallInfo\n"));
  639. Status = STATUS_UNSUCCESSFUL ;
  640. goto Cleanup;
  641. }
  642. //
  643. // Allocate a credential block and initialize it.
  644. //
  645. Credential = (PSSP_CREDENTIAL)NtLmAllocate(sizeof(SSP_CREDENTIAL) );
  646. if ( Credential == NULL ) {
  647. Status = STATUS_NO_MEMORY;
  648. SspPrint((SSP_CRITICAL, "Error from NtLmAllocate 0x%lx\n", Status));
  649. goto Cleanup;
  650. }
  651. ZeroMemory( Credential, sizeof(*Credential) );
  652. Credential->References = 1;
  653. Credential->ClientProcessID = ClientInfo->ProcessID;
  654. Credential->CredentialUseFlags = CredentialUseFlags;
  655. Credential->MutableCredFlags = CredFlags;
  656. Credential->ImpersonationLevel = ClientInfo->ImpersonationLevel;
  657. Credential->Unlinked = TRUE;
  658. if ( ( CallInfo.Attributes & SECPKG_CALL_KERNEL_MODE ) != 0 )
  659. {
  660. Credential->KernelClient = TRUE ;
  661. }
  662. else
  663. {
  664. Credential->KernelClient = FALSE ;
  665. }
  666. //
  667. // Stick the logon ID in the credential
  668. //
  669. Credential->LogonId = *LogonId;
  670. //
  671. // Stick the supplemental credentials into the credential.
  672. //
  673. if (ARGUMENT_PRESENT(DomainName))
  674. {
  675. Credential->DomainName = *DomainName;
  676. }
  677. if (ARGUMENT_PRESENT(UserName))
  678. {
  679. Credential->UserName = *UserName;
  680. }
  681. if (ARGUMENT_PRESENT(Password))
  682. {
  683. SspHidePassword(Password);
  684. Credential->Password = *Password;
  685. }
  686. //
  687. // Add it to the list of valid credential handles.
  688. //
  689. Credential->Unlinked = FALSE;
  690. Credential->CredentialTag = SSP_CREDENTIAL_TAG_ACTIVE;
  691. RtlAcquireResourceExclusive( &SspCredentialCritSect, TRUE );
  692. InsertHeadList( &SspCredentialList, &Credential->Next );
  693. RtlReleaseResource( &SspCredentialCritSect );
  694. SspPrint((SSP_API_MORE, "Added Credential 0x%lx\n", Credential ));
  695. //
  696. // Don't bother dereferencing because we already set the
  697. // reference count to 1.
  698. //
  699. }
  700. //
  701. // Return output parameters to the caller.
  702. //
  703. *CredentialHandle = (LSA_SEC_HANDLE) Credential;
  704. *Lifetime = NtLmGlobalForever;
  705. Cleanup:
  706. if ( !NT_SUCCESS(Status) ) {
  707. if ( Credential != NULL ) {
  708. (VOID)NtLmFree( Credential );
  709. }
  710. }
  711. SspPrint((SSP_API_MORE, "Leaving SsprAcquireCredentialHandle\n"));
  712. return Status;
  713. }
  714. NTSTATUS
  715. SsprFreeCredentialHandle(
  716. IN ULONG_PTR CredentialHandle
  717. )
  718. /*++
  719. Routine Description:
  720. This API is used to notify the security system that the credentials are
  721. no longer needed and allows the application to free the handle acquired
  722. in the call described above. When all references to this credential
  723. set has been removed then the credentials may themselves be removed.
  724. Arguments:
  725. CredentialHandle - Credential Handle obtained through
  726. AcquireCredentialHandle.
  727. Return Value:
  728. STATUS_SUCCESS -- Call completed successfully
  729. SEC_E_NO_SPM -- Security Support Provider is not running
  730. STATUS_INVALID_HANDLE -- Credential Handle is invalid
  731. --*/
  732. {
  733. NTSTATUS Status = STATUS_SUCCESS;
  734. PSSP_CREDENTIAL Credential;
  735. SspPrint(( SSP_API_MORE, "SspFreeCredentialHandle Entered\n" ));
  736. //
  737. // Find the referenced credential and delink it.
  738. //
  739. Status = SspCredentialReferenceCredential(
  740. CredentialHandle,
  741. TRUE, // remove the instance of the credential
  742. &Credential );
  743. if ( !NT_SUCCESS( Status ) )
  744. {
  745. goto Cleanup ;
  746. }
  747. //
  748. // Dereferencing the Credential will remove the client's reference
  749. // to it, causing it to be rundown if nobody else is using it.
  750. //
  751. SspCredentialDereferenceCredential( Credential );
  752. //
  753. // Free and locally used resources.
  754. //
  755. Cleanup:
  756. SspPrint(( SSP_API_MORE, "SspFreeCredentialHandle returns 0x%lx\n", Status ));
  757. return Status;
  758. }
  759. NTSTATUS
  760. SspCredentialInitialize(
  761. VOID
  762. )
  763. /*++
  764. Routine Description:
  765. This function initializes this module.
  766. Arguments:
  767. None.
  768. Return Value:
  769. Status of the operation.
  770. --*/
  771. {
  772. NTSTATUS Status = STATUS_SUCCESS;
  773. //
  774. // Initialize the Credential list to be empty.
  775. //
  776. __try
  777. {
  778. RtlInitializeResource(&SspCredentialCritSect);
  779. }
  780. __except(EXCEPTION_EXECUTE_HANDLER)
  781. {
  782. Status = STATUS_INSUFFICIENT_RESOURCES;
  783. goto Cleanup;
  784. }
  785. InitializeListHead( &SspCredentialList );
  786. Cleanup:
  787. return Status;
  788. }
  789. VOID
  790. SspCredentialTerminate(
  791. VOID
  792. )
  793. /*++
  794. Routine Description:
  795. This function cleans up any dangling credentials.
  796. Arguments:
  797. None.
  798. Return Value:
  799. Status of the operation.
  800. --*/
  801. {
  802. #if 0
  803. NTSTATUS Status ;
  804. //
  805. // Drop any lingering Credentials
  806. //
  807. RtlAcquireResourceShared( &SspCredentialCritSect, TRUE );
  808. while ( !IsListEmpty( &SspCredentialList ) ) {
  809. ULONG_PTR CredentialHandle;
  810. PSSP_CREDENTIAL Credential;
  811. CredentialHandle =
  812. (LSA_SEC_HANDLE) CONTAINING_RECORD( SspCredentialList.Flink,
  813. SSP_CREDENTIAL,
  814. Next );
  815. RtlReleaseResource( &SspCredentialCritSect );
  816. Status = SspCredentialReferenceCredential(
  817. CredentialHandle,
  818. TRUE,
  819. TRUE,
  820. &Credential ); // Remove Credential
  821. if ( Credential != NULL ) {
  822. SspCredentialDereferenceCredential(Credential);
  823. }
  824. RtlAcquireResourceShared( &SspCredentialCritSect, TRUE );
  825. }
  826. RtlReleaseResource( &SspCredentialCritSect );
  827. //
  828. // Delete the critical section
  829. //
  830. RtlDeleteResource(&SspCredentialCritSect);
  831. #endif
  832. return;
  833. }
  834. BOOL
  835. SspEnableAllPrivilegesToken(
  836. IN HANDLE ClientTokenHandle
  837. )
  838. {
  839. PTOKEN_PRIVILEGES pPrivileges;
  840. BYTE FastBuffer[ 512 ];
  841. PBYTE SlowBuffer = NULL;
  842. DWORD cbPrivileges;
  843. BOOL fSuccess;
  844. pPrivileges = (PTOKEN_PRIVILEGES)FastBuffer;
  845. cbPrivileges = sizeof( FastBuffer );
  846. fSuccess = GetTokenInformation(
  847. ClientTokenHandle,
  848. TokenPrivileges,
  849. pPrivileges,
  850. cbPrivileges,
  851. &cbPrivileges
  852. );
  853. if( !fSuccess ) {
  854. if( GetLastError() != ERROR_INSUFFICIENT_BUFFER )
  855. return FALSE;
  856. SlowBuffer = (PBYTE)NtLmAllocate( cbPrivileges );
  857. if( SlowBuffer == NULL )
  858. return FALSE;
  859. pPrivileges = (PTOKEN_PRIVILEGES)SlowBuffer;
  860. fSuccess = GetTokenInformation(
  861. ClientTokenHandle,
  862. TokenPrivileges,
  863. pPrivileges,
  864. cbPrivileges,
  865. &cbPrivileges
  866. );
  867. }
  868. if( fSuccess && pPrivileges->PrivilegeCount != 0 ) {
  869. DWORD indexPrivilege;
  870. for( indexPrivilege = 0 ;
  871. indexPrivilege < pPrivileges->PrivilegeCount ;
  872. indexPrivilege ++ )
  873. {
  874. pPrivileges->Privileges[ indexPrivilege ].Attributes |=
  875. SE_PRIVILEGE_ENABLED;
  876. }
  877. fSuccess = AdjustTokenPrivileges(
  878. ClientTokenHandle,
  879. FALSE,
  880. pPrivileges,
  881. 0,
  882. NULL,
  883. NULL
  884. );
  885. if( fSuccess && GetLastError() != ERROR_SUCCESS )
  886. fSuccess = FALSE;
  887. }
  888. if( SlowBuffer )
  889. NtLmFree( SlowBuffer );
  890. return fSuccess;
  891. }