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.

528 lines
17 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. kerbxchg.c
  5. Abstract:
  6. This module implements the routines for setting up a kerberos session.
  7. Author:
  8. Balan Sethu Raman [SethuR] 7-March-1995
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. #include <kerbxchg.h>
  14. #ifdef ALLOC_PRAGMA
  15. #pragma alloc_text(PAGE, SmbKerberosSessionSetupExchangeStart)
  16. #pragma alloc_text(PAGE, ParseKerberosSessionSetupResponse)
  17. #pragma alloc_text(PAGE, SmbKerberosSessionSetupExchangeReceive)
  18. #pragma alloc_text(PAGE, SmbKerberosSessionSetupExchangeSendCompletionHandler)
  19. #pragma alloc_text(PAGE, SmbKerberosSessionSetupExchangeCopyDataHandler)
  20. #pragma alloc_text(PAGE, SmbKerberosSessionSetupExchangeFinalize)
  21. #endif
  22. //
  23. // The Bug check file id for this module
  24. //
  25. #define BugCheckFileId (RDBSS_BUG_CHECK_SMB_NETROOT)
  26. //
  27. // The local debug trace level
  28. //
  29. #define Dbg (DEBUG_TRACE_DISPATCH)
  30. //
  31. // Forward declarations ...
  32. //
  33. #define KERBEROS_SESSION_SETUP_BUFFER_SIZE (4096)
  34. NTSTATUS
  35. SmbKerberosSessionSetupExchangeFinalize(
  36. PSMB_EXCHANGE pExchange,
  37. BOOLEAN *pPostFinalize);
  38. NTSTATUS
  39. SmbKerberosSessionSetupExchangeStart(
  40. PSMB_EXCHANGE pExchange)
  41. /*++
  42. Routine Description:
  43. This is the start routine for net root construction exchanges. This initiates the
  44. construction of the appropriate SMB's if required.
  45. Arguments:
  46. pExchange - the exchange instance
  47. Return Value:
  48. RXSTATUS - The return status for the operation
  49. --*/
  50. {
  51. NTSTATUS Status;
  52. PSMB_KERBEROS_SESSION_SETUP_EXCHANGE pKerberosExchange;
  53. PAGED_CODE();
  54. pKerberosExchange = (PSMB_KERBEROS_SESSION_SETUP_EXCHANGE)pExchange;
  55. ASSERT(pKerberosExchange->Type == KERBEROS_SESSION_SETUP_EXCHANGE);
  56. pKerberosExchange->BufferLength = KERBEROS_SESSION_SETUP_BUFFER_SIZE;
  57. pKerberosExchange->pBuffer = RxAllocatePoolWithTag(
  58. PagedPool,
  59. pKerberosExchange->BufferLength,
  60. MRXSMB_KERBEROS_POOLTAG);
  61. pKerberosExchange->pServerResponseBlob = NULL;
  62. pKerberosExchange->ServerResponseBlobLength = 0;
  63. if (pKerberosExchange->pBuffer == NULL) {
  64. Status = STATUS_INSUFFICIENT_RESOURCES;
  65. } else {
  66. PSMB_HEADER pSmbHeader = (PSMB_HEADER)(pKerberosExchange->pBuffer);
  67. PREQ_NT_SESSION_SETUP_ANDX pSessionSetupRequest;
  68. PGENERIC_ANDX pGenericAndX;
  69. ULONG SmbBufferUnconsumed;
  70. USHORT Flags2 = 0;
  71. // Fill in the buffer header
  72. pSessionSetupRequest = (PREQ_NT_SESSION_SETUP_ANDX)(pSmbHeader + 1);
  73. pGenericAndX = (PGENERIC_ANDX)pSessionSetupRequest;
  74. SmbBufferUnconsumed = pKerberosExchange->BufferLength - sizeof(SMB_HEADER);
  75. ASSERT(pExchange->SmbCeContext.pServerEntry->Server.Dialect == CAIROX_DIALECT);
  76. Flags2 |= (SMB_FLAGS2_UNICODE |
  77. SMB_FLAGS2_KNOWS_EAS |
  78. SMB_FLAGS2_KNOWS_LONG_NAMES |
  79. SMB_FLAGS2_NT_STATUS);
  80. *((PULONG)&pSmbHeader->Protocol) = SMB_HEADER_PROTOCOL;
  81. pSmbHeader->Flags = (SMB_FLAGS_CASE_INSENSITIVE | SMB_FLAGS_CANONICALIZED_PATHS);
  82. pSmbHeader->Flags2 = Flags2;
  83. pSmbHeader->Pid = MRXSMB_PROCESS_ID;
  84. pSmbHeader->Uid = 0;
  85. pSmbHeader->Tid = 0;
  86. pSmbHeader->ErrorClass = 0;
  87. pSmbHeader->Reserved = 0;
  88. pSmbHeader->Command = SMB_COM_SESSION_SETUP_ANDX;
  89. SmbPutUshort(&pSmbHeader->Error,0);
  90. // Build the session setup and x.
  91. Status = SMBCE_SERVER_DIALECT_DISPATCH(
  92. &pExchange->SmbCeContext.pServerEntry->Server,
  93. BuildSessionSetup,
  94. (pExchange,
  95. pGenericAndX,
  96. &SmbBufferUnconsumed));
  97. if (Status == RX_MAP_STATUS(SUCCESS)) {
  98. // Update the buffer for the construction of the following SMB.
  99. SmbPutUshort(&pSessionSetupRequest->AndXOffset,
  100. (USHORT)(pKerberosExchange->BufferLength - SmbBufferUnconsumed));
  101. pSessionSetupRequest->AndXCommand = SMB_COM_NO_ANDX_COMMAND;
  102. pSessionSetupRequest->AndXReserved = 0;
  103. } else {
  104. if (Status == RX_MAP_STATUS(NO_LOGON_SERVERS)) {
  105. // If no kerberos logon servers are available downgrade to a downlevel
  106. // connection and retry.
  107. pKerberosExchange->SmbCeContext.pServerEntry->Server.Dialect = NTLANMAN_DIALECT;
  108. }
  109. SmbCeReferenceSessionEntry(pKerberosExchange->SmbCeContext.pSessionEntry);
  110. SmbCeUpdateSessionEntryState(
  111. pExchange->SmbCeContext.pSessionEntry,
  112. SMBCEDB_INVALID);
  113. SmbCeCompleteSessionEntryInitialization(pExchange->SmbCeContext.pSessionEntry);
  114. pExchange->SmbCeFlags &= ~SMBCE_EXCHANGE_SESSION_CONSTRUCTOR;
  115. }
  116. if (Status == RX_MAP_STATUS(SUCCESS)) {
  117. pKerberosExchange->pBufferAsMdl = RxAllocateMdl(
  118. pKerberosExchange->pBuffer,
  119. KERBEROS_SESSION_SETUP_BUFFER_SIZE);
  120. if (pKerberosExchange->pBufferAsMdl != NULL) {
  121. RxProbeAndLockPages(
  122. pKerberosExchange->pBufferAsMdl,
  123. KernelMode,
  124. IoModifyAccess,
  125. Status);
  126. if (NT_SUCCESS(Status)) {
  127. Status = SmbCeTranceive(
  128. pExchange,
  129. (RXCE_SEND_PARTIAL | RXCE_SEND_SYNCHRONOUS),
  130. pKerberosExchange->pBufferAsMdl,
  131. (pKerberosExchange->BufferLength -
  132. SmbBufferUnconsumed));
  133. RxDbgTrace( 0, Dbg, ("Net Root SmbCeTranceive returned %lx\n",Status));
  134. }
  135. }
  136. }
  137. }
  138. return Status;
  139. }
  140. NTSTATUS
  141. ParseKerberosSessionSetupResponse(
  142. IN PSMB_KERBEROS_SESSION_SETUP_EXCHANGE pKerberosExchange,
  143. IN ULONG BytesIndicated,
  144. IN ULONG BytesAvailable,
  145. IN PSMB_HEADER pSmbHeader)
  146. {
  147. NTSTATUS Status;
  148. ULONG ResponseLength;
  149. PAGED_CODE();
  150. // The SMB exchange completed without an error.
  151. RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("ParseSmbHeader BytesIndicated %ld\n",BytesIndicated));
  152. RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("ParseSmbHeader BytesIndicated %ld\n",BytesIndicated));
  153. RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("ParseSmbHeader BytesAvailable %ld\n",BytesAvailable));
  154. // The bytes indicated should be atleast cover the SMB_HEADER and the
  155. // session setup response ( fixed portion )
  156. ResponseLength = sizeof(SMB_HEADER) + FIELD_OFFSET(RESP_SESSION_SETUP_ANDX,Buffer);
  157. if (BytesIndicated > ResponseLength) {
  158. PRESP_SESSION_SETUP_ANDX pSessionSetupResponse;
  159. pSessionSetupResponse = (PRESP_SESSION_SETUP_ANDX)(pSmbHeader + 1);
  160. pKerberosExchange->ResponseLength = ResponseLength +
  161. SmbGetUshort(&pSessionSetupResponse->ByteCount);
  162. pKerberosExchange->SmbCeContext.pSessionEntry->Session.UserId = pSmbHeader->Uid;
  163. RxDbgTrace(0,Dbg,("Kerberos session setup response length %ld\n",pKerberosExchange->ResponseLength));
  164. if (BytesIndicated < pKerberosExchange->ResponseLength) {
  165. // Set up the response for copying the data.
  166. if (pKerberosExchange->ResponseLength > pKerberosExchange->BufferLength) {
  167. Status = STATUS_BUFFER_OVERFLOW;
  168. } else {
  169. Status = STATUS_MORE_PROCESSING_REQUIRED;
  170. }
  171. } else {
  172. // The regular session setup response consists of three strings corresponding
  173. // to the server's operating system type, lanman type and the domain name.
  174. // Skip past the three strings to locate the kerberos blob that has been
  175. // returned which needs to be autheticated locally.
  176. // ***** NOTE ******
  177. // Currently the server changes made by Arnold do not support the three
  178. // strings that were previously returned by the Server, viz., the operating
  179. // system name, the LANMAN version and the domain name. If the server is
  180. // changed in this regard the corresponding change neeeds to be made here.
  181. // set up the offsets in the response.
  182. pKerberosExchange->ServerResponseBlobOffset = sizeof(SMB_HEADER) +
  183. FIELD_OFFSET(RESP_SESSION_SETUP_ANDX,Buffer);
  184. pKerberosExchange->ServerResponseBlobLength = pSessionSetupResponse->ByteCount;
  185. // Copy the response onto the buffer associated with the exchange.
  186. RtlCopyMemory(pKerberosExchange->pBuffer,
  187. pSmbHeader,
  188. pKerberosExchange->ResponseLength);
  189. Status = STATUS_SUCCESS;
  190. }
  191. } else {
  192. // Abort the exchange. No further processing can be done.
  193. Status = STATUS_INVALID_NETWORK_RESPONSE;
  194. }
  195. return Status;
  196. }
  197. NTSTATUS
  198. SmbKerberosSessionSetupExchangeReceive(
  199. IN struct _SMB_EXCHANGE *pExchange, // The exchange instance
  200. IN ULONG BytesIndicated,
  201. IN ULONG BytesAvailable,
  202. OUT ULONG *pBytesTaken,
  203. IN PSMB_HEADER pSmbHeader,
  204. OUT PMDL *pDataBufferPointer,
  205. OUT PULONG pDataSize)
  206. /*++
  207. Routine Description:
  208. This is the recieve indication handling routine for net root construction exchanges
  209. Arguments:
  210. pExchange - the exchange instance
  211. BytesIndicated - the number of bytes indicated
  212. Bytes Available - the number of bytes available
  213. pBytesTaken - the number of bytes consumed
  214. pSmbHeader - the byte buffer
  215. pDataBufferPointer - the buffer into which the remaining data is to be copied.
  216. pDataSize - the buffer size.
  217. Return Value:
  218. RXSTATUS - The return status for the operation
  219. Notes:
  220. This routine is called at DPC level.
  221. --*/
  222. {
  223. NTSTATUS Status;
  224. PSMB_KERBEROS_SESSION_SETUP_EXCHANGE pKerberosExchange;
  225. ULONG SessionSetupResponseLength = 0;
  226. PAGED_CODE();
  227. pKerberosExchange = (PSMB_KERBEROS_SESSION_SETUP_EXCHANGE)pExchange;
  228. // Parse the response. Finalize the exchange instance if all the data is available
  229. Status = ParseKerberosSessionSetupResponse(
  230. pKerberosExchange,
  231. BytesIndicated,
  232. BytesAvailable,
  233. pSmbHeader);
  234. if (Status != STATUS_MORE_PROCESSING_REQUIRED) {
  235. *pBytesTaken = BytesAvailable;
  236. Status = STATUS_SUCCESS;
  237. } else {
  238. *pBytesTaken = 0;
  239. *pDataBufferPointer = pKerberosExchange->pBufferAsMdl;
  240. *pDataSize = pKerberosExchange->ResponseLength;
  241. }
  242. return Status;
  243. }
  244. NTSTATUS
  245. SmbKerberosSessionSetupExchangeSendCompletionHandler(
  246. IN PSMB_EXCHANGE pExchange, // The exchange instance
  247. IN PMDL pXmitBuffer,
  248. IN NTSTATUS SendCompletionStatus)
  249. /*++
  250. Routine Description:
  251. This is the send call back indication handling routine for net root construction exchanges
  252. Arguments:
  253. pExchange - the exchange instance
  254. Return Value:
  255. RXSTATUS - The return status for the operation
  256. --*/
  257. {
  258. PAGED_CODE();
  259. return STATUS_SUCCESS;
  260. }
  261. NTSTATUS
  262. SmbKerberosSessionSetupExchangeCopyDataHandler(
  263. IN PSMB_EXCHANGE pExchange, // The exchange instance
  264. IN PMDL pCopyDataBuffer,
  265. IN ULONG DataSize)
  266. /*++
  267. Routine Description:
  268. This is the copy data handling routine for net root construction exchanges
  269. Arguments:
  270. pExchange - the exchange instance
  271. Return Value:
  272. RXSTATUS - The return status for the operation
  273. --*/
  274. {
  275. PSMB_KERBEROS_SESSION_SETUP_EXCHANGE pKerberosExchange;
  276. PSMB_HEADER pSmbHeader;
  277. PAGED_CODE();
  278. pKerberosExchange = (PSMB_KERBEROS_SESSION_SETUP_EXCHANGE)pExchange;
  279. pSmbHeader = (PSMB_HEADER)pCopyDataBuffer;
  280. pKerberosExchange->Status = ParseKerberosSessionSetupResponse(
  281. pKerberosExchange,
  282. DataSize,
  283. DataSize,
  284. pSmbHeader);
  285. return STATUS_SUCCESS;
  286. }
  287. NTSTATUS
  288. SmbKerberosSessionSetupExchangeFinalize(
  289. PSMB_EXCHANGE pExchange,
  290. BOOLEAN *pPostFinalize)
  291. /*++
  292. Routine Description:
  293. This routine finalkzes the construct net root exchange. It resumes the RDBSS by invoking
  294. the call back and discards the exchange
  295. Arguments:
  296. pExchange - the exchange instance
  297. CurrentIrql - the current interrupt request level
  298. pPostFinalize - a pointer to a BOOLEAN if the request should be posted
  299. Return Value:
  300. RXSTATUS - The return status for the operation
  301. --*/
  302. {
  303. NTSTATUS Status;
  304. PSMB_KERBEROS_SESSION_SETUP_EXCHANGE pKerberosExchange;
  305. PSMBCE_RESUMPTION_CONTEXT pResumptionContext;
  306. PAGED_CODE();
  307. if (RxShouldPostCompletion()) {
  308. *pPostFinalize = TRUE;
  309. return RX_MAP_STATUS(SUCCESS);
  310. } else {
  311. *pPostFinalize = FALSE;
  312. }
  313. pKerberosExchange = (PSMB_KERBEROS_SESSION_SETUP_EXCHANGE)pExchange;
  314. // A copying operation on the server response BLOB is avoided by temporarily
  315. // setting up the exchange pointer to the original buffer in which the response
  316. // was received and initiating a allocation only if required.
  317. pKerberosExchange->pServerResponseBlob =
  318. ((PBYTE)pKerberosExchange->pBuffer +
  319. pKerberosExchange->ServerResponseBlobOffset);
  320. // Determine if further processing is required. If not finalize the
  321. // session entry.
  322. RxDbgTrace(0,Dbg,
  323. ("SmbKerberosSessionSetupExchangeFinalize: pKerberosExchange->Status = %lx\n",pKerberosExchange->Status));
  324. if (pKerberosExchange->Status == RX_MAP_STATUS(SUCCESS)) {
  325. Status = KerberosValidateServerResponse(pKerberosExchange);
  326. }
  327. if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
  328. pKerberosExchange->pServerResponseBlob = RxAllocatePoolWithTag(
  329. PagedPool,
  330. pKerberosExchange->ServerResponseBlobLength,
  331. MRXSMB_KERBEROS_POOLTAG);
  332. if (pKerberosExchange->pServerResponseBlob != NULL) {
  333. RtlCopyMemory(
  334. pKerberosExchange->pServerResponseBlob,
  335. ((PBYTE)pKerberosExchange->pBuffer +
  336. pKerberosExchange->ServerResponseBlobOffset),
  337. pKerberosExchange->ServerResponseBlobLength);
  338. } else {
  339. Status = STATUS_INSUFFICIENT_RESOURCES;
  340. }
  341. } else {
  342. pKerberosExchange->pServerResponseBlob = NULL;
  343. }
  344. if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
  345. Status = SmbCeInitiateExchange((PSMB_EXCHANGE)pKerberosExchange);
  346. } else {
  347. // Reset the constructor flags in the exchange.
  348. pKerberosExchange->SmbCeFlags &= ~SMBCE_EXCHANGE_SESSION_CONSTRUCTOR;
  349. if (pKerberosExchange->pServerResponseBlob != NULL) {
  350. RxFreePool(pKerberosExchange->pServerResponseBlob);
  351. }
  352. RxDbgTrace(0,Dbg,("Kerberos Exchange Session Final Status(%lx)\n",Status));
  353. // Finalize the session based upon the status
  354. if (Status == STATUS_SUCCESS) {
  355. SmbCeUpdateSessionEntryState(
  356. pKerberosExchange->SmbCeContext.pSessionEntry,
  357. SMBCEDB_ACTIVE);
  358. } else {
  359. if (Status == RX_MAP_STATUS(NO_LOGON_SERVERS)) {
  360. // If no kerberos logon servers are available downgrade to a downlevel
  361. // connection and retry.
  362. pKerberosExchange->SmbCeContext.pServerEntry->Server.Dialect = NTLANMAN_DIALECT;
  363. }
  364. SmbCeUpdateSessionEntryState(
  365. pKerberosExchange->SmbCeContext.pSessionEntry,
  366. SMBCEDB_INVALID);
  367. }
  368. // Complete the session construction.
  369. SmbCeReferenceSessionEntry(pKerberosExchange->SmbCeContext.pSessionEntry);
  370. SmbCeCompleteSessionEntryInitialization(pKerberosExchange->SmbCeContext.pSessionEntry);
  371. pKerberosExchange->SmbCeFlags &= ~SMBCE_EXCHANGE_SESSION_CONSTRUCTOR;
  372. pResumptionContext = pKerberosExchange->pResumptionContext;
  373. // Tear down the exchange instance ...
  374. SmbCeDiscardExchange(pKerberosExchange);
  375. if (pResumptionContext != NULL) {
  376. pResumptionContext->Status = Status;
  377. SmbCeResume(pResumptionContext);
  378. }
  379. }
  380. return STATUS_SUCCESS;
  381. }
  382. SMB_EXCHANGE_DISPATCH_VECTOR
  383. KerberosSessionSetupExchangeDispatch =
  384. {
  385. SmbKerberosSessionSetupExchangeStart,
  386. SmbKerberosSessionSetupExchangeReceive,
  387. SmbKerberosSessionSetupExchangeCopyDataHandler,
  388. NULL,
  389. SmbKerberosSessionSetupExchangeFinalize
  390. };
  391.