#include #define INITGUID // must be before iadmw.h #include // Interface header //#include // MD_ & IIS_MD_ defines #include // MD_ & IIS_MD_ defines #define REASONABLE_TIMEOUT 1000 #define MD_ISAPI_RESTRICTION_LIST (IIS_MD_HTTP_BASE+163) #define MD_CGI_RESTRICTION_LIST (IIS_MD_HTTP_BASE+164) #define MD_RESTRICTION_LIST_CUSTOM_DESC (IIS_MD_HTTP_BASE+165) void ShowHelp(void); LPSTR StripWhitespace(LPSTR pszString); BOOL OpenMetabaseAndDoStuff(WCHAR * wszVDir, WCHAR * wszDir, int iTrans); BOOL GetVdirPhysicalPath(IMSAdminBase *pIMSAdminBase,WCHAR * wszVDir,WCHAR *wszStringPathToFill); BOOL AddVirtualDir(IMSAdminBase *pIMSAdminBase, WCHAR * wszVDir, WCHAR * wszDir); BOOL RemoveVirtualDir(IMSAdminBase *pIMSAdminBase, WCHAR * wszVDir); HRESULT LoadAllData(IMSAdminBase * pmb, METADATA_HANDLE hMetabase,WCHAR *subdir, BYTE **buf, DWORD *size,DWORD *count); HRESULT AddVirtualServer(UINT iServerNum, UINT iServerPort, WCHAR * wszDefaultVDirDir); HRESULT DelVirtualServer(UINT iServerNum); HRESULT AddRemoveIISRestrictionListEntry(WCHAR * wszFilePath,BOOL bBinaryIsISAPI,BOOL bEnableThisBinary); HRESULT AddRemoveIISCustomDescriptionEntry(WCHAR * wszFilePathInput,WCHAR * wszDescription,BOOL bCannotBeRemovedByUser, BOOL bAddToList); BOOL OpenMetabaseAndDoExport(void); BOOL OpenMetabaseAndDoImport(void); BOOL OpenMetabaseAndGetVersion(void); HRESULT RemoteOpenMetabaseAndCallExport( const WCHAR *pcszMachineName, const WCHAR *pcszUserName, const WCHAR *pcszDomain, const WCHAR *pcszPassword ); inline HRESULT SetBlanket(LPUNKNOWN pIUnk) { return CoSetProxyBlanket( pIUnk, RPC_C_AUTHN_WINNT, // NTLM authentication service RPC_C_AUTHZ_NONE, // default authorization service... NULL, // no mutual authentication RPC_C_AUTHN_LEVEL_CONNECT, // authentication level RPC_C_IMP_LEVEL_IMPERSONATE, // impersonation level NULL, // use current token EOAC_NONE ); // no special capabilities } #define TRANS_ADD 0 #define TRANS_DEL 1 #define TRANS_PRINT_PATH 2 #define TRANS_ADD_VIRTUAL_SERVER 4 #define TRANS_DEL_VIRTUAL_SERVER 8 #define TRANS_ADD_ISAPI_RESTRICT 16 #define TRANS_DEL_ISAPI_RESTRICT 32 #define TRANS_ADD_CGI_RESTRICT 64 #define TRANS_DEL_CGI_RESTRICT 128 #define TRANS_ADD_CUSTOM_DESCRIPTION 256 #define TRANS_DEL_CUSTOM_DESCRIPTION 512 #define TRANS_EXPORT_CONFIG 1024 #define TRANS_GET_VERSION 2048 int __cdecl main(int argc,char *argv[]) { BOOL fRet = FALSE; int argno; char * pArg = NULL; char * pCmdStart = NULL; WCHAR wszPrintString[MAX_PATH]; char szTempString[MAX_PATH]; int iGotParamC = FALSE; int iGotParamI = FALSE; int iGotParamS = FALSE; int iGotParamL = FALSE; int iGotParamM = FALSE; int iGotParamN = FALSE; int iGotParamP = FALSE; int iGotParamV = FALSE; int iDoDelete = FALSE; int iDoWebPath = FALSE; int iDoExport = FALSE; int iDoImport = FALSE; int iDoVersion = FALSE; int iTrans = 0; WCHAR wszDirPath[MAX_PATH]; WCHAR wszVDirName[MAX_PATH]; WCHAR wszTempString_C[MAX_PATH]; WCHAR wszTempString_I[MAX_PATH]; WCHAR wszTempString_S[MAX_PATH]; WCHAR wszTempString_L[MAX_PATH]; WCHAR wszTempString_M[MAX_PATH]; WCHAR wszTempString_N[MAX_PATH]; WCHAR wszTempString_P[MAX_PATH]; wszDirPath[0] = '\0'; wszVDirName[0] = '\0'; wszTempString_C[0] = '\0'; wszTempString_I[0] = '\0'; wszTempString_S[0] = '\0'; wszTempString_L[0] = '\0'; wszTempString_M[0] = '\0'; wszTempString_N[0] = '\0'; wszTempString_P[0] = '\0'; for(argno=1; argnoSaveData(); if( SUCCEEDED( hr )) { fRet = TRUE; } } if (TRUE == fRet) { wsprintf(wszPrintString,L"SUCCESS:removed vdir=%s\n", wszVDir); wprintf(wszPrintString); } else { wsprintf(wszPrintString,L"FAILED to remove vdir=%s, err=0x%x\n", wszVDir, hr); wprintf(wszPrintString); } break; case TRANS_ADD: if( AddVirtualDir( pIMSAdminBase, wszVDir, wszDir)) { hr = pIMSAdminBase->SaveData(); if( SUCCEEDED( hr )) { fRet = TRUE; } } if (TRUE == fRet) { wsprintf(wszPrintString,L"SUCCESS: %s=%s", wszVDir, wszDir); wprintf(wszPrintString); } else { wsprintf(wszPrintString,L"FAILED to set: %s=%s, err=0x%x", wszVDir, wszDir, hr); wprintf(wszPrintString); } break; default: WCHAR wszRootPath[MAX_PATH]; if (TRUE == GetVdirPhysicalPath(pIMSAdminBase,wszVDir,(WCHAR *) wszRootPath)) { fRet = TRUE; if (_wcsicmp(wszVDir, L"") == 0) { wsprintf(wszPrintString,L"/=%s", wszRootPath); } else { wsprintf(wszPrintString,L"%s=%s", wszVDir, wszRootPath); } wprintf(wszPrintString); } else { wprintf(L"FAILED to get root path"); } break; } if (pIMSAdminBase) { pIMSAdminBase->Release(); pIMSAdminBase = NULL; } CoUninitialize(); return fRet; } BOOL GetVdirPhysicalPath(IMSAdminBase *pIMSAdminBase,WCHAR * wszVDir,WCHAR *wszStringPathToFill) { HRESULT hr; BOOL fRet = FALSE; METADATA_HANDLE hMetabase = NULL; // handle to metabase METADATA_RECORD mr; WCHAR szTmpData[MAX_PATH]; DWORD dwMDRequiredDataLen; // open key to ROOT on website #1 (default) hr = pIMSAdminBase->OpenKey(METADATA_MASTER_ROOT_HANDLE, L"/LM/W3SVC/1", METADATA_PERMISSION_READ, REASONABLE_TIMEOUT, &hMetabase); if( FAILED( hr )) { return FALSE; } // Get the physical path for the WWWROOT mr.dwMDIdentifier = MD_VR_PATH; mr.dwMDAttributes = 0; mr.dwMDUserType = IIS_MD_UT_FILE; mr.dwMDDataType = STRING_METADATA; mr.dwMDDataLen = sizeof( szTmpData ); mr.pbMDData = reinterpret_cast(szTmpData); // if nothing specified get the root. if (_wcsicmp(wszVDir, L"") == 0) { WCHAR wszTempDir[MAX_PATH]; wsprintf(wszTempDir,L"/ROOT/%s", wszVDir); hr = pIMSAdminBase->GetData( hMetabase, wszTempDir, &mr, &dwMDRequiredDataLen ); } else { hr = pIMSAdminBase->GetData( hMetabase, L"/ROOT", &mr, &dwMDRequiredDataLen ); } pIMSAdminBase->CloseKey( hMetabase ); if( SUCCEEDED( hr )) { wcscpy(wszStringPathToFill,szTmpData); fRet = TRUE; } pIMSAdminBase->CloseKey( hMetabase ); return fRet; } BOOL AddVirtualDir(IMSAdminBase *pIMSAdminBase,WCHAR * wszVDir,WCHAR * wszDir) { HRESULT hr; BOOL fRet = FALSE; METADATA_HANDLE hMetabase = NULL; // handle to metabase WCHAR wszTempPath[MAX_PATH]; DWORD dwMDRequiredDataLen = 0; DWORD dwAccessPerm = 0; METADATA_RECORD mr; // Attempt to open the virtual dir set on Web server #1 (default server) hr = pIMSAdminBase->OpenKey( METADATA_MASTER_ROOT_HANDLE, L"/LM/W3SVC/1/ROOT", METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE, REASONABLE_TIMEOUT, &hMetabase ); // Create the key if it does not exist. if( FAILED( hr )) { return FALSE; } fRet = TRUE; mr.dwMDIdentifier = MD_VR_PATH; mr.dwMDAttributes = 0; mr.dwMDUserType = IIS_MD_UT_FILE; mr.dwMDDataType = STRING_METADATA; mr.dwMDDataLen = sizeof( wszTempPath ); mr.pbMDData = reinterpret_cast(wszTempPath); // see if MD_VR_PATH exists. hr = pIMSAdminBase->GetData( hMetabase, wszVDir, &mr, &dwMDRequiredDataLen ); if( FAILED( hr )) { fRet = FALSE; if( hr == MD_ERROR_DATA_NOT_FOUND || HRESULT_CODE(hr) == ERROR_PATH_NOT_FOUND ) { // Write both the key and the values if GetData() failed with any of the two errors. pIMSAdminBase->AddKey( hMetabase, wszVDir ); mr.dwMDIdentifier = MD_VR_PATH; mr.dwMDAttributes = METADATA_INHERIT; mr.dwMDUserType = IIS_MD_UT_FILE; mr.dwMDDataType = STRING_METADATA; mr.dwMDDataLen = (wcslen(wszDir) + 1) * sizeof(WCHAR); mr.pbMDData = reinterpret_cast(wszDir); // Write MD_VR_PATH value hr = pIMSAdminBase->SetData( hMetabase, wszVDir, &mr ); fRet = SUCCEEDED( hr ); // Set the default authentication method if( fRet ) { DWORD dwAuthorization = MD_AUTH_NT; // NTLM only. mr.dwMDIdentifier = MD_AUTHORIZATION; mr.dwMDAttributes = METADATA_INHERIT; // need to inherit so that all subdirs are also protected. mr.dwMDUserType = IIS_MD_UT_FILE; mr.dwMDDataType = DWORD_METADATA; mr.dwMDDataLen = sizeof(DWORD); mr.pbMDData = reinterpret_cast(&dwAuthorization); // Write MD_AUTHORIZATION value hr = pIMSAdminBase->SetData( hMetabase, wszVDir, &mr ); fRet = SUCCEEDED( hr ); } } } // In the following, do the stuff that we always want to do to the virtual dir, regardless of Admin's setting. if( fRet ) { dwAccessPerm = MD_ACCESS_READ | MD_ACCESS_SCRIPT; mr.dwMDIdentifier = MD_ACCESS_PERM; mr.dwMDAttributes = METADATA_INHERIT; // Make it inheritable so all subdirectories will have the same rights. mr.dwMDUserType = IIS_MD_UT_FILE; mr.dwMDDataType = DWORD_METADATA; mr.dwMDDataLen = sizeof(DWORD); mr.pbMDData = reinterpret_cast(&dwAccessPerm); // Write MD_ACCESS_PERM value hr = pIMSAdminBase->SetData( hMetabase, wszVDir, &mr ); fRet = SUCCEEDED( hr ); } if( fRet ) { PWCHAR szDefLoadFile = L"Default.htm,Default.asp"; mr.dwMDIdentifier = MD_DEFAULT_LOAD_FILE; mr.dwMDAttributes = 0; // no need for inheritence mr.dwMDUserType = IIS_MD_UT_FILE; mr.dwMDDataType = STRING_METADATA; mr.dwMDDataLen = (wcslen(szDefLoadFile) + 1) * sizeof(WCHAR); mr.pbMDData = reinterpret_cast(szDefLoadFile); // Write MD_DEFAULT_LOAD_FILE value hr = pIMSAdminBase->SetData( hMetabase, wszVDir, &mr ); fRet = SUCCEEDED( hr ); } if( fRet ) { PWCHAR wszKeyType = IIS_CLASS_WEB_VDIR_W; mr.dwMDIdentifier = MD_KEY_TYPE; mr.dwMDAttributes = 0; // no need for inheritence mr.dwMDUserType = IIS_MD_UT_SERVER; mr.dwMDDataType = STRING_METADATA; mr.dwMDDataLen = (wcslen(wszKeyType) + 1) * sizeof(WCHAR); mr.pbMDData = reinterpret_cast(wszKeyType); // Write MD_DEFAULT_LOAD_FILE value hr = pIMSAdminBase->SetData( hMetabase, wszVDir, &mr ); fRet = SUCCEEDED( hr ); } pIMSAdminBase->CloseKey( hMetabase ); return fRet; } BOOL RemoveVirtualDir(IMSAdminBase *pIMSAdminBase,WCHAR * wszVDir) { METADATA_HANDLE hMetabase = NULL; // handle to metabase HRESULT hr; // Attempt to open the virtual dir set on Web server #1 (default server) hr = pIMSAdminBase->OpenKey( METADATA_MASTER_ROOT_HANDLE, L"/LM/W3SVC/1/ROOT", METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE, REASONABLE_TIMEOUT, &hMetabase ); if( FAILED( hr )) { return FALSE; } // We don't check the return value since the key may already // not exist and we could get an error for that reason. pIMSAdminBase->DeleteKey( hMetabase, wszVDir ); pIMSAdminBase->CloseKey( hMetabase ); return TRUE; } HRESULT LoadAllData(IMSAdminBase * pmb, METADATA_HANDLE hMetabase, WCHAR *subdir, BYTE **buf, DWORD *size, DWORD *count) { DWORD dataSet; DWORD neededSize; HRESULT hr; // // Try to get the property names. // hr = pmb->GetAllData(hMetabase, subdir, METADATA_NO_ATTRIBUTES, ALL_METADATA, ALL_METADATA, count, &dataSet, *size, *buf, &neededSize); if (!SUCCEEDED(hr)) { DWORD code = ERROR_INSUFFICIENT_BUFFER; if (hr == RETURNCODETOHRESULT(ERROR_INSUFFICIENT_BUFFER)) { delete *buf; *buf = 0; *size = neededSize; *buf = new BYTE[neededSize]; hr = pmb->GetAllData(hMetabase, subdir, METADATA_NO_ATTRIBUTES, ALL_METADATA, ALL_METADATA, count, &dataSet, *size, *buf, &neededSize); } } return hr; } const DWORD getAllBufSize = 4096*2; HRESULT OpenMetabaseAndGetAllData(void) { HRESULT hr = E_FAIL; IMSAdminBase *pIMSAdminBase = NULL; // Metabase interface pointer WCHAR wszPrintString[MAX_PATH + MAX_PATH]; METADATA_HANDLE hMetabase = NULL; // handle to metabase DWORD bufSize = getAllBufSize; BYTE *buf = new BYTE[bufSize]; DWORD count=0; DWORD linesize =0; BYTE *pBuf1=NULL; BYTE *pBuf2=NULL; if( FAILED (CoInitializeEx( NULL, COINIT_MULTITHREADED )) || FAILED (::CoCreateInstance(CLSID_MSAdminBase, NULL, CLSCTX_ALL, IID_IMSAdminBase, (void **)&pIMSAdminBase))) { wprintf(L"CoCreateInstance. FAILED. code=0x%x\n",hr); return hr; } // Attempt to open the virtual dir set on Web server #1 (default server) hr = pIMSAdminBase->OpenKey( METADATA_MASTER_ROOT_HANDLE, L"/Schema/Properties", METADATA_PERMISSION_READ, REASONABLE_TIMEOUT, &hMetabase ); if( FAILED( hr )) { wprintf(L"pIMSAdminBase->OpenKey. FAILED. code=0x%x\n",hr); goto OpenMetabaseAndGetAllData_Exit; } hr = LoadAllData(pIMSAdminBase, hMetabase, L"Names", &buf, &bufSize, &count); if( FAILED( hr )) { wprintf(L"LoadAllData: FAILED. code=0x%x\n",hr); goto OpenMetabaseAndGetAllData_Exit; } wprintf(L"LoadAllData: Succeeded. bufSize=0x%x, count=0x%x, buf=%p, end of buf=%p\n",bufSize,count,buf,buf+bufSize); wprintf(L"Here is the last 1000 bytes, that the client received.\n"); linesize = 0; pBuf1 = buf+bufSize - 1000; for (int i=0;pBuf1= 16) { linesize=0; wprintf(L"\n"); } } wprintf(L"\n"); hr = S_OK; OpenMetabaseAndGetAllData_Exit: if (pIMSAdminBase) { pIMSAdminBase->Release(); pIMSAdminBase = NULL; } CoUninitialize(); return hr; } HRESULT DelVirtualServer(UINT iServerNum) { HRESULT hr = E_FAIL; return hr; } // iServerNum the virtual server number // iServerPort the virtual server port (port 80 is the default site's port,so you can't use this and you can't use one that is already in use) // wszDir the physical directory where the default site is located HRESULT AddVirtualServer(UINT iServerNum, UINT iServerPort, WCHAR * wszDefaultVDirDir) { HRESULT hr = E_FAIL; IMSAdminBase *pIMSAdminBase = NULL; // Metabase interface pointer METADATA_HANDLE hMetabase = NULL; // handle to metabase METADATA_RECORD mr; WCHAR wszMetabasePath[_MAX_PATH]; WCHAR wszMetabasePathRoot[10]; WCHAR wszData[_MAX_PATH]; DWORD dwData = 0; METADATA_HANDLE hKeyBase = METADATA_MASTER_ROOT_HANDLE; if( FAILED (CoInitializeEx( NULL, COINIT_MULTITHREADED )) || FAILED (::CoCreateInstance(CLSID_MSAdminBase, NULL, CLSCTX_ALL, IID_IMSAdminBase, (void **)&pIMSAdminBase))) { wprintf(L"CoCreateInstance. FAILED. code=0x%x\n",hr); return hr; } // Create the new node wsprintf(wszMetabasePath,L"LM/W3SVC/%i",iServerNum); // try to open the specified metabase node, it might already exist hr = pIMSAdminBase->OpenKey(hKeyBase, wszMetabasePath, METADATA_PERMISSION_READ, REASONABLE_TIMEOUT, &hMetabase); if (hr == RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND)) { hr = pIMSAdminBase->CloseKey(hMetabase); // open the metabase root handle hr = pIMSAdminBase->OpenKey(hKeyBase, L"", METADATA_PERMISSION_WRITE | METADATA_PERMISSION_READ, REASONABLE_TIMEOUT,&hMetabase); if( FAILED( hr )) { // if we can't even open the root handle, then we're pretty hosed wprintf(L"1OpenKey. FAILED. code=0x%x\n",hr); goto AddVirtualServer_Exit; } // and add our node hr = pIMSAdminBase->AddKey(hMetabase, wszMetabasePath); if (FAILED(hr)) { wprintf(L"AddKey. FAILED. code=0x%x\n",hr); pIMSAdminBase->CloseKey(hMetabase); goto AddVirtualServer_Exit; } else { hr = pIMSAdminBase->CloseKey(hMetabase); if (FAILED(hr)) { goto AddVirtualServer_Exit; } else { // open it again hr = pIMSAdminBase->OpenKey(hKeyBase, wszMetabasePath, METADATA_PERMISSION_WRITE | METADATA_PERMISSION_READ, REASONABLE_TIMEOUT, &hMetabase); if (FAILED(hr)) { wprintf(L"2OpenKey. FAILED. code=0x%x\n",hr); pIMSAdminBase->CloseKey(hMetabase); goto AddVirtualServer_Exit; } } } } else { if (FAILED(hr)) { wprintf(L"3OpenKey. FAILED. code=0x%x\n",hr); goto AddVirtualServer_Exit; } else { // we were able to open the path, so it must already exist! hr = ERROR_ALREADY_EXISTS; pIMSAdminBase->CloseKey(hMetabase); goto AddVirtualServer_Exit; } } // We should have a brand new Key now... // // Create stuff in the node of this path! // // // /LM/W3SVC/1/KeyType // memset( (PVOID)wszData, 0, sizeof(wszData)); wcscpy(wszData,IIS_CLASS_WEB_SERVER_W); mr.dwMDIdentifier = MD_KEY_TYPE; mr.dwMDAttributes = 0; // no need for inheritence mr.dwMDUserType = IIS_MD_UT_SERVER; mr.dwMDDataType = STRING_METADATA; mr.dwMDDataLen = (wcslen(wszData) + 1) * sizeof(WCHAR); mr.pbMDData = reinterpret_cast(wszData); hr = pIMSAdminBase->SetData( hMetabase, L"", &mr ); if (FAILED(hr)) { wprintf(L"SetData[MD_KEY_TYPE]. FAILED. code=0x%x\n",hr); } // // /W3SVC/1/ServerBindings // memset( (PVOID)wszData, 0, sizeof(wszData)); wsprintf(wszData, L":%d:", iServerPort); mr.dwMDIdentifier = MD_SERVER_BINDINGS; mr.dwMDAttributes = METADATA_INHERIT; mr.dwMDUserType = IIS_MD_UT_SERVER; mr.dwMDDataType = MULTISZ_METADATA; mr.dwMDDataLen = GetMultiStrSize(wszData) * sizeof(WCHAR); mr.pbMDData = reinterpret_cast(wszData); hr = pIMSAdminBase->SetData( hMetabase, L"", &mr ); if (FAILED(hr)) { wprintf(L"SetData[MD_SERVER_BINDINGS]. FAILED. code=0x%x\n",hr); } // // /W3SVC/1/SecureBindings // memset( (PVOID)wszData, 0, sizeof(wszData)); wcscpy(wszData, L" "); mr.dwMDIdentifier = MD_SECURE_BINDINGS; mr.dwMDAttributes = METADATA_INHERIT; mr.dwMDUserType = IIS_MD_UT_SERVER; mr.dwMDDataType = MULTISZ_METADATA; mr.dwMDDataLen = GetMultiStrSize(wszData) * sizeof(WCHAR); mr.pbMDData = reinterpret_cast(wszData); hr = pIMSAdminBase->SetData( hMetabase, L"", &mr ); if (FAILED(hr)) { wprintf(L"SetData[MD_SECURE_BINDINGS]. FAILED. code=0x%x\n",hr); } // // Create stuff in the /Root node of this path! // wcscpy(wszMetabasePathRoot, L"/Root"); wcscpy(wszData,IIS_CLASS_WEB_VDIR_W); // W3SVC/3/Root/KeyType mr.dwMDIdentifier = MD_KEY_TYPE; mr.dwMDAttributes = 0; // no need for inheritence mr.dwMDUserType = IIS_MD_UT_SERVER; mr.dwMDDataType = STRING_METADATA; mr.dwMDDataLen = (wcslen(wszData) + 1) * sizeof(WCHAR); mr.pbMDData = reinterpret_cast(wszData); hr = pIMSAdminBase->SetData( hMetabase, wszMetabasePathRoot, &mr ); if (FAILED(hr)) { wprintf(L"SetData[MD_KEY_TYPE]. FAILED. code=0x%x\n",hr); } // W3SVC/3/Root/VrPath mr.dwMDIdentifier = MD_VR_PATH; mr.dwMDAttributes = METADATA_INHERIT; mr.dwMDUserType = IIS_MD_UT_FILE; mr.dwMDDataType = STRING_METADATA; mr.dwMDDataLen = (wcslen(wszDefaultVDirDir) + 1) * sizeof(WCHAR); mr.pbMDData = reinterpret_cast(wszDefaultVDirDir); hr = pIMSAdminBase->SetData( hMetabase, wszMetabasePathRoot, &mr ); if (FAILED(hr)) { wprintf(L"SetData[MD_VR_PATH]. FAILED. code=0x%x\n",hr); } // W3SVC/3/Root/Authorizaton dwData = MD_AUTH_ANONYMOUS | MD_AUTH_NT; mr.dwMDIdentifier = MD_AUTHORIZATION; mr.dwMDAttributes = METADATA_INHERIT; mr.dwMDUserType = IIS_MD_UT_FILE; mr.dwMDDataType = DWORD_METADATA; mr.dwMDDataLen = sizeof(DWORD); mr.pbMDData = reinterpret_cast(&dwData); hr = pIMSAdminBase->SetData( hMetabase, wszMetabasePathRoot, &mr ); if (FAILED(hr)) { wprintf(L"SetData[MD_AUTHORIZATION]. FAILED. code=0x%x\n",hr); } // W3SVC/3/Root/AccessPerm dwData = MD_ACCESS_SCRIPT | MD_ACCESS_READ; mr.dwMDIdentifier = MD_ACCESS_PERM; mr.dwMDAttributes = METADATA_INHERIT; mr.dwMDUserType = IIS_MD_UT_FILE; mr.dwMDDataType = DWORD_METADATA; mr.dwMDDataLen = sizeof(DWORD); mr.pbMDData = reinterpret_cast(&dwData); hr = pIMSAdminBase->SetData( hMetabase, wszMetabasePathRoot, &mr ); if (FAILED(hr)) { wprintf(L"SetData[MD_ACCESS_PERM]. FAILED. code=0x%x\n",hr); } // W3SVC/3/Root/DirectoryBrowsing dwData = MD_DIRBROW_SHOW_DATE | MD_DIRBROW_SHOW_TIME | MD_DIRBROW_SHOW_SIZE | MD_DIRBROW_SHOW_EXTENSION | MD_DIRBROW_LONG_DATE | MD_DIRBROW_LOADDEFAULT; // | MD_DIRBROW_ENABLED; mr.dwMDIdentifier = MD_DIRECTORY_BROWSING; mr.dwMDAttributes = METADATA_INHERIT; mr.dwMDUserType = IIS_MD_UT_FILE; mr.dwMDDataType = DWORD_METADATA; mr.dwMDDataLen = sizeof(DWORD); mr.pbMDData = reinterpret_cast(&dwData); hr = pIMSAdminBase->SetData( hMetabase, wszMetabasePathRoot, &mr ); if (FAILED(hr)) { wprintf(L"SetData[MD_DIRECTORY_BROWSING]. FAILED. code=0x%x\n",hr); } /* dwData = 0; mr.dwMDIdentifier = MD_SERVER_AUTOSTART; mr.dwMDAttributes = METADATA_INHERIT; mr.dwMDUserType = IIS_MD_UT_FILE; mr.dwMDDataType = DWORD_METADATA; mr.dwMDDataLen = sizeof(DWORD); mr.pbMDData = reinterpret_cast(&dwData); hr = pIMSAdminBase->SetData( hMetabase, wszMetabasePathRoot, &mr ); if (FAILED(hr)) { wprintf(L"SetData[MD_SERVER_AUTOSTART]. FAILED. code=0x%x\n",hr); } */ pIMSAdminBase->CloseKey(hMetabase); AddVirtualServer_Exit: if (pIMSAdminBase) { pIMSAdminBase->Release(); pIMSAdminBase = NULL; } CoUninitialize(); return hr; } // returns 0 if not found // returns 1 if StrToFind is found but StrToFind2 is not found // returns 2 if StrToFind is found and StrToFind2 is found INT FindWstrInMultiStrSpecial(LPWSTR pMultiStr, LPWSTR StrToFind, LPWSTR StrToFind2) { INT iReturn = 0; LPWSTR pTempMultiStr = pMultiStr; DWORD dwCharCount = 0; while (1) { if (pTempMultiStr) { // The 1st entry should be // the type. so it will be either 1 or a number. // so let's skip till the next null. // then increment until we hit another null. while (*pTempMultiStr) { pTempMultiStr++; dwCharCount++; } // check for the ending \0\0 if ( *(pTempMultiStr+1) == NULL) { break; } else { pTempMultiStr++; dwCharCount++; } // compare this value to the imput value if (0 == _wcsicmp((const wchar_t *) pTempMultiStr,StrToFind)) { iReturn = 1; } // so let's skip till the next null. // then increment until we hit another null. while (*pTempMultiStr) { pTempMultiStr++; dwCharCount++; } // check for the ending \0\0 if ( *(pTempMultiStr+1) == NULL) { break; } else { pTempMultiStr++; dwCharCount++; } // check for an exact match. if (0 != iReturn) { // compare this value to the imput value if (StrToFind2 != NULL) { if (0 == _wcsicmp((const wchar_t *) pTempMultiStr,StrToFind2)) { iReturn = 2; break; } } break; } // so let's skip till the next null. // then increment until we hit another null. while (*pTempMultiStr) { pTempMultiStr++; dwCharCount++; } // check for the ending \0\0 if ( *(pTempMultiStr+1) == NULL) { break; } else { pTempMultiStr++; dwCharCount++; } // Check if we screwed up somehow and are in an infinite loop. // could happen if we don't find an ending \0\0 if (dwCharCount > 32000) { break; } } } return iReturn; } BOOL FindWstrInMultiStr(LPWSTR pMultiStr, LPWSTR StrToFind) { BOOL bFound = FALSE; LPWSTR pTempMultiStr = pMultiStr; DWORD dwCharCount = 0; while (1) { if (pTempMultiStr) { // compare this value to the imput value if (0 == _wcsicmp((const wchar_t *) pTempMultiStr,StrToFind)) { bFound = TRUE; break; } // then increment until we hit another null. while (*pTempMultiStr) { pTempMultiStr++; dwCharCount++; } // check for the ending \0\0 if ( *(pTempMultiStr+1) == NULL) { break; } else { pTempMultiStr++; dwCharCount++; } // Check if we screwed up somehow and are in an infinite loop. // could happen if we don't find an ending \0\0 if (dwCharCount > 32000) { break; } } } return bFound; } BOOL RemoveWstrInMultiStr(LPWSTR pMultiStr, LPWSTR StrToFind) { BOOL bFound = FALSE; LPWSTR pTempMultiStr = pMultiStr; DWORD dwCharCount = 0; while (1) { if (pTempMultiStr) { // compare this value to the imput value if (0 == _wcsicmp((const wchar_t *) pTempMultiStr,StrToFind)) { LPWSTR pLastDoubleNull = NULL; LPWSTR pBeginPath = pTempMultiStr; bFound = TRUE; // then increment until we hit another null. while (*pTempMultiStr) { pTempMultiStr++; } pTempMultiStr++; // Find the last double null. pLastDoubleNull = pTempMultiStr; if (*pLastDoubleNull) { while (1) { if (NULL == *pLastDoubleNull && NULL == *(pLastDoubleNull+1)) { break; } pLastDoubleNull++; } pLastDoubleNull++; } // check if we are the last entry. if (pLastDoubleNull == pTempMultiStr) { // set everything to nulls memset(pBeginPath,0,(pLastDoubleNull-pBeginPath) * sizeof(WCHAR)); } else { // move everything behind it to where we are. memmove(pBeginPath,pTempMultiStr, (pLastDoubleNull - pTempMultiStr) * sizeof(WCHAR)); // and set everything behind that to nulls memset(pBeginPath + (pLastDoubleNull - pTempMultiStr),0,(pTempMultiStr-pBeginPath) * sizeof(WCHAR)); } break; } // then increment until we hit another null. while (*pTempMultiStr) { pTempMultiStr++; dwCharCount++; } // check for the ending \0\0 if ( *(pTempMultiStr+1) == NULL) { break; } else { pTempMultiStr++; dwCharCount++; } // Check if we screwed up somehow and are in an infinite loop. // could happen if we don't find an ending \0\0 if (dwCharCount > 32000) { break; } } } return bFound; } BOOL IsAllowAllByDefault(LPWSTR pMultiStr) { BOOL bFound = FALSE; if (pMultiStr) { if (0 == _wcsicmp((const wchar_t *) pMultiStr,L"1")) { bFound = TRUE; } } return bFound; } // returns TRUE if we need to write to metabase // returns bAddToList = true if we need to add to the list // returns bAddToList = false if we need to remove from the list // returns FALSE if we don't need to write to metabase // BOOL IsAddRemoveOrDoNothing(LPWSTR pMultiStr,LPWSTR wszFilePath,BOOL bEnableThisBinary,BOOL * bAddToList) { BOOL bReturn = FALSE; BOOL bAllowAllByDefault = FALSE; BOOL bFound = FALSE; if (!bAddToList || !pMultiStr || !wszFilePath) { return FALSE; } // set flag to see if we are in deny all by default // or if we are in enable all by default.. if (TRUE == IsAllowAllByDefault((WCHAR *) pMultiStr)) { bAllowAllByDefault = TRUE; } // Loop thru the data to see if we are already present... // // data looks like this: // 0 or 1\0 // fileentry1\0 // filenetry2\0 // last fileentry\0\0 // bFound = FindWstrInMultiStr((WCHAR *) pMultiStr,wszFilePath); // Make some decisions if (bEnableThisBinary) { if (bFound) { if (bAllowAllByDefault) { // trying to enable // the list is allow by default // it's in the list, so that means it's currently not enabled.. // We need to remove it from the list! *bAddToList = FALSE; bReturn = TRUE; goto IsAddRemoveOrDoNothing_Exit; } else { // trying to enable // the list is deny by default // it's in the list. so that means it's currently already enabled! // do nothing! get out, things are groovy. bReturn = FALSE; goto IsAddRemoveOrDoNothing_Exit; } } else { if (bAllowAllByDefault) { // trying to enable // the list is allow by default // it's not in the list // so that means it's currently already enabled! // do nothing! get out. things are groovy. bReturn = FALSE; goto IsAddRemoveOrDoNothing_Exit; } else { // trying to enable // the list is deny by default // it's not in the list // so that means we need to add it to the list *bAddToList = TRUE; bReturn = TRUE; goto IsAddRemoveOrDoNothing_Exit; } } } else { if (bFound) { if (bAllowAllByDefault) { // trying to disable // the list is allow by default // it's in the list, so that means it's currently disabled already // do nothing! get out. things are groovy. bReturn = FALSE; goto IsAddRemoveOrDoNothing_Exit; } else { // trying to disable // the list is deny by default // it's in the list. so that means currently it is enabled, so // we want to make sure to remove it from the list // so that it will be denied. *bAddToList = FALSE; bReturn = TRUE; goto IsAddRemoveOrDoNothing_Exit; } } else { if (bAllowAllByDefault) { // trying to disable // the list is allow by default // it's not in the list // so that means it's currently being allowed // we need to add it to the list so that it will be denied *bAddToList = TRUE; bReturn = TRUE; goto IsAddRemoveOrDoNothing_Exit; } else { // trying to disable // the list is deny by default // it's in the list, so that means it's currently disabled already // do nothing! get out. things are groovy. bReturn = FALSE; goto IsAddRemoveOrDoNothing_Exit; } } } IsAddRemoveOrDoNothing_Exit: return bReturn; } // wszFilePath = is the fully qualified path to the binary which will be enabled or disabled // bBinaryIsISAPI = is the flag which determines which metabase setting to set // when set to TRUE it will perform action on the ISAPI restriction list // when set to FALSE it will perform action on the CGI restriction list // bEnableThisBinary = is the flag which determines weather the binary should be allowed to run or not. // when set to TRUE it will ensure that the specified binary will be allowed to run // when set to FALSE it will ensure that the specified binary will not be allowed to run // will figure out what is the right thing to do from what current metabase settings is HRESULT AddRemoveIISRestrictionListEntry(WCHAR * wszFilePathInput,BOOL bBinaryIsISAPI,BOOL bEnableThisBinary) { HRESULT hr = E_FAIL; IMSAdminBase *pIMSAdminBase = NULL; // Metabase interface pointer METADATA_HANDLE hMetabase = NULL; // handle to metabase METADATA_RECORD mr; BYTE * pbDataOld = NULL; BYTE * pbDataNew = NULL; DWORD dwMDRequiredDataLen = 0; DWORD dwNewEntryLength = 0; DWORD dwNewTotalLength = 0; DWORD dwOldByteLength = 0; BOOL bAddToList = FALSE; WCHAR * wszFilePath = NULL; // Convert any env vars to hard coded paths LPWSTR pch = wcschr( (LPWSTR) wszFilePathInput, L'%'); if (pch) { // determine the length of the expanded string DWORD len = ::ExpandEnvironmentStrings(wszFilePathInput, 0, 0); if (!len) { return hr; } wszFilePath = (WCHAR *) GlobalAlloc(GPTR, (len + 1) * sizeof(WCHAR)); DWORD len1 = ExpandEnvironmentStrings((LPWSTR) wszFilePathInput,const_cast(wszFilePath),len); if (len1 != len) { if (wszFilePath) { GlobalFree(wszFilePath);wszFilePath = NULL; } return hr; } } else { wszFilePath = wszFilePathInput; } hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); if (hr == RPC_E_CHANGED_MODE) { // fine. try again hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); } if (FAILED(hr)) { return hr; } hr = CoCreateInstance(CLSID_MSAdminBase,NULL,CLSCTX_ALL,IID_IMSAdminBase,(void **)&pIMSAdminBase); if (FAILED(hr)) { goto AddRemoveIISRestrictionListEntry_Exit; } // open the specified metabase node hr = pIMSAdminBase->OpenKey(METADATA_MASTER_ROOT_HANDLE, L"LM/W3SVC", METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE, REASONABLE_TIMEOUT, &hMetabase); if (FAILED(hr)) { hMetabase = NULL; goto AddRemoveIISRestrictionListEntry_Exit; } if (bBinaryIsISAPI) { mr.dwMDIdentifier = MD_ISAPI_RESTRICTION_LIST; } else { mr.dwMDIdentifier = MD_CGI_RESTRICTION_LIST; } mr.dwMDAttributes = 0; // no need for inheritence mr.dwMDUserType = IIS_MD_UT_SERVER; mr.dwMDDataType = MULTISZ_METADATA; mr.dwMDDataLen = 0; mr.pbMDData = reinterpret_cast(pbDataOld); // first we need to figure out how much space we need hr = pIMSAdminBase->GetData(hMetabase, L"", &mr, &dwMDRequiredDataLen); if(FAILED(hr)) { // if there isn't a value there that we need to update // then create one if( hr == MD_ERROR_DATA_NOT_FOUND || HRESULT_CODE(hr) == ERROR_PATH_NOT_FOUND ) { WCHAR wszDefaultData[4]; // set to "allow all by default" memset( (PVOID)wszDefaultData, 0, sizeof(wszDefaultData)); wcscpy(wszDefaultData, L"1"); if (bBinaryIsISAPI) { mr.dwMDIdentifier = MD_ISAPI_RESTRICTION_LIST; } else { mr.dwMDIdentifier = MD_CGI_RESTRICTION_LIST; } mr.dwMDAttributes = 0; // no need for inheritence mr.dwMDUserType = IIS_MD_UT_SERVER; mr.dwMDDataType = MULTISZ_METADATA; mr.dwMDDataLen = GetMultiStrSize(wszDefaultData) * sizeof(WCHAR); mr.pbMDData = reinterpret_cast(wszDefaultData); // Write value hr = pIMSAdminBase->SetData(hMetabase, L"", &mr); // find out how much space we need. mr.dwMDDataLen = 0; mr.pbMDData = reinterpret_cast(pbDataOld); hr = pIMSAdminBase->GetData(hMetabase, L"", &mr, &dwMDRequiredDataLen); if(FAILED(hr)) { goto AddRemoveIISRestrictionListEntry_Exit; } } else { goto AddRemoveIISRestrictionListEntry_Exit; } } pbDataOld = (BYTE *) GlobalAlloc(GPTR, dwMDRequiredDataLen); if (!pbDataOld) { hr = E_OUTOFMEMORY; goto AddRemoveIISRestrictionListEntry_Exit; } // do the real call to get the data from the metabase mr.dwMDDataLen = dwMDRequiredDataLen; mr.pbMDData = reinterpret_cast(pbDataOld); hr = pIMSAdminBase->GetData(hMetabase, L"", &mr, &dwMDRequiredDataLen); if (FAILED(hr)) { goto AddRemoveIISRestrictionListEntry_Exit; } if (FALSE == IsAddRemoveOrDoNothing((WCHAR *) pbDataOld, wszFilePath, bEnableThisBinary, &bAddToList)) { hr = S_OK; goto AddRemoveIISRestrictionListEntry_Exit; } if (bAddToList) { // Recalc the amount of space we'll need to add this entry into the list dwOldByteLength = GetMultiStrSize( (WCHAR*) pbDataOld) * sizeof(WCHAR); dwNewEntryLength = wcslen(wszFilePath) * sizeof(WCHAR); dwNewTotalLength = dwOldByteLength + dwNewEntryLength + 2; // Alloc enough space for the old data and the new data. // Don't use realloc here, because for somereason it would fail in // certain test runs. pbDataNew = (BYTE *) GlobalAlloc(GPTR, dwNewTotalLength); if (!pbDataNew) { hr = E_OUTOFMEMORY; goto AddRemoveIISRestrictionListEntry_Exit; } // copy the old data... memcpy(pbDataNew,pbDataOld,dwOldByteLength); // append on the new data memcpy((pbDataNew + dwOldByteLength) - 2,wszFilePath,dwNewEntryLength); memset((pbDataNew + dwOldByteLength + dwNewEntryLength) - 2,0,4); // free the old data if (pbDataOld) { GlobalFree(pbDataOld); pbDataOld = NULL; } } else { dwOldByteLength = GetMultiStrSize( (WCHAR*) pbDataOld) * sizeof(WCHAR); // Don't use realloc here, because for somereason it would fail in // certain test runs. pbDataNew = (BYTE *) GlobalAlloc(GPTR, dwOldByteLength); if (!pbDataNew) { hr = E_OUTOFMEMORY; goto AddRemoveIISRestrictionListEntry_Exit; } // copy the old data... memcpy(pbDataNew,pbDataOld,dwOldByteLength); // free the old data if (pbDataOld) { GlobalFree(pbDataOld); pbDataOld = NULL; } // remove an entry from the list if (FALSE == RemoveWstrInMultiStr((WCHAR *) pbDataNew,wszFilePath)) { // we were not able to find the value in the string hr = S_OK; goto AddRemoveIISRestrictionListEntry_Exit; } else { // keep removing till it's all gone BOOL bRet = TRUE; do { bRet = RemoveWstrInMultiStr((WCHAR *) pbDataNew,wszFilePath); } while (bRet); } // other wise pbDataOld is updated with the new data // proceed to write the new data out } // Write the new data out if (bBinaryIsISAPI) { mr.dwMDIdentifier = MD_ISAPI_RESTRICTION_LIST; } else { mr.dwMDIdentifier = MD_CGI_RESTRICTION_LIST; } mr.dwMDAttributes = 0; // no need for inheritence mr.dwMDUserType = IIS_MD_UT_SERVER; mr.dwMDDataType = MULTISZ_METADATA; mr.dwMDDataLen = GetMultiStrSize((WCHAR*)pbDataNew) * sizeof(WCHAR); mr.pbMDData = reinterpret_cast (pbDataNew); //DumpWstrInMultiStr((WCHAR *) pbDataNew); hr = pIMSAdminBase->SetData(hMetabase, L"", &mr); AddRemoveIISRestrictionListEntry_Exit: if (FAILED(hr)) { wprintf(L"Failed to %s '%s' to/from %s\r\n", bEnableThisBinary ? L"Enable" : L"Disable", wszFilePath, bBinaryIsISAPI ? L"MD_ISAPI_RESTRICTION_LIST" : L"MD_CGI_RESTRICTION_LIST" ); } else { wprintf(L"Succeeded to %s '%s' to/from %s\r\n", bEnableThisBinary ? L"Enable" : L"Disable", wszFilePath, bBinaryIsISAPI ? L"MD_ISAPI_RESTRICTION_LIST" : L"MD_CGI_RESTRICTION_LIST" ); } if (hMetabase) { pIMSAdminBase->CloseKey(hMetabase); hMetabase = NULL; } if (pIMSAdminBase) { pIMSAdminBase->Release(); pIMSAdminBase = NULL; } if (pbDataOld) { GlobalFree(pbDataOld); pbDataOld = NULL; } if (pbDataNew) { GlobalFree(pbDataNew); pbDataNew = NULL; } CoUninitialize(); return hr; } BOOL DeleteEntryFromMultiSZ3Pair( LPCWSTR ptstrMultiSZ, LPCWSTR ptstrKey ) /*++ Routine Description: Search for the specified key in MultiSZ key-value 3 string pairs looks like: 1,c:\mydir\myfilename.dll,mydescription 1,c:\mydir\myfilename.dll,mydescription 1,c:\mydir\myfilename.dll,mydescription Arguments: ptstrMultiSZ - Points to the data to be searched ptstrKey - Specifies the key string Return Value: Pointer to the value string corresponding to the specified key string; NULL if the specified key string is not found --*/ { LPWSTR pPointer1 = NULL; LPWSTR pPointer2 = NULL; LPWSTR pPointer3 = NULL; LPWSTR pPointer4 = NULL; LPCWSTR pPointerEnd = NULL; pPointerEnd = GetEndOfMultiSz((LPCWSTR) ptstrMultiSZ); // Advanced past beginning nulls if any. while (*ptstrMultiSZ == NULL) { ptstrMultiSZ++; } // make sure 1st entry is at least a single digit // if not, then let's skip until we find one while (*ptstrMultiSZ != NULL) { if (wcslen(ptstrMultiSZ) < 2) { break; } ptstrMultiSZ += wcslen(ptstrMultiSZ) + 1; } while (*ptstrMultiSZ != NULL) { // Assign pointer to the 1st entry pPointer1 = (LPWSTR) ptstrMultiSZ; // Advance to the first key... ptstrMultiSZ += wcslen(ptstrMultiSZ) + 1; pPointer2 = (LPWSTR) ptstrMultiSZ; if (ptstrMultiSZ && *ptstrMultiSZ) { ptstrMultiSZ += wcslen(ptstrMultiSZ) + 1; pPointer3 = (LPWSTR) ptstrMultiSZ; // // If the current string matches the specified key string, // then return the corresponding value string // if (_wcsicmp(pPointer2, ptstrKey) == 0) { // we found our entry, delete it and get out // Get the beginning of the next entry.. ptstrMultiSZ += wcslen(ptstrMultiSZ) + 1; if (*ptstrMultiSZ != NULL) { ULONG_PTR dwTotalSizeOfDeletion = dwTotalSizeOfDeletion = (ULONG_PTR) ptstrMultiSZ - (ULONG_PTR)pPointer1; // erase this memory memset(pPointer1, 0, dwTotalSizeOfDeletion); // move trailing memory over erased memory (overwritting it) memmove(pPointer1, ptstrMultiSZ, ((ULONG_PTR) pPointerEnd - (ULONG_PTR) ptstrMultiSZ)); // erase stuff behind it. memset((void*) ((ULONG_PTR) pPointerEnd - (ULONG_PTR) dwTotalSizeOfDeletion), 0, dwTotalSizeOfDeletion); } else { *pPointer1 = NULL; *pPointer1++ = NULL; } return TRUE; } // // Otherwise, advance to the next 3 string pair // ptstrMultiSZ += wcslen(ptstrMultiSZ) + 1; } } return FALSE; } // wszFilePath = // wszDescription = HRESULT AddRemoveIISCustomDescriptionEntry(WCHAR * wszFilePathInput,WCHAR * wszDescription,BOOL bCannotBeRemovedByUser,BOOL bAddToList) { HRESULT hr = E_FAIL; IMSAdminBase *pIMSAdminBase = NULL; // Metabase interface pointer METADATA_HANDLE hMetabase = NULL; // handle to metabase METADATA_RECORD mr; BYTE * pbDataOld = NULL; BYTE * pbDataNew = NULL; DWORD dwMDRequiredDataLen = 0; DWORD dwNewEntryLength = 0; DWORD dwNewTotalLength = 0; DWORD dwOldByteLength = 0; WCHAR * wszFilePath = NULL; INT iFound = 0; // Convert any env vars to hard coded paths LPWSTR pch = wcschr( (LPWSTR) wszFilePathInput, L'%'); if (pch) { // determine the length of the expanded string DWORD len = ::ExpandEnvironmentStrings(wszFilePathInput, 0, 0); if (!len) { return hr; } wszFilePath = (WCHAR *) GlobalAlloc(GPTR, (len + 1) * sizeof(WCHAR)); DWORD len1 = ExpandEnvironmentStrings((LPWSTR) wszFilePathInput,const_cast(wszFilePath),len); if (len1 != len) { if (wszFilePath) { GlobalFree(wszFilePath);wszFilePath = NULL; } return hr; } } else { wszFilePath = wszFilePathInput; } hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); if (hr == RPC_E_CHANGED_MODE) { // fine. try again hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); } if (FAILED(hr)) { return hr; } hr = CoCreateInstance(CLSID_MSAdminBase,NULL,CLSCTX_ALL,IID_IMSAdminBase,(void **)&pIMSAdminBase); if (FAILED(hr)) { goto AddRemoveIISCustomDescriptionEntry_Exit; } // open the specified metabase node hr = pIMSAdminBase->OpenKey(METADATA_MASTER_ROOT_HANDLE, L"LM/W3SVC", METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE, REASONABLE_TIMEOUT, &hMetabase); if (FAILED(hr)) { hMetabase = NULL; goto AddRemoveIISCustomDescriptionEntry_Exit; } mr.dwMDIdentifier = MD_RESTRICTION_LIST_CUSTOM_DESC; mr.dwMDAttributes = 0; // no need for inheritence mr.dwMDUserType = IIS_MD_UT_SERVER; mr.dwMDDataType = MULTISZ_METADATA; mr.dwMDDataLen = 0; mr.pbMDData = reinterpret_cast(pbDataOld); // first we need to figure out how much space we need hr = pIMSAdminBase->GetData(hMetabase, L"", &mr, &dwMDRequiredDataLen); if(FAILED(hr)) { // if there isn't a value there that we need to update // then create one if( hr == MD_ERROR_DATA_NOT_FOUND || HRESULT_CODE(hr) == ERROR_PATH_NOT_FOUND ) { if (bAddToList) { // make enough room for the new entry... dwNewTotalLength = 2 * sizeof(WCHAR); // char + 1null dwNewTotalLength = dwNewTotalLength + ((wcslen(wszFilePathInput) + 1) * sizeof(WCHAR)); // string + 1 null dwNewTotalLength = dwNewTotalLength + ((wcslen(wszDescription) + 2) * sizeof(WCHAR)); // string + 1 null and 1 ending null pbDataNew = (BYTE *) GlobalAlloc(GPTR, dwNewTotalLength); if (!pbDataNew) { hr = E_OUTOFMEMORY; goto AddRemoveIISCustomDescriptionEntry_Exit; } // set to empty memset(pbDataNew, 0, dwNewTotalLength); // create the entry if (bCannotBeRemovedByUser) { memcpy(pbDataNew,L"1",sizeof(WCHAR)); } else { memcpy(pbDataNew,L"0",sizeof(WCHAR)); } // append on the new data dwNewEntryLength = ((wcslen(wszFilePathInput) + 1) * sizeof(WCHAR)); memcpy((pbDataNew + (sizeof(WCHAR) * 2)),wszFilePath, dwNewEntryLength); memcpy((pbDataNew + (sizeof(WCHAR) * 2) + dwNewEntryLength),wszDescription,((wcslen(wszDescription) + 1) * sizeof(WCHAR))); memset((pbDataNew + (sizeof(WCHAR) * 2) + dwNewEntryLength + ((wcslen(wszDescription) + 1) * sizeof(WCHAR))),0,2); mr.dwMDIdentifier = MD_RESTRICTION_LIST_CUSTOM_DESC; mr.dwMDAttributes = 0; // no need for inheritence mr.dwMDUserType = IIS_MD_UT_SERVER; mr.dwMDDataType = MULTISZ_METADATA; mr.dwMDDataLen = GetMultiStrSize((WCHAR*) pbDataNew) * sizeof(WCHAR); mr.pbMDData = reinterpret_cast(pbDataNew); // Write value hr = pIMSAdminBase->SetData(hMetabase, L"", &mr); goto AddRemoveIISCustomDescriptionEntry_Exit; } else { // we don't need to do anything else // there are no entries, so there is nothing to remove hr = S_OK; goto AddRemoveIISCustomDescriptionEntry_Exit; } } else { goto AddRemoveIISCustomDescriptionEntry_Exit; } } pbDataOld = (BYTE *) GlobalAlloc(GPTR, dwMDRequiredDataLen); if (!pbDataOld) { hr = E_OUTOFMEMORY; goto AddRemoveIISCustomDescriptionEntry_Exit; } // do the real call to get the data from the metabase mr.dwMDDataLen = dwMDRequiredDataLen; mr.pbMDData = reinterpret_cast(pbDataOld); hr = pIMSAdminBase->GetData(hMetabase, L"", &mr, &dwMDRequiredDataLen); if (FAILED(hr)) { goto AddRemoveIISCustomDescriptionEntry_Exit; } iFound = FindWstrInMultiStrSpecial((WCHAR *) pbDataOld,wszFilePath,NULL); if (0 == iFound) { if (!bAddToList) { // the entry doesn't exist // so we don't have to remove it hr = S_OK; //wprintf(L"found = 0, skip remove!!\r\n"); goto AddRemoveIISCustomDescriptionEntry_Exit; } // otherwise, proceed to add the entry.... } else if (2 == iFound) { if (bAddToList) { // there already is an entry there // so we can exit and don't have to do anything //wprintf(L"found = 2, skip adding!!\r\n"); hr = S_OK; goto AddRemoveIISCustomDescriptionEntry_Exit; } // otherwise, proceed to remove the entry.... } else { // we must have a 1 // which means we found the filename but the description is different... //wprintf(L"%s found only filename!!! pbDataOld=%p\n",wszFilePath,pbDataOld); // proceed to update the entry // Write some code to update the description... } if (bAddToList) { //wprintf(L"doing add!\r\n"); DWORD dwTempLen = 0; // Recalc the amount of space we'll need to add this entry into the list dwOldByteLength = GetMultiStrSize( (WCHAR*) pbDataOld) * sizeof(WCHAR); dwNewEntryLength = ( (sizeof(WCHAR) * 2) + ((wcslen(wszFilePath) + 1) * sizeof(WCHAR)) + ((wcslen(wszDescription) + 1) * sizeof(WCHAR)) ); dwNewTotalLength = dwOldByteLength + dwNewEntryLength + (sizeof(WCHAR)); // string + 1 null and 1 ending null // Alloc enough space for the old data and the new data. // Don't use realloc here, because for somereason it would fail in // certain test runs. pbDataNew = (BYTE *) GlobalAlloc(GPTR, dwNewTotalLength); if (!pbDataNew) { hr = E_OUTOFMEMORY; goto AddRemoveIISCustomDescriptionEntry_Exit; } // set to empty memset(pbDataNew, 0, dwNewTotalLength); // copy the old data... memcpy(pbDataNew,pbDataOld,dwOldByteLength); // append entry #1 on to the new data -- backup over the double nulls dwTempLen = dwOldByteLength - 2; if (bCannotBeRemovedByUser) {memcpy((pbDataNew + dwTempLen),L"1",sizeof(WCHAR));} else {memcpy((pbDataNew + dwTempLen),L"0",sizeof(WCHAR));} memset((pbDataNew + dwTempLen + sizeof(WCHAR)),0,2); dwTempLen = dwTempLen + sizeof(WCHAR) + sizeof(WCHAR); // append entry #2 dwNewEntryLength = ((wcslen(wszFilePath) + 1) * sizeof(WCHAR)); memcpy((pbDataNew + dwTempLen),wszFilePath,dwNewEntryLength); dwTempLen = dwTempLen + dwNewEntryLength; // append entry #3 dwNewEntryLength = ((wcslen(wszDescription) + 1) * sizeof(WCHAR)); memcpy((pbDataNew + dwTempLen),wszDescription,dwNewEntryLength); dwTempLen = dwTempLen + dwNewEntryLength; // make sure it ends with double nulls memset((pbDataNew + dwTempLen),0,4); // free the old data if (pbDataOld) { GlobalFree(pbDataOld); pbDataOld = NULL; } } else { dwOldByteLength = GetMultiStrSize( (WCHAR*) pbDataOld) * sizeof(WCHAR); // Don't use realloc here, because for somereason it would fail in // certain test runs. pbDataNew = (BYTE *) GlobalAlloc(GPTR, dwOldByteLength); if (!pbDataNew) { hr = E_OUTOFMEMORY; goto AddRemoveIISCustomDescriptionEntry_Exit; } // copy the old data... memcpy(pbDataNew,pbDataOld,dwOldByteLength); // free the old data if (pbDataOld) { GlobalFree(pbDataOld); pbDataOld = NULL; } BOOL bDeletedSomething = FALSE; do { bDeletedSomething = DeleteEntryFromMultiSZ3Pair((LPCWSTR) pbDataNew,wszFilePath); } while (bDeletedSomething); // other wise pbDataOld is updated with the new data // proceed to write the new data out } // Write the new data out mr.dwMDIdentifier = MD_RESTRICTION_LIST_CUSTOM_DESC; mr.dwMDAttributes = 0; // no need for inheritence mr.dwMDUserType = IIS_MD_UT_SERVER; mr.dwMDDataType = MULTISZ_METADATA; mr.dwMDDataLen = GetMultiStrSize((WCHAR*)pbDataNew) * sizeof(WCHAR); mr.pbMDData = reinterpret_cast (pbDataNew); DumpWstrInMultiStr((WCHAR *) pbDataNew); hr = pIMSAdminBase->SetData(hMetabase, L"", &mr); AddRemoveIISCustomDescriptionEntry_Exit: if (FAILED(hr)) { wprintf(L"Failed to %s '%s'\r\n", bAddToList ? L"Add" : L"Remove", wszFilePath ); } else { wprintf(L"Succeeded to %s '%s'\r\n", bAddToList ? L"Add" : L"Remove", wszFilePath ); } if (hMetabase) { pIMSAdminBase->CloseKey(hMetabase); hMetabase = NULL; } if (pIMSAdminBase) { pIMSAdminBase->Release(); pIMSAdminBase = NULL; } if (pbDataOld) { GlobalFree(pbDataOld); pbDataOld = NULL; } if (pbDataNew) { GlobalFree(pbDataNew); pbDataNew = NULL; } CoUninitialize(); return hr; } BOOL OpenMetabaseAndDoExport(void) { BOOL fRet = FALSE; HRESULT hr; IMSAdminBase *pIMSAdminBase = NULL; // Metabase interface pointer IMSAdminBase2 *pIMSAdminBase2 = NULL; // Metabase interface pointer WCHAR wszExportPassword[_MAX_PATH]; WCHAR wszExportFileName[_MAX_PATH]; WCHAR wszMetabaseNodeToExport[_MAX_PATH]; wcscpy(wszExportFileName,L"c:\\TestExport.xml"); wcscpy(wszExportPassword,L"TestPassword"); wcscpy(wszMetabaseNodeToExport,L"/LM/W3SVC/1"); if (FAILED (hr = CoInitializeEx( NULL, COINIT_MULTITHREADED ))) { if (FAILED (hr = CoInitializeEx( NULL, COINIT_APARTMENTTHREADED ))) { return FALSE; } } if (FAILED (hr = ::CoCreateInstance(CLSID_MSAdminBase,NULL,CLSCTX_ALL,IID_IMSAdminBase,(void **)&pIMSAdminBase))) { goto OpenMetabaseAndDoExport_Exit; } if (SUCCEEDED(hr = pIMSAdminBase->QueryInterface(IID_IMSAdminBase2, (void **)&pIMSAdminBase2))) { SetBlanket(pIMSAdminBase2); hr = pIMSAdminBase2->Export(wszExportPassword,wszExportFileName,wszMetabaseNodeToExport,MD_EXPORT_INHERITED); pIMSAdminBase2->Release(); pIMSAdminBase2 = NULL; } if (FAILED(hr)) { wprintf(L"Failed to Export to file:%s,err=0x%x\r\n",wszExportFileName,hr); } else { wprintf(L"Succeeded to Export to file:%s\r\n",wszExportFileName); fRet = TRUE; } OpenMetabaseAndDoExport_Exit: if (pIMSAdminBase) { pIMSAdminBase->Release(); pIMSAdminBase = NULL; } CoUninitialize(); return fRet; } BOOL OpenMetabaseAndDoImport(void) { BOOL fRet = FALSE; HRESULT hr; IMSAdminBase *pIMSAdminBase = NULL; // Metabase interface pointer IMSAdminBase2 *pIMSAdminBase2 = NULL; // Metabase interface pointer WCHAR wszExportPassword[_MAX_PATH]; WCHAR wszImportFileName[_MAX_PATH]; WCHAR wszMetabaseNode1[_MAX_PATH]; WCHAR wszMetabaseNode2[_MAX_PATH]; wcscpy(wszImportFileName,L"c:\\TestExport.xml"); wcscpy(wszExportPassword,L"TestPassword"); wcscpy(wszMetabaseNode1,L"/LM/W3SVC/1"); wcscpy(wszMetabaseNode2,L"/LM/W3SVC/100"); if (FAILED (hr = CoInitializeEx( NULL, COINIT_MULTITHREADED ))) { if (FAILED (hr = CoInitializeEx( NULL, COINIT_APARTMENTTHREADED ))) { return FALSE; } } if (FAILED (hr = ::CoCreateInstance(CLSID_MSAdminBase,NULL,CLSCTX_ALL,IID_IMSAdminBase,(void **)&pIMSAdminBase))) { goto OpenMetabaseAndDoExport_Exit; } if (SUCCEEDED(hr = pIMSAdminBase->QueryInterface(IID_IMSAdminBase2, (void **)&pIMSAdminBase2))) { SetBlanket(pIMSAdminBase2); hr = pIMSAdminBase2->Import(wszExportPassword,wszImportFileName,wszMetabaseNode1,wszMetabaseNode2,MD_IMPORT_NODE_ONLY); pIMSAdminBase2->Release(); pIMSAdminBase2 = NULL; } if (FAILED(hr)) { wprintf(L"Failed to Export to file:%s,err=0x%x\r\n",wszImportFileName,hr); } else { wprintf(L"Succeeded to Export to file:%s\r\n",wszImportFileName); fRet = TRUE; } OpenMetabaseAndDoExport_Exit: if (pIMSAdminBase) { pIMSAdminBase->Release(); pIMSAdminBase = NULL; } CoUninitialize(); return fRet; } BOOL GetIISVersion_Internal_iiscnfgp(IMSAdminBase *pIMSAdminBase,DWORD * dwReturnedMajorVersion,DWORD * dwReturnedMinorVersion) { HRESULT hr; BOOL fRet = FALSE; METADATA_HANDLE hMetabase = NULL; // handle to metabase METADATA_RECORD mr; WCHAR szTmpData[MAX_PATH]; DWORD dwMDRequiredDataLen; // open key hr = pIMSAdminBase->OpenKey(METADATA_MASTER_ROOT_HANDLE, L"/LM/W3SVC/Info", METADATA_PERMISSION_READ, REASONABLE_TIMEOUT, &hMetabase); if( FAILED( hr )) { return FALSE; } //#define MD_SERVER_VERSION_MAJOR (IIS_MD_SERVER_BASE+101 ) //#define MD_SERVER_VERSION_MINOR (IIS_MD_SERVER_BASE+102 ) DWORD pdwValue = 0; mr.dwMDIdentifier = MD_SERVER_VERSION_MAJOR; mr.dwMDAttributes = 0; mr.dwMDUserType = IIS_MD_UT_SERVER; mr.dwMDDataType = DWORD_METADATA; mr.dwMDDataLen = sizeof(pdwValue); mr.pbMDData = reinterpret_cast(&pdwValue); pdwValue = 0; dwMDRequiredDataLen = 0; *dwReturnedMajorVersion = 0; hr = pIMSAdminBase->GetData( hMetabase, L"", &mr, &dwMDRequiredDataLen ); if( SUCCEEDED( hr )) { *dwReturnedMajorVersion = pdwValue; } mr.dwMDIdentifier = MD_SERVER_VERSION_MINOR; mr.pbMDData = reinterpret_cast(&pdwValue); pdwValue = 0; dwMDRequiredDataLen = 0; *dwReturnedMinorVersion = 0; hr = pIMSAdminBase->GetData( hMetabase, L"", &mr, &dwMDRequiredDataLen ); if( SUCCEEDED( hr )) { *dwReturnedMinorVersion = pdwValue; } WCHAR wszPrintString[MAX_PATH]; wsprintf(wszPrintString,L"MajorVer=%d,MinorVer=%d\n", *dwReturnedMajorVersion, *dwReturnedMinorVersion); wprintf(wszPrintString); pIMSAdminBase->CloseKey( hMetabase ); if( SUCCEEDED( hr )) { fRet = TRUE; } pIMSAdminBase->CloseKey( hMetabase ); return fRet; } BOOL OpenMetabaseAndGetVersion() { BOOL fRet = FALSE; HRESULT hr; IMSAdminBase *pIMSAdminBase = NULL; // Metabase interface pointer if( FAILED (CoInitializeEx( NULL, COINIT_MULTITHREADED )) || FAILED (::CoCreateInstance(CLSID_MSAdminBase, NULL, CLSCTX_ALL, IID_IMSAdminBase, (void **)&pIMSAdminBase))) { return FALSE; } DWORD dwMajorVersion,dwMinorVersion=0; GetIISVersion_Internal_iiscnfgp(pIMSAdminBase,&dwMajorVersion,&dwMinorVersion); if (pIMSAdminBase) { pIMSAdminBase->Release(); pIMSAdminBase = NULL; } CoUninitialize(); return fRet; } HRESULT RemoteOpenMetabaseAndCallExport( const WCHAR *pcszMachineName, const WCHAR *pcszUserName, const WCHAR *pcszDomain, const WCHAR *pcszPassword ) { HRESULT hr = E_FAIL; IMSAdminBase *pIMSAdminBase = NULL; IMSAdminBase2 *pIMSAdminBase2 = NULL; COSERVERINFO svrInfo; COAUTHINFO AuthInfo; COAUTHIDENTITY AuthId; ZeroMemory(&svrInfo, sizeof(COSERVERINFO)); ZeroMemory(&AuthInfo, sizeof(COAUTHINFO)); ZeroMemory(&AuthId, sizeof(COAUTHIDENTITY)); AuthId.User = (USHORT*) pcszUserName; AuthId.UserLength = wcslen (pcszUserName); AuthId.Domain = (USHORT*)pcszDomain; AuthId.DomainLength = wcslen (pcszDomain); AuthId.Password = (USHORT*)pcszPassword; AuthId.PasswordLength = wcslen (pcszPassword); AuthId.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; AuthInfo.dwAuthnSvc = RPC_C_AUTHN_WINNT; AuthInfo.dwAuthzSvc = RPC_C_AUTHZ_NONE; AuthInfo.pwszServerPrincName = NULL; // RPC_C_AUTHN_LEVEL_DEFAULT 0 // RPC_C_AUTHN_LEVEL_NONE 1 // RPC_C_AUTHN_LEVEL_CONNECT 2 // RPC_C_AUTHN_LEVEL_CALL 3 // RPC_C_AUTHN_LEVEL_PKT 4 // RPC_C_AUTHN_LEVEL_PKT_INTEGRITY 5 // RPC_C_AUTHN_LEVEL_PKT_PRIVACY 6 //AuthInfo.dwAuthnLevel = RPC_C_AUTHN_LEVEL_PKT_PRIVACY; AuthInfo.dwAuthnLevel = RPC_C_AUTHN_LEVEL_DEFAULT; AuthInfo.dwImpersonationLevel = RPC_C_IMP_LEVEL_IMPERSONATE; AuthInfo.pAuthIdentityData = &AuthId; AuthInfo.dwCapabilities = EOAC_NONE; svrInfo.dwReserved1 = 0; svrInfo.dwReserved2 = 0; svrInfo.pwszName = (LPWSTR) pcszMachineName; svrInfo.pAuthInfo = &AuthInfo; if(FAILED(hr = CoInitializeEx(NULL, COINIT_MULTITHREADED))) { if(FAILED(hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED))) { wprintf(L"CoInitializeEx failed:hr=0x%x\r\n",hr); return hr; } } MULTI_QI res[1] = { {&IID_IMSAdminBase, NULL, 0} }; // CLSCTX_INPROC_SERVER = 1, // CLSCTX_INPROC_HANDLER = 2, // CLSCTX_LOCAL_SERVER = 4 // CLSCTX_REMOTE_SERVER = 16 // CLSCTX_NO_CODE_DOWNLOAD = 400 // CLSCTX_NO_FAILURE_LOG = 4000 // #define CLSCTX_SERVER (CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER) // #define CLSCTX_ALL (CLSCTX_INPROC_HANDLER | CLSCTX_SERVER) if (FAILED(hr = CoCreateInstanceEx(CLSID_MSAdminBase,NULL,CLSCTX_ALL,&svrInfo,1,res))) { wprintf(L"CoCreateInstanceEx failed:hr=0x%x\r\n",hr); goto RemoteOpenMetabaseAndCallExport_Exit; } pIMSAdminBase = (IMSAdminBase *)res[0].pItf; { hr = ::CoSetProxyBlanket( pIMSAdminBase, AuthInfo.dwAuthnSvc, AuthInfo.dwAuthzSvc, AuthInfo.pwszServerPrincName, AuthInfo.dwAuthnLevel, AuthInfo.dwImpersonationLevel, AuthInfo.pAuthIdentityData, AuthInfo.dwCapabilities ); if (FAILED(hr)) { wprintf(L"CoSetProxyBlanket failed:hr=0x%x\r\n",hr); goto RemoteOpenMetabaseAndCallExport_Exit; } // There is a remote IUnknown interface that lurks behind IUnknown. // If that is not set, then the Release call can return access denied. IUnknown * pUnk = NULL; hr = pIMSAdminBase->QueryInterface(IID_IUnknown, (void **)&pUnk); if(FAILED(hr)) { wprintf(L"QueryInterface failed:hr=0x%x\r\n",hr); return hr; } hr = ::CoSetProxyBlanket( pUnk, AuthInfo.dwAuthnSvc, AuthInfo.dwAuthzSvc, AuthInfo.pwszServerPrincName, AuthInfo.dwAuthnLevel, AuthInfo.dwImpersonationLevel, AuthInfo.pAuthIdentityData, AuthInfo.dwCapabilities ); if (FAILED(hr)) { wprintf(L"CoSetProxyBlanket2 failed:hr=0x%x\r\n",hr); goto RemoteOpenMetabaseAndCallExport_Exit; } pUnk->Release();pUnk = NULL; } if (FAILED(hr = pIMSAdminBase->QueryInterface(IID_IMSAdminBase2, (void **)&pIMSAdminBase2))) { wprintf(L"QueryInterface2 failed:hr=0x%x\r\n",hr); goto RemoteOpenMetabaseAndCallExport_Exit; } hr = ::CoSetProxyBlanket( pIMSAdminBase2, AuthInfo.dwAuthnSvc, AuthInfo.dwAuthzSvc, AuthInfo.pwszServerPrincName, AuthInfo.dwAuthnLevel, AuthInfo.dwImpersonationLevel, AuthInfo.pAuthIdentityData, AuthInfo.dwCapabilities ); if (FAILED(hr)) { wprintf(L"CoSetProxyBlanket3 failed:hr=0x%x\r\n",hr); goto RemoteOpenMetabaseAndCallExport_Exit; } hr = pIMSAdminBase2->Export(L"testing",L"c:\\testing.xml333",L"LM/W3SVC/1",0); if (FAILED(hr)) { wprintf(L"pIMSAdminBase2->Export failed:ret=0x%x\r\n",hr); } RemoteOpenMetabaseAndCallExport_Exit: if (SUCCEEDED(hr)) { wprintf(L"RemoteOpenMetabaseAndCallExport:SUCCEEDED!!!! :hr=0x%x\r\n",hr); } if (pIMSAdminBase2) { pIMSAdminBase2->Release(); pIMSAdminBase2 = NULL; } if (pIMSAdminBase) { pIMSAdminBase->Release(); pIMSAdminBase = NULL; } CoUninitialize(); return hr; }