/*++

DCOM Permission Configuration Sample
Copyright (c) 1996, Microsoft Corporation. All rights reserved.

Module Name:

    dcomperm.cpp

Abstract:

    Main module for DCOM Permission Configuration Sample

Author:

    Michael Nelson

Environment:

    Windows NT

--*/

#include "dcomperm.h"

#include <conio.h>
#include <ntsecapi.h>
#include <stdio.h>
#include <stdlib.h>
#include <tchar.h>
#include <windows.h>

void
ShowUsage (
    LPTSTR ErrorString
    )
{
    _tprintf (TEXT("%s\n"), ErrorString);
    _tprintf (TEXT("Syntax: dcomperm <option> [...]\n\n"));

    _tprintf (TEXT("Options:\n"));

    _tprintf (TEXT("   -da <\"set\" or \"remove\"> <Principal Name> [\"permit\" or \"deny\"]\n"));
    _tprintf (TEXT("   -da list\n"));
    _tprintf (TEXT("       Modify or list the default access permission list\n\n"));

    _tprintf (TEXT("   -dl <\"set\" or \"remove\"> <Principal Name> [\"permit\" or \"deny\"]\n"));
    _tprintf (TEXT("   -dl list\n"));
    _tprintf (TEXT("       Modify or list the default launch permission list\n\n"));

    _tprintf (TEXT("   -aa <AppID> <\"set\" or \"remove\"> <Principal Name> [\"permit\" or \"deny\"]\n"));
    _tprintf (TEXT("   -aa <AppID> default\n"));
    _tprintf (TEXT("   -aa <AppID> list\n"));
    _tprintf (TEXT("       Modify or list the access permission list for a specific AppID\n\n"));

    _tprintf (TEXT("   -al <AppID> <\"set\" or \"remove\"> <Principal Name> [\"permit\" or \"deny\"]\n"));
    _tprintf (TEXT("   -al <AppID> default\n"));
    _tprintf (TEXT("   -al <AppID> list\n"));
    _tprintf (TEXT("   -al <AppID> zap_list\n"));
    _tprintf (TEXT("       Modify or list the launch permission list for a specific AppID\n\n"));

////    _tprintf (TEXT("Press any key to continue. . ."));
////    _getch();
////    _tprintf (TEXT("\r                               \r"));

    _tprintf (TEXT("   -runas <AppID> <Principal Name> <Password>\n"));
    _tprintf (TEXT("   -runas <AppID> \"Interactive User\"\n"));
    _tprintf (TEXT("   -runas <AppID> remove\n"));
    _tprintf (TEXT("       Set the RunAs information for a specific AppID\n\n"));

    _tprintf (TEXT("Examples:\n"));
    _tprintf (TEXT("   dcomperm -da set redmond\\t-miken permit\n"));
    _tprintf (TEXT("   dcomperm -dl set redmond\\jdoe deny\n"));
    _tprintf (TEXT("   dcomperm -aa {12345678-1234-1234-1234-00aa00bbf7c7} list\n"));
    _tprintf (TEXT("   dcomperm -al {12345678-1234-1234-1234-00aa00bbf7c7} remove redmond\\t-miken\n"));
    _tprintf (TEXT("   dcomperm -runas {12345678-1234-1234-1234-00aa00bbf7c7} redmond\\jdoe password\n"));

    exit (0);
}

void
Error (
    LPTSTR ErrorMessage,
    DWORD ErrorCode
    )
{
    TCHAR messageBuffer [255] = { '\0' };

    _tprintf (TEXT("%s\n%s"), ErrorMessage, SystemMessage (messageBuffer, ErrorCode));
    exit (0);
}

void
HandleDAOption (
    int argc,
    TCHAR **argv
    )
{
    DWORD returnValue = 0;

    if (argc < 3)
        ShowUsage (TEXT("Invalid number of arguments."));

    if (_tcscmp (_tcsupr (argv [2]), TEXT("LIST")) == 0)
    {
        _tprintf (TEXT("Default access permission list:\n\n"));
        ListDefaultAccessACL();
        return;
    }

    if (argc < 4)
        ShowUsage (TEXT("Invalid number of arguments."));

    if (_tcscmp (_tcsupr (argv [2]), TEXT("SET")) == 0)
    {
        if (argc < 5)
            ShowUsage (TEXT("Invalid number of arguments."));

        if (_tcscmp (_tcsupr (argv [4]), TEXT("PERMIT")) == 0)
            returnValue = ChangeDefaultAccessACL (argv [3], true, true); else

        if (_tcscmp (_tcsupr (argv [4]), TEXT("DENY")) == 0)
            returnValue = ChangeDefaultAccessACL (argv [3], true, false); else
        {
            ShowUsage (TEXT("You can only set a user's permissions to \"permit\" or \"deny\".\n\n"));
        }

        if (returnValue != ERROR_SUCCESS)
            Error (TEXT("ERROR: Cannot add user to default access ACL."), returnValue);
    } else
    if (_tcscmp (_tcsupr (argv [2]), TEXT("REMOVE")) == 0)
    {
        returnValue = ChangeDefaultAccessACL (argv[3], false, false);

        if (returnValue != ERROR_SUCCESS)
            Error (TEXT("ERROR: Cannot remove user from default access ACL."), returnValue);
    } else
        ShowUsage (TEXT("You can only \"set\" or \"remove\" a user."));
}

void
HandleDLOption (
    int argc,
    TCHAR **argv
    )
{
    DWORD returnValue = 0;

    if (argc < 3)
        ShowUsage (TEXT("Invalid number of arguments."));

    if (_tcscmp (_tcsupr (argv [2]), TEXT("LIST")) == 0)
    {
        _tprintf (TEXT("Default launch permission list:\n\n"));
        ListDefaultLaunchACL();
        return;
    }

    if (argc < 4)
        ShowUsage (TEXT("Invalid number of arguments."));

    if (_tcscmp (_tcsupr (argv [2]), TEXT("SET")) == 0)
    {
        if (argc < 5)
            ShowUsage (TEXT("Invalid number of arguments."));

        if (_tcscmp (_tcsupr (argv [4]), TEXT("PERMIT")) == 0)
            returnValue = ChangeDefaultLaunchACL (argv [3], true, true); else

        if (_tcscmp (_tcsupr (argv [4]), TEXT("DENY")) == 0)
            returnValue = ChangeDefaultLaunchACL (argv [3], true, false); else
        {
            ShowUsage (TEXT("You can only set a user's permissions to \"permit\" or \"deny\".\n\n"));
        }

        if (returnValue != ERROR_SUCCESS)
            Error (TEXT("ERROR: Cannot add user to default launch ACL."), returnValue);
    } else
    if (_tcscmp (_tcsupr (argv [3]), TEXT("REMOVE")) == 0)
    {
        returnValue = ChangeDefaultLaunchACL (argv[3], false, false);

        if (returnValue != ERROR_SUCCESS)
            Error (TEXT("ERROR: Cannot remove user from default launch ACL."), returnValue);
    } else
        ShowUsage (TEXT("You can only \"set\" or \"remove\" a user."));
}

void
HandleAAOption (
    int argc,
    TCHAR **argv
    )
{
    DWORD returnValue = 0;
    HKEY  registryKey;
    TCHAR appid [256];
    TCHAR keyName [256];

    if (argc < 4)
        ShowUsage (TEXT("Invalid number of arguments."));

    if (_tcscmp (_tcsupr (argv[3]), TEXT("LIST")) == 0)
    {
        if (argc < 4)
            ShowUsage (TEXT("Invalid number of arguments."));

        _tprintf (TEXT("Access permission list for AppID %s:\n\n"), argv[2]);
        ListAppIDAccessACL (argv[2]);
        return;
    }

    if (_tcscmp (_tcsupr (argv[3]), TEXT("DEFAULT")) == 0)
    {
        if (argv [2][0] == '{')
            wsprintf (appid, TEXT("%s"), argv [2]); else
            wsprintf (appid, TEXT("{%s}"), argv [2]);

        wsprintf (keyName, TEXT("APPID\\%s"), appid);

        returnValue = RegOpenKeyEx (HKEY_CLASSES_ROOT, keyName, 0, KEY_ALL_ACCESS, &registryKey);
        if (returnValue != ERROR_SUCCESS && returnValue != ERROR_FILE_NOT_FOUND)
            Error (TEXT("ERROR: Cannot open AppID registry key."), returnValue);

        returnValue = RegDeleteValue (registryKey, TEXT("AccessPermission"));
        if (returnValue != ERROR_SUCCESS && returnValue != ERROR_FILE_NOT_FOUND)
            Error (TEXT("ERROR: Cannot delete AccessPermission value."), returnValue);

        RegCloseKey (registryKey);
        return;
    }

    if (argc < 5)
        ShowUsage (TEXT("Invalid number of arguments."));

    if (_tcscmp (_tcsupr (argv [3]), TEXT("SET")) == 0)
    {
        if (argc < 6)
            ShowUsage (TEXT("Invalid number of arguments."));

        if (_tcscmp (_tcsupr (argv [5]), TEXT("PERMIT")) == 0)
            returnValue = ChangeAppIDAccessACL (argv[2], argv [4], true, true); else

        if (_tcscmp (_tcsupr (argv [5]), TEXT("DENY")) == 0)
            returnValue = ChangeAppIDAccessACL (argv[2], argv [4], true, false); else
        {
            ShowUsage (TEXT("You can only set a user's permissions to \"permit\" or \"deny\".\n\n"));
        }

        if (returnValue != ERROR_SUCCESS)
            Error (TEXT("ERROR: Cannot add user to application access ACL."), returnValue);
    } else
    if (_tcscmp (_tcsupr (argv [3]), TEXT("REMOVE")) == 0)
    {
        returnValue = ChangeAppIDAccessACL (argv[2], argv[4], false, false);

        if (returnValue != ERROR_SUCCESS)
            Error (TEXT("ERROR: Cannot remove user from application access ACL."), returnValue);
    } else
        ShowUsage (TEXT("You can only \"set\" or \"remove\" a user."));
}

void
HandleALOption (
    int argc,
    TCHAR **argv
    )
{
    DWORD returnValue = 0;
    HKEY  registryKey;
    TCHAR appid [256];
    TCHAR keyName [256];

    if (argc < 4)
        ShowUsage (TEXT("Invalid number of arguments."));

    if (_tcscmp (_tcsupr (argv[3]), TEXT("LIST")) == 0)
    {
        if (argc < 4)
            ShowUsage (TEXT("Invalid number of arguments.\n"));

        _tprintf (TEXT("Launch permission list for AppID %s:\n\n"), argv[2]);
        ListAppIDLaunchACL (argv[2]);
        return;
    }
    if (_tcscmp (_tcsupr (argv[3]), TEXT("ZAP_LIST")) == 0)
    {
        if (argc < 4)
            ShowUsage (TEXT("Invalid number of arguments.\n"));

        _tprintf (TEXT("Zapping launch permissions for AppID %s:\n\n"), argv[2]);
        ZapAppIDLaunchACL (argv[2]);
        return;
    }

    if (_tcscmp (_tcsupr (argv[3]), TEXT("DEFAULT")) == 0)
    {
        if (argv [2][0] == '{')
            wsprintf (appid, TEXT("%s"), argv [2]); else
            wsprintf (appid, TEXT("{%s}"), argv [2]);

        wsprintf (keyName, TEXT("APPID\\%s"), appid);

        returnValue = RegOpenKeyEx (HKEY_CLASSES_ROOT, keyName, 0, KEY_ALL_ACCESS, &registryKey);
        if (returnValue != ERROR_SUCCESS && returnValue != ERROR_FILE_NOT_FOUND)
            Error (TEXT("ERROR: Cannot open AppID registry key."), returnValue);

        returnValue = RegDeleteValue (registryKey, TEXT("LaunchPermission"));
        if (returnValue != ERROR_SUCCESS && returnValue != ERROR_FILE_NOT_FOUND)
            Error (TEXT("ERROR: Cannot delete LaunchPermission value."), returnValue);

        RegCloseKey (registryKey);
        return;
    }

    if (argc < 5)
        ShowUsage (TEXT("Invalid number of arguments."));

    if (_tcscmp (_tcsupr (argv [3]), TEXT("SET")) == 0)
    {
        if (argc < 6)
            ShowUsage (TEXT("Invalid number of arguments."));

        if (_tcscmp (_tcsupr (argv [5]), TEXT("PERMIT")) == 0)
            returnValue = ChangeAppIDLaunchACL (argv[2], argv [4], true, true); else

        if (_tcscmp (_tcsupr (argv [5]), TEXT("DENY")) == 0)
            returnValue = ChangeAppIDLaunchACL (argv[2], argv [4], true, false); else
        {
            ShowUsage (TEXT("You can only set a user's permissions to \"permit\" or \"deny\".\n\n"));
        }

        if (returnValue != ERROR_SUCCESS)
            Error (TEXT("ERROR: Cannot add user to application launch ACL."), returnValue);
    } else
    if (_tcscmp (_tcsupr (argv [3]), TEXT("REMOVE")) == 0)
    {
        returnValue = ChangeAppIDLaunchACL (argv[2], argv[4], false, false);

        if (returnValue != ERROR_SUCCESS)
            Error (TEXT("ERROR: Cannot remove user from application launch ACL."), returnValue);
    } else
        ShowUsage (TEXT("You can only \"set\" or \"remove\" a user."));
}

void
HandleRunAsOption (
    int argc,
    TCHAR **argv
    )
{
    DWORD returnValue = 0;
    HKEY  registryKey;
    TCHAR appid [256];
    TCHAR keyName [256];

    if (argc < 4)
        ShowUsage (TEXT("Invalid number of arguments."));

    if (argv [2][0] == '{')
        wsprintf (appid, TEXT("%s"), argv [2]); else
        wsprintf (appid, TEXT("{%s}"), argv [2]);

    wsprintf (keyName, TEXT("APPID\\%s"), appid);

    returnValue = RegOpenKeyEx (HKEY_CLASSES_ROOT, keyName, 0, KEY_ALL_ACCESS, &registryKey);
    if (returnValue != ERROR_SUCCESS)
        Error (TEXT("ERROR: Cannot open AppID registry key."), returnValue);

    bool try_setting_password = true;  // we will usually do this.
    if (_tcscmp (_tcsupr (argv[3]), TEXT("REMOVE")) == 0) {
      // we were told to remove the RunAs entry.
      try_setting_password = false;
      returnValue = RegDeleteValue(registryKey, TEXT("RunAs"));
      if (returnValue != ERROR_SUCCESS)
          Error (TEXT("ERROR: Cannot remove RunAs registry value."), returnValue);
    } else {
      returnValue = RegSetValueEx (registryKey, TEXT("RunAs"), 0, REG_SZ, (LPBYTE) argv [3], (DWORD)(_tcslen (argv[3]) * sizeof (TCHAR)));
      if (returnValue != ERROR_SUCCESS)
          Error (TEXT("ERROR: Cannot set RunAs registry value."), returnValue);
    }

    RegCloseKey (registryKey);

    if (try_setting_password && (_tcscmp (_tcsupr (argv[3]), TEXT("INTERACTIVE USER")) != 0) )
    {
        if (argc < 5)
            ShowUsage (TEXT("Invalid number of arguments."));

        returnValue = SetRunAsPassword (argv[2], argv[3], argv[4]);
        if (returnValue != ERROR_SUCCESS)
            Error (TEXT("ERROR: Cannot set RunAs password."), returnValue);
    }
}

int dcomperm_main(int argc, char **argv)
{
#ifdef TESTING
    printf("args:\n");
    for (int i = 0; i < argc; i++) {
      printf("#%d: %s\n", i, argv[i]);
    }
    char c = getchar();
#endif

    if (argc < 2) {
        ShowUsage (TEXT("No option specified."));
        return 95;  // error.
    }

    if (_tcscmp (_tcsupr (argv [1]), TEXT("-DA")) == 0)
        HandleDAOption (argc, argv);
    else if (_tcscmp (_tcsupr (argv [1]), TEXT("-DL")) == 0)
        HandleDLOption (argc, argv);
    else if (_tcscmp (_tcsupr (argv [1]), TEXT("-AA")) == 0)
        HandleAAOption (argc, argv);
    else if (_tcscmp (_tcsupr (argv [1]), TEXT("-AL")) == 0)
        HandleALOption (argc, argv);
    else if (_tcscmp (_tcsupr (argv [1]), TEXT("-RUNAS")) == 0)
        HandleRunAsOption (argc, argv);
    else {
        ShowUsage (TEXT("Invalid option specified."));
        return 98;  // error.
    }
    return 0;  // no error.
}


