windows-nt/Source/XPSP1/NT/drivers/wdm/usb/usbccgp/security.c
2020-09-26 16:20:57 +08:00

210 lines
6.8 KiB
C

/*
*************************************************************************
* File: SECURITY.C
*
* Module: USBCCGP.SYS
* USB Common Class Generic Parent driver.
*
* Copyright (c) 1998 Microsoft Corporation
*
*
* Author: ervinp
*
*************************************************************************
*/
#include <wdm.h>
#include <usbdi.h>
#include <usbdlib.h>
#include <usbioctl.h>
#include "usbccgp.h"
#include "security.h"
#include "debug.h"
NTSTATUS GetUniqueIdFromCSInterface(PPARENT_FDO_EXT parentFdoExt, PMEDIA_SERIAL_NUMBER_DATA serialNumData, ULONG serialNumLen)
{
PUCHAR uniqueIdBuf;
NTSTATUS status;
ULONG bufLen = 0;
// BUGBUG - check CSM#
/*
* Need to allocate a locked buffer for the call to USB.
*/
uniqueIdBuf = ALLOCPOOL(NonPagedPool, CSM1_GET_UNIQUE_ID_LENGTH);
if (uniqueIdBuf){
URB urb = { 0 };
urb.UrbHeader.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
urb.UrbHeader.Function = URB_FUNCTION_CLASS_INTERFACE;
urb.UrbControlVendorClassRequest.TransferFlags = USBD_TRANSFER_DIRECTION_IN;
urb.UrbControlVendorClassRequest.TransferBufferLength = CSM1_GET_UNIQUE_ID_LENGTH;
urb.UrbControlVendorClassRequest.TransferBuffer = uniqueIdBuf;
urb.UrbControlVendorClassRequest.Request = CSM1_REQUEST_GET_UNIQUE_ID;
urb.UrbControlVendorClassRequest.Value = 0;
urb.UrbControlVendorClassRequest.Index = (USHORT)(parentFdoExt->CSInterfaceNumber | (parentFdoExt->CSChannelId << 8));
status = SubmitUrb(parentFdoExt, &urb, TRUE, NULL, NULL);
if (NT_SUCCESS(status)){
bufLen = urb.UrbControlVendorClassRequest.TransferBufferLength;
ASSERT(bufLen <= CSM1_GET_UNIQUE_ID_LENGTH);
ASSERT(serialNumLen > 0);
bufLen = MIN(bufLen, CSM1_GET_UNIQUE_ID_LENGTH);
bufLen = MIN(bufLen, serialNumLen);
RtlCopyMemory(serialNumData->SerialNumberData, uniqueIdBuf, bufLen);
DBGDUMPBYTES("GetUniqueIdFromCSInterface - unique id:", serialNumData->SerialNumberData, bufLen);
}
else {
DBGERR(("CSM1_REQUEST_GET_UNIQUE_ID failed with %xh.", status));
}
FREEPOOL(uniqueIdBuf);
}
else {
DBGERR(("couldn't allocate unique id buf"));
status = STATUS_INSUFFICIENT_RESOURCES;
}
serialNumData->SerialNumberLength = bufLen;
serialNumData->Result = status;
return status;
}
NTSTATUS GetMediaSerialNumber(PPARENT_FDO_EXT parentFdoExt, PIRP irp)
{
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(irp);
PMEDIA_SERIAL_NUMBER_DATA serialNumData;
NTSTATUS status;
ULONG serialNumLen;
DBGVERBOSE(("*** IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER ***"));
/*
* IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER is a METHOD_BUFFERED irp.
* So the kernel allocated a systemBuffer for us IF the app passed
* in a non-zero buffer size. So we don't need to probe the buffer
* itself, but we do need to:
* 1. verify that the buffer was indeed allocated
* 2. that it is large enough
*
* The buffer is a var-size struct; be careful to not dereference any
* field until it is verified that the struct is longer than the offset
* of that field.
* Note that serialNumData->SerialNumberLength is the alleged size
* of the serialNumData->SerialNumberData array, not of the entire structure.
*/
serialNumData = irp->AssociatedIrp.SystemBuffer;
if (serialNumData &&
(irpSp->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(MEDIA_SERIAL_NUMBER_DATA))) {
// Serial number buffer length is the size of the output buffer minus
// the size of the MEDIA_SERIAL_NUMBER_DATA structure.
serialNumLen = irpSp->Parameters.DeviceIoControl.OutputBufferLength -
sizeof(MEDIA_SERIAL_NUMBER_DATA);
status = GetUniqueIdFromCSInterface(parentFdoExt, serialNumData, serialNumLen);
irp->IoStatus.Information = FIELD_OFFSET(MEDIA_SERIAL_NUMBER_DATA, SerialNumberData) +
serialNumData->SerialNumberLength;
}
else {
DBGERR(("Bad buffer with IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER, irp=%ph.", irp));
status = STATUS_INVALID_BUFFER_SIZE;
}
return status;
}
/*
* GetChannelDescForInterface
*
* BUGBUG - INCOMPLETE
* We don't support multiple channel descriptors yet.
* Eventually we'll need to return a channel id
* for a particular protected interface/endpoint.
*/
CS_CHANNEL_DESCRIPTOR *GetChannelDescForInterface(PPARENT_FDO_EXT parentFdoExt, ULONG interfaceNum)
{
PUSB_INTERFACE_DESCRIPTOR interfaceDesc;
CS_CHANNEL_DESCRIPTOR *channelDesc = NULL;
CS_METHOD_AND_VARIANT *methodAndVar;
interfaceDesc = USBD_ParseConfigurationDescriptorEx(
parentFdoExt->configDesc,
parentFdoExt->configDesc,
-1,
0, // BUGBUG - allow alternate CS interfaces ?
USB_DEVICE_CLASS_CONTENT_SECURITY,
-1,
-1);
if (interfaceDesc){
PUSB_COMMON_DESCRIPTOR commonDesc = (PUSB_COMMON_DESCRIPTOR)interfaceDesc;
while (POINTER_DISTANCE(commonDesc, parentFdoExt->configDesc) < parentFdoExt->configDesc->wTotalLength){
if (commonDesc->bDescriptorType == CS_DESCRIPTOR_TYPE_CHANNEL){
channelDesc = (CS_CHANNEL_DESCRIPTOR *)commonDesc;
break;
}
(PUCHAR)commonDesc += commonDesc->bLength;
}
}
if (channelDesc){
/*
* Make sure that this channel descriptor supports CSM1,
* which is all we support right now.
* BUGBUG
*/
BOOLEAN foundSupportedCSM = FALSE;
for (methodAndVar = channelDesc->methodAndVariant;
POINTER_DISTANCE(methodAndVar, channelDesc) < channelDesc->bLength;
methodAndVar++){
if (methodAndVar->bMethod == CSM_BASIC){
foundSupportedCSM = TRUE;
break;
}
}
if (!foundSupportedCSM){
DBGERR(("Did not find supported CSM !"));
channelDesc = NULL;
}
}
ASSERT(channelDesc);
return channelDesc;
}
VOID InitCSInfo(PPARENT_FDO_EXT parentFdoExt, ULONG CSIfaceNumber)
{
CS_CHANNEL_DESCRIPTOR *channelDesc;
channelDesc = GetChannelDescForInterface(parentFdoExt, 0); // BUGBUG iface# not used because only support one channel desc
if (channelDesc){
parentFdoExt->CSChannelId = channelDesc->bChannelID;
parentFdoExt->CSInterfaceNumber = CSIfaceNumber;
parentFdoExt->haveCSInterface = TRUE;
}
else {
ASSERT(channelDesc);
}
}