Commit 8dfebb7f authored by jan.koester's avatar jan.koester
Browse files

test

parent 95dc1ac0
Loading
Loading
Loading
Loading
Loading

data/dirviews.js

0 → 100644
+283 −0
Changes for data/dirviews.js: 283 added lines, 0 removed lines.
Original line number Diff line number Diff line
/* Views of the directory-backed infrastructure of a domain: DNS zones and
 * records, Windows group policy objects. Uses the helpers of admin.html
 * (ajaxGet, ajaxPostMultipart, setContent, loadDomainSelector, ...). The
 * API is /settings/<domain>/api/{dns*,wingpo*}, see src/dirapi.cpp. */

function dirApi(action, param) {
    return "/settings/" + currentDomain + "/api/" + action + (param ? "/" + param : "");
}

function dirPost(action, param, fields, done) {
    var fd = new FormData();
    for (var k in fields)
        if (fields.hasOwnProperty(k)) fd.append(k, fields[k]);
    ajaxPostMultipart(dirApi(action, param), fd, function(err, data) {
        if (err) { alert(dirErr(err)); return; }
        if (data && data.error) { alert(data.error); return; }
        done(data);
    });
}

function dirErr(err) {
    var m = /\{.*\}/.exec(String(err));
    if (m) { try { return JSON.parse(m[0]).error || err; } catch (e) {} }
    return err;
}

function needRealDomain(title) {
    if (currentDomain !== "admin") return false;
    setContent('<h3>' + title + '</h3><p class="hint">Gibt es nur in echten Domänen, nicht in admin.local.</p>');
    return true;
}

/* ================= DNS ================= */
var g_dnsZone = null;

function loadDns() {
    currentView = loadDns;
    setActiveNav('nav-dns');
    loadDomainSelector(function() {
        if (needRealDomain('DNS')) return;
        if (g_dnsZone) { loadDnsZone(g_dnsZone); return; }
        ajaxGet(dirApi("dnszones"), function(err, data) {
            if (err) { showError(dirErr(err)); return; }
            var h = '<h3>DNS-Zonen</h3>';
            h += '<p class="hint">Die AD-Locator-Einträge (SRV für LDAP/Kerberos, A für Domäne und DC) erzeugt der Server selbst; hier stehen die gespeicherten Zonen und eigenen Einträge.</p>';
            h += '<table class="admin-table userlist"><tr><th>Zone</th><th>Art</th><th>Dynamische Updates</th><th>Actions</th></tr>';
            var zs = data.zones || [];
            for (var i = 0; i < zs.length; i++) {
                var z = zs[i], n = escapeHtml(z.name);
                h += '<tr><td><a href="#" onclick="loadDnsZone(\'' + n + '\'); return false;">' + n + '</a></td>';
                h += '<td>' + (z.reverse ? 'Reverse' : 'Forward') + (z.domainzone ? ' (Domäne)' : '') + '</td>';
                h += '<td><select onchange="dnsSetUpdate(\'' + n + '\', this.value)">';
                ['none', 'nonsecure', 'secure'].forEach(function(u) {
                    h += '<option value="' + u + '"' + (z.allowupdate === u ? ' selected' : '') + '>' + u + '</option>';
                });
                h += '</select></td><td><ul>';
                h += '<li><a class="button" href="#" onclick="loadDnsZone(\'' + n + '\'); return false;">Records</a></li>';
                if (!z.domainzone)
                    h += '<li><a class="button danger" href="#" onclick="dnsDeleteZone(\'' + n + '\'); return false;">Delete</a></li>';
                h += '</ul></td></tr>';
            }
            if (!zs.length) h += '<tr><td colspan="4"><em>keine Zonen</em></td></tr>';
            h += '</table>';
            h += '<h4>Neue Zone</h4><form onsubmit="dnsCreateZone(this); return false;">';
            h += '<label>Forward-Zone <input name="name" placeholder="sub.example.com"></label> ';
            h += '<label>oder Reverse-Netz <input name="network" placeholder="10.1.1.0/24"></label> ';
            h += '<label>Updates <select name="allowupdate"><option>nonsecure</option><option>secure</option><option>none</option></select></label> ';
            h += '<input type="submit" class="button" value="Anlegen"></form>';
            setContent(h);
        });
    }, true);
}

function dnsCreateZone(f) {
    dirPost("dnscreatezone", "", {name: f.name.value, network: f.network.value, allowupdate: f.allowupdate.value},
            function() { loadDns(); });
}
function dnsSetUpdate(zone, v) {
    dirPost("dnssetzone", zone, {allowupdate: v}, function() {});
}
function dnsDeleteZone(zone) {
    if (!confirm("Zone " + zone + " mit allen Einträgen löschen?")) return;
    dirPost("dnsdeletezone", zone, {}, function() { loadDns(); });
}

var DNS_TYPES = ['A', 'AAAA', 'CNAME', 'MX', 'TXT', 'SRV', 'PTR', 'NS'];
var DNS_HINTS = {A: '10.1.1.20', AAAA: 'fd00::20', CNAME: 'host.example.com', MX: '10 mail.example.com',
                 TXT: 'v=spf1 -all', SRV: '0 100 443 host.example.com', PTR: 'host.example.com', NS: 'ns.example.com'};

function loadDnsZone(zone) {
    g_dnsZone = zone;
    ajaxGet(dirApi("dnsrecords", zone), function(err, data) {
        if (err) { g_dnsZone = null; showError(dirErr(err)); return; }
        var h = '<h3>Zone ' + escapeHtml(zone) + '</h3>';
        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)); });
        window.g_dnsRecords = rs;
        for (var i = 0; i < rs.length; i++) {
            var r = rs[i];
            h += '<tr><td>' + escapeHtml(r.name) + '</td><td>' + r.type + (r.dynamic ? ' <small>(dyn.)</small>' : '') + '</td>';
            h += '<td>' + r.ttl + '</td><td>' + escapeHtml(r.data) + '</td><td>';
            if (!r.readonly) {
                h += '<ul><li><a class="button" href="#" onclick="dnsEditRecord(' + i + '); return false;">Edit</a></li>';
                h += '<li><a class="button danger" href="#" onclick="dnsDeleteRecord(' + i + '); return false;">Delete</a></li></ul>';
            }
            h += '</td></tr>';
        }
        h += '</table>';
        h += '<h4 id="dns-form-title">Neuer Eintrag</h4><form id="dns-form" onsubmit="dnsSaveRecord(this); return false;">';
        h += '<input type="hidden" name="edit" value="">';
        h += '<label>Name <input name="name" placeholder="' + (data.reverse ? '20 oder 10.1.1.20' : 'host (@ = Zone)') + '"></label> ';
        h += '<label>Typ <select name="type" onchange="this.form.data.placeholder=DNS_HINTS[this.value]">';
        DNS_TYPES.forEach(function(t) { h += '<option' + (data.reverse && t === 'PTR' ? ' selected' : '') + '>' + t + '</option>'; });
        h += '</select></label> ';
        h += '<label>Daten <input name="data" size="40" placeholder="' + DNS_HINTS[data.reverse ? 'PTR' : 'A'] + '"></label> ';
        h += '<label>TTL <input name="ttl" size="6" value="900"></label> ';
        h += '<input type="submit" class="button" value="Speichern"> ';
        h += '<a href="#" onclick="loadDnsZone(g_dnsZone); return false;">Abbrechen</a></form>';
        setContent(h);
    });
}

function dnsEditRecord(i) {
    var r = window.g_dnsRecords[i], f = document.getElementById('dns-form');
    f.edit.value = String(i);
    f.name.value = r.name; f.type.value = r.type; f.data.value = r.data; f.ttl.value = r.ttl;
    document.getElementById('dns-form-title').textContent = 'Eintrag bearbeiten';
    f.scrollIntoView();
}

function dnsSaveRecord(f) {
    var fields = {name: f.name.value, type: f.type.value, data: f.data.value, ttl: f.ttl.value};
    var action = "dnsaddrecord";
    if (f.edit.value !== '') {
        var r = window.g_dnsRecords[parseInt(f.edit.value, 10)];
        fields.oldname = r.name; fields.oldtype = r.type; fields.olddata = r.data;
        action = "dnseditrecord";
    }
    dirPost(action, g_dnsZone, fields, function() { loadDnsZone(g_dnsZone); });
}

function dnsDeleteRecord(i) {
    var r = window.g_dnsRecords[i];
    if (!confirm(r.name + ' ' + r.type + ' ' + r.data + ' löschen?')) return;
    dirPost("dnsdeleterecord", g_dnsZone, {name: r.name, type: r.type, data: r.data}, function() { loadDnsZone(g_dnsZone); });
}

/* ================= Windows group policy ================= */
var g_winGpos = [];
var g_winTargets = [];

function gpoId(guid) { return String(guid).replace(/[{}]/g, ''); }

function loadWinGpos() {
    currentView = loadWinGpos;
    setActiveNav('nav-wingpo');
    loadDomainSelector(function() {
        if (needRealDomain('Windows GPOs')) return;
        ajaxGet(dirApi("wingpolist"), function(err, data) {
            if (err) { showError(dirErr(err)); return; }
            g_winGpos = data.gpos || [];
            g_winTargets = data.targets || [];
            var h = '<h3>Windows-Gruppenrichtlinien</h3>';
            h += '<p class="hint">Gruppenrichtlinienobjekte für Windows-Clients (getrennt von den fenrirds-Policies). Sie liegen im Verzeichnis und im SYSVOL; GPMC kann dieselben Objekte bearbeiten. Hier: Verknüpfungen und Registry-Richtlinien (Registry.pol).</p>';
            h += '<table class="admin-table userlist"><tr><th>Name</th><th>Version (C/U)</th><th>Computer</th><th>Benutzer</th><th>Verknüpft mit</th><th>Actions</th></tr>';
            for (var i = 0; i < g_winGpos.length; i++) {
                var g = g_winGpos[i];
                h += '<tr><td>' + escapeHtml(g.name) + '<br><small>' + escapeHtml(g.guid) + '</small></td>';
                h += '<td>' + g.machineversion + ' / ' + g.userversion + '</td>';
                h += '<td><input type="checkbox"' + (g.machineenabled ? ' checked' : '') + ' onchange="winGpoFlag(' + i + ', \'machineenabled\', this.checked)"></td>';
                h += '<td><input type="checkbox"' + (g.userenabled ? ' checked' : '') + ' onchange="winGpoFlag(' + i + ', \'userenabled\', this.checked)"></td>';
                h += '<td>';
                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>';
                }
                if (!g.links.length) h += '<em>-</em>';
                h += '</td><td><ul>';
                h += '<li><a class="button" href="#" onclick="loadWinGpoRegistry(' + i + ', \'machine\'); return false;">Registry</a></li>';
                h += '<li><a class="button" href="#" onclick="winGpoRename(' + i + '); return false;">Rename</a></li>';
                if (!g.builtin)
                    h += '<li><a class="button danger" href="#" onclick="winGpoDelete(' + i + '); return false;">Delete</a></li>';
                h += '</ul></td></tr>';
            }
            h += '</table>';
            h += '<h4>Neue GPO</h4><form onsubmit="winGpoCreate(this); return false;"><label>Name <input name="name"></label> <input type="submit" class="button" value="Anlegen"></form>';
            h += '<h4>Verknüpfen</h4><form onsubmit="winGpoAddLink(this); return false;">';
            h += '<label>GPO <select name="gpo">';
            g_winGpos.forEach(function(g, i) { h += '<option value="' + i + '">' + escapeHtml(g.name) + '</option>'; });
            h += '</select></label> <label>mit <select name="target">';
            g_winTargets.forEach(function(t, i) { h += '<option value="' + i + '">' + escapeHtml(t.name) + '</option>'; });
            h += '</select></label> <label><input type="checkbox" name="enforced"> erzwungen</label> ';
            h += '<input type="submit" class="button" value="Verknüpfen"></form>';
            setContent(h);
        });
    }, true);
}

function winGpoCreate(f) {
    dirPost("wingpocreate", "", {name: f.name.value}, function() { loadWinGpos(); });
}
function winGpoRename(i) {
    var g = g_winGpos[i], n = prompt("Neuer Name", g.name);
    if (!n || n === g.name) return;
    dirPost("wingposet", gpoId(g.guid), {name: n}, function() { loadWinGpos(); });
}
function winGpoDelete(i) {
    var g = g_winGpos[i];
    if (!confirm('GPO "' + g.name + '" löschen? Alle Verknüpfungen werden entfernt.')) return;
    dirPost("wingpodelete", gpoId(g.guid), {}, function() { loadWinGpos(); });
}
function winGpoFlag(i, which, on) {
    var fields = {};
    fields[which] = on ? 'true' : 'false';
    dirPost("wingposet", gpoId(g_winGpos[i].guid), fields, function() { loadWinGpos(); });
}
function winGpoAddLink(f) {
    var g = g_winGpos[parseInt(f.gpo.value, 10)], t = g_winTargets[parseInt(f.target.value, 10)];
    dirPost("wingpolink", gpoId(g.guid), {target: t.dn, mode: 'link', enforced: f.enforced.checked ? 'true' : 'false'},
            function() { loadWinGpos(); });
}
function winGpoLink(i, k, what) {
    var g = g_winGpos[i], l = g.links[k];
    var f = {target: l.target, mode: what === 'unlink' ? 'unlink' : 'update',
             enforced: String(what === 'enforce' ? !l.enforced : l.enforced),
             disabled: String(what === 'toggle' ? !l.disabled : l.disabled)};
    if (what === 'unlink' && !confirm('Verknüpfung mit ' + l.targetname + ' entfernen?')) return;
    dirPost("wingpolink", gpoId(g.guid), f, function() { loadWinGpos(); });
}

/* ---- Registry.pol editor ---- */
var REG_TYPES = ['REG_DWORD', 'REG_SZ', 'REG_EXPAND_SZ', 'REG_MULTI_SZ', 'REG_QWORD', 'REG_BINARY'];
var g_regGpo = -1, g_regPart = 'machine', g_regValues = [];

function loadWinGpoRegistry(i, part) {
    g_regGpo = i; g_regPart = part;
    var g = g_winGpos[i];
    dirPost("wingporegistry", gpoId(g.guid), {part: part}, function(data) {
        g_regValues = data.values || [];
        renderRegistry();
    });
}

function renderRegistry() {
    var g = g_winGpos[g_regGpo];
    var h = '<h3>' + escapeHtml(g.name) + ' &ndash; Registry</h3>';
    h += '<p><a href="#" onclick="loadWinGpos(); return false;">&larr; alle GPOs</a> | ';
    h += (g_regPart === 'machine' ? '<b>Computer (HKLM)</b>' : '<a href="#" onclick="loadWinGpoRegistry(g_regGpo, \'machine\'); return false;">Computer (HKLM)</a>') + ' | ';
    h += (g_regPart === 'user' ? '<b>Benutzer (HKCU)</b>' : '<a href="#" onclick="loadWinGpoRegistry(g_regGpo, \'user\'); return false;">Benutzer (HKCU)</a>') + '</p>';
    h += '<p class="hint">Schlüssel relativ zu ' + (g_regPart === 'machine' ? 'HKEY_LOCAL_MACHINE' : 'HKEY_CURRENT_USER') + ', z.B. Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU. REG_MULTI_SZ: ein Wert pro Zeile; REG_BINARY: Hex. Wertname **del.&lt;Name&gt; löscht einen Wert auf dem Client.</p>';
    h += '<table class="admin-table userlist"><tr><th>Schlüssel</th><th>Wertname</th><th>Typ</th><th>Daten</th><th></th></tr>';
    for (var i = 0; i < g_regValues.length; i++) {
        var v = g_regValues[i];
        h += '<tr><td><input size="40" value="' + escapeHtml(v.key) + '" onchange="g_regValues[' + i + '].key=this.value"></td>';
        h += '<td><input value="' + escapeHtml(v.name) + '" onchange="g_regValues[' + i + '].name=this.value"></td>';
        h += '<td><select onchange="g_regValues[' + i + '].type=this.value">';
        REG_TYPES.forEach(function(t) { h += '<option' + (v.type === t ? ' selected' : '') + '>' + t + '</option>'; });
        h += '</select></td>';
        if (v.type === 'REG_MULTI_SZ')
            h += '<td><textarea rows="3" onchange="g_regValues[' + i + '].data=this.value">' + escapeHtml(v.data) + '</textarea></td>';
        else
            h += '<td><input size="30" value="' + escapeHtml(v.data) + '" onchange="g_regValues[' + i + '].data=this.value"></td>';
        h += '<td><a class="button danger" href="#" onclick="g_regValues.splice(' + i + ',1); renderRegistry(); return false;">&times;</a></td></tr>';
    }
    if (!g_regValues.length) h += '<tr><td colspan="5"><em>keine Werte</em></td></tr>';
    h += '</table><p>';
    h += '<a class="button" href="#" onclick="g_regValues.push({key:\'Software\\\\Policies\\\\\', name:\'\', type:\'REG_DWORD\', data:\'0\'}); renderRegistry(); return false;">Wert hinzufügen</a> ';
    h += '<a class="button" href="#" onclick="saveRegistry(); return false;">Speichern</a></p>';
    setContent(h);
}

function saveRegistry() {
    var g = g_winGpos[g_regGpo];
    dirPost("wingposetregistry", gpoId(g.guid), {part: g_regPart, values: JSON.stringify(g_regValues)}, function() {
        alert('Gespeichert. Die Clients übernehmen die Änderung bei der nächsten Richtlinienaktualisierung (gpupdate).');
        loadWinGpoRegistry(g_regGpo, g_regPart);
    });
}
+10 −0
Changes for plugin/ad/ad.cpp: 10 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@

#include "ad.h"
#include "grouppolicy.h"
#include "dsdb/dns.h"
#include "sysvol.h"
#include "crypto/gss.h"
#include "crypto/ntlm.h"
@@ -1095,6 +1096,15 @@ void ActiveDirectory::loadDomains() {
                /* SYSVOL layout + the default Windows GPOs and their links */
                sysvol::Store sv(*bck);
                winpolicy::Manager(*d.dir, sv).ensureDefaults();
                /* the domain's DNS zone, so it can be managed right away (the
                 * DNS plugin would create it on its next rebuild otherwise) */
                if (!_DcHost.empty()) {
                    dsdb::dns::Store dz(*d.dir);
                    dsdb::dns::ZoneInfo zi;
                    std::string zerr;
                    if (!dz.zone(e.name, zi))
                        dz.createZone(e.name, dsdb::dns::UPDATE_NONSECURE, _DcHost, zerr);
                }
            } catch (std::exception &ex) {
                std::cerr << "AD: provision '" << e.name << "' failed: " << ex.what() << std::endl;
            }