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.

1215 lines
38 KiB

  1. /*++
  2. Copyright (c) 1989 - 1999 Microsoft Corporation
  3. Module Name:
  4. smbadmin.c
  5. Abstract:
  6. This module implements the SMB's that need to be exchanged to facilitate
  7. bookkeeping at the server
  8. --*/
  9. #include "precomp.h"
  10. #pragma hdrstop
  11. #ifdef ALLOC_PRAGMA
  12. #pragma alloc_text(PAGE, SmbCeNegotiate)
  13. #pragma alloc_text(PAGE, SmbCeDisconnect)
  14. #pragma alloc_text(PAGE, SmbCeLogOff)
  15. #pragma alloc_text(PAGE, SmbCeInitializeAdminExchange)
  16. #pragma alloc_text(PAGE, SmbCeDiscardAdminExchange)
  17. #pragma alloc_text(PAGE, SmbCeCompleteAdminExchange)
  18. #pragma alloc_text(PAGE, SmbAdminExchangeStart)
  19. #endif
  20. //
  21. // The Bug check file id for this module
  22. //
  23. #define BugCheckFileId (RDBSS_BUG_CHECK_SMB_NETROOT)
  24. //
  25. // The local debug trace level
  26. //
  27. #define Dbg (DEBUG_TRACE_DISPATCH)
  28. extern
  29. SMB_EXCHANGE_DISPATCH_VECTOR EchoExchangeDispatch;
  30. extern NTSTATUS
  31. SmbCeInitializeAdminExchange(
  32. PSMB_ADMIN_EXCHANGE pSmbAdminExchange,
  33. PSMBCEDB_SERVER_ENTRY pServerEntry,
  34. PSMBCEDB_SESSION_ENTRY pSessionEntry,
  35. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry,
  36. UCHAR SmbCommand);
  37. extern VOID
  38. SmbCeDiscardAdminExchange(
  39. PSMB_ADMIN_EXCHANGE pSmbAdminExchange);
  40. extern NTSTATUS
  41. SmbCeCompleteAdminExchange(
  42. PSMB_ADMIN_EXCHANGE pSmbAdminExchange);
  43. VOID
  44. SmbReferenceRecord(
  45. PREFERENCE_RECORD pReferenceRecord,
  46. PVOID FileName,
  47. ULONG FileLine)
  48. {
  49. int i;
  50. for (i=REFERENCE_RECORD_SIZE-1;i>0;i--) {
  51. pReferenceRecord[i].FileName = pReferenceRecord[i-1].FileName;
  52. pReferenceRecord[i].FileLine = pReferenceRecord[i-1].FileLine;
  53. }
  54. pReferenceRecord[0].FileName = FileName;
  55. pReferenceRecord[0].FileLine = FileLine;
  56. }
  57. PSMB_EXCHANGE
  58. SmbSetServerEntryNegotiateExchange(
  59. PSMBCEDB_SERVER_ENTRY pServerEntry,
  60. PSMB_ADMIN_EXCHANGE pSmbAdminExchange)
  61. {
  62. PSMB_EXCHANGE pStoredExchange;
  63. SmbCeIncrementPendingLocalOperations((PSMB_EXCHANGE)pSmbAdminExchange);
  64. pStoredExchange = InterlockedCompareExchangePointer(
  65. &pServerEntry->pNegotiateExchange,
  66. pSmbAdminExchange,
  67. NULL);
  68. if (pStoredExchange != NULL) {
  69. SmbCeDecrementPendingLocalOperationsAndFinalize((PSMB_EXCHANGE)pSmbAdminExchange);
  70. }
  71. return pStoredExchange;
  72. }
  73. PSMB_EXCHANGE
  74. SmbResetServerEntryNegotiateExchange(
  75. PSMBCEDB_SERVER_ENTRY pServerEntry)
  76. {
  77. PSMB_EXCHANGE pStoredExchange;
  78. pStoredExchange = (PSMB_EXCHANGE)InterlockedCompareExchangePointer(
  79. &pServerEntry->pNegotiateExchange,
  80. NULL,
  81. pServerEntry->pNegotiateExchange);
  82. return pStoredExchange;
  83. }
  84. NTSTATUS
  85. SmbCeNegotiate(
  86. PSMBCEDB_SERVER_ENTRY pServerEntry,
  87. PMRX_SRV_CALL pSrvCall)
  88. /*++
  89. Routine Description:
  90. This routine issues the negotiate SMB to the server
  91. Arguments:
  92. pServerEntry - the server entry
  93. pSrvCall - the associated srv call instance in the wrapper
  94. Return Value:
  95. STATUS_SUCCESS - the server call construction has been finalized.
  96. Other Status codes correspond to error situations.
  97. Notes:
  98. Since the negotiate SMB can be directed at either a unknown server or a server
  99. whose capabilitiese are known it is upto the caller to decide to wait for the
  100. response.
  101. On some transports a reconnect is possible without having to tear down an existing
  102. connection, i.e. attempting to send a packet reestablishes the connection at the
  103. lower level. Since this is not supported by all the transports ( with the exception
  104. of TCP/IP) the reference server entry initiates this process by tearing down the
  105. existing transport and reinitializsing it.
  106. As part of the negotiate response the domain name to which the server belongs is
  107. sent back. Since the negotiate response is processed at DPC level, a preparatory
  108. allocation needs to be made ( This will ensure minimal work at DPC level).
  109. In this routine this is accomplished by allocating a buffer from nonpaged
  110. pool of MAX_PATH and associating it with the DomainName fild in the server entry
  111. prior to the TRanceive. On resumption from Tranceive this buffer is deallocated and
  112. a buffer from paged pool corresponding to the exact length is allocated to hold the
  113. domain name.
  114. --*/
  115. {
  116. NTSTATUS Status;
  117. PSMB_ADMIN_EXCHANGE pSmbAdminExchange;
  118. ULONG NegotiateSmbLength;
  119. PVOID pNegotiateSmb;
  120. PAGED_CODE();
  121. pSmbAdminExchange = (PSMB_ADMIN_EXCHANGE)SmbMmAllocateExchange(ADMIN_EXCHANGE,NULL);
  122. if (pSmbAdminExchange != NULL) {
  123. Status = SmbCeInitializeAdminExchange(
  124. pSmbAdminExchange,
  125. pServerEntry,
  126. NULL,
  127. NULL,
  128. SMB_COM_NEGOTIATE);
  129. if (Status == STATUS_SUCCESS) {
  130. // Build the negotiate SMB and allocate the temporary buffer for
  131. // the DOMAIN name.
  132. Status = BuildNegotiateSmb(
  133. &pNegotiateSmb,
  134. &NegotiateSmbLength);
  135. if (Status == STATUS_SUCCESS) {
  136. pSmbAdminExchange->pSmbBuffer = pNegotiateSmb;
  137. pSmbAdminExchange->SmbBufferLength = NegotiateSmbLength;
  138. // Preparatory allocation for the domain name buffer
  139. pSmbAdminExchange->Negotiate.pSrvCall = pSrvCall;
  140. pSmbAdminExchange->Negotiate.DomainName.Length = 0;
  141. pSmbAdminExchange->Negotiate.DomainName.MaximumLength = MAX_PATH;
  142. pSmbAdminExchange->Negotiate.DomainName.Buffer
  143. = (PWCHAR)RxAllocatePoolWithTag(
  144. NonPagedPool,
  145. MAX_PATH,
  146. MRXSMB_ADMIN_POOLTAG);
  147. if (pSmbAdminExchange->Negotiate.DomainName.Buffer == NULL) {
  148. Status = STATUS_INSUFFICIENT_RESOURCES;
  149. }
  150. }
  151. if (Status == STATUS_SUCCESS) {
  152. BOOLEAN fExchangeDiscarded = FALSE;
  153. SMBCE_RESUMPTION_CONTEXT ResumptionContext;
  154. PSMB_EXCHANGE pStoredExchange;
  155. SmbCeInitializeResumptionContext(&ResumptionContext);
  156. pSmbAdminExchange->pResumptionContext = &ResumptionContext;
  157. // Since the Negotiate SMB is the first SMB that is sent on a
  158. // connection the MID mapping data structures have not been setup.
  159. // Therefore a certain amount of additional initialization is
  160. // required to ensure that the Negotiate SMB can be handled correctly.
  161. // This involves presetting the MID field in the header and the
  162. // SMBCE_EXCHANGE_MID_VALID field in the exchange.
  163. //
  164. // A beneficial side effect of implementing it this way is the reduced
  165. // path length for the regular Send/Receives on a connection.
  166. pSmbAdminExchange->SmbCeFlags = (SMBCE_EXCHANGE_REUSE_MID |
  167. SMBCE_EXCHANGE_RETAIN_MID |
  168. SMBCE_EXCHANGE_TIMED_RECEIVE_OPERATION |
  169. SMBCE_EXCHANGE_MID_VALID);
  170. // Prevent the admin exchange from being finalized before returning back to this routine.
  171. SmbCeIncrementPendingLocalOperations((PSMB_EXCHANGE)pSmbAdminExchange);
  172. pStoredExchange = SmbSetServerEntryNegotiateExchange(
  173. pServerEntry,
  174. pSmbAdminExchange);
  175. if ((pServerEntry->Header.State == SMBCEDB_CONSTRUCTION_IN_PROGRESS) &&
  176. (pStoredExchange == NULL)) {
  177. // The Negotiate SMB exchange has been built successfully. Initiate it.
  178. Status = SmbCeInitiateExchange((PSMB_EXCHANGE)pSmbAdminExchange);
  179. if ((pSmbAdminExchange->SmbStatus != STATUS_SUCCESS) ||
  180. (Status != STATUS_PENDING && Status != STATUS_SUCCESS)) {
  181. pStoredExchange = (PSMB_EXCHANGE)InterlockedCompareExchangePointer(
  182. &pServerEntry->pNegotiateExchange,
  183. NULL,
  184. pSmbAdminExchange);
  185. if (pStoredExchange == (PSMB_EXCHANGE)pSmbAdminExchange) {
  186. SmbCeDecrementPendingLocalOperations((PSMB_EXCHANGE)pSmbAdminExchange);
  187. }
  188. if (pSmbAdminExchange->SmbStatus == STATUS_SUCCESS) {
  189. pSmbAdminExchange->SmbStatus = Status;
  190. }
  191. pSmbAdminExchange->Status = pSmbAdminExchange->SmbStatus;
  192. }
  193. // Admin exchange is ready to be finalized
  194. SmbCeDecrementPendingLocalOperationsAndFinalize((PSMB_EXCHANGE)pSmbAdminExchange);
  195. // Wait for the finalization.
  196. SmbCeSuspend(&ResumptionContext);
  197. Status = SmbCeCompleteAdminExchange(pSmbAdminExchange);
  198. } else {
  199. InterlockedCompareExchangePointer(
  200. &pServerEntry->pNegotiateExchange,
  201. NULL,
  202. pSmbAdminExchange);
  203. SmbCeDiscardAdminExchange(pSmbAdminExchange);
  204. Status = STATUS_CONNECTION_DISCONNECTED;
  205. }
  206. }
  207. } else {
  208. SmbMmFreeExchange((PSMB_EXCHANGE)pSmbAdminExchange);
  209. }
  210. } else {
  211. Status = STATUS_INSUFFICIENT_RESOURCES;
  212. }
  213. return Status;
  214. }
  215. NTSTATUS
  216. SmbCeSendEchoProbe(
  217. PSMBCEDB_SERVER_ENTRY pServerEntry,
  218. PMRXSMB_ECHO_PROBE_SERVICE_CONTEXT pEchoProbeContext)
  219. /*++
  220. Routine Description:
  221. This routine sends an echo probe to the specified server
  222. Arguments:
  223. pServerEntry - the server entry
  224. pEchoProbeCOntext - the echo probe context
  225. Return Value:
  226. STATUS_SUCCESS - the disconnect SMB was sent successfully
  227. Other Status codes correspond to error situations.
  228. Notes:
  229. --*/
  230. {
  231. NTSTATUS Status;
  232. PSMB_ADMIN_EXCHANGE pSmbAdminExchange;
  233. pSmbAdminExchange = (PSMB_ADMIN_EXCHANGE)SmbMmAllocateExchange(ADMIN_EXCHANGE,NULL);
  234. if (pSmbAdminExchange != NULL) {
  235. Status = SmbCeInitializeAdminExchange(
  236. pSmbAdminExchange,
  237. pServerEntry,
  238. NULL,
  239. NULL,
  240. SMB_COM_ECHO);
  241. if (Status == STATUS_SUCCESS) {
  242. ULONG EchoMdlSize;
  243. ULONG requestSize;
  244. pSmbAdminExchange->Mid = SMBCE_ECHO_PROBE_MID;
  245. pSmbAdminExchange->SmbCeFlags = (SMBCE_EXCHANGE_REUSE_MID |
  246. SMBCE_EXCHANGE_RETAIN_MID |
  247. SMBCE_EXCHANGE_TIMED_RECEIVE_OPERATION |
  248. SMBCE_EXCHANGE_MID_VALID);
  249. requestSize = pEchoProbeContext->EchoSmbLength + TRANSPORT_HEADER_SIZE;
  250. EchoMdlSize = (ULONG)MmSizeOfMdl(
  251. pEchoProbeContext->pEchoSmb,
  252. requestSize);
  253. pSmbAdminExchange->EchoProbe.pEchoProbeMdl =
  254. RxAllocatePoolWithTag(
  255. NonPagedPool,
  256. (EchoMdlSize + requestSize ),
  257. MRXSMB_ADMIN_POOLTAG);
  258. if (pSmbAdminExchange->EchoProbe.pEchoProbeMdl != NULL) {
  259. PBYTE pEchoProbeBuffer;
  260. pEchoProbeBuffer = (PBYTE)pSmbAdminExchange->EchoProbe.pEchoProbeMdl +
  261. EchoMdlSize + TRANSPORT_HEADER_SIZE;
  262. pSmbAdminExchange->EchoProbe.EchoProbeLength = pEchoProbeContext->EchoSmbLength;
  263. RtlCopyMemory(
  264. pEchoProbeBuffer,
  265. pEchoProbeContext->pEchoSmb,
  266. pEchoProbeContext->EchoSmbLength);
  267. RxInitializeHeaderMdl(
  268. pSmbAdminExchange->EchoProbe.pEchoProbeMdl,
  269. pEchoProbeBuffer,
  270. pEchoProbeContext->EchoSmbLength);
  271. MmBuildMdlForNonPagedPool(
  272. pSmbAdminExchange->EchoProbe.pEchoProbeMdl);
  273. InterlockedIncrement(&pServerEntry->Server.NumberOfEchoProbesSent);
  274. // The ECHO probe SMB exchange has been built successfully. Initiate it.
  275. Status = SmbCeInitiateExchange((PSMB_EXCHANGE)pSmbAdminExchange);
  276. } else {
  277. Status = STATUS_INSUFFICIENT_RESOURCES;
  278. }
  279. if (Status != STATUS_PENDING) {
  280. Status = SmbCeCompleteAdminExchange(pSmbAdminExchange);
  281. }
  282. } else {
  283. SmbMmFreeExchange((PSMB_EXCHANGE)pSmbAdminExchange);
  284. }
  285. } else {
  286. Status = STATUS_INSUFFICIENT_RESOURCES;
  287. }
  288. return Status;
  289. }
  290. NTSTATUS
  291. SmbCeDisconnect(
  292. PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext)
  293. /*++
  294. Routine Description:
  295. This routine issues the disconnect SMB for an existing connection to the server
  296. Arguments:
  297. pServerEntry - the server entry
  298. pVNetRootContext - the VNetRootContext
  299. Return Value:
  300. STATUS_SUCCESS - the disconnect SMB was sent successfully
  301. Other Status codes correspond to error situations.
  302. Notes:
  303. --*/
  304. {
  305. NTSTATUS Status;
  306. PSMB_ADMIN_EXCHANGE pSmbAdminExchange;
  307. PSMB_HEADER pSmbHeader;
  308. PREQ_TREE_DISCONNECT pReqTreeDisconnect;
  309. PAGED_CODE();
  310. pSmbAdminExchange = (PSMB_ADMIN_EXCHANGE)SmbMmAllocateExchange(ADMIN_EXCHANGE,NULL);
  311. if (pSmbAdminExchange != NULL) {
  312. UCHAR LastCommandInHeader;
  313. PUCHAR pCommand;
  314. Status = SmbCeInitializeAdminExchange(
  315. pSmbAdminExchange,
  316. pVNetRootContext->pServerEntry,
  317. pVNetRootContext->pSessionEntry,
  318. pVNetRootContext->pNetRootEntry,
  319. SMB_COM_TREE_DISCONNECT);
  320. if (Status == STATUS_SUCCESS) {
  321. BOOLEAN fExchangeDiscarded = FALSE;
  322. pSmbAdminExchange->pSmbBuffer =
  323. (PCHAR) pSmbAdminExchange->Disconnect.DisconnectSmb + TRANSPORT_HEADER_SIZE;
  324. pSmbHeader = (PSMB_HEADER)pSmbAdminExchange->pSmbBuffer;
  325. pReqTreeDisconnect = (PREQ_TREE_DISCONNECT)(pSmbHeader + 1);
  326. // Build the header
  327. Status = SmbCeBuildSmbHeader(
  328. (PSMB_EXCHANGE)pSmbAdminExchange,
  329. pSmbAdminExchange->pSmbBuffer,
  330. sizeof(SMB_HEADER),
  331. &pSmbAdminExchange->SmbBufferLength,
  332. &LastCommandInHeader,
  333. &pCommand);
  334. if (Status == STATUS_SUCCESS) {
  335. ASSERT(LastCommandInHeader == SMB_COM_NO_ANDX_COMMAND);
  336. *pCommand = SMB_COM_TREE_DISCONNECT;
  337. pSmbHeader->Tid = pVNetRootContext->TreeId;
  338. pReqTreeDisconnect->WordCount = 0;
  339. SmbPutUshort(&pReqTreeDisconnect->ByteCount,0);
  340. pSmbAdminExchange->SmbBufferLength += FIELD_OFFSET(REQ_TREE_DISCONNECT,Buffer);
  341. Status = SmbCeInitiateExchange((PSMB_EXCHANGE)pSmbAdminExchange);
  342. if ((Status == STATUS_PENDING) ||
  343. (Status == STATUS_SUCCESS)) {
  344. // async completion will also discard the exchange
  345. fExchangeDiscarded = TRUE;
  346. }
  347. }
  348. if (!fExchangeDiscarded) {
  349. SmbCeDiscardAdminExchange(pSmbAdminExchange);
  350. }
  351. } else {
  352. SmbMmFreeExchange((PSMB_EXCHANGE)pSmbAdminExchange);
  353. }
  354. } else {
  355. Status = STATUS_INSUFFICIENT_RESOURCES;
  356. }
  357. return Status;
  358. }
  359. NTSTATUS
  360. SmbCeLogOff(
  361. PSMBCEDB_SERVER_ENTRY pServerEntry,
  362. PSMBCEDB_SESSION_ENTRY pSessionEntry)
  363. /*++
  364. Routine Description:
  365. This routine issues the logoff SMB for an existing session to the server
  366. Arguments:
  367. pServerEntry - the server entry
  368. pSessionEntry - the associated session entry
  369. Return Value:
  370. STATUS_SUCCESS - the logoff was successfully sent.
  371. Other Status codes correspond to error situations.
  372. Notes:
  373. --*/
  374. {
  375. NTSTATUS Status;
  376. PSMB_ADMIN_EXCHANGE pSmbAdminExchange;
  377. PSMB_HEADER pSmbHeader;
  378. PREQ_LOGOFF_ANDX pReqLogOffAndX;
  379. PAGED_CODE();
  380. if (pServerEntry->Server.SecurityMode == SECURITY_MODE_SHARE_LEVEL) {
  381. if (pSessionEntry != NULL) {
  382. SmbCeDereferenceSessionEntry(pSessionEntry);
  383. }
  384. return STATUS_SUCCESS;
  385. }
  386. //
  387. // Some servers (like linux) don't really know how to handle session logoffs.
  388. // So, let's just be sure that we only do this to NT or better servers,
  389. // because we know that they handle it correctly. The version of Linux we have
  390. // seems to like to negotiate the NT dialect even though it really isn't NT. That's
  391. // why the extra check is put in here for NT status codes.
  392. //
  393. if( pServerEntry->Server.Dialect < NTLANMAN_DIALECT ||
  394. !FlagOn(pServerEntry->Server.DialectFlags,DF_NT_STATUS) ) {
  395. if (pSessionEntry != NULL) {
  396. SmbCeDereferenceSessionEntry(pSessionEntry);
  397. }
  398. return STATUS_SUCCESS;
  399. }
  400. pSmbAdminExchange = (PSMB_ADMIN_EXCHANGE)SmbMmAllocateExchange(ADMIN_EXCHANGE,NULL);
  401. if (pSmbAdminExchange != NULL) {
  402. UCHAR LastCommandInHeader;
  403. PUCHAR pCommand;
  404. Status = SmbCeInitializeAdminExchange(
  405. pSmbAdminExchange,
  406. pServerEntry,
  407. pSessionEntry,
  408. NULL,
  409. SMB_COM_LOGOFF_ANDX);
  410. if (Status == STATUS_SUCCESS) {
  411. BOOLEAN fExchangeDiscarded = FALSE;
  412. pSmbAdminExchange->pSmbBuffer =
  413. (PCHAR) pSmbAdminExchange->LogOff.LogOffSmb + TRANSPORT_HEADER_SIZE;
  414. pSmbHeader = (PSMB_HEADER)pSmbAdminExchange->pSmbBuffer;
  415. pReqLogOffAndX = (PREQ_LOGOFF_ANDX)(pSmbHeader + 1);
  416. // Build the header
  417. Status = SmbCeBuildSmbHeader(
  418. (PSMB_EXCHANGE)pSmbAdminExchange,
  419. pSmbAdminExchange->pSmbBuffer,
  420. sizeof(SMB_HEADER),
  421. &pSmbAdminExchange->SmbBufferLength,
  422. &LastCommandInHeader,
  423. &pCommand);
  424. if (Status == STATUS_SUCCESS) {
  425. ASSERT(LastCommandInHeader == SMB_COM_NO_ANDX_COMMAND);
  426. *pCommand = SMB_COM_LOGOFF_ANDX;
  427. pReqLogOffAndX->WordCount = 2;
  428. pReqLogOffAndX->AndXCommand = SMB_COM_NO_ANDX_COMMAND;
  429. pReqLogOffAndX->AndXReserved = 0;
  430. SmbPutUshort(&pReqLogOffAndX->AndXOffset,0);
  431. SmbPutUshort(&pReqLogOffAndX->ByteCount,0);
  432. pSmbAdminExchange->SmbBufferLength += FIELD_OFFSET(REQ_LOGOFF_ANDX,Buffer);
  433. Status = SmbCeInitiateExchange((PSMB_EXCHANGE)pSmbAdminExchange);
  434. if ((Status == STATUS_PENDING) ||
  435. (Status == STATUS_SUCCESS)) {
  436. // async completion will discard the exchange
  437. fExchangeDiscarded = TRUE;
  438. }
  439. }
  440. if (!fExchangeDiscarded) {
  441. SmbCeDiscardAdminExchange(pSmbAdminExchange);
  442. }
  443. } else {
  444. SmbMmFreeExchange((PSMB_EXCHANGE)pSmbAdminExchange);
  445. }
  446. } else {
  447. Status = STATUS_INSUFFICIENT_RESOURCES;
  448. }
  449. return Status;
  450. }
  451. NTSTATUS
  452. SmbCeInitializeAdminExchange(
  453. PSMB_ADMIN_EXCHANGE pSmbAdminExchange,
  454. PSMBCEDB_SERVER_ENTRY pServerEntry,
  455. PSMBCEDB_SESSION_ENTRY pSessionEntry,
  456. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry,
  457. UCHAR SmbCommand)
  458. /*++
  459. Routine Description:
  460. This routine initializes the ADMIN exchange
  461. Arguments:
  462. pSmbAdminExchange - the exchange
  463. pServerEntry - the associated server entry
  464. pSessionEntry - the associated session entry
  465. pNetRootEntry - the associated net root entry
  466. SmbCommand - the SMB command
  467. Return Value:
  468. STATUS_SUCCESS - the logoff was successfully sent.
  469. Other Status codes correspond to error situations.
  470. Notes:
  471. The ADMIN_EXCHANGE is a special type of exchange used for bootstrap/teardown
  472. situations in which the initialization of the exchange cannot follow the noraml
  473. course of events. In some cases not all the components required for proper
  474. initialization of the exchange are present, e.g., NEGOTIATE we do not have a
  475. valid session/tree connect. It is for this reason that the three important
  476. elements of initialization, i.e., Server/Session/NetRoot have to be explicitly
  477. specified. NULL is used to signify a dont care situation for a particular component.
  478. --*/
  479. {
  480. NTSTATUS Status;
  481. PAGED_CODE();
  482. Status = SmbCeIncrementActiveExchangeCount();
  483. if (Status == STATUS_SUCCESS) {
  484. PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext;
  485. pSmbAdminExchange->CancellationStatus = SMBCE_EXCHANGE_NOT_CANCELLED;
  486. if ((SmbCommand == SMB_COM_NEGOTIATE) ||
  487. (SmbCommand == SMB_COM_ECHO)) {
  488. pSmbAdminExchange->SmbCeContext.pServerEntry = pServerEntry;
  489. pSmbAdminExchange->SmbCeContext.pVNetRootContext = NULL;
  490. } else {
  491. pVNetRootContext = (PSMBCE_V_NET_ROOT_CONTEXT)
  492. RxAllocatePoolWithTag(
  493. NonPagedPool,
  494. sizeof(SMBCE_V_NET_ROOT_CONTEXT),
  495. MRXSMB_VNETROOT_POOLTAG);
  496. if (pVNetRootContext != NULL) {
  497. pVNetRootContext->pServerEntry = pServerEntry;
  498. pVNetRootContext->pSessionEntry = pSessionEntry;
  499. pVNetRootContext->pNetRootEntry = pNetRootEntry;
  500. pSmbAdminExchange->SmbCeContext.pVNetRootContext = pVNetRootContext;
  501. pSmbAdminExchange->SmbCeContext.pServerEntry = pServerEntry;
  502. } else {
  503. Status = STATUS_INSUFFICIENT_RESOURCES;
  504. }
  505. }
  506. if (Status == STATUS_SUCCESS) {
  507. SmbCeReferenceServerEntry(pServerEntry);
  508. pSmbAdminExchange->pSmbMdl = NULL;
  509. pSmbAdminExchange->pSmbBuffer = NULL;
  510. pSmbAdminExchange->SmbBufferLength = 0;
  511. // Set the SmbCe state to overrule the common method of having to hunt
  512. // up a valid TID/FID etc. and reconnects.
  513. pSmbAdminExchange->SmbCommand = SmbCommand;
  514. pSmbAdminExchange->SmbCeState = SMBCE_EXCHANGE_NETROOT_INITIALIZED;
  515. switch (pSmbAdminExchange->SmbCommand) {
  516. case SMB_COM_NEGOTIATE:
  517. {
  518. pSmbAdminExchange->Negotiate.DomainName.Length = 0;
  519. pSmbAdminExchange->Negotiate.DomainName.MaximumLength = 0;
  520. pSmbAdminExchange->Negotiate.DomainName.Buffer = NULL;
  521. pSmbAdminExchange->Negotiate.pNegotiateMdl = NULL;
  522. }
  523. break;
  524. case SMB_COM_TREE_DISCONNECT:
  525. case SMB_COM_LOGOFF_ANDX:
  526. break;
  527. case SMB_COM_ECHO:
  528. {
  529. pSmbAdminExchange->pDispatchVector = &EchoExchangeDispatch;
  530. pSmbAdminExchange->EchoProbe.pEchoProbeMdl = NULL;
  531. pSmbAdminExchange->EchoProbe.EchoProbeLength = 0;
  532. }
  533. break;
  534. default:
  535. ASSERT(!"Valid Command for Admin Exchange");
  536. break;
  537. }
  538. }
  539. }
  540. return Status;
  541. }
  542. VOID
  543. SmbCeDiscardAdminExchange(
  544. PSMB_ADMIN_EXCHANGE pSmbAdminExchange)
  545. /*++
  546. Routine Description:
  547. This routine discards the ADMIN exchange
  548. Arguments:
  549. pSmbAdminExchange - the exchange
  550. --*/
  551. {
  552. PSMBCEDB_SERVER_ENTRY pServerEntry;
  553. PSMBCEDB_SESSION_ENTRY pSessionEntry;
  554. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry;
  555. PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext;
  556. PAGED_CODE();
  557. SmbCeAcquireResource();
  558. RemoveEntryList(&pSmbAdminExchange->ExchangeList);
  559. SmbCeReleaseResource();
  560. pServerEntry = SmbCeGetExchangeServerEntry(pSmbAdminExchange);
  561. pSessionEntry = SmbCeGetExchangeSessionEntry(pSmbAdminExchange);
  562. pNetRootEntry = SmbCeGetExchangeNetRootEntry(pSmbAdminExchange);
  563. pVNetRootContext = SmbCeGetExchangeVNetRootContext(pSmbAdminExchange);
  564. if (pSmbAdminExchange->pSmbMdl != NULL) {
  565. RxUnlockHeaderPages(pSmbAdminExchange->pSmbMdl);
  566. IoFreeMdl(pSmbAdminExchange->pSmbMdl);
  567. }
  568. switch (pSmbAdminExchange->SmbCommand) {
  569. case SMB_COM_NEGOTIATE:
  570. {
  571. pSmbAdminExchange->pSmbBuffer = NULL;
  572. if (pSmbAdminExchange->Negotiate.DomainName.Buffer != NULL) {
  573. RxFreePool(
  574. pSmbAdminExchange->Negotiate.DomainName.Buffer);
  575. }
  576. if (pSmbAdminExchange->Negotiate.pNegotiateMdl != NULL) {
  577. IoFreeMdl(
  578. pSmbAdminExchange->Negotiate.pNegotiateMdl);
  579. }
  580. }
  581. break;
  582. case SMB_COM_TREE_DISCONNECT:
  583. break;
  584. case SMB_COM_LOGOFF_ANDX:
  585. {
  586. SmbCeUpdateSessionEntryState(pSessionEntry,SMBCEDB_MARKED_FOR_DELETION);
  587. SmbCeDereferenceSessionEntry(pSessionEntry);
  588. }
  589. break;
  590. case SMB_COM_ECHO:
  591. {
  592. if (pSmbAdminExchange->EchoProbe.pEchoProbeMdl != NULL) {
  593. MmPrepareMdlForReuse(pSmbAdminExchange->EchoProbe.pEchoProbeMdl);
  594. RxFreePool(pSmbAdminExchange->EchoProbe.pEchoProbeMdl);
  595. }
  596. }
  597. break;
  598. default:
  599. ASSERT(!"Valid Command For Admin Exchange");
  600. break;
  601. }
  602. // Tear down all the copy data requests associated with this exchange
  603. SmbCePurgeBuffersAssociatedWithExchange(pServerEntry,(PSMB_EXCHANGE)pSmbAdminExchange);
  604. SmbCeUninitializeExchangeTransport((PSMB_EXCHANGE)pSmbAdminExchange);
  605. SmbCeDereferenceServerEntry(pServerEntry);
  606. if (pVNetRootContext != NULL) {
  607. RxFreePool(pVNetRootContext);
  608. }
  609. SmbMmFreeExchange((PSMB_EXCHANGE)pSmbAdminExchange);
  610. SmbCeDecrementActiveExchangeCount();
  611. }
  612. NTSTATUS
  613. SmbCeCompleteAdminExchange(
  614. PSMB_ADMIN_EXCHANGE pSmbAdminExchange)
  615. /*++
  616. Routine Description:
  617. This is the routine used for completing the SMB ADMIN exchanges.
  618. Arguments:
  619. pExchange - the exchange instance
  620. Return Value:
  621. RXSTATUS - The return status for the operation
  622. Notes:
  623. This routine encapsulates the TAIL for all SMB admin exchanges. They carry
  624. out the local action required based upon the outcome of the exchange.
  625. --*/
  626. {
  627. NTSTATUS Status = STATUS_SUCCESS;
  628. PSMBCEDB_SERVER_ENTRY pServerEntry;
  629. SMBCEDB_OBJECT_STATE ServerState;
  630. PAGED_CODE();
  631. pServerEntry = SmbCeGetExchangeServerEntry(pSmbAdminExchange);
  632. switch (pSmbAdminExchange->SmbCommand) {
  633. case SMB_COM_NEGOTIATE:
  634. {
  635. if (pSmbAdminExchange->Status != STATUS_SUCCESS) {
  636. pServerEntry->ServerStatus = pSmbAdminExchange->Status;
  637. }
  638. if (pServerEntry->ServerStatus == STATUS_SUCCESS) {
  639. if (pServerEntry->DomainName.Buffer) {
  640. RxFreePool(pServerEntry->DomainName.Buffer);
  641. pServerEntry->DomainName.Buffer = NULL;
  642. }
  643. pServerEntry->DomainName.Length = pSmbAdminExchange->Negotiate.DomainName.Length;
  644. pServerEntry->DomainName.MaximumLength = pServerEntry->DomainName.Length;
  645. if (pServerEntry->DomainName.Length > 0) {
  646. pServerEntry->DomainName.Buffer = RxAllocatePoolWithTag(
  647. NonPagedPool,
  648. pServerEntry->DomainName.Length,
  649. MRXSMB_SERVER_POOLTAG);
  650. }
  651. if (pServerEntry->DomainName.Buffer != NULL) {
  652. // Copy the domain name into the server entry
  653. RtlCopyMemory(
  654. pServerEntry->DomainName.Buffer,
  655. pSmbAdminExchange->Negotiate.DomainName.Buffer,
  656. pServerEntry->DomainName.Length);
  657. } else {
  658. //The downlevel server doesn't have a domain name. It's not a problem if the
  659. //DomainName.Buffer equals to NULL.
  660. if (pServerEntry->DomainName.Length > 0) {
  661. pServerEntry->DomainName.Length = 0;
  662. pServerEntry->DomainName.MaximumLength = 0;
  663. pServerEntry->ServerStatus = STATUS_INSUFFICIENT_RESOURCES;
  664. }
  665. }
  666. if (pServerEntry->ServerStatus == STATUS_SUCCESS) {
  667. pServerEntry->ServerStatus = SmbCeUpdateSrvCall(pServerEntry);
  668. }
  669. }
  670. Status = pServerEntry->ServerStatus;
  671. if (pServerEntry->ServerStatus == STATUS_SUCCESS) {
  672. pServerEntry->Server.EchoProbeState = ECHO_PROBE_IDLE;
  673. }
  674. }
  675. break;
  676. case SMB_COM_TREE_DISCONNECT:
  677. case SMB_COM_LOGOFF_ANDX:
  678. case SMB_COM_ECHO:
  679. default:
  680. break;
  681. }
  682. SmbCeDiscardAdminExchange(pSmbAdminExchange);
  683. return Status;
  684. }
  685. NTSTATUS
  686. SmbAdminExchangeStart(
  687. PSMB_EXCHANGE pExchange)
  688. /*++
  689. Routine Description:
  690. This is the start routine for administrative SMB exchanges.
  691. Arguments:
  692. pExchange - the exchange instance
  693. Return Value:
  694. RXSTATUS - The return status for the operation
  695. --*/
  696. {
  697. NTSTATUS Status;
  698. PSMB_ADMIN_EXCHANGE pSmbAdminExchange;
  699. PAGED_CODE();
  700. pSmbAdminExchange = (PSMB_ADMIN_EXCHANGE)pExchange;
  701. switch (pSmbAdminExchange->SmbCommand) {
  702. case SMB_COM_NEGOTIATE:
  703. case SMB_COM_LOGOFF_ANDX:
  704. case SMB_COM_TREE_DISCONNECT:
  705. {
  706. ASSERT(pSmbAdminExchange->pSmbMdl == NULL);
  707. RxAllocateHeaderMdl(
  708. pSmbAdminExchange->pSmbBuffer,
  709. pSmbAdminExchange->SmbBufferLength,
  710. pSmbAdminExchange->pSmbMdl
  711. );
  712. if (pSmbAdminExchange->pSmbMdl != NULL) {
  713. RxProbeAndLockHeaderPages(
  714. pSmbAdminExchange->pSmbMdl,
  715. KernelMode,
  716. IoModifyAccess,
  717. Status);
  718. if (Status == STATUS_SUCCESS) {
  719. Status = SmbCeTranceive(
  720. pExchange,
  721. RXCE_SEND_SYNCHRONOUS,
  722. pSmbAdminExchange->pSmbMdl,
  723. pSmbAdminExchange->SmbBufferLength);
  724. RxDbgTrace( 0, Dbg, ("Net Root SmbCeTranceive returned %lx\n",Status));
  725. } else {
  726. IoFreeMdl(pSmbAdminExchange->pSmbMdl);
  727. pSmbAdminExchange->pSmbMdl = NULL;
  728. }
  729. } else {
  730. Status = STATUS_INSUFFICIENT_RESOURCES;
  731. }
  732. }
  733. break;
  734. case SMB_COM_ECHO:
  735. {
  736. Status = SmbCeSend(
  737. pExchange,
  738. 0,
  739. pSmbAdminExchange->EchoProbe.pEchoProbeMdl,
  740. pSmbAdminExchange->EchoProbe.EchoProbeLength);
  741. }
  742. break;
  743. default:
  744. break;
  745. }
  746. return Status;
  747. }
  748. NTSTATUS
  749. SmbAdminExchangeReceive(
  750. IN struct _SMB_EXCHANGE *pExchange, // The exchange instance
  751. IN ULONG BytesIndicated,
  752. IN ULONG BytesAvailable,
  753. OUT ULONG *pBytesTaken,
  754. IN PSMB_HEADER pSmbHeader,
  755. OUT PMDL *pDataBufferPointer,
  756. OUT PULONG pDataSize,
  757. IN ULONG ReceiveFlags)
  758. /*++
  759. Routine Description:
  760. This is the recieve indication handling routine for net root construction exchanges
  761. Arguments:
  762. pExchange - the exchange instance
  763. BytesIndicated - the number of bytes indicated
  764. Bytes Available - the number of bytes available
  765. pBytesTaken - the number of bytes consumed
  766. pSmbHeader - the byte buffer
  767. pDataBufferPointer - the buffer into which the remaining data is to be copied.
  768. pDataSize - the buffer size.
  769. Return Value:
  770. RXSTATUS - The return status for the operation
  771. Notes:
  772. This routine is called at DPC level.
  773. --*/
  774. {
  775. NTSTATUS Status;
  776. PSMB_ADMIN_EXCHANGE pSmbAdminExchange;
  777. RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("ParseSmbHeader BytesIndicated/Available %ld %ld\n",BytesIndicated,BytesAvailable));
  778. pSmbAdminExchange = (PSMB_ADMIN_EXCHANGE)pExchange;
  779. switch (pSmbAdminExchange->SmbCommand) {
  780. case SMB_COM_NEGOTIATE:
  781. {
  782. Status = ParseNegotiateResponse(
  783. pSmbAdminExchange,
  784. BytesIndicated,
  785. BytesAvailable,
  786. pBytesTaken,
  787. pSmbHeader,
  788. pDataBufferPointer,
  789. pDataSize);
  790. if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
  791. if (*pDataBufferPointer != NULL &&
  792. ((*pBytesTaken + *pDataSize) <= BytesAvailable ||
  793. !FlagOn(ReceiveFlags,TDI_RECEIVE_ENTIRE_MESSAGE))) {
  794. pSmbAdminExchange->Negotiate.pNegotiateMdl = *pDataBufferPointer;
  795. } else {
  796. *pBytesTaken = BytesAvailable;
  797. Status = STATUS_SUCCESS;
  798. pExchange->Status = STATUS_INVALID_NETWORK_RESPONSE;
  799. }
  800. }
  801. }
  802. break;
  803. case SMB_COM_TREE_DISCONNECT:
  804. case SMB_COM_LOGOFF_ANDX:
  805. {
  806. *pBytesTaken = BytesAvailable;
  807. Status = STATUS_SUCCESS;
  808. }
  809. break;
  810. case SMB_COM_ECHO:
  811. // Since the echo probe responses are handled by the receive indication routine
  812. // at DPC level this routine should never be called for echo probes.
  813. default:
  814. {
  815. *pBytesTaken = 0;
  816. Status = STATUS_DATA_NOT_ACCEPTED;
  817. }
  818. break;
  819. }
  820. return Status;
  821. }
  822. NTSTATUS
  823. SmbAdminExchangeCopyDataHandler(
  824. IN PSMB_EXCHANGE pExchange, // The exchange instance
  825. IN PMDL pCopyDataBuffer,
  826. IN ULONG DataSize)
  827. /*++
  828. Routine Description:
  829. This is the copy data handling routine for administrative SMB exchanges
  830. Arguments:
  831. pExchange - the exchange instance
  832. Return Value:
  833. RXSTATUS - The return status for the operation
  834. --*/
  835. {
  836. UNREFERENCED_PARAMETER(pExchange);
  837. return STATUS_SUCCESS;
  838. }
  839. NTSTATUS
  840. SmbAdminExchangeSendCallbackHandler(
  841. IN PSMB_EXCHANGE pExchange,
  842. IN PMDL pXmitBuffer,
  843. IN NTSTATUS SendCompletionStatus)
  844. /*++
  845. Routine Description:
  846. This is the send call back indication handling routine for transact exchanges
  847. Arguments:
  848. pExchange - the exchange instance
  849. Return Value:
  850. NTSTATUS - The return status for the operation
  851. --*/
  852. {
  853. return STATUS_SUCCESS;
  854. UNREFERENCED_PARAMETER(pExchange);
  855. UNREFERENCED_PARAMETER(pXmitBuffer);
  856. UNREFERENCED_PARAMETER(SendCompletionStatus);
  857. }
  858. NTSTATUS
  859. SmbAdminExchangeFinalize(
  860. PSMB_EXCHANGE pExchange,
  861. BOOLEAN *pPostFinalize)
  862. /*++
  863. Routine Description:
  864. This routine finalkzes the construct net root exchange. It resumes the RDBSS by invoking
  865. the call back and discards the exchange
  866. Arguments:
  867. pExchange - the exchange instance
  868. CurrentIrql - the current interrupt request level
  869. pPostFinalize - a pointer to a BOOLEAN if the request should be posted
  870. Return Value:
  871. RXSTATUS - The return status for the operation
  872. --*/
  873. {
  874. PSMB_ADMIN_EXCHANGE pSmbAdminExchange = (PSMB_ADMIN_EXCHANGE)pExchange;
  875. if (pSmbAdminExchange->pResumptionContext != NULL) {
  876. // Signal the event
  877. *pPostFinalize = FALSE;
  878. SmbCeResume(pSmbAdminExchange->pResumptionContext);
  879. } else {
  880. if (RxShouldPostCompletion()) {
  881. *pPostFinalize = TRUE;
  882. return STATUS_SUCCESS;
  883. } else {
  884. *pPostFinalize = FALSE;
  885. SmbCeCompleteAdminExchange(pSmbAdminExchange);
  886. }
  887. }
  888. return STATUS_SUCCESS;
  889. }
  890. SMB_EXCHANGE_DISPATCH_VECTOR
  891. AdminExchangeDispatch = {
  892. SmbAdminExchangeStart,
  893. SmbAdminExchangeReceive,
  894. SmbAdminExchangeCopyDataHandler,
  895. NULL, // No Send Completion handler
  896. SmbAdminExchangeFinalize
  897. };
  898. SMB_EXCHANGE_DISPATCH_VECTOR
  899. EchoExchangeDispatch = {
  900. SmbAdminExchangeStart,
  901. SmbAdminExchangeReceive,
  902. SmbAdminExchangeCopyDataHandler,
  903. SmbAdminExchangeSendCallbackHandler,
  904. SmbAdminExchangeFinalize
  905. };
  906.