r2348 - initial external authenticator support
[racktables] / upgrade.php
CommitLineData
6dc745d2 1<?php
fbbb74fb 2
90b96ff6
DO
3$relnotes = array
4(
4114697d 5 '0.17.0' => "Another change is the addition of support for file uploads. Files are stored<br>" .
90b96ff6 6 "in the database. There are several settings in php.ini which you may need to modify:<br>" .
4114697d
DO
7 "<ul><li>file_uploads - needs to be On</li>" .
8 "<li>upload_max_filesize - max size for uploaded files</li>" .
9 "<li>post_max_size - max size of all form data submitted via POST (including files)</li></ul>",
90b96ff6
DO
10);
11
fbbb74fb
DO
12// At the moment we assume, that for any two releases we can
13// sequentally execute all batches, that separate them, and
14// nothing will break. If this changes one day, the function
15// below will have to generate smarter upgrade paths, while
16// the upper layer will remain the same.
17// Returning an empty array means that no upgrade is necessary.
4114697d 18// Returning NULL indicates an error.
fbbb74fb
DO
19function getDBUpgradePath ($v1, $v2)
20{
a6f83a72
DO
21 $versionhistory = array
22 (
b3f866fc 23 '0.16.4',
64347dcf 24 '0.16.5',
90b96ff6 25 '0.16.6',
30d0a2a3 26 '0.17.0',
a6f83a72 27 );
fbbb74fb 28 $skip = TRUE;
4114697d 29 $path = NULL;
fbbb74fb
DO
30 // Now collect all versions > $v1 and <= $v2
31 foreach ($versionhistory as $v)
32 {
4114697d 33 if ($skip and $v == $v1)
fbbb74fb
DO
34 {
35 $skip = FALSE;
4114697d 36 $path = array();
fbbb74fb
DO
37 continue;
38 }
39 if ($skip)
40 continue;
41 $path[] = $v;
42 if ($v == $v2)
43 break;
44 }
45 return $path;
46}
47
90b96ff6
DO
48// Upgrade batches are named exactly as the release where they first appear.
49// That is simple, but seems sufficient for beginning.
fbbb74fb
DO
50function executeUpgradeBatch ($batchid)
51{
52 $query = array();
ce109ff2 53 global $dbxlink;
fbbb74fb
DO
54 switch ($batchid)
55 {
64347dcf
DO
56 case '0.16.5':
57 $query[] = "INSERT INTO `Config` (varname, varvalue, vartype, emptyok, is_hidden, description) VALUES ('IPV4_TREE_SHOW_USAGE','yes','string','no','no','Show address usage in IPv4 tree')";
58 $query[] = "update Config set varvalue = '0.16.5' where varname = 'DB_VERSION'";
59 break;
90b96ff6
DO
60 case '0.16.6':
61 $query[] = "update Config set varvalue = '0.16.6' where varname = 'DB_VERSION'";
62 break;
30d0a2a3 63 case '0.17.0':
e1ae3fb4
AD
64 // create tables for storing files (requires InnoDB support)
65 if (!isInnoDBSupported ())
66 {
f3c50166
AD
67 showError ("Cannot upgrade because InnoDB tables are not supported by your MySQL server. See the README for details.", __FILE__);
68 die;
e1ae3fb4 69 }
90b96ff6
DO
70 // Many dictionary changes were made... remove all dictvendor entries and install fresh.
71 // Take care not to erase locally added records. 0.16.x ends with max key 797
72 $query[] = 'DELETE FROM Dictionary WHERE ((chapter_no BETWEEN 11 AND 14) or (chapter_no BETWEEN 16 AND 19) ' .
73 'or (chapter_no BETWEEN 21 AND 24)) and dict_key <= 797';
f3c50166
AD
74 $f = fopen ("install/init-dictvendors.sql", 'r');
75 if ($f === FALSE)
76 {
77 showError ("Failed to open install/init-dictvendors.sql for reading");
78 die;
79 }
80 $longq = '';
81 while (!feof ($f))
82 {
83 $line = fgets ($f);
84 if (ereg ('^--', $line))
85 continue;
86 $longq .= $line;
87 }
88 fclose ($f);
89 foreach (explode (";\n", $longq) as $dict_query)
90 {
91 if (empty ($dict_query))
92 continue;
93 $query[] = $dict_query;
94 }
95
96 // schema changes for file management
e1ae3fb4
AD
97 $query[] = "
98CREATE TABLE `File` (
99 `id` int(10) unsigned NOT NULL auto_increment,
100 `name` char(255) NOT NULL,
101 `type` char(255) NOT NULL,
102 `size` int(10) unsigned NOT NULL,
103 `ctime` datetime NOT NULL,
104 `mtime` datetime NOT NULL,
105 `atime` datetime NOT NULL,
106 `contents` longblob NOT NULL,
107 `comment` text,
108 PRIMARY KEY (`id`)
109) ENGINE=InnoDB";
110 $query[] = "
111CREATE TABLE `FileLink` (
112 `id` int(10) unsigned NOT NULL auto_increment,
113 `file_id` int(10) unsigned NOT NULL,
114 `entity_type` enum('ipv4net','ipv4rspool','ipv4vs','object','rack','user') NOT NULL default 'object',
115 `entity_id` int(10) NOT NULL,
116 PRIMARY KEY (`id`),
af721881 117 UNIQUE KEY `FileLink-unique` (`file_id`,`entity_type`,`entity_id`),
e1ae3fb4
AD
118 KEY `FileLink-file_id` (`file_id`),
119 CONSTRAINT `FileLink-File_fkey` FOREIGN KEY (`file_id`) REFERENCES `File` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
120) ENGINE=InnoDB";
121 $query[] = "ALTER TABLE TagStorage MODIFY COLUMN target_realm enum('file','ipv4net','ipv4rspool','ipv4vs','object','rack','user') NOT NULL default 'object'";
f3c50166
AD
122
123 // add network security as an object type
d4739002
AD
124 $query[] = "INSERT INTO `Chapter` (`chapter_no`, `sticky`, `chapter_name`) VALUES (24,'no','network security models')";
125 $query[] = "INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_no`) VALUES (798,1,0)";
126 $query[] = "INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_no`) VALUES (798,2,24)";
127 $query[] = "INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_no`) VALUES (798,3,0)";
128 $query[] = "INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_no`) VALUES (798,5,0)";
129 $query[] = "INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_no`) VALUES (798,14,0)";
130 $query[] = "INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_no`) VALUES (798,16,0)";
131 $query[] = "INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_no`) VALUES (798,17,0)";
132 $query[] = "INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_no`) VALUES (798,18,0)";
133 $query[] = "INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_no`) VALUES (798,20,0)";
134 $query[] = "INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_no`) VALUES (798,21,0)";
135 $query[] = "INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_no`) VALUES (798,22,0)";
136 $query[] = "INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_no`) VALUES (798,24,0)";
d4739002 137 $query[] = "UPDATE Dictionary SET dict_value = 'Network switch' WHERE dict_key = 8";
706ce117
DO
138 $query[] = 'alter table IPBonds rename to IPv4Allocation';
139 $query[] = 'alter table PortForwarding rename to IPv4NAT';
140 $query[] = 'alter table IPRanges rename to IPv4Network';
141 $query[] = 'alter table IPAddress rename to IPv4Address';
142 $query[] = 'alter table IPLoadBalancer rename to IPv4LB';
4114697d 143 $query[] = 'alter table IPRSPool rename to IPv4RSPool';
706ce117 144 $query[] = 'alter table IPRealServer rename to IPv4RS';
4114697d 145 $query[] = 'alter table IPVirtualService rename to IPv4VS';
e1ae3fb4 146 $query[] = "UPDATE Config SET varvalue = '0.17.0' WHERE varname = 'DB_VERSION'";
b3f866fc 147 break;
fbbb74fb 148 default:
b0348307 149 showError ("executeUpgradeBatch () failed, because batch '${batchid}' isn't defined", __FILE__);
fbbb74fb
DO
150 die;
151 break;
152 }
fbbb74fb 153 $failures = array();
4114697d 154 echo "<tr><th>Executing batch '${batchid}'</th><td>";
fbbb74fb
DO
155 foreach ($query as $q)
156 {
157 $result = $dbxlink->query ($q);
4114697d 158 if ($result == NULL)
758fe24c 159 {
758fe24c
DO
160 $errorInfo = $dbxlink->errorInfo();
161 $failures[] = array ($q, $errorInfo[2]);
162 }
fbbb74fb 163 }
fbbb74fb 164 if (!count ($failures))
4114697d 165 echo "<strong><font color=green>done</font></strong>";
fbbb74fb
DO
166 else
167 {
4114697d 168 echo "<strong><font color=red>The following queries failed:</font></strong><br><pre>";
fbbb74fb
DO
169 foreach ($failures as $f)
170 {
171 list ($q, $i) = $f;
4114697d 172 echo "${q} -- ${i}\n";
fbbb74fb 173 }
4114697d 174 echo "</pre>";
fbbb74fb 175 }
4114697d 176 echo '</td></tr>';
fbbb74fb
DO
177}
178
179// ******************************************************************
180//
181// Execution starts here
182//
183// ******************************************************************
184
185$root = (empty($_SERVER['HTTPS'])?'http':'https').
186 '://'.
187 (isset($_SERVER['HTTP_HOST'])?$_SERVER['HTTP_HOST']:($_SERVER['SERVER_NAME'].($_SERVER['SERVER_PORT']=='80'?'':$_SERVER['SERVER_PORT']))).
54c2a7a8
DO
188 dirname($_SERVER['PHP_SELF']);
189if (substr ($root, -1) != '/')
190 $root .= '/';
fbbb74fb
DO
191
192// The below will be necessary as long as we rely on showError()
193require_once 'inc/interface.php';
194
195require_once 'inc/config.php';
196require_once 'inc/database.php';
197if (file_exists ('inc/secret.php'))
198 require_once 'inc/secret.php';
199else
200 die ("Database connection parameters are read from inc/secret.php file, " .
201 "which cannot be found.\nCopy provided inc/secret-sample.php to " .
202 "inc/secret.php and modify to your setup.\n\nThen reload the page.");
203
204try
205{
206 $dbxlink = new PDO ($pdo_dsn, $db_username, $db_password);
207}
208catch (PDOException $e)
209{
210 die ("Database connection failed:\n\n" . $e->getMessage());
211}
212
fbbb74fb
DO
213// Now we need to be sure that the current user is the administrator.
214// The rest doesn't matter within this context.
215// We still continue to use the current authenticator though, but this will
216// last only till the UserAccounts remains the same. After that this file
217// will have to dig into the DB for the user accounts.
218require_once 'inc/auth.php';
219
a1f3710a
DO
220// 1. This didn't fail sanely, because getUserAccounts() depended on showError()
221// 2. getUserAccounts() doesn't work for old DBs since 0.16.0. Let's have own
222// copy until it breaks too.
223
224function getUserAccounts_local ()
225{
226 global $dbxlink;
227 $query = 'select user_id, user_name, user_password_hash from UserAccount order by user_name';
228 if (($result = $dbxlink->query ($query)) == NULL)
229 die ('SQL query failed in ' . __FUNCTION__);
230 $ret = array();
231 while ($row = $result->fetch (PDO::FETCH_ASSOC))
232 foreach (array ('user_id', 'user_name', 'user_password_hash') as $cname)
233 $ret[$row['user_name']][$cname] = $row[$cname];
234 return $ret;
235}
236
237$accounts = getUserAccounts_local();
fbbb74fb 238
d78fdaea
DO
239// Only administrator is always authenticated locally, so reject others
240// for authenticate() to succeed.
99ee5479
DO
241
242if
243(
244 !isset ($_SERVER['PHP_AUTH_USER']) or
245 !isset ($_SERVER['PHP_AUTH_PW']) or
246 $accounts[$_SERVER['PHP_AUTH_USER']]['user_id'] != 1 or
247 !authenticated_via_database (escapeString ($_SERVER['PHP_AUTH_USER']), escapeString ($_SERVER['PHP_AUTH_PW']))
248)
249{
c0142c01
DO
250 header ('WWW-Authenticate: Basic realm="RackTables upgrade"');
251 header ('HTTP/1.0 401 Unauthorized');
b0348307 252 showError ('You must be authenticated as an administrator to complete the upgrade.', __FILE__);
99ee5479
DO
253 die;
254}
fbbb74fb
DO
255
256$dbver = getDatabaseVersion();
4114697d
DO
257echo '<table border=1>';
258echo "<tr><th>Current status</th><td>Data version: ${dbver}<br>Code version: " . CODE_VERSION . "</td></tr>\n";
259
260$path = getDBUpgradePath ($dbver, CODE_VERSION);
261if ($path === NULL)
758fe24c 262{
4114697d
DO
263 echo "<tr><th>Upgrade path</th><td><font color=red>not found</font></td></tr>\n";
264 echo "<tr><th>Summary</th><td>Check README for more information.</td></tr>\n";
758fe24c 265}
4114697d 266else
5f4027b8 267{
4114697d
DO
268 if (!count ($path))
269 echo "<tr><th>Summary</th><td>Come back later.</td></tr>\n";
270 else
271 {
272 echo "<tr><th>Upgrade path</th><td>${dbver} &rarr; " . implode (' &rarr; ', $path) . "</td></tr>\n";
273 foreach ($path as $batchid)
274 {
275 executeUpgradeBatch ($batchid);
276 if (isset ($relnotes[$batchid]))
277 echo "<tr><th>Release notes for ${batchid}</th><td>" . $relnotes[$batchid] . "</td></tr>\n";
278 }
279 echo "<tr><th>Summary</th><td>Upgrade complete, it is Ok to <a href='${root}'>enter</a> the system.</td></tr>\n";
280 }
5f4027b8 281}
4114697d 282echo '</table>';
fbbb74fb
DO
283
284?>