/*++ Copyright (c) 1998 Microsoft Corporation Module Name: routing\netsh\ipx\ipxmon\ipxmon.c Abstract: IPX Command dispatcher. Revision History: V Raman 11/25/98 Created --*/ #include "precomp.h" #pragma hdrstop // // Guid for IPMON.DLL // // {b1641451-84b8-11d2-b940-3078302c2030} // static const GUID g_MyGuid = IPXMONTR_GUID; // // Well known ROUTING guid // static const GUID g_RoutingGuid = ROUTING_GUID; // // IPX monitor version // #define IPX_HELPER_VERSION 1 // // random wrapper macros // #define MALLOC(x) HeapAlloc( GetProcessHeap(), 0, x ) #define REALLOC(x,y) HeapReAlloc( GetProcessHeap(), 0, x, y ) #define FREE(x) HeapFree( GetProcessHeap(), 0, x ) // // The table of Add, Delete, Set and Show Commands for IPX RTR MGR // To add a command to one of the command groups, just add the // CMD_ENTRY to the correct table. To add a new cmd group, create its // cmd table and then add the group entry to group table // // // The commands are prefix-matched with the command-line, in sequential // order. So a command like 'ADD INTERFACE FILTER' must come before // the command 'ADD INTERFACE' in the table. Likewise, // a command like 'ADD ROUTE' must come before the command // 'ADD ROUTEPREF' in the table. // CMD_ENTRY g_IpxAddCmdTable[] = { CREATE_CMD_ENTRY( IPX_ADD_ROUTE, HandleIpxAddRoute), CREATE_CMD_ENTRY( IPX_ADD_SERVICE, HandleIpxAddService ), CREATE_CMD_ENTRY( IPX_ADD_FILTER, HandleIpxAddFilter ), CREATE_CMD_ENTRY( IPX_ADD_INTERFACE, HandleIpxAddInterface ) }; CMD_ENTRY g_IpxDelCmdTable[] = { CREATE_CMD_ENTRY( IPX_DELETE_ROUTE, HandleIpxDelRoute ), CREATE_CMD_ENTRY( IPX_DELETE_SERVICE, HandleIpxDelService ), CREATE_CMD_ENTRY( IPX_DELETE_FILTER, HandleIpxDelFilter ), CREATE_CMD_ENTRY( IPX_DELETE_INTERFACE, HandleIpxDelInterface ) }; CMD_ENTRY g_IpxSetCmdTable[] = { CREATE_CMD_ENTRY( IPX_SET_ROUTE, HandleIpxSetRoute ), CREATE_CMD_ENTRY( IPX_SET_SERVICE, HandleIpxSetService ), CREATE_CMD_ENTRY( IPX_SET_FILTER, HandleIpxSetFilter ), CREATE_CMD_ENTRY( IPX_SET_INTERFACE, HandleIpxSetInterface ), CREATE_CMD_ENTRY( IPX_SET_GLOBAL, HandleIpxSetLoglevel ) }; CMD_ENTRY g_IpxShowCmdTable[] = { CREATE_CMD_ENTRY( IPX_SHOW_ROUTE, HandleIpxShowRoute ), CREATE_CMD_ENTRY( IPX_SHOW_SERVICE, HandleIpxShowService), CREATE_CMD_ENTRY( IPX_SHOW_FILTER, HandleIpxShowFilter ), CREATE_CMD_ENTRY( IPX_SHOW_INTERFACE, HandleIpxShowInterface ), CREATE_CMD_ENTRY( IPX_SHOW_GLOBAL, HandleIpxShowLoglevel ), CREATE_CMD_ENTRY( IPX_SHOW_ROUTETABLE, HandleIpxShowRouteTable ), CREATE_CMD_ENTRY( IPX_SHOW_SERVICETABLE,HandleIpxShowServiceTable ), }; CMD_GROUP_ENTRY g_IpxCmdGroups[] = { CREATE_CMD_GROUP_ENTRY( GROUP_ADD, g_IpxAddCmdTable ), CREATE_CMD_GROUP_ENTRY( GROUP_DELETE, g_IpxDelCmdTable ), CREATE_CMD_GROUP_ENTRY( GROUP_SET, g_IpxSetCmdTable ), CREATE_CMD_GROUP_ENTRY( GROUP_SHOW, g_IpxShowCmdTable ) }; ULONG g_ulNumGroups = sizeof(g_IpxCmdGroups)/sizeof(CMD_GROUP_ENTRY); // // Top level commands // CMD_ENTRY g_IpxCmds[] = { CREATE_CMD_ENTRY( IPX_UPDATE, HandleIpxUpdate ) }; ULONG g_ulNumTopCmds = sizeof(g_IpxCmds)/sizeof(CMD_ENTRY); // // Handle to this DLL // HANDLE g_hModule; // // Handle to router being administered // HANDLE g_hMprConfig; HANDLE g_hMprAdmin; HANDLE g_hMIBServer; // // Commit mode // BOOL g_bCommit; DWORD ParentVersion; BOOL g_bIpxDirty = FALSE; NS_CONTEXT_CONNECT_FN IpxConnect; NS_CONTEXT_SUBENTRY_FN IpxSubEntry; // // Variable that stores whether or not the helper has been // initialized // ULONG g_ulInitCount; // // Router name // PWCHAR g_pwszRouter = NULL; // // Prototype declarations for functions in this file // DWORD WINAPI IpxUnInit( IN DWORD dwReserved ); BOOL IsHelpToken( PWCHAR pwszToken ); BOOL IA64VersionCheck ( IN UINT CIMOSType, // WMI: Win32_OperatingSystem OSType IN UINT CIMOSProductSuite, // WMI: Win32_OperatingSystem OSProductSuite IN LPCWSTR CIMOSVersion, // WMI: Win32_OperatingSystem Version IN LPCWSTR CIMOSBuildNumber, // WMI: Win32_OperatingSystem BuildNumber IN LPCWSTR CIMServicePackMajorVersion, // WMI: Win32_OperatingSystem ServicePackMajorVersion IN LPCWSTR CIMServicePackMinorVersion, // WMI: Win32_OperatingSystem ServicePackMinorVersion IN UINT CIMProcessorArchitecture, // WMI: Win32_Processor Architecture IN DWORD dwReserved ) { if (CIMProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) // IA64=6 (x86 == 0) return TRUE; else return FALSE; } DWORD WINAPI IpxStartHelper( IN CONST GUID *pguidParent, IN DWORD dwVersion ) /*++ Routine Description : Registers the contexts supported by this helper Arguements : pguidParent - NETSH guid Return value : Don't know --*/ { DWORD dwErr; NS_CONTEXT_ATTRIBUTES attMyAttributes; PNS_PRIV_CONTEXT_ATTRIBUTES pNsPrivContextAttributes; pNsPrivContextAttributes = MALLOC(sizeof(NS_PRIV_CONTEXT_ATTRIBUTES)); if (!pNsPrivContextAttributes) { return ERROR_NOT_ENOUGH_MEMORY; } ParentVersion = dwVersion; ZeroMemory( &attMyAttributes, sizeof(NS_CONTEXT_ATTRIBUTES)); ZeroMemory(pNsPrivContextAttributes, sizeof(NS_PRIV_CONTEXT_ATTRIBUTES)); attMyAttributes.pwszContext = L"ipx"; attMyAttributes.guidHelper = g_MyGuid; attMyAttributes.dwVersion = 1; attMyAttributes.dwFlags = 0; attMyAttributes.ulNumTopCmds = g_ulNumTopCmds; attMyAttributes.pTopCmds = (CMD_ENTRY (*)[])&g_IpxCmds; attMyAttributes.ulNumGroups = g_ulNumGroups; attMyAttributes.pCmdGroups = (CMD_GROUP_ENTRY (*)[])&g_IpxCmdGroups; attMyAttributes.pfnCommitFn = NULL; attMyAttributes.pfnDumpFn = IpxDump; attMyAttributes.pfnConnectFn= IpxConnect; attMyAttributes.pfnOsVersionCheck = IA64VersionCheck; pNsPrivContextAttributes->pfnEntryFn = NULL; pNsPrivContextAttributes->pfnSubEntryFn = IpxSubEntry; attMyAttributes.pReserved = pNsPrivContextAttributes; dwErr = RegisterContext( &attMyAttributes ); return dwErr; } DWORD WINAPI InitHelperDll( IN DWORD dwNetshVersion, OUT PNS_DLL_ATTRIBUTES pDllTable ) /*++ Routine Description : initialize this helper DLL Arguements : pUtilityTable - List of helper functions from the SHELL pDllTable - Callbacks into this helper DLL passed back to the shell Return value : NO_ERROR - Success --*/ { DWORD dwErr; NS_HELPER_ATTRIBUTES attMyAttributes; // // See if this is the first time we are being called // if ( InterlockedIncrement( &g_ulInitCount ) isnot 1 ) { return NO_ERROR; } // // Connect to router config. Also serves as a check to // see if the router is configured on the machine // dwErr = MprConfigServerConnect( NULL, &g_hMprConfig ); if( dwErr isnot NO_ERROR ) { DisplayError( NULL, dwErr ); return dwErr; } pDllTable->dwVersion = NETSH_VERSION_50; pDllTable->pfnStopFn = StopHelperDll; // // Register helpers // ZeroMemory( &attMyAttributes, sizeof(attMyAttributes) ); attMyAttributes.guidHelper = g_MyGuid; attMyAttributes.dwVersion = IPX_HELPER_VERSION; attMyAttributes.pfnStart = IpxStartHelper; attMyAttributes.pfnStop = NULL; RegisterHelper( &g_RoutingGuid, &attMyAttributes ); return NO_ERROR; } DWORD WINAPI StopHelperDll( IN DWORD dwReserved ) /*++ Routine Description : Arguements : Return value : --*/ { if ( InterlockedDecrement( &g_ulInitCount ) isnot 0 ) { return NO_ERROR; } #if 0 IpxCommit(NETSH_FLUSH); #endif return NO_ERROR; } BOOL WINAPI IpxDllEntry( HINSTANCE hInstDll, DWORD fdwReason, LPVOID pReserved ) /*++ Routine Description : Arguements : Return value : --*/ { switch (fdwReason) { case DLL_PROCESS_ATTACH: { g_hModule = hInstDll; DisableThreadLibraryCalls(hInstDll); break; } case DLL_PROCESS_DETACH: { break; } default: { break; } } return TRUE; } DWORD ConnectToRouter( IN LPCWSTR pwszRouter ) { DWORD rc, dwErr; if (g_pwszRouter != pwszRouter) { if (g_hMprConfig) { MprConfigServerDisconnect(g_hMprConfig); g_hMprConfig = NULL; } if (g_hMprAdmin) { MprAdminServerDisconnect(g_hMprAdmin); g_hMprAdmin = NULL; } if (g_hMIBServer) { MprAdminMIBServerDisconnect(g_hMIBServer); g_hMIBServer = NULL; } } // // Connect to router config if required // (when is this ever required) // if ( !g_hMprConfig ) { dwErr = MprConfigServerConnect( (LPWSTR)pwszRouter, &g_hMprConfig ); if ( dwErr isnot NO_ERROR ) { return ERROR_CONNECT_REMOTE_CONFIG; } } // // Check to see if router is running. If so, get the handles // do { if ( MprAdminIsServiceRunning( (LPWSTR)pwszRouter ) ) { if ( MprAdminServerConnect( (LPWSTR)pwszRouter, &g_hMprAdmin ) == NO_ERROR ) { if ( MprAdminMIBServerConnect( (LPWSTR)pwszRouter, &g_hMIBServer ) == NO_ERROR ) { // DEBUG("Got server handle"); break; } else { MprAdminServerDisconnect( g_hMprAdmin ); } } } g_hMprAdmin = g_hMIBServer = NULL; } while (FALSE); return NO_ERROR; } DWORD WINAPI IpxConnect( IN LPCWSTR pwszRouter ) { // If context info is dirty, reregister it if (g_bIpxDirty) { IpxStartHelper(NULL, ParentVersion); } return ConnectToRouter(pwszRouter); } BOOL IsHelpToken( PWCHAR pwszToken ) /*++ Routine Description : Arguements : Return value : --*/ { if( MatchToken( pwszToken, CMD_IPX_HELP1 ) ) { return TRUE; } if( MatchToken( pwszToken, CMD_IPX_HELP2 ) ) { return TRUE; } return FALSE; } BOOL IsReservedKeyWord( PWCHAR pwszToken ) /*++ Routine Description : Arguements : Return value : --*/ { return FALSE; } DWORD MungeArguments( IN OUT LPWSTR *ppwcArguments, IN DWORD dwArgCount, OUT PBYTE *ppbNewArg, OUT PDWORD pdwNewArgCount, OUT PBOOL pbFreeArg ) /*++ Routine Description : To conform to the routemon style of command line, the netsh command line is munged. Munging involves adding a space after the '=' for each "Option=Value" pair on the command line to convert it to "Option= Value". In addition, the first command line arguement is set to the process name "netsh" and all the remaining arguements are shifted one down. Again for conformance reasons. Arguements : ppwcArguments - Current argument list dwArgCount - Number of args in ppwcArguments pbNewArg - Pointer to a buffer that will contain the munged arglist pdwNewArgCount - New argument count after munging pbFreeArg - TRUE if pbNewArg needs to be freed by the invoker. Return value : NO_ERROR - Success ERROR_NOT_ENOUGH_MEMORY - Memory alloc failed --*/ { DWORD dwIndex, dwInd, dwErr; BOOL bPresent = FALSE; PWCHAR *ppwcArgs; *pbFreeArg = FALSE; // // Scan arguement list to see if any are of the form "Option=Value" // for ( dwIndex = 0; dwIndex < dwArgCount; dwIndex++ ) { if ( wcsstr( ppwcArguments[ dwIndex ], NETSH_ARG_DELIMITER ) ) { // // there is an = in this arguement // bPresent = TRUE; break; } } // // if none of the args have an '=', then return the arg. list as is // if ( !bPresent ) { *ppbNewArg = (PBYTE) ppwcArguments; return NO_ERROR; } // // Args. of the form "option=value" are present // ppwcArgs = (PWCHAR *) HeapAlloc( GetProcessHeap(), 0, 2 * dwArgCount * sizeof( PWCHAR ) ); if ( ppwcArgs == NULL ) { return ERROR_NOT_ENOUGH_MEMORY; } ZeroMemory( ppwcArgs, 2 * dwArgCount * sizeof( PWCHAR ) ); // // Copy args that do not have an '=' as is // for ( dwInd = 0; dwInd < dwIndex; dwInd++ ) { DWORD dwLen = ( wcslen( ppwcArguments[ dwInd ] ) + 1 ) * sizeof( WCHAR ); ppwcArgs[ dwInd ] = (PWCHAR) HeapAlloc( GetProcessHeap(), 0, ( wcslen( ppwcArguments[ dwInd ] ) + 1 ) * sizeof( WCHAR ) ); if ( ppwcArgs[ dwInd ] == NULL ) { dwErr = ERROR_NOT_ENOUGH_MEMORY; goto cleanup; } wcscpy( ppwcArgs[ dwInd ], ppwcArguments[ dwInd ] ); } // // Convert args. of the form "option=value" to the form "option= value". // The space is what its all about // for ( dwInd = dwIndex; dwIndex < dwArgCount; dwInd++, dwIndex++ ) { // // Check if this arg. has an '=' sign // if ( wcsstr( ppwcArguments[ dwIndex ], NETSH_ARG_DELIMITER ) ) { // // arg is of the form "option=value" // // break it into 2 arguments of the form // arg(i) == option= // argv(i+1) == value // PWCHAR pw1, pw2; DWORD dwLen; pw1 = wcstok( ppwcArguments[ dwIndex ], NETSH_ARG_DELIMITER ); pw2 = wcstok( NULL, NETSH_ARG_DELIMITER ); dwLen = ( wcslen( pw1 ) + 2 ) * sizeof( WCHAR ); dwLen = ( wcslen( pw2 ) + 1 ) * sizeof( WCHAR ); ppwcArgs[ dwInd ] = (PWCHAR) HeapAlloc( GetProcessHeap(), 0, ( wcslen( pw1 ) + 2 ) * sizeof( WCHAR ) ); ppwcArgs[ dwInd + 1] = (PWCHAR) HeapAlloc( GetProcessHeap(), 0, ( wcslen( pw2 ) + 1 ) * sizeof( WCHAR ) ); if ( ( ppwcArgs[ dwInd ] == NULL ) || ( ppwcArgs[ dwInd + 1 ] == NULL ) ) { dwErr = ERROR_NOT_ENOUGH_MEMORY; goto cleanup; } wcscpy( ppwcArgs[ dwInd ], pw1 ); wcscat( ppwcArgs[ dwInd++ ], NETSH_ARG_DELIMITER ); wcscpy( ppwcArgs[ dwInd ], pw2 ); (*pdwNewArgCount)++; } else { // // no = in this arg, copy as is // ppwcArgs[ dwInd ] = (PWCHAR) HeapAlloc( GetProcessHeap(), 0, ( wcslen( ppwcArguments[ dwIndex ] ) + 1 ) * sizeof( WCHAR ) ); if ( ppwcArgs[ dwInd ] == NULL ) { dwErr = ERROR_NOT_ENOUGH_MEMORY; goto cleanup; } wcscpy( ppwcArgs[ dwInd ], ppwcArguments[ dwIndex ] ); } } *pbFreeArg = TRUE; *ppbNewArg = (PBYTE) ppwcArgs; return NO_ERROR; cleanup : // // Error. Free all allocations // for ( dwInd = 0; dwInd < 2 * dwArgCount; dwInd++ ) { if ( ppwcArgs[ dwInd ] ) { HeapFree( GetProcessHeap(), 0, ppwcArgs[ dwInd ] ); } } if ( ppwcArgs ) { HeapFree( GetProcessHeap(), 0, ppwcArgs ); } return dwErr; } VOID FreeArgTable( IN DWORD dwArgCount, IN OUT LPWSTR *ppwcArgs ) /*++ Routine Description : Frees the allocations for the argument table Arguments : dwArgCount - number of arguments in ppwcArguments ppwcArgs - Table of arguments Return Value : --*/ { DWORD dwInd; for ( dwInd = 0; dwInd < 2 * dwArgCount; dwInd++ ) { if ( ppwcArgs[ dwInd ] ) { HeapFree( GetProcessHeap(), 0, ppwcArgs[ dwInd ] ); } } if ( ppwcArgs ) { HeapFree( GetProcessHeap(), 0, ppwcArgs ); } } DWORD GetTagToken( IN HANDLE hModule, IN OUT LPWSTR *ppwcArguments, IN DWORD dwCurrentIndex, IN DWORD dwArgCount, IN PTAG_TYPE pttTagToken, IN DWORD dwNumTags, OUT PDWORD pdwOut ) /*++ Routine Description: Identifies each argument based on its tag. It assumes that each argument has a tag. It also removes tag= from each argument. Arguments: ppwcArguments - The argument array. Each argument has tag=value form dwCurrentIndex - ppwcArguments[dwCurrentIndex] is first arg. dwArgCount - ppwcArguments[dwArgCount - 1] is last arg. pttTagToken - Array of tag token ids that are allowed in the args dwNumTags - Size of pttTagToken pdwOut - Array identifying the type of each argument. Return Value: NO_ERROR, ERROR_INVALID_PARAMETER, ERROR_INVALID_OPTION_TAG --*/ { DWORD i,j,len; PWCHAR pwcTag,pwcTagVal,pwszArg; BOOL bFound = FALSE; // // This function assumes that every argument has a tag // It goes ahead and removes the tag. // for (i = dwCurrentIndex; i < dwArgCount; i++) { len = wcslen(ppwcArguments[i]); if (len is 0) { // // something wrong with arg // pdwOut[i] = (DWORD) -1; continue; } pwszArg = HeapAlloc(GetProcessHeap(),0,(len + 1) * sizeof(WCHAR)); if (pwszArg is NULL) { DisplayError(g_hModule, ERROR_NOT_ENOUGH_MEMORY); return ERROR_NOT_ENOUGH_MEMORY; } wcscpy(pwszArg, ppwcArguments[i]); pwcTag = wcstok(pwszArg, NETSH_ARG_DELIMITER); // // Got the first part // Now if next call returns NULL then there was no tag // pwcTagVal = wcstok((PWCHAR)NULL, NETSH_ARG_DELIMITER); if (pwcTagVal is NULL) { // DisplayMessage(g_hModule, MSG_IP_TAG_NOT_PRESENT, ppwcArguments[i] ); HeapFree(GetProcessHeap(),0,pwszArg); return ERROR_INVALID_PARAMETER; } // // Got the tag. Now try to match it // bFound = FALSE; pdwOut[i - dwCurrentIndex] = (DWORD) -1; for ( j = 0; j < dwNumTags; j++) { if (MatchToken(pwcTag, pttTagToken[j].pwszTag)) { // // Tag matched // bFound = TRUE; pdwOut[i - dwCurrentIndex] = j; break; } } if (bFound) { // // Remove tag from the argument // wcscpy(ppwcArguments[i], pwcTagVal); } else { //DisplayMessage(g_hModule, MSG_IP_INVALID_TAG, pwcTag); HeapFree(GetProcessHeap(),0,pwszArg); return ERROR_INVALID_OPTION_TAG; } HeapFree(GetProcessHeap(),0,pwszArg); } return NO_ERROR; } DWORD WINAPI IpxSubEntry( IN const NS_CONTEXT_ATTRIBUTES *pSubContext, IN LPCWSTR pwszMachine, IN OUT LPWSTR *ppwcArguments, IN DWORD dwArgCount, IN DWORD dwFlags, IN PVOID pvData, OUT LPWSTR pwcNewContext ) { DWORD dwErr, dwNewArgCount = dwArgCount; PWCHAR *ppwcNewArg = NULL; BOOL bFreeNewArg; PNS_PRIV_CONTEXT_ATTRIBUTES pNsPrivContextAttributes = pSubContext->pReserved; dwErr = MungeArguments( ppwcArguments, dwArgCount, (PBYTE*) &ppwcNewArg, &dwNewArgCount, &bFreeNewArg ); if (dwErr isnot NO_ERROR ) { return dwErr; } if ( (pNsPrivContextAttributes) && (pNsPrivContextAttributes->pfnEntryFn) ) { dwErr = (*pNsPrivContextAttributes->pfnEntryFn)( pwszMachine, ppwcNewArg, dwNewArgCount, dwFlags, g_hMIBServer, pwcNewContext ); } else { dwErr = GenericMonitor(pSubContext, pwszMachine, ppwcNewArg, dwNewArgCount, dwFlags, g_hMIBServer, pwcNewContext ); } if ( bFreeNewArg ) { FreeArgTable( dwArgCount, ppwcNewArg ); } return dwErr; }