oci.php 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. <?php
  2. namespace OC\Setup;
  3. class OCI extends AbstractDatabase {
  4. public $dbprettyname = 'Oracle';
  5. protected $dbtablespace;
  6. public function initialize($config) {
  7. parent::initialize($config);
  8. if (array_key_exists('dbtablespace', $config)) {
  9. $this->dbtablespace = $config['dbtablespace'];
  10. } else {
  11. $this->dbtablespace = 'USERS';
  12. }
  13. \OC_Config::setValue('dbtablespace', $this->dbtablespace);
  14. }
  15. public function setupDatabase($username) {
  16. $e_host = addslashes($this->dbhost);
  17. $e_dbname = addslashes($this->dbname);
  18. //check if the database user has admin right
  19. if ($e_host == '') {
  20. $easy_connect_string = $e_dbname; // use dbname as easy connect name
  21. } else {
  22. $easy_connect_string = '//'.$e_host.'/'.$e_dbname;
  23. }
  24. \OC_Log::write('setup oracle', 'connect string: ' . $easy_connect_string, \OC_Log::DEBUG);
  25. $connection = @oci_connect($this->dbuser, $this->dbpassword, $easy_connect_string);
  26. if(!$connection) {
  27. $errorMessage = $this->getLastError();
  28. if ($errorMessage) {
  29. throw new \DatabaseSetupException($this->trans->t('Oracle connection could not be established'),
  30. $errorMessage.' Check environment: ORACLE_HOME='.getenv('ORACLE_HOME')
  31. .' ORACLE_SID='.getenv('ORACLE_SID')
  32. .' LD_LIBRARY_PATH='.getenv('LD_LIBRARY_PATH')
  33. .' NLS_LANG='.getenv('NLS_LANG')
  34. .' tnsnames.ora is '.(is_readable(getenv('ORACLE_HOME').'/network/admin/tnsnames.ora')?'':'not ').'readable');
  35. }
  36. throw new \DatabaseSetupException($this->trans->t('Oracle username and/or password not valid'),
  37. 'Check environment: ORACLE_HOME='.getenv('ORACLE_HOME')
  38. .' ORACLE_SID='.getenv('ORACLE_SID')
  39. .' LD_LIBRARY_PATH='.getenv('LD_LIBRARY_PATH')
  40. .' NLS_LANG='.getenv('NLS_LANG')
  41. .' tnsnames.ora is '.(is_readable(getenv('ORACLE_HOME').'/network/admin/tnsnames.ora')?'':'not ').'readable');
  42. }
  43. //check for roles creation rights in oracle
  44. $query='SELECT count(*) FROM user_role_privs, role_sys_privs'
  45. ." WHERE user_role_privs.granted_role = role_sys_privs.role AND privilege = 'CREATE ROLE'";
  46. $stmt = oci_parse($connection, $query);
  47. if (!$stmt) {
  48. $entry = $this->trans->t('DB Error: "%s"', array($this->getLastError($connection))) . '<br />';
  49. $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '<br />';
  50. \OC_Log::write('setup.oci', $entry, \OC_Log::WARN);
  51. }
  52. $result = oci_execute($stmt);
  53. if($result) {
  54. $row = oci_fetch_row($stmt);
  55. }
  56. if($result and $row[0] > 0) {
  57. //use the admin login data for the new database user
  58. //add prefix to the oracle user name to prevent collisions
  59. $this->dbuser='oc_'.$username;
  60. //create a new password so we don't need to store the admin config in the config file
  61. $this->dbpassword=\OC_Util::generateRandomBytes(30);
  62. //oracle passwords are treated as identifiers:
  63. // must start with alphanumeric char
  64. // needs to be shortened to 30 bytes, as the two " needed to escape the identifier count towards the identifier length.
  65. $this->dbpassword=substr($this->dbpassword, 0, 30);
  66. $this->createDBUser($connection);
  67. \OC_Config::setValue('dbuser', $this->dbuser);
  68. \OC_Config::setValue('dbname', $this->dbuser);
  69. \OC_Config::setValue('dbpassword', $this->dbpassword);
  70. //create the database not necessary, oracle implies user = schema
  71. //$this->createDatabase($this->dbname, $this->dbuser, $connection);
  72. } else {
  73. \OC_Config::setValue('dbuser', $this->dbuser);
  74. \OC_Config::setValue('dbname', $this->dbname);
  75. \OC_Config::setValue('dbpassword', $this->dbpassword);
  76. //create the database not necessary, oracle implies user = schema
  77. //$this->createDatabase($this->dbname, $this->dbuser, $connection);
  78. }
  79. //FIXME check tablespace exists: select * from user_tablespaces
  80. // the connection to dbname=oracle is not needed anymore
  81. oci_close($connection);
  82. // connect to the oracle database (schema=$this->dbuser) an check if the schema needs to be filled
  83. $this->dbuser = \OC_Config::getValue('dbuser');
  84. //$this->dbname = \OC_Config::getValue('dbname');
  85. $this->dbpassword = \OC_Config::getValue('dbpassword');
  86. $e_host = addslashes($this->dbhost);
  87. $e_dbname = addslashes($this->dbname);
  88. if ($e_host == '') {
  89. $easy_connect_string = $e_dbname; // use dbname as easy connect name
  90. } else {
  91. $easy_connect_string = '//'.$e_host.'/'.$e_dbname;
  92. }
  93. $connection = @oci_connect($this->dbuser, $this->dbpassword, $easy_connect_string);
  94. if(!$connection) {
  95. throw new \DatabaseSetupException($this->trans->t('Oracle username and/or password not valid'),
  96. $this->trans->t('You need to enter either an existing account or the administrator.'));
  97. }
  98. $query = "SELECT count(*) FROM user_tables WHERE table_name = :un";
  99. $stmt = oci_parse($connection, $query);
  100. $un = $this->tableprefix.'users';
  101. oci_bind_by_name($stmt, ':un', $un);
  102. if (!$stmt) {
  103. $entry = $this->trans->t('DB Error: "%s"', array($this->getLastError($connection))) . '<br />';
  104. $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '<br />';
  105. \OC_Log::write('setup.oci', $entry, \OC_Log::WARN);
  106. }
  107. $result = oci_execute($stmt);
  108. if($result) {
  109. $row = oci_fetch_row($stmt);
  110. }
  111. if(!$result or $row[0]==0) {
  112. \OC_DB::createDbFromStructure($this->dbDefinitionFile);
  113. }
  114. }
  115. /**
  116. * @param resource $connection
  117. */
  118. private function createDBUser($connection) {
  119. $name = $this->dbuser;
  120. $password = $this->dbpassword;
  121. $query = "SELECT * FROM all_users WHERE USERNAME = :un";
  122. $stmt = oci_parse($connection, $query);
  123. if (!$stmt) {
  124. $entry = $this->trans->t('DB Error: "%s"', array($this->getLastError($connection))) . '<br />';
  125. $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '<br />';
  126. \OC_Log::write('setup.oci', $entry, \OC_Log::WARN);
  127. }
  128. oci_bind_by_name($stmt, ':un', $name);
  129. $result = oci_execute($stmt);
  130. if(!$result) {
  131. $entry = $this->trans->t('DB Error: "%s"', array($this->getLastError($connection))) . '<br />';
  132. $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '<br />';
  133. \OC_Log::write('setup.oci', $entry, \OC_Log::WARN);
  134. }
  135. if(! oci_fetch_row($stmt)) {
  136. //user does not exists let's create it :)
  137. //password must start with alphabetic character in oracle
  138. $query = 'CREATE USER '.$name.' IDENTIFIED BY "'.$password.'" DEFAULT TABLESPACE '.$this->dbtablespace;
  139. $stmt = oci_parse($connection, $query);
  140. if (!$stmt) {
  141. $entry = $this->trans->t('DB Error: "%s"', array($this->getLastError($connection))) . '<br />';
  142. $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '<br />';
  143. \OC_Log::write('setup.oci', $entry, \OC_Log::WARN);
  144. }
  145. //oci_bind_by_name($stmt, ':un', $name);
  146. $result = oci_execute($stmt);
  147. if(!$result) {
  148. $entry = $this->trans->t('DB Error: "%s"', array($this->getLastError($connection))) . '<br />';
  149. $entry .= $this->trans->t('Offending command was: "%s", name: %s, password: %s',
  150. array($query, $name, $password)) . '<br />';
  151. \OC_Log::write('setup.oci', $entry, \OC_Log::WARN);
  152. }
  153. } else { // change password of the existing role
  154. $query = "ALTER USER :un IDENTIFIED BY :pw";
  155. $stmt = oci_parse($connection, $query);
  156. if (!$stmt) {
  157. $entry = $this->trans->t('DB Error: "%s"', array($this->getLastError($connection))) . '<br />';
  158. $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '<br />';
  159. \OC_Log::write('setup.oci', $entry, \OC_Log::WARN);
  160. }
  161. oci_bind_by_name($stmt, ':un', $name);
  162. oci_bind_by_name($stmt, ':pw', $password);
  163. $result = oci_execute($stmt);
  164. if(!$result) {
  165. $entry = $this->trans->t('DB Error: "%s"', array($this->getLastError($connection))) . '<br />';
  166. $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '<br />';
  167. \OC_Log::write('setup.oci', $entry, \OC_Log::WARN);
  168. }
  169. }
  170. // grant necessary roles
  171. $query = 'GRANT CREATE SESSION, CREATE TABLE, CREATE SEQUENCE, CREATE TRIGGER, UNLIMITED TABLESPACE TO '.$name;
  172. $stmt = oci_parse($connection, $query);
  173. if (!$stmt) {
  174. $entry = $this->trans->t('DB Error: "%s"', array($this->getLastError($connection))) . '<br />';
  175. $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '<br />';
  176. \OC_Log::write('setup.oci', $entry, \OC_Log::WARN);
  177. }
  178. $result = oci_execute($stmt);
  179. if(!$result) {
  180. $entry = $this->trans->t('DB Error: "%s"', array($this->getLastError($connection))) . '<br />';
  181. $entry .= $this->trans->t('Offending command was: "%s", name: %s, password: %s',
  182. array($query, $name, $password)) . '<br />';
  183. \OC_Log::write('setup.oci', $entry, \OC_Log::WARN);
  184. }
  185. }
  186. /**
  187. * @param resource $connection
  188. * @return string
  189. */
  190. protected function getLastError($connection = null) {
  191. if ($connection) {
  192. $error = oci_error($connection);
  193. } else {
  194. $error = oci_error();
  195. }
  196. foreach (array('message', 'code') as $key) {
  197. if (isset($error[$key])) {
  198. return $error[$key];
  199. }
  200. }
  201. return '';
  202. }
  203. }