/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*-
 * ex: set softtabstop=4 tabstop=8 expandtab shiftwidth=4: *
 * Editor Settings: expandtabs and use 4 spaces for indentation */

/*
 * Copyright Likewise Software    2004-2010
 * All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 *
 * This program 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 General Public License
 * for more details.  You should have received a copy of the GNU General
 * Public License along with this program.  If not, see
 * <http://www.gnu.org/licenses/>.
 *
 * LIKEWISE SOFTWARE MAKES THIS SOFTWARE AVAILABLE UNDER OTHER LICENSING
 * TERMS AS WELL.  IF YOU HAVE ENTERED INTO A SEPARATE LICENSE AGREEMENT
 * WITH LIKEWISE SOFTWARE, THEN YOU MAY ELECT TO USE THE SOFTWARE UNDER THE
 * TERMS OF THAT SOFTWARE LICENSE AGREEMENT INSTEAD OF THE TERMS OF THE GNU
 * GENERAL PUBLIC LICENSE, NOTWITHSTANDING THE ABOVE NOTICE.  IF YOU
 * HAVE QUESTIONS, OR WISH TO REQUEST A COPY OF THE ALTERNATE LICENSING
 * TERMS OFFERED BY LIKEWISE SOFTWARE, PLEASE CONTACT LIKEWISE SOFTWARE AT
 * license@likewisesoftware.com
 */

/*
 * Copyright (C) Likewise Software. All rights reserved.
 *
 * Module Name:
 *
 *        lpsecurity.c
 *
 * Abstract:
 *
 *        Likewise Security and Authentication Subsystem (LSASS)
 *
 *        Local Authentication Provider
 *
 *        Account security descriptor functions
 *
 * Authors: Rafal Szczesniak (rafal@likewise.com)
 */

#include "includes.h"


DWORD
LocalDirAllocateAbsoluteFromSelfRelativeSD(
    IN PSECURITY_DESCRIPTOR_RELATIVE pSecurityDescRelative,
    OUT PSECURITY_DESCRIPTOR_ABSOLUTE *ppSecurityDesc
    )
{
    DWORD err = ERROR_SUCCESS;
    NTSTATUS ntStatus = STATUS_SUCCESS;
    PSECURITY_DESCRIPTOR_ABSOLUTE pSecurityDesc = NULL;
    DWORD securityDescSize = 0;
    PACL pDacl = NULL;
    DWORD daclSize = 0;
    PACL pSacl = NULL;
    DWORD saclSize = 0;
    PSID pOwnerSid = NULL;
    DWORD ownerSidSize = 0;
    PSID pGroupSid = NULL;
    DWORD groupSidSize = 0;

    ntStatus = RtlSelfRelativeToAbsoluteSD(
                        pSecurityDescRelative,
                        pSecurityDesc,
                        &securityDescSize,
                        pDacl,
                        &daclSize,
                        pSacl,
                        &saclSize,
                        pOwnerSid,
                        &ownerSidSize,
                        pGroupSid,
                        &groupSidSize);
    if (ntStatus == STATUS_BUFFER_TOO_SMALL)
    {
        ntStatus = STATUS_SUCCESS;
    }
    else if (ntStatus != STATUS_SUCCESS)
    {
        BAIL_ON_NT_STATUS(ntStatus);
    }

    err = LwAllocateMemory(
                        securityDescSize,
                        OUT_PPVOID(&pSecurityDesc));
    BAIL_ON_LSA_ERROR(err);

    if (daclSize)
    {
        err = LwAllocateMemory(
                            daclSize,
                            OUT_PPVOID(&pDacl));
        BAIL_ON_LSA_ERROR(err);
    }

    if (saclSize)
    {
        err = LwAllocateMemory(
                            saclSize,
                            OUT_PPVOID(&pSacl));
        BAIL_ON_LSA_ERROR(err);
    }

    if (ownerSidSize)
    {
        err = LwAllocateMemory(
                            ownerSidSize,
                            OUT_PPVOID(&pOwnerSid));
        BAIL_ON_LSA_ERROR(err);
    }

    if (groupSidSize)
    {
        err = LwAllocateMemory(
                            groupSidSize,
                            OUT_PPVOID(&pGroupSid));
        BAIL_ON_LSA_ERROR(err);
    }

    ntStatus = RtlSelfRelativeToAbsoluteSD(
                        pSecurityDescRelative,
                        pSecurityDesc,
                        &securityDescSize,
                        pDacl,
                        &daclSize,
                        pSacl,
                        &saclSize,
                        pOwnerSid,
                        &ownerSidSize,
                        pGroupSid,
                        &groupSidSize);
    BAIL_ON_NT_STATUS(ntStatus);

    *ppSecurityDesc = pSecurityDesc;

error:
    if (err == ERROR_SUCCESS &&
        ntStatus != STATUS_SUCCESS)
    {
        err = LwNtStatusToWin32Error(ntStatus);
    }

    if (err)
    {
        LocalDirFreeSecurityDescriptor(&pSecurityDesc);
    }

    return err;
}


VOID
LocalDirFreeSecurityDescriptor(
    PSECURITY_DESCRIPTOR_ABSOLUTE *ppSecDesc
    )
{
    NTSTATUS ntStatus = STATUS_SUCCESS;
    PSECURITY_DESCRIPTOR_ABSOLUTE pSecDesc = NULL;
    PSID pOwnerSid = NULL;
    BOOLEAN bOwnerDefaulted = FALSE;
    PSID pPrimaryGroupSid = NULL;
    BOOLEAN bPrimaryGroupDefaulted = FALSE;
    PACL pDacl = NULL;
    BOOLEAN bDaclPresent = FALSE;
    BOOLEAN bDaclDefaulted = FALSE;
    PACL pSacl = NULL;
    BOOLEAN bSaclPresent = FALSE;
    BOOLEAN bSaclDefaulted = FALSE;

    if (ppSecDesc == NULL ||
        *ppSecDesc == NULL)
    {
        return;
    }

    pSecDesc = *ppSecDesc;

    ntStatus = RtlGetOwnerSecurityDescriptor(pSecDesc,
                                             &pOwnerSid,
                                             &bOwnerDefaulted);
    BAIL_ON_NT_STATUS(ntStatus);

    ntStatus = RtlGetGroupSecurityDescriptor(pSecDesc,
                                             &pPrimaryGroupSid,
                                             &bPrimaryGroupDefaulted);
    BAIL_ON_NT_STATUS(ntStatus);

    ntStatus = RtlGetDaclSecurityDescriptor(pSecDesc,
                                            &bDaclPresent,
                                            &pDacl,
                                            &bDaclDefaulted);
    BAIL_ON_NT_STATUS(ntStatus);

    ntStatus = RtlGetSaclSecurityDescriptor(pSecDesc,
                                            &bSaclPresent,
                                            &pSacl,
                                            &bSaclDefaulted);
    BAIL_ON_NT_STATUS(ntStatus);

error:
    LW_SAFE_FREE_MEMORY(pOwnerSid);
    LW_SAFE_FREE_MEMORY(pPrimaryGroupSid);

    if (bDaclPresent)
    {
        LW_SAFE_FREE_MEMORY(pDacl);
    }

    if (bSaclPresent)
    {
        LW_SAFE_FREE_MEMORY(pSacl);
    }

    LW_SAFE_FREE_MEMORY(pSecDesc);
    *ppSecDesc = NULL;
}
