diff --git a/model/zone.php b/model/zone.php index da23521..313b738 100644 --- a/model/zone.php +++ b/model/zone.php @@ -712,13 +712,14 @@ public function process_bulk_json_rrset_update($update, $author = null) { $errors = array(); $revs_missing = array('A' => array(), 'AAAA' => array()); $revs_updated = array(); + $acting_user = $author ?? $active_user; $update = json_decode($update); if(is_null($update)) throw new InvalidJSON(json_last_error_msg()); if(!isset($update->actions) && !is_array($update->actions)) throw new BadData('No actions provided.'); if(isset($config['web']['force_change_comment']) && intval($config['web']['force_change_comment']) == 1 && empty($update->comment)) throw new BadData('A change comment must be provided.'); foreach($update->actions as $action) { try { - $changes[] = $this->process_rrset_action($action, $trash, $revs_missing, $revs_updated); + $changes[] = $this->process_rrset_action($action, $trash, $revs_missing, $revs_updated, $acting_user); } catch(RuntimeException $e) { $errors[] = $e->getMessage(); } @@ -810,7 +811,7 @@ private function process_rrset_action($update, &$trash, &$revs_missing, &$revs_u if(!$autocreate_ptr || $rr->disabled) { $rr->{'set-ptr'} = false; } else { - $rr->{'set-ptr'} = $zone_dir->check_reverse_record_zone($rrset->name, $rrset->type, $rr->content, $revs_missing, $revs_updated); + $rr->{'set-ptr'} = $zone_dir->check_reverse_record_zone($rrset->name, $rrset->type, $rr->content, $revs_missing, $revs_updated, $acting_user); } $rrset->add_resource_record($rr); } @@ -849,7 +850,7 @@ private function process_rrset_action($update, &$trash, &$revs_missing, &$revs_u if(!$autocreate_ptr || $rr->disabled) { $rr->{'set-ptr'} = false; } else { - $rr->{'set-ptr'} = $zone_dir->check_reverse_record_zone($rrset->name, $rrset->type, $rr->content, $revs_missing, $revs_updated); + $rr->{'set-ptr'} = $zone_dir->check_reverse_record_zone($rrset->name, $rrset->type, $rr->content, $revs_missing, $revs_updated, $acting_user); } $rrset->add_resource_record($rr); } diff --git a/model/zonedirectory.php b/model/zonedirectory.php index b4ea1d1..14ba35e 100644 --- a/model/zonedirectory.php +++ b/model/zonedirectory.php @@ -230,9 +230,12 @@ public function list_accounts() { * @param string $address that DNS record points to * @param array $revs_missing keep track of reverse zones that are missing * @param array $revs_updated keep track of reverse zones that will be updated + * @param User|null $acting_user The user on whose behalf this change is executed. If null, + * falls back to $active_user for backward-compatibility. */ - public function check_reverse_record_zone($name, $type, $address, &$revs_missing, &$revs_notify) { + public function check_reverse_record_zone($name, $type, $address, &$revs_missing, &$revs_notify, $acting_user = null) { global $zone_dir, $active_user; + $acting = $acting_user ?: $active_user; if($type == 'A') { $reverse_address = implode('.', array_reverse(explode('.', $address))).'.in-addr.arpa.'; @@ -248,6 +251,17 @@ public function check_reverse_record_zone($name, $type, $address, &$revs_missing do { try { $reverse_zone = $zone_dir->get_zone_by_name($reverse_zone_name); + // only allow if acting user can administer the reverse zone + $level = ($acting->admin ? 'administrator' : $acting->access_to($reverse_zone)); + if ($level !== 'administrator') { + // Don’t leak zone details if the user cannot actually access it + $alert = new UserAlert; + $alert->content = 'Reverse record could not be created for '.hesc($address).' in '.hesc(DNSZoneName::unqualify($reverse_zone->name)).' because the original requester does not have permission to modify this reverse zone. Not creating PTR record for '.hesc($name); + $alert->class = 'warning'; + $acting->add_alert($alert); + return false; + } + // See if a record already exists for this IP foreach($reverse_zone->list_resource_record_sets() as $rrset) { if($rrset->name == $reverse_address) {