//Implementation of CAuthMethods class #include "stdafx.h" #include "Pop3Auth.h" #include "AuthMethodsEnum.h" #include #include #include #include #include CAuthMethods::CAuthMethods() { m_bIsInitialized=FALSE; m_lCurrentMethodIndex=-1; m_bstrServerName=NULL; m_lMachineRole=0; InitializeCriticalSection(&m_csVectorGuard); } CAuthMethods::~CAuthMethods() { CleanUp(); DeleteCriticalSection(&m_csVectorGuard); } STDMETHODIMP CAuthMethods::get_Count(LONG *pVal) { if(NULL == pVal) { return E_POINTER; } if(!m_bIsInitialized) { if(!Initialize()) { return E_FAIL; } } *pVal=m_Index.size(); return S_OK; } STDMETHODIMP CAuthMethods::get_Item(VARIANT vID, IAuthMethod **ppVal) { HRESULT hr=E_INVALIDARG; if(NULL == ppVal) { return E_POINTER; } if(! m_bIsInitialized) { if(!Initialize()) { return E_FAIL; } } if(VT_I4 == vID.vt) { vID.lVal--; // Collections should be 1-based if(vID.lVal>=0 && vID.lValpIAuthMethod ->QueryInterface(IID_IAuthMethod, (void **)ppVal); } } else if(VT_BSTR==vID.vt) { for(long i=0; i< m_Index.size(); i++) { if( 0==wcscmp(m_AuthVector[m_Index[i]]->bstrName, vID.bstrVal) ) { hr=m_AuthVector[m_Index[i]]->pIAuthMethod ->QueryInterface(IID_IAuthMethod, (void **)ppVal); break; } } } if(S_OK==hr) { VARIANT vServer; vServer.vt=VT_BSTR; vServer.bstrVal=m_bstrServerName; if(m_bstrServerName!=NULL) { hr = (*ppVal)->Put(SZ_SERVER_NAME, vServer); } } return hr; } STDMETHODIMP CAuthMethods::get__NewEnum(IEnumVARIANT **ppVal) { if(ppVal==NULL) { return E_POINTER; } HRESULT hr=S_OK; CComObject *pAuthEnum; *ppVal=NULL; if(!m_bIsInitialized) { if(!Initialize()) { return E_FAIL; } } hr = CComObject::CreateInstance(&pAuthEnum); // Reference count still 0 if(SUCCEEDED(hr)) { hr=pAuthEnum->Init(&m_AuthVector); if(SUCCEEDED(hr)) { hr=pAuthEnum->QueryInterface(IID_IEnumVARIANT,(void **)(ppVal) ); } if(FAILED(hr)) { delete(pAuthEnum); } } return hr; } STDMETHODIMP CAuthMethods::Add(BSTR bstrName, BSTR bstrGUID) { HRESULT hr=S_OK;; PAUTH_METHOD_INFO pAuthMethodInfo=NULL; if(NULL==bstrName || NULL==bstrGUID) { return E_INVALIDARG; } pAuthMethodInfo=new(AUTH_METHOD_INFO); if(pAuthMethodInfo == NULL) { return E_OUTOFMEMORY; } pAuthMethodInfo->bstrGuid=SysAllocString(bstrGUID); pAuthMethodInfo->bstrName=SysAllocString(bstrName); if( (NULL==pAuthMethodInfo->bstrGuid) ||(NULL==pAuthMethodInfo->bstrName)) { delete pAuthMethodInfo; hr=E_OUTOFMEMORY; } EnterCriticalSection(&m_csVectorGuard); m_AuthVector.push_back(pAuthMethodInfo); m_Index.push_back(m_AuthVector.size()-1); LeaveCriticalSection(&m_csVectorGuard); return hr; } STDMETHODIMP CAuthMethods::Remove(VARIANT vID) { HRESULT hr=E_INVALIDARG; AUTHINDEX::iterator itor=m_Index.begin(); if(!m_bIsInitialized) { if(!Initialize()) { return E_FAIL; } } if(m_Index.size()==1) { //Can not remove the last Auth method return E_FAIL; } if(VT_I4 == vID.vt) { vID.lVal--; // Collections should be 1-based if(vID.lVal>=0 && vID.lValbstrName, vID.bstrVal)) { itor+=i; m_Index.erase(itor); if(i==m_lCurrentMethodIndex) { m_lCurrentMethodIndex=0; } else if (ibstrGuid)+1; } if ( 0 != iBufferSize ) { iBufferSize++; pBuffer=(WCHAR *)malloc(iBufferSize*sizeof(WCHAR)); if(NULL != pBuffer) { pCurrent=pBuffer; for(i=0;ibstrGuid); pCurrent+=wcslen(m_AuthVector[i]->bstrGuid)+1; } *pCurrent=0; //Double NULL to terminate if( ERROR_SUCCESS== RegHKLMOpenKey( POP3SERVER_AUTH_SUBKEY, KEY_SET_VALUE, &hPop3Key, m_bstrServerName) ) { if(ERROR_SUCCESS == RegSetValueEx(hPop3Key, VALUENAME_AUTHMETHODS, NULL, REG_MULTI_SZ, (LPBYTE)pBuffer, iBufferSize*sizeof(WCHAR))) { if( ERROR_SUCCESS == RegSetValueEx(hPop3Key, VALUENAME_DEFAULTAUTH, NULL, REG_DWORD, (LPBYTE)&(m_Index[m_lCurrentMethodIndex]), sizeof(DWORD))) { // Need to restart the service (if the Auth method is being changed, which means # domains = 0 long lCount; CComPtr spIConfig; CComPtr spIDomains; hr = CoCreateInstance( __uuidof( P3Config ), NULL, CLSCTX_ALL, __uuidof( IP3Config ),reinterpret_cast( &spIConfig )); if ( S_OK == hr ) { hr = spIConfig->put_MachineName( m_bstrServerName ); if ( S_OK == hr) { hr = spIConfig->get_Domains( &spIDomains ); } } if( S_OK == hr ) { hr = spIDomains->get_Count( &lCount ); if ( S_OK == hr && 0 == lCount && _IsServiceRunning( POP3_SERVICE_NAME )) hr = _RestartService( POP3_SERVICE_NAME ); } } } RegCloseKey(hPop3Key); } free(pBuffer); } else //pBuffer == NULL { hr=E_OUTOFMEMORY; } } LeaveCriticalSection(&m_csVectorGuard); return hr; } STDMETHODIMP CAuthMethods::put_MachineName(BSTR newVal) { if(NULL!=m_bstrServerName) { SysFreeString(m_bstrServerName); m_bstrServerName=NULL; } if ( (NULL != newVal) && (0 < wcslen( newVal ))) { CleanUp(); m_bstrServerName=SysAllocString(newVal); if(NULL==m_bstrServerName) { return E_OUTOFMEMORY; } } // Actually verify we can get the current auth method of the remote machine. // This enforces that we can only administer remote AD machine's if we are in the same domain. HRESULT hr; VARIANT v; CComPtr spIAuthMethod; VariantInit( &v ); hr = get_CurrentAuthMethod( &v ); if ( S_OK == hr ) hr = get_Item( v, &spIAuthMethod ); if ( S_OK != hr ) CleanUp(); return hr; } STDMETHODIMP CAuthMethods::get_MachineName(BSTR *pVal) { if(NULL == pVal) { return E_POINTER; } if(NULL!=m_bstrServerName) { *pVal=SysAllocString(m_bstrServerName); if(NULL == *pVal) { return E_OUTOFMEMORY; } } else { *pVal=NULL; } return S_OK; } STDMETHODIMP CAuthMethods::get_CurrentAuthMethod(VARIANT *pVal) { if(NULL == pVal) { return E_POINTER; } if( !m_bIsInitialized) { if(!Initialize()) { return E_FAIL; } } if(pVal->vt != VT_EMPTY ) { return E_INVALIDARG; } if(m_lCurrentMethodIndex <0 ) { //The current authmethod is not valid return HRESULT_FROM_WIN32(ERROR_DS_AUTH_METHOD_NOT_SUPPORTED); } pVal->vt=VT_I4; pVal->lVal=m_lCurrentMethodIndex + 1; // Collections should be 1-based return S_OK; } STDMETHODIMP CAuthMethods::put_CurrentAuthMethod(VARIANT vID) { HRESULT hr=E_INVALIDARG; if(!m_bIsInitialized) { if(!Initialize()) { return E_FAIL; } } EnterCriticalSection(&m_csVectorGuard); if(VT_I4 == vID.vt) { vID.lVal--; // Collections should be 1-based if(vID.lVal>=0 && vID.lValbstrName, vID.bstrVal) ) { hr=VerifyCurrentAuthMethod(i); if(S_OK == hr) { m_lCurrentMethodIndex=i; } break; } } } LeaveCriticalSection(&m_csVectorGuard); return hr; } void CAuthMethods::CleanUp() { for(int i=0; i< m_AuthVector.size(); i++) { if(NULL != m_AuthVector[i]->pIAuthMethod) { m_AuthVector[i]->pIAuthMethod->Release(); } SysFreeString(m_AuthVector[i]->bstrGuid); SysFreeString(m_AuthVector[i]->bstrName); delete m_AuthVector[i]; } m_AuthVector.clear(); m_Index.clear(); if(NULL!=m_bstrServerName) { SysFreeString(m_bstrServerName); m_bstrServerName=NULL; } m_bIsInitialized=FALSE; } BOOL CAuthMethods::Initialize() { HKEY hPop3Key; BOOL bRtVal=FALSE; DWORD cbSize=sizeof(DWORD); DWORD dwType; LONG lErr; LONG lCurrentMethodIndex=0; WCHAR *wBuffer=NULL; EnterCriticalSection(&m_csVectorGuard); if( !m_bIsInitialized ) { SetMachineRole(); //Load data from the registry if( ERROR_SUCCESS==RegHKLMOpenKey( POP3SERVER_AUTH_SUBKEY, KEY_QUERY_VALUE, &hPop3Key, m_bstrServerName) ) { if(ERROR_SUCCESS== RegQueryValueEx(hPop3Key, VALUENAME_DEFAULTAUTH, NULL, &dwType, (LPBYTE)&(lCurrentMethodIndex), &cbSize)) { cbSize=0; if(ERROR_SUCCESS== RegQueryValueEx(hPop3Key, VALUENAME_AUTHMETHODS, NULL, &dwType, NULL, &cbSize)) { wBuffer=(WCHAR *)malloc(cbSize); if(NULL!=wBuffer) { ZeroMemory(wBuffer, cbSize); if(ERROR_SUCCESS== RegQueryValueEx(hPop3Key, VALUENAME_AUTHMETHODS, NULL, &dwType, (LPBYTE)wBuffer, &cbSize)) { if(PopulateAuthMethods(wBuffer, cbSize)) { for(int i=0;ibstrGuid=SysAllocString(pStart); if(NULL == pAuthInfo->bstrGuid) { bRetVal=FALSE; break; } if(S_OK != CreateObj(pAuthInfo, &(pAuthInfo->pIAuthMethod))) { bRetVal=FALSE; break; } if(S_OK != pAuthInfo->pIAuthMethod->get_Name(&(pAuthInfo->bstrName)) ) { bRetVal=FALSE; break; } m_AuthVector.push_back(pAuthInfo); if(SUCCEEDED(VerifyAuthMethod(pAuthInfo->bstrGuid))) { //Only show valid auth methods m_Index.push_back(m_AuthVector.size()-1); pAuthInfo->bIsValid=TRUE; } else { pAuthInfo->bIsValid=FALSE; } pStart=pEnd+1; pEnd=pStart+wcslen(pStart); } if(!bRetVal) { if(NULL !=pAuthInfo) { if(NULL!=pAuthInfo->pIAuthMethod) { pAuthInfo->pIAuthMethod->Release(); } SysFreeString(pAuthInfo->bstrGuid); SysFreeString(pAuthInfo->bstrName); delete pAuthInfo; } CleanUp(); } return bRetVal; } HRESULT CAuthMethods::CreateObj(PAUTH_METHOD_INFO pAuthInfo, IAuthMethod **ppVal) { HRESULT hr=S_OK; UUID uuid; if( ( NULL == pAuthInfo ) || ( NULL == ppVal ) ) { return E_POINTER; } if(pAuthInfo->bstrGuid == NULL) { return E_INVALIDARG; } if(RPC_S_OK != UuidFromString(pAuthInfo->bstrGuid, &uuid)) { return E_INVALIDARG; } hr=CoCreateInstance(uuid, NULL, CLSCTX_INPROC_SERVER, IID_IAuthMethod, (LPVOID *)ppVal); return hr; } //The index here is the relative index exposed through public interface STDMETHODIMP CAuthMethods::VerifyCurrentAuthMethod(int iIndex) { HRESULT hr=E_FAIL; long lCount=0; if(! m_bIsInitialized) { if(!Initialize()) { return E_FAIL; } } if( iIndex < 0 ) { if(m_lCurrentMethodIndex < 0 ) { return HRESULT_FROM_WIN32(ERROR_DS_AUTH_METHOD_NOT_SUPPORTED); } iIndex=m_lCurrentMethodIndex; } if( (NO_DOMAIN==m_lMachineRole) && (0==_wcsicmp(m_AuthVector[m_Index[iIndex]]->bstrGuid, SZ_AUTH_ID_DOMAIN_AD)) ) { return E_INVALIDARG; } if( (DOMAIN_CONTROLLER==m_lMachineRole) && (0==_wcsicmp(m_AuthVector[m_Index[iIndex]]->bstrGuid, SZ_AUTH_ID_LOCAL_SAM)) ) { return E_INVALIDARG; } if( 0 ==_wcsicmp(m_AuthVector[m_Index[iIndex]]->bstrGuid, SZ_AUTH_ID_MD5_HASH) ) { // Set the SPA required reg key to 0 RegSetSPARequired(0); //Don't care if the key does not exist } if( iIndex != m_lCurrentMethodIndex) { // Can not change Auth Method if there is a email domain CComPtr spIConfig; CComPtr spIDomains; hr = CoCreateInstance( __uuidof( P3Config ), NULL, CLSCTX_ALL, __uuidof( IP3Config ),reinterpret_cast( &spIConfig )); if( S_OK == hr ) { hr = spIConfig->put_MachineName( m_bstrServerName ); if( S_OK== hr) { hr = spIConfig->get_Domains( &spIDomains ); } } if( S_OK == hr ) { hr = spIDomains->get_Count( &lCount ); if ( S_OK == hr ) { if(0==lCount) { return S_OK; } } } return STG_E_ACCESSDENIED; } return S_OK; } HRESULT CAuthMethods::SetMachineRole() { DSROLE_PRIMARY_DOMAIN_INFO_BASIC *pMachineRole=NULL; //Check the Role of the machine if( ERROR_SUCCESS== DsRoleGetPrimaryDomainInformation( m_bstrServerName, DsRolePrimaryDomainInfoBasic, (PBYTE *)(&pMachineRole)) ) { switch(pMachineRole->MachineRole) { case DsRole_RoleStandaloneWorkstation: case DsRole_RoleStandaloneServer: m_lMachineRole=NO_DOMAIN; break; case DsRole_RoleMemberWorkstation: case DsRole_RoleMemberServer:m_lMachineRole=DOMAIN_NONE_DC; break; case DsRole_RoleBackupDomainController: case DsRole_RolePrimaryDomainController:m_lMachineRole=DOMAIN_CONTROLLER; break; } DsRoleFreeMemory(pMachineRole); pMachineRole=NULL; return S_OK; } return E_FAIL; } HRESULT CAuthMethods::VerifyAuthMethod(BSTR bstrGuid) { if(bstrGuid == NULL) { return E_POINTER; } if( (NO_DOMAIN==m_lMachineRole) && (0==_wcsicmp(bstrGuid, SZ_AUTH_ID_DOMAIN_AD)) ) { return E_FAIL; } if( (DOMAIN_CONTROLLER==m_lMachineRole) && (0==_wcsicmp(bstrGuid, SZ_AUTH_ID_LOCAL_SAM)) ) { return E_FAIL; } return S_OK; }