* @version 2.0 */ // Available encryption types for class Auth_SQL. define('AUTH_ENCRYPT_MD5', 'md5'); define('AUTH_ENCRYPT_CRYPT', 'crypt'); define('AUTH_ENCRYPT_SHA1', 'sha1'); define('AUTH_ENCRYPT_PLAINTEXT', 'plaintext'); class Auth_SQL { var $_auth = ''; var $_sess = '_auth_'; var $_authentication_tested; var $_params = array(); // Default param values. var $_default_params = array( // Message displayed by requireLogin(). 'login_required_message' => 'Please login', // Automatically create table and verify columns. Better set to false after site launch. 'create_table' => true, // The database table containing users to authenticate. 'db_table' => 'user_tbl', // The name of the primary key for the db_table. 'db_primary_key' => 'user_id', // The name of the username key for the db_table. 'db_username_column' => 'username', // If using the db_login_table feature, specify the db_login_table. The primary key must match the primary key for the db_table. 'db_login_table' => 'user_login_tbl', // The type of encryption to use for passwords stored in the db_table. Use one of the AUTH_ENCRYPT_* types specified above. 'encryption_type' => AUTH_ENCRYPT_MD5, // The URL to the login script. 'login_url' => '/', // The maximum amount of time a user is allowed to be logged in. They will be forced to login again if they expire. // This applies to admins and users. In seconds. 21600 seconds = 6 hours. 'login_timeout' => 21600, // The maximum amount of time a user is allowed to be idle before their session expires. They will be forced to login again if they expire. // This applies to admins and users. In seconds. 3600 seconds = 1 hour. 'idle_timeout' => 3600, // The period of time to compare login abuse attempts. If a threshold of logins is reached in this amount of time the account is blocked. // Days and hours, like this: 'DD:HH' 'login_abuse_timeframe' => '04:00', // The number of warnings a user will receive (and their password reset each time) before their account is completely blocked. 'login_abuse_warnings' => 3, // The maximum number of IP addresses a user can login with over the timeout period before their account is blocked. 'login_abuse_max_ips' => 5, // The IP address subnet size threshold. Uses a CIDR notation network mask (see CIDR cheatsheet at bottom). // Any integar between 0 and 32 is permitted. Setting this to '24' permits any address in a // class C network (255.255.255.0) to be considered the same. Setting to '32' compares each IP absolutely. // Setting to '0' ignores all IPs, thus disabling login_abuse checking. 'login_abuse_ip_bitmask' => 32, // Specify usernames to exclude from the account abuse detection system. This is specified as a hardcoded array provided at // class instantiation time, or can be saved in the db_table under the login_abuse_exempt field. 'login_abuse_exempt_usernames' => array(), // An array of IP blocks that are bypass the remote_addr comparison check. Useful for dynamic IPs or those behind proxy servers. 'trusted_networks' => array(), // Allow user accounts to be blocked? Requires the user table to have the columns 'blocked' and 'blocked_reason' 'blocking' => false, // Use a db_login_table to detect excessive logins. This requires blocking to be enabled. 'abuse_detection' => false, ); /** * Constructs a new authentication object. * * @access public * @param optional array $params A hash containing parameters. */ function Auth_SQL($auth_name=null) { if (isset($auth_name)) { $this->_auth = $auth_name; $this->_sess .= $auth_name; } // Initialize default parameters. $this->setParam($this->_default_params); // Get create tables config from global context. if (!is_null(App::getParam('db_create_tables'))) { $this->setParam(array('create_table' => App::getParam('db_create_tables'))); } } /** * Setup the database tables for this class. * * @access public * @author Quinn Comendant * @since 26 Aug 2005 17:09:36 */ function initDB($recreate_db=false) { static $_db_tested = false; if ($recreate_db || !$_db_tested && $this->getParam('create_table')) { // User table. if ($recreate_db) { DB::query("DROP TABLE IF EXISTS " . $this->getParam('db_table')); App::logMsg(sprintf('Dropping and recreating table %s.', $this->getParam('db_table')), LOG_DEBUG, __FILE__, __LINE__); } // The minimal columns for a table compatable with the Auth_SQL class. DB::query("CREATE TABLE IF NOT EXISTS " . $this->getParam('db_table') . " ( " . $this->getParam('db_primary_key') . " smallint(11) NOT NULL auto_increment, " . $this->getParam('db_username_column') . " varchar(255) NOT NULL default '', userpass varchar(255) NOT NULL default '', first_name varchar(255) NOT NULL default '', last_name varchar(255) NOT NULL default '', email varchar(255) NOT NULL default '', user_type enum('public', 'editor', 'admin', 'root') default NULL, login_abuse_exempt enum('true') default NULL, blocked enum('true') default NULL, blocked_reason varchar(255) NOT NULL default '', abuse_warning_level tinyint(4) NOT NULL default '0', seconds_online int(11) NOT NULL default '0', last_login_datetime datetime NOT NULL default '0000-00-00 00:00:00', last_access_datetime datetime NOT NULL default '0000-00-00 00:00:00', last_login_ip varchar(255) NOT NULL default '0.0.0.0', added_by_user_id smallint(11) default NULL, modified_by_user_id smallint(11) default NULL, added_datetime datetime NOT NULL default '0000-00-00 00:00:00', modified_datetime datetime NOT NULL default '0000-00-00 00:00:00', PRIMARY KEY (" . $this->getParam('db_primary_key') . "), KEY " . $this->getParam('db_username_column') . " (" . $this->getParam('db_username_column') . "), KEY userpass (userpass), KEY email (email) )"); if (!DB::columnExists($this->getParam('db_table'), array( $this->getParam('db_primary_key'), $this->getParam('db_username_column'), 'userpass', 'first_name', 'last_name', 'email', 'user_type', 'login_abuse_exempt', 'blocked', 'blocked_reason', 'abuse_warning_level', 'seconds_online', 'last_login_datetime', 'last_access_datetime', 'last_login_ip', 'added_by_user_id', 'modified_by_user_id', 'added_datetime', 'modified_datetime', ), false, false)) { App::logMsg(sprintf('Database table %s has invalid columns. Please update this table manually.', $this->getParam('db_table')), LOG_ALERT, __FILE__, __LINE__); trigger_error(sprintf('Database table %s has invalid columns. Please update this table manually.', $this->getParam('db_table')), E_USER_ERROR); } // Login table is used for abuse_detection features. if ($this->getParam('abuse_detection')) { if ($recreate_db) { DB::query("DROP TABLE IF EXISTS " . $this->getParam('db_login_table')); App::logMsg(sprintf('Dropping and recreating table %s.', $this->getParam('db_login_table')), LOG_DEBUG, __FILE__, __LINE__); } DB::query("CREATE TABLE IF NOT EXISTS " . $this->getParam('db_login_table') . " ( " . $this->getParam('db_primary_key') . " smallint(11) NOT NULL default '0', login_datetime datetime NOT NULL default '0000-00-00 00:00:00', remote_ip_binary char(32) NOT NULL default '', KEY " . $this->getParam('db_primary_key') . " (" . $this->getParam('db_primary_key') . "), KEY login_datetime (login_datetime), KEY remote_ip_binary (remote_ip_binary) )"); if (!DB::columnExists($this->getParam('db_login_table'), array( $this->getParam('db_primary_key'), 'login_datetime', 'remote_ip_binary', ), false, false)) { App::logMsg(sprintf('Database table %s has invalid columns. Please update this table manually.', $this->getParam('db_login_table')), LOG_ALERT, __FILE__, __LINE__); trigger_error(sprintf('Database table %s has invalid columns. Please update this table manually.', $this->getParam('db_login_table')), E_USER_ERROR); } } } $_db_tested = true; } /** * Sets a variable into a registered auth session. * * @access public * @param mixed $key Which value to set. * @param mixed $val Value to set variable to. */ function setVal($key, $val) { if (!isset($_SESSION[$this->_sess]['user_data'])) { $_SESSION[$this->_sess]['user_data'] = array(); } $_SESSION[$this->_sess]['user_data'][$key] = $val; } /** * Returns a specified value from a registered auth session. * * @access public * @param mixed $key Which value to return. * @param mixed $default Value to return if key not found in user_data. * @return mixed Value stored in session. */ function getVal($key, $default='') { if (isset($_SESSION[$this->_sess][$key])) { return $_SESSION[$this->_sess][$key]; } else if (isset($_SESSION[$this->_sess]['user_data'][$key])) { return $_SESSION[$this->_sess]['user_data'][$key]; } else { return $default; } } /** * Set the params of an auth object. * * @param array $params Array of parameter keys and value to set. * @return bool true on success, false on failure */ function setParam($params) { if (isset($params) && is_array($params)) { // Merge new parameters with old overriding only those passed. $this->_params = array_merge($this->_params, $params); } } /** * Return the value of a parameter, if it exists. * * @access public * @param string $param Which parameter to return. * @return mixed Configured parameter value. */ function getParam($param) { if (isset($this->_params[$param])) { return $this->_params[$param]; } else { App::logMsg(sprintf('Parameter is not set: %s', $param), LOG_DEBUG, __FILE__, __LINE__); return null; } } /** * Clear any authentication tokens in the current session. A.K.A. logout. * * @access public */ function clearAuth() { $this->initDB(); DB::query(" UPDATE " . $this->_params['db_table'] . " SET seconds_online = seconds_online + (UNIX_TIMESTAMP() - UNIX_TIMESTAMP(last_access_datetime)), last_login_datetime = '0000-00-00 00:00:00' WHERE " . $this->_params['db_primary_key'] . " = '" . $this->getVal('user_id') . "' "); $_SESSION[$this->_sess] = array(); $_SESSION[$this->_sess]['authenticated'] = false; } /** * Find out if a set of login credentials are valid. * * @access private * @param string $username The username to check. * @param string $password The password to compare to username. * @return mixed False if credentials not found in DB, or returns DB row matching credentials. */ function authenticate($username, $password) { $this->initDB(); // Query DB for user matching credentials. $qid = DB::query(" SELECT *, " . $this->_params['db_primary_key'] . " AS user_id FROM " . $this->_params['db_table'] . " WHERE " . $this->_params['db_username_column'] . " = '" . addslashes($username) . "' AND BINARY userpass = '" . addslashes($this->encryptPassword($password)) . "' "); // Return user data if found. if ($user_data = mysql_fetch_assoc($qid)) { App::logMsg(sprintf('Authentication successful for %s %s (%s)', $this->_auth, $user_data['user_id'], $username), LOG_INFO, __FILE__, __LINE__); return $user_data; } else { App::logMsg(sprintf('Authentication failed for %s %s (encrypted attempted password: %s)', $this->_auth, $username, $this->encryptPassword($password)), LOG_NOTICE, __FILE__, __LINE__); return false; } } /** * If user authenticated, register login into session. * * @access private * @param string $username The username to check. * @param string $password The password to compare to username. * @return boolean Whether or not the credentials are valid. */ function login($username, $password) { $this->initDB(); $this->clearAuth(); if (!$user_data = $this->authenticate($username, $password)) { // No login: failed authentication! return false; } // Register authenticated session. $_SESSION[$this->_sess] = array( 'authenticated' => true, 'user_id' => $user_data['user_id'], 'auth_name' => $this->_auth, 'username' => $username, 'login_datetime' => date('Y-m-d H:i:s'), 'last_access_datetime' => date('Y-m-d H:i:s'), 'remote_ip' => getRemoteAddr(), 'login_abuse_exempt' => isset($user_data['login_abuse_exempt']) ? !empty($user_data['login_abuse_exempt']) : in_array($username, $this->_params['login_abuse_exempt_usernames']), 'user_data' => $user_data ); /** * Check if the account is blocked, respond in context to reason. Cancel the login if blocked. */ if ($this->getParam('blocking')) { if (!empty($user_data['blocked'])) { App::logMsg(sprintf('%s %s (%s) login failed due to blocked account: %s', ucfirst($this->_auth), $this->getVal('user_id'), $this->getVal('username'), $this->getVal('blocked_reason')), LOG_NOTICE, __FILE__, __LINE__); switch ($user_data['blocked_reason']) { case 'account abuse' : App::raiseMsg(sprintf(_("This account has been blocked due to possible account abuse. Please contact us to reactivate."), null), MSG_WARNING, __FILE__, __LINE__); break; default : App::raiseMsg(sprintf(_("This account is currently not active. %s"), $user_data['blocked_reason']), MSG_WARNING, __FILE__, __LINE__); break; } // No login: user is blocked! $this->clearAuth(); return false; } } /** * Check the db_login_table for too many logins under this account. * (1) Count the number of unique IP addresses that logged in under this user within the login_abuse_timeframe * (2) If this number exceeds the login_abuse_max_ips, assume multiple people are logging in under the same account. **/ if ($this->getParam('abuse_detection') && !$this->getVal('login_abuse_exempt')) { $qid = DB::query(" SELECT COUNT(DISTINCT LEFT(remote_ip_binary, " . $this->_params['login_abuse_ip_bitmask'] . ")) FROM " . $this->_params['db_login_table'] . " WHERE " . $this->_params['db_primary_key'] . " = '" . $this->getVal('user_id') . "' AND DATE_ADD(login_datetime, INTERVAL '" . $this->_params['login_abuse_timeframe'] . "' DAY_HOUR) > NOW() "); list($distinct_ips) = mysql_fetch_row($qid); if ($distinct_ips > $this->_params['login_abuse_max_ips']) { if ($this->getVal('abuse_warning_level') < $this->_params['login_abuse_warnings']) { // Warn the user with a password reset. $this->resetPassword(null, _("This is a security precaution. We have detected this account has been accessed from multiple computers simultaneously. It is against policy to share login information with others. If further account abuse is detected this account will be blocked.")); App::raiseMsg(_("Your password has been reset as a security precaution. Please check your email for more information."), MSG_NOTICE, __FILE__, __LINE__); App::logMsg(sprintf('Account abuse detected for %s %s (%s) from IP %s', $this->_auth, $this->getVal('user_id'), $this->getVal('username'), $this->getVal('remote_ip')), LOG_WARNING, __FILE__, __LINE__); } else { // Block the account with the reason of account abuse. $this->blockAccount(null, 'account abuse'); App::raiseMsg(_("Your account has been blocked as a security precaution. Please contact us for more information."), MSG_NOTICE, __FILE__, __LINE__); App::logMsg(sprintf('Account blocked for %s %s (%s) from IP %s', $this->_auth, $this->getVal('user_id'), $this->getVal('username'), $this->getVal('remote_ip')), LOG_ALERT, __FILE__, __LINE__); } // Increment user's warning level. DB::query("UPDATE " . $this->_params['db_table'] . " SET abuse_warning_level = abuse_warning_level + 1 WHERE " . $this->_params['db_primary_key'] . " = '" . $this->getVal('user_id') . "'"); // Reset the login counter for this user. DB::query("DELETE FROM " . $this->_params['db_login_table'] . " WHERE " . $this->_params['db_primary_key'] . " = '" . $this->getVal('user_id') . "'"); // No login: reset password because of account abuse! $this->clearAuth(); return false; } // Update the login counter table with this login access. Convert IP to binary. DB::query(" INSERT INTO " . $this->_params['db_login_table'] . " ( " . $this->_params['db_primary_key'] . ", login_datetime, remote_ip_binary ) VALUES ( '" . $this->getVal('user_id') . "', '" . $this->getVal('login_datetime') . "', '" . sprintf('%032b', ip2long($this->getVal('remote_ip'))) . "' ) "); } // Update user table with this login. DB::query(" UPDATE " . $this->_params['db_table'] . " SET last_login_datetime = '" . $this->getVal('login_datetime') . "', last_access_datetime = '" . $this->getVal('login_datetime') . "', last_login_ip = '" . $this->getVal('remote_ip') . "' WHERE " . $this->_params['db_primary_key'] . " = '" . $this->getVal('user_id') . "' "); // We're logged-in! return true; } /** * Test if user has a currently logged-in session. * - authentication flag set to true * - username not empty * - total logged-in time is not greater than login_timeout * - idle time is not greater than idle_timeout * - remote address is the same as the login remote address (aol users excluded). * * @access public */ function isLoggedIn($user_id=null) { $this->initDB(); if (isset($user_id)) { // Check the login status of a specific user. $qid = DB::query(" SELECT 1 FROM " . $this->_params['db_table'] . " WHERE " . $this->_params['db_primary_key'] . " = '" . addslashes($user_id) . "' AND DATE_ADD(last_login_datetime, INTERVAL '" . $this->_params['login_timeout'] . "' SECOND) > NOW() AND DATE_ADD(last_access_datetime, INTERVAL '" . $this->_params['idle_timeout'] . "' SECOND) > NOW() "); return (mysql_num_rows($qid) > 0); } // User login test need only be run once per script execution. We cache the result in the session. if ($this->_authentication_tested && isset($_SESSION[$this->_sess]['authenticated'])) { return $_SESSION[$this->_sess]['authenticated']; } // Tesing login should occur once. This is the first time. Set flag. $this->_authentication_tested = true; // Some users will access from networks with a changing IP number (i.e. behind a proxy server). These users must be allowed entry by adding their IP to the list of trusted_networks. if ($trusted_net = ipInRange(getRemoteAddr(), $this->_params['trusted_networks'])) { $user_in_trusted_network = true; App::logMsg(sprintf('%s%s accessing from trusted network %s', ucfirst($this->_auth), ($this->getVal('user_id') ? ' ' . $this->getVal('user_id') . ' (' . $this->getVal('username') . ')' : ''), $trusted_net ), LOG_INFO, __FILE__, __LINE__); } else if (preg_match('/proxy.aol.com$/i', getRemoteAddr(true))) { $user_in_trusted_network = true; App::logMsg(sprintf('%s%s accessing from trusted network proxy.aol.com', ucfirst($this->_auth), ($this->getVal('user_id') ? ' ' . $this->getVal('user_id') . ' (' . $this->getVal('username') . ')' : '') ), LOG_INFO, __FILE__, __LINE__); } else { $user_in_trusted_network = false; } // Test login with information stored in session. Skip IP matching for users from trusted networks. if (isset($_SESSION[$this->_sess]) && true === $_SESSION[$this->_sess]['authenticated'] && !empty($_SESSION[$this->_sess]['username']) && strtotime($_SESSION[$this->_sess]['login_datetime']) > time() - $this->_params['login_timeout'] && strtotime($_SESSION[$this->_sess]['last_access_datetime']) > time() - $this->_params['idle_timeout'] && ($_SESSION[$this->_sess]['remote_ip'] == getRemoteAddr() || $user_in_trusted_network) ) { // User is authenticated! $_SESSION[$this->_sess]['last_access_datetime'] = date('Y-m-d H:i:s'); // Update the DB with the last_access_datetime and increment the seconds_online. DB::query(" UPDATE " . $this->_params['db_table'] . " SET seconds_online = seconds_online + (UNIX_TIMESTAMP() - UNIX_TIMESTAMP(last_access_datetime)) + 1, last_access_datetime = '" . $this->getVal('last_access_datetime') . "' WHERE " . $this->_params['db_primary_key'] . " = '" . $this->getVal('user_id') . "' "); if (mysql_affected_rows(DB::getDBH()) > 0) { // User record still exists in DB. Do this to ensure user was not delete from DB between accesses. Notice "+ 1" in SQL above to ensure record is modified. return true; } else { App::logMsg(sprintf('User update failed. Record not found for %s %s (%s).', $this->_auth, $this->getVal('user_id'), $this->getVal('username')), LOG_NOTICE, __FILE__, __LINE__); } } else if (isset($_SESSION[$this->_sess]) && true === $_SESSION[$this->_sess]['authenticated']) { // User is authenticated, but login has expired. if (strtotime($_SESSION[$this->_sess]['last_access_datetime']) > time() - 43200) { // Only raise message if last session is less than 12 hours old. App::raiseMsg(sprintf(_("Your %s session has closed. You need to log-in again."), strtolower($this->_auth)), MSG_NOTICE, __FILE__, __LINE__); } // Log the reason for login expiration. $expire_reasons = array(); if (empty($_SESSION[$this->_sess]['username'])) { $expire_reasons[] = 'username not found'; } if (strtotime($_SESSION[$this->_sess]['login_datetime']) <= time() - $this->_params['login_timeout']) { $expire_reasons[] = 'login_timeout expired'; } if (strtotime($_SESSION[$this->_sess]['last_access_datetime']) <= time() - $this->_params['idle_timeout']) { $expire_reasons[] = 'idle_timeout expired'; } if ($_SESSION[$this->_sess]['remote_ip'] != getRemoteAddr()) { $expire_reasons[] = sprintf('remote_ip not matched (%s != %s)', $_SESSION[$this->_sess]['remote_ip'], getRemoteAddr()); } App::logMsg(sprintf('%s %s (%s) session expired: %s', ucfirst($this->_auth), $this->getVal('user_id'), $this->getVal('username'), join(', ', $expire_reasons)), LOG_INFO, __FILE__, __LINE__); } // User is not authenticated. $this->clearAuth(); return false; } /** * Redirect user to login page if they are not logged in. * * @param string $message The text description of a message to raise. * @param int $type The type of message: MSG_NOTICE, * MSG_SUCCESS, MSG_WARNING, or MSG_ERR. * @param string $file __FILE__. * @param string $line __LINE__. * @access public */ function requireLogin($message='', $type=MSG_NOTICE, $file=null, $line=null) { if (!$this->isLoggedIn()) { // Display message for requiring login. App::raiseMsg($message, $type, $file, $line); // Login scripts must have the same 'login' tag for boomerangURL verification/manipulation. App::setBoomerangURL(absoluteMe(), 'login'); App::dieURL($this->_params['login_url']); } } /** * This sets the 'blocked' field for a user in the db_table, and also * adds an optional reason * * @param string $reason The reason for blocking the account. */ function blockAccount($user_id=null, $reason='') { $this->initDB(); if ($this->getParam('blocking')) { if (strlen(addslashes($reason)) > 255) { // blocked_reason field is varchar(255). App::logMsg(sprintf('Blocked reason provided is greater than 255 characters: %s', $reason), LOG_WARNING, __FILE__, __LINE__); } // Get user_id if specified. $user_id = isset($user_id) ? $user_id : $this->getVal('user_id'); DB::query(" UPDATE " . $this->_params['db_table'] . " SET blocked = 'true', blocked_reason = '" . addslashes($reason) . "' WHERE " . $this->_params['db_primary_key'] . " = '" . addslashes($user_id) . "' "); } } /** * Unblocks a user in the db_table, and clears any blocked_reason. */ function unblockAccount($user_id=null) { $this->initDB(); if ($this->getParam('blocking')) { // Get user_id if specified. $user_id = isset($user_id) ? $user_id : $this->getVal('user_id'); DB::query(" UPDATE " . $this->_params['db_table'] . " SET blocked = '', blocked_reason = '' WHERE " . $this->_params['db_primary_key'] . " = '" . addslashes($user_id) . "' "); } } /** * Returns true if username already exists in database. * * @param string $username Username to look for. * @return bool True if username exists. */ function usernameExists($username) { $this->initDB(); $qid = DB::query(" SELECT 1 FROM " . $this->_params['db_table'] . " WHERE " . $this->_params['db_username_column'] . " = '" . addslashes($username) . "' "); return (mysql_num_rows($qid) > 0); } /** * Returns a username for a specified user id. * * @param string $user_id User id to look for. * @return string Username, or false if none found. */ function getUsername($user_id) { $this->initDB(); $qid = DB::query(" SELECT " . $this->_params['db_username_column'] . " FROM " . $this->_params['db_table'] . " WHERE " . $this->_params['db_primary_key'] . " = '" . addslashes($user_id) . "' "); if (list($username) = mysql_fetch_row($qid)) { return $username; } else { return false; } } /** * Returns a randomly generated password based on $pattern. The pattern is any * sequence of 'x', 'V', 'C', 'v', 'c', or 'd' and if it is something like 'cvccv' this * function will generate a pronouncable password. Recommend using more complex * patterns, at minimum the US State Department standard: cvcddcvc. * * - x a random upper or lower alpha character or digit * - C a random upper or lower consanant * - V a random upper or lower vowel * - c a random lowercase consanant * - v a random lowercase vowel * - d a random digit * * @param string $pattern a sequence of character types, above. * @return string a password */ function generatePassword($pattern='CvccvCdd') { mt_srand((double) microtime() * 10000000); $str = ''; for ($i=0; $i_params['encryption_type']) { case AUTH_ENCRYPT_PLAINTEXT : return $password; break; case AUTH_ENCRYPT_CRYPT : return crypt($password, crypt($password)); break; case AUTH_ENCRYPT_SHA1 : return sha1($password); break; case AUTH_ENCRYPT_MD5 : default : return md5($password); break; } } /** * */ function setPassword($user_id=null, $password) { $this->initDB(); // Get user_id if specified. $user_id = isset($user_id) ? $user_id : $this->getVal('user_id'); // Issue the password change query. DB::query(" UPDATE " . $this->_params['db_table'] . " SET userpass = '" . addslashes($this->encryptPassword($password)) . "' WHERE " . $this->_params['db_primary_key'] . " = '" . addslashes($user_id) . "' "); } /** * Resets the password for the user with the specified id. * * @param string $user_id The id of the user to reset. * @param string $reason Additional message to add to the reset email. * @return string The user's new password. */ function resetPassword($user_id=null, $reason='') { $this->initDB(); // Get user_id if specified. $user_id = isset($user_id) ? $user_id : $this->getVal('user_id'); // Reset password of a specific user. $qid = DB::query(" SELECT * FROM " . $this->_params['db_table'] . " WHERE " . $this->_params['db_primary_key'] . " = '" . addslashes($user_id) . "' "); if (!$user_data = mysql_fetch_assoc($qid)) { App::logMsg(sprintf('Reset password failed. %s %s not found.', ucfirst($this->_auth), $user_id), LOG_NOTICE, __FILE__, __LINE__); return false; } // Make sure user has an email on record. if (!isset($user_data['email']) || '' == trim($user_data['email'])) { App::logMsg(sprintf('Password reset but notification failed, no email address for %s %s (%s).', $this->_auth, $user_data[$this->_params['db_primary_key']], $user_data[$this->_params['db_username_column']]), LOG_NOTICE, __FILE__, __LINE__); } // Get new password. $password = $this->generatePassword(); // Update password query. $this->setPassword($user_id, $password); // Body for email. $email_body = << $user_data['email'], 'from' => sprintf('%s <%s>', App::getParam('site_name'), App::getParam('site_email')), 'subject' => sprintf('%s password change', App::getParam('site_name')) )); $email->setString($email_body); $email->replace(array( 'site_name' => App::getParam('site_name'), 'site_url' => App::getParam('site_url'), 'name' => ('' != $user_data['first_name'] . $user_data['last_name'] ? $user_data['first_name'] . ' ' . $user_data['last_name'] : $user_data[$this->_params['db_username_column']]), 'username' => $user_data[$this->_params['db_username_column']], 'password' => $password, 'reason' => $reason, )); $email->send(); return array( 'username' => $user_data[$this->_params['db_username_column']], 'userpass' => $password ); } /** * If the current user has access to the specified $security_zone, return true. * If the optional $priv is supplied, test that against the zone. * * @param constant $security_zone string of comma delimited priviliges for the zone * @param string $priv a privilege that might be found in a zone * @return bool true if user is a member of security zone, false otherwise */ function inClearanceZone($security_zone, $priv='') { return true; $zone_members = preg_split('/,\s*/', $security_zone); $priv = empty($priv) ? $this->getVal('priv') : $priv; // If the current user's privilege level is NOT in that array or if the // user has no privilege, return false. Otherwise the user is clear. if (!in_array($priv, $zone_members) || empty($priv)) { return false; } else { return true; } } /** * This function tests a list of arguments $security_zone against the priv that the current user has. * If the user doesn't have one of the supplied privs, die. * * @param constant $security_zone string of comma delimited priviliges for the zone */ function requireAccessClearance($security_zone, $message='') { return true; $zone_members = preg_split('/,\s*/', $security_zone); /* If the current user's privilege level is NOT in that array or if the * user has no privilege, DIE with a message. */ if (!in_array($this->getVal('priv'), $zone_members) || !$this->getVal('priv')) { $message = empty($message) ? _("You have insufficient privileges to view that page.") : $message; App::raiseMsg($message, MSG_NOTICE, __FILE__, __LINE__); App::dieBoomerangURL(); } } } // end class // CIDR cheatsheet // // Netmask Netmask (binary) CIDR Notes // _____________________________________________________________________________ // 255.255.255.255 11111111.11111111.11111111.11111111 /32 Host (single addr) // 255.255.255.254 11111111.11111111.11111111.11111110 /31 Unuseable // 255.255.255.252 11111111.11111111.11111111.11111100 /30 2 useable // 255.255.255.248 11111111.11111111.11111111.11111000 /29 6 useable // 255.255.255.240 11111111.11111111.11111111.11110000 /28 14 useable // 255.255.255.224 11111111.11111111.11111111.11100000 /27 30 useable // 255.255.255.192 11111111.11111111.11111111.11000000 /26 62 useable // 255.255.255.128 11111111.11111111.11111111.10000000 /25 126 useable // 255.255.255.0 11111111.11111111.11111111.00000000 /24 "Class C" 254 useable // // 255.255.254.0 11111111.11111111.11111110.00000000 /23 2 Class C's // 255.255.252.0 11111111.11111111.11111100.00000000 /22 4 Class C's // 255.255.248.0 11111111.11111111.11111000.00000000 /21 8 Class C's // 255.255.240.0 11111111.11111111.11110000.00000000 /20 16 Class C's // 255.255.224.0 11111111.11111111.11100000.00000000 /19 32 Class C's // 255.255.192.0 11111111.11111111.11000000.00000000 /18 64 Class C's // 255.255.128.0 11111111.11111111.10000000.00000000 /17 128 Class C's // 255.255.0.0 11111111.11111111.00000000.00000000 /16 "Class B" // // 255.254.0.0 11111111.11111110.00000000.00000000 /15 2 Class B's // 255.252.0.0 11111111.11111100.00000000.00000000 /14 4 Class B's // 255.248.0.0 11111111.11111000.00000000.00000000 /13 8 Class B's // 255.240.0.0 11111111.11110000.00000000.00000000 /12 16 Class B's // 255.224.0.0 11111111.11100000.00000000.00000000 /11 32 Class B's // 255.192.0.0 11111111.11000000.00000000.00000000 /10 64 Class B's // 255.128.0.0 11111111.10000000.00000000.00000000 /9 128 Class B's // 255.0.0.0 11111111.00000000.00000000.00000000 /8 "Class A" // // 254.0.0.0 11111110.00000000.00000000.00000000 /7 // 252.0.0.0 11111100.00000000.00000000.00000000 /6 // 248.0.0.0 11111000.00000000.00000000.00000000 /5 // 240.0.0.0 11110000.00000000.00000000.00000000 /4 // 224.0.0.0 11100000.00000000.00000000.00000000 /3 // 192.0.0.0 11000000.00000000.00000000.00000000 /2 // 128.0.0.0 10000000.00000000.00000000.00000000 /1 // 0.0.0.0 00000000.00000000.00000000.00000000 /0 IP space ?>