Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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