#include "precomp.h" const WCHAR c_szCurrentBuildNumber[] = L"CurrentBuildNumber"; const WCHAR c_szWinVersionPath[] = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"; const WCHAR c_szAssignFmt[] = L"%s = %s"; const WCHAR c_szAssignFmt10[] = L"%s = %d"; const WCHAR c_szAssignFmt16[] = L"%s = %x"; WCHAR pszRemoteAccessParamStub[] = L"SYSTEM\\CurrentControlSet\\Services\\RemoteAccess\\Parameters\\"; WCHAR pszEnableIn[] = L"EnableIn"; WCHAR pszAllowNetworkAccess[] = L"AllowNetworkAccess"; typedef struct _NAME_NODE { PWCHAR pszName; struct _NAME_NODE* pNext; } NAME_NODE; #if 0 DWORD RutlDispTokenErrMsg( IN HANDLE hModule, IN DWORD dwMsgId, IN DWORD dwTagId, IN LPCWSTR pwszValue ) /*++ Routine Description: Displays error message with token arguments. Arguments: dwMsgId - Message to be printed dwTagId - The tag string id pwszValue - the value specified for the tag in the Return Value: NO_ERROR --*/ { PWCHAR pwszTag; pwszTag = MakeString(hModule, dwTagId); DisplayMessage(hModule, dwMsgId, pwszValue, pwszTag); FreeString(pwszTag); return NO_ERROR; } #endif DWORD WINAPI RutlGetTagToken( 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 = NULL; 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 = RutlAlloc((len + 1) * sizeof(WCHAR), FALSE); if (pwszArg is NULL) { DisplayError(NULL, 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, ERROR_NO_TAG, ppwcArguments[i]); RutlFree(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 { DisplayError(NULL, ERROR_INVALID_OPTION_TAG, pwcTag); RutlFree(pwszArg); return ERROR_INVALID_OPTION_TAG; } RutlFree(pwszArg); } return NO_ERROR; } DWORD WINAPI RutlCreateDumpFile( IN LPCWSTR pwszName, OUT PHANDLE phFile ) { HANDLE hFile; *phFile = NULL; // Create/open the file hFile = CreateFileW(pwszName, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) return GetLastError(); // Go to the end of the file SetFilePointer(hFile, 0, NULL, FILE_END); *phFile = hFile; return NO_ERROR; } VOID WINAPI RutlCloseDumpFile( HANDLE hFile ) { CloseHandle(hFile); } // // Returns an allocated block of memory conditionally // zeroed of the given size. // PVOID WINAPI RutlAlloc( IN DWORD dwBytes, IN BOOL bZero ) { PVOID pvRet; DWORD dwFlags = 0; if (bZero) { dwFlags |= HEAP_ZERO_MEMORY; } return HeapAlloc(GetProcessHeap(), dwFlags, dwBytes); } // // Conditionally free's a pointer if it is non-null // VOID WINAPI RutlFree( IN PVOID pvData ) { if (pvData) { HeapFree(GetProcessHeap(), 0, pvData); } } // // Uses RutlAlloc to copy a string // PWCHAR WINAPI RutlStrDup( IN LPCWSTR pwszSrc ) { PWCHAR pszRet = NULL; DWORD dwLen; if ((pwszSrc is NULL) or ((dwLen = wcslen(pwszSrc)) == 0) ) { return NULL; } pszRet = (PWCHAR) RutlAlloc((dwLen + 1) * sizeof(WCHAR), FALSE); if (pszRet isnot NULL) { wcscpy(pszRet, pwszSrc); } return pszRet; } // // Uses RutlAlloc to copy a dword // LPDWORD WINAPI RutlDwordDup( IN DWORD dwSrc ) { LPDWORD lpdwRet = NULL; lpdwRet = (LPDWORD) RutlAlloc(sizeof(DWORD), FALSE); if (lpdwRet isnot NULL) { *lpdwRet = dwSrc; } return lpdwRet; } // // Returns the build number of operating system // DWORD WINAPI RutlGetOsVersion( IN RASMON_SERVERINFO *pServerInfo ) { DWORD dwErr, dwType = REG_SZ, dwLength; HKEY hkVersion = NULL; WCHAR pszBuildNumber[64]; // // Initialize // pServerInfo->dwBuild = 0; do { // // Connect to the remote server // dwErr = RegConnectRegistry( pServerInfo->pszServer, HKEY_LOCAL_MACHINE, &pServerInfo->hkMachine); if ( dwErr != ERROR_SUCCESS ) { break; } // // Open the windows version key // dwErr = RegOpenKeyEx( pServerInfo->hkMachine, c_szWinVersionPath, 0, KEY_QUERY_VALUE, &hkVersion ); if ( dwErr != NO_ERROR ) { break; } // // Read in the current version key // dwLength = sizeof(pszBuildNumber); dwErr = RegQueryValueEx ( hkVersion, c_szCurrentBuildNumber, NULL, &dwType, (BYTE*)pszBuildNumber, &dwLength ); if (dwErr != NO_ERROR) { break; } pServerInfo->dwBuild = (DWORD) wcstol(pszBuildNumber, NULL, 10); } while (FALSE); // Cleanup { if ( hkVersion ) { RegCloseKey( hkVersion ); } } return dwErr; } DWORD WINAPI RutlParseOptions( IN OUT LPWSTR *ppwcArguments, IN DWORD dwCurrentIndex, IN DWORD dwArgCount, IN DWORD dwNumArgs, IN TAG_TYPE* rgTags, IN DWORD dwTagCount, OUT LPDWORD* ppdwTagTypes) /*++ Routine Description: Based on an array of tag types returns which options are included in the given command line. Arguments: ppwcArguments - Argument array dwCurrentIndex - ppwcArguments[dwCurrentIndex] is the first arg dwArgCount - ppwcArguments[dwArgCount - 1] is the last arg Return Value: NO_ERROR --*/ { LPDWORD pdwTagType; DWORD i, dwErr = NO_ERROR; // If there are no arguments, there's nothing to to // if ( dwNumArgs == 0 ) { return NO_ERROR; } // Set up the table of present options pdwTagType = (LPDWORD) RutlAlloc(dwArgCount * sizeof(DWORD), TRUE); if(pdwTagType is NULL) { DisplayError(NULL, ERROR_NOT_ENOUGH_MEMORY); return ERROR_NOT_ENOUGH_MEMORY; } do { // // The argument has a tag. Assume all of them have tags // if(wcsstr(ppwcArguments[dwCurrentIndex], NETSH_ARG_DELIMITER)) { dwErr = RutlGetTagToken( g_hModule, ppwcArguments, dwCurrentIndex, dwArgCount, rgTags, dwTagCount, pdwTagType); if(dwErr isnot NO_ERROR) { if(dwErr is ERROR_INVALID_OPTION_TAG) { dwErr = ERROR_INVALID_SYNTAX; break; } } } else { // // No tags - all args must be in order // for(i = 0; i < dwNumArgs; i++) { pdwTagType[i] = i; } } } while (FALSE); // Cleanup { if (dwErr is NO_ERROR) { *ppdwTagTypes = pdwTagType; } else { RutlFree(pdwTagType); } } return dwErr; } BOOL WINAPI RutlIsHelpToken( PWCHAR pwszToken ) { if(MatchToken(pwszToken, CMD_RAS_HELP1)) return TRUE; if(MatchToken(pwszToken, CMD_RAS_HELP2)) return TRUE; return FALSE; } PWCHAR WINAPI RutlAssignmentFromTokens( IN HINSTANCE hModule, IN LPCWSTR pwszToken, IN LPCWSTR pszString) { PWCHAR pszRet = NULL; LPCWSTR pszCmd = NULL; DWORD dwErr = NO_ERROR, dwSize; do { pszCmd = pwszToken; // Compute the string lenghth needed // dwSize = wcslen(pszString) + wcslen(pszCmd) + wcslen(c_szAssignFmt) + 1; dwSize *= sizeof(WCHAR); // Allocate the return value pszRet = (PWCHAR) RutlAlloc(dwSize, FALSE); if (pszRet is NULL) { dwErr = ERROR_NOT_ENOUGH_MEMORY; break; } // Copy in the command assignment wsprintfW(pszRet, c_szAssignFmt, pszCmd, pszString); } while (FALSE); // Cleanup { if (dwErr isnot NO_ERROR) { if (pszRet isnot NULL) { RutlFree(pszRet); } pszRet = NULL; } } return pszRet; } PWCHAR WINAPI RutlAssignmentFromTokenAndDword( IN HINSTANCE hModule, IN LPCWSTR pwszToken, IN DWORD dwDword, IN DWORD dwRadius) { PWCHAR pszRet = NULL; LPCWSTR pszCmd = NULL; DWORD dwErr = NO_ERROR, dwSize; do { pszCmd = pwszToken; // Compute the string length needed // dwSize = 64 + wcslen(pszCmd) + wcslen(c_szAssignFmt10) + 1; dwSize *= sizeof(WCHAR); // Allocate the return value pszRet = (PWCHAR) RutlAlloc(dwSize, FALSE); if (pszRet is NULL) { dwErr = ERROR_NOT_ENOUGH_MEMORY; break; } // Copy in the command assignment if (dwRadius == 10) { wsprintfW(pszRet, c_szAssignFmt10, pszCmd, dwDword); } else { wsprintfW(pszRet, c_szAssignFmt16, pszCmd, dwDword); } } while (FALSE); // Cleanup { if (dwErr isnot NO_ERROR) { if (pszRet isnot NULL) { RutlFree(pszRet); } pszRet = NULL; } } return pszRet; } DWORD RutlRegReadDword( IN HKEY hKey, IN LPCWSTR pszValName, OUT LPDWORD lpdwValue) { DWORD dwSize = sizeof(DWORD), dwType = REG_DWORD, dwErr; dwErr = RegQueryValueExW( hKey, pszValName, NULL, &dwType, (LPBYTE)lpdwValue, &dwSize); if (dwErr == ERROR_FILE_NOT_FOUND) { dwErr = NO_ERROR; } return dwErr; } DWORD RutlRegReadString( IN HKEY hKey, IN LPCWSTR pszValName, OUT LPWSTR* ppszValue) { DWORD dwErr = NO_ERROR, dwSize = 0; *ppszValue = NULL; // Findout how big the buffer should be // dwErr = RegQueryValueExW( hKey, pszValName, NULL, NULL, NULL, &dwSize); if (dwErr == ERROR_FILE_NOT_FOUND) { return NO_ERROR; } if (dwErr != ERROR_SUCCESS) { return dwErr; } // Allocate the string // *ppszValue = (PWCHAR) RutlAlloc(dwSize, TRUE); if (*ppszValue == NULL) { return ERROR_NOT_ENOUGH_MEMORY; } // Read the value in and return // dwErr = RegQueryValueExW( hKey, pszValName, NULL, NULL, (LPBYTE)*ppszValue, &dwSize); return dwErr; } DWORD RutlRegWriteDword( IN HKEY hKey, IN LPCWSTR pszValName, IN DWORD dwValue) { return RegSetValueExW( hKey, pszValName, 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(DWORD)); } DWORD RutlRegWriteString( IN HKEY hKey, IN LPCWSTR pszValName, IN LPCWSTR pszValue) { return RegSetValueExW( hKey, pszValName, 0, REG_SZ, (LPBYTE)pszValue, (wcslen(pszValue) + 1) * sizeof(WCHAR)); } // // Enumerates all of the subkeys of a given key // DWORD RutlRegEnumKeys( IN HKEY hkKey, IN RAS_REGKEY_ENUM_FUNC_CB pCallback, IN HANDLE hData) { DWORD dwErr = NO_ERROR, i, dwNameSize = 0, dwCurSize = 0; DWORD dwCount = 0; HKEY hkCurKey = NULL; PWCHAR pszName = NULL; NAME_NODE *pHead = NULL, *pTemp = NULL; do { // Find out how many sub keys there are // dwErr = RegQueryInfoKeyW( hkKey, NULL, NULL, NULL, &dwCount, &dwNameSize, NULL, NULL, NULL, NULL, NULL, NULL); if (dwErr != ERROR_SUCCESS) { return dwErr; } dwNameSize++; // Allocate the name buffer // pszName = (PWCHAR) RutlAlloc(dwNameSize * sizeof(WCHAR), FALSE); if (pszName == NULL) { dwErr = ERROR_NOT_ENOUGH_MEMORY; break; } // Loop through the keys building the list // for (i = 0; i < dwCount; i++) { dwCurSize = dwNameSize; // Get the name of the current key // dwErr = RegEnumKeyExW( hkKey, i, pszName, &dwCurSize, 0, NULL, NULL, NULL); if (dwErr != ERROR_SUCCESS) { continue; } // Add the key to the list // pTemp = (NAME_NODE*) RutlAlloc(sizeof(NAME_NODE), TRUE); if (pTemp == NULL) { dwErr = ERROR_NOT_ENOUGH_MEMORY; break; } pTemp->pszName = RutlStrDup(pszName); if (pTemp->pszName == NULL) { dwErr = ERROR_NOT_ENOUGH_MEMORY; break; } pTemp->pNext = pHead; pHead = pTemp; } BREAK_ON_DWERR(dwErr); // Now loop through the list, calling the callback. // The reason the items are added to a list like this // is that this allows the callback to safely delete // the reg key without messing up the enumeration // pTemp = pHead; while (pTemp) { // Open the subkey // dwErr = RegOpenKeyExW( hkKey, pTemp->pszName, 0, KEY_ALL_ACCESS, &hkCurKey); if (dwErr != ERROR_SUCCESS) { continue; } // Call the callback // dwErr = pCallback(pTemp->pszName, hkCurKey, hData); RegCloseKey(hkCurKey); if (dwErr != NO_ERROR) { break; } pTemp = pTemp->pNext; } } while (FALSE); // Cleanup { RutlFree(pszName); while (pHead) { RutlFree(pHead->pszName); pTemp = pHead->pNext; RutlFree(pHead); pHead = pTemp; } } return dwErr; } // // Generic parse // DWORD RutlParse( IN OUT LPWSTR* ppwcArguments, IN DWORD dwCurrentIndex, IN DWORD dwArgCount, IN BOOL* pbDone, OUT RASMON_CMD_ARG* pRasArgs, IN DWORD dwRasArgCount) { DWORD i, dwNumArgs, dwErr, dwLevel = 0; LPDWORD pdwTagType = NULL; TAG_TYPE* pTags = NULL; RASMON_CMD_ARG* pArg = NULL; if (dwRasArgCount == 0) { return ERROR_INVALID_PARAMETER; } do { // Initialize dwNumArgs = dwArgCount - dwCurrentIndex; // Generate a list of the tags // pTags = (TAG_TYPE*) RutlAlloc(dwRasArgCount * sizeof(TAG_TYPE), TRUE); if (pTags == NULL) { dwErr = ERROR_NOT_ENOUGH_MEMORY; break; } for (i = 0; i < dwRasArgCount; i++) { CopyMemory(&pTags[i], &pRasArgs[i].rgTag, sizeof(TAG_TYPE)); } // Get the list of present options // dwErr = RutlParseOptions( ppwcArguments, dwCurrentIndex, dwArgCount, dwNumArgs, pTags, dwRasArgCount, &pdwTagType); if (dwErr isnot NO_ERROR) { break; } // Copy the tag info back // for (i = 0; i < dwRasArgCount; i++) { CopyMemory(&pRasArgs[i].rgTag, &pTags[i], sizeof(TAG_TYPE)); } for(i = 0; i < dwNumArgs; i++) { // Validate the current argument // if (pdwTagType[i] >= dwRasArgCount) { i = dwNumArgs; dwErr = ERROR_INVALID_SYNTAX; break; } pArg = &pRasArgs[pdwTagType[i]]; // Get the value of the argument // switch (pArg->dwType) { case RASMONTR_CMD_TYPE_STRING: pArg->Val.pszValue = RutlStrDup(ppwcArguments[i + dwCurrentIndex]); break; case RASMONTR_CMD_TYPE_DWORD: pArg->Val.dwValue = _wtol(ppwcArguments[i + dwCurrentIndex]); break; case RASMONTR_CMD_TYPE_ENUM: dwErr = MatchEnumTag(g_hModule, ppwcArguments[i + dwCurrentIndex], pArg->dwEnumCount, pArg->rgEnums, &(pArg->Val.dwValue)); if(dwErr != NO_ERROR) { RutlDispTokenErrMsg( g_hModule, EMSG_BAD_OPTION_VALUE, pArg->rgTag.pwszTag, ppwcArguments[i + dwCurrentIndex]); i = dwNumArgs; dwErr = ERROR_INVALID_PARAMETER; } break; } if (dwErr != NO_ERROR) { break; } // Mark the argument as present if needed // if (pArg->rgTag.bPresent) { dwErr = ERROR_TAG_ALREADY_PRESENT; i = dwNumArgs; break; } pArg->rgTag.bPresent = TRUE; } if(dwErr isnot NO_ERROR) { break; } // Make sure that all of the required parameters have // been included. // for (i = 0; i < dwRasArgCount; i++) { if ((pRasArgs[i].rgTag.dwRequired & NS_REQ_PRESENT) && !pRasArgs[i].rgTag.bPresent) { DisplayMessage(g_hModule, EMSG_CANT_FIND_EOPT); dwErr = ERROR_INVALID_SYNTAX; break; } } if(dwErr isnot NO_ERROR) { break; } } while (FALSE); // Cleanup { if (pTags) { RutlFree(pTags); } if (pdwTagType) { RutlFree(pdwTagType); } } return dwErr; }