You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3252 lines
107 KiB
3252 lines
107 KiB
// P3AdminWorker.cpp: implementation of the CP3AdminWorker class.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
#include "stdafx.h"
|
|
#include "P3AdminWorker.h"
|
|
#include "P3Admin.h"
|
|
|
|
#include <mailbox.h>
|
|
#include <MetabaseUtil.h>
|
|
#include <POP3RegKeys.h>
|
|
#include <util.h>
|
|
#include <servutil.h>
|
|
#include <POP3Server.h>
|
|
#include <POP3Auth.h>
|
|
#include <AuthID.h>
|
|
|
|
#include <seo.h>
|
|
#include <smtpguid.h>
|
|
#include <Iads.h>
|
|
#include <Adshlp.h>
|
|
#include <smtpinet.h>
|
|
#include <inetinfo.h>
|
|
#include <windns.h>
|
|
#include <sddl.h>
|
|
#include <Aclapi.h>
|
|
#include <lm.h>
|
|
|
|
#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<LPVOID*>( &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<IAuthMethod> 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<LPVOID*>( 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<IAuthMethods> 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<IADsContainer> spIADsContainer;
|
|
CComPtr<IUnknown> spIUnk;
|
|
|
|
*pp = NULL;
|
|
hr = GetSMTPDomainPath( sBuffer, NULL, sizeof( sBuffer )/sizeof( WCHAR ));
|
|
if ( S_OK == hr )
|
|
hr = ADsGetObject( sBuffer, IID_IADsContainer, reinterpret_cast<LPVOID*>( &spIADsContainer ));
|
|
if SUCCEEDED( hr )
|
|
hr = spIADsContainer->get__NewEnum( &spIUnk );
|
|
if SUCCEEDED( hr )
|
|
hr = spIUnk->QueryInterface( IID_IEnumVARIANT, reinterpret_cast<LPVOID*>( 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 <AuthID.h>
|
|
// 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.
|
|
// <mailbox> ::= <local-part> "@" <domain>
|
|
// <local-part> ::= <dot-string> | <quoted-string>
|
|
// <dot-string> ::= <string> | <string> "." <dot-string> -> . 0x2e
|
|
// <quoted-string> ::= """ <qtext> """ -> " 0x22 not going to allow this because it creates other complications
|
|
// <string> ::= <char> | <char> <string>
|
|
// <char> ::= <c> | "\" <x>
|
|
// <x> ::= any one of the 128 ASCII characters (no exceptions) -> This means any thing is permitted, even the special characters!
|
|
// <c> ::= any one of the 128 ASCII characters,
|
|
// but not any <special> or <SP>
|
|
// <special> ::= "<" | ">" | "(" | ")" | "[" | "]" | "\" | "."
|
|
// | "," | ";" | ":" | "@" """ | the control
|
|
// characters (ASCII codes 0 through 31 inclusive and 127)
|
|
// <SP> ::= 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<IP3Config> spIConfig;
|
|
CComPtr<IP3Domains> spIDomains;
|
|
CComPtr<IP3Domain> spIDomain = NULL;
|
|
CComPtr<IEnumVARIANT> spIEnumVARIANT;
|
|
|
|
VariantInit( &v );
|
|
hr = CoCreateInstance( __uuidof( P3Config ), NULL, CLSCTX_ALL, __uuidof( IP3Config ),reinterpret_cast<LPVOID *>( &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<void**>( &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<IEventBindingManager> spIBindingManager;
|
|
CComPtr<IEventBindings> spIBindings;
|
|
CComPtr<IEventBinding> spIBinding;
|
|
CComPtr<IEventPropertyBag> spISourceProps;
|
|
|
|
CComPtr<IEventUtil> spIUtil;
|
|
|
|
/////////////////////////////
|
|
// Bind our SMTP Store Driver
|
|
/////////////////////////////
|
|
|
|
hr = CoCreateInstance( __uuidof( CEventUtil ), NULL, CLSCTX_ALL, __uuidof( IEventUtil ),reinterpret_cast<LPVOID*>( &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<long>(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<IADs> spIADs = NULL;
|
|
CComPtr<IEnumVARIANT> 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<void**>( &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<IAuthMethod> 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<IAuthMethod> 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<IADsContainer> spIADsContainer;
|
|
CComPtr<IADs> spIADs;
|
|
CComPtr<IDispatch> 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<LPVOID*>( &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<LPVOID*>( &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<IADs> spIADs;
|
|
|
|
hr = GetSMTPDomainPath( sBuffer, psDomainName, sizeof( sBuffer )/sizeof( WCHAR ));
|
|
if ( S_OK == hr )
|
|
hr = ADsGetObject( sBuffer, IID_IADs, reinterpret_cast<LPVOID*>( &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<IADsContainer> spIADsContainer;
|
|
CComPtr<IADs> spIADs;
|
|
_bstr_t _bstrDomain = psDomainName;
|
|
|
|
hr = GetSMTPDomainPath( sBuffer, NULL, sizeof( sBuffer )/sizeof( WCHAR ));
|
|
if ( S_OK == hr )
|
|
hr = ADsGetObject( sBuffer, IID_IADsContainer, reinterpret_cast<LPVOID*>( &spIADsContainer ));
|
|
if ( SUCCEEDED( hr ))
|
|
{
|
|
hr = spIADsContainer->Delete( _bstrClass, _bstrDomain );
|
|
if SUCCEEDED( hr )
|
|
{ // Commit the change
|
|
hr = spIADsContainer->QueryInterface( IID_IADs, reinterpret_cast<LPVOID*>( &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;
|
|
}
|
|
|