//+-------------------------------------------------------------------------
//
//  Microsoft Windows
//
//  Copyright (C) Microsoft Corporation, 1996 - 1999
//
//  File:       owner.cpp
//
//  This file contains the implementation of the Owner page.
//
//--------------------------------------------------------------------------
#include "aclpriv.h"
#include <initguid.h> // needed to get the GUIDs defined in oleacc.h
#include <oleacc.h> // contains IAccProp* definitions



//Context Help IDs
const static DWORD aEffHelpIDs[] =
{
    IDC_EFF_NAME_STATIC,        IDH_EFF_NAME,
    IDC_EFF_NAME,               IDH_EFF_NAME,
    IDC_EFF_SELECT,             IDH_EFF_SELECT,
    IDC_EFF_PERMISSION_STATIC,  IDH_EFF_PERM_LIST,
    IDC_EFF_PERM_LIST,          IDH_EFF_PERM_LIST,
    IDC_EFF_STATIC,             -1,
    0, 0
};


LPCWSTR g_ListStateMap = 
    L"A:0"
    L":0:0x50" // checked, disabled - STATE_SYSTEM_READONLY | STATE_SYSTEM_CHECKED
    L":1:0x40" // disabled - STATE_SYSTEM_READONLY
    L":";


LPCWSTR g_ListRoleMap = 
    L"A:0"
    L":0:0x2C" // checkbox - ROLE_SYSTEM_CHECKBUTTON (ie. checkbox)
    L":1:0x2C"
    L":";


int LV_ADDITEM(HWND hwndList, 
               LPCTSTR pszName, 
               int index, 
               PSI_ACCESS pAccess, 
               BOOL bChecked)
{
    LVITEM lvItem;    
    TraceAssert(pAccess != NULL);
    TraceAssert(pszName != NULL);

    lvItem.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
    lvItem.iItem = index;
    lvItem.iSubItem = 0;
    lvItem.pszText = (LPTSTR)pszName;
    lvItem.lParam = (LPARAM)pAccess;
    lvItem.iImage = bChecked ? 0 : 1;

    // Insert item into list
    index = ListView_InsertItem(hwndList, &lvItem);
    ListView_SetCheckState(hwndList,index,bChecked);
    
    return index;
}

typedef struct _EffCacheItem
{    
    POBJECT_TYPE_LIST pObjectTypeList;
    ULONG cObjectTypeListLength;
    PACCESS_MASK pGrantedAccessList;
    PSID pSid;
}EFFCACHEITEM,*PEFFCACHEITEM;


//This Function checks is pAccess is granted.
BOOL IsChecked( PSI_ACCESS pAccess,
                PEFFCACHEITEM pCacheItem)
{
    TraceEnter(TRACE_EFFPERM, "IsChecked");
    TraceAssert(pCacheItem != NULL);
    TraceAssert(pAccess != NULL);

    POBJECT_TYPE_LIST pObjectTypeList = pCacheItem->pObjectTypeList;
    ULONG cObjectTypeListLength = pCacheItem->cObjectTypeListLength;
    PACCESS_MASK pGrantedAccessList = pCacheItem->pGrantedAccessList;

    //0th Grant is for full object. 
    if( (pAccess->mask & pGrantedAccessList[0]) == pAccess->mask )
        return TRUE;

    BOOL bGuidNULL = pAccess->pguid ?IsEqualGUID(*(pAccess->pguid), GUID_NULL): TRUE;
    LPGUID pguid;        

    for( UINT i = 1; i < cObjectTypeListLength; ++i )
    {
        pguid = pObjectTypeList[i].ObjectType;
        if( pguid == NULL ||
            IsEqualGUID(*pguid, GUID_NULL) ||
            (!bGuidNULL && IsEqualGUID(*pguid,*(pAccess->pguid))) )
        {
            if( (pAccess->mask & pGrantedAccessList[i]) == pAccess->mask )
                return TRUE;
        }
    }
    return FALSE;
}



class CEffPage: public CSecurityPage
{
public:
    CEffPage(LPSECURITYINFO psi, SI_OBJECT_INFO *psiObjectInfo);
    virtual ~CEffPage();

private:
    virtual BOOL DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
    BOOL InitDlg(HWND hDlg);
    void OnSelect(HWND hDlg);
    void InitListBox(HWND hDlg);
    HRESULT GetEffectivePerm(PSID pSid, PEFFCACHEITEM *ppCacheItem);
    PSID GetSelectedSID(){ return m_pSid; }

private:
    PSID m_pSid;    //Sid of the security principal for which permissions are displayed
   
    PSI_ACCESS m_pAccess;
    ULONG m_cAccesses;
};


HPROPSHEETPAGE
CreateEffectivePermPage(LPSECURITYINFO psi, SI_OBJECT_INFO *psiObjectInfo)
{
    HPROPSHEETPAGE hPage = NULL;
    CEffPage *pPage;
    
    TraceEnter(TRACE_EFFPERM, "CreateEffectivePermPage");
    TraceAssert(psi!=NULL);
    TraceAssert(psiObjectInfo);

    pPage = new CEffPage(psi, psiObjectInfo);

    if (pPage)
    {
        hPage = pPage->CreatePropSheetPage(MAKEINTRESOURCE(IDD_EFFECTIVE_PERM_PAGE));

        if (!hPage)
            delete pPage;
    }

    TraceLeaveValue(hPage);
}


CEffPage::CEffPage(LPSECURITYINFO psi, SI_OBJECT_INFO *psiObjectInfo)
: CSecurityPage(psi, SI_PAGE_OWNER) , m_pSid(NULL),
  m_pAccess(NULL), m_cAccesses(0)
{
    // Lookup known SIDs asynchronously so the dialog
    // will initialize faster
}

CEffPage::~CEffPage()
{
    if (m_pSid)
        LocalFree(m_pSid);
}
BOOL 
CEffPage::DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    BOOL bResult = TRUE;
    LPPSHNOTIFY lpsn;
    switch(uMsg)
    {
    case WM_INITDIALOG:
        InitDlg(hDlg);
        break;


    case WM_COMMAND:
        switch (GET_WM_COMMAND_ID(wParam, lParam))
        {
        case IDC_EFF_SELECT:
            OnSelect(hDlg);
            break;
        default:
            bResult = FALSE;
        }
        break;

    case WM_HELP:
        if (IsWindowEnabled(hDlg))
        {
            WinHelp((HWND)((LPHELPINFO)lParam)->hItemHandle,
                            c_szAcluiHelpFile,
                            HELP_WM_HELP,
                            (DWORD_PTR)aEffHelpIDs);
        }
        break;

    case WM_CONTEXTMENU:
        if (IsWindowEnabled(hDlg))
        {
            WinHelp(hDlg,
                    c_szAcluiHelpFile,
                    HELP_CONTEXTMENU,
                    (DWORD_PTR)aEffHelpIDs);
        }
        break;
    case PSM_QUERYSIBLINGS:
        if(GetSelectedSID())
            InitListBox(hDlg);                
        break;

    default:
        bResult = FALSE;
    }

    return bResult;
}


BOOL
CEffPage::InitDlg( HWND hDlg )
{

    HWND hwndList;
    RECT rc;
    LV_COLUMN col;
    TCHAR szBuffer[MAX_COLUMN_CHARS];
    HRESULT hr = S_OK;
    ULONG iDefaultAccess;
    HCURSOR hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));

    TraceEnter(TRACE_EFFPERM, "CEffPage::InitDlg");
    TraceAssert(hDlg != NULL);
    TraceAssert(m_psi != NULL);
    TraceAssert(m_pei != NULL);

    hwndList = GetDlgItem(hDlg, IDC_EFF_PERM_LIST);

    //
    // Create & set the image list for the listview.  If there is a
    // problem CreateSidImageList will return NULL which won't hurt
    // anything. In that case we'll just continue without an image list.
    //
    ListView_SetImageList(hwndList,
                          LoadImageList(::hModule, MAKEINTRESOURCE(IDB_CHECKBOX)),
                          LVSIL_SMALL);


    // Set extended LV style for whole line selection with InfoTips
    ListView_SetExtendedListViewStyleEx(hwndList,
                                        LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP, 
                                        LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP);


	IAccPropServices * pAccPropSvc = NULL;
	hr = CoCreateInstance( CLSID_AccPropServices, NULL, CLSCTX_SERVER, IID_IAccPropServices, (void **) & pAccPropSvc );
	if( hr == S_OK && pAccPropSvc )
	{
		// Don't have to check HRESULT here, since if they fail we just ignore anyway,
		// but may want to log it while debugging.
		pAccPropSvc->SetHwndPropStr(hwndList, OBJID_CLIENT, 0, PROPID_ACC_ROLEMAP, g_ListRoleMap );
		pAccPropSvc->SetHwndPropStr(hwndList, OBJID_CLIENT, 0, PROPID_ACC_STATEMAP, g_ListStateMap );
		pAccPropSvc->Release();
	}



    //
    // Add appropriate listview columns
    //
    GetClientRect(hwndList, &rc);

    LoadString(::hModule, IDS_PERMISSIONS, szBuffer, ARRAYSIZE(szBuffer));
    col.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM | LVCF_WIDTH;
    col.fmt = LVCFMT_LEFT;
    col.pszText = szBuffer;
    col.iSubItem = 0;
    col.cx = rc.right - GetSystemMetrics(SM_CXVSCROLL);
    ListView_InsertColumn(hwndList, 0, &col);


    //Get the access Rights
    hr = m_psi->GetAccessRights(&GUID_NULL,
                                SI_ADVANCED|SI_EDIT_EFFECTIVE,
                                &m_pAccess,
                                &m_cAccesses,
                                &iDefaultAccess);
    FailGracefully(hr, "GetAccessRights Failed");    
    //Initialize the List box
    InitListBox(hDlg);

exit_gracefully:


    SetCursor(hcur);

    if (FAILED(hr))
    {
        HWND hwnd;
        // Hide and disable everything
        for (hwnd = GetWindow(hDlg, GW_CHILD);
             hwnd != NULL;
             hwnd = GetWindow(hwnd, GW_HWNDNEXT))
        {
            ShowWindow(hwnd, SW_HIDE);
            EnableWindow(hwnd, FALSE);
        }

        // Enable and show the "No Security" message
        hwnd = GetDlgItem(hDlg, IDC_NO_EFFECTIVE);
        EnableWindow(hwnd, TRUE);
        ShowWindow(hwnd, SW_SHOW);
    }

    TraceLeaveValue(TRUE);
}

VOID
CEffPage::OnSelect(HWND hDlg)
{
    PUSER_LIST pUserList = NULL;
    LPEFFECTIVEPERMISSION pei;
    HRESULT hr = S_OK;

    TraceEnter(TRACE_EFFPERM, "CEffPage::OnSelect");

    if (S_OK == GetUserGroup(hDlg, FALSE, &pUserList))
    {
        TraceAssert(NULL != pUserList);
        TraceAssert(1 == pUserList->cUsers);

        // Free up previous sid
        if (m_pSid)
            LocalFree(m_pSid);

        // Copy the new sid
        m_pSid = LocalAllocSid(pUserList->rgUsers[0].pSid);
        if (m_pSid)
        {
            SetDlgItemText(hDlg, IDC_EFF_NAME, pUserList->rgUsers[0].pszName);
        }
        LocalFree(pUserList);
        InitListBox(hDlg); 
    }    
}


VOID
CEffPage::InitListBox(HWND hDlg)
{
    HWND hwndList;
    BOOL bProperties;

    PSI_ACCESS pAccess;
    ULONG cAccesses;
    DWORD dwType;
    TCHAR szName[MAX_PATH];
    PSID pSid = NULL;
    PEFFCACHEITEM pCacheItem = NULL; 
    int index;
    TraceEnter(TRACE_EFFPERM, "CEffPage::InitListBox");
    TraceAssert( m_pAccess != NULL );
    TraceAssert(m_cAccesses != 0 );

    HRESULT hr = S_OK;
    hwndList = GetDlgItem(hDlg, IDC_EFF_PERM_LIST);

    if(!IsWindowEnabled(hwndList))
    {        
        //Hide Error Message
        HWND hwnd = GetDlgItem(hDlg, IDC_EFF_ERROR);
        EnableWindow(hwnd, FALSE);
        ShowWindow(hwnd, SW_HIDE);
        //Show List box
        EnableWindow(hwndList, TRUE);
        ShowWindow(hwndList, SW_SHOW);
    }

    //Clear all items
    ListView_DeleteAllItems(hwndList);

    pAccess = m_pAccess;
    cAccesses = m_cAccesses;
    dwType = SI_ACCESS_SPECIFIC | SI_ACCESS_PROPERTY;
    
    //Get the current sid
    pSid = GetSelectedSID();
    if( pSid )
    {
        hr = GetEffectivePerm(pSid, &pCacheItem);
        FailGracefully(hr,"GetEffectivePermission Failed");
    }

    index = 0;        
    // Enumerate the permissions and add to the checklist
    ULONG i;
    for (i = 0; i < cAccesses; i++, pAccess++)
    {
        LPCTSTR pszName;

        // Only add permissions that have any of the flags specified in dwType
        if (!(pAccess->dwFlags & dwType))
            continue;

        //Don't Add Permission which have inherit only on
        if( pAccess->dwFlags & INHERIT_ONLY_ACE )
            continue;

        pszName = pAccess->pszName;
        if (IS_INTRESOURCE(pszName))
        {
            TraceAssert(m_siObjectInfo.hInstance != NULL);

            if (LoadString(m_siObjectInfo.hInstance,
                           (UINT)((ULONG_PTR)pszName),
                           szName,
                           ARRAYSIZE(szName)) == 0)
            {
                LoadString(::hModule,
                           IDS_UNKNOWN,
                           szName,
                           ARRAYSIZE(szName));
            }
            pszName = szName;
        }
        
        BOOL bChecked = FALSE;
        if(pSid)
        {
            bChecked = IsChecked( pAccess, pCacheItem );
        }
        index = LV_ADDITEM( hwndList, pszName, index, pAccess, bChecked);
        index++;
    }    
    if(index)
    {
        SelectListViewItem(hwndList, 0);
        // Redraw the list
        SendMessage(hwndList, WM_SETREDRAW, TRUE, 0);
        ListView_RedrawItems(hwndList, 0, -1);
    }



exit_gracefully:
    if(pCacheItem)
    {
        if(pCacheItem->pGrantedAccessList)
            LocalFree(pCacheItem->pGrantedAccessList);
        LocalFree(pCacheItem);
    }
    if(FAILED(hr))
    {
        //Hide List box
        HWND hwnd = GetDlgItem(hDlg, IDC_EFF_PERM_LIST);
        EnableWindow(hwnd, FALSE);
        ShowWindow(hwnd, SW_HIDE);
        
        //Format Error Message To Display
        WCHAR buffer[MAX_PATH];
        LPWSTR pszCaption = NULL;
        GetWindowText(GetDlgItem(hDlg, IDC_EFF_NAME),
                      buffer, 
                      MAX_PATH-1);
        FormatStringID(&pszCaption, ::hModule, IDS_EFF_ERROR, buffer);
        
        //Show Error Message
        hwnd = GetDlgItem(hDlg, IDC_EFF_ERROR);
        EnableWindow(hwnd, TRUE);
        SetWindowText(hwnd,pszCaption);
        ShowWindow(hwnd, SW_SHOW);
        LocalFreeString(&pszCaption);
    }
    TraceLeaveVoid();
}

//Calling function frees *ppCacheItem->pGrantedAccessList
//and *ppCacheItem

HRESULT
CEffPage::GetEffectivePerm(PSID pSid,
                           PEFFCACHEITEM *ppCacheItem )
{
    PSECURITY_DESCRIPTOR pSD;
    
    HRESULT hr = S_OK;
    ULONG cItems = 0;
    PEFFCACHEITEM pCacheTemp = NULL;

    TraceEnter(TRACE_EFFPERM, "CEffPage::GetEffectivePerm");
    TraceAssert(pSid != NULL);
    TraceAssert(ppCacheItem != NULL);

    pCacheTemp = (PEFFCACHEITEM)LocalAlloc( LPTR, sizeof(EFFCACHEITEM) + GetLengthSid(pSid));
    
    if(!pCacheTemp)
        ExitGracefully(hr, E_OUTOFMEMORY, "Lcoal Alloc Failed");
    pCacheTemp->pSid = (PSID)(pCacheTemp + 1);
    CopySid(GetLengthSid(pSid), pCacheTemp->pSid, pSid);

    
    if(m_psi)
    {
        hr = m_psi->GetSecurity(OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
                                &pSD,
                                FALSE);
        FailGracefully(hr, "GetSecurity Failed");
    }
    
    if( m_pei)
    {
        DWORD dwTemp;
        hr = m_pei->GetEffectivePermission(&(m_siObjectInfo.guidObjectType),
                                           pCacheTemp->pSid,
                                           m_siObjectInfo.pszServerName,
                                           //NULL,
                                           pSD,
                                           &(pCacheTemp->pObjectTypeList),
                                           &(pCacheTemp->cObjectTypeListLength),
                                           &(pCacheTemp->pGrantedAccessList),
                                           &dwTemp);
        if(SUCCEEDED(hr))
        {
            if(!pCacheTemp->pObjectTypeList || !pCacheTemp->pGrantedAccessList)
                hr = E_FAIL;
        }

        FailGracefully(hr, "GetEffectivePermission Failed");
        
    }
exit_gracefully:
    
    if( !SUCCEEDED(hr) )
    {
        LocalFree(pCacheTemp);
        pCacheTemp = NULL;
    }
    *ppCacheItem = pCacheTemp;

    TraceLeaveResult(hr);
}