FORCEINLINE BOOLEAN FxIrp::Is32bitProcess( VOID ) { #if defined(_WIN64) #if BUILD_WOW64_ENABLED return IoIs32bitProcess(m_Irp); #else // BUILD_WOW64_ENABLED return FALSE; #endif // BUILD_WOW64_ENABLED #else // defined(_WIN64) return TRUE; #endif // defined(_WIN64) }
/** * Worker for VBoxDrvNtDeviceControl that takes the slow IOCtl functions. * * @returns NT status code. * * @param pDevObj Device object. * @param pSession The session. * @param pIrp Request packet. * @param pStack The stack location containing the DeviceControl parameters. */ static int VBoxDrvNtDeviceControlSlow(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PIRP pIrp, PIO_STACK_LOCATION pStack) { NTSTATUS rcNt; unsigned cbOut = 0; int rc = 0; Log2(("VBoxDrvNtDeviceControlSlow(%p,%p): ioctl=%#x pBuf=%p cbIn=%#x cbOut=%#x pSession=%p\n", pDevExt, pIrp, pStack->Parameters.DeviceIoControl.IoControlCode, pIrp->AssociatedIrp.SystemBuffer, pStack->Parameters.DeviceIoControl.InputBufferLength, pStack->Parameters.DeviceIoControl.OutputBufferLength, pSession)); #ifdef RT_ARCH_AMD64 /* Don't allow 32-bit processes to do any I/O controls. */ if (!IoIs32bitProcess(pIrp)) #endif { /* Verify that it's a buffered CTL. */ if ((pStack->Parameters.DeviceIoControl.IoControlCode & 0x3) == METHOD_BUFFERED) { /* Verify that the sizes in the request header are correct. */ PSUPREQHDR pHdr = (PSUPREQHDR)pIrp->AssociatedIrp.SystemBuffer; if ( pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr) && pStack->Parameters.DeviceIoControl.InputBufferLength == pHdr->cbIn && pStack->Parameters.DeviceIoControl.OutputBufferLength == pHdr->cbOut) { /* * Do the job. */ rc = supdrvIOCtl(pStack->Parameters.DeviceIoControl.IoControlCode, pDevExt, pSession, pHdr); if (!rc) { rcNt = STATUS_SUCCESS; cbOut = pHdr->cbOut; if (cbOut > pStack->Parameters.DeviceIoControl.OutputBufferLength) { cbOut = pStack->Parameters.DeviceIoControl.OutputBufferLength; OSDBGPRINT(("VBoxDrvLinuxIOCtl: too much output! %#x > %#x; uCmd=%#x!\n", pHdr->cbOut, cbOut, pStack->Parameters.DeviceIoControl.IoControlCode)); } } else rcNt = STATUS_INVALID_PARAMETER; Log2(("VBoxDrvNtDeviceControlSlow: returns %#x cbOut=%d rc=%#x\n", rcNt, cbOut, rc)); } else { Log(("VBoxDrvNtDeviceControlSlow: Mismatching sizes (%#x) - Hdr=%#lx/%#lx Irp=%#lx/%#lx!\n", pStack->Parameters.DeviceIoControl.IoControlCode, pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr) ? pHdr->cbIn : 0, pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr) ? pHdr->cbOut : 0, pStack->Parameters.DeviceIoControl.InputBufferLength, pStack->Parameters.DeviceIoControl.OutputBufferLength)); rcNt = STATUS_INVALID_PARAMETER; } } else { Log(("VBoxDrvNtDeviceControlSlow: not buffered request (%#x) - not supported\n", pStack->Parameters.DeviceIoControl.IoControlCode)); rcNt = STATUS_NOT_SUPPORTED; } } #ifdef RT_ARCH_AMD64 else { Log(("VBoxDrvNtDeviceControlSlow: WOW64 req - not supported\n")); rcNt = STATUS_NOT_SUPPORTED; } #endif /* complete the request. */ pIrp->IoStatus.Status = rcNt; pIrp->IoStatus.Information = cbOut; IoCompleteRequest(pIrp, IO_NO_INCREMENT); return rcNt; }
NTSTATUS Bus_IoCtl ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: Handle user mode PlugIn, UnPlug and device Eject requests. Arguments: DeviceObject - pointer to a device object. Irp - pointer to an I/O Request Packet. Return Value: NT status code --*/ { PIO_STACK_LOCATION irpStack; NTSTATUS status; ULONG inlen, outlen; PFDO_DEVICE_DATA fdoData; PVOID buffer; PAGED_CODE (); // // It is not safe to call IOCTL in raised IRQL. // ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); fdoData = (PFDO_DEVICE_DATA) DeviceObject->DeviceExtension; // // We only take Device Control requests for the FDO. // That is the bus itself. // if (!fdoData->IsFDO) { // // These commands are only allowed to go to the FDO. // status = STATUS_INVALID_DEVICE_REQUEST; Irp->IoStatus.Status = status; IoCompleteRequest (Irp, IO_NO_INCREMENT); return status; } // // Check to see whether the bus is removed // if (fdoData->DevicePnPState == Deleted) { Irp->IoStatus.Status = status = STATUS_NO_SUCH_DEVICE; IoCompleteRequest (Irp, IO_NO_INCREMENT); return status; } Bus_IncIoCount (fdoData); irpStack = IoGetCurrentIrpStackLocation (Irp); buffer = Irp->AssociatedIrp.SystemBuffer; inlen = irpStack->Parameters.DeviceIoControl.InputBufferLength; outlen = irpStack->Parameters.DeviceIoControl.OutputBufferLength; status = STATUS_INVALID_PARAMETER; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("%d called\n", irpStack->Parameters.DeviceIoControl.IoControlCode)); switch (irpStack->Parameters.DeviceIoControl.IoControlCode) { case IOCTL_NDASBUS_ADD_TARGET: { PPDO_DEVICE_DATA pdoData; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_NDASBUS_ADD_TARGET inlen %d, outlen %d, sizeof(NDASBUS_ADD_TARGET_DATA) %d\n", inlen, outlen, sizeof(NDASBUS_ADD_TARGET_DATA))); if ((inlen == outlen) && (sizeof(NDASBUS_ADD_TARGET_DATA) <= inlen)) { ULONG ulSize; PNDASBUS_ADD_TARGET_DATA addTargetData = buffer; BOOLEAN accepted; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("IOCTL_NDASBUS_ADD_TARGET called\n")); Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_NDASBUS_ADD_TARGET Target Type %d\n", addTargetData->ucTargetType)); status = STATUS_SUCCESS; // // Check structure size // if(VerifySizeOfAddTargetData(addTargetData, &ulSize) == 0) { status = STATUS_INVALID_PARAMETER; break; } if(ulSize != inlen) { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("ADD_TARGET: Size mismatch. Req %d, in %d\n", ulSize, inlen)); status = STATUS_UNSUCCESSFUL; break; } // // Check to see if acceptable structure. // accepted = TRUE; switch(addTargetData->ucTargetType) { case NDASSCSI_TYPE_DISK_NORMAL: case NDASSCSI_TYPE_DVD: case NDASSCSI_TYPE_VDVD: case NDASSCSI_TYPE_MO: if(addTargetData->ulNumberOfUnitDiskList != 1) accepted = FALSE; break; case NDASSCSI_TYPE_DISK_MIRROR: if(2 != addTargetData->ulNumberOfUnitDiskList) accepted = FALSE; break; case NDASSCSI_TYPE_DISK_AGGREGATION: if (addTargetData->ulNumberOfUnitDiskList < 2 || addTargetData->ulNumberOfUnitDiskList > MAX_NR_UNITDISK_FOR_AGGR) accepted = FALSE; break; case NDASSCSI_TYPE_DISK_RAID0: switch(addTargetData->ulNumberOfUnitDiskList) { case 2: case 4: case 8: break; default: // do not accept accepted = FALSE; break; } break; case NDASSCSI_TYPE_DISK_RAID1R3: { ULONG ulDiskCount; ulDiskCount = addTargetData->ulNumberOfUnitDiskList - addTargetData->RAID_Info.nSpareDisk; if (2 != ulDiskCount) accepted = FALSE; } break; case NDASSCSI_TYPE_DISK_RAID4R3: { ULONG ulDiskCount; ulDiskCount = addTargetData->ulNumberOfUnitDiskList - addTargetData->RAID_Info.nSpareDisk; switch(ulDiskCount) { case 3: // 2 + 1 case 5: // 4 + 1 case 9: // 8 + 1 break; default: // do not accept accepted = FALSE; break; } break; } default: Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("ADD_TARGET: Bad Disk Type.\n")); accepted = FALSE; break; } if(accepted == FALSE) { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("ADD_TARGET: Invaild type.\n")); status = STATUS_UNSUCCESSFUL; break; } #if DBG NDBusIoctlLogError( fdoData->Self, NDASBUS_IO_TRY_TO_ADDTARGET, IOCTL_NDASBUS_ADD_TARGET, addTargetData->ulSlotNo); #endif // Find Pdo Data... pdoData = LookupPdoData(fdoData, addTargetData->ulSlotNo); if(pdoData == NULL) { Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("no pdo\n")); status = STATUS_UNSUCCESSFUL; NDBusIoctlLogError( fdoData->Self, NDASBUS_IO_PDO_NOT_FOUND, IOCTL_NDASBUS_ADD_TARGET, addTargetData->ulSlotNo); break; } // // Save the add target information to the PDO extension // pdoData->LanscsiAdapterPDO.AddDevInfo = ExAllocatePoolWithTag(NonPagedPool, inlen, BUSENUM_POOL_TAG); if(pdoData->LanscsiAdapterPDO.AddDevInfo == NULL) { Irp->IoStatus.Information = 0; status = STATUS_INSUFFICIENT_RESOURCES; break; } else { RtlCopyMemory(pdoData->LanscsiAdapterPDO.AddDevInfo, addTargetData, inlen); status = STATUS_SUCCESS; } pdoData->LanscsiAdapterPDO.AddDevInfoLength = inlen; // // Init PDO status // pdoData->LanscsiAdapterPDO.LastAdapterStatus = NDASSCSI_ADAPTERINFO_STATUS_INIT; pdoData->LanscsiAdapterPDO.DeviceMode = addTargetData->DeviceMode; // // Notify to NDASSCSI // Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_NDASBUS_ADD_TARGET SetEvent AddTargetEvent!\n")); KeSetEvent(&pdoData->LanscsiAdapterPDO.AddTargetEvent, IO_NO_INCREMENT, FALSE); // // Register Target // if(pdoData->Persistent) { status = LSBus_RegisterTarget(fdoData, addTargetData); if(!NT_SUCCESS(status)) { ExFreePoolWithTag(pdoData->LanscsiAdapterPDO.AddDevInfo, BUSENUM_POOL_TAG); pdoData->LanscsiAdapterPDO.AddDevInfo = NULL; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("ADD_TARGET: LSBus_RegisterTarget() failed. STATUS=%08lx\n", status)); status = STATUS_INTERNAL_DB_ERROR; NDBusIoctlLogError( fdoData->Self, NDASBUS_IO_REGISTER_TARGET_FAIL, IOCTL_NDASBUS_ADD_TARGET, addTargetData->ulSlotNo); } else { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_INFO, ("ADD_TARGET: Successfully registered.\n")); } } ObDereferenceObject(pdoData->Self); Irp->IoStatus.Information = outlen; } else { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_NDASBUS_ADD_TARGET length mismatch!!!" " inlen %d, outlen %d, sizeof(NDASBUS_ADD_TARGET_DATA) %d\n", inlen, outlen, sizeof(NDASBUS_ADD_TARGET_DATA))); } } break; case IOCTL_NDASBUS_REMOVE_TARGET: { PPDO_DEVICE_DATA pdoData; PNDASBUS_REMOVE_TARGET_DATA removeTarget; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("IOCTL_NDASBUS_REMOVE_TARGET called\n")); if (sizeof (NDASBUS_REMOVE_TARGET_DATA) != inlen) break; removeTarget = (PNDASBUS_REMOVE_TARGET_DATA)buffer; pdoData = LookupPdoData(fdoData, removeTarget->ulSlotNo); if(pdoData == NULL) { Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("no pdo\n")); status = STATUS_UNSUCCESSFUL; NDBusIoctlLogError( fdoData->Self, NDASBUS_IO_PDO_NOT_FOUND, IOCTL_NDASBUS_REMOVE_TARGET, removeTarget->ulSlotNo); break; } // // redirect to the NDAS SCSI Device // status = LSBus_IoctlToNdasScsiDevice( pdoData, NDASSCSI_IOCTL_REMOVE_TARGET, buffer, sizeof(NDASBUS_REMOVE_TARGET_DATA), NULL, 0 ); if(NT_SUCCESS(status) && pdoData->Persistent) { status = LSBus_UnregisterTarget(fdoData, removeTarget->ulSlotNo, removeTarget->ulTargetId); if(!NT_SUCCESS(status)) { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_INFO, ( "REMOVE_TARGET: Removed Target instance," " but LSBus_UnregisterTarget() failed.\n")); status = STATUS_INTERNAL_DB_ERROR; NDBusIoctlLogError( fdoData->Self, NDASBUS_IO_UNREGISTER_TARGET_FAIL, IOCTL_NDASBUS_REMOVE_TARGET, removeTarget->ulSlotNo); } #if DBG else { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_INFO, ("REMOVE_TARGET: LSBus_UnregisterTarget() succeeded.\n")); } #endif } ObDereferenceObject(pdoData->Self); Irp->IoStatus.Information = 0; break; } case IOCTL_NDASBUS_STARTSTOP_REGISTRARENUM:{ PULONG onOff = (PULONG)buffer; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ( "STARTSTOP_REGISTRARENUM: inlen %d, outlen %d OnOff %u\n", inlen, outlen, *onOff)); KeEnterCriticalRegion(); ExAcquireFastMutexUnsafe(&fdoData->RegMutex); if(*onOff != 0) { // // Save old state. // Activate the registrar's enumeration // *onOff = fdoData->StartStopRegistrarEnum; fdoData->StartStopRegistrarEnum = TRUE; } else { // // Save old state. // Deactivate the registrar's enumeration // *onOff = fdoData->StartStopRegistrarEnum; fdoData->StartStopRegistrarEnum = FALSE; } // // Clean up non-enumerated entries. // LSBus_CleanupNDASDeviceRegistryUnsafe(fdoData); ExReleaseFastMutexUnsafe(&fdoData->RegMutex); KeLeaveCriticalRegion(); Irp->IoStatus.Information = sizeof(ULONG); status = STATUS_SUCCESS; break; } case IOCTL_NDASBUS_REGISTER_DEVICE: { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ( "REGISTER_DEVICE: inlen %d, outlen %d," " sizeof(NDASBUS_PLUGIN_HARDWARE_EX2) %d\n", inlen, outlen, sizeof(NDASBUS_PLUGIN_HARDWARE_EX2))); if ((inlen == outlen)) { PNDASBUS_PLUGIN_HARDWARE_EX2 PlugIn = buffer; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("REGISTER_DEVICE: entered\n")); status = LSBus_RegisterDevice(fdoData, PlugIn); Irp->IoStatus.Information = 0; } else Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("REGISTER_DEVICE: length mismatch!!!" " inlen %d, outlen %d, sizeof(NDASBUS_PLUGIN_HARDWARE_EX2) %d\n", inlen, outlen, sizeof(NDASBUS_PLUGIN_HARDWARE_EX2))); } break; case IOCTL_NDASBUS_REGISTER_TARGET: { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ( "REGISTER_TARGET: inlen %d, outlen %d," " sizeof(NDASBUS_ADD_TARGET_DATA) %d\n", inlen, outlen, sizeof(NDASBUS_ADD_TARGET_DATA))); if ((inlen == outlen)) { PNDASBUS_ADD_TARGET_DATA AddTargetData = buffer; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("REGISTER_TARGET: entered\n")); status = LSBus_RegisterTarget(fdoData, AddTargetData); Irp->IoStatus.Information = 0; } else { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ( "REGISTER_TARGET: length mismatch!!!" " inlen %d, outlen %d, sizeof(NDASBUS_ADD_TARGET_DATA) %d\n", inlen, outlen, sizeof(NDASBUS_ADD_TARGET_DATA))); } } break; case IOCTL_NDASBUS_UNREGISTER_DEVICE: { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ( "UNREGISTER_DEVICE: inlen %d, outlen %d," " sizeof(NDASBUS_UNREGISTER_NDASDEV) %d\n", inlen, outlen, sizeof(NDASBUS_UNREGISTER_NDASDEV))); if ((inlen == outlen)) { PNDASBUS_UNREGISTER_NDASDEV UnregDev = buffer; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("UNREGISTER_DEVICE: entered\n")); status = LSBus_UnregisterDevice(fdoData, UnregDev->SlotNo); Irp->IoStatus.Information = 0; } else { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ( "UNREGISTER_DEVICE: length mismatch!!!" " inlen %d, outlen %d, sizeof(NDASBUS_ADD_TARGET_DATA) %d\n", inlen, outlen, sizeof(NDASBUS_UNREGISTER_NDASDEV))); } } break; case IOCTL_NDASBUS_UNREGISTER_TARGET: { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ( "UNREGISTER_TARGET: inlen %d, outlen %d," " sizeof(NDASBUS_UNREGISTER_TARGET) %d\n", inlen, outlen, sizeof(NDASBUS_UNREGISTER_TARGET))); if ((inlen == outlen)) { PNDASBUS_UNREGISTER_TARGET UnregTarget = buffer; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("UNREGISTER_TARGET: entered\n")); status = LSBus_UnregisterTarget(fdoData, UnregTarget->SlotNo, UnregTarget->TargetId); Irp->IoStatus.Information = 0; } else { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ( "UNREGISTER_TARGET: length mismatch!!!" " inlen %d, outlen %d, sizeof(NDASBUS_UNREGISTER_TARGET) %d\n", inlen, outlen, sizeof(NDASBUS_UNREGISTER_TARGET))); } } break; case IOCTL_NDASBUS_SETPDOINFO: { PPDO_DEVICE_DATA pdoData; PNDASBUS_SETPDOINFO SetPdoInfo; KIRQL oldIrql; PVOID sectionHandle; BOOLEAN acceptStatus; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("IOCTL_NDASBUS_SETPDOINFO called\n")); if (sizeof (NDASBUS_SETPDOINFO) != inlen) break; acceptStatus = TRUE; SetPdoInfo = (PNDASBUS_SETPDOINFO)buffer; pdoData = LookupPdoData(fdoData, SetPdoInfo->SlotNo); if(pdoData == NULL) { Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("no pdo\n")); status = STATUS_UNSUCCESSFUL; NDBusIoctlLogError( fdoData->Self, NDASBUS_IO_PDO_NOT_FOUND, IOCTL_NDASBUS_SETPDOINFO, SetPdoInfo->SlotNo); break; } // // lock the code section of this function to acquire spinlock in raised IRQL. // sectionHandle = MmLockPagableCodeSection(Bus_IoCtl); KeAcquireSpinLock(&pdoData->LanscsiAdapterPDO.LSDevDataSpinLock, &oldIrql); Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("!!!!!!!!!!!!!!!!!! SETPDOINFO: PDO %p: %08lx %08lx %08lx\n", pdoData->Self, SetPdoInfo->AdapterStatus, SetPdoInfo->SupportedFeatures, SetPdoInfo->EnabledFeatures)); // // Deny the status change if the current status is STATUS_STOPPED except for RESETSTATUS flag. // if(ADAPTERINFO_ISSTATUS(pdoData->LanscsiAdapterPDO.LastAdapterStatus, NDASSCSI_ADAPTERINFO_STATUS_STOPPED)) { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("SETPDOINFO: 'An event occured after 'Stopped' event\n")); if(ADAPTERINFO_ISSTATUSFLAG(SetPdoInfo->AdapterStatus, NDASSCSI_ADAPTERINFO_STATUSFLAG_RESETSTATUS)) { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("SETPDOINFO: Reset-status event accepted.\n")); } else { acceptStatus = FALSE; } } else { if(pdoData->LanscsiAdapterPDO.AddDevInfo == NULL) { acceptStatus = FALSE; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("!!!!!!!!!!!!!!!!!! SETPDOINFO: AddTarget is not occured. Too early to set status.\n")); } } // // Mask off RESETSTATUS. // NDAS service does not need to know it. // SetPdoInfo->AdapterStatus &= ~NDASSCSI_ADAPTERINFO_STATUSFLAG_RESETSTATUS; // // Set status values to the corresponding physical device object. // Save to the extension // if(acceptStatus) { PNDASBUS_PDOEVENT_ENTRY pdoEventEntry; pdoEventEntry = NdasBusCreatePdoStatusItem(SetPdoInfo->AdapterStatus); if(pdoEventEntry) { NdasBusQueuePdoStatusItem(&pdoData->LanscsiAdapterPDO, pdoEventEntry); } #if DBG else { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("SETPDOINFO: Could not allocate PDO status entry.\n")); } #endif pdoData->LanscsiAdapterPDO.LastAdapterStatus = SetPdoInfo->AdapterStatus; pdoData->LanscsiAdapterPDO.SupportedFeatures = SetPdoInfo->SupportedFeatures; pdoData->LanscsiAdapterPDO.EnabledFeatures = SetPdoInfo->EnabledFeatures; // // Queue plugout worker if the NDAS SCSI stop abnormally. // Notify the NDAS service of abnormal termination // if(ADAPTERINFO_ISSTATUS(SetPdoInfo->AdapterStatus, NDASSCSI_ADAPTERINFO_STATUS_STOPPED) && ADAPTERINFO_ISSTATUSFLAG(SetPdoInfo->AdapterStatus, NDASSCSI_ADAPTERINFO_STATUSFLAG_ABNORMAL_TERMINAT)) { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("SETPDOINFO: Queueing Unplug worker!!!!!!!!\n")); status = QueueUnplugWorker(fdoData, SetPdoInfo->SlotNo); // // Set disconnection event // KeSetEvent(pdoData->LanscsiAdapterPDO.DisconEventToService, IO_DISK_INCREMENT, FALSE); } else { // // Notify the adapter status change // KeSetEvent(pdoData->LanscsiAdapterPDO.AlarmEventToService, IO_DISK_INCREMENT, FALSE); } } KeReleaseSpinLock(&pdoData->LanscsiAdapterPDO.LSDevDataSpinLock, oldIrql); // // Release the code section. // MmUnlockPagableImageSection(sectionHandle); status = STATUS_SUCCESS; ObDereferenceObject(pdoData->Self); Irp->IoStatus.Information = outlen; } break; case IOCTL_NDASBUS_QUERY_NODE_ALIVE: { PPDO_DEVICE_DATA pdoData; BOOLEAN bAlive; PNDASBUS_NODE_ALIVE_IN pNodeAliveIn; NDASBUS_NODE_ALIVE_OUT nodeAliveOut; // Check Parameter. if(inlen != sizeof(NDASBUS_NODE_ALIVE_IN) || outlen != sizeof(NDASBUS_NODE_ALIVE_OUT)) { status = STATUS_UNKNOWN_REVISION; break; } pNodeAliveIn = (PNDASBUS_NODE_ALIVE_IN)Irp->AssociatedIrp.SystemBuffer; Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_NOISE, ("FDO: IOCTL_NDASBUS_QUERY_NODE_ALIVE SlotNumber = %d\n", pNodeAliveIn->SlotNo)); pdoData = LookupPdoData(fdoData, pNodeAliveIn->SlotNo); if(pdoData == NULL) { // Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_TRACE, // ("[LanScsiBus]Bus_IoCtl: IOCTL_NDASBUS_QUERY_NODE_ALIVE No pdo\n")); bAlive = FALSE; } else { bAlive = TRUE; } // For Result... nodeAliveOut.SlotNo = pNodeAliveIn->SlotNo; nodeAliveOut.bAlive = bAlive; // Get Adapter Status. if(bAlive == TRUE) { if( ADAPTERINFO_ISSTATUS(pdoData->LanscsiAdapterPDO.LastAdapterStatus, NDASSCSI_ADAPTERINFO_STATUS_STOPPING)) { nodeAliveOut.bHasError = TRUE; Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_NDASBUS_QUERY_NODE_ALIVE Adapter has Error 0x%x\n", nodeAliveOut.bHasError)); } else { nodeAliveOut.bHasError = FALSE; } } if(pdoData) ObDereferenceObject(pdoData->Self); RtlCopyMemory( Irp->AssociatedIrp.SystemBuffer, &nodeAliveOut, sizeof(NDASBUS_NODE_ALIVE_OUT) ); Irp->IoStatus.Information = sizeof(NDASBUS_NODE_ALIVE_OUT); status = STATUS_SUCCESS; } break; // // added by hootch 01172004 // case IOCTL_NDASBUS_UPGRADETOWRITE: { PPDO_DEVICE_DATA pdoData; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("IOCTL_NDASBUS_UPGRADETOWRITE called\n")); // Check Parameter. if(inlen != sizeof(NDASBUS_UPGRADE_TO_WRITE)) { Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_NDASBUS_UPGRADETOWRITE: Invalid input buffer length\n")); status = STATUS_UNKNOWN_REVISION; break; } pdoData = LookupPdoData(fdoData, ((PNDASBUS_UPGRADE_TO_WRITE)buffer)->SlotNo); if(pdoData == NULL) { Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_NDASBUS_UPGRADETOWRITE: No pdo for Slotno:%d\n", ((PNDASBUS_UPGRADE_TO_WRITE)buffer)->SlotNo)); status = STATUS_NO_SUCH_DEVICE; NDBusIoctlLogError( fdoData->Self, NDASBUS_IO_PDO_NOT_FOUND, IOCTL_NDASBUS_UPGRADETOWRITE, ((PNDASBUS_UPGRADE_TO_WRITE)buffer)->SlotNo); } else { // // redirect to the NDASSCSI Device // status = LSBus_IoctlToNdasScsiDevice( pdoData, NDASSCSI_IOCTL_UPGRADETOWRITE, buffer, inlen, buffer, outlen ); ObDereferenceObject(pdoData->Self); } Irp->IoStatus.Information = 0; } break; case IOCTL_NDASBUS_REDIRECT_NDASSCSI: { PPDO_DEVICE_DATA pdoData; PNDASBUS_REDIRECT_NDASSCSI redirectIoctl; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("IOCTL_NDASBUS_REDIRECT_NDASSCSI called\n")); // Check Parameter. if(inlen < sizeof(NDASBUS_REDIRECT_NDASSCSI)) { Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_NDASBUS_REDIRECT_NDASSCSI: Invalid input buffer length\n")); status = STATUS_UNKNOWN_REVISION; break; } redirectIoctl = (PNDASBUS_REDIRECT_NDASSCSI)buffer; pdoData = LookupPdoData(fdoData, redirectIoctl->SlotNo); if(pdoData == NULL) { Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_NDASBUS_REDIRECT_NDASSCSI: No pdo for Slotno:%d\n", redirectIoctl->SlotNo)); status = STATUS_NO_SUCH_DEVICE; } else { // // redirect to the NDASSCSI Device // status = LSBus_IoctlToNdasScsiDevice( pdoData, redirectIoctl->IoctlCode, redirectIoctl->IoctlData, redirectIoctl->IoctlDataSize, redirectIoctl->IoctlData, redirectIoctl->IoctlDataSize ); ObDereferenceObject(pdoData->Self); } Irp->IoStatus.Information = 0; } break; case IOCTL_NDASBUS_QUERY_NDASSCSIINFO: { PPDO_DEVICE_DATA pdoData; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("IOCTL_NDASBUS_QUERY_NDASSCSIINFO called\n")); // Check Parameter. if(inlen < FIELD_OFFSET(NDASSCSI_QUERY_INFO_DATA, QueryData) ) { Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_NDASBUS_QUERY_NDASSCSIINFO: Invalid input buffer length too small.\n")); status = STATUS_UNKNOWN_REVISION; break; } pdoData = LookupPdoData(fdoData, ((PNDASSCSI_QUERY_INFO_DATA)buffer)->NdasScsiAddress.SlotNo); if(pdoData == NULL) { Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_NDASBUS_QUERY_NDASSCSIINFO No pdo\n")); status = STATUS_NO_SUCH_DEVICE; NDBusIoctlLogError( fdoData->Self, NDASBUS_IO_PDO_NOT_FOUND, IOCTL_NDASBUS_QUERY_NDASSCSIINFO, ((PNDASSCSI_QUERY_INFO_DATA)buffer)->NdasScsiAddress.SlotNo); } else { // // redirect to the NDASSCSI Device // status = LSBus_IoctlToNdasScsiDevice( pdoData, NDASSCSI_IOCTL_QUERYINFO_EX, buffer, inlen, buffer, outlen ); ObDereferenceObject(pdoData->Self); } Irp->IoStatus.Information = outlen; } break; case IOCTL_NDASBUS_QUERY_INFORMATION: { // PPDO_DEVICE_DATA pdoData; NDASBUS_QUERY_INFORMATION Query; PNDASBUS_INFORMATION Information; LONG BufferLenNeeded; // Check Parameter. if( inlen < sizeof(NDASBUS_QUERY_INFORMATION) /*|| outlen < sizeof(NDASBUS_INFORMATION) */) { status = STATUS_UNKNOWN_REVISION; break; } RtlCopyMemory(&Query, buffer, sizeof(NDASBUS_QUERY_INFORMATION)); Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_TRACE, ("FDO: IOCTL_NDASBUS_QUERY_INFORMATION QueryType : %d SlotNumber = %d\n", Query.InfoClass, Query.SlotNo)); Information = (PNDASBUS_INFORMATION)buffer; ASSERT(Information); Information->InfoClass = Query.InfoClass; status = LSBus_QueryInformation(fdoData, IoIs32bitProcess(Irp), &Query, Information, outlen, &BufferLenNeeded); if(NT_SUCCESS(status)) { Information->Size = BufferLenNeeded; Irp->IoStatus.Information = BufferLenNeeded; } else { Irp->IoStatus.Information = BufferLenNeeded; } } break; case IOCTL_NDASBUS_PLUGIN_HARDWARE_EX2: { ULONG structLen; // Without variable length field ULONG wholeStructLen; // With variable length field ULONG inputWholeStructLen; // // Check 32 bit thunking request // if(IoIs32bitProcess(Irp)) { structLen = FIELD_OFFSET(NDASBUS_PLUGIN_HARDWARE_EX2_32, HardwareIDs); wholeStructLen = sizeof(NDASBUS_PLUGIN_HARDWARE_EX2_32); inputWholeStructLen = ((PNDASBUS_PLUGIN_HARDWARE_EX2_32) buffer)->Size; } else { structLen = FIELD_OFFSET(NDASBUS_PLUGIN_HARDWARE_EX2, HardwareIDs); wholeStructLen = sizeof(NDASBUS_PLUGIN_HARDWARE_EX2); inputWholeStructLen = ((PNDASBUS_PLUGIN_HARDWARE_EX2) buffer)->Size; } if ((inlen == outlen) && // // Make sure it has at least two nulls and the size // field is set to the declared size of the struct // ((structLen + sizeof(UNICODE_NULL) * 2) <= inlen) && // // The size field should be set to the sizeof the struct as declared // and *not* the size of the struct plus the multi_sz // (wholeStructLen == inputWholeStructLen)) { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("PlugIn called\n")); status= Bus_PlugInDeviceEx2((PNDASBUS_PLUGIN_HARDWARE_EX2)buffer, inlen, fdoData, IoIs32bitProcess(Irp), Irp->RequestorMode, FALSE); Irp->IoStatus.Information = outlen; } } break; case IOCTL_NDASBUS_GETVERSION: { if (outlen >= sizeof(NDASBUS_GET_VERSION)) { PNDASBUS_GET_VERSION version = (PNDASBUS_GET_VERSION)buffer; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("IOCTL_NDASBUS_GETVERSION: called\n")); try { version->VersionMajor = VER_FILEMAJORVERSION; version->VersionMinor = VER_FILEMINORVERSION; version->VersionBuild = VER_FILEBUILD; version->VersionPrivate = VER_FILEBUILD_QFE; Irp->IoStatus.Information = sizeof(NDASBUS_GET_VERSION); status = STATUS_SUCCESS; } except (EXCEPTION_EXECUTE_HANDLER) { status = GetExceptionCode(); Irp->IoStatus.Information = 0; } } } break; case IOCTL_NDASBUS_UNPLUG_HARDWARE: { if ((sizeof (NDASBUS_UNPLUG_HARDWARE) == inlen) && (inlen == outlen) && (((PNDASBUS_UNPLUG_HARDWARE)buffer)->Size == inlen)) { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("UnPlug called\n")); status= Bus_UnPlugDevice( (PNDASBUS_UNPLUG_HARDWARE)buffer, fdoData); Irp->IoStatus.Information = outlen; } } break; case IOCTL_NDASBUS_EJECT_HARDWARE: { if ((sizeof (NDASBUS_EJECT_HARDWARE) == inlen) && (inlen == outlen) && (((PNDASBUS_EJECT_HARDWARE)buffer)->Size == inlen)) { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("Eject called\n")); status= Bus_EjectDevice((PNDASBUS_EJECT_HARDWARE)buffer, fdoData); Irp->IoStatus.Information = outlen; } } break; case IOCTL_NDASBUS_DVD_GET_STATUS: { PPDO_DEVICE_DATA pdoData; PNDASBUS_DVD_STATUS pDvdStatusData; // Check Parameter. if((inlen != outlen) || (sizeof(NDASBUS_DVD_STATUS) > inlen)) { status = STATUS_UNSUCCESSFUL ; break; } pDvdStatusData = (PNDASBUS_DVD_STATUS)Irp->AssociatedIrp.SystemBuffer; Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("FDO: IOCTL_NDASBUS_DVD_GET_STATUS SlotNumber = %d\n", pDvdStatusData->SlotNo)); pdoData = LookupPdoData(fdoData, pDvdStatusData->SlotNo); if(pdoData == NULL) { Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_NDASBUS_DVD_GET_STATUS No pdo\n")); status = STATUS_UNSUCCESSFUL; NDBusIoctlLogError( fdoData->Self, NDASBUS_IO_PDO_NOT_FOUND, IOCTL_NDASBUS_DVD_GET_STATUS, pDvdStatusData->SlotNo); break; } else { if(pdoData->LanscsiAdapterPDO.Flags & LSDEVDATA_FLAG_LURDESC) { // // A LUR descriptor is set. // if(((PLURELATION_DESC)pdoData->LanscsiAdapterPDO.AddDevInfo)->DevType != NDASSCSI_TYPE_DVD) { Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_NDASBUS_DVD_GET_STATUS No DVD Device\n")); status = STATUS_UNSUCCESSFUL; break; } } else { // // ADD_TARGET_DATA is set. // if(((PNDASBUS_ADD_TARGET_DATA)pdoData->LanscsiAdapterPDO.AddDevInfo)->ucTargetType != NDASSCSI_TYPE_DVD) { Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_NDASBUS_DVD_GET_STATUS No DVD Device\n")); status = STATUS_UNSUCCESSFUL; break; } } // // redirect to the NDASSCSI Device // status = LSBus_IoctlToNdasScsiDevice( pdoData, NDASSCSI_IOCTL_GET_DVD_STATUS, buffer, inlen, buffer, outlen ); ObDereferenceObject(pdoData->Self); status = STATUS_SUCCESS; Irp->IoStatus.Information = outlen; } } break; default: break; // default status is STATUS_INVALID_PARAMETER }
VOID Rio500_EvtIoDeviceControl( _In_ WDFQUEUE Queue, _In_ WDFREQUEST Request, _In_ size_t OutputBufferLength, _In_ size_t InputBufferLength, _In_ ULONG IoControlCode ) /*++ Routine Description: This event is called when the framework receives IRP_MJ_DEVICE_CONTROL requests from the system. Arguments: Queue - Handle to the framework queue object that is associated with the I/O request. Request - Handle to a framework request object. OutputBufferLength - length of the request's output buffer, if an output buffer is available. InputBufferLength - length of the request's input buffer, if an input buffer is available. IoControlCode - the driver-defined or system-defined I/O control code (IOCTL) that is associated with the request. Return Value: VOID --*/ { WDFDEVICE device; PVOID ioBuffer; PRIO_IOCTL_BLOCK ioBufferRio; size_t bufLength; NTSTATUS status; PDEVICE_CONTEXT pDevContext; ULONG length = 0; URB urb; PMDL pMdl = NULL; WDF_MEMORY_DESCRIPTOR memoryDesc; #ifdef _WIN64 BOOLEAN isWowRequest = FALSE; #endif // _WIN64 UNREFERENCED_PARAMETER(OutputBufferLength); UNREFERENCED_PARAMETER(InputBufferLength); Rio500_DbgPrint(3, ("Entered Rio500_DispatchDevCtrl\n")); PAGED_CODE(); // // initialize variables // device = WdfIoQueueGetDevice(Queue); pDevContext = GetDeviceContext(device); switch(IoControlCode) { case IOCTL_RIO500_RESET_PIPE: status = ResetPipe(pDevContext->ReadPipe); if (NT_SUCCESS(status)) { status = ResetPipe(pDevContext->WritePipe); } break; case IOCTL_RIO500_GET_CONFIG_DESCRIPTOR: if (pDevContext->UsbConfigurationDescriptor) { length = pDevContext->UsbConfigurationDescriptor->wTotalLength; status = WdfRequestRetrieveOutputBuffer(Request, length, &ioBuffer, &bufLength); if (!NT_SUCCESS(status)) { Rio500_DbgPrint(1, ("WdfRequestRetrieveInputBuffer failed\n")); break; } RtlCopyMemory(ioBuffer, pDevContext->UsbConfigurationDescriptor, length); status = STATUS_SUCCESS; } else { status = STATUS_INVALID_DEVICE_STATE; } break; case IOCTL_RIO500_RESET_DEVICE: status = ResetDevice(device); break; case IOCTL_RIO500_RIO_COMMAND: #ifdef _WIN64 if (IoIs32bitProcess(NULL)) { bufLength = sizeof(RIO_IOCTL_BLOCK) - sizeof(DWORD32); isWowRequest = TRUE; } else #endif // _WIN64 { bufLength = sizeof(RIO_IOCTL_BLOCK); } status = WdfRequestRetrieveInputBuffer( Request, bufLength, &ioBufferRio, NULL ); if (NT_SUCCESS(status)) { #ifdef _WIN64 if (isWowRequest) { ioBuffer = (PVOID)ioBufferRio->MsgData.DataWow; } else #endif // _WIN64 { ioBuffer = ioBufferRio->MsgData.Data; } if (ioBufferRio->MsgLength != 0 && ioBuffer != NULL) { pMdl = IoAllocateMdl( ioBuffer, ioBufferRio->MsgLength, FALSE, FALSE, NULL ); MmProbeAndLockPages(pMdl, (KPROCESSOR_MODE)KernelMode, IoModifyAccess); } memset(&urb, 0, sizeof(urb)); urb.UrbControlVendorClassRequest.Hdr.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST); urb.UrbControlVendorClassRequest.Hdr.Function = URB_FUNCTION_VENDOR_DEVICE; urb.UrbControlVendorClassRequest.TransferBuffer = NULL; urb.UrbControlVendorClassRequest.RequestTypeReservedBits = 0x00; urb.UrbControlVendorClassRequest.TransferBufferLength = ioBufferRio->MsgLength; urb.UrbControlVendorClassRequest.TransferBufferMDL = pMdl; urb.UrbControlVendorClassRequest.Request = ioBufferRio->RequestCode; urb.UrbControlVendorClassRequest.Value = ioBufferRio->MsgValue; urb.UrbControlVendorClassRequest.Index = ioBufferRio->MsgIndex; urb.UrbControlVendorClassRequest.TransferFlags = USBD_SHORT_TRANSFER_OK; if (ioBufferRio->RequestType & 0x80) { urb.UrbControlVendorClassRequest.TransferFlags |= USBD_TRANSFER_DIRECTION_IN; } urb.UrbControlVendorClassRequest.UrbLink = NULL; WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memoryDesc, &urb, sizeof(urb)); status = WdfIoTargetSendInternalIoctlOthersSynchronously( WdfDeviceGetIoTarget(device), Request, IOCTL_INTERNAL_USB_SUBMIT_URB, &memoryDesc, NULL, NULL, NULL, NULL ); if (pMdl != NULL) { MmUnlockPages(pMdl); IoFreeMdl(pMdl); } } break; default: status = STATUS_INVALID_DEVICE_REQUEST; break; } WdfRequestCompleteWithInformation(Request, status, length); Rio500_DbgPrint(3, ("Exit Rio500_DispatchDevCtrl\n")); }
GUID * AFSValidateProcessEntry( IN HANDLE ProcessId, IN BOOLEAN bProcessTreeLocked) { GUID *pAuthGroup = NULL; NTSTATUS ntStatus = STATUS_SUCCESS; AFSProcessCB *pProcessCB = NULL, *pParentProcessCB = NULL; AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSDeviceObject->DeviceExtension; ULONGLONG ullProcessID = (ULONGLONG)ProcessId; UNICODE_STRING uniSIDString; ULONG ulSIDHash = 0; AFSSIDEntryCB *pSIDEntryCB = NULL; ULONG ulSessionId = 0; ULONGLONG ullTableHash = 0; AFSThreadCB *pParentThreadCB = NULL; UNICODE_STRING uniGUID; BOOLEAN bImpersonation = FALSE; __Enter { uniSIDString.Length = 0; uniSIDString.MaximumLength = 0; uniSIDString.Buffer = NULL; if ( !bProcessTreeLocked) { AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSValidateProcessEntry Acquiring Control ProcessTree.TreeLock lock %p SHARED %08lX\n", pDeviceExt->Specific.Control.ProcessTree.TreeLock, PsGetCurrentThread())); AFSAcquireShared( pDeviceExt->Specific.Control.ProcessTree.TreeLock, TRUE); } AFSDbgTrace(( AFS_SUBSYSTEM_AUTHGROUP_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "%s Entry for ProcessID %I64X\n", __FUNCTION__, ullProcessID)); ntStatus = AFSLocateHashEntry( pDeviceExt->Specific.Control.ProcessTree.TreeHead, ullProcessID, (AFSBTreeEntry **)&pProcessCB); if( !NT_SUCCESS( ntStatus) || pProcessCB == NULL) { if ( !bProcessTreeLocked) { AFSReleaseResource( pDeviceExt->Specific.Control.ProcessTree.TreeLock); AFSAcquireExcl( pDeviceExt->Specific.Control.ProcessTree.TreeLock, TRUE); } ntStatus = AFSLocateHashEntry( pDeviceExt->Specific.Control.ProcessTree.TreeHead, ullProcessID, (AFSBTreeEntry **)&pProcessCB); if( !NT_SUCCESS( ntStatus) || pProcessCB == NULL) { AFSProcessCreate( 0, ProcessId, 0, 0); } if( !NT_SUCCESS( ntStatus) || pProcessCB == NULL) { AFSDbgTrace(( AFS_SUBSYSTEM_AUTHGROUP_PROCESSING, AFS_TRACE_LEVEL_ERROR, "%s Failed to locate process entry for ProcessID %I64X\n", __FUNCTION__, ullProcessID)); try_return( ntStatus = STATUS_UNSUCCESSFUL); } if ( !bProcessTreeLocked) { AFSConvertToShared( pDeviceExt->Specific.Control.ProcessTree.TreeLock); } } // // Locate and lock the ParentProcessCB if we have one // if( pProcessCB->ParentProcessId != 0) { AFSDbgTrace(( AFS_SUBSYSTEM_AUTHGROUP_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "%s Locating process entry for Parent ProcessID %I64X\n", __FUNCTION__, pProcessCB->ParentProcessId)); ntStatus = AFSLocateHashEntry( pDeviceExt->Specific.Control.ProcessTree.TreeHead, (ULONGLONG)pProcessCB->ParentProcessId, (AFSBTreeEntry **)&pParentProcessCB); if( NT_SUCCESS( ntStatus) && pParentProcessCB != NULL) { AFSAcquireExcl( &pParentProcessCB->Lock, TRUE); AFSDbgTrace(( AFS_SUBSYSTEM_AUTHGROUP_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "%s Located process entry for Parent ProcessID %I64X\n", __FUNCTION__, pProcessCB->ParentProcessId)); } } else { AFSDbgTrace(( AFS_SUBSYSTEM_AUTHGROUP_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "%s No parent ID for ProcessID %I64X\n", __FUNCTION__, ullProcessID)); } AFSAcquireExcl( &pProcessCB->Lock, TRUE); #if defined(_WIN64) // // Mark the process as 64-bit if it is. // if( !IoIs32bitProcess( NULL)) { SetFlag( pProcessCB->Flags, AFS_PROCESS_FLAG_IS_64BIT); } else { ClearFlag( pProcessCB->Flags, AFS_PROCESS_FLAG_IS_64BIT); } #endif // // Locate the SID for the caller // ntStatus = AFSGetCallerSID( &uniSIDString, &bImpersonation); if( !NT_SUCCESS( ntStatus)) { AFSDbgTrace(( AFS_SUBSYSTEM_AUTHGROUP_PROCESSING, AFS_TRACE_LEVEL_ERROR, "%s Failed to locate callers SID for ProcessID %I64X\n", __FUNCTION__, ullProcessID)); try_return( ntStatus); } ulSessionId = AFSGetSessionId( (HANDLE)ullProcessID, &bImpersonation); if( ulSessionId == (ULONG)-1) { AFSDbgTrace(( AFS_SUBSYSTEM_AUTHGROUP_PROCESSING, AFS_TRACE_LEVEL_ERROR, "%s Failed to retrieve session ID for ProcessID %I64X\n", __FUNCTION__, ullProcessID)); try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); } AFSDbgTrace(( AFS_SUBSYSTEM_AUTHGROUP_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "%s Retrieved callers SID %wZ for ProcessID %I64X Session %08lX\n", __FUNCTION__, &uniSIDString, ullProcessID, ulSessionId)); // // If there is an Auth Group for the current process, // our job is finished. // if ( bImpersonation == FALSE) { pAuthGroup = pProcessCB->ActiveAuthGroup; if( pAuthGroup != NULL && !AFSIsNoPAGAuthGroup( pAuthGroup)) { uniGUID.Buffer = NULL; RtlStringFromGUID( *pAuthGroup, &uniGUID); AFSDbgTrace(( AFS_SUBSYSTEM_AUTHGROUP_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "%s Located valid AuthGroup GUID %wZ for SID %wZ ProcessID %I64X Session %08lX\n", __FUNCTION__, &uniGUID, &uniSIDString, ullProcessID, ulSessionId)); if( uniGUID.Buffer != NULL) { RtlFreeUnicodeString( &uniGUID); } try_return( ntStatus = STATUS_SUCCESS); } // // The current process does not yet have an Auth Group. Try to inherit // one from the parent process thread that created this process. // if( pParentProcessCB != NULL) { for ( pParentThreadCB = pParentProcessCB->ThreadList; pParentThreadCB != NULL; pParentThreadCB = pParentThreadCB->Next) { if( pParentThreadCB->ThreadId == pProcessCB->CreatingThreadId) { break; } } // // If the creating thread was found and it has a thread specific // Auth Group, use that even if it is the No PAG // if( pParentThreadCB != NULL && pParentThreadCB->ActiveAuthGroup != NULL && !AFSIsNoPAGAuthGroup( pParentThreadCB->ActiveAuthGroup)) { pProcessCB->ActiveAuthGroup = pParentThreadCB->ActiveAuthGroup; uniGUID.Buffer = NULL; RtlStringFromGUID( *(pProcessCB->ActiveAuthGroup), &uniGUID); AFSDbgTrace(( AFS_SUBSYSTEM_AUTHGROUP_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "%s PID %I64X Session %08lX inherited Active AuthGroup %wZ from thread %I64X\n", __FUNCTION__, ullProcessID, ulSessionId, &uniGUID, pParentThreadCB->ThreadId)); if( uniGUID.Buffer != NULL) { RtlFreeUnicodeString( &uniGUID); } } // // If the parent thread was not found or does not have an auth group // else if( pParentProcessCB->ActiveAuthGroup != NULL && !AFSIsNoPAGAuthGroup( pParentProcessCB->ActiveAuthGroup)) { pProcessCB->ActiveAuthGroup = pParentProcessCB->ActiveAuthGroup; uniGUID.Buffer = NULL; RtlStringFromGUID( *(pProcessCB->ActiveAuthGroup), &uniGUID); AFSDbgTrace(( AFS_SUBSYSTEM_AUTHGROUP_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "%s PID %I64X Session %08lX inherited Active AuthGroup %wZ from parent PID %I64X\n", __FUNCTION__, ullProcessID, ulSessionId, &uniGUID, pParentProcessCB->TreeEntry.HashIndex)); if( uniGUID.Buffer != NULL) { RtlFreeUnicodeString( &uniGUID); } } // // If an Auth Group was inherited, set it to be the active group // if( pProcessCB->ActiveAuthGroup != NULL && !AFSIsNoPAGAuthGroup( pParentProcessCB->ActiveAuthGroup)) { pAuthGroup = pProcessCB->ActiveAuthGroup; uniGUID.Buffer = NULL; RtlStringFromGUID( *(pProcessCB->ActiveAuthGroup), &uniGUID); AFSDbgTrace(( AFS_SUBSYSTEM_AUTHGROUP_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "%s Returning(1) Active AuthGroup %wZ for SID %wZ PID %I64X Session %08lX\n", __FUNCTION__, &uniGUID, &uniSIDString, ullProcessID, ulSessionId)); if( uniGUID.Buffer != NULL) { RtlFreeUnicodeString( &uniGUID); } try_return( ntStatus); } } } // // If no Auth Group was inherited, assign one based upon the Session and SID // ntStatus = RtlHashUnicodeString( &uniSIDString, TRUE, HASH_STRING_ALGORITHM_DEFAULT, &ulSIDHash); if( !NT_SUCCESS( ntStatus)) { AFSDbgTrace(( AFS_SUBSYSTEM_AUTHGROUP_PROCESSING, AFS_TRACE_LEVEL_ERROR, "%s Failed to hash SID %wZ for PID %I64X Session %08lX Status %08lX\n", __FUNCTION__, &uniSIDString, ullProcessID, ulSessionId, ntStatus)); try_return( ntStatus); } ullTableHash = ( ((ULONGLONG)ulSessionId << 32) | ulSIDHash); AFSAcquireShared( pDeviceExt->Specific.Control.AuthGroupTree.TreeLock, TRUE); ntStatus = AFSLocateHashEntry( pDeviceExt->Specific.Control.AuthGroupTree.TreeHead, (ULONGLONG)ullTableHash, (AFSBTreeEntry **)&pSIDEntryCB); if( !NT_SUCCESS( ntStatus) || pSIDEntryCB == NULL) { AFSReleaseResource( pDeviceExt->Specific.Control.AuthGroupTree.TreeLock); AFSAcquireExcl( pDeviceExt->Specific.Control.AuthGroupTree.TreeLock, TRUE); ntStatus = AFSLocateHashEntry( pDeviceExt->Specific.Control.AuthGroupTree.TreeHead, (ULONGLONG)ullTableHash, (AFSBTreeEntry **)&pSIDEntryCB); if( !NT_SUCCESS( ntStatus) || pSIDEntryCB == NULL) { pSIDEntryCB = (AFSSIDEntryCB *)AFSExAllocatePoolWithTag( NonPagedPool, sizeof( AFSSIDEntryCB), AFS_AG_ENTRY_CB_TAG); if( pSIDEntryCB == NULL) { AFSReleaseResource( pDeviceExt->Specific.Control.AuthGroupTree.TreeLock); try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); } RtlZeroMemory( pSIDEntryCB, sizeof( AFSSIDEntryCB)); pSIDEntryCB->TreeEntry.HashIndex = (ULONGLONG)ullTableHash; while( ExUuidCreate( &pSIDEntryCB->AuthGroup) == STATUS_RETRY); uniGUID.Buffer = NULL; RtlStringFromGUID( pSIDEntryCB->AuthGroup, &uniGUID); AFSDbgTrace(( AFS_SUBSYSTEM_AUTHGROUP_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "%s SID %wZ PID %I64X Session %08lX generated NEW AG %wZ\n", __FUNCTION__, &uniSIDString, ullProcessID, ulSessionId, &uniGUID)); if( uniGUID.Buffer != NULL) { RtlFreeUnicodeString( &uniGUID); } if( pDeviceExt->Specific.Control.AuthGroupTree.TreeHead == NULL) { pDeviceExt->Specific.Control.AuthGroupTree.TreeHead = (AFSBTreeEntry *)pSIDEntryCB; } else { AFSInsertHashEntry( pDeviceExt->Specific.Control.AuthGroupTree.TreeHead, &pSIDEntryCB->TreeEntry); } } AFSConvertToShared( pDeviceExt->Specific.Control.AuthGroupTree.TreeLock); } AFSReleaseResource( pDeviceExt->Specific.Control.AuthGroupTree.TreeLock); // // Store the auth group into the process cb // pProcessCB->ActiveAuthGroup = &pSIDEntryCB->AuthGroup; uniGUID.Buffer = NULL; RtlStringFromGUID( pSIDEntryCB->AuthGroup, &uniGUID); AFSDbgTrace(( AFS_SUBSYSTEM_AUTHGROUP_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "%s SID %wZ PID %I64X Session %08lX assigned AG %wZ\n", __FUNCTION__, &uniSIDString, ullProcessID, ulSessionId, &uniGUID)); if( uniGUID.Buffer != NULL) { RtlFreeUnicodeString( &uniGUID); } // // Set the AFS_PROCESS_LOCAL_SYSTEM_AUTH flag if the process SID // is LOCAL_SYSTEM // if( AFSIsLocalSystemSID( &uniSIDString)) { SetFlag( pProcessCB->Flags, AFS_PROCESS_LOCAL_SYSTEM_AUTH); AFSDbgTrace(( AFS_SUBSYSTEM_AUTHGROUP_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "%s Setting PID %I64X Session %08lX with LOCAL SYSTEM AUTHORITY\n", __FUNCTION__, ullProcessID, ulSessionId)); } // // Return the auth group // pAuthGroup = pProcessCB->ActiveAuthGroup; uniGUID.Buffer = NULL; RtlStringFromGUID( *(pProcessCB->ActiveAuthGroup), &uniGUID); AFSDbgTrace(( AFS_SUBSYSTEM_AUTHGROUP_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "%s Returning(2) Active AuthGroup %wZ for SID %wZ PID %I64X Session %08lX\n", __FUNCTION__, &uniGUID, &uniSIDString, ullProcessID, ulSessionId)); if( uniGUID.Buffer != NULL) { RtlFreeUnicodeString( &uniGUID); } try_exit: if( pProcessCB != NULL) { if( bImpersonation == FALSE && !BooleanFlagOn( pProcessCB->Flags, AFS_PROCESS_FLAG_ACE_SET) && NT_SUCCESS( ntStatus)) { ntStatus = AFSProcessSetProcessDacl( pProcessCB); if( !NT_SUCCESS( ntStatus)) { pAuthGroup = NULL; } else { SetFlag( pProcessCB->Flags, AFS_PROCESS_FLAG_ACE_SET); } } AFSReleaseResource( &pProcessCB->Lock); } if( pParentProcessCB != NULL) { AFSReleaseResource( &pParentProcessCB->Lock); } if( uniSIDString.Length > 0) { RtlFreeUnicodeString( &uniSIDString); } if ( !bProcessTreeLocked) { AFSReleaseResource( pDeviceExt->Specific.Control.ProcessTree.TreeLock); } } return pAuthGroup; }
NTSTATUS FatCommonDeviceControl ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ) /*++ Routine Description: This is the common routine for doing Device control operations called by both the fsd and fsp threads Arguments: Irp - Supplies the Irp to process InFsp - Indicates if this is the fsp thread or someother thread Return Value: NTSTATUS - The return status for the operation --*/ { NTSTATUS Status; PIO_STACK_LOCATION IrpSp; KEVENT WaitEvent; PVOID CompletionContext = NULL; PVCB Vcb; PFCB Fcb; PCCB Ccb; PAGED_CODE(); // // Get a pointer to the current Irp stack location // IrpSp = IoGetCurrentIrpStackLocation( Irp ); DebugTrace(+1, Dbg, "FatCommonDeviceControl\n", 0); DebugTrace( 0, Dbg, "Irp = %p\n", Irp); DebugTrace( 0, Dbg, "MinorFunction = %08lx\n", IrpSp->MinorFunction); // // Decode the file object, the only type of opens we accept are // user volume opens. // if (FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb ) != UserVolumeOpen) { FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); DebugTrace(-1, Dbg, "FatCommonDeviceControl -> %08lx\n", STATUS_INVALID_PARAMETER); return STATUS_INVALID_PARAMETER; } // // A few IOCTLs actually require some intervention on our part // switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) { case IOCTL_VOLSNAP_FLUSH_AND_HOLD_WRITES: // // This is sent by the Volume Snapshot driver (Lovelace). // We flush the volume, and hold all file resources // to make sure that nothing more gets dirty. Then we wait // for the IRP to complete or cancel. // SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ); FatAcquireExclusiveVolume( IrpContext, Vcb ); FatFlushAndCleanVolume( IrpContext, Irp, Vcb, FlushWithoutPurge ); KeInitializeEvent( &WaitEvent, NotificationEvent, FALSE ); CompletionContext = &WaitEvent; // // Get the next stack location, and copy over the stack location // IoCopyCurrentIrpStackLocationToNext( Irp ); // // Set up the completion routine // IoSetCompletionRoutine( Irp, FatDeviceControlCompletionRoutine, CompletionContext, TRUE, TRUE, TRUE ); break; case IOCTL_DISK_COPY_DATA: // // We cannot allow this IOCTL to be sent unless the volume is locked, // since this IOCTL allows direct writing of data to the volume. // We do allow kernel callers to force access via a flag. A handle that // issued a dismount can send this IOCTL as well. // if (!FlagOn( Vcb->VcbState, VCB_STATE_FLAG_LOCKED ) && !FlagOn( IrpSp->Flags, SL_FORCE_DIRECT_WRITE ) && !FlagOn( Ccb->Flags, CCB_FLAG_COMPLETE_DISMOUNT )) { FatCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED ); DebugTrace(-1, Dbg, "FatCommonDeviceControl -> %08lx\n", STATUS_ACCESS_DENIED); return STATUS_ACCESS_DENIED; } break; case IOCTL_SCSI_PASS_THROUGH: case IOCTL_SCSI_PASS_THROUGH_DIRECT: case IOCTL_SCSI_PASS_THROUGH_EX: case IOCTL_SCSI_PASS_THROUGH_DIRECT_EX: // // If someone is issuing a format unit command underneath us, then make // sure we mark the device as needing verification when they close their // handle. // if ((!FlagOn( IrpSp->FileObject->Flags, FO_FILE_MODIFIED ) || !FlagOn( Ccb->Flags, CCB_FLAG_SENT_FORMAT_UNIT )) && (Irp->AssociatedIrp.SystemBuffer != NULL)) { PCDB Cdb = NULL; // // If this is a 32 bit application running on 64 bit then thunk the // input structures to grab the Cdb. // #if defined (_WIN64) && defined(BUILD_WOW64_ENABLED) if (IoIs32bitProcess(Irp)) { if ( (IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH) || (IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT )) { if (IrpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof( SCSI_PASS_THROUGH32 )) { Cdb = (PCDB)((PSCSI_PASS_THROUGH32)(Irp->AssociatedIrp.SystemBuffer))->Cdb; } } else { if (IrpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof( SCSI_PASS_THROUGH32_EX )) { Cdb = (PCDB)((PSCSI_PASS_THROUGH32_EX)(Irp->AssociatedIrp.SystemBuffer))->Cdb; } } } else { #endif if ( (IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH) || (IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT )) { if (IrpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof( SCSI_PASS_THROUGH )) { Cdb = (PCDB)((PSCSI_PASS_THROUGH)(Irp->AssociatedIrp.SystemBuffer))->Cdb; } } else { if (IrpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof( SCSI_PASS_THROUGH_EX )) { Cdb = (PCDB)((PSCSI_PASS_THROUGH_EX)(Irp->AssociatedIrp.SystemBuffer))->Cdb; } } #if defined (_WIN64) && defined(BUILD_WOW64_ENABLED) } #endif if ((Cdb != NULL) && (Cdb->AsByte[0] == SCSIOP_FORMAT_UNIT)) { SetFlag( Ccb->Flags, CCB_FLAG_SENT_FORMAT_UNIT ); SetFlag( IrpSp->FileObject->Flags, FO_FILE_MODIFIED ); } } // // Fall through as we do not need to know the outcome of this operation. // default: // // FAT doesn't need to see this on the way back, so skip ourselves. // IoSkipCurrentIrpStackLocation( Irp ); break; } // // Send the request. // Status = IoCallDriver(Vcb->TargetDeviceObject, Irp); if (Status == STATUS_PENDING && CompletionContext) { KeWaitForSingleObject( &WaitEvent, Executive, KernelMode, FALSE, NULL ); Status = Irp->IoStatus.Status; } // // If we had a context, the IRP remains for us and we will complete it. // Handle it appropriately. // if (CompletionContext) { // // Release all the resources that we held because of a // VOLSNAP_FLUSH_AND_HOLD. // NT_ASSERT( IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_VOLSNAP_FLUSH_AND_HOLD_WRITES ); FatReleaseVolume( IrpContext, Vcb ); // // If we had no context, the IRP will complete asynchronously. // } else { Irp = NULL; } FatCompleteRequest( IrpContext, Irp, Status ); DebugTrace(-1, Dbg, "FatCommonDeviceControl -> %08lx\n", Status); return Status; }