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.

2407 lines
75 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. ccmp.c
  5. Abstract:
  6. Cluster Control Message Protocol code.
  7. Author:
  8. Mike Massa (mikemas) January 24, 1997
  9. Revision History:
  10. Who When What
  11. -------- -------- ----------------------------------------------
  12. mikemas 01-24-97 created
  13. Notes:
  14. --*/
  15. #include "precomp.h"
  16. #pragma hdrstop
  17. #include "ccmp.tmh"
  18. #include <sspi.h>
  19. #ifdef ALLOC_PRAGMA
  20. #pragma alloc_text(INIT, CcmpLoad)
  21. #pragma alloc_text(PAGE, CcmpUnload)
  22. #endif // ALLOC_PRAGMA
  23. //
  24. // Local Data
  25. //
  26. PCN_RESOURCE_POOL CcmpSendRequestPool = NULL;
  27. PCN_RESOURCE_POOL CcmpMcastHBSendRequestPool = NULL;
  28. PCN_RESOURCE_POOL CcmpReceiveRequestPool = NULL;
  29. #define CCMP_SEND_REQUEST_POOL_DEPTH 5
  30. #define CCMP_RECEIVE_REQUEST_POOL_DEPTH 2
  31. typedef enum {
  32. CcmpInvalidMsgCode = 0
  33. } CCMP_MSG_CODE;
  34. //
  35. // Packet header structures must be packed.
  36. //
  37. #include <packon.h>
  38. typedef struct {
  39. ULONG SeqNumber;
  40. ULONG AckNumber;
  41. } CCMP_HEARTBEAT_MSG, *PCCMP_HEARTBEAT_MSG;
  42. typedef struct {
  43. ULONG SeqNumber;
  44. } CCMP_POISON_MSG, *PCCMP_POISON_MSG;
  45. typedef struct {
  46. ULONG Epoch;
  47. CX_CLUSTERSCREEN McastTargetNodes;
  48. } CCMP_MCAST_HEARTBEAT_HEADER, *PCCMP_MCAST_HEARTBEAT_MSG;
  49. typedef struct {
  50. UCHAR Type;
  51. UCHAR Code;
  52. union {
  53. USHORT Checksum;
  54. USHORT NodeCount; // multicast heartbeats
  55. };
  56. union {
  57. CCMP_HEARTBEAT_MSG Heartbeat;
  58. CCMP_POISON_MSG Poison;
  59. CCMP_MCAST_HEARTBEAT_HEADER McastHeartbeat;
  60. } Message;
  61. } CCMP_HEADER, *PCCMP_HEADER;
  62. #include <packoff.h>
  63. typedef struct {
  64. PCX_SEND_COMPLETE_ROUTINE CompletionRoutine;
  65. PVOID CompletionContext;
  66. PVOID MessageData;
  67. } CCMP_SEND_CONTEXT, *PCCMP_SEND_CONTEXT;
  68. typedef struct {
  69. PCNP_NETWORK Network;
  70. CL_NODE_ID SourceNodeId;
  71. ULONG TsduSize;
  72. ULONG CnpReceiveFlags;
  73. } CCMP_RECEIVE_CONTEXT, *PCCMP_RECEIVE_CONTEXT;
  74. //
  75. // Size of pre-allocated buffers for CCMP multicast heartbeats.
  76. //
  77. #define CCMP_MCAST_HEARTBEAT_PAYLOAD_PREALLOC(_NodeCount) \
  78. ((_NodeCount) * sizeof(CX_HB_NODE_INFO))
  79. #define CCMP_MCAST_HEARTBEAT_PREALLOC(_NodeCount) \
  80. (sizeof(CCMP_HEADER) \
  81. + CCMP_MCAST_HEARTBEAT_PAYLOAD_PREALLOC(_NodeCount) \
  82. )
  83. //
  84. // Security contexts.
  85. //
  86. // The heartbeat and poison packets are signed to detect tampering or
  87. // spoofing. The context is first established in user mode, then passed to
  88. // clusnet and imported into the kernel security package.
  89. //
  90. // A node maintains an inbound and outbound based context with each node in
  91. // the cluster. Hence, an array, indexed by Node Id, holds the data used to
  92. // represent a context between this node and the specified node.
  93. //
  94. // The use of multiple, simultaneous security packages is supported on NT5. As
  95. // of right now, the signature size can't be determined until the context has
  96. // been generated. It's possible for the signature buffer size for the initial
  97. // context to be smaller than the buffer size for subsequent
  98. // contexts. RichardW is going to provide the ability to determine the
  99. // signature size for a given package without having to generate a context.
  100. //
  101. // There are two scenarios where changing signature buffer size has an effect:
  102. // 1) a mixed mode (SP4/NT5), 2 node cluster is using NTLM with a signature
  103. // buffer size of 16 bytes. The SP4 node is upgraded to NT5. When the two
  104. // nodes join, they will use kerberos which has a larger signature buffer size
  105. // than NTLM but the 1st node has already allocated 16 b. signature
  106. // buffers. This could be fixed by noting the change in buffer size and
  107. // reallocating the lookaside list for the new size. This doesn't solve the
  108. // problem with more than 2 nodes: 2) with > 2 node, mixed mode clusters, it's
  109. // possible to have some nodes using NTLM and others using kerberos. If the
  110. // max signature buffer can be determined before any contexts are generated
  111. // then we'll allocated the largest buffer needed. If not, either multiple
  112. // sets of signature buffers have to be maintained or the old, smaller buffer
  113. // list is deallocated while a new, larger list is generated (in a
  114. // synchronized fashion of course).
  115. //
  116. typedef struct _CLUSNET_SECURITY_DATA {
  117. CtxtHandle Inbound;
  118. CtxtHandle Outbound;
  119. ULONG SignatureBufferSize;
  120. } CLUSNET_SECURITY_DATA, * PCLUSNET_SECURITY_DATA;
  121. //
  122. // this array of structs holds the in/outbound contexts and the signature
  123. // buffer size needed for communicating with the node indexed at this
  124. // location. The index is based on internal (zero based) numbering.
  125. //
  126. CLUSNET_SECURITY_DATA SecurityContexts[ ClusterMinNodeId + ClusterDefaultMaxNodes ];
  127. //
  128. // the size of the signature buffers in the sig buffer lookaside list
  129. //
  130. ULONG AllocatedSignatureBufferSize = 0;
  131. //
  132. // the largest size of the signature buffers imported
  133. //
  134. ULONG MaxSignatureSize = 0;
  135. CN_LOCK SecCtxtLock;
  136. #define VALID_SSPI_HANDLE( _x ) ((_x).dwUpper != (ULONG_PTR)-1 && \
  137. (_x).dwLower != (ULONG_PTR)-1 )
  138. #define INVALIDATE_SSPI_HANDLE( _x ) { \
  139. (_x).dwUpper = (ULONG_PTR)-1; \
  140. (_x).dwLower = (ULONG_PTR)-1; \
  141. }
  142. //
  143. // Lookaside list of signature data and its MDL
  144. //
  145. typedef struct _SIGNATURE_DATA {
  146. SINGLE_LIST_ENTRY Next;
  147. CN_SIGNATURE_FIELD
  148. PMDL SigMDL;
  149. UCHAR PacketSignature[0];
  150. } SIGNATURE_DATA, *PSIGNATURE_DATA;
  151. PNPAGED_LOOKASIDE_LIST SignatureLL;
  152. #define CN_SIGNATURE_TAG CN_POOL_TAG
  153. //
  154. // Routines exported within the Cluster Transport.
  155. //
  156. NTSTATUS
  157. CcmpLoad(
  158. VOID
  159. )
  160. {
  161. NTSTATUS status;
  162. ULONG i;
  163. IF_CNDBG(CN_DEBUG_INIT) {
  164. CNPRINT(("[CCMP] Loading...\n"));
  165. }
  166. CcmpSendRequestPool = CnpCreateSendRequestPool(
  167. CNP_VERSION_UNICAST,
  168. PROTOCOL_CCMP,
  169. sizeof(CCMP_HEADER),
  170. sizeof(CCMP_SEND_CONTEXT),
  171. CCMP_SEND_REQUEST_POOL_DEPTH
  172. );
  173. if (CcmpSendRequestPool == NULL) {
  174. return(STATUS_INSUFFICIENT_RESOURCES);
  175. }
  176. CcmpReceiveRequestPool = CnpCreateReceiveRequestPool(
  177. sizeof(CCMP_RECEIVE_CONTEXT),
  178. CCMP_RECEIVE_REQUEST_POOL_DEPTH
  179. );
  180. if (CcmpSendRequestPool == NULL) {
  181. return(STATUS_INSUFFICIENT_RESOURCES);
  182. }
  183. CcmpMcastHBSendRequestPool =
  184. CnpCreateSendRequestPool(
  185. CNP_VERSION_MULTICAST,
  186. PROTOCOL_CCMP,
  187. (USHORT)CCMP_MCAST_HEARTBEAT_PREALLOC(ClusterDefaultMaxNodes),
  188. (USHORT)sizeof(CCMP_SEND_CONTEXT),
  189. CCMP_SEND_REQUEST_POOL_DEPTH
  190. );
  191. if (CcmpMcastHBSendRequestPool == NULL) {
  192. IF_CNDBG( CN_DEBUG_INIT )
  193. CNPRINT(("[CCMP]: no memory for mcast heartbeat "
  194. "send request pool\n"));
  195. return(STATUS_INSUFFICIENT_RESOURCES);
  196. }
  197. //
  198. // initialize the individual client and server side security contexts
  199. //
  200. for ( i = ClusterMinNodeId; i <= ClusterDefaultMaxNodes; ++i ) {
  201. INVALIDATE_SSPI_HANDLE( SecurityContexts[ i ].Outbound );
  202. INVALIDATE_SSPI_HANDLE( SecurityContexts[ i ].Inbound );
  203. SecurityContexts[ i ].SignatureBufferSize = 0;
  204. }
  205. CnInitializeLock( &SecCtxtLock, CNP_SEC_CTXT_LOCK );
  206. SignatureLL = NULL;
  207. IF_CNDBG(CN_DEBUG_INIT) {
  208. CNPRINT(("[CCMP] Loaded.\n"));
  209. }
  210. return(STATUS_SUCCESS);
  211. } // CcmpLoad
  212. VOID
  213. CcmpUnload(
  214. VOID
  215. )
  216. {
  217. ULONG i;
  218. PAGED_CODE();
  219. IF_CNDBG(CN_DEBUG_INIT) {
  220. CNPRINT(("[CCMP] Unloading...\n"));
  221. }
  222. if (CcmpSendRequestPool != NULL) {
  223. CnpDeleteSendRequestPool(CcmpSendRequestPool);
  224. CcmpSendRequestPool = NULL;
  225. }
  226. if (CcmpMcastHBSendRequestPool != NULL) {
  227. CnpDeleteSendRequestPool(CcmpMcastHBSendRequestPool);
  228. CcmpMcastHBSendRequestPool = NULL;
  229. }
  230. if (CcmpReceiveRequestPool != NULL) {
  231. CnpDeleteReceiveRequestPool(CcmpReceiveRequestPool);
  232. CcmpReceiveRequestPool = NULL;
  233. }
  234. //
  235. // free Signature buffers and delete security contexts
  236. //
  237. if ( SignatureLL != NULL ) {
  238. ExDeleteNPagedLookasideList( SignatureLL );
  239. CnFreePool( SignatureLL );
  240. SignatureLL = NULL;
  241. AllocatedSignatureBufferSize = 0;
  242. }
  243. for ( i = ClusterMinNodeId; i <= ClusterDefaultMaxNodes; ++i ) {
  244. CxDeleteSecurityContext( i );
  245. }
  246. IF_CNDBG(CN_DEBUG_INIT) {
  247. CNPRINT(("[CCMP] Unload complete.\n"));
  248. }
  249. return;
  250. } // CcmpUnload
  251. #ifdef MM_IN_CLUSNET
  252. VOID
  253. CcmpCompleteSendMembershipMsg(
  254. IN NTSTATUS Status,
  255. IN ULONG BytesSent,
  256. IN PCNP_SEND_REQUEST SendRequest,
  257. IN PMDL DataMdl,
  258. IN PIRP Irp
  259. )
  260. {
  261. PCCMP_SEND_CONTEXT sendContext = SendRequest->UpperProtocolContext;
  262. CnAssert(DataMdl != NULL);
  263. if (NT_SUCCESS(Status)) {
  264. if (BytesSent >= sizeof(CCMP_HEADER)) {
  265. BytesSent -= sizeof(CCMP_HEADER);
  266. }
  267. else {
  268. BytesSent = 0;
  269. CnAssert(FALSE);
  270. }
  271. //
  272. // Update the Information field of the completed IRP to
  273. // reflect the actual bytes sent (adjusted for the CCMP
  274. // header).
  275. //
  276. Irp->IoStatus.Information = BytesSent;
  277. }
  278. else {
  279. CnAssert(BytesSent == 0);
  280. }
  281. //
  282. // Call the completion routine.
  283. //
  284. (*(sendContext->CompletionRoutine))(
  285. Status,
  286. BytesSent,
  287. sendContext->CompletionContext,
  288. sendContext->MessageData
  289. );
  290. //
  291. // Free the stuff we allocated.
  292. //
  293. IoFreeMdl(DataMdl);
  294. CnFreeResource((PCN_RESOURCE) SendRequest);
  295. return;
  296. } // CcmpCompleteSendMembershipMsg
  297. NTSTATUS
  298. CxSendMembershipMessage(
  299. IN CL_NODE_ID DestinationNodeId,
  300. IN PVOID MessageData,
  301. IN USHORT MessageDataLength,
  302. IN PCX_SEND_COMPLETE_ROUTINE CompletionRoutine,
  303. IN PVOID CompletionContext OPTIONAL
  304. )
  305. {
  306. NTSTATUS status;
  307. PCNP_SEND_REQUEST sendRequest;
  308. PCCMP_HEADER ccmpHeader;
  309. PMDL dataMdl;
  310. PCCMP_SEND_CONTEXT sendContext;
  311. CnAssert(MessageData != NULL);
  312. CnAssert(MessageDataLength > 0);
  313. dataMdl = IoAllocateMdl(
  314. MessageData,
  315. MessageDataLength,
  316. FALSE,
  317. FALSE,
  318. NULL
  319. );
  320. if (dataMdl != NULL) {
  321. MmBuildMdlForNonPagedPool(dataMdl);
  322. sendRequest = (PCNP_SEND_REQUEST) CnAllocateResource(
  323. CcmpSendRequestPool
  324. );
  325. if (sendRequest != NULL) {
  326. //
  327. // Fill in the CCMP header.
  328. //
  329. ccmpHeader = sendRequest->UpperProtocolHeader;
  330. RtlZeroMemory(ccmpHeader, sizeof(CCMP_HEADER));
  331. ccmpHeader->Type = CcmpMembershipMsgType;
  332. //
  333. // Fill in the caller portion of the CNP send request.
  334. //
  335. sendRequest->UpperProtocolIrp = NULL;
  336. sendRequest->CompletionRoutine = CcmpCompleteSendMembershipMsg;
  337. //
  338. // Fill in our own send context.
  339. //
  340. sendContext = sendRequest->UpperProtocolContext;
  341. sendContext->CompletionRoutine = CompletionRoutine;
  342. sendContext->CompletionContext = CompletionContext;
  343. sendContext->MessageData = MessageData;
  344. //
  345. // Send the message.
  346. //
  347. status = CnpSendPacket(
  348. sendRequest,
  349. DestinationNodeId,
  350. dataMdl,
  351. MessageDataLength,
  352. FALSE,
  353. ClusterAnyNetworkId
  354. );
  355. return(status);
  356. }
  357. IoFreeMdl(dataMdl);
  358. }
  359. status = STATUS_INSUFFICIENT_RESOURCES;
  360. return(status);
  361. } // CxSendMembershipMessage
  362. #endif // MM_IN_CLUSNET
  363. VOID
  364. CcmpCompleteSendHeartbeatMsg(
  365. IN NTSTATUS Status,
  366. IN OUT PULONG BytesSent,
  367. IN PCNP_SEND_REQUEST SendRequest,
  368. IN PMDL DataMdl
  369. )
  370. {
  371. PCCMP_HEADER ccmpHeader = SendRequest->UpperProtocolHeader;
  372. PCNP_HEADER cnpHeader = SendRequest->CnpHeader;
  373. PSIGNATURE_DATA SigData;
  374. if (NT_SUCCESS(Status)) {
  375. MEMLOG(MemLogHBPacketSendComplete,
  376. CcmpHeartbeatMsgType,
  377. ccmpHeader->Message.Heartbeat.SeqNumber);
  378. CnTrace(CCMP_SEND_DETAIL, CcmpTraceSendHBComplete,
  379. "[CCMP] Send of heartbeat to node %u completed, seqno %u.",
  380. cnpHeader->DestinationAddress, // LOGULONG
  381. ccmpHeader->Message.Heartbeat.SeqNumber // LOGULONG
  382. );
  383. //
  384. // Strip the CCMP header off of the byte count
  385. //
  386. if (*BytesSent >= sizeof(CCMP_HEADER)) {
  387. *BytesSent -= sizeof(CCMP_HEADER);
  388. }
  389. else {
  390. *BytesSent = 0;
  391. CnAssert(FALSE);
  392. }
  393. }
  394. else {
  395. MEMLOG(MemLogPacketSendFailed,
  396. cnpHeader->DestinationAddress,
  397. Status);
  398. CnTrace(CCMP_SEND_ERROR, CcmpTraceSendHBFailedBelow,
  399. "[CCMP] Transport failed to send heartbeat to node %u, "
  400. "seqno %u, status %!status!.",
  401. cnpHeader->DestinationAddress, // LOGULONG
  402. ccmpHeader->Message.Heartbeat.SeqNumber, // LOGULONG
  403. Status // LOGSTATUS
  404. );
  405. CnAssert(*BytesSent == 0);
  406. }
  407. //
  408. // Strip the sig data off of the byte count and free it
  409. //
  410. CnAssert(DataMdl != NULL);
  411. SigData = CONTAINING_RECORD(
  412. DataMdl->MappedSystemVa,
  413. SIGNATURE_DATA,
  414. PacketSignature
  415. );
  416. if (NT_SUCCESS(Status)) {
  417. if (*BytesSent >= SigData->SigMDL->ByteCount) {
  418. *BytesSent -= SigData->SigMDL->ByteCount;
  419. } else {
  420. *BytesSent = 0;
  421. CnAssert(FALSE);
  422. }
  423. }
  424. // XXX: restore the original buffer size
  425. SigData->SigMDL->ByteCount = AllocatedSignatureBufferSize;
  426. ExFreeToNPagedLookasideList( SignatureLL, SigData );
  427. //
  428. // At this point BytesSent should be zero.
  429. //
  430. CnAssert(*BytesSent == 0);
  431. //
  432. // Free the send request.
  433. //
  434. CnFreeResource((PCN_RESOURCE) SendRequest);
  435. return;
  436. } // CcmpCompleteSendHeartbeatMsg
  437. NTSTATUS
  438. CxSendHeartBeatMessage(
  439. IN CL_NODE_ID DestinationNodeId,
  440. IN ULONG SeqNumber,
  441. IN ULONG AckNumber,
  442. IN CL_NETWORK_ID NetworkId
  443. )
  444. {
  445. NTSTATUS status;
  446. PCNP_SEND_REQUEST sendRequest;
  447. PCCMP_HEADER ccmpHeader;
  448. SecBufferDesc SignatureDescriptor;
  449. SecBuffer SignatureSecBuffer[2];
  450. PSIGNATURE_DATA SigData;
  451. CN_IRQL SecContextIrql;
  452. PCLUSNET_SECURITY_DATA contextData = &SecurityContexts[ DestinationNodeId ];
  453. sendRequest = (PCNP_SEND_REQUEST) CnAllocateResource( CcmpSendRequestPool );
  454. if (sendRequest != NULL) {
  455. //
  456. // Fill in the CCMP header.
  457. //
  458. ccmpHeader = sendRequest->UpperProtocolHeader;
  459. RtlZeroMemory(ccmpHeader, sizeof(CCMP_HEADER));
  460. ccmpHeader->Type = CcmpHeartbeatMsgType;
  461. ccmpHeader->Message.Heartbeat.SeqNumber = SeqNumber;
  462. ccmpHeader->Message.Heartbeat.AckNumber = AckNumber;
  463. //
  464. // allocate a buffer and generate a signature. SignatureLL
  465. // will be NULL if security contexts have not yet been
  466. // imported.
  467. //
  468. if (SignatureLL != NULL) {
  469. SigData = ExAllocateFromNPagedLookasideList( SignatureLL );
  470. if (SigData != NULL) {
  471. //
  472. // acquire the lock on the security contexts and see if
  473. // we have a valid one with which to send this packet
  474. //
  475. CnAcquireLock( &SecCtxtLock, &SecContextIrql );
  476. if ( VALID_SSPI_HANDLE( contextData->Outbound )) {
  477. //
  478. // build a descriptor for the message and signature
  479. //
  480. SignatureDescriptor.cBuffers = 2;
  481. SignatureDescriptor.pBuffers = SignatureSecBuffer;
  482. SignatureDescriptor.ulVersion = SECBUFFER_VERSION;
  483. SignatureSecBuffer[0].BufferType = SECBUFFER_DATA;
  484. SignatureSecBuffer[0].cbBuffer = sizeof(CCMP_HEADER);
  485. SignatureSecBuffer[0].pvBuffer = (PVOID)ccmpHeader;
  486. SignatureSecBuffer[1].BufferType = SECBUFFER_TOKEN;
  487. SignatureSecBuffer[1].cbBuffer =
  488. contextData->SignatureBufferSize;
  489. SignatureSecBuffer[1].pvBuffer =
  490. SigData->PacketSignature;
  491. status = MakeSignature(&contextData->Outbound,
  492. 0,
  493. &SignatureDescriptor,
  494. 0);
  495. CnAssert( status == STATUS_SUCCESS );
  496. CnReleaseLock( &SecCtxtLock, SecContextIrql );
  497. if ( status == STATUS_SUCCESS ) {
  498. //
  499. // Fill in the caller portion of the CNP send request.
  500. //
  501. sendRequest->UpperProtocolIrp = NULL;
  502. sendRequest->CompletionRoutine =
  503. CcmpCompleteSendHeartbeatMsg;
  504. //
  505. // Send the message.
  506. //
  507. MEMLOG(
  508. MemLogHBPacketSend,
  509. CcmpHeartbeatMsgType,
  510. SeqNumber
  511. );
  512. CnTrace(CCMP_SEND_DETAIL, CcmpTraceSendHB,
  513. "[CCMP] Sending heartbeat to node %u "
  514. "on network %u, seqno %u, ackno %u.",
  515. DestinationNodeId, // LOGULONG
  516. NetworkId, // LOGULONG
  517. SeqNumber, // LOGULONG
  518. AckNumber // LOGULONG
  519. );
  520. //
  521. // XXX: adjust the MDL to reflect the true
  522. // number of bytes in the signature buffer. This
  523. // will go away when the max sig buffer size can
  524. // be determined in user mode
  525. //
  526. SigData->SigMDL->ByteCount =
  527. contextData->SignatureBufferSize;
  528. status = CnpSendPacket(
  529. sendRequest,
  530. DestinationNodeId,
  531. SigData->SigMDL,
  532. (USHORT)contextData->SignatureBufferSize,
  533. FALSE,
  534. NetworkId);
  535. //
  536. // CnpSendPacket is responsible for ensuring
  537. // that CcmpCompleteSendHeartbeatMsg is called (it
  538. // is stored in the send request data structure).
  539. //
  540. }
  541. } else {
  542. CnReleaseLock( &SecCtxtLock, SecContextIrql );
  543. ExFreeToNPagedLookasideList( SignatureLL, SigData );
  544. CnFreeResource((PCN_RESOURCE) sendRequest);
  545. status = STATUS_CLUSTER_NO_SECURITY_CONTEXT;
  546. }
  547. } else {
  548. CnFreeResource((PCN_RESOURCE) sendRequest);
  549. status = STATUS_INSUFFICIENT_RESOURCES;
  550. }
  551. } else {
  552. CnFreeResource((PCN_RESOURCE) sendRequest);
  553. status = STATUS_CLUSTER_NO_SECURITY_CONTEXT;
  554. }
  555. } else {
  556. status = STATUS_INSUFFICIENT_RESOURCES;
  557. }
  558. if (!NT_SUCCESS(status)) {
  559. CnTrace(CCMP_SEND_ERROR, CcmpTraceSendHBFailedInternal,
  560. "[CCMP] Failed to send heartbeat to node %u on net %u, "
  561. "seqno %u, status %!status!.",
  562. DestinationNodeId, // LOGULONG
  563. NetworkId, // LOGULONG
  564. SeqNumber, // LOGULONG
  565. status // LOGSTATUS
  566. );
  567. }
  568. return(status);
  569. } // CxSendHeartbeatMessage
  570. VOID
  571. CcmpCompleteSendMcastHeartbeatMsg(
  572. IN NTSTATUS Status,
  573. IN OUT PULONG BytesSent,
  574. IN PCNP_SEND_REQUEST SendRequest,
  575. IN PMDL DataMdl
  576. )
  577. {
  578. PCCMP_HEADER ccmpHeader = SendRequest->UpperProtocolHeader;
  579. PCNP_HEADER cnpHeader = SendRequest->CnpHeader;
  580. PCCMP_SEND_CONTEXT sendContext = SendRequest->UpperProtocolContext;
  581. if (NT_SUCCESS(Status)) {
  582. MEMLOG(MemLogHBPacketSendComplete,
  583. CcmpMcastHeartbeatMsgType,
  584. 0xFFFFFFFF);
  585. CnTrace(
  586. CCMP_SEND_DETAIL, CcmpTraceSendMcastHBComplete,
  587. "[CCMP] Send of multicast heartbeat "
  588. "on network id %u completed.",
  589. SendRequest->Network->Id // LOGULONG
  590. );
  591. //
  592. // Strip the CCMP header and multicast heartbeat payload
  593. // off of the byte count. The size of the message sent was
  594. // saved in the send request data structure.
  595. //
  596. if (*BytesSent >= SendRequest->UpperProtocolHeaderLength) {
  597. *BytesSent -= SendRequest->UpperProtocolHeaderLength;
  598. }
  599. else {
  600. *BytesSent = 0;
  601. CnAssert(FALSE);
  602. }
  603. }
  604. else {
  605. MEMLOG(MemLogPacketSendFailed,
  606. cnpHeader->DestinationAddress,
  607. Status);
  608. CnTrace(
  609. CCMP_SEND_ERROR, CcmpTraceSendHBFailedBelow,
  610. "[CCMP] Transport failed to send multicast "
  611. "heartbeat on network id %u, status %!status!.",
  612. SendRequest->Network->Id, // LOGULONG
  613. Status // LOGSTATUS
  614. );
  615. CnAssert(*BytesSent == 0);
  616. }
  617. //
  618. // At this point BytesSent should be zero.
  619. //
  620. CnAssert(*BytesSent == 0);
  621. //
  622. // Call the completion routine if one was specified
  623. //
  624. if (sendContext->CompletionRoutine) {
  625. (*(sendContext->CompletionRoutine))(
  626. Status,
  627. *BytesSent,
  628. sendContext->CompletionContext,
  629. NULL
  630. );
  631. }
  632. //
  633. // Free the send request.
  634. //
  635. CnFreeResource((PCN_RESOURCE) SendRequest);
  636. return;
  637. } // CcmpCompleteSendHeartbeatMsg
  638. NTSTATUS
  639. CxSendMcastHeartBeatMessage(
  640. IN CL_NETWORK_ID NetworkId,
  641. IN PVOID McastGroup,
  642. IN CX_CLUSTERSCREEN McastTargetNodes,
  643. IN ULONG McastEpoch,
  644. IN CX_HB_NODE_INFO NodeInfo[],
  645. IN PCX_SEND_COMPLETE_ROUTINE CompletionRoutine, OPTIONAL
  646. IN PVOID CompletionContext OPTIONAL
  647. )
  648. /*++
  649. Routine Description:
  650. Send a multicast heartbeat message. The mcast heartbeat is
  651. structured as follows:
  652. CCMP_HEADER
  653. CNP_MCAST_SIGNATURE (including signature buffer)
  654. CCMP_MCAST_HEARTBEAT_MESSAGE
  655. Arguments:
  656. NetworkId - network to send mcast heartbeat
  657. McastGroup - contains data for the multicast group to
  658. which the message is to be sent
  659. McastTargetNodes - screen that indicates whether the
  660. (internal) node id is a target of this multicast heartbeat.
  661. McastEpoch - cluster multicast epoch number
  662. NodeInfo - vector, of size ClusterDefaultMaxNodes+ClusterMinNodeId,
  663. of node info data structures indexed by dest node id
  664. CompletionRoutine - called in this routine if the request is
  665. not passed down to a lower level (in which case it will be
  666. called by this routine's completion routine)
  667. CompletionContext - context for CompletionRoutine
  668. Return value:
  669. NTSTATUS
  670. --*/
  671. {
  672. NTSTATUS status = STATUS_HOST_UNREACHABLE;
  673. PCNP_SEND_REQUEST sendRequest;
  674. PCCMP_HEADER ccmpHeader;
  675. PCCMP_SEND_CONTEXT sendContext;
  676. CX_HB_NODE_INFO UNALIGNED * payload;
  677. PVOID signHeaders[2];
  678. ULONG signHeaderLengths[2];
  679. ULONG sigLen;
  680. PCNP_MULTICAST_GROUP mcastGroup;
  681. BOOLEAN pushedPacket = FALSE;
  682. mcastGroup = (PCNP_MULTICAST_GROUP) McastGroup;
  683. CnAssert(mcastGroup != NULL);
  684. sendRequest = (PCNP_SEND_REQUEST) CnAllocateResource(
  685. CcmpMcastHBSendRequestPool
  686. );
  687. if (sendRequest != NULL) {
  688. //
  689. // Fill in the caller portion of the CNP send request.
  690. //
  691. sendRequest->UpperProtocolIrp = NULL;
  692. sendRequest->CompletionRoutine = CcmpCompleteSendMcastHeartbeatMsg;
  693. sendRequest->McastGroup = mcastGroup;
  694. //
  695. // Fill in our own send context.
  696. //
  697. sendContext = sendRequest->UpperProtocolContext;
  698. sendContext->CompletionRoutine = CompletionRoutine;
  699. sendContext->CompletionContext = CompletionContext;
  700. //
  701. // Fill in the CCMP header.
  702. //
  703. ccmpHeader = sendRequest->UpperProtocolHeader;
  704. RtlZeroMemory(ccmpHeader, sizeof(CCMP_HEADER));
  705. ccmpHeader->Type = CcmpMcastHeartbeatMsgType;
  706. ccmpHeader->NodeCount= (USHORT) ClusterDefaultMaxNodes;
  707. ccmpHeader->Message.McastHeartbeat.Epoch = McastEpoch;
  708. ccmpHeader->Message.McastHeartbeat.McastTargetNodes = McastTargetNodes;
  709. //
  710. // Fill in the heartbeat data.
  711. //
  712. payload = (CX_HB_NODE_INFO UNALIGNED *)(ccmpHeader + 1);
  713. RtlCopyMemory(
  714. payload,
  715. &(NodeInfo[ClusterMinNodeId]),
  716. sizeof(*NodeInfo) * ClusterDefaultMaxNodes
  717. );
  718. //
  719. // Send the message.
  720. //
  721. MEMLOG(
  722. MemLogHBPacketSend,
  723. CcmpMcastHeartbeatMsgType,
  724. 0xFFFFFFFF
  725. );
  726. CnTrace(
  727. CCMP_SEND_DETAIL, CcmpTraceSendMcastHB,
  728. "[CCMP] Sending multicast heartbeat on network %u, "
  729. "node count %u, target mask %04X",
  730. NetworkId, // LOGULONG
  731. ClusterDefaultMaxNodes, // LOGUSHORT
  732. McastTargetNodes.UlongScreen
  733. );
  734. status = CnpSendPacket(
  735. sendRequest,
  736. ClusterAnyNodeId,
  737. NULL,
  738. 0,
  739. FALSE,
  740. NetworkId
  741. );
  742. //
  743. // CnpSendPacket is responsible for ensuring
  744. // that CcmpCompleteSendMcastHeartbeatMsg is called
  745. // (it is stored in the send request data structure).
  746. //
  747. pushedPacket = TRUE;
  748. } else {
  749. status = STATUS_INSUFFICIENT_RESOURCES;
  750. }
  751. if (!NT_SUCCESS(status)) {
  752. CnTrace(CCMP_SEND_ERROR, CcmpTraceSendMcastHBFailedInternal,
  753. "[CCMP] Failed to send multicast heartbeat on net %u, "
  754. "status %!status!, pushedPacket = %!bool!.",
  755. NetworkId, // LOGULONG
  756. status, // LOGSTATUS
  757. pushedPacket
  758. );
  759. }
  760. //
  761. // If the request wasn't submitted to the next lower layer and
  762. // a completion routine was provided, call the completion
  763. // routine.
  764. //
  765. if (!pushedPacket && CompletionRoutine) {
  766. (*CompletionRoutine)(
  767. status,
  768. 0,
  769. CompletionContext,
  770. NULL
  771. );
  772. }
  773. return(status);
  774. } // CxSendMcastHeartBeatMessage
  775. VOID
  776. CcmpCompleteSendPoisonPkt(
  777. IN NTSTATUS Status,
  778. IN OUT PULONG BytesSent,
  779. IN PCNP_SEND_REQUEST SendRequest,
  780. IN PMDL DataMdl
  781. )
  782. {
  783. PCCMP_SEND_CONTEXT sendContext = SendRequest->UpperProtocolContext;
  784. PSIGNATURE_DATA SigData;
  785. PCNP_HEADER cnpHeader = (PCNP_HEADER) SendRequest->CnpHeader;
  786. MEMLOG(MemLogHBPacketSendComplete,
  787. CcmpPoisonMsgType,
  788. ( sendContext->CompletionRoutine == NULL ));
  789. IF_CNDBG( CN_DEBUG_POISON | CN_DEBUG_CCMPSEND )
  790. CNPRINT(("[CCMP] Send of poison packet to node %u completed "
  791. "with status %08x\n",
  792. cnpHeader->DestinationAddress, Status));
  793. if (NT_SUCCESS(Status)) {
  794. CnTrace(CCMP_SEND_DETAIL, CcmpTraceSendPoisonComplete,
  795. "[CCMP] Send of poison packet to node %u completed.",
  796. cnpHeader->DestinationAddress // LOGULONG
  797. );
  798. //
  799. // Strip the CCMP header off of the byte count
  800. //
  801. if (*BytesSent >= sizeof(CCMP_HEADER)) {
  802. *BytesSent -= sizeof(CCMP_HEADER);
  803. }
  804. else {
  805. *BytesSent = 0;
  806. CnAssert(FALSE);
  807. }
  808. } else {
  809. CnTrace(CCMP_SEND_ERROR, CcmpTraceSendPoisonFailedBelow,
  810. "[CCMP] Transport failed to send poison packet to node %u, "
  811. "status %!status!.",
  812. cnpHeader->DestinationAddress, // LOGULONG
  813. Status // LOGSTATUS
  814. );
  815. CnAssert(*BytesSent == 0);
  816. }
  817. //
  818. // Strip the sig data off of the byte count and free it
  819. //
  820. CnAssert(DataMdl != NULL);
  821. SigData = CONTAINING_RECORD(
  822. DataMdl->MappedSystemVa,
  823. SIGNATURE_DATA,
  824. PacketSignature
  825. );
  826. if (NT_SUCCESS(Status)) {
  827. if (*BytesSent >= SigData->SigMDL->ByteCount) {
  828. *BytesSent -= SigData->SigMDL->ByteCount;
  829. } else {
  830. *BytesSent = 0;
  831. CnAssert(FALSE);
  832. }
  833. }
  834. // XXX: restore the original buffer size
  835. SigData->SigMDL->ByteCount = AllocatedSignatureBufferSize;
  836. ExFreeToNPagedLookasideList( SignatureLL, SigData );
  837. //
  838. // At this point BytesSent should be zero.
  839. //
  840. CnAssert(*BytesSent == 0);
  841. //
  842. // Call the completion routine if one was specified
  843. //
  844. if (sendContext->CompletionRoutine) {
  845. (*(sendContext->CompletionRoutine))(
  846. Status,
  847. *BytesSent,
  848. sendContext->CompletionContext,
  849. sendContext->MessageData
  850. );
  851. }
  852. //
  853. // Free the send request.
  854. //
  855. CnFreeResource((PCN_RESOURCE) SendRequest);
  856. return;
  857. } // CcmpCompleteSendPoisonPkt
  858. VOID
  859. CxSendPoisonPacket(
  860. IN CL_NODE_ID DestinationNodeId,
  861. IN PCX_SEND_COMPLETE_ROUTINE CompletionRoutine, OPTIONAL
  862. IN PVOID CompletionContext, OPTIONAL
  863. IN PIRP Irp OPTIONAL
  864. )
  865. {
  866. NTSTATUS status;
  867. PCNP_NODE node;
  868. node = CnpFindNode(DestinationNodeId);
  869. if (node == NULL) {
  870. if (CompletionRoutine) {
  871. (*CompletionRoutine)(
  872. STATUS_CLUSTER_NODE_NOT_FOUND,
  873. 0,
  874. CompletionContext,
  875. NULL
  876. );
  877. }
  878. if (Irp) {
  879. Irp->IoStatus.Status = STATUS_CLUSTER_NODE_NOT_FOUND;
  880. Irp->IoStatus.Information = 0;
  881. IF_CNDBG( CN_DEBUG_POISON | CN_DEBUG_CCMPSEND )
  882. CNPRINT(("[CCMP] CxSendPoisonPacket completing IRP "
  883. "%p with status %08x\n",
  884. Irp, Irp->IoStatus.Status));
  885. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  886. }
  887. }
  888. else {
  889. CcmpSendPoisonPacket(
  890. node,
  891. CompletionRoutine,
  892. CompletionContext,
  893. NULL,
  894. Irp
  895. );
  896. }
  897. return;
  898. } // CxSendPoisonPacket
  899. VOID
  900. CcmpSendPoisonPacket(
  901. IN PCNP_NODE Node,
  902. IN PCX_SEND_COMPLETE_ROUTINE CompletionRoutine, OPTIONAL
  903. IN PVOID CompletionContext, OPTIONAL
  904. IN PCNP_NETWORK Network, OPTIONAL
  905. IN PIRP Irp OPTIONAL
  906. )
  907. /*++
  908. Notes:
  909. Called with the node lock held. Returns with the node lock released.
  910. If this send request is not submitted to the next lower layer,
  911. CompletionRoutine must be called (if it is not NULL).
  912. --*/
  913. {
  914. NTSTATUS status;
  915. PCNP_SEND_REQUEST sendRequest;
  916. PCCMP_HEADER ccmpHeader;
  917. PCCMP_SEND_CONTEXT sendContext;
  918. SecBufferDesc SignatureDescriptor;
  919. SecBuffer SignatureSecBuffer[2];
  920. PSIGNATURE_DATA SigData;
  921. CN_IRQL SecContextIrql;
  922. SECURITY_STATUS secStatus;
  923. PCNP_INTERFACE interface;
  924. PCLUSNET_SECURITY_DATA contextData = &SecurityContexts[Node->Id];
  925. CL_NETWORK_ID networkId;
  926. CL_NODE_ID nodeId = Node->Id;
  927. sendRequest = (PCNP_SEND_REQUEST) CnAllocateResource(CcmpSendRequestPool);
  928. if (sendRequest != NULL) {
  929. //
  930. // make sure we have an interface to send this on. We
  931. // could be shutting down and have dropped info out of
  932. // the database
  933. //
  934. if ( Network != NULL ) {
  935. PLIST_ENTRY entry;
  936. //
  937. // we really want to send this packet over the indicated
  938. // network. walk the node's interface list matching the
  939. // supplied network id to the interface's network ID and
  940. // send the packet on that interface
  941. //
  942. for (entry = Node->InterfaceList.Flink;
  943. entry != &(Node->InterfaceList);
  944. entry = entry->Flink
  945. )
  946. {
  947. interface = CONTAINING_RECORD(entry,
  948. CNP_INTERFACE,
  949. NodeLinkage);
  950. if ( interface->Network == Network ) {
  951. break;
  952. }
  953. }
  954. if ( entry == &Node->InterfaceList ) {
  955. interface = Node->CurrentInterface;
  956. }
  957. }
  958. else {
  959. interface = Node->CurrentInterface;
  960. }
  961. if ( interface != NULL ) {
  962. networkId = interface->Network->Id;
  963. //
  964. // Fill in the CCMP header.
  965. //
  966. ccmpHeader = sendRequest->UpperProtocolHeader;
  967. RtlZeroMemory(ccmpHeader, sizeof(CCMP_HEADER));
  968. ccmpHeader->Type = CcmpPoisonMsgType;
  969. ccmpHeader->Message.Poison.SeqNumber =
  970. ++(interface->SequenceToSend);
  971. CnReleaseLock( &Node->Lock, Node->Irql );
  972. //
  973. // Fill in the caller portion of the CNP send request.
  974. //
  975. sendRequest->UpperProtocolIrp = Irp;
  976. sendRequest->CompletionRoutine = CcmpCompleteSendPoisonPkt;
  977. //
  978. // Fill in our own send context.
  979. //
  980. sendContext = sendRequest->UpperProtocolContext;
  981. sendContext->CompletionRoutine = CompletionRoutine;
  982. sendContext->CompletionContext = CompletionContext;
  983. //
  984. // allocate a signature buffer and generate one. SignatureLL
  985. // will be NULL if security contexts have not yet been
  986. // imported.
  987. //
  988. if (SignatureLL != NULL) {
  989. SigData = ExAllocateFromNPagedLookasideList( SignatureLL );
  990. if (SigData != NULL) {
  991. //
  992. // acquire the lock on the security contexts and see if
  993. // we have a valid one with which to send this packet
  994. //
  995. CnAcquireLock( &SecCtxtLock, &SecContextIrql );
  996. if ( VALID_SSPI_HANDLE( contextData->Outbound )) {
  997. //
  998. // build a descriptor for the message and signature
  999. //
  1000. SignatureDescriptor.cBuffers = 2;
  1001. SignatureDescriptor.pBuffers = SignatureSecBuffer;
  1002. SignatureDescriptor.ulVersion = SECBUFFER_VERSION;
  1003. SignatureSecBuffer[0].BufferType = SECBUFFER_DATA;
  1004. SignatureSecBuffer[0].cbBuffer = sizeof(CCMP_HEADER);
  1005. SignatureSecBuffer[0].pvBuffer = (PVOID)ccmpHeader;
  1006. SignatureSecBuffer[1].BufferType = SECBUFFER_TOKEN;
  1007. SignatureSecBuffer[1].cbBuffer =
  1008. contextData->SignatureBufferSize;
  1009. SignatureSecBuffer[1].pvBuffer =
  1010. SigData->PacketSignature;
  1011. secStatus = MakeSignature(
  1012. &contextData->Outbound,
  1013. 0,
  1014. &SignatureDescriptor,
  1015. 0);
  1016. CnAssert( secStatus == STATUS_SUCCESS );
  1017. CnReleaseLock( &SecCtxtLock, SecContextIrql );
  1018. //
  1019. // no completion routine means this routine was called
  1020. // from the heartbeat dpc. We'll use that to
  1021. // distinguish between that and clussvc calling for a
  1022. // poison packet to be sent.
  1023. //
  1024. //
  1025. // WMI tracing prints the thread id,
  1026. // can figure out DPC or not on our own
  1027. //
  1028. CnTrace(CCMP_SEND_DETAIL, CcmpTraceSendPoison,
  1029. "[CCMP] Sending poison packet to node %u "
  1030. "on net %u.",
  1031. nodeId, // LOGULONG
  1032. networkId // LOGULONG
  1033. );
  1034. MEMLOG(MemLogHBPacketSend,
  1035. CcmpPoisonMsgType,
  1036. ( CompletionRoutine == NULL ));
  1037. //
  1038. // Send the message.
  1039. //
  1040. //
  1041. // XXX: adjust the MDL to reflect the true number of
  1042. // bytes in the signature buffer. This will go away
  1043. // when the max sig buffer size can be determined in
  1044. // user mode
  1045. //
  1046. SigData->SigMDL->ByteCount =
  1047. contextData->SignatureBufferSize;
  1048. CnpSendPacket(
  1049. sendRequest,
  1050. nodeId,
  1051. SigData->SigMDL,
  1052. (USHORT)contextData->SignatureBufferSize,
  1053. FALSE,
  1054. networkId
  1055. );
  1056. //
  1057. // CnpSendPacket is responsible for ensuring
  1058. // that CcmpCompleteSendPoisonPkt is called.
  1059. // CcmpCompleteSendPoisonPkt calls CompletionRoutine,
  1060. // which was a parameter to this routine.
  1061. //
  1062. return;
  1063. } else {
  1064. CnReleaseLock( &SecCtxtLock, SecContextIrql );
  1065. ExFreeToNPagedLookasideList( SignatureLL, SigData );
  1066. CnFreeResource((PCN_RESOURCE) sendRequest);
  1067. status = STATUS_CLUSTER_NO_SECURITY_CONTEXT;
  1068. }
  1069. } else {
  1070. CnFreeResource((PCN_RESOURCE) sendRequest);
  1071. status = STATUS_INSUFFICIENT_RESOURCES;
  1072. }
  1073. } else {
  1074. CnFreeResource((PCN_RESOURCE) sendRequest);
  1075. status = STATUS_CLUSTER_NO_SECURITY_CONTEXT;
  1076. }
  1077. } else {
  1078. CnReleaseLock( &Node->Lock, Node->Irql );
  1079. CnFreeResource((PCN_RESOURCE) sendRequest);
  1080. status = STATUS_CLUSTER_NETINTERFACE_NOT_FOUND;
  1081. }
  1082. } else {
  1083. CnReleaseLock( &Node->Lock, Node->Irql );
  1084. IF_CNDBG( CN_DEBUG_POISON )
  1085. CNPRINT(("[CCMP] No send resources for SendPoisonPacket\n"));
  1086. status = STATUS_INSUFFICIENT_RESOURCES;
  1087. }
  1088. CnTrace(CCMP_SEND_ERROR, CcmpTraceSendPoisonFailedInternal,
  1089. "[CCMP] Failed to send poison packet to node %u, status %!status!.",
  1090. nodeId, // LOGULONG
  1091. status // LOGSTATUS
  1092. );
  1093. //
  1094. // The request to send a poison packet did not make it to the
  1095. // next lower layer. If a completion routine was provided,
  1096. // call it now.
  1097. //
  1098. if (CompletionRoutine) {
  1099. (*CompletionRoutine)(
  1100. status,
  1101. 0,
  1102. CompletionContext,
  1103. NULL
  1104. );
  1105. }
  1106. //
  1107. // If an upper protocol IRP was provided, complete it now.
  1108. //
  1109. if (Irp) {
  1110. IF_CNDBG( CN_DEBUG_POISON | CN_DEBUG_CCMPSEND )
  1111. CNPRINT(("[CCMP] CcmpSendPoisonPacket completing IRP "
  1112. "%p with status %08x\n",
  1113. Irp, status));
  1114. Irp->IoStatus.Status = status;
  1115. Irp->IoStatus.Information = 0;
  1116. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1117. }
  1118. return;
  1119. } // CcmpSendPoisonPacket
  1120. VOID
  1121. CcmpProcessReceivePacket(
  1122. IN PCNP_NETWORK Network,
  1123. IN CL_NODE_ID SourceNodeId,
  1124. IN ULONG CnpReceiveFlags,
  1125. IN ULONG TsduSize,
  1126. IN PVOID Tsdu
  1127. )
  1128. {
  1129. CCMP_HEADER UNALIGNED * header = Tsdu;
  1130. SECURITY_STATUS SecStatus;
  1131. CX_HB_NODE_INFO UNALIGNED * nodeInfo;
  1132. CnVerifyCpuLockMask(
  1133. 0, // Required
  1134. 0xFFFFFFFF, // Forbidden
  1135. 0 // Maximum
  1136. );
  1137. CnAssert(TsduSize >= sizeof(CCMP_HEADER));
  1138. //
  1139. // adjust to point past CCMP header to message payload.
  1140. //
  1141. // For unicasts, the message payload is the Signature data.
  1142. //
  1143. // For multicasts, the signature was verified at the CNP level.
  1144. //
  1145. if (header->Type == CcmpMcastHeartbeatMsgType) {
  1146. IF_CNDBG(CN_DEBUG_CCMPRECV) {
  1147. CNPRINT(("[CCMP] Recv'd mcast packet from node %u "
  1148. "on network %u, node count %u, target "
  1149. "mask %04x, CNP flags %x.\n",
  1150. SourceNodeId,
  1151. Network->Id,
  1152. header->NodeCount,
  1153. header->Message.McastHeartbeat.McastTargetNodes.UlongScreen,
  1154. CnpReceiveFlags
  1155. ));
  1156. }
  1157. //
  1158. // Verify that the message was identified as a CNP multicast
  1159. // and that the signature was verified.
  1160. //
  1161. if ((CnpReceiveFlags &
  1162. (CNP_RECV_FLAG_MULTICAST | CNP_RECV_FLAG_SIGNATURE_VERIFIED)
  1163. ) !=
  1164. (CNP_RECV_FLAG_MULTICAST | CNP_RECV_FLAG_SIGNATURE_VERIFIED)
  1165. ) {
  1166. IF_CNDBG(CN_DEBUG_CCMPRECV) {
  1167. CNPRINT(("[CCMP] Dropping mcast packet from node %u "
  1168. "that was not identified as CNP multicast, "
  1169. "CNP flags %x.\n",
  1170. SourceNodeId, CnpReceiveFlags
  1171. ));
  1172. }
  1173. CnTrace(CCMP_RECV_ERROR, CcmpTraceReceiveNotVerified,
  1174. "[CCMP] Dropping mcast packet from node %u "
  1175. "that was not identified as CNP multicast, "
  1176. "CNP flags %x.",
  1177. SourceNodeId, CnpReceiveFlags
  1178. );
  1179. //
  1180. // Drop it.
  1181. //
  1182. goto error_exit;
  1183. }
  1184. //
  1185. // Verify that the node count reported in the header is reasonable.
  1186. // It must be compatible with our assumption that the entire
  1187. // cluster screen fits in one ULONG.
  1188. //
  1189. if (header->NodeCount >
  1190. (sizeof(header->Message.McastHeartbeat.McastTargetNodes) * BYTEL)
  1191. ) {
  1192. IF_CNDBG(CN_DEBUG_CCMPRECV) {
  1193. CNPRINT(("[CCMP] Recv'd mcast packet from node %u "
  1194. "with invalid node count %u, CNP flags %x.\n",
  1195. SourceNodeId,
  1196. header->NodeCount,
  1197. CnpReceiveFlags
  1198. ));
  1199. }
  1200. CnTrace(CCMP_RECV_ERROR, CcmpTraceReceiveNotTarget,
  1201. "[CCMP] Recv'd mcast packet from node %u "
  1202. "with invalid node count %u, CNP flags %x.",
  1203. SourceNodeId,
  1204. header->NodeCount,
  1205. CnpReceiveFlags
  1206. );
  1207. //
  1208. // Drop it.
  1209. //
  1210. goto error_exit;
  1211. }
  1212. //
  1213. // Verify that the packet contains data for this node.
  1214. //
  1215. if (!CnpClusterScreenMember(
  1216. header->Message.McastHeartbeat.McastTargetNodes.ClusterScreen,
  1217. INT_NODE(CnLocalNodeId)
  1218. )) {
  1219. IF_CNDBG(CN_DEBUG_CCMPRECV) {
  1220. CNPRINT(("[CCMP] Recv'd mcast packet from node %u "
  1221. "but node %u is not a target, CNP flags %x.\n",
  1222. SourceNodeId, CnLocalNodeId, CnpReceiveFlags
  1223. ));
  1224. }
  1225. CnTrace(CCMP_RECV_ERROR, CcmpTraceReceiveNotTarget,
  1226. "[CCMP] Recv'd mcast packet from node %u "
  1227. "but node %u is not a target, CNP flags %x.",
  1228. SourceNodeId, CnLocalNodeId, CnpReceiveFlags
  1229. );
  1230. //
  1231. // Drop it.
  1232. //
  1233. goto error_exit;
  1234. }
  1235. nodeInfo = (CX_HB_NODE_INFO UNALIGNED *)((PUCHAR)Tsdu +
  1236. sizeof(CCMP_HEADER));
  1237. SecStatus = SEC_E_OK;
  1238. } else {
  1239. SecBufferDesc PacketDataDescriptor;
  1240. SecBuffer PacketData[3];
  1241. ULONG fQOP;
  1242. CN_IRQL SecContextIrql;
  1243. PCLUSNET_SECURITY_DATA contextData = &SecurityContexts[SourceNodeId];
  1244. CnAssert(!(CnpReceiveFlags & CNP_RECV_FLAG_MULTICAST));
  1245. CnAssert(!(CnpReceiveFlags & CNP_RECV_FLAG_SIGNATURE_VERIFIED));
  1246. Tsdu = header + 1;
  1247. TsduSize -= sizeof(CCMP_HEADER);
  1248. //
  1249. // Acquire the security context lock.
  1250. //
  1251. CnAcquireLock( &SecCtxtLock, &SecContextIrql );
  1252. //
  1253. // Verify that we have a valid context data.
  1254. //
  1255. if ( !VALID_SSPI_HANDLE( contextData->Inbound )) {
  1256. CnReleaseLock( &SecCtxtLock, SecContextIrql );
  1257. IF_CNDBG(CN_DEBUG_CCMPRECV) {
  1258. CNPRINT(("[CCMP] Dropping packet - no security context "
  1259. "available for src node %u.\n",
  1260. SourceNodeId // LOGULONG
  1261. ));
  1262. }
  1263. CnTrace(CCMP_RECV_ERROR, CcmpTraceReceiveNoSecurityContext,
  1264. "[CCMP] Dropping packet - no security context available for "
  1265. "src node %u.",
  1266. SourceNodeId // LOGULONG
  1267. );
  1268. MEMLOG( MemLogNoSecurityContext, SourceNodeId, 0 );
  1269. //
  1270. // Drop it.
  1271. //
  1272. goto error_exit;
  1273. }
  1274. //
  1275. // Validate that the received signature size is expected.
  1276. //
  1277. if ( TsduSize < contextData->SignatureBufferSize ) {
  1278. IF_CNDBG(CN_DEBUG_CCMPRECV) {
  1279. CNPRINT(("[CCMP] Recv'd packet from node %u with "
  1280. "invalid signature buffer size %u.\n",
  1281. SourceNodeId,
  1282. TsduSize
  1283. ));
  1284. }
  1285. CnTrace(CCMP_RECV_ERROR, CcmpTraceReceiveBadSignatureSize,
  1286. "[CCMP] Recv'd packet from node %u with invalid signature "
  1287. "buffer size %u.",
  1288. SourceNodeId, // LOGULONG
  1289. TsduSize // LOGULONG
  1290. );
  1291. MEMLOG( MemLogSignatureSize, SourceNodeId, TsduSize );
  1292. CnReleaseLock( &SecCtxtLock, SecContextIrql );
  1293. //
  1294. // Drop it.
  1295. //
  1296. goto error_exit;
  1297. }
  1298. //
  1299. // Build the descriptors for the message and the
  1300. // signature buffer
  1301. //
  1302. PacketDataDescriptor.cBuffers = 2;
  1303. PacketDataDescriptor.pBuffers = PacketData;
  1304. PacketDataDescriptor.ulVersion = SECBUFFER_VERSION;
  1305. PacketData[0].BufferType = SECBUFFER_DATA;
  1306. PacketData[0].cbBuffer = sizeof(CCMP_HEADER);
  1307. PacketData[0].pvBuffer = (PVOID)header;
  1308. PacketData[1].BufferType = SECBUFFER_TOKEN;
  1309. PacketData[1].cbBuffer = contextData->SignatureBufferSize;
  1310. PacketData[1].pvBuffer = (PVOID)Tsdu;
  1311. //
  1312. // Verify the signature of the packet.
  1313. //
  1314. SecStatus = VerifySignature(&contextData->Inbound,
  1315. &PacketDataDescriptor,
  1316. 0, // no sequence number
  1317. &fQOP); // Quality of protection
  1318. //
  1319. // Release the security context lock.
  1320. //
  1321. CnReleaseLock( &SecCtxtLock, SecContextIrql );
  1322. }
  1323. //
  1324. // If the signature was verified, deliver the message.
  1325. //
  1326. if ( SecStatus == SEC_E_OK ) {
  1327. if (header->Type == CcmpHeartbeatMsgType) {
  1328. CnpReceiveHeartBeatMessage(Network,
  1329. SourceNodeId,
  1330. header->Message.Heartbeat.SeqNumber,
  1331. header->Message.Heartbeat.AckNumber,
  1332. FALSE,
  1333. 0);
  1334. }
  1335. else if (header->Type == CcmpMcastHeartbeatMsgType) {
  1336. CnpReceiveHeartBeatMessage(
  1337. Network,
  1338. SourceNodeId,
  1339. nodeInfo[INT_NODE(CnLocalNodeId)].SeqNumber,
  1340. nodeInfo[INT_NODE(CnLocalNodeId)].AckNumber,
  1341. ((CnpReceiveFlags & CNP_RECV_FLAG_CURRENT_MULTICAST_GROUP) ?
  1342. TRUE : FALSE),
  1343. header->Message.McastHeartbeat.Epoch
  1344. );
  1345. }
  1346. else if (header->Type == CcmpPoisonMsgType) {
  1347. CnpReceivePoisonPacket(Network,
  1348. SourceNodeId,
  1349. header->Message.Heartbeat.SeqNumber);
  1350. }
  1351. #ifdef MM_IN_CLUSNET
  1352. else if (header->Type == CcmpMembershipMsgType) {
  1353. if (TsduSize > 0) {
  1354. PVOID messageBuffer = Tsdu;
  1355. //
  1356. // Copy the data if it is unaligned.
  1357. //
  1358. if ( (((ULONG) Tsdu) & 0x3) != 0 ) {
  1359. IF_CNDBG(CN_DEBUG_CCMPRECV) {
  1360. CNPRINT(("[CCMP] Copying misaligned membership packet\n"));
  1361. }
  1362. messageBuffer = CnAllocatePool(TsduSize);
  1363. if (messageBuffer != NULL) {
  1364. RtlMoveMemory(messageBuffer, Tsdu, TsduSize);
  1365. }
  1366. }
  1367. if (messageBuffer != NULL) {
  1368. CmmReceiveMessageHandler(SourceNodeId,
  1369. messageBuffer,
  1370. TsduSize);
  1371. }
  1372. if (messageBuffer != Tsdu) {
  1373. CnFreePool(messageBuffer);
  1374. }
  1375. }
  1376. }
  1377. #endif // MM_IN_CLUSNET
  1378. else {
  1379. IF_CNDBG(CN_DEBUG_CCMPRECV) {
  1380. CNPRINT(("[CCMP] Received packet with unknown "
  1381. "type %u from node %u, CNP flags %x.\n",
  1382. header->Type,
  1383. SourceNodeId,
  1384. CnpReceiveFlags
  1385. ));
  1386. }
  1387. CnTrace(CCMP_RECV_ERROR, CcmpTraceReceiveInvalidType,
  1388. "[CCMP] Received packet with unknown type %u from "
  1389. "node %u, CNP flags %x.",
  1390. header->Type, // LOGUCHAR
  1391. SourceNodeId, // LOGULONG
  1392. CnpReceiveFlags // LOGXLONG
  1393. );
  1394. CnAssert(FALSE);
  1395. }
  1396. } else {
  1397. IF_CNDBG(CN_DEBUG_CCMPRECV) {
  1398. CNPRINT(("[CCMP] Recv'd packet type %u with bad "
  1399. "signature from node %d, security status %08x, "
  1400. "CNP flags %x.\n",
  1401. header->Type,
  1402. SourceNodeId,
  1403. SecStatus,
  1404. CnpReceiveFlags
  1405. ));
  1406. }
  1407. CnTrace(CCMP_RECV_ERROR, CcmpTraceReceiveInvalidSignature,
  1408. "[CCMP] Recv'd %!msgtype! packet with bad signature from node %d, "
  1409. "security status %08x, CNP flags %x.",
  1410. header->Type, // LOGMsgType
  1411. SourceNodeId, // LOGULONG
  1412. SecStatus, // LOGXLONG
  1413. CnpReceiveFlags // LOGXLONG
  1414. );
  1415. MEMLOG( MemLogInvalidSignature, SourceNodeId, header->Type );
  1416. }
  1417. error_exit:
  1418. CnVerifyCpuLockMask(
  1419. 0, // Required
  1420. 0xFFFFFFFF, // Forbidden
  1421. 0 // Maximum
  1422. );
  1423. return;
  1424. } // CcmpProcessReceivePacket
  1425. NTSTATUS
  1426. CcmpCompleteReceivePacket(
  1427. IN PDEVICE_OBJECT DeviceObject,
  1428. IN PIRP Irp,
  1429. IN PVOID Context
  1430. )
  1431. {
  1432. PCNP_RECEIVE_REQUEST request = Context;
  1433. PCCMP_RECEIVE_CONTEXT context = request->UpperProtocolContext;
  1434. if (Irp->IoStatus.Status == STATUS_SUCCESS) {
  1435. CnAssert(Irp->IoStatus.Information == context->TsduSize);
  1436. CcmpProcessReceivePacket(
  1437. context->Network,
  1438. context->SourceNodeId,
  1439. context->CnpReceiveFlags,
  1440. (ULONG)Irp->IoStatus.Information,
  1441. request->DataBuffer
  1442. );
  1443. }
  1444. else {
  1445. CnTrace(CCMP_RECV_ERROR, CcmpTraceCompleteReceiveFailed,
  1446. "[CDP] Failed to fetch packet data, src node %u, "
  1447. "CNP flags %x, status %!status!.",
  1448. context->SourceNodeId, // LOGULONG
  1449. context->CnpReceiveFlags, // LOGXLONG
  1450. Irp->IoStatus.Status // LOGSTATUS
  1451. );
  1452. }
  1453. CnpFreeReceiveRequest(request);
  1454. CnVerifyCpuLockMask(
  1455. 0, // Required
  1456. 0xFFFFFFFF, // Forbidden
  1457. 0 // Maximum
  1458. );
  1459. return(STATUS_MORE_PROCESSING_REQUIRED);
  1460. } // CcmpCompleteReceivePacket
  1461. NTSTATUS
  1462. CcmpReceivePacketHandler(
  1463. IN PCNP_NETWORK Network,
  1464. IN CL_NODE_ID SourceNodeId,
  1465. IN ULONG CnpReceiveFlags,
  1466. IN ULONG TdiReceiveDatagramFlags,
  1467. IN ULONG BytesIndicated,
  1468. IN ULONG BytesAvailable,
  1469. OUT PULONG BytesTaken,
  1470. IN PVOID Tsdu,
  1471. OUT PIRP * Irp
  1472. )
  1473. {
  1474. NTSTATUS status;
  1475. CCMP_HEADER UNALIGNED * header = Tsdu;
  1476. PCNP_RECEIVE_REQUEST request;
  1477. CnAssert(KeGetCurrentIrql() == DISPATCH_LEVEL);
  1478. if (BytesIndicated >= sizeof(CCMP_HEADER)) {
  1479. if (BytesIndicated == BytesAvailable) {
  1480. CcmpProcessReceivePacket(
  1481. Network,
  1482. SourceNodeId,
  1483. CnpReceiveFlags,
  1484. BytesAvailable,
  1485. Tsdu
  1486. );
  1487. *BytesTaken += BytesAvailable;
  1488. *Irp = NULL;
  1489. CnVerifyCpuLockMask(
  1490. 0, // Required
  1491. 0xFFFFFFFF, // Forbidden
  1492. 0 // Maximum
  1493. );
  1494. return(STATUS_SUCCESS);
  1495. }
  1496. //
  1497. // We need to fetch the rest of the packet before we
  1498. // can process it.
  1499. //
  1500. // This message cannot be a CNP multicast, because
  1501. // the CNP layer could not have verified an incomplete
  1502. // message.
  1503. //
  1504. CnAssert(!(CnpReceiveFlags & CNP_RECV_FLAG_MULTICAST));
  1505. CnAssert(!(CnpReceiveFlags & CNP_RECV_FLAG_SIGNATURE_VERIFIED));
  1506. CnAssert(header->Type != CcmpMcastHeartbeatMsgType);
  1507. request = CnpAllocateReceiveRequest(
  1508. CcmpReceiveRequestPool,
  1509. Network,
  1510. BytesAvailable,
  1511. CcmpCompleteReceivePacket
  1512. );
  1513. if (request != NULL) {
  1514. PCCMP_RECEIVE_CONTEXT context = request->UpperProtocolContext;
  1515. context->Network = Network;
  1516. context->SourceNodeId = SourceNodeId;
  1517. context->TsduSize = BytesAvailable;
  1518. context->CnpReceiveFlags = CnpReceiveFlags;
  1519. *Irp = request->Irp;
  1520. IF_CNDBG(CN_DEBUG_CCMPRECV) {
  1521. CNPRINT(("[CCMP] Fetching packet data, src node %u, "
  1522. "BI %u, BA %u, CNP flags %x.\n",
  1523. SourceNodeId, BytesIndicated,
  1524. BytesAvailable, CnpReceiveFlags));
  1525. }
  1526. CnTrace(CCMP_RECV_DETAIL, CcmpTraceCompleteReceive,
  1527. "[CCMP] Fetching packet data, src node %u, "
  1528. "BI %u, BA %u, CNP flags %x.",
  1529. SourceNodeId, // LOGULONG
  1530. BytesIndicated, // LOGULONG
  1531. BytesAvailable, // LOGULONG
  1532. CnpReceiveFlags // LOGXLONG
  1533. );
  1534. CnVerifyCpuLockMask(
  1535. 0, // Required
  1536. 0xFFFFFFFF, // Forbidden
  1537. 0 // Maximum
  1538. );
  1539. return(STATUS_MORE_PROCESSING_REQUIRED);
  1540. }
  1541. else {
  1542. IF_CNDBG(CN_DEBUG_CCMPRECV) {
  1543. CNPRINT(("[CCMP] Dropped incoming packet - "
  1544. "out of resources, src node %u.\n",
  1545. SourceNodeId));
  1546. }
  1547. CnTrace(CCMP_RECV_ERROR, CcmpTraceDropReceiveOOR,
  1548. "[CCMP] Dropped incoming packet - out of resources, "
  1549. "src node %u.",
  1550. SourceNodeId // LOGULONG
  1551. );
  1552. }
  1553. }
  1554. else {
  1555. IF_CNDBG(CN_DEBUG_CCMPRECV) {
  1556. CNPRINT(("[CCMP] Dropped incoming runt packet, "
  1557. "src node %u, BI %u, BA %u, CNP flags %x.\n",
  1558. SourceNodeId, BytesIndicated, BytesAvailable,
  1559. CnpReceiveFlags));
  1560. }
  1561. CnTrace(CCMP_RECV_ERROR, CcmpTraceDropReceiveRunt,
  1562. "[CCMP] Dropped incoming runt packet, src node %u, "
  1563. "BI %u, BA %u, CNP flags %x.",
  1564. SourceNodeId, // LOGULONG
  1565. BytesIndicated, // LOGULONG
  1566. BytesAvailable, // LOGULONG
  1567. CnpReceiveFlags // LOGXLONG
  1568. );
  1569. }
  1570. //
  1571. // Something went wrong. Drop the packet.
  1572. //
  1573. *BytesTaken += BytesAvailable;
  1574. CnVerifyCpuLockMask(
  1575. 0, // Required
  1576. 0xFFFFFFFF, // Forbidden
  1577. 0 // Maximum
  1578. );
  1579. return(STATUS_SUCCESS);
  1580. } // CcmpReceivePacketHandler
  1581. PVOID
  1582. SignatureAllocate(
  1583. IN POOL_TYPE PoolType,
  1584. IN SIZE_T NumberOfBytes,
  1585. IN ULONG Tag
  1586. )
  1587. {
  1588. PSIGNATURE_DATA SignatureData;
  1589. CnAssert( NumberOfBytes == ( sizeof(SIGNATURE_DATA) + AllocatedSignatureBufferSize ));
  1590. //
  1591. // allocate the space and then construct an MDL describing it
  1592. //
  1593. SignatureData = ExAllocatePoolWithTag( PoolType, NumberOfBytes, Tag );
  1594. if ( SignatureData != NULL ) {
  1595. SignatureData->SigMDL = IoAllocateMdl(SignatureData->PacketSignature,
  1596. AllocatedSignatureBufferSize,
  1597. FALSE,
  1598. FALSE,
  1599. NULL);
  1600. if ( SignatureData->SigMDL != NULL ) {
  1601. MmBuildMdlForNonPagedPool(SignatureData->SigMDL);
  1602. CN_INIT_SIGNATURE( SignatureData, CN_SIGNATURE_TAG );
  1603. } else {
  1604. ExFreePool( SignatureData );
  1605. SignatureData = NULL;
  1606. }
  1607. }
  1608. return SignatureData;
  1609. }
  1610. VOID
  1611. SignatureFree(
  1612. IN PVOID Buffer
  1613. )
  1614. {
  1615. PSIGNATURE_DATA SignatureData = (PSIGNATURE_DATA)Buffer;
  1616. CN_ASSERT_SIGNATURE( SignatureData, CN_SIGNATURE_TAG );
  1617. IoFreeMdl( SignatureData->SigMDL );
  1618. ExFreePool( SignatureData );
  1619. }
  1620. VOID
  1621. CxDeleteSecurityContext(
  1622. IN CL_NODE_ID NodeId
  1623. )
  1624. /*++
  1625. Routine Description:
  1626. Delete the security context associated with the specified node
  1627. Arguments:
  1628. NodeId - Id of the node blah blah blah
  1629. Return Value:
  1630. None
  1631. --*/
  1632. {
  1633. PCLUSNET_SECURITY_DATA contextData = &SecurityContexts[ NodeId ];
  1634. if ( VALID_SSPI_HANDLE( contextData->Inbound )) {
  1635. DeleteSecurityContext( &contextData->Inbound );
  1636. INVALIDATE_SSPI_HANDLE( contextData->Inbound );
  1637. }
  1638. if ( VALID_SSPI_HANDLE( contextData->Outbound )) {
  1639. DeleteSecurityContext( &contextData->Outbound );
  1640. INVALIDATE_SSPI_HANDLE( contextData->Outbound );
  1641. }
  1642. }
  1643. NTSTATUS
  1644. CxImportSecurityContext(
  1645. IN CL_NODE_ID NodeId,
  1646. IN PWCHAR PackageName,
  1647. IN ULONG PackageNameSize,
  1648. IN ULONG SignatureSize,
  1649. IN PVOID ServerContext,
  1650. IN PVOID ClientContext
  1651. )
  1652. /*++
  1653. Routine Description:
  1654. import a security context that was established in user mode into
  1655. the kernel SSP. We are passed pointers to the structures in user
  1656. mode, so they have be probed and used within try/except blocks.
  1657. Arguments:
  1658. NodeId - # of node with which a security context was established
  1659. PackageName - user process pointer to security package name
  1660. PackageNameSize - length, in bytes, of PackageName
  1661. SignatureSize - size, in bytes, needed for a Signature Buffer
  1662. ServerContext - user process pointer to area that contains the
  1663. SecBuffer for an inbound security context
  1664. ClientContext - same as ServerContext, but for outbound security
  1665. context
  1666. Return Value:
  1667. STATUS_SUCCESS if everything worked ok, otherwise some error in issperr.h
  1668. --*/
  1669. {
  1670. PSecBuffer InboundSecBuffer = (PSecBuffer)ServerContext;
  1671. PSecBuffer OutboundSecBuffer = (PSecBuffer)ClientContext;
  1672. PVOID CapturedInboundSecData;
  1673. ULONG CapturedInboundSecDataSize;
  1674. PVOID CapturedOutboundSecData;
  1675. ULONG CapturedOutboundSecDataSize;
  1676. CtxtHandle InboundContext;
  1677. CtxtHandle OutboundContext;
  1678. NTSTATUS Status;
  1679. PWCHAR KPackageName = NULL;
  1680. PSecBuffer KInboundSecBuffer = NULL;
  1681. PSecBuffer KOutboundSecBuffer = NULL;
  1682. PVOID KInboundData = NULL;
  1683. PVOID KOutboundData = NULL;
  1684. CN_IRQL SecContextIrql;
  1685. SECURITY_STRING PackageNameDesc;
  1686. //
  1687. // even though this routine is not marked pagable, make sure that we're
  1688. // not running at raised IRQL since DeleteSecurityContext will puke.
  1689. //
  1690. PAGED_CODE();
  1691. IF_CNDBG( CN_DEBUG_INIT )
  1692. CNPRINT(("[CCMP]: Importing security contexts from %ws\n",
  1693. PackageName));
  1694. if ( AllocatedSignatureBufferSize == 0 ) {
  1695. //
  1696. // first time in this routine, so create a lookaside list pool for
  1697. // signature buffers and their MDLs
  1698. //
  1699. CnAssert( SignatureLL == NULL );
  1700. SignatureLL = CnAllocatePool( sizeof( NPAGED_LOOKASIDE_LIST ));
  1701. if ( SignatureLL != NULL ) {
  1702. //
  1703. // with the support of multiple packages, the only way to
  1704. // determine the sig buffer size was after a context had been
  1705. // generated. Knowing the max size of all sig buffers used by the
  1706. // service before this routine is called will prevent having to
  1707. // add a bunch of synchronization code that would allocate new
  1708. // buffers and phase out the old buffer pool. on NT5, NTLM uses 16
  1709. // bytes while kerberos uses 37b. We've asked security for a call
  1710. // that will give us the max sig size for a set of packages but
  1711. // that hasn't materialized, hence we force the sig buffer size to
  1712. // something that will work for both NTLM and kerberos. But this
  1713. // discussion is kinda moot since we don't use kerberos anyway on
  1714. // NT5.
  1715. //
  1716. // AllocatedSignatureBufferSize = SignatureSize;
  1717. AllocatedSignatureBufferSize = 64;
  1718. #if 0
  1719. ExInitializeNPagedLookasideList(SignatureLL,
  1720. SignatureAllocate,
  1721. SignatureFree,
  1722. 0,
  1723. sizeof( SIGNATURE_DATA ) + SignatureSize,
  1724. CN_POOL_TAG,
  1725. 4);
  1726. #endif
  1727. ExInitializeNPagedLookasideList(SignatureLL,
  1728. SignatureAllocate,
  1729. SignatureFree,
  1730. 0,
  1731. sizeof( SIGNATURE_DATA ) + AllocatedSignatureBufferSize,
  1732. CN_POOL_TAG,
  1733. 4);
  1734. } else {
  1735. IF_CNDBG( CN_DEBUG_INIT )
  1736. CNPRINT(("[CCMP]: no memory for signature LL\n"));
  1737. Status = STATUS_INSUFFICIENT_RESOURCES;
  1738. goto error_exit;
  1739. }
  1740. } else if ( SignatureSize > AllocatedSignatureBufferSize ) {
  1741. //
  1742. // the signature buffer is growing. the problem is that the lookaside
  1743. // list is already in use by other nodes.
  1744. //
  1745. Status = STATUS_INVALID_PARAMETER;
  1746. goto error_exit;
  1747. }
  1748. //
  1749. // validate the pointers passed in as the SecBuffers
  1750. //
  1751. try {
  1752. ProbeForRead( PackageName,
  1753. PackageNameSize,
  1754. sizeof( UCHAR ) );
  1755. ProbeForRead( InboundSecBuffer,
  1756. sizeof( SecBuffer ),
  1757. sizeof( UCHAR ) );
  1758. ProbeForRead( OutboundSecBuffer,
  1759. sizeof( SecBuffer ),
  1760. sizeof( UCHAR ) );
  1761. //
  1762. // made it this far; now capture the internal pointers and their
  1763. // lengths. Probe the embedded pointers in the SecBuffers using the
  1764. // captured data
  1765. //
  1766. CapturedInboundSecData = InboundSecBuffer->pvBuffer;
  1767. CapturedInboundSecDataSize = InboundSecBuffer->cbBuffer;
  1768. CapturedOutboundSecData = OutboundSecBuffer->pvBuffer;
  1769. CapturedOutboundSecDataSize = OutboundSecBuffer->cbBuffer;
  1770. ProbeForRead( CapturedInboundSecData,
  1771. CapturedInboundSecDataSize,
  1772. sizeof( UCHAR ) );
  1773. ProbeForRead( CapturedOutboundSecData,
  1774. CapturedOutboundSecDataSize,
  1775. sizeof( UCHAR ) );
  1776. //
  1777. // make local copies of everything since security doesn't
  1778. // handle accvios very well
  1779. //
  1780. KPackageName = CnAllocatePoolWithQuota( PackageNameSize );
  1781. if ( KPackageName == NULL ) {
  1782. ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
  1783. }
  1784. RtlCopyMemory( KPackageName, PackageName, PackageNameSize );
  1785. KInboundSecBuffer = CnAllocatePoolWithQuota( sizeof( SecBuffer ));
  1786. if ( KInboundSecBuffer == NULL ) {
  1787. ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
  1788. }
  1789. *KInboundSecBuffer = *InboundSecBuffer;
  1790. KInboundSecBuffer->cbBuffer = CapturedInboundSecDataSize;
  1791. KOutboundSecBuffer = CnAllocatePoolWithQuota( sizeof( SecBuffer ));
  1792. if ( KOutboundSecBuffer == NULL ) {
  1793. ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
  1794. }
  1795. *KOutboundSecBuffer = *OutboundSecBuffer;
  1796. KOutboundSecBuffer->cbBuffer = CapturedOutboundSecDataSize;
  1797. KInboundData = CnAllocatePoolWithQuota( KInboundSecBuffer->cbBuffer );
  1798. if ( KInboundData == NULL ) {
  1799. ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
  1800. }
  1801. RtlCopyMemory( KInboundData, CapturedInboundSecData, CapturedInboundSecDataSize );
  1802. KInboundSecBuffer->pvBuffer = KInboundData;
  1803. KOutboundData = CnAllocatePoolWithQuota( KOutboundSecBuffer->cbBuffer );
  1804. if ( KOutboundData == NULL ) {
  1805. ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
  1806. }
  1807. RtlCopyMemory( KOutboundData, CapturedOutboundSecData, CapturedOutboundSecDataSize );
  1808. KOutboundSecBuffer->pvBuffer = KOutboundData;
  1809. } except(EXCEPTION_EXECUTE_HANDLER) {
  1810. //
  1811. // An exception was incurred while attempting to probe or copy
  1812. // from one of the caller's parameters. Simply return an
  1813. // appropriate error status code.
  1814. //
  1815. Status = GetExceptionCode();
  1816. IF_CNDBG( CN_DEBUG_INIT )
  1817. CNPRINT(("[CCMP]: Buffer probe failed %08X", Status ));
  1818. goto error_exit;
  1819. }
  1820. //
  1821. // import the data we were handed
  1822. //
  1823. RtlInitUnicodeString( &PackageNameDesc, KPackageName );
  1824. Status = ImportSecurityContext(&PackageNameDesc,
  1825. KInboundSecBuffer,
  1826. NULL,
  1827. &InboundContext);
  1828. if ( NT_SUCCESS( Status )) {
  1829. Status = ImportSecurityContext(&PackageNameDesc,
  1830. KOutboundSecBuffer,
  1831. NULL,
  1832. &OutboundContext);
  1833. if ( NT_SUCCESS( Status )) {
  1834. CtxtHandle oldInbound;
  1835. CtxtHandle oldOutbound;
  1836. PCLUSNET_SECURITY_DATA contextData = &SecurityContexts[ NodeId ];
  1837. INVALIDATE_SSPI_HANDLE( oldInbound );
  1838. INVALIDATE_SSPI_HANDLE( oldOutbound );
  1839. //
  1840. // DeleteSecurityContext can't be called at raised IRQL so make
  1841. // copies of the contexts to be deleted under the lock. After
  1842. // releasing the lock, we can delete the old contexts.
  1843. //
  1844. CnAcquireLock( &SecCtxtLock, &SecContextIrql );
  1845. if ( VALID_SSPI_HANDLE( contextData->Inbound )) {
  1846. oldInbound = contextData->Inbound;
  1847. }
  1848. if ( VALID_SSPI_HANDLE( contextData->Outbound )) {
  1849. oldOutbound = contextData->Outbound;
  1850. }
  1851. contextData->Inbound = InboundContext;
  1852. contextData->Outbound = OutboundContext;
  1853. contextData->SignatureBufferSize = SignatureSize;
  1854. //
  1855. // Update MaxSignatureSize -- the largest signature imported
  1856. // so far.
  1857. //
  1858. if (SignatureSize > MaxSignatureSize) {
  1859. MaxSignatureSize = SignatureSize;
  1860. }
  1861. CnReleaseLock( &SecCtxtLock, SecContextIrql );
  1862. if ( VALID_SSPI_HANDLE( oldInbound )) {
  1863. DeleteSecurityContext( &oldInbound );
  1864. }
  1865. if ( VALID_SSPI_HANDLE( oldOutbound )) {
  1866. DeleteSecurityContext( &oldOutbound );
  1867. }
  1868. } else {
  1869. IF_CNDBG( CN_DEBUG_INIT )
  1870. CNPRINT(("[CCMP]: import of outbound security context failed %08X\n", Status ));
  1871. DeleteSecurityContext( &InboundContext );
  1872. goto error_exit;
  1873. }
  1874. } else {
  1875. IF_CNDBG( CN_DEBUG_INIT )
  1876. CNPRINT(("[CCMP]: import of inbound security context failed %08X\n", Status ));
  1877. goto error_exit;
  1878. }
  1879. error_exit:
  1880. //
  1881. // Clean up allocations.
  1882. //
  1883. if ( KPackageName ) {
  1884. CnFreePool( KPackageName );
  1885. }
  1886. if ( KInboundSecBuffer ) {
  1887. CnFreePool( KInboundSecBuffer );
  1888. }
  1889. if ( KOutboundSecBuffer ) {
  1890. CnFreePool( KOutboundSecBuffer );
  1891. }
  1892. if ( KInboundData ) {
  1893. CnFreePool( KInboundData );
  1894. }
  1895. if ( KOutboundData ) {
  1896. CnFreePool( KOutboundData );
  1897. }
  1898. if (NT_SUCCESS(Status)) {
  1899. return Status;
  1900. }
  1901. //
  1902. // The following is only executed in an error situation.
  1903. //
  1904. IF_CNDBG( CN_DEBUG_INIT ) {
  1905. CNPRINT(("[CCMP]: CxImportSecurityContext returning %08X%\n", Status));
  1906. }
  1907. if (CcmpMcastHBSendRequestPool != NULL) {
  1908. CnpDeleteSendRequestPool(CcmpMcastHBSendRequestPool);
  1909. CcmpMcastHBSendRequestPool = NULL;
  1910. }
  1911. if (SignatureLL != NULL) {
  1912. ExDeleteNPagedLookasideList(SignatureLL);
  1913. CnFreePool(SignatureLL);
  1914. SignatureLL = NULL;
  1915. }
  1916. return Status;
  1917. } // CxImportSecurityContext