Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1494 lines
38 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. cnpmisc.c
  5. Abstract:
  6. Miscellaneous routines for the Cluster Network Protocol.
  7. Author:
  8. Mike Massa (mikemas) January 24, 1997
  9. Revision History:
  10. Who When What
  11. -------- -------- ----------------------------------------------
  12. mikemas 01-24-97 created
  13. Notes:
  14. --*/
  15. #include "precomp.h"
  16. #pragma hdrstop
  17. #include "cnpmisc.tmh"
  18. #include <tdiinfo.h>
  19. #include <tcpinfo.h>
  20. #include <fipsapi.h>
  21. #include <sspi.h>
  22. //
  23. // Local function prototypes
  24. //
  25. NTSTATUS
  26. CnpRestartDeviceControl (
  27. IN PDEVICE_OBJECT DeviceObject,
  28. IN PIRP Irp,
  29. IN PVOID Context
  30. );
  31. #ifdef ALLOC_PRAGMA
  32. //
  33. // All of this code is pageable.
  34. //
  35. #pragma alloc_text(PAGE, CnpTdiSetEventHandler)
  36. #pragma alloc_text(PAGE, CnpIssueDeviceControl)
  37. #endif // ALLOC_PRAGMA
  38. NTSTATUS
  39. CnpRestartDeviceControl (
  40. IN PDEVICE_OBJECT DeviceObject,
  41. IN PIRP Irp,
  42. IN PVOID Context
  43. )
  44. {
  45. PBOOLEAN reuseIrp = (PBOOLEAN) Context;
  46. //
  47. // If there was an MDL in the IRP, free it and reset the pointer to
  48. // NULL. The IO system can't handle a nonpaged pool MDL being freed
  49. // in an IRP, which is why we do it here.
  50. //
  51. if ( Irp->MdlAddress != NULL ) {
  52. IoFreeMdl( Irp->MdlAddress );
  53. Irp->MdlAddress = NULL;
  54. }
  55. //
  56. // Mark the IRP pending, if necessary.
  57. //
  58. if (Irp->PendingReturned) {
  59. IoMarkIrpPending(Irp);
  60. }
  61. //
  62. // If we are reusing a client IRP, tell the I/O manager not to
  63. // halt I/O completion processing immediately.
  64. //
  65. if (*reuseIrp) {
  66. if (Irp->UserIosb != NULL) {
  67. *(Irp->UserIosb) = Irp->IoStatus;
  68. }
  69. if (Irp->UserEvent != NULL) {
  70. KeSetEvent(Irp->UserEvent, IO_NO_INCREMENT, FALSE);
  71. }
  72. return STATUS_MORE_PROCESSING_REQUIRED;
  73. } else {
  74. return STATUS_SUCCESS;
  75. }
  76. } // CnpRestartDeviceControl
  77. NTSTATUS
  78. CnpIssueDeviceControl (
  79. IN PFILE_OBJECT FileObject,
  80. IN PDEVICE_OBJECT DeviceObject,
  81. IN PVOID IrpParameters,
  82. IN ULONG IrpParametersLength,
  83. IN PVOID MdlBuffer,
  84. IN ULONG MdlBufferLength,
  85. IN UCHAR MinorFunction,
  86. IN PIRP ClientIrp OPTIONAL
  87. )
  88. /*++
  89. Routine Description:
  90. Issues a device control request to a TDI provider and waits for the
  91. request to complete.
  92. Arguments:
  93. FileObject - a pointer to the file object corresponding to a TDI
  94. handle
  95. DeviceObject - a pointer to the device object corresponding to the
  96. FileObject.
  97. IrpParameters - information to write to the parameters section of the
  98. stack location of the IRP.
  99. IrpParametersLength - length of the parameter information. Cannot be
  100. greater than 16.
  101. MdlBuffer - if non-NULL, a buffer of nonpaged pool to be mapped
  102. into an MDL and placed in the MdlAddress field of the IRP.
  103. MdlBufferLength - the size of the buffer pointed to by MdlBuffer.
  104. MinorFunction - the minor function code for the request.
  105. ClientIrp - client IRP that may be reusable for this ioctl
  106. Return Value:
  107. NTSTATUS -- Indicates the status of the request.
  108. --*/
  109. {
  110. NTSTATUS status = STATUS_SUCCESS;
  111. PIRP irp;
  112. PIO_STACK_LOCATION irpSp;
  113. KEVENT event;
  114. IO_STATUS_BLOCK ioStatusBlock;
  115. PDEVICE_OBJECT deviceObject;
  116. PMDL mdl;
  117. KPROCESSOR_MODE clientRequestorMode;
  118. PKEVENT clientUserEvent;
  119. PIO_STATUS_BLOCK clientIosb;
  120. PMDL clientMdl;
  121. BOOLEAN reuseIrp = FALSE;
  122. PAGED_CODE( );
  123. //
  124. // Initialize the kernel event that will signal I/O completion.
  125. //
  126. KeInitializeEvent( &event, SynchronizationEvent, FALSE );
  127. //
  128. // If there is a ClientIrp available, check if it has sufficient
  129. // stack locations.
  130. //
  131. if (ClientIrp != NULL
  132. && CnpIsIrpStackSufficient(ClientIrp, DeviceObject)) {
  133. //
  134. // Reuse the client IRP rather than allocating a new one.
  135. //
  136. reuseIrp = TRUE;
  137. irp = ClientIrp;
  138. //
  139. // Save state from client IRP
  140. //
  141. clientRequestorMode = irp->RequestorMode;
  142. clientUserEvent = irp->UserEvent;
  143. clientIosb = irp->UserIosb;
  144. clientMdl = irp->MdlAddress;
  145. } else {
  146. //
  147. // Reference the passed in file object. This is necessary because
  148. // the IO completion routine dereferences it.
  149. //
  150. ObReferenceObject( FileObject );
  151. //
  152. // Set the file object event to a non-signaled state.
  153. //
  154. (VOID) KeResetEvent( &FileObject->Event );
  155. //
  156. // Attempt to allocate and initialize the I/O Request Packet (IRP)
  157. // for this operation.
  158. //
  159. irp = IoAllocateIrp( (DeviceObject)->StackSize, TRUE );
  160. if ( irp == NULL ) {
  161. ObDereferenceObject( FileObject );
  162. return STATUS_INSUFFICIENT_RESOURCES;
  163. }
  164. //
  165. // Fill in the service independent parameters in the IRP.
  166. //
  167. irp->Flags = (LONG)IRP_SYNCHRONOUS_API;
  168. irp->PendingReturned = FALSE;
  169. irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
  170. irp->AssociatedIrp.SystemBuffer = NULL;
  171. irp->UserBuffer = NULL;
  172. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  173. irp->Tail.Overlay.OriginalFileObject = FileObject;
  174. irp->Tail.Overlay.AuxiliaryBuffer = NULL;
  175. //
  176. // Queue the IRP to the thread.
  177. //
  178. IoEnqueueIrp( irp );
  179. }
  180. //
  181. // If an MDL buffer was specified, get an MDL, map the buffer,
  182. // and place the MDL pointer in the IRP.
  183. //
  184. if ( MdlBuffer != NULL ) {
  185. mdl = IoAllocateMdl(
  186. MdlBuffer,
  187. MdlBufferLength,
  188. FALSE,
  189. FALSE,
  190. irp
  191. );
  192. if ( mdl == NULL ) {
  193. if (!reuseIrp) {
  194. IoFreeIrp( irp );
  195. ObDereferenceObject( FileObject );
  196. } else {
  197. irp->MdlAddress = clientMdl;
  198. }
  199. return STATUS_INSUFFICIENT_RESOURCES;
  200. }
  201. MmBuildMdlForNonPagedPool( mdl );
  202. } else {
  203. irp->MdlAddress = NULL;
  204. }
  205. irp->RequestorMode = KernelMode;
  206. irp->UserIosb = &ioStatusBlock;
  207. irp->UserEvent = &event;
  208. //
  209. // Put the file object pointer in the stack location.
  210. //
  211. irpSp = IoGetNextIrpStackLocation( irp );
  212. irpSp->FileObject = FileObject;
  213. irpSp->DeviceObject = DeviceObject;
  214. //
  215. // Fill in the service-dependent parameters for the request.
  216. //
  217. CnAssert( IrpParametersLength <= sizeof(irpSp->Parameters) );
  218. RtlCopyMemory( &irpSp->Parameters, IrpParameters, IrpParametersLength );
  219. irpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  220. irpSp->MinorFunction = MinorFunction;
  221. //
  222. // Set up a completion routine which we'll use to free the MDL
  223. // allocated previously.
  224. //
  225. IoSetCompletionRoutine(
  226. irp,
  227. CnpRestartDeviceControl,
  228. (PVOID) &reuseIrp,
  229. TRUE,
  230. TRUE,
  231. TRUE
  232. );
  233. status = IoCallDriver( DeviceObject, irp );
  234. //
  235. // If necessary, wait for the I/O to complete.
  236. //
  237. if ( status == STATUS_PENDING ) {
  238. KeWaitForSingleObject(
  239. (PVOID)&event,
  240. UserRequest,
  241. KernelMode,
  242. FALSE,
  243. NULL
  244. );
  245. }
  246. //
  247. // If the request was successfully queued, get the final I/O status.
  248. //
  249. if ( NT_SUCCESS(status) ) {
  250. status = ioStatusBlock.Status;
  251. }
  252. //
  253. // Before returning, restore the client IRP
  254. //
  255. if (reuseIrp) {
  256. irp->RequestorMode = clientRequestorMode;
  257. irp->UserIosb = clientIosb;
  258. irp->UserEvent = clientUserEvent;
  259. irp->MdlAddress = clientMdl;
  260. }
  261. return status;
  262. } // CnpIssueDeviceControl
  263. NTSTATUS
  264. CnpTdiSetEventHandler(
  265. IN PFILE_OBJECT FileObject,
  266. IN PDEVICE_OBJECT DeviceObject,
  267. IN ULONG EventType,
  268. IN PVOID EventHandler,
  269. IN PVOID EventContext,
  270. IN PIRP ClientIrp OPTIONAL
  271. )
  272. /*++
  273. Routine Description:
  274. Sets up a TDI indication handler on a connection or address object
  275. (depending on the file handle). This is done synchronously, which
  276. shouldn't usually be an issue since TDI providers can usually complete
  277. indication handler setups immediately.
  278. Arguments:
  279. FileObject - a pointer to the file object for an open connection or
  280. address object.
  281. DeviceObject - a pointer to the device object associated with the
  282. file object.
  283. EventType - the event for which the indication handler should be
  284. called.
  285. EventHandler - the routine to call when tghe specified event occurs.
  286. EventContext - context which is passed to the indication routine.
  287. ClientIrp - client IRP that may be passed to CnpIssueDeviceControl
  288. for reuse
  289. Return Value:
  290. NTSTATUS -- Indicates the status of the request.
  291. --*/
  292. {
  293. TDI_REQUEST_KERNEL_SET_EVENT parameters;
  294. NTSTATUS status;
  295. PAGED_CODE( );
  296. parameters.EventType = EventType;
  297. parameters.EventHandler = EventHandler;
  298. parameters.EventContext = EventContext;
  299. status = CnpIssueDeviceControl(
  300. FileObject,
  301. DeviceObject,
  302. &parameters,
  303. sizeof(parameters),
  304. NULL,
  305. 0,
  306. TDI_SET_EVENT_HANDLER,
  307. ClientIrp
  308. );
  309. return(status);
  310. } // CnpTdiSetEventHandler
  311. NTSTATUS
  312. CnpTdiErrorHandler(
  313. IN PVOID TdiEventContext,
  314. IN NTSTATUS Status
  315. )
  316. {
  317. return(STATUS_SUCCESS);
  318. } // CnpTdiErrorHandler
  319. VOID
  320. CnpAttachSystemProcess(
  321. VOID
  322. )
  323. /*++
  324. Routine Description:
  325. Attach to the system process, as determined during DriverEntry
  326. and stored in CnSystemProcess.
  327. Arguments:
  328. None.
  329. Return value:
  330. None.
  331. Notes:
  332. Must be followed by a call to CnpDetachSystemProcess.
  333. Implemented in this module due to header conflicts with
  334. ntddk.h.
  335. --*/
  336. {
  337. KeAttachProcess(CnSystemProcess);
  338. return;
  339. } // CnpAttachSystemProcess
  340. VOID
  341. CnpDetachSystemProcess(
  342. VOID
  343. )
  344. /*++
  345. Routine Description:
  346. Detach from the system process.
  347. Arguments:
  348. None.
  349. Return value:
  350. None.
  351. Notes:
  352. Must be preceded by a call to CnpDetachSystemProcess.
  353. Implemented in this module due to header conflicts with
  354. ntddk.h.
  355. --*/
  356. {
  357. KeDetachProcess();
  358. return;
  359. } // CnpDetachSystemProcess
  360. NTSTATUS
  361. CnpOpenDevice(
  362. IN LPWSTR DeviceName,
  363. OUT HANDLE *Handle
  364. )
  365. /*++
  366. Routine Description:
  367. Opens a handle to DeviceName. Since no EaBuffer is specified,
  368. CnpOpenDevice opens a control channel for TDI transports.
  369. Arguments:
  370. DeviceName - device to open
  371. Handle - resulting handle, NULL on failure
  372. Return Value:
  373. Status of ZwCreateFile
  374. Notes:
  375. Specifies OBJ_KERNEL_HANDLE, meaning that the resulting
  376. handle is only valid in kernel-mode. This routine
  377. cannot be called to obtain a handle that will be
  378. exported to user-mode.
  379. --*/
  380. {
  381. UNICODE_STRING nameString;
  382. OBJECT_ATTRIBUTES objectAttributes;
  383. IO_STATUS_BLOCK iosb;
  384. NTSTATUS status;
  385. *Handle = (HANDLE) NULL;
  386. RtlInitUnicodeString(&nameString, DeviceName);
  387. InitializeObjectAttributes(
  388. &objectAttributes,
  389. &nameString,
  390. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  391. (HANDLE) NULL,
  392. (PSECURITY_DESCRIPTOR) NULL
  393. );
  394. status = ZwCreateFile(
  395. Handle,
  396. SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
  397. &objectAttributes,
  398. &iosb,
  399. NULL,
  400. FILE_ATTRIBUTE_NORMAL,
  401. FILE_SHARE_READ | FILE_SHARE_WRITE,
  402. FILE_OPEN_IF,
  403. 0,
  404. NULL,
  405. 0
  406. );
  407. if (!NT_SUCCESS(status)) {
  408. IF_CNDBG(CN_DEBUG_OPEN) {
  409. CNPRINT(("[Clusnet] Failed to open device %S, status %lx\n",
  410. DeviceName, status));
  411. }
  412. *Handle = NULL;
  413. }
  414. return(status);
  415. } // CnpOpenDevice
  416. NTSTATUS
  417. CnpZwDeviceControl(
  418. IN HANDLE Handle,
  419. IN ULONG IoControlCode,
  420. IN PVOID InputBuffer,
  421. IN ULONG InputBufferLength,
  422. IN PVOID OutputBuffer,
  423. IN ULONG OutputBufferLength
  424. )
  425. {
  426. NTSTATUS status = STATUS_SUCCESS;
  427. IO_STATUS_BLOCK iosb;
  428. HANDLE event;
  429. PAGED_CODE();
  430. status = ZwCreateEvent( &event,
  431. EVENT_ALL_ACCESS,
  432. NULL,
  433. SynchronizationEvent,
  434. FALSE );
  435. if (NT_SUCCESS(status)) {
  436. status = ZwDeviceIoControlFile(
  437. Handle,
  438. event,
  439. NULL,
  440. NULL,
  441. &iosb,
  442. IoControlCode,
  443. InputBuffer,
  444. InputBufferLength,
  445. OutputBuffer,
  446. OutputBufferLength
  447. );
  448. if (status == STATUS_PENDING) {
  449. status = ZwWaitForSingleObject( event, FALSE, NULL );
  450. CnAssert( status == STATUS_SUCCESS );
  451. status = iosb.Status;
  452. }
  453. ZwClose( event );
  454. }
  455. return(status);
  456. } // CnpZwDeviceControl
  457. #define TCP_SET_INFO_EX_BUFFER_PREALLOCSIZE 16
  458. #define TCP_SET_INFO_EX_PREALLOCSIZE \
  459. (FIELD_OFFSET(TCP_REQUEST_SET_INFORMATION_EX, Buffer) \
  460. + TCP_SET_INFO_EX_BUFFER_PREALLOCSIZE \
  461. )
  462. NTSTATUS
  463. CnpSetTcpInfoEx(
  464. IN HANDLE Handle,
  465. IN ULONG Entity,
  466. IN ULONG Class,
  467. IN ULONG Type,
  468. IN ULONG Id,
  469. IN PVOID Value,
  470. IN ULONG ValueLength
  471. )
  472. {
  473. NTSTATUS status;
  474. PTCP_REQUEST_SET_INFORMATION_EX setInfoEx;
  475. UCHAR infoBuf[TCP_SET_INFO_EX_PREALLOCSIZE]={0};
  476. //
  477. // Check if we need to dynamically allocate.
  478. //
  479. if (ValueLength > TCP_SET_INFO_EX_BUFFER_PREALLOCSIZE) {
  480. setInfoEx = CnAllocatePool(
  481. FIELD_OFFSET(TCP_REQUEST_SET_INFORMATION_EX, Buffer)
  482. + ValueLength
  483. );
  484. if (setInfoEx == NULL) {
  485. return(STATUS_INSUFFICIENT_RESOURCES);
  486. }
  487. RtlZeroMemory(
  488. setInfoEx,
  489. FIELD_OFFSET(TCP_REQUEST_SET_INFORMATION_EX, Buffer) + ValueLength
  490. );
  491. } else {
  492. setInfoEx = (PTCP_REQUEST_SET_INFORMATION_EX)&infoBuf[0];
  493. }
  494. setInfoEx->ID.toi_entity.tei_entity = Entity;
  495. setInfoEx->ID.toi_entity.tei_instance = 0;
  496. setInfoEx->ID.toi_class = Class;
  497. setInfoEx->ID.toi_type = Type;
  498. setInfoEx->ID.toi_id = Id;
  499. setInfoEx->BufferSize = ValueLength;
  500. RtlCopyMemory(setInfoEx->Buffer, Value, ValueLength);
  501. status = CnpZwDeviceControl(
  502. Handle,
  503. IOCTL_TCP_SET_INFORMATION_EX,
  504. setInfoEx,
  505. FIELD_OFFSET(TCP_REQUEST_SET_INFORMATION_EX, Buffer)
  506. + ValueLength,
  507. NULL,
  508. 0
  509. );
  510. //
  511. // Free the buffer, if dynamically allocated
  512. //
  513. if (setInfoEx != (PTCP_REQUEST_SET_INFORMATION_EX)&infoBuf[0]) {
  514. CnFreePool(setInfoEx);
  515. }
  516. return(status);
  517. } // CnpSetTcpInfoEx
  518. NTSTATUS
  519. CnpMakeSignature(
  520. IN PSecBufferDesc Data,
  521. IN DESTable * DesTable,
  522. IN PVOID SigBuffer, OPTIONAL
  523. IN ULONG SigBufferLength, OPTIONAL
  524. OUT PSecBuffer * SigSecBuffer, OPTIONAL
  525. OUT ULONG * SigLen OPTIONAL
  526. )
  527. /*++
  528. Routine Description:
  529. Builds a signature for Data.
  530. Arguments:
  531. Data - data to be signed, packaged in a SecBufferDesc. All
  532. SecBuffers in Data should be of type SECBUFFER_DATA
  533. except exactly one which has type SECBUFFER_TOKEN.
  534. Other buffers will be ignored.
  535. DESTable - DES table containing encryption/decryption keys
  536. SigBuffer - Buffer in which to place completed signature. If NULL,
  537. signature is written into signature secbuffer (has
  538. type SECBUFFER_TOKEN in Data).
  539. SigBufferLength - length of buffer at SigBuffer, if provided
  540. SigSecBuffer - If non-NULL, returns pointer to signature secbuffer
  541. from Data.
  542. SigLen - on success, contains length of signature written
  543. on SEC_E_BUFFER_TOO_SMALL, contains required signature length
  544. undefined otherwise
  545. Return value:
  546. SEC_E_OK if successful.
  547. SEC_E_SECPKG_NOT_FOUND if the security buffer version is wrong.
  548. SEC_E_BUFFER_TOO_SMALL if SigBufferLength is too small.
  549. SEC_E_INVALID_TOKEN if Data is a misformed SecBuffer.
  550. --*/
  551. {
  552. A_SHA_CTX shaCtxt;
  553. UCHAR hashBuffer[CX_SIGNATURE_LENGTH] = { 0 };
  554. ULONG hashSize;
  555. ULONG bufIndex;
  556. PSecBuffer sigSecBuffer = NULL;
  557. PSecBuffer curBuffer;
  558. PUCHAR curBlock;
  559. PUCHAR encryptedHashBuffer;
  560. ULONG status;
  561. //
  562. // Verify the version.
  563. //
  564. if (Data->ulVersion != SECBUFFER_VERSION) {
  565. status = SEC_E_SECPKG_NOT_FOUND;
  566. goto error_exit;
  567. }
  568. //
  569. // Verify that the provided sig buffer is big enough.
  570. //
  571. if (SigBuffer != NULL && SigBufferLength < CX_SIGNATURE_LENGTH) {
  572. status = SEC_E_BUFFER_TOO_SMALL;
  573. goto error_exit;
  574. }
  575. //
  576. // Initialize the SHA context.
  577. //
  578. CxFipsFunctionTable.FipsSHAInit(&shaCtxt);
  579. //
  580. // Hash the data.
  581. //
  582. for (bufIndex = 0, curBuffer = &(Data->pBuffers[bufIndex]);
  583. bufIndex < Data->cBuffers;
  584. bufIndex++, curBuffer++) {
  585. //
  586. // Process this buffer according to its type.
  587. //
  588. if (curBuffer->BufferType == SECBUFFER_DATA) {
  589. //
  590. // Hash this buffer.
  591. //
  592. CxFipsFunctionTable.FipsSHAUpdate(
  593. &shaCtxt,
  594. (PUCHAR) curBuffer->pvBuffer,
  595. curBuffer->cbBuffer
  596. );
  597. } else if (curBuffer->BufferType == SECBUFFER_TOKEN) {
  598. if (sigSecBuffer != NULL) {
  599. status = SEC_E_INVALID_TOKEN;
  600. goto error_exit;
  601. } else {
  602. sigSecBuffer = curBuffer;
  603. //
  604. // Verify that the signature buffer is big enough.
  605. //
  606. if (sigSecBuffer->cbBuffer < A_SHA_DIGEST_LEN) {
  607. *SigLen = CX_SIGNATURE_LENGTH;
  608. status = SEC_E_BUFFER_TOO_SMALL;
  609. goto error_exit;
  610. }
  611. //
  612. // Set the output buffer.
  613. //
  614. if (SigBuffer == NULL) {
  615. encryptedHashBuffer = sigSecBuffer->pvBuffer;
  616. } else {
  617. encryptedHashBuffer = SigBuffer;
  618. }
  619. }
  620. }
  621. }
  622. //
  623. // Verify that we found a buffer for the signature.
  624. //
  625. if (sigSecBuffer == NULL) {
  626. status = SEC_E_INVALID_TOKEN;
  627. goto error_exit;
  628. }
  629. //
  630. // Complete the hash.
  631. //
  632. CxFipsFunctionTable.FipsSHAFinal(&shaCtxt, hashBuffer);
  633. //
  634. // Encrypt the hash one DES block at a time.
  635. //
  636. for (bufIndex = 0;
  637. bufIndex < CX_SIGNATURE_LENGTH;
  638. bufIndex += DES_BLOCKLEN) {
  639. CxFipsFunctionTable.FipsDes(
  640. &(encryptedHashBuffer[bufIndex]),
  641. &(hashBuffer[bufIndex]),
  642. DesTable,
  643. ENCRYPT
  644. );
  645. }
  646. if (SigSecBuffer != NULL) {
  647. *SigSecBuffer = sigSecBuffer;
  648. }
  649. if (SigLen != NULL) {
  650. *SigLen = CX_SIGNATURE_LENGTH;
  651. }
  652. status = SEC_E_OK;
  653. error_exit:
  654. return(status);
  655. } // CnpMakeSignature
  656. NTSTATUS
  657. CnpVerifySignature(
  658. IN PSecBufferDesc Data,
  659. IN DESTable * DesTable
  660. )
  661. /*++
  662. Routine Description:
  663. Verifies a signature for data.
  664. Arguments:
  665. Data - data to be verified, packaged in a SecBufferDesc. All
  666. SecBuffers in Data should be of type SECBUFFER_DATA
  667. except exactly one which has type SECBUFFER_TOKEN.
  668. Other buffers will be ignored.
  669. DESTable - DES table containing encryption/decryption keys
  670. Return value:
  671. SEC_E_OK if the signature is correct.
  672. SEC_E_SECPKG_NOT_FOUND if the security buffer version is wrong.
  673. SEC_E_INVALID_TOKEN if Data is a misformed SecBuffer.
  674. SEC_E_MESSAGE_ALTERED if signature is incorrect (including if it
  675. is the wrong length).
  676. --*/
  677. {
  678. UCHAR encryptedHashBuffer[CX_SIGNATURE_LENGTH];
  679. PSecBuffer sigBuffer = NULL;
  680. ULONG status;
  681. status = CnpMakeSignature(
  682. Data,
  683. DesTable,
  684. encryptedHashBuffer,
  685. sizeof(encryptedHashBuffer),
  686. &sigBuffer,
  687. NULL
  688. );
  689. if (status == STATUS_SUCCESS) {
  690. //
  691. // Compare the generated signature to the provided signature.
  692. //
  693. if (RtlCompareMemory(
  694. encryptedHashBuffer,
  695. sigBuffer->pvBuffer,
  696. sigBuffer->cbBuffer
  697. ) != sigBuffer->cbBuffer) {
  698. status = SEC_E_MESSAGE_ALTERED;
  699. } else {
  700. status = SEC_E_OK;
  701. }
  702. }
  703. return(status);
  704. } // CnpVerifySignature
  705. NTSTATUS
  706. CnpSignMulticastMessage(
  707. IN PCNP_SEND_REQUEST SendRequest,
  708. IN PMDL DataMdl,
  709. IN OUT CL_NETWORK_ID * NetworkId,
  710. OUT ULONG * SigDataLen OPTIONAL
  711. )
  712. /*++
  713. Routine Description:
  714. Sign a message.
  715. If NetworkId is not ClusterAnyNetworkId, the mcast group
  716. field must be set (and already referenced) in the SendRequest.
  717. This is the group that will be used to send the packet.
  718. Arguments:
  719. SendRequest - send request, used to locate the upper protocol
  720. header to sign, as well as the signature buffer.
  721. DataMdl - data to sign
  722. NetworkId - IN: network on which to send the message, or
  723. ClusterAnyNetworkId if it should be chosen
  724. OUT: network id chosen to send packet
  725. SigDataLen - OUT (OPTIONAL): number of bytes occupied in
  726. message by signature data and signature
  727. --*/
  728. {
  729. NTSTATUS status;
  730. PCNP_NETWORK network;
  731. PCNP_MULTICAST_GROUP mcastGroup;
  732. BOOLEAN mcastGroupReferenced = FALSE;
  733. CNP_HEADER UNALIGNED * cnpHeader;
  734. CNP_SIGNATURE UNALIGNED * cnpSig;
  735. SecBufferDesc sigDescriptor;
  736. SecBuffer sigSecBufferPrealloc[4];
  737. PSecBuffer sigSecBuffer = NULL;
  738. ULONG secBufferCount;
  739. ULONG sigLen;
  740. PMDL mdl;
  741. PSecBuffer curBuffer;
  742. CnAssert(SendRequest != NULL);
  743. CnAssert(((CNP_HEADER UNALIGNED *)SendRequest->CnpHeader)->Version ==
  744. CNP_VERSION_MULTICAST);
  745. //
  746. // Determine which network to use.
  747. //
  748. if (*NetworkId != ClusterAnyNetworkId) {
  749. mcastGroup = SendRequest->McastGroup;
  750. CnAssert(mcastGroup != NULL);
  751. } else {
  752. network = CnpGetBestMulticastNetwork();
  753. if (network == NULL) {
  754. CnTrace(CNP_SEND_ERROR, CnpMcastGetBestNetwork,
  755. "[CNP] Failed to find best multicast network."
  756. );
  757. status = STATUS_NETWORK_UNREACHABLE;
  758. goto error_exit;
  759. }
  760. //
  761. // Get the network id and mcast group before releasing
  762. // the network lock.
  763. //
  764. *NetworkId = network->Id;
  765. mcastGroup = network->CurrentMcastGroup;
  766. if (mcastGroup == NULL) {
  767. CnTrace(CNP_SEND_ERROR, CnpMcastGroupNull,
  768. "[CNP] Best multicast network %u has null "
  769. "multicast group.",
  770. network->Id
  771. );
  772. CnReleaseLock(&(network->Lock), network->Irql);
  773. status = STATUS_NETWORK_UNREACHABLE;
  774. goto error_exit;
  775. }
  776. CnpReferenceMulticastGroup(mcastGroup);
  777. mcastGroupReferenced = TRUE;
  778. CnReleaseLock(&(network->Lock), network->Irql);
  779. }
  780. CnAssert(mcastGroup->SignatureLength <= CX_SIGNATURE_LENGTH);
  781. //
  782. // Determine how many sig sec buffers we will need.
  783. // The common case is four: one for a header,
  784. // one for the data, one for the salt, and one for
  785. // the signature. We prealloc sig buffers on the
  786. // stack for the common case, but we dynamically
  787. // allocate if needed (e.g. if the data is a chain
  788. // of MDLs).
  789. //
  790. secBufferCount = 3;
  791. for (mdl = DataMdl; mdl != NULL; mdl = mdl->Next) {
  792. secBufferCount++;
  793. }
  794. //
  795. // Allocate the sig sec buffers.
  796. //
  797. if (secBufferCount <= 4) {
  798. sigSecBuffer = &sigSecBufferPrealloc[0];
  799. } else {
  800. sigSecBuffer = CnAllocatePool(
  801. secBufferCount * sizeof(SecBuffer)
  802. );
  803. if (sigSecBuffer == NULL) {
  804. status = STATUS_INSUFFICIENT_RESOURCES;
  805. goto error_exit;
  806. }
  807. }
  808. //
  809. // Prepare the descriptor for the message and signature.
  810. //
  811. sigDescriptor.cBuffers = secBufferCount;
  812. sigDescriptor.pBuffers = sigSecBuffer;
  813. sigDescriptor.ulVersion = SECBUFFER_VERSION;
  814. curBuffer = sigSecBuffer;
  815. //
  816. // Header.
  817. //
  818. if (SendRequest->UpperProtocolHeader != NULL) {
  819. CnAssert(SendRequest->UpperProtocolHeaderLength > 0);
  820. curBuffer->BufferType = SECBUFFER_DATA;
  821. curBuffer->cbBuffer = SendRequest->UpperProtocolHeaderLength;
  822. curBuffer->pvBuffer = SendRequest->UpperProtocolHeader;
  823. curBuffer++;
  824. }
  825. //
  826. // The payload provided by our client.
  827. //
  828. for (mdl = DataMdl; mdl != NULL; mdl = mdl->Next) {
  829. curBuffer->BufferType = SECBUFFER_DATA;
  830. curBuffer->cbBuffer = MmGetMdlByteCount(mdl);
  831. curBuffer->pvBuffer = MmGetMdlVirtualAddress(mdl);
  832. curBuffer++;
  833. }
  834. //
  835. // The salt.
  836. //
  837. curBuffer->BufferType = SECBUFFER_DATA;
  838. curBuffer->cbBuffer = mcastGroup->SaltLength;
  839. curBuffer->pvBuffer = mcastGroup->Salt;
  840. curBuffer++;
  841. //
  842. // The Signature.
  843. //
  844. cnpHeader = (CNP_HEADER UNALIGNED *)(SendRequest->CnpHeader);
  845. cnpSig = (CNP_SIGNATURE UNALIGNED *)(cnpHeader + 1);
  846. curBuffer->BufferType = SECBUFFER_TOKEN;
  847. curBuffer->pvBuffer = cnpSig->SigBuffer;
  848. curBuffer->cbBuffer = CX_SIGNATURE_LENGTH;
  849. status = CnpMakeSignature(
  850. &sigDescriptor,
  851. &(mcastGroup->DesTable),
  852. NULL,
  853. 0,
  854. NULL,
  855. &sigLen
  856. );
  857. if (status == STATUS_SUCCESS && sigLen <= CX_SIGNATURE_LENGTH) {
  858. //
  859. // Fill in the CNP signature data.
  860. //
  861. cnpSig->PayloadOffset = (USHORT) CNP_SIG_LENGTH(CX_SIGNATURE_LENGTH);
  862. cnpSig->Version = CNP_SIG_VERSION_1;
  863. cnpSig->NetworkId = *NetworkId;
  864. cnpSig->ClusterNetworkBrand = mcastGroup->McastNetworkBrand;
  865. cnpSig->SigBufferLen = (USHORT) sigLen;
  866. } else {
  867. IF_CNDBG(CN_DEBUG_CNPSEND) {
  868. CNPRINT(("[CNP] MakeSignature failed or returned "
  869. "an unexpected length, status %x, "
  870. "expected length %d, returned length %d.\n",
  871. status, CX_SIGNATURE_LENGTH, sigLen));
  872. }
  873. CnTrace(CNP_SEND_ERROR, CnpMcastMakeSigFailed,
  874. "[CNP] MakeSignature failed or returned "
  875. "an unexpected length, status %!status!, "
  876. "expected length %d, returned length %d.",
  877. status, CX_SIGNATURE_LENGTH, sigLen
  878. );
  879. status = STATUS_CLUSTER_NO_SECURITY_CONTEXT;
  880. }
  881. if (SigDataLen != NULL) {
  882. *SigDataLen = cnpSig->PayloadOffset;
  883. }
  884. SendRequest->McastGroup = mcastGroup;
  885. error_exit:
  886. if (sigSecBuffer != NULL &&
  887. sigSecBuffer != &sigSecBufferPrealloc[0]) {
  888. CnFreePool(sigSecBuffer);
  889. sigSecBuffer = NULL;
  890. }
  891. if (status != STATUS_SUCCESS && mcastGroupReferenced) {
  892. CnAssert(mcastGroup != NULL);
  893. CnpDereferenceMulticastGroup(mcastGroup);
  894. mcastGroupReferenced = FALSE;
  895. }
  896. return(status);
  897. } // CnpSignMulticastMessage
  898. NTSTATUS
  899. CnpVerifyMulticastMessage(
  900. IN PCNP_NETWORK Network,
  901. IN PVOID Tsdu,
  902. IN ULONG TsduLength,
  903. IN ULONG ExpectedPayload,
  904. OUT ULONG * BytesTaken,
  905. OUT BOOLEAN * CurrentGroup
  906. )
  907. /*++
  908. Routine Description:
  909. Verify a message.
  910. Arguments:
  911. Network - network on which message arrived
  912. Tsdu - points to protocol header
  913. TsduLength - length of TSDU, including signature data
  914. ExpectedPayload - expected payload after signature data
  915. BytesTaken - OUT: quantity of data consumed by signature
  916. CurrentGroup - OUT: whether signature matched current
  917. multicast group.
  918. Return value:
  919. SEC_E_OK or error status.
  920. --*/
  921. {
  922. NTSTATUS status;
  923. CNP_SIGNATURE UNALIGNED * cnpSig = Tsdu;
  924. ULONG sigBufBytes = 0;
  925. ULONG sigPayOffBytes = 0;
  926. PVOID payload;
  927. ULONG payloadLength;
  928. PCNP_MULTICAST_GROUP currMcastGroup = NULL;
  929. PCNP_MULTICAST_GROUP prevMcastGroup = NULL;
  930. SecBufferDesc sigDescriptor;
  931. SecBuffer sigSecBufferPrealloc[3];
  932. PSecBuffer sigSecBuffer = NULL;
  933. PSecBuffer curBuffer;
  934. //
  935. // Verify that the signature is present. Do not
  936. // dereference any signature data until we know
  937. // it's there.
  938. //
  939. if (
  940. // Verify that signature header data is present.
  941. (TsduLength < (ULONG)CNP_SIGHDR_LENGTH) ||
  942. // Verify that signature buffer is present
  943. (TsduLength < (sigBufBytes = CNP_SIG_LENGTH(cnpSig->SigBufferLen))) ||
  944. // Verify that the payload offset is reasonable
  945. (TsduLength <= (sigPayOffBytes = cnpSig->PayloadOffset)) ||
  946. // Verify that the expected payload is present
  947. (TsduLength - sigPayOffBytes != ExpectedPayload)
  948. ) {
  949. IF_CNDBG(CN_DEBUG_CNPRECV) {
  950. CNPRINT(("[CNP] Cannot verify mcast packet with "
  951. "mis-sized payload: TsduLength %u, required "
  952. "sig hdr %u, sig buffer %u, "
  953. "payload offset %u, expected payload %u.\n",
  954. TsduLength,
  955. CNP_SIGHDR_LENGTH,
  956. sigBufBytes,
  957. sigPayOffBytes,
  958. ExpectedPayload
  959. ));
  960. }
  961. CnTrace(CNP_RECV_ERROR, CnpTraceReceiveTooSmall,
  962. "[CNP] Cannot verify mcast packet with "
  963. "undersized payload: TsduLength %u, required "
  964. "sig hdr %u, sig buffer %u, "
  965. "payload offset %u, expected payload %u.\n",
  966. TsduLength,
  967. CNP_SIGHDR_LENGTH,
  968. sigBufBytes,
  969. sigPayOffBytes,
  970. ExpectedPayload
  971. );
  972. //
  973. // Drop it.
  974. //
  975. status = SEC_E_INCOMPLETE_MESSAGE;
  976. goto error_exit;
  977. }
  978. //
  979. // Verify that the signature protocol is understood.
  980. //
  981. if (cnpSig->Version != CNP_SIG_VERSION_1) {
  982. IF_CNDBG(CN_DEBUG_CNPRECV) {
  983. CNPRINT(("[CNP] Cannot verify mcast packet with "
  984. "unknown signature version: %u.\n",
  985. cnpSig->Version
  986. ));
  987. }
  988. CnTrace(
  989. CNP_RECV_ERROR, CnpTraceRecvUnknownSigVersion,
  990. "[CNP] Cannot verify mcast packet with "
  991. "unknown signature version: %u.",
  992. cnpSig->Version
  993. );
  994. //
  995. // Drop it.
  996. //
  997. status = SEC_E_BAD_PKGID;
  998. goto error_exit;
  999. }
  1000. //
  1001. // Locate the payload following the signature data.
  1002. //
  1003. payload = (PVOID)((PUCHAR)(cnpSig) + sigPayOffBytes);
  1004. payloadLength = TsduLength - sigPayOffBytes;
  1005. //
  1006. // Lock the network object and reference the
  1007. // multicast groups.
  1008. //
  1009. CnAcquireLock(&(Network->Lock), &(Network->Irql));
  1010. currMcastGroup = Network->CurrentMcastGroup;
  1011. if (currMcastGroup != NULL) {
  1012. CnpReferenceMulticastGroup(currMcastGroup);
  1013. }
  1014. prevMcastGroup = Network->CurrentMcastGroup;
  1015. if (prevMcastGroup != NULL) {
  1016. CnpReferenceMulticastGroup(prevMcastGroup);
  1017. }
  1018. CnReleaseLock(&(Network->Lock), Network->Irql);
  1019. //
  1020. // Verify that the packet network id matches the
  1021. // local network object.
  1022. //
  1023. if (cnpSig->NetworkId != Network->Id) {
  1024. IF_CNDBG(CN_DEBUG_CNPRECV) {
  1025. CNPRINT(("[CNP] Mcast packet has bad network "
  1026. "id: found %d, expected %d.\n",
  1027. cnpSig->NetworkId,
  1028. Network->Id
  1029. ));
  1030. }
  1031. CnTrace(
  1032. CNP_RECV_ERROR, CnpTraceReceiveBadNetworkId,
  1033. "[CNP] Mcast packet has bad network id: "
  1034. "found %d, expected %d.",
  1035. cnpSig->NetworkId,
  1036. Network->Id
  1037. );
  1038. //
  1039. // Drop it.
  1040. //
  1041. status = SEC_E_TARGET_UNKNOWN;
  1042. goto error_exit;
  1043. }
  1044. //
  1045. // Verify that the brand matches either the current or
  1046. // previous multicast group.
  1047. //
  1048. if (currMcastGroup != NULL &&
  1049. cnpSig->ClusterNetworkBrand != currMcastGroup->McastNetworkBrand) {
  1050. // can't use currMcastGroup
  1051. CnpDereferenceMulticastGroup(currMcastGroup);
  1052. currMcastGroup = NULL;
  1053. }
  1054. if (prevMcastGroup != NULL &&
  1055. cnpSig->ClusterNetworkBrand != prevMcastGroup->McastNetworkBrand) {
  1056. // can't use prevMcastGroup
  1057. CnpDereferenceMulticastGroup(prevMcastGroup);
  1058. prevMcastGroup = NULL;
  1059. }
  1060. if (currMcastGroup == NULL && prevMcastGroup == NULL) {
  1061. IF_CNDBG(CN_DEBUG_CNPRECV) {
  1062. CNPRINT(("[CNP] Recv'd mcast packet with brand %x, "
  1063. "but no matching multicast groups.\n",
  1064. cnpSig->ClusterNetworkBrand
  1065. ));
  1066. }
  1067. CnTrace(
  1068. CNP_RECV_ERROR, CnpTraceReceiveBadBrand,
  1069. "[CNP] Recv'd mcast packet with brand %x, "
  1070. "but no matching multicast groups.",
  1071. cnpSig->ClusterNetworkBrand
  1072. );
  1073. //
  1074. // Drop it.
  1075. //
  1076. status = SEC_E_TARGET_UNKNOWN;
  1077. goto error_exit;
  1078. }
  1079. //
  1080. // Build the signature descriptor for verification. The bytes
  1081. // that were signed (and hence need to be verified) include
  1082. // the payload data, starting after the signature, and the salt.
  1083. //
  1084. sigSecBuffer = &sigSecBufferPrealloc[0];
  1085. curBuffer = sigSecBuffer;
  1086. sigDescriptor.cBuffers = 2;
  1087. sigDescriptor.pBuffers = sigSecBuffer;
  1088. sigDescriptor.ulVersion = SECBUFFER_VERSION;
  1089. //
  1090. // Data.
  1091. //
  1092. if (payloadLength > 0) {
  1093. sigDescriptor.cBuffers = 3;
  1094. curBuffer->BufferType = SECBUFFER_DATA;
  1095. curBuffer->cbBuffer = payloadLength;
  1096. curBuffer->pvBuffer = payload;
  1097. curBuffer++;
  1098. }
  1099. //
  1100. // Signature.
  1101. //
  1102. curBuffer->BufferType = SECBUFFER_TOKEN;
  1103. curBuffer->cbBuffer = cnpSig->SigBufferLen;
  1104. curBuffer->pvBuffer = (PVOID)&(cnpSig->SigBuffer[0]);
  1105. curBuffer++;
  1106. /*CNPRINT(("[CNP] Verifying message of length %d with "
  1107. "sig of length %d.\n",
  1108. HeaderLength + payloadLength,
  1109. cnpSig->SigBufferLen));*/
  1110. //
  1111. // Try the current multicast group, and if necessary,
  1112. // the previous multicast group.
  1113. //
  1114. status = SEC_E_INVALID_TOKEN;
  1115. if (currMcastGroup != NULL) {
  1116. //
  1117. // Salt.
  1118. //
  1119. curBuffer->BufferType = SECBUFFER_DATA;
  1120. curBuffer->cbBuffer = currMcastGroup->SaltLength;
  1121. curBuffer->pvBuffer = currMcastGroup->Salt;
  1122. status = CnpVerifySignature(
  1123. &sigDescriptor,
  1124. &(currMcastGroup->DesTable)
  1125. );
  1126. if (status == SEC_E_OK && CurrentGroup != NULL) {
  1127. *CurrentGroup = TRUE;
  1128. }
  1129. }
  1130. if (status != SEC_E_OK && prevMcastGroup != NULL) {
  1131. curBuffer->cbBuffer = prevMcastGroup->SaltLength;
  1132. curBuffer->pvBuffer = prevMcastGroup->Salt;
  1133. status = CnpVerifySignature(
  1134. &sigDescriptor,
  1135. &(prevMcastGroup->DesTable)
  1136. );
  1137. if (status == SEC_E_OK && CurrentGroup != NULL) {
  1138. *CurrentGroup = FALSE;
  1139. }
  1140. }
  1141. if (status == SEC_E_OK) {
  1142. *BytesTaken = sigPayOffBytes;
  1143. }
  1144. error_exit:
  1145. if (currMcastGroup != NULL) {
  1146. CnpDereferenceMulticastGroup(currMcastGroup);
  1147. }
  1148. if (prevMcastGroup != NULL) {
  1149. CnpDereferenceMulticastGroup(prevMcastGroup);
  1150. }
  1151. CnVerifyCpuLockMask(
  1152. 0, // Required
  1153. 0xFFFFFFFF, // Forbidden
  1154. 0 // Maximum
  1155. );
  1156. return(status);
  1157. } // CnpVerifyMulticastMessage