/*++

Copyright (c) 1992  Microsoft Corporation

Module Name:

    ctlklsa.c

Abstract:

    Local Security Authority Subsystem - Short CT for Lsa LookupAccountName/Sid

    This is a small test that simply calls the LsaLookupName/Sid API once.

Usage:

    ctlklsa \\ServerName [-p] -a AccountName ... AccountName

        -p - pause before name and sid lookup operation
        -a - start of list of account names


Building Instructions:

    nmake UMTEST=ctlklsa UMTYPE=console

Author:


Environment:

Revision History:

--*/

#include "lsaclip.h"


VOID
DumpSID(
    IN PSID        s
    );

VOID
CtPause(
    );

#define LSA_WIN_STANDARD_BUFFER_SIZE           0x000000200L

VOID _CRTAPI1
main(argc, argv)
int argc;
char **argv;
{
    NTSTATUS
        Status = STATUS_SUCCESS,
        SidStatus;

    ULONG
        Index,
        ArgCount = (ULONG) argc,
        DomainIndex,
        NameIndex,
        NameCount,
        DomainSidLength;

    ANSI_STRING
        NamesAnsi[ LSA_WIN_STANDARD_BUFFER_SIZE],
        SystemNameAnsi;

    UNICODE_STRING
        Names[ LSA_WIN_STANDARD_BUFFER_SIZE],
        SystemName;

    PUNICODE_STRING
        DomainName;

    PSID
        Sid = NULL,
        *Sids = NULL;

    SECURITY_QUALITY_OF_SERVICE
        SecurityQualityOfService;

    OBJECT_ATTRIBUTES
        ObjectAttributes;

    LSA_HANDLE
        PolicyHandle;

    PLSA_REFERENCED_DOMAIN_LIST
        ReferencedDomains = NULL,
        ReferencedSidsDomains = NULL;

    PLSA_TRANSLATED_SID
        TranslatedSids = NULL;

    PLSA_TRANSLATED_NAME
        TranslatedNames = NULL;

    UCHAR
        SubAuthorityCount;

    BOOLEAN
        Pause = FALSE,
        DoLookupSids = TRUE;

    if (argc < 4) {

        printf("usage:  ctlkacct <ServerName> [-p] -a <AccountName> [<AccountName> ...]\n\n");
        printf("        -p - pause before name and sid lookup operations\n");
        printf("        -a - start of list of account names\n\n");
        printf("example:\n");
        printf("        ctlklsa \\\\jimk -p -a interactive \"domain guests\" administrators\n\n");
        return;
    }

    NameIndex = 0;

    //
    // Capture argument 1, the Server Name
    //

    RtlInitString( &SystemNameAnsi, (PUCHAR) argv[1] );

    Status = RtlAnsiStringToUnicodeString(
                 &SystemName,
                 &SystemNameAnsi,
                 TRUE
                 );

    if (!NT_SUCCESS(Status)) {

        goto MainError;
    }

    for (Index = 2; Index < ArgCount; Index++) {

        if (strncmp(argv[Index], "-p", 2) == 0) {

            //
            // The caller wants a pause before each lookup call.
            //

            Pause = TRUE;
        } else if (strncmp(argv[Index], "-a", 2) == 0) {

            Index++;

            while (Index < ArgCount) {

                if (strncmp(argv[Index], "-", 1) == 0) {

                    Index--;
                    break;
                }

                //
                // Capture the Account Name as a Unicode String.
                //

                RtlInitString( &NamesAnsi[ NameIndex ], argv[Index] );

                Status = RtlAnsiStringToUnicodeString(
                             &Names[ NameIndex ],
                             &NamesAnsi[ NameIndex ],
                             TRUE
                             );

                if (!NT_SUCCESS(Status)) {

                    break;
                }

                NameIndex++;
                Index++;
            }

            if (Index == ArgCount) {

                break;
            }
        }
    }

    if (!NT_SUCCESS(Status)) {

        goto MainError;
    }

    NameCount = NameIndex;

    SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
    SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
    SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
    SecurityQualityOfService.EffectiveOnly = FALSE;

    //
    // Set up the object attributes prior to opening the LSA.
    //

    InitializeObjectAttributes(
        &ObjectAttributes,
        NULL,
        0L,
        NULL,
        NULL
        );

    //
    // The InitializeObjectAttributes macro presently stores NULL for
    // the SecurityQualityOfService field, so we must manually copy that
    // structure for now.
    //

    ObjectAttributes.SecurityQualityOfService = &SecurityQualityOfService;

    //
    // Open the LSA Policy Database for the target system.  This is the
    // starting point for the Name Lookup operation.
    //

    Status = LsaOpenPolicy(
                 &SystemName,
                 &ObjectAttributes,
                 POLICY_LOOKUP_NAMES,
                 &PolicyHandle
                 );

    if (!NT_SUCCESS(Status)) {

        goto MainError;
    }

    if (Pause) {

        printf( "\n\n..... Pausing before name lookup \n      ");
        CtPause(  );
    }


    //
    // Attempt to translate the Names to Sids.
    //

    Status = LsaLookupNames(
                 PolicyHandle,
                 NameCount,
                 Names,
                 &ReferencedDomains,
                 &TranslatedSids
                 );

    if (!NT_SUCCESS(Status)) {

        goto MainError;
    }

    //
    // Build the Sids from the output.
    //

    Sids = (PSID *) LocalAlloc( 0, NameCount * sizeof (PSID) );


    if (Sids == NULL) {

        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto MainError;
    }


    for (NameIndex = 0; NameIndex < NameCount; NameIndex++) {

        if (TranslatedSids[NameIndex].Use == SidTypeUnknown) {

            Sids[NameIndex] = NULL;
            DoLookupSids = FALSE;

        } else {
            DomainIndex = TranslatedSids[NameIndex].DomainIndex;

            DomainSidLength = RtlLengthSid(
                                 ReferencedDomains->Domains[DomainIndex].Sid
                                 );


        
            Sid = (PSID) LocalAlloc( (UINT) 0, (UINT) (DomainSidLength + sizeof(ULONG)) );
        
            if (Sid == NULL) {
                printf(" ** ERROR - couldn't allocate heap !!\n");
                return;
            }
        
            RtlMoveMemory(
                Sid,
                ReferencedDomains->Domains[DomainIndex].Sid,
                DomainSidLength
                );

            if (TranslatedSids[NameIndex].Use != SidTypeDomain) {

                (*RtlSubAuthorityCountSid( Sid ))++;
                SubAuthorityCount = *RtlSubAuthorityCountSid( Sid );
                *RtlSubAuthoritySid(Sid,SubAuthorityCount - (UCHAR) 1) =
                    TranslatedSids[NameIndex].RelativeId;
            }

            Sids[NameIndex] = Sid;
        }
    }


    //
    // Pause before SID lookup...
    //

    if (!DoLookupSids) {
        printf("\n\n      Unknown Name causing sid lookup to be skipped\n");
    } else {
        if (Pause) {
        
            printf( "\n\n..... Pausing before SID lookup \n      ");
            CtPause();
        }
        
        //
        // Now translate the Sids back to Names
        //
        
        SidStatus = LsaLookupSids(
                        PolicyHandle,
                        NameCount,
                        (PSID *) Sids,
                        &ReferencedSidsDomains,
                        &TranslatedNames
                        );
    }

    /*
     * Print information returned by LookupAccountName
     */


    printf(
        "*********************************************\n"
        "Information returned by LookupAccountName\n"
        "*********************************************\n\n"
        );

    for (NameIndex = 0; NameIndex < NameCount; NameIndex++) {


        printf("   Name looked up:  *%wZ*\n", &Names[NameIndex]);

        printf("          Use = ");
        
        switch (TranslatedSids[NameIndex].Use) {
        
        case SidTypeUser:
        
              printf("SidTypeUser\n");
              break;
        
        case SidTypeGroup:
        
              printf("SidTypeGroup\n");
              break;
        
        case SidTypeDomain:
        
              printf("SidTypeDomain\n");
              break;
        
        case SidTypeAlias:
        
              printf("SidTypeAlias\n");
              break;
        
        case SidTypeWellKnownGroup:
        
            printf("SidTypeWellKnownGroup\n");
            break;
        
        case SidTypeDeletedAccount:
        
            printf("SidTypeDeletedAccount\n");
            break;
        
        case SidTypeInvalid:
        
            printf("SidTypeInvalid\n");
            break;
        
        case SidTypeUnknown:
        
            printf("SidTypeUnknown\n\n");
            break;
        
        default:
        
            printf("Hmmm - something unusual came back !!!! \n\n");
            break;
        
        }

        if (TranslatedSids[NameIndex].Use != SidTypeUnknown) {
        
            printf("          Sid = " );
            DumpSID((PSID) Sids[NameIndex]);
        
            DomainIndex = TranslatedSids[NameIndex].DomainIndex;
            DomainName = &ReferencedDomains->Domains[ DomainIndex ].Name;
        
            printf("          Referenced Domain Name = *%wZ*\n\n", DomainName );
        }
    }


    if (DoLookupSids) {
        printf(
            "*********************************************\n"
            "Information returned by LookupAccountSid\n"
            "*********************************************\n\n"
            );

        if (!NT_SUCCESS(SidStatus)) {
            printf(" Sid lookup failed.  Status 0x%lx\n"
                   " Dumping sids that were being looked up...\n",
                   SidStatus);
        }
        
        for (NameIndex = 0; NameIndex < NameCount; NameIndex++) {
        

            printf("   Sid = " );
            DumpSID((PSID) Sids[NameIndex]);

            if (NT_SUCCESS(SidStatus)) {
        
                printf("          Sid Use = ");
            
                switch (TranslatedNames[NameIndex].Use) {
                      
                case SidTypeUser:
              
                    printf("SidTypeUser\n");
                    break;
              
                case SidTypeGroup:
              
                    printf("SidTypeGroup\n");
                    break;
              
                case SidTypeDomain:
              
                    printf("SidTypeDomain\n");
                    break;
              
                case SidTypeAlias:
              
                    printf("SidTypeAlias\n");
                    break;
              
                case SidTypeWellKnownGroup:
              
                    printf("SidTypeWellKnownGroup\n");
                    break;
              
                case SidTypeDeletedAccount:
              
                    printf("SidTypeDeletedAccount\n");
                    break;
              
                case SidTypeInvalid:
              
                    printf("SidTypeInvalid\n");
                    break;
              
                case SidTypeUnknown:
              
                    printf("SidTypeUnknown\n");
                    break;
              
                default:
            
                    printf("Hmmm - unexpected value !!!\n");
                    break;
                }

                DomainIndex = TranslatedNames[NameIndex].DomainIndex;
                DomainName = &ReferencedSidsDomains->Domains[ DomainIndex ].Name;
                if (TranslatedNames[NameIndex].Use == SidTypeDomain) {
                    printf(
                        "          Domain Name = *%wZ*\n\n",
                        DomainName
                        );
                } else {
                    printf(
                        "          Account Name = *%wZ*\n"
                        "          Referenced Domain Name = *%wZ*\n\n",
                        &TranslatedNames[NameIndex].Name,
                        DomainName
                        );
                }
            }
        }
    }


MainFinish:

    return;

MainError:

    printf("Error: status = 0x%lx\n", Status);

    goto MainFinish;
}


VOID
DumpSID(
    IN PSID s
    )

{
    SID_IDENTIFIER_AUTHORITY
        *a;

    ULONG
        id = 0,
        i;

    BOOLEAN
        PrintValue = FALSE;

    try {


        a = GetSidIdentifierAuthority(s);

        printf("s-1-");

        for (i=0; i<5; i++) {
            if ((a->Value[i] != 0) || PrintValue) {
                printf("%02x", a->Value[i]);
                PrintValue = TRUE;
            }
        }
        printf("%02x", a->Value[5]);


        for (i = 0; i < (ULONG) *GetSidSubAuthorityCount(s); i++) {

            printf("-0x%lx", *GetSidSubAuthority(s, i));
        }


    } except (EXCEPTION_EXECUTE_HANDLER) {

        printf("<invalid pointer (0x%lx)>\n", s);
    }
    printf("\n");
}

VOID
CtPause(
    )
{
    CHAR
        IgnoreInput[300];

    printf("Press <ENTER> to continue . . .");
    gets( &IgnoreInput[0] );
    return;
}