Skip to content

Commit

Permalink
separate the CLI command implementations (#10)
Browse files Browse the repository at this point in the history
  • Loading branch information
briantist authored May 17, 2022
1 parent 394987f commit 31ec634
Show file tree
Hide file tree
Showing 7 changed files with 243 additions and 203 deletions.
30 changes: 30 additions & 0 deletions src/CcgVault/CLI/CliCommandPing.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System;

namespace CcgVault
{
partial class Program
{
class CliCommandPing : ICliCommand
{
public void Help(string text)
{
Console.WriteLine("ccgvault.exe ping");
Console.WriteLine();
Console.WriteLine("Runs a simple method against the COM+ service, implicitly registering it in the process.");
Console.WriteLine();
Console.WriteLine("The following options are accepted:");
Console.WriteLine(text);
Exit(-1);
}

public void Invoke()
{
using (var ccg = new CcgPlugin())
{
Console.WriteLine("Expecting response: 'Pong'");
Console.WriteLine($"Got response: '{ccg.Ping()}'");
}
}
}
}
}
81 changes: 81 additions & 0 deletions src/CcgVault/CLI/CliCommandRegistry.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
using Microsoft.Win32;
using System;
using System.Runtime.InteropServices;
using System.Security.AccessControl;
using System.Security.Principal;

namespace CcgVault
{
partial class Program
{
class CliCommandRegistry : ICliCommand
{
public bool Permission { get; set; }
public bool ComClass { get; set; }

public void Help(string text)
{
Console.WriteLine("ccgvault.exe registry");
Console.WriteLine();
Console.WriteLine(@"Adds the CcgVault CLSID to the allowed CCG plugins and/or sets permission and ownership of the CCG\COMClasses key.");
Console.WriteLine();
Console.WriteLine("The following options are accepted:");
Console.WriteLine(text);
Exit(-1);
}

public void Invoke()
{
var subkey = @"SYSTEM\CurrentControlSet\Control\CCG\COMClasses";

if (!(Permission || ComClass))
{
Console.WriteLine("Neither --permission nor --comclass were specified. Choose one or both.");
Exit(-1);
}

RegistryKey key;

if (Permission)
{
using (new TokenPrivilege(TokenPrivilege.SE_TAKE_OWNERSHIP_NAME, TokenPrivilege.SE_RESTORE_NAME))
{
key = Registry.LocalMachine.OpenSubKey(subkey, RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryRights.TakeOwnership);

if (key == null)
{
Console.WriteLine($"{subkey} not found or error opening key.");
Exit(-1);
}

const string SID_ADMINISTRATORS = "S-1-5-32-544";
var admins = new SecurityIdentifier(SID_ADMINISTRATORS).Translate(typeof(NTAccount));
var ac = key.GetAccessControl();
ac.SetOwner(admins);
key.SetAccessControl(ac);
key.Close();

key = Registry.LocalMachine.OpenSubKey(subkey, RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryRights.TakeOwnership);
ac = key.GetAccessControl();
ac.AddAccessRule(new RegistryAccessRule(admins,
RegistryRights.FullControl,
InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit,
PropagationFlags.None,
AccessControlType.Allow));
key.SetAccessControl(ac);
key.Close();
}
}

if (ComClass)
{
var pluginId = (GuidAttribute)Attribute.GetCustomAttribute(typeof(CcgPlugin), typeof(GuidAttribute), true);

key = Registry.LocalMachine.OpenSubKey(subkey, RegistryKeyPermissionCheck.ReadWriteSubTree);
key.CreateSubKey($"{{{pluginId.Value}}}");
key.Close();
}
}
}
}
}
81 changes: 81 additions & 0 deletions src/CcgVault/CLI/CliCommandService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
using COMAdmin;
using System;
using System.EnterpriseServices;
using System.Reflection;
using System.Runtime.InteropServices;

namespace CcgVault
{
partial class Program
{
class CliCommandService : ICliCommand
{
public bool Install { get; set; }
public bool Uninstall { get; set; }

public void Help(string text)
{
Console.WriteLine("ccgvault.exe service");
Console.WriteLine();
Console.WriteLine("Installs or uninstalls a Windows (NT) service to associate with the COM+ application.");
Console.WriteLine();
Console.WriteLine("The following options are accepted:");
Console.WriteLine(text);
Exit(-1);
}

public void Invoke()
{
if (Install && Uninstall)
{
Console.WriteLine("Both --install and --uninstall were specified. Choose one or the other.");
Exit(-1);
}

if (!(Install || Uninstall))
{
Console.WriteLine("Neither --install nor --uninstall were specified. Choose one or the other.");
Exit(-1);
}

var appId = Assembly.GetExecutingAssembly().GetCustomAttribute<ApplicationIDAttribute>().Value;
var serviceName = Assembly.GetExecutingAssembly().GetCustomAttribute<ApplicationNameAttribute>().Value;

// https://docs.microsoft.com/en-us/windows/win32/api/comadmin/nf-comadmin-icomadmincatalog2-createserviceforapplication
var oCatalog = (ICOMAdminCatalog2)Activator.CreateInstance(Type.GetTypeFromProgID("ComAdmin.COMAdminCatalog"));

if (Install)
{
try
{
oCatalog.CreateServiceForApplication(
bstrApplicationIDOrName: appId.ToString("B"), // Using an AppID, the GUID needs to be formatted with curly braces {}
bstrServiceName: serviceName,
bstrStartType: "SERVICE_DEMAND_START",
bstrErrorControl: "SERVICE_ERROR_NORMAL",
bstrDependencies: null,
bstrRunAs: null,
bstrPassword: null,
bDesktopOk: false);
}
catch (COMException e) when (e.HResult == -2147023823) // 0x80070431 ERROR_SERVICE_EXISTS
{
// ignore
}
}

if (Uninstall)
{
try
{
oCatalog.DeleteServiceForApplication(bstrApplicationIDOrName: appId.ToString("B")); // Using an AppID, the GUID needs to be formatted with curly braces {}
}
catch (COMException e) when (e.HResult == -2146368458) // 0x80110436 COMADMIN_E_SERVICENOTINSTALLED
{
// ignore
}
}
}
}
}
}
34 changes: 34 additions & 0 deletions src/CcgVault/CLI/CliCommandTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System;

namespace CcgVault
{
partial class Program
{
class CliCommandTest : ICliCommand
{
public string Input { get; set; }

public void Invoke()
{
using (CcgPlugin ccg = new CcgPlugin())
{
string domain, user, pass;
ccg.GetPasswordCredentials(Input, out domain, out user, out pass);

Console.WriteLine($"Domain: {domain}\nUser: {user}\nPass: {pass}");
}
}

public void Help(string text)
{
Console.WriteLine("ccgvault.exe test");
Console.WriteLine();
Console.WriteLine("Tests the credential process with the given input string.");
Console.WriteLine();
Console.WriteLine("The following options are accepted:");
Console.WriteLine(text);
Exit(-1);
}
}
}
}
11 changes: 11 additions & 0 deletions src/CcgVault/CLI/ICliCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace CcgVault
{
partial class Program
{
interface ICliCommand
{
void Invoke();
void Help(string text);
}
}
}
5 changes: 5 additions & 0 deletions src/CcgVault/CcgVault.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@
<ItemGroup>
<Compile Include="AuthType.cs" />
<Compile Include="CcgPlugin.cs" />
<Compile Include="CLI\CliCommandPing.cs" />
<Compile Include="CLI\CliCommandRegistry.cs" />
<Compile Include="CLI\CliCommandService.cs" />
<Compile Include="CLI\CliCommandTest.cs" />
<Compile Include="CLI\ICliCommand.cs" />
<Compile Include="TokenPrivilege.cs" />
<Compile Include="Config.cs" />
<Compile Include="BackendType.cs" />
Expand Down
Loading

0 comments on commit 31ec634

Please sign in to comment.