/* Editor Settings: expandtabs and use 4 spaces for indentation
 * ex: set softtabstop=4 tabstop=8 expandtab shiftwidth=4: *
 */

/*
 * Copyright Likewise Software    2004-2009
 * All rights reserved.
 *
 * 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 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
 * LESSER 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:
 *
 *        samr_openaccount.c
 *
 * Abstract:
 *
 *        Remote Procedure Call (RPC) Server Interface
 *
 *        SamrOpenAccount function
 *
 * Authors: Rafal Szczesniak (rafal@likewise.com)
 */

#include "includes.h"


NTSTATUS
SamrSrvOpenAccount(
    IN  handle_t          hBinding,
    IN  DOMAIN_HANDLE     hDomain,
    IN  DWORD             dwAccessMask,
    IN  DWORD             dwRid,
    IN  SAMDB_OBJECT_TYPE ObjectType,
    OUT ACCOUNT_HANDLE   *phAccount
    )
{
    NTSTATUS ntStatus = STATUS_SUCCESS;
    DWORD dwError = ERROR_SUCCESS;
    SAMDB_QUERY query = {0};
    PSAMDB_OBJECT_INFO *ppObject = NULL;
    PSAMDB_OBJECT_INFO accountObject = NULL;
    PDOMAIN_CONTEXT pDomCtx = NULL;
    PCONNECT_CONTEXT pConnCtx = NULL;
    PACCOUNT_CONTEXT pAcctCtx = NULL;
    ULONG ulSidLength = 0;
    PSID pSid = NULL;
    PSID pDomainSid = NULL;
    SECURITY_INFORMATION securityInformation = 0;
    PSECURITY_DESCRIPTOR_RELATIVE pSecDescRelative = NULL;
    PSECURITY_DESCRIPTOR_ABSOLUTE pSecDescAbsolute = NULL;
    GENERIC_MAPPING GenericMapping = {0};
    DWORD dwAccessGranted = 0;
    PWSTR pwszAccountName = NULL;
    PSID pAccountSid = NULL;
    PWSTR description = NULL;
    DWORD dwAccountRid = 0;

    if (ObjectType != SAMDB_OBJECT_TYPE_USER &&
        ObjectType != SAMDB_OBJECT_TYPE_LOCAL_GROUP)
    {
        ntStatus = STATUS_INVALID_PARAMETER;
        BAIL_ON_NT_STATUS(ntStatus);
    }

    pDomCtx  = (PDOMAIN_CONTEXT)hDomain;
    pConnCtx = pDomCtx->pConnCtx;

    if (pDomCtx == NULL || pDomCtx->Type != SamrContextDomain)
    {
        ntStatus = STATUS_INVALID_HANDLE;
        BAIL_ON_NT_STATUS(ntStatus);
    }

    if (!(pDomCtx->dwAccessGranted & DOMAIN_ACCESS_OPEN_ACCOUNT))
    {
        ntStatus = STATUS_ACCESS_DENIED;
        BAIL_ON_NT_STATUS(ntStatus);
    }

    pDomainSid = pDomCtx->pDomainSid;

    dwError = LwAllocateMemory(sizeof(*pAcctCtx),
                               OUT_PPVOID(&pAcctCtx));
    BAIL_ON_LSA_ERROR(dwError);

    ulSidLength = RtlLengthRequiredSid(pDomainSid->SubAuthorityCount + 1);
    dwError = LwAllocateMemory(ulSidLength,
                               OUT_PPVOID(&pSid));
    BAIL_ON_LSA_ERROR(dwError);

    ntStatus = RtlCopySid(ulSidLength, pSid, pDomainSid);
    BAIL_ON_NT_STATUS(ntStatus);

    ntStatus = RtlAppendRidSid(ulSidLength, pSid, dwRid);
    BAIL_ON_NT_STATUS(ntStatus);

    query.Sid = pSid;

    dwError = SamDbFindObjects(ObjectType,
                               SAMDB_QUERY_TYPE_SID,
                               1,
                               &query,
                               &ppObject);
    accountObject = ppObject[0];
    if (accountObject == NULL)
    {
        ntStatus = STATUS_NO_SUCH_USER;
        BAIL_ON_NT_STATUS(ntStatus);
    }

    /*
     * Perform an access check
     */
    securityInformation =
        OWNER_SECURITY_INFORMATION |
        GROUP_SECURITY_INFORMATION |
        DACL_SECURITY_INFORMATION |
        SACL_SECURITY_INFORMATION;

    dwError = SamDbQuerySecurityDescriptor(
                                   pSid,
                                   securityInformation,
                                   &pSecDescRelative);
    BAIL_ON_LSA_ERROR(dwError);

    dwError = SamrSrvAllocateAbsoluteFromSelfRelativeSD(
                                   pSecDescRelative,
                                   &pSecDescAbsolute);
    BAIL_ON_LSA_ERROR(dwError);

    if (!RtlAccessCheck(pSecDescAbsolute,
                        pConnCtx->pUserToken,
                        dwAccessMask,
                        pAcctCtx->dwAccessGranted,
                        &GenericMapping,
                        &dwAccessGranted,
                        &ntStatus))
    {
        BAIL_ON_NT_STATUS(ntStatus);
    }

    // Copy the account name
    dwError = LwAllocateWc16String(&pwszAccountName, accountObject->Name);
    BAIL_ON_LSA_ERROR(dwError);

    // Copy the SID
    ntStatus = RtlDuplicateSid(&pAccountSid, accountObject->Sid);
    BAIL_ON_NT_STATUS(ntStatus);

    if (ObjectType == SAMDB_OBJECT_TYPE_LOCAL_GROUP &&
        accountObject->Info.LocalGroup.Description != NULL)
    {
        dwError = LwAllocateWc16String(
                              &description,
                              accountObject->Info.LocalGroup.Description);
        BAIL_ON_LSA_ERROR(dwError);

        pAcctCtx->pwszDescription = description;
    }

    // Get the RID
    dwAccountRid = pAccountSid->SubAuthority[pAccountSid->SubAuthorityCount - 1];

    pAcctCtx->Type             = SamrContextAccount;
    pAcctCtx->refcount         = 1;
    pAcctCtx->dwAccessGranted  = dwAccessGranted;
    pAcctCtx->ObjectType       = ObjectType;
    pAcctCtx->pwszName         = pwszAccountName;
    pAcctCtx->pSid             = pAccountSid;
    pAcctCtx->dwRid            = dwAccountRid;

    pAcctCtx->pDomCtx          = pDomCtx;
    InterlockedIncrement(&pDomCtx->refcount);

    *phAccount = (ACCOUNT_HANDLE)pAcctCtx;

error:
    if (ntStatus == STATUS_SUCCESS &&
        dwError != ERROR_SUCCESS)
    {
        ntStatus = LwWin32ErrorToNtStatus(dwError);
    }

    if (ntStatus)
    {
        if (pAcctCtx)
        {
            SamrSrvAccountContextFree(pAcctCtx);
        }

        *phAccount = NULL;
    }

    if (ppObject)
    {
        SamDbFreeObjects(1, ppObject);
    }

    LW_SAFE_FREE_MEMORY(pSid);
    if (pSecDescRelative)
    {
        SamDbFree(pSecDescRelative);
    }

    if (pSecDescAbsolute)
    {
        SamrSrvFreeSecurityDescriptor(&pSecDescAbsolute);
    }

    return ntStatus;

}


/*
local variables:
mode: c
c-basic-offset: 4
indent-tabs-mode: nil
tab-width: 4
end:
*/
