Windows NT 4.0 source code leak
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.

2657 lines
74 KiB

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