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

  1. // P3AdminWorker.cpp: implementation of the CP3AdminWorker class.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #include "stdafx.h"
  5. #include "P3AdminWorker.h"
  6. #include "P3Admin.h"
  7. #include <mailbox.h>
  8. #include <MetabaseUtil.h>
  9. #include <POP3RegKeys.h>
  10. #include <util.h>
  11. #include <servutil.h>
  12. #include <POP3Server.h>
  13. #include <POP3Auth.h>
  14. #include <AuthID.h>
  15. #include <seo.h>
  16. #include <smtpguid.h>
  17. #include <Iads.h>
  18. #include <Adshlp.h>
  19. #include <smtpinet.h>
  20. #include <inetinfo.h>
  21. #include <windns.h>
  22. #include <sddl.h>
  23. #include <Aclapi.h>
  24. #include <lm.h>
  25. #define DOMAINMUTEX_NAME L"Global\\P3AdminWorkerDomain-"
  26. #define USERMUTEX_NAME L"Global\\P3AdminWorkerUser-"
  27. #define ERROR_NO_FILE_ATTR 0xffffffff
  28. DWORD SetMailBoxDACL(LPWSTR wszPath,PSECURITY_DESCRIPTOR pSD, DWORD dwLevel)
  29. {
  30. HANDLE hFind;
  31. DWORD dwLastErr;
  32. WIN32_FIND_DATA FileInfo;
  33. WCHAR wszMailFilter[POP3_MAX_PATH+6];
  34. WCHAR wszFullPathFileName[POP3_MAX_PATH];
  35. DWORD dwRt=ERROR_SUCCESS;
  36. if(NULL == wszPath || NULL == pSD)
  37. {
  38. return ERROR_INVALID_DATA;
  39. }
  40. //Now set everything in the directory
  41. wsprintf(wszMailFilter,
  42. L"%s\\*.*",
  43. wszPath);
  44. hFind=FindFirstFile(wszMailFilter,
  45. &(FileInfo));
  46. if(INVALID_HANDLE_VALUE == hFind)
  47. {
  48. dwLastErr= GetLastError();
  49. if(ERROR_FILE_NOT_FOUND == dwLastErr ||
  50. ERROR_SUCCESS == dwLastErr)
  51. {
  52. return ERROR_SUCCESS;
  53. }
  54. else
  55. {
  56. return dwLastErr;
  57. }
  58. }
  59. BOOL bMoreFile=TRUE;
  60. while(bMoreFile)
  61. {
  62. if(wcscmp(FileInfo.cFileName, L".")!=0 &&
  63. wcscmp(FileInfo.cFileName, L"..")!=0)
  64. {
  65. wnsprintf(wszFullPathFileName,sizeof(wszFullPathFileName)/sizeof(WCHAR),L"%s\\%s", wszPath, FileInfo.cFileName);
  66. wszFullPathFileName[sizeof(wszFullPathFileName)/sizeof(WCHAR)-1]=0;
  67. if(!SetFileSecurity(wszFullPathFileName, DACL_SECURITY_INFORMATION, pSD))
  68. {
  69. dwRt=GetLastError();
  70. }
  71. if( (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) &&
  72. (ERROR_SUCCESS ==dwRt) && (dwLevel > 0) )
  73. {
  74. //We need to go down the dir
  75. dwRt=SetMailBoxDACL(wszFullPathFileName, pSD, dwLevel-1);
  76. }
  77. if( ERROR_SUCCESS != dwRt)
  78. {
  79. break;
  80. }
  81. }
  82. bMoreFile=FindNextFile(hFind,&FileInfo);
  83. }
  84. FindClose(hFind);
  85. return dwRt;
  86. }
  87. //////////////////////////////////////////////////////////////////////
  88. // Construction/Destruction
  89. //////////////////////////////////////////////////////////////////////
  90. CP3AdminWorker::CP3AdminWorker() :
  91. m_psMachineName(NULL), m_psMachineMailRoot(NULL), m_bImpersonation(false), m_isPOP3Installed(true)
  92. {
  93. // TODO: dougb this is temporary code to force AD to cache for us, should be removed
  94. WCHAR sBuffer[MAX_PATH*2];
  95. HRESULT hr = GetSMTPDomainPath( sBuffer, L"", MAX_PATH*2 );
  96. if ( S_OK == hr )
  97. {
  98. sBuffer[ wcslen( sBuffer ) - 1 ] = 0; //Remove the last /
  99. hr = ADsGetObject( sBuffer, IID_IADs, reinterpret_cast<LPVOID*>( &m_spTemporaryFixIADs ));
  100. }
  101. DWORD dwVersion;
  102. if (( ERROR_SUCCESS == RegQueryVersion( dwVersion, NULL )) && ( 0 == dwVersion ))
  103. m_isPOP3Installed = false;
  104. }
  105. CP3AdminWorker::~CP3AdminWorker()
  106. {
  107. if ( NULL != m_psMachineName )
  108. delete m_psMachineName;
  109. if ( NULL != m_psMachineMailRoot )
  110. delete m_psMachineMailRoot;
  111. }
  112. //////////////////////////////////////////////////////////////////////
  113. // Implementation, public
  114. //////////////////////////////////////////////////////////////////////
  115. /////////////////////////////////////////////////////////////////////////////
  116. // AddDomain, public
  117. //
  118. // Purpose:
  119. // Set the Meta base options required to add a new Local domain to the SMTP service.
  120. // Add the domain to our Store.
  121. // This involves:
  122. // Create a new object of type IIsSmtpDomain
  123. // Setting the RouteAction Property to 16
  124. // Creating a directory in the mailroot.
  125. //
  126. // Arguments:
  127. // LPWSTR psDomainName : Domain name to add
  128. //
  129. // Returns: S_OK on success, appropriate HRESULT otherwise
  130. HRESULT CP3AdminWorker::AddDomain( LPWSTR psDomainName )
  131. {
  132. if ( NULL == psDomainName )
  133. return E_INVALIDARG;
  134. HRESULT hr, hr2 = S_OK;
  135. // Valid Domain Name? || DNS_ERROR_NON_RFC_NAME == dnStatus
  136. DNS_STATUS dnStatus = DnsValidateName_W( psDomainName, DnsNameDomain );
  137. hr = ( ERROR_SUCCESS == dnStatus ) ? S_OK : HRESULT_FROM_WIN32( ERROR_INVALID_DOMAINNAME );
  138. // Also need to block domain names with a trailing .
  139. if ( S_OK == hr )
  140. {
  141. if ( L'.' == *(psDomainName + wcslen( psDomainName ) - 1) )
  142. hr = HRESULT_FROM_WIN32( ERROR_INVALID_DOMAINNAME );
  143. }
  144. // Do we need to add this Domain?
  145. // Validate the domain in SMTP
  146. if ( S_OK == hr )
  147. hr = ExistsSMTPDomain( psDomainName );
  148. if ( S_OK == hr )
  149. hr = HRESULT_FROM_WIN32( ERROR_DOMAIN_EXISTS );
  150. else if ( HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ) == hr )
  151. hr = S_OK;
  152. // Validate the domain in the Store
  153. if ( S_OK == hr )
  154. hr = ExistsStoreDomain( psDomainName );
  155. if ( S_OK == hr )
  156. hr2 = ERROR_FILE_EXISTS;
  157. else if ( HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ) == hr )
  158. hr = S_OK;
  159. if ( S_OK == hr )
  160. {
  161. hr = AddSMTPDomain( psDomainName );
  162. if ( S_OK == hr && ERROR_FILE_EXISTS != hr2 )
  163. {
  164. hr = AddStoreDomain( psDomainName );
  165. if ( S_OK != hr )
  166. RemoveSMTPDomain( psDomainName );
  167. }
  168. }
  169. return ( S_OK == hr ) ? hr2 : hr;
  170. }
  171. /////////////////////////////////////////////////////////////////////////////
  172. // AddUser, public
  173. //
  174. // Purpose:
  175. // Create a new user mailbox.
  176. // This involves:
  177. // Verify the domain exists.
  178. // Create the mailbox directory and lock file.
  179. //
  180. // Arguments:
  181. // LPWSTR psDomainName : Domain name to add to
  182. // LPWSTR psUserName : User name to add
  183. //
  184. // Returns: S_OK on success, appropriate HRESULT otherwise
  185. HRESULT CP3AdminWorker::AddUser( LPWSTR psDomainName, LPWSTR psUserName )
  186. {
  187. // psDomainName - checked by ValidateDomain
  188. // psBuffer - checked by BuildEmailAddrW2A
  189. HRESULT hr = S_OK;
  190. CMailBox mailboxX;
  191. WCHAR sEmailAddr[POP3_MAX_ADDRESS_LENGTH];
  192. bool bLocked;
  193. // Validate the domain
  194. if ( S_OK == hr )
  195. hr = ValidateDomain( psDomainName );
  196. // Validate the user
  197. if ( S_OK == hr )
  198. {
  199. if ( !isValidMailboxName( psUserName ))
  200. hr = HRESULT_FROM_WIN32( ERROR_BAD_USERNAME );
  201. }
  202. if ( S_OK == hr )
  203. bLocked = IsDomainLocked( psDomainName );
  204. if ( SUCCEEDED( hr ))
  205. { // See if the mailbox already exists
  206. hr = BuildEmailAddr( psDomainName, psUserName, sEmailAddr, sizeof( sEmailAddr ) / sizeof (WCHAR) );
  207. if ( S_OK == hr )
  208. hr = MailboxSetRemote();
  209. if ( S_OK == hr )
  210. { // Do we need to enforce uniqueness across domains?
  211. CComPtr<IAuthMethod> spIAuthMethod;
  212. BSTR bstrAuthType = NULL;
  213. hr = GetCurrentAuthentication( &spIAuthMethod );
  214. if ( S_OK == hr )
  215. hr = spIAuthMethod->get_ID( &bstrAuthType );
  216. if ( S_OK == hr )
  217. {
  218. if ( 0 == _wcsicmp( bstrAuthType, SZ_AUTH_ID_LOCAL_SAM ) )
  219. {
  220. hr = SearchDomainsForMailbox( psUserName, NULL );
  221. if ( S_OK == hr ) // The Mailbox exists in at least one domain
  222. {
  223. if ( mailboxX.OpenMailBox( sEmailAddr ))
  224. {
  225. mailboxX.CloseMailBox();
  226. hr = HRESULT_FROM_WIN32( ERROR_FILE_EXISTS );
  227. }
  228. else
  229. hr = HRESULT_FROM_WIN32( ERROR_USER_EXISTS );
  230. }
  231. else if ( HRESULT_FROM_WIN32( ERROR_NO_SUCH_USER ) == hr ) // This is what we were hoping for
  232. hr = S_OK;
  233. }
  234. SysFreeString( bstrAuthType );
  235. }
  236. }
  237. if ( S_OK == hr )
  238. {
  239. if ( mailboxX.OpenMailBox( sEmailAddr ))
  240. {
  241. mailboxX.CloseMailBox();
  242. hr = HRESULT_FROM_WIN32( ERROR_FILE_EXISTS );
  243. }
  244. else
  245. {
  246. LPWSTR psMachineName = NULL;
  247. if ( !mailboxX.CreateMailBox( sEmailAddr ))
  248. hr = E_FAIL;
  249. if ( S_OK == hr && bLocked )
  250. LockUser( psDomainName, psUserName ); // Hate to fail because of problem here, therefore ignore return code
  251. }
  252. }
  253. MailboxResetRemote();
  254. }
  255. return hr;
  256. }
  257. /////////////////////////////////////////////////////////////////////////////
  258. // ControlService, public
  259. //
  260. // Purpose:
  261. // Ask the Service Control Manager to send a cotnrol code to the service.
  262. //
  263. // Arguments:
  264. //
  265. // Returns: S_OK on success, appropriate HRESULT otherwise
  266. HRESULT CP3AdminWorker::ControlService( LPWSTR psService, DWORD dwControl )
  267. {
  268. if ( NULL == psService )
  269. return E_INVALIDARG;
  270. if ( 0 == _wcsicmp( POP3_SERVICE_NAME, psService ) ||
  271. 0 == _wcsicmp( SMTP_SERVICE_NAME_W, psService ) ||
  272. 0 == _wcsicmp( IISADMIN_SERVICE_NAME, psService ) ||
  273. 0 == _wcsicmp( W3_SERVICE_NAME, psService )
  274. )
  275. return _ControlService( psService, dwControl, m_psMachineName );
  276. else
  277. return E_INVALIDARG;
  278. }
  279. /////////////////////////////////////////////////////////////////////////////
  280. // CreateQuotaSIDFile, public
  281. //
  282. // Purpose:
  283. // Create the Quota file for the mailbox.
  284. // A permanent quota file is created which contains the SID of the user and is used
  285. // by the SMTP service to assign ownership of new mail files.
  286. //
  287. // Arguments:
  288. // LPWSTR psDomainName : domain of mailbox
  289. // LPWSTR psMailboxName : mailbox
  290. // PSID *ppSIDOwner : Pointer to buffer to receive Owner SID (must be deleted by caller)
  291. // LPWSTR psMachineName : system name (remote computer) can be NULL
  292. // LPWSTR psUserName : user name
  293. //
  294. // Returns: S_OK on success, appropriate HRESULT otherwise
  295. HRESULT CP3AdminWorker::CreateQuotaSIDFile( LPWSTR psDomainName, LPWSTR psMailboxName, BSTR bstrAuthType, LPWSTR psMachineName, LPWSTR psUserName )
  296. {
  297. // psDomainName - checked by BuildUserPath
  298. // psUserName - checked by BuildUserPath
  299. // bstrAuthType - checked by GetSID
  300. if ( NULL == psMachineName )
  301. psMachineName = m_psMachineName;
  302. HRESULT hr = S_OK;
  303. WCHAR sQuotaFile[POP3_MAX_PATH];
  304. HANDLE hQuotaFile;
  305. hr = BuildUserPath( psDomainName, psMailboxName, sQuotaFile, sizeof( sQuotaFile )/sizeof(WCHAR) );
  306. if ( S_OK == hr )
  307. {
  308. if ( (sizeof( sQuotaFile )/sizeof(WCHAR)) > ( wcslen( sQuotaFile ) + wcslen( QUOTA_FILENAME_W ) + 1 ))
  309. {
  310. wcscat( sQuotaFile, L"\\" );
  311. wcscat( sQuotaFile, QUOTA_FILENAME_W );
  312. hQuotaFile = CreateFile( sQuotaFile, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
  313. if ( INVALID_HANDLE_VALUE != hQuotaFile )
  314. {
  315. PSID pSIDOwner = NULL;
  316. DWORD dwOwnerSID, dwBytesWritten;
  317. hr = GetQuotaSID( bstrAuthType, psUserName, psMachineName, &pSIDOwner, &dwOwnerSID );
  318. if ( S_OK == hr )
  319. {
  320. if ( !WriteFile( hQuotaFile, pSIDOwner, dwOwnerSID, &dwBytesWritten, NULL ))
  321. hr = HRESULT_FROM_WIN32(GetLastError());
  322. delete [] pSIDOwner;
  323. }
  324. CloseHandle( hQuotaFile );
  325. if ( S_OK != hr )
  326. DeleteFile( sQuotaFile );
  327. }
  328. else
  329. hr = HRESULT_FROM_WIN32(GetLastError());
  330. }
  331. else
  332. hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
  333. }
  334. return hr;
  335. }
  336. /////////////////////////////////////////////////////////////////////////////
  337. // GetConfirmAddUser, public
  338. //
  339. // Purpose:
  340. // Get the Confirm Add User registry key.
  341. //
  342. // Arguments:
  343. // BOOL *pbConfirm : current value
  344. //
  345. // Returns: S_OK on success, appropriate HRESULT otherwise
  346. HRESULT CP3AdminWorker::GetConfirmAddUser( BOOL *pbConfirm )
  347. {
  348. if ( NULL == pbConfirm )
  349. return E_INVALIDARG;
  350. DWORD dwValue;
  351. long lRC = RegQueryConfirmAddUser( dwValue, m_psMachineName );
  352. if ( ERROR_SUCCESS == lRC )
  353. {
  354. *pbConfirm = (dwValue) ? TRUE : FALSE;
  355. return S_OK;
  356. }
  357. return HRESULT_FROM_WIN32( lRC );
  358. }
  359. /////////////////////////////////////////////////////////////////////////////
  360. // GetAuthenticationMethods, public
  361. //
  362. // Purpose:
  363. // Get an initialized IAuthMethods interface pointer
  364. //
  365. // Arguments:
  366. // IAuthMethods* *ppIAuthMethods: return interface pointer to initialized IAuthMethods
  367. //
  368. // Returns: S_OK on success, appropriate HRESULT otherwise
  369. HRESULT CP3AdminWorker::GetAuthenticationMethods( IAuthMethods* *ppIAuthMethods ) const
  370. {
  371. if ( NULL == ppIAuthMethods )
  372. return E_INVALIDARG;
  373. HRESULT hr;
  374. hr = CoCreateInstance( __uuidof( AuthMethods ), NULL, CLSCTX_INPROC_SERVER, __uuidof( IAuthMethods ), reinterpret_cast<LPVOID*>( ppIAuthMethods ));
  375. if ( S_OK == hr )
  376. { // If necessary set the machine name property
  377. if ( NULL != m_psMachineName )
  378. {
  379. _bstr_t _bstrMachineName = m_psMachineName;
  380. hr = (*ppIAuthMethods)->put_MachineName( _bstrMachineName );
  381. }
  382. }
  383. assert( S_OK == hr );
  384. return hr;
  385. }
  386. /////////////////////////////////////////////////////////////////////////////
  387. // GetCurrentAuthentication, public
  388. //
  389. // Purpose:
  390. // Get an initialized IAuthMethod interface pointer for the current active Authentication method
  391. //
  392. // Arguments:
  393. // IAuthMethod* *ppIAuthMethod: return interface pointer to initialized IAuthMethod
  394. //
  395. // Returns: S_OK on success, appropriate HRESULT otherwise
  396. HRESULT CP3AdminWorker::GetCurrentAuthentication( IAuthMethod* *ppIAuthMethod ) const
  397. {
  398. if ( NULL == ppIAuthMethod )
  399. return E_INVALIDARG;
  400. HRESULT hr;
  401. CComPtr<IAuthMethods> spIAuthMethods;
  402. _variant_t _v;
  403. hr = GetAuthenticationMethods( &spIAuthMethods );
  404. if ( S_OK == hr )
  405. hr = spIAuthMethods->get_CurrentAuthMethod( &_v );
  406. if ( S_OK == hr )
  407. hr = spIAuthMethods->get_Item( _v, ppIAuthMethod );
  408. return hr;
  409. }
  410. /////////////////////////////////////////////////////////////////////////////
  411. // GetDomainCount, public
  412. //
  413. // Purpose:
  414. // Get an Enumerator for the SMTP domains in the Metabase
  415. //
  416. // Arguments:
  417. // int *piCount : domain count
  418. //
  419. // Returns: S_OK on success, appropriate HRESULT otherwise
  420. HRESULT CP3AdminWorker::GetDomainCount( ULONG *piCount)
  421. {
  422. if ( NULL == piCount )
  423. return E_INVALIDARG;
  424. HRESULT hr = S_OK;
  425. HANDLE hfSearch;
  426. WCHAR sBuffer[POP3_MAX_PATH];
  427. WIN32_FIND_DATA stFindFileData;
  428. _bstr_t _bstr;
  429. *piCount = 0;
  430. hr = GetMailroot( sBuffer, sizeof( sBuffer )/sizeof(WCHAR));
  431. // Directory Search
  432. if ( S_OK == hr )
  433. {
  434. if ( ( wcslen( sBuffer ) + 2 ) < sizeof( sBuffer )/sizeof(WCHAR))
  435. {
  436. wcscat( sBuffer, L"\\*" );
  437. hfSearch = FindFirstFileEx( sBuffer, FindExInfoStandard, &stFindFileData, FindExSearchLimitToDirectories, NULL, 0 );
  438. if ( INVALID_HANDLE_VALUE == hfSearch )
  439. hr = HRESULT_FROM_WIN32(GetLastError());
  440. while ( S_OK == hr )
  441. { // Count directories
  442. if ( FILE_ATTRIBUTE_DIRECTORY == ( FILE_ATTRIBUTE_DIRECTORY & stFindFileData.dwFileAttributes ))
  443. {
  444. _bstr = stFindFileData.cFileName;
  445. if ( S_OK == ExistsSMTPDomain( _bstr ))
  446. (*piCount) += 1;
  447. }
  448. if ( !FindNextFile( hfSearch, &stFindFileData ))
  449. hr = HRESULT_FROM_WIN32(GetLastError());
  450. }
  451. if ( HRESULT_FROM_WIN32(ERROR_NO_MORE_FILES) == hr || HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr )
  452. hr = S_OK;
  453. if(INVALID_HANDLE_VALUE!=hfSearch)
  454. {
  455. FindClose(hfSearch);
  456. hfSearch=INVALID_HANDLE_VALUE;
  457. }
  458. }
  459. else
  460. hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  461. }
  462. return hr;
  463. }
  464. /////////////////////////////////////////////////////////////////////////////
  465. // GetNewEnum, public
  466. //
  467. // Purpose:
  468. // Get an Enumerator for the SMTP domains in the Metabase
  469. //
  470. // Arguments:
  471. // IEnumVARIANT **pp : the returned Enumerator object
  472. //
  473. // Returns: S_OK on success, appropriate HRESULT otherwise
  474. HRESULT CP3AdminWorker::GetDomainEnum( IEnumVARIANT **pp )
  475. {
  476. if ( NULL == pp )
  477. return E_POINTER;
  478. HRESULT hr = E_FAIL;
  479. WCHAR sBuffer[POP3_MAX_PATH];
  480. _variant_t _v;
  481. CComPtr<IADsContainer> spIADsContainer;
  482. CComPtr<IUnknown> spIUnk;
  483. *pp = NULL;
  484. hr = GetSMTPDomainPath( sBuffer, NULL, sizeof( sBuffer )/sizeof( WCHAR ));
  485. if ( S_OK == hr )
  486. hr = ADsGetObject( sBuffer, IID_IADsContainer, reinterpret_cast<LPVOID*>( &spIADsContainer ));
  487. if SUCCEEDED( hr )
  488. hr = spIADsContainer->get__NewEnum( &spIUnk );
  489. if SUCCEEDED( hr )
  490. hr = spIUnk->QueryInterface( IID_IEnumVARIANT, reinterpret_cast<LPVOID*>( pp ));
  491. return hr;
  492. }
  493. /////////////////////////////////////////////////////////////////////////////
  494. // GetDomainLock, public
  495. //
  496. // Purpose:
  497. // Determine if the domain is locked.
  498. //
  499. // Arguments:
  500. // LPWSTR psDomainName : Domain name to check lock
  501. // BOOL *pisLocked : return value
  502. //
  503. // Returns: S_OK on success, appropriate HRESULT otherwise
  504. HRESULT CP3AdminWorker::GetDomainLock( LPWSTR psDomainName, BOOL *pisLocked )
  505. {
  506. // psDomainName - checked by CreateDomainMutex
  507. if ( NULL == pisLocked )
  508. return E_INVALIDARG;
  509. HRESULT hr = S_OK;
  510. HANDLE hMutex = NULL;
  511. // Create a Mutex Name for this domain to ensure we are the only one accessing it.
  512. hr = CreateDomainMutex( psDomainName, &hMutex );
  513. // Validate
  514. if ( S_OK == hr )
  515. {
  516. hr = ValidateDomain( psDomainName );
  517. }
  518. // Lock all the Mailboxes
  519. if ( S_OK == hr )
  520. *pisLocked = IsDomainLocked( psDomainName ) ? TRUE : FALSE;
  521. // Cleanup
  522. if ( NULL != hMutex )
  523. CloseHandle( hMutex );
  524. return hr;
  525. }
  526. /////////////////////////////////////////////////////////////////////////////
  527. // GetQuotaSID, public
  528. //
  529. // Purpose:
  530. // Create the Quota file for the mailbox.
  531. // A permanent quota file is created which contains the SID of the user and is used
  532. // by the SMTP service to assign ownership of new mail files.
  533. //
  534. // Arguments:
  535. // BSTR bstrAuthType : Authentication type <AuthID.h>
  536. // LPWSTR psUserName : user to lock
  537. // LPWSTR psMachineName : system name (remote computer) can be NULL
  538. // PSID *ppSIDOwner : Pointer to buffer to receive Owner SID (must be deleted by caller)
  539. // LPDWORD pdwOwnerSID : Pointer to variable thate receives the size of the Owner SID
  540. //
  541. // Returns: S_OK on success, appropriate HRESULT otherwise
  542. HRESULT CP3AdminWorker::GetQuotaSID( BSTR bstrAuthType, LPWSTR psUserName, LPWSTR psMachineName, PSID *ppSIDOwner, LPDWORD pdwOwnerSID )
  543. {
  544. if ( NULL == bstrAuthType || NULL == psUserName || NULL == ppSIDOwner || NULL == pdwOwnerSID )
  545. return E_INVALIDARG;
  546. 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 ))
  547. return E_INVALIDARG;
  548. // psMachineName == NULL is valid!
  549. HRESULT hr = S_OK;
  550. DWORD dwDomSize = 0, dwSize = 0;
  551. BOOL bRC;
  552. LPWSTR psDomainName = NULL;
  553. LPWSTR psAccountName = NULL;
  554. PSID pSIDOwner = NULL;
  555. SID_NAME_USE sidNameUse;
  556. *pdwOwnerSID = 0;
  557. *ppSIDOwner = NULL;
  558. if ( 0 == _wcsicmp( SZ_AUTH_ID_DOMAIN_AD, bstrAuthType ))
  559. { // UPN name or SAM name?
  560. if ( NULL == wcsrchr( psUserName, L'@' ))
  561. { // SAM name
  562. NET_API_STATUS netStatus;
  563. LPWSTR psNameBuffer;
  564. NETSETUP_JOIN_STATUS enumJoinStatus;
  565. netStatus = NetGetJoinInformation( psMachineName, &psNameBuffer, &enumJoinStatus );
  566. if ( NERR_Success == netStatus )
  567. {
  568. psAccountName = new WCHAR[ wcslen( psUserName ) + wcslen( psNameBuffer ) + 3 ];
  569. if ( NULL != psAccountName )
  570. wsprintf( psAccountName, L"%s\\%s", psNameBuffer, psUserName );
  571. else
  572. hr = E_OUTOFMEMORY;
  573. NetApiBufferFree( psNameBuffer );
  574. }
  575. else
  576. hr = E_OUTOFMEMORY;
  577. }
  578. else
  579. { // UPN name
  580. psAccountName = new WCHAR[ wcslen( psUserName ) + 1 ];
  581. if ( NULL != psAccountName )
  582. wcscpy( psAccountName, psUserName );
  583. else
  584. hr = E_OUTOFMEMORY;
  585. }
  586. }
  587. if ( 0 == _wcsicmp( SZ_AUTH_ID_LOCAL_SAM, bstrAuthType ))
  588. {
  589. if ( NULL != psMachineName )
  590. {
  591. psAccountName = new WCHAR[ wcslen( psUserName ) + wcslen( psMachineName ) + 3 ];
  592. if ( NULL != psAccountName )
  593. wsprintf( psAccountName, L"%s\\%s", psMachineName, psUserName );
  594. else
  595. hr = E_OUTOFMEMORY;
  596. }
  597. else
  598. {
  599. WCHAR sMachineName[MAX_COMPUTERNAME_LENGTH+1];
  600. DWORD dwSize = sizeof(sMachineName)/sizeof(WCHAR);
  601. if ( !GetComputerName( sMachineName, &dwSize ))
  602. hr = HRESULT_FROM_WIN32( GetLastError());
  603. if ( S_OK == hr )
  604. {
  605. psAccountName = new WCHAR[ wcslen( psUserName ) + wcslen( sMachineName ) + 3 ];
  606. if ( NULL != psAccountName )
  607. wsprintf( psAccountName, L"%s\\%s", sMachineName, psUserName );
  608. else
  609. hr = E_OUTOFMEMORY;
  610. }
  611. }
  612. }
  613. if ( 0 == _wcsicmp( SZ_AUTH_ID_MD5_HASH, bstrAuthType ))
  614. psAccountName = psUserName;
  615. if ( S_OK == hr )
  616. {
  617. bRC = LookupAccountNameW( psMachineName, psAccountName, NULL, pdwOwnerSID, NULL, &dwDomSize, &sidNameUse );
  618. if ( !bRC && ( ERROR_INSUFFICIENT_BUFFER == GetLastError()) && (0 < *pdwOwnerSID) && (0 < dwDomSize) )
  619. {
  620. SetLastError( ERROR_OUTOFMEMORY );
  621. pSIDOwner = new BYTE[*pdwOwnerSID];
  622. if ( NULL != pSIDOwner )
  623. {
  624. psDomainName = new WCHAR[dwDomSize];
  625. if ( NULL != psDomainName )
  626. {
  627. if ( LookupAccountNameW( psMachineName, psAccountName, pSIDOwner, pdwOwnerSID, psDomainName, &dwDomSize, &sidNameUse ))
  628. {
  629. *ppSIDOwner = pSIDOwner;
  630. SetLastError( ERROR_SUCCESS );
  631. }
  632. delete [] psDomainName;
  633. }
  634. if ( ERROR_SUCCESS != GetLastError() )
  635. delete [] pSIDOwner;
  636. }
  637. }
  638. if ( ERROR_SUCCESS != GetLastError()) hr = HRESULT_FROM_WIN32(GetLastError());
  639. }
  640. if ( NULL != psAccountName && 0 != _wcsicmp( SZ_AUTH_ID_MD5_HASH, bstrAuthType ))
  641. delete [] psAccountName;
  642. return hr;
  643. }
  644. /////////////////////////////////////////////////////////////////////////////
  645. // EnablePOP3SVC, public
  646. //
  647. // Purpose:
  648. // Make sure the POP3SVC is Running and startup set to Automatic.
  649. //
  650. // Arguments:
  651. //
  652. // Returns: S_OK on success, appropriate HRESULT otherwise
  653. HRESULT CP3AdminWorker::EnablePOP3SVC()
  654. {
  655. HRESULT hr = _ChangeServiceStartType( POP3_SERVICE_NAME, SERVICE_AUTO_START );
  656. if ( S_OK == hr )
  657. hr = _StartService( POP3_SERVICE_NAME );
  658. return hr;
  659. }
  660. /////////////////////////////////////////////////////////////////////////////
  661. // GetLoggingLevel, public
  662. //
  663. // Purpose:
  664. // Get Logging Level registry key.
  665. //
  666. // Arguments:
  667. // long *plLoggingLevel : return value
  668. //
  669. // Returns: S_OK on success, appropriate HRESULT otherwise
  670. HRESULT CP3AdminWorker::GetLoggingLevel( long *plLoggingLevel )
  671. {
  672. if ( NULL == plLoggingLevel )
  673. return E_INVALIDARG;
  674. HRESULT hr = S_OK;
  675. DWORD dwLogLevel;
  676. long lRC;
  677. lRC = RegQueryLoggingLevel( dwLogLevel, m_psMachineName );
  678. if ( ERROR_SUCCESS == lRC )
  679. *plLoggingLevel = dwLogLevel;
  680. else
  681. hr = HRESULT_FROM_WIN32( lRC );
  682. return hr;
  683. }
  684. /////////////////////////////////////////////////////////////////////////////
  685. // GetMachineName, public
  686. //
  687. // Purpose:
  688. // Get the Machine Name that all operations should be performed on..
  689. //
  690. // Arguments:
  691. // LPWSTR psMachineName : buffer
  692. // DWORD dwSize : buffer size
  693. //
  694. // Returns: S_OK on success, appropriate HRESULT otherwise
  695. HRESULT CP3AdminWorker::GetMachineName( LPWSTR psMachineName, DWORD dwSize )
  696. {
  697. if ( NULL == psMachineName )
  698. return E_INVALIDARG;
  699. HRESULT hr = S_OK;
  700. if ( NULL == m_psMachineName )
  701. ZeroMemory( psMachineName, dwSize * sizeof( WCHAR ));
  702. else
  703. {
  704. if ( dwSize > wcslen( m_psMachineName ))
  705. wcscpy( psMachineName, m_psMachineName );
  706. else
  707. hr = TYPE_E_BUFFERTOOSMALL;
  708. }
  709. return hr;
  710. }
  711. /////////////////////////////////////////////////////////////////////////////
  712. // GetMailroot, public
  713. //
  714. // Purpose:
  715. // Get Mailroot registry key.
  716. //
  717. // Arguments:
  718. // LPWSTR psMailRoot : buffer
  719. // DWORD dwSize : buffer size
  720. //
  721. // Returns: S_OK on success, appropriate HRESULT otherwise
  722. HRESULT CP3AdminWorker::GetMailroot( LPWSTR psMailRoot, DWORD dwSize, bool bUNC /*= true*/ )
  723. {
  724. if ( NULL == psMailRoot )
  725. return E_INVALIDARG;
  726. long lRC;
  727. lRC = RegQueryMailRoot( psMailRoot, dwSize, m_psMachineName );
  728. if ( ERROR_SUCCESS == lRC && NULL != m_psMachineName && true == bUNC )
  729. {
  730. // Replace drive: with drive$
  731. if ( L':' == psMailRoot[1] )
  732. {
  733. psMailRoot[1] = L'$';
  734. if ( dwSize > (wcslen( psMailRoot ) + wcslen( m_psMachineName ) + 3) )
  735. {
  736. LPWSTR psBuffer = new WCHAR[wcslen(psMailRoot)+1];
  737. if ( NULL != psBuffer )
  738. {
  739. wcscpy( psBuffer, psMailRoot );
  740. wcscpy( psMailRoot, L"\\\\" );
  741. wcscat( psMailRoot, m_psMachineName );
  742. wcscat( psMailRoot, L"\\" );
  743. wcscat( psMailRoot, psBuffer );
  744. delete [] psBuffer;
  745. }
  746. else
  747. lRC = ERROR_OUTOFMEMORY;
  748. }
  749. else
  750. lRC = ERROR_INSUFFICIENT_BUFFER;
  751. }
  752. //else dougb commented out because this breaks UNC paths when administering remote machines!
  753. // lRC = ERROR_INVALID_DATA;
  754. }
  755. if ( ERROR_SUCCESS == lRC )
  756. return S_OK;
  757. return HRESULT_FROM_WIN32( lRC );
  758. }
  759. HRESULT CP3AdminWorker::GetNextUser( HANDLE& hfSearch, LPCWSTR psDomainName, LPWSTR psBuffer, DWORD dwBufferSize )
  760. {
  761. if ( NULL == psDomainName )
  762. return E_INVALIDARG;
  763. if ( NULL == psBuffer )
  764. return E_INVALIDARG;
  765. HRESULT hr = S_OK;
  766. bool bFound = false;
  767. WCHAR sBuffer[POP3_MAX_ADDRESS_LENGTH];
  768. _bstr_t _bstr;
  769. LPWSTR ps;
  770. CMailBox mailboxX;
  771. WIN32_FIND_DATA stFindFileData;
  772. hr = MailboxSetRemote();
  773. if ( S_OK == hr )
  774. {
  775. if ( !FindNextFile( hfSearch, &stFindFileData ))
  776. hr = HRESULT_FROM_WIN32(GetLastError());
  777. }
  778. while ( S_OK == hr && !bFound )
  779. { // Count directories
  780. if ( FILE_ATTRIBUTE_DIRECTORY == ( FILE_ATTRIBUTE_DIRECTORY & stFindFileData.dwFileAttributes ))
  781. {
  782. ps = mailboxX.GetMailboxFromStoreNameW( stFindFileData.cFileName );
  783. if ( NULL != ps )
  784. {
  785. _bstr = ps;
  786. _bstr += L"@";
  787. _bstr += psDomainName;
  788. if ( mailboxX.OpenMailBox( _bstr ))
  789. {
  790. if ( dwBufferSize > wcslen( ps ))
  791. {
  792. wcscpy( psBuffer, ps );
  793. bFound = true;
  794. mailboxX.CloseMailBox();
  795. }
  796. }
  797. }
  798. }
  799. if ( !bFound )
  800. {
  801. if ( !FindNextFile( hfSearch, &stFindFileData ))
  802. hr = HRESULT_FROM_WIN32(GetLastError());
  803. }
  804. }
  805. MailboxResetRemote();
  806. if ( HRESULT_FROM_WIN32(ERROR_NO_MORE_FILES) == hr )
  807. {
  808. hr = S_FALSE;
  809. FindClose( hfSearch );
  810. hfSearch = INVALID_HANDLE_VALUE;
  811. }
  812. return hr;
  813. }
  814. /////////////////////////////////////////////////////////////////////////////
  815. // GetPort, public
  816. //
  817. // Purpose:
  818. // Get the Port registry key.
  819. //
  820. // Arguments:
  821. // long* plPort : current value
  822. //
  823. // Returns: S_OK on success, appropriate HRESULT otherwise
  824. HRESULT CP3AdminWorker::GetPort( long *plPort )
  825. {
  826. if ( NULL == plPort )
  827. return E_INVALIDARG;
  828. DWORD dwValue;
  829. long lRC = RegQueryPort( dwValue, m_psMachineName );
  830. if ( ERROR_SUCCESS == lRC )
  831. {
  832. *plPort = dwValue;
  833. return S_OK;
  834. }
  835. return HRESULT_FROM_WIN32( lRC );
  836. }
  837. /////////////////////////////////////////////////////////////////////////////
  838. // GetServiceStatus, public
  839. //
  840. // Purpose:
  841. // Get the service status from the Service Control Manager.
  842. //
  843. // Arguments:
  844. // long* plStatus : the status
  845. //
  846. // Returns: S_OK on success, appropriate HRESULT otherwise
  847. HRESULT CP3AdminWorker::GetServiceStatus( LPWSTR psService, LPDWORD plStatus )
  848. {
  849. if ( NULL == plStatus )
  850. return E_INVALIDARG;
  851. if ( NULL == psService )
  852. return E_INVALIDARG;
  853. HRESULT hr = E_FAIL;
  854. if ( 0 == _wcsicmp( POP3_SERVICE_NAME, psService ) ||
  855. 0 == _wcsicmp( SMTP_SERVICE_NAME_W, psService ) ||
  856. 0 == _wcsicmp( IISADMIN_SERVICE_NAME, psService ) ||
  857. 0 == _wcsicmp( W3_SERVICE_NAME, psService )
  858. )
  859. {
  860. *plStatus = _GetServiceStatus( psService, m_psMachineName );
  861. if ( 0 != *plStatus )
  862. hr = S_OK;
  863. }
  864. else
  865. hr = E_INVALIDARG;
  866. return hr;
  867. }
  868. /////////////////////////////////////////////////////////////////////////////
  869. // GetSocketBacklog, public
  870. //
  871. // Purpose:
  872. // Get the Socket Backlog registry key.
  873. //
  874. // Arguments:
  875. // long* plBacklog : current value
  876. //
  877. // Returns: S_OK on success, appropriate HRESULT otherwise
  878. HRESULT CP3AdminWorker::GetSocketBacklog( long *plBacklog )
  879. {
  880. if ( NULL == plBacklog )
  881. return E_INVALIDARG;
  882. DWORD dwValue;
  883. long lRC = RegQuerySocketBacklog( dwValue, m_psMachineName );
  884. if ( ERROR_SUCCESS == lRC )
  885. {
  886. *plBacklog = dwValue;
  887. return S_OK;
  888. }
  889. return HRESULT_FROM_WIN32( lRC );
  890. }
  891. /////////////////////////////////////////////////////////////////////////////
  892. // GetSocketMax, public
  893. //
  894. // Purpose:
  895. // Get the Socket Max registry key.
  896. //
  897. // Arguments:
  898. // long* plMax : current value
  899. //
  900. // Returns: S_OK on success, appropriate HRESULT otherwise
  901. HRESULT CP3AdminWorker::GetSocketMax( long *plMax )
  902. {
  903. if ( NULL == plMax )
  904. return E_INVALIDARG;
  905. DWORD dwValue;
  906. long lRC = RegQuerySocketMax( dwValue, m_psMachineName );
  907. if ( ERROR_SUCCESS == lRC )
  908. {
  909. *plMax = dwValue;
  910. return S_OK;
  911. }
  912. return HRESULT_FROM_WIN32( lRC );
  913. }
  914. /////////////////////////////////////////////////////////////////////////////
  915. // GetSocketMin, public
  916. //
  917. // Purpose:
  918. // Get the Socket Min registry key.
  919. //
  920. // Arguments:
  921. // long* plMax : current value
  922. //
  923. // Returns: S_OK on success, appropriate HRESULT otherwise
  924. HRESULT CP3AdminWorker::GetSocketMin( long *plMin )
  925. {
  926. if ( NULL == plMin )
  927. return E_INVALIDARG;
  928. DWORD dwValue;
  929. long lRC = RegQuerySocketMin( dwValue, m_psMachineName );
  930. if ( ERROR_SUCCESS == lRC )
  931. {
  932. *plMin = dwValue;
  933. return S_OK;
  934. }
  935. return HRESULT_FROM_WIN32( lRC );
  936. }
  937. /////////////////////////////////////////////////////////////////////////////
  938. // GetSocketThreshold, public
  939. //
  940. // Purpose:
  941. // Get the Socket Threshold registry key.
  942. //
  943. // Arguments:
  944. // long* plThreshold : current value
  945. //
  946. // Returns: S_OK on success, appropriate HRESULT otherwise
  947. HRESULT CP3AdminWorker::GetSocketThreshold( long *plThreshold )
  948. {
  949. if ( NULL == plThreshold )
  950. return E_INVALIDARG;
  951. DWORD dwValue;
  952. long lRC = RegQuerySocketThreshold( dwValue, m_psMachineName );
  953. if ( ERROR_SUCCESS == lRC )
  954. {
  955. *plThreshold = dwValue;
  956. return S_OK;
  957. }
  958. return HRESULT_FROM_WIN32( lRC );
  959. }
  960. /////////////////////////////////////////////////////////////////////////////
  961. // GetSPARequired, public
  962. //
  963. // Purpose:
  964. // Get the SPARequired registry key.
  965. //
  966. // Arguments:
  967. // BOOL *pbSPARequired : current value
  968. //
  969. // Returns: S_OK on success, appropriate HRESULT otherwise
  970. HRESULT CP3AdminWorker::GetSPARequired( BOOL *pbSPARequired )
  971. {
  972. if ( NULL == pbSPARequired )
  973. return E_INVALIDARG;
  974. DWORD dwValue;
  975. long lRC = RegQuerySPARequired( dwValue, m_psMachineName );
  976. if ( ERROR_SUCCESS == lRC )
  977. {
  978. *pbSPARequired = (dwValue) ? TRUE : FALSE;
  979. return S_OK;
  980. }
  981. return HRESULT_FROM_WIN32( lRC );
  982. }
  983. /////////////////////////////////////////////////////////////////////////////
  984. // GetThreadCountPerCPU, public
  985. //
  986. // Purpose:
  987. // Get the ThreadCountPerCPU registry key.
  988. //
  989. // Arguments:
  990. // long* plCount : current value
  991. //
  992. // Returns: S_OK on success, appropriate HRESULT otherwise
  993. HRESULT CP3AdminWorker::GetThreadCountPerCPU( long *plCount )
  994. {
  995. if ( NULL == plCount )
  996. return E_INVALIDARG;
  997. DWORD dwValue;
  998. long lRC = RegQueryThreadCountPerCPU( dwValue, m_psMachineName );
  999. if ( ERROR_SUCCESS == lRC )
  1000. {
  1001. *plCount = dwValue;
  1002. return S_OK;
  1003. }
  1004. return HRESULT_FROM_WIN32( lRC );
  1005. }
  1006. HRESULT CP3AdminWorker::GetUserCount( LPWSTR psDomainName, long *plCount )
  1007. {
  1008. // psDomainName - checked by BuildDomainPath
  1009. if ( NULL == plCount )
  1010. return E_INVALIDARG;
  1011. HRESULT hr;
  1012. HANDLE hfSearch;
  1013. WCHAR sBuffer[POP3_MAX_PATH];
  1014. WIN32_FIND_DATA stFindFileData;
  1015. LPWSTR ps;
  1016. _bstr_t _bstr;
  1017. CMailBox mailboxX;
  1018. *plCount = 0;
  1019. hr = BuildDomainPath( psDomainName, sBuffer, sizeof( sBuffer )/sizeof(WCHAR) );
  1020. if (S_OK == hr)
  1021. {
  1022. if ((sizeof( sBuffer )/sizeof(WCHAR)) > (wcslen( sBuffer ) + wcslen(MAILBOX_PREFIX_W) + wcslen(MAILBOX_EXTENSION_W) + 2 ))
  1023. {
  1024. wcscat( sBuffer, L"\\" );
  1025. wcscat( sBuffer, MAILBOX_PREFIX_W );
  1026. wcscat( sBuffer, L"*" );
  1027. wcscat( sBuffer, MAILBOX_EXTENSION_W );
  1028. }
  1029. else
  1030. hr = E_UNEXPECTED;
  1031. }
  1032. if ( S_OK == hr )
  1033. hr = MailboxSetRemote();
  1034. if ( S_OK == hr )
  1035. {
  1036. // Directory Search
  1037. hfSearch = FindFirstFileEx( sBuffer, FindExInfoStandard, &stFindFileData, FindExSearchLimitToDirectories, NULL, 0 );
  1038. if ( INVALID_HANDLE_VALUE == hfSearch )
  1039. hr = HRESULT_FROM_WIN32(GetLastError());
  1040. while ( S_OK == hr )
  1041. { // Count directories
  1042. if ( FILE_ATTRIBUTE_DIRECTORY == ( FILE_ATTRIBUTE_DIRECTORY & stFindFileData.dwFileAttributes ))
  1043. {
  1044. ps = mailboxX.GetMailboxFromStoreNameW( stFindFileData.cFileName );
  1045. if ( NULL != ps )
  1046. {
  1047. _bstr = ps;
  1048. _bstr += L"@";
  1049. _bstr += psDomainName;
  1050. if ( mailboxX.OpenMailBox( _bstr ))
  1051. {
  1052. mailboxX.CloseMailBox();
  1053. (*plCount) += 1;
  1054. }
  1055. }
  1056. }
  1057. if ( !FindNextFile( hfSearch, &stFindFileData ))
  1058. hr = HRESULT_FROM_WIN32(GetLastError());
  1059. }
  1060. if ( HRESULT_FROM_WIN32(ERROR_NO_MORE_FILES) == hr || HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr )
  1061. hr = S_OK;
  1062. if(INVALID_HANDLE_VALUE!=hfSearch)
  1063. {
  1064. FindClose(hfSearch);
  1065. hfSearch=INVALID_HANDLE_VALUE;
  1066. }
  1067. }
  1068. MailboxResetRemote();
  1069. return hr;
  1070. }
  1071. /////////////////////////////////////////////////////////////////////////////
  1072. // GetUserLock, public
  1073. //
  1074. // Purpose:
  1075. // Determine if the user is locked.
  1076. //
  1077. // Arguments:
  1078. // LPWSTR psDomainName : Domain of user
  1079. // LPWSTR psUserName : User to check lock
  1080. // BOOL *pisLocked : return value
  1081. //
  1082. // Returns: S_OK on success, appropriate HRESULT otherwise
  1083. HRESULT CP3AdminWorker::GetUserLock( LPWSTR psDomainName, LPWSTR psUserName, BOOL *pisLocked )
  1084. {
  1085. // psDomainName - checked by CreateUserMutex
  1086. // psBuffer - checked by CreateUserMutex
  1087. if ( NULL == pisLocked )
  1088. return E_INVALIDARG;
  1089. HRESULT hr = S_OK;
  1090. HANDLE hMutex = NULL;
  1091. // Create a Mutex Name for this domain to ensure we are the only one accessing it.
  1092. hr = CreateUserMutex( psDomainName, psUserName, &hMutex );
  1093. if ( S_OK == hr )
  1094. *pisLocked = isUserLocked( psDomainName, psUserName ) ? TRUE : FALSE;
  1095. // Cleanup
  1096. if ( NULL != hMutex )
  1097. CloseHandle( hMutex );
  1098. return hr;
  1099. }
  1100. /////////////////////////////////////////////////////////////////////////////
  1101. // GetUserMessageDiskUsage, public
  1102. //
  1103. // Purpose:
  1104. // Get the number of messages in the mailbox.
  1105. //
  1106. // Arguments:
  1107. // LPWSTR psDomainName : Domain of user
  1108. // LPWSTR psUserName : User to check
  1109. // long *plFactor : Base 10 multiplicand for plUsage
  1110. // long *plUsage : Disk Usage
  1111. //
  1112. // Returns: S_OK on success, appropriate HRESULT otherwise
  1113. HRESULT CP3AdminWorker::GetUserMessageDiskUsage( LPWSTR psDomainName, LPWSTR psUserName, long *plFactor, long *plUsage )
  1114. {
  1115. // psDomainName - checked by BuildEmailAddrW2A
  1116. // psBuffer - checked by BuildEmailAddrW2A
  1117. if ( NULL == plFactor )
  1118. return E_INVALIDARG;
  1119. if ( NULL == plUsage )
  1120. return E_INVALIDARG;
  1121. HRESULT hr;
  1122. CMailBox mailboxX;
  1123. WCHAR sEmailAddr[POP3_MAX_ADDRESS_LENGTH];
  1124. DWORD dwTotalSize;
  1125. hr = BuildEmailAddr( psDomainName, psUserName, sEmailAddr, sizeof( sEmailAddr )/sizeof(WCHAR) );
  1126. if ( S_OK == hr )
  1127. hr = MailboxSetRemote();
  1128. if ( S_OK == hr )
  1129. {
  1130. hr = E_FAIL;
  1131. if ( mailboxX.OpenMailBox( sEmailAddr ))
  1132. {
  1133. if ( mailboxX.EnumerateMailBox() )
  1134. {
  1135. dwTotalSize = mailboxX.GetTotalSize();
  1136. if ( INT_MAX > dwTotalSize )
  1137. {
  1138. *plFactor = 1;
  1139. *plUsage = dwTotalSize;
  1140. }
  1141. else
  1142. {
  1143. *plFactor = 10;
  1144. *plUsage = dwTotalSize / 10;
  1145. }
  1146. hr = S_OK;
  1147. }
  1148. mailboxX.CloseMailBox();
  1149. }
  1150. }
  1151. MailboxResetRemote();
  1152. return hr;
  1153. }
  1154. /////////////////////////////////////////////////////////////////////////////
  1155. // GetUserMessageCount, public
  1156. //
  1157. // Purpose:
  1158. // Get the number of messages in the mailbox.
  1159. //
  1160. // Arguments:
  1161. // LPWSTR psDomainName : Domain of user
  1162. // LPWSTR psUserName : User to check
  1163. // long *plCount : return value
  1164. //
  1165. // Returns: S_OK on success, appropriate HRESULT otherwise
  1166. HRESULT CP3AdminWorker::GetUserMessageCount( LPWSTR psDomainName, LPWSTR psUserName, long *plCount )
  1167. {
  1168. // psDomainName - checked by BuildEmailAddrW2A
  1169. // psBuffer - checked by BuildEmailAddrW2A
  1170. if ( NULL == plCount )
  1171. return E_INVALIDARG;
  1172. HRESULT hr;
  1173. CMailBox mailboxX;
  1174. WCHAR sEmailAddr[POP3_MAX_ADDRESS_LENGTH];
  1175. hr = BuildEmailAddr(psDomainName, psUserName, sEmailAddr, sizeof( sEmailAddr )/sizeof(WCHAR) );
  1176. if ( S_OK == hr )
  1177. hr = MailboxSetRemote();
  1178. if ( S_OK == hr )
  1179. {
  1180. hr = E_FAIL;
  1181. if ( mailboxX.OpenMailBox( sEmailAddr ))
  1182. {
  1183. if ( mailboxX.EnumerateMailBox() )
  1184. {
  1185. *plCount = mailboxX.GetMailCount();
  1186. hr = S_OK;
  1187. }
  1188. mailboxX.CloseMailBox();
  1189. }
  1190. }
  1191. MailboxResetRemote();
  1192. return hr;
  1193. }
  1194. /////////////////////////////////////////////////////////////////////////////
  1195. // InitFindFirstFile, public
  1196. //
  1197. // Purpose:
  1198. // Initialize a file search. Used for enumerating users.
  1199. //
  1200. // Arguments:
  1201. // HANDLE& hfSearch : search handle to initialize
  1202. //
  1203. // Returns: S_OK or S_FALSE (no users) on success, appropriate HRESULT otherwise
  1204. HRESULT CP3AdminWorker::InitFindFirstUser( HANDLE& hfSearch, LPCWSTR psDomainName, LPWSTR psBuffer, DWORD dwBufferSize )
  1205. {
  1206. // psDomainName - checked by BuildEmailAddrW2A
  1207. if ( NULL == psBuffer )
  1208. return E_INVALIDARG;
  1209. HRESULT hr = S_OK;
  1210. bool bFound = false;
  1211. WCHAR sBuffer[POP3_MAX_PATH];
  1212. _bstr_t _bstr;
  1213. LPWSTR ps;
  1214. CMailBox mailboxX;
  1215. WIN32_FIND_DATA stFindFileData;
  1216. if ( INVALID_HANDLE_VALUE != hfSearch )
  1217. {
  1218. FindClose( hfSearch );
  1219. hfSearch = INVALID_HANDLE_VALUE;
  1220. }
  1221. // Build the Path
  1222. hr = BuildDomainPath( psDomainName, sBuffer, (sizeof( sBuffer )/sizeof(WCHAR)));
  1223. if (S_OK == hr)
  1224. {
  1225. if ((sizeof( sBuffer )/sizeof(WCHAR)) > (wcslen( sBuffer ) + wcslen(MAILBOX_PREFIX_W) + wcslen(MAILBOX_EXTENSION_W) + 2 ))
  1226. {
  1227. wcscat( sBuffer, L"\\" );
  1228. wcscat( sBuffer, MAILBOX_PREFIX_W );
  1229. wcscat( sBuffer, L"*" );
  1230. wcscat( sBuffer, MAILBOX_EXTENSION_W );
  1231. }
  1232. else
  1233. hr = E_UNEXPECTED;
  1234. }
  1235. if ( S_OK == hr )
  1236. hr = MailboxSetRemote();
  1237. if ( S_OK == hr )
  1238. {
  1239. // Directory Search
  1240. hfSearch = FindFirstFileEx( sBuffer, FindExInfoStandard, &stFindFileData, FindExSearchLimitToDirectories, NULL, 0 );
  1241. if ( INVALID_HANDLE_VALUE == hfSearch )
  1242. hr = HRESULT_FROM_WIN32(GetLastError());
  1243. while ( S_OK == hr && !bFound )
  1244. { // Make sure we have a mailbox directory
  1245. if ( FILE_ATTRIBUTE_DIRECTORY == ( FILE_ATTRIBUTE_DIRECTORY & stFindFileData.dwFileAttributes ))
  1246. {
  1247. ps = mailboxX.GetMailboxFromStoreNameW( stFindFileData.cFileName );
  1248. if ( NULL != ps )
  1249. {
  1250. _bstr = ps;
  1251. _bstr += L"@";
  1252. _bstr += psDomainName;
  1253. if ( mailboxX.OpenMailBox( _bstr ))
  1254. {
  1255. if ( dwBufferSize > wcslen( ps ))
  1256. {
  1257. wcscpy( psBuffer, ps );
  1258. bFound = true;
  1259. mailboxX.CloseMailBox();
  1260. }
  1261. else
  1262. hr = HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER );
  1263. }
  1264. }
  1265. }
  1266. if ( !bFound )
  1267. {
  1268. if ( !FindNextFile( hfSearch, &stFindFileData ))
  1269. hr = HRESULT_FROM_WIN32(GetLastError());
  1270. }
  1271. }
  1272. if ( HRESULT_FROM_WIN32(ERROR_NO_MORE_FILES) == hr || HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr )
  1273. hr = S_FALSE;
  1274. }
  1275. MailboxResetRemote();
  1276. return hr;
  1277. }
  1278. /////////////////////////////////////////////////////////////////////////////
  1279. // IsDomainLocked, public
  1280. //
  1281. // Purpose:
  1282. // Determine if the domain is locked.
  1283. // Domain locking involved renaming all the mailbox lock files to LOCKRENAME_FILENAME plus
  1284. // creating a file in the domain directory.
  1285. // Checking for the file in the domain directory is a sufficient check for our purposes.
  1286. //
  1287. // Arguments:
  1288. // LPWSTR psDomainName : domain to check
  1289. //
  1290. // Returns: S_OK on success, appropriate HRESULT otherwise
  1291. bool CP3AdminWorker::IsDomainLocked( LPWSTR psDomainName )
  1292. {
  1293. // psDomainName - checked by BuildDomainPath
  1294. HRESULT hr;
  1295. bool bRC = false;
  1296. WCHAR sDomainPath[POP3_MAX_PATH];
  1297. WCHAR sBuffer[POP3_MAX_PATH];
  1298. hr = BuildDomainPath( psDomainName, sDomainPath, sizeof( sDomainPath )/sizeof(WCHAR) );
  1299. if ( S_OK == hr )
  1300. { // Directory Search
  1301. if ( (sizeof( sBuffer )/sizeof(WCHAR)) > (wcslen( sDomainPath ) + wcslen(LOCKRENAME_FILENAME) + 1 ))
  1302. {
  1303. wcscpy( sBuffer, sDomainPath );
  1304. wcscat( sBuffer, L"\\" );
  1305. wcscat( sBuffer, LOCKRENAME_FILENAME );
  1306. if ( ERROR_NO_FILE_ATTR != GetFileAttributes( sBuffer ))
  1307. bRC = true;
  1308. }
  1309. else
  1310. hr = E_UNEXPECTED;
  1311. }
  1312. return bRC;
  1313. }
  1314. /////////////////////////////////////////////////////////////////////////////
  1315. // isUserLocked, public
  1316. //
  1317. // Purpose:
  1318. // Determine if the user is locked. Users can be locked in one of two fashions:
  1319. // Domain locking involved renaming all the mailbox lock files to LOCKRENAME_FILENAME,
  1320. // or the LOCK_FILENAME may be in use. Either way OpenMailbox will fail.
  1321. //
  1322. // Arguments:
  1323. // LPWSTR psDomainName : domain of user
  1324. // LPWSTR psUserName : user to check
  1325. //
  1326. // Returns: S_OK on success, appropriate HRESULT otherwise
  1327. bool CP3AdminWorker::isUserLocked( LPWSTR psDomainName, LPWSTR psUserName )
  1328. {
  1329. // psDomainName - checked by BuildEmailAddrW2A
  1330. // psBuffer - checked by BuildEmailAddrW2A
  1331. bool bRC = false;
  1332. HRESULT hr;
  1333. CMailBox mailboxX;
  1334. WCHAR sEmailAddr[POP3_MAX_ADDRESS_LENGTH];
  1335. hr = BuildEmailAddr( psDomainName, psUserName, sEmailAddr, sizeof( sEmailAddr )/sizeof(WCHAR) );
  1336. if ( S_OK == hr )
  1337. hr = MailboxSetRemote();
  1338. if ( S_OK == hr )
  1339. {
  1340. if ( mailboxX.OpenMailBox( sEmailAddr ))
  1341. {
  1342. HRESULT hr = S_OK;
  1343. WCHAR sBuffer[POP3_MAX_PATH];
  1344. WCHAR sLockFile[POP3_MAX_PATH];
  1345. hr = BuildUserPath( psDomainName, psUserName, sBuffer, sizeof( sBuffer )/sizeof(WCHAR) );
  1346. if ( S_OK == hr )
  1347. {
  1348. if ((sizeof( sLockFile )/sizeof(WCHAR)) > ( wcslen( sBuffer ) + wcslen( LOCK_FILENAME ) + 1 ))
  1349. {
  1350. wcscpy( sLockFile, sBuffer );
  1351. wcscat( sLockFile, L"\\" );
  1352. wcscat( sLockFile, LOCK_FILENAME );
  1353. if ( -1 == GetFileAttributes( sLockFile ))
  1354. bRC = true;
  1355. }
  1356. }
  1357. mailboxX.CloseMailBox();
  1358. }
  1359. }
  1360. MailboxResetRemote();
  1361. return bRC;
  1362. }
  1363. BYTE g_ASCII128[128] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00-0F
  1364. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 10-1F
  1365. 0,1,0,1,1,1,1,1,0,0,0,1,0,1,1,0, // 20-2F
  1366. 1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, // 30-3F
  1367. 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 40-4F
  1368. 1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1, // 50-5F
  1369. 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 60-6F
  1370. 1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1 // 70-7F
  1371. };
  1372. /////////////////////////////////////////////////////////////////////////////
  1373. // isValidMailboxName, public
  1374. //
  1375. // Purpose:
  1376. // Perform RFC 821 validation on the mailbox name
  1377. // user - The maximum total length of a user name is 64 characters.
  1378. // <mailbox> ::= <local-part> "@" <domain>
  1379. // <local-part> ::= <dot-string> | <quoted-string>
  1380. // <dot-string> ::= <string> | <string> "." <dot-string> -> . 0x2e
  1381. // <quoted-string> ::= """ <qtext> """ -> " 0x22 not going to allow this because it creates other complications
  1382. // <string> ::= <char> | <char> <string>
  1383. // <char> ::= <c> | "\" <x>
  1384. // <x> ::= any one of the 128 ASCII characters (no exceptions) -> This means any thing is permitted, even the special characters!
  1385. // <c> ::= any one of the 128 ASCII characters,
  1386. // but not any <special> or <SP>
  1387. // <special> ::= "<" | ">" | "(" | ")" | "[" | "]" | "\" | "."
  1388. // | "," | ";" | ":" | "@" """ | the control
  1389. // characters (ASCII codes 0 through 31 inclusive and 127)
  1390. // <SP> ::= the space character (ASCII code 32)
  1391. //
  1392. // Arguments:
  1393. // LPWSTR psMailbox : name to validate
  1394. //
  1395. // Returns: S_OK on success, appropriate HRESULT otherwise
  1396. bool CP3AdminWorker::isValidMailboxName( LPWSTR psMailbox )
  1397. {
  1398. if ( NULL == psMailbox )
  1399. return false;
  1400. if ( POP3_MAX_MAILBOX_LENGTH <= wcslen( psMailbox ) || 0 == wcslen( psMailbox ))
  1401. return false;
  1402. bool bRC = true;
  1403. WCHAR *pch = psMailbox;
  1404. for ( pch = psMailbox; 0x0 != *pch && bRC; pch++ )
  1405. {
  1406. if ( 127 < *pch || !g_ASCII128[*pch] )
  1407. bRC = false;
  1408. }
  1409. if ( bRC && ( 0x2e == psMailbox[0] || 0x2e == psMailbox[wcslen( psMailbox )-1] ))
  1410. bRC = false;
  1411. return bRC;
  1412. }
  1413. /////////////////////////////////////////////////////////////////////////////
  1414. // LockDomain, public
  1415. //
  1416. // Purpose:
  1417. // Lock all the mailboxes in the domain.
  1418. // This involves renaming all the mailbox lock files so that the Service
  1419. // can no longer access them.
  1420. // Also create a Lock file in the domain directory to distinguish between
  1421. // a domain lock and all mailboxes locked.
  1422. //
  1423. // Arguments:
  1424. // LPWSTR psDomainName : domain to lock
  1425. //
  1426. // Returns: S_OK on success, appropriate HRESULT otherwise
  1427. HRESULT CP3AdminWorker::LockDomain( LPWSTR psDomainName, bool bVerifyNotInUse /*= false*/ )
  1428. {
  1429. // psDomainName - checked by BuildDomainPath
  1430. HRESULT hr = S_OK;
  1431. HANDLE hfSearch, hf;
  1432. WCHAR sDomainPath[POP3_MAX_PATH];
  1433. WCHAR sBuffer[POP3_MAX_PATH];
  1434. WCHAR sLockFile[POP3_MAX_PATH];
  1435. WCHAR sRenameFile[POP3_MAX_PATH];
  1436. WIN32_FIND_DATA stFindFileData;
  1437. hr = BuildDomainPath( psDomainName, sDomainPath, sizeof( sDomainPath )/sizeof(WCHAR) );
  1438. if ( S_OK == hr )
  1439. { // Directory Search
  1440. wcscpy( sBuffer, sDomainPath );
  1441. if ((sizeof( sBuffer )/sizeof(WCHAR)) > (wcslen( sBuffer ) + wcslen(MAILBOX_PREFIX_W) + wcslen(MAILBOX_EXTENSION_W)) + 2 )
  1442. {
  1443. wcscat( sBuffer, L"\\" );
  1444. wcscat( sBuffer, MAILBOX_PREFIX_W );
  1445. wcscat( sBuffer, L"*" );
  1446. wcscat( sBuffer, MAILBOX_EXTENSION_W );
  1447. }
  1448. else
  1449. hr = E_UNEXPECTED;
  1450. hfSearch = FindFirstFileEx( sBuffer, FindExInfoStandard, &stFindFileData, FindExSearchLimitToDirectories, NULL, 0 );
  1451. if ( INVALID_HANDLE_VALUE == hfSearch )
  1452. hr = HRESULT_FROM_WIN32(GetLastError());
  1453. while ( S_OK == hr )
  1454. { // Lock each directory (user)
  1455. if ( FILE_ATTRIBUTE_DIRECTORY == ( FILE_ATTRIBUTE_DIRECTORY & stFindFileData.dwFileAttributes ))
  1456. {
  1457. if (( (sizeof( sLockFile )/sizeof(WCHAR)) > ( wcslen( sDomainPath ) + wcslen( stFindFileData.cFileName ) + wcslen( LOCK_FILENAME ) + 2 )) &&
  1458. ( (sizeof( sRenameFile )/sizeof(WCHAR)) > ( wcslen( sDomainPath ) + wcslen( stFindFileData.cFileName ) + wcslen( LOCKRENAME_FILENAME ) + 2 )))
  1459. {
  1460. wcscpy( sLockFile, sDomainPath );
  1461. wcscat( sLockFile, L"\\" );
  1462. wcscat( sLockFile, stFindFileData.cFileName );
  1463. wcscat( sLockFile, L"\\" );
  1464. wcscpy( sRenameFile, sLockFile );
  1465. wcscat( sLockFile, LOCK_FILENAME );
  1466. wcscat( sRenameFile, LOCKRENAME_FILENAME );
  1467. if ( !MoveFile( sLockFile, sRenameFile ))
  1468. { // If the lock file does not exist, that is okay (this must not be one of our directories)
  1469. DWORD dwRC = GetLastError();
  1470. if ( ERROR_FILE_NOT_FOUND != dwRC )
  1471. hr = HRESULT_FROM_WIN32(dwRC);
  1472. }
  1473. else
  1474. { // Try an exclusive lock on the file to make sure the service does not have access to it.
  1475. if ( bVerifyNotInUse )
  1476. {
  1477. hf = CreateFile( sRenameFile, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_HIDDEN, NULL );
  1478. if ( INVALID_HANDLE_VALUE == hf )
  1479. hr = HRESULT_FROM_WIN32( GetLastError() );
  1480. else
  1481. CloseHandle( hf );
  1482. }
  1483. }
  1484. }
  1485. else
  1486. hr = E_FAIL;
  1487. }
  1488. if ( S_OK == hr && !FindNextFile( hfSearch, &stFindFileData ))
  1489. hr = HRESULT_FROM_WIN32(GetLastError());
  1490. }
  1491. if ( HRESULT_FROM_WIN32(ERROR_NO_MORE_FILES) == hr || HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr )
  1492. hr = S_OK;
  1493. if(INVALID_HANDLE_VALUE!=hfSearch)
  1494. {
  1495. FindClose(hfSearch);
  1496. hfSearch=INVALID_HANDLE_VALUE;
  1497. }
  1498. if ( S_OK == hr )
  1499. {
  1500. if ((sizeof( sBuffer )/sizeof(WCHAR)) > (wcslen( sDomainPath ) + wcslen(LOCKRENAME_FILENAME) + 1 ))
  1501. {
  1502. HANDLE hf;
  1503. wcscpy( sBuffer, sDomainPath );
  1504. wcscat( sBuffer, L"\\" );
  1505. wcscat( sBuffer, LOCKRENAME_FILENAME );
  1506. hf = CreateFile( sBuffer, GENERIC_ALL, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_HIDDEN, NULL );
  1507. if ( INVALID_HANDLE_VALUE != hf )
  1508. CloseHandle( hf );
  1509. else
  1510. { // If the lock file already exists, that is okay (domain already locked) - we only expect this error in the LockForDelete scenario
  1511. DWORD dwRC = GetLastError();
  1512. if ( !(bVerifyNotInUse && ERROR_FILE_EXISTS == dwRC ))
  1513. hr = HRESULT_FROM_WIN32(dwRC);
  1514. }
  1515. }
  1516. }
  1517. // Ran into a problem need to undo everything we've done
  1518. if ( S_OK != hr )
  1519. UnlockDomain( psDomainName ); // Don't overwrite existing return code
  1520. }
  1521. return hr;
  1522. }
  1523. /////////////////////////////////////////////////////////////////////////////
  1524. // LockUser, public
  1525. //
  1526. // Purpose:
  1527. // Lock the user mailbox.
  1528. // A permanent lock is created by renaming all the mailbox lock file so that the Service
  1529. // can no longer it.
  1530. //
  1531. // Arguments:
  1532. // LPWSTR psDomainName : domain of user
  1533. // LPWSTR psUserName : user to lock
  1534. //
  1535. // Returns: S_OK on success, appropriate HRESULT otherwise
  1536. HRESULT CP3AdminWorker::LockUser( LPWSTR psDomainName, LPWSTR psUserName )
  1537. {
  1538. // psDomainName - checked by BuildUserPath
  1539. // psUserName - checked by BuildUserPath
  1540. HRESULT hr = S_OK;
  1541. WCHAR sBuffer[POP3_MAX_PATH];
  1542. WCHAR sLockFile[POP3_MAX_PATH];
  1543. WCHAR sRenameFile[POP3_MAX_PATH];
  1544. hr = BuildUserPath( psDomainName, psUserName, sBuffer, sizeof( sBuffer )/sizeof(WCHAR) );
  1545. if ( S_OK == hr )
  1546. {
  1547. if (( (sizeof( sLockFile )/sizeof(WCHAR)) > ( wcslen( sBuffer ) + wcslen( LOCK_FILENAME ) + 1 )) &&
  1548. ( (sizeof( sRenameFile )/sizeof(WCHAR)) > ( wcslen( sBuffer ) + wcslen( LOCKRENAME_FILENAME ) + 1 )))
  1549. {
  1550. wcscpy( sLockFile, sBuffer );
  1551. wcscat( sLockFile, L"\\" );
  1552. wcscpy( sRenameFile, sLockFile );
  1553. wcscat( sLockFile, LOCK_FILENAME );
  1554. wcscat( sRenameFile, LOCKRENAME_FILENAME );
  1555. if ( !MoveFile( sLockFile, sRenameFile ))
  1556. {
  1557. DWORD dwRC = GetLastError();
  1558. hr = HRESULT_FROM_WIN32(dwRC);
  1559. }
  1560. }
  1561. }
  1562. return hr;
  1563. }
  1564. /////////////////////////////////////////////////////////////////////////////
  1565. // MailboxSetRemote, public
  1566. //
  1567. // Purpose:
  1568. // Set the Mailbox static path to the remote machine, if necessary.
  1569. //
  1570. // Returns: S_OK on success, appropriate HRESULT otherwise
  1571. HRESULT CP3AdminWorker::MailboxSetRemote()
  1572. {
  1573. if ( NULL != m_psMachineMailRoot )
  1574. {
  1575. if ( !CMailBox::SetMailRoot( m_psMachineMailRoot ) )
  1576. return E_FAIL;
  1577. }
  1578. return S_OK;
  1579. }
  1580. /////////////////////////////////////////////////////////////////////////////
  1581. // MailboxResetRemote, public
  1582. //
  1583. // Purpose:
  1584. // Reset the Mailbox static path back to the local machine, if necessary.
  1585. //
  1586. // Returns: S_OK on success, appropriate HRESULT otherwise
  1587. HRESULT CP3AdminWorker::MailboxResetRemote()
  1588. {
  1589. if ( NULL != m_psMachineMailRoot )
  1590. {
  1591. if ( !CMailBox::SetMailRoot( ))
  1592. return E_FAIL;
  1593. }
  1594. return S_OK;
  1595. }
  1596. /////////////////////////////////////////////////////////////////////////////
  1597. // RemoveDomain, public
  1598. //
  1599. // Purpose:
  1600. // Remove the Meta base options required to remove a Local domain from the SMTP service.
  1601. // Remove the domain from our Store.
  1602. //
  1603. // Arguments:
  1604. // LPWSTR psDomainName : Domain name to remove
  1605. //
  1606. // Returns: S_OK on success, appropriate HRESULT otherwise
  1607. HRESULT CP3AdminWorker::RemoveDomain( LPWSTR psDomainName )
  1608. {
  1609. // psDomainName - checked by CreateDomainMutex
  1610. HRESULT hr = S_OK;
  1611. HANDLE hMutex = NULL;
  1612. // Create a Mutex Name for this domain to ensure we are the only one accessing it.
  1613. hr = CreateDomainMutex( psDomainName, &hMutex );
  1614. // Validate
  1615. if ( S_OK == hr )
  1616. {
  1617. hr = ValidateDomain( psDomainName );
  1618. if ( HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr )
  1619. { // Domain exists in SMTP but not in Store, let's delete from SMTP anyway
  1620. hr = RemoveSMTPDomain( psDomainName );
  1621. if ( S_OK == hr )
  1622. hr = ERROR_PATH_NOT_FOUND;
  1623. }
  1624. }
  1625. // Lock all the Mailboxes
  1626. if ( S_OK == hr )
  1627. {
  1628. hr = LockDomainForDelete( psDomainName );
  1629. // Remove
  1630. if ( S_OK == hr )
  1631. {
  1632. hr = RemoveSMTPDomain( psDomainName );
  1633. if ( S_OK == hr )
  1634. {
  1635. hr = RemoveStoreDomain( psDomainName );
  1636. if FAILED( hr )
  1637. AddSMTPDomain( psDomainName );
  1638. }
  1639. if ( S_OK != hr )
  1640. UnlockDomain( psDomainName );
  1641. }
  1642. }
  1643. // Cleanup
  1644. if ( NULL != hMutex )
  1645. CloseHandle( hMutex );
  1646. return hr;
  1647. }
  1648. /////////////////////////////////////////////////////////////////////////////
  1649. // RemoveUser, public
  1650. //
  1651. // Purpose:
  1652. // Remove a user mailbox.
  1653. //
  1654. // Arguments:
  1655. // LPWSTR psDomainName : Domain name to remove from
  1656. // LPWSTR psUserName : User name to remove
  1657. //
  1658. // Returns: S_OK on success, appropriate HRESULT otherwise
  1659. HRESULT CP3AdminWorker::RemoveUser( LPWSTR psDomainName, LPWSTR psUserName )
  1660. {
  1661. // psDomainName - checked by BuildUserPath
  1662. // psUserName - checked by BuildUserPath
  1663. HRESULT hr;
  1664. HANDLE hMutex = NULL;
  1665. WCHAR sEmailAddr[POP3_MAX_ADDRESS_LENGTH];
  1666. WCHAR sRenameFile[POP3_MAX_PATH];
  1667. WCHAR sUserFile[POP3_MAX_PATH];
  1668. CMailBox mailboxX;
  1669. hr = BuildUserPath( psDomainName, psUserName, sUserFile, sizeof( sUserFile )/sizeof(WCHAR) );
  1670. if ( S_OK == hr )
  1671. { // build the path to the mail dir \MailRoot\Domain@User
  1672. hr = BuildDomainPath( psDomainName, sRenameFile, sizeof( sRenameFile )/sizeof(WCHAR) );
  1673. if ( S_OK == hr )
  1674. {
  1675. if ( (wcslen( sRenameFile ) + wcslen( MAILBOX_PREFIX_W ) + wcslen( psUserName ) + wcslen( MAILBOX_EXTENSION2_W ) + 1) < (sizeof( sRenameFile )/sizeof(WCHAR)) )
  1676. { // build the path to the mail dir \MailRoot\Domain\User
  1677. wcscat( sRenameFile, L"\\" );
  1678. wcscat( sRenameFile, MAILBOX_PREFIX_W );
  1679. wcscat( sRenameFile, psUserName );
  1680. wcscat( sRenameFile, MAILBOX_EXTENSION2_W );
  1681. }
  1682. else
  1683. hr = E_FAIL;
  1684. }
  1685. }
  1686. // Validate the domain
  1687. if ( S_OK == hr )
  1688. {
  1689. hr = ValidateDomain( psDomainName );
  1690. }
  1691. if ( S_OK == hr )
  1692. hr = MailboxSetRemote();
  1693. if ( S_OK == hr )
  1694. { // See if the mailbox already exists
  1695. hr = BuildEmailAddr( psDomainName, psUserName, sEmailAddr, sizeof( sEmailAddr )/sizeof(WCHAR) );
  1696. if ( mailboxX.OpenMailBox( sEmailAddr ))
  1697. { // Create a Mutex Name for this user@domain to ensure we are the only one accessing it.
  1698. hr = CreateUserMutex( psDomainName, psUserName, &hMutex );
  1699. // Lock the Mailbox to make sure we are the only one accessing it then
  1700. // rename it to something unique, release our lock on the mailbox, then kill it.
  1701. if ( S_OK == hr )
  1702. {
  1703. if ( MoveFile( sUserFile, sRenameFile )) // rename
  1704. {
  1705. if ( !BDeleteDirTree( sRenameFile )) // kill
  1706. {
  1707. hr = HRESULT_FROM_WIN32( GetLastError());
  1708. if SUCCEEDED( hr ) hr = E_FAIL; // Make sure we have a failure code
  1709. // Now what? Try to repair what's left of this mess.
  1710. if ( MoveFile( sRenameFile, sUserFile ))
  1711. { // What if the lock file was deleted?
  1712. if ( mailboxX.OpenMailBox( sEmailAddr ))
  1713. mailboxX.RepairMailBox();
  1714. }
  1715. }
  1716. }
  1717. else
  1718. hr = HRESULT_FROM_WIN32( GetLastError());
  1719. }
  1720. // Cleanup
  1721. if ( NULL != hMutex )
  1722. CloseHandle( hMutex );
  1723. mailboxX.CloseMailBox(); // It's okay to do this even if the mailbox is already closed.
  1724. }
  1725. else
  1726. hr = HRESULT_FROM_WIN32( GetLastError());
  1727. }
  1728. MailboxResetRemote();
  1729. return hr;
  1730. }
  1731. /////////////////////////////////////////////////////////////////////////////
  1732. // SearchDomainsForMailbox, public
  1733. //
  1734. // Purpose:
  1735. // Search all domains for the first occurance of a given mailbox
  1736. //
  1737. // Arguments:
  1738. // LPWSTR psUserName : Mailbox to search for
  1739. // LPWSTR *ppsDomain : Name of domain mailbox found in !Must be freed by caller
  1740. //
  1741. // Returns: S_OK if mailbox found (if not NULL ppsDomain will contain the domain name),
  1742. // HRESULT_FROM_WIN32( ERROR_NO_SUCH_USER ) if mailbox not found in any domain,
  1743. // appropriate HRESULT otherwise
  1744. HRESULT CP3AdminWorker::SearchDomainsForMailbox( LPTSTR psUserName, LPTSTR *ppsDomain )
  1745. {
  1746. if ( NULL == psUserName )
  1747. return E_INVALIDARG;
  1748. if ( 0 == wcslen( psUserName ))
  1749. return E_INVALIDARG;
  1750. if ( NULL != ppsDomain )
  1751. *ppsDomain = NULL;
  1752. HRESULT hr = S_OK;
  1753. bool bFound = false;
  1754. BSTR bstrName;
  1755. WCHAR sEmailAddr[POP3_MAX_ADDRESS_LENGTH];
  1756. VARIANT v;
  1757. CMailBox mailboxX;
  1758. CComPtr<IP3Config> spIConfig;
  1759. CComPtr<IP3Domains> spIDomains;
  1760. CComPtr<IP3Domain> spIDomain = NULL;
  1761. CComPtr<IEnumVARIANT> spIEnumVARIANT;
  1762. VariantInit( &v );
  1763. hr = CoCreateInstance( __uuidof( P3Config ), NULL, CLSCTX_ALL, __uuidof( IP3Config ),reinterpret_cast<LPVOID *>( &spIConfig ));
  1764. if ( S_OK == hr )
  1765. hr = spIConfig->get_Domains( &spIDomains );
  1766. if ( S_OK == hr )
  1767. hr = spIDomains->get__NewEnum( &spIEnumVARIANT );
  1768. if ( S_OK == hr )
  1769. hr = spIEnumVARIANT->Next( 1, &v, NULL );
  1770. while ( S_OK == hr && !bFound )
  1771. {
  1772. if ( VT_DISPATCH != V_VT( &v ))
  1773. hr = E_UNEXPECTED;
  1774. else
  1775. {
  1776. if ( NULL != spIDomain.p )
  1777. spIDomain.Release();
  1778. hr = V_DISPATCH( &v )->QueryInterface( __uuidof( IP3Domain ), reinterpret_cast<void**>( &spIDomain ));
  1779. }
  1780. if ( S_OK == hr )
  1781. {
  1782. hr = spIDomain->get_Name( &bstrName );
  1783. if ( S_OK == hr )
  1784. { // See if the mailbox already exists
  1785. hr = BuildEmailAddr( bstrName, psUserName, sEmailAddr, sizeof( sEmailAddr )/sizeof(WCHAR) );
  1786. if ( S_OK == hr )
  1787. {
  1788. if ( mailboxX.OpenMailBox( sEmailAddr ))
  1789. { // We found the mailbox, time to exit
  1790. bFound = true;
  1791. mailboxX.CloseMailBox(); // return void!
  1792. if ( NULL != ppsDomain )
  1793. { // Let's return the domain name
  1794. *ppsDomain = new WCHAR[ wcslen( bstrName ) + 1];
  1795. if ( NULL == *ppsDomain )
  1796. hr = E_OUTOFMEMORY;
  1797. else
  1798. wcscpy( *ppsDomain, bstrName );
  1799. }
  1800. }
  1801. }
  1802. SysFreeString( bstrName );
  1803. }
  1804. }
  1805. VariantClear( &v );
  1806. if ( S_OK == hr && !bFound )
  1807. {
  1808. hr = spIEnumVARIANT->Next( 1, &v, NULL );
  1809. }
  1810. }
  1811. if ( S_FALSE == hr )
  1812. {
  1813. hr = HRESULT_FROM_WIN32( ERROR_NO_SUCH_USER ) ; // Reached end of enumeration
  1814. }
  1815. return hr;
  1816. }
  1817. /////////////////////////////////////////////////////////////////////////////
  1818. // SetConfirmAddUser, public
  1819. //
  1820. // Purpose:
  1821. // Set the Confirm Add User registry key.
  1822. //
  1823. // Arguments:
  1824. // BOOL bConfirm: new value
  1825. //
  1826. // Returns: S_OK on success, appropriate HRESULT otherwise
  1827. HRESULT CP3AdminWorker::SetConfirmAddUser( BOOL bConfirm )
  1828. {
  1829. HRESULT hr = S_OK;
  1830. if ( TRUE != bConfirm && FALSE != bConfirm )
  1831. hr = HRESULT_FROM_WIN32( ERROR_DS_RANGE_CONSTRAINT );
  1832. else
  1833. {
  1834. DWORD dwValue = bConfirm ? 1 : 0;
  1835. long lRC = RegSetConfirmAddUser( dwValue, m_psMachineName );
  1836. if ( ERROR_SUCCESS != lRC )
  1837. hr = HRESULT_FROM_WIN32( lRC );
  1838. }
  1839. return hr;
  1840. }
  1841. /////////////////////////////////////////////////////////////////////////////
  1842. // SetDomainLock, public
  1843. //
  1844. // Purpose:
  1845. // Set the domain lock.
  1846. //
  1847. // Arguments:
  1848. // LPWSTR psDomainName : Domain name to lock
  1849. // BOOL bLock : TRUE - to lock the domain, FALSE - to unlock the domain
  1850. //
  1851. // Returns: S_OK on success, appropriate HRESULT otherwise
  1852. HRESULT CP3AdminWorker::SetDomainLock( LPWSTR psDomainName, BOOL bLock )
  1853. {
  1854. // psDomainName - checked by CreateDomainMutex
  1855. HRESULT hr = S_OK;
  1856. HANDLE hMutex = NULL;
  1857. // Validate
  1858. if ( S_OK == hr )
  1859. {
  1860. hr = ValidateDomain( psDomainName );
  1861. }
  1862. // Create a Mutex Name for this domain to ensure we are the only one accessing it.
  1863. hr = CreateDomainMutex( psDomainName, &hMutex );
  1864. // Lock all the Mailboxes
  1865. if ( S_OK == hr )
  1866. {
  1867. if ( bLock )
  1868. {
  1869. if ( !IsDomainLocked( psDomainName ))
  1870. hr = LockDomain( psDomainName );
  1871. else
  1872. hr = HRESULT_FROM_WIN32( ERROR_LOCKED );
  1873. }
  1874. else
  1875. {
  1876. if ( IsDomainLocked( psDomainName ))
  1877. hr = UnlockDomain( psDomainName );
  1878. else
  1879. hr = HRESULT_FROM_WIN32( ERROR_NOT_LOCKED );
  1880. }
  1881. }
  1882. // Cleanup
  1883. if ( NULL != hMutex )
  1884. CloseHandle( hMutex );
  1885. return hr;
  1886. }
  1887. /////////////////////////////////////////////////////////////////////////////
  1888. // SetUserLock, public
  1889. //
  1890. // Purpose:
  1891. // Set the domain lock.
  1892. //
  1893. // Arguments:
  1894. // LPWSTR psDomainName : Domain name of user
  1895. // LPWSTR psUserName : User name to lock
  1896. // BOOL bLock : TRUE - to lock the user, FALSE - to unlock the user
  1897. //
  1898. // Returns: S_OK on success, appropriate HRESULT otherwise
  1899. HRESULT CP3AdminWorker::SetUserLock( LPWSTR psDomainName, LPWSTR psUserName, BOOL bLock )
  1900. {
  1901. // psDomainName - checked by CreateUserMutex
  1902. // psUserName - checked by CreateUserMutex
  1903. HRESULT hr = S_OK;
  1904. HANDLE hMutex = NULL;
  1905. WCHAR sEmailAddr[POP3_MAX_ADDRESS_LENGTH];
  1906. CMailBox mailboxX;
  1907. // Create a Mutex Name for this user to ensure we are the only one accessing it.
  1908. hr = CreateUserMutex( psDomainName, psUserName, &hMutex );
  1909. if ( S_OK == hr )
  1910. {
  1911. if ( FALSE == bLock )
  1912. {
  1913. if ( IsDomainLocked( psDomainName ))
  1914. hr = HRESULT_FROM_WIN32( ERROR_INVALID_DOMAIN_STATE );
  1915. }
  1916. }
  1917. if ( S_OK == hr )
  1918. hr = BuildEmailAddr( psDomainName, psUserName, sEmailAddr, sizeof( sEmailAddr )/sizeof(WCHAR));
  1919. if ( S_OK == hr )
  1920. hr = MailboxSetRemote();
  1921. if ( S_OK == hr )
  1922. { // Validate the Mailbox
  1923. if ( !mailboxX.OpenMailBox( sEmailAddr ))
  1924. hr = HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND );
  1925. }
  1926. // Lock/Unlock the Mailbox
  1927. if ( S_OK == hr )
  1928. {
  1929. if ( bLock )
  1930. {
  1931. if ( !isUserLocked( psDomainName, psUserName ))
  1932. { // Lock the user
  1933. hr = LockUser( psDomainName, psUserName );
  1934. }
  1935. else
  1936. hr = HRESULT_FROM_WIN32( ERROR_LOCKED );
  1937. }
  1938. else
  1939. {
  1940. if ( isUserLocked( psDomainName, psUserName ))
  1941. { // UnLock the user
  1942. hr = UnlockUser( psDomainName, psUserName );
  1943. }
  1944. else
  1945. hr = HRESULT_FROM_WIN32( ERROR_NOT_LOCKED );
  1946. }
  1947. mailboxX.CloseMailBox();
  1948. }
  1949. MailboxResetRemote();
  1950. // Cleanup
  1951. if ( NULL != hMutex )
  1952. CloseHandle( hMutex );
  1953. return hr;
  1954. }
  1955. /////////////////////////////////////////////////////////////////////////////
  1956. // SetIISConfig, public
  1957. /////////////////////////////////////////////////////////////////////////////
  1958. // exchange OnSMTP event sink bindings directions
  1959. // {1b3c0666-e470-11d1-aa67-00c04fa345f6}
  1960. //DEFINE_GUID(GUID_PLAT_SMTPSVC,
  1961. //0x1b3c0666, 0xe470, 0x11d1, 0xaa, 0x67, 0x0, 0xc0, 0x4f, 0xa3, 0x45, 0xf6);
  1962. #define GUID_PLAT_SMTPSVC L"{1b3c0666-e470-11d1-aa67-00c04fa345f6}"
  1963. // {fb65c4dc-e468-11d1-aa67-00c04fa345f6}
  1964. //DEFINE_GUID(SMTP_PLAT_SOURCE_TYPE_GUID,
  1965. //0xfb65c4dc, 0xe468, 0x11d1, 0xaa, 0x67, 0x0, 0xc0, 0x4f, 0xa3, 0x45, 0xf6);
  1966. #define SMTP_PLAT_SOURCE_TYPE_GUID L"{fb65c4dc-e468-11d1-aa67-00c04fa345f6}"
  1967. // SMTP Store Events
  1968. // {59175850-e533-11d1-aa67-00c04fa345f6}
  1969. //DECLARE_EVENTGUID_STRING( g_szcatidSmtpStoreDriver, "{59175850-e533-11d1-aa67-00c04fa345f6}");
  1970. //DEFINE_GUID(CATID_SMTP_STORE_DRIVER, 0x59175850, 0xe533, 0x11d1, 0xaa, 0x67, 0x0, 0xc0, 0x4f, 0xa3, 0x45, 0xf6);
  1971. #define CATID_SMTP_STORE_DRIVER L"{59175850-e533-11d1-aa67-00c04fa345f6}"
  1972. #define STR_P3STOREDRIVER_DISPLAY_NAME L"POP 3 SMTP Store Driver"
  1973. #define STR_P3STOREDRIVER_SINKCLASS L"POP3SMTPStoreDriver.CPOP3SMTPStoreDriver"
  1974. #define CLSID_CSimpleDriver L"{9100BE35-711B-4b34-8AC9-BA350C2117BE}"
  1975. /////////////////////////////////////////////////////////////////////////////
  1976. // SetIISConfig, public
  1977. //
  1978. // Purpose:
  1979. // Set the Meta base options required for our SMTP Store Driver to work.
  1980. // This involves:
  1981. // DELETE SMTPSVC/1/DropDirectory
  1982. // Bind our SMTP Store Driver
  1983. //
  1984. // Arguments:
  1985. // BOOL bBindSink : TRUE, perform the necessary configuration
  1986. // FALSE, remove any configuration changes (try to reconstruct DropDirectory setting)
  1987. //
  1988. // Returns: S_OK on success, appropriate HRESULT otherwise
  1989. HRESULT CP3AdminWorker::SetIISConfig( bool bBindSink )
  1990. {
  1991. HRESULT hr;
  1992. CComPtr<IEventBindingManager> spIBindingManager;
  1993. CComPtr<IEventBindings> spIBindings;
  1994. CComPtr<IEventBinding> spIBinding;
  1995. CComPtr<IEventPropertyBag> spISourceProps;
  1996. CComPtr<IEventUtil> spIUtil;
  1997. /////////////////////////////
  1998. // Bind our SMTP Store Driver
  1999. /////////////////////////////
  2000. hr = CoCreateInstance( __uuidof( CEventUtil ), NULL, CLSCTX_ALL, __uuidof( IEventUtil ),reinterpret_cast<LPVOID*>( &spIUtil ));
  2001. if ( S_OK == hr && NULL != spIUtil.p )
  2002. {
  2003. hr = spIUtil->RegisterSource(CComBSTR( SMTP_PLAT_SOURCE_TYPE_GUID ),
  2004. CComBSTR( GUID_PLAT_SMTPSVC ),
  2005. 1,
  2006. CComBSTR( L"smtpsvc" ),
  2007. CComBSTR( L"" ),
  2008. CComBSTR( L"event.metabasedatabasemanager" ),
  2009. CComBSTR( L"smtpsvc 1" ), // Set up the default site (instance)
  2010. &spIBindingManager);
  2011. if ( S_OK == hr )
  2012. {
  2013. hr = spIBindingManager->get_Bindings( _bstr_t( CATID_SMTP_STORE_DRIVER ), &spIBindings );
  2014. if ( S_OK == hr )
  2015. {
  2016. if ( bBindSink )
  2017. { // Create binding
  2018. hr = spIBindings->Add( _bstr_t( CLSID_CSimpleDriver ),&spIBinding );
  2019. if ( S_OK == hr )
  2020. {
  2021. hr = spIBinding->put_DisplayName( _bstr_t( STR_P3STOREDRIVER_DISPLAY_NAME ));
  2022. if SUCCEEDED( hr )
  2023. hr = spIBinding->put_SinkClass( _bstr_t( STR_P3STOREDRIVER_SINKCLASS ));
  2024. if SUCCEEDED( hr )
  2025. hr = spIBinding->get_SourceProperties(&spISourceProps);
  2026. if SUCCEEDED( hr )
  2027. {
  2028. _variant_t _v(static_cast<long>(0));
  2029. hr = spISourceProps->Add( _bstr_t( L"priority" ), &_v );
  2030. }
  2031. if SUCCEEDED( hr )
  2032. hr = spIBinding->Save();
  2033. }
  2034. }
  2035. else
  2036. { // Delete binding
  2037. _variant_t _v( CLSID_CSimpleDriver );
  2038. hr = spIBindings->Remove( &_v );
  2039. }
  2040. }
  2041. }
  2042. }
  2043. if ( SUCCEEDED( hr ) && !bBindSink ) // Unregistering
  2044. { // Remove all domains from SMTP
  2045. ULONG ulFetch;
  2046. BSTR bstrDomainName;
  2047. VARIANT v;
  2048. CComPtr<IADs> spIADs = NULL;
  2049. CComPtr<IEnumVARIANT> spIEnumVARIANT = NULL;
  2050. VariantInit( &v );
  2051. hr = GetDomainEnum( &spIEnumVARIANT );
  2052. while ( S_OK == hr )
  2053. {
  2054. hr = spIEnumVARIANT->Next( 1, &v, &ulFetch );
  2055. if ( S_OK == hr && 1 == ulFetch )
  2056. {
  2057. if ( VT_DISPATCH == V_VT( &v ))
  2058. hr = V_DISPATCH( &v )->QueryInterface( __uuidof( IADs ), reinterpret_cast<void**>( &spIADs ));
  2059. else
  2060. hr = E_UNEXPECTED;
  2061. VariantClear( &v );
  2062. if ( S_OK == hr )
  2063. {
  2064. hr = spIADs->get_Name( &bstrDomainName );
  2065. if ( S_OK == hr )
  2066. {
  2067. hr = ValidateDomain( bstrDomainName );
  2068. if ( S_OK == hr )
  2069. hr = RemoveSMTPDomain( bstrDomainName );
  2070. SysFreeString( bstrDomainName );
  2071. }
  2072. spIADs.Release();
  2073. spIADs = NULL;
  2074. }
  2075. }
  2076. if ( S_OK == hr )
  2077. { // We deleted an SMTP domain, therefore we need a new Enum
  2078. spIEnumVARIANT.Release();
  2079. hr = GetDomainEnum( &spIEnumVARIANT );
  2080. }
  2081. else if ( HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ) == hr )
  2082. hr = S_OK; // Some of the domains might not be our domains.
  2083. }
  2084. if ( S_FALSE == hr )
  2085. hr = S_OK;
  2086. }
  2087. ///////////////////////////////////////
  2088. // Make some final registry key changes
  2089. ///////////////////////////////////////
  2090. if SUCCEEDED( hr )
  2091. {
  2092. WCHAR sBuffer[POP3_MAX_MAILROOT_LENGTH];
  2093. hr = GetDefaultMailRoot( sBuffer, sizeof(sBuffer)/sizeof(WCHAR) );
  2094. if ( S_OK == hr )
  2095. hr = SetMailroot( sBuffer );
  2096. if ( S_OK == hr )
  2097. {
  2098. long lRC;
  2099. lRC = RegSetupOCM();
  2100. if ( ERROR_SUCCESS != lRC )
  2101. hr = HRESULT_FROM_WIN32(lRC);
  2102. }
  2103. }
  2104. return hr;
  2105. }
  2106. /////////////////////////////////////////////////////////////////////////////
  2107. // SetLoggingLevel, public
  2108. //
  2109. // Purpose:
  2110. // Set the LoggingLevel registry key.
  2111. //
  2112. // Arguments:
  2113. // long lLoggingLevel : new value
  2114. //
  2115. // Returns: S_OK on success, appropriate HRESULT otherwise
  2116. HRESULT CP3AdminWorker::SetLoggingLevel( long lLoggingLevel )
  2117. {
  2118. if ( 0 > lLoggingLevel || 3 < lLoggingLevel )
  2119. return HRESULT_FROM_WIN32( ERROR_DS_RANGE_CONSTRAINT );
  2120. HRESULT hr = S_OK;
  2121. long lRC;
  2122. lRC = RegSetLoggingLevel( lLoggingLevel, m_psMachineName );
  2123. if ( ERROR_SUCCESS != lRC )
  2124. hr = HRESULT_FROM_WIN32( lRC );
  2125. return hr;
  2126. }
  2127. /////////////////////////////////////////////////////////////////////////////
  2128. // SetMachineName, public
  2129. //
  2130. // Purpose:
  2131. // Set the Machine Name that all operations should be performed on.
  2132. // Note: We can not administer remote machine using AD authentication if they are in a different domain
  2133. //
  2134. // Arguments:
  2135. // LPWSTR psMachineName : new value, NULL means Local Machine.
  2136. //
  2137. // Returns: S_OK on success, appropriate HRESULT otherwise
  2138. HRESULT CP3AdminWorker::SetMachineName( LPWSTR psMachineName )
  2139. {
  2140. if ( !m_isPOP3Installed )
  2141. return E_UNEXPECTED;
  2142. HRESULT hr = S_OK;
  2143. if ( NULL != m_psMachineName )
  2144. {
  2145. delete m_psMachineName;
  2146. m_psMachineName = NULL;
  2147. }
  2148. if ( NULL != m_psMachineMailRoot )
  2149. {
  2150. delete m_psMachineMailRoot ;
  2151. m_psMachineMailRoot = NULL;
  2152. }
  2153. if ( NULL != psMachineName )
  2154. {
  2155. DWORD dwLength = wcslen( psMachineName );
  2156. if ( 0 < dwLength )
  2157. {
  2158. if ( S_OK == hr )
  2159. {
  2160. m_psMachineName = new WCHAR[dwLength+1];
  2161. m_psMachineMailRoot = new WCHAR[POP3_MAX_MAILROOT_LENGTH];
  2162. if ( NULL != m_psMachineName && NULL != m_psMachineMailRoot )
  2163. {
  2164. wcscpy( m_psMachineName, psMachineName );
  2165. hr = GetMailroot( m_psMachineMailRoot, POP3_MAX_MAILROOT_LENGTH );
  2166. }
  2167. else
  2168. hr = E_OUTOFMEMORY;
  2169. }
  2170. if ( S_OK == hr )
  2171. { // Check the Auth Method of the remote machine
  2172. CComPtr<IAuthMethod> spIAuthMethod;
  2173. hr = GetCurrentAuthentication( &spIAuthMethod ); // Enforces that remote machine using AD authentication are in our domain!
  2174. }
  2175. }
  2176. }
  2177. return hr;
  2178. }
  2179. /////////////////////////////////////////////////////////////////////////////
  2180. // SetMailroot, public
  2181. //
  2182. // Purpose:
  2183. // Set the Mail root registry key.
  2184. //
  2185. // Arguments:
  2186. // LPWSTR psMailRoot : new value
  2187. //
  2188. // Returns: S_OK on success, appropriate HRESULT otherwise
  2189. HRESULT CP3AdminWorker::SetMailroot( LPWSTR psMailRoot )
  2190. {
  2191. if ( NULL == psMailRoot )
  2192. return E_INVALIDARG;
  2193. if ( POP3_MAX_MAILROOT_LENGTH < wcslen( psMailRoot ))
  2194. return E_INVALIDARG;
  2195. HRESULT hr = S_OK;
  2196. TCHAR sBuffer[POP3_MAX_MAILROOT_LENGTH-6], sBuffer2[POP3_MAX_MAILROOT_LENGTH-6]; // Need to leave room for \\? or \\?\UNC
  2197. DWORD dwRC;
  2198. WCHAR sMailRoot[POP3_MAX_PATH];
  2199. // Same logic as GetMailroot
  2200. wcscpy( sMailRoot, psMailRoot );
  2201. if ( NULL != m_psMachineName )
  2202. { // Replace drive: with drive$
  2203. if ( L':' == sMailRoot[1] )
  2204. {
  2205. sMailRoot[1] = L'$';
  2206. if ( sizeof( sMailRoot )/sizeof(WCHAR) > (wcslen( sMailRoot ) + wcslen( m_psMachineName ) + 3) )
  2207. {
  2208. LPWSTR psBuffer = new WCHAR[wcslen(psMailRoot)+1];
  2209. if ( NULL != psBuffer )
  2210. {
  2211. wcscpy( psBuffer, sMailRoot );
  2212. wcscpy( sMailRoot, L"\\\\" );
  2213. wcscat( sMailRoot, m_psMachineName );
  2214. wcscat( sMailRoot, L"\\" );
  2215. wcscat( sMailRoot, psBuffer );
  2216. delete [] psBuffer;
  2217. }
  2218. else
  2219. hr = HRESULT_FROM_WIN32( ERROR_OUTOFMEMORY );
  2220. }
  2221. else
  2222. hr = HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER );
  2223. }
  2224. }
  2225. if ( S_OK == hr )
  2226. {
  2227. hr = HRESULT_FROM_WIN32( ERROR_BAD_PATHNAME );
  2228. dwRC = GetFileAttributes( sMailRoot );
  2229. if ( -1 != dwRC )
  2230. { // Must begin with x:\ or \\.
  2231. if ( ( FILE_ATTRIBUTE_DIRECTORY & dwRC ) && ( ( 0 == _wcsnicmp( psMailRoot+1, L":\\", 2 )) || ( 0 == _wcsnicmp( psMailRoot, L"\\\\", 2 ))))
  2232. {
  2233. if ( GetVolumePathName( sMailRoot, sBuffer, sizeof( sBuffer )/sizeof( TCHAR )))
  2234. {
  2235. if ( GetVolumeNameForVolumeMountPoint( sBuffer, sBuffer2, sizeof( sBuffer2 )/sizeof( TCHAR )))
  2236. { // Make sure the mailroot is not CDROM or removable disk
  2237. if ( DRIVE_FIXED == GetDriveType( sBuffer ))
  2238. hr = S_OK;
  2239. }
  2240. else
  2241. { // Make sure this is a UNC Path
  2242. if ( NULL == wcschr( sMailRoot, L':' ))
  2243. hr = S_OK;
  2244. }
  2245. }
  2246. }
  2247. else
  2248. hr = HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND );
  2249. }
  2250. else
  2251. hr = HRESULT_FROM_WIN32( GetLastError());
  2252. }
  2253. if ( S_OK == hr )
  2254. {
  2255. //Set the default ACLs for the mailroot directory
  2256. 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)";
  2257. PSECURITY_DESCRIPTOR pSD;
  2258. ULONG lSize=0;
  2259. if(ConvertStringSecurityDescriptorToSecurityDescriptorW( wszSDL, SDDL_REVISION_1, &pSD, &lSize))
  2260. {
  2261. if( !SetFileSecurityW(sMailRoot, DACL_SECURITY_INFORMATION|PROTECTED_DACL_SECURITY_INFORMATION, pSD) )
  2262. hr = HRESULT_FROM_WIN32( GetLastError());
  2263. else
  2264. hr = HRESULT_FROM_WIN32( SetMailBoxDACL(sMailRoot, pSD, 2));
  2265. LocalFree(pSD);
  2266. }
  2267. else
  2268. hr = HRESULT_FROM_WIN32( GetLastError());
  2269. }
  2270. if( S_OK == hr )
  2271. {
  2272. hr = HRESULT_FROM_WIN32( RegSetMailRoot( psMailRoot, m_psMachineName ));
  2273. if( S_OK == hr )
  2274. {
  2275. if ( NULL == m_psMachineName )
  2276. {
  2277. if ( !CMailBox::SetMailRoot( ))
  2278. hr = E_FAIL;
  2279. }
  2280. else
  2281. hr = GetMailroot( m_psMachineMailRoot, POP3_MAX_MAILROOT_LENGTH );
  2282. }
  2283. }
  2284. return hr;
  2285. }
  2286. /////////////////////////////////////////////////////////////////////////////
  2287. // SetPort, public
  2288. //
  2289. // Purpose:
  2290. // Set the Port registry key.
  2291. //
  2292. // Arguments:
  2293. // long lPort : new value
  2294. //
  2295. // Returns: S_OK on success, appropriate HRESULT otherwise
  2296. HRESULT CP3AdminWorker::SetPort( long lPort )
  2297. {
  2298. long lRC;
  2299. if ( 1 > lPort || 65535 < lPort )
  2300. lRC = ERROR_DS_RANGE_CONSTRAINT;
  2301. else
  2302. lRC = RegSetPort( lPort, m_psMachineName );
  2303. if ( ERROR_SUCCESS == lRC )
  2304. return S_OK;
  2305. return HRESULT_FROM_WIN32( lRC );
  2306. }
  2307. /////////////////////////////////////////////////////////////////////////////
  2308. // SetSockets, public
  2309. //
  2310. // Purpose:
  2311. // Set the Sockets registry keys;
  2312. //
  2313. // Arguments:
  2314. // long lMax: new Max ( must be >= lMin && >= lMin + lThreshold )
  2315. // long lMin: new Min ( must be >= lThreshold )
  2316. // long lThreshold: new Threshold ( must be > 0 && < lMax. Special case 0 if lMin == lMax
  2317. // long lBacklog: new Backlog ( must be > 0 )
  2318. //
  2319. // Returns: S_OK on success, appropriate HRESULT otherwise
  2320. HRESULT CP3AdminWorker::SetSockets( long lMax, long lMin, long lThreshold, long lBacklog )
  2321. {
  2322. long lRC;
  2323. if ( (1 > lMax || 32000 < lMax) ||
  2324. (1 > lMin || 32000 < lMin) ||
  2325. (0 > lThreshold || 100 < lThreshold) ||
  2326. (0 > lBacklog || 100 < lBacklog)
  2327. )
  2328. return HRESULT_FROM_WIN32( ERROR_DS_RANGE_CONSTRAINT );
  2329. if ( (lMax < lMin) || (lMax < lMin + lThreshold) )
  2330. return E_INVALIDARG;
  2331. if ( lMin < lThreshold )
  2332. return E_INVALIDARG;
  2333. if ( (1 > lThreshold) && !((lMin == lMax) && (lThreshold == 0)) )
  2334. return E_INVALIDARG;
  2335. lRC = RegSetSocketMax( lMax, m_psMachineName );
  2336. if ( ERROR_SUCCESS == lRC )
  2337. lRC = RegSetSocketMin( lMin, m_psMachineName );
  2338. if ( ERROR_SUCCESS == lRC )
  2339. lRC = RegSetSocketThreshold( lThreshold, m_psMachineName );
  2340. if ( ERROR_SUCCESS == lRC )
  2341. lRC = RegSetSocketBacklog( lBacklog, m_psMachineName );
  2342. if ( ERROR_SUCCESS == lRC )
  2343. return S_OK;
  2344. return HRESULT_FROM_WIN32( lRC );
  2345. }
  2346. /////////////////////////////////////////////////////////////////////////////
  2347. // SetSPARequired, public
  2348. //
  2349. // Purpose:
  2350. // Set the SPA Required registry key.
  2351. //
  2352. // Arguments:
  2353. // BOOL bSPARequired : new value
  2354. //
  2355. // Returns: S_OK on success, appropriate HRESULT otherwise
  2356. HRESULT CP3AdminWorker::SetSPARequired( BOOL bSPARequired )
  2357. {
  2358. HRESULT hr = S_OK;
  2359. if ( TRUE != bSPARequired && FALSE != bSPARequired )
  2360. hr = HRESULT_FROM_WIN32( ERROR_DS_RANGE_CONSTRAINT );
  2361. else
  2362. {
  2363. DWORD dwValue = bSPARequired ? 1 : 0;
  2364. if ( 1 == dwValue )
  2365. {
  2366. CComPtr<IAuthMethod> spIAuthMethod;
  2367. BSTR bstrAuthType;
  2368. hr = GetCurrentAuthentication( &spIAuthMethod );
  2369. if ( S_OK == hr )
  2370. hr = spIAuthMethod->get_ID( &bstrAuthType );
  2371. if ( S_OK == hr )
  2372. {
  2373. if ( 0 == _wcsicmp( bstrAuthType, SZ_AUTH_ID_MD5_HASH ))
  2374. hr = HRESULT_FROM_WIN32( ERROR_DS_INAPPROPRIATE_AUTH );
  2375. SysFreeString( bstrAuthType );
  2376. }
  2377. }
  2378. if ( S_OK == hr )
  2379. {
  2380. long lRC = RegSetSPARequired( dwValue, m_psMachineName );
  2381. if ( ERROR_SUCCESS != lRC )
  2382. hr = HRESULT_FROM_WIN32( lRC );
  2383. }
  2384. }
  2385. return hr;
  2386. }
  2387. /////////////////////////////////////////////////////////////////////////////
  2388. // SetThreadCountPerCPU, public
  2389. //
  2390. // Purpose:
  2391. // Set the thread count registry key.
  2392. //
  2393. // Arguments:
  2394. // long lCount : new value
  2395. //
  2396. // Returns: S_OK on success, appropriate HRESULT otherwise
  2397. HRESULT CP3AdminWorker::SetThreadCountPerCPU( long lCount )
  2398. {
  2399. long lRC;
  2400. if ( 1 > lCount || 32 < lCount )
  2401. lRC = ERROR_DS_RANGE_CONSTRAINT;
  2402. else
  2403. lRC = RegSetThreadCount( lCount, m_psMachineName );
  2404. if ( ERROR_SUCCESS == lRC )
  2405. return S_OK;
  2406. return HRESULT_FROM_WIN32( lRC );
  2407. }
  2408. /////////////////////////////////////////////////////////////////////////////
  2409. // StartService, public
  2410. //
  2411. // Purpose:
  2412. // Ask the Service Control Manager to start the service.
  2413. //
  2414. // Arguments:
  2415. //
  2416. // Returns: S_OK on success, appropriate HRESULT otherwise
  2417. HRESULT CP3AdminWorker::StartService( LPWSTR psService )
  2418. {
  2419. if ( NULL == psService )
  2420. return E_INVALIDARG;
  2421. if ( 0 == _wcsicmp( POP3_SERVICE_NAME, psService ) ||
  2422. 0 == _wcsicmp( SMTP_SERVICE_NAME_W, psService ) ||
  2423. 0 == _wcsicmp( IISADMIN_SERVICE_NAME, psService ) ||
  2424. 0 == _wcsicmp( W3_SERVICE_NAME, psService )
  2425. )
  2426. return _StartService( psService, m_psMachineName );
  2427. else
  2428. return E_INVALIDARG;
  2429. }
  2430. /////////////////////////////////////////////////////////////////////////////
  2431. // StopService, public
  2432. //
  2433. // Purpose:
  2434. // Ask the Service Control Manager to stop the service.
  2435. //
  2436. // Arguments:
  2437. //
  2438. // Returns: S_OK on success, appropriate HRESULT otherwise
  2439. HRESULT CP3AdminWorker::StopService( LPWSTR psService )
  2440. {
  2441. if ( NULL == psService )
  2442. return E_INVALIDARG;
  2443. if ( 0 == _wcsicmp( POP3_SERVICE_NAME, psService ) ||
  2444. 0 == _wcsicmp( SMTP_SERVICE_NAME_W, psService ) ||
  2445. 0 == _wcsicmp( IISADMIN_SERVICE_NAME, psService ) ||
  2446. 0 == _wcsicmp( W3_SERVICE_NAME, psService )
  2447. )
  2448. return _StopService( psService, TRUE, m_psMachineName);
  2449. else
  2450. return E_INVALIDARG;
  2451. }
  2452. /////////////////////////////////////////////////////////////////////////////
  2453. // UnlockDomain, public
  2454. //
  2455. // Purpose:
  2456. // Unlock all the mailboxes in the domain.
  2457. // This involves renaming all the mailbox lock files so that the Service
  2458. // can once again access them
  2459. // Plus deleting the file in the domain directory.
  2460. //
  2461. // Arguments:
  2462. // LPWSTR psDomainName : domain to unlock
  2463. //
  2464. // Returns: S_OK on success, appropriate HRESULT otherwise
  2465. HRESULT CP3AdminWorker::UnlockDomain( LPWSTR psDomainName )
  2466. {
  2467. // psDomainName - checked by BuildDomainPath
  2468. HRESULT hr;
  2469. HANDLE hfSearch;
  2470. WCHAR sBuffer[POP3_MAX_PATH];
  2471. WCHAR sDomainPath[POP3_MAX_PATH];
  2472. WCHAR sLockFile[POP3_MAX_PATH];
  2473. WCHAR sRenameFile[POP3_MAX_PATH];
  2474. WIN32_FIND_DATA stFindFileData;
  2475. hr = BuildDomainPath( psDomainName, sDomainPath, sizeof( sBuffer )/sizeof(WCHAR) );
  2476. if ( S_OK == hr )
  2477. { // Directory Search
  2478. wcscpy( sBuffer, sDomainPath );
  2479. if ((sizeof( sBuffer )/sizeof(WCHAR)) > (wcslen( sBuffer ) + wcslen(MAILBOX_PREFIX_W) + wcslen(MAILBOX_EXTENSION_W)) + 2 )
  2480. {
  2481. wcscat( sBuffer, L"\\" );
  2482. wcscat( sBuffer, MAILBOX_PREFIX_W );
  2483. wcscat( sBuffer, L"*" );
  2484. wcscat( sBuffer, MAILBOX_EXTENSION_W );
  2485. }
  2486. else
  2487. hr = E_UNEXPECTED;
  2488. hfSearch = FindFirstFileEx( sBuffer, FindExInfoStandard, &stFindFileData, FindExSearchLimitToDirectories, NULL, 0 );
  2489. if ( INVALID_HANDLE_VALUE == hfSearch )
  2490. hr = HRESULT_FROM_WIN32( GetLastError());
  2491. while ( S_OK == hr )
  2492. { // Lock each directory (user)
  2493. if ( FILE_ATTRIBUTE_DIRECTORY == ( FILE_ATTRIBUTE_DIRECTORY & stFindFileData.dwFileAttributes ))
  2494. {
  2495. if (( (sizeof( sLockFile )/sizeof(WCHAR)) > ( wcslen( sDomainPath ) + wcslen( stFindFileData.cFileName ) + wcslen( LOCK_FILENAME ) + 2 )) &&
  2496. ( (sizeof( sRenameFile )/sizeof(WCHAR)) > ( wcslen( sDomainPath ) + wcslen( stFindFileData.cFileName ) + wcslen( LOCKRENAME_FILENAME ) + 2 )))
  2497. {
  2498. wcscpy( sLockFile, sDomainPath );
  2499. wcscat( sLockFile, L"\\" );
  2500. wcscat( sLockFile, stFindFileData.cFileName );
  2501. wcscat( sLockFile, L"\\" );
  2502. wcscpy( sRenameFile, sLockFile );
  2503. wcscat( sLockFile, LOCK_FILENAME );
  2504. wcscat( sRenameFile, LOCKRENAME_FILENAME );
  2505. if ( !MoveFile( sRenameFile, sLockFile ))
  2506. { // If the rename file does not exist, that is okay.
  2507. DWORD dwRC = GetLastError();
  2508. if ( ERROR_FILE_NOT_FOUND != dwRC )
  2509. hr = HRESULT_FROM_WIN32(dwRC);
  2510. }
  2511. }
  2512. }
  2513. if ( !FindNextFile( hfSearch, &stFindFileData ))
  2514. hr = HRESULT_FROM_WIN32(GetLastError());
  2515. }
  2516. if ( HRESULT_FROM_WIN32(ERROR_NO_MORE_FILES) == hr || HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr )
  2517. hr = S_OK;
  2518. if(INVALID_HANDLE_VALUE!=hfSearch)
  2519. {
  2520. FindClose(hfSearch);
  2521. hfSearch=INVALID_HANDLE_VALUE;
  2522. }
  2523. if ( S_OK == hr )
  2524. {
  2525. if ((sizeof( sBuffer )/sizeof(WCHAR)) > (wcslen( sDomainPath ) + wcslen(LOCKRENAME_FILENAME) + 1 ))
  2526. {
  2527. wcscpy( sBuffer, sDomainPath );
  2528. wcscat( sBuffer, L"\\" );
  2529. wcscat( sBuffer, LOCKRENAME_FILENAME );
  2530. if ( !DeleteFile( sBuffer ))
  2531. hr = HRESULT_FROM_WIN32(GetLastError());
  2532. }
  2533. }
  2534. }
  2535. return hr;
  2536. }
  2537. /////////////////////////////////////////////////////////////////////////////
  2538. // UnlockUser, public
  2539. //
  2540. // Purpose:
  2541. // Unlock all the mailboxes in the domain.
  2542. // This involves renaming all the mailbox lock files so that the Service
  2543. // can once again access them
  2544. //
  2545. // Arguments:
  2546. // LPWSTR psDomainName : domain of user
  2547. // LPWSTR psUserName : user to unlock
  2548. //
  2549. // Returns: S_OK on success, appropriate HRESULT otherwise
  2550. HRESULT CP3AdminWorker::UnlockUser( LPWSTR psDomainName, LPWSTR psUserName )
  2551. {
  2552. // psDomainName - checked by BuildUserPath
  2553. // psUserName - checked by BuildUserPath
  2554. HRESULT hr = S_OK;
  2555. WCHAR sBuffer[POP3_MAX_PATH];
  2556. WCHAR sLockFile[POP3_MAX_PATH];
  2557. WCHAR sRenameFile[POP3_MAX_PATH];
  2558. hr = BuildUserPath( psDomainName, psUserName, sBuffer, sizeof( sBuffer )/sizeof(WCHAR) );
  2559. if ( S_OK == hr )
  2560. {
  2561. if (( (sizeof( sLockFile )/sizeof(WCHAR)) > ( wcslen( sBuffer ) + wcslen( LOCK_FILENAME ) + 1 )) &&
  2562. ( (sizeof( sRenameFile )/sizeof(WCHAR)) > ( wcslen( sBuffer ) + wcslen( LOCKRENAME_FILENAME ) + 1 )))
  2563. {
  2564. wcscpy( sLockFile, sBuffer );
  2565. wcscat( sLockFile, L"\\" );
  2566. wcscpy( sRenameFile, sLockFile );
  2567. wcscat( sLockFile, LOCK_FILENAME );
  2568. wcscat( sRenameFile, LOCKRENAME_FILENAME );
  2569. if ( !MoveFile( sRenameFile, sLockFile ))
  2570. {
  2571. DWORD dwRC = GetLastError();
  2572. hr = HRESULT_FROM_WIN32(dwRC);
  2573. }
  2574. }
  2575. }
  2576. return hr;
  2577. }
  2578. /////////////////////////////////////////////////////////////////////////////
  2579. // ValidateDomain, public
  2580. //
  2581. // Purpose:
  2582. // Validate the Domain.
  2583. // This involves:
  2584. // Verify it exists in SMTP and our store
  2585. //
  2586. // Arguments:
  2587. // LPWSTR psDomainName : Domain name to validate
  2588. //
  2589. // Returns: S_OK on success, appropriate HRESULT otherwise
  2590. HRESULT CP3AdminWorker::ValidateDomain( LPWSTR psDomainName ) const
  2591. {
  2592. // psDomainName - checked by ExistsSMTPDomain
  2593. HRESULT hr;
  2594. // Validate the domain in SMTP
  2595. hr = ExistsSMTPDomain( psDomainName );
  2596. if ( HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ) == hr )
  2597. hr = HRESULT_FROM_WIN32( ERROR_NO_SUCH_DOMAIN );
  2598. if ( S_OK == hr ) // Validate the domain in the Store
  2599. hr = ExistsStoreDomain( psDomainName );
  2600. return hr;
  2601. }
  2602. //////////////////////////////////////////////////////////////////////
  2603. // Implementation, private
  2604. //////////////////////////////////////////////////////////////////////
  2605. /////////////////////////////////////////////////////////////////////////////
  2606. // CreateDomainMutex, protected
  2607. //
  2608. // Purpose:
  2609. // Synchronize access for domain operations.
  2610. //
  2611. // Arguments:
  2612. // LPWSTR psDomainName : Domain name
  2613. // HANDLE *hMutex : return value
  2614. //
  2615. // Returns: S_OK on success, appropriate HRESULT otherwise
  2616. HRESULT CP3AdminWorker::CreateDomainMutex( LPWSTR psDomainName, HANDLE *phMutex )
  2617. {
  2618. if ( NULL == psDomainName )
  2619. return E_INVALIDARG;
  2620. if ( NULL == phMutex )
  2621. return E_INVALIDARG;
  2622. HRESULT hr = S_OK;
  2623. WCHAR sName[POP3_MAX_DOMAIN_LENGTH+64];
  2624. *phMutex = NULL;
  2625. if ( (sizeof( sName )/sizeof(WCHAR)) > ( wcslen( DOMAINMUTEX_NAME ) + wcslen( psDomainName )))
  2626. {
  2627. wcscpy( sName, DOMAINMUTEX_NAME );
  2628. wcscat( sName, psDomainName );
  2629. *phMutex = CreateMutex( NULL, TRUE, sName );
  2630. }
  2631. if ( NULL == *phMutex )
  2632. {
  2633. hr = HRESULT_FROM_WIN32( GetLastError());
  2634. if SUCCEEDED( hr ) hr = E_FAIL;
  2635. }
  2636. else if ( ERROR_ALREADY_EXISTS == GetLastError() )
  2637. {
  2638. hr = E_ACCESSDENIED;
  2639. }
  2640. return hr;
  2641. }
  2642. /////////////////////////////////////////////////////////////////////////////
  2643. // CreateUserMutex, protected
  2644. //
  2645. // Purpose:
  2646. // Synchronize access for user operations.
  2647. //
  2648. // Arguments:
  2649. // LPWSTR psDomainName : Domain name
  2650. // LPWSTR psUserName : User
  2651. // HANDLE *hMutex : return value
  2652. //
  2653. // Returns: S_OK on success, appropriate HRESULT otherwise
  2654. HRESULT CP3AdminWorker::CreateUserMutex( LPWSTR psDomainName, LPWSTR psUserName, HANDLE *phMutex )
  2655. {
  2656. if ( NULL == psDomainName )
  2657. return E_INVALIDARG;
  2658. if ( NULL == psUserName )
  2659. return E_INVALIDARG;
  2660. if ( NULL == phMutex )
  2661. return E_INVALIDARG;
  2662. HRESULT hr = S_OK;
  2663. WCHAR sName[POP3_MAX_ADDRESS_LENGTH+64];
  2664. *phMutex = NULL;
  2665. if ( (sizeof( sName )/sizeof(WCHAR)) > ( wcslen( USERMUTEX_NAME ) + wcslen( psUserName ) + wcslen( psDomainName ) + 1))
  2666. {
  2667. wcscpy( sName, USERMUTEX_NAME );
  2668. wcscat( sName, psUserName );
  2669. wcscat( sName, L"@" );
  2670. wcscat( sName, psDomainName );
  2671. *phMutex = CreateMutex( NULL, TRUE, sName );
  2672. }
  2673. if ( NULL == *phMutex )
  2674. {
  2675. hr = HRESULT_FROM_WIN32( GetLastError());
  2676. if SUCCEEDED( hr ) hr = E_FAIL;
  2677. }
  2678. else if ( ERROR_ALREADY_EXISTS == GetLastError() )
  2679. hr = E_ACCESSDENIED;
  2680. return hr;
  2681. }
  2682. HRESULT CP3AdminWorker::AddSMTPDomain( LPWSTR psDomainName )
  2683. {
  2684. HRESULT hr;
  2685. WCHAR sBuffer[POP3_MAX_PATH];
  2686. _bstr_t _bstrClass( L"IIsSmtpDomain" );
  2687. _variant_t _v;
  2688. CComPtr<IADsContainer> spIADsContainer;
  2689. CComPtr<IADs> spIADs;
  2690. CComPtr<IDispatch> spIDispatch = NULL;
  2691. _bstr_t _bstrDomain = psDomainName;
  2692. hr = GetSMTPDomainPath( sBuffer, NULL, sizeof( sBuffer )/sizeof( WCHAR ));
  2693. if ( S_OK == hr )
  2694. hr = ADsGetObject( sBuffer, IID_IADsContainer, reinterpret_cast<LPVOID*>( &spIADsContainer ));
  2695. if ( SUCCEEDED( hr ))
  2696. { // Invoke the create method on the container object to create the new object of default class, in this case, IIsSmtpDomain.
  2697. hr = spIADsContainer->Create( _bstrClass, _bstrDomain, &spIDispatch );
  2698. if SUCCEEDED( hr )
  2699. { // Get the newly created object
  2700. hr = spIDispatch->QueryInterface( IID_IADs, reinterpret_cast<LPVOID*>( &spIADs ));
  2701. if SUCCEEDED( hr )
  2702. {
  2703. _v.vt = VT_I4;
  2704. _v.lVal = SMTP_DELIVER; // This is what David Braun told us to do! SMTP_ALIAS; // This is what the native tool sets
  2705. hr = spIADs->Put( L"RouteAction", _v );
  2706. if SUCCEEDED( hr )
  2707. hr = spIADs->SetInfo();
  2708. }
  2709. }
  2710. }
  2711. return hr;
  2712. }
  2713. HRESULT CP3AdminWorker::AddStoreDomain( LPWSTR psDomainName )
  2714. {
  2715. // psDomainName - checked by ExistsStoreDomain
  2716. HRESULT hr;
  2717. WCHAR sBuffer[POP3_MAX_PATH];
  2718. hr = ExistsStoreDomain( psDomainName );
  2719. if SUCCEEDED( hr )
  2720. hr = HRESULT_FROM_WIN32( ERROR_FILE_EXISTS );
  2721. else if ( HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ) == hr )
  2722. hr = S_OK;
  2723. if SUCCEEDED( hr )
  2724. {
  2725. hr = BuildDomainPath( psDomainName, sBuffer, sizeof( sBuffer )/sizeof(WCHAR) );
  2726. if ( S_OK == hr )
  2727. {
  2728. if ( !CreateDirectory( sBuffer, NULL ))
  2729. {
  2730. hr = HRESULT_FROM_WIN32( GetLastError());
  2731. if SUCCEEDED( hr ) hr = E_FAIL;
  2732. }
  2733. }
  2734. else
  2735. if SUCCEEDED( hr ) hr = E_UNEXPECTED;
  2736. }
  2737. return hr;
  2738. }
  2739. HRESULT CP3AdminWorker::BuildDomainPath( LPCWSTR psDomainName, LPWSTR psBuffer, DWORD dwBufferSize ) const
  2740. {
  2741. if ( NULL == psDomainName )
  2742. return E_INVALIDARG;
  2743. if ( NULL == psBuffer )
  2744. return E_INVALIDARG;
  2745. USES_CONVERSION;
  2746. HRESULT hr = S_OK;
  2747. LPCWSTR psMailRoot;
  2748. if ( NULL != m_psMachineMailRoot )
  2749. psMailRoot = m_psMachineMailRoot;
  2750. else
  2751. psMailRoot = CMailBox::GetMailRoot();
  2752. if ( (NULL != psMailRoot) && ( 0 < wcslen( psMailRoot )) && (wcslen( psMailRoot ) + wcslen( psDomainName ) + 1) < dwBufferSize )
  2753. { // build the path to the mail dir \MailRoot\Domain
  2754. wcscpy( psBuffer, psMailRoot );
  2755. wcscat( psBuffer, L"\\" );
  2756. wcscat( psBuffer, psDomainName );
  2757. }
  2758. else
  2759. {
  2760. hr = HRESULT_FROM_WIN32( GetLastError() );
  2761. if SUCCEEDED( hr ) hr = E_FAIL;
  2762. }
  2763. return hr;
  2764. }
  2765. HRESULT CP3AdminWorker::BuildEmailAddr( LPCWSTR psDomainName, LPCWSTR psUserName, LPWSTR psEmailAddr, DWORD dwBufferSize ) const
  2766. {
  2767. if ( NULL == psDomainName )
  2768. return E_INVALIDARG;
  2769. if ( NULL == psUserName )
  2770. return E_INVALIDARG;
  2771. if ( NULL == psEmailAddr )
  2772. return E_INVALIDARG;
  2773. HRESULT hr = S_OK;
  2774. if ( ( wcslen( psDomainName ) + wcslen( psUserName ) + 1 ) < dwBufferSize )
  2775. { // build the emailaddress
  2776. wcscpy( psEmailAddr, psUserName );
  2777. wcscat( psEmailAddr, L"@" );
  2778. wcscat( psEmailAddr, psDomainName );
  2779. }
  2780. else
  2781. hr = E_UNEXPECTED;
  2782. return hr;
  2783. }
  2784. HRESULT CP3AdminWorker::BuildEmailAddrW2A( LPCWSTR psDomainName, LPCWSTR psUserName, LPSTR psEmailAddr, DWORD dwBufferSize ) const
  2785. {
  2786. if ( NULL == psDomainName )
  2787. return E_INVALIDARG;
  2788. if ( NULL == psUserName )
  2789. return E_INVALIDARG;
  2790. if ( NULL == psEmailAddr )
  2791. return E_INVALIDARG;
  2792. USES_CONVERSION;
  2793. HRESULT hr = S_OK;
  2794. if ( ( wcslen( psDomainName ) + wcslen( psUserName ) + 1 ) < dwBufferSize )
  2795. { // build the emailaddress
  2796. strcpy( psEmailAddr, W2A( psUserName ));
  2797. strcat( psEmailAddr, "@" );
  2798. strcat( psEmailAddr, W2A( psDomainName ));
  2799. }
  2800. else
  2801. hr = E_UNEXPECTED;
  2802. return hr;
  2803. }
  2804. HRESULT CP3AdminWorker::BuildUserPath( LPCWSTR psDomainName, LPCWSTR psUserName, LPWSTR psBuffer, DWORD dwBufferSize ) const
  2805. {
  2806. // psDomainName - checked by BuildDomainPath
  2807. // psBuffer - checked by BuildDomainPath
  2808. if ( NULL == psUserName )
  2809. return E_INVALIDARG;
  2810. HRESULT hr;
  2811. hr = BuildDomainPath( psDomainName, psBuffer, dwBufferSize );
  2812. if (S_OK == hr)
  2813. {
  2814. if ( (wcslen( psBuffer ) + wcslen( MAILBOX_PREFIX_W ) + wcslen( psUserName ) + wcslen( MAILBOX_EXTENSION_W ) + 1) < dwBufferSize )
  2815. { // build the path to the mail dir \MailRoot\Domain\User
  2816. wcscat( psBuffer, L"\\" );
  2817. wcscat( psBuffer, MAILBOX_PREFIX_W );
  2818. wcscat( psBuffer, psUserName );
  2819. wcscat( psBuffer, MAILBOX_EXTENSION_W );
  2820. }
  2821. else
  2822. hr = E_FAIL;
  2823. }
  2824. return hr;
  2825. }
  2826. bool CP3AdminWorker::ExistsDomain( LPWSTR psDomainName ) const
  2827. {
  2828. // psDomainName - checked by ExistsSMTPDomain
  2829. HRESULT hr;
  2830. hr = ExistsSMTPDomain( psDomainName );
  2831. if SUCCEEDED( hr )
  2832. hr = ExistsStoreDomain( psDomainName );
  2833. return SUCCEEDED( hr ) ? true : false;
  2834. }
  2835. HRESULT CP3AdminWorker::ExistsSMTPDomain( LPWSTR psDomainName ) const
  2836. {
  2837. if ( NULL == psDomainName )
  2838. return E_INVALIDARG;
  2839. if ( !m_isPOP3Installed )
  2840. return S_OK; // By pass checking if running in Pop2Exch scenario.
  2841. HRESULT hr = E_INVALIDARG;
  2842. WCHAR sBuffer[POP3_MAX_PATH];
  2843. _variant_t _v;
  2844. CComPtr<IADs> spIADs;
  2845. hr = GetSMTPDomainPath( sBuffer, psDomainName, sizeof( sBuffer )/sizeof( WCHAR ));
  2846. if ( S_OK == hr )
  2847. hr = ADsGetObject( sBuffer, IID_IADs, reinterpret_cast<LPVOID*>( &spIADs ));
  2848. return hr;
  2849. }
  2850. HRESULT CP3AdminWorker::ExistsStoreDomain( LPWSTR psDomainName ) const
  2851. {
  2852. if ( NULL == psDomainName )
  2853. return E_INVALIDARG;
  2854. HRESULT hr = S_OK;
  2855. WCHAR sBuffer[POP3_MAX_PATH];
  2856. DWORD dwAttrib;
  2857. // Valid Domain Name? || DNS_ERROR_NON_RFC_NAME == dnStatus
  2858. DNS_STATUS dnStatus = DnsValidateName_W( psDomainName, DnsNameDomain );
  2859. hr = ( ERROR_SUCCESS == dnStatus ) ? S_OK : HRESULT_FROM_WIN32( ERROR_INVALID_DOMAINNAME );
  2860. if ( S_OK == hr )
  2861. {
  2862. hr = BuildDomainPath( psDomainName, sBuffer, sizeof( sBuffer )/sizeof(WCHAR) );
  2863. if ( S_OK == hr )
  2864. { // Check the existance of the dir
  2865. dwAttrib = GetFileAttributes( sBuffer );
  2866. if ( (ERROR_NO_FILE_ATTR == dwAttrib) || (FILE_ATTRIBUTE_DIRECTORY != ( FILE_ATTRIBUTE_DIRECTORY & dwAttrib )) )
  2867. { // Domain does not exist!
  2868. hr = HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND );
  2869. }
  2870. }
  2871. else
  2872. if SUCCEEDED( hr ) hr = E_UNEXPECTED;
  2873. }
  2874. return hr;
  2875. }
  2876. HRESULT CP3AdminWorker::GetSMTPDomainPath( LPWSTR psBuffer, LPWSTR psSuffix, DWORD dwBufferSize ) const
  2877. {
  2878. if ( NULL == psBuffer )
  2879. return E_INVALIDARG;
  2880. HRESULT hr = S_OK;
  2881. DWORD dwSuffixLength = 0;
  2882. if ( NULL != psSuffix )
  2883. dwSuffixLength = wcslen( psSuffix ) + 1;
  2884. if ( NULL == m_psMachineName )
  2885. { // Local
  2886. if ( (wcslen( ADS_SMTPDOMAIN_PATH_LOCAL ) + dwSuffixLength) < dwBufferSize )
  2887. wcscpy( psBuffer, ADS_SMTPDOMAIN_PATH_LOCAL );
  2888. else
  2889. hr = E_FAIL;
  2890. }
  2891. else
  2892. { // Remote
  2893. if ( (wcslen( ADS_SMTPDOMAIN_PATH_REMOTE ) + wcslen( m_psMachineName ) + dwSuffixLength) < dwBufferSize )
  2894. swprintf( psBuffer, ADS_SMTPDOMAIN_PATH_REMOTE, m_psMachineName );
  2895. else
  2896. hr = E_FAIL;
  2897. }
  2898. if ( S_OK == hr && NULL != psSuffix )
  2899. {
  2900. wcscat( psBuffer, L"/" );
  2901. wcscat( psBuffer, psSuffix );
  2902. }
  2903. return hr;
  2904. }
  2905. HRESULT CP3AdminWorker::RemoveSMTPDomain( LPWSTR psDomainName )
  2906. {
  2907. HRESULT hr;
  2908. WCHAR sBuffer[POP3_MAX_PATH];
  2909. _bstr_t _bstrClass( L"IIsSmtpDomain" );
  2910. _variant_t _v;
  2911. CComPtr<IADsContainer> spIADsContainer;
  2912. CComPtr<IADs> spIADs;
  2913. _bstr_t _bstrDomain = psDomainName;
  2914. hr = GetSMTPDomainPath( sBuffer, NULL, sizeof( sBuffer )/sizeof( WCHAR ));
  2915. if ( S_OK == hr )
  2916. hr = ADsGetObject( sBuffer, IID_IADsContainer, reinterpret_cast<LPVOID*>( &spIADsContainer ));
  2917. if ( SUCCEEDED( hr ))
  2918. {
  2919. hr = spIADsContainer->Delete( _bstrClass, _bstrDomain );
  2920. if SUCCEEDED( hr )
  2921. { // Commit the change
  2922. hr = spIADsContainer->QueryInterface( IID_IADs, reinterpret_cast<LPVOID*>( &spIADs ));
  2923. if SUCCEEDED( hr )
  2924. hr = spIADs->SetInfo();
  2925. }
  2926. }
  2927. return hr;
  2928. }
  2929. HRESULT CP3AdminWorker::RemoveStoreDomain( LPWSTR psDomainName )
  2930. {
  2931. // psDomainName - checked by ExistsStoreDomain
  2932. HRESULT hr = S_OK;
  2933. WCHAR sBuffer[POP3_MAX_PATH];
  2934. hr = ExistsStoreDomain( psDomainName );
  2935. if SUCCEEDED( hr )
  2936. {
  2937. hr = BuildDomainPath( psDomainName, sBuffer, sizeof( sBuffer )/sizeof(WCHAR));
  2938. if ( S_OK == hr )
  2939. {
  2940. if ( !BDeleteDirTree( sBuffer ))
  2941. {
  2942. hr = HRESULT_FROM_WIN32( GetLastError());
  2943. if SUCCEEDED( hr ) hr = E_FAIL;
  2944. }
  2945. }
  2946. else
  2947. if SUCCEEDED( hr ) hr = E_UNEXPECTED;
  2948. }
  2949. return hr;
  2950. }