<?php
// DON'T put whitespace at the beginning or end of this file!!!
// Debugging: lets print what's in $_REQUEST
printmsg("Get/Post vars:", 3);
foreach (array_keys($_REQUEST) as $key) printmsg("Name: $key Value: $_REQUEST[$key]", 3);
// MP: moved this stuff to config.inc.php
// Include the basic database functions
//require_once($conf['inc_functions_db']);
// (Re)Connect to the DB now.
//global $onadb;
//$onadb = db_pconnect('mysqlt', $conf['mysql_context']);
// Include functions that replace the default session handler with one that uses MySQL as a backend
//require_once($conf['inc_db_sessions']);
// Include the GUI functions
//require_once($conf['inc_functions_gui']);
// Start the session handler (this calls a function defined below in this file)
//startSession();
// Include the GUI functions
//require_once($base.'/include/functions_auth.inc.php');
/***************/
/* Functions */
/***************/
///////////////////////////////////////////////////////////////////////
// Function: printmsg (string $msg, int $level)
//
// $msg = Message you would like to display
// $level = debug level that has to be reached before this message would be displayed.
//
// Prints a message if $level is less than or equal to global debug value
//
///////////////////////////////////////////////////////////////////////
function printmsg($msg="",$debugLevel=0) {
global $conf, $self;
if ($debugLevel <= $conf['debug'] and isset($msg)) {
// Get a username or "anonymous"
if (isset($_SESSION['ona']['auth']['user']['username']))
$username = $_SESSION['ona']['auth']['user']['username'];
else
$username = "anonymous";
// Print to a log file if needed
if ($conf['logfile'])
ona_logmsg($msg);
// log level 0 entries to database table
if ($conf['log_to_db'] and $debugLevel == 0) {
global $onadb;
// MP TODO: log using tia64n
list($status, $rows) = db_insert_record($onadb, 'ona_logs', array('username' => $username, 'remote_addr' => $_SERVER['REMOTE_ADDR'], 'message' => $msg,'context_name' => $self['context_name']));
}
// Print to syslogd if needed
if ($conf['syslog']) {
// MP: fix this up so it uses openlog and allows the user to set the facility?
syslog(LOG_INFO, "{$username}@{$_SERVER['REMOTE_ADDR']}: $msg");
}
// Print to stdout (i.e. the web page) if needed
if ($conf['stdout']) {
if ($self['nohtml'] == 1)
echo $msg . "\n";
else {
$msg = htmlentities($msg, ENT_QUOTES, $conf['php_charset']);
echo "<b>[$debugLevel]</b>:<font style=\"
font-size:12px;
color:crimson;
background-color:yellow;
\">
$msg
</font><b></b><br>\n";
}
}
}
}
///////////////////////////////////////////////////////////////////////
// Function: logmsg(string $message, string $logfile)
//
// Write $message into $logfile.
// $logfile is optional and will use a default specified below.
//
// $message = the message to be logged to disk
// $logfile = the file we should log it to
//
//
///////////////////////////////////////////////////////////////////////
function ona_logmsg($message, $logfile="") {
global $conf, $self;
// Do a little input validation
if (!isset($message) or $message == "") {
return("Can't log a blank line you idiot!");
}
// Get logfile from $conf if it wasn't specified
if (!$logfile) {
$logfile = $conf['logfile'];
}
// Open the file
$file = fopen($logfile, "a+");
if (!$file) {
return(1);
}
// Get the hostname (and a few other things we don't use)
// After this we can reference $uname['nodename'] which will have our hostname
$uname['nodename'] = "UNKNOWN_SVR_NAME";
if (function_exists('posix_uname')) {
$uname = posix_uname();
}
// Get a username or "anonymous"
if (isset($_SESSION['ona']['auth']['user']['username'])) {
$username = $_SESSION['ona']['auth']['user']['username'];
}
else {
$username = "anonymous";
}
// Build the exact line we want to write to the file
$logdata = date("M j G:i:s ") . "{$uname['nodename']} {$username}@{$_SERVER['REMOTE_ADDR']}: [{$self['context_name']}] {$message}\n";
// Write the line to the file
if (!fwrite($file, $logdata)) {
return(1);
}
// Close the file
fclose($file);
// Return 0 for no errors, or >0 if there was any errors
return(0);
}
///////////////////////////////////////////////////////////////////////
// Function: strsize (string $string)
//
// Returns a nicely formatted string of the size of the string $string
//
///////////////////////////////////////////////////////////////////////
function strsize($string) {
$tmp = array("B", "KB", "MB", "GB", "TB", "PB");
$pos = 0;
$size = strlen($string);
while ($size >= 1024) {
$size /= 1024;
$pos++;
}
return round($size,2)." ".$tmp[$pos];
}
///////////////////////////////////////////////////////////////////////
// Function: truncate (string $msg, int length)
//
// $msg = Message you would like to (possibly) truncate
// $length = Max length you want $msg to be
//
// Returns $msg with a maximum length of $length.
//
///////////////////////////////////////////////////////////////////////
function truncate($msg="",$length=0) {
global $conf;
if ($length > 0)
$msg = (mb_strlen($msg) < $length) ? $msg : mb_substr($msg,0,$length - 3) . "...";
return($msg);
}
///////////////////////////////////////////////////////////////////////
// Function: fix_input(string $in)
//
// Basically does a "strip_slashes()" if magic quotes are turned on.
// Returns the fixed input.
///////////////////////////////////////////////////////////////////////
function fix_input($string) {
// Stripslashes from $_REQUEST input if magic_quotes is enabled -
// we quote everything properly in this code :)
if (get_magic_quotes_gpc())
$string = stripslashes($string);
return($string);
}
/**
* convert line ending to unix format
*
* @see formText() for 2crlf conversion
* @author Andreas Gohr <hide@address.com>
*/
function cleanText($text){
$text = preg_replace("/(\015\012)|(\015)/","\012",$text);
return $text;
}
/**
* Simple function to replicate PHP 5 behaviour of microtime()
*/
function microtime_float() {
list($usec, $sec) = explode(" ", microtime());
return ((float)$usec + (float)$sec);
}
///////////////////////////////////////////////////////////////////////
// Function: ip_mangle($ip, [$format])
//
// $input is the ip address in either numeric or dotted format
// $format is the format the ip address will be returned in:
// 1 or numeric: 170666057
// 2 or dotted: 10.44.40.73
// 3 or cidr: 24 (or /24) (for netmasks only)
// 4 or binary: 1010101010101010101010101010101010101010
//
// Options 5,6,7 are only supported by GMP module
// 5 or bin128: 1010101010101010101010101010101010101010... (128 bits)
// 6 or ipv6: FE80:0000:0000:0000:0202:B3FF:FE1E:8329
// 7 or ipv6gz: FE80::202:B3FF:FE1E:8329 or
// ::C000:280 or
// ::ffff:C000:280
//
//
//
// 8 or flip: 10.1.2.3 changes to 3.2.1.10
//
//
// Wrapper around the two versions of ip_mangle. one with GMP one without.
// The non GMP version is not ipv6 compatible
//
// Example:
// print "IP is: " . ip_mangle(170666057)
///////////////////////////////////////////////////////////////////////
function ip_mangle($ip="", $format="default") {
global $self;
if (function_exists('gmp_init')) {
return(ip_mangle_gmp($ip, $format));
}
else {
printmsg("INFO => Falling back to non GMP enabled ip_mangle function",5);
return(ip_mangle_no_gmp($ip, $format));
}
}
///////////////////////////////////////////////////////////////////////
// Function: ip_mangle($ip, [$format])
//
// $input is the ip address in either numeric or dotted format
// $format is the format the ip address will be returned in:
// 1 or numeric: 170666057
// 2 or dotted: 10.44.40.73
// 3 or cidr: 24 (or /24) (for netmasks only)
// 4 or binary: 1010101010101010101010101010101010101010
// 8 or flip: 10.1.2.3 changes to 3.2.1.10
//
// Formats the input IP address into the format specified. When a
// format is not specified dotted format is returned unless you
// supply a dotted input, in which case numeric format (1) is returned.
// Returns -1 on any error and stores a message in $self['error']
//
// Example:
// print "IP is: " . ip_mangle(170666057)
///////////////////////////////////////////////////////////////////////
function ip_mangle_no_gmp($ip="", $format="default") {
global $self;
// Is input in dotted format (2)?
if (preg_match('/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/', $ip)) {
$ip = ip2long($ip);
if ($format == "default") { $format = 1; }
}
// Is it in CIDR format (3)?
else if (preg_match('/^\/?(\d{1,2})$/', $ip, $matches)) {
if (!($matches[1] >= 0 && $matches[1] <= 32)) {
$self['error'] = "ERROR => Invalid CIDR mask";
return(-1);
}
// So create a binary string of 1's and 0's and convert it to an int
$ip = bindec(str_pad(str_pad("", $matches[1], "1"), 32, "0"));
if ($format == "default") { $format = 2; }
}
// Is it in binary format (4)?
else if (preg_match('/^[01]{32}$/', $ip)) {
$ip = bindec($ip);
if ($format == "default") { $format = 2; }
}
// If it has a non-digit character, it's invalid.
else if (preg_match('/\D/', $ip)) {
$ip = -1;
}
// Then input must be in numeric format (1)
else {
// We flip it to dotted and back again to make sure it's a valid address
$ip = long2ip($ip);
$ip = ip2long($ip);
if ($format == "default") { $format = 2; }
}
// If the address wasn't valid return an error
if ($ip == -1) {
$self['error'] = "ERROR => Invalid IP address";
return(-1);
}
// Is output format 1 (numeric)?
if ($format == 1 or $format == 'numeric') {
return(sprintf("%u", $ip));
}
// Is output format 2 (dotted)?
else if ($format == 2 or $format == 'dotted') {
return(long2ip($ip));
}
// Is output format 3 (CIDR)?
else if ($format == 3 or $format == 'cidr') {
// Make sure the address is a valid mask - convert it to 1's and 0's,
// then make sure it's all 1's followed by all 0's.
$binary = str_pad(decbin($ip), 32, "0", STR_PAD_LEFT);
if (!(preg_match('/^1+0*$/', $binary))) {
$self['error'] = "ERROR => IP address specified is not a valid netmask";
return(-1);
}
// Return the number of 1's at the beginning of the binary representation of $ip
return(strlen(rtrim($binary,"0")));
}
// Is output format 4 (binary string)?
else if ($format == 4 or $format == 'binary') {
// Convert the integer to it's 32 bit binary representation
return(str_pad(decbin($ip), 32, "0", STR_PAD_LEFT));
}
// Is output format 8 (flipped IP string)?
else if ($format == 8 or $format == 'flip') {
$octet = explode('.',long2ip(sprintf("%s", $ip)));
return(sprintf("%s.%s.%s.%s",$octet[3],$octet[2],$octet[1],$octet[0]));
}
else {
$self['error'] = "ERROR => ip_mangle() Invalid IP address format specified!";
return(-1);
}
}
///////////////////////////////////////////////////////////////////////
// Function: ip_mangle($ip, [$format])
//
// $input is the ip address in either numeric or dotted format
// $format is the format the ip address will be returned in:
// 1 or numeric: 170666057
// 2 or dotted: 10.44.40.73
// 3 or cidr: 24 (or /24) (for netmasks only)
// 4 or binary: 1010101010101010101010101010101010101010 (32 bits)
// 5 or bin128: 1010101010101010101010101010101010101010... (128 bits)
// 6 or ipv6: FE80:0000:0000:0000:0202:B3FF:FE1E:8329
// 7 or ipv6gz: FE80::202:B3FF:FE1E:8329 or
// ::C000:280 or
// ::ffff:C000:280
// 8 or flip: 10.1.2.3 changes to 3.2.1.10
//
// (currently unsupported for input or output) 0:0:0:0:0:0:192.0.2.128
// (currently unsupported for input or output) ::ffff:192.0.2.128
// (currently unsupported for input or output) ::192.0.2.128
//
// Formats the input IP address into the format specified. When a
// format is not specified dotted format is returned unless you
// supply a dotted input, in which case numeric format (1) is returned.
// Returns -1 on any error and stores a message in $self['error']
//
// Example:
// print "IP is: " . ip_mangle(170666057)
///////////////////////////////////////////////////////////////////////
function ip_mangle_gmp($ip="", $format="default") {
// is_ipv4 returns TRUE if $inp can be represented as an IPv4 address
// FALSE if $inp cannot be represented as an IPv4 address (e.g. IPv6)
// Note: $inp is a 'gmp' resource, created by 'gmp_init()'.
if(!function_exists("is_ipv4")) {
function is_ipv4($inp) {
if(gmp_cmp(gmp_init("0xffffffff"), $inp) >= 0)
return TRUE;
return FALSE;
}
}
// Split a string into an array, each element of length $length characters.
// This function doesn't exist in PHP < 5.0.0.
if (!function_exists("str_split")) {
function str_split($str,$length = 1) {
if ($length < 1) return false;
$strlen = strlen($str);
$ret = array();
for ($i = 0; $i < $strlen; $i += $length) {
$ret[] = substr($str,$i,$length);
}
return $ret;
}
}
// Converts an ipv6 formatted input string to a GMP resource
if (!function_exists("ip2gmp6")) {
function ip2gmp6($ip) {
// Expand '::' to zero stanzas
if (substr_count($ip, '::'))
$ip = str_replace('::',
str_repeat(':0000', 8-substr_count($ip, ':')) . ':', $ip);
$ip = explode(':', $ip) ;
$r_ip = '';
// Insert any missing leading zeros in each stanza.
foreach ($ip as $v)
$r_ip .= str_pad($v, 4, 0, STR_PAD_LEFT) ;
return (gmp_init($r_ip, 16));
}
}
// When given an uncompressed IPv6 address string of the form
// 0000:1111:2222:3333:4444:5555:6666:7777:8888, this
// will return a 'compressed' IPv6 address string. It replaces the
// longest consecutive sequence of "0000" stanzas with double
// colons ("::") and strips any leading zeros in each stanza.
//
// For example, input string fe80:0000:0000:0000:00ff:0000:a033:05b7
// will be output as string fe80::ff:0:a033:5b7.
if (!function_exists("ipv6gz")) {
function ipv6gz($ip) {
$e = explode(':', $ip);
$e[] = "XXXX"; // add a sentinel value
$zeros = array("0000");
$result = array_intersect ($e, $zeros );
// $result now contains only the non-zero stanzas from $ip
if (sizeof($result) > 0) {
// Find the longest sequence of zero stanzas
$begin = $start = ""; $len = 0;
foreach($e as $key=>$val) {
if($val === "0000") {
if($begin === "") {
$begin = $key;
if ($start === "")
$start = $begin;
}
} else {
if($begin !== "") {
if($key-$begin > $len) {
$len = $key-$begin;
$start = $begin;
}
$begin = "";
}
}
}
array_pop($e); // remove the sentinel value
// Replace that sequence with '::', strip leading zeros, etc
$newip=array();
foreach($e as $key=>$val) {
if($start !== "" && $key > $start && $key < $start+$len) continue;
if($start !== "" && $key === $start)
$val = '';
else
$val = base_convert($val, 16, 16);
$newip[] = $val;
}
// Corner cases: (1) If the final stanza is compressed, add one more
// empty array element, so we will end with two colons, not just one.
// (2) If the whole string was zeros, then add another empty element.
// (3) If the beginning stanza is compressed, prepend an empty array
// element, _unless_ cases (1) and (2) were both true.
if($start+$len == 8) { $newip[] = ''; }
if($len == 8) { $newip[] = ''; }
if($start == 0 && $len < 8) { array_unshift($newip, ''); }
$ip = implode(':', $newip);
}
return $ip;
}
}
global $self;
// Is input in IPv4 dotted format (2)?
if (preg_match('/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/', $ip)) {
if($ip != long2ip(ip2long($ip))) {
$self['error'] = "ERROR => Invalid IPv4 address";
return(-1);
}
$ip = gmp_init(sprintf("%u", ip2long($ip)), 10);
if ($format == "default") { $format = "numeric"; }
}
// Is it in IPv4/IPv6 CIDR format (3)?
else if (preg_match('/^\/?(\d{1,3})$/', $ip, $matches)) {
if (!($matches[1] >= 0 && $matches[1] <= 128)) {
$self['error'] = "ERROR => Invalid CIDR mask";
return(-1);
}
// So create a binary string of 1's and 0's and convert it to an int
if($ip <= 32) { $cidr_bits = 32; }
else { $cidr_bits = 128; }
$ip = gmp_init(str_pad(str_pad("", $matches[1], "1"), $cidr_bits, "0"), 2);
if ($format == "default") {
// Default to IPv6 output if the input was IPv6, IPv4 otherwise
if (is_ipv4($ip))
$format = "dotted";
else
$format = "ipv6";
}
}
// Is it in 32-bit binary format (4)?
else if (preg_match('/^[01]{32}$/', $ip)) {
//$ip = bindec($ip);
$ip = gmp_init(strval($ip), 2);
if ($format == "default") { $format = "dotted"; }
}
// Is it in 128-bit binary format (5)?
else if (preg_match('/^[01]{128}$/', $ip)) {
$ip = gmp_init(strval($ip), 2);
if ($format == "default") { $format = "ipv6"; }
}
// Is it in ipv6 format (6)?
// This matches the 'full' uncompressed IPv6 format, the format without
// leading zeros in each stanza, and also 'compressed' IPv6 format, which
// substitutes '::' for multiple zero stanzas.
else if ( (substr_count($ip, '::') == 1 && substr_count($ip, ':::') == 0 &&
preg_match('/^:|([0-9A-F]{1,4}:){0,7}:|(:[0-9A-F]{1,4}){0,7}$/i', $ip)) or
preg_match('/^([0-9A-F]{1,4}:){7}([0-9A-F]{1,4})$/i', $ip)) {
$ip = ip2gmp6($ip);
if ($format == "default") { $format = "numeric"; }
}
// If at this point, it has a non-digit character, it's invalid.
else if (preg_match('/\D/', $ip)) {
$ip = -1;
}
// If we get here, then the input must be in numeric format (1)
else {
$ip = gmp_init(strval($ip), 10);
if ($format == "default") {
if(is_ipv4($ip))
$format = "dotted";
else
$format = "ipv6";
}
}
// If the address wasn't valid return an error --
// check for out-of-range values (< 0 or > 2**128)
if (gmp_cmp(gmp_init(-1), $ip) >= 0 or
gmp_cmp(gmp_pow("2", 128), $ip) <= 0) {
$self['error'] = "ERROR => Invalid IP address";
return(-1);
}
// Is output format 1 (numeric)?
if ($format == 1 or $format == 'numeric')
//return(sprintf("%u", $ip));
return(sprintf("%s", gmp_strval($ip, 10)));
// Is output format 2 (dotted)?
else if ($format == 2 or $format == 'dotted') {
if(!is_ipv4($ip)) {
$self['error'] = "ERROR => Invalid IPv4 address";
return(-1);
}
return(long2ip(sprintf("%s", gmp_strval($ip))));
}
// Is output format 3 (CIDR)?
else if ($format == 3 or $format == 'cidr') {
// Make sure the address is a valid mask - convert it to 1's and 0's,
// then make sure it's all 1's followed by all 0's.
if(is_ipv4($ip))
$cidr_bits = 32;
else
$cidr_bits = 128;
$binary = str_pad(gmp_strval($ip, 2), $cidr_bits, "0", STR_PAD_LEFT);
if (!(preg_match('/^1+0*$/', $binary))) {
$self['error'] = "ERROR => IP address specified is not a valid netmask";
return(-1);
}
// Return the number of 1's at the beginning of the binary representation of $ip
return(strlen(rtrim(gmp_strval($ip, 2), "0")));
}
// Is output format 4 (32-bit binary string)?
else if ($format == 4 or $format == 'binary') {
// Convert the integer to its 32-bit binary representation
return(str_pad(gmp_strval($ip, 2), 32, "0", STR_PAD_LEFT));
}
// Is output format 5 (128-bit binary string)?
else if ($format == 5 or $format == 'bin128') {
// Convert the number to its 128-bit binary representation
return(str_pad(gmp_strval($ip, 2), 128, "0", STR_PAD_LEFT));
}
// Is output format 6 (uncompressed IPv6 string)?
else if ($format == 6 or $format == 'ipv6') {
// Convert the number to 8x 16-bit hexidecimal stanzas.
return(implode(":", str_split(str_pad(gmp_strval($ip, 16), 32, "0", STR_PAD_LEFT), 4)));
}
// Is output format 7 (compressed IPv6 string)?
else if ($format == 7 or $format == 'ipv6gz') {
return(ipv6gz(implode(":", str_split(str_pad(gmp_strval($ip, 16), 32, "0", STR_PAD_LEFT), 4))));
}
// Is output format 8 (flipped IP string)?
else if ($format == 8 or $format == 'flip') {
if(!is_ipv4($ip)) {
$self['error'] = "ERROR => Invalid IPv4 address";
return(-1);
}
$octet = explode('.',long2ip(sprintf("%s", gmp_strval($ip))));
return(sprintf("%s.%s.%s.%s",$octet[3],$octet[2],$octet[1],$octet[0]));
}
else {
$self['error'] = "ERROR => ip_mangle() Invalid IP address format specified!";
return(-1);
}
}
///////////////////////////////////////////////////////////////////////
// Function: ipcalc_info($ip,$mask)
//
// Gathers various bits of IP info for use in an ipcalc tools/modules
// Returns an array of those bits of info.
//
// Example:
// $level = ipcalc_info($ip,$mask)
///////////////////////////////////////////////////////////////////////
function ipcalc_info($ip='', $mask='') {
global $conf, $self;
// MP: fix the fact that I"m not testing for the GMP module.. it will fail for ipv6 stuff
$retarray = array();
$retarray['in_ip'] = $ip;
$retarray['in_mask'] = $mask;
$retarray['mask_cidr'] = ip_mangle($retarray['in_mask'], 'cidr');
// Process the IP address
$retarray['ip_dotted'] = ip_mangle($retarray['in_ip'], dotted);
$retarray['ip_numeric'] = ip_mangle($retarray['in_ip'], numeric);
$retarray['ip_binary'] = ip_mangle($retarray['in_ip'], binary);
$retarray['ip_bin128'] = ip_mangle($retarray['in_ip'], bin128);
$retarray['ip_ipv6'] = ip_mangle($retarray['in_ip'], ipv6);
$retarray['ip_ipv6gz'] = ip_mangle($retarray['in_ip'], ipv6gz);
$retarray['ip_flip'] = ip_mangle($retarray['in_ip'], flip);
// Process the mask
$retarray['mask_dotted'] = ip_mangle($retarray['in_mask'], dotted);
$retarray['mask_numeric'] = ip_mangle($retarray['in_mask'], numeric);
$retarray['mask_binary'] = ip_mangle($retarray['in_mask'], binary);
$retarray['mask_bin128'] = ip_mangle($retarray['in_mask'], bin128);
$retarray['mask_ipv6'] = ip_mangle($retarray['in_mask'], ipv6);
$retarray['mask_ipv6gz'] = ip_mangle($retarray['in_mask'], ipv6gz);
$retarray['mask_flip'] = ip_mangle($retarray['in_mask'], flip);
// Invert the binary mask
$inverted = str_replace("0", "x", ip_mangle($retarray['in_mask'], binary));
$inverted = str_replace("1", "0", $inverted);
$inverted = str_replace("x", "1", $inverted);
$retarray['mask_bin_invert'] = $inverted;
$retarray['mask_dotted_invert'] = ip_mangle($inverted, dotted);
// Check boundaries
// This section checks that the IP address and mask are valid together.
// if the IP address does not fall on a proper boundary based on the provided mask
// we will return the 'truenet' that it would fall into.
$retarray['netboundary'] = 1;
$ip1 = $retarray['ip_binary'];
$ip2 = str_pad(substr($ip1, 0, $retarray['mask_cidr']), 32, '0');
$ip1 = ip_mangle($ip1, 'dotted');
$ip2 = ip_mangle($ip2, 'dotted');
$retarray['truenet'] = $ip2; // this is the subnet IP that your IP would fall in given the mask provided.
if ($ip1 != $ip2)
$retarray['netboundary'] = 0; // this means the IP passed in is NOT on a network boundary
// Get IP address counts
$total = (0xffffffff - ip_mangle($retarray['in_mask'], 'numeric')) + 1;
$usable = $total - 2;
$lastip = ip_mangle($ip2, numeric) - 1 + $total;
$retarray['ip_total'] = $total;
$retarray['ip_usable'] = $usable;
$retarray['ip_last'] = ip_mangle($lastip, dotted);
return($retarray);
}
///////////////////////////////////////////////////////////////////////
// Function: sanitize_security_level($int, $default)
//
// Takes a string and returns either the same number if it's a valid
// security level or $default if $int is empty.
// Will return an error if the level is greater than your current
// level as defined in the session.
// Returns -1 on any error and stores a message in $self['error']
//
// Example:
// $level = sanitize_security_level($level)
///////////////////////////////////////////////////////////////////////
function sanitize_security_level($string="", $default=-1) {
global $conf, $self;
if ($default == -1) $default = $conf['ona_lvl'];
if ($string == "") return($default);
// If it's valid, use it..
if (is_numeric($string) and $string <= 99) {
// Make sure it's not higher than the user's current level
if ($string <= $_SESSION['auth']['user']['level'])
return($string);
else {
$self['error'] = "ERROR => Security-level can't be higher than your own level!";
return(-1);
}
}
else {
$self['error'] = "ERROR => Invalid security-level specified!";
return(-1);
}
}
///////////////////////////////////////////////////////////////////////
// Function: sanitize_hostname($string)
//
// Takes a string and returns either the same string if it's a valid
// hostname or FALSE if not.
// Returns FALSE on any error and stores a message in $self['error']
//
// Example:
// $hostname = sanitize_hostname('hostname');
// if ($hostname) { do($something); }
///////////////////////////////////////////////////////////////////////
function sanitize_hostname($string="") {
global $self;
if ($string == "") { return(false); }
// The rules for hostnames:
// * Must start and end with an alphanumeric character
// * Must consist of the valid character set: a-z0-9.-_
// * Can not have more than one consecutive period
// * Length must range between 1 and 63 characters
// lets test out if it has a / in it to strip the view name portion
if (strstr($string,'/')) {
list($dnsview,$string) = explode('/', $string);
}
// We lower case all dns names
$string = strtolower($string);
// If it is a wildcard, let it through
if ($string == "*") { return($string); }
// If it's valid, use it..
if (preg_match('/^([a-z0-9_\*]([a-z0-9_\.\-]*))?[a-z0-9]$/', $string)) {
// Make sure it doesn't have more than one "." in a row
if (stristr($string, '..')) { return(false); }
// The syntax is ok, make sure it's not too long
if (strlen($string) > 63) { return(false); }
// It's ok! Return it.
return($string);
}
$self['error'] = "ERROR => Invalid hostname!";
return(false);
}
///////////////////////////////////////////////////////////////////////
// Function: mac_mangle($mac_address, [$format])
//
// $mac_address is a mac address in almost any format
// $format is the format the mac address will be returned in:
// 1 = non formatted raw form: A9B1CCD2392D
// 2 = typical format: A9:B1:CC:D2:39:2D
// 3 = cisco format: A9B1.CCD2.392D
//
// Formats the input MAC address into the format specified. When a
// format is not specified, and input is in format 2 or 3, format 1
// is returned -- if input is in format 1, format 2 is returned.
// Returns -1 on any error and stores a message in $self['error']
//
// Example:
// print "MAC is: " . mac_mangle('A9B1CCD2392D')
///////////////////////////////////////////////////////////////////////
function mac_mangle($input="", $format="default") {
global $self;
// Make sure we got input
if (!$input) { $self['error'] = "ERROR => MAC address was null"; return(-1); }
$matches = array();
// Is input in raw format? (1)
if (preg_match('/^([A-Fa-f0-9]{2})([A-Fa-f0-9]{2})([A-Fa-f0-9]{2})([A-Fa-f0-9]{2})([A-Fa-f0-9]{2})([A-Fa-f0-9]{2})$/', $input, $matches)) {
if ($format == "default") { $format = 2; }
}
// Is input in typical format? (2)
else if (preg_match('/^([A-Fa-f0-9]{2}).([A-Fa-f0-9]{2}).([A-Fa-f0-9]{2}).([A-Fa-f0-9]{2}).([A-Fa-f0-9]{2}).([A-Fa-f0-9]{2})$/', $input, $matches)) {
if ($format == "default") { $format = 1; }
}
// Is input in cisco format? (3)
else if (preg_match('/^([A-Fa-f0-9]{2})([A-Fa-f0-9]{2})\.([A-Fa-f0-9]{2})([A-Fa-f0-9]{2})\.([A-Fa-f0-9]{2})([A-Fa-f0-9]{2})$/', $input, $matches)) {
if ($format == "default") { $format = 1; }
}
else {
$self['error'] = "ERROR => Invalid MAC address";
return(-1);
}
// Output in format 1 (raw)?
if ($format == 1) {
return(strtoupper($matches[1] . $matches[2] . $matches[3] . $matches[4] . $matches[5] . $matches[6]));
}
// Output in format 2 (typical)?
else if ($format == 2) {
return(strtoupper($matches[1] . ':' . $matches[2] . ':' . $matches[3] . ':' . $matches[4] . ':' . $matches[5] . ':' . $matches[6]));
}
// Output in format 2 (cisco)?
else if ($format == 3) {
return(strtoupper($matches[1] . $matches[2] . '.' . $matches[3] . $matches[4] . '.' . $matches[5] . $matches[6]));
}
else {
$self['error'] = "ERROR => mac_mangle() Invalid MAC format specified!";
return(-1);
}
}
///////////////////////////////////////////////////////////////////////
// Function: string ip_complete($ip, [$filler=0])
//
// Completes a partial ip address with $filler and returns it.
// Returns -1 if the input string doesn't at least match /\d+\./
//
// $input is a partial or complete ip address in dotted format.
// $filler is the number to replace incomplete ip pieces with.
//
// Examples:
// $string = ip_complete('192.168', '0');
// $string == '192.168.0.0'
//
// $string = ip_complete('192.168.', '255');
// $string == '192.168.255.255'
//
// Note: If the IP address is invalid -1 is returned. So if the
// input string is something like '192.515' -1 will be returned.
///////////////////////////////////////////////////////////////////////
function ip_complete($ip='', $filler=0) {
global $self;
// Make sure it looks like a partial IP address
if (!preg_match('/^(\d+)\.(\d+)?\.?(\d+)?\.?(\d+)?$/', $ip, $matches)) { return(-1); }
// Build $ip with $filler
$ip = $matches[1];
if (is_numeric($matches[2])) { $ip .= ".{$matches[2]}"; } else { $ip .= ".{$filler}"; }
if (is_numeric($matches[3])) { $ip .= ".{$matches[3]}"; } else { $ip .= ".{$filler}"; }
if (is_numeric($matches[4])) { $ip .= ".{$matches[4]}"; } else { $ip .= ".{$filler}"; }
return(ip_mangle($ip, 'dotted'));
}
///////////////////////////////////////////////////////////////////////
// Function: date_mangle(int $timestamp | string $date)
//
// Returns int $timestamp as a MySQL formatted date string, or
// Returns string $date (a onadb formatted date) as an int timestamp.
// Returns -1 on error.
///////////////////////////////////////////////////////////////////////
function date_mangle($time=-1) {
// Do a little input validation
if ($time == -1) return(-1);
if (preg_match('/(\d\d\d\d)\D(\d\d)\D(\d\d)\s+(\d\d)\D(\d\d)\D(\d\d)/', $time, $parts))
$date = strtotime("{$parts[2]}/{$parts[3]}/{$parts[1]} {$parts[4]}:{$parts[5]}:{$parts[6]}");
else
$date = date('Y-m-d H:i:s', $time);
return($date);
}
///////////////////////////////////////////////////////////////////////
// Function: tzsecs($tz_offset)
//
// Returns the int $tz_offset * 60 * 60 .. effectivly converting the
// timezone offset to seconds.
///////////////////////////////////////////////////////////////////////
function tzsecs($tz_offset=0) {
return($tz_offset * 60 * 60);
}
///////////////////////////////////////////////////////////////////////
// Function: gmtime()
//
// Returns the current UTC time in seconds since 1970.
///////////////////////////////////////////////////////////////////////
function gmtime() {
$time = time() + (date('Z') * -1);
return(date('U', $time));
}
///////////////////////////////////////////////////////////////////////
// Function: validate_email($email_address)
//
// Returns the original string if it looks like a valid email address,
// false if not.
///////////////////////////////////////////////////////////////////////
function validate_email($input) {
if (preg_match('/^[A-Z0-9._%-]+@[A-Z0-9._%-]+\.[A-Z]{2,6}$/i', $input))
return $input;
return false;
}
///////////////////////////////////////////////////////////////////////
// Function: validate_url($url)
//
// Returns the original string if it looks like a valid url,
// false if not.
///////////////////////////////////////////////////////////////////////
function validate_url($input) {
$input = strtolower($input);
if (preg_match('/^\w+$/', $input))
return $input;
return false;
}
///////////////////////////////////////////////////////////////////////
// Function: validate_username($username)
//
// Returns the original string if it looks like a valid email address,
// false if not.
///////////////////////////////////////////////////////////////////////
function validate_username($input) {
if (preg_match('/^[a-z0-9\.\-_]+$/i', $input))
return $input;
return false;
}
///////////////////////////////////////////////////////////////////////
// Function: startSession()
//
// Call this function to start the PHP session
// This function should not be used in place of securePage()!
// This function does not make sure they have a valid username,
// call securePage() first.
//
// Returns 0 on success, 1 on failure.
//
///////////////////////////////////////////////////////////////////////
function startSession() {
global $conf;
// If the command line agent, dcm.pl, is making the request, don't really start a session.
if (preg_match('/console-module-interface/', $_SERVER['HTTP_USER_AGENT'])) {
// Pretend to log them in
if (preg_match('/unix_username=([^&]+?)(&|$)/', $_REQUEST['options'], $matches)) {
$_SESSION['ona']['auth']['user']['username'] = $matches[1];
}
return(1);
}
// Set the name of the cookie (nicer than default name)
session_name("ONA_SESSION_ID");
// Set cookie to expire at end of session
// secure cookie
if (isset($_SERVER['HTTPS']) && 'on' == $_SERVER['HTTPS']) {
session_set_cookie_params(0, '/', $_SERVER["SERVER_NAME"], 1);
}
// normal cookie
else {
session_set_cookie_params(0, '/');
}
// (Re)start the session
session_start();
// According to PHP.net comment this is a good thing to do:
// http://us2.php.net/manual/en/function.session-start.php
header("Cache-control: private");
// Display session variables
// if ($conf['debug'] >= 0) {
// print "Session Variables:<pre>";
// var_export($_SESSION);
// print "</pre>\n";
// }
return(0);
}
///////////////////////////////////////////////////////////////////////
// Function: securePage()
//
// Call this function at the top of each page that needs to be
// secure (i.e. it requires a user who is properly logged in)
//
// MP: not used currently.. login is built into the html_desktop
//
///////////////////////////////////////////////////////////////////////
function securePage() {
global $conf;
// If the sessionID is not present start the session (reading the
// users cookie and loading their settings from disk)
if ( ONA_SESSION_ID != "" ) startSession();
// Make sure their session is still active
if (!(isset($_SESSION['ona']['auth']['user']['username']))) {
//header("Location: {$https}{$baseURL}/login.php?expired=1");
exit();
}
return(0);
}
///////////////////////////////////////////////////////////////////////
// Function: loggedIn()
//
// Returns true if the user is authenticated, false if not
//
///////////////////////////////////////////////////////////////////////
function loggedIn() {
// Make sure their session is still active
if (isset($_SESSION['ona']['auth']['user']['username']))
return true;
return false;
}
//////////////////////////////////////////////////////////////////////////////
// Returns true if the current user has access to the requested resource,
// false if not.
//////////////////////////////////////////////////////////////////////////////
function auth($resource,$msg_level=1) {
if (!is_string($resource)) return false;
if (array_key_exists($resource, (array)$_SESSION['ona']['auth']['perms'])) {
printmsg("DEBUG => auth() User[{$_SESSION['ona']['auth']['user']['username']}] has the {$resource} permission",5);
return true;
}
printmsg("DEBUG => auth() User[{$_SESSION['ona']['auth']['user']['username']}] does not have the {$resource} permission",$msg_level);
return false;
}
//////////////////////////////////////////////////////////////////////////////
// Returns true if the current user has a "level" greater than or equal to
// the level passed into the function. Returns false if not.
//////////////////////////////////////////////////////////////////////////////
function authlvl($level) {
// FIXME: hack until we get auth stuff working:
printmsg("DEBUG => FIXME: authlvl() always returns true for now", 1);
return true;
if (!is_numeric($level)) return false;
if ($_SESSION['ona']['auth']['user']['level'] >= $level) {
printmsg("DEBUG => authlvl() {$_SESSION['ona']['auth']['user']['username']}'s level is >= {$level}",1);
return true;
}
printmsg("DEBUG => authlvl() {$_SESSION['ona']['auth']['user']['username']}'s level is not >= {$level}",1);
return false;
}
///////////////////////////////////////////////////////////////////////
// Function: load_module($name)
//
// Runs a require_once($filename) to load the module named $name
// Returns 0 on success, 1 on failure. On failure $self['error']
// will contain an error description.
// Note: $conf['dcm_module_dir'] must be defined!
//
// Example:
// load_module('my_module');
///////////////////////////////////////////////////////////////////////
function load_module($name='') {
global $conf, $self, $onadb;
if (!$name) {
$self['error'] = "ERROR => load_module() No module specified!";
return(1);
}
// If the module is already loaded, return success
if (function_exists($name)) { return(0); }
// Make sure we're connected to the DB
// require_once($conf['inc_functions_db']);
// Use cache if possible
if (!is_array($self['cache']['modules']) or !array_key_exists('get_module_list', $self['cache']['modules'])) {
// Get a list of the valid "modules" and their descriptions.
require_once($conf['dcm_module_dir'] . '/get_module_list.inc.php');
list($status, $self['cache']['modules']) = get_module_list('type=array');
}
// Make sure the user requested a valid "module"
if (!array_key_exists($name, $self['cache']['modules'])) {
// Otherwise print an error
$self['error'] = "ERROR => The requested module is not valid!";
return(1);
}
// Make sure the include file containing the function(s)/module(s) requested exists..
// We have to find out which file it's in.
list($status, $rows, $module) = db_get_record($onadb, 'dcm_module_list', array('name' => $name));
if ($status or $rows != 1) {
$self['error'] = 'ERROR => The specified module does not exist';
return(1);
}
$file = $conf['dcm_module_dir'] . '/' . $module['file'];
if (!is_file($file)) {
// Otherwise print an error
$self['error'] = "ERROR => The include file ({$file}) for the {$name} module doesn't exist!";
return(1);
}
// Include the file
// The file should define a function called generate_config() to which we pass a node-name,
// and receive a configuration file.
require_once($file);
// Test that the module function existed in the file we just loaded
if (!function_exists($name)) {
$self['error'] = "ERROR => The module function {$name} doesn't exist in file: {$file}";
return(1);
}
return(0);
}
///////////////////////////////////////////////////////////////////////
// Function: run_module(string $module, string or array $module_options, $transaction=1)
//
// Runs the specified module and returns the status and output
// of the specified module.
//
// Input Values:
// $module = the name of the module to run.
// $options = an array of key => value pairs to pass to the module,
// or an already formatted string of the key => value
// pairs.
// $transaction = set to 0 or false to disable transaction code.
//
// Return Values:
// Returns a two part array: array($status, $output)
// $status = exit status of the specified module, generally 0 on
// success and non-zero on error.
// $output = textual output of the specified module. This can
// occasionally be an error message generated by this
// function itself.
//
// Example:
// list($status, $text) = run_module('alias_del', array('alias' => 'time01'));
///////////////////////////////////////////////////////////////////////
function run_module($module='', $options='', $transaction=1) {
global $conf, $self, $onadb;
// Build the options array string from $options_string if we need to
// This is only used for logging! If $options_string is an array it
// is passed untouched to the module.
$options_string = $options;
if (is_array($options)) {
$options_string = '';
$and = '';
foreach (array_keys($options) as $key) {
// Quote any "special" characters in the value.
// Specifically the '=' and '&' characters need to be escaped.
$options[$key] = str_replace(array('=', '&'), array('\=', '\&'), $options[$key]);
// If the key has no value or it is the javascript key, dont print it.
if (($options[$key] != "") and ($key != 'js')) {
$options_string .= "{$and}{$key}={$options[$key]}";
$and = '&';
}
}
}
// get the options as an array so we can look for logging info
$local_options = parse_options($options);
// If the user passes in an option called 'module_loglevel' then use it as the run module output level
// otherwise default it to 1 so it will print out as normal.
$log_level = 1;
if ($local_options['module_loglevel']) {
$log_level = $local_options['module_loglevel'];
}
// Remove config info as it can be huge and could have sensitive info in it.
// This could cause issues since I"m doing & as an anchor at the end. see how it goes.
// The module that is called could also display this information depending on debug level
$options_string = preg_replace("/config=.*&/", '', $options_string);
printmsg("INFO => Running module: {$module} options: {$options_string}", $log_level);
// Load the module
if (load_module($module)) { return(array(1, $self['error'] . "\n")); }
// Start an DB transaction (If the database supports it)
if ($transaction) $has_trans = $onadb->BeginTrans();
if (!$has_trans) printmsg("WARNING => Transactions support not available on this database, this can cause problems!", 1);
// If begintrans worked and we support transactions, do the smarter "starttrans" function
if ($has_trans) {
printmsg("DEBUG => Commiting transaction", 2);
$onadb->StartTrans();
}
// Start a timer so we can display moudle run time if debugging is enabled
$start_time = microtime_float();
// Run the function
list($status, $output) = $module($options);
// Stop the timer, and display how long it took
$stop_time = microtime_float();
printmsg("DEBUG => [Module_runtime] " . round(($stop_time - $start_time), 2) . " seconds -- [Total_SQL_Queries] " . $self['db_get_record_count'] . " -- [Module_exit_code] {$status}", 1);
// Either commit, or roll back the transaction
if ($transaction and $has_trans) {
if ($status != 0) {
printmsg("INFO => There was a module error, marking transaction for a Rollback!", 1);
//$onadb->RollbackTrans();
$onadb->FailTrans();
}
}
if ($has_trans) {
// If there was any sort of failure, make sure the status has incremented, this catches sub module output errors;
if ($onadb->HasFailedTrans()) $status = $status + 1;
printmsg("DEBUG => Commiting transaction", 2);
$onadb->CompleteTrans();
}
// Return the module's output
return(array($status, $output));
}
///////////////////////////////////////////////////////////////////////
// Function: parse_options($options)
//
// Takes an options string (passed to a dcm module) and returns
// an array of the key=value pairs included in it.
// Values are allowed to contain "=" and "&" characters as long as
// they are escaped with a "\" character.
//
// Example:
// $options = parse_options('key=value&key2=value2');
// if ($options['key'] == 'value') { Blah; }
///////////////////////////////////////////////////////////////////////
function parse_options($options="") {
// If it's already an array, just return it
if (is_array($options)) { return($options); }
$newoptions = array();
// Replace "\&" and "\=" with a random string
$replace_and = '{' . md5(mt_rand(100000, 900000)) . '}';
$replace_eq = '{' . md5(mt_rand(100000, 900000)) . '}';
$options = str_replace(
array('\&', '\='),
array($replace_and, $replace_eq),
$options
);
// Parse incoming options - split on '&'
foreach (split('&', $options) as $set) {
$pair = array('','');
// Now split on '='
$pair = split('=', $set);
// Replace previously escaped & and = characters with the real thing
$pair = str_replace(
array($replace_and, $replace_eq),
array('&', '='),
$pair);
// And set the key=value in $newoptions
$newoptions[$pair[0]] = $pair[1];
}
return($newoptions);
}
///////////////////////////////////////////////////////////////////////
// Function: sanitize_YN($string, $default)
//
// Takes a string and returns either 'Y' or 'N'. 'Y' is returned
// by default if $string is empty, unless $default is changed.
//
// Example:
// $string = sanitize_YN($string)
///////////////////////////////////////////////////////////////////////
function sanitize_YN($string="", $default="Y") {
if ($string == "")
return($default);
$string = strtolower($string);
if ($string == 'no' or $string == 'n' or $string == 'off' or $string == '0')
return('N');
else if ($string == 'yes' or $string == 'y' or $string == 'on' or $string == '1')
return('Y');
else
return($default);
}
/**
* show diff
*
* @author Andreas Gohr <hide@address.com>
* Modified by Brandon Zehm, pulled from dokuwiki.
* Requires DifferenceEngine.php from dokuwiki.
*
* Input: two strings
* Output: html
*/
function html_diff($old, $new, $oldname='', $newname='', $stdout=1) {
global $conf;
$html = '';
if(!($old and $new)) return('ERROR => Insufficient parameters passed to html_diff()!');
// Load diff code
require_once($conf['inc_diff']);
$df = new Diff(split("\n",htmlspecialchars($old)),
split("\n",htmlspecialchars($new)));
$tdf = new TableDiffFormatter();
$html .= <<<EOL
\n <table class="diff" width="100%">
<tr>
<td colspan="2" width="50%" class="diff-header">
{$oldname}
</td>
<td colspan="2" width="50%" class="diff-header">
{$newname}
</td>
</tr>
EOL;
$html .= $tdf->format($df) . "</table>";
if ($stdout)
echo $html;
else
return($html);
}
///////////////////////////////////////////////////////////////////////
// Function: format_array($array)
//
// Takes an array and returns a formatted string of the contents
// of the array for display. Usually used in the ona_xxx_display()
// functions to display database records.
//
// Example:
// $string = format_array($array)
///////////////////////////////////////////////////////////////////////
function format_array($array=array()) {
$text = '';
foreach (array_keys($array) as $key) {
// Make some data look pretty
if ($key == 'ip_addr') { $array[$key] = ip_mangle($array[$key], 'dotted'); }
else if ($key == 'ip_addr_start') { $array[$key] = ip_mangle($array[$key], 'dotted'); }
else if ($key == 'ip_addr_end') { $array[$key] = ip_mangle($array[$key], 'dotted'); }
else if ($key == 'ip_mask') { $array[$key] = ip_mangle($array[$key]); }
else if ($key == 'mac_addr') { $array[$key] = mac_mangle($array[$key]); if ($array[$key] == -1) $array[$key] = ''; }
else if ($key == 'host_id') {
list($status, $rows, $host) = ona_find_host($array[$key]);
if ($host['id'])
$array[$key] = str_pad($array[$key], 20) . strtolower("({$host['fqdn']})");
}
else if ($key == 'server_id') {
list($status, $rows, $server) = ona_get_server_record(array('id' => $array[$key]));
list($status, $rows, $host) = ona_find_host($server['host_id']);
if ($host['id'])
$array[$key] = str_pad($array[$key], 20) . strtolower("({$host['fqdn']})");
}
else if ($key == 'subnet_id') {
list($status, $rows, $subnet) = ona_get_subnet_record(array('id' => $array[$key]));
if ($subnet['id'])
$array[$key] = str_pad($array[$key], 20) . strtoupper("({$subnet['name']})");
}
else if ($key == 'domain_id' or $key == 'primary_dns_domain_id') {
list($status, $rows, $domain) = ona_get_domain_record(array('id' => $array[$key]));
$array[$key] = str_pad($array[$key], 20) . strtolower("({$domain['fqdn']})");
}
else if ($key == 'interface_id') {
list($status, $rows, $interface) = ona_get_interface_record(array('id' => $array[$key]));
$array[$key] = str_pad($array[$key], 20) . '(' .ip_mangle($interface['ip_addr'], 'dotted') . ')';
}
else if ($key == 'custom_attribute_type_id') {
list($status, $rows, $ca) = ona_get_custom_attribute_type_record(array('id' => $array[$key]));
if ($ca['id'])
$array[$key] = str_pad($array[$key], 20) . "({$ca['name']})";
}
// Align columns
if ($array[$key]) { $text .= str_pad(" {$key}", 30) . $array[$key] . "\n"; }
}
// Return a nice string :)
return($text);
}
?>