/*
   Copyright (C) 2009 Red Hat, Inc.

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/

#ifndef _H_SECURITY
#define _H_SECURITY

#include <aclapi.h>

//gets user-only-access security attributes. returns 0 on success, error code on failure.
//user is responsible to LocalFree(dacl).
static DWORD get_security_attributes(SECURITY_ATTRIBUTES* psa, SECURITY_DESCRIPTOR* psd, PACL* ppdacl)
{
    EXPLICIT_ACCESS ea;
    TRUSTEE trst;
    DWORD ret = 0;

    ZeroMemory(psa, sizeof(*psa));
    ZeroMemory(psd, sizeof(*psd));
    psa->nLength = sizeof(*psa);
    psa->bInheritHandle = false;
    psa->lpSecurityDescriptor = psd;

    ZeroMemory(&trst, sizeof(trst));
    trst.pMultipleTrustee = NULL;
    trst.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
    trst.TrusteeForm = TRUSTEE_IS_NAME;
    trst.TrusteeType = TRUSTEE_IS_USER;
    trst.ptstrName = L"CURRENT_USER";

    ZeroMemory(&ea, sizeof(ea));
    ea.grfAccessPermissions = GENERIC_WRITE | GENERIC_READ;
    ea.grfAccessMode = SET_ACCESS;
    ea.grfInheritance = NO_INHERITANCE;
    ea.Trustee = trst;

    ret = SetEntriesInAcl(1, &ea, NULL, ppdacl);
    if (ret != ERROR_SUCCESS) {
        return ret;
    }
    if (!ret && !InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION)) {
        ret = GetLastError();
    }
    if (!ret && !SetSecurityDescriptorDacl(psd, TRUE, *ppdacl, FALSE)) {
        ret = GetLastError();
    }
    return ret;
}

static int get_sid(HANDLE handle, PSID* ppsid, PSECURITY_DESCRIPTOR* ppsec_desc)
{
    DWORD ret = GetSecurityInfo(handle, SE_KERNEL_OBJECT, OWNER_SECURITY_INFORMATION,
                                ppsid, NULL, NULL, NULL, ppsec_desc);
    if (ret != ERROR_SUCCESS) {
        return ret;
    }
    if (!IsValidSid(*ppsid)) {
        return -1;
    }
    return 0;
}

//checks whether the handle owner is the current user.
static bool is_same_user(HANDLE handle)
{
    PSECURITY_DESCRIPTOR psec_desc_handle = NULL;
    PSECURITY_DESCRIPTOR psec_desc_user = NULL;
    PSID psid_handle;
    PSID psid_user;
    bool ret;
    
    ret = !get_sid(handle, &psid_handle, &psec_desc_handle) &&
          !get_sid(GetCurrentProcess(), &psid_user, &psec_desc_user) &&
          EqualSid(psid_handle, psid_user);
    LocalFree(psec_desc_handle);
    LocalFree(psec_desc_user);
    return ret;
}

#endif
