//*********************************************************** // Copyright (C) Microsoft Corporation, 1996 - 1998 // // metasnap.cpp // // Description: Metabase Snapshot utility tool main // // History: 15-July-98 Tamas Nemeth (t-tamasn) Created. // //*********************************************************** #define INITGUID #define E_UNKNOWN_ARG 0x10000 #define E_WRONG_NUMBER_ARGS 0x20000 #define E_NULL_PTR 0x30000 #define DEFAULT_MD_TIMEOUT 0x1000 #define DEFAULT_GETALL_BUFFER_SIZE 4096 //#define DBG_ASSERT(exp) //# define DBG_ASSERT(exp) ((void)0) /* Do Nothing */ //#include "stdafx.h" //#include "winsock.h" //#undef dllexp //#include "tcpdllp.hxx" //#define _RDNS_STANDALONE //#include "afx.h" #include #include #include #include #include #include "iadmw.h" #include "iiscnfg.h" #include "uiutils.h" //#include //extern "C" DEBUG_PRINTS * g_pDebug = NULL; //#undef dllexp //#include "tcpdllp.hxx" //#define _RDNS_STANDALONE enum ERROR_PARAMETER { MACHINE_NAME, START_KEY_NAME, }; struct _CMD_PARAMS { LPWSTR szMachineName; LPWSTR szStartKey; BOOL bShowSecure; // DWORD dwErrParameter; // to determine which parameter is incorrect }; typedef struct _CMD_PARAMS CMD_PARAMS; //typedef CString* pCString; // Global variables: //DWORD* dwSortArray; PBYTE pbGetAllBuffer; // Function prototypes: HRESULT PrintKeyRecursively(IMSAdminBase *pcAdmCom, WCHAR *lpwstrFullPath, CMD_PARAMS* pcpCommandStructure); HRESULT PrintAllPropertiesAtKey (IMSAdminBase *pcAdmCom, METADATA_HANDLE hmdHandle, CMD_PARAMS* pcpCommandStructure); VOID PrintProperty(METADATA_GETALL_RECORD & mdr, BOOL bShowSecure); VOID PrintDataTypeAndValue(METADATA_GETALL_RECORD *pmdgr, BOOL bShowSecure); DWORD ParseCommands (int argc, char *argv[], CMD_PARAMS *pcpCommandStructure); VOID DisplayHelp(); // new stuff DWORD AddAccessEntries( IN ADDRESS_CHECK & ac, IN BOOL fName, IN BOOL fGrant, //OUT CObListPlus & oblAccessList, OUT DWORD & cEntries ) /*++ Routine Description: Add specific kind of addresses from the list to the oblist of access entries Arguments: ADDRESS_CHECK & ac : Address list input object BOOL fName : TRUE for names, FALSE for ip BOOL fGrant : TRUE for granted, FALSE for denied CObListPlus & oblAccessList : ObList to add access entries to int & cEntries : Returns the number of entries Return Value: Error code Notes: Sentinel entries (ip 0.0.0.0) are not added to the oblist, but are reflected in the cEntries return value --*/ { DWORD i; DWORD dwFlags; if (fName) { // // Domain names // LPSTR lpName; cEntries = ac.GetNbName(fGrant); //printf("Number of names: %ld.\n",cEntries); for (i = 0L; i < cEntries; ++i) { if (ac.GetName(fGrant, i, &lpName, &dwFlags)) { if (fGrant) printf("\tGranted to %s.\n",lpName); else printf("\tDenied to %s.\n",lpName); /*CString strDomain(lpName); if (!(dwFlags & DNSLIST_FLAG_NOSUBDOMAIN)) { strDomain = _T("*.") + strDomain; }*/ //oblAccessList.AddTail(new CIPAccessDescriptor(fGrant, strDomain)); } } } else { // // IP Addresses // LPBYTE lpMask; LPBYTE lpAddr; cEntries = ac.GetNbAddr(fGrant); //printf("Number of addresses: %ld.\n",cEntries); for (i = 0L; i < cEntries; ++i) { if (ac.GetAddr(fGrant, i, &dwFlags, &lpMask, &lpAddr)) { if (lpAddr[0] != 0 || lpAddr[1] != 0 || lpAddr[2] !=0 || lpAddr[3] !=0) { if (lpAddr[0] != 0 || lpAddr[1] != 0 || lpAddr[2] !=0 || lpAddr[3] !=0) if (fGrant) printf("\tGranted to %d",lpAddr[0]); else printf("\tDenied to %d",lpAddr[0]); for (int j = 1; j<4; j++) printf(".%d",lpAddr[j]); if (lpMask[0] != 255 || lpMask[1] != 255 || lpMask[2] !=255 || lpMask[3] !=255) { printf(" (Mask: %d",lpMask[0]); for (int j = 1; j<4; j++) printf(".%d",lpMask[j]); printf(")"); } printf(".\n"); } else printf("\tDenied to everyone.\n"); } } } return ERROR_SUCCESS; } DWORD BuildIplOblistFromBlob( IN METADATA_GETALL_RECORD & mdgr //OUT CObListPlus & oblAccessList, // OUT BOOL & fGrantByDefault ) { //oblAccessList.RemoveAll(); if (mdgr.dwMDDataLen == 0) { return ERROR_SUCCESS; } ADDRESS_CHECK ac; ac.BindCheckList(mdgr.pbMDData, mdgr.dwMDDataLen); DWORD cGrantAddr, cGrantName, cDenyAddr, cDenyName; // Name/IP Granted/Deny // ============================================================ AddAccessEntries(ac, TRUE, TRUE, cGrantName); AddAccessEntries(ac, FALSE, TRUE, cGrantAddr); AddAccessEntries(ac, TRUE, FALSE, cDenyName); AddAccessEntries(ac, FALSE, FALSE, cDenyAddr); ac.UnbindCheckList(); // fGrantByDefault = (cDenyAddr + cDenyName != 0L) // || (cGrantAddr + cGrantName == 0L); return ERROR_SUCCESS; } // end new VOID __cdecl main (int argc, char *argv[]) { if (argc == 1) { DisplayHelp(); return; } CMD_PARAMS pcpCommands; DWORD dwRetVal = ParseCommands (argc, argv, &pcpCommands); if (dwRetVal != ERROR_SUCCESS) { if (dwRetVal == E_OUTOFMEMORY) fprintf (stderr, "ERROR: Out of memory."); else if (dwRetVal == E_WRONG_NUMBER_ARGS) fprintf (stderr, "ERROR: Invalid number of arguments."); else if (dwRetVal == E_INVALIDARG) { fprintf (stderr, "ERROR: Invalid input value"); switch (pcpCommands.dwErrParameter) { case (MACHINE_NAME): fputs (" for MachineName.", stderr); break; case (START_KEY_NAME): fputs (" for StartKey.", stderr); break; default: fputs (".", stderr); break; } } else fprintf (stderr, "ERROR: Unknown error in processing arguments."); fputs(" Enter \"metasnap\" without arguments to display help.\n", stderr); return; } IMSAdminBase *pcAdmCom = NULL; //interface pointer IClassFactory * pcsfFactory = NULL; COSERVERINFO csiMachineName; COSERVERINFO *pcsiParam = NULL; // Fill the structure for CoGetClassObject: csiMachineName.pAuthInfo = NULL; csiMachineName.dwReserved1 = 0; csiMachineName.dwReserved2 = 0; pcsiParam = &csiMachineName; csiMachineName.pwszName = pcpCommands.szMachineName; // Initialize COM: HRESULT hresError = CoInitializeEx(NULL, COINIT_MULTITHREADED); if (FAILED(hresError)) { fprintf (stderr, "ERROR: COM Initialization failed. Error: %d (%#x)\n", hresError, hresError); return; } hresError = CoGetClassObject(GETAdminBaseCLSID(TRUE), CLSCTX_SERVER, pcsiParam, IID_IClassFactory, (void**) &pcsfFactory); if (FAILED(hresError)) { switch (hresError) { case HRESULT_FROM_WIN32(REGDB_E_CLASSNOTREG): fprintf(stderr, "ERROR: IIS Metabase does not exist.\n"); break; case HRESULT_FROM_WIN32(E_ACCESSDENIED): fprintf(stderr, "ERROR: Access to Metabase denied.\n"); break; case HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE): fprintf(stderr, "ERROR: The specified host is unavailable.\n"); break; default: fprintf (stderr, "ERROR: Couldn't get Metabase Object. Error: %d (%#x)\n", hresError, hresError); break; } return; } hresError = pcsfFactory->CreateInstance(NULL, IID_IMSAdminBase, (void **) &pcAdmCom); if (FAILED(hresError)) { switch (hresError) { case HRESULT_FROM_WIN32(RPC_S_SEC_PKG_ERROR): fprintf (stderr, "ERROR: A security-related error occurred.\n"); break; case HRESULT_FROM_WIN32(E_OUTOFMEMORY): fprintf (stderr, "ERROR: There is not enough memory available.\n"); break; default: fprintf (stderr, "ERROR: Couldn't create Metabase Instance. Error: %d (%#x)\n", hresError, hresError); break; } pcsfFactory->Release(); return; } pcsfFactory->Release(); METADATA_HANDLE hmdHandle; hresError = pcAdmCom->OpenKey ( METADATA_MASTER_ROOT_HANDLE, pcpCommands.szStartKey, METADATA_PERMISSION_READ, DEFAULT_MD_TIMEOUT, &hmdHandle); if (FAILED(hresError)) { switch (hresError) { case HRESULT_FROM_WIN32(ERROR_PATH_BUSY): fprintf (stderr, "ERROR: The specified key is already in use.\n"); break; case HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND): fprintf (stderr, "ERROR: The specified key is not found.\n"); break; default: fprintf (stderr, "ERROR: Couldn't open Metabase Key. Error: %d (%#x)\n", hresError, hresError); break; } pcAdmCom->Release(); return; } // Recurse and dump children printf("\nIP address and domain name access restrictions:\n"); hresError = PrintKeyRecursively(pcAdmCom, pcpCommands.szStartKey, &pcpCommands); if (hresError != ERROR_SUCCESS) { switch (hresError) { case HRESULT_FROM_WIN32(ERROR_PATH_BUSY): fprintf (stderr, "ERROR: Could not open a key because it is already in use.\n"); break; case HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY): fprintf (stderr, "ERROR: There is not enough memory available.\n"); break; default: fprintf (stderr, "ERROR: Failed dumping metabase. Error: %u (%#x)\n", hresError, hresError); break; } } pcAdmCom->CloseKey (hmdHandle); pcAdmCom->Release(); if (hresError == ERROR_SUCCESS) fputs("Successfully printed IP Security information.\n", stderr); } DWORD ParseCommands (int argc, char *argv [], CMD_PARAMS *pcpCommandStructure) { if (pcpCommandStructure == NULL) return E_NULL_PTR; if ( argc > 3 ) return E_WRONG_NUMBER_ARGS; // Set default values: pcpCommandStructure->szMachineName = (LPWSTR) HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, (9 + 1) * sizeof (WCHAR) ); if (pcpCommandStructure->szMachineName == NULL) return E_OUTOFMEMORY; wcscpy(pcpCommandStructure->szMachineName,L"localhost"); pcpCommandStructure->bShowSecure = FALSE; // Handle StartKey: DWORD dwStartKeyLen = _mbstrlen(argv[1]) + 3; pcpCommandStructure->szStartKey = (LPWSTR) HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, (dwStartKeyLen + 1) * sizeof (WCHAR)); LPWSTR lpwstrTemp = (LPWSTR) HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, (dwStartKeyLen + 1) * sizeof (WCHAR)); // _mbscpy(lpwstrTemp,"/LM"); // wcscat(lpwstrTemp, argv[1]); // printf("%S\n",lpwstrTemp); // wcscpy(pcpCommands.szStartKey, lpwstrTemp); if (pcpCommandStructure->szStartKey == NULL) return E_OUTOFMEMORY; DWORD dwResult = MultiByteToWideChar( CP_ACP, 0, argv[1], dwStartKeyLen + 1, pcpCommandStructure->szStartKey, dwStartKeyLen + 1); if (dwResult == 0) { pcpCommandStructure->dwErrParameter = START_KEY_NAME; return E_INVALIDARG; } // Add /lm to StartKey: wcscpy(lpwstrTemp,L"/LM"); wcscat(lpwstrTemp, pcpCommandStructure->szStartKey); wcscpy(pcpCommandStructure->szStartKey, lpwstrTemp); // Chop off trailing slashes: LPWSTR lpwchTemp = pcpCommandStructure->szStartKey; for (DWORD i=0; i < dwStartKeyLen-1; i++) lpwchTemp++; if (!wcscmp(lpwchTemp, TEXT("/") ) || !wcscmp(lpwchTemp, TEXT("\\")) ) *(lpwchTemp) = (WCHAR)'\0'; // Look for MachineName: if ( argc > 2 && strcmp("-s",argv[2])) { DWORD dwMachineNameLen = _mbstrlen(argv[2]); pcpCommandStructure->szMachineName = (LPWSTR) HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, (dwMachineNameLen + 1) * sizeof (WCHAR) ); if (pcpCommandStructure->szMachineName == NULL) return E_OUTOFMEMORY; dwResult = MultiByteToWideChar( CP_ACP, 0, argv[2], dwMachineNameLen + 1, pcpCommandStructure->szMachineName, dwMachineNameLen + 1); if (dwResult == 0) { pcpCommandStructure->dwErrParameter = MACHINE_NAME; return E_INVALIDARG; } // Check for "-s" flag: if (argc == 4) { if ( !strcmp("-s",argv[3]) ) pcpCommandStructure->bShowSecure = TRUE; else return E_INVALIDARG; } } else if (argc == 3 && !strcmp("-s",argv[2])) pcpCommandStructure->bShowSecure = TRUE; else if (argc > 2) return E_INVALIDARG; return ERROR_SUCCESS; } HRESULT PrintKeyRecursively(IMSAdminBase *pcAdmCom, WCHAR *lpwstrFullPath, CMD_PARAMS* pcpCommandStructure) { METADATA_HANDLE hmdHandle; HRESULT hresError = pcAdmCom->OpenKey( METADATA_MASTER_ROOT_HANDLE, lpwstrFullPath, METADATA_PERMISSION_READ, DEFAULT_MD_TIMEOUT, &hmdHandle); if (hresError != ERROR_SUCCESS) return hresError; // Get all data into a buffer: DWORD dwNumDataEntries ; DWORD dwDataSetNumber; DWORD dwRequestBufferSize = DEFAULT_GETALL_BUFFER_SIZE; DWORD dwRequiredDataLen; // Allocate a default buffer size pbGetAllBuffer = (PBYTE)HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, DEFAULT_GETALL_BUFFER_SIZE); if (pbGetAllBuffer == NULL) return HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY); hresError = pcAdmCom -> GetAllData ( hmdHandle, TEXT ("/"), 0, 0, 0, &dwNumDataEntries, &dwDataSetNumber, dwRequestBufferSize, pbGetAllBuffer, &dwRequiredDataLen); if (hresError == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) { // retry the GetAllData with the new buffer size dwRequestBufferSize = dwRequiredDataLen; pbGetAllBuffer = (PBYTE)HeapReAlloc (GetProcessHeap(), 0, pbGetAllBuffer, dwRequestBufferSize); if (!pbGetAllBuffer) return HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY); hresError = pcAdmCom -> GetAllData ( hmdHandle, TEXT ("/"), 0, 0, 0, &dwNumDataEntries, &dwDataSetNumber, dwRequestBufferSize, pbGetAllBuffer, &dwRequiredDataLen); } if (hresError != ERROR_SUCCESS) { HeapFree (GetProcessHeap(), 0, pbGetAllBuffer); return hresError; } METADATA_GETALL_RECORD *pmdgr = NULL; for (DWORD dwIndex = 0; dwIndex < dwNumDataEntries; dwIndex ++) { pmdgr = &(((METADATA_GETALL_RECORD *) pbGetAllBuffer)[dwIndex]); pmdgr->pbMDData = pmdgr->dwMDDataOffset + pbGetAllBuffer; if (pmdgr->dwMDIdentifier == 6019 && pmdgr->dwMDDataType == BINARY_METADATA && pmdgr->dwMDDataLen > 0) { printf(" [%S]\n",lpwstrFullPath); // PrintProperty(*pmdgr, pcpCommandStructure->bShowSecure); BuildIplOblistFromBlob( *pmdgr); } } WCHAR *lpwstrTempPath = (WCHAR*) HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, METADATA_MAX_NAME_LEN * sizeof (WCHAR)); if (lpwstrTempPath == NULL) return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); // Find out number of the children: DWORD dwChildCount = 0; while (1) { hresError = pcAdmCom->EnumKeys ( hmdHandle, TEXT("/"), lpwstrTempPath, dwChildCount); if (hresError != ERROR_SUCCESS) break; dwChildCount++; } if (dwChildCount == 0) return ERROR_SUCCESS; // Dynamically allocate arrays: LPWSTR * lpwstrChildPath = new LPWSTR[dwChildCount]; DWORD * dwSortedIndex = new DWORD[dwChildCount]; // Initialization: for (dwIndex = 0; dwIndex < dwChildCount; dwIndex++) { dwSortedIndex[dwIndex] = dwIndex; hresError = pcAdmCom->EnumKeys ( hmdHandle, TEXT("/"), lpwstrTempPath, dwIndex); lpwstrChildPath[dwIndex] = (WCHAR*) HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, (wcslen (lpwstrTempPath) + 1) * sizeof (WCHAR)); if (lpwstrChildPath[dwIndex] == NULL) { hresError = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); break; } else wcscpy(lpwstrChildPath[dwIndex], lpwstrTempPath); } if (hresError == ERROR_SUCCESS) { // Sort children lexicographically (here we assume that dwChildCount is small) if (dwChildCount > 1 ) { DWORD dwTemp; for (DWORD i = 1; i < dwChildCount; i++) for (DWORD j=0; j < dwChildCount-i; j++) { if (wcscmp(lpwstrChildPath[dwSortedIndex[j]],lpwstrChildPath[dwSortedIndex[j+1]]) > 0) { dwTemp = dwSortedIndex[j+1]; dwSortedIndex[j+1] = dwSortedIndex[j]; dwSortedIndex[j] = dwTemp; } } } for (dwIndex = 0; dwIndex < dwChildCount; dwIndex++) { // create the full path name for the child: wsprintf(lpwstrTempPath,TEXT("%s/%s"),lpwstrFullPath,lpwstrChildPath[dwSortedIndex[dwIndex]]); HeapFree (GetProcessHeap(), 0, lpwstrChildPath[dwSortedIndex[dwIndex]]); hresError = PrintKeyRecursively (pcAdmCom, lpwstrTempPath, pcpCommandStructure); if (hresError != ERROR_SUCCESS) break; } } // Close keys, free memory and exit pcAdmCom->CloseKey(hmdHandle); delete lpwstrChildPath; delete dwSortedIndex; HeapFree (GetProcessHeap(), 0, lpwstrTempPath); return hresError; } VOID DisplayHelp() { fprintf (stderr, "\n DESCRIPTION: Displays the IP address/domain name restictions.\n\n"); fprintf (stderr, " FORMAT: ipperm \n\n"); fprintf (stderr, " : metabase key to start at.\n"); fprintf (stderr, " : name of host (optional, default: localhost).\n\n"); fprintf (stderr, " EXAMPLES: ipperm /w3svc/1 t-tamasn2\n"); fprintf (stderr, " ipperm / > dump.txt (dump all to text)\n\n"); }