Source code of Windows XP (NT5)
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.

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