Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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