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.

733 lines
17 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. lsa.c
  5. Abstract:
  6. Implements security network logon
  7. Author:
  8. Ahmed Mohamed (ahmedm) 1-Feb-2000
  9. Revision History:
  10. --*/
  11. #include <nt.h>
  12. #include <ntdef.h>
  13. #include <ntrtl.h>
  14. #include <nturtl.h>
  15. #include <ntlsa.h>
  16. #include <ntmsv1_0.h>
  17. #include <windows.h>
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <stdarg.h>
  21. #include <string.h>
  22. #include <fcntl.h>
  23. #include <io.h>
  24. //int lstrlenW(char *);
  25. typedef int BOOL;
  26. typedef unsigned int UINT;
  27. typedef unsigned int *PUINT;
  28. typedef unsigned char *LPBYTE;
  29. #define LocalLSAInit() (LsaHandle != NULL)
  30. #ifdef LSA_AUDIT_FLAG
  31. int LsaAuditFlag = 0;
  32. #endif
  33. #define BUF_SIZ 512
  34. void
  35. replstar(
  36. IN char * starred,
  37. OUT LPWSTR UnicodeOut
  38. )
  39. /*++ replstar
  40. Routine Description:
  41. replaces the '*' in the string with either spaces or NULL
  42. if it's the only memeber of the string. Used by parse().
  43. Converts the resultant string to unicode.
  44. Arguments:
  45. char * starred -
  46. Return Value:
  47. void -
  48. Warnings:
  49. --*/
  50. {
  51. char *cp;
  52. STRING AnsiString;
  53. UNICODE_STRING UnicodeString;
  54. if ( !strcmp(starred,"*") ) {
  55. *starred = '\0';
  56. } else {
  57. for ( cp = starred; *cp; ++cp )
  58. if (*cp == '*')
  59. *cp = ' ';
  60. }
  61. //
  62. // Convert the result to unicode
  63. //
  64. AnsiString.Buffer = starred;
  65. AnsiString.Length = AnsiString.MaximumLength =
  66. (USHORT) strlen( starred );
  67. UnicodeString.Buffer = UnicodeOut;
  68. UnicodeString.Length = 0;
  69. UnicodeString.MaximumLength = BUF_SIZ * sizeof(WCHAR);
  70. (VOID) RtlAnsiStringToUnicodeString( &UnicodeString, &AnsiString, FALSE );
  71. return;
  72. }
  73. VOID
  74. NlpPutString(
  75. IN PUNICODE_STRING OutString,
  76. IN PUNICODE_STRING InString,
  77. IN PUCHAR *Where
  78. )
  79. /*++ NlpPutString
  80. Routine Description:
  81. This routine copies the InString string to the memory pointed to by
  82. the Where parameter, and fixes the OutString string to point to that
  83. new copy.
  84. Parameters:
  85. OutString - A pointer to a destination NT string
  86. InString - A pointer to an NT string to be copied
  87. Where - A pointer to space to put the actual string for the
  88. OutString. The pointer is adjusted to point to the first byte
  89. following the copied string.
  90. Return Values:
  91. None.
  92. --*/
  93. {
  94. ASSERT( OutString != NULL );
  95. ASSERT( InString != NULL );
  96. ASSERT( Where != NULL && *Where != NULL);
  97. if ( InString->Length > 0 )
  98. {
  99. OutString->Buffer = (PWCH) *Where;
  100. OutString->MaximumLength = InString->Length;
  101. *Where += OutString->MaximumLength;
  102. RtlCopyString( (PSTRING) OutString, (PSTRING) InString );
  103. }
  104. else
  105. {
  106. RtlInitUnicodeString(OutString, NULL);
  107. }
  108. return;
  109. }
  110. BOOL
  111. LsapLogonNetwork(
  112. IN HANDLE LsaHandle,
  113. IN ULONG AuthenticationPackage,
  114. IN LPWSTR Username,
  115. IN PUCHAR ChallengeToClient,
  116. IN PMSV1_0_GETCHALLENRESP_RESPONSE ChallengeResponse,
  117. IN UINT cbChallengeResponse,
  118. IN LPWSTR Domain,
  119. OUT PLUID LogonId,
  120. OUT PHANDLE TokenHandle
  121. )
  122. /*++ LogonNetwork
  123. Routine Description:
  124. Logs a user onto the network
  125. Arguments:
  126. IN LPWSTR Username - self explanatory
  127. IN ChallengeToClient - The challenge sent to the client
  128. IN ChallengeResponse - The response sent from the client
  129. IN LPWSTR Domain - Logon Domain Name
  130. OUT PLUID LogonId - Unique generated logon id
  131. OUT PHANDLE TokenHandle - handle to the logon token
  132. Return Value:
  133. BOOL -
  134. Warnings:
  135. --*/
  136. {
  137. NTSTATUS Status;
  138. UNICODE_STRING TempString;
  139. UNICODE_STRING TempString2;
  140. UNICODE_STRING OriginName;
  141. PMSV1_0_LM20_LOGON Auth;
  142. PCHAR Auth1[MSV1_0_CHALLENGE_LENGTH + BUF_SIZ*2];
  143. PUCHAR Strings;
  144. PMSV1_0_LM20_LOGON_PROFILE ProfileBuffer;
  145. ULONG ProfileBufferSize;
  146. NTSTATUS SubStatus;
  147. TOKEN_SOURCE SourceContext;
  148. QUOTA_LIMITS QuotaLimits;
  149. /*
  150. * Fill in the Authentication structure.
  151. */
  152. Auth = (PMSV1_0_LM20_LOGON) Auth1;
  153. Strings = (PUCHAR)(Auth + 1);
  154. Auth->MessageType = MsV1_0Lm20Logon;
  155. RtlMoveMemory( Auth->ChallengeToClient,
  156. ChallengeToClient,
  157. MSV1_0_CHALLENGE_LENGTH );
  158. /* Init Strings
  159. * username
  160. */
  161. RtlInitUnicodeString( &TempString, Username );
  162. NlpPutString( &Auth->UserName, &TempString, &Strings );
  163. /*
  164. * workstation name
  165. */
  166. RtlInitUnicodeString( &TempString, L"NetQFS" );
  167. NlpPutString( &Auth->Workstation, &TempString, &Strings );
  168. /*
  169. * Challenge Response
  170. */
  171. Auth->CaseSensitiveChallengeResponse.Length = 0;
  172. Auth->CaseSensitiveChallengeResponse.MaximumLength = 0;
  173. Auth->CaseSensitiveChallengeResponse.Buffer = NULL;
  174. #ifdef OLD
  175. RtlInitUnicodeString(
  176. (PUNICODE_STRING)&TempString2,
  177. (PCWSTR)ChallengeResponse );
  178. #else
  179. TempString2.Buffer = (PWSTR)ChallengeResponse;
  180. TempString2.Length = (USHORT)cbChallengeResponse;
  181. TempString2.MaximumLength = TempString2.Length;
  182. #endif
  183. if( TempString2.Length > 24 ) {
  184. TempString2.Length = 24;
  185. }
  186. NlpPutString(
  187. (PUNICODE_STRING)&Auth->CaseInsensitiveChallengeResponse,
  188. (PUNICODE_STRING)&TempString2,
  189. &Strings );
  190. /*
  191. * domain
  192. */
  193. RtlInitUnicodeString( &TempString, Domain );
  194. NlpPutString( &Auth->LogonDomainName, &TempString, &Strings );
  195. RtlInitUnicodeString( &OriginName, L"NetQFS" );
  196. Status = LsaLogonUser(
  197. LsaHandle,
  198. (PSTRING)&OriginName,
  199. Network,
  200. AuthenticationPackage,
  201. // LATER? AuthenticationPackage | LSA_CALL_LICENSE_SERVER,
  202. Auth,
  203. (ULONG)(Strings - (PUCHAR)Auth),
  204. NULL,
  205. &SourceContext,
  206. (PVOID *)&ProfileBuffer,
  207. &ProfileBufferSize,
  208. LogonId,
  209. TokenHandle,
  210. &QuotaLimits,
  211. &SubStatus );
  212. if ( !NT_SUCCESS( Status ) )
  213. {
  214. extern void WINAPI debug_log(char *,...);
  215. debug_log("Logon failed %x\n",Status);
  216. // LSA Can't be trusted to not scrog our variables
  217. *TokenHandle = NULL;
  218. return( FALSE );
  219. }
  220. LsaFreeReturnBuffer( ProfileBuffer );
  221. return( TRUE );
  222. }
  223. BOOL
  224. LsapChallenge(
  225. HANDLE LsaHandle,
  226. ULONG AuthenticationPackage,
  227. UCHAR *ChallengeToClient
  228. )
  229. /*++ Challenge
  230. Routine Description:
  231. get a challenge
  232. Arguments:
  233. OUT ChallengeToClient - Returns the challenge to send to the client
  234. Return Value:
  235. NTSTATUS -
  236. Warnings:
  237. --*/
  238. {
  239. NTSTATUS Status;
  240. NTSTATUS ProtocolStatus;
  241. ULONG ResponseSize;
  242. MSV1_0_LM20_CHALLENGE_REQUEST Request;
  243. PMSV1_0_LM20_CHALLENGE_RESPONSE Response;
  244. /*
  245. * Fill in the Authentication structure.
  246. */
  247. Request.MessageType = MsV1_0Lm20ChallengeRequest;
  248. Status = LsaCallAuthenticationPackage (
  249. LsaHandle,
  250. AuthenticationPackage,
  251. &Request,
  252. sizeof(Request),
  253. (PVOID *)&Response,
  254. &ResponseSize,
  255. &ProtocolStatus );
  256. if ( !NT_SUCCESS( Status ) || !NT_SUCCESS( ProtocolStatus) )
  257. {
  258. printf("ChallengeRequest failed %x\n",Status);
  259. return( FALSE );
  260. }
  261. RtlMoveMemory( ChallengeToClient,
  262. Response->ChallengeToClient,
  263. MSV1_0_CHALLENGE_LENGTH );
  264. LsaFreeReturnBuffer( Response );
  265. return( TRUE );
  266. }
  267. BOOL
  268. LsaGetChallenge(
  269. HANDLE LsaHandle,
  270. ULONG AuthenticationPackage,
  271. LPBYTE lpChallenge,
  272. UINT cbSize,
  273. PUINT lpcbChallengeSize
  274. )
  275. {
  276. #ifdef LSA_AUDIT_FLAG
  277. if (LsaAuditFlag == TRUE) {
  278. memset(lpChallenge, 0, MSV1_0_CHALLENGE_LENGTH);
  279. *lpcbChallengeSize = MSV1_0_CHALLENGE_LENGTH;
  280. return TRUE;
  281. }
  282. #endif
  283. if( LocalLSAInit() ) {
  284. *lpcbChallengeSize = MSV1_0_CHALLENGE_LENGTH;
  285. return LsapChallenge( LsaHandle, AuthenticationPackage, lpChallenge );
  286. } else {
  287. return( FALSE );
  288. }
  289. }
  290. BOOL
  291. LsaValidateLogon(
  292. HANDLE LsaHandle,
  293. ULONG AuthenticationPackage,
  294. LPBYTE lpChallenge,
  295. UINT cbChallengeSize,
  296. LPBYTE lpResponse,
  297. UINT cbResponseSize,
  298. LPSTR lpszUserName,
  299. LPSTR lpszDomainName,
  300. LUID *pLogonId,
  301. PHANDLE phLogonToken
  302. )
  303. {
  304. WCHAR wcUser[ BUF_SIZ ];
  305. WCHAR wcDomain[ BUF_SIZ ];
  306. BOOL nlRet;
  307. DWORD sz = BUF_SIZ;
  308. #ifdef LSA_AUDIT_FLAG
  309. if (LsaAuditFlag == 1) {
  310. pLogonId->LowPart = 10;
  311. pLogonId->HighPart = 0;
  312. *phLogonToken = INVALID_HANDLE_VALUE;
  313. return TRUE;
  314. }
  315. #endif
  316. if (GetUserName((LPSTR)wcUser, &sz)) {
  317. if (lpszUserName != NULL && *lpszUserName != '\0' &&
  318. _stricmp(lpszUserName, (LPSTR)wcUser) &&
  319. _stricmp(lpszUserName, "administrator")) {
  320. return FALSE;
  321. }
  322. }
  323. if( !LocalLSAInit() ) {
  324. return( FALSE );
  325. }
  326. replstar( lpszUserName, wcUser );
  327. replstar( lpszDomainName, wcDomain );
  328. nlRet = LsapLogonNetwork( LsaHandle, AuthenticationPackage,
  329. wcUser, lpChallenge,
  330. (PMSV1_0_GETCHALLENRESP_RESPONSE)lpResponse,
  331. cbResponseSize, wcDomain, pLogonId, phLogonToken );
  332. return( nlRet );
  333. }
  334. BOOL
  335. LsaGetChallengeResponse(
  336. HANDLE LsaHandle,
  337. ULONG AuthenticationPackage,
  338. LUID LogonId,
  339. LPSTR lpszPasswordK1,
  340. int cbPasswordK1,
  341. LPSTR lpszChallenge,
  342. int cbChallenge,
  343. int *pcbPasswordK1,
  344. BOOL *pbHasPasswordK1 )
  345. {
  346. NTSTATUS Status;
  347. NTSTATUS ProtocolStatus;
  348. ULONG ResponseSize;
  349. PMSV1_0_GETCHALLENRESP_RESPONSE Response;
  350. PMSV1_0_GETCHALLENRESP_REQUEST Request;
  351. PCHAR Auth1[BUF_SIZ];
  352. PUCHAR Strings;
  353. if( !LocalLSAInit() ) {
  354. *pbHasPasswordK1 = FALSE;
  355. return( FALSE );
  356. }
  357. Request = (PMSV1_0_GETCHALLENRESP_REQUEST) Auth1;
  358. Request->MessageType = MsV1_0Lm20GetChallengeResponse;
  359. Request->ParameterControl = 0;
  360. Request->ParameterControl |= USE_PRIMARY_PASSWORD;
  361. Request->LogonId = LogonId;
  362. Strings = (PUCHAR)(Request + 1);
  363. RtlMoveMemory( Request->ChallengeToClient,
  364. lpszChallenge,
  365. cbChallenge );
  366. RtlInitUnicodeString( &Request->Password, NULL );
  367. Status = LsaCallAuthenticationPackage (
  368. LsaHandle,
  369. AuthenticationPackage,
  370. Request,
  371. sizeof(MSV1_0_GETCHALLENRESP_REQUEST),
  372. (PVOID *)&Response,
  373. &ResponseSize,
  374. &ProtocolStatus );
  375. if ( !NT_SUCCESS( Status ) || !NT_SUCCESS( ProtocolStatus) )
  376. {
  377. return( FALSE );
  378. }
  379. *pcbPasswordK1 = (Response)->CaseInsensitiveChallengeResponse.Length;
  380. memcpy( lpszPasswordK1,
  381. (Response)->CaseInsensitiveChallengeResponse.Buffer,
  382. (Response)->CaseInsensitiveChallengeResponse.Length );
  383. *pbHasPasswordK1 = TRUE;
  384. LsaFreeReturnBuffer( Response );
  385. return( TRUE );
  386. }
  387. #ifdef QON_TCB_REQUIRED
  388. // When we have support for untrusted on REQUEST we disable this. Till then we need TCB.
  389. // I am disabling this since the we don't need TCB anymore. Note if we
  390. // want to run in win2k then we must have TCB and this code path reenabled.
  391. NTSTATUS
  392. LsaInit(HANDLE *pLsaHandle, ULONG *pAuthenticationPackage)
  393. {
  394. char MyName[MAX_PATH];
  395. char * ModuleName;
  396. STRING LogonProcessName;
  397. STRING PackageName;
  398. ULONG dummy;
  399. NTSTATUS Status;
  400. NTSTATUS TempStatus;
  401. BOOLEAN WasEnabled;
  402. HANDLE LsaHandle = NULL;
  403. ULONG AuthenticationPackage;
  404. BOOLEAN fThread = FALSE; // did we enable privilege in thread token?
  405. BOOL fReverted = FALSE; // did we RevertToSelf() during call?
  406. HANDLE hPreviousToken = NULL;
  407. #ifdef LSA_AUDIT_FLAG
  408. if (LsaAuditFlag == TRUE) {
  409. *pLsaHandle = 0;
  410. *pAuthenticationPackage = 0;
  411. return STATUS_SUCCESS;
  412. }
  413. #endif
  414. //
  415. // three SeTcbPrivilege scenarios:
  416. // 1. present in process token, thread not impersonating.
  417. // 2. present in process token, thread is impersonating.
  418. // 3. present in thread token.
  419. //
  420. //
  421. // try in this order:
  422. // process token (original method).
  423. // if thread impersonating, thread token
  424. // if thread impersonating, process token after reverting.
  425. //
  426. Status = RtlAdjustPrivilege(SE_TCB_PRIVILEGE, TRUE, FALSE, &WasEnabled);
  427. if (!NT_SUCCESS(Status))
  428. {
  429. TempStatus = NtOpenThreadToken(
  430. NtCurrentThread(),
  431. TOKEN_IMPERSONATE,
  432. FALSE,
  433. &hPreviousToken
  434. );
  435. if( !NT_SUCCESS(TempStatus) ) {
  436. //
  437. // retry with accesscheck against process.
  438. //
  439. if( TempStatus != STATUS_ACCESS_DENIED )
  440. goto Cleanup;
  441. TempStatus = NtOpenThreadToken(
  442. NtCurrentThread(),
  443. TOKEN_IMPERSONATE,
  444. TRUE,
  445. &hPreviousToken
  446. );
  447. if( !NT_SUCCESS(TempStatus) )
  448. goto Cleanup;
  449. }
  450. //
  451. // thread token is present.
  452. // first, try enabling the privilege in the thread token.
  453. //
  454. fThread = TRUE;
  455. Status = RtlAdjustPrivilege(SE_TCB_PRIVILEGE, TRUE, fThread, &WasEnabled);
  456. if( !NT_SUCCESS(Status) ) {
  457. HANDLE NewToken = NULL;
  458. //
  459. // if that fails, try reverting and enabling privilege in process token.
  460. //
  461. TempStatus = NtSetInformationThread(
  462. NtCurrentThread(),
  463. ThreadImpersonationToken,
  464. &NewToken,
  465. sizeof(NewToken)
  466. );
  467. if( !NT_SUCCESS(TempStatus) )
  468. goto Cleanup;
  469. fThread = FALSE;
  470. fReverted = TRUE;
  471. Status = RtlAdjustPrivilege(SE_TCB_PRIVILEGE, TRUE, fThread, &WasEnabled);
  472. if( !NT_SUCCESS(Status) )
  473. goto Cleanup;
  474. }
  475. }
  476. GetModuleFileNameA(NULL, MyName, MAX_PATH);
  477. ModuleName = strrchr(MyName, '\\');
  478. if (!ModuleName)
  479. {
  480. ModuleName = MyName;
  481. }
  482. //
  483. // Hookup to the LSA and locate our authentication package.
  484. //
  485. RtlInitString(&LogonProcessName, ModuleName);
  486. Status = LsaRegisterLogonProcess(
  487. &LogonProcessName,
  488. &LsaHandle,
  489. &dummy
  490. );
  491. //
  492. // Turn off the privilege now.
  493. //
  494. if( !WasEnabled ) {
  495. (VOID) RtlAdjustPrivilege(SE_TCB_PRIVILEGE, FALSE, fThread, &WasEnabled);
  496. }
  497. if (!NT_SUCCESS(Status)) {
  498. LsaHandle = NULL;
  499. goto Cleanup;
  500. }
  501. //
  502. // Connect with the MSV1_0 authentication package
  503. //
  504. RtlInitString(&PackageName, MSV1_0_PACKAGE_NAME); //"MICROSOFT_AUTHENTICATION_PACKAGE_V1_0");
  505. Status = LsaLookupAuthenticationPackage (
  506. LsaHandle,
  507. &PackageName,
  508. &AuthenticationPackage
  509. );
  510. if (!NT_SUCCESS(Status)) {
  511. goto Cleanup;
  512. }
  513. *pLsaHandle = LsaHandle;
  514. *pAuthenticationPackage = AuthenticationPackage;
  515. Cleanup:
  516. if( hPreviousToken ) {
  517. if( fReverted ) {
  518. //
  519. // put old token back...
  520. //
  521. (VOID) NtSetInformationThread(
  522. NtCurrentThread(),
  523. ThreadImpersonationToken,
  524. &hPreviousToken,
  525. sizeof(hPreviousToken)
  526. );
  527. }
  528. NtClose( hPreviousToken );
  529. }
  530. if( !NT_SUCCESS(Status) ) {
  531. if( LsaHandle ) {
  532. (VOID) LsaDeregisterLogonProcess( LsaHandle );
  533. LsaHandle = NULL;
  534. }
  535. }
  536. return Status;
  537. }
  538. #else
  539. NTSTATUS
  540. LsaInit(HANDLE *pLsaHandle, ULONG *pAuthenticationPackage)
  541. {
  542. char MyName[MAX_PATH];
  543. char * ModuleName;
  544. STRING LogonProcessName;
  545. STRING PackageName;
  546. ULONG dummy;
  547. NTSTATUS Status;
  548. NTSTATUS TempStatus;
  549. BOOLEAN WasEnabled;
  550. HANDLE LsaHandle;
  551. ULONG AuthenticationPackage;
  552. BOOLEAN fThread = FALSE; // did we enable privilege in thread token?
  553. BOOL fReverted = FALSE; // did we RevertToSelf() during call?
  554. HANDLE hPreviousToken = NULL;
  555. //
  556. // Connect with LSA process
  557. //
  558. Status = LsaConnectUntrusted(&LsaHandle);
  559. if (!NT_SUCCESS(Status))
  560. return Status;
  561. //
  562. // Connect with the MSV1_0 authentication package
  563. //
  564. RtlInitString(&PackageName, MSV1_0_PACKAGE_NAME); //"MICROSOFT_AUTHENTICATION_PACKAGE_V1_0");
  565. Status = LsaLookupAuthenticationPackage (
  566. LsaHandle,
  567. &PackageName,
  568. &AuthenticationPackage
  569. );
  570. if (NT_SUCCESS(Status)) {
  571. *pLsaHandle = LsaHandle;
  572. *pAuthenticationPackage = AuthenticationPackage;
  573. } else {
  574. (VOID) LsaDeregisterLogonProcess( LsaHandle );
  575. }
  576. return Status;
  577. }
  578. #endif