This commit is contained in:
Richard Underwood 2018-06-07 08:44:46 +00:00 committed by GitHub
commit 20a70838b0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 1451 additions and 243 deletions

134
groups.php Normal file
View file

@ -0,0 +1,134 @@
<?php
include_once('includes/config.inc.php');
include_once('includes/session.inc.php');
include_once('includes/misc.inc.php');
if (!is_csrf_safe()) {
header('Status: 403');
header('Location: ./index.php');
jtable_respond(null, 'error', "Authentication required");
}
if (!is_adminuser()) {
header('Status: 403');
jtable_respond(null, 'error', "You need admin privileges to get here");
}
if (!isset($_GET['action'])) {
header('Status: 400');
jtable_respond(null, 'error', 'No action given');
}
switch ($_GET['action']) {
case "list":
$groups = get_all_groups();
jtable_respond($groups);
break;
case "listoptions":
$groups = get_all_groups();
$retgroups = array();
foreach ($groups as $group) {
$retgroups[] = array(
'DisplayText' => $group['name'] . " - " . $group['desc'],
'Value' => $group['name']);
}
jtable_respond($retgroups, 'options');
break;
case "create":
$name = isset($_POST['name']) ? $_POST['name'] : '';
$desc = isset($_POST['desc']) ? $_POST['desc'] : '';
if (!valid_group($name)) {
jtable_respond(null, 'error', "Please only use ^[a-z0-9@_.-]+$ for group names");
}
if (group_exists($name)) {
jtable_respond(null, 'error', 'Group already exists');
}
if (add_group($name, $desc)) {
$result = array('name' => $name, 'desc' => $desc);
jtable_respond($result, 'single');
} else {
jtable_respond(null, 'error', 'Could not create group');
}
break;
case "update":
$id = isset($_POST['id']) ? intval($_POST['id']) : '';
$name = isset($_POST['name']) ? $_POST['name'] : '';
$desc = isset($_POST['desc']) ? $_POST['desc'] : '';
if ($id != '' and update_group($id, $name, $desc)) {
$result = array('name' => $name, 'desc' => $desc);
jtable_respond($result, 'single');
} else {
jtable_respond(null, 'error', 'Could not update group');
}
break;
case "delete":
$id = isset($_POST['id']) ? intval($_POST['id']) : '';
if ($id != '' and delete_group($id) !== FALSE) {
jtable_respond(null, 'delete');
} else {
jtable_respond(null, 'error', 'Could not delete group');
}
break;
case "listmembers":
$groupid = isset($_GET['groupid']) ? intval($_GET['groupid']) : '';
if ($groupid != '') {
$groups = get_group_members($groupid);
jtable_respond($groups);
} else {
jtable_respond(null, 'error', 'Could not list group members');
}
break;
case "addmember":
$groupid = isset($_GET['groupid']) ? intval($_GET['groupid']) : '';
$user = isset($_POST['user']) ? $_POST['user'] : '';
if ($groupid != '') {
if (user_exists($user)) {
if(is_group_member($groupid,$user)) {
jtable_respond(null, 'error', "User already a member of the group");
} elseif(!is_null($id=add_group_member($groupid,$user))) {
$entry = array('id' => $id,'user' => $user);
jtable_respond($entry, 'single');
} else {
jtable_respond(null, 'error', "Failed to add user to group");
}
} else {
jtable_respond(null, 'error', "User doesn't exist");
}
} else {
jtable_respond(null, 'error', 'Group not specified');
}
break;
case "removemember":
$id = isset($_POST['id']) ? $_POST['id'] : '';
if ($id != '') {
if(remove_group_member($id)) {
jtable_respond(null, 'delete');
} else {
jtable_respond(null, 'error', "Failed to delete user from group");
}
} else {
jtable_respond(null, 'error', 'ID not specified');
}
break;
default:
jtable_respond(null, 'error', 'Invalid action');
break;
}

View file

@ -10,6 +10,12 @@ $logging = TRUE;
$allowclearlogs = TRUE; # Allow clearing of log entries
$allowrotatelogs = FALSE;# Allow rotation to text file on server
$restrictediting = TRUE; # Restrict editing of record types
$restrictedtypes = array(
'SOA' => 1,
'NS' => 1
);
# Log directory - if allowrotatelogs is set, this is where the logs will
# be written. It must be writeable by the web server user.
$logsdirectory = "../etc";

60
includes/database.inc.php Normal file
View file

@ -0,0 +1,60 @@
<?php
// matches version in scheme.sql
$db_version=2;
// Initialise a new DB with latest version
function init_db() {
global $authdb, $db;
is_dir(dirname($authdb)) || mkdir(dirname($authdb));
$db = new SQLite3($authdb, SQLITE3_OPEN_CREATE|SQLITE3_OPEN_READWRITE);
$createsql = file_get_contents('includes/scheme.sql');
$db->exec($createsql);
$salt = bin2hex(openssl_random_pseudo_bytes(16));
$db->exec("INSERT INTO users (emailaddress, password, isadmin) VALUES ('admin', '".crypt("admin", '$6$'.$salt)."', 1)");
return $db;
}
function open_db() {
global $authdb, $db, $db_version;
if (!isset($db)) {
$db = new SQLite3($authdb, SQLITE3_OPEN_READWRITE);
$db->exec('PRAGMA foreign_keys = 1');
}
$version = intval($db->querySingle('SELECT value FROM metadata WHERE name = "version"'));
switch($version) {
case 0:
$sql = file_get_contents('includes/upgrade-0-1.sql');
$db->exec($sql);
writelog("Upgraded schema to version 1","system");
// continue
case 1: // never existed
$sql = file_get_contents('includes/upgrade-1-2.sql');
$db->exec($sql);
writelog("Upgraded schema to version 2","system");
// continue
case $db_version:
break;
}
return $db;
}
function get_db() {
global $authdb, $db;
if (!isset($db)) {
open_db();
}
return $db;
}
?>

176
includes/groups.inc.php Normal file
View file

@ -0,0 +1,176 @@
<?php
function get_all_groups() {
$db = get_db();
$r = $db->query('SELECT id, name, desc FROM groups ORDER BY name');
$ret = array();
while ($row = $r->fetchArray(SQLITE3_ASSOC)) {
array_push($ret, $row);
}
return $ret;
}
function get_group_info($name) {
$db = get_db();
$q = $db->prepare('SELECT * FROM groups WHERE name = ?');
$q->bindValue(1, $name);
$result = $q->execute();
$groupinfo = $result->fetchArray(SQLITE3_ASSOC);
return $groupinfo;
}
function get_group_name($id) {
$db = get_db();
$q = $db->prepare('SELECT name FROM groups WHERE id = ?');
$q->bindValue(1, $id, SQLITE3_INTEGER);
$r = $q->execute();
$ret = $r->fetchArray(SQLITE3_NUM);
if($ret) {
return $ret[0];
} else {
return null;
}
}
function group_exists($name) {
return (bool) get_group_info($name);
}
function add_group($name, $desc) {
$db = get_db();
$q = $db->prepare('INSERT INTO groups (name, desc) VALUES (?, ?)');
$q->bindValue(1, $name, SQLITE3_TEXT);
$q->bindValue(2, $desc, SQLITE3_TEXT);
$ret = $q->execute();
writelog("Added group $name ($desc).");
return $ret;
}
function update_group($id, $name, $desc) {
$db = get_db();
$q = $db->prepare('SELECT * FROM groups WHERE id = ?');
$q->bindValue(1, $id, SQLITE3_INTEGER);
$result = $q->execute();
$groupinfo = $result->fetchArray(SQLITE3_ASSOC);
$q->close();
$oldname = $groupinfo['name'];
$q = $db->prepare('UPDATE groups SET name = ?, desc = ? WHERE id = ?');
$q->bindValue(1, $name, SQLITE3_TEXT);
$q->bindValue(2, $desc, SQLITE3_TEXT);
$q->bindValue(3, $id, SQLITE3_INTEGER);
writelog("Updating group $oldname to: $name ($desc) ");
$ret = $q->execute();
return $ret;
}
function delete_group($id) {
$db = get_db();
$q = $db->prepare('SELECT * FROM groups WHERE id = ?');
$q->bindValue(1, $id, SQLITE3_INTEGER);
$result = $q->execute();
$groupinfo = $result->fetchArray(SQLITE3_ASSOC);
$q->close();
if($groupinfo) {
$q = $db->prepare('DELETE FROM groups WHERE id = ?');
$q->bindValue(1, $id, SQLITE3_INTEGER);
$ret = $q->execute();
writelog("Deleted group " . $groupinfo['name'] . ".");
return $ret;
} else {
return false;
}
}
function valid_group($name) {
return ( bool ) preg_match( "/^[a-z0-9@_.-]+$/i" , $name );
}
function get_group_members($id) {
$db = get_db();
$q = $db->prepare('SELECT groupmembers.id,users.emailaddress AS user FROM groupmembers,users WHERE "group" = ? AND groupmembers.user = users.id');
$q->bindValue(1, $id, SQLITE3_INTEGER);
$result = $q->execute();
$ret = array();
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
array_push($ret, $row);
}
return $ret;
}
function get_group_id($group) {
$info=get_group_info($group);
if($info) {
return $info['id'];
} else {
return null;
}
}
function is_group_member($id,$user) {
$db = get_db();
$q = $db->prepare('SELECT id FROM groupmembers WHERE "group" = ? AND user = ?');
$q->bindValue(1, $id, SQLITE3_INTEGER);
$q->bindValue(2, get_user_id($user), SQLITE3_INTEGER);
$r = $q->execute();
$ret = $r->fetchArray(SQLITE3_NUM);
return (bool) $ret;
}
function add_group_member($id,$user) {
$db = get_db();
$userid=get_user_id($user);
$q = $db->prepare('INSERT INTO groupmembers ("group", user) VALUES (?, ?)');
$q->bindValue(1, $id, SQLITE3_INTEGER);
$q->bindValue(2, $userid, SQLITE3_INTEGER);
$ret = $q->execute();
if($ret) {
writelog("Added user $user to group " . get_group_name($id) . ".");
return $db->lastInsertRowID();
} else {
writelog("Failed to add user $user to group " . get_group_name($id) . ".");
return null;
}
}
function remove_group_member($id) {
$db = get_db();
$q = $db->prepare('SELECT groups.name,users.emailaddress FROM groupmembers,users,groups WHERE groupmembers.id=? AND groupmembers.user=users.id AND groupmembers."group"=groups.id');
$q->bindValue(1, $id, SQLITE3_INTEGER);
$r = $q->execute();
$ret = $r->fetchArray(SQLITE3_NUM);
$group=$ret[0];
$user=$ret[1];
$q->close();
$q = $db->prepare('DELETE FROM groupmembers WHERE id=?');
$q->bindValue(1, $id, SQLITE3_INTEGER);
$ret = $q->execute();
if($ret) {
writelog("Removed user $user from group $group.");
} else {
writelog("Failed to remove user $user from group $group.");
}
return $ret;
}
?>

View file

@ -1,6 +1,7 @@
<?php
include('config.inc.php');
include_once('config.inc.php');
include_once('database.inc.php');
$blocklogin = FALSE;
@ -59,13 +60,12 @@ if (function_exists('openssl_random_pseudo_bytes') === FALSE) {
$defaults['defaulttype'] = ucfirst(strtolower($defaults['defaulttype']));
if (isset($authdb) && !file_exists($authdb) && class_exists('SQLite3')) {
is_dir(dirname($authdb)) || mkdir(dirname($authdb));
$db = new SQLite3($authdb, SQLITE3_OPEN_CREATE|SQLITE3_OPEN_READWRITE);
$createsql = file_get_contents('includes/scheme.sql');
$db->exec($createsql);
$salt = bin2hex(openssl_random_pseudo_bytes(16));
$db->exec("INSERT INTO users (emailaddress, password, isadmin) VALUES ('admin', '".crypt("admin", '$6$'.$salt)."', 1)");
if(class_exists('SQLite3')) {
if (isset($authdb) && !file_exists($authdb)) {
init_db();
} else {
open_db();
}
}
function string_starts_with($string, $prefix)
@ -84,17 +84,6 @@ function string_ends_with($string, $suffix)
return (substr($string, -$length) === $suffix);
}
function get_db() {
global $authdb, $db;
if (!isset($db)) {
$db = new SQLite3($authdb, SQLITE3_OPEN_READWRITE);
$db->exec('PRAGMA foreign_keys = 1');
}
return $db;
}
function get_all_users() {
$db = get_db();
$r = $db->query('SELECT id, emailaddress, isadmin FROM users ORDER BY emailaddress');
@ -106,6 +95,40 @@ function get_all_users() {
return $ret;
}
/* Fetches a list of usernames from the DB for autocomplete.
* Restricts list by $term which can appear anywhere in the username
* Restricts results to $num responses
*/
function get_usernames_filtered($term, $num = 10) {
$db = get_db();
$q = $db->prepare("SELECT emailaddress FROM users WHERE emailaddress LIKE ? ORDER BY emailaddress LIMIT 0, ?");
$q->bindValue(1, "%" . $term . "%", SQLITE3_TEXT);
$q->bindValue(2, $num, SQLITE3_INTEGER);
$r = $q->execute();
$ret = array();
while ($row = $r->fetchArray(SQLITE3_NUM)) {
array_push($ret, $row[0]);
}
return $ret;
}
function get_groups_filtered($term, $num = 10) {
$db = get_db();
$q = $db->prepare("SELECT name FROM groups WHERE name LIKE ? ORDER BY name LIMIT 0, ?");
$q->bindValue(1, "%" . $term . "%", SQLITE3_TEXT);
$q->bindValue(2, $num, SQLITE3_INTEGER);
$r = $q->execute();
$ret = array();
while ($row = $r->fetchArray(SQLITE3_NUM)) {
array_push($ret, $row[0]);
}
return $ret;
}
function get_user_info($u) {
$db = get_db();
$q = $db->prepare('SELECT * FROM users WHERE emailaddress = ?');
@ -216,6 +239,10 @@ function valid_user($name) {
}
function jtable_respond($records, $method = 'multiple', $msg = 'Undefined errormessage') {
if($records == null) {
$records=array();
}
$jTableResult = array();
if ($method == 'error') {
$jTableResult['Result'] = "ERROR";
@ -355,13 +382,6 @@ function writelog($line, $user=False) {
try {
$db = get_db();
$q = $db->prepare('CREATE TABLE IF NOT EXISTS logs (
id INTEGER PRIMARY KEY,
user TEXT NOT NULL,
log TEXT NOT NULL,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP);');
$ret = $q->execute();
$q = $db->prepare('INSERT INTO logs (user, log) VALUES (:user, :log)');
$q->bindValue(':user', $user, SQLITE3_TEXT);
$q->bindValue(':log', $line, SQLITE3_TEXT);
@ -455,4 +475,53 @@ if (!function_exists('hash_pbkdf2')) {
}
}
// get user id from name
function get_user_id($user) {
$info=get_user_info($user);
if($info) {
return $info['id'];
} else {
return null;
}
}
// get zone id from name
function get_zone_id($zone) {
$db = get_db();
$q = $db->prepare('SELECT id FROM zones WHERE zone=?');
$q->bindValue(1, $zone, SQLITE3_TEXT);
$r = $q->execute();
$ret = $r->fetchArray(SQLITE3_NUM);
if($ret) {
return $ret[0];
} else {
return null;
}
}
// get user name from id
function get_user_name($userid) {
$db = get_db();
$q = $db->prepare('SELECT emailAddress FROM users WHERE id = ?');
$q->bindValue(1, $userid, SQLITE3_INTEGER);
$r = $q->execute();
$ret = $r->fetchArray(SQLITE3_NUM);
if($ret) {
return $ret[0];
} else {
return null;
}
}
// Include functions for group management
include_once('groups.inc.php');
// Include functions for permissions management
include_once('permissions.inc.php');
?>

View file

@ -0,0 +1,253 @@
<?php
/*
* Permissions.
*
* Set on either users or groups.
* User permissions override any permissions on groups (as are more specific)
* Group permissions are additive
* "Account" renamed as "Owner" in interface, and will always have full permissions.
*
* Bitmask:
* 0x01 - View
* 0x02 - Update non-special records
* 0x04 - Update special records
* 0x08 - Admin (e.g. change permissions)
*
* The interface will use combinations of these shown in the permissionsmap below.
*
*/
$permissionmap=array(
'0' => 'No permissions',
'1' => 'View Only',
'3' => 'Update normal records',
'7' => 'Update all records',
'15' => 'Admin'
);
define('PERM_VIEW',0x01);
define('PERM_UPDATE',0x02);
define('PERM_UPDATESPECIAL',0x04);
define('PERM_ADMIN',0x08);
define('PERM_ALL',0xffff);
// Interface function - Return an array of permissions for the zone
function get_zone_permissions($zone) {
$db = get_db();
$q = $db->prepare('SELECT p.id,p.user,u.emailAddress AS uname,p."group",g.name AS gname, p.permissions FROM permissions p LEFT JOIN users u ON p.user=u.id LEFT JOIN groups g ON p."group"=g.id LEFT JOIN zones z ON p.zone=z.id WHERE z.zone=?');
$q->bindValue(1, $zone, SQLITE3_TEXT);
$result = $q->execute();
$ret = array();
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
$row2 = array();
$row2['id']=$row['id'];
if($row['user']>0) {
$row2['type']='user';
$row2['value']=$row['uname'];
} else {
$row2['type']='group';
$row2['value']=$row['gname'];
}
$row2['permissions']=$row['permissions'];
array_push($ret, $row2);
}
return $ret;
}
// Interface function - Set permissions for a zone - either userid or groupid should be null
function set_permissions($userid,$groupid,$zone,$permissions) {
global $permissionmap;
$db = get_db();
$q = $db->prepare('INSERT INTO permissions (zone,user,"group",permissions) VALUES (?,?,?,?)');
$q->bindValue(1, get_zone_id($zone), SQLITE3_INTEGER);
$q->bindValue(2, $userid, SQLITE3_INTEGER);
$q->bindValue(3, $groupid, SQLITE3_INTEGER);
$q->bindValue(4, $permissions, SQLITE3_INTEGER);
$ret = $q->execute();
if(!is_null($userid)) {
$who="user " . get_user_name($userid);
} else {
$who="group " . get_group_name($groupid);
}
if($ret) {
writelog("Added '$permissionmap[$permissions]' permissions for $who from zone $zone.");
return $db->lastInsertRowID();
} else {
writelog("Failed to add permissions to zone $zone for $who.");
return null;
}
}
// Interface function - Copy permissions from one zone to another - used for cloning, so assumes no existing permissions on the domain
function copy_permissions($srczone,$dstzone) {
$db = get_db();
$q = $db->prepare('SELECT p.user,p."group",p.permissions FROM permissions p, zones z WHERE p.zone=z.id AND z.zone=?');
$q->bindValue(1, $srczone, SQLITE3_TEXT);
$result = $q->execute();
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
set_permissions($row['user'],$row['group'],$dstzone,$row['permissions']);
}
return null;
}
// Interface function - Update permissions for a zone
function update_permissions($id,$permissions) {
global $permissionmap;
$db = get_db();
$q = $db->prepare('SELECT p.permissions, u.emailAddress, g.name, z.zone FROM permissions p LEFT JOIN users u ON p.user=u.id LEFT JOIN groups g ON p."group"=g.id LEFT JOIN zones z ON p.zone=z.id WHERE p.id=?');
$q->bindValue(1, $id, SQLITE3_INTEGER);
$r = $q->execute();
$ret = $r->fetchArray(SQLITE3_NUM);
if($ret[1]!='') {
$who="user " . $ret[1];
} else {
$who="group " . $ret[2];
}
$before=$ret[0];
$zone=$ret[3];
$q->close();
$q = $db->prepare('UPDATE permissions SET permissions=? WHERE id=?');
$q->bindValue(1, $permissions, SQLITE3_INTEGER);
$q->bindValue(2, $id, SQLITE3_INTEGER);
$ret = $q->execute();
if($ret) {
writelog("Permissions changed on zone $zone for $who from '$permissionmap[$before]' to '$permissionmap[$permissions]'.");
return $db->lastInsertRowID();
} else {
writelog("Failed to set permissions on zone $zone for $who (permissions id $id).");
return null;
}
}
// Interface function - Remove permissions from a zone
function remove_permissions($id) {
global $permissionmap;
$db = get_db();
$q = $db->prepare('SELECT p.permissions, u.emailAddress, g.name, z.zone FROM permissions p LEFT JOIN users u ON p.user=u.id LEFT JOIN groups g ON p."group"=g.id LEFT JOIN zones z ON p.zone=z.id WHERE p.id=?');
$q->bindValue(1, $id, SQLITE3_INTEGER);
$r = $q->execute();
$ret = $r->fetchArray(SQLITE3_NUM);
if($ret[1]!='') {
$who="user " . $ret[1];
} else {
$who="group " . $ret[2];
}
$before=$ret[0];
$zone=$ret[3];
$q->close();
$q = $db->prepare('DELETE FROM permissions WHERE id=?');
$q->bindValue(1, $id, SQLITE3_INTEGER);
$ret = $q->execute();
if($ret) {
writelog("Removed '$permissionmap[$before]' permissions for $who from zone $zone");
} else {
writelog("Failed to remove permissions for $who from zone $zone (permissions id $id).");
}
return $ret;
}
// Utility function - Return the permissions set on the zone for this user *not including any group membership*
function user_permissions($zone,$userid) {
$db = get_db();
$q = $db->prepare('SELECT p.permissions FROM permissions p LEFT JOIN zones z ON p.zone=z.id WHERE p.user=? AND z.zone=?');
$q->bindValue(1, $userid, SQLITE3_INTEGER);
$q->bindValue(2, $zone, SQLITE3_TEXT);
$r = $q->execute();
if($r) {
$ret = $r->fetchArray(SQLITE3_NUM);
return $ret[0];
} else {
return null;
}
}
// Utility function - Return the permissions set on the zone for this group
function group_permissions($zone,$groupid) {
$db = get_db();
$q = $db->prepare('SELECT p.permissions FROM permissions p LEFT JOIN zones z ON p.zone=z.id WHERE p."group"=? AND z.zone=?');
$q->bindValue(1, $groupid, SQLITE3_INTEGER);
$q->bindValue(2, $zone, SQLITE3_TEXT);
$r = $q->execute();
if($r) {
$ret = $r->fetchArray(SQLITE3_NUM);
return $ret[0];
} else {
return null;
}
}
// utility function - get the owner of the domain. Move to misc?
function zone_owner($zone) {
$db = get_db();
$q = $db->prepare('SELECT owner FROM zones WHERE zones.zone=?');
$q->bindValue(1,$zone,SQLITE3_TEXT);
$r = $q->execute();
if($r) {
$ret = $r->fetchArray(SQLITE3_NUM);
return $ret[0];
} else {
return null;
}
}
// Utility function - Return the calculated permissions for this user/zone
function permissions($zone,$userid) {
if(is_adminuser() || ($userid == zone_owner($zone))) {
return PERM_ALL;
}
$perm=user_permissions($zone,$userid);
if(!is_null($perm)) {
return $perm;
} else {
$perm=0;
$zoneid=get_zone_id($zone);
$db = get_db();
$q = $db->prepare('SELECT p.permissions FROM groupmembers gm LEFT JOIN permissions p ON p."group"=gm."group" WHERE zone=? AND p."group">0 AND gm.user=?');
$q->bindValue(1, $zoneid, SQLITE3_INTEGER);
$q->bindValue(2, $userid, SQLITE3_INTEGER);
$r = $q->execute();
while ($row = $r->fetchArray(SQLITE3_NUM)) {
$perm=$perm|$row[0];
}
return $perm;
}
}
// Utility function - check a permission for current user
function check_permissions($zone,$permmask) {
return (bool) (permissions($zone,get_user_id(get_sess_user()))&$permmask);
}
?>

View file

@ -12,3 +12,39 @@ CREATE TABLE zones (
owner INTEGER NOT NULL,
UNIQUE(zone),
FOREIGN KEY(owner) REFERENCES users(id) ON DELETE CASCADE ON UPDATE CASCADE );
CREATE TABLE logs (
id INTEGER PRIMARY KEY,
user TEXT NOT NULL,
log TEXT NOT NULL,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP);
CREATE TABLE groups (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name VARCHAR UNIQUE NOT NULL,
desc VARCHAR);
CREATE TABLE groupmembers (
id INTEGER PRIMARY KEY AUTOINCREMENT,
"group" INTEGER NOT NULL,
user INTEGER NOT NULL,
UNIQUE("group",user),
FOREIGN KEY("group") REFERENCES groups(id) ON DELETE CASCADE,
FOREIGN KEY(user) REFERENCES users(id) ON DELETE CASCADE);
CREATE TABLE permissions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
zone INTEGER NOT NULL,
user INTEGER,
"group" INTEGER,
permissions INTEGER,
UNIQUE(zone,user,"group"),
FOREIGN KEY(zone) REFERENCES zones(id) ON DELETE CASCADE,
FOREIGN KEY(user) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY("group") REFERENCES groups(id) ON DELETE CASCADE);
CREATE TABLE metadata (
name VARCHAR PRIMARY KEY,
value VARCHAR NOT NULL);
INSERT INTO metadata (name, value) VALUES ("version","2");

5
includes/upgrade-0-1.sql Normal file
View file

@ -0,0 +1,5 @@
CREATE TABLE IF NOT EXISTS logs (
id INTEGER PRIMARY KEY,
user TEXT NOT NULL,
log TEXT NOT NULL,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP);

29
includes/upgrade-1-2.sql Normal file
View file

@ -0,0 +1,29 @@
CREATE TABLE groups (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name VARCHAR UNIQUE NOT NULL,
desc VARCHAR);
CREATE TABLE groupmembers (
id INTEGER PRIMARY KEY AUTOINCREMENT,
"group" INTEGER NOT NULL,
user INTEGER NOT NULL,
UNIQUE("group",user),
FOREIGN KEY("group") REFERENCES groups(id) ON DELETE CASCADE,
FOREIGN KEY(user) REFERENCES users(id) ON DELETE CASCADE);
CREATE TABLE permissions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
zone INTEGER NOT NULL,
user INTEGER,
"group" INTEGER,
permissions INTEGER,
UNIQUE(zone,user,"group"),
FOREIGN KEY(zone) REFERENCES zones(id) ON DELETE CASCADE,
FOREIGN KEY(user) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY("group") REFERENCES groups(id) ON DELETE CASCADE);
CREATE TABLE metadata (
name VARCHAR PRIMARY KEY,
value VARCHAR NOT NULL);
INSERT INTO metadata (name, value) VALUES ("version","2");

439
index.php
View file

@ -48,6 +48,8 @@ if (is_logged_in() and isset($_POST['formname']) and $_POST['formname'] === "cha
<script src="jquery-ui/ui/button.js" type="text/javascript"></script>
<script src="jquery-ui/ui/resizable.js" type="text/javascript"></script>
<script src="jquery-ui/ui/dialog.js" type="text/javascript"></script>
<script src="jquery-ui/ui/menu.js" type="text/javascript"></script>
<script src="jquery-ui/ui/autocomplete.js" type="text/javascript"></script>
<script src="jtable/lib/jquery.jtable.min.js" type="text/javascript"></script>
<script src="js/addclear/addclear.js" type="text/javascript"></script>
</head>
@ -162,7 +164,7 @@ if ($blocklogin === TRUE) {
<ul>
<li><a href="#" id="zoneadmin">Zones</a></li>
<?php if (is_adminuser()) { ?>
<li><a href="#" id="useradmin">Users</a></li>
<li><a href="#" id="useradmin">Users/Groups</a></li>
<li><a href="#" id="logadmin">Logs</a></li>
<?php } ?>
<li><a href="#" id="aboutme">About me</a></li>
@ -188,6 +190,7 @@ if ($blocklogin === TRUE) {
<?php if (is_adminuser()) { ?>
<div id="users">
<div class="tables" id="Users"></div>
<div class="tables" id="Groups"></div>
</div>
<div id="logs">
<div class="tables" id="Logs"></div>
@ -373,7 +376,7 @@ $(document).ready(function () {
},
<?php if (is_adminuser()) { ?>
account: {
title: 'Account',
title: 'Owner',
width: '8%',
display: displayContent('account'),
options: function(data) {
@ -471,6 +474,75 @@ $(document).ready(function () {
return $img;
}
},
<?php if (is_adminuser()) { ?>
permissions: {
title: 'Permissions',
width: '10%',
create: false,
edit: false,
display: function(data) {
var $img = $('<img class="list" src="img/list.png" title="Permissions" />');
$img.click(function () {
$('#SlaveZones').jtable('openChildTable',
$img.closest('tr'), {
title: 'Permissions for ' + data.record.name,
openChildAsAccordion: true,
actions: {
listAction: 'permissions.php?action=list&zoneid=' + data.record.id,
createAction: 'permissions.php?action=add&zoneid=' + data.record.id,
updateAction: 'permissions.php?action=update&zoneid=' + data.record.id,
deleteAction: 'permissions.php?action=remove&zoneid=' + data.record.id
},
fields: {
id: {
key: true,
type: 'hidden'
},
type: {
title: 'Type',
inputClass: "permissionstype",
options: {
'user': 'User',
'group': 'Group'
},
create: true,
edit: false
},
value: {
title: 'Name',
inputClass: "usergrouplist",
display: displayContent('value'),
create: true,
edit: false
},
permissions: {
title: 'Permissions',
options: {
'0' : 'No permissions',
'1' : 'View Only',
'15' : 'Admin'
}
}
},
formCreated: function(event, dat) {
$( ".usergrouplist" ).autocomplete({
source: "permissions.php?action=autocomplete&type=" + $( ".permissionstype" ).val()
});
$( ".permissionstype" ).change(function() {
$( ".usergrouplist" ).val("");
$( ".usergrouplist" ).autocomplete({
source: "permissions.php?action=autocomplete&type=" + $( ".permissionstype" ).val()
});
});
}
}, function (data) {
data.childTable.jtable('load');
})
});
return $img;
}
},
<?php } ?>
exportzone: {
title: '',
width: '1%',
@ -515,12 +587,111 @@ $(document).ready(function () {
],
},
sorting: false,
selecting: true,
selectOnRowClick: true,
selectionChanged: function (data) {
var $selectedRows = $('#MasterZones').jtable('selectedRows');
$selectedRows.each(function () {
var zone = $(this).data('record');
openChildAsAccordion: true,
actions: {
listAction: 'zones.php?action=list',
<?php if (is_adminuser() or $allowzoneadd === TRUE) { ?>
createAction: 'zones.php?action=create',
deleteAction: 'zones.php?action=delete',
<?php } ?>
<?php if (is_adminuser()) { ?>
updateAction: 'zones.php?action=update'
<?php } ?>
},
fields: {
id: {
key: true,
type: 'hidden'
},
name: {
title: 'Domain',
width: '8%',
display: displayContent('name'),
edit: false,
inputClass: 'domain',
listClass: 'domain'
},
dnssec: {
title: 'DNSSEC',
width: '3%',
create: false,
edit: false,
display: displayDnssecIcon,
listClass: 'dnssec'
},
<?php if (is_adminuser()) { ?>
account: {
title: 'Owner',
width: '8%',
display: displayContent('account'),
options: function(data) {
return 'users.php?action=listoptions&e='+$epoch;
},
defaultValue: 'admin',
inputClass: 'account',
listClass: 'account'
},
<?php } ?>
kind: {
title: 'Type',
width: '20%',
display: displayContent('kind'),
options: {'Native': 'Native', 'Master': 'Master'},
defaultValue: '<?php echo $defaults['defaulttype']; ?>',
edit: false,
inputClass: 'kind',
listClass: 'kind'
},
template: {
title: 'Template',
options: <?php echo json_encode(user_template_names()); ?>,
list: false,
create: true,
edit: false,
inputClass: 'template'
},
nameserver: {
title: 'Nameservers',
create: true,
list: false,
edit: false,
input: function(data) {
var $template = data.form.find('#Edit-template');
var ns_form = '<?php foreach($defaults['ns'] as $ns) echo '<input type="text" name="nameserver[]" value="'.$ns.'" /><br />'; ?>';
var $elem = $('<div id="nameservers">' + ns_form + '</div>');
$template.change(function() {
$.get('zones.php?action=getformnameservers&template='+$template.val(), function(getdata) {
if (getdata != "") {
$("#nameservers").html(getdata);
} else {
$("#nameservers").html(ns_form);
}
});
});
return $elem;
},
inputClass: 'nameserver nameserver1'
},
serial: {
title: 'Serial',
width: '10%',
display: displayContent('serial'),
create: false,
edit: false,
inputClass: 'serial',
listClass: 'serial'
},
records: {
title: 'Records',
width: '10%',
paging: true,
pageSize: 20,
create: false,
edit: false,
display: function(data) {
var $img = $('<img class="list" src="img/list.png" title="Records" />');
$img.click(function () {
var zone = data.record;
$('#MasterZones').jtable('openChildTable',
$(this).closest('tr'), {
title: 'Records in ' + zone.name,
@ -710,102 +881,86 @@ $(document).ready(function () {
opentableTitle=opentable.find('.jtable-title-text').text();
data.childTable.jtable('load');
});
});
return $img;
}
},
<?php if (is_adminuser()) { ?>
permissions: {
title: 'Permissions',
width: '10%',
create: false,
edit: false,
display: function(data) {
var $img = $('<img class="list" src="img/list.png" title="Permissions" />');
$img.click(function () {
$('#MasterZones').jtable('openChildTable',
$img.closest('tr'), {
title: 'Permissions for ' + data.record.name,
openChildAsAccordion: true,
actions: {
listAction: 'zones.php?action=list',
<?php if (is_adminuser() or $allowzoneadd === TRUE) { ?>
createAction: 'zones.php?action=create',
deleteAction: 'zones.php?action=delete',
<?php } ?>
<?php if (is_adminuser()) { ?>
updateAction: 'zones.php?action=update'
<?php } ?>
listAction: 'permissions.php?action=list&zoneid=' + data.record.id,
createAction: 'permissions.php?action=add&zoneid=' + data.record.id,
updateAction: 'permissions.php?action=update&zoneid=' + data.record.id,
deleteAction: 'permissions.php?action=remove&zoneid=' + data.record.id
},
fields: {
id: {
key: true,
type: 'hidden'
},
name: {
title: 'Domain',
width: '8%',
display: displayContent('name'),
edit: false,
inputClass: 'domain',
listClass: 'domain'
type: {
title: 'Type',
inputClass: "permissionstype",
options: {
'user': 'User',
'group': 'Group'
},
dnssec: {
title: 'DNSSEC',
width: '3%',
create: false,
edit: false,
display: displayDnssecIcon,
listClass: 'dnssec'
create: true,
edit: false
},
<?php if (is_adminuser()) { ?>
account: {
title: 'Account',
width: '8%',
display: displayContent('account'),
options: function(data) {
return 'users.php?action=listoptions&e='+$epoch;
value: {
title: 'Name',
inputClass: "usergrouplist",
display: displayContent('value'),
create: true,
edit: false
},
defaultValue: 'admin',
inputClass: 'account',
listClass: 'account'
permissions: {
title: 'Permissions',
options: {
'0' : 'No permissions',
'1' : 'View Only',
<?php if($restrictediting) { ?>
'3' : 'Update normal records',
'7' : 'Update all records',
<?php } else { ?>
'7' : 'Update',
<?php } ?>
'15' : 'Admin'
}
}
},
formCreated: function(event, dat) {
$( ".usergrouplist" ).autocomplete({
source: "permissions.php?action=autocomplete&type=" + $( ".permissionstype" ).val()
});
$( ".permissionstype" ).change(function() {
$( ".usergrouplist" ).val("");
$( ".usergrouplist" ).autocomplete({
source: "permissions.php?action=autocomplete&type=" + $( ".permissionstype" ).val()
});
});
}
}, function (data) {
data.childTable.jtable('load');
})
});
return $img;
}
},
<?php } ?>
kind: {
title: 'Type',
width: '20%',
display: displayContent('kind'),
options: {'Native': 'Native', 'Master': 'Master'},
defaultValue: '<?php echo $defaults['defaulttype']; ?>',
edit: false,
inputClass: 'kind',
listClass: 'kind'
},
template: {
title: 'Template',
options: <?php echo json_encode(user_template_names()); ?>,
list: false,
create: true,
edit: false,
inputClass: 'template'
},
nameserver: {
title: 'Nameservers',
create: true,
list: false,
edit: false,
input: function(data) {
var $template = data.form.find('#Edit-template');
var ns_form = '<?php foreach($defaults['ns'] as $ns) echo '<input type="text" name="nameserver[]" value="'.$ns.'" /><br />'; ?>';
var $elem = $('<div id="nameservers">' + ns_form + '</div>');
$template.change(function() {
$.get('zones.php?action=getformnameservers&template='+$template.val(), function(getdata) {
if (getdata != "") {
$("#nameservers").html(getdata);
} else {
$("#nameservers").html(ns_form);
}
});
});
return $elem;
},
inputClass: 'nameserver nameserver1'
},
serial: {
title: 'Serial',
width: '10%',
display: displayContent('serial'),
create: false,
edit: false,
inputClass: 'serial',
listClass: 'serial'
},
exportzone: {
title: '',
width: '1%',
@ -832,7 +987,7 @@ $(document).ready(function () {
},
<?php if (is_adminuser()) { ?>
account: {
title: 'Account',
title: 'Owner',
options: function(data) {
return 'users.php?action=listoptions&e='+$epoch;
},
@ -900,8 +1055,15 @@ $(document).ready(function () {
title: 'Domain',
inputClass: 'destname'
},
copypermissions: {
title: 'Copy Permissions',
type: 'checkbox',
values: {'0': 'No', '1': 'Yes'},
defaultValue: 1,
inputClass: 'copypermissions'
},
account: {
title: 'Account',
title: 'Owner',
options: function(data) {
return 'users.php?action=listoptions&e='+$epoch;
},
@ -954,11 +1116,11 @@ $(document).ready(function () {
<?php if (is_adminuser()) { ?>
$('#logs').hide();
$('#Users').hide();
$('#users').hide();
$('#AboutMe').hide();
$('#aboutme').click(function () {
$('#logs').hide();
$('#Users').hide();
$('#users').hide();
$('#MasterZones').hide();
$('#SlaveZones').hide();
$('#AboutMe').show();
@ -969,17 +1131,18 @@ $(document).ready(function () {
$('#SlaveZones').hide();
$('#AboutMe').hide();
$('#Users').jtable('load');
$('#Users').show();
$('#Groups').jtable('load');
$('#users').show();
});
$('#zoneadmin').click(function () {
$('#logs').hide();
$('#Users').hide();
$('#users').hide();
$('#AboutMe').hide();
$('#MasterZones').show();
$('#SlaveZones').show();
});
$('#logadmin').click(function () {
$('#Users').hide();
$('#users').hide();
$('#AboutMe').hide();
$('#MasterZones').hide();
$('#SlaveZones').hide();
@ -1036,6 +1199,90 @@ $(document).ready(function () {
}
});
$('#Groups').jtable({
title: 'Groups',
paging: true,
pageSize: 20,
sorting: false,
openChildAsAccordion: true,
actions: {
listAction: 'groups.php?action=list',
createAction: 'groups.php?action=create',
deleteAction: 'groups.php?action=delete',
updateAction: 'groups.php?action=update'
},
messages: {
addNewRecord: 'Add new group',
deleteConfirmation: 'This group will be deleted. Are you sure?'
},
fields: {
id: {
key: true,
type: 'hidden'
},
name: {
width: '25%',
title: 'Group name',
display: displayContent('name'),
edit: true
},
desc: {
width: '70%',
title: 'Description',
display: displayContent('desc')
},
members: {
width: '5%',
title: 'Members',
sorting: false,
edit: false,
create: false,
display: function (data) {
var $img = $('<img class="list" src="img/list.png" title="Edit Members">');
$img.click(function() {
$('#Groups').jtable('openChildTable',
$img.closest('tr'), {
title: 'Members of ' + data.record.name,
messages: {
addNewRecord: 'Add group member',
deleteConfirmation: 'This user will be removed from the group. Are you sure?'
},
actions: {
listAction: 'groups.php?action=listmembers&groupid=' + data.record.id,
createAction: 'groups.php?action=addmember&groupid=' + data.record.id,
deleteAction: 'groups.php?action=removemember&groupid=' + data.record.id
},
fields: {
id: {
key: true,
type: 'hidden'
},
user: {
title: 'Username',
inputClass: "userlist",
display: displayContent('user')
}
},
formCreated: function(event, data) {
$( ".userlist" ).autocomplete({
source: "users.php?action=autocomplete"
});
}
}, function (data) { //opened handler
data.childTable.jtable('load');
});
});
return $img;
}
}
},
recordAdded: function() {
$epoch = getEpoch();
$("#MasterZones").jtable('reload');
$("#SlaveZones").jtable('reload');
}
});
$('#Logs').jtable({
title: 'Logs',
paging: true,

121
permissions.php Normal file
View file

@ -0,0 +1,121 @@
<?php
include_once('includes/config.inc.php');
include_once('includes/session.inc.php');
include_once('includes/misc.inc.php');
if (!is_csrf_safe()) {
header('Status: 403');
header('Location: ./index.php');
jtable_respond(null, 'error', "Authentication required");
}
$zoneid = isset($_GET['zoneid']) ? $_GET['zoneid'] : '';
if (!is_adminuser()) {
header('Status: 403');
jtable_respond(null, 'error', "You need admin privileges to get here");
}
if (!isset($_GET['action'])) {
header('Status: 400');
jtable_respond(null, 'error', 'No action given');
}
switch ($_GET['action']) {
case "list":
if ($zoneid != '') {
$permissions = get_zone_permissions($zoneid);
jtable_respond($permissions);
} else {
jtable_respond(null, 'error', 'Zone id required');
}
break;
case "add":
$type = isset($_POST['type']) ? $_POST['type'] : '';
$value = isset($_POST['value']) ? $_POST['value'] : '';
$permissions = isset($_POST['permissions']) ? $_POST['permissions'] : '';
$zone = isset($_GET['zoneid']) ? $_GET['zoneid'] : '';
if ($zoneid != '') {
if($type == 'user') {
if (user_exists($value)) {
$userid=get_user_id($value);
if(!is_null(user_permissions($zone,$userid))) {
jtable_respond(null, 'error', "User already has permissions set for this zone");
} elseif(!is_null($id=set_permissions($userid,null,$zone,$permissions))) {
$entry = array('id' => $id, 'type' => 'user', 'value' => $value, 'permissions' => $permissions);
jtable_respond($entry, 'single');
} else {
jtable_respond(null, 'error', "Failed to set permissions");
}
} else {
jtable_respond(null, 'error', "User doesn't exist");
}
} else {
if (group_exists($value)) {
$groupid=get_group_id($value);
if(!is_null(group_permissions($zone,$groupid))) {
jtable_respond(null, 'error', "Group already has permissions set for this zone");
} elseif(!is_null($id=set_permissions(null,$groupid,$zone,$permissions))) {
$entry = array('id' => $id, 'type' => 'group', 'value' => $value, 'permissions' => $permissions);
jtable_respond($entry, 'single');
} else {
jtable_respond(null, 'error', "Failed to set permissions");
}
} else {
jtable_respond(null, 'error', "Group doesn't exist");
}
}
} else {
jtable_respond(null, 'error', 'Zone not specified');
}
break;
case "remove":
$id = isset($_POST['id']) ? $_POST['id'] : '';
if ($id != '') {
if(remove_permissions($id)) {
jtable_respond(null, 'delete');
} else {
jtable_respond(null, 'error', "Failed to remove permissions");
}
} else {
jtable_respond(null, 'error', 'ID not specified');
}
break;
case "update":
$id = isset($_POST['id']) ? $_POST['id'] : '';
$permissions = isset($_POST['permissions']) ? intval($_POST['permissions']) : 0;
if ($id != '') {
if(update_permissions($id,$permissions)) {
$result = array('id' => $id, 'permissions' => $permissions);
jtable_respond($result, 'single');
} else {
jtable_respond(null, 'error', 'Failed to set permissions');
}
} else {
jtable_respond(null, 'error', 'ID not specified');
}
case "autocomplete":
$type = isset($_GET['type']) ? $_GET['type'] : '';
$term = isset($_GET['term']) ? $_GET['term'] : '';
if($type == 'user') {
$users=get_usernames_filtered($term);
print json_encode($users);
} else {
$groups=get_groups_filtered($term);
print json_encode($groups);
}
break;
default:
jtable_respond(null, 'error', 'Invalid action');
break;
}

View file

@ -38,6 +38,12 @@ case "listoptions":
jtable_respond($retusers, 'options');
break;
case "autocomplete":
$term = isset($_GET['term']) ? $_GET['term'] : '';
$users=get_usernames_filtered($term);
print json_encode($users);
break;
case "create":
$emailaddress = isset($_POST['emailaddress']) ? $_POST['emailaddress'] : '';
$isadmin = isset($_POST['isadmin']) ? $_POST['isadmin'] : '0';

View file

@ -97,7 +97,7 @@ function record_compare_content($a, $b) {
return 0;
}
function add_db_zone($zonename, $accountname) {
function add_db_zone($zonename, $accountname, $createuser = false) {
if (valid_user($accountname) === false) {
jtable_respond(null, 'error', "$accountname is not a valid username");
}
@ -105,7 +105,7 @@ function add_db_zone($zonename, $accountname) {
jtable_respond(null, 'error', "$zonename is not a valid zonename");
}
if (is_apiuser() && !user_exists($accountname)) {
if ((is_apiuser() || $createuser) && !user_exists($accountname)) {
add_user($accountname);
}
@ -152,10 +152,6 @@ function quote_content($content) {
return $content;
}
function check_account($zone) {
return is_adminuser() or ($zone->account === get_sess_user());
}
if (isset($_GET['action'])) {
$action = $_GET['action'];
} else {
@ -178,7 +174,11 @@ case "listslaves":
$zone->setAccount(get_zone_account($zone->name, 'admin'));
}
if (!check_account($zone))
if(is_null(get_zone_id($zone->name))) {
add_db_zone($zone->name, $zone->account, true);
}
if (!check_permissions($zone->id,PERM_VIEW))
continue;
if ($action == "listslaves" and $zone->kind == "Slave") {
@ -200,6 +200,10 @@ case "listrecords":
$zone->parse($zonedata);
$records = $zone->rrsets2records();
if (!check_permissions($zone->id,PERM_VIEW)) {
jtable_respond(null, 'error', "You are not permitted to list records for " . $zone->id);
break;
}
if(!empty($_POST['label'])) {
$records=array_filter($records,
function ($val) {
@ -248,6 +252,12 @@ case "listrecords":
case "delete":
$zone = $api->loadzone($_POST['id']);
if (!check_permissions($zone->id,PERM_ADMIN)) {
jtable_respond(null, 'error', "You are not permitted to delete " . $zone->id);
break;
}
$api->deletezone($_POST['id']);
delete_db_zone($zone['name']);
@ -262,13 +272,16 @@ case "create":
if (!is_adminuser() and $allowzoneadd !== true) {
jtable_respond(null, 'error', "You are not allowed to add zones");
break;
}
if (!_valid_label($zonename)) {
jtable_respond(null, 'error', "Please only use [a-z0-9_/.-]");
break;
}
if (!$zonename || !$zonekind) {
jtable_respond(null, 'error', "Not enough data");
break;
}
$zone = new Zone();
@ -351,10 +364,15 @@ case "update":
writelog("Set SOA-EDIT-API to ".$defaults['soa_edit_api']." for ",$zone->name);
$zoneaccount = isset($_POST['account']) ? $_POST['account'] : $zone->account;
if (!check_permissions($zone->id,PERM_ADMIN)) {
jtable_respond(null, 'error', "You are not permitted to update " . $zone->id);
break;
}
if ($zone->account !== $zoneaccount) {
if (!is_adminuser()) {
header("Status: 403 Access denied");
jtable_respond(null, 'error', "Can't change account");
jtable_respond(null, 'error', "Can't change owner");
} else {
add_db_zone($zone->name, $zoneaccount);
$zone->setAccount($zoneaccount);
@ -382,6 +400,18 @@ case "createrecord":
$type = $_POST['type'];
$content = $_POST['content'];
if (!check_permissions($zone->id,PERM_UPDATE)) {
jtable_respond(null, 'error', "You are not permitted to create records in " . $zone->id);
break;
}
if($restrictediting && $restrictedtypes[$type]) {
if (!check_permissions($zone->id,PERM_UPDATESPECIAL)) {
jtable_respond(null, 'error', "You are not permitted to create $type records in " . $zone->id);
break;
}
}
if ('' == $name) {
$name = $zone->name;
} elseif (string_ends_with($name, '.')) {
@ -425,6 +455,19 @@ case "editrecord":
$old_record = decode_record_id(isset($_POST['id']) ? $_POST['id'] : '');
$rrset = $zone->getRRSet($old_record['name'], $old_record['type']);
if (!check_permissions($zone->id,PERM_UPDATE)) {
jtable_respond(null, 'error', "You are not permitted to update records in " . $zone->id);
break;
}
if($restrictediting && $restrictedtypes[$old_record['type']]) {
if (!check_permissions($zone->id,PERM_UPDATESPECIAL)) {
jtable_respond(null, 'error', "You are not permitted to update " . $old_record['type'] . " records in " . $zone->id);
break;
}
}
$rrset->deleteRecord($old_record['content']);
$content = $_POST['content'];
@ -450,6 +493,19 @@ case "deleterecord":
$old_record = decode_record_id(isset($_POST['id']) ? $_POST['id'] : '');
$rrset = $zone->getRRSet($old_record['name'], $old_record['type']);
if (!check_permissions($zone->id,PERM_UPDATE)) {
jtable_respond(null, 'error', "You are not permitted to delete records from " . $zone->id);
break;
}
if($restrictediting && $restrictedtypes[$old_record['type']]) {
if (!check_permissions($zone->id,PERM_UPDATESPECIAL)) {
jtable_respond(null, 'error', "You are not permitted to delete " . $old_record['type'] . " records from " . $zone->id);
break;
}
}
$rrset->deleteRecord($old_record['content']);
$api->savezone($zone->export());
@ -466,6 +522,12 @@ case "export":
case "clone":
$name = $_POST['destname'];
$src = $_POST['sourcename'];
$copypermissions = $_POST['copypermissions'];
if (!is_adminuser() and $allowzoneadd !== true) {
jtable_respond(null, 'error', "You are not allowed to add zones");
break;
}
if (!string_ends_with($name, '.')) {
$name = $name.".";
@ -505,6 +567,10 @@ case "clone":
$zone = $api->savezone($srczone->export());
if($copypermissions==1) {
copy_permissions($src,$name);
}
writelog("Cloned zone $src into $name");
jtable_respond($zone, 'single');
break;