'error', 'cause' => 'auth-load' ) ); exit; } } else { print json_encode( array( 'response' => 'error', 'cause' => 'config-error' ) ); exit; } /*******************************/ function new_key( $hex = false ) { // Basically this is at the moment a slightly modified // version of generate_password() from user_functiions.php // The behaviour/output of this function is expected to change // so using generate_password() directly does not make sense... $length = 16; $string = ""; while ( strlen( $string ) < $length ) { if ( $hex ) $string .= substr(md5(rand().rand()), 0, $length+1); else { $string .= crypt( substr(sha1(rand()), 0, $length+1) ); $string = preg_replace( '/\W/', '', $string); } } return substr( $string, 1, $length ); } function simple_authfail() { print json_encode( array( 'response' => 'failed', 'cause' => 'unauthorized', 'description' => 'Not authorized') ); exit; } function token_auth( ) { global $_POST; // TODO: Part of ping/pong requirement. // Run a function to clear all authkeys older than 5 minutes. expire_authkeys(); if ( array_key_exists('session', $_POST ) && array_key_exists('auth_key', $_POST ) ) { if ( ! check_session($_POST['session'] ) ) simple_authfail(); if ( ! check_authkey($_POST['auth_key'] ) ) simple_authfail(); } else simple_authfail(); } function get_cookie_path () { $name = $_SERVER["SCRIPT_NAME"]; $file = basename($name); $path = preg_replace("/".$file."/", "", $name); return $path; } function check_authkey ( $key ) { // TODO: Make real, actual checks... if ( $key ) return true; return false; } function expire_authkeys() { global $config; // Force deletion of sessions that have expired keys. $query = sprintf("SELECT session, sessid FROM %s WHERE `last` < DATE_SUB( NOW(), INTERVAL %d MINUTE)", $config['sessionkeys_table'], $config['sessionkey_lifetime']); $result = sql_dbquery( $config['hermes_db'], $query ); while ( $row = @mysql_fetch_row( $result ) ) { remove_session( $row[0], $row[1] ); } $query = sprintf("DELETE FROM %s WHERE `last` < DATE_SUB( NOW(), INTERVAL %d MINUTE)", $config['sessionkeys_table'], $config['sessionkey_lifetime']); sql_dbexec( $config['hermes_db'], $query ); } function update_authkey ( $session, $authid ) { global $config; $key = substr(new_key(), 0, 8); expire_authkeys(); // TODO: Refresh cookie $remote = $_SERVER['REMOTE_ADDR']; $query = sprintf("INSERT INTO %s ( `sessid`, `session`, `authid`, `client`, `key`, `last` ) VALUES ( '%s', '%s', '%s', '%s', '%s', NOW() ) ON DUPLICATE KEY UPDATE `key` = '%s', `last` = NOW()", $config['sessionkeys_table'], session_id(), session_name(), sql_clean($authid), sql_clean($remote), sql_clean($key), sql_clean($key)); if ( ! sql_dbexec( $config['hermes_db'], $query ) ) { mysql_error(); } $_SESSION['kkey'] = $key; $_SESSION['when'] = time(); return $key; } function check_session ( $name ) { session_name( $name ); session_start(); if ( ! $_SESSION['authid'] ) { return clear_credentials($name); } if ( ! $_COOKIE['client_key'] ) { return clear_credentials($name); } $authid = $_SESSION['authid']; $type = $_SESSION['type']; $client_key = $_COOKIE['client_key']; $level = get_authorization( $type, $authid ); if ( $level == false ) { return clear_credentials($name); } $session_key = md5( $name . $authid ); if ( $client_key != $session_key ) { return clear_credentials($name); } // If we got this far, things are looking good. return true; } function set_credentials( $authid, $type ) { $name = new_key(true); session_name( $name ); session_start(); $_SESSION['authid'] = $authid; $_SESSION['type'] = $type; $client_key = md5( $name . $authid ); setcookie('client_key', $client_key, time()+180*60, get_cookie_path() ); return $name; } function clear_credentials($name) { global $config; setcookie('client_key', '', 0, get_cookie_path() ); remove_session($name); $_SESSION = array(); $query = sprintf("DELETE FROM %s WHERE `session` = '%s'", $config['sessionkeys_table'], sql_clean($name)); sql_dbexec( $config['hermes_db'], $query ); return false; } function remove_session ($name, $id = null ) { if ( $id == null ) { session_destroy(); setcookie($name, '', 0, "/"); return; } $current_session = session_name( ); $current_sessid = session_id( ); session_commit(); session_id( $id ); session_start(); setcookie( $name, '', 0, "/"); $_SESSION=array(); session_destroy(); if ( $current_session && $current_session != $name ) { session_id($current_sessid); session_start(); } } function add_apikey ( $host, $level ) { global $config; if ( !is_numeric($level) ) return false; $key = new_key(); // Try to add the new key to authorizations first. If this // fails, there will be the least amount of data to clean up ... if ( ! update_authorization( "key", $key, $level ) ) return false; $query = sprintf("INSERT INTO %s ( host, apikey ) VALUES ( '%s', '%s' )", $config['apikeys_table'], sql_clean($host), sql_clean($key)); if ( ! sql_dbexec( $config['hermes_db'], $query ) ) return false; return $key; } function remove_apikey( $key ) { global $config; if ( ! verify_apikey( $key, true ) ) return false; if ( ! remove_authorization( $key ) ) return false; $query = sprintf("DELETE FROM %s WHERE apikey = '%s'", $config['apikeys_table'], sql_clean($key) ); if ( ! sql_dbexec( $config['hermes_db'], $query ) ) return false; return true; } function verify_apikey( $key, $skip_hostcheck = false ) { global $config; $query = sprintf("SELECT host FROM %s WHERE apikey = '%s'", $config['apikeys_table'], sql_clean($key) ); $row = sql_dbquery_single( $config['hermes_db'], $query ); if (!$row) return false; $host = $row['host']; if ( $host && ( $skip_hostcheck ) ) return true; if ( $host == $_SERVER['REMOTE_ADDR'] ) return true; return false; } function list_apikeys () { global $config; $query = sprintf("SELECT k.apikey AS apikey, k.host AS host, a.access_level AS access_level FROM %s k INNER JOIN %s a ON k.apikey = a.authid WHERE a.type = 'key'", $config['apikeys_table'], $config['authorizations_table']); $list = array(); $result = sql_dbquery( $config['hermes_db'], $query); if ( ! $result ) return $list; while ( $row = @mysql_fetch_assoc( $result ) ) { array_push( $list, array( 'api_key' => $row['apikey'], 'host' => $row['host'], 'level' => authlevel_name( $row['access_level'] ) )); } return $list; } function list_authusers () { global $config; $query = sprintf("SELECT authid, access_level FROM %s WHERE type = 'user'", $config['authorizations_table']); $list = array(); $result = sql_dbquery( $config['hermes_db'], $query); if ( ! $result ) return $list; while ( $row = @mysql_fetch_assoc( $result ) ) { $username = $row['authid']; $user_data = authuser_getinfo( $username ); // TODO: Remove invalid users here? if ( ! $user_data ) continue; array_push( $list, array( 'user' => $username, 'name' => $user_data['name'], 'email' => $user_data['email'], 'level' => authlevel_name( $row['access_level'] ) )); } return $list; } function update_authorization( $type, $authid, $level ) { global $config; if ( !is_numeric($level) ) return false; if ( ($type != "key") && ($type != "user") ) return false; $query = sprintf("INSERT INTO %s ( authid, type, access_level ) VALUES ( '%s', '%s', %d ) ON DUPLICATE KEY UPDATE access_level=%d", $config['authorizations_table'], sql_clean($authid), $type, $level, $level); if ( ! sql_dbexec( $config['hermes_db'], $query ) ) return false; return true; } function remove_authorization( $authid ) { global $config; $query = sprintf("DELETE FROM %s WHERE authid = '%s'", $config['authorizations_table'], sql_clean($authid) ); //print $query . "\n\n"; if ( ! sql_dbexec( $config['hermes_db'], $query ) ) return false; return true; } function get_authorization( $type, $authid ) { global $config; // If API-key is used, but key fails verification, write is impossible. if ( ( $type == "key" ) && ( ! verify_apikey( $authid, true ) ) ) return false; // If User-login is used, but backend is unable to provide info, fail. if ( ( $type == "user" ) && ( ! authuser_getinfo( $authid ) ) ) return false; // The only types of access control supported are "user" or "key". if ( ($type != "user" ) && ($type != "key") ) return false; $query = sprintf("SELECT access_level FROM %s WHERE authid = '%s'", $config['authorizations_table'], sql_clean($authid) ); $row = sql_dbquery_single( $config['hermes_db'], $query ); if (!$row) return false; $level = $row['access_level']; return $level; } function can_write ( ) { // Stub, to be called on any API nodes that write data in the DB. $authid = $_SESSION['authid']; $type = $_SESSION['type']; $level = get_authorization( $type, $authid ); if ( $level >= authlevel_value('read_write') ) return $level; else return false; } ?>