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

3271 lines
81 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1995.
  5. //
  6. // File: neglsa.cxx
  7. //
  8. // Contents: General (both win9x and nt) functions
  9. //
  10. // Classes:
  11. //
  12. // Functions:
  13. //
  14. // History: 02-09-00 RichardW Created - split from negotiat.cxx
  15. //
  16. //----------------------------------------------------------------------------
  17. #include <lsapch.hxx>
  18. #ifdef WIN32_CHICAGO
  19. #include <kerb.hxx>
  20. #endif // WIN32_CHICAGO
  21. extern "C"
  22. {
  23. #include <align.h>
  24. #include <lm.h>
  25. #include <dsgetdc.h>
  26. #include <cryptdll.h>
  27. #include <netlib.h>
  28. #include <spmgr.h>
  29. #include "sesmgr.h"
  30. #include "spinit.h"
  31. }
  32. #include "negotiat.hxx"
  33. #include <stdio.h>
  34. GUID GUID_NULL = {0L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  35. TOKEN_SOURCE LsapTokenSource = {"LSA", 0};
  36. //
  37. // Hardcoded english strings for LocalService and NetworkService
  38. // since the account names may come from the registry (which isn't
  39. // localized).
  40. //
  41. #define LOCALSERVICE_NAME L"LocalService"
  42. #define NETWORKSERVICE_NAME L"NetworkService"
  43. #define NTAUTHORITY_NAME L"NT AUTHORITY"
  44. UNICODE_STRING LocalServiceName = { sizeof(LOCALSERVICE_NAME) - 2,
  45. sizeof(LOCALSERVICE_NAME),
  46. LOCALSERVICE_NAME };
  47. UNICODE_STRING NetworkServiceName = { sizeof(NETWORKSERVICE_NAME) - 2,
  48. sizeof(NETWORKSERVICE_NAME),
  49. NETWORKSERVICE_NAME };
  50. UNICODE_STRING NTAuthorityName = { sizeof(NTAUTHORITY_NAME) - 2,
  51. sizeof(NTAUTHORITY_NAME),
  52. NTAUTHORITY_NAME };
  53. HANDLE NegEventLogHandle = NULL ;
  54. ULONG NegEventLogLevel = 3 ;
  55. //
  56. // RELOCATE_ONE - Relocate a single pointer in a client buffer.
  57. //
  58. // Note: this macro is dependent on parameter names as indicated in the
  59. // description below. On error, this macro goes to 'Cleanup' with
  60. // 'Status' set to the NT Status code.
  61. //
  62. // The MaximumLength is forced to be Length.
  63. //
  64. // Define a macro to relocate a pointer in the buffer the client passed in
  65. // to be relative to 'ProtocolSubmitBuffer' rather than being relative to
  66. // 'ClientBufferBase'. The result is checked to ensure the pointer and
  67. // the data pointed to is within the first 'SubmitBufferSize' of the
  68. // 'ProtocolSubmitBuffer'.
  69. //
  70. // The relocated field must be aligned to a WCHAR boundary.
  71. //
  72. // _q - Address of UNICODE_STRING structure which points to data to be
  73. // relocated
  74. //
  75. #define RELOCATE_ONE( _q ) \
  76. { \
  77. ULONG_PTR Offset; \
  78. \
  79. Offset = (((PUCHAR)((_q)->Buffer)) - ((PUCHAR)ClientBufferBase)); \
  80. if ( Offset >= SubmitBufferSize || \
  81. Offset + (_q)->Length > SubmitBufferSize || \
  82. !COUNT_IS_ALIGNED( Offset, ALIGN_WCHAR) ) { \
  83. \
  84. Status = STATUS_INVALID_PARAMETER; \
  85. goto Cleanup; \
  86. } \
  87. \
  88. (_q)->Buffer = (PWSTR)(((PUCHAR)ProtocolSubmitBuffer) + Offset); \
  89. (_q)->MaximumLength = (_q)->Length ; \
  90. }
  91. //
  92. // NULL_RELOCATE_ONE - Relocate a single (possibly NULL) pointer in a client
  93. // buffer.
  94. //
  95. // This macro special cases a NULL pointer then calls RELOCATE_ONE. Hence
  96. // it has all the restrictions of RELOCATE_ONE.
  97. //
  98. //
  99. // _q - Address of UNICODE_STRING structure which points to data to be
  100. // relocated
  101. //
  102. #define NULL_RELOCATE_ONE( _q ) \
  103. { \
  104. if ( (_q)->Buffer == NULL ) { \
  105. if ( (_q)->Length != 0 ) { \
  106. Status = STATUS_INVALID_PARAMETER; \
  107. goto Cleanup; \
  108. } \
  109. } else if ( (_q)->Length == 0 ) { \
  110. (_q)->Buffer = NULL; \
  111. } else { \
  112. RELOCATE_ONE( _q ); \
  113. } \
  114. }
  115. #define MAX_EVENT_STRINGS 8
  116. extern SECPKG_PRIMARY_CRED NegPrimarySystemCredentials;
  117. //
  118. // Local function prototypes
  119. //
  120. NTSTATUS
  121. NegpMakeServiceToken(
  122. IN ULONG ulAccountId,
  123. OUT PLUID pLogonId,
  124. OUT PVOID *ProfileBuffer,
  125. OUT PULONG ProfileBufferLength,
  126. OUT PNTSTATUS ApiSubStatus,
  127. OUT PLSA_TOKEN_INFORMATION_TYPE TokenInformationType,
  128. OUT PVOID *TokenInformation,
  129. OUT PUNICODE_STRING *AccountName,
  130. OUT PUNICODE_STRING *AuthenticatingAuthority,
  131. OUT PUNICODE_STRING *MachineName,
  132. OUT PSECPKG_PRIMARY_CRED PrimaryCredentials,
  133. OUT PSECPKG_SUPPLEMENTAL_CRED_ARRAY * CachedCredentials
  134. );
  135. BOOL
  136. NegpIsLocalOrNetworkService(
  137. IN PVOID ProtocolSubmitBuffer,
  138. IN PVOID ClientBufferBase,
  139. IN ULONG SubmitBufferSize,
  140. OUT PUNICODE_STRING *AccountName,
  141. OUT PUNICODE_STRING *AuthenticatingAuthority,
  142. OUT PUNICODE_STRING *MachineName,
  143. OUT PULONG pulAccountId
  144. );
  145. VOID
  146. NegpReportEvent(
  147. IN WORD EventType,
  148. IN DWORD EventId,
  149. IN DWORD Category,
  150. IN NTSTATUS Status,
  151. IN DWORD NumberOfStrings,
  152. ...
  153. )
  154. {
  155. va_list arglist;
  156. ULONG i;
  157. PWSTR Strings[ MAX_EVENT_STRINGS ];
  158. BOOLEAN Allocated[ MAX_EVENT_STRINGS ] = { 0 };
  159. WCHAR StatusString[ MAX_PATH ];
  160. WCHAR FinalStatus[ MAX_PATH ];
  161. HANDLE Dll ;
  162. BOOL FreeDll = FALSE ;
  163. DWORD rv;
  164. if (NegEventLogHandle == NULL )
  165. {
  166. //
  167. // only log identical event once per hour.
  168. // note that LSA doesn't cleanup this 'handle' during shutdown,
  169. // to avoid preventing log failures during shutdown.
  170. //
  171. NegEventLogHandle = NetpEventlogOpen( L"LSASRV", 60000*60 );
  172. if ( NegEventLogHandle == NULL )
  173. {
  174. return ;
  175. }
  176. }
  177. //
  178. // We're not supposed to be logging this, so nuke it
  179. //
  180. if ((NegEventLogLevel & (1 << EventType)) == 0)
  181. {
  182. return ;
  183. }
  184. //
  185. // Look at the strings, if they were provided
  186. //
  187. va_start( arglist, NumberOfStrings );
  188. if (NumberOfStrings > MAX_EVENT_STRINGS) {
  189. NumberOfStrings = MAX_EVENT_STRINGS;
  190. }
  191. for (i=0; i<NumberOfStrings; i++) {
  192. PUNICODE_STRING String = va_arg( arglist, PUNICODE_STRING );
  193. //
  194. // Make sure strings are NULL-terminated. Do it in place for
  195. // those strings whose buffers can accomodate an additional character,
  196. // and allocate memory for the rest.
  197. //
  198. if ( String->MaximumLength > String->Length ) {
  199. Strings[i] = String->Buffer;
  200. } else {
  201. Strings[i] = ( PWSTR )LsapAllocatePrivateHeap( String->Length + sizeof( WCHAR ));
  202. if ( Strings[i] == NULL ) {
  203. goto Cleanup;
  204. }
  205. Allocated[i] = TRUE;
  206. RtlCopyMemory( Strings[i], String->Buffer, String->Length );
  207. }
  208. Strings[i][String->Length / sizeof( WCHAR )] = L'\0';
  209. }
  210. if ( Status != 0 )
  211. {
  212. static HMODULE NtDll;
  213. static HMODULE Kernel32;
  214. //
  215. // Map the status code:
  216. //
  217. //
  218. // The value "type" is not known. Try and figure out what it
  219. // is.
  220. //
  221. if ( (Status & 0xC0000000) == 0xC0000000 )
  222. {
  223. //
  224. // Easy: NTSTATUS failure case
  225. //
  226. if( NtDll == NULL )
  227. {
  228. NtDll = GetModuleHandleW( L"NTDLL.DLL" );
  229. }
  230. Dll = NtDll;
  231. }
  232. else if ( ( Status & 0xF0000000 ) == 0xD0000000 )
  233. {
  234. //
  235. // HRESULT from NTSTATUS
  236. //
  237. if( NtDll == NULL )
  238. {
  239. NtDll = GetModuleHandleW( L"NTDLL.DLL" );
  240. }
  241. Dll = NtDll;
  242. Status &= 0xCFFFFFFF ;
  243. }
  244. else if ( ( Status & 0x80000000 ) == 0x80000000 )
  245. {
  246. //
  247. // Note, this can overlap with NTSTATUS warning area. In that
  248. // case, force the NTSTATUS.
  249. //
  250. if( Kernel32 == NULL )
  251. {
  252. Kernel32 = GetModuleHandleW( L"KERNEL32.DLL" );
  253. }
  254. Dll = Kernel32;
  255. }
  256. else
  257. {
  258. //
  259. // Sign bit is off. Explore some known ranges:
  260. //
  261. if ( (Status >= WSABASEERR) && (Status <= WSABASEERR + 1000 ))
  262. {
  263. Dll = LoadLibraryW( L"ws2_32.dll" );
  264. FreeDll = TRUE ;
  265. }
  266. else if ( ( Status >= NERR_BASE ) && ( Status <= MAX_NERR ) )
  267. {
  268. Dll = LoadLibraryW( L"netmsg.dll" );
  269. FreeDll = TRUE ;
  270. }
  271. else
  272. {
  273. if( Kernel32 == NULL )
  274. {
  275. Kernel32 = GetModuleHandleW( L"KERNEL32.DLL" );
  276. }
  277. Dll = Kernel32;
  278. }
  279. }
  280. if (!FormatMessage(
  281. FORMAT_MESSAGE_IGNORE_INSERTS |
  282. FORMAT_MESSAGE_FROM_HMODULE,
  283. Dll,
  284. Status,
  285. 0,
  286. StatusString,
  287. MAX_PATH,
  288. NULL ) )
  289. {
  290. StatusString[0] = L' ';
  291. StatusString[1] = L'\0';
  292. }
  293. if ( Status < 0 )
  294. {
  295. _snwprintf( FinalStatus, MAX_PATH, L"\"%ws (%#x)\"", StatusString, Status );
  296. }
  297. else
  298. {
  299. _snwprintf( FinalStatus, MAX_PATH, L"\"%ws (%#x, %d)\"", StatusString, Status, Status );
  300. }
  301. if ( NumberOfStrings < MAX_EVENT_STRINGS )
  302. {
  303. Strings[ NumberOfStrings++ ] = FinalStatus ;
  304. }
  305. }
  306. //
  307. // Report the event to the eventlog service
  308. //
  309. NetpEventlogWriteEx(
  310. NegEventLogHandle,
  311. EventType,
  312. Category,
  313. EventId,
  314. NumberOfStrings,
  315. 0,
  316. Strings,
  317. NULL
  318. );
  319. Cleanup:
  320. for ( i = 0 ; i < NumberOfStrings ; i++ ) {
  321. if ( Allocated[i] ) {
  322. LsapFreePrivateHeap( Strings[i] );
  323. }
  324. }
  325. }
  326. //+---------------------------------------------------------------------------
  327. //
  328. // Function: NegLsaPolicyChangeCallback
  329. //
  330. // Synopsis: Called by the policy engine in the LSA when local policy changes,
  331. // allowing us to update our state about the machine account, etc.
  332. //
  333. // Arguments: ChangedInfoClass - Class of policy that changed
  334. //
  335. // History: 2-9-00 RichardW Created
  336. //
  337. // Notes:
  338. //
  339. //----------------------------------------------------------------------------
  340. VOID
  341. NTAPI
  342. NegLsaPolicyChangeCallback(
  343. IN POLICY_NOTIFICATION_INFORMATION_CLASS ChangedInfoClass
  344. )
  345. {
  346. PLSAPR_POLICY_INFORMATION Policy = NULL ;
  347. NTSTATUS Status ;
  348. GUID GuidNull = GUID_NULL ;
  349. PLSAP_LOGON_SESSION LogonSession = NULL ;
  350. BOOL Uplevel ;
  351. //
  352. // Right now, only domain information is interesting
  353. //
  354. if ( ChangedInfoClass != PolicyNotifyDnsDomainInformation )
  355. {
  356. return ;
  357. }
  358. DebugLog(( DEB_TRACE_NEG, "Domain change, updating state\n" ));
  359. //
  360. // Reset the trust list. The next time someone asks for the trust
  361. // list, it will have expired and they will get a fresh one.
  362. //
  363. NegTrustTime.QuadPart = 0 ;
  364. //
  365. // Obtain the new policy settings
  366. //
  367. Status = LsaIQueryInformationPolicyTrusted(
  368. PolicyDnsDomainInformation,
  369. &Policy );
  370. if ( NT_SUCCESS( Status ) )
  371. {
  372. //
  373. // If the domain has a GUID, then it is an uplevel domain
  374. //
  375. if ( Policy->PolicyDnsDomainInfo.DomainGuid == GuidNull )
  376. {
  377. Uplevel = FALSE ;
  378. }
  379. else
  380. {
  381. Uplevel = TRUE ;
  382. }
  383. //
  384. // Done with the policy info
  385. //
  386. LsaIFree_LSAPR_POLICY_INFORMATION(
  387. PolicyDnsDomainInformation,
  388. Policy
  389. );
  390. NegUplevelDomain = Uplevel ;
  391. //
  392. // Update the package ID for the local system logon session
  393. // Note, any additional special logon sessions will need to be
  394. // updated as well.
  395. //
  396. LogonSession = LsapLocateLogonSession( &SystemLogonId );
  397. if ( LogonSession )
  398. {
  399. if ( Uplevel )
  400. {
  401. LogonSession->CreatingPackage = NegPackageId ;
  402. }
  403. else
  404. {
  405. LogonSession->CreatingPackage = NtlmPackageId ;
  406. }
  407. LsapReleaseLogonSession( LogonSession );
  408. }
  409. }
  410. {
  411. ULONG Size;
  412. static WCHAR NegNetbiosComputerName[ MAX_COMPUTERNAME_LENGTH + 1 ];
  413. static WCHAR NegDnsComputerName[ DNS_MAX_NAME_BUFFER_LENGTH + 1 ];
  414. //
  415. // refresh the computer names.
  416. // note we could avoid taking the lock around these calls if we dyna-alloc'd
  417. // and freed the existing buffers. We don't expect this path to be hit often,
  418. // so avoid the hassle.
  419. //
  420. NegWriteLockComputerNames();
  421. Size = sizeof(NegDnsComputerName) / sizeof(WCHAR);
  422. //
  423. // Note, if this fails, it's ok. We just won't be able to make
  424. // some optimizations later.
  425. //
  426. if(!GetComputerNameExW(
  427. ComputerNamePhysicalDnsFullyQualified,
  428. NegDnsComputerName,
  429. &Size
  430. ))
  431. {
  432. NegDnsComputerName[ 0 ] = L'\0';
  433. }
  434. RtlInitUnicodeString( &NegDnsComputerName_U, NegDnsComputerName );
  435. Size = sizeof(NegNetbiosComputerName) / sizeof(WCHAR);
  436. if(!GetComputerNameExW(
  437. ComputerNamePhysicalNetBIOS,
  438. NegNetbiosComputerName,
  439. &Size
  440. ))
  441. {
  442. NegNetbiosComputerName[ 0 ] = L'\0';
  443. }
  444. RtlInitUnicodeString( &NegNetbiosComputerName_U, NegNetbiosComputerName );
  445. NegUnlockComputerNames();
  446. }
  447. }
  448. //+---------------------------------------------------------------------------
  449. //
  450. // Function: NegParamChange
  451. //
  452. // Synopsis: Called by LSA whenever the LSA registry key changes
  453. //
  454. // Arguments: [p] --
  455. //
  456. // History: 5-11-00 RichardW Created
  457. //
  458. // Notes:
  459. //
  460. //----------------------------------------------------------------------------
  461. DWORD
  462. WINAPI
  463. NegParamChange(
  464. PVOID p
  465. )
  466. {
  467. NTSTATUS Status ;
  468. PSECPKG_EVENT_NOTIFY Notify;
  469. HKEY LsaKey ;
  470. Notify = (PSECPKG_EVENT_NOTIFY) p;
  471. if ( Notify->EventClass != NOTIFY_CLASS_REGISTRY_CHANGE )
  472. {
  473. return( 0 );
  474. }
  475. if ( RegOpenKeyEx(
  476. HKEY_LOCAL_MACHINE,
  477. TEXT("System\\CurrentControlSet\\Control\\Lsa"),
  478. 0,
  479. KEY_READ,
  480. &LsaKey ) == 0 )
  481. {
  482. NegpReadRegistryParameters( LsaKey );
  483. RegCloseKey( LsaKey );
  484. }
  485. return 0 ;
  486. }
  487. //+---------------------------------------------------------------------------
  488. //
  489. // Function: NegEnumPackagePrefixesCall
  490. //
  491. // Synopsis: LsaCallPackage routine to identify the prefxes (or OIDs) for
  492. // all the packages, for SASL support.
  493. //
  494. // Arguments:
  495. //
  496. // History:
  497. //
  498. // Notes:
  499. //
  500. //----------------------------------------------------------------------------
  501. NTSTATUS
  502. NegEnumPackagePrefixesCall(
  503. IN PLSA_CLIENT_REQUEST ClientRequest,
  504. IN PVOID ProtocolSubmitBuffer,
  505. IN PVOID ClientBufferBase,
  506. IN ULONG SubmitBufferLength,
  507. OUT PVOID *ProtocolReturnBuffer,
  508. OUT PULONG ReturnBufferLength,
  509. OUT PNTSTATUS ProtocolStatus
  510. )
  511. {
  512. UCHAR PrefixBuffer[ NEGOTIATE_MAX_PREFIX ];
  513. NTSTATUS Status ;
  514. PNEGOTIATE_PACKAGE_PREFIXES Prefixes ;
  515. PNEGOTIATE_PACKAGE_PREFIX Prefix ;
  516. PNEGOTIATE_PACKAGE_PREFIX_WOW PrefixWow ;
  517. ULONG PackageCount ;
  518. BOOL WowClient = FALSE ;
  519. PNEG_PACKAGE Package ;
  520. PLIST_ENTRY Scan ;
  521. SECPKG_CALL_INFO CallInfo ;
  522. ULONG Size ;
  523. LsapGetCallInfo( &CallInfo );
  524. if ( CallInfo.Attributes & SECPKG_CALL_WOWCLIENT )
  525. {
  526. WowClient = TRUE;
  527. }
  528. NegReadLockList();
  529. Size = sizeof( NEGOTIATE_PACKAGE_PREFIXES ) +
  530. sizeof( NEGOTIATE_PACKAGE_PREFIX ) * ( NegPackageCount + 1 );
  531. Prefixes = (PNEGOTIATE_PACKAGE_PREFIXES) LsapAllocatePrivateHeap( Size );
  532. if ( !Prefixes )
  533. {
  534. NegUnlockList();
  535. return SEC_E_INSUFFICIENT_MEMORY ;
  536. }
  537. Prefixes->MessageType = NegEnumPackagePrefixes ;
  538. Prefixes->Offset = sizeof( NEGOTIATE_PACKAGE_PREFIXES );
  539. //
  540. // We're going to do one or the other, but initializing them both
  541. // makes the compiler happier.
  542. //
  543. Prefix = (PNEGOTIATE_PACKAGE_PREFIX) ( Prefixes + 1 );
  544. PrefixWow = (PNEGOTIATE_PACKAGE_PREFIX_WOW) ( Prefixes + 1);
  545. if ( WowClient )
  546. {
  547. PrefixWow->PackageId = (ULONG) NegPackageId ;
  548. PrefixWow->PrefixLen = sizeof( NegSpnegoMechEncodedOid );
  549. PrefixWow->PackageDataA = NULL ;
  550. PrefixWow->PackageDataW = NULL ;
  551. RtlCopyMemory( PrefixWow->Prefix,
  552. NegSpnegoMechEncodedOid,
  553. sizeof( NegSpnegoMechEncodedOid ) );
  554. PrefixWow++ ;
  555. }
  556. else
  557. {
  558. Prefix->PackageId = NegPackageId ;
  559. Prefix->PrefixLen = sizeof( NegSpnegoMechEncodedOid );
  560. Prefix->PackageDataA = NULL ;
  561. Prefix->PackageDataW = NULL ;
  562. RtlCopyMemory( Prefix->Prefix,
  563. NegSpnegoMechEncodedOid,
  564. sizeof( NegSpnegoMechEncodedOid ) );
  565. Prefix++ ;
  566. }
  567. PackageCount = 1 ;
  568. Scan = NegPackageList.Flink ;
  569. while ( Scan != &NegPackageList )
  570. {
  571. Package = CONTAINING_RECORD( Scan, NEG_PACKAGE, List );
  572. if ( !WowClient )
  573. {
  574. Prefix->PackageId = Package->LsaPackage->dwPackageID ;
  575. Prefix->PrefixLen = Package->PrefixLen ;
  576. Prefix->PackageDataA = NULL ;
  577. Prefix->PackageDataW = NULL ;
  578. RtlCopyMemory( Prefix->Prefix,
  579. Package->Prefix,
  580. Package->PrefixLen );
  581. Prefix++ ;
  582. PackageCount++ ;
  583. }
  584. else
  585. {
  586. if ( Package->LsaPackage->fPackage & SP_WOW_SUPPORT )
  587. {
  588. PrefixWow->PackageId = (ULONG) Package->LsaPackage->dwPackageID ;
  589. PrefixWow->PrefixLen = Package->PrefixLen ;
  590. PrefixWow->PackageDataA = NULL ;
  591. PrefixWow->PackageDataW = NULL ;
  592. RtlCopyMemory( PrefixWow->Prefix,
  593. Package->Prefix,
  594. Package->PrefixLen );
  595. PrefixWow++ ;
  596. PackageCount++ ;
  597. }
  598. }
  599. Scan = Scan->Flink ;
  600. }
  601. NegUnlockList();
  602. //
  603. // Set the final count of packages:
  604. //
  605. Prefixes->PrefixCount = PackageCount ;
  606. Status = LsapAllocateClientBuffer(
  607. NULL,
  608. Size,
  609. ProtocolReturnBuffer );
  610. if ( NT_SUCCESS( Status ) )
  611. {
  612. Status = LsapCopyToClient(
  613. Prefixes,
  614. *ProtocolReturnBuffer,
  615. Size );
  616. *ReturnBufferLength = Size ;
  617. }
  618. LsapFreePrivateHeap( Prefixes );
  619. return Status ;
  620. }
  621. NTSTATUS
  622. NegGetCallerNameCall(
  623. IN PLSA_CLIENT_REQUEST ClientRequest,
  624. IN PVOID ProtocolSubmitBuffer,
  625. IN PVOID ClientBufferBase,
  626. IN ULONG SubmitBufferLength,
  627. OUT PVOID *ProtocolReturnBuffer,
  628. OUT PULONG ReturnBufferLength,
  629. OUT PNTSTATUS ProtocolStatus
  630. )
  631. {
  632. PNEGOTIATE_CALLER_NAME_REQUEST Request ;
  633. PNEGOTIATE_CALLER_NAME_RESPONSE Response ;
  634. PNEGOTIATE_CALLER_NAME_RESPONSE_WOW ResponseWow ;
  635. SECPKG_CLIENT_INFO ClientInfo ;
  636. SECPKG_CALL_INFO CallInfo ;
  637. NTSTATUS Status ;
  638. PNEG_LOGON_SESSION LogonSession ;
  639. ULONG ClientSize ;
  640. PUCHAR Where ;
  641. PVOID ClientBuffer ;
  642. BOOL ReCheckAccess = FALSE ;
  643. *ProtocolReturnBuffer = NULL ;
  644. *ReturnBufferLength = 0 ;
  645. *ProtocolStatus = 0 ;
  646. if ( SubmitBufferLength != sizeof( NEGOTIATE_CALLER_NAME_REQUEST ) )
  647. {
  648. return STATUS_INVALID_PARAMETER ;
  649. }
  650. Request = (PNEGOTIATE_CALLER_NAME_REQUEST) ProtocolSubmitBuffer ;
  651. Status = LsapGetClientInfo( &ClientInfo );
  652. if ( !NT_SUCCESS( Status ) )
  653. {
  654. return Status ;
  655. }
  656. LsapGetCallInfo( &CallInfo );
  657. if ( RtlIsZeroLuid( &Request->LogonId ) )
  658. {
  659. Request->LogonId = ClientInfo.LogonId ;
  660. }
  661. else
  662. {
  663. if ( !RtlEqualLuid( &ClientInfo.LogonId, &Request->LogonId ) )
  664. {
  665. ReCheckAccess = TRUE ;
  666. }
  667. }
  668. LogonSession = NegpLocateLogonSession( &Request->LogonId );
  669. if ( LogonSession )
  670. {
  671. if ( ReCheckAccess )
  672. {
  673. if ( !RtlEqualLuid( &ClientInfo.LogonId, &LogonSession->ParentLogonId ) )
  674. {
  675. Status = STATUS_ACCESS_DENIED ;
  676. goto AccessDeniedError ;
  677. }
  678. }
  679. if ( LogonSession->AlternateName.Buffer == NULL )
  680. {
  681. //
  682. // No alternate ID
  683. //
  684. Status = STATUS_NO_SUCH_LOGON_SESSION ;
  685. goto AccessDeniedError ;
  686. }
  687. ClientSize = sizeof( NEGOTIATE_CALLER_NAME_RESPONSE ) +
  688. LogonSession->AlternateName.Length + sizeof( WCHAR );
  689. Response = (PNEGOTIATE_CALLER_NAME_RESPONSE) LsapAllocatePrivateHeap( ClientSize );
  690. if ( Response )
  691. {
  692. ClientBuffer = LsapClientAllocate( ClientSize );
  693. if ( ClientBuffer )
  694. {
  695. Where = (PUCHAR) ClientBuffer + sizeof( NEGOTIATE_CALLER_NAME_RESPONSE ) ;
  696. //
  697. // If a WOW client, copy these to the 32bit locations. Note
  698. // that this will leave a "hole," but that's ok.
  699. //
  700. if ( CallInfo.Attributes & SECPKG_CALL_WOWCLIENT )
  701. {
  702. ResponseWow = (PNEGOTIATE_CALLER_NAME_RESPONSE_WOW) Response ;
  703. ResponseWow->MessageType = NegGetCallerName ;
  704. ResponseWow->CallerName = PtrToUlong(Where) ;
  705. }
  706. else
  707. {
  708. Response->MessageType = NegGetCallerName ;
  709. Response->CallerName = (PWSTR) Where ;
  710. }
  711. RtlCopyMemory( (Response + 1),
  712. LogonSession->AlternateName.Buffer,
  713. LogonSession->AlternateName.Length );
  714. *ProtocolReturnBuffer = ClientBuffer ;
  715. *ReturnBufferLength = ClientSize ;
  716. *ProtocolStatus = 0 ;
  717. Status = LsapCopyToClient( Response,
  718. ClientBuffer,
  719. ClientSize ) ;
  720. }
  721. else
  722. {
  723. Status = STATUS_NO_MEMORY ;
  724. }
  725. LsapFreePrivateHeap( Response );
  726. }
  727. AccessDeniedError:
  728. NegpDerefLogonSession( LogonSession );
  729. }
  730. else
  731. {
  732. Status = STATUS_NO_SUCH_LOGON_SESSION ;
  733. }
  734. *ProtocolStatus = Status ;
  735. return STATUS_SUCCESS ;
  736. }
  737. PNEG_LOGON_SESSION
  738. NegpBuildLogonSession(
  739. PLUID LogonId,
  740. ULONG_PTR LogonPackage,
  741. ULONG_PTR DefaultPackage
  742. )
  743. {
  744. PNEG_LOGON_SESSION LogonSession ;
  745. LogonSession = (PNEG_LOGON_SESSION) LsapAllocatePrivateHeap( sizeof( NEG_LOGON_SESSION ) );
  746. if ( LogonSession )
  747. {
  748. LogonSession->LogonId = *LogonId ;
  749. LogonSession->CreatingPackage = LogonPackage ;
  750. LogonSession->DefaultPackage = DefaultPackage ;
  751. LogonSession->RefCount = 2 ;
  752. RtlEnterCriticalSection( &NegLogonSessionListLock );
  753. InsertHeadList( &NegLogonSessionList, &LogonSession->List );
  754. RtlLeaveCriticalSection( &NegLogonSessionListLock );
  755. }
  756. return LogonSession ;
  757. }
  758. VOID
  759. NegpDerefLogonSession(
  760. PNEG_LOGON_SESSION LogonSession
  761. )
  762. {
  763. BOOL FreeIt = FALSE ;
  764. RtlEnterCriticalSection( &NegLogonSessionListLock );
  765. LogonSession->RefCount-- ;
  766. if ( LogonSession->RefCount == 0 )
  767. {
  768. RemoveEntryList( &LogonSession->List );
  769. FreeIt = TRUE ;
  770. }
  771. RtlLeaveCriticalSection( &NegLogonSessionListLock );
  772. if ( FreeIt )
  773. {
  774. if ( LogonSession->AlternateName.Buffer )
  775. {
  776. LsapFreePrivateHeap( LogonSession->AlternateName.Buffer );
  777. }
  778. LsapFreePrivateHeap( LogonSession );
  779. }
  780. }
  781. VOID
  782. NegpDerefLogonSessionById(
  783. PLUID LogonId
  784. )
  785. {
  786. BOOL FreeIt = FALSE ;
  787. PLIST_ENTRY Scan ;
  788. PNEG_LOGON_SESSION LogonSession = NULL;
  789. RtlEnterCriticalSection( &NegLogonSessionListLock );
  790. Scan = NegLogonSessionList.Flink ;
  791. while ( Scan != &NegLogonSessionList )
  792. {
  793. LogonSession = CONTAINING_RECORD( Scan, NEG_LOGON_SESSION, List );
  794. if ( RtlEqualLuid( LogonId, &LogonSession->LogonId ) )
  795. {
  796. LogonSession->RefCount -- ;
  797. if ( LogonSession->RefCount == 0 )
  798. {
  799. RemoveEntryList( &LogonSession->List );
  800. FreeIt = TRUE ;
  801. }
  802. break;
  803. }
  804. LogonSession = NULL ;
  805. Scan = Scan->Flink ;
  806. }
  807. RtlLeaveCriticalSection( &NegLogonSessionListLock );
  808. if ( FreeIt )
  809. {
  810. DsysAssert( LogonSession != NULL );
  811. if ( LogonSession->AlternateName.Buffer )
  812. {
  813. LsapFreePrivateHeap( LogonSession->AlternateName.Buffer );
  814. }
  815. LsapFreePrivateHeap( LogonSession );
  816. }
  817. }
  818. PNEG_LOGON_SESSION
  819. NegpLocateLogonSession(
  820. PLUID LogonId
  821. )
  822. {
  823. PLIST_ENTRY Scan ;
  824. PNEG_LOGON_SESSION LogonSession = NULL;
  825. RtlEnterCriticalSection( &NegLogonSessionListLock );
  826. Scan = NegLogonSessionList.Flink ;
  827. while ( Scan != &NegLogonSessionList )
  828. {
  829. LogonSession = CONTAINING_RECORD( Scan, NEG_LOGON_SESSION, List );
  830. if ( RtlEqualLuid( LogonId, &LogonSession->LogonId ) )
  831. {
  832. break;
  833. }
  834. LogonSession = NULL ;
  835. Scan = Scan->Flink ;
  836. }
  837. if ( LogonSession )
  838. {
  839. LogonSession->RefCount++ ;
  840. }
  841. RtlLeaveCriticalSection( &NegLogonSessionListLock );
  842. return LogonSession ;
  843. }
  844. NTSTATUS
  845. NTAPI
  846. NegpMapLogonRequest(
  847. IN PVOID ProtocolSubmitBuffer,
  848. IN PVOID ClientBufferBase,
  849. IN ULONG SubmitBufferSize,
  850. OUT PMSV1_0_INTERACTIVE_LOGON * LogonInfo
  851. )
  852. {
  853. NTSTATUS Status = STATUS_SUCCESS ;
  854. PMSV1_0_INTERACTIVE_LOGON Authentication = NULL;
  855. PSECURITY_SEED_AND_LENGTH SeedAndLength;
  856. UCHAR Seed;
  857. //
  858. // Ensure this is really an interactive logon.
  859. //
  860. Authentication =
  861. (PMSV1_0_INTERACTIVE_LOGON) ProtocolSubmitBuffer;
  862. if ( Authentication->MessageType != MsV1_0InteractiveLogon ) {
  863. DebugLog(( DEB_ERROR, "Neg: Bad Validation Class %d\n",
  864. Authentication->MessageType));
  865. Status = STATUS_BAD_VALIDATION_CLASS;
  866. goto Cleanup;
  867. }
  868. //
  869. // If the password length is greater than 255 (i.e., the
  870. // upper byte of the length is non-zero) then the password
  871. // has been run-encoded for privacy reasons. Get the
  872. // run-encode seed out of the upper-byte of the length
  873. // for later use.
  874. //
  875. //
  876. SeedAndLength = (PSECURITY_SEED_AND_LENGTH)
  877. &Authentication->Password.Length;
  878. Seed = SeedAndLength->Seed;
  879. SeedAndLength->Seed = 0;
  880. //
  881. // Enforce length restrictions on username and password.
  882. //
  883. if ( Authentication->UserName.Length > UNLEN ||
  884. Authentication->Password.Length > PWLEN ) {
  885. DebugLog(( DEB_ERROR, "Neg: Name or password too long\n"));
  886. Status = STATUS_NAME_TOO_LONG;
  887. goto Cleanup;
  888. }
  889. //
  890. // Relocate any pointers to be relative to 'Authentication'
  891. //
  892. NULL_RELOCATE_ONE( &Authentication->LogonDomainName );
  893. RELOCATE_ONE( &Authentication->UserName );
  894. NULL_RELOCATE_ONE( &Authentication->Password );
  895. //
  896. // Now decode the password, if necessary
  897. //
  898. if (Seed != 0 ) {
  899. __try {
  900. RtlRunDecodeUnicodeString( Seed, &Authentication->Password);
  901. } __except(EXCEPTION_EXECUTE_HANDLER) {
  902. Status = STATUS_ILL_FORMED_PASSWORD;
  903. goto Cleanup;
  904. }
  905. }
  906. *LogonInfo = Authentication ;
  907. Cleanup:
  908. return Status ;
  909. }
  910. VOID
  911. NegpDerefTrustList(
  912. PNEG_TRUST_LIST TrustList
  913. )
  914. {
  915. RtlEnterCriticalSection( &NegTrustListLock );
  916. TrustList->RefCount-- ;
  917. if ( TrustList->RefCount == 0 )
  918. {
  919. if( NegTrustList == TrustList )
  920. {
  921. NegTrustList = NULL;
  922. }
  923. RtlLeaveCriticalSection( &NegTrustListLock );
  924. NetApiBufferFree( TrustList->Trusts );
  925. LsapFreePrivateHeap( TrustList );
  926. return;
  927. }
  928. RtlLeaveCriticalSection( &NegTrustListLock );
  929. }
  930. PNEG_TRUST_LIST
  931. NegpGetTrustList(
  932. VOID
  933. )
  934. {
  935. PDS_DOMAIN_TRUSTS Trusts = NULL;
  936. DWORD TrustCount ;
  937. PNEG_TRUST_LIST TrustList = NULL ;
  938. DWORD NetStatus ;
  939. LARGE_INTEGER Now ;
  940. BOOLEAN TrustListLocked = TRUE;
  941. GetSystemTimeAsFileTime( (LPFILETIME) &Now );
  942. RtlEnterCriticalSection( &NegTrustListLock );
  943. if ( Now.QuadPart > NegTrustTime.QuadPart + FIFTEEN_MINUTES )
  944. {
  945. if( NegTrustList != NULL && NegTrustList->RefCount == 1 )
  946. {
  947. NegpDerefTrustList( NegTrustList );
  948. NegTrustList = NULL;
  949. }
  950. }
  951. if( NegTrustList != NULL )
  952. {
  953. TrustList = NegTrustList ;
  954. TrustList->RefCount++ ;
  955. goto Cleanup;
  956. }
  957. RtlLeaveCriticalSection( &NegTrustListLock );
  958. TrustListLocked = FALSE;
  959. NetStatus = DsEnumerateDomainTrustsW( NULL,
  960. DS_DOMAIN_IN_FOREST |
  961. DS_DOMAIN_PRIMARY,
  962. &Trusts,
  963. &TrustCount );
  964. if ( NetStatus != 0 )
  965. {
  966. goto Cleanup;
  967. }
  968. TrustList = (PNEG_TRUST_LIST) LsapAllocatePrivateHeap( sizeof( NEG_TRUST_LIST ) );
  969. if( TrustList == NULL )
  970. {
  971. goto Cleanup;
  972. }
  973. TrustList->RefCount = 2 ;
  974. TrustList->TrustCount = TrustCount ;
  975. TrustList->Trusts = Trusts ;
  976. RtlEnterCriticalSection( &NegTrustListLock );
  977. TrustListLocked = TRUE;
  978. if( NegTrustList != NULL )
  979. {
  980. PNEG_TRUST_LIST FreeTrustList = TrustList;
  981. TrustList = NegTrustList ;
  982. TrustList->RefCount++ ;
  983. RtlLeaveCriticalSection( &NegTrustListLock );
  984. TrustListLocked = FALSE;
  985. LsapFreePrivateHeap( FreeTrustList );
  986. goto Cleanup;
  987. }
  988. Trusts = NULL;
  989. NegTrustList = TrustList ;
  990. NegTrustTime = Now ;
  991. Cleanup:
  992. if( TrustListLocked )
  993. {
  994. RtlLeaveCriticalSection( &NegTrustListLock );
  995. }
  996. if( Trusts != NULL )
  997. {
  998. NetApiBufferFree( Trusts );
  999. }
  1000. return TrustList ;
  1001. }
  1002. NEG_DOMAIN_TYPES
  1003. NegpIsUplevelDomain(
  1004. PLUID LogonId,
  1005. SECURITY_LOGON_TYPE LogonType,
  1006. PUNICODE_STRING Domain
  1007. )
  1008. {
  1009. PNEG_TRUST_LIST TrustList ;
  1010. UNICODE_STRING String ;
  1011. ULONG i ;
  1012. BOOL IsUplevel = FALSE ;
  1013. LONG Error ;
  1014. PDOMAIN_CONTROLLER_INFOW Info ;
  1015. UNREFERENCED_PARAMETER(LogonId);
  1016. //
  1017. // Case #1. Local logons are not uplevel, and should be allowed to
  1018. // use NTLM right off the bat. Therefore, return false
  1019. //
  1020. if ( RtlEqualUnicodeString(
  1021. Domain,
  1022. &MachineName,
  1023. TRUE ) )
  1024. {
  1025. return NegLocalDomain;
  1026. }
  1027. if ( LogonType == CachedInteractive )
  1028. {
  1029. return NegUpLevelDomain;
  1030. }
  1031. //
  1032. // Case #2. We logged on to a domain, but we need to check if it is
  1033. // an uplevel domain in our forest. If it is, then return true, otherwise
  1034. // it's not an uplevel domain and NTLM is acceptable. If we can't obtain the
  1035. // trust list, assume downlevel.
  1036. //
  1037. TrustList = NegpGetTrustList();
  1038. if ( TrustList )
  1039. {
  1040. for ( i = 0 ; i < TrustList->TrustCount ; i++ )
  1041. {
  1042. RtlInitUnicodeString( &String, TrustList->Trusts[i].NetbiosDomainName );
  1043. if ( RtlEqualUnicodeString( Domain,
  1044. &String,
  1045. TRUE ) )
  1046. {
  1047. //
  1048. // Hit, check it
  1049. //
  1050. if ( ( TrustList->Trusts[i].DnsDomainName != NULL ) &&
  1051. ( TrustList->Trusts[i].Flags & DS_DOMAIN_IN_FOREST ) )
  1052. {
  1053. IsUplevel = TRUE ;
  1054. break;
  1055. }
  1056. }
  1057. }
  1058. NegpDerefTrustList( TrustList );
  1059. }
  1060. if ( IsUplevel )
  1061. {
  1062. return NegUpLevelDomain ;
  1063. }
  1064. //
  1065. // Case #3 - if this is an uplevel domain we live in, then the answer returned
  1066. // by netlogon is authoritative:
  1067. //
  1068. if ( NegUplevelDomain )
  1069. {
  1070. return NegDownLevelDomain ;
  1071. }
  1072. //
  1073. // Case #4 - if we are living in a downlevel domain, netlogon won't know if the domain
  1074. // we just talked to is uplevel or downlevel. So, we need to figure out directly.
  1075. //
  1076. Error = DsGetDcNameW(
  1077. NULL,
  1078. Domain->Buffer,
  1079. NULL,
  1080. NULL,
  1081. DS_DIRECTORY_SERVICE_REQUIRED,
  1082. &Info );
  1083. if ( Error == 0 )
  1084. {
  1085. IsUplevel = TRUE ;
  1086. NetApiBufferFree( Info );
  1087. }
  1088. else
  1089. {
  1090. IsUplevel = FALSE ;
  1091. }
  1092. return ( IsUplevel ? NegUpLevelTrustedDomain : NegDownLevelDomain );
  1093. }
  1094. //+-------------------------------------------------------------------------
  1095. //
  1096. // Function: NegpCloneLogonSession
  1097. //
  1098. // Synopsis: Handles a NewCredentials type of logon.
  1099. //
  1100. // Effects:
  1101. //
  1102. // Arguments:
  1103. //
  1104. // Requires:
  1105. //
  1106. // Returns:
  1107. //
  1108. // Notes:
  1109. //
  1110. //
  1111. //--------------------------------------------------------------------------
  1112. NTSTATUS
  1113. NTAPI
  1114. NegpCloneLogonSession(
  1115. IN PVOID ProtocolSubmitBuffer,
  1116. IN PVOID ClientBufferBase,
  1117. IN ULONG SubmitBufferSize,
  1118. OUT PVOID *ProfileBuffer,
  1119. OUT PULONG ProfileBufferLength,
  1120. OUT PLUID NewLogonId,
  1121. OUT PNTSTATUS ApiSubStatus,
  1122. OUT PLSA_TOKEN_INFORMATION_TYPE TokenInformationType,
  1123. OUT PVOID *TokenInformation,
  1124. OUT PUNICODE_STRING *AccountName,
  1125. OUT PUNICODE_STRING *AuthenticatingAuthority,
  1126. OUT PUNICODE_STRING *MachineName,
  1127. OUT PSECPKG_PRIMARY_CRED PrimaryCredentials,
  1128. OUT PSECPKG_SUPPLEMENTAL_CRED_ARRAY * CachedCredentials
  1129. )
  1130. {
  1131. NTSTATUS Status ;
  1132. HANDLE hToken ;
  1133. UCHAR SmallBuffer[ 128 ];
  1134. PLSA_TOKEN_INFORMATION_V1 TokenInfo = NULL ;
  1135. PTOKEN_USER User = NULL ;
  1136. PTOKEN_GROUPS Groups = NULL ;
  1137. PTOKEN_GROUPS FinalGroups = NULL ;
  1138. PTOKEN_PRIMARY_GROUP PrimaryGroup = NULL ;
  1139. TOKEN_STATISTICS TokenStats ;
  1140. PLSAP_LOGON_SESSION LogonSession ;
  1141. PNEG_LOGON_SESSION NegLogonSession ;
  1142. LUID LogonId ;
  1143. LUID LocalServiceLuid = LOCALSERVICE_LUID;
  1144. LUID NetworkServiceLuid = NETWORKSERVICE_LUID;
  1145. LUID LocalSystemLuid = SYSTEM_LUID;
  1146. BOOL fFilterGroups;
  1147. PMSV1_0_INTERACTIVE_LOGON Authentication = NULL;
  1148. DWORD Size ;
  1149. ULONG i ;
  1150. ULONG j ;
  1151. PWSTR AltName, AltNameScan ;
  1152. Status = LsapImpersonateClient();
  1153. if ( !NT_SUCCESS( Status ) )
  1154. {
  1155. return Status ;
  1156. }
  1157. //
  1158. // Open the token for the lifetime of this call. This makes sure that the
  1159. // client doesn't die on us, taking out the logon session (potentially).
  1160. //
  1161. Status = NtOpenThreadToken(
  1162. NtCurrentThread(),
  1163. TOKEN_QUERY,
  1164. TRUE,
  1165. &hToken );
  1166. RevertToSelf();
  1167. if ( !NT_SUCCESS( Status ) )
  1168. {
  1169. return Status ;
  1170. }
  1171. //
  1172. // Grovel the token, and build up a list of groups that we will use for
  1173. // the new token. Only non-builtin groups will be used.
  1174. //
  1175. TokenInfo = (PLSA_TOKEN_INFORMATION_V1) LsapAllocateLsaHeap(
  1176. sizeof( LSA_TOKEN_INFORMATION_V1) );
  1177. if ( !TokenInfo )
  1178. {
  1179. Status = STATUS_NO_MEMORY ;
  1180. goto Clone_Exit ;
  1181. }
  1182. Status = NtQueryInformationToken(
  1183. hToken,
  1184. TokenStatistics,
  1185. &TokenStats,
  1186. sizeof( TokenStats ),
  1187. &Size );
  1188. if ( !NT_SUCCESS( Status ) )
  1189. {
  1190. goto Clone_Exit ;
  1191. }
  1192. TokenInfo->ExpirationTime = TokenStats.ExpirationTime ;
  1193. User = (PTOKEN_USER) SmallBuffer ;
  1194. Size = sizeof( SmallBuffer );
  1195. Status = NtQueryInformationToken(
  1196. hToken,
  1197. TokenUser,
  1198. User,
  1199. Size,
  1200. &Size );
  1201. if ( ( Status == STATUS_BUFFER_OVERFLOW ) ||
  1202. ( Status == STATUS_BUFFER_TOO_SMALL ) )
  1203. {
  1204. User = (PTOKEN_USER) LsapAllocatePrivateHeap( Size );
  1205. if ( User )
  1206. {
  1207. Status = NtQueryInformationToken(
  1208. hToken,
  1209. TokenUser,
  1210. User,
  1211. Size,
  1212. &Size );
  1213. }
  1214. else
  1215. {
  1216. Status = STATUS_NO_MEMORY ;
  1217. }
  1218. }
  1219. if ( !NT_SUCCESS( Status ) )
  1220. {
  1221. goto Clone_Exit ;
  1222. }
  1223. TokenInfo->User.User.Attributes = 0 ;
  1224. TokenInfo->User.User.Sid = LsapAllocateLsaHeap( RtlLengthSid( User->User.Sid ) );
  1225. if ( TokenInfo->User.User.Sid )
  1226. {
  1227. RtlCopyMemory( TokenInfo->User.User.Sid,
  1228. User->User.Sid,
  1229. RtlLengthSid( User->User.Sid ) );
  1230. }
  1231. else
  1232. {
  1233. Status = STATUS_NO_MEMORY ;
  1234. goto Clone_Exit ;
  1235. }
  1236. if ( User != (PTOKEN_USER) SmallBuffer )
  1237. {
  1238. LsapFreePrivateHeap( User );
  1239. }
  1240. User = NULL ;
  1241. Status = NtQueryInformationToken(
  1242. hToken,
  1243. TokenGroups,
  1244. NULL,
  1245. 0,
  1246. &Size );
  1247. if ( ( Status != STATUS_BUFFER_OVERFLOW ) &&
  1248. ( Status != STATUS_BUFFER_TOO_SMALL ) )
  1249. {
  1250. goto Clone_Exit ;
  1251. }
  1252. Groups = (PTOKEN_GROUPS) LsapAllocatePrivateHeap( Size );
  1253. if ( !Groups )
  1254. {
  1255. Status = STATUS_NO_MEMORY ;
  1256. goto Clone_Exit ;
  1257. }
  1258. Status = NtQueryInformationToken(
  1259. hToken,
  1260. TokenGroups,
  1261. Groups,
  1262. Size,
  1263. &Size );
  1264. if ( !NT_SUCCESS( Status ) )
  1265. {
  1266. goto Clone_Exit ;
  1267. }
  1268. //
  1269. // Grovel through the group list, and ditch those we don't care about.
  1270. // i always travels ahead of j. Skip groups that have one or two RIDs,
  1271. // because those are the builtin ones.
  1272. //
  1273. FinalGroups = (PTOKEN_GROUPS) LsapAllocatePrivateHeap( sizeof( TOKEN_GROUPS ) +
  1274. Groups->GroupCount * sizeof( SID_AND_ATTRIBUTES ) );
  1275. if ( !FinalGroups )
  1276. {
  1277. goto Clone_Exit ;
  1278. }
  1279. //
  1280. // Don't filter out groups for tokens where the LSA has hardcoded info on
  1281. // how to build the token. If we filter in those cases, we strip out SIDs
  1282. // that won't be replaced by the LSA policy/filter routines later on.
  1283. //
  1284. fFilterGroups = !RtlEqualLuid(&TokenStats.AuthenticationId, &LocalSystemLuid) &&
  1285. !RtlEqualLuid(&TokenStats.AuthenticationId, &LocalServiceLuid) &&
  1286. !RtlEqualLuid(&TokenStats.AuthenticationId, &NetworkServiceLuid);
  1287. for ( i = 0, j = 0 ; i < Groups->GroupCount ; i++ )
  1288. {
  1289. if ( !fFilterGroups || *RtlSubAuthorityCountSid( Groups->Groups[ i ].Sid ) > 2 )
  1290. {
  1291. FinalGroups->Groups[ j ].Attributes = Groups->Groups[ i ].Attributes ;
  1292. Status = LsapDuplicateSid2( &FinalGroups->Groups[ j ].Sid,
  1293. Groups->Groups[ i ].Sid );
  1294. j++ ;
  1295. if( !NT_SUCCESS(Status) )
  1296. {
  1297. break;
  1298. }
  1299. }
  1300. }
  1301. FinalGroups->GroupCount = j ;
  1302. if ( !NT_SUCCESS( Status ) )
  1303. {
  1304. goto Clone_Exit ;
  1305. }
  1306. //
  1307. // whew. Set this in the token info, and null out the other pointer
  1308. // so we don't free it inadvertantly.
  1309. //
  1310. TokenInfo->Groups = FinalGroups ;
  1311. FinalGroups = NULL ;
  1312. //
  1313. // Determine the primary group:
  1314. //
  1315. PrimaryGroup = (PTOKEN_PRIMARY_GROUP) SmallBuffer ;
  1316. Size = sizeof( SmallBuffer );
  1317. Status = NtQueryInformationToken(
  1318. hToken,
  1319. TokenPrimaryGroup,
  1320. PrimaryGroup,
  1321. Size,
  1322. &Size );
  1323. if ( ( Status == STATUS_BUFFER_OVERFLOW ) ||
  1324. ( Status == STATUS_BUFFER_TOO_SMALL ) )
  1325. {
  1326. PrimaryGroup = (PTOKEN_PRIMARY_GROUP) LsapAllocatePrivateHeap( Size );
  1327. Status = NtQueryInformationToken(
  1328. hToken,
  1329. TokenPrimaryGroup,
  1330. PrimaryGroup,
  1331. Size,
  1332. &Size );
  1333. }
  1334. if ( !NT_SUCCESS( Status ) )
  1335. {
  1336. goto Clone_Exit ;
  1337. }
  1338. TokenInfo->PrimaryGroup.PrimaryGroup = LsapAllocateLsaHeap( RtlLengthSid( PrimaryGroup->PrimaryGroup ) );
  1339. if ( TokenInfo->PrimaryGroup.PrimaryGroup )
  1340. {
  1341. RtlCopyMemory( TokenInfo->PrimaryGroup.PrimaryGroup,
  1342. PrimaryGroup->PrimaryGroup,
  1343. RtlLengthSid( PrimaryGroup->PrimaryGroup ) );
  1344. }
  1345. else
  1346. {
  1347. Status = STATUS_NO_MEMORY ;
  1348. goto Clone_Exit ;
  1349. }
  1350. if ( PrimaryGroup != (PTOKEN_PRIMARY_GROUP) SmallBuffer )
  1351. {
  1352. LsapFreePrivateHeap( PrimaryGroup );
  1353. }
  1354. PrimaryGroup = NULL ;
  1355. //
  1356. // Almost there -- now dupe the privileges
  1357. //
  1358. TokenInfo->Privileges = NULL ;
  1359. Size = 0;
  1360. Status = NtQueryInformationToken(
  1361. hToken,
  1362. TokenPrivileges,
  1363. TokenInfo->Privileges,
  1364. Size,
  1365. &Size );
  1366. if ( ( Status == STATUS_BUFFER_OVERFLOW ) ||
  1367. ( Status == STATUS_BUFFER_TOO_SMALL ) )
  1368. {
  1369. TokenInfo->Privileges = (PTOKEN_PRIVILEGES) LsapAllocateLsaHeap(Size);
  1370. if (TokenInfo->Privileges == NULL)
  1371. {
  1372. Status = STATUS_NO_MEMORY;
  1373. }
  1374. else
  1375. {
  1376. Status = NtQueryInformationToken(
  1377. hToken,
  1378. TokenPrivileges,
  1379. TokenInfo->Privileges,
  1380. Size,
  1381. &Size);
  1382. }
  1383. }
  1384. if ( !NT_SUCCESS( Status ) )
  1385. {
  1386. goto Clone_Exit;
  1387. }
  1388. //
  1389. // Ok, we have completed the Token Information. Now, we need to parse
  1390. // the supplied buffer to come up with creds for the other packages, since
  1391. // that's what this is all about
  1392. //
  1393. Status = NegpMapLogonRequest(
  1394. ProtocolSubmitBuffer,
  1395. ClientBufferBase,
  1396. SubmitBufferSize,
  1397. &Authentication );
  1398. if ( !NT_SUCCESS( Status ) )
  1399. {
  1400. goto Clone_Exit ;
  1401. }
  1402. //
  1403. // Stuff the names:
  1404. //
  1405. *AccountName = (PUNICODE_STRING) LsapAllocateLsaHeap( sizeof( UNICODE_STRING ) );
  1406. if ( ! ( *AccountName ) )
  1407. {
  1408. Status = STATUS_NO_MEMORY ;
  1409. goto Clone_Exit ;
  1410. }
  1411. *AuthenticatingAuthority = (PUNICODE_STRING) LsapAllocateLsaHeap( sizeof( UNICODE_STRING ) );
  1412. if ( ! ( *AuthenticatingAuthority ) )
  1413. {
  1414. Status = STATUS_NO_MEMORY ;
  1415. goto Clone_Exit ;
  1416. }
  1417. *MachineName = (PUNICODE_STRING) LsapAllocateLsaHeap( sizeof( UNICODE_STRING ) );
  1418. if ( ! ( *MachineName ) )
  1419. {
  1420. Status = STATUS_NO_MEMORY ;
  1421. goto Clone_Exit ;
  1422. }
  1423. //
  1424. // Tokens that the LSA normally constructs (SYSTEM, LocalService, NetworkService)
  1425. // have special names for returned as part of SID --> name lookups that don't
  1426. // necessarily match what's in the token as the account/authority names. Cruft
  1427. // up the new token with these special names instead of the standard ones.
  1428. //
  1429. if (fFilterGroups)
  1430. {
  1431. Status = LsapGetLogonSessionAccountInfo(
  1432. &TokenStats.AuthenticationId,
  1433. (*AccountName),
  1434. (*AuthenticatingAuthority) );
  1435. }
  1436. else
  1437. {
  1438. LSAP_WELL_KNOWN_SID_INDEX dwIndex = LsapLocalSystemSidIndex;
  1439. if (RtlEqualLuid(&TokenStats.AuthenticationId, &LocalServiceLuid))
  1440. {
  1441. dwIndex = LsapLocalServiceSidIndex;
  1442. }
  1443. else if (RtlEqualLuid(&TokenStats.AuthenticationId, &NetworkServiceLuid))
  1444. {
  1445. dwIndex = LsapNetworkServiceSidIndex;
  1446. }
  1447. Status = LsapDuplicateString(*AccountName,
  1448. LsapDbWellKnownSidName(dwIndex));
  1449. if ( !NT_SUCCESS( Status ) )
  1450. {
  1451. goto Clone_Exit ;
  1452. }
  1453. Status = LsapDuplicateString(*AuthenticatingAuthority,
  1454. LsapDbWellKnownSidDescription(dwIndex));
  1455. }
  1456. if ( !NT_SUCCESS( Status ) )
  1457. {
  1458. goto Clone_Exit ;
  1459. }
  1460. //
  1461. // Construct the credential data to pass on to the other packages:
  1462. //
  1463. Status = LsapDuplicateString( &PrimaryCredentials->DomainName,
  1464. &Authentication->LogonDomainName );
  1465. if ( !NT_SUCCESS( Status ) )
  1466. {
  1467. goto Clone_Exit ;
  1468. }
  1469. Status = LsapDuplicateString( &PrimaryCredentials->DownlevelName,
  1470. &Authentication->UserName );
  1471. if ( !NT_SUCCESS( Status ) )
  1472. {
  1473. goto Clone_Exit ;
  1474. }
  1475. Status = LsapDuplicateString( &PrimaryCredentials->Password,
  1476. &Authentication->Password );
  1477. if ( !NT_SUCCESS( Status ) )
  1478. {
  1479. goto Clone_Exit ;
  1480. }
  1481. Status = LsapDuplicateSid( &PrimaryCredentials->UserSid,
  1482. TokenInfo->User.User.Sid );
  1483. if ( !NT_SUCCESS( Status ) )
  1484. {
  1485. goto Clone_Exit ;
  1486. }
  1487. PrimaryCredentials->Flags = PRIMARY_CRED_CLEAR_PASSWORD ;
  1488. //
  1489. // Let the LSA do the rest:
  1490. //
  1491. NtAllocateLocallyUniqueId( &LogonId );
  1492. Status = LsapCreateLogonSession( &LogonId );
  1493. if ( !NT_SUCCESS( Status ) )
  1494. {
  1495. goto Clone_Exit ;
  1496. }
  1497. NegLogonSession = NegpBuildLogonSession( &LogonId,
  1498. NegPackageId,
  1499. NegPackageId );
  1500. if ( !NegLogonSession )
  1501. {
  1502. Status = STATUS_NO_MEMORY ;
  1503. goto Clone_Exit;
  1504. }
  1505. AltName = (PWSTR) LsapAllocatePrivateHeap( Authentication->UserName.Length +
  1506. Authentication->LogonDomainName.Length +
  1507. 2 * sizeof( WCHAR ) );
  1508. if ( AltName )
  1509. {
  1510. AltNameScan = AltName ;
  1511. RtlCopyMemory( AltNameScan,
  1512. Authentication->LogonDomainName.Buffer,
  1513. Authentication->LogonDomainName.Length );
  1514. AltNameScan += Authentication->LogonDomainName.Length / sizeof(WCHAR) ;
  1515. *AltNameScan++ = L'\\';
  1516. RtlCopyMemory( AltNameScan,
  1517. Authentication->UserName.Buffer,
  1518. Authentication->UserName.Length );
  1519. AltNameScan += Authentication->UserName.Length / sizeof( WCHAR ) ;
  1520. *AltNameScan++ = L'\0';
  1521. RtlInitUnicodeString( &NegLogonSession->AlternateName, AltName );
  1522. }
  1523. NegLogonSession->ParentLogonId = TokenStats.AuthenticationId ;
  1524. NegpDerefLogonSession( NegLogonSession );
  1525. PrimaryCredentials->LogonId = LogonId ;
  1526. *ProfileBuffer = NULL ;
  1527. *ProfileBufferLength = 0 ;
  1528. *NewLogonId = LogonId ;
  1529. *ApiSubStatus = STATUS_SUCCESS ;
  1530. *TokenInformationType = LsaTokenInformationV1 ;
  1531. *TokenInformation = TokenInfo ;
  1532. TokenInfo = NULL ;
  1533. *CachedCredentials = NULL ;
  1534. Clone_Exit:
  1535. if ( Groups )
  1536. {
  1537. LsapFreePrivateHeap( Groups );
  1538. }
  1539. if ( FinalGroups )
  1540. {
  1541. LsapFreeTokenGroups( FinalGroups );
  1542. }
  1543. if ( TokenInfo )
  1544. {
  1545. if ( TokenInfo->User.User.Sid )
  1546. {
  1547. LsapFreeLsaHeap( TokenInfo->User.User.Sid );
  1548. }
  1549. if ( TokenInfo->Groups )
  1550. {
  1551. LsapFreeTokenGroups( TokenInfo->Groups );
  1552. }
  1553. if ( TokenInfo->Privileges )
  1554. {
  1555. LsapFreeLsaHeap( TokenInfo->Privileges );
  1556. }
  1557. LsapFreeLsaHeap( TokenInfo );
  1558. }
  1559. if ( (User != NULL) &&
  1560. (User != (PTOKEN_USER) SmallBuffer ) )
  1561. {
  1562. LsapFreePrivateHeap( User );
  1563. }
  1564. if ( hToken != NULL )
  1565. {
  1566. NtClose( hToken );
  1567. }
  1568. if ( !NT_SUCCESS( Status ) )
  1569. {
  1570. if ( *AuthenticatingAuthority )
  1571. {
  1572. if ( (*AuthenticatingAuthority)->Buffer )
  1573. {
  1574. LsapFreeLsaHeap( (*AuthenticatingAuthority)->Buffer );
  1575. }
  1576. LsapFreeLsaHeap( *AuthenticatingAuthority );
  1577. *AuthenticatingAuthority = NULL;
  1578. }
  1579. if ( *AccountName )
  1580. {
  1581. if ( (*AccountName)->Buffer )
  1582. {
  1583. LsapFreeLsaHeap( (*AccountName)->Buffer );
  1584. }
  1585. LsapFreeLsaHeap( *AccountName );
  1586. *AccountName = NULL;
  1587. }
  1588. if ( *MachineName )
  1589. {
  1590. if ( (*MachineName)->Buffer )
  1591. {
  1592. LsapFreeLsaHeap( (*MachineName)->Buffer );
  1593. }
  1594. LsapFreeLsaHeap( *MachineName );
  1595. *MachineName = NULL;
  1596. }
  1597. }
  1598. return Status ;
  1599. }
  1600. //+-------------------------------------------------------------------------
  1601. //
  1602. // Function: NegLogonUserEx2
  1603. //
  1604. // Synopsis: Handles service, batch, and interactive logons
  1605. //
  1606. // Effects:
  1607. //
  1608. // Arguments:
  1609. //
  1610. // Requires:
  1611. //
  1612. // Returns:
  1613. //
  1614. // Notes:
  1615. //
  1616. //
  1617. //--------------------------------------------------------------------------
  1618. NTSTATUS
  1619. NTAPI
  1620. NegLogonUserEx2(
  1621. IN PLSA_CLIENT_REQUEST ClientRequest,
  1622. IN SECURITY_LOGON_TYPE LogonType,
  1623. IN PVOID ProtocolSubmitBuffer,
  1624. IN PVOID ClientBufferBase,
  1625. IN ULONG SubmitBufferSize,
  1626. OUT PVOID *ProfileBuffer,
  1627. OUT PULONG ProfileBufferLength,
  1628. OUT PLUID NewLogonId,
  1629. OUT PNTSTATUS ApiSubStatus,
  1630. OUT PLSA_TOKEN_INFORMATION_TYPE TokenInformationType,
  1631. OUT PVOID *TokenInformation,
  1632. OUT PUNICODE_STRING *AccountName,
  1633. OUT PUNICODE_STRING *AuthenticatingAuthority,
  1634. OUT PUNICODE_STRING *MachineName,
  1635. OUT PSECPKG_PRIMARY_CRED PrimaryCredentials,
  1636. OUT PSECPKG_SUPPLEMENTAL_CRED_ARRAY * CachedCredentials
  1637. )
  1638. {
  1639. NTSTATUS Status = STATUS_NO_LOGON_SERVERS;
  1640. PNEG_PACKAGE Package;
  1641. PVOID LocalSubmitBuffer = NULL;
  1642. ULONG_PTR CurrentPackageId = GetCurrentPackageId();
  1643. PLSAP_SECURITY_PACKAGE * LogonPackages = NULL;
  1644. PNEG_LOGON_SESSION LogonSession ;
  1645. PWSTR AltName, AltNameScan ;
  1646. NEG_DOMAIN_TYPES DomainType ;
  1647. ULONG LogonPackageCount = 0;
  1648. ULONG Index;
  1649. if ( LogonType == NewCredentials )
  1650. {
  1651. return NegpCloneLogonSession(
  1652. ProtocolSubmitBuffer,
  1653. ClientBufferBase,
  1654. SubmitBufferSize,
  1655. ProfileBuffer,
  1656. ProfileBufferLength,
  1657. NewLogonId,
  1658. ApiSubStatus,
  1659. TokenInformationType,
  1660. TokenInformation,
  1661. AccountName,
  1662. AuthenticatingAuthority,
  1663. MachineName,
  1664. PrimaryCredentials,
  1665. CachedCredentials
  1666. );
  1667. }
  1668. //
  1669. // Allocate a local copy of the submit buffer so each package can
  1670. // mark it up.
  1671. //
  1672. LocalSubmitBuffer = LsapAllocateLsaHeap(SubmitBufferSize);
  1673. if (LocalSubmitBuffer == NULL)
  1674. {
  1675. return(STATUS_INSUFFICIENT_RESOURCES);
  1676. }
  1677. if ( LogonType == Service )
  1678. {
  1679. ULONG ulAccountId;
  1680. //
  1681. // Copy the submit buffer for the package to mark up
  1682. //
  1683. RtlCopyMemory(
  1684. LocalSubmitBuffer,
  1685. ProtocolSubmitBuffer,
  1686. SubmitBufferSize
  1687. );
  1688. if (NegpIsLocalOrNetworkService(
  1689. LocalSubmitBuffer,
  1690. ClientBufferBase,
  1691. SubmitBufferSize,
  1692. AccountName,
  1693. AuthenticatingAuthority,
  1694. MachineName,
  1695. &ulAccountId))
  1696. {
  1697. Status = NegpMakeServiceToken(
  1698. ulAccountId,
  1699. NewLogonId,
  1700. ProfileBuffer,
  1701. ProfileBufferLength,
  1702. ApiSubStatus,
  1703. TokenInformationType,
  1704. TokenInformation,
  1705. AccountName,
  1706. AuthenticatingAuthority,
  1707. MachineName,
  1708. PrimaryCredentials,
  1709. CachedCredentials
  1710. );
  1711. goto Cleanup;
  1712. }
  1713. }
  1714. LogonPackages = (PLSAP_SECURITY_PACKAGE *) LsapAllocateLsaHeap( NegPackageCount * sizeof(PLSAP_SECURITY_PACKAGE));
  1715. if (LogonPackages == NULL)
  1716. {
  1717. Status = STATUS_INSUFFICIENT_RESOURCES;
  1718. goto Cleanup;
  1719. }
  1720. NegReadLockList();
  1721. Package = (PNEG_PACKAGE) NegPackageList.Flink ;
  1722. while ( (PVOID) Package != (PVOID) &NegPackageList )
  1723. {
  1724. if (((Package->LsaPackage->fCapabilities & SECPKG_FLAG_LOGON) != 0) &&
  1725. ((Package->Flags & NEG_PACKAGE_EXTRA_OID ) == 0 ) &&
  1726. (Package->LsaPackage->FunctionTable.LogonUserEx2 != NULL))
  1727. {
  1728. LogonPackages[LogonPackageCount++] = Package->LsaPackage;
  1729. }
  1730. Package = (PNEG_PACKAGE) Package->List.Flink ;
  1731. }
  1732. NegUnlockList();
  1733. for (Index = 0; Index < LogonPackageCount; Index++)
  1734. {
  1735. //
  1736. // Cleanup the old audit strings so they don't get leaked
  1737. // when the package re-allocates them.
  1738. //
  1739. if ((*MachineName) != NULL) {
  1740. if ((*MachineName)->Buffer != NULL) {
  1741. LsapFreeLsaHeap( (*MachineName)->Buffer );
  1742. }
  1743. LsapFreeLsaHeap( (*MachineName) );
  1744. (*MachineName) = NULL;
  1745. }
  1746. if ((*AccountName) != NULL) {
  1747. if ((*AccountName)->Buffer != NULL) {
  1748. LsapFreeLsaHeap( (*AccountName)->Buffer );
  1749. }
  1750. LsapFreeLsaHeap( (*AccountName) );
  1751. (*AccountName) = NULL ;
  1752. }
  1753. if ((*AuthenticatingAuthority) != NULL) {
  1754. if ((*AuthenticatingAuthority)->Buffer != NULL) {
  1755. LsapFreeLsaHeap( (*AuthenticatingAuthority)->Buffer );
  1756. }
  1757. LsapFreeLsaHeap( (*AuthenticatingAuthority) );
  1758. (*AuthenticatingAuthority) = NULL ;
  1759. }
  1760. //
  1761. // Copy the submit buffer for the package to mark up
  1762. //
  1763. RtlCopyMemory(
  1764. LocalSubmitBuffer,
  1765. ProtocolSubmitBuffer,
  1766. SubmitBufferSize
  1767. );
  1768. SetCurrentPackageId(LogonPackages[Index]->dwPackageID);
  1769. Status = LogonPackages[Index]->FunctionTable.LogonUserEx2(
  1770. ClientRequest,
  1771. LogonType,
  1772. LocalSubmitBuffer,
  1773. ClientBufferBase,
  1774. SubmitBufferSize,
  1775. ProfileBuffer,
  1776. ProfileBufferLength,
  1777. NewLogonId,
  1778. ApiSubStatus,
  1779. TokenInformationType,
  1780. TokenInformation,
  1781. AccountName,
  1782. AuthenticatingAuthority,
  1783. MachineName,
  1784. PrimaryCredentials,
  1785. CachedCredentials
  1786. );
  1787. SetCurrentPackageId(CurrentPackageId);
  1788. //
  1789. // Bug 226401 If the local machine secret is different from the
  1790. // machine account password, kerberos can't decrpyt the workstation
  1791. // ticket and returns STATUS_TRUSTED_RELATIONSHIP_FAILURE (used to
  1792. // return STATUS_TRUST_FAILURE). If this is a DC, we
  1793. // should fall back to NTLM.
  1794. //
  1795. if (Status == STATUS_TRUST_FAILURE ||
  1796. Status == STATUS_TRUSTED_RELATIONSHIP_FAILURE)
  1797. {
  1798. if (NegMachineState & SECPKG_STATE_DOMAIN_CONTROLLER)
  1799. {
  1800. Status = STATUS_NO_LOGON_SERVERS;
  1801. }
  1802. }
  1803. if ((Status != STATUS_NO_LOGON_SERVERS) &&
  1804. (Status != STATUS_NETLOGON_NOT_STARTED) &&
  1805. (Status != SEC_E_NO_AUTHENTICATING_AUTHORITY) &&
  1806. (Status != SEC_E_ETYPE_NOT_SUPP) &&
  1807. (Status != STATUS_KDC_UNKNOWN_ETYPE) &&
  1808. (Status != STATUS_NO_TRUST_SAM_ACCOUNT) &&
  1809. (Status != STATUS_INVALID_PARAMETER) &&
  1810. (Status != STATUS_INVALID_LOGON_TYPE) &&
  1811. (Status != STATUS_INVALID_INFO_CLASS ) &&
  1812. (Status != STATUS_NETWORK_UNREACHABLE) &&
  1813. (Status != STATUS_BAD_VALIDATION_CLASS) )
  1814. {
  1815. break;
  1816. }
  1817. }
  1818. if ( NT_SUCCESS( Status ) )
  1819. {
  1820. LogonSession = NegpBuildLogonSession(
  1821. NewLogonId,
  1822. LogonPackages[ Index ]->dwPackageID,
  1823. LogonPackages[ Index ]->dwPackageID );
  1824. if ( LogonSession )
  1825. {
  1826. if ( LogonPackages[ Index ]->dwRPCID == NTLMSP_RPCID )
  1827. {
  1828. DebugLog(( DEB_TRACE_NEG, "NTLM Logon\n" ));
  1829. //
  1830. // Check if this is an uplevel or downlevel domain
  1831. //
  1832. DomainType = NegpIsUplevelDomain( NewLogonId, LogonType, *AuthenticatingAuthority );
  1833. if( DomainType == NegLocalDomain )
  1834. {
  1835. //
  1836. // change from Win2k:
  1837. // allow full negotiation range by default for local logons.
  1838. // Kerberos now quickly fails local account originated operations.
  1839. //
  1840. LogonSession->DefaultPackage = NegPackageId ;
  1841. }
  1842. if ( DomainType == NegUpLevelDomain )
  1843. {
  1844. if( (LogonType == CachedInteractive) &&
  1845. ((PrimaryCredentials->Flags >> PRIMARY_CRED_LOGON_PACKAGE_SHIFT) == NTLMSP_RPCID)
  1846. )
  1847. {
  1848. //
  1849. // leave the package as NTLM.
  1850. //
  1851. } else {
  1852. LogonSession->DefaultPackage = NEG_INVALID_PACKAGE ;
  1853. }
  1854. }
  1855. else if ( DomainType == NegUpLevelTrustedDomain )
  1856. {
  1857. LogonSession->DefaultPackage = NegPackageId ;
  1858. }
  1859. else
  1860. {
  1861. //
  1862. // leave the DefaultPackage as NTLM.
  1863. //
  1864. NOTHING;
  1865. }
  1866. }
  1867. //
  1868. // Create the name:
  1869. //
  1870. AltName = (PWSTR) LsapAllocatePrivateHeap(
  1871. (*AccountName)->Length +
  1872. (*AuthenticatingAuthority)->Length +
  1873. 2 * sizeof( WCHAR ) );
  1874. if ( AltName )
  1875. {
  1876. AltNameScan = AltName ;
  1877. RtlCopyMemory( AltNameScan,
  1878. (*AuthenticatingAuthority)->Buffer,
  1879. (*AuthenticatingAuthority)->Length );
  1880. AltNameScan += (*AuthenticatingAuthority)->Length / sizeof(WCHAR) ;
  1881. *AltNameScan++ = L'\\';
  1882. RtlCopyMemory( AltNameScan,
  1883. (*AccountName)->Buffer,
  1884. (*AccountName)->Length );
  1885. AltNameScan += (*AccountName)->Length / sizeof( WCHAR ) ;
  1886. *AltNameScan++ = L'\0';
  1887. RtlInitUnicodeString( &LogonSession->AlternateName, AltName );
  1888. }
  1889. NegpDerefLogonSession( LogonSession );
  1890. }
  1891. }
  1892. Cleanup:
  1893. if( LogonPackages )
  1894. {
  1895. LsapFreeLsaHeap(LogonPackages);
  1896. }
  1897. if( LocalSubmitBuffer )
  1898. {
  1899. ZeroMemory(LocalSubmitBuffer, SubmitBufferSize);
  1900. LsapFreeLsaHeap(LocalSubmitBuffer);
  1901. }
  1902. return(Status);
  1903. }
  1904. //+-------------------------------------------------------------------------
  1905. //
  1906. // Function: NegpMakeServiceToken
  1907. //
  1908. // Synopsis: Handles the logon for LocalService and NetworkService
  1909. //
  1910. // Effects:
  1911. //
  1912. // Arguments:
  1913. //
  1914. // Requires:
  1915. //
  1916. // Returns:
  1917. //
  1918. // Notes: On error, this routine frees the buffers allocated by
  1919. // the prior call to NegpIsLocalOrNetworkService
  1920. //
  1921. //--------------------------------------------------------------------------
  1922. NTSTATUS
  1923. NegpMakeServiceToken(
  1924. IN ULONG ulAccountId,
  1925. OUT PLUID pLogonId,
  1926. OUT PVOID *ProfileBuffer,
  1927. OUT PULONG ProfileBufferLength,
  1928. OUT PNTSTATUS ApiSubStatus,
  1929. OUT PLSA_TOKEN_INFORMATION_TYPE TokenInformationType,
  1930. OUT PVOID *TokenInformation,
  1931. OUT PUNICODE_STRING *AccountName,
  1932. OUT PUNICODE_STRING *AuthenticatingAuthority,
  1933. OUT PUNICODE_STRING *MachineName,
  1934. OUT PSECPKG_PRIMARY_CRED PrimaryCredentials,
  1935. OUT PSECPKG_SUPPLEMENTAL_CRED_ARRAY * CachedCredentials
  1936. )
  1937. {
  1938. NTSTATUS Status;
  1939. LPBYTE pBuffer;
  1940. ULONG ulTokenLength;
  1941. PSID Owner;
  1942. PSID UserSid;
  1943. ULONG DaclLength;
  1944. PACL pDacl;
  1945. DWORD dwSidLen;
  1946. HMODULE hStringsResource;
  1947. LUID SystemId = SYSTEM_LUID;
  1948. PTOKEN_GROUPS pGroups;
  1949. PSID_AND_ATTRIBUTES pSidAndAttrs;
  1950. ULONG NormalGroupAttributes;
  1951. TIME_FIELDS TimeFields;
  1952. SECPKG_CLIENT_INFO ClientInfo;
  1953. SID_IDENTIFIER_AUTHORITY IdentifierAuthority = SECURITY_NT_AUTHORITY;
  1954. PLSA_TOKEN_INFORMATION_V2 pTokenInfo = NULL;
  1955. PLSAP_LOGON_SESSION pLogonSession = NULL;
  1956. //
  1957. // Don't allow untrusted clients to call this API.
  1958. //
  1959. Status = LsapGetClientInfo(&ClientInfo);
  1960. if (!NT_SUCCESS(Status))
  1961. {
  1962. goto ErrorExit;
  1963. }
  1964. if (!RtlEqualLuid(&ClientInfo.LogonId, &SystemId))
  1965. {
  1966. Status = STATUS_ACCESS_DENIED;
  1967. goto ErrorExit;
  1968. }
  1969. if (ulAccountId == LSAP_SID_NAME_LOCALSERVICE)
  1970. {
  1971. LUID LocalServiceId = LOCALSERVICE_LUID;
  1972. UNICODE_STRING EmptyString = {0, 0, NULL};
  1973. UserSid = LsapLocalServiceSid;
  1974. PrimaryCredentials->LogonId = LocalServiceId;
  1975. *pLogonId = LocalServiceId;
  1976. Status = LsapDuplicateSid(&PrimaryCredentials->UserSid,
  1977. UserSid);
  1978. if (!NT_SUCCESS(Status))
  1979. {
  1980. goto ErrorExit;
  1981. }
  1982. Status = LsapDuplicateString(&PrimaryCredentials->DomainName,
  1983. &EmptyString);
  1984. if (!NT_SUCCESS(Status))
  1985. {
  1986. goto ErrorExit;
  1987. }
  1988. Status = LsapDuplicateString(&PrimaryCredentials->DownlevelName,
  1989. &EmptyString);
  1990. if (!NT_SUCCESS(Status))
  1991. {
  1992. goto ErrorExit;
  1993. }
  1994. Status = LsapDuplicateString(&PrimaryCredentials->Password,
  1995. &EmptyString);
  1996. if (!NT_SUCCESS(Status))
  1997. {
  1998. goto ErrorExit;
  1999. }
  2000. }
  2001. else
  2002. {
  2003. LUID NetworkServiceId = NETWORKSERVICE_LUID;
  2004. ASSERT( ulAccountId == LSAP_SID_NAME_NETWORKSERVICE );
  2005. UserSid = LsapNetworkServiceSid;
  2006. Status = NegpCopyCredsToBuffer(&NegPrimarySystemCredentials,
  2007. NULL,
  2008. PrimaryCredentials,
  2009. NULL);
  2010. if (!NT_SUCCESS(Status))
  2011. {
  2012. goto ErrorExit;
  2013. }
  2014. PrimaryCredentials->LogonId = NetworkServiceId;
  2015. *pLogonId = NetworkServiceId;
  2016. Status = LsapDuplicateSid(&PrimaryCredentials->UserSid,
  2017. UserSid);
  2018. if (!NT_SUCCESS(Status))
  2019. {
  2020. goto ErrorExit;
  2021. }
  2022. }
  2023. *CachedCredentials = NULL;
  2024. ASSERT(UserSid != NULL);
  2025. //
  2026. // Make sure there's a logon session for this account
  2027. //
  2028. pLogonSession = LsapLocateLogonSession(pLogonId);
  2029. if (pLogonSession == NULL)
  2030. {
  2031. Status = LsapCreateLogonSession(pLogonId);
  2032. pLogonSession = LsapLocateLogonSession(pLogonId);
  2033. if( pLogonSession == NULL )
  2034. {
  2035. if (!NT_SUCCESS(Status))
  2036. {
  2037. goto ErrorExit;
  2038. }
  2039. ASSERT(pLogonSession != NULL);
  2040. Status = STATUS_NO_SUCH_LOGON_SESSION;
  2041. goto ErrorExit;
  2042. }
  2043. Status = STATUS_SUCCESS;
  2044. }
  2045. //
  2046. // Compute the length of the default DACL for the token
  2047. //
  2048. DaclLength = (ULONG) sizeof(ACL)
  2049. + 2 * ((ULONG) sizeof(ACCESS_ALLOWED_ACE) - sizeof(ULONG))
  2050. + RtlLengthSid( LsapLocalSystemSid )
  2051. + RtlLengthSid( UserSid );
  2052. #define NUM_TOKEN_GROUPS 4
  2053. //
  2054. // The SIDs are 4-byte aligned so this shouldn't cause problems
  2055. // with unaligned accesses (as long as the DACL stays at the
  2056. // end of the buffer).
  2057. //
  2058. ulTokenLength = sizeof(LSA_TOKEN_INFORMATION_V2)
  2059. + RtlLengthSid( UserSid ) // User
  2060. + sizeof(TOKEN_GROUPS)
  2061. + (NUM_TOKEN_GROUPS - 1) * sizeof(SID_AND_ATTRIBUTES)
  2062. + RtlLengthSid( UserSid ) // Primary group
  2063. + RtlLengthSid( LsapWorldSid ) // Groups
  2064. + RtlLengthSid( LsapAuthenticatedUserSid )
  2065. + RtlLengthSid( LsapLocalSid )
  2066. + RtlLengthSid( LsapAliasUsersSid )
  2067. + RtlLengthSid( UserSid ) // Owner
  2068. + DaclLength; // DefaultDacl
  2069. pTokenInfo = (PLSA_TOKEN_INFORMATION_V2) LsapAllocateLsaHeap(ulTokenLength);
  2070. if (pTokenInfo == NULL)
  2071. {
  2072. Status = STATUS_NO_MEMORY;
  2073. goto ErrorExit;
  2074. }
  2075. //
  2076. // Set up expiration time
  2077. //
  2078. TimeFields.Year = 3000;
  2079. TimeFields.Month = 1;
  2080. TimeFields.Day = 1;
  2081. TimeFields.Hour = 1;
  2082. TimeFields.Minute = 1;
  2083. TimeFields.Second = 1;
  2084. TimeFields.Milliseconds = 1;
  2085. TimeFields.Weekday = 1;
  2086. RtlTimeFieldsToTime( &TimeFields, &pTokenInfo->ExpirationTime );
  2087. //
  2088. // Set up the groups -- do this first so the nested pointers
  2089. // don't cause 64-bit alignment faults
  2090. //
  2091. pGroups = (PTOKEN_GROUPS) (pTokenInfo + 1);
  2092. pSidAndAttrs = pGroups->Groups;
  2093. pBuffer = (LPBYTE) (pSidAndAttrs + NUM_TOKEN_GROUPS);
  2094. pGroups->GroupCount = NUM_TOKEN_GROUPS;
  2095. #undef NUM_TOKEN_GROUPS
  2096. //
  2097. // Set up the attributes to be assigned to groups
  2098. //
  2099. NormalGroupAttributes = (SE_GROUP_MANDATORY |
  2100. SE_GROUP_ENABLED_BY_DEFAULT |
  2101. SE_GROUP_ENABLED);
  2102. dwSidLen = RtlLengthSid(LsapWorldSid);
  2103. RtlCopySid(dwSidLen, pBuffer, LsapWorldSid);
  2104. pSidAndAttrs[0].Sid = (PSID) pBuffer;
  2105. pBuffer += dwSidLen;
  2106. dwSidLen = RtlLengthSid(LsapAuthenticatedUserSid);
  2107. RtlCopySid(dwSidLen, pBuffer, LsapAuthenticatedUserSid);
  2108. pSidAndAttrs[1].Sid = (PSID) pBuffer;
  2109. pBuffer += dwSidLen;
  2110. dwSidLen = RtlLengthSid(LsapLocalSid);
  2111. RtlCopySid(dwSidLen, pBuffer, LsapLocalSid);
  2112. pSidAndAttrs[2].Sid = (PSID) pBuffer;
  2113. pBuffer += dwSidLen;
  2114. dwSidLen = RtlLengthSid(LsapAliasUsersSid);
  2115. RtlCopySid(dwSidLen, pBuffer, LsapAliasUsersSid);
  2116. pSidAndAttrs[3].Sid = (PSID) pBuffer;
  2117. pBuffer += dwSidLen;
  2118. pSidAndAttrs[0].Attributes = NormalGroupAttributes;
  2119. pSidAndAttrs[1].Attributes = NormalGroupAttributes;
  2120. pSidAndAttrs[2].Attributes = NormalGroupAttributes;
  2121. pSidAndAttrs[3].Attributes = NormalGroupAttributes;
  2122. pTokenInfo->Groups = pGroups;
  2123. //
  2124. // Set up the user ID
  2125. //
  2126. dwSidLen = RtlLengthSid(UserSid);
  2127. RtlCopySid(dwSidLen, (PSID) pBuffer, UserSid);
  2128. pTokenInfo->User.User.Sid = (PSID) pBuffer;
  2129. pTokenInfo->User.User.Attributes = 0;
  2130. pBuffer += dwSidLen;
  2131. //
  2132. // Establish the primary group
  2133. //
  2134. dwSidLen = RtlLengthSid(UserSid);
  2135. RtlCopySid(dwSidLen, (PSID) pBuffer, UserSid);
  2136. pTokenInfo->PrimaryGroup.PrimaryGroup = (PSID) pBuffer;
  2137. pBuffer += dwSidLen;
  2138. //
  2139. // Set the default owner
  2140. //
  2141. dwSidLen = RtlLengthSid(UserSid);
  2142. RtlCopySid(dwSidLen, (PSID) pBuffer, UserSid);
  2143. pTokenInfo->Owner.Owner = (PSID) pBuffer;
  2144. pBuffer += dwSidLen;
  2145. //
  2146. // Privileges -- none by default (set by policy)
  2147. //
  2148. pTokenInfo->Privileges = NULL;
  2149. //
  2150. // Set up the default DACL for token. Give system full reign of terror.
  2151. //
  2152. pDacl = (PACL) pBuffer;
  2153. Status = RtlCreateAcl(pDacl, DaclLength, ACL_REVISION2);
  2154. ASSERT( NT_SUCCESS(Status) );
  2155. Status = RtlAddAccessAllowedAce(pDacl,
  2156. ACL_REVISION2,
  2157. GENERIC_ALL,
  2158. LsapLocalSystemSid);
  2159. ASSERT( NT_SUCCESS(Status) );
  2160. Status = RtlAddAccessAllowedAce(pDacl,
  2161. ACL_REVISION2,
  2162. GENERIC_ALL,
  2163. UserSid);
  2164. ASSERT( NT_SUCCESS(Status) );
  2165. RtlCopyMemory(pBuffer, pDacl, DaclLength);
  2166. pTokenInfo->DefaultDacl.DefaultDacl = (PACL) pBuffer;
  2167. pBuffer += DaclLength;
  2168. ASSERT( (ULONG)(ULONG_PTR)(pBuffer - (LPBYTE) pTokenInfo) == ulTokenLength );
  2169. //
  2170. // Now fill in the out parameters
  2171. //
  2172. //
  2173. // LocalService/NetworkService have no profile
  2174. //
  2175. *ProfileBuffer = NULL;
  2176. *ProfileBufferLength = 0;
  2177. *TokenInformationType = LsaTokenInformationV2;
  2178. *TokenInformation = pTokenInfo;
  2179. LsapReleaseLogonSession(pLogonSession);
  2180. *ApiSubStatus = STATUS_SUCCESS;
  2181. return STATUS_SUCCESS;
  2182. ErrorExit:
  2183. if (*AuthenticatingAuthority)
  2184. {
  2185. LsapFreeLsaHeap((*AuthenticatingAuthority)->Buffer);
  2186. LsapFreeLsaHeap(*AuthenticatingAuthority);
  2187. *AuthenticatingAuthority = NULL;
  2188. }
  2189. if (*AccountName)
  2190. {
  2191. LsapFreeLsaHeap((*AccountName)->Buffer);
  2192. LsapFreeLsaHeap(*AccountName);
  2193. *AccountName = NULL;
  2194. }
  2195. if (*MachineName)
  2196. {
  2197. LsapFreeLsaHeap((*MachineName)->Buffer);
  2198. LsapFreeLsaHeap(*MachineName);
  2199. *MachineName = NULL;
  2200. }
  2201. LsapFreeLsaHeap(PrimaryCredentials->UserSid);
  2202. PrimaryCredentials->UserSid = NULL;
  2203. LsapFreeLsaHeap(PrimaryCredentials->DomainName.Buffer);
  2204. RtlZeroMemory(&PrimaryCredentials->DomainName, sizeof(UNICODE_STRING));
  2205. LsapFreeLsaHeap(PrimaryCredentials->DownlevelName.Buffer);
  2206. RtlZeroMemory(&PrimaryCredentials->DownlevelName, sizeof(UNICODE_STRING));
  2207. LsapFreeLsaHeap(PrimaryCredentials->Password.Buffer);
  2208. RtlZeroMemory(&PrimaryCredentials->Password, sizeof(UNICODE_STRING));
  2209. if (pLogonSession)
  2210. {
  2211. LsapReleaseLogonSession(pLogonSession);
  2212. }
  2213. LsapFreeLsaHeap(pTokenInfo);
  2214. *ApiSubStatus = Status;
  2215. return Status;
  2216. }
  2217. //+-------------------------------------------------------------------------
  2218. //
  2219. // Function: NegpIsLocalOrNetworkService
  2220. //
  2221. // Synopsis: Allocates memory for the account name, machine name,
  2222. // and authenticating authority for LocalService and
  2223. // NetworkService logons
  2224. //
  2225. // Effects:
  2226. //
  2227. // Arguments:
  2228. //
  2229. // Requires:
  2230. //
  2231. // Returns:
  2232. //
  2233. // Notes: The caller is responsible for freeing the allocated
  2234. // buffers if this routine succeeds
  2235. //
  2236. //--------------------------------------------------------------------------
  2237. BOOL
  2238. NegpIsLocalOrNetworkService(
  2239. IN PVOID ProtocolSubmitBuffer,
  2240. IN PVOID ClientBufferBase,
  2241. IN ULONG SubmitBufferSize,
  2242. OUT PUNICODE_STRING *AccountName,
  2243. OUT PUNICODE_STRING *AuthenticatingAuthority,
  2244. OUT PUNICODE_STRING *MachineName,
  2245. OUT PULONG pulAccountId
  2246. )
  2247. {
  2248. NTSTATUS Status;
  2249. PUNICODE_STRING pTempAccount;
  2250. PUNICODE_STRING pTempAuthority;
  2251. PMSV1_0_INTERACTIVE_LOGON Authentication = NULL;
  2252. *AccountName = NULL;
  2253. *AuthenticatingAuthority = NULL;
  2254. *MachineName = NULL;
  2255. //
  2256. // Parse the supplied buffer to come up with creds
  2257. //
  2258. Status = NegpMapLogonRequest(
  2259. ProtocolSubmitBuffer,
  2260. ClientBufferBase,
  2261. SubmitBufferSize,
  2262. &Authentication);
  2263. if (!NT_SUCCESS(Status))
  2264. {
  2265. goto ErrorExit ;
  2266. }
  2267. //
  2268. // Get the info to compare for LocalService first. Check both the
  2269. // localized version and the non-localized version (which could come
  2270. // from the registry).
  2271. //
  2272. pTempAuthority = &WellKnownSids[LsapLocalServiceSidIndex].DomainName;
  2273. pTempAccount = &WellKnownSids[LsapLocalServiceSidIndex].Name;
  2274. if (RtlCompareUnicodeString(&NTAuthorityName,
  2275. &Authentication->LogonDomainName,
  2276. TRUE) == 0)
  2277. {
  2278. //
  2279. // Hardcoded "NT AUTHORITY" -- check hardcoded
  2280. // "LocalService" and "NetworkService" and
  2281. // localize it here on a match.
  2282. //
  2283. if (RtlCompareUnicodeString(&LocalServiceName,
  2284. &Authentication->UserName,
  2285. TRUE) == 0)
  2286. {
  2287. pTempAccount = &WellKnownSids[LsapLocalServiceSidIndex].Name;
  2288. *pulAccountId = LSAP_SID_NAME_LOCALSERVICE;
  2289. Status = STATUS_SUCCESS;
  2290. }
  2291. else if (RtlCompareUnicodeString(&NetworkServiceName,
  2292. &Authentication->UserName,
  2293. TRUE) == 0)
  2294. {
  2295. pTempAccount = &WellKnownSids[LsapNetworkServiceSidIndex].Name;
  2296. *pulAccountId = LSAP_SID_NAME_NETWORKSERVICE;
  2297. Status = STATUS_SUCCESS;
  2298. }
  2299. else
  2300. {
  2301. Status = STATUS_NO_SUCH_USER;
  2302. }
  2303. }
  2304. else
  2305. {
  2306. Status = STATUS_NO_SUCH_USER;
  2307. }
  2308. //
  2309. // Hardcoded comparison failed -- try localized versions. Note that
  2310. // we have to check again (rather than using an "else" with the "if"
  2311. // above) since "NT AUTHORITY" may be both the hardcoded and the
  2312. // localized name (e.g., in English). Since Status is already a
  2313. // failure code, let the failure cases trickle through.
  2314. //
  2315. if (!NT_SUCCESS(Status))
  2316. {
  2317. if (RtlCompareUnicodeString(pTempAuthority,
  2318. &Authentication->LogonDomainName,
  2319. TRUE) == 0)
  2320. {
  2321. //
  2322. // Localized "NT AUTHORITY" -- check localized
  2323. // "LocalService" and "NetworkService"
  2324. //
  2325. pTempAccount = &WellKnownSids[LsapLocalServiceSidIndex].Name;
  2326. if (RtlCompareUnicodeString(pTempAccount,
  2327. &Authentication->UserName,
  2328. TRUE) == 0)
  2329. {
  2330. *pulAccountId = LSAP_SID_NAME_LOCALSERVICE;
  2331. Status = STATUS_SUCCESS;
  2332. }
  2333. else
  2334. {
  2335. pTempAccount = &WellKnownSids[LsapNetworkServiceSidIndex].Name;
  2336. if (RtlCompareUnicodeString(pTempAccount,
  2337. &Authentication->UserName,
  2338. TRUE) == 0)
  2339. {
  2340. *pulAccountId = LSAP_SID_NAME_NETWORKSERVICE;
  2341. Status = STATUS_SUCCESS;
  2342. }
  2343. else
  2344. {
  2345. Status = STATUS_NO_SUCH_USER;
  2346. }
  2347. }
  2348. }
  2349. else
  2350. {
  2351. Status = STATUS_NO_SUCH_USER;
  2352. }
  2353. }
  2354. if (!NT_SUCCESS(Status))
  2355. {
  2356. goto ErrorExit;
  2357. }
  2358. //
  2359. // Stuff the names:
  2360. //
  2361. *AccountName = (PUNICODE_STRING) LsapAllocateLsaHeap(sizeof(UNICODE_STRING));
  2362. if (!(*AccountName))
  2363. {
  2364. Status = STATUS_NO_MEMORY;
  2365. goto ErrorExit;
  2366. }
  2367. Status = LsapDuplicateString(*AccountName,
  2368. pTempAccount);
  2369. if (!NT_SUCCESS(Status))
  2370. {
  2371. goto ErrorExit;
  2372. }
  2373. *AuthenticatingAuthority = (PUNICODE_STRING) LsapAllocateLsaHeap(sizeof(UNICODE_STRING));
  2374. if (!(*AuthenticatingAuthority))
  2375. {
  2376. Status = STATUS_NO_MEMORY;
  2377. goto ErrorExit;
  2378. }
  2379. Status = LsapDuplicateString(*AuthenticatingAuthority,
  2380. pTempAuthority);
  2381. if (!NT_SUCCESS(Status))
  2382. {
  2383. goto ErrorExit;
  2384. }
  2385. *MachineName = (PUNICODE_STRING) LsapAllocateLsaHeap(sizeof(UNICODE_STRING));
  2386. if (!(*MachineName))
  2387. {
  2388. Status = STATUS_NO_MEMORY;
  2389. goto ErrorExit ;
  2390. }
  2391. return TRUE;
  2392. ErrorExit:
  2393. if (*AuthenticatingAuthority)
  2394. {
  2395. LsapFreeLsaHeap((*AuthenticatingAuthority)->Buffer);
  2396. LsapFreeLsaHeap(*AuthenticatingAuthority);
  2397. *AuthenticatingAuthority = NULL;
  2398. }
  2399. if (*AccountName)
  2400. {
  2401. LsapFreeLsaHeap((*AccountName)->Buffer);
  2402. LsapFreeLsaHeap(*AccountName);
  2403. *AccountName = NULL;
  2404. }
  2405. if (*MachineName)
  2406. {
  2407. LsapFreeLsaHeap((*MachineName)->Buffer);
  2408. LsapFreeLsaHeap(*MachineName);
  2409. *MachineName = NULL;
  2410. }
  2411. return FALSE;
  2412. }
  2413. BOOL
  2414. NegpRearrangeMechsIfNeccessary(
  2415. struct MechTypeList ** RealMechList,
  2416. PSECURITY_STRING Target,
  2417. PBOOL DirectPacket
  2418. )
  2419. {
  2420. PWSTR FirstSlash ;
  2421. PWSTR SecondSlash = NULL;
  2422. PNEG_TRUST_LIST TrustList = NULL ;
  2423. UNICODE_STRING TargetHost ;
  2424. UNICODE_STRING SpnPrefix;
  2425. UNICODE_STRING HttpPrefix;
  2426. struct MechTypeList * MechList ;
  2427. struct MechTypeList * Reorder = NULL ;
  2428. struct MechTypeList * Trailer ;
  2429. BOOL Rearranged = FALSE ;
  2430. BOOL HttpSpn = FALSE;
  2431. if ( Target == NULL )
  2432. {
  2433. DebugLog(( DEB_TRACE_NEG, "Loopback detected for local target (no targetname)\n"));
  2434. goto loopback;
  2435. }
  2436. if ( Target->Length == 0 )
  2437. {
  2438. DebugLog(( DEB_TRACE_NEG, "Loopback detected for local target (no targetname)\n"));
  2439. goto loopback;
  2440. }
  2441. //
  2442. // Now, examine the target and determine if it is referring to us
  2443. //
  2444. FirstSlash = wcschr( Target->Buffer, L'/' );
  2445. if ( !FirstSlash )
  2446. {
  2447. //
  2448. // Not an SPN, we're out of here
  2449. //
  2450. return FALSE ;
  2451. } else {
  2452. *FirstSlash = L'\0';
  2453. }
  2454. //
  2455. // HACK HACK HACK: We've got to call NTLM directly in
  2456. // the loopback case, or Wininet can't handle our "extra" nego trips....
  2457. //
  2458. RtlInitUnicodeString(
  2459. &SpnPrefix,
  2460. Target->Buffer
  2461. );
  2462. RtlInitUnicodeString(
  2463. &HttpPrefix,
  2464. L"HTTP"
  2465. );
  2466. if (RtlEqualUnicodeString(
  2467. &SpnPrefix,
  2468. &HttpPrefix,
  2469. TRUE
  2470. ))
  2471. {
  2472. HttpSpn = TRUE;
  2473. DebugLog((DEB_TRACE_NEG, "Found HTTP SPN, about to force NTLM directly\n"));
  2474. }
  2475. *FirstSlash = L'/';
  2476. // END HACK END HACK
  2477. FirstSlash++ ;
  2478. //
  2479. // if this is a svc/instance/domain style SPN, ignore the trailer
  2480. // portion
  2481. //
  2482. SecondSlash = wcschr( Target->Buffer, L'/' );
  2483. if ( SecondSlash )
  2484. {
  2485. *SecondSlash = L'\0';
  2486. }
  2487. RtlInitUnicodeString( &TargetHost, FirstSlash );
  2488. NegReadLockComputerNames();
  2489. if (!RtlEqualUnicodeString( &TargetHost, &NegDnsComputerName_U, TRUE ) &&
  2490. !RtlEqualUnicodeString( &TargetHost, &NegNetbiosComputerName_U, TRUE ) &&
  2491. !RtlEqualUnicodeString( &TargetHost, &NegLocalHostName_U, TRUE ) )
  2492. {
  2493. NegUnlockComputerNames();
  2494. goto Cleanup ;
  2495. }
  2496. NegUnlockComputerNames();
  2497. //
  2498. // We have a loopback condition. The target we are going to is our own host
  2499. // name. So, scan through the mech list, and find the NTLM mech (if present)
  2500. // and bump it up.
  2501. //
  2502. #if DBG
  2503. if ( SecondSlash )
  2504. {
  2505. //
  2506. // for debug builds, reset the string now for the dump message, so that
  2507. // we can make sure the right targets are being caught. Free builds will
  2508. // reset this at the cleanup stage.
  2509. //
  2510. *SecondSlash = L'/';
  2511. SecondSlash = NULL ;
  2512. }
  2513. #endif
  2514. DebugLog(( DEB_TRACE_NEG, "Loopback detected for target %ws\n", Target->Buffer ));
  2515. loopback:
  2516. MechList = *RealMechList ;
  2517. Trailer = NULL ;
  2518. while ( MechList )
  2519. {
  2520. if ( (MechList->value != NULL) &&
  2521. (NegpCompareOid( MechList->value, NegNtlmMechOid ) == 0)
  2522. )
  2523. {
  2524. //
  2525. // Found NTLM. Unlink it and put it at the head of the new list
  2526. //
  2527. Reorder = MechList ;
  2528. if ( Trailer )
  2529. {
  2530. Trailer->next = MechList->next ;
  2531. }
  2532. else
  2533. {
  2534. // update original pointer
  2535. *RealMechList = MechList->next ;
  2536. }
  2537. MechList = MechList->next ;
  2538. Reorder->next = NULL ;
  2539. }
  2540. else
  2541. {
  2542. Trailer = MechList ;
  2543. MechList = MechList->next ;
  2544. }
  2545. }
  2546. //
  2547. // Reorder points to the NTLM element, if there are NTLM creds. If not, this is NULL.
  2548. // Now, append the rest of the list
  2549. //
  2550. if ( Reorder )
  2551. {
  2552. Reorder->next = *RealMechList ;
  2553. *RealMechList = Reorder ;
  2554. Rearranged = TRUE ;
  2555. }
  2556. // Only set this if everything else went well
  2557. // HACK PART 2
  2558. *DirectPacket = HttpSpn;
  2559. Cleanup:
  2560. if ( SecondSlash )
  2561. {
  2562. *SecondSlash = L'/';
  2563. }
  2564. return Rearranged ;
  2565. }