Commit 716ec99a authored by jan.koester's avatar jan.koester
Browse files

test

parent 941093c6
Loading
Loading
Loading
Loading
Loading
+42 −38
Changes for plugin/ad/ad.cpp: 42 added lines, 38 removed lines.
Original line number Diff line number Diff line
@@ -2233,6 +2233,46 @@ static bool serverOwnedAttr(const std::string &canon) {
    return dsdb::iequals(canon, "objectSid") || dsdb::iequals(canon, "objectGUID");
}

namespace {
    const dsdb::Values *attrVals(const dsdb::AttrMap &a, const char *name) {
        auto it = a.find(name);
        return it == a.end() ? nullptr : &it->second;
    }
    std::string dnKey(const std::string &s) {
        dsdb::Dn d;
        return dsdb::Dn::parse(s, d) ? d.key() : dsdb::lower(s);
    }
    /* add/remove `dnStr` in attribute `attr` of the object at `target` */
    void editLink(dsdb::Directory &dir, const std::string &target, const char *attr,
                  const std::string &dnStr, bool add) {
        dsdb::Dn tdn;
        if (!dsdb::Dn::parse(target, tdn)) return;
        auto e = dir.byDn(tdn);
        if (!e) return;
        dsdb::Values v = e->get(attr) ? *e->get(attr) : dsdb::Values{};
        std::string k = dnKey(dnStr);
        auto it = std::find_if(v.begin(), v.end(), [&](const std::string &x) { return dnKey(x) == k; });
        if (add == (it != v.end())) return;
        if (add) v.push_back(dnStr); else v.erase(it);
        dsdb::AttrMap a;
        a[attr] = v;
        try { dir.modify(e->objectGuid, a, nullptr, true); } catch (...) {}
    }
    /* keep member.memberOf in step with a group's member list, as AD's
     * linked attributes do (Kerberos PACs are built from memberOf) */
    void syncMemberOf(dsdb::Directory &dir, const std::string &groupDn,
                      const dsdb::Values &oldMembers, const dsdb::Values &newMembers) {
        auto has = [](const dsdb::Values &v, const std::string &x) {
            std::string k = dnKey(x);
            return std::any_of(v.begin(), v.end(), [&](const std::string &y) { return dnKey(y) == k; });
        };
        for (auto &m : newMembers)
            if (!has(oldMembers, m)) editLink(dir, m, "memberOf", groupDn, true);
        for (auto &m : oldMembers)
            if (!has(newMembers, m)) editLink(dir, m, "memberOf", groupDn, false);
    }
}

std::vector<uint8_t> ActiveDirectory::handleAddRequest(const uint8_t *content, size_t len,
                                                       int32_t msgId, LdapSession &session) {
    const uint8_t appResp = LdapBer::CLASS_APPLICATION | LdapBer::CONSTRUCTED | LDAP_ADD_RESPONSE;
@@ -2314,7 +2354,7 @@ std::vector<uint8_t> ActiveDirectory::handleAddRequest(const uint8_t *content, s
            attrs["objectSid"] = {d->meta.sid.withRid(rid).binary()};
        }
        d->dir->create(dn, attrs, sec.get());
        if (auto *mem = dsdb::get(attrs, "member"))
        if (auto *mem = attrVals(attrs, "member"))
            syncMemberOf(*d->dir, dn.str(), {}, *mem);
    } catch (std::exception &e) {
        return buildLdapMessage(msgId, appResp, buildLdapResult(LDAP_OTHER, "", e.what()));
@@ -2322,42 +2362,6 @@ std::vector<uint8_t> ActiveDirectory::handleAddRequest(const uint8_t *content, s
    return buildLdapMessage(msgId, appResp, buildLdapResult(LDAP_SUCCESS, "", ""));
}

namespace {
    std::string dnKey(const std::string &s) {
        dsdb::Dn d;
        return dsdb::Dn::parse(s, d) ? d.key() : dsdb::lower(s);
    }
    /* add/remove `dnStr` in attribute `attr` of the object at `target` */
    void editLink(dsdb::Directory &dir, const std::string &target, const char *attr,
                  const std::string &dnStr, bool add) {
        dsdb::Dn tdn;
        if (!dsdb::Dn::parse(target, tdn)) return;
        auto e = dir.byDn(tdn);
        if (!e) return;
        dsdb::Values v = e->get(attr) ? *e->get(attr) : dsdb::Values{};
        std::string k = dnKey(dnStr);
        auto it = std::find_if(v.begin(), v.end(), [&](const std::string &x) { return dnKey(x) == k; });
        if (add == (it != v.end())) return;
        if (add) v.push_back(dnStr); else v.erase(it);
        dsdb::AttrMap a;
        a[attr] = v;
        try { dir.modify(e->objectGuid, a, nullptr, true); } catch (...) {}
    }
    /* keep member.memberOf in step with a group's member list, as AD's
     * linked attributes do (Kerberos PACs are built from memberOf) */
    void syncMemberOf(dsdb::Directory &dir, const std::string &groupDn,
                      const dsdb::Values &oldMembers, const dsdb::Values &newMembers) {
        auto has = [](const dsdb::Values &v, const std::string &x) {
            std::string k = dnKey(x);
            return std::any_of(v.begin(), v.end(), [&](const std::string &y) { return dnKey(y) == k; });
        };
        for (auto &m : newMembers)
            if (!has(oldMembers, m)) editLink(dir, m, "memberOf", groupDn, true);
        for (auto &m : oldMembers)
            if (!has(newMembers, m)) editLink(dir, m, "memberOf", groupDn, false);
    }
}

std::vector<uint8_t> ActiveDirectory::handleModifyRequest(const uint8_t *content, size_t len,
                                                          int32_t msgId, LdapSession &session) {
    const uint8_t appResp = LdapBer::CLASS_APPLICATION | LdapBer::CONSTRUCTED | LDAP_MODIFY_RESPONSE;
@@ -2472,7 +2476,7 @@ std::vector<uint8_t> ActiveDirectory::handleModifyRequest(const uint8_t *content
            dsdb::setInt(attrs, "msDS-KeyVersionNumber", newSec->kvno);
        d->dir->modify(cur->objectGuid, attrs, newSec.get());
        const dsdb::Values none;
        const dsdb::Values *was = cur->get("member"), *now = dsdb::get(attrs, "member");
        const dsdb::Values *was = cur->get("member"), *now = attrVals(attrs, "member");
        if (was || now)
            syncMemberOf(*d->dir, cur->dn.str(), was ? *was : none, now ? *now : none);
    } catch (std::exception &e) {