reload_logout("'.$target.'")'; echo xml_from_array($results); } /* Redirect them to the login page */ if (AJAX_INCLUDE != '1') { header ('Location: ' . Config::get('web_path') . '/login.php'); } exit; } // logout /** * get_session_data * This takes a key and returns the raw data from the database, nothing to * see here move along people */ public static function get_session_data($key) { $key = Dba::escape($key); $sql = "SELECT * FROM `session` WHERE `id`='$key' AND `expire` > '" . time() . "'"; $db_results = Dba::query($sql); $results = Dba::fetch_assoc($db_results); if (!count($results)) { return false; } return $results; } // get_session_data /** * create_cookie * This is seperated into it's own function because of some flaws in specific * webservers *cough* IIS *cough* which prevent us from setting a cookie at the * same time as a header redirect. As such on view of a login a cookie is set with * the proper name */ public static function create_cookie() { /* Setup the cookie prefs before we throw down, this is very important */ $cookie_life = Config::get('cookie_life'); $cookie_path = Config::get('cookie_path'); $cookie_domain = false; $cookie_secure = Config::get('cookie_secure'); session_set_cookie_params($cookie_life,$cookie_path,$cookie_domain,$cookie_secure); session_name(Config::get('session_name')); /* Start the session */ self::ungimp_ie(); session_start(); } // create_cookie, just watch out for the cookie monster /** * create_remember_cookie * This function just creates the remember me cookie, nothing special */ public static function create_remember_cookie() { $remember_length = Config::get('remember_length'); $session_name = Config::get('session_name'); Config::set('cookie_life',$remember_length,'1'); setcookie($session_name . '_remember',"Rappelez-vous, rappelez-vous le 27 mars",time() + $remember_length,'/'); } // create_remember_cookie /** * session_create * This is called when you want to create a new session * it takes care of setting the initial cookie, and inserting the first chunk of * data, nifty ain't it! */ public static function session_create($data) { // Regenerate the session ID to prevent fixation switch ($data['type']) { case 'xml-rpc': case 'api': $key = md5(uniqid(rand(), true)); break; case 'mysql': default: session_regenerate_id(); // Before refresh we don't have the cookie so we have to use session ID $key = session_id(); break; } // end switch on data type $username = Dba::escape($data['username']); $ip = $_SERVER['REMOTE_ADDR'] ? Dba::escape(inet_pton($_SERVER['REMOTE_ADDR'])) : '0'; $type = Dba::escape($data['type']); $value = Dba::escape($data['value']); $agent = Dba::escape(substr($_SERVER['HTTP_USER_AGENT'],0,254)); $expire = Dba::escape(time() + Config::get('session_length')); /* We can't have null things here people */ if (!strlen($value)) { $value = ' '; } /* Insert the row */ $sql = "INSERT INTO `session` (`id`,`username`,`ip`,`type`,`agent`,`value`,`expire`) " . " VALUES ('$key','$username','$ip','$type','$agent','$value','$expire')"; $db_results = Dba::query($sql); if (!$db_results) { debug_event('SESSION',"Session Creation Failed with Query: $sql and " . Dba::error(),'1'); return false; } debug_event('SESSION','Session Created:' . $key,'6'); return $key; } // session_create /** * check_session * This checks for an existing sessoin and if it's still valid then go ahead and start it and return * true */ public static function check_session() { $session_name = Config::get('session_name'); // No cookie n go! if (!isset($_COOKIE[$session_name])) { return false; } // Check for a remember me if (isset($_COOKIE[$session_name . '_remember'])) { self::create_remember_cookie(); } // Setup the cookie params before we start the session this is vital session_set_cookie_params( Config::get('cookie_life'), Config::get('cookie_path'), Config::get('cookie_domain'), Config::get('cookie_secure')); // Set name session_name($session_name); // Ungimp IE and go self::ungimp_ie(); session_start(); return true; } // check_session /** * session_exists * This checks to see if the specified session of the specified type * exists, it also provides an array of key'd data that may be required * based on the type */ public static function session_exists($type,$key,$data=array()) { // Switch on the type they pass switch ($type) { case 'xml-rpc': case 'api': $key = Dba::escape($key); $time = time(); $sql = "SELECT * FROM `session` WHERE `id`='$key' AND `expire` > '$time' AND `type`='$type'"; $db_results = Dba::read($sql); if (Dba::num_rows($db_results)) { return true; } break; //FIXME: This should use the IN() mojo and compare against enabled auths case 'interface': $key = Dba::escape($key); $time = time(); $sql = "SELECT * FROM `session` WHERE `id`='$key' AND `expire` > '$time' AND `type`!='api' AND `type`!='xml-rpc'"; $db_results = Dba::read($sql); if (Dba::num_rows($db_results)) { return true; } break; case 'stream': $key = Dba::escape($key); $ip = Dba::escape(inet_pton($data['ip'])); $agent = Dba::escape($data['agent']); $sql = "SELECT * FROM `session_stream` WHERE `id`='$key' AND `expire` > '$time' AND `ip`='$ip' AND `agent`='$agent'"; $db_results = Dba::query($sql); if (Dba::num_rows($db_results)) { return true; } break; default: return false; break; } // type // Default to false return false; } // session_exists /** * session_extend * This should really be extend_session but hey you gotta go with the flow * this takes a SID and extends it's expire */ public static function session_extend($sid) { $sid = Dba::escape($sid); $expire = isset($_COOKIE[Config::get('session_name') . '_remember']) ? time() + Config::get('remember_length') : time() + Config::get('session_length'); $sql = "UPDATE `session` SET `expire`='$expire' WHERE `id`='$sid'"; $db_results = Dba::query($sql); debug_event('SESSION','Session:' . $sid . ' Has been Extended to ' . $expire,'6'); return $db_results; } // session_extend /** * _auto_init * This function is called when the object is included, this sets up the session_save_handler */ public static function _auto_init() { if (!function_exists('session_start')) { header("Location:" . Config::get('web_path') . "/test.php"); exit; } session_set_save_handler(array('vauth','open'),array('vauth','close'),array('vauth','read'),array('vauth','write'),array('vauth','destroy'),array('vauth','gc')); } // auto init /** * ungimp_ie * This function sets the cache limiting to public if you are running * some flavor of IE. The detection used here is very conservative so feel free * to fix it. This only has to be done if we're rolling HTTPS */ public static function ungimp_ie() { // If no https, no ungimpage required if ($_SERVER['HTTPS'] != 'on') { return true; } // Try to detect IE $agent = trim($_SERVER['HTTP_USER_AGENT']); if (strstr($agent,'MSIE') || strstr($agent,'Internet Explorer/')) { session_cache_limiter('public'); } return true; } // ungimp_ie /** * authenticate * This takes a username and password and then returns true or false * based on what happens when we try to do the auth then */ public static function authenticate($username,$password) { // Foreach the auth methods foreach (Config::get('auth_methods') as $method) { // Build the function name and call the custom method on this class $function_name = $method . '_auth'; if (!method_exists('vauth',$function_name)) { continue; } $results = self::$function_name($username,$password); // If we achive victory return if ($results['success']) { break; } } // end foreach return $results; } // authenticate /** * mysql_auth * This is the core function of authentication by ampache. It checks their current password * and then tries to figure out if it can use the new SHA password hash or if it needs to fall * back on the mysql method */ private static function mysql_auth($username,$password) { $username = Dba::escape($username); $password = Dba::escape($password); if (!strlen($password) OR !strlen($username)) { Error::add('general',_('Error Username or Password incorrect, please try again')); return false; } // We have to pull the password in order to figure out how to handle it *cry* $sql = "SELECT `password` FROM `user` WHERE `username`='$username'"; $db_results = Dba::read($sql); $row = Dba::fetch_assoc($db_results); // If it's using the old method then roll with that if (substr($row['password'],0,1) == '*' OR strlen($row['password']) < 32) { $response = self::vieux_mysql_auth($username,$password); return $response; } // Use SHA2 now... cooking with fire, SHA3 in 2012 *excitement* $password = hash('sha256',$password); $sql = "SELECT `username`,`id` FROM `user` WHERE `password`='$password' AND `username`='$username'"; $db_results = Dba::read($sql); $row = Dba::fetch_assoc($db_results); if (!count($row)) { Error::add('general',_('Error Username or Password incorrect, please try again')); return false; } $row['type'] = 'mysql'; $row['success'] = true; return $row; } // mysql_auth /** * vieux_mysql_auth * This is a private function, it should only be called by authenticate */ private static function vieux_mysql_auth($username,$password) { $password_check_sql = "PASSWORD('$password')"; // This has to still be here because lots of people use old_password in their config file $sql = "SELECT `password` FROM `user` WHERE `username`='$username'"; $db_results = Dba::query($sql); $row = Dba::fetch_assoc($db_results); $sql = "SELECT version()"; $db_results = Dba::query($sql); $version = Dba::fetch_row($db_results); $mysql_version = substr(preg_replace("/(\d+)\.(\d+)\.(\d+).*/","$1$2$3",$version[0]),0,3); if ($mysql_version > "409" AND substr($row['password'],0,1) !== "*") { $password_check_sql = "OLD_PASSWORD('$password')"; } $sql = "SELECT `username`,`id` FROM `user` WHERE `username`='$username' AND `password`=$password_check_sql"; $db_results = Dba::query($sql); $results = Dba::fetch_assoc($db_results); if (!$results) { Error::add('general',_('Error Username or Password incorrect, please try again')); return false; } if (Config::get('prevent_multiple_logins')) { $client = new User($results['id']); $current_ip = $client->is_logged_in(); if ($current_ip AND $current_ip != inet_pton($_SERVER['REMOTE_ADDR'])) { debug_event('Login','Concurrent Login Failure, attempted to login from ' . $_SERVER['REMOTE_ADDR'] . ' and already logged in','1'); Error::add('general','User Already Logged in'); return false; } } // if prevent_multiple_logins $results['type'] = 'mysql'; $results['password'] = 'old'; $results['success'] = true; return $results; } // vieux_mysql_auth /** * ldap_auth * Step one, connect to the LDAP server and perform a search for teh username provided. * If its found, attempt to bind using that username and the password provided. * Step two, figure out if they are authorized to use ampache: * TODO: need implimented still: * * require-group "The DN fetched from the LDAP directory (or the username passed by the client) occurs in the LDAP group" * * require-dn "Grant access if the DN in the directive matches the DN fetched from the LDAP directory" * * require-attribute "an attribute fetched from the LDAP directory matches the given value" */ private static function ldap_auth($username,$password) { $ldap_username = Config::get('ldap_username'); $ldap_password = Config::get('ldap_password'); /* Currently not implemented */ $require_group = Config::get('ldap_require_group'); // This is the DN for the users (required) $ldap_dn = Config::get('ldap_search_dn'); // This is the server url (required) $ldap_url = Config::get('ldap_url'); // This is the ldap filter string (required) $ldap_filter = Config::get('ldap_filter'); //This is the ldap objectclass (required) $ldap_class = Config::get('ldap_objectclass'); $ldap_name_field = Config::get('ldap_name_field'); $ldap_email_field = Config::get('ldap_email_field'); if ($ldap_link = ldap_connect($ldap_url) ) { /* Set to Protocol 3 */ ldap_set_option($ldap_link, LDAP_OPT_PROTOCOL_VERSION, 3); // bind using our auth, if we need to, for initial search for username if (!ldap_bind($ldap_link, $ldap_username, $ldap_password)) { $results['success'] = false; $results['error'] = "Could not bind to LDAP server."; return $results; } // If bind fails $sr = ldap_search($ldap_link, $ldap_dn, "(&(objectclass=$ldap_class)($ldap_filter=$username))"); $info = ldap_get_entries($ldap_link, $sr); if ($info["count"] == 1) { $user_entry = ldap_first_entry($ldap_link, $sr); $user_dn = ldap_get_dn($ldap_link, $user_entry); // bind using the user.. $retval = ldap_bind($ldap_link, $user_dn, $password); if ($retval) { ldap_close($ldap_link); $results['success'] = true; $results['type'] = "ldap"; $results['username'] = $username; $results['name'] = $info[0][$ldap_name_field][0]; $results['email'] = $info[0][$ldap_email_field][0]; return $results; } // if we get something good back } // if something was sent back } // if failed connect /* Default to bad news */ $results['success'] = false; $results['error'] = "LDAP login attempt failed"; return $results; } // ldap_auth /** * http_auth * This auth method relies on HTTP auth from Apache * This is not a very secure method of authentication * and defaults to off. */ public static function http_auth($username) { $results['success'] = true; $results['type'] = 'http'; $results['username'] = $username; $results['name'] = $username; $results['email'] = ''; return $results; } // http_auth } // end of vauth class ?>