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.

1284 lines
40 KiB

  1. /*++
  2. Copyright (c) 1987-1999 Microsoft Corporation
  3. Module Name:
  4. srvcall.c
  5. Abstract:
  6. This module implements the routines for handling the creation/manipulation of
  7. server entries in the connection engine database. It also contains the routines
  8. for parsing the negotiate response from the server.
  9. --*/
  10. #include "precomp.h"
  11. #pragma hdrstop
  12. #ifdef ALLOC_PRAGMA
  13. #pragma alloc_text(PAGE, SmbCeCreateSrvCall)
  14. #pragma alloc_text(PAGE, MRxSmbCreateSrvCall)
  15. #pragma alloc_text(PAGE, MRxSmbFinalizeSrvCall)
  16. #pragma alloc_text(PAGE, MRxSmbSrvCallWinnerNotify)
  17. #pragma alloc_text(PAGE, MRxSmbInitializeEchoProbeService)
  18. #pragma alloc_text(PAGE, MRxSmbTearDownEchoProbeService)
  19. #pragma alloc_text(PAGE, BuildNegotiateSmb)
  20. #endif
  21. RXDT_DefineCategory(SRVCALL);
  22. #define Dbg (DEBUG_TRACE_SRVCALL)
  23. VOID
  24. SmbCeCreateSrvCall(
  25. PMRX_SRVCALL_CALLBACK_CONTEXT pCallbackContext)
  26. /*++
  27. Routine Description:
  28. This routine patches the RDBSS created srv call instance with the information required
  29. by the mini redirector.
  30. Arguments:
  31. CallBackContext - the call back context in RDBSS for continuation.
  32. Return Value:
  33. RXSTATUS - The return status for the operation
  34. --*/
  35. {
  36. NTSTATUS Status;
  37. PMRX_SRVCALLDOWN_STRUCTURE SrvCalldownStructure;
  38. PMRX_SRV_CALL pSrvCall;
  39. PAGED_CODE();
  40. SrvCalldownStructure =
  41. (PMRX_SRVCALLDOWN_STRUCTURE)(pCallbackContext->SrvCalldownStructure);
  42. pSrvCall = SrvCalldownStructure->SrvCall;
  43. ASSERT( pSrvCall );
  44. ASSERT( NodeType(pSrvCall) == RDBSS_NTC_SRVCALL );
  45. SmbCeInitializeServerEntry(
  46. pSrvCall,
  47. pCallbackContext,
  48. SrvCalldownStructure->RxContext->Create.TreeConnectOpenDeferred);
  49. }
  50. NTSTATUS
  51. MRxSmbCreateSrvCall(
  52. PMRX_SRV_CALL pSrvCall,
  53. PMRX_SRVCALL_CALLBACK_CONTEXT pCallbackContext)
  54. /*++
  55. Routine Description:
  56. This routine patches the RDBSS created srv call instance with the information required
  57. by the mini redirector.
  58. Arguments:
  59. RxContext - Supplies the context of the original create/ioctl
  60. CallBackContext - the call back context in RDBSS for continuation.
  61. Return Value:
  62. RXSTATUS - The return status for the operation
  63. Notes:
  64. Certain transport related interfaces require handle to be passed in. This
  65. implies that the SRV_CALL instances need to be initialized in the context
  66. of a well known process, i.e., the RDBSS process.
  67. In the normal course of event is this request was issued within the context
  68. of the system process we should continue without having to post. However
  69. there are cases in MIPS when stack overflows. In order to avoid such situations
  70. the request is posted in all cases.
  71. --*/
  72. {
  73. NTSTATUS Status;
  74. UNICODE_STRING ServerName;
  75. PMRX_SRVCALL_CALLBACK_CONTEXT SCCBC = pCallbackContext;
  76. PMRX_SRVCALLDOWN_STRUCTURE SrvCalldownStructure = (PMRX_SRVCALLDOWN_STRUCTURE)(pCallbackContext->SrvCalldownStructure);
  77. PAGED_CODE();
  78. ASSERT( pSrvCall );
  79. ASSERT( NodeType(pSrvCall) == RDBSS_NTC_SRVCALL );
  80. // Dispatch the request to a system thread.
  81. Status = RxDispatchToWorkerThread(
  82. MRxSmbDeviceObject,
  83. DelayedWorkQueue,
  84. SmbCeCreateSrvCall,
  85. pCallbackContext);
  86. if (Status == STATUS_SUCCESS) {
  87. // Map the return value since the wrapper expects PENDING.
  88. Status = STATUS_PENDING;
  89. } else {
  90. // There was an error in dispatching the SmbCeCreateSrvCall method to
  91. // a worker thread. Complete the request and return STATUS_PENDING.
  92. SCCBC->Status = Status;
  93. SrvCalldownStructure->CallBack(SCCBC);
  94. Status = STATUS_PENDING;
  95. }
  96. return Status;
  97. }
  98. NTSTATUS
  99. MRxSmbFinalizeSrvCall(
  100. PMRX_SRV_CALL pSrvCall,
  101. BOOLEAN Force)
  102. /*++
  103. Routine Description:
  104. This routine destroys a given server call instance
  105. Arguments:
  106. pSrvCall - the server call instance to be disconnected.
  107. Force - TRUE if a disconnection is to be enforced immediately.
  108. Return Value:
  109. RXSTATUS - The return status for the operation
  110. --*/
  111. {
  112. NTSTATUS Status = STATUS_SUCCESS;
  113. PSMBCEDB_SERVER_ENTRY pServerEntry;
  114. PAGED_CODE();
  115. // if the server entry is not filled in, then there's nothing to do. this occurs
  116. // on a srvcall that we never successfuly hooked up to........
  117. if (pSrvCall->Context == NULL) {
  118. return(Status);
  119. }
  120. pServerEntry = SmbCeGetAssociatedServerEntry(pSrvCall);
  121. if (pServerEntry != NULL) {
  122. InterlockedCompareExchangePointer(
  123. &pServerEntry->pRdbssSrvCall,
  124. NULL,
  125. pSrvCall);
  126. SmbCeDereferenceServerEntry(pServerEntry);
  127. }
  128. pSrvCall->Context = NULL;
  129. return Status;
  130. }
  131. NTSTATUS
  132. MRxSmbSrvCallWinnerNotify(
  133. IN PMRX_SRV_CALL pSrvCall,
  134. IN BOOLEAN ThisMinirdrIsTheWinner,
  135. IN OUT PVOID pSrvCallContext)
  136. /*++
  137. Routine Description:
  138. This routine finalizes the mini rdr context associated with an RDBSS Server call instance
  139. Arguments:
  140. pSrvCall - the Server Call
  141. ThisMinirdrIsTheWinner - TRUE if this mini rdr is the choosen one.
  142. pSrvCallContext - the server call context created by the mini redirector.
  143. Return Value:
  144. RXSTATUS - The return status for the operation
  145. Notes:
  146. The two phase construction protocol for Server calls is required because of parallel
  147. initiation of a number of mini redirectors. The RDBSS finalizes the particular mini
  148. redirector to be used in communicating with a given server based on quality of
  149. service criterion.
  150. --*/
  151. {
  152. NTSTATUS Status = STATUS_SUCCESS;
  153. PSMBCEDB_SERVER_ENTRY pServerEntry;
  154. PAGED_CODE();
  155. pServerEntry = (PSMBCEDB_SERVER_ENTRY)pSrvCallContext;
  156. if (!ThisMinirdrIsTheWinner) {
  157. //
  158. // Some other mini rdr has been choosen to connect to the server. Destroy
  159. // the data structures created for this mini redirector.
  160. //
  161. SmbCeUpdateServerEntryState(pServerEntry,SMBCEDB_MARKED_FOR_DELETION);
  162. SmbCeDereferenceServerEntry(pServerEntry);
  163. return STATUS_SUCCESS;
  164. }
  165. pSrvCall->Context = pServerEntry;
  166. pSrvCall->Flags |= SRVCALL_FLAG_CASE_INSENSITIVE_NETROOTS |
  167. SRVCALL_FLAG_CASE_INSENSITIVE_FILENAMES;
  168. pSrvCall->MaximumNumberOfCloseDelayedFiles = MRxSmbConfiguration.DormantFileLimit + 1;
  169. pServerEntry->Server.IsLoopBack = FALSE;
  170. return STATUS_SUCCESS;
  171. }
  172. //
  173. // The following type defines and data structures are used for parsing negotiate SMB
  174. // responses.
  175. //
  176. typedef enum _SMB_NEGOTIATE_TYPE_ {
  177. SMB_CORE_NEGOTIATE,
  178. SMB_EXTENDED_NEGOTIATE,
  179. SMB_NT_NEGOTIATE
  180. } SMB_NEGOTIATE_TYPE, *PSMB_NEGOTIATE_TYPE;
  181. typedef struct _SMB_DIALECTS_ {
  182. SMB_NEGOTIATE_TYPE NegotiateType;
  183. USHORT DispatchVectorIndex;
  184. } SMB_DIALECTS, *PSMB_DIALECTS;
  185. SMBCE_SERVER_DISPATCH_VECTOR
  186. s_SmbServerDispatchVectors[] = {
  187. {BuildSessionSetupSmb,CoreBuildTreeConnectSmb},
  188. {BuildSessionSetupSmb,LmBuildTreeConnectSmb},
  189. {BuildSessionSetupSmb,NtBuildTreeConnectSmb},
  190. };
  191. SMB_DIALECTS
  192. s_SmbDialects[] = {
  193. { SMB_CORE_NEGOTIATE, 0},
  194. //{ SMB_CORE_NEGOTIATE, 0 },
  195. //{ SMB_EXTENDED_NEGOTIATE, 1 },
  196. { SMB_EXTENDED_NEGOTIATE, 1 },
  197. { SMB_EXTENDED_NEGOTIATE, 1 },
  198. { SMB_EXTENDED_NEGOTIATE, 1 },
  199. { SMB_EXTENDED_NEGOTIATE, 1 },
  200. { SMB_NT_NEGOTIATE, 2 },
  201. };
  202. CHAR s_DialectNames[] = {
  203. "\2" PCNET1 "\0"
  204. //\2notyet" XENIXCORE "\0"
  205. //\2notyet" MSNET103 "\0"
  206. "\2" LANMAN10 "\0"
  207. "\2" WFW10 "\0"
  208. "\2" LANMAN12
  209. "\0\2" LANMAN21
  210. // "\0\2" NTLANMAN
  211. };
  212. #define __second(a,b) (b)
  213. ULONG
  214. MRxSmbDialectFlags[] = {
  215. __second( PCNET1, DF_CORE ),
  216. //__second( XENIXCORE, DF_CORE | DF_MIXEDCASEPW | DF_MIXEDCASE ),
  217. //__second( MSNET103, DF_CORE | DF_OLDRAWIO | DF_LOCKREAD | DF_EXTENDNEGOT ),
  218. __second( LANMAN10, DF_CORE | DF_NEWRAWIO | DF_LOCKREAD | DF_EXTENDNEGOT |
  219. DF_LANMAN10 ),
  220. __second( WFW10, DF_CORE | DF_NEWRAWIO | DF_LOCKREAD | DF_EXTENDNEGOT |
  221. DF_LANMAN10 | DF_WFW),
  222. __second( LANMAN12, DF_CORE | DF_NEWRAWIO | DF_LOCKREAD | DF_EXTENDNEGOT |
  223. DF_LANMAN10 | DF_LANMAN20 |
  224. DF_MIXEDCASE | DF_LONGNAME | DF_SUPPORTEA ),
  225. __second( LANMAN21, DF_CORE | DF_NEWRAWIO | DF_LOCKREAD | DF_EXTENDNEGOT |
  226. DF_LANMAN10 | DF_LANMAN20 |
  227. DF_MIXEDCASE | DF_LONGNAME | DF_SUPPORTEA |
  228. DF_LANMAN21),
  229. __second( NTLANMAN, DF_CORE | DF_NEWRAWIO |
  230. DF_NTPROTOCOL | DF_NTNEGOTIATE |
  231. DF_MIXEDCASEPW | DF_LANMAN10 | DF_LANMAN20 |
  232. DF_LANMAN21 | DF_MIXEDCASE | DF_LONGNAME |
  233. DF_SUPPORTEA | DF_TIME_IS_UTC )
  234. };
  235. ULONG s_NumberOfDialects = sizeof(s_SmbDialects) / sizeof(s_SmbDialects[0]);
  236. PBYTE s_pNegotiateSmb = NULL;
  237. ULONG s_NegotiateSmbLength = 0;
  238. PBYTE s_pEchoSmb = NULL;
  239. BYTE s_EchoData[] = "JlJmIhClBsr";
  240. #define SMB_ECHO_COUNT (1)
  241. // Number of ticks 100ns ticks in a day.
  242. LARGE_INTEGER s_MaxTimeZoneBias;
  243. extern NTSTATUS
  244. GetNTSecurityParameters(
  245. PSMB_ADMIN_EXCHANGE pSmbAdminExchange,
  246. PSMBCE_SERVER pServer,
  247. PUNICODE_STRING pDomainName,
  248. PRESP_NT_NEGOTIATE pNtNegotiateResponse,
  249. ULONG BytesIndicated,
  250. ULONG BytesAvailable,
  251. PULONG pBytesTaken,
  252. PMDL *pDataBufferPointer,
  253. PULONG pDataSize);
  254. extern NTSTATUS
  255. GetLanmanSecurityParameters(
  256. PSMBCE_SERVER pServer,
  257. PRESP_NEGOTIATE pNegotiateResponse);
  258. extern VOID
  259. GetLanmanTimeBias(
  260. PSMBCE_SERVER pServer,
  261. PRESP_NEGOTIATE pNegotiateResponse);
  262. // Number of 100 ns ticks in one minute
  263. #define ONE_MINUTE_IN_TIME (60 * 1000 * 10000)
  264. NTSTATUS
  265. MRxSmbInitializeEchoProbeService(
  266. PMRXSMB_ECHO_PROBE_SERVICE_CONTEXT pEchoProbeContext)
  267. /*++
  268. Routine Description:
  269. This routine builds the echo SMB
  270. Return Value:
  271. STATUS_SUCCESS if construction of an ECHO smb was successful
  272. Other Status codes correspond to error situations.
  273. --*/
  274. {
  275. NTSTATUS Status = STATUS_SUCCESS;
  276. ULONG DialectIndex;
  277. PSMB_HEADER pSmbHeader = NULL;
  278. PREQ_ECHO pReqEcho = NULL;
  279. PAGED_CODE();
  280. pEchoProbeContext->EchoSmbLength = sizeof(SMB_HEADER) +
  281. FIELD_OFFSET(REQ_ECHO,Buffer) +
  282. sizeof(s_EchoData);
  283. pEchoProbeContext->pEchoSmb = (PBYTE)RxAllocatePoolWithTag(
  284. NonPagedPool,
  285. pEchoProbeContext->EchoSmbLength,
  286. MRXSMB_ECHO_POOLTAG);
  287. if (pEchoProbeContext->pEchoSmb != NULL) {
  288. pSmbHeader = (PSMB_HEADER)pEchoProbeContext->pEchoSmb;
  289. pReqEcho = (PREQ_ECHO)((PBYTE)pEchoProbeContext->pEchoSmb + sizeof(SMB_HEADER));
  290. // Fill in the header
  291. RtlZeroMemory( pSmbHeader, sizeof( SMB_HEADER ) );
  292. *(PULONG)(&pSmbHeader->Protocol) = (ULONG)SMB_HEADER_PROTOCOL;
  293. // By default, paths in SMBs are marked as case insensitive and
  294. // canonicalized.
  295. pSmbHeader->Flags =
  296. SMB_FLAGS_CASE_INSENSITIVE | SMB_FLAGS_CANONICALIZED_PATHS;
  297. // Get the flags2 field out of the SmbContext
  298. SmbPutAlignedUshort(
  299. &pSmbHeader->Flags2,
  300. (SMB_FLAGS2_KNOWS_LONG_NAMES |
  301. SMB_FLAGS2_KNOWS_EAS |
  302. SMB_FLAGS2_IS_LONG_NAME |
  303. SMB_FLAGS2_NT_STATUS |
  304. SMB_FLAGS2_UNICODE));
  305. // Fill in the process id.
  306. SmbPutUshort(&pSmbHeader->Pid, MRXSMB_PROCESS_ID );
  307. SmbPutUshort(&pSmbHeader->Tid,0xffff); // Invalid TID
  308. // Lastly, fill in the smb command code.
  309. pSmbHeader->Command = (UCHAR) SMB_COM_ECHO;
  310. pReqEcho->WordCount = 1;
  311. RtlMoveMemory( pReqEcho->Buffer, s_EchoData, sizeof( s_EchoData ) );
  312. SmbPutUshort(&pReqEcho->EchoCount, SMB_ECHO_COUNT);
  313. SmbPutUshort(&pReqEcho->ByteCount, (USHORT) sizeof( s_EchoData ) );
  314. } else {
  315. Status = STATUS_INSUFFICIENT_RESOURCES;
  316. }
  317. return Status;
  318. }
  319. VOID
  320. MRxSmbTearDownEchoProbeService(
  321. PMRXSMB_ECHO_PROBE_SERVICE_CONTEXT pEchoProbeContext)
  322. /*++
  323. Routine Description:
  324. This routine tears down the echo processing context
  325. --*/
  326. {
  327. PAGED_CODE();
  328. if (pEchoProbeContext->pEchoSmb != NULL) {
  329. RxFreePool(pEchoProbeContext->pEchoSmb);
  330. pEchoProbeContext->pEchoSmb = NULL;
  331. }
  332. }
  333. NTSTATUS
  334. BuildNegotiateSmb(
  335. PVOID *pSmbBufferPointer,
  336. PULONG pSmbBufferLength)
  337. /*++
  338. Routine Description:
  339. This routine builds the negotiate SMB
  340. Arguments:
  341. pSmbBufferPointer - a placeholder for the smb buffer
  342. pNegotiateSmbLength - the smb buffer size
  343. Return Value:
  344. STATUS_SUCCESS - implies that pServer is a valid instnace .
  345. Other Status codes correspond to error situations.
  346. --*/
  347. {
  348. NTSTATUS Status = STATUS_SUCCESS;
  349. ULONG DialectIndex;
  350. PSMB_HEADER pSmbHeader = NULL;
  351. PREQ_NEGOTIATE pReqNegotiate = NULL;
  352. PAGED_CODE();
  353. if (s_pNegotiateSmb == NULL) {
  354. s_NegotiateSmbLength = sizeof(SMB_HEADER) +
  355. FIELD_OFFSET(REQ_NEGOTIATE,Buffer) +
  356. sizeof(s_DialectNames);
  357. s_pNegotiateSmb = (PBYTE)RxAllocatePoolWithTag(
  358. PagedPool,
  359. s_NegotiateSmbLength + TRANSPORT_HEADER_SIZE,
  360. MRXSMB_ADMIN_POOLTAG);
  361. if (s_pNegotiateSmb != NULL) {
  362. s_pNegotiateSmb += TRANSPORT_HEADER_SIZE;
  363. pSmbHeader = (PSMB_HEADER)s_pNegotiateSmb;
  364. pReqNegotiate = (PREQ_NEGOTIATE)(s_pNegotiateSmb + sizeof(SMB_HEADER));
  365. // Fill in the header
  366. RtlZeroMemory( pSmbHeader, sizeof( SMB_HEADER ) );
  367. *(PULONG)(&pSmbHeader->Protocol) = (ULONG)SMB_HEADER_PROTOCOL;
  368. // By default, paths in SMBs are marked as case insensitive and
  369. // canonicalized.
  370. pSmbHeader->Flags =
  371. SMB_FLAGS_CASE_INSENSITIVE | SMB_FLAGS_CANONICALIZED_PATHS;
  372. // Put our flags2 field. The Ox10 is a temporary flag for SLM
  373. // corruption detection
  374. SmbPutAlignedUshort(
  375. &pSmbHeader->Flags2,
  376. (SMB_FLAGS2_KNOWS_LONG_NAMES
  377. | SMB_FLAGS2_KNOWS_EAS
  378. | SMB_FLAGS2_IS_LONG_NAME
  379. | SMB_FLAGS2_NT_STATUS
  380. | SMB_FLAGS2_UNICODE
  381. ));
  382. // Fill in the process id.
  383. SmbPutUshort( &pSmbHeader->Pid, MRXSMB_PROCESS_ID );
  384. // Lastly, fill in the smb command code.
  385. pSmbHeader->Command = (UCHAR) SMB_COM_NEGOTIATE;
  386. pReqNegotiate->WordCount = 0;
  387. RtlMoveMemory(
  388. pReqNegotiate->Buffer,
  389. s_DialectNames,
  390. sizeof( s_DialectNames ) );
  391. SmbPutUshort(
  392. &pReqNegotiate->ByteCount,
  393. (USHORT) sizeof( s_DialectNames ) );
  394. // Initialize the maximum time zone bias used in negotiate response parsing.
  395. s_MaxTimeZoneBias.QuadPart = Int32x32To64(24*60*60,1000*10000);
  396. } else {
  397. Status = STATUS_INSUFFICIENT_RESOURCES;
  398. }
  399. }
  400. if (NT_SUCCESS(Status)) {
  401. *pSmbBufferLength = s_NegotiateSmbLength;
  402. *pSmbBufferPointer = s_pNegotiateSmb;
  403. }
  404. return Status;
  405. }
  406. ULONG MRxSmbSrvWriteBufSize = 0xffff; //use the negotiated size
  407. NTSTATUS
  408. ParseNegotiateResponse(
  409. IN OUT PSMB_ADMIN_EXCHANGE pSmbAdminExchange,
  410. IN ULONG BytesIndicated,
  411. IN ULONG BytesAvailable,
  412. OUT PULONG pBytesTaken,
  413. IN PSMB_HEADER pSmbHeader,
  414. OUT PMDL *pDataBufferPointer,
  415. OUT PULONG pDataSize)
  416. /*++
  417. Routine Description:
  418. This routine parses the response from the server
  419. Arguments:
  420. pServer - the server instance
  421. pDomainName - the domain name string to be extracted from the response
  422. pSmbHeader - the response SMB
  423. BytesAvailable - length of the response
  424. pBytesTaken - response consumed
  425. Return Value:
  426. STATUS_SUCCESS - the server call construction has been finalized.
  427. Other Status codes correspond to error situations.
  428. Notes:
  429. The SMB servers can speak a variety of dialects of the SMB protocol. The initial
  430. negotiate response can come in one of three possible flavours. Either we get the
  431. NT negotiate response SMB from a NT server or the extended response from DOS and
  432. OS/2 servers or the CORE response from other servers.
  433. --*/
  434. {
  435. NTSTATUS Status = STATUS_SUCCESS;
  436. PSMBCEDB_SERVER_ENTRY pServerEntry;
  437. PSMBCE_SERVER pServer;
  438. PUNICODE_STRING pDomainName;
  439. USHORT DialectIndex;
  440. PRESP_NEGOTIATE pNegotiateResponse;
  441. ULONG NegotiateSmbLength;
  442. ASSERT( pSmbHeader != NULL );
  443. pServerEntry = SmbCeGetExchangeServerEntry(pSmbAdminExchange);
  444. pServer = &pServerEntry->Server;
  445. pDomainName = &pSmbAdminExchange->Negotiate.DomainName;
  446. pNegotiateResponse = (PRESP_NEGOTIATE) (pSmbHeader + 1);
  447. NegotiateSmbLength = sizeof(SMB_HEADER);
  448. *pBytesTaken = NegotiateSmbLength;
  449. // Assume that the indicated response is sufficient.
  450. // The TDI imposed minimum of 128 bytes subsumes the negotiate response.
  451. *pDataBufferPointer = NULL;
  452. *pDataSize = 0;
  453. DialectIndex = SmbGetUshort( &pNegotiateResponse->DialectIndex );
  454. if (DialectIndex == (USHORT) -1) {
  455. // means server cannot accept any requests from
  456. *pBytesTaken = BytesAvailable;
  457. pServerEntry->ServerStatus = STATUS_REQUEST_NOT_ACCEPTED;
  458. return Status;
  459. }
  460. if (pNegotiateResponse->WordCount < 1 || DialectIndex > s_NumberOfDialects) {
  461. *pBytesTaken = BytesAvailable;
  462. pServerEntry->ServerStatus = STATUS_INVALID_NETWORK_RESPONSE;
  463. return Status;
  464. }
  465. // set the domain name length to zero ( default initialization )
  466. pDomainName->Length = 0;
  467. // Fix up the dialect type and the corresponding dispatch vector.
  468. pServer->Dialect = (SMB_DIALECT)DialectIndex;
  469. pServer->DialectFlags = MRxSmbDialectFlags[DialectIndex];
  470. pServer->pDispatch = &s_SmbServerDispatchVectors[s_SmbDialects[DialectIndex].DispatchVectorIndex];
  471. // Parse the response based upon the type of negotiate response expected.
  472. switch (s_SmbDialects[DialectIndex].NegotiateType) {
  473. case SMB_NT_NEGOTIATE:
  474. {
  475. ULONG NegotiateResponseLength;
  476. LARGE_INTEGER ZeroTime;
  477. LARGE_INTEGER LocalTimeBias;
  478. LARGE_INTEGER ServerTimeBias;
  479. PRESP_NT_NEGOTIATE pNtNegotiateResponse = (PRESP_NT_NEGOTIATE) pNegotiateResponse;
  480. ASSERT(BytesAvailable > sizeof(RESP_NT_NEGOTIATE));
  481. if (pNtNegotiateResponse->WordCount != 17) {
  482. *pBytesTaken = BytesAvailable;
  483. Status = STATUS_INVALID_NETWORK_RESPONSE;
  484. } else {
  485. // parse and map the capabilities.
  486. ULONG NtCapabilities;
  487. NegotiateResponseLength = FIELD_OFFSET(RESP_NT_NEGOTIATE,Buffer) +
  488. SmbGetUshort(&pNtNegotiateResponse->ByteCount);
  489. NegotiateSmbLength += NegotiateResponseLength;
  490. //Start with a clean slate
  491. pServer->Capabilities = 0;
  492. // Initialize server based constants
  493. pServer->MaximumRequests = SmbGetUshort( &pNtNegotiateResponse->MaxMpxCount );
  494. pServer->MaximumVCs = SmbGetUshort( &pNtNegotiateResponse->MaxNumberVcs );
  495. pServer->MaximumBufferSize = SmbGetUlong( &pNtNegotiateResponse->MaxBufferSize );
  496. NtCapabilities = pServer->NtServer.NtCapabilities = SmbGetUlong(&pNtNegotiateResponse->Capabilities);
  497. if (NtCapabilities & CAP_RAW_MODE) {
  498. pServer->Capabilities |= (RAW_READ_CAPABILITY | RAW_WRITE_CAPABILITY);
  499. }
  500. if (NtCapabilities & CAP_DFS) {
  501. pServer->Capabilities |= CAP_DFS;
  502. }
  503. //copy other nt capabilities into the dialog flags
  504. if (NtCapabilities & CAP_UNICODE) {
  505. pServer->DialectFlags |= DF_UNICODE;
  506. }
  507. if (NtCapabilities & CAP_LARGE_FILES) {
  508. pServer->DialectFlags |= DF_LARGE_FILES;
  509. }
  510. if (NtCapabilities & CAP_NT_SMBS) {
  511. pServer->DialectFlags |= DF_NT_SMBS | DF_NT_FIND;
  512. }
  513. if (NtCapabilities & CAP_NT_FIND) {
  514. pServer->DialectFlags |= DF_NT_FIND;
  515. }
  516. if (NtCapabilities & CAP_RPC_REMOTE_APIS) {
  517. pServer->DialectFlags |= DF_RPC_REMOTE;
  518. }
  519. if (NtCapabilities & CAP_NT_STATUS) {
  520. pServer->DialectFlags |= DF_NT_STATUS;
  521. }
  522. if (NtCapabilities & CAP_LEVEL_II_OPLOCKS) {
  523. pServer->DialectFlags |= DF_OPLOCK_LVL2;
  524. }
  525. if (NtCapabilities & CAP_LOCK_AND_READ) {
  526. pServer->DialectFlags |= DF_LOCKREAD;
  527. }
  528. if (NtCapabilities & CAP_INFOLEVEL_PASSTHRU) {
  529. pServer->DialectFlags |= DF_NT_INFO_PASSTHROUGH;
  530. }
  531. // For non disk files the LARGE_READX capability is not useful.
  532. pServer->MaximumNonDiskFileReadBufferSize =
  533. pServer->MaximumBufferSize -
  534. QuadAlign(
  535. sizeof(SMB_HEADER) +
  536. FIELD_OFFSET(
  537. REQ_NT_READ_ANDX,
  538. Buffer[0]));
  539. if (NtCapabilities & CAP_LARGE_READX) {
  540. if (NtCapabilities & CAP_LARGE_WRITEX) {
  541. pServer->MaximumDiskFileReadBufferSize = 60*1024;
  542. } else {
  543. // The maximum size for reads to servers which support
  544. // large read and x is constrained by the USHORT to record
  545. // lengths in the SMB. Thus the maximum length that can be used
  546. // is (65536 - 1) . This length should accomodate the header as
  547. // well as the rest of the SMB. Actually, tho, we cut back to 60K.
  548. pServer->MaximumDiskFileReadBufferSize = 60*1024;
  549. }
  550. } else {
  551. pServer->MaximumDiskFileReadBufferSize = pServer->MaximumNonDiskFileReadBufferSize;
  552. }
  553. // Specifying a zero local time will give you the time zone bias
  554. ZeroTime.HighPart = ZeroTime.LowPart = 0;
  555. ExLocalTimeToSystemTime( &ZeroTime, &LocalTimeBias );
  556. ServerTimeBias = RtlEnlargedIntegerMultiply(
  557. (LONG)SmbGetUshort(
  558. &pNtNegotiateResponse->ServerTimeZone),
  559. ONE_MINUTE_IN_TIME );
  560. pServer->TimeZoneBias.QuadPart = ServerTimeBias.QuadPart -
  561. LocalTimeBias.QuadPart;
  562. if (!FlagOn(pServer->DialectFlags,DF_NT_SMBS)) {
  563. //sigh...........
  564. pServer->DialectFlags &= ~(DF_MIXEDCASEPW);
  565. pServer->DialectFlags |= DF_W95;
  566. }
  567. Status = GetNTSecurityParameters(
  568. pSmbAdminExchange,
  569. pServer,
  570. pDomainName,
  571. pNtNegotiateResponse,
  572. BytesIndicated,
  573. BytesAvailable,
  574. pBytesTaken,
  575. pDataBufferPointer,
  576. pDataSize);
  577. pServer->MaximumNonDiskFileWriteBufferSize =
  578. min(
  579. MRxSmbSrvWriteBufSize,
  580. pServer->MaximumBufferSize -
  581. QuadAlign(
  582. sizeof(SMB_HEADER) +
  583. FIELD_OFFSET(
  584. REQ_NT_WRITE_ANDX,
  585. Buffer[0])));
  586. if (NtCapabilities & CAP_LARGE_WRITEX) {
  587. pServer->DialectFlags |= DF_LARGE_WRITEX;
  588. pServer->MaximumDiskFileWriteBufferSize = 0x10000;
  589. } else {
  590. pServer->MaximumDiskFileWriteBufferSize =
  591. pServer->MaximumNonDiskFileWriteBufferSize;
  592. }
  593. }
  594. }
  595. break;
  596. case SMB_EXTENDED_NEGOTIATE :
  597. {
  598. // An SMB_EXTENDED_NEGOTIATE response is never partially indicated. The response
  599. // length is ithin the TDI minimum for indication.
  600. USHORT RawMode;
  601. // DOS or OS2 server
  602. if (pNegotiateResponse->WordCount != 13 &&
  603. pNegotiateResponse->WordCount != 10 &&
  604. pNegotiateResponse->WordCount != 8) {
  605. Status = STATUS_INVALID_NETWORK_RESPONSE;
  606. } else {
  607. NegotiateSmbLength += FIELD_OFFSET(RESP_NEGOTIATE,Buffer) +
  608. SmbGetUshort(&pNegotiateResponse->ByteCount);
  609. ASSERT(
  610. (BytesIndicated >= NegotiateSmbLength) &&
  611. (BytesIndicated == BytesAvailable));
  612. RawMode = SmbGetUshort( &pNegotiateResponse->RawMode );
  613. pServer->Capabilities |= ((RawMode & 0x1) != 0
  614. ? RAW_READ_CAPABILITY : 0);
  615. pServer->Capabilities |= ((RawMode & 0x2) != 0
  616. ? RAW_WRITE_CAPABILITY : 0);
  617. if (pSmbHeader->Flags & SMB_FLAGS_LOCK_AND_READ_OK) {
  618. pServer->DialectFlags |= DF_LOCKREAD;
  619. }
  620. pServer->EncryptPasswords = FALSE;
  621. pServer->MaximumVCs = 1;
  622. pServer->MaximumBufferSize = SmbGetUshort( &pNegotiateResponse->MaxBufferSize );
  623. pServer->MaximumDiskFileReadBufferSize =
  624. pServer->MaximumBufferSize -
  625. QuadAlign(
  626. sizeof(SMB_HEADER) +
  627. FIELD_OFFSET(
  628. RESP_READ_ANDX,
  629. Buffer[0]));
  630. pServer->MaximumNonDiskFileReadBufferSize = pServer->MaximumDiskFileReadBufferSize;
  631. pServer->MaximumDiskFileWriteBufferSize = pServer->MaximumDiskFileReadBufferSize;
  632. pServer->MaximumNonDiskFileWriteBufferSize = pServer->MaximumDiskFileReadBufferSize;
  633. pServer->MaximumRequests = SmbGetUshort(
  634. &pNegotiateResponse->MaxMpxCount );
  635. pServer->MaximumVCs = SmbGetUshort(
  636. &pNegotiateResponse->MaxNumberVcs );
  637. if (pNegotiateResponse->WordCount == 13) {
  638. //CODE.IMPROVEMENT use the DF_bit for this
  639. switch (pServer->Dialect) {
  640. case LANMAN10_DIALECT:
  641. case WFW10_DIALECT:
  642. case LANMAN12_DIALECT:
  643. case LANMAN21_DIALECT:
  644. GetLanmanTimeBias( pServer,pNegotiateResponse );
  645. break;
  646. }
  647. Status = GetLanmanSecurityParameters( pServer,pNegotiateResponse );
  648. }
  649. }
  650. *pBytesTaken = BytesAvailable;
  651. }
  652. break;
  653. case SMB_CORE_NEGOTIATE :
  654. default :
  655. {
  656. // An SMB_CORE_NEGOTIATE response is never partially indicated. The response
  657. // length is ithin the TDI minimum for indication.
  658. pServer->SecurityMode = SECURITY_MODE_SHARE_LEVEL;
  659. pServer->EncryptPasswords = FALSE;
  660. pServer->MaximumBufferSize = 0;
  661. pServer->MaximumRequests = 1;
  662. pServer->MaximumVCs = 1;
  663. pServer->SessionKey = 0;
  664. if (pSmbHeader->Flags & SMB_FLAGS_OPLOCK) {
  665. pServer->DialectFlags |= DF_OPLOCK;
  666. }
  667. *pBytesTaken = BytesAvailable;
  668. ASSERT(BytesIndicated == BytesAvailable);
  669. }
  670. }
  671. if (pServer->MaximumRequests == 0) {
  672. //
  673. // If this is a Lanman 1.0 or better server, this is a invalid negotiate
  674. // response. For others it would have been set to 1.
  675. //
  676. Status = STATUS_INVALID_NETWORK_RESPONSE;
  677. }
  678. if ((Status == STATUS_SUCCESS) ||
  679. (Status == STATUS_MORE_PROCESSING_REQUIRED)) {
  680. // Note that this code relies on the minimum incication size covering
  681. // the negotiate response header.
  682. // Check to make sure that the time zone bias isn't more than +-24
  683. // hours.
  684. //
  685. if ((pServer->TimeZoneBias.QuadPart > s_MaxTimeZoneBias.QuadPart) ||
  686. (-pServer->TimeZoneBias.QuadPart > s_MaxTimeZoneBias.QuadPart)) {
  687. // Set the bias to 0 - assume local time zone.
  688. pServer->TimeZoneBias.LowPart = pServer->TimeZoneBias.HighPart = 0;
  689. }
  690. // Do not allow negotiated buffersize to exceed the size of a USHORT.
  691. // Remove 4096 bytes to avoid overrun and make it easier to handle
  692. // than 0xffff
  693. pServer->MaximumBufferSize =
  694. (pServer->MaximumBufferSize < 0x00010000) ? pServer->MaximumBufferSize :
  695. 0x00010000 - 4096;
  696. } else {
  697. pServerEntry->ServerStatus = Status;
  698. *pBytesTaken = BytesAvailable;
  699. }
  700. if ((pServer->DialectFlags & DF_NTNEGOTIATE)!=0) {
  701. InterlockedIncrement(&MRxSmbStatistics.LanmanNtConnects);
  702. } else if ((pServer->DialectFlags & DF_LANMAN21)!=0) {
  703. InterlockedIncrement(&MRxSmbStatistics.Lanman21Connects);
  704. } else if ((pServer->DialectFlags & DF_LANMAN20)!=0) {
  705. InterlockedIncrement(&MRxSmbStatistics.Lanman20Connects);
  706. } else {
  707. InterlockedIncrement(&MRxSmbStatistics.CoreConnects);
  708. }
  709. if ((pServer->Dialect == NTLANMAN_DIALECT) &&
  710. !pServer->EncryptPasswords) {
  711. // Encrypted password is required on NTLANMAN
  712. pServer->Dialect = LANMAN21_DIALECT;
  713. }
  714. return Status;
  715. }
  716. NTSTATUS
  717. GetNTSecurityParameters(
  718. PSMB_ADMIN_EXCHANGE pSmbAdminExchange,
  719. PSMBCE_SERVER pServer,
  720. PUNICODE_STRING pDomainName,
  721. PRESP_NT_NEGOTIATE pNtNegotiateResponse,
  722. ULONG BytesIndicated,
  723. ULONG BytesAvailable,
  724. PULONG pBytesTaken,
  725. PMDL *pDataBufferPointer,
  726. PULONG pDataSize)
  727. /*++
  728. Routine Description:
  729. This routine extracts the security parameters from an NT server
  730. Arguments:
  731. pServer - the server
  732. pDomainName - the domain name
  733. pNtNegotiateResponse - the response
  734. NegotiateResponseLength - size of the negotiate response
  735. Return Value:
  736. STATUS_SUCCESS - implies that pServer is a valid instnace .
  737. Other Status codes correspond to error situations.
  738. --*/
  739. {
  740. NTSTATUS Status = STATUS_SUCCESS;
  741. USHORT ByteCount;
  742. PUSHORT pByteCountInSmb =
  743. ((PUSHORT)((PUCHAR) pNtNegotiateResponse + 1)) +
  744. pNtNegotiateResponse->WordCount;
  745. PUCHAR pBuffer = (PUCHAR)(pByteCountInSmb + 1);
  746. *pBytesTaken += FIELD_OFFSET(RESP_NT_NEGOTIATE,Buffer);
  747. ByteCount = SmbGetUshort(pByteCountInSmb);
  748. pServer->SecurityMode = (((pNtNegotiateResponse->SecurityMode & NEGOTIATE_USER_SECURITY) != 0)
  749. ? SECURITY_MODE_USER_LEVEL
  750. : SECURITY_MODE_SHARE_LEVEL);
  751. pServer->EncryptPasswords = ((pNtNegotiateResponse->SecurityMode & NEGOTIATE_ENCRYPT_PASSWORDS) != 0);
  752. pServer->EncryptionKeyLength = 0;
  753. *pBytesTaken = BytesAvailable;
  754. pServer->SessionKey = SmbGetUlong( &pNtNegotiateResponse->SessionKey );
  755. if (pServer->EncryptPasswords) {
  756. pServer->EncryptionKeyLength = pNtNegotiateResponse->EncryptionKeyLength;
  757. if (pServer->EncryptionKeyLength != 0) {
  758. ASSERT( CRYPT_TXT_LEN == MSV1_0_CHALLENGE_LENGTH );
  759. if (pServer->EncryptionKeyLength != CRYPT_TXT_LEN) {
  760. Status = STATUS_INVALID_NETWORK_RESPONSE;
  761. } else {
  762. RtlCopyMemory(
  763. pServer->EncryptionKey,
  764. pBuffer,
  765. pServer->EncryptionKeyLength );
  766. if (ByteCount - pServer->EncryptionKeyLength > 0) {
  767. ASSERT((pDomainName->Buffer != NULL) &&
  768. (pDomainName->MaximumLength >= (ByteCount - pServer->EncryptionKeyLength)));
  769. pBuffer = pBuffer + pServer->EncryptionKeyLength;
  770. pDomainName->Length = ByteCount - pServer->EncryptionKeyLength;
  771. if (pDomainName->Length & 1) {
  772. // The remainder of the length is odd. This implies that the server did
  773. // some alignment.
  774. pBuffer++;
  775. pDomainName->Length -= 1;
  776. }
  777. RtlCopyMemory(
  778. pDomainName->Buffer,
  779. pBuffer,
  780. pDomainName->Length);
  781. }
  782. }
  783. }
  784. }
  785. return Status;
  786. }
  787. NTSTATUS
  788. GetLanmanSecurityParameters(
  789. PSMBCE_SERVER pServer,
  790. PRESP_NEGOTIATE pNegotiateResponse)
  791. /*++
  792. Routine Description:
  793. This routine extracts the security parameters from a LANMAN server
  794. Arguments:
  795. pServer - the server
  796. pNtNegotiateResponse - the response
  797. Return Value:
  798. STATUS_SUCCESS - implies that pServer is a valid instnace .
  799. Other Status codes correspond to error situations.
  800. --*/
  801. {
  802. USHORT i;
  803. USHORT SecurityMode;
  804. pServer->SessionKey = SmbGetUlong( &pNegotiateResponse->SessionKey );
  805. SecurityMode = SmbGetUshort( &pNegotiateResponse->SecurityMode );
  806. pServer->SecurityMode = (((SecurityMode & 1) != 0)
  807. ? SECURITY_MODE_USER_LEVEL
  808. : SECURITY_MODE_SHARE_LEVEL);
  809. pServer->EncryptPasswords = ((SecurityMode & 2) != 0);
  810. if (pServer->EncryptPasswords) {
  811. if (pServer->Dialect == LANMAN21_DIALECT) {
  812. pServer->EncryptionKeyLength = SmbGetUshort(&pNegotiateResponse->EncryptionKeyLength);
  813. } else {
  814. pServer->EncryptionKeyLength = SmbGetUshort(&pNegotiateResponse->ByteCount);
  815. }
  816. if (pServer->EncryptionKeyLength != 0) {
  817. if (pServer->EncryptionKeyLength > CRYPT_TXT_LEN) {
  818. return( STATUS_INVALID_NETWORK_RESPONSE );
  819. }
  820. for (i = 0; i < pServer->EncryptionKeyLength; i++) {
  821. pServer->EncryptionKey[i] = pNegotiateResponse->Buffer[i];
  822. }
  823. }
  824. }
  825. return( STATUS_SUCCESS );
  826. }
  827. LARGE_INTEGER
  828. ConvertSmbTimeToTime (
  829. IN SMB_TIME Time,
  830. IN SMB_DATE Date
  831. )
  832. /*++
  833. Routine Description:
  834. This routine converts an SMB time to an NT time structure.
  835. Arguments:
  836. IN SMB_TIME Time - Supplies the time of day to convert
  837. IN SMB_DATE Date - Supplies the day of the year to convert
  838. IN PSERVERLISTENTRY Server - if supplied, supplies the server for tz bias.
  839. Return Value:
  840. LARGE_INTEGER - Time structure describing input time.
  841. --*/
  842. {
  843. TIME_FIELDS TimeFields;
  844. LARGE_INTEGER OutputTime;
  845. //
  846. // This routine cannot be paged because it is called from both the
  847. // RdrFileDiscardableSection and the RdrVCDiscardableSection.
  848. //
  849. if (SmbIsTimeZero(&Date) && SmbIsTimeZero(&Time)) {
  850. OutputTime.LowPart = OutputTime.HighPart = 0;
  851. } else {
  852. TimeFields.Year = Date.Struct.Year + (USHORT )1980;
  853. TimeFields.Month = Date.Struct.Month;
  854. TimeFields.Day = Date.Struct.Day;
  855. TimeFields.Hour = Time.Struct.Hours;
  856. TimeFields.Minute = Time.Struct.Minutes;
  857. TimeFields.Second = Time.Struct.TwoSeconds*(USHORT )2;
  858. TimeFields.Milliseconds = 0;
  859. //
  860. // Make sure that the times specified in the SMB are reasonable
  861. // before converting them.
  862. //
  863. if (TimeFields.Year < 1601) {
  864. TimeFields.Year = 1601;
  865. }
  866. if (TimeFields.Month > 12) {
  867. TimeFields.Month = 12;
  868. }
  869. if (TimeFields.Hour >= 24) {
  870. TimeFields.Hour = 23;
  871. }
  872. if (TimeFields.Minute >= 60) {
  873. TimeFields.Minute = 59;
  874. }
  875. if (TimeFields.Second >= 60) {
  876. TimeFields.Second = 59;
  877. }
  878. if (!RtlTimeFieldsToTime(&TimeFields, &OutputTime)) {
  879. OutputTime.HighPart = 0;
  880. OutputTime.LowPart = 0;
  881. return OutputTime;
  882. }
  883. ExLocalTimeToSystemTime(&OutputTime, &OutputTime);
  884. }
  885. return OutputTime;
  886. }
  887. VOID
  888. GetLanmanTimeBias(
  889. PSMBCE_SERVER pServer,
  890. PRESP_NEGOTIATE pNegotiateResponse)
  891. /*++
  892. Routine Description:
  893. This routine extracts the time bias from a Lanman server
  894. Arguments:
  895. pServer - the server
  896. pNtNegotiateResponse - the response
  897. Return Value:
  898. STATUS_SUCCESS - implies that pServer is a valid instnace .
  899. Other Status codes correspond to error situations.
  900. --*/
  901. {
  902. // If this is a LM 1.0 or 2.0 server (ie a non NT server), we
  903. // remember the timezone and bias our time based on this value.
  904. //
  905. // The redirector assumes that all times from these servers are
  906. // local time for the server, and converts them to local time
  907. // using this bias. It then tells the user the local time for
  908. // the file on the server.
  909. LARGE_INTEGER Workspace, ServerTime, CurrentTime;
  910. BOOLEAN Negated = FALSE;
  911. SMB_TIME SmbServerTime;
  912. SMB_DATE SmbServerDate;
  913. SmbMoveTime(&SmbServerTime, &pNegotiateResponse->ServerTime);
  914. SmbMoveDate(&SmbServerDate, &pNegotiateResponse->ServerDate);
  915. ServerTime = ConvertSmbTimeToTime(SmbServerTime, SmbServerDate);
  916. KeQuerySystemTime(&CurrentTime);
  917. Workspace.QuadPart = CurrentTime.QuadPart - ServerTime.QuadPart;
  918. if ( Workspace.HighPart < 0) {
  919. // avoid using -ve large integers to routines that accept only unsigned
  920. Workspace.QuadPart = -Workspace.QuadPart;
  921. Negated = TRUE;
  922. }
  923. //
  924. // Workspace has the exact difference in 100ns intervals
  925. // between the server and redirector times. To remove the minor
  926. // difference between the time settings on the two machines we
  927. // round the Bias to the nearest 30 minutes.
  928. //
  929. // Calculate ((exact bias+15minutes)/30minutes)* 30minutes
  930. // then convert back to the bias time.
  931. //
  932. Workspace.QuadPart += ((LONGLONG) ONE_MINUTE_IN_TIME) * 15;
  933. // Workspace is now exact bias + 15 minutes in 100ns units
  934. Workspace.QuadPart /= ((LONGLONG) ONE_MINUTE_IN_TIME) * 30;
  935. pServer->TimeZoneBias.QuadPart = Workspace.QuadPart * ((LONGLONG) ONE_MINUTE_IN_TIME) * 30;
  936. if ( Negated == TRUE ) {
  937. pServer->TimeZoneBias.QuadPart = -pServer->TimeZoneBias.QuadPart;
  938. }
  939. }