Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1271 lines
36 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. #undef UNICODE
  18. #include <nt.h>
  19. #include <ntrtl.h>
  20. #include <nturtl.h>
  21. #include <windows.h>
  22. #include <crypt.h>
  23. #include <mpr.h>
  24. #include <ntlsa.h>
  25. #include <ntmsv1_0.h>
  26. #include <wchar.h>
  27. #include <stdlib.h>
  28. #include <lmcons.h>
  29. #define SECURITY_WIN32
  30. #define SECURITY_KERBEROS
  31. #include <security.h>
  32. //
  33. // We dynamically load mpr.dll (no big surprise there), in order to call
  34. // WNetLogonNotify, as defined in private\inc\mpr.h. This prototype matches
  35. // it -- consult the header file for all the parameters.
  36. //
  37. typedef (* LOGONNOTIFYFN)(LPCWSTR, PLUID, LPCWSTR, LPVOID,
  38. LPCWSTR, LPVOID, LPWSTR, LPVOID, LPWSTR *);
  39. //
  40. // The QuotaLimits are global, because the defaults
  41. // are always used for accounts, based on server/wksta, and no one ever
  42. // calls lsasetaccountquota
  43. //
  44. HANDLE Logon32LsaHandle = NULL;
  45. ULONG Logon32MsvHandle = 0xFFFFFFFF;
  46. ULONG Logon32KerbHandle = 0xFFFFFFFF;
  47. WCHAR Logon32DomainName[16] = L""; // NOTE: This should be DNLEN from
  48. // lmcons.h, but that would be a
  49. // lot of including
  50. QUOTA_LIMITS Logon32QuotaLimits;
  51. HINSTANCE Logon32MprHandle = NULL;
  52. LOGONNOTIFYFN Logon32LogonNotify = NULL;
  53. RTL_CRITICAL_SECTION Logon32Lock;
  54. #define LockLogon() RtlEnterCriticalSection( &Logon32Lock )
  55. #define UnlockLogon() RtlLeaveCriticalSection( &Logon32Lock )
  56. SID_IDENTIFIER_AUTHORITY L32SystemSidAuthority = SECURITY_NT_AUTHORITY;
  57. SID_IDENTIFIER_AUTHORITY L32LocalSidAuthority = SECURITY_LOCAL_SID_AUTHORITY;
  58. #define COMMON_CREATE_SUSPENDED 0x00000001 // Suspended, do not Resume()
  59. #define COMMON_CREATE_PROCESSSD 0x00000002 // Whack the process SD
  60. #define COMMON_CREATE_THREADSD 0x00000004 // Whack the thread SD
  61. #define BaseSetLastNTError(_x_) \
  62. { \
  63. ULONG dwErrorCode; \
  64. dwErrorCode = RtlNtStatusToDosError( (_x_) ); \
  65. SetLastError( dwErrorCode ); \
  66. }
  67. //+---------------------------------------------------------------------------
  68. //
  69. // Function: Logon32Initialize
  70. //
  71. // Synopsis: Initializes the critical section
  72. //
  73. // Arguments: [hMod] --
  74. // [Reason] --
  75. // [Context] --
  76. //
  77. //----------------------------------------------------------------------------
  78. BOOL
  79. Logon32Initialize(
  80. VOID
  81. )
  82. {
  83. NTSTATUS Status;
  84. Status = RtlInitializeCriticalSection( &Logon32Lock );
  85. return( Status == STATUS_SUCCESS );
  86. }
  87. /***************************************************************************\
  88. * CreateLogonSid
  89. *
  90. * Creates a logon sid for a new logon.
  91. *
  92. * If LogonId is non NULL, on return the LUID that is part of the logon
  93. * sid is returned here.
  94. *
  95. * History:
  96. * 12-05-91 Davidc Created
  97. \***************************************************************************/
  98. PSID
  99. L32CreateLogonSid(
  100. PLUID LogonId OPTIONAL
  101. )
  102. {
  103. NTSTATUS Status;
  104. ULONG Length;
  105. PSID Sid;
  106. LUID Luid;
  107. //
  108. // Generate a locally unique id to include in the logon sid
  109. //
  110. Status = NtAllocateLocallyUniqueId(&Luid);
  111. if (!NT_SUCCESS(Status)) {
  112. return(NULL);
  113. }
  114. //
  115. // Allocate space for the sid and fill it in.
  116. //
  117. Length = RtlLengthRequiredSid(SECURITY_LOGON_IDS_RID_COUNT);
  118. Sid = (PSID)LocalAlloc(LMEM_FIXED, Length);
  119. if (Sid != NULL) {
  120. RtlInitializeSid(Sid, &L32SystemSidAuthority, SECURITY_LOGON_IDS_RID_COUNT);
  121. ASSERT(SECURITY_LOGON_IDS_RID_COUNT == 3);
  122. *(RtlSubAuthoritySid(Sid, 0)) = SECURITY_LOGON_IDS_RID;
  123. *(RtlSubAuthoritySid(Sid, 1 )) = Luid.HighPart;
  124. *(RtlSubAuthoritySid(Sid, 2 )) = Luid.LowPart;
  125. }
  126. //
  127. // Return the logon LUID if required.
  128. //
  129. if (LogonId != NULL) {
  130. *LogonId = Luid;
  131. }
  132. return(Sid);
  133. }
  134. /*******************************************************************
  135. NAME: GetDefaultDomainName
  136. SYNOPSIS: Fills in the given array with the name of the default
  137. domain to use for logon validation.
  138. ENTRY: pszDomainName - Pointer to a buffer that will receive
  139. the default domain name.
  140. cchDomainName - The size (in charactesr) of the domain
  141. name buffer.
  142. RETURNS: TRUE if successful, FALSE if not.
  143. HISTORY:
  144. KeithMo 05-Dec-1994 Created.
  145. RichardW 10-Jan-95 Liberated from sockets and stuck in base
  146. ********************************************************************/
  147. BOOL
  148. L32GetDefaultDomainName(
  149. PUNICODE_STRING pDomainName
  150. )
  151. {
  152. OBJECT_ATTRIBUTES ObjectAttributes;
  153. NTSTATUS NtStatus;
  154. INT Result;
  155. DWORD err = 0;
  156. LSA_HANDLE LsaPolicyHandle = NULL;
  157. PPOLICY_ACCOUNT_DOMAIN_INFO DomainInfo = NULL;
  158. PUNICODE_STRING pDomain;
  159. if (Logon32DomainName[0] != L'\0')
  160. {
  161. RtlInitUnicodeString(pDomainName, Logon32DomainName);
  162. return(TRUE);
  163. }
  164. //
  165. // Open a handle to the local machine's LSA policy object.
  166. //
  167. InitializeObjectAttributes( &ObjectAttributes, // object attributes
  168. NULL, // name
  169. 0L, // attributes
  170. NULL, // root directory
  171. NULL ); // security descriptor
  172. NtStatus = LsaOpenPolicy( NULL, // system name
  173. &ObjectAttributes, // object attributes
  174. POLICY_EXECUTE, // access mask
  175. &LsaPolicyHandle ); // policy handle
  176. if( !NT_SUCCESS( NtStatus ) )
  177. {
  178. BaseSetLastNTError(NtStatus);
  179. return(FALSE);
  180. }
  181. //
  182. // Query the domain information from the policy object.
  183. //
  184. NtStatus = LsaQueryInformationPolicy( LsaPolicyHandle,
  185. PolicyAccountDomainInformation,
  186. (PVOID *) &DomainInfo );
  187. if (!NT_SUCCESS(NtStatus))
  188. {
  189. BaseSetLastNTError(NtStatus);
  190. LsaClose(LsaPolicyHandle);
  191. return(FALSE);
  192. }
  193. (void) LsaClose(LsaPolicyHandle);
  194. //
  195. // Copy the domain name into our cache, and
  196. //
  197. CopyMemory( Logon32DomainName,
  198. DomainInfo->DomainName.Buffer,
  199. DomainInfo->DomainName.Length );
  200. //
  201. // Null terminate it appropriately
  202. //
  203. Logon32DomainName[DomainInfo->DomainName.Length / sizeof(WCHAR)] = L'\0';
  204. //
  205. // Clean up
  206. //
  207. LsaFreeMemory( (PVOID)DomainInfo );
  208. //
  209. // And init the string
  210. //
  211. RtlInitUnicodeString(pDomainName, Logon32DomainName);
  212. return TRUE;
  213. } // GetDefaultDomainName
  214. //+---------------------------------------------------------------------------
  215. //
  216. // Function: L32pInitLsa
  217. //
  218. // Synopsis: Initialize connection with LSA
  219. //
  220. // Arguments: (none)
  221. //
  222. // History: 4-21-95 RichardW Created
  223. //
  224. // Notes:
  225. //
  226. //----------------------------------------------------------------------------
  227. BOOL
  228. L32pInitLsa(void)
  229. {
  230. char MyName[MAX_PATH];
  231. char * ModuleName;
  232. STRING LogonProcessName;
  233. STRING PackageName;
  234. ULONG dummy;
  235. NTSTATUS Status;
  236. BOOLEAN WasEnabled;
  237. Status = RtlAdjustPrivilege(SE_TCB_PRIVILEGE, TRUE, FALSE, &WasEnabled);
  238. if (!NT_SUCCESS(Status))
  239. {
  240. BaseSetLastNTError(Status);
  241. return(FALSE);
  242. }
  243. GetModuleFileNameA(NULL, MyName, MAX_PATH);
  244. ModuleName = strrchr(MyName, '\\');
  245. if (!ModuleName)
  246. {
  247. ModuleName = MyName;
  248. }
  249. //
  250. // Hookup to the LSA and locate our authentication package.
  251. //
  252. RtlInitString(&LogonProcessName, ModuleName);
  253. Status = LsaRegisterLogonProcess(
  254. &LogonProcessName,
  255. &Logon32LsaHandle,
  256. &dummy
  257. );
  258. //
  259. // Turn off the privilege now.
  260. //
  261. if (!WasEnabled)
  262. {
  263. (VOID) RtlAdjustPrivilege(SE_TCB_PRIVILEGE, FALSE, FALSE, &WasEnabled);
  264. }
  265. if (!NT_SUCCESS(Status)) {
  266. BaseSetLastNTError(Status);
  267. return(FALSE);
  268. }
  269. //
  270. // Connect with the MSV1_0 authentication package
  271. //
  272. RtlInitString(&PackageName, "MICROSOFT_AUTHENTICATION_PACKAGE_V1_0");
  273. Status = LsaLookupAuthenticationPackage (
  274. Logon32LsaHandle,
  275. &PackageName,
  276. &Logon32MsvHandle
  277. );
  278. if (!NT_SUCCESS(Status)) {
  279. BaseSetLastNTError(Status);
  280. (VOID) LsaDeregisterLogonProcess( Logon32LsaHandle );
  281. Logon32LsaHandle = NULL;
  282. return(FALSE);
  283. }
  284. //
  285. // Connect with the Kerberos authentication package
  286. //
  287. RtlInitString(&PackageName, MICROSOFT_KERBEROS_NAME_A);
  288. Status = LsaLookupAuthenticationPackage (
  289. Logon32LsaHandle,
  290. &PackageName,
  291. &Logon32KerbHandle
  292. );
  293. if (!NT_SUCCESS(Status)) {
  294. BaseSetLastNTError(Status);
  295. (VOID) LsaDeregisterLogonProcess( Logon32LsaHandle );
  296. Logon32LsaHandle = NULL;
  297. return(FALSE);
  298. }
  299. return(TRUE);
  300. }
  301. //+---------------------------------------------------------------------------
  302. //
  303. // Function: L32pNotifyMpr
  304. //
  305. // Synopsis: Loads the MPR DLL and notifies the network providers (like
  306. // csnw) so they know about this logon session and the credentials
  307. //
  308. // Arguments: [NewLogon] -- New logon information
  309. // [LogonId] -- Logon ID
  310. //
  311. // History: 4-24-95 RichardW Created
  312. //
  313. // Notes:
  314. //
  315. //----------------------------------------------------------------------------
  316. BOOL
  317. L32pNotifyMpr(
  318. PMSV1_0_INTERACTIVE_LOGON NewLogon,
  319. PLUID LogonId
  320. )
  321. {
  322. MSV1_0_INTERACTIVE_LOGON OldLogon;
  323. LPWSTR LogonScripts;
  324. DWORD status;
  325. if ( Logon32MprHandle == NULL )
  326. {
  327. LockLogon();
  328. if ( Logon32MprHandle == NULL)
  329. {
  330. Logon32MprHandle = LoadLibrary("mpr.dll");
  331. if (Logon32MprHandle != NULL) {
  332. Logon32LogonNotify = (LOGONNOTIFYFN) GetProcAddress(
  333. Logon32MprHandle,
  334. "WNetLogonNotify");
  335. }
  336. }
  337. UnlockLogon();
  338. }
  339. if ( Logon32LogonNotify != NULL )
  340. {
  341. CopyMemory(&OldLogon, NewLogon, sizeof(OldLogon));
  342. status = Logon32LogonNotify(
  343. L"Windows NT Network Provider",
  344. LogonId,
  345. L"MSV1_0:Interactive",
  346. (LPVOID)NewLogon,
  347. L"MSV1_0:Interactive",
  348. (LPVOID)&OldLogon,
  349. L"SvcCtl", // StationName
  350. NULL, // StationHandle
  351. &LogonScripts); // LogonScripts
  352. if (status == NO_ERROR) {
  353. if (LogonScripts != NULL ) {
  354. (void) LocalFree(LogonScripts);
  355. }
  356. }
  357. return( TRUE );
  358. }
  359. return( FALSE );
  360. }
  361. //+---------------------------------------------------------------------------
  362. //
  363. // Function: L32pLogonUser
  364. //
  365. // Synopsis: Wraps up the call to LsaLogonUser
  366. //
  367. // Arguments: [LsaHandle] --
  368. // [AuthenticationPackage] --
  369. // [LogonType] --
  370. // [UserName] --
  371. // [Domain] --
  372. // [Password] --
  373. // [LogonSid] --
  374. // [LogonId] --
  375. // [LogonToken] --
  376. // [Quotas] --
  377. // [pProfileBuffer] --
  378. // [pProfileBufferLength] --
  379. // [pSubStatus] --
  380. //
  381. // History: 4-24-95 RichardW Created
  382. //
  383. // Notes:
  384. //
  385. //----------------------------------------------------------------------------
  386. NTSTATUS
  387. L32pLogonUser(
  388. IN HANDLE LsaHandle,
  389. IN ULONG AuthenticationPackage,
  390. IN SECURITY_LOGON_TYPE LogonType,
  391. IN PUNICODE_STRING UserName,
  392. IN PUNICODE_STRING Domain,
  393. IN PUNICODE_STRING Password,
  394. IN PSID LogonSid,
  395. OUT PLUID LogonId,
  396. OUT PHANDLE LogonToken,
  397. OUT PQUOTA_LIMITS Quotas,
  398. OUT PVOID *pProfileBuffer,
  399. OUT PULONG pProfileBufferLength,
  400. OUT PNTSTATUS pSubStatus
  401. )
  402. {
  403. NTSTATUS Status;
  404. STRING OriginName;
  405. TOKEN_SOURCE SourceContext;
  406. PMSV1_0_INTERACTIVE_LOGON MsvAuthInfo;
  407. PKERB_INTERACTIVE_LOGON KerbAuthInfo;
  408. PMSV1_0_LM20_LOGON MsvNetAuthInfo;
  409. PVOID AuthInfoBuf;
  410. ULONG AuthInfoSize;
  411. PTOKEN_GROUPS TokenGroups;
  412. PSID LocalSid;
  413. WCHAR ComputerName[ MAX_COMPUTERNAME_LENGTH + 1 ];
  414. DWORD ComputerNameLength;
  415. union {
  416. LUID Luid;
  417. NT_CHALLENGE NtChallenge;
  418. } Challenge;
  419. NT_OWF_PASSWORD PasswordHash;
  420. OEM_STRING LmPassword;
  421. UCHAR LmPasswordBuf[ LM20_PWLEN + 1 ];
  422. LM_OWF_PASSWORD LmPasswordHash;
  423. #if DBG
  424. if (!RtlValidSid(LogonSid))
  425. {
  426. return(STATUS_INVALID_PARAMETER);
  427. }
  428. #endif
  429. //
  430. // Initialize source context structure
  431. //
  432. strncpy(SourceContext.SourceName, "Advapi ", sizeof(SourceContext.SourceName)); // LATER from res file
  433. Status = NtAllocateLocallyUniqueId(&SourceContext.SourceIdentifier);
  434. if (!NT_SUCCESS(Status)) {
  435. return(Status);
  436. }
  437. //
  438. // Set logon origin
  439. //
  440. RtlInitString(&OriginName, "LogonUser API");
  441. //
  442. // For network logons, do the magic.
  443. //
  444. if (AuthenticationPackage == Logon32MsvHandle)
  445. {
  446. if ( LogonType == Network )
  447. {
  448. ComputerNameLength = MAX_COMPUTERNAME_LENGTH + 1;
  449. if (!GetComputerNameW( ComputerName, &ComputerNameLength ) )
  450. {
  451. return( STATUS_INVALID_PARAMETER );
  452. }
  453. AuthInfoSize = sizeof( MSV1_0_LM20_LOGON ) +
  454. sizeof( WCHAR ) * ( wcslen( UserName->Buffer ) + 1 +
  455. wcslen( Domain->Buffer ) + 1 +
  456. ComputerNameLength + 1) +
  457. NT_RESPONSE_LENGTH +
  458. LM_RESPONSE_LENGTH ;
  459. MsvNetAuthInfo = AuthInfoBuf = RtlAllocateHeap( RtlProcessHeap(),
  460. HEAP_ZERO_MEMORY,
  461. AuthInfoSize );
  462. if ( !MsvNetAuthInfo )
  463. {
  464. return( STATUS_NO_MEMORY );
  465. }
  466. //
  467. // Start packing in the string
  468. //
  469. MsvNetAuthInfo->MessageType = MsV1_0NetworkLogon;
  470. //
  471. // Copy the user name into the authentication buffer
  472. //
  473. MsvNetAuthInfo->UserName.Length =
  474. (USHORT)sizeof(WCHAR)*wcslen(UserName->Buffer);
  475. MsvNetAuthInfo->UserName.MaximumLength =
  476. MsvNetAuthInfo->UserName.Length + sizeof(WCHAR);
  477. MsvNetAuthInfo->UserName.Buffer = (PWSTR)(MsvNetAuthInfo+1);
  478. wcscpy(MsvNetAuthInfo->UserName.Buffer, UserName->Buffer);
  479. //
  480. // Copy the domain name into the authentication buffer
  481. //
  482. MsvNetAuthInfo->LogonDomainName.Length =
  483. (USHORT)sizeof(WCHAR)*wcslen(Domain->Buffer);
  484. MsvNetAuthInfo->LogonDomainName.MaximumLength =
  485. MsvNetAuthInfo->LogonDomainName.Length + sizeof(WCHAR);
  486. MsvNetAuthInfo->LogonDomainName.Buffer = (PWSTR)
  487. ((PBYTE)(MsvNetAuthInfo->UserName.Buffer) +
  488. MsvNetAuthInfo->UserName.MaximumLength);
  489. wcscpy(MsvNetAuthInfo->LogonDomainName.Buffer, Domain->Buffer);
  490. //
  491. // Copy the workstation name into the buffer
  492. //
  493. MsvNetAuthInfo->Workstation.Length = (USHORT)
  494. (sizeof(WCHAR) * ComputerNameLength);
  495. MsvNetAuthInfo->Workstation.MaximumLength =
  496. MsvNetAuthInfo->Workstation.Length + sizeof(WCHAR);
  497. MsvNetAuthInfo->Workstation.Buffer = (PWSTR)
  498. ((PBYTE) (MsvNetAuthInfo->LogonDomainName.Buffer) +
  499. MsvNetAuthInfo->LogonDomainName.MaximumLength );
  500. wcscpy( MsvNetAuthInfo->Workstation.Buffer, ComputerName );
  501. //
  502. // Now, generate the bits for the challenge
  503. //
  504. Status = NtAllocateLocallyUniqueId( &Challenge.Luid );
  505. if ( !NT_SUCCESS(Status) )
  506. {
  507. RtlFreeHeap( RtlProcessHeap(), 0, MsvNetAuthInfo );
  508. return( Status );
  509. }
  510. RtlCopyMemory( MsvNetAuthInfo->ChallengeToClient,
  511. & Challenge,
  512. MSV1_0_CHALLENGE_LENGTH );
  513. //
  514. // Set up space for response
  515. //
  516. MsvNetAuthInfo->CaseSensitiveChallengeResponse.Buffer = (PUCHAR)
  517. ((PBYTE) (MsvNetAuthInfo->Workstation.Buffer) +
  518. MsvNetAuthInfo->Workstation.MaximumLength );
  519. MsvNetAuthInfo->CaseSensitiveChallengeResponse.Length =
  520. NT_RESPONSE_LENGTH;
  521. MsvNetAuthInfo->CaseSensitiveChallengeResponse.MaximumLength =
  522. NT_RESPONSE_LENGTH;
  523. RtlCalculateNtOwfPassword(
  524. Password,
  525. & PasswordHash );
  526. RtlCalculateNtResponse(
  527. & Challenge.NtChallenge,
  528. & PasswordHash,
  529. (PNT_RESPONSE) MsvNetAuthInfo->CaseSensitiveChallengeResponse.Buffer );
  530. //
  531. // Now do the painful LM compatible hash, so anyone who is maintaining
  532. // their account from a WfW machine will still have a password.
  533. //
  534. LmPassword.Buffer = LmPasswordBuf;
  535. LmPassword.Length = LmPassword.MaximumLength = LM20_PWLEN + 1;
  536. Status = RtlUpcaseUnicodeStringToOemString(
  537. & LmPassword,
  538. Password,
  539. FALSE );
  540. if ( NT_SUCCESS(Status) )
  541. {
  542. MsvNetAuthInfo->CaseInsensitiveChallengeResponse.Buffer = (PUCHAR)
  543. ((PBYTE) (MsvNetAuthInfo->CaseSensitiveChallengeResponse.Buffer) +
  544. MsvNetAuthInfo->CaseSensitiveChallengeResponse.MaximumLength );
  545. MsvNetAuthInfo->CaseInsensitiveChallengeResponse.Length =
  546. LM_RESPONSE_LENGTH;
  547. MsvNetAuthInfo->CaseInsensitiveChallengeResponse.MaximumLength =
  548. LM_RESPONSE_LENGTH;
  549. RtlCalculateLmOwfPassword(
  550. LmPassword.Buffer,
  551. & LmPasswordHash );
  552. ZeroMemory( LmPassword.Buffer, LmPassword.Length );
  553. RtlCalculateLmResponse(
  554. & Challenge.NtChallenge,
  555. & LmPasswordHash,
  556. (PLM_RESPONSE) MsvNetAuthInfo->CaseInsensitiveChallengeResponse.Buffer );
  557. }
  558. else
  559. {
  560. //
  561. // If we're here, the NT (supplied) password is longer than the
  562. // limit allowed for LM passwords. NULL out the field, so that
  563. // MSV knows not to worry about it.
  564. //
  565. RtlZeroMemory( &MsvNetAuthInfo->CaseInsensitiveChallengeResponse,
  566. sizeof( STRING ) );
  567. }
  568. }
  569. else
  570. {
  571. //
  572. // Build logon structure for non-network logons - service,
  573. // batch, interactive
  574. //
  575. AuthInfoSize = sizeof(MSV1_0_INTERACTIVE_LOGON) +
  576. sizeof(WCHAR)*(wcslen(UserName->Buffer) + 1 +
  577. wcslen(Domain->Buffer) + 1 +
  578. wcslen(Password->Buffer) + 1 );
  579. MsvAuthInfo = AuthInfoBuf = RtlAllocateHeap(RtlProcessHeap(),
  580. HEAP_ZERO_MEMORY,
  581. AuthInfoSize);
  582. if (MsvAuthInfo == NULL) {
  583. return(STATUS_NO_MEMORY);
  584. }
  585. //
  586. // This authentication buffer will be used for a logon attempt
  587. //
  588. MsvAuthInfo->MessageType = MsV1_0InteractiveLogon;
  589. //
  590. // Copy the user name into the authentication buffer
  591. //
  592. MsvAuthInfo->UserName.Length =
  593. (USHORT)sizeof(WCHAR)*wcslen(UserName->Buffer);
  594. MsvAuthInfo->UserName.MaximumLength =
  595. MsvAuthInfo->UserName.Length + sizeof(WCHAR);
  596. MsvAuthInfo->UserName.Buffer = (PWSTR)(MsvAuthInfo+1);
  597. wcscpy(MsvAuthInfo->UserName.Buffer, UserName->Buffer);
  598. //
  599. // Copy the domain name into the authentication buffer
  600. //
  601. MsvAuthInfo->LogonDomainName.Length =
  602. (USHORT)sizeof(WCHAR)*wcslen(Domain->Buffer);
  603. MsvAuthInfo->LogonDomainName.MaximumLength =
  604. MsvAuthInfo->LogonDomainName.Length + sizeof(WCHAR);
  605. MsvAuthInfo->LogonDomainName.Buffer = (PWSTR)
  606. ((PBYTE)(MsvAuthInfo->UserName.Buffer) +
  607. MsvAuthInfo->UserName.MaximumLength);
  608. wcscpy(MsvAuthInfo->LogonDomainName.Buffer, Domain->Buffer);
  609. //
  610. // Copy the password into the authentication buffer
  611. // Hide it once we have copied it. Use the same seed value
  612. // that we used for the original password in pGlobals.
  613. //
  614. MsvAuthInfo->Password.Length =
  615. (USHORT)sizeof(WCHAR)*wcslen(Password->Buffer);
  616. MsvAuthInfo->Password.MaximumLength =
  617. MsvAuthInfo->Password.Length + sizeof(WCHAR);
  618. MsvAuthInfo->Password.Buffer = (PWSTR)
  619. ((PBYTE)(MsvAuthInfo->LogonDomainName.Buffer) +
  620. MsvAuthInfo->LogonDomainName.MaximumLength);
  621. wcscpy(MsvAuthInfo->Password.Buffer, Password->Buffer);
  622. }
  623. }
  624. else if (AuthenticationPackage == Logon32KerbHandle)
  625. {
  626. //
  627. // Build logon structure for non-network logons - service,
  628. // batch, interactive
  629. //
  630. AuthInfoSize = sizeof(KERB_INTERACTIVE_LOGON) +
  631. sizeof(WCHAR)*(wcslen(UserName->Buffer) + 1 +
  632. wcslen(Domain->Buffer) + 1 +
  633. wcslen(Password->Buffer) + 1 );
  634. KerbAuthInfo = AuthInfoBuf = RtlAllocateHeap(RtlProcessHeap(),
  635. HEAP_ZERO_MEMORY,
  636. AuthInfoSize);
  637. if (KerbAuthInfo == NULL) {
  638. return(STATUS_NO_MEMORY);
  639. }
  640. //
  641. // This authentication buffer will be used for a logon attempt
  642. //
  643. KerbAuthInfo->MessageType = KerbInteractiveLogon;
  644. //
  645. // Copy the user name into the authentication buffer
  646. //
  647. KerbAuthInfo->UserName.Length =
  648. (USHORT)sizeof(WCHAR)*wcslen(UserName->Buffer);
  649. KerbAuthInfo->UserName.MaximumLength =
  650. KerbAuthInfo->UserName.Length + sizeof(WCHAR);
  651. KerbAuthInfo->UserName.Buffer = (PWSTR)(KerbAuthInfo+1);
  652. wcscpy(KerbAuthInfo->UserName.Buffer, UserName->Buffer);
  653. //
  654. // Copy the domain name into the authentication buffer
  655. //
  656. KerbAuthInfo->LogonDomainName.Length =
  657. (USHORT)sizeof(WCHAR)*wcslen(Domain->Buffer);
  658. KerbAuthInfo->LogonDomainName.MaximumLength =
  659. KerbAuthInfo->LogonDomainName.Length + sizeof(WCHAR);
  660. KerbAuthInfo->LogonDomainName.Buffer = (PWSTR)
  661. ((PBYTE)(KerbAuthInfo->UserName.Buffer) +
  662. KerbAuthInfo->UserName.MaximumLength);
  663. wcscpy(KerbAuthInfo->LogonDomainName.Buffer, Domain->Buffer);
  664. //
  665. // Copy the password into the authentication buffer
  666. // Hide it once we have copied it. Use the same seed value
  667. // that we used for the original password in pGlobals.
  668. //
  669. KerbAuthInfo->Password.Length =
  670. (USHORT)sizeof(WCHAR)*wcslen(Password->Buffer);
  671. KerbAuthInfo->Password.MaximumLength =
  672. KerbAuthInfo->Password.Length + sizeof(WCHAR);
  673. KerbAuthInfo->Password.Buffer = (PWSTR)
  674. ((PBYTE)(KerbAuthInfo->LogonDomainName.Buffer) +
  675. KerbAuthInfo->LogonDomainName.MaximumLength);
  676. wcscpy(KerbAuthInfo->Password.Buffer, Password->Buffer);
  677. }
  678. //
  679. // Create logon token groups
  680. //
  681. #define TOKEN_GROUP_COUNT 2 // We'll add the local SID and the logon SID
  682. TokenGroups = (PTOKEN_GROUPS) RtlAllocateHeap(RtlProcessHeap(), 0,
  683. sizeof(TOKEN_GROUPS) +
  684. (TOKEN_GROUP_COUNT - ANYSIZE_ARRAY) * sizeof(SID_AND_ATTRIBUTES));
  685. if (TokenGroups == NULL) {
  686. RtlFreeHeap(RtlProcessHeap(), 0, AuthInfoBuf);
  687. return(STATUS_NO_MEMORY);
  688. }
  689. //
  690. // Fill in the logon token group list
  691. //
  692. Status = RtlAllocateAndInitializeSid(
  693. &L32LocalSidAuthority,
  694. 1,
  695. SECURITY_LOCAL_RID,
  696. 0, 0, 0, 0, 0, 0, 0,
  697. &LocalSid
  698. );
  699. if ( NT_SUCCESS( Status ) )
  700. {
  701. TokenGroups->GroupCount = TOKEN_GROUP_COUNT;
  702. TokenGroups->Groups[0].Sid = LogonSid;
  703. TokenGroups->Groups[0].Attributes =
  704. SE_GROUP_MANDATORY | SE_GROUP_ENABLED |
  705. SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_LOGON_ID;
  706. TokenGroups->Groups[1].Sid = LocalSid;
  707. TokenGroups->Groups[1].Attributes =
  708. SE_GROUP_MANDATORY | SE_GROUP_ENABLED |
  709. SE_GROUP_ENABLED_BY_DEFAULT;
  710. //
  711. // Now try to log this on
  712. //
  713. Status = LsaLogonUser (
  714. LsaHandle,
  715. &OriginName,
  716. LogonType,
  717. AuthenticationPackage,
  718. AuthInfoBuf,
  719. AuthInfoSize,
  720. TokenGroups,
  721. &SourceContext,
  722. pProfileBuffer,
  723. pProfileBufferLength,
  724. LogonId,
  725. LogonToken,
  726. Quotas,
  727. pSubStatus
  728. );
  729. RtlFreeSid(LocalSid);
  730. }
  731. //
  732. // Discard token group list
  733. //
  734. RtlFreeHeap(RtlProcessHeap(), 0, TokenGroups);
  735. //
  736. // Notify all the network providers, if this is a NON network logon
  737. //
  738. if ( NT_SUCCESS( Status ) &&
  739. (LogonType != Network) )
  740. {
  741. L32pNotifyMpr(AuthInfoBuf, LogonId);
  742. }
  743. //
  744. // Discard authentication buffer
  745. //
  746. RtlFreeHeap(RtlProcessHeap(), 0, AuthInfoBuf);
  747. return(Status);
  748. }
  749. //+---------------------------------------------------------------------------
  750. //
  751. // Function: LogonUserA
  752. //
  753. // Synopsis: ANSI wrapper for LogonUserW. See description below
  754. //
  755. // Arguments: [lpszUsername] --
  756. // [lpszDomain] --
  757. // [lpszPassword] --
  758. // [dwLogonType] --
  759. // [dwLogonProvider] --
  760. // [phToken] --
  761. //
  762. // History: 4-25-95 RichardW Created
  763. //
  764. // Notes:
  765. //
  766. //----------------------------------------------------------------------------
  767. BOOL
  768. WINAPI
  769. KerbLogonUserA(
  770. LPSTR lpszUsername,
  771. LPSTR lpszDomain,
  772. LPSTR lpszPassword,
  773. DWORD dwLogonType,
  774. DWORD dwLogonProvider,
  775. HANDLE * phToken
  776. )
  777. {
  778. UNICODE_STRING Username;
  779. UNICODE_STRING Domain;
  780. UNICODE_STRING Password;
  781. NTSTATUS Status;
  782. BOOL bRet;
  783. Username.Buffer = NULL;
  784. Domain.Buffer = NULL;
  785. Password.Buffer = NULL;
  786. Status = RtlCreateUnicodeStringFromAsciiz(&Username, lpszUsername);
  787. if (!NT_SUCCESS(Status))
  788. {
  789. BaseSetLastNTError(Status);
  790. bRet = FALSE;
  791. goto Cleanup;
  792. }
  793. Status = RtlCreateUnicodeStringFromAsciiz(&Domain, lpszDomain);
  794. if (!NT_SUCCESS(Status))
  795. {
  796. BaseSetLastNTError(Status);
  797. bRet = FALSE;
  798. goto Cleanup;
  799. }
  800. Status = RtlCreateUnicodeStringFromAsciiz(&Password, lpszPassword);
  801. if (!NT_SUCCESS(Status))
  802. {
  803. BaseSetLastNTError(Status);
  804. bRet = FALSE;
  805. goto Cleanup;
  806. }
  807. bRet = KerbLogonUserW(
  808. Username.Buffer,
  809. Domain.Buffer,
  810. Password.Buffer,
  811. dwLogonType,
  812. dwLogonProvider,
  813. phToken);
  814. Cleanup:
  815. if (Username.Buffer)
  816. {
  817. RtlFreeUnicodeString(&Username);
  818. }
  819. if (Domain.Buffer)
  820. {
  821. RtlFreeUnicodeString(&Domain);
  822. }
  823. if (Password.Buffer)
  824. {
  825. RtlZeroMemory(Password.Buffer, Password.Length);
  826. RtlFreeUnicodeString(&Password);
  827. }
  828. return(bRet);
  829. }
  830. //+---------------------------------------------------------------------------
  831. //
  832. // Function: LogonUserW
  833. //
  834. // Synopsis: Logs a user on via plaintext password, username and domain
  835. // name via the LSA.
  836. //
  837. // Arguments: [lpszUsername] -- User name
  838. // [lpszDomain] -- Domain name
  839. // [lpszPassword] -- Password
  840. // [dwLogonType] -- Logon type
  841. // [dwLogonProvider] -- Provider
  842. // [phToken] -- Returned handle to primary token
  843. //
  844. // History: 4-25-95 RichardW Created
  845. //
  846. // Notes: Requires SeTcbPrivilege, and will enable it if not already
  847. // present.
  848. //
  849. //----------------------------------------------------------------------------
  850. BOOL
  851. WINAPI
  852. KerbLogonUserW(
  853. PWSTR lpszUsername,
  854. PWSTR lpszDomain,
  855. PWSTR lpszPassword,
  856. DWORD dwLogonType,
  857. DWORD dwLogonProvider,
  858. HANDLE * phToken
  859. )
  860. {
  861. NTSTATUS Status;
  862. ULONG PackageId;
  863. UNICODE_STRING Username;
  864. UNICODE_STRING Domain;
  865. UNICODE_STRING Password;
  866. LUID LogonId;
  867. PSID pLogonSid;
  868. PVOID Profile;
  869. ULONG ProfileLength;
  870. NTSTATUS SubStatus;
  871. SECURITY_LOGON_TYPE LogonType;
  872. //
  873. // Validate the provider
  874. //
  875. if (dwLogonProvider == LOGON32_PROVIDER_DEFAULT)
  876. {
  877. dwLogonProvider = LOGON32_PROVIDER_WINNT35;
  878. }
  879. if (dwLogonProvider > LOGON32_PROVIDER_WINNT40)
  880. {
  881. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  882. return(FALSE);
  883. }
  884. switch (dwLogonType)
  885. {
  886. case LOGON32_LOGON_INTERACTIVE:
  887. LogonType = Interactive;
  888. break;
  889. case LOGON32_LOGON_BATCH:
  890. LogonType = Batch;
  891. break;
  892. case LOGON32_LOGON_SERVICE:
  893. LogonType = Service;
  894. break;
  895. case LOGON32_LOGON_NETWORK:
  896. LogonType = Network;
  897. break;
  898. default:
  899. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  900. return(FALSE);
  901. break;
  902. }
  903. //
  904. // If the MSV handle is -1, grab the lock, and try again:
  905. //
  906. if (Logon32MsvHandle == 0xFFFFFFFF)
  907. {
  908. LockLogon();
  909. //
  910. // If the MSV handle is still -1, init our connection to lsa. We
  911. // have the lock, so no other threads can be trying this right now.
  912. //
  913. if (Logon32MsvHandle == 0xFFFFFFFF)
  914. {
  915. if (!L32pInitLsa())
  916. {
  917. return( FALSE );
  918. }
  919. }
  920. UnlockLogon();
  921. }
  922. //
  923. // Validate the parameters. NULL or empty domain or NULL or empty
  924. // user name is invalid.
  925. //
  926. RtlInitUnicodeString(&Username, lpszUsername);
  927. if (Username.Length == 0)
  928. {
  929. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  930. return(FALSE);
  931. }
  932. //
  933. // Initialize the token handle, if the pointer is invalid, then catch
  934. // the exception now.
  935. //
  936. *phToken = NULL;
  937. //
  938. // Parse that domain. Note, if the special token . is passed in for
  939. // domain, we will use the right value from the LSA, meaning AccountDomain.
  940. // If the domain is null, the lsa will talk to the local domain, the
  941. // primary domain, and then on from there...
  942. //
  943. if (lpszDomain && *lpszDomain)
  944. {
  945. if ((lpszDomain[0] == L'.') &&
  946. (lpszDomain[1] == L'\0') )
  947. {
  948. if (!L32GetDefaultDomainName(&Domain))
  949. {
  950. return(FALSE);
  951. }
  952. }
  953. else
  954. RtlInitUnicodeString(&Domain, lpszDomain);
  955. }
  956. else
  957. {
  958. RtlInitUnicodeString(&Domain, lpszDomain);
  959. }
  960. //
  961. // Finally, init the password
  962. //
  963. RtlInitUnicodeString(&Password, lpszPassword);
  964. //
  965. // Get a logon sid to refer to this guy (not that anyone will be able to
  966. // use it...
  967. //
  968. pLogonSid = L32CreateLogonSid(NULL);
  969. if (!pLogonSid)
  970. {
  971. BaseSetLastNTError(STATUS_NO_MEMORY);
  972. return(FALSE);
  973. }
  974. //
  975. // Attempt the logon
  976. //
  977. Status = L32pLogonUser(
  978. Logon32LsaHandle,
  979. (dwLogonProvider == LOGON32_PROVIDER_WINNT35) ?
  980. Logon32MsvHandle : Logon32KerbHandle,
  981. LogonType,
  982. &Username,
  983. &Domain,
  984. &Password,
  985. pLogonSid,
  986. &LogonId,
  987. phToken,
  988. &Logon32QuotaLimits,
  989. &Profile,
  990. &ProfileLength,
  991. &SubStatus);
  992. //
  993. // Done with logon sid, regardless of result:
  994. //
  995. LocalFree( pLogonSid );
  996. if (!NT_SUCCESS(Status))
  997. {
  998. if (Status == STATUS_ACCOUNT_RESTRICTION)
  999. {
  1000. BaseSetLastNTError(SubStatus);
  1001. }
  1002. else
  1003. BaseSetLastNTError(Status);
  1004. return(FALSE);
  1005. }
  1006. if (Profile != NULL)
  1007. {
  1008. LsaFreeReturnBuffer(Profile);
  1009. }
  1010. return(TRUE);
  1011. }