diff -r b11a2f1353c0 -r a78537db2850 install.php --- a/install.php Sat Nov 03 14:30:53 2007 -0400 +++ b/install.php Tue Nov 06 10:53:33 2007 -0500 @@ -64,6 +64,527 @@ require('includes/functions.php'); strip_magic_quotes_gpc(); +$neutral_color = 'C'; + +// +// INSTALLER LIBRARY +// + +function run_installer_stage($stage_id, $stage_name, $function, $failure_explanation, $allow_skip = true) +{ + static $resumed = false; + static $resume_stack = array(); + + if ( empty($resume_stack) && isset($_POST['resume_stack']) && preg_match('/[a-z_]+((\|[a-z_]+)+)/', $_POST['resume_stack']) ) + { + $resume_stack = explode('|', $_POST['resume_stack']); + } + + $already_run = false; + if ( in_array($stage_id, $resume_stack) ) + { + $already_run = true; + } + + if ( !$resumed ) + { + if ( !isset($_GET['stage']) ) + $resumed = true; + if ( isset($_GET['stage']) && $_GET['stage'] == $stage_id ) + { + $resumed = true; + } + } + if ( !$resumed && $allow_skip ) + { + echo_stage_success($stage_id, "[dbg: skipped] $stage_name"); + return false; + } + if ( !function_exists($function) ) + die('libenanoinstall: CRITICAL: function "' . $function . '" for ' . $stage_id . ' doesn\'t exist'); + $result = @call_user_func($function, false, $already_run); + if ( $result ) + { + echo_stage_success($stage_id, $stage_name); + $resume_stack[] = $stage_id; + return true; + } + else + { + echo_stage_failure($stage_id, $stage_name, $failure_explanation, $resume_stack); + return false; + } +} + +function start_install_table() +{ + echo '
SECURITY: malformed database name
"); + + // First, try to connect using the normal credentials + $conn = @mysql_connect($_POST['db_host'], $_POST['db_user'], $_POST['db_pass']); + if ( !$conn ) + { + // Connection failed. Do we have the root username and password? + if ( !empty($_POST['db_root_user']) && !empty($_POST['db_root_pass']) ) + { + $conn_root = @mysql_connect($_POST['db_host'], $_POST['db_root_user'], $_POST['db_root_pass']); + if ( !$conn_root ) + { + // Couldn't connect using either set of credentials. Bail out. + return false; + } + // Create the user account + $q = @mysql_query("GRANT ALL PRIVILEGES ON test.* TO '{$db_user}'@'localhost' IDENTIFIED BY '$db_pass' WITH GRANT OPTION;", $conn_root); + if ( !$q ) + { + return false; + } + // Revoke privileges from test, we don't need them + $q = @mysql_query("REVOKE ALL PRIVILEGES ON test.* FROM '{$db_user}'@'localhost';", $conn_root); + if ( !$q ) + { + return false; + } + if ( $_POST['db_host'] != 'localhost' && $_POST['db_host'] != '127.0.0.1' && $_POST['db_host'] != '::1' ) + { + // If not connecting to a server running on localhost, allow from any host + // this is safer than trying to detect the hostname of the webserver, but less secure + $q = @mysql_query("GRANT ALL PRIVILEGES ON test.* TO '{$db_user}'@'%' IDENTIFIED BY '$db_pass' WITH GRANT OPTION;", $conn_root); + if ( !$q ) + { + return false; + } + // Revoke privileges from test, we don't need them + $q = @mysql_query("REVOKE ALL PRIVILEGES ON test.* FROM '{$db_user}'@'%';", $conn_root); + if ( !$q ) + { + return false; + } + } + } + } + $q = @mysql_query("USE $db_name;", $conn); + if ( !$q ) + { + // access denied to the database; try the whole root schenanegan again + if ( !empty($_POST['db_root_user']) && !empty($_POST['db_root_pass']) ) + { + $conn_root = @mysql_connect($_POST['db_host'], $_POST['db_root_user'], $_POST['db_root_pass']); + if ( !$conn_root ) + { + // Couldn't connect as root; bail out + return false; + } + // create the database, if it doesn't exist + $q = @mysql_query("CREATE DATABASE IF NOT EXISTS $db_name;", $conn_root); + if ( !$q ) + { + // this really should never fail, so don't give any tolerance to it + return false; + } + // we're in with root rights; grant access to the database + $q = @mysql_query("GRANT ALL PRIVILEGES ON $db_name.* TO '{$db_user}'@'localhost';", $conn_root); + if ( !$q ) + { + return false; + } + if ( $_POST['db_host'] != 'localhost' && $_POST['db_host'] != '127.0.0.1' && $_POST['db_host'] != '::1' ) + { + $q = @mysql_query("GRANT ALL PRIVILEGES ON $db_name.* TO '{$db_user}'@'%';", $conn_root); + if ( !$q ) + { + return false; + } + } + } + else + { + return false; + } + // try again + $q = @mysql_query("USE $db_name;", $conn); + if ( !$q ) + { + // really failed this time; bail out + return false; + } + } + // connected and database exists + return true; +} + +function stg_drop_tables() +{ + $conn = stg_mysql_connect(true); + if ( !$conn ) + return false; + // Our list of tables included in Enano + $tables = Array( 'categories', 'comments', 'config', 'logs', 'page_text', 'session_keys', 'pages', 'users', 'users_extra', 'themes', 'buddies', 'banlist', 'files', 'privmsgs', 'sidebar', 'hits', 'search_index', 'groups', 'group_members', 'acl', 'search_cache', 'tags', 'page_groups', 'page_group_members' ); + + // Drop each table individually; if it fails, it probably means we're trying to drop a + // table that didn't exist in the Enano version we're deleting the database for. + foreach ( $tables as $table ) + { + // Remember that table_prefix is sanitized. + $table = "{$_POST['table_prefix']}$table"; + @mysql_query("DROP TABLE $table;", $conn); + } + return true; +} + +function stg_decrypt_admin_pass($act_get = false) +{ + static $decrypted_pass = false; + if ( $act_get ) + return $decrypted_pass; + + $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE); + + if ( !empty($_POST['crypt_data']) ) + { + require('config.new.php'); + if ( !isset($cryptkey) ) + { + return false; + } + define('_INSTRESUME_AES_KEYBACKUP', $key); + $key = hexdecode($cryptkey); + + $decrypted_pass = $aes->decrypt($_POST['crypt_data'], $key, ENC_HEX); + + } + else + { + $decrypted_pass = $_POST['admin_pass']; + } + if ( empty($decrypted_pass) ) + return false; + return true; +} + +function stg_generate_aes_key($act_get = false) +{ + static $key = false; + if ( $act_get ) + return $key; + + $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE); + $key = $aes->gen_readymade_key(); + return true; +} + +function stg_parse_schema($act_get = false) +{ + static $schema; + if ( $act_get ) + return $schema; + + $admin_pass = stg_decrypt_admin_pass(true); + $key = stg_generate_aes_key(true); + $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE); + $key = $aes->hextostring($key); + $admin_pass = $aes->encrypt($admin_pass, $key, ENC_HEX); + + $cacheonoff = is_writable(ENANO_ROOT.'/cache/') ? '1' : '0'; + + $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_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); + $schema = str_replace('{{REAL_NAME}}', '', $schema); + $schema = str_replace('{{TABLE_PREFIX}}', $_POST['table_prefix'], $schema); + $schema = str_replace('{{VERSION}}', ENANO_VERSION, $schema); + $schema = str_replace('{{ADMIN_EMBED_PHP}}', $_POST['admin_embed_php'], $schema); + // Not anymore!! :-D + // $schema = str_replace('{{BETA_VERSION}}', ENANO_BETA_VERSION, $schema); + + if(isset($_POST['wiki_mode'])) + { + $schema = str_replace('{{WIKI_MODE}}', '1', $schema); + } + else + { + $schema = str_replace('{{WIKI_MODE}}', '0', $schema); + } + + // Build an array of queries + $schema = explode("\n", $schema); + + foreach ( $schema as $i => $sql ) + { + $query =& $schema[$i]; + $t = trim($query); + if ( empty($t) || preg_match('/^(\#|--)/i', $t) ) + { + unset($schema[$i]); + unset($query); + } + } + + $schema = array_values($schema); + $schema = implode("\n", $schema); + $schema = explode(";\n", $schema); + + foreach ( $schema as $i => $sql ) + { + $query =& $schema[$i]; + if ( substr($query, ( strlen($query) - 1 ), 1 ) != ';' ) + { + $query .= ';'; + } + } + + return true; +} + +function stg_install($_unused, $already_run) +{ + // This one's pretty easy. + $conn = stg_mysql_connect(true); + if ( !is_resource($conn) ) + return false; + $schema = stg_parse_schema(true); + if ( !is_array($schema) ) + return false; + + // If we're resuming installation, the encryption key was regenerated. + // This means we'll have to update the encrypted password in the database. + if ( $already_run ) + { + $admin_pass = stg_decrypt_admin_pass(true); + $key = stg_generate_aes_key(true); + $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE); + $key = $aes->hextostring($key); + $admin_pass = $aes->encrypt($admin_pass, $key, ENC_HEX); + $admin_user = mysql_real_escape_string($_POST['admin_user']); + + $q = @mysql_query("UPDATE {$_POST['table_prefix']}users SET password='$admin_pass' WHERE username='$admin_user';"); + if ( !$q ) + { + echo 'MySQL return: ' . mysql_error() . '
'; + return false; + } + + return true; + } + + // OK, do the loop, baby!!! + foreach($schema as $q) + { + $r = mysql_query($q, $conn); + if ( !$r ) + { + echo 'MySQL return: ' . mysql_error() . '
'; + return false; + } + } + + return true; +} + +function stg_write_config() +{ + $privkey = stg_generate_aes_key(true); + + switch($_POST['urlscheme']) + { + case "ugly": + default: + $cp = scriptPath.'/index.php?title='; + break; + case "short": + $cp = scriptPath.'/index.php/'; + break; + case "tiny": + $cp = scriptPath.'/'; + break; + } + + if ( $_POST['urlscheme'] == 'tiny' ) + { + $contents = '# Begin Enano rules +RewriteEngine on +RewriteCond %{REQUEST_FILENAME} !-d +RewriteCond %{REQUEST_FILENAME} !-f +RewriteRule ^(.+) '.scriptPath.'/index.php?title=$1 [L,QSA] +RewriteRule \.(php|html|gif|jpg|png|css|js)$ - [L] +# End Enano rules +'; + if ( file_exists('./.htaccess') ) + $ht = fopen(ENANO_ROOT.'/.htaccess', 'a+'); + else + $ht = fopen(ENANO_ROOT.'/.htaccess.new', 'w'); + if ( !$ht ) + return false; + fwrite($ht, $contents); + fclose($ht); + } + + $config_file = ''; + + $cf_handle = fopen(ENANO_ROOT.'/config.new.php', 'w'); + if ( !$cf_handle ) + return false; + fwrite($cf_handle, $config_file); + + fclose($cf_handle); + + return true; +} + +function _stg_rename_config_revert() +{ + if ( file_exists('./config.php') ) + { + @rename('./config.php', './config.new.php'); + } + + $handle = @fopen('./config.php.new', 'w'); + if ( !$handle ) + return false; + $contents = ''; + fwrite($handle, $contents); + fclose($handle); + return true; +} + +function stg_rename_config() +{ + if ( !@rename('./config.new.php', './config.php') ) + { + echo 'Can\'t rename config.php
'; + _stg_rename_config_revert(); + return false; + } + + if ( $_POST['urlscheme'] == 'tiny' && !file_exists('./.htaccess') ) + { + if ( !@rename('./.htaccess.new', './.htaccess') ) + { + echo 'Can\'t rename .htaccess
'; + _stg_rename_config_revert(); + return false; + } + } + return true; +} + +function stg_start_api_success() +{ + return true; +} + +function stg_start_api_failure() +{ + return false; +} + +function stg_init_logs() +{ + global $db, $session, $paths, $template, $plugins; // Common objects + + $q = $db->sql_query('INSERT INTO ' . table_prefix . 'logs(log_type,action,time_id,date_string,author,page_text,edit_summary) VALUES(\'security\', \'install_enano\', ' . time() . ', \'' . date('d M Y h:i a') . '\', \'' . mysql_real_escape_string($_POST['admin_user']) . '\', \'' . mysql_real_escape_string(ENANO_VERSION) . '\', \'' . mysql_real_escape_string($_SERVER['REMOTE_ADDR']) . '\');'); + if ( !$q ) + { + echo 'MySQL return: ' . mysql_error() . '
'; + return false; + } + + if ( !$session->get_permissions('clear_logs') ) + { + echo '$session: denied clear_logs
'; + return false; + } + + PageUtils::flushlogs('Main_Page', 'Article'); + + return true; +} //die('Key size: ' . AES_BITS . 'ERROR: Cannot open config.php for writing - exiting!
'; @@ -759,37 +1280,38 @@ fwrite($handle, ''); fclose($handle); } - ?> + // Sorry for the ugly hack, but this f***s up jEdit badly. + echo ' + '; + ?>