Created
October 16, 2015 06:44
-
-
Save sandersaares/32b92c15f97a0eb33fae to your computer and use it in GitHub Desktop.
Grant access rights to DCOM objects as a MSBuild task
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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