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.

971 lines
35 KiB

  1. /*++
  2. Copyright (c) 1987-1999 Microsoft Corporation
  3. Module Name:
  4. sessetup.c
  5. Abstract:
  6. This module implements the Session setup related routines
  7. --*/
  8. #include "precomp.h"
  9. #pragma hdrstop
  10. #include "ntlmsp.h"
  11. //
  12. // The local debug trace level
  13. //
  14. #define Dbg (DEBUG_TRACE_DISPATCH)
  15. #ifdef ALLOC_PRAGMA
  16. #pragma alloc_text(PAGE, BuildSessionSetupSmb)
  17. #pragma alloc_text(PAGE, BuildNtLanmanResponsePrologue)
  18. #pragma alloc_text(PAGE, BuildNtLanmanResponseEpilogue)
  19. #pragma alloc_text(PAGE, BuildSessionSetupSecurityInformation)
  20. #pragma alloc_text(PAGE, BuildTreeConnectSecurityInformation)
  21. #endif
  22. BOOLEAN EnablePlainTextPassword = FALSE;
  23. NTSTATUS
  24. BuildSessionSetupSmb(
  25. PSMB_EXCHANGE pExchange,
  26. PGENERIC_ANDX pAndXSmb,
  27. PULONG pAndXSmbBufferSize)
  28. /*++
  29. Routine Description:
  30. This routine builds the session setup SMB for a NT server
  31. Arguments:
  32. pExchange - the exchange instance
  33. pAndXSmb - the session setup to be filled in
  34. pAndXSmbBufferSize - the SMB buffer size on input modified to remaining size on
  35. output.
  36. Return Value:
  37. NTSTATUS - The return status for the operation
  38. Notes:
  39. Eventhough the general structure of the code tries to isolate dialect specific issues
  40. as much as possible this routine takes the opposite approach. This is because of the
  41. preamble and prologue to security interaction which far outweigh the dialect specific
  42. work required to be done. Therefore in the interests of a smaller footprint this approach
  43. has been adopted.
  44. --*/
  45. {
  46. NTSTATUS Status;
  47. PSMBCEDB_SESSION_ENTRY pSessionEntry;
  48. PSMBCE_SERVER pServer;
  49. PSMBCE_SESSION pSession;
  50. PREQ_SESSION_SETUP_ANDX pSessionSetup;
  51. PREQ_NT_SESSION_SETUP_ANDX pNtSessionSetup;
  52. ULONG OriginalBufferSize = *pAndXSmbBufferSize;
  53. PAGED_CODE();
  54. pSessionEntry = SmbCeGetExchangeSessionEntry(pExchange);
  55. pServer = SmbCeGetExchangeServer(pExchange);
  56. pSession = SmbCeGetExchangeSession(pExchange);
  57. // There are three different variants of session setup and X that can be shipped to the
  58. // server. All three of them share some common fields. The setting of these common fields
  59. // is done in all the three cases by accessing the passed in buffer as an instance of
  60. // REQ_SESSION_SETUP_ANDX. The fields specific to the remaining two are conditionalized upon
  61. // accessing the same buffer as an instance of REQ_NT_SESSION_SETUP_ANDX. This implies that
  62. // great care must be taken in shuffling the fields in these two structs.
  63. pSessionSetup = (PREQ_SESSION_SETUP_ANDX)pAndXSmb;
  64. pNtSessionSetup = (PREQ_NT_SESSION_SETUP_ANDX)pSessionSetup;
  65. pSessionSetup->AndXCommand = 0xff; // No ANDX
  66. pSessionSetup->AndXReserved = 0x00; // Reserved (MBZ)
  67. SmbPutUshort(&pSessionSetup->AndXOffset, 0x0000); // No AndX as of yet.
  68. // Since we can allocate pool dynamically, we set our buffer size
  69. // to match that of the server.
  70. SmbPutUshort(&pSessionSetup->MaxBufferSize, (USHORT)pServer->MaximumBufferSize);
  71. SmbPutUshort(&pSessionSetup->MaxMpxCount, pServer->MaximumRequests);
  72. SmbPutUshort(&pSessionSetup->VcNumber, (USHORT)pSessionEntry->SessionVCNumber);
  73. SmbPutUlong(&pSessionSetup->SessionKey, pServer->SessionKey);
  74. SmbPutUlong(&pSessionSetup->Reserved, 0);
  75. if (pServer->Dialect == NTLANMAN_DIALECT) {
  76. // Set up the NT server session setup specific parameters.
  77. SmbPutUshort(&pNtSessionSetup->WordCount,13);
  78. // Set the capabilities
  79. SmbPutUlong(
  80. &pNtSessionSetup->Capabilities,
  81. (CAP_NT_STATUS |
  82. CAP_UNICODE |
  83. CAP_LEVEL_II_OPLOCKS |
  84. CAP_NT_SMBS ));
  85. } else {
  86. SmbPutUshort(&pSessionSetup->WordCount,10);
  87. }
  88. // Build the security information in the session setup SMB.
  89. Status = BuildSessionSetupSecurityInformation(
  90. pExchange,
  91. (PBYTE)pSessionSetup,
  92. pAndXSmbBufferSize);
  93. if (NT_SUCCESS(Status)) {
  94. // Copy the operating system name and the LANMAN version info
  95. // position the buffer for copying the operating system name and the lanman type.
  96. PBYTE pBuffer = (PBYTE)pSessionSetup +
  97. OriginalBufferSize -
  98. *pAndXSmbBufferSize;
  99. if (FlagOn(pServer->DialectFlags,DF_UNICODE)){
  100. //
  101. // Make sure the UNICODE string is suitably aligned
  102. //
  103. if( ((ULONG_PTR)pBuffer) & 01 ) {
  104. pBuffer++;
  105. (*pAndXSmbBufferSize)--;
  106. }
  107. Status = SmbPutUnicodeString(
  108. &pBuffer,
  109. &SmbCeContext.OperatingSystem,
  110. pAndXSmbBufferSize);
  111. if (NT_SUCCESS(Status)) {
  112. Status = SmbPutUnicodeString(
  113. &pBuffer,
  114. &SmbCeContext.LanmanType,
  115. pAndXSmbBufferSize);
  116. }
  117. } else {
  118. Status = SmbPutUnicodeStringAsOemString(
  119. &pBuffer,
  120. &SmbCeContext.OperatingSystem,
  121. pAndXSmbBufferSize);
  122. if (NT_SUCCESS(Status)) {
  123. Status = SmbPutUnicodeStringAsOemString(
  124. &pBuffer,
  125. &SmbCeContext.LanmanType,
  126. pAndXSmbBufferSize);
  127. }
  128. }
  129. if (NT_SUCCESS(Status)) {
  130. if (pServer->Dialect == NTLANMAN_DIALECT) {
  131. SmbPutUshort(
  132. &pNtSessionSetup->ByteCount,
  133. (USHORT)(OriginalBufferSize -
  134. FIELD_OFFSET(REQ_NT_SESSION_SETUP_ANDX,Buffer) -
  135. *pAndXSmbBufferSize));
  136. } else {
  137. SmbPutUshort(
  138. &pSessionSetup->ByteCount,
  139. (USHORT)(OriginalBufferSize -
  140. FIELD_OFFSET(REQ_SESSION_SETUP_ANDX,Buffer) -
  141. *pAndXSmbBufferSize));
  142. }
  143. }
  144. }
  145. return Status;
  146. }
  147. #define IsCredentialHandleValid(pCredHandle) \
  148. (((pCredHandle)->dwLower != 0xffffffff) && ((pCredHandle)->dwUpper != 0xffffffff))
  149. #define IsSecurityContextHandleValid(pContextHandle) \
  150. (((pContextHandle)->dwLower != 0xffffffff) && ((pContextHandle)->dwUpper != 0xffffffff))
  151. NTSTATUS
  152. BuildNtLanmanResponsePrologue(
  153. PSMB_EXCHANGE pExchange,
  154. PUNICODE_STRING pUserName,
  155. PUNICODE_STRING pDomainName,
  156. PSTRING pCaseSensitiveResponse,
  157. PSTRING pCaseInsensitiveResponse,
  158. PSECURITY_RESPONSE_CONTEXT pResponseContext)
  159. /*++
  160. Routine Description:
  161. This routine builds the security related information for the session setup SMB.
  162. Arguments:
  163. Return Value:
  164. RXSTATUS - The return status for the operation
  165. Notes:
  166. --*/
  167. {
  168. NTSTATUS Status;
  169. NTSTATUS FinalStatus;
  170. UNICODE_STRING ServerName;
  171. PVOID pTargetInformation;
  172. ULONG TargetInformationSize;
  173. SecBufferDesc InputToken;
  174. SecBuffer InputBuffer[2];
  175. SecBufferDesc *pOutputBufferDescriptor = NULL;
  176. SecBuffer *pOutputBuffer = NULL;
  177. ULONG_PTR OutputBufferDescriptorSize;
  178. ULONG LsaFlags = ISC_REQ_ALLOCATE_MEMORY;
  179. TimeStamp Expiry;
  180. PCHALLENGE_MESSAGE InToken = NULL;
  181. ULONG InTokenSize;
  182. PNTLM_CHALLENGE_MESSAGE NtlmInToken = NULL;
  183. ULONG NtlmInTokenSize = 0;
  184. PAUTHENTICATE_MESSAGE OutToken = NULL;
  185. PNTLM_INITIALIZE_RESPONSE NtlmOutToken = NULL;
  186. PUCHAR p = NULL;
  187. ULONG_PTR AllocateSize;
  188. PSMBCE_SERVER pServer = SmbCeGetExchangeServer(pExchange);
  189. PSMBCE_SESSION pSession = SmbCeGetExchangeSession(pExchange);
  190. PAGED_CODE();
  191. try {
  192. pResponseContext->LanmanSetup.pResponseBuffer = NULL;
  193. SmbCeGetServerName(
  194. pExchange->SmbCeContext.pVNetRoot->pNetRoot->pSrvCall,
  195. &ServerName);
  196. TargetInformationSize = ServerName.Length;
  197. pTargetInformation = ServerName.Buffer;
  198. InTokenSize = sizeof(CHALLENGE_MESSAGE) + TargetInformationSize;
  199. NtlmInTokenSize = sizeof(NTLM_CHALLENGE_MESSAGE);
  200. if (pSession->pPassword != NULL) {
  201. NtlmInTokenSize += pSession->pPassword->Length;
  202. LsaFlags |= ISC_REQ_USE_SUPPLIED_CREDS;
  203. }
  204. if (pSession->pUserName != NULL) {
  205. NtlmInTokenSize += pSession->pUserName->Length;
  206. LsaFlags |= ISC_REQ_USE_SUPPLIED_CREDS;
  207. }
  208. if (pSession->pUserDomainName != NULL) {
  209. NtlmInTokenSize += pSession->pUserDomainName->Length;
  210. LsaFlags |= ISC_REQ_USE_SUPPLIED_CREDS;
  211. }
  212. // For Alignment purposes, we want InTokenSize rounded up to
  213. // the nearest word size.
  214. AllocateSize = ((InTokenSize + 3) & ~3) + NtlmInTokenSize;
  215. Status = ZwAllocateVirtualMemory(
  216. NtCurrentProcess(),
  217. &InToken,
  218. 0L,
  219. &AllocateSize,
  220. MEM_COMMIT,
  221. PAGE_READWRITE);
  222. if (!NT_SUCCESS(Status)) {
  223. try_return(Status);
  224. }
  225. // Allocate the output buffer
  226. OutputBufferDescriptorSize = sizeof(SecBufferDesc) + 2 * sizeof(SecBuffer);
  227. Status = ZwAllocateVirtualMemory(
  228. NtCurrentProcess(),
  229. &pOutputBufferDescriptor,
  230. 0L,
  231. &OutputBufferDescriptorSize,
  232. MEM_COMMIT,
  233. PAGE_READWRITE);
  234. if (!NT_SUCCESS(Status)) {
  235. try_return(Status);
  236. }
  237. pOutputBuffer = (SecBuffer *)(pOutputBufferDescriptor + 1);
  238. pResponseContext->LanmanSetup.pResponseBuffer = pOutputBufferDescriptor;
  239. RxDbgTrace(0,Dbg,("Allocate VM %08lx in process %8lx\n", InToken, NtCurrentProcess()));
  240. // partition off the NTLM in token part of the
  241. // buffer
  242. if (LsaFlags & ISC_REQ_USE_SUPPLIED_CREDS)
  243. {
  244. NtlmInToken = (PNTLM_CHALLENGE_MESSAGE) ((PUCHAR) InToken + InTokenSize);
  245. NtlmInToken = (PNTLM_CHALLENGE_MESSAGE) (((ULONG_PTR) NtlmInToken + 3) & ~3);
  246. RtlZeroMemory(NtlmInToken,NtlmInTokenSize);
  247. p = (PUCHAR) NtlmInToken + sizeof(NTLM_CHALLENGE_MESSAGE);
  248. }
  249. if(!IsCredentialHandleValid(&pSession->CredentialHandle)) {
  250. UNICODE_STRING LMName;
  251. TimeStamp LifeTime;
  252. LMName.Buffer = (PWSTR) InToken;
  253. LMName.Length = NTLMSP_NAME_SIZE;
  254. LMName.MaximumLength = LMName.Length;
  255. RtlCopyMemory(
  256. LMName.Buffer,
  257. NTLMSP_NAME,
  258. NTLMSP_NAME_SIZE);
  259. Status = AcquireCredentialsHandleW(
  260. NULL,
  261. &LMName,
  262. SECPKG_CRED_OUTBOUND,
  263. &pSession->LogonId,
  264. NULL,
  265. NULL,
  266. (PVOID)1,
  267. &pSession->CredentialHandle,
  268. &LifeTime);
  269. if(!NT_SUCCESS(Status)) {
  270. pSession->CredentialHandle.dwUpper = 0xffffffff;
  271. pSession->CredentialHandle.dwLower = 0xffffffff;
  272. try_return(Status);
  273. }
  274. }
  275. // Copy in the pass,user,domain if they were specified
  276. if(pSession->pPassword != NULL) {
  277. NtlmInToken->Password.Length = pSession->pPassword->Length;
  278. NtlmInToken->Password.MaximumLength = pSession->pPassword->Length;
  279. RtlCopyMemory(
  280. p,
  281. pSession->pPassword->Buffer,
  282. pSession->pPassword->Length);
  283. NtlmInToken->Password.Buffer = (ULONG) (p - (PUCHAR)NtlmInToken);
  284. p += pSession->pPassword->Length;
  285. }
  286. if(pSession->pUserName != NULL) {
  287. NtlmInToken->UserName.Length = pSession->pUserName->Length;
  288. NtlmInToken->UserName.MaximumLength = pSession->pUserName->Length;
  289. RtlCopyMemory(
  290. p,
  291. pSession->pUserName->Buffer,
  292. pSession->pUserName->Length);
  293. NtlmInToken->UserName.Buffer = (ULONG) (p - (PUCHAR)NtlmInToken);
  294. p += pSession->pUserName->Length;
  295. }
  296. if (pSession->pUserDomainName != NULL) {
  297. NtlmInToken->DomainName.Length = pSession->pUserDomainName->Length;
  298. NtlmInToken->DomainName.MaximumLength = pSession->pUserDomainName->Length;
  299. RtlCopyMemory(
  300. p,
  301. pSession->pUserDomainName->Buffer,
  302. pSession->pUserDomainName->Length);
  303. NtlmInToken->DomainName.Buffer = (ULONG) (p - (PUCHAR)NtlmInToken);
  304. p += pSession->pUserDomainName->Length;
  305. }
  306. RtlCopyMemory(
  307. InToken->Signature,
  308. NTLMSSP_SIGNATURE,
  309. sizeof(NTLMSSP_SIGNATURE));
  310. InToken->MessageType = NtLmChallenge;
  311. InToken->NegotiateFlags = NTLMSSP_NEGOTIATE_UNICODE |
  312. NTLMSSP_NEGOTIATE_OEM |
  313. NTLMSSP_REQUEST_INIT_RESPONSE |
  314. NTLMSSP_TARGET_TYPE_SERVER;
  315. RtlCopyMemory(
  316. InToken->Challenge,
  317. pServer->EncryptionKey,
  318. MSV1_0_CHALLENGE_LENGTH);
  319. InToken->TargetName.Length =
  320. InToken->TargetName.MaximumLength = (USHORT)TargetInformationSize;
  321. InToken->TargetName.Buffer = sizeof(CHALLENGE_MESSAGE);
  322. RtlCopyMemory(
  323. (PCHAR)InToken + sizeof(CHALLENGE_MESSAGE),
  324. pTargetInformation,
  325. TargetInformationSize);
  326. InputToken.pBuffers = InputBuffer;
  327. InputToken.cBuffers = 1;
  328. InputToken.ulVersion = 0;
  329. InputBuffer[0].pvBuffer = InToken;
  330. InputBuffer[0].cbBuffer = InTokenSize;
  331. InputBuffer[0].BufferType = SECBUFFER_TOKEN;
  332. if (LsaFlags & ISC_REQ_USE_SUPPLIED_CREDS)
  333. {
  334. InputToken.cBuffers = 2;
  335. InputBuffer[1].pvBuffer = NtlmInToken;
  336. InputBuffer[1].cbBuffer = NtlmInTokenSize;
  337. InputBuffer[1].BufferType = SECBUFFER_TOKEN;
  338. }
  339. pOutputBufferDescriptor->pBuffers = pOutputBuffer;
  340. pOutputBufferDescriptor->cBuffers = 2;
  341. pOutputBufferDescriptor->ulVersion = 0;
  342. pOutputBuffer[0].pvBuffer = NULL;
  343. pOutputBuffer[0].cbBuffer = 0;
  344. pOutputBuffer[0].BufferType = SECBUFFER_TOKEN;
  345. pOutputBuffer[1].pvBuffer = NULL;
  346. pOutputBuffer[1].cbBuffer = 0;
  347. pOutputBuffer[1].BufferType = SECBUFFER_TOKEN;
  348. Status = InitializeSecurityContextW(
  349. &pSession->CredentialHandle,
  350. (PCtxtHandle)NULL,
  351. NULL,
  352. LsaFlags,
  353. 0,
  354. SECURITY_NATIVE_DREP,
  355. &InputToken,
  356. 0,
  357. &pSession->SecurityContextHandle,
  358. pOutputBufferDescriptor,
  359. &FinalStatus,
  360. &Expiry);
  361. if(!NT_SUCCESS(Status)) {
  362. Status = MapSecurityError(Status);
  363. SmbCeLog(("IniSecCtxStat %lx %lx\n",SmbCeGetExchangeSessionEntry(pExchange),Status));
  364. try_return(Status);
  365. }
  366. OutToken = (PAUTHENTICATE_MESSAGE) pOutputBuffer[0].pvBuffer;
  367. ASSERT(OutToken != NULL);
  368. RxDbgTrace(0,Dbg,("InitSecCtxt OutToken is %8lx\n", OutToken));
  369. // The security response the pointers are encoded in terms off the offset
  370. // from the beginning of the buffer. Make the appropriate adjustments.
  371. if (ARGUMENT_PRESENT(pCaseSensitiveResponse)) {
  372. pCaseSensitiveResponse->Length = OutToken->NtChallengeResponse.Length;
  373. pCaseSensitiveResponse->MaximumLength = OutToken->NtChallengeResponse.MaximumLength;
  374. pCaseSensitiveResponse->Buffer = (PBYTE)OutToken + (ULONG_PTR)OutToken->NtChallengeResponse.Buffer;
  375. }
  376. if (ARGUMENT_PRESENT(pCaseInsensitiveResponse)) {
  377. pCaseInsensitiveResponse->Length = OutToken->LmChallengeResponse.Length;
  378. pCaseInsensitiveResponse->MaximumLength = OutToken->LmChallengeResponse.MaximumLength;
  379. pCaseInsensitiveResponse->Buffer = (PBYTE)OutToken + (ULONG_PTR)OutToken->LmChallengeResponse.Buffer;
  380. }
  381. if (pSession->pUserDomainName != NULL) {
  382. *pDomainName = *(pSession->pUserDomainName);
  383. } else {
  384. pDomainName->Length = OutToken->DomainName.Length;
  385. pDomainName->MaximumLength = pDomainName->Length;
  386. pDomainName->Buffer = (PWCHAR)((PBYTE)OutToken + (ULONG_PTR)OutToken->DomainName.Buffer);
  387. }
  388. if (pSession->pUserName != NULL) {
  389. *pUserName = *(pSession->pUserName);
  390. } else {
  391. pUserName->Length = OutToken->UserName.Length;
  392. pUserName->MaximumLength = OutToken->UserName.MaximumLength;
  393. pUserName->Buffer = (PWCHAR)((PBYTE)OutToken + (ULONG_PTR)OutToken->UserName.Buffer);
  394. }
  395. NtlmOutToken = pOutputBuffer[1].pvBuffer;
  396. if (NtlmOutToken != NULL) {
  397. RtlCopyMemory(
  398. pSession->UserSessionKey,
  399. NtlmOutToken->UserSessionKey,
  400. MSV1_0_USER_SESSION_KEY_LENGTH);
  401. RtlCopyMemory(
  402. pSession->LanmanSessionKey,
  403. NtlmOutToken->LanmanSessionKey,
  404. MSV1_0_LANMAN_SESSION_KEY_LENGTH);
  405. }
  406. try_exit:NOTHING;
  407. } finally {
  408. if (InToken != NULL) {
  409. NTSTATUS TemporaryStatus;
  410. TemporaryStatus = ZwFreeVirtualMemory(
  411. NtCurrentProcess(),
  412. &InToken,
  413. &AllocateSize,
  414. MEM_RELEASE);
  415. ASSERT (NT_SUCCESS(TemporaryStatus));
  416. }
  417. if (!NT_SUCCESS(Status)) {
  418. BuildNtLanmanResponseEpilogue(pExchange, pResponseContext);
  419. }
  420. }
  421. return Status;
  422. }
  423. NTSTATUS
  424. BuildNtLanmanResponseEpilogue(
  425. PSMB_EXCHANGE pExchange,
  426. PSECURITY_RESPONSE_CONTEXT pResponseContext)
  427. {
  428. NTSTATUS Status = STATUS_SUCCESS;
  429. PSMBCE_SESSION pSession = SmbCeGetExchangeSession(pExchange);
  430. PAGED_CODE();
  431. if (pResponseContext->LanmanSetup.pResponseBuffer != NULL) {
  432. ULONG i = 0;
  433. SecBufferDesc *pBufferDescriptor = (SecBufferDesc *)pResponseContext->LanmanSetup.pResponseBuffer;
  434. SecBuffer *pBuffer = pBufferDescriptor->pBuffers;
  435. ULONG_PTR BufferDescriptorSize = sizeof(SecBufferDesc) + 2 * sizeof(SecBuffer);
  436. for (i = 0; i < pBufferDescriptor->cBuffers; i++) {
  437. if (pBuffer[i].pvBuffer != NULL) {
  438. FreeContextBuffer(pBuffer[i].pvBuffer);
  439. }
  440. }
  441. Status = ZwFreeVirtualMemory(
  442. NtCurrentProcess(),
  443. &pBufferDescriptor,
  444. &BufferDescriptorSize,
  445. MEM_RELEASE);
  446. pResponseContext->LanmanSetup.pResponseBuffer = NULL;
  447. }
  448. return Status;
  449. }
  450. VOID
  451. UninitializeSecurityContextsForSession(
  452. PSMBCE_SESSION pSession)
  453. {
  454. CtxtHandle CredentialHandle,SecurityContextHandle,InvalidHandle;
  455. SmbCeLog(("UninitSecCont %lx\n",pSession));
  456. InvalidHandle.dwUpper = 0xffffffff;
  457. InvalidHandle.dwLower = 0xffffffff;
  458. SmbCeAcquireSpinLock();
  459. CredentialHandle = pSession->CredentialHandle;
  460. pSession->CredentialHandle = InvalidHandle;
  461. SecurityContextHandle = pSession->SecurityContextHandle;
  462. pSession->SecurityContextHandle = InvalidHandle;
  463. SmbCeReleaseSpinLock();
  464. if (IsCredentialHandleValid(&CredentialHandle))
  465. {
  466. FreeCredentialsHandle(&CredentialHandle);
  467. }
  468. if (IsSecurityContextHandleValid(&SecurityContextHandle)) {
  469. DeleteSecurityContext(&SecurityContextHandle);
  470. }
  471. }
  472. NTSTATUS
  473. BuildSessionSetupSecurityInformation(
  474. PSMB_EXCHANGE pExchange,
  475. PBYTE pSmbBuffer,
  476. PULONG pSmbBufferSize)
  477. /*++
  478. Routine Description:
  479. This routine builds the security related information for the session setup SMB
  480. Arguments:
  481. pServer - the server instance
  482. pSmbBuffer - the SMB buffer
  483. pSmbBufferSize - the size of the buffer on input ( modified to size remaining on
  484. output)
  485. Return Value:
  486. RXSTATUS - The return status for the operation
  487. Notes:
  488. Eventhough the genral structure of the code tries to isolate dialect specific issues
  489. as much as possible this routine takes the opposite approach. This is because of the
  490. preamble and prologue to security interaction which far outweigh the dialect specific
  491. work required to be done. Therefore in the interests of a smaller footprint this approach
  492. has been adopted.
  493. --*/
  494. {
  495. NTSTATUS Status;
  496. UNICODE_STRING UserName;
  497. UNICODE_STRING DomainName;
  498. STRING CaseSensitiveResponse;
  499. STRING CaseInsensitiveResponse;
  500. PSMBCE_SERVER pServer = SmbCeGetExchangeServer(pExchange);
  501. PSMBCE_SESSION pSession = SmbCeGetExchangeSession(pExchange);
  502. PSMBCEDB_SERVER_ENTRY pServerEntry = SmbCeGetExchangeServerEntry(pExchange);
  503. SECURITY_RESPONSE_CONTEXT ResponseContext;
  504. PAGED_CODE();
  505. RxDbgTrace( +1, Dbg, ("BuildSessionSetupSecurityInformation -- Entry\n"));
  506. Status = BuildNtLanmanResponsePrologue(
  507. pExchange,
  508. &UserName,
  509. &DomainName,
  510. &CaseSensitiveResponse,
  511. &CaseInsensitiveResponse,
  512. &ResponseContext);
  513. if (Status == STATUS_SUCCESS) {
  514. // If the security package returns us the credentials corresponding to a
  515. // NULL session mark the session as a NULL session. This will avoid
  516. // conflicts with the user trying to present the credentials for a NULL
  517. // session, i.e., explicitly specified zero length passwords, user name
  518. // and domain name.
  519. RxDbgTrace(0,Dbg,("Session %lx UN Length %lx DN length %ld IR length %ld SR length %ld\n",
  520. pSession,UserName.Length,DomainName.Length,
  521. CaseInsensitiveResponse.Length,CaseSensitiveResponse.Length));
  522. if ((UserName.Length == 0) &&
  523. (DomainName.Length == 0) &&
  524. (CaseSensitiveResponse.Length == 0) &&
  525. (CaseInsensitiveResponse.Length == 1)) {
  526. RxDbgTrace(0,Dbg,("Implicit NULL session setup\n"));
  527. pSession->Flags |= SMBCE_SESSION_FLAGS_NULL_CREDENTIALS;
  528. }
  529. }
  530. if (NT_SUCCESS(Status)) {
  531. PBYTE pBuffer = pSmbBuffer;
  532. ULONG BufferSize = *pSmbBufferSize;
  533. if ((pServer->Dialect == NTLANMAN_DIALECT) && (pServer->EncryptPasswords)) {
  534. PREQ_NT_SESSION_SETUP_ANDX pNtSessionSetupReq = (PREQ_NT_SESSION_SETUP_ANDX)pSmbBuffer;
  535. // It it is a NT server both the case insensitive and case sensitive passwords
  536. // need to be copied. for share-level, just copy a token 1-byte NULL password
  537. // Position the buffer for copying the password.
  538. pBuffer += FIELD_OFFSET(REQ_NT_SESSION_SETUP_ANDX,Buffer);
  539. BufferSize -= FIELD_OFFSET(REQ_NT_SESSION_SETUP_ANDX,Buffer);
  540. if (pServer->SecurityMode == SECURITY_MODE_USER_LEVEL){
  541. RxDbgTrace( 0, Dbg, ("BuildSessionSetupSecurityInformation -- NtUserPasswords\n"));
  542. SmbPutUshort(
  543. &pNtSessionSetupReq->CaseInsensitivePasswordLength,
  544. CaseInsensitiveResponse.Length);
  545. SmbPutUshort(
  546. &pNtSessionSetupReq->CaseSensitivePasswordLength,
  547. CaseSensitiveResponse.Length);
  548. Status = SmbPutString(
  549. &pBuffer,
  550. &CaseInsensitiveResponse,
  551. &BufferSize);
  552. if (NT_SUCCESS(Status)) {
  553. Status = SmbPutString(
  554. &pBuffer,
  555. &CaseSensitiveResponse,
  556. &BufferSize);
  557. }
  558. } else {
  559. RxDbgTrace( 0, Dbg, ("BuildSessionSetupSecurityInformation -- NtSharePasswords\n"));
  560. SmbPutUshort(&pNtSessionSetupReq->CaseInsensitivePasswordLength, 1);
  561. SmbPutUshort(&pNtSessionSetupReq->CaseSensitivePasswordLength, 1);
  562. *pBuffer = 0;
  563. *(pBuffer+1) = 0;
  564. pBuffer += 2;
  565. BufferSize -= 2;
  566. }
  567. } else {
  568. PREQ_SESSION_SETUP_ANDX pSessionSetupReq = (PREQ_SESSION_SETUP_ANDX)pSmbBuffer;
  569. // Position the buffer for copying the password.
  570. pBuffer += FIELD_OFFSET(REQ_SESSION_SETUP_ANDX,Buffer);
  571. BufferSize -= FIELD_OFFSET(REQ_SESSION_SETUP_ANDX,Buffer);
  572. if ( (pServer->SecurityMode == SECURITY_MODE_USER_LEVEL)
  573. && (CaseInsensitiveResponse.Length > 0)) {
  574. if (pServer->EncryptPasswords) {
  575. // For other lanman servers only the case insensitive password is required.
  576. SmbPutUshort(
  577. &pSessionSetupReq->PasswordLength,
  578. CaseInsensitiveResponse.Length);
  579. // Copy the password
  580. Status = SmbPutString(
  581. &pBuffer,
  582. &CaseInsensitiveResponse,
  583. &BufferSize);
  584. } else {
  585. if (EnablePlainTextPassword) {
  586. if (pSession->pPassword != NULL) {
  587. SmbPutUshort(
  588. &pSessionSetupReq->PasswordLength,
  589. pSession->pPassword->Length/2 + 1);
  590. Status = SmbPutUnicodeStringAsOemString(
  591. &pBuffer,
  592. pSession->pPassword,
  593. &BufferSize);
  594. } else {
  595. SmbPutUshort(&pSessionSetupReq->PasswordLength,1);
  596. *pBuffer++ = '\0';
  597. BufferSize -= sizeof(CHAR);
  598. }
  599. } else {
  600. Status = STATUS_LOGON_FAILURE;
  601. }
  602. }
  603. } else {
  604. // Share level security. Send a null string for the password
  605. SmbPutUshort(&pSessionSetupReq->PasswordLength,1);
  606. *pBuffer++ = '\0';
  607. BufferSize -= sizeof(CHAR);
  608. }
  609. }
  610. // The User name and the domain name strings can be either copied from
  611. // the information returned in the request response or the information
  612. // that is already present in the session entry.
  613. if (NT_SUCCESS(Status)) {
  614. if ((pServer->Dialect == NTLANMAN_DIALECT) &&
  615. (pServer->NtServer.NtCapabilities & CAP_UNICODE)) {
  616. // Copy the account/domain names as UNICODE strings
  617. PBYTE pTempBuffer = pBuffer;
  618. RxDbgTrace( 0, Dbg, ("BuildSessionSetupSecurityInformation -- account/domain as unicode\n"));
  619. pBuffer = ALIGN_SMB_WSTR(pBuffer);
  620. BufferSize -= (ULONG)(pBuffer - pTempBuffer);
  621. Status = SmbPutUnicodeString(
  622. &pBuffer,
  623. &UserName,
  624. &BufferSize);
  625. if (NT_SUCCESS(Status)) {
  626. Status = SmbPutUnicodeString(
  627. &pBuffer,
  628. &DomainName,
  629. &BufferSize);
  630. }
  631. } else {
  632. // Copy the account/domain names as ASCII strings.
  633. RxDbgTrace( 0, Dbg, ("BuildSessionSetupSecurityInformation -- account/domain as ascii\n"));
  634. Status = SmbPutUnicodeStringAsOemString(
  635. &pBuffer,
  636. &UserName,
  637. &BufferSize);
  638. if (NT_SUCCESS(Status)) {
  639. Status = SmbPutUnicodeStringAsOemString(
  640. &pBuffer,
  641. &DomainName,
  642. &BufferSize);
  643. }
  644. }
  645. }
  646. if (NT_SUCCESS(Status)) {
  647. *pSmbBufferSize = BufferSize;
  648. }
  649. }
  650. BuildNtLanmanResponseEpilogue(pExchange, &ResponseContext);
  651. // Detach from the rdr process.
  652. RxDbgTrace( -1, Dbg, ("BuildSessionSetupSecurityInformation -- Exit, status=%08lx\n",Status));
  653. return Status;
  654. }
  655. NTSTATUS
  656. BuildTreeConnectSecurityInformation(
  657. PSMB_EXCHANGE pExchange,
  658. PBYTE pBuffer,
  659. PBYTE pPasswordLength,
  660. PULONG pSmbBufferSize)
  661. /*++
  662. Routine Description:
  663. This routine builds the security related information for the session setup SMB
  664. Arguments:
  665. pServer - the server instance
  666. pLogonId - the logon id. for which the session is being setup
  667. pPassword - the user supplied password if any
  668. pBuffer - the password buffer
  669. pPasswordLength - where the password length is to be stored
  670. pSmbBufferSize - the size of the buffer on input ( modified to size remaining on
  671. output)
  672. Return Value:
  673. NTSTATUS - The return status for the operation
  674. Notes:
  675. Eventhough the genral structure of the code tries to isolate dialect specific issues
  676. as much as possible this routine takes the opposite approach. This is because of the
  677. preamble and prologue to security interaction which far outweigh the dialect specific
  678. work required to be done. Therefore in the interests of a smaller footprint this approach
  679. has been adopted.
  680. --*/
  681. {
  682. NTSTATUS FinalStatus,Status;
  683. UNICODE_STRING UserName,DomainName;
  684. STRING CaseSensitiveChallengeResponse,CaseInsensitiveChallengeResponse;
  685. SECURITY_RESPONSE_CONTEXT ResponseContext;
  686. ULONG PasswordLength = 0;
  687. PSMBCE_SERVER pServer = SmbCeGetExchangeServer(pExchange);
  688. PSMBCE_SESSION pSession = SmbCeGetExchangeSession(pExchange);
  689. PAGED_CODE();
  690. Status = STATUS_SUCCESS;
  691. if (pServer->EncryptPasswords) {
  692. Status = BuildNtLanmanResponsePrologue(
  693. pExchange,
  694. &UserName,
  695. &DomainName,
  696. &CaseSensitiveChallengeResponse,
  697. &CaseInsensitiveChallengeResponse,
  698. &ResponseContext);
  699. if (NT_SUCCESS(Status)) {
  700. if (FlagOn(pServer->DialectFlags,DF_MIXEDCASEPW)) {
  701. RxDbgTrace( 0, Dbg, ("BuildTreeConnectSecurityInformation -- case sensitive password\n"));
  702. // Copy the password length onto the SMB buffer
  703. PasswordLength = CaseSensitiveChallengeResponse.Length;
  704. // Copy the password
  705. Status = SmbPutString(
  706. &pBuffer,
  707. &CaseSensitiveChallengeResponse,
  708. pSmbBufferSize);
  709. } else {
  710. RxDbgTrace( 0, Dbg, ("BuildTreeConnectSecurityInformation -- case insensitive password\n"));
  711. // Copy the password length onto the SMB buffer
  712. PasswordLength = CaseInsensitiveChallengeResponse.Length;
  713. // Copy the password
  714. Status = SmbPutString(
  715. &pBuffer,
  716. &CaseInsensitiveChallengeResponse,
  717. pSmbBufferSize);
  718. }
  719. BuildNtLanmanResponseEpilogue(pExchange, &ResponseContext);
  720. }
  721. } else {
  722. if (pSession->pPassword == NULL) {
  723. // The logon password cannot be sent as plain text. Send a Null string as password.
  724. PasswordLength = 1;
  725. if (*pSmbBufferSize >= 1) {
  726. *((PCHAR)pBuffer) = '\0';
  727. pBuffer += sizeof(CHAR);
  728. Status = STATUS_SUCCESS;
  729. } else {
  730. Status = STATUS_BUFFER_OVERFLOW;
  731. }
  732. } else {
  733. if (EnablePlainTextPassword) {
  734. OEM_STRING OemString;
  735. OemString.Length = OemString.MaximumLength = (USHORT)(*pSmbBufferSize - sizeof(CHAR));
  736. OemString.Buffer = pBuffer;
  737. Status = RtlUnicodeStringToOemString(
  738. &OemString,
  739. pSession->pPassword,
  740. FALSE);
  741. if (NT_SUCCESS(Status)) {
  742. PasswordLength = OemString.Length+1;
  743. }
  744. } else {
  745. Status = STATUS_LOGON_FAILURE;
  746. }
  747. }
  748. // reduce the byte count
  749. *pSmbBufferSize -= PasswordLength;
  750. }
  751. SmbPutUshort(pPasswordLength,(USHORT)PasswordLength);
  752. return Status;
  753. }
  754.