Leaked source code of windows server 2003
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

// 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;
}