Commit 95dc1ac0 authored by jan.koester's avatar jan.koester
Browse files

next

parent 5cf9da48
Loading
Loading
Loading
Loading
Loading
+1 −0
Changes for CMakeLists.txt: 1 added line, 0 removed lines.
Original line number Diff line number Diff line
@@ -89,6 +89,7 @@ install(FILES
    data/wizzard.html
    data/setup.html
    data/serverconfig.js
    data/dirviews.js
    data/login.html
    data/index.html
    data/fenrirds.png
+7 −0
Changes for data/admin.html: 7 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@
    <title>FenrirDirectoryServer Admin</title>
    <link rel="stylesheet" href="/style.css">
    <script src="/serverconfig.js"></script>
    <script src="/dirviews.js"></script>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style>
        .admin-table { border-collapse: separate; border-spacing: 0; width: 100%; margin: 1em 0; border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }
@@ -68,6 +69,8 @@
                <li id="nav-clients"><a href="#" onclick="loadClients(); return false;">Clients</a></li>
                <li id="nav-services" style="display:none"><a href="#" onclick="loadServices(); return false;">Services</a></li>
                <li id="nav-gpos"><a href="#" onclick="loadGpos(); return false;">Policies</a></li>
                <li id="nav-wingpo" style="display:none"><a href="#" onclick="loadWinGpos(); return false;">Windows GPOs</a></li>
                <li id="nav-dns" style="display:none"><a href="#" onclick="loadDns(); return false;">DNS</a></li>
                <li id="nav-sessions"><a href="#" onclick="loadSessions(); return false;">Sessions</a></li>
                <li id="nav-server" style="display:none"><a href="#" onclick="loadServerConfig(); return false;">Server</a></li>
                <li id="nav-cluster" style="display:none"><a href="#" onclick="loadClusterStatus(); return false;">Cluster</a></li>
@@ -1498,6 +1501,10 @@ window.onload = function() {
            document.getElementById('nav-computers').style.display = '';
        if (data.superadmin || gpo[GPO_MANAGE_SERVICES])
            document.getElementById('nav-services').style.display = '';
        if (data.superadmin || gpo[GPO_MANAGE_SERVICES]) {
            document.getElementById('nav-dns').style.display = '';
            document.getElementById('nav-wingpo').style.display = '';
        }
        if (data.superadmin || gpo[GPO_EXPORT_IMPORT])
            document.getElementById('nav-export').style.display = '';

+5 −0
Changes for plugin/ad/ad.cpp: 5 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -39,6 +39,8 @@
#include <netplus/eventapi.h>

#include "ad.h"
#include "grouppolicy.h"
#include "sysvol.h"
#include "crypto/gss.h"
#include "crypto/ntlm.h"

@@ -1090,6 +1092,9 @@ void ActiveDirectory::loadDomains() {
                d.dir->provision(_AdminPassword);
                if (!_DcHost.empty())
                    d.dir->provisionDc(_DcHost);   /* this DC's own account + SPNs */
                /* SYSVOL layout + the default Windows GPOs and their links */
                sysvol::Store sv(*bck);
                winpolicy::Manager(*d.dir, sv).ensureDefaults();
            } catch (std::exception &ex) {
                std::cerr << "AD: provision '" << e.name << "' failed: " << ex.what() << std::endl;
            }
+160 −1
Changes for plugin/smb/smb.cpp: 160 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -625,7 +625,7 @@ SmbServer::Reply SmbServer::sessionSetup(Conn &c, const smb::Smb2Header &req,
        c.sessions.erase(sid);
        smb::Smb2Header r2 = req;
        r2.sessionId = sid;
        reply.pdu = errorResponse(r2, ST_LOGON_FAILURE);
        reply.pdu = errorResponse(r2, smb::STATUS_LOGON_FAILURE);
        return reply;
    };
    /* principal -> user + DNS domain */
@@ -1621,3 +1621,162 @@ std::vector<uint8_t> SmbServer::queryInfo(Conn &c, const smb::Smb2Header &req, u
    resp.insert(resp.end(), out.begin(), out.end());
    return resp;
}

/*****************************************************************************
 * SET_INFO
 *****************************************************************************/
std::vector<uint8_t> SmbServer::setInfo(Conn &c, Session &s, const smb::Smb2Header &req, uint64_t fid,
                                        const uint8_t *body, size_t blen) {
    (void)s;
    if (blen < 32)
        return errorResponse(req, ST_INVALID_PARAMETER);
    uint8_t type = body[2], cls = body[3];
    uint32_t len = rd32(body + 4);
    uint16_t off = rd16(body + 8);
    if (off < 64 || size_t(off - 64) + len > blen)
        return errorResponse(req, ST_INVALID_PARAMETER);
    const uint8_t *b = body + (off - 64);
    auto it = c.opens.find(fid);
    if (it == c.opens.end())
        return errorResponse(req, ST_FILE_CLOSED);
    Open &o = it->second;
    if (o.pipe)
        return errorResponse(req, ST_NOT_SUPPORTED);
    bool fixedFolder = o.root || o.path.empty() || (o.kind == SHARE_NETLOGON && o.path == "scripts");
    sysvol::Store *st = o.root ? nullptr : storeFor(o.domain);
    std::string err;

    auto ok = [&]() {
        smb::Smb2Header h;
        h.command = req.command; h.messageId = req.messageId; h.sessionId = req.sessionId;
        h.treeId = req.treeId; h.status = ST_SUCCESS;
        h.creditReqResp = std::max<uint16_t>(1, std::min<uint16_t>(req.creditReqResp, 128));
        auto resp = smb::buildHeader(h);
        w16(resp, 2);
        return resp;
    };

    if (type == 3) {                                     /* security descriptor */
        if (!o.writable || !st)
            return errorResponse(req, ST_ACCESS_DENIED);
        if (!st->setSecurity(o.path, std::string(reinterpret_cast<const char *>(b), len), err))
            return errorResponse(req, ST_ACCESS_DENIED);
        return ok();
    }
    if (type != 1)
        return errorResponse(req, ST_INVALID_INFO_CLASS);

    switch (cls) {
    case 4: {                                            /* FileBasicInformation */
        if (len < 36)
            return errorResponse(req, ST_INFO_LENGTH_MISMATCH);
        if (!o.writable || fixedFolder)
            return ok();                                 /* times on fixed folders: ignore */
        flush(o);
        int64_t ct = int64_t(rd64(b)), at = int64_t(rd64(b + 8)), mt = int64_t(rd64(b + 16));
        uint32_t attrs = rd32(b + 32);
        if (!st->setInfo(o.path, attrs ? int64_t(attrs & ~uint32_t(sysvol::ATTR_NORMAL)) : -1,
                         ct > 0 ? ct : -1, mt > 0 ? mt : -1, at > 0 ? at : -1, err))
            return errorResponse(req, ST_ACCESS_DENIED);
        return ok();
    }
    case 10: {                                           /* FileRenameInformation */
        if (len < 20)
            return errorResponse(req, ST_INFO_LENGTH_MISMATCH);
        if (!o.writable || fixedFolder)
            return errorResponse(req, ST_ACCESS_DENIED);
        bool replace = b[0] != 0;
        uint32_t nlen = rd32(b + 16);
        if (20 + size_t(nlen) > len)
            return errorResponse(req, ST_INVALID_PARAMETER);
        std::string target;
        if (!sysvol::normalize(rpc::fromUtf16(b + 20, nlen), target) || target.empty())
            return errorResponse(req, ST_NAME_INVALID);
        std::string to;
        if (o.kind == SHARE_SYSVOL) {
            std::string first = target.substr(0, target.find('/'));
            if (lowerAscii(first) != lowerAscii(o.domain) || target.find('/') == std::string::npos)
                return errorResponse(req, ST_ACCESS_DENIED);   /* no moves between domains */
            to = target.substr(target.find('/') + 1);
        } else {
            to = "scripts/" + target;
        }
        flush(o);
        if (!st->rename(o.path, to, replace, err)) {
            std::cerr << "[SMB] rename " << o.path << " -> " << to << ": " << err << std::endl;
            return errorResponse(req, err == "target exists" ? ST_NAME_COLLISION : ST_ACCESS_DENIED);
        }
        /* opens below the old path follow the move */
        for (auto &kv : c.opens) {
            Open &x = kv.second;
            if (x.pipe || x.domain != o.domain || x.kind != o.kind) continue;
            if (lowerAscii(x.path) == lowerAscii(o.path) && &x != &o)
                x.path = to;
            else if (lowerAscii(x.path).compare(0, o.path.size() + 1, lowerAscii(o.path) + "/") == 0)
                x.path = to + x.path.substr(o.path.size());
        }
        o.path = to;
        return ok();
    }
    case 13:                                             /* FileDispositionInformation */
    case 64: {                                           /* FileDispositionInformationEx */
        if (len < 1)
            return errorResponse(req, ST_INFO_LENGTH_MISMATCH);
        bool del = cls == 13 ? b[0] != 0 : (len >= 4 && (rd32(b) & 1));
        if (del) {
            if (!o.writable || fixedFolder)
                return errorResponse(req, ST_ACCESS_DENIED);
            if (o.dir && st && !st->list(o.path).empty())
                return errorResponse(req, ST_DIRECTORY_NOT_EMPTY);
        }
        o.deleteOnClose = del;
        return ok();
    }
    case 20: {                                           /* FileEndOfFileInformation */
        if (len < 8)
            return errorResponse(req, ST_INFO_LENGTH_MISMATCH);
        if (!o.writable || o.dir)
            return errorResponse(req, ST_ACCESS_DENIED);
        uint64_t eof = rd64(b);
        if (eof > (64ULL << 20))
            return errorResponse(req, 0xC000007F /* DISK_FULL */);
        o.data.resize(eof, '\0');
        o.dirty = true;
        return ok();
    }
    case 14:                                             /* FilePositionInformation */
    case 16:                                             /* FileModeInformation */
    case 19:                                             /* FileAllocationInformation */
        return ok();
    default:
        return errorResponse(req, ST_INVALID_INFO_CLASS);
    }
}

} /* namespace fenrirds */

/*****************************************************************************
 * Plugin factory
 *****************************************************************************/
#include <json-c/json.h>

extern "C" {

fenrirds::Plugin *fenrirds_plugin_create(fenrirds::AuthBackend &backend, const char *configJson) {
    std::string bindAddr = "0.0.0.0", host;
    int port = 445;
    if (configJson) {
        json_object *j = json_tokener_parse(configJson);
        if (j) {
            if (auto *x = json_object_object_get(j, "smb_bind")) bindAddr = json_object_get_string(x);
            if (auto *x = json_object_object_get(j, "smb_port")) port = json_object_get_int(x);
            if (auto *x = json_object_object_get(j, "dns_hostname")) host = json_object_get_string(x);
            json_object_put(j);
        }
    }
    return new fenrirds::SmbServer(backend, bindAddr, port, host);
}

void fenrirds_plugin_destroy(fenrirds::Plugin *p) { delete p; }

}
+1 −0
Changes for src/CMakeLists.txt: 1 added line, 0 removed lines.
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ list(APPEND fenrirdsSrcs
    dsdb/dns.cpp
    dsdb/secdesc.cpp
    sysvol.cpp
    grouppolicy.cpp
    rpc/ndr.cpp
    rpc/dcerpc.cpp
    rpc/services.cpp
Loading