/*++ Copyright (c) 2000-2001 Microsoft Corporation Module Name: SecConLib.cpp Abstract: Implementation of: CSecConLib Author: Brent R. Midwood Apr-2002 Revision History: --*/ #include "secconlib.h" #include "debug.h" #include "iiscnfg.h" #define BAIL_ON_FAILURE(hr) if (FAILED(hr)) { goto done; } #define DEFAULT_TIMEOUT_VALUE 30000 #define SEMICOLON_STRING L";" #define SEMICOLON_CHAR L';' #define COMMA_STRING L"," #define COMMA_CHAR L',' #define ZERO_STRING L"0" #define ZERO_CHAR L'0' #define ONE_STRING L"1" #define ONE_CHAR L'1' CSecConLib::CSecConLib() { m_bInit = false; } CSecConLib::CSecConLib( IMSAdminBase* pIABase) { SC_ASSERT(pIABase != NULL); m_spIABase = pIABase; m_bInit = true; } CSecConLib::~CSecConLib() { } HRESULT CSecConLib::InternalInitIfNecessary() { HRESULT hr = S_OK; CSafeLock csSafe(m_SafeCritSec); if(m_bInit) { return hr; } hr = csSafe.Lock(); hr = HRESULT_FROM_WIN32(hr); if(FAILED(hr)) { return hr; } if(!m_bInit) { hr = CoCreateInstance( CLSID_MSAdminBase, NULL, CLSCTX_ALL, IID_IMSAdminBase, (void**)&m_spIABase); if(FAILED(hr)) { m_bInit = false; } else { m_bInit = true; } } csSafe.Unlock(); return hr; } STDMETHODIMP CSecConLib::EnableApplication( /* [in] */ LPCWSTR wszApplication, /* [in] */ LPCWSTR wszPath) { DWORD dwAppNameSz = 0; WCHAR *pwszAppProp = NULL; DWORD dwAppPropSz = 0; HRESULT hr = S_OK; bool bFound = false; WCHAR *pTop = NULL; // compute arg length dwAppNameSz = (DWORD)wcslen(wszApplication); hr = InternalInitIfNecessary(); if (FAILED(hr)) { BAIL_ON_FAILURE(hr); } // get the current property value for applicationdep list hr = GetMultiSZPropVal(wszPath, MD_APP_DEPENDENCIES, &pwszAppProp, &dwAppPropSz); BAIL_ON_FAILURE(hr); if (NULL == pwszAppProp) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } pTop = pwszAppProp; // go thru the apps one by one while (pwszAppProp[0]) { DWORD dwTokSz = (DWORD)wcslen(pwszAppProp) + 1; // check to see if the app matches if (!_wcsnicmp(wszApplication, pwszAppProp, dwAppNameSz) && pwszAppProp[dwAppNameSz] == SEMICOLON_CHAR) { bFound = true; WCHAR *pGroups = &pwszAppProp[dwAppNameSz + ((DWORD)sizeof(SEMICOLON_CHAR) / (DWORD)sizeof(WCHAR))]; while (pGroups) { WCHAR *pTemp = wcschr(pGroups, COMMA_CHAR); if (pTemp) { *pTemp = 0; // replace comma w/ null } hr = EnableWebServiceExtension(pGroups, wszPath); BAIL_ON_FAILURE(hr); if (pTemp) { pGroups = pTemp + 1; // go past comma } else { pGroups = NULL; } } } pwszAppProp += dwTokSz; // go to the next part of the multisz } if (!bFound) { BAIL_ON_FAILURE(hr = MD_ERROR_DATA_NOT_FOUND); } done: if (pTop) { delete [] pTop; } return hr; } HRESULT CSecConLib::SetMultiSZPropVal( LPCWSTR wszPath, DWORD dwMetaId, WCHAR *pBuffer, DWORD dwBufSize) { HRESULT hr = S_OK; METADATA_RECORD mdrMDData; METADATA_HANDLE hObjHandle = NULL; hr = m_spIABase->OpenKey( METADATA_MASTER_ROOT_HANDLE, wszPath, METADATA_PERMISSION_WRITE, DEFAULT_TIMEOUT_VALUE, &hObjHandle ); BAIL_ON_FAILURE(hr); if (!pBuffer) { hr = m_spIABase->DeleteData( hObjHandle, (LPWSTR)L"", dwMetaId, ALL_METADATA ); BAIL_ON_FAILURE(hr); } else { MD_SET_DATA_RECORD(&mdrMDData, dwMetaId, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, MULTISZ_METADATA, dwBufSize * sizeof(WCHAR), pBuffer); hr = m_spIABase->SetData( hObjHandle, L"", &mdrMDData ); BAIL_ON_FAILURE(hr); } done: m_spIABase->CloseKey(hObjHandle); return hr; } HRESULT CSecConLib::GetMultiSZPropVal( LPCWSTR wszPath, DWORD dwMetaId, WCHAR **ppBuffer, DWORD *dwBufSize) { HRESULT hr = S_OK; DWORD dwBufferSize = 0; METADATA_RECORD mdrMDData; WCHAR *pBuffer = NULL; METADATA_HANDLE hObjHandle = NULL; hr = m_spIABase->OpenKey( METADATA_MASTER_ROOT_HANDLE, wszPath, METADATA_PERMISSION_READ, DEFAULT_TIMEOUT_VALUE, &hObjHandle ); BAIL_ON_FAILURE(hr); MD_SET_DATA_RECORD(&mdrMDData, dwMetaId, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, MULTISZ_METADATA, dwBufferSize, pBuffer); hr = m_spIABase->GetData( hObjHandle, L"", &mdrMDData, &dwBufferSize ); if (dwBufferSize > 0) { *dwBufSize = dwBufferSize / sizeof(WCHAR); pBuffer = (WCHAR*) new BYTE[dwBufferSize]; if (!pBuffer) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } MD_SET_DATA_RECORD(&mdrMDData, dwMetaId, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, MULTISZ_METADATA, dwBufferSize, pBuffer); hr = m_spIABase->GetData( hObjHandle, L"", &mdrMDData, &dwBufferSize ); } BAIL_ON_FAILURE(hr); *ppBuffer = pBuffer; hr = m_spIABase->CloseKey(hObjHandle); return hr; done: if (pBuffer) { delete [] pBuffer; } m_spIABase->CloseKey(hObjHandle); return hr; } STDMETHODIMP CSecConLib::RemoveApplication( /* [in] */ LPCWSTR wszApplication, /* [in] */ LPCWSTR wszPath) { DWORD dwAppNameSz = 0; WCHAR *pwszOrig = NULL; WCHAR *pTopOrig = NULL; WCHAR *pwszAppProp = NULL; DWORD dwAppPropSz = 0; HRESULT hr = S_OK; bool bFound = false; // compute arg length dwAppNameSz = (DWORD)wcslen(wszApplication); hr = InternalInitIfNecessary(); if (FAILED(hr)) { BAIL_ON_FAILURE(hr); } // get the current property value for applicationdep list hr = GetMultiSZPropVal(wszPath, MD_APP_DEPENDENCIES, &pwszAppProp, &dwAppPropSz); BAIL_ON_FAILURE(hr); // remove the application // copy the property pwszOrig = new WCHAR[dwAppPropSz]; pTopOrig = pwszOrig; if (!pwszOrig) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } memcpy(pwszOrig, pwszAppProp, dwAppPropSz * sizeof(WCHAR)); dwAppPropSz = 1; //reset size to contain one for the last null WCHAR* pMidBuf = pwszAppProp; // copy the old apps one by one while (pwszOrig[0]) { DWORD dwTokSz = (DWORD)wcslen(pwszOrig) + 1; // check to see if the app already exists if (!_wcsnicmp(wszApplication, pwszOrig, dwAppNameSz) && pwszOrig[dwAppNameSz] == SEMICOLON_CHAR) { bFound = true; } else { // copy it in if (NULL == pMidBuf) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } wcscpy(pMidBuf, pwszOrig); pMidBuf += dwTokSz; // advance past null *pMidBuf = 0; // add the last null dwAppPropSz += dwTokSz; } pwszOrig += dwTokSz; // go to the next part of the multisz } if (!bFound) { BAIL_ON_FAILURE(hr = MD_ERROR_DATA_NOT_FOUND); } // set the new property value for property if (dwAppPropSz < 3) { // handle deleting the last one hr = SetMultiSZPropVal(wszPath, MD_APP_DEPENDENCIES, NULL, 0); } else { hr = SetMultiSZPropVal(wszPath, MD_APP_DEPENDENCIES, pwszAppProp, dwAppPropSz); } BAIL_ON_FAILURE(hr); done: if (pTopOrig) { delete [] pTopOrig; } if (pwszAppProp) { delete [] pwszAppProp; } return hr; } STDMETHODIMP CSecConLib::QueryGroupIDStatus( /* [in] */ LPCWSTR wszPath, /* [in] */ LPCWSTR wszGroupID, /* [out] */ WCHAR **pszBuffer, // MULTI_SZ - allocated in here, caller should delete /* [out] */ DWORD *pdwBufferSize) // length includes double null { WCHAR *pwszAppProp = NULL; DWORD dwAppPropSz = 0; WCHAR *pList = NULL; WCHAR *pTempList = NULL; DWORD dwListLen = 1; // one for the extra null at the end DWORD dwOldListLen = 1; HRESULT hr = S_OK; WCHAR *pTop = NULL; hr = InternalInitIfNecessary(); if (FAILED(hr)) { BAIL_ON_FAILURE(hr); } // get the current property value for applicationdep list hr = GetMultiSZPropVal(wszPath, MD_APP_DEPENDENCIES, &pwszAppProp, &dwAppPropSz); BAIL_ON_FAILURE(hr); if (NULL == pwszAppProp) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } pTop = pwszAppProp; // iterate through the apps while (pwszAppProp[0]) { // reset bFound bool bFound = false; WCHAR* pMidBuf = wcschr(pwszAppProp, SEMICOLON_CHAR); if (!pMidBuf) { BAIL_ON_FAILURE(hr = E_FAIL); } // null the semicolon and go past it *pMidBuf = 0; *pMidBuf++; // does this app have a dependency on the GroupID that got passed in? WCHAR* pGroupID = NULL; WCHAR* pGroups = new WCHAR[(DWORD)wcslen(pMidBuf) + 1]; if (!pGroups) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } // copy in the GroupIDs wcscpy(pGroups, pMidBuf); // look at each GroupID pGroupID = wcstok(pGroups, COMMA_STRING); while (pGroupID && !bFound) { if (!wcscmp(pGroupID, wszGroupID)) { bFound = true; } pGroupID = wcstok(NULL, COMMA_STRING); } if (pGroups) { delete [] pGroups; } // do we want to add this app to the list? if (bFound) { // allocate the memory dwListLen += (DWORD)wcslen(pwszAppProp) + 1; // for the null pTempList = new WCHAR[dwListLen]; if (!pTempList) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } if (pList) { // copy the previous list memcpy(pTempList, pList, dwOldListLen * sizeof(WCHAR)); delete [] pList; } // copy on the app name wcscpy(&pTempList[dwOldListLen - 1], pwszAppProp); pTempList[dwListLen-1] = 0; pTempList[dwListLen-2] = 0; pList = pTempList; dwOldListLen = dwListLen; } // now go to the next application pwszAppProp = pMidBuf + (DWORD)wcslen(pMidBuf) + 1; } *pszBuffer = pList; *pdwBufferSize = dwListLen; done: if (pTop) { delete [] pTop; } return hr; } STDMETHODIMP CSecConLib::ListApplications( /* [in] */ LPCWSTR wszPath, /* [out] */ WCHAR **pszBuffer, // MULTI_SZ - allocated in here, caller should delete /* [out] */ DWORD *pdwBufferSize) // length includes double null { WCHAR *pwszAppProp = NULL; DWORD dwAppPropSz = 0; WCHAR *pList = NULL; WCHAR *pTempList = NULL; DWORD dwListLen = 1; // one for the extra null at the end DWORD dwOldListLen = 1; HRESULT hr = S_OK; WCHAR *pTop = NULL; hr = InternalInitIfNecessary(); if (FAILED(hr)) { BAIL_ON_FAILURE(hr); } // get the current property value for applicationdep list hr = GetMultiSZPropVal(wszPath, MD_APP_DEPENDENCIES, &pwszAppProp, &dwAppPropSz); BAIL_ON_FAILURE(hr); if (NULL == pwszAppProp) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } pTop = pwszAppProp; // iterate through the apps while (pwszAppProp[0]) { WCHAR* pMidBuf = wcschr(pwszAppProp, SEMICOLON_CHAR); if (!pMidBuf) { BAIL_ON_FAILURE(hr = E_FAIL); } // null the semicolon and go past it *pMidBuf = 0; *pMidBuf++; // allocate the memory dwListLen += (DWORD)wcslen(pwszAppProp) + 1; // for the null pTempList = new WCHAR[dwListLen]; if (!pTempList) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } if (pList) { // copy the previous list memcpy(pTempList, pList, dwOldListLen * sizeof(WCHAR)); delete [] pList; } // copy on the app name wcscpy(&pTempList[dwOldListLen - 1], pwszAppProp); pTempList[dwListLen-1] = 0; pTempList[dwListLen-2] = 0; pList = pTempList; dwOldListLen = dwListLen; // now go to the next application pwszAppProp = pMidBuf + (DWORD)wcslen(pMidBuf) + 1; } if (!pList) { // make it a valid empty multisz dwListLen = 2; pList = new WCHAR[dwListLen]; if (!pList) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } wmemset(pList, 0, dwListLen); } *pszBuffer = pList; *pdwBufferSize = dwListLen; done: if (pTop) { delete [] pTop; } return hr; } STDMETHODIMP CSecConLib::AddDependency( /* [in] */ LPCWSTR wszApplication, /* [in] */ LPCWSTR wszGroupID, /* [in] */ LPCWSTR wszPath) { WCHAR *pwszAppProp = NULL; WCHAR *pwszOrig = NULL; WCHAR *pwszTopOrig = NULL; DWORD dwAppPropSz = 0; DWORD dwAppNameSz = 0; DWORD dwGroupIDSz = 0; HRESULT hr = S_OK; bool bDone = false; // compute arg length dwAppNameSz = (DWORD)wcslen(wszApplication); dwGroupIDSz = (DWORD)wcslen(wszGroupID); hr = InternalInitIfNecessary(); if (FAILED(hr)) { BAIL_ON_FAILURE(hr); } // get the current property value for applicationdep list hr = GetMultiSZPropVal(wszPath, MD_APP_DEPENDENCIES, &pwszAppProp, &dwAppPropSz); if (MD_ERROR_DATA_NOT_FOUND == hr) { // this is okay, we just need to create the property. hr = S_OK; dwAppPropSz = 0; } BAIL_ON_FAILURE(hr); // add the dependency if (!dwAppPropSz) { // create the property // size of the property = len(App) + 1(semicolon) + len(GID) + 2(double null MULTISZ) dwAppPropSz = dwAppNameSz + (DWORD)wcslen(SEMICOLON_STRING) + dwGroupIDSz + 2; // No Leak // pwszAppProp never got alloced since we didn't get any value back, // so no need to delete first... pwszAppProp = new WCHAR[dwAppPropSz]; if (!pwszAppProp) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } wcscpy(pwszAppProp, wszApplication); wcscat(pwszAppProp, SEMICOLON_STRING); wcscat(pwszAppProp, wszGroupID); // add the double null pwszAppProp[dwAppPropSz-1] = 0; pwszAppProp[dwAppPropSz-2] = 0; } else { // property already exists // copy the property pwszOrig = new WCHAR[dwAppPropSz]; pwszTopOrig = pwszOrig; if (!pwszOrig) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } memcpy(pwszOrig, pwszAppProp, dwAppPropSz * sizeof(WCHAR)); // resize the new property to the biggest possible if (pwszAppProp) { delete [] pwszAppProp; } // max new size is old size + len(app) + 1(semicolon) + len(GID) + null dwAppPropSz = dwAppPropSz + dwAppNameSz + (DWORD)wcslen(SEMICOLON_STRING) + dwGroupIDSz + 1; pwszAppProp = new WCHAR[dwAppPropSz]; if (!pwszAppProp) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } WCHAR* pMidBuf = pwszAppProp; // copy the old dependencies one by one while (pwszOrig[0]) { wcscpy(pMidBuf, pwszOrig); // check to see if the app already exists if (!_wcsnicmp(wszApplication, pMidBuf, dwAppNameSz) && pMidBuf[dwAppNameSz] == SEMICOLON_CHAR) { // since we're not adding the app, subtract the size of the app and trailing null dwAppPropSz = dwAppPropSz - dwAppNameSz - 1; // this is the correct app, so now look for the GroupID pMidBuf += dwAppNameSz + 1; // go to the first GroupID // need a temp copy, sinc wcstok modifies the string WCHAR* pTokTemp = new WCHAR[(DWORD)wcslen(pMidBuf) + 1]; if (!pTokTemp) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } wcscpy(pTokTemp, pMidBuf); WCHAR* token = wcstok( pTokTemp, COMMA_STRING ); while (token && !bDone) { if (!_wcsicmp(token, wszGroupID)) { // we found the group ID, so the user is trying // to add a dependency that is already there if (pTokTemp) { delete [] pTokTemp; } BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(ERROR_DUP_NAME)); } token = wcstok( NULL, COMMA_STRING ); } if (pTokTemp) { delete [] pTokTemp; } pMidBuf += (DWORD)wcslen(pMidBuf); // go to the null at the end of this part if (!bDone) { // we didn't find the GroupID, so add it wcscat(pMidBuf, COMMA_STRING); wcscat(pMidBuf, wszGroupID); pMidBuf += (DWORD)wcslen(pMidBuf); // go to the null at the end of this part bDone = true; } pMidBuf++; // go to the next char and make it a null pMidBuf[0] = 0; } else // no change here, move pMidBuf along... { pMidBuf += (DWORD)wcslen(pMidBuf) + 1; // go past the null } pwszOrig += (DWORD)wcslen(pwszOrig) + 1; // go to the next part of the multisz } if (!bDone) { // we didn't even find the application, so add both app & groupID wcscpy(pMidBuf, wszApplication); wcscat(pMidBuf, SEMICOLON_STRING); wcscat(pMidBuf, wszGroupID); pMidBuf[(DWORD)wcslen(pMidBuf)+1] = 0; // add the last null } } // set the new property value for property hr = SetMultiSZPropVal(wszPath, MD_APP_DEPENDENCIES, pwszAppProp, dwAppPropSz); BAIL_ON_FAILURE(hr); done: if (pwszTopOrig) { delete [] pwszTopOrig; } if (pwszAppProp) { delete [] pwszAppProp; } return hr; } STDMETHODIMP CSecConLib::RemoveDependency( /* [in] */ LPCWSTR wszApplication, /* [in] */ LPCWSTR wszGroupID, /* [in] */ LPCWSTR wszPath) { HRESULT hr = S_OK; WCHAR *pwszOrig = NULL; WCHAR *pwszTopOrig = NULL; WCHAR *pwszAppProp = NULL; WCHAR *pStartStr = NULL; DWORD dwAppPropSz = 0; DWORD dwAppNameSz = 0; DWORD dwGroupIDSz = 0; bool bFound = false; bool bOtherGIDs = false; // compute arg length dwAppNameSz = (DWORD)wcslen(wszApplication); dwGroupIDSz = (DWORD)wcslen(wszGroupID); hr = InternalInitIfNecessary(); if (FAILED(hr)) { BAIL_ON_FAILURE(hr); } // get the current property value for applicationdep list hr = GetMultiSZPropVal(wszPath, MD_APP_DEPENDENCIES, &pwszAppProp, &dwAppPropSz); BAIL_ON_FAILURE(hr); // remove the dependency // copy the property pwszOrig = new WCHAR[dwAppPropSz]; pwszTopOrig = pwszOrig; if (!pwszOrig) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } memcpy(pwszOrig, pwszAppProp, dwAppPropSz * sizeof(WCHAR)); WCHAR* pMidBuf = pwszAppProp; // copy the old dependencies one by one while (pwszOrig[0]) { // check to see if the app already exists if (!_wcsnicmp(wszApplication, pwszOrig, dwAppNameSz) && pwszOrig[dwAppNameSz] == SEMICOLON_CHAR) { pStartStr = pMidBuf; // this is the correct app, so now look for the GroupID pMidBuf += dwAppNameSz + 1; // go to the first GroupID // need a temp copy, sinc wcstok modifies the string WCHAR* pTokTemp = new WCHAR[(DWORD)wcslen(pMidBuf) + 1]; if (!pTokTemp) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } wcscpy(pTokTemp, pMidBuf); WCHAR* token = wcstok( pTokTemp, COMMA_STRING ); while (token) { if (bOtherGIDs) { wcscpy(pMidBuf, COMMA_STRING); pMidBuf += (DWORD)wcslen(pMidBuf); } if (!wcscmp(token, wszGroupID)) { // we found the group ID bFound = true; // adjust the final length = no comma, no GID dwAppPropSz = dwAppPropSz - (DWORD)wcslen(COMMA_STRING) - dwGroupIDSz; if (bOtherGIDs) { // need to backup over the last comma we inserted pMidBuf -= (DWORD)wcslen(COMMA_STRING); *pMidBuf = 0; } } else { bOtherGIDs = true; wcscpy(pMidBuf, token); pMidBuf += (DWORD)wcslen(pMidBuf); } token = wcstok( NULL, COMMA_STRING ); } if (pTokTemp) { delete [] pTokTemp; } if (!bOtherGIDs) { // deleted last dependency, so delete the app pMidBuf = pStartStr; dwAppPropSz = dwAppPropSz - dwAppNameSz - 1; // account for null } else { pMidBuf++; *pMidBuf = 0; } } else // no change here, move pMidBuf along... { if (NULL == pMidBuf) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } wcscpy(pMidBuf, pwszOrig); // copy the part without mods pMidBuf += (DWORD)wcslen(pMidBuf) + 1; // go past the null } pwszOrig += (DWORD)wcslen(pwszOrig) + 1; // go to the next part of the multisz } if (!bFound) { // user is trying to remove a non-existent dependency BAIL_ON_FAILURE(hr = MD_ERROR_DATA_NOT_FOUND); } *pMidBuf = 0; // set the new property value for property if (dwAppPropSz < 3) { // handle deleting the last one hr = SetMultiSZPropVal(wszPath, MD_APP_DEPENDENCIES, NULL, 0); } else { hr = SetMultiSZPropVal(wszPath, MD_APP_DEPENDENCIES, pwszAppProp, dwAppPropSz); } BAIL_ON_FAILURE(hr); done: if (pwszTopOrig) { delete [] pwszTopOrig; } if (pwszAppProp) { delete [] pwszAppProp; } return hr; } STDMETHODIMP CSecConLib::EnableWebServiceExtension( /* [in] */ LPCWSTR wszExtension, /* [in] */ LPCWSTR wszPath) { HRESULT hr = S_OK; hr = InternalInitIfNecessary(); if (FAILED(hr)) { BAIL_ON_FAILURE(hr); } hr = StatusWServEx(true, wszExtension, wszPath); if (FAILED(hr)) { BAIL_ON_FAILURE(hr); } done: return hr; } STDMETHODIMP CSecConLib::DisableWebServiceExtension( /* [in] */ LPCWSTR wszExtension, /* [in] */ LPCWSTR wszPath) { HRESULT hr = S_OK; hr = InternalInitIfNecessary(); if (FAILED(hr)) { BAIL_ON_FAILURE(hr); } hr = StatusWServEx(false, wszExtension, wszPath); if (FAILED(hr)) { BAIL_ON_FAILURE(hr); } done: return hr; } STDMETHODIMP CSecConLib::ListWebServiceExtensions( /* [in] */ LPCWSTR wszPath, /* [out] */ WCHAR **pszBuffer, // MULTI_SZ - allocated in here, caller should delete /* [out] */ DWORD *pdwBufferSize) // length includes double null { WCHAR *pwszRListProp = NULL; DWORD dwRListPropSz = 0; WCHAR *pList = NULL; WCHAR *pTempList = NULL; DWORD dwListLen = 1; // one for the extra null at the end DWORD dwOldListLen = 1; HRESULT hr = S_OK; WCHAR *pTop = NULL; WCHAR *pMidBuf = NULL; bool bFound = false; bool bSpecial = false; hr = InternalInitIfNecessary(); if (FAILED(hr)) { BAIL_ON_FAILURE(hr); } // get the current property value for applicationdep list hr = GetMultiSZPropVal(wszPath, MD_WEB_SVC_EXT_RESTRICTION_LIST, &pwszRListProp, &dwRListPropSz); BAIL_ON_FAILURE(hr); if (NULL == pwszRListProp) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } pTop = pwszRListProp; // iterate through the files while (pwszRListProp[0]) { // get to the group ID for (int i=0; i<3; i++) { pMidBuf = wcschr(pwszRListProp, COMMA_CHAR); if (!pMidBuf) { // don't fail. just treat this as a special case and break out bSpecial = true; pMidBuf = pwszRListProp; break; } // null the comma and go past it *pMidBuf = 0; *pMidBuf++; pwszRListProp = pMidBuf; } if (COMMA_CHAR == pMidBuf[0]) { bSpecial = true; pMidBuf = pwszRListProp; } if (!bSpecial) { // now we're looking at the group ID pMidBuf = wcschr(pwszRListProp, COMMA_CHAR); // if we can't find the comma, just treat the whole thing as a GroupID // otherwise, the GroupID ends at the comma if (pMidBuf) { // null the comma and go past it *pMidBuf = 0; *pMidBuf++; } // check to see if the entry is in the list already WCHAR *pCheck = pList; while (pCheck && *pCheck) { if (!_wcsicmp(pCheck, pwszRListProp)) { bFound = true; pCheck = NULL; } else { pCheck += (DWORD)wcslen(pCheck) + 1; } } if (!bFound) { // allocate the memory dwListLen += (DWORD)wcslen(pwszRListProp) + 1; // for the null pTempList = new WCHAR[dwListLen]; if (!pTempList) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } if (pList) { // copy the previous list memcpy(pTempList, pList, dwOldListLen * sizeof(WCHAR)); delete [] pList; } // copy on the file name wcscpy(&pTempList[dwOldListLen - 1], pwszRListProp); pTempList[dwListLen-1] = 0; pTempList[dwListLen-2] = 0; pList = pTempList; dwOldListLen = dwListLen; } } // now go to the next application pwszRListProp = pMidBuf + (DWORD)wcslen(pMidBuf) + 1; bFound = false; bSpecial = false; } if (!pList) { // make it a valid empty multisz dwListLen = 2; pList = new WCHAR[dwListLen]; if (!pList) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } wmemset(pList, 0, dwListLen); } *pszBuffer = pList; *pdwBufferSize = dwListLen; done: if (pTop) { delete [] pTop; } return hr; } STDMETHODIMP CSecConLib::EnableExtensionFile( /* [in] */ LPCWSTR wszExFile, /* [in] */ LPCWSTR wszPath) { HRESULT hr = S_OK; hr = InternalInitIfNecessary(); if (FAILED(hr)) { BAIL_ON_FAILURE(hr); } hr = StatusExtensionFile(true, wszExFile, wszPath); if (FAILED(hr)) { BAIL_ON_FAILURE(hr); } done: return hr; } STDMETHODIMP CSecConLib::DisableExtensionFile( /* [in] */ LPCWSTR wszExFile, /* [in] */ LPCWSTR wszPath) { HRESULT hr = S_OK; hr = InternalInitIfNecessary(); if (FAILED(hr)) { BAIL_ON_FAILURE(hr); } hr = StatusExtensionFile(false, wszExFile, wszPath); if (FAILED(hr)) { BAIL_ON_FAILURE(hr); } done: return hr; } HRESULT CSecConLib::StatusWServEx( /* [in] */ bool bEnable, /* [in] */ LPCWSTR wszWServEx, /* [in] */ LPCWSTR wszPath) { WCHAR *pwszRListProp = NULL; WCHAR *pTop = NULL; DWORD dwRListPropSz = 0; HRESULT hr = S_OK; DWORD dwWServExSz = 0; bool bFound = false; // compute arg length dwWServExSz = (DWORD)wcslen(wszWServEx); // get the current property value for restriction list hr = GetMultiSZPropVal(wszPath, MD_WEB_SVC_EXT_RESTRICTION_LIST, &pwszRListProp, &dwRListPropSz); BAIL_ON_FAILURE(hr); if (NULL == pwszRListProp) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } pTop = pwszRListProp; // look at the files one by one while (pwszRListProp[0]) { DWORD dwTokSz = (DWORD)wcslen(pwszRListProp) + 1; WCHAR *pFileTemp = new WCHAR[dwTokSz]; WCHAR *pToken; if (!pFileTemp) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } // check to see if we're at the right group wcscpy(pFileTemp, pwszRListProp); pToken = wcstok( pFileTemp, COMMA_STRING ); // look at the group ID for (int i=0; i<3; i++) { if (pToken) { pToken = wcstok( NULL, COMMA_STRING ); } } if (pToken && (!wcscmp(pToken, wszWServEx))) { bFound = true; if (bEnable) { pwszRListProp[0] = ONE_CHAR; } else { pwszRListProp[0] = ZERO_CHAR; } } pwszRListProp += dwTokSz; // go to the next part of the multisz if (pFileTemp) { delete [] pFileTemp; } } if (!bFound) { BAIL_ON_FAILURE(hr = MD_ERROR_DATA_NOT_FOUND); } // set the new property value for property hr = SetMultiSZPropVal(wszPath, MD_WEB_SVC_EXT_RESTRICTION_LIST, pTop, dwRListPropSz); BAIL_ON_FAILURE(hr); done: if (pTop) { delete [] pTop; } return hr; } HRESULT CSecConLib::StatusExtensionFile( /* [in] */ bool bEnable, /* [in] */ LPCWSTR wszExFile, /* [in] */ LPCWSTR wszPath) { WCHAR *pwszRListProp = NULL; WCHAR *pTop = NULL; DWORD dwRListPropSz = 0; HRESULT hr = S_OK; DWORD dwFileNameSz = 0; bool bFound = false; // compute arg length dwFileNameSz = (DWORD)wcslen(wszExFile); // get the current property value for restriction list hr = GetMultiSZPropVal(wszPath, MD_WEB_SVC_EXT_RESTRICTION_LIST, &pwszRListProp, &dwRListPropSz); BAIL_ON_FAILURE(hr); if (NULL == pwszRListProp) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } pTop = pwszRListProp; // look at the files one by one while (pwszRListProp[0]) { DWORD dwTokSz = (DWORD)wcslen(pwszRListProp) + 1; // check to see if we're at the right file // look past the bool(1) + comma(sizof_comma_char) DWORD dwTemp = (DWORD)sizeof(COMMA_CHAR) / (DWORD)sizeof(WCHAR); if ((!_wcsnicmp(wszExFile, &pwszRListProp[1 + dwTemp], dwFileNameSz)) && ((pwszRListProp[dwFileNameSz + dwTemp + 1] == COMMA_CHAR) || (pwszRListProp[dwFileNameSz + dwTemp + 1] == NULL) ) ) { bFound = true; if (bEnable) { pwszRListProp[0] = ONE_CHAR; } else { pwszRListProp[0] = ZERO_CHAR; } } pwszRListProp += dwTokSz; // go to the next part of the multisz } if (!bFound) { BAIL_ON_FAILURE(hr = MD_ERROR_DATA_NOT_FOUND); } // set the new property value for property hr = SetMultiSZPropVal(wszPath, MD_WEB_SVC_EXT_RESTRICTION_LIST, pTop, dwRListPropSz); BAIL_ON_FAILURE(hr); done: if (pTop) { delete [] pTop; } return hr; } STDMETHODIMP CSecConLib::AddExtensionFile( /* [in] */ LPCWSTR bstrExtensionFile, /* [in] */ bool bAccess, /* [in] */ LPCWSTR bstrGroupID, /* [in] */ bool bCanDelete, /* [in] */ LPCWSTR bstrDescription, /* [in] */ LPCWSTR wszPath) { HRESULT hr = S_OK; WCHAR *pwszRListProp = NULL; WCHAR *pwszOrig = NULL; WCHAR *pwszTopOrig = NULL; DWORD dwRListPropSz = 0; DWORD dwFileNameSz = 0; DWORD dwGroupIDSz = 0; DWORD dwDescSz = 0; // compute arg length dwFileNameSz = (DWORD)wcslen(bstrExtensionFile); dwGroupIDSz = (DWORD)wcslen(bstrGroupID); dwDescSz = (DWORD)wcslen(bstrDescription); hr = InternalInitIfNecessary(); if (FAILED(hr)) { BAIL_ON_FAILURE(hr); } // get the current property value for restriction list hr = GetMultiSZPropVal(wszPath, MD_WEB_SVC_EXT_RESTRICTION_LIST, &pwszRListProp, &dwRListPropSz); if (MD_ERROR_DATA_NOT_FOUND == hr) { // this is okay, we just need to create the property. hr = S_OK; dwRListPropSz = 0; } BAIL_ON_FAILURE(hr); if (!dwRListPropSz) { // create the property // size of the property = 1(0 or 1) + 1(comma) + len(file) + 1(comma) + 1(0 or 1) + // 1(comma) + len(GID) + 1(comma) + len(descr) + 2(double null MULTISZ) dwRListPropSz = 1 + (DWORD)wcslen(COMMA_STRING) + dwFileNameSz + (DWORD)wcslen(COMMA_STRING) + 1 + (DWORD)wcslen(COMMA_STRING) + dwGroupIDSz + (DWORD)wcslen(COMMA_STRING) + dwDescSz + 2; // No Leak // pwszRListProp never got alloced since we didn't get any value back, // so no need to delete first... pwszRListProp = new WCHAR[dwRListPropSz]; if (!pwszRListProp) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } if (bAccess) { wcscpy(pwszRListProp, ONE_STRING); } else { wcscpy(pwszRListProp, ZERO_STRING); } wcscat(pwszRListProp, COMMA_STRING); wcscat(pwszRListProp, bstrExtensionFile); wcscat(pwszRListProp, COMMA_STRING); if (bCanDelete) { wcscat(pwszRListProp, ONE_STRING); } else { wcscat(pwszRListProp, ZERO_STRING); } wcscat(pwszRListProp, COMMA_STRING); wcscat(pwszRListProp, bstrGroupID); wcscat(pwszRListProp, COMMA_STRING); wcscat(pwszRListProp, bstrDescription); // add the double null pwszRListProp[dwRListPropSz-1] = 0; pwszRListProp[dwRListPropSz-2] = 0; } else { // property already exists // copy the property pwszOrig = new WCHAR[dwRListPropSz]; pwszTopOrig = pwszOrig; if (!pwszOrig) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } memcpy(pwszOrig, pwszRListProp, dwRListPropSz * sizeof(WCHAR)); // resize the new property to the biggest possible if (pwszRListProp) { delete [] pwszRListProp; } // max new size is old size + new stuff // new stuff = 1(0 or 1) + 1(comma) + len(file) + 1(comma) + 1(0 or 1) + // 1(comma) + len(GID) + 1(comma) + len(descr) + 1(null) dwRListPropSz = dwRListPropSz + 1 + (DWORD)wcslen(COMMA_STRING) + dwFileNameSz + (DWORD)wcslen(COMMA_STRING) + 1 + (DWORD)wcslen(COMMA_STRING) + dwGroupIDSz + (DWORD)wcslen(COMMA_STRING) + dwDescSz + 1; pwszRListProp = new WCHAR[dwRListPropSz]; if (!pwszRListProp) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } WCHAR* pMidBuf = pwszRListProp; // copy the old list entries one by one while (pwszOrig[0]) { wcscpy(pMidBuf, pwszOrig); // skip over the #, pMidBuf += 1 + (DWORD)wcslen(COMMA_STRING); // check to see if the app already exists if ((!_wcsnicmp(bstrExtensionFile, pMidBuf, dwFileNameSz)) && ((pMidBuf[dwFileNameSz] == COMMA_CHAR) || (pMidBuf[dwFileNameSz] == NULL) ) ) { BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(ERROR_DUP_NAME)); } pwszOrig += (DWORD)wcslen(pwszOrig) + 1; // go to the next part of the multisz pMidBuf += (DWORD)wcslen(pMidBuf) + 1; // go past the null } // now copy the new file entry on if (bAccess) { wcscpy(pMidBuf, ONE_STRING); } else { wcscpy(pMidBuf, ZERO_STRING); } wcscat(pMidBuf, COMMA_STRING); wcscat(pMidBuf, bstrExtensionFile); wcscat(pMidBuf, COMMA_STRING); if (bCanDelete) { wcscat(pMidBuf, ONE_STRING); } else { wcscat(pMidBuf, ZERO_STRING); } wcscat(pMidBuf, COMMA_STRING); wcscat(pMidBuf, bstrGroupID); wcscat(pMidBuf, COMMA_STRING); wcscat(pMidBuf, bstrDescription); // add the last null pMidBuf += (DWORD)wcslen(pMidBuf) + 1; *pMidBuf = 0; } // set the new property value for property hr = SetMultiSZPropVal(wszPath, MD_WEB_SVC_EXT_RESTRICTION_LIST, pwszRListProp, dwRListPropSz); BAIL_ON_FAILURE(hr); done: if (pwszTopOrig) { delete [] pwszTopOrig; } if (pwszRListProp) { delete [] pwszRListProp; } return hr; } STDMETHODIMP CSecConLib::DeleteExtensionFileRecord( /* [in] */ LPCWSTR wszExFile, /* [in] */ LPCWSTR wszPath) { HRESULT hr = S_OK; WCHAR *pwszRListProp = NULL; WCHAR *pwszOrig = NULL; WCHAR *pTopOrig = NULL; DWORD dwRListPropSz = 0; DWORD dwFileNameSz = 0; bool bFound = false; // compute arg length dwFileNameSz = (DWORD)wcslen(wszExFile); hr = InternalInitIfNecessary(); if (FAILED(hr)) { BAIL_ON_FAILURE(hr); } // get the current property value for applicationdep list hr = GetMultiSZPropVal(wszPath, MD_WEB_SVC_EXT_RESTRICTION_LIST, &pwszRListProp, &dwRListPropSz); BAIL_ON_FAILURE(hr); // remove the application // copy the property pwszOrig = new WCHAR[dwRListPropSz]; pTopOrig = pwszOrig; if (!pwszOrig) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } memcpy(pwszOrig, pwszRListProp, dwRListPropSz * sizeof(WCHAR)); dwRListPropSz = 1; //reset size to contain one for the last null WCHAR* pMidBuf = pwszRListProp; // copy the old apps one by one while (pwszOrig[0]) { DWORD dwTokSz = (DWORD)wcslen(pwszOrig) + 1; // check to see if we're at the right file // look past the bool(1) + comma(sizof_comma_char) DWORD dwTemp = (DWORD)sizeof(COMMA_CHAR) / (DWORD)sizeof(WCHAR); if (!_wcsnicmp(wszExFile, &pwszOrig[1 + dwTemp], dwFileNameSz) && pwszOrig[dwFileNameSz + dwTemp + 1] == COMMA_CHAR) { bFound = true; // we don't want to do this... spec change in progress // check if this is deletable or not - if not, bail with an error //if (pwszOrig[dwFileNameSz + 1 + (2 * dwTemp)] == ZERO_CHAR) //{ // BAIL_ON_FAILURE(hr = E_FAIL); //} } else { // copy it in wcscpy(pMidBuf, pwszOrig); pMidBuf += dwTokSz; // advance past null *pMidBuf = 0; // add the last null dwRListPropSz += dwTokSz; } pwszOrig += dwTokSz; // go to the next part of the multisz } if (!bFound) { BAIL_ON_FAILURE(hr = MD_ERROR_DATA_NOT_FOUND); } // set the new property value for property if (dwRListPropSz < 3) { // handle deleting the last one hr = SetMultiSZPropVal(wszPath, MD_WEB_SVC_EXT_RESTRICTION_LIST, NULL, 0); } else { hr = SetMultiSZPropVal(wszPath, MD_WEB_SVC_EXT_RESTRICTION_LIST, pwszRListProp, dwRListPropSz); } BAIL_ON_FAILURE(hr); done: if (pTopOrig) { delete [] pTopOrig; } if (pwszRListProp) { delete [] pwszRListProp; } return hr; } STDMETHODIMP CSecConLib::ListExtensionFiles( /* [in] */ LPCWSTR wszPath, /* [out] */ WCHAR **pszBuffer, // MULTI_SZ - allocated in here, caller should delete /* [out] */ DWORD *pdwBufferSize) // length includes double null { WCHAR *pwszRListProp = NULL; DWORD dwRListPropSz = 0; WCHAR *pList = NULL; WCHAR *pTempList = NULL; DWORD dwListLen = 1; // one for the extra null at the end DWORD dwOldListLen = 1; HRESULT hr = S_OK; WCHAR *pTop = NULL; hr = InternalInitIfNecessary(); if (FAILED(hr)) { BAIL_ON_FAILURE(hr); } // get the current property value for applicationdep list hr = GetMultiSZPropVal(wszPath, MD_WEB_SVC_EXT_RESTRICTION_LIST, &pwszRListProp, &dwRListPropSz); BAIL_ON_FAILURE(hr); if (NULL == pwszRListProp) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } pTop = pwszRListProp; // iterate through the files while (pwszRListProp[0]) { pwszRListProp += 1 + ((DWORD)sizeof(COMMA_CHAR)/(DWORD)sizeof(WCHAR)); WCHAR* pMidBuf = wcschr(pwszRListProp, COMMA_CHAR); if (pMidBuf) { // null the comma and go past it *pMidBuf = 0; *pMidBuf++; // allocate the memory dwListLen += (DWORD)wcslen(pwszRListProp) + 1; // for the null pTempList = new WCHAR[dwListLen]; if (!pTempList) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } if (pList) { // copy the previous list memcpy(pTempList, pList, dwOldListLen * sizeof(WCHAR)); delete [] pList; } // copy on the file name wcscpy(&pTempList[dwOldListLen - 1], pwszRListProp); pTempList[dwListLen-1] = 0; pTempList[dwListLen-2] = 0; pList = pTempList; dwOldListLen = dwListLen; } else { pMidBuf = pwszRListProp + (DWORD)wcslen(pwszRListProp) + 1; } // now go to the next application pwszRListProp = pMidBuf + (DWORD)wcslen(pMidBuf) + 1; } if (!pList) { // make it a valid empty multisz dwListLen = 2; pList = new WCHAR[dwListLen]; if (!pList) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } wmemset(pList, 0, dwListLen); } *pszBuffer = pList; *pdwBufferSize = dwListLen; done: if (pTop) { delete [] pTop; } return hr; }