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.

580 lines
16 KiB

  1. #include "stdafx.h"
  2. #include "compdata.h"
  3. #include "wizinfo.hpp"
  4. #include "ncattr.hpp"
  5. #include "select.h"
  6. //
  7. // defaultObjectCategory of the classes derived from the following should be set
  8. // to defaultObjectCategory of the parent class.
  9. //
  10. // the first column contains class ldap names,
  11. // the second contains their corresponding OIDs (in case the user specifies them)
  12. const TCHAR * rgszSpecialClassesLdapNames[] = {
  13. USER_CLASS_NAME,
  14. GROUP_CLASS_NAME,
  15. COMPUTER_CLASS_NAME,
  16. PRINTER_CLASS_NAME,
  17. TEXT("volume"),
  18. TEXT("contact"),
  19. NULL
  20. };
  21. // must match rgszSpecialClassesLdapNames[].
  22. const TCHAR * rgszSpecialClassesOIDs[] = {
  23. TEXT("1.2.840.113556.1.5.9"), // USER_CLASS_NAME
  24. TEXT("1.2.840.113556.1.5.8"), // GROUP_CLASS_NAME
  25. TEXT("1.2.840.113556.1.3.30"), // COMPUTER_CLASS_NAME
  26. TEXT("1.2.840.113556.1.5.23"), // PRINTER_CLASS_NAME
  27. TEXT("1.2.840.113556.1.5.36"), // TEXT("volume")
  28. TEXT("1.2.840.113556.1.5.15"), // TEXT("contact")
  29. NULL
  30. };
  31. const DWORD NewClassAttributesPage::help_map[] =
  32. {
  33. IDC_MANDATORY_LIST, IDH_CLASS_MMB_MANDATORY_ATTRIBUTES,
  34. IDC_MANDATORY_ADD, IDH_CLASS_MMB_MANDATORY_ADD,
  35. IDC_MANDATORY_REMOVE, IDH_CLASS_MMB_MANDATORY_REMOVE,
  36. IDC_OPTIONAL_LIST, IDH_CLASS_MMB_OPTIONAL_ATTRIBUTES,
  37. IDC_OPTIONAL_ADD, IDH_CLASS_MMB_OPTIONAL_ADD,
  38. IDC_OPTIONAL_REMOVE, IDH_CLASS_MMB_OPTIONAL_REMOVE,
  39. 0, 0
  40. };
  41. BEGIN_MESSAGE_MAP(NewClassAttributesPage, CPropertyPage)
  42. ON_BN_CLICKED(IDC_OPTIONAL_ADD, OnButtonOptionalAdd)
  43. ON_BN_CLICKED(IDC_OPTIONAL_REMOVE, OnButtonOptionalRemove)
  44. ON_BN_CLICKED(IDC_MANDATORY_ADD, OnButtonMandatoryAdd)
  45. ON_BN_CLICKED(IDC_MANDATORY_REMOVE, OnButtonMandatoryRemove)
  46. ON_LBN_SELCHANGE(IDC_MANDATORY_LIST,OnMandatorySelChange)
  47. ON_LBN_SELCHANGE(IDC_OPTIONAL_LIST, OnOptionalSelChange)
  48. ON_MESSAGE(WM_HELP, OnHelp)
  49. ON_MESSAGE(WM_CONTEXTMENU, OnContextHelp)
  50. END_MESSAGE_MAP()
  51. NewClassAttributesPage::NewClassAttributesPage(
  52. CreateClassWizardInfo* wi,
  53. ComponentData* cd)
  54. :
  55. CPropertyPage(IDD_CREATE_CLASS_ATTRIBUTES),
  56. wiz_info(*wi),
  57. parent_ComponentData(*cd)
  58. {
  59. }
  60. BOOL
  61. NewClassAttributesPage::OnInitDialog()
  62. {
  63. // This calls must be done before DDX binding
  64. listbox_mandatory.InitType( &parent_ComponentData,
  65. SELECT_ATTRIBUTES,
  66. IDC_MANDATORY_REMOVE
  67. );
  68. listbox_optional.InitType( &parent_ComponentData,
  69. SELECT_ATTRIBUTES,
  70. IDC_OPTIONAL_REMOVE
  71. );
  72. CPropertyPage::OnInitDialog();
  73. return FALSE; // return TRUE unless you set the focus to a control
  74. // EXCEPTION: OCX Property Pages should return FALSE
  75. }
  76. void
  77. NewClassAttributesPage::OnOK()
  78. {
  79. CPropertyPage::OnOK();
  80. }
  81. BOOL
  82. NewClassAttributesPage::OnKillActive()
  83. {
  84. if (saveAndValidate())
  85. {
  86. // allow loss of focus
  87. return TRUE;
  88. }
  89. return FALSE;
  90. }
  91. bool
  92. NewClassAttributesPage::saveAndValidate()
  93. {
  94. // save settings
  95. wiz_info.strlistMandatory.RemoveAll();
  96. HRESULT hr =
  97. RetrieveEditItemsWithExclusions(
  98. listbox_mandatory,
  99. wiz_info.strlistMandatory,
  100. 0);
  101. ASSERT(SUCCEEDED(hr));
  102. wiz_info.strlistOptional.RemoveAll();
  103. hr =
  104. RetrieveEditItemsWithExclusions(
  105. listbox_optional,
  106. wiz_info.strlistOptional,
  107. 0);
  108. ASSERT(SUCCEEDED(hr));
  109. // nothing to validate...
  110. return true;
  111. }
  112. BOOL
  113. NewClassAttributesPage::OnSetActive()
  114. {
  115. OnMandatorySelChange();
  116. OnOptionalSelChange();
  117. CPropertySheet* parent = (CPropertySheet*) GetParent();
  118. parent->SetWizardButtons(PSWIZB_BACK | PSWIZB_FINISH);
  119. return TRUE;
  120. }
  121. BOOL
  122. NewClassAttributesPage::OnWizardFinish()
  123. {
  124. if (!saveAndValidate())
  125. {
  126. return FALSE;
  127. }
  128. // Create the class object. We do the create here (instead of at the point
  129. // where DoModal is invoked) because we want the wizard to remain if the
  130. // create fails for some reason.
  131. CThemeContextActivator activator;
  132. CWaitCursor wait;
  133. HRESULT hr = S_OK;
  134. SchemaObject* new_object = 0;
  135. do
  136. {
  137. // bind to the schema container
  138. CString schema_path;
  139. parent_ComponentData.GetBasePathsInfo()->GetSchemaPath(schema_path);
  140. CComPtr<IADsContainer> schema_container;
  141. hr = SchemaOpenObject(
  142. // ADSI guys don't grok const.
  143. const_cast<PWSTR>(static_cast<PCWSTR>(schema_path)),
  144. IID_IADsContainer,
  145. reinterpret_cast<void**>(&schema_container));
  146. BREAK_ON_FAILED_HRESULT(hr);
  147. // Get Relative Name
  148. CString strRelativeName;
  149. parent_ComponentData.GetSchemaObjectPath( wiz_info.cn, strRelativeName, ADS_FORMAT_LEAF );
  150. // create the class object
  151. CComPtr<IDispatch> dispatch;
  152. hr =
  153. schema_container->Create(
  154. CComBSTR(g_ClassFilter),
  155. CComBSTR(strRelativeName),
  156. &dispatch);
  157. BREAK_ON_FAILED_HRESULT(hr);
  158. CComPtr<IADs> iads;
  159. hr =
  160. dispatch->QueryInterface(IID_IADs, reinterpret_cast<void**>(&iads));
  161. BREAK_ON_FAILED_HRESULT(hr);
  162. //
  163. // populate the class object's properties
  164. //
  165. // OID
  166. {
  167. CComVariant value(CComBSTR(wiz_info.oid));
  168. hr = iads->Put(CComBSTR(g_GlobalClassID), value);
  169. BREAK_ON_FAILED_HRESULT(hr);
  170. }
  171. // class type
  172. {
  173. CComVariant value(wiz_info.type + 1);
  174. hr = iads->Put(CComBSTR(g_ObjectClassCategory), value);
  175. BREAK_ON_FAILED_HRESULT(hr);
  176. }
  177. // description
  178. if (!wiz_info.description.IsEmpty())
  179. {
  180. CComVariant value(CComBSTR(wiz_info.description));
  181. hr = iads->Put(CComBSTR(g_Description), value);
  182. BREAK_ON_FAILED_HRESULT(hr);
  183. }
  184. // default security descriptor
  185. {
  186. // authenticated users - full access
  187. // system - full control
  188. // domain admins - full control
  189. static const PWSTR defsd =
  190. L"D:(A;;RPWPCRCCDCLCLOLORCWOWDSDDTDTSW;;;DA)"
  191. L"(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;;RPLCLORC;;;AU)";
  192. CComVariant value(defsd);
  193. hr = iads->Put(CComBSTR(g_DefaultAcl), value);
  194. BREAK_ON_FAILED_HRESULT(hr);
  195. }
  196. // LDAP display name
  197. if (!wiz_info.ldapDisplayName.IsEmpty())
  198. {
  199. CComVariant value(wiz_info.ldapDisplayName);
  200. hr = iads->Put(CComBSTR(g_DisplayName), value);
  201. BREAK_ON_FAILED_HRESULT(hr);
  202. }
  203. // parent class
  204. if (!wiz_info.parentClass.IsEmpty())
  205. {
  206. PCWSTR pstr = NULL;
  207. SchemaObject * parent_class =
  208. parent_ComponentData.g_SchemaCache.LookupSchemaObject(
  209. wiz_info.parentClass,
  210. SCHMMGMT_CLASS);
  211. if( parent_class )
  212. {
  213. pstr = parent_class->oid;
  214. }
  215. else
  216. {
  217. pstr = wiz_info.parentClass;
  218. }
  219. CComVariant value(pstr);
  220. hr = iads->Put(CComBSTR(g_SubclassOf), value);
  221. if( FAILED(hr) )
  222. {
  223. parent_ComponentData.g_SchemaCache.ReleaseRef(parent_class);
  224. break;
  225. }
  226. // check if parent is one of the magic classes whose defaultObjectCategory
  227. // should be the same as the parent.
  228. BOOL fIsSpecialParent = FALSE;
  229. ASSERT( sizeof(rgszSpecialClassesOIDs) == sizeof(rgszSpecialClassesLdapNames) );
  230. if( parent_class )
  231. {
  232. fIsSpecialParent = IsInList( rgszSpecialClassesLdapNames,
  233. parent_class->ldapDisplayName );
  234. }
  235. else
  236. {
  237. UINT uIndex = 0;
  238. // lookup by LDAP failed. check if parent is specified by OID
  239. fIsSpecialParent = IsInList( rgszSpecialClassesOIDs,
  240. wiz_info.parentClass,
  241. &uIndex );
  242. if( fIsSpecialParent )
  243. {
  244. parent_class = parent_ComponentData.g_SchemaCache.LookupSchemaObject(
  245. rgszSpecialClassesLdapNames[uIndex],
  246. SCHMMGMT_CLASS);
  247. ASSERT( parent_class ); // the schema cache must contain well known classes.
  248. }
  249. }
  250. // if this is a special class, get parent's defaultObjectCategory.
  251. if( fIsSpecialParent && parent_class )
  252. {
  253. CString szParentPath;
  254. IADs * pIADsParentObject = NULL;
  255. VARIANT adsValue;
  256. VariantInit( &adsValue );
  257. do { // one pass do-while loop to help with error handling
  258. // if any errors occure, ignore them.
  259. // Find out the defaultObjectCategory of the parent class & use it
  260. parent_ComponentData.GetSchemaObjectPath( parent_class->commonName, szParentPath );
  261. if( szParentPath.IsEmpty() )
  262. break;
  263. hr = SchemaOpenObject( const_cast<LPWSTR>((LPCWSTR)szParentPath),
  264. IID_IADs,
  265. (void **)&pIADsParentObject );
  266. if ( !pIADsParentObject || FAILED(hr) )
  267. {
  268. DoErrMsgBox( ::GetActiveWindow(), TRUE, GetErrorMessage(hr) );
  269. hr = NULL;
  270. break;
  271. }
  272. // NTRAID#NTBUG9-540866-2002/02/13-dantra-Schema Manager: passing WCHAR * instead of BSTR to method requiring a BSTR
  273. hr = pIADsParentObject->Get( const_cast<BSTR>((LPCTSTR)g_DefaultCategory),
  274. &adsValue );
  275. if( FAILED(hr) )
  276. {
  277. DoErrMsgBox( ::GetActiveWindow(), TRUE, GetErrorMessage(hr,TRUE) );
  278. hr = NULL;
  279. break;
  280. }
  281. ASSERT( adsValue.vt == VT_BSTR );
  282. // preserve hr so that save fails after this loop
  283. // NTRAID#NTBUG9-540866-2002/02/13-dantra-Schema Manager: passing WCHAR * instead of BSTR to method requiring a BSTR
  284. hr = iads->Put( const_cast<BSTR>((LPCTSTR)g_DefaultCategory),
  285. adsValue );
  286. } while (FALSE);
  287. VariantClear( &adsValue );
  288. parent_ComponentData.g_SchemaCache.ReleaseRef(parent_class);
  289. if( pIADsParentObject )
  290. pIADsParentObject->Release();
  291. BREAK_ON_FAILED_HRESULT(hr);
  292. }
  293. else
  294. {
  295. parent_ComponentData.g_SchemaCache.ReleaseRef(parent_class);
  296. }
  297. }
  298. // optional attributes
  299. if (!wiz_info.strlistOptional.IsEmpty())
  300. {
  301. VARIANT value;
  302. ::VariantInit(&value);
  303. hr = StringListToVariant(value, wiz_info.strlistOptional);
  304. // NTRAID#NTBUG9-543624-2002/02/15-dantra-Result of StringListToVariant being ignored resulting in call to IADs::PutEx with incorrect data
  305. BREAK_ON_FAILED_HRESULT(hr);
  306. // NTRAID#NTBUG9-540866-2002/02/13-dantra-Schema Manager: passing WCHAR * instead of BSTR to method requiring a BSTR
  307. hr = iads->PutEx( ADS_PROPERTY_UPDATE, CComBSTR(g_MayContain), value);
  308. ::VariantClear(&value);
  309. BREAK_ON_FAILED_HRESULT(hr);
  310. }
  311. // mandatory attributes
  312. if (!wiz_info.strlistMandatory.IsEmpty())
  313. {
  314. VARIANT value;
  315. ::VariantInit(&value);
  316. hr = StringListToVariant(value, wiz_info.strlistMandatory);
  317. // don't break: plod onward.
  318. // NTRAID#NTBUG9-543624-2002/02/15-dantra-Result of StringListToVariant being ignored resulting in call to IADs::PutEx with incorrect data
  319. BREAK_ON_FAILED_HRESULT(hr);
  320. // NTRAID#NTBUG9-540866-2002/02/13-dantra-Schema Manager: passing WCHAR * instead of BSTR to method requiring a BSTR
  321. hr = iads->PutEx( ADS_PROPERTY_UPDATE, CComBSTR(g_MustContain), value);
  322. ::VariantClear(&value);
  323. BREAK_ON_FAILED_HRESULT(hr);
  324. }
  325. // commit the create
  326. hr = iads->SetInfo();
  327. BREAK_ON_FAILED_HRESULT(hr);
  328. // if there was no ldap name, and it worked, cn was used as ldap name
  329. if( wiz_info.ldapDisplayName.IsEmpty() )
  330. {
  331. CComVariant value;
  332. hr = iads->Get(CComBSTR(g_DisplayName), &value);
  333. ASSERT( SUCCEEDED(hr) ); // should be there!!!
  334. if( SUCCEEDED(hr) )
  335. {
  336. ASSERT( value.vt == VT_BSTR );
  337. wiz_info.ldapDisplayName = value.bstrVal;
  338. }
  339. }
  340. // create a cache entry for the new class object
  341. new_object = new SchemaObject;
  342. new_object->schemaObjectType = SCHMMGMT_CLASS;
  343. new_object->commonName = wiz_info.cn;
  344. new_object->ldapDisplayName = wiz_info.ldapDisplayName;
  345. new_object->oid = wiz_info.oid;
  346. new_object->dwClassType = wiz_info.type + 1;
  347. new_object->subClassOf = wiz_info.parentClass;
  348. ListEntry* new_list = 0;
  349. hr =
  350. StringListToColumnList(
  351. &parent_ComponentData,
  352. wiz_info.strlistOptional,
  353. &new_list);
  354. BREAK_ON_FAILED_HRESULT(hr);
  355. new_object->mayContain = new_list;
  356. new_list = 0;
  357. hr =
  358. StringListToColumnList(
  359. &parent_ComponentData,
  360. wiz_info.strlistMandatory,
  361. &new_list);
  362. BREAK_ON_FAILED_HRESULT(hr);
  363. new_object->mustContain = new_list;
  364. // stuff the new cache entry into the cache
  365. hr =
  366. parent_ComponentData.g_SchemaCache.InsertSchemaObject(new_object);
  367. BREAK_ON_FAILED_HRESULT(hr);
  368. hr =
  369. parent_ComponentData.g_SchemaCache.InsertSortedSchemaObject(new_object);
  370. BREAK_ON_FAILED_HRESULT(hr);
  371. // insert the new cache object into the snapin ui
  372. parent_ComponentData.g_ClassCookieList.InsertSortedDisplay(
  373. &parent_ComponentData,
  374. new_object);
  375. }
  376. while (0);
  377. if (FAILED(hr))
  378. {
  379. delete new_object;
  380. if (hr == ADS_EXTENDED_ERROR)
  381. {
  382. DoExtErrMsgBox();
  383. }
  384. else
  385. {
  386. CString title;
  387. title.LoadString(AFX_IDS_APP_TITLE);
  388. CString error_text;
  389. CString name;
  390. HRESULT last_ads_hr = GetLastADsError(hr, error_text, name);
  391. if (HRESULT_CODE(last_ads_hr) == ERROR_DS_INVALID_LDAP_DISPLAY_NAME)
  392. {
  393. error_text.LoadString(IDS_LDAPDISPLAYNAME_FORMAT_ERROR);
  394. }
  395. else
  396. {
  397. error_text = GetErrorMessage(hr,TRUE);
  398. }
  399. ::MessageBox(
  400. m_hWnd,
  401. error_text,
  402. title,
  403. MB_OK | MB_ICONSTOP);
  404. }
  405. return FALSE;
  406. }
  407. // end the wizard
  408. // @@ call base::OnWizardFinish()?
  409. return TRUE;
  410. }
  411. void
  412. NewClassAttributesPage::OnButtonOptionalAdd()
  413. {
  414. listbox_optional.AddNewObjectToList();
  415. }
  416. void
  417. NewClassAttributesPage::OnButtonMandatoryAdd()
  418. {
  419. listbox_mandatory.AddNewObjectToList();
  420. }
  421. void
  422. NewClassAttributesPage::OnButtonOptionalRemove()
  423. {
  424. listbox_optional.RemoveListBoxItem();
  425. }
  426. void
  427. NewClassAttributesPage::OnButtonMandatoryRemove()
  428. {
  429. listbox_mandatory.RemoveListBoxItem();
  430. }
  431. void
  432. NewClassAttributesPage::OnMandatorySelChange()
  433. {
  434. listbox_mandatory.OnSelChange();
  435. }
  436. void
  437. NewClassAttributesPage::OnOptionalSelChange()
  438. {
  439. listbox_optional.OnSelChange();
  440. }
  441. void
  442. NewClassAttributesPage::DoDataExchange(CDataExchange *pDX)
  443. {
  444. CPropertyPage::DoDataExchange(pDX);
  445. DDX_Control(pDX, IDC_MANDATORY_LIST, listbox_mandatory);
  446. DDX_Control(pDX, IDC_OPTIONAL_LIST, listbox_optional);
  447. }