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.

1271 lines
39 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997 - 1999
  6. //
  7. // File: newobjcr.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. /////////////////////////////////////////////////////////////////////
  11. // newobjcr.cpp
  12. //
  13. // This file contains implementation of functions to create
  14. // new ADs objects.
  15. //
  16. // HISTORY
  17. // 19-Aug-97 Dan Morin Creation.
  18. //
  19. /////////////////////////////////////////////////////////////////////
  20. #include "stdafx.h"
  21. #include "newobj.h"
  22. #include "dlgcreat.h"
  23. #include "dscmn.h" // CrackName()
  24. #include "gencreat.h"
  25. #include "querysup.h" // CDSSearch
  26. extern "C"
  27. {
  28. #ifdef FRS_CREATE
  29. #include "dsquery.h" // CLSID_DsFindFrsMembers
  30. #endif // FRS_CREATE
  31. #include <schedule.h>
  32. }
  33. #define BREAK_ON_TRUE(b) if (b) { ASSERT(FALSE); break; }
  34. #define BREAK_ON_FAIL BREAK_ON_TRUE(FAILED(hr))
  35. #define RETURN_IF_FAIL if (FAILED(hr)) { ASSERT(FALSE); return hr; }
  36. //
  37. // The schedule block has been redefined to have 1 byte for every hour.
  38. // CODEWORK These should be defined in SCHEDULE.H. JonN 2/9/98
  39. //
  40. #define INTERVAL_MASK 0x0F
  41. #define RESERVED 0xF0
  42. #define FIRST_15_MINUTES 0x01
  43. #define SECOND_15_MINUTES 0x02
  44. #define THIRD_15_MINUTES 0x04
  45. #define FORTH_15_MINUTES 0x08
  46. // The dialog has one bit per hour, the DS schedule has one byte per hour
  47. #define cbDSScheduleArrayLength (24*7)
  48. #define HeadersSizeNum(NumberOfSchedules) \
  49. (sizeof(SCHEDULE) + ((NumberOfSchedules)-1)*sizeof(SCHEDULE_HEADER))
  50. inline ULONG HeadersSize(SCHEDULE* psched)
  51. {
  52. return HeadersSizeNum(psched->NumberOfSchedules);
  53. }
  54. /////////////////////////////////////////////////////////////////////
  55. // HrCreateADsUser()
  56. //
  57. // Create a new user.
  58. //
  59. HRESULT HrCreateADsUser(INOUT CNewADsObjectCreateInfo * pNewADsObjectCreateInfo)
  60. {
  61. ASSERT(pNewADsObjectCreateInfo != NULL);
  62. #ifdef INETORGPERSON
  63. ASSERT(0 == lstrcmp(L"user", pNewADsObjectCreateInfo->m_pszObjectClass) || 0 == lstrcmp(L"inetOrgPerson", pNewADsObjectCreateInfo->m_pszObjectClass));
  64. #else
  65. ASSERT(0 == lstrcmp(L"user", pNewADsObjectCreateInfo->m_pszObjectClass));
  66. #endif
  67. CCreateNewUserWizard wiz(pNewADsObjectCreateInfo);
  68. return wiz.DoModal();
  69. } // HrCreateADsUser()
  70. /////////////////////////////////////////////////////////////////////
  71. // HrCreateADsVolume()
  72. //
  73. // Create a new volume.
  74. //
  75. HRESULT
  76. HrCreateADsVolume(INOUT CNewADsObjectCreateInfo * pNewADsObjectCreateInfo)
  77. {
  78. ASSERT(pNewADsObjectCreateInfo != NULL);
  79. ASSERT(0 == lstrcmp(L"volume", pNewADsObjectCreateInfo->m_pszObjectClass));
  80. CCreateNewVolumeWizard wiz(pNewADsObjectCreateInfo);
  81. return wiz.DoModal();
  82. } // HrCreateADsVolume()
  83. /////////////////////////////////////////////////////////////////////
  84. // HrCreateADsComputer()
  85. //
  86. // Create a new computer.
  87. //
  88. HRESULT
  89. HrCreateADsComputer(INOUT CNewADsObjectCreateInfo * pNewADsObjectCreateInfo)
  90. {
  91. ASSERT(pNewADsObjectCreateInfo != NULL);
  92. ASSERT(0 == lstrcmp(L"computer", pNewADsObjectCreateInfo->m_pszObjectClass));
  93. CCreateNewComputerWizard wiz(pNewADsObjectCreateInfo);
  94. return wiz.DoModal();
  95. } // HrCreateADsComputer()
  96. /////////////////////////////////////////////////////////////////////
  97. // HrCreateADsPrintQueue()
  98. //
  99. // Create a new print queue object.
  100. //
  101. HRESULT
  102. HrCreateADsPrintQueue(INOUT CNewADsObjectCreateInfo * pNewADsObjectCreateInfo)
  103. {
  104. ASSERT(pNewADsObjectCreateInfo != NULL);
  105. ASSERT(0 == lstrcmp(L"printQueue", pNewADsObjectCreateInfo->m_pszObjectClass));
  106. CCreateNewPrintQWizard wiz(pNewADsObjectCreateInfo);
  107. return wiz.DoModal();
  108. } // HrCreateADsPrintQueue()
  109. /////////////////////////////////////////////////////////////////////
  110. // HrCreateADsNtDsConnection()
  111. //
  112. // Create a new NTDS-Connection object. Note that this is not supported
  113. // if the parent is an FRS object.
  114. //
  115. HRESULT
  116. HrCreateADsNtDsConnection(INOUT CNewADsObjectCreateInfo * pNewADsObjectCreateInfo)
  117. {
  118. ASSERT(pNewADsObjectCreateInfo != NULL);
  119. ASSERT(0 == lstrcmp(L"nTDSConnection", pNewADsObjectCreateInfo->m_pszObjectClass));
  120. // do not allow this in the standalone case
  121. if (pNewADsObjectCreateInfo->IsStandaloneUI())
  122. {
  123. ASSERT(FALSE);
  124. return E_INVALIDARG;
  125. }
  126. // determine whether this is an NTDS connection or an FRS connection
  127. // CODEWORK this code can probably be removed
  128. CPathCracker pathCracker;
  129. HRESULT hr = S_OK;
  130. CString strConfigPath;
  131. CComBSTR sbstrParentPath;
  132. bool fParentIsFrs = false;
  133. {
  134. // determine whether this is an FRS instance
  135. CComQIPtr<IADs, &IID_IADs> spIADsParent( pNewADsObjectCreateInfo->m_pIADsContainer );
  136. ASSERT( !!spIADsParent );
  137. CComBSTR sbstrClass;
  138. hr = spIADsParent->get_ADsPath( &sbstrParentPath );
  139. RETURN_IF_FAIL;
  140. hr = spIADsParent->get_Class( &sbstrClass );
  141. RETURN_IF_FAIL;
  142. hr = DSPROP_IsFrsObject( sbstrClass, &fParentIsFrs );
  143. RETURN_IF_FAIL;
  144. // Determine which subtree should be searched
  145. if (fParentIsFrs)
  146. {
  147. #ifndef FRS_CREATE
  148. // We shouldn't have seen the option to create a connection here
  149. ASSERT(FALSE);
  150. return S_FALSE;
  151. #else
  152. sbstrClass.Empty();
  153. hr = spIADsParent->get_ADsPath( &sbstrClass );
  154. RETURN_IF_FAIL;
  155. hr = DSPROP_RemoveX500LeafElements( 1, &sbstrClass );
  156. RETURN_IF_FAIL;
  157. strConfigPath = sbstrClass;
  158. #endif // FRS_CREATE
  159. }
  160. else
  161. {
  162. pNewADsObjectCreateInfo->GetBasePathsInfo()->GetConfigPath(strConfigPath);
  163. }
  164. }
  165. CCreateNewObjectCnWizard wiz(pNewADsObjectCreateInfo);
  166. // Get the target server path from the user. The path is stored in a BSTR variant.
  167. CComBSTR sbstrTargetServer;
  168. #ifdef FRS_CREATE
  169. if (fParentIsFrs)
  170. {
  171. hr = DSPROP_DSQuery(
  172. pNewADsObjectCreateInfo->GetParentHwnd(),
  173. strConfigPath,
  174. const_cast<CLSID*>(&CLSID_DsFindFrsMembers),
  175. &sbstrTargetServer );
  176. }
  177. else
  178. #endif // FRS_CREATE
  179. {
  180. hr = DSPROP_PickNTDSDSA(
  181. pNewADsObjectCreateInfo->GetParentHwnd(),
  182. strConfigPath,
  183. &sbstrTargetServer );
  184. }
  185. if (hr == S_FALSE)
  186. {
  187. // User canceled the dialog
  188. return S_FALSE;
  189. }
  190. RETURN_IF_FAIL;
  191. if (sbstrTargetServer == sbstrParentPath)
  192. {
  193. // 6231: Shouldn't be able to create a connection to "yourself"
  194. ReportMessageEx( pNewADsObjectCreateInfo->GetParentHwnd(),
  195. IDS_CONNECTION_TO_SELF );
  196. return S_FALSE;
  197. }
  198. CComBSTR sbstrTargetServerX500DN;
  199. hr = pathCracker.Set( sbstrTargetServer, ADS_SETTYPE_FULL );
  200. RETURN_IF_FAIL;
  201. hr = pathCracker.SetDisplayType( ADS_DISPLAY_FULL );
  202. RETURN_IF_FAIL;
  203. hr = pathCracker.Retrieve( ADS_FORMAT_X500_DN, &sbstrTargetServerX500DN );
  204. RETURN_IF_FAIL;
  205. // 33881: prevent duplicate connection objects
  206. {
  207. CDSSearch Search;
  208. Search.Init(sbstrParentPath);
  209. CString filter;
  210. filter.Format(L"(fromServer=%s)", sbstrTargetServerX500DN);
  211. Search.SetFilterString(const_cast<LPTSTR>((LPCTSTR) filter));
  212. LPWSTR pAttrs[1] =
  213. {
  214. L"name"
  215. };
  216. Search.SetAttributeList(pAttrs, 1);
  217. Search.SetSearchScope(ADS_SCOPE_SUBTREE);
  218. hr = Search.DoQuery();
  219. if (SUCCEEDED(hr))
  220. {
  221. hr = Search.GetNextRow();
  222. if (SUCCEEDED(hr) && S_ADS_NOMORE_ROWS != hr)
  223. {
  224. DWORD dwRetval = ReportMessageEx(
  225. pNewADsObjectCreateInfo->GetParentHwnd(),
  226. IDS_DUPLICATE_CONNECTION,
  227. MB_YESNO | MB_DEFBUTTON2 | MB_ICONWARNING );
  228. if (IDYES != dwRetval)
  229. return S_FALSE;
  230. }
  231. }
  232. }
  233. hr = pNewADsObjectCreateInfo->HrAddVariantBstr(
  234. L"fromServer", sbstrTargetServerX500DN, TRUE );
  235. RETURN_IF_FAIL;
  236. {
  237. // NTDS: set default name to RDN of parent of target NTDS-DSA
  238. // FRS: set default name to RDN of target NTFRS-Member
  239. CComBSTR bstrDefaultRDN;
  240. hr = pathCracker.SetDisplayType(ADS_DISPLAY_VALUE_ONLY);
  241. RETURN_IF_FAIL;
  242. hr = pathCracker.GetElement( (fParentIsFrs) ? 0 : 1, &bstrDefaultRDN );
  243. RETURN_IF_FAIL;
  244. ASSERT( !!bstrDefaultRDN && TEXT('\0') != *bstrDefaultRDN );
  245. pNewADsObjectCreateInfo->m_strDefaultObjectName = bstrDefaultRDN;
  246. hr = pathCracker.SetDisplayType(ADS_DISPLAY_FULL);
  247. RETURN_IF_FAIL;
  248. }
  249. //
  250. // Must do this before DoModal, OnOK will try to actually create the object
  251. //
  252. hr = pNewADsObjectCreateInfo->HrAddVariantLong(L"options", 0, TRUE);
  253. RETURN_IF_FAIL;
  254. hr = pNewADsObjectCreateInfo->HrAddVariantBoolean(L"enabledConnection", TRUE, TRUE);
  255. RETURN_IF_FAIL;
  256. {
  257. //
  258. // Store initial schedule
  259. //
  260. BYTE abyteSchedule[ HeadersSizeNum(1) + cbDSScheduleArrayLength ];
  261. ZeroMemory( &abyteSchedule, sizeof(abyteSchedule) );
  262. PSCHEDULE pNewScheduleBlock = (PSCHEDULE) abyteSchedule;
  263. pNewScheduleBlock->Size = sizeof(abyteSchedule);
  264. pNewScheduleBlock->NumberOfSchedules = 1;
  265. pNewScheduleBlock->Schedules[0].Type = SCHEDULE_INTERVAL;
  266. pNewScheduleBlock->Schedules[0].Offset = HeadersSizeNum(1);
  267. memset( ((BYTE*)pNewScheduleBlock)+pNewScheduleBlock->Schedules[0].Offset,
  268. INTERVAL_MASK,
  269. cbDSScheduleArrayLength ); // turn on all intervals
  270. CComVariant varSchedule;
  271. hr = BinaryToVariant( sizeof(abyteSchedule), abyteSchedule, &varSchedule );
  272. RETURN_IF_FAIL;
  273. hr = pNewADsObjectCreateInfo->HrAddVariantCopyVar(L"schedule", IN varSchedule, TRUE);
  274. RETURN_IF_FAIL;
  275. }
  276. // CODEWORK: Need to set the dialog caption
  277. hr = wiz.DoModal();
  278. return hr;
  279. } // HrCreateADsNtDsConnection()
  280. HRESULT
  281. HrCreateADsFixedName(INOUT CNewADsObjectCreateInfo * pNewADsObjectCreateInfo)
  282. {
  283. // Store the object name in the temporary storage
  284. LPCWSTR pcsz = reinterpret_cast<LPCWSTR>(pNewADsObjectCreateInfo->QueryCreationParameter());
  285. ASSERT( NULL != pcsz );
  286. pNewADsObjectCreateInfo->HrCreateNew(pcsz);
  287. // Create and persist the object
  288. HRESULT hr = pNewADsObjectCreateInfo->HrSetInfo(TRUE /*fSilentError*/);
  289. if (SUCCEEDED(hr)) {
  290. CString csCaption, csMsg;
  291. csCaption.LoadString(IDS_CREATE_NEW_OBJECT_TITLE);
  292. csMsg.Format(IDS_s_CREATE_NEW_OBJECT_NOTICE, pNewADsObjectCreateInfo->GetName());
  293. ::MessageBox(
  294. pNewADsObjectCreateInfo->GetParentHwnd(),
  295. csMsg,
  296. csCaption,
  297. MB_OK | MB_SETFOREGROUND | MB_ICONINFORMATION);
  298. }
  299. return hr;
  300. }
  301. HRESULT
  302. HrCreateADsSiteLink(INOUT CNewADsObjectCreateInfo * pNewADsObjectCreateInfo)
  303. {
  304. ASSERT(pNewADsObjectCreateInfo != NULL);
  305. ASSERT(0 == lstrcmp(gsz_siteLink, pNewADsObjectCreateInfo->m_pszObjectClass));
  306. // load list of sites
  307. DSPROP_BSTR_BLOCK bstrblock;
  308. CComQIPtr<IADs, &IID_IADs> container(pNewADsObjectCreateInfo->m_pIADsContainer);
  309. if (container)
  310. {
  311. CComBSTR container_path;
  312. container->get_ADsPath(&container_path);
  313. HRESULT hr = DSPROP_RemoveX500LeafElements( 2, &container_path );
  314. if ( SUCCEEDED(hr) )
  315. {
  316. hr = DSPROP_ShallowSearch(
  317. &bstrblock,
  318. container_path,
  319. L"site" );
  320. }
  321. if ( FAILED(hr) )
  322. {
  323. ReportErrorEx (pNewADsObjectCreateInfo->GetParentHwnd(),
  324. IDS_SITELINKERROR_READING_SITES,
  325. hr,
  326. MB_OK, NULL, 0);
  327. return S_FALSE;
  328. }
  329. }
  330. if ( 2 > bstrblock.QueryCount() )
  331. {
  332. ReportMessageEx(pNewADsObjectCreateInfo->GetParentHwnd(),
  333. IDS_SITELINK_NOT_ENOUGH_SITES,
  334. MB_OK | MB_ICONSTOP);
  335. // allow wizard to continue, CODEWORK note that this
  336. // doesn't quite work right when zero sites are detected
  337. }
  338. // set default cost to 100 (by request of JeffParh)
  339. HRESULT hr = pNewADsObjectCreateInfo->HrAddVariantLong(L"cost", 100L, TRUE);
  340. RETURN_IF_FAIL;
  341. // set default replInterval to 180 (by request of JeffParh)
  342. hr = pNewADsObjectCreateInfo->HrAddVariantLong(L"replInterval", 180L, TRUE);
  343. RETURN_IF_FAIL;
  344. CCreateNewSiteLinkWizard wiz(pNewADsObjectCreateInfo,bstrblock);
  345. return wiz.DoModal();
  346. }
  347. HRESULT
  348. HrCreateADsSiteLinkBridge(INOUT CNewADsObjectCreateInfo * pNewADsObjectCreateInfo)
  349. {
  350. ASSERT(pNewADsObjectCreateInfo != NULL);
  351. ASSERT(0 == lstrcmp(gsz_siteLinkBridge, pNewADsObjectCreateInfo->m_pszObjectClass));
  352. // load list of site links
  353. DSPROP_BSTR_BLOCK bstrblock;
  354. CComQIPtr<IADs, &IID_IADs> container(pNewADsObjectCreateInfo->m_pIADsContainer);
  355. if (container)
  356. {
  357. CComBSTR container_path;
  358. container->get_ADsPath(&container_path);
  359. HRESULT hr = DSPROP_ShallowSearch(
  360. &bstrblock,
  361. container_path,
  362. L"siteLink" );
  363. if ( FAILED(hr) )
  364. {
  365. ReportErrorEx (pNewADsObjectCreateInfo->GetParentHwnd(),
  366. IDS_SITELINKBRIDGEERROR_READING_SITELINKS,
  367. hr,
  368. MB_OK, NULL, 0);
  369. return S_FALSE;
  370. }
  371. }
  372. if ( 2 > bstrblock.QueryCount() )
  373. {
  374. ReportMessageEx(pNewADsObjectCreateInfo->GetParentHwnd(),
  375. IDS_SITELINKBRIDGE_NOT_ENOUGH_SITELINKS,
  376. MB_OK | MB_ICONSTOP);
  377. return S_FALSE; // do not allow wizard to continue
  378. }
  379. CCreateNewSiteLinkBridgeWizard wiz(pNewADsObjectCreateInfo,bstrblock);
  380. return wiz.DoModal();
  381. }
  382. #ifdef FRS_CREATE
  383. HRESULT
  384. HrCreateADsNtFrsMember(INOUT CNewADsObjectCreateInfo * pNewADsObjectCreateInfo)
  385. {
  386. ASSERT(pNewADsObjectCreateInfo != NULL);
  387. ASSERT(0 == lstrcmp(gsz_nTFRSMember, pNewADsObjectCreateInfo->m_pszObjectClass));
  388. //
  389. // set up Frs-Computer-Reference attribute
  390. //
  391. CComBSTR sbstrComputerPath;
  392. // pNewADsObjectCreateInfo->m_strDefaultObjectName = sbstrComputerRDN;
  393. HRESULT hr = DSPROP_PickComputer( pNewADsObjectCreateInfo->GetParentHwnd(), &sbstrComputerPath );
  394. RETURN_IF_FAIL;
  395. // Allow user to quit if user hit Cancel
  396. if (hr == S_FALSE)
  397. return S_FALSE;
  398. // set default name to RDN of target Computer
  399. hr = pathCracker.Set(sbstrComputerPath, ADS_SETTYPE_FULL);
  400. RETURN_IF_FAIL;
  401. hr = pathCracker.SetDisplayType(ADS_DISPLAY_VALUE_ONLY);
  402. RETURN_IF_FAIL;
  403. sbstrComputerPath.Empty();
  404. hr = pathCracker.GetElement( 0, &sbstrComputerPath );
  405. RETURN_IF_FAIL;
  406. pNewADsObjectCreateInfo->m_strDefaultObjectName = sbstrComputerPath;
  407. hr = pathCracker.SetDisplayType(ADS_DISPLAY_FULL);
  408. RETURN_IF_FAIL;
  409. // set frsComputerReference for new object
  410. sbstrComputerPath.Empty();
  411. hr = pathCracker.Retrieve( ADS_FORMAT_X500_DN, &sbstrComputerPath );
  412. RETURN_IF_FAIL;
  413. hr = pNewADsObjectCreateInfo->HrAddVariantBstr(
  414. L"frsComputerReference", sbstrComputerPath, TRUE );
  415. RETURN_IF_FAIL;
  416. hr = HrCreateADsSimpleObject(pNewADsObjectCreateInfo);
  417. return hr;
  418. }
  419. HRESULT
  420. HrCreateADsNtFrsSubscriber(INOUT CNewADsObjectCreateInfo * pNewADsObjectCreateInfo)
  421. {
  422. ASSERT(pNewADsObjectCreateInfo != NULL);
  423. ASSERT(0 == lstrcmp(gsz_nTFRSSubscriber, pNewADsObjectCreateInfo->m_pszObjectClass));
  424. // User finds target nTFRSMember object
  425. CComBSTR sbstrTargetMember;
  426. HRESULT hr = DSPROP_DSQuery(
  427. pNewADsObjectCreateInfo->GetParentHwnd(),
  428. NULL, // any member
  429. const_cast<CLSID*>(&CLSID_DsFindFrsMembers),
  430. &sbstrTargetMember );
  431. if (hr == S_FALSE)
  432. {
  433. // User canceled the dialog
  434. return S_FALSE;
  435. }
  436. RETURN_IF_FAIL;
  437. // set default name of new nTFRSSubscriber to RDN of target nTFRSMember
  438. hr = pathCracker.Set( sbstrTargetMember, ADS_SETTYPE_FULL );
  439. RETURN_IF_FAIL;
  440. hr = pathCracker.SetDisplayType(ADS_DISPLAY_VALUE_ONLY);
  441. RETURN_IF_FAIL;
  442. sbstrTargetMember.Empty();
  443. hr = pathCracker.GetElement( 0, &sbstrTargetMember );
  444. RETURN_IF_FAIL;
  445. pNewADsObjectCreateInfo->m_strDefaultObjectName = sbstrTargetMember;
  446. hr = pathCracker.SetDisplayType(ADS_DISPLAY_FULL);
  447. RETURN_IF_FAIL;
  448. // set fRSMemberReference attribute to target nTFRSMember
  449. sbstrTargetMember.Empty();
  450. hr = pathCracker.Retrieve( ADS_FORMAT_X500_DN, &sbstrTargetMember );
  451. RETURN_IF_FAIL;
  452. hr = pNewADsObjectCreateInfo->HrAddVariantBstr(
  453. L"fRSMemberReference", sbstrTargetMember, TRUE );
  454. RETURN_IF_FAIL;
  455. CCreateNewFrsSubscriberWizard wiz(pNewADsObjectCreateInfo);
  456. return wiz.DoModal();
  457. }
  458. //+----------------------------------------------------------------------------
  459. //
  460. // Function: CreateADsNtFrsSubscriptions
  461. //
  462. // Purpose: Create an NT-FRS-Subscriptions object and then grant its parent
  463. // (a computer object) full access.
  464. //
  465. //-----------------------------------------------------------------------------
  466. HRESULT
  467. CreateADsNtFrsSubscriptions(CNewADsObjectCreateInfo * pNewADsObjectCreateInfo)
  468. {
  469. LPCWSTR pcsz = reinterpret_cast<LPCWSTR>(pNewADsObjectCreateInfo->QueryCreationParameter());
  470. ASSERT( NULL != pcsz );
  471. pNewADsObjectCreateInfo->HrCreateNew(pcsz);
  472. //
  473. // Create and persist the object. This must be done before attempting to modify
  474. // the Security Descriptor.
  475. //
  476. HRESULT hr = pNewADsObjectCreateInfo->HrSetInfo();
  477. if (FAILED(hr))
  478. {
  479. TRACE(_T("pNewADsObjectCreateInfo->HrSetInfo failed!\n"));
  480. return hr;
  481. }
  482. //
  483. // Create a new ACE on this object granting the parent full control. First, get the
  484. // parent's SID.
  485. //
  486. CComVariant varSID;
  487. CComPtr <IADs> pADS;
  488. hr = pNewADsObjectCreateInfo->m_pIADsContainer->QueryInterface(IID_IADs, (PVOID*)&pADS);
  489. if (FAILED(hr))
  490. {
  491. TRACE(_T("QueryInterface(IID_IADs) failed!\n"));
  492. return hr;
  493. }
  494. hr = pADS->Get(L"objectSid", &varSID);
  495. if (FAILED(hr))
  496. {
  497. TRACE(_T("Get(\"objectSid\") failed!\n"));
  498. return hr;
  499. }
  500. ASSERT((varSID.vt & ~VT_ARRAY) == VT_UI1); // this better be an array of BYTEs.
  501. ASSERT(varSID.parray->cbElements && varSID.parray->pvData);
  502. //
  503. // Get this object's Security Descriptor.
  504. //
  505. CComPtr <IDirectoryObject> pDirObj;
  506. hr = pNewADsObjectCreateInfo->PGetIADsPtr()->QueryInterface(IID_IDirectoryObject, (PVOID*)&pDirObj);
  507. if (FAILED(hr))
  508. {
  509. TRACE(_T("QueryInterface(IID_IDirectoryObject) failed!\n"));
  510. return hr;
  511. }
  512. const PWSTR wzSecDescriptor = L"nTSecurityDescriptor";
  513. PADS_ATTR_INFO pAttrs = NULL;
  514. DWORD cAttrs = 0;
  515. LPWSTR rgpwzAttrNames[] = {wzSecDescriptor};
  516. hr = pDirObj->GetObjectAttributes(rgpwzAttrNames, 1, &pAttrs, &cAttrs);
  517. if (FAILED(hr))
  518. {
  519. TRACE(_T("GetObjectAttributes(wzSecDescriptor) failed!\n"));
  520. return hr;
  521. }
  522. ASSERT(cAttrs == 1); // SD is a required attribute. Blow chunks if missing.
  523. ASSERT(pAttrs != NULL);
  524. ASSERT(pAttrs->pADsValues != NULL);
  525. if (!pAttrs->pADsValues->SecurityDescriptor.lpValue ||
  526. !pAttrs->pADsValues->SecurityDescriptor.dwLength)
  527. {
  528. TRACE(_T("IADS return bogus SD!\n"));
  529. FreeADsMem(pAttrs);
  530. return E_UNEXPECTED;
  531. }
  532. if (!IsValidSecurityDescriptor(pAttrs->pADsValues->SecurityDescriptor.lpValue))
  533. {
  534. TRACE(_T("IsValidSecurityDescriptor failed!\n"));
  535. FreeADsMem(pAttrs);
  536. return HRESULT_FROM_WIN32(GetLastError());
  537. }
  538. //
  539. // Can't modify a self-relative SD so convert it to an absolute one.
  540. //
  541. PSECURITY_DESCRIPTOR pAbsSD = NULL, pNewSD;
  542. PACL pDacl = NULL, pSacl = NULL;
  543. PSID pOwnerSid = NULL, pPriGrpSid = NULL;
  544. DWORD cbSD = 0, cbDacl = 0, cbSacl = 0, cbOwner = 0, cbPriGrp = 0;
  545. if (!MakeAbsoluteSD(pAttrs->pADsValues->SecurityDescriptor.lpValue,
  546. pAbsSD, &cbSD, pDacl, &cbDacl,
  547. pSacl, &cbSacl, pOwnerSid, &cbOwner,
  548. pPriGrpSid, &cbPriGrp))
  549. {
  550. DWORD dwErr = GetLastError();
  551. if (dwErr != ERROR_INSUFFICIENT_BUFFER)
  552. {
  553. TRACE(_T("MakeAbsoluteSD failed to return buffer sizes!\n"));
  554. FreeADsMem(pAttrs);
  555. return HRESULT_FROM_WIN32(GetLastError());
  556. }
  557. }
  558. if (!cbDacl)
  559. {
  560. TRACE(_T("SD missing DACL!\n"));
  561. FreeADsMem(pAttrs);
  562. return E_UNEXPECTED;
  563. }
  564. WORD wSizeNeeded = (WORD)(sizeof(ACCESS_ALLOWED_ACE) + // the last element of
  565. GetLengthSid(varSID.parray->pvData) - // the ACE struct is the
  566. sizeof(DWORD)); // first DWORD of the SID.
  567. CSmartBytePtr spAbsSD(cbSD), spSacl(cbSacl);
  568. CSmartBytePtr spDacl(cbDacl + wSizeNeeded);
  569. CSmartBytePtr spOwnerSid(cbOwner), spPriGrpSid(cbPriGrp);
  570. pAbsSD = spAbsSD;
  571. pDacl = (PACL)(PBYTE)spDacl;
  572. pSacl = (PACL)(PBYTE)spSacl;
  573. pOwnerSid = spOwnerSid;
  574. pPriGrpSid = spPriGrpSid;
  575. if (!(pAbsSD && pDacl && pSacl && pOwnerSid && pPriGrpSid))
  576. {
  577. TRACE(_T("SD allocation failed!\n"));
  578. FreeADsMem(pAttrs);
  579. return E_OUTOFMEMORY;
  580. }
  581. if (!MakeAbsoluteSD(pAttrs->pADsValues->SecurityDescriptor.lpValue,
  582. pAbsSD, &cbSD, pDacl, &cbDacl,
  583. pSacl, &cbSacl, pOwnerSid, &cbOwner,
  584. pPriGrpSid, &cbPriGrp))
  585. {
  586. TRACE(_T("MakeAbsoluteSD failed!\n"));
  587. FreeADsMem(pAttrs);
  588. return HRESULT_FROM_WIN32(GetLastError());
  589. }
  590. FreeADsMem(pAttrs);
  591. //
  592. // Add ACE. First tell the DACL that there is enough room.
  593. //
  594. ACL_SIZE_INFORMATION asi;
  595. if (!GetAclInformation(pDacl, &asi, sizeof(asi), AclSizeInformation))
  596. {
  597. TRACE(_T("GetAclInformation failed!\n"));
  598. return HRESULT_FROM_WIN32(GetLastError());
  599. }
  600. if (asi.AclBytesFree < wSizeNeeded)
  601. {
  602. pDacl->AclSize += wSizeNeeded;
  603. }
  604. if (!AddAccessAllowedAce(pDacl,
  605. ACL_REVISION_DS,
  606. STANDARD_RIGHTS_ALL | ACTRL_DS_OPEN |
  607. ACTRL_DS_CREATE_CHILD | ACTRL_DS_DELETE_CHILD |
  608. ACTRL_DS_LIST | ACTRL_DS_SELF |
  609. ACTRL_DS_READ_PROP | ACTRL_DS_WRITE_PROP |
  610. ACTRL_DS_DELETE_TREE | ACTRL_DS_LIST_OBJECT,
  611. varSID.parray->pvData))
  612. {
  613. TRACE(_T("AddAccessAllowedAce failed!\n"));
  614. return HRESULT_FROM_WIN32(GetLastError());
  615. }
  616. //
  617. // Put the SD back together again (sort of like Humpty Dumpty)...
  618. //
  619. SECURITY_DESCRIPTOR_CONTROL sdc;
  620. DWORD dwRev;
  621. if (!GetSecurityDescriptorControl(pAbsSD, &sdc, &dwRev))
  622. {
  623. TRACE(_T("GetSecurityDescriptorControl failed!\n"));
  624. return HRESULT_FROM_WIN32(GetLastError());
  625. }
  626. SECURITY_DESCRIPTOR sd;
  627. if (!InitializeSecurityDescriptor(&sd, dwRev))
  628. {
  629. TRACE(_T("InitializeSecurityDescriptor failed!\n"));
  630. return HRESULT_FROM_WIN32(GetLastError());
  631. }
  632. if (!SetSecurityDescriptorOwner(&sd, pOwnerSid, sdc & SE_OWNER_DEFAULTED))
  633. {
  634. TRACE(_T("SetSecurityDescriptorOwner failed!\n"));
  635. return HRESULT_FROM_WIN32(GetLastError());
  636. }
  637. if (!SetSecurityDescriptorGroup(&sd, pPriGrpSid, sdc & SE_GROUP_DEFAULTED))
  638. {
  639. TRACE(_T("SetSecurityDescriptorOwner failed!\n"));
  640. return HRESULT_FROM_WIN32(GetLastError());
  641. }
  642. if (!SetSecurityDescriptorSacl(&sd, sdc & SE_SACL_PRESENT, pSacl, sdc & SE_SACL_DEFAULTED))
  643. {
  644. TRACE(_T("SetSecurityDescriptorOwner failed!\n"));
  645. return HRESULT_FROM_WIN32(GetLastError());
  646. }
  647. if (!SetSecurityDescriptorDacl(&sd, sdc & SE_DACL_PRESENT, pDacl, sdc & SE_DACL_DEFAULTED))
  648. {
  649. TRACE(_T("SetSecurityDescriptorOwner failed!\n"));
  650. return HRESULT_FROM_WIN32(GetLastError());
  651. }
  652. DWORD dwSDlen = GetSecurityDescriptorLength(&sd);
  653. CSmartBytePtr spNewSD(dwSDlen);
  654. if (!spNewSD)
  655. {
  656. TRACE(_T("SD allocation failed!\n"));
  657. return E_OUTOFMEMORY;
  658. }
  659. pNewSD = (PSECURITY_DESCRIPTOR)spNewSD;
  660. if (!MakeSelfRelativeSD(&sd, pNewSD, &dwSDlen))
  661. {
  662. DWORD dwErr = GetLastError();
  663. if (dwErr != ERROR_INSUFFICIENT_BUFFER)
  664. {
  665. TRACE(_T("MakeSelfRelativeSD failed, err: %d!\n"), dwErr);
  666. return HRESULT_FROM_WIN32(GetLastError());
  667. }
  668. if (!spNewSD.ReAlloc(dwSDlen))
  669. {
  670. TRACE(_T("Unable to re-alloc SD buffer!\n"));
  671. return E_OUTOFMEMORY;
  672. }
  673. if (!MakeSelfRelativeSD(&sd, pNewSD, &dwSDlen))
  674. {
  675. TRACE(_T("MakeSelfRelativeSD failed, err: %d!\n"), GetLastError());
  676. return HRESULT_FROM_WIN32(GetLastError());
  677. }
  678. }
  679. dwSDlen = GetSecurityDescriptorLength(pNewSD);
  680. if (dwSDlen < SECURITY_DESCRIPTOR_MIN_LENGTH)
  681. {
  682. TRACE(_T("Bad computer security descriptor length!\n"));
  683. return HRESULT_FROM_WIN32(GetLastError());
  684. }
  685. if (!IsValidSecurityDescriptor(pNewSD))
  686. {
  687. TRACE(_T("IsValidSecurityDescriptor failed!\n"));
  688. return HRESULT_FROM_WIN32(GetLastError());
  689. }
  690. //
  691. // Save the modified SD back to this object.
  692. //
  693. DWORD cModified;
  694. ADSVALUE ADsValueSecurityDesc = {ADSTYPE_NT_SECURITY_DESCRIPTOR, NULL};
  695. ADS_ATTR_INFO AttrInfoSecurityDesc = {wzSecDescriptor, ADS_ATTR_UPDATE,
  696. ADSTYPE_NT_SECURITY_DESCRIPTOR,
  697. &ADsValueSecurityDesc, 1};
  698. ADsValueSecurityDesc.SecurityDescriptor.dwLength = dwSDlen;
  699. ADsValueSecurityDesc.SecurityDescriptor.lpValue = (PBYTE)pNewSD;
  700. ADS_ATTR_INFO rgAttrs[1];
  701. rgAttrs[0] = AttrInfoSecurityDesc;
  702. hr = pDirObj->SetObjectAttributes(rgAttrs, 1, &cModified);
  703. if (FAILED(hr))
  704. {
  705. TRACE(_T("SetObjectAttributes on SecurityDescriptor failed!\n"));
  706. return hr;
  707. }
  708. return S_OK;
  709. }
  710. #endif // FRS_CREATE
  711. HRESULT
  712. HrCreateADsSubnet(INOUT CNewADsObjectCreateInfo * pNewADsObjectCreateInfo)
  713. {
  714. ASSERT(pNewADsObjectCreateInfo != NULL);
  715. ASSERT(0 == lstrcmp(L"subnet", pNewADsObjectCreateInfo->m_pszObjectClass));
  716. CreateNewSubnetWizard wiz(pNewADsObjectCreateInfo);
  717. return wiz.DoModal();
  718. }
  719. // Note that this assumes that the site is the "grandparent" of the server.
  720. // If it isn't, the wrong name will appear in the site field.
  721. HRESULT ExtractServerAndSiteName(
  722. IN LPWSTR pwszServerDN,
  723. OUT BSTR* pbstrServerName,
  724. OUT BSTR* pbstrSiteName )
  725. {
  726. CPathCracker pathCracker;
  727. *pbstrServerName = NULL;
  728. *pbstrSiteName = NULL;
  729. if ( NULL == pwszServerDN || L'\0' == *pwszServerDN )
  730. return S_OK;
  731. HRESULT hr = pathCracker.Set( pwszServerDN, ADS_SETTYPE_DN );
  732. RETURN_IF_FAIL;
  733. hr = pathCracker.SetDisplayType( ADS_DISPLAY_VALUE_ONLY );
  734. RETURN_IF_FAIL;
  735. hr = pathCracker.GetElement( 0, pbstrServerName );
  736. RETURN_IF_FAIL;
  737. hr = pathCracker.GetElement( 2, pbstrSiteName );
  738. RETURN_IF_FAIL;
  739. hr = pathCracker.SetDisplayType( ADS_DISPLAY_FULL );
  740. RETURN_IF_FAIL;
  741. return S_OK;
  742. }
  743. HRESULT
  744. HrCreateADsServer(INOUT CNewADsObjectCreateInfo * pNewADsObjectCreateInfo)
  745. {
  746. HRESULT hr = S_OK;
  747. #ifdef SERVER_COMPUTER_REFERENCE
  748. CComBSTR sbstrComputerPath;
  749. CComBSTR sbstrX500DN;
  750. CComBSTR sbstrComputerRDN;
  751. CComBSTR sbstrTemp;
  752. CComVariant svarServerReference;
  753. CComPtr<IADs> spIADsComputer;
  754. bool fSkipComputerModify = false;
  755. do
  756. {
  757. hr = DSPROP_PickComputer( pNewADsObjectCreateInfo->GetParentHwnd(), &sbstrComputerPath );
  758. BREAK_ON_FAIL;
  759. // Allow user to quit if user hit Cancel
  760. if (hr == S_FALSE)
  761. {
  762. DWORD dwRetval = ReportMessageEx(
  763. pNewADsObjectCreateInfo->GetParentHwnd(),
  764. IDS_SKIP_SERVER_REFERENCE,
  765. MB_YESNO | MB_DEFBUTTON2 | MB_ICONWARNING );
  766. if (IDYES != dwRetval)
  767. {
  768. hr = S_FALSE;
  769. break;
  770. }
  771. fSkipComputerModify=true;
  772. }
  773. else
  774. { // prepare to modify computer object
  775. /*
  776. // Since the dialog was in single-select mode and the user was able
  777. // to hit OK, there should be exactly one selection.
  778. BREAK_ON_TRUE(1 != pSelection->cItems);
  779. */
  780. // retrieve the ADsPath to the selected computer
  781. // hr = pathCracker.Set(pSelection->aDsSelection[0].pwzADsPath, ADS_SETTYPE_FULL);
  782. hr = pathCracker.Set(sbstrComputerPath, ADS_SETTYPE_FULL);
  783. sbstrComputerPath.Empty();
  784. BREAK_ON_FAIL;
  785. // if this is a GC: path, the server might have a read-only copy of
  786. // this object. Change the path to an LDAP: path and remove the server.
  787. hr = pathCracker.Retrieve(ADS_FORMAT_PROVIDER,&sbstrTemp);
  788. BREAK_ON_FAIL;
  789. long lnFormatType = ADS_FORMAT_WINDOWS;
  790. if ( lstrcmp(sbstrTemp, TEXT("LDAP")) )
  791. {
  792. ASSERT( !lstrcmp(sbstrTemp, TEXT("GC")) );
  793. #error CODEWORK this usage of ADS_SETTYPE_PROVIDER will no longer work! JonN 2/12/99
  794. hr = pathCracker.Set(TEXT("LDAP"),ADS_SETTYPE_PROVIDER);
  795. BREAK_ON_FAIL;
  796. lnFormatType = ADS_FORMAT_WINDOWS_NO_SERVER;
  797. }
  798. sbstrTemp.Empty();
  799. hr = pathCracker.Retrieve(lnFormatType,&sbstrComputerPath);
  800. BREAK_ON_FAIL;
  801. // We preserve the servername in case Computer Picker returns one.
  802. // Extract the name of the computer object and make that the default name
  803. // of the new server object
  804. hr = pathCracker.SetDisplayType(ADS_DISPLAY_VALUE_ONLY);
  805. BREAK_ON_FAIL;
  806. hr = pathCracker.GetElement(0,&sbstrComputerRDN);
  807. BREAK_ON_FAIL;
  808. BREAK_ON_TRUE( !sbstrComputerRDN || TEXT('\0') == *sbstrComputerRDN );
  809. pNewADsObjectCreateInfo->m_strDefaultObjectName = sbstrComputerRDN;
  810. hr = pathCracker.SetDisplayType(ADS_DISPLAY_FULL);
  811. BREAK_ON_FAIL;
  812. // Now check whether the computer already references a server.
  813. // Note that we may be using a serverless path, ADSI will try to find a
  814. // replica on the same domain as the computer object.
  815. hr = DSAdminOpenObject(sbstrComputerPath,
  816. IID_IADs,
  817. (PVOID*)&spIADsComputer,
  818. FALSE /*bServer*/
  819. );
  820. // DSAdminOpenObject might fail if the initial path chosen by Computer Picker
  821. // is a GC: path. The code above would munge the GC: path to an LDAP:
  822. // serverless path, and ADSI might choose a replica which hasn't
  823. // replicated this object yet.
  824. if ( SUCCEEDED(hr) )
  825. {
  826. hr = spIADsComputer->Get( L"serverReference", &svarServerReference );
  827. }
  828. if ( E_ADS_PROPERTY_NOT_FOUND == hr )
  829. {
  830. hr = S_OK;
  831. }
  832. else if ( FAILED(hr) )
  833. {
  834. PVOID apv[1] = { (BSTR)sbstrComputerRDN };
  835. DWORD dwRetval = ReportErrorEx(
  836. pNewADsObjectCreateInfo->GetParentHwnd(),
  837. IDS_12_SERVER_REFERENCE_FAILED,
  838. hr,
  839. MB_YESNO | MB_DEFBUTTON2 | MB_ICONWARNING,
  840. apv,
  841. 1 );
  842. if (IDYES != dwRetval)
  843. {
  844. hr = S_FALSE;
  845. break;
  846. }
  847. fSkipComputerModify=TRUE;
  848. hr = S_OK;
  849. }
  850. else
  851. {
  852. if ( VT_BSTR == V_VT(&svarServerReference) && NULL != V_BSTR(&svarServerReference) )
  853. {
  854. CComBSTR sbstrServerName;
  855. CComBSTR sbstrSiteName;
  856. hr = ExtractServerAndSiteName(
  857. V_BSTR(&svarServerReference), &sbstrServerName, &sbstrSiteName );
  858. BREAK_ON_FAIL;
  859. PVOID apv[3];
  860. apv[0] = (BSTR)sbstrComputerRDN;
  861. apv[1] = (BSTR)sbstrServerName;
  862. apv[2] = (BSTR)sbstrSiteName;
  863. DWORD dwRetval = ReportMessageEx(
  864. pNewADsObjectCreateInfo->GetParentHwnd(),
  865. IDS_123_COMPUTER_OBJECT_ALREADY_USED,
  866. MB_YESNO | MB_DEFBUTTON2 | MB_ICONWARNING,
  867. apv,
  868. 3 );
  869. if (IDYES != dwRetval)
  870. {
  871. hr = S_FALSE;
  872. break;
  873. }
  874. }
  875. }
  876. } // prepare to modify computer object
  877. #endif // SERVER_COMPUTER_REFERENCE
  878. // This is the standard UI to create a simple object
  879. hr = HrCreateADsSimpleObject(pNewADsObjectCreateInfo);
  880. #ifdef SERVER_COMPUTER_REFERENCE
  881. if ( FAILED(hr) || S_FALSE == hr )
  882. {
  883. break;
  884. }
  885. // If an error occurs after the server was successfully created, we use a
  886. // special error message.
  887. do { // false loop
  888. if (fSkipComputerModify)
  889. break; // CODEWORK also display a fancy message?
  890. // Get the path to the new Server object in X500 format
  891. hr = pNewADsObjectCreateInfo->PGetIADsPtr()->get_ADsPath(&sbstrTemp);
  892. BREAK_ON_FAIL;
  893. hr = pathCracker.Set(sbstrTemp,ADS_SETTYPE_FULL);
  894. BREAK_ON_FAIL;
  895. hr = pathCracker.SetDisplayType(ADS_DISPLAY_FULL);
  896. BREAK_ON_FAIL;
  897. hr = pathCracker.Retrieve(ADS_FORMAT_X500_DN,&sbstrX500DN);
  898. BREAK_ON_FAIL;
  899. // Set the computer object's serverReference attribute
  900. // to point to the new Server object
  901. svarServerReference = sbstrX500DN;
  902. hr = spIADsComputer->Put( L"serverReference", svarServerReference );
  903. BREAK_ON_FAIL;
  904. hr = spIADsComputer->SetInfo();
  905. BREAK_ON_FAIL;
  906. } while (false); // false loop
  907. if ( FAILED(hr) )
  908. {
  909. // The server was created but the computer could not be updated
  910. CComBSTR sbstrServerName;
  911. CComBSTR sbstrSiteName;
  912. (void) ExtractServerAndSiteName(
  913. V_BSTR(&svarServerReference), &sbstrServerName, &sbstrSiteName );
  914. PVOID apv[3];
  915. apv[0] = (BSTR)sbstrComputerRDN;
  916. apv[1] = (BSTR)sbstrServerName;
  917. apv[2] = (BSTR)sbstrSiteName;
  918. (void) ReportErrorEx(
  919. pNewADsObjectCreateInfo->GetParentHwnd(),
  920. IDS_1234_SERVER_REFERENCE_ERROR,
  921. hr,
  922. MB_OK | MB_ICONEXCLAMATION,
  923. apv,
  924. 3 );
  925. hr = S_OK;
  926. }
  927. } while (false); // false loop
  928. #endif // SERVER_COMPUTER_REFERENCE
  929. // cleanup
  930. return hr;
  931. }
  932. HRESULT
  933. HrCreateADsSite(INOUT CNewADsObjectCreateInfo * pNewADsObjectCreateInfo)
  934. {
  935. HRESULT hr = CreateNewSiteWizard(pNewADsObjectCreateInfo).DoModal();
  936. if ( !SUCCEEDED(hr) || S_FALSE == hr )
  937. return hr;
  938. // need to create sub objects
  939. IADs* pIADs = pNewADsObjectCreateInfo->PGetIADsPtr();
  940. ASSERT(pIADs != NULL);
  941. IADsContainer* pIADsContainer = NULL;
  942. hr = pIADs->QueryInterface(IID_IADsContainer, (void**)&pIADsContainer);
  943. ASSERT(SUCCEEDED(hr));
  944. if (FAILED(hr))
  945. {
  946. ASSERT(FALSE);
  947. return S_OK; // should never happen
  948. }
  949. LPCWSTR lpszAttrString = L"cn=";
  950. hr = HrCreateFixedNameHelper(gsz_nTDSSiteSettings, lpszAttrString, pIADsContainer);
  951. ASSERT(SUCCEEDED(hr));
  952. hr = HrCreateFixedNameHelper(gsz_serversContainer, lpszAttrString, pIADsContainer);
  953. ASSERT(SUCCEEDED(hr));
  954. hr = HrCreateFixedNameHelper(gsz_licensingSiteSettings, lpszAttrString, pIADsContainer);
  955. ASSERT(SUCCEEDED(hr));
  956. pIADsContainer->Release();
  957. LPCWSTR pcszSiteName = pNewADsObjectCreateInfo->GetName();
  958. static bool g_DisplayedWarning = false;
  959. if (!g_DisplayedWarning)
  960. {
  961. g_DisplayedWarning = true;
  962. (void) ReportMessageEx(
  963. pNewADsObjectCreateInfo->GetParentHwnd(),
  964. IDS_NEW_SITE_INFO,
  965. MB_OK | MB_ICONINFORMATION | MB_HELP,
  966. (PVOID*)(&pcszSiteName),
  967. 1,
  968. 0,
  969. L"sag_ADsite_checklist_2.htm"
  970. );
  971. }
  972. return S_OK;
  973. }
  974. HRESULT
  975. HrCreateADsOrganizationalUnit(INOUT CNewADsObjectCreateInfo * pNewADsObjectCreateInfo)
  976. {
  977. ASSERT(pNewADsObjectCreateInfo != NULL);
  978. ASSERT(0 == lstrcmp(L"organizationalUnit", pNewADsObjectCreateInfo->m_pszObjectClass));
  979. CCreateNewOUWizard wiz(pNewADsObjectCreateInfo);
  980. return wiz.DoModal();
  981. }
  982. HRESULT
  983. HrCreateADsGroup(INOUT CNewADsObjectCreateInfo * pNewADsObjectCreateInfo)
  984. {
  985. ASSERT(pNewADsObjectCreateInfo != NULL);
  986. ASSERT(0 == lstrcmp(L"group", pNewADsObjectCreateInfo->m_pszObjectClass));
  987. CCreateNewGroupWizard wiz(pNewADsObjectCreateInfo);
  988. return wiz.DoModal();
  989. }
  990. HRESULT
  991. HrCreateADsContact(INOUT CNewADsObjectCreateInfo * pNewADsObjectCreateInfo)
  992. {
  993. ASSERT(pNewADsObjectCreateInfo != NULL);
  994. ASSERT(0 == lstrcmp(L"contact", pNewADsObjectCreateInfo->m_pszObjectClass));
  995. CCreateNewContactWizard wiz(pNewADsObjectCreateInfo);
  996. return wiz.DoModal();
  997. }
  998. /////////////////////////////////////////////////////////////////////
  999. // HrCreateADsSimpleObject()
  1000. //
  1001. // Create a simple object which "cn" is the
  1002. // only mandatory attribute.
  1003. //
  1004. // IMPLEMENTATION NOTES
  1005. // Invoke a dialog asking for the cannonical name.
  1006. //
  1007. HRESULT HrCreateADsSimpleObject(INOUT CNewADsObjectCreateInfo * pNewADsObjectCreateInfo)
  1008. {
  1009. ASSERT(pNewADsObjectCreateInfo != NULL);
  1010. CCreateNewObjectCnWizard wiz(pNewADsObjectCreateInfo);
  1011. return wiz.DoModal();
  1012. } // HrCreateADsSimpleObject()
  1013. /////////////////////////////////////////////////////////////////////
  1014. // HrCreateADsObjectGenericWizard()
  1015. //
  1016. // Create an object invoking a "Generic Create" wizard.
  1017. // The wizard will have as many pages as the number of mandatory attributes.
  1018. //
  1019. // INTERFACE NOTES
  1020. // This routine must have the same interface as PFn_HrCreateADsObject().
  1021. //
  1022. // IMPLEMENTATION NOTES
  1023. // The wizard will look into the Directory Schema and determine what are
  1024. // the mandatory attributes.
  1025. //
  1026. // REMARKS
  1027. // Although the wizard is the most versatile tool to create a new
  1028. // object, it is the least user-friendly way of doing so. The wizard
  1029. // has no understanding how the attributes relates. Therefore it
  1030. // is suggested to provide your own HrCreateADs*() routine to provide
  1031. // a friendlier dialog to the user.
  1032. //
  1033. HRESULT
  1034. HrCreateADsObjectGenericWizard(INOUT CNewADsObjectCreateInfo * pNewADsObjectCreateInfo)
  1035. {
  1036. ASSERT(pNewADsObjectCreateInfo != NULL);
  1037. // cannot have a Generic Wizard when running as standalone object
  1038. ASSERT(!pNewADsObjectCreateInfo->IsStandaloneUI());
  1039. if (pNewADsObjectCreateInfo->IsStandaloneUI())
  1040. return E_INVALIDARG;
  1041. CCreateNewObjectGenericWizard dlg;
  1042. if (dlg.FDoModal(INOUT pNewADsObjectCreateInfo))
  1043. return S_OK;
  1044. return S_FALSE;
  1045. } // HrCreateADsObjectGenericWizard()
  1046. /////////////////////////////////////////////////////////////////////
  1047. // HrCreateADsObjectOverride()
  1048. //
  1049. // handler for object creation using a replacement dialog
  1050. HRESULT
  1051. HrCreateADsObjectOverride(INOUT CNewADsObjectCreateInfo* pNewADsObjectCreateInfo)
  1052. {
  1053. BOOL bHandled = FALSE;
  1054. HRESULT hr = E_INVALIDARG;
  1055. if (!pNewADsObjectCreateInfo->IsStandaloneUI())
  1056. {
  1057. // try to create the dialog creation handler (full UI replacement)
  1058. // this functionality is not exposed by the standalone UI
  1059. IDsAdminCreateObj* pCreateObj = NULL;
  1060. hr = ::CoCreateInstance(pNewADsObjectCreateInfo->GetCreateInfo()->clsidWizardPrimaryPage,
  1061. NULL, CLSCTX_INPROC_SERVER,
  1062. IID_IDsAdminCreateObj, (void**)&pCreateObj);
  1063. if (SUCCEEDED(hr))
  1064. {
  1065. // try to initialize handler
  1066. hr = pCreateObj->Initialize(pNewADsObjectCreateInfo->m_pIADsContainer,
  1067. pNewADsObjectCreateInfo->GetCopyFromObject(),
  1068. pNewADsObjectCreateInfo->m_pszObjectClass);
  1069. if (SUCCEEDED(hr))
  1070. {
  1071. // execute call for creation
  1072. IADs* pADsObj = NULL;
  1073. bHandled = TRUE;
  1074. hr = pCreateObj->CreateModal(pNewADsObjectCreateInfo->GetParentHwnd(), &pADsObj);
  1075. // can have S_OK, S_FALSE, and error
  1076. if ((hr == S_OK) && pADsObj != NULL)
  1077. {
  1078. // hold to the returned, newly created object
  1079. pNewADsObjectCreateInfo->SetIADsPtr(pADsObj); // it will addref
  1080. pADsObj->Release();
  1081. }
  1082. }
  1083. pCreateObj->Release();
  1084. }
  1085. } // not standalone UI
  1086. // check if the dialog creation handler was properly called
  1087. if (bHandled)
  1088. return hr;
  1089. // try to create a primary extension handler (partial UI replacement)
  1090. CCreateNewObjectWizardBase wiz(pNewADsObjectCreateInfo);
  1091. hr = wiz.InitPrimaryExtension();
  1092. if (SUCCEEDED(hr))
  1093. {
  1094. bHandled = TRUE;
  1095. hr = wiz.DoModal();
  1096. }
  1097. // check if the dialog creation handler was properly called
  1098. if (bHandled)
  1099. return hr;
  1100. // The handler failed, need to recover, trying our internal creation UI
  1101. PFn_HrCreateADsObject pfnCreateObject = NULL;
  1102. PVOID pVoid = NULL;
  1103. // we try to find a better handler than the generic wizard
  1104. // by looking in our table
  1105. if (!FindHandlerFunction(pNewADsObjectCreateInfo->m_pszObjectClass,
  1106. &pfnCreateObject, &pVoid))
  1107. {
  1108. // failed any match
  1109. if (pNewADsObjectCreateInfo->IsStandaloneUI())
  1110. {
  1111. // cannot have generic wizard on standalone UI
  1112. return E_INVALIDARG;
  1113. }
  1114. else
  1115. {
  1116. // set the default to point to the "Generic Create" wizard
  1117. ReportErrorEx(pNewADsObjectCreateInfo->GetParentHwnd(),
  1118. IDS_NO_CREATION_WIZARD,
  1119. S_OK,
  1120. MB_OK | MB_ICONWARNING,
  1121. NULL,
  1122. 0);
  1123. pfnCreateObject = HrCreateADsObjectGenericWizard;
  1124. }
  1125. }
  1126. pNewADsObjectCreateInfo->SetCreationParameter(pVoid);
  1127. ASSERT(pfnCreateObject != NULL);
  1128. // call the function handler as last resort
  1129. return pfnCreateObject(pNewADsObjectCreateInfo);
  1130. } // HrCreateADsObjectOverride()