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.

1818 lines
62 KiB

  1. /*++ BUILD Version: 0009 // Increment this if a change has global effects
  2. Copyright (c) 1987-1993 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. Author:
  10. Balan Sethu Raman (SethuR) 06-Mar-95 Created
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. #ifdef ALLOC_PRAGMA
  15. #pragma alloc_text(PAGE, SmbCeCreateSrvCall)
  16. #pragma alloc_text(PAGE, MRxSmbCreateSrvCall)
  17. #pragma alloc_text(PAGE, MRxSmbFinalizeSrvCall)
  18. #pragma alloc_text(PAGE, MRxSmbSrvCallWinnerNotify)
  19. #pragma alloc_text(PAGE, MRxSmbInitializeEchoProbeService)
  20. #pragma alloc_text(PAGE, MRxSmbTearDownEchoProbeService)
  21. #pragma alloc_text(PAGE, MRxSmbMaskNegotiateSmb)
  22. #pragma alloc_text(PAGE, BuildNegotiateSmb)
  23. #endif
  24. RXDT_DefineCategory(SRVCALL);
  25. #define Dbg (DEBUG_TRACE_SRVCALL)
  26. extern BOOLEAN MRxSmbSecuritySignaturesEnabled;
  27. extern BOOLEAN MRxSmbSecuritySignaturesRequired;
  28. VOID
  29. SmbCeCreateSrvCall(
  30. PMRX_SRVCALL_CALLBACK_CONTEXT pCallbackContext)
  31. /*++
  32. Routine Description:
  33. This routine patches the RDBSS created srv call instance with the information required
  34. by the mini redirector.
  35. Arguments:
  36. CallBackContext - the call back context in RDBSS for continuation.
  37. Return Value:
  38. RXSTATUS - The return status for the operation
  39. --*/
  40. {
  41. NTSTATUS Status;
  42. PMRX_SRVCALLDOWN_STRUCTURE SrvCalldownStructure;
  43. PMRX_SRV_CALL pSrvCall;
  44. PAGED_CODE();
  45. SrvCalldownStructure =
  46. (PMRX_SRVCALLDOWN_STRUCTURE)(pCallbackContext->SrvCalldownStructure);
  47. pSrvCall = SrvCalldownStructure->SrvCall;
  48. ASSERT( pSrvCall );
  49. ASSERT( NodeType(pSrvCall) == RDBSS_NTC_SRVCALL );
  50. SmbCeInitializeServerEntry(
  51. pSrvCall,
  52. pCallbackContext,
  53. SrvCalldownStructure->RxContext->Create.TreeConnectOpenDeferred);
  54. }
  55. NTSTATUS
  56. MRxSmbCreateSrvCall(
  57. PMRX_SRV_CALL pSrvCall,
  58. PMRX_SRVCALL_CALLBACK_CONTEXT pCallbackContext)
  59. /*++
  60. Routine Description:
  61. This routine patches the RDBSS created srv call instance with the information required
  62. by the mini redirector.
  63. Arguments:
  64. RxContext - Supplies the context of the original create/ioctl
  65. CallBackContext - the call back context in RDBSS for continuation.
  66. Return Value:
  67. RXSTATUS - The return status for the operation
  68. Notes:
  69. Certain transport related interfaces require handle to be passed in. This
  70. implies that the SRV_CALL instances need to be initialized in the context
  71. of a well known process, i.e., the RDBSS process.
  72. In the normal course of event is this request was issued within the context
  73. of the system process we should continue without having to post. However
  74. there are cases in MIPS when stack overflows. In order to avoid such situations
  75. the request is posted in all cases.
  76. --*/
  77. {
  78. NTSTATUS Status;
  79. UNICODE_STRING ServerName;
  80. PMRX_SRVCALL_CALLBACK_CONTEXT SCCBC = pCallbackContext;
  81. PMRX_SRVCALLDOWN_STRUCTURE SrvCalldownStructure = (PMRX_SRVCALLDOWN_STRUCTURE)(pCallbackContext->SrvCalldownStructure);
  82. PAGED_CODE();
  83. ASSERT( pSrvCall );
  84. ASSERT( NodeType(pSrvCall) == RDBSS_NTC_SRVCALL );
  85. // Dispatch the request to a system thread.
  86. Status = RxDispatchToWorkerThread(
  87. MRxSmbDeviceObject,
  88. DelayedWorkQueue,
  89. SmbCeCreateSrvCall,
  90. pCallbackContext);
  91. if (Status == STATUS_SUCCESS) {
  92. // Map the return value since the wrapper expects PENDING.
  93. Status = STATUS_PENDING;
  94. } else {
  95. // There was an error in dispatching the SmbCeCreateSrvCall method to
  96. // a worker thread. Complete the request and return STATUS_PENDING.
  97. SCCBC->Status = Status;
  98. SrvCalldownStructure->CallBack(SCCBC);
  99. Status = STATUS_PENDING;
  100. }
  101. return Status;
  102. }
  103. NTSTATUS
  104. MRxSmbFinalizeSrvCall(
  105. PMRX_SRV_CALL pSrvCall,
  106. BOOLEAN Force)
  107. /*++
  108. Routine Description:
  109. This routine destroys a given server call instance
  110. Arguments:
  111. pSrvCall - the server call instance to be disconnected.
  112. Force - TRUE if a disconnection is to be enforced immediately.
  113. Return Value:
  114. RXSTATUS - The return status for the operation
  115. --*/
  116. {
  117. NTSTATUS Status = STATUS_SUCCESS;
  118. PSMBCEDB_SERVER_ENTRY pServerEntry;
  119. PAGED_CODE();
  120. // if the server entry is not filled in, then there's nothing to do. this occurs
  121. // on a srvcall that we never successfuly hooked up to........
  122. if (pSrvCall->Context == NULL) {
  123. return(Status);
  124. }
  125. pServerEntry = SmbCeGetAssociatedServerEntry(pSrvCall);
  126. if (pServerEntry != NULL) {
  127. InterlockedCompareExchangePointer(
  128. &pServerEntry->pRdbssSrvCall,
  129. NULL,
  130. pSrvCall);
  131. SmbCeDereferenceServerEntry(pServerEntry);
  132. }
  133. pSrvCall->Context = NULL;
  134. return Status;
  135. }
  136. NTSTATUS
  137. MRxSmbSrvCallWinnerNotify(
  138. IN PMRX_SRV_CALL pSrvCall,
  139. IN BOOLEAN ThisMinirdrIsTheWinner,
  140. IN OUT PVOID pSrvCallContext)
  141. /*++
  142. Routine Description:
  143. This routine finalizes the mini rdr context associated with an RDBSS Server call instance
  144. Arguments:
  145. pSrvCall - the Server Call
  146. ThisMinirdrIsTheWinner - TRUE if this mini rdr is the choosen one.
  147. pSrvCallContext - the server call context created by the mini redirector.
  148. Return Value:
  149. RXSTATUS - The return status for the operation
  150. Notes:
  151. The two phase construction protocol for Server calls is required because of parallel
  152. initiation of a number of mini redirectors. The RDBSS finalizes the particular mini
  153. redirector to be used in communicating with a given server based on quality of
  154. service criterion.
  155. --*/
  156. {
  157. NTSTATUS Status = RX_MAP_STATUS(SUCCESS);
  158. PSMBCEDB_SERVER_ENTRY pServerEntry;
  159. PAGED_CODE();
  160. pServerEntry = (PSMBCEDB_SERVER_ENTRY)pSrvCallContext;
  161. if (!ThisMinirdrIsTheWinner) {
  162. //
  163. // Some other mini rdr has been choosen to connect to the server. Destroy
  164. // the data structures created for this mini redirector.
  165. //
  166. SmbCeUpdateServerEntryState(pServerEntry,SMBCEDB_MARKED_FOR_DELETION);
  167. SmbCeDereferenceServerEntry(pServerEntry);
  168. return STATUS_SUCCESS;
  169. }
  170. pSrvCall->Context = pServerEntry;
  171. pSrvCall->Flags |= SRVCALL_FLAG_CASE_INSENSITIVE_NETROOTS |
  172. SRVCALL_FLAG_CASE_INSENSITIVE_FILENAMES;
  173. pSrvCall->MaximumNumberOfCloseDelayedFiles = MRxSmbConfiguration.DormantFileLimit + 1;
  174. return STATUS_SUCCESS;
  175. }
  176. extern GUID CachedServerGuid;
  177. NTSTATUS
  178. MRxSmbCheckForLoopBack(
  179. IN PSMBCEDB_SERVER_ENTRY pServerEntry)
  180. /*++
  181. Routine Description:
  182. This routine checks for loop back case and set the flag accordingly
  183. Arguments:
  184. pServerEntry - the Server Entry
  185. Return Value:
  186. RXSTATUS - The return status for the operation
  187. Notes:
  188. --*/
  189. {
  190. pServerEntry->Server.IsLoopBack = FALSE;
  191. //
  192. // Check for loopback. NT5 servers support extended security, and return a
  193. // GUID in the negotiate response. We also know that the NT5 server stores
  194. // its GUID in the registry. So we compare the registry value on this machine
  195. // to the GUID value returned from the server to which we just connected. If
  196. // they match, then we are looping back to ourselves!
  197. //
  198. // The Server registry entry is now cached to prevent deadlock.
  199. //
  200. if( BooleanFlagOn( pServerEntry->Server.DialectFlags, DF_EXTENDED_SECURITY ) ) {
  201. if( RtlCompareMemory( &CachedServerGuid,
  202. &pServerEntry->Server.NtServer.ServerGuid,
  203. sizeof( GUID ) ) == sizeof( GUID ) ) {
  204. //
  205. // The GUID in the registry (cached) matches the GUID we got back from the
  206. // server! We must be looping back to ourselves!
  207. //
  208. pServerEntry->Server.IsLoopBack = TRUE;
  209. }
  210. }
  211. return STATUS_SUCCESS;
  212. }
  213. //
  214. // The following type defines and data structures are used for parsing negotiate SMB
  215. // responses.
  216. //
  217. #include "protocol.h"
  218. //superceded in smbxchng.h
  219. //#define MRXSMB_PROCESS_ID 0xCAFE
  220. typedef enum _SMB_NEGOTIATE_TYPE_ {
  221. SMB_CORE_NEGOTIATE,
  222. SMB_EXTENDED_NEGOTIATE,
  223. SMB_NT_NEGOTIATE
  224. } SMB_NEGOTIATE_TYPE, *PSMB_NEGOTIATE_TYPE;
  225. typedef struct _SMB_DIALECTS_ {
  226. SMB_NEGOTIATE_TYPE NegotiateType;
  227. USHORT DispatchVectorIndex;
  228. } SMB_DIALECTS, *PSMB_DIALECTS;
  229. SMBCE_SERVER_DISPATCH_VECTOR
  230. s_SmbServerDispatchVectors[] = {
  231. {BuildSessionSetupSmb,CoreBuildTreeConnectSmb},
  232. {BuildSessionSetupSmb,LmBuildTreeConnectSmb},
  233. {BuildSessionSetupSmb,NtBuildTreeConnectSmb},
  234. {BuildSessionSetupSmb,NtBuildTreeConnectSmb}
  235. };
  236. //CODE.IMPROVEMENT since, in fact, we may never implement XENIXCORE and MSNET13
  237. // we should hack them out. however, there is an enum in smbce.h that must be kept
  238. // sync with these arrays.
  239. SMB_DIALECTS
  240. s_SmbDialects[] = {
  241. { SMB_CORE_NEGOTIATE, 0},
  242. //{ SMB_CORE_NEGOTIATE, 0 },
  243. //{ SMB_EXTENDED_NEGOTIATE, 1 },
  244. { SMB_EXTENDED_NEGOTIATE, 1 },
  245. { SMB_EXTENDED_NEGOTIATE, 1 },
  246. { SMB_EXTENDED_NEGOTIATE, 1 },
  247. { SMB_EXTENDED_NEGOTIATE, 1 },
  248. { SMB_NT_NEGOTIATE, 2 },
  249. { SMB_NT_NEGOTIATE, 3}
  250. };
  251. CHAR s_DialectNames[] = {
  252. "\2" PCNET1 "\0"
  253. //\2notyet" XENIXCORE "\0"
  254. //\2notyet" MSNET103 "\0"
  255. "\2" LANMAN10 "\0"
  256. "\2" WFW10 "\0"
  257. "\2" LANMAN12 "\0"
  258. "\2" LANMAN21
  259. "\0\2" NTLANMAN
  260. };
  261. #define __second(a,b) (b)
  262. ULONG
  263. MRxSmbDialectFlags[] = {
  264. __second( PCNET1, DF_CORE ),
  265. //__second( XENIXCORE, DF_CORE | DF_MIXEDCASEPW | DF_MIXEDCASE ),
  266. //__second( MSNET103, DF_CORE | DF_OLDRAWIO | DF_LOCKREAD | DF_EXTENDNEGOT ),
  267. __second( LANMAN10, DF_CORE | DF_NEWRAWIO | DF_LOCKREAD | DF_EXTENDNEGOT |
  268. DF_LANMAN10 ),
  269. __second( WFW10, DF_CORE | DF_NEWRAWIO | DF_LOCKREAD | DF_EXTENDNEGOT |
  270. DF_LANMAN10 | DF_WFW),
  271. __second( LANMAN12, DF_CORE | DF_NEWRAWIO | DF_LOCKREAD | DF_EXTENDNEGOT |
  272. DF_LANMAN10 | DF_LANMAN20 |
  273. DF_MIXEDCASE | DF_LONGNAME | DF_SUPPORTEA ),
  274. __second( LANMAN21, DF_CORE | DF_NEWRAWIO | DF_LOCKREAD | DF_EXTENDNEGOT |
  275. DF_LANMAN10 | DF_LANMAN20 |
  276. DF_MIXEDCASE | DF_LONGNAME | DF_SUPPORTEA |
  277. DF_LANMAN21),
  278. __second( NTLANMAN, DF_CORE | DF_NEWRAWIO |
  279. DF_NTPROTOCOL | DF_NTNEGOTIATE |
  280. DF_MIXEDCASEPW | DF_LANMAN10 | DF_LANMAN20 |
  281. DF_LANMAN21 | DF_MIXEDCASE | DF_LONGNAME |
  282. DF_SUPPORTEA | DF_TIME_IS_UTC )
  283. };
  284. ULONG s_NumberOfDialects = sizeof(s_SmbDialects) / sizeof(s_SmbDialects[0]);
  285. PBYTE s_pNegotiateSmb = NULL;
  286. PBYTE s_pNegotiateSmbRemoteBoot = NULL;
  287. ULONG s_NegotiateSmbLength = 0;
  288. PBYTE s_pEchoSmb = NULL;
  289. BYTE s_EchoData[] = "JlJmIhClBsr";
  290. #define SMB_ECHO_COUNT (1)
  291. // Number of ticks 100ns ticks in a day.
  292. LARGE_INTEGER s_MaxTimeZoneBias;
  293. extern NTSTATUS
  294. GetNTSecurityParameters(
  295. PSMB_ADMIN_EXCHANGE pSmbAdminExchange,
  296. PSMBCE_SERVER pServer,
  297. PUNICODE_STRING pDomainName,
  298. PRESP_NT_NEGOTIATE pNtNegotiateResponse,
  299. ULONG BytesIndicated,
  300. ULONG BytesAvailable,
  301. PULONG pBytesTaken,
  302. PMDL *pDataBufferPointer,
  303. PULONG pDataSize);
  304. extern NTSTATUS
  305. GetLanmanSecurityParameters(
  306. PSMB_ADMIN_EXCHANGE pSmbAdminExchange,
  307. PSMBCE_SERVER pServer,
  308. PRESP_NEGOTIATE pNegotiateResponse,
  309. ULONG BytesIndicated);
  310. extern VOID
  311. GetLanmanTimeBias(
  312. PSMBCE_SERVER pServer,
  313. PRESP_NEGOTIATE pNegotiateResponse);
  314. // Number of 100 ns ticks in one minute
  315. #define ONE_MINUTE_IN_TIME (60 * 1000 * 10000)
  316. NTSTATUS
  317. MRxSmbInitializeEchoProbeService(
  318. PMRXSMB_ECHO_PROBE_SERVICE_CONTEXT pEchoProbeContext)
  319. /*++
  320. Routine Description:
  321. This routine builds the echo SMB
  322. Return Value:
  323. STATUS_SUCCESS if construction of an ECHO smb was successful
  324. Other Status codes correspond to error situations.
  325. --*/
  326. {
  327. NTSTATUS Status = STATUS_SUCCESS;
  328. ULONG DialectIndex;
  329. PSMB_HEADER pSmbHeader = NULL;
  330. PREQ_ECHO pReqEcho = NULL;
  331. PAGED_CODE();
  332. pEchoProbeContext->EchoSmbLength = sizeof(SMB_HEADER) +
  333. FIELD_OFFSET(REQ_ECHO,Buffer) +
  334. sizeof(s_EchoData);
  335. pEchoProbeContext->pEchoSmb = (PBYTE)RxAllocatePoolWithTag(
  336. NonPagedPool,
  337. pEchoProbeContext->EchoSmbLength,
  338. MRXSMB_ECHO_POOLTAG);
  339. if (pEchoProbeContext->pEchoSmb != NULL) {
  340. pSmbHeader = (PSMB_HEADER)pEchoProbeContext->pEchoSmb;
  341. pReqEcho = (PREQ_ECHO)((PBYTE)pEchoProbeContext->pEchoSmb + sizeof(SMB_HEADER));
  342. // Fill in the header
  343. RtlZeroMemory( pSmbHeader, sizeof( SMB_HEADER ) );
  344. *(PULONG)(&pSmbHeader->Protocol) = (ULONG)SMB_HEADER_PROTOCOL;
  345. // By default, paths in SMBs are marked as case insensitive and
  346. // canonicalized.
  347. pSmbHeader->Flags =
  348. SMB_FLAGS_CASE_INSENSITIVE | SMB_FLAGS_CANONICALIZED_PATHS;
  349. // Get the flags2 field out of the SmbContext
  350. SmbPutAlignedUshort(
  351. &pSmbHeader->Flags2,
  352. (SMB_FLAGS2_KNOWS_LONG_NAMES |
  353. SMB_FLAGS2_KNOWS_EAS |
  354. SMB_FLAGS2_IS_LONG_NAME |
  355. SMB_FLAGS2_NT_STATUS |
  356. SMB_FLAGS2_UNICODE));
  357. // Fill in the process id.
  358. SmbPutUshort(&pSmbHeader->Pid, MRXSMB_PROCESS_ID );
  359. SmbPutUshort(&pSmbHeader->Tid,0xffff); // Invalid TID
  360. // Lastly, fill in the smb command code.
  361. pSmbHeader->Command = (UCHAR) SMB_COM_ECHO;
  362. pReqEcho->WordCount = 1;
  363. RtlMoveMemory( pReqEcho->Buffer, s_EchoData, sizeof( s_EchoData ) );
  364. SmbPutUshort(&pReqEcho->EchoCount, SMB_ECHO_COUNT);
  365. SmbPutUshort(&pReqEcho->ByteCount, (USHORT) sizeof( s_EchoData ) );
  366. } else {
  367. Status = STATUS_INSUFFICIENT_RESOURCES;
  368. }
  369. return Status;
  370. }
  371. VOID
  372. MRxSmbTearDownEchoProbeService(
  373. PMRXSMB_ECHO_PROBE_SERVICE_CONTEXT pEchoProbeContext)
  374. /*++
  375. Routine Description:
  376. This routine tears down the echo processing context
  377. --*/
  378. {
  379. PAGED_CODE();
  380. if (pEchoProbeContext->pEchoSmb != NULL) {
  381. RxFreePool(pEchoProbeContext->pEchoSmb);
  382. pEchoProbeContext->pEchoSmb = NULL;
  383. }
  384. }
  385. ULONG MRxSmbNegotiateMask = 6; //controls which protocols are not negotiated
  386. //#define MRXSMB_ALLOW_NEGOTIATE_MASKING
  387. #ifdef MRXSMB_ALLOW_NEGOTIATE_MASKING
  388. ULONG MRxSmbCapturedNegotiateMask = 0; //indicates which protocols are currently defeated
  389. CHAR MRxSmbDefeatString[] = "xyz";
  390. VOID
  391. MRxSmbMaskNegotiateSmb ()
  392. /*++
  393. Routine Description:
  394. This routine masks the negotiate buffer to reduce the number of dialects that are
  395. negotiated.
  396. Arguments:
  397. none
  398. Return Value:
  399. NA
  400. --*/
  401. {
  402. PREQ_NEGOTIATE pReqNegotiate;
  403. PUCHAR p,pshadow,q;
  404. ULONG i,numberofdialects,negotiatemask;
  405. PAGED_CODE();
  406. if ((MRxSmbNegotiateMask == MRxSmbCapturedNegotiateMask)
  407. || (s_pNegotiateSmb == NULL) ){
  408. return;
  409. }
  410. pReqNegotiate = (PREQ_NEGOTIATE)(s_pNegotiateSmb + sizeof(SMB_HEADER));
  411. p = pReqNegotiate->Buffer;
  412. pshadow = s_DialectNames;
  413. negotiatemask = MRxSmbNegotiateMask;
  414. numberofdialects = sizeof(MRxSmbDialectFlags)/sizeof(MRxSmbDialectFlags[0]);
  415. DbgPrint("Build Negotiate mask=%x\n",negotiatemask);
  416. for (i=0;;) {
  417. ASSERT(*p == '\2');
  418. ASSERT(*pshadow == '\2');
  419. p++; pshadow++;
  420. DbgPrint("Considering Protocol %s\n",pshadow);
  421. if (negotiatemask&1) {
  422. DbgPrint("Protocol to fffff %s\n",pshadow);
  423. }
  424. //for each protocol, either copy in characters from the defeat string
  425. //or from the original source depending on the mask. here, pshadow points
  426. //to the original, q points to the defeat string and p points to the actual
  427. //bits in the SMB_COM_NEGOTIATE
  428. for (q=MRxSmbDefeatString;;) {
  429. if (*p=='\2') break;
  430. if (*q==0) break;
  431. if (negotiatemask&1) {
  432. *p = *q;
  433. } else {
  434. *p = *pshadow;
  435. }
  436. p++; q++; pshadow++;
  437. }
  438. i++;
  439. if (i>=numberofdialects) break;
  440. negotiatemask>>=1;
  441. //if(negotiate_mask==0)break;
  442. DbgPrint("moving up to i=%d\n",i);
  443. for (;*p!='\2';) {
  444. p++; pshadow++;
  445. }
  446. }
  447. MRxSmbCapturedNegotiateMask = MRxSmbNegotiateMask;
  448. }
  449. #else
  450. #define MRxSmbMaskNegotiateSmb()
  451. #endif
  452. NTSTATUS
  453. BuildNegotiateSmb(
  454. PVOID *pSmbBufferPointer,
  455. PULONG pSmbBufferLength,
  456. BOOLEAN RemoteBootSession)
  457. /*++
  458. Routine Description:
  459. This routine builds the negotiate SMB
  460. Arguments:
  461. pSmbBufferPointer - a placeholder for the smb buffer
  462. pNegotiateSmbLength - the smb buffer size
  463. RemoteBootServer - is this for connection to a remote boot server
  464. Return Value:
  465. STATUS_SUCCESS - implies that pServer is a valid instnace .
  466. Other Status codes correspond to error situations.
  467. --*/
  468. {
  469. NTSTATUS Status = STATUS_SUCCESS;
  470. ULONG DialectIndex;
  471. PSMB_HEADER pSmbHeader = NULL;
  472. PREQ_NEGOTIATE pReqNegotiate = NULL;
  473. PAGED_CODE();
  474. if (s_pNegotiateSmb == NULL) {
  475. s_NegotiateSmbLength = sizeof(SMB_HEADER) +
  476. FIELD_OFFSET(REQ_NEGOTIATE,Buffer) +
  477. sizeof(s_DialectNames);
  478. s_pNegotiateSmb = (PBYTE)RxAllocatePoolWithTag(
  479. PagedPool,
  480. s_NegotiateSmbLength + TRANSPORT_HEADER_SIZE,
  481. MRXSMB_ADMIN_POOLTAG);
  482. if (s_pNegotiateSmb != NULL) {
  483. s_pNegotiateSmb += TRANSPORT_HEADER_SIZE;
  484. pSmbHeader = (PSMB_HEADER)s_pNegotiateSmb;
  485. pReqNegotiate = (PREQ_NEGOTIATE)(s_pNegotiateSmb + sizeof(SMB_HEADER));
  486. // Fill in the header
  487. RtlZeroMemory( pSmbHeader, sizeof( SMB_HEADER ) );
  488. *(PULONG)(&pSmbHeader->Protocol) = (ULONG)SMB_HEADER_PROTOCOL;
  489. // By default, paths in SMBs are marked as case insensitive and
  490. // canonicalized.
  491. pSmbHeader->Flags =
  492. SMB_FLAGS_CASE_INSENSITIVE | SMB_FLAGS_CANONICALIZED_PATHS;
  493. // Put our flags2 field. The Ox10 is a temporary flag for SLM
  494. // corruption detection
  495. SmbPutAlignedUshort(
  496. &pSmbHeader->Flags2,
  497. (SMB_FLAGS2_KNOWS_LONG_NAMES
  498. | SMB_FLAGS2_KNOWS_EAS
  499. | SMB_FLAGS2_IS_LONG_NAME
  500. | SMB_FLAGS2_NT_STATUS
  501. | SMB_FLAGS2_UNICODE
  502. | SMB_FLAGS2_EXTENDED_SECURITY
  503. | 0x10
  504. ));
  505. // Fill in the process id.
  506. SmbPutUshort( &pSmbHeader->Pid, MRXSMB_PROCESS_ID );
  507. // Lastly, fill in the smb command code.
  508. pSmbHeader->Command = (UCHAR) SMB_COM_NEGOTIATE;
  509. pReqNegotiate->WordCount = 0;
  510. RtlMoveMemory(
  511. pReqNegotiate->Buffer,
  512. s_DialectNames,
  513. sizeof( s_DialectNames ) );
  514. SmbPutUshort(
  515. &pReqNegotiate->ByteCount,
  516. (USHORT) sizeof( s_DialectNames ) );
  517. // Initialize the maximum time zone bias used in negotiate response parsing.
  518. s_MaxTimeZoneBias.QuadPart = Int32x32To64(24*60*60,1000*10000);
  519. } else {
  520. Status = STATUS_INSUFFICIENT_RESOURCES;
  521. }
  522. }
  523. if (MRxSmbBootedRemotely && s_pNegotiateSmbRemoteBoot == NULL) {
  524. s_pNegotiateSmbRemoteBoot = (PBYTE)RxAllocatePoolWithTag(
  525. PagedPool,
  526. s_NegotiateSmbLength + TRANSPORT_HEADER_SIZE,
  527. MRXSMB_ADMIN_POOLTAG);
  528. if (s_pNegotiateSmbRemoteBoot != NULL) {
  529. USHORT RemoteBootFlags2;
  530. //
  531. // Now that s_pNegotiateSmb has been filled in, copy it to
  532. // s_pNegotiateSmbRemoteBoot and modify as needed. We don't
  533. // worry about masking s_pNegotiateSmbRemoteBoot.
  534. //
  535. s_pNegotiateSmbRemoteBoot += TRANSPORT_HEADER_SIZE;
  536. RtlCopyMemory(s_pNegotiateSmbRemoteBoot,
  537. s_pNegotiateSmb,
  538. s_NegotiateSmbLength);
  539. pSmbHeader = (PSMB_HEADER)s_pNegotiateSmbRemoteBoot;
  540. //
  541. // Turn off the SMB_FLAGS2_EXTENDED_SECURITY bit.
  542. //
  543. RemoteBootFlags2 = SmbGetAlignedUshort(&pSmbHeader->Flags2);
  544. RemoteBootFlags2 &= ~SMB_FLAGS2_EXTENDED_SECURITY;
  545. SmbPutAlignedUshort(&pSmbHeader->Flags2,
  546. RemoteBootFlags2);
  547. } else {
  548. RxFreePool(s_pNegotiateSmb - TRANSPORT_HEADER_SIZE);
  549. Status = STATUS_INSUFFICIENT_RESOURCES;
  550. }
  551. }
  552. if (NT_SUCCESS(Status)) {
  553. *pSmbBufferLength = s_NegotiateSmbLength;
  554. if (RemoteBootSession) {
  555. *pSmbBufferPointer = s_pNegotiateSmbRemoteBoot;
  556. } else {
  557. *pSmbBufferPointer = s_pNegotiateSmb;
  558. }
  559. }
  560. MRxSmbMaskNegotiateSmb();
  561. return Status;
  562. }
  563. ULONG MRxSmbSrvWriteBufSize = 0xffff; //use the negotiated size
  564. NTSTATUS
  565. ParseNegotiateResponse(
  566. IN OUT PSMB_ADMIN_EXCHANGE pSmbAdminExchange,
  567. IN ULONG BytesIndicated,
  568. IN ULONG BytesAvailable,
  569. OUT PULONG pBytesTaken,
  570. IN PSMB_HEADER pSmbHeader,
  571. OUT PMDL *pDataBufferPointer,
  572. OUT PULONG pDataSize)
  573. /*++
  574. Routine Description:
  575. This routine parses the response from the server
  576. Arguments:
  577. pServer - the server instance
  578. pDomainName - the domain name string to be extracted from the response
  579. pSmbHeader - the response SMB
  580. BytesAvailable - length of the response
  581. pBytesTaken - response consumed
  582. Return Value:
  583. STATUS_SUCCESS - the server call construction has been finalized.
  584. Other Status codes correspond to error situations.
  585. Notes:
  586. The SMB servers can speak a variety of dialects of the SMB protocol. The initial
  587. negotiate response can come in one of three possible flavours. Either we get the
  588. NT negotiate response SMB from a NT server or the extended response from DOS and
  589. OS/2 servers or the CORE response from other servers.
  590. --*/
  591. {
  592. NTSTATUS Status = STATUS_SUCCESS;
  593. PSMBCEDB_SERVER_ENTRY pServerEntry;
  594. PSMBCE_SERVER pServer;
  595. PUNICODE_STRING pDomainName;
  596. USHORT DialectIndex;
  597. PRESP_NEGOTIATE pNegotiateResponse;
  598. ULONG NegotiateSmbLength;
  599. ASSERT( pSmbHeader != NULL );
  600. pServerEntry = SmbCeGetExchangeServerEntry(pSmbAdminExchange);
  601. pServer = &pServerEntry->Server;
  602. if (sizeof(SMB_HEADER) + FIELD_OFFSET(RESP_NEGOTIATE, Buffer) > BytesIndicated) {
  603. *pBytesTaken = BytesAvailable;
  604. pServerEntry->ServerStatus = STATUS_INVALID_NETWORK_RESPONSE;
  605. return Status;
  606. }
  607. pDomainName = &pSmbAdminExchange->Negotiate.DomainName;
  608. pNegotiateResponse = (PRESP_NEGOTIATE) (pSmbHeader + 1);
  609. NegotiateSmbLength = sizeof(SMB_HEADER);
  610. *pBytesTaken = NegotiateSmbLength;
  611. // Assume that the indicated response is sufficient. The only cases in which this
  612. // will not be TRUE is for the EXTENDED NEGOITIATE in which the security blob
  613. // is passed back. In all other cases the TDI imposed minimum of 128 bytes
  614. // subsumes the negotiate response.
  615. *pDataBufferPointer = NULL;
  616. *pDataSize = 0;
  617. DialectIndex = SmbGetUshort( &pNegotiateResponse->DialectIndex );
  618. if (DialectIndex == (USHORT) -1) {
  619. // means server cannot accept any requests from
  620. *pBytesTaken = BytesAvailable;
  621. pServerEntry->ServerStatus = STATUS_REQUEST_NOT_ACCEPTED;
  622. return Status;
  623. }
  624. if (pNegotiateResponse->WordCount < 1 || DialectIndex > s_NumberOfDialects) {
  625. *pBytesTaken = BytesAvailable;
  626. pServerEntry->ServerStatus = STATUS_INVALID_NETWORK_RESPONSE;
  627. return Status;
  628. }
  629. // set the domain name length to zero ( default initialization )
  630. pDomainName->Length = 0;
  631. // Fix up the dialect type and the corresponding dispatch vector.
  632. pServer->Dialect = (SMB_DIALECT)DialectIndex;
  633. pServer->DialectFlags = MRxSmbDialectFlags[DialectIndex];
  634. pServer->pDispatch = &s_SmbServerDispatchVectors[s_SmbDialects[DialectIndex].DispatchVectorIndex];
  635. // Parse the response based upon the type of negotiate response expected.
  636. switch (s_SmbDialects[DialectIndex].NegotiateType) {
  637. case SMB_NT_NEGOTIATE:
  638. {
  639. ULONG NegotiateResponseLength;
  640. LARGE_INTEGER ZeroTime;
  641. LARGE_INTEGER LocalTimeBias;
  642. LARGE_INTEGER ServerTimeBias;
  643. PRESP_NT_NEGOTIATE pNtNegotiateResponse = (PRESP_NT_NEGOTIATE) pNegotiateResponse;
  644. if (sizeof(SMB_HEADER) + FIELD_OFFSET(RESP_NT_NEGOTIATE, Buffer) > BytesAvailable) {
  645. *pBytesTaken = BytesAvailable;
  646. pServerEntry->ServerStatus = STATUS_INVALID_NETWORK_RESPONSE;
  647. return Status;
  648. }
  649. if (pNtNegotiateResponse->WordCount != 17) {
  650. *pBytesTaken = BytesAvailable;
  651. Status = STATUS_INVALID_NETWORK_RESPONSE;
  652. } else {
  653. // parse and map the capabilities.
  654. ULONG NtCapabilities;
  655. NegotiateResponseLength = FIELD_OFFSET(RESP_NT_NEGOTIATE,Buffer) +
  656. SmbGetUshort(&pNtNegotiateResponse->ByteCount);
  657. NegotiateSmbLength += NegotiateResponseLength;
  658. //Start with a clean slate
  659. pServer->Capabilities = 0;
  660. // Initialize server based constants
  661. pServer->MaximumRequests = SmbGetUshort( &pNtNegotiateResponse->MaxMpxCount );
  662. pServer->MaximumVCs = SmbGetUshort( &pNtNegotiateResponse->MaxNumberVcs );
  663. pServer->MaximumBufferSize = SmbGetUlong( &pNtNegotiateResponse->MaxBufferSize );
  664. NtCapabilities = pServer->NtServer.NtCapabilities = SmbGetUlong(&pNtNegotiateResponse->Capabilities);
  665. if (NtCapabilities & CAP_RAW_MODE) {
  666. pServer->Capabilities |= (RAW_READ_CAPABILITY | RAW_WRITE_CAPABILITY);
  667. }
  668. if ((NtCapabilities & CAP_COMPRESSED_DATA) &&
  669. MRxSmbEnableCompression) {
  670. pServer->Capabilities |= COMPRESSED_DATA_CAPABILITY;
  671. }
  672. if (NtCapabilities & CAP_DFS) {
  673. pServer->Capabilities |= CAP_DFS;
  674. }
  675. if (NtCapabilities & CAP_LWIO) {
  676. pServer->Capabilities |= LWIO_CAPABILITY;
  677. }
  678. //copy other nt capabilities into the dialog flags
  679. if (NtCapabilities & CAP_UNICODE) {
  680. pServer->DialectFlags |= DF_UNICODE;
  681. }
  682. if (NtCapabilities & CAP_LARGE_FILES) {
  683. pServer->DialectFlags |= DF_LARGE_FILES;
  684. }
  685. if (NtCapabilities & CAP_NT_SMBS) {
  686. pServer->DialectFlags |= DF_NT_SMBS | DF_NT_FIND;
  687. }
  688. if (NtCapabilities & CAP_NT_FIND) {
  689. pServer->DialectFlags |= DF_NT_FIND;
  690. }
  691. if (NtCapabilities & CAP_RPC_REMOTE_APIS) {
  692. pServer->DialectFlags |= DF_RPC_REMOTE;
  693. }
  694. if (NtCapabilities & CAP_NT_STATUS) {
  695. pServer->DialectFlags |= DF_NT_STATUS;
  696. }
  697. if (NtCapabilities & CAP_LEVEL_II_OPLOCKS) {
  698. pServer->DialectFlags |= DF_OPLOCK_LVL2;
  699. }
  700. if (NtCapabilities & CAP_LOCK_AND_READ) {
  701. pServer->DialectFlags |= DF_LOCKREAD;
  702. }
  703. if (NtCapabilities & CAP_EXTENDED_SECURITY) {
  704. pServer->DialectFlags |= DF_EXTENDED_SECURITY;
  705. }
  706. if (NtCapabilities & CAP_INFOLEVEL_PASSTHRU) {
  707. pServer->DialectFlags |= DF_NT_INFO_PASSTHROUGH;
  708. }
  709. // For non disk files the LARGE_READX capability is not useful.
  710. pServer->MaximumNonDiskFileReadBufferSize =
  711. pServer->MaximumBufferSize -
  712. QuadAlign(
  713. sizeof(SMB_HEADER) +
  714. FIELD_OFFSET(
  715. REQ_NT_READ_ANDX,
  716. Buffer[0]));
  717. if (NtCapabilities & CAP_LARGE_READX) {
  718. if (NtCapabilities & CAP_LARGE_WRITEX) {
  719. pServer->MaximumDiskFileReadBufferSize = 60*1024;
  720. } else {
  721. // The maximum size for reads to servers which support
  722. // large read and x is constrained by the USHORT to record
  723. // lengths in the SMB. Thus the maximum length that can be used
  724. // is (65536 - 1) . This length should accomodate the header as
  725. // well as the rest of the SMB. Actually, tho, we cut back to 60K.
  726. pServer->MaximumDiskFileReadBufferSize = 60*1024;
  727. }
  728. } else {
  729. pServer->MaximumDiskFileReadBufferSize = pServer->MaximumNonDiskFileReadBufferSize;
  730. }
  731. // Specifying a zero local time will give you the time zone bias
  732. ZeroTime.HighPart = ZeroTime.LowPart = 0;
  733. ExLocalTimeToSystemTime( &ZeroTime, &LocalTimeBias );
  734. ServerTimeBias = RtlEnlargedIntegerMultiply(
  735. (LONG)SmbGetUshort(
  736. &pNtNegotiateResponse->ServerTimeZone),
  737. ONE_MINUTE_IN_TIME );
  738. pServer->TimeZoneBias.QuadPart = ServerTimeBias.QuadPart -
  739. LocalTimeBias.QuadPart;
  740. if (!FlagOn(pServer->DialectFlags,DF_NT_SMBS)) {
  741. //sigh...........
  742. pServer->DialectFlags &= ~(DF_MIXEDCASEPW);
  743. pServer->DialectFlags |= DF_W95;
  744. }
  745. Status = GetNTSecurityParameters(
  746. pSmbAdminExchange,
  747. pServer,
  748. pDomainName,
  749. pNtNegotiateResponse,
  750. BytesIndicated,
  751. BytesAvailable,
  752. pBytesTaken,
  753. pDataBufferPointer,
  754. pDataSize);
  755. pServer->MaximumNonDiskFileWriteBufferSize =
  756. min(
  757. MRxSmbSrvWriteBufSize,
  758. pServer->MaximumBufferSize -
  759. QuadAlign(
  760. sizeof(SMB_HEADER) +
  761. FIELD_OFFSET(
  762. REQ_NT_WRITE_ANDX,
  763. Buffer[0])));
  764. if (NtCapabilities & CAP_LARGE_WRITEX &&
  765. !(MRxSmbSecuritySignaturesEnabled && pServer->SecuritySignaturesEnabled)) {
  766. pServer->DialectFlags |= DF_LARGE_WRITEX;
  767. pServer->MaximumDiskFileWriteBufferSize = 0x10000;
  768. } else {
  769. pServer->MaximumDiskFileWriteBufferSize =
  770. pServer->MaximumNonDiskFileWriteBufferSize;
  771. }
  772. }
  773. }
  774. break;
  775. case SMB_EXTENDED_NEGOTIATE :
  776. {
  777. // An SMB_EXTENDED_NEGOTIATE response is never partially indicated. The response
  778. // length is ithin the TDI minimum for indication.
  779. USHORT RawMode;
  780. // DOS or OS2 server
  781. if (pNegotiateResponse->WordCount != 13 &&
  782. pNegotiateResponse->WordCount != 10 && // some downlevel server returns invalid WordCount
  783. pNegotiateResponse->WordCount != 8) {
  784. Status = STATUS_INVALID_NETWORK_RESPONSE;
  785. } else {
  786. NegotiateSmbLength += FIELD_OFFSET(RESP_NEGOTIATE,Buffer) +
  787. SmbGetUshort(&pNegotiateResponse->ByteCount);
  788. if (BytesIndicated < NegotiateSmbLength) {
  789. *pBytesTaken = BytesAvailable;
  790. pServerEntry->ServerStatus = STATUS_INVALID_NETWORK_RESPONSE;
  791. return Status;
  792. }
  793. RawMode = SmbGetUshort( &pNegotiateResponse->RawMode );
  794. pServer->Capabilities |= ((RawMode & 0x1) != 0
  795. ? RAW_READ_CAPABILITY : 0);
  796. pServer->Capabilities |= ((RawMode & 0x2) != 0
  797. ? RAW_WRITE_CAPABILITY : 0);
  798. if (pSmbHeader->Flags & SMB_FLAGS_LOCK_AND_READ_OK) {
  799. pServer->DialectFlags |= DF_LOCKREAD;
  800. }
  801. pServer->EncryptPasswords = FALSE;
  802. pServer->MaximumVCs = 1;
  803. pServer->MaximumBufferSize = SmbGetUshort( &pNegotiateResponse->MaxBufferSize );
  804. pServer->MaximumDiskFileReadBufferSize =
  805. pServer->MaximumBufferSize -
  806. QuadAlign(
  807. sizeof(SMB_HEADER) +
  808. FIELD_OFFSET(
  809. RESP_READ_ANDX,
  810. Buffer[0]));
  811. pServer->MaximumNonDiskFileReadBufferSize = pServer->MaximumDiskFileReadBufferSize;
  812. pServer->MaximumDiskFileWriteBufferSize = pServer->MaximumDiskFileReadBufferSize;
  813. pServer->MaximumNonDiskFileWriteBufferSize = pServer->MaximumDiskFileReadBufferSize;
  814. pServer->MaximumRequests = SmbGetUshort(
  815. &pNegotiateResponse->MaxMpxCount );
  816. pServer->MaximumVCs = SmbGetUshort(
  817. &pNegotiateResponse->MaxNumberVcs );
  818. if (pNegotiateResponse->WordCount == 13) {
  819. //CODE.IMPROVEMENT use the DF_bit for this
  820. switch (pServer->Dialect) {
  821. case LANMAN10_DIALECT:
  822. case WFW10_DIALECT:
  823. case LANMAN12_DIALECT:
  824. case LANMAN21_DIALECT:
  825. GetLanmanTimeBias( pServer,pNegotiateResponse );
  826. break;
  827. }
  828. Status = GetLanmanSecurityParameters(pSmbAdminExchange,pServer,pNegotiateResponse,BytesIndicated);
  829. }
  830. }
  831. *pBytesTaken = BytesAvailable;
  832. }
  833. break;
  834. case SMB_CORE_NEGOTIATE :
  835. default :
  836. {
  837. // An SMB_CORE_NEGOTIATE response is never partially indicated. The response
  838. // length is ithin the TDI minimum for indication.
  839. pServer->SecurityMode = SECURITY_MODE_SHARE_LEVEL;
  840. pServer->EncryptPasswords = FALSE;
  841. pServer->MaximumBufferSize = 0;
  842. pServer->MaximumRequests = 1;
  843. pServer->MaximumVCs = 1;
  844. pServer->SessionKey = 0;
  845. if (pSmbHeader->Flags & SMB_FLAGS_OPLOCK) {
  846. pServer->DialectFlags |= DF_OPLOCK;
  847. }
  848. *pBytesTaken = BytesAvailable;
  849. ASSERT(BytesIndicated == BytesAvailable);
  850. }
  851. }
  852. if (pServer->MaximumRequests == 0) {
  853. //
  854. // If this is a Lanman 1.0 or better server, this is a invalid negotiate
  855. // response. For others it would have been set to 1.
  856. //
  857. Status = STATUS_INVALID_NETWORK_RESPONSE;
  858. }
  859. if ((Status == STATUS_SUCCESS) ||
  860. (Status == STATUS_MORE_PROCESSING_REQUIRED)) {
  861. // Note that this code relies on the minimum incication size covering
  862. // the negotiate response header.
  863. // Check to make sure that the time zone bias isn't more than +-24
  864. // hours.
  865. //
  866. #ifndef WIN9X
  867. if ((pServer->TimeZoneBias.QuadPart > s_MaxTimeZoneBias.QuadPart) ||
  868. (-pServer->TimeZoneBias.QuadPart > s_MaxTimeZoneBias.QuadPart)) {
  869. #else
  870. if ((pServer->TimeZoneBias.HighPart > s_MaxTimeZoneBias.HighPart) ||
  871. (-pServer->TimeZoneBias.HighPart > s_MaxTimeZoneBias.HighPart)) {
  872. #endif
  873. // Set the bias to 0 - assume local time zone.
  874. pServer->TimeZoneBias.LowPart = pServer->TimeZoneBias.HighPart = 0;
  875. }
  876. // Do not allow negotiated buffersize to exceed the size of a USHORT.
  877. // Remove 4096 bytes to avoid overrun and make it easier to handle
  878. // than 0xffff
  879. pServer->MaximumBufferSize =
  880. (pServer->MaximumBufferSize < 0x00010000) ? pServer->MaximumBufferSize :
  881. 0x00010000 - 4096;
  882. } else {
  883. pServerEntry->ServerStatus = Status;
  884. *pBytesTaken = BytesAvailable;
  885. Status = STATUS_SUCCESS;
  886. }
  887. if ((pServer->DialectFlags & DF_NTNEGOTIATE)!=0) {
  888. InterlockedIncrement(&MRxSmbStatistics.LanmanNtConnects);
  889. } else if ((pServer->DialectFlags & DF_LANMAN21)!=0) {
  890. InterlockedIncrement(&MRxSmbStatistics.Lanman21Connects);
  891. } else if ((pServer->DialectFlags & DF_LANMAN20)!=0) {
  892. InterlockedIncrement(&MRxSmbStatistics.Lanman20Connects);
  893. } else {
  894. InterlockedIncrement(&MRxSmbStatistics.CoreConnects);
  895. }
  896. if (pServer->MaximumRequests > (USHORT)MRxSmbConfiguration.MaximumNumberOfCommands) {
  897. pServer->MaximumRequests = (USHORT)MRxSmbConfiguration.MaximumNumberOfCommands;
  898. }
  899. if (MRxSmbSecuritySignaturesRequired &&
  900. !pServer->SecuritySignaturesEnabled &&
  901. pServerEntry->ServerStatus == STATUS_SUCCESS ) {
  902. // the client refuses to connect to a server that doesn't support security
  903. // signature which is required by the client.
  904. pServerEntry->ServerStatus = STATUS_LOGIN_WKSTA_RESTRICTION;
  905. }
  906. return Status;
  907. }
  908. NTSTATUS
  909. GetNTSecurityParameters(
  910. PSMB_ADMIN_EXCHANGE pSmbAdminExchange,
  911. PSMBCE_SERVER pServer,
  912. PUNICODE_STRING pDomainName,
  913. PRESP_NT_NEGOTIATE pNtNegotiateResponse,
  914. ULONG BytesIndicated,
  915. ULONG BytesAvailable,
  916. PULONG pBytesTaken,
  917. PMDL *pDataBufferPointer,
  918. PULONG pDataSize)
  919. /*++
  920. Routine Description:
  921. This routine extracts the security parameters from an NT server
  922. Arguments:
  923. pServer - the server
  924. pDomainName - the domain name
  925. pNtNegotiateResponse - the response
  926. NegotiateResponseLength - size of the negotiate response
  927. Return Value:
  928. STATUS_SUCCESS - implies that pServer is a valid instnace .
  929. Other Status codes correspond to error situations.
  930. --*/
  931. {
  932. NTSTATUS Status = STATUS_SUCCESS;
  933. USHORT ByteCount;
  934. PUSHORT pByteCountInSmb =
  935. ((PUSHORT)((PUCHAR) pNtNegotiateResponse + 1)) +
  936. pNtNegotiateResponse->WordCount;
  937. PUCHAR pBuffer = (PUCHAR)(pByteCountInSmb + 1);
  938. *pBytesTaken += FIELD_OFFSET(RESP_NT_NEGOTIATE,Buffer);
  939. ByteCount = SmbGetUshort(pByteCountInSmb);
  940. pServer->SecurityMode = (((pNtNegotiateResponse->SecurityMode & NEGOTIATE_USER_SECURITY) != 0)
  941. ? SECURITY_MODE_USER_LEVEL
  942. : SECURITY_MODE_SHARE_LEVEL);
  943. pServer->EncryptPasswords = ((pNtNegotiateResponse->SecurityMode & NEGOTIATE_ENCRYPT_PASSWORDS) != 0);
  944. pServer->EncryptionKeyLength = 0;
  945. pServer->SecuritySignaturesEnabled = ((pNtNegotiateResponse->SecurityMode &
  946. NEGOTIATE_SECURITY_SIGNATURES_ENABLED) != 0);
  947. pServer->SecuritySignaturesRequired = ((pNtNegotiateResponse->SecurityMode &
  948. NEGOTIATE_SECURITY_SIGNATURES_REQUIRED) != 0);
  949. if (BooleanFlagOn(pServer->NtServer.NtCapabilities,CAP_EXTENDED_SECURITY)) {
  950. ULONG SecurityBlobLength;
  951. // The server supports the new security validation scheme. In such cases
  952. // the BLOB to be passed to the local security package is shipped as
  953. // part of the negotiate response.
  954. if ((ByteCount < sizeof(GUID)) ||
  955. (*pBytesTaken + sizeof(GUID) > BytesIndicated)) {
  956. *pBytesTaken = BytesAvailable;
  957. pSmbAdminExchange->Status = STATUS_INVALID_NETWORK_RESPONSE;
  958. return STATUS_SUCCESS;
  959. }
  960. // Extract the Server GUID
  961. RtlCopyMemory(
  962. &pServer->NtServer.ServerGuid,
  963. pBuffer,
  964. sizeof(GUID));
  965. *pBytesTaken += sizeof(GUID);
  966. if (pServer->NtServer.pSecurityBlob != NULL) {
  967. RxFreePool(pServer->NtServer.pSecurityBlob);
  968. pServer->NtServer.pSecurityBlob = NULL;
  969. pServer->NtServer.SecurityBlobLength = 0;
  970. }
  971. // Allocate the Blob and copy the security Blob from the response
  972. if ((SecurityBlobLength = ByteCount - sizeof(GUID)) > 0) {
  973. pServer->NtServer.pSecurityBlob = RxAllocatePoolWithTag(
  974. NonPagedPool,
  975. SecurityBlobLength,
  976. MRXSMB_ADMIN_POOLTAG);
  977. if (pServer->NtServer.pSecurityBlob != NULL) {
  978. pServer->NtServer.SecurityBlobLength = SecurityBlobLength;
  979. // If the Blob has been completely indicated it can be copied directly.
  980. // On the other hand if it is not completely indicated an MDl needs to
  981. // be setup to allow the underlying TDI layer to complete the copy
  982. // into the allocated buffer. This entails allocating an MDL of the
  983. // appropriate size and setting it up.
  984. if ((*pBytesTaken + SecurityBlobLength) <= BytesIndicated) {
  985. RtlCopyMemory(
  986. pServer->NtServer.pSecurityBlob,
  987. (pBuffer + sizeof(GUID)),
  988. SecurityBlobLength);
  989. *pBytesTaken += SecurityBlobLength;
  990. ASSERT(*pBytesTaken == BytesAvailable);
  991. } else {
  992. if ((*pBytesTaken + SecurityBlobLength) <= BytesAvailable) {
  993. // In this case the blob was not indicated completely.
  994. *pDataBufferPointer = RxAllocateMdl(
  995. pServer->NtServer.pSecurityBlob,
  996. SecurityBlobLength);
  997. if (*pDataBufferPointer == NULL) {
  998. RxFreePool(pServer->NtServer.pSecurityBlob);
  999. pServer->NtServer.pSecurityBlob = NULL;
  1000. pServer->NtServer.SecurityBlobLength = 0;
  1001. Status = STATUS_INSUFFICIENT_RESOURCES;
  1002. } else {
  1003. MmBuildMdlForNonPagedPool(*pDataBufferPointer);
  1004. *pDataSize = SecurityBlobLength;
  1005. Status = STATUS_MORE_PROCESSING_REQUIRED;
  1006. }
  1007. } else {
  1008. *pBytesTaken = BytesAvailable;
  1009. Status = STATUS_SUCCESS;
  1010. pSmbAdminExchange->Status = STATUS_INVALID_NETWORK_RESPONSE;
  1011. }
  1012. }
  1013. } else {
  1014. Status = STATUS_INSUFFICIENT_RESOURCES;
  1015. }
  1016. }
  1017. } else {
  1018. *pBytesTaken = BytesAvailable;
  1019. pServer->SessionKey = SmbGetUlong( &pNtNegotiateResponse->SessionKey );
  1020. if (pServer->EncryptPasswords) {
  1021. if (BytesIndicated < sizeof(SMB_HEADER) + FIELD_OFFSET(RESP_NT_NEGOTIATE, Buffer) + ByteCount ) {
  1022. *pBytesTaken = BytesAvailable;
  1023. pSmbAdminExchange->Status = STATUS_INVALID_NETWORK_RESPONSE;
  1024. return STATUS_SUCCESS;
  1025. }
  1026. pServer->EncryptionKeyLength = pNtNegotiateResponse->EncryptionKeyLength;
  1027. if (pServer->EncryptionKeyLength != 0) {
  1028. ASSERT( CRYPT_TXT_LEN == MSV1_0_CHALLENGE_LENGTH );
  1029. if (pServer->EncryptionKeyLength != CRYPT_TXT_LEN) {
  1030. Status = STATUS_INVALID_NETWORK_RESPONSE;
  1031. } else {
  1032. RtlCopyMemory(
  1033. pServer->EncryptionKey,
  1034. pBuffer,
  1035. pServer->EncryptionKeyLength );
  1036. if (ByteCount - pServer->EncryptionKeyLength > 0) {
  1037. pBuffer = pBuffer + pServer->EncryptionKeyLength;
  1038. pDomainName->Length = ByteCount - pServer->EncryptionKeyLength;
  1039. if (pDomainName->Length <= pDomainName->MaximumLength) {
  1040. if (pDomainName->Length & 1) {
  1041. // The remainder of the length is odd. This implies that the server did
  1042. // some alignment.
  1043. pBuffer++;
  1044. pDomainName->Length -= 1;
  1045. }
  1046. RtlCopyMemory(
  1047. pDomainName->Buffer,
  1048. pBuffer,
  1049. pDomainName->Length);
  1050. } else {
  1051. pDomainName->Length = 0;
  1052. Status = STATUS_BUFFER_OVERFLOW;
  1053. }
  1054. }
  1055. }
  1056. }
  1057. }
  1058. }
  1059. return Status;
  1060. }
  1061. NTSTATUS
  1062. GetLanmanSecurityParameters(
  1063. PSMB_ADMIN_EXCHANGE pSmbAdminExchange,
  1064. PSMBCE_SERVER pServer,
  1065. PRESP_NEGOTIATE pNegotiateResponse,
  1066. ULONG BytesIndicated)
  1067. /*++
  1068. Routine Description:
  1069. This routine extracts the security parameters from a LANMAN server
  1070. Arguments:
  1071. pServer - the server
  1072. pNtNegotiateResponse - the response
  1073. Return Value:
  1074. STATUS_SUCCESS - implies that pServer is a valid instnace .
  1075. Other Status codes correspond to error situations.
  1076. --*/
  1077. {
  1078. USHORT i;
  1079. USHORT SecurityMode;
  1080. pServer->SessionKey = SmbGetUlong( &pNegotiateResponse->SessionKey );
  1081. SecurityMode = SmbGetUshort( &pNegotiateResponse->SecurityMode );
  1082. pServer->SecurityMode = (((SecurityMode & 1) != 0)
  1083. ? SECURITY_MODE_USER_LEVEL
  1084. : SECURITY_MODE_SHARE_LEVEL);
  1085. pServer->EncryptPasswords = ((SecurityMode & 2) != 0);
  1086. if (pServer->EncryptPasswords) {
  1087. if (pServer->Dialect == LANMAN21_DIALECT) {
  1088. pServer->EncryptionKeyLength = SmbGetUshort(&pNegotiateResponse->EncryptionKeyLength);
  1089. } else {
  1090. pServer->EncryptionKeyLength = SmbGetUshort(&pNegotiateResponse->ByteCount);
  1091. }
  1092. if (pServer->EncryptionKeyLength != 0) {
  1093. if (pServer->EncryptionKeyLength > CRYPT_TXT_LEN) {
  1094. return( STATUS_INVALID_NETWORK_RESPONSE );
  1095. }
  1096. if (BytesIndicated < sizeof(SMB_HEADER) + FIELD_OFFSET(RESP_NEGOTIATE, Buffer) + pServer->EncryptionKeyLength) {
  1097. pSmbAdminExchange->Status = STATUS_INVALID_NETWORK_RESPONSE;
  1098. return STATUS_SUCCESS;
  1099. }
  1100. for (i = 0; i < pServer->EncryptionKeyLength; i++) {
  1101. pServer->EncryptionKey[i] = pNegotiateResponse->Buffer[i];
  1102. }
  1103. }
  1104. }
  1105. return( STATUS_SUCCESS );
  1106. }
  1107. LARGE_INTEGER
  1108. ConvertSmbTimeToTime (
  1109. IN SMB_TIME Time,
  1110. IN SMB_DATE Date
  1111. )
  1112. /*++
  1113. Routine Description:
  1114. This routine converts an SMB time to an NT time structure.
  1115. Arguments:
  1116. IN SMB_TIME Time - Supplies the time of day to convert
  1117. IN SMB_DATE Date - Supplies the day of the year to convert
  1118. IN PSERVERLISTENTRY Server - if supplied, supplies the server for tz bias.
  1119. Return Value:
  1120. LARGE_INTEGER - Time structure describing input time.
  1121. --*/
  1122. {
  1123. TIME_FIELDS TimeFields;
  1124. LARGE_INTEGER OutputTime;
  1125. //
  1126. // This routine cannot be paged because it is called from both the
  1127. // RdrFileDiscardableSection and the RdrVCDiscardableSection.
  1128. //
  1129. if (SmbIsTimeZero(&Date) && SmbIsTimeZero(&Time)) {
  1130. OutputTime.LowPart = OutputTime.HighPart = 0;
  1131. } else {
  1132. TimeFields.Year = Date.Struct.Year + (USHORT )1980;
  1133. TimeFields.Month = Date.Struct.Month;
  1134. TimeFields.Day = Date.Struct.Day;
  1135. TimeFields.Hour = Time.Struct.Hours;
  1136. TimeFields.Minute = Time.Struct.Minutes;
  1137. TimeFields.Second = Time.Struct.TwoSeconds*(USHORT )2;
  1138. TimeFields.Milliseconds = 0;
  1139. //
  1140. // Make sure that the times specified in the SMB are reasonable
  1141. // before converting them.
  1142. //
  1143. if (TimeFields.Year < 1601) {
  1144. TimeFields.Year = 1601;
  1145. }
  1146. if (TimeFields.Month > 12) {
  1147. TimeFields.Month = 12;
  1148. }
  1149. if (TimeFields.Hour >= 24) {
  1150. TimeFields.Hour = 23;
  1151. }
  1152. if (TimeFields.Minute >= 60) {
  1153. TimeFields.Minute = 59;
  1154. }
  1155. if (TimeFields.Second >= 60) {
  1156. TimeFields.Second = 59;
  1157. }
  1158. if (!RtlTimeFieldsToTime(&TimeFields, &OutputTime)) {
  1159. OutputTime.HighPart = 0;
  1160. OutputTime.LowPart = 0;
  1161. return OutputTime;
  1162. }
  1163. ExLocalTimeToSystemTime(&OutputTime, &OutputTime);
  1164. }
  1165. return OutputTime;
  1166. }
  1167. VOID
  1168. GetLanmanTimeBias(
  1169. PSMBCE_SERVER pServer,
  1170. PRESP_NEGOTIATE pNegotiateResponse)
  1171. /*++
  1172. Routine Description:
  1173. This routine extracts the time bias from a Lanman server
  1174. Arguments:
  1175. pServer - the server
  1176. pNtNegotiateResponse - the response
  1177. Return Value:
  1178. STATUS_SUCCESS - implies that pServer is a valid instnace .
  1179. Other Status codes correspond to error situations.
  1180. --*/
  1181. {
  1182. // If this is a LM 1.0 or 2.0 server (ie a non NT server), we
  1183. // remember the timezone and bias our time based on this value.
  1184. //
  1185. // The redirector assumes that all times from these servers are
  1186. // local time for the server, and converts them to local time
  1187. // using this bias. It then tells the user the local time for
  1188. // the file on the server.
  1189. LARGE_INTEGER Workspace, ServerTime, CurrentTime;
  1190. BOOLEAN Negated = FALSE;
  1191. SMB_TIME SmbServerTime;
  1192. SMB_DATE SmbServerDate;
  1193. SmbMoveTime(&SmbServerTime, &pNegotiateResponse->ServerTime);
  1194. SmbMoveDate(&SmbServerDate, &pNegotiateResponse->ServerDate);
  1195. ServerTime = ConvertSmbTimeToTime(SmbServerTime, SmbServerDate);
  1196. KeQuerySystemTime(&CurrentTime);
  1197. #ifndef WIN9X
  1198. Workspace.QuadPart = CurrentTime.QuadPart - ServerTime.QuadPart;
  1199. #else
  1200. RxLiSubLi(&Workspace.QuadPart, &CurrentTime.QuadPart, &ServerTime.QuadPart);
  1201. #endif
  1202. if ( Workspace.HighPart < 0) {
  1203. // avoid using -ve large integers to routines that accept only unsigned
  1204. #ifndef WIN9X
  1205. Workspace.QuadPart = -Workspace.QuadPart;
  1206. #else
  1207. Workspace.HighPart = -Workspace.HighPart;
  1208. Workspace.LowPart = -Workspace.LowPart;
  1209. #endif
  1210. Negated = TRUE;
  1211. }
  1212. //
  1213. // Workspace has the exact difference in 100ns intervals
  1214. // between the server and redirector times. To remove the minor
  1215. // difference between the time settings on the two machines we
  1216. // round the Bias to the nearest 30 minutes.
  1217. //
  1218. // Calculate ((exact bias+15minutes)/30minutes)* 30minutes
  1219. // then convert back to the bias time.
  1220. //
  1221. #ifndef WIN9X
  1222. Workspace.QuadPart += ((LONGLONG) ONE_MINUTE_IN_TIME) * 15;
  1223. // Workspace is now exact bias + 15 minutes in 100ns units
  1224. Workspace.QuadPart /= ((LONGLONG) ONE_MINUTE_IN_TIME) * 30;
  1225. pServer->TimeZoneBias.QuadPart = Workspace.QuadPart * ((LONGLONG) ONE_MINUTE_IN_TIME) * 30;
  1226. #else
  1227. pServer->TimeZoneBias.HighPart = Workspace.HighPart;
  1228. pServer->TimeZoneBias.LowPart = Workspace.LowPart;
  1229. #endif
  1230. if ( Negated == TRUE ) {
  1231. #ifndef WIN9X
  1232. pServer->TimeZoneBias.QuadPart = -pServer->TimeZoneBias.QuadPart;
  1233. #else
  1234. pServer->TimeZoneBias.HighPart = -pServer->TimeZoneBias.HighPart;
  1235. pServer->TimeZoneBias.LowPart = -pServer->TimeZoneBias.LowPart;
  1236. #endif
  1237. }
  1238. }
  1239. NTSTATUS
  1240. MRxSmbCheckTransportName(
  1241. IN PIRP Irp,
  1242. OUT PSMBCEDB_SERVER_ENTRY *ppServerEntry)
  1243. /*++
  1244. Routine Description:
  1245. This routine implements the transport name checking on existing connection the server.
  1246. If the tranport name is provided on the Irp, we have 3 cases:
  1247. 1. There is no connection to the the server requested;
  1248. 2. There is an existing connection to the server and the transport used by the connection has
  1249. the same name as provided;
  1250. 3. There is an existing connection to the server and the transport used by the connection has
  1251. the different name as provided.
  1252. This routine will force to tear down the connection on case 3 and let the server reconnected
  1253. on the new transport.
  1254. Arguments:
  1255. Irp - Supplies the Irp being processed
  1256. Return Value:
  1257. NTSTATUS - The return status for the operation
  1258. --*/
  1259. {
  1260. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1261. PSMBCEDB_SERVER_ENTRY pServerEntry = NULL;
  1262. NTSTATUS Status = STATUS_SUCCESS;
  1263. PFILE_FULL_EA_INFORMATION pEaEntry;
  1264. pEaEntry = (PFILE_FULL_EA_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
  1265. if ((pEaEntry != NULL) && (Irp->Flags & IRP_CREATE_OPERATION)) {
  1266. if (IrpSp->Parameters.Create.Options & FILE_CREATE_TREE_CONNECTION) {
  1267. for(;;) {
  1268. if (strcmp(pEaEntry->EaName, EA_NAME_TRANSPORT) == 0) {
  1269. if (pEaEntry->EaValueLength > 0) {
  1270. RXCE_TRANSPORT RxCeTransport;
  1271. USHORT NameLength;
  1272. PUNICODE_STRING ServerName = &IrpSp->FileObject->FileName;
  1273. PUNICODE_STRING TransportName = NULL;
  1274. if (pEaEntry->EaValueLength > 0) {
  1275. TransportName = RxAllocatePoolWithTag(
  1276. NonPagedPool,
  1277. (sizeof(UNICODE_STRING) + pEaEntry->EaValueLength),
  1278. MRXSMB_MISC_POOLTAG);
  1279. } else {
  1280. break;
  1281. }
  1282. if (TransportName != NULL) {
  1283. TransportName->Length = pEaEntry->EaValueLength;
  1284. TransportName->MaximumLength = pEaEntry->EaValueLength;
  1285. TransportName->Buffer = (PWCHAR)((PCHAR)TransportName + sizeof(UNICODE_STRING));
  1286. RtlCopyMemory(
  1287. TransportName->Buffer,
  1288. pEaEntry->EaName + pEaEntry->EaNameLength + 1,
  1289. TransportName->Length);
  1290. } else {
  1291. Status = STATUS_INSUFFICIENT_RESOURCES;
  1292. break;
  1293. }
  1294. NameLength = ServerName->Length;
  1295. SmbCeAcquireResource();
  1296. pServerEntry = SmbCeGetFirstServerEntry();
  1297. while (pServerEntry != NULL) {
  1298. if ((NameLength > pServerEntry->Name.Length) &&
  1299. (ServerName->Buffer[pServerEntry->Name.Length/2] == OBJ_NAME_PATH_SEPARATOR)) {
  1300. ServerName->Length = pServerEntry->Name.Length;
  1301. if (RtlEqualUnicodeString(
  1302. &pServerEntry->Name,
  1303. ServerName,
  1304. TRUE)) {
  1305. if (pServerEntry->Header.State == SMBCEDB_CONSTRUCTION_IN_PROGRESS) {
  1306. pServerEntry = NULL;
  1307. Status = STATUS_CONNECTION_ACTIVE;
  1308. break;
  1309. }
  1310. SmbCeReferenceServerEntry(pServerEntry);
  1311. if (pServerEntry->pTransport != NULL) {
  1312. RxCeTransport = pServerEntry->pTransport->pTransport->RxCeTransport;
  1313. if (!RtlEqualUnicodeString(
  1314. &RxCeTransport.Name,
  1315. TransportName,
  1316. TRUE)) {
  1317. PSMBCE_TRANSPORT PreferredTransport;
  1318. if (!MRxSmbBootedRemotely &&
  1319. IsListEmpty(&pServerEntry->ActiveExchanges) &&
  1320. (pServerEntry->Server.NumberOfSrvOpens == 0) && //needs to be fixed
  1321. (InterlockedCompareExchange(&(pServerEntry->TransportSpecifiedByUser),1,0) == 0) &&
  1322. ((PreferredTransport = SmbCeFindTransport(TransportName)) != NULL)) {
  1323. if (pServerEntry->Server.NumberOfSrvOpens > 0) {
  1324. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry = NULL;
  1325. pNetRootEntry = SmbCeGetFirstNetRootEntry(pServerEntry);
  1326. while (pNetRootEntry != NULL) {
  1327. RxFinalizeNetRoot((PNET_ROOT)pNetRootEntry->pRdbssNetRoot,TRUE,FALSE);
  1328. pNetRootEntry = SmbCeGetNextNetRootEntry(pServerEntry,pNetRootEntry);
  1329. }
  1330. }
  1331. RxDbgTrace(0, Dbg, ("Force tear down connection over Transport: %wZ\n", &RxCeTransport.Name));
  1332. SmbCeTransportDisconnectIndicated(pServerEntry);
  1333. RxDbgTrace(0, Dbg, ("Build connection over Transport: %wZ\n", TransportName));
  1334. if (pServerEntry->PreferredTransport != NULL) {
  1335. SmbCeDereferenceTransport(pServerEntry->PreferredTransport);
  1336. }
  1337. pServerEntry->PreferredTransport = PreferredTransport;
  1338. } else {
  1339. SmbCeDereferenceServerEntry(pServerEntry);
  1340. pServerEntry = NULL;
  1341. Status = STATUS_CONNECTION_ACTIVE;
  1342. }
  1343. }
  1344. }
  1345. break;
  1346. }
  1347. }
  1348. pServerEntry = SmbCeGetNextServerEntry(pServerEntry);
  1349. }
  1350. SmbCeReleaseResource();
  1351. RxFreePool(TransportName);
  1352. ServerName->Length = NameLength;
  1353. }
  1354. break;
  1355. } else {
  1356. if (pEaEntry->NextEntryOffset == 0) {
  1357. break;
  1358. } else
  1359. pEaEntry = (PFILE_FULL_EA_INFORMATION)
  1360. ((PCHAR) pEaEntry + pEaEntry->NextEntryOffset);
  1361. }
  1362. }
  1363. }
  1364. }
  1365. *ppServerEntry = pServerEntry;
  1366. return Status;
  1367. }