【问题标题】:How can I access the nTSecurityDescriptor with a normal ldap client?如何使用普通 ldap 客户端访问 nTSecurityDescriptor?
【发布时间】:2013-05-13 12:13:24
【问题描述】:

我尝试以普通域用户的身份使用 ldapsearch(或其他东西)从 linux 机器上读取 nTSecurityDescriptor

搜索其他东西可以,但我找不到nTSecurityDescriptor

This KB 可能是相关的,但作为域管理员运行不是服务的选项。

那么我该如何阅读这些信息呢?我知道我可以阅读 DACL,但问题是如何阅读。

【问题讨论】:

    标签: active-directory ldap


    【解决方案1】:

    我为 Windows ntSecurityDescriptor 管理创建了一个新的 Java (JNDI) 库(Apache2 许可证)。从http://blog.tirasa.net/ntsecuritydescripto-management.html 开始阅读介绍。

    查看库 (https://github.com/Tirasa/ADSDDL) 集成测试以获取任何帮助。 以下示例将“用户无法更改密码”ACE 添加到 DACL。

    final SearchControls controls = new SearchControls();
    controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
    controls.setReturningAttributes(new String[] { "nTSecurityDescriptor" });
    
    ctx.setRequestControls(new Control[] { new SDFlagsControl(0x00000004) });
    
    NamingEnumeration<SearchResult> results = 
        ctx.search(baseContext, searchFilter, controls);
    
    SearchResult res = results.next();
    final String dn = res.getNameInNamespace();
    
    byte[] orig = (byte[]) res.getAttributes().get("nTSecurityDescriptor").get();
    
    SDDL sddl = new SDDL(orig);
    results.close();
    
    final List<ACE> toBeChanged = new ArrayList<>();
    
    for (ACE ace : sddl.getDacl().getAces()) {
        if ((ace.getType() == AceType.ACCESS_ALLOWED_OBJECT_ACE_TYPE
           || ace.getType() == AceType.ACCESS_DENIED_OBJECT_ACE_TYPE)
           && ace.getObjectFlags().getFlags().contains(
                     AceObjectFlags.Flag.ACE_OBJECT_TYPE_PRESENT)) {
            if (GUID.getGuidAsString(ace.getObjectType()).equals(
                         UCP_OBJECT_GUID)) {
    
                final SID sid = ace.getSid();
                if (sid.getSubAuthorities().size() == 1
                    && ((Arrays.equals(sid.getIdentifierAuthority(), 
                       new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 })
                    && Arrays.equals(sid.getSubAuthorities().get(0), 
                       new byte[] { 0x00, 0x00, 0x00, 0x00 }))
                    || (Arrays.equals(sid.getIdentifierAuthority(), 
                       new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x05 })
                     && Arrays.equals(sid.getSubAuthorities().get(0), 
                       new byte[] { 0x00, 0x00, 0x00, 0x0a })))) {
                    toBeChanged.add(ace);
                }
            }
        }
    }
    
    if (toBeChanged.isEmpty()) {
        // prepare aces
        ACE self = ACE.newInstance(AceType.ACCESS_DENIED_OBJECT_ACE_TYPE);
        self.setObjectFlags(new AceObjectFlags(
                    AceObjectFlags.Flag.ACE_OBJECT_TYPE_PRESENT));
        self.setObjectType(GUID.getGuidAsByteArray(UCP_OBJECT_GUID));
        self.setRights(new AceRights().addOjectRight(AceRights.ObjectRight.CR));
        SID sd = SID.newInstance(NumberFacility.getBytes(0x000000000001));
        sd.addSubAuthority(NumberFacility.getBytes(0));
        self.setSid(sd);
    
        ACE all = ACE.newInstance(AceType.ACCESS_DENIED_OBJECT_ACE_TYPE);
        all.setObjectFlags(new AceObjectFlags(
                    AceObjectFlags.Flag.ACE_OBJECT_TYPE_PRESENT));
        all.setObjectType(GUID.getGuidAsByteArray(UCP_OBJECT_GUID));
        all.setRights(new AceRights().addOjectRight(AceRights.ObjectRight.CR));
        sd = SID.newInstance(NumberFacility.getBytes(0x000000000005));
        sd.addSubAuthority(NumberFacility.getBytes(0x0A));
        all.setSid(sd);
    
        sddl.getDacl().getAces().add(self);
        sddl.getDacl().getAces().add(all);
    } else {
        for (ACE ace : toBeChanged) {
            ace.setType(AceType.ACCESS_DENIED_OBJECT_ACE_TYPE);
        }
    }
    
    final Attribute ntSecurityDescriptor = new BasicAttribute(
          "ntSecurityDescriptor", sddl.toByteArray());
    
    final ModificationItem[] mods = new ModificationItem[1];
    mods[0] = new ModificationItem(
          DirContext.REPLACE_ATTRIBUTE, ntSecurityDescriptor);
    
    ctx.modifyAttributes(dn, mods);
    // .....
    

    【讨论】:

    • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接的答案可能会失效。
    • 我刚刚包含了答案的基本部分。
    【解决方案2】:

    要将ntSecurityDescriptor 选择为非特权帐户,您需要使用值为7 的LDAP_SERVER_SD_FLAGS_OID 服务器控件。这表示您希望安全描述符的所有部分都减去SACL。默认值(包括 SACL)似乎是导致属性不返回的原因,因为大多数非特权帐户将无权访问 SACL,因此 AD 似乎什么也不返回。

    此问题/答案中的更多详细信息:

    Selecting the AD ntSecurityDescriptor Attribute as a Non-Admin

    【讨论】:

    • 使用ldapsearch命令行工具时可以设置这个标志吗?
    【解决方案3】:

    看起来,这是不可能的。

    很遗憾微软产品使用的底层API(COM API等)不是开源的,所以我什至不知道怎么做。

    但我可以通过 windows API 调用 GetSecurityInfo 在 windows 上获取安全描述符。

    【讨论】:

    • ntSecurityDescriptor 的格式作为 MS-DTYP 开放规范文档的一部分在安全描述符第 2.4 节及其小节中进行了详细描述。挑战在于将其转换为可以实际解码结构的代码,因为它不是微软在开源世界中提供库的东西。 Fabio Martelli 创建并在他的回答中引用的库对于那些尝试自己实现的人来说是一个很好的参考。
    • 问题是我如何获得二进制数据块。我必须向 LDAP 服务器发送什么?
    • 好像以非管理员身份取值,需要设置LDAP_SERVER_SD_FLAGS_OID服务器控件。有关控件的一些信息,请参阅此:msdn.microsoft.com/en-us/library/cc223323.aspx。似乎在管理用户下运行时假定控制,而不是在普通帐户下运行。但是,我还没有对此进行测试。
    • @ChadSikorra 谢谢,这正是我想要的。
    • 如果您有兴趣,我在this answer 有更多详细信息。看来ntSecurityDescriptor 没有为普通用户返回的原因是他们无权访问安全描述符的 SACL。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-12-27
    • 1970-01-01
    • 2015-02-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多