/* 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 #include #include #include #include #include #include #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 { wsprintfW(pszDest,L"%s", 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; }