|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
/* * ********************************************************************************* |
|
4
|
|
|
* (c) 2011-15 GÉANT on behalf of the GN3, GN3plus and GN4 consortia |
|
5
|
|
|
* License: see the LICENSE file in the root directory |
|
6
|
|
|
* ********************************************************************************* */ |
|
7
|
|
|
?> |
|
8
|
|
|
<?php |
|
9
|
|
|
|
|
10
|
|
|
require_once(dirname(dirname(dirname(dirname(__FILE__)))) . "/config/_config.php"); |
|
11
|
|
|
|
|
12
|
|
|
require_once("Helper.php"); |
|
13
|
|
|
require_once("Options.php"); |
|
14
|
|
|
require_once("CAT.php"); |
|
15
|
|
|
require_once("X509.php"); |
|
16
|
|
|
require_once("EAP.php"); |
|
17
|
|
|
require_once("DBConnection.php"); |
|
18
|
|
|
|
|
19
|
|
|
require_once("input_validation.inc.php"); |
|
20
|
|
|
require_once("auth.inc.php"); // no authentication here, but we need to check if authenticated |
|
21
|
|
|
|
|
22
|
|
|
define("BUTTON_CLOSE", 0); |
|
23
|
|
|
define("BUTTON_CONTINUE", 1); |
|
24
|
|
|
define("BUTTON_DELETE", 2); |
|
25
|
|
|
define("BUTTON_SAVE", 3); |
|
26
|
|
|
define("BUTTON_EDIT", 4); |
|
27
|
|
|
define("BUTTON_TAKECONTROL", 5); |
|
28
|
|
|
define("BUTTON_PURGECACHE", 6); |
|
29
|
|
|
define("BUTTON_FLUSH_AND_RESTART", 7); |
|
30
|
|
|
define("BUTTON_SANITY_TESTS", 8); |
|
31
|
|
|
|
|
32
|
|
|
$global_location_count = 0; |
|
33
|
|
|
|
|
34
|
|
|
function display_name($input) { |
|
35
|
|
|
$DisplayNames = [_("Support: Web") => "support:url", |
|
36
|
|
|
_("Support: EAP Types") => "support:eap_types", |
|
37
|
|
|
_("Support: Phone") => "support:phone", |
|
38
|
|
|
_("Support: E-Mail") => "support:email", |
|
39
|
|
|
_("Institution Name") => "general:instname", |
|
40
|
|
|
_("Location") => "general:geo_coordinates", |
|
41
|
|
|
_("Logo URL") => "general:logo_url", |
|
42
|
|
|
_("Logo image") => "general:logo_file", |
|
43
|
|
|
_("Configure Wired Ethernet") => "media:wired", |
|
44
|
|
|
_("Name (CN) of Authentication Server") => "eap:server_name", |
|
45
|
|
|
_("Enable device assessment") => "eap:enable_nea", |
|
46
|
|
|
_("Terms of Use") => "support:info_file", |
|
47
|
|
|
_("CA Certificate URL") => "eap:ca_url", |
|
48
|
|
|
_("CA Certificate File") => "eap:ca_file", |
|
49
|
|
|
_("Profile Display Name") => "profile:name", |
|
50
|
|
|
_("Production-Ready") => "profile:production", |
|
51
|
|
|
_("Extra text on downloadpage for device") => "device-specific:customtext", |
|
52
|
|
|
_("Redirection Target") => "device-specific:redirect", |
|
53
|
|
|
_("Extra text on downloadpage for EAP method") => "eap-specific:customtext", |
|
54
|
|
|
_("Turn on selection of EAP-TLS User-Name") => "eap-specific:tls_use_other_id", |
|
55
|
|
|
_("Profile Description") => "profile:description", |
|
56
|
|
|
_("Federation Administrator") => "user:fedadmin", |
|
57
|
|
|
_("Real Name") => "user:realname", |
|
58
|
|
|
_("E-Mail Address") => "user:email", |
|
59
|
|
|
_("PEAP-MSCHAPv2") => EAP::$PEAP_MSCHAP2, |
|
60
|
|
|
_("TLS") => EAP::$TLS, |
|
61
|
|
|
_("TTLS-PAP") => EAP::$TTLS_PAP, |
|
62
|
|
|
_("TTLS-MSCHAPv2") => EAP::$TTLS_MSCHAP2, |
|
63
|
|
|
_("TTLS-GTC") => EAP::$TTLS_GTC, |
|
64
|
|
|
_("FAST-GTC") => EAP::$FAST_GTC, |
|
65
|
|
|
_("EAP-pwd") => EAP::$PWD, |
|
66
|
|
|
_("eduroam-as-a-service") => EAP::$SILVERBULLET, |
|
67
|
|
|
_("Remove/Disable SSID") => "media:remove_SSID", |
|
68
|
|
|
_("Custom CSS file for User Area") => "fed:css_file", |
|
69
|
|
|
_("Federation Logo") => "fed:logo_file", |
|
70
|
|
|
_("Preferred Skin for User Area") => "fed:desired_skin", |
|
71
|
|
|
_("Federation Operator Name") => "fed:realname", |
|
72
|
|
|
_("Custom text in IdP Invitations") => "fed:custominvite", |
|
73
|
|
|
_("Enable Silver Bullet") => "fed:silverbullet", |
|
74
|
|
|
_("Silver Bullet: Do not terminate EAP") => "fed:silverbullet-noterm", |
|
75
|
|
|
_("Silver Bullet: max users per profile") => "fed:silverbullet-maxusers", |
|
76
|
|
|
]; |
|
77
|
|
|
|
|
78
|
|
|
if (count(Config::$CONSORTIUM['ssid']) > 0) { |
|
79
|
|
|
$DisplayNames[_("Additional SSID")] = "media:SSID"; |
|
80
|
|
|
$DisplayNames[_("Additional SSID (with WPA/TKIP)")] = "media:SSID_with_legacy"; |
|
81
|
|
|
} else { |
|
82
|
|
|
$DisplayNames[_("SSID")] = "media:SSID"; |
|
83
|
|
|
$DisplayNames[_("SSID (with WPA/TKIP)")] = "media:SSID_with_legacy"; |
|
84
|
|
|
} |
|
85
|
|
|
|
|
86
|
|
|
if (!empty(Config::$CONSORTIUM['interworking-consortium-oi']) && count(Config::$CONSORTIUM['interworking-consortium-oi']) > 0) { |
|
87
|
|
|
$DisplayNames[_("Additional HS20 Consortium OI")] = "media:consortium_OI"; |
|
88
|
|
|
} else { |
|
89
|
|
|
$DisplayNames[_("HS20 Consortium OI")] = "media:consortium_OI"; |
|
90
|
|
|
} |
|
91
|
|
|
|
|
92
|
|
|
$find = array_search($input, $DisplayNames); |
|
93
|
|
|
|
|
94
|
|
|
if ($find === FALSE) { // sending back the original if we didn't find a better name |
|
95
|
|
|
$find = $input; |
|
96
|
|
|
} |
|
97
|
|
|
return $find; |
|
98
|
|
|
} |
|
99
|
|
|
|
|
100
|
|
|
function tooltip($input) { |
|
101
|
|
|
$descriptions = []; |
|
102
|
|
|
if (count(Config::$CONSORTIUM['ssid']) > 0) { |
|
103
|
|
|
$descriptions[sprintf(_("This attribute can be set if you want to configure an additional SSID besides the default SSIDs for %s. It is almost always a bad idea not to use the default SSIDs. The only exception is if you have premises with an overlap of the radio signal with another %s hotspot. Typical misconceptions about additional SSIDs include: I want to have a local SSID for my own users. It is much better to use the default SSID and separate user groups with VLANs. That approach has two advantages: 1) your users will configure %s properly because it is their everyday SSID; 2) if you use a custom name and advertise this one as extra secure, your users might at some point roam to another place which happens to have the same SSID name. They might then be misled to believe that they are connecting to an extra secure network while they are not."), Config::$CONSORTIUM['name'], Config::$CONSORTIUM['name'], Config::$CONSORTIUM['name'])] = "media:SSID"; |
|
104
|
|
|
} |
|
105
|
|
|
|
|
106
|
|
|
$find = array_search($input, $descriptions); |
|
107
|
|
|
|
|
108
|
|
|
if ($find === FALSE) { |
|
109
|
|
|
return ""; |
|
110
|
|
|
} |
|
111
|
|
|
return "<span class='tooltip' onclick='alert(\"" . $find . "\")'><img src='../resources/images/icons/question-mark-icon.png" . "'></span>"; |
|
112
|
|
|
} |
|
113
|
|
|
|
|
114
|
|
|
function UI_message($level, $text = 0, $caption = 0, $omittabletags = FALSE) { |
|
115
|
|
|
|
|
116
|
|
|
$UI_messages = [ |
|
117
|
|
|
L_OK => ['icon' => '../resources/images/icons/Quetto/check-icon.png', 'text' => _("OK")], |
|
118
|
|
|
L_REMARK => ['icon' => '../resources/images/icons/Quetto/info-icon.png', 'text' => _("Remark")], |
|
119
|
|
|
L_WARN => ['icon' => '../resources/images/icons/Quetto/danger-icon.png', 'text' => _("Warning!")], |
|
120
|
|
|
L_ERROR => ['icon' => '../resources/images/icons/Quetto/no-icon.png', 'text' => _("Error!")], |
|
121
|
|
|
]; |
|
122
|
|
|
|
|
123
|
|
|
$retval = ""; |
|
124
|
|
|
if (!$omittabletags) |
|
125
|
|
|
$retval .= "<tr><td>"; |
|
126
|
|
|
$caption = $caption !== 0 ? $caption : $UI_messages[$level]['text']; |
|
127
|
|
|
$retval .= "<img class='icon' src='" . $UI_messages[$level]['icon'] . "' alt='" . $caption . "' title='" . $caption . "'/>"; |
|
128
|
|
|
if (!$omittabletags) |
|
129
|
|
|
$retval .= "</td><td>"; |
|
130
|
|
|
if ($text !== 0) |
|
131
|
|
|
$retval .= $text; |
|
132
|
|
|
if (!$omittabletags) |
|
133
|
|
|
$retval .= "</td></tr>"; |
|
134
|
|
|
return $retval; |
|
135
|
|
|
} |
|
136
|
|
|
|
|
137
|
|
|
function UI_okay($text = 0, $caption = 0, $omittabletags = FALSE) { |
|
138
|
|
|
return UI_message(L_OK, $text, $caption, $omittabletags); |
|
139
|
|
|
} |
|
140
|
|
|
|
|
141
|
|
|
function UI_remark($text = 0, $caption = 0, $omittabletags = FALSE) { |
|
142
|
|
|
return UI_message(L_REMARK, $text, $caption, $omittabletags); |
|
143
|
|
|
} |
|
144
|
|
|
|
|
145
|
|
|
function UI_warning($text = 0, $caption = 0, $omittabletags = FALSE) { |
|
146
|
|
|
return UI_message(L_WARN, $text, $caption, $omittabletags); |
|
147
|
|
|
} |
|
148
|
|
|
|
|
149
|
|
|
function UI_error($text = 0, $caption = 0, $omittabletags = FALSE) { |
|
150
|
|
|
return UI_message(L_ERROR, $text, $caption, $omittabletags); |
|
151
|
|
|
} |
|
152
|
|
|
|
|
153
|
|
|
function check_upload_sanity($optiontype, $filename) { |
|
154
|
|
|
switch ($optiontype) { |
|
155
|
|
|
case "general:logo_file": |
|
156
|
|
|
case "fed:logo_file": |
|
157
|
|
|
case "internal:logo_from_url": |
|
158
|
|
|
// we check logo_file with ImageMagick |
|
159
|
|
|
$image = new Imagick(); |
|
160
|
|
|
try { |
|
161
|
|
|
$image->readImageBlob($filename); |
|
162
|
|
|
} catch (ImagickException $exception) { |
|
163
|
|
|
echo "Error" . $exception->getMessage(); |
|
164
|
|
|
return FALSE; |
|
165
|
|
|
} |
|
166
|
|
|
// image survived the sanity check |
|
167
|
|
|
return TRUE; |
|
168
|
|
|
case "eap:ca_file": |
|
169
|
|
|
// echo "Checking $optiontype with file $filename"; |
|
170
|
|
|
$cert = X509::processCertificate($filename); |
|
171
|
|
|
if ($cert) { |
|
172
|
|
|
return TRUE; |
|
173
|
|
|
} |
|
174
|
|
|
// echo "Error! The certificate seems broken!"; |
|
175
|
|
|
return FALSE; |
|
176
|
|
|
case "support:info_file": |
|
177
|
|
|
$info = new finfo(); |
|
178
|
|
|
$filetype = $info->buffer($filename, FILEINFO_MIME_TYPE); |
|
179
|
|
|
|
|
180
|
|
|
// we only take plain text files in UTF-8! |
|
181
|
|
|
if ($filetype == "text/plain" && iconv("UTF-8", "UTF-8", $filename) !== FALSE) { |
|
182
|
|
|
return TRUE; |
|
183
|
|
|
} |
|
184
|
|
|
return FALSE; |
|
185
|
|
|
default: |
|
186
|
|
|
return FALSE; |
|
187
|
|
|
} |
|
188
|
|
|
} |
|
189
|
|
|
|
|
190
|
|
|
function getBlobFromDB($ref, $checkpublic) { |
|
191
|
|
|
|
|
192
|
|
|
$reference = valid_DB_reference($ref); |
|
193
|
|
|
|
|
194
|
|
|
if ($reference == FALSE) { |
|
195
|
|
|
return; |
|
196
|
|
|
} |
|
197
|
|
|
|
|
198
|
|
|
// the data is either public (just give it away) or not; in this case, only |
|
199
|
|
|
// release if the data belongs to admin himself |
|
200
|
|
|
if ($checkpublic) { |
|
201
|
|
|
// we might be called without session context (filepreview) so get the |
|
202
|
|
|
// context if needed |
|
203
|
|
|
if (session_status() != PHP_SESSION_ACTIVE) { |
|
204
|
|
|
session_start(); |
|
205
|
|
|
} |
|
206
|
|
|
$owners = DBConnection::isDataRestricted($reference["table"], $reference["rowindex"]); |
|
207
|
|
|
|
|
208
|
|
|
$owners_condensed = []; |
|
209
|
|
|
|
|
210
|
|
|
if ($owners !== FALSE) { // see if we're authenticated and owners of the data |
|
211
|
|
|
foreach ($owners as $oneowner) { |
|
|
|
|
|
|
212
|
|
|
$owners_condensed[] = $oneowner['ID']; |
|
213
|
|
|
} |
|
214
|
|
|
if (!isAuthenticated()) { |
|
215
|
|
|
return FALSE; // admin-only, but we are not an admin |
|
216
|
|
|
} elseif (array_search($_SESSION['user'], $owners_condensed) === FALSE) { |
|
217
|
|
|
return FALSE; // wrong guy |
|
218
|
|
|
} else { |
|
|
|
|
|
|
219
|
|
|
// carry on and get the data |
|
220
|
|
|
} |
|
221
|
|
|
} |
|
222
|
|
|
} |
|
223
|
|
|
|
|
224
|
|
|
$blob = DBConnection::fetchRawDataByIndex($reference["table"], $reference["rowindex"]); |
|
|
|
|
|
|
225
|
|
|
if (!$blob) { |
|
226
|
|
|
return FALSE; |
|
227
|
|
|
} |
|
228
|
|
|
return $blob; |
|
229
|
|
|
} |
|
230
|
|
|
|
|
231
|
|
|
function display_size($number) { |
|
232
|
|
|
if ($number > 1024 * 1024) { |
|
233
|
|
|
return round($number / 1024 / 1024, 2) . " MiB"; |
|
234
|
|
|
} |
|
235
|
|
|
if ($number > 1024) { |
|
236
|
|
|
return round($number / 1024, 2) . " KiB"; |
|
237
|
|
|
} |
|
238
|
|
|
return $number . " B"; |
|
239
|
|
|
} |
|
240
|
|
|
|
|
241
|
|
|
function previewCAinHTML($ca_reference) { |
|
242
|
|
|
$found = preg_match("/^ROWID-.*/", $ca_reference); |
|
243
|
|
|
if (!$found) { |
|
244
|
|
|
return "<div>" . _("Error, ROWID expected.") . "</div>"; |
|
245
|
|
|
} |
|
246
|
|
|
|
|
247
|
|
|
$ca_blob = base64_decode(getBlobFromDB($ca_reference, FALSE)); |
|
248
|
|
|
|
|
249
|
|
|
$func = new X509; |
|
250
|
|
|
$details = $func->processCertificate($ca_blob); |
|
|
|
|
|
|
251
|
|
|
if ($details === FALSE) { |
|
252
|
|
|
return _("There was an error processing the certificate!"); |
|
253
|
|
|
} |
|
254
|
|
|
|
|
255
|
|
|
$details['name'] = preg_replace('/(.)\/(.)/', "$1<br/>$2", $details['name']); |
|
256
|
|
|
$details['name'] = preg_replace('/\//', "", $details['name']); |
|
257
|
|
|
$certstatus = ( $details['root'] == 1 ? "R" : "I"); |
|
258
|
|
|
if ($details['ca'] == 0 && $details['root'] != 1) { |
|
259
|
|
|
return "<div class='ca-summary' style='background-color:red'><div style='position:absolute; right: 0px; width:20px; height:20px; background-color:maroon; border-radius:10px; text-align: center;'><div style='padding-top:3px; font-weight:bold; color:#ffffff;'>S</div></div>" . _("This is a <strong>SERVER</strong> certificate!") . "<br/>" . $details['name'] . "</div>"; |
|
260
|
|
|
} |
|
261
|
|
|
return "<div class='ca-summary' ><div style='position:absolute; right: 0px; width:20px; height:20px; background-color:#0000ff; border-radius:10px; text-align: center;'><div style='padding-top:3px; font-weight:bold; color:#ffffff;'>$certstatus</div></div>" . $details['name'] . "</div>"; |
|
262
|
|
|
} |
|
263
|
|
|
|
|
264
|
|
|
function previewImageinHTML($image_reference) { |
|
265
|
|
|
$found = preg_match("/^ROWID-.*/", $image_reference); |
|
266
|
|
|
if (!$found) { |
|
267
|
|
|
return "<div>" . _("Error, ROWID expected.") . "</div>"; |
|
268
|
|
|
} |
|
269
|
|
|
return "<img style='max-width:150px' src='inc/filepreview.php?id=" . $image_reference . "' alt='" . _("Preview of logo file") . "'/>"; |
|
270
|
|
|
} |
|
271
|
|
|
|
|
272
|
|
|
function previewInfoFileinHTML($fileReference) { |
|
273
|
|
|
$found = preg_match("/^ROWID-.*/", $fileReference); |
|
274
|
|
|
if (!$found) { |
|
275
|
|
|
return _("<div>Error, ROWID expected, got $fileReference.</div>"); |
|
276
|
|
|
} |
|
277
|
|
|
|
|
278
|
|
|
$fileBlob = unserialize(getBlobFromDB($fileReference, FALSE)); |
|
279
|
|
|
$decodedFileBlob = base64_decode($fileBlob['content']); |
|
280
|
|
|
$fileinfo = new finfo(); |
|
281
|
|
|
return "<div class='ca-summary'>" . _("File exists") . " (" . $fileinfo->buffer($decodedFileBlob, FILEINFO_MIME_TYPE) . ", " . display_size(strlen($decodedFileBlob)) . ")<br/><a href='inc/filepreview.php?id=$fileReference'>" . _("Preview") . "</a></div>"; |
|
282
|
|
|
} |
|
283
|
|
|
|
|
284
|
|
|
function infoblock($optionlist, $class, $level) { |
|
285
|
|
|
// echo "<pre>".print_r($optionlist)."</pre>"; |
|
|
|
|
|
|
286
|
|
|
$google_markers = []; |
|
287
|
|
|
$retval = ""; |
|
288
|
|
|
$optioninfo = Options::instance(); |
|
289
|
|
|
|
|
290
|
|
|
foreach ($optionlist as $option) { |
|
291
|
|
|
$type = $optioninfo->optionType($option['name']); |
|
292
|
|
|
// echo "CLASS $class, OPTIONNAME ".$option['name']." LEVEL $level, TYPE ".$type['type']." FLAG ".$type['flag']."\n"; |
|
|
|
|
|
|
293
|
|
|
if (preg_match('/^' . $class . '/', $option['name']) && $option['level'] == "$level") { |
|
294
|
|
|
// all non-multilang attribs get this assignment ... |
|
295
|
|
|
$language = ""; |
|
296
|
|
|
$content = $option['value']; |
|
297
|
|
|
// ... override them with multilang tags if needed |
|
298
|
|
|
if ($type["flag"] == "ML") { |
|
299
|
|
|
// echo "processing multi-lang ".$option['name']. "with value ".$option['value']; |
|
|
|
|
|
|
300
|
|
|
$taggedarray = unserialize($option['value']); |
|
301
|
|
|
$language = _("default/other languages"); |
|
302
|
|
View Code Duplication |
if ($taggedarray['lang'] != 'C') { |
|
|
|
|
|
|
303
|
|
|
$language = Config::$LANGUAGES[$taggedarray['lang']]['display']; |
|
304
|
|
|
} |
|
305
|
|
|
$content = $taggedarray["content"]; |
|
306
|
|
|
} |
|
307
|
|
|
|
|
308
|
|
|
switch ($type["type"]) { |
|
309
|
|
|
case "coordinates": |
|
310
|
|
|
$coords = unserialize($option['value']); |
|
311
|
|
|
$google_markers[] = $coords; |
|
312
|
|
|
break; |
|
313
|
|
|
case "file": |
|
314
|
|
|
$retval .= "<tr><td>" . display_name($option['name']) . "</td><td>$language</td><td>"; |
|
315
|
|
|
switch ($option['name']) { |
|
316
|
|
|
case "general:logo_file": |
|
317
|
|
|
case "fed:logo_file": |
|
318
|
|
|
$retval .= previewImageinHTML('ROWID-' . $option['level'] . '-' . $option['row']); |
|
319
|
|
|
break; |
|
320
|
|
|
case "eap:ca_file": |
|
321
|
|
|
$retval .= previewCAinHTML('ROWID-' . $option['level'] . '-' . $option['row']); |
|
322
|
|
|
break; |
|
323
|
|
|
case "support:info_file": |
|
324
|
|
|
$retval .= previewInfoFileinHTML('ROWID-' . $option['level'] . '-' . $option['row']); |
|
325
|
|
|
break; |
|
326
|
|
|
default: |
|
327
|
|
|
} |
|
328
|
|
|
break; |
|
329
|
|
|
case "boolean": |
|
330
|
|
|
$retval .= "<tr><td>" . display_name($option['name']) . "</td><td>$language</td><td><strong>" . ($content == "on" ? _("on") : _("off") ) . "</strong></td></tr>"; |
|
331
|
|
|
break; |
|
332
|
|
|
default: |
|
333
|
|
|
$retval .= "<tr><td>" . display_name($option['name']) . "</td><td>$language</td><td><strong>$content</strong></td></tr>"; |
|
334
|
|
|
} |
|
335
|
|
|
} |
|
336
|
|
|
} |
|
337
|
|
|
if (count($google_markers)) { |
|
338
|
|
|
$marker = '<markers>'; |
|
339
|
|
|
$location_count = 0; |
|
340
|
|
|
foreach ($google_markers as $g) { |
|
341
|
|
|
$location_count++; |
|
342
|
|
|
$marker .= '<marker name="' . $location_count . '" lat="' . $g['lat'] . '" lng="' . $g['lon'] . '" />'; |
|
343
|
|
|
} |
|
344
|
|
|
$marker .= '</markers>'; |
|
345
|
|
|
$retval .= '<tr><td><script>markers=\'' . $marker . '\';</script></td><td></td><td></td></tr>'; |
|
346
|
|
|
} |
|
347
|
|
|
|
|
348
|
|
|
|
|
349
|
|
|
return $retval; |
|
350
|
|
|
} |
|
351
|
|
|
|
There are different options of fixing this problem.
If you want to be on the safe side, you can add an additional type-check:
If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:
Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.