5 '0.17.0' => "This release requires changes to the configuration file. " .
6 "Move inc/secret.php to local/secret.php and add the following to the file:<br><br>" .
7 "\$user_auth_src = 'database';<br>\$require_local_account = TRUE;<br><br>" .
8 "(and adjust to your needs, if necessary)<br>" .
9 "Another change is the addition of support for file uploads. Files are stored<br>" .
10 "in the database. There are several settings in php.ini which you may need to modify:<br>" .
11 "<ul><li>file_uploads - needs to be On</li>" .
12 "<li>upload_max_filesize - max size for uploaded files</li>" .
13 "<li>post_max_size - max size of all form data submitted via POST (including files)</li></ul><br>" .
14 "Local user accounts used to have 'enabled' flag, which allowed individual blocking and<br>" .
15 "unblocking of each. This flag was dropped in favor of existing mean of access<br>" .
16 "setup (RackCode). An unconditional denying rule is automatically added into RackCode<br>" .
17 "for such blocked account, so the effective security policy remains the same.<br>",
20 // At the moment we assume, that for any two releases we can
21 // sequentally execute all batches, that separate them, and
22 // nothing will break. If this changes one day, the function
23 // below will have to generate smarter upgrade paths, while
24 // the upper layer will remain the same.
25 // Returning an empty array means that no upgrade is necessary.
26 // Returning NULL indicates an error.
27 function getDBUpgradePath ($v1, $v2)
29 $versionhistory = array
36 if (!in_array ($v1, $versionhistory) or !in_array ($v2, $versionhistory))
40 // Now collect all versions > $v1 and <= $v2
41 foreach ($versionhistory as $v)
43 if ($skip and $v == $v1)
58 // Upgrade batches are named exactly as the release where they first appear.
59 // That is simple, but seems sufficient for beginning.
60 function executeUpgradeBatch ($batchid)
67 $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')";
68 $query[] = "update Config set varvalue = '0.16.5' where varname = 'DB_VERSION'";
71 $query[] = "update Config set varvalue = '0.16.6' where varname = 'DB_VERSION'";
74 // create tables for storing files (requires InnoDB support)
75 if (!isInnoDBSupported ())
77 showError ("Cannot upgrade because InnoDB tables are not supported by your MySQL server. See the README for details.", __FILE__
);
81 $query[] = "alter table Chapter change chapter_no id int(10) unsigned NOT NULL auto_increment";
82 $query[] = "alter table Chapter change chapter_name name char(128) NOT NULL";
83 $query[] = "alter table Chapter drop key chapter_name";
84 $query[] = "alter table Chapter add UNIQUE KEY name (name)";
85 $query[] = "alter table Attribute change attr_id id int(10) unsigned NOT NULL auto_increment";
86 $query[] = "alter table Attribute change attr_type type enum('string','uint','float','dict') default NULL";
87 $query[] = "alter table Attribute change attr_name name char(64) default NULL";
88 $query[] = "alter table Attribute drop key attr_name";
89 $query[] = "alter table Attribute add UNIQUE KEY name (name)";
90 $query[] = "alter table AttributeMap change chapter_no chapter_id int(10) unsigned NOT NULL";
91 $query[] = "alter table Dictionary change chapter_no chapter_id int(10) unsigned NOT NULL";
92 // Many dictionary changes were made... remove all dictvendor entries and install fresh.
93 // Take care not to erase locally added records. 0.16.x ends with max key 797
94 $query[] = 'DELETE FROM Dictionary WHERE ((chapter_id BETWEEN 11 AND 14) or (chapter_id BETWEEN 16 AND 19) ' .
95 'or (chapter_id BETWEEN 21 AND 24)) and dict_key <= 797';
96 $f = fopen ("install/init-dictvendors.sql", 'r');
99 showError ("Failed to open install/init-dictvendors.sql for reading");
106 if (ereg ('^--', $line))
111 foreach (explode (";\n", $longq) as $dict_query)
113 if (empty ($dict_query))
115 $query[] = $dict_query;
118 // schema changes for file management
120 CREATE TABLE `File` (
121 `id` int(10) unsigned NOT NULL auto_increment,
122 `name` char(255) NOT NULL,
123 `type` char(255) NOT NULL,
124 `size` int(10) unsigned NOT NULL,
125 `ctime` datetime NOT NULL,
126 `mtime` datetime NOT NULL,
127 `atime` datetime NOT NULL,
128 `contents` longblob NOT NULL,
131 UNIQUE KEY `name` (`name`)
134 CREATE TABLE `FileLink` (
135 `id` int(10) unsigned NOT NULL auto_increment,
136 `file_id` int(10) unsigned NOT NULL,
137 `entity_type` enum('ipv4net','ipv4rspool','ipv4vs','object','rack','user') NOT NULL default 'object',
138 `entity_id` int(10) NOT NULL,
140 UNIQUE KEY `FileLink-unique` (`file_id`,`entity_type`,`entity_id`),
141 KEY `FileLink-file_id` (`file_id`),
142 CONSTRAINT `FileLink-File_fkey` FOREIGN KEY (`file_id`) REFERENCES `File` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
144 $query[] = "ALTER TABLE TagStorage MODIFY COLUMN target_realm enum('file','ipv4net','ipv4rspool','ipv4vs','object','rack','user') NOT NULL default 'object'";
146 $query[] = "INSERT INTO `Dictionary` (`chapter_id`, `dict_key`, `dict_value`) VALUES (1,798,'Network security')";
147 $query[] = "INSERT INTO `Dictionary` (`chapter_id`, `dict_key`, `dict_value`) VALUES (1,965,'Wireless')";
148 $query[] = "INSERT INTO `Chapter` (`id`, `sticky`, `name`) VALUES (24,'no','network security models')";
149 $query[] = "INSERT INTO `Chapter` (`id`, `sticky`, `name`) VALUES (25,'no','wireless models')";
150 $query[] = "INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_id`) VALUES (798,1,0)";
151 $query[] = "INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_id`) VALUES (798,2,24)";
152 $query[] = "INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_id`) VALUES (798,3,0)";
153 $query[] = "INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_id`) VALUES (798,5,0)";
154 $query[] = "INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_id`) VALUES (798,14,0)";
155 $query[] = "INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_id`) VALUES (798,16,0)";
156 $query[] = "INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_id`) VALUES (798,17,0)";
157 $query[] = "INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_id`) VALUES (798,18,0)";
158 $query[] = "INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_id`) VALUES (798,20,0)";
159 $query[] = "INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_id`) VALUES (798,21,0)";
160 $query[] = "INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_id`) VALUES (798,22,0)";
161 $query[] = "INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_id`) VALUES (798,24,0)";
162 $query[] = "INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_id`) VALUES (965,1,0)";
163 $query[] = "INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_id`) VALUES (965,3,0)";
164 $query[] = "INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_id`) VALUES (965,2,25)";
165 $query[] = "UPDATE Dictionary SET dict_value = 'Network switch' WHERE dict_key = 8";
166 $query[] = 'alter table IPBonds rename to IPv4Allocation';
167 $query[] = 'alter table PortForwarding rename to IPv4NAT';
168 $query[] = 'alter table IPRanges rename to IPv4Network';
169 $query[] = 'alter table IPAddress rename to IPv4Address';
170 $query[] = 'alter table IPLoadBalancer rename to IPv4LB';
171 $query[] = 'alter table IPRSPool rename to IPv4RSPool';
172 $query[] = 'alter table IPRealServer rename to IPv4RS';
173 $query[] = 'alter table IPVirtualService rename to IPv4VS';
174 $query[] = "alter table TagStorage change column target_realm entity_realm enum('file','ipv4net','ipv4vs','ipv4rspool','object','rack','user') NOT NULL default 'object'";
175 $query[] = 'alter table TagStorage change column target_id entity_id int(10) unsigned NOT NULL';
176 $query[] = 'alter table TagStorage drop key entity_tag';
177 $query[] = 'alter table TagStorage drop key target_id';
178 $query[] = 'alter table TagStorage add UNIQUE KEY `entity_tag` (`entity_realm`,`entity_id`,`tag_id`)';
179 $query[] = 'alter table TagStorage add KEY `entity_id` (`entity_id`)';
180 $query[] = "INSERT INTO `Config` (varname, varvalue, vartype, emptyok, is_hidden, description) VALUES ('PREVIEW_TEXT_MAXCHARS','10240','uint','yes','no','Max chars for text file preview')";
181 $query[] = "INSERT INTO `Config` (varname, varvalue, vartype, emptyok, is_hidden, description) VALUES ('PREVIEW_TEXT_ROWS','25','uint','yes','no','Rows for text file preview')";
182 $query[] = "INSERT INTO `Config` (varname, varvalue, vartype, emptyok, is_hidden, description) VALUES ('PREVIEW_TEXT_COLS','80','uint','yes','no','Columns for text file preview')";
183 $query[] = "INSERT INTO `Config` (varname, varvalue, vartype, emptyok, is_hidden, description) VALUES ('PREVIEW_IMAGE_MAXPXS','320','uint','yes','no','Max pixels per axis for image file preview')";
184 $query[] = "INSERT INTO `Config` (varname, varvalue, vartype, emptyok, is_hidden, description) VALUES ('VENDOR_SIEVE','','string','yes','no','Vendor sieve configuration')";
185 $query[] = "INSERT INTO `Config` (varname, varvalue, vartype, emptyok, is_hidden, description) VALUES ('IPV4LB_LISTSRC','{\$typeid_4}','string','yes','no','List source: IPv4 load balancers')";
186 $query[] = "INSERT INTO `Config` (varname, varvalue, vartype, emptyok, is_hidden, description) VALUES ('IPV4OBJ_LISTSRC','{\$typeid_4} or {\$typeid_7} or {\$typeid_8} or {\$typeid_12} or {\$typeid_445} or {\$typeid_447}','string','yes','no','List source: IPv4-enabled objects')";
187 $query[] = "INSERT INTO `Config` (varname, varvalue, vartype, emptyok, is_hidden, description) VALUES ('IPV4NAT_LISTSRC','{\$typeid_4} or {\$typeid_7} or {\$typeid_8}','string','yes','no','List source: IPv4 NAT performers')";
188 $query[] = "INSERT INTO `Config` (varname, varvalue, vartype, emptyok, is_hidden, description) VALUES ('ASSETWARN_LISTSRC','{\$typeid_4} or {\$typeid_7} or {\$typeid_8}','string','yes','no','List source: object, for which asset tag should be set')";
189 $query[] = "INSERT INTO `Config` (varname, varvalue, vartype, emptyok, is_hidden, description) VALUES ('NAMEWARN_LISTSRC','{\$typeid_4} or {\$typeid_7} or {\$typeid_8}','string','yes','no','List source: object, for which common name should be set')";
190 $query[] = "INSERT INTO `Config` (varname, varvalue, vartype, emptyok, is_hidden, description) VALUES ('RACKS_PER_ROW','12','unit','yes','no','Racks per row')";
191 $query[] = "INSERT INTO `Config` (varname, varvalue, vartype, emptyok, is_hidden, description) VALUES ('FILTER_PREDICATE_SIEVE','','string','yes','no','Predicate sieve regex(7)')";
192 $query[] = "INSERT INTO `Config` (varname, varvalue, vartype, emptyok, is_hidden, description) VALUES ('FILTER_DEFAULT_ANDOR','or','string','no','no','Default list filter boolean operation (or/and)')";
193 $query[] = "INSERT INTO `Config` (varname, varvalue, vartype, emptyok, is_hidden, description) VALUES ('FILTER_SUGGEST_ANDOR','yes','string','no','no','Suggest and/or selector in list filter')";
194 $query[] = "INSERT INTO `Config` (varname, varvalue, vartype, emptyok, is_hidden, description) VALUES ('FILTER_SUGGEST_TAGS','yes','string','no','no','Suggest tags in list filter')";
195 $query[] = "INSERT INTO `Config` (varname, varvalue, vartype, emptyok, is_hidden, description) VALUES ('FILTER_SUGGEST_PREDICATES','yes','string','no','no','Suggest predicates in list filter')";
196 $query[] = "INSERT INTO `Config` (varname, varvalue, vartype, emptyok, is_hidden, description) VALUES ('FILTER_SUGGEST_EXTRA','no','string','no','no','Suggest extra expression in list filter')";
197 $query[] = "delete from Config where varname = 'USER_AUTH_SRC'";
198 $query[] = "delete from Config where varname = 'COOKIE_TTL'";
199 $query[] = "delete from Config where varname = 'rtwidth_0'";
200 $query[] = "delete from Config where varname = 'rtwidth_1'";
201 $query[] = "delete from Config where varname = 'rtwidth_2'";
202 $query[] = "delete from Config where varname = 'NAMEFUL_OBJTYPES'";
203 $query[] = "delete from Config where varname = 'REQUIRE_ASSET_TAG_FOR'";
204 $query[] = "delete from Config where varname = 'IPV4_PERFORMERS'";
205 $query[] = "delete from Config where varname = 'NATV4_PERFORMERS'";
206 $query[] = "alter table TagTree add column valid_realm set('file','ipv4net','ipv4vs','ipv4rspool','object','rack','user') not null default 'file,ipv4net,ipv4vs,ipv4rspool,object,rack,user' after parent_id";
207 $result = $dbxlink->query ("select user_id, user_name, user_realname from UserAccount where user_enabled = 'no'");
208 while ($row = $result->fetch (PDO
::FETCH_ASSOC
))
209 $query[] = "update Script set script_text = concat('deny {\$userid_${row['user_id']}} # ${row['user_name']} (${row['user_realname']})\n', script_text) where script_name = 'RackCode'";
210 $query[] = "update Script set script_text = NULL where script_name = 'RackCodeCache'";
212 $query[] = "alter table UserAccount drop column user_enabled";
214 $query[] = "CREATE TABLE RackRow ( id int(10) unsigned NOT NULL auto_increment, name char(255) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM";
216 $result = $dbxlink->query ("select dict_key, dict_value from Dictionary where chapter_no = 3");
217 while($row = $result->fetch(PDO
::FETCH_NUM
))
219 $query[] = "insert into RackRow set id=${row[0]}, name='${row[1]}'";
221 $query[] = "delete from Dictionary where chapter_id = 3";
222 $query[] = "delete from Chapter where id = 3";
224 CREATE TABLE `LDAPCache` (
225 `presented_username` char(64) NOT NULL,
226 `successful_hash` char(40) NOT NULL,
227 `first_success` timestamp NOT NULL default CURRENT_TIMESTAMP,
228 `last_retry` timestamp NOT NULL default '0000-00-00 00:00:00',
229 `displayed_name` char(128) default NULL,
231 UNIQUE KEY `presented_username` (`presented_username`),
232 KEY `scanidx` (`presented_username`,`successful_hash`)
234 $query[] = "alter table UserAccount modify column user_password_hash char(40) NULL";
235 $query[] = 'ALTER TABLE Rack DROP COLUMN deleted';
236 $query[] = 'ALTER TABLE RackHistory DROP COLUMN deleted';
237 $query[] = 'ALTER TABLE RackObject DROP COLUMN deleted';
238 $query[] = 'ALTER TABLE RackObjectHistory DROP COLUMN deleted';
239 // Can't be added straight due to many duplicates, even in "dictbase" data.
240 $result = $dbxlink->query ('SELECT type1, type2, count(*) - 1 as excess FROM PortCompat GROUP BY type1, type2 HAVING excess > 0');
241 while ($row = $result->fetch (PDO
::FETCH_ASSOC
))
242 $query[] = "DELETE FROM PortCompat WHERE type1 = ${row['type1']} AND type2 = ${row['type2']} limit ${row['excess']}";
244 $query[] = 'ALTER TABLE PortCompat DROP KEY type1';
245 $query[] = 'ALTER TABLE PortCompat ADD UNIQUE (type1, type2)';
246 $query[] = "UPDATE Config SET varvalue = '0.17.0' WHERE varname = 'DB_VERSION'";
250 showError ("executeUpgradeBatch () failed, because batch '${batchid}' isn't defined", __FILE__
);
255 echo "<tr><th>Executing batch '${batchid}'</th><td>";
256 foreach ($query as $q)
258 $result = $dbxlink->query ($q);
261 $errorInfo = $dbxlink->errorInfo();
262 $failures[] = array ($q, $errorInfo[2]);
265 if (!count ($failures))
266 echo "<strong><font color=green>done</font></strong>";
269 echo "<strong><font color=red>The following queries failed:</font></strong><br><pre>";
270 foreach ($failures as $f)
273 echo "${q} -- ${i}\n";
280 // ******************************************************************
282 // Execution starts here
284 // ******************************************************************
286 $root = (empty($_SERVER['HTTPS']) or $_SERVER['HTTPS'] == 'off') ?
'http://' : 'https://';
287 $root .= isset ($_SERVER['HTTP_HOST']) ?
$_SERVER['HTTP_HOST'] : ($_SERVER['SERVER_NAME'].($_SERVER['SERVER_PORT']=='80'?
'':$_SERVER['SERVER_PORT']));
288 $root .= strtr (dirname ($_SERVER['PHP_SELF']), '\\', '/');
289 if (substr ($root, -1) != '/')
292 // The below will be necessary as long as we rely on showError()
293 require_once 'inc/interface.php';
295 require_once 'inc/config.php';
296 require_once 'inc/database.php';
297 if (file_exists ('local/secret.php'))
298 require_once 'local/secret.php';
299 elseif (file_exists ('inc/secret.php')) // 0.16.x -> 0.17.x upgrade
301 require_once 'inc/secret.php';
302 $user_auth_src = getConfigVar ('USER_AUTH_SRC');
305 die ("Database connection parameters are read from local/secret.php file, " .
306 "which cannot be found.\nCopy provided config/secret-sample.php to " .
307 "local/secret.php and modify to your setup.\n\nThen reload the page.");
311 $dbxlink = new PDO ($pdo_dsn, $db_username, $db_password);
313 catch (PDOException
$e)
315 die ("Database connection failed:\n\n" . $e->getMessage());
318 // Now we need to be sure that the current user is the administrator.
319 // The rest doesn't matter within this context.
321 function authenticate_admin ($username, $password)
324 $hash = sha1 ($password);
325 $query = "select count(*) from UserAccount where user_id = 1 and user_name = '${username}' and user_password_hash = '${hash}'";
326 if (($result = $dbxlink->query ($query)) == NULL)
327 die ('SQL query failed in ' . __FUNCTION__
);
328 $rows = $result->fetchAll (PDO
::FETCH_NUM
);
329 return $rows[0][0] == 1;
332 switch ($user_auth_src)
335 case 'ldap': // authenticate against DB as well
338 !isset ($_SERVER['PHP_AUTH_USER']) or
339 !strlen ($_SERVER['PHP_AUTH_USER']) or
340 !isset ($_SERVER['PHP_AUTH_PW']) or
341 !strlen ($_SERVER['PHP_AUTH_PW']) or
342 !authenticate_admin (escapeString ($_SERVER['PHP_AUTH_USER']), escapeString ($_SERVER['PHP_AUTH_PW']))
345 header ('WWW-Authenticate: Basic realm="RackTables upgrade"');
346 header ('HTTP/1.0 401 Unauthorized');
347 showError ('You must be authenticated as an administrator to complete the upgrade.', __FILE__
);
354 !isset ($_SERVER['REMOTE_USER']) or
355 !strlen ($_SERVER['REMOTE_USER'])
358 showError ('System misconfiguration. The web-server didn\'t authenticate the user, although ought to do.');
363 showError ('authentication source misconfiguration', __FILE__
);
367 $dbver = getDatabaseVersion();
368 echo '<table border=1>';
369 echo "<tr><th>Current status</th><td>Data version: ${dbver}<br>Code version: " . CODE_VERSION
. "</td></tr>\n";
371 $path = getDBUpgradePath ($dbver, CODE_VERSION
);
374 echo "<tr><th>Upgrade path</th><td><font color=red>not found</font></td></tr>\n";
375 echo "<tr><th>Summary</th><td>Check README for more information.</td></tr>\n";
380 echo "<tr><th>Summary</th><td>Come back later.</td></tr>\n";
383 echo "<tr><th>Upgrade path</th><td>${dbver} → " . implode (' → ', $path) . "</td></tr>\n";
384 foreach ($path as $batchid)
386 executeUpgradeBatch ($batchid);
387 if (isset ($relnotes[$batchid]))
388 echo "<tr><th>Release notes for ${batchid}</th><td>" . $relnotes[$batchid] . "</td></tr>\n";
390 echo "<tr><th>Summary</th><td>Upgrade complete, it is Ok to <a href='${root}'>enter</a> the system.</td></tr>\n";