You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

setup.php 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  1. <?php
  2. /**
  3. * Postfix Admin
  4. *
  5. * LICENSE
  6. * This source file is subject to the GPL license that is bundled with
  7. * this package in the file LICENSE.TXT.
  8. *
  9. * Further details on the project are available at http://postfixadmin.sf.net
  10. *
  11. * @version $Id$
  12. * @license GNU GPL v2 or later.
  13. *
  14. * File: setup.php
  15. * Used to help ensure a server is setup appropriately during installation/setup.
  16. * After setup, it should be renamed or removed.
  17. *
  18. * Template File: -none-
  19. *
  20. * Template Variables: -none-
  21. *
  22. * Form POST \ GET Variables: -none-
  23. */
  24. define('POSTFIXADMIN', 1); # by defining it here, common.php will not start a session.
  25. require_once(dirname(__FILE__).'/common.php'); # make sure correct common.php is used.
  26. $CONF['show_header_text'] = 'NO';
  27. $CONF['theme_logo'] = 'images/logo-default.png';
  28. $CONF['theme_css'] = 'css/default.css';
  29. require(dirname(__FILE__) . '/../templates/header.php');
  30. ?>
  31. <div class='setup'>
  32. <h2>Postfix Admin Setup Checker</h2>
  33. <p>Running software:
  34. <ul>
  35. <?php
  36. //
  37. // Check for availablilty functions
  38. //
  39. $f_phpversion = function_exists("phpversion");
  40. $f_apache_get_version = function_exists("apache_get_version");
  41. $f_get_magic_quotes_gpc = function_exists("get_magic_quotes_gpc");
  42. $f_mysql_connect = function_exists("mysql_connect");
  43. $f_mysqli_connect = function_exists("mysqli_connect");
  44. $f_pg_connect = function_exists("pg_connect");
  45. $f_sqlite_open = class_exists("SQLite3");
  46. $f_session_start = function_exists("session_start");
  47. $f_preg_match = function_exists("preg_match");
  48. $f_mb_encode_mimeheader = function_exists("mb_encode_mimeheader");
  49. $f_imap_open = function_exists("imap_open");
  50. $file_config = file_exists(realpath("./../config.inc.php"));
  51. $file_local_config = file_exists(realpath("./../config.local.php"));
  52. $error = 0;
  53. $errormsg = array();
  54. //
  55. // Check for PHP version
  56. //
  57. $phpversion = 'unknown-version';
  58. if ($f_phpversion == 1) {
  59. if (phpversion() < 5) {
  60. print "<li><b>Error: Depends on: PHP v5+</b><br /></li>\n";
  61. $error += 1;
  62. } elseif (version_compare(phpversion(), '5.2.3') < 0) {
  63. # smarty uses htmlentities() with 4 parameters, the 4th parameter was introduced in PHP 5.2.3
  64. # older PHP versions will cause warnings
  65. $phpversion = 5;
  66. print "<li><b>Recommended PHP version: >= 5.2.3, you have " . phpversion() . "</b></li>\n";
  67. } else {
  68. $phpversion = 5;
  69. print "<li>PHP version " . phpversion() . "</li>\n";
  70. }
  71. # TODO: check for PHP >= 5.2.3 - smarty uses htmlentities with 4 parameters. The forth parameter was added in PHP 5.2.3, older versions will give a warning
  72. } else {
  73. print "<li><b>Unable to check for PHP version. (missing function: phpversion())</b></li>\n";
  74. }
  75. //
  76. // Check for Apache version
  77. //
  78. if ($f_apache_get_version == 1) {
  79. print "<li>" . apache_get_version() . "</li>\n";
  80. } else {
  81. # not running on Apache.
  82. # However postfixadmin _is_ running, so obviously we are on a supported webserver ;-))
  83. # No need to confuse the user with a warning.
  84. }
  85. print "</ul>";
  86. print "<p>Checking for dependencies:\n";
  87. print "<ul>\n";
  88. //
  89. // Check for Magic Quotes
  90. //
  91. if ($f_get_magic_quotes_gpc == 1) {
  92. if (get_magic_quotes_gpc() == 0) {
  93. print "<li>Magic Quotes: Disabled - OK</li>\n";
  94. } else {
  95. print "<li><b>Warning: Magic Quotes: ON (internal workaround used)</b></li>\n";
  96. }
  97. } else {
  98. print "<li><b>Unable to check for Magic Quotes. (missing function: get_magic_quotes_gpc())</b></li>\n";
  99. }
  100. //
  101. // Check for config.inc.php
  102. //
  103. $config_loaded = 0;
  104. if ($file_config == 1) {
  105. print "<li>Depends on: presence config.inc.php - OK</li>\n";
  106. require_once(dirname(__FILE__) .'/../config.inc.php');
  107. $config_loaded = 1;
  108. if (isset($CONF['configured'])) {
  109. if ($CONF['configured'] === true) {
  110. print "<li>Checking \$CONF['configured'] - OK\n";
  111. } else {
  112. print "<li><b>Warning: \$CONF['configured'] is 'false'.<br>\n";
  113. print "You must edit your config.local.php and change this to true (this indicates you've created the database and user)</b>\n";
  114. }
  115. }
  116. } else {
  117. print "<li><b>Error: Depends on: presence config.inc.php - NOT FOUND</b><br /></li>\n";
  118. print "Create the file, and edit as appropriate (e.g. select database type etc)<br />";
  119. print "For example:<br />\n";
  120. print "<code><pre>cp config.inc.php.sample config.inc.php</pre></code>\n";
  121. $error += 1;
  122. }
  123. //
  124. // Check for config.local.php
  125. //
  126. if ($file_local_config == 1) {
  127. print "<li>Depends on: presence config.local.php - OK</li>\n";
  128. } else {
  129. print "<li><b>Warning: config.local.php - NOT FOUND</b><br /></li>\n";
  130. print "It's Recommended to store your own settings in config.local.php instead of editing config.inc.php<br />";
  131. print "Create the file, and edit as appropriate (e.g. select database type etc)<br />";
  132. }
  133. //
  134. // Check if there is support for at least 1 database
  135. //
  136. if (($f_mysql_connect == 0) and ($f_mysqli_connect == 0) and ($f_pg_connect == 0) and ($f_sqlite_open == 0)) {
  137. print "<li><b>Error: There is no database support in your PHP setup</b><br />\n";
  138. print "To install MySQL 3.23 or 4.0 support on FreeBSD:<br />\n";
  139. print "<pre>% cd /usr/ports/databases/php{$phpversion}-mysql/\n";
  140. print "% make clean install\n";
  141. print " - or with portupgrade -\n";
  142. print "% portinstall php{$phpversion}-mysql</pre>\n";
  143. if ($phpversion >= 5) {
  144. print "To install MySQL 4.1 support on FreeBSD:<br />\n";
  145. print "<pre>% cd /usr/ports/databases/php5-mysqli/\n";
  146. print "% make clean install\n";
  147. print " - or with portupgrade -\n";
  148. print "% portinstall php5-mysqli</pre>\n";
  149. }
  150. print "To install PostgreSQL support on FreeBSD:<br />\n";
  151. print "<pre>% cd /usr/ports/databases/php{$phpversion}-pgsql/\n";
  152. print "% make clean install\n";
  153. print " - or with portupgrade -\n";
  154. print "% portinstall php{$phpversion}-pgsql</pre></li>\n";
  155. $error += 1;
  156. }
  157. //
  158. // MySQL 3.23, 4.0 functions
  159. //
  160. if ($f_mysql_connect == 1) {
  161. print "<li>Depends on: MySQL 3.23, 4.0 - OK</li>\n";
  162. }
  163. //
  164. // MySQL 4.1 functions
  165. //
  166. if ($phpversion >= 5) {
  167. if ($f_mysqli_connect == 1) {
  168. print "<li>Depends on: MySQL 4.1 - OK\n";
  169. if (!($config_loaded && $CONF['database_type'] == 'mysqli')) {
  170. print "<br>(change the database_type to 'mysqli' in config.local.php if you want to use MySQL)\n";
  171. }
  172. print "</li>";
  173. }
  174. }
  175. //
  176. // PostgreSQL functions
  177. //
  178. if ($f_pg_connect == 1) {
  179. print "<li>Depends on: PostgreSQL - OK \n";
  180. if (!($config_loaded && $CONF['database_type'] == 'pgsql')) {
  181. print "<br>(change the database_type to 'pgsql' in config.local.php if you want to use PostgreSQL)\n";
  182. }
  183. print "</li>";
  184. }
  185. if ($f_sqlite_open == 1) {
  186. print "<li>Depends on: SQLite - OK \n";
  187. if (!($config_loaded && db_sqlite())) {
  188. print "<br>(change the database_type to 'sqlite' in config.local.php if you want to use SQLite)\n";
  189. }
  190. print "</li>";
  191. }
  192. //
  193. // Database connection
  194. //
  195. if ($config_loaded) {
  196. list($link, $error_text) = db_connect(true);
  197. if ($error_text == "") {
  198. print "<li>Testing database connection (using {$CONF['database_type']}) - OK</li>";
  199. } else {
  200. print "<li><b>Error: Can't connect to database</b><br />\n";
  201. print "Please edit the \$CONF['database_*'] parameters in config.local.php.\n";
  202. print "$error_text</li>\n";
  203. $error ++;
  204. }
  205. }
  206. //
  207. // Session functions
  208. //
  209. if ($f_session_start == 1) {
  210. print "<li>Depends on: session - OK</li>\n";
  211. } else {
  212. print "<li><b>Error: Depends on: session - NOT FOUND</b><br />\n";
  213. print "To install session support on FreeBSD:<br />\n";
  214. print "<pre>% cd /usr/ports/www/php$phpversion-session/\n";
  215. print "% make clean install\n";
  216. print " - or with portupgrade -\n";
  217. print "% portinstall php$phpversion-session</pre></li>\n";
  218. $error += 1;
  219. }
  220. //
  221. // PCRE functions
  222. //
  223. if ($f_preg_match == 1) {
  224. print "<li>Depends on: pcre - OK</li>\n";
  225. } else {
  226. print "<li><b>Error: Depends on: pcre - NOT FOUND</b><br />\n";
  227. print "To install pcre support on FreeBSD:<br />\n";
  228. print "<pre>% cd /usr/ports/devel/php$phpversion-pcre/\n";
  229. print "% make clean install\n";
  230. print " - or with portupgrade -\n";
  231. print "% portinstall php$phpversion-pcre</pre></li>\n";
  232. $error += 1;
  233. }
  234. //
  235. // Multibyte functions
  236. //
  237. if ($f_mb_encode_mimeheader == 1) {
  238. print "<li>Depends on: multibyte string - OK</li>\n";
  239. } else {
  240. print "<li><b>Error: Depends on: multibyte string - NOT FOUND</b><br />\n";
  241. print "To install multibyte string support, install php$phpversion-mbstring</li>\n";
  242. $error += 1;
  243. }
  244. //
  245. // Imap functions
  246. //
  247. if ($f_imap_open == 1) {
  248. print "<li>Depends on: IMAP functions - OK</li>\n";
  249. } else {
  250. print "<li><b>Warning: Depends on: IMAP functions - NOT FOUND</b><br />\n";
  251. print "To install IMAP support, install php$phpversion-imap<br />\n";
  252. print "Without IMAP support, you won't be able to create subfolders when creating mailboxes.</li>\n";
  253. # $error += 1;
  254. }
  255. print "</ul>";
  256. if ($error != 0) {
  257. print "<p><b>Please fix the errors listed above.</b></p>";
  258. } else {
  259. print "<p>Everything seems fine... attempting to create/update database structure</p>\n";
  260. require_once(dirname(__FILE__) .'/upgrade.php');
  261. $tUsername = '';
  262. $setupMessage = '';
  263. $lostpw_error = 0;
  264. $setuppw = "";
  265. if (isset($CONF['setup_password'])) {
  266. $setuppw = $CONF['setup_password'];
  267. }
  268. if (safepost("form") == "setuppw") {
  269. # "setup password" form submitted
  270. if (safepost('setup_password') != safepost('setup_password2')) {
  271. $setupMessage = "The two passwords differ!";
  272. $lostpw_error = 1;
  273. } else {
  274. list($lostpw_error, $lostpw_result) = check_setup_password(safepost('setup_password'), 1);
  275. $setupMessage = $lostpw_result;
  276. $setuppw = "changed";
  277. }
  278. } elseif (safepost("form") == "createadmin") {
  279. # "create admin" form submitted
  280. list($pw_check_error, $pw_check_result) = check_setup_password(safepost('setup_password'));
  281. if ($pw_check_result != 'pass_OK') {
  282. $error += 1;
  283. $setupMessage = $pw_check_result;
  284. }
  285. if ($error == 0 && $pw_check_result == 'pass_OK') {
  286. // XXX need to ensure domains table includes an 'ALL' entry.
  287. $table_domain = table_by_key('domain');
  288. $r = db_query("SELECT * FROM $table_domain WHERE domain = 'ALL'");
  289. if ($r['rows'] == 0) {
  290. db_insert('domain', array('domain' => 'ALL', 'description' => '', 'transport' => '')); // all other fields should default through the schema.
  291. }
  292. $values = array(
  293. 'username' => safepost('username'),
  294. 'password' => safepost('password'),
  295. 'password2' => safepost('password2'),
  296. 'superadmin' => 1,
  297. 'domains' => array(),
  298. 'active' => 1,
  299. );
  300. list($error, $setupMessage, $errormsg) = create_admin($values);
  301. if ($error != 0) {
  302. $tUsername = htmlentities($values['username']);
  303. } else {
  304. $setupMessage .= "<p>You are done with your basic setup. ";
  305. $setupMessage .= "<p><b>You can now <a href='login.php'>login to PostfixAdmin</a> using the account you just created.</b>";
  306. }
  307. }
  308. }
  309. if (($setuppw == "" || $setuppw == "changeme" || safeget("lostpw") == 1 || $lostpw_error != 0) /* && $_SERVER['REQUEST_METHOD'] != "POST" */) {
  310. # show "create setup password" form?>
  311. <div class="standout"><?php print $setupMessage; ?></div>
  312. <div id="edit_form">
  313. <form name="setuppw" method="post" action="setup.php">
  314. <input type="hidden" name="form" value="setuppw" />
  315. <table>
  316. <tr>
  317. <td colspan="3"><h3>Change setup password</h3></td>
  318. </tr>
  319. <tr>
  320. <td><label for="setup_password">Setup password</label></td>
  321. <td><input class="flat" type="password" name="setup_password" value="" /></td>
  322. <td></td>
  323. </tr>
  324. <tr>
  325. <td><label for="setup_password2">Setup password (again)</label></td>
  326. <td><input class="flat" type="password" name="setup_password2" value="" /></td>
  327. <td></td>
  328. </tr>
  329. <tr>
  330. <td colspan="3" class="hlp_center"><input class="button" type="submit" name="submit" value="Generate password hash" /></td>
  331. </tr>
  332. </table>
  333. </form>
  334. </div>
  335. <?php
  336. } elseif (
  337. (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] == "GET") ||
  338. $error != 0 ||
  339. $lostpw_error == 0) {
  340. ?>
  341. <div class="standout"><?php print $setupMessage; ?></div>
  342. <div id="edit_form">
  343. <form name="create_admin" method="post">
  344. <input type="hidden" name="form" value="createadmin" />
  345. <table>
  346. <td colspan="3"><h3>Create superadmin account</h3></td>
  347. </tr>
  348. <tr>
  349. <td><label for="setup_password">Setup password</label></td>
  350. <td><input id=setup_password class="flat" type="password" name="setup_password" value="" /></td>
  351. <td><a href="setup.php?lostpw=1">Lost password?</a></td>
  352. </tr>
  353. <tr>
  354. <td><label for="username"><?php print $PALANG['admin'] . ":"; ?></label></td>
  355. <td><input id="username" class="flat" type="text" name="username" value="<?php print $tUsername; ?>" /></td>
  356. <td><?= _error_field($errormsg, 'username'); ?> <?php print $PALANG['email_address'] ?></td>
  357. </tr>
  358. <tr>
  359. <td><label for="password"><?php print $PALANG['password'] . ":"; ?></label></td>
  360. <td><input id="password" class="flat" type="password" name="password" /></td>
  361. <td><?= _error_field($errormsg, 'password'); ?></td>
  362. </tr>
  363. <tr>
  364. <td><label for="password2"><?php print $PALANG['password_again'] . ":"; ?></label></td>
  365. <td><input id="password2" class="flat" type="password" name="password2" /></td>
  366. <td><?= _error_field($errormsg, 'password2'); ?></td>
  367. </tr>
  368. <tr>
  369. <td colspan="3" class="hlp_center"><input class="button" type="submit" name="submit" value="<?php print $PALANG['pAdminCreate_admin_button']; ?>" /></td>
  370. </tr>
  371. </table>
  372. </form>
  373. </div>
  374. <?php
  375. } ?>
  376. <b>Since version 2.3 there is no requirement to delete setup.php!</b><br />
  377. <b>Check the config.inc.php file for any other settings that you might need to change!<br />
  378. <?php
  379. }
  380. ?>
  381. </div>
  382. </body>
  383. </html>
  384. <?php
  385. function _error_field($errors, $key) {
  386. if (!isset($errors[$key])) {
  387. return '';
  388. }
  389. return "<span style='color: red'>{$errors[$key]}</span>";
  390. }
  391. function generate_setup_password_salt() {
  392. $salt = time() . '*' . $_SERVER['REMOTE_ADDR'] . '*' . mt_rand(0, 60000);
  393. $salt = md5($salt);
  394. return $salt;
  395. }
  396. function encrypt_setup_password($password, $salt) {
  397. return $salt . ':' . sha1($salt . ':' . $password);
  398. }
  399. /*
  400. returns: array(
  401. 'error' => 0 (or 1),
  402. 'message => text
  403. )
  404. */
  405. function check_setup_password($password, $lostpw_mode = 0) {
  406. global $CONF;
  407. $error = 1; # be pessimistic
  408. $setuppw = "";
  409. if (isset($CONF['setup_password'])) {
  410. $setuppw = $CONF['setup_password'];
  411. }
  412. list($confsalt, $confpass, $trash) = explode(':', $setuppw . '::');
  413. $pass = encrypt_setup_password($password, $confsalt);
  414. $validpass = validate_password($password);
  415. if ($password == "") { # no password specified?
  416. $result = "Setup password must be specified<br />If you didn't set up a setup password yet, enter the password you want to use.";
  417. } elseif (count($validpass) > 0) {
  418. $result = $validpass[0]; # TODO: honor all error messages, not only the first one
  419. } elseif ($pass == $setuppw && $lostpw_mode == 0) { # correct passsword (and not asking for a new password)
  420. $result = "pass_OK";
  421. $error = 0;
  422. } else {
  423. $pass = encrypt_setup_password($password, generate_setup_password_salt());
  424. $result = "";
  425. if ($lostpw_mode == 1) {
  426. $error = 0; # non-matching password is expected when the user asks for a new password
  427. } else {
  428. $result = '<p><b>Setup password not specified correctly</b></p>';
  429. }
  430. $result .= '<p>If you want to use the password you entered as setup password, edit config.inc.php or config.local.php and set</p>';
  431. $result .= "<pre>\$CONF['setup_password'] = '$pass';</pre>";
  432. }
  433. return array($error, $result);
  434. }
  435. function create_admin($values) {
  436. DEFINE('POSTFIXADMIN_SETUP', 1); # avoids instant redirect to login.php after creating the admin
  437. $handler = new AdminHandler(1, 'setup.php');
  438. $formconf = $handler->webformConfig();
  439. if (!$handler->init($values['username'])) {
  440. return array(1, "", $handler->errormsg);
  441. }
  442. if (!$handler->set($values)) {
  443. return array(1, "", $handler->errormsg);
  444. }
  445. if (!$handler->store()) {
  446. return array(1, "", $handler->errormsg);
  447. }
  448. return array(
  449. 0,
  450. $handler->infomsg['success'],
  451. array(),
  452. );
  453. }
  454. /* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */
  455. ?>