# HG changeset patch # User Dan # Date 1195436228 18000 # Node ID f088805540aea5720cbd2a0ce9919dcfcbc1fac4 # Parent 917dcc6c4ceb9d62ab37967a8d9855544785e21e# Parent 5bcdee999015a73ff3efb5ff102ef5fdb7dd6e1a Merging in fixes and updates from stable diff -r 917dcc6c4ceb -r f088805540ae includes/common.php --- a/includes/common.php Sat Nov 17 22:25:37 2007 -0500 +++ b/includes/common.php Sun Nov 18 20:37:08 2007 -0500 @@ -273,6 +273,12 @@ @call_user_func('page_'.$p[1].'_'.$p[0].'_preloader'); } + // One quick security check... + if ( !is_valid_ip($_SERVER['REMOTE_ADDR']) ) + { + die('SECURITY: spoofed IP address'); + } + $session->start(); $paths->init(); diff -r 917dcc6c4ceb -r f088805540ae includes/dbal.php --- a/includes/dbal.php Sat Nov 17 22:25:37 2007 -0500 +++ b/includes/dbal.php Sun Nov 18 20:37:08 2007 -0500 @@ -121,13 +121,25 @@ return $internal_text; } - function connect() { + function connect() + { $this->enable_errorhandler(); + dc_here('dbal: trying to connect....'); - @include(ENANO_ROOT.'/config.php'); - if(isset($crypto_key)) + + if ( defined('IN_ENANO_INSTALL') ) + { + @include(ENANO_ROOT.'/config.new.php'); + } + else + { + @include(ENANO_ROOT.'/config.php'); + } + + if ( isset($crypto_key) ) unset($crypto_key); // Get this sucker out of memory fast - if(!defined('ENANO_INSTALLED') && !defined('MIDGET_INSTALLED') && !defined('IN_ENANO_INSTALL') ) + + if ( !defined('ENANO_INSTALLED') && !defined('MIDGET_INSTALLED') && !defined('IN_ENANO_INSTALL') ) { dc_here('dbal: oops, looks like Enano isn\'t set up. Constants ENANO_INSTALLED, MIDGET_INSTALLED, and IN_ENANO_INSTALL are all undefined.'); header('Location: install.php'); @@ -136,46 +148,74 @@ $this->_conn = @mysql_connect($dbhost, $dbuser, $dbpasswd); unset($dbuser); unset($dbpasswd); // Security - if(!$this->_conn) { dc_here('dbal: uhoh!
'.mysql_error()); grinding_halt('Enano is having a problem', '

Error: couldn\'t connect to MySQL.
'.mysql_error().'

'); } + + if ( !$this->_conn ) + { + dc_here('dbal: uhoh!
'.mysql_error()); + grinding_halt('Enano is having a problem', '

Error: couldn\'t connect to MySQL.
'.mysql_error().'

'); + } + + // Reset some variables $this->query_backtrace = ''; $this->num_queries = 0; + dc_here('dbal: we\'re in, selecting database...'); $q = $this->sql_query('USE `'.$dbname.'`;'); - if(!$q) $this->_die('The database could not be selected.'); + + if ( !$q ) + $this->_die('The database could not be selected.'); + + // We're in! dc_here('dbal: connected to MySQL'); + $this->disable_errorhandler(); + return true; } - function sql_query($q) { + function sql_query($q) + { $this->enable_errorhandler(); $this->num_queries++; - $this->query_backtrace .= $q."\n"; + $this->query_backtrace .= $q . "\n"; $this->latest_query = $q; dc_here('dbal: making SQL query:
'.$q.''); - if(!$this->_conn) $this->_die('A database connection has not yet been established.'); - if(!$this->check_query($q)) + // First make sure we have a connection + if ( !$this->_conn ) + { + $this->_die('A database connection has not yet been established.'); + } + // Does this query look malicious? + if ( !$this->check_query($q) ) { $this->report_query($q); grinding_halt('SQL Injection attempt', '

Enano has caught and prevented an SQL injection attempt. Your IP address has been recorded and the administrator has been notified.

Query was:

'.htmlspecialchars($q).'
'); } + $r = mysql_query($q, $this->_conn); $this->latest_result = $r; $this->disable_errorhandler(); return $r; } - function sql_unbuffered_query($q) { + function sql_unbuffered_query($q) + { $this->enable_errorhandler(); $this->num_queries++; $this->query_backtrace .= '(UNBUFFERED) ' . $q."\n"; $this->latest_query = $q; dc_here('dbal: making SQL query:
'.$q.''); - if(!$this->_conn) $this->_die('A database connection has not yet been established.'); - if(!$this->check_query($q)) + // First make sure we have a connection + if ( !$this->_conn ) + { + $this->_die('A database connection has not yet been established.'); + } + // Does this query look malicious? + if ( !$this->check_query($q) ) { $this->report_query($q); grinding_halt('SQL Injection attempt', '

Enano has caught and prevented an SQL injection attempt. Your IP address has been recorded and the administrator has been notified.

Query was:

'.htmlspecialchars($q).'
'); } + $r = mysql_unbuffered_query($q, $this->_conn); $this->latest_result = $r; $this->disable_errorhandler(); diff -r 917dcc6c4ceb -r f088805540ae includes/functions.php --- a/includes/functions.php Sat Nov 17 22:25:37 2007 -0500 +++ b/includes/functions.php Sun Nov 18 20:37:08 2007 -0500 @@ -2735,7 +2735,7 @@ { $array[$i] = decode_unicode_url($val); } - else + else if ( is_array($val) ) { $array[$i] = decode_unicode_array($val); } @@ -2999,6 +2999,72 @@ return $ips; } +/** + * Parses a valid IP address range into a regular expression. + * @param string IP range string + * @return string + */ + +function parse_ip_range_regex($range) +{ + // Regular expression to test the range string for validity + $regex = '/^(([0-9]+(-[0-9]+)?)(\|([0-9]+(-[0-9]+)?))*)\.' + . '(([0-9]+(-[0-9]+)?)(\|([0-9]+(-[0-9]+)?))*)\.' + . '(([0-9]+(-[0-9]+)?)(\|([0-9]+(-[0-9]+)?))*)\.' + . '(([0-9]+(-[0-9]+)?)(\|([0-9]+(-[0-9]+)?))*)$/'; + if ( !preg_match($regex, $range) ) + { + return false; + } + $octets = array(0 => array(), 1 => array(), 2 => array(), 3 => array()); + list($octets[0], $octets[1], $octets[2], $octets[3]) = explode('.', $range); + $return = '^'; + foreach ( $octets as $octet ) + { + // alternatives array + $alts = array(); + if ( strpos($octet, '|') ) + { + $particles = explode('|', $octet); + } + else + { + $particles = array($octet); + } + foreach ( $particles as $atom ) + { + // each $atom will be either + if ( strval(intval($atom)) == $atom ) + { + $alts[] = $atom; + continue; + } + else + { + // it's a range - parse it out + $alt2 = int_range($atom); + if ( !$alt2 ) + return false; + foreach ( $alt2 as $neutrino ) + $alts[] = $neutrino; + } + } + $alts = array_unique($alts); + $alts = '|' . implode('|', $alts) . '|'; + // we can further optimize/compress this by weaseling our way into using some character ranges + for ( $i = 1; $i <= 25; $i++ ) + { + $alts = str_replace("|{$i}0|{$i}1|{$i}2|{$i}3|{$i}4|{$i}5|{$i}6|{$i}7|{$i}8|{$i}9|", "|{$i}[0-9]|", $alts); + } + $alts = str_replace("|1|2|3|4|5|6|7|8|9|", "|[1-9]|", $alts); + $alts = '(' . substr($alts, 1, -1) . ')'; + $return .= $alts . '\.'; + } + $return = substr($return, 0, -2); + $return .= '$'; + return $return; +} + function password_score_len($password) { if ( !is_string($password) ) diff -r 917dcc6c4ceb -r f088805540ae includes/pageutils.php --- a/includes/pageutils.php Sat Nov 17 22:25:37 2007 -0500 +++ b/includes/pageutils.php Sun Nov 18 20:37:08 2007 -0500 @@ -24,6 +24,7 @@ function checkusername($name) { global $db, $session, $paths, $template, $plugins; // Common objects + $name = str_replace('_', ' ', $name); $q = $db->sql_query('SELECT username FROM ' . table_prefix.'users WHERE username=\'' . $db->escape(rawurldecode($name)) . '\''); if ( !$q ) { diff -r 917dcc6c4ceb -r f088805540ae includes/sessions.php --- a/includes/sessions.php Sat Nov 17 22:25:37 2007 -0500 +++ b/includes/sessions.php Sun Nov 18 20:37:08 2007 -0500 @@ -151,7 +151,7 @@ */ //var $valid_username = '([A-Za-z0-9 \!\@\(\)-]+)'; - var $valid_username = '([^<>_&\?\'"%\n\r\t\a\/]+)'; + var $valid_username = '([^<>&\?\'"%\n\r\t\a\/]+)'; /** * What we're allowed to do as far as permissions go. This changes based on the value of the "auth" URI param. @@ -260,7 +260,16 @@ function __construct() { global $db, $session, $paths, $template, $plugins; // Common objects - include(ENANO_ROOT.'/config.php'); + + if ( defined('IN_ENANO_INSTALL') ) + { + @include(ENANO_ROOT.'/config.new.php'); + } + else + { + @include(ENANO_ROOT.'/config.php'); + } + unset($dbhost, $dbname, $dbuser, $dbpasswd); if(isset($crypto_key)) { @@ -563,7 +572,7 @@ * @return string 'success' on success, or error string on failure */ - function login_with_crypto($username, $aes_data, $aes_key, $challenge, $level = USER_LEVEL_MEMBER, $captcha_hash = false, $captcha_code = false) + function login_with_crypto($username, $aes_data, $aes_key_id, $challenge, $level = USER_LEVEL_MEMBER, $captcha_hash = false, $captcha_code = false) { global $db, $session, $paths, $template, $plugins; // Common objects @@ -613,7 +622,7 @@ // Fetch our decryption key - $aes_key = $this->fetch_public_key($aes_key); + $aes_key = $this->fetch_public_key($aes_key_id); if(!$aes_key) return array( 'success' => false, @@ -636,6 +645,7 @@ $success = false; // Escaped username + $username = str_replace('_', ' ', $username); $db_username_lower = $this->prepare_text(strtolower($username)); $db_username = $this->prepare_text($username); @@ -802,6 +812,10 @@ $pass_hashed = ( $already_md5ed ) ? $password : md5($password); + // Replace underscores with spaces in username + // (Added in 1.0.2) + $username = str_replace('_', ' ', $username); + // Perhaps we're upgrading Enano? if($this->compat) { @@ -1025,7 +1039,7 @@ /** * Registers a session key in the database. This function *ASSUMES* that the username and password have already been validated! - * Basically the session key is a base64-encoded cookie (encrypted with the site's private key) that says "u=[username];p=[sha1 of password]" + * Basically the session key is a hex-encoded cookie (encrypted with the site's private key) that says "u=[username];p=[sha1 of password];s=[unique key id]" * @param int $user_id * @param string $username * @param string $password @@ -1084,7 +1098,7 @@ } /** - * Identical to register_session in nature, but uses the old login/table structure. DO NOT use this. + * Identical to register_session in nature, but uses the old login/table structure. DO NOT use this except in the upgrade script under very controlled circumstances. * @see sessionManager::register_session() * @access private */ @@ -1536,59 +1550,79 @@ function check_banlist() { global $db, $session, $paths, $template, $plugins; // Common objects - if($this->compat) - $q = $this->sql('SELECT ban_id,ban_type,ban_value,is_regex FROM '.table_prefix.'banlist ORDER BY ban_type;'); - else - $q = $this->sql('SELECT ban_id,ban_type,ban_value,is_regex,reason FROM '.table_prefix.'banlist ORDER BY ban_type;'); - if(!$q) $db->_die('The banlist data could not be selected.'); - $banned = false; - while($row = $db->fetchrow()) + $col_reason = ( $this->compat ) ? '"No reason entered (session manager is in compatibility mode)" AS reason' : 'reason'; + $is_banned = false; + if ( $this->user_logged_in ) { - if($this->compat) - $row['reason'] = 'None available - session manager is in compatibility mode'; - switch($row['ban_type']) + // check by IP, email, and username + $sql = "SELECT $col_reason, ban_value, ban_type, is_regex FROM " . table_prefix . "banlist WHERE \n" + . " ( ban_type = " . BAN_IP . " AND is_regex = 0 ) OR \n" + . " ( ban_type = " . BAN_IP . " AND is_regex = 1 AND '{$_SERVER['REMOTE_ADDR']}' REGEXP ban_value ) OR \n" + . " ( ban_type = " . BAN_USER . " AND is_regex = 0 AND ban_value = '{$this->username}' ) OR \n" + . " ( ban_type = " . BAN_USER . " AND is_regex = 1 AND '{$this->username}' REGEXP ban_value ) OR \n" + . " ( ban_type = " . BAN_EMAIL . " AND is_regex = 0 AND ban_value = '{$this->email}' ) OR \n" + . " ( ban_type = " . BAN_EMAIL . " AND is_regex = 1 AND '{$this->email}' REGEXP ban_value ) \n" + . " ORDER BY ban_type ASC;"; + $q = $this->sql($sql); + if ( $db->numrows() > 0 ) { - case BAN_IP: - if(intval($row['is_regex'])==1) { - if(preg_match('#'.$row['ban_value'].'#i', $_SERVER['REMOTE_ADDR'])) + while ( list($reason, $ban_value, $ban_type, $is_regex) = $db->fetchrow_num() ) + { + if ( $ban_type == BAN_IP && $row['is_regex'] != 1 ) { + // check range + $regexp = parse_ip_range_regex($ban_value); + if ( !$regexp ) + { + continue; + } + if ( preg_match("/$regexp/", $_SERVER['REMOTE_ADDR']) ) + { + $banned = true; + } + } + else + { + // User is banned $banned = true; - $reason = $row['reason']; } } - else { - if($row['ban_value']==$_SERVER['REMOTE_ADDR']) { $banned = true; $reason = $row['reason']; } - } - break; - case BAN_USER: - if(intval($row['is_regex'])==1) { - if(preg_match('#'.$row['ban_value'].'#i', $this->username)) + } + $db->free_result(); + } + else + { + // check by IP only + $sql = "SELECT $col_reason, ban_value, ban_type, is_regex FROM " . table_prefix . "banlist WHERE + ( ban_type = " . BAN_IP . " AND is_regex = 0 ) OR + ( ban_type = " . BAN_IP . " AND is_regex = 1 AND '{$_SERVER['REMOTE_ADDR']}' REGEXP ban_value ) + ORDER BY ban_type ASC;"; + $q = $this->sql($sql); + if ( $db->numrows() > 0 ) + { + while ( list($reason, $ban_value, $ban_type, $is_regex) = $db->fetchrow_num() ) + { + if ( $ban_type == BAN_IP && $row['is_regex'] != 1 ) { + // check range + $regexp = parse_ip_range_regex($ban_value); + if ( !$regexp ) + continue; + if ( preg_match("/$regexp/", $_SERVER['REMOTE_ADDR']) ) + { + $banned = true; + } + } + else + { + // User is banned $banned = true; - $reason = $row['reason']; } } - else { - if($row['ban_value']==$this->username) { $banned = true; $reason = $row['reason']; } - } - break; - case BAN_EMAIL: - if(intval($row['is_regex'])==1) { - if(preg_match('#'.$row['ban_value'].'#i', $this->email)) - { - $banned = true; - $reason = $row['reason']; - } - } - else { - if($row['ban_value']==$this->email) { $banned = true; $reason = $row['reason']; } - } - break; - default: - die('Ban error: rule "'.$row['ban_value'].'" has an invalid type ('.$row['ban_type'].')'); } + $db->free_result(); } - if($banned && $paths->get_pageid_from_url() != $paths->nslist['Special'].'CSS') + if ( $banned && $paths->get_pageid_from_url() != $paths->nslist['Special'].'CSS' ) { // This guy is banned - kill the session, kill the database connection, bail out, and be pretty about it die_semicritical('Ban notice', '
You have been banned from this website. Please contact the site administrator for more information.

Reason:
'.$reason.'
'); @@ -1600,11 +1634,11 @@ /** * Registers a user. This does not perform any type of login. - * @param string $username - * @param string $password This should be unencrypted. - * @param string $email - * @param string $real_name Optional, defaults to ''. - * @param bool $coppa Optional. If true, the account is not activated initially and an admin activation request is sent. The caller is responsible for sending the address info and notice. + * @param string New user's username + * @param string This should be unencrypted. + * @param string E-mail address. + * @param string Optional, defaults to ''. + * @param bool Optional. If true, the account is not activated initially and an admin activation request is sent. The caller is responsible for sending the address info and notice. */ function create_user($username, $password, $email, $real_name = '', $coppa = false) @@ -1615,6 +1649,7 @@ $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE); if(!preg_match('#^'.$this->valid_username.'$#', $username)) return 'The username you chose contains invalid characters.'; + $username = str_replace('_', ' ', $username); $user_orig = $username; $username = $this->prepare_text($username); $email = $this->prepare_text($email); diff -r 917dcc6c4ceb -r f088805540ae install.php --- a/install.php Sat Nov 17 22:25:37 2007 -0500 +++ b/install.php Sun Nov 18 20:37:08 2007 -0500 @@ -105,7 +105,7 @@ } if ( !$resumed && $allow_skip ) { - echo_stage_success($stage_id, "[dbg: skipped] $stage_name"); + echo_stage_success($stage_id, $stage_name); return false; } if ( !function_exists($function) ) @@ -142,7 +142,6 @@ $neutral_color = ( $neutral_color == 'A' ) ? 'C' : 'A'; echo '' . htmlspecialchars($stage_name) . 'Done' . "\n"; ob_flush(); - flush(); } function echo_stage_failure($stage_id, $stage_name, $failure_explanation, $resume_stack) @@ -153,12 +152,12 @@ $neutral_color = ( $neutral_color == 'A' ) ? 'C' : 'A'; echo '' . htmlspecialchars($stage_name) . 'Failed' . "\n"; ob_flush(); - flush(); close_install_table(); $post_data = ''; $mysql_error = mysql_error(); foreach ( $_POST as $key => $value ) { + // FIXME: These should really also be sanitized for double quotes $value = htmlspecialchars($value); $key = htmlspecialchars($key); $post_data .= " \n"; @@ -388,11 +387,15 @@ $cacheonoff = is_writable(ENANO_ROOT.'/cache/') ? '1' : '0'; + $admin_user = $_POST['admin_user']; + $admin_user = str_replace('_', ' ', $admin_user); + $admin_user = mysql_real_escape_string($admin_user); + $schema = file_get_contents('schema.sql'); $schema = str_replace('{{SITE_NAME}}', mysql_real_escape_string($_POST['sitename'] ), $schema); $schema = str_replace('{{SITE_DESC}}', mysql_real_escape_string($_POST['sitedesc'] ), $schema); $schema = str_replace('{{COPYRIGHT}}', mysql_real_escape_string($_POST['copyright'] ), $schema); - $schema = str_replace('{{ADMIN_USER}}', mysql_real_escape_string($_POST['admin_user'] ), $schema); + $schema = str_replace('{{ADMIN_USER}}', $admin_user , $schema); $schema = str_replace('{{ADMIN_PASS}}', mysql_real_escape_string($admin_pass ), $schema); $schema = str_replace('{{ADMIN_EMAIL}}', mysql_real_escape_string($_POST['admin_email']), $schema); $schema = str_replace('{{ENABLE_CACHE}}', mysql_real_escape_string($cacheonoff ), $schema); @@ -462,6 +465,7 @@ $key = $aes->hextostring($key); $admin_pass = $aes->encrypt($admin_pass, $key, ENC_HEX); $admin_user = mysql_real_escape_string($_POST['admin_user']); + $admin_user = str_replace('_', ' ', $admin_user); $q = @mysql_query("UPDATE {$_POST['table_prefix']}users SET password='$admin_pass' WHERE username='$admin_user';"); if ( !$q ) @@ -1826,52 +1830,77 @@ err('Hacking attempt was detected in table_prefix.'); start_install_table(); - // The stages connect, decrypt, genkey, and parse are preprocessing and don't do any actual data modification. - // Thus, they need to be run on each retry, e.g. never skipped. - run_installer_stage('connect', $lang->get('install_stg_connect_title'), 'stg_mysql_connect', $lang->get('install_stg_connect_body'), false); - if ( isset($_POST['drop_tables']) ) + + // Are we just trying to auto-rename the config files? If so, skip everything else + if ( !isset($_GET['stage']) || ( isset($_GET['stage']) && $_GET['stage'] != 'renameconfig' ) ) { - // Are we supposed to drop any existing tables? If so, do it now - run_installer_stage('drop', $lang->get('install_stg_drop_title'), 'stg_drop_tables', 'This step never returns failure'); + + // The stages connect, decrypt, genkey, and parse are preprocessing and don't do any actual data modification. + // Thus, they need to be run on each retry, e.g. never skipped. + run_installer_stage('connect', $lang->get('install_stg_connect_title'), 'stg_mysql_connect', $lang->get('install_stg_connect_body'), false); + if ( isset($_POST['drop_tables']) ) + { + // Are we supposed to drop any existing tables? If so, do it now + run_installer_stage('drop', $lang->get('install_stg_drop_title'), 'stg_drop_tables', 'This step never returns failure'); + } + run_installer_stage('decrypt', $lang->get('install_stg_decrypt_title'), 'stg_decrypt_admin_pass', $lang->get('install_stg_decrypt_body'), false); + run_installer_stage('genkey', $lang->get('install_stg_genkey_title', array( 'aes_bits' => AES_BITS )), 'stg_generate_aes_key', $lang->get('install_stg_genkey_body'), false); + run_installer_stage('parse', $lang->get('install_stg_parse_title'), 'stg_parse_schema', $lang->get('install_stg_parse_body'), false); + run_installer_stage('sql', $lang->get('install_stg_sql_title'), 'stg_install', $lang->get('install_stg_sql_body'), false); + run_installer_stage('writeconfig', $lang->get('install_stg_writeconfig_title'), 'stg_write_config', $lang->get('install_stg_writeconfig_body')); + + // Mainstream installation complete - Enano should be usable now + // The stage of starting the API is special because it has to be called out of function context. + // To alleviate this, we have two functions, one that returns success and one that returns failure + // If the Enano API load is successful, the success function is called to report the action to the user + // If unsuccessful, the failure report is sent + + $template_bak = $template; + + $_GET['title'] = 'Main_Page'; + require('includes/common.php'); + + if ( is_object($db) && is_object($session) ) + { + run_installer_stage('startapi', $lang->get('install_stg_startapi_title'), 'stg_start_api_success', '...', false); + } + else + { + run_installer_stage('startapi', $lang->get('install_stg_startapi_title'), 'stg_start_api_failure', $lang->get('install_stg_startapi_body'), false); + } + + // We need to be logged in (with admin rights) before logs can be flushed + $admin_password = stg_decrypt_admin_pass(true); + $session->login_without_crypto($_POST['admin_user'], $admin_password, false); + + // Now that login cookies are set, initialize the session manager and ACLs + $session->start(); + $paths->init(); + + run_installer_stage('importlang', $lang->get('install_stg_importlang_title'), 'stg_import_language', $lang->get('install_stg_importlang_body')); + run_installer_stage('initlogs', $lang->get('install_stg_initlogs_title'), 'stg_init_logs', $lang->get('install_stg_initlogs_body')); + + /* + * HACKERS: + * If you're making a custom distribution of Enano, put all your custom plugin-related code here. + * You have access to the full Enano API as well as being logged in with complete admin rights. + * Don't do anything horrendously fancy here, unless you add a new stage (or more than one) and + * have the progress printed out properly. + */ + + } // check for stage == renameconfig + else + { + // If we did skip the main installer routine, set $template_bak to make the reversal later work properly + $template_bak = $template; } - run_installer_stage('decrypt', $lang->get('install_stg_decrypt_title'), 'stg_decrypt_admin_pass', $lang->get('install_stg_decrypt_body'), false); - run_installer_stage('genkey', $lang->get('install_stg_genkey_title', array( 'aes_bits' => AES_BITS )), 'stg_generate_aes_key', $lang->get('install_stg_genkey_body'), false); - run_installer_stage('parse', $lang->get('install_stg_parse_title'), 'stg_parse_schema', $lang->get('install_stg_parse_body'), false); - run_installer_stage('sql', $lang->get('install_stg_sql_title'), 'stg_install', $lang->get('install_stg_sql_body'), false); - run_installer_stage('writeconfig', $lang->get('install_stg_writeconfig_title'), 'stg_write_config', $lang->get('install_stg_writeconfig_body')); + + // Final step is to rename the config file + // In early revisions of 1.0.2, this step was performed prior to the initialization of the Enano API. It was decided to move + // this stage to the end because it will fail more often than any other stage, thus making alternate routes imperative. If this + // stage fails, then no big deal, we'll just have the user rename the files manually and then let them see the pretty success message. run_installer_stage('renameconfig', $lang->get('install_stg_rename_title'), 'stg_rename_config', $lang->get('install_stg_rename_body')); - // Mainstream installation complete - Enano should be usable now - // The stage of starting the API is special because it has to be called out of function context. - // To alleviate this, we have two functions, one that returns success and one that returns failure - // If the Enano API init is successful, the success function is called to report the action to the user - // If unsuccessful, the failure report is sent - - $template_bak = $template; - - $_GET['title'] = 'Main_Page'; - require('includes/common.php'); - - if ( is_object($db) && is_object($session) ) - { - run_installer_stage('startapi', $lang->get('install_stg_startapi_title'), 'stg_start_api_success', '...', false); - } - else - { - run_installer_stage('startapi', $lang->get('install_stg_startapi_title'), 'stg_start_api_failure', $lang->get('install_stg_startapi_body'), false); - } - - // We need to be logged in (with admin rights) before logs can be flushed - $admin_password = stg_decrypt_admin_pass(true); - $session->login_without_crypto($_POST['admin_user'], $admin_password, false); - - // Now that login cookies are set, initialize the session manager and ACLs - $session->start(); - $paths->init(); - - run_installer_stage('importlang', $lang->get('install_stg_importlang_title'), 'stg_import_language', $lang->get('install_stg_importlang_body')); - - run_installer_stage('initlogs', $lang->get('install_stg_initlogs_title'), 'stg_init_logs', $lang->get('install_stg_initlogs_body')); close_install_table(); unset($template); diff -r 917dcc6c4ceb -r f088805540ae plugins/SpecialAdmin.php --- a/plugins/SpecialAdmin.php Sat Nov 17 22:25:37 2007 -0500 +++ b/plugins/SpecialAdmin.php Sun Nov 18 20:37:08 2007 -0500 @@ -2228,17 +2228,14 @@ } if ( $type == BAN_IP ) { - // parse a range of addresses - $range = parse_ip_range($entry); - if ( !$range ) + if ( !isset($_POST['regex']) ) { - $error = true; - echo '
Malformed IP address expression.
'; - break; + // as of 1.0.2 parsing is done at runtime + $entries[] = $entry; } - foreach ($range as $ip) + else { - $entries[] = $ip; + $entries[] = $entry; } } else @@ -2290,7 +2287,7 @@ ?> Type:
Rule:
- You can ban multiple IP addresses, users, or e-mail addresses by separating entries with a single comma (User1,User2). Do not put a space after the comma. For IP addresses, you may specify ranges like 172|192.168.4-30|90-167.1-90, which will turn into 172 and 192 . 168 . 4-30 and 90-167 . 1 - 90, which matches 18,899 IP addresses. Don't specify large ranges (like the example one here) at once or you risk temporarily (~60sec) overloading the server.
+ You can ban multiple IP addresses, users, or e-mail addresses by separating entries with a single comma (User1,User2). Do not put a space after the comma. For IP addresses, you may specify ranges like 172|192.168.4-30|90-167.1-90, which will turn into 172 and 192 . 168 . 4-30 and 90-167 . 1 - 90, which matches 18,899 IP addresses.
Reason to show to the banned user:
(advanced users only)
diff -r 917dcc6c4ceb -r f088805540ae plugins/SpecialUserFuncs.php --- a/plugins/SpecialUserFuncs.php Sat Nov 17 22:25:37 2007 -0500 +++ b/plugins/SpecialUserFuncs.php Sun Nov 18 20:37:08 2007 -0500 @@ -820,7 +820,7 @@ if(!namegood && ( field.name == 'username' || field.name == '_nil' ) ) { //if(frm.username.value.match(/^([A-z0-9 \!@\-\(\)]+){2,}$/ig)) - var regex = new RegExp('^([^<>_&\?]+){2,}$', 'ig'); + var regex = new RegExp('^([^<>&\?]+){2,}$', 'ig'); if ( frm.username.value.match(regex) ) { document.getElementById('s_username').src='/images/unknown.gif'; @@ -885,10 +885,8 @@ if(!namegood) { - + var regex = new RegExp('^([^<>&\?]+){2,}$', 'ig'); + if ( frm.username.value.match(regex) ) { document.getElementById('s_username').src='/images/unknown.gif'; document.getElementById('e_username').innerHTML = ' ';