setup.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. <?php
  2. $hasSQLite = (is_callable('sqlite_open') or class_exists('SQLite3'));
  3. $hasMySQL = is_callable('mysql_connect');
  4. $hasPostgreSQL = is_callable('pg_connect');
  5. $datadir = OC_Config::getValue('datadirectory', OC::$SERVERROOT.'/data');
  6. $opts = array(
  7. 'hasSQLite' => $hasSQLite,
  8. 'hasMySQL' => $hasMySQL,
  9. 'hasPostgreSQL' => $hasPostgreSQL,
  10. 'directory' => $datadir,
  11. 'errors' => array(),
  12. );
  13. if(isset($_POST['install']) AND $_POST['install']=='true') {
  14. // We have to launch the installation process :
  15. $e = OC_Setup::install($_POST);
  16. $errors = array('errors' => $e);
  17. if(count($e) > 0) {
  18. //OC_Template::printGuestPage("", "error", array("errors" => $errors));
  19. $options = array_merge($_POST, $opts, $errors);
  20. OC_Template::printGuestPage("", "installation", $options);
  21. }
  22. else {
  23. header("Location: ".OC::$WEBROOT.'/');
  24. exit();
  25. }
  26. }
  27. else {
  28. OC_Template::printGuestPage("", "installation", $opts);
  29. }
  30. class OC_Setup {
  31. public static function install($options) {
  32. $error = array();
  33. $dbtype = $options['dbtype'];
  34. if(empty($options['adminlogin'])) {
  35. $error[] = 'Set an admin username.';
  36. }
  37. if(empty($options['adminpass'])) {
  38. $error[] = 'Set an admin password.';
  39. }
  40. if(empty($options['directory'])) {
  41. $error[] = 'Specify a data folder.';
  42. }
  43. if($dbtype=='mysql' or $dbtype=='pgsql') { //mysql and postgresql needs more config options
  44. if($dbtype=='mysql')
  45. $dbprettyname = 'MySQL';
  46. else
  47. $dbprettyname = 'PostgreSQL';
  48. if(empty($options['dbuser'])) {
  49. $error[] = "$dbprettyname enter the database username.";
  50. }
  51. if(empty($options['dbname'])) {
  52. $error[] = "$dbprettyname enter the database name.";
  53. }
  54. if(empty($options['dbhost'])) {
  55. $error[] = "$dbprettyname set the database host.";
  56. }
  57. }
  58. if(count($error) == 0) { //no errors, good
  59. $username = htmlspecialchars_decode($options['adminlogin']);
  60. $password = htmlspecialchars_decode($options['adminpass']);
  61. $datadir = htmlspecialchars_decode($options['directory']);
  62. //use sqlite3 when available, otherise sqlite2 will be used.
  63. if($dbtype=='sqlite' and class_exists('SQLite3')){
  64. $dbtype='sqlite3';
  65. }
  66. //generate a random salt that is used to salt the local user passwords
  67. $salt=mt_rand(1000,9000).mt_rand(1000,9000).mt_rand(1000,9000).mt_rand(1000,9000).mt_rand(1000,9000).mt_rand(1000,9000).mt_rand(1000,9000).mt_rand(1000,9000);
  68. OC_Config::setValue('passwordsalt', $salt);
  69. //write the config file
  70. OC_Config::setValue('datadirectory', $datadir);
  71. OC_Config::setValue('dbtype', $dbtype);
  72. OC_Config::setValue('version',implode('.',OC_Util::getVersion()));
  73. if($dbtype == 'mysql') {
  74. $dbuser = $options['dbuser'];
  75. $dbpass = $options['dbpass'];
  76. $dbname = $options['dbname'];
  77. $dbhost = $options['dbhost'];
  78. $dbtableprefix = isset($options['dbtableprefix']) ? $options['dbtableprefix'] : 'oc_';
  79. OC_Config::setValue('dbname', $dbname);
  80. OC_Config::setValue('dbhost', $dbhost);
  81. OC_Config::setValue('dbtableprefix', $dbtableprefix);
  82. //check if the database user has admin right
  83. $connection = @mysql_connect($dbhost, $dbuser, $dbpass);
  84. if(!$connection) {
  85. $error[] = array(
  86. 'error' => 'MySQL username and/or password not valid',
  87. 'hint' => 'You need to enter either an existing account or the administrator.'
  88. );
  89. return($error);
  90. }
  91. else {
  92. $oldUser=OC_Config::getValue('dbuser', false);
  93. $oldPassword=OC_Config::getValue('dbpassword', false);
  94. $query="SELECT user FROM mysql.user WHERE user='$dbuser'"; //this should be enough to check for admin rights in mysql
  95. if(mysql_query($query, $connection)) {
  96. //use the admin login data for the new database user
  97. //add prefix to the mysql user name to prevent collissions
  98. $dbusername=substr('oc_'.$username,0,16);
  99. if($dbusername!=$oldUser){
  100. //hash the password so we don't need to store the admin config in the config file
  101. $dbpassword=md5(time().$password);
  102. self::createDBUser($dbusername, $dbpassword, $connection);
  103. OC_Config::setValue('dbuser', $dbusername);
  104. OC_Config::setValue('dbpassword', $dbpassword);
  105. }
  106. //create the database
  107. self::createDatabase($dbname, $dbusername, $connection);
  108. }
  109. else {
  110. if($dbuser!=$oldUser){
  111. OC_Config::setValue('dbuser', $dbuser);
  112. OC_Config::setValue('dbpassword', $dbpass);
  113. }
  114. //create the database
  115. self::createDatabase($dbname, $dbuser, $connection);
  116. }
  117. //fill the database if needed
  118. $query="select count(*) from information_schema.tables where table_schema='$dbname' AND table_name = '{$dbtableprefix}users';";
  119. $result = mysql_query($query,$connection);
  120. if($result){
  121. $row=mysql_fetch_row($result);
  122. }
  123. if(!$result or $row[0]==0) {
  124. OC_DB::createDbFromStructure('db_structure.xml');
  125. }
  126. mysql_close($connection);
  127. }
  128. }
  129. elseif($dbtype == 'pgsql') {
  130. $dbuser = $options['dbuser'];
  131. $dbpass = $options['dbpass'];
  132. $dbname = $options['dbname'];
  133. $dbhost = $options['dbhost'];
  134. $dbtableprefix = $options['dbtableprefix'];
  135. OC_CONFIG::setValue('dbname', $dbname);
  136. OC_CONFIG::setValue('dbhost', $dbhost);
  137. OC_CONFIG::setValue('dbtableprefix', $dbtableprefix);
  138. //check if the database user has admin right
  139. $connection_string = "host=$dbhost dbname=postgres user=$dbuser password=$dbpass";
  140. $connection = @pg_connect($connection_string);
  141. if(!$connection) {
  142. $error[] = array(
  143. 'error' => 'PostgreSQL username and/or password not valid',
  144. 'hint' => 'You need to enter either an existing account or the administrator.'
  145. );
  146. }
  147. else {
  148. //check for roles creation rights in postgresql
  149. $query="SELECT 1 FROM pg_roles WHERE rolcreaterole=TRUE AND rolname='$dbuser'";
  150. $result = pg_query($connection, $query);
  151. if($result and pg_num_rows($result) > 0) {
  152. //use the admin login data for the new database user
  153. //add prefix to the postgresql user name to prevent collissions
  154. $dbusername='oc_'.$username;
  155. //create a new password so we don't need to store the admin config in the config file
  156. $dbpassword=md5(time());
  157. self::pg_createDBUser($dbusername, $dbpassword, $connection);
  158. OC_CONFIG::setValue('dbuser', $dbusername);
  159. OC_CONFIG::setValue('dbpassword', $dbpassword);
  160. //create the database
  161. self::pg_createDatabase($dbname, $dbusername, $connection);
  162. }
  163. else {
  164. OC_CONFIG::setValue('dbuser', $dbuser);
  165. OC_CONFIG::setValue('dbpassword', $dbpass);
  166. //create the database
  167. self::pg_createDatabase($dbname, $dbuser, $connection);
  168. }
  169. // the connection to dbname=postgres is not needed anymore
  170. pg_close($connection);
  171. // connect to the ownCloud database (dbname=$dbname) an check if it needs to be filled
  172. $dbuser = OC_CONFIG::getValue('dbuser');
  173. $dbpass = OC_CONFIG::getValue('dbpassword');
  174. $connection_string = "host=$dbhost dbname=$dbname user=$dbuser password=$dbpass";
  175. $connection = @pg_connect($connection_string);
  176. if(!$connection) {
  177. $error[] = array(
  178. 'error' => 'PostgreSQL username and/or password not valid',
  179. 'hint' => 'You need to enter either an existing account or the administrator.'
  180. );
  181. } else {
  182. $query = "select count(*) FROM pg_class WHERE relname='{$dbtableprefix}users' limit 1";
  183. $result = pg_query($connection, $query);
  184. if($result) {
  185. $row = pg_fetch_row($result);
  186. }
  187. if(!$result or $row[0]==0) {
  188. OC_DB::createDbFromStructure('db_structure.xml');
  189. }
  190. }
  191. }
  192. }
  193. else {
  194. //delete the old sqlite database first, might cause infinte loops otherwise
  195. if(file_exists("$datadir/owncloud.db")){
  196. unlink("$datadir/owncloud.db");
  197. }
  198. //in case of sqlite, we can always fill the database
  199. OC_DB::createDbFromStructure('db_structure.xml');
  200. }
  201. //create the user and group
  202. try {
  203. OC_User::createUser($username, $password);
  204. }
  205. catch(Exception $exception) {
  206. $error[] = $exception->getMessage();
  207. }
  208. if(count($error) == 0) {
  209. OC_Appconfig::setValue('core', 'installedat',microtime(true));
  210. OC_Appconfig::setValue('core', 'lastupdatedat',microtime(true));
  211. OC_Group::createGroup('admin');
  212. OC_Group::addToGroup($username, 'admin');
  213. OC_User::login($username, $password);
  214. //guess what this does
  215. OC_Installer::installShippedApps();
  216. //create htaccess files for apache hosts
  217. if (strstr($_SERVER['SERVER_SOFTWARE'], 'Apache')) {
  218. self::createHtaccess();
  219. }
  220. //and we are done
  221. OC_Config::setValue('installed', true);
  222. }
  223. }
  224. return $error;
  225. }
  226. public static function createDatabase($name,$user,$connection) {
  227. //we cant use OC_BD functions here because we need to connect as the administrative user.
  228. $query = "CREATE DATABASE IF NOT EXISTS `$name`";
  229. $result = mysql_query($query, $connection);
  230. if(!$result) {
  231. $entry='DB Error: "'.mysql_error($connection).'"<br />';
  232. $entry.='Offending command was: '.$query.'<br />';
  233. echo($entry);
  234. }
  235. $query="GRANT ALL PRIVILEGES ON `$name` . * TO '$user'";
  236. $result = mysql_query($query, $connection); //this query will fail if there aren't the right permissons, ignore the error
  237. }
  238. private static function createDBUser($name,$password,$connection) {
  239. // we need to create 2 accounts, one for global use and one for local user. if we don't specify the local one,
  240. // the anonymous user would take precedence when there is one.
  241. $query = "CREATE USER '$name'@'localhost' IDENTIFIED BY '$password'";
  242. $result = mysql_query($query, $connection);
  243. $query = "CREATE USER '$name'@'%' IDENTIFIED BY '$password'";
  244. $result = mysql_query($query, $connection);
  245. }
  246. public static function pg_createDatabase($name,$user,$connection) {
  247. //we cant use OC_BD functions here because we need to connect as the administrative user.
  248. $e_name = pg_escape_string($name);
  249. $e_user = pg_escape_string($user);
  250. $query = "CREATE DATABASE \"$e_name\" OWNER \"$e_user\"";
  251. $result = pg_query($connection, $query);
  252. if(!$result) {
  253. $entry='DB Error: "'.pg_last_error($connection).'"<br />';
  254. $entry.='Offending command was: '.$query.'<br />';
  255. echo($entry);
  256. }
  257. $query = "REVOKE ALL PRIVILEGES ON DATABASE \"$e_name\" FROM PUBLIC";
  258. $result = pg_query($connection, $query);
  259. }
  260. private static function pg_createDBUser($name,$password,$connection) {
  261. $e_name = pg_escape_string($name);
  262. $e_password = pg_escape_string($password);
  263. $query = "CREATE USER \"$e_name\" CREATEDB PASSWORD '$e_password';";
  264. $result = pg_query($connection, $query);
  265. if(!$result) {
  266. $entry='DB Error: "'.pg_last_error($connection).'"<br />';
  267. $entry.='Offending command was: '.$query.'<br />';
  268. echo($entry);
  269. }
  270. }
  271. /**
  272. * create .htaccess files for apache hosts
  273. */
  274. private static function createHtaccess() {
  275. $content = "ErrorDocument 403 ".OC::$WEBROOT."/core/templates/403.php\n";//custom 403 error page
  276. $content.= "ErrorDocument 404 ".OC::$WEBROOT."/core/templates/404.php\n";//custom 404 error page
  277. $content.= "<IfModule mod_php5.c>\n";
  278. $content.= "php_value upload_max_filesize 512M\n";//upload limit
  279. $content.= "php_value post_max_size 512M\n";
  280. $content.= "php_value memory_limit 512M\n";
  281. $content.= "<IfModule env_module>\n";
  282. $content.= " SetEnv htaccessWorking true\n";
  283. $content.= "</IfModule>\n";
  284. $content.= "</IfModule>\n";
  285. $content.= "<IfModule mod_rewrite.c>\n";
  286. $content.= "RewriteEngine on\n";
  287. $content.= "RewriteRule .* - [env=HTTP_AUTHORIZATION:%{HTTP:Authorization}]\n";
  288. $content.= "RewriteRule ^.well-known/host-meta /public.php?service=host-meta [QSA,L]\n";
  289. $content.= "RewriteRule ^.well-known/carddav /remote.php/carddav/ [R]\n";
  290. $content.= "RewriteRule ^.well-known/caldav /remote.php/caldav/ [R]\n";
  291. $content.= "RewriteRule ^apps/([^/]*)/(.*\.(css|php))$ index.php?app=$1&getfile=$2 [QSA,L]\n";
  292. $content.= "RewriteRule ^remote/(.*) remote.php [QSA,L]\n";
  293. $content.= "</IfModule>\n";
  294. $content.= "Options -Indexes\n";
  295. @file_put_contents(OC::$SERVERROOT.'/.htaccess', $content); //supress errors in case we don't have permissions for it
  296. $content = "deny from all\n";
  297. $content.= "IndexIgnore *";
  298. file_put_contents(OC_Config::getValue('datadirectory', OC::$SERVERROOT.'/data').'/.htaccess', $content);
  299. file_put_contents(OC_Config::getValue('datadirectory', OC::$SERVERROOT.'/data').'/index.html', '');
  300. }
  301. }
  302. ?>