Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Grant access rights to DCOM objects as a MSBuild task
namespace Axinom.Environment.MSBuild.Tasks
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.AccessControl;
using System.Security.Principal;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Microsoft.Win32;
/// <summary>
/// Grants access rights to a set of DCOM objects, specified by their application IDs.
/// Existing rights are not modified, so this task never removes access rights that already exist.
/// </summary>
public sealed class GrantDcomRights : Task
{
/// <summary>
/// The objects to grant rights to, identified by IDs formatted exactly like this: {42152A9D-AFFE-48B8-9C61-C1C5DDB64FF7}.
/// </summary>
[Required]
public ITaskItem[] Objects { get; set; }
/// <summary>
/// The account name of the user who will gain access to the objects.
/// </summary>
[Required]
public string User { get; set; }
public bool GrantLocalLaunch { get; set; }
public bool GrantRemoteLaunch { get; set; }
public bool GrantLocalActivation { get; set; }
public bool GrantRemoteActivation { get; set; }
public bool GrantLocalAccess { get; set; }
public bool GrantRemoteAccess { get; set; }
public override bool Execute()
{
Log.LogMessage("Resolving user...");
var userSid = (SecurityIdentifier)new NTAccount(User).Translate(typeof(SecurityIdentifier));
foreach (var objectID in Objects)
{
Log.LogMessage("Granting rights to {0}", objectID.ItemSpec);
GrantLaunchRights(objectID.ItemSpec, userSid);
GrantAccessRights(objectID.ItemSpec, userSid);
}
return !Log.HasLoggedErrors;
}
private const int BasicLaunchRight = 1;
private const int LocalLaunchRight = 2;
private const int RemoteLaunchRight = 4;
private const int LocalActivateRight = 8;
private const int RemoteActivateRight = 16;
private const int BasicAccessRight = 1;
private const int LocalAccessRight = 2;
private const int RemoteAccessRight = 4;
private void GrantLaunchRights(string objectID, SecurityIdentifier userSid)
{
if (!GrantLocalLaunch && !GrantRemoteLaunch && !GrantLocalActivation && !GrantRemoteActivation)
return; // Nothing to grant.
var securityDescriptor = GetLaunchSecurityDescriptor(objectID);
var acl = securityDescriptor.DiscretionaryAcl;
CommonAce targetEntry = null;
// Does the user already have an entry?
foreach (var entry in acl)
{
if (entry.AceType != AceType.AccessAllowed)
continue;
if (((CommonAce)entry).SecurityIdentifier == userSid)
{
targetEntry = (CommonAce)entry;
break;
}
}
if (targetEntry == null)
{
// Guess not. Let's add one.
targetEntry = new CommonAce(AceFlags.None, AceQualifier.AccessAllowed, 0, userSid, false, null);
acl.InsertAce(acl.Count, targetEntry);
}
int grantsMask = BasicLaunchRight;
if (GrantLocalLaunch)
grantsMask |= LocalLaunchRight;
if (GrantRemoteLaunch)
grantsMask |= RemoteLaunchRight;
if (GrantLocalActivation)
grantsMask |= LocalActivateRight;
if (GrantRemoteActivation)
grantsMask |= RemoteActivateRight;
targetEntry.AccessMask |= grantsMask;
SetLaunchSecurityDescriptor(objectID, securityDescriptor);
}
private void GrantAccessRights(string objectID, SecurityIdentifier userSid)
{
if (!GrantLocalAccess && !GrantRemoteAccess)
return; // Nothing to grant.
var securityDescriptor = GetAccessSecurityDescriptor(objectID);
var acl = securityDescriptor.DiscretionaryAcl;
CommonAce targetEntry = null;
// Does the user already have an entry?
foreach (var entry in acl)
{
if (entry.AceType != AceType.AccessAllowed)
continue;
if (((CommonAce)entry).SecurityIdentifier == userSid)
{
targetEntry = (CommonAce)entry;
break;
}
}
if (targetEntry == null)
{
// Guess not. Let's add one.
targetEntry = new CommonAce(AceFlags.None, AceQualifier.AccessAllowed, 0, userSid, false, null);
acl.InsertAce(acl.Count, targetEntry);
}
int grantsMask = BasicAccessRight;
if (GrantLocalAccess)
grantsMask |= LocalAccessRight;
if (GrantRemoteAccess)
grantsMask |= RemoteAccessRight;
targetEntry.AccessMask |= grantsMask;
SetAccessSecurityDescriptor(objectID, securityDescriptor);
}
private RawSecurityDescriptor GetAccessSecurityDescriptor(string objectID)
{
var descriptorBytes = Registry.GetValue("HKEY_CLASSES_ROOT\\AppID\\" + objectID, "AccessPermission", null) as byte[];
if (descriptorBytes == null)
return GetDefaultAccessSecurityDescriptor();
return new RawSecurityDescriptor(descriptorBytes, 0);
}
private RawSecurityDescriptor GetLaunchSecurityDescriptor(string objectID)
{
var descriptorBytes = Registry.GetValue("HKEY_CLASSES_ROOT\\AppID\\" + objectID, "LaunchPermission", null) as byte[];
if (descriptorBytes == null)
return GetDefaultLaunchSecurityDescriptor();
return new RawSecurityDescriptor(descriptorBytes, 0);
}
private void SetAccessSecurityDescriptor(string objectID, RawSecurityDescriptor descriptor)
{
byte[] buffer = new byte[descriptor.BinaryLength];
descriptor.GetBinaryForm(buffer, 0);
Registry.SetValue("HKEY_CLASSES_ROOT\\AppID\\" + objectID, "AccessPermission", buffer, RegistryValueKind.Binary);
}
private void SetLaunchSecurityDescriptor(string objectID, RawSecurityDescriptor descriptor)
{
byte[] buffer = new byte[descriptor.BinaryLength];
descriptor.GetBinaryForm(buffer, 0);
Registry.SetValue("HKEY_CLASSES_ROOT\\AppID\\" + objectID, "LaunchPermission", buffer, RegistryValueKind.Binary);
}
private const string BuiltinDefaultAccessSecurityDescriptor = "AQAEgFwAAABsAAAAAAAAABQAAAACAEgAAwAAAAAAFAAHAAAAAQEAAAAAAAUKAAAAAAAUAAMAAAABAQAAAAAABRIAAAAAABgABwAAAAECAAAAAAAFIAAAACACAAABAgAAAAAABSAAAAAgAgAAAQIAAAAAAAUgAAAAIAIAAA==";
private const string BuiltinDefaultLaunchSecurityDescriptor = "AQAEgFwAAABsAAAAAAAAABQAAAACAEgAAwAAAAAAGAAfAAAAAQIAAAAAAAUgAAAAIAIAAAAAFAALAAAAAQEAAAAAAAUEAAAAAAAUAAsAAAABAQAAAAAABRIAAAABAgAAAAAABSAAAAAgAgAAAQIAAAAAAAUgAAAAIAIAAA==";
private RawSecurityDescriptor GetDefaultAccessSecurityDescriptor()
{
var descriptorBytes = Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Ole", "DefaultAccessPermission", null) as byte[];
if (descriptorBytes == null)
{
Log.LogWarning("The system default DCOM access security descriptor was not found. Falling back to built-in default which may or may not work.");
return new RawSecurityDescriptor(Convert.FromBase64String(BuiltinDefaultAccessSecurityDescriptor), 0);
}
return new RawSecurityDescriptor(descriptorBytes, 0);
}
private RawSecurityDescriptor GetDefaultLaunchSecurityDescriptor()
{
var descriptorBytes = Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Ole", "DefaultLaunchPermission", null) as byte[];
if (descriptorBytes == null)
{
Log.LogWarning("The system default DCOM launch security descriptor was not found. Falling back to built-in default which may or may not work.");
return new RawSecurityDescriptor(Convert.FromBase64String(BuiltinDefaultLaunchSecurityDescriptor), 0);
}
return new RawSecurityDescriptor(descriptorBytes, 0);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment