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.

275 lines
7.8 KiB

13 years ago
13 years ago
13 years ago
13 years ago
  1. <?php
  2. /**
  3. * Copyright (c) 2014 Lukas Reschke <lukas@owncloud.com>
  4. * This file is licensed under the Affero General Public License version 3 or
  5. * later.
  6. * See the COPYING-README file.
  7. */
  8. use OCP\IConfig;
  9. class DatabaseSetupException extends \OC\HintException {
  10. }
  11. class OC_Setup {
  12. /** @var IConfig */
  13. protected $config;
  14. /**
  15. * @param IConfig $config
  16. */
  17. function __construct(IConfig $config) {
  18. $this->config = $config;
  19. }
  20. static $dbSetupClasses = array(
  21. 'mysql' => '\OC\Setup\MySQL',
  22. 'pgsql' => '\OC\Setup\PostgreSQL',
  23. 'oci' => '\OC\Setup\OCI',
  24. 'mssql' => '\OC\Setup\MSSQL',
  25. 'sqlite' => '\OC\Setup\Sqlite',
  26. 'sqlite3' => '\OC\Setup\Sqlite',
  27. );
  28. /**
  29. * @return OC_L10N
  30. */
  31. public static function getTrans(){
  32. return \OC::$server->getL10N('lib');
  33. }
  34. /**
  35. * Wrapper around the "class_exists" PHP function to be able to mock it
  36. * @param string $name
  37. * @return bool
  38. */
  39. public function class_exists($name) {
  40. return class_exists($name);
  41. }
  42. /**
  43. * Wrapper around the "is_callable" PHP function to be able to mock it
  44. * @param string $name
  45. * @return bool
  46. */
  47. public function is_callable($name) {
  48. return is_callable($name);
  49. }
  50. /**
  51. * Get the available and supported databases of this instance
  52. *
  53. * @throws Exception
  54. * @return array
  55. */
  56. public function getSupportedDatabases() {
  57. $availableDatabases = array(
  58. 'sqlite' => array(
  59. 'type' => 'class',
  60. 'call' => 'SQLite3',
  61. 'name' => 'SQLite'
  62. ),
  63. 'mysql' => array(
  64. 'type' => 'function',
  65. 'call' => 'mysql_connect',
  66. 'name' => 'MySQL/MariaDB'
  67. ),
  68. 'pgsql' => array(
  69. 'type' => 'function',
  70. 'call' => 'pg_connect',
  71. 'name' => 'PostgreSQL'
  72. ),
  73. 'oci' => array(
  74. 'type' => 'function',
  75. 'call' => 'oci_connect',
  76. 'name' => 'Oracle'
  77. ),
  78. 'mssql' => array(
  79. 'type' => 'function',
  80. 'call' => 'sqlsrv_connect',
  81. 'name' => 'MS SQL'
  82. )
  83. );
  84. $configuredDatabases = $this->config->getSystemValue('supportedDatabases',
  85. array('sqlite', 'mysql', 'pgsql', 'oci', 'mssql'));
  86. if(!is_array($configuredDatabases)) {
  87. throw new Exception('Supported databases are not properly configured.');
  88. }
  89. $supportedDatabases = array();
  90. foreach($configuredDatabases as $database) {
  91. if(array_key_exists($database, $availableDatabases)) {
  92. $working = false;
  93. if($availableDatabases[$database]['type'] === 'class') {
  94. $working = $this->class_exists($availableDatabases[$database]['call']);
  95. } elseif ($availableDatabases[$database]['type'] === 'function') {
  96. $working = $this->is_callable($availableDatabases[$database]['call']);
  97. }
  98. if($working) {
  99. $supportedDatabases[$database] = $availableDatabases[$database]['name'];
  100. }
  101. }
  102. }
  103. return $supportedDatabases;
  104. }
  105. /**
  106. * @param $options
  107. * @return array
  108. */
  109. public static function install($options) {
  110. $l = self::getTrans();
  111. $error = array();
  112. $dbType = $options['dbtype'];
  113. if(empty($options['adminlogin'])) {
  114. $error[] = $l->t('Set an admin username.');
  115. }
  116. if(empty($options['adminpass'])) {
  117. $error[] = $l->t('Set an admin password.');
  118. }
  119. if(empty($options['directory'])) {
  120. $options['directory'] = OC::$SERVERROOT."/data";
  121. }
  122. if (!isset(self::$dbSetupClasses[$dbType])) {
  123. $dbType = 'sqlite';
  124. }
  125. $username = htmlspecialchars_decode($options['adminlogin']);
  126. $password = htmlspecialchars_decode($options['adminpass']);
  127. $dataDir = htmlspecialchars_decode($options['directory']);
  128. $class = self::$dbSetupClasses[$dbType];
  129. /** @var \OC\Setup\AbstractDatabase $dbSetup */
  130. $dbSetup = new $class(self::getTrans(), 'db_structure.xml');
  131. $error = array_merge($error, $dbSetup->validate($options));
  132. // validate the data directory
  133. if (
  134. (!is_dir($dataDir) and !mkdir($dataDir)) or
  135. !is_writable($dataDir)
  136. ) {
  137. $error[] = $l->t("Can't create or write into the data directory %s", array($dataDir));
  138. }
  139. if(count($error) != 0) {
  140. return $error;
  141. }
  142. //no errors, good
  143. if(isset($options['trusted_domains'])
  144. && is_array($options['trusted_domains'])) {
  145. $trustedDomains = $options['trusted_domains'];
  146. } else {
  147. $trustedDomains = array(OC_Request::serverHost());
  148. }
  149. if (OC_Util::runningOnWindows()) {
  150. $dataDir = rtrim(realpath($dataDir), '\\');
  151. }
  152. //use sqlite3 when available, otherwise sqlite2 will be used.
  153. if($dbType=='sqlite' and class_exists('SQLite3')) {
  154. $dbType='sqlite3';
  155. }
  156. //generate a random salt that is used to salt the local user passwords
  157. $salt = \OC::$server->getSecureRandom()->getLowStrengthGenerator()->generate(30);
  158. \OC::$server->getConfig()->setSystemValue('passwordsalt', $salt);
  159. // generate a secret
  160. $secret = \OC::$server->getSecureRandom()->getMediumStrengthGenerator()->generate(48);
  161. \OC::$server->getConfig()->setSystemValue('secret', $secret);
  162. //write the config file
  163. \OC::$server->getConfig()->setSystemValue('trusted_domains', $trustedDomains);
  164. \OC::$server->getConfig()->setSystemValue('datadirectory', $dataDir);
  165. \OC::$server->getConfig()->setSystemValue('overwrite.cli.url', \OC_Request::serverProtocol() . '://' . \OC_Request::serverHost() . OC::$WEBROOT);
  166. \OC::$server->getConfig()->setSystemValue('dbtype', $dbType);
  167. \OC::$server->getConfig()->setSystemValue('version', implode('.', OC_Util::getVersion()));
  168. try {
  169. $dbSetup->initialize($options);
  170. $dbSetup->setupDatabase($username);
  171. } catch (DatabaseSetupException $e) {
  172. $error[] = array(
  173. 'error' => $e->getMessage(),
  174. 'hint' => $e->getHint()
  175. );
  176. return($error);
  177. } catch (Exception $e) {
  178. $error[] = array(
  179. 'error' => 'Error while trying to create admin user: ' . $e->getMessage(),
  180. 'hint' => ''
  181. );
  182. return($error);
  183. }
  184. //create the user and group
  185. try {
  186. OC_User::createUser($username, $password);
  187. } catch(Exception $exception) {
  188. $error[] = $exception->getMessage();
  189. }
  190. if(count($error) == 0) {
  191. $appConfig = \OC::$server->getAppConfig();
  192. $appConfig->setValue('core', 'installedat', microtime(true));
  193. $appConfig->setValue('core', 'lastupdatedat', microtime(true));
  194. OC_Group::createGroup('admin');
  195. OC_Group::addToGroup($username, 'admin');
  196. OC_User::login($username, $password);
  197. //guess what this does
  198. OC_Installer::installShippedApps();
  199. // create empty file in data dir, so we can later find
  200. // out that this is indeed an ownCloud data directory
  201. file_put_contents(OC_Config::getValue('datadirectory', OC::$SERVERROOT.'/data').'/.ocdata', '');
  202. // Update htaccess files for apache hosts
  203. if (isset($_SERVER['SERVER_SOFTWARE']) && strstr($_SERVER['SERVER_SOFTWARE'], 'Apache')) {
  204. self::updateHtaccess();
  205. self::protectDataDirectory();
  206. }
  207. //and we are done
  208. OC_Config::setValue('installed', true);
  209. }
  210. return $error;
  211. }
  212. /**
  213. * Append the correct ErrorDocument path for Apache hosts
  214. */
  215. public static function updateHtaccess() {
  216. $content = "\n";
  217. $content.= "ErrorDocument 403 ".OC::$WEBROOT."/core/templates/403.php\n";//custom 403 error page
  218. $content.= "ErrorDocument 404 ".OC::$WEBROOT."/core/templates/404.php";//custom 404 error page
  219. @file_put_contents(OC::$SERVERROOT.'/.htaccess', $content, FILE_APPEND); //suppress errors in case we don't have permissions for it
  220. }
  221. public static function protectDataDirectory() {
  222. //Require all denied
  223. $now = date('Y-m-d H:i:s');
  224. $content = "# Generated by ownCloud on $now\n";
  225. $content.= "# line below if for Apache 2.4\n";
  226. $content.= "<ifModule mod_authz_core>\n";
  227. $content.= "Require all denied\n";
  228. $content.= "</ifModule>\n\n";
  229. $content.= "# line below if for Apache 2.2\n";
  230. $content.= "<ifModule !mod_authz_core>\n";
  231. $content.= "deny from all\n";
  232. $content.= "</ifModule>\n\n";
  233. $content.= "# section for Apache 2.2 and 2.4\n";
  234. $content.= "IndexIgnore *\n";
  235. file_put_contents(OC_Config::getValue('datadirectory', OC::$SERVERROOT.'/data').'/.htaccess', $content);
  236. file_put_contents(OC_Config::getValue('datadirectory', OC::$SERVERROOT.'/data').'/index.html', '');
  237. }
  238. }