Source code of Windows XP (NT5)
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.

1643 lines
50 KiB

  1. #include "stdafx.h"
  2. #include "exchange.hpp"
  3. #include "common.hpp"
  4. #include "err.hpp"
  5. #include "ErrDct.hpp"
  6. #include "UString.hpp"
  7. #include "sidcache.hpp"
  8. #include "sd.hpp"
  9. #include "SecObj.hpp"
  10. #include "MAPIProf.hpp"
  11. #include "exldap.h"
  12. #include "Mcs.h"
  13. extern TErrorDct err;
  14. #define NOT_PT_ERROR(x) ( PROP_TYPE(x.ulPropTag) != PT_ERROR )
  15. #define LDAP_PortNumber_DN_Part L"/cn=Protocols/cn=LDAP"
  16. #define ATT_OBJ_CLASS L"Obj-Class"
  17. #define ATT_DIST_NAME L"Obj-Dist-Name"
  18. #define ATT_LDAP_PORT L"Port-Number"
  19. #define LDAP_USE_SITE_VALUES L"Use-Site-Values"
  20. // Stuff related to dynamic loading of DAPI.DLL
  21. HINSTANCE hDapi = NULL;
  22. LPDAPISTART pDAPIStart = NULL;
  23. LPDAPIEND pDAPIEnd = NULL;
  24. LPDAPIREAD pDAPIRead = NULL;
  25. LPDAPIWRITE pDAPIWrite = NULL;
  26. LPDAPIFREEMEMORY pDAPIFreeMemory = NULL;
  27. LPBATCHEXPORT pBatchExport = NULL;
  28. BOOL LoadDAPI()
  29. {
  30. BOOL success = TRUE;
  31. if ( ! hDapi )
  32. {
  33. success = FALSE;
  34. hDapi = LoadLibrary(_T("DAPI.DLL"));
  35. if ( hDapi )
  36. {
  37. do { // once
  38. pDAPIStart = (LPDAPISTART)GetProcAddress(hDapi,"DAPIStartW@8");
  39. if ( ! pDAPIStart )
  40. {
  41. err.MsgWrite(ErrE,DCT_MSG_DAPI_ENTRY_POINT_NOT_FOUND_S,L"DAPIStart");
  42. break;
  43. }
  44. pDAPIEnd = (LPDAPIEND)GetProcAddress(hDapi,"DAPIEnd@4");
  45. if ( ! pDAPIEnd )
  46. {
  47. err.MsgWrite(ErrE,DCT_MSG_DAPI_ENTRY_POINT_NOT_FOUND_S,L"DAPIEnd");
  48. break;
  49. }
  50. pDAPIRead = (LPDAPIREAD)GetProcAddress(hDapi,"DAPIReadW@24");
  51. if ( ! pDAPIRead )
  52. {
  53. err.MsgWrite(ErrE,DCT_MSG_DAPI_ENTRY_POINT_NOT_FOUND_S,L"DAPIRead");
  54. break;
  55. }
  56. pDAPIWrite = (LPDAPIWRITE)GetProcAddress(hDapi,"DAPIWriteW@28");
  57. if ( ! pDAPIWrite )
  58. {
  59. err.MsgWrite(ErrE,DCT_MSG_DAPI_ENTRY_POINT_NOT_FOUND_S,L"DAPIWrite");
  60. break;
  61. }
  62. pDAPIFreeMemory = (LPDAPIFREEMEMORY)GetProcAddress(hDapi,"DAPIFreeMemory@4");
  63. if ( ! pDAPIFreeMemory )
  64. {
  65. err.MsgWrite(ErrE,DCT_MSG_DAPI_ENTRY_POINT_NOT_FOUND_S,L"DAPIFreeMemory");
  66. break;
  67. }
  68. pBatchExport = (LPBATCHEXPORT)GetProcAddress(hDapi,"BatchExportA@4");
  69. if ( ! pBatchExport )
  70. {
  71. err.MsgWrite(ErrE,DCT_MSG_DAPI_ENTRY_POINT_NOT_FOUND_S,L"BatchExport");
  72. break;
  73. }
  74. success = TRUE;
  75. } while (false);
  76. }
  77. else
  78. {
  79. err.MsgWrite(ErrE,DCT_MSG_DAPI_LOAD_LIBRARY_FAILED);
  80. }
  81. }
  82. if ( ! success )
  83. {
  84. ReleaseDAPI();
  85. }
  86. return success;
  87. }
  88. void ReleaseDAPI()
  89. {
  90. if ( hDapi )
  91. {
  92. FreeLibrary(hDapi);
  93. hDapi = NULL;
  94. pDAPIStart = NULL;
  95. pDAPIEnd = NULL;
  96. pDAPIRead = NULL;
  97. pDAPIWrite = NULL;
  98. pDAPIFreeMemory = NULL;
  99. pBatchExport = NULL;
  100. }
  101. }
  102. TGlobalDirectory::TGlobalDirectory()
  103. {
  104. m_stat = NULL;
  105. m_bUseDefaultMapiProfile = FALSE; // Whether to use MAPI profile listed in Registry.
  106. m_bPromptForMapiProfile = TRUE; // Whether to prompt for MAPI profile.
  107. m_pszMapiProfile = NULL; // MAPI profile to use.
  108. // MAPI
  109. m_bMapiInitialized = FALSE; // TRUE if initialization was successful.
  110. m_pMapiSession = NULL; // MAPI session handle.
  111. m_pAdrBook = NULL; // The master AB.
  112. m_pGlobalList = NULL;
  113. m_pGlobalTable = NULL;
  114. m_pGlobalPropertyTags = NULL;
  115. m_pGlobalRows = NULL;
  116. m_pRootRows = NULL;
  117. m_pContainer = NULL;
  118. m_pContainerTable = NULL;
  119. }
  120. TGlobalDirectory::~TGlobalDirectory()
  121. {
  122. delete [] m_pszMapiProfile;
  123. CloseGlobalList();
  124. EndMapiSession();
  125. }
  126. LPTSTR TGlobalDirectory::GetMapiProfile() const
  127. {
  128. return m_pszMapiProfile;
  129. }
  130. BOOL TGlobalDirectory::DoUseDefaultMapiProfile() const
  131. {
  132. return m_bUseDefaultMapiProfile;
  133. }
  134. BOOL TGlobalDirectory::DoPromptForMapiProfile() const
  135. {
  136. return m_bPromptForMapiProfile;
  137. }
  138. ///////////////////////////////////////////////////////////////////////////////
  139. // Log a MAPI warning or error.
  140. void
  141. TGlobalDirectory::LogMapiError(
  142. int iSeverity, // in - Severity (i.e. ErrW, ErrE, etc)
  143. LPCTSTR pszEntryPoint, // in - API that generated the error
  144. HRESULT hr // in - error code
  145. )
  146. {
  147. if (hr != 0)
  148. err.MsgWrite(iSeverity,DCT_MSG_GENERIC_HRESULT_SD, pszEntryPoint, hr);
  149. else
  150. err.MsgWrite(iSeverity,DCT_MSG_GENERIC_S, pszEntryPoint);
  151. }
  152. void
  153. TGlobalDirectory::LogDapiError(
  154. int iSeverity, // in - severity of error (i.e. ErrW, ErrE, etc.)
  155. LPCTSTR pszUserMessage, // in - message describing the action that failed
  156. DAPI_EVENT * pResult // in - DAPIEvent error structure returned from Exchange
  157. )
  158. {
  159. WCHAR strMsg[1000];
  160. DWORD dimMsg = DIM(strMsg);
  161. DWORD lenMsg;
  162. DAPI_EVENT * pEvt;
  163. WCHAR msg[2000];
  164. if ( !pResult )
  165. return;
  166. safecopy(msg,pszUserMessage);
  167. for ( pEvt = pResult ; pEvt ; pEvt = pEvt->pNextEvent )
  168. {
  169. strMsg[0] = 0;
  170. lenMsg = FormatMessageW(
  171. FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  172. pEvt->hinstDAPI,
  173. pEvt->dwDAPIError,
  174. 0,
  175. strMsg,
  176. dimMsg,
  177. (va_list*)pEvt->rgpszSubst
  178. );
  179. UStrCpy(msg+UStrLen(msg),strMsg,DIM(msg)-UStrLen(msg));
  180. }
  181. err.MsgWrite(iSeverity,DCT_MSG_GENERIC_S,&*msg);
  182. }
  183. ///////////////////////////////////////////////////////////////////////////////
  184. // Start a MAPI session.
  185. // Tries to use the profile specified on the command line.
  186. BOOL TGlobalDirectory::StartMapiSession()
  187. {
  188. //ASSERT(m_bMapiInitialized == FALSE);
  189. MCSASSERT(m_pMapiSession == NULL);
  190. HRESULT hr;
  191. if ( !m_bMapiInitialized )
  192. {
  193. hr = (*pMAPIInitialize)(NULL);
  194. if (FAILED(hr))
  195. {
  196. LogMapiError(ErrE, TEXT("MAPIInitialize"), hr);
  197. return FALSE;
  198. }
  199. m_bMapiInitialized = TRUE;
  200. }
  201. FLAGS fLogonOptions = MAPI_NEW_SESSION | MAPI_NO_MAIL;
  202. LPTSTR pszMapiProfile;
  203. if (DoUseDefaultMapiProfile()) {
  204. fLogonOptions |= MAPI_USE_DEFAULT;
  205. pszMapiProfile = NULL;
  206. }
  207. else if (DoPromptForMapiProfile()) {
  208. fLogonOptions |= MAPI_LOGON_UI | MAPI_EXPLICIT_PROFILE;
  209. pszMapiProfile = NULL;
  210. }
  211. else {
  212. fLogonOptions |= MAPI_EXPLICIT_PROFILE ;
  213. pszMapiProfile = GetMapiProfile();
  214. }
  215. hr = (*pMAPILogonEx)(0, pszMapiProfile, NULL, fLogonOptions | MAPI_UNICODE, &m_pMapiSession);
  216. if (FAILED(hr)) {
  217. switch (hr) {
  218. case MAPI_E_USER_CANCEL:
  219. break;
  220. default:
  221. err.SysMsgWrite(ErrE,hr,DCT_MSG_NO_MAPI_SESSION_D,hr);
  222. break;
  223. }
  224. return FALSE;
  225. }
  226. m_bLoggedFailedClose = FALSE;
  227. return TRUE;
  228. } /* TGlobalDirectory::StartMapiSession() */
  229. ///////////////////////////////////////////////////////////////////////////////
  230. // Terminate a MAPI session.
  231. // No-op if there's not one open.
  232. void TGlobalDirectory::EndMapiSession()
  233. {
  234. if (m_pMapiSession) {
  235. HRESULT hr = m_pMapiSession->Logoff(0, 0, 0);
  236. if (SUCCEEDED(hr))
  237. m_pMapiSession = NULL;
  238. else if (!m_bLoggedFailedClose) {
  239. err.SysMsgWrite(ErrW,hr,DCT_MSG_MAPI_LOGOFF_FAILED_D,hr);
  240. }
  241. // NOTE: If this fails once, it may fail twice.
  242. // The second failure will come on the dtor.
  243. // This is on purpose. It's a retry. But we report it only once.
  244. }
  245. if (m_bMapiInitialized)
  246. {
  247. (*pMAPIUninitialize)();
  248. m_bMapiInitialized = FALSE;
  249. }
  250. } /* TGlobalDirectory::EndMapiSession() */
  251. ///////////////////////////////////////////////////////////////////////////////
  252. // Open the Address Book and get an interface to the Global List.
  253. // The Global List contains the Distribution Lists.
  254. BOOL TGlobalDirectory::OpenGlobalList()
  255. {
  256. // Open the Address Book.
  257. if ( ! m_pMapiSession )
  258. return FALSE;
  259. HRESULT hr = m_pMapiSession->OpenAddressBook(0, NULL, AB_NO_DIALOG , &m_pAdrBook);
  260. if (FAILED(hr))
  261. {
  262. err.SysMsgWrite(ErrE,hr,DCT_MSG_NO_ADDRBOOK_D,hr);
  263. return FALSE;
  264. }
  265. // Get the GAL entry ID.
  266. ULONG cbEntryId;
  267. LPENTRYID pEntryId;
  268. hr = HrFindExchangeGlobalAddressList(m_pAdrBook, &cbEntryId, &pEntryId);
  269. if (FAILED(hr))
  270. {
  271. err.SysMsgWrite(ErrE,hr,DCT_MSG_FAILED_TO_OPEN_GAL_D,hr);
  272. return FALSE;
  273. }
  274. // Load the GAL from the AB.
  275. ULONG ulObjType;
  276. hr = m_pAdrBook->OpenEntry(cbEntryId, pEntryId, NULL, 0, &ulObjType, (LPUNKNOWN*)&m_pGlobalList);
  277. (*pMAPIFreeBuffer)(pEntryId);
  278. if (FAILED(hr))
  279. {
  280. err.SysMsgWrite(ErrE,hr,DCT_MSG_RETRIEVE_GAL_FAILED_D,hr);
  281. return FALSE;
  282. }
  283. // Get a list of the contents of the Global List.
  284. hr = m_pGlobalList->GetContentsTable(0, &m_pGlobalTable);
  285. if (FAILED(hr))
  286. {
  287. err.SysMsgWrite(ErrE,hr,DCT_MSG_RETRIEVE_GAL_FAILED_D,hr);
  288. return FALSE;
  289. }
  290. return TRUE;
  291. } /* TEaSyncCommand::OpenGlobalList() */
  292. ///////////////////////////////////////////////////////////////////////////////
  293. // Release the interfaces to the Global List and the Address Book.
  294. void TGlobalDirectory::CloseGlobalList()
  295. {
  296. if (m_pGlobalTable != NULL)
  297. {
  298. m_pGlobalTable->Release();
  299. m_pGlobalTable = NULL;
  300. }
  301. if (m_pGlobalList != NULL)
  302. {
  303. m_pGlobalList->Release();
  304. m_pGlobalList = NULL;
  305. }
  306. if (m_pAdrBook != NULL)
  307. {
  308. m_pAdrBook->Release();
  309. m_pAdrBook = NULL;
  310. }
  311. } /* TGlobalDirectory::CloseGlobalList() */
  312. BOOL
  313. TGlobalDirectory::UpdateEntry(
  314. LPMAPIPROP pUserEntry, // in - interface to mail recipient object
  315. ULONG ulType, // in - type of object
  316. SecurityTranslatorArgs * args // in - translation settings
  317. )
  318. {
  319. // Prepare to get the columns that interest us.
  320. // For DCT, we probably only care about ASSOC_NT_ACCOUNT, and possibly PR_EMS_AB_NT_SECURITY_DESCRIPTOR
  321. HRESULT hr;
  322. BOOL anychange = FALSE;
  323. BOOL verbose = args->LogVerbose();
  324. MCSASSERT(pUserEntry);
  325. if ( args->Cache()->IsCancelled() )
  326. {
  327. err.MsgWrite(0,DCT_MSG_OPERATION_ABORTED);
  328. return FALSE;
  329. }
  330. SizedSPropTagArray(5, oPropertiesToGet) =
  331. {
  332. 5,
  333. {
  334. PR_DISPLAY_NAME,
  335. PR_EMS_AB_ASSOC_NT_ACCOUNT, // SID
  336. PR_ENTRYID,
  337. PR_EMS_AB_NT_SECURITY_DESCRIPTOR, // SD
  338. PR_DISPLAY_TYPE
  339. }
  340. };
  341. ULONG ulPropsReturned = 0;
  342. LPSPropValue pUserProperties = NULL;
  343. hr = pUserEntry->GetProps((SPropTagArray *)&oPropertiesToGet,
  344. 0, &ulPropsReturned, &pUserProperties);
  345. if (FAILED(hr))
  346. {
  347. err.SysMsgWrite(ErrE,hr,DCT_MSG_GET_SECURITY_FOR_RECIP_FAILED_D,hr);
  348. pUserEntry->Release();
  349. pUserEntry = NULL;
  350. return FALSE;
  351. }
  352. if (ulPropsReturned != oPropertiesToGet.cValues)
  353. {
  354. err.MsgWrite(ErrE,DCT_MSG_GET_SECURITY_FOR_RECIP_FAILED_D,hr);
  355. pUserEntry->Release();
  356. pUserEntry = NULL;
  357. return FALSE;
  358. }
  359. // 1. Translate the PR_EMS_AB_ASSOC_NT_ACCOUNT property
  360. WCHAR name[MAX_PATH];
  361. safecopy(name,pUserProperties[0].Value.lpszW);
  362. if ( m_stat )
  363. {
  364. m_stat->DisplayPath(name);
  365. m_stat->IncrementExamined(mailbox);
  366. }
  367. PISID pSid = (PISID)pUserProperties[1].Value.bin.lpb;
  368. if (pSid != NULL)
  369. {
  370. LPSPropValue pNewPropValues = NULL;
  371. LPSPropProblemArray pProblems = NULL;
  372. // check if the sid is one we need to change
  373. //TRACE (_T("DisplayName = %s "),pUserProperties[0].Value.lpszW);
  374. PSID newSid = 0;
  375. TAcctNode * node;
  376. if ( IsValidSid(pSid) )
  377. {
  378. node = args->Cache()->Lookup(pSid);
  379. if ( m_stat )
  380. {
  381. m_stat->IncrementOwnerExamined();
  382. if ( verbose )
  383. err.MsgWrite(0,DCT_MSG_EXAMINED_S,pUserProperties[0].Value.lpszW);
  384. }
  385. if ( node == (TAcctNode*)-1 && m_stat )
  386. m_stat->IncrementOwnerNoTarget();
  387. if ( node && (node != (TAcctNode *)-1) && node->IsValidOnTgt() )
  388. newSid = args->Cache()->GetTgtSid(node);
  389. else
  390. newSid = NULL;
  391. }
  392. else
  393. {
  394. newSid = NULL;
  395. }
  396. if ( newSid )
  397. {
  398. //TRACE (_T("needs to be translated\n"));
  399. // update the entry, or maybe put it into a list of entries to be updated
  400. // Allocate a buffer to set the property.
  401. MCSASSERT ( IsValidSid(newSid) );
  402. PSID pMapiSid;
  403. DWORD dwSidLength = GetLengthSid(newSid);
  404. hr = ResultFromScode((*pMAPIAllocateBuffer)((sizeof SPropValue) * 1, (void **)&pNewPropValues));
  405. if (FAILED(hr))
  406. {
  407. err.SysMsgWrite(ErrE,hr,DCT_MSG_FAILED_TO_ALLOCATE_BUFFER_D,hr);
  408. goto exit_update_sid;
  409. }
  410. // Allocate a buffer for the SID
  411. hr = ResultFromScode((*pMAPIAllocateBuffer)(dwSidLength, (void **)&pMapiSid));
  412. if (FAILED(hr))
  413. {
  414. err.SysMsgWrite(ErrE,hr,DCT_MSG_FAILED_TO_ALLOCATE_BUFFER_D,hr);
  415. goto exit_update_sid;
  416. }
  417. // Copy the SID.
  418. CopySid(dwSidLength,pMapiSid,newSid);
  419. // Write the SID
  420. pNewPropValues[0].ulPropTag = PR_EMS_AB_ASSOC_NT_ACCOUNT;
  421. pNewPropValues[0].Value.bin.lpb = (UCHAR *)pMapiSid;
  422. pNewPropValues[0].Value.bin.cb = dwSidLength;
  423. MCSASSERT (IsValidSid (pMapiSid) );
  424. if ( m_stat )
  425. {
  426. m_stat->IncrementOwnerChange(node,mailbox,NULL);
  427. }
  428. anychange = TRUE;
  429. if ( ! args->NoChange() )
  430. {
  431. hr = pUserEntry->SetProps(1, pNewPropValues, &pProblems);
  432. if (FAILED(hr))
  433. {
  434. err.SysMsgWrite(ErrE,hr,DCT_MSG_UPDATE_ACCOUNT_FAILED_D, hr);
  435. pProblems = NULL; // Don't try to free this if SetProps fails.
  436. goto exit_update_sid;
  437. }
  438. // Save changes.
  439. hr = pUserEntry->SaveChanges(KEEP_OPEN_READWRITE);
  440. if (FAILED(hr))
  441. {
  442. err.SysMsgWrite(ErrE,hr,DCT_MSG_SAVE_CHANGES_FAILED_D, hr);
  443. goto exit_update_sid;
  444. }
  445. }
  446. exit_update_sid:
  447. if (pMapiSid != NULL)
  448. (*pMAPIFreeBuffer)(pMapiSid);
  449. if (pProblems != NULL)
  450. (*pMAPIFreeBuffer)(pProblems);
  451. if (pNewPropValues != NULL)
  452. (*pMAPIFreeBuffer)(pNewPropValues);
  453. }
  454. }
  455. // 2. Translate the PR_EMS_AB_NT_SECURITY_DESCRIPTOR property
  456. PSECURITY_DESCRIPTOR pSD = (PSECURITY_DESCRIPTOR)pUserProperties[3].Value.bin.lpb;
  457. if ( pSD && PR_EMS_AB_NT_SECURITY_DESCRIPTOR == pUserProperties[3].ulPropTag )
  458. {
  459. TMapiSD tMailbox((SECURITY_DESCRIPTOR *)pSD);
  460. tMailbox.SetName(pUserProperties[0].Value.lpszW);
  461. if ( tMailbox.HasSecurity() )
  462. {
  463. TSD * pSD = tMailbox.GetSecurity();
  464. bool changes = tMailbox.ResolveSDInternal(args->Cache(),m_stat,verbose,args->TranslationMode(),mailbox, FALSE);
  465. if ( changes )
  466. {
  467. anychange = TRUE;
  468. // need to write the changes
  469. LPSPropValue pNewPropValues = NULL;
  470. LPSPropProblemArray pProblems = NULL;
  471. // update the entry
  472. // Allocate a buffer to set the property.
  473. SECURITY_DESCRIPTOR * pMapiSD;
  474. SECURITY_DESCRIPTOR * pRelSD = (SECURITY_DESCRIPTOR *)pSD->MakeRelSD();
  475. DWORD dwSDLength = GetSecurityDescriptorLength(pRelSD);
  476. if ( ! pRelSD )
  477. {
  478. goto exit_update_sd;
  479. }
  480. hr = ResultFromScode((*pMAPIAllocateBuffer)((sizeof SPropValue) * 1, (void **)&pNewPropValues));
  481. if (FAILED(hr))
  482. {
  483. err.SysMsgWrite(ErrE,hr,DCT_MSG_FAILED_TO_ALLOCATE_BUFFER_D,hr);
  484. goto exit_update_sd;
  485. }
  486. // Allocate a buffer for the SD
  487. hr = ResultFromScode((*pMAPIAllocateBuffer)(dwSDLength, (void **)&pMapiSD));
  488. if (FAILED(hr))
  489. {
  490. err.SysMsgWrite(ErrE,hr,DCT_MSG_FAILED_TO_ALLOCATE_BUFFER_D,hr);
  491. goto exit_update_sd;
  492. }
  493. // Copy the SD.
  494. memcpy(pMapiSD,pRelSD,dwSDLength );
  495. // Write the SD
  496. free(pRelSD);
  497. pNewPropValues[0].ulPropTag = PR_EMS_AB_NT_SECURITY_DESCRIPTOR;
  498. pNewPropValues[0].Value.bin.lpb = (UCHAR *)pMapiSD;
  499. pNewPropValues[0].Value.bin.cb = dwSDLength;
  500. if ( ! args->NoChange() )
  501. {
  502. hr = pUserEntry->SetProps(1, pNewPropValues, &pProblems);
  503. if (FAILED(hr))
  504. {
  505. err.SysMsgWrite(ErrE,hr,DCT_MSG_RECIP_SD_WRITE_FAILED_SD,pUserProperties[0].Value.lpszW,hr);
  506. pProblems = NULL; // Don't try to free this if SetProps fails.
  507. goto exit_update_sd;
  508. }
  509. // Save changes.
  510. hr = pUserEntry->SaveChanges(KEEP_OPEN_READONLY);
  511. if (FAILED(hr))
  512. {
  513. err.SysMsgWrite(ErrE,hr,DCT_MSG_RECIP_SD_SAVE_FAILED_SD,pUserProperties[0].Value.lpszW,hr);
  514. goto exit_update_sd;
  515. }
  516. }
  517. exit_update_sd:
  518. if (pMapiSD != NULL)
  519. (*pMAPIFreeBuffer)(pMapiSD);
  520. if (pProblems != NULL)
  521. (*pMAPIFreeBuffer)(pProblems);
  522. if (pNewPropValues != NULL)
  523. (*pMAPIFreeBuffer)(pNewPropValues);
  524. }
  525. }
  526. }
  527. if ( anychange && m_stat )
  528. {
  529. m_stat->IncrementChanged(mailbox);
  530. if ( args->LogFileDetails() )
  531. err.MsgWrite(0,DCT_MSG_CHANGED_S,pUserProperties[0].Value.lpszW);
  532. }
  533. (*pMAPIFreeBuffer)(pUserProperties);
  534. pUserProperties = NULL;
  535. return TRUE;
  536. }
  537. BOOL
  538. TGlobalDirectory::Scan(
  539. SecurityTranslatorArgs * args, // in - translation settings
  540. WCHAR const * container // in - distinguished name or display name of container to process
  541. )
  542. {
  543. LPABCONT pRootEntry = NULL; // root of AB
  544. ULONG ulObjectType = 0;
  545. HRESULT hr;
  546. // TAccountCache * cache = args->Cache();
  547. if ( args->Cache()->IsCancelled() )
  548. {
  549. err.MsgWrite(0,DCT_MSG_OPERATION_ABORTED);
  550. return FALSE;
  551. }
  552. if ( ! m_pAdrBook )
  553. {
  554. OpenGlobalList();
  555. }
  556. if ( ! m_pAdrBook )
  557. {
  558. return FALSE;
  559. }
  560. /* SizedSPropTagArray(3, rgPropTags) =
  561. {
  562. 3,
  563. {
  564. PR_ENTRYID,
  565. PR_DISPLAY_NAME,
  566. PR_DEPTH,
  567. }
  568. };
  569. */
  570. // Open the root entry.
  571. hr = m_pAdrBook->OpenEntry(0, NULL, NULL, 0, &ulObjectType, (LPUNKNOWN*)&pRootEntry);
  572. if (FAILED(hr))
  573. {
  574. err.SysMsgWrite(ErrE,hr,DCT_MSG_GET_AB_ROOT_FAILED_D,hr);
  575. return FALSE;
  576. }
  577. ScanHierarchy(pRootEntry,args,container);
  578. return TRUE;
  579. }
  580. BOOL
  581. TGlobalDirectory::ScanHierarchy(
  582. LPABCONT pContainer, // in - interface pointer to address book
  583. SecurityTranslatorArgs * args, // in - translation settings
  584. WCHAR const * container // in - distinguished name or display name of container
  585. )
  586. {
  587. HRESULT hr;
  588. LPMAPITABLE pContainerTable = NULL;
  589. LPSRowSet pContainerRows = NULL;
  590. LPABCONT pEntry = NULL;
  591. ULONG ulObjectType = 0;
  592. BOOL foundContainer = FALSE;
  593. MCSASSERT(pContainer);
  594. if ( args->Cache()->IsCancelled() )
  595. {
  596. err.MsgWrite(0,DCT_MSG_OPERATION_ABORTED);
  597. return FALSE;
  598. }
  599. // Get its hierarchical table.
  600. SizedSPropTagArray(4, rgPropTags) =
  601. {
  602. 4,
  603. {
  604. PR_ENTRYID,
  605. PR_DISPLAY_NAME_A, // I tried to get the display name in unicode format, but it did not work.
  606. PR_OBJECT_TYPE,
  607. PR_EMS_AB_OBJ_DIST_NAME_A
  608. }
  609. };
  610. hr = pContainer->GetHierarchyTable(CONVENIENT_DEPTH, &pContainerTable);
  611. if (FAILED(hr))
  612. {
  613. err.SysMsgWrite(ErrE,hr,DCT_MSG_GET_HIER_TABLE_FAILED_D,hr);
  614. return FALSE;
  615. }
  616. // Get a list of all rows.
  617. hr = (*pHrQueryAllRows)(pContainerTable, (LPSPropTagArray)&rgPropTags, NULL, NULL, 0, &pContainerRows);
  618. if (FAILED(hr))
  619. {
  620. err.SysMsgWrite(ErrE,hr,DCT_MSG_GET_TABLE_CONTENTS_FAILED_D,hr);
  621. pContainerTable->Release();
  622. return FALSE;
  623. }
  624. for (ULONG ulRow = (ULONG)0; ulRow < pContainerRows->cRows; ++ulRow)
  625. {
  626. if ( args->Cache()->IsCancelled() )
  627. {
  628. err.MsgWrite(0,DCT_MSG_OPERATION_ABORTED);
  629. return FALSE;
  630. }
  631. hr = m_pAdrBook->OpenEntry(pContainerRows->aRow[ulRow].lpProps[0].Value.bin.cb,
  632. (LPENTRYID)pContainerRows->aRow[ulRow].lpProps[0].Value.bin.lpb,
  633. NULL,
  634. MAPI_MODIFY, // or 0 if nochange mode
  635. &ulObjectType,
  636. (LPUNKNOWN *)&pEntry);
  637. if (!SUCCEEDED(hr))
  638. {
  639. err.SysMsgWrite(ErrE,hr,DCT_MSG_OPEN_CONTAINER_FAILED_SD,pContainerRows->aRow[ulRow].lpProps[1].Value.lpszW,hr);
  640. return FALSE;
  641. }
  642. else
  643. {
  644. // LPMAPITABLE pContainerTable = NULL; // container table
  645. UCHAR containerA[LEN_DistName];
  646. safecopy(containerA,container);
  647. // look for the specified container
  648. if ( NOT_PT_ERROR(pContainerRows->aRow[ulRow].lpProps[1] )
  649. && !UStrICmp(containerA,pContainerRows->aRow[ulRow].lpProps[1].Value.lpszA) )
  650. {
  651. foundContainer = TRUE;
  652. break;
  653. }
  654. if ( container && container[0]== '/' )
  655. {
  656. // Check the distinguished name
  657. LPSPropValue props;
  658. ULONG ulCount;
  659. HRESULT hr2;
  660. hr2 = pEntry->GetProps((LPSPropTagArray)&rgPropTags,0,&ulCount,&props);
  661. if ( SUCCEEDED(hr) )
  662. {
  663. if ( ulCount >= 4 && NOT_PT_ERROR(props[3]) )
  664. {
  665. if ( !UStrICmp(props[3].Value.lpszA,containerA) )
  666. {
  667. foundContainer = TRUE;
  668. }
  669. }
  670. (*pMAPIFreeBuffer)(props);
  671. props = NULL;
  672. }
  673. else
  674. {
  675. err.SysMsgWrite(ErrE,hr2,DCT_MSG_GET_CONTAINER_INFO_FAILED_D,hr2);
  676. }
  677. if ( foundContainer )
  678. break;
  679. }
  680. }
  681. }
  682. // if we found the container, process it's contents
  683. if ( foundContainer )
  684. {
  685. if ( args->LogFileDetails() )
  686. err.MsgWrite(0,DCT_MSG_EXAMINING_CONTENTS_S,pContainerRows->aRow[ulRow].lpProps[1].Value.lpszW);
  687. // Get its contents table.
  688. hr = pEntry->GetContentsTable(0, &pContainerTable);
  689. if (FAILED(hr))
  690. {
  691. err.SysMsgWrite(ErrE,hr,DCT_MSG_GET_CONTAINER_INFO_FAILED_D,hr);
  692. pEntry->Release();
  693. pEntry = NULL;
  694. return FALSE;
  695. }
  696. // need to scan contents and hierarchy for this item
  697. m_pContainer = pEntry;
  698. m_name = pContainerRows->aRow[ulRow].lpProps[1].Value.lpszW;
  699. ScanContents(pContainerTable,args);
  700. }
  701. else
  702. {
  703. err.MsgWrite(ErrW,DCT_MSG_CONTAINER_NOT_FOUND_S,container);
  704. }
  705. (*pFreeProws)(pContainerRows);
  706. pContainerRows = NULL;
  707. pContainerTable->Release();
  708. return TRUE;
  709. }
  710. ///////////////////////////////////////////////////////////////////////////////
  711. // Scan the contents of the Container for sids that need to be converted.
  712. BOOL
  713. TGlobalDirectory::ScanContents(
  714. LPMAPITABLE pContainerTable, // in - contents table for container
  715. SecurityTranslatorArgs * args // in - translation settings
  716. )
  717. {
  718. ULONG ulDLEntries;
  719. // WCHAR em[500] = L"";
  720. MCSASSERT (pContainerTable);
  721. if ( args->Cache()->IsCancelled() )
  722. {
  723. err.MsgWrite(0,DCT_MSG_OPERATION_ABORTED);
  724. return FALSE;
  725. }
  726. HRESULT hr = pContainerTable->GetRowCount(0, &ulDLEntries);
  727. if (FAILED(hr))
  728. {
  729. err.SysMsgWrite(ErrE,hr,DCT_MSG_COUNT_CONTAINER_FAILED_SD,m_name,hr);
  730. return FALSE;
  731. }
  732. // Determine which column of the table has the Entry ID.
  733. LPSPropTagArray pDLPropTags = NULL;
  734. hr = pContainerTable->QueryColumns(0, &pDLPropTags);
  735. if (FAILED(hr))
  736. {
  737. err.SysMsgWrite(ErrE,hr,DCT_MSG_CONTAINER_CORRUPTED_SD,m_name,hr);
  738. return FALSE;
  739. }
  740. ULONG ulEntryIdColumn;
  741. BOOL bFoundEntryId = FALSE;
  742. for (UINT ulCol = 0; ulCol < pDLPropTags->cValues; ++ulCol)
  743. {
  744. if (pDLPropTags->aulPropTag[ulCol] == PR_ENTRYID)
  745. {
  746. ulEntryIdColumn = ulCol;
  747. bFoundEntryId = TRUE;
  748. break;
  749. }
  750. }
  751. (*pMAPIFreeBuffer)(pDLPropTags);
  752. pDLPropTags = NULL;
  753. if (!bFoundEntryId)
  754. {
  755. err.SysMsgWrite(ErrE,hr,DCT_MSG_CONTAINER_CORRUPTED_SD,m_name,hr);
  756. return FALSE;
  757. }
  758. // Peruse the rows for the SIDs and names.
  759. LPSRowSet pDLRows = NULL;
  760. LPMAPIPROP pUserEntry = NULL;
  761. for (ULONG ulRow = 0; ulRow < ulDLEntries; ++ulRow)
  762. {
  763. if ( args->Cache()->IsCancelled() )
  764. {
  765. break;
  766. }
  767. hr = pContainerTable->SeekRow(BOOKMARK_BEGINNING, ulRow, NULL);
  768. if (FAILED(hr))
  769. {
  770. err.SysMsgWrite(ErrE,hr,DCT_MSG_CANT_FIND_ENTRY_SD,m_name,hr);
  771. return FALSE;
  772. }
  773. hr = pContainerTable->QueryRows(1, TBL_NOADVANCE, &pDLRows);
  774. if (FAILED(hr))
  775. {
  776. err.SysMsgWrite(ErrE,hr,DCT_MSG_CANT_LOAD_ENTRY_SD,m_name,hr);
  777. return FALSE;
  778. }
  779. // Get the current entry.
  780. ULONG ulEntryType = 0;
  781. if ( pDLRows && pDLRows->cRows )
  782. {
  783. hr = m_pContainer->OpenEntry(pDLRows->aRow[0].lpProps[ulEntryIdColumn].Value.bin.cb,
  784. (ENTRYID *)pDLRows->aRow[0].lpProps[ulEntryIdColumn].Value.bin.lpb,
  785. NULL,
  786. MAPI_MODIFY,
  787. &ulEntryType,
  788. (LPUNKNOWN*)&pUserEntry);
  789. }
  790. (*pFreeProws)(pDLRows);
  791. pDLRows = NULL;
  792. if (FAILED(hr))
  793. {
  794. err.SysMsgWrite(ErrE,hr,DCT_MSG_RECIP_LOAD_FAILED_SD,m_name,hr);
  795. return FALSE;
  796. }
  797. if ( pUserEntry )
  798. {
  799. UpdateEntry(pUserEntry,ulEntryType, args);
  800. pUserEntry->Release();
  801. pUserEntry = NULL;
  802. }
  803. }
  804. if ( args->Cache()->IsCancelled() )
  805. {
  806. err.MsgWrite(0,DCT_MSG_OPERATION_ABORTED);
  807. return FALSE;
  808. }
  809. return TRUE;
  810. }
  811. BOOL TGlobalDirectory::OpenContainerByRow(long row)
  812. {
  813. HRESULT hr;
  814. ULONG ulObjectType = 0;
  815. MCSASSERT( m_pRootRows );
  816. // TODO: check that row is in valid range.
  817. // Load the container that should contain the DL.
  818. hr = m_pAdrBook->OpenEntry( m_pRootRows->aRow[row].lpProps[0].Value.bin.cb,
  819. (LPENTRYID)m_pRootRows->aRow[row].lpProps[0].Value.bin.lpb,
  820. NULL,
  821. MAPI_MODIFY, // or 0 if nochange mode
  822. &ulObjectType,
  823. (LPUNKNOWN *)&m_pContainer);
  824. (*pFreeProws)(m_pRootRows);
  825. m_pRootRows = NULL;
  826. if (FAILED(hr)) {
  827. err.SysMsgWrite(ErrE,hr,DCT_MSG_OPEN_CONTAINER_FAILED_SD,L"",hr);
  828. return FALSE;
  829. }
  830. // Look for the DL in its container.
  831. // LPMAPITABLE pContainerTable = NULL; // container table
  832. // Get its contents table.
  833. hr = m_pContainer->GetContentsTable(0, &m_pContainerTable);
  834. if (FAILED(hr)) {
  835. err.SysMsgWrite(ErrE,hr,DCT_MSG_GET_TABLE_CONTENTS_FAILED_D,hr);
  836. m_pContainer->Release();
  837. m_pContainer = NULL;
  838. return FALSE;
  839. }
  840. return TRUE;
  841. }
  842. #define NDX_SID 3
  843. #define NDX_SD 4
  844. DWORD
  845. TGlobalDirectory::GetLDAPPort(
  846. WCHAR * server
  847. )
  848. {
  849. DWORD port = LDAP_PORT;
  850. // DWORD rc = 0;
  851. DAPI_ENTRY attList;
  852. DAPI_ENTRY * pValues;
  853. ATT_VALUE atts[3];
  854. WCHAR distName[300];
  855. PDAPI_EVENT result = NULL;
  856. DAPI_ENTRY * pAttributes = NULL;
  857. if ( ! LoadDAPI() )
  858. {
  859. err.MsgWrite(ErrW,DCT_MSG_LDAP_PORT_DETECT_FAILED_S,server);
  860. return port;
  861. }
  862. if ( DAPIOpen(server) )
  863. {
  864. // set up the attribute list
  865. attList.unAttributes = 3;
  866. attList.ulEvalTag = VALUE_ARRAY;
  867. attList.rgEntryValues = atts;
  868. atts[0].DapiType = DAPI_UNICODE;
  869. atts[0].Value.pszW = ATT_OBJ_CLASS;
  870. atts[0].size = UStrLen(atts[0].Value.pszW);
  871. atts[0].pNextValue = NULL;
  872. atts[1].DapiType = DAPI_UNICODE;
  873. atts[1].Value.pszW = ATT_LDAP_PORT;
  874. atts[1].size = UStrLen(atts[1].Value.pszW);
  875. atts[1].pNextValue = NULL;
  876. atts[2].DapiType = DAPI_UNICODE;
  877. atts[2].Value.pszW = LDAP_USE_SITE_VALUES;
  878. atts[2].size = UStrLen(atts[2].Value.pszW);
  879. atts[2].pNextValue = NULL;
  880. // construct the DN for the attribute
  881. swprintf(distName,L"/cn=Configuration/cn=Servers/cn=%s%s",server,LDAP_PortNumber_DN_Part);
  882. result = (*pDAPIRead)(m_dSession,DAPI_RAW_MODE,distName,&attList,
  883. &pValues, &pAttributes);
  884. if ( ! result )
  885. {
  886. if ( pValues && pValues->rgEntryValues[2].Value.iValue == 0 )
  887. {
  888. // not using site defaults - rgEntryValues[1] contains the correct value for this server
  889. if ( pValues && pValues->rgEntryValues[1].DapiType == DAPI_INT )
  890. {
  891. port = pValues->rgEntryValues[1].Value.iValue;
  892. }
  893. }
  894. else
  895. {
  896. // This server is using the default values for the site - need to look at the site level to find the correct value
  897. (*pDAPIFreeMemory)(pValues);
  898. swprintf(distName,L"/cn=Configuration%s",LDAP_PortNumber_DN_Part);
  899. attList.unAttributes = 2; // don't want to get 'Use-Site-Defaults' this time (we're looking at the Site)
  900. result = (*pDAPIRead)(m_dSession,DAPI_RAW_MODE,distName,&attList,
  901. &pValues, &pAttributes);
  902. if ( ! result )
  903. {
  904. if ( pValues && pValues->rgEntryValues[1].DapiType == DAPI_INT )
  905. {
  906. // Here's the default value for the site
  907. port = pValues->rgEntryValues[1].Value.iValue;
  908. }
  909. }
  910. else
  911. {
  912. (*pDAPIFreeMemory)(result);
  913. }
  914. }
  915. (*pDAPIFreeMemory)(pValues);
  916. }
  917. else
  918. {
  919. (*pDAPIFreeMemory)(result);
  920. }
  921. }
  922. else
  923. {
  924. err.MsgWrite(ErrW,DCT_MSG_LDAP_PORT_DETECT_FAILED_S,server);
  925. }
  926. DAPIClose();
  927. ReleaseDAPI();
  928. return port;
  929. }
  930. void
  931. TGlobalDirectory::GetSiteNameForServer(
  932. WCHAR const * server, // in - name of exchange server to use
  933. CLdapEnum * e, // in - LDAP connection to use for query
  934. WCHAR * siteName // out- distinguished name of exchange site for server
  935. )
  936. {
  937. WCHAR * atts[6] = { L"distinguishedName", L"rdn",NULL };
  938. WCHAR query[200];
  939. DWORD rc;
  940. WCHAR ** values = NULL;
  941. siteName[0] = 0;
  942. swprintf(query,L"(&(objectClass=computer)(rdn=%ls))",server);
  943. rc = e->Open(query,L"",2,100,3,atts);
  944. // there should be only one server with this name
  945. if (! rc )
  946. rc = e->Next(&values);
  947. if (! rc )
  948. {
  949. if ( !UStrICmp(values[1],server) )
  950. {
  951. WCHAR serverPrefix[LEN_Path];
  952. swprintf(serverPrefix,L"cn=%ls,cn=Servers,cn=Configuration,",values[1]);
  953. if ( ! UStrICmp(values[0],serverPrefix,UStrLen(serverPrefix)) )
  954. {
  955. UStrCpy(siteName,values[0] + UStrLen(serverPrefix));
  956. }
  957. else
  958. {
  959. err.MsgWrite(ErrE,DCT_MSG_GENERIC_S,values[0]);
  960. }
  961. }
  962. else
  963. {
  964. err.MsgWrite(ErrE,DCT_MSG_LDAP_CALL_FAILED_SD,server,ERROR_NOT_FOUND);
  965. }
  966. e->FreeData(values);
  967. }
  968. else
  969. {
  970. err.SysMsgWrite(ErrE,e->m_connection.LdapMapErrorToWin32(rc),DCT_MSG_LDAP_CALL_FAILED_SD,server,rc);
  971. }
  972. }
  973. BOOL
  974. TGlobalDirectory::DoLdapTranslation(
  975. WCHAR * server,
  976. WCHAR * creds,
  977. WCHAR * password,
  978. SecurityTranslatorArgs * args,
  979. WCHAR * basept,
  980. WCHAR * query
  981. )
  982. {
  983. CLdapEnum e;
  984. WCHAR * atts[6] = { L"distinguishedName", L"rdn", L"cn", L"Assoc-NT-Account",L"NT-Security-Descriptor",NULL };
  985. WCHAR ** values = NULL;
  986. ULONG port = GetLDAPPort(server);
  987. ULONG pageSize = 100;
  988. WCHAR basepoint[LEN_Path] = L"";
  989. e.m_connection.SetCredentials(creds,password);
  990. DWORD rc = e.InitConnection(server,port);
  991. BOOL anychange = FALSE;
  992. BOOL verbose = args->LogVerbose();
  993. BOOL bUseMapFile = args->UsingMapFile();
  994. if (! rc )
  995. {
  996. if ( ! basept )
  997. {
  998. GetSiteNameForServer(server,&e,basepoint);
  999. }
  1000. else
  1001. {
  1002. // use the user-specified basepoint
  1003. safecopy(basepoint,basept);
  1004. }
  1005. if ( query )
  1006. {
  1007. rc = e.Open(query,basepoint,2,pageSize,5,atts);
  1008. }
  1009. else
  1010. {
  1011. rc = e.Open(L"(objectClass=*)",basepoint,2,pageSize,5,atts);
  1012. }
  1013. if ( ! rc )
  1014. {
  1015. do
  1016. {
  1017. rc = e.Next(&values);
  1018. anychange = FALSE;
  1019. if (! rc )
  1020. {
  1021. if ( args->Cache()->IsCancelled() )
  1022. {
  1023. err.MsgWrite(0,DCT_MSG_OPERATION_ABORTED);
  1024. return FALSE;
  1025. }
  1026. if ( m_stat )
  1027. {
  1028. m_stat->DisplayPath(values[0]);
  1029. m_stat->IncrementExamined(mailbox);
  1030. }
  1031. // update the Assoc-NT-Account, if any
  1032. if ( values[NDX_SID] && *values[NDX_SID] )
  1033. {
  1034. // convert the SID to a binary value and look it up in the cache
  1035. BYTE pSid[500];
  1036. if ( e.m_connection.StringToBytes(values[NDX_SID],pSid) )
  1037. {
  1038. // check if the sid is one we need to change
  1039. //TRACE (_T("DisplayName = %s "),pUserProperties[0].Value.lpszW);
  1040. PSID newSid = 0;
  1041. TAcctNode * node;
  1042. if ( IsValidSid(pSid) )
  1043. {
  1044. if (!bUseMapFile)
  1045. node = args->Cache()->Lookup(pSid);
  1046. else
  1047. node = args->Cache()->LookupWODomain(pSid);
  1048. if ( m_stat )
  1049. {
  1050. m_stat->IncrementOwnerExamined();
  1051. if ( verbose )
  1052. err.MsgWrite(0,DCT_MSG_EXAMINED_S,values[0]);
  1053. }
  1054. if ( node == (TAcctNode*)-1 && m_stat )
  1055. m_stat->IncrementOwnerNoTarget();
  1056. if ( node && (node != (TAcctNode *)-1) && node->IsValidOnTgt() )
  1057. {
  1058. if (!bUseMapFile)
  1059. newSid = args->Cache()->GetTgtSid(node);
  1060. else
  1061. newSid = args->Cache()->GetTgtSidWODomain(node);
  1062. }
  1063. else
  1064. newSid = NULL;
  1065. }
  1066. else
  1067. {
  1068. newSid = NULL;
  1069. }
  1070. if ( newSid )
  1071. {
  1072. //TRACE (_T("needs to be translated\n"));
  1073. MCSASSERT ( IsValidSid(newSid) );
  1074. WCHAR newSidStr[1000];
  1075. if ( e.m_connection.BytesToString((BYTE*)newSid,newSidStr,GetLengthSid(newSid)) )
  1076. {
  1077. if ( m_stat )
  1078. {
  1079. m_stat->IncrementOwnerChange(node,mailbox,NULL);
  1080. }
  1081. anychange = TRUE;
  1082. if ( ! args->NoChange() )
  1083. {
  1084. rc = e.m_connection.UpdateSimpleStringValue(values[0],atts[NDX_SID],newSidStr);
  1085. if ( rc )
  1086. {
  1087. err.SysMsgWrite(ErrE,rc,DCT_MSG_UPDATE_ACCOUNT_FAILED_D, rc);
  1088. }
  1089. }
  1090. }
  1091. }
  1092. }
  1093. }
  1094. // Update the NT-Security-Descriptor, if any
  1095. if ( values[NDX_SD] && *values[NDX_SD] )
  1096. {
  1097. // convert the SID to a binary value and look it up in the cache
  1098. BYTE * pSD = new BYTE[UStrLen(values[NDX_SD])];
  1099. if (!pSD)
  1100. return FALSE;
  1101. if ( e.m_connection.StringToBytes(values[NDX_SD],pSD) )
  1102. {
  1103. TMapiSD tMailbox((SECURITY_DESCRIPTOR *)pSD);
  1104. if ( tMailbox.HasSecurity() )
  1105. {
  1106. TSD * pSD2 = tMailbox.GetSecurity();
  1107. bool changes = tMailbox.ResolveSDInternal(args->Cache(),m_stat,verbose,args->TranslationMode(),mailbox, bUseMapFile);
  1108. if ( changes )
  1109. {
  1110. anychange = TRUE;
  1111. SECURITY_DESCRIPTOR * pRelSD = (SECURITY_DESCRIPTOR *)pSD2->MakeRelSD();
  1112. DWORD dwSDLength = GetSecurityDescriptorLength(pRelSD);
  1113. if ( ! args->NoChange() )
  1114. {
  1115. WCHAR * pSDString = new WCHAR[1 + dwSDLength * 2];
  1116. if (!pSDString)
  1117. {
  1118. delete [] pSD;
  1119. return FALSE;
  1120. }
  1121. if ( e.m_connection.BytesToString((BYTE*)pRelSD,pSDString,dwSDLength) )
  1122. {
  1123. rc = e.m_connection.UpdateSimpleStringValue(values[0],atts[NDX_SD],pSDString);
  1124. if ( rc )
  1125. {
  1126. err.SysMsgWrite(ErrE,rc,DCT_MSG_RECIP_SD_WRITE_FAILED_SD,values[0],rc);
  1127. if ( rc == ERROR_INVALID_PARAMETER )
  1128. {
  1129. // this error occurs when the security descriptor is too large
  1130. // don't abort in this case
  1131. rc = 0;
  1132. }
  1133. }
  1134. }
  1135. delete [] pSDString;
  1136. }
  1137. }
  1138. }
  1139. }
  1140. delete [] pSD;
  1141. }
  1142. if ( anychange && m_stat )
  1143. {
  1144. m_stat->IncrementChanged(mailbox);
  1145. if ( args->LogFileDetails() )
  1146. err.MsgWrite(0,DCT_MSG_CHANGED_S,values[0]);
  1147. }
  1148. e.FreeData(values);
  1149. }
  1150. } while ( ! rc );
  1151. }
  1152. if ( rc && (rc != LDAP_COMPARE_FALSE) && (rc != ERROR_NOT_FOUND) )
  1153. {
  1154. err.SysMsgWrite(ErrE,e.m_connection.LdapMapErrorToWin32(rc),DCT_MSG_LDAP_CALL_FAILED_SD,server,rc);
  1155. }
  1156. }
  1157. else
  1158. {
  1159. err.SysMsgWrite(ErrE,rc,DCT_MSG_CANNOT_CONNECT_TO_EXCHANGE_SERVER_SSD,server,creds,rc);
  1160. }
  1161. return rc;
  1162. }
  1163. BOOL
  1164. TGlobalDirectory::DoDAPITranslation(
  1165. WCHAR * serv, // in - Exchange server
  1166. SecurityTranslatorArgs * args // in - translation options
  1167. )
  1168. {
  1169. // enumerate organizations, sites, and containers
  1170. if ( DAPIOpen( serv ) )
  1171. {
  1172. HRESULT hr;
  1173. LPWSTR pOrganizations = NULL;
  1174. LPWSTR pSites = NULL;
  1175. LPWSTR pContainers = NULL;
  1176. WCHAR * server;
  1177. WCHAR container[1];
  1178. if ( args->Cache()->IsCancelled() )
  1179. {
  1180. err.MsgWrite(0,DCT_MSG_OPERATION_ABORTED);
  1181. return FALSE;
  1182. }
  1183. server = new WCHAR[wcslen(serv) + 1];
  1184. if (!server)
  1185. return FALSE;
  1186. UStrCpy(server,serv);
  1187. container[0] = 0;
  1188. // enumerate organizations
  1189. m_stat->DisplayPath(GET_STRING(IDS_ScanningExchangeDirectory));
  1190. hr = HrEnumOrganizations(container,server,&pOrganizations);
  1191. if ( SUCCEEDED(hr) )
  1192. {
  1193. for ( ; pOrganizations && *pOrganizations ; pOrganizations+=UStrLen(pOrganizations) + 1 )
  1194. {
  1195. if ( args->Cache()->IsCancelled() )
  1196. {
  1197. err.MsgWrite(0,DCT_MSG_OPERATION_ABORTED);
  1198. break;
  1199. }
  1200. WCHAR wOrganizations[300];
  1201. safecopy(wOrganizations,pOrganizations);
  1202. DAPITranslate(wOrganizations,args);
  1203. //enumerate sites
  1204. hr = HrEnumSites(server,pOrganizations,&pSites);
  1205. if ( SUCCEEDED(hr) )
  1206. {
  1207. for ( ; pSites && *pSites ; pSites+=UStrLen(pSites) + 1 )
  1208. {
  1209. if ( args->Cache()->IsCancelled() )
  1210. {
  1211. err.MsgWrite(0,DCT_MSG_OPERATION_ABORTED);
  1212. break;
  1213. }
  1214. WCHAR wSites[300];
  1215. safecopy(wSites,pSites);
  1216. DAPITranslate(wSites,args);
  1217. //enumerate containers
  1218. hr = HrEnumContainers(server,pSites,TRUE,&pContainers);
  1219. if ( SUCCEEDED(hr) )
  1220. {
  1221. for ( ; pContainers && *pContainers ; pContainers+=UStrLen(pContainers) + 1 )
  1222. {
  1223. if (args->Cache()->IsCancelled() )
  1224. {
  1225. err.MsgWrite(0,DCT_MSG_OPERATION_ABORTED);
  1226. break;
  1227. }
  1228. WCHAR wContainers[300];
  1229. safecopy(wContainers,pContainers);
  1230. DAPITranslate(wContainers,args);
  1231. }
  1232. }
  1233. else
  1234. {
  1235. err.SysMsgWrite(ErrE,hr,DCT_MSG_ENUM_CONTAINERS_FAILED_SD,hr);
  1236. }
  1237. }
  1238. }
  1239. else
  1240. {
  1241. err.SysMsgWrite(ErrE,hr,DCT_MSG_ENUM_SITES_FAILED_SD,hr);
  1242. }
  1243. }
  1244. }
  1245. else
  1246. {
  1247. err.SysMsgWrite(ErrE,hr,DCT_MSG_ENUM_ORGS_FAILED_SD,hr);
  1248. }
  1249. DAPIClose();
  1250. }
  1251. m_stat->DisplayPath(L"");
  1252. return TRUE;
  1253. }
  1254. BOOL
  1255. TGlobalDirectory::DAPIOpen(
  1256. WCHAR * server // in - name of exchange server
  1257. )
  1258. {
  1259. PDAPI_EVENT result;
  1260. BOOL bRc;
  1261. WCHAR * serv;
  1262. if ( ! LoadDAPI() )
  1263. {
  1264. return FALSE;
  1265. }
  1266. serv = new WCHAR [wcslen(server) + 1];
  1267. if (!serv)
  1268. return FALSE;
  1269. UStrCpy(serv,&*server);
  1270. // initialize parms
  1271. m_dParms.dwDAPISignature = DAPI_SIGNATURE;
  1272. m_dParms.dwFlags = DAPI_RAW_MODE | DAPI_EVENT_SOME;
  1273. m_dParms.pszDSAName = serv; // computer name of directory service agent
  1274. m_dParms.pszBasePoint = NULL;
  1275. m_dParms.pszContainer = NULL;
  1276. m_dParms.pszNTDomain = NULL;
  1277. m_dParms.pszCreateTemplate = NULL;
  1278. m_dParms.pAttributes = NULL;
  1279. result = (*pDAPIStart)(&m_dSession,&m_dParms);
  1280. if ( result )
  1281. {
  1282. // this is an error - need to show a message or something
  1283. LogDapiError(ErrE,L"DAPIStart: ",result);
  1284. (*pDAPIFreeMemory)(result);
  1285. bRc = FALSE;
  1286. }
  1287. else
  1288. bRc = TRUE;
  1289. return bRc;
  1290. }
  1291. BOOL TGlobalDirectory::DAPIClose()
  1292. {
  1293. (*pDAPIEnd)(&m_dSession);
  1294. return TRUE;
  1295. }
  1296. void StripQuotes(TCHAR * distName)
  1297. {
  1298. int nChars = UStrLen(distName);
  1299. int i, // input index
  1300. o; // output index
  1301. BOOL prevQuote = FALSE;
  1302. for ( i = 0,o = 0 ; i < nChars ; i++ )
  1303. {
  1304. if ( distName[i] != _T('"') || prevQuote )
  1305. {
  1306. prevQuote = FALSE;
  1307. distName[o] = distName[i];
  1308. o++;
  1309. }
  1310. else
  1311. {
  1312. // leave the output pointer where it is, so the character will be overwritten
  1313. prevQuote = TRUE;
  1314. }
  1315. }
  1316. distName[o] = 0;
  1317. }
  1318. BOOL TGlobalDirectory::DAPITranslate(WCHAR * dn, SecurityTranslatorArgs * args)
  1319. {
  1320. PDAPI_EVENT result;
  1321. TCHAR * distName; // distinguished name of object to read.
  1322. DAPI_ENTRY * pValues = NULL;
  1323. DAPI_ENTRY * pAttributes = NULL;
  1324. ATT_VALUE attributes[8]; // DapiType, Value, size, pNextValue
  1325. WCHAR * att_names[8];
  1326. bool verbose = false;
  1327. if ( args->Cache()->IsCancelled() )
  1328. {
  1329. err.MsgWrite(0,DCT_MSG_OPERATION_ABORTED);
  1330. return FALSE;
  1331. }
  1332. att_names[0] = L"Obj-Class";
  1333. att_names[1] = L"DSA-Signature";
  1334. att_names[2] = L"Directory Name";
  1335. att_names[3] = L"Obj-View-Containers";
  1336. att_names[4] = L"Obj-Dist-Name";
  1337. int sdIndex = 5;
  1338. att_names[sdIndex] = L"NT-Security-Descriptor";
  1339. att_names[6] = L"Organizational-Unit-Name";
  1340. att_names[7] = L"Organization-Name";
  1341. DAPI_ENTRY attr;
  1342. attr.unAttributes = 8;
  1343. attr.ulEvalTag = VALUE_ARRAY;
  1344. attr.rgEntryValues = attributes;
  1345. for ( int i = 0 ; i < 8 ; i++ )
  1346. {
  1347. attributes[i].DapiType = DAPI_UNICODE;
  1348. attributes[i].Value.pszW = att_names[i];
  1349. attributes[i].size = UStrLen(att_names[i]);
  1350. attributes[i].pNextValue = NULL;
  1351. }
  1352. // we may need DAPI_RESTRICT_ACCESS and/or DAPI_MODIFY_REPLACE_PROPERTIES
  1353. distName = new TCHAR[wcslen(dn) + 1];
  1354. if (!distName)
  1355. return FALSE;
  1356. UStrCpy(distName,(LPCTSTR)dn);
  1357. StripQuotes(distName);
  1358. result = (*pDAPIRead)(m_dSession,DAPI_RAW_MODE,distName,&attr,
  1359. &pValues, &pAttributes);
  1360. if ( m_stat )
  1361. {
  1362. WCHAR wpath[MAX_PATH+1];
  1363. safecopy(wpath,&*distName);
  1364. m_stat->DisplayPath(wpath);
  1365. m_stat->IncrementExamined(container);
  1366. if ( verbose )
  1367. err.MsgWrite(0,DCT_MSG_EXAMINED_S,&*dn);
  1368. }
  1369. if ( result )
  1370. {
  1371. // this is an error - need to show a message or something
  1372. LogDapiError(ErrE,L"DAPIRead: ",result);
  1373. (*pDAPIFreeMemory)(result);
  1374. }
  1375. if ( pValues && pValues->rgEntryValues[sdIndex].DapiType == DAPI_BINARY )
  1376. {
  1377. SECURITY_DESCRIPTOR * pSD = (SECURITY_DESCRIPTOR *)pValues->rgEntryValues[sdIndex].Value.lpBinary;
  1378. TMapiSD exContainer(pSD);
  1379. if ( exContainer.HasSecurity() )
  1380. {
  1381. exContainer.SetName(distName);
  1382. bool changes = exContainer.ResolveSDInternal(args->Cache(),m_stat,false,args->TranslationMode(),container, FALSE);
  1383. // ULONG usn = 0;
  1384. if ( changes )
  1385. {
  1386. if (m_stat)
  1387. {
  1388. m_stat->IncrementChanged(container);
  1389. if ( args->LogFileDetails() )
  1390. err.MsgWrite(0,DCT_MSG_CHANGED_S,&*dn);
  1391. }
  1392. // record the changes
  1393. if ( ! args->NoChange() )
  1394. {
  1395. TSD * tSD = exContainer.GetSecurity();
  1396. pSD = (SECURITY_DESCRIPTOR *)tSD->MakeRelSD();
  1397. pValues->rgEntryValues[sdIndex].Value.lpBinary = (UCHAR *)pSD;
  1398. // make sure the size is still correct. For NT 3.51 and 4 it
  1399. // should always be, since all the SIDs are the same length, but
  1400. // we don't want this to break if it gets a different-length SID
  1401. pValues->rgEntryValues[sdIndex].size = GetSecurityDescriptorLength(pSD);
  1402. // Change the directory name to match the distinguished name, otherwise you get
  1403. // object not found error.
  1404. pValues->rgEntryValues[2].Value.pszW = pValues->rgEntryValues[4].Value.pszW;
  1405. // Same problem for the OU-Name for Sites
  1406. if ( pValues->rgEntryValues[6].DapiType != DAPI_NO_VALUE )
  1407. {
  1408. pValues->rgEntryValues[6].Value.pszW = pValues->rgEntryValues[4].Value.pszW;
  1409. }
  1410. // Same problem for the O-name for organizations
  1411. if ( pValues->rgEntryValues[7].DapiType != DAPI_NO_VALUE )
  1412. {
  1413. pValues->rgEntryValues[7].Value.pszW = pValues->rgEntryValues[4].Value.pszW;
  1414. }
  1415. result = (*pDAPIWrite)(m_dSession,DAPI_WRITE_MODIFY,&attr,pValues,NULL,NULL,NULL);
  1416. if ( result )
  1417. {
  1418. LogDapiError(ErrE,L"DAPIWrite: ",result);
  1419. (*pDAPIFreeMemory)(result);
  1420. }
  1421. free(pSD);
  1422. }
  1423. }
  1424. }
  1425. }
  1426. // cleanup
  1427. if ( pValues )
  1428. (*pDAPIFreeMemory)(pValues);
  1429. if ( pAttributes )
  1430. (*pDAPIFreeMemory)(pAttributes);
  1431. delete [] distName;
  1432. return TRUE;
  1433. }