/* Editor Settings: expandtabs and use 4 spaces for indentation
 * ex: set softtabstop=4 tabstop=8 expandtab shiftwidth=4: *
 * -*- mode: c, c-basic-offset: 4 -*- */
/*
 * Copyright Likewise Software. 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
 * .
 *
 * 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:
 *
 *        lwmapsecurity-test.c
 *
 * Abstract:
 *
 *        Likewise Map Security - Test Program
 *
 * Authors: Danilo Almeida (dalmeida@likewise.com)
 */
#include 
#include 
#include "config.h"
#include 
#include 
#include 
#include 
#define LOG(Format, ...) \
    printf(Format "\n", ## __VA_ARGS__)
#define ASSERT_NT_SUCCESS_STATUS(status) \
    do { \
        if (!NT_SUCCESS(status)) \
        { \
            MapErrorCodes(status); \
            exit(1); \
        } \
    } while (0)
VOID
MapErrorCodes(
    NTSTATUS status
    );
int
IsNumber(char* strNum);
void
ParseArgs(
    int argc,
    char* argv[]);
static
VOID
DumpTokenInfo(
    IN PACCESS_TOKEN Token,
    IN TOKEN_INFORMATION_CLASS TokenInformationClass
    )
{
    NTSTATUS status = STATUS_SUCCESS;
    PBYTE tokenInfo = NULL;
    ULONG size = 0;
    ULONG savedSize = 0;
    status = RtlQueryAccessTokenInformation(
                    Token,
                    TokenInformationClass,
                    tokenInfo,
                    size,
                    &size);
    assert(STATUS_BUFFER_TOO_SMALL == status);
    savedSize = size;
    status = RTL_ALLOCATE(&tokenInfo, BYTE, size);
    ASSERT_NT_SUCCESS_STATUS(status);
    status = RtlQueryAccessTokenInformation(
                    Token,
                    TokenInformationClass,
                    tokenInfo,
                    size,
                    &size);
    ASSERT_NT_SUCCESS_STATUS(status);
    assert(size == savedSize);
    switch (TokenInformationClass)
    {
        case TokenUser:
        {
            PTOKEN_USER tokenUser = (PTOKEN_USER) tokenInfo;
            PSTR sidString = NULL;
            status = RtlAllocateCStringFromSid(&sidString, tokenUser->User.Sid);
            ASSERT_NT_SUCCESS_STATUS(status);
            LOG("User = %s", sidString);
            break;
        }
        case TokenGroups:
        {
            PTOKEN_GROUPS tokenGroups = (PTOKEN_GROUPS) tokenInfo;
            ULONG i = 0;
            PSTR sidString = NULL;
            LOG("GroupCount = %u", tokenGroups->GroupCount);
            for (i = 0; i < tokenGroups->GroupCount; i++)
            {
                status = RtlAllocateCStringFromSid(&sidString, tokenGroups->Groups[i].Sid);
                ASSERT_NT_SUCCESS_STATUS(status);
                LOG("Groups[%u] = (0x%08x, %s)", i, tokenGroups->Groups[i].Attributes, sidString);
            }
            break;
        }
        case TokenOwner:
        {
            PTOKEN_OWNER tokenOwner = (PTOKEN_OWNER) tokenInfo;
            PSTR sidString = NULL;
            status = RtlAllocateCStringFromSid(&sidString, tokenOwner->Owner);
            ASSERT_NT_SUCCESS_STATUS(status);
            LOG("Owner = %s", sidString);
            break;
        }
        case TokenPrimaryGroup:
        {
            PTOKEN_PRIMARY_GROUP tokenPrimaryGroup = (PTOKEN_PRIMARY_GROUP) tokenInfo;
            PSTR sidString = NULL;
            status = RtlAllocateCStringFromSid(&sidString, tokenPrimaryGroup->PrimaryGroup);
            ASSERT_NT_SUCCESS_STATUS(status);
            LOG("PrimaryGroup = %s", sidString);
            break;
        }
        case TokenDefaultDacl:
        {
            PTOKEN_DEFAULT_DACL tokenDefaultDacl = (PTOKEN_DEFAULT_DACL) tokenInfo;
            LOG("Have DefaultdDacl = %c", tokenDefaultDacl->DefaultDacl ? 'Y' : 'N');
            break;
        }
    }
}
static
VOID
DumpTokenUnixInfo(
    IN PACCESS_TOKEN Token
    )
{
    NTSTATUS status = STATUS_SUCCESS;
    TOKEN_UNIX tokenUnix = { 0 };
    status = RtlQueryAccessTokenUnixInformation(
                    Token,
                    &tokenUnix);
    ASSERT_NT_SUCCESS_STATUS(status);
    LOG("Unix.Uid = %u", tokenUnix.Uid);
    LOG("Unix.Gid = %u", tokenUnix.Gid);
    LOG("Unix.Umask = 0%03o", tokenUnix.Umask);
}
static
VOID
DumpToken(
    IN PACCESS_TOKEN Token
    )
{
    DumpTokenInfo(Token, TokenUser);
    DumpTokenInfo(Token, TokenGroups);
    DumpTokenInfo(Token, TokenOwner);
    DumpTokenInfo(Token, TokenPrimaryGroup);
    DumpTokenInfo(Token, TokenDefaultDacl);
    DumpTokenUnixInfo(Token);
}
static
VOID
ShowUsage(
    IN PCSTR pszProgramName
    )
{
    printf("Usage: %s  \n"
           "   or: %s \n"
           "\n"
           "  Test lwmapsecurity library.\n"
           "\n",
           pszProgramName,
           pszProgramName);
}
void
ParseArgs(
    int argc,
    char* argv[])
{
    if ( argc < 2 || (strcmp(argv[1], "--help") == 0) || (strcmp(argv[1], "-h") == 0))
    {
        ShowUsage(argv[0]);
        exit(0);
    }
    else
    {
        if(argc == 2)
        {
            if( isalpha((int)*argv[1]) == 0)
            {
                fprintf(stdout, "Name should start with an alphabet\n\n");
                ShowUsage(argv[0]);
                exit(1);
            }
        }
        else if (argc == 3)
        {
            if ( IsNumber(argv[1]) || IsNumber(argv[2]) )
            {
                fprintf(stdout, "uid and gid should be numbers\n\n");
                ShowUsage(argv[0]);
                exit(1);
            }
        }
        else
        {
            fprintf(stdout, "Too many arguements\n\n");
            ShowUsage(argv[0]);
            exit(1);
        }
    }
}
int
main(
    IN int argc,
    IN char* argv[]
    )
{
    NTSTATUS status = 0;
    PLW_MAP_SECURITY_CONTEXT context = NULL;
    PACCESS_TOKEN accessToken = NULL;
    ParseArgs(argc, argv);
    status = LwMapSecurityCreateContext(&context);
    ASSERT_NT_SUCCESS_STATUS(status);
    if (argc == 2)
    {
        status = LwMapSecurityCreateAccessTokenFromCStringUsername(
                        context,
                        &accessToken,
                        argv[1]);
        ASSERT_NT_SUCCESS_STATUS(status);
    }
    else if (argc == 3)
    {
        int uid = atoi(argv[1]);
        int gid = atoi(argv[2]);
        status = LwMapSecurityCreateAccessTokenFromUidGid(
                        context,
                        &accessToken,
                        (ULONG) uid,
                        (ULONG) gid);
        ASSERT_NT_SUCCESS_STATUS(status);
    }
    DumpToken(accessToken);
    RtlReleaseAccessToken(&accessToken);
    LwMapSecurityFreeContext(&context);
    return NT_SUCCESS(status) ? 0 : 1;
}
int
IsNumber(char* strNum)
{
    int nLen = 0;
    int nIndex = 0;
    nLen = strlen(strNum);
    for (nIndex = 0; nIndex < nLen; nIndex++)
    {
        if (isdigit((int)strNum[nIndex]) == 0)
            return -1;
    }
    return 0;
}
VOID
MapErrorCodes(
    NTSTATUS status
    )
{
    switch (status)
    {
        case LW_STATUS_NOT_FOUND:
            fprintf(stderr,"User not found. Error code 0x%X\n", status);
            break;
        default:
            fprintf(stderr,"Invalid operation. Error code 0x%X\n", status);
            break;
	}
}