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()); }