Windows2003-3790/multimedia/wmdm_sr1/common/serialnumber/serialid.cpp
2020-09-30 16:53:55 +02:00

1299 lines
41 KiB
C++

//-----------------------------------------------------------------------------
//
// File: serialid.cpp
//
// Microsoft Digital Rights Management
// Copyright (C) Microsoft Corporation, 1998 - 1999, All Rights Reserved
//
// Description:
//
//-----------------------------------------------------------------------------
#include <windows.h>
#include <stddef.h>
#include "drmerr.h"
#include "aspi32.h"
#include "serialid.h"
#include "spti.h"
//#include "KBDevice.h"
#include <crtdbg.h>
HRESULT __stdcall UtilStartStopService(bool fStartService);
// #define WRITE_TO_LOG_FILE
#if defined(DBG) || defined(WRITE_TO_LOG_FILE)
#include <stdio.h>
#endif
void DebugMsg(const char* pszFormat, ...)
{
#if defined(DBG) || defined(WRITE_TO_LOG_FILE)
char buf[1024];
sprintf(buf, "[Serial Number Library](%lu): ", GetCurrentThreadId());
va_list arglist;
va_start(arglist, pszFormat);
vsprintf(&buf[strlen(buf)], pszFormat, arglist);
va_end(arglist);
strcat(buf, "\n");
#if defined(DBG)
OutputDebugString(buf);
#endif
#if defined(WRITE_TO_LOG_FILE)
FILE* fp = fopen("c:\\WmdmService.txt", "a");
if (fp)
{
fprintf(fp, buf);
fclose(fp);
}
#endif
#endif
}
#ifdef USE_IOREADY
#ifndef __Using_iomegaReady_Lib__
#define __Using_iomegaReady_Lib__
#endif
#include "ioReadyMin.h"
#endif
#define WCS_PMID_SOFT L"media.id"
BOOL IsWinNT()
{
OSVERSIONINFO osvi;
BOOL bRet=FALSE;
ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if ( ! GetVersionEx ( (OSVERSIONINFO *) &osvi) )
return FALSE;
switch ( osvi.dwPlatformId )
{
case VER_PLATFORM_WIN32_NT:
bRet=TRUE;
break;
case VER_PLATFORM_WIN32_WINDOWS:
bRet=FALSE;
break;
case VER_PLATFORM_WIN32s:
bRet=FALSE;
break;
}
return bRet;
}
BOOL IsAdministrator(DWORD& dwLastError)
{
dwLastError = ERROR_SUCCESS;
if ( IsWinNT() )
{
/* typedef SC_HANDLE (*T_POSCM)(LPCTSTR,LPCTSTR,DWORD);
T_POSCM p_OpenSCM=NULL;
p_OpenSCM = (T_POSCM)GetProcAddress(GetModuleHandle("advapi32.dll"), "OpenSCManagerA");
if( !p_OpenSCM )
{
return FALSE;
}
*/
SC_HANDLE hSCM = OpenSCManagerA(NULL, // local machine
NULL, // ServicesActive database
SC_MANAGER_ALL_ACCESS); // full access
if ( !hSCM )
{
dwLastError = GetLastError();
if (dwLastError == ERROR_ACCESS_DENIED)
{
dwLastError = ERROR_SUCCESS;
}
return FALSE;
}
else
{
CloseServiceHandle(hSCM);
return TRUE;
}
}
else // On Win9x, everybody is admin
{
return TRUE;
}
}
UINT __stdcall UtilGetDriveType(LPSTR szDL)
{
return GetDriveTypeA(szDL);
}
BOOL IsIomegaDrive(DWORD dwDriveNum)
{
BOOL bRet=FALSE;
#ifdef USE_IOREADY
if (dwDriveNum >= 26)
{
return bRet;
}
ioReady::Drive *pDrive = NULL;
pDrive = new ioReady::Drive((int) dwDriveNum);
if ( pDrive )
{
if ( pDrive->isIomegaDrive() )
bRet=TRUE;
delete pDrive;
}
#endif
DebugMsg("IsIomegaDrive returning %u", bRet);
return bRet;
}
BOOL GetIomegaDiskSerialNumber(DWORD dwDriveNum, PWMDMID pSN)
{
BOOL bRet=FALSE;
#ifdef USE_IOREADY
if (dwDriveNum >= 26)
{
return bRet;
}
ioReady::Drive *pDrive = NULL;
char *pszSerial = NULL;
pDrive = new ioReady::Drive((int) dwDriveNum);
if ( pDrive )
{
if ( pDrive->isIomegaDrive() )
{
ioReady::Disk &refDisk = pDrive->getDisk();
pszSerial = (char *)refDisk.getMediaSerialNumber();
if ( pszSerial[0] )
{
ZeroMemory(pSN->pID, WMDMID_LENGTH);
if (ioReady::ct_nSerialNumberLength <= sizeof(pSN->pID))
{
CopyMemory(pSN->pID, pszSerial, ioReady::ct_nSerialNumberLength);
pSN->SerialNumberLength = ioReady::ct_nSerialNumberLength;
pSN->dwVendorID = MDSP_PMID_IOMEGA;
bRet = TRUE;
}
}
}
}
delete pDrive;
#endif
return bRet;
}
HRESULT __stdcall UtilGetManufacturer(LPWSTR pDeviceName, LPWSTR *ppwszName, UINT nMaxChars)
{
HRESULT hr=S_OK;
CARg(pDeviceName);
CARg(ppwszName);
CPRg(nMaxChars>16); // ensure enough buffer size
DWORD dwDriveNum;
// We use only the first char of pDeviceName and expect it to
// be a drive letter. The rest of pDeviceName is not validated.
// Perhaps it should, but we don't want to break our clients.
if (pDeviceName[0] >= L'A' && pDeviceName[0] <= L'Z')
{
dwDriveNum = pDeviceName[0] - L'A';
}
else if (pDeviceName[0] >= L'a' && pDeviceName[0] <= L'z')
{
dwDriveNum = pDeviceName[0] - L'a';
}
else
{
hr = E_INVALIDARG;
goto Error;
}
if ( IsIomegaDrive(dwDriveNum) )
wcscpy(*ppwszName, L"Iomega");
else
{
wcscpy(*ppwszName, L"Unknown");
WMDMID snData;
snData.cbSize = sizeof(WMDMID);
if ( S_OK==UtilGetSerialNumber(pDeviceName, &snData, FALSE) )
{
switch ( snData.dwVendorID )
{
case 1:
wcscpy(*ppwszName, L"SanDisk");
break;
case 2:
wcscpy(*ppwszName, L"Iomega");
break;
}
}
}
Error:
return hr;
}
#include <winioctl.h>
// This is defined in the Whistler platform SDK.
#ifndef IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER
#define IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER CTL_CODE( \
IOCTL_STORAGE_BASE, 0x304, METHOD_BUFFERED, FILE_ANY_ACCESS )
#endif
HRESULT GetMSNWithNtIoctl(LPCWSTR wcsDevice, PWMDMID pSN)
{
HRESULT hr=S_OK;
HANDLE hDevice = INVALID_HANDLE_VALUE;
BOOL bResult;
MEDIA_SERIAL_NUMBER_DATA MSNGetSize;
MEDIA_SERIAL_NUMBER_DATA* pMSN = NULL; // Buffer to hold the serial number
DWORD dwBufferSize; // Size of pMSNNt buffer
ULONG i;
DWORD dwRet = 0; // Bytes returned
CARg(pSN);
DebugMsg("Entering GetMSNWithNtIoctl");
hDevice = CreateFileW( wcsDevice,
GENERIC_READ,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL |
SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS,
NULL);
CWRg(hDevice != INVALID_HANDLE_VALUE);
DebugMsg("GetMSNWithNtIoctl: CreateFile ok");
// Get size of buffer we need to allocate
bResult = DeviceIoControl( hDevice,
IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER,
NULL,
0,
(LPVOID)&MSNGetSize,
sizeof(MEDIA_SERIAL_NUMBER_DATA),
&dwRet,
NULL);
// Handle expected buffer overrun error
if ( !bResult )
{
hr = HRESULT_FROM_WIN32(GetLastError());
// Error 'more data is available' is an expected error code
if ( hr == HRESULT_FROM_WIN32(ERROR_MORE_DATA) )
{
hr = S_OK;
}
else goto Error;
}
DebugMsg("GetMSNWithNtIoctl: DeviceIoControl1 ok");
if (dwRet < RTL_SIZEOF_THROUGH_FIELD(MEDIA_SERIAL_NUMBER_DATA, SerialNumberLength))
{
DebugMsg("GetMSNWithNtIoctl: DeviceIoControl1 dwRet bad: %u, expected >= %u",
dwRet, RTL_SIZEOF_THROUGH_FIELD(MEDIA_SERIAL_NUMBER_DATA, SerialNumberLength));
hr = E_INVALIDARG;
goto Error;
}
// No serial number?
if ( MSNGetSize.SerialNumberLength == 0 )
{
DebugMsg("GetMSNWithNtIoctl: DeviceIoControl1: MSNGetSize.SerialNumberLength == 0");
hr = E_FAIL;
goto Error;
}
// The WMDMID structure we are using can only handle 128 bytes long serial numbers
if ( MSNGetSize.SerialNumberLength > WMDMID_LENGTH )
{
DebugMsg("GetMSNWithNtIoctl: DeviceIoControl1: MSNGetSize.SerialNumberLength > WMDMID_LENGTH");
hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
goto Error;
}
// Allocate buffer and call to get the serial number
dwBufferSize = sizeof(MEDIA_SERIAL_NUMBER_DATA) + MSNGetSize.SerialNumberLength;
pMSN = (MEDIA_SERIAL_NUMBER_DATA*) new BYTE[dwBufferSize];
if ( pMSN == NULL )
{
DebugMsg("GetMSNWithNtIoctl: Out of memory allocating %u bytes", dwBufferSize);
hr = E_OUTOFMEMORY;
goto Error;
}
bResult = DeviceIoControl( hDevice,
IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER,
NULL,
0,
(LPVOID)pMSN,
dwBufferSize,
&dwRet,
NULL);
if ( !bResult )
{
hr = HRESULT_FROM_WIN32(GetLastError());
DebugMsg("GetMSNWithNtIoctl: DeviceIoControl2 failed, hr = 0x%x", hr);
goto Error;
}
if (dwRet < FIELD_OFFSET(MEDIA_SERIAL_NUMBER_DATA, SerialNumberData) + pMSN->SerialNumberLength)
{
hr = E_INVALIDARG;
DebugMsg("GetMSNWithNtIoctl: DeviceIoControl1: MSNGetSize.SerialNumberLength == 0");
goto Error;
}
if (pMSN->SerialNumberLength > sizeof(pSN->pID))
{
hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
DebugMsg("GetMSNWithNtIoctl: DeviceIoControl2: MSNGetSize.SerialNumberLength > WMDMID_LENGTH");
goto Error;
}
// Copy serial number to out structure
memcpy( pSN->pID, pMSN->SerialNumberData, pMSN->SerialNumberLength );
pSN->SerialNumberLength = pMSN->SerialNumberLength;
// Check result
pSN->dwVendorID = MDSP_PMID_SANDISK;
if ( pSN->SerialNumberLength > 24 )
{
char szVID[4];
for ( i=0; i<3; i++ )
{
szVID[i]=(pSN->pID[18+i]);
}
szVID[i]=0;
LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
SORT_DEFAULT);
// if ( !lstrcmpiA(szVID, "ZIP") ||
// !lstrcmpiA(szVID, "JAZ") ||
// !lstrcmpiA(szVID, "CLI") )
if (CompareStringA(lcid, NORM_IGNORECASE, szVID, -1, "ZIP", -1) == CSTR_EQUAL ||
CompareStringA(lcid, NORM_IGNORECASE, szVID, -1, "JAZ", -1) == CSTR_EQUAL ||
CompareStringA(lcid, NORM_IGNORECASE, szVID, -1, "CLI", -1) == CSTR_EQUAL)
{
pSN->dwVendorID = MDSP_PMID_IOMEGA;
}
}
if ( (pSN->dwVendorID==MDSP_PMID_IOMEGA) && (pSN->SerialNumberLength>19) )
{
pSN->SerialNumberLength = 19;
pSN->pID[18] = 0;
}
DebugMsg("GetMSNWithNtIoctl ok, pSN->SerialNumberLength = %u", pSN->SerialNumberLength);
Error:
if ( hDevice != INVALID_HANDLE_VALUE ) CloseHandle(hDevice);
if ( pMSN ) delete [] pMSN;
return hr;
}
HRESULT GetMSNWith9xIoctl(char chDriveLetter, PWMDMID pSN, DWORD dwCode, DWORD dwIOCTL )
{
HRESULT hr=S_OK;
HANDLE hDevice=INVALID_HANDLE_VALUE;
BOOL bResult;
MEDIA_SERIAL_NUMBER_DATA MSNGetSize;
MEDIA_SERIAL_NUMBER_DATA* pMSN = NULL; // Buffer to hold the serial number
ULONG uBufferSize; // Size of pMSN
DWORD dwRet = 0; // Bytes returned
// _ASSERT( dwCode == 0x440D ||
// dwCode == 0x4404 );
// _ASSERT( (dwIOCTL == (0x0800 | 0x75)) ||
// (dwIOCTL == WIN9X_IOCTL_GET_MEDIA_SERIAL_NUMBER) );
CARg(pSN);
hDevice = CreateFile("\\\\.\\VWIN32",0,0,NULL,OPEN_EXISTING,FILE_FLAG_DELETE_ON_CLOSE,0);
CFRg(hDevice != INVALID_HANDLE_VALUE);
DIOC_REGISTERS reg;
DWORD cb;
WORD drv;
drv = (chDriveLetter >= 'a' ) ? (chDriveLetter-'a') : (chDriveLetter-'A');
// Call first to get serial number size
{
MSNGetSize.SerialNumberLength = 0;
reg.reg_EAX = dwCode; //create the ioctl
reg.reg_EBX = drv;
reg.reg_EBX++;
reg.reg_ECX = dwIOCTL; // BUGBUG, needs definition of 0x75
//
// ISSUE: The following code will not work on 64-bit systems.
// The conditional is only to get the code to compiler.
//
#if defined(_WIN64)
reg.reg_EDX = (DWORD)(DWORD_PTR)&MSNGetSize;
#else
reg.reg_EDX = (DWORD)&MSNGetSize;
#endif
reg.reg_Flags = 0x0001;
bResult = DeviceIoControl( hDevice,
VWIN32_DIOC_DOS_IOCTL,
&reg,
sizeof(DIOC_REGISTERS),
&reg,
sizeof(DIOC_REGISTERS),
&cb,
NULL );
// Check for errors
if ( bResult && !(reg.reg_Flags&0x0001) )
{
if ( (MSNGetSize.Result != ERROR_SUCCESS) &&
(MSNGetSize.Result != ERROR_MORE_DATA ) )
{
hr = HRESULT_FROM_WIN32(MSNGetSize.Result);
goto Error;
}
}
// No serial number?
if ( MSNGetSize.SerialNumberLength == 0 )
{
hr = E_FAIL;
goto Error;
}
// Max serial number size is 128 byte right now
if ( MSNGetSize.SerialNumberLength > WMDMID_LENGTH )
{
hr = E_FAIL;
goto Error;
}
// Allocate buffer to get serial number
uBufferSize = MSNGetSize.SerialNumberLength + sizeof(MEDIA_SERIAL_NUMBER_DATA);
pMSN = (MEDIA_SERIAL_NUMBER_DATA*) new BYTE[uBufferSize];
if ( pMSN == NULL )
{
hr = E_OUTOFMEMORY;
goto Error;
}
}
// Call again to accually get the serial number
{
pMSN->SerialNumberLength = uBufferSize;
reg.reg_EAX = dwCode; //create the ioctl
reg.reg_EBX = drv;
reg.reg_EBX++;
reg.reg_ECX = dwIOCTL; // BUGBUG, needs definition of 0x75
//
// ISSUE: The following code will not work on 64-bit systems.
// The conditional is only to get the code to compiler.
//
#if defined(_WIN64)
reg.reg_EDX = (DWORD)0;
#else
reg.reg_EDX = (DWORD)pMSN;
#endif
reg.reg_Flags = 0x0001;
bResult = DeviceIoControl( hDevice,
VWIN32_DIOC_DOS_IOCTL,
&reg,
sizeof(DIOC_REGISTERS),
&reg,
sizeof(DIOC_REGISTERS),
&cb,
NULL );
// Check for errors
if ( bResult && !(reg.reg_Flags&0x0001) )
{
if ( (pMSN->Result != ERROR_SUCCESS) )
{
hr = HRESULT_FROM_WIN32(pMSN->Result);
goto Error;
}
}
}
// Copy serial number to out structure
// and 'figure out' vendor
{
memcpy( pSN->pID, pMSN->SerialNumberData, pMSN->SerialNumberLength );
pSN->SerialNumberLength = pMSN->SerialNumberLength;
pSN->dwVendorID = MDSP_PMID_SANDISK;
if ( pSN->SerialNumberLength > 24 )
{
char szVID[4];
ULONG i;
for ( i=0; i<3; i++ )
{
szVID[i]=(pSN->pID[18+i]);
}
szVID[i]=0;
LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
SORT_DEFAULT);
// if ( !lstrcmpiA(szVID, "ZIP") ||
// !lstrcmpiA(szVID, "JAZ") ||
// !lstrcmpiA(szVID, "CLI") )
if (CompareStringA(lcid, NORM_IGNORECASE, szVID, -1, "ZIP", -1) == CSTR_EQUAL ||
CompareStringA(lcid, NORM_IGNORECASE, szVID, -1, "JAZ", -1) == CSTR_EQUAL ||
CompareStringA(lcid, NORM_IGNORECASE, szVID, -1, "CLI", -1) == CSTR_EQUAL)
{
pSN->dwVendorID = MDSP_PMID_IOMEGA;
}
}
if ( (pSN->dwVendorID==MDSP_PMID_IOMEGA) && (pSN->SerialNumberLength>19) )
{
pSN->SerialNumberLength = 19;
pSN->pID[18] = 0;
}
}
Error:
if ( hDevice != INVALID_HANDLE_VALUE ) CloseHandle(hDevice);
if ( pMSN ) delete [] pMSN;
return hr;
}
HRESULT GetDeviceSNwithNTScsiPassThrough(LPCWSTR wszDevice, PWMDMID pSN)
{
HRESULT hr=S_OK;
HANDLE fileHandle=INVALID_HANDLE_VALUE;
UCHAR buffer[2048];
BOOL status;
ULONG returned, length, i, bufOffset;
SCSI_PASS_THROUGH_WITH_BUFFERS sptwb;
PSCSI_ADAPTER_BUS_INFO adapterInfo;
PSCSI_INQUIRY_DATA inquiryData;
DebugMsg("Entering GetDeviceSNwithNTScsiPassThrough");
ZeroMemory(pSN, sizeof(WMDMID));
fileHandle = CreateFileW(wszDevice,
GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS,
NULL);
CWRg(fileHandle != INVALID_HANDLE_VALUE);
DebugMsg("GetDeviceSNwithNTScsiPassThrough: CreateFile ok");
status = DeviceIoControl(fileHandle,
IOCTL_SCSI_GET_INQUIRY_DATA,
NULL,
0,
buffer,
sizeof(buffer),
&returned,
FALSE);
// CWRg(status);
// We use IOCTL_SCSI_GET_INQUIRY_DATA to get the disk's SCSI address, if
// this fails, it is not on a SCSI bus so the SCSI address will be all zeros
if ( status )
{
DebugMsg("GetDeviceSNwithNTScsiPassThrough: DeviceIoControl1 ok");
if (returned < sizeof(SCSI_ADAPTER_BUS_INFO))
{
DebugMsg("GetDeviceSNwithNTScsiPassThrough: DeviceIoControl1 returned = %u < sizeof(SCSI_ADAPTER_BUS_INFO) = %u",
returned, sizeof(SCSI_ADAPTER_BUS_INFO));
hr = E_INVALIDARG;
goto Error;
}
adapterInfo = (PSCSI_ADAPTER_BUS_INFO) buffer;
CFRg(adapterInfo->NumberOfBuses>0);
if (returned < adapterInfo->BusData[0].InquiryDataOffset + sizeof(SCSI_INQUIRY_DATA))
{
hr = E_INVALIDARG;
DebugMsg("GetDeviceSNwithNTScsiPassThrough: DeviceIoControl1 returned = %u < adapterInfo->BusData[0].InquiryDataOffset (%u) + sizeof(SCSI_INQUIRY_DATA) (%u)",
returned, adapterInfo->BusData[0].InquiryDataOffset, sizeof(SCSI_INQUIRY_DATA));
goto Error;
}
inquiryData = (PSCSI_INQUIRY_DATA) (buffer +
adapterInfo->BusData[0].InquiryDataOffset); // we know card readers has only one bus
}
ZeroMemory(&sptwb,sizeof(sptwb));
sptwb.spt.Length = sizeof(SCSI_PASS_THROUGH);
sptwb.spt.PathId = (status?inquiryData->PathId:0);
sptwb.spt.TargetId = (status?inquiryData->TargetId:0);
sptwb.spt.Lun = (status?inquiryData->Lun:0);
sptwb.spt.CdbLength = CDB6GENERIC_LENGTH;
sptwb.spt.SenseInfoLength = 24;
sptwb.spt.DataIn = SCSI_IOCTL_DATA_IN;
sptwb.spt.DataTransferLength = 256 /*256*/;
sptwb.spt.TimeOutValue = 2;
sptwb.spt.DataBufferOffset =
offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf);
sptwb.spt.SenseInfoOffset =
offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucSenseBuf);
sptwb.spt.Cdb[0] = 0x12 /* Command - SCSIOP_INQUIRY */;
sptwb.spt.Cdb[1] = 0x01; /* Request - VitalProductData */
sptwb.spt.Cdb[2] = 0x80 /* VPD page 80 - serial number page */;
sptwb.spt.Cdb[3] = 0;
sptwb.spt.Cdb[4] = 0xff /*255*/;
sptwb.spt.Cdb[5] = 0;
length = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf) +
sptwb.spt.DataTransferLength;
status = DeviceIoControl(fileHandle,
IOCTL_SCSI_PASS_THROUGH,
&sptwb,
sizeof(SCSI_PASS_THROUGH),
&sptwb,
length,
&returned,
FALSE);
CWRg(status);
// CFRg(sptwb.ucDataBuf[3]>0);
// Keep or remove this @@@@
if (returned < offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf) + 4)
{
hr = E_INVALIDARG;
DebugMsg("GetDeviceSNwithNTScsiPassThrough: DeviceIoControl2 returned = %u < offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf) + 4 = %u",
returned, offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf) + 4);
goto Error;
}
// Here there is a difference between Parallel and USB Unit:
// Since the Parallel Unit is an emulation of SCSI disk, it doesn't follow SCSI spec.
pSN->SerialNumberLength=0;
pSN->dwVendorID=0;
if ( sptwb.ucDataBuf[3] == 0 ) // this is the SanDisk USB device
{
pSN->SerialNumberLength = 20;
// Keep or remove this @@@@
if (returned < offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf) + 5)
{
hr = E_INVALIDARG;
DebugMsg("GetDeviceSNwithNTScsiPassThrough: DeviceIoControl2 returned = %u < offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf) + 5 = %u",
returned, offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf) + 5);
goto Error;
}
if ( sptwb.ucDataBuf[4] > 0 )
{
if ((DWORD) (sptwb.ucDataBuf[4]) + 5 >= (DWORD) (pSN->SerialNumberLength))
{
bufOffset=(sptwb.ucDataBuf[4]+5)-(pSN->SerialNumberLength);
}
else
{
hr = E_INVALIDARG;
goto Error;
}
}
else
{ // There are 50K ImageMate III devices that read like this
bufOffset=36;
}
}
else if ( sptwb.ucDataBuf[3] > 0 )
{
pSN->SerialNumberLength = sptwb.ucDataBuf[3];
bufOffset=4;
}
DebugMsg("GetDeviceSNwithNTScsiPassThrough: DeviceIoControl2 pSN->SerialNumberLength = %u",
pSN->SerialNumberLength);
// The WMDMID structure we are using can only handle 128 bytes long serial numbers
if ( pSN->SerialNumberLength > WMDMID_LENGTH )
{
hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
DebugMsg("GetDeviceSNwithNTScsiPassThrough: DeviceIoControl2 pSN->SerialNumberLength > WMDMID_LENGTH = %u", WMDMID_LENGTH);
goto Error;
}
// Keep or remove this @@@@
if (returned < offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf) + bufOffset + pSN->SerialNumberLength)
{
hr = E_INVALIDARG;
DebugMsg("GetDeviceSNwithNTScsiPassThrough: DeviceIoControl2 returned = %u < offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf) (=%u) + bufOffset (=%u) + pSN->SerialNumberLength) (=%u) = %u",
returned, offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf), bufOffset, pSN->SerialNumberLength,
offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf) + bufOffset + pSN->SerialNumberLength);
goto Error;
}
for ( i=0; i<pSN->SerialNumberLength; i++ )
{
pSN->pID[i] = sptwb.ucDataBuf[bufOffset+i];
if ( !(pSN->dwVendorID) && pSN->pID[i] && pSN->pID[i] != 0x20 )
pSN->dwVendorID = MDSP_PMID_SANDISK;
}
if ( !(pSN->dwVendorID) )
hr=S_FALSE;
else
hr=S_OK;
Error:
if ( fileHandle != INVALID_HANDLE_VALUE )
CloseHandle(fileHandle);
DebugMsg("GetDeviceSNwithNTScsiPassThrough: returning hr = 0x%x", hr);
return hr;
}
HRESULT GetMediaSerialNumberFromNTService(DWORD dwDN, PWMDMID pSN)
{
HANDLE hPipe = INVALID_HANDLE_VALUE;
BYTE ubBuf[256];
BOOL fSuccess;
DWORD cbRead, cbWritten;
WCHAR wszPipename[64] = L"\\\\.\\pipe\\WMDMPMSPpipe";
DWORD dwErr;
PMEDIA_SERIAL_NUMBER_DATA pMSN;
HRESULT hr;
BOOL bStarted = 0;
if (dwDN >= 26)
{
_ASSERTE(dwDN < 26);
hr = E_INVALIDARG;
goto ErrorExit;
}
// Try to open a named pipe; wait for it, if necessary.
for ( DWORD dwTriesLeft = 3; dwTriesLeft; dwTriesLeft -- )
{
// Set the impersonation level to the lowest one that works.
// The real server impersonates us to validate the drive type.
// SECURITY_ANONYMOUS is enough for this as long as the drive
// specified is of the form x: (i.e., is not an ms-dos device name
// in the DosDevices directory)
hPipe = CreateFileW(
wszPipename,
GENERIC_READ |GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS,
NULL
);
// Break if the pipe handle is valid.
if ( hPipe != INVALID_HANDLE_VALUE )
{
// Success
fSuccess=TRUE;
break;
}
// If all pipe instances are busy or if server has not yet created
// the first instance of the named pipe, wait for a while and retry.
// Else, exit.
dwErr=GetLastError();
DebugMsg("GetMediaSerialNumberFromNTService(): CreateFile on drive %u failed, last err = %u, Tries left = %u, bStarted = %d",
dwDN, dwErr, dwTriesLeft, bStarted);
if ( dwErr != ERROR_PIPE_BUSY && dwErr != ERROR_FILE_NOT_FOUND)
{
fSuccess=FALSE;
break;
}
if (dwErr == ERROR_FILE_NOT_FOUND && !bStarted)
{
dwTriesLeft++; // Don't count this iteration
bStarted = 1;
// We start the service here because the service now
// times out sfter a period of inactivity.
// We ignore errors. If the start fails, we'll
// timeout anyway. (If we did respond to errors, note
// that the service may already be running and that
// shuld not be considered an error.)
UtilStartStopService(TRUE);
// Wait for service to start
for (DWORD i = 2; i > 0; i--)
{
Sleep(1000);
if (WaitNamedPipeW(wszPipename, 0))
{
// Service is up and running and a pipe instance
// is available
break;
}
else
{
// Either the service has not yet started or no
// pipe instance is available. Just keep going.
}
}
// Even if the wait for the named pipe failed,
// go on. We'll try once more below and bail out.
}
// All pipe instances are busy (or the service is starting),
// so wait for 1 second.
// Note: Do not use NMPWAIT_USE_DEFAULT_WAIT since the
// server of this named pipe may be spoofing our server
// and may have the set the default very high.
if ( ! WaitNamedPipeW(wszPipename, 1000) )
{
fSuccess=FALSE;
break;
}
} // end of for loop
if ( !fSuccess )
{
hr=HRESULT_FROM_WIN32(ERROR_CANTOPEN);
goto ErrorExit;
}
ZeroMemory(ubBuf, sizeof(ubBuf));
pMSN = (PMEDIA_SERIAL_NUMBER_DATA)ubBuf;
// pMSN->SerialNumberLength = 128;
pMSN->Reserved[1] = dwDN;
DWORD cbTotalWritten = 0;
do
{
fSuccess = WriteFile(
hPipe, // pipe handle
ubBuf + cbTotalWritten, // message
sizeof(*pMSN)- cbTotalWritten, // +128, // message length
&cbWritten, // bytes written
NULL // not overlapped
);
if ( !fSuccess) // || cbWritten != sizeof(*pMSN))
{
hr=HRESULT_FROM_WIN32(ERROR_CANTWRITE);
goto ErrorExit;
}
cbTotalWritten += cbWritten;
_ASSERTE(cbTotalWritten <= sizeof(*pMSN));
}
while (cbTotalWritten < sizeof(*pMSN));
DWORD cbTotalRead = 0;
DWORD cbTotalToRead;
do
{
// Read from the pipe.
fSuccess = ReadFile(
hPipe, // pipe handle
ubBuf + cbTotalRead, // buffer to receive reply
sizeof(ubBuf) - cbTotalRead, // size of buffer
&cbRead, // number of bytes read
NULL // not overlapped
);
// This is a byte mode pipe, not a message mode one, so we
// do not expect ERROR_MORE_DATA. Anyway, let this be as is.
if ( !fSuccess && (dwErr=GetLastError()) != ERROR_MORE_DATA )
{
break;
}
cbTotalRead += cbRead;
_ASSERTE(cbTotalRead <= sizeof(ubBuf));
// We expect at least FIELD_OFFSET(MEDIA_SERIAL_NUMBER_DATA, SerialNumberData)
// bytes in the response
cbTotalToRead = FIELD_OFFSET(MEDIA_SERIAL_NUMBER_DATA, SerialNumberData);
if (cbTotalRead >= cbTotalToRead)
{
pMSN = (PMEDIA_SERIAL_NUMBER_DATA)ubBuf;
if ( ERROR_SUCCESS == pMSN->Result )
{
cbTotalToRead += pMSN->SerialNumberLength;
}
else
{
cbTotalToRead = sizeof(MEDIA_SERIAL_NUMBER_DATA);
}
// Server should write exactly cbTotalToRead bytes.
// We should not have read any more because
// we wrote only 1 request. (If we write >1 request, we may
// get responses to both request.)
_ASSERTE(cbTotalRead <= cbTotalToRead);
if (cbTotalToRead > sizeof(ubBuf))
{
// We don't expect this. Server bad?
fSuccess = FALSE;
break;
}
}
else
{
// cbTotalToRead does not have to be changed
}
} while ( !fSuccess || cbTotalRead < cbTotalToRead); // repeat loop if ERROR_MORE_DATA
if ( fSuccess )
{
pMSN = (PMEDIA_SERIAL_NUMBER_DATA)ubBuf;
if ( ERROR_SUCCESS == pMSN->Result &&
pMSN->SerialNumberLength <= sizeof(pSN->pID))
{
CopyMemory(pSN->pID, pMSN->SerialNumberData, pMSN->SerialNumberLength);
pSN->SerialNumberLength = pMSN->SerialNumberLength;
pSN->dwVendorID = pMSN->Reserved[1];
pSN->cbSize = sizeof(*pSN);
hr=S_OK;
}
else if (pMSN->Result != ERROR_SUCCESS)
{
hr = HRESULT_FROM_WIN32(pMSN->Result);
}
else
{
hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
}
else
{
hr=HRESULT_FROM_WIN32(ERROR_CANTREAD);
}
ErrorExit:
if ( hPipe != INVALID_HANDLE_VALUE )
CloseHandle(hPipe);
return hr;
}
HRESULT UtilGetHardSN(WCHAR *wcsDeviceName, DWORD dwDriveNum, PWMDMID pSN)
{
HRESULT hr=S_OK;
ULONG i;
DebugMsg("Entering UtilGetHardSN, drivenum %u", dwDriveNum);
CARg(pSN);
DWORD dwLastError;
if ( IsAdministrator(dwLastError) )
{
// Convert device name to an ascii char - done only on Win9x
char szTmp[MAX_PATH];
*szTmp = 0;
// Following only for NT. If we have a DOS device name, use it.
// Else, open the drive letter.
WCHAR wcsDriveName[] = L"\\\\.\\?:";
if (dwDriveNum >= 26)
{
_ASSERTE(dwDriveNum < 26);
hr = E_INVALIDARG;
goto Error;
}
LPCWSTR wcsDeviceToOpen = wcsDriveName;
wcsDriveName[4] = (WCHAR) (dwDriveNum + L'A');
// Try IOCTL calls
if ( IsWinNT() )
{
// NT, try IOCTL_GET_MEDIA_SERIAL_NUMBER method first
hr = GetMSNWithNtIoctl(wcsDeviceToOpen, pSN);
}
else
{
if ( WideCharToMultiByte(CP_ACP, NULL, wcsDeviceName, -1, szTmp, sizeof(szTmp), NULL, NULL) == 0 )
{
hr = E_INVALIDARG;
goto Error;
}
// Try two other IOCTL calls on Win9x
hr = GetMSNWith9xIoctl( szTmp[0], pSN, 0x440D, (0x0800 | 0x75) );
if ( FAILED(hr) )
{
hr = GetMSNWith9xIoctl( szTmp[0], pSN, 0x4404, WIN9X_IOCTL_GET_MEDIA_SERIAL_NUMBER );
}
}
// Try Iomega
if ( FAILED(hr) )
{
if ( IsIomegaDrive(dwDriveNum) )
{
if ( GetIomegaDiskSerialNumber(dwDriveNum, pSN) )
{
hr=S_OK;
}
else
{
hr = E_FAIL;
goto Error;
}
}
}
// Try new SCSI_PASS_THROUGH "Get Media Serial Number" command
if ( FAILED(hr) )
{
if ( IsWinNT() )
{
// This was pulled because it was not standardized.
// hr = GetMediaSNwithNTScsiPassThrough(szTmp, pSN);
}
else
{
// @@@@ Remove this as well?
Aspi32Util a32u;
if ( a32u.DoSCSIPassThrough(szTmp, pSN, TRUE ) )
{
hr=S_OK;
}
else
{
hr = E_FAIL;
}
}
}
// Last chance, try old 'bad'
// SCSI_PASS_THROUGH "Get Device Serial Number" command
if ( FAILED(hr) )
{
// // We are using the DEVICE serial number as a MEDIA serial number.
// // This violates the SCSI spec. We are only keeping this functionality
// // for the devices we know that needs it.
// if( CheckForKBDevice( szTmp[0] ) == FALSE )
// {
// hr = E_FAIL;
// goto Error;
// }
if ( IsWinNT() )
{
CHRg(GetDeviceSNwithNTScsiPassThrough(wcsDeviceToOpen, pSN));
}
else
{
Aspi32Util a32u;
CFRg( a32u.DoSCSIPassThrough(szTmp, pSN, FALSE ) );
}
}
}
else if (dwLastError != ERROR_SUCCESS)
{
hr = HRESULT_FROM_WIN32(dwLastError);
goto Error;
}
else // If on NT and nonAdmin, try use PMSP Service
{
hr = GetMediaSerialNumberFromNTService(dwDriveNum, pSN);
if (FAILED(hr))
{
goto Error;
}
}
// put sanity check here
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
for ( i=0; i<(pSN->SerialNumberLength); i++ )
{
if ( pSN->pID[i] && pSN->pID[i] != 0x20 )
{
hr = S_OK;
break;
}
}
Error:
DebugMsg("Leaving UtilGetHardSN, hr = 0x%x");
return hr;
}
// fCreate is an unused parameter. Ir was used in an obsolete code path that
// has been deleted
HRESULT __stdcall UtilGetSerialNumber(WCHAR *wcsDeviceName, PWMDMID pSerialNumber, BOOL fCreate)
{
HRESULT hr = E_FAIL;
DebugMsg("Entering UtilGetSerialNumber");
if (!pSerialNumber || !wcsDeviceName)
{
return E_INVALIDARG;
}
DWORD dwDriveNum;
// We use only the first char of pDeviceName and expect it to
// be a drive letter. The rest of pDeviceName is not validated.
// Perhaps it should, but we don't want to break our clients.
if (wcsDeviceName[0] >= L'A' && wcsDeviceName[0] <= L'Z')
{
dwDriveNum = wcsDeviceName[0] - L'A';
}
else if (wcsDeviceName[0] >= L'a' && wcsDeviceName[0] <= L'z')
{
dwDriveNum = wcsDeviceName[0] - L'a';
}
else
{
hr = E_INVALIDARG;
goto Error;
}
pSerialNumber->cbSize = sizeof(WMDMID);
hr = UtilGetHardSN(wcsDeviceName, dwDriveNum, pSerialNumber);
if ( FAILED( hr ) )
{
if ( hr != HRESULT_FROM_WIN32(ERROR_INVALID_DATA) )
{
pSerialNumber->SerialNumberLength = 0;
pSerialNumber->dwVendorID = 0;
ZeroMemory(pSerialNumber->pID, sizeof(pSerialNumber->pID));
hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
}
// hr = S_FALSE;
}
Error:
DebugMsg("Leaving UtilGetSerialNumber, hr = 0x%x", hr);
return hr;
}
HRESULT __stdcall UtilStartStopService(bool fStartService)
{
HRESULT hr = S_OK;
SERVICE_STATUS ServiceStatus;
DWORD dwLastError;
if ( IsAdministrator(dwLastError) )
{
//
// We are on Win 9x machine or NT machine with admin previleges. In
// either case, we don't want to run the service.
//
DebugMsg("UtilStartStopService(): fStartService = %d, returning S_OK (IsAdmin returned TRUE)",
fStartService);
return S_OK;
}
else
{
// We ignore dwLastError
}
// open the service control manager
SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
SC_HANDLE hService = NULL;
if ( !hSCM )
{
hr = HRESULT_FROM_WIN32(GetLastError());
DebugMsg("UtilStartStopService(): fStartService = %d, OpenSCManager failed, last err (as hr) = 0x%x",
fStartService, hr);
goto Error;
}
// open the service
hService = OpenService(hSCM,
"WmdmPmSp",
(fStartService? SERVICE_START : SERVICE_STOP) | SERVICE_QUERY_STATUS);
if ( !hService )
{
hr = HRESULT_FROM_WIN32(GetLastError());
DebugMsg("UtilStartStopService(): fStartService = %d, OpenService failed, last err (as hr) = 0x%x",
fStartService, hr);
goto Error;
}
if ( !QueryServiceStatus( hService, &ServiceStatus ) )
{
hr = HRESULT_FROM_WIN32(GetLastError());
DebugMsg("UtilStartStopService(): fStartService = %d, QueryServiceStatus failed, last err (as hr) = 0x%x",
fStartService, hr);
goto Error;
}
if ( fStartService && ServiceStatus.dwCurrentState != SERVICE_RUNNING)
{
// start the service
if(!StartService(hService, 0, NULL) )
{
hr = HRESULT_FROM_WIN32(GetLastError());
DebugMsg("UtilStartStopService(): fStartService = %d, StartService failed, last err (as hr) = 0x%x",
fStartService, hr);
goto Error;
}
}
if(!fStartService && ServiceStatus.dwCurrentState != SERVICE_STOP)
{
// stop the service.
if(!ControlService(hService, SERVICE_CONTROL_STOP, &ServiceStatus))
{
hr = HRESULT_FROM_WIN32(GetLastError());
DebugMsg("UtilStartStopService(): fStartService = %d, ControlService failed, last err (as hr) = 0x%x",
fStartService, hr);
goto Error;
}
}
Error:
if ( hService )
{
CloseServiceHandle(hService);
}
if ( hSCM )
{
CloseServiceHandle(hSCM);
}
DebugMsg("UtilStartStopService(): fStartService = %d, returning hr = 0x%x",
fStartService, hr);
return hr;
}