245 lines
9.9 KiB
C++
245 lines
9.9 KiB
C++
#ifdef OS_WINCE
|
|
|
|
#include "windows.h"
|
|
#include <winsock.h>
|
|
#include "ceconfig.h"
|
|
|
|
// extern "C" {
|
|
// The following four files are from the OS, but are needed here
|
|
// by the GUID-generation code, so they were copied over.
|
|
// Ick...
|
|
#include "tdiinfo.h"
|
|
#include "tdistat.h"
|
|
#include "llinfo.h"
|
|
#include "wscntl.h"
|
|
|
|
#define REGISTRY_ROOT TEXT("Software\\Microsoft\\Terminal Server Client")
|
|
#define REGISTRY_VALUE_UUID TEXT("UUID")
|
|
#define ETHER_ADDRESS_LENGTH 6
|
|
#define DEFAULT_MINIMUM_ENTITIES 32
|
|
#define MAX_ADAPTER_DESCRIPTION_LENGTH 128
|
|
#define RPC_UUID_TIME_HIGH_MASK 0x0FFF
|
|
#define RPC_UUID_VERSION 0x1000
|
|
#define RPC_UUID_RESERVED 0x80
|
|
#define RPC_UUID_CLOCK_SEQ_HI_MASK 0x3F
|
|
|
|
typedef struct {
|
|
unsigned long ulTimeLow;
|
|
unsigned short usTimeMid;
|
|
unsigned short usTimeHiAndVersion;
|
|
unsigned char ucClockSeqHiAndReserved;
|
|
unsigned char ucClockSeqLow;
|
|
unsigned char ucNodeId[6];
|
|
} _UUID;
|
|
|
|
static unsigned int gs_seq = 0;
|
|
static LARGE_INTEGER gs_tm = {0};
|
|
static unsigned char gs_ucEtherAddr[ETHER_ADDRESS_LENGTH];
|
|
static int gs_fIsAddressInitialized = FALSE;
|
|
|
|
static void GetAdapterAddress()
|
|
{
|
|
if(!gs_fIsAddressInitialized) {
|
|
memset (gs_ucEtherAddr, 0, sizeof(gs_ucEtherAddr));
|
|
// Load WinSock.DLL so we can call into WsControl(...)
|
|
HINSTANCE hInstWinSock = LoadLibrary(TEXT("winsock.dll"));
|
|
if(0 != hInstWinSock) {
|
|
DWORD(*fpfWsControl)(DWORD Protocol, DWORD Action, LPVOID InputBuffer, LPDWORD InputBufferLength, LPVOID OutputBuffer, LPDWORD OutputBufferLength);
|
|
fpfWsControl = (DWORD(*)(DWORD Protocol, DWORD Action, LPVOID InputBuffer, LPDWORD InputBufferLength, LPVOID OutputBuffer, LPDWORD OutputBufferLength))GetProcAddress(hInstWinSock, TEXT("WsControl"));
|
|
if(0 != fpfWsControl) {
|
|
// First, obtain list of TCP entities...
|
|
TCP_REQUEST_QUERY_INFORMATION_EX req;
|
|
memset(&req, 0, sizeof(req));
|
|
req.ID.toi_entity.tei_entity = GENERIC_ENTITY;
|
|
req.ID.toi_entity.tei_instance = 0;
|
|
req.ID.toi_class = INFO_CLASS_GENERIC;
|
|
req.ID.toi_type = INFO_TYPE_PROVIDER;
|
|
req.ID.toi_id = ENTITY_LIST_ID;
|
|
int iInputLen = sizeof(req);
|
|
int iOutputLen = sizeof(TDIEntityID) * DEFAULT_MINIMUM_ENTITIES;
|
|
TDIEntityID *pEntity = NULL;
|
|
for ( ; ; ) {
|
|
int iPrevOutputLen = iOutputLen;
|
|
pEntity = (TDIEntityID*)LocalAlloc(LPTR, (size_t)iOutputLen);
|
|
if (!pEntity)
|
|
break;
|
|
DWORD status = fpfWsControl(IPPROTO_TCP,
|
|
WSCNTL_TCPIP_QUERY_INFO,
|
|
(LPVOID)&req,
|
|
(ULONG *)&iInputLen,
|
|
(LPVOID)pEntity,
|
|
(ULONG *)&iOutputLen
|
|
);
|
|
if (status != TDI_SUCCESS) {
|
|
LocalFree(pEntity);
|
|
pEntity = NULL;
|
|
break;
|
|
}
|
|
if (iOutputLen <= iPrevOutputLen)
|
|
break;
|
|
LocalFree(pEntity);
|
|
}
|
|
if (0 != pEntity) {
|
|
int iCount = (UINT)(iOutputLen / sizeof(TDIEntityID));
|
|
// Second, walk through these in search of adapters
|
|
TDIEntityID *pRunner = pEntity;
|
|
for (int i = 0; i < iCount; ++i, ++pRunner) {
|
|
// IF_ENTITY: this entity/instance describes an adapter
|
|
if (pRunner->tei_entity == IF_ENTITY) {
|
|
// find out if this entity supports MIB requests
|
|
memset(&req, 0, sizeof(req));
|
|
TDIObjectID id;
|
|
memset (&id, 0, sizeof(id));
|
|
id.toi_entity = *pRunner;
|
|
id.toi_class = INFO_CLASS_GENERIC;
|
|
id.toi_type = INFO_TYPE_PROVIDER;
|
|
id.toi_id = ENTITY_TYPE_ID;
|
|
req.ID = id;
|
|
DWORD fIsMib = FALSE;
|
|
iInputLen = sizeof(req);
|
|
iOutputLen = sizeof(fIsMib);
|
|
DWORD status = fpfWsControl(IPPROTO_TCP,
|
|
WSCNTL_TCPIP_QUERY_INFO,
|
|
(LPVOID)&req,
|
|
(ULONG *)&iInputLen,
|
|
(LPVOID)&fIsMib,
|
|
(ULONG *)&iOutputLen
|
|
);
|
|
if (status != TDI_SUCCESS)
|
|
break;
|
|
if (fIsMib != IF_MIB)
|
|
continue;
|
|
// MIB requests supported - query the adapter info
|
|
id.toi_class = INFO_CLASS_PROTOCOL;
|
|
id.toi_id = IF_MIB_STATS_ID;
|
|
memset(&req, 0, sizeof(req));
|
|
req.ID = id;
|
|
BYTE info[sizeof(IFEntry) + MAX_ADAPTER_DESCRIPTION_LENGTH + 1];
|
|
iInputLen = sizeof(req);
|
|
iOutputLen = sizeof(info);
|
|
status = fpfWsControl(IPPROTO_TCP,
|
|
WSCNTL_TCPIP_QUERY_INFO,
|
|
(LPVOID)&req,
|
|
(ULONG *)&iInputLen,
|
|
(LPVOID)&info,
|
|
(ULONG *)&iOutputLen
|
|
);
|
|
if (status != TDI_SUCCESS)
|
|
break;
|
|
if (iOutputLen > sizeof(info))
|
|
continue;
|
|
IFEntry* pIfEntry = (IFEntry*)info;
|
|
memcpy (gs_ucEtherAddr, pIfEntry->if_physaddr, sizeof (gs_ucEtherAddr));
|
|
gs_fIsAddressInitialized = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
LocalFree (pEntity);
|
|
}
|
|
}
|
|
FreeLibrary(hInstWinSock);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
BOOL generate_guid (GUID *guid) {
|
|
GetAdapterAddress(); // It may fail, but gs_ucEtherAddr will still be all 0
|
|
_UUID *p_uuid = (_UUID *)guid;
|
|
SYSTEMTIME st;
|
|
GetLocalTime(&st);
|
|
LARGE_INTEGER tm2;
|
|
SystemTimeToFileTime (&st, (FILETIME *)&tm2);
|
|
if (gs_tm.QuadPart < tm2.QuadPart)
|
|
gs_tm = tm2;
|
|
else
|
|
++gs_tm.QuadPart;
|
|
if (gs_tm.QuadPart > tm2.QuadPart + 1000) { // Clock reset or super heavy usage
|
|
gs_tm = tm2;
|
|
++gs_seq;
|
|
}
|
|
unsigned int uiLowPart = gs_tm.LowPart;
|
|
unsigned int uiHighPart = gs_tm.HighPart;
|
|
unsigned int uiSeq = gs_seq;
|
|
p_uuid->ulTimeLow = (unsigned long)uiLowPart;
|
|
p_uuid->usTimeMid = (unsigned short)(uiHighPart & 0x0000FFFF);
|
|
p_uuid->usTimeHiAndVersion = (unsigned short)(( (unsigned short)(uiHighPart >> 16) & RPC_UUID_TIME_HIGH_MASK) | RPC_UUID_VERSION);
|
|
p_uuid->ucClockSeqHiAndReserved = RPC_UUID_RESERVED | (((unsigned char) (uiSeq >> 8)) & (unsigned char) RPC_UUID_CLOCK_SEQ_HI_MASK);
|
|
p_uuid->ucClockSeqLow = (unsigned char) (uiSeq & 0x00FF);
|
|
p_uuid->ucNodeId[0] = gs_ucEtherAddr[0];
|
|
p_uuid->ucNodeId[1] = gs_ucEtherAddr[1];
|
|
p_uuid->ucNodeId[2] = gs_ucEtherAddr[2];
|
|
p_uuid->ucNodeId[3] = gs_ucEtherAddr[3];
|
|
p_uuid->ucNodeId[4] = gs_ucEtherAddr[4];
|
|
p_uuid->ucNodeId[5] = gs_ucEtherAddr[5];
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL OEMGetUUID(GUID* pGuid)
|
|
{
|
|
DWORD len;
|
|
HKEY hKey;
|
|
BOOL fRetVal = FALSE;
|
|
|
|
len = sizeof(UUID);
|
|
|
|
// Try to read the UUID from the registry - if we find one, use it
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGISTRY_ROOT, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
|
|
{
|
|
DWORD dwType;
|
|
|
|
if ( ( RegQueryValueEx(hKey, REGISTRY_VALUE_UUID, 0, &dwType,
|
|
(BYTE*)pGuid, &len) == ERROR_SUCCESS) && (sizeof(UUID) == len) )
|
|
{
|
|
fRetVal = TRUE;
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
if (!fRetVal)
|
|
{
|
|
// We didn't find a UUID in the registry, so we need to generate one now
|
|
|
|
// First, try asking the hardware for a UUID...
|
|
fRetVal = KernelIoControl(IOCTL_HAL_GET_UUID, NULL, 0, pGuid, len, &len);
|
|
|
|
// If the hardware was unable to provide a UUID, generate one now.
|
|
if (!fRetVal)
|
|
{
|
|
fRetVal = generate_guid(pGuid);
|
|
}
|
|
|
|
// Save the UUID (however we got it) in the registry so that we will always use this UUID
|
|
if(fRetVal) {
|
|
DWORD dwDisposition;
|
|
BOOL fSavedKey = FALSE;
|
|
if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, REGISTRY_ROOT, 0, 0, 0, KEY_ALL_ACCESS, 0, &hKey, &dwDisposition) == ERROR_SUCCESS)
|
|
{
|
|
if (RegSetValueEx(hKey, REGISTRY_VALUE_UUID, 0, REG_BINARY, (BYTE*)pGuid, len) == ERROR_SUCCESS)
|
|
{
|
|
fSavedKey = TRUE;
|
|
}
|
|
RegCloseKey(hKey);
|
|
}
|
|
// If we can't save the registry key, we have to return failure because we don't want to leak licenses
|
|
fRetVal = fSavedKey;
|
|
}
|
|
}
|
|
|
|
if (!fRetVal)
|
|
{
|
|
// We failed to generate a UUID.
|
|
MessageBox(NULL,
|
|
TEXT("Can't read or generate licensing information. (Unable to generate a UUID or read one from the registry.)"),
|
|
TEXT("Error"), MB_OK);
|
|
|
|
}
|
|
|
|
return fRetVal;
|
|
}
|
|
|
|
// }; // extern "C"
|
|
|
|
#endif // OS_WINCE
|