Commit e833dd61 authored by jan.koester's avatar jan.koester
Browse files

test

parent 9b6ffbb8
Loading
Loading
Loading
Loading
+2 −0
Changes for src/config.cpp: 2 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -187,6 +187,8 @@ void readDomain(const Scope &s, Config &cfg, bool multi, bool &idBaseSet) {
    if (cfg.servers.empty()) cfg.servers.push_back(cfg.domain);
    readInt(s, "port", cfg.port, 1, 65535);
    readInt(s, "netlogon_port", cfg.netlogonPort, 1, 65535);
    readString(s, "netbios_domain", cfg.netbiosDomain);
    for (char &c : cfg.netbiosDomain) c = (char)toupper((unsigned char)c);

    std::string tls = "ldaps";
    readString(s, "tls", tls);
+1 −0
Changes for src/config.h: 1 added line, 0 removed lines.
Original line number Diff line number Diff line
@@ -93,6 +93,7 @@ struct Config {
    int pageSize = 500;

    int netlogonPort = 0;               /* NETLOGON RPC port; 0 = ask the endpoint mapper */
    std::string netbiosDomain;          /* the short domain name (EXAMPLE); default: from the directory */

    int ldapPort() const { return port ? port : tls == ldap::Tls::Ldaps ? 636 : 389; }
};
+34 −7
Changes for src/daemon.cpp: 34 added lines, 7 removed lines.
Original line number Diff line number Diff line
@@ -86,6 +86,8 @@ struct Domain {
    /* offline: none of its domain controllers is asked before this */
    std::atomic<long long> retryAt{0};
    std::atomic<bool> offline{false};
    /* the short (NetBIOS) domain name the directory gave, "" until asked */
    std::string netbios;

    explicit Domain(const Config &c) : cfg(c), src(c), dir(c, src) {}
};
@@ -130,6 +132,36 @@ std::string acceptKrb5(Server &s, const std::string &arg) {
    }
}

/* the short domain name (EXAMPLE): netbios_domain, else the nETBIOSName
 * of the domain's crossRef in the configuration partition -- it need not
 * be the DNS name's first label (intranet.example.com may be SAMBA) --
 * and, while the directory can't be asked, that first label */
std::string netbiosName(Domain &d) {
    if (!d.cfg.netbiosDomain.empty()) return d.cfg.netbiosDomain;
    std::lock_guard<std::mutex> l(d.lock);
    if (d.netbios.empty()) {
        try {
            std::string config;
            d.src.search("", ldap::Base, "(objectClass=*)", {"configurationNamingContext"}, [&](const ldap::Entry &e) {
                if (const std::string *c = e.first("configurationnamingcontext")) config = *c;
            }, 0);
            if (config.empty()) config = "CN=Configuration," + d.cfg.base;
            d.src.search("CN=Partitions," + config, ldap::OneLevel,
                         "(&(objectClass=crossRef)(nCName=" + d.cfg.base + "))", {"nETBIOSName"},
                         [&](const ldap::Entry &e) {
                if (const std::string *n = e.first("netbiosname")) d.netbios = *n;
            }, 0);
            for (char &c : d.netbios) c = (char)toupper((unsigned char)c);
        } catch (const std::exception &e) {
            std::cerr << "adconnectd: " << d.cfg.domain << ": NetBIOS name: " << e.what() << std::endl;
        }
    }
    if (!d.netbios.empty()) return d.netbios;
    std::string nb = d.cfg.domain.substr(0, d.cfg.domain.find('.'));
    for (char &c : nb) c = (char)toupper((unsigned char)c);
    return nb;
}

/* NTLM: a domain user's NTLM response, checked by its domain controller over
 * NETLOGON (for sharedd/ksmbd SMB logins that don't use Kerberos). The request
 * arg is tab-separated: domain, account, workstation, base64(server challenge),
@@ -154,11 +186,6 @@ std::string acceptNtlm(Server &s, const std::string &arg) {
    in.serverChallenge = f[3]; in.ntResponse = f[4]; in.lmResponse = f[5];
    if (in.serverChallenge.size() != 8) return formatError("bad NTLM request");

    auto netbios = [](const std::string &dom) {
        std::string nb = dom.substr(0, dom.find('.'));
        for (char &c : nb) c = (char)toupper((unsigned char)c);
        return nb;
    };
    auto upper = [](std::string v) {
        for (char &c : v) c = (char)toupper((unsigned char)c);
        return v;
@@ -172,7 +199,7 @@ std::string acceptNtlm(Server &s, const std::string &arg) {
    if (want.empty() && at != std::string::npos) want = upper(in.account.substr(at + 1));
    Domain *d = nullptr;
    for (auto &dp : s.domains)
        if (netbios(dp->cfg.domain) == want || upper(dp->cfg.domain) == want || upper(dp->cfg.krbRealm) == want) {
        if (netbiosName(*dp) == want || upper(dp->cfg.domain) == want || upper(dp->cfg.krbRealm) == want) {
            d = dp.get();
            break;
        }
@@ -198,7 +225,7 @@ std::string acceptNtlm(Server &s, const std::string &arg) {
    nc.computer = d->cfg.krbPrincipal;
    if (!nc.computer.empty() && nc.computer.back() == '$') nc.computer.pop_back();
    nc.machinePassword = d->cfg.bindPassword;
    nc.domainNetbios = netbios(d->cfg.domain);
    nc.domainNetbios = netbiosName(*d);
    try {
        NtlmResult r = samLogonNetwork(nc, in);
        return "N\t" + std::to_string((unsigned long)r.status) + "\t" + base64Encode(r.sessionKey) + "\n" + End;
+15 −3
Changes for src/netlogon.cpp: 15 added lines, 3 removed lines.
Original line number Diff line number Diff line
@@ -194,7 +194,9 @@ void ndrInlineStr(Bytes &s, const std::string &w) {
    p32(s, n); p32(s, 0); p32(s, n);
    s += utf16(w); s += (char)0; s += (char)0;
}
void align2(Bytes &b) { if (b.size() % 2) b += (char)0; }
void ndrUniqStr(Bytes &s, uint32_t &ref, const std::string &w) {
    align4(s); /* the referent: after an odd-length string only 2-aligned */
    p32(s, ref); ref += 4;
    ndrInlineStr(s, w);
}
@@ -243,6 +245,7 @@ Bytes buildNetworkStub(const std::string &server, const std::string &computer, c
    ndrUniqStr(s, ref, computer);
    p16(s, 2);               /* logon_level = NetlogonNetworkInformation */
    p16(s, 2);               /* union discriminant */
    align4(s);               /* the union arm, a pointer */
    p32(s, ref); ref += 4;   /* netr_NetworkInfo referent (pointee inline below) */
    /* netr_NetworkInfo fixed part */
    lsaFixed(s, ref, domain);
@@ -260,13 +263,22 @@ Bytes buildNetworkStub(const std::string &server, const std::string &computer, c
    crData(s, nt);
    crData(s, lm);
    /* remaining top-level [in] params */
    align2(s);
    p16(s, 6);               /* validation_level = NetlogonValidationSamInfo4 */
    p16(s, 0);               /* align to 4 */
    align4(s);
    p32(s, 0);               /* flags */
    secVt(s);
    return s;
}

/* a fault PDU's status (after alloc_hint, context id, cancel count) */
std::string faultStatus(const Bytes &r) {
    if ((uint8_t)r[2] != 3 || r.size() < 28) return std::string();
    char b[32];
    snprintf(b, sizeof(b), " (status 0x%08x)", (unsigned)g32((const uint8_t *)r.data() + 24));
    return b;
}

/* ---- DCE/RPC over a libnetplus TCP connection ---- */
struct Rpc {
    std::unique_ptr<netplus::tcp> sock;
@@ -347,7 +359,7 @@ struct Rpc {
        req += stub;
        sendAll(req);
        Bytes r = recvPdu();
        if ((uint8_t)r[2] != 2) throw std::runtime_error("netlogon: request faulted");
        if ((uint8_t)r[2] != 2) throw std::runtime_error("netlogon: request faulted" + faultStatus(r));
        return r.substr(24);
    }
    /* a schannel-sealed request, returns the decrypted response stub */
@@ -365,7 +377,7 @@ struct Rpc {
        req += data; req += sect; req += sig;
        sendAll(req);
        Bytes r = recvPdu();
        if ((uint8_t)r[2] != 2) throw std::runtime_error("netlogon: sealed request faulted");
        if ((uint8_t)r[2] != 2) throw std::runtime_error("netlogon: sealed request faulted" + faultStatus(r));
        uint16_t al = g16((const uint8_t *)r.data() + 10);
        size_t frag = r.size();
        if (al == 0 || frag < 24 + 8 + al) throw std::runtime_error("netlogon: bad sealed response");