for more details. * * Copyright 2007-2010 Rejo Zenger * Copyright 2010-2017 Poweradmin Development Team * * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ /** * Script that handles requests to update DNS records, required for clients * with dynamic ip addresses * * @package Poweradmin * @copyright 2007-2010 Rejo Zenger * @copyright 2010-2016 Poweradmin Development Team * @license http://opensource.org/licenses/GPL-3.0 GPL */ require('inc/config.inc.php'); require('inc/database.inc.php'); require('inc/record.inc.php'); $db = dbConnect(); /** Make sql query safe * * @param mixed $value Unsafe Value * * @return mixed $value Safe Value */ function safe($value) { global $db, $db_type; if ($db_type == 'mysql' || $db_type == 'sqlite') { $value = $db->quote($value, 'text'); $value = substr($value, 1, -1); // remove quotes } elseif ($db_type == 'pgsql') { $value = pg_escape_string($value); } else { return status_exit('baddbtype'); } return $value; } /** Get exit status message * * Print verbose status message for request * * @param string $status Short status message * * @return boolean false */ function status_exit($status) { $verbose_codes = array( 'badagent' => 'Your user agent is not valid.', 'badauth' => 'No username available.', 'badauth2' => 'Invalid username or password. Authentication failed.', 'notfqdn' => 'The hostname you specified was not valid.', 'dnserr' => 'A DNS error has occurred on our end. We apologize for any inconvenience.', '!yours' => 'The specified hostname does not belong to you.', 'nohost' => 'The specified hostname does not exist.', 'good' => 'Your hostname has been updated.', '911' => 'A critical error has occurred on our end. We apologize for any inconvenience.', 'nochg' => 'This update was identical to your last update, so no changes were made to your hostname configuration.', 'baddbtype' => 'Unsupported database type', ); if (isset($_REQUEST['verbose'])) { $pieces = preg_split('/\s/', $status); $status = $verbose_codes[$pieces[0]]; } echo "$status\n"; return false; } /** Check whether the given address is an IP address * * @param string $ip Given IP address * * @return string A if IPv4, AAAA if IPv6 or 0 if invalid */ function valid_ip_address($ip) { if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { $value = 'A'; } elseif (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { $value = 'AAAA'; } else { $value = 0; } return $value; } if (!(isset($_SERVER)) && !$_SERVER['HTTP_USER_AGENT']) { return status_exit('badagent'); } // Grab username & password based on HTTP auth, alternatively the query string if (isset($_SERVER['PHP_AUTH_USER'])) { $auth_username = $_SERVER['PHP_AUTH_USER']; } elseif (isset($_REQUEST['username'])) { $auth_username = $_REQUEST['username']; } if (isset($_SERVER['PHP_AUTH_PW'])) { $auth_password = $_SERVER['PHP_AUTH_PW']; } elseif (isset($_REQUEST['password'])) { $auth_password = $_REQUEST['password']; } // If we still don't have a username, throw up if (!isset($auth_username)) { header('WWW-Authenticate: Basic realm="DNS Update"'); header('HTTP/1.0 401 Unauthorized'); return status_exit('badauth'); } $username = safe($auth_username); // FIXME: supports only md5 hashes $password = md5(safe($auth_password)); $hostname = safe($_REQUEST['hostname']); // Grab IP to use $given_ip = ""; $given_ip6 = ""; if (!empty($_REQUEST['myip'])) { $given_ip = $_REQUEST['myip']; } elseif (!empty($_REQUEST['ip'])) { $given_ip = $_REQUEST['ip']; } if (!empty($_REQUEST['myip6'])) { $given_ip6 = $_REQUEST['myip6']; } elseif (!empty($_REQUEST['ip6'])) { $given_ip6 = $_REQUEST['ip6']; } if (valid_ip_address($given_ip) === 'AAAA') { $given_ip6 = $given_ip; } // Look for tag to grab the IP we coming from if (($given_ip6 == "whatismyip") && (valid_ip_address($_SERVER['REMOTE_ADDR']) === 'AAAA')) { $given_ip6 = $_SERVER['REMOTE_ADDR']; } if (($given_ip == "whatismyip") && (valid_ip_address($_SERVER['REMOTE_ADDR']) === 'A')) { $given_ip = $_SERVER['REMOTE_ADDR']; } elseif (($given_ip == "whatismyip") && (valid_ip_address($_SERVER['REMOTE_ADDR']) === 'AAAA') && (!(valid_ip_address($given_ip6) === 'AAAA'))) { $given_ip6 = $_SERVER['REMOTE_ADDR']; } // Finally get safe version of the IP $ip = safe($given_ip); $ip6 = safe($given_ip6); // Check its ok... if ((!valid_ip_address($ip)) && (!valid_ip_address($ip6))) { return status_exit('dnserr'); } if (!strlen($hostname)) { return status_exit('notfqdn'); } $user_query = " SELECT users.id FROM users, perm_templ, perm_templ_items, perm_items WHERE users.username = '$username' AND users.password = '$password' AND users.active = 1 AND perm_templ.id = users.perm_templ AND perm_templ_items.templ_id = perm_templ.id AND perm_items.id = perm_templ_items.perm_id AND ( perm_items.name = 'zone_content_edit_own' OR perm_items.name = 'zone_content_edit_others' ) "; $user = $db->queryRow($user_query); if (!$user) { return status_exit('badauth2'); } $zones_query = "SELECT domain_id FROM zones WHERE owner='{$user["id"]}'"; $zones_result = $db->query($zones_query); $was_updated = false; $no_update_necessary = false; while ($zone = $zones_result->fetchRow()) { $zone_updated = false; $name_query = "SELECT name, type, content FROM records WHERE domain_id='{$zone["domain_id"]}' and (type = 'A' OR type = 'AAAA') "; $result = $db->query($name_query); while ($record = $result->fetchRow()) { if ($hostname == $record['name']) { if (($record['type'] == 'A') && (valid_ip_address($ip) === 'A')) { if ($ip == $record['content']) { $no_update_necessary = true; } else { $update_query = "UPDATE records SET content ='{$ip}' where name='{$record["name"]}' and type='A'"; $update_result = $db->query($update_query); $zone_updated = true; $was_updated = true; } } elseif (($record['type'] == 'AAAA') && (valid_ip_address($ip6) === 'AAAA')) { if ($ip6 == $record['content']) { $no_update_necessary = true; } else { $update_query = "UPDATE records SET content ='{$ip6}' where name='{$record["name"]}' and type='AAAA'"; $update_result = $db->query($update_query); $zone_updated = true; $was_updated = true; } } } } if ($zone_updated) { update_soa_serial($zone['domain_id']); } } return (($was_updated || $no_update_necessary) ? status_exit('good') : status_exit('!yours'));