Passed
Push — master ( 111bd7...9273d1 )
by Stefan
06:58
created

disp_name()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 3
c 0
b 0
f 0
rs 10
cc 2
eloc 2
nc 2
nop 1
1
<?php
2
/*
3
 * *****************************************************************************
4
 * Contributions to this work were made on behalf of the GÉANT project, a 
5
 * project that has received funding from the European Union’s Framework 
6
 * Programme 7 under Grant Agreements No. 238875 (GN3) and No. 605243 (GN3plus),
7
 * Horizon 2020 research and innovation programme under Grant Agreements No. 
8
 * 691567 (GN4-1) and No. 731122 (GN4-2).
9
 * On behalf of the aforementioned projects, GEANT Association is the sole owner
10
 * of the copyright in all material which was developed by a member of the GÉANT
11
 * project. GÉANT Vereniging (Association) is registered with the Chamber of 
12
 * Commerce in Amsterdam with registration number 40535155 and operates in the 
13
 * UK as a branch of GÉANT Vereniging.
14
 * 
15
 * Registered office: Hoekenrode 3, 1102BR Amsterdam, The Netherlands. 
16
 * UK branch address: City House, 126-130 Hills Road, Cambridge CB2 1PQ, UK
17
 *
18
 * License: see the web/copyright.inc.php file in the file structure or
19
 *          <base_url>/copyright.php after deploying the software
20
 */
21
22
require_once dirname(dirname(dirname(__FILE__))) . "/config/_config.php";
23
24
$loggerInstance = new \core\common\Logging();
25
$validator = new \web\lib\common\InputValidation();
26
$languageInstance = new \core\common\Language();
27
$languageInstance->setTextDomain("diagnostics");
28
29
30
31
$additional_message = [
32
    \core\common\Entity::L_OK => '',
33
    \core\common\Entity::L_REMARK => _("Some properties of the connection attempt were sub-optimal; the list is below."),
34
    \core\common\Entity::L_WARN => _("Some properties of the connection attempt were sub-optimal; the list is below."),
35
    \core\common\Entity::L_ERROR => _("Some configuration errors were observed; the list is below."),
36
];
37
38
if (!isset($_REQUEST['test_type']) || !$_REQUEST['test_type']) {
39
    throw new Exception("No test type specified!");
40
}
41
42
$test_type = $_REQUEST['test_type'];
43
44
$check_realm = $validator->realm($_REQUEST['realm']);
45
46
if ($check_realm === FALSE) {
47
    throw new Exception("Invalid realm was submitted!");
48
}
49
50
if (isset($_REQUEST['profile_id'])) {
51
    $my_profile = $validator->existingProfile($_REQUEST['profile_id']);
52
    if (!$my_profile instanceof \core\ProfileRADIUS) {
53
        throw new Exception("RADIUS Tests can only be performed on RADIUS Profiles (d'oh!)");
54
    }
55
    $testsuite = new \core\diag\RADIUSTests($check_realm, $my_profile->getRealmCheckOuterUsername(), $my_profile->getEapMethodsinOrderOfPreference(1), $my_profile->getCollapsedAttributes()['eap:server_name'], $my_profile->getCollapsedAttributes()['eap:ca_file']);
56
} else {
57
    $my_profile = NULL;
58
    $testsuite = new \core\diag\RADIUSTests($check_realm, "@".$check_realm);
59
}
60
61
62
$hostindex = $_REQUEST['hostindex'];
63
if (!is_numeric($hostindex)) {
64
    throw new Exception("The requested host index is not numeric!");
65
}
66
67
$posted_host = $_REQUEST['src'];
68
if (is_numeric($posted_host)) { // UDP tests, this is an index to the test host in config
69
    $host = filter_var(\config\Diagnostics::RADIUSTESTS['UDP-hosts'][$hostindex]['ip'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE);
70
} else { // dynamic discovery host, potentially unvetted user input
71
    // contains port number; needs to be redacted for filter_var to work
72
    // in any case, it's a printable string, so filter it initially
73
    
74
    $filteredHost = filter_input(INPUT_GET,'src', FILTER_SANITIZE_STRING) ?? filter_input(INPUT_POST,'src', FILTER_SANITIZE_STRING);
75
    $hostonly1 = preg_replace('/:[0-9]*$/', "", $filteredHost);
76
    $hostonly2 = preg_replace('/^\[/', "", $hostonly1);
77
    $hostonly3 = preg_replace('/\]$/', "", $hostonly2);
78
    $hostonly = filter_var($hostonly3, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE);
79
    // check if this is a valid IP address
80
    if ($hostonly === FALSE) {
81
        throw new Exception("The configured test host ($hostonly) is not a valid IP address from acceptable IP ranges!");
82
    }
83
    // host IP address testing passed. So let's take our port number back
84
    $host = $filteredHost;
85
    
86
}
87
88
89
90
$returnarray = [];
91
$timeout = \config\Diagnostics::RADIUSTESTS['UDP-hosts'][$hostindex]['timeout'];
92
switch ($test_type) {
93
    case 'udp_login':
94
        $i = 0;
95
        $returnarray['hostindex'] = $hostindex;
96
        $eaps = $my_profile->getEapMethodsinOrderOfPreference(1);
97
        $user_name = $validator->syntaxConformUser(isset($_REQUEST['username']) && $_REQUEST['username'] ? $_REQUEST['username'] : "");
98
        $outer_user_name = $validator->syntaxConformUser(isset($_REQUEST['outer_username']) && $_REQUEST['outer_username'] ? $_REQUEST['outer_username'] : $user_name);
99
        $testsuite->setOuterIdentity($outer_user_name);
100
        $user_password = isset($_REQUEST['password']) && $_REQUEST['password'] ? $_REQUEST['password'] : ""; //!!
101
        $returnarray['result'] = [];
102
        foreach ($eaps as $eap) {
103
            if ($eap->getIntegerRep() == \core\common\EAP::INTEGER_TLS) {
104
                $run_test = TRUE;
105
                if ($_FILES['cert']['error'] == UPLOAD_ERR_OK) {
106
                    $clientcertdata = file_get_contents($_FILES['cert']['tmp_name']);
107
                    $privkey_pass = isset($_REQUEST['privkey_pass']) && $_REQUEST['privkey_pass'] ? $_REQUEST['privkey_pass'] : ""; //!!
108
                    if (isset($_REQUEST['tls_username']) && $_REQUEST['tls_username']) {
109
                        $tls_username = $validator->syntaxConformUser(filter_input(INPUT_POST, 'tls_username', FILTER_SANITIZE_STRING));
110
                    } else {
111
                        if (openssl_pkcs12_read($clientcertdata, $certs, $privkey_pass)) {
112
                            $mydetails = openssl_x509_parse($certs['cert']);
113
                            if (isset($mydetails['subject']['CN']) && $mydetails['subject']['CN']) {
114
                                $tls_username = $mydetails['subject']['CN'];
115
                                $loggerInstance->debug(4, "PKCS12-CN=$tls_username\n");
116
                            } else {
117
                                $testresult = \core\diag\RADIUSTests::RETVAL_INCOMPLETE_DATA;
118
                                $run_test = FALSE;
119
                            }
120
                        } else {
121
                            $testresult = \core\diag\RADIUSTests::RETVAL_WRONG_PKCS12_PASSWORD;
122
                            $run_test = FALSE;
123
                        }
124
                    }
125
                } else {
126
                    $testresult = \core\diag\RADIUSTests::RETVAL_INCOMPLETE_DATA;
127
                    $run_test = FALSE;
128
                }
129
                if ($run_test) {
130
                    $loggerInstance->debug(4, "TLS-USERNAME=$tls_username\n");
131
                    $testresult = $testsuite->udpLogin($hostindex, $eap->getArrayRep(), $tls_username, $privkey_pass, TRUE, TRUE, $clientcertdata);
132
                }
133
            } else {
134
                $testresult = $testsuite->udpLogin($hostindex, $eap->getArrayRep(), $user_name, $user_password);
135
            }
136
            $returnarray['result'][$i] = $testsuite->consolidateUdpResult($hostindex);
137
            $returnarray['result'][$i]['eap'] = $eap->getPrintableRep();
138
            $returnarray['returncode'][$i] = $testresult;
139
140
141
            switch ($testresult) {
142
                case \core\diag\RADIUSTests::RETVAL_OK:
143
                    $level = $returnarray['result'][$i]['level'];
144
                    switch ($level) {
145
                        case \core\common\Entity::L_OK:
146
                            $message = _("<strong>Test successful.</strong>");
147
                            break;
148
                        case \core\common\Entity::L_REMARK:
149
                        case \core\common\Entity::L_WARN:
150
                            $message = _("<strong>Test partially successful</strong>: authentication succeded.") . ' ' . $additional_message[$level];
151
                            break;
152
                        case \core\common\Entity::L_ERROR:
153
                            $message = _("<strong>Test FAILED</strong>: authentication succeded.") . ' ' . $additional_message[$level];
154
                            break;
155
                    }
156
                    break;
157
                case \core\diag\RADIUSTests::RETVAL_CONVERSATION_REJECT:
158
                    $message = _("<strong>Test FAILED</strong>: the request was rejected. The most likely cause is that you have misspelt the Username and/or the Password.");
159
                    $level = \core\common\Entity::L_ERROR;
160
                    break;
161
                case \core\diag\RADIUSTests::RETVAL_NOTCONFIGURED:
162
                    $level = \core\common\Entity::L_ERROR;
163
                    $message = _("This method cannot be tested");
164
                    break;
165
                case \core\diag\RADIUSTests::RETVAL_IMMEDIATE_REJECT:
166
                    $level = \core\common\Entity::L_ERROR;
167
                    $message = _("<strong>Test FAILED</strong>: the request was rejected immediately, without EAP conversation. Either you have misspelt the Username or there is something seriously wrong with your server.");
168
                    unset($returnarray['result'][$i]['cert_oddities']);
169
                    $returnarray['result'][$i]['server'] = 0;
170
                    break;
171
                case \core\diag\RADIUSTests::RETVAL_NO_RESPONSE:
172
                    $level = \core\common\Entity::L_ERROR;
173
                    $message = sprintf(_("<strong>Test FAILED</strong>: no reply from the RADIUS server after %d seconds. Either the responsible server is down, or routing is broken!"), $timeout);
174
                    unset($returnarray['result'][$i]['cert_oddities']);
175
                    $returnarray['result'][$i]['server'] = 0;
176
                    break;
177
                case \core\diag\RADIUSTests::RETVAL_SERVER_UNFINISHED_COMM:
178
                    $returnarray['message'] = sprintf(_("<strong>Test FAILED</strong>: there was a bidirectional RADIUS conversation, but it did not finish after %d seconds!"), $timeout);
179
                    $returnarray['level'] = \core\common\Entity::L_ERROR;
180
                    break;
181
                default:
182
                    $level = isset($testsuite->returnCodes[$testresult]['severity']) ? $testsuite->returnCodes[$testresult]['severity'] : \core\common\Entity::L_ERROR;
183
                    $message = isset($testsuite->returnCodes[$testresult]['message']) ? $testsuite->returnCodes[$testresult]['message'] : _("<strong>Test FAILED</strong>");
184
                    $returnarray['result'][$i]['server'] = 0;
185
                    break;
186
            }
187
            $returnarray['result'][$i]['level'] = $level;
188
            $returnarray['result'][$i]['message'] = $message;
189
            $i++;
190
        }
191
        break;
192
    case 'udp':
193
        $i = 0;
194
        $returnarray['hostindex'] = $hostindex;
195
        $testresult = $testsuite->udpReachability($hostindex);
196
        $returnarray['result'][$i] = $testsuite->consolidateUdpResult($hostindex);
197
        $returnarray['result'][$i]['eap'] = 'ALL';
198
        $returnarray['returncode'][$i] = $testresult;
199
        // a failed check may not have gotten any certificate, be prepared for that
200
        switch ($testresult) {
201
            case \core\diag\RADIUSTests::RETVAL_CONVERSATION_REJECT:
202
                $level = $returnarray['result'][$i]['level'];
203
                if ($level > \core\common\Entity::L_OK) {
204
                    $message = _("<strong>Test partially successful</strong>: a bidirectional RADIUS conversation with multiple round-trips was carried out, and ended in an Access-Reject as planned.") . ' ' . $additional_message[$level];
205
                } else {
206
                    $message = _("<strong>Test successful</strong>: a bidirectional RADIUS conversation with multiple round-trips was carried out, and ended in an Access-Reject as planned.");
207
                }
208
                break;
209
            case \core\diag\RADIUSTests::RETVAL_IMMEDIATE_REJECT:
210
                $message = _("<strong>Test FAILED</strong>: the request was rejected immediately, without EAP conversation. This is not necessarily an error: if the RADIUS server enforces that outer identities correspond to an existing username, then this result is expected (Note: you could configure a valid outer identity in your profile settings to get past this hurdle). In all other cases, the server appears misconfigured or it is unreachable.");
211
                $level = \core\common\Entity::L_WARN;
212
                break;
213
            case \core\diag\RADIUSTests::RETVAL_NO_RESPONSE:
214
                $returnarray['result'][$i]['server'] = 0;
215
                $message = sprintf(_("<strong>Test FAILED</strong>: no reply from the RADIUS server after %d seconds. Either the responsible server is down, or routing is broken!"), $timeout);
216
                $level = \core\common\Entity::L_ERROR;
217
                break;
218
            case \core\diag\RADIUSTests::RETVAL_SERVER_UNFINISHED_COMM:
219
                $message = sprintf(_("<strong>Test FAILED</strong>: there was a bidirectional RADIUS conversation, but it did not finish after %d seconds!"), $timeout);
220
                $level = \core\common\Entity::L_ERROR;
221
                break;
222
            default:
223
                $message = _("unhandled error");
224
                $level = \core\common\Entity::L_ERROR;
225
                break;
226
        }
227
        $loggerInstance->debug(4, "SERVER=" . $returnarray['result'][$i]['server'] . "\n");
228
        $returnarray['result'][$i]['level'] = $level;
229
        $returnarray['result'][$i]['message'] = $message;
230
        break;
231
    case 'capath':
232
        $rfc6614suite = new \core\diag\RFC6614Tests([$host]);
233
        $testresult = $rfc6614suite->cApathCheck($host);
234
        $returnarray['IP'] = $host;
235
        $returnarray['hostindex'] = $hostindex;
236
        // the host member of the array may not be set if RETVAL_SKIPPED was
237
        // returned (e.g. IPv6 host), be prepared for that
238
        if (isset($rfc6614suite->TLS_CA_checks_result[$host])) {
239
            $returnarray['time_millisec'] = sprintf("%d", $rfc6614suite->TLS_CA_checks_result[$host]['time_millisec']);
240
            if (isset($rfc6614suite->TLS_CA_checks_result[$host]['cert_oddity']) && ($rfc6614suite->TLS_CA_checks_result[$host]['cert_oddity'] == \core\diag\RADIUSTests::CERTPROB_UNKNOWN_CA)) {
241
                $returnarray['message'] = _("<strong>ERROR</strong>: the server presented a certificate which is from an unknown authority!") . ' (' . sprintf(_("elapsed time: %d"), $rfc6614suite->TLS_CA_checks_result[$host]['time_millisec']) . '&nbsp;ms)';
242
                $returnarray['level'] = \core\common\Entity::L_ERROR;
243
            } else {
244
                $returnarray['message'] = $rfc6614suite->returnCodes[$rfc6614suite->TLS_CA_checks_result[$host]['status']]["message"];
245
                $returnarray['level'] = \core\common\Entity::L_OK;
246
                if ($rfc6614suite->TLS_CA_checks_result[$host]['status'] != \core\diag\RADIUSTests::RETVAL_CONNECTION_REFUSED) {
247
                    $returnarray['message'] .= ' (' . sprintf(_("elapsed time: %d"), $rfc6614suite->TLS_CA_checks_result[$host]['time_millisec']) . '&nbsp;ms)';
248
                } else {
249
                    $returnarray['level'] = \core\common\Entity::L_ERROR;
250
                }
251
                if ($rfc6614suite->TLS_CA_checks_result[$host]['status'] == \core\diag\RADIUSTests::RETVAL_OK) {
252
                    $returnarray['certdata'] = [];
253
                    $returnarray['certdata']['subject'] = $rfc6614suite->TLS_CA_checks_result[$host]['certdata']['subject'];
254
                    $returnarray['certdata']['issuer'] = $rfc6614suite->TLS_CA_checks_result[$host]['certdata']['issuer'];
255
                    $returnarray['certdata']['extensions'] = [];
256
                    if (isset($rfc6614suite->TLS_CA_checks_result[$host]['certdata']['extensions']['subjectaltname'])) {
257
                        $returnarray['certdata']['extensions']['subjectaltname'] = $rfc6614suite->TLS_CA_checks_result[$host]['certdata']['extensions']['subjectaltname'];
258
                    }
259
                    if (isset($rfc6614suite->TLS_CA_checks_result[$host]['certdata']['extensions']['policyoid'])) {
260
                        $returnarray['certdata']['extensions']['policies'] = join(' ', $rfc6614suite->TLS_CA_checks_result[$host]['certdata']['extensions']['policyoid']);
261
                    }
262
                    if (isset($rfc6614suite->TLS_CA_checks_result[$host]['certdata']['extensions']['crlDistributionPoint'])) {
263
                        $returnarray['certdata']['extensions']['crldistributionpoints'] = $rfc6614suite->TLS_CA_checks_result[$host]['certdata']['extensions']['crlDistributionPoint'];
264
                    }
265
                    if (isset($rfc6614suite->TLS_CA_checks_result[$host]['certdata']['extensions']['authorityInfoAccess'])) {
266
                        $returnarray['certdata']['extensions']['authorityinfoaccess'] = $rfc6614suite->TLS_CA_checks_result[$host]['certdata']['extensions']['authorityInfoAccess'];
267
                    }
268
                }
269
                $returnarray['cert_oddities'] = [];
270
            }
271
        }
272
        $returnarray['result'] = $testresult;
273
        break;
274
    case 'clients':
275
        $rfc6614suite = new \core\diag\RFC6614Tests([$host]);
276
        $testresult = $rfc6614suite->tlsClientSideCheck($host);
277
        $returnarray['IP'] = $host;
278
        $returnarray['hostindex'] = $hostindex;
279
        $k = 0;
280
        // the host member of the array may not exist if RETVAL_SKIPPED came out
281
        // (e.g. no client cert to test with). Be prepared for that
282
        if (isset($rfc6614suite->TLS_clients_checks_result[$host])) {
283
            foreach ($rfc6614suite->TLS_clients_checks_result[$host]['ca'] as $type => $cli) {
284
                foreach ($cli as $key => $val) {
285
                    $returnarray['ca'][$k][$key] = $val;
286
                }
287
                $k++;
288
            }
289
        }
290
        $returnarray['result'] = $testresult;
291
        break;
292
293
    default:
294
        throw new Exception("Unknown test requested: default case reached!");
295
}
296
297
echo(json_encode($returnarray));
298
299