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.

2070 lines
62 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. smbtree.c
  5. Abstract:
  6. This module contains routines for dealing with tree connects and
  7. disconnects:
  8. Tree Connect
  9. Tree Connect And X
  10. Tree Disconnect
  11. Author:
  12. David Treadwell (davidtr) 15-Nov-1989
  13. Revision History:
  14. --*/
  15. #include "precomp.h"
  16. #include "smbtree.tmh"
  17. #pragma hdrstop
  18. #ifdef ALLOC_PRAGMA
  19. #pragma alloc_text( PAGE, SrvSmbTreeConnect )
  20. #pragma alloc_text( PAGE, SrvSmbTreeConnectAndX )
  21. #pragma alloc_text( PAGE, SrvSmbTreeDisconnect )
  22. #endif
  23. SMB_PROCESSOR_RETURN_TYPE
  24. SrvSmbTreeConnect (
  25. SMB_PROCESSOR_PARAMETERS
  26. )
  27. /*++
  28. Routine Description:
  29. Processes a tree connect SMB.
  30. Arguments:
  31. SMB_PROCESSOR_PARAMETERS - See smbprocs.h for a description
  32. of the parameters to SMB processor routines.
  33. Return Value:
  34. SMB_PROCESSOR_RETURN_TYPE - See smbprocs.h
  35. --*/
  36. {
  37. PREQ_TREE_CONNECT request;
  38. PRESP_TREE_CONNECT response;
  39. PSESSION session;
  40. PSECURITY_CONTEXT SecurityContext;
  41. PCONNECTION connection;
  42. PPAGED_CONNECTION pagedConnection;
  43. PTABLE_HEADER tableHeader;
  44. PTABLE_ENTRY entry;
  45. SHORT tidIndex;
  46. PSHARE share;
  47. PTREE_CONNECT treeConnect;
  48. PSZ password, service;
  49. USHORT len;
  50. NTSTATUS status = STATUS_SUCCESS;
  51. NTSTATUS TableStatus;
  52. SMB_STATUS SmbStatus = SmbStatusInProgress;
  53. BOOLEAN didLogon = FALSE;
  54. SHORT uidIndex;
  55. SMB_DIALECT smbDialect;
  56. PUNICODE_STRING clientMachineNameString;
  57. ACCESS_MASK desiredAccess;
  58. ACCESS_MASK grantedAccess;
  59. SECURITY_SUBJECT_CONTEXT subjectContext;
  60. UNICODE_STRING domain = { 0, 0, StrNull };
  61. PAGED_CODE( );
  62. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  63. WorkContext->PreviousSMB = EVENT_TYPE_SMB_TREE_CONNECT;
  64. SrvWmiStartContext(WorkContext);
  65. IF_SMB_DEBUG(TREE1) {
  66. KdPrint(( "Tree connect request header at 0x%p, response header at 0x%p\n",
  67. WorkContext->RequestHeader, WorkContext->ResponseHeader ));
  68. KdPrint(( "Tree connect request parameters at 0x%p, response parameters at 0x%p\n",
  69. WorkContext->RequestParameters,
  70. WorkContext->ResponseParameters ));
  71. }
  72. //
  73. // Set up parameters.
  74. //
  75. request = (PREQ_TREE_CONNECT)(WorkContext->RequestParameters);
  76. response = (PRESP_TREE_CONNECT)(WorkContext->ResponseParameters);
  77. connection = WorkContext->Connection;
  78. pagedConnection = connection->PagedConnection;
  79. smbDialect = connection->SmbDialect;
  80. // If we are requiring extended security signatures, than we can't let this through
  81. if( SrvRequireExtendedSignatures )
  82. {
  83. SrvSetSmbError( WorkContext, STATUS_LOGIN_WKSTA_RESTRICTION );
  84. status = STATUS_LOGIN_WKSTA_RESTRICTION;
  85. SmbStatus = SmbStatusSendResponse;
  86. goto Cleanup;
  87. }
  88. //
  89. // If this client has not yet done a session setup and this his first
  90. // tree connection then we must first do a logon. (i.e. SessionSetup)
  91. //
  92. len = SrvGetStringLength(
  93. (PSZ)request->Buffer,
  94. END_OF_REQUEST_SMB( WorkContext ),
  95. FALSE, // not unicode
  96. FALSE // do not include null terminator
  97. );
  98. if( len == (USHORT)-1 ) {
  99. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  100. status = STATUS_INVALID_SMB;
  101. SmbStatus = SmbStatusSendResponse;
  102. goto Cleanup;
  103. }
  104. password = (PSZ)request->Buffer + 2 + len;
  105. len = SrvGetStringLength(
  106. password,
  107. END_OF_REQUEST_SMB( WorkContext ),
  108. FALSE, // not unicode
  109. FALSE // do not include null terminator
  110. );
  111. if( len == (USHORT)-1 ) {
  112. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  113. status = STATUS_INVALID_SMB;
  114. SmbStatus = SmbStatusSendResponse;
  115. goto Cleanup;
  116. }
  117. service = password + (len + 1) + 1;
  118. //
  119. // Allocate a tree connect block. We do this early on the
  120. // assumption that the request will usually succeed. This also
  121. // reduces the amount of time that we hold the lock.
  122. //
  123. SrvAllocateTreeConnect( &treeConnect, NULL );
  124. if ( treeConnect == NULL ) {
  125. //
  126. // Unable to allocate tree connect. Return an error to the
  127. // client.
  128. //
  129. SrvSetSmbError( WorkContext, STATUS_INSUFF_SERVER_RESOURCES );
  130. status = STATUS_INSUFF_SERVER_RESOURCES;
  131. SmbStatus = SmbStatusSendResponse;
  132. goto Cleanup;
  133. }
  134. ASSERT( SrvSessionList.Lock == &SrvOrderedListLock );
  135. ACQUIRE_LOCK( &connection->Lock );
  136. if ( connection->CurrentNumberOfSessions != 0 ) {
  137. RELEASE_LOCK( &connection->Lock );
  138. session = SrvVerifyUid (
  139. WorkContext,
  140. SmbGetAlignedUshort( &WorkContext->RequestHeader->Uid )
  141. );
  142. if ( session == NULL ) {
  143. //
  144. // This should only happen if the client has already
  145. // established a session, as in tree connecting with a bad
  146. // UID.
  147. //
  148. SrvFreeTreeConnect( treeConnect );
  149. SrvSetSmbError( WorkContext, STATUS_SMB_BAD_UID );
  150. status = STATUS_SMB_BAD_UID;
  151. SmbStatus = SmbStatusSendResponse;
  152. goto Cleanup;
  153. }
  154. else if( session->IsSessionExpired )
  155. {
  156. SrvFreeTreeConnect( treeConnect );
  157. status = SESSION_EXPIRED_STATUS_CODE;
  158. SrvSetSmbError( WorkContext, status );
  159. SmbStatus = SmbStatusSendResponse;
  160. goto Cleanup;
  161. }
  162. } else if ( (smbDialect <= SmbDialectLanMan10) ||
  163. (smbDialect == SmbDialectIllegal) ) {
  164. //
  165. // An LM 1.0 or newer client has tried to do a tree connect
  166. // without first doing session setup. We call this a protocol
  167. // violation.
  168. //
  169. // Also catch clients that are trying to connect without
  170. // negotiating a valid protocol.
  171. //
  172. RELEASE_LOCK( &connection->Lock );
  173. IF_DEBUG(SMB_ERRORS) {
  174. if ( smbDialect == SmbDialectIllegal ) {
  175. KdPrint(("SrvSmbTreeConnect: Client %z is using an illegal "
  176. "dialect.\n", (PCSTRING)&connection->OemClientMachineNameString ));;
  177. } else {
  178. KdPrint(( "Client speaking dialect %ld sent tree connect without session setup.\n", connection->SmbDialect ));
  179. }
  180. }
  181. SrvFreeTreeConnect( treeConnect );
  182. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  183. status = STATUS_INVALID_SMB;
  184. SmbStatus = SmbStatusSendResponse;
  185. goto Cleanup;
  186. } else {
  187. UNICODE_STRING machineName;
  188. PENDPOINT endpoint;
  189. BOOLEAN seqNumbers;
  190. RELEASE_LOCK( &connection->Lock );
  191. //
  192. // Convert the client name to unicode
  193. //
  194. clientMachineNameString = &connection->ClientMachineNameString;
  195. if ( clientMachineNameString->Length == 0 ) {
  196. UNICODE_STRING clientMachineName;
  197. clientMachineName.Buffer = connection->ClientMachineName;
  198. clientMachineName.MaximumLength =
  199. (USHORT)(COMPUTER_NAME_LENGTH+1)*sizeof(WCHAR);
  200. (VOID)RtlOemStringToUnicodeString(
  201. &clientMachineName,
  202. &connection->OemClientMachineNameString,
  203. FALSE
  204. );
  205. //
  206. // Add the double backslashes to the length
  207. //
  208. clientMachineNameString->Length =
  209. (USHORT)(clientMachineName.Length + 2*sizeof(WCHAR));
  210. }
  211. //
  212. // Form a string describing the computer name without the
  213. // leading backslashes.
  214. //
  215. machineName.Buffer = clientMachineNameString->Buffer + 2;
  216. machineName.Length = clientMachineNameString->Length - 2 * sizeof(WCHAR);
  217. machineName.MaximumLength =
  218. clientMachineNameString->MaximumLength - 2 * sizeof(WCHAR);
  219. SecurityContext = SrvAllocateSecurityContext();
  220. if( SecurityContext == NULL )
  221. {
  222. SrvFreeTreeConnect( treeConnect );
  223. SrvSetSmbError( WorkContext, STATUS_INSUFF_SERVER_RESOURCES );
  224. status = STATUS_INSUFF_SERVER_RESOURCES;
  225. SmbStatus = SmbStatusSendResponse;
  226. goto Cleanup;
  227. }
  228. //
  229. // Allocate a session block.
  230. //
  231. SrvAllocateSession(
  232. &session,
  233. &machineName,
  234. &domain );
  235. if ( session == NULL ) {
  236. //
  237. // Unable to allocate a Session block. Return an error
  238. // status.
  239. //
  240. SrvDereferenceSecurityContext( SecurityContext );
  241. SrvFreeTreeConnect( treeConnect );
  242. SrvSetSmbError( WorkContext, STATUS_INSUFF_SERVER_RESOURCES );
  243. status = STATUS_INSUFF_SERVER_RESOURCES;
  244. SmbStatus = SmbStatusSendResponse;
  245. goto Cleanup;
  246. }
  247. //
  248. // Assume that down-level clients that are getting logged on
  249. // here will always use canonicalized (uppercase) paths. This
  250. // will result in case insensitivity for all operations.
  251. //
  252. session->UsingUppercasePaths = TRUE;
  253. //
  254. // The only way for a client to tell us the buffer size or the
  255. // max count of pending requests he wants to use is the Session
  256. // Setup SMB. If he didn't send one, then we get to
  257. // unilaterally determine the buffer size and multiplex count
  258. // used by both of us.
  259. //
  260. endpoint = connection->Endpoint;
  261. if ( endpoint->IsConnectionless ) {
  262. ULONG adapterNumber;
  263. //
  264. // Our session max buffer size is the smaller of the
  265. // server receive buffer size and the ipx transport
  266. // indicated max packet size.
  267. //
  268. adapterNumber =
  269. WorkContext->ClientAddress->DatagramOptions.LocalTarget.NicId;
  270. session->MaxBufferSize =
  271. (USHORT) GetIpxMaxBufferSize(
  272. endpoint,
  273. adapterNumber,
  274. SrvReceiveBufferLength
  275. );
  276. } else {
  277. session->MaxBufferSize = (USHORT)SrvReceiveBufferLength;
  278. }
  279. session->MaxMpxCount = SrvMaxMpxCount;
  280. if ( session->MaxMpxCount < 2 ) {
  281. connection->OplocksAlwaysDisabled = TRUE;
  282. }
  283. if( SrvSmbSecuritySignaturesRequired == TRUE &&
  284. WorkContext->Connection->Endpoint->IsConnectionless == FALSE ) {
  285. seqNumbers = TRUE;
  286. } else {
  287. seqNumbers = FALSE;
  288. }
  289. //
  290. // Try to find legitimate name/password combination.
  291. //
  292. status = SrvValidateUser(
  293. &SecurityContext->UserHandle,
  294. session,
  295. connection,
  296. &machineName,
  297. password,
  298. strlen( password ) + 1,
  299. NULL, // CaseSensitivePassword
  300. 0, // CaseSensitivePasswordLength
  301. seqNumbers,
  302. NULL // action
  303. );
  304. //
  305. // If a bad name/password combination was sent, return an error.
  306. //
  307. if ( !NT_SUCCESS(status) ) {
  308. SrvFreeSession( session );
  309. SrvFreeTreeConnect ( treeConnect );
  310. IF_DEBUG(ERRORS) {
  311. KdPrint(( "SrvSmbTreeConnect: Bad user/password combination.\n" ));
  312. }
  313. SrvStatistics.LogonErrors++;
  314. SrvSetSmbError( WorkContext, status );
  315. SmbStatus = SmbStatusSendResponse;
  316. goto Cleanup;
  317. }
  318. IF_SMB_DEBUG(ADMIN1) {
  319. KdPrint(( "Validated user: %ws\n",
  320. connection->ClientMachineName ));
  321. }
  322. //
  323. // Making a new session visible is a multiple-step operation. It
  324. // must be inserted in the global ordered tree connect list and the
  325. // containing connection's session table, and the connection must be
  326. // referenced. We need to make these operations appear atomic, so
  327. // that the session cannot be accessed elsewhere before we're done
  328. // setting it up. In order to do this, we hold all necessary locks
  329. // the entire time we're doing the operations. The first operation
  330. // is protected by the global ordered list lock
  331. // (SrvOrderedListLock), while the other operations are protected by
  332. // the per-connection lock. We take out the ordered list lock
  333. // first, then the connection lock. This ordering is required by
  334. // lock levels (see lock.h).
  335. //
  336. //
  337. // Ready to try to find a UID for the session. Check to see if
  338. // the connection is being closed, and if so, terminate this
  339. // operation.
  340. //
  341. ASSERT( SrvSessionList.Lock == &SrvOrderedListLock );
  342. ACQUIRE_LOCK( SrvSessionList.Lock );
  343. ACQUIRE_LOCK( &connection->Lock );
  344. // Set the Security Context now that we have the lock acquired
  345. SrvReplaceSessionSecurityContext( session, SecurityContext, WorkContext );
  346. if ( GET_BLOCK_STATE(connection) != BlockStateActive ) {
  347. RELEASE_LOCK( &connection->Lock );
  348. RELEASE_LOCK( SrvSessionList.Lock );
  349. IF_DEBUG(ERRORS) {
  350. KdPrint(( "SrvSmbTreeConnect: Connection closing\n" ));
  351. }
  352. SrvFreeSession( session );
  353. SrvFreeTreeConnect( treeConnect );
  354. SrvSetSmbError( WorkContext, STATUS_INVALID_PARAMETER );
  355. status = STATUS_INVALID_PARAMETER;
  356. SmbStatus = SmbStatusSendResponse;
  357. goto Cleanup;
  358. }
  359. //
  360. // Because the client is speaking the "core" dialect, it will
  361. // not send a valid UID in future SMBs, so it can only have one
  362. // session. We define that session to live in UID slot 0. We
  363. // know that the client has no sessions yet, so slot 0 must be
  364. // free.
  365. //
  366. tableHeader = &pagedConnection->SessionTable;
  367. ASSERT( tableHeader->Table[0].Owner == NULL );
  368. uidIndex = 0;
  369. //
  370. // Remove the UID slot from the free list and set its owner and
  371. // sequence number. Create a UID for the session. Increment
  372. // count of sessions.
  373. //
  374. entry = &tableHeader->Table[uidIndex];
  375. tableHeader->FirstFreeEntry = entry->NextFreeEntry;
  376. DEBUG entry->NextFreeEntry = -2;
  377. if ( tableHeader->LastFreeEntry == uidIndex ) {
  378. tableHeader->LastFreeEntry = -1;
  379. }
  380. entry->Owner = session;
  381. INCREMENT_UID_SEQUENCE( entry->SequenceNumber );
  382. if ( uidIndex == 0 && entry->SequenceNumber == 0 ) {
  383. INCREMENT_UID_SEQUENCE( entry->SequenceNumber );
  384. }
  385. session->Uid = MAKE_UID( uidIndex, entry->SequenceNumber );
  386. connection->CurrentNumberOfSessions++;
  387. IF_SMB_DEBUG(ADMIN1) {
  388. KdPrint(( "Found UID. Index = 0x%lx, sequence = 0x%lx\n",
  389. (ULONG)UID_INDEX( session->Uid ),
  390. (ULONG)UID_SEQUENCE( session->Uid ) ));
  391. }
  392. //
  393. // Insert the session on the global session list.
  394. //
  395. SrvInsertEntryOrderedList( &SrvSessionList, session );
  396. //
  397. // Reference the connection block to account for the new
  398. // session.
  399. //
  400. SrvReferenceConnection( connection );
  401. session->Connection = connection;
  402. RELEASE_LOCK( &connection->Lock );
  403. RELEASE_LOCK( SrvSessionList.Lock );
  404. //
  405. // Session successfully created. Remember its address in the
  406. // work context block.
  407. //
  408. // *** Note that the reference count on the session block is
  409. // initially set to 2, to allow for the active status on the
  410. // block and the pointer that we're maintaining. In other
  411. // words, this is a referenced pointer, and the pointer must
  412. // be dereferenced when processing of this SMB is complete.
  413. //
  414. WorkContext->Session = session;
  415. didLogon = TRUE;
  416. }
  417. //
  418. // Try to match pathname against available shared resources. Note
  419. // that if SrvVerifyShare finds a matching share, it references it
  420. // and stores its address in WorkContext->Share.
  421. //
  422. share = SrvVerifyShare(
  423. WorkContext,
  424. (PSZ)request->Buffer + 1,
  425. service,
  426. SMB_IS_UNICODE( WorkContext ),
  427. session->IsNullSession,
  428. &status,
  429. NULL
  430. );
  431. //
  432. // If no match was found, return an error.
  433. //
  434. if ( share == NULL ) {
  435. if ( didLogon ) {
  436. SrvCloseSession( session );
  437. }
  438. SrvFreeTreeConnect( treeConnect );
  439. IF_DEBUG(ERRORS) {
  440. KdPrint(( "SrvSmbTreeConnect: SrvVerifyShare failed for %s. Status = %x\n", request->Buffer+1, status ));
  441. }
  442. SrvSetSmbError( WorkContext, status );
  443. SmbStatus = SmbStatusSendResponse;
  444. goto Cleanup;
  445. }
  446. //
  447. // Impersonate the user so that we can capture his security context.
  448. // This is necessary in order to determine whether the user can
  449. // connect to the share.
  450. //
  451. status = IMPERSONATE( WorkContext );
  452. if( !NT_SUCCESS( status ) ) {
  453. SrvSetSmbError( WorkContext, status );
  454. if ( didLogon ) {
  455. SrvCloseSession( session );
  456. }
  457. SrvFreeTreeConnect( treeConnect );
  458. SmbStatus = SmbStatusSendResponse;
  459. goto Cleanup;
  460. }
  461. SeCaptureSubjectContext( &subjectContext );
  462. //
  463. // Set up the desired access on the share, based on whether the
  464. // server is paused. If the server is paused, admin privilege is
  465. // required to connect to any share; if the server is not paused,
  466. // admin privilege is required only for admin shares (C$, etc.).
  467. //
  468. if ( SrvPaused ) {
  469. desiredAccess = SRVSVC_PAUSED_SHARE_CONNECT;
  470. } else {
  471. desiredAccess = SRVSVC_SHARE_CONNECT;
  472. }
  473. //
  474. // Check whether the user has access to this share.
  475. //
  476. if ( !SeAccessCheck(
  477. share->SecurityDescriptor,
  478. &subjectContext,
  479. FALSE,
  480. desiredAccess,
  481. 0L,
  482. NULL,
  483. &SrvShareConnectMapping,
  484. UserMode,
  485. &grantedAccess,
  486. &status
  487. ) ) {
  488. IF_SMB_DEBUG(TREE2) {
  489. KdPrint(( "SrvSmbTreeConnect: SeAccessCheck failed: %X\n",
  490. status ));
  491. }
  492. //
  493. // Release the subject context and revert to the server's security
  494. // context.
  495. //
  496. SeReleaseSubjectContext( &subjectContext );
  497. REVERT( );
  498. if ( SrvPaused ) {
  499. SrvSetSmbError( WorkContext, STATUS_SHARING_PAUSED );
  500. status = STATUS_SHARING_PAUSED;
  501. } else {
  502. SrvSetSmbError( WorkContext, status );
  503. }
  504. if ( didLogon ) {
  505. SrvCloseSession( session );
  506. }
  507. SrvFreeTreeConnect( treeConnect );
  508. SmbStatus = SmbStatusSendResponse;
  509. goto Cleanup;
  510. }
  511. ASSERT( grantedAccess == desiredAccess );
  512. //
  513. // Release the subject context and revert to the server's security
  514. // context.
  515. //
  516. SeReleaseSubjectContext( &subjectContext );
  517. REVERT( );
  518. //
  519. // Let the license server know
  520. //
  521. if( share->ShareType != ShareTypePipe ) {
  522. status = SrvXsLSOperation( session, XACTSRV_MESSAGE_LSREQUEST );
  523. if( !NT_SUCCESS( status ) ) {
  524. if ( didLogon ) {
  525. SrvCloseSession( session );
  526. }
  527. SrvFreeTreeConnect( treeConnect );
  528. IF_DEBUG(ERRORS) {
  529. KdPrint(( "SrvSmbTreeConnect: License server returned %X\n",
  530. status ));
  531. }
  532. SrvSetSmbError( WorkContext, status );
  533. SmbStatus = SmbStatusSendResponse;
  534. goto Cleanup;
  535. }
  536. }
  537. //
  538. // Making a new tree connect visible is a three-step operation. It
  539. // must be inserted in the containing share's tree connect list, the
  540. // global ordered tree connect list, and the containing connection's
  541. // tree connect table. We need to make these operations appear
  542. // atomic, so that the tree connect cannot be accessed elsewhere
  543. // before we're done setting it up. In order to do this, we hold
  544. // all necessary locks the entire time we're doing the three
  545. // operations. The first and second operations are protected by the
  546. // global share lock (SrvShareLock), while the third operation is
  547. // protected by the per-connection lock. We take out the share lock
  548. // first, then the connection lock. This ordering is required by
  549. // lock levels (see lock.h).
  550. //
  551. // Another problem here is that the checking of the share state, the
  552. // inserting of the tree connect on the share's list, and the
  553. // referencing of the share all need to be atomic. (The same holds
  554. // for the connection actions.) Normally this would not be a
  555. // problem, because we could just hold the share lock while doing
  556. // all three actions. However, in this case we also need to hold
  557. // the connection lock, and we can't call SrvReferenceShare while
  558. // doing that. To get around this problem, we reference the share
  559. // _before_ taking out the locks, and dereference after releasing
  560. // the locks if we decide not to insert the tree connect.
  561. //
  562. status = SrvReferenceShareForTreeConnect( share );
  563. //
  564. // SrvReferenceShareForTreeConnect will fail if it cannot open the
  565. // share root directory for some reason. If this happens,
  566. // fail the tree connect attempt.
  567. //
  568. if ( !NT_SUCCESS(status) ) {
  569. if ( didLogon ) {
  570. SrvCloseSession( session );
  571. }
  572. SrvFreeTreeConnect( treeConnect );
  573. IF_DEBUG(ERRORS) {
  574. KdPrint(( "SrvSmbTreeConnect: open of share root failed:%X\n",
  575. status ));
  576. }
  577. SrvSetSmbError( WorkContext, status );
  578. SmbStatus = SmbStatusSendResponse;
  579. goto Cleanup;
  580. }
  581. ACQUIRE_LOCK( &SrvShareLock );
  582. ASSERT( SrvTreeConnectList.Lock == &SrvShareLock );
  583. ACQUIRE_LOCK( &connection->Lock );
  584. //
  585. // We first check all conditions to make sure that we can actually
  586. // insert this tree connect block.
  587. //
  588. // Make sure that the share isn't closing, and that there aren't
  589. // already too many uses on this share.
  590. //
  591. if ( GET_BLOCK_STATE(share) != BlockStateActive ) {
  592. //
  593. // The share is closing. Reject the request.
  594. //
  595. IF_DEBUG(ERRORS) {
  596. KdPrint(( "SrvSmbTreeConnect: Share %wZ (0x%p) is closing\n",
  597. &share->ShareName, share ));
  598. }
  599. status = STATUS_INVALID_PARAMETER;
  600. goto cant_insert;
  601. }
  602. if ( share->CurrentUses > share->MaxUses ) {
  603. //
  604. // The share is full. Reject the request.
  605. //
  606. IF_DEBUG(ERRORS) {
  607. KdPrint(( "SrvSmbTreeConnect: No more uses available for share %wZ (0x%p), max = %ld\n",
  608. &share->ShareName, share, share->MaxUses ));
  609. }
  610. status = STATUS_REQUEST_NOT_ACCEPTED;
  611. goto cant_insert;
  612. }
  613. //
  614. // Make sure that the connection isn't closing.
  615. //
  616. if ( GET_BLOCK_STATE(connection) != BlockStateActive ) {
  617. IF_DEBUG(SMB_ERRORS) {
  618. KdPrint(( "SrvSmbTreeConnect: Connection closing\n" ));
  619. }
  620. SrvSetSmbError( WorkContext, STATUS_INVALID_PARAMETER );
  621. status = STATUS_INVALID_PARAMETER;
  622. goto cant_insert;
  623. }
  624. //
  625. // Find a TID that can be used for this tree connect.
  626. //
  627. tableHeader = &pagedConnection->TreeConnectTable;
  628. if ( tableHeader->FirstFreeEntry == -1
  629. &&
  630. SrvGrowTable(
  631. tableHeader,
  632. SrvInitialTreeTableSize,
  633. SrvMaxTreeTableSize,
  634. &TableStatus ) == FALSE
  635. ) {
  636. //
  637. // No free entries in the tree table. Reject the request.
  638. //
  639. IF_DEBUG(ERRORS) {
  640. KdPrint(( "SrvSmbTreeConnect: No more TIDs available.\n" ));
  641. }
  642. status = TableStatus;
  643. if( TableStatus == STATUS_INSUFF_SERVER_RESOURCES )
  644. {
  645. SrvLogTableFullError( SRV_TABLE_TREE_CONNECT );
  646. }
  647. goto cant_insert;
  648. }
  649. tidIndex = tableHeader->FirstFreeEntry;
  650. //
  651. // All conditions have been satisfied. We can now do the things
  652. // necessary to make the tree connect visible.
  653. //
  654. // Increment the count of uses for the share. Link the tree connect
  655. // into the list of active tree connects for the share. Save the
  656. // share address in the tree connect. Note that we referenced the
  657. // share earlier, before taking out the connection lock.
  658. //
  659. SrvInsertTailList(
  660. &share->TreeConnectList,
  661. &treeConnect->ShareListEntry
  662. );
  663. treeConnect->Share = share;
  664. //
  665. // Remove the TID slot from the free list and set its owner and
  666. // sequence number. Create a TID for the tree connect.
  667. //
  668. entry = &tableHeader->Table[tidIndex];
  669. tableHeader->FirstFreeEntry = entry->NextFreeEntry;
  670. DEBUG entry->NextFreeEntry = -2;
  671. if ( tableHeader->LastFreeEntry == tidIndex ) {
  672. tableHeader->LastFreeEntry = -1;
  673. }
  674. entry->Owner = treeConnect;
  675. INCREMENT_TID_SEQUENCE( entry->SequenceNumber );
  676. if ( tidIndex == 0 && entry->SequenceNumber == 0 ) {
  677. INCREMENT_TID_SEQUENCE( entry->SequenceNumber );
  678. }
  679. treeConnect->Tid = MAKE_TID( tidIndex, entry->SequenceNumber );
  680. IF_SMB_DEBUG(TREE1) {
  681. KdPrint(( "Found TID. Index = 0x%lx, sequence = 0x%lx\n",
  682. TID_INDEX( treeConnect->Tid ),
  683. TID_SEQUENCE( treeConnect->Tid ) ));
  684. }
  685. //
  686. // Reference the connection to account for the active tree connect.
  687. //
  688. SrvReferenceConnection( connection );
  689. treeConnect->Connection = connection;
  690. if( session )
  691. {
  692. SrvReferenceSession( session );
  693. treeConnect->Session = session;
  694. }
  695. //
  696. // Link the tree connect into the global list of tree connects.
  697. //
  698. SrvInsertEntryOrderedList( &SrvTreeConnectList, treeConnect );
  699. //
  700. // If this session is the one controlling the extended security signatures,
  701. // see if we need to hash the session key
  702. //
  703. if( session->SessionKeyState == SrvSessionKeyAuthenticating )
  704. {
  705. // Downlevel machines that use a simple TREE_CONNECT (instead of TREE_CONNECT_ANDX)
  706. // don't understand extended signatures, so we can make the session key availible.
  707. // Note that if the REQUIRE_EXTENDED_SIGNATURES policy is active, that check occurred
  708. // above.
  709. session->SessionKeyState = SrvSessionKeyAvailible;
  710. }
  711. //
  712. // Release the locks used to make this operation appear atomic.
  713. //
  714. RELEASE_LOCK( &connection->Lock );
  715. RELEASE_LOCK( &SrvShareLock );
  716. //
  717. // Get the qos information for this connection
  718. //
  719. SrvUpdateVcQualityOfService ( connection, NULL );
  720. //
  721. // Tree connect successfully created. Because the tree connect was
  722. // created with an initial reference count of 2, dereference it now.
  723. //
  724. // *** Don't bother to save the tree connect address in the work
  725. // context block, because we're going to forget our pointers
  726. // soon anyway (we're done with the request). TreeConnectAndX
  727. // has to remember these things, though.
  728. //
  729. SrvDereferenceTreeConnect( treeConnect );
  730. //
  731. // Set up response SMB.
  732. //
  733. SmbPutAlignedUshort( &WorkContext->ResponseHeader->Tid, treeConnect->Tid );
  734. response->WordCount = 2;
  735. SmbPutUshort( &response->MaxBufferSize, (USHORT)session->MaxBufferSize );
  736. SmbPutUshort( &response->Tid, treeConnect->Tid );
  737. SmbPutUshort( &response->ByteCount, 0 );
  738. WorkContext->ResponseParameters = NEXT_LOCATION(
  739. response,
  740. RESP_TREE_CONNECT,
  741. 0
  742. );
  743. IF_DEBUG(TRACE2) KdPrint(( "SrvSmbTreeConnect complete.\n" ));
  744. SmbStatus = SmbStatusSendResponse;
  745. goto Cleanup;
  746. cant_insert:
  747. //
  748. // We get here if for some reason we decide that we can't insert
  749. // the tree connect. On entry, status contains the reason code.
  750. // The connection lock and the share lock are held.
  751. //
  752. RELEASE_LOCK( &connection->Lock );
  753. RELEASE_LOCK( &SrvShareLock );
  754. if ( didLogon ) {
  755. SrvCloseSession( session );
  756. }
  757. SrvDereferenceShareForTreeConnect( share );
  758. SrvFreeTreeConnect( treeConnect );
  759. SrvSetSmbError( WorkContext, status );
  760. SmbStatus = SmbStatusSendResponse;
  761. Cleanup:
  762. SrvWmiEndContext(WorkContext);
  763. return SmbStatus;
  764. } // SrvSmbTreeConnect
  765. SMB_PROCESSOR_RETURN_TYPE
  766. SrvSmbTreeConnectAndX (
  767. SMB_PROCESSOR_PARAMETERS
  768. )
  769. /*++
  770. Routine Description:
  771. Processes a tree connect and X SMB.
  772. Arguments:
  773. SMB_PROCESSOR_PARAMETERS - See smbprocs.h for a description
  774. of the parameters to SMB processor routines.
  775. Return Value:
  776. SMB_PROCESSOR_RETURN_TYPE - See smbprocs.h
  777. --*/
  778. {
  779. PREQ_TREE_CONNECT_ANDX request;
  780. PRESP_TREE_CONNECT_ANDX response;
  781. PRESP_EXTENDED_TREE_CONNECT_ANDX responseExtended;
  782. PRESP_21_TREE_CONNECT_ANDX response21;
  783. NTSTATUS status = STATUS_SUCCESS;
  784. NTSTATUS TableStatus;
  785. SMB_STATUS SmbStatus = SmbStatusInProgress;
  786. PCONNECTION connection;
  787. PPAGED_CONNECTION pagedConnection;
  788. PTABLE_HEADER tableHeader;
  789. PTABLE_ENTRY entry;
  790. SHORT tidIndex;
  791. PSHARE share;
  792. PTREE_CONNECT treeConnect;
  793. PVOID shareName;
  794. PUCHAR shareType;
  795. USHORT shareNameLength;
  796. USHORT reqAndXOffset;
  797. UCHAR nextCommand;
  798. PSZ shareString;
  799. USHORT shareStringLength;
  800. USHORT RequestFlags;
  801. USHORT byteCount;
  802. USHORT maxByteCount;
  803. PUCHAR smbBuffer;
  804. PSESSION session;
  805. SECURITY_SUBJECT_CONTEXT subjectContext;
  806. ACCESS_MASK desiredAccess;
  807. ACCESS_MASK grantedAccess;
  808. BOOLEAN isUnicode;
  809. UNICODE_STRING serverName;
  810. BOOLEAN remapPipeNames = FALSE;
  811. BOOLEAN KeyHashed = FALSE;
  812. PAGED_CODE( );
  813. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  814. WorkContext->PreviousSMB = EVENT_TYPE_SMB_TREE_CONNECT_AND_X;
  815. SrvWmiStartContext(WorkContext);
  816. IF_SMB_DEBUG(TREE1) {
  817. KdPrint(( "Tree connect and X request header at 0x%p, response header at 0x%p\n",
  818. WorkContext->RequestHeader, WorkContext->ResponseHeader ));
  819. KdPrint(( "Tree connect and X request parameters at 0x%p, response parameters at 0x%p\n",
  820. WorkContext->RequestParameters,
  821. WorkContext->ResponseParameters ));
  822. }
  823. //
  824. // Set up parameters.
  825. //
  826. request = (PREQ_TREE_CONNECT_ANDX)(WorkContext->RequestParameters);
  827. response = (PRESP_TREE_CONNECT_ANDX)(WorkContext->ResponseParameters);
  828. responseExtended = (PRESP_EXTENDED_TREE_CONNECT_ANDX)(WorkContext->ResponseParameters);
  829. response21 = (PRESP_21_TREE_CONNECT_ANDX)(WorkContext->ResponseParameters);
  830. //
  831. // If bit 0 of Flags is set, disconnect tree in header TID. We must
  832. // get the appropriate tree connect pointer. SrvVerifyTid does this
  833. // for us, referencing the tree connect and storing the pointer in
  834. // the work context block. We have to dereference the block and
  835. // erase the pointer after calling SrvCloseTreeConnect.
  836. //
  837. if ( (SmbGetUshort( &request->Flags ) & 1) != 0 ) {
  838. if ( SrvVerifyTid(
  839. WorkContext,
  840. SmbGetAlignedUshort( &WorkContext->RequestHeader->Tid )
  841. ) == NULL ) {
  842. IF_DEBUG(ERRORS) {
  843. KdPrint(( "SrvSmbTreeConnectAndX: Invalid TID to disconnect: 0x%lx\n",
  844. SmbGetAlignedUshort( &WorkContext->RequestHeader->Tid ) ));
  845. }
  846. //
  847. // Just ignore an invalid TID--this is what the LM 2.0
  848. // server does.
  849. //
  850. } else {
  851. SrvCloseTreeConnect( WorkContext->TreeConnect );
  852. SrvDereferenceTreeConnect( WorkContext->TreeConnect );
  853. WorkContext->TreeConnect = NULL;
  854. }
  855. }
  856. //
  857. // Validate the UID in the header and get a session pointer. We need
  858. // the user's token to check whether they can access this share.
  859. //
  860. session = SrvVerifyUid(
  861. WorkContext,
  862. SmbGetAlignedUshort( &WorkContext->RequestHeader->Uid )
  863. );
  864. //
  865. // If we couldn't find a valid session fail the tree connect.
  866. //
  867. if ( session == NULL ) {
  868. IF_DEBUG(ERRORS) {
  869. KdPrint(( "SrvSmbTreeConnectAndX: rejecting tree connect for "
  870. "session %p due to server paused.\n", session ));
  871. }
  872. SrvSetSmbError( WorkContext, STATUS_SMB_BAD_UID );
  873. status = STATUS_SMB_BAD_UID;
  874. SmbStatus = SmbStatusSendResponse;
  875. goto Cleanup;
  876. }
  877. else if( session->IsSessionExpired )
  878. {
  879. status = SESSION_EXPIRED_STATUS_CODE;
  880. SrvSetSmbError( WorkContext, status );
  881. SmbStatus = SmbStatusSendResponse;
  882. goto Cleanup;
  883. }
  884. //
  885. // Try to match pathname against available shared resources. Note
  886. // that if SrvVerifyShare finds a matching share, it references it
  887. // and stores its address in WorkContext->Share.
  888. //
  889. shareName = (PSZ)request->Buffer +
  890. SmbGetUshort( &request->PasswordLength );
  891. connection = WorkContext->Connection;
  892. pagedConnection = connection->PagedConnection;
  893. isUnicode = SMB_IS_UNICODE( WorkContext );
  894. if ( isUnicode ) {
  895. shareName = ALIGN_SMB_WSTR( shareName );
  896. }
  897. shareNameLength = SrvGetStringLength(
  898. shareName,
  899. END_OF_REQUEST_SMB( WorkContext ),
  900. SMB_IS_UNICODE( WorkContext ),
  901. TRUE // include null terminator
  902. );
  903. //
  904. // if share name is bogus, return an error.
  905. //
  906. if ( shareNameLength == (USHORT)-1 ) {
  907. IF_DEBUG(ERRORS) {
  908. KdPrint(( "SrvSmbTreeConnectAndX: pathname is bogus.\n"));
  909. }
  910. SrvSetSmbError( WorkContext, STATUS_BAD_NETWORK_NAME );
  911. status = STATUS_BAD_NETWORK_NAME;
  912. SmbStatus = SmbStatusSendResponse;
  913. goto Cleanup;
  914. }
  915. shareType = (PCHAR)shareName + shareNameLength;
  916. share = SrvVerifyShare(
  917. WorkContext,
  918. shareName,
  919. shareType,
  920. isUnicode,
  921. session->IsNullSession,
  922. &status,
  923. &serverName
  924. );
  925. //
  926. // If no match was found, return an error.
  927. //
  928. if ( share == NULL ) {
  929. IF_DEBUG(ERRORS) {
  930. KdPrint(( "SrvSmbTreeConnectAndX: pathname does not match "
  931. "any shares: %s\n", shareName ));
  932. }
  933. SrvSetSmbError( WorkContext, status );
  934. SmbStatus = SmbStatusSendResponse;
  935. goto Cleanup;
  936. }
  937. //
  938. // If the the client is connecting with a netbiosless transport and the name of the
  939. // server which the client was requesting doesn't match any of our servernames, then
  940. // the client has accidentally connected to the wrong server. Let the client know.
  941. //
  942. if( !SrvDisableStrictNameChecking &&
  943. serverName.Buffer != NULL &&
  944. connection->Endpoint->IsNoNetBios &&
  945. SrvIsDottedQuadAddress( &serverName ) == FALSE &&
  946. SrvFindNamedEndpoint( &serverName, NULL ) == FALSE &&
  947. SrvIsLocalHost( &serverName ) == FALSE ) {
  948. BOOL bBadName = TRUE;
  949. // Last check, make sure its not the domain DNS name (which may differ from the NETBIOS DNS name)
  950. ACQUIRE_LOCK_SHARED( &SrvEndpointLock );
  951. // We only check up to the first ., so ntdev.microsoft.com would match SrvDnsDomainName "NTDEV"
  952. // Strip off the excess info for the check, then put it back
  953. if( SrvDnsDomainName ) {
  954. if( SrvDnsDomainName->Length <= serverName.Length )
  955. {
  956. USHORT oldLength = serverName.Length;
  957. serverName.Length = SrvDnsDomainName->Length;
  958. if( RtlEqualUnicodeString( &serverName, SrvDnsDomainName, TRUE ) )
  959. {
  960. bBadName = FALSE;
  961. }
  962. serverName.Length = oldLength;
  963. }
  964. }
  965. RELEASE_LOCK( &SrvEndpointLock );
  966. //
  967. // The client has connected to this server in error--turn the client back!
  968. //
  969. if( bBadName )
  970. {
  971. SrvSetSmbError( WorkContext, STATUS_DUPLICATE_NAME );
  972. status = STATUS_DUPLICATE_NAME;
  973. SmbStatus = SmbStatusSendResponse;
  974. goto Cleanup;
  975. }
  976. }
  977. //
  978. // Impersonate the user so that we can capture his security context.
  979. // This is necessary in order to determine whether the user can
  980. // connect to the share.
  981. //
  982. status = IMPERSONATE( WorkContext );
  983. if( !NT_SUCCESS( status ) ) {
  984. SrvSetSmbError( WorkContext, status );
  985. SmbStatus = SmbStatusSendResponse;
  986. goto Cleanup;
  987. }
  988. SeCaptureSubjectContext( &subjectContext );
  989. //
  990. // Set up the desired access on the share, based on whether the
  991. // server is paused. If the server is paused, admin privilege is
  992. // required to connect to any share; if the server is not paused,
  993. // admin privilege is required only for admin shares (C$, etc.).
  994. //
  995. if ( SrvPaused ) {
  996. desiredAccess = SRVSVC_PAUSED_SHARE_CONNECT;
  997. } else {
  998. desiredAccess = SRVSVC_SHARE_CONNECT;
  999. }
  1000. //
  1001. // Check whether the user has access to this share.
  1002. //
  1003. if ( !SeAccessCheck(
  1004. share->SecurityDescriptor,
  1005. &subjectContext,
  1006. FALSE,
  1007. desiredAccess,
  1008. 0L,
  1009. NULL,
  1010. &SrvShareConnectMapping,
  1011. UserMode,
  1012. &grantedAccess,
  1013. &status
  1014. ) ) {
  1015. IF_SMB_DEBUG(TREE2) {
  1016. KdPrint(( "SrvSmbTreeConnectAndX: SeAccessCheck failed: %X\n",
  1017. status ));
  1018. }
  1019. //
  1020. // Release the subject context and revert to the server's security
  1021. // context.
  1022. //
  1023. SeReleaseSubjectContext( &subjectContext );
  1024. REVERT( );
  1025. if ( SrvPaused ) {
  1026. SrvSetSmbError( WorkContext, STATUS_SHARING_PAUSED );
  1027. status = STATUS_SHARING_PAUSED;
  1028. } else {
  1029. SrvSetSmbError( WorkContext, status );
  1030. }
  1031. SmbStatus = SmbStatusSendResponse;
  1032. goto Cleanup;
  1033. }
  1034. ASSERT( grantedAccess == desiredAccess );
  1035. //
  1036. // Release the subject context and revert to the server's security
  1037. // context.
  1038. //
  1039. SeReleaseSubjectContext( &subjectContext );
  1040. REVERT( );
  1041. //
  1042. // See if the license server wants to let this person in on the NTAS
  1043. //
  1044. if( share->ShareType != ShareTypePipe ) {
  1045. status = SrvXsLSOperation( session, XACTSRV_MESSAGE_LSREQUEST );
  1046. if( !NT_SUCCESS( status ) ) {
  1047. IF_DEBUG(ERRORS) {
  1048. KdPrint(( "SrvSmbTreeConnectAndX: License server returned %X\n",
  1049. status ));
  1050. }
  1051. SrvSetSmbError( WorkContext, status );
  1052. SmbStatus = SmbStatusSendResponse;
  1053. goto Cleanup;
  1054. }
  1055. } else if( serverName.Buffer != NULL ) {
  1056. //
  1057. // This is the IPC$ share. See if we're supposed to remap pipe names
  1058. //
  1059. SrvFindNamedEndpoint( &serverName, &remapPipeNames );
  1060. }
  1061. //
  1062. // Allocate a tree connect block.
  1063. //
  1064. SrvAllocateTreeConnect( &treeConnect, serverName.Buffer ? &serverName : NULL );
  1065. if ( treeConnect == NULL ) {
  1066. //
  1067. // Unable to allocate tree connect. Return an error to the
  1068. // client.
  1069. //
  1070. SrvSetSmbError( WorkContext, STATUS_INSUFF_SERVER_RESOURCES );
  1071. status = STATUS_INSUFF_SERVER_RESOURCES;
  1072. SmbStatus = SmbStatusSendResponse;
  1073. goto Cleanup;
  1074. }
  1075. treeConnect->RemapPipeNames = remapPipeNames;
  1076. //
  1077. // Making a new tree connect visible is a three-step operation. It
  1078. // must be inserted in the containing share's tree connect list, the
  1079. // global ordered tree connect list, and the containing connection's
  1080. // tree connect table. We need to make these operations appear
  1081. // atomic, so that the tree connect cannot be accessed elsewhere
  1082. // before we're done setting it up. In order to do this, we hold
  1083. // all necessary locks the entire time we're doing the three
  1084. // operations. The first and second operations are protected by the
  1085. // global share lock (SrvShareLock), while the third operation is
  1086. // protected by the per-connection lock. We take out the share lock
  1087. // first, then the connection lock. This ordering is required by
  1088. // lock levels (see lock.h).
  1089. //
  1090. // Another problem here is that the checking of the share state, the
  1091. // inserting of the tree connect on the share's list, and the
  1092. // referencing of the share all need to be atomic. (The same holds
  1093. // for the connection actions.) Normally this would not be a
  1094. // problem, because we could just hold the share lock while doing
  1095. // all three actions. However, in this case we also need to hold
  1096. // the connection lock, and we can't call SrvReferenceShare while
  1097. // doing that. To get around this problem, we reference the share
  1098. // _before_ taking out the locks, and dereference after releasing
  1099. // the locks if we decide not to insert the tree connect.
  1100. //
  1101. status = SrvReferenceShareForTreeConnect( share );
  1102. //
  1103. // SrvReferenceShareForTreeConnect will fail if it cannot open the
  1104. // share root directory for some reason. If this happens,
  1105. // fail the tree connect attempt.
  1106. //
  1107. if ( !NT_SUCCESS(status) ) {
  1108. SrvFreeTreeConnect( treeConnect );
  1109. IF_DEBUG(ERRORS) {
  1110. KdPrint(( "SrvSmbTreeConnectAndX: open of share root failed:%X\n",
  1111. status ));
  1112. }
  1113. SrvSetSmbError( WorkContext, status );
  1114. SmbStatus = SmbStatusSendResponse;
  1115. goto Cleanup;
  1116. }
  1117. ACQUIRE_LOCK( &SrvShareLock );
  1118. ASSERT( SrvTreeConnectList.Lock == &SrvShareLock );
  1119. ACQUIRE_LOCK( &connection->Lock );
  1120. if( SrvRequireExtendedSignatures )
  1121. {
  1122. // If we are requiring extended signatures, and the client has not
  1123. // asked for them on this request or any previous request, deny
  1124. // this request.
  1125. if( session->SessionKeyState == SrvSessionKeyAuthenticating )
  1126. {
  1127. if ( !(request->Flags & TREE_CONNECT_ANDX_EXTENDED_SIGNATURES) ) {
  1128. status = STATUS_LOGIN_WKSTA_RESTRICTION;
  1129. goto cant_insert;
  1130. }
  1131. }
  1132. }
  1133. // If they sent this uplevel flag on a downlevel request, than someone must
  1134. // of been tricking us during negotiate. Fail.
  1135. if( (request->Flags & TREE_CONNECT_ANDX_EXTENDED_SIGNATURES) &&
  1136. (connection->SmbDialect > SmbDialectDosLanMan21) )
  1137. {
  1138. status = STATUS_DOWNGRADE_DETECTED;
  1139. goto cant_insert;
  1140. }
  1141. //
  1142. // We first check all conditions to make sure that we can actually
  1143. // insert this tree connect block.
  1144. //
  1145. // Make sure that the share isn't closing, and that there aren't
  1146. // already too many uses on this share.
  1147. //
  1148. if ( GET_BLOCK_STATE(share) != BlockStateActive ) {
  1149. //
  1150. // The share is closing. Reject the request.
  1151. //
  1152. IF_DEBUG(ERRORS) {
  1153. KdPrint(( "SrvSmbTreeConnectAndX: Share %wZ (0x%p) is closing\n",
  1154. &share->ShareName, share ));
  1155. }
  1156. status = STATUS_INVALID_PARAMETER;
  1157. goto cant_insert;
  1158. }
  1159. if ( share->CurrentUses > share->MaxUses ) {
  1160. //
  1161. // The share is full. Reject the request.
  1162. //
  1163. IF_DEBUG(ERRORS) {
  1164. KdPrint(( "SrvSmbTreeConnectAndX: No more uses available for share %wZ (0x%p), max = %ld\n",
  1165. &share->ShareName, share, share->MaxUses ));
  1166. }
  1167. status = STATUS_REQUEST_NOT_ACCEPTED;
  1168. goto cant_insert;
  1169. }
  1170. //
  1171. // Make sure that the connection isn't closing, and that there's
  1172. // room in its tree connect table.
  1173. //
  1174. if ( GET_BLOCK_STATE(connection) != BlockStateActive ) {
  1175. IF_DEBUG(SMB_ERRORS) {
  1176. KdPrint(( "SrvSmbTreeConnectAndX: Connection closing\n" ));
  1177. }
  1178. SrvSetSmbError( WorkContext, STATUS_INVALID_PARAMETER );
  1179. status = STATUS_INVALID_PARAMETER;
  1180. goto cant_insert;
  1181. }
  1182. //
  1183. // Find a TID that can be used for this tree connect.
  1184. //
  1185. tableHeader = &pagedConnection->TreeConnectTable;
  1186. if ( tableHeader->FirstFreeEntry == -1
  1187. &&
  1188. SrvGrowTable(
  1189. tableHeader,
  1190. SrvInitialTreeTableSize,
  1191. SrvMaxTreeTableSize,
  1192. &TableStatus ) == FALSE
  1193. ) {
  1194. //
  1195. // No free entries in the tree table. Reject the request.
  1196. //
  1197. IF_DEBUG(ERRORS) {
  1198. KdPrint(( "SrvSmbTreeConnect: No more TIDs available.\n" ));
  1199. }
  1200. if( TableStatus == STATUS_INSUFF_SERVER_RESOURCES )
  1201. {
  1202. SrvLogTableFullError( SRV_TABLE_TREE_CONNECT );
  1203. }
  1204. status = TableStatus;
  1205. goto cant_insert;
  1206. }
  1207. tidIndex = tableHeader->FirstFreeEntry;
  1208. //
  1209. // All conditions have been satisfied. We can now do the things
  1210. // necessary to make the tree connect visible.
  1211. //
  1212. // Link the tree connect into the list of active tree connects for
  1213. // the share. Save the share address in the tree connect. Note
  1214. // that we referenced the share earlier, before taking out the
  1215. // connection lock.
  1216. //
  1217. SrvInsertTailList(
  1218. &share->TreeConnectList,
  1219. &treeConnect->ShareListEntry
  1220. );
  1221. treeConnect->Share = share;
  1222. //
  1223. // Remove the TID slot from the free list and set its owner and
  1224. // sequence number. Create a TID for the tree connect.
  1225. //
  1226. entry = &tableHeader->Table[tidIndex];
  1227. tableHeader->FirstFreeEntry = entry->NextFreeEntry;
  1228. DEBUG entry->NextFreeEntry = -2;
  1229. if ( tableHeader->LastFreeEntry == tidIndex ) {
  1230. tableHeader->LastFreeEntry = -1;
  1231. }
  1232. entry->Owner = treeConnect;
  1233. INCREMENT_TID_SEQUENCE( entry->SequenceNumber );
  1234. if ( tidIndex == 0 && entry->SequenceNumber == 0 ) {
  1235. INCREMENT_TID_SEQUENCE( entry->SequenceNumber );
  1236. }
  1237. treeConnect->Tid = MAKE_TID( tidIndex, entry->SequenceNumber );
  1238. IF_SMB_DEBUG(TREE1) {
  1239. KdPrint(( "Found TID. Index = 0x%lx, sequence = 0x%lx\n",
  1240. TID_INDEX( treeConnect->Tid ),
  1241. TID_SEQUENCE( treeConnect->Tid ) ));
  1242. }
  1243. //
  1244. // Reference the connection to account for the active tree connect.
  1245. //
  1246. SrvReferenceConnection( connection );
  1247. treeConnect->Connection = connection;
  1248. if( session )
  1249. {
  1250. SrvReferenceSession( session );
  1251. treeConnect->Session = session;
  1252. }
  1253. //
  1254. // Link the tree connect into the global list of tree connects.
  1255. //
  1256. SrvInsertEntryOrderedList( &SrvTreeConnectList, treeConnect );
  1257. //
  1258. // If this session is the one controlling the extended security signatures,
  1259. // see if we need to hash the session key
  1260. //
  1261. if( session->SessionKeyState == SrvSessionKeyAuthenticating )
  1262. {
  1263. if (request->Flags & TREE_CONNECT_ANDX_EXTENDED_SIGNATURES) {
  1264. // Hash the session key
  1265. SrvHashUserSessionKey( session->NtUserSessionKey );
  1266. KeyHashed = TRUE;
  1267. }
  1268. // This machine has either upgraded to hashed session key, or does not want to
  1269. // Move to availible
  1270. session->SessionKeyState = SrvSessionKeyAvailible;
  1271. }
  1272. //
  1273. // Release the locks used to make this operation appear atomic.
  1274. //
  1275. RELEASE_LOCK( &connection->Lock );
  1276. RELEASE_LOCK( &SrvShareLock );
  1277. //
  1278. // Get the qos information for this connection
  1279. //
  1280. SrvUpdateVcQualityOfService ( connection, NULL );
  1281. //
  1282. // Tree connect successfully created. Save the tree connect block
  1283. // address in the work context block. Note that the reference count
  1284. // on the new block was incremented on creation to account for our
  1285. // reference to the block.
  1286. //
  1287. WorkContext->TreeConnect = treeConnect;
  1288. //
  1289. // Set up response SMB, making sure to save request fields first in
  1290. // case the response overwrites the request.
  1291. //
  1292. reqAndXOffset = SmbGetUshort( &request->AndXOffset );
  1293. nextCommand = request->AndXCommand;
  1294. RequestFlags = SmbGetUshort(&request->Flags);
  1295. SmbPutAlignedUshort( &WorkContext->RequestHeader->Tid, treeConnect->Tid );
  1296. SmbPutAlignedUshort( &WorkContext->ResponseHeader->Tid, treeConnect->Tid );
  1297. response->AndXCommand = nextCommand;
  1298. response->AndXReserved = 0;
  1299. if ( connection->SmbDialect > SmbDialectDosLanMan21) {
  1300. response->WordCount = 2;
  1301. smbBuffer = (PUCHAR)response->Buffer;
  1302. } else {
  1303. if (RequestFlags & TREE_CONNECT_ANDX_EXTENDED_RESPONSE) {
  1304. responseExtended->WordCount = 7;
  1305. smbBuffer = (PUCHAR)responseExtended->Buffer;
  1306. } else {
  1307. response21->WordCount = 3;
  1308. smbBuffer = (PUCHAR)response21->Buffer;
  1309. }
  1310. // Fields common to 21 and extended response.
  1311. response21->OptionalSupport = SMB_SUPPORT_SEARCH_BITS;
  1312. if (share->IsDfs) {
  1313. response21->OptionalSupport |= SMB_SHARE_IS_IN_DFS;
  1314. }
  1315. if (KeyHashed)
  1316. {
  1317. response21->OptionalSupport |= SMB_EXTENDED_SIGNATURES;
  1318. }
  1319. switch( share->CSCState ) {
  1320. case CSC_CACHE_MANUAL_REINT:
  1321. response21->OptionalSupport |= SMB_CSC_CACHE_MANUAL_REINT;
  1322. break;
  1323. case CSC_CACHE_AUTO_REINT:
  1324. response21->OptionalSupport |= SMB_CSC_CACHE_AUTO_REINT;
  1325. break;
  1326. case CSC_CACHE_VDO:
  1327. response21->OptionalSupport |= SMB_CSC_CACHE_VDO;
  1328. break;
  1329. case CSC_CACHE_NONE:
  1330. response21->OptionalSupport |= SMB_CSC_NO_CACHING;
  1331. break;
  1332. }
  1333. if( SrvNoAliasingOnFilesystem || (share->ShareProperties & SHI1005_FLAGS_ALLOW_NAMESPACE_CACHING) )
  1334. {
  1335. response21->OptionalSupport |= SMB_UNIQUE_FILE_NAME;
  1336. }
  1337. }
  1338. // Calculate the size of the response buffer
  1339. maxByteCount = (USHORT)(END_OF_RESPONSE_BUFFER(WorkContext) - smbBuffer + 1);
  1340. //
  1341. // Append the service name string to the SMB. The service name
  1342. // is always sent in ANSI.
  1343. //
  1344. shareString = StrShareTypeNames[share->ShareType];
  1345. shareStringLength = (USHORT)( strlen( shareString ) + 1 );
  1346. if( shareStringLength > maxByteCount )
  1347. {
  1348. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  1349. status = STATUS_INVALID_SMB;
  1350. SmbStatus = SmbStatusSendResponse;
  1351. goto Cleanup;
  1352. }
  1353. RtlCopyMemory ( smbBuffer, shareString, shareStringLength );
  1354. byteCount = shareStringLength;
  1355. smbBuffer += shareStringLength;
  1356. if ( connection->SmbDialect <= SmbDialectDosLanMan21 ) {
  1357. //
  1358. // Append the file system name to the response.
  1359. // If the file system name is unavailable, supply the nul string
  1360. // as the name.
  1361. //
  1362. if ( isUnicode ) {
  1363. if ( ((ULONG_PTR)smbBuffer & 1) != 0 ) {
  1364. smbBuffer++;
  1365. byteCount++;
  1366. }
  1367. if ( share->Type.FileSystem.Name.Buffer != NULL ) {
  1368. if( byteCount + share->Type.FileSystem.Name.Length > maxByteCount )
  1369. {
  1370. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  1371. status = STATUS_INVALID_SMB;
  1372. SmbStatus = SmbStatusSendResponse;
  1373. goto Cleanup;
  1374. }
  1375. RtlCopyMemory(
  1376. smbBuffer,
  1377. share->Type.FileSystem.Name.Buffer,
  1378. share->Type.FileSystem.Name.Length
  1379. );
  1380. byteCount += share->Type.FileSystem.Name.Length;
  1381. } else {
  1382. *(PWCH)smbBuffer = UNICODE_NULL;
  1383. byteCount += sizeof( UNICODE_NULL );
  1384. }
  1385. } else {
  1386. if ( share->Type.FileSystem.Name.Buffer != NULL ) {
  1387. if( byteCount + share->Type.FileSystem.OemName.Length > maxByteCount )
  1388. {
  1389. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  1390. status = STATUS_INVALID_SMB;
  1391. SmbStatus = SmbStatusSendResponse;
  1392. goto Cleanup;
  1393. }
  1394. RtlCopyMemory(
  1395. smbBuffer,
  1396. share->Type.FileSystem.OemName.Buffer,
  1397. share->Type.FileSystem.OemName.Length
  1398. );
  1399. byteCount += share->Type.FileSystem.OemName.Length;
  1400. } else {
  1401. *(PUCHAR)smbBuffer = '\0';
  1402. byteCount += 1;
  1403. }
  1404. }
  1405. if (RequestFlags & TREE_CONNECT_ANDX_EXTENDED_RESPONSE) {
  1406. PRESP_EXTENDED_TREE_CONNECT_ANDX ExtendedResponse;
  1407. ExtendedResponse = (PRESP_EXTENDED_TREE_CONNECT_ANDX)response;
  1408. SmbPutUshort( &ExtendedResponse->ByteCount, byteCount );
  1409. SrvUpdateMaximalShareAccessRightsInResponse(
  1410. WorkContext,
  1411. &ExtendedResponse->MaximalShareAccessRights,
  1412. &ExtendedResponse->GuestMaximalShareAccessRights);
  1413. SmbPutUshort(
  1414. &ExtendedResponse->AndXOffset,
  1415. GET_ANDX_OFFSET(
  1416. WorkContext->ResponseHeader,
  1417. WorkContext->ResponseParameters,
  1418. RESP_EXTENDED_TREE_CONNECT_ANDX,
  1419. byteCount
  1420. )
  1421. );
  1422. } else {
  1423. SmbPutUshort( &response21->ByteCount, byteCount );
  1424. SmbPutUshort(
  1425. &response->AndXOffset,
  1426. GET_ANDX_OFFSET(
  1427. WorkContext->ResponseHeader,
  1428. WorkContext->ResponseParameters,
  1429. RESP_21_TREE_CONNECT_ANDX,
  1430. byteCount
  1431. )
  1432. );
  1433. }
  1434. } else { // if Smb dialect == LAN Man 2.1
  1435. SmbPutUshort( &response->ByteCount, byteCount );
  1436. SmbPutUshort(
  1437. &response->AndXOffset,
  1438. GET_ANDX_OFFSET(
  1439. WorkContext->ResponseHeader,
  1440. WorkContext->ResponseParameters,
  1441. RESP_TREE_CONNECT_ANDX,
  1442. byteCount
  1443. )
  1444. );
  1445. }
  1446. WorkContext->ResponseParameters = (PUCHAR)WorkContext->ResponseHeader +
  1447. SmbGetUshort( &response->AndXOffset );
  1448. //
  1449. // Test for legal followon command.
  1450. //
  1451. switch ( nextCommand ) {
  1452. case SMB_COM_NO_ANDX_COMMAND:
  1453. break;
  1454. case SMB_COM_OPEN:
  1455. case SMB_COM_OPEN_ANDX:
  1456. case SMB_COM_CREATE:
  1457. case SMB_COM_CREATE_NEW:
  1458. case SMB_COM_CREATE_DIRECTORY:
  1459. case SMB_COM_DELETE:
  1460. case SMB_COM_DELETE_DIRECTORY:
  1461. case SMB_COM_SEARCH:
  1462. case SMB_COM_FIND:
  1463. case SMB_COM_FIND_UNIQUE:
  1464. case SMB_COM_COPY:
  1465. case SMB_COM_RENAME:
  1466. case SMB_COM_NT_RENAME:
  1467. case SMB_COM_CHECK_DIRECTORY:
  1468. case SMB_COM_QUERY_INFORMATION:
  1469. case SMB_COM_SET_INFORMATION:
  1470. case SMB_COM_QUERY_INFORMATION_SRV:
  1471. case SMB_COM_OPEN_PRINT_FILE:
  1472. case SMB_COM_GET_PRINT_QUEUE:
  1473. case SMB_COM_TRANSACTION:
  1474. //
  1475. // Make sure the AndX command is still within the received SMB
  1476. //
  1477. if( (PCHAR)WorkContext->RequestHeader + reqAndXOffset <=
  1478. END_OF_REQUEST_SMB( WorkContext ) ) {
  1479. break;
  1480. }
  1481. /* Falls Through */
  1482. default: // Illegal followon command
  1483. IF_DEBUG(SMB_ERRORS) {
  1484. KdPrint(( "SrvSmbTreeConnectAndX: Illegal followon command: 0x%c\n", nextCommand ));
  1485. }
  1486. SrvLogInvalidSmb( WorkContext );
  1487. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  1488. status = STATUS_INVALID_SMB;
  1489. SmbStatus = SmbStatusSendResponse;
  1490. goto Cleanup;
  1491. }
  1492. //
  1493. // If there is an AndX command, set up to process it. Otherwise,
  1494. // indicate completion to the caller.
  1495. //
  1496. if ( nextCommand != SMB_COM_NO_ANDX_COMMAND ) {
  1497. // *** Watch out for overwriting request with response.
  1498. WorkContext->NextCommand = nextCommand;
  1499. WorkContext->RequestParameters = (PUCHAR)WorkContext->RequestHeader +
  1500. reqAndXOffset;
  1501. SmbStatus = SmbStatusMoreCommands;
  1502. goto Cleanup;
  1503. }
  1504. IF_DEBUG(TRACE2) KdPrint(( "SrvSmbTreeConnectAndX complete.\n" ));
  1505. SmbStatus = SmbStatusSendResponse;
  1506. goto Cleanup;
  1507. cant_insert:
  1508. //
  1509. // We get here if for some reason we decide that we can't insert
  1510. // the tree connect. On entry, status contains the reason code.
  1511. // The connection lock and the share lock are held.
  1512. //
  1513. RELEASE_LOCK( &connection->Lock );
  1514. RELEASE_LOCK( &SrvShareLock );
  1515. SrvDereferenceShareForTreeConnect( share );
  1516. SrvFreeTreeConnect( treeConnect );
  1517. SrvSetSmbError( WorkContext, status );
  1518. SmbStatus = SmbStatusSendResponse;
  1519. Cleanup:
  1520. SrvWmiEndContext(WorkContext);
  1521. return SmbStatus;
  1522. } // SrvSmbTreeConnectAndX
  1523. SMB_PROCESSOR_RETURN_TYPE
  1524. SrvSmbTreeDisconnect (
  1525. SMB_PROCESSOR_PARAMETERS
  1526. )
  1527. /*++
  1528. Routine Description:
  1529. Processes a tree disconnect SMB.
  1530. Arguments:
  1531. SMB_PROCESSOR_PARAMETERS - See smbprocs.h for a description
  1532. of the parameters to SMB processor routines.
  1533. Return Value:
  1534. SMB_PROCESSOR_RETURN_TYPE - See smbprocs.h
  1535. --*/
  1536. {
  1537. PREQ_TREE_DISCONNECT request;
  1538. PRESP_TREE_DISCONNECT response;
  1539. PTREE_CONNECT treeConnect;
  1540. NTSTATUS status = STATUS_SUCCESS;
  1541. SMB_STATUS SmbStatus = SmbStatusInProgress;
  1542. PAGED_CODE( );
  1543. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  1544. WorkContext->PreviousSMB = EVENT_TYPE_SMB_TREE_DISCONNECT;
  1545. SrvWmiStartContext(WorkContext);
  1546. IF_SMB_DEBUG(TREE1) {
  1547. KdPrint(( "Tree disconnect request header at 0x%p, response header at 0x%p\n",
  1548. WorkContext->RequestHeader, WorkContext->ResponseHeader ));
  1549. KdPrint(( "Tree disconnect request parameters at 0x%p, response parameters at 0x%p\n",
  1550. WorkContext->RequestParameters,
  1551. WorkContext->ResponseParameters ));
  1552. }
  1553. //
  1554. // Set up parameters.
  1555. //
  1556. request = (PREQ_TREE_DISCONNECT)(WorkContext->RequestParameters);
  1557. response = (PRESP_TREE_DISCONNECT)(WorkContext->ResponseParameters);
  1558. //
  1559. // Find tree connect corresponding to given TID if a tree connect
  1560. // pointer has not already been put in the WorkContext block by an
  1561. // AndX command.
  1562. //
  1563. treeConnect = SrvVerifyTid(
  1564. WorkContext,
  1565. SmbGetAlignedUshort( &WorkContext->RequestHeader->Tid )
  1566. );
  1567. if ( treeConnect == NULL ) {
  1568. IF_DEBUG(SMB_ERRORS) {
  1569. KdPrint(( "SrvSmbTreeDisconnect: Invalid TID: 0x%lx\n",
  1570. SmbGetAlignedUshort( &WorkContext->RequestHeader->Tid ) ));
  1571. }
  1572. SrvSetSmbError( WorkContext, STATUS_SMB_BAD_TID );
  1573. status = STATUS_SMB_BAD_UID;
  1574. SmbStatus = SmbStatusSendResponse;
  1575. goto Cleanup;
  1576. }
  1577. //
  1578. // Do the actual tree disconnect.
  1579. //
  1580. SrvCloseTreeConnect( WorkContext->TreeConnect );
  1581. //
  1582. // Build the response SMB.
  1583. //
  1584. response->WordCount = 0;
  1585. SmbPutUshort( &response->ByteCount, 0 );
  1586. WorkContext->ResponseParameters = NEXT_LOCATION(
  1587. response,
  1588. RESP_TREE_DISCONNECT,
  1589. 0
  1590. );
  1591. SmbStatus = SmbStatusSendResponse;
  1592. IF_DEBUG(TRACE2) KdPrint(( "SrvSmbTreeDisconnect complete.\n" ));
  1593. Cleanup:
  1594. SrvWmiEndContext(WorkContext);
  1595. return SmbStatus;
  1596. } // SrvSmbTreeDisconnect