text: /////////////////////////////////////////////////////////////////////////////
  //
  //  Copyright (c) 1998-2000 Microsoft Corporation
  //
  //  Module Name:
  //      ClusPage.cpp
  //
  //  Abstract:
  //      CClusterSecurityPage class implementation.  This class will encapsulate
  //      the cluster security extension page.
  //
  //  Author:
  //      Galen Barbee    (galenb)    February 11, 1998
  //
  //  Revision History:
  //
  //  Notes:
  //
  /////////////////////////////////////////////////////////////////////////////
  
  #include "stdafx.h"
  #include "resource.h"
  #include "ClusPage.h"
  #include "AclUtils.h"
  #include <clusudef.h>
  
  static GENERIC_MAPPING ShareMap =
  {
      CLUSAPI_READ_ACCESS,
      CLUSAPI_CHANGE_ACCESS,
      CLUSAPI_NO_ACCESS,
      CLUSAPI_ALL_ACCESS
  };
  
  static SI_ACCESS siClusterAccesses[] =
  {
      { &GUID_NULL, CLUSAPI_ALL_ACCESS, MAKEINTRESOURCE(IDS_ACLEDIT_PERM_GEN_ALL), SI_ACCESS_GENERAL | SI_ACCESS_SPECIFIC /*| OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE*/ }
  };
  
  /////////////////////////////////////////////////////////////////////////////
  //++
  //
  //  CClusterSecurityInformation::CClusterSecurityInformation
  //
  //  Routine Description:
  //      Default contructor
  //
  //  Arguments:
  //      none
  //
  //  Return Value:
  //      none
  //
  //--
  /////////////////////////////////////////////////////////////////////////////
  CClusterSecurityInformation::CClusterSecurityInformation( void )
      : m_pcsp( NULL )
  {
      m_pShareMap     = &ShareMap;
      m_psiAccess     = (SI_ACCESS *) &siClusterAccesses;
      m_nAccessElems  = ARRAYSIZE( siClusterAccesses );
      m_nDefAccess    = 0;
      m_dwFlags       =   SI_EDIT_PERMS
                        | SI_NO_ACL_PROTECT
                        //| SI_UGOP_PROVIDED
                        //| SI_NO_UGOP_ACCOUNT_GROUPS
                        //| SI_NO_UGOP_USERS
                        //| SI_NO_UGOP_LOCAL_GROUPS
                        //| SI_NO_UGOP_WELLKNOWN
                        //| SI_NO_UGOP_BUILTIN
                        ;
  
  } //*** CClusterSecurityInformation::CClusterSecurityInformation()
  
  /////////////////////////////////////////////////////////////////////////////
  //++
  //
  //  CClusterSecurityInformation::GetSecurity
  //
  //  Routine Description:
  //      Give our security descriptor to the ISecurityInfomation UI
  //      so it can be displayed and edited.
  //
  //  Arguments:
  //      RequestedInformation    [IN]
  //      ppSecurityDescriptor    [IN OUT]
  //      fDefault                [IN]
  //
  //  Return Value:
  //      E_FAIL for error and S_OK for success.
  //
  //--
  /////////////////////////////////////////////////////////////////////////////
  STDMETHODIMP CClusterSecurityInformation::GetSecurity(
      IN      SECURITY_INFORMATION RequestedInformation,
      IN OUT  PSECURITY_DESCRIPTOR *ppSecurityDescriptor,
      IN      BOOL fDefault
      )
  {
      AFX_MANAGE_STATE( ::AfxGetStaticModuleState() );
  
      HRESULT hr = E_FAIL;
  
      try
      {
          if ( ppSecurityDescriptor != NULL )
          {
              PSECURITY_DESCRIPTOR    pSD = NULL;
  
              pSD = ClRtlCopySecurityDescriptor( Pcsp()->Psec() );
              if ( pSD != NULL )
              {
                  //hr = HrFixupSD( pSD );
                  //if ( SUCCEEDED( hr ) )
                  //{
                      *ppSecurityDescriptor = pSD;
                  //}
                  hr = S_OK;
              } // if: no errors copying the security descriptor
              else
              {
                  hr = GetLastError();
                  TRACE( _T("CClusterSecurityInformation::GetSecurity() - Error %08.8x copying the security descriptor.\n"), hr );
                  hr = HRESULT_FROM_WIN32( hr );
              } // else: error copying the security descriptor
          }
          else
          {
              hr = S_OK;
          } // else: no security descriptor pointer
      }
      catch ( ... )
      {
          TRACE( _T("CClusterSecurityInformation::GetSecurity() - Unknown error occurred.\n") );
      }
  
      return hr;
  
  } //*** CClusterSecurityInformation::GetSecurity()
  
  /////////////////////////////////////////////////////////////////////////////
  //++
  //
  //  CClusterSecurityInformation::SetSecurity
  //
  //  Routine Description:
  //      ISecurityInformation is giving back the edited security descriptor.
  //
  //  Arguments:
  //      SecurityInformation [IN]
  //      pSecurityDescriptor [IN OUT]
  //
  //  Return Value:
  //      E_FAIL for error and S_OK for success.
  //
  //--
  /////////////////////////////////////////////////////////////////////////////
  STDMETHODIMP CClusterSecurityInformation::SetSecurity(
      IN SECURITY_INFORMATION SecurityInformation,
      IN PSECURITY_DESCRIPTOR pSecurityDescriptor
      )
  {
      AFX_MANAGE_STATE( ::AfxGetStaticModuleState() );
  
      HRESULT hr = E_FAIL;
      PSID    pSystemSid = NULL;
      PSID    pAdminSid = NULL;
      PSID    pNetServiceSid = NULL;
  
      try
      {
          SID_IDENTIFIER_AUTHORITY    siaNtAuthority = SECURITY_NT_AUTHORITY;
  
          hr = CSecurityInformation::SetSecurity( SecurityInformation, pSecurityDescriptor );
          if ( hr == S_OK )
          {
              if ( AllocateAndInitializeSid(
                          &siaNtAuthority,
                          1,
                          SECURITY_LOCAL_SYSTEM_RID,
                          0, 0, 0, 0, 0, 0, 0,
                          &pSystemSid
                          ) )
              {
                  CString strMsg;
  
                  if ( BSidInSD( pSecurityDescriptor, pSystemSid ) )
                  {
                      //
                      // allocate and init the Administrators group sid
                      //
                      if ( AllocateAndInitializeSid(
                                  &siaNtAuthority,
                                  2,
                                  SECURITY_BUILTIN_DOMAIN_RID,
                                  DOMAIN_ALIAS_RID_ADMINS,
                                  0, 0, 0, 0, 0, 0,
                                  &pAdminSid
                                  ) )
                      {
                          if ( BSidInSD( pSecurityDescriptor, pAdminSid ) )
                          {
                              //
                              // allocate and init the Network Service sid
                              //
                              if ( AllocateAndInitializeSid(
                                          &siaNtAuthority,
                                          1,
                                          SECURITY_NETWORK_SERVICE_RID,
                                          0, 0, 0, 0, 0, 0, 0,
                                          &pNetServiceSid
                                          ) )
                              {
                                  if ( BSidInSD( pSecurityDescriptor, pNetServiceSid ) )
                                  {
                                      hr = Pcsp()->HrSetSecurityDescriptor( pSecurityDescriptor );
                                  } // if: service SID in the SD
                                  else
                                  {
                                      strMsg.LoadString( IDS_NETSERVICE_ACCOUNT_NOT_SPECIFIED );
                                      AfxMessageBox( strMsg, MB_OK | MB_ICONSTOP );
  
                                      hr = S_FALSE;   // if there are missing required accounts then return S_FALSE to keep AclUi alive.
                                  } // else
                              } // if: allocate and init service SID
                          } // if: admin SID in the SD
                          else
                          {
                              strMsg.LoadString( IDS_ADMIN_ACCOUNT_NOT_SPECIFIED );
                              AfxMessageBox( strMsg, MB_OK | MB_ICONSTOP );
  
                              hr = S_FALSE;   // if there are missing required accounts then return S_FALSE to keep AclUi alive.
                          } // else
                      } // if: allocate and init admin SID
                  } // if: system SID in the SD
                  else
                  {
                      strMsg.LoadString( IDS_SYS_ACCOUNT_NOT_SPECIFIED );
                      AfxMessageBox( strMsg, MB_OK | MB_ICONSTOP );
  
                      hr = S_FALSE;   // if there are missing required accounts then return S_FALSE to keep AclUi alive.
                  } // else
              } // if: allocate and init system SID
          } // if: CSecurityInformation::SetSecurity() worked
      }
      catch( ... )
      {
          ;
      }
  
      if ( pSystemSid != NULL )
      {
          FreeSid( pSystemSid );
      }
  
      if ( pAdminSid != NULL )
      {
          FreeSid( pAdminSid );
      }
  
      if ( pNetServiceSid != NULL )
      {
          FreeSid( pNetServiceSid );
      }
  
      return hr;
  
  } //*** CClusterSecurityInformation::SetSecurity()
  
  /////////////////////////////////////////////////////////////////////////////
  //++
  //
  //  CClusterSecurityInformation::HrInit
  //
  //  Routine Description:
  //      Initialize method.
  //
  //  Arguments:
  //      pcsp        [IN]    back pointer to parent property page wrapper
  //      strServer   [IN]    cluster name
  //
  //  Return Value:
  //      S_OK for success.  E_FAIL for failure.
  //
  //--
  /////////////////////////////////////////////////////////////////////////////
  HRESULT CClusterSecurityInformation::HrInit(
      IN CClusterSecurityPage *   pcsp,
      IN CString const &          strServer,
      IN CString const &          strNode
      )
  {
      ASSERT( pcsp != NULL );
      ASSERT( strServer.GetLength() > 0 );
      AFX_MANAGE_STATE( ::AfxGetStaticModuleState() );
  
      m_pcsp                      = pcsp;
      m_strServer                 = strServer;
      m_strNode                   = strNode;
      m_nLocalSIDErrorMessageID   = IDS_LOCAL_ACCOUNTS_SPECIFIED_CLUS;
  
      return S_OK;
  
  } //*** CClusterSecurityInformation::HrInit()
  
  /////////////////////////////////////////////////////////////////////////////
  //++
  //
  //  CClusterSecurityInformation::BSidInSD
  //
  //  Routine Description:
  //      Determines if there is an ACEs for the passed in SID in the
  //      Security Descriptor (pSD) after the ACL editor has been called
  //
  //  Arguments:
  //      pSD     [IN] - Security Descriptor to be checked.
  //      pSid    [IN] - SID to look for
  //
  //  Return Value:
  //      TRUE if an ACE for the SID was found, False otherwise.
  //
  /////////////////////////////////////////////////////////////////////////////
  BOOL CClusterSecurityInformation::BSidInSD(
      IN PSECURITY_DESCRIPTOR pSD,
      IN PSID                 pSid
      )
  {
      BOOL    bSIdInACL = FALSE;
  
      try
      {
          PACL    pDACL           = NULL;
          BOOL    bHasDACL        = FALSE;
          BOOL    bDaclDefaulted  = FALSE;
  
          if ( ::GetSecurityDescriptorDacl( pSD, &bHasDACL, &pDACL, &bDaclDefaulted ) )
          {
              if ( bHasDACL && ( pDACL != NULL ) && ::IsValidAcl( pDACL ) )
              {
                  ACL_SIZE_INFORMATION    asiAclSize;
                  ACCESS_ALLOWED_ACE *    paaAllowedAce;
  
                  if ( ::GetAclInformation( pDACL, (LPVOID) &asiAclSize, sizeof( asiAclSize ), AclSizeInformation ) )
                  {
                      //
                      // Search the ACL for the SID
                      //
                      for ( DWORD dwCount = 0; dwCount < asiAclSize.AceCount; dwCount++ )
                      {
                          if ( ::GetAce( pDACL, dwCount, (LPVOID *) &paaAllowedAce ) )
                          {
                              if ( paaAllowedAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE )
                              {
                                  if ( EqualSid( &paaAllowedAce->SidStart, pSid ) )
                                  {
                                      bSIdInACL = TRUE;
                                      break;
                                  } // if: EqualSid
                              } // if: is this an access allowed ace?
                          } // if: can we get the ace from the DACL?
                      } // for
                  } // if: get ACL information
              } // if: is the ACL valid
          } // if: get the ACL from the SD
      }
      catch ( ... )
      {
          TRACE( _T("CClusterSecurityInformation::BSidInSD() - Unknown error occurred.\n") );
      }
  
      return bSIdInACL;
  
  } //*** CClusterSecurityInformation::BSidInSD()
  
  /////////////////////////////////////////////////////////////////////////////
  //++
  //
  //  CClusterSecurityInformation::HrFixupSD
  //
  //  Routine Description:
  //      Performs any fixups to the SD that may be requrired.
  //
  //  Arguments:
  //      pSD     [IN] - Security Descriptor to be checked.
  //
  //  Return Value:
  //      S_OK, or other Win32 error
  //
  /////////////////////////////////////////////////////////////////////////////
  HRESULT CClusterSecurityInformation::HrFixupSD(
      IN PSECURITY_DESCRIPTOR pSD
      )
  {
      HRESULT hr = S_OK;
      PSID    pSystemSid = NULL;
      PSID    pAdminSid = NULL;
      PSID    pNetServiceSid = NULL;
  
      try
      {
          SID_IDENTIFIER_AUTHORITY    siaNtAuthority = SECURITY_NT_AUTHORITY;
  
          if ( AllocateAndInitializeSid( &siaNtAuthority,
                                         1,
                                         SECURITY_LOCAL_SYSTEM_RID,
                                         0, 0, 0, 0, 0, 0, 0,
                                         &pSystemSid ) )
          {
              if ( ! BSidInSD( pSD, pSystemSid ) )
              {
                  HrAddSidToSD( &pSD, pSystemSid );
              } // if: system SID found in SD
          } // if: allocate system SID
  
          //
          // allocate and init the Administrators group sid
          //
          if ( AllocateAndInitializeSid(
                      &siaNtAuthority,
                      2,
                      SECURITY_BUILTIN_DOMAIN_RID,
                      DOMAIN_ALIAS_RID_ADMINS,
                      0, 0, 0, 0, 0, 0,
                      &pAdminSid
                      ) ) {
              if ( ! BSidInSD( pSD, pAdminSid ) )
              {
                  HrAddSidToSD( &pSD, pAdminSid );
              } // if: admin SID found in SD
          } // if: allocate admin SID
  
          //
          // allocate and init the Network Service sid
          //
          if ( AllocateAndInitializeSid(
                      &siaNtAuthority,
                      1,
                      SECURITY_NETWORK_SERVICE_RID,
                      0, 0, 0, 0, 0, 0, 0,
                      &pNetServiceSid
                      ) ) {
              if ( ! BSidInSD( pSD, pNetServiceSid ) )
              {
                  HrAddSidToSD( &pSD, pNetServiceSid );
              } // if: Network Service SID found in SD
          } // if: allocate Network Service SID
      }
      catch ( ... )
      {
          TRACE( _T("CClusterSecurityInformation::HrFixupSD() - Unknown error occurred.\n") );
      }
  
      if ( pSystemSid != NULL )
      {
          FreeSid( pSystemSid );
      }
  
      if ( pAdminSid != NULL )
      {
          FreeSid( pAdminSid );
      }
  
      if ( pNetServiceSid != NULL )
      {
          FreeSid( pNetServiceSid );
      }
  
      return hr;
  
  } //*** CClusterSecurityInformation::HrFixupSD()
  
  /////////////////////////////////////////////////////////////////////////////
  //++
  //
  //  CClusterSecurityInformation::HrAddSidToSD
  //
  //  Routine Description:
  //      Adds the passed in SID to the DACL of the passed in SD
  //
  //  Arguments:
  //      ppSD    [IN, OUT]   - Security Descriptor to be added to
  //      PSid    [IN]        - SID to add
  //
  //  Return Value:
  //      S_OK, or other Win32 error
  //
  /////////////////////////////////////////////////////////////////////////////
  HRESULT CClusterSecurityInformation::HrAddSidToSD(
      IN OUT PSECURITY_DESCRIPTOR *   ppSD,
      IN     PSID                     pSid
      )
  {
      HRESULT                 hr = S_OK;
      DWORD                   sc;
      SECURITY_DESCRIPTOR     sd;
      DWORD                   dwSDLen = sizeof( SECURITY_DESCRIPTOR );
      PACL                    pDacl = NULL;
      DWORD                   dwDaclLen = 0;
      PACL                    pSacl = NULL;
      DWORD                   dwSaclLen = 0;
      PSID                    pOwnerSid = NULL;
      DWORD                   dwOwnerSidLen = 0;
      PSID                    pGroupSid = NULL;
      DWORD                   dwGroupSidLen = NULL;
      PSECURITY_DESCRIPTOR    pNewSD = NULL;
      DWORD                   dwNewSDLen = 0;
  
      try
      {
          BOOL bRet = FALSE;
  
          bRet = ::MakeAbsoluteSD(    *ppSD,              // address of self relative SD
                                      &sd,                // address of absolute SD
                                      &dwSDLen,           // address of size of absolute SD
                                      NULL,               // address of discretionary ACL
                                      &dwDaclLen,         // address of size of discretionary ACL
                                      NULL,               // address of system ACL
                                      &dwSaclLen,         // address of size of system ACL
                                      NULL,               // address of owner SID
                                      &dwOwnerSidLen,     // address of size of owner SID
                                      NULL,               // address of primary-group SID
                                      &dwGroupSidLen      // address of size of group SID
                                      );
          if ( ! bRet )
          {
              sc = ::GetLastError();
              hr = HRESULT_FROM_WIN32( sc );
              if ( hr != ERROR_INSUFFICIENT_BUFFER )      // Duh, we're trying to find out how big the buffer should be?
              {
                  goto fnExit;
              }
          }
  
          //
          // increase the DACL length to hold one more ace and its sid.
          //
          dwDaclLen += ( sizeof( ACCESS_ALLOWED_ACE ) + GetLengthSid( pSid ) +1024 );
          pDacl = (PACL) ::LocalAlloc( LMEM_ZEROINIT, dwDaclLen );
          if ( pDacl == NULL )
          {
              hr = E_OUTOFMEMORY;
              goto fnExit;
          }
  
          InitializeAcl( pDacl,  dwDaclLen, ACL_REVISION );
  
          if ( dwSaclLen > 0 )
          {
              pSacl = (PACL) ::LocalAlloc( LMEM_ZEROINIT, dwSaclLen );
              if ( pSacl == NULL )
              {
                  hr = E_OUTOFMEMORY;
                  goto fnExit;
              }
          }
  
          if ( dwOwnerSidLen > 0 )
          {
              pOwnerSid = (PSID) ::LocalAlloc( LMEM_ZEROINIT, dwOwnerSidLen );
              if ( pOwnerSid == NULL )
              {
                  hr = E_OUTOFMEMORY;
                  goto fnExit;
              }
          }
  
          if ( dwGroupSidLen > 0 )
          {
              pGroupSid = (PSID) ::LocalAlloc( LMEM_ZEROINIT, dwGroupSidLen );
              if ( pGroupSid == NULL )
              {
                  hr = E_OUTOFMEMORY;
                  goto fnExit;
              }
          }
  
          bRet = ::MakeAbsoluteSD(    *ppSD,              // address of self relative SD
                                      &sd,                // address of absolute SD
                                      &dwSDLen,           // address of size of absolute SD
                                      pDacl,              // address of discretionary ACL
                                      &dwDaclLen,         // address of size of discretionary ACL
                                      pSacl,              // address of system ACL
                                      &dwSaclLen,         // address of size of system ACL
                                      pOwnerSid,          // address of owner SID
                                      &dwOwnerSidLen,     // address of size of owner SID
                                      pGroupSid,          // address of primary-group SID
                                      &dwGroupSidLen      // address of size of group SID
                                      );
          if ( !bRet )
          {
              goto fnExit;
          }
  
          //
          // Add the ACE for the SID to the DACL
          //
  //      if ( !AddAccessAllowedAceEx( pDacl,
  //                                     ACL_REVISION,
  //                                     CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE,
  //                                     CLUSAPI_ALL_ACCESS,
  //                                     pSid ) )
          if ( ! AddAccessAllowedAce(
                      pDacl,
                      ACL_REVISION,
                      CLUSAPI_ALL_ACCESS,
                      pSid
                      ) )
          {
              sc = ::GetLastError();
              hr = HRESULT_FROM_WIN32( sc );
              goto fnExit;
          }
  
          if ( ! ::SetSecurityDescriptorDacl( &sd, TRUE, pDacl, FALSE ) )
          {
              sc = ::GetLastError();
              hr = HRESULT_FROM_WIN32( sc );
              goto fnExit;
          }
  
          if ( ! ::SetSecurityDescriptorOwner( &sd, pOwnerSid, FALSE ) )
          {
              sc = ::GetLastError();
              hr = HRESULT_FROM_WIN32( sc );
              goto fnExit;
          }
  
          if ( ! ::SetSecurityDescriptorGroup( &sd, pGroupSid, FALSE ) )
          {
              sc = ::GetLastError();
              hr = HRESULT_FROM_WIN32( sc );
              goto fnExit;
          }
  
          if ( ! ::SetSecurityDescriptorSacl( &sd, TRUE, pSacl, FALSE ) )
          {
              sc = ::GetLastError();
              hr = HRESULT_FROM_WIN32( sc );
              goto fnExit;
          }
  
          dwNewSDLen = 0 ;
  
          if ( ! ::MakeSelfRelativeSD( &sd, NULL, &dwNewSDLen ) )
          {
              sc = ::GetLastError();
              hr = HRESULT_FROM_WIN32( sc );
              if ( hr != HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER ) ) // Duh, we're trying to find out how big the buffer should be?
              {
                  goto fnExit;
              }
          }
  
          pNewSD = ::LocalAlloc( LPTR, dwNewSDLen );
          if ( pNewSD != NULL )
          {
              if ( ! ::MakeSelfRelativeSD( &sd, pNewSD, &dwNewSDLen ) )
              {
                  sc = ::GetLastError();
                  hr = HRESULT_FROM_WIN32( sc );
                  goto fnExit;
              }
  
              ::LocalFree( *ppSD );
              *ppSD = pNewSD;
              hr = ERROR_SUCCESS;
          } else
          {
              hr = ERROR_NOT_ENOUGH_MEMORY;
          }
      }
      catch ( ... )
      {
          TRACE( _T("CClusterSecurityInformation::HrAddSidToSD() - Unknown error occurred.\n") );
      }
  
  fnExit:
  
      if ( pSacl != NULL )
      {
          ::LocalFree( pSacl );
      }
  
      if ( pOwnerSid != NULL )
      {
          ::LocalFree( pOwnerSid );
      }
  
      if ( pGroupSid != NULL )
      {
          ::LocalFree( pGroupSid );
      }
  
      return hr;
  
  } //*** CClusterSecurityInformation::HrAddSidToSD()
  
  
  //*************************************************************************//
  
  
  /////////////////////////////////////////////////////////////////////////////
  //++
  //
  //  CClusterSecurityPage::CClusterSecurityPage
  //
  //  Routine Description:
  //      Default contructor.
  //
  //  Arguments:
  //      none
  //
  //  Return Value:
  //      none
  //
  //--
  /////////////////////////////////////////////////////////////////////////////
  CClusterSecurityPage::CClusterSecurityPage( void )
      : m_psec( NULL )
      , m_psecPrev( NULL )
      , m_hpage( 0 )
      , m_hkey( 0 )
      , m_psecinfo( NULL )
      , m_pOwner( NULL )
      , m_pGroup( NULL )
      , m_fOwnerDef( FALSE )
      , m_fGroupDef( FALSE )
  {
      AFX_MANAGE_STATE( ::AfxGetStaticModuleState() );
  
      m_bSecDescModified = FALSE;
  
  } //*** CClusterSecurityPage::CClusterSecurityPage()
  
  /////////////////////////////////////////////////////////////////////////////
  //++
  //
  //  CClusterSecurityPage::~CClusterSecurityPage
  //
  //  Routine Description:
  //      Destructor
  //
  //  Arguments:
  //      none
  //
  //  Return Value:
  //      none
  //
  //--
  /////////////////////////////////////////////////////////////////////////////
  CClusterSecurityPage::~CClusterSecurityPage( void )
  {
      AFX_MANAGE_STATE( ::AfxGetStaticModuleState() );
  
      ::LocalFree( m_psec );
      m_psec = NULL;
  
      ::LocalFree( m_psecPrev );
      m_psecPrev = NULL;
  
      ::LocalFree( m_pOwner );
      m_pOwner = NULL;
  
      ::LocalFree( m_pGroup );
      m_pGroup = NULL;
  
      m_psecinfo->Release();
  
  } //*** CClusterSecurityPage::~CClusterSecurityPage()
  
  /////////////////////////////////////////////////////////////////////////////
  //++
  //
  //  CClusterSecurityPage::HrInit
  //
  //  Routine Description:
  //      Initialize method.
  //
  //  Arguments:
  //      peo     [IN]    back pointer to parent extension object.
  //
  //  Return Value:
  //      S_OK        Page was initialized successfully.
  //      hr          Error initializing the page.
  //
  //--
  /////////////////////////////////////////////////////////////////////////////
  HRESULT CClusterSecurityPage::HrInit( IN CExtObject * peo )
  {
      ASSERT( peo != NULL );
      AFX_MANAGE_STATE( ::AfxGetStaticModuleState() );
  
      HRESULT _hr = S_OK;
      DWORD   _sc;
  
      if ( peo != NULL )
      {
          m_peo = peo;
  
          _hr = CComObject< CClusterSecurityInformation >::CreateInstance( &m_psecinfo );
          if ( SUCCEEDED( _hr ) )
          {
              m_psecinfo->AddRef();
  
              m_hkey = GetClusterKey( Hcluster(), KEY_ALL_ACCESS );
              if ( m_hkey != NULL )
              {
                  _hr = HrGetSecurityDescriptor();
                  if ( SUCCEEDED( _hr ) )
                  {
                      CString strServer;
                      CString strNode;
  
                      strServer.Format( _T( "\\\\%s" ), StrClusterName() );
  
                      // Get the node on which the Cluster Name resource is online.
                      if ( BGetClusterNetworkNameNode( strNode ) )
                      {
                          _hr = m_psecinfo->HrInit( this, strServer, strNode );
                          if ( SUCCEEDED( _hr ) )
                          {
                              m_hpage = CreateClusterSecurityPage( m_psecinfo );
                              if ( m_hpage == NULL )
                              {
                                  _sc = ::GetLastError();
                                  _hr = HRESULT_FROM_WIN32( _sc );
                              } // if: error creating the page
                          } // if: initialized security info successfully
                      } // if: retrieved cluster network name node successfully
                      else
                      {
                      } // else: error getting cluster network name node
                  } // if: error getting SD
              } // if: retrieved cluster key
              else
              {
                  _sc = ::GetLastError();
                  _hr = HRESULT_FROM_WIN32( _sc );
                  TRACE( _T( "CClusterSecurityPage::ScInit() - Failed to get the cluster key, 0x%08lx.\n" ), _sc );
              } // else: error getting cluster key
          } // if: created security info object successfully
          else
          {
              TRACE( _T( "CClusterSecurityPage::ScInit() - Failed to create CClusterSecurityInformation object, %0x%08lx.\n" ), _hr );
          }
      } // if: extension object is available
  
      return _hr;
  
  } //*** CClusterSecurityPage::HrInit()
  
  /////////////////////////////////////////////////////////////////////////////
  //++
  //
  //  CClusterSecurityPage::HrGetSecurityDescriptor
  //
  //  Routine Description:
  //      Get the security descriptor from the cluster database or create a
  //      default one if it doesn't exist.
  //
  //  Arguments:
  //      none
  //
  //  Return Value:
  //
  //
  //--
  /////////////////////////////////////////////////////////////////////////////
  HRESULT CClusterSecurityPage::HrGetSecurityDescriptor( void )
  {
      AFX_MANAGE_STATE( ::AfxGetStaticModuleState() );
      HRESULT                 hr = S_OK;
      PSECURITY_DESCRIPTOR    psec = NULL;
  
      hr = HrGetSDFromClusterDB( &psec );                                             //uses localalloc
      if ( FAILED( hr ) || ( psec == NULL ) || ( IsValidSecurityDescriptor( psec ) == FALSE ) )
      {
          DWORD   sc;
          DWORD   dwLen = 0;
   
          //
          //  If the SD was not found or was not a valid SD then build a default
          //  SD and save it into the cluster DB...
          //
   
          TRACE( _T( "Security Descriptor is NULL.  Build default SD" ) );
          sc = ::ClRtlBuildDefaultClusterSD( NULL, &psec, &dwLen );                   //uses localalloc
          hr = HRESULT_FROM_WIN32( sc );
          if ( FAILED( hr ) )
          {
              TRACE( _T( "ClRtlBuildDefaultClusterSD failed, 0x%08x" ), hr );
          } // if: error building the default SD
          else
          {
              SetPermissions( psec );
          } // else: 
      } // if: error getting SD from cluster database
  
      if ( SUCCEEDED( hr ) )
      {
          delete m_psec;
          m_psec = ClRtlCopySecurityDescriptor( psec );
          hr = GetLastError();                // Get the last error
          ::LocalFree( psec );
          psec = NULL;
          if ( m_psec == NULL )
          {
              hr = HRESULT_FROM_WIN32( hr );  // Convert to HRESULT
              goto Cleanup;
          } // if: error copying the security descriptor
  
          hr = HrGetSDOwner( m_psec );
          if ( SUCCEEDED( hr ) )
          {
              hr = HrGetSDGroup( m_psec );
              if ( SUCCEEDED( hr ) )
              {
                  m_psecPrev = ClRtlCopySecurityDescriptor( m_psec );
                  if ( m_psecPrev == NULL )
                  {
                      hr = GetLastError();            // Get the last error
                      hr = HRESULT_FROM_WIN32( hr );  // Convert to HRESULT
                      goto Cleanup;
                  } // if: error copying the security descriptor
              } // if: got SD group successfully
          } // if: got SD owner successfully
      } // if: retrieved or built SD successfully
  
  #ifdef _DEBUG
      if ( m_psec != NULL )
      {
          ASSERT( IsValidSecurityDescriptor( m_psec ) );
      }
  #endif
  
  Cleanup:
      return hr;
  
  } //*** CClusterSecurityPage::HrGetSecurityDescriptor()
  
  /////////////////////////////////////////////////////////////////////////////
  //++
  //
  //  CClusterSecurityPage::HrSetSecurityDescriptor
  //
  //  Routine Description:
  //      Save the new security descriptor to the cluster database.
  //
  //  Arguments:
  //      psec    [IN]    the new security descriptor
  //
  //  Return Value:
  //      hr
  //
  //--
  /////////////////////////////////////////////////////////////////////////////
  HRESULT CClusterSecurityPage::HrSetSecurityDescriptor(
      IN PSECURITY_DESCRIPTOR psec
      )
  {
      ASSERT( psec != NULL );
      AFX_MANAGE_STATE( ::AfxGetStaticModuleState() );
  
      HRESULT hr = S_OK;
  
      try
      {
          if ( psec != NULL )
          {
              CWaitCursor wc;
  
              ASSERT( IsValidSecurityDescriptor( psec ) );
              if ( IsValidSecurityDescriptor( psec ) )
              {
                  hr = HrSetSDOwner( psec );
                  if ( SUCCEEDED( hr ) )
                  {
                      hr = HrSetSDGroup( psec );
                      if ( SUCCEEDED( hr ) )
                      {
                          LocalFree( m_psecPrev );
                          m_psecPrev = NULL;
  
                          if ( m_psec == NULL )
                          {
                              m_psecPrev = NULL;
                          } // if: no previous value
                          else
                          {
                              m_psecPrev = ClRtlCopySecurityDescriptor( m_psec );
                              if ( m_psecPrev == NULL )
                              {
                                  hr = GetLastError();            // Get the last error
                                  TRACE( _T( "CClusterSecurityPage::HrSetSecurityDescriptor() - Error %08.8x copying the previous SD.\n" ), hr );
                                  hr = HRESULT_FROM_WIN32( hr );  // Convert to HRESULT
                                  goto Cleanup;
                              } // if: error copying the security descriptor
                          } // else: previous value exists
  
                          LocalFree( m_psec );
                          m_psec = NULL;
  
                          m_psec = ClRtlCopySecurityDescriptor( psec );
                          if ( m_psec == NULL )
                          {
                              hr = GetLastError();            // Get the last error
                              TRACE( _T( "CClusterSecurityPage::HrSetSecurityDescriptor() - Error %08.8x copying the new SD.\n" ), hr );
                              hr = HRESULT_FROM_WIN32( hr );  // Convert to HRESULT
                              goto Cleanup;
                          } // if: error copying the security descriptor
  
                          SetPermissions( m_psec );
                      } // if: SD group set successfully
                  } // if: SD owner set successfully
              } // if: security descriptor is valid
              else
              {
                  hr = HRESULT_FROM_WIN32( ERROR_INVALID_SECURITY_DESCR );
                  TRACE( _T( "CClusterSecurityPage::HrSetSecurityDescriptor() - Invalid security descriptor.\n" ) );
              } // else: invalid security descriptor
          } // if: security descriptor specified
          else
          {
              hr = HRESULT_FROM_WIN32( ERROR_INVALID_SECURITY_DESCR );
          } // else: no security descriptor specified
      } // try
      catch ( ... )
      {
          hr = E_FAIL;
          TRACE( _T( "CClusterSecurityPage::HrSetSecurityDescriptor() - Unknown error occurred.\n" ) );
      }
  
  Cleanup:
      return hr;
  
  }  //*** CClusterSecurityPage::HrSetSecurityDescriptor()
  
  /////////////////////////////////////////////////////////////////////////////
  //++
  //
  //  CClusterSecurityPage::SetPermissions
  //
  //  Routine Description:
  //      Set the permissions for accessing the cluster.
  //
  //  Arguments:
  //      psec            [IN] Security descriptor.
  //
  //  Return Value:
  //      None.
  //
  //  Exceptions Thrown:
  //      Any exceptions thrown by CClusterItem::WriteValue().
  //--
  /////////////////////////////////////////////////////////////////////////////
  void CClusterSecurityPage::SetPermissions(
      IN const PSECURITY_DESCRIPTOR psec
  )
  {
      ASSERT( psec != NULL );
      ASSERT( IsValidSecurityDescriptor( psec ) );
  
      DWORD       cbNew;
      DWORD       cbOld;
      LPBYTE      psecPrev;       // buffer for use by ScWriteValue.  Prev SD is saved elsewhere now.
  
      // Get the length of the two security descriptors.
      if ( m_psecPrev == NULL )
      {
          cbOld = 0;
      }
      else
      {
          cbOld = ::GetSecurityDescriptorLength( m_psecPrev );
      }
  
      if ( psec == NULL )
      {
          cbNew = 0;
      }
      else
      {
          cbNew = ::GetSecurityDescriptorLength( psec );
      }
  
      // Allocate a new buffer for the previous data pointer.
      try
      {
          psecPrev = new BYTE [cbOld];
          if ( psecPrev == NULL )
          {
              return;
          } // if: error allocating previous data buffer
      }
      catch ( CMemoryException * )
      {
          return;
      }  // catch:  CMemoryException
      ::CopyMemory( psecPrev, m_psecPrev, cbOld );
  
      ScWriteValue( CLUSREG_NAME_CLUS_SD, (LPBYTE) psec, cbNew, (LPBYTE *) &psecPrev, cbOld, m_hkey );
  
      //
      //  Convert the NT5 SD to one that is compatible with the ACLEdit stuff on
      //  NT4.  If that conversion fails then don't write it to the cluster DB.
      //
  
      PSECURITY_DESCRIPTOR psd = NULL;
  
      psd = ClRtlConvertClusterSDToNT4Format( psec );
      if ( psd != NULL )
      {
          ScWriteValue( CLUSREG_NAME_CLUS_SECURITY, (LPBYTE) psd, cbNew, (LPBYTE *) &psecPrev, cbOld, m_hkey );
          ::LocalFree( psd );
      } // if:
  
      delete [] psecPrev;
  
  }  //*** CClusterSecurityPage::SetPermissions()
  
  /////////////////////////////////////////////////////////////////////////////
  //++
  //
  //  CClusterSecurityPage::HrGetSDOwner
  //
  //  Routine Description:
  //      Get the owner sid and save it.
  //
  //  Arguments:
  //      psec            [IN] Security descriptor.
  //
  //  Return Value:
  //      hr
  //
  //--
  /////////////////////////////////////////////////////////////////////////////
  HRESULT CClusterSecurityPage::HrGetSDOwner(
      IN const PSECURITY_DESCRIPTOR psec
      )
  {
      HRESULT hr      = S_OK;
      DWORD   sc;
      PSID    pOwner  = NULL;
  
      if ( ::GetSecurityDescriptorOwner( psec, &pOwner, &m_fOwnerDef ) != 0 )
      {
          // The security descriptor does not have an owner.
          if ( pOwner == NULL )
          {
              ::LocalFree( m_pOwner );
              m_pOwner = NULL;
          }
          else
          {
              DWORD   dwLen = ::GetLengthSid( pOwner );
  
              // copy the sid since AclUi will free the SD...
              hr = ::GetLastError();
              if ( SUCCEEDED( hr ) )
              {
                  ::LocalFree( m_pOwner );
  
                  m_pOwner = ::LocalAlloc( LMEM_ZEROINIT, dwLen );
                  if ( m_pOwner != NULL )
                  {
                      if ( ::CopySid( dwLen, m_pOwner, pOwner ) )
                      {
                          hr = S_OK;
                      }
                      else
                      {
                          sc = ::GetLastError();
                          hr = HRESULT_FROM_WIN32( sc );
                      }
                  }
                  else
                  {
                      sc = ::GetLastError();
                      hr = HRESULT_FROM_WIN32( sc );
                  }
              }
          }
      }
      else
      {
          sc = ::GetLastError();
          hr = HRESULT_FROM_WIN32( sc );
      }
  
      return( hr );
  
  }  //*** CClusterSecurityPage::HrGetSDOwner()
  
  /////////////////////////////////////////////////////////////////////////////
  //++
  //
  //  CClusterSecurityPage::HrGetSDGroup
  //
  //  Routine Description:
  //      Get the group sid and save it.
  //
  //  Arguments:
  //      psec            [IN] Security descriptor.
  //
  //  Return Value:
  //      None.
  //
  //--
  /////////////////////////////////////////////////////////////////////////////
  HRESULT CClusterSecurityPage::HrGetSDGroup(
      IN const PSECURITY_DESCRIPTOR psec
      )
  {
      HRESULT hr      = S_OK;
      DWORD   sc;
      PSID    pGroup  = NULL;
  
      if ( ::GetSecurityDescriptorOwner( psec, &pGroup, &m_fOwnerDef ) != 0 )
      {
          // This SID does not contain group information.
          if ( pGroup == NULL )
          {
              ::LocalFree( m_pGroup );
              m_pGroup = NULL;
          }
          else
          {
              DWORD   dwLen = ::GetLengthSid( pGroup );
  
              // copy the sid since AclUi will free the SD...
              hr = ::GetLastError();
              if ( SUCCEEDED( hr ) )
              {
                  ::LocalFree( m_pGroup );
                  m_pGroup = ::LocalAlloc( LMEM_ZEROINIT, dwLen );
                  if ( m_pGroup != NULL )
                  {
                      if ( ::CopySid( dwLen, m_pGroup, pGroup ) )
                      {
                          hr = S_OK;
                      }
                      else
                      {
                          sc = ::GetLastError();
                          hr = HRESULT_FROM_WIN32( sc );
                      }
                  }
                  else
                  {
                      sc = ::GetLastError();
                      hr = HRESULT_FROM_WIN32( sc );
                  }
              }
          }
      }
      else
      {
          sc = ::GetLastError();
          hr = HRESULT_FROM_WIN32( sc );
      }
  
      return( hr );
  
  }  //*** CClusterSecurityPage::HrGetSDGroup()
  
  /////////////////////////////////////////////////////////////////////////////
  //++
  //
  //  CClusterSecurityPage::HrSetSDOwner
  //
  //  Routine Description:
  //      Set the owner sid.
  //
  //  Arguments:
  //      psec            [IN] Security descriptor.
  //
  //  Return Value:
  //      None.
  //
  //--
  /////////////////////////////////////////////////////////////////////////////
  HRESULT CClusterSecurityPage::HrSetSDOwner(
      IN PSECURITY_DESCRIPTOR psec
      )
  {
      HRESULT hr = S_OK;
  
      if ( !::SetSecurityDescriptorOwner( psec, m_pOwner, m_fOwnerDef ) )
      {
          DWORD sc = ::GetLastError();
          hr = HRESULT_FROM_WIN32( sc );
      }
  
      return( hr );
  
  }  //*** CClusterSecurityPage::HrSetSDOwner()
  
  /////////////////////////////////////////////////////////////////////////////
  //++
  //
  //  CClusterSecurityPage::HrSetSDGroup
  //
  //  Routine Description:
  //      Set the group sid.
  //
  //  Arguments:
  //      psec            [IN] Security descriptor.
  //
  //  Return Value:
  //      None.
  //
  //--
  /////////////////////////////////////////////////////////////////////////////
  HRESULT CClusterSecurityPage::HrSetSDGroup(
      IN PSECURITY_DESCRIPTOR psec
      )
  {
      HRESULT hr = S_OK;
  
      if ( !::SetSecurityDescriptorGroup( psec, m_pGroup, m_fGroupDef ) )
      {
          DWORD sc = ::GetLastError();
          hr = HRESULT_FROM_WIN32( sc );
      }
  
      return( hr );
  
  }  //*** CClusterSecurityPage::HrSetSDGroup()
  
  /////////////////////////////////////////////////////////////////////////////
  //++
  //
  //  CClusterSecurityPage::HrGetSDFromClusterDB
  //
  //  Routine Description:
  //      Retrieve the SD from the cluster database.
  //
  //  Arguments:
  //      ppsec           [OUT] Pointer to security descriptor.
  //
  //  Return Value:
  //      S_OK for success
  //      Any error returned by ScReadValue
  //
  //--
  /////////////////////////////////////////////////////////////////////////////
  HRESULT CClusterSecurityPage::HrGetSDFromClusterDB(
      OUT PSECURITY_DESCRIPTOR * ppsec
      )
  {
      AFX_MANAGE_STATE( ::AfxGetStaticModuleState() );
      ASSERT( ppsec != NULL );
  
      HRESULT                 hr = E_FAIL;
      PSECURITY_DESCRIPTOR    psd = NULL;
  
      if ( ppsec != NULL )
      {
          DWORD sc;
  
          // Read the security descriptor.
          sc = ScReadValue( CLUSREG_NAME_CLUS_SD, (LPBYTE *) &psd, m_hkey ); //alloc using new
          hr = HRESULT_FROM_WIN32( sc );
  
          if ( FAILED( hr ) || ( psd == NULL ) )
          {   // try getting the NT4 SD...
              sc = ScReadValue( CLUSREG_NAME_CLUS_SECURITY, (LPBYTE *) &psd, m_hkey ); //alloc using new
              hr = HRESULT_FROM_WIN32( sc );
  
              if ( SUCCEEDED( hr ) )
              {
                  *ppsec = ::ClRtlConvertClusterSDToNT5Format( psd );
              }
          }
          else
          {
              *ppsec = ClRtlCopySecurityDescriptor( psd );
              if ( *ppsec == NULL )
              {
                  hr = GetLastError();            // Get the last error
                  hr = HRESULT_FROM_WIN32( hr );  // Convert to HRESULT
              } // if: error copying the security descriptor
          }
  
          delete [] psd;
  
          if ( *ppsec != NULL )
          {
              ::ClRtlExamineSD( *ppsec, "[ClusPage]" );
          } // if: security descriptor is available to be examined
      }
  
      return hr;
  
  }  //*** CClusterSecurityPage::HrGetSDFromClusterDB
  