|
|
/*
File GuidMap.c
Defines interface to map a guid interface name to an unique descriptive name describing that interface and vice versa.
Paul Mayfield, 8/25/97
Copyright 1997, Microsoft Corporation. */
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <winerror.h>
#include <netcfgx.h>
#include <netcon.h>
#include "rtcfg.h"
#include "guidmap.h"
#include "enumlan.h"
#include "hashtab.h"
#define GUIDMAP_HASH_SIZE 101
#define GUIDMAP_FUNCTION_MAPFRIENDLY 0x1
#define GUIDMAP_FUNCTION_MAPGUID 0x2
//
// Structure defines the control block for a guid map
//
typedef struct _GUIDMAPCB { PWCHAR pszServer; BOOL bNt40; EL_ADAPTER_INFO * pNodes; DWORD dwNodeCount; HANDLE hNameHashTable; HANDLE hGuidHashTable; BOOL bLoaded;
} GUIDMAPCB;
DWORD GuidMapSeedHashTable ( OUT HANDLE * phTable, IN HashTabHashFuncPtr pHashFunc, IN HashTabKeyCompFuncPtr pCompFunc, IN EL_ADAPTER_INFO * pNodes, IN DWORD dwCount, IN DWORD dwOffset);
ULONG GuidMapHashGuid ( IN HANDLE hGuid); ULONG GuidMapHashName ( IN HANDLE hName); int GuidMapCompGuids ( IN HANDLE hGuid, IN HANDLE hNameMapNode); int GuidMapCompNames ( IN HANDLE hName, IN HANDLE hNameMapNode);
//
// Initialize the guid map for the given server
//
DWORD GuidMapInit ( IN PWCHAR pszServer, OUT HANDLE * phGuidMap ) { GUIDMAPCB * pMapCb;
// Validate params
if (! phGuidMap) { return ERROR_INVALID_PARAMETER; }
// Allocate the control block
pMapCb = Malloc (sizeof (GUIDMAPCB)); if (!pMapCb) { return ERROR_NOT_ENOUGH_MEMORY; }
// Initialize
RtlZeroMemory (pMapCb, sizeof (GUIDMAPCB)); pMapCb->pszServer = pszServer;
*phGuidMap = (HANDLE)pMapCb;
return NO_ERROR; }
//
// Loads and prepares the guid map so that it can
// perform the given map function (a GUIDMAP_FUNCTION_XXX value).
//
DWORD GuidMapLoad ( IN GUIDMAPCB * pMapCb, IN DWORD dwFunction) { DWORD dwErr;
// We've done all the work we need to if we aren't looking
// at an nt5 machine
if (pMapCb->bNt40) { return NO_ERROR; }
// Load the guid map
if (! pMapCb->bLoaded) { dwErr = ElEnumLanAdapters ( pMapCb->pszServer, &(pMapCb->pNodes), &(pMapCb->dwNodeCount), &(pMapCb->bNt40) ); if (dwErr != NO_ERROR) { return dwErr; }
pMapCb->bLoaded = TRUE; }
// Seed the appropriate mapping hash table as needed
if ((dwFunction == GUIDMAP_FUNCTION_MAPFRIENDLY) && (pMapCb->hGuidHashTable == NULL)) { GuidMapSeedHashTable ( &(pMapCb->hGuidHashTable), GuidMapHashGuid, GuidMapCompGuids, pMapCb->pNodes, pMapCb->dwNodeCount, FIELD_OFFSET(EL_ADAPTER_INFO, guid)); } else if ((dwFunction == GUIDMAP_FUNCTION_MAPGUID) && (pMapCb->hNameHashTable == NULL)) { GuidMapSeedHashTable ( &(pMapCb->hNameHashTable), GuidMapHashName, GuidMapCompNames, pMapCb->pNodes, pMapCb->dwNodeCount, FIELD_OFFSET(EL_ADAPTER_INFO, pszName)); }
return NO_ERROR; }
//
// Cleans up resources obtained through GuidMapInit
//
DWORD GuidMapCleanup ( IN HANDLE hGuidMap, IN BOOL bFree ) { GUIDMAPCB * pMap = (GUIDMAPCB*)hGuidMap;
if (!pMap) { return ERROR_INVALID_HANDLE; }
if (pMap->pNodes) { ElCleanup (pMap->pNodes, pMap->dwNodeCount); }
if (pMap->hNameHashTable) { HashTabCleanup (pMap->hNameHashTable); }
if (pMap->hGuidHashTable) { HashTabCleanup (pMap->hGuidHashTable); }
RtlZeroMemory (pMap, sizeof(GUIDMAPCB));
if(bFree) { Free (pMap); }
return NO_ERROR; }
//
// Hash function for guids -- sum up the guid and mod
//
ULONG GuidMapHashGuid ( HANDLE hGuid) { DWORD dwSum = 0, * pdwCur; DWORD_PTR dwEnd = (DWORD_PTR)hGuid + sizeof(GUID);
for (pdwCur = (DWORD*)hGuid; (DWORD_PTR)pdwCur < dwEnd; pdwCur++) { dwSum += *pdwCur; }
return dwSum % GUIDMAP_HASH_SIZE; }
//
// Hash function for names -- sum up the characters and mod
//
ULONG GuidMapHashName ( HANDLE hName) { PWCHAR pszString = *((PWCHAR *)hName); DWORD dwSum = 0;
while (pszString && *pszString) { dwSum += towlower(*pszString); pszString++; }
return dwSum % GUIDMAP_HASH_SIZE; }
//
// Comparison function for guids to NAMEMAPNODES
//
int GuidMapCompGuids ( IN HANDLE hGuid, IN HANDLE hNameMapNode) { return memcmp ( (GUID*)hGuid, &(((EL_ADAPTER_INFO *)hNameMapNode)->guid), sizeof(GUID)); }
//
// Comparison function for names to NAMEMAPNODES
//
int GuidMapCompNames ( IN HANDLE hName, IN HANDLE hNameMapNode) { return lstrcmpi( *((PWCHAR*)hName), ((EL_ADAPTER_INFO *)hNameMapNode)->pszName); }
//
// Seeds the given hash table. Offset is the offset into the
// namemapnode of the key for insertion.
//
DWORD GuidMapSeedHashTable ( OUT HANDLE * phTable, IN HashTabHashFuncPtr pHashFunc, IN HashTabKeyCompFuncPtr pCompFunc, IN EL_ADAPTER_INFO * pNodes, IN DWORD dwCount, IN DWORD dwOffset) { DWORD dwErr, i, dwHashSize = GUIDMAP_HASH_SIZE;
// Initialize the hash table
dwErr = HashTabCreate ( dwHashSize, pHashFunc, pCompFunc, NULL, NULL, NULL, phTable ); if (dwErr != NO_ERROR) { return dwErr; }
// Add all of the nodes to the hash table
for (i = 0; i < dwCount; i++) { HashTabInsert ( *phTable, (HANDLE)((DWORD_PTR)(&(pNodes[i])) + dwOffset), (HANDLE)(&(pNodes[i])) ); }
return NO_ERROR; }
//
// Gets the name and status of a given adapter
//
DWORD GuidMapLookupNameAndStatus( GUIDMAPCB* pMapCb, GUID* pGuid, PWCHAR* ppszName, DWORD* lpdwStatus) { EL_ADAPTER_INFO * pNode; DWORD dwErr;
dwErr = HashTabFind ( pMapCb->hGuidHashTable, (HANDLE)pGuid, (HANDLE*)&pNode ); if (dwErr != NO_ERROR) { return dwErr; }
*ppszName = pNode->pszName; *lpdwStatus = pNode->dwStatus; return NO_ERROR; }
//
// Looks up a name given a guid
//
DWORD GuidMapLookupName ( GUIDMAPCB * pMapCb, GUID * pGuid, PWCHAR * ppszName) { DWORD dwStatus;
return GuidMapLookupNameAndStatus(pMapCb, pGuid, ppszName, &dwStatus); }
//
// Looks up a guid given a name
//
DWORD GuidMapLookupGuid ( IN GUIDMAPCB * pMapCb, IN PWCHAR pszName, GUID * pGuid) { EL_ADAPTER_INFO * pNode; DWORD dwErr;
dwErr = HashTabFind ( pMapCb->hNameHashTable, (HANDLE)&pszName, (HANDLE*)&pNode ); if (dwErr != NO_ERROR) { return dwErr; }
*pGuid = pNode->guid; return NO_ERROR; }
//
// Returns a pointer to the packet name portion of
// the interface name if it exists.
//
PWCHAR GuidMapFindPacketName( IN PWCHAR pszName) { PWCHAR res;
if ((res = wcsstr(pszName, L"SNAP")) != NULL) { return res; } if ((res = wcsstr(pszName, L"EthII")) != NULL) { return res; } if ((res = wcsstr(pszName, L"802.2")) != NULL) { return res; } if ((res = wcsstr(pszName, L"802.3")) != NULL) { return res; }
return NULL; }
//
// Takes in a friendly interface name and removes it's
// [xxxx] packet type appending.
//
DWORD GuidMapParseOutPacketName ( IN PWCHAR pszName, OUT PWCHAR pszNameNoPacket, OUT PWCHAR pszPacketName) { PWCHAR pszPacket = GuidMapFindPacketName (pszName); int len;
if (pszPacket) { pszPacket--; len = (int) ((((DWORD_PTR)pszPacket) - ((DWORD_PTR)pszName)) / sizeof (WCHAR)); lstrcpynW (pszNameNoPacket, pszName, len); pszNameNoPacket[len] = 0; pszPacket++; pszPacket[wcslen(pszPacket) - 1] = (WCHAR)0; lstrcpyW (pszPacketName, pszPacket); } else { lstrcpyW (pszNameNoPacket, pszName); pszPacketName[0] = 0; }
return NO_ERROR; }
//
// Generates the version of the interface as stored in the registry. This
// is done by finding the packet type if any and appending it to the
// guid name.
//
DWORD GuidMapFormatGuidName( OUT PWCHAR pszDest, IN DWORD dwBufferSize, IN PWCHAR pszGuidName, IN PWCHAR pszPacketType) { DWORD dwSize; // Upper case the guid name
_wcsupr(pszGuidName);
// Calculate the space required for storing pszGuidName, the opening and
// closing braces, and the terminating NULL
dwSize = (wcslen(pszGuidName) + 2 + 1)* sizeof (WCHAR); if ( pszPacketType[0] ) { // add the space required to store the pszPacketType and "/"
dwSize += (wcslen(pszPacketType) + 1) * sizeof (WCHAR); } if ( dwBufferSize < dwSize ) { return ERROR_BUFFER_OVERFLOW; }
// Generate the name
if (pszPacketType[0]) { wsprintfW(pszDest,L"{%s}/%s", pszGuidName, pszPacketType); } else { wsprintfW(pszDest,L"{%s}", pszGuidName); }
return NO_ERROR; }
//
// Appends the packet type if any to the interface name.
//
DWORD GuidMapFormatFriendlyName ( OUT PWCHAR pszDest, IN DWORD dwBufferSize, IN PWCHAR pszFriendlyName, IN PWCHAR pszGuidName) { PWCHAR pszType = NULL; DWORD dwSize;
pszType = GuidMapFindPacketName(pszGuidName);
// Calculate the space required for storing pszFriendlyName and the terminating NULL
dwSize = (wcslen(pszFriendlyName) + 1)* sizeof (WCHAR); if ( pszType ) { // add the space required to store the pszType, the blank space, and the
// opening and closing square brackets
dwSize += (wcslen(pszType) + 3) * sizeof (WCHAR); } if ( dwBufferSize < dwSize ) { return ERROR_BUFFER_OVERFLOW; }
if (pszType) { wsprintfW(pszDest,L"%s [%s]", pszFriendlyName, pszType); } else { wcscpy(pszDest, pszFriendlyName); }
return NO_ERROR; }
//
// Parses out the guid portion of an interface name
//
DWORD GuidMapGetGuidString( IN PWCHAR pszName, OUT PWCHAR* ppszGuidString) { PWCHAR pszBegin = NULL, pszEnd = NULL; PWCHAR pszRet = NULL; int i, length; DWORD dwErr = NO_ERROR;
do { // Validate parameters
//
if (!pszName || !ppszGuidString) { return ERROR_INVALID_PARAMETER; }
// Find out if this is a guid string
pszBegin = wcsstr(pszName, L"{"); pszEnd = wcsstr(pszName, L"}");
// If there is no guid portion, return success with a
//null pszGuidString
if ((pszBegin == NULL) || (pszEnd == NULL)) { *ppszGuidString = NULL; break; }
// Check the format of the return
//
if ((DWORD_PTR)pszBegin >= (DWORD_PTR)pszEnd) { dwErr = ERROR_CAN_NOT_COMPLETE; break; }
// Allocate the return value
//
length = 41; pszRet = (PWCHAR) Malloc(length * sizeof(WCHAR)); if (pszRet == NULL) { dwErr = ERROR_NOT_ENOUGH_MEMORY; break; }
i=0; pszBegin++; while ((pszBegin != pszEnd) && (i < length)) { pszRet[i++]=*pszBegin; pszBegin++; } pszRet[i]=0;
*ppszGuidString = pszRet; } while (FALSE);
// Cleanup
{ if (dwErr != NO_ERROR) { if (pszRet) { Free(pszRet); } } }
return dwErr; }
//
// Derive the friendly name from the guid name
//
DWORD GuidMapGetFriendlyName ( IN SERVERCB *pserver, IN PWCHAR pszGuidName, IN DWORD dwBufferSize, OUT PWCHAR pszFriendlyName ) { GUIDMAPCB * pMapCb = (GUIDMAPCB*)(pserver->hGuidMap); PWCHAR pszGuidString = NULL, pszNetmanName = NULL; DWORD dwErr = NO_ERROR; GUID Guid;
// Sanity Check
if (!pMapCb || !pszGuidName || !pszFriendlyName || !dwBufferSize) { return ERROR_INVALID_PARAMETER; }
// Prepare the map for friendly name lookups
dwErr = GuidMapLoad (pMapCb, GUIDMAP_FUNCTION_MAPFRIENDLY); if (dwErr != NO_ERROR) { return dwErr; }
// Nt40 machines require no mapping
if (pMapCb->bNt40) { return ERROR_NOT_FOUND; }
do { // Get the guid string from the interface name
dwErr = GuidMapGetGuidString(pszGuidName, &pszGuidString); if (dwErr != NO_ERROR) { break; }
// If there is no guid, there is no mapping
if (! pszGuidString) { dwErr = ERROR_NOT_FOUND; break; } // Convert the guid string
if (UuidFromStringW (pszGuidString, &Guid)!= RPC_S_OK) { dwErr = ERROR_CAN_NOT_COMPLETE; break; } // Look up the descriptive name
dwErr = GuidMapLookupName (pMapCb, &Guid, &pszNetmanName); if (dwErr != NO_ERROR) { break; }
// If the registry is corrupt, it is possible for an
// adapter with a null name to be mapped. Taking this
// precaution will prevent an AV in this
// case (shouldn't happen anyway)
//
if (pszNetmanName == NULL) { pszNetmanName = L""; } // Copy in the string
dwErr = GuidMapFormatFriendlyName ( pszFriendlyName, dwBufferSize, pszNetmanName, pszGuidName); if ( dwErr != NO_ERROR ) { break; } } while (FALSE);
// Cleanup
{ if (pszGuidString) { Free (pszGuidString); } }
return dwErr; }
//
// Derive the guid name from the friendly name
//
DWORD GuidMapGetGuidName ( IN SERVERCB *pserver, IN PWCHAR pszFriendlyName, IN DWORD dwBufferSize, OUT PWCHAR pszGuidName ) { WCHAR pszNoPacketName[1024], pszPacketDesc[64], *pszGuid = NULL; GUIDMAPCB * pMapCb = (GUIDMAPCB*)(pserver->hGuidMap); DWORD dwErr; GUID Guid;
// Validate paramters
if (!pMapCb || !pszFriendlyName || !pszGuidName || !dwBufferSize) { return ERROR_INVALID_PARAMETER; }
// Prepare the map for guid name lookups
dwErr = GuidMapLoad (pMapCb, GUIDMAP_FUNCTION_MAPGUID); if (dwErr != NO_ERROR) { return dwErr; }
// Nt40 machines require no mapping
if (pMapCb->bNt40) { return ERROR_NOT_FOUND; }
// Remove the packet type from the friendly name
GuidMapParseOutPacketName ( pszFriendlyName, pszNoPacketName, pszPacketDesc);
// If we don't have the name in the guid map, then
// this must be a non lan interface.
dwErr = GuidMapLookupGuid (pMapCb, pszNoPacketName, &Guid);
if (dwErr != NO_ERROR) { return dwErr; } // Otherwise, return its Guid name
do { if(RPC_S_OK != UuidToStringW (&Guid, &pszGuid)) { break; } if (pszGuid) { dwErr = GuidMapFormatGuidName( pszGuidName, dwBufferSize, pszGuid, pszPacketDesc); if ( dwErr != NO_ERROR ) { if ( pszGuid ) { RpcStringFreeW (&pszGuid); pszGuid = NULL; } return dwErr; } } } while (FALSE); // Cleanup
{ if (pszGuid) { RpcStringFreeW (&pszGuid); } }
return NO_ERROR; }
//
// States whether a mapping for the given guid name
// exists without actually providing the friendly
// name. This is more efficient than GuidMapGetFriendlyName
// when the friendly name is not required.
//
DWORD GuidMapIsAdapterInstalled( IN HANDLE hGuidMap, IN PWCHAR pszGuidName, OUT PBOOL pfMappingExists) { GUIDMAPCB * pMapCb = (GUIDMAPCB*)hGuidMap; PWCHAR pszGuidString = NULL, pszNetmanName = NULL; DWORD dwErr = NO_ERROR, dwSize, dwStatus = 0; GUID Guid;
// Sanity Check
if (!pMapCb || !pszGuidName) { return ERROR_INVALID_PARAMETER; }
// Prepare the map for friendly name lookups
dwErr = GuidMapLoad (pMapCb, GUIDMAP_FUNCTION_MAPFRIENDLY); if (dwErr != NO_ERROR) { return dwErr; }
// Nt40 machines require no mapping
if (pMapCb->bNt40) { *pfMappingExists = TRUE; return NO_ERROR; }
do { // Get the guid string from the interface name
dwErr = GuidMapGetGuidString(pszGuidName, &pszGuidString); if (dwErr != NO_ERROR) { break; }
// If there is no guid, there is no mapping
if (! pszGuidString) { dwErr = ERROR_NOT_FOUND; break; } // Convert the guid string
if (UuidFromStringW (pszGuidString, &Guid)!= RPC_S_OK) { dwErr = ERROR_CAN_NOT_COMPLETE; break; } // Look up the descriptive name
dwErr = GuidMapLookupNameAndStatus ( pMapCb, &Guid, &pszNetmanName, &dwStatus); if ((dwErr == NO_ERROR) && (pszNetmanName) && (dwStatus != EL_STATUS_NOT_THERE)) { *pfMappingExists = TRUE; } else { *pfMappingExists = FALSE; } } while (FALSE);
// Cleanup
{ if (pszGuidString) { Free (pszGuidString); } }
return dwErr; }
|