// P3AdminWorker.cpp: implementation of the CP3AdminWorker class. // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "P3AdminWorker.h" #include "P3Admin.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DOMAINMUTEX_NAME L"Global\\P3AdminWorkerDomain-" #define USERMUTEX_NAME L"Global\\P3AdminWorkerUser-" #define ERROR_NO_FILE_ATTR 0xffffffff DWORD SetMailBoxDACL(LPWSTR wszPath,PSECURITY_DESCRIPTOR pSD, DWORD dwLevel) { HANDLE hFind; DWORD dwLastErr; WIN32_FIND_DATA FileInfo; WCHAR wszMailFilter[POP3_MAX_PATH+6]; WCHAR wszFullPathFileName[POP3_MAX_PATH]; DWORD dwRt=ERROR_SUCCESS; if(NULL == wszPath || NULL == pSD) { return ERROR_INVALID_DATA; } //Now set everything in the directory wsprintf(wszMailFilter, L"%s\\*.*", wszPath); hFind=FindFirstFile(wszMailFilter, &(FileInfo)); if(INVALID_HANDLE_VALUE == hFind) { dwLastErr= GetLastError(); if(ERROR_FILE_NOT_FOUND == dwLastErr || ERROR_SUCCESS == dwLastErr) { return ERROR_SUCCESS; } else { return dwLastErr; } } BOOL bMoreFile=TRUE; while(bMoreFile) { if(wcscmp(FileInfo.cFileName, L".")!=0 && wcscmp(FileInfo.cFileName, L"..")!=0) { wnsprintf(wszFullPathFileName,sizeof(wszFullPathFileName)/sizeof(WCHAR),L"%s\\%s", wszPath, FileInfo.cFileName); wszFullPathFileName[sizeof(wszFullPathFileName)/sizeof(WCHAR)-1]=0; if(!SetFileSecurity(wszFullPathFileName, DACL_SECURITY_INFORMATION, pSD)) { dwRt=GetLastError(); } if( (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) && (ERROR_SUCCESS ==dwRt) && (dwLevel > 0) ) { //We need to go down the dir dwRt=SetMailBoxDACL(wszFullPathFileName, pSD, dwLevel-1); } if( ERROR_SUCCESS != dwRt) { break; } } bMoreFile=FindNextFile(hFind,&FileInfo); } FindClose(hFind); return dwRt; } ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// CP3AdminWorker::CP3AdminWorker() : m_psMachineName(NULL), m_psMachineMailRoot(NULL), m_bImpersonation(false), m_isPOP3Installed(true) { // TODO: dougb this is temporary code to force AD to cache for us, should be removed WCHAR sBuffer[MAX_PATH*2]; HRESULT hr = GetSMTPDomainPath( sBuffer, L"", MAX_PATH*2 ); if ( S_OK == hr ) { sBuffer[ wcslen( sBuffer ) - 1 ] = 0; //Remove the last / hr = ADsGetObject( sBuffer, IID_IADs, reinterpret_cast( &m_spTemporaryFixIADs )); } DWORD dwVersion; if (( ERROR_SUCCESS == RegQueryVersion( dwVersion, NULL )) && ( 0 == dwVersion )) m_isPOP3Installed = false; } CP3AdminWorker::~CP3AdminWorker() { if ( NULL != m_psMachineName ) delete m_psMachineName; if ( NULL != m_psMachineMailRoot ) delete m_psMachineMailRoot; } ////////////////////////////////////////////////////////////////////// // Implementation, public ////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// // AddDomain, public // // Purpose: // Set the Meta base options required to add a new Local domain to the SMTP service. // Add the domain to our Store. // This involves: // Create a new object of type IIsSmtpDomain // Setting the RouteAction Property to 16 // Creating a directory in the mailroot. // // Arguments: // LPWSTR psDomainName : Domain name to add // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::AddDomain( LPWSTR psDomainName ) { if ( NULL == psDomainName ) return E_INVALIDARG; HRESULT hr, hr2 = S_OK; // Valid Domain Name? || DNS_ERROR_NON_RFC_NAME == dnStatus DNS_STATUS dnStatus = DnsValidateName_W( psDomainName, DnsNameDomain ); hr = ( ERROR_SUCCESS == dnStatus ) ? S_OK : HRESULT_FROM_WIN32( ERROR_INVALID_DOMAINNAME ); // Also need to block domain names with a trailing . if ( S_OK == hr ) { if ( L'.' == *(psDomainName + wcslen( psDomainName ) - 1) ) hr = HRESULT_FROM_WIN32( ERROR_INVALID_DOMAINNAME ); } // Do we need to add this Domain? // Validate the domain in SMTP if ( S_OK == hr ) hr = ExistsSMTPDomain( psDomainName ); if ( S_OK == hr ) hr = HRESULT_FROM_WIN32( ERROR_DOMAIN_EXISTS ); else if ( HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ) == hr ) hr = S_OK; // Validate the domain in the Store if ( S_OK == hr ) hr = ExistsStoreDomain( psDomainName ); if ( S_OK == hr ) hr2 = ERROR_FILE_EXISTS; else if ( HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ) == hr ) hr = S_OK; if ( S_OK == hr ) { hr = AddSMTPDomain( psDomainName ); if ( S_OK == hr && ERROR_FILE_EXISTS != hr2 ) { hr = AddStoreDomain( psDomainName ); if ( S_OK != hr ) RemoveSMTPDomain( psDomainName ); } } return ( S_OK == hr ) ? hr2 : hr; } ///////////////////////////////////////////////////////////////////////////// // AddUser, public // // Purpose: // Create a new user mailbox. // This involves: // Verify the domain exists. // Create the mailbox directory and lock file. // // Arguments: // LPWSTR psDomainName : Domain name to add to // LPWSTR psUserName : User name to add // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::AddUser( LPWSTR psDomainName, LPWSTR psUserName ) { // psDomainName - checked by ValidateDomain // psBuffer - checked by BuildEmailAddrW2A HRESULT hr = S_OK; CMailBox mailboxX; WCHAR sEmailAddr[POP3_MAX_ADDRESS_LENGTH]; bool bLocked; // Validate the domain if ( S_OK == hr ) hr = ValidateDomain( psDomainName ); // Validate the user if ( S_OK == hr ) { if ( !isValidMailboxName( psUserName )) hr = HRESULT_FROM_WIN32( ERROR_BAD_USERNAME ); } if ( S_OK == hr ) bLocked = IsDomainLocked( psDomainName ); if ( SUCCEEDED( hr )) { // See if the mailbox already exists hr = BuildEmailAddr( psDomainName, psUserName, sEmailAddr, sizeof( sEmailAddr ) / sizeof (WCHAR) ); if ( S_OK == hr ) hr = MailboxSetRemote(); if ( S_OK == hr ) { // Do we need to enforce uniqueness across domains? CComPtr spIAuthMethod; BSTR bstrAuthType = NULL; hr = GetCurrentAuthentication( &spIAuthMethod ); if ( S_OK == hr ) hr = spIAuthMethod->get_ID( &bstrAuthType ); if ( S_OK == hr ) { if ( 0 == _wcsicmp( bstrAuthType, SZ_AUTH_ID_LOCAL_SAM ) ) { hr = SearchDomainsForMailbox( psUserName, NULL ); if ( S_OK == hr ) // The Mailbox exists in at least one domain { if ( mailboxX.OpenMailBox( sEmailAddr )) { mailboxX.CloseMailBox(); hr = HRESULT_FROM_WIN32( ERROR_FILE_EXISTS ); } else hr = HRESULT_FROM_WIN32( ERROR_USER_EXISTS ); } else if ( HRESULT_FROM_WIN32( ERROR_NO_SUCH_USER ) == hr ) // This is what we were hoping for hr = S_OK; } SysFreeString( bstrAuthType ); } } if ( S_OK == hr ) { if ( mailboxX.OpenMailBox( sEmailAddr )) { mailboxX.CloseMailBox(); hr = HRESULT_FROM_WIN32( ERROR_FILE_EXISTS ); } else { LPWSTR psMachineName = NULL; if ( !mailboxX.CreateMailBox( sEmailAddr )) hr = E_FAIL; if ( S_OK == hr && bLocked ) LockUser( psDomainName, psUserName ); // Hate to fail because of problem here, therefore ignore return code } } MailboxResetRemote(); } return hr; } ///////////////////////////////////////////////////////////////////////////// // ControlService, public // // Purpose: // Ask the Service Control Manager to send a cotnrol code to the service. // // Arguments: // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::ControlService( LPWSTR psService, DWORD dwControl ) { if ( NULL == psService ) return E_INVALIDARG; if ( 0 == _wcsicmp( POP3_SERVICE_NAME, psService ) || 0 == _wcsicmp( SMTP_SERVICE_NAME_W, psService ) || 0 == _wcsicmp( IISADMIN_SERVICE_NAME, psService ) || 0 == _wcsicmp( W3_SERVICE_NAME, psService ) ) return _ControlService( psService, dwControl, m_psMachineName ); else return E_INVALIDARG; } ///////////////////////////////////////////////////////////////////////////// // CreateQuotaSIDFile, public // // Purpose: // Create the Quota file for the mailbox. // A permanent quota file is created which contains the SID of the user and is used // by the SMTP service to assign ownership of new mail files. // // Arguments: // LPWSTR psDomainName : domain of mailbox // LPWSTR psMailboxName : mailbox // PSID *ppSIDOwner : Pointer to buffer to receive Owner SID (must be deleted by caller) // LPWSTR psMachineName : system name (remote computer) can be NULL // LPWSTR psUserName : user name // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::CreateQuotaSIDFile( LPWSTR psDomainName, LPWSTR psMailboxName, BSTR bstrAuthType, LPWSTR psMachineName, LPWSTR psUserName ) { // psDomainName - checked by BuildUserPath // psUserName - checked by BuildUserPath // bstrAuthType - checked by GetSID if ( NULL == psMachineName ) psMachineName = m_psMachineName; HRESULT hr = S_OK; WCHAR sQuotaFile[POP3_MAX_PATH]; HANDLE hQuotaFile; hr = BuildUserPath( psDomainName, psMailboxName, sQuotaFile, sizeof( sQuotaFile )/sizeof(WCHAR) ); if ( S_OK == hr ) { if ( (sizeof( sQuotaFile )/sizeof(WCHAR)) > ( wcslen( sQuotaFile ) + wcslen( QUOTA_FILENAME_W ) + 1 )) { wcscat( sQuotaFile, L"\\" ); wcscat( sQuotaFile, QUOTA_FILENAME_W ); hQuotaFile = CreateFile( sQuotaFile, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); if ( INVALID_HANDLE_VALUE != hQuotaFile ) { PSID pSIDOwner = NULL; DWORD dwOwnerSID, dwBytesWritten; hr = GetQuotaSID( bstrAuthType, psUserName, psMachineName, &pSIDOwner, &dwOwnerSID ); if ( S_OK == hr ) { if ( !WriteFile( hQuotaFile, pSIDOwner, dwOwnerSID, &dwBytesWritten, NULL )) hr = HRESULT_FROM_WIN32(GetLastError()); delete [] pSIDOwner; } CloseHandle( hQuotaFile ); if ( S_OK != hr ) DeleteFile( sQuotaFile ); } else hr = HRESULT_FROM_WIN32(GetLastError()); } else hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW); } return hr; } ///////////////////////////////////////////////////////////////////////////// // GetConfirmAddUser, public // // Purpose: // Get the Confirm Add User registry key. // // Arguments: // BOOL *pbConfirm : current value // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::GetConfirmAddUser( BOOL *pbConfirm ) { if ( NULL == pbConfirm ) return E_INVALIDARG; DWORD dwValue; long lRC = RegQueryConfirmAddUser( dwValue, m_psMachineName ); if ( ERROR_SUCCESS == lRC ) { *pbConfirm = (dwValue) ? TRUE : FALSE; return S_OK; } return HRESULT_FROM_WIN32( lRC ); } ///////////////////////////////////////////////////////////////////////////// // GetAuthenticationMethods, public // // Purpose: // Get an initialized IAuthMethods interface pointer // // Arguments: // IAuthMethods* *ppIAuthMethods: return interface pointer to initialized IAuthMethods // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::GetAuthenticationMethods( IAuthMethods* *ppIAuthMethods ) const { if ( NULL == ppIAuthMethods ) return E_INVALIDARG; HRESULT hr; hr = CoCreateInstance( __uuidof( AuthMethods ), NULL, CLSCTX_INPROC_SERVER, __uuidof( IAuthMethods ), reinterpret_cast( ppIAuthMethods )); if ( S_OK == hr ) { // If necessary set the machine name property if ( NULL != m_psMachineName ) { _bstr_t _bstrMachineName = m_psMachineName; hr = (*ppIAuthMethods)->put_MachineName( _bstrMachineName ); } } assert( S_OK == hr ); return hr; } ///////////////////////////////////////////////////////////////////////////// // GetCurrentAuthentication, public // // Purpose: // Get an initialized IAuthMethod interface pointer for the current active Authentication method // // Arguments: // IAuthMethod* *ppIAuthMethod: return interface pointer to initialized IAuthMethod // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::GetCurrentAuthentication( IAuthMethod* *ppIAuthMethod ) const { if ( NULL == ppIAuthMethod ) return E_INVALIDARG; HRESULT hr; CComPtr spIAuthMethods; _variant_t _v; hr = GetAuthenticationMethods( &spIAuthMethods ); if ( S_OK == hr ) hr = spIAuthMethods->get_CurrentAuthMethod( &_v ); if ( S_OK == hr ) hr = spIAuthMethods->get_Item( _v, ppIAuthMethod ); return hr; } ///////////////////////////////////////////////////////////////////////////// // GetDomainCount, public // // Purpose: // Get an Enumerator for the SMTP domains in the Metabase // // Arguments: // int *piCount : domain count // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::GetDomainCount( ULONG *piCount) { if ( NULL == piCount ) return E_INVALIDARG; HRESULT hr = S_OK; HANDLE hfSearch; WCHAR sBuffer[POP3_MAX_PATH]; WIN32_FIND_DATA stFindFileData; _bstr_t _bstr; *piCount = 0; hr = GetMailroot( sBuffer, sizeof( sBuffer )/sizeof(WCHAR)); // Directory Search if ( S_OK == hr ) { if ( ( wcslen( sBuffer ) + 2 ) < sizeof( sBuffer )/sizeof(WCHAR)) { wcscat( sBuffer, L"\\*" ); hfSearch = FindFirstFileEx( sBuffer, FindExInfoStandard, &stFindFileData, FindExSearchLimitToDirectories, NULL, 0 ); if ( INVALID_HANDLE_VALUE == hfSearch ) hr = HRESULT_FROM_WIN32(GetLastError()); while ( S_OK == hr ) { // Count directories if ( FILE_ATTRIBUTE_DIRECTORY == ( FILE_ATTRIBUTE_DIRECTORY & stFindFileData.dwFileAttributes )) { _bstr = stFindFileData.cFileName; if ( S_OK == ExistsSMTPDomain( _bstr )) (*piCount) += 1; } if ( !FindNextFile( hfSearch, &stFindFileData )) hr = HRESULT_FROM_WIN32(GetLastError()); } if ( HRESULT_FROM_WIN32(ERROR_NO_MORE_FILES) == hr || HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr ) hr = S_OK; if(INVALID_HANDLE_VALUE!=hfSearch) { FindClose(hfSearch); hfSearch=INVALID_HANDLE_VALUE; } } else hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); } return hr; } ///////////////////////////////////////////////////////////////////////////// // GetNewEnum, public // // Purpose: // Get an Enumerator for the SMTP domains in the Metabase // // Arguments: // IEnumVARIANT **pp : the returned Enumerator object // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::GetDomainEnum( IEnumVARIANT **pp ) { if ( NULL == pp ) return E_POINTER; HRESULT hr = E_FAIL; WCHAR sBuffer[POP3_MAX_PATH]; _variant_t _v; CComPtr spIADsContainer; CComPtr spIUnk; *pp = NULL; hr = GetSMTPDomainPath( sBuffer, NULL, sizeof( sBuffer )/sizeof( WCHAR )); if ( S_OK == hr ) hr = ADsGetObject( sBuffer, IID_IADsContainer, reinterpret_cast( &spIADsContainer )); if SUCCEEDED( hr ) hr = spIADsContainer->get__NewEnum( &spIUnk ); if SUCCEEDED( hr ) hr = spIUnk->QueryInterface( IID_IEnumVARIANT, reinterpret_cast( pp )); return hr; } ///////////////////////////////////////////////////////////////////////////// // GetDomainLock, public // // Purpose: // Determine if the domain is locked. // // Arguments: // LPWSTR psDomainName : Domain name to check lock // BOOL *pisLocked : return value // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::GetDomainLock( LPWSTR psDomainName, BOOL *pisLocked ) { // psDomainName - checked by CreateDomainMutex if ( NULL == pisLocked ) return E_INVALIDARG; HRESULT hr = S_OK; HANDLE hMutex = NULL; // Create a Mutex Name for this domain to ensure we are the only one accessing it. hr = CreateDomainMutex( psDomainName, &hMutex ); // Validate if ( S_OK == hr ) { hr = ValidateDomain( psDomainName ); } // Lock all the Mailboxes if ( S_OK == hr ) *pisLocked = IsDomainLocked( psDomainName ) ? TRUE : FALSE; // Cleanup if ( NULL != hMutex ) CloseHandle( hMutex ); return hr; } ///////////////////////////////////////////////////////////////////////////// // GetQuotaSID, public // // Purpose: // Create the Quota file for the mailbox. // A permanent quota file is created which contains the SID of the user and is used // by the SMTP service to assign ownership of new mail files. // // Arguments: // BSTR bstrAuthType : Authentication type // LPWSTR psUserName : user to lock // LPWSTR psMachineName : system name (remote computer) can be NULL // PSID *ppSIDOwner : Pointer to buffer to receive Owner SID (must be deleted by caller) // LPDWORD pdwOwnerSID : Pointer to variable thate receives the size of the Owner SID // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::GetQuotaSID( BSTR bstrAuthType, LPWSTR psUserName, LPWSTR psMachineName, PSID *ppSIDOwner, LPDWORD pdwOwnerSID ) { if ( NULL == bstrAuthType || NULL == psUserName || NULL == ppSIDOwner || NULL == pdwOwnerSID ) return E_INVALIDARG; if ( 0 != _wcsicmp( SZ_AUTH_ID_LOCAL_SAM, bstrAuthType ) && 0 != _wcsicmp( SZ_AUTH_ID_DOMAIN_AD, bstrAuthType ) && 0 != _wcsicmp( SZ_AUTH_ID_MD5_HASH, bstrAuthType )) return E_INVALIDARG; // psMachineName == NULL is valid! HRESULT hr = S_OK; DWORD dwDomSize = 0, dwSize = 0; BOOL bRC; LPWSTR psDomainName = NULL; LPWSTR psAccountName = NULL; PSID pSIDOwner = NULL; SID_NAME_USE sidNameUse; *pdwOwnerSID = 0; *ppSIDOwner = NULL; if ( 0 == _wcsicmp( SZ_AUTH_ID_DOMAIN_AD, bstrAuthType )) { // UPN name or SAM name? if ( NULL == wcsrchr( psUserName, L'@' )) { // SAM name NET_API_STATUS netStatus; LPWSTR psNameBuffer; NETSETUP_JOIN_STATUS enumJoinStatus; netStatus = NetGetJoinInformation( psMachineName, &psNameBuffer, &enumJoinStatus ); if ( NERR_Success == netStatus ) { psAccountName = new WCHAR[ wcslen( psUserName ) + wcslen( psNameBuffer ) + 3 ]; if ( NULL != psAccountName ) wsprintf( psAccountName, L"%s\\%s", psNameBuffer, psUserName ); else hr = E_OUTOFMEMORY; NetApiBufferFree( psNameBuffer ); } else hr = E_OUTOFMEMORY; } else { // UPN name psAccountName = new WCHAR[ wcslen( psUserName ) + 1 ]; if ( NULL != psAccountName ) wcscpy( psAccountName, psUserName ); else hr = E_OUTOFMEMORY; } } if ( 0 == _wcsicmp( SZ_AUTH_ID_LOCAL_SAM, bstrAuthType )) { if ( NULL != psMachineName ) { psAccountName = new WCHAR[ wcslen( psUserName ) + wcslen( psMachineName ) + 3 ]; if ( NULL != psAccountName ) wsprintf( psAccountName, L"%s\\%s", psMachineName, psUserName ); else hr = E_OUTOFMEMORY; } else { WCHAR sMachineName[MAX_COMPUTERNAME_LENGTH+1]; DWORD dwSize = sizeof(sMachineName)/sizeof(WCHAR); if ( !GetComputerName( sMachineName, &dwSize )) hr = HRESULT_FROM_WIN32( GetLastError()); if ( S_OK == hr ) { psAccountName = new WCHAR[ wcslen( psUserName ) + wcslen( sMachineName ) + 3 ]; if ( NULL != psAccountName ) wsprintf( psAccountName, L"%s\\%s", sMachineName, psUserName ); else hr = E_OUTOFMEMORY; } } } if ( 0 == _wcsicmp( SZ_AUTH_ID_MD5_HASH, bstrAuthType )) psAccountName = psUserName; if ( S_OK == hr ) { bRC = LookupAccountNameW( psMachineName, psAccountName, NULL, pdwOwnerSID, NULL, &dwDomSize, &sidNameUse ); if ( !bRC && ( ERROR_INSUFFICIENT_BUFFER == GetLastError()) && (0 < *pdwOwnerSID) && (0 < dwDomSize) ) { SetLastError( ERROR_OUTOFMEMORY ); pSIDOwner = new BYTE[*pdwOwnerSID]; if ( NULL != pSIDOwner ) { psDomainName = new WCHAR[dwDomSize]; if ( NULL != psDomainName ) { if ( LookupAccountNameW( psMachineName, psAccountName, pSIDOwner, pdwOwnerSID, psDomainName, &dwDomSize, &sidNameUse )) { *ppSIDOwner = pSIDOwner; SetLastError( ERROR_SUCCESS ); } delete [] psDomainName; } if ( ERROR_SUCCESS != GetLastError() ) delete [] pSIDOwner; } } if ( ERROR_SUCCESS != GetLastError()) hr = HRESULT_FROM_WIN32(GetLastError()); } if ( NULL != psAccountName && 0 != _wcsicmp( SZ_AUTH_ID_MD5_HASH, bstrAuthType )) delete [] psAccountName; return hr; } ///////////////////////////////////////////////////////////////////////////// // EnablePOP3SVC, public // // Purpose: // Make sure the POP3SVC is Running and startup set to Automatic. // // Arguments: // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::EnablePOP3SVC() { HRESULT hr = _ChangeServiceStartType( POP3_SERVICE_NAME, SERVICE_AUTO_START ); if ( S_OK == hr ) hr = _StartService( POP3_SERVICE_NAME ); return hr; } ///////////////////////////////////////////////////////////////////////////// // GetLoggingLevel, public // // Purpose: // Get Logging Level registry key. // // Arguments: // long *plLoggingLevel : return value // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::GetLoggingLevel( long *plLoggingLevel ) { if ( NULL == plLoggingLevel ) return E_INVALIDARG; HRESULT hr = S_OK; DWORD dwLogLevel; long lRC; lRC = RegQueryLoggingLevel( dwLogLevel, m_psMachineName ); if ( ERROR_SUCCESS == lRC ) *plLoggingLevel = dwLogLevel; else hr = HRESULT_FROM_WIN32( lRC ); return hr; } ///////////////////////////////////////////////////////////////////////////// // GetMachineName, public // // Purpose: // Get the Machine Name that all operations should be performed on.. // // Arguments: // LPWSTR psMachineName : buffer // DWORD dwSize : buffer size // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::GetMachineName( LPWSTR psMachineName, DWORD dwSize ) { if ( NULL == psMachineName ) return E_INVALIDARG; HRESULT hr = S_OK; if ( NULL == m_psMachineName ) ZeroMemory( psMachineName, dwSize * sizeof( WCHAR )); else { if ( dwSize > wcslen( m_psMachineName )) wcscpy( psMachineName, m_psMachineName ); else hr = TYPE_E_BUFFERTOOSMALL; } return hr; } ///////////////////////////////////////////////////////////////////////////// // GetMailroot, public // // Purpose: // Get Mailroot registry key. // // Arguments: // LPWSTR psMailRoot : buffer // DWORD dwSize : buffer size // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::GetMailroot( LPWSTR psMailRoot, DWORD dwSize, bool bUNC /*= true*/ ) { if ( NULL == psMailRoot ) return E_INVALIDARG; long lRC; lRC = RegQueryMailRoot( psMailRoot, dwSize, m_psMachineName ); if ( ERROR_SUCCESS == lRC && NULL != m_psMachineName && true == bUNC ) { // Replace drive: with drive$ if ( L':' == psMailRoot[1] ) { psMailRoot[1] = L'$'; if ( dwSize > (wcslen( psMailRoot ) + wcslen( m_psMachineName ) + 3) ) { LPWSTR psBuffer = new WCHAR[wcslen(psMailRoot)+1]; if ( NULL != psBuffer ) { wcscpy( psBuffer, psMailRoot ); wcscpy( psMailRoot, L"\\\\" ); wcscat( psMailRoot, m_psMachineName ); wcscat( psMailRoot, L"\\" ); wcscat( psMailRoot, psBuffer ); delete [] psBuffer; } else lRC = ERROR_OUTOFMEMORY; } else lRC = ERROR_INSUFFICIENT_BUFFER; } //else dougb commented out because this breaks UNC paths when administering remote machines! // lRC = ERROR_INVALID_DATA; } if ( ERROR_SUCCESS == lRC ) return S_OK; return HRESULT_FROM_WIN32( lRC ); } HRESULT CP3AdminWorker::GetNextUser( HANDLE& hfSearch, LPCWSTR psDomainName, LPWSTR psBuffer, DWORD dwBufferSize ) { if ( NULL == psDomainName ) return E_INVALIDARG; if ( NULL == psBuffer ) return E_INVALIDARG; HRESULT hr = S_OK; bool bFound = false; WCHAR sBuffer[POP3_MAX_ADDRESS_LENGTH]; _bstr_t _bstr; LPWSTR ps; CMailBox mailboxX; WIN32_FIND_DATA stFindFileData; hr = MailboxSetRemote(); if ( S_OK == hr ) { if ( !FindNextFile( hfSearch, &stFindFileData )) hr = HRESULT_FROM_WIN32(GetLastError()); } while ( S_OK == hr && !bFound ) { // Count directories if ( FILE_ATTRIBUTE_DIRECTORY == ( FILE_ATTRIBUTE_DIRECTORY & stFindFileData.dwFileAttributes )) { ps = mailboxX.GetMailboxFromStoreNameW( stFindFileData.cFileName ); if ( NULL != ps ) { _bstr = ps; _bstr += L"@"; _bstr += psDomainName; if ( mailboxX.OpenMailBox( _bstr )) { if ( dwBufferSize > wcslen( ps )) { wcscpy( psBuffer, ps ); bFound = true; mailboxX.CloseMailBox(); } } } } if ( !bFound ) { if ( !FindNextFile( hfSearch, &stFindFileData )) hr = HRESULT_FROM_WIN32(GetLastError()); } } MailboxResetRemote(); if ( HRESULT_FROM_WIN32(ERROR_NO_MORE_FILES) == hr ) { hr = S_FALSE; FindClose( hfSearch ); hfSearch = INVALID_HANDLE_VALUE; } return hr; } ///////////////////////////////////////////////////////////////////////////// // GetPort, public // // Purpose: // Get the Port registry key. // // Arguments: // long* plPort : current value // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::GetPort( long *plPort ) { if ( NULL == plPort ) return E_INVALIDARG; DWORD dwValue; long lRC = RegQueryPort( dwValue, m_psMachineName ); if ( ERROR_SUCCESS == lRC ) { *plPort = dwValue; return S_OK; } return HRESULT_FROM_WIN32( lRC ); } ///////////////////////////////////////////////////////////////////////////// // GetServiceStatus, public // // Purpose: // Get the service status from the Service Control Manager. // // Arguments: // long* plStatus : the status // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::GetServiceStatus( LPWSTR psService, LPDWORD plStatus ) { if ( NULL == plStatus ) return E_INVALIDARG; if ( NULL == psService ) return E_INVALIDARG; HRESULT hr = E_FAIL; if ( 0 == _wcsicmp( POP3_SERVICE_NAME, psService ) || 0 == _wcsicmp( SMTP_SERVICE_NAME_W, psService ) || 0 == _wcsicmp( IISADMIN_SERVICE_NAME, psService ) || 0 == _wcsicmp( W3_SERVICE_NAME, psService ) ) { *plStatus = _GetServiceStatus( psService, m_psMachineName ); if ( 0 != *plStatus ) hr = S_OK; } else hr = E_INVALIDARG; return hr; } ///////////////////////////////////////////////////////////////////////////// // GetSocketBacklog, public // // Purpose: // Get the Socket Backlog registry key. // // Arguments: // long* plBacklog : current value // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::GetSocketBacklog( long *plBacklog ) { if ( NULL == plBacklog ) return E_INVALIDARG; DWORD dwValue; long lRC = RegQuerySocketBacklog( dwValue, m_psMachineName ); if ( ERROR_SUCCESS == lRC ) { *plBacklog = dwValue; return S_OK; } return HRESULT_FROM_WIN32( lRC ); } ///////////////////////////////////////////////////////////////////////////// // GetSocketMax, public // // Purpose: // Get the Socket Max registry key. // // Arguments: // long* plMax : current value // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::GetSocketMax( long *plMax ) { if ( NULL == plMax ) return E_INVALIDARG; DWORD dwValue; long lRC = RegQuerySocketMax( dwValue, m_psMachineName ); if ( ERROR_SUCCESS == lRC ) { *plMax = dwValue; return S_OK; } return HRESULT_FROM_WIN32( lRC ); } ///////////////////////////////////////////////////////////////////////////// // GetSocketMin, public // // Purpose: // Get the Socket Min registry key. // // Arguments: // long* plMax : current value // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::GetSocketMin( long *plMin ) { if ( NULL == plMin ) return E_INVALIDARG; DWORD dwValue; long lRC = RegQuerySocketMin( dwValue, m_psMachineName ); if ( ERROR_SUCCESS == lRC ) { *plMin = dwValue; return S_OK; } return HRESULT_FROM_WIN32( lRC ); } ///////////////////////////////////////////////////////////////////////////// // GetSocketThreshold, public // // Purpose: // Get the Socket Threshold registry key. // // Arguments: // long* plThreshold : current value // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::GetSocketThreshold( long *plThreshold ) { if ( NULL == plThreshold ) return E_INVALIDARG; DWORD dwValue; long lRC = RegQuerySocketThreshold( dwValue, m_psMachineName ); if ( ERROR_SUCCESS == lRC ) { *plThreshold = dwValue; return S_OK; } return HRESULT_FROM_WIN32( lRC ); } ///////////////////////////////////////////////////////////////////////////// // GetSPARequired, public // // Purpose: // Get the SPARequired registry key. // // Arguments: // BOOL *pbSPARequired : current value // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::GetSPARequired( BOOL *pbSPARequired ) { if ( NULL == pbSPARequired ) return E_INVALIDARG; DWORD dwValue; long lRC = RegQuerySPARequired( dwValue, m_psMachineName ); if ( ERROR_SUCCESS == lRC ) { *pbSPARequired = (dwValue) ? TRUE : FALSE; return S_OK; } return HRESULT_FROM_WIN32( lRC ); } ///////////////////////////////////////////////////////////////////////////// // GetThreadCountPerCPU, public // // Purpose: // Get the ThreadCountPerCPU registry key. // // Arguments: // long* plCount : current value // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::GetThreadCountPerCPU( long *plCount ) { if ( NULL == plCount ) return E_INVALIDARG; DWORD dwValue; long lRC = RegQueryThreadCountPerCPU( dwValue, m_psMachineName ); if ( ERROR_SUCCESS == lRC ) { *plCount = dwValue; return S_OK; } return HRESULT_FROM_WIN32( lRC ); } HRESULT CP3AdminWorker::GetUserCount( LPWSTR psDomainName, long *plCount ) { // psDomainName - checked by BuildDomainPath if ( NULL == plCount ) return E_INVALIDARG; HRESULT hr; HANDLE hfSearch; WCHAR sBuffer[POP3_MAX_PATH]; WIN32_FIND_DATA stFindFileData; LPWSTR ps; _bstr_t _bstr; CMailBox mailboxX; *plCount = 0; hr = BuildDomainPath( psDomainName, sBuffer, sizeof( sBuffer )/sizeof(WCHAR) ); if (S_OK == hr) { if ((sizeof( sBuffer )/sizeof(WCHAR)) > (wcslen( sBuffer ) + wcslen(MAILBOX_PREFIX_W) + wcslen(MAILBOX_EXTENSION_W) + 2 )) { wcscat( sBuffer, L"\\" ); wcscat( sBuffer, MAILBOX_PREFIX_W ); wcscat( sBuffer, L"*" ); wcscat( sBuffer, MAILBOX_EXTENSION_W ); } else hr = E_UNEXPECTED; } if ( S_OK == hr ) hr = MailboxSetRemote(); if ( S_OK == hr ) { // Directory Search hfSearch = FindFirstFileEx( sBuffer, FindExInfoStandard, &stFindFileData, FindExSearchLimitToDirectories, NULL, 0 ); if ( INVALID_HANDLE_VALUE == hfSearch ) hr = HRESULT_FROM_WIN32(GetLastError()); while ( S_OK == hr ) { // Count directories if ( FILE_ATTRIBUTE_DIRECTORY == ( FILE_ATTRIBUTE_DIRECTORY & stFindFileData.dwFileAttributes )) { ps = mailboxX.GetMailboxFromStoreNameW( stFindFileData.cFileName ); if ( NULL != ps ) { _bstr = ps; _bstr += L"@"; _bstr += psDomainName; if ( mailboxX.OpenMailBox( _bstr )) { mailboxX.CloseMailBox(); (*plCount) += 1; } } } if ( !FindNextFile( hfSearch, &stFindFileData )) hr = HRESULT_FROM_WIN32(GetLastError()); } if ( HRESULT_FROM_WIN32(ERROR_NO_MORE_FILES) == hr || HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr ) hr = S_OK; if(INVALID_HANDLE_VALUE!=hfSearch) { FindClose(hfSearch); hfSearch=INVALID_HANDLE_VALUE; } } MailboxResetRemote(); return hr; } ///////////////////////////////////////////////////////////////////////////// // GetUserLock, public // // Purpose: // Determine if the user is locked. // // Arguments: // LPWSTR psDomainName : Domain of user // LPWSTR psUserName : User to check lock // BOOL *pisLocked : return value // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::GetUserLock( LPWSTR psDomainName, LPWSTR psUserName, BOOL *pisLocked ) { // psDomainName - checked by CreateUserMutex // psBuffer - checked by CreateUserMutex if ( NULL == pisLocked ) return E_INVALIDARG; HRESULT hr = S_OK; HANDLE hMutex = NULL; // Create a Mutex Name for this domain to ensure we are the only one accessing it. hr = CreateUserMutex( psDomainName, psUserName, &hMutex ); if ( S_OK == hr ) *pisLocked = isUserLocked( psDomainName, psUserName ) ? TRUE : FALSE; // Cleanup if ( NULL != hMutex ) CloseHandle( hMutex ); return hr; } ///////////////////////////////////////////////////////////////////////////// // GetUserMessageDiskUsage, public // // Purpose: // Get the number of messages in the mailbox. // // Arguments: // LPWSTR psDomainName : Domain of user // LPWSTR psUserName : User to check // long *plFactor : Base 10 multiplicand for plUsage // long *plUsage : Disk Usage // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::GetUserMessageDiskUsage( LPWSTR psDomainName, LPWSTR psUserName, long *plFactor, long *plUsage ) { // psDomainName - checked by BuildEmailAddrW2A // psBuffer - checked by BuildEmailAddrW2A if ( NULL == plFactor ) return E_INVALIDARG; if ( NULL == plUsage ) return E_INVALIDARG; HRESULT hr; CMailBox mailboxX; WCHAR sEmailAddr[POP3_MAX_ADDRESS_LENGTH]; DWORD dwTotalSize; hr = BuildEmailAddr( psDomainName, psUserName, sEmailAddr, sizeof( sEmailAddr )/sizeof(WCHAR) ); if ( S_OK == hr ) hr = MailboxSetRemote(); if ( S_OK == hr ) { hr = E_FAIL; if ( mailboxX.OpenMailBox( sEmailAddr )) { if ( mailboxX.EnumerateMailBox() ) { dwTotalSize = mailboxX.GetTotalSize(); if ( INT_MAX > dwTotalSize ) { *plFactor = 1; *plUsage = dwTotalSize; } else { *plFactor = 10; *plUsage = dwTotalSize / 10; } hr = S_OK; } mailboxX.CloseMailBox(); } } MailboxResetRemote(); return hr; } ///////////////////////////////////////////////////////////////////////////// // GetUserMessageCount, public // // Purpose: // Get the number of messages in the mailbox. // // Arguments: // LPWSTR psDomainName : Domain of user // LPWSTR psUserName : User to check // long *plCount : return value // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::GetUserMessageCount( LPWSTR psDomainName, LPWSTR psUserName, long *plCount ) { // psDomainName - checked by BuildEmailAddrW2A // psBuffer - checked by BuildEmailAddrW2A if ( NULL == plCount ) return E_INVALIDARG; HRESULT hr; CMailBox mailboxX; WCHAR sEmailAddr[POP3_MAX_ADDRESS_LENGTH]; hr = BuildEmailAddr(psDomainName, psUserName, sEmailAddr, sizeof( sEmailAddr )/sizeof(WCHAR) ); if ( S_OK == hr ) hr = MailboxSetRemote(); if ( S_OK == hr ) { hr = E_FAIL; if ( mailboxX.OpenMailBox( sEmailAddr )) { if ( mailboxX.EnumerateMailBox() ) { *plCount = mailboxX.GetMailCount(); hr = S_OK; } mailboxX.CloseMailBox(); } } MailboxResetRemote(); return hr; } ///////////////////////////////////////////////////////////////////////////// // InitFindFirstFile, public // // Purpose: // Initialize a file search. Used for enumerating users. // // Arguments: // HANDLE& hfSearch : search handle to initialize // // Returns: S_OK or S_FALSE (no users) on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::InitFindFirstUser( HANDLE& hfSearch, LPCWSTR psDomainName, LPWSTR psBuffer, DWORD dwBufferSize ) { // psDomainName - checked by BuildEmailAddrW2A if ( NULL == psBuffer ) return E_INVALIDARG; HRESULT hr = S_OK; bool bFound = false; WCHAR sBuffer[POP3_MAX_PATH]; _bstr_t _bstr; LPWSTR ps; CMailBox mailboxX; WIN32_FIND_DATA stFindFileData; if ( INVALID_HANDLE_VALUE != hfSearch ) { FindClose( hfSearch ); hfSearch = INVALID_HANDLE_VALUE; } // Build the Path hr = BuildDomainPath( psDomainName, sBuffer, (sizeof( sBuffer )/sizeof(WCHAR))); if (S_OK == hr) { if ((sizeof( sBuffer )/sizeof(WCHAR)) > (wcslen( sBuffer ) + wcslen(MAILBOX_PREFIX_W) + wcslen(MAILBOX_EXTENSION_W) + 2 )) { wcscat( sBuffer, L"\\" ); wcscat( sBuffer, MAILBOX_PREFIX_W ); wcscat( sBuffer, L"*" ); wcscat( sBuffer, MAILBOX_EXTENSION_W ); } else hr = E_UNEXPECTED; } if ( S_OK == hr ) hr = MailboxSetRemote(); if ( S_OK == hr ) { // Directory Search hfSearch = FindFirstFileEx( sBuffer, FindExInfoStandard, &stFindFileData, FindExSearchLimitToDirectories, NULL, 0 ); if ( INVALID_HANDLE_VALUE == hfSearch ) hr = HRESULT_FROM_WIN32(GetLastError()); while ( S_OK == hr && !bFound ) { // Make sure we have a mailbox directory if ( FILE_ATTRIBUTE_DIRECTORY == ( FILE_ATTRIBUTE_DIRECTORY & stFindFileData.dwFileAttributes )) { ps = mailboxX.GetMailboxFromStoreNameW( stFindFileData.cFileName ); if ( NULL != ps ) { _bstr = ps; _bstr += L"@"; _bstr += psDomainName; if ( mailboxX.OpenMailBox( _bstr )) { if ( dwBufferSize > wcslen( ps )) { wcscpy( psBuffer, ps ); bFound = true; mailboxX.CloseMailBox(); } else hr = HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER ); } } } if ( !bFound ) { if ( !FindNextFile( hfSearch, &stFindFileData )) hr = HRESULT_FROM_WIN32(GetLastError()); } } if ( HRESULT_FROM_WIN32(ERROR_NO_MORE_FILES) == hr || HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr ) hr = S_FALSE; } MailboxResetRemote(); return hr; } ///////////////////////////////////////////////////////////////////////////// // IsDomainLocked, public // // Purpose: // Determine if the domain is locked. // Domain locking involved renaming all the mailbox lock files to LOCKRENAME_FILENAME plus // creating a file in the domain directory. // Checking for the file in the domain directory is a sufficient check for our purposes. // // Arguments: // LPWSTR psDomainName : domain to check // // Returns: S_OK on success, appropriate HRESULT otherwise bool CP3AdminWorker::IsDomainLocked( LPWSTR psDomainName ) { // psDomainName - checked by BuildDomainPath HRESULT hr; bool bRC = false; WCHAR sDomainPath[POP3_MAX_PATH]; WCHAR sBuffer[POP3_MAX_PATH]; hr = BuildDomainPath( psDomainName, sDomainPath, sizeof( sDomainPath )/sizeof(WCHAR) ); if ( S_OK == hr ) { // Directory Search if ( (sizeof( sBuffer )/sizeof(WCHAR)) > (wcslen( sDomainPath ) + wcslen(LOCKRENAME_FILENAME) + 1 )) { wcscpy( sBuffer, sDomainPath ); wcscat( sBuffer, L"\\" ); wcscat( sBuffer, LOCKRENAME_FILENAME ); if ( ERROR_NO_FILE_ATTR != GetFileAttributes( sBuffer )) bRC = true; } else hr = E_UNEXPECTED; } return bRC; } ///////////////////////////////////////////////////////////////////////////// // isUserLocked, public // // Purpose: // Determine if the user is locked. Users can be locked in one of two fashions: // Domain locking involved renaming all the mailbox lock files to LOCKRENAME_FILENAME, // or the LOCK_FILENAME may be in use. Either way OpenMailbox will fail. // // Arguments: // LPWSTR psDomainName : domain of user // LPWSTR psUserName : user to check // // Returns: S_OK on success, appropriate HRESULT otherwise bool CP3AdminWorker::isUserLocked( LPWSTR psDomainName, LPWSTR psUserName ) { // psDomainName - checked by BuildEmailAddrW2A // psBuffer - checked by BuildEmailAddrW2A bool bRC = false; HRESULT hr; CMailBox mailboxX; WCHAR sEmailAddr[POP3_MAX_ADDRESS_LENGTH]; hr = BuildEmailAddr( psDomainName, psUserName, sEmailAddr, sizeof( sEmailAddr )/sizeof(WCHAR) ); if ( S_OK == hr ) hr = MailboxSetRemote(); if ( S_OK == hr ) { if ( mailboxX.OpenMailBox( sEmailAddr )) { HRESULT hr = S_OK; WCHAR sBuffer[POP3_MAX_PATH]; WCHAR sLockFile[POP3_MAX_PATH]; hr = BuildUserPath( psDomainName, psUserName, sBuffer, sizeof( sBuffer )/sizeof(WCHAR) ); if ( S_OK == hr ) { if ((sizeof( sLockFile )/sizeof(WCHAR)) > ( wcslen( sBuffer ) + wcslen( LOCK_FILENAME ) + 1 )) { wcscpy( sLockFile, sBuffer ); wcscat( sLockFile, L"\\" ); wcscat( sLockFile, LOCK_FILENAME ); if ( -1 == GetFileAttributes( sLockFile )) bRC = true; } } mailboxX.CloseMailBox(); } } MailboxResetRemote(); return bRC; } BYTE g_ASCII128[128] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00-0F 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 10-1F 0,1,0,1,1,1,1,1,0,0,0,1,0,1,1,0, // 20-2F 1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, // 30-3F 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 40-4F 1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1, // 50-5F 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 60-6F 1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1 // 70-7F }; ///////////////////////////////////////////////////////////////////////////// // isValidMailboxName, public // // Purpose: // Perform RFC 821 validation on the mailbox name // user - The maximum total length of a user name is 64 characters. // ::= "@" // ::= | // ::= | "." -> . 0x2e // ::= """ """ -> " 0x22 not going to allow this because it creates other complications // ::= | // ::= | "\" // ::= any one of the 128 ASCII characters (no exceptions) -> This means any thing is permitted, even the special characters! // ::= any one of the 128 ASCII characters, // but not any or // ::= "<" | ">" | "(" | ")" | "[" | "]" | "\" | "." // | "," | ";" | ":" | "@" """ | the control // characters (ASCII codes 0 through 31 inclusive and 127) // ::= the space character (ASCII code 32) // // Arguments: // LPWSTR psMailbox : name to validate // // Returns: S_OK on success, appropriate HRESULT otherwise bool CP3AdminWorker::isValidMailboxName( LPWSTR psMailbox ) { if ( NULL == psMailbox ) return false; if ( POP3_MAX_MAILBOX_LENGTH <= wcslen( psMailbox ) || 0 == wcslen( psMailbox )) return false; bool bRC = true; WCHAR *pch = psMailbox; for ( pch = psMailbox; 0x0 != *pch && bRC; pch++ ) { if ( 127 < *pch || !g_ASCII128[*pch] ) bRC = false; } if ( bRC && ( 0x2e == psMailbox[0] || 0x2e == psMailbox[wcslen( psMailbox )-1] )) bRC = false; return bRC; } ///////////////////////////////////////////////////////////////////////////// // LockDomain, public // // Purpose: // Lock all the mailboxes in the domain. // This involves renaming all the mailbox lock files so that the Service // can no longer access them. // Also create a Lock file in the domain directory to distinguish between // a domain lock and all mailboxes locked. // // Arguments: // LPWSTR psDomainName : domain to lock // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::LockDomain( LPWSTR psDomainName, bool bVerifyNotInUse /*= false*/ ) { // psDomainName - checked by BuildDomainPath HRESULT hr = S_OK; HANDLE hfSearch, hf; WCHAR sDomainPath[POP3_MAX_PATH]; WCHAR sBuffer[POP3_MAX_PATH]; WCHAR sLockFile[POP3_MAX_PATH]; WCHAR sRenameFile[POP3_MAX_PATH]; WIN32_FIND_DATA stFindFileData; hr = BuildDomainPath( psDomainName, sDomainPath, sizeof( sDomainPath )/sizeof(WCHAR) ); if ( S_OK == hr ) { // Directory Search wcscpy( sBuffer, sDomainPath ); if ((sizeof( sBuffer )/sizeof(WCHAR)) > (wcslen( sBuffer ) + wcslen(MAILBOX_PREFIX_W) + wcslen(MAILBOX_EXTENSION_W)) + 2 ) { wcscat( sBuffer, L"\\" ); wcscat( sBuffer, MAILBOX_PREFIX_W ); wcscat( sBuffer, L"*" ); wcscat( sBuffer, MAILBOX_EXTENSION_W ); } else hr = E_UNEXPECTED; hfSearch = FindFirstFileEx( sBuffer, FindExInfoStandard, &stFindFileData, FindExSearchLimitToDirectories, NULL, 0 ); if ( INVALID_HANDLE_VALUE == hfSearch ) hr = HRESULT_FROM_WIN32(GetLastError()); while ( S_OK == hr ) { // Lock each directory (user) if ( FILE_ATTRIBUTE_DIRECTORY == ( FILE_ATTRIBUTE_DIRECTORY & stFindFileData.dwFileAttributes )) { if (( (sizeof( sLockFile )/sizeof(WCHAR)) > ( wcslen( sDomainPath ) + wcslen( stFindFileData.cFileName ) + wcslen( LOCK_FILENAME ) + 2 )) && ( (sizeof( sRenameFile )/sizeof(WCHAR)) > ( wcslen( sDomainPath ) + wcslen( stFindFileData.cFileName ) + wcslen( LOCKRENAME_FILENAME ) + 2 ))) { wcscpy( sLockFile, sDomainPath ); wcscat( sLockFile, L"\\" ); wcscat( sLockFile, stFindFileData.cFileName ); wcscat( sLockFile, L"\\" ); wcscpy( sRenameFile, sLockFile ); wcscat( sLockFile, LOCK_FILENAME ); wcscat( sRenameFile, LOCKRENAME_FILENAME ); if ( !MoveFile( sLockFile, sRenameFile )) { // If the lock file does not exist, that is okay (this must not be one of our directories) DWORD dwRC = GetLastError(); if ( ERROR_FILE_NOT_FOUND != dwRC ) hr = HRESULT_FROM_WIN32(dwRC); } else { // Try an exclusive lock on the file to make sure the service does not have access to it. if ( bVerifyNotInUse ) { hf = CreateFile( sRenameFile, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_HIDDEN, NULL ); if ( INVALID_HANDLE_VALUE == hf ) hr = HRESULT_FROM_WIN32( GetLastError() ); else CloseHandle( hf ); } } } else hr = E_FAIL; } if ( S_OK == hr && !FindNextFile( hfSearch, &stFindFileData )) hr = HRESULT_FROM_WIN32(GetLastError()); } if ( HRESULT_FROM_WIN32(ERROR_NO_MORE_FILES) == hr || HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr ) hr = S_OK; if(INVALID_HANDLE_VALUE!=hfSearch) { FindClose(hfSearch); hfSearch=INVALID_HANDLE_VALUE; } if ( S_OK == hr ) { if ((sizeof( sBuffer )/sizeof(WCHAR)) > (wcslen( sDomainPath ) + wcslen(LOCKRENAME_FILENAME) + 1 )) { HANDLE hf; wcscpy( sBuffer, sDomainPath ); wcscat( sBuffer, L"\\" ); wcscat( sBuffer, LOCKRENAME_FILENAME ); hf = CreateFile( sBuffer, GENERIC_ALL, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_HIDDEN, NULL ); if ( INVALID_HANDLE_VALUE != hf ) CloseHandle( hf ); else { // If the lock file already exists, that is okay (domain already locked) - we only expect this error in the LockForDelete scenario DWORD dwRC = GetLastError(); if ( !(bVerifyNotInUse && ERROR_FILE_EXISTS == dwRC )) hr = HRESULT_FROM_WIN32(dwRC); } } } // Ran into a problem need to undo everything we've done if ( S_OK != hr ) UnlockDomain( psDomainName ); // Don't overwrite existing return code } return hr; } ///////////////////////////////////////////////////////////////////////////// // LockUser, public // // Purpose: // Lock the user mailbox. // A permanent lock is created by renaming all the mailbox lock file so that the Service // can no longer it. // // Arguments: // LPWSTR psDomainName : domain of user // LPWSTR psUserName : user to lock // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::LockUser( LPWSTR psDomainName, LPWSTR psUserName ) { // psDomainName - checked by BuildUserPath // psUserName - checked by BuildUserPath HRESULT hr = S_OK; WCHAR sBuffer[POP3_MAX_PATH]; WCHAR sLockFile[POP3_MAX_PATH]; WCHAR sRenameFile[POP3_MAX_PATH]; hr = BuildUserPath( psDomainName, psUserName, sBuffer, sizeof( sBuffer )/sizeof(WCHAR) ); if ( S_OK == hr ) { if (( (sizeof( sLockFile )/sizeof(WCHAR)) > ( wcslen( sBuffer ) + wcslen( LOCK_FILENAME ) + 1 )) && ( (sizeof( sRenameFile )/sizeof(WCHAR)) > ( wcslen( sBuffer ) + wcslen( LOCKRENAME_FILENAME ) + 1 ))) { wcscpy( sLockFile, sBuffer ); wcscat( sLockFile, L"\\" ); wcscpy( sRenameFile, sLockFile ); wcscat( sLockFile, LOCK_FILENAME ); wcscat( sRenameFile, LOCKRENAME_FILENAME ); if ( !MoveFile( sLockFile, sRenameFile )) { DWORD dwRC = GetLastError(); hr = HRESULT_FROM_WIN32(dwRC); } } } return hr; } ///////////////////////////////////////////////////////////////////////////// // MailboxSetRemote, public // // Purpose: // Set the Mailbox static path to the remote machine, if necessary. // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::MailboxSetRemote() { if ( NULL != m_psMachineMailRoot ) { if ( !CMailBox::SetMailRoot( m_psMachineMailRoot ) ) return E_FAIL; } return S_OK; } ///////////////////////////////////////////////////////////////////////////// // MailboxResetRemote, public // // Purpose: // Reset the Mailbox static path back to the local machine, if necessary. // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::MailboxResetRemote() { if ( NULL != m_psMachineMailRoot ) { if ( !CMailBox::SetMailRoot( )) return E_FAIL; } return S_OK; } ///////////////////////////////////////////////////////////////////////////// // RemoveDomain, public // // Purpose: // Remove the Meta base options required to remove a Local domain from the SMTP service. // Remove the domain from our Store. // // Arguments: // LPWSTR psDomainName : Domain name to remove // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::RemoveDomain( LPWSTR psDomainName ) { // psDomainName - checked by CreateDomainMutex HRESULT hr = S_OK; HANDLE hMutex = NULL; // Create a Mutex Name for this domain to ensure we are the only one accessing it. hr = CreateDomainMutex( psDomainName, &hMutex ); // Validate if ( S_OK == hr ) { hr = ValidateDomain( psDomainName ); if ( HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr ) { // Domain exists in SMTP but not in Store, let's delete from SMTP anyway hr = RemoveSMTPDomain( psDomainName ); if ( S_OK == hr ) hr = ERROR_PATH_NOT_FOUND; } } // Lock all the Mailboxes if ( S_OK == hr ) { hr = LockDomainForDelete( psDomainName ); // Remove if ( S_OK == hr ) { hr = RemoveSMTPDomain( psDomainName ); if ( S_OK == hr ) { hr = RemoveStoreDomain( psDomainName ); if FAILED( hr ) AddSMTPDomain( psDomainName ); } if ( S_OK != hr ) UnlockDomain( psDomainName ); } } // Cleanup if ( NULL != hMutex ) CloseHandle( hMutex ); return hr; } ///////////////////////////////////////////////////////////////////////////// // RemoveUser, public // // Purpose: // Remove a user mailbox. // // Arguments: // LPWSTR psDomainName : Domain name to remove from // LPWSTR psUserName : User name to remove // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::RemoveUser( LPWSTR psDomainName, LPWSTR psUserName ) { // psDomainName - checked by BuildUserPath // psUserName - checked by BuildUserPath HRESULT hr; HANDLE hMutex = NULL; WCHAR sEmailAddr[POP3_MAX_ADDRESS_LENGTH]; WCHAR sRenameFile[POP3_MAX_PATH]; WCHAR sUserFile[POP3_MAX_PATH]; CMailBox mailboxX; hr = BuildUserPath( psDomainName, psUserName, sUserFile, sizeof( sUserFile )/sizeof(WCHAR) ); if ( S_OK == hr ) { // build the path to the mail dir \MailRoot\Domain@User hr = BuildDomainPath( psDomainName, sRenameFile, sizeof( sRenameFile )/sizeof(WCHAR) ); if ( S_OK == hr ) { if ( (wcslen( sRenameFile ) + wcslen( MAILBOX_PREFIX_W ) + wcslen( psUserName ) + wcslen( MAILBOX_EXTENSION2_W ) + 1) < (sizeof( sRenameFile )/sizeof(WCHAR)) ) { // build the path to the mail dir \MailRoot\Domain\User wcscat( sRenameFile, L"\\" ); wcscat( sRenameFile, MAILBOX_PREFIX_W ); wcscat( sRenameFile, psUserName ); wcscat( sRenameFile, MAILBOX_EXTENSION2_W ); } else hr = E_FAIL; } } // Validate the domain if ( S_OK == hr ) { hr = ValidateDomain( psDomainName ); } if ( S_OK == hr ) hr = MailboxSetRemote(); if ( S_OK == hr ) { // See if the mailbox already exists hr = BuildEmailAddr( psDomainName, psUserName, sEmailAddr, sizeof( sEmailAddr )/sizeof(WCHAR) ); if ( mailboxX.OpenMailBox( sEmailAddr )) { // Create a Mutex Name for this user@domain to ensure we are the only one accessing it. hr = CreateUserMutex( psDomainName, psUserName, &hMutex ); // Lock the Mailbox to make sure we are the only one accessing it then // rename it to something unique, release our lock on the mailbox, then kill it. if ( S_OK == hr ) { if ( MoveFile( sUserFile, sRenameFile )) // rename { if ( !BDeleteDirTree( sRenameFile )) // kill { hr = HRESULT_FROM_WIN32( GetLastError()); if SUCCEEDED( hr ) hr = E_FAIL; // Make sure we have a failure code // Now what? Try to repair what's left of this mess. if ( MoveFile( sRenameFile, sUserFile )) { // What if the lock file was deleted? if ( mailboxX.OpenMailBox( sEmailAddr )) mailboxX.RepairMailBox(); } } } else hr = HRESULT_FROM_WIN32( GetLastError()); } // Cleanup if ( NULL != hMutex ) CloseHandle( hMutex ); mailboxX.CloseMailBox(); // It's okay to do this even if the mailbox is already closed. } else hr = HRESULT_FROM_WIN32( GetLastError()); } MailboxResetRemote(); return hr; } ///////////////////////////////////////////////////////////////////////////// // SearchDomainsForMailbox, public // // Purpose: // Search all domains for the first occurance of a given mailbox // // Arguments: // LPWSTR psUserName : Mailbox to search for // LPWSTR *ppsDomain : Name of domain mailbox found in !Must be freed by caller // // Returns: S_OK if mailbox found (if not NULL ppsDomain will contain the domain name), // HRESULT_FROM_WIN32( ERROR_NO_SUCH_USER ) if mailbox not found in any domain, // appropriate HRESULT otherwise HRESULT CP3AdminWorker::SearchDomainsForMailbox( LPTSTR psUserName, LPTSTR *ppsDomain ) { if ( NULL == psUserName ) return E_INVALIDARG; if ( 0 == wcslen( psUserName )) return E_INVALIDARG; if ( NULL != ppsDomain ) *ppsDomain = NULL; HRESULT hr = S_OK; bool bFound = false; BSTR bstrName; WCHAR sEmailAddr[POP3_MAX_ADDRESS_LENGTH]; VARIANT v; CMailBox mailboxX; CComPtr spIConfig; CComPtr spIDomains; CComPtr spIDomain = NULL; CComPtr spIEnumVARIANT; VariantInit( &v ); hr = CoCreateInstance( __uuidof( P3Config ), NULL, CLSCTX_ALL, __uuidof( IP3Config ),reinterpret_cast( &spIConfig )); if ( S_OK == hr ) hr = spIConfig->get_Domains( &spIDomains ); if ( S_OK == hr ) hr = spIDomains->get__NewEnum( &spIEnumVARIANT ); if ( S_OK == hr ) hr = spIEnumVARIANT->Next( 1, &v, NULL ); while ( S_OK == hr && !bFound ) { if ( VT_DISPATCH != V_VT( &v )) hr = E_UNEXPECTED; else { if ( NULL != spIDomain.p ) spIDomain.Release(); hr = V_DISPATCH( &v )->QueryInterface( __uuidof( IP3Domain ), reinterpret_cast( &spIDomain )); } if ( S_OK == hr ) { hr = spIDomain->get_Name( &bstrName ); if ( S_OK == hr ) { // See if the mailbox already exists hr = BuildEmailAddr( bstrName, psUserName, sEmailAddr, sizeof( sEmailAddr )/sizeof(WCHAR) ); if ( S_OK == hr ) { if ( mailboxX.OpenMailBox( sEmailAddr )) { // We found the mailbox, time to exit bFound = true; mailboxX.CloseMailBox(); // return void! if ( NULL != ppsDomain ) { // Let's return the domain name *ppsDomain = new WCHAR[ wcslen( bstrName ) + 1]; if ( NULL == *ppsDomain ) hr = E_OUTOFMEMORY; else wcscpy( *ppsDomain, bstrName ); } } } SysFreeString( bstrName ); } } VariantClear( &v ); if ( S_OK == hr && !bFound ) { hr = spIEnumVARIANT->Next( 1, &v, NULL ); } } if ( S_FALSE == hr ) { hr = HRESULT_FROM_WIN32( ERROR_NO_SUCH_USER ) ; // Reached end of enumeration } return hr; } ///////////////////////////////////////////////////////////////////////////// // SetConfirmAddUser, public // // Purpose: // Set the Confirm Add User registry key. // // Arguments: // BOOL bConfirm: new value // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::SetConfirmAddUser( BOOL bConfirm ) { HRESULT hr = S_OK; if ( TRUE != bConfirm && FALSE != bConfirm ) hr = HRESULT_FROM_WIN32( ERROR_DS_RANGE_CONSTRAINT ); else { DWORD dwValue = bConfirm ? 1 : 0; long lRC = RegSetConfirmAddUser( dwValue, m_psMachineName ); if ( ERROR_SUCCESS != lRC ) hr = HRESULT_FROM_WIN32( lRC ); } return hr; } ///////////////////////////////////////////////////////////////////////////// // SetDomainLock, public // // Purpose: // Set the domain lock. // // Arguments: // LPWSTR psDomainName : Domain name to lock // BOOL bLock : TRUE - to lock the domain, FALSE - to unlock the domain // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::SetDomainLock( LPWSTR psDomainName, BOOL bLock ) { // psDomainName - checked by CreateDomainMutex HRESULT hr = S_OK; HANDLE hMutex = NULL; // Validate if ( S_OK == hr ) { hr = ValidateDomain( psDomainName ); } // Create a Mutex Name for this domain to ensure we are the only one accessing it. hr = CreateDomainMutex( psDomainName, &hMutex ); // Lock all the Mailboxes if ( S_OK == hr ) { if ( bLock ) { if ( !IsDomainLocked( psDomainName )) hr = LockDomain( psDomainName ); else hr = HRESULT_FROM_WIN32( ERROR_LOCKED ); } else { if ( IsDomainLocked( psDomainName )) hr = UnlockDomain( psDomainName ); else hr = HRESULT_FROM_WIN32( ERROR_NOT_LOCKED ); } } // Cleanup if ( NULL != hMutex ) CloseHandle( hMutex ); return hr; } ///////////////////////////////////////////////////////////////////////////// // SetUserLock, public // // Purpose: // Set the domain lock. // // Arguments: // LPWSTR psDomainName : Domain name of user // LPWSTR psUserName : User name to lock // BOOL bLock : TRUE - to lock the user, FALSE - to unlock the user // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::SetUserLock( LPWSTR psDomainName, LPWSTR psUserName, BOOL bLock ) { // psDomainName - checked by CreateUserMutex // psUserName - checked by CreateUserMutex HRESULT hr = S_OK; HANDLE hMutex = NULL; WCHAR sEmailAddr[POP3_MAX_ADDRESS_LENGTH]; CMailBox mailboxX; // Create a Mutex Name for this user to ensure we are the only one accessing it. hr = CreateUserMutex( psDomainName, psUserName, &hMutex ); if ( S_OK == hr ) { if ( FALSE == bLock ) { if ( IsDomainLocked( psDomainName )) hr = HRESULT_FROM_WIN32( ERROR_INVALID_DOMAIN_STATE ); } } if ( S_OK == hr ) hr = BuildEmailAddr( psDomainName, psUserName, sEmailAddr, sizeof( sEmailAddr )/sizeof(WCHAR)); if ( S_OK == hr ) hr = MailboxSetRemote(); if ( S_OK == hr ) { // Validate the Mailbox if ( !mailboxX.OpenMailBox( sEmailAddr )) hr = HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ); } // Lock/Unlock the Mailbox if ( S_OK == hr ) { if ( bLock ) { if ( !isUserLocked( psDomainName, psUserName )) { // Lock the user hr = LockUser( psDomainName, psUserName ); } else hr = HRESULT_FROM_WIN32( ERROR_LOCKED ); } else { if ( isUserLocked( psDomainName, psUserName )) { // UnLock the user hr = UnlockUser( psDomainName, psUserName ); } else hr = HRESULT_FROM_WIN32( ERROR_NOT_LOCKED ); } mailboxX.CloseMailBox(); } MailboxResetRemote(); // Cleanup if ( NULL != hMutex ) CloseHandle( hMutex ); return hr; } ///////////////////////////////////////////////////////////////////////////// // SetIISConfig, public ///////////////////////////////////////////////////////////////////////////// // exchange OnSMTP event sink bindings directions // {1b3c0666-e470-11d1-aa67-00c04fa345f6} //DEFINE_GUID(GUID_PLAT_SMTPSVC, //0x1b3c0666, 0xe470, 0x11d1, 0xaa, 0x67, 0x0, 0xc0, 0x4f, 0xa3, 0x45, 0xf6); #define GUID_PLAT_SMTPSVC L"{1b3c0666-e470-11d1-aa67-00c04fa345f6}" // {fb65c4dc-e468-11d1-aa67-00c04fa345f6} //DEFINE_GUID(SMTP_PLAT_SOURCE_TYPE_GUID, //0xfb65c4dc, 0xe468, 0x11d1, 0xaa, 0x67, 0x0, 0xc0, 0x4f, 0xa3, 0x45, 0xf6); #define SMTP_PLAT_SOURCE_TYPE_GUID L"{fb65c4dc-e468-11d1-aa67-00c04fa345f6}" // SMTP Store Events // {59175850-e533-11d1-aa67-00c04fa345f6} //DECLARE_EVENTGUID_STRING( g_szcatidSmtpStoreDriver, "{59175850-e533-11d1-aa67-00c04fa345f6}"); //DEFINE_GUID(CATID_SMTP_STORE_DRIVER, 0x59175850, 0xe533, 0x11d1, 0xaa, 0x67, 0x0, 0xc0, 0x4f, 0xa3, 0x45, 0xf6); #define CATID_SMTP_STORE_DRIVER L"{59175850-e533-11d1-aa67-00c04fa345f6}" #define STR_P3STOREDRIVER_DISPLAY_NAME L"POP 3 SMTP Store Driver" #define STR_P3STOREDRIVER_SINKCLASS L"POP3SMTPStoreDriver.CPOP3SMTPStoreDriver" #define CLSID_CSimpleDriver L"{9100BE35-711B-4b34-8AC9-BA350C2117BE}" ///////////////////////////////////////////////////////////////////////////// // SetIISConfig, public // // Purpose: // Set the Meta base options required for our SMTP Store Driver to work. // This involves: // DELETE SMTPSVC/1/DropDirectory // Bind our SMTP Store Driver // // Arguments: // BOOL bBindSink : TRUE, perform the necessary configuration // FALSE, remove any configuration changes (try to reconstruct DropDirectory setting) // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::SetIISConfig( bool bBindSink ) { HRESULT hr; CComPtr spIBindingManager; CComPtr spIBindings; CComPtr spIBinding; CComPtr spISourceProps; CComPtr spIUtil; ///////////////////////////// // Bind our SMTP Store Driver ///////////////////////////// hr = CoCreateInstance( __uuidof( CEventUtil ), NULL, CLSCTX_ALL, __uuidof( IEventUtil ),reinterpret_cast( &spIUtil )); if ( S_OK == hr && NULL != spIUtil.p ) { hr = spIUtil->RegisterSource(CComBSTR( SMTP_PLAT_SOURCE_TYPE_GUID ), CComBSTR( GUID_PLAT_SMTPSVC ), 1, CComBSTR( L"smtpsvc" ), CComBSTR( L"" ), CComBSTR( L"event.metabasedatabasemanager" ), CComBSTR( L"smtpsvc 1" ), // Set up the default site (instance) &spIBindingManager); if ( S_OK == hr ) { hr = spIBindingManager->get_Bindings( _bstr_t( CATID_SMTP_STORE_DRIVER ), &spIBindings ); if ( S_OK == hr ) { if ( bBindSink ) { // Create binding hr = spIBindings->Add( _bstr_t( CLSID_CSimpleDriver ),&spIBinding ); if ( S_OK == hr ) { hr = spIBinding->put_DisplayName( _bstr_t( STR_P3STOREDRIVER_DISPLAY_NAME )); if SUCCEEDED( hr ) hr = spIBinding->put_SinkClass( _bstr_t( STR_P3STOREDRIVER_SINKCLASS )); if SUCCEEDED( hr ) hr = spIBinding->get_SourceProperties(&spISourceProps); if SUCCEEDED( hr ) { _variant_t _v(static_cast(0)); hr = spISourceProps->Add( _bstr_t( L"priority" ), &_v ); } if SUCCEEDED( hr ) hr = spIBinding->Save(); } } else { // Delete binding _variant_t _v( CLSID_CSimpleDriver ); hr = spIBindings->Remove( &_v ); } } } } if ( SUCCEEDED( hr ) && !bBindSink ) // Unregistering { // Remove all domains from SMTP ULONG ulFetch; BSTR bstrDomainName; VARIANT v; CComPtr spIADs = NULL; CComPtr spIEnumVARIANT = NULL; VariantInit( &v ); hr = GetDomainEnum( &spIEnumVARIANT ); while ( S_OK == hr ) { hr = spIEnumVARIANT->Next( 1, &v, &ulFetch ); if ( S_OK == hr && 1 == ulFetch ) { if ( VT_DISPATCH == V_VT( &v )) hr = V_DISPATCH( &v )->QueryInterface( __uuidof( IADs ), reinterpret_cast( &spIADs )); else hr = E_UNEXPECTED; VariantClear( &v ); if ( S_OK == hr ) { hr = spIADs->get_Name( &bstrDomainName ); if ( S_OK == hr ) { hr = ValidateDomain( bstrDomainName ); if ( S_OK == hr ) hr = RemoveSMTPDomain( bstrDomainName ); SysFreeString( bstrDomainName ); } spIADs.Release(); spIADs = NULL; } } if ( S_OK == hr ) { // We deleted an SMTP domain, therefore we need a new Enum spIEnumVARIANT.Release(); hr = GetDomainEnum( &spIEnumVARIANT ); } else if ( HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ) == hr ) hr = S_OK; // Some of the domains might not be our domains. } if ( S_FALSE == hr ) hr = S_OK; } /////////////////////////////////////// // Make some final registry key changes /////////////////////////////////////// if SUCCEEDED( hr ) { WCHAR sBuffer[POP3_MAX_MAILROOT_LENGTH]; hr = GetDefaultMailRoot( sBuffer, sizeof(sBuffer)/sizeof(WCHAR) ); if ( S_OK == hr ) hr = SetMailroot( sBuffer ); if ( S_OK == hr ) { long lRC; lRC = RegSetupOCM(); if ( ERROR_SUCCESS != lRC ) hr = HRESULT_FROM_WIN32(lRC); } } return hr; } ///////////////////////////////////////////////////////////////////////////// // SetLoggingLevel, public // // Purpose: // Set the LoggingLevel registry key. // // Arguments: // long lLoggingLevel : new value // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::SetLoggingLevel( long lLoggingLevel ) { if ( 0 > lLoggingLevel || 3 < lLoggingLevel ) return HRESULT_FROM_WIN32( ERROR_DS_RANGE_CONSTRAINT ); HRESULT hr = S_OK; long lRC; lRC = RegSetLoggingLevel( lLoggingLevel, m_psMachineName ); if ( ERROR_SUCCESS != lRC ) hr = HRESULT_FROM_WIN32( lRC ); return hr; } ///////////////////////////////////////////////////////////////////////////// // SetMachineName, public // // Purpose: // Set the Machine Name that all operations should be performed on. // Note: We can not administer remote machine using AD authentication if they are in a different domain // // Arguments: // LPWSTR psMachineName : new value, NULL means Local Machine. // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::SetMachineName( LPWSTR psMachineName ) { if ( !m_isPOP3Installed ) return E_UNEXPECTED; HRESULT hr = S_OK; if ( NULL != m_psMachineName ) { delete m_psMachineName; m_psMachineName = NULL; } if ( NULL != m_psMachineMailRoot ) { delete m_psMachineMailRoot ; m_psMachineMailRoot = NULL; } if ( NULL != psMachineName ) { DWORD dwLength = wcslen( psMachineName ); if ( 0 < dwLength ) { if ( S_OK == hr ) { m_psMachineName = new WCHAR[dwLength+1]; m_psMachineMailRoot = new WCHAR[POP3_MAX_MAILROOT_LENGTH]; if ( NULL != m_psMachineName && NULL != m_psMachineMailRoot ) { wcscpy( m_psMachineName, psMachineName ); hr = GetMailroot( m_psMachineMailRoot, POP3_MAX_MAILROOT_LENGTH ); } else hr = E_OUTOFMEMORY; } if ( S_OK == hr ) { // Check the Auth Method of the remote machine CComPtr spIAuthMethod; hr = GetCurrentAuthentication( &spIAuthMethod ); // Enforces that remote machine using AD authentication are in our domain! } } } return hr; } ///////////////////////////////////////////////////////////////////////////// // SetMailroot, public // // Purpose: // Set the Mail root registry key. // // Arguments: // LPWSTR psMailRoot : new value // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::SetMailroot( LPWSTR psMailRoot ) { if ( NULL == psMailRoot ) return E_INVALIDARG; if ( POP3_MAX_MAILROOT_LENGTH < wcslen( psMailRoot )) return E_INVALIDARG; HRESULT hr = S_OK; TCHAR sBuffer[POP3_MAX_MAILROOT_LENGTH-6], sBuffer2[POP3_MAX_MAILROOT_LENGTH-6]; // Need to leave room for \\? or \\?\UNC DWORD dwRC; WCHAR sMailRoot[POP3_MAX_PATH]; // Same logic as GetMailroot wcscpy( sMailRoot, psMailRoot ); if ( NULL != m_psMachineName ) { // Replace drive: with drive$ if ( L':' == sMailRoot[1] ) { sMailRoot[1] = L'$'; if ( sizeof( sMailRoot )/sizeof(WCHAR) > (wcslen( sMailRoot ) + wcslen( m_psMachineName ) + 3) ) { LPWSTR psBuffer = new WCHAR[wcslen(psMailRoot)+1]; if ( NULL != psBuffer ) { wcscpy( psBuffer, sMailRoot ); wcscpy( sMailRoot, L"\\\\" ); wcscat( sMailRoot, m_psMachineName ); wcscat( sMailRoot, L"\\" ); wcscat( sMailRoot, psBuffer ); delete [] psBuffer; } else hr = HRESULT_FROM_WIN32( ERROR_OUTOFMEMORY ); } else hr = HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER ); } } if ( S_OK == hr ) { hr = HRESULT_FROM_WIN32( ERROR_BAD_PATHNAME ); dwRC = GetFileAttributes( sMailRoot ); if ( -1 != dwRC ) { // Must begin with x:\ or \\. if ( ( FILE_ATTRIBUTE_DIRECTORY & dwRC ) && ( ( 0 == _wcsnicmp( psMailRoot+1, L":\\", 2 )) || ( 0 == _wcsnicmp( psMailRoot, L"\\\\", 2 )))) { if ( GetVolumePathName( sMailRoot, sBuffer, sizeof( sBuffer )/sizeof( TCHAR ))) { if ( GetVolumeNameForVolumeMountPoint( sBuffer, sBuffer2, sizeof( sBuffer2 )/sizeof( TCHAR ))) { // Make sure the mailroot is not CDROM or removable disk if ( DRIVE_FIXED == GetDriveType( sBuffer )) hr = S_OK; } else { // Make sure this is a UNC Path if ( NULL == wcschr( sMailRoot, L':' )) hr = S_OK; } } } else hr = HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ); } else hr = HRESULT_FROM_WIN32( GetLastError()); } if ( S_OK == hr ) { //Set the default ACLs for the mailroot directory WCHAR wszSDL[MAX_PATH]=L"O:BAG:BAD:PAR(A;OICI;GA;;;BA)(A;OICIIO;GA;;;CO)(A;OICI;GA;;;NS)(A;OICI;GA;;;SY)"; PSECURITY_DESCRIPTOR pSD; ULONG lSize=0; if(ConvertStringSecurityDescriptorToSecurityDescriptorW( wszSDL, SDDL_REVISION_1, &pSD, &lSize)) { if( !SetFileSecurityW(sMailRoot, DACL_SECURITY_INFORMATION|PROTECTED_DACL_SECURITY_INFORMATION, pSD) ) hr = HRESULT_FROM_WIN32( GetLastError()); else hr = HRESULT_FROM_WIN32( SetMailBoxDACL(sMailRoot, pSD, 2)); LocalFree(pSD); } else hr = HRESULT_FROM_WIN32( GetLastError()); } if( S_OK == hr ) { hr = HRESULT_FROM_WIN32( RegSetMailRoot( psMailRoot, m_psMachineName )); if( S_OK == hr ) { if ( NULL == m_psMachineName ) { if ( !CMailBox::SetMailRoot( )) hr = E_FAIL; } else hr = GetMailroot( m_psMachineMailRoot, POP3_MAX_MAILROOT_LENGTH ); } } return hr; } ///////////////////////////////////////////////////////////////////////////// // SetPort, public // // Purpose: // Set the Port registry key. // // Arguments: // long lPort : new value // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::SetPort( long lPort ) { long lRC; if ( 1 > lPort || 65535 < lPort ) lRC = ERROR_DS_RANGE_CONSTRAINT; else lRC = RegSetPort( lPort, m_psMachineName ); if ( ERROR_SUCCESS == lRC ) return S_OK; return HRESULT_FROM_WIN32( lRC ); } ///////////////////////////////////////////////////////////////////////////// // SetSockets, public // // Purpose: // Set the Sockets registry keys; // // Arguments: // long lMax: new Max ( must be >= lMin && >= lMin + lThreshold ) // long lMin: new Min ( must be >= lThreshold ) // long lThreshold: new Threshold ( must be > 0 && < lMax. Special case 0 if lMin == lMax // long lBacklog: new Backlog ( must be > 0 ) // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::SetSockets( long lMax, long lMin, long lThreshold, long lBacklog ) { long lRC; if ( (1 > lMax || 32000 < lMax) || (1 > lMin || 32000 < lMin) || (0 > lThreshold || 100 < lThreshold) || (0 > lBacklog || 100 < lBacklog) ) return HRESULT_FROM_WIN32( ERROR_DS_RANGE_CONSTRAINT ); if ( (lMax < lMin) || (lMax < lMin + lThreshold) ) return E_INVALIDARG; if ( lMin < lThreshold ) return E_INVALIDARG; if ( (1 > lThreshold) && !((lMin == lMax) && (lThreshold == 0)) ) return E_INVALIDARG; lRC = RegSetSocketMax( lMax, m_psMachineName ); if ( ERROR_SUCCESS == lRC ) lRC = RegSetSocketMin( lMin, m_psMachineName ); if ( ERROR_SUCCESS == lRC ) lRC = RegSetSocketThreshold( lThreshold, m_psMachineName ); if ( ERROR_SUCCESS == lRC ) lRC = RegSetSocketBacklog( lBacklog, m_psMachineName ); if ( ERROR_SUCCESS == lRC ) return S_OK; return HRESULT_FROM_WIN32( lRC ); } ///////////////////////////////////////////////////////////////////////////// // SetSPARequired, public // // Purpose: // Set the SPA Required registry key. // // Arguments: // BOOL bSPARequired : new value // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::SetSPARequired( BOOL bSPARequired ) { HRESULT hr = S_OK; if ( TRUE != bSPARequired && FALSE != bSPARequired ) hr = HRESULT_FROM_WIN32( ERROR_DS_RANGE_CONSTRAINT ); else { DWORD dwValue = bSPARequired ? 1 : 0; if ( 1 == dwValue ) { CComPtr spIAuthMethod; BSTR bstrAuthType; hr = GetCurrentAuthentication( &spIAuthMethod ); if ( S_OK == hr ) hr = spIAuthMethod->get_ID( &bstrAuthType ); if ( S_OK == hr ) { if ( 0 == _wcsicmp( bstrAuthType, SZ_AUTH_ID_MD5_HASH )) hr = HRESULT_FROM_WIN32( ERROR_DS_INAPPROPRIATE_AUTH ); SysFreeString( bstrAuthType ); } } if ( S_OK == hr ) { long lRC = RegSetSPARequired( dwValue, m_psMachineName ); if ( ERROR_SUCCESS != lRC ) hr = HRESULT_FROM_WIN32( lRC ); } } return hr; } ///////////////////////////////////////////////////////////////////////////// // SetThreadCountPerCPU, public // // Purpose: // Set the thread count registry key. // // Arguments: // long lCount : new value // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::SetThreadCountPerCPU( long lCount ) { long lRC; if ( 1 > lCount || 32 < lCount ) lRC = ERROR_DS_RANGE_CONSTRAINT; else lRC = RegSetThreadCount( lCount, m_psMachineName ); if ( ERROR_SUCCESS == lRC ) return S_OK; return HRESULT_FROM_WIN32( lRC ); } ///////////////////////////////////////////////////////////////////////////// // StartService, public // // Purpose: // Ask the Service Control Manager to start the service. // // Arguments: // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::StartService( LPWSTR psService ) { if ( NULL == psService ) return E_INVALIDARG; if ( 0 == _wcsicmp( POP3_SERVICE_NAME, psService ) || 0 == _wcsicmp( SMTP_SERVICE_NAME_W, psService ) || 0 == _wcsicmp( IISADMIN_SERVICE_NAME, psService ) || 0 == _wcsicmp( W3_SERVICE_NAME, psService ) ) return _StartService( psService, m_psMachineName ); else return E_INVALIDARG; } ///////////////////////////////////////////////////////////////////////////// // StopService, public // // Purpose: // Ask the Service Control Manager to stop the service. // // Arguments: // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::StopService( LPWSTR psService ) { if ( NULL == psService ) return E_INVALIDARG; if ( 0 == _wcsicmp( POP3_SERVICE_NAME, psService ) || 0 == _wcsicmp( SMTP_SERVICE_NAME_W, psService ) || 0 == _wcsicmp( IISADMIN_SERVICE_NAME, psService ) || 0 == _wcsicmp( W3_SERVICE_NAME, psService ) ) return _StopService( psService, TRUE, m_psMachineName); else return E_INVALIDARG; } ///////////////////////////////////////////////////////////////////////////// // UnlockDomain, public // // Purpose: // Unlock all the mailboxes in the domain. // This involves renaming all the mailbox lock files so that the Service // can once again access them // Plus deleting the file in the domain directory. // // Arguments: // LPWSTR psDomainName : domain to unlock // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::UnlockDomain( LPWSTR psDomainName ) { // psDomainName - checked by BuildDomainPath HRESULT hr; HANDLE hfSearch; WCHAR sBuffer[POP3_MAX_PATH]; WCHAR sDomainPath[POP3_MAX_PATH]; WCHAR sLockFile[POP3_MAX_PATH]; WCHAR sRenameFile[POP3_MAX_PATH]; WIN32_FIND_DATA stFindFileData; hr = BuildDomainPath( psDomainName, sDomainPath, sizeof( sBuffer )/sizeof(WCHAR) ); if ( S_OK == hr ) { // Directory Search wcscpy( sBuffer, sDomainPath ); if ((sizeof( sBuffer )/sizeof(WCHAR)) > (wcslen( sBuffer ) + wcslen(MAILBOX_PREFIX_W) + wcslen(MAILBOX_EXTENSION_W)) + 2 ) { wcscat( sBuffer, L"\\" ); wcscat( sBuffer, MAILBOX_PREFIX_W ); wcscat( sBuffer, L"*" ); wcscat( sBuffer, MAILBOX_EXTENSION_W ); } else hr = E_UNEXPECTED; hfSearch = FindFirstFileEx( sBuffer, FindExInfoStandard, &stFindFileData, FindExSearchLimitToDirectories, NULL, 0 ); if ( INVALID_HANDLE_VALUE == hfSearch ) hr = HRESULT_FROM_WIN32( GetLastError()); while ( S_OK == hr ) { // Lock each directory (user) if ( FILE_ATTRIBUTE_DIRECTORY == ( FILE_ATTRIBUTE_DIRECTORY & stFindFileData.dwFileAttributes )) { if (( (sizeof( sLockFile )/sizeof(WCHAR)) > ( wcslen( sDomainPath ) + wcslen( stFindFileData.cFileName ) + wcslen( LOCK_FILENAME ) + 2 )) && ( (sizeof( sRenameFile )/sizeof(WCHAR)) > ( wcslen( sDomainPath ) + wcslen( stFindFileData.cFileName ) + wcslen( LOCKRENAME_FILENAME ) + 2 ))) { wcscpy( sLockFile, sDomainPath ); wcscat( sLockFile, L"\\" ); wcscat( sLockFile, stFindFileData.cFileName ); wcscat( sLockFile, L"\\" ); wcscpy( sRenameFile, sLockFile ); wcscat( sLockFile, LOCK_FILENAME ); wcscat( sRenameFile, LOCKRENAME_FILENAME ); if ( !MoveFile( sRenameFile, sLockFile )) { // If the rename file does not exist, that is okay. DWORD dwRC = GetLastError(); if ( ERROR_FILE_NOT_FOUND != dwRC ) hr = HRESULT_FROM_WIN32(dwRC); } } } if ( !FindNextFile( hfSearch, &stFindFileData )) hr = HRESULT_FROM_WIN32(GetLastError()); } if ( HRESULT_FROM_WIN32(ERROR_NO_MORE_FILES) == hr || HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr ) hr = S_OK; if(INVALID_HANDLE_VALUE!=hfSearch) { FindClose(hfSearch); hfSearch=INVALID_HANDLE_VALUE; } if ( S_OK == hr ) { if ((sizeof( sBuffer )/sizeof(WCHAR)) > (wcslen( sDomainPath ) + wcslen(LOCKRENAME_FILENAME) + 1 )) { wcscpy( sBuffer, sDomainPath ); wcscat( sBuffer, L"\\" ); wcscat( sBuffer, LOCKRENAME_FILENAME ); if ( !DeleteFile( sBuffer )) hr = HRESULT_FROM_WIN32(GetLastError()); } } } return hr; } ///////////////////////////////////////////////////////////////////////////// // UnlockUser, public // // Purpose: // Unlock all the mailboxes in the domain. // This involves renaming all the mailbox lock files so that the Service // can once again access them // // Arguments: // LPWSTR psDomainName : domain of user // LPWSTR psUserName : user to unlock // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::UnlockUser( LPWSTR psDomainName, LPWSTR psUserName ) { // psDomainName - checked by BuildUserPath // psUserName - checked by BuildUserPath HRESULT hr = S_OK; WCHAR sBuffer[POP3_MAX_PATH]; WCHAR sLockFile[POP3_MAX_PATH]; WCHAR sRenameFile[POP3_MAX_PATH]; hr = BuildUserPath( psDomainName, psUserName, sBuffer, sizeof( sBuffer )/sizeof(WCHAR) ); if ( S_OK == hr ) { if (( (sizeof( sLockFile )/sizeof(WCHAR)) > ( wcslen( sBuffer ) + wcslen( LOCK_FILENAME ) + 1 )) && ( (sizeof( sRenameFile )/sizeof(WCHAR)) > ( wcslen( sBuffer ) + wcslen( LOCKRENAME_FILENAME ) + 1 ))) { wcscpy( sLockFile, sBuffer ); wcscat( sLockFile, L"\\" ); wcscpy( sRenameFile, sLockFile ); wcscat( sLockFile, LOCK_FILENAME ); wcscat( sRenameFile, LOCKRENAME_FILENAME ); if ( !MoveFile( sRenameFile, sLockFile )) { DWORD dwRC = GetLastError(); hr = HRESULT_FROM_WIN32(dwRC); } } } return hr; } ///////////////////////////////////////////////////////////////////////////// // ValidateDomain, public // // Purpose: // Validate the Domain. // This involves: // Verify it exists in SMTP and our store // // Arguments: // LPWSTR psDomainName : Domain name to validate // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::ValidateDomain( LPWSTR psDomainName ) const { // psDomainName - checked by ExistsSMTPDomain HRESULT hr; // Validate the domain in SMTP hr = ExistsSMTPDomain( psDomainName ); if ( HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ) == hr ) hr = HRESULT_FROM_WIN32( ERROR_NO_SUCH_DOMAIN ); if ( S_OK == hr ) // Validate the domain in the Store hr = ExistsStoreDomain( psDomainName ); return hr; } ////////////////////////////////////////////////////////////////////// // Implementation, private ////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// // CreateDomainMutex, protected // // Purpose: // Synchronize access for domain operations. // // Arguments: // LPWSTR psDomainName : Domain name // HANDLE *hMutex : return value // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::CreateDomainMutex( LPWSTR psDomainName, HANDLE *phMutex ) { if ( NULL == psDomainName ) return E_INVALIDARG; if ( NULL == phMutex ) return E_INVALIDARG; HRESULT hr = S_OK; WCHAR sName[POP3_MAX_DOMAIN_LENGTH+64]; *phMutex = NULL; if ( (sizeof( sName )/sizeof(WCHAR)) > ( wcslen( DOMAINMUTEX_NAME ) + wcslen( psDomainName ))) { wcscpy( sName, DOMAINMUTEX_NAME ); wcscat( sName, psDomainName ); *phMutex = CreateMutex( NULL, TRUE, sName ); } if ( NULL == *phMutex ) { hr = HRESULT_FROM_WIN32( GetLastError()); if SUCCEEDED( hr ) hr = E_FAIL; } else if ( ERROR_ALREADY_EXISTS == GetLastError() ) { hr = E_ACCESSDENIED; } return hr; } ///////////////////////////////////////////////////////////////////////////// // CreateUserMutex, protected // // Purpose: // Synchronize access for user operations. // // Arguments: // LPWSTR psDomainName : Domain name // LPWSTR psUserName : User // HANDLE *hMutex : return value // // Returns: S_OK on success, appropriate HRESULT otherwise HRESULT CP3AdminWorker::CreateUserMutex( LPWSTR psDomainName, LPWSTR psUserName, HANDLE *phMutex ) { if ( NULL == psDomainName ) return E_INVALIDARG; if ( NULL == psUserName ) return E_INVALIDARG; if ( NULL == phMutex ) return E_INVALIDARG; HRESULT hr = S_OK; WCHAR sName[POP3_MAX_ADDRESS_LENGTH+64]; *phMutex = NULL; if ( (sizeof( sName )/sizeof(WCHAR)) > ( wcslen( USERMUTEX_NAME ) + wcslen( psUserName ) + wcslen( psDomainName ) + 1)) { wcscpy( sName, USERMUTEX_NAME ); wcscat( sName, psUserName ); wcscat( sName, L"@" ); wcscat( sName, psDomainName ); *phMutex = CreateMutex( NULL, TRUE, sName ); } if ( NULL == *phMutex ) { hr = HRESULT_FROM_WIN32( GetLastError()); if SUCCEEDED( hr ) hr = E_FAIL; } else if ( ERROR_ALREADY_EXISTS == GetLastError() ) hr = E_ACCESSDENIED; return hr; } HRESULT CP3AdminWorker::AddSMTPDomain( LPWSTR psDomainName ) { HRESULT hr; WCHAR sBuffer[POP3_MAX_PATH]; _bstr_t _bstrClass( L"IIsSmtpDomain" ); _variant_t _v; CComPtr spIADsContainer; CComPtr spIADs; CComPtr spIDispatch = NULL; _bstr_t _bstrDomain = psDomainName; hr = GetSMTPDomainPath( sBuffer, NULL, sizeof( sBuffer )/sizeof( WCHAR )); if ( S_OK == hr ) hr = ADsGetObject( sBuffer, IID_IADsContainer, reinterpret_cast( &spIADsContainer )); if ( SUCCEEDED( hr )) { // Invoke the create method on the container object to create the new object of default class, in this case, IIsSmtpDomain. hr = spIADsContainer->Create( _bstrClass, _bstrDomain, &spIDispatch ); if SUCCEEDED( hr ) { // Get the newly created object hr = spIDispatch->QueryInterface( IID_IADs, reinterpret_cast( &spIADs )); if SUCCEEDED( hr ) { _v.vt = VT_I4; _v.lVal = SMTP_DELIVER; // This is what David Braun told us to do! SMTP_ALIAS; // This is what the native tool sets hr = spIADs->Put( L"RouteAction", _v ); if SUCCEEDED( hr ) hr = spIADs->SetInfo(); } } } return hr; } HRESULT CP3AdminWorker::AddStoreDomain( LPWSTR psDomainName ) { // psDomainName - checked by ExistsStoreDomain HRESULT hr; WCHAR sBuffer[POP3_MAX_PATH]; hr = ExistsStoreDomain( psDomainName ); if SUCCEEDED( hr ) hr = HRESULT_FROM_WIN32( ERROR_FILE_EXISTS ); else if ( HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ) == hr ) hr = S_OK; if SUCCEEDED( hr ) { hr = BuildDomainPath( psDomainName, sBuffer, sizeof( sBuffer )/sizeof(WCHAR) ); if ( S_OK == hr ) { if ( !CreateDirectory( sBuffer, NULL )) { hr = HRESULT_FROM_WIN32( GetLastError()); if SUCCEEDED( hr ) hr = E_FAIL; } } else if SUCCEEDED( hr ) hr = E_UNEXPECTED; } return hr; } HRESULT CP3AdminWorker::BuildDomainPath( LPCWSTR psDomainName, LPWSTR psBuffer, DWORD dwBufferSize ) const { if ( NULL == psDomainName ) return E_INVALIDARG; if ( NULL == psBuffer ) return E_INVALIDARG; USES_CONVERSION; HRESULT hr = S_OK; LPCWSTR psMailRoot; if ( NULL != m_psMachineMailRoot ) psMailRoot = m_psMachineMailRoot; else psMailRoot = CMailBox::GetMailRoot(); if ( (NULL != psMailRoot) && ( 0 < wcslen( psMailRoot )) && (wcslen( psMailRoot ) + wcslen( psDomainName ) + 1) < dwBufferSize ) { // build the path to the mail dir \MailRoot\Domain wcscpy( psBuffer, psMailRoot ); wcscat( psBuffer, L"\\" ); wcscat( psBuffer, psDomainName ); } else { hr = HRESULT_FROM_WIN32( GetLastError() ); if SUCCEEDED( hr ) hr = E_FAIL; } return hr; } HRESULT CP3AdminWorker::BuildEmailAddr( LPCWSTR psDomainName, LPCWSTR psUserName, LPWSTR psEmailAddr, DWORD dwBufferSize ) const { if ( NULL == psDomainName ) return E_INVALIDARG; if ( NULL == psUserName ) return E_INVALIDARG; if ( NULL == psEmailAddr ) return E_INVALIDARG; HRESULT hr = S_OK; if ( ( wcslen( psDomainName ) + wcslen( psUserName ) + 1 ) < dwBufferSize ) { // build the emailaddress wcscpy( psEmailAddr, psUserName ); wcscat( psEmailAddr, L"@" ); wcscat( psEmailAddr, psDomainName ); } else hr = E_UNEXPECTED; return hr; } HRESULT CP3AdminWorker::BuildEmailAddrW2A( LPCWSTR psDomainName, LPCWSTR psUserName, LPSTR psEmailAddr, DWORD dwBufferSize ) const { if ( NULL == psDomainName ) return E_INVALIDARG; if ( NULL == psUserName ) return E_INVALIDARG; if ( NULL == psEmailAddr ) return E_INVALIDARG; USES_CONVERSION; HRESULT hr = S_OK; if ( ( wcslen( psDomainName ) + wcslen( psUserName ) + 1 ) < dwBufferSize ) { // build the emailaddress strcpy( psEmailAddr, W2A( psUserName )); strcat( psEmailAddr, "@" ); strcat( psEmailAddr, W2A( psDomainName )); } else hr = E_UNEXPECTED; return hr; } HRESULT CP3AdminWorker::BuildUserPath( LPCWSTR psDomainName, LPCWSTR psUserName, LPWSTR psBuffer, DWORD dwBufferSize ) const { // psDomainName - checked by BuildDomainPath // psBuffer - checked by BuildDomainPath if ( NULL == psUserName ) return E_INVALIDARG; HRESULT hr; hr = BuildDomainPath( psDomainName, psBuffer, dwBufferSize ); if (S_OK == hr) { if ( (wcslen( psBuffer ) + wcslen( MAILBOX_PREFIX_W ) + wcslen( psUserName ) + wcslen( MAILBOX_EXTENSION_W ) + 1) < dwBufferSize ) { // build the path to the mail dir \MailRoot\Domain\User wcscat( psBuffer, L"\\" ); wcscat( psBuffer, MAILBOX_PREFIX_W ); wcscat( psBuffer, psUserName ); wcscat( psBuffer, MAILBOX_EXTENSION_W ); } else hr = E_FAIL; } return hr; } bool CP3AdminWorker::ExistsDomain( LPWSTR psDomainName ) const { // psDomainName - checked by ExistsSMTPDomain HRESULT hr; hr = ExistsSMTPDomain( psDomainName ); if SUCCEEDED( hr ) hr = ExistsStoreDomain( psDomainName ); return SUCCEEDED( hr ) ? true : false; } HRESULT CP3AdminWorker::ExistsSMTPDomain( LPWSTR psDomainName ) const { if ( NULL == psDomainName ) return E_INVALIDARG; if ( !m_isPOP3Installed ) return S_OK; // By pass checking if running in Pop2Exch scenario. HRESULT hr = E_INVALIDARG; WCHAR sBuffer[POP3_MAX_PATH]; _variant_t _v; CComPtr spIADs; hr = GetSMTPDomainPath( sBuffer, psDomainName, sizeof( sBuffer )/sizeof( WCHAR )); if ( S_OK == hr ) hr = ADsGetObject( sBuffer, IID_IADs, reinterpret_cast( &spIADs )); return hr; } HRESULT CP3AdminWorker::ExistsStoreDomain( LPWSTR psDomainName ) const { if ( NULL == psDomainName ) return E_INVALIDARG; HRESULT hr = S_OK; WCHAR sBuffer[POP3_MAX_PATH]; DWORD dwAttrib; // Valid Domain Name? || DNS_ERROR_NON_RFC_NAME == dnStatus DNS_STATUS dnStatus = DnsValidateName_W( psDomainName, DnsNameDomain ); hr = ( ERROR_SUCCESS == dnStatus ) ? S_OK : HRESULT_FROM_WIN32( ERROR_INVALID_DOMAINNAME ); if ( S_OK == hr ) { hr = BuildDomainPath( psDomainName, sBuffer, sizeof( sBuffer )/sizeof(WCHAR) ); if ( S_OK == hr ) { // Check the existance of the dir dwAttrib = GetFileAttributes( sBuffer ); if ( (ERROR_NO_FILE_ATTR == dwAttrib) || (FILE_ATTRIBUTE_DIRECTORY != ( FILE_ATTRIBUTE_DIRECTORY & dwAttrib )) ) { // Domain does not exist! hr = HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ); } } else if SUCCEEDED( hr ) hr = E_UNEXPECTED; } return hr; } HRESULT CP3AdminWorker::GetSMTPDomainPath( LPWSTR psBuffer, LPWSTR psSuffix, DWORD dwBufferSize ) const { if ( NULL == psBuffer ) return E_INVALIDARG; HRESULT hr = S_OK; DWORD dwSuffixLength = 0; if ( NULL != psSuffix ) dwSuffixLength = wcslen( psSuffix ) + 1; if ( NULL == m_psMachineName ) { // Local if ( (wcslen( ADS_SMTPDOMAIN_PATH_LOCAL ) + dwSuffixLength) < dwBufferSize ) wcscpy( psBuffer, ADS_SMTPDOMAIN_PATH_LOCAL ); else hr = E_FAIL; } else { // Remote if ( (wcslen( ADS_SMTPDOMAIN_PATH_REMOTE ) + wcslen( m_psMachineName ) + dwSuffixLength) < dwBufferSize ) swprintf( psBuffer, ADS_SMTPDOMAIN_PATH_REMOTE, m_psMachineName ); else hr = E_FAIL; } if ( S_OK == hr && NULL != psSuffix ) { wcscat( psBuffer, L"/" ); wcscat( psBuffer, psSuffix ); } return hr; } HRESULT CP3AdminWorker::RemoveSMTPDomain( LPWSTR psDomainName ) { HRESULT hr; WCHAR sBuffer[POP3_MAX_PATH]; _bstr_t _bstrClass( L"IIsSmtpDomain" ); _variant_t _v; CComPtr spIADsContainer; CComPtr spIADs; _bstr_t _bstrDomain = psDomainName; hr = GetSMTPDomainPath( sBuffer, NULL, sizeof( sBuffer )/sizeof( WCHAR )); if ( S_OK == hr ) hr = ADsGetObject( sBuffer, IID_IADsContainer, reinterpret_cast( &spIADsContainer )); if ( SUCCEEDED( hr )) { hr = spIADsContainer->Delete( _bstrClass, _bstrDomain ); if SUCCEEDED( hr ) { // Commit the change hr = spIADsContainer->QueryInterface( IID_IADs, reinterpret_cast( &spIADs )); if SUCCEEDED( hr ) hr = spIADs->SetInfo(); } } return hr; } HRESULT CP3AdminWorker::RemoveStoreDomain( LPWSTR psDomainName ) { // psDomainName - checked by ExistsStoreDomain HRESULT hr = S_OK; WCHAR sBuffer[POP3_MAX_PATH]; hr = ExistsStoreDomain( psDomainName ); if SUCCEEDED( hr ) { hr = BuildDomainPath( psDomainName, sBuffer, sizeof( sBuffer )/sizeof(WCHAR)); if ( S_OK == hr ) { if ( !BDeleteDirTree( sBuffer )) { hr = HRESULT_FROM_WIN32( GetLastError()); if SUCCEEDED( hr ) hr = E_FAIL; } } else if SUCCEEDED( hr ) hr = E_UNEXPECTED; } return hr; }