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.

3101 lines
94 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. message.c
  5. Abstract:
  6. Routines for the message passing interface for regroup
  7. Author:
  8. John Vert (jvert) 5/30/1996
  9. Revision History:
  10. --*/
  11. #include "service.h"
  12. #include "sspi.h"
  13. #include "issperr.h"
  14. #include "clmsg.h"
  15. #include "wrgp.h"
  16. #include "wsclus.h"
  17. //
  18. // Private Constants
  19. //
  20. #define CLMSG_DATAGRAM_PORT 1
  21. #define CLMSG_MAX_WORK_THREADS 2
  22. #define CLMSG_WORK_THREAD_PRIORITY THREAD_PRIORITY_ABOVE_NORMAL
  23. //
  24. // security package info
  25. //
  26. // For NT5, the security context generation code was rewritten to allow
  27. // multiple packages to be specified. The packages are tried in order until
  28. // there are no more packages or a context has been successfully
  29. // generated.
  30. //
  31. // The default is the negotiate package in secur32.dll which will negotiate
  32. // either kerberos or NTLM. Between NT5 systems, the actual package used
  33. // depends on the veresion of the DC: NT5 DCs support kerberos while NT4 DCs
  34. // use NTLM. Mixed mode clusters use NTLM. The NTLM portion of Negotiate
  35. // doesn't interoperate with NT4 NTLM hence the need for trying NTLM directly.
  36. //
  37. // These routines use multi-leg style authentication, i.e., a security blob is
  38. // passed between the client and server until the security routines indicate
  39. // that they have succeeded or failed. Note that encryption is not specified
  40. // for two reasons: we don't need it and it prevents the code from working on
  41. // the non-US versions where NTLM doesn't have an encryption capability.
  42. //
  43. // The DLL and package values can be overridden via the registry.
  44. //
  45. #define DEFAULT_SSPI_DLL TEXT("SECUR32.DLL")
  46. WCHAR DefaultSspiPackageList[] = L"NTLM" L"\0";
  47. //WCHAR DefaultSspiPackageList[] = L"negotiate" L"\0" L"NTLM" L"\0";
  48. #define VALID_SSPI_HANDLE( _x ) ((_x).dwUpper != (ULONG_PTR)-1 && \
  49. (_x).dwLower != (ULONG_PTR)-1 )
  50. #define INVALIDATE_SSPI_HANDLE( _x ) { \
  51. (_x).dwUpper = (ULONG_PTR)-1; \
  52. (_x).dwLower = (ULONG_PTR)-1; \
  53. }
  54. //
  55. // Private Types
  56. //
  57. //
  58. // the Data array in CLMSG_DATAGRAM_CONTEXT contains the contents of the
  59. // regroup message and the digital signature of the message. Currently, it is
  60. // not possible to get the signature buffer size until a context is
  61. // negotiated. A DCR has been submitted asking for a query that doesn't
  62. // require a context. In lieu of that, we know that for kerberos, the sig
  63. // buffer size is 35b while it is 16b for NTLM. When that feature is
  64. // available, the DatagramContext allocation should be moved into
  65. // ClMsgLoadSecurityProvider.
  66. //
  67. #define MAX_SIGNATURE_SIZE 64
  68. typedef struct {
  69. CLRTL_WORK_ITEM ClRtlWorkItem;
  70. DWORD Flags;
  71. SOCKADDR_CLUSTER SourceAddress;
  72. INT SourceAddressLength;
  73. UCHAR Data[ sizeof(rgp_msgbuf) + MAX_SIGNATURE_SIZE ];
  74. } CLMSG_DATAGRAM_CONTEXT, *PCLMSG_DATAGRAM_CONTEXT;
  75. typedef struct {
  76. CLRTL_WORK_ITEM ClRtlWorkItem;
  77. CLUSNET_EVENT EventData;
  78. } CLMSG_EVENT_CONTEXT, *PCLMSG_EVENT_CONTEXT;
  79. //
  80. // info specific to a package. Many pair-wise context associations may use the
  81. // same package. Package info is maintained in a single linked list.
  82. //
  83. typedef struct _CLUSTER_PACKAGE_INFO {
  84. struct _CLUSTER_PACKAGE_INFO * Next;
  85. LPWSTR Name;
  86. CredHandle OutboundSecurityCredentials;
  87. CredHandle InboundSecurityCredentials;
  88. ULONG SecurityTokenSize;
  89. ULONG SignatureBufferSize;
  90. } CLUSTER_PACKAGE_INFO, *PCLUSTER_PACKAGE_INFO;
  91. //
  92. // pair-wise context data
  93. //
  94. typedef struct _CLUSTER_SECURITY_DATA {
  95. CtxtHandle Outbound;
  96. CtxtHandle Inbound;
  97. PCLUSTER_PACKAGE_INFO PackageInfo;
  98. BOOL OutboundStable;
  99. BOOL InboundStable;
  100. } CLUSTER_SECURITY_DATA, *PCLUSTER_SECURITY_DATA;
  101. //
  102. // Private Data
  103. //
  104. PCLRTL_WORK_QUEUE WorkQueue = NULL;
  105. PCLMSG_DATAGRAM_CONTEXT DatagramContext = NULL;
  106. PCLMSG_EVENT_CONTEXT EventContext = NULL;
  107. SOCKET DatagramSocket = INVALID_SOCKET;
  108. HANDLE ClusnetHandle = NULL;
  109. RPC_BINDING_HANDLE * Session = NULL;
  110. BOOLEAN ClMsgInitialized = FALSE;
  111. HINSTANCE SecurityProvider;
  112. PSecurityFunctionTable SecurityFuncs;
  113. CRITICAL_SECTION SecContextLock;
  114. PCLUSTER_PACKAGE_INFO PackageInfoList;
  115. //
  116. // [GorN 08/01/99]
  117. //
  118. // Every time CreateDefaultBinding is called we increase
  119. // generation counter for the node.
  120. //
  121. // In DeleteDefaultBinding, we do a delete, only if generation
  122. // number passed matches the binding generation of that node.
  123. //
  124. // We use GenerationCritSect for synchronization.
  125. // [HACKHACK] We are not deleting GenerationCritSect.
  126. // It will get cleaned up by ExitProcess <grin>
  127. //
  128. DWORD *BindingGeneration = NULL;
  129. CRITICAL_SECTION GenerationCritSect;
  130. //
  131. // the security context array is indexed using internal node numbering (0
  132. // based) and protected by SecContextLock. For sending and recv'ing packets,
  133. // the lock is held while the signature is created/verified. Locking gets
  134. // trickier during the setup of a security context since it involves separate
  135. // inbound and outbound contexts which cause messages to be sent between
  136. // nodes. There is still a window where something bad could happen since
  137. // verifying a signature with a partially setup context is bad. The
  138. // {In,Out}boundStable vars are used to track whether the actual context
  139. // handle can be checked for validity and then, if valid, used for signature
  140. // operations.
  141. //
  142. // The joining node initially sets up an outbound context with its sponsor
  143. // (inbound for sponsor). If that is successful, the sponsor sets up an
  144. // outbound context with the joiner (inbound for joiner). This is done in such
  145. // a way that SecContextLock cannot be held at a high level; it must be
  146. // released when ever a message is sent via MmRpcEstablishSecurityContext.
  147. // The lock may be held recursively (by the same thread obviously) during
  148. // certain periods.
  149. //
  150. CLUSTER_SECURITY_DATA SecurityCtxtData[ ClusterDefaultMaxNodes ];
  151. //
  152. // Private Routines
  153. //
  154. VOID
  155. ClMsgDatagramHandler(
  156. IN PCLRTL_WORK_ITEM WorkItem,
  157. IN DWORD Status,
  158. IN DWORD BytesTransferred,
  159. IN ULONG_PTR IoContext
  160. )
  161. {
  162. WSABUF wsaBuf;
  163. int err;
  164. SecBufferDesc BufferDescriptor;
  165. SecBuffer SignatureDescriptor[2];
  166. ULONG fQOP;
  167. SECURITY_STATUS SecStatus;
  168. PCLUSTER_SECURITY_DATA SecurityData;
  169. DWORD retryCount;
  170. DWORD signatureBufferSize;
  171. PVOID signatureBuffer;
  172. rgp_msgbuf * regroupMsg;
  173. PCLMSG_DATAGRAM_CONTEXT datagramContext = CONTAINING_RECORD(
  174. WorkItem,
  175. CLMSG_DATAGRAM_CONTEXT,
  176. ClRtlWorkItem
  177. );
  178. UNREFERENCED_PARAMETER(IoContext);
  179. CL_ASSERT(WorkItem == &(datagramContext->ClRtlWorkItem));
  180. if (Status == ERROR_SUCCESS || Status == WSAEMSGSIZE ) {
  181. if (BytesTransferred == sizeof(rgp_msgbuf)) {
  182. // If clusnet verified the signature of a packet,
  183. // it sets sac_zero field of a source address to 1
  184. if (datagramContext->SourceAddress.sac_zero == 1) {
  185. ClRtlLogPrint(LOG_NOISE,
  186. "[ClMsg] recv'd mcast from %1!u!\n",
  187. datagramContext->SourceAddress.sac_node);
  188. RGP_LOCK;
  189. MMDiag((PVOID)datagramContext->Data,
  190. BytesTransferred,
  191. &BytesTransferred);
  192. RGP_UNLOCK;
  193. } else {
  194. ClRtlLogPrint(LOG_NOISE,
  195. "[ClMsg] unrecognized packet from %1!u! discarded (%2!u!)\n",
  196. datagramContext->SourceAddress.sac_node, datagramContext->SourceAddress.sac_zero);
  197. }
  198. } else {
  199. EnterCriticalSection( &SecContextLock );
  200. SecurityData = &SecurityCtxtData[ INT_NODE( datagramContext->SourceAddress.sac_node )];
  201. if ( SecurityData->InboundStable &&
  202. VALID_SSPI_HANDLE( SecurityData->Inbound))
  203. {
  204. //
  205. // get pointer to signature buffer at back of packet
  206. //
  207. regroupMsg = (rgp_msgbuf *)(datagramContext->Data);
  208. signatureBuffer = (PVOID)(regroupMsg + 1);
  209. signatureBufferSize = SecurityData->PackageInfo->SignatureBufferSize;
  210. CL_ASSERT( sizeof(rgp_msgbuf) == BytesTransferred - signatureBufferSize );
  211. //
  212. // Build the descriptors for the message and the
  213. // signature buffer
  214. //
  215. BufferDescriptor.cBuffers = 2;
  216. BufferDescriptor.pBuffers = SignatureDescriptor;
  217. BufferDescriptor.ulVersion = SECBUFFER_VERSION;
  218. SignatureDescriptor[0].BufferType = SECBUFFER_DATA;
  219. SignatureDescriptor[0].cbBuffer = BytesTransferred - signatureBufferSize;
  220. SignatureDescriptor[0].pvBuffer = (PVOID)regroupMsg;
  221. SignatureDescriptor[1].BufferType = SECBUFFER_TOKEN;
  222. SignatureDescriptor[1].cbBuffer = signatureBufferSize;
  223. SignatureDescriptor[1].pvBuffer = (PVOID)signatureBuffer;
  224. SecStatus = (*SecurityFuncs->VerifySignature)(
  225. &SecurityData->Inbound,
  226. &BufferDescriptor,
  227. 0, // no sequence number
  228. &fQOP); // Quality of protection
  229. LeaveCriticalSection( &SecContextLock );
  230. if ( SecStatus == SEC_E_OK ) {
  231. //
  232. // only feed this buffer to MM if it hasn't been tampered
  233. // with. since we're running over a datagram transport, it
  234. // will be possible to lose packets
  235. //
  236. RGP_LOCK;
  237. MMDiag((PVOID)datagramContext->Data,
  238. BytesTransferred - signatureBufferSize,
  239. &BytesTransferred);
  240. RGP_UNLOCK;
  241. } else {
  242. ClRtlLogPrint(LOG_UNUSUAL,
  243. "[ClMsg] Signature verify on message from node %1!u! failed, "
  244. "status %2!08X!\n",
  245. datagramContext->SourceAddress.sac_node,
  246. SecStatus);
  247. }
  248. } else {
  249. LeaveCriticalSection( &SecContextLock );
  250. ClRtlLogPrint(LOG_UNUSUAL,
  251. "[ClMsg] No security context to verify message from node %1!u!!\n",
  252. datagramContext->SourceAddress.sac_node);
  253. }
  254. }
  255. }
  256. else {
  257. ClRtlLogPrint(LOG_UNUSUAL,
  258. "[ClMsg] Receive datagram failed, status %1!u!\n",
  259. Status
  260. );
  261. }
  262. retryCount = 0;
  263. while ((Status != WSAENOTSOCK) && (retryCount++ < 10)) {
  264. //
  265. // Repost the request
  266. //
  267. ZeroMemory(datagramContext, sizeof(CLMSG_DATAGRAM_CONTEXT));
  268. datagramContext->ClRtlWorkItem.WorkRoutine = ClMsgDatagramHandler;
  269. datagramContext->ClRtlWorkItem.Context = datagramContext;
  270. datagramContext->SourceAddressLength = sizeof(SOCKADDR_CLUSTER);
  271. wsaBuf.len = sizeof( datagramContext->Data );
  272. wsaBuf.buf = (PCHAR)&datagramContext->Data;
  273. err = WSARecvFrom(
  274. DatagramSocket,
  275. &wsaBuf,
  276. 1,
  277. &BytesTransferred,
  278. &(datagramContext->Flags),
  279. (struct sockaddr *) &(datagramContext->SourceAddress),
  280. &(datagramContext->SourceAddressLength),
  281. &(datagramContext->ClRtlWorkItem.Overlapped),
  282. NULL
  283. );
  284. if ((err == 0) || ((Status = WSAGetLastError()) == WSA_IO_PENDING)) {
  285. return;
  286. }
  287. ClRtlLogPrint(LOG_UNUSUAL,
  288. "[ClMsg] Post of receive datagram failed, status %1!u!\n",
  289. Status
  290. );
  291. Sleep(100);
  292. }
  293. if (Status != WSAENOTSOCK) {
  294. ClRtlLogPrint(LOG_CRITICAL,
  295. "[ClMsg] Post of receive datagram failed too many times. Halting.\n"
  296. );
  297. CL_UNEXPECTED_ERROR(Status);
  298. CsInconsistencyHalt(Status);
  299. }
  300. else {
  301. //
  302. // The socket was closed. Do nothing.
  303. //
  304. ClRtlLogPrint(LOG_NOISE,
  305. "[ClMsg] Datagram socket was closed. status %1!u!\n",
  306. Status
  307. );
  308. }
  309. LocalFree(DatagramContext); DatagramContext = NULL;
  310. return;
  311. } // ClMsgDatagramHandler
  312. #if defined(DBG)
  313. int IgnoreJoinerNodeUp = MM_INVALID_NODE; // Fault Injection variable
  314. #endif
  315. VOID
  316. ClMsgEventHandler(
  317. IN PCLRTL_WORK_ITEM WorkItem,
  318. IN DWORD Status,
  319. IN DWORD BytesTransferred,
  320. IN ULONG_PTR IoContext
  321. )
  322. {
  323. PCLMSG_EVENT_CONTEXT eventContext = CONTAINING_RECORD(
  324. WorkItem,
  325. CLMSG_EVENT_CONTEXT,
  326. ClRtlWorkItem
  327. );
  328. PCLUSNET_EVENT event = &(eventContext->EventData);
  329. BOOL EpochsEqual;
  330. UNREFERENCED_PARAMETER(IoContext);
  331. CL_ASSERT(WorkItem == &(eventContext->ClRtlWorkItem));
  332. if (Status == ERROR_SUCCESS) {
  333. if (BytesTransferred == sizeof(CLUSNET_EVENT)) {
  334. //
  335. // handle the event. First make sure that the epoch in the event
  336. // matches MM's epoch. If not, ignore this event.
  337. //
  338. switch ( event->EventType ) {
  339. case ClusnetEventNodeUp:
  340. ClRtlLogPrint(LOG_NOISE,
  341. "[ClMsg] Received node up event for node %1!u!, epoch %2!u!\n",
  342. event->NodeId,
  343. event->Epoch
  344. );
  345. #if defined(DBG)
  346. if( IgnoreJoinerNodeUp == (node_t)event->NodeId ) {
  347. ClRtlLogPrint(LOG_NOISE,
  348. "[ClMsg] Fault injection. Ignoring node up for %1!u!\n",
  349. event->NodeId
  350. );
  351. break;
  352. }
  353. #endif
  354. RGP_LOCK;
  355. EpochsEqual = ( event->Epoch == rgp->OS_specific_control.EventEpoch );
  356. if ( EpochsEqual ) {
  357. rgp_monitor_node( (node_t)event->NodeId );
  358. RGP_UNLOCK;
  359. } else {
  360. RGP_UNLOCK;
  361. ClRtlLogPrint(LOG_UNUSUAL,
  362. "[ClMsg] Unequal Event Epochs. MM = %1!u! Clusnet = %2!u! !!!\n",
  363. rgp->OS_specific_control.EventEpoch,
  364. event->Epoch);
  365. }
  366. break;
  367. case ClusnetEventNodeDown:
  368. //
  369. // handle this the same as if the rgp periodic check had
  370. // detected a late IAmAlive packet
  371. //
  372. ClRtlLogPrint(LOG_NOISE,
  373. "[ClMsg] Received node down event for node %1!u!, epoch %2!u!\n",
  374. event->NodeId,
  375. event->Epoch
  376. );
  377. RGP_LOCK;
  378. EpochsEqual = ( event->Epoch == rgp->OS_specific_control.EventEpoch );
  379. if ( EpochsEqual ) {
  380. rgp_event_handler(RGP_EVT_LATEPOLLPACKET, (node_t)event->NodeId );
  381. RGP_UNLOCK;
  382. } else {
  383. RGP_UNLOCK;
  384. ClRtlLogPrint(LOG_UNUSUAL,
  385. "[ClMsg] Unequal Event Epochs. MM = %1!u! Clusnet = %2!u! !!!\n",
  386. rgp->OS_specific_control.EventEpoch,
  387. event->Epoch);
  388. }
  389. break;
  390. case ClusnetEventPoisonPacketReceived:
  391. ClRtlLogPrint(LOG_NOISE,
  392. "[ClMsg] Received poison event.\n",
  393. event->NodeId,
  394. event->Epoch
  395. );
  396. RGP_ERROR((uint16) (RGP_PARIAH + event->NodeId));
  397. break;
  398. case ClusnetEventNetInterfaceUp:
  399. case ClusnetEventNetInterfaceUnreachable:
  400. case ClusnetEventNetInterfaceFailed:
  401. ClRtlLogPrint(LOG_NOISE,
  402. "[ClMsg] Received interface %1!ws! event for node %2!u! network %3!u!\n",
  403. ( (event->EventType == ClusnetEventNetInterfaceUp) ?
  404. L"up" :
  405. ( ( event->EventType ==
  406. ClusnetEventNetInterfaceUnreachable
  407. ) ?
  408. L"unreachable" :
  409. L"failed"
  410. )
  411. ),
  412. event->NodeId,
  413. event->NetworkId
  414. );
  415. NmPostPnpEvent(
  416. event->EventType,
  417. event->NodeId,
  418. event->NetworkId
  419. );
  420. break;
  421. case ClusnetEventAddAddress:
  422. case ClusnetEventDelAddress:
  423. ClRtlLogPrint(LOG_NOISE,
  424. "[ClMsg] Received %1!ws! address event, address %2!x!\n",
  425. ((event->EventType == ClusnetEventAddAddress) ?
  426. L"add" : L"delete"),
  427. event->NetworkId
  428. );
  429. NmPostPnpEvent(
  430. event->EventType,
  431. event->NetworkId,
  432. 0
  433. );
  434. break;
  435. case ClusnetEventMulticastSet:
  436. ClRtlLogPrint(LOG_NOISE,
  437. "[ClMsg] Received new multicast reachable node "
  438. "set event: %1!x!.\n",
  439. event->NodeId
  440. );
  441. SetMulticastReachable(event->NodeId);
  442. break;
  443. default:
  444. ClRtlLogPrint(LOG_NOISE,
  445. "[ClMsg] Received unhandled event type %1!u! node %2!u! network %3!u!\n",
  446. event->EventType,
  447. event->NodeId,
  448. event->NetworkId
  449. );
  450. break;
  451. }
  452. }
  453. else {
  454. ClRtlLogPrint(LOG_UNUSUAL,
  455. "[ClMsg] Received event buffer of size %1!u! !!!\n",
  456. BytesTransferred
  457. );
  458. CL_ASSERT(BytesTransferred == sizeof(CLUSNET_EVENT));
  459. }
  460. //
  461. // Repost the request
  462. //
  463. ClRtlInitializeWorkItem(
  464. &(eventContext->ClRtlWorkItem),
  465. ClMsgEventHandler,
  466. eventContext
  467. );
  468. Status = ClusnetGetNextEvent(
  469. ClusnetHandle,
  470. &(eventContext->EventData),
  471. &(eventContext->ClRtlWorkItem.Overlapped)
  472. );
  473. if ((Status == ERROR_IO_PENDING) || (Status == ERROR_SUCCESS)) {
  474. return;
  475. }
  476. }
  477. //
  478. // Some kind of error occurred
  479. //
  480. if (Status != ERROR_OPERATION_ABORTED) {
  481. ClRtlLogPrint(LOG_UNUSUAL,
  482. "[ClMsg] GetNextEvent failed, status %1!u!\n",
  483. Status
  484. );
  485. CL_UNEXPECTED_ERROR(Status);
  486. }
  487. else {
  488. //
  489. // The control channel was closed. Do nothing.
  490. //
  491. ClRtlLogPrint(LOG_NOISE, "[ClMsg] Control Channel was closed.\n");
  492. }
  493. LocalFree(EventContext); EventContext = NULL;
  494. return;
  495. } // ClMsgEventHandler
  496. DWORD
  497. ClMsgInitializeSecurityPackage(
  498. LPCWSTR PackageName
  499. )
  500. /*++
  501. Routine Description:
  502. Find the specified security package and acquire inboud/outbound credential
  503. handles to it
  504. Arguments:
  505. PackageName - package to find in security DLL
  506. Return Value:
  507. ERROR_SUCCESS if everything worked ok...
  508. --*/
  509. {
  510. DWORD status;
  511. ULONG i;
  512. PWSTR securityPackageName;
  513. DWORD numPackages;
  514. PSecPkgInfo secPackageInfoBase = NULL;
  515. PSecPkgInfo secPackageInfo;
  516. TimeStamp expiration;
  517. PCLUSTER_PACKAGE_INFO clusterPackageInfo;
  518. //
  519. // enumerate the packages provided by this provider and look through the
  520. // results to find one that matches the specified package name.
  521. //
  522. status = (*SecurityFuncs->EnumerateSecurityPackages)(&numPackages,
  523. &secPackageInfoBase);
  524. if ( status != SEC_E_OK ) {
  525. ClRtlLogPrint(LOG_CRITICAL,
  526. "[ClMsg] Can't enum security packages 0x%1!08X!\n",
  527. status
  528. );
  529. goto error_exit;
  530. }
  531. secPackageInfo = secPackageInfoBase;
  532. for ( i = 0; i < numPackages; ++i ) {
  533. if ( _wcsicmp( PackageName, secPackageInfo->Name ) == 0) {
  534. break;
  535. }
  536. ++secPackageInfo;
  537. }
  538. if ( i == numPackages ) {
  539. status = (DWORD)SEC_E_SECPKG_NOT_FOUND; // [THINKTHINK] not a good choice
  540. ClRtlLogPrint(LOG_CRITICAL,
  541. "[ClMsg] Couldn't find %1!ws! security package\n",
  542. PackageName);
  543. goto error_exit;
  544. }
  545. //
  546. // allocate a blob to hold our package info and stuff it on the the list
  547. //
  548. clusterPackageInfo = LocalAlloc( LMEM_FIXED, sizeof(CLUSTER_PACKAGE_INFO));
  549. if ( clusterPackageInfo == NULL ) {
  550. status = GetLastError();
  551. ClRtlLogPrint(LOG_CRITICAL,
  552. "[ClMsg] Couldn't allocate memory for package info (%1!u!)\n",
  553. status);
  554. goto error_exit;
  555. }
  556. clusterPackageInfo->Name = LocalAlloc(LMEM_FIXED,
  557. (wcslen(secPackageInfo->Name)+1) * sizeof(WCHAR));
  558. if ( clusterPackageInfo->Name == NULL ) {
  559. status = GetLastError();
  560. ClRtlLogPrint(LOG_CRITICAL,
  561. "[ClMsg] Couldn't allocate memory for package info name (%1!u!)\n",
  562. status);
  563. goto error_exit;
  564. }
  565. wcscpy( clusterPackageInfo->Name, secPackageInfo->Name );
  566. if ( PackageInfoList == NULL ) {
  567. PackageInfoList = clusterPackageInfo;
  568. } else {
  569. PCLUSTER_PACKAGE_INFO nextPackage;
  570. nextPackage = PackageInfoList;
  571. while ( nextPackage->Next != NULL ) {
  572. nextPackage = nextPackage->Next;
  573. }
  574. nextPackage->Next = clusterPackageInfo;
  575. }
  576. clusterPackageInfo->Next = NULL;
  577. clusterPackageInfo->SecurityTokenSize = secPackageInfo->cbMaxToken;
  578. //
  579. // finally get a set of credential handles. Note that there is a bug in
  580. // the security packages that prevent using an in/outbound
  581. // credential. When/if that gets fixed, this code could be greatly
  582. // simplified.
  583. //
  584. status = (*SecurityFuncs->AcquireCredentialsHandle)(
  585. NULL,
  586. secPackageInfo->Name,
  587. SECPKG_CRED_OUTBOUND,
  588. NULL,
  589. NULL,
  590. NULL,
  591. NULL,
  592. &clusterPackageInfo->OutboundSecurityCredentials,
  593. &expiration);
  594. if ( status != SEC_E_OK ) {
  595. ClRtlLogPrint(LOG_CRITICAL,
  596. "[ClMsg] Can't obtain outbound credentials %1!08X!\n",
  597. status
  598. );
  599. goto error_exit;
  600. }
  601. status = (*SecurityFuncs->AcquireCredentialsHandle)(
  602. NULL,
  603. secPackageInfo->Name,
  604. SECPKG_CRED_INBOUND,
  605. NULL,
  606. NULL,
  607. NULL,
  608. NULL,
  609. &clusterPackageInfo->InboundSecurityCredentials,
  610. &expiration);
  611. if ( status != SEC_E_OK ) {
  612. ClRtlLogPrint(LOG_CRITICAL,
  613. "[ClMsg] Can't obtain inbound credentials %1!08X!\n",
  614. status
  615. );
  616. }
  617. error_exit:
  618. if ( secPackageInfoBase != NULL ) {
  619. (*SecurityFuncs->FreeContextBuffer)( secPackageInfoBase );
  620. }
  621. return status;
  622. } // ClMsgInitializeSecurityPackage
  623. DWORD
  624. ClMsgLoadSecurityProvider(
  625. VOID
  626. )
  627. /*++
  628. Routine Description:
  629. Load the security DLL and construct a list of packages to use for context
  630. establishment.
  631. This allows use of a set of registry keys to override the current security
  632. DLL/packages. This is not meant as a general mechanism since switching the
  633. security provider in a synchronized fashion through out all the nodes in
  634. the cluster has numerous issues. This is meant as a bailout for a customer
  635. that is stuck because of some random problem with security or has their
  636. own security package (the fools!)
  637. Arguments:
  638. None
  639. Return Value:
  640. ERROR_SUCCESS if everything worked ok...
  641. --*/
  642. {
  643. DWORD status;
  644. WCHAR securityProviderDLLName[ MAX_PATH ];
  645. DWORD securityDLLNameSize = sizeof( securityProviderDLLName );
  646. DWORD packageListSize = 0;
  647. INIT_SECURITY_INTERFACE initSecurityInterface;
  648. BOOL dllNameSpecified = TRUE;
  649. LPWSTR securityPackages = NULL;
  650. LPWSTR packageName;
  651. ULONG packagesLoaded = 0;
  652. ULONG i;
  653. HKEY hClusSvcKey = NULL;
  654. DWORD regType;
  655. //
  656. // see if a specific security DLL is named in the registry. if not, fail
  657. // back to the default.
  658. //
  659. status = RegOpenKeyW(HKEY_LOCAL_MACHINE,
  660. CLUSREG_KEYNAME_CLUSSVC_PARAMETERS,
  661. &hClusSvcKey);
  662. if ( status == ERROR_SUCCESS ) {
  663. status = RegQueryValueExW(hClusSvcKey,
  664. CLUSREG_NAME_SECURITY_DLL_NAME,
  665. 0,
  666. &regType,
  667. (LPBYTE)&securityProviderDLLName,
  668. &securityDLLNameSize);
  669. if (status != ERROR_SUCCESS ||
  670. securityDLLNameSize == sizeof( UNICODE_NULL ) ||
  671. regType != REG_SZ)
  672. {
  673. if ( status == ERROR_SUCCESS ) {
  674. if ( regType != REG_SZ ) {
  675. ClRtlLogPrint(LOG_UNUSUAL,
  676. "[ClMsg] The security DLL key must be of type REG_SZ. Using "
  677. "%1!ws! as provider.\n",
  678. DEFAULT_SSPI_DLL);
  679. } else if ( securityDLLNameSize == sizeof( UNICODE_NULL )) {
  680. ClRtlLogPrint(LOG_UNUSUAL,
  681. "[ClMsg] No value specified for security DLL key. Using "
  682. "%1!ws! as provider.\n",
  683. DEFAULT_SSPI_DLL);
  684. }
  685. } else if ( status != ERROR_FILE_NOT_FOUND ) {
  686. ClRtlLogPrint(LOG_UNUSUAL,
  687. "[ClMsg] Can't read security DLL key, status %1!u!. Using "
  688. "%2!ws! as provider\n",
  689. status,
  690. DEFAULT_SSPI_DLL);
  691. }
  692. wcscpy( securityProviderDLLName, DEFAULT_SSPI_DLL );
  693. dllNameSpecified = FALSE;
  694. } else {
  695. ClRtlLogPrint(LOG_NOISE,
  696. "[ClMsg] Using %1!ws! as the security provider DLL\n",
  697. securityProviderDLLName);
  698. }
  699. } else {
  700. wcscpy( securityProviderDLLName, DEFAULT_SSPI_DLL );
  701. dllNameSpecified = FALSE;
  702. }
  703. SecurityProvider = LoadLibrary( securityProviderDLLName );
  704. if ( SecurityProvider == NULL ) {
  705. status = GetLastError();
  706. ClRtlLogPrint(LOG_CRITICAL,
  707. "[ClMsg] Unable to load security provider %1!ws!, status %2!u!\n",
  708. securityProviderDLLName,
  709. status);
  710. goto error_exit;
  711. }
  712. //
  713. // get a pointer to the initialize function in the DLL
  714. //
  715. initSecurityInterface =
  716. (INIT_SECURITY_INTERFACE)GetProcAddress(SecurityProvider,
  717. SECURITY_ENTRYPOINT_ANSI);
  718. if ( initSecurityInterface == NULL ) {
  719. status = GetLastError();
  720. ClRtlLogPrint(LOG_CRITICAL,
  721. "[ClMsg] Unable to get security init function, status %1!u!\n",
  722. status);
  723. goto error_exit;
  724. }
  725. //
  726. // now get a pointer to all the security funcs
  727. //
  728. SecurityFuncs = (*initSecurityInterface)();
  729. if ( SecurityFuncs == NULL ) {
  730. status = ERROR_INVALID_FUNCTION;
  731. ClRtlLogPrint(LOG_CRITICAL,
  732. "[ClMsg] Unable to get security function table\n");
  733. goto error_exit;
  734. }
  735. if ( dllNameSpecified ) {
  736. //
  737. // If a DLL name was specified in the registry, then the package name
  738. // key must be specified as well. Get its size first.
  739. //
  740. status = RegQueryValueExW(hClusSvcKey,
  741. CLUSREG_NAME_SECURITY_PACKAGE_LIST,
  742. 0,
  743. &regType,
  744. NULL,
  745. &packageListSize);
  746. if (status != ERROR_SUCCESS ||
  747. packageListSize == sizeof( UNICODE_NULL ) ||
  748. regType != REG_MULTI_SZ)
  749. {
  750. if ( status == ERROR_SUCCESS ) {
  751. if ( regType != REG_MULTI_SZ ) {
  752. ClRtlLogPrint(LOG_CRITICAL,
  753. "[ClMsg] The security package key must of type REG_MULTI_SZ.\n");
  754. } else if ( packageListSize == sizeof( UNICODE_NULL )) {
  755. ClRtlLogPrint(LOG_CRITICAL,
  756. "[ClMsg] No package names were specified for %1!ws!.\n",
  757. securityProviderDLLName);
  758. }
  759. status = ERROR_INVALID_PARAMETER;
  760. } else {
  761. ClRtlLogPrint(LOG_CRITICAL,
  762. "[ClMsg] Can't read security package key (%1!u!).\n",
  763. status);
  764. }
  765. goto error_exit;
  766. }
  767. securityPackages = LocalAlloc( LMEM_FIXED, packageListSize );
  768. if ( securityPackages == NULL ) {
  769. ClRtlLogPrint(LOG_CRITICAL,
  770. "[ClMsg] Can't allocate memory for package list.\n");
  771. status = GetLastError();
  772. goto error_exit;
  773. }
  774. status = RegQueryValueExW(hClusSvcKey,
  775. CLUSREG_NAME_SECURITY_PACKAGE_LIST,
  776. 0,
  777. &regType,
  778. (PUCHAR)securityPackages,
  779. &packageListSize);
  780. CL_ASSERT( status == ERROR_SUCCESS );
  781. } else {
  782. securityPackages = LocalAlloc(LMEM_FIXED,
  783. sizeof( DefaultSspiPackageList ));
  784. if ( securityPackages == NULL ) {
  785. ClRtlLogPrint(LOG_CRITICAL,
  786. "[ClMsg] Can't allocate memory for default package list.\n");
  787. status = GetLastError();
  788. goto error_exit;
  789. }
  790. memcpy(securityPackages,
  791. DefaultSspiPackageList,
  792. sizeof( DefaultSspiPackageList ));
  793. }
  794. //
  795. // initialize each package in the list
  796. //
  797. packageName = securityPackages;
  798. while ( *packageName != UNICODE_NULL ) {
  799. status = ClMsgInitializeSecurityPackage( packageName );
  800. if ( status == ERROR_SUCCESS ) {
  801. ++packagesLoaded;
  802. ClRtlLogPrint(LOG_NOISE,
  803. "[ClMsg] Initialized %1!ws! package.\n",
  804. packageName);
  805. } else {
  806. ClRtlLogPrint(LOG_UNUSUAL,
  807. "[ClMsg] %1!ws! package failed to initialize, status %2!08X!.\n",
  808. packageName,
  809. status);
  810. }
  811. packageName = packageName + wcslen( packageName ) + 1;;
  812. }
  813. if ( packagesLoaded == 0 ) {
  814. ClRtlLogPrint(LOG_CRITICAL, "[ClMsg] No security packages could be initialized.\n");
  815. status = ERROR_NO_SUCH_PACKAGE;
  816. goto error_exit;
  817. }
  818. //
  819. // initialize the individual client and server side security contexts.
  820. // a context handle is stable when it is marked as invalid.
  821. //
  822. for ( i = ClusterMinNodeId; i <= NmMaxNodeId; ++i ) {
  823. PCLUSTER_SECURITY_DATA SecurityData = &SecurityCtxtData[ INT_NODE( i )];
  824. SecurityData->InboundStable = TRUE;
  825. SecurityData->OutboundStable = TRUE;
  826. SecurityData->PackageInfo = NULL;
  827. INVALIDATE_SSPI_HANDLE( SecurityData->Outbound );
  828. INVALIDATE_SSPI_HANDLE( SecurityData->Inbound );
  829. }
  830. error_exit:
  831. if ( hClusSvcKey != NULL ) {
  832. RegCloseKey(hClusSvcKey);
  833. }
  834. if ( securityPackages != NULL ) {
  835. LocalFree( securityPackages );
  836. }
  837. return status;
  838. } // ClMsgLoadSecurityProvider
  839. DWORD
  840. ClMsgImportSecurityContexts(
  841. CL_NODE_ID NodeId,
  842. LPWSTR SecurityPackageName,
  843. DWORD SignatureBufferSize
  844. )
  845. /*++
  846. Routine Description:
  847. Export the inbound/outbound security contexts for the specified node and
  848. ship them to clusnet for use in signing heartbeat and poison pkts
  849. Arguments:
  850. NodeId - Id of the node whose contexts are being exported
  851. SecurityPackageName - name of package used with which to establish context
  852. SignatureBufferSize - number of bytes needed for the signature buffer
  853. Return Value:
  854. ERROR_SUCCESS if everything worked ok...
  855. --*/
  856. {
  857. DWORD Status = ERROR_SUCCESS;
  858. SecBuffer ServerContext;
  859. SecBuffer ClientContext;
  860. CL_NODE_ID InternalNodeId = INT_NODE( NodeId );
  861. ClRtlLogPrint(LOG_NOISE, "[ClMsg] Importing security contexts from %1!ws! package.\n",
  862. SecurityPackageName);
  863. Status = (*SecurityFuncs->ExportSecurityContext)(
  864. &SecurityCtxtData[ InternalNodeId ].Inbound,
  865. 0,
  866. &ServerContext,
  867. 0);
  868. if ( !NT_SUCCESS( Status )) {
  869. return Status;
  870. }
  871. Status = (*SecurityFuncs->ExportSecurityContext)(
  872. &SecurityCtxtData[ InternalNodeId ].Outbound,
  873. 0,
  874. &ClientContext,
  875. 0);
  876. if ( NT_SUCCESS( Status )) {
  877. CL_ASSERT( SignatureBufferSize > 0 );
  878. Status = ClusnetImportSecurityContexts(NmClusnetHandle,
  879. NodeId,
  880. SecurityPackageName,
  881. SignatureBufferSize,
  882. &ServerContext,
  883. &ClientContext);
  884. (*SecurityFuncs->FreeContextBuffer)( ClientContext.pvBuffer );
  885. }
  886. (*SecurityFuncs->FreeContextBuffer)( ServerContext.pvBuffer );
  887. return Status;
  888. } // ClMsgImportSecurityContexts
  889. DWORD
  890. ClMsgEstablishSecurityContext(
  891. IN DWORD JoinSequence,
  892. IN DWORD TargetNodeId,
  893. IN SECURITY_ROLE RoleOfClient,
  894. IN PCLUSTER_PACKAGE_INFO PackageInfo
  895. )
  896. /*++
  897. Routine Description:
  898. try to establish an outbound security context with the other node using
  899. the specified package name. The initialized security blob is shipped to
  900. the other side via RPC. This process continues back and forth until the
  901. security APIs indicate that the context has been successfully generated or
  902. has failed.
  903. Arguments:
  904. JoinSequence - Sequence number of the join. Used by the other node to
  905. determine if this blob is the generation of a new context
  906. TargetNodeId - Id of the node with which to generate the context
  907. RoleOfClient - indicates whether the client establishing the security
  908. context is acting as a cluster member or a joining
  909. member. Determines when the client/server roles of
  910. establishing a security context are reversed
  911. PackageInfo - pointer to security package info to be used
  912. Return Value:
  913. ERROR_SUCCESS if everything worked ok...
  914. --*/
  915. {
  916. CtxtHandle ClientContext;
  917. TimeStamp Expiration;
  918. SecBufferDesc ServerBufferDescriptor;
  919. SecBuffer ServerSecurityToken;
  920. SecBufferDesc ClientBufferDescriptor;
  921. SecBuffer ClientSecurityToken;
  922. ULONG ContextRequirements;
  923. ULONG ContextAttributes;
  924. SECURITY_STATUS OurStatus;
  925. SECURITY_STATUS ServerStatus = SEC_I_CONTINUE_NEEDED;
  926. ULONG passCount = 1;
  927. error_status_t RPCStatus;
  928. DWORD Status = ERROR_SUCCESS;
  929. DWORD FacilityCode;
  930. PCLUSTER_SECURITY_DATA TargetSecurityData;
  931. ClRtlLogPrint(LOG_NOISE,"[ClMsg] Establishing outbound security context with the "
  932. "%1!ws! package.\n",
  933. PackageInfo->Name);
  934. //
  935. // obtain a security context with the target node by swapping token
  936. // buffers until the process is complete.
  937. //
  938. // Build the Client (caller of this function) and Server (target node)
  939. // buffer descriptors.
  940. //
  941. ServerBufferDescriptor.cBuffers = 1;
  942. ServerBufferDescriptor.pBuffers = &ServerSecurityToken;
  943. ServerBufferDescriptor.ulVersion = SECBUFFER_VERSION;
  944. ServerSecurityToken.BufferType = SECBUFFER_TOKEN;
  945. ServerSecurityToken.pvBuffer = LocalAlloc(LMEM_FIXED, PackageInfo->SecurityTokenSize);
  946. if ( ServerSecurityToken.pvBuffer == NULL ) {
  947. return GetLastError();
  948. }
  949. ClientBufferDescriptor.cBuffers = 1;
  950. ClientBufferDescriptor.pBuffers = &ClientSecurityToken;
  951. ClientBufferDescriptor.ulVersion = SECBUFFER_VERSION;
  952. ClientSecurityToken.BufferType = SECBUFFER_TOKEN;
  953. ClientSecurityToken.pvBuffer = LocalAlloc(LMEM_FIXED, PackageInfo->SecurityTokenSize);
  954. ClientSecurityToken.cbBuffer = 0;
  955. if ( ClientSecurityToken.pvBuffer == NULL ) {
  956. LocalFree( ServerSecurityToken.pvBuffer );
  957. return GetLastError();
  958. }
  959. //
  960. // Indicate context requirements. replay is necessary in order for the
  961. // context to generate valid signatures
  962. //
  963. ContextRequirements = ISC_REQ_MUTUAL_AUTH |
  964. ISC_REQ_REPLAY_DETECT |
  965. ISC_REQ_DATAGRAM;
  966. //
  967. // if there is an old outbound context, delete it now and mark it as
  968. // unstable
  969. //
  970. TargetSecurityData = &SecurityCtxtData[ INT_NODE( TargetNodeId )];
  971. EnterCriticalSection( &SecContextLock );
  972. if ( VALID_SSPI_HANDLE( TargetSecurityData->Outbound )) {
  973. (*SecurityFuncs->DeleteSecurityContext)( &TargetSecurityData->Outbound );
  974. }
  975. TargetSecurityData->OutboundStable = FALSE;
  976. LeaveCriticalSection( &SecContextLock );
  977. //
  978. // we obtain a blob from the SSPI provider, which is shiped over to the
  979. // other side where another blob is generated. This continues until the
  980. // two SSPI providers say we're done or an error has occurred.
  981. //
  982. do {
  983. //
  984. // init the output buffer each time we loop
  985. //
  986. ServerSecurityToken.cbBuffer = PackageInfo->SecurityTokenSize;
  987. EnterCriticalSection( &SecContextLock );
  988. #if CLUSTER_BETA
  989. ClRtlLogPrint(LOG_NOISE,"[ClMsg] init pass %1!u!: server token size = %2!u!, "
  990. "client = %3!u!\n",
  991. passCount,
  992. ServerSecurityToken.cbBuffer,
  993. ClientSecurityToken.cbBuffer);
  994. #endif
  995. OurStatus = (*SecurityFuncs->InitializeSecurityContext)(
  996. &PackageInfo->OutboundSecurityCredentials,
  997. passCount == 1 ? NULL : &TargetSecurityData->Outbound,
  998. NULL, // CsServiceDomainAccount, BUGBUG Temporary Workaround See Bug 160108
  999. ContextRequirements,
  1000. 0,
  1001. SECURITY_NATIVE_DREP,
  1002. passCount == 1 ? NULL : &ClientBufferDescriptor,
  1003. 0,
  1004. &TargetSecurityData->Outbound,
  1005. &ServerBufferDescriptor,
  1006. &ContextAttributes,
  1007. &Expiration);
  1008. #if CLUSTER_BETA
  1009. ClRtlLogPrint(LOG_NOISE,"[ClMsg] after init pass %1!u!: status = %2!X!, server "
  1010. "token size = %3!u!, client = %4!u!\n",
  1011. passCount,
  1012. OurStatus,
  1013. ServerSecurityToken.cbBuffer,
  1014. ClientSecurityToken.cbBuffer);
  1015. #endif
  1016. ClRtlLogPrint(LOG_NOISE,
  1017. "[ClMsg] The outbound security context to node %1!u! was %2!ws!, "
  1018. "status %3!08X!.\n",
  1019. TargetNodeId,
  1020. NT_SUCCESS( OurStatus ) ? L"initialized" : L"rejected",
  1021. OurStatus);
  1022. if ( !NT_SUCCESS( OurStatus )) {
  1023. if ( VALID_SSPI_HANDLE( TargetSecurityData->Outbound)) {
  1024. (*SecurityFuncs->DeleteSecurityContext)( &TargetSecurityData->Outbound );
  1025. INVALIDATE_SSPI_HANDLE( TargetSecurityData->Outbound );
  1026. }
  1027. LeaveCriticalSection( &SecContextLock );
  1028. Status = OurStatus;
  1029. break;
  1030. }
  1031. //
  1032. // complete the blob if the Security package directs us as such
  1033. //
  1034. if ( OurStatus == SEC_I_COMPLETE_NEEDED ||
  1035. OurStatus == SEC_I_COMPLETE_AND_CONTINUE ) {
  1036. (*SecurityFuncs->CompleteAuthToken)(
  1037. &TargetSecurityData->Outbound,
  1038. &ServerBufferDescriptor
  1039. );
  1040. }
  1041. LeaveCriticalSection( &SecContextLock );
  1042. //
  1043. // blobs are passed to the server side until it returns ok.
  1044. //
  1045. if (ServerStatus == SEC_I_CONTINUE_NEEDED ||
  1046. ServerStatus == SEC_I_COMPLETE_AND_CONTINUE ) {
  1047. ClientSecurityToken.cbBuffer = PackageInfo->SecurityTokenSize;
  1048. RPCStatus = MmRpcEstablishSecurityContext(
  1049. Session[ TargetNodeId ],
  1050. JoinSequence,
  1051. NmLocalNodeId,
  1052. passCount == 1,
  1053. RoleOfClient,
  1054. ServerSecurityToken.pvBuffer,
  1055. ServerSecurityToken.cbBuffer,
  1056. ClientSecurityToken.pvBuffer,
  1057. &ClientSecurityToken.cbBuffer,
  1058. &ServerStatus);
  1059. FacilityCode = HRESULT_FACILITY( ServerStatus );
  1060. if (
  1061. ( FacilityCode != 0 && !SUCCEEDED( ServerStatus ))
  1062. ||
  1063. ( FacilityCode == 0 && ServerStatus != ERROR_SUCCESS )
  1064. ||
  1065. RPCStatus != RPC_S_OK )
  1066. {
  1067. //
  1068. // either the blob was rejected or we had an RPC failure. If
  1069. // RPC, then ServerStatus is meaningless. Note that we don't
  1070. // delete the security context on the side since that might
  1071. // clobber an already negotiated context (i.e., the joiner has
  1072. // already negotiated its outbound context and the sponsor is
  1073. // in this routine trying to negotiate its outbound
  1074. // context. If the sponsor negotiation fails at some point, we
  1075. // don't want to whack the joiner's outbound context).
  1076. //
  1077. if ( RPCStatus != RPC_S_OK ) {
  1078. ServerStatus = RPCStatus;
  1079. }
  1080. ClRtlLogPrint(LOG_UNUSUAL,
  1081. "[ClMsg] The outbound security context was rejected by node %1!u!, "
  1082. "status 0x%2!08X!.\n",
  1083. TargetNodeId,
  1084. ServerStatus);
  1085. EnterCriticalSection( &SecContextLock );
  1086. if ( VALID_SSPI_HANDLE( TargetSecurityData->Outbound )) {
  1087. (*SecurityFuncs->DeleteSecurityContext)( &TargetSecurityData->Outbound );
  1088. INVALIDATE_SSPI_HANDLE( TargetSecurityData->Outbound );
  1089. }
  1090. LeaveCriticalSection( &SecContextLock );
  1091. Status = ServerStatus;
  1092. break;
  1093. } else {
  1094. ClRtlLogPrint(LOG_NOISE,
  1095. "[ClMsg] The outbound security context was accepted by node %1!u!, "
  1096. "status 0x%2!08X!.\n",
  1097. TargetNodeId,
  1098. ServerStatus);
  1099. }
  1100. }
  1101. ++passCount;
  1102. } while ( ServerStatus == SEC_I_CONTINUE_NEEDED ||
  1103. ServerStatus == SEC_I_COMPLETE_AND_CONTINUE ||
  1104. OurStatus == SEC_I_CONTINUE_NEEDED ||
  1105. OurStatus == SEC_I_COMPLETE_AND_CONTINUE );
  1106. if ( OurStatus == SEC_E_OK && ServerStatus == SEC_E_OK ) {
  1107. SecPkgContext_Sizes contextSizes;
  1108. SecPkgContext_PackageInfo packageInfo;
  1109. SYSTEMTIME localSystemTime;
  1110. SYSTEMTIME renegotiateSystemTime;
  1111. FILETIME expFileTime;
  1112. FILETIME renegotiateFileTime;
  1113. TIME_ZONE_INFORMATION timeZoneInfo;
  1114. DWORD timeType;
  1115. #if 0
  1116. //
  1117. // convert the expiration time to something meaningful we can print in
  1118. // the log.
  1119. //
  1120. timeType = GetTimeZoneInformation( &timeZoneInfo );
  1121. if ( timeType != TIME_ZONE_ID_INVALID ) {
  1122. expFileTime.dwLowDateTime = Expiration.LowPart;
  1123. expFileTime.dwHighDateTime = Expiration.HighPart;
  1124. if ( FileTimeToSystemTime( &expFileTime, &localSystemTime )) {
  1125. PWCHAR timeDecoration = L"";
  1126. if ( timeType == TIME_ZONE_ID_STANDARD ) {
  1127. timeDecoration = timeZoneInfo.StandardName;
  1128. } else if ( timeType == TIME_ZONE_ID_DAYLIGHT ) {
  1129. timeDecoration = timeZoneInfo.DaylightName;
  1130. }
  1131. ClRtlLogPrint(LOG_NOISE,
  1132. "[ClMsg] Context expires at %1!u!:%2!02u!:%3!02u! %4!u!/%5!u!/%6!u! %7!ws!\n",
  1133. localSystemTime.wHour,
  1134. localSystemTime.wMinute,
  1135. localSystemTime.wSecond,
  1136. localSystemTime.wMonth,
  1137. localSystemTime.wDay,
  1138. localSystemTime.wYear,
  1139. timeDecoration);
  1140. }
  1141. }
  1142. //
  1143. // now compute the half life of the expiration and set a timer to go
  1144. // off and renegotiate a context at that time
  1145. //
  1146. #endif
  1147. //
  1148. // mark context data as usable and get the size of the signature
  1149. // buffer
  1150. //
  1151. TargetSecurityData->InboundStable = TRUE;
  1152. Status = (*SecurityFuncs->QueryContextAttributes)(
  1153. &TargetSecurityData->Inbound,
  1154. SECPKG_ATTR_SIZES,
  1155. &contextSizes);
  1156. if ( !NT_SUCCESS( Status )) {
  1157. ClRtlLogPrint(LOG_CRITICAL,
  1158. "[ClMsg] Unable to query signature size, status %1!08X!.\n",
  1159. Status);
  1160. goto error_exit;
  1161. }
  1162. PackageInfo->SignatureBufferSize = contextSizes.cbMaxSignature;
  1163. CL_ASSERT( contextSizes.cbMaxSignature <= MAX_SIGNATURE_SIZE );
  1164. //
  1165. // get the name of the negotiated package and import the contexts for
  1166. // use in clusnet
  1167. //
  1168. Status = (*SecurityFuncs->QueryContextAttributes)(
  1169. &TargetSecurityData->Inbound,
  1170. SECPKG_ATTR_PACKAGE_INFO,
  1171. &packageInfo);
  1172. if ( !NT_SUCCESS( Status )) {
  1173. ClRtlLogPrint(LOG_CRITICAL,
  1174. "[ClMsg] Unable to query package info, status %1!08X!.\n",
  1175. Status);
  1176. goto error_exit;
  1177. }
  1178. Status = ClMsgImportSecurityContexts(TargetNodeId,
  1179. packageInfo.PackageInfo->Name,
  1180. contextSizes.cbMaxSignature);
  1181. (*SecurityFuncs->FreeContextBuffer)( packageInfo.PackageInfo );
  1182. if ( Status != ERROR_SUCCESS ) {
  1183. ClRtlLogPrint(LOG_UNUSUAL,
  1184. "[ClMsg] Can't import node %1!u! security contexts on server, "
  1185. "status %2!08X!.\n",
  1186. TargetNodeId,
  1187. Status);
  1188. }
  1189. //
  1190. // we have valid contexts with this package so record that this is the
  1191. // one we're using
  1192. //
  1193. TargetSecurityData->PackageInfo = PackageInfo;
  1194. }
  1195. error_exit:
  1196. //
  1197. // the context is stable (either good or invalid) at this point
  1198. //
  1199. EnterCriticalSection( &SecContextLock );
  1200. TargetSecurityData->OutboundStable = TRUE;
  1201. LeaveCriticalSection( &SecContextLock );
  1202. //
  1203. // free buffers used during this process
  1204. //
  1205. LocalFree( ClientSecurityToken.pvBuffer );
  1206. LocalFree( ServerSecurityToken.pvBuffer );
  1207. return Status;
  1208. } // ClMsgEstablishSecurityContext
  1209. //
  1210. // Exported Routines
  1211. //
  1212. DWORD
  1213. ClMsgInit(
  1214. DWORD mynode
  1215. )
  1216. {
  1217. DWORD status;
  1218. SOCKADDR_CLUSTER clusaddr;
  1219. int err;
  1220. DWORD ignored;
  1221. DWORD bytesReceived = 0;
  1222. WSABUF wsaBuf;
  1223. UNREFERENCED_PARAMETER(mynode);
  1224. if (ClMsgInitialized == TRUE) {
  1225. ClRtlLogPrint(LOG_NOISE, "[ClMsg] Already initialized!!!\n");
  1226. return(ERROR_SUCCESS);
  1227. }
  1228. ClRtlLogPrint(LOG_NOISE, "[ClMsg] Initializing.\n");
  1229. InitializeCriticalSection( &SecContextLock );
  1230. //
  1231. // load the security provider DLL and get the list of package names
  1232. //
  1233. status = ClMsgLoadSecurityProvider();
  1234. if ( status != ERROR_SUCCESS ) {
  1235. goto error_exit;
  1236. }
  1237. InitializeCriticalSection( &GenerationCritSect );
  1238. //
  1239. // Create the binding generation table.
  1240. //
  1241. BindingGeneration = LocalAlloc(
  1242. LMEM_FIXED,
  1243. sizeof(DWORD) * (NmMaxNodeId + 1)
  1244. );
  1245. if (BindingGeneration == NULL) {
  1246. status = ERROR_NOT_ENOUGH_MEMORY;
  1247. goto error_exit;
  1248. }
  1249. ZeroMemory(BindingGeneration, sizeof(DWORD) * (NmMaxNodeId + 1));
  1250. //
  1251. // Create the RPC binding handle table.
  1252. //
  1253. Session = LocalAlloc(
  1254. LMEM_FIXED,
  1255. sizeof(RPC_BINDING_HANDLE) * (NmMaxNodeId + 1)
  1256. );
  1257. if (Session == NULL) {
  1258. status = ERROR_NOT_ENOUGH_MEMORY;
  1259. goto error_exit;
  1260. }
  1261. ZeroMemory(Session, sizeof(RPC_BINDING_HANDLE) * (NmMaxNodeId + 1));
  1262. //
  1263. // Create a work queue to process overlapped I/O completions
  1264. //
  1265. WorkQueue = ClRtlCreateWorkQueue(
  1266. CLMSG_MAX_WORK_THREADS,
  1267. CLMSG_WORK_THREAD_PRIORITY
  1268. );
  1269. if (WorkQueue == NULL) {
  1270. status = GetLastError();
  1271. ClRtlLogPrint(LOG_UNUSUAL,
  1272. "[ClMsg] Unable to create work queue, status %1!u!\n",
  1273. status
  1274. );
  1275. goto error_exit;
  1276. }
  1277. //
  1278. // Allocate a datagram receive context
  1279. //
  1280. DatagramContext = LocalAlloc(LMEM_FIXED, sizeof(CLMSG_DATAGRAM_CONTEXT));
  1281. if (DatagramContext == NULL) {
  1282. status = GetLastError();
  1283. ClRtlLogPrint(LOG_CRITICAL,
  1284. "[ClMsg] Unable to allocate datagram receive buffer, status %1!u!\n",
  1285. status
  1286. );
  1287. goto error_exit;
  1288. }
  1289. //
  1290. // Allocate an event receive context
  1291. //
  1292. EventContext = LocalAlloc(LMEM_FIXED, sizeof(CLMSG_EVENT_CONTEXT));
  1293. if (EventContext == NULL) {
  1294. status = GetLastError();
  1295. ClRtlLogPrint(LOG_CRITICAL,
  1296. "[ClMsg] Unable to allocate event context, status %1!u!\n",
  1297. status
  1298. );
  1299. goto error_exit;
  1300. }
  1301. //
  1302. // Open and bind the datagram socket
  1303. //
  1304. DatagramSocket = WSASocket(
  1305. AF_CLUSTER,
  1306. SOCK_DGRAM,
  1307. CLUSPROTO_CDP,
  1308. NULL,
  1309. 0,
  1310. WSA_FLAG_OVERLAPPED
  1311. );
  1312. if (DatagramSocket == INVALID_SOCKET) {
  1313. status = WSAGetLastError();
  1314. ClRtlLogPrint(LOG_UNUSUAL,
  1315. "[ClMsg] Unable to create dgram socket, status %1!u!\n",
  1316. status
  1317. );
  1318. goto error_exit;
  1319. }
  1320. ZeroMemory(&clusaddr, sizeof(SOCKADDR_CLUSTER));
  1321. clusaddr.sac_family = AF_CLUSTER;
  1322. clusaddr.sac_port = CLMSG_DATAGRAM_PORT;
  1323. clusaddr.sac_node = 0;
  1324. err = bind(
  1325. DatagramSocket,
  1326. (struct sockaddr *) &clusaddr,
  1327. sizeof(SOCKADDR_CLUSTER)
  1328. );
  1329. if (err == SOCKET_ERROR) {
  1330. status = WSAGetLastError();
  1331. ClRtlLogPrint(LOG_CRITICAL,
  1332. "[ClMsg] Unable to bind dgram socket, status %1!u!\n",
  1333. status
  1334. );
  1335. closesocket(DatagramSocket); DatagramSocket = INVALID_SOCKET;
  1336. goto error_exit;
  1337. }
  1338. //
  1339. // Tell the Cluster Transport to disable node state checks on
  1340. // this socket.
  1341. //
  1342. err = WSAIoctl(
  1343. DatagramSocket,
  1344. SIO_CLUS_IGNORE_NODE_STATE,
  1345. NULL,
  1346. 0,
  1347. NULL,
  1348. 0,
  1349. &ignored,
  1350. NULL,
  1351. NULL
  1352. );
  1353. if (err == SOCKET_ERROR) {
  1354. status = WSAGetLastError();
  1355. ClRtlLogPrint(LOG_CRITICAL,
  1356. "[ClMsg] Ignore state ioctl failed, status %1!u!\n",
  1357. status
  1358. );
  1359. closesocket(DatagramSocket); DatagramSocket = INVALID_SOCKET;
  1360. goto error_exit;
  1361. }
  1362. //
  1363. // Associate the socket with the work queue
  1364. //
  1365. status = ClRtlAssociateIoHandleWorkQueue(
  1366. WorkQueue,
  1367. (HANDLE) DatagramSocket,
  1368. 0
  1369. );
  1370. if (status != ERROR_SUCCESS) {
  1371. ClRtlLogPrint(LOG_CRITICAL,
  1372. "[ClMsg] Failed to associate socket with work queue, status %1!u!\n",
  1373. status
  1374. );
  1375. closesocket(DatagramSocket); DatagramSocket = INVALID_SOCKET;
  1376. goto error_exit;
  1377. }
  1378. //
  1379. // Open a control channel to the Cluster Network driver.
  1380. //
  1381. ClusnetHandle = ClusnetOpenControlChannel(FILE_SHARE_READ);
  1382. if (ClusnetHandle == NULL) {
  1383. status = GetLastError();
  1384. ClRtlLogPrint(LOG_CRITICAL,
  1385. "[ClMsg] Unable to open control channel to Cluster Network driver, status %1!u!\n",
  1386. status
  1387. );
  1388. goto error_exit;
  1389. }
  1390. //
  1391. // Associate the control channel with the work queue
  1392. //
  1393. status = ClRtlAssociateIoHandleWorkQueue(
  1394. WorkQueue,
  1395. ClusnetHandle,
  1396. 0
  1397. );
  1398. if (status != ERROR_SUCCESS) {
  1399. ClRtlLogPrint(LOG_CRITICAL,
  1400. "[ClMsg] Failed to associate control channel with work queue, status %1!u!\n",
  1401. status
  1402. );
  1403. CloseHandle(ClusnetHandle); ClusnetHandle = NULL;
  1404. goto error_exit;
  1405. }
  1406. //
  1407. // Post a receive on the socket
  1408. //
  1409. ZeroMemory(DatagramContext, sizeof(CLMSG_DATAGRAM_CONTEXT));
  1410. DatagramContext->ClRtlWorkItem.WorkRoutine = ClMsgDatagramHandler,
  1411. DatagramContext->ClRtlWorkItem.Context = DatagramContext;
  1412. DatagramContext->SourceAddressLength = sizeof(SOCKADDR_CLUSTER);
  1413. wsaBuf.len = sizeof( DatagramContext->Data );
  1414. wsaBuf.buf = (PCHAR)&DatagramContext->Data;
  1415. err = WSARecvFrom(
  1416. DatagramSocket,
  1417. &wsaBuf,
  1418. 1,
  1419. &bytesReceived,
  1420. &(DatagramContext->Flags),
  1421. (struct sockaddr *) &(DatagramContext->SourceAddress),
  1422. &(DatagramContext->SourceAddressLength),
  1423. &(DatagramContext->ClRtlWorkItem.Overlapped),
  1424. NULL
  1425. );
  1426. if (err == SOCKET_ERROR) {
  1427. status = WSAGetLastError();
  1428. if (status != WSA_IO_PENDING) {
  1429. ClRtlLogPrint(LOG_CRITICAL,
  1430. "[ClMsg] Unable to post datagram receive, status %1!u!\n",
  1431. status
  1432. );
  1433. goto error_exit;
  1434. }
  1435. }
  1436. //
  1437. // Enable delivery of all Cluster Network event types
  1438. //
  1439. status = ClusnetSetEventMask(ClusnetHandle, ClusnetEventAll);
  1440. if (status != ERROR_SUCCESS) {
  1441. ClRtlLogPrint(LOG_CRITICAL,
  1442. "[ClMsg] Unable to set event mask, status %1!u!\n",
  1443. status
  1444. );
  1445. goto error_exit;
  1446. }
  1447. //
  1448. // Post a work item to receive the next Cluster Network event
  1449. //
  1450. ClRtlInitializeWorkItem(
  1451. &(EventContext->ClRtlWorkItem),
  1452. ClMsgEventHandler,
  1453. EventContext
  1454. );
  1455. status = ClusnetGetNextEvent(
  1456. ClusnetHandle,
  1457. &(EventContext->EventData),
  1458. &(EventContext->ClRtlWorkItem.Overlapped)
  1459. );
  1460. if ((status != ERROR_IO_PENDING) && (status != ERROR_SUCCESS)) {
  1461. ClRtlLogPrint(LOG_CRITICAL,
  1462. "[ClMsg] GetNextEvent failed, status %1!u!\n",
  1463. status
  1464. );
  1465. goto error_exit;
  1466. }
  1467. ClMsgInitialized = TRUE;
  1468. return(ERROR_SUCCESS);
  1469. error_exit:
  1470. ClMsgCleanup();
  1471. return(status);
  1472. } // ClMsgInit
  1473. VOID
  1474. ClMsgCleanup(
  1475. VOID
  1476. )
  1477. {
  1478. ULONG i;
  1479. PCLUSTER_PACKAGE_INFO packageInfo;
  1480. ClRtlLogPrint(LOG_NOISE, "[ClMsg] Cleaning up\n");
  1481. if (Session != NULL) {
  1482. LocalFree(Session); Session = NULL;
  1483. }
  1484. if (BindingGeneration != NULL) {
  1485. LocalFree(BindingGeneration); BindingGeneration = NULL;
  1486. }
  1487. if (WorkQueue != NULL) {
  1488. if (DatagramSocket != INVALID_SOCKET) {
  1489. closesocket(DatagramSocket); DatagramSocket = INVALID_SOCKET;
  1490. }
  1491. else {
  1492. if (DatagramContext != NULL) {
  1493. LocalFree(DatagramContext); DatagramContext = NULL;
  1494. }
  1495. }
  1496. if (ClusnetHandle != NULL) {
  1497. CloseHandle(ClusnetHandle); ClusnetHandle = NULL;
  1498. }
  1499. else {
  1500. if (EventContext != NULL) {
  1501. LocalFree(EventContext); EventContext = NULL;
  1502. }
  1503. }
  1504. ClRtlDestroyWorkQueue(WorkQueue); WorkQueue = NULL;
  1505. }
  1506. //
  1507. // clean up the security related stuff
  1508. //
  1509. EnterCriticalSection( &SecContextLock );
  1510. for ( i = ClusterMinNodeId; i <= NmMaxNodeId; ++i ) {
  1511. PCLUSTER_SECURITY_DATA SecurityData = &SecurityCtxtData[ INT_NODE( i )];
  1512. if ( VALID_SSPI_HANDLE( SecurityData->Outbound )) {
  1513. (*SecurityFuncs->DeleteSecurityContext)( &SecurityData->Outbound );
  1514. INVALIDATE_SSPI_HANDLE( SecurityData->Outbound );
  1515. }
  1516. if ( VALID_SSPI_HANDLE( SecurityData->Inbound )) {
  1517. (*SecurityFuncs->DeleteSecurityContext)( &SecurityData->Inbound );
  1518. INVALIDATE_SSPI_HANDLE( SecurityData->Inbound );
  1519. }
  1520. SecurityData->PackageInfo = NULL;
  1521. SecurityData->InboundStable = TRUE;
  1522. SecurityData->OutboundStable = TRUE;
  1523. }
  1524. LeaveCriticalSection( &SecContextLock );
  1525. packageInfo = PackageInfoList;
  1526. while ( packageInfo != NULL ) {
  1527. PCLUSTER_PACKAGE_INFO lastInfo;
  1528. if ( VALID_SSPI_HANDLE( packageInfo->OutboundSecurityCredentials )) {
  1529. (*SecurityFuncs->FreeCredentialHandle)( &packageInfo->OutboundSecurityCredentials );
  1530. }
  1531. if ( VALID_SSPI_HANDLE( packageInfo->InboundSecurityCredentials )) {
  1532. (*SecurityFuncs->FreeCredentialHandle)( &packageInfo->InboundSecurityCredentials );
  1533. }
  1534. LocalFree( packageInfo->Name );
  1535. lastInfo = packageInfo;
  1536. packageInfo = packageInfo->Next;
  1537. LocalFree( lastInfo );
  1538. }
  1539. PackageInfoList = NULL;
  1540. if ( SecurityProvider != NULL ) {
  1541. FreeLibrary( SecurityProvider );
  1542. SecurityProvider = NULL;
  1543. SecurityFuncs = NULL;
  1544. }
  1545. ClMsgInitialized = FALSE;
  1546. //
  1547. // [REENGINEER] GorN 8/25/2000: if a join fails, ClMsgCleanup will be executed,
  1548. // but some stray RPC thread can call s_MmRpcDeleteSecurityContext later.
  1549. // s_MmRpcDeleteSecuryContext needs SecContextLock for synchronization
  1550. // See bug #145746.
  1551. // I traced the code and it seems that all code paths that execute ClMsgCleanup
  1552. // will eventually lead to clustering service death, so it is valid (though ugly)
  1553. // not to delete this critical section.
  1554. //
  1555. // DeleteCriticalSection( &SecContextLock );
  1556. return;
  1557. } // ClMsgCleanup
  1558. DWORD
  1559. ClMsgSendUnack(
  1560. DWORD DestinationNode,
  1561. LPCSTR Message,
  1562. DWORD MessageLength
  1563. )
  1564. /*++
  1565. Description
  1566. Send an unacknowledged datagram to the destintation node. The only
  1567. packets coming through this function should be regroup packets.
  1568. Heartbeats and poison packets originate in clusnet. Packets sent by
  1569. MM as a result of the Join process are handled by MmRpcMsgSend, which
  1570. is authenticated.
  1571. A valid security context must be established between the local and
  1572. destination node. The message is signed.
  1573. --*/
  1574. {
  1575. DWORD status = ERROR_SUCCESS;
  1576. SOCKADDR_CLUSTER clusaddr;
  1577. int bytesSent;
  1578. SecBufferDesc SignatureDescriptor;
  1579. SecBuffer SignatureSecBuffer[2];
  1580. PUCHAR SignatureBuffer;
  1581. WSABUF wsaBuf[2];
  1582. SECURITY_STATUS SecStatus;
  1583. PCLUSTER_SECURITY_DATA SecurityData;
  1584. CL_ASSERT(ClMsgInitialized == TRUE);
  1585. CL_ASSERT(DatagramSocket != INVALID_SOCKET);
  1586. CL_ASSERT(DestinationNode <= NmMaxNodeId);
  1587. if (DestinationNode == 0) {
  1588. // no signing if multicasting
  1589. ZeroMemory(&clusaddr, sizeof(SOCKADDR_CLUSTER));
  1590. clusaddr.sac_family = AF_CLUSTER;
  1591. clusaddr.sac_port = CLMSG_DATAGRAM_PORT;
  1592. clusaddr.sac_node = DestinationNode;
  1593. wsaBuf[0].len = MessageLength;
  1594. wsaBuf[0].buf = (PCHAR)Message;
  1595. status = WSASendTo(DatagramSocket,
  1596. wsaBuf,
  1597. 1,
  1598. &bytesSent,
  1599. 0,
  1600. (struct sockaddr *) &clusaddr,
  1601. sizeof(clusaddr),
  1602. NULL,
  1603. NULL);
  1604. if (status == SOCKET_ERROR) {
  1605. status = WSAGetLastError();
  1606. ClRtlLogPrint(LOG_UNUSUAL,
  1607. "[ClMsg] Multicast Datagram send failed, status %1!u!\n",
  1608. status
  1609. );
  1610. }
  1611. } else if (DestinationNode != NmLocalNodeId) {
  1612. EnterCriticalSection( &SecContextLock );
  1613. SecurityData = &SecurityCtxtData[ INT_NODE( DestinationNode )];
  1614. CL_ASSERT( SecurityData->PackageInfo->SignatureBufferSize <= 256 );
  1615. SignatureBuffer = _alloca( SecurityData->PackageInfo->SignatureBufferSize );
  1616. if ( !SignatureBuffer ) {
  1617. // if we fail - return error now
  1618. LeaveCriticalSection( &SecContextLock );
  1619. return(ERROR_NOT_ENOUGH_MEMORY);
  1620. }
  1621. if ( SecurityData->OutboundStable &&
  1622. VALID_SSPI_HANDLE( SecurityData->Outbound)) {
  1623. //
  1624. // build a descriptor for the message and signature
  1625. //
  1626. SignatureDescriptor.cBuffers = 2;
  1627. SignatureDescriptor.pBuffers = SignatureSecBuffer;
  1628. SignatureDescriptor.ulVersion = SECBUFFER_VERSION;
  1629. SignatureSecBuffer[0].BufferType = SECBUFFER_DATA;
  1630. SignatureSecBuffer[0].cbBuffer = MessageLength;
  1631. SignatureSecBuffer[0].pvBuffer = (PVOID)Message;
  1632. SignatureSecBuffer[1].BufferType = SECBUFFER_TOKEN;
  1633. SignatureSecBuffer[1].cbBuffer = SecurityData->PackageInfo->SignatureBufferSize;
  1634. SignatureSecBuffer[1].pvBuffer = SignatureBuffer;
  1635. //
  1636. // generate the signature. We'll let the provider generate
  1637. // the sequence number.
  1638. //
  1639. SecStatus = (*SecurityFuncs->MakeSignature)(
  1640. &SecurityData->Outbound,
  1641. 0,
  1642. &SignatureDescriptor,
  1643. 0); // no supplied sequence number
  1644. LeaveCriticalSection( &SecContextLock );
  1645. if ( NT_SUCCESS( SecStatus )) {
  1646. ZeroMemory(&clusaddr, sizeof(SOCKADDR_CLUSTER));
  1647. clusaddr.sac_family = AF_CLUSTER;
  1648. clusaddr.sac_port = CLMSG_DATAGRAM_PORT;
  1649. clusaddr.sac_node = DestinationNode;
  1650. wsaBuf[0].len = MessageLength;
  1651. wsaBuf[0].buf = (PCHAR)Message;
  1652. wsaBuf[1].len = SecurityData->PackageInfo->SignatureBufferSize;
  1653. wsaBuf[1].buf = (PCHAR)SignatureBuffer;
  1654. status = WSASendTo(DatagramSocket,
  1655. wsaBuf,
  1656. 2,
  1657. &bytesSent,
  1658. 0,
  1659. (struct sockaddr *) &clusaddr,
  1660. sizeof(clusaddr),
  1661. NULL,
  1662. NULL);
  1663. if (status == SOCKET_ERROR) {
  1664. status = WSAGetLastError();
  1665. ClRtlLogPrint(LOG_UNUSUAL,
  1666. "[ClMsg] Datagram send failed, status %1!u!\n",
  1667. status
  1668. );
  1669. }
  1670. } else {
  1671. ClRtlLogPrint(LOG_UNUSUAL,
  1672. "[ClMsg] Couldn't create signature for packet to node %u. Status: %08X\n",
  1673. DestinationNode,
  1674. SecStatus);
  1675. }
  1676. } else {
  1677. LeaveCriticalSection( &SecContextLock );
  1678. status = ERROR_CLUSTER_NO_SECURITY_CONTEXT;
  1679. ClRtlLogPrint(LOG_UNUSUAL,
  1680. "[ClMsg] No Security context for node %1!u!\n",
  1681. DestinationNode);
  1682. }
  1683. }
  1684. else {
  1685. MMDiag( (LPCSTR)Message, MessageLength, &MessageLength);
  1686. }
  1687. return(status);
  1688. } // ClMsgSendUnack
  1689. DWORD
  1690. ClMsgCreateRpcBinding(
  1691. IN PNM_NODE Node,
  1692. OUT RPC_BINDING_HANDLE * BindingHandle,
  1693. IN DWORD RpcBindingOptions
  1694. )
  1695. {
  1696. DWORD Status;
  1697. RPC_BINDING_HANDLE NewBindingHandle;
  1698. WCHAR *BindingString = NULL;
  1699. CL_NODE_ID NodeId = NmGetNodeId(Node);
  1700. ClRtlLogPrint(LOG_NOISE,
  1701. "[ClMsg] Creating RPC binding for node %1!u!\n",
  1702. NodeId
  1703. );
  1704. Status = RpcStringBindingComposeW(
  1705. L"e248d0b8-bf15-11cf-8c5e-08002bb49649",
  1706. CLUSTER_RPC_PROTSEQ,
  1707. (LPWSTR) OmObjectId(Node),
  1708. CLUSTER_RPC_PORT,
  1709. NULL,
  1710. &BindingString
  1711. );
  1712. if (Status != RPC_S_OK) {
  1713. ClRtlLogPrint(LOG_CRITICAL,
  1714. "[ClMsg] Failed to compose binding string for node %1!u!, status %2!u!\n",
  1715. NodeId,
  1716. Status
  1717. );
  1718. return(Status);
  1719. }
  1720. Status = RpcBindingFromStringBindingW(BindingString, &NewBindingHandle);
  1721. RpcStringFreeW(&BindingString);
  1722. if (Status != RPC_S_OK) {
  1723. ClRtlLogPrint(LOG_CRITICAL,
  1724. "[ClMsg] Failed to compose binding handle for node %1!u!, status %2!u!\n",
  1725. NodeId,
  1726. Status
  1727. );
  1728. return(Status);
  1729. }
  1730. //
  1731. // If we have RpcBindingOptions, then set them
  1732. //
  1733. if ( RpcBindingOptions ) {
  1734. Status = RpcBindingSetOption(
  1735. NewBindingHandle,
  1736. RpcBindingOptions,
  1737. TRUE
  1738. );
  1739. if (Status != RPC_S_OK) {
  1740. ClRtlLogPrint(LOG_UNUSUAL,
  1741. "[ClMsg] Unable to set unique RPC binding option for node %1!u!, status %2!u!.\n",
  1742. NodeId,
  1743. Status
  1744. );
  1745. }
  1746. }
  1747. Status = RpcMgmtSetComTimeout(
  1748. NewBindingHandle,
  1749. CLUSTER_INTRACLUSTER_RPC_COM_TIMEOUT
  1750. );
  1751. if (Status != RPC_S_OK) {
  1752. ClRtlLogPrint(LOG_UNUSUAL,
  1753. "[ClMsg] Unable to set RPC com timeout to node %1!u!, status %2!u!.\n",
  1754. NodeId,
  1755. Status
  1756. );
  1757. }
  1758. Status = ClMsgVerifyRpcBinding(NewBindingHandle);
  1759. if (Status == ERROR_SUCCESS) {
  1760. *BindingHandle = NewBindingHandle;
  1761. }
  1762. return(Status);
  1763. } // ClMsgCreateRpcBinding
  1764. DWORD
  1765. ClMsgVerifyRpcBinding(
  1766. IN RPC_BINDING_HANDLE BindingHandle
  1767. )
  1768. {
  1769. DWORD status = ERROR_SUCCESS;
  1770. DWORD packageIndex;
  1771. if ( CsUseAuthenticatedRPC ) {
  1772. //
  1773. // establish a security context with for the intracluster binding. We
  1774. // need a routine to call since datagram RPC doesn't set up the
  1775. // context until the first call. MmRpcDeleteSecurityContext is
  1776. // idempotent and won't do any damage in that respect.
  1777. //
  1778. for (packageIndex = 0;
  1779. packageIndex < CsNumberOfRPCSecurityPackages;
  1780. ++packageIndex )
  1781. {
  1782. status = RpcBindingSetAuthInfoW(
  1783. BindingHandle,
  1784. CsServiceDomainAccount,
  1785. RPC_C_AUTHN_LEVEL_CONNECT,
  1786. CsRPCSecurityPackage[ packageIndex ],
  1787. NULL,
  1788. RPC_C_AUTHZ_NAME
  1789. );
  1790. if (status != RPC_S_OK) {
  1791. ClRtlLogPrint(LOG_UNUSUAL,
  1792. "[ClMsg] Unable to set IntraCluster AuthInfo using %1!ws! "
  1793. "package, Status %2!u!.\n",
  1794. CsRPCSecurityPackageName[packageIndex],
  1795. status
  1796. );
  1797. continue;
  1798. }
  1799. status = MmRpcDeleteSecurityContext(
  1800. BindingHandle,
  1801. NmLocalNodeId
  1802. );
  1803. if ( status == RPC_S_OK ) {
  1804. ClRtlLogPrint(LOG_NOISE,
  1805. "[ClMsg] Using %1!ws! package for RPC security contexts.\n",
  1806. CsRPCSecurityPackageName[packageIndex]
  1807. );
  1808. break;
  1809. } else {
  1810. ClRtlLogPrint(LOG_NOISE,
  1811. "[ClMsg] Failed to establish RPC security context using %1!ws! package "
  1812. ", status %2!u!.\n",
  1813. CsRPCSecurityPackageName[packageIndex],
  1814. status
  1815. );
  1816. }
  1817. }
  1818. }
  1819. return(status);
  1820. } // ClMsgVerifyRpcBinding
  1821. VOID
  1822. ClMsgDeleteRpcBinding(
  1823. IN RPC_BINDING_HANDLE BindingHandle
  1824. )
  1825. {
  1826. RPC_BINDING_HANDLE bindingHandle = BindingHandle;
  1827. RpcBindingFree(&bindingHandle);
  1828. return;
  1829. } // ClMsgDeleteRpcBinding
  1830. DWORD
  1831. ClMsgCreateDefaultRpcBinding(
  1832. IN PNM_NODE Node,
  1833. OUT PDWORD Generation
  1834. )
  1835. {
  1836. DWORD Status;
  1837. RPC_BINDING_HANDLE BindingHandle;
  1838. CL_NODE_ID NodeId = NmGetNodeId( Node );
  1839. CL_ASSERT(Session != NULL);
  1840. //
  1841. // [GorN 08/01.99] InterlockedAdd will not work here,
  1842. // see the code in ClMsgdeleteDefaultRpcBinding
  1843. //
  1844. EnterCriticalSection( &GenerationCritSect );
  1845. *Generation = ++BindingGeneration[NodeId];
  1846. LeaveCriticalSection( &GenerationCritSect );
  1847. ClRtlLogPrint(LOG_NOISE,
  1848. "[ClMsg] BindingGeneration %1!u!\n",
  1849. BindingGeneration[NodeId]
  1850. );
  1851. if (Session[NodeId] != NULL) {
  1852. ClRtlLogPrint(LOG_NOISE,
  1853. "[ClMsg] Verifying old RPC binding for node %1!u!\n",
  1854. NodeId
  1855. );
  1856. BindingHandle = Session[NodeId];
  1857. Status = ClMsgVerifyRpcBinding(BindingHandle);
  1858. }
  1859. else {
  1860. Status = ClMsgCreateRpcBinding(
  1861. Node,
  1862. &BindingHandle,
  1863. 0 );
  1864. if (Status == RPC_S_OK) {
  1865. Session[NodeId] = BindingHandle;
  1866. }
  1867. }
  1868. return(Status);
  1869. } // ClMsgCreateDefaultRpcBinding
  1870. VOID
  1871. ClMsgDeleteDefaultRpcBinding(
  1872. IN PNM_NODE Node,
  1873. IN DWORD Generation
  1874. )
  1875. {
  1876. CL_NODE_ID NodeId = NmGetNodeId(Node);
  1877. RPC_BINDING_HANDLE BindingHandle;
  1878. if (Session != NULL) {
  1879. EnterCriticalSection( &GenerationCritSect );
  1880. BindingHandle = Session[NodeId];
  1881. if (Generation != BindingGeneration[NodeId]) {
  1882. BindingHandle = NULL;
  1883. ClRtlLogPrint(LOG_UNUSUAL,
  1884. "[ClMsg] DeleteDefaultBinding. Gen %1!u! != BindingGen %2!u!\n",
  1885. Generation,
  1886. BindingGeneration[NodeId]);
  1887. }
  1888. LeaveCriticalSection( &GenerationCritSect );
  1889. if (BindingHandle != NULL) {
  1890. Session[NodeId] = NULL;
  1891. ClMsgDeleteRpcBinding(BindingHandle);
  1892. }
  1893. }
  1894. return;
  1895. } // ClMsgDeleteDefaultRpcBinding
  1896. DWORD
  1897. ClMsgCreateActiveNodeSecurityContext(
  1898. IN DWORD JoinSequence,
  1899. IN PNM_NODE Node
  1900. )
  1901. /*++
  1902. Routine Description:
  1903. Create security contexts between the joiner and the specified cluster
  1904. member.
  1905. Arguments:
  1906. JoinSequence - the current join sequence number. Used the sponsor to
  1907. determine if this is beginning of a new context generation
  1908. sequence
  1909. Node - A pointer to the target node object.
  1910. Return Value:
  1911. ERROR_SUCCESS if everything worked ok...
  1912. --*/
  1913. {
  1914. DWORD memberNodeId = NmGetNodeId( Node );
  1915. CLUSTER_NODE_STATE nodeState;
  1916. DWORD status = ERROR_SUCCESS;
  1917. DWORD internalMemberId;
  1918. PCLUSTER_PACKAGE_INFO packageInfo;
  1919. nodeState = NmGetNodeState( Node );
  1920. if (nodeState == ClusterNodeUp || nodeState == ClusterNodePaused) {
  1921. #if DBG
  1922. CLUSNET_NODE_COMM_STATE NodeCommState;
  1923. status = ClusnetGetNodeCommState(
  1924. NmClusnetHandle,
  1925. memberNodeId,
  1926. &NodeCommState);
  1927. CL_ASSERT(status == ERROR_SUCCESS);
  1928. CL_ASSERT(NodeCommState == ClusnetNodeCommStateOnline);
  1929. #endif // DBG
  1930. packageInfo = PackageInfoList;
  1931. while ( packageInfo != NULL ) {
  1932. status = ClMsgEstablishSecurityContext(JoinSequence,
  1933. memberNodeId,
  1934. SecurityRoleJoiningMember,
  1935. packageInfo);
  1936. if ( status == ERROR_SUCCESS ) {
  1937. break;
  1938. }
  1939. //
  1940. // clean up if it didn't work
  1941. //
  1942. internalMemberId = INT_NODE( memberNodeId );
  1943. EnterCriticalSection( &SecContextLock );
  1944. if ( VALID_SSPI_HANDLE( SecurityCtxtData[ internalMemberId ].Outbound )) {
  1945. (*SecurityFuncs->DeleteSecurityContext)(
  1946. &SecurityCtxtData[ internalMemberId ].Outbound);
  1947. INVALIDATE_SSPI_HANDLE( SecurityCtxtData[ internalMemberId ].Outbound );
  1948. }
  1949. MmRpcDeleteSecurityContext(Session[ memberNodeId ],
  1950. NmLocalNodeId);
  1951. LeaveCriticalSection( &SecContextLock );
  1952. packageInfo = packageInfo->Next;
  1953. }
  1954. }
  1955. return status;
  1956. } // ClMsgCreateActiveNodeSecurityContext
  1957. error_status_t
  1958. s_TestRPCSecurity(
  1959. IN handle_t IDL_handle
  1960. )
  1961. /*++
  1962. Description:
  1963. Dummy routine to make sure we don't get any failures due to
  1964. authentication when calling other ExtroCluster interfaces
  1965. --*/
  1966. {
  1967. return ERROR_SUCCESS;
  1968. } // s_TestRPCSecurity
  1969. error_status_t
  1970. s_MmRpcEstablishSecurityContext(
  1971. IN handle_t IDL_handle,
  1972. DWORD NmJoinSequence,
  1973. DWORD EstablishingNodeId,
  1974. BOOL FirstTime,
  1975. SECURITY_ROLE RoleOfClient,
  1976. const UCHAR *ServerContext,
  1977. DWORD ServerContextLength,
  1978. UCHAR *ClientContext,
  1979. DWORD *ClientContextLength,
  1980. HRESULT * ServerStatus
  1981. )
  1982. /*++
  1983. Routine Description:
  1984. Server side of the RPC interface for establishing a security context
  1985. Arguments:
  1986. IDL_handle - RPC binding handle, not used.
  1987. EstablishingNodeId - ID of node wishing to establish security context with us
  1988. FirstTime - used for multi-leg authentication sequences
  1989. RoleOfClient - indicates whether the client establishing the security
  1990. context is acting as a cluster member or a joining member. Determines
  1991. when the client/server roles of establishing a security context are
  1992. reversed.
  1993. ServerContext - security context buffer built by client and used as
  1994. input by server
  1995. ServerContextLength - size of ServerContext in bytes
  1996. ClientContext - address of buffer used by Server in which to write
  1997. context to be sent back to client
  1998. ClientContextLength - pointer to size of ClientContext in bytes. Set by
  1999. client on input to reflect length of ClientContext. Set by server to
  2000. indicate length of ClientContext after AcceptSecurityContext is called.
  2001. ServerStatus - pointer to value that receives status of security package
  2002. call. This is not returned as a function value so as to distinguish
  2003. between RPC errors and errors from this function.
  2004. Return Value:
  2005. ERROR_SUCCESS if everything works ok.
  2006. --*/
  2007. {
  2008. SecBufferDesc ServerBufferDescriptor;
  2009. SecBuffer ServerSecurityToken;
  2010. SecBufferDesc ClientBufferDescriptor;
  2011. SecBuffer ClientSecurityToken;
  2012. SECURITY_STATUS Status = ERROR_SUCCESS;
  2013. ULONG ContextAttributes;
  2014. TimeStamp Expiration;
  2015. PCLUSTER_SECURITY_DATA SecurityData;
  2016. PNM_NODE joinerNode = NULL;
  2017. ULONG contextRequirements;
  2018. PCLUSTER_PACKAGE_INFO clusterPackageInfo;
  2019. static ULONG passCount;
  2020. CL_ASSERT(EstablishingNodeId >= ClusterMinNodeId &&
  2021. EstablishingNodeId <= NmMaxNodeId );
  2022. if (RoleOfClient == SecurityRoleJoiningMember) {
  2023. //
  2024. // The caller is a joining member.
  2025. //
  2026. joinerNode = NmReferenceJoinerNode(NmJoinSequence,
  2027. EstablishingNodeId);
  2028. if (joinerNode == NULL) {
  2029. Status = GetLastError();
  2030. }
  2031. }
  2032. else {
  2033. //
  2034. // The caller is a cluster member.
  2035. //
  2036. DWORD joinSequence = NmGetJoinSequence();
  2037. CL_ASSERT(joinSequence == NmJoinSequence);
  2038. if (joinSequence != NmJoinSequence) {
  2039. //
  2040. // This should never happen.
  2041. //
  2042. ClRtlLogPrint(LOG_UNUSUAL,
  2043. "[NM] Received call to establish a security context from member node "
  2044. "%1!u! with bogus join sequence %2!u!.\n",
  2045. EstablishingNodeId,
  2046. NmJoinSequence);
  2047. Status = ERROR_INVALID_PARAMETER;
  2048. }
  2049. }
  2050. if ( Status != ERROR_SUCCESS ) {
  2051. *ServerStatus = Status;
  2052. return ERROR_SUCCESS;
  2053. }
  2054. if ( FirstTime ) {
  2055. passCount = 1;
  2056. ClRtlLogPrint(LOG_NOISE,
  2057. "[ClMsg] Establishing inbound security context with node %1!u!, sequence %2!u!\n",
  2058. EstablishingNodeId,
  2059. NmJoinSequence);
  2060. } else {
  2061. ++passCount;
  2062. }
  2063. SecurityData = &SecurityCtxtData[ INT_NODE( EstablishingNodeId )];
  2064. EnterCriticalSection( &SecContextLock );
  2065. //
  2066. // if we have a leftover handle, try to zap it now
  2067. //
  2068. if ( FirstTime && VALID_SSPI_HANDLE( SecurityData->Inbound )) {
  2069. (*SecurityFuncs->DeleteSecurityContext)( &SecurityData->Inbound );
  2070. INVALIDATE_SSPI_HANDLE( SecurityData->Inbound );
  2071. SecurityData->InboundStable = FALSE;
  2072. }
  2073. //
  2074. // Build the input buffer descriptor.
  2075. //
  2076. ServerBufferDescriptor.cBuffers = 1;
  2077. ServerBufferDescriptor.pBuffers = &ServerSecurityToken;
  2078. ServerBufferDescriptor.ulVersion = SECBUFFER_VERSION;
  2079. ServerSecurityToken.BufferType = SECBUFFER_TOKEN;
  2080. ServerSecurityToken.cbBuffer = ServerContextLength;
  2081. ServerSecurityToken.pvBuffer = (PUCHAR)ServerContext;
  2082. //
  2083. // Build the output buffer descriptor.
  2084. //
  2085. ClientBufferDescriptor.cBuffers = 1;
  2086. ClientBufferDescriptor.pBuffers = &ClientSecurityToken;
  2087. ClientBufferDescriptor.ulVersion = SECBUFFER_VERSION;
  2088. ClientSecurityToken.BufferType = SECBUFFER_TOKEN;
  2089. ClientSecurityToken.cbBuffer = *ClientContextLength;
  2090. ClientSecurityToken.pvBuffer = ClientContext;
  2091. contextRequirements = ASC_REQ_MUTUAL_AUTH |
  2092. ASC_REQ_REPLAY_DETECT |
  2093. ASC_REQ_DATAGRAM;
  2094. //
  2095. // we don't want to rely on version info to determine what type of package
  2096. // the joiner is using, so we'll try to accept the context with all the
  2097. // packages that are listed in the security package list.
  2098. //
  2099. if ( FirstTime ) {
  2100. CL_ASSERT( PackageInfoList != NULL );
  2101. clusterPackageInfo = PackageInfoList;
  2102. while ( clusterPackageInfo != NULL ) {
  2103. Status = (*SecurityFuncs->AcceptSecurityContext)(
  2104. &clusterPackageInfo->InboundSecurityCredentials,
  2105. NULL,
  2106. &ServerBufferDescriptor,
  2107. contextRequirements,
  2108. SECURITY_NATIVE_DREP,
  2109. &SecurityData->Inbound, // receives new context handle
  2110. &ClientBufferDescriptor, // receives output security token
  2111. &ContextAttributes, // receives context attributes
  2112. &Expiration // receives context expiration time
  2113. );
  2114. #if CLUSTER_BETA
  2115. ClRtlLogPrint(LOG_NOISE,
  2116. "[ClMsg] pass 1 accept using %1!ws!: status = 0x%2!08X!, server "
  2117. "token size = %3!u!, client = %4!u!\n",
  2118. clusterPackageInfo->Name,
  2119. Status,
  2120. ServerSecurityToken.cbBuffer,
  2121. ClientSecurityToken.cbBuffer);
  2122. #endif
  2123. ClRtlLogPrint(LOG_NOISE,
  2124. "[ClMsg] The inbound security context from node %1!u! using the "
  2125. "%2!ws! package was %3!ws!, status %4!08X!\n",
  2126. EstablishingNodeId,
  2127. clusterPackageInfo->Name,
  2128. NT_SUCCESS( Status ) ? L"accepted" : L"rejected",
  2129. Status);
  2130. if ( NT_SUCCESS( Status )) {
  2131. SecurityData->PackageInfo = clusterPackageInfo;
  2132. break;
  2133. }
  2134. clusterPackageInfo = clusterPackageInfo->Next;
  2135. }
  2136. if ( !NT_SUCCESS( Status )) {
  2137. goto error_exit;
  2138. }
  2139. } else {
  2140. CL_ASSERT( SecurityData->PackageInfo != NULL );
  2141. Status = (*SecurityFuncs->AcceptSecurityContext)(
  2142. &SecurityData->PackageInfo->InboundSecurityCredentials,
  2143. &SecurityData->Inbound,
  2144. &ServerBufferDescriptor,
  2145. contextRequirements,
  2146. SECURITY_NATIVE_DREP,
  2147. &SecurityData->Inbound, // receives new context handle
  2148. &ClientBufferDescriptor, // receives output security token
  2149. &ContextAttributes, // receives context attributes
  2150. &Expiration // receives context expiration time
  2151. );
  2152. #if CLUSTER_BETA
  2153. ClRtlLogPrint(LOG_NOISE,
  2154. "[ClMsg] after pass %1!u! accept using %2!ws!: status = 0x%3!08X!, server "
  2155. "token size = %4!u!, client = %5!u!\n",
  2156. passCount,
  2157. SecurityData->PackageInfo->Name,
  2158. Status,
  2159. ServerSecurityToken.cbBuffer,
  2160. ClientSecurityToken.cbBuffer);
  2161. #endif
  2162. ClRtlLogPrint(LOG_NOISE,
  2163. "[ClMsg] The inbound security context from node %1!u! using the %2!ws! package "
  2164. "was %3!ws!, status: %4!08X!\n",
  2165. EstablishingNodeId,
  2166. SecurityData->PackageInfo->Name,
  2167. NT_SUCCESS( Status ) ? L"accepted" : L"rejected",
  2168. Status);
  2169. if ( !NT_SUCCESS( Status )) {
  2170. goto error_exit;
  2171. }
  2172. }
  2173. //
  2174. // update the client's notion of how long its buffer is
  2175. //
  2176. *ClientContextLength = ClientSecurityToken.cbBuffer;
  2177. if (Status == SEC_E_OK
  2178. &&
  2179. RoleOfClient == SecurityRoleJoiningMember)
  2180. {
  2181. //
  2182. // now we have the server side (inbound) of a security context between
  2183. // the joining node and its sponsor (the joining side may not be
  2184. // completely done generating the context). This context is used by
  2185. // the joining node to sign packets and by the sponsor to verify
  2186. // them. Now we do the same thing with client/server roles reversed in
  2187. // order to create an outbound security context which is used by the
  2188. // sponsor to sign packets and by the joining node to verify those
  2189. // packets.
  2190. //
  2191. // look up the package that was used to generate the inbound context
  2192. // and use it for the outbound
  2193. //
  2194. SecPkgContext_PackageInfo packageInfo;
  2195. Status = (*SecurityFuncs->QueryContextAttributes)(
  2196. &SecurityData->Inbound,
  2197. SECPKG_ATTR_PACKAGE_INFO,
  2198. &packageInfo);
  2199. if ( !NT_SUCCESS( Status )) {
  2200. ClRtlLogPrint(LOG_CRITICAL,
  2201. "[ClMsg] Unable to query inbound context package info, status %1!08X!.\n",
  2202. Status);
  2203. goto error_exit;
  2204. }
  2205. clusterPackageInfo = PackageInfoList;
  2206. while ( clusterPackageInfo != NULL ) {
  2207. if (( wcscmp( clusterPackageInfo->Name, packageInfo.PackageInfo->Name ) == 0 )
  2208. ||
  2209. ( _wcsicmp( L"kerberos", packageInfo.PackageInfo->Name ) == 0
  2210. &&
  2211. _wcsicmp( L"negotiate", clusterPackageInfo->Name ) == 0
  2212. ))
  2213. {
  2214. break;
  2215. }
  2216. clusterPackageInfo = clusterPackageInfo->Next;
  2217. }
  2218. if ( clusterPackageInfo == NULL ) {
  2219. ClRtlLogPrint(LOG_CRITICAL,
  2220. "[ClMsg] Unable to find matching security package for %1!ws!.\n",
  2221. packageInfo.PackageInfo->Name);
  2222. (*SecurityFuncs->FreeContextBuffer)( packageInfo.PackageInfo );
  2223. Status = SEC_E_SECPKG_NOT_FOUND;
  2224. goto error_exit;
  2225. }
  2226. (*SecurityFuncs->FreeContextBuffer)( packageInfo.PackageInfo );
  2227. Status = ClMsgEstablishSecurityContext(NmJoinSequence,
  2228. EstablishingNodeId,
  2229. SecurityRoleClusterMember,
  2230. clusterPackageInfo);
  2231. }
  2232. if ( !NT_SUCCESS( Status ) &&
  2233. VALID_SSPI_HANDLE( SecurityData->Inbound)) {
  2234. (*SecurityFuncs->DeleteSecurityContext)( &SecurityData->Inbound );
  2235. INVALIDATE_SSPI_HANDLE( SecurityData->Inbound );
  2236. }
  2237. if (joinerNode != NULL) {
  2238. NmDereferenceJoinerNode(joinerNode);
  2239. }
  2240. error_exit:
  2241. LeaveCriticalSection( &SecContextLock );
  2242. *ServerStatus = Status;
  2243. return ERROR_SUCCESS;
  2244. } // s_MmRpcEstablishSecurityContext
  2245. error_status_t
  2246. s_MmRpcDeleteSecurityContext(
  2247. IN handle_t IDL_handle,
  2248. DWORD NodeId
  2249. )
  2250. /*++
  2251. Routine Description:
  2252. Server side of the RPC interface for clearing a security context
  2253. Arguments:
  2254. IDL_handle - RPC binding handle, not used.
  2255. NodeId - Node ID of client wishing to tear down this context
  2256. Return Value:
  2257. ERROR_SUCCESS
  2258. --*/
  2259. {
  2260. PCLUSTER_SECURITY_DATA SecurityData;
  2261. if ( NodeId >= ClusterMinNodeId && NodeId <= NmMaxNodeId ) {
  2262. ClRtlLogPrint(LOG_NOISE,
  2263. "[ClMsg] Deleting security contexts for node %1!u!.\n",
  2264. NodeId);
  2265. SecurityData = &SecurityCtxtData[ INT_NODE( NodeId )];
  2266. EnterCriticalSection( &SecContextLock );
  2267. if ( VALID_SSPI_HANDLE( SecurityData->Inbound)) {
  2268. (*SecurityFuncs->DeleteSecurityContext)( &SecurityData->Inbound);
  2269. INVALIDATE_SSPI_HANDLE( SecurityData->Inbound );
  2270. }
  2271. if ( VALID_SSPI_HANDLE( SecurityData->Outbound)) {
  2272. (*SecurityFuncs->DeleteSecurityContext)( &SecurityData->Outbound);
  2273. INVALIDATE_SSPI_HANDLE( SecurityData->Outbound );
  2274. }
  2275. SecurityData->OutboundStable = TRUE;
  2276. SecurityData->InboundStable = TRUE;
  2277. LeaveCriticalSection( &SecContextLock );
  2278. }
  2279. return ERROR_SUCCESS;
  2280. } // s_MmRpcDeleteSecurityContext
  2281. DWORD
  2282. ClSend(
  2283. DWORD targetnode,
  2284. LPCSTR buffer,
  2285. DWORD length,
  2286. DWORD timeout
  2287. )
  2288. {
  2289. /* This sends the given message to the designated node, and receives
  2290. an acknowledgement from the target to confirm good receipt. This
  2291. function blocks until the msg is delivered to the target CM.
  2292. The target node may not be Up at the time.
  2293. The function will fail if the message is not acknowledged by the
  2294. target node within <timeout> ms. <timeout> = -1 implies BLOCKING.
  2295. Errors:
  2296. xxx No path to node; node went down.
  2297. xxx Timeout
  2298. */
  2299. DWORD status=RPC_S_OK;
  2300. ClRtlLogPrint(LOG_NOISE,
  2301. "[ClMsg] send to node %1!u!\n",
  2302. targetnode
  2303. );
  2304. if (targetnode != NmLocalNodeId) {
  2305. CL_ASSERT(Session[targetnode] != NULL);
  2306. NmStartRpc(targetnode);
  2307. status = MmRpcMsgSend(
  2308. Session[targetnode],
  2309. buffer,
  2310. length);
  2311. NmEndRpc(targetnode);
  2312. if (status != ERROR_SUCCESS) {
  2313. if (status == RPC_S_CALL_FAILED_DNE) {
  2314. //
  2315. // Try again since the first call to a restarted RPC server
  2316. // will fail.
  2317. //
  2318. NmStartRpc(targetnode);
  2319. status = MmRpcMsgSend(
  2320. Session[targetnode],
  2321. buffer,
  2322. length
  2323. );
  2324. NmEndRpc(targetnode);
  2325. if (status != ERROR_SUCCESS) {
  2326. ClRtlLogPrint(LOG_UNUSUAL,
  2327. "[ClMsg] send failed, status %1!u!\n",
  2328. status
  2329. );
  2330. }
  2331. }
  2332. }
  2333. if(status != RPC_S_OK) {
  2334. NmDumpRpcExtErrorInfo(status);
  2335. }
  2336. }
  2337. else {
  2338. MMDiag( (LPCSTR)buffer, sizeof(rgp_msgbuf), &length /* in/out */ );
  2339. status = ERROR_SUCCESS;
  2340. }
  2341. return(status);
  2342. } // ClSend
  2343. error_status_t
  2344. s_MmRpcMsgSend(
  2345. IN handle_t IDL_handle,
  2346. IN const UCHAR *buffer,
  2347. IN DWORD length
  2348. )
  2349. /*++
  2350. Routine Description:
  2351. Server side of the RPC interface for unacknowledge messages.
  2352. Arguments:
  2353. IDL_handle - RPC binding handle, not used.
  2354. buffer - Supplies a pointer to the message data.
  2355. length - Supplies the length of the message data.
  2356. Return Value:
  2357. ERROR_SUCCESS
  2358. --*/
  2359. {
  2360. //
  2361. // Dispatch the message.
  2362. //
  2363. MMDiag( (LPCSTR)buffer, sizeof(rgp_msgbuf), &length /* in/out */ );
  2364. return(ERROR_SUCCESS);
  2365. } // s_MmRpcMsgSend
  2366. VOID
  2367. ClMsgBanishNode(
  2368. IN CL_NODE_ID BanishedNodeId
  2369. )
  2370. /*
  2371. RPC to all the other cluster members that the specified node
  2372. is banished. It must rejoin the cluster in order to participate
  2373. in cluster activity
  2374. */
  2375. {
  2376. DWORD node;
  2377. DWORD Status;
  2378. node_t InternalNodeId;
  2379. for (node = ClusterMinNodeId; node <= NmMaxNodeId; ++node ) {
  2380. //
  2381. // don't send this message to:
  2382. // 1) us
  2383. // 2) the banished node
  2384. // 3) any other node we have marked as banished
  2385. // 4) any node not part of the cluster
  2386. //
  2387. InternalNodeId = INT_NODE( node );
  2388. if ( node != NmLocalNodeId &&
  2389. node != BanishedNodeId &&
  2390. !ClusterMember(
  2391. rgp->OS_specific_control.Banished,
  2392. InternalNodeId
  2393. ) &&
  2394. ClusterMember( rgp->outerscreen, InternalNodeId ))
  2395. {
  2396. Status = MmRpcBanishNode( Session[node], BanishedNodeId );
  2397. if( Status != ERROR_SUCCESS ) {
  2398. ClRtlLogPrint(LOG_UNUSUAL,
  2399. "[ClMsg] Node %1!u! failed request to banish node %2!u!, status %3!u!\n",
  2400. node, BanishedNodeId, Status
  2401. );
  2402. }
  2403. }
  2404. }
  2405. }
  2406. error_status_t
  2407. s_MmRpcBanishNode(
  2408. IN handle_t IDL_handle,
  2409. IN DWORD BanishedNodeId
  2410. )
  2411. {
  2412. RGP_LOCK;
  2413. if ( !ClusterMember (
  2414. rgp->outerscreen,
  2415. INT_NODE(BanishedNodeId) )
  2416. )
  2417. {
  2418. int perturbed = rgp_is_perturbed();
  2419. RGP_UNLOCK;
  2420. if (perturbed) {
  2421. ClRtlLogPrint(LOG_UNUSUAL,
  2422. "[MM] s_MmRpcBanishNode: %1!u!, banishing is already in progress.\n",
  2423. BanishedNodeId
  2424. );
  2425. } else {
  2426. ClRtlLogPrint(LOG_UNUSUAL,
  2427. "[MM] s_MmRpcBanishNode: %1!u! is already banished.\n",
  2428. BanishedNodeId
  2429. );
  2430. }
  2431. return MM_OK;
  2432. }
  2433. rgp_event_handler( RGP_EVT_BANISH_NODE, (node_t) BanishedNodeId );
  2434. RGP_UNLOCK;
  2435. return ERROR_SUCCESS;
  2436. } // s_MmRpcBanishNode
  2437. /************************************************************************
  2438. *
  2439. * MMiNodeDownCallback
  2440. * ===================
  2441. *
  2442. * Description:
  2443. *
  2444. * This Membership Manager internal routine is registered with the
  2445. * OS-independent portion of the regroup engine to get called when
  2446. * a node is declared down. This routine will then call the "real"
  2447. * callback routine which was registered with the MMInit call.
  2448. *
  2449. * Parameters:
  2450. *
  2451. * failed_nodes
  2452. * bitmask of the nodes that failed.
  2453. *
  2454. * Returns:
  2455. *
  2456. * none
  2457. *
  2458. ************************************************************************/
  2459. void
  2460. MMiNodeDownCallback(
  2461. IN cluster_t failed_nodes
  2462. )
  2463. {
  2464. BITSET bitset;
  2465. node_t i;
  2466. //
  2467. // Translate cluster_t into Bitset
  2468. // and call NodesDownCallback
  2469. //
  2470. BitsetInit(bitset);
  2471. for ( i=0; i < (node_t) rgp->num_nodes; i++)
  2472. {
  2473. if ( ClusterMember(failed_nodes, i) ) {
  2474. BitsetAdd(bitset, EXT_NODE(i));
  2475. }
  2476. }
  2477. //
  2478. // [Future] - Leave the binding handle in place so we can send back
  2479. // poison packets. Reinstate the delete when we have a
  2480. // real response mechanism.
  2481. //
  2482. // ClMsgDeleteNodeBinding(nodeId);
  2483. if ( rgp->OS_specific_control.NodesDownCallback != RGP_NULL_PTR ) {
  2484. (*(rgp->OS_specific_control.NodesDownCallback))( bitset );
  2485. }
  2486. return;
  2487. }