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.

1928 lines
53 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. dispatch.c
  5. Abstract:
  6. Dispatch routines for the Cluster Network Driver.
  7. Author:
  8. Mike Massa (mikemas) January 3, 1997
  9. Revision History:
  10. Who When What
  11. -------- -------- ----------------------------------------------
  12. mikemas 01-03-97 created
  13. Notes:
  14. --*/
  15. #include "precomp.h"
  16. #pragma hdrstop
  17. #include "dispatch.tmh"
  18. #include <strsafe.h>
  19. //
  20. // Data
  21. //
  22. PCN_FSCONTEXT CnExclusiveChannel = NULL;
  23. //
  24. // Un-exported Prototypes
  25. //
  26. NTSYSAPI
  27. NTSTATUS
  28. NTAPI
  29. ZwOpenProcess (
  30. OUT PHANDLE ProcessHandle,
  31. IN ACCESS_MASK DesiredAccess,
  32. IN POBJECT_ATTRIBUTES ObjectAttributes,
  33. IN PCLIENT_ID ClientId OPTIONAL
  34. );
  35. //
  36. // Local Prototypes
  37. //
  38. FILE_FULL_EA_INFORMATION UNALIGNED *
  39. CnFindEA(
  40. PFILE_FULL_EA_INFORMATION StartEA,
  41. CHAR *TargetName,
  42. USHORT TargetNameLength
  43. );
  44. NTSTATUS
  45. CnCreate(
  46. IN PDEVICE_OBJECT DeviceObject,
  47. IN PIRP Irp,
  48. IN PIO_STACK_LOCATION IrpSp
  49. );
  50. NTSTATUS
  51. CnCleanup(
  52. IN PDEVICE_OBJECT DeviceObject,
  53. IN PIRP Irp,
  54. IN PIO_STACK_LOCATION IrpSp
  55. );
  56. NTSTATUS
  57. CnClose(
  58. IN PDEVICE_OBJECT DeviceObject,
  59. IN PIRP Irp,
  60. IN PIO_STACK_LOCATION IrpSp
  61. );
  62. NTSTATUS
  63. CnEnableShutdownOnClose(
  64. IN PIRP Irp
  65. );
  66. BOOLEAN
  67. CnPerformSecurityCheck(
  68. IN PIRP Irp,
  69. IN PIO_STACK_LOCATION IrpSp,
  70. OUT PNTSTATUS Status
  71. );
  72. //
  73. // Mark pageable code.
  74. //
  75. #ifdef ALLOC_PRAGMA
  76. #pragma alloc_text(PAGE, CnDispatchDeviceControl)
  77. #pragma alloc_text(PAGE, CnFindEA)
  78. #pragma alloc_text(PAGE, CnCreate)
  79. #pragma alloc_text(PAGE, CnEnableShutdownOnClose)
  80. #pragma alloc_text(PAGE, CnPerformSecurityCheck)
  81. #endif // ALLOC_PRAGMA
  82. //
  83. // Function definitions
  84. //
  85. VOID
  86. CnDereferenceFsContext(
  87. PCN_FSCONTEXT FsContext
  88. )
  89. {
  90. LONG newValue = InterlockedDecrement(&(FsContext->ReferenceCount));
  91. CnAssert(newValue >= 0);
  92. if (newValue != 0) {
  93. return;
  94. }
  95. //
  96. // Set the cleanup event.
  97. //
  98. KeSetEvent(&(FsContext->CleanupEvent), 0, FALSE);
  99. return;
  100. } // CnDereferenceFsContext
  101. NTSTATUS
  102. CnMarkRequestPending(
  103. PIRP Irp,
  104. PIO_STACK_LOCATION IrpSp,
  105. PDRIVER_CANCEL CancelRoutine
  106. )
  107. /*++
  108. Notes:
  109. Called with IoCancelSpinLock held.
  110. --*/
  111. {
  112. PCN_FSCONTEXT fsContext = (PCN_FSCONTEXT) IrpSp->FileObject->FsContext;
  113. CN_IRQL oldIrql;
  114. //
  115. // Set up for cancellation
  116. //
  117. CnAssert(Irp->CancelRoutine == NULL);
  118. if (!Irp->Cancel) {
  119. IoMarkIrpPending(Irp);
  120. IoSetCancelRoutine(Irp, CancelRoutine);
  121. CnReferenceFsContext(fsContext);
  122. IF_CNDBG(CN_DEBUG_IRP) {
  123. CNPRINT((
  124. "[Clusnet] Pending irp %p fileobj %p.\n",
  125. Irp,
  126. IrpSp->FileObject
  127. ));
  128. }
  129. return(STATUS_SUCCESS);
  130. }
  131. //
  132. // The IRP has already been cancelled.
  133. //
  134. IF_CNDBG(CN_DEBUG_IRP) {
  135. CNPRINT(("[Clusnet] irp %p already cancelled.\n", Irp));
  136. }
  137. return(STATUS_CANCELLED);
  138. } // CnPrepareIrpForCancel
  139. VOID
  140. CnCompletePendingRequest(
  141. IN PIRP Irp,
  142. IN NTSTATUS Status,
  143. IN ULONG BytesReturned
  144. )
  145. /*++
  146. Routine Description:
  147. Completes a pending request.
  148. Arguments:
  149. Irp - A pointer to the IRP for this request.
  150. Status - The final status of the request.
  151. BytesReturned - Bytes sent/received information.
  152. Return Value:
  153. None.
  154. Notes:
  155. Called with IoCancelSpinLock held. Lock Irql is stored in Irp->CancelIrql.
  156. Releases IoCancelSpinLock before returning.
  157. --*/
  158. {
  159. PIO_STACK_LOCATION irpSp;
  160. PCN_FSCONTEXT fsContext;
  161. irpSp = IoGetCurrentIrpStackLocation(Irp);
  162. fsContext = (PCN_FSCONTEXT) irpSp->FileObject->FsContext;
  163. IoSetCancelRoutine(Irp, NULL);
  164. CnDereferenceFsContext(fsContext);
  165. IF_CNDBG(CN_DEBUG_IRP) {
  166. CNPRINT((
  167. "[Clusnet] Completing irp %p fileobj %p, status %lx\n",
  168. Irp,
  169. irpSp->FileObject,
  170. Status
  171. ));
  172. }
  173. if (Irp->Cancel || fsContext->CancelIrps) {
  174. IF_CNDBG(CN_DEBUG_IRP) {
  175. CNPRINT(("[Clusnet] Completed irp %p was cancelled\n", Irp));
  176. }
  177. Status = (NTSTATUS) STATUS_CANCELLED;
  178. BytesReturned = 0;
  179. }
  180. CnReleaseCancelSpinLock(Irp->CancelIrql);
  181. Irp->IoStatus.Status = (NTSTATUS) Status;
  182. Irp->IoStatus.Information = BytesReturned;
  183. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  184. return;
  185. } // CnCompletePendingRequest
  186. PFILE_OBJECT
  187. CnBeginCancelRoutine(
  188. IN PIRP Irp
  189. )
  190. /*++
  191. Routine Description:
  192. Performs common bookkeeping for irp cancellation.
  193. Arguments:
  194. Irp - Pointer to I/O request packet
  195. Return Value:
  196. A pointer to the file object on which the irp was submitted.
  197. This value must be passed to CnEndCancelRequest().
  198. Notes:
  199. Called with cancel spinlock held.
  200. --*/
  201. {
  202. PIO_STACK_LOCATION irpSp;
  203. PCN_FSCONTEXT fsContext;
  204. NTSTATUS status = STATUS_SUCCESS;
  205. PFILE_OBJECT fileObject;
  206. CnAssert(Irp->Cancel);
  207. irpSp = IoGetCurrentIrpStackLocation(Irp);
  208. fileObject = irpSp->FileObject;
  209. fsContext = (PCN_FSCONTEXT) fileObject->FsContext;
  210. IoSetCancelRoutine(Irp, NULL);
  211. //
  212. // Add a reference so the object can't be closed while the cancel routine
  213. // is executing.
  214. //
  215. CnReferenceFsContext(fsContext);
  216. IF_CNDBG(CN_DEBUG_IRP) {
  217. CNPRINT((
  218. "[Clusnet] Cancelling irp %p fileobj %p\n",
  219. Irp,
  220. fileObject
  221. ));
  222. }
  223. return(fileObject);
  224. } // CnBeginCancelRoutine
  225. VOID
  226. CnEndCancelRoutine(
  227. PFILE_OBJECT FileObject
  228. )
  229. /*++
  230. Routine Description:
  231. Performs common bookkeeping for irp cancellation.
  232. Arguments:
  233. Return Value:
  234. Notes:
  235. Called with cancel spinlock held.
  236. --*/
  237. {
  238. PCN_FSCONTEXT fsContext = (PCN_FSCONTEXT) FileObject->FsContext;
  239. //
  240. // Remove the reference placed on the endpoint by the cancel routine.
  241. //
  242. CnDereferenceFsContext(fsContext);
  243. IF_CNDBG(CN_DEBUG_IRP) {
  244. CNPRINT((
  245. "[Clusnet] Finished cancelling, fileobj %p\n",
  246. FileObject
  247. ));
  248. }
  249. return;
  250. } // CnEndCancelRoutine
  251. NTSTATUS
  252. CnDispatchInternalDeviceControl(
  253. IN PDEVICE_OBJECT DeviceObject,
  254. IN PIRP Irp
  255. )
  256. /*++
  257. Routine Description:
  258. This is the dispatch routine for Internal Device Control IRPs.
  259. This is the hot path for kernel-mode TDI clients.
  260. Arguments:
  261. DeviceObject - Pointer to device object for target device
  262. Irp - Pointer to I/O request packet
  263. Return Value:
  264. An NT status code.
  265. --*/
  266. {
  267. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  268. NTSTATUS status = STATUS_SUCCESS;
  269. ULONG fileType = (ULONG)((ULONG_PTR)irpSp->FileObject->FsContext2);
  270. #if DBG
  271. KIRQL entryIrql = KeGetCurrentIrql();
  272. #endif // DBG
  273. Irp->IoStatus.Information = 0;
  274. if (DeviceObject == CdpDeviceObject) {
  275. if (fileType == TDI_TRANSPORT_ADDRESS_FILE) {
  276. if (irpSp->MinorFunction == TDI_SEND_DATAGRAM) {
  277. status = CxSendDatagram(Irp, irpSp);
  278. #if DBG
  279. CnAssert(entryIrql == KeGetCurrentIrql());
  280. #endif // DBG
  281. return(status);
  282. }
  283. else if (irpSp->MinorFunction == TDI_RECEIVE_DATAGRAM) {
  284. status = CxReceiveDatagram(Irp, irpSp);
  285. #if DBG
  286. CnAssert(entryIrql == KeGetCurrentIrql());
  287. #endif // DBG
  288. return(status);
  289. }
  290. else if (irpSp->MinorFunction == TDI_SET_EVENT_HANDLER) {
  291. status = CxSetEventHandler(Irp, irpSp);
  292. #if DBG
  293. CnAssert(entryIrql == KeGetCurrentIrql());
  294. #endif // DBG
  295. return(status);
  296. }
  297. //
  298. // Fall through to common code.
  299. //
  300. }
  301. //
  302. // These functions are common to all endpoint types.
  303. //
  304. switch(irpSp->MinorFunction) {
  305. case TDI_QUERY_INFORMATION:
  306. status = CxQueryInformation(Irp, irpSp);
  307. break;
  308. case TDI_SET_INFORMATION:
  309. case TDI_ACTION:
  310. CNPRINT((
  311. "[Clusnet] Call to unimplemented TDI function 0x%x\n",
  312. irpSp->MinorFunction
  313. ));
  314. status = STATUS_NOT_IMPLEMENTED;
  315. break;
  316. default:
  317. CNPRINT((
  318. "[Clusnet] Call to invalid TDI function 0x%x\n",
  319. irpSp->MinorFunction
  320. ));
  321. status = STATUS_INVALID_DEVICE_REQUEST;
  322. }
  323. }
  324. else {
  325. CNPRINT((
  326. "[Clusnet] Invalid internal device control function 0x%x on device %ws\n",
  327. irpSp->MinorFunction,
  328. DD_CLUSNET_DEVICE_NAME
  329. ));
  330. status = STATUS_INVALID_DEVICE_REQUEST;
  331. }
  332. Irp->IoStatus.Status = status;
  333. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  334. #if DBG
  335. CnAssert(entryIrql == KeGetCurrentIrql());
  336. #endif // DBG
  337. return(status);
  338. } // CnDispatchInternalDeviceControl
  339. NTSTATUS
  340. CnDispatchDeviceControl(
  341. IN PDEVICE_OBJECT DeviceObject,
  342. IN PIRP Irp
  343. )
  344. /*++
  345. Routine Description:
  346. This is the top-level dispatch routine for Device Control IRPs.
  347. Arguments:
  348. DeviceObject - Pointer to device object for target device
  349. Irp - Pointer to I/O request packet
  350. Return Value:
  351. An NT status code.
  352. Notes:
  353. This routine completes any IRPs for which the return code is not
  354. STATUS_PENDING.
  355. --*/
  356. {
  357. NTSTATUS status;
  358. CCHAR ioIncrement = IO_NO_INCREMENT;
  359. BOOLEAN resourceAcquired = FALSE;
  360. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  361. ULONG ioControlCode =
  362. irpSp->Parameters.DeviceIoControl.IoControlCode;
  363. ULONG fileType =
  364. (ULONG) ((ULONG_PTR) irpSp->FileObject->FsContext2);
  365. PAGED_CODE();
  366. //
  367. // Set this in advance. Any subsequent dispatch routine that cares
  368. // about it will modify it itself.
  369. //
  370. Irp->IoStatus.Information = 0;
  371. //
  372. // The following commands are valid on only TDI address objects.
  373. //
  374. if (ioControlCode == IOCTL_CX_IGNORE_NODE_STATE) {
  375. if (fileType == TDI_TRANSPORT_ADDRESS_FILE) {
  376. status = CxDispatchDeviceControl(Irp, irpSp);
  377. }
  378. else {
  379. //
  380. // Not handled. Return an error.
  381. //
  382. status = STATUS_INVALID_DEVICE_REQUEST;
  383. }
  384. goto complete_request;
  385. }
  386. //
  387. // No other commands are valid on TDI address objects.
  388. //
  389. if (fileType == TDI_TRANSPORT_ADDRESS_FILE) {
  390. //
  391. // Not handled. Return an error.
  392. //
  393. status = STATUS_INVALID_DEVICE_REQUEST;
  394. goto complete_request;
  395. }
  396. //
  397. // The remaining commands are valid for control channels.
  398. //
  399. CnAssert(fileType == TDI_CONTROL_CHANNEL_FILE);
  400. //
  401. // The following set of commands affect only this file object and
  402. // can be issued at any time. We do not need to hold the CnResource
  403. // in order to process them. Nor do we need to be in the initialized.
  404. // state.
  405. //
  406. switch(ioControlCode) {
  407. case IOCTL_CLUSNET_SET_EVENT_MASK:
  408. {
  409. PCN_FSCONTEXT fsContext = irpSp->FileObject->FsContext;
  410. PCLUSNET_SET_EVENT_MASK_REQUEST request;
  411. ULONG requestSize;
  412. request = (PCLUSNET_SET_EVENT_MASK_REQUEST)
  413. Irp->AssociatedIrp.SystemBuffer;
  414. requestSize =
  415. irpSp->Parameters.DeviceIoControl.InputBufferLength;
  416. if (requestSize >= sizeof(CLUSNET_SET_EVENT_MASK_REQUEST))
  417. {
  418. //
  419. // Kernel mode callers must supply a callback.
  420. // User mode callers must not.
  421. //
  422. if ( !( (Irp->RequestorMode == KernelMode) &&
  423. (request->KmodeEventCallback == NULL)
  424. )
  425. &&
  426. !( (Irp->RequestorMode == UserMode) &&
  427. (request->KmodeEventCallback != NULL)
  428. )
  429. )
  430. {
  431. status = CnSetEventMask( fsContext, request );
  432. }
  433. else {
  434. status = STATUS_INVALID_PARAMETER;
  435. }
  436. }
  437. else {
  438. status = STATUS_INVALID_PARAMETER;
  439. }
  440. }
  441. goto complete_request;
  442. case IOCTL_CLUSNET_GET_NEXT_EVENT:
  443. {
  444. PCLUSNET_EVENT_RESPONSE response;
  445. ULONG responseSize;
  446. responseSize =
  447. irpSp->Parameters.DeviceIoControl.OutputBufferLength;
  448. if ( (responseSize < sizeof(CLUSNET_EVENT_RESPONSE))) {
  449. status = STATUS_INVALID_PARAMETER;
  450. }
  451. else {
  452. status = CnGetNextEvent( Irp, irpSp );
  453. ioIncrement = IO_NETWORK_INCREMENT;
  454. }
  455. }
  456. goto complete_request;
  457. case IOCTL_CLUSNET_SET_IAMALIVE_PARAM:
  458. {
  459. PCLUSNET_SET_IAMALIVE_PARAM_REQUEST request;
  460. ULONG requestSize;
  461. request = (PCLUSNET_SET_IAMALIVE_PARAM_REQUEST)
  462. Irp->AssociatedIrp.SystemBuffer;
  463. requestSize = irpSp->Parameters.DeviceIoControl.InputBufferLength;
  464. if ((requestSize < sizeof(CLUSNET_SET_IAMALIVE_PARAM_REQUEST)) ||
  465. (request->Action >= ClussvcHangActionMax)) {
  466. status = STATUS_INVALID_PARAMETER;
  467. }
  468. else {
  469. PEPROCESS process = PsGetCurrentProcess();
  470. IF_CNDBG(CN_DEBUG_INIT) {
  471. CNPRINT((
  472. "[ClusNet] Set Clussvc to Clusnet Hb params: Timeout=%u(s) Action=%u\n",
  473. request->Timeout,
  474. (ULONG)request->Action
  475. ));
  476. }
  477. CnTrace(HBEAT_EVENT, HbTraceSetIamaliveParam,
  478. "[ClusNet] Set Clussvc to Clusnet Hb params: Timeout=%u(s) Action=%u\n",
  479. request->Timeout,
  480. (ULONG)request->Action
  481. );
  482. ClussvcClusnetHbTimeoutTicks = (request->Timeout * 1000)/HEART_BEAT_PERIOD;
  483. ClussvcClusnetHbTimeoutAction = request->Action;
  484. InterlockedExchange(&ClussvcClusnetHbTickCount, 0);
  485. // Save the timeout in seconds for the bugcheck parameter.
  486. ClussvcClusnetHbTimeoutSeconds = request->Timeout;
  487. //
  488. // Log a warning if the current process doesn't match the monitored
  489. // process (clussvc should set its own params).
  490. //
  491. if (process != ClussvcProcessObject) {
  492. IF_CNDBG(CN_DEBUG_INIT) {
  493. CNPRINT((
  494. "[ClusNet] Warning: process configuring hang detection "
  495. "parameters (%p) is not clussvc (%p).\n",
  496. process, ClussvcProcessObject
  497. ));
  498. }
  499. CnTrace(HBEAT_ERROR, HbTraceSetIamaliveParamProcMismatch,
  500. "[ClusNet] Warning: process configuring hang detection "
  501. "parameters (%p) is not clussvc (%p).\n",
  502. process, ClussvcProcessObject
  503. );
  504. }
  505. status = STATUS_SUCCESS;
  506. }
  507. }
  508. goto complete_request;
  509. case IOCTL_CLUSNET_IAMALIVE:
  510. {
  511. InterlockedExchange(&ClussvcClusnetHbTickCount, ClussvcClusnetHbTimeoutTicks);
  512. status = STATUS_SUCCESS;
  513. }
  514. goto complete_request;
  515. } // end of switch
  516. //
  517. // Not handled yet. Fall through.
  518. //
  519. if (ClusnetIsGeneralIoctl(ioControlCode)) {
  520. if (!ClusnetIsNTEIoctl(ioControlCode)) {
  521. //
  522. // The following commands require exclusive access to CnResource.
  523. //
  524. resourceAcquired = CnAcquireResourceExclusive(
  525. CnResource,
  526. TRUE
  527. );
  528. if (!resourceAcquired) {
  529. CnAssert(resourceAcquired == TRUE);
  530. status = STATUS_UNSUCCESSFUL;
  531. goto complete_request;
  532. }
  533. switch(ioControlCode) {
  534. case IOCTL_CLUSNET_INITIALIZE:
  535. if (CnState == CnStateShutdown) {
  536. PCLUSNET_INITIALIZE_REQUEST request;
  537. ULONG requestSize;
  538. request = (PCLUSNET_INITIALIZE_REQUEST)
  539. Irp->AssociatedIrp.SystemBuffer;
  540. requestSize =
  541. irpSp->Parameters.DeviceIoControl.InputBufferLength;
  542. if (requestSize < sizeof(CLUSNET_INITIALIZE_REQUEST)) {
  543. status = STATUS_INVALID_PARAMETER;
  544. }
  545. else {
  546. status = CnInitialize(
  547. request->LocalNodeId,
  548. request->MaxNodes
  549. );
  550. }
  551. }
  552. else {
  553. status = STATUS_INVALID_DEVICE_REQUEST;
  554. }
  555. goto complete_request;
  556. case IOCTL_CLUSNET_ENABLE_SHUTDOWN_ON_CLOSE:
  557. status = CnEnableShutdownOnClose(Irp);
  558. goto complete_request;
  559. case IOCTL_CLUSNET_DISABLE_SHUTDOWN_ON_CLOSE:
  560. {
  561. PCN_FSCONTEXT fsContext = irpSp->FileObject->FsContext;
  562. fsContext->ShutdownOnClose = FALSE;
  563. if ( ClussvcProcessHandle ) {
  564. CnCloseProcessHandle( &ClussvcProcessHandle );
  565. ClussvcProcessHandle = NULL;
  566. }
  567. status = STATUS_SUCCESS;
  568. }
  569. goto complete_request;
  570. case IOCTL_CLUSNET_HALT:
  571. status = CnShutdown();
  572. CnReleaseResourceForThread(
  573. CnResource,
  574. (ERESOURCE_THREAD) PsGetCurrentThread()
  575. );
  576. resourceAcquired = FALSE;
  577. //
  578. // Issue a Halt event. If clusdisk still has a handle
  579. // to clusnet, then it will release its reservations.
  580. //
  581. CnIssueEvent( ClusnetEventHalt, 0, 0 );
  582. goto complete_request;
  583. case IOCTL_CLUSNET_SHUTDOWN:
  584. status = CnShutdown();
  585. goto complete_request;
  586. case IOCTL_CLUSNET_SET_MEMORY_LOGGING:
  587. {
  588. PCLUSNET_SET_MEM_LOGGING_REQUEST request;
  589. ULONG requestSize;
  590. request = (PCLUSNET_SET_MEM_LOGGING_REQUEST)
  591. Irp->AssociatedIrp.SystemBuffer;
  592. requestSize =
  593. irpSp->Parameters.DeviceIoControl.InputBufferLength;
  594. if ( (requestSize < sizeof(CLUSNET_SET_MEM_LOGGING_REQUEST))) {
  595. status = STATUS_INVALID_PARAMETER;
  596. }
  597. else {
  598. status = CnSetMemLogging( request );
  599. }
  600. }
  601. goto complete_request;
  602. #if DBG
  603. case IOCTL_CLUSNET_SET_DEBUG_MASK:
  604. {
  605. PCLUSNET_SET_DEBUG_MASK_REQUEST request;
  606. ULONG requestSize;
  607. request = (PCLUSNET_SET_DEBUG_MASK_REQUEST)
  608. Irp->AssociatedIrp.SystemBuffer;
  609. requestSize =
  610. irpSp->Parameters.DeviceIoControl.InputBufferLength;
  611. if (requestSize < sizeof(CLUSNET_SET_DEBUG_MASK_REQUEST)) {
  612. status = STATUS_INVALID_PARAMETER;
  613. }
  614. else {
  615. CnDebug = request->DebugMask;
  616. status = STATUS_SUCCESS;
  617. }
  618. }
  619. goto complete_request;
  620. #endif // DBG
  621. } // end switch
  622. } else {
  623. //
  624. // The following commands are only valid if we are
  625. // in the initialized state. The resource is
  626. // acquired to start the operation in the proper
  627. // state; however, the dispatched routines are
  628. // reentrant, so the resource can be released before
  629. // the IRPs complete.
  630. //
  631. resourceAcquired = CnAcquireResourceShared(
  632. CnResource,
  633. TRUE
  634. );
  635. if (!resourceAcquired) {
  636. CnAssert(resourceAcquired == TRUE);
  637. status = STATUS_UNSUCCESSFUL;
  638. goto complete_request;
  639. }
  640. if (CnState != CnStateInitialized) {
  641. status = STATUS_DEVICE_NOT_READY;
  642. goto complete_request;
  643. }
  644. switch(ioControlCode) {
  645. case IOCTL_CLUSNET_ADD_NTE:
  646. status = IpaAddNTE(Irp, irpSp);
  647. goto complete_request;
  648. case IOCTL_CLUSNET_DELETE_NTE:
  649. status = IpaDeleteNTE(Irp, irpSp);
  650. goto complete_request;
  651. case IOCTL_CLUSNET_SET_NTE_ADDRESS:
  652. status = IpaSetNTEAddress(Irp, irpSp);
  653. goto complete_request;
  654. case IOCTL_CLUSNET_ADD_NBT_INTERFACE:
  655. {
  656. PNETBT_ADD_DEL_IF request;
  657. ULONG requestSize;
  658. PNETBT_ADD_DEL_IF response;
  659. ULONG responseSize;
  660. request = (PNETBT_ADD_DEL_IF)
  661. Irp->AssociatedIrp.SystemBuffer;
  662. response = (PNETBT_ADD_DEL_IF) request;
  663. requestSize =
  664. irpSp->Parameters.DeviceIoControl.InputBufferLength;
  665. responseSize =
  666. irpSp->Parameters.DeviceIoControl.OutputBufferLength;
  667. //
  668. // Validate the request and response buffers.
  669. //
  670. if (
  671. // request data structure
  672. (requestSize < sizeof(NETBT_ADD_DEL_IF)) ||
  673. // request device name must fit in request buffer
  674. (requestSize <
  675. (FIELD_OFFSET(NETBT_ADD_DEL_IF, IfName[0]) +
  676. request->Length)) ||
  677. // request device name must be null-terminated
  678. // StringCchLengthW will probe for NULL termination
  679. // up to the character count in the second
  680. // parameter. If there is no NULL termination
  681. // within that count, an error is returned.
  682. (StringCchLengthW(
  683. (LPCWSTR)&(request->IfName[0]),
  684. request->Length / sizeof(WCHAR),
  685. NULL
  686. ) != S_OK) ||
  687. // response data structure
  688. (responseSize < sizeof(NETBT_ADD_DEL_IF))
  689. )
  690. {
  691. status = STATUS_INVALID_PARAMETER;
  692. }
  693. else {
  694. status = NbtAddIf(
  695. request,
  696. requestSize,
  697. response,
  698. &responseSize
  699. );
  700. CnAssert(status != STATUS_PENDING);
  701. if (NT_SUCCESS(status)) {
  702. Irp->IoStatus.Information = responseSize;
  703. }
  704. }
  705. }
  706. goto complete_request;
  707. case IOCTL_CLUSNET_DEL_NBT_INTERFACE:
  708. {
  709. PNETBT_ADD_DEL_IF request;
  710. ULONG requestSize;
  711. request = (PNETBT_ADD_DEL_IF)
  712. Irp->AssociatedIrp.SystemBuffer;
  713. requestSize =
  714. irpSp->Parameters.DeviceIoControl.InputBufferLength;
  715. //
  716. // Validate the request buffer. There is no response
  717. // buffer.
  718. //
  719. if (
  720. // request data structure
  721. (requestSize < sizeof(NETBT_ADD_DEL_IF)) ||
  722. // request device name must fit in request buffer
  723. (requestSize <
  724. (FIELD_OFFSET(NETBT_ADD_DEL_IF, IfName[0]) +
  725. request->Length)) ||
  726. // request device name must be null-terminated
  727. // StringCchLengthW will probe for NULL termination
  728. // up to the character count in the second
  729. // parameter. If there is no NULL termination
  730. // within that count, an error is returned.
  731. (StringCchLengthW(
  732. (LPCWSTR)&(request->IfName[0]),
  733. request->Length / sizeof(WCHAR),
  734. NULL
  735. ) != S_OK)
  736. )
  737. {
  738. status = STATUS_INVALID_PARAMETER;
  739. }
  740. else {
  741. status = NbtDeleteIf(request, requestSize);
  742. CnAssert(status != STATUS_PENDING);
  743. }
  744. }
  745. goto complete_request;
  746. } // end switch
  747. }
  748. //
  749. // Not handled. Return an error.
  750. //
  751. status = STATUS_INVALID_DEVICE_REQUEST;
  752. goto complete_request;
  753. }
  754. else {
  755. //
  756. // The following commands require shared access to CnResource.
  757. // They are only valid in the initialized state.
  758. //
  759. resourceAcquired = CnAcquireResourceShared(CnResource, TRUE);
  760. if (!resourceAcquired) {
  761. CnAssert(resourceAcquired == TRUE);
  762. status = STATUS_UNSUCCESSFUL;
  763. goto complete_request;
  764. }
  765. if (CnState == CnStateInitialized) {
  766. if (ClusnetIsTransportIoctl(ioControlCode)) {
  767. status = CxDispatchDeviceControl(Irp, irpSp);
  768. }
  769. else {
  770. //
  771. // Not handled. Return an error.
  772. //
  773. status = STATUS_INVALID_DEVICE_REQUEST;
  774. }
  775. }
  776. else {
  777. //
  778. // We haven't been initialized yet. Return an error.
  779. //
  780. status = STATUS_DEVICE_NOT_READY;
  781. }
  782. }
  783. complete_request:
  784. if (resourceAcquired) {
  785. CnReleaseResourceForThread(
  786. CnResource,
  787. (ERESOURCE_THREAD) PsGetCurrentThread()
  788. );
  789. }
  790. if (status != STATUS_PENDING) {
  791. Irp->IoStatus.Status = status;
  792. IoCompleteRequest(Irp, ioIncrement);
  793. }
  794. return(status);
  795. } // CnDispatchDeviceControl
  796. NTSTATUS
  797. CnDispatch(
  798. IN PDEVICE_OBJECT DeviceObject,
  799. IN PIRP Irp
  800. )
  801. /*++
  802. Routine Description:
  803. This is the generic dispatch routine for the driver.
  804. Arguments:
  805. DeviceObject - Pointer to device object for target device
  806. Irp - Pointer to I/O request packet
  807. Return Value:
  808. An NT status code.
  809. --*/
  810. {
  811. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  812. NTSTATUS status = STATUS_SUCCESS;
  813. #if DBG
  814. KIRQL entryIrql = KeGetCurrentIrql();
  815. #endif // DBG
  816. PAGED_CODE();
  817. CnAssert(irpSp->MajorFunction != IRP_MJ_INTERNAL_DEVICE_CONTROL);
  818. switch (irpSp->MajorFunction) {
  819. case IRP_MJ_CREATE:
  820. status = CnCreate(DeviceObject, Irp, irpSp);
  821. break;
  822. case IRP_MJ_CLEANUP:
  823. status = CnCleanup(DeviceObject, Irp, irpSp);
  824. break;
  825. case IRP_MJ_CLOSE:
  826. status = CnClose(DeviceObject, Irp, irpSp);
  827. break;
  828. case IRP_MJ_SHUTDOWN:
  829. IF_CNDBG(CN_DEBUG_INIT) {
  830. CNPRINT(("[ClusNet] Processing shutdown notification...\n"));
  831. }
  832. {
  833. BOOLEAN acquired = CnAcquireResourceExclusive(
  834. CnResource,
  835. TRUE
  836. );
  837. CnAssert(acquired == TRUE);
  838. (VOID) CnShutdown();
  839. if (acquired) {
  840. CnReleaseResourceForThread(
  841. CnResource,
  842. (ERESOURCE_THREAD) PsGetCurrentThread()
  843. );
  844. }
  845. //
  846. // Issue a Halt event. If clusdisk still has a handle
  847. // to clusnet, then it will release its reservations
  848. //
  849. CnIssueEvent( ClusnetEventHalt, 0, 0 );
  850. status = STATUS_SUCCESS;
  851. }
  852. IF_CNDBG(CN_DEBUG_INIT) {
  853. CNPRINT(("[ClusNet] Shutdown processing complete.\n"));
  854. }
  855. break;
  856. default:
  857. IF_CNDBG(CN_DEBUG_IRP) {
  858. CNPRINT((
  859. "[ClusNet] Received IRP with unsupported "
  860. "major function 0x%lx\n",
  861. irpSp->MajorFunction
  862. ));
  863. }
  864. status = STATUS_INVALID_DEVICE_REQUEST;
  865. break;
  866. }
  867. CnAssert(status != STATUS_PENDING);
  868. Irp->IoStatus.Status = status;
  869. Irp->IoStatus.Information = 0;
  870. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  871. #if DBG
  872. CnAssert(entryIrql == KeGetCurrentIrql());
  873. #endif // DBG
  874. return(status);
  875. } // CnDispatch
  876. NTSTATUS
  877. CnCreate(
  878. IN PDEVICE_OBJECT DeviceObject,
  879. IN PIRP Irp,
  880. IN PIO_STACK_LOCATION IrpSp
  881. )
  882. /*++
  883. Routine Description:
  884. Handler for create IRPs.
  885. Arguments:
  886. DeviceObject - Pointer to the device object for this request.
  887. Irp - Pointer to I/O request packet
  888. Return Value:
  889. An NT status code.
  890. Notes:
  891. This routine never returns STATUS_PENDING.
  892. The calling routine must complete the IRP.
  893. --*/
  894. {
  895. PCN_FSCONTEXT fsContext;
  896. FILE_FULL_EA_INFORMATION *ea;
  897. FILE_FULL_EA_INFORMATION UNALIGNED *targetEA;
  898. NTSTATUS status;
  899. PAGED_CODE();
  900. //
  901. // Reject unathorized opens
  902. //
  903. if ( (IrpSp->FileObject->RelatedFileObject != NULL) ||
  904. (IrpSp->FileObject->FileName.Length != 0)
  905. )
  906. {
  907. return(STATUS_ACCESS_DENIED);
  908. }
  909. ea = (PFILE_FULL_EA_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
  910. if ((DeviceObject == CdpDeviceObject) && (ea != NULL)) {
  911. IF_CNDBG(CN_DEBUG_OPEN) {
  912. CNPRINT((
  913. "[ClusNet] Opening address object, file object %p\n",
  914. IrpSp->FileObject
  915. ));
  916. }
  917. //
  918. // Verify that the caller has access to open CDP sockets.
  919. //
  920. if (!CnPerformSecurityCheck(Irp, IrpSp, &status)) {
  921. IF_CNDBG(CN_DEBUG_OPEN) {
  922. CNPRINT((
  923. "[ClusNet] Failed CDP security check, error %lx\n",
  924. status
  925. ));
  926. }
  927. return(STATUS_ACCESS_DENIED);
  928. }
  929. //
  930. // This is the CDP device. This should be an address object open.
  931. //
  932. targetEA = CnFindEA(
  933. ea,
  934. TdiTransportAddress,
  935. TDI_TRANSPORT_ADDRESS_LENGTH
  936. );
  937. if (targetEA != NULL) {
  938. IrpSp->FileObject->FsContext2 = (PVOID)
  939. TDI_TRANSPORT_ADDRESS_FILE;
  940. //
  941. // Open an address object. This will also allocate the common
  942. // file object context structure.
  943. //
  944. status = CxOpenAddress(
  945. &fsContext,
  946. (TRANSPORT_ADDRESS UNALIGNED *)
  947. &(targetEA->EaName[targetEA->EaNameLength + 1]),
  948. targetEA->EaValueLength
  949. );
  950. }
  951. else {
  952. IF_CNDBG(CN_DEBUG_OPEN) {
  953. CNPRINT((
  954. "[ClusNet] No transport address in EA!\n"
  955. ));
  956. }
  957. status = STATUS_INVALID_PARAMETER;
  958. }
  959. }
  960. else {
  961. //
  962. // This is a control channel open.
  963. //
  964. IF_CNDBG(CN_DEBUG_OPEN) {
  965. IF_CNDBG(CN_DEBUG_OPEN) {
  966. CNPRINT((
  967. "[ClusNet] Opening control channel, file object %p\n",
  968. IrpSp->FileObject
  969. ));
  970. }
  971. }
  972. //
  973. // Allocate our common file object context structure.
  974. //
  975. fsContext = CnAllocatePool(sizeof(CN_FSCONTEXT));
  976. if (fsContext != NULL) {
  977. IrpSp->FileObject->FsContext2 = (PVOID) TDI_CONTROL_CHANNEL_FILE;
  978. CN_INIT_SIGNATURE(fsContext, CN_CONTROL_CHANNEL_SIG);
  979. //
  980. // Check the sharing flags. If this is an exclusive open, check
  981. // to make sure there isn't already an exclusive open outstanding.
  982. //
  983. if (IrpSp->Parameters.Create.ShareAccess == 0) {
  984. BOOLEAN acquired = CnAcquireResourceExclusive(
  985. CnResource,
  986. TRUE
  987. );
  988. CnAssert(acquired == TRUE);
  989. if (CnExclusiveChannel == NULL) {
  990. CnExclusiveChannel = fsContext;
  991. //
  992. // (Re)enable the halt processing mechanism.
  993. //
  994. CnEnableHaltProcessing();
  995. status = STATUS_SUCCESS;
  996. }
  997. else {
  998. CnFreePool(fsContext);
  999. status = STATUS_SHARING_VIOLATION;
  1000. }
  1001. if (acquired) {
  1002. CnReleaseResourceForThread(
  1003. CnResource,
  1004. (ERESOURCE_THREAD) PsGetCurrentThread()
  1005. );
  1006. }
  1007. }
  1008. else {
  1009. status = STATUS_SUCCESS;
  1010. }
  1011. }
  1012. else {
  1013. status = STATUS_INSUFFICIENT_RESOURCES;
  1014. }
  1015. }
  1016. if (status == STATUS_SUCCESS) {
  1017. IrpSp->FileObject->FsContext = fsContext;
  1018. fsContext->FileObject = IrpSp->FileObject;
  1019. fsContext->ReferenceCount = 1;
  1020. fsContext->CancelIrps = FALSE;
  1021. fsContext->ShutdownOnClose = FALSE;
  1022. KeInitializeEvent(
  1023. &(fsContext->CleanupEvent),
  1024. SynchronizationEvent,
  1025. FALSE
  1026. );
  1027. //
  1028. // init the Event list stuff. We use the empty list test on the
  1029. // Linkage field to see if this context block is already been linked
  1030. // to the event file object list
  1031. //
  1032. fsContext->EventMask = 0;
  1033. InitializeListHead( &fsContext->EventList );
  1034. InitializeListHead( &fsContext->Linkage );
  1035. fsContext->EventIrp = NULL;
  1036. }
  1037. return(status);
  1038. } // CnCreate
  1039. NTSTATUS
  1040. CnCleanup(
  1041. IN PDEVICE_OBJECT DeviceObject,
  1042. IN PIRP Irp,
  1043. IN PIO_STACK_LOCATION IrpSp
  1044. )
  1045. /*++
  1046. Routine Description:
  1047. Cancels all outstanding Irps on a device object and waits for them to be
  1048. completed before returning.
  1049. Arguments:
  1050. DeviceObject - Pointer to the device object on which the Irp was received.
  1051. Irp - Pointer to I/O request packet
  1052. IrpSp - Pointer to the current stack location in the Irp.
  1053. Return Value:
  1054. An NT status code.
  1055. Notes:
  1056. This routine may block.
  1057. This routine never returns STATUS_PENDING.
  1058. The calling routine must complete the IRP.
  1059. --*/
  1060. {
  1061. CN_IRQL oldIrql;
  1062. NTSTATUS status;
  1063. ULONG fileType =
  1064. (ULONG)((ULONG_PTR)IrpSp->FileObject->FsContext2);
  1065. PCN_FSCONTEXT fsContext = (PCN_FSCONTEXT) IrpSp->FileObject->FsContext;
  1066. PLIST_ENTRY EventEntry;
  1067. PIRP eventIrp;
  1068. if (fileType == TDI_TRANSPORT_ADDRESS_FILE) {
  1069. //
  1070. // This is an address object.
  1071. //
  1072. CnAssert(DeviceObject == CdpDeviceObject);
  1073. status = CxCloseAddress(fsContext);
  1074. }
  1075. else {
  1076. //
  1077. // This is a control channel.
  1078. //
  1079. CnAssert(fileType == TDI_CONTROL_CHANNEL_FILE);
  1080. //
  1081. // If this channel has a shutdown trigger enabled,
  1082. // shutdown the driver.
  1083. //
  1084. if (fsContext->ShutdownOnClose) {
  1085. BOOLEAN shutdownScheduled;
  1086. //
  1087. // Bug 303422: CnShutdown closes handles that were opened
  1088. // in the context of the system process. However, attaching
  1089. // to the system process during shutdown can cause a
  1090. // bugcheck under certain conditions. The only alternative
  1091. // is to defer executing of CnShutdown to a system worker
  1092. // thread.
  1093. //
  1094. // Rather than creating a new event object, leverage the
  1095. // cleanup event in the fscontext. It is reset before use
  1096. // below.
  1097. //
  1098. KeClearEvent(&(fsContext->CleanupEvent));
  1099. shutdownScheduled = CnHaltOperation(&(fsContext->CleanupEvent));
  1100. if (shutdownScheduled) {
  1101. status = KeWaitForSingleObject(
  1102. &(fsContext->CleanupEvent),
  1103. (Irp->RequestorMode == KernelMode
  1104. ? Executive : UserRequest),
  1105. KernelMode,
  1106. FALSE,
  1107. NULL
  1108. );
  1109. CnAssert(NT_SUCCESS(status));
  1110. status = STATUS_SUCCESS;
  1111. }
  1112. //
  1113. // issue a Halt event. If clusdisk still has a handle
  1114. // to clusnet, then it will release its reservations
  1115. //
  1116. CnIssueEvent( ClusnetEventHalt, 0, 0 );
  1117. }
  1118. //
  1119. // if this guy forgot to clear the event mask before
  1120. // closing the handle, do the appropriate cleanup
  1121. // now.
  1122. //
  1123. if ( fsContext->EventMask ) {
  1124. CLUSNET_SET_EVENT_MASK_REQUEST EventRequest;
  1125. EventRequest.EventMask = 0;
  1126. //
  1127. // cannot proceed if CnSetEventMask returns a timeout
  1128. // error. this indicates that the fsContext has not
  1129. // been removed from the EventFileHandles list because
  1130. // of lock starvation.
  1131. do {
  1132. status = CnSetEventMask( fsContext, &EventRequest );
  1133. } while ( status == STATUS_TIMEOUT );
  1134. CnAssert( status == STATUS_SUCCESS );
  1135. }
  1136. CnAcquireCancelSpinLock( &oldIrql );
  1137. CnAcquireLockAtDpc( &EventLock );
  1138. if ( fsContext->EventIrp != NULL ) {
  1139. eventIrp = fsContext->EventIrp;
  1140. fsContext->EventIrp = NULL;
  1141. CnReleaseLockFromDpc( &EventLock );
  1142. eventIrp->CancelIrql = oldIrql;
  1143. CnCompletePendingRequest(eventIrp, STATUS_CANCELLED, 0);
  1144. } else {
  1145. CnReleaseLockFromDpc( &EventLock );
  1146. CnReleaseCancelSpinLock( oldIrql );
  1147. }
  1148. }
  1149. //
  1150. // Remove the initial reference and wait for all pending work
  1151. // to complete.
  1152. //
  1153. fsContext->CancelIrps = TRUE;
  1154. KeResetEvent(&(fsContext->CleanupEvent));
  1155. CnDereferenceFsContext(fsContext);
  1156. IF_CNDBG(CN_DEBUG_CLEANUP) {
  1157. CNPRINT((
  1158. "[ClusNet] Waiting for completion of Irps on file object %p\n",
  1159. IrpSp->FileObject
  1160. ));
  1161. }
  1162. status = KeWaitForSingleObject(
  1163. &(fsContext->CleanupEvent),
  1164. (Irp->RequestorMode == KernelMode ? Executive : UserRequest),
  1165. KernelMode,
  1166. FALSE,
  1167. NULL
  1168. );
  1169. CnAssert(NT_SUCCESS(status));
  1170. status = STATUS_SUCCESS;
  1171. IF_CNDBG(CN_DEBUG_CLEANUP) {
  1172. CNPRINT((
  1173. "[Clusnet] Wait on file object %p finished\n",
  1174. IrpSp->FileObject
  1175. ));
  1176. }
  1177. return(status);
  1178. } // CnCleanup
  1179. NTSTATUS
  1180. CnClose(
  1181. IN PDEVICE_OBJECT DeviceObject,
  1182. IN PIRP Irp,
  1183. IN PIO_STACK_LOCATION IrpSp
  1184. )
  1185. /*++
  1186. Routine Description:
  1187. Dispatch routine for MJ_CLOSE IRPs. Performs final cleanup of the
  1188. open file object.
  1189. Arguments:
  1190. DeviceObject - Pointer to the device object on which the Irp was received.
  1191. Irp - Pointer to I/O request packet
  1192. IrpSp - Pointer to the current stack location in the Irp.
  1193. Return Value:
  1194. An NT status code.
  1195. Notes:
  1196. This routine never returns STATUS_PENDING.
  1197. The calling routine must complete the IRP.
  1198. --*/
  1199. {
  1200. BOOLEAN acquired;
  1201. PCN_FSCONTEXT fsContext = (PCN_FSCONTEXT) IrpSp->FileObject->FsContext;
  1202. ULONG fileType =
  1203. (ULONG)((ULONG_PTR)IrpSp->FileObject->FsContext2);
  1204. CnAssert(fsContext->ReferenceCount == 0);
  1205. CnAssert(IsListEmpty(&(fsContext->EventList)));
  1206. if (fileType == TDI_CONTROL_CHANNEL_FILE) {
  1207. acquired = CnAcquireResourceExclusive(
  1208. CnResource,
  1209. TRUE
  1210. );
  1211. CnAssert(acquired == TRUE);
  1212. if (CnExclusiveChannel == fsContext) {
  1213. CnExclusiveChannel = NULL;
  1214. }
  1215. if (acquired) {
  1216. CnReleaseResourceForThread(
  1217. CnResource,
  1218. (ERESOURCE_THREAD) PsGetCurrentThread()
  1219. );
  1220. }
  1221. }
  1222. IF_CNDBG(CN_DEBUG_CLOSE) {
  1223. CNPRINT((
  1224. "[ClusNet] Close on file object %p\n",
  1225. IrpSp->FileObject
  1226. ));
  1227. }
  1228. CnFreePool(fsContext);
  1229. return(STATUS_SUCCESS);
  1230. } // CnClose
  1231. FILE_FULL_EA_INFORMATION UNALIGNED *
  1232. CnFindEA(
  1233. PFILE_FULL_EA_INFORMATION StartEA,
  1234. CHAR *TargetName,
  1235. USHORT TargetNameLength
  1236. )
  1237. /*++
  1238. Routine Description:
  1239. Parses and extended attribute list for a given target attribute.
  1240. Arguments:
  1241. StartEA - the first extended attribute in the list.
  1242. TargetName - the name of the target attribute.
  1243. TargetNameLength - the length of the name of the target attribute.
  1244. Return Value:
  1245. A pointer to the requested attribute or NULL if the target wasn't found.
  1246. --*/
  1247. {
  1248. USHORT i;
  1249. BOOLEAN found;
  1250. FILE_FULL_EA_INFORMATION UNALIGNED * CurrentEA;
  1251. FILE_FULL_EA_INFORMATION UNALIGNED * NextEA;
  1252. PAGED_CODE();
  1253. NextEA = (FILE_FULL_EA_INFORMATION UNALIGNED *) StartEA;
  1254. do {
  1255. found = TRUE;
  1256. CurrentEA = NextEA;
  1257. NextEA = (FILE_FULL_EA_INFORMATION UNALIGNED *)
  1258. ( ((PUCHAR) StartEA) + CurrentEA->NextEntryOffset);
  1259. if (CurrentEA->EaNameLength != TargetNameLength) {
  1260. continue;
  1261. }
  1262. for (i=0; i < CurrentEA->EaNameLength; i++) {
  1263. if (CurrentEA->EaName[i] == TargetName[i]) {
  1264. continue;
  1265. }
  1266. found = FALSE;
  1267. break;
  1268. }
  1269. if (found) {
  1270. return(CurrentEA);
  1271. }
  1272. } while(CurrentEA->NextEntryOffset != 0);
  1273. return(NULL);
  1274. } // CnFindEA
  1275. NTSTATUS
  1276. CnEnableShutdownOnClose(
  1277. PIRP Irp
  1278. )
  1279. {
  1280. NTSTATUS status;
  1281. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  1282. PCN_FSCONTEXT fsContext = irpSp->FileObject->FsContext;
  1283. ULONG requestSize;
  1284. CLIENT_ID ClientId;
  1285. OBJECT_ATTRIBUTES ObjAttributes;
  1286. PCLUSNET_SHUTDOWN_ON_CLOSE_REQUEST request;
  1287. PAGED_CODE();
  1288. request = (PCLUSNET_SHUTDOWN_ON_CLOSE_REQUEST)
  1289. Irp->AssociatedIrp.SystemBuffer;
  1290. requestSize = irpSp->Parameters.DeviceIoControl.InputBufferLength;
  1291. if ( requestSize >= sizeof(CLUSNET_SHUTDOWN_ON_CLOSE_REQUEST)
  1292. )
  1293. {
  1294. //
  1295. // illegal for kernel mode
  1296. //
  1297. if ( Irp->RequestorMode != KernelMode ) {
  1298. //
  1299. // Get a handle to the cluster service process.
  1300. // This is used to kill the service if a poison
  1301. // pkt is received. Since a kernel worker thread
  1302. // is used to kill the cluster service, we need
  1303. // to acquire the handle in the system process.
  1304. //
  1305. IF_CNDBG(CN_DEBUG_INIT) {
  1306. CNPRINT(("[Clusnet] Acquiring process handle\n"));
  1307. }
  1308. if (ClussvcProcessHandle == NULL) {
  1309. KeAttachProcess( CnSystemProcess );
  1310. ClientId.UniqueThread = (HANDLE)NULL;
  1311. ClientId.UniqueProcess = UlongToHandle(request->ProcessId);
  1312. InitializeObjectAttributes(
  1313. &ObjAttributes,
  1314. NULL,
  1315. 0,
  1316. (HANDLE) NULL,
  1317. (PSECURITY_DESCRIPTOR) NULL
  1318. );
  1319. status = ZwOpenProcess(
  1320. &ClussvcProcessHandle,
  1321. 0,
  1322. &ObjAttributes,
  1323. &ClientId
  1324. );
  1325. if ( NT_SUCCESS( status )) {
  1326. NTSTATUS subStatus;
  1327. fsContext->ShutdownOnClose = TRUE;
  1328. //
  1329. // Get the clussvc process pointer. This is
  1330. // used only as an informational parameter
  1331. // in the hang detection bugcheck, so a
  1332. // failure is non-fatal.
  1333. //
  1334. subStatus = ObReferenceObjectByHandle(
  1335. ClussvcProcessHandle,
  1336. 0,
  1337. NULL,
  1338. KernelMode,
  1339. &ClussvcProcessObject,
  1340. NULL
  1341. );
  1342. if (NT_SUCCESS(subStatus)) {
  1343. //
  1344. // Immediately drop the reference so that we
  1345. // don't need to drop it later. Since the
  1346. // process object is only used for informational
  1347. // purposes, we are not concerned with its
  1348. // reference count. We save the pointer and
  1349. // assume it is good as long as we hold a
  1350. // handle to the process.
  1351. //
  1352. ObDereferenceObject(ClussvcProcessObject);
  1353. } else {
  1354. IF_CNDBG(CN_DEBUG_INIT) {
  1355. CNPRINT((
  1356. "[Clusnet] Failed to reference "
  1357. "clussvc process object by handle, "
  1358. "status %08X.\n",
  1359. subStatus
  1360. ));
  1361. }
  1362. CnTrace(HBEAT_ERROR, HbTraceClussvcProcessObj,
  1363. "[Clusnet] Failed to reference "
  1364. "clussvc process object by handle, "
  1365. "status %!status!.\n",
  1366. subStatus
  1367. );
  1368. ClussvcProcessObject = NULL;
  1369. }
  1370. } else {
  1371. IF_CNDBG(CN_DEBUG_INIT) {
  1372. CNPRINT((
  1373. "[Clusnet] ZwOpenProcess failed. status = %08X\n",
  1374. status
  1375. ));
  1376. }
  1377. }
  1378. KeDetachProcess();
  1379. }
  1380. else {
  1381. status = STATUS_INVALID_DEVICE_REQUEST;
  1382. }
  1383. }
  1384. else {
  1385. status = STATUS_INVALID_PARAMETER_MIX;
  1386. }
  1387. }
  1388. else {
  1389. status = STATUS_INVALID_PARAMETER;
  1390. }
  1391. return(status);
  1392. } // CnEnableShutdownOnClose
  1393. BOOLEAN
  1394. CnPerformSecurityCheck(
  1395. PIRP Irp,
  1396. PIO_STACK_LOCATION IrpSp,
  1397. PNTSTATUS Status
  1398. )
  1399. /*++
  1400. Routine Description:
  1401. Compares security context of the endpoint creator to that
  1402. of the administrator and local system.
  1403. Arguments:
  1404. Irp - Pointer to I/O request packet.
  1405. IrpSp - pointer to the IO stack location to use for this request.
  1406. Status - returns status generated by access check on failure.
  1407. Return Value:
  1408. TRUE - the socket creator has admin or local system privilige
  1409. FALSE - the socket creator is just a plain user
  1410. Notes:
  1411. This code was lifted from AFD.
  1412. --*/
  1413. {
  1414. BOOLEAN accessGranted;
  1415. PACCESS_STATE accessState;
  1416. PIO_SECURITY_CONTEXT securityContext;
  1417. PPRIVILEGE_SET privileges = NULL;
  1418. ACCESS_MASK grantedAccess;
  1419. PGENERIC_MAPPING genericMapping;
  1420. ACCESS_MASK accessMask = GENERIC_ALL;
  1421. //
  1422. // Enable access to all the globally defined SIDs
  1423. //
  1424. genericMapping = IoGetFileObjectGenericMapping();
  1425. RtlMapGenericMask(&accessMask, genericMapping);
  1426. securityContext = IrpSp->Parameters.Create.SecurityContext;
  1427. accessState = securityContext->AccessState;
  1428. SeLockSubjectContext(&accessState->SubjectSecurityContext);
  1429. accessGranted = SeAccessCheck(
  1430. CdpAdminSecurityDescriptor,
  1431. &accessState->SubjectSecurityContext,
  1432. TRUE,
  1433. accessMask,
  1434. 0,
  1435. &privileges,
  1436. IoGetFileObjectGenericMapping(),
  1437. (KPROCESSOR_MODE)((IrpSp->Flags & SL_FORCE_ACCESS_CHECK)
  1438. ? UserMode
  1439. : Irp->RequestorMode),
  1440. &grantedAccess,
  1441. Status
  1442. );
  1443. if (privileges) {
  1444. (VOID) SeAppendPrivileges(
  1445. accessState,
  1446. privileges
  1447. );
  1448. SeFreePrivileges(privileges);
  1449. }
  1450. if (accessGranted) {
  1451. accessState->PreviouslyGrantedAccess |= grantedAccess;
  1452. accessState->RemainingDesiredAccess &= ~( grantedAccess | MAXIMUM_ALLOWED );
  1453. CnAssert(NT_SUCCESS(*Status));
  1454. }
  1455. else {
  1456. CnAssert(!NT_SUCCESS(*Status));
  1457. }
  1458. SeUnlockSubjectContext(&accessState->SubjectSecurityContext);
  1459. return (accessGranted);
  1460. } // CnPerformSecurityCheck