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.

3422 lines
93 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1993.
  5. //
  6. // File: logon32.c
  7. //
  8. // Contents:
  9. //
  10. // Classes:
  11. //
  12. // Functions:
  13. //
  14. // History: 9-30-94 RichardW Created
  15. //
  16. //----------------------------------------------------------------------------
  17. #include "advapi.h"
  18. #include <crypt.h>
  19. #include <mpr.h>
  20. #include <ntlsa.h>
  21. #include <ntmsv1_0.h>
  22. #include <wchar.h>
  23. #include <stdlib.h>
  24. #include <lmcons.h>
  25. #define SECURITY_WIN32
  26. #include <security.h>
  27. #include <windows.h>
  28. #include <winbase.h>
  29. #include <winbasep.h>
  30. #include <execsrv.h>
  31. //
  32. // We dynamically load mpr.dll (no big surprise there), in order to call
  33. // WNetLogonNotify, as defined in private\inc\mpr.h. This prototype matches
  34. // it -- consult the header file for all the parameters.
  35. //
  36. typedef (* LOGONNOTIFYFN)(LPCWSTR, PLUID, LPCWSTR, LPVOID,
  37. LPCWSTR, LPVOID, LPWSTR, LPVOID, LPWSTR *);
  38. //
  39. // The QuotaLimits are global, because the defaults
  40. // are always used for accounts, based on server/wksta, and no one ever
  41. // calls lsasetaccountquota
  42. //
  43. HANDLE Logon32LsaHandle = NULL;
  44. ULONG Logon32MsvHandle = 0xFFFFFFFF;
  45. ULONG Logon32NegoHandle = 0xFFFFFFFF;
  46. WCHAR Logon32DomainName[DNLEN+1] = L"";
  47. QUOTA_LIMITS Logon32QuotaLimits;
  48. HINSTANCE Logon32MprHandle = NULL;
  49. LOGONNOTIFYFN Logon32LogonNotify = NULL;
  50. RTL_CRITICAL_SECTION Logon32Lock;
  51. #define LockLogon() RtlEnterCriticalSection( &Logon32Lock )
  52. #define UnlockLogon() RtlLeaveCriticalSection( &Logon32Lock )
  53. SID_IDENTIFIER_AUTHORITY L32SystemSidAuthority = SECURITY_NT_AUTHORITY;
  54. SID_IDENTIFIER_AUTHORITY L32LocalSidAuthority = SECURITY_LOCAL_SID_AUTHORITY;
  55. #define COMMON_CREATE_SUSPENDED 0x00000001 // Suspended, do not Resume()
  56. #define COMMON_CREATE_PROCESSSD 0x00000002 // Whack the process SD
  57. #define COMMON_CREATE_THREADSD 0x00000004 // Whack the thread SD
  58. BOOL
  59. WINAPI
  60. LogonUserCommonA(
  61. LPSTR lpszUsername,
  62. LPSTR lpszDomain,
  63. LPSTR lpszPassword,
  64. DWORD dwLogonType,
  65. DWORD dwLogonProvider,
  66. BOOL fExVersion,
  67. HANDLE * phToken,
  68. PSID * ppLogonSid,
  69. PVOID * ppProfileBuffer,
  70. DWORD * pdwProfileLength,
  71. PQUOTA_LIMITS pQuotaLimits
  72. );
  73. BOOL
  74. WINAPI
  75. LogonUserCommonW(
  76. PWSTR lpszUsername,
  77. PWSTR lpszDomain,
  78. PWSTR lpszPassword,
  79. DWORD dwLogonType,
  80. DWORD dwLogonProvider,
  81. BOOL fExVersion,
  82. HANDLE * phToken,
  83. PSID * ppLogonSid,
  84. PVOID * ppProfileBuffer,
  85. DWORD * pdwProfileLength,
  86. PQUOTA_LIMITS pQuotaLimits
  87. );
  88. //+---------------------------------------------------------------------------
  89. //
  90. // Function: Logon32Initialize
  91. //
  92. // Synopsis: Initializes the critical section
  93. //
  94. // Arguments: [hMod] --
  95. // [Reason] --
  96. // [Context] --
  97. //
  98. //----------------------------------------------------------------------------
  99. BOOL
  100. Logon32Initialize(
  101. IN PVOID hMod,
  102. IN ULONG Reason,
  103. IN PCONTEXT Context)
  104. {
  105. NTSTATUS Status;
  106. if (Reason == DLL_PROCESS_ATTACH)
  107. {
  108. Status = RtlInitializeCriticalSection( &Logon32Lock );
  109. return( Status == STATUS_SUCCESS );
  110. }
  111. return( TRUE );
  112. }
  113. /***************************************************************************\
  114. * FindLogonSid
  115. *
  116. * Finds logon sid for a new logon from the access token.
  117. *
  118. \***************************************************************************/
  119. PSID
  120. L32FindLogonSid(
  121. IN HANDLE hToken
  122. )
  123. {
  124. PTOKEN_GROUPS pGroups = NULL;
  125. DWORD cbGroups;
  126. BYTE FastBuffer[ 512 ];
  127. PTOKEN_GROUPS pSlowBuffer = NULL;
  128. UINT i;
  129. PSID Sid = NULL;
  130. pGroups = (PTOKEN_GROUPS)FastBuffer;
  131. cbGroups = sizeof(FastBuffer);
  132. if(!GetTokenInformation(
  133. hToken,
  134. TokenGroups,
  135. pGroups,
  136. cbGroups,
  137. &cbGroups
  138. ))
  139. {
  140. if( GetLastError() != ERROR_INSUFFICIENT_BUFFER ) {
  141. return NULL;
  142. }
  143. pSlowBuffer = (PTOKEN_GROUPS)LocalAlloc(LMEM_FIXED, cbGroups);
  144. if( pSlowBuffer == NULL ) {
  145. return NULL;
  146. }
  147. pGroups = pSlowBuffer;
  148. if(!GetTokenInformation(
  149. hToken,
  150. TokenGroups,
  151. pGroups,
  152. cbGroups,
  153. &cbGroups
  154. )) {
  155. goto Cleanup;
  156. }
  157. }
  158. //
  159. // Get the logon Sid by looping through the Sids in the token
  160. //
  161. for(i = 0 ; i < pGroups->GroupCount ; i++) {
  162. if(pGroups->Groups[i].Attributes & SE_GROUP_LOGON_ID) {
  163. DWORD dwSidLength;
  164. //
  165. // insure we are dealing with a valid Sid
  166. //
  167. if(!IsValidSid(pGroups->Groups[i].Sid)) {
  168. goto Cleanup;
  169. }
  170. //
  171. // get required allocation size to copy the Sid
  172. //
  173. dwSidLength = GetLengthSid(pGroups->Groups[i].Sid);
  174. Sid = (PSID)LocalAlloc( LMEM_FIXED, dwSidLength );
  175. if( Sid == NULL ) {
  176. goto Cleanup;
  177. }
  178. CopySid(dwSidLength, Sid, pGroups->Groups[i].Sid);
  179. break;
  180. }
  181. }
  182. Cleanup:
  183. if( pSlowBuffer )
  184. {
  185. LocalFree( pSlowBuffer );
  186. }
  187. return Sid;
  188. }
  189. /*******************************************************************
  190. NAME: GetDefaultDomainName
  191. SYNOPSIS: Fills in the given array with the name of the default
  192. domain to use for logon validation.
  193. ENTRY: pszDomainName - Pointer to a buffer that will receive
  194. the default domain name.
  195. cchDomainName - The size (in charactesr) of the domain
  196. name buffer.
  197. RETURNS: TRUE if successful, FALSE if not.
  198. HISTORY:
  199. KeithMo 05-Dec-1994 Created.
  200. RichardW 10-Jan-95 Liberated from sockets and stuck in base
  201. ********************************************************************/
  202. BOOL
  203. L32GetDefaultDomainName(
  204. PUNICODE_STRING pDomainName
  205. )
  206. {
  207. OBJECT_ATTRIBUTES ObjectAttributes;
  208. NTSTATUS NtStatus;
  209. INT Result;
  210. DWORD err = 0;
  211. LSA_HANDLE LsaPolicyHandle = NULL;
  212. PPOLICY_ACCOUNT_DOMAIN_INFO DomainInfo = NULL;
  213. PUNICODE_STRING pDomain;
  214. if (Logon32DomainName[0] != L'\0')
  215. {
  216. RtlInitUnicodeString(pDomainName, Logon32DomainName);
  217. return(TRUE);
  218. }
  219. //
  220. // Open a handle to the local machine's LSA policy object.
  221. //
  222. InitializeObjectAttributes( &ObjectAttributes, // object attributes
  223. NULL, // name
  224. 0L, // attributes
  225. NULL, // root directory
  226. NULL ); // security descriptor
  227. NtStatus = LsaOpenPolicy( NULL, // system name
  228. &ObjectAttributes, // object attributes
  229. POLICY_EXECUTE, // access mask
  230. &LsaPolicyHandle ); // policy handle
  231. if( !NT_SUCCESS( NtStatus ) )
  232. {
  233. BaseSetLastNTError(NtStatus);
  234. return(FALSE);
  235. }
  236. //
  237. // Query the domain information from the policy object.
  238. //
  239. NtStatus = LsaQueryInformationPolicy( LsaPolicyHandle,
  240. PolicyAccountDomainInformation,
  241. (PVOID *) &DomainInfo );
  242. if (!NT_SUCCESS(NtStatus))
  243. {
  244. BaseSetLastNTError(NtStatus);
  245. LsaClose(LsaPolicyHandle);
  246. return(FALSE);
  247. }
  248. (void) LsaClose(LsaPolicyHandle);
  249. //
  250. // Copy the domain name into our cache, and
  251. //
  252. CopyMemory( Logon32DomainName,
  253. DomainInfo->DomainName.Buffer,
  254. DomainInfo->DomainName.Length );
  255. //
  256. // Null terminate it appropriately
  257. //
  258. Logon32DomainName[DomainInfo->DomainName.Length / sizeof(WCHAR)] = L'\0';
  259. //
  260. // Clean up
  261. //
  262. LsaFreeMemory( (PVOID)DomainInfo );
  263. //
  264. // And init the string
  265. //
  266. RtlInitUnicodeString(pDomainName, Logon32DomainName);
  267. return TRUE;
  268. } // GetDefaultDomainName
  269. //+---------------------------------------------------------------------------
  270. //
  271. // Function: L32pInitLsa
  272. //
  273. // Synopsis: Initialize connection with LSA
  274. //
  275. // Arguments: (none)
  276. //
  277. // History: 4-21-95 RichardW Created
  278. //
  279. // Notes:
  280. //
  281. //----------------------------------------------------------------------------
  282. BOOL
  283. L32pInitLsa(void)
  284. {
  285. STRING PackageName;
  286. ULONG MsvHandle;
  287. ULONG NegoHandle;
  288. NTSTATUS Status;
  289. //
  290. // Hookup to the LSA and locate our authentication package.
  291. //
  292. Status = LsaConnectUntrusted(
  293. &Logon32LsaHandle
  294. );
  295. if (!NT_SUCCESS(Status)) {
  296. Logon32LsaHandle = NULL;
  297. goto Cleanup;
  298. }
  299. //
  300. // Connect with the MSV1_0 authentication package
  301. //
  302. RtlInitString(&PackageName, "MICROSOFT_AUTHENTICATION_PACKAGE_V1_0");
  303. Status = LsaLookupAuthenticationPackage (
  304. Logon32LsaHandle,
  305. &PackageName,
  306. &MsvHandle
  307. );
  308. if (!NT_SUCCESS(Status)) {
  309. goto Cleanup;
  310. }
  311. //
  312. // Connect with the Negotiate authentication package
  313. //
  314. RtlInitString(&PackageName, NEGOSSP_NAME_A);
  315. Status = LsaLookupAuthenticationPackage (
  316. Logon32LsaHandle,
  317. &PackageName,
  318. &NegoHandle
  319. );
  320. if (!NT_SUCCESS(Status)) {
  321. goto Cleanup;
  322. }
  323. //
  324. // Wait until successful to update the 2 globals.
  325. //
  326. Logon32NegoHandle = NegoHandle;
  327. Logon32MsvHandle = MsvHandle;
  328. Cleanup:
  329. if( !NT_SUCCESS(Status) ) {
  330. if( Logon32LsaHandle ) {
  331. (VOID) LsaDeregisterLogonProcess( Logon32LsaHandle );
  332. Logon32LsaHandle = NULL;
  333. }
  334. BaseSetLastNTError( Status );
  335. return FALSE;
  336. }
  337. return TRUE;
  338. }
  339. //+---------------------------------------------------------------------------
  340. //
  341. // Function: L32pNotifyMpr
  342. //
  343. // Synopsis: Loads the MPR DLL and notifies the network providers (like
  344. // csnw) so they know about this logon session and the credentials
  345. //
  346. // Arguments: [NewLogon] -- New logon information
  347. // [LogonId] -- Logon ID
  348. //
  349. // History: 4-24-95 RichardW Created
  350. //
  351. // Notes:
  352. //
  353. //----------------------------------------------------------------------------
  354. BOOL
  355. L32pNotifyMpr(
  356. PMSV1_0_INTERACTIVE_LOGON NewLogon,
  357. PLUID LogonId
  358. )
  359. {
  360. MSV1_0_INTERACTIVE_LOGON OldLogon;
  361. LPWSTR LogonScripts;
  362. DWORD status;
  363. LUID LocalServiceLuid = LOCALSERVICE_LUID;
  364. LUID NetworkServiceLuid = NETWORKSERVICE_LUID;
  365. if (RtlEqualLuid(LogonId, &LocalServiceLuid)
  366. ||
  367. RtlEqualLuid(LogonId, &NetworkServiceLuid))
  368. {
  369. //
  370. // Don't notify providers for LocalService/NetworkService logons
  371. //
  372. return( TRUE );
  373. }
  374. if ( Logon32MprHandle == NULL )
  375. {
  376. LockLogon();
  377. if ( Logon32MprHandle == NULL)
  378. {
  379. Logon32MprHandle = LoadLibrary("mpr.dll");
  380. if (Logon32MprHandle != NULL) {
  381. Logon32LogonNotify = (LOGONNOTIFYFN) GetProcAddress(
  382. Logon32MprHandle,
  383. "WNetLogonNotify");
  384. }
  385. }
  386. UnlockLogon();
  387. }
  388. if ( Logon32LogonNotify != NULL )
  389. {
  390. CopyMemory(&OldLogon, NewLogon, sizeof(OldLogon));
  391. status = Logon32LogonNotify(
  392. L"Windows NT Network Provider",
  393. LogonId,
  394. L"MSV1_0:Interactive",
  395. (LPVOID)NewLogon,
  396. L"MSV1_0:Interactive",
  397. (LPVOID)&OldLogon,
  398. L"SvcCtl", // StationName
  399. NULL, // StationHandle
  400. &LogonScripts); // LogonScripts
  401. if (status == NO_ERROR) {
  402. if (LogonScripts != NULL ) {
  403. (void) LocalFree(LogonScripts);
  404. }
  405. }
  406. return( TRUE );
  407. }
  408. return( FALSE );
  409. }
  410. //+---------------------------------------------------------------------------
  411. //
  412. // Function: L32pLogonUser
  413. //
  414. // Synopsis: Wraps up the call to LsaLogonUser
  415. //
  416. // Arguments: [LsaHandle] --
  417. // [AuthenticationPackage] --
  418. // [LogonType] --
  419. // [UserName] --
  420. // [Domain] --
  421. // [Password] --
  422. // [LogonId] --
  423. // [LogonToken] --
  424. // [Quotas] --
  425. // [pProfileBuffer] --
  426. // [pProfileBufferLength] --
  427. // [pSubStatus] --
  428. //
  429. // History: 4-24-95 RichardW Created
  430. //
  431. // Notes:
  432. //
  433. //----------------------------------------------------------------------------
  434. NTSTATUS
  435. L32pLogonUser(
  436. IN HANDLE LsaHandle,
  437. IN ULONG AuthenticationPackage,
  438. IN SECURITY_LOGON_TYPE LogonType,
  439. IN PUNICODE_STRING UserName,
  440. IN PUNICODE_STRING Domain,
  441. IN PUNICODE_STRING Password,
  442. OUT PLUID LogonId,
  443. OUT PHANDLE LogonToken,
  444. OUT PQUOTA_LIMITS Quotas,
  445. OUT PVOID *pProfileBuffer,
  446. OUT PULONG pProfileBufferLength,
  447. OUT PNTSTATUS pSubStatus
  448. )
  449. {
  450. NTSTATUS Status;
  451. STRING OriginName;
  452. TOKEN_SOURCE SourceContext;
  453. PMSV1_0_INTERACTIVE_LOGON MsvAuthInfo;
  454. PMSV1_0_LM20_LOGON MsvNetAuthInfo;
  455. PVOID AuthInfoBuf;
  456. ULONG AuthInfoSize;
  457. WCHAR ComputerName[ MAX_COMPUTERNAME_LENGTH + 1 ];
  458. DWORD ComputerNameLength;
  459. //
  460. // Initialize source context structure
  461. //
  462. strncpy(SourceContext.SourceName, "Advapi ", sizeof(SourceContext.SourceName)); // LATER from res file
  463. Status = NtAllocateLocallyUniqueId(&SourceContext.SourceIdentifier);
  464. if (!NT_SUCCESS(Status)) {
  465. return(Status);
  466. }
  467. //
  468. // Set logon origin
  469. //
  470. RtlInitString(&OriginName, "LogonUser API");
  471. //
  472. // For network logons, do the magic.
  473. //
  474. if ( ( LogonType == Network ) )
  475. {
  476. ComputerNameLength = MAX_COMPUTERNAME_LENGTH + 1;
  477. if (!GetComputerNameW( ComputerName, &ComputerNameLength ) )
  478. {
  479. return(STATUS_INVALID_PARAMETER);
  480. }
  481. AuthInfoSize = sizeof( MSV1_0_LM20_LOGON ) +
  482. UserName->Length +
  483. Domain->Length +
  484. sizeof(WCHAR) * (ComputerNameLength + 1) +
  485. Password->Length;
  486. MsvNetAuthInfo = AuthInfoBuf = RtlAllocateHeap( RtlProcessHeap(),
  487. HEAP_ZERO_MEMORY,
  488. AuthInfoSize );
  489. if ( !MsvNetAuthInfo )
  490. {
  491. return( STATUS_NO_MEMORY );
  492. }
  493. //
  494. // Start packing in the string
  495. //
  496. MsvNetAuthInfo->MessageType = MsV1_0NetworkLogon;
  497. //
  498. // Copy the user name into the authentication buffer
  499. //
  500. MsvNetAuthInfo->UserName.Length =
  501. UserName->Length;
  502. MsvNetAuthInfo->UserName.MaximumLength =
  503. MsvNetAuthInfo->UserName.Length;
  504. MsvNetAuthInfo->UserName.Buffer = (PWSTR)(MsvNetAuthInfo+1);
  505. RtlCopyMemory(
  506. MsvNetAuthInfo->UserName.Buffer,
  507. UserName->Buffer,
  508. UserName->Length
  509. );
  510. //
  511. // Copy the domain name into the authentication buffer
  512. //
  513. MsvNetAuthInfo->LogonDomainName.Length = Domain->Length;
  514. MsvNetAuthInfo->LogonDomainName.MaximumLength = Domain->Length ;
  515. MsvNetAuthInfo->LogonDomainName.Buffer = (PWSTR)
  516. ((PBYTE)(MsvNetAuthInfo->UserName.Buffer) +
  517. MsvNetAuthInfo->UserName.MaximumLength);
  518. RtlCopyMemory(
  519. MsvNetAuthInfo->LogonDomainName.Buffer,
  520. Domain->Buffer,
  521. Domain->Length);
  522. //
  523. // Copy the workstation name into the buffer
  524. //
  525. MsvNetAuthInfo->Workstation.Length = (USHORT)
  526. (sizeof(WCHAR) * ComputerNameLength);
  527. MsvNetAuthInfo->Workstation.MaximumLength =
  528. MsvNetAuthInfo->Workstation.Length + sizeof(WCHAR);
  529. MsvNetAuthInfo->Workstation.Buffer = (PWSTR)
  530. ((PBYTE) (MsvNetAuthInfo->LogonDomainName.Buffer) +
  531. MsvNetAuthInfo->LogonDomainName.MaximumLength );
  532. wcscpy( MsvNetAuthInfo->Workstation.Buffer, ComputerName );
  533. //
  534. // Set up space for Password (Unicode)
  535. //
  536. MsvNetAuthInfo->CaseSensitiveChallengeResponse.Buffer = (PUCHAR)
  537. ((PBYTE) (MsvNetAuthInfo->Workstation.Buffer) +
  538. MsvNetAuthInfo->Workstation.MaximumLength );
  539. MsvNetAuthInfo->CaseSensitiveChallengeResponse.Length =
  540. MsvNetAuthInfo->CaseSensitiveChallengeResponse.MaximumLength =
  541. Password->Length;
  542. RtlCopyMemory(
  543. MsvNetAuthInfo->CaseSensitiveChallengeResponse.Buffer,
  544. Password->Buffer,
  545. Password->Length);
  546. //
  547. // Zero out the ascii password
  548. //
  549. RtlZeroMemory( &MsvNetAuthInfo->CaseInsensitiveChallengeResponse,
  550. sizeof(MsvNetAuthInfo->CaseInsensitiveChallengeResponse));
  551. //
  552. // to be consistent with Negotiate/Kerberos for _WINNT50 cases,
  553. // allow machine accounts to be logged on.
  554. //
  555. MsvNetAuthInfo->ParameterControl = MSV1_0_CLEARTEXT_PASSWORD_ALLOWED |
  556. MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT |
  557. MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT;
  558. }
  559. else
  560. {
  561. //
  562. // Build logon structure for non-network logons - service,
  563. // batch, interactive, unlock, new credentials, networkcleartext
  564. //
  565. AuthInfoSize = sizeof(MSV1_0_INTERACTIVE_LOGON) +
  566. UserName->Length +
  567. Domain->Length +
  568. Password->Length;
  569. MsvAuthInfo = AuthInfoBuf = RtlAllocateHeap(RtlProcessHeap(),
  570. HEAP_ZERO_MEMORY,
  571. AuthInfoSize);
  572. if (MsvAuthInfo == NULL) {
  573. return(STATUS_NO_MEMORY);
  574. }
  575. //
  576. // This authentication buffer will be used for a logon attempt
  577. //
  578. MsvAuthInfo->MessageType = MsV1_0InteractiveLogon;
  579. //
  580. // Copy the user name into the authentication buffer
  581. //
  582. MsvAuthInfo->UserName.Length = UserName->Length;
  583. MsvAuthInfo->UserName.MaximumLength =
  584. MsvAuthInfo->UserName.Length;
  585. MsvAuthInfo->UserName.Buffer = (PWSTR)(MsvAuthInfo+1);
  586. RtlCopyMemory(
  587. MsvAuthInfo->UserName.Buffer,
  588. UserName->Buffer,
  589. UserName->Length
  590. );
  591. //
  592. // Copy the domain name into the authentication buffer
  593. //
  594. MsvAuthInfo->LogonDomainName.Length = Domain->Length;
  595. MsvAuthInfo->LogonDomainName.MaximumLength =
  596. MsvAuthInfo->LogonDomainName.Length;
  597. MsvAuthInfo->LogonDomainName.Buffer = (PWSTR)
  598. ((PBYTE)(MsvAuthInfo->UserName.Buffer) +
  599. MsvAuthInfo->UserName.MaximumLength);
  600. RtlCopyMemory(
  601. MsvAuthInfo->LogonDomainName.Buffer,
  602. Domain->Buffer,
  603. Domain->Length
  604. );
  605. //
  606. // Copy the password into the authentication buffer
  607. // Hide it once we have copied it. Use the same seed value
  608. // that we used for the original password in pGlobals.
  609. //
  610. MsvAuthInfo->Password.Length = Password->Length;
  611. MsvAuthInfo->Password.MaximumLength =
  612. MsvAuthInfo->Password.Length;
  613. MsvAuthInfo->Password.Buffer = (PWSTR)
  614. ((PBYTE)(MsvAuthInfo->LogonDomainName.Buffer) +
  615. MsvAuthInfo->LogonDomainName.MaximumLength);
  616. RtlCopyMemory(
  617. MsvAuthInfo->Password.Buffer,
  618. Password->Buffer,
  619. Password->Length
  620. );
  621. }
  622. //
  623. // Now try to log this sucker on
  624. //
  625. Status = LsaLogonUser (
  626. LsaHandle,
  627. &OriginName,
  628. LogonType,
  629. AuthenticationPackage,
  630. AuthInfoBuf,
  631. AuthInfoSize,
  632. NULL,
  633. &SourceContext,
  634. pProfileBuffer,
  635. pProfileBufferLength,
  636. LogonId,
  637. LogonToken,
  638. Quotas,
  639. pSubStatus
  640. );
  641. //
  642. // Notify all the network providers, if this is a NON network logon
  643. //
  644. if ( NT_SUCCESS( Status ) &&
  645. (LogonType != Network) )
  646. {
  647. L32pNotifyMpr(AuthInfoBuf, LogonId);
  648. }
  649. //
  650. // Discard authentication buffer
  651. //
  652. RtlFreeHeap(RtlProcessHeap(), 0, AuthInfoBuf);
  653. return(Status);
  654. }
  655. //+---------------------------------------------------------------------------
  656. //
  657. // Function: LogonUserCommonA
  658. //
  659. // Synopsis: ANSI wrapper for LogonUserCommonW. See description below
  660. //
  661. // Arguments: [lpszUsername] --
  662. // [lpszDomain] --
  663. // [lpszPassword] --
  664. // [dwLogonType] --
  665. // [dwLogonProvider] --
  666. // [fExVersion] --
  667. // [phToken] --
  668. // [ppLogonSid] --
  669. // [ppProfileBuffer] --
  670. // [pdwProfileLength] --
  671. // [pQuotaLimits] --
  672. //
  673. // History: 2-15-2000 JSchwart Created from RichardW's LogonUserA
  674. //
  675. // Notes:
  676. //
  677. //----------------------------------------------------------------------------
  678. BOOL
  679. WINAPI
  680. LogonUserCommonA(
  681. LPSTR lpszUsername,
  682. LPSTR lpszDomain,
  683. LPSTR lpszPassword,
  684. DWORD dwLogonType,
  685. DWORD dwLogonProvider,
  686. BOOL fExVersion,
  687. HANDLE * phToken,
  688. PSID * ppLogonSid,
  689. PVOID * ppProfileBuffer,
  690. DWORD * pdwProfileLength,
  691. PQUOTA_LIMITS pQuotaLimits
  692. )
  693. {
  694. UNICODE_STRING Username;
  695. UNICODE_STRING Domain;
  696. UNICODE_STRING Password;
  697. ANSI_STRING Temp ;
  698. NTSTATUS Status;
  699. BOOL bRet;
  700. Username.Buffer = NULL;
  701. Domain.Buffer = NULL;
  702. Password.Buffer = NULL;
  703. RtlInitAnsiString( &Temp, lpszUsername );
  704. Status = RtlAnsiStringToUnicodeString( &Username, &Temp, TRUE );
  705. if (!NT_SUCCESS( Status ) )
  706. {
  707. BaseSetLastNTError(Status);
  708. bRet = FALSE;
  709. goto Cleanup;
  710. }
  711. RtlInitAnsiString( &Temp, lpszDomain );
  712. Status = RtlAnsiStringToUnicodeString(&Domain, &Temp, TRUE );
  713. if (!NT_SUCCESS(Status))
  714. {
  715. BaseSetLastNTError(Status);
  716. bRet = FALSE;
  717. goto Cleanup;
  718. }
  719. RtlInitAnsiString( &Temp, lpszPassword );
  720. Status = RtlAnsiStringToUnicodeString( &Password, &Temp, TRUE );
  721. if (!NT_SUCCESS(Status))
  722. {
  723. BaseSetLastNTError(Status);
  724. bRet = FALSE;
  725. goto Cleanup;
  726. }
  727. bRet = LogonUserCommonW( Username.Buffer,
  728. Domain.Buffer,
  729. Password.Buffer,
  730. dwLogonType,
  731. dwLogonProvider,
  732. fExVersion,
  733. phToken,
  734. ppLogonSid,
  735. ppProfileBuffer,
  736. pdwProfileLength,
  737. pQuotaLimits );
  738. Cleanup:
  739. if (Username.Buffer)
  740. {
  741. RtlFreeUnicodeString(&Username);
  742. }
  743. if (Domain.Buffer)
  744. {
  745. RtlFreeUnicodeString(&Domain);
  746. }
  747. if (Password.Buffer)
  748. {
  749. RtlZeroMemory(Password.Buffer, Password.Length);
  750. RtlFreeUnicodeString(&Password);
  751. }
  752. return(bRet);
  753. }
  754. //+---------------------------------------------------------------------------
  755. //
  756. // Function: LogonUserA
  757. //
  758. // Synopsis: ANSI wrapper for LogonUserW. See description below
  759. //
  760. // Arguments: [lpszUsername] --
  761. // [lpszDomain] --
  762. // [lpszPassword] --
  763. // [dwLogonType] --
  764. // [dwLogonProvider] --
  765. // [phToken] --
  766. //
  767. // History: 4-25-95 RichardW Created
  768. //
  769. // Notes:
  770. //
  771. //----------------------------------------------------------------------------
  772. BOOL
  773. WINAPI
  774. LogonUserA(
  775. LPSTR lpszUsername,
  776. LPSTR lpszDomain,
  777. LPSTR lpszPassword,
  778. DWORD dwLogonType,
  779. DWORD dwLogonProvider,
  780. HANDLE * phToken
  781. )
  782. {
  783. return LogonUserCommonA(lpszUsername,
  784. lpszDomain,
  785. lpszPassword,
  786. dwLogonType,
  787. dwLogonProvider,
  788. FALSE, // LogonUserA
  789. phToken,
  790. NULL, // ppLogonSid
  791. NULL, // ppProfileBuffer
  792. NULL, // pdwProfileLength
  793. NULL); // pQuotaLimits
  794. }
  795. //+---------------------------------------------------------------------------
  796. //
  797. // Function: LogonUserExA
  798. //
  799. // Synopsis: ANSI wrapper for LogonUserExW. See description below
  800. //
  801. // Arguments: [lpszUsername] --
  802. // [lpszDomain] --
  803. // [lpszPassword] --
  804. // [dwLogonType] --
  805. // [dwLogonProvider] --
  806. // [phToken] --
  807. // [ppLogonSid] --
  808. // [ppProfileBuffer] --
  809. // [pdwProfileLength] --
  810. // [pQuotaLimits] --
  811. //
  812. // History: 2-15-2000 JSchwart Created from RichardW's LogonUserW
  813. //
  814. // Notes:
  815. //
  816. //----------------------------------------------------------------------------
  817. BOOL
  818. WINAPI
  819. LogonUserExA(
  820. LPSTR lpszUsername,
  821. LPSTR lpszDomain,
  822. LPSTR lpszPassword,
  823. DWORD dwLogonType,
  824. DWORD dwLogonProvider,
  825. HANDLE * phToken,
  826. PSID * ppLogonSid,
  827. PVOID * ppProfileBuffer,
  828. DWORD * pdwProfileLength,
  829. PQUOTA_LIMITS pQuotaLimits
  830. )
  831. {
  832. return LogonUserCommonA(lpszUsername,
  833. lpszDomain,
  834. lpszPassword,
  835. dwLogonType,
  836. dwLogonProvider,
  837. TRUE, // LogonUserExA
  838. phToken,
  839. ppLogonSid,
  840. ppProfileBuffer,
  841. pdwProfileLength,
  842. pQuotaLimits);
  843. }
  844. //+---------------------------------------------------------------------------
  845. //
  846. // Function: LogonUserCommonW
  847. //
  848. // Synopsis: Common code for LogonUserW and LogonUserExW. Logs a user on
  849. // via plaintext password, username and domain name via the LSA.
  850. //
  851. // Arguments: [lpszUsername] -- User name
  852. // [lpszDomain] -- Domain name
  853. // [lpszPassword] -- Password
  854. // [dwLogonType] -- Logon type
  855. // [dwLogonProvider] -- Provider
  856. // [fExVersion] -- LogonUserExW or LogonUserW
  857. // [phToken] -- Returned handle to primary token
  858. // [ppLogonSid] -- Returned logon sid
  859. // [ppProfileBuffer] -- Returned user profile buffer
  860. // [pdwProfileLength] -- Returned profile length
  861. //
  862. // History: 2-15-2000 JSchwart Created from RichardW's LogonUserW
  863. //
  864. // Notes: Requires SeTcbPrivilege, and will enable it if not already
  865. // present.
  866. //
  867. //----------------------------------------------------------------------------
  868. BOOL
  869. WINAPI
  870. LogonUserCommonW(
  871. PWSTR lpszUsername,
  872. PWSTR lpszDomain,
  873. PWSTR lpszPassword,
  874. DWORD dwLogonType,
  875. DWORD dwLogonProvider,
  876. BOOL fExVersion,
  877. HANDLE * phToken,
  878. PSID * ppLogonSid,
  879. PVOID * ppProfileBuffer,
  880. DWORD * pdwProfileLength,
  881. PQUOTA_LIMITS pQuotaLimits
  882. )
  883. {
  884. NTSTATUS Status;
  885. ULONG PackageId;
  886. UNICODE_STRING Username;
  887. UNICODE_STRING Domain;
  888. UNICODE_STRING Password;
  889. HANDLE hTempToken;
  890. HANDLE * phTempToken;
  891. LUID LogonId;
  892. PVOID Profile;
  893. ULONG ProfileLength;
  894. NTSTATUS SubStatus = STATUS_SUCCESS;
  895. SECURITY_LOGON_TYPE LogonType;
  896. //
  897. // Validate the provider
  898. //
  899. if (dwLogonProvider == LOGON32_PROVIDER_DEFAULT)
  900. {
  901. dwLogonProvider = LOGON32_PROVIDER_WINNT50;
  902. //
  903. // if domain was not supplied, and username is not a UPN, use
  904. // _WINNT40 to be compatible.
  905. //
  906. if((lpszUsername != NULL) &&
  907. (lpszDomain == NULL || lpszDomain[ 0 ] == L'\0'))
  908. {
  909. if( wcschr( lpszUsername, '@' ) == NULL )
  910. {
  911. dwLogonProvider = LOGON32_PROVIDER_WINNT40;
  912. }
  913. }
  914. }
  915. if (dwLogonProvider > LOGON32_PROVIDER_WINNT50)
  916. {
  917. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  918. return(FALSE);
  919. }
  920. switch (dwLogonType)
  921. {
  922. case LOGON32_LOGON_INTERACTIVE:
  923. LogonType = Interactive;
  924. break;
  925. case LOGON32_LOGON_BATCH:
  926. LogonType = Batch;
  927. break;
  928. case LOGON32_LOGON_SERVICE:
  929. LogonType = Service;
  930. break;
  931. case LOGON32_LOGON_NETWORK:
  932. LogonType = Network;
  933. break;
  934. case LOGON32_LOGON_UNLOCK:
  935. LogonType = Unlock ;
  936. break;
  937. case LOGON32_LOGON_NETWORK_CLEARTEXT:
  938. LogonType = NetworkCleartext ;
  939. break;
  940. case LOGON32_LOGON_NEW_CREDENTIALS:
  941. LogonType = NewCredentials;
  942. break;
  943. default:
  944. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  945. return(FALSE);
  946. break;
  947. }
  948. //
  949. // If the MSV handle is -1, grab the lock, and try again:
  950. //
  951. if (Logon32MsvHandle == 0xFFFFFFFF || Logon32NegoHandle == 0xFFFFFFFF)
  952. {
  953. LockLogon();
  954. //
  955. // If the MSV handle is still -1, init our connection to lsa. We
  956. // have the lock, so no other threads can't be trying this right now.
  957. //
  958. if (Logon32MsvHandle == 0xFFFFFFFF || Logon32NegoHandle == 0xFFFFFFFF)
  959. {
  960. if (!L32pInitLsa())
  961. {
  962. UnlockLogon();
  963. return( FALSE );
  964. }
  965. }
  966. UnlockLogon();
  967. }
  968. //
  969. // Validate the parameters. NULL or empty domain or NULL or empty
  970. // user name is invalid.
  971. //
  972. RtlInitUnicodeString(&Username, lpszUsername);
  973. if (Username.Length == 0)
  974. {
  975. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  976. return(FALSE);
  977. }
  978. //
  979. // Initialize/check parameters based on which API we're servicing.
  980. //
  981. if (!fExVersion)
  982. {
  983. //
  984. // LogonUserW -- phToken is required. Initialize the token handle,
  985. // if the pointer is invalid, then catch the exception now.
  986. //
  987. *phToken = NULL;
  988. phTempToken = phToken;
  989. }
  990. else
  991. {
  992. //
  993. // LogonUserExW -- phToken, ppLogonSid, ppProfileBuffer, and
  994. // pdwProfileLength are optional. Initialize as appropriate.
  995. //
  996. if (ARGUMENT_PRESENT(phToken))
  997. {
  998. *phToken = NULL;
  999. phTempToken = phToken;
  1000. }
  1001. else
  1002. {
  1003. //
  1004. // Dummy token handle to use in the LsaLogonUser call
  1005. //
  1006. phTempToken = &hTempToken;
  1007. }
  1008. if (ARGUMENT_PRESENT(ppLogonSid))
  1009. {
  1010. *ppLogonSid = NULL;
  1011. }
  1012. if (!!ppProfileBuffer ^ !!pdwProfileLength)
  1013. {
  1014. //
  1015. // Can't have one without the other...
  1016. //
  1017. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  1018. return(FALSE);
  1019. }
  1020. if (ARGUMENT_PRESENT(ppProfileBuffer))
  1021. {
  1022. *ppProfileBuffer = NULL;
  1023. *pdwProfileLength = 0;
  1024. }
  1025. if (ARGUMENT_PRESENT(pQuotaLimits))
  1026. {
  1027. RtlZeroMemory(pQuotaLimits, sizeof(QUOTA_LIMITS));
  1028. }
  1029. }
  1030. //
  1031. // Parse that domain. Note, if the special token . is passed in for
  1032. // domain, we will use the right value from the LSA, meaning AccountDomain.
  1033. // If the domain is null, the lsa will talk to the local domain, the
  1034. // primary domain, and then on from there...
  1035. //
  1036. if (lpszDomain && *lpszDomain)
  1037. {
  1038. if ((lpszDomain[0] == L'.') &&
  1039. (lpszDomain[1] == L'\0') )
  1040. {
  1041. if (!L32GetDefaultDomainName(&Domain))
  1042. {
  1043. return(FALSE);
  1044. }
  1045. }
  1046. else
  1047. {
  1048. RtlInitUnicodeString(&Domain, lpszDomain);
  1049. }
  1050. }
  1051. else
  1052. {
  1053. RtlInitUnicodeString(&Domain, lpszDomain);
  1054. }
  1055. //
  1056. // Finally, init the password
  1057. //
  1058. RtlInitUnicodeString(&Password, lpszPassword);
  1059. //
  1060. // Attempt the logon
  1061. //
  1062. Status = L32pLogonUser(
  1063. Logon32LsaHandle,
  1064. (dwLogonProvider == LOGON32_PROVIDER_WINNT50) ?
  1065. Logon32NegoHandle : Logon32MsvHandle,
  1066. LogonType,
  1067. &Username,
  1068. &Domain,
  1069. &Password,
  1070. &LogonId,
  1071. phTempToken,
  1072. pQuotaLimits ? pQuotaLimits : &Logon32QuotaLimits,
  1073. &Profile,
  1074. &ProfileLength,
  1075. &SubStatus);
  1076. //
  1077. // Set output parameters based on which API we're servicing
  1078. //
  1079. // TODO: review cleanup code if something fails mid-stream.
  1080. //
  1081. if (!fExVersion)
  1082. {
  1083. if (!NT_SUCCESS(Status))
  1084. {
  1085. if (Status == STATUS_ACCOUNT_RESTRICTION)
  1086. {
  1087. BaseSetLastNTError(SubStatus);
  1088. }
  1089. else
  1090. {
  1091. BaseSetLastNTError(Status);
  1092. }
  1093. return(FALSE);
  1094. }
  1095. if (Profile != NULL)
  1096. {
  1097. LsaFreeReturnBuffer(Profile);
  1098. }
  1099. }
  1100. else
  1101. {
  1102. //
  1103. // We may need the allocated buffers if all went well, so
  1104. // check the return status first.
  1105. //
  1106. if (!NT_SUCCESS(Status))
  1107. {
  1108. if (Status == STATUS_ACCOUNT_RESTRICTION)
  1109. {
  1110. BaseSetLastNTError(SubStatus);
  1111. }
  1112. else
  1113. {
  1114. BaseSetLastNTError(Status);
  1115. }
  1116. return(FALSE);
  1117. }
  1118. //
  1119. // The logon succeeded -- fill in the requested output parameters.
  1120. //
  1121. if (ARGUMENT_PRESENT(ppProfileBuffer))
  1122. {
  1123. if (Profile != NULL)
  1124. {
  1125. ASSERT(ProfileLength != 0);
  1126. *ppProfileBuffer = Profile;
  1127. *pdwProfileLength = ProfileLength;
  1128. }
  1129. }
  1130. else
  1131. {
  1132. if (Profile != NULL)
  1133. {
  1134. LsaFreeReturnBuffer(Profile);
  1135. }
  1136. }
  1137. if (ARGUMENT_PRESENT(ppLogonSid))
  1138. {
  1139. *ppLogonSid = L32FindLogonSid( *phTempToken );
  1140. }
  1141. if (!ARGUMENT_PRESENT(phToken))
  1142. {
  1143. //
  1144. // Close the dummy token handle
  1145. //
  1146. CloseHandle(*phTempToken);
  1147. }
  1148. }
  1149. return(TRUE);
  1150. }
  1151. //+---------------------------------------------------------------------------
  1152. //
  1153. // Function: LogonUserW
  1154. //
  1155. // Synopsis: Logs a user on via plaintext password, username and domain
  1156. // name via the LSA.
  1157. //
  1158. // Arguments: [lpszUsername] -- User name
  1159. // [lpszDomain] -- Domain name
  1160. // [lpszPassword] -- Password
  1161. // [dwLogonType] -- Logon type
  1162. // [dwLogonProvider] -- Provider
  1163. // [phToken] -- Returned handle to primary token
  1164. //
  1165. // History: 4-25-95 RichardW Created
  1166. //
  1167. // Notes: Requires SeTcbPrivilege, and will enable it if not already
  1168. // present.
  1169. //
  1170. //----------------------------------------------------------------------------
  1171. BOOL
  1172. WINAPI
  1173. LogonUserW(
  1174. PWSTR lpszUsername,
  1175. PWSTR lpszDomain,
  1176. PWSTR lpszPassword,
  1177. DWORD dwLogonType,
  1178. DWORD dwLogonProvider,
  1179. HANDLE * phToken
  1180. )
  1181. {
  1182. return LogonUserCommonW(lpszUsername,
  1183. lpszDomain,
  1184. lpszPassword,
  1185. dwLogonType,
  1186. dwLogonProvider,
  1187. FALSE, // LogonUserW
  1188. phToken,
  1189. NULL, // ppLogonSid
  1190. NULL, // ppProfileBuffer
  1191. NULL, // pdwProfileLength
  1192. NULL); // pQuotaLimits
  1193. }
  1194. //+---------------------------------------------------------------------------
  1195. //
  1196. // Function: LogonUserExW
  1197. //
  1198. // Synopsis: Logs a user on via plaintext password, username and domain
  1199. // name via the LSA.
  1200. //
  1201. // Arguments: [lpszUsername] -- User name
  1202. // [lpszDomain] -- Domain name
  1203. // [lpszPassword] -- Password
  1204. // [dwLogonType] -- Logon type
  1205. // [dwLogonProvider] -- Provider
  1206. // [phToken] -- Returned handle to primary token
  1207. // [ppLogonSid] -- Returned logon sid
  1208. // [ppProfileBuffer] -- Returned user profile buffer
  1209. // [pdwProfileLength] -- Returned profile length
  1210. // [pQuotaLimits] -- Returned quota limits
  1211. //
  1212. // History: 2-15-2000 JSchwart Created from RichardW's LogonUserW
  1213. //
  1214. // Notes: Requires SeTcbPrivilege, and will enable it if not already
  1215. // present.
  1216. //
  1217. //----------------------------------------------------------------------------
  1218. BOOL
  1219. WINAPI
  1220. LogonUserExW(
  1221. PWSTR lpszUsername,
  1222. PWSTR lpszDomain,
  1223. PWSTR lpszPassword,
  1224. DWORD dwLogonType,
  1225. DWORD dwLogonProvider,
  1226. HANDLE * phToken,
  1227. PSID * ppLogonSid,
  1228. PVOID * ppProfileBuffer,
  1229. DWORD * pdwProfileLength,
  1230. PQUOTA_LIMITS pQuotaLimits
  1231. )
  1232. {
  1233. return LogonUserCommonW(lpszUsername,
  1234. lpszDomain,
  1235. lpszPassword,
  1236. dwLogonType,
  1237. dwLogonProvider,
  1238. TRUE, // LogonUserExW
  1239. phToken,
  1240. ppLogonSid,
  1241. ppProfileBuffer,
  1242. pdwProfileLength,
  1243. pQuotaLimits);
  1244. }
  1245. //+---------------------------------------------------------------------------
  1246. //
  1247. // Function: ImpersonateLoggedOnUser
  1248. //
  1249. // Synopsis: Duplicates the token passed in if it is primary, and assigns
  1250. // it to the thread that called.
  1251. //
  1252. // Arguments: [hToken] --
  1253. //
  1254. // History: 1-10-95 RichardW Created
  1255. //
  1256. // Notes:
  1257. //
  1258. //----------------------------------------------------------------------------
  1259. BOOL
  1260. WINAPI
  1261. ImpersonateLoggedOnUser(
  1262. HANDLE hToken
  1263. )
  1264. {
  1265. TOKEN_TYPE Type;
  1266. ULONG cbType;
  1267. HANDLE hImpToken;
  1268. NTSTATUS Status;
  1269. SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
  1270. OBJECT_ATTRIBUTES ObjectAttributes;
  1271. BOOL fCloseImp;
  1272. Status = NtQueryInformationToken(
  1273. hToken,
  1274. TokenType,
  1275. &Type,
  1276. sizeof(TOKEN_TYPE),
  1277. &cbType);
  1278. if (!NT_SUCCESS(Status))
  1279. {
  1280. BaseSetLastNTError(Status);
  1281. return(FALSE);
  1282. }
  1283. if (Type == TokenPrimary)
  1284. {
  1285. InitializeObjectAttributes(
  1286. &ObjectAttributes,
  1287. NULL,
  1288. 0L,
  1289. NULL,
  1290. NULL);
  1291. SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  1292. SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
  1293. SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  1294. SecurityQualityOfService.EffectiveOnly = FALSE;
  1295. ObjectAttributes.SecurityQualityOfService = &SecurityQualityOfService;
  1296. Status = NtDuplicateToken( hToken,
  1297. TOKEN_IMPERSONATE | TOKEN_QUERY,
  1298. &ObjectAttributes,
  1299. FALSE,
  1300. TokenImpersonation,
  1301. &hImpToken
  1302. );
  1303. if (!NT_SUCCESS(Status))
  1304. {
  1305. BaseSetLastNTError(Status);
  1306. return(FALSE);
  1307. }
  1308. fCloseImp = TRUE;
  1309. }
  1310. else
  1311. {
  1312. hImpToken = hToken;
  1313. fCloseImp = FALSE;
  1314. }
  1315. Status = NtSetInformationThread(
  1316. NtCurrentThread(),
  1317. ThreadImpersonationToken,
  1318. (PVOID) &hImpToken,
  1319. sizeof(hImpToken)
  1320. );
  1321. if (fCloseImp)
  1322. {
  1323. (void) NtClose(hImpToken);
  1324. }
  1325. if (!NT_SUCCESS(Status))
  1326. {
  1327. BaseSetLastNTError(Status);
  1328. return(FALSE);
  1329. }
  1330. return(TRUE);
  1331. }
  1332. //+---------------------------------------------------------------------------
  1333. //
  1334. // Function: L32SetProcessToken
  1335. //
  1336. // Synopsis: Sets the primary token for the new process.
  1337. //
  1338. // Arguments: [psd] --
  1339. // [hProcess] --
  1340. // [hThread] --
  1341. // [hToken] --
  1342. //
  1343. // History: 4-25-95 RichardW Created
  1344. //
  1345. // Notes:
  1346. //
  1347. //----------------------------------------------------------------------------
  1348. BOOL
  1349. L32SetProcessToken(
  1350. PSECURITY_DESCRIPTOR psd,
  1351. HANDLE hProcess,
  1352. HANDLE hThread,
  1353. HANDLE hToken,
  1354. BOOL AlreadyImpersonating
  1355. )
  1356. {
  1357. NTSTATUS Status, AdjustStatus;
  1358. PROCESS_ACCESS_TOKEN PrimaryTokenInfo;
  1359. HANDLE TokenToAssign;
  1360. OBJECT_ATTRIBUTES ObjectAttributes;
  1361. BOOLEAN WasEnabled;
  1362. HANDLE NullHandle;
  1363. //
  1364. // Check for a NULL token. (No need to do anything)
  1365. // The process will run in the parent process's context and inherit
  1366. // the default ACL from the parent process's token.
  1367. //
  1368. if (hToken == NULL)
  1369. {
  1370. return(TRUE);
  1371. }
  1372. //
  1373. // A primary token can only be assigned to one process.
  1374. // Duplicate the logon token so we can assign one to the new
  1375. // process.
  1376. //
  1377. InitializeObjectAttributes(
  1378. &ObjectAttributes,
  1379. NULL,
  1380. 0,
  1381. NULL,
  1382. psd
  1383. );
  1384. Status = NtDuplicateToken(
  1385. hToken, // Duplicate this token
  1386. 0, // Same desired access
  1387. &ObjectAttributes,
  1388. FALSE, // EffectiveOnly
  1389. TokenPrimary, // TokenType
  1390. &TokenToAssign // Duplicate token handle stored here
  1391. );
  1392. if (!NT_SUCCESS(Status)) {
  1393. return(FALSE);
  1394. }
  1395. //
  1396. // Set the process's primary token. This is actually much more complex
  1397. // to implement in a single API, but we'll live with it. This MUST be
  1398. // called when we are not impersonating! The client generally does *not*
  1399. // have the SeAssignPrimary privilege
  1400. //
  1401. //
  1402. // Enable the required privilege
  1403. //
  1404. if ( !AlreadyImpersonating )
  1405. {
  1406. Status = RtlImpersonateSelf( SecurityImpersonation );
  1407. }
  1408. else
  1409. {
  1410. Status = STATUS_SUCCESS ;
  1411. }
  1412. if ( NT_SUCCESS( Status ) )
  1413. {
  1414. //
  1415. // We now allow restricted tokens to passed in, so we don't
  1416. // fail if the privilege isn't held. Let the kernel deal with
  1417. // the possibilities.
  1418. //
  1419. Status = RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE, TRUE,
  1420. TRUE, &WasEnabled);
  1421. if ( !NT_SUCCESS( Status ) )
  1422. {
  1423. WasEnabled = TRUE ; // Don't try to restore it.
  1424. }
  1425. PrimaryTokenInfo.Token = TokenToAssign;
  1426. PrimaryTokenInfo.Thread = hThread;
  1427. Status = NtSetInformationProcess(
  1428. hProcess,
  1429. ProcessAccessToken,
  1430. (PVOID)&PrimaryTokenInfo,
  1431. (ULONG)sizeof(PROCESS_ACCESS_TOKEN)
  1432. );
  1433. //
  1434. // Restore the privilege to its previous state
  1435. //
  1436. if (!WasEnabled)
  1437. {
  1438. AdjustStatus = RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE,
  1439. WasEnabled, TRUE, &WasEnabled);
  1440. if (NT_SUCCESS(Status)) {
  1441. Status = AdjustStatus;
  1442. }
  1443. }
  1444. //
  1445. // Revert back to process.
  1446. //
  1447. if ( !AlreadyImpersonating )
  1448. {
  1449. NullHandle = NULL;
  1450. AdjustStatus = NtSetInformationThread(
  1451. NtCurrentThread(),
  1452. ThreadImpersonationToken,
  1453. (PVOID) &NullHandle,
  1454. sizeof( HANDLE ) );
  1455. if ( NT_SUCCESS( Status ) )
  1456. {
  1457. Status = AdjustStatus;
  1458. }
  1459. }
  1460. } else {
  1461. NOTHING;
  1462. }
  1463. //
  1464. // We're finished with the token handle
  1465. //
  1466. NtClose(TokenToAssign);
  1467. if (!NT_SUCCESS(Status)) {
  1468. BaseSetLastNTError(Status);
  1469. }
  1470. return (NT_SUCCESS(Status));
  1471. }
  1472. //+---------------------------------------------------------------------------
  1473. //
  1474. // Function: L32SetProcessQuotas
  1475. //
  1476. // Synopsis: Updates the quotas for the process
  1477. //
  1478. // Arguments: [hProcess] --
  1479. //
  1480. // History: 4-25-95 RichardW Created
  1481. //
  1482. // Notes:
  1483. //
  1484. //----------------------------------------------------------------------------
  1485. BOOL
  1486. L32SetProcessQuotas(
  1487. HANDLE hProcess,
  1488. BOOL AlreadyImpersonating )
  1489. {
  1490. NTSTATUS Status = STATUS_SUCCESS;
  1491. NTSTATUS AdjustStatus = STATUS_SUCCESS;
  1492. QUOTA_LIMITS RequestedLimits;
  1493. BOOLEAN WasEnabled;
  1494. HANDLE NullHandle;
  1495. RequestedLimits = Logon32QuotaLimits;
  1496. RequestedLimits.MinimumWorkingSetSize = 0;
  1497. RequestedLimits.MaximumWorkingSetSize = 0;
  1498. //
  1499. // Set the process's quota. This MUST be
  1500. // called when we are not impersonating! The client generally does *not*
  1501. // have the SeIncreaseQuota privilege.
  1502. //
  1503. if ( !AlreadyImpersonating )
  1504. {
  1505. Status = RtlImpersonateSelf( SecurityImpersonation );
  1506. }
  1507. if ( NT_SUCCESS( Status ) )
  1508. {
  1509. if (RequestedLimits.PagedPoolLimit != 0) {
  1510. Status = RtlAdjustPrivilege(SE_INCREASE_QUOTA_PRIVILEGE, TRUE,
  1511. TRUE, &WasEnabled);
  1512. if ( NT_SUCCESS( Status ) )
  1513. {
  1514. Status = NtSetInformationProcess(
  1515. hProcess,
  1516. ProcessQuotaLimits,
  1517. (PVOID)&RequestedLimits,
  1518. (ULONG)sizeof(QUOTA_LIMITS)
  1519. );
  1520. if (!WasEnabled)
  1521. {
  1522. AdjustStatus = RtlAdjustPrivilege(SE_INCREASE_QUOTA_PRIVILEGE,
  1523. WasEnabled, FALSE, &WasEnabled);
  1524. if (NT_SUCCESS(Status)) {
  1525. Status = AdjustStatus;
  1526. }
  1527. }
  1528. }
  1529. }
  1530. if ( !AlreadyImpersonating )
  1531. {
  1532. NullHandle = NULL;
  1533. AdjustStatus = NtSetInformationThread(
  1534. NtCurrentThread(),
  1535. ThreadImpersonationToken,
  1536. (PVOID) &NullHandle,
  1537. sizeof( HANDLE ) );
  1538. if ( NT_SUCCESS( Status ) )
  1539. {
  1540. Status = AdjustStatus;
  1541. }
  1542. }
  1543. }
  1544. if (!NT_SUCCESS(Status))
  1545. {
  1546. BaseSetLastNTError(Status);
  1547. return(FALSE);
  1548. }
  1549. return(TRUE);
  1550. }
  1551. //+---------------------------------------------------------------------------
  1552. //
  1553. // Function: L32CommonCreate
  1554. //
  1555. // Synopsis:
  1556. //
  1557. // Effects:
  1558. //
  1559. // Arguments: [CreateFlags] -- Flags (see top of file)
  1560. // [hToken] -- Primary token to use
  1561. // [lpProcessInfo] -- Process Info
  1562. //
  1563. // History: 1-20-95 RichardW Created
  1564. //
  1565. // Notes:
  1566. //
  1567. //----------------------------------------------------------------------------
  1568. BOOL
  1569. L32CommonCreate(
  1570. DWORD CreateFlags,
  1571. HANDLE hToken,
  1572. LPPROCESS_INFORMATION lpProcessInfo
  1573. )
  1574. {
  1575. PTOKEN_DEFAULT_DACL pDefDacl;
  1576. DWORD cDefDacl = 0;
  1577. NTSTATUS Status;
  1578. PSECURITY_DESCRIPTOR psd;
  1579. unsigned char buf[SECURITY_DESCRIPTOR_MIN_LENGTH];
  1580. BOOL Success = TRUE;
  1581. TOKEN_TYPE Type;
  1582. DWORD dummy;
  1583. HANDLE hThreadToken;
  1584. HANDLE hNull;
  1585. BOOL UsingImpToken = FALSE ;
  1586. #ifdef ALLOW_IMPERSONATION_TOKENS
  1587. HANDLE hTempToken;
  1588. #endif
  1589. //
  1590. // Determine type of token, since a non primary token will not work
  1591. // on a process. Now, we could duplicate it into a primary token,
  1592. // and whack it into the process, but that leaves the process possibly
  1593. // without credentials.
  1594. //
  1595. Status = NtQueryInformationToken(hToken, TokenType,
  1596. (PUCHAR) &Type, sizeof(Type), &dummy);
  1597. if (!NT_SUCCESS(Status))
  1598. {
  1599. BaseSetLastNTError(Status);
  1600. NtTerminateProcess(lpProcessInfo->hProcess, ERROR_ACCESS_DENIED);
  1601. NtClose(lpProcessInfo->hProcess);
  1602. NtClose(lpProcessInfo->hThread);
  1603. RtlZeroMemory( lpProcessInfo, sizeof( PROCESS_INFORMATION ) );
  1604. return(FALSE);
  1605. }
  1606. if (Type != TokenPrimary)
  1607. {
  1608. #ifdef ALLOW_IMPERSONATION_TOKENS
  1609. OBJECT_ATTRIBUTES ObjectAttributes;
  1610. InitializeObjectAttributes(
  1611. &ObjectAttributes,
  1612. NULL,
  1613. 0L,
  1614. NULL,
  1615. NULL);
  1616. SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  1617. SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
  1618. SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  1619. SecurityQualityOfService.EffectiveOnly = FALSE;
  1620. ObjectAttributes.SecurityQualityOfService = &SecurityQualityOfService;
  1621. Status = NtDuplicateToken( hToken,
  1622. TOKEN_IMPERSONATE | TOKEN_QUERY,
  1623. &ObjectAttributes,
  1624. FALSE,
  1625. TokenPrimary,
  1626. &hTempToken
  1627. );
  1628. if (!NT_SUCCESS(Status))
  1629. {
  1630. BaseSetLastNTError(Status);
  1631. NtTerminateProcess(lpProcessInfo->hProcess, ERROR_ACCESS_DENIED);
  1632. NtClose(lpProcessInfo->hProcess);
  1633. NtClose(lpProcessInfo->hThread);
  1634. RtlZeroMemory( lpProcessInfo, sizeof( PROCESS_INFORMATION ) );
  1635. return(FALSE);
  1636. }
  1637. hToken = hTempToken;
  1638. #else // !ALLOW_IMPERSONATION_TOKENS
  1639. BaseSetLastNTError(STATUS_BAD_TOKEN_TYPE);
  1640. NtTerminateProcess(lpProcessInfo->hProcess, ERROR_ACCESS_DENIED);
  1641. NtClose(lpProcessInfo->hProcess);
  1642. NtClose(lpProcessInfo->hThread);
  1643. RtlZeroMemory( lpProcessInfo, sizeof( PROCESS_INFORMATION ) );
  1644. return(FALSE);
  1645. #endif
  1646. }
  1647. #ifdef ALLOW_IMPERSONATION_TOKENS
  1648. else
  1649. {
  1650. hTempToken = NULL;
  1651. }
  1652. #endif
  1653. //
  1654. // Okay, get the default DACL from the token. This DACL will be
  1655. // applied to the process. Note that the creator of this process may
  1656. // not be able to open it again after the DACL is applied. However,
  1657. // since the caller already has a valid handle (in ProcessInfo), they
  1658. // can keep doing things.
  1659. //
  1660. pDefDacl = NULL;
  1661. Status = NtQueryInformationToken(hToken,
  1662. TokenDefaultDacl,
  1663. NULL, 0, &cDefDacl);
  1664. if (NT_SUCCESS(Status) || (Status == STATUS_BUFFER_TOO_SMALL))
  1665. {
  1666. pDefDacl = RtlAllocateHeap(RtlProcessHeap(), HEAP_ZERO_MEMORY, cDefDacl);
  1667. if (pDefDacl)
  1668. {
  1669. Status = NtQueryInformationToken( hToken,
  1670. TokenDefaultDacl,
  1671. pDefDacl, cDefDacl,
  1672. &cDefDacl);
  1673. }
  1674. else
  1675. {
  1676. Status = STATUS_NO_MEMORY;
  1677. }
  1678. }
  1679. if (!NT_SUCCESS(Status))
  1680. {
  1681. if (pDefDacl)
  1682. {
  1683. RtlFreeHeap(RtlProcessHeap(), 0, pDefDacl);
  1684. }
  1685. //
  1686. // Our failure mantra: Set the last error, kill the process (since it
  1687. // is suspended, and hasn't actually started yet, we can do this safely)
  1688. // close the handles, and return false.
  1689. //
  1690. #ifdef ALLOW_IMPERSONATION_TOKENS
  1691. if (hTempToken)
  1692. {
  1693. NtClose( hTempToken );
  1694. }
  1695. #endif
  1696. BaseSetLastNTError(Status);
  1697. NtTerminateProcess(lpProcessInfo->hProcess, ERROR_ACCESS_DENIED);
  1698. NtClose(lpProcessInfo->hProcess);
  1699. NtClose(lpProcessInfo->hThread);
  1700. RtlZeroMemory( lpProcessInfo, sizeof( PROCESS_INFORMATION ) );
  1701. return(FALSE);
  1702. }
  1703. psd = (PSECURITY_DESCRIPTOR) buf;
  1704. InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION);
  1705. SetSecurityDescriptorDacl(psd, TRUE, pDefDacl->DefaultDacl, FALSE);
  1706. if (CreateFlags & (COMMON_CREATE_PROCESSSD | COMMON_CREATE_THREADSD))
  1707. {
  1708. //
  1709. // Now, based on what we're told:
  1710. //
  1711. if (CreateFlags & COMMON_CREATE_PROCESSSD)
  1712. {
  1713. Success = SetKernelObjectSecurity( lpProcessInfo->hProcess,
  1714. DACL_SECURITY_INFORMATION,
  1715. psd);
  1716. }
  1717. //
  1718. // Ah, WOW apps created through here don't have thread handles,
  1719. // so check:
  1720. //
  1721. if ((Success) &&
  1722. (CreateFlags & COMMON_CREATE_THREADSD))
  1723. {
  1724. if ( lpProcessInfo->hThread )
  1725. {
  1726. Success = SetKernelObjectSecurity( lpProcessInfo->hThread,
  1727. DACL_SECURITY_INFORMATION,
  1728. psd);
  1729. }
  1730. }
  1731. }
  1732. else
  1733. {
  1734. Success = TRUE;
  1735. }
  1736. if (Success)
  1737. {
  1738. //
  1739. // Unfortunately, this is usually called when we are impersonating,
  1740. // because one does not want to start a process for a user that he
  1741. // does not actually have access to. However, this user also does
  1742. // not have (usually) AssignPrimary and IncreaseQuota privileges.
  1743. // So, if we are impersonating, we open the thread token, then
  1744. // stop impersonating, saving the token away to restore later.
  1745. //
  1746. Status = NtOpenThreadToken( NtCurrentThread(),
  1747. TOKEN_IMPERSONATE,
  1748. TRUE,
  1749. &hThreadToken);
  1750. if (NT_SUCCESS(Status))
  1751. {
  1752. //
  1753. // Okay, stop impersonating:
  1754. //
  1755. hNull = NULL;
  1756. Status = NtSetInformationThread(
  1757. NtCurrentThread(),
  1758. ThreadImpersonationToken,
  1759. (PVOID) &hNull,
  1760. sizeof(hNull)
  1761. );
  1762. }
  1763. else
  1764. {
  1765. hThreadToken = NULL;
  1766. }
  1767. //
  1768. // Okay, we've set the process security descriptor. Now, set the
  1769. // process primary token to the right thing
  1770. //
  1771. Success = L32SetProcessToken( psd,
  1772. lpProcessInfo->hProcess,
  1773. lpProcessInfo->hThread,
  1774. hToken,
  1775. FALSE );
  1776. if ( !Success && hThreadToken )
  1777. {
  1778. Status = NtSetInformationThread(
  1779. NtCurrentThread(),
  1780. ThreadImpersonationToken,
  1781. (PVOID) &hThreadToken,
  1782. sizeof(hThreadToken)
  1783. );
  1784. UsingImpToken = TRUE ;
  1785. Success = L32SetProcessToken(
  1786. psd,
  1787. lpProcessInfo->hProcess,
  1788. lpProcessInfo->hThread,
  1789. hToken,
  1790. TRUE );
  1791. }
  1792. if ( Success )
  1793. {
  1794. #ifdef ALLOW_IMPERSONATION_TOKENS
  1795. if (hTempToken)
  1796. {
  1797. NtClose(hTempToken);
  1798. }
  1799. #endif
  1800. //
  1801. // That worked. Now adjust the quota to be something reasonable
  1802. //
  1803. Success = L32SetProcessQuotas(
  1804. lpProcessInfo->hProcess,
  1805. UsingImpToken );
  1806. if ( (!Success) &&
  1807. (hThreadToken != NULL) &&
  1808. (UsingImpToken == FALSE ) )
  1809. {
  1810. Status = NtSetInformationThread(
  1811. NtCurrentThread(),
  1812. ThreadImpersonationToken,
  1813. (PVOID) &hThreadToken,
  1814. sizeof(hThreadToken)
  1815. );
  1816. UsingImpToken = TRUE ;
  1817. Success = L32SetProcessQuotas(
  1818. lpProcessInfo->hProcess,
  1819. TRUE );
  1820. }
  1821. if ( Success )
  1822. {
  1823. //
  1824. // If we're not supposed to leave it suspended, resume the
  1825. // thread and let it run...
  1826. //
  1827. if ((CreateFlags & COMMON_CREATE_SUSPENDED) == 0)
  1828. {
  1829. ResumeThread(lpProcessInfo->hThread);
  1830. }
  1831. RtlFreeHeap(RtlProcessHeap(), 0, pDefDacl);
  1832. if (hThreadToken)
  1833. {
  1834. Status = NtSetInformationThread(
  1835. NtCurrentThread(),
  1836. ThreadImpersonationToken,
  1837. (PVOID) &hThreadToken,
  1838. sizeof(hThreadToken)
  1839. );
  1840. NtClose(hThreadToken);
  1841. }
  1842. return(TRUE);
  1843. }
  1844. }
  1845. //
  1846. // If we were impersonating before, resume impersonating here
  1847. //
  1848. if (hThreadToken)
  1849. {
  1850. Status = NtSetInformationThread(
  1851. NtCurrentThread(),
  1852. ThreadImpersonationToken,
  1853. (PVOID) &hThreadToken,
  1854. sizeof(hThreadToken)
  1855. );
  1856. //
  1857. // Done with this now.
  1858. //
  1859. NtClose(hThreadToken);
  1860. }
  1861. }
  1862. //
  1863. // Failure mantra again...
  1864. //
  1865. if (pDefDacl)
  1866. {
  1867. RtlFreeHeap(RtlProcessHeap(), 0, pDefDacl);
  1868. }
  1869. NtTerminateProcess(lpProcessInfo->hProcess, ERROR_ACCESS_DENIED);
  1870. NtClose(lpProcessInfo->hProcess);
  1871. NtClose(lpProcessInfo->hThread);
  1872. RtlZeroMemory( lpProcessInfo, sizeof( PROCESS_INFORMATION ) );
  1873. return(FALSE);
  1874. }
  1875. //+---------------------------------------------------------------------------
  1876. //
  1877. // Function: SaferiReplaceProcessThreadTokens
  1878. //
  1879. // Synopsis:
  1880. // Provides a privately exported function to replace the access token
  1881. // of a process and its primary thread of a new process before its
  1882. // execution has begun. The process is left in a suspended state
  1883. // after the token modification has been performed.
  1884. //
  1885. // Effects:
  1886. //
  1887. // Arguments: [NewTokenHandle] -- Primary token to use
  1888. // [ProcessHandle] -- Process handle
  1889. // [ThreadHandle] -- Handle of process's primary Thread
  1890. //
  1891. // History: 8-25-2000 JLawson Created
  1892. //
  1893. // Notes:
  1894. // This is merely a wrapper function that calls L32CommonCreate.
  1895. //
  1896. //----------------------------------------------------------------------------
  1897. BOOL
  1898. WINAPI
  1899. SaferiReplaceProcessThreadTokens(
  1900. IN HANDLE NewTokenHandle,
  1901. IN HANDLE ProcessHandle,
  1902. IN HANDLE ThreadHandle
  1903. )
  1904. {
  1905. PROCESS_INFORMATION TempProcessInfo;
  1906. RtlZeroMemory( &TempProcessInfo, sizeof( PROCESS_INFORMATION ) );
  1907. TempProcessInfo.hProcess = ProcessHandle;
  1908. TempProcessInfo.hThread = ThreadHandle;
  1909. return (L32CommonCreate(
  1910. COMMON_CREATE_PROCESSSD | COMMON_CREATE_THREADSD |
  1911. COMMON_CREATE_SUSPENDED,
  1912. NewTokenHandle,
  1913. &TempProcessInfo));
  1914. }
  1915. //+---------------------------------------------------------------------------
  1916. //
  1917. // MarshallString
  1918. //
  1919. // Marshall in a UNICODE_NULL terminated WCHAR string
  1920. //
  1921. // ENTRY:
  1922. // pSource (input)
  1923. // Pointer to source string
  1924. //
  1925. // pBase (input)
  1926. // Base buffer pointer for normalizing the string pointer
  1927. //
  1928. // MaxSize (input)
  1929. // Maximum buffer size available
  1930. //
  1931. // ppPtr (input/output)
  1932. // Pointer to the current context pointer in the marshall buffer.
  1933. // This is updated as data is marshalled into the buffer
  1934. //
  1935. // pCount (input/output)
  1936. // Current count of data in the marshall buffer.
  1937. // This is updated as data is marshalled into the buffer
  1938. //
  1939. // EXIT:
  1940. // NULL - Error
  1941. // !=NULL "normalized" pointer to the string in reference to pBase
  1942. //
  1943. //+---------------------------------------------------------------------------
  1944. PWCHAR
  1945. MarshallString(
  1946. PCWSTR pSource,
  1947. PCHAR pBase,
  1948. ULONG MaxSize,
  1949. PCHAR *ppPtr,
  1950. PULONG pCount
  1951. )
  1952. {
  1953. ULONG Len;
  1954. PCHAR ptr;
  1955. Len = wcslen( pSource );
  1956. Len++; // include the NULL;
  1957. Len *= sizeof(WCHAR); // convert to bytes
  1958. if( (*pCount + Len) > MaxSize ) {
  1959. return( NULL );
  1960. }
  1961. RtlMoveMemory( *ppPtr, pSource, Len );
  1962. //
  1963. // the normalized ptr is the current count
  1964. //
  1965. // Sundown note: ptr is a zero-extension of *pCount.
  1966. ptr = (PCHAR)ULongToPtr(*pCount);
  1967. *ppPtr += Len;
  1968. *pCount += Len;
  1969. return((PWCHAR)ptr);
  1970. }
  1971. #if DBG
  1972. void DumpOutLastErrorString()
  1973. {
  1974. LPVOID lpMsgBuf;
  1975. FormatMessage(
  1976. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  1977. FORMAT_MESSAGE_FROM_SYSTEM |
  1978. FORMAT_MESSAGE_IGNORE_INSERTS,
  1979. NULL,
  1980. GetLastError(),
  1981. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  1982. (LPTSTR) &lpMsgBuf,
  1983. 0,
  1984. NULL
  1985. );
  1986. //
  1987. // Process any inserts in lpMsgBuf.
  1988. // ...
  1989. // Display the string.
  1990. //
  1991. KdPrint(("%s\n", (LPCTSTR)lpMsgBuf ));
  1992. //
  1993. // Free the buffer.
  1994. //
  1995. LocalFree( lpMsgBuf );
  1996. }
  1997. #endif
  1998. #ifdef DBG
  1999. #define DBG_DumpOutLastError DumpOutLastErrorString();
  2000. #else
  2001. #define DBG_DumpOutLastError
  2002. #endif
  2003. //+---------------------------------------------------------------------------
  2004. //
  2005. // This function was originally defined in \nt\private\ole32\dcomss\olescm\execclt.cxx
  2006. //
  2007. // CreateRemoteSessionProcessW()
  2008. //
  2009. // Create a process on the given Terminal Server Session. This is in UNICODE
  2010. //
  2011. // ENTRY:
  2012. // SessionId (input)
  2013. // SessionId of Session to create process on
  2014. //
  2015. // Param1 (input/output)
  2016. // Comments
  2017. //
  2018. // Comments
  2019. // The security attribs are not used by the session, they are set to NULL
  2020. // We may consider to extend this feature in the future, assuming there is a
  2021. // need for it.
  2022. //
  2023. // EXIT:
  2024. // STATUS_SUCCESS - no error
  2025. //+---------------------------------------------------------------------------
  2026. BOOL
  2027. CreateRemoteSessionProcessW(
  2028. ULONG SessionId,
  2029. BOOL System,
  2030. HANDLE hToken,
  2031. PCWSTR lpszImageName,
  2032. PCWSTR lpszCommandLine,
  2033. PSECURITY_ATTRIBUTES psaProcess, // these are ignored on the session side, set to NULL
  2034. PSECURITY_ATTRIBUTES psaThread, // these are ignored on the session side, set to NULL
  2035. BOOL fInheritHandles,
  2036. DWORD fdwCreate,
  2037. LPVOID lpvEnvionment,
  2038. LPCWSTR lpszCurDir,
  2039. LPSTARTUPINFOW pStartInfo,
  2040. LPPROCESS_INFORMATION pProcInfo
  2041. )
  2042. {
  2043. BOOL Result = TRUE;
  2044. HANDLE hPipe = NULL;
  2045. WCHAR szPipeName[MAX_PATH];
  2046. PCHAR ptr;
  2047. ULONG Count, AmountWrote, AmountRead;
  2048. DWORD MyProcId;
  2049. PEXECSRV_REQUEST pReq;
  2050. EXECSRV_REPLY Rep;
  2051. CHAR Buf[EXECSRV_BUFFER_SIZE];
  2052. ULONG MaxSize = EXECSRV_BUFFER_SIZE;
  2053. DWORD rc;
  2054. LPVOID lpMsgBuf;
  2055. ULONG envSize=0; // size of the lpEnvironemt, if any
  2056. PWCHAR lpEnv;
  2057. #if DBG
  2058. if( lpszImageName )
  2059. KdPrint(("logon32.c: CreateRemoteSessionProcessW: lpszImageName %ws\n",lpszImageName));
  2060. if( lpszCommandLine )
  2061. KdPrint(("logon32.c: CreateRemoteSessionProcessW: lpszCommandLine %ws\n",lpszCommandLine));
  2062. #endif
  2063. //
  2064. // Winlogon handles all now. System flag tells it what to do
  2065. //
  2066. swprintf(szPipeName, EXECSRV_SYSTEM_PIPE_NAME, SessionId);
  2067. while ( TRUE )
  2068. {
  2069. hPipe = CreateFileW(
  2070. szPipeName,
  2071. GENERIC_READ|GENERIC_WRITE,
  2072. 0, // File share mode
  2073. NULL, // default security
  2074. OPEN_EXISTING,
  2075. 0, // Attrs and flags
  2076. NULL // template file handle
  2077. );
  2078. if( hPipe == INVALID_HANDLE_VALUE )
  2079. {
  2080. if (GetLastError() == ERROR_PIPE_BUSY)
  2081. {
  2082. if (!WaitNamedPipeW( szPipeName, 30000 ))
  2083. { // 30 sec
  2084. KdPrint(("logon32.c: Waited too long for pipe name %ws\n", szPipeName));
  2085. return(FALSE);
  2086. }
  2087. }
  2088. else
  2089. {
  2090. DBG_DumpOutLastError;
  2091. KdPrint(("logon32.c: Could not create pipe name %ws\n", szPipeName));
  2092. return(FALSE);
  2093. }
  2094. }
  2095. else
  2096. {
  2097. break;
  2098. }
  2099. }
  2100. //
  2101. // Get the handle to the current process
  2102. //
  2103. MyProcId = GetCurrentProcessId();
  2104. //
  2105. // setup the marshalling
  2106. //
  2107. ptr = Buf;
  2108. Count = 0;
  2109. pReq = (PEXECSRV_REQUEST)ptr;
  2110. ptr += sizeof(EXECSRV_REQUEST);
  2111. Count += sizeof(EXECSRV_REQUEST);
  2112. //
  2113. // set the basic parameters
  2114. //
  2115. pReq->System = System;
  2116. pReq->hToken = hToken;
  2117. pReq->RequestingProcessId = MyProcId;
  2118. pReq->fInheritHandles = fInheritHandles;
  2119. pReq->fdwCreate = fdwCreate;
  2120. //
  2121. // marshall the ImageName string
  2122. //
  2123. if( lpszImageName ) {
  2124. pReq->lpszImageName = MarshallString( lpszImageName, Buf, MaxSize, &ptr, &Count );
  2125. if (! pReq->lpszImageName)
  2126. {
  2127. Result = FALSE;
  2128. goto Cleanup;
  2129. }
  2130. }
  2131. else {
  2132. pReq->lpszImageName = NULL;
  2133. }
  2134. //
  2135. // marshall in the CommandLine string
  2136. //
  2137. if( lpszCommandLine ) {
  2138. pReq->lpszCommandLine = MarshallString( lpszCommandLine, Buf, MaxSize, &ptr, &Count );
  2139. if ( ! pReq->lpszCommandLine )
  2140. {
  2141. Result = FALSE;
  2142. goto Cleanup;
  2143. }
  2144. }
  2145. else {
  2146. pReq->lpszCommandLine = NULL;
  2147. }
  2148. //
  2149. // marshall in the CurDir string
  2150. //
  2151. if( lpszCurDir ) {
  2152. pReq->lpszCurDir = MarshallString( lpszCurDir, Buf, MaxSize, &ptr, &Count );
  2153. if ( ! pReq->lpszCurDir )
  2154. {
  2155. Result = FALSE;
  2156. goto Cleanup;
  2157. }
  2158. }
  2159. else {
  2160. pReq->lpszCurDir = NULL;
  2161. }
  2162. //
  2163. // marshall in the StartupInfo structure
  2164. //
  2165. RtlMoveMemory( &pReq->StartInfo, pStartInfo, sizeof(STARTUPINFO) );
  2166. //
  2167. // Now marshall the strings in STARTUPINFO
  2168. //
  2169. if( pStartInfo->lpDesktop ) {
  2170. pReq->StartInfo.lpDesktop = MarshallString( pStartInfo->lpDesktop, Buf, MaxSize, &ptr, &Count );
  2171. if (! pReq->StartInfo.lpDesktop )
  2172. {
  2173. Result = FALSE;
  2174. goto Cleanup;
  2175. }
  2176. }
  2177. else {
  2178. pReq->StartInfo.lpDesktop = NULL;
  2179. }
  2180. if( pStartInfo->lpTitle ) {
  2181. pReq->StartInfo.lpTitle = MarshallString( pStartInfo->lpTitle, Buf, MaxSize, &ptr, &Count );
  2182. if ( !pReq->StartInfo.lpTitle )
  2183. {
  2184. Result = FALSE;
  2185. goto Cleanup;
  2186. }
  2187. }
  2188. else {
  2189. pReq->StartInfo.lpTitle = NULL;
  2190. }
  2191. //
  2192. // WARNING: This version does not pass the following:
  2193. //
  2194. // Also saProcess and saThread are ignored right now and use
  2195. // the users default security on the remote WinStation
  2196. //
  2197. // Set things that are always NULL
  2198. //
  2199. pReq->StartInfo.lpReserved = NULL; // always NULL
  2200. if ( lpvEnvionment)
  2201. {
  2202. for ( lpEnv = (PWCHAR) lpvEnvionment;
  2203. (*lpEnv ) && (envSize + Count < MaxSize ) ; lpEnv++)
  2204. {
  2205. while( *lpEnv )
  2206. {
  2207. lpEnv++;
  2208. envSize += 2; // we are dealing with wide chars
  2209. if ( envSize+Count >= MaxSize )
  2210. {
  2211. // we have too many
  2212. // vars in the user's profile.
  2213. KdPrint(("\tEnv length too big = %d \n", envSize));
  2214. break;
  2215. }
  2216. }
  2217. // this is the null which marked the end of the last env var.
  2218. envSize +=2;
  2219. }
  2220. envSize += 2; // this is the final NULL
  2221. if ( Count + envSize < MaxSize )
  2222. {
  2223. RtlMoveMemory( (PCHAR)&Buf[Count] ,lpvEnvionment, envSize );
  2224. // SUNDOWN: Count is zero-extended and store in lpvEnvironment.
  2225. // This zero-extension is valid. The consuming code [see tsext\notify\execsrv.c]
  2226. // considers lpvEnvironment as an offset (<2GB).
  2227. pReq->lpvEnvironment = (PCHAR)ULongToPtr(Count);
  2228. ptr += envSize; // for the next guy
  2229. Count += envSize; // the count used so far
  2230. }
  2231. else // no room left to make a complete copy
  2232. {
  2233. pReq->lpvEnvironment = NULL;
  2234. }
  2235. }
  2236. else
  2237. {
  2238. pReq->lpvEnvironment = NULL;
  2239. }
  2240. //
  2241. // now fill in the total count
  2242. //
  2243. pReq->Size = Count;
  2244. #if DBG
  2245. KdPrint(("pReq->Size = %d, envSize = %d \n", pReq->Size , envSize ));
  2246. #endif
  2247. //
  2248. // Now send the buffer out to the server
  2249. //
  2250. Result = WriteFile(
  2251. hPipe,
  2252. Buf,
  2253. Count,
  2254. &AmountWrote,
  2255. NULL
  2256. );
  2257. if( !Result ) {
  2258. KdPrint(("logon32.c: Error %d sending request\n",GetLastError() ));
  2259. goto Cleanup;
  2260. }
  2261. //
  2262. // Now read the reply
  2263. //
  2264. Result = ReadFile(
  2265. hPipe,
  2266. &Rep,
  2267. sizeof(Rep),
  2268. &AmountRead,
  2269. NULL
  2270. );
  2271. if( !Result ) {
  2272. KdPrint(("logon32.c: Error %d reading reply\n",GetLastError()));
  2273. goto Cleanup;
  2274. }
  2275. //
  2276. // Check the result
  2277. //
  2278. if( !Rep.Result ) {
  2279. KdPrint(("logon32.c: Error %d in reply\n",Rep.LastError));
  2280. //
  2281. // set the error in the current thread to the returned error
  2282. //
  2283. Result = Rep.Result;
  2284. SetLastError( Rep.LastError );
  2285. goto Cleanup;
  2286. }
  2287. //
  2288. // We copy the PROCESS_INFO structure from the reply
  2289. // to the caller.
  2290. //
  2291. // The remote site has duplicated the handles into our
  2292. // process space for hProcess and hThread so that they will
  2293. // behave like CreateProcessW()
  2294. //
  2295. RtlMoveMemory( pProcInfo, &Rep.ProcInfo, sizeof( PROCESS_INFORMATION ) );
  2296. Cleanup:
  2297. CloseHandle(hPipe);
  2298. KdPrint(("logon32.c:: Result 0x%x\n", Result));
  2299. return(Result);
  2300. }
  2301. //+---------------------------------------------------------------------------
  2302. //
  2303. // Function: CreateProcessAsUserW
  2304. //
  2305. // Synopsis: Creates a process running as the user in hToken.
  2306. //
  2307. // Arguments: [hToken] -- Handle to a Primary Token to use
  2308. // [lpApplicationName] -- as CreateProcess() q.v.
  2309. // [lpCommandLine] --
  2310. // [lpProcessAttributes] --
  2311. // [lpThreadAttributes] --
  2312. // [bInheritHandles] --
  2313. // [dwCreationFlags] --
  2314. // [lpEnvironment] --
  2315. // [lpCurrentDirectory] --
  2316. // [lpStartupInfo] --
  2317. // [lpProcessInformation] --
  2318. //
  2319. // Return Values
  2320. // If the function succeeds, the return value is nonzero.
  2321. // If the function fails, the return value is zero. To get extended error information, call GetLastError.
  2322. //
  2323. // History: 4-25-95 RichardW Created
  2324. // 1-14-98 AraBern add changes for Hydra
  2325. // Notes:
  2326. //
  2327. //
  2328. //----------------------------------------------------------------------------
  2329. BOOL
  2330. WINAPI
  2331. CreateProcessAsUserW(
  2332. HANDLE hToken,
  2333. LPCWSTR lpApplicationName,
  2334. LPWSTR lpCommandLine,
  2335. LPSECURITY_ATTRIBUTES lpProcessAttributes,
  2336. LPSECURITY_ATTRIBUTES lpThreadAttributes,
  2337. BOOL bInheritHandles,
  2338. DWORD dwCreationFlags,
  2339. LPVOID lpEnvironment,
  2340. LPCWSTR lpCurrentDirectory,
  2341. LPSTARTUPINFOW lpStartupInfo,
  2342. LPPROCESS_INFORMATION lpProcessInformation
  2343. )
  2344. {
  2345. DWORD CreateFlags;
  2346. DWORD clientSessionID=0;
  2347. DWORD currentSessionID=0;
  2348. DWORD resultLength;
  2349. HANDLE hTmpToken;
  2350. DWORD curProcId ;
  2351. NTSTATUS Status ;
  2352. CreateFlags = (dwCreationFlags & CREATE_SUSPENDED ? COMMON_CREATE_SUSPENDED : 0);
  2353. //
  2354. // get the sessionID (if zero then it means that we are on the console).
  2355. //
  2356. currentSessionID = NtCurrentPeb()->SessionId;
  2357. if ( !GetTokenInformation ( hToken, TokenSessionId , &clientSessionID,sizeof( DWORD), &resultLength ) )
  2358. {
  2359. //
  2360. // get the access token for the client of this call
  2361. // get token instead of process since the client might have only
  2362. // impersonated the thread, not the process
  2363. //
  2364. DBG_DumpOutLastError;
  2365. ASSERT( FALSE );
  2366. currentSessionID = 0;
  2367. //
  2368. // We should probably return FALSE here, but at this time we don't want to alter the
  2369. // non-Hydra code-execution-flow at all.
  2370. //
  2371. }
  2372. // KdPrint(("logon32.c: CreateProcessAsUserW(): clientSessionID = %d, currentSessionID = %d \n",
  2373. // clientSessionID, currentSessionID ));
  2374. if ( clientSessionID != currentSessionID )
  2375. {
  2376. //
  2377. // If the client session ID is not the same as the current session ID, then, we are attempting
  2378. // to create a process on a remote session from the current session.
  2379. // This block of code is used to accomplish such process creation, it is Terminal-Server specific
  2380. //
  2381. BOOL bHaveImpersonated;
  2382. HANDLE hCurrentThread;
  2383. HANDLE hPrevToken = NULL;
  2384. DWORD rc;
  2385. TOKEN_TYPE tokenType;
  2386. //
  2387. // We must send the request to the remote session
  2388. // of the requestor
  2389. //
  2390. // NOTE: The current WinStationCreateProcessW() does not use
  2391. // the supplied security descriptor, but creates the
  2392. // process under the account of the logged on user.
  2393. //
  2394. //
  2395. // Stop impersonating before doing the WinStationCreateProcess.
  2396. // The remote winstation exec thread will launch the app under
  2397. // the users context. We must not be impersonating because this
  2398. // call only lets SYSTEM request the remote execute.
  2399. //
  2400. //
  2401. // Handle Inheritance is not allowed for cross session process creation
  2402. //
  2403. if (bInheritHandles) {
  2404. SetLastError(ERROR_INVALID_PARAMETER);
  2405. return FALSE;
  2406. }
  2407. hCurrentThread = GetCurrentThread();
  2408. //
  2409. // Init bHaveImpersonated to the FALSE state
  2410. //
  2411. bHaveImpersonated = FALSE;
  2412. //
  2413. // Since the caller of this function (runas-> SecLogon service ) has already
  2414. // impersonated the new (target) user, we do the OpenThreadToken with
  2415. // OpenAsSelf = TRUE
  2416. //
  2417. if ( OpenThreadToken( hCurrentThread, TOKEN_QUERY, TRUE, &hPrevToken ) )
  2418. {
  2419. bHaveImpersonated = TRUE;
  2420. if ( !RevertToSelf() )
  2421. {
  2422. return FALSE;
  2423. }
  2424. }
  2425. //
  2426. // else, we are not impersonating, as reflected by the init value of bHaveImpersonated
  2427. //
  2428. rc = CreateRemoteSessionProcessW(
  2429. clientSessionID,
  2430. FALSE, // not creating a process for System
  2431. hToken,
  2432. lpApplicationName,
  2433. lpCommandLine,
  2434. lpProcessAttributes,
  2435. lpThreadAttributes,
  2436. bInheritHandles,
  2437. dwCreationFlags | CREATE_SEPARATE_WOW_VDM,
  2438. lpEnvironment,
  2439. lpCurrentDirectory,
  2440. lpStartupInfo,
  2441. lpProcessInformation) ;
  2442. //
  2443. // Undo the effect of RevertToSelf() if we had impersoanted
  2444. //
  2445. if ( bHaveImpersonated )
  2446. {
  2447. Status = NtSetInformationThread(
  2448. NtCurrentThread(),
  2449. ThreadImpersonationToken,
  2450. &hPrevToken,
  2451. sizeof( hPrevToken ) );
  2452. NtClose( hPrevToken );
  2453. }
  2454. if ( rc )
  2455. {
  2456. return TRUE;
  2457. }
  2458. else
  2459. {
  2460. return FALSE;
  2461. }
  2462. }
  2463. else
  2464. //
  2465. // this is the standard non-Hydra related call block
  2466. //
  2467. {
  2468. HANDLE hRestrictedToken = NULL;
  2469. BOOL b = FALSE;
  2470. if (!CreateProcessInternalW(hToken,
  2471. lpApplicationName,
  2472. lpCommandLine,
  2473. lpProcessAttributes,
  2474. lpThreadAttributes,
  2475. bInheritHandles,
  2476. (dwCreationFlags | CREATE_SUSPENDED |
  2477. CREATE_SEPARATE_WOW_VDM),
  2478. lpEnvironment,
  2479. lpCurrentDirectory,
  2480. lpStartupInfo,
  2481. lpProcessInformation,
  2482. &hRestrictedToken))
  2483. {
  2484. //
  2485. // The internal routine might return a token even in the failure case
  2486. // since it uses try-finally. Free the token if needed.
  2487. //
  2488. if (hRestrictedToken != NULL)
  2489. {
  2490. NtClose(hRestrictedToken);
  2491. }
  2492. return(FALSE);
  2493. }
  2494. CreateFlags |= (lpProcessAttributes ? 0 : COMMON_CREATE_PROCESSSD);
  2495. CreateFlags |= (lpThreadAttributes ? 0 : COMMON_CREATE_THREADSD);
  2496. //
  2497. // If a restricted token was returned, set it on the process.
  2498. // Else use the token provided by the caller.
  2499. //
  2500. if (hRestrictedToken == NULL)
  2501. {
  2502. b = (L32CommonCreate(CreateFlags, hToken, lpProcessInformation));
  2503. }
  2504. else
  2505. {
  2506. b = (L32CommonCreate(CreateFlags, hRestrictedToken, lpProcessInformation));
  2507. NtClose(hRestrictedToken);
  2508. }
  2509. return b;
  2510. }
  2511. }
  2512. /***************************************************************************\
  2513. * OemToCharW
  2514. *
  2515. * OemToCharW(pSrc, pDst) - Translates the OEM string at pSrc into
  2516. * the Unicode string at pDst. pSrc == pDst is not legal.
  2517. *
  2518. * History:
  2519. * This function was copied from NT\windows\Core\ntuser\client\oemxlate.c
  2520. *
  2521. \***************************************************************************/
  2522. BOOL WINAPI ConvertOemToCharW(
  2523. LPCSTR pSrc,
  2524. LPWSTR pDst)
  2525. {
  2526. int cch;
  2527. if (pSrc == NULL || pDst == NULL) {
  2528. return FALSE;
  2529. } else if (pSrc == (LPCSTR)pDst) {
  2530. /*
  2531. * MultiByteToWideChar() requires pSrc != pDst: fail this call.
  2532. * LATER: Is this really true?
  2533. */
  2534. return FALSE;
  2535. }
  2536. cch = strlen(pSrc) + 1;
  2537. MultiByteToWideChar(
  2538. CP_OEMCP, // Unicode -> OEM
  2539. MB_PRECOMPOSED | MB_USEGLYPHCHARS, // visual map to precomposed
  2540. (LPSTR)pSrc, cch, // source & length
  2541. pDst, // destination
  2542. cch); // max poss. precomposed length
  2543. return TRUE;
  2544. }
  2545. //----------------------------------------------------------------------------
  2546. //
  2547. // Function: OemToCharW_WithAllocation()
  2548. //
  2549. // Synopsis: This func will allocated memory for the string ppDst which
  2550. // must be then deallocatd thru a call to LocalFree().
  2551. // If the passed in ansi string is NULL, then no memory
  2552. // is allocated, and a NULL is returned
  2553. //
  2554. // Arguments:
  2555. // LPCSTR [in] ansi string for which we want the wide version
  2556. // *LPWSTR [out] the wide version of ansi string
  2557. // Return:
  2558. // BOOL : TRUE if no errors.
  2559. // BOOL : FALSE if unable to allocated memory.
  2560. //
  2561. //----------------------------------------------------------------------------
  2562. BOOL WINAPI OemToCharW_WithAllocation( LPCSTR pSrc,
  2563. LPWSTR *ppDst)
  2564. {
  2565. DWORD size;
  2566. if (pSrc)
  2567. {
  2568. size = strlen( pSrc );
  2569. *ppDst = ( WCHAR *) LocalAlloc(LMEM_FIXED, ( size + 1 ) * sizeof( WCHAR ) );
  2570. if ( ppDst )
  2571. {
  2572. ConvertOemToCharW( pSrc, *ppDst );
  2573. return TRUE;
  2574. }
  2575. else
  2576. return FALSE;
  2577. }
  2578. else
  2579. {
  2580. *ppDst = NULL;
  2581. return TRUE;
  2582. }
  2583. }
  2584. // ANSI wrapper for CreateRemoteSessionProcessW()
  2585. //
  2586. BOOL
  2587. CreateRemoteSessionProcessA(
  2588. ULONG SessionId,
  2589. BOOL System,
  2590. HANDLE hToken,
  2591. LPCSTR lpApplicationName,
  2592. LPSTR lpCommandLine,
  2593. LPSECURITY_ATTRIBUTES lpProcessAttributes,
  2594. LPSECURITY_ATTRIBUTES lpThreadAttributes,
  2595. BOOL bInheritHandles,
  2596. DWORD dwCreationFlags,
  2597. LPVOID lpEnvironment,
  2598. LPCSTR lpCurrentDirectory,
  2599. LPSTARTUPINFOA lpStartupInfo,
  2600. LPPROCESS_INFORMATION lpProcessInformation
  2601. )
  2602. {
  2603. NTSTATUS st;
  2604. BOOL rc,rc2;
  2605. STARTUPINFOW WCHAR_StartupInfo;
  2606. PWCHAR pWCHAR_AppName, pWCHAR_CommandLine, pWCHAR_CurDir, pWCHAR_Title, pWCHAR_Desktop;
  2607. pWCHAR_AppName = pWCHAR_CommandLine = pWCHAR_CurDir = pWCHAR_Title = pWCHAR_Desktop = NULL;
  2608. // in case there is a premature return from this function.
  2609. rc2 = FALSE;
  2610. if ( !( rc = OemToCharW_WithAllocation( lpApplicationName , &pWCHAR_AppName ) ))
  2611. {
  2612. goto Cleanup;
  2613. }
  2614. if ( !( rc = OemToCharW_WithAllocation( lpCommandLine , &pWCHAR_CommandLine ) ))
  2615. {
  2616. goto Cleanup;
  2617. }
  2618. if ( !( rc = OemToCharW_WithAllocation( lpCurrentDirectory , &pWCHAR_CurDir ) ))
  2619. {
  2620. goto Cleanup;
  2621. }
  2622. if ( !( rc = OemToCharW_WithAllocation( lpStartupInfo->lpTitle , &pWCHAR_Title ) ))
  2623. {
  2624. goto Cleanup;
  2625. }
  2626. if ( !( rc = OemToCharW_WithAllocation( lpStartupInfo->lpDesktop , &pWCHAR_Desktop ) ))
  2627. {
  2628. goto Cleanup;
  2629. }
  2630. WCHAR_StartupInfo.cb = lpStartupInfo->cb ;
  2631. WCHAR_StartupInfo.cbReserved2 = lpStartupInfo->cbReserved2;
  2632. WCHAR_StartupInfo.dwFillAttribute = lpStartupInfo->dwFillAttribute;
  2633. WCHAR_StartupInfo.dwFlags = lpStartupInfo->dwFlags;
  2634. WCHAR_StartupInfo.dwX = lpStartupInfo->dwX;
  2635. WCHAR_StartupInfo.dwXCountChars = lpStartupInfo->dwXCountChars;
  2636. WCHAR_StartupInfo.dwXSize = lpStartupInfo->dwXSize;
  2637. WCHAR_StartupInfo.dwY = lpStartupInfo->dwY;
  2638. WCHAR_StartupInfo.dwYCountChars = lpStartupInfo->dwYCountChars;
  2639. WCHAR_StartupInfo.dwYSize = lpStartupInfo->dwYSize;
  2640. WCHAR_StartupInfo.hStdError = lpStartupInfo->hStdError;
  2641. WCHAR_StartupInfo.hStdInput = lpStartupInfo->hStdInput;
  2642. WCHAR_StartupInfo.hStdOutput = lpStartupInfo->hStdOutput;
  2643. WCHAR_StartupInfo.lpReserved2 = lpStartupInfo->lpReserved2;
  2644. WCHAR_StartupInfo.wShowWindow = lpStartupInfo->wShowWindow;
  2645. WCHAR_StartupInfo.lpDesktop = pWCHAR_Desktop;
  2646. WCHAR_StartupInfo.lpReserved = NULL;
  2647. WCHAR_StartupInfo.lpTitle = pWCHAR_Title;
  2648. rc2 = CreateRemoteSessionProcessW(
  2649. SessionId,
  2650. System,
  2651. hToken,
  2652. pWCHAR_AppName ,
  2653. pWCHAR_CommandLine,
  2654. lpProcessAttributes,
  2655. lpThreadAttributes ,
  2656. bInheritHandles,
  2657. dwCreationFlags,
  2658. lpEnvironment,
  2659. pWCHAR_CurDir,
  2660. &WCHAR_StartupInfo,
  2661. lpProcessInformation
  2662. );
  2663. Cleanup:
  2664. if ( !rc ) // rc is set to FALSE if an attempted memory allocation has failed.
  2665. {
  2666. BaseSetLastNTError(STATUS_NO_MEMORY);
  2667. }
  2668. if (pWCHAR_AppName)
  2669. {
  2670. LocalFree( pWCHAR_AppName );
  2671. }
  2672. if (pWCHAR_CommandLine)
  2673. {
  2674. LocalFree( pWCHAR_CommandLine );
  2675. }
  2676. if (pWCHAR_CurDir)
  2677. {
  2678. LocalFree( pWCHAR_CurDir );
  2679. }
  2680. if (pWCHAR_Title)
  2681. {
  2682. LocalFree( pWCHAR_Title );
  2683. }
  2684. if (pWCHAR_Desktop)
  2685. {
  2686. LocalFree( pWCHAR_Desktop );
  2687. }
  2688. return rc2;
  2689. }
  2690. //+---------------------------------------------------------------------------
  2691. //
  2692. // Function: CreateProcessAsUserA
  2693. //
  2694. // Synopsis: ANSI wrapper for CreateProcessAsUserW
  2695. //
  2696. // Arguments: [hToken] --
  2697. // [lpApplicationName] --
  2698. // [lpCommandLine] --
  2699. // [lpProcessAttributes] --
  2700. // [lpThreadAttributes] --
  2701. // [bInheritHandles] --
  2702. // [dwCreationFlags] --
  2703. // [lpEnvironment] --
  2704. // [lpCurrentDirectory] --
  2705. // [lpStartupInfo] --
  2706. // [lpProcessInformation] --
  2707. //
  2708. // Return Values
  2709. // If the function succeeds, the return value is nonzero.
  2710. // If the function fails, the return value is zero. To get extended error information, call GetLastError.
  2711. //
  2712. // History: 4-25-95 RichardW Created
  2713. // 1-14-98 AraBern add changes for Hydra
  2714. //
  2715. // Notes:
  2716. //
  2717. //----------------------------------------------------------------------------
  2718. BOOL
  2719. WINAPI
  2720. CreateProcessAsUserA(
  2721. HANDLE hToken,
  2722. LPCSTR lpApplicationName,
  2723. LPSTR lpCommandLine,
  2724. LPSECURITY_ATTRIBUTES lpProcessAttributes,
  2725. LPSECURITY_ATTRIBUTES lpThreadAttributes,
  2726. BOOL bInheritHandles,
  2727. DWORD dwCreationFlags,
  2728. LPVOID lpEnvironment,
  2729. LPCSTR lpCurrentDirectory,
  2730. LPSTARTUPINFOA lpStartupInfo,
  2731. LPPROCESS_INFORMATION lpProcessInformation
  2732. )
  2733. {
  2734. DWORD CreateFlags;
  2735. DWORD clientSessionID=0;
  2736. DWORD currentSessionID=0;
  2737. DWORD resultLength;
  2738. HANDLE hTmpToken;
  2739. DWORD curProcId ;
  2740. NTSTATUS Status ;
  2741. CreateFlags = (dwCreationFlags & CREATE_SUSPENDED ? COMMON_CREATE_SUSPENDED : 0);
  2742. //
  2743. // get the session if (zero means console).
  2744. //
  2745. currentSessionID = NtCurrentPeb()->SessionId;
  2746. if ( !GetTokenInformation ( hToken, TokenSessionId , &clientSessionID,sizeof( DWORD), &resultLength ) )
  2747. {
  2748. //
  2749. // get the access token for the client of this call
  2750. // use get token instead of process since the client might have only
  2751. // impersonated the thread, not the process
  2752. //
  2753. DBG_DumpOutLastError;
  2754. ASSERT( FALSE );
  2755. currentSessionID = 0;
  2756. //
  2757. // We should probably return FALSE here, but at this time we don't want to alter the
  2758. // non-Hydra code-execution-flow at all.
  2759. //
  2760. }
  2761. KdPrint(("logon32.c: CreateProcessAsUserA(): clientSessionID = %d, currentSessionID = %d \n",
  2762. clientSessionID, currentSessionID ));
  2763. if ( ( clientSessionID != currentSessionID ))
  2764. {
  2765. //
  2766. // If the client session ID is not the same as the current session ID, then, we are attempting
  2767. // to create a process on a remote session from the current session.
  2768. // This block of code is used to accomplish such process creation, it is Terminal-Server specific
  2769. //
  2770. BOOL bHaveImpersonated;
  2771. HANDLE hCurrentThread;
  2772. HANDLE hPrevToken = NULL;
  2773. DWORD rc;
  2774. TOKEN_TYPE tokenType;
  2775. //
  2776. // We must send the request to the remote WinStation
  2777. // of the requestor
  2778. //
  2779. // NOTE: The current WinStationCreateProcessW() does not use
  2780. // the supplied security descriptor, but creates the
  2781. // process under the account of the logged on user.
  2782. //
  2783. //
  2784. // Stop impersonating before doing the WinStationCreateProcess.
  2785. // The remote winstation exec thread will launch the app under
  2786. // the users context. We must not be impersonating because this
  2787. // call only lets SYSTEM request the remote execute.
  2788. //
  2789. hCurrentThread = GetCurrentThread();
  2790. //
  2791. // Init bHaveImpersonated to the FALSE state
  2792. //
  2793. bHaveImpersonated = FALSE;
  2794. //
  2795. // Since the caller of this function (runas-> SecLogon service ) has already
  2796. // impersonated the new (target) user, we do the OpenThreadToken with
  2797. // OpenAsSelf = TRUE
  2798. //
  2799. if ( OpenThreadToken( hCurrentThread, TOKEN_QUERY, TRUE, &hPrevToken ) )
  2800. {
  2801. bHaveImpersonated = TRUE;
  2802. if ( !RevertToSelf() )
  2803. {
  2804. return FALSE;
  2805. }
  2806. }
  2807. //
  2808. // else, we are not impersonating, as reflected by the init value of bHaveImpersonated
  2809. //
  2810. rc = CreateRemoteSessionProcessA(
  2811. clientSessionID,
  2812. FALSE, // not creating a process for System
  2813. hToken,
  2814. lpApplicationName,
  2815. lpCommandLine,
  2816. lpProcessAttributes,
  2817. lpThreadAttributes,
  2818. bInheritHandles,
  2819. dwCreationFlags | CREATE_SEPARATE_WOW_VDM,
  2820. lpEnvironment,
  2821. lpCurrentDirectory,
  2822. lpStartupInfo,
  2823. lpProcessInformation) ;
  2824. //
  2825. // Undo the effect of RevertToSelf() if we had impersoanted
  2826. //
  2827. if ( bHaveImpersonated )
  2828. {
  2829. Status = NtSetInformationThread(
  2830. NtCurrentThread(),
  2831. ThreadImpersonationToken,
  2832. &hPrevToken,
  2833. sizeof( hPrevToken ) );
  2834. NtClose( hPrevToken );
  2835. }
  2836. if ( rc )
  2837. {
  2838. return TRUE;
  2839. }
  2840. else
  2841. {
  2842. return FALSE;
  2843. }
  2844. }
  2845. else
  2846. //
  2847. // this is the standard non-Hydra related call block
  2848. //
  2849. {
  2850. HANDLE hRestrictedToken = NULL;
  2851. BOOL b = FALSE;
  2852. if (!CreateProcessInternalA(hToken,
  2853. lpApplicationName,
  2854. lpCommandLine,
  2855. lpProcessAttributes,
  2856. lpThreadAttributes,
  2857. bInheritHandles,
  2858. (dwCreationFlags | CREATE_SUSPENDED |
  2859. CREATE_SEPARATE_WOW_VDM),
  2860. lpEnvironment,
  2861. lpCurrentDirectory,
  2862. lpStartupInfo,
  2863. lpProcessInformation,
  2864. &hRestrictedToken))
  2865. {
  2866. //
  2867. // The internal routine might return a token even in the failure case
  2868. // since it uses try-finally. Free the token if needed.
  2869. //
  2870. if (hRestrictedToken != NULL)
  2871. {
  2872. NtClose(hRestrictedToken);
  2873. }
  2874. return(FALSE);
  2875. }
  2876. CreateFlags |= (lpProcessAttributes ? 0 : COMMON_CREATE_PROCESSSD);
  2877. CreateFlags |= (lpThreadAttributes ? 0 : COMMON_CREATE_THREADSD);
  2878. //
  2879. // If a restricted token was returned, set it on the process.
  2880. // Else use the token provided by the caller.
  2881. //
  2882. if (hRestrictedToken == NULL)
  2883. {
  2884. b = (L32CommonCreate(CreateFlags, hToken, lpProcessInformation));
  2885. }
  2886. else
  2887. {
  2888. b = (L32CommonCreate(CreateFlags, hRestrictedToken, lpProcessInformation));
  2889. NtClose(hRestrictedToken);
  2890. }
  2891. return b;
  2892. }
  2893. }