# HG changeset patch # User Dan # Date 1194310240 18000 # Node ID 07cf7b0c175f44c883fa042b51c7314fa08b75ba # Parent c15c1d2bdeb8f7b09131603a081383e4cfcd2b63 Out with the old, in with the new. Welcome to Enano's new installer framework! diff -r c15c1d2bdeb8 -r 07cf7b0c175f install.php --- a/install.php Mon Nov 05 17:11:37 2007 -0500 +++ b/install.php Mon Nov 05 19:50:40 2007 -0500 @@ -64,6 +64,509 @@ 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); + 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); + 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); + 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); + 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 $db_name;", $conn); + 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); + 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); + 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 . '' . htmlspecialchars(print_r($schema, true)) . ''; - // break; - - echo 'done!
Please rename config.new.php manually to config.php. If you selected Tiny URLs, please also rename .htaccess.new to .htaccess.'); - - if ( $_POST['urlscheme'] == 'tiny' ) - { - if ( !@rename('./.htaccess.new', './.htaccess') ) - err('failed!
Please rename .htaccess.new manually to .htaccess.');
- }
-
- echo 'done!
Starting the Enano API...';
-
- $template_bak = $template;
-
- // Get Enano loaded
- $_GET['title'] = 'Main_Page';
- require('includes/common.php');
-
// We need to be logged in (with admin rights) before logs can be flushed
- $session->login_without_crypto($_POST['admin_user'], $dec, false);
+ $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('initlogs', 'Initialize logs', 'stg_init_logs', 'The session manager denied the request to flush logs for the main page.
+ While under most circumstances you can still finish the installation, you should be aware that some servers cannot
+ properly set cookies due to limitations with PHP. These limitations are exposed primarily when this issue is encountered during installation. If you choose
+ to finish the installation, please be aware that you may be unable to log into your site.');
+ close_install_table();
+
unset($template);
$template =& $template_bak;
-
- echo 'done!
Initializing logs...';
-
- $q = $db->sql_query('INSERT INTO ' . $_POST['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']) . '\');', $conn);
- if ( !$q )
- err('Error setting up logs: '.$db->get_error());
-
- // This is only in RAM; it's meant to correct a race condition encountered by several testers
- $session->acl_merge(array(
- 'clear_logs' => AUTH_ALLOW
- ));
-
- if ( !$session->get_permissions('clear_logs') )
- {
- echo '
The session manager denied the request to flush logs for the main page.
- While under most circumstances you can still finish the installation, you should be aware that some servers cannot
- properly set cookies due to limitations with PHP. These limitations are exposed primarily when this issue is encountered during installation. If you choose
- to finish the installation, please be aware that you may be unable to log into your site.
Review any warnings above, and then click here to finish the installation.'; + + echo '
Review any warnings above, and then click here to finish the installation.'; // echo '';