Loading plugin/ad/ad.cpp +25 −3 Changes for plugin/ad/ad.cpp: 25 added lines, 3 removed lines. Original line number Diff line number Diff line Loading @@ -1766,7 +1766,8 @@ LdapEntry ActiveDirectory::renderEntry(const dsdb::Entry &ent, } /* objectGUID is the record UUID (a separate Entry field, not in attrs): * synthesize it as the 16-byte binary GUID AD clients expect. Windows * synthesize it as the 16-byte binary GUID AD clients expect -- the * UUID's bytes as they are (network order), see buildRootDSE(). Windows * reads the domain/computer objectGUID during a join and rejects an entry * that lacks it (ERROR_INVALID_PARAMETER). */ if (!ent.attrs.count("objectGUID") && wanted("objectGUID", findAttribute("objectGUID"))) { Loading Loading @@ -1972,6 +1973,12 @@ LdapEntry ActiveDirectory::buildRootDSE() { e.addAttribute("supportedSASLMechanisms", std::vector<std::string>{"GSSAPI", "GSS-SPNEGO"}); e.addAttribute("vendorName", "tuxist.de"); e.addAttribute("vendorVersion", "FenrirDirectoryServer"); /* Our objectGUIDs are the record UUIDs (RFC 9562 version 4) in network * byte order -- not a Windows GUID with Data1-3 little endian, though * Windows reads the same 16 bytes as one. FenrirOS members * (adconnect id_mapping: uuid) take them as the accounts' native UUID * ids only when this says so. */ e.addAttribute("fenrirObjectGuidIsUuid", "TRUE"); e.addAttribute("isSynchronized", "TRUE"); e.addAttribute("supportedControl", std::vector<std::string>{ "1.2.840.113556.1.4.319", /* paged results */ Loading Loading @@ -2121,6 +2128,13 @@ bool ActiveDirectory::parseFilter(const uint8_t *data, size_t len, dsdb::Filter /****************************************************************************** * Add / Modify / Delete / ModifyDN *****************************************************************************/ /* objectSid and objectGUID are the server's: FenrirOS members map file * owners between them and the accounts' ids (adconnect SIDOF/IDOF), so a * client that could set them could take over another account's files. */ static bool serverOwnedAttr(const std::string &canon) { return dsdb::iequals(canon, "objectSid") || dsdb::iequals(canon, "objectGUID"); } 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; Loading Loading @@ -2163,8 +2177,13 @@ std::vector<uint8_t> ActiveDirectory::handleAddRequest(const uint8_t *content, s while (voff < pl && LdapBer::parseTLV(pc, pl, voff, vt, vc, vl)) vals.emplace_back(reinterpret_cast<const char*>(vc), vl); } if (!type.empty()) attrs[dsdb::canonicalName(type)] = std::move(vals); if (!type.empty()) { std::string canon = dsdb::canonicalName(type); if (serverOwnedAttr(canon)) return buildLdapMessage(msgId, appResp, buildLdapResult(LDAP_UNWILLING_TO_PERFORM, "", canon + " is set by the server")); attrs[canon] = std::move(vals); } } } Loading Loading @@ -2267,6 +2286,9 @@ std::vector<uint8_t> ActiveDirectory::handleModifyRequest(const uint8_t *content if (type.empty()) continue; std::string canon = dsdb::canonicalName(type); if (serverOwnedAttr(canon)) return buildLdapMessage(msgId, appResp, buildLdapResult(LDAP_UNWILLING_TO_PERFORM, "", canon + " is set by the server")); if (dsdb::iequals(canon, "unicodePwd")) { if (!vals.empty()) { Loading src/dsdb/directory.cpp +20 −2 Changes for src/dsdb/directory.cpp: 20 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -39,7 +39,7 @@ MatchContext Directory::matchContext() { Dn d; if (!Dn::parse(cur, d)) continue; std::lock_guard<std::mutex> lk(_Mtx); /* search() holds _Mtx already (matchContext()'s only user) */ Entry *e = findByDnLocked(d); if (!e) continue; Loading Loading @@ -99,11 +99,23 @@ Entry *Directory::findByDnLocked(const Dn &dn) { return &_Entries[it->second]; } /* objectGUID is the record UUID, not in the attribute map: a filter on it * (adconnect finds an account by its id this way) needs it added */ static bool mentionsGuid(const Filter &f) { if (iequals(f.attr, "objectGUID")) return true; for (auto &c : f.children) if (mentionsGuid(c)) return true; return false; } void Directory::search(const Dn &base, int scope, const Filter &filter, const std::function<bool(const Entry &)> &sink) { std::lock_guard<std::mutex> lk(_Mtx); ensureFresh(); MatchContext ctx = matchContext(); bool withGuid = mentionsGuid(filter); for (auto &e : _Entries) { bool inScope = false; switch (scope) { Loading @@ -113,7 +125,13 @@ void Directory::search(const Dn &base, int scope, const Filter &filter, } if (!inScope) continue; if (!matches(filter, e.attrs, ctx)) if (withGuid) { AttrMap a = e.attrs; if (!a.count("objectGUID")) a["objectGUID"] = {std::string(reinterpret_cast<const char*>(e.objectGuid.value), 16)}; if (!matches(filter, a, ctx)) continue; } else if (!matches(filter, e.attrs, ctx)) continue; if (!sink(e)) return; Loading src/dsdb/directory.h +1 −0 Changes for src/dsdb/directory.h: 1 added line, 0 removed lines. Original line number Diff line number Diff line Loading @@ -128,6 +128,7 @@ namespace fenrirds { /* next RID from the domain head's pool */ uint32_t allocateRid(); /* with _Mtx held: its callbacks look entries up unlocked */ MatchContext matchContext(); private: Loading Loading
plugin/ad/ad.cpp +25 −3 Changes for plugin/ad/ad.cpp: 25 added lines, 3 removed lines. Original line number Diff line number Diff line Loading @@ -1766,7 +1766,8 @@ LdapEntry ActiveDirectory::renderEntry(const dsdb::Entry &ent, } /* objectGUID is the record UUID (a separate Entry field, not in attrs): * synthesize it as the 16-byte binary GUID AD clients expect. Windows * synthesize it as the 16-byte binary GUID AD clients expect -- the * UUID's bytes as they are (network order), see buildRootDSE(). Windows * reads the domain/computer objectGUID during a join and rejects an entry * that lacks it (ERROR_INVALID_PARAMETER). */ if (!ent.attrs.count("objectGUID") && wanted("objectGUID", findAttribute("objectGUID"))) { Loading Loading @@ -1972,6 +1973,12 @@ LdapEntry ActiveDirectory::buildRootDSE() { e.addAttribute("supportedSASLMechanisms", std::vector<std::string>{"GSSAPI", "GSS-SPNEGO"}); e.addAttribute("vendorName", "tuxist.de"); e.addAttribute("vendorVersion", "FenrirDirectoryServer"); /* Our objectGUIDs are the record UUIDs (RFC 9562 version 4) in network * byte order -- not a Windows GUID with Data1-3 little endian, though * Windows reads the same 16 bytes as one. FenrirOS members * (adconnect id_mapping: uuid) take them as the accounts' native UUID * ids only when this says so. */ e.addAttribute("fenrirObjectGuidIsUuid", "TRUE"); e.addAttribute("isSynchronized", "TRUE"); e.addAttribute("supportedControl", std::vector<std::string>{ "1.2.840.113556.1.4.319", /* paged results */ Loading Loading @@ -2121,6 +2128,13 @@ bool ActiveDirectory::parseFilter(const uint8_t *data, size_t len, dsdb::Filter /****************************************************************************** * Add / Modify / Delete / ModifyDN *****************************************************************************/ /* objectSid and objectGUID are the server's: FenrirOS members map file * owners between them and the accounts' ids (adconnect SIDOF/IDOF), so a * client that could set them could take over another account's files. */ static bool serverOwnedAttr(const std::string &canon) { return dsdb::iequals(canon, "objectSid") || dsdb::iequals(canon, "objectGUID"); } 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; Loading Loading @@ -2163,8 +2177,13 @@ std::vector<uint8_t> ActiveDirectory::handleAddRequest(const uint8_t *content, s while (voff < pl && LdapBer::parseTLV(pc, pl, voff, vt, vc, vl)) vals.emplace_back(reinterpret_cast<const char*>(vc), vl); } if (!type.empty()) attrs[dsdb::canonicalName(type)] = std::move(vals); if (!type.empty()) { std::string canon = dsdb::canonicalName(type); if (serverOwnedAttr(canon)) return buildLdapMessage(msgId, appResp, buildLdapResult(LDAP_UNWILLING_TO_PERFORM, "", canon + " is set by the server")); attrs[canon] = std::move(vals); } } } Loading Loading @@ -2267,6 +2286,9 @@ std::vector<uint8_t> ActiveDirectory::handleModifyRequest(const uint8_t *content if (type.empty()) continue; std::string canon = dsdb::canonicalName(type); if (serverOwnedAttr(canon)) return buildLdapMessage(msgId, appResp, buildLdapResult(LDAP_UNWILLING_TO_PERFORM, "", canon + " is set by the server")); if (dsdb::iequals(canon, "unicodePwd")) { if (!vals.empty()) { Loading
src/dsdb/directory.cpp +20 −2 Changes for src/dsdb/directory.cpp: 20 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -39,7 +39,7 @@ MatchContext Directory::matchContext() { Dn d; if (!Dn::parse(cur, d)) continue; std::lock_guard<std::mutex> lk(_Mtx); /* search() holds _Mtx already (matchContext()'s only user) */ Entry *e = findByDnLocked(d); if (!e) continue; Loading Loading @@ -99,11 +99,23 @@ Entry *Directory::findByDnLocked(const Dn &dn) { return &_Entries[it->second]; } /* objectGUID is the record UUID, not in the attribute map: a filter on it * (adconnect finds an account by its id this way) needs it added */ static bool mentionsGuid(const Filter &f) { if (iequals(f.attr, "objectGUID")) return true; for (auto &c : f.children) if (mentionsGuid(c)) return true; return false; } void Directory::search(const Dn &base, int scope, const Filter &filter, const std::function<bool(const Entry &)> &sink) { std::lock_guard<std::mutex> lk(_Mtx); ensureFresh(); MatchContext ctx = matchContext(); bool withGuid = mentionsGuid(filter); for (auto &e : _Entries) { bool inScope = false; switch (scope) { Loading @@ -113,7 +125,13 @@ void Directory::search(const Dn &base, int scope, const Filter &filter, } if (!inScope) continue; if (!matches(filter, e.attrs, ctx)) if (withGuid) { AttrMap a = e.attrs; if (!a.count("objectGUID")) a["objectGUID"] = {std::string(reinterpret_cast<const char*>(e.objectGuid.value), 16)}; if (!matches(filter, a, ctx)) continue; } else if (!matches(filter, e.attrs, ctx)) continue; if (!sink(e)) return; Loading
src/dsdb/directory.h +1 −0 Changes for src/dsdb/directory.h: 1 added line, 0 removed lines. Original line number Diff line number Diff line Loading @@ -128,6 +128,7 @@ namespace fenrirds { /* next RID from the domain head's pool */ uint32_t allocateRid(); /* with _Mtx held: its callbacks look entries up unlocked */ MatchContext matchContext(); private: Loading