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

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