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.

1265 lines
34 KiB

  1. #include "stdafx.h"
  2. #include "compdata.h"
  3. #include "cmponent.h"
  4. #include "attrgen.hpp"
  5. #include "resource.h"
  6. #include "dataobj.h"
  7. const TCHAR szUserClass[] = USER_CLASS_NAME ;
  8. // disable User Copy for the following list of attributes
  9. const TCHAR * rgszExclClass[] = { _T("cn"), _T("displayName"),
  10. _T("sAMAccountName"), _T("userAccountControl"),
  11. _T("userParameters"), _T("userPrincipalName"),
  12. NULL };
  13. //
  14. // The following table is copied from dirsync\ldifds\ldifldap\samrestrict.h
  15. //
  16. // CLASS_USER, SampUserObjectType (ldapdisplayname: user)
  17. //
  18. PCWSTR rgszExclClass2[] = { // user[] = {
  19. L"memberOf", // SAMP_USER_GROUPS, ATT_MEMBER
  20. L"dBCSPwd", // SAMP_USER_DBCS_PWD, ATT_DBCS_PWD
  21. L"ntPwdHistory", // SAMP_USER_NT_PWD_HISTORY, ATT_NT_PWD_HISTORY
  22. L"lmPwdHistory", // SAMP_USER_LM_PWD_HISTORY, ATT_LM_PWD_HISTORY
  23. L"lastLogon", // SAMP_FIXED_USER_LAST_LOGON, ATT_LAST_LOGON
  24. L"lastLogoff", // SAMP_FIXED_USER_LAST_LOGOFF, ATT_LAST_LOGOFF
  25. L"badPasswordTime", // SAMP_FIXED_USER_LAST_BAD_PASSWORD_TIME,
  26. // ATT_BAD_PASSWORD_TIME
  27. L"rid", // SAMP_FIXED_USER_USERID, ATT_RID
  28. L"badPwdCount", // SAMP_FIXED_USER_BAD_PWD_COUNT,
  29. // ATT_BAD_PWD_COUNT
  30. L"logonCount", // SAMP_FIXED_USER_LOGON_COUNT, ATT_LOGON_COUNT
  31. L"sAMAccountType", // SAMP_USER_ACCOUNT_TYPE, ATT_SAM_ACCOUNT_TYPE
  32. L"supplementalCredentials", // SAMP_FIXED_USER_SUPPLEMENTAL_CREDENTIALS,
  33. // ATT_SUPPLEMENTAL_CREDENTIALS
  34. L"objectSid", // not in mappings.c, but still required!,
  35. // ATT_OBJECT_SID
  36. L"pwdLastSet",
  37. NULL
  38. };
  39. const TCHAR szTopClass[] = _T("Top");
  40. const CDialogControlsInfo ctrls[] =
  41. {
  42. { IDC_ATTRIB_GENERAL_DESCRIPTION_EDIT, g_Description, TRUE },
  43. { IDC_ATTRIB_GENERAL_MIN_EDIT, g_RangeLower, TRUE },
  44. { IDC_ATTRIB_GENERAL_MAX_EDIT, g_RangeUpper, TRUE },
  45. { IDC_ATTRIB_GENERAL_DISPLAYABLE_CHECK, g_ShowInAdvViewOnly, FALSE },
  46. { IDC_ATTRIB_GENERAL_DEACTIVATE, g_isDefunct, FALSE },
  47. { IDC_ATTRIB_GENERAL_INDEX_CHECK, g_IndexFlag, FALSE },
  48. { IDC_ATTRIB_GENERAL_REPLICATED, g_GCReplicated, FALSE },
  49. { IDC_ATTRIB_GENERAL_CPYATTR_CHECK, g_IndexFlag, FALSE },
  50. { IDC_ATTRIB_GENERAL_ANR_CHECK, g_IndexFlag, FALSE },
  51. { IDC_ATTRIB_GENERAL_CONTAINERIZED_INDEX_CHECK, g_IndexFlag, FALSE},
  52. } ;
  53. const DWORD AttributeGeneralPage::help_map[] =
  54. {
  55. IDI_ATTRIBUTE, NO_HELP,
  56. IDC_ATTRIB_GENERAL_NAME_STATIC, NO_HELP,
  57. IDC_ATTRIB_GENERAL_DESCRIPTION_EDIT, IDH_ATTRIB_GENERAL_DESCRIPTION_EDIT,
  58. IDC_ATTRIB_GENERAL_LDN, IDH_ATTRIB_GENERAL_LDN,
  59. IDC_ATTRIB_GENERAL_OID_EDIT, IDH_ATTRIB_GENERAL_OID_EDIT,
  60. IDC_ATTRIB_GENERAL_VALUE_STATIC, NO_HELP,
  61. IDC_ATTRIB_GENERAL_SYNTAX_EDIT, IDH_ATTRIB_GENERAL_SYNTAX_EDIT,
  62. IDC_ATTRIB_GENERAL_MIN_EDIT, IDH_ATTRIB_GENERAL_MIN_EDIT,
  63. IDC_ATTRIB_GENERAL_MAX_EDIT, IDH_ATTRIB_GENERAL_MAX_EDIT,
  64. IDC_ATTRIB_GENERAL_DISPLAYABLE_CHECK, IDH_ATTRIB_GENERAL_DISPLAYABLE_CHECK,
  65. IDC_ATTRIB_GENERAL_DEACTIVATE, IDH_ATTRIB_DEACTIVATE,
  66. IDC_ATTRIB_GENERAL_INDEX_CHECK, IDH_ATTRIB_GENERAL_INDEX_CHECK,
  67. IDC_ATTRIB_GENERAL_CONTAINERIZED_INDEX_CHECK, IDH_ATTRIB_GENERAL_CONTAINERIZED_INDEX_CHECK,
  68. IDC_ATTRIB_GENERAL_ANR_CHECK, IDH_ATTRIB_GENERAL_ANR_CHECK,
  69. IDC_ATTRIB_GENERAL_REPLICATED, IDH_REPLICATED,
  70. IDC_ATTRIB_GENERAL_CPYATTR_CHECK, IDH_ATTRIB_GENERAL_CPYATTR_CHECK,
  71. IDC_ATTRIB_GENERAL_SYSCLASS_STATIC, NO_HELP,
  72. 0, 0
  73. };
  74. // returns state of bit n
  75. inline
  76. bool
  77. getbit(const DWORD& bits, int n)
  78. {
  79. return (bits & (1 << n)) ? true : false;
  80. }
  81. // sets bit n to 1
  82. inline
  83. void
  84. setbit(DWORD& bits, int n)
  85. {
  86. bits |= (1 << n);
  87. }
  88. // sets bit n to 0
  89. inline
  90. void
  91. clearbit(DWORD& bits, int n)
  92. {
  93. bits &= ~(1 << n);
  94. }
  95. //
  96. // Attribute property sheet routines.
  97. //
  98. BEGIN_MESSAGE_MAP( AttributeGeneralPage, CDialog )
  99. ON_MESSAGE(WM_HELP, OnHelp)
  100. ON_MESSAGE(WM_CONTEXTMENU, OnContextHelp)
  101. ON_BN_CLICKED(IDC_ATTRIB_GENERAL_INDEX_CHECK, OnIndexClick)
  102. ON_BN_CLICKED(IDC_ATTRIB_GENERAL_DEACTIVATE, OnDeactivateClick)
  103. END_MESSAGE_MAP()
  104. AttributeGeneralPage::AttributeGeneralPage(
  105. Component* pResultControl,
  106. LPDATAOBJECT lpDataObject)
  107. :
  108. CPropertyPage( IDD_ATTRIB_GENERAL ),
  109. pCookie( NULL ),
  110. pIADsObject( NULL ),
  111. pObject( NULL),
  112. lpResultDataObject( lpDataObject ),
  113. pComponent( pResultControl ),
  114. fDataLoaded( FALSE ),
  115. Displayable( TRUE ),
  116. DDXDisplayable( TRUE ),
  117. search_flags(0),
  118. DDXIndexed( FALSE ),
  119. DDXANR( FALSE ),
  120. DDXCopyOnDuplicate( FALSE ),
  121. Defunct( FALSE ),
  122. DDXDefunct( FALSE ),
  123. ReplicatedToGC( FALSE ),
  124. DDXReplicatedToGC( FALSE ),
  125. DDXContainerIndexed( FALSE ),
  126. m_editLowerRange( CParsedEdit::EDIT_TYPE_UINT32 ),
  127. m_editUpperRange( CParsedEdit::EDIT_TYPE_UINT32 )
  128. {
  129. }
  130. BOOL
  131. AttributeGeneralPage::OnSetActive()
  132. {
  133. // If pIADsObject is NULL, close dialog box
  134. if( CPropertyPage::OnSetActive() )
  135. {
  136. if ( !pIADsObject )
  137. {
  138. return FALSE;
  139. }
  140. else
  141. {
  142. // always enable the Apply button
  143. SetModified(TRUE);
  144. return TRUE;
  145. }
  146. }
  147. else
  148. return FALSE;
  149. }
  150. AttributeGeneralPage::~AttributeGeneralPage(
  151. )
  152. {
  153. ComponentData& Scope = pComponent->QueryComponentDataRef();
  154. //
  155. // Always make sure we free the IADs object.
  156. //
  157. if ( pIADsObject ) {
  158. pIADsObject->Release();
  159. pIADsObject = NULL;
  160. }
  161. //
  162. // And release the cache.
  163. //
  164. if ( pObject ) {
  165. Scope.g_SchemaCache.ReleaseRef( pObject );
  166. }
  167. }
  168. BOOL
  169. AttributeGeneralPage::OnInitDialog()
  170. {
  171. CPropertyPage::OnInitDialog();
  172. ASSERT( GetDlgItem(IDC_ATTRIB_GENERAL_DESCRIPTION_EDIT) );
  173. ( static_cast<CEdit *>( GetDlgItem(IDC_ATTRIB_GENERAL_DESCRIPTION_EDIT) ) )
  174. -> LimitText( 1024 ) ;
  175. m_editLowerRange.SubclassEdit(IDC_ATTRIB_GENERAL_MIN_EDIT, this, cchMinMaxRange);
  176. m_editUpperRange.SubclassEdit(IDC_ATTRIB_GENERAL_MAX_EDIT, this, cchMinMaxRange);
  177. return TRUE;
  178. }
  179. void
  180. AttributeGeneralPage::Load(
  181. Cookie& CookieRef
  182. ) {
  183. //
  184. // Store the cookie object pointer. Everything
  185. // else gets loaded when the page is displayed.
  186. //
  187. pCookie = &CookieRef;
  188. return;
  189. }
  190. BOOL
  191. AttributeGeneralPage::OnApply(
  192. VOID
  193. ) {
  194. HRESULT hr;
  195. VARIANT AdsValue;
  196. BOOL fChangesMade = FALSE;
  197. BOOL fRangeChange = FALSE;
  198. BOOL fApplyAbort = FALSE; // stop later saves
  199. BOOL fApplyFailed = FALSE; // should not close the box
  200. DWORD dwRange;
  201. // Enable hourglass
  202. CWaitCursor wait;
  203. //
  204. // We have to flush the IADS property cache if we
  205. // have a failure so later operations won't fail because
  206. // of a bad cached attribute.
  207. //
  208. IADsPropertyList *pPropertyList;
  209. hr = pIADsObject->QueryInterface( IID_IADsPropertyList,
  210. reinterpret_cast<void**>(&pPropertyList) );
  211. if ( FAILED( hr ) ) {
  212. pPropertyList = NULL;
  213. fApplyAbort = TRUE;
  214. }
  215. //
  216. // Check to see if something we cared about changed.
  217. // We care about Description, Min, Max, Indexed,
  218. // Defunct, ReplicatedToGC, and Displayable.
  219. //
  220. AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
  221. VariantInit( &AdsValue );
  222. //
  223. // Defunct -- in case it was deactivated, activate the object first
  224. //
  225. if( !fApplyAbort && !DDXDefunct && DDXDefunct != Defunct )
  226. {
  227. hr = ChangeDefunctState( DDXDefunct, Defunct, pPropertyList, fApplyAbort, fApplyFailed );
  228. }
  229. //
  230. // Description
  231. //
  232. if ( !fApplyAbort && DDXDescription != Description ) {
  233. V_VT(&AdsValue) = VT_BSTR;
  234. V_BSTR(&AdsValue) = const_cast<BSTR>((LPCTSTR)DDXDescription);
  235. if ( DDXDescription.IsEmpty() ) {
  236. hr = pIADsObject->PutEx( ADS_PROPERTY_CLEAR,
  237. const_cast<BSTR>((LPCTSTR)g_Description),
  238. AdsValue );
  239. } else {
  240. hr = pIADsObject->Put( const_cast<BSTR>((LPCTSTR)g_Description),
  241. AdsValue );
  242. }
  243. ASSERT( SUCCEEDED( hr ) );
  244. hr = pIADsObject->SetInfo();
  245. if ( SUCCEEDED( hr ) ) {
  246. pObject->description = DDXDescription;
  247. fChangesMade = TRUE;
  248. Description = DDXDescription;
  249. } else {
  250. pPropertyList->PurgePropertyList();
  251. if( ERROR_DS_UNWILLING_TO_PERFORM == HRESULT_CODE(hr) )
  252. {
  253. fApplyFailed = TRUE;
  254. DoErrMsgBox( ::GetActiveWindow(), TRUE, IDS_ERR_EDIT_DESC );
  255. }
  256. else
  257. {
  258. fApplyAbort = TRUE;
  259. DoErrMsgBox( ::GetActiveWindow(), TRUE, GetErrorMessage(hr,TRUE) );
  260. }
  261. }
  262. VariantInit( &AdsValue );
  263. }
  264. //
  265. // Displayable
  266. //
  267. if ( !fApplyAbort && DDXDisplayable != Displayable ) {
  268. V_VT(&AdsValue) = VT_BOOL;
  269. if ( DDXDisplayable ) {
  270. V_BOOL(&AdsValue) = 0;
  271. } else {
  272. V_BOOL(&AdsValue) = -1;
  273. }
  274. hr = pIADsObject->Put(g_ShowInAdvViewOnly, AdsValue);
  275. ASSERT( SUCCEEDED( hr ) );
  276. hr = pIADsObject->SetInfo();
  277. if ( FAILED( hr ) ) {
  278. pPropertyList->PurgePropertyList();
  279. if( ERROR_DS_UNWILLING_TO_PERFORM == HRESULT_CODE(hr) )
  280. {
  281. fApplyFailed = TRUE;
  282. DoErrMsgBox( ::GetActiveWindow(), TRUE, IDS_ERR_EDIT_DISPLAYABLE );
  283. }
  284. else
  285. {
  286. fApplyAbort = TRUE;
  287. DoErrMsgBox( ::GetActiveWindow(), TRUE, GetErrorMessage(hr,TRUE) );
  288. }
  289. }
  290. else
  291. {
  292. Displayable = DDXDisplayable;
  293. }
  294. VariantInit( &AdsValue );
  295. }
  296. //
  297. // ReplicatedToGC
  298. //
  299. if ( !fApplyAbort && DDXReplicatedToGC != ReplicatedToGC ) {
  300. V_VT(&AdsValue) = VT_BOOL;
  301. if ( DDXReplicatedToGC ) {
  302. V_BOOL(&AdsValue) = -1;
  303. } else {
  304. V_BOOL(&AdsValue) = 0;
  305. }
  306. hr = pIADsObject->Put( const_cast<BSTR>((LPCTSTR)g_GCReplicated),
  307. AdsValue );
  308. ASSERT( SUCCEEDED( hr ) );
  309. hr = pIADsObject->SetInfo();
  310. if ( FAILED( hr ) ) {
  311. pPropertyList->PurgePropertyList();
  312. if( ERROR_DS_UNWILLING_TO_PERFORM == HRESULT_CODE(hr) )
  313. {
  314. fApplyFailed = TRUE;
  315. DoErrMsgBox( ::GetActiveWindow(), TRUE, IDS_ERR_EDIT_GC );
  316. }
  317. else
  318. {
  319. fApplyAbort = TRUE;
  320. DoErrMsgBox( ::GetActiveWindow(), TRUE, GetErrorMessage(hr,TRUE) );
  321. }
  322. }
  323. else
  324. {
  325. ReplicatedToGC = DDXReplicatedToGC;
  326. }
  327. VariantInit( &AdsValue );
  328. }
  329. //
  330. // Indexed
  331. //
  332. // make sure ANR is not set when Indexed is unchecked
  333. if( !DDXIndexed )
  334. DDXANR = FALSE;
  335. if( !fApplyAbort &&
  336. (getbit(search_flags, INDEX_BIT_ATTINDEX) != (DDXIndexed ? 1 : 0)
  337. || getbit(search_flags, INDEX_BIT_ANR) != (DDXANR ? 1 : 0)
  338. || getbit(search_flags, INDEX_BIT_COPYONDUPLICATE) != (DDXCopyOnDuplicate ? 1 : 0)
  339. || getbit(search_flags, INDEX_BIT_PDNTATTINDEX) != (DDXContainerIndexed ? 1 : 0)) )
  340. {
  341. DWORD DDXsearch_flags = search_flags;
  342. V_VT(&AdsValue) = VT_I4;
  343. if (DDXIndexed)
  344. setbit(DDXsearch_flags, INDEX_BIT_ATTINDEX);
  345. else
  346. clearbit(DDXsearch_flags, INDEX_BIT_ATTINDEX);
  347. ASSERT( DDXIndexed || !DDXANR );
  348. if (DDXANR)
  349. setbit(DDXsearch_flags, INDEX_BIT_ANR);
  350. else
  351. clearbit(DDXsearch_flags, INDEX_BIT_ANR);
  352. if (DDXCopyOnDuplicate)
  353. setbit(DDXsearch_flags, INDEX_BIT_COPYONDUPLICATE);
  354. else
  355. clearbit(DDXsearch_flags, INDEX_BIT_COPYONDUPLICATE);
  356. if (DDXContainerIndexed)
  357. setbit(DDXsearch_flags, INDEX_BIT_PDNTATTINDEX);
  358. else
  359. clearbit(DDXsearch_flags, INDEX_BIT_PDNTATTINDEX);
  360. V_I4(&AdsValue) = DDXsearch_flags;
  361. hr = pIADsObject->Put( const_cast<BSTR>((LPCTSTR)g_IndexFlag),
  362. AdsValue );
  363. ASSERT( SUCCEEDED( hr ) );
  364. hr = pIADsObject->SetInfo();
  365. if ( FAILED( hr ) ) {
  366. pPropertyList->PurgePropertyList();
  367. if( ERROR_DS_UNWILLING_TO_PERFORM == HRESULT_CODE(hr) )
  368. {
  369. fApplyFailed = TRUE;
  370. DoErrMsgBox( ::GetActiveWindow(), TRUE, IDS_ERR_EDIT_INDEXED );
  371. }
  372. else
  373. {
  374. fApplyAbort = TRUE;
  375. DoErrMsgBox( ::GetActiveWindow(), TRUE, GetErrorMessage(hr,TRUE) );
  376. }
  377. }
  378. else
  379. {
  380. search_flags = DDXsearch_flags;
  381. }
  382. VariantInit( &AdsValue );
  383. }
  384. //
  385. // RangeUpper and RangeLower
  386. // These have to be set together so the server
  387. // range validation works correctly.
  388. //
  389. if ( !fApplyAbort && RangeUpper != DDXRangeUpper ) {
  390. if ( DDXRangeUpper.IsEmpty() ) {
  391. //
  392. // Clear the value.
  393. //
  394. hr = pIADsObject->PutEx( ADS_PROPERTY_CLEAR,
  395. const_cast<BSTR>((LPCTSTR)g_RangeUpper),
  396. AdsValue );
  397. ASSERT( SUCCEEDED( hr ) );
  398. } else {
  399. //
  400. // Store the new value.
  401. //
  402. ASSERT(pObject);
  403. hr = GetSafeSignedDWORDFromString( this, dwRange, DDXRangeUpper,
  404. g_Syntax[ pObject->SyntaxOrdinal ].m_fIsSigned );
  405. ASSERT( S_OK == hr ); // validation should have taken care of min/max stuff
  406. V_VT( &AdsValue ) = VT_I4;
  407. V_I4( &AdsValue ) = dwRange;
  408. hr = pIADsObject->Put( const_cast<BSTR>((LPCTSTR)g_RangeUpper),
  409. AdsValue );
  410. ASSERT( SUCCEEDED( hr ) );
  411. }
  412. fRangeChange = TRUE;
  413. VariantInit( &AdsValue );
  414. }
  415. if ( !fApplyAbort && RangeLower != DDXRangeLower ) {
  416. if ( DDXRangeLower.IsEmpty() ) {
  417. //
  418. // Clear the value.
  419. //
  420. hr = pIADsObject->PutEx( ADS_PROPERTY_CLEAR,
  421. const_cast<BSTR>((LPCTSTR)g_RangeLower),
  422. AdsValue );
  423. ASSERT( SUCCEEDED( hr ) );
  424. } else {
  425. //
  426. // Store the new value.
  427. //
  428. ASSERT(pObject);
  429. hr = GetSafeSignedDWORDFromString( this, dwRange, DDXRangeLower,
  430. g_Syntax[ pObject->SyntaxOrdinal ].m_fIsSigned );
  431. ASSERT( S_OK == hr ); // validation should have taken care of min/max stuff
  432. V_VT( &AdsValue ) = VT_I4;
  433. V_I4( &AdsValue ) = dwRange;
  434. hr = pIADsObject->Put( const_cast<BSTR>((LPCTSTR)g_RangeLower),
  435. AdsValue );
  436. ASSERT( SUCCEEDED( hr ) );
  437. }
  438. fRangeChange = TRUE;
  439. VariantInit( &AdsValue );
  440. }
  441. //
  442. // Actually commit the changes.
  443. //
  444. if ( !fApplyAbort && fRangeChange ) {
  445. hr = pIADsObject->SetInfo();
  446. if ( FAILED( hr ) ) {
  447. pPropertyList->PurgePropertyList();
  448. if( ERROR_DS_UNWILLING_TO_PERFORM == HRESULT_CODE(hr) )
  449. {
  450. fApplyFailed = TRUE;
  451. DoErrMsgBox( ::GetActiveWindow(), TRUE, IDS_ERR_CREATE_MINMAX );
  452. }
  453. else
  454. {
  455. fApplyAbort = TRUE;
  456. DoErrMsgBox( ::GetActiveWindow(), TRUE, GetErrorMessage(hr,TRUE) );
  457. }
  458. }
  459. else
  460. {
  461. RangeLower = DDXRangeLower;
  462. RangeUpper = DDXRangeUpper;
  463. }
  464. }
  465. //
  466. // Defunct -- in case it was active, deactivate the object after we are done update
  467. //
  468. if( !fApplyAbort && DDXDefunct && DDXDefunct != Defunct )
  469. {
  470. hr = ChangeDefunctState( DDXDefunct, Defunct, pPropertyList, fApplyAbort, fApplyFailed );
  471. }
  472. //
  473. // If there are visible changes, update the views.
  474. //
  475. if ( ( fChangesMade ) &&
  476. ( pComponent ) &&
  477. ( lpResultDataObject ) ) {
  478. CCookie* pBaseCookie;
  479. Cookie* pCookie;
  480. hr = ExtractData( lpResultDataObject,
  481. CSchmMgmtDataObject::m_CFRawCookie,
  482. OUT reinterpret_cast<PBYTE>(&pBaseCookie),
  483. sizeof(pBaseCookie) );
  484. ASSERT( SUCCEEDED(hr) );
  485. pCookie = pComponent->ActiveCookie(pBaseCookie);
  486. ASSERT( NULL != pCookie );
  487. hr = pComponent->m_pResultData->UpdateItem( pCookie->hResultId );
  488. ASSERT( SUCCEEDED(hr) );
  489. }
  490. if ( pPropertyList ) {
  491. pPropertyList->Release();
  492. }
  493. return !fApplyAbort && !fApplyFailed ; // return TRUE if nothing happened
  494. }
  495. void
  496. AttributeGeneralPage::DoDataExchange(
  497. CDataExchange *pDX
  498. ) {
  499. HRESULT hr;
  500. CString szAdsPath;
  501. VARIANT AdsResult;
  502. UINT SyntaxOrdinal = SCHEMA_SYNTAX_UNKNOWN;
  503. ComponentData& Scope = pComponent->QueryComponentDataRef();
  504. AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
  505. // Enable hourglass
  506. CWaitCursor wait;
  507. CPropertyPage::DoDataExchange( pDX );
  508. VariantInit( &AdsResult );
  509. // We still want to do the DDX exchange at the bottom
  510. // even if the data is already loaded so make it part
  511. // of this if statement instead of short circuiting
  512. // from within
  513. if ( !pDX->m_bSaveAndValidate &&
  514. !fDataLoaded) {
  515. //
  516. // Get the schema cache object and the actual ADS object.
  517. // Keep the ADS object around while the page is loaded.
  518. //
  519. ASSERT( !pObject ); // Must be NULL initially
  520. pObject = Scope.g_SchemaCache.LookupSchemaObjectByCN(
  521. pCookie->strSchemaObject,
  522. SCHMMGMT_ATTRIBUTE );
  523. if ( pObject ) {
  524. Scope.GetSchemaObjectPath( pObject->commonName, szAdsPath );
  525. if ( !szAdsPath.IsEmpty() ) {
  526. hr = ADsGetObject( (LPWSTR)(LPCWSTR)szAdsPath,
  527. IID_IADs,
  528. (void **)&pIADsObject );
  529. if( SUCCEEDED(hr) )
  530. {
  531. BOOL fIsConstructed = FALSE;
  532. // Igrnore error code
  533. IsConstructedObject( pIADsObject, fIsConstructed );
  534. // Enable check box if ths attribute is not in the excluded
  535. // list and available for the User Class
  536. GetDlgItem(IDC_ATTRIB_GENERAL_CPYATTR_CHECK)->EnableWindow(
  537. !fIsConstructed &&
  538. !IsInList( rgszExclClass, pObject->ldapDisplayName ) &&
  539. !IsInList( rgszExclClass2, pObject->ldapDisplayName ) &&
  540. IsAttributeInUserClass( pObject->ldapDisplayName ) );
  541. }
  542. }
  543. }
  544. //
  545. // If we have no ADS object, we should error out!
  546. //
  547. if ( !pIADsObject )
  548. {
  549. DoErrMsgBox( ::GetActiveWindow(), TRUE, IDS_ERR_NO_SCHEMA_OBJECT );
  550. // Because there is no pIADsObject, OnSetActive() will close dialog box
  551. return;
  552. }
  553. //
  554. // ObjectName - Use the ldapDisplayName to be consistent
  555. // with the other admin components.
  556. //
  557. hr = pIADsObject->Get( const_cast<BSTR>((LPCTSTR)g_DisplayName),
  558. &AdsResult );
  559. if ( SUCCEEDED( hr ) ) {
  560. ASSERT( AdsResult.vt == VT_BSTR );
  561. ObjectName = AdsResult.bstrVal;
  562. VariantClear( &AdsResult );
  563. }
  564. //
  565. // Description
  566. //
  567. hr = pIADsObject->Get( const_cast<BSTR>((LPCTSTR)g_Description),
  568. &AdsResult );
  569. if ( SUCCEEDED( hr ) ) {
  570. ASSERT( AdsResult.vt == VT_BSTR );
  571. Description = AdsResult.bstrVal;
  572. DDXDescription = AdsResult.bstrVal;
  573. VariantClear( &AdsResult );
  574. }
  575. //
  576. // CommonName
  577. //
  578. hr = pIADsObject->Get( const_cast<BSTR>((LPCTSTR)g_CN),
  579. &AdsResult );
  580. if ( SUCCEEDED( hr ) ) {
  581. ASSERT( AdsResult.vt == VT_BSTR );
  582. DisplayName = AdsResult.bstrVal;
  583. VariantClear( &AdsResult );
  584. }
  585. //
  586. // SysClass
  587. //
  588. hr = pIADsObject->Get( const_cast<BSTR>((LPCTSTR)g_SystemOnly),
  589. &AdsResult );
  590. if ( SUCCEEDED( hr ) ) {
  591. ASSERT( AdsResult.vt == VT_BOOL );
  592. if ( AdsResult.boolVal ) {
  593. SysClassString = g_SysAttrString;
  594. } else {
  595. SysClassString = L"";
  596. }
  597. VariantClear( &AdsResult );
  598. } else {
  599. SysClassString = L"";
  600. }
  601. //
  602. // Syntax
  603. //
  604. // No need to reload from schema -- syntax never changes
  605. //
  606. ASSERT(pObject);
  607. if( pObject )
  608. SyntaxOrdinal = pObject->SyntaxOrdinal;
  609. SyntaxString = g_Syntax[ SyntaxOrdinal ].m_strSyntaxName;
  610. //
  611. // Syntax min and max values.
  612. //
  613. hr = pIADsObject->Get( const_cast<BSTR>((LPCTSTR)g_RangeLower),
  614. &AdsResult );
  615. if ( SUCCEEDED( hr ) ) {
  616. ASSERT( V_VT( &AdsResult ) == VT_I4 );
  617. RangeLower.Format( g_Syntax[ SyntaxOrdinal ].m_fIsSigned ?
  618. g_INT32_FORMAT : g_UINT32_FORMAT,
  619. V_I4( &AdsResult ) );
  620. ASSERT( RangeLower.GetLength() <= cchMinMaxRange );
  621. DDXRangeLower = RangeLower;
  622. VariantClear( &AdsResult );
  623. }
  624. hr = pIADsObject->Get( const_cast<BSTR>((LPCTSTR)g_RangeUpper),
  625. &AdsResult );
  626. if ( SUCCEEDED( hr ) ) {
  627. ASSERT( V_VT( &AdsResult ) == VT_I4 );
  628. RangeUpper.Format( g_Syntax[ SyntaxOrdinal ].m_fIsSigned ?
  629. g_INT32_FORMAT : g_UINT32_FORMAT,
  630. V_I4( &AdsResult ) );
  631. ASSERT( RangeUpper.GetLength() <= cchMinMaxRange );
  632. DDXRangeUpper = RangeUpper;
  633. VariantClear( &AdsResult );
  634. }
  635. //
  636. // Multi-Valued
  637. //
  638. MultiValued.LoadString( IDS_ATTRIBUTE_MULTI );
  639. hr = pIADsObject->Get( const_cast<BSTR>((LPCTSTR)g_IsSingleValued),
  640. &AdsResult );
  641. if ( SUCCEEDED( hr ) ) {
  642. ASSERT( AdsResult.vt == VT_BOOL );
  643. if ( AdsResult.boolVal == -1 ) {
  644. MultiValued.Empty();
  645. MultiValued.LoadString( IDS_ATTRIBUTE_SINGLE );
  646. }
  647. VariantClear( &AdsResult );
  648. }
  649. //
  650. // Displayable
  651. //
  652. hr = pIADsObject->Get(g_ShowInAdvViewOnly, &AdsResult);
  653. if ( SUCCEEDED( hr ) ) {
  654. ASSERT( AdsResult.vt == VT_BOOL );
  655. if ( AdsResult.boolVal == -1 ) {
  656. Displayable = FALSE;
  657. DDXDisplayable = FALSE;
  658. }
  659. VariantClear( &AdsResult );
  660. }
  661. //
  662. // Defunct
  663. //
  664. hr = pIADsObject->Get( const_cast<BSTR>((LPCTSTR)g_isDefunct),
  665. &AdsResult );
  666. if ( SUCCEEDED( hr ) ) {
  667. ASSERT( AdsResult.vt == VT_BOOL );
  668. if ( AdsResult.boolVal == -1 ) {
  669. Defunct = TRUE;
  670. DDXDefunct = TRUE;
  671. }
  672. VariantClear( &AdsResult );
  673. }
  674. //
  675. // ReplicatedToGC
  676. //
  677. hr = pIADsObject->Get( const_cast<BSTR>((LPCTSTR)g_GCReplicated),
  678. &AdsResult );
  679. if ( SUCCEEDED( hr ) ) {
  680. ASSERT( AdsResult.vt == VT_BOOL );
  681. if ( AdsResult.boolVal == -1 ) {
  682. ReplicatedToGC = TRUE;
  683. DDXReplicatedToGC = TRUE;
  684. }
  685. VariantClear( &AdsResult );
  686. }
  687. //
  688. // OID
  689. //
  690. hr = pIADsObject->Get( const_cast<BSTR>((LPCTSTR)g_GlobalAttributeID),
  691. &AdsResult );
  692. if ( SUCCEEDED( hr ) ) {
  693. ASSERT( AdsResult.vt == VT_BSTR );
  694. OidString = AdsResult.bstrVal;
  695. VariantClear( &AdsResult );
  696. }
  697. //
  698. // Indexed, ANR, & Copy on duplicate
  699. //
  700. hr = pIADsObject->Get( const_cast<BSTR>((LPCTSTR)g_IndexFlag),
  701. &AdsResult );
  702. if (SUCCEEDED(hr))
  703. {
  704. ASSERT(AdsResult.vt == VT_I4);
  705. search_flags = V_I4(&AdsResult);
  706. // Index this attribute in the Active Directory
  707. DDXIndexed = getbit( search_flags, INDEX_BIT_ATTINDEX );
  708. // Ambiguous Name Resolution (ANR)
  709. // checkbox must exist
  710. ASSERT( GetDlgItem(IDC_ATTRIB_GENERAL_ANR_CHECK) );
  711. // if not indexed, or not allowed, disable the checkbox
  712. GetDlgItem(IDC_ATTRIB_GENERAL_ANR_CHECK)->EnableWindow(
  713. g_Syntax[ SyntaxOrdinal ].m_fIsANRCapable ? DDXIndexed : FALSE );
  714. if( DDXIndexed )
  715. DDXANR = getbit( search_flags, INDEX_BIT_ANR );
  716. else
  717. {
  718. DDXANR = FALSE;
  719. // if not indexed, ANR in DS should not be set
  720. ASSERT( !getbit( search_flags, INDEX_BIT_ANR ) );
  721. }
  722. // Attribute is copied when duplicating a user
  723. DDXCopyOnDuplicate = getbit( search_flags, INDEX_BIT_COPYONDUPLICATE );
  724. VariantClear( &AdsResult );
  725. }
  726. // Containerized index
  727. DDXContainerIndexed = getbit( search_flags, INDEX_BIT_PDNTATTINDEX );
  728. // Determine if this is a category 1 object & disable read-only fields
  729. BOOL fIsSystemObject = FALSE;
  730. hr = IsCategory1Object( pIADsObject, fIsSystemObject );
  731. if( SUCCEEDED(hr) && fIsSystemObject )
  732. {
  733. ASSERT( GetDlgItem(IDC_ATTRIB_GENERAL_MIN_EDIT) );
  734. ASSERT( GetDlgItem(IDC_ATTRIB_GENERAL_MAX_EDIT) );
  735. ASSERT( GetDlgItem(IDC_ATTRIB_GENERAL_DEACTIVATE) );
  736. reinterpret_cast<CEdit *>( GetDlgItem(IDC_ATTRIB_GENERAL_MIN_EDIT) )->SetReadOnly();
  737. reinterpret_cast<CEdit *>( GetDlgItem(IDC_ATTRIB_GENERAL_MAX_EDIT) )->SetReadOnly();
  738. GetDlgItem(IDC_ATTRIB_GENERAL_DEACTIVATE)->EnableWindow( FALSE );
  739. }
  740. hr = DissableReadOnlyAttributes( this, pIADsObject, ctrls, sizeof(ctrls)/sizeof(ctrls[0]) );
  741. ASSERT( SUCCEEDED(hr) ); // shouldn't fail, but unimportant, so ignore error
  742. // warn the user if this is a read/write defunct object
  743. ASSERT( GetDlgItem(IDC_ATTRIB_GENERAL_DEACTIVATE) );
  744. if( DDXDefunct &&
  745. GetDlgItem(IDC_ATTRIB_GENERAL_DEACTIVATE)->IsWindowEnabled() )
  746. {
  747. AfxMessageBox( IDS_WARNING_DEFUNCT, MB_OK | MB_ICONINFORMATION );
  748. }
  749. //
  750. // Remember that the data is loaded.
  751. //
  752. fDataLoaded = TRUE;
  753. m_editLowerRange.SetSigned( g_Syntax[ SyntaxOrdinal ].m_fIsSigned );
  754. m_editUpperRange.SetSigned( g_Syntax[ SyntaxOrdinal ].m_fIsSigned );
  755. }
  756. //
  757. // Set up the dialog data exchange.
  758. //
  759. DDX_Text( pDX, IDC_ATTRIB_GENERAL_NAME_STATIC, ObjectName );
  760. DDX_Text( pDX, IDC_ATTRIB_GENERAL_SYSCLASS_STATIC, SysClassString );
  761. DDX_Text( pDX, IDC_ATTRIB_GENERAL_SYNTAX_EDIT, SyntaxString );
  762. DDX_Text( pDX, IDC_ATTRIB_GENERAL_OID_EDIT, OidString );
  763. DDX_Text( pDX, IDC_ATTRIB_GENERAL_VALUE_STATIC, MultiValued );
  764. DDX_Text( pDX, IDC_ATTRIB_GENERAL_LDN, DisplayName );
  765. DDX_Text( pDX, IDC_ATTRIB_GENERAL_DESCRIPTION_EDIT, DDXDescription );
  766. DDXV_VerifyAttribRange( pDX, g_Syntax[ pObject->SyntaxOrdinal ].m_fIsSigned,
  767. IDC_ATTRIB_GENERAL_MIN_EDIT, DDXRangeLower,
  768. IDC_ATTRIB_GENERAL_MAX_EDIT, DDXRangeUpper );
  769. DDX_Check( pDX, IDC_ATTRIB_GENERAL_DISPLAYABLE_CHECK, DDXDisplayable );
  770. DDX_Check( pDX, IDC_ATTRIB_GENERAL_INDEX_CHECK, DDXIndexed );
  771. DDX_Check( pDX, IDC_ATTRIB_GENERAL_ANR_CHECK, DDXANR );
  772. DDX_Check( pDX, IDC_ATTRIB_GENERAL_CPYATTR_CHECK, DDXCopyOnDuplicate );
  773. DDX_Check( pDX, IDC_ATTRIB_GENERAL_REPLICATED, DDXReplicatedToGC );
  774. DDX_Check( pDX, IDC_ATTRIB_GENERAL_CONTAINERIZED_INDEX_CHECK, DDXContainerIndexed );
  775. // Since we want the checkbox label to be positive
  776. // the value is actually the opposite of defunct
  777. int checkValue = !Defunct;
  778. DDX_Check( pDX, IDC_ATTRIB_GENERAL_DEACTIVATE, checkValue );
  779. DDXDefunct = !checkValue;
  780. return;
  781. }
  782. void
  783. AttributeGeneralPage::OnIndexClick()
  784. {
  785. ASSERT( pObject );
  786. if( pObject && g_Syntax[ pObject->SyntaxOrdinal ].m_fIsANRCapable )
  787. {
  788. GetDlgItem(IDC_ATTRIB_GENERAL_ANR_CHECK)->
  789. EnableWindow( IsDlgButtonChecked(IDC_ATTRIB_GENERAL_INDEX_CHECK) );
  790. }
  791. }
  792. void
  793. AttributeGeneralPage::OnDeactivateClick()
  794. {
  795. if( !IsDlgButtonChecked(IDC_ATTRIB_GENERAL_DEACTIVATE) )
  796. {
  797. if( IDOK != AfxMessageBox( IDS_WARNING_DEFUNCT_SET, MB_OKCANCEL | MB_ICONWARNING ) )
  798. {
  799. CheckDlgButton( IDC_ATTRIB_GENERAL_DEACTIVATE, BST_UNCHECKED );
  800. }
  801. }
  802. }
  803. // Search User class & aux classes for the specified attribute
  804. BOOL
  805. AttributeGeneralPage::IsAttributeInUserClass( const CString & strAttribDN )
  806. {
  807. BOOL fFound = FALSE;
  808. ComponentData & Scope = pComponent->QueryComponentDataRef();
  809. SchemaObject * pObject = Scope.g_SchemaCache.LookupSchemaObject(
  810. CString( szUserClass ),
  811. SCHMMGMT_CLASS );
  812. //
  813. // Call the attribute check routine. This routine
  814. // will call itself recursively to search the
  815. // inheritance structure of the class User.
  816. //
  817. if ( pObject ) {
  818. fFound = RecursiveIsAttributeInUserClass( strAttribDN, pObject );
  819. Scope.g_SchemaCache.ReleaseRef( pObject );
  820. }
  821. return fFound ;
  822. }
  823. // Search the user class & subclasses
  824. BOOL
  825. AttributeGeneralPage::RecursiveIsAttributeInUserClass(
  826. const CString & strAttribDN,
  827. SchemaObject * pObject )
  828. {
  829. BOOL fFound = FALSE;
  830. //
  831. // Don't process "top" here since everyone inherits from it.
  832. //
  833. // i don't think we ever get "top" here?
  834. ASSERT( pObject->ldapDisplayName.CompareNoCase( szTopClass ) );
  835. if ( !pObject->ldapDisplayName.CompareNoCase(szTopClass) )
  836. return fFound;
  837. DebugTrace( L"RecursiveIsAttributeInUserClass: %ls\n",
  838. const_cast<LPWSTR>((LPCTSTR)pObject->ldapDisplayName) );
  839. // Check every list
  840. if( !SearchResultList( strAttribDN, pObject->systemMayContain) &&
  841. !SearchResultList( strAttribDN, pObject->mayContain) &&
  842. !SearchResultList( strAttribDN, pObject->systemMustContain) &&
  843. !SearchResultList( strAttribDN, pObject->mustContain) )
  844. {
  845. //
  846. // The attribute was not found in the given class, diging deeper...
  847. // Check each auxiliary class...
  848. //
  849. fFound = TraverseAuxiliaryClassList( strAttribDN,
  850. pObject->systemAuxiliaryClass );
  851. if( !fFound )
  852. {
  853. fFound = TraverseAuxiliaryClassList( strAttribDN,
  854. pObject->auxiliaryClass );
  855. }
  856. }
  857. else
  858. {
  859. fFound = TRUE;
  860. }
  861. return fFound ;
  862. }
  863. // Linear search of the linked list for the string strAttribDN
  864. BOOL
  865. AttributeGeneralPage::SearchResultList(
  866. const CString & strAttribDN,
  867. ListEntry * pList )
  868. {
  869. // Traverse the list
  870. while ( pList )
  871. {
  872. // Searching for the existance of the attribute
  873. if( !pList->Attribute.CompareNoCase( strAttribDN ) )
  874. return TRUE;
  875. pList = pList->pNext;
  876. }
  877. return FALSE;
  878. }
  879. // Traverse each auxiliary class by recursivly
  880. // calling RecursiveIsAttributeInUserClass()
  881. BOOL
  882. AttributeGeneralPage::TraverseAuxiliaryClassList(
  883. const CString & strAttribDN,
  884. ListEntry * pList )
  885. {
  886. SchemaObject * pInheritFrom = NULL;
  887. ComponentData & Scope = pComponent->QueryComponentDataRef();
  888. BOOL fFound = FALSE;
  889. while ( !fFound && pList ) {
  890. pInheritFrom = Scope.g_SchemaCache.LookupSchemaObject( pList->Attribute,
  891. SCHMMGMT_CLASS );
  892. if ( pInheritFrom )
  893. {
  894. // recursive call
  895. fFound = RecursiveIsAttributeInUserClass( strAttribDN, pInheritFrom );
  896. Scope.g_SchemaCache.ReleaseRef( pInheritFrom );
  897. }
  898. pList = pList->pNext;
  899. }
  900. return fFound ;
  901. }
  902. HRESULT
  903. AttributeGeneralPage::ChangeDefunctState( BOOL DDXDefunct,
  904. BOOL & Defunct,
  905. IADsPropertyList * pPropertyList,
  906. BOOL & fApplyAbort,
  907. BOOL & fApplyFailed )
  908. {
  909. ASSERT( !fApplyAbort && DDXDefunct != Defunct );
  910. VARIANT AdsValue;
  911. HRESULT hr = S_OK;
  912. VariantInit( &AdsValue );
  913. V_VT(&AdsValue) = VT_BOOL;
  914. if ( DDXDefunct ) {
  915. V_BOOL(&AdsValue) = -1;
  916. } else {
  917. V_BOOL(&AdsValue) = 0;
  918. }
  919. hr = pIADsObject->Put( const_cast<BSTR>((LPCTSTR)g_isDefunct),
  920. AdsValue );
  921. ASSERT( SUCCEEDED( hr ) );
  922. hr = pIADsObject->SetInfo();
  923. if ( FAILED( hr ) ) {
  924. pPropertyList->PurgePropertyList();
  925. if( ERROR_DS_UNWILLING_TO_PERFORM == HRESULT_CODE(hr) )
  926. {
  927. fApplyFailed = TRUE;
  928. DoErrMsgBox( ::GetActiveWindow(),
  929. TRUE,
  930. DDXDefunct ? IDS_ERR_EDIT_DEFUNCT_SET : IDS_ERR_EDIT_DEFUNCT_REMOVE );
  931. }
  932. else
  933. {
  934. fApplyAbort = TRUE;
  935. DoErrMsgBox( ::GetActiveWindow(), TRUE, GetErrorMessage(hr,TRUE) );
  936. }
  937. } else {
  938. pObject->isDefunct = DDXDefunct;
  939. Defunct = DDXDefunct;
  940. }
  941. return hr;
  942. }