//----------------------------------------------------------------------------- // // File: serialid.cpp // // Microsoft Digital Rights Management // Copyright (C) Microsoft Corporation, 1998 - 1999, All Rights Reserved // // Description: // //----------------------------------------------------------------------------- #include #include #include "drmerr.h" #include "aspi32.h" #include "serialid.h" #include "spti.h" //#include "KBDevice.h" #include HRESULT __stdcall UtilStartStopService(bool fStartService); // #define WRITE_TO_LOG_FILE #if defined(DBG) || defined(WRITE_TO_LOG_FILE) #include #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 // 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, ®, sizeof(DIOC_REGISTERS), ®, 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, ®, sizeof(DIOC_REGISTERS), ®, 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; iSerialNumberLength; 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; }