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.

3994 lines
105 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) Microsoft Corporation 1991 - 1992
  6. //
  7. // File: Logons.c
  8. //
  9. // Contents: Logon Session lists and so forth
  10. //
  11. // Functions InitLogonSessions
  12. // AddLogonSession
  13. // LocateLogonSession
  14. //
  15. //
  16. // History: 27 Oct 92 RichardW Created
  17. //
  18. //------------------------------------------------------------------------
  19. #include <lsapch.hxx>
  20. extern "C"
  21. {
  22. #include <ntrmlsa.h>
  23. #include "sidcache.h"
  24. #include <adtp.h>
  25. #include <secext.h>
  26. #include <lm.h> // NetApiBufferFree
  27. NTSTATUS LsapInitializeCredentials();
  28. }
  29. #define THIRTY_MIN { 0x30E23400, 0x00000004 }
  30. #define NEVER_MIN { 0xFFFFFFFF, 0x7FFFFFFF }
  31. #define LOGON_SESSION_LIST_COUNT_MAX 8
  32. // insure power of 2.
  33. C_ASSERT( (LOGON_SESSION_LIST_COUNT_MAX % 2) == 0 );
  34. ULONG LogonSessionListCount;
  35. RTL_RESOURCE LogonSessionListLock[ LOGON_SESSION_LIST_COUNT_MAX ] ;
  36. PVOID LogonSessionTable ;
  37. PHANDLE_PACKAGE LogonSessionPackage ;
  38. LIST_ENTRY LogonSessionList[ LOGON_SESSION_LIST_COUNT_MAX ] ;
  39. ULONG LogonSessionCount[ LOGON_SESSION_LIST_COUNT_MAX ] ;
  40. PLSAP_DS_NAME_MAP LocalSystemNameMap ;
  41. #define LogonIdToListIndex(Id) (Id.LowPart & (LogonSessionListCount-1))
  42. #define LogonIdToListIndexPtr(Id) (Id->LowPart & (LogonSessionListCount-1))
  43. #define WriteLockLogonSessionList(LockIndex) RtlAcquireResourceExclusive( &LogonSessionListLock[LockIndex], TRUE )
  44. #define ReadLockLogonSessionList(LockIndex) RtlAcquireResourceShared( &LogonSessionListLock[LockIndex], TRUE )
  45. #define ReadToWriteLockLogonSessionList(LockIndex) RtlConvertSharedToExclusive( &LogonSessionListLock[LockIndex] )
  46. #define UnlockLogonSessionList(LockIndex) RtlReleaseResource( &LogonSessionListLock[LockIndex] )
  47. // #define LOGON_SESSION_TRACK 1
  48. #ifdef LOGON_SESSION_TRACK
  49. HANDLE LogonSessionLog ;
  50. #endif
  51. extern "C"
  52. VOID LogonSessionLogWrite( PCHAR Format, ... );
  53. #ifdef LOGON_SESSION_TRACK
  54. #define LSLog( x ) LogonSessionLogWrite x
  55. #else
  56. #define LSLog( x )
  57. #endif
  58. LARGE_INTEGER LsapNameLifespans[ LSAP_MAX_DS_NAMES ] =
  59. {
  60. THIRTY_MIN, // Unknown
  61. THIRTY_MIN, // FQDN (CN=yada, DC=yada)
  62. NEVER_MIN, // SAM Compatible
  63. THIRTY_MIN, // Display (Fred Smith)
  64. THIRTY_MIN, // unused
  65. THIRTY_MIN, // unused
  66. NEVER_MIN, // GUID
  67. THIRTY_MIN, // Canonical
  68. THIRTY_MIN, // UPN
  69. THIRTY_MIN, // Canonical Ex
  70. THIRTY_MIN, // SPN
  71. NEVER_MIN, // unused (by GetUserNameEx)
  72. NEVER_MIN // DNS domain name
  73. };
  74. #define LsapConvertLuidToSecHandle( L, H ) \
  75. ((PSecHandle)(H))->dwLower = ((PLUID)(L))->HighPart ; \
  76. ((PSecHandle)(H))->dwUpper = ((PLUID)(L))->LowPart ;
  77. BOOL
  78. LsapSetSamAccountNameForLogonSession(
  79. PLSAP_LOGON_SESSION LogonSession
  80. );
  81. NTSTATUS
  82. LsapGetFormatsForLogon(
  83. PLSAP_LOGON_SESSION LogonSession,
  84. IN LPWSTR Domain,
  85. IN LPWSTR Name,
  86. IN ULONG NameType,
  87. OUT PLSAP_DS_NAME_MAP * Map
  88. );
  89. NTSTATUS
  90. LsapCreateDnsNameFromCanonicalName(
  91. IN PLSAP_LOGON_SESSION LogonSession,
  92. IN ULONG NameType,
  93. OUT PLSAP_DS_NAME_MAP * Map
  94. );
  95. #ifdef LOGON_SESSION_TRACK
  96. VOID
  97. LogonSessionLogWrite(
  98. PCHAR Format,
  99. ...
  100. )
  101. {
  102. CHAR Buffer[ 256 ];
  103. va_list ArgList ;
  104. int TotalSize ;
  105. ULONG SizeWritten ;
  106. if ( LogonSessionLog == NULL )
  107. {
  108. return;
  109. }
  110. va_start( ArgList, Format );
  111. if ((TotalSize = _vsnprintf(Buffer,
  112. sizeof(Buffer),
  113. Format, ArgList)) < 0)
  114. {
  115. return;
  116. }
  117. WriteFile( LogonSessionLog, Buffer, TotalSize, &SizeWritten, NULL );
  118. }
  119. VOID
  120. LsapInitLogonSessionLog(
  121. VOID
  122. )
  123. {
  124. WCHAR Path[ MAX_PATH ];
  125. ExpandEnvironmentStrings(L"%SystemRoot%\\Debug\\logonsession.log", Path, MAX_PATH );
  126. LogonSessionLog = CreateFile( Path, GENERIC_WRITE, FILE_SHARE_READ,
  127. NULL, CREATE_ALWAYS, 0, NULL );
  128. if ( LogonSessionLog == INVALID_HANDLE_VALUE )
  129. {
  130. LogonSessionLog = NULL ;
  131. return ;
  132. }
  133. LogonSessionLogWrite( "New LogonSession log created\n" );
  134. }
  135. #endif
  136. ULONG LogonFormats[] =
  137. {
  138. NameFullyQualifiedDN, // needed for GPO
  139. NameUniqueId // needed for GPO
  140. };
  141. BOOLEAN
  142. LsapIsNameFormatUsedForLogon(
  143. IN ULONG NameType
  144. )
  145. {
  146. ULONG i;
  147. for ( i = 0; i < (sizeof(LogonFormats)/sizeof(LogonFormats[0])); i++) {
  148. if ( NameType == LogonFormats[i] ) {
  149. return TRUE;
  150. }
  151. }
  152. return FALSE;
  153. }
  154. //+---------------------------------------------------------------------------
  155. //
  156. // Function: LsapDerefDsNameMap
  157. //
  158. // Synopsis: Drops the refcount on a DS name map and deletes it if the
  159. // refcount hits zero
  160. //
  161. // Arguments: [Map] -- Pointer to the DS name map
  162. //
  163. // History: 8-17-98 RichardW Created
  164. //
  165. // Notes: If Map points into an active logon session, THE EXCLUSIVE
  166. // WRITE LOCK FOR THAT LOGON SESSION MUST BE HELD WHEN THIS
  167. // ROUTINE IS CALLED.
  168. //
  169. //----------------------------------------------------------------------------
  170. VOID
  171. LsapDerefDsNameMap(
  172. PLSAP_DS_NAME_MAP Map
  173. )
  174. {
  175. LONG RefCount;
  176. RefCount = InterlockedDecrement( &Map->RefCount );
  177. if ( RefCount == 0 )
  178. {
  179. LsapFreePrivateHeap( Map );
  180. }
  181. }
  182. PLSAP_DS_NAME_MAP
  183. LsapCreateDsNameMap(
  184. PUNICODE_STRING Name,
  185. ULONG NameType
  186. )
  187. {
  188. LSAP_DS_NAME_MAP * Map ;
  189. LARGE_INTEGER Now ;
  190. PLARGE_INTEGER Lifespan ;
  191. Map = (PLSAP_DS_NAME_MAP) LsapAllocatePrivateHeap(
  192. sizeof( LSAP_DS_NAME_MAP ) + Name->Length + sizeof(WCHAR) );
  193. if ( Map )
  194. {
  195. Lifespan = &LsapNameLifespans[ NameType ];
  196. if ( Lifespan->QuadPart != 0x7FFFFFFFFFFFFFFF )
  197. {
  198. GetSystemTimeAsFileTime( (LPFILETIME) &Now );
  199. Map->ExpirationTime.QuadPart = Now.QuadPart + Lifespan->QuadPart ;
  200. }
  201. else
  202. {
  203. Map->ExpirationTime.QuadPart = Lifespan->QuadPart ;
  204. }
  205. Map->RefCount = 1 ;
  206. Map->Name.Buffer = (PWSTR) ( Map + 1 );
  207. Map->Name.MaximumLength = (USHORT) ( Name->Length + sizeof(WCHAR) );
  208. Map->Name.Length = Name->Length ;
  209. RtlCopyMemory( Map->Name.Buffer,
  210. Name->Buffer,
  211. Name->Length );
  212. Map->Name.Buffer[ Map->Name.Length / sizeof( WCHAR )] = L'\0';
  213. }
  214. return Map ;
  215. }
  216. //+---------------------------------------------------------------------------
  217. //
  218. // Function: LsapLogonSessionDelete
  219. //
  220. // Synopsis: Callback invoked when record is to be deleted.
  221. //
  222. // Arguments: [Handle] --
  223. // [Context] --
  224. //
  225. // History: 8-17-98 RichardW Created
  226. //
  227. // Notes:
  228. //
  229. //----------------------------------------------------------------------------
  230. VOID
  231. LsapLogonSessionDelete(
  232. PSecHandle Handle,
  233. PVOID Context,
  234. ULONG RefCount
  235. )
  236. {
  237. PLSAP_LOGON_SESSION LogonSession ;
  238. ULONG i;
  239. ULONG ListIndex;
  240. BOOLEAN bAudit;
  241. LogonSession = (PLSAP_LOGON_SESSION) Context ;
  242. NTSTATUS Status;
  243. if (LogonSession->UserSid != NULL)
  244. {
  245. Status = LsapAdtAuditingEnabledByLogonId(
  246. AuditCategoryLogon,
  247. &LogonSession->LogonId,
  248. EVENTLOG_AUDIT_SUCCESS,
  249. &bAudit
  250. );
  251. if (!NT_SUCCESS( Status ))
  252. {
  253. LsapAuditFailed( Status );
  254. }
  255. else if (bAudit)
  256. {
  257. LsapAdtAuditLogoff( LogonSession );
  258. }
  259. }
  260. Status = LsapAdtLogoffPerUserAuditing(
  261. &LogonSession->LogonId
  262. );
  263. if ( !NT_SUCCESS(Status)) {
  264. DebugLog(( DEB_ERROR, "LSA LsapAdtLogoffPerUserAuditing failed, %x\n", Status ));
  265. }
  266. ListIndex = LogonIdToListIndex(LogonSession->LogonId);
  267. WriteLockLogonSessionList(ListIndex);
  268. RemoveEntryList( &LogonSession->List );
  269. LogonSessionCount[ListIndex]-- ;
  270. UnlockLogonSessionList(ListIndex);
  271. LSLog(( "Deleting logon session %x:%x\n",
  272. LogonSession->LogonId.HighPart,
  273. LogonSession->LogonId.LowPart ));
  274. for ( i = 0 ; i < LSAP_MAX_DS_NAMES ; i++ )
  275. {
  276. if ( LogonSession->DsNames[ i ] )
  277. {
  278. LsapDerefDsNameMap( LogonSession->DsNames[ i ] );
  279. LogonSession->DsNames[ i ] = NULL ;
  280. }
  281. }
  282. LsapAuLogonTerminatedPackages( &LogonSession->LogonId );
  283. if ( LogonSession->Packages )
  284. {
  285. LsapFreePackageCredentialList( LogonSession->Packages );
  286. }
  287. if ( LogonSession->UserSid )
  288. {
  289. LsapDbReleaseLogonNameFromCache( LogonSession->UserSid );
  290. LsapFreeLsaHeap( LogonSession->UserSid );
  291. }
  292. if ( LogonSession->ProfilePath.Buffer )
  293. {
  294. LsapFreeLsaHeap( LogonSession->ProfilePath.Buffer );
  295. }
  296. if ( LogonSession->AuthorityName.Buffer )
  297. {
  298. LsapFreeLsaHeap( LogonSession->AuthorityName.Buffer );
  299. }
  300. if ( LogonSession->AccountName.Buffer )
  301. {
  302. LsapFreeLsaHeap( LogonSession->AccountName.Buffer );
  303. }
  304. if ( LogonSession->NewAuthorityName.Buffer )
  305. {
  306. LsapFreeLsaHeap( LogonSession->NewAuthorityName.Buffer );
  307. }
  308. if ( LogonSession->NewAccountName.Buffer )
  309. {
  310. LsapFreeLsaHeap( LogonSession->NewAccountName.Buffer );
  311. }
  312. if( LogonSession->LogonServer.Buffer )
  313. {
  314. LsapFreePrivateHeap( LogonSession->LogonServer.Buffer );
  315. }
  316. if ( LogonSession->TokenHandle != NULL )
  317. {
  318. NtClose( LogonSession->TokenHandle );
  319. }
  320. if ( LogonSession->LicenseHandle != INVALID_HANDLE_VALUE )
  321. {
  322. LsaFreeLicenseHandle( LogonSession->LicenseHandle );
  323. }
  324. CredpDereferenceCredSets( &LogonSession->CredentialSets );
  325. LsapFreePrivateHeap( Context );
  326. }
  327. NTSTATUS
  328. LsapCreateLsaLogonSession(
  329. IN PLUID Luid,
  330. OUT PLSAP_LOGON_SESSION * pLogonSession
  331. )
  332. {
  333. PLSAP_LOGON_SESSION LogonSession ;
  334. SecHandle Handle ;
  335. LogonSession = (PLSAP_LOGON_SESSION) LsapAllocatePrivateHeap(
  336. sizeof( LSAP_LOGON_SESSION ) );
  337. *pLogonSession = LogonSession ;
  338. if ( LogonSession )
  339. {
  340. LSLog(( "Creating logon session %x:%x\n",
  341. Luid->HighPart, Luid->LowPart ));
  342. RtlZeroMemory( LogonSession, sizeof( LSAP_LOGON_SESSION ) );
  343. LogonSession->LogonId = *Luid ;
  344. GetSystemTimeAsFileTime( (LPFILETIME) &LogonSession->LogonTime );
  345. LsapConvertLuidToSecHandle( Luid, &Handle );
  346. if ( LogonSessionPackage->AddHandle(
  347. LogonSessionTable,
  348. &Handle,
  349. LogonSession,
  350. 0 ) )
  351. {
  352. ULONG ListIndex = LogonIdToListIndex(LogonSession->LogonId);
  353. WriteLockLogonSessionList(ListIndex);
  354. InsertHeadList( &LogonSessionList[ListIndex], &LogonSession->List );
  355. LogonSessionCount[ListIndex]++ ;
  356. UnlockLogonSessionList(ListIndex);
  357. return STATUS_SUCCESS;
  358. }
  359. else
  360. {
  361. LsapFreePrivateHeap( LogonSession );
  362. }
  363. return STATUS_UNSUCCESSFUL ;
  364. }
  365. return STATUS_NO_MEMORY ;
  366. }
  367. BOOLEAN
  368. LsapLogonSessionInitialize(
  369. VOID
  370. )
  371. {
  372. LUID LocalSystem = SYSTEM_LUID ;
  373. PLSAP_LOGON_SESSION LogonSession ;
  374. PLSAPR_POLICY_DNS_DOMAIN_INFO DnsDomainInfo = NULL;
  375. PLSAP_DS_NAME_MAP NameMap = NULL;
  376. NTSTATUS Status ;
  377. NT_PRODUCT_TYPE ProductType;
  378. ULONG LockIndex;
  379. HANDLE ProcessToken;
  380. UNICODE_STRING UnicodeString;
  381. OBJECT_ATTRIBUTES obja;
  382. Status = LsapInitializeCredentials();
  383. if (!NT_SUCCESS(Status))
  384. {
  385. return FALSE;
  386. }
  387. LogonSessionListCount = 1;
  388. RtlGetNtProductType( &ProductType );
  389. if( ProductType == NtProductLanManNt ||
  390. ProductType == NtProductServer )
  391. {
  392. SYSTEM_INFO si;
  393. GetSystemInfo( &si );
  394. //
  395. // if not an even power of two, bump it up.
  396. //
  397. if( si.dwNumberOfProcessors & 1 )
  398. {
  399. si.dwNumberOfProcessors++;
  400. }
  401. //
  402. // insure it fits in the confines of the max allowed.
  403. //
  404. if( si.dwNumberOfProcessors > LOGON_SESSION_LIST_COUNT_MAX)
  405. {
  406. si.dwNumberOfProcessors = LOGON_SESSION_LIST_COUNT_MAX;
  407. }
  408. if( si.dwNumberOfProcessors )
  409. {
  410. LogonSessionListCount = si.dwNumberOfProcessors;
  411. }
  412. LogonSessionPackage = &LargeHandlePackage ;
  413. } else {
  414. LogonSessionPackage = &SmallHandlePackage ;
  415. }
  416. //
  417. // list count is 1, or a power of two, for index purposes.
  418. //
  419. ASSERT( (LogonSessionListCount == 1) || ((LogonSessionListCount % 2) == 0) );
  420. for( LockIndex=0 ; LockIndex < LogonSessionListCount ; LockIndex++ )
  421. {
  422. __try {
  423. RtlInitializeResource (&LogonSessionListLock[LockIndex]);
  424. } __except(EXCEPTION_EXECUTE_HANDLER)
  425. {
  426. Status = STATUS_INSUFFICIENT_RESOURCES;
  427. break;
  428. }
  429. InitializeListHead( &LogonSessionList[LockIndex] );
  430. }
  431. if (!NT_SUCCESS(Status))
  432. {
  433. return FALSE;
  434. }
  435. #ifdef LOGON_SESSION_TRACK
  436. LsapInitLogonSessionLog();
  437. LogonSessionPackage = &LargeHandlePackage ;
  438. #endif
  439. if ( LogonSessionPackage->Initialize() )
  440. {
  441. LogonSessionTable = LogonSessionPackage->Create(
  442. HANDLE_PACKAGE_CALLBACK_ON_DELETE |
  443. HANDLE_PACKAGE_REQUIRE_UNIQUE,
  444. NULL,
  445. LsapLogonSessionDelete );
  446. if ( LogonSessionTable == NULL )
  447. {
  448. return FALSE ;
  449. }
  450. }
  451. else
  452. {
  453. return FALSE ;
  454. }
  455. //
  456. // Now, create the initial logon session for local system:
  457. //
  458. Status = LsapCreateLsaLogonSession(
  459. &LocalSystem,
  460. &LogonSession );
  461. if ( !NT_SUCCESS( Status ) )
  462. {
  463. return FALSE ;
  464. }
  465. Status = LsapDuplicateString(
  466. &LogonSession->AccountName,
  467. LsapDbWellKnownSidName(LsapLocalSystemSidIndex) );
  468. if ( !NT_SUCCESS( Status ) )
  469. {
  470. return FALSE ;
  471. }
  472. Status = LsapDuplicateString(
  473. &LogonSession->AuthorityName,
  474. LsapDbWellKnownSidDescription(LsapLocalSystemSidIndex) );
  475. if ( !NT_SUCCESS( Status ) )
  476. {
  477. return FALSE ;
  478. }
  479. Status = LsapDuplicateSid(
  480. &LogonSession->UserSid,
  481. LsapLocalSystemSid );
  482. if ( !NT_SUCCESS( Status ) )
  483. {
  484. return FALSE ;
  485. }
  486. LogonSession->LogonType = (SECURITY_LOGON_TYPE) 0 ;
  487. LogonSession->LicenseHandle = INVALID_HANDLE_VALUE ;
  488. //
  489. // Store the NT4 name away separately:
  490. //
  491. LsapSetSamAccountNameForLogonSession( LogonSession );
  492. if ( LogonSession->DsNames[ NameSamCompatible ] )
  493. {
  494. LocalSystemNameMap = LogonSession->DsNames[ NameSamCompatible ];
  495. LogonSession->DsNames[ NameSamCompatible ] = NULL ;
  496. }
  497. //
  498. // Add the DNS domain name for the machine account
  499. //
  500. Status = LsaIQueryInformationPolicyTrusted(PolicyDnsDomainInformation,
  501. (PLSAPR_POLICY_INFORMATION *) &DnsDomainInfo);
  502. if (NT_SUCCESS(Status))
  503. {
  504. //
  505. // No other threads around -- just jam the name in the logon session directly
  506. //
  507. NameMap = LsapCreateDsNameMap( (PUNICODE_STRING) &DnsDomainInfo->DnsDomainName,
  508. NameDnsDomain );
  509. //
  510. // Free the primary domain info
  511. //
  512. LsaIFree_LSAPR_POLICY_INFORMATION(PolicyDnsDomainInformation,
  513. (PLSAPR_POLICY_INFORMATION) DnsDomainInfo);
  514. if ( NameMap == NULL )
  515. {
  516. return FALSE;
  517. }
  518. LogonSession->DsNames[ NameDnsDomain ] = NameMap;
  519. }
  520. //
  521. // Grab a token handle for the logon session
  522. //
  523. Status = NtOpenProcessToken(
  524. NtCurrentProcess(),
  525. TOKEN_DUPLICATE|TOKEN_QUERY,
  526. &ProcessToken );
  527. if (NT_SUCCESS( Status )) {
  528. Status = LsapSetSessionToken( ProcessToken, &LocalSystem );
  529. NtClose( ProcessToken );
  530. if ( !NT_SUCCESS( Status ) ) {
  531. return FALSE ;
  532. }
  533. }
  534. //
  535. // Init System Logon will update the names appropriately.
  536. //
  537. return TRUE ;
  538. }
  539. NTSTATUS
  540. LsapCreateLogonSession(
  541. IN OUT PLUID LogonId
  542. )
  543. /*++
  544. Routine Description:
  545. This function adds a new logon session to the list of logon sessions.
  546. This service acquires the AuLock.
  547. Arguments:
  548. LogonId - The ID to assign to the new logon session. If it is zero,
  549. a new logon ID will be created.
  550. Return Value:
  551. STATUS_SUCCESS - The logon session has been successfully deleted.
  552. STATUS_LOGON_SESSION_COLLISION - The specified Logon ID is already in
  553. use by another logon session.
  554. STATUS_QUOTA_EXCEEDED - The request could not be fulfilled due to
  555. memory quota limitations.
  556. --*/
  557. {
  558. NTSTATUS Status;
  559. PLSAP_LOGON_SESSION NewSession;
  560. SecHandle Handle ;
  561. //
  562. // Create a logon Id if it has not already been don
  563. //
  564. if (LogonId->LowPart == 0 && LogonId->HighPart == 0)
  565. {
  566. Status = NtAllocateLocallyUniqueId(LogonId);
  567. ASSERT(NT_SUCCESS(Status));
  568. }
  569. Status = LsapCreateLsaLogonSession(
  570. LogonId,
  571. &NewSession );
  572. if ( !NT_SUCCESS( Status ) )
  573. {
  574. return Status ;
  575. }
  576. NewSession->CreatingPackage = GetCurrentPackageId();
  577. RtlCopyLuid( &NewSession->LogonId, LogonId );
  578. //
  579. // Tell the reference monitor about the logon session...
  580. //
  581. Status = LsapCallRm(
  582. RmCreateLogonSession,
  583. (PVOID)LogonId,
  584. (ULONG)sizeof(LUID),
  585. NULL,
  586. 0
  587. );
  588. if ( !NT_SUCCESS(Status) ) {
  589. LsapConvertLuidToSecHandle( LogonId, &Handle );
  590. LogonSessionPackage->DeleteHandle(
  591. LogonSessionTable,
  592. &Handle,
  593. FALSE );
  594. return Status;
  595. }
  596. return STATUS_SUCCESS;
  597. }
  598. NTSTATUS
  599. LsapGetLogonSessionAccountInfo (
  600. IN PLUID LogonId,
  601. OUT PUNICODE_STRING AccountName,
  602. OUT PUNICODE_STRING AuthorityName
  603. )
  604. /*++
  605. Routine Description:
  606. This function retrieves username and authentication domain information
  607. for a specified logon session.
  608. Arguments:
  609. LogonId - The ID of the logon session to set.
  610. AccountName - points to a unicode string with no buffer. A buffer
  611. containing the account name will be allocated and returned
  612. using the PROCESS HEAP - NOT THE LSA HEAP.
  613. AuthorityName - points to a unicode string with no buffer. A buffer
  614. containing the authority name will be allocated and returned
  615. using the PROCESS HEAP - NOT THE LSA HEAP.
  616. Return Value:
  617. STATUS_NO_SUCH_LOGON_SESSION - The specified logon session does
  618. not currently exist.
  619. STATUS_NO_MEMORY - Could not allocate enough process heap.
  620. --*/
  621. {
  622. NTSTATUS Status = STATUS_SUCCESS;
  623. PLSAP_LOGON_SESSION LogonSession;
  624. ULONG ListIndex;
  625. AccountName->Length = 0;
  626. AccountName->Buffer = NULL;
  627. AccountName->MaximumLength = 0;
  628. AuthorityName->Length = 0;
  629. AuthorityName->Buffer = NULL;
  630. AuthorityName->MaximumLength = 0;
  631. LogonSession = LsapLocateLogonSession(LogonId);
  632. if (LogonSession == NULL)
  633. {
  634. return STATUS_NO_SUCH_LOGON_SESSION ;
  635. }
  636. ListIndex = LogonIdToListIndex( LogonSession->LogonId );
  637. ReadLockLogonSessionList(ListIndex);
  638. if ( NT_SUCCESS( Status ) &&
  639. LogonSession->AccountName.Buffer )
  640. {
  641. Status = LsapDuplicateString( AccountName, &LogonSession->AccountName );
  642. }
  643. if ( NT_SUCCESS( Status ) &&
  644. LogonSession->AuthorityName.Buffer )
  645. {
  646. Status = LsapDuplicateString( AuthorityName, &LogonSession->AuthorityName );
  647. }
  648. UnlockLogonSessionList(ListIndex);
  649. LsapReleaseLogonSession(LogonSession);
  650. return(Status);
  651. }
  652. BOOL
  653. LsapSetSamAccountNameForLogonSession(
  654. PLSAP_LOGON_SESSION LogonSession
  655. )
  656. {
  657. UNICODE_STRING CombinedName ;
  658. if ( LogonSession->AccountName.Buffer &&
  659. LogonSession->AuthorityName.Buffer )
  660. {
  661. SafeAllocaAllocate(CombinedName.Buffer,
  662. LogonSession->AccountName.Length +
  663. LogonSession->AuthorityName.Length +
  664. sizeof( WCHAR ) * 2);
  665. if ( CombinedName.Buffer )
  666. {
  667. CombinedName.MaximumLength = LogonSession->AccountName.Length +
  668. LogonSession->AuthorityName.Length +
  669. sizeof( WCHAR ) * 2 ;
  670. CombinedName.Length = CombinedName.MaximumLength - 2 ;
  671. RtlCopyMemory( CombinedName.Buffer,
  672. LogonSession->AuthorityName.Buffer,
  673. LogonSession->AuthorityName.Length );
  674. CombinedName.Buffer[ LogonSession->AuthorityName.Length / sizeof(WCHAR) ] = L'\\';
  675. RtlCopyMemory( &CombinedName.Buffer[ LogonSession->AuthorityName.Length / sizeof( WCHAR ) + 1],
  676. LogonSession->AccountName.Buffer,
  677. LogonSession->AccountName.Length );
  678. CombinedName.Buffer[ CombinedName.Length / sizeof(WCHAR) ] = L'\0';
  679. LogonSession->DsNames[ NameSamCompatible ] =
  680. LsapCreateDsNameMap(
  681. &CombinedName,
  682. NameSamCompatible );
  683. SafeAllocaFree(CombinedName.Buffer);
  684. }
  685. else
  686. {
  687. return FALSE;
  688. }
  689. }
  690. return ( LogonSession->DsNames[ NameSamCompatible ] != NULL );
  691. }
  692. NTSTATUS
  693. LsapSetLogonSessionAccountInfo (
  694. IN PLUID LogonId,
  695. IN PUNICODE_STRING AccountName,
  696. IN PUNICODE_STRING AuthorityName,
  697. IN OPTIONAL PUNICODE_STRING ProfilePath,
  698. IN PSID * pUserSid,
  699. IN SECURITY_LOGON_TYPE LogonType,
  700. IN OPTIONAL PSECPKG_PRIMARY_CRED PrimaryCredentials
  701. )
  702. /*++
  703. Routine Description:
  704. This function sets username and authentication domain information
  705. for a specified logon session.
  706. The current account name and authority name, if any, will be freed.
  707. However, if this is the system logon session the information won't
  708. be set.
  709. Arguments:
  710. LogonId - The ID of the logon session to set.
  711. AccountName - points to a unicode string containing the account name
  712. to be assigned to the logon session. Both the UNICODE_STRING
  713. structure and the buffer pointed to by that structure are expected
  714. to be allocated from lsa heap, and they will eventually be freed
  715. to that heap when no longer needed.
  716. AuthorityName - points to a unicode string containing the name of the
  717. authenticating authority of the logon session. Both the
  718. UNICODE_STRING structure and the buffer pointed to by that structure
  719. are expected to be allocated from lsa heap, and they will eventually
  720. be freed to that heap when no longer needed.
  721. ProfilePath - points to a unicode string containing the path to the
  722. user's profile. The structure & buffer need to be freed.
  723. Return Value:
  724. STATUS_NO_SUCH_LOGON_SESSION - The specified logon session does
  725. not currently exist.
  726. --*/
  727. {
  728. NTSTATUS Status = STATUS_SUCCESS;
  729. PLSAP_LOGON_SESSION LogonSession;
  730. ULONG ListIndex;
  731. UNICODE_STRING NullString = { 0 };
  732. ULONG i ;
  733. UNICODE_STRING CombinedName ;
  734. UNICODE_STRING OldAccountName = {0};
  735. UNICODE_STRING OldProfilePath = {0};
  736. UNICODE_STRING OldAuthorityName = {0};
  737. PSID OldUserSid = NULL;
  738. UNICODE_STRING OldLogonServer = {0};
  739. UNICODE_STRING LogonServer = {0};
  740. SECURITY_LOGON_TYPE OldLogonType;
  741. BOOL fAccountNameChanged = TRUE;
  742. BOOL fAuthorityNameChanged = TRUE;
  743. BOOL fUserSidChanged = TRUE;
  744. ASSERT( pUserSid );
  745. LogonSession = LsapLocateLogonSession(LogonId);
  746. if ( !LogonSession )
  747. {
  748. return STATUS_NO_SUCH_LOGON_SESSION ;
  749. }
  750. //
  751. // Get a Credential Set for this session.
  752. //
  753. if ( ( ( LogonType == Interactive ) ||
  754. ( LogonType == Batch ) ||
  755. ( LogonType == Service ) ||
  756. ( LogonType == CachedInteractive ) ||
  757. ( LogonType == RemoteInteractive ) ) &&
  758. ( *pUserSid != NULL ) ) {
  759. Status = CredpCreateCredSets( *pUserSid,
  760. AuthorityName,
  761. &LogonSession->CredentialSets );
  762. if ( !NT_SUCCESS(Status) ) {
  763. LsapReleaseLogonSession(LogonSession);
  764. return Status;
  765. }
  766. }
  767. if( PrimaryCredentials != NULL )
  768. {
  769. if( PrimaryCredentials->LogonServer.Buffer )
  770. {
  771. LogonServer.Buffer = (PWSTR)LsapAllocatePrivateHeap( PrimaryCredentials->LogonServer.Length );
  772. if ( LogonServer.Buffer != NULL )
  773. {
  774. CopyMemory( LogonServer.Buffer,
  775. PrimaryCredentials->LogonServer.Buffer,
  776. PrimaryCredentials->LogonServer.Length
  777. );
  778. LogonServer.Length = PrimaryCredentials->LogonServer.Length;
  779. LogonServer.MaximumLength = LogonServer.Length;
  780. }
  781. else
  782. {
  783. LsapReleaseLogonSession( LogonSession );
  784. return STATUS_NO_MEMORY;
  785. }
  786. }
  787. }
  788. ListIndex = LogonIdToListIndex( LogonSession->LogonId );
  789. WriteLockLogonSessionList(ListIndex);
  790. for ( i = 0 ; i < LSAP_MAX_DS_NAMES ; i++ )
  791. {
  792. //
  793. // Save the names that were prepopulated by the auth package.
  794. // SAM name is restored further down.
  795. //
  796. if ( LogonSession->DsNames[ i ]
  797. &&
  798. (i != NameDisplay)
  799. &&
  800. (i != NameUserPrincipal)
  801. &&
  802. (i != NameDnsDomain))
  803. {
  804. LsapDerefDsNameMap( LogonSession->DsNames[ i ] );
  805. LogonSession->DsNames[ i ] = NULL ;
  806. }
  807. }
  808. //
  809. // Free current names if necessary. Since LsapDbAddLogonNameToCache is
  810. // called outside the scope of the LogonSessionListLock, there's a potential
  811. // race condition when multiple threads call LsaLogonUser for LocalService
  812. // or NetworkService (since they always use the same logon session). To
  813. // avoid this, don't update the parameters in the logon session unless
  814. // the incoming parameters are different from those already in the session.
  815. // Do this only for the parameters LsapDbAddLogonNameToCache uses (account
  816. // name, authority name, and user SID).
  817. //
  818. if (LogonSession->AccountName.Buffer != NULL)
  819. {
  820. if (RtlCompareUnicodeString(&LogonSession->AccountName,
  821. AccountName,
  822. TRUE) == 0)
  823. {
  824. fAccountNameChanged = FALSE;
  825. }
  826. }
  827. if (LogonSession->AuthorityName.Buffer != NULL)
  828. {
  829. if (RtlCompareUnicodeString(&LogonSession->AuthorityName,
  830. AuthorityName,
  831. TRUE) == 0)
  832. {
  833. fAuthorityNameChanged = FALSE;
  834. }
  835. }
  836. if (LogonSession->UserSid != NULL)
  837. {
  838. if (RtlEqualSid(LogonSession->UserSid,
  839. *pUserSid))
  840. {
  841. fUserSidChanged = FALSE;
  842. }
  843. }
  844. //
  845. // Assign the new names - they may be null
  846. //
  847. if (fAccountNameChanged)
  848. {
  849. OldAccountName = LogonSession->AccountName;
  850. if ( AccountName )
  851. {
  852. LogonSession->AccountName = *AccountName;
  853. }
  854. else
  855. {
  856. LogonSession->AccountName = NullString ;
  857. }
  858. }
  859. if (fAuthorityNameChanged)
  860. {
  861. OldAuthorityName = LogonSession->AuthorityName;
  862. if ( AuthorityName )
  863. {
  864. LogonSession->AuthorityName = *AuthorityName;
  865. }
  866. else
  867. {
  868. LogonSession->AuthorityName = NullString ;
  869. }
  870. }
  871. OldProfilePath = LogonSession->ProfilePath;
  872. if ( ProfilePath )
  873. {
  874. LogonSession->ProfilePath = *ProfilePath;
  875. }
  876. else
  877. {
  878. LogonSession->ProfilePath = NullString ;
  879. }
  880. if (fUserSidChanged)
  881. {
  882. OldUserSid = LogonSession->UserSid;
  883. LogonSession->UserSid = *pUserSid;
  884. }
  885. OldLogonType = LogonSession->LogonType;
  886. LogonSession->LogonType = LogonType;
  887. OldLogonServer = LogonSession->LogonServer;
  888. LogonSession->LogonServer = LogonServer;
  889. LogonServer.Buffer = NULL;
  890. if ( FALSE == LsapSetSamAccountNameForLogonSession( LogonSession ))
  891. {
  892. Status = STATUS_NO_MEMORY;
  893. }
  894. if ( !NT_SUCCESS( Status ))
  895. {
  896. if ( fAccountNameChanged )
  897. {
  898. LogonSession->AccountName = OldAccountName;
  899. OldAccountName.Buffer = NULL;
  900. }
  901. if ( fAuthorityNameChanged )
  902. {
  903. LogonSession->AuthorityName = OldAuthorityName;
  904. OldAuthorityName.Buffer = NULL;
  905. }
  906. LogonSession->ProfilePath = OldProfilePath;
  907. OldProfilePath.Buffer = NULL;
  908. if ( fUserSidChanged )
  909. {
  910. LogonSession->UserSid = OldUserSid;
  911. OldUserSid = NULL;
  912. }
  913. LogonServer = LogonSession->LogonServer;
  914. LogonSession->LogonServer = OldLogonServer;
  915. OldLogonServer.Buffer = NULL;
  916. LogonSession->LogonType = OldLogonType;
  917. }
  918. UnlockLogonSessionList(ListIndex);
  919. if ( NT_SUCCESS( Status ))
  920. {
  921. if ( fAccountNameChanged && AccountName )
  922. {
  923. AccountName->Buffer = NULL;
  924. AccountName->Length = 0;
  925. }
  926. if ( fAuthorityNameChanged && AuthorityName )
  927. {
  928. AuthorityName->Buffer = NULL;
  929. AuthorityName->Length = 0;
  930. }
  931. if ( fUserSidChanged && pUserSid )
  932. {
  933. *pUserSid = NULL;
  934. }
  935. if ( ProfilePath )
  936. {
  937. ProfilePath->Buffer = NULL;
  938. ProfilePath->Length = 0;
  939. }
  940. }
  941. if ( NT_SUCCESS( Status ) &&
  942. LogonSession->UserSid &&
  943. LogonSession->AccountName.Buffer &&
  944. LogonSession->AuthorityName.Buffer )
  945. {
  946. LsapDbAddLogonNameToCache(
  947. &LogonSession->AccountName,
  948. &LogonSession->AuthorityName,
  949. LogonSession->UserSid );
  950. }
  951. LsapReleaseLogonSession(LogonSession);
  952. if( OldAccountName.Buffer )
  953. {
  954. LsapFreeLsaHeap( OldAccountName.Buffer );
  955. }
  956. if( OldAuthorityName.Buffer )
  957. {
  958. LsapFreeLsaHeap( OldAuthorityName.Buffer );
  959. }
  960. if( OldProfilePath.Buffer )
  961. {
  962. LsapFreeLsaHeap( OldProfilePath.Buffer );
  963. }
  964. if( OldUserSid )
  965. {
  966. LsapFreeLsaHeap( OldUserSid );
  967. }
  968. if( OldLogonServer.Buffer )
  969. {
  970. LsapFreePrivateHeap( OldLogonServer.Buffer );
  971. }
  972. return(Status);
  973. }
  974. NTSTATUS
  975. LsapLogonSessionDeletedWrkr(
  976. IN PLSA_COMMAND_MESSAGE CommandMessage,
  977. OUT PLSA_REPLY_MESSAGE ReplyMessage
  978. )
  979. /*++
  980. Routine Description:
  981. This function is called by the reference monitor (via LPC) when the
  982. reference count on a logon session drops to zero. This indicates that
  983. the logon session is no longer needed. This is technically when the
  984. user is considered (from a security standpoint) to be logged out.
  985. Arguments:
  986. CommandMessage - Pointer to structure containing LSA command message
  987. information consisting of an LPC PORT_MESSAGE structure followed
  988. by the command number (LsapComponentTestCommand).
  989. The command-specific portion of this parameter contains the
  990. LogonId (LUID) of the logon session whose reference count
  991. has dropped to zero.
  992. ReplyMessage - Pointer to structure containing LSA reply message
  993. information consisting of an LPC PORT_MESSAGE structure followed
  994. by the command ReturnedStatus field in which a status code from the
  995. command will be returned.
  996. Return Value:
  997. None.
  998. --*/
  999. {
  1000. NTSTATUS Status;
  1001. LUID LogonId;
  1002. SecHandle Handle ;
  1003. //
  1004. // Check that command is expected type
  1005. //
  1006. ASSERT( CommandMessage->CommandNumber == LsapLogonSessionDeletedCommand );
  1007. //
  1008. // Typecast the command parameter to what we expect.
  1009. //
  1010. LogonId = *((LUID *) CommandMessage->CommandParams);
  1011. LsapConvertLuidToSecHandle( &LogonId, &Handle );
  1012. LogonSessionPackage->DeleteHandle(
  1013. LogonSessionTable,
  1014. &Handle,
  1015. FALSE );
  1016. UNREFERENCED_PARAMETER(ReplyMessage); // Intentionally not referenced
  1017. return( STATUS_SUCCESS );
  1018. }
  1019. PLSAP_LOGON_SESSION
  1020. LsapLocateLogonSession(
  1021. PLUID LogonId
  1022. )
  1023. {
  1024. SecHandle Handle ;
  1025. PLSAP_LOGON_SESSION LogonSession ;
  1026. LsapConvertLuidToSecHandle( LogonId, &Handle );
  1027. LogonSession = (PLSAP_LOGON_SESSION) LogonSessionPackage->GetHandleContext(
  1028. LogonSessionTable,
  1029. &Handle );
  1030. return LogonSession ;
  1031. }
  1032. VOID
  1033. LsapReleaseLogonSession(
  1034. PLSAP_LOGON_SESSION LogonSession
  1035. )
  1036. {
  1037. SecHandle Handle ;
  1038. LsapConvertLuidToSecHandle( &LogonSession->LogonId, &Handle );
  1039. LogonSessionPackage->ReleaseContext(
  1040. LogonSessionTable,
  1041. &Handle );
  1042. }
  1043. NTSTATUS
  1044. LsapDeleteLogonSession (
  1045. IN PLUID LogonId
  1046. )
  1047. /*++
  1048. Routine Description:
  1049. This function deletes a logon session context record. It is expected
  1050. that no TOKEN objects were ever created within this logon session.
  1051. This means we must inform the Reference Monitor to clean up its
  1052. information on the logon session.
  1053. If TOKEN objecs were created within this logon session, then deletion
  1054. of those tokens will cause the logon session to be deleted.
  1055. This service acquires the AuLock.
  1056. Arguments:
  1057. LogonId - The ID of the logon session to delete.
  1058. Return Value:
  1059. STATUS_SUCCESS - The logon session has been successfully deleted.
  1060. STATUS_NO_SUCH_LOGON_SESSION - The specified logon session doesn't
  1061. exist.
  1062. STATUS_BAD_LOGON_SESSION_STATE - The logon session is not in a state
  1063. that allows it to be deleted. This is typically an indication
  1064. that the logon session has had a token created within it, and it
  1065. may no longer be explicitly deleted.
  1066. --*/
  1067. {
  1068. PLSAP_LOGON_SESSION LogonSession ;
  1069. SecHandle Handle;
  1070. NTSTATUS Status ;
  1071. Status = LsapCallRm(
  1072. RmDeleteLogonSession,
  1073. (PVOID)LogonId,
  1074. (ULONG)sizeof(LUID),
  1075. NULL,
  1076. 0
  1077. );
  1078. if ( !NT_SUCCESS(Status)) {
  1079. DebugLog(( DEB_ERROR, "LSA/RM DeleteLogonSession failed, %x\n", Status ));
  1080. }
  1081. LsapConvertLuidToSecHandle( LogonId, &Handle );
  1082. LogonSessionPackage->DeleteHandle(
  1083. LogonSessionTable,
  1084. &Handle,
  1085. FALSE );
  1086. return STATUS_SUCCESS ;
  1087. }
  1088. PLSAP_DS_NAME_MAP
  1089. LsapGetNameForLocalSystem(
  1090. VOID
  1091. )
  1092. {
  1093. InterlockedIncrement( &LocalSystemNameMap->RefCount );
  1094. return LocalSystemNameMap;
  1095. }
  1096. NTSTATUS
  1097. LsapImpersonateNetworkService(
  1098. VOID
  1099. )
  1100. {
  1101. NTSTATUS Status;
  1102. HANDLE TokenHandle = NULL;
  1103. LUID NetworkServiceLuid = NETWORKSERVICE_LUID;
  1104. Status = LsapOpenTokenByLogonId(&NetworkServiceLuid, &TokenHandle);
  1105. if (!NT_SUCCESS(Status))
  1106. {
  1107. goto Cleanup;
  1108. }
  1109. Status = NtSetInformationThread(
  1110. NtCurrentThread(),
  1111. ThreadImpersonationToken,
  1112. &TokenHandle,
  1113. sizeof(TokenHandle)
  1114. );
  1115. if (!NT_SUCCESS( Status))
  1116. {
  1117. goto Cleanup;
  1118. }
  1119. Cleanup:
  1120. if (TokenHandle)
  1121. {
  1122. NtClose(TokenHandle);
  1123. }
  1124. return Status;
  1125. }
  1126. NTSTATUS
  1127. LsapGetNameForLogonSession(
  1128. PLSAP_LOGON_SESSION LogonSession,
  1129. ULONG NameType,
  1130. PLSAP_DS_NAME_MAP * Map,
  1131. BOOL LocalOnly
  1132. )
  1133. {
  1134. NTSTATUS Status ;
  1135. ULONG ListIndex;
  1136. PLSAP_DS_NAME_MAP NameMap ;
  1137. LARGE_INTEGER Now ;
  1138. WCHAR TranslatedNameBuffer[ MAX_PATH ];
  1139. ULONG TranslatedNameLength ;
  1140. PWSTR TranslatedName = NULL ;
  1141. UNICODE_STRING TransName ;
  1142. PLSAP_DS_NAME_MAP SamMap ;
  1143. BOOL TranslateStatus;
  1144. BOOL Flush = FALSE ;
  1145. DWORD Options ;
  1146. WCHAR * AuthorityName = NULL;
  1147. WCHAR * SamMapName = NULL;
  1148. BOOLEAN NeedToImpersonate = TRUE;
  1149. BOOL NeedDnsDomainName = FALSE;
  1150. BOOL GotComputerName = FALSE;
  1151. *Map = NULL ;
  1152. Options = NameType & SPM_NAME_OPTION_MASK ;
  1153. NameType &= (~SPM_NAME_OPTION_MASK );
  1154. if ( Options & SPM_NAME_OPTION_FLUSH )
  1155. {
  1156. Flush = TRUE ;
  1157. }
  1158. if ( NameType >= LSAP_MAX_DS_NAMES )
  1159. {
  1160. return STATUS_INVALID_PARAMETER ;
  1161. }
  1162. GetSystemTimeAsFileTime( (LPFILETIME) &Now );
  1163. //
  1164. // Check for format/account combinations that have no chance
  1165. // of succeeding (e.g., DS formats for local-only accounts)
  1166. // to avoid hitting the network. Do this outside of the
  1167. // critical region since the LUID is a read-only field.
  1168. //
  1169. if (NameType == NameUniqueId)
  1170. {
  1171. LUID LocalServiceLuid = LOCALSERVICE_LUID;
  1172. LUID NetworkServiceLuid = NETWORKSERVICE_LUID;
  1173. if (RtlEqualLuid(&LogonSession->LogonId,
  1174. &LocalServiceLuid)
  1175. ||
  1176. RtlEqualLuid(&LogonSession->LogonId,
  1177. &NetworkServiceLuid))
  1178. {
  1179. return STATUS_NO_SUCH_DOMAIN;
  1180. }
  1181. }
  1182. ListIndex = LogonIdToListIndex( LogonSession->LogonId );
  1183. ReadLockLogonSessionList(ListIndex);
  1184. if ( LogonSession->DsNames[ NameType ] )
  1185. {
  1186. NameMap = LogonSession->DsNames[ NameType ];
  1187. if ( ( NameMap->ExpirationTime.QuadPart >= Now.QuadPart ) &&
  1188. ( !Flush ) )
  1189. {
  1190. //
  1191. // Valid entry, bump the ref count and return it
  1192. //
  1193. InterlockedIncrement( &NameMap->RefCount );
  1194. UnlockLogonSessionList(ListIndex);
  1195. *Map = NameMap ;
  1196. return STATUS_SUCCESS ;
  1197. }
  1198. //
  1199. // convert the lock to exclusive.
  1200. //
  1201. ReadToWriteLockLogonSessionList(ListIndex);
  1202. //
  1203. // Entry has expired. Remove it, crack the name anew
  1204. //
  1205. LsapDerefDsNameMap( NameMap );
  1206. LogonSession->DsNames[ NameType ] = NULL ;
  1207. }
  1208. SamMap = LogonSession->DsNames[ NameSamCompatible ];
  1209. if ( SamMap == NULL )
  1210. {
  1211. LsapSetSamAccountNameForLogonSession( LogonSession );
  1212. SamMap = LogonSession->DsNames[ NameSamCompatible ] ;
  1213. if ( SamMap == NULL )
  1214. {
  1215. UnlockLogonSessionList(ListIndex);
  1216. return STATUS_NO_MEMORY ;
  1217. }
  1218. }
  1219. //
  1220. // Not present, or it had expired. Crack from the beginning:
  1221. //
  1222. if ( NameType == NameSamCompatible )
  1223. {
  1224. *Map = SamMap ;
  1225. InterlockedIncrement( &SamMap->RefCount );
  1226. UnlockLogonSessionList(ListIndex);
  1227. return STATUS_SUCCESS ;
  1228. }
  1229. else if ( NameType == NameDnsDomain )
  1230. {
  1231. //
  1232. // See if we're dealing with an NT4 domain, in which case we won't
  1233. // have a DNS domain name. If so, return ERROR_NONE_MAPPED for
  1234. // consistency and a way for the caller to know the DC is NT4.
  1235. //
  1236. if (!LocalOnly)
  1237. {
  1238. DWORD dwError;
  1239. PDOMAIN_CONTROLLER_INFO pDcInfo = NULL;
  1240. TranslatedNameLength = MAX_PATH ;
  1241. TranslatedName = TranslatedNameBuffer ;
  1242. if (!GetComputerNameW( TranslatedName, &TranslatedNameLength ))
  1243. {
  1244. //
  1245. // GetComputerNameW only sets the last Win32 error but we
  1246. // need to return an NTSTATUS code. Set the last status
  1247. // to STATUS_UNSUCCESSFUL (via RtlNtStatusToDosError) and
  1248. // then reset the last Win32 error.
  1249. //
  1250. dwError = GetLastError();
  1251. SetLastError(RtlNtStatusToDosError(STATUS_UNSUCCESSFUL));
  1252. SetLastError(dwError);
  1253. return NtCurrentTeb()->LastStatusValue;
  1254. }
  1255. RtlInitUnicodeString( &TransName, TranslatedName );
  1256. GotComputerName = TRUE;
  1257. //
  1258. // Don't hit the network for local logons.
  1259. //
  1260. if ( !RtlEqualUnicodeString( &LogonSession->AuthorityName,
  1261. &TransName,
  1262. TRUE ) )
  1263. {
  1264. if (LogonSession->AuthorityName.MaximumLength <= LogonSession->AuthorityName.Length ||
  1265. LogonSession->AuthorityName.Buffer[LogonSession->AuthorityName.Length / sizeof(WCHAR)] != L'\0')
  1266. {
  1267. SafeAllocaAllocate(AuthorityName,
  1268. LogonSession->AuthorityName.Length + sizeof(WCHAR));
  1269. if (AuthorityName == NULL)
  1270. {
  1271. UnlockLogonSessionList(ListIndex);
  1272. return STATUS_INSUFFICIENT_RESOURCES;
  1273. }
  1274. RtlCopyMemory(AuthorityName,
  1275. LogonSession->AuthorityName.Buffer,
  1276. LogonSession->AuthorityName.Length);
  1277. AuthorityName[LogonSession->AuthorityName.Length / sizeof( WCHAR )] = L'\0';
  1278. }
  1279. else
  1280. {
  1281. AuthorityName = LogonSession->AuthorityName.Buffer;
  1282. }
  1283. //
  1284. // Note that this perf hit is negligible for the non-NT4 case as the next call
  1285. // to DsGetDcName (in SecpTranslateName) will be satisfied from the cache. In
  1286. // the NT4 case, we'd otherwise drop into SecpTranslateName and make a failing
  1287. // DsGetDcName call there instead.
  1288. //
  1289. UnlockLogonSessionList(ListIndex);
  1290. dwError = DsGetDcName(NULL,
  1291. AuthorityName,
  1292. NULL,
  1293. NULL,
  1294. DS_DIRECTORY_SERVICE_PREFERRED,
  1295. &pDcInfo);
  1296. // LOCKLOCK: think about read, then convert to write, re-check.
  1297. WriteLockLogonSessionList(ListIndex);
  1298. //
  1299. // Recheck the name in case it was filled in while we
  1300. // were hitting the network.
  1301. //
  1302. if ( LogonSession->DsNames[ NameType ] )
  1303. {
  1304. NameMap = LogonSession->DsNames[ NameType ];
  1305. if ( ( NameMap->ExpirationTime.QuadPart >= Now.QuadPart ) &&
  1306. ( !Flush ) )
  1307. {
  1308. //
  1309. // Valid entry, bump the ref count and return it
  1310. //
  1311. InterlockedIncrement( &NameMap->RefCount );
  1312. UnlockLogonSessionList(ListIndex);
  1313. if (dwError == NO_ERROR)
  1314. {
  1315. NetApiBufferFree(pDcInfo);
  1316. }
  1317. *Map = NameMap ;
  1318. return STATUS_SUCCESS ;
  1319. }
  1320. //
  1321. // Entry has expired. Remove it, crack the name anew
  1322. //
  1323. LsapDerefDsNameMap( NameMap );
  1324. LogonSession->DsNames[ NameType ] = NULL ;
  1325. }
  1326. if (dwError != NO_ERROR)
  1327. {
  1328. UnlockLogonSessionList(ListIndex);
  1329. //
  1330. // DsGetDcName doesn't set the last error. Set it now along
  1331. // with the last status value (first SetLastError sets the
  1332. // status value via RtlNtStatusToDosError).
  1333. //
  1334. SetLastError(RtlNtStatusToDosError(STATUS_UNSUCCESSFUL));
  1335. SetLastError(dwError);
  1336. return NtCurrentTeb()->LastStatusValue;
  1337. }
  1338. if (!(pDcInfo->Flags & DS_DS_FLAG))
  1339. {
  1340. //
  1341. // NT4 DC
  1342. //
  1343. UnlockLogonSessionList(ListIndex);
  1344. NetApiBufferFree(pDcInfo);
  1345. return STATUS_NONE_MAPPED;
  1346. }
  1347. NetApiBufferFree(pDcInfo);
  1348. }
  1349. }
  1350. //
  1351. // Since NameDnsDomain is a GetUserNameEx construct, calling
  1352. // the DS for it will directly will fail. Ask the DS for the
  1353. // canonical name and on success, extract the DNS name below.
  1354. //
  1355. NeedDnsDomainName = TRUE;
  1356. NameType = NameCanonical;
  1357. //
  1358. // If the canonical name is already there, we don't
  1359. // need to hit the DS below.
  1360. //
  1361. if (LogonSession->DsNames[NameType])
  1362. {
  1363. Status = LsapCreateDnsNameFromCanonicalName(LogonSession, NameType, Map);
  1364. UnlockLogonSessionList(ListIndex);
  1365. return Status;
  1366. }
  1367. //
  1368. // We may have the CanonicalEx name and not Canonical -- try that one too.
  1369. //
  1370. NameType = NameCanonicalEx;
  1371. if (LogonSession->DsNames[NameType])
  1372. {
  1373. Status = LsapCreateDnsNameFromCanonicalName(LogonSession, NameType, Map);
  1374. UnlockLogonSessionList(ListIndex);
  1375. return Status;
  1376. }
  1377. //
  1378. // Otherwise fall through and hit the DS for the canonical name if allowed
  1379. //
  1380. if (LocalOnly)
  1381. {
  1382. UnlockLogonSessionList(ListIndex);
  1383. return STATUS_NONE_MAPPED;
  1384. }
  1385. }
  1386. UnlockLogonSessionList(ListIndex);
  1387. if (LocalOnly)
  1388. {
  1389. //
  1390. // We got this far and the name's not yet mapped. Since we
  1391. // can't hit the network, fail.
  1392. //
  1393. return STATUS_NONE_MAPPED;
  1394. }
  1395. if (!GotComputerName)
  1396. {
  1397. TranslatedNameLength = MAX_PATH ;
  1398. TranslatedName = TranslatedNameBuffer ;
  1399. if (!GetComputerNameW( TranslatedName, &TranslatedNameLength ))
  1400. {
  1401. //
  1402. // GetComputerNameW only sets the last Win32 error but we
  1403. // need to return an NTSTATUS code. Set the last status
  1404. // to STATUS_UNSUCCESSFUL (via RtlNtStatusToDosError) and
  1405. // then reset the last Win32 error.
  1406. //
  1407. DWORD dwError = GetLastError();
  1408. SetLastError(RtlNtStatusToDosError(STATUS_UNSUCCESSFUL));
  1409. SetLastError(dwError);
  1410. return NtCurrentTeb()->LastStatusValue;
  1411. }
  1412. RtlInitUnicodeString( &TransName, TranslatedName );
  1413. }
  1414. if ( RtlEqualUnicodeString( &LogonSession->AuthorityName,
  1415. &TransName,
  1416. TRUE ) )
  1417. {
  1418. //
  1419. // Local Logons don't get mapped names.
  1420. //
  1421. return STATUS_NONE_MAPPED ;
  1422. }
  1423. //
  1424. // Make sure AuthorityName and SamMapName are NULL-terminated.
  1425. // Create dynamically allocated copies if necessary.
  1426. //
  1427. if (AuthorityName == NULL &&
  1428. (LogonSession->AuthorityName.MaximumLength <= LogonSession->AuthorityName.Length ||
  1429. LogonSession->AuthorityName.Buffer[LogonSession->AuthorityName.Length / sizeof(WCHAR)] != L'\0'))
  1430. {
  1431. SafeAllocaAllocate(AuthorityName,
  1432. LogonSession->AuthorityName.Length + sizeof(WCHAR));
  1433. if (AuthorityName == NULL)
  1434. {
  1435. return STATUS_INSUFFICIENT_RESOURCES;
  1436. }
  1437. RtlCopyMemory(AuthorityName, LogonSession->AuthorityName.Buffer, LogonSession->AuthorityName.Length);
  1438. AuthorityName[LogonSession->AuthorityName.Length / sizeof( WCHAR )] = L'\0';
  1439. }
  1440. else
  1441. {
  1442. AuthorityName = LogonSession->AuthorityName.Buffer;
  1443. }
  1444. if (SamMap->Name.MaximumLength <= SamMap->Name.Length ||
  1445. SamMap->Name.Buffer[SamMap->Name.Length / sizeof(WCHAR)] != L'\0')
  1446. {
  1447. SafeAllocaAllocate(SamMapName,
  1448. SamMap->Name.Length + sizeof(WCHAR));
  1449. if (SamMapName == NULL)
  1450. {
  1451. if (AuthorityName != LogonSession->AuthorityName.Buffer)
  1452. {
  1453. SafeAllocaFree(AuthorityName);
  1454. }
  1455. return STATUS_INSUFFICIENT_RESOURCES;
  1456. }
  1457. RtlCopyMemory(SamMapName, SamMap->Name.Buffer, SamMap->Name.Length);
  1458. SamMapName[SamMap->Name.Length / sizeof( WCHAR )] = L'\0';
  1459. }
  1460. else
  1461. {
  1462. SamMapName = SamMap->Name.Buffer;
  1463. }
  1464. //
  1465. // We are going to be hitting the wire; if this is a special
  1466. // known format, then optimize by calling DsCrackName to return
  1467. // the other popular formats. The cache will be seeded with
  1468. // the results and hence avoid calls in the future. This is
  1469. // done to improve logon performance.
  1470. //
  1471. if ( LsapIsNameFormatUsedForLogon( NameType ) ) {
  1472. Status = LsapGetFormatsForLogon( LogonSession,
  1473. AuthorityName,
  1474. SamMapName,
  1475. NameType,
  1476. Map );
  1477. if ( NT_SUCCESS( Status ) ) {
  1478. // we are done!
  1479. goto Exit;
  1480. } else {
  1481. // Ok -- go the slow way
  1482. Status = STATUS_SUCCESS;
  1483. }
  1484. }
  1485. Retry:
  1486. //
  1487. // Translate the name, in the caller's context if possible
  1488. //
  1489. if ( NeedToImpersonate )
  1490. {
  1491. Status = LsapImpersonateClient();
  1492. if ( !NT_SUCCESS(Status) )
  1493. {
  1494. if (Status != STATUS_BAD_IMPERSONATION_LEVEL)
  1495. {
  1496. goto Exit;
  1497. }
  1498. //
  1499. // Failed to impersonate as the client supplied an identify-level
  1500. // token. Make sure the following code knows not to revert or
  1501. // to retry using machine creds as it's redundant.
  1502. //
  1503. Status = LsapImpersonateNetworkService();
  1504. if ( !NT_SUCCESS(Status) )
  1505. {
  1506. goto Exit;
  1507. }
  1508. }
  1509. }
  1510. //
  1511. // No need to "clear" Status to STATUS_SUCCESS here as it's
  1512. // always set below before returning on all codepaths.
  1513. //
  1514. TranslatedNameLength = MAX_PATH ;
  1515. TranslatedName = TranslatedNameBuffer ;
  1516. TranslateStatus = SecpTranslateName(
  1517. AuthorityName,
  1518. SamMapName,
  1519. NameSamCompatible,
  1520. (EXTENDED_NAME_FORMAT) NameType,
  1521. TranslatedName,
  1522. &TranslatedNameLength );
  1523. if ( !TranslateStatus )
  1524. {
  1525. Status = NtCurrentTeb()->LastStatusValue ;
  1526. if ( Status == STATUS_BUFFER_TOO_SMALL )
  1527. {
  1528. TranslatedName = (PWSTR) LsapAllocatePrivateHeap( TranslatedNameLength * sizeof( WCHAR ) );
  1529. if ( TranslatedName )
  1530. {
  1531. TranslateStatus = SecpTranslateName(
  1532. AuthorityName,
  1533. SamMapName,
  1534. NameSamCompatible,
  1535. (EXTENDED_NAME_FORMAT) NameType,
  1536. TranslatedName,
  1537. &TranslatedNameLength );
  1538. }
  1539. } else if ( NeedToImpersonate &&
  1540. NtCurrentTeb()->LastErrorValue == ERROR_ACCESS_DENIED ) {
  1541. //
  1542. // Fall back to machine creds and try again
  1543. //
  1544. RevertToSelf();
  1545. NeedToImpersonate = FALSE;
  1546. goto Retry;
  1547. }
  1548. }
  1549. if ( NeedToImpersonate ) {
  1550. RevertToSelf();
  1551. }
  1552. if ( TranslateStatus )
  1553. {
  1554. // LOCKLOCK: think about read, then convert to write, re-check.
  1555. WriteLockLogonSessionList(ListIndex);
  1556. if ( LogonSession->DsNames[ NameType ] )
  1557. {
  1558. //
  1559. // Someone else filled it in while we were out cracking
  1560. // it as well. Use theirs, discard ours:
  1561. //
  1562. NameMap = LogonSession->DsNames[ NameType ];
  1563. InterlockedIncrement( &NameMap->RefCount );
  1564. UnlockLogonSessionList(ListIndex);
  1565. *Map = NameMap ;
  1566. if ( TranslatedName != TranslatedNameBuffer )
  1567. {
  1568. LsapFreePrivateHeap( TranslatedName );
  1569. }
  1570. Status = STATUS_SUCCESS;
  1571. goto Exit;
  1572. }
  1573. //
  1574. // SecpTranslateName returns length including the terminating NULL,
  1575. // so correct for that here
  1576. //
  1577. TransName.Buffer = TranslatedName ;
  1578. TransName.Length = (USHORT) (( TranslatedNameLength - 1 ) * sizeof(WCHAR));
  1579. TransName.MaximumLength = TransName.Length + sizeof( WCHAR );
  1580. NameMap = LsapCreateDsNameMap(
  1581. &TransName,
  1582. NameType );
  1583. if ( NameMap )
  1584. {
  1585. LogonSession->DsNames[ NameType ] = NameMap ;
  1586. InterlockedIncrement( &NameMap->RefCount );
  1587. UnlockLogonSessionList(ListIndex);
  1588. *Map = NameMap ;
  1589. if ( TranslatedName != TranslatedNameBuffer )
  1590. {
  1591. LsapFreePrivateHeap( TranslatedName );
  1592. }
  1593. Status = STATUS_SUCCESS;
  1594. goto Exit;
  1595. }
  1596. else
  1597. {
  1598. UnlockLogonSessionList(ListIndex);
  1599. Status = STATUS_NO_MEMORY ;
  1600. }
  1601. }
  1602. else
  1603. {
  1604. Status = NtCurrentTeb()->LastStatusValue ;
  1605. }
  1606. //
  1607. // If the DS couldn't map the UPN (e.g., the account has a default UPN), we can
  1608. // still potentially cruft up a UPN using <SAM account name>@<DNS domain name>
  1609. //
  1610. if (Status == STATUS_NONE_MAPPED && NameType == NameUserPrincipal)
  1611. {
  1612. ReadLockLogonSessionList(ListIndex);
  1613. PLSAP_DS_NAME_MAP UsernameMap = LogonSession->DsNames[NameSamCompatible];
  1614. PLSAP_DS_NAME_MAP DnsNameMap = LogonSession->DsNames[NameDnsDomain];
  1615. if (UsernameMap != NULL && DnsNameMap != NULL)
  1616. {
  1617. //
  1618. // Modifying the refcount in maps that point into
  1619. // active logon sessions -- need the write lock.
  1620. //
  1621. ReadToWriteLockLogonSessionList(ListIndex);
  1622. InterlockedIncrement( &UsernameMap->RefCount );
  1623. InterlockedIncrement( &DnsNameMap->RefCount );
  1624. LPWSTR Upn;
  1625. LPWSTR Scan = wcschr(UsernameMap->Name.Buffer, L'\\');
  1626. ULONG Index;
  1627. if (Scan != NULL)
  1628. {
  1629. Scan++;
  1630. }
  1631. else
  1632. {
  1633. Scan = UsernameMap->Name.Buffer;
  1634. }
  1635. //
  1636. // SAM name is always NULL-terminated
  1637. //
  1638. Index = wcslen(Scan);
  1639. SafeAllocaAllocate(Upn, Index * sizeof(WCHAR) + DnsNameMap->Name.Length + 2 * sizeof(WCHAR));
  1640. if (Upn != NULL)
  1641. {
  1642. UNICODE_STRING String;
  1643. wcsncpy(Upn, Scan, Index);
  1644. Upn[Index++] = L'@';
  1645. RtlCopyMemory(Upn + Index, DnsNameMap->Name.Buffer, DnsNameMap->Name.Length);
  1646. Upn[Index + DnsNameMap->Name.Length / sizeof(WCHAR)] = L'\0';
  1647. LsapDerefDsNameMap(UsernameMap);
  1648. LsapDerefDsNameMap(DnsNameMap);
  1649. RtlInitUnicodeString(&String, Upn);
  1650. *Map = LsapCreateDsNameMap(&String, NameType);
  1651. Status = (*Map == NULL ? STATUS_NO_MEMORY : STATUS_SUCCESS);
  1652. SafeAllocaFree(Upn);
  1653. }
  1654. else
  1655. {
  1656. LsapDerefDsNameMap(UsernameMap);
  1657. LsapDerefDsNameMap(DnsNameMap);
  1658. Status = STATUS_NO_MEMORY;
  1659. }
  1660. }
  1661. UnlockLogonSessionList(ListIndex);
  1662. }
  1663. if ( TranslatedName != TranslatedNameBuffer )
  1664. {
  1665. LsapFreePrivateHeap( TranslatedName );
  1666. }
  1667. Exit:
  1668. if (NeedDnsDomainName && NT_SUCCESS(Status))
  1669. {
  1670. //
  1671. // We successfully retrieved the canonical name but what we really
  1672. // want is the DnsDomainName -- extract it and add it to the session.
  1673. //
  1674. // LOCKLOCK: think about read, then convert to write, re-check.
  1675. WriteLockLogonSessionList(ListIndex);
  1676. //
  1677. // Another thread may have cracked the name before we got here.
  1678. //
  1679. NameMap = LogonSession->DsNames[ NameDnsDomain ];
  1680. if ( NameMap )
  1681. {
  1682. if ( ( NameMap->ExpirationTime.QuadPart >= Now.QuadPart ) &&
  1683. ( !Flush ) )
  1684. {
  1685. //
  1686. // Valid entry, bump the ref count and return it
  1687. //
  1688. InterlockedIncrement( &NameMap->RefCount );
  1689. *Map = NameMap ;
  1690. NeedDnsDomainName = FALSE ;
  1691. Status = STATUS_SUCCESS;
  1692. }
  1693. else
  1694. {
  1695. //
  1696. // Entry has expired. Remove it, crack the name anew
  1697. //
  1698. LsapDerefDsNameMap( NameMap );
  1699. LogonSession->DsNames[ NameDnsDomain ] = NULL ;
  1700. }
  1701. }
  1702. if (NeedDnsDomainName)
  1703. {
  1704. Status = LsapCreateDnsNameFromCanonicalName(LogonSession, NameType, Map);
  1705. //
  1706. // Since we just successfully created the canonical name map, its refcount
  1707. // has been bumped up. Undo that since we're really after the DnsDomainName
  1708. // (whose refcount was bumped up in LsapCreateDnsNameFromCanonicalName).
  1709. //
  1710. // LOCKLOCK: if exlusive lock held, don't use interlocked.
  1711. //LogonSession->DsNames[NameType]->RefCount--;
  1712. InterlockedDecrement( &LogonSession->DsNames[NameType]->RefCount );
  1713. }
  1714. UnlockLogonSessionList(ListIndex);
  1715. NameType = NameDnsDomain;
  1716. }
  1717. if (AuthorityName != LogonSession->AuthorityName.Buffer)
  1718. {
  1719. SafeAllocaFree(AuthorityName);
  1720. }
  1721. if (SamMapName != SamMap->Name.Buffer)
  1722. {
  1723. SafeAllocaFree(SamMapName);
  1724. }
  1725. return Status ;
  1726. }
  1727. NTSTATUS
  1728. WLsaEnumerateLogonSession(
  1729. PULONG Count,
  1730. PLUID * Sessions
  1731. )
  1732. {
  1733. PLUID Logons ;
  1734. PVOID LocalCopy = NULL ;
  1735. PLIST_ENTRY Scan ;
  1736. PLSAP_LOGON_SESSION LogonSession ;
  1737. PVOID ClientMemory ;
  1738. ULONG ListIndex;
  1739. NTSTATUS Status ;
  1740. ULONG TotalLogonSessionCount = 0;
  1741. BOOLEAN LogonSessionsLocked = TRUE;
  1742. //
  1743. // lock all the lists for read access, and get a total count.
  1744. //
  1745. for( ListIndex = 0 ; ListIndex < LogonSessionListCount ; ListIndex++ )
  1746. {
  1747. ReadLockLogonSessionList(ListIndex);
  1748. TotalLogonSessionCount += LogonSessionCount[ ListIndex ];
  1749. }
  1750. SafeAllocaAllocate(Logons, TotalLogonSessionCount * sizeof(LUID));
  1751. if ( !Logons )
  1752. {
  1753. Status = STATUS_NO_MEMORY ;
  1754. goto Cleanup;
  1755. }
  1756. *Count = TotalLogonSessionCount ;
  1757. LocalCopy = Logons ;
  1758. for (ListIndex = 0 ; ListIndex < LogonSessionListCount ; ListIndex++ )
  1759. {
  1760. Scan = LogonSessionList[ListIndex].Flink ;
  1761. while ( Scan != &LogonSessionList[ListIndex] )
  1762. {
  1763. LogonSession = CONTAINING_RECORD( Scan, LSAP_LOGON_SESSION, List );
  1764. *Logons++ = LogonSession->LogonId ;
  1765. Scan = Scan->Flink ;
  1766. }
  1767. UnlockLogonSessionList( ListIndex );
  1768. }
  1769. LogonSessionsLocked = FALSE;
  1770. ClientMemory = LsapClientAllocate( *Count * sizeof( LUID ) );
  1771. if ( ClientMemory )
  1772. {
  1773. Status = LsapCopyToClient( LocalCopy,
  1774. ClientMemory,
  1775. *Count * sizeof( LUID ) );
  1776. *Sessions = (PLUID) ClientMemory ;
  1777. }
  1778. else
  1779. {
  1780. Status = STATUS_NO_MEMORY ;
  1781. }
  1782. Cleanup:
  1783. if( LogonSessionsLocked )
  1784. {
  1785. for (ListIndex = 0 ; ListIndex < LogonSessionListCount ; ListIndex++ )
  1786. {
  1787. UnlockLogonSessionList( ListIndex );
  1788. }
  1789. }
  1790. SafeAllocaFree(LocalCopy);
  1791. return Status ;
  1792. }
  1793. NTSTATUS
  1794. LsaIGetNbAndDnsDomainNames(
  1795. IN PUNICODE_STRING DomainName,
  1796. OUT PUNICODE_STRING DnsDomainName,
  1797. OUT PUNICODE_STRING NetbiosDomainName
  1798. )
  1799. /*++
  1800. Routine Description:
  1801. Get both the Netbios name and DNS name of a domain. DomainName must correspond to
  1802. the account domain of some user that is currently logged onto the system.
  1803. Arguments:
  1804. DomainName - Name of the Netbios or DNS domain to query.
  1805. DnsDomainName - Returns the DnsDomainName of the domain if DomainName is trusted.
  1806. DnsDomainName->Buffer will be zero terminated.
  1807. DnsDomainName->Buffer must be freed using LsaIFreeHeap.
  1808. NetbiosDomainName - Returns the Netbios domain name of the domain if DomainName is trusted.
  1809. NetbiosDomainName->Buffer will be zero terminated.
  1810. NetbiosDomainName->Buffer must be freed using LsaIFreeHeap.
  1811. Return Value:
  1812. STATUS_SUCCESS: The routine functioned properly.
  1813. DnsDomainName->Buffer and NetbiosDomainName->Buffer will return null if
  1814. the mapping isn't known.
  1815. --*/
  1816. {
  1817. PLUID Logons ;
  1818. PVOID LocalCopy ;
  1819. PLIST_ENTRY Scan ;
  1820. PLSAP_LOGON_SESSION LogonSession ;
  1821. PVOID ClientMemory ;
  1822. NTSTATUS Status = STATUS_SUCCESS;
  1823. PUNICODE_STRING LocalDnsDomainName;
  1824. ULONG ListIndex;
  1825. BOOLEAN EntryFound = FALSE;
  1826. //
  1827. // Initialization
  1828. //
  1829. RtlInitUnicodeString( DnsDomainName, NULL );
  1830. RtlInitUnicodeString( NetbiosDomainName, NULL );
  1831. //
  1832. // Loop through the logon session list trying to find a match
  1833. //
  1834. for( ListIndex = 0 ; ListIndex < LogonSessionListCount ; ListIndex++ )
  1835. {
  1836. ReadLockLogonSessionList(ListIndex);
  1837. for ( Scan = LogonSessionList[ListIndex].Flink; Scan != &LogonSessionList[ListIndex]; Scan = Scan->Flink ) {
  1838. LogonSession = CONTAINING_RECORD( Scan, LSAP_LOGON_SESSION, List );
  1839. //
  1840. // Ignore this entry unless both names are known
  1841. //
  1842. if (LogonSession->DsNames[NameDnsDomain] == NULL)
  1843. {
  1844. continue;
  1845. }
  1846. LocalDnsDomainName = &LogonSession->DsNames[NameDnsDomain]->Name;
  1847. if ( LocalDnsDomainName->Length == 0 ||
  1848. LogonSession->AuthorityName.Length == 0 )
  1849. {
  1850. continue;
  1851. }
  1852. //
  1853. // Compare the passed in name with the Netbios and DNS name on the entry
  1854. //
  1855. if ( (DomainName->Length == LogonSession->AuthorityName.Length &&
  1856. RtlEqualUnicodeString( DomainName,
  1857. &LogonSession->AuthorityName,
  1858. TRUE ) ) ||
  1859. (DomainName->Length == LocalDnsDomainName->Length &&
  1860. RtlEqualUnicodeString( DomainName,
  1861. LocalDnsDomainName,
  1862. TRUE ) ) ) {
  1863. //
  1864. // Grab the Dns domain name
  1865. //
  1866. DnsDomainName->Buffer = (LPWSTR) LsapAllocatePrivateHeapNoZero(
  1867. LocalDnsDomainName->Length +
  1868. sizeof(WCHAR) );
  1869. if ( DnsDomainName->Buffer == NULL ) {
  1870. Status = STATUS_INSUFFICIENT_RESOURCES;
  1871. break;
  1872. }
  1873. RtlCopyMemory( DnsDomainName->Buffer,
  1874. LocalDnsDomainName->Buffer,
  1875. LocalDnsDomainName->Length );
  1876. DnsDomainName->Buffer[LocalDnsDomainName->Length/sizeof(WCHAR)] = L'\0';
  1877. DnsDomainName->Length = LocalDnsDomainName->Length;
  1878. DnsDomainName->MaximumLength = LocalDnsDomainName->Length + sizeof(WCHAR);
  1879. //
  1880. // Grab the netbios domain name
  1881. //
  1882. NetbiosDomainName->Buffer = (LPWSTR) LsapAllocatePrivateHeapNoZero(
  1883. LogonSession->AuthorityName.Length +
  1884. sizeof(WCHAR) );
  1885. if ( NetbiosDomainName->Buffer == NULL ) {
  1886. LsapFreePrivateHeap( DnsDomainName->Buffer );
  1887. DnsDomainName->Buffer = NULL;
  1888. Status = STATUS_INSUFFICIENT_RESOURCES;
  1889. break;
  1890. }
  1891. RtlCopyMemory( NetbiosDomainName->Buffer,
  1892. LogonSession->AuthorityName.Buffer,
  1893. LogonSession->AuthorityName.Length );
  1894. NetbiosDomainName->Buffer[LogonSession->AuthorityName.Length/sizeof(WCHAR)] = L'\0';
  1895. NetbiosDomainName->Length = LogonSession->AuthorityName.Length;
  1896. NetbiosDomainName->MaximumLength = LogonSession->AuthorityName.Length + sizeof(WCHAR);
  1897. Status = STATUS_SUCCESS;
  1898. EntryFound = TRUE;
  1899. break;
  1900. }
  1901. }
  1902. UnlockLogonSessionList(ListIndex);
  1903. if( !NT_SUCCESS(Status) || EntryFound )
  1904. {
  1905. break;
  1906. }
  1907. }
  1908. return Status;
  1909. }
  1910. NTSTATUS
  1911. WLsaGetLogonSessionData(
  1912. PLUID LogonId,
  1913. PVOID * LogonData
  1914. )
  1915. {
  1916. PLSAP_LOGON_SESSION LogonSession;
  1917. ULONG Size ;
  1918. PVOID ClientBuffer ;
  1919. PUCHAR Offset ;
  1920. PUCHAR LocalOffset ;
  1921. NTSTATUS Status ;
  1922. PSECURITY_LOGON_SESSION_DATA Data = NULL;
  1923. PLSAP_SECURITY_PACKAGE Package ;
  1924. HANDLE Token ;
  1925. BOOL OkayToQuery = FALSE ;
  1926. PLSAP_DS_NAME_MAP DnsMap = NULL;
  1927. PLSAP_DS_NAME_MAP UpnMap = NULL;
  1928. ULONG ListIndex;
  1929. USHORT cbAccount, cbAuthority, cbLogonServer;
  1930. ULONG cbSid;
  1931. LPWSTR lpLocalAccount = NULL, lpLocalAuthority, lpLocalLogonServer;
  1932. PSID lpLocalSid;
  1933. BOOL LogonSessionListLocked = FALSE;
  1934. LogonSession = LsapLocateLogonSession( LogonId );
  1935. if ( !LogonSession )
  1936. {
  1937. return STATUS_NO_SUCH_LOGON_SESSION ;
  1938. }
  1939. Status = LsapImpersonateClient();
  1940. ListIndex = LogonIdToListIndex(LogonSession->LogonId);
  1941. ReadLockLogonSessionList(ListIndex);
  1942. LogonSessionListLocked = TRUE;
  1943. if ( NT_SUCCESS( Status ) )
  1944. {
  1945. if ( LogonSession->UserSid == NULL ||
  1946. !CheckTokenMembership( NULL,
  1947. LogonSession->UserSid,
  1948. &OkayToQuery ) )
  1949. {
  1950. OkayToQuery = FALSE ;
  1951. }
  1952. if ( !OkayToQuery )
  1953. {
  1954. if ( !CheckTokenMembership( NULL,
  1955. LsapAliasAdminsSid,
  1956. &OkayToQuery ) )
  1957. {
  1958. OkayToQuery = FALSE ;
  1959. }
  1960. }
  1961. RevertToSelf();
  1962. }
  1963. if ( !OkayToQuery )
  1964. {
  1965. Status = STATUS_ACCESS_DENIED ;
  1966. }
  1967. if ( !NT_SUCCESS( Status ) )
  1968. {
  1969. goto Cleanup;
  1970. }
  1971. Package = SpmpLocatePackage( LogonSession->CreatingPackage );
  1972. if ( !Package )
  1973. {
  1974. Status = STATUS_NO_SUCH_LOGON_SESSION ;
  1975. goto Cleanup;
  1976. }
  1977. //
  1978. // Make local copies of the fields of interest in the
  1979. // logon session so they don't change mid-stream.
  1980. //
  1981. cbAccount = LogonSession->AccountName.Buffer ? LogonSession->AccountName.Length : 0;
  1982. cbAuthority = LogonSession->AuthorityName.Buffer ? LogonSession->AuthorityName.Length : 0;
  1983. cbLogonServer = LogonSession->LogonServer.Buffer ? LogonSession->LogonServer.Length : 0;
  1984. cbSid = LogonSession->UserSid ? RtlLengthSid(LogonSession->UserSid) : 0;
  1985. Size = cbAccount + cbAuthority + cbLogonServer + 3 * sizeof(WCHAR) + cbSid;
  1986. SafeAllocaAllocate(lpLocalAccount, Size);
  1987. if ( !lpLocalAccount )
  1988. {
  1989. Status = STATUS_NO_MEMORY;
  1990. goto Cleanup;
  1991. }
  1992. lpLocalAuthority = lpLocalAccount + cbAccount / sizeof(WCHAR) + 1;
  1993. lpLocalLogonServer = lpLocalAuthority + cbAuthority / sizeof(WCHAR) + 1;
  1994. RtlZeroMemory(lpLocalAccount, Size);
  1995. if ( cbAccount )
  1996. {
  1997. RtlCopyMemory(lpLocalAccount, LogonSession->AccountName.Buffer, cbAccount);
  1998. }
  1999. if ( cbAuthority )
  2000. {
  2001. RtlCopyMemory(lpLocalAuthority, LogonSession->AuthorityName.Buffer, cbAuthority);
  2002. }
  2003. if ( cbLogonServer )
  2004. {
  2005. RtlCopyMemory(lpLocalLogonServer, LogonSession->LogonServer.Buffer, cbLogonServer);
  2006. }
  2007. if (cbSid)
  2008. {
  2009. lpLocalSid = (PSID) (lpLocalLogonServer + cbLogonServer / sizeof(WCHAR) + 1);
  2010. RtlCopyMemory(lpLocalSid, LogonSession->UserSid, cbSid);
  2011. }
  2012. else
  2013. {
  2014. lpLocalSid = NULL;
  2015. }
  2016. UpnMap = LogonSession->DsNames[NameUserPrincipal];
  2017. if (UpnMap != NULL)
  2018. {
  2019. InterlockedIncrement( &UpnMap->RefCount );
  2020. }
  2021. DnsMap = LogonSession->DsNames[NameDnsDomain];
  2022. if (DnsMap != NULL)
  2023. {
  2024. InterlockedIncrement( &DnsMap->RefCount );
  2025. }
  2026. UnlockLogonSessionList(ListIndex);
  2027. LogonSessionListLocked = FALSE;
  2028. Size += sizeof( SECURITY_LOGON_SESSION_DATA ) +
  2029. Package->Name.Length + sizeof( WCHAR ) +
  2030. sizeof(WCHAR) + // DnsMap
  2031. sizeof(WCHAR) ; // UpnMap
  2032. if( DnsMap != NULL )
  2033. {
  2034. Size += DnsMap->Name.Length;
  2035. }
  2036. if( UpnMap != NULL )
  2037. {
  2038. Size += UpnMap->Name.Length;
  2039. }
  2040. SafeAllocaAllocate(Data, Size);
  2041. if ( !Data )
  2042. {
  2043. Status = STATUS_NO_MEMORY ;
  2044. goto Cleanup;
  2045. }
  2046. ClientBuffer = LsapClientAllocate( Size );
  2047. if ( !ClientBuffer )
  2048. {
  2049. Status = STATUS_NO_MEMORY ;
  2050. goto Cleanup;
  2051. }
  2052. Offset = (PUCHAR) ClientBuffer + sizeof( SECURITY_LOGON_SESSION_DATA );
  2053. LocalOffset = (PUCHAR) ( Data + 1 );
  2054. Data->Size = sizeof( SECURITY_LOGON_SESSION_DATA );
  2055. Data->LogonId = LogonSession->LogonId ;
  2056. Data->LogonType = (ULONG) LogonSession->LogonType ;
  2057. Data->Session = LogonSession->Session ;
  2058. Data->LogonTime = LogonSession->LogonTime ;
  2059. //
  2060. // do the UserSid first since it needs to be 4-byte aligned
  2061. //
  2062. if ( lpLocalSid )
  2063. {
  2064. Data->Sid = (PSID) Offset ;
  2065. RtlCopyMemory(LocalOffset,
  2066. lpLocalSid,
  2067. cbSid);
  2068. Offset += cbSid;
  2069. LocalOffset += cbSid;
  2070. }
  2071. else
  2072. {
  2073. Data->Sid = (PSID) NULL ;
  2074. }
  2075. Data->UserName.Length = cbAccount ;
  2076. Data->UserName.MaximumLength = Data->UserName.Length + sizeof( WCHAR );
  2077. Data->UserName.Buffer = (PWSTR) Offset ;
  2078. RtlCopyMemory( LocalOffset,
  2079. lpLocalAccount,
  2080. cbAccount );
  2081. LocalOffset += cbAccount ;
  2082. *LocalOffset++ = '\0';
  2083. *LocalOffset++ = '\0';
  2084. Offset += Data->UserName.MaximumLength ;
  2085. Data->LogonDomain.Length = cbAuthority ;
  2086. Data->LogonDomain.MaximumLength = Data->LogonDomain.Length + sizeof( WCHAR );
  2087. Data->LogonDomain.Buffer = (PWSTR) Offset ;
  2088. RtlCopyMemory( LocalOffset,
  2089. lpLocalAuthority,
  2090. cbAuthority );
  2091. LocalOffset += cbAuthority ;
  2092. *LocalOffset++ = '\0';
  2093. *LocalOffset++ = '\0';
  2094. Offset += Data->LogonDomain.MaximumLength ;
  2095. Data->AuthenticationPackage.Length = Package->Name.Length ;
  2096. Data->AuthenticationPackage.MaximumLength = Data->AuthenticationPackage.Length + sizeof( WCHAR );
  2097. Data->AuthenticationPackage.Buffer = (PWSTR) Offset ;
  2098. RtlCopyMemory( LocalOffset,
  2099. Package->Name.Buffer,
  2100. Package->Name.Length );
  2101. LocalOffset += Package->Name.Length ;
  2102. *LocalOffset++ = '\0';
  2103. *LocalOffset++ = '\0';
  2104. Offset += Data->AuthenticationPackage.MaximumLength ;
  2105. //
  2106. // do the LogonServer
  2107. //
  2108. Data->LogonServer.Length = cbLogonServer ;
  2109. Data->LogonServer.MaximumLength = Data->LogonServer.Length + sizeof( WCHAR );
  2110. Data->LogonServer.Buffer = (PWSTR) Offset ;
  2111. RtlCopyMemory( LocalOffset,
  2112. lpLocalLogonServer,
  2113. cbLogonServer );
  2114. LocalOffset += cbLogonServer ;
  2115. *LocalOffset++ = '\0';
  2116. *LocalOffset++ = '\0';
  2117. Offset += Data->LogonServer.MaximumLength ;
  2118. //
  2119. // do the DnsDomainName
  2120. //
  2121. if (DnsMap != NULL)
  2122. {
  2123. Data->DnsDomainName.Length = DnsMap->Name.Length;
  2124. Data->DnsDomainName.MaximumLength = Data->DnsDomainName.Length + sizeof( WCHAR );
  2125. Data->DnsDomainName.Buffer = (PWSTR) Offset ;
  2126. RtlCopyMemory( LocalOffset,
  2127. DnsMap->Name.Buffer,
  2128. DnsMap->Name.Length );
  2129. LocalOffset += DnsMap->Name.Length ;
  2130. *LocalOffset++ = '\0';
  2131. *LocalOffset++ = '\0';
  2132. Offset += Data->DnsDomainName.MaximumLength ;
  2133. }
  2134. else
  2135. {
  2136. Data->DnsDomainName.Length = Data->DnsDomainName.MaximumLength = 0;
  2137. Data->DnsDomainName.Buffer = (PWSTR) Offset;
  2138. *LocalOffset++ = '\0';
  2139. *LocalOffset++ = '\0';
  2140. }
  2141. //
  2142. // do the Upn
  2143. //
  2144. if (UpnMap != NULL)
  2145. {
  2146. Data->Upn.Length = UpnMap->Name.Length ;
  2147. Data->Upn.MaximumLength = Data->Upn.Length + sizeof( WCHAR );
  2148. Data->Upn.Buffer = (PWSTR) Offset ;
  2149. RtlCopyMemory( LocalOffset,
  2150. UpnMap->Name.Buffer,
  2151. UpnMap->Name.Length );
  2152. LocalOffset += UpnMap->Name.Length ;
  2153. *LocalOffset++ = '\0';
  2154. *LocalOffset++ = '\0';
  2155. Offset += Data->Upn.MaximumLength ;
  2156. }
  2157. else
  2158. {
  2159. Data->Upn.Length = Data->Upn.MaximumLength = 0;
  2160. Data->Upn.Buffer = (PWSTR) Offset;
  2161. *LocalOffset++ = '\0';
  2162. *LocalOffset++ = '\0';
  2163. }
  2164. Status = LsapCopyToClient( Data,
  2165. ClientBuffer,
  2166. Size );
  2167. *LogonData = ClientBuffer ;
  2168. Cleanup:
  2169. if (DnsMap != NULL || UpnMap != NULL)
  2170. {
  2171. if ( !LogonSessionListLocked )
  2172. {
  2173. WriteLockLogonSessionList(ListIndex);
  2174. LogonSessionListLocked = TRUE;
  2175. }
  2176. if (DnsMap != NULL)
  2177. {
  2178. LsapDerefDsNameMap(DnsMap);
  2179. }
  2180. if (UpnMap != NULL)
  2181. {
  2182. LsapDerefDsNameMap(UpnMap);
  2183. }
  2184. }
  2185. if ( LogonSessionListLocked )
  2186. {
  2187. UnlockLogonSessionList(ListIndex);
  2188. }
  2189. LsapReleaseLogonSession( LogonSession );
  2190. SafeAllocaFree(Data);
  2191. SafeAllocaFree(lpLocalAccount);
  2192. return Status ;
  2193. }
  2194. NTSTATUS
  2195. LsapGetFormatsForLogon(
  2196. IN PLSAP_LOGON_SESSION LogonSession,
  2197. IN LPWSTR Domain,
  2198. IN LPWSTR Name,
  2199. IN ULONG DesiredNameType,
  2200. OUT PLSAP_DS_NAME_MAP * Map
  2201. )
  2202. {
  2203. NTSTATUS Status = STATUS_SUCCESS;
  2204. LPWSTR *TranslatedNames = NULL;
  2205. BOOL TranslateStatus;
  2206. PLSAP_DS_NAME_MAP NameMap;
  2207. UNICODE_STRING TransName;
  2208. ULONG i;
  2209. BOOLEAN NeedToImpersonate = TRUE;
  2210. ULONG ListIndex = LogonIdToListIndex(LogonSession->LogonId);
  2211. Retry:
  2212. if ( NeedToImpersonate )
  2213. {
  2214. Status = LsapImpersonateClient();
  2215. if ( !NT_SUCCESS(Status) )
  2216. {
  2217. if ( Status != STATUS_BAD_IMPERSONATION_LEVEL )
  2218. {
  2219. goto Exit;
  2220. }
  2221. //
  2222. // Failed to impersonate as the client supplied an identify-level
  2223. // token. Make sure the following code knows not to revert or
  2224. // to retry using machine creds as it's redundant.
  2225. //
  2226. Status = LsapImpersonateNetworkService();
  2227. if ( !NT_SUCCESS(Status) )
  2228. {
  2229. goto Exit;
  2230. }
  2231. }
  2232. }
  2233. //
  2234. // If the client thread is using an identify or anonymous level token,
  2235. // do the translation in system context.
  2236. //
  2237. TranslateStatus = SecpTranslateNameEx( Domain,
  2238. Name,
  2239. NameSamCompatible,
  2240. (EXTENDED_NAME_FORMAT*) LogonFormats,
  2241. sizeof(LogonFormats)/sizeof(LogonFormats[0]),
  2242. &TranslatedNames );
  2243. //
  2244. // If we successfully impersonated above, revert now.
  2245. //
  2246. if ( NeedToImpersonate )
  2247. {
  2248. RevertToSelf();
  2249. }
  2250. Status = STATUS_SUCCESS;
  2251. if ( !TranslateStatus ) {
  2252. if ( NeedToImpersonate &&
  2253. NtCurrentTeb()->LastErrorValue == ERROR_ACCESS_DENIED ) {
  2254. //
  2255. // Fall back to machine creds and try again
  2256. //
  2257. NeedToImpersonate = FALSE;
  2258. goto Retry;
  2259. }
  2260. Status = STATUS_UNSUCCESSFUL;
  2261. } else {
  2262. ULONG i;
  2263. // LOCKLOCK: look at read, convertwrite, recheck
  2264. WriteLockLogonSessionList(ListIndex);
  2265. for (i = 0; i < sizeof(LogonFormats)/sizeof(LogonFormats[0]); i++ ) {
  2266. ULONG NameFormat = LogonFormats[i];
  2267. if ( LogonSession->DsNames[ NameFormat ] ) {
  2268. //
  2269. // Someone else filled it in while we were out cracking
  2270. // it as well. Use theirs, discard ours:
  2271. //
  2272. NameMap = LogonSession->DsNames[ NameFormat ];
  2273. } else {
  2274. //
  2275. // Still no entry -- create one
  2276. //
  2277. TransName.Buffer = TranslatedNames[i] ;
  2278. TransName.Length = (USHORT) (wcslen(TranslatedNames[i]) * sizeof(WCHAR));
  2279. TransName.MaximumLength = TransName.Length + sizeof( WCHAR );
  2280. NameMap = LsapCreateDsNameMap(
  2281. &TransName,
  2282. NameFormat );
  2283. if ( NameMap )
  2284. {
  2285. LogonSession->DsNames[ NameFormat ] = NameMap ;
  2286. }
  2287. else
  2288. {
  2289. UnlockLogonSessionList(ListIndex);
  2290. Status = STATUS_NO_MEMORY ;
  2291. goto Exit;
  2292. }
  2293. }
  2294. if ( NameFormat == DesiredNameType ) {
  2295. InterlockedIncrement( &NameMap->RefCount );
  2296. *Map = NameMap ;
  2297. }
  2298. }
  2299. //
  2300. // Should have found a match
  2301. //
  2302. ASSERT( *Map );
  2303. UnlockLogonSessionList(ListIndex);
  2304. }
  2305. Exit:
  2306. if ( TranslatedNames ) {
  2307. for ( i = 0; i < sizeof(LogonFormats)/sizeof(LogonFormats[0]); i++ ) {
  2308. if ( TranslatedNames[i] ) {
  2309. SecpFreeMemory( TranslatedNames[i] );
  2310. }
  2311. }
  2312. SecpFreeMemory( TranslatedNames );
  2313. }
  2314. return Status;
  2315. }
  2316. NTSTATUS
  2317. LsapSetSessionToken(
  2318. IN HANDLE InputTokenHandle,
  2319. IN PLUID LogonId
  2320. )
  2321. /*++
  2322. Routine Description:
  2323. This routine duplicates the InputTokenHandle and sets that duplicated handle on the
  2324. LogonSession identified by the LogonId.
  2325. The duplicated handle is available for subsequent callers of LsapOpenTokenByLogonId.
  2326. Arguments:
  2327. InputTokenHandle - A handle to a token for the logon session
  2328. LogonId - The logon id of the session
  2329. Return Values:
  2330. Status of the operation.
  2331. --*/
  2332. {
  2333. NTSTATUS Status;
  2334. OBJECT_ATTRIBUTES ObjAttrs;
  2335. SECURITY_QUALITY_OF_SERVICE SecurityQofS;
  2336. HANDLE TokenHandle = NULL;
  2337. ULONG TokenIsReferenced;
  2338. ULONG StatsSize ;
  2339. TOKEN_STATISTICS TokenStats ;
  2340. PLSAP_LOGON_SESSION LogonSession = NULL;
  2341. //
  2342. // Get the credential set from the logon session.
  2343. //
  2344. LogonSession = LsapLocateLogonSession( LogonId );
  2345. if ( LogonSession == NULL ) {
  2346. ASSERT( LogonSession != NULL );
  2347. // This isn't fatal.
  2348. Status = STATUS_SUCCESS;
  2349. goto Cleanup;
  2350. }
  2351. //
  2352. // Ensure there isn't already a token for this session.
  2353. //
  2354. if ( LogonSession->TokenHandle != NULL ) {
  2355. // This can happen for "local service" and "network service"
  2356. // This isn't fatal.
  2357. Status = STATUS_SUCCESS;
  2358. goto Cleanup;
  2359. }
  2360. //
  2361. // Duplicate the token
  2362. //
  2363. Status = NtQueryInformationToken(
  2364. InputTokenHandle,
  2365. TokenStatistics,
  2366. &TokenStats,
  2367. sizeof( TokenStats ),
  2368. &StatsSize );
  2369. if ( !NT_SUCCESS( Status ) ) {
  2370. // This isn't fatal.
  2371. Status = STATUS_SUCCESS;
  2372. goto Cleanup;
  2373. }
  2374. //
  2375. // if primary token handed in (eg: system process), over-ride to SecurityImpersonation from SecurityAnonymous
  2376. //
  2377. if(TokenStats.TokenType == TokenPrimary)
  2378. {
  2379. TokenStats.ImpersonationLevel = SecurityImpersonation;
  2380. }
  2381. InitializeObjectAttributes( &ObjAttrs, NULL, 0L, NULL, NULL );
  2382. SecurityQofS.Length = sizeof( SECURITY_QUALITY_OF_SERVICE );
  2383. SecurityQofS.ImpersonationLevel = min( SecurityImpersonation, TokenStats.ImpersonationLevel );
  2384. SecurityQofS.ContextTrackingMode = FALSE; // Snapshot client context
  2385. SecurityQofS.EffectiveOnly = FALSE;
  2386. ObjAttrs.SecurityQualityOfService = &SecurityQofS;
  2387. Status = NtDuplicateToken( InputTokenHandle,
  2388. TOKEN_ALL_ACCESS,
  2389. &ObjAttrs,
  2390. FALSE,
  2391. TokenImpersonation,
  2392. &TokenHandle );
  2393. if ( !NT_SUCCESS(Status) ) {
  2394. goto Cleanup;
  2395. }
  2396. //
  2397. // Make this token not reference the logon session.
  2398. // (Otherwise, the existence of this token reference would prevent the reference monitor
  2399. // from detecting the last reference to the logon session.)
  2400. //
  2401. TokenIsReferenced = FALSE;
  2402. Status = NtSetInformationToken( TokenHandle,
  2403. TokenSessionReference,
  2404. &TokenIsReferenced,
  2405. sizeof(TokenIsReferenced) );
  2406. if ( !NT_SUCCESS(Status) ) {
  2407. goto Cleanup;
  2408. }
  2409. //
  2410. // once the token is added to the logonsession, it is read-only.
  2411. //
  2412. if( InterlockedCompareExchangePointer(
  2413. &LogonSession->TokenHandle,
  2414. TokenHandle,
  2415. NULL
  2416. ) == NULL)
  2417. {
  2418. //
  2419. // if the value was NULL initially, then we updated it with the new token
  2420. // set the new token NULL so we don't free it.
  2421. //
  2422. TokenHandle = NULL;
  2423. }
  2424. Status = STATUS_SUCCESS;
  2425. Cleanup:
  2426. if ( TokenHandle != NULL ) {
  2427. NtClose( TokenHandle );
  2428. }
  2429. if ( LogonSession != NULL ) {
  2430. LsapReleaseLogonSession( LogonSession );
  2431. }
  2432. return Status;
  2433. }
  2434. NTSTATUS
  2435. LsapOpenTokenByLogonId(
  2436. IN PLUID LogonId,
  2437. OUT HANDLE *RetTokenHandle
  2438. )
  2439. /*++
  2440. Routine Description:
  2441. This routine opens a token by LogonId. It is only valid for LogonIds where all of the
  2442. following are true:
  2443. * A logon session has been created via LsapCreateLogonSession, AND
  2444. * A token has been created via LsapCreateToken or by the LSA after an authentication package
  2445. returns successfully from LsaApLogonUser(Ex)(2).
  2446. Arguments:
  2447. LogonId - The logon id of the session
  2448. RetTokenHandle - Returns a handle to the token. The token is an impersonation token,
  2449. is granted TOKEN_ALL_ACCESS, and should be closed via NtClose.
  2450. Return Values:
  2451. Status of the operation.
  2452. STATUS_NO_SUCH_LOGON_SESSION - The logon session does not exist.
  2453. STATUS_NO_TOKEN - There is no token for this logon session.
  2454. --*/
  2455. {
  2456. NTSTATUS Status;
  2457. OBJECT_ATTRIBUTES ObjAttrs;
  2458. SECURITY_QUALITY_OF_SERVICE SecurityQofS;
  2459. HANDLE TokenHandle = NULL;
  2460. PLSAP_LOGON_SESSION LogonSession = NULL;
  2461. PSession pSession = GetCurrentSession();
  2462. //
  2463. // Get the credential set from the logon session.
  2464. //
  2465. LogonSession = LsapLocateLogonSession( LogonId );
  2466. if ( LogonSession == NULL ) {
  2467. //
  2468. // If this is the anonymous logon id,
  2469. // create a token.
  2470. //
  2471. if ( RtlEqualLuid( LogonId,
  2472. &LsapAnonymousLogonId ) ) {
  2473. LSA_TOKEN_INFORMATION_NULL VNull;
  2474. TOKEN_SOURCE NullTokenSource = {"*LAnon*", 0};
  2475. HANDLE ImpersonatedToken = NULL;
  2476. VNull.Groups = NULL;
  2477. VNull.ExpirationTime.HighPart = 0x7FFFFFFF;
  2478. VNull.ExpirationTime.LowPart = 0xFFFFFFFF;
  2479. //
  2480. // insure we aren't impersonating a client when we try to create the token
  2481. // this is relevant for inproc security package consumers.
  2482. // BLACKCOMB: Duplicate a cached anonymous token instead.
  2483. //
  2484. Status = NtOpenThreadToken(
  2485. NtCurrentThread(),
  2486. TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_QUERY_SOURCE,
  2487. TRUE,
  2488. &ImpersonatedToken
  2489. );
  2490. if (!NT_SUCCESS(Status))
  2491. {
  2492. if (Status != STATUS_NO_TOKEN)
  2493. {
  2494. goto Cleanup;
  2495. }
  2496. ImpersonatedToken = NULL ;
  2497. }
  2498. Status = LsapCreateNullToken( LogonId,
  2499. &NullTokenSource,
  2500. &VNull,
  2501. RetTokenHandle );
  2502. if ( ImpersonatedToken )
  2503. {
  2504. NtSetInformationThread(
  2505. NtCurrentThread(),
  2506. ThreadImpersonationToken,
  2507. &ImpersonatedToken,
  2508. sizeof(HANDLE)
  2509. );
  2510. NtClose(ImpersonatedToken);
  2511. }
  2512. goto Cleanup;
  2513. }
  2514. Status = STATUS_NO_SUCH_LOGON_SESSION;
  2515. goto Cleanup;
  2516. }
  2517. //
  2518. // Ensure there is a token for this session.
  2519. //
  2520. if ( LogonSession->TokenHandle == NULL ) {
  2521. Status = STATUS_NO_TOKEN;
  2522. goto Cleanup;
  2523. }
  2524. //
  2525. // Duplicate the token
  2526. // NOTE: logon session is not locked because the token is a read-only field once set.
  2527. //
  2528. InitializeObjectAttributes( &ObjAttrs, NULL, 0L, NULL, NULL );
  2529. SecurityQofS.Length = sizeof( SECURITY_QUALITY_OF_SERVICE );
  2530. SecurityQofS.ImpersonationLevel = SecurityImpersonation;
  2531. SecurityQofS.ContextTrackingMode = FALSE; // Snapshot client context
  2532. SecurityQofS.EffectiveOnly = FALSE;
  2533. ObjAttrs.SecurityQualityOfService = &SecurityQofS;
  2534. Status = NtDuplicateToken( LogonSession->TokenHandle,
  2535. TOKEN_ALL_ACCESS,
  2536. &ObjAttrs,
  2537. FALSE,
  2538. TokenImpersonation,
  2539. &TokenHandle );
  2540. if ( !NT_SUCCESS(Status) ) {
  2541. goto Cleanup;
  2542. }
  2543. if( pSession )
  2544. {
  2545. //
  2546. // for terminal server, the session can change after the original logon.
  2547. // insure the caller gets an token with the correct SessionId.
  2548. //
  2549. if( pSession->SessionId != LogonSession->Session )
  2550. {
  2551. HANDLE PriorToken = NULL;
  2552. //
  2553. // if there is an impersonation token present, as can be the case in
  2554. // certain in-proc scenarios, save and restore the token around the privileged
  2555. // operation.
  2556. //
  2557. Status = NtOpenThreadToken(
  2558. NtCurrentThread(),
  2559. TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_READ,
  2560. TRUE,
  2561. &PriorToken );
  2562. if ( NT_SUCCESS( Status ) )
  2563. {
  2564. HANDLE NullToken = NULL;
  2565. //
  2566. // revert to self...
  2567. //
  2568. NtSetInformationThread(
  2569. NtCurrentThread(),
  2570. ThreadImpersonationToken,
  2571. &NullToken,
  2572. sizeof( HANDLE )
  2573. );
  2574. }
  2575. //
  2576. // privileged operation: update the token sessionId.
  2577. //
  2578. Status = NtSetInformationToken(
  2579. TokenHandle,
  2580. TokenSessionId,
  2581. &pSession->SessionId,
  2582. sizeof( ULONG )
  2583. );
  2584. ASSERT( NT_SUCCESS(Status) );
  2585. //
  2586. // put the prior token back.
  2587. //
  2588. if ( PriorToken )
  2589. {
  2590. NtSetInformationThread(
  2591. NtCurrentThread(),
  2592. ThreadImpersonationToken,
  2593. &PriorToken,
  2594. sizeof( HANDLE )
  2595. );
  2596. NtClose( PriorToken );
  2597. }
  2598. if( !NT_SUCCESS(Status) )
  2599. {
  2600. goto Cleanup;
  2601. }
  2602. }
  2603. }
  2604. *RetTokenHandle = TokenHandle;
  2605. TokenHandle = NULL;
  2606. Status = STATUS_SUCCESS;
  2607. Cleanup:
  2608. if ( TokenHandle != NULL ) {
  2609. NtClose( TokenHandle );
  2610. }
  2611. if ( LogonSession != NULL ) {
  2612. LsapReleaseLogonSession( LogonSession );
  2613. }
  2614. return Status;
  2615. }
  2616. NTSTATUS
  2617. LsapDomainRenameHandlerForLogonSessions(
  2618. IN PUNICODE_STRING OldNetbiosName,
  2619. IN PUNICODE_STRING OldDnsName,
  2620. IN PUNICODE_STRING NewNetbiosName,
  2621. IN PUNICODE_STRING NewDnsName
  2622. )
  2623. /*++
  2624. Routine Description:
  2625. Walks the logon sessions list and renames the logon sessions with the given
  2626. new netbios and DNS domain names
  2627. Arguments:
  2628. OldNetbiosName old netbios name of the domain
  2629. OldDnsName old DNS name of the domain
  2630. NewNetbiosName new netbios name of the domain
  2631. NewDnsName new DNS name of the domain
  2632. Returns:
  2633. STATUS_ error code
  2634. --*/
  2635. {
  2636. ULONG ListIndex;
  2637. NTSTATUS Status = STATUS_SUCCESS;
  2638. ASSERT( OldNetbiosName );
  2639. ASSERT( OldDnsName );
  2640. ASSERT( NewNetbiosName );
  2641. ASSERT( NewDnsName );
  2642. for(ListIndex = 0 ; ListIndex < LogonSessionListCount ; ListIndex++ )
  2643. {
  2644. // LOCKLOCK: look at read, convertwrite on match,
  2645. WriteLockLogonSessionList(ListIndex);
  2646. for ( PLIST_ENTRY Scan = LogonSessionList[ListIndex].Flink;
  2647. Scan != &LogonSessionList[ListIndex];
  2648. Scan = Scan->Flink ) {
  2649. UNICODE_STRING NetbiosName = {0};
  2650. UNICODE_STRING DnsName = {0};
  2651. PLSAP_LOGON_SESSION LogonSession = CONTAINING_RECORD( Scan, LSAP_LOGON_SESSION, List );
  2652. PLSAP_DS_NAME_MAP SamMap = LogonSession->DsNames[ NameSamCompatible ];
  2653. PLSAP_DS_NAME_MAP DnsMap = LogonSession->DsNames[ NameDnsDomain ];
  2654. Status = STATUS_SUCCESS;
  2655. if ( NT_SUCCESS( Status ) &&
  2656. RtlEqualUnicodeString(
  2657. OldNetbiosName,
  2658. &LogonSession->AuthorityName,
  2659. TRUE )) {
  2660. Status = LsapDuplicateString( // Use LsapAllocateLsaHeap
  2661. &NetbiosName,
  2662. NewNetbiosName
  2663. );
  2664. }
  2665. if ( NT_SUCCESS( Status ) &&
  2666. DnsMap &&
  2667. RtlEqualUnicodeString(
  2668. OldDnsName,
  2669. &DnsMap->Name,
  2670. TRUE )) {
  2671. Status = LsapDuplicateString2( // Use LsapAllocatePrivateHeap
  2672. &DnsName,
  2673. NewDnsName
  2674. );
  2675. }
  2676. if ( !NT_SUCCESS( Status )) {
  2677. LsapFreeLsaHeap( NetbiosName.Buffer );
  2678. LsapFreePrivateHeap( DnsName.Buffer );
  2679. break;
  2680. }
  2681. if ( NetbiosName.Buffer ) {
  2682. LsapFreeLsaHeap( LogonSession->AuthorityName.Buffer );
  2683. LogonSession->AuthorityName = NetbiosName;
  2684. }
  2685. if ( DnsMap && DnsName.Buffer )
  2686. {
  2687. LsapDerefDsNameMap(DnsMap);
  2688. LogonSession->DsNames[NameDnsDomain] = LsapCreateDsNameMap(&DnsName, NameDnsDomain);
  2689. }
  2690. if ( SamMap &&
  2691. SamMap->Name.Length > OldNetbiosName->Length &&
  2692. 0 == _wcsnicmp(
  2693. SamMap->Name.Buffer,
  2694. OldNetbiosName->Buffer,
  2695. OldNetbiosName->Length / sizeof( WCHAR )) &&
  2696. SamMap->Name.Buffer[ OldNetbiosName->Length / sizeof( WCHAR )] == L'\\' ) {
  2697. LsapDerefDsNameMap( SamMap );
  2698. if ( FALSE == LsapSetSamAccountNameForLogonSession( LogonSession )) {
  2699. Status = STATUS_INSUFFICIENT_RESOURCES;
  2700. break;
  2701. }
  2702. }
  2703. }
  2704. UnlockLogonSessionList(ListIndex);
  2705. }
  2706. return Status;
  2707. }
  2708. NTSTATUS
  2709. LsapCreateDnsNameFromCanonicalName(
  2710. IN PLSAP_LOGON_SESSION LogonSession,
  2711. IN ULONG NameType,
  2712. OUT PLSAP_DS_NAME_MAP * Map
  2713. )
  2714. /*++
  2715. Routine Description:
  2716. Internal routine used to extract the DnsDomainName given the canonical name
  2717. Arguments:
  2718. LogonSession - The logon session in question
  2719. Map - Pointer that receives the allocated/refcounted name map on success
  2720. Return Values:
  2721. Status of the operation.
  2722. Notes:
  2723. The LogonSessionListLock MUST be held for exclusive access when this routine is called
  2724. --*/
  2725. {
  2726. PLSAP_DS_NAME_MAP CanonicalNameMap = LogonSession->DsNames[NameType];
  2727. UNICODE_STRING DnsDomainName;
  2728. LPWSTR lpSlash;
  2729. USHORT i;
  2730. ASSERT(CanonicalNameMap != NULL);
  2731. ASSERT(LogonSession->DsNames[NameDnsDomain] == NULL);
  2732. //
  2733. // Find the first forward slash in the canonical name. No guarantees on
  2734. // NULL-termination in a UNICODE_STRING.
  2735. //
  2736. lpSlash = NULL;
  2737. for (i = 0; i < CanonicalNameMap->Name.Length; i++)
  2738. {
  2739. if (CanonicalNameMap->Name.Buffer[i] == L'/')
  2740. {
  2741. lpSlash = &CanonicalNameMap->Name.Buffer[i];
  2742. break;
  2743. }
  2744. }
  2745. if (lpSlash == NULL)
  2746. {
  2747. //
  2748. // The canonical name is bad -- bail.
  2749. //
  2750. ASSERT(lpSlash != NULL);
  2751. return STATUS_NONE_MAPPED;
  2752. }
  2753. RtlInitUnicodeString(&DnsDomainName, CanonicalNameMap->Name.Buffer);
  2754. DnsDomainName.Length = (USHORT) (lpSlash - CanonicalNameMap->Name.Buffer) * sizeof(WCHAR);
  2755. *Map = LsapCreateDsNameMap(&DnsDomainName, NameDnsDomain);
  2756. if (*Map == NULL)
  2757. {
  2758. return STATUS_NO_MEMORY;
  2759. }
  2760. LogonSession->DsNames[NameDnsDomain] = *Map;
  2761. // LOCKLOCK: check refcount interlocked if not exclusive.
  2762. // (*Map)->RefCount++;
  2763. InterlockedIncrement( &(*Map)->RefCount );
  2764. return STATUS_SUCCESS;
  2765. }
  2766. NTSTATUS
  2767. LsaIAddNameToLogonSession(
  2768. IN PLUID LogonId,
  2769. IN ULONG NameFormat,
  2770. IN PUNICODE_STRING Name
  2771. )
  2772. /*++
  2773. Routine Description:
  2774. Internal routine for the auth packages to call to add names to the cache in the
  2775. logon session
  2776. Arguments:
  2777. LogonId - The logon id of the session
  2778. NameFormat - The EXTENDED_NAME_FORMAT for the name in question (from secext.h)
  2779. Name - The name itself
  2780. Return Values:
  2781. Status of the operation.
  2782. STATUS_NO_SUCH_LOGON_SESSION - The logon session does not exist.
  2783. --*/
  2784. {
  2785. PLSAP_LOGON_SESSION LogonSession;
  2786. PLSAP_DS_NAME_MAP NameMap;
  2787. ULONG ListIndex;
  2788. BOOL fDeleteMap = FALSE;
  2789. //
  2790. // We trust the auth package to be passing in valid parameters
  2791. // session so assert on all invalid parameter errors.
  2792. //
  2793. if (Name == NULL)
  2794. {
  2795. //
  2796. // Package doesn't have this info -- ignore it
  2797. //
  2798. return STATUS_SUCCESS;
  2799. }
  2800. LogonSession = LsapLocateLogonSession(LogonId);
  2801. if (LogonSession == NULL)
  2802. {
  2803. ASSERT(LogonSession != NULL);
  2804. return STATUS_NO_SUCH_LOGON_SESSION;
  2805. }
  2806. ASSERT(NameFormat < LSAP_MAX_DS_NAMES && NameFormat != NameSamCompatible);
  2807. NameMap = LsapCreateDsNameMap(Name, NameFormat);
  2808. if (NameMap == NULL)
  2809. {
  2810. LsapReleaseLogonSession(LogonSession);
  2811. return STATUS_NO_MEMORY;
  2812. }
  2813. //
  2814. // Update the logon session.
  2815. //
  2816. ListIndex = LogonIdToListIndexPtr( LogonId );
  2817. ReadLockLogonSessionList(ListIndex);
  2818. if (LogonSession->DsNames[NameFormat] == NULL)
  2819. {
  2820. //
  2821. // check again, this time with the write lock held.
  2822. //
  2823. ReadToWriteLockLogonSessionList(ListIndex);
  2824. if( LogonSession->DsNames[NameFormat] == NULL )
  2825. {
  2826. LogonSession->DsNames[NameFormat] = NameMap;
  2827. }
  2828. else
  2829. {
  2830. fDeleteMap = TRUE;
  2831. }
  2832. }
  2833. else
  2834. {
  2835. //
  2836. // Another thread beat us to it -- keep the name in the session
  2837. //
  2838. fDeleteMap = TRUE;
  2839. }
  2840. UnlockLogonSessionList(ListIndex);
  2841. if (fDeleteMap)
  2842. {
  2843. //
  2844. // No need to hold a lock here as NameMap doesn't
  2845. // point into an active logon session.
  2846. //
  2847. LsapDerefDsNameMap(NameMap);
  2848. }
  2849. LsapReleaseLogonSession(LogonSession);
  2850. return STATUS_SUCCESS;
  2851. }
  2852. NTSTATUS
  2853. LsaIGetNameFromLuid(
  2854. IN PLUID LogonId,
  2855. IN ULONG NameFormat,
  2856. IN BOOLEAN LocalOnly,
  2857. IN OUT PUNICODE_STRING Name
  2858. )
  2859. /*++
  2860. Routine Description:
  2861. Internal routine for the auth packages to call to get the stored lsa version
  2862. of names by LUID.
  2863. Arguments:
  2864. LogonId - The logon id of the session
  2865. NameFormat - The EXTENDED_NAME_FORMAT for the name in question (from secext.h)
  2866. LocalOnly - Stay on box?
  2867. Name - The name itself, freed by caller useing FreePrivateHeap
  2868. Return Values:
  2869. Status of the operation.
  2870. STATUS_NO_SUCH_LOGON_SESSION - The logon session does not exist.
  2871. --*/
  2872. {
  2873. PLSAP_LOGON_SESSION LogonSession;
  2874. PLSAP_DS_NAME_MAP NameMap;
  2875. BOOL fDeleteMap = FALSE;
  2876. NTSTATUS Status;
  2877. LogonSession = LsapLocateLogonSession(LogonId);
  2878. if (LogonSession == NULL)
  2879. {
  2880. ASSERT(LogonSession != NULL);
  2881. return STATUS_NO_SUCH_LOGON_SESSION;
  2882. }
  2883. ASSERT(NameFormat < LSAP_MAX_DS_NAMES);
  2884. //
  2885. // Note: This function is intended for use in kerberos
  2886. // to build information for a logon session created
  2887. // by another package. As such, we'll only be looking
  2888. // for DNS domain & client name. We should never have to
  2889. // go off box for this info.
  2890. //
  2891. Status = LsapGetNameForLogonSession(
  2892. LogonSession,
  2893. NameFormat,
  2894. &NameMap,
  2895. LocalOnly
  2896. );
  2897. LsapReleaseLogonSession(LogonSession);
  2898. if (!NT_SUCCESS(Status))
  2899. {
  2900. goto cleanup;
  2901. }
  2902. Name->Length = NameMap->Name.Length;
  2903. Name->MaximumLength = NameMap->Name.MaximumLength;
  2904. Name->Buffer = (PWSTR) LsapAllocatePrivateHeap(Name->MaximumLength);
  2905. if (Name->Buffer == NULL)
  2906. {
  2907. Status = STATUS_NO_MEMORY;
  2908. goto cleanup;
  2909. }
  2910. RtlCopyUnicodeString(
  2911. Name,
  2912. &NameMap->Name
  2913. );
  2914. cleanup:
  2915. if (NameMap)
  2916. {
  2917. LsapDerefDsNameMap(NameMap);
  2918. }
  2919. return Status;
  2920. }
  2921. NTSTATUS
  2922. LsaISetLogonGuidInLogonSession(
  2923. IN PLUID LogonId,
  2924. IN LPGUID LogonGuid
  2925. )
  2926. /*++
  2927. Routine Description:
  2928. Internal routine for the auth packages (currently only kerberos)
  2929. to set the logon GUID in the logon session
  2930. Arguments:
  2931. LogonId - The logon id of the session
  2932. LogonGuid - The logon GUID of the session
  2933. Return Values:
  2934. Status of the operation.
  2935. STATUS_NO_SUCH_LOGON_SESSION - The logon session does not exist.
  2936. --*/
  2937. {
  2938. PLSAP_LOGON_SESSION LogonSession = NULL;
  2939. NTSTATUS Status = STATUS_SUCCESS;
  2940. ULONG ListIndex;
  2941. GUID ZeroGuid = { 0 };
  2942. //
  2943. // We trust the auth package to be passing in valid parameters
  2944. // session so assert on all invalid parameter errors.
  2945. //
  2946. LogonSession = LsapLocateLogonSession(LogonId);
  2947. if (LogonSession == NULL)
  2948. {
  2949. Status = STATUS_NO_SUCH_LOGON_SESSION;
  2950. goto Cleanup;
  2951. }
  2952. //
  2953. // Update the logon session.
  2954. //
  2955. // take the appropriate lock depending on the input.
  2956. ListIndex = LogonIdToListIndexPtr(LogonId);
  2957. if ( LogonGuid )
  2958. {
  2959. WriteLockLogonSessionList(ListIndex);
  2960. RtlCopyMemory( &LogonSession->LogonGuid, LogonGuid, sizeof(GUID) );
  2961. }
  2962. else
  2963. {
  2964. //
  2965. // it's likely already zero.
  2966. //
  2967. ReadLockLogonSessionList(ListIndex);
  2968. if( memcmp( &LogonSession->LogonGuid, &ZeroGuid, sizeof(ZeroGuid) ) != 0 )
  2969. {
  2970. ReadToWriteLockLogonSessionList(ListIndex);
  2971. RtlCopyMemory( &LogonSession->LogonGuid, &ZeroGuid, sizeof(GUID) );
  2972. }
  2973. }
  2974. UnlockLogonSessionList(ListIndex);
  2975. Cleanup:
  2976. if ( LogonSession )
  2977. {
  2978. LsapReleaseLogonSession(LogonSession);
  2979. }
  2980. return Status;
  2981. }
  2982. NTSTATUS
  2983. LsaISetPackageAttrInLogonSession(
  2984. IN PLUID LogonId,
  2985. IN ULONG PackageAttr
  2986. )
  2987. /*++
  2988. Routine Description:
  2989. Internal routine for the auth packages (currently only NTLM)
  2990. to set package-specific attributes in the logon session
  2991. Arguments:
  2992. LogonId - The logon id of the session
  2993. PackageAttr - Mask of package-specific flags to set in the logon session
  2994. Return Values:
  2995. Status of the operation.
  2996. STATUS_NO_SUCH_LOGON_SESSION - The logon session does not exist.
  2997. --*/
  2998. {
  2999. PLSAP_LOGON_SESSION LogonSession = NULL;
  3000. //
  3001. // We trust the auth package to be passing in valid parameters
  3002. // session so assert on all invalid parameter errors.
  3003. //
  3004. LogonSession = LsapLocateLogonSession(LogonId);
  3005. if (LogonSession == NULL)
  3006. {
  3007. ASSERT(LogonSession != NULL);
  3008. return STATUS_NO_SUCH_LOGON_SESSION;
  3009. }
  3010. //
  3011. // Update the logon session -- don't lock as this is
  3012. // a write-once field.
  3013. //
  3014. // NOTE: this field is effectively read-only once a package has returned
  3015. // control from the initial logon path. (eg: once a server can use the token/session)
  3016. LogonSession->PackageSpecificAttr |= PackageAttr;
  3017. LsapReleaseLogonSession(LogonSession);
  3018. return STATUS_SUCCESS;
  3019. }