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.

1851 lines
50 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. logon32.cxx
  5. Abstract:
  6. Provide a replacement for LogonUser to login a user
  7. as a net logon. Also support sub-authentication DLL IDs
  8. Author:
  9. Philippe Choquier (phillich) 10-january-1996
  10. Created from base\advapi\logon32.c
  11. --*/
  12. #include "lonsint.hxx"
  13. #pragma hdrstop
  14. extern "C" {
  15. #include <ntsam.h>
  16. #include <ntlsa.h>
  17. #include <ntmsv1_0.h>
  18. #include <kerberos.h>
  19. #include <crypt.h>
  20. #include <logonmsv.h>
  21. #include <inetsec.h>
  22. #define SECURITY_WIN32
  23. #include <sspi.h> // Security Support Provider APIs
  24. #include <issperr.h>
  25. }
  26. #include <svcloc.h>
  27. #include <lonsi.hxx>
  28. #include <tslogon.hxx>
  29. #include <buffer.hxx>
  30. #if !defined(MSV1_0_RETURN_PASSWORD_EXPIRY)
  31. #define MSV1_0_RETURN_PASSWORD_EXPIRY 0x40
  32. #endif
  33. //
  34. // We dynamically load mpr.dll (no big surprise there), in order to call
  35. // WNetLogonNotify, as defined in private\inc\mpr.h. This prototype matches
  36. // it -- consult the header file for all the parameters.
  37. //
  38. typedef (* LOGONNOTIFYFN)(LPCWSTR, PLUID, LPCWSTR, LPVOID,
  39. LPCWSTR, LPVOID, LPWSTR, LPVOID, LPWSTR *);
  40. #define LEN_ALIGN(a,b) (((a)+b-1)&~(b-1))
  41. ULONG
  42. BaseSetLastNTError(
  43. IN NTSTATUS Status
  44. )
  45. /*++
  46. Routine Description:
  47. This API sets the "last error value" and the "last error string"
  48. based on the value of Status. For status codes that don't have
  49. a corresponding error string, the string is set to null.
  50. Arguments:
  51. Status - Supplies the status value to store as the last error value.
  52. Return Value:
  53. The corresponding Win32 error code that was stored in the
  54. "last error value" thread variable.
  55. --*/
  56. {
  57. ULONG dwErrorCode;
  58. dwErrorCode = RtlNtStatusToDosError( Status );
  59. SetLastError( dwErrorCode );
  60. return( dwErrorCode );
  61. }
  62. //
  63. // The QuotaLimits are global, because the defaults
  64. // are always used for accounts, based on server/wksta, and no one ever
  65. // calls lsasetaccountquota
  66. //
  67. HANDLE Logon32LsaHandle = NULL;
  68. ULONG Logon32MsvHandle = 0xFFFFFFFF;
  69. ULONG Logon32KerberosHandle = 0xFFFFFFFF;
  70. WCHAR Logon32DomainName[16] = L""; // NOTE: This should be DNLEN from
  71. // lmcons.h, but that would be a
  72. // lot of including
  73. QUOTA_LIMITS Logon32QuotaLimits;
  74. LOGONNOTIFYFN Logon32LogonNotify = NULL;
  75. HINSTANCE Logon32MprHandle = NULL;
  76. CRITICAL_SECTION Logon32Lock;
  77. BOOL fLsaInitialized = FALSE;
  78. #define LockLogon() EnterCriticalSection( &Logon32Lock )
  79. #define UnlockLogon() LeaveCriticalSection( &Logon32Lock )
  80. SID_IDENTIFIER_AUTHORITY L32SystemSidAuthority = SECURITY_NT_AUTHORITY;
  81. SID_IDENTIFIER_AUTHORITY L32LocalSidAuthority = SECURITY_LOCAL_SID_AUTHORITY;
  82. #define COMMON_CREATE_SUSPENDED 0x00000001 // Suspended, do not Resume()
  83. #define COMMON_CREATE_PROCESSSD 0x00000002 // Whack the process SD
  84. #define COMMON_CREATE_THREADSD 0x00000004 // Whack the thread SD
  85. BOOL
  86. IISLogon32Initialize(
  87. IN PVOID hMod,
  88. IN ULONG Reason,
  89. IN PCONTEXT Context)
  90. /*++
  91. Routine Description:
  92. Initializes the critical section
  93. Arguments:
  94. hMod -- reserved, must be NULL
  95. Reason -- DLL_PROCESS_ATTACH or DLL_PROCESS_DETACH
  96. Context -- reserved, must be NULL
  97. Returns:
  98. TRUE if initialization success, else FALSE
  99. --*/
  100. {
  101. return( TRUE );
  102. }
  103. PSID
  104. L32CreateLogonSid(
  105. PLUID LogonId OPTIONAL
  106. )
  107. /*++
  108. Routine Description:
  109. Creates a logon sid for a new logon.
  110. Arguments:
  111. LogonId -- If non NULL, on return the LUID that is part of the logon
  112. sid is returned here.
  113. Returns:
  114. Logon SID or NULL if error
  115. --*/
  116. {
  117. NTSTATUS Status;
  118. ULONG Length;
  119. PSID Sid;
  120. LUID Luid;
  121. //
  122. // Generate a locally unique id to include in the logon sid
  123. //
  124. Status = NtAllocateLocallyUniqueId(&Luid);
  125. if (!NT_SUCCESS(Status)) {
  126. return(NULL);
  127. }
  128. //
  129. // Allocate space for the sid and fill it in.
  130. //
  131. Length = RtlLengthRequiredSid(SECURITY_LOGON_IDS_RID_COUNT);
  132. Sid = (PSID)LocalAlloc(LMEM_FIXED, Length);
  133. if (Sid != NULL) {
  134. RtlInitializeSid(Sid, &L32SystemSidAuthority, SECURITY_LOGON_IDS_RID_COUNT);
  135. ASSERT(SECURITY_LOGON_IDS_RID_COUNT == 3);
  136. *(RtlSubAuthoritySid(Sid, 0)) = SECURITY_LOGON_IDS_RID;
  137. *(RtlSubAuthoritySid(Sid, 1 )) = Luid.HighPart;
  138. *(RtlSubAuthoritySid(Sid, 2 )) = Luid.LowPart;
  139. }
  140. //
  141. // Return the logon LUID if required.
  142. //
  143. if (LogonId != NULL) {
  144. *LogonId = Luid;
  145. }
  146. return(Sid);
  147. }
  148. BOOL
  149. L32pInitLsa(
  150. void
  151. )
  152. /*++
  153. Routine Description:
  154. Initialize connection with LSA
  155. Arguments:
  156. None
  157. Returns:
  158. TRUE if success, FALSE if error
  159. --*/
  160. {
  161. char MyName[MAX_PATH];
  162. char * ModuleName;
  163. STRING LogonProcessName;
  164. STRING PackageName;
  165. ULONG dummy;
  166. NTSTATUS Status;
  167. BOOLEAN WasEnabled;
  168. Status = RtlAdjustPrivilege(SE_TCB_PRIVILEGE, TRUE, FALSE, &WasEnabled);
  169. if (!NT_SUCCESS(Status))
  170. {
  171. BaseSetLastNTError(Status);
  172. return(FALSE);
  173. }
  174. if (GetModuleFileNameA(NULL, MyName, MAX_PATH))
  175. {
  176. ModuleName = strrchr(MyName, '\\');
  177. if (!ModuleName)
  178. {
  179. ModuleName = MyName;
  180. }
  181. }
  182. else
  183. {
  184. BaseSetLastNTError(STATUS_OBJECT_NAME_NOT_FOUND);
  185. return(FALSE);
  186. }
  187. //
  188. // Hookup to the LSA and locate our authentication package.
  189. //
  190. RtlInitString(&LogonProcessName, ModuleName);
  191. Status = LsaRegisterLogonProcess(
  192. &LogonProcessName,
  193. &Logon32LsaHandle,
  194. &dummy
  195. );
  196. //
  197. // Turn off the privilege now.
  198. //
  199. if (!WasEnabled)
  200. {
  201. (VOID) RtlAdjustPrivilege(SE_TCB_PRIVILEGE, FALSE, FALSE, &WasEnabled);
  202. }
  203. if (!NT_SUCCESS(Status)) {
  204. BaseSetLastNTError(Status);
  205. return(FALSE);
  206. }
  207. //
  208. // Connect with the MSV1_0 authentication package
  209. //
  210. RtlInitString(&PackageName, "MICROSOFT_AUTHENTICATION_PACKAGE_V1_0");
  211. Status = LsaLookupAuthenticationPackage (
  212. Logon32LsaHandle,
  213. &PackageName,
  214. &Logon32MsvHandle
  215. );
  216. if (!NT_SUCCESS(Status)) {
  217. BaseSetLastNTError(Status);
  218. (VOID) LsaDeregisterLogonProcess( Logon32LsaHandle );
  219. Logon32LsaHandle = NULL;
  220. return(FALSE);
  221. }
  222. //
  223. // Get the kerberos package
  224. //
  225. RtlInitString(&PackageName, MICROSOFT_KERBEROS_NAME_A);
  226. Status = LsaLookupAuthenticationPackage (
  227. Logon32LsaHandle,
  228. &PackageName,
  229. &Logon32KerberosHandle
  230. );
  231. if (!NT_SUCCESS(Status)) {
  232. BaseSetLastNTError(Status);
  233. (VOID) LsaDeregisterLogonProcess( Logon32LsaHandle );
  234. Logon32LsaHandle = NULL;
  235. Logon32MsvHandle = 0xFFFFFFFF;
  236. return(FALSE);
  237. }
  238. //
  239. // We are now initialized (duh)
  240. //
  241. fLsaInitialized = TRUE;
  242. return(TRUE);
  243. }
  244. //+---------------------------------------------------------------------------
  245. //
  246. // Function: L32pNotifyMpr
  247. //
  248. // Synopsis: Loads the MPR DLL and notifies the network providers (like
  249. // csnw) so they know about this logon session and the credentials
  250. //
  251. // Arguments: [NewLogon] -- New logon information
  252. // [LogonId] -- Logon ID
  253. //
  254. // History: 4-24-95 RichardW Created
  255. //
  256. // Notes:
  257. //
  258. //----------------------------------------------------------------------------
  259. BOOL
  260. L32pNotifyMpr(
  261. PMSV1_0_INTERACTIVE_LOGON NewLogon,
  262. PLUID LogonId
  263. )
  264. {
  265. MSV1_0_INTERACTIVE_LOGON OldLogon;
  266. LPWSTR LogonScripts;
  267. DWORD status;
  268. if ( Logon32MprHandle == NULL )
  269. {
  270. LockLogon();
  271. if ( Logon32MprHandle == NULL)
  272. {
  273. Logon32MprHandle = LoadLibrary("mpr.dll");
  274. if (Logon32MprHandle != NULL) {
  275. Logon32LogonNotify = (LOGONNOTIFYFN) GetProcAddress(
  276. Logon32MprHandle,
  277. "WNetLogonNotify");
  278. }
  279. }
  280. UnlockLogon();
  281. }
  282. if ( Logon32LogonNotify != NULL )
  283. {
  284. CopyMemory(&OldLogon, NewLogon, sizeof(OldLogon));
  285. status = Logon32LogonNotify(
  286. L"Windows NT Network Provider",
  287. LogonId,
  288. L"MSV1_0:Interactive",
  289. (LPVOID)NewLogon,
  290. L"MSV1_0:Interactive",
  291. (LPVOID)&OldLogon,
  292. L"SvcCtl", // StationName
  293. NULL, // StationHandle
  294. &LogonScripts); // LogonScripts
  295. if (status == NO_ERROR) {
  296. if (LogonScripts != NULL ) {
  297. (void) LocalFree(LogonScripts);
  298. }
  299. }
  300. return( TRUE );
  301. }
  302. return( FALSE );
  303. }
  304. NTSTATUS
  305. L32pLogonNetUser(
  306. IN HANDLE LsaHandle,
  307. IN ULONG AuthenticationPackage,
  308. IN SECURITY_LOGON_TYPE LogonType,
  309. IN PUNICODE_STRING UserName,
  310. IN PUNICODE_STRING Domain,
  311. IN PSTRING Password,
  312. IN PUNICODE_STRING Workstation,
  313. IN DWORD dwSubAuth,
  314. IN PSID LogonSid,
  315. OUT PLUID LogonId,
  316. OUT PHANDLE LogonToken,
  317. OUT PQUOTA_LIMITS Quotas,
  318. OUT PVOID *pProfileBuffer,
  319. OUT PULONG pProfileBufferLength,
  320. OUT PNTSTATUS pSubStatus
  321. )
  322. /*++
  323. Routine Description:
  324. Wraps up the call to LsaLogonUser
  325. Arguments:
  326. LsaHandle -- handle to LSA package
  327. AuthenticationPackage -- ID of authentication package to use
  328. LogonType -- Interactive, network, ...
  329. UserName -- User Name
  330. Domain -- Domain validating the user name
  331. Password -- clear text password, can be empty if a sub-auth package is used
  332. Workstation -- workstation where the login take place, can be NULL
  333. if local login
  334. dwSubAuth -- Sub-authentication DLL ID
  335. LogonSid -- Logon SID for this session
  336. LogonId -- created logon ID
  337. LogonToken -- created logon token
  338. Quotas -- quota info
  339. pProfileBuffer -- account profile
  340. pProfileBufferLength -- account profile length
  341. pSubStatus -- substatus for authentication failure
  342. Returns:
  343. 0 if success, else NT status
  344. --*/
  345. {
  346. NTSTATUS Status;
  347. STRING OriginName;
  348. TOKEN_SOURCE SourceContext;
  349. PMSV1_0_LM20_LOGON MsvAuthInfo;
  350. PMSV1_0_LM20_LOGON MsvNetAuthInfo;
  351. PMSV1_0_INTERACTIVE_LOGON MsvInterAuthInfo;
  352. PMSV1_0_SUBAUTH_LOGON MsvSubAuthInfo;
  353. PVOID AuthInfoBuf;
  354. ULONG AuthInfoSize;
  355. PTOKEN_GROUPS TokenGroups;
  356. PSID LocalSid;
  357. UNICODE_STRING UnicodePassword;
  358. //WCHAR ComputerName[ MAX_COMPUTERNAME_LENGTH + 1 ];
  359. DWORD ComputerNameLength;
  360. NT_RESPONSE NtResponse;
  361. LM_RESPONSE LmResponse;
  362. union {
  363. LUID Luid;
  364. NT_CHALLENGE NtChallenge;
  365. } Challenge;
  366. NT_OWF_PASSWORD PasswordHash;
  367. OEM_STRING LmPassword;
  368. UCHAR LmPasswordBuf[ LM20_PWLEN + 1 ];
  369. LM_OWF_PASSWORD LmPasswordHash;
  370. #if DBG
  371. if (!RtlValidSid(LogonSid))
  372. {
  373. return(STATUS_INVALID_PARAMETER);
  374. }
  375. #endif
  376. //
  377. // Initialize source context structure
  378. //
  379. strncpy(SourceContext.SourceName, "IIS ", sizeof(SourceContext.SourceName)); // LATER from res file
  380. Status = NtAllocateLocallyUniqueId(&SourceContext.SourceIdentifier);
  381. if (!NT_SUCCESS(Status))
  382. {
  383. return(Status);
  384. }
  385. UnicodePassword.Buffer = NULL;
  386. //
  387. // Set logon origin
  388. //
  389. RtlInitString(&OriginName, "IIS security API");
  390. //
  391. // For network logons, do the magic.
  392. //
  393. if ( LogonType == Network )
  394. {
  395. #if 0
  396. ComputerNameLength = MAX_COMPUTERNAME_LENGTH + 1;
  397. if (!GetComputerNameW( ComputerName, &ComputerNameLength ) )
  398. {
  399. return( STATUS_INVALID_PARAMETER );
  400. }
  401. #else
  402. ComputerNameLength = wcslen( Workstation->Buffer );
  403. #endif
  404. if (!RtlCreateUnicodeStringFromAsciiz( &UnicodePassword, Password->Buffer ))
  405. {
  406. return STATUS_NO_MEMORY;
  407. }
  408. AuthInfoSize = sizeof( MSV1_0_LM20_LOGON ) +
  409. sizeof( WCHAR ) * ( wcslen( UserName->Buffer ) + 1 +
  410. wcslen( Domain->Buffer ) + 1 +
  411. ComputerNameLength + 1) +
  412. NT_RESPONSE_LENGTH +
  413. LM_RESPONSE_LENGTH ;
  414. MsvNetAuthInfo = (PMSV1_0_LM20_LOGON)
  415. (AuthInfoBuf = RtlAllocateHeap( RtlProcessHeap(),
  416. HEAP_ZERO_MEMORY,
  417. AuthInfoSize ));
  418. if ( !MsvNetAuthInfo )
  419. {
  420. return( STATUS_NO_MEMORY );
  421. }
  422. //
  423. // Start packing in the string
  424. //
  425. MsvNetAuthInfo->MessageType = MsV1_0NetworkLogon;
  426. //
  427. // Copy the user name into the authentication buffer
  428. //
  429. MsvNetAuthInfo->UserName.Length =
  430. (USHORT)sizeof(WCHAR)*wcslen(UserName->Buffer);
  431. MsvNetAuthInfo->UserName.MaximumLength =
  432. MsvNetAuthInfo->UserName.Length + sizeof(WCHAR);
  433. MsvNetAuthInfo->UserName.Buffer = (PWSTR)(MsvNetAuthInfo+1);
  434. wcscpy(MsvNetAuthInfo->UserName.Buffer, UserName->Buffer);
  435. //
  436. // Copy the domain name into the authentication buffer
  437. //
  438. MsvNetAuthInfo->LogonDomainName.Length =
  439. (USHORT)sizeof(WCHAR)*wcslen(Domain->Buffer);
  440. MsvNetAuthInfo->LogonDomainName.MaximumLength =
  441. MsvNetAuthInfo->LogonDomainName.Length + sizeof(WCHAR);
  442. MsvNetAuthInfo->LogonDomainName.Buffer = (PWSTR)
  443. ((PBYTE)(MsvNetAuthInfo->UserName.Buffer) +
  444. MsvNetAuthInfo->UserName.MaximumLength);
  445. wcscpy(MsvNetAuthInfo->LogonDomainName.Buffer, Domain->Buffer);
  446. //
  447. // Copy the workstation name into the buffer
  448. //
  449. MsvNetAuthInfo->Workstation.Length = (USHORT)
  450. (sizeof(WCHAR) * ComputerNameLength);
  451. MsvNetAuthInfo->Workstation.MaximumLength =
  452. MsvNetAuthInfo->Workstation.Length + sizeof(WCHAR);
  453. MsvNetAuthInfo->Workstation.Buffer = (PWSTR)
  454. ((PBYTE) (MsvNetAuthInfo->LogonDomainName.Buffer) +
  455. MsvNetAuthInfo->LogonDomainName.MaximumLength );
  456. wcscpy( MsvNetAuthInfo->Workstation.Buffer, Workstation->Buffer );
  457. //
  458. // Now, generate the bits for the challenge
  459. //
  460. Status = NtAllocateLocallyUniqueId( &Challenge.Luid );
  461. if ( !NT_SUCCESS(Status) )
  462. {
  463. RtlFreeHeap( RtlProcessHeap(), 0, MsvNetAuthInfo );
  464. return( Status );
  465. }
  466. RtlCopyMemory( MsvNetAuthInfo->ChallengeToClient,
  467. & Challenge,
  468. MSV1_0_CHALLENGE_LENGTH );
  469. //
  470. // Set up space for response
  471. //
  472. MsvNetAuthInfo->CaseSensitiveChallengeResponse.Buffer = (PCHAR)
  473. ((PBYTE) (MsvNetAuthInfo->Workstation.Buffer) +
  474. MsvNetAuthInfo->Workstation.MaximumLength );
  475. MsvNetAuthInfo->CaseSensitiveChallengeResponse.Length =
  476. NT_RESPONSE_LENGTH;
  477. MsvNetAuthInfo->CaseSensitiveChallengeResponse.MaximumLength =
  478. NT_RESPONSE_LENGTH;
  479. RtlCalculateNtOwfPassword(
  480. & UnicodePassword,
  481. & PasswordHash );
  482. RtlCalculateNtResponse(
  483. & Challenge.NtChallenge,
  484. & PasswordHash,
  485. & NtResponse );
  486. RtlCopyMemory( MsvNetAuthInfo->CaseSensitiveChallengeResponse.Buffer,
  487. & NtResponse,
  488. NT_RESPONSE_LENGTH );
  489. //
  490. // Now do the painful LM compatible hash, so anyone who is maintaining
  491. // their account from a WfW machine will still have a password.
  492. //
  493. LmPassword.Buffer = (CHAR*)LmPasswordBuf;
  494. LmPassword.Length = LmPassword.MaximumLength = LM20_PWLEN + 1;
  495. Status = RtlUpcaseUnicodeStringToOemString(
  496. & LmPassword,
  497. & UnicodePassword,
  498. FALSE );
  499. if ( NT_SUCCESS(Status) )
  500. {
  501. MsvNetAuthInfo->CaseInsensitiveChallengeResponse.Buffer = (PCHAR)
  502. ((PBYTE) (MsvNetAuthInfo->CaseSensitiveChallengeResponse.Buffer) +
  503. MsvNetAuthInfo->CaseSensitiveChallengeResponse.MaximumLength );
  504. MsvNetAuthInfo->CaseInsensitiveChallengeResponse.Length =
  505. LM_RESPONSE_LENGTH;
  506. MsvNetAuthInfo->CaseInsensitiveChallengeResponse.MaximumLength =
  507. LM_RESPONSE_LENGTH;
  508. RtlCalculateLmOwfPassword(
  509. LmPassword.Buffer,
  510. & LmPasswordHash );
  511. ZeroMemory( LmPassword.Buffer, LmPassword.Length );
  512. RtlCalculateLmResponse(
  513. & Challenge.NtChallenge,
  514. & LmPasswordHash,
  515. & LmResponse );
  516. RtlCopyMemory( MsvNetAuthInfo->CaseInsensitiveChallengeResponse.Buffer,
  517. & LmResponse,
  518. LM_RESPONSE_LENGTH );
  519. }
  520. else
  521. {
  522. //
  523. // If we're here, the NT (supplied) password is longer than the
  524. // limit allowed for LM passwords. NULL out the field, so that
  525. // MSV knows not to worry about it.
  526. //
  527. RtlZeroMemory( &MsvNetAuthInfo->CaseInsensitiveChallengeResponse,
  528. sizeof( STRING ) );
  529. }
  530. MsvNetAuthInfo->ParameterControl = MSV1_0_RETURN_PASSWORD_EXPIRY;
  531. }
  532. else if ( LogonType == (SECURITY_LOGON_TYPE)IIS_Network )
  533. {
  534. if (!RtlCreateUnicodeStringFromAsciiz( &UnicodePassword, Password->Buffer ))
  535. {
  536. return STATUS_NO_MEMORY;
  537. }
  538. //
  539. // Build logon structure for IIS network logons. We'll be using the subauth DLL
  540. // in this case
  541. //
  542. AuthInfoSize = sizeof(MSV1_0_SUBAUTH_LOGON) +
  543. sizeof(WCHAR)*(wcslen(UserName->Buffer) + 1 +
  544. wcslen(Domain->Buffer) + 1 +
  545. wcslen(Workstation->Buffer) + 1 ) +
  546. sizeof(WCHAR)*wcslen(UnicodePassword.Buffer) +
  547. LEN_ALIGN(strlen(Password->Buffer),sizeof(WCHAR));
  548. AuthInfoBuf = RtlAllocateHeap( RtlProcessHeap(),
  549. HEAP_ZERO_MEMORY,
  550. AuthInfoSize);
  551. MsvSubAuthInfo = (PMSV1_0_SUBAUTH_LOGON)AuthInfoBuf;
  552. if (MsvSubAuthInfo == NULL) {
  553. return(STATUS_NO_MEMORY);
  554. }
  555. //
  556. // This authentication buffer will be used for a logon attempt
  557. //
  558. MsvSubAuthInfo->MessageType = MsV1_0SubAuthLogon;
  559. MsvSubAuthInfo->SubAuthPackageId = dwSubAuth;
  560. //
  561. // Copy the domain name into the authentication buffer
  562. //
  563. MsvSubAuthInfo->LogonDomainName.Length =
  564. (USHORT)sizeof(WCHAR)*wcslen(Domain->Buffer);
  565. MsvSubAuthInfo->LogonDomainName.MaximumLength =
  566. MsvSubAuthInfo->LogonDomainName.Length + sizeof(WCHAR);
  567. MsvSubAuthInfo->LogonDomainName.Buffer = (PWSTR)(MsvSubAuthInfo+1);
  568. wcscpy(MsvSubAuthInfo->LogonDomainName.Buffer, Domain->Buffer);
  569. //
  570. // Copy the user name into the authentication buffer
  571. //
  572. MsvSubAuthInfo->UserName.Length =
  573. (USHORT)sizeof(WCHAR)*wcslen(UserName->Buffer);
  574. MsvSubAuthInfo->UserName.MaximumLength =
  575. MsvSubAuthInfo->UserName.Length + sizeof(WCHAR);
  576. MsvSubAuthInfo->UserName.Buffer = (PWSTR)
  577. ((PBYTE)(MsvSubAuthInfo->LogonDomainName.Buffer) +
  578. MsvSubAuthInfo->LogonDomainName.MaximumLength);
  579. wcscpy(MsvSubAuthInfo->UserName.Buffer, UserName->Buffer);
  580. //
  581. // Copy the workstation
  582. //
  583. MsvSubAuthInfo->Workstation.Length =
  584. (USHORT)sizeof(WCHAR)*wcslen(Workstation->Buffer);
  585. MsvSubAuthInfo->Workstation.MaximumLength =
  586. MsvSubAuthInfo->Workstation.Length + sizeof(WCHAR);
  587. MsvSubAuthInfo->Workstation.Buffer = (PWSTR)
  588. ((PBYTE)(MsvSubAuthInfo->UserName.Buffer) +
  589. MsvSubAuthInfo->UserName.MaximumLength);
  590. wcscpy(MsvSubAuthInfo->Workstation.Buffer, Workstation->Buffer);
  591. memset( MsvSubAuthInfo->ChallengeToClient,
  592. '\0',
  593. sizeof(MsvSubAuthInfo->ChallengeToClient) );
  594. MsvSubAuthInfo->AuthenticationInfo1.Buffer =
  595. ((PCHAR)(MsvSubAuthInfo->Workstation.Buffer) +
  596. MsvSubAuthInfo->Workstation.MaximumLength);
  597. MsvSubAuthInfo->AuthenticationInfo1.Length = (USHORT)sizeof(WCHAR)*wcslen(UnicodePassword.Buffer);
  598. MsvSubAuthInfo->AuthenticationInfo1.MaximumLength
  599. = MsvSubAuthInfo->AuthenticationInfo1.Length;
  600. memcpy( MsvSubAuthInfo->AuthenticationInfo1.Buffer,
  601. UnicodePassword.Buffer,
  602. MsvSubAuthInfo->AuthenticationInfo1.Length );
  603. MsvSubAuthInfo->AuthenticationInfo2.Buffer =
  604. ((PCHAR)(MsvSubAuthInfo->AuthenticationInfo1.Buffer) +
  605. MsvSubAuthInfo->AuthenticationInfo1.MaximumLength);
  606. MsvSubAuthInfo->AuthenticationInfo2.Length = (USHORT)strlen(Password->Buffer);
  607. MsvSubAuthInfo->AuthenticationInfo2.MaximumLength
  608. = LEN_ALIGN(MsvSubAuthInfo->AuthenticationInfo2.Length,sizeof(WCHAR));
  609. memcpy( MsvSubAuthInfo->AuthenticationInfo2.Buffer,
  610. Password->Buffer,
  611. MsvSubAuthInfo->AuthenticationInfo2.Length );
  612. MsvSubAuthInfo->ParameterControl = (dwSubAuth << MSV1_0_SUBAUTHENTICATION_DLL_SHIFT)
  613. | MSV1_0_UPDATE_LOGON_STATISTICS
  614. | MSV1_0_DONT_TRY_GUEST_ACCOUNT
  615. | MSV1_0_CLEARTEXT_PASSWORD_ALLOWED
  616. | MSV1_0_RETURN_PASSWORD_EXPIRY
  617. | MSV1_0_SUBAUTHENTICATION_DLL_EX
  618. | MSV1_0_DISABLE_PERSONAL_FALLBACK
  619. ;
  620. LogonType = Network;
  621. }
  622. else
  623. {
  624. //
  625. // Build logon structure for non-network logons - service,
  626. // batch, interactive
  627. //
  628. if (!RtlCreateUnicodeStringFromAsciiz( &UnicodePassword, Password->Buffer ))
  629. {
  630. return STATUS_NO_MEMORY;
  631. }
  632. AuthInfoSize = sizeof(MSV1_0_INTERACTIVE_LOGON) +
  633. sizeof(WCHAR)*(wcslen(UserName->Buffer) + 1 +
  634. wcslen(Domain->Buffer) + 1 +
  635. wcslen(UnicodePassword.Buffer) + 1 );
  636. AuthInfoBuf = RtlAllocateHeap( RtlProcessHeap(),
  637. HEAP_ZERO_MEMORY,
  638. AuthInfoSize);
  639. MsvInterAuthInfo = (PMSV1_0_INTERACTIVE_LOGON)AuthInfoBuf;
  640. if (MsvInterAuthInfo == NULL)
  641. {
  642. return STATUS_NO_MEMORY;
  643. }
  644. //
  645. // This authentication buffer will be used for a logon attempt
  646. //
  647. MsvInterAuthInfo->MessageType = MsV1_0InteractiveLogon;
  648. //
  649. // Copy the user name into the authentication buffer
  650. //
  651. MsvInterAuthInfo->UserName.Length =
  652. (USHORT)sizeof(WCHAR)*wcslen(UserName->Buffer);
  653. MsvInterAuthInfo->UserName.MaximumLength =
  654. MsvInterAuthInfo->UserName.Length + sizeof(WCHAR);
  655. MsvInterAuthInfo->UserName.Buffer = (PWSTR)(MsvInterAuthInfo+1);
  656. wcscpy(MsvInterAuthInfo->UserName.Buffer, UserName->Buffer);
  657. //
  658. // Copy the domain name into the authentication buffer
  659. //
  660. MsvInterAuthInfo->LogonDomainName.Length =
  661. (USHORT)sizeof(WCHAR)*wcslen(Domain->Buffer);
  662. MsvInterAuthInfo->LogonDomainName.MaximumLength =
  663. MsvInterAuthInfo->LogonDomainName.Length + sizeof(WCHAR);
  664. MsvInterAuthInfo->LogonDomainName.Buffer = (PWSTR)
  665. ((PBYTE)(MsvInterAuthInfo->UserName.Buffer) +
  666. MsvInterAuthInfo->UserName.MaximumLength);
  667. wcscpy(MsvInterAuthInfo->LogonDomainName.Buffer, Domain->Buffer);
  668. //
  669. // Copy the password into the authentication buffer
  670. // Hide it once we have copied it. Use the same seed value
  671. // that we used for the original password in pGlobals.
  672. //
  673. MsvInterAuthInfo->Password.Length =
  674. (USHORT)sizeof(WCHAR)*wcslen(UnicodePassword.Buffer);
  675. MsvInterAuthInfo->Password.MaximumLength =
  676. MsvInterAuthInfo->Password.Length + sizeof(WCHAR);
  677. MsvInterAuthInfo->Password.Buffer = (PWSTR)
  678. ((PBYTE)(MsvInterAuthInfo->LogonDomainName.Buffer) +
  679. MsvInterAuthInfo->LogonDomainName.MaximumLength);
  680. wcscpy(MsvInterAuthInfo->Password.Buffer, UnicodePassword.Buffer);
  681. }
  682. //
  683. // Create logon token groups
  684. //
  685. #define TOKEN_GROUP_COUNT 2 // We'll add the local SID and the logon SID
  686. TokenGroups = (PTOKEN_GROUPS) RtlAllocateHeap(RtlProcessHeap(), 0,
  687. sizeof(TOKEN_GROUPS) +
  688. (TOKEN_GROUP_COUNT - ANYSIZE_ARRAY) * sizeof(SID_AND_ATTRIBUTES));
  689. if (TokenGroups == NULL) {
  690. RtlFreeHeap(RtlProcessHeap(), 0, AuthInfoBuf);
  691. return(STATUS_NO_MEMORY);
  692. }
  693. //
  694. // Fill in the logon token group list
  695. //
  696. Status = RtlAllocateAndInitializeSid(
  697. &L32LocalSidAuthority,
  698. 1,
  699. SECURITY_LOCAL_RID,
  700. 0, 0, 0, 0, 0, 0, 0,
  701. &LocalSid
  702. );
  703. TokenGroups->GroupCount = TOKEN_GROUP_COUNT;
  704. TokenGroups->Groups[0].Sid = LogonSid;
  705. TokenGroups->Groups[0].Attributes =
  706. SE_GROUP_MANDATORY | SE_GROUP_ENABLED |
  707. SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_LOGON_ID;
  708. TokenGroups->Groups[1].Sid = LocalSid;
  709. TokenGroups->Groups[1].Attributes =
  710. SE_GROUP_MANDATORY | SE_GROUP_ENABLED |
  711. SE_GROUP_ENABLED_BY_DEFAULT;
  712. //
  713. // Now try to log this one on
  714. //
  715. Status = LsaLogonUser (
  716. LsaHandle,
  717. &OriginName,
  718. LogonType,
  719. AuthenticationPackage,
  720. AuthInfoBuf,
  721. AuthInfoSize,
  722. TokenGroups,
  723. &SourceContext,
  724. pProfileBuffer,
  725. pProfileBufferLength,
  726. LogonId,
  727. LogonToken,
  728. Quotas,
  729. pSubStatus
  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. LogonType != IIS_Network )
  741. {
  742. L32pNotifyMpr( (PMSV1_0_INTERACTIVE_LOGON)AuthInfoBuf, LogonId );
  743. }
  744. //
  745. // Discard authentication buffer
  746. //
  747. RtlFreeHeap(RtlProcessHeap(), 0, AuthInfoBuf);
  748. if ( UnicodePassword.Buffer != NULL )
  749. {
  750. RtlFreeUnicodeString(&UnicodePassword);
  751. }
  752. RtlFreeSid(LocalSid);
  753. return(Status);
  754. }
  755. BOOL
  756. WINAPI
  757. IISLogonNetUserW(
  758. PWSTR lpszUsername,
  759. PWSTR lpszDomain,
  760. PSTR lpszPassword,
  761. PWSTR lpszWorkstation,
  762. DWORD dwSubAuth,
  763. DWORD dwLogonType,
  764. DWORD dwLogonProvider,
  765. HANDLE * phToken,
  766. LARGE_INTEGER * pExpiry
  767. )
  768. /*++
  769. Routine Description:
  770. Logs a user on via username and domain
  771. name via the LSA.
  772. Arguments:
  773. lpszUsername -- user name
  774. lpszDomain -- domain validating the user name
  775. lpszPassword -- clear text password, can be empty if a sub-auth DLL
  776. is used
  777. lpszWorkstation -- workstation requesting the login, can be NULL
  778. for local workstation
  779. dwSubAuth -- sub-auth DLL ID
  780. dwLogonType -- one of LOGON32_LOGON_NETWORK, LOGON32_LOGON_IIS_NETWORK
  781. dwLogonProvider -- must be LOGON32_PROVIDER_DEFAULT
  782. phToken -- created access token
  783. pExpiry -- ptr to pwd expiration time
  784. Returns:
  785. TRUE if success, FALSE if error
  786. --*/
  787. {
  788. NTSTATUS Status;
  789. ULONG PackageId;
  790. UNICODE_STRING Username;
  791. UNICODE_STRING Domain;
  792. STRING Password;
  793. UNICODE_STRING Workstation;
  794. LUID LogonId;
  795. PSID pLogonSid;
  796. PVOID Profile;
  797. ULONG ProfileLength;
  798. NTSTATUS SubStatus;
  799. SECURITY_LOGON_TYPE LogonType;
  800. WCHAR achComputerName[MAX_COMPUTERNAME_LENGTH+1];
  801. //
  802. // Validate the provider
  803. //
  804. if (dwLogonProvider == LOGON32_PROVIDER_DEFAULT)
  805. {
  806. dwLogonProvider = LOGON32_PROVIDER_WINNT35;
  807. }
  808. if (dwLogonProvider != LOGON32_PROVIDER_WINNT35)
  809. {
  810. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  811. return(FALSE);
  812. }
  813. switch (dwLogonType)
  814. {
  815. case LOGON32_LOGON_IIS_NETWORK:
  816. LogonType = (SECURITY_LOGON_TYPE)IIS_Network;
  817. break;
  818. case LOGON32_LOGON_NETWORK:
  819. LogonType = Network;
  820. break;
  821. case LOGON32_LOGON_INTERACTIVE:
  822. LogonType = Interactive;
  823. break;
  824. case LOGON32_LOGON_BATCH:
  825. LogonType = Batch;
  826. break;
  827. case LOGON32_LOGON_SERVICE:
  828. LogonType = Service;
  829. break;
  830. case LOGON32_LOGON_NETWORK_CLEARTEXT:
  831. LogonType = NetworkCleartext;
  832. break;
  833. default:
  834. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  835. return(FALSE);
  836. break;
  837. }
  838. if ( lpszWorkstation == NULL )
  839. {
  840. DWORD dwL = MAX_COMPUTERNAME_LENGTH+1;
  841. if ( !GetComputerNameW( achComputerName, &dwL ) )
  842. {
  843. return(FALSE);
  844. }
  845. lpszWorkstation = achComputerName;
  846. }
  847. //
  848. // Initialize LSA stuff only once
  849. //
  850. if ( !fLsaInitialized )
  851. {
  852. LockLogon();
  853. if ( !fLsaInitialized )
  854. {
  855. if ( !L32pInitLsa() )
  856. {
  857. UnlockLogon();
  858. return FALSE;
  859. }
  860. }
  861. UnlockLogon();
  862. }
  863. //
  864. // Validate the parameters. NULL or empty domain or NULL or empty
  865. // user name is invalid.
  866. //
  867. RtlInitUnicodeString(&Username, lpszUsername);
  868. if (Username.Length == 0)
  869. {
  870. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  871. return(FALSE);
  872. }
  873. RtlInitUnicodeString(&Domain, lpszDomain);
  874. RtlInitString(&Password, lpszPassword);
  875. //
  876. // Finally, init the workstation
  877. //
  878. RtlInitUnicodeString(&Workstation, lpszWorkstation);
  879. //
  880. // Get a logon sid to refer to this guy (not that anyone will be able to
  881. // use it...
  882. //
  883. pLogonSid = L32CreateLogonSid(NULL);
  884. if (!pLogonSid)
  885. {
  886. BaseSetLastNTError(STATUS_NO_MEMORY);
  887. return(FALSE);
  888. }
  889. //
  890. // Attempt the logon
  891. //
  892. Status = L32pLogonNetUser(
  893. Logon32LsaHandle,
  894. Logon32MsvHandle,
  895. LogonType,
  896. &Username,
  897. &Domain,
  898. &Password,
  899. &Workstation,
  900. dwSubAuth,
  901. pLogonSid,
  902. &LogonId,
  903. phToken,
  904. &Logon32QuotaLimits,
  905. &Profile,
  906. &ProfileLength,
  907. &SubStatus);
  908. //
  909. // Done with logon sid, regardless of result:
  910. //
  911. LocalFree( pLogonSid );
  912. if (!NT_SUCCESS(Status))
  913. {
  914. if (Status == STATUS_ACCOUNT_RESTRICTION)
  915. {
  916. BaseSetLastNTError(SubStatus);
  917. }
  918. else
  919. {
  920. BaseSetLastNTError(Status);
  921. }
  922. return(FALSE);
  923. }
  924. if (Profile != NULL)
  925. {
  926. if ( pExpiry != NULL )
  927. {
  928. switch ( dwLogonType )
  929. {
  930. case LOGON32_LOGON_IIS_NETWORK:
  931. case LOGON32_LOGON_NETWORK:
  932. memcpy( pExpiry,
  933. &(((PMSV1_0_LM20_LOGON_PROFILE)Profile)
  934. ->LogoffTime),
  935. sizeof(LARGE_INTEGER) );
  936. break;
  937. default:
  938. //
  939. // if pwd never expire, MustChange.HighPart == 0x7fffffff
  940. // if user cannot change pwd, CanChange == LastSet
  941. //
  942. if ( ((PMSV1_0_INTERACTIVE_PROFILE)Profile)
  943. ->PasswordMustChange.HighPart
  944. != 0x7fffffff )
  945. {
  946. memcpy( pExpiry,
  947. &(((PMSV1_0_INTERACTIVE_PROFILE)Profile)
  948. ->PasswordMustChange),
  949. sizeof(LARGE_INTEGER) );
  950. }
  951. else
  952. {
  953. ((PMSV1_0_INTERACTIVE_PROFILE)Profile)
  954. ->PasswordMustChange.LowPart = 0xffffffff;
  955. ((PMSV1_0_INTERACTIVE_PROFILE)Profile)
  956. ->PasswordMustChange.HighPart = 0x7fffffff;
  957. }
  958. break;
  959. }
  960. }
  961. LsaFreeReturnBuffer(Profile);
  962. }
  963. return(TRUE);
  964. }
  965. BOOL
  966. WINAPI
  967. IISLogonNetUserA(
  968. PSTR lpszUsername,
  969. PSTR lpszDomain,
  970. PSTR lpszPassword,
  971. PSTR lpszWorkstation,
  972. DWORD dwSubAuth,
  973. DWORD dwLogonType,
  974. DWORD dwLogonProvider,
  975. HANDLE * phToken,
  976. LARGE_INTEGER * pExpiry
  977. )
  978. /*++
  979. Routine Description:
  980. Logs a user on via username and domain
  981. name via the LSA.
  982. Arguments:
  983. lpszUsername -- user name
  984. lpszDomain -- domain validating the user name
  985. lpszPassword -- clear text password, can be empty if a sub-auth DLL
  986. is used
  987. lpszWorkstation -- workstation requesting the login, can be NULL
  988. for local workstation
  989. dwSubAuth -- sub-auth DLL ID
  990. dwLogonType -- one of LOGON32_LOGON_NETWORK, LOGON32_LOGON_IIS_NETWORK
  991. dwLogonProvider -- must be LOGON32_PROVIDER_DEFAULT
  992. phToken -- created access token
  993. pExpiry -- ptr to pwd expiration time
  994. Returns:
  995. TRUE if success, FALSE if error
  996. --*/
  997. {
  998. UNICODE_STRING Username;
  999. UNICODE_STRING Domain;
  1000. UNICODE_STRING Workstation;
  1001. NTSTATUS Status;
  1002. BOOL bRet;
  1003. Username.Buffer = NULL;
  1004. Domain.Buffer = NULL;
  1005. Workstation.Buffer = NULL;
  1006. if ( !RtlCreateUnicodeStringFromAsciiz(&Username, lpszUsername) )
  1007. {
  1008. bRet = FALSE;
  1009. goto Cleanup;
  1010. }
  1011. if (!RtlCreateUnicodeStringFromAsciiz(&Domain, lpszDomain))
  1012. {
  1013. bRet = FALSE;
  1014. goto Cleanup;
  1015. }
  1016. if ( lpszWorkstation )
  1017. {
  1018. if (!RtlCreateUnicodeStringFromAsciiz(&Workstation, lpszWorkstation))
  1019. {
  1020. bRet = FALSE;
  1021. goto Cleanup;
  1022. }
  1023. }
  1024. bRet = IISLogonNetUserW(
  1025. Username.Buffer,
  1026. Domain.Buffer,
  1027. lpszPassword,
  1028. Workstation.Buffer,
  1029. dwSubAuth,
  1030. dwLogonType,
  1031. dwLogonProvider,
  1032. phToken,
  1033. pExpiry
  1034. ) ;
  1035. Cleanup:
  1036. if (Username.Buffer)
  1037. {
  1038. RtlFreeUnicodeString(&Username);
  1039. }
  1040. if (Domain.Buffer)
  1041. {
  1042. RtlFreeUnicodeString(&Domain);
  1043. }
  1044. if (Workstation.Buffer)
  1045. {
  1046. RtlFreeUnicodeString(&Workstation);
  1047. }
  1048. return bRet;
  1049. }
  1050. BOOL
  1051. WINAPI
  1052. IISNetUserCookieA(
  1053. LPSTR lpszUsername,
  1054. DWORD dwSeed,
  1055. LPSTR lpszCookieBuff,
  1056. DWORD dwBuffSize
  1057. )
  1058. /*++
  1059. Routine Description:
  1060. Compute logon validator ( to be used as password )
  1061. for IISSuba
  1062. Arguments:
  1063. lpszUsername -- user name
  1064. dwSeed -- start value of cookie
  1065. Returns:
  1066. TRUE if success, FALSE if error
  1067. --*/
  1068. {
  1069. UNICODE_STRING Username;
  1070. LPWSTR lpwszUserName;
  1071. NTSTATUS Status;
  1072. #define TOHEX(a) ((a)>=10 ? 'a'+(a)-10 : '0'+(a))
  1073. if ( dwBuffSize < sizeof(dwSeed)*2 + 1 )
  1074. {
  1075. SetLastError( ERROR_INSUFFICIENT_BUFFER );
  1076. return FALSE;
  1077. }
  1078. if ( !RtlCreateUnicodeStringFromAsciiz(&Username, lpszUsername) )
  1079. {
  1080. return FALSE;
  1081. }
  1082. lpwszUserName = Username.Buffer;
  1083. while ( *lpwszUserName )
  1084. {
  1085. dwSeed = ((dwSeed << 5) | ( dwSeed >> 27 )) ^ ((*lpwszUserName++)&0xff);
  1086. }
  1087. RtlFreeUnicodeString(&Username);
  1088. lpszCookieBuff[0] = '0' + IISSUBA_COOKIE;
  1089. lpszCookieBuff[1] = '"';
  1090. for ( UINT x = 0, y = 2 ; x < sizeof(dwSeed) ; ++x )
  1091. {
  1092. UINT v;
  1093. v = ((LPBYTE)&dwSeed)[x]>>4;
  1094. lpszCookieBuff[y++] = TOHEX( v );
  1095. v = ((LPBYTE)&dwSeed)[x]&0x0f;
  1096. lpszCookieBuff[y++] = TOHEX( v );
  1097. }
  1098. lpszCookieBuff[y] = '\0';
  1099. return TRUE;
  1100. }
  1101. BOOL
  1102. WINAPI
  1103. IISLogonDigestUserA(
  1104. PDIGEST_LOGON_INFO pDigestLogonInfo,
  1105. DWORD dwAlgo,
  1106. HANDLE * phToken
  1107. )
  1108. /*++
  1109. Routine Description:
  1110. Logs a user on via username and domain
  1111. name via the LSA using Digest authentication
  1112. Arguments:
  1113. pDigestLogonInfo - Digest parameters for use in logon
  1114. dwAlgo - type of logon
  1115. phToken -- created access token
  1116. Returns:
  1117. TRUE if success, FALSE if error
  1118. --*/
  1119. {
  1120. UNICODE_STRING Username;
  1121. UNICODE_STRING Domain;
  1122. STRING Password;
  1123. NTSTATUS Status;
  1124. BOOL bRet;
  1125. char achA[3];
  1126. int l;
  1127. Username.Buffer = NULL;
  1128. Domain.Buffer = NULL;
  1129. Password.Buffer = NULL;
  1130. if (!RtlCreateUnicodeStringFromAsciiz(&Username,
  1131. pDigestLogonInfo->pszNtUser))
  1132. {
  1133. bRet = FALSE;
  1134. goto Cleanup;
  1135. }
  1136. if (!RtlCreateUnicodeStringFromAsciiz(&Domain,
  1137. pDigestLogonInfo->pszDomain))
  1138. {
  1139. bRet = FALSE;
  1140. goto Cleanup;
  1141. }
  1142. achA[0] = (int)dwAlgo + '0';
  1143. achA[1] = '"';
  1144. achA[2] = '\0';
  1145. l = strlen(achA) +
  1146. strlen(pDigestLogonInfo->pszRealm) +
  1147. strlen(pDigestLogonInfo->pszURI) +
  1148. strlen(pDigestLogonInfo->pszMethod) +
  1149. strlen(pDigestLogonInfo->pszNonce) +
  1150. strlen(pDigestLogonInfo->pszCurrentNonce) +
  1151. strlen(pDigestLogonInfo->pszResponse) +
  1152. strlen(pDigestLogonInfo->pszUser) +
  1153. strlen(pDigestLogonInfo->pszQOP) +
  1154. strlen(pDigestLogonInfo->pszCNonce) +
  1155. strlen(pDigestLogonInfo->pszNC) +
  1156. 32;
  1157. if ( Password.Buffer = (CHAR*)RtlAllocateHeap( RtlProcessHeap(), HEAP_ZERO_MEMORY, l) )
  1158. {
  1159. Password.MaximumLength = (USHORT)l;
  1160. }
  1161. else
  1162. {
  1163. Password.MaximumLength = 0;
  1164. }
  1165. Password.Length = 0;
  1166. if( !NT_SUCCESS( Status = RtlAppendAsciizToString( &Password, achA)) ||
  1167. !NT_SUCCESS( Status = RtlAppendAsciizToString( &Password, pDigestLogonInfo->pszRealm)) ||
  1168. !NT_SUCCESS( Status = RtlAppendAsciizToString( &Password, "\"")) ||
  1169. !NT_SUCCESS( Status = RtlAppendAsciizToString( &Password, pDigestLogonInfo->pszURI)) ||
  1170. !NT_SUCCESS( Status = RtlAppendAsciizToString( &Password, "\"")) ||
  1171. !NT_SUCCESS( Status = RtlAppendAsciizToString( &Password, pDigestLogonInfo->pszMethod)) ||
  1172. !NT_SUCCESS( Status = RtlAppendAsciizToString( &Password, "\"")) ||
  1173. !NT_SUCCESS( Status = RtlAppendAsciizToString( &Password, pDigestLogonInfo->pszNonce)) ||
  1174. !NT_SUCCESS( Status = RtlAppendAsciizToString( &Password, "\"")) ||
  1175. !NT_SUCCESS( Status = RtlAppendAsciizToString( &Password, pDigestLogonInfo->pszCurrentNonce)) ||
  1176. !NT_SUCCESS( Status = RtlAppendAsciizToString( &Password, "\"")) ||
  1177. !NT_SUCCESS( Status = RtlAppendAsciizToString( &Password, pDigestLogonInfo->pszResponse)) ||
  1178. !NT_SUCCESS( Status = RtlAppendAsciizToString( &Password, "\"")) ||
  1179. !NT_SUCCESS( Status = RtlAppendAsciizToString( &Password, pDigestLogonInfo->pszUser)) ||
  1180. !NT_SUCCESS( Status = RtlAppendAsciizToString( &Password, "\"")) ||
  1181. !NT_SUCCESS( Status = RtlAppendAsciizToString( &Password, pDigestLogonInfo->pszQOP)) ||
  1182. !NT_SUCCESS( Status = RtlAppendAsciizToString( &Password, "\"")) ||
  1183. !NT_SUCCESS( Status = RtlAppendAsciizToString( &Password, pDigestLogonInfo->pszCNonce)) ||
  1184. !NT_SUCCESS( Status = RtlAppendAsciizToString( &Password, "\"")) ||
  1185. !NT_SUCCESS( Status = RtlAppendAsciizToString( &Password, pDigestLogonInfo->pszNC)) ||
  1186. !NT_SUCCESS( Status = RtlAppendAsciizToString( &Password, "\"")) )
  1187. {
  1188. BaseSetLastNTError(Status);
  1189. bRet = FALSE;
  1190. goto Cleanup;
  1191. }
  1192. bRet = IISLogonNetUserW(
  1193. Username.Buffer,
  1194. Domain.Buffer,
  1195. Password.Buffer,
  1196. NULL,
  1197. IIS_SUBAUTH_ID,
  1198. LOGON32_LOGON_IIS_NETWORK,
  1199. LOGON32_PROVIDER_DEFAULT,
  1200. phToken,
  1201. NULL
  1202. ) ;
  1203. Cleanup:
  1204. if (Username.Buffer)
  1205. {
  1206. RtlFreeUnicodeString(&Username);
  1207. }
  1208. if (Domain.Buffer)
  1209. {
  1210. RtlFreeUnicodeString(&Domain);
  1211. }
  1212. if ( Password.Buffer )
  1213. {
  1214. RtlFreeHeap(RtlProcessHeap(), 0, Password.Buffer );
  1215. }
  1216. return bRet;
  1217. }
  1218. BOOL
  1219. WINAPI
  1220. IISLogonPassportUserW(
  1221. WCHAR * pszUserName,
  1222. WCHAR * pszDomainName,
  1223. HANDLE * phToken
  1224. )
  1225. /*++
  1226. Routine Description:
  1227. Get a passport user
  1228. Arguments:
  1229. pszUserName - User name
  1230. pszDomainName - Domain name
  1231. phToken - Receives token
  1232. Returns:
  1233. TRUE if success, FALSE if error
  1234. --*/
  1235. {
  1236. BOOL bRet;
  1237. STRING OriginName;
  1238. NTSTATUS Status;
  1239. KERB_S4U_LOGON* pLogonInfo;
  1240. ULONG cbLogonInfo;
  1241. STACK_BUFFER( buffLogonInfo, 256 );
  1242. DWORD cchUserName;
  1243. DWORD cchDomainName;
  1244. HANDLE hToken;
  1245. TOKEN_SOURCE SourceContext;
  1246. PKERB_INTERACTIVE_PROFILE pProfile = NULL;
  1247. LUID LogonId;
  1248. QUOTA_LIMITS Quotas;
  1249. NTSTATUS SubStatus;
  1250. DWORD cbProfile;
  1251. //
  1252. // Initialize LSA stuff only once
  1253. //
  1254. if ( !fLsaInitialized )
  1255. {
  1256. LockLogon();
  1257. if ( !fLsaInitialized )
  1258. {
  1259. if ( !L32pInitLsa() )
  1260. {
  1261. UnlockLogon();
  1262. return FALSE;
  1263. }
  1264. }
  1265. UnlockLogon();
  1266. DBG_ASSERT( fLsaInitialized == TRUE );
  1267. }
  1268. //
  1269. // Set logon origin
  1270. //
  1271. RtlInitString(&OriginName, "IIS security API");
  1272. //
  1273. // Determine the size of the logon buffer
  1274. //
  1275. cchUserName = wcslen( pszUserName );
  1276. cchDomainName = wcslen( pszDomainName );
  1277. cbLogonInfo = sizeof( KERB_S4U_LOGON );
  1278. cbLogonInfo += ( cchUserName + 1 ) * sizeof( WCHAR );
  1279. cbLogonInfo += ( cchDomainName + 1 ) * sizeof( WCHAR );
  1280. bRet = buffLogonInfo.Resize( cbLogonInfo );
  1281. if ( !bRet )
  1282. {
  1283. return FALSE;
  1284. }
  1285. pLogonInfo = (KERB_S4U_LOGON*) buffLogonInfo.QueryPtr();
  1286. //
  1287. // Setup the logon buffer
  1288. //
  1289. pLogonInfo->MessageType = KerbS4ULogon;
  1290. pLogonInfo->Flags = 0;
  1291. memcpy( pLogonInfo + 1,
  1292. pszUserName,
  1293. ( cchUserName + 1 ) * sizeof( WCHAR ) );
  1294. memcpy( (PBYTE)( pLogonInfo + 1 ) + ( cchUserName + 1 ) * sizeof( WCHAR ),
  1295. pszDomainName,
  1296. ( cchDomainName + 1 ) );
  1297. pLogonInfo->ClientUpn.Length = (USHORT) cchUserName * sizeof( WCHAR );
  1298. pLogonInfo->ClientUpn.MaximumLength = (USHORT) cchUserName * sizeof( WCHAR );
  1299. pLogonInfo->ClientUpn.Buffer = (WCHAR*) (pLogonInfo + 1);
  1300. pLogonInfo->ClientRealm.Length = (USHORT) cchDomainName * sizeof( WCHAR );
  1301. pLogonInfo->ClientRealm.MaximumLength = (USHORT) cchDomainName * sizeof( WCHAR );
  1302. pLogonInfo->ClientRealm.Buffer = (WCHAR*) ((PBYTE)(pLogonInfo+1) + (cchUserName + 1)*sizeof(WCHAR));
  1303. //
  1304. // Do the logon
  1305. //
  1306. Status = LsaLogonUser( Logon32LsaHandle,
  1307. &OriginName,
  1308. Network,
  1309. Logon32KerberosHandle,
  1310. pLogonInfo,
  1311. cbLogonInfo,
  1312. NULL,
  1313. &SourceContext,
  1314. (PVOID*) &pProfile,
  1315. &cbProfile,
  1316. &LogonId,
  1317. &hToken,
  1318. &Quotas,
  1319. &SubStatus );
  1320. if ( !NT_SUCCESS( Status ) )
  1321. {
  1322. SetLastError( Status );
  1323. return FALSE;
  1324. }
  1325. DBG_ASSERT( hToken != NULL );
  1326. *phToken = hToken;
  1327. return TRUE;
  1328. }
  1329. /*******************************************************************
  1330. NAME: GetDefaultDomainName
  1331. SYNOPSIS: Fills in the given array with the name of the default
  1332. domain to use for logon validation.
  1333. ENTRY: pszDomainName - Pointer to a buffer that will receive
  1334. the default domain name.
  1335. cchDomainName - The size (in charactesr) of the domain
  1336. name buffer.
  1337. RETURNS: TRUE if successful, FALSE if not.
  1338. HISTORY:
  1339. KeithMo 05-Dec-1994 Created.
  1340. ********************************************************************/
  1341. BOOL
  1342. IISGetDefaultDomainName(
  1343. CHAR * pszDomainName,
  1344. DWORD cchDomainName
  1345. )
  1346. {
  1347. OBJECT_ATTRIBUTES ObjectAttributes;
  1348. NTSTATUS NtStatus;
  1349. INT Result;
  1350. DWORD err = 0;
  1351. LSA_HANDLE LsaPolicyHandle = NULL;
  1352. PPOLICY_ACCOUNT_DOMAIN_INFO DomainInfo = NULL;
  1353. //
  1354. // Open a handle to the local machine's LSA policy object.
  1355. //
  1356. InitializeObjectAttributes( &ObjectAttributes, // object attributes
  1357. NULL, // name
  1358. 0L, // attributes
  1359. NULL, // root directory
  1360. NULL ); // security descriptor
  1361. NtStatus = LsaOpenPolicy( NULL, // system name
  1362. &ObjectAttributes, // object attributes
  1363. POLICY_EXECUTE, // access mask
  1364. &LsaPolicyHandle ); // policy handle
  1365. if( !NT_SUCCESS( NtStatus ) )
  1366. {
  1367. DBGPRINTF(( DBG_CONTEXT,
  1368. "cannot open lsa policy, error %08lX\n",
  1369. NtStatus ));
  1370. err = LsaNtStatusToWinError( NtStatus );
  1371. // Failure LsaOpenPolicy() does not guarantee that
  1372. // LsaPolicyHandle was not touched.
  1373. LsaPolicyHandle = NULL;
  1374. goto Cleanup;
  1375. }
  1376. //
  1377. // Query the domain information from the policy object.
  1378. //
  1379. NtStatus = LsaQueryInformationPolicy( LsaPolicyHandle,
  1380. PolicyAccountDomainInformation,
  1381. (PVOID *)&DomainInfo );
  1382. if( !NT_SUCCESS( NtStatus ) )
  1383. {
  1384. DBGPRINTF(( DBG_CONTEXT,
  1385. "cannot query lsa policy info, error %08lX\n",
  1386. NtStatus ));
  1387. err = LsaNtStatusToWinError( NtStatus );
  1388. goto Cleanup;
  1389. }
  1390. //
  1391. // Convert the name from UNICODE to ANSI.
  1392. //
  1393. Result = WideCharToMultiByte( CP_ACP,
  1394. 0, // flags
  1395. (LPCWSTR)DomainInfo->DomainName.Buffer,
  1396. DomainInfo->DomainName.Length / sizeof(WCHAR),
  1397. pszDomainName,
  1398. cchDomainName - 1, // save room for '\0'
  1399. NULL,
  1400. NULL );
  1401. if( Result <= 0 )
  1402. {
  1403. err = GetLastError();
  1404. DBGPRINTF(( DBG_CONTEXT,
  1405. "cannot convert domain name to ANSI, error %d\n",
  1406. err ));
  1407. goto Cleanup;
  1408. }
  1409. //
  1410. // Ensure the ANSI string is zero terminated.
  1411. //
  1412. DBG_ASSERT( (DWORD)Result < cchDomainName );
  1413. pszDomainName[Result] = '\0';
  1414. //
  1415. // Success!
  1416. //
  1417. DBG_ASSERT( err == 0 );
  1418. Cleanup:
  1419. if( DomainInfo != NULL )
  1420. {
  1421. LsaFreeMemory( (PVOID)DomainInfo );
  1422. }
  1423. if( LsaPolicyHandle != NULL )
  1424. {
  1425. LsaClose( LsaPolicyHandle );
  1426. }
  1427. if ( err )
  1428. {
  1429. SetLastError( err );
  1430. return FALSE;
  1431. }
  1432. return TRUE;
  1433. } // IISGetDefaultDomainName