Loading plugin/ad/ad.cpp +75 −0 Changes for plugin/ad/ad.cpp: 75 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -1722,6 +1722,55 @@ std::vector<uint8_t> ActiveDirectory::handleUnbindRequest(int32_t, LdapSession & /****************************************************************************** * Search *****************************************************************************/ namespace { /* the subschema subentry (RFC 4512 4.2) generated from the schema * tables: attributeTypes and objectClasses in RFC 4512 notation */ LdapEntry buildSubschema(const std::string &dn) { LdapEntry e; e.dn = dn; e.addAttribute("objectClass", std::vector<std::string>{"top", "subSchema"}); e.addAttribute("cn", "Aggregate"); e.addAttribute("name", "Aggregate"); e.addAttribute("modifyTimeStamp", "20261030000000.0Z"); std::vector<std::string> at, oc; for (auto &a : dsdb::attributes()) { std::string v = std::string("( ") + a.oid + " NAME '" + a.name + "' SYNTAX '" + dsdb::ldapSyntaxOid(a.syntax) + "'"; if (a.flags & dsdb::A_SINGLE) v += " SINGLE-VALUE"; if (a.flags & (dsdb::A_SYSTEM | dsdb::A_CONSTRUCTED)) v += " NO-USER-MODIFICATION"; at.push_back(v + " )"); } for (auto &c : dsdb::classes()) { std::string v = std::string("( ") + c.oid + " NAME '" + c.name + "'"; if (c.superior && *c.superior && std::string(c.superior) != c.name) v += std::string(" SUP ") + c.superior; if (c.category == 1) v += " STRUCTURAL"; else if (c.category == 2) v += " ABSTRACT"; else if (c.category == 3) v += " AUXILIARY"; std::vector<std::string> must; std::string m = c.must ? c.must : ""; size_t st = 0; while (st < m.size()) { size_t comma = m.find(',', st); std::string one = m.substr(st, comma == std::string::npos ? std::string::npos : comma - st); if (!one.empty()) must.push_back(one); if (comma == std::string::npos) break; st = comma + 1; } if (must.size() == 1) v += " MUST " + must[0]; else if (must.size() > 1) { v += " MUST ( "; for (size_t i = 0; i < must.size(); ++i) v += (i ? " $ " : "") + must[i]; v += " )"; } oc.push_back(v + " )"); } e.addAttribute("attributeTypes", at); e.addAttribute("objectClasses", oc); return e; } } std::vector<uint8_t> ActiveDirectory::handleSearchRequest(const uint8_t *content, size_t len, int32_t msgId, LdapSession &session, const std::vector<LdapControl> &controls) { Loading Loading @@ -1849,6 +1898,32 @@ std::vector<uint8_t> ActiveDirectory::handleSearchRequest(const uint8_t *content if (!dsdb::Dn::parse(baseObject, base)) return buildSearchResultDone(msgId, LDAP_INVALID_DN_SYNTAX, "baseObject"); /* the subschema subentry the rootDSE points to */ { std::lock_guard<std::mutex> lock(_Lock); for (auto &d : _Domains) { dsdb::Dn agg = d.meta.baseDn.child("CN", "Configuration").child("CN", "Schema").child("CN", "Aggregate"); if (!(base == agg)) continue; if (scopeVal == LDAP_SCOPE_BASE) { LdapEntry full = buildSubschema(agg.str()), le; le.dn = full.dn; bool all = requested.empty(); for (auto &r : requested) if (r == "*" || r == "+") all = true; for (auto &a : full.attributes) { bool want = all; for (auto &r : requested) if (dsdb::iequals(r, a.type)) want = true; if (want) le.attributes.push_back(a); } auto e = buildSearchResultEntry(msgId, le); out.insert(out.end(), e.begin(), e.end()); } auto done = buildSearchResultDone(msgId, LDAP_SUCCESS); out.insert(out.end(), done.begin(), done.end()); return out; } } std::lock_guard<std::mutex> lock(_Lock); bool found = false; LdapResultCode rc = LDAP_SUCCESS; Loading plugin/krb5/krb5.cpp +14 −0 Changes for plugin/krb5/krb5.cpp: 14 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -3735,6 +3735,20 @@ std::vector<uint8_t> Krb5KDC::handleStandardTgsReq(const uint8_t *data, size_t l } /* Verify authenticator principal matches TGT */ /* the TGT's PAC must carry our krbtgt signatures (server + KDC); a * TGT from this realm without a valid PAC was not issued by us */ if (!isCrossRealmTgt && !tgt_enc.authData.empty()) { std::vector<uint8_t> pac; int tgsEtype = tgtDecryptKey.size() == 32 ? 18 : 17; if (dsdb::authDataToPac(tgt_enc.authData, pac) && !(dsdb::verifyPacServerSignature(pac, tgtDecryptKey, tgsEtype) && dsdb::verifyPacKdcSignature(pac, tgtDecryptKey, tgsEtype))) { std::cerr << "[KDC] TGS-REQ: PAC signature check failed" << std::endl; return buildStandardError(KRB_AP_ERR_MODIFIED, "PAC signature invalid", req.sname.realm, req.sname.name, req.sname.instance); } } if (auth.cname.name != tgt_enc.cname.name || toUpperRealm(auth.cname.realm) != toUpperRealm(tgt_enc.cname.realm)) { return buildStandardError(KRB_AP_ERR_BAD_INTEGRITY, Loading plugin/krb5/krb5.h +1 −0 Changes for plugin/krb5/krb5.h: 1 added line, 0 removed lines. Original line number Diff line number Diff line Loading @@ -98,6 +98,7 @@ namespace fenrirds { KRB_AP_ERR_TKT_NYV = 33, KRB_AP_ERR_REPEAT = 34, KRB_AP_ERR_SKEW = 37, KRB_AP_ERR_MODIFIED = 41, KRB_ERR_GENERIC = 60 }; Loading plugin/smb/smb.cpp +7 −0 Changes for plugin/smb/smb.cpp: 7 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -171,6 +171,7 @@ void RpcPipe::handlePdu(const std::vector<uint8_t> &pdu) { << " iface=" << _name << std::endl; auto known = [this](const rpc::SyntaxId &a) { return rpc::isLsarpc(a.uuid) || rpc::isSamr(a.uuid) || rpc::isNetlogon(a.uuid) || rpc::isSrvsvc(a.uuid) || rpc::isWkssvc(a.uuid) || (_tcp && (rpc::isDrsuapi(a.uuid) || rpc::isEpm(a.uuid))); }; std::string secAddr = _tcp ? std::to_string(_localPort) : "\\PIPE\\" + _name; Loading Loading @@ -340,6 +341,12 @@ std::vector<uint8_t> RpcPipe::dispatch(const rpc::RequestPdu &req, bool schannel iface = "netlogon"; res = rpc::netlogonDispatch(req.opnum, req.stub, _sessionKey, schannel ? _netsec.computer() : std::string()); } else if (rpc::isSrvsvc(_boundAbstract.uuid)) { iface = "srvsvc"; res = rpc::srvsvcDispatch(req.opnum, req.stub); } else if (rpc::isWkssvc(_boundAbstract.uuid)) { iface = "wkssvc"; res = rpc::wkssvcDispatch(req.opnum, req.stub); } else if (_tcp && rpc::isEpm(_boundAbstract.uuid)) { iface = "epm"; res = rpc::epmDispatch(req.opnum, req.stub, _localIp, _rpcPort); Loading src/CMakeLists.txt +1 −0 Changes for src/CMakeLists.txt: 1 added line, 0 removed lines. Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ list(APPEND fenrirdsSrcs rpc/netsec.cpp rpc/epm.cpp rpc/drsuapi.cpp rpc/srvsvc.cpp smb/smb2.cpp ) Loading Loading
plugin/ad/ad.cpp +75 −0 Changes for plugin/ad/ad.cpp: 75 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -1722,6 +1722,55 @@ std::vector<uint8_t> ActiveDirectory::handleUnbindRequest(int32_t, LdapSession & /****************************************************************************** * Search *****************************************************************************/ namespace { /* the subschema subentry (RFC 4512 4.2) generated from the schema * tables: attributeTypes and objectClasses in RFC 4512 notation */ LdapEntry buildSubschema(const std::string &dn) { LdapEntry e; e.dn = dn; e.addAttribute("objectClass", std::vector<std::string>{"top", "subSchema"}); e.addAttribute("cn", "Aggregate"); e.addAttribute("name", "Aggregate"); e.addAttribute("modifyTimeStamp", "20261030000000.0Z"); std::vector<std::string> at, oc; for (auto &a : dsdb::attributes()) { std::string v = std::string("( ") + a.oid + " NAME '" + a.name + "' SYNTAX '" + dsdb::ldapSyntaxOid(a.syntax) + "'"; if (a.flags & dsdb::A_SINGLE) v += " SINGLE-VALUE"; if (a.flags & (dsdb::A_SYSTEM | dsdb::A_CONSTRUCTED)) v += " NO-USER-MODIFICATION"; at.push_back(v + " )"); } for (auto &c : dsdb::classes()) { std::string v = std::string("( ") + c.oid + " NAME '" + c.name + "'"; if (c.superior && *c.superior && std::string(c.superior) != c.name) v += std::string(" SUP ") + c.superior; if (c.category == 1) v += " STRUCTURAL"; else if (c.category == 2) v += " ABSTRACT"; else if (c.category == 3) v += " AUXILIARY"; std::vector<std::string> must; std::string m = c.must ? c.must : ""; size_t st = 0; while (st < m.size()) { size_t comma = m.find(',', st); std::string one = m.substr(st, comma == std::string::npos ? std::string::npos : comma - st); if (!one.empty()) must.push_back(one); if (comma == std::string::npos) break; st = comma + 1; } if (must.size() == 1) v += " MUST " + must[0]; else if (must.size() > 1) { v += " MUST ( "; for (size_t i = 0; i < must.size(); ++i) v += (i ? " $ " : "") + must[i]; v += " )"; } oc.push_back(v + " )"); } e.addAttribute("attributeTypes", at); e.addAttribute("objectClasses", oc); return e; } } std::vector<uint8_t> ActiveDirectory::handleSearchRequest(const uint8_t *content, size_t len, int32_t msgId, LdapSession &session, const std::vector<LdapControl> &controls) { Loading Loading @@ -1849,6 +1898,32 @@ std::vector<uint8_t> ActiveDirectory::handleSearchRequest(const uint8_t *content if (!dsdb::Dn::parse(baseObject, base)) return buildSearchResultDone(msgId, LDAP_INVALID_DN_SYNTAX, "baseObject"); /* the subschema subentry the rootDSE points to */ { std::lock_guard<std::mutex> lock(_Lock); for (auto &d : _Domains) { dsdb::Dn agg = d.meta.baseDn.child("CN", "Configuration").child("CN", "Schema").child("CN", "Aggregate"); if (!(base == agg)) continue; if (scopeVal == LDAP_SCOPE_BASE) { LdapEntry full = buildSubschema(agg.str()), le; le.dn = full.dn; bool all = requested.empty(); for (auto &r : requested) if (r == "*" || r == "+") all = true; for (auto &a : full.attributes) { bool want = all; for (auto &r : requested) if (dsdb::iequals(r, a.type)) want = true; if (want) le.attributes.push_back(a); } auto e = buildSearchResultEntry(msgId, le); out.insert(out.end(), e.begin(), e.end()); } auto done = buildSearchResultDone(msgId, LDAP_SUCCESS); out.insert(out.end(), done.begin(), done.end()); return out; } } std::lock_guard<std::mutex> lock(_Lock); bool found = false; LdapResultCode rc = LDAP_SUCCESS; Loading
plugin/krb5/krb5.cpp +14 −0 Changes for plugin/krb5/krb5.cpp: 14 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -3735,6 +3735,20 @@ std::vector<uint8_t> Krb5KDC::handleStandardTgsReq(const uint8_t *data, size_t l } /* Verify authenticator principal matches TGT */ /* the TGT's PAC must carry our krbtgt signatures (server + KDC); a * TGT from this realm without a valid PAC was not issued by us */ if (!isCrossRealmTgt && !tgt_enc.authData.empty()) { std::vector<uint8_t> pac; int tgsEtype = tgtDecryptKey.size() == 32 ? 18 : 17; if (dsdb::authDataToPac(tgt_enc.authData, pac) && !(dsdb::verifyPacServerSignature(pac, tgtDecryptKey, tgsEtype) && dsdb::verifyPacKdcSignature(pac, tgtDecryptKey, tgsEtype))) { std::cerr << "[KDC] TGS-REQ: PAC signature check failed" << std::endl; return buildStandardError(KRB_AP_ERR_MODIFIED, "PAC signature invalid", req.sname.realm, req.sname.name, req.sname.instance); } } if (auth.cname.name != tgt_enc.cname.name || toUpperRealm(auth.cname.realm) != toUpperRealm(tgt_enc.cname.realm)) { return buildStandardError(KRB_AP_ERR_BAD_INTEGRITY, Loading
plugin/krb5/krb5.h +1 −0 Changes for plugin/krb5/krb5.h: 1 added line, 0 removed lines. Original line number Diff line number Diff line Loading @@ -98,6 +98,7 @@ namespace fenrirds { KRB_AP_ERR_TKT_NYV = 33, KRB_AP_ERR_REPEAT = 34, KRB_AP_ERR_SKEW = 37, KRB_AP_ERR_MODIFIED = 41, KRB_ERR_GENERIC = 60 }; Loading
plugin/smb/smb.cpp +7 −0 Changes for plugin/smb/smb.cpp: 7 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -171,6 +171,7 @@ void RpcPipe::handlePdu(const std::vector<uint8_t> &pdu) { << " iface=" << _name << std::endl; auto known = [this](const rpc::SyntaxId &a) { return rpc::isLsarpc(a.uuid) || rpc::isSamr(a.uuid) || rpc::isNetlogon(a.uuid) || rpc::isSrvsvc(a.uuid) || rpc::isWkssvc(a.uuid) || (_tcp && (rpc::isDrsuapi(a.uuid) || rpc::isEpm(a.uuid))); }; std::string secAddr = _tcp ? std::to_string(_localPort) : "\\PIPE\\" + _name; Loading Loading @@ -340,6 +341,12 @@ std::vector<uint8_t> RpcPipe::dispatch(const rpc::RequestPdu &req, bool schannel iface = "netlogon"; res = rpc::netlogonDispatch(req.opnum, req.stub, _sessionKey, schannel ? _netsec.computer() : std::string()); } else if (rpc::isSrvsvc(_boundAbstract.uuid)) { iface = "srvsvc"; res = rpc::srvsvcDispatch(req.opnum, req.stub); } else if (rpc::isWkssvc(_boundAbstract.uuid)) { iface = "wkssvc"; res = rpc::wkssvcDispatch(req.opnum, req.stub); } else if (_tcp && rpc::isEpm(_boundAbstract.uuid)) { iface = "epm"; res = rpc::epmDispatch(req.opnum, req.stub, _localIp, _rpcPort); Loading
src/CMakeLists.txt +1 −0 Changes for src/CMakeLists.txt: 1 added line, 0 removed lines. Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ list(APPEND fenrirdsSrcs rpc/netsec.cpp rpc/epm.cpp rpc/drsuapi.cpp rpc/srvsvc.cpp smb/smb2.cpp ) Loading