summaryrefslogtreecommitdiffstats
path: root/lib/private/setup/postgresql.php
blob: d2d902d96b659a15780f9ebf32183ef8bd6e7d50 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
<?php
/**
 * @author Bart Visscher <bartv@thisnet.nl>
 * @author Christopher Schäpers <kondou@ts.unde.re>
 * @author eduardo <eduardo@vnexu.net>
 * @author Joas Schilling <nickvergessen@gmx.de>
 *
 * @copyright Copyright (c) 2015, ownCloud, Inc.
 * @license AGPL-3.0
 *
 * This code is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License, version 3,
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License, version 3,
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
 *
 */
namespace OC\Setup;

class PostgreSQL extends AbstractDatabase {
	public $dbprettyname = 'PostgreSQL';

	public function setupDatabase($username) {
		$e_host = addslashes($this->dbhost);
		$e_user = addslashes($this->dbuser);
		$e_password = addslashes($this->dbpassword);

		// Fix database with port connection
		if(strpos($e_host, ':')) {
			list($e_host, $port)=explode(':', $e_host, 2);
		} else {
			$port=false;
		}

		//check if the database user has admin rights
		$connection_string = "host='$e_host' dbname=postgres user='$e_user' port='$port' password='$e_password'";
		$connection = @pg_connect($connection_string);
		if(!$connection) {
			// Try if we can connect to the DB with the specified name
			$e_dbname = addslashes($this->dbname);
			$connection_string = "host='$e_host' dbname='$e_dbname' user='$e_user' port='$port' password='$e_password'";
			$connection = @pg_connect($connection_string);

			if(!$connection)
				throw new \OC\DatabaseSetupException($this->trans->t('PostgreSQL username and/or password not valid'),
						$this->trans->t('You need to enter either an existing account or the administrator.'));
		}
		$e_user = pg_escape_string($this->dbuser);
		//check for roles creation rights in postgresql
		$query="SELECT 1 FROM pg_roles WHERE rolcreaterole=TRUE AND rolname='$e_user'";
		$result = pg_query($connection, $query);
		if($result and pg_num_rows($result) > 0) {
			//use the admin login data for the new database user

			//add prefix to the postgresql user name to prevent collisions
			$this->dbuser='oc_'.$username;
			//create a new password so we don't need to store the admin config in the config file
			$this->dbpassword=\OC_Util::generateRandomBytes(30);

			$this->createDBUser($connection);
		}

		\OC_Config::setValues([
			'dbuser'		=> $this->dbuser,
			'dbpassword'	=> $this->dbpassword,
		]);

		//create the database
		$this->createDatabase($connection);

		// the connection to dbname=postgres is not needed anymore
		pg_close($connection);

		// connect to the ownCloud database (dbname=$this->dbname) and check if it needs to be filled
		$this->dbuser = \OC_Config::getValue('dbuser');
		$this->dbpassword = \OC_Config::getValue('dbpassword');

		$e_host = addslashes($this->dbhost);
		$e_dbname = addslashes($this->dbname);
		$e_user = addslashes($this->dbuser);
		$e_password = addslashes($this->dbpassword);

        	// Fix database with port connection
		if(strpos($e_host, ':')) {
			list($e_host, $port)=explode(':', $e_host, 2);
		} else {
			$port=false;
		}

		$connection_string = "host='$e_host' dbname='$e_dbname' user='$e_user' port='$port' password='$e_password'";
		$connection = @pg_connect($connection_string);
		if(!$connection) {
			throw new \OC\DatabaseSetupException($this->trans->t('PostgreSQL username and/or password not valid'),
					$this->trans->t('You need to enter either an existing account or the administrator.'));
		}
		$query = "select count(*) FROM pg_class WHERE relname='".$this->tableprefix."users' limit 1";
		$result = pg_query($connection, $query);
		if($result) {
			$row = pg_fetch_row($result);
		}
		if(!$result or $row[0]==0) {
			\OC_DB::createDbFromStructure($this->dbDefinitionFile);
		}
	}

	private function createDatabase($connection) {
		//we cant use OC_BD functions here because we need to connect as the administrative user.
		$e_name = pg_escape_string($this->dbname);
		$e_user = pg_escape_string($this->dbuser);
		$query = "select datname from pg_database where datname = '$e_name'";
		$result = pg_query($connection, $query);
		if(!$result) {
			$entry = $this->trans->t('DB Error: "%s"', array(pg_last_error($connection))) . '<br />';
			$entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '<br />';
			\OC_Log::write('setup.pg', $entry, \OC_Log::WARN);
		}
		if(! pg_fetch_row($result)) {
			//The database does not exists... let's create it
			$query = "CREATE DATABASE \"$e_name\" OWNER \"$e_user\"";
			$result = pg_query($connection, $query);
			if(!$result) {
				$entry = $this->trans->t('DB Error: "%s"', array(pg_last_error($connection))) . '<br />';
				$entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '<br />';
				\OC_Log::write('setup.pg', $entry, \OC_Log::WARN);
			}
			else {
				$query = "REVOKE ALL PRIVILEGES ON DATABASE \"$e_name\" FROM PUBLIC";
				pg_query($connection, $query);
			}
		}
	}

	private function createDBUser($connection) {
		$e_name = pg_escape_string($this->dbuser);
		$e_password = pg_escape_string($this->dbpassword);
		$query = "select * from pg_roles where rolname='$e_name';";
		$result = pg_query($connection, $query);
		if(!$result) {
			$entry = $this->trans->t('DB Error: "%s"', array(pg_last_error($connection))) . '<br />';
			$entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '<br />';
			\OC_Log::write('setup.pg', $entry, \OC_Log::WARN);
		}

		if(! pg_fetch_row($result)) {
			//user does not exists let's create it :)
			$query = "CREATE USER \"$e_name\" CREATEDB PASSWORD '$e_password';";
			$result = pg_query($connection, $query);
			if(!$result) {
				$entry = $this->trans->t('DB Error: "%s"', array(pg_last_error($connection))) . '<br />';
				$entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '<br />';
				\OC_Log::write('setup.pg', $entry, \OC_Log::WARN);
			}
		}
		else { // change password of the existing role
			$query = "ALTER ROLE \"$e_name\" WITH PASSWORD '$e_password';";
			$result = pg_query($connection, $query);
			if(!$result) {
				$entry = $this->trans->t('DB Error: "%s"', array(pg_last_error($connection))) . '<br />';
				$entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '<br />';
				\OC_Log::write('setup.pg', $entry, \OC_Log::WARN);
			}
		}
	}
}