Commit 71b2f376 authored by jan.koester's avatar jan.koester
Browse files

protokoll fix

parent 9393f3d7
Loading
Loading
Loading
Loading
Loading
+6 −0
Changes for plugin/smb/smb.cpp: 6 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -194,6 +194,12 @@ std::vector<uint8_t> SmbServer::handleMessage(Conn &c, const std::vector<uint8_t
        return pdu;
    };

    /* verify the signature of a signed request once the session is keyed */
    if (c.haveKeys && (req.flags & smb::SMB2_FLAGS_SIGNED)) {
        if (!smb::verifySignature(c.dialect, c.keys.signing, msg))
            return errorResponse(req, smb::STATUS_ACCESS_DENIED);
    }

    switch (req.command) {
    case smb::SMB2_NEGOTIATE: {
        smb::NegotiateRequest nr;
+64 −12
Changes for src/rpc/samr.cpp: 64 added lines, 12 removed lines.
Original line number Diff line number Diff line
@@ -85,6 +85,36 @@ namespace {
        return in.unistrBuffer();
    }

    /* SAMR acct_flags (ACB_*) <-> LDAP userAccountControl */
    uint32_t acbToUac(uint32_t acb) {
        uint32_t u = 0;
        if (acb & 0x0001) u |= 0x0002;      /* DISABLED */
        if (acb & 0x0002) u |= 0x0008;      /* HOMDIRREQ */
        if (acb & 0x0004) u |= 0x0020;      /* PWNOTREQ */
        if (acb & 0x0010) u |= 0x0200;      /* NORMAL */
        if (acb & 0x0040) u |= 0x0800;      /* DOMTRUST */
        if (acb & 0x0080) u |= 0x1000;      /* WSTRUST */
        if (acb & 0x0100) u |= 0x2000;      /* SVRTRUST */
        if (acb & 0x0200) u |= 0x10000;     /* PWNOEXP */
        if (acb & 0x0400) u |= 0x0010;      /* AUTOLOCK -> LOCKOUT */
        if (!u) u = 0x0200;                 /* default NORMAL */
        return u;
    }
    uint32_t uacToAcb(uint32_t u) {
        uint32_t acb = 0;
        if (u & 0x0002) acb |= 0x0001;
        if (u & 0x0008) acb |= 0x0002;
        if (u & 0x0020) acb |= 0x0004;
        if (u & 0x0200) acb |= 0x0010;
        if (u & 0x0800) acb |= 0x0040;
        if (u & 0x1000) acb |= 0x0080;
        if (u & 0x2000) acb |= 0x0100;
        if (u & 0x10000) acb |= 0x0200;
        if (u & 0x0010) acb |= 0x0400;
        if (!acb) acb |= 0x0010;
        return acb;
    }

    DispatchResult ok(const std::vector<uint8_t> &stub, uint32_t status = ST_OK) {
        DispatchResult r; r.stub = stub; r.status = status; return r;
    }
@@ -193,8 +223,8 @@ DispatchResult samrDispatch(uint16_t opnum, const std::vector<uint8_t> &stub,
            NdrPull in(stub);
            in.handle();                 /* domain handle */
            std::string acct = readName(in);
            uint32_t acctFlags = 0x1000; /* default WORKSTATION_TRUST for CreateUser */
            if (opnum == SAMR_CREATEUSER2) acctFlags = in.u32();
            uint32_t acb = 0x0080;       /* default ACB_WSTRUST for CreateUser */
            if (opnum == SAMR_CREATEUSER2) acb = in.u32();
            in.u32();                    /* desired access */
            Dom d; if (!openDom(d)) return handleOut(PolicyHandle{}, ST_INVALID);
            dsdb::Directory dir(*d.bck, d.meta);
@@ -205,18 +235,20 @@ DispatchResult samrDispatch(uint16_t opnum, const std::vector<uint8_t> &stub,
            }
            std::string shortName = acct;
            if (!shortName.empty() && shortName.back() == '$') shortName.pop_back();
            dsdb::Dn dn = d.meta.baseDn.child("CN", "Computers").child("CN", shortName);
            /* samr acct_flags are ACB_*; convert to LDAP userAccountControl */
            bool computer = (acb & 0x0080) || (acb & 0x0100);   /* ACB_WSTRUST/SVRTRUST */
            uint32_t uac = acbToUac(acb);
            dsdb::Dn dn = d.meta.baseDn.child("CN", computer ? "Computers" : "Users").child("CN", shortName);
            uint32_t rid = dir.allocateRid();
            dsdb::AttrMap a;
            bool computer = (acctFlags & 0x1000) || (acctFlags & 0x2000);  /* WS or SRV trust */
            if (computer)
                a["objectClass"] = {"top", "person", "organizationalPerson", "user", "computer"};
            else
                a["objectClass"] = {"top", "person", "organizationalPerson", "user"};
            a["sAMAccountName"] = {acct};
            a["objectSid"] = {d.info.sid.withRid(rid).binary()};
            /* new account is disabled until the password is set */
            dsdb::setInt(a, "userAccountControl", int32_t(acctFlags | 0x0002 /*DISABLE*/ | 0x0020 /*PASSWD_NOTREQD*/));
            /* new account is disabled + no-pw until the password is set */
            dsdb::setInt(a, "userAccountControl", int32_t(uac | 0x0002 /*DISABLE*/ | 0x0020 /*PASSWD_NOTREQD*/));
            dsdb::setInt(a, "primaryGroupID", computer ? 515 : 513);
            uuid::uuid g = dir.create(dn, a);
            NdrPush p;
@@ -246,9 +278,9 @@ DispatchResult samrDispatch(uint16_t opnum, const std::vector<uint8_t> &stub,
            in.u16();   /* the switch echoes the level */
            std::unique_ptr<dsdb::Secrets> newSec;
            if (level == 16) {
                /* SAMR_USER_CONTROL_INFORMATION: u32 acct_flags */
                uint32_t uac = in.u32();
                dsdb::setInt(attrs, "userAccountControl", int32_t(uac));
                /* SAMR_USER_CONTROL_INFORMATION: u32 acct_flags (ACB_*) */
                uint32_t acb = in.u32();
                dsdb::setInt(attrs, "userAccountControl", int32_t(acbToUac(acb)));
            } else if ((level == 25 || level == 26 || level == 24 || level == 23) && sessionKey.size() >= 16) {
                /* the buffer is a 516-byte SAMPR_USER_PASSWORD encrypted with
                 * RC4(session key) (levels 24/25) ... level 25/26 include extra
@@ -294,9 +326,29 @@ DispatchResult samrDispatch(uint16_t opnum, const std::vector<uint8_t> &stub,
            return ok(p.buf);
        }
        case SAMR_QUERYUSERINFO: {
            /* minimal: return a null info pointer + success is not valid;
             * respond with level unsupported for now */
            NdrPush p; p.ref(false); p.u32(0xC0000003 /* INVALID_INFO_CLASS-ish */);
            NdrPull in(stub);
            PolicyHandle h = in.handle();
            uint16_t level = in.u16();
            HObj obj;
            if (!lookupHandle(h, obj) || obj.kind != H_USER) {
                NdrPush p; p.ref(false); p.u32(ST_ACCESS); return ok(p.buf);
            }
            Dom d; if (!openDom(d)) { NdrPush p; p.ref(false); p.u32(ST_INVALID); return ok(p.buf); }
            dsdb::Directory dir(*d.bck, d.meta);
            auto e = dir.byGuid(obj.guid);
            if (!e) { NdrPush p; p.ref(false); p.u32(ST_NO_SUCH_USER); return ok(p.buf); }
            if (level == 16) {
                uint32_t uac = uint32_t(dsdb::intValue(e->attrs, "userAccountControl", 0x200));
                NdrPush p;
                p.ref(true);        /* info pointer */
                p.u16(16);          /* union discriminant */
                p.align(4);
                p.u32(uacToAcb(uac));   /* SAMR_USER_CONTROL_INFORMATION.acct_flags */
                p.u32(ST_OK);
                return ok(p.buf);
            }
            /* other levels not yet supported */
            NdrPush p; p.ref(false); p.u32(0xC0000003 /* INVALID_INFO_CLASS */);
            return ok(p.buf);
        }
        default:
+13 −2
Changes for tests/proto/test_samr.cpp: 13 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -69,7 +69,7 @@ TEST(samr_join_flow) {
    cu.u16(uint16_t(crypto::utf16le("WS1$").size()));
    cu.ref(true); cu.align(4); cu.u32(4); cu.u32(0); cu.u32(4);
    { auto u = crypto::utf16le("WS1$"); cu.bytes(u.data(), u.size()); }
    cu.u32(0x1000);     /* acct_flags WORKSTATION_TRUST */
    cu.u32(0x0080);     /* ACB_WSTRUST */
    cu.u32(0x02000000); /* desired access */
    auto cur = samrDispatch(50, cu.buf);
    NdrPull cp(cur.stub);
@@ -100,7 +100,18 @@ TEST(samr_join_flow) {
    NdrPull sup(sur.stub);
    CHECK_EQ(sup.u32(), uint32_t(0));

    samrDispatch(1, ({ NdrPush c; c.handle(userH); c.buf; }));
    /* QueryUserInfo level 16 -> acct_flags back in ACB form (ACB_WSTRUST set) */
    NdrPush qi; qi.handle(userH); qi.u16(16);
    auto qir = samrDispatch(36, qi.buf);
    NdrPull qp(qir.stub);
    CHECK(qp.ref() != 0);
    CHECK_EQ(qp.u16(), uint16_t(16));
    qp.align(4);
    uint32_t acb = qp.u32();
    CHECK(acb & 0x0080);       /* ACB_WSTRUST */
    CHECK_EQ(qp.u32(), uint32_t(0));

    { NdrPush cl; cl.handle(userH); samrDispatch(1, cl.buf); }
    unlink(path.c_str()); unlink((path + ".lock").c_str()); unlink((path + ".dom").c_str());
}