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.

2934 lines
89 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. smbadmin.c
  5. Abstract:
  6. This module contains routines for processing the administrative SMBs:
  7. negotiate, session setup, tree connect, and logoff.
  8. Author:
  9. David Treadwell (davidtr) 30-Oct-1989
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #include "smbadmin.tmh"
  14. #pragma hdrstop
  15. #define ENCRYPT_TEXT_LENGTH 20
  16. VOID
  17. GetEncryptionKey (
  18. OUT CHAR EncryptionKey[MSV1_0_CHALLENGE_LENGTH]
  19. );
  20. VOID SRVFASTCALL
  21. BlockingSessionSetupAndX (
  22. IN OUT PWORK_CONTEXT WorkContext
  23. );
  24. NTSTATUS
  25. GetNtSecurityParameters(
  26. IN PWORK_CONTEXT WorkContext,
  27. OUT PCHAR *CasesensitivePassword,
  28. OUT PULONG CasesensitivePasswordLength,
  29. OUT PCHAR *CaseInsensitivePassword,
  30. OUT PULONG CaseInsensitivePasswordLength,
  31. OUT PUNICODE_STRING UserName,
  32. OUT PUNICODE_STRING DomainName,
  33. OUT PCHAR *RestOfDataBuffer,
  34. OUT PULONG RestOfDataLength );
  35. VOID
  36. BuildSessionSetupAndXResponse(
  37. IN PWORK_CONTEXT WorkContext,
  38. IN UCHAR NextCommand,
  39. IN USHORT Action,
  40. IN BOOLEAN IsUnicode);
  41. NTSTATUS
  42. GetExtendedSecurityParameters(
  43. IN PWORK_CONTEXT WorkContext,
  44. OUT PUCHAR *SecurityBuffer,
  45. OUT PULONG SecurityBufferLength,
  46. OUT PCHAR *RestOfDataBuffer,
  47. OUT PULONG RestOfDataLength );
  48. VOID
  49. BuildExtendedSessionSetupAndXResponse(
  50. IN PWORK_CONTEXT WorkContext,
  51. IN ULONG SecurityBlobLength,
  52. IN NTSTATUS Status,
  53. IN UCHAR NextCommand,
  54. IN BOOLEAN IsUnicode);
  55. VOID
  56. InsertNativeOSAndType(
  57. IN BOOLEAN IsUnicode,
  58. OUT PCHAR Buffer,
  59. OUT PUSHORT ByteCount);
  60. //
  61. // EncryptionKeyCount is a monotonically increasing count of the number
  62. // of times GetEncryptionKey has been called. This number is added to
  63. // the system time to ensure that we do not use the same seed twice in
  64. // generating a random challenge.
  65. //
  66. STATIC
  67. ULONG EncryptionKeyCount = 0;
  68. ULONG SrvKsecValidErrors = 0;
  69. #ifdef ALLOC_PRAGMA
  70. #pragma alloc_text( PAGE, SrvSmbNegotiate )
  71. #pragma alloc_text( PAGE, SrvSmbProcessExit )
  72. #pragma alloc_text( PAGE, SrvSmbSessionSetupAndX )
  73. #pragma alloc_text( PAGE, BlockingSessionSetupAndX )
  74. #pragma alloc_text( PAGE, SrvSmbLogoffAndX )
  75. #pragma alloc_text( PAGE, GetEncryptionKey )
  76. #pragma alloc_text( PAGE, GetNtSecurityParameters )
  77. #pragma alloc_text( PAGE, BuildSessionSetupAndXResponse )
  78. #pragma alloc_text( PAGE, GetExtendedSecurityParameters )
  79. #pragma alloc_text( PAGE, BuildExtendedSessionSetupAndXResponse )
  80. #pragma alloc_text( PAGE, InsertNativeOSAndType )
  81. #endif
  82. SMB_PROCESSOR_RETURN_TYPE
  83. SrvSmbNegotiate (
  84. SMB_PROCESSOR_PARAMETERS
  85. )
  86. /*++
  87. Routine Description:
  88. Processes a negotiate SMB.
  89. Arguments:
  90. SMB_PROCESSOR_PARAMETERS - See smbprocs.h for a description
  91. of the parameters to SMB processor routines.
  92. Return Value:
  93. SMB_PROCESSOR_RETURN_TYPE - See smbprocs.h
  94. --*/
  95. {
  96. PREQ_NEGOTIATE request;
  97. PRESP_NT_NEGOTIATE ntResponse;
  98. PRESP_NEGOTIATE response;
  99. PRESP_OLD_NEGOTIATE respOldNegotiate;
  100. PCONNECTION connection;
  101. PENDPOINT endpoint;
  102. PPAGED_CONNECTION pagedConnection;
  103. USHORT byteCount;
  104. USHORT flags2;
  105. PSMB_HEADER smbHeader;
  106. PSZ s, es;
  107. SMB_DIALECT bestDialect, serverDialect, firstDialect;
  108. USHORT consumerDialectChosen, consumerDialect;
  109. LARGE_INTEGER serverTime;
  110. SMB_DATE date;
  111. SMB_TIME time;
  112. ULONG capabilities;
  113. NTSTATUS status = STATUS_SUCCESS;
  114. SMB_STATUS SmbStatus = SmbStatusInProgress;
  115. PAGED_CODE( );
  116. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  117. WorkContext->PreviousSMB = EVENT_TYPE_SMB_NEGOTIATE;
  118. SrvWmiStartContext(WorkContext);
  119. IF_SMB_DEBUG(ADMIN1) {
  120. SrvPrint2( "Negotiate request header at 0x%p, response header at 0x%p\n",
  121. WorkContext->RequestHeader, WorkContext->ResponseHeader );
  122. SrvPrint2( "Negotiate request parameters at 0x%p, response parameters at 0x%p\n",
  123. WorkContext->RequestParameters,
  124. WorkContext->ResponseParameters );
  125. }
  126. //
  127. // Set up input and output buffers for parameters.
  128. //
  129. request = (PREQ_NEGOTIATE)WorkContext->RequestParameters;
  130. response = (PRESP_NEGOTIATE)WorkContext->ResponseParameters;
  131. ntResponse = (PRESP_NT_NEGOTIATE)WorkContext->ResponseParameters;
  132. smbHeader = WorkContext->RequestHeader;
  133. //
  134. // Make sure that this is the first negotiate command sent.
  135. // SrvStartListen() sets the dialect to illegal, so if it has changed
  136. // then a negotiate SMB has already been sent.
  137. //
  138. connection = WorkContext->Connection;
  139. pagedConnection = connection->PagedConnection;
  140. endpoint = connection->Endpoint;
  141. if ( connection->SmbDialect != SmbDialectIllegal ) {
  142. IF_DEBUG(SMB_ERRORS) {
  143. SrvPrint0( "SrvSmbNegotiate: Command already sent.\n" );
  144. }
  145. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  146. status = STATUS_INVALID_SMB;
  147. SmbStatus = SmbStatusSendResponse;
  148. goto Cleanup;
  149. }
  150. //
  151. // We don't know anything about the version number of this client yet.
  152. //
  153. pagedConnection->ClientBuildNumber = 0;
  154. #if SRVNTVERCHK
  155. pagedConnection->ClientTooOld = FALSE;
  156. #endif
  157. //
  158. // Find out which (if any) of the sent dialect strings matches the
  159. // dialect strings known by this server. The ByteCount is verified
  160. // to be legitimate in SrvProcessSmb, so it is not possible to walk
  161. // off the end of the SMB here.
  162. //
  163. bestDialect = SmbDialectIllegal;
  164. consumerDialectChosen = (USHORT)0xFFFF;
  165. es = END_OF_REQUEST_SMB( WorkContext );
  166. if( endpoint->IsPrimaryName ) {
  167. firstDialect = FIRST_DIALECT;
  168. } else {
  169. firstDialect = FIRST_DIALECT_EMULATED;
  170. }
  171. for ( s = (PSZ)request->Buffer, consumerDialect = 0;
  172. s <= es && s < SmbGetUshort( &request->ByteCount ) + (PSZ)request->Buffer;
  173. consumerDialect++ ) {
  174. if ( *s++ != SMB_FORMAT_DIALECT ) {
  175. IF_DEBUG(SMB_ERRORS) {
  176. SrvPrint0( "SrvSmbNegotiate: Invalid dialect format code.\n" );
  177. }
  178. SrvLogInvalidSmb( WorkContext );
  179. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  180. status = STATUS_INVALID_SMB;
  181. SmbStatus = SmbStatusSendResponse;
  182. goto Cleanup;
  183. }
  184. for ( serverDialect = firstDialect;
  185. serverDialect < bestDialect;
  186. serverDialect++ ) {
  187. if ( !strcmp( s, StrDialects[serverDialect] ) ) {
  188. IF_SMB_DEBUG(ADMIN2) {
  189. SrvPrint2( "Matched: %s and %s\n",
  190. StrDialects[serverDialect], s );
  191. }
  192. bestDialect = serverDialect;
  193. consumerDialectChosen = consumerDialect;
  194. }
  195. }
  196. //
  197. // Go to the next dialect string
  198. //
  199. for( ; *s && s < es; s++ )
  200. ;
  201. //
  202. // We are now at the end of the buffer, or are pointing to the NULL.
  203. // Advance the pointer. If we are at the end of the buffer, the test in
  204. // the loop will terminate.
  205. //
  206. s++;
  207. }
  208. connection->SmbDialect = bestDialect;
  209. if( bestDialect <= SmbDialectNtLanMan ) {
  210. connection->IpxDropDuplicateCount = MIN_IPXDROPDUP;
  211. } else {
  212. connection->IpxDropDuplicateCount = MAX_IPXDROPDUP;
  213. }
  214. IF_SMB_DEBUG(ADMIN1) {
  215. SrvPrint2( "Choosing dialect #%ld, string = %s\n",
  216. consumerDialectChosen, StrDialects[bestDialect] );
  217. }
  218. //
  219. // Determine the current system time on the server. We use this
  220. // to determine the time zone of the server and to tell the client
  221. // the current time of day on the server.
  222. //
  223. KeQuerySystemTime( &serverTime );
  224. //
  225. // If the consumer only knows the core protocol, return short (old)
  226. // form of the negotiate response. Also, if no dialect is acceptable,
  227. // return 0xFFFF as the selected dialect.
  228. //
  229. if ( bestDialect == SmbDialectPcNet10 ||
  230. consumerDialectChosen == (USHORT)0xFFFF ) {
  231. respOldNegotiate = (PRESP_OLD_NEGOTIATE)response;
  232. respOldNegotiate->WordCount = 1;
  233. SmbPutUshort( &respOldNegotiate->DialectIndex, consumerDialectChosen );
  234. SmbPutUshort( &respOldNegotiate->ByteCount, 0 );
  235. WorkContext->ResponseParameters = NEXT_LOCATION(
  236. respOldNegotiate,
  237. RESP_OLD_NEGOTIATE,
  238. 0
  239. );
  240. }
  241. else if ( bestDialect > SmbDialectNtLanMan ) {
  242. USHORT securityMode;
  243. //
  244. // Send the OS/2 LAN Man SMB response.
  245. //
  246. WorkContext->ResponseHeader->Flags =
  247. (UCHAR)(WorkContext->RequestHeader->Flags | SMB_FLAGS_LOCK_AND_READ_OK);
  248. response->WordCount = 13;
  249. SmbPutUshort( &response->DialectIndex, consumerDialectChosen );
  250. //
  251. // Indicate that we're user-level security and that we
  252. // want encrypted passwords.
  253. //
  254. securityMode = NEGOTIATE_USER_SECURITY | NEGOTIATE_ENCRYPT_PASSWORDS;
  255. SmbPutUshort(
  256. &response->SecurityMode,
  257. securityMode
  258. );
  259. //
  260. // Get an encryption key for this connection.
  261. //
  262. GetEncryptionKey( pagedConnection->EncryptionKey );
  263. SmbPutUshort( &response->EncryptionKeyLength, MSV1_0_CHALLENGE_LENGTH );
  264. SmbPutUshort( &response->Reserved, 0 );
  265. byteCount = MSV1_0_CHALLENGE_LENGTH;
  266. RtlCopyMemory(
  267. response->Buffer,
  268. pagedConnection->EncryptionKey,
  269. MSV1_0_CHALLENGE_LENGTH
  270. );
  271. if ( endpoint->IsConnectionless ) {
  272. ULONG adapterNumber;
  273. ULONG maxBufferSize;
  274. //
  275. // Our server max buffer size is the smaller of the
  276. // server receive buffer size and the ipx transport
  277. // indicated max packet size.
  278. //
  279. adapterNumber =
  280. WorkContext->ClientAddress->DatagramOptions.LocalTarget.NicId;
  281. maxBufferSize = GetIpxMaxBufferSize(
  282. endpoint,
  283. adapterNumber,
  284. SrvReceiveBufferLength
  285. );
  286. SmbPutUshort(
  287. &response->MaxBufferSize,
  288. (USHORT)maxBufferSize
  289. );
  290. } else {
  291. SmbPutUshort(
  292. &response->MaxBufferSize,
  293. (USHORT)SrvReceiveBufferLength
  294. );
  295. }
  296. SmbPutUshort( &response->MaxMpxCount, MIN(125, SrvMaxMpxCount) ); // Only send max of 125 to Win9x machines since they'll not connect if higher
  297. SmbPutUshort( &response->MaxNumberVcs, (USHORT)SrvMaxNumberVcs );
  298. SmbPutUlong( &response->SessionKey, 0 );
  299. //
  300. // If this is an MS-NET 1.03 client or before, then tell him that we
  301. // don't support raw writes. MS-NET 1.03 does different things with
  302. // raw writes that are more trouble than they're worth, and since
  303. // raw is simply a performance issue, we don't support it.
  304. //
  305. if ( bestDialect >= SmbDialectMsNet103 ) {
  306. SmbPutUshort(
  307. &response->RawMode,
  308. (USHORT)(SrvEnableRawMode ?
  309. NEGOTIATE_READ_RAW_SUPPORTED :
  310. 0)
  311. );
  312. } else {
  313. SmbPutUshort(
  314. &response->RawMode,
  315. (USHORT)(SrvEnableRawMode ?
  316. NEGOTIATE_READ_RAW_SUPPORTED |
  317. NEGOTIATE_WRITE_RAW_SUPPORTED :
  318. 0)
  319. );
  320. }
  321. SmbPutUlong( &response->SessionKey, 0 );
  322. SrvTimeToDosTime( &serverTime, &date, &time );
  323. SmbPutDate( &response->ServerDate, date );
  324. SmbPutTime( &response->ServerTime, time );
  325. //
  326. // Get time zone bias. We compute this during session
  327. // setup rather than once during server startup because
  328. // we might switch from daylight time to standard time
  329. // or vice versa during normal server operation.
  330. //
  331. SmbPutUshort( &response->ServerTimeZone,
  332. SrvGetOs2TimeZone(&serverTime) );
  333. if ( bestDialect == SmbDialectLanMan21 ||
  334. bestDialect == SmbDialectDosLanMan21 ) {
  335. //
  336. // Append the domain to the SMB.
  337. //
  338. RtlCopyMemory(
  339. response->Buffer + byteCount,
  340. endpoint->OemDomainName.Buffer,
  341. endpoint->OemDomainName.Length + sizeof(CHAR)
  342. );
  343. byteCount += endpoint->OemDomainName.Length + sizeof(CHAR);
  344. }
  345. SmbPutUshort( &response->ByteCount, byteCount );
  346. WorkContext->ResponseParameters = NEXT_LOCATION(
  347. response,
  348. RESP_NEGOTIATE,
  349. byteCount
  350. );
  351. } else {
  352. //
  353. // NT or better protocol has been negotiated.
  354. //
  355. flags2 = SmbGetAlignedUshort( &smbHeader->Flags2 );
  356. //
  357. // We are going to attempt to validate this user with one of the listed
  358. // security packages at the end of the smb. Currently the smb will
  359. // simply contain the output of EnumerateSecurityPackages.
  360. //
  361. if ( flags2 & SMB_FLAGS2_EXTENDED_SECURITY ) {
  362. if (!WorkContext->UsingExtraSmbBuffer) {
  363. status = SrvAllocateExtraSmbBuffer(WorkContext);
  364. if (!NT_SUCCESS(status)) {
  365. SrvSetSmbError(WorkContext, status);
  366. SmbStatus = SmbStatusSendResponse;
  367. goto Cleanup;
  368. }
  369. RtlCopyMemory(
  370. WorkContext->ResponseHeader,
  371. WorkContext->RequestHeader,
  372. sizeof( SMB_HEADER )
  373. );
  374. }
  375. ntResponse = (PRESP_NT_NEGOTIATE)WorkContext->ResponseParameters;
  376. capabilities = CAP_EXTENDED_SECURITY;
  377. } else {
  378. capabilities = 0;
  379. }
  380. #ifdef INCLUDE_SMB_PERSISTENT
  381. if ( bestDialect == SmbDialectNtLanMan2 ) {
  382. capabilities |= CAP_PERSISTENT_HANDLES;
  383. SrvPrint1( "SrvSmbNegotiate: persistent handles for conn 0x%x.\n",
  384. WorkContext->Connection );
  385. }
  386. #endif
  387. ntResponse->WordCount = 17;
  388. SmbPutUshort( &ntResponse->DialectIndex, consumerDialectChosen );
  389. // !!! This says that we don't want encrypted passwords.
  390. // If this is negotiating NtLanMan, but not UNICODE, we know its not a Win9x client
  391. // so it can handle MaxMpx larger than 125
  392. if( flags2 & SMB_FLAGS2_UNICODE )
  393. {
  394. SmbPutUshort( &ntResponse->MaxMpxCount, SrvMaxMpxCount );
  395. }
  396. else
  397. {
  398. // Again, for the Win9x problems we need to minimize the Mpx count.
  399. SmbPutUshort( &ntResponse->MaxMpxCount, MIN(125,SrvMaxMpxCount) );
  400. }
  401. SmbPutUshort( &ntResponse->MaxNumberVcs, (USHORT)SrvMaxNumberVcs );
  402. SmbPutUlong( &ntResponse->MaxRawSize, 64 * 1024 ); // !!!
  403. SmbPutUlong( &ntResponse->SessionKey, 0 );
  404. capabilities |= CAP_RAW_MODE |
  405. CAP_UNICODE |
  406. CAP_LARGE_FILES |
  407. CAP_NT_SMBS |
  408. CAP_NT_FIND |
  409. CAP_RPC_REMOTE_APIS |
  410. CAP_NT_STATUS |
  411. CAP_LEVEL_II_OPLOCKS |
  412. CAP_INFOLEVEL_PASSTHRU |
  413. CAP_LOCK_AND_READ;
  414. //
  415. // If we're supporting Dfs operations, let the client know about it.
  416. //
  417. if( SrvDfsFastIoDeviceControl ) {
  418. capabilities |= CAP_DFS;
  419. }
  420. if ( endpoint->IsConnectionless ) {
  421. ULONG adapterNumber;
  422. ULONG maxBufferSize;
  423. capabilities |= CAP_MPX_MODE;
  424. capabilities &= ~CAP_RAW_MODE;
  425. //
  426. // Our server max buffer size is the smaller of the
  427. // server receive buffer size and the ipx transport
  428. // indicated max packet size.
  429. //
  430. adapterNumber =
  431. WorkContext->ClientAddress->DatagramOptions.LocalTarget.NicId;
  432. maxBufferSize = GetIpxMaxBufferSize(
  433. endpoint,
  434. adapterNumber,
  435. SrvReceiveBufferLength
  436. );
  437. SmbPutUlong(
  438. &ntResponse->MaxBufferSize,
  439. maxBufferSize
  440. );
  441. } else {
  442. SmbPutUlong(
  443. &ntResponse->MaxBufferSize,
  444. SrvReceiveBufferLength
  445. );
  446. capabilities |= CAP_LARGE_READX;
  447. //
  448. // Unfortunately, NetBT is the only protocol that reliably supports
  449. // transfers exceeding the negotiated buffer size. So disable the
  450. // other protocols for now (hopefully)
  451. //
  452. if( connection->ClientIPAddress ) {
  453. capabilities |= CAP_LARGE_WRITEX;
  454. if( SrvSupportsCompression ) {
  455. capabilities |= CAP_COMPRESSED_DATA;
  456. }
  457. }
  458. }
  459. SmbPutUlong( &ntResponse->Capabilities, capabilities );
  460. //
  461. // Stick the servers system time and timezone in the negotiate
  462. // response.
  463. //
  464. SmbPutUlong( &ntResponse->SystemTimeLow, serverTime.LowPart );
  465. SmbPutUlong( &ntResponse->SystemTimeHigh, serverTime.HighPart );
  466. SmbPutUshort( &ntResponse->ServerTimeZone,
  467. SrvGetOs2TimeZone(&serverTime) );
  468. //
  469. // Indicate that we're user-level security and that we
  470. // want encrypted passwords.
  471. //
  472. ntResponse->SecurityMode =
  473. NEGOTIATE_USER_SECURITY | NEGOTIATE_ENCRYPT_PASSWORDS;
  474. //
  475. // There is a bug in some W9x clients that preclude the use of security
  476. // signatures. We have produced a fix for vredir.vxd for this, but we
  477. // can not tell whether or not we are working with one of these fixed
  478. // clients. The only way i can think of to tell the difference between
  479. // a W9x client and a properly functioning NT client is to look to see
  480. // if the client understands NT status codes.
  481. //
  482. if( SrvSmbSecuritySignaturesEnabled &&
  483. ( SrvEnableW9xSecuritySignatures == TRUE ||
  484. (flags2 & SMB_FLAGS2_NT_STATUS) ) ) {
  485. ntResponse->SecurityMode |= NEGOTIATE_SECURITY_SIGNATURES_ENABLED;
  486. if( SrvSmbSecuritySignaturesRequired ) {
  487. ntResponse->SecurityMode |= NEGOTIATE_SECURITY_SIGNATURES_REQUIRED;
  488. }
  489. }
  490. //
  491. // Get an encryption key for this connection.
  492. //
  493. if ((capabilities & CAP_EXTENDED_SECURITY) == 0) {
  494. GetEncryptionKey( pagedConnection->EncryptionKey );
  495. RtlCopyMemory(
  496. ntResponse->Buffer,
  497. pagedConnection->EncryptionKey,
  498. MSV1_0_CHALLENGE_LENGTH
  499. );
  500. ASSERT ( MSV1_0_CHALLENGE_LENGTH <= 0xff ) ;
  501. ntResponse->EncryptionKeyLength = MSV1_0_CHALLENGE_LENGTH;
  502. byteCount = MSV1_0_CHALLENGE_LENGTH;
  503. {
  504. USHORT domainLength;
  505. PWCH buffer = (PWCHAR)( ntResponse->Buffer+byteCount );
  506. PWCH ptr;
  507. domainLength = endpoint->DomainName.Length +
  508. sizeof(UNICODE_NULL);
  509. ptr = endpoint->DomainName.Buffer;
  510. RtlCopyMemory(
  511. buffer,
  512. ptr,
  513. domainLength
  514. );
  515. byteCount += domainLength;
  516. //
  517. // Append the server name to the response.
  518. //
  519. if( SrvComputerName.Buffer ) {
  520. buffer = (PWCHAR)((LPSTR)buffer + domainLength);
  521. RtlCopyMemory( buffer,
  522. SrvComputerName.Buffer,
  523. SrvComputerName.Length
  524. );
  525. SmbPutUshort( &buffer[ SrvComputerName.Length / 2 ], UNICODE_NULL );
  526. byteCount += SrvComputerName.Length + sizeof( UNICODE_NULL );
  527. }
  528. }
  529. SmbPutUshort( &ntResponse->ByteCount, byteCount );
  530. WorkContext->ResponseParameters = NEXT_LOCATION(
  531. ntResponse,
  532. RESP_NT_NEGOTIATE,
  533. byteCount
  534. );
  535. } // if !(capabilities & CAP_EXTENDED_SECURITY)
  536. else {
  537. CtxtHandle negotiateHandle;
  538. USHORT bufferLength;
  539. PCHAR buffer;
  540. //
  541. // Reserved if extended security negotiated (MBZ!)
  542. //
  543. ntResponse->EncryptionKeyLength = 0;
  544. //
  545. // SrvGetExtensibleSecurityNegotiateBuffer will fill in the
  546. // securityblob field and return the length of that information.
  547. //
  548. RtlCopyMemory(&ntResponse->Buffer, &ServerGuid, sizeof(ServerGuid) );
  549. byteCount = sizeof(ServerGuid);
  550. buffer = ntResponse->Buffer + byteCount;
  551. status = SrvGetExtensibleSecurityNegotiateBuffer(
  552. &negotiateHandle,
  553. buffer,
  554. &bufferLength
  555. );
  556. if (!NT_SUCCESS(status)) {
  557. SrvSetSmbError(WorkContext, STATUS_ACCESS_DENIED);
  558. status = STATUS_ACCESS_DENIED;
  559. SmbStatus = SmbStatusSendResponse;
  560. goto Cleanup;
  561. }
  562. //
  563. // Grab the session locks here...
  564. //
  565. ACQUIRE_LOCK( &connection->Lock );
  566. connection->NegotiateHandle = negotiateHandle;
  567. RELEASE_LOCK( &connection->Lock );
  568. byteCount += bufferLength;
  569. SmbPutUshort( &ntResponse->ByteCount, byteCount );
  570. WorkContext->ResponseParameters = NEXT_LOCATION(
  571. ntResponse,
  572. RESP_NT_NEGOTIATE,
  573. byteCount
  574. );
  575. }
  576. } // else (NT protocol has been negotiated).
  577. SmbStatus = SmbStatusSendResponse;
  578. IF_DEBUG(TRACE2) SrvPrint0( "SrvSmbNegotiate complete.\n" );
  579. Cleanup:
  580. SrvWmiEndContext(WorkContext);
  581. return SmbStatus;
  582. } // SrvSmbNegotiate
  583. SMB_PROCESSOR_RETURN_TYPE
  584. SrvSmbProcessExit (
  585. SMB_PROCESSOR_PARAMETERS
  586. )
  587. /*++
  588. Routine Description:
  589. Processes a Process Exit SMB.
  590. Arguments:
  591. SMB_PROCESSOR_PARAMETERS - See smbprocs.h for a description
  592. of the parameters to SMB processor routines.
  593. Return Value:
  594. SMB_PROCESSOR_RETURN_TYPE - See smbprocs.h
  595. --*/
  596. {
  597. PREQ_PROCESS_EXIT request;
  598. PRESP_PROCESS_EXIT response;
  599. PSESSION session;
  600. USHORT pid;
  601. NTSTATUS status = STATUS_SUCCESS;
  602. PAGED_CODE( );
  603. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  604. WorkContext->PreviousSMB = EVENT_TYPE_SMB_PROCESS_EXIT;
  605. SrvWmiStartContext(WorkContext);
  606. IF_SMB_DEBUG(ADMIN1) {
  607. SrvPrint2( "Process exit request header at 0x%p, response header at 0x%p\n",
  608. WorkContext->RequestHeader,
  609. WorkContext->ResponseHeader );
  610. SrvPrint2( "Process exit request parameters at 0x%p, response parameters at 0x%p\n",
  611. WorkContext->RequestParameters,
  612. WorkContext->ResponseParameters );
  613. }
  614. //
  615. // Set up parameters.
  616. //
  617. request = (PREQ_PROCESS_EXIT)(WorkContext->RequestParameters);
  618. response = (PRESP_PROCESS_EXIT)(WorkContext->ResponseParameters);
  619. //
  620. // If a session block has not already been assigned to the current
  621. // work context, verify the UID. If verified, the address of the
  622. // session block corresponding to this user is stored in the
  623. // WorkContext block and the session block is referenced.
  624. //
  625. session = SrvVerifyUid(
  626. WorkContext,
  627. SmbGetAlignedUshort( &WorkContext->RequestHeader->Uid )
  628. );
  629. if ( session == NULL ) {
  630. IF_DEBUG(SMB_ERRORS) {
  631. SrvPrint1( "SrvSmbProcessExit: Invalid UID: 0x%lx\n",
  632. SmbGetAlignedUshort( &WorkContext->RequestHeader->Uid ) );
  633. }
  634. SrvSetSmbError( WorkContext, STATUS_SMB_BAD_UID );
  635. status = STATUS_SMB_BAD_UID;
  636. goto Cleanup;
  637. }
  638. //
  639. // Close all files with the same PID as in the header for this request.
  640. //
  641. pid = SmbGetAlignedUshort( &WorkContext->RequestHeader->Pid );
  642. IF_SMB_DEBUG(ADMIN1) SrvPrint1( "Closing files with PID = %lx\n", pid );
  643. SrvCloseRfcbsOnSessionOrPid( session, &pid );
  644. //
  645. // Close all searches with the same PID as in the header for this request.
  646. //
  647. IF_SMB_DEBUG(ADMIN1) SrvPrint1( "Closing searches with PID = %lx\n", pid );
  648. SrvCloseSearches(
  649. session->Connection,
  650. (PSEARCH_FILTER_ROUTINE)SrvSearchOnPid,
  651. (PVOID) pid,
  652. NULL
  653. );
  654. //
  655. // Close any cached directories for this client
  656. //
  657. SrvCloseCachedDirectoryEntries( session->Connection );
  658. //
  659. // Build the response SMB.
  660. //
  661. response->WordCount = 0;
  662. SmbPutUshort( &response->ByteCount, 0 );
  663. WorkContext->ResponseParameters = NEXT_LOCATION(
  664. response,
  665. RESP_PROCESS_EXIT,
  666. 0
  667. );
  668. Cleanup:
  669. SrvWmiEndContext(WorkContext);
  670. return SmbStatusSendResponse;
  671. } // SrvSmbProcessExit
  672. SMB_PROCESSOR_RETURN_TYPE
  673. SrvSmbSessionSetupAndX(
  674. SMB_PROCESSOR_PARAMETERS
  675. )
  676. /*++
  677. Routine Description:
  678. Processes a session setup and X SMB.
  679. Arguments:
  680. SMB_PROCESSOR_PARAMETERS - See smbprocs.h for a description
  681. of the parameters to SMB processor routines.
  682. Return Value:
  683. SMB_PROCESSOR_RETURN_TYPE - See smbprocs.h
  684. --*/
  685. {
  686. PAGED_CODE();
  687. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  688. WorkContext->PreviousSMB = EVENT_TYPE_SMB_SESSION_SETUP_AND_X;
  689. SrvWmiStartContext(WorkContext);
  690. //
  691. // This SMB must be processed in a blocking thread.
  692. //
  693. WorkContext->FspRestartRoutine = BlockingSessionSetupAndX;
  694. SrvQueueWorkToBlockingThread( WorkContext );
  695. SrvWmiEndContext(WorkContext);
  696. return SmbStatusInProgress;
  697. } // SrvSmbSessionSetupAndX
  698. VOID SRVFASTCALL
  699. BlockingSessionSetupAndX(
  700. IN OUT PWORK_CONTEXT WorkContext
  701. )
  702. /*++
  703. Routine Description:
  704. Processes a session setup and X SMB.
  705. Arguments:
  706. SMB_PROCESSOR_PARAMETERS - See smbprocs.h for a description
  707. of the parameters to SMB processor routines.
  708. Return Value:
  709. SMB_PROCESSOR_RETURN_TYPE - See smbprocs.h
  710. --*/
  711. {
  712. PREQ_SESSION_SETUP_ANDX request;
  713. PREQ_NT_SESSION_SETUP_ANDX ntRequest;
  714. PREQ_NT_EXTENDED_SESSION_SETUP_ANDX ntExtendedRequest;
  715. PRESP_SESSION_SETUP_ANDX response;
  716. NTSTATUS SecStatus ;
  717. NTSTATUS status = STATUS_SUCCESS;
  718. SMB_STATUS SmbStatus = SmbStatusInProgress;
  719. PSESSION session;
  720. PCONNECTION connection;
  721. PENDPOINT endpoint;
  722. PPAGED_CONNECTION pagedConnection;
  723. PTABLE_ENTRY entry;
  724. LUID logonId;
  725. SHORT uidIndex;
  726. USHORT reqAndXOffset;
  727. UCHAR nextCommand;
  728. PCHAR smbInformation;
  729. ULONG smbInformationLength;
  730. ULONG returnBufferLength = 0;
  731. #ifdef INCLUDE_SMB_PERSISTENT
  732. ULONG persistentSessionId = 0;
  733. #endif
  734. UNICODE_STRING nameString;
  735. UNICODE_STRING domainString;
  736. USHORT action = 0;
  737. USHORT byteCount;
  738. BOOLEAN locksHeld;
  739. BOOLEAN isUnicode, isExtendedSecurity;
  740. BOOLEAN smbSecuritySignatureRequired = FALSE;
  741. BOOLEAN previousSecuritySignatureState;
  742. PAGED_CODE();
  743. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  744. WorkContext->PreviousSMB = EVENT_TYPE_SMB_SESSION_SETUP_AND_X;
  745. SrvWmiStartContext(WorkContext);
  746. //
  747. // If the connection has closed (timed out), abort.
  748. //
  749. connection = WorkContext->Connection;
  750. if ( GET_BLOCK_STATE(connection) != BlockStateActive ) {
  751. IF_DEBUG(ERRORS) {
  752. SrvPrint0( "SrvSmbSessionSetupAndX: Connection closing\n" );
  753. }
  754. SrvEndSmbProcessing( WorkContext, SmbStatusNoResponse );
  755. SmbStatus = SmbStatusNoResponse;
  756. goto Cleanup;
  757. }
  758. IF_SMB_DEBUG(ADMIN1) {
  759. SrvPrint2( "Session setup request header at 0x%p, response header at 0x%p\n",
  760. WorkContext->RequestHeader, WorkContext->ResponseHeader );
  761. SrvPrint2( "Session setup request parameters at 0x%p, response parameters at 0x%p\n",
  762. WorkContext->RequestParameters,
  763. WorkContext->ResponseParameters );
  764. }
  765. //
  766. // Initialize local variables for error cleanup.
  767. //
  768. nameString.Buffer = NULL;
  769. domainString.Buffer = NULL;
  770. session = NULL;
  771. locksHeld = FALSE;
  772. isExtendedSecurity = FALSE;
  773. //
  774. // Set up parameters.
  775. //
  776. request = (PREQ_SESSION_SETUP_ANDX)(WorkContext->RequestParameters);
  777. ntRequest = (PREQ_NT_SESSION_SETUP_ANDX)(WorkContext->RequestParameters);
  778. ntExtendedRequest = (PREQ_NT_EXTENDED_SESSION_SETUP_ANDX)(WorkContext->RequestParameters);
  779. response = (PRESP_SESSION_SETUP_ANDX)(WorkContext->ResponseParameters);
  780. connection = WorkContext->Connection;
  781. pagedConnection = connection->PagedConnection;
  782. previousSecuritySignatureState = connection->SmbSecuritySignatureActive;
  783. //
  784. // First verify that the SMB format is correct.
  785. //
  786. if ( (connection->SmbDialect <= SmbDialectNtLanMan &&
  787. (!((request->WordCount == 13) ||
  788. ((request->WordCount == 12) &&
  789. ((ntExtendedRequest->Capabilities & CAP_EXTENDED_SECURITY) != 0))))) ||
  790. (connection->SmbDialect > SmbDialectNtLanMan &&
  791. request->WordCount != 10 ) ||
  792. (connection->SmbDialect == SmbDialectIllegal ) ) {
  793. //
  794. // The SMB word count is invalid.
  795. //
  796. IF_DEBUG(SMB_ERRORS) {
  797. if ( connection->SmbDialect == SmbDialectIllegal ) {
  798. SrvPrint1("BlockingSessionSetupAndX: Client %z is using an "
  799. "illegal dialect.\n", (PCSTRING)&connection->OemClientMachineNameString );
  800. }
  801. }
  802. status = STATUS_INVALID_SMB;
  803. goto error_exit1;
  804. }
  805. //
  806. // Convert the client name to unicode
  807. //
  808. if ( pagedConnection->ClientMachineNameString.Length == 0 ) {
  809. UNICODE_STRING clientMachineName;
  810. clientMachineName.Buffer = pagedConnection->ClientMachineName;
  811. clientMachineName.MaximumLength =
  812. (USHORT)(COMPUTER_NAME_LENGTH+1)*sizeof(WCHAR);
  813. (VOID)RtlOemStringToUnicodeString(
  814. &clientMachineName,
  815. &connection->OemClientMachineNameString,
  816. FALSE
  817. );
  818. //
  819. // Add the double backslashes to the length
  820. //
  821. pagedConnection->ClientMachineNameString.Length =
  822. (USHORT)(clientMachineName.Length + 2*sizeof(WCHAR));
  823. }
  824. //
  825. // If this is LanMan 2.1 or better, the session setup response may
  826. // be longer than the request. Allocate an extra SMB buffer. The
  827. // buffer is freed after we have finished sending the SMB response.
  828. //
  829. // !!! Try to be smarter before grabbing the extra buffer.
  830. //
  831. if ( connection->SmbDialect <= SmbDialectDosLanMan21 &&
  832. !WorkContext->UsingExtraSmbBuffer) {
  833. status = SrvAllocateExtraSmbBuffer( WorkContext );
  834. if ( !NT_SUCCESS(status) ) {
  835. goto error_exit;
  836. }
  837. response = (PRESP_SESSION_SETUP_ANDX)(WorkContext->ResponseParameters);
  838. RtlCopyMemory(
  839. WorkContext->ResponseHeader,
  840. WorkContext->RequestHeader,
  841. sizeof( SMB_HEADER )
  842. );
  843. }
  844. //
  845. // Get the client capabilities
  846. //
  847. if ( connection->SmbDialect <= SmbDialectNtLanMan ) {
  848. if (ntRequest->WordCount == 13) {
  849. connection->ClientCapabilities =
  850. SmbGetUlong( &ntRequest->Capabilities ) &
  851. ( CAP_UNICODE |
  852. CAP_LARGE_FILES |
  853. CAP_NT_SMBS |
  854. CAP_NT_FIND |
  855. CAP_NT_STATUS |
  856. CAP_DYNAMIC_REAUTH |
  857. CAP_EXTENDED_SECURITY |
  858. #ifdef INCLUDE_SMB_PERSISTENT
  859. CAP_PERSISTENT_HANDLES |
  860. #endif
  861. CAP_LEVEL_II_OPLOCKS );
  862. } else {
  863. connection->ClientCapabilities =
  864. SmbGetUlong( &ntExtendedRequest->Capabilities ) &
  865. ( CAP_UNICODE |
  866. CAP_LARGE_FILES |
  867. CAP_NT_SMBS |
  868. CAP_NT_FIND |
  869. CAP_NT_STATUS |
  870. CAP_DYNAMIC_REAUTH |
  871. CAP_EXTENDED_SECURITY |
  872. #ifdef INCLUDE_SMB_PERSISTENT
  873. CAP_PERSISTENT_HANDLES |
  874. #endif
  875. CAP_LEVEL_II_OPLOCKS );
  876. }
  877. if ( connection->ClientCapabilities & CAP_NT_SMBS ) {
  878. connection->ClientCapabilities |= CAP_NT_FIND;
  879. }
  880. #ifdef INCLUDE_SMB_PERSISTENT
  881. if ( connection->SmbDialect <= SmbDialectNtLanMan2 ) {
  882. //
  883. // do we need to restore a previous lost connection?
  884. //
  885. if (connection->ClientCapabilities & CAP_PERSISTENT_HANDLES) {
  886. while ( persistentSessionId == 0 ) {
  887. persistentSessionId = InterlockedIncrement( &SrvGlobalPersistentSessionId );
  888. }
  889. }
  890. } else {
  891. connection->ClientCapabilities &= ~CAP_PERSISTENT_HANDLES;
  892. }
  893. #endif
  894. }
  895. //
  896. // See if the client is requesting the use of SMB security signatures
  897. //
  898. if( SrvSmbSecuritySignaturesEnabled == TRUE &&
  899. connection->Endpoint->IsConnectionless == FALSE &&
  900. connection->SmbSecuritySignatureActive == FALSE &&
  901. ( SrvSmbSecuritySignaturesRequired == TRUE ||
  902. (WorkContext->RequestHeader->Flags2 & SMB_FLAGS2_SMB_SECURITY_SIGNATURE)) ) {
  903. smbSecuritySignatureRequired = TRUE;
  904. } else {
  905. smbSecuritySignatureRequired = FALSE;
  906. }
  907. //
  908. // Figure out what kind of security to use, use it to validate the
  909. // session setup request, and construct the session if request checks out.
  910. //
  911. isExtendedSecurity = CLIENT_CAPABLE_OF( EXTENDED_SECURITY, connection );
  912. if( isExtendedSecurity ) {
  913. USHORT flags2;
  914. flags2 = SmbGetAlignedUshort( &WorkContext->RequestHeader->Flags2 );
  915. isExtendedSecurity = ((flags2 & SMB_FLAGS2_EXTENDED_SECURITY) != 0);
  916. }
  917. isUnicode = SMB_IS_UNICODE( WorkContext );
  918. if ((connection->SmbDialect <= SmbDialectNtLanMan) && isExtendedSecurity) {
  919. //
  920. // We are validating a client using extended security. This meansthat
  921. // there may be multiple round-trips necessary for the SessionSetup&X
  922. // SMB. Each request and response carries a "security blob", which is
  923. // fed into the security system. The security system may generate
  924. // a new blob which is transmitted to the other end. This exchange
  925. // may require an arbitrary number of round trips.
  926. //
  927. PUCHAR securityBuffer;
  928. ULONG securityBufferLength;
  929. PRESP_NT_EXTENDED_SESSION_SETUP_ANDX ntExtendedResponse =
  930. (PRESP_NT_EXTENDED_SESSION_SETUP_ANDX)( WorkContext->ResponseParameters );
  931. //
  932. // No AndX is permitted with extended security logons
  933. //
  934. if( request->AndXCommand != SMB_COM_NO_ANDX_COMMAND ) {
  935. IF_DEBUG(SMB_ERRORS) {
  936. KdPrint(( "No follow-on command allowed for extended SS&X\n" ));
  937. }
  938. status = STATUS_INVALID_SMB;
  939. } else {
  940. //
  941. // Clean up old dead connections from this client
  942. //
  943. if( SmbGetUshort( &ntRequest->VcNumber ) == 0 ) {
  944. SrvCloseConnectionsFromClient( connection, FALSE );
  945. }
  946. status = GetExtendedSecurityParameters(
  947. WorkContext,
  948. &securityBuffer,
  949. &securityBufferLength,
  950. &smbInformation,
  951. &smbInformationLength );
  952. }
  953. if (NT_SUCCESS(status)) {
  954. USHORT Uid = SmbGetAlignedUshort(&WorkContext->RequestHeader->Uid);
  955. //
  956. // Let's see if we have a session with this UID already around.
  957. //
  958. if( Uid ) {
  959. session = SrvVerifyUid ( WorkContext, Uid );
  960. if( session != NULL ) {
  961. //
  962. // This is an attempt to either refresh the UID, or we are
  963. // in the middle of an extended security negotiation.
  964. //
  965. ACQUIRE_LOCK( &connection->Lock );
  966. if( session->LogonSequenceInProgress == FALSE ) {
  967. //
  968. // We are just beginning to start the refresh
  969. // of the UID.
  970. //
  971. session->LogonSequenceInProgress = TRUE;
  972. session->IsAdmin = FALSE;
  973. session->IsSessionExpired = TRUE;
  974. status = SrvFreeSecurityContexts( session );
  975. //
  976. // Reduce the session count, as it will be incremented if authentication succeeds
  977. //
  978. ExInterlockedAddUlong(
  979. &SrvStatistics.CurrentNumberOfSessions,
  980. -1,
  981. &GLOBAL_SPIN_LOCK(Statistics)
  982. );
  983. }
  984. RELEASE_LOCK( &connection->Lock );
  985. } else {
  986. //
  987. // We don't know anything about the UID which
  988. // the client gave to us.
  989. //
  990. status = STATUS_SMB_BAD_UID;
  991. }
  992. } else {
  993. //
  994. // This is the first SS&X for this user id
  995. //
  996. SrvAllocateSession( &session, NULL, NULL );
  997. if( session == NULL ) {
  998. status = STATUS_INSUFF_SERVER_RESOURCES;
  999. }
  1000. }
  1001. if( session != NULL ) {
  1002. //
  1003. // Validate the security buffer sent from the client. Note that
  1004. // this may change the UserHandle value, so we need to own
  1005. // the connection lock.
  1006. //
  1007. ACQUIRE_LOCK( &connection->Lock );
  1008. //
  1009. // Try to authenticate this user. If we get NT_SUCCESS(), then
  1010. // the user is fully authenticated. If we get
  1011. // STATUS_NOT_MORE_PROCESSING_REQUIRED, then things are going well,
  1012. // but we need to do some more exchanges with the client before
  1013. // authentication is complete. Anything else is an error
  1014. //
  1015. returnBufferLength = WorkContext->ResponseBuffer->BufferLength -
  1016. PTR_DIFF(ntExtendedResponse->Buffer,
  1017. WorkContext->ResponseBuffer->Buffer);
  1018. status = SrvValidateSecurityBuffer(
  1019. WorkContext->Connection,
  1020. &session->UserHandle,
  1021. session,
  1022. securityBuffer,
  1023. securityBufferLength,
  1024. smbSecuritySignatureRequired,
  1025. ntExtendedResponse->Buffer,
  1026. &returnBufferLength,
  1027. &session->LogOffTime,
  1028. session->NtUserSessionKey,
  1029. &session->LogonId,
  1030. &session->GuestLogon
  1031. );
  1032. SecStatus = KSecValidateBuffer(
  1033. ntExtendedResponse->Buffer,
  1034. returnBufferLength );
  1035. if ( !NT_SUCCESS( SecStatus ) ) {
  1036. #if DBG
  1037. KdPrint(( "SRV: invalid buffer from KsecDD: %p,%lx\n",
  1038. ntExtendedResponse->Buffer, returnBufferLength ));
  1039. #endif
  1040. SrvKsecValidErrors++;
  1041. }
  1042. RELEASE_LOCK( &connection->Lock );
  1043. if( NT_SUCCESS(status) ) {
  1044. //
  1045. // This client is now fully authenticated!
  1046. //
  1047. session->IsAdmin = SrvIsAdmin( session->UserHandle );
  1048. session->IsNullSession = SrvIsNullSession( session->UserHandle );
  1049. session->KickOffTime.QuadPart = 0x7FFFFFFFFFFFFFFF;
  1050. session->EncryptedLogon = TRUE;
  1051. session->LogonSequenceInProgress = FALSE;
  1052. session->IsSessionExpired = FALSE;
  1053. if( session->IsNullSession ) {
  1054. session->LogOffTime.QuadPart = 0x7FFFFFFFFFFFFFFF;
  1055. }
  1056. #ifdef INCLUDE_SMB_PERSISTENT
  1057. session->PersistentId = persistentSessionId;
  1058. session->PersistentFileOffset = 0;
  1059. session->PersistentState = PersistentStateFreed;
  1060. #endif
  1061. #if SRVNTVERCHK
  1062. //
  1063. // If we are restricting the domains of our clients, grab the
  1064. // domain string of this client and compare against the list.
  1065. // If the client is in the list, set the flag that disallows
  1066. // access to disk shares.
  1067. //
  1068. if( SrvInvalidDomainNames != NULL ) {
  1069. if( domainString.Buffer == NULL ) {
  1070. SrvGetUserAndDomainName( session, NULL, &domainString );
  1071. }
  1072. ACQUIRE_LOCK_SHARED( &SrvConfigurationLock );
  1073. if( SrvInvalidDomainNames != NULL && domainString.Buffer != NULL ) {
  1074. int i;
  1075. for( i = 0; SrvInvalidDomainNames[i]; i++ ) {
  1076. if( _wcsicmp( SrvInvalidDomainNames[i],
  1077. domainString.Buffer
  1078. ) == 0 ) {
  1079. session->ClientBadDomain = TRUE;
  1080. break;
  1081. }
  1082. }
  1083. }
  1084. RELEASE_LOCK( &SrvConfigurationLock );
  1085. }
  1086. #endif
  1087. } else {
  1088. if( status == STATUS_MORE_PROCESSING_REQUIRED ) {
  1089. session->LogonSequenceInProgress = TRUE;
  1090. }
  1091. }
  1092. }
  1093. }
  1094. } else {
  1095. PCHAR caseInsensitivePassword;
  1096. CLONG caseInsensitivePasswordLength;
  1097. PCHAR caseSensitivePassword;
  1098. CLONG caseSensitivePasswordLength;
  1099. status = GetNtSecurityParameters(
  1100. WorkContext,
  1101. &caseSensitivePassword,
  1102. &caseSensitivePasswordLength,
  1103. &caseInsensitivePassword,
  1104. &caseInsensitivePasswordLength,
  1105. &nameString,
  1106. &domainString,
  1107. &smbInformation,
  1108. &smbInformationLength );
  1109. if (NT_SUCCESS(status)) {
  1110. SrvAllocateSession( &session, &nameString, &domainString );
  1111. if( session != NULL ) {
  1112. status = SrvValidateUser(
  1113. &session->UserHandle,
  1114. session,
  1115. WorkContext->Connection,
  1116. &nameString,
  1117. caseInsensitivePassword,
  1118. caseInsensitivePasswordLength,
  1119. caseSensitivePassword,
  1120. caseSensitivePasswordLength,
  1121. smbSecuritySignatureRequired,
  1122. &action
  1123. );
  1124. } else {
  1125. status = STATUS_INSUFF_SERVER_RESOURCES;
  1126. }
  1127. }
  1128. }
  1129. //
  1130. // Done with the name strings - they were captured into the session
  1131. // structure if needed.
  1132. //
  1133. if (!isUnicode || isExtendedSecurity) {
  1134. if (nameString.Buffer != NULL) {
  1135. RtlFreeUnicodeString( &nameString );
  1136. nameString.Buffer = NULL;
  1137. }
  1138. if (domainString.Buffer != NULL) {
  1139. RtlFreeUnicodeString( &domainString );
  1140. domainString.Buffer = NULL;
  1141. }
  1142. }
  1143. //
  1144. // If a bad name/password combination was sent, return an error.
  1145. //
  1146. if ( !NT_SUCCESS(status) && status != STATUS_MORE_PROCESSING_REQUIRED ) {
  1147. IF_DEBUG(ERRORS) {
  1148. SrvPrint0( "BlockingSessionSetupAndX: Bad user/password combination.\n" );
  1149. }
  1150. SrvStatistics.LogonErrors++;
  1151. goto error_exit;
  1152. }
  1153. if( previousSecuritySignatureState == FALSE &&
  1154. connection->SmbSecuritySignatureActive == TRUE ) {
  1155. //
  1156. // We have 'turned on' SMB security signatures. Make sure that the
  1157. // signature for the Session Setup & X is correct
  1158. //
  1159. //
  1160. // The client's index was 0
  1161. //
  1162. WorkContext->SmbSecuritySignatureIndex = 0;
  1163. //
  1164. // Our response index is 1
  1165. //
  1166. WorkContext->ResponseSmbSecuritySignatureIndex = 1;
  1167. //
  1168. // And the next request should be index 2
  1169. //
  1170. connection->SmbSecuritySignatureIndex = 2;
  1171. }
  1172. //
  1173. // If we have a new session, fill in the remaining required information. We
  1174. // may be operating on an already existing session if we are in the middle
  1175. // of a multi-round-trip extended security blob exchange, or if we are
  1176. // renewing a session.
  1177. //
  1178. if ( WorkContext->Session == NULL ) {
  1179. if( connection->SmbDialect <= SmbDialectDosLanMan21 ) {
  1180. ACQUIRE_LOCK( &connection->Lock );
  1181. if ( connection->ClientOSType.Buffer == NULL ) {
  1182. ULONG length;
  1183. PWCH infoBuffer;
  1184. //
  1185. // If the SMB buffer is ANSI, adjust the size of the buffer we
  1186. // are allocating to Unicode size.
  1187. //
  1188. if ( isUnicode ) {
  1189. smbInformation = ALIGN_SMB_WSTR(smbInformation);
  1190. }
  1191. length = isUnicode ? smbInformationLength : smbInformationLength * sizeof( WCHAR );
  1192. infoBuffer = ALLOCATE_NONPAGED_POOL(
  1193. length,
  1194. BlockTypeDataBuffer );
  1195. if ( infoBuffer == NULL ) {
  1196. RELEASE_LOCK( &connection->Lock );
  1197. status = STATUS_INSUFF_SERVER_RESOURCES;
  1198. goto error_exit;
  1199. }
  1200. connection->ClientOSType.Buffer = (PWCH)infoBuffer;
  1201. connection->ClientOSType.MaximumLength = (USHORT)length;
  1202. //
  1203. // Copy the client OS type to the new buffer.
  1204. //
  1205. length = SrvGetString(
  1206. &connection->ClientOSType,
  1207. smbInformation,
  1208. END_OF_REQUEST_SMB( WorkContext ),
  1209. isUnicode
  1210. );
  1211. if ( length == (USHORT)-1) {
  1212. connection->ClientOSType.Buffer = NULL;
  1213. RELEASE_LOCK( &connection->Lock );
  1214. DEALLOCATE_NONPAGED_POOL( infoBuffer );
  1215. status = STATUS_INVALID_SMB;
  1216. goto error_exit;
  1217. }
  1218. smbInformation += length + sizeof( WCHAR );
  1219. connection->ClientLanManType.Buffer = (PWCH)(
  1220. (PCHAR)connection->ClientOSType.Buffer +
  1221. connection->ClientOSType.Length +
  1222. sizeof( WCHAR ) );
  1223. connection->ClientLanManType.MaximumLength =
  1224. connection->ClientOSType.MaximumLength -
  1225. connection->ClientOSType.Length -
  1226. sizeof( WCHAR );
  1227. //
  1228. // Copy the client LAN Manager type to the new buffer.
  1229. //
  1230. length = SrvGetString(
  1231. &connection->ClientLanManType,
  1232. smbInformation,
  1233. END_OF_REQUEST_SMB( WorkContext ),
  1234. isUnicode
  1235. );
  1236. if ( length == (USHORT)-1) {
  1237. connection->ClientOSType.Buffer = NULL;
  1238. RELEASE_LOCK( &connection->Lock );
  1239. DEALLOCATE_NONPAGED_POOL( infoBuffer );
  1240. status = STATUS_INVALID_SMB;
  1241. goto error_exit;
  1242. }
  1243. //
  1244. // If we have an NT5 or later client, grab the build number from the
  1245. // OS version string.
  1246. //
  1247. if( isExtendedSecurity &&
  1248. connection->ClientOSType.Length &&
  1249. connection->PagedConnection->ClientBuildNumber == 0 ) {
  1250. PWCHAR pdigit = connection->ClientOSType.Buffer;
  1251. PWCHAR epdigit = pdigit + connection->ClientOSType.Length/sizeof(WCHAR);
  1252. ULONG clientBuildNumber = 0;
  1253. //
  1254. // Scan the ClientOSType string to find the last number, and
  1255. // convert to a ULONG. It should be the build number
  1256. //
  1257. while( 1 ) {
  1258. //
  1259. // Scan the string until we find a number.
  1260. //
  1261. for( ; pdigit < epdigit; pdigit++ ) {
  1262. if( *pdigit >= L'0' && *pdigit <= L'9' ) {
  1263. break;
  1264. }
  1265. }
  1266. //
  1267. // If we've hit the end of the string, we are done
  1268. //
  1269. if( pdigit == epdigit ) {
  1270. break;
  1271. }
  1272. clientBuildNumber = 0;
  1273. //
  1274. // Convert the number to a ULONG, assuming it is the build number
  1275. //
  1276. while( pdigit < epdigit && *pdigit >= L'0' && *pdigit <= '9' ) {
  1277. clientBuildNumber *= 10;
  1278. clientBuildNumber += (*pdigit++ - L'0');
  1279. }
  1280. }
  1281. connection->PagedConnection->ClientBuildNumber = clientBuildNumber;
  1282. #if SRVNTVERCHK
  1283. if( SrvMinNT5Client > 0 ) {
  1284. BOOLEAN allowThisClient = FALSE;
  1285. DWORD i;
  1286. //
  1287. // See if we should allow this client, because it is a well-known
  1288. // IP address. This is to allow the build lab to more slowly upgrade
  1289. // than the rest of us.
  1290. //
  1291. if( connection->ClientIPAddress != 0 &&
  1292. connection->Endpoint->IsConnectionless == FALSE ) {
  1293. for( i = 0; SrvAllowIPAddress[i]; i++ ) {
  1294. if( SrvAllowIPAddress[i] == connection->ClientIPAddress ) {
  1295. allowThisClient = TRUE;
  1296. break;
  1297. }
  1298. }
  1299. }
  1300. if( allowThisClient == FALSE &&
  1301. connection->PagedConnection->ClientBuildNumber < SrvMinNT5Client ) {
  1302. connection->PagedConnection->ClientTooOld = TRUE;
  1303. }
  1304. }
  1305. #endif
  1306. }
  1307. }
  1308. RELEASE_LOCK( &connection->Lock );
  1309. }
  1310. //
  1311. // If using uppercase pathnames, indicate in the session block. DOS
  1312. // always uses uppercase paths.
  1313. //
  1314. if ( (WorkContext->RequestHeader->Flags &
  1315. SMB_FLAGS_CANONICALIZED_PATHS) != 0 ||
  1316. IS_DOS_DIALECT( connection->SmbDialect ) ) {
  1317. session->UsingUppercasePaths = TRUE;
  1318. } else {
  1319. session->UsingUppercasePaths = FALSE;
  1320. }
  1321. //
  1322. // Enter data from request SMB into the session block. If MaxMpx is 1
  1323. // disable oplocks on this connection.
  1324. //
  1325. endpoint = connection->Endpoint;
  1326. if ( endpoint->IsConnectionless ) {
  1327. ULONG adapterNumber;
  1328. //
  1329. // Our session max buffer size is the smaller of the
  1330. // client buffer size and the ipx transport
  1331. // indicated max packet size.
  1332. //
  1333. adapterNumber =
  1334. WorkContext->ClientAddress->DatagramOptions.LocalTarget.NicId;
  1335. session->MaxBufferSize =
  1336. (USHORT)GetIpxMaxBufferSize(
  1337. endpoint,
  1338. adapterNumber,
  1339. (ULONG)SmbGetUshort(&request->MaxBufferSize)
  1340. );
  1341. } else {
  1342. session->MaxBufferSize = SmbGetUshort( &request->MaxBufferSize );
  1343. }
  1344. //
  1345. // Make sure the MaxBufferSize is correctly sized
  1346. //
  1347. session->MaxBufferSize &= ~03;
  1348. if( session->MaxBufferSize < SrvMinClientBufferSize ) {
  1349. //
  1350. // Client asked for a buffer size that is too small!
  1351. //
  1352. IF_DEBUG(ERRORS) {
  1353. KdPrint(( "BlockingSessionSetupAndX: Bad Client Buffer Size: %u\n",
  1354. session->MaxBufferSize ));
  1355. }
  1356. status = STATUS_INVALID_SMB;
  1357. goto error_exit;
  1358. }
  1359. session->MaxMpxCount = SmbGetUshort( &request->MaxMpxCount );
  1360. if ( session->MaxMpxCount < 2 ) {
  1361. connection->OplocksAlwaysDisabled = TRUE;
  1362. }
  1363. }
  1364. //
  1365. // If we have completely authenticated the client, and the client thinks
  1366. // that it is the first user on this connection, get rid of other
  1367. // connections (may be due to rebooting of client). Also get rid of other
  1368. // sessions on this connection with the same user name--this handles a
  1369. // DOS "weirdness" where it sends multiple session setups if a tree connect
  1370. // fails.
  1371. //
  1372. // *** If VcNumber is non-zero, we do nothing special. This is the
  1373. // case even though the SrvMaxVcNumber configurable variable
  1374. // should always be equal to one. If a second VC is established
  1375. // between machines, a new session must also be established.
  1376. // This duplicates the LM 2.0 server's behavior.
  1377. //
  1378. if( isExtendedSecurity == FALSE &&
  1379. NT_SUCCESS( status ) &&
  1380. SmbGetUshort( &request->VcNumber ) == 0 ) {
  1381. UNICODE_STRING userName;
  1382. SrvCloseConnectionsFromClient( connection, FALSE );
  1383. //
  1384. // If a client is smart enough to use extended security, then it
  1385. // is presumably smart enough to know what it wants to do with
  1386. // its sessions. So don't just blow off sessions from this client.
  1387. //
  1388. SrvGetUserAndDomainName( session, &userName, NULL );
  1389. if( userName.Buffer ) {
  1390. SrvCloseSessionsOnConnection( connection, &userName );
  1391. SrvReleaseUserAndDomainName( session, &userName, NULL );
  1392. }
  1393. }
  1394. if( WorkContext->Session == NULL ) {
  1395. //
  1396. // Making a new session visible is a multiple-step operation. It
  1397. // must be inserted in the global ordered tree connect list and the
  1398. // containing connection's session table, and the connection must be
  1399. // referenced. We need to make these operations appear atomic, so
  1400. // that the session cannot be accessed elsewhere before we're done
  1401. // setting it up. In order to do this, we hold all necessary locks
  1402. // the entire time we're doing the operations. The first operation
  1403. // is protected by the global ordered list lock
  1404. // (SrvOrderedListLock), while the other operations are protected by
  1405. // the per-connection lock. We take out the ordered list lock
  1406. // first, then the connection lock. This ordering is required by
  1407. // lock levels (see lock.h).
  1408. //
  1409. ASSERT( SrvSessionList.Lock == &SrvOrderedListLock );
  1410. ACQUIRE_LOCK( SrvSessionList.Lock );
  1411. ACQUIRE_LOCK( &connection->Lock );
  1412. locksHeld = TRUE;
  1413. //
  1414. // Ready to try to find a UID for the session. Check to see if the
  1415. // connection is being closed, and if so, terminate this operation.
  1416. //
  1417. if ( GET_BLOCK_STATE(connection) != BlockStateActive ) {
  1418. IF_DEBUG(ERRORS) {
  1419. SrvPrint0( "BlockingSessionSetupAndX: Connection closing\n" );
  1420. }
  1421. status = STATUS_INVALID_PARAMETER;
  1422. goto error_exit;
  1423. }
  1424. //
  1425. // If this client speaks a dialect above LM 1.0, find a UID that can
  1426. // be used for this session. Otherwise, just use location 0 of the
  1427. // table because those clients will not send a UID in SMBs and they
  1428. // can have only one session.
  1429. //
  1430. if ( connection->SmbDialect < SmbDialectLanMan10 ) {
  1431. NTSTATUS TableStatus;
  1432. if ( pagedConnection->SessionTable.FirstFreeEntry == -1
  1433. &&
  1434. SrvGrowTable(
  1435. &pagedConnection->SessionTable,
  1436. SrvInitialSessionTableSize,
  1437. SrvMaxSessionTableSize,
  1438. &TableStatus ) == FALSE
  1439. ) {
  1440. //
  1441. // No free entries in the user table. Reject the request.
  1442. //
  1443. IF_DEBUG(ERRORS) {
  1444. SrvPrint0( "BlockingSessionSetupAndX: No more UIDs available.\n" );
  1445. }
  1446. if( TableStatus == STATUS_INSUFF_SERVER_RESOURCES )
  1447. {
  1448. // The table size is being exceeded, log an error
  1449. SrvLogTableFullError( SRV_TABLE_SESSION );
  1450. status = STATUS_SMB_TOO_MANY_UIDS;
  1451. }
  1452. else
  1453. {
  1454. // Memory allocation error, report it
  1455. status = TableStatus;
  1456. }
  1457. goto error_exit;
  1458. }
  1459. uidIndex = pagedConnection->SessionTable.FirstFreeEntry;
  1460. } else { // if ( dialect < SmbDialectLanMan10 )
  1461. //
  1462. // If this client already has a session at this server, abort.
  1463. // The session should have been closed by the call to
  1464. // SrvCloseSessionsOnConnection above. (We could try to work
  1465. // around the existence of the session by closing it, but that
  1466. // would involve releasing the locks, closing the session, and
  1467. // retrying. This case shouldn't happen.)
  1468. //
  1469. if ( pagedConnection->SessionTable.Table[0].Owner != NULL ) {
  1470. IF_DEBUG(ERRORS) {
  1471. SrvPrint0( "BlockingSessionSetupAndX: Core client already has session.\n" );
  1472. }
  1473. status = STATUS_SMB_TOO_MANY_UIDS;
  1474. goto error_exit;
  1475. }
  1476. //
  1477. // Use location 0 of the session table.
  1478. //
  1479. IF_SMB_DEBUG(ADMIN2) {
  1480. SrvPrint0( "Client LM 1.0 or before--using location 0 of session table.\n" );
  1481. }
  1482. uidIndex = 0;
  1483. }
  1484. //
  1485. // Remove the UID slot from the free list and set its owner and
  1486. // sequence number. Create a UID for the session. Increment count
  1487. // of sessions.
  1488. //
  1489. entry = &pagedConnection->SessionTable.Table[uidIndex];
  1490. pagedConnection->SessionTable.FirstFreeEntry = entry->NextFreeEntry;
  1491. DEBUG entry->NextFreeEntry = -2;
  1492. if ( pagedConnection->SessionTable.LastFreeEntry == uidIndex ) {
  1493. pagedConnection->SessionTable.LastFreeEntry = -1;
  1494. }
  1495. INCREMENT_UID_SEQUENCE( entry->SequenceNumber );
  1496. if ( uidIndex == 0 && entry->SequenceNumber == 0 ) {
  1497. INCREMENT_UID_SEQUENCE( entry->SequenceNumber );
  1498. }
  1499. session->Uid = MAKE_UID( uidIndex, entry->SequenceNumber );
  1500. entry->Owner = session;
  1501. pagedConnection->CurrentNumberOfSessions++;
  1502. IF_SMB_DEBUG(ADMIN1) {
  1503. SrvPrint2( "Found UID. Index = 0x%lx, sequence = 0x%lx\n",
  1504. UID_INDEX( session->Uid ),
  1505. UID_SEQUENCE( session->Uid ) );
  1506. }
  1507. //
  1508. // Insert the session on the global session list.
  1509. //
  1510. SrvInsertEntryOrderedList( &SrvSessionList, session );
  1511. //
  1512. // Reference the connection block to account for the new session.
  1513. //
  1514. SrvReferenceConnection( connection );
  1515. session->Connection = connection;
  1516. RELEASE_LOCK( &connection->Lock );
  1517. RELEASE_LOCK( SrvSessionList.Lock );
  1518. //
  1519. // Session successfully created. Insert the session in the global
  1520. // list of active sessions. Remember its address in the work
  1521. // context block.
  1522. //
  1523. // *** Note that the reference count on the session block is
  1524. // initially set to 2, to allow for the active status on the
  1525. // block and the pointer that we're maintaining. In other
  1526. // words, this is a referenced pointer, and the pointer must be
  1527. // dereferenced when processing of this SMB is complete.
  1528. //
  1529. WorkContext->Session = session;
  1530. }
  1531. //
  1532. // Build response SMB, making sure to save request fields first in
  1533. // case the response overwrites the request. Save the
  1534. // newly-assigned UID in both the request SMB and the response SMB
  1535. // so that subsequent command processors and the client,
  1536. // respectively, can see it.
  1537. //
  1538. nextCommand = request->AndXCommand;
  1539. reqAndXOffset = SmbGetUshort( &request->AndXOffset );
  1540. SmbPutAlignedUshort( &WorkContext->RequestHeader->Uid, session->Uid );
  1541. SmbPutAlignedUshort( &WorkContext->ResponseHeader->Uid, session->Uid );
  1542. if (isExtendedSecurity) {
  1543. BuildExtendedSessionSetupAndXResponse(
  1544. WorkContext,
  1545. returnBufferLength,
  1546. status,
  1547. nextCommand,
  1548. isUnicode);
  1549. } else {
  1550. BuildSessionSetupAndXResponse(
  1551. WorkContext,
  1552. nextCommand,
  1553. action,
  1554. isUnicode);
  1555. }
  1556. WorkContext->ResponseParameters = (PCHAR)WorkContext->ResponseHeader +
  1557. SmbGetUshort( &response->AndXOffset );
  1558. //
  1559. // Test for legal followon command.
  1560. //
  1561. switch ( nextCommand ) {
  1562. case SMB_COM_NO_ANDX_COMMAND:
  1563. break;
  1564. case SMB_COM_TREE_CONNECT_ANDX:
  1565. case SMB_COM_OPEN:
  1566. case SMB_COM_OPEN_ANDX:
  1567. case SMB_COM_CREATE:
  1568. case SMB_COM_CREATE_NEW:
  1569. case SMB_COM_CREATE_DIRECTORY:
  1570. case SMB_COM_DELETE:
  1571. case SMB_COM_DELETE_DIRECTORY:
  1572. case SMB_COM_FIND:
  1573. case SMB_COM_FIND_UNIQUE:
  1574. case SMB_COM_COPY:
  1575. case SMB_COM_RENAME:
  1576. case SMB_COM_NT_RENAME:
  1577. case SMB_COM_CHECK_DIRECTORY:
  1578. case SMB_COM_QUERY_INFORMATION:
  1579. case SMB_COM_SET_INFORMATION:
  1580. case SMB_COM_QUERY_INFORMATION_SRV:
  1581. case SMB_COM_OPEN_PRINT_FILE:
  1582. case SMB_COM_GET_PRINT_QUEUE:
  1583. case SMB_COM_TRANSACTION:
  1584. //
  1585. // Make sure the AndX command is still within the received SMB
  1586. //
  1587. if( (PCHAR)WorkContext->RequestHeader + reqAndXOffset <=
  1588. END_OF_REQUEST_SMB( WorkContext ) ) {
  1589. break;
  1590. }
  1591. /* Falls Through */
  1592. default: // Illegal followon command
  1593. IF_DEBUG(SMB_ERRORS) {
  1594. SrvPrint1( "BlockingSessionSetupAndX: Illegal followon command: "
  1595. "0x%lx\n", nextCommand );
  1596. }
  1597. status = STATUS_INVALID_SMB;
  1598. goto error_exit1;
  1599. }
  1600. //
  1601. // If there is an AndX command, set up to process it. Otherwise,
  1602. // indicate completion to the caller.
  1603. //
  1604. if ( nextCommand != SMB_COM_NO_ANDX_COMMAND ) {
  1605. WorkContext->NextCommand = nextCommand;
  1606. WorkContext->RequestParameters = (PCHAR)WorkContext->RequestHeader +
  1607. reqAndXOffset;
  1608. SrvProcessSmb( WorkContext );
  1609. SmbStatus = SmbStatusNoResponse;
  1610. goto Cleanup;
  1611. }
  1612. IF_DEBUG(TRACE2) SrvPrint0( "BlockingSessionSetupAndX complete.\n" );
  1613. goto normal_exit;
  1614. error_exit:
  1615. if ( locksHeld ) {
  1616. RELEASE_LOCK( &connection->Lock );
  1617. RELEASE_LOCK( SrvSessionList.Lock );
  1618. }
  1619. if ( session != NULL ) {
  1620. if( WorkContext->Session ) {
  1621. //
  1622. // A re-validation of the session failed, or the extended exchange
  1623. // of security blobs failed. Get rid of this user.
  1624. //
  1625. SrvCloseSession( session );
  1626. SrvStatistics.SessionsLoggedOff++;
  1627. //
  1628. // Dereference the session, since it's no longer valid
  1629. //
  1630. SrvDereferenceSession( session );
  1631. WorkContext->Session = NULL;
  1632. } else {
  1633. SrvFreeSession( session );
  1634. }
  1635. }
  1636. if ( !isUnicode ) {
  1637. if ( domainString.Buffer != NULL ) {
  1638. RtlFreeUnicodeString( &domainString );
  1639. }
  1640. if ( nameString.Buffer != NULL ) {
  1641. RtlFreeUnicodeString( &nameString );
  1642. }
  1643. }
  1644. error_exit1:
  1645. SrvSetSmbError( WorkContext, status );
  1646. normal_exit:
  1647. SrvEndSmbProcessing( WorkContext, SmbStatusSendResponse );
  1648. SmbStatus = SmbStatusSendResponse;
  1649. Cleanup:
  1650. SrvWmiEndContext(WorkContext);
  1651. return;
  1652. } // BlockingSessionSetupAndX
  1653. NTSTATUS
  1654. GetExtendedSecurityParameters(
  1655. IN PWORK_CONTEXT WorkContext,
  1656. OUT PUCHAR *SecurityBuffer,
  1657. OUT PULONG SecurityBufferLength,
  1658. OUT PCHAR *RestOfDataBuffer,
  1659. OUT PULONG RestOfDataLength)
  1660. /*++
  1661. Routine Description:
  1662. Extracts the extensible security parameters from an extended session
  1663. setup and X SMB.
  1664. Arguments:
  1665. WorkContext - Context of the SMB
  1666. SecurityBuffer - On return, points to the security buffer inside the
  1667. extended session setup and X SMB
  1668. SecurityBufferLength - On return, size in bytes of SecurityBuffer.
  1669. RestOfDataBuffer - On return, points just past the security buffer
  1670. ResetOfDataLength - On return, size in bytes of *RestOfDataBuffer
  1671. Return Value:
  1672. STATUS_SUCCESS - This routine merely returns pointers within an SMB
  1673. --*/
  1674. {
  1675. NTSTATUS status;
  1676. PCONNECTION connection;
  1677. PREQ_NT_EXTENDED_SESSION_SETUP_ANDX ntExtendedRequest;
  1678. ULONG maxlength;
  1679. connection = WorkContext->Connection;
  1680. ASSERT( connection->SmbDialect <= SmbDialectNtLanMan );
  1681. ntExtendedRequest = (PREQ_NT_EXTENDED_SESSION_SETUP_ANDX)
  1682. (WorkContext->RequestParameters);
  1683. maxlength = (ULONG)(WorkContext->RequestBuffer->DataLength + sizeof( USHORT ) -
  1684. ((ULONG_PTR)ntExtendedRequest->Buffer -
  1685. (ULONG_PTR)WorkContext->RequestBuffer->Buffer));
  1686. //
  1687. // Get the extended security buffer
  1688. //
  1689. *SecurityBuffer = (PUCHAR) ntExtendedRequest->Buffer;
  1690. *SecurityBufferLength = ntExtendedRequest->SecurityBlobLength;
  1691. *RestOfDataBuffer = ntExtendedRequest->Buffer +
  1692. ntExtendedRequest->SecurityBlobLength;
  1693. *RestOfDataLength = (USHORT)( (PUCHAR)ntExtendedRequest->Buffer +
  1694. sizeof(USHORT) +
  1695. SmbGetUshort( &ntExtendedRequest->ByteCount) -
  1696. (*RestOfDataBuffer)
  1697. );
  1698. if( *SecurityBufferLength > maxlength ||
  1699. *RestOfDataLength > maxlength - *SecurityBufferLength ) {
  1700. IF_DEBUG(SMB_ERRORS) {
  1701. KdPrint(( "GetExtendedSecurityParameters: Invalid security buffer\n" ));
  1702. }
  1703. return STATUS_INVALID_SMB;
  1704. }
  1705. return( STATUS_SUCCESS );
  1706. }
  1707. NTSTATUS
  1708. GetNtSecurityParameters(
  1709. IN PWORK_CONTEXT WorkContext,
  1710. OUT PCHAR *CaseSensitivePassword,
  1711. OUT PULONG CaseSensitivePasswordLength,
  1712. OUT PCHAR *CaseInsensitivePassword,
  1713. OUT PULONG CaseInsensitivePasswordLength,
  1714. OUT PUNICODE_STRING UserName,
  1715. OUT PUNICODE_STRING DomainName,
  1716. OUT PCHAR *RestOfDataBuffer,
  1717. OUT PULONG RestOfDataLength)
  1718. {
  1719. NTSTATUS status = STATUS_SUCCESS;
  1720. PCONNECTION connection;
  1721. PREQ_NT_SESSION_SETUP_ANDX ntRequest;
  1722. PREQ_SESSION_SETUP_ANDX request;
  1723. PSZ userName;
  1724. USHORT nameLength;
  1725. BOOLEAN isUnicode;
  1726. connection = WorkContext->Connection;
  1727. ntRequest = (PREQ_NT_SESSION_SETUP_ANDX)(WorkContext->RequestParameters);
  1728. request = (PREQ_SESSION_SETUP_ANDX)(WorkContext->RequestParameters);
  1729. //
  1730. // Get the account name, and additional information from the SMB buffer.
  1731. //
  1732. if ( connection->SmbDialect <= SmbDialectNtLanMan) {
  1733. //
  1734. // The NT-NT SMB protocol passes both case sensitive (Unicode,
  1735. // mixed case) and case insensitive (ANSI, uppercased) passwords.
  1736. // Get pointers to them to pass to SrvValidateUser.
  1737. //
  1738. *CaseInsensitivePasswordLength =
  1739. (CLONG)SmbGetUshort(&ntRequest->CaseInsensitivePasswordLength);
  1740. *CaseInsensitivePassword = (PCHAR)(ntRequest->Buffer);
  1741. *CaseSensitivePasswordLength =
  1742. (CLONG)SmbGetUshort( &ntRequest->CaseSensitivePasswordLength );
  1743. *CaseSensitivePassword =
  1744. *CaseInsensitivePassword + *CaseInsensitivePasswordLength;
  1745. userName = (PSZ)(*CaseSensitivePassword +
  1746. *CaseSensitivePasswordLength);
  1747. } else {
  1748. //
  1749. // Downlevel clients do not pass the case sensitive password;
  1750. // just get the case insensitive password and use NULL as the
  1751. // case sensitive password. LSA will do the right thing with
  1752. // it.
  1753. //
  1754. *CaseInsensitivePasswordLength =
  1755. (CLONG)SmbGetUshort( &request->PasswordLength );
  1756. *CaseInsensitivePassword = (PCHAR)request->Buffer;
  1757. *CaseSensitivePasswordLength = 0;
  1758. *CaseSensitivePassword = NULL;
  1759. userName = (PSZ)(request->Buffer + *CaseInsensitivePasswordLength);
  1760. }
  1761. if( (*CaseInsensitivePassword) != NULL &&
  1762. (*CaseInsensitivePassword) + (*CaseInsensitivePasswordLength) >
  1763. END_OF_REQUEST_SMB( WorkContext ) ) {
  1764. status = STATUS_INVALID_SMB;
  1765. goto error_exit;
  1766. }
  1767. if( (*CaseSensitivePassword) != NULL &&
  1768. (*CaseSensitivePassword) + (*CaseSensitivePasswordLength) >
  1769. END_OF_REQUEST_SMB( WorkContext ) ) {
  1770. status = STATUS_INVALID_SMB;
  1771. goto error_exit;
  1772. }
  1773. isUnicode = SMB_IS_UNICODE( WorkContext );
  1774. if ( isUnicode ) {
  1775. userName = ALIGN_SMB_WSTR( userName );
  1776. }
  1777. nameLength = SrvGetStringLength(
  1778. userName,
  1779. END_OF_REQUEST_SMB( WorkContext ),
  1780. isUnicode,
  1781. FALSE // don't include null terminator
  1782. );
  1783. if ( nameLength == (USHORT)-1 ) {
  1784. status = STATUS_INVALID_SMB;
  1785. goto error_exit;
  1786. }
  1787. status = SrvMakeUnicodeString(
  1788. isUnicode,
  1789. UserName,
  1790. userName,
  1791. &nameLength );
  1792. if ( !NT_SUCCESS( status ) ) {
  1793. goto error_exit;
  1794. }
  1795. //
  1796. // If client information strings exists, extract the information
  1797. // from the SMB buffer.
  1798. //
  1799. if ( connection->SmbDialect <= SmbDialectDosLanMan21) {
  1800. PCHAR smbInformation;
  1801. USHORT length;
  1802. PWCH infoBuffer;
  1803. smbInformation = userName + nameLength +
  1804. ( isUnicode ? sizeof( WCHAR ) : 1 );
  1805. //
  1806. // Now copy the strings to the allocated buffer.
  1807. //
  1808. if ( isUnicode ) {
  1809. smbInformation = ALIGN_SMB_WSTR( smbInformation );
  1810. }
  1811. length = SrvGetStringLength(
  1812. smbInformation,
  1813. END_OF_REQUEST_SMB( WorkContext ),
  1814. isUnicode,
  1815. FALSE // don't include null terminator
  1816. );
  1817. if ( length == (USHORT)-1) {
  1818. status = STATUS_INVALID_SMB;
  1819. goto error_exit;
  1820. }
  1821. //
  1822. // DOS clients send an empty domain name if they don't know
  1823. // their domain name (e.g., during logon). OS/2 clients send
  1824. // a name of "?". This confuses the LSA. Convert such a name
  1825. // to an empty name.
  1826. //
  1827. if ( isUnicode ) {
  1828. if ( (length == sizeof(WCHAR)) &&
  1829. (*(PWCH)smbInformation == '?') ) {
  1830. length = 0;
  1831. }
  1832. } else {
  1833. if ( (length == 1) && (*smbInformation == '?') ) {
  1834. length = 0;
  1835. }
  1836. }
  1837. status = SrvMakeUnicodeString(
  1838. isUnicode,
  1839. DomainName,
  1840. smbInformation,
  1841. &length
  1842. );
  1843. if ( !NT_SUCCESS( status ) ) {
  1844. goto error_exit;
  1845. }
  1846. smbInformation += length + ( isUnicode ? sizeof(WCHAR) : 1 );
  1847. *RestOfDataBuffer = smbInformation;
  1848. if (connection->SmbDialect <= SmbDialectNtLanMan) {
  1849. *RestOfDataLength = (USHORT) ( (PUCHAR)&ntRequest->ByteCount +
  1850. sizeof(USHORT) +
  1851. SmbGetUshort(&ntRequest->ByteCount) -
  1852. smbInformation
  1853. );
  1854. } else {
  1855. PREQ_SESSION_SETUP_ANDX request;
  1856. request = (PREQ_SESSION_SETUP_ANDX)(WorkContext->RequestParameters);
  1857. *RestOfDataLength = (USHORT) ( (PUCHAR)&request->ByteCount +
  1858. sizeof(USHORT) +
  1859. SmbGetUshort(&request->ByteCount) -
  1860. smbInformation
  1861. );
  1862. }
  1863. } else {
  1864. DomainName->Length = 0;
  1865. *RestOfDataBuffer = NULL;
  1866. *RestOfDataLength = 0;
  1867. }
  1868. error_exit:
  1869. return( status );
  1870. }
  1871. VOID
  1872. BuildExtendedSessionSetupAndXResponse(
  1873. IN PWORK_CONTEXT WorkContext,
  1874. IN ULONG ReturnBufferLength,
  1875. IN NTSTATUS Status,
  1876. IN UCHAR NextCommand,
  1877. IN BOOLEAN IsUnicode)
  1878. {
  1879. PRESP_NT_EXTENDED_SESSION_SETUP_ANDX ntExtendedResponse;
  1880. PCHAR buffer;
  1881. USHORT byteCount;
  1882. ntExtendedResponse = (PRESP_NT_EXTENDED_SESSION_SETUP_ANDX)
  1883. (WorkContext->ResponseParameters);
  1884. ntExtendedResponse->WordCount = 4;
  1885. ntExtendedResponse->AndXCommand = NextCommand;
  1886. ntExtendedResponse->AndXReserved = 0;
  1887. if( WorkContext->Session && WorkContext->Session->GuestLogon ) {
  1888. SmbPutUshort( &ntExtendedResponse->Action, SMB_SETUP_GUEST );
  1889. } else {
  1890. SmbPutUshort( &ntExtendedResponse->Action, 0 );
  1891. }
  1892. SmbPutUshort( &ntExtendedResponse->SecurityBlobLength,(USHORT)ReturnBufferLength );
  1893. buffer = ntExtendedResponse->Buffer + ReturnBufferLength;
  1894. if (IsUnicode)
  1895. buffer = ALIGN_SMB_WSTR( buffer );
  1896. InsertNativeOSAndType( IsUnicode, buffer, &byteCount );
  1897. byteCount += (USHORT)ReturnBufferLength;
  1898. SmbPutUshort( &ntExtendedResponse->ByteCount, byteCount );
  1899. SmbPutUshort( &ntExtendedResponse->AndXOffset, GET_ANDX_OFFSET(
  1900. WorkContext->ResponseHeader,
  1901. WorkContext->ResponseParameters,
  1902. RESP_NT_EXTENDED_SESSION_SETUP_ANDX,
  1903. byteCount
  1904. ) );
  1905. //
  1906. // Make sure we return the error status here, as the client uses it to
  1907. // determine if extra round trips are necessary
  1908. //
  1909. SrvSetSmbError2 ( WorkContext, Status, TRUE );
  1910. }
  1911. VOID
  1912. BuildSessionSetupAndXResponse(
  1913. IN PWORK_CONTEXT WorkContext,
  1914. IN UCHAR NextCommand,
  1915. IN USHORT Action,
  1916. IN BOOLEAN IsUnicode)
  1917. {
  1918. PRESP_SESSION_SETUP_ANDX response;
  1919. PCONNECTION connection;
  1920. PENDPOINT endpoint;
  1921. PCHAR buffer;
  1922. USHORT byteCount;
  1923. response = (PRESP_SESSION_SETUP_ANDX) (WorkContext->ResponseParameters);
  1924. connection = WorkContext->Connection;
  1925. endpoint = connection->Endpoint;
  1926. response->WordCount = 3;
  1927. response->AndXCommand = NextCommand;
  1928. response->AndXReserved = 0;
  1929. if (connection->SmbDialect <= SmbDialectDosLanMan21) {
  1930. buffer = response->Buffer;
  1931. if (IsUnicode)
  1932. buffer = ALIGN_SMB_WSTR( buffer );
  1933. InsertNativeOSAndType( IsUnicode, buffer, &byteCount );
  1934. buffer = buffer + byteCount;
  1935. if (connection->SmbDialect <= SmbDialectNtLanMan) {
  1936. USHORT stringLength;
  1937. if ( IsUnicode ) {
  1938. buffer = ALIGN_SMB_WSTR( buffer );
  1939. stringLength = endpoint->DomainName.Length + sizeof(UNICODE_NULL);
  1940. RtlCopyMemory(
  1941. buffer,
  1942. endpoint->DomainName.Buffer,
  1943. stringLength
  1944. );
  1945. byteCount += (USHORT)stringLength;
  1946. } else {
  1947. stringLength = endpoint->OemDomainName.Length + sizeof(CHAR);
  1948. RtlCopyMemory(
  1949. (PVOID) buffer,
  1950. endpoint->OemDomainName.Buffer,
  1951. stringLength
  1952. );
  1953. byteCount += (USHORT)stringLength;
  1954. }
  1955. }
  1956. } else {
  1957. byteCount = 0;
  1958. }
  1959. SmbPutUshort( &response->ByteCount, byteCount );
  1960. //
  1961. // Normally, turning on bit 0 of Action indicates that the user was
  1962. // logged on as GUEST. However, NT does not have automatic guest
  1963. // logon--a user ID and password are required for every single logon
  1964. // (though the password may have null length). Therefore, the
  1965. // server need not concern itself with what kind of account the
  1966. // client gets.
  1967. //
  1968. // Bit 1 tells the client that the user was logged on
  1969. // using the lm session key instead of the user session key.
  1970. //
  1971. SmbPutUshort( &response->Action, Action );
  1972. SmbPutUshort( &response->AndXOffset, GET_ANDX_OFFSET(
  1973. WorkContext->ResponseHeader,
  1974. WorkContext->ResponseParameters,
  1975. RESP_SESSION_SETUP_ANDX,
  1976. byteCount
  1977. ) );
  1978. }
  1979. VOID
  1980. InsertNativeOSAndType(
  1981. IN BOOLEAN IsUnicode,
  1982. OUT PCHAR Buffer,
  1983. OUT PUSHORT ByteCount)
  1984. {
  1985. USHORT stringLength;
  1986. if ( IsUnicode ) {
  1987. stringLength = (USHORT)(SrvNativeOS.Length + sizeof(UNICODE_NULL));
  1988. RtlCopyMemory(
  1989. Buffer,
  1990. SrvNativeOS.Buffer,
  1991. stringLength
  1992. );
  1993. *ByteCount = stringLength;
  1994. stringLength = SrvNativeLanMan.Length + sizeof(UNICODE_NULL);
  1995. RtlCopyMemory(
  1996. (PCHAR)Buffer + *ByteCount,
  1997. SrvNativeLanMan.Buffer,
  1998. stringLength
  1999. );
  2000. *ByteCount += (USHORT)stringLength;
  2001. } else {
  2002. stringLength = SrvOemNativeOS.Length + sizeof(CHAR);
  2003. RtlCopyMemory(
  2004. Buffer,
  2005. SrvOemNativeOS.Buffer,
  2006. stringLength
  2007. );
  2008. *ByteCount = stringLength;
  2009. stringLength = SrvOemNativeLanMan.Length + sizeof(CHAR);
  2010. RtlCopyMemory(
  2011. (PCHAR)Buffer + *ByteCount,
  2012. SrvOemNativeLanMan.Buffer,
  2013. stringLength
  2014. );
  2015. *ByteCount += (USHORT)stringLength;
  2016. }
  2017. }
  2018. SMB_PROCESSOR_RETURN_TYPE
  2019. SrvSmbLogoffAndX (
  2020. SMB_PROCESSOR_PARAMETERS
  2021. )
  2022. /*++
  2023. Routine Description:
  2024. Processes a Logoff and X SMB.
  2025. Arguments:
  2026. SMB_PROCESSOR_PARAMETERS - See smbprocs.h for a description
  2027. of the parameters to SMB processor routines.
  2028. Return Value:
  2029. SMB_PROCESSOR_RETURN_TYPE - See smbprocs.h
  2030. --*/
  2031. {
  2032. PREQ_LOGOFF_ANDX request;
  2033. PRESP_LOGOFF_ANDX response;
  2034. PSESSION session;
  2035. USHORT reqAndXOffset;
  2036. UCHAR nextCommand;
  2037. NTSTATUS status = STATUS_SUCCESS;
  2038. SMB_STATUS SmbStatus = SmbStatusInProgress;
  2039. PAGED_CODE( );
  2040. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  2041. WorkContext->PreviousSMB = EVENT_TYPE_SMB_LOGOFF_AND_X;
  2042. SrvWmiStartContext(WorkContext);
  2043. IF_SMB_DEBUG(ADMIN1) {
  2044. SrvPrint2( "Logoff request header at 0x%p, response header at 0x%p\n",
  2045. WorkContext->RequestHeader, WorkContext->ResponseHeader );
  2046. SrvPrint2( "Logoff request parameters at 0x%p, response parameters at 0x%p\n",
  2047. WorkContext->RequestParameters,
  2048. WorkContext->ResponseParameters );
  2049. }
  2050. //
  2051. // Set up parameters.
  2052. //
  2053. request = (PREQ_LOGOFF_ANDX)(WorkContext->RequestParameters);
  2054. response = (PRESP_LOGOFF_ANDX)(WorkContext->ResponseParameters);
  2055. //
  2056. // If a session block has not already been assigned to the current
  2057. // work context, verify the UID. If verified, the address of the
  2058. // session block corresponding to this user is stored in the
  2059. // WorkContext block and the session block is referenced.
  2060. //
  2061. session = SrvVerifyUid(
  2062. WorkContext,
  2063. SmbGetAlignedUshort( &WorkContext->RequestHeader->Uid )
  2064. );
  2065. if ( session == NULL ) {
  2066. IF_DEBUG(SMB_ERRORS) {
  2067. SrvPrint1( "SrvSmbLogoffAndX: Invalid UID: 0x%lx\n",
  2068. SmbGetAlignedUshort( &WorkContext->RequestHeader->Uid ) );
  2069. }
  2070. SrvSetSmbError( WorkContext, STATUS_SMB_BAD_UID );
  2071. status = STATUS_SMB_BAD_UID;
  2072. SmbStatus = SmbStatusSendResponse;
  2073. goto Cleanup;
  2074. }
  2075. //
  2076. // If we need to visit the license server, get over to a blocking
  2077. // thread to ensure that we don't consume the nonblocking threads
  2078. //
  2079. if( WorkContext->UsingBlockingThread == 0 &&
  2080. session->IsLSNotified == TRUE ) {
  2081. //
  2082. // Insert the work item at the tail of the blocking work queue
  2083. //
  2084. SrvInsertWorkQueueTail(
  2085. &SrvBlockingWorkQueue,
  2086. (PQUEUEABLE_BLOCK_HEADER)WorkContext
  2087. );
  2088. SmbStatus = SmbStatusInProgress;
  2089. goto Cleanup;
  2090. }
  2091. //
  2092. // Do the actual logoff.
  2093. //
  2094. SrvCloseSession( session );
  2095. SrvStatistics.SessionsLoggedOff++;
  2096. //
  2097. // Dereference the session, since it's no longer valid, but we may
  2098. // end up processing a chained command. Clear the session pointer
  2099. // in the work context block to indicate that we've done this.
  2100. //
  2101. SrvDereferenceSession( session );
  2102. WorkContext->Session = NULL;
  2103. //
  2104. // Build the response SMB, making sure to save request fields first
  2105. // in case the response overwrites the request.
  2106. //
  2107. reqAndXOffset = SmbGetUshort( &request->AndXOffset );
  2108. nextCommand = request->AndXCommand;
  2109. response->WordCount = 2;
  2110. response->AndXCommand = request->AndXCommand;
  2111. response->AndXReserved = 0;
  2112. SmbPutUshort( &response->AndXOffset, GET_ANDX_OFFSET(
  2113. WorkContext->ResponseHeader,
  2114. WorkContext->ResponseParameters,
  2115. RESP_LOGOFF_ANDX,
  2116. 0
  2117. ) );
  2118. SmbPutUshort( &response->ByteCount, 0 );
  2119. WorkContext->ResponseParameters = (PCHAR)WorkContext->ResponseHeader +
  2120. SmbGetUshort( &response->AndXOffset );
  2121. //
  2122. // Test for legal followon command.
  2123. //
  2124. switch ( nextCommand ) {
  2125. case SMB_COM_NO_ANDX_COMMAND:
  2126. break;
  2127. case SMB_COM_SESSION_SETUP_ANDX:
  2128. //
  2129. // Make sure the AndX command is still within the received SMB
  2130. //
  2131. if( (PCHAR)WorkContext->RequestHeader + reqAndXOffset <=
  2132. END_OF_REQUEST_SMB( WorkContext ) ) {
  2133. break;
  2134. }
  2135. /* Falls Through */
  2136. default:
  2137. IF_DEBUG(SMB_ERRORS) {
  2138. SrvPrint1( "SrvSmbLogoffAndX: Illegal followon command: 0x%lx\n",
  2139. nextCommand );
  2140. }
  2141. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  2142. status = STATUS_INVALID_SMB;
  2143. SmbStatus = SmbStatusSendResponse;
  2144. goto Cleanup;
  2145. }
  2146. //
  2147. // If there is an AndX command, set up to process it. Otherwise,
  2148. // indicate completion to the caller.
  2149. //
  2150. if ( nextCommand != SMB_COM_NO_ANDX_COMMAND ) {
  2151. WorkContext->NextCommand = nextCommand;
  2152. WorkContext->RequestParameters = (PCHAR)WorkContext->RequestHeader +
  2153. reqAndXOffset;
  2154. SmbStatus = SmbStatusMoreCommands;
  2155. goto Cleanup;
  2156. }
  2157. SmbStatus = SmbStatusSendResponse;
  2158. IF_DEBUG(TRACE2) SrvPrint0( "SrvSmbLogoffAndX complete.\n" );
  2159. Cleanup:
  2160. SrvWmiEndContext(WorkContext);
  2161. return SmbStatus;
  2162. } // SrvSmbLogoffAndX
  2163. STATIC
  2164. VOID
  2165. GetEncryptionKey (
  2166. OUT CHAR EncryptionKey[MSV1_0_CHALLENGE_LENGTH]
  2167. )
  2168. /*++
  2169. Routine Description:
  2170. Creates an encryption key to use as a challenge for a logon.
  2171. *** Although the MSV1_0 authentication package has a function that
  2172. returns an encryption key, we do not use that function in order
  2173. to avoid a trip through LPC and into LSA.
  2174. Arguments:
  2175. EncryptionKey - a pointer to a buffer which receives the encryption
  2176. key.
  2177. Return Value:
  2178. NTSTATUS - result of operation.
  2179. --*/
  2180. {
  2181. union {
  2182. LARGE_INTEGER time;
  2183. UCHAR bytes[8];
  2184. } u;
  2185. ULONG seed;
  2186. ULONG challenge[2];
  2187. ULONG result3;
  2188. //
  2189. // Create a pseudo-random 8-byte number by munging the system time
  2190. // for use as a random number seed.
  2191. //
  2192. // Start by getting the system time.
  2193. //
  2194. ASSERT( MSV1_0_CHALLENGE_LENGTH == 2 * sizeof(ULONG) );
  2195. KeQuerySystemTime( &u.time );
  2196. //
  2197. // To ensure that we don't use the same system time twice, add in the
  2198. // count of the number of times this routine has been called. Then
  2199. // increment the counter.
  2200. //
  2201. // *** Since we don't use the low byte of the system time (it doesn't
  2202. // take on enough different values, because of the timer
  2203. // resolution), we increment the counter by 0x100.
  2204. //
  2205. // *** We don't interlock the counter because we don't really care
  2206. // if it's not 100% accurate.
  2207. //
  2208. u.time.LowPart += EncryptionKeyCount;
  2209. EncryptionKeyCount += 0x100;
  2210. //
  2211. // Now use parts of the system time as a seed for the random
  2212. // number generator.
  2213. //
  2214. // *** Because the middle two bytes of the low part of the system
  2215. // time change most rapidly, we use those in forming the seed.
  2216. //
  2217. seed = ((u.bytes[1] + 1) << 0) |
  2218. ((u.bytes[2] + 0) << 8) |
  2219. ((u.bytes[2] - 1) << 16) |
  2220. ((u.bytes[1] + 0) << 24);
  2221. //
  2222. // Now get two random numbers. RtlRandom does not return negative
  2223. // numbers, so we pseudo-randomly negate them.
  2224. //
  2225. challenge[0] = RtlRandom( &seed );
  2226. challenge[1] = RtlRandom( &seed );
  2227. result3 = RtlRandom( &seed );
  2228. if ( (result3 & 0x1) != 0 ) {
  2229. challenge[0] |= 0x80000000;
  2230. }
  2231. if ( (result3 & 0x2) != 0 ) {
  2232. challenge[1] |= 0x80000000;
  2233. }
  2234. //
  2235. // Return the challenge.
  2236. //
  2237. RtlCopyMemory( EncryptionKey, challenge, MSV1_0_CHALLENGE_LENGTH );
  2238. } // GetEncryptionKey