以编程方式实现 dcomcnfg 功能

发布于 2024-07-11 07:37:46 字数 295 浏览 7 评论 0原文

我可以找到有关如何为 DCOM 编程的各种内容,但几乎没有找到有关如何以编程方式设置/检查安全性的内容。

我并不是想重新创建 dcomcnfg,但如果我知道如何在 C#(首选或 VB.net)中重现 dcomcnfg 的所有功能,那么我的目标就在眼前。

我似乎无法找到任何关于此的好资源,没有开源 API,甚至没有如何执行每个步骤的快速示例。 即使在这里,DCOM 或 dcomcnfg 返回的结果也很少,并且没有真正涉及如何设置/验证/列出安全性。

如果有人有一些开放 API 的指针或一些示例,我将不胜感激。

I can find all sorts of stuff on how to program for DCOM, but practically nothing on how to set/check the security programmatically.

I'm not trying to recreate dcomcnfg, but if I knew how to reproduce all the functionality of dcomcnfg in C# (preferred, or VB.net) then my goal is in sight.

I can't seem to be able to find any good resource on this, no open source API's or even quick examples of how to do each step. Even here DCOM or dcomcnfg returns few results and none really about how to set/verify/list security.

If anybody has some pointers to an open API or some examples I would appreciate it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

梦屿孤独相伴 2024-07-18 07:37:46

丹尼尔发布的答案非常有帮助。 非常感谢你,丹尼尔!

Microsoft 文档 的一个问题是,它们指示注册表值包含二进制形式的 ACL。 因此,例如,如果您尝试设置计算机的默认访问权限(而不是每个进程),您将访问注册表项 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Ole\DefaultAccessPermission。 但是,在我最初尝试使用 System.Security.AccessControl.RawACL 类访问此密钥时失败了。

正如 Daniel 的代码所示,该值实际上并不是 ACL,而实际上是包含 ACL 的 SecurityDescriptor。

因此,即使我知道这篇文章已经过时,我仍将发布我的解决方案,用于检查和设置安全设置并添加 NetworkService 以进行默认本地访问。 当然,我确信您可以接受并使其变得更好,但首先您只需要更改密钥和访问掩码即可。

static class ComACLRights{
    public const int COM_RIGHTS_EXECUTE= 1;
    public const int COM_RIGHTS_EXECUTE_LOCAL = 2;
    public const int COM_RIGHTS_EXECUTE_REMOTE = 4;
    public const int COM_RIGHTS_ACTIVATE_LOCAL = 8;
    public const int COM_RIGHTS_ACTIVATE_REMOTE = 16;
}
class Program
{
    static void Main(string[] args)
    {
        var value = Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Ole", "DefaultAccessPermission", null);

        RawSecurityDescriptor sd;
        RawAcl acl;

        if (value == null)
        {
            System.Console.WriteLine("Default Access Permission key has not been created yet");
            sd = new RawSecurityDescriptor("");
        }else{
            sd = new RawSecurityDescriptor(value as byte[], 0);
        }
        acl = sd.DiscretionaryAcl;
        bool found = false;
        foreach (CommonAce ca in acl)
        {
            if (ca.SecurityIdentifier.IsWellKnown(WellKnownSidType.NetworkServiceSid))
            {
                //ensure local access is set
                ca.AccessMask |= ComACLRights.COM_RIGHTS_EXECUTE | ComACLRights.COM_RIGHTS_EXECUTE_LOCAL | ComACLRights.COM_RIGHTS_ACTIVATE_LOCAL;    //set local access.  Always set execute
                found = true;
                break;
            }
        }
        if(!found){
            //Network Service was not found.  Add it to the ACL
            SecurityIdentifier si = new SecurityIdentifier( 
                WellKnownSidType.NetworkServiceSid, null);
            CommonAce ca = new CommonAce(
                AceFlags.None, 
                AceQualifier.AccessAllowed, 
                ComACLRights.COM_RIGHTS_EXECUTE | ComACLRights.COM_RIGHTS_EXECUTE_LOCAL | ComACLRights.COM_RIGHTS_ACTIVATE_LOCAL, 
                si, 
                false, 
                null);
            acl.InsertAce(acl.Count, ca);
        }
        //re-set the ACL
        sd.DiscretionaryAcl = acl;

        byte[] binaryform = new byte[sd.BinaryLength];
        sd.GetBinaryForm(binaryform, 0);
        Registry.SetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Ole", "DefaultAccessPermission", binaryform, RegistryValueKind.Binary);
    }
}

The answer posted by Daniel was HUGELY helpful. Thank you so much, Daniel!

An issue with Microsoft's documentation is that they indicate that the registry values contain an ACL in binary form. So, for instance, if you were trying to set the machine's default access (rather than per-process), you would be accessing registry key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Ole\DefaultAccessPermission. However, in my initial attempts to access this key using the System.Security.AccessControl.RawACL class were failing.

As Daniel's code indicate's the value is not actually an ACL, but really is a SecurityDescriptor with the ACL in it.

So, even though I know this post is old, I'm going to post my solution for checking and setting the security settings and adding NetworkService for Default local access. Of course, you could take this and make it better I'm sure, but to get started you would simply need to change the key and the access mask.

static class ComACLRights{
    public const int COM_RIGHTS_EXECUTE= 1;
    public const int COM_RIGHTS_EXECUTE_LOCAL = 2;
    public const int COM_RIGHTS_EXECUTE_REMOTE = 4;
    public const int COM_RIGHTS_ACTIVATE_LOCAL = 8;
    public const int COM_RIGHTS_ACTIVATE_REMOTE = 16;
}
class Program
{
    static void Main(string[] args)
    {
        var value = Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Ole", "DefaultAccessPermission", null);

        RawSecurityDescriptor sd;
        RawAcl acl;

        if (value == null)
        {
            System.Console.WriteLine("Default Access Permission key has not been created yet");
            sd = new RawSecurityDescriptor("");
        }else{
            sd = new RawSecurityDescriptor(value as byte[], 0);
        }
        acl = sd.DiscretionaryAcl;
        bool found = false;
        foreach (CommonAce ca in acl)
        {
            if (ca.SecurityIdentifier.IsWellKnown(WellKnownSidType.NetworkServiceSid))
            {
                //ensure local access is set
                ca.AccessMask |= ComACLRights.COM_RIGHTS_EXECUTE | ComACLRights.COM_RIGHTS_EXECUTE_LOCAL | ComACLRights.COM_RIGHTS_ACTIVATE_LOCAL;    //set local access.  Always set execute
                found = true;
                break;
            }
        }
        if(!found){
            //Network Service was not found.  Add it to the ACL
            SecurityIdentifier si = new SecurityIdentifier( 
                WellKnownSidType.NetworkServiceSid, null);
            CommonAce ca = new CommonAce(
                AceFlags.None, 
                AceQualifier.AccessAllowed, 
                ComACLRights.COM_RIGHTS_EXECUTE | ComACLRights.COM_RIGHTS_EXECUTE_LOCAL | ComACLRights.COM_RIGHTS_ACTIVATE_LOCAL, 
                si, 
                false, 
                null);
            acl.InsertAce(acl.Count, ca);
        }
        //re-set the ACL
        sd.DiscretionaryAcl = acl;

        byte[] binaryform = new byte[sd.BinaryLength];
        sd.GetBinaryForm(binaryform, 0);
        Registry.SetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Ole", "DefaultAccessPermission", binaryform, RegistryValueKind.Binary);
    }
}
我家小可爱 2024-07-18 07:37:46

面对类似的情况(从 MSI 配置 DCOM 安全性),我设法创建一个解决方案,通过更改 HKEY_CLASSES_ROOT\AppID{APP-GUID-GOES-HERE} 中的注册表项值来完成我想要的操作。 感谢阿诺特的回答让我走上了正确的道路。

具体来说,我创建了一个方法来编辑 DCOM 对象的安全权限,这些权限存储在 LaunchPermission 和 AccessPermission 注册表项值中。 这些是序列化的安全描述符,您可以通过 RawSecurityDescriptor 传递二进制数据来访问它们。 此类以美味的 .NET-y 方式简化了许多细节,但您仍然需要注意有关 Windows ACL 的所有逻辑细节,并且必须确保使用 <代码>RawSecurityDescriptor.GetBinaryForm。

我创建的方法称为 EditOrCreateACE。 此方法将编辑帐户的现有 ACE,或插入新的 ACE,并确保访问掩码已设置传递的标志。 我将其作为示例附在此处,这绝不是有关如何处理它的任何权威,因为我对 Windows ACL 的知识仍然知之甚少:

// These are constants for the access mask on LaunchPermission.
// I'm unsure of the exact constants for AccessPermission
private const int COM_RIGHTS_EXECUTE = 1;
private const int COM_RIGHTS_EXECUTE_LOCAL = 2;
private const int COM_RIGHTS_EXECUTE_REMOTE = 4;
private const int COM_RIGHTS_ACTIVATE_LOCAL = 8;
private const int COM_RIGHTS_ACTIVATE_REMOTE = 16;

void EditOrCreateACE(string keyname, string valuename,
                      string accountname, int mask)
{
    // Get security descriptor from registry
    byte[] keyval = (byte[]) Registry.GetValue(keyname, valuename,
                                               new byte[] { });
    RawSecurityDescriptor sd;
    if (keyval.Length > 0) {
        sd = new RawSecurityDescriptor(keyval, 0);
    } else {
        sd = InitializeEmptySecurityDescriptor();
    }
    RawAcl acl = sd.DiscretionaryAcl;

    CommonAce accountACE = null;

    // Look for the account in the ACL
    int i = 0;
    foreach (GenericAce ace in acl) {
        if (ace.AceType == AceType.AccessAllowed) {
            CommonAce c_ace = ace as CommonAce;
            NTAccount account = 
                c_ace.SecurityIdentifier.Translate(typeof(NTAccount))
                as NTAccount;
            if (account.Value.Contains(accountname)) {
                accountACE = c_ace;
            }
            i++;
        }
    }

    // If no ACE found for the given account, insert a new one at the end
    // of the ACL, otherwise just set the mask
    if (accountACE == null) {
        SecurityIdentifier ns_account = 
            (new NTAccount(accountname)).Translate(typeof(SecurityIdentifier))
            as SecurityIdentifier;
        CommonAce ns = new CommonAce(AceFlags.None, AceQualifier.AccessAllowed,
                                     mask, ns_account, false, null);
        acl.InsertAce(acl.Count, ns);
    } else {
        accountACE.AccessMask |= mask;
    }

    // Write security descriptor back to registry
    byte[] binarySd = new byte[sd.BinaryLength];
    sd.GetBinaryForm(binarySd, 0);
    Registry.SetValue(keyname, valuename, binarySd);
}

private static RawSecurityDescriptor InitializeEmptySecurityDescriptor()
{
    var localSystem = 
        new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null);
    var new_sd =
        new RawSecurityDescriptor(ControlFlags.DiscretionaryAclPresent,
                                  localSystem, localSystem, null,
                                  new RawAcl(GenericAcl.AclRevision, 1));
    return new_sd;
}

请注意,此代码绝不是完美的。 如果注册表中缺少这些 ACL 的整个注册表项值,则合成的 ACL 将仅授予对所传递帐户的访问权限,而不会授予其他任何权限。 我还确信有很多错误情况我没有正确处理,并且我掩盖了很多细节。 同样,它是如何在 .NET 中处理 DCOM ACL 的示例

Facing similar circumstances (configuring DCOM security from an MSI) I managed to create a solution that does what I want by altering registry key values in HKEY_CLASSES_ROOT\AppID{APP-GUID-GOES-HERE}. Thanks to Arnout's answer for setting me on the right path.

In specific, I created a method to edit the security permissions for DCOM objects, which are stored in the LaunchPermission and AccessPermission registry key values. These are serialized security descriptors, which you can access by passing the binary data through RawSecurityDescriptor. This class simplifies a lot of the details in a delicious .NET-y fashion, but you still have to attend to all the logical details regarding Windows ACL, and you have to make sure to write the security descriptor back to the registry by using RawSecurityDescriptor.GetBinaryForm.

The method I created was called EditOrCreateACE. This method will either edit an existing ACE for an account, or insert a new one, and ensure that the access mask has the passed flags set. I attach it here as an example, this is by no means any authority on how to deal with it, since I know very little of Windows ACL stuff still:

// These are constants for the access mask on LaunchPermission.
// I'm unsure of the exact constants for AccessPermission
private const int COM_RIGHTS_EXECUTE = 1;
private const int COM_RIGHTS_EXECUTE_LOCAL = 2;
private const int COM_RIGHTS_EXECUTE_REMOTE = 4;
private const int COM_RIGHTS_ACTIVATE_LOCAL = 8;
private const int COM_RIGHTS_ACTIVATE_REMOTE = 16;

void EditOrCreateACE(string keyname, string valuename,
                      string accountname, int mask)
{
    // Get security descriptor from registry
    byte[] keyval = (byte[]) Registry.GetValue(keyname, valuename,
                                               new byte[] { });
    RawSecurityDescriptor sd;
    if (keyval.Length > 0) {
        sd = new RawSecurityDescriptor(keyval, 0);
    } else {
        sd = InitializeEmptySecurityDescriptor();
    }
    RawAcl acl = sd.DiscretionaryAcl;

    CommonAce accountACE = null;

    // Look for the account in the ACL
    int i = 0;
    foreach (GenericAce ace in acl) {
        if (ace.AceType == AceType.AccessAllowed) {
            CommonAce c_ace = ace as CommonAce;
            NTAccount account = 
                c_ace.SecurityIdentifier.Translate(typeof(NTAccount))
                as NTAccount;
            if (account.Value.Contains(accountname)) {
                accountACE = c_ace;
            }
            i++;
        }
    }

    // If no ACE found for the given account, insert a new one at the end
    // of the ACL, otherwise just set the mask
    if (accountACE == null) {
        SecurityIdentifier ns_account = 
            (new NTAccount(accountname)).Translate(typeof(SecurityIdentifier))
            as SecurityIdentifier;
        CommonAce ns = new CommonAce(AceFlags.None, AceQualifier.AccessAllowed,
                                     mask, ns_account, false, null);
        acl.InsertAce(acl.Count, ns);
    } else {
        accountACE.AccessMask |= mask;
    }

    // Write security descriptor back to registry
    byte[] binarySd = new byte[sd.BinaryLength];
    sd.GetBinaryForm(binarySd, 0);
    Registry.SetValue(keyname, valuename, binarySd);
}

private static RawSecurityDescriptor InitializeEmptySecurityDescriptor()
{
    var localSystem = 
        new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null);
    var new_sd =
        new RawSecurityDescriptor(ControlFlags.DiscretionaryAclPresent,
                                  localSystem, localSystem, null,
                                  new RawAcl(GenericAcl.AclRevision, 1));
    return new_sd;
}

Do note that this code is by no means perfect. If the entire registry key value for these ACL is missing in the registry, the ACL that is synthesized will ONLY grant access to the passed account and nothing else. I'm also sure there are lots of error conditions I've not handled properly and details I've glossed over. Again, it's an example of how to deal with DCOM ACL in .NET.

喵星人汪星人 2024-07-18 07:37:46

此信息存储在 HKCR\AppID\{Your-AppID}\LaunchPermissionAccessPermission 中。 这些是包含序列化安全描述符的 REG_BINARY 值。 不知道是否有任何东西可以方便地访问 .NET 中的内容...

有关 MSDN

This information is stored in HKCR\AppID\{Your-AppID}\LaunchPermission and AccessPermission. These are REG_BINARY values containing serialized security descriptors. No idea whether there's anything providing convenient access to those from .NET...

More info on MSDN.

苍风燃霜 2024-07-18 07:37:46

我找不到任何 .NET 方法来执行此操作 - 您可以使用 MS 命令行实用程序 DCOMPerm(也此处) 这是 SDK 的一部分。

I couldn't find any .NET way of doing this - you can use the MS command line utility DCOMPerm (also here) which is part of the SDK.

假装爱人 2024-07-18 07:37:46

我发现这个解决方案有效:

    public static void SetUp()
    {
        SetCOMSercurityAccess("DefaultAccessPermission");
        SetCOMSercurityAccess("DefaultLaunchPermission");
    }
    private static void SetCOMSercurityAccess(string regKey)
    {
        //This is the magic permission!
        byte[] binaryform = new string[]
        {
            "01","00","04","80","80","00","00","00","90","00","00","00","00","00","00","00","14","00","00","00","02","00","6c","00","04",
            "00","00","00","00","00","14","00","1f","00","00","00","01","01","00","00","00","00","00","05","12","00","00","00","00","00",
            "24","00","0b","00","00","00","01","05","00","00","00","00","00","05","15","00","00","00","a3","53","d8","c8","94","bd","63",
            "84","88","bf","fa","cf","a7","2b","00","00","00","00","18","00","1f","00","00","00","01","02","00","00","00","00","00","05",
            "20","00","00","00","20","02","00","00","00","00","14","00","1f","00","00","00","01","01","00","00","00","00","00","05","04",
            "00","00","00","01","02","00","00","00","00","00","05","20","00","00","00","20","02","00","00","01","02","00","00","00","00",
            "00","05","20","00","00","00","20","02","00","00"
        }.Select(o=> Convert.ToByte(o,16)).ToArray();
        Registry.SetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Ole", regKey, binaryform, RegistryValueKind.Binary);
    }

如果它可以帮助其他人......

I found this solution working:

    public static void SetUp()
    {
        SetCOMSercurityAccess("DefaultAccessPermission");
        SetCOMSercurityAccess("DefaultLaunchPermission");
    }
    private static void SetCOMSercurityAccess(string regKey)
    {
        //This is the magic permission!
        byte[] binaryform = new string[]
        {
            "01","00","04","80","80","00","00","00","90","00","00","00","00","00","00","00","14","00","00","00","02","00","6c","00","04",
            "00","00","00","00","00","14","00","1f","00","00","00","01","01","00","00","00","00","00","05","12","00","00","00","00","00",
            "24","00","0b","00","00","00","01","05","00","00","00","00","00","05","15","00","00","00","a3","53","d8","c8","94","bd","63",
            "84","88","bf","fa","cf","a7","2b","00","00","00","00","18","00","1f","00","00","00","01","02","00","00","00","00","00","05",
            "20","00","00","00","20","02","00","00","00","00","14","00","1f","00","00","00","01","01","00","00","00","00","00","05","04",
            "00","00","00","01","02","00","00","00","00","00","05","20","00","00","00","20","02","00","00","01","02","00","00","00","00",
            "00","05","20","00","00","00","20","02","00","00"
        }.Select(o=> Convert.ToByte(o,16)).ToArray();
        Registry.SetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Ole", regKey, binaryform, RegistryValueKind.Binary);
    }

In case it help others...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文