prepare('INSERT OR REPLACE INTO zones (zone, owner) VALUES (?, (SELECT id FROM users WHERE emailaddress = ?))');
$q->bindValue(1, $zonename, SQLITE3_TEXT);
$q->bindValue(2, $accountname, SQLITE3_TEXT);
$q->execute();
}
function delete_db_zone($zonename)
{
if (!_valid_label($zonename)) {
jtable_respond(null, 'error', "$zonename is not a valid zonename");
}
$db = get_db();
$q = $db->prepare('DELETE FROM zones WHERE zone = ?');
$q->bindValue(1, $zonename, SQLITE3_TEXT);
$q->execute();
}
function get_zone_account($zonename, $default)
{
if (!_valid_label($zonename)) {
jtable_respond(null, 'error', "$zonename is not a valid zonename");
}
$db = get_db();
$q = $db->prepare('SELECT u.emailaddress FROM users u, zones z WHERE z.owner = u.id AND z.zone = ?');
$q->bindValue(1, $zonename, SQLITE3_TEXT);
$result = $q->execute();
$zoneinfo = $result->fetchArray(SQLITE3_ASSOC);
if (isset($zoneinfo['emailaddress']) && $zoneinfo['emailaddress'] != null) {
return $zoneinfo['emailaddress'];
}
return $default;
}
function quote_content($content)
{
# empty TXT records are ok, otherwise require surrounding quotes: "..."
if (strlen($content) == 1 || substr($content, 0, 1) !== '"' || substr($content, -1) !== '"') {
# fix quoting: first escape all \, then all ", then surround with quotes.
$content = '"' . str_replace('"', '\\"', str_replace('\\', '\\\\', $content)) . '"';
}
return $content;
}
function check_account($zone)
{
return is_adminuser() or ($zone->account === get_sess_user());
}
if (isset($_GET['action'])) {
$action = $_GET['action'];
} else {
jtable_respond(null, 'error', 'No action given');
}
try {
$api = new PdnsAPI();
switch ($action) {
case 'list':
case 'listslaves':
$return = [];
$q = isset($_POST['domsearch']) ? $_POST['domsearch'] : false;
foreach ($api->listzones($q) as $sresult) {
$zone = new Zone();
$zone->parse($sresult);
if ($zone->account == '') {
$zone->setAccount(get_zone_account($zone->name, 'admin'));
}
if (!check_account($zone)) {
continue;
}
if ($action == 'listslaves' and $zone->kind == 'Slave') {
array_push($return, $zone->export());
} elseif ($action == 'list' and $zone->kind != 'Slave') {
if ($zone->dnssec) {
$zone->setKeyinfo($api->getzonekeys($zone->id));
}
array_push($return, $zone->export());
}
}
usort($return, 'zone_compare');
jtable_respond($return);
break;
case 'listrecords':
$zonedata = $api->loadzone($_GET['zoneid']);
$zone = new Zone();
$zone->parse($zonedata);
$records = $zone->rrsets2records();
if (!empty($_POST['label'])) {
$records=array_filter(
$records,
function ($val) {
return(stripos($val['name'], $_POST['label']) !== false);
}
);
}
if (!empty($_POST['type'])) {
$records=array_filter(
$records,
function ($val) {
return($val['type'] == $_POST['type']);
}
);
}
if (!empty($_POST['content'])) {
$records=array_filter(
$records,
function ($val) {
return(stripos($val['content'], $_POST['content']) !== false);
}
);
}
if (isset($_GET['jtSorting'])) {
list($scolumn, $sorder) = preg_split('/ /', $_GET['jtSorting']);
switch ($scolumn) {
case 'type':
usort($records, 'record_compare_type');
break;
case 'content':
usort($records, 'record_compare_content');
break;
default:
usort($records, 'record_compare_name');
break;
}
if ($sorder == 'DESC') {
$records = array_reverse($records);
}
} else {
usort($records, 'record_compare_name');
}
jtable_respond($records);
break;
case 'delete':
$zone = $api->loadzone($_POST['id']);
$api->deletezone($_POST['id']);
delete_db_zone($zone['name']);
writelog('Deleted zone ' . $zone['name']);
jtable_respond(null, 'delete');
break;
case 'create':
$zonename = isset($_POST['name']) ? $_POST['name'] : '';
$zonekind = isset($_POST['kind']) ? $_POST['kind'] : '';
if (!is_adminuser() and $allowzoneadd !== true) {
jtable_respond(null, 'error', 'You are not allowed to add zones');
}
if (!_valid_label($zonename)) {
jtable_respond(null, 'error', 'Please only use [a-z0-9_/.-]');
}
if (!$zonename || !$zonekind) {
jtable_respond(null, 'error', 'Not enough data');
}
$zone = new Zone();
$zone->setKind($zonekind);
$zone->setName($zonename);
if ($zonekind != 'Slave') {
if (!isset($_POST['zone']) or isset($_POST['owns'])) {
foreach ($_POST['nameserver'] as $ns) {
$zone->addNameserver($ns);
}
} else {
$zone->importData($_POST['zone']);
}
if (isset($defaults['soa_edit_api'])) {
$zone->setSoaEditApi($defaults['soa_edit_api'], true);
}
if (isset($defaults['soa_edit'])) {
$zone->setSoaEdit($defaults['soa_edit']);
}
} else { // Slave
if (isset($_POST['masters'])) {
foreach (preg_split('/[,;\s]+/', $_POST['masters'], null, PREG_SPLIT_NO_EMPTY) as $master) {
$zone->addMaster($master);
}
}
}
// only admin user and original account can "recreate" zones that are already
// present in our own db but got lost in pdns.
if (!is_adminuser() && get_sess_user() !== get_zone_account($zonename, get_sess_user())) {
jtable_respond(null, 'error', 'Zone already owned by someone else');
}
$api->savezone($zone->export());
$zone = new Zone();
$zone->parse($api->loadzone($zonename));
$zonename = $zone->name;
if (is_adminuser() && isset($_POST['account'])) {
add_db_zone($zonename, $_POST['account']);
$zone->setAccount($_POST['account']);
} else {
add_db_zone($zonename, get_sess_user());
$zone->setAccount(get_sess_user());
}
if (isset($_POST['template']) && $_POST['template'] != 'None') {
foreach (user_template_list() as $template) {
if ($template['name'] !== $_POST['template']) {
continue;
}
foreach ($template['records'] as $record) {
$rrset = $zone->getRRSet($record['name'], $record['type']);
if ($rrset) {
$rrset->delete();
}
}
$api->savezone($zone->export());
foreach ($template['records'] as $record) {
$name = $record['name'] != '' ? join([$record['name'],'.',$zonename]) : $zonename;
$record['content'] = str_replace('[zonename]', $zonename, $record['content']);
$zone->addRecord($name, $record['type'], $record['content']);
}
break;
}
}
$zone = $api->savezone($zone->export());
writelog('Created zone ' . $zone['name']);
jtable_respond($zone, 'single');
break;
case 'update':
$zone = new Zone();
$zone->parse($api->loadzone($_POST['id']));
if ($zone->setSoaEditApi($defaults['soa_edit_api']) != false) {
writelog('Set SOA-EDIT-API to ' . $defaults['soa_edit_api'] . ' for ', $zone->name);
}
$zoneaccount = isset($_POST['account']) ? $_POST['account'] : $zone->account;
if ($zone->account !== $zoneaccount) {
if (!is_adminuser()) {
header('Status: 403 Access denied');
jtable_respond(null, 'error', "Can't change account");
} else {
add_db_zone($zone->name, $zoneaccount);
$zone->setAccount($zoneaccount);
}
}
if (isset($_POST['masters'])) {
$zone->eraseMasters();
foreach (preg_split('/[,;\s]+/', $_POST['masters'], null, PREG_SPLIT_NO_EMPTY) as $master) {
$zone->addMaster($master);
}
}
writelog('Updated zone ' . $zone->name);
jtable_respond($api->savezone($zone->export()), 'single');
break;
case 'createrecord':
$zone = new Zone();
$zone->parse($api->loadzone($_GET['zoneid']));
if ($zone->setSoaEditApi($defaults['soa_edit_api']) != false) {
writelog('Set SOA-EDIT-API to ' . $defaults['soa_edit_api'] . ' for ', $zone->name);
}
$name = isset($_POST['name']) ? $_POST['name'] : '';
$type = $_POST['type'];
$content = $_POST['content'];
if ('' == $name) {
$name = $zone->name;
} elseif (string_ends_with($name, '.')) {
# "absolute" name, shouldn't append zone[name] - but check.
if (!string_ends_with($name, $zone->name)) {
jtable_respond(null, 'error', "Name $name not in zone " . $zone->name);
}
} elseif (!string_ends_with($name . '.', $zone->name)) {
$name = $name . '.' . $zone->name;
} else {
$name = $name . '.';
}
if (!_valid_label($name)) {
jtable_respond(null, 'error', 'Please only use [a-z0-9_/.-]');
}
if (!$type) {
jtable_respond(null, 'error', 'Require a type');
}
if (!is_ascii($content)) {
jtable_respond(null, 'error', 'Please only use ASCII-characters in your fields');
}
if (array_search($type, $quoteus) !== false) {
$content = quote_content($content);
}
$record = $zone->addRecord($name, $type, $content, $_POST['disabled'], $_POST['ttl'], $_POST['setptr']);
$api->savezone($zone->export());
writelog('Created record: ' . $record['id']);
jtable_respond($record, 'single');
break;
case 'editrecord':
$zone = new Zone();
$zone->parse($api->loadzone($_GET['zoneid']));
if ($zone->setSoaEditApi($defaults['soa_edit_api']) != false) {
writelog('Set SOA-EDIT-API to ' . $defaults['soa_edit_api'] . ' for ', $zone->name);
}
$old_record = decode_record_id(isset($_POST['id']) ? $_POST['id'] : '');
$rrset = $zone->getRRSet($old_record['name'], $old_record['type']);
$rrset->deleteRecord($old_record['content']);
$content = $_POST['content'];
$type = $_POST['type'];
if (array_search($type, $quoteus) !== false) {
$content = quote_content($content);
}
$zone->addRecord($_POST['name'], $_POST['type'], $content, $_POST['disabled'], $_POST['ttl'], $_POST['setptr']);
$api->savezone($zone->export());
$record = $zone->getRecord($_POST['name'], $_POST['type'], $content);
writelog('Updated record ' . $_POST['id'] . ' to ' . $record['id']);
jtable_respond($record, 'single');
break;
case 'deleterecord':
$zone = new Zone();
$zone->parse($api->loadzone($_GET['zoneid']));
if ($zone->setSoaEditApi($defaults['soa_edit_api']) != false) {
writelog('Set SOA-EDIT-API to ' . $defaults['soa_edit_api'] . ' for ', $zone->name);
}
$old_record = decode_record_id(isset($_POST['id']) ? $_POST['id'] : '');
$rrset = $zone->getRRSet($old_record['name'], $old_record['type']);
$rrset->deleteRecord($old_record['content']);
$api->savezone($zone->export());
writelog('Deleted record ' . $_POST['id']);
jtable_respond(null, 'delete');
break;
case 'export':
writelog('Exported zone ' . $_GET['zoneid']);
jtable_respond($api->exportzone($_GET['zoneid']), 'single');
break;
case 'clone':
$name = $_POST['destname'];
$src = $_POST['sourcename'];
if (!string_ends_with($name, '.')) {
$name = $name . '.';
}
if (!_valid_label($name)) {
jtable_respond(null, 'error', 'Invalid destination zonename');
}
$srczone = new Zone();
$srczone->parse($api->loadzone($src));
if ($srczone->setSoaEditApi($defaults['soa_edit_api']) != false) {
writelog('Set SOA-EDIT-API to ' . $defaults['soa_edit_api'] . ' for ', $srczone->name);
}
$srczone->setId('');
$srczone->setName($name);
$srczone->setSerial('');
$srczone->setKind($_POST['kind']);
$zone = $api->savezone($srczone->export());
$srczone->parse($zone);
foreach ($srczone->rrsets as $rrset) {
$newname = $rrset->name;
$newname = preg_replace('/' . $src . '$/', $name, $newname);
$rrset->setName($newname);
}
if (is_adminuser() && isset($_POST['account'])) {
add_db_zone($name, $_POST['account']);
$srczone->setAccount($_POST['account']);
} else {
add_db_zone($name, get_sess_user());
$srczone->setAccount(get_sess_user());
}
$zone = $api->savezone($srczone->export());
writelog("Cloned zone $src into $name");
jtable_respond($zone, 'single');
break;
case 'gettemplatenameservers':
$ret = [];
$type = $_GET['prisec'];
foreach (user_template_list() as $template) {
if ($template['name'] !== $_GET['template']) {
continue;
}
$rc = 0;
foreach ($template['records'] as $record) {
if ($record['type'] == 'NS') {
if (($type == 'pri' && $rc == 0) or ($type == 'sec' && $rc == 1)) {
echo $record['content'];
exit(0);
}
$rc++;
}
}
echo '';
}
break;
case 'getformnameservers':
$inputs = [];
foreach (user_template_list() as $template) {
if ($template['name'] !== $_GET['template']) {
continue;
}
foreach ($template['records'] as $record) {
if ($record['type'] == 'NS' and array_search($record['content'], $inputs) === false) {
array_push($inputs, $record['content']);
echo '
';
}
}
}
break;
case 'formzonelist':
$zones = $api->listzones();
usort($zones, 'zone_compare');
$ret = [];
foreach ($zones as $zone) {
if ($zone['kind'] == 'Slave') {
continue;
}
array_push($ret, [
'DisplayText' => $zone['name'],
'Value' => $zone['id']]);
}
jtable_respond($ret, 'options');
break;
default:
jtable_respond(null, 'error', 'No such action');
break;
}
} catch (Exception $e) {
jtable_respond(null, 'error', $e->getMessage());
}