Commit 9067bb3b authored by jan.koester's avatar jan.koester
Browse files

test

parent a4a16ef8
Loading
Loading
Loading
Loading
Loading
+8 −4
Changes for data/dirviews.js: 8 added lines, 4 removed lines.
Original line number Diff line number Diff line
@@ -95,7 +95,11 @@ function loadDnsZone(zone) {
        h += '<p><a href="#" onclick="g_dnsZone=null; loadDns(); return false;">&larr; alle Zonen</a></p>';
        h += '<table class="admin-table userlist"><tr><th>Name</th><th>Typ</th><th>TTL</th><th>Daten</th><th>Actions</th></tr>';
        var rs = data.records || [];
        rs.sort(function(a, b) { return a.name === b.name ? (a.type < b.type ? -1 : 1) : (a.name === '@' ? -1 : b.name === '@' ? 1 : (a.name < b.name ? -1 : 1)); });
        var rank = function(r) { return r.type === 'SOA' ? '0' : r.type === 'NS' ? '1' : '2' + r.type; };
        rs.sort(function(a, b) {
            if (a.name !== b.name) return a.name === '@' ? -1 : b.name === '@' ? 1 : (a.name < b.name ? -1 : 1);
            return rank(a) < rank(b) ? -1 : rank(a) > rank(b) ? 1 : 0;
        });
        window.g_dnsRecords = rs;
        for (var i = 0; i < rs.length; i++) {
            var r = rs[i];
@@ -175,9 +179,9 @@ function loadWinGpos() {
                for (var k = 0; k < g.links.length; k++) {
                    var l = g.links[k];
                    h += '<div>' + escapeHtml(l.targetname) + (l.enforced ? ' <b>[erzwungen]</b>' : '') + (l.disabled ? ' <i>[deaktiviert]</i>' : '');
                    h += ' <a href="#" title="erzwingen umschalten" onclick="winGpoLink(' + i + ',' + k + ',\'enforce\'); return false;">E</a>';
                    h += ' <a href="#" title="aktiv umschalten" onclick="winGpoLink(' + i + ',' + k + ',\'toggle\'); return false;">A</a>';
                    h += ' <a href="#" title="Verknüpfung entfernen" onclick="winGpoLink(' + i + ',' + k + ',\'unlink\'); return false;">&times;</a></div>';
                    h += '<br><small><a href="#" onclick="winGpoLink(' + i + ',' + k + ',\'enforce\'); return false;">' + (l.enforced ? 'nicht erzwingen' : 'erzwingen') + '</a>';
                    h += ' &middot; <a href="#" onclick="winGpoLink(' + i + ',' + k + ',\'toggle\'); return false;">' + (l.disabled ? 'aktivieren' : 'deaktivieren') + '</a>';
                    h += ' &middot; <a href="#" onclick="winGpoLink(' + i + ',' + k + ',\'unlink\'); return false;">entfernen</a></small></div>';
                }
                if (!g.links.length) h += '<em>-</em>';
                h += '</td><td><ul>';
+43 −10
Changes for plugin/ad/ad.cpp: 43 added lines, 10 removed lines.
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *******************************************************************************/

#include <ctime>
#include <iostream>
#include <cstring>
#include <map>
@@ -1245,7 +1246,8 @@ void ActiveDirectory::RequestEvent(netplus::con &curcon, const int, ULONG_PTR) {
            }
            if (!responses.empty()) {
                fenrirds::crypto::Bytes resp(responses.begin(), responses.end());
                auto wrapped = gss::wrap(session->gssKey, session->gssEtype, true, session->sendSeq++, resp);
                auto wrapped = gss::wrap(session->gssKey, session->gssEtype, true, session->sendSeq++, resp,
                                         session->ssf == 2);
                uint32_t wl = uint32_t(wrapped.size());
                curcon.SendData.push_back(char(wl >> 24));
                curcon.SendData.push_back(char(wl >> 16));
@@ -1525,18 +1527,31 @@ std::vector<uint8_t> ActiveDirectory::handleBindRequest(const uint8_t *content,
            session.gssEtype = res.sessionEtype;
            session.gssClient = res.clientPrincipal;
            session.gssState = LdapSession::GssSentApRep;
            session.sendSeq = res.acceptorSeq;
            session.recvSeq = res.initiatorSeq;

            std::vector<uint8_t> krb5reply;
            if (!res.apRep.empty()) {
                krb5reply = {0x02, 0x00};   /* GSS AP-REP token id */
                krb5reply.insert(krb5reply.end(), res.apRep.begin(), res.apRep.end());
                /* RFC 1964 framing: 0x60, krb5 OID, tok id 02 00, AP-REP */
                krb5reply = gss::wrapInitialToken(res.apRep, 0x0200);
            }
            std::vector<uint8_t> creds;
            if (spnego) {
                std::vector<uint8_t> krb5oid(gss::KRB5_OID, gss::KRB5_OID + 11);
                std::vector<uint8_t> mic = gss::getMic(session.gssKey, session.gssEtype,
                                                       true, 0, session.gssMechTypes);
                                                       true, session.sendSeq++, session.gssMechTypes);
                creds = gss::buildSpnegoResp(gss::ACCEPT_COMPLETED, &krb5oid, krb5reply, mic);
                /* GSS-SPNEGO has no RFC 4752 layer negotiation: the bind is
                 * done, and the client signs or seals the following PDUs as
                 * it asked for in its authenticator (MS-ADTS 5.1.1.1.2) */
                session.ssf = (res.gssFlags & 0x10) ? 2 : (res.gssFlags & 0x20) ? 1 : 0;
                session.authenticated = true;
                session.bindDN = session.gssClient;
                session.gssState = LdapSession::GssNone;
                std::cerr << "[LDAP] bind GSS-SPNEGO COMPLETE client='" << session.gssClient
                          << "' flags=0x" << std::hex << res.gssFlags << std::dec
                          << " ssf=" << session.ssf << " -> SUCCESS" << std::endl;
                return bindResp(LDAP_SUCCESS, &creds);
            } else {
                creds = krb5reply;
            }
@@ -1547,7 +1562,7 @@ std::vector<uint8_t> ActiveDirectory::handleBindRequest(const uint8_t *content,
            /* offer the SASL security layer: none|integrity|confidentiality,
             * with a max receive buffer. Wrapped (sign) with the context key. */
            uint32_t maxBuf = 0x000FFFFF;
            std::vector<uint8_t> sec = {0x03, uint8_t(maxBuf >> 16), uint8_t(maxBuf >> 8), uint8_t(maxBuf)};
            std::vector<uint8_t> sec = {0x07, uint8_t(maxBuf >> 16), uint8_t(maxBuf >> 8), uint8_t(maxBuf)};
            auto tok = gss::wrap(session.gssKey, session.gssEtype, true, session.sendSeq++, sec);
            session.gssState = LdapSession::GssSentSecLayer;
            return bindResp(SASL_BIND_IN_PROGRESS, &tok);
@@ -1559,8 +1574,7 @@ std::vector<uint8_t> ActiveDirectory::handleBindRequest(const uint8_t *content,
            return bindResp(LDAP_INVALID_CREDENTIALS, nullptr);
        uint8_t layer = plain[0];
        session.ssf = (layer & 0x04) ? 2 : (layer & 0x02) ? 1 : 0;
        session.recvSeq = 1;   /* the sec-layer tokens consumed seq 0 each way */
        session.sendSeq = 1;
        session.recvSeq++;     /* the sec-layer tokens consumed one each way */
        session.authenticated = true;
        session.bindDN = session.gssClient;
        session.gssState = LdapSession::GssNone;
@@ -2052,9 +2066,28 @@ LdapEntry ActiveDirectory::buildRootDSE() {
        e.addAttribute("configurationNamingContext", config);
        e.addAttribute("schemaNamingContext", "CN=Schema," + config);
        e.addAttribute("subschemaSubentry", "CN=Aggregate,CN=Schema," + config);
        e.addAttribute("dnsHostName", _Domains.front().meta.dnsName);
        e.addAttribute("ldapServiceName", _Domains.front().meta.dnsName + ":fenrirds$@" + _Domains.front().meta.realm);
        e.addAttribute("serverName", "CN=FENRIRDS,CN=Servers,CN=Default-First-Site-Name,CN=Sites," + config);
        /* the DC's own FQDN: clients build the ldap/<host> SPN from it */
        std::string host = _DcHost.empty() ? _Domains.front().meta.dnsName : _DcHost;
        std::string shortHost = dsdb::lower(host.substr(0, host.find('.')));
        std::string server = "CN=" + dsdb::upper(shortHost) + ",CN=Servers,CN=Default-First-Site-Name,CN=Sites," + config;
        e.addAttribute("dnsHostName", host);
        e.addAttribute("ldapServiceName", _Domains.front().meta.dnsName + ":" + shortHost + "$@" +
                                          _Domains.front().meta.realm);
        e.addAttribute("serverName", server);
        e.addAttribute("dsServiceName", "CN=NTDS Settings," + server);
        e.addAttribute("domainFunctionality", "7");
        e.addAttribute("forestFunctionality", "7");
        e.addAttribute("domainControllerFunctionality", "7");
        e.addAttribute("isGlobalCatalogReady", "TRUE");
    }
    {
        /* currentTime (GeneralizedTime): Samba's net ads reads it on connect */
        time_t now = time(nullptr);
        struct tm tmv;
        gmtime_r(&now, &tmv);
        char buf[32];
        strftime(buf, sizeof(buf), "%Y%m%d%H%M%S.0Z", &tmv);
        e.addAttribute("currentTime", std::string(buf));
    }
    return e;
}
+47 −6
Changes for plugin/krb5/krb5.cpp: 47 added lines, 6 removed lines.
Original line number Diff line number Diff line
@@ -1671,6 +1671,38 @@ bool Asn1Der::parseAuthenticator(const uint8_t *data, size_t len,
                if (parseTLV(content, content_len, ioff, itag, icontent, icontent_len))
                    parseGeneralizedTime(icontent, icontent_len, auth.ctime);
                break;
            case 3: /* cksum: Checksum ::= SEQUENCE { cksumtype [0], checksum [1] } */
            {
                size_t coff = 0;
                uint8_t ctag;
                const uint8_t *cseq;
                size_t cseqLen;
                if (!parseTLV(content, content_len, coff, ctag, cseq, cseqLen) || ctag != TAG_SEQUENCE)
                    break;
                int32_t ctype = 0;
                std::vector<uint8_t> cdata;
                size_t poff = 0;
                while (poff < cseqLen) {
                    uint8_t ptag;
                    const uint8_t *pc;
                    size_t pl;
                    if (!parseTLV(cseq, cseqLen, poff, ptag, pc, pl)) break;
                    size_t xoff = 0;
                    uint8_t xtag;
                    const uint8_t *xc;
                    size_t xl;
                    if (!parseTLV(pc, pl, xoff, xtag, xc, xl)) continue;
                    if ((ptag & 0x1F) == 0) parseInteger(xc, xl, ctype);
                    else if ((ptag & 0x1F) == 1) cdata.assign(xc, xc + xl);
                }
                /* GSS checksum: Lgth(4) = 16, Bnd(16), Flags(4, little endian) */
                if (ctype == 0x8003 && cdata.size() >= 24) {
                    auth.gss_flags = uint32_t(cdata[20]) | uint32_t(cdata[21]) << 8 |
                                     uint32_t(cdata[22]) << 16 | uint32_t(cdata[23]) << 24;
                    auth.has_gss_cksum = true;
                }
                break;
            }
            case 6: /* subkey (EncryptionKey) — the GSS context key */
                if (parseEncryptionKey(content, content_len, auth.subkey))
                    auth.has_subkey = true;
@@ -3836,6 +3868,9 @@ bool Krb5KDC::gssAccept(const std::vector<uint8_t> &apReqData, GssAcceptResult &
        Krb5Service svc("", "", ap.ticket.sname.realm, svcKey);
        out.apRep = svc.buildApRep(auth, et.session_key);
    }
    out.gssFlags = auth.has_gss_cksum ? auth.gss_flags : 0;
    out.initiatorSeq = auth.seq_number;
    out.acceptorSeq = auth.seq_number;   /* what buildApRep announces */
    return true;
}

@@ -4370,12 +4405,18 @@ bool Krb5Service::verifyApReq(const std::vector<uint8_t> &apReqData,

std::vector<uint8_t> Krb5Service::buildApRep(const Krb5Authenticator &auth,
                                               const Krb5SessionKey &sessionKey) {
    /* Build encrypted part: timestamp + cusec + seq-number */
    auto encTimestamp = Asn1Der::encodePaEncTimestamp(auth.ctime, auth.cusec);

    /* Add seq-number */
    std::vector<uint8_t> repData = encTimestamp;
    /* For simplicity, reuse PA-ENC-TS-ENC format with the seq number appended */
    /* EncAPRepPart ::= [APPLICATION 27] SEQUENCE {
     *   ctime [0] KerberosTime, cusec [1] Microseconds,
     *   subkey [2] EncryptionKey OPTIONAL, seq-number [3] UInt32 OPTIONAL }
     * ctime/cusec echo the authenticator (that proves the service to the
     * client); seq-number is the acceptor's initial GSS sequence number, we
     * use the initiator's (as Windows does for DCE style, and harmless else). */
    std::vector<uint8_t> seq;
    Asn1Der::encodeContextTag(seq, 0, Asn1Der::encodeGeneralizedTime(auth.ctime));
    Asn1Der::encodeContextTag(seq, 1, Asn1Der::encodeUInteger(auth.cusec));
    Asn1Der::encodeContextTag(seq, 3, Asn1Der::encodeUInteger(auth.seq_number));
    std::vector<uint8_t> repData;
    Asn1Der::encodeTLV(repData, 0x7B /* [APPLICATION 27] */, Asn1Der::encodeSequence(seq));

    auto enc_rep = Krb5Crypto::encrypt(sessionKey.keydata, repData,
                                        KRB5_KU_AP_REP_ENC_PART);
+4 −0
Changes for plugin/krb5/krb5.h: 4 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -474,6 +474,10 @@ namespace fenrirds {
        uint32_t         seq_number;          /* sequence number       */
        Krb5SessionKey   subkey;              /* [6] subkey (GSS context key) */
        bool             has_subkey = false;
        /* [3] cksum of type 0x8003 (RFC 4121 4.1.1): the GSS context flags
         * (DELEG 1, MUTUAL 2, REPLAY 4, SEQUENCE 8, CONF 0x10, INTEG 0x20) */
        uint32_t         gss_flags = 0;
        bool             has_gss_cksum = false;

        Krb5Authenticator();

+4 −2
Changes for plugin/smb/smb.cpp: 4 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -720,11 +720,13 @@ SmbServer::Reply SmbServer::sessionSetup(Conn &c, const smb::Smb2Header &req,
    setPrincipal(res.clientPrincipal);
    s.sessionKey = res.sessionKey;
    std::vector<uint8_t> krb5reply;
    if (!res.apRep.empty()) { krb5reply = {0x02,0x00}; krb5reply.insert(krb5reply.end(), res.apRep.begin(), res.apRep.end()); }
    /* the reply mech token: RFC 1964 framing (0x60, krb5 OID, tok id 02 00) */
    if (!res.apRep.empty())
        krb5reply = gss::wrapInitialToken(res.apRep, 0x0200);
    std::vector<uint8_t> outTok;
    if (spnego) {
        std::vector<uint8_t> oid(gss::KRB5_OID, gss::KRB5_OID+11);
        auto m = gss::getMic(res.sessionKey, res.sessionEtype, true, 0, mechTypes);
        auto m = gss::getMic(res.sessionKey, res.sessionEtype, true, res.acceptorSeq, mechTypes);
        outTok = gss::buildSpnegoResp(gss::ACCEPT_COMPLETED, &oid, krb5reply, m);
    } else {
        outTok = krb5reply;
Loading