Revision ac631bba
Added by Luiz Gustavo S. Costa over 14 years ago
usr/local/captiveportal/index.php | ||
---|---|---|
204 | 204 |
|
205 | 205 |
exit; |
206 | 206 |
|
207 |
function portal_reply_page($redirurl, $type = null, $message = null, $clientmac = null, $clientip = null, $username = null, $password = null) { |
|
208 |
global $g, $config; |
|
209 |
|
|
210 |
/* Get captive portal layout */ |
|
211 |
if ($type == "redir") { |
|
212 |
header("Location: {$redirurl}"); |
|
213 |
return; |
|
214 |
} else if ($type == "login") |
|
215 |
$htmltext = get_include_contents("{$g['varetc_path']}/captiveportal.html"); |
|
216 |
else |
|
217 |
$htmltext = get_include_contents("{$g['varetc_path']}/captiveportal-error.html"); |
|
218 |
|
|
219 |
/* substitute the PORTAL_REDIRURL variable */ |
|
220 |
if ($config['captiveportal']['preauthurl']) { |
|
221 |
$htmltext = str_replace("\$PORTAL_REDIRURL\$", "{$config['captiveportal']['preauthurl']}", $htmltext); |
|
222 |
$htmltext = str_replace("#PORTAL_REDIRURL#", "{$config['captiveportal']['preauthurl']}", $htmltext); |
|
223 |
} |
|
224 |
|
|
225 |
/* substitute other variables */ |
|
226 |
if (isset($config['captiveportal']['httpslogin'])) { |
|
227 |
$htmltext = str_replace("\$PORTAL_ACTION\$", "https://{$config['captiveportal']['httpsname']}:8001/", $htmltext); |
|
228 |
$htmltext = str_replace("#PORTAL_ACTION#", "https://{$config['captiveportal']['httpsname']}:8001/", $htmltext); |
|
229 |
} else { |
|
230 |
$ifip = portal_ip_from_client_ip($clientip); |
|
231 |
if (!$ifip) |
|
232 |
$ourhostname = $config['system']['hostname'] . ":8000"; |
|
233 |
else |
|
234 |
$ourhostname = "{$ifip}:8000"; |
|
235 |
$htmltext = str_replace("\$PORTAL_ACTION\$", "http://{$ourhostname}/", $htmltext); |
|
236 |
$htmltext = str_replace("#PORTAL_ACTION#", "http://{$ourhostname}/", $htmltext); |
|
237 |
} |
|
238 |
|
|
239 |
$htmltext = str_replace("\$PORTAL_REDIRURL\$", htmlspecialchars($redirurl), $htmltext); |
|
240 |
$htmltext = str_replace("\$PORTAL_MESSAGE\$", htmlspecialchars($message), $htmltext); |
|
241 |
$htmltext = str_replace("\$CLIENT_MAC\$", htmlspecialchars($clientmac), $htmltext); |
|
242 |
$htmltext = str_replace("\$CLIENT_IP\$", htmlspecialchars($clientip), $htmltext); |
|
243 |
|
|
244 |
// Special handling case for captive portal master page so that it can be ran |
|
245 |
// through the PHP interpreter using the include method above. We convert the |
|
246 |
// $VARIABLE$ case to #VARIABLE# in /etc/inc/captiveportal.inc before writing out. |
|
247 |
$htmltext = str_replace("#PORTAL_REDIRURL#", htmlspecialchars($redirurl), $htmltext); |
|
248 |
$htmltext = str_replace("#PORTAL_MESSAGE#", htmlspecialchars($message), $htmltext); |
|
249 |
$htmltext = str_replace("#CLIENT_MAC#", htmlspecialchars($clientmac), $htmltext); |
|
250 |
$htmltext = str_replace("#CLIENT_IP#", htmlspecialchars($clientip), $htmltext); |
|
251 |
$htmltext = str_replace("#USERNAME#", htmlspecialchars($username), $htmltext); |
|
252 |
$htmltext = str_replace("#PASSWORD#", htmlspecialchars($password), $htmltext); |
|
253 |
|
|
254 |
echo $htmltext; |
|
255 |
} |
|
256 |
|
|
257 |
function portal_mac_radius($clientmac,$clientip) { |
|
258 |
global $config ; |
|
259 |
|
|
260 |
$radmac_secret = $config['captiveportal']['radmac_secret']; |
|
261 |
|
|
262 |
/* authentication against the radius server */ |
|
263 |
$username = mac_format($clientmac); |
|
264 |
$auth_list = radius($username,$radmac_secret,$clientip,$clientmac,"MACHINE LOGIN"); |
|
265 |
if ($auth_list['auth_val'] == 2) |
|
266 |
return TRUE; |
|
267 |
if (!empty($auth_list['url_redirection'])) |
|
268 |
portal_reply_page($auth_list['url_redirection'], "redir"); |
|
269 |
|
|
270 |
return FALSE; |
|
271 |
} |
|
272 |
|
|
273 |
function portal_allow($clientip,$clientmac,$username,$password = null, $attributes = null, $ruleno = null) { |
|
274 |
|
|
275 |
global $redirurl, $g, $config, $type, $passthrumac, $_POST; |
|
276 |
|
|
277 |
/* See if a ruleno is passed, if not start sessions because this means there isn't one atm */ |
|
278 |
if ($ruleno == null) |
|
279 |
$ruleno = captiveportal_get_next_ipfw_ruleno(); |
|
280 |
|
|
281 |
/* if the pool is empty, return appropriate message and exit */ |
|
282 |
if (is_null($ruleno)) { |
|
283 |
portal_reply_page($redirurl, "error", "System reached maximum login capacity"); |
|
284 |
log_error("WARNING! Captive portal has reached maximum login capacity"); |
|
285 |
exit; |
|
286 |
} |
|
287 |
|
|
288 |
// Ensure we create an array if we are missing attributes |
|
289 |
if (!is_array($attributes)) |
|
290 |
$attributes = array(); |
|
291 |
|
|
292 |
/* read in client database */ |
|
293 |
$cpdb = captiveportal_read_db(); |
|
294 |
|
|
295 |
$radiusservers = captiveportal_get_radius_servers(); |
|
296 |
|
|
297 |
if ($attributes['voucher']) |
|
298 |
$remaining_time = $attributes['session_timeout']; |
|
299 |
|
|
300 |
$writecfg = false; |
|
301 |
/* Find an existing session */ |
|
302 |
if ((isset($config['captiveportal']['noconcurrentlogins'])) && $passthrumac) { |
|
303 |
if (isset($config['captiveportal']['passthrumacadd'])) { |
|
304 |
$mac = captiveportal_passthrumac_findbyname($username); |
|
305 |
if (!empty($mac)) { |
|
306 |
if ($_POST['replacemacpassthru']) { |
|
307 |
foreach ($config['captiveportal']['passthrumac'] as $idx => $macent) { |
|
308 |
if ($macent['mac'] == $mac['mac']) { |
|
309 |
$macrules = ""; |
|
310 |
$ruleno = captiveportal_get_ipfw_passthru_ruleno($mac['mac']); |
|
311 |
if ($ruleno) { |
|
312 |
captiveportal_free_ipfw_ruleno($ruleno, true); |
|
313 |
$macrules .= "delete {$ruleno}\n"; |
|
314 |
++$ruleno; |
|
315 |
$macrules .= "delete {$ruleno}\n"; |
|
316 |
} |
|
317 |
unset($config['captiveportal']['passthrumac'][$idx]); |
|
318 |
$mac['mac'] = $clientmac; |
|
319 |
$config['captiveportal']['passthrumac'][] = $mac; |
|
320 |
$macrules .= captiveportal_passthrumac_configure_entry($mac); |
|
321 |
file_put_contents("{$g['tmp_path']}/macentry.rules.tmp", $macrules); |
|
322 |
mwexec("/sbin/ipfw -q {$g['tmp_path']}/macentry.rules.tmp"); |
|
323 |
$writecfg = true; |
|
324 |
$sessionid = true; |
|
325 |
break; |
|
326 |
} |
|
327 |
} |
|
328 |
} else { |
|
329 |
portal_reply_page($redirurl, "error", "Username: {$username} is already authenticated using another MAC address.", |
|
330 |
$clientmac, $clientip, $username, $password); |
|
331 |
exit; |
|
332 |
} |
|
333 |
} |
|
334 |
} |
|
335 |
} |
|
336 |
|
|
337 |
$nousers = count($cpdb); |
|
338 |
for ($i = 0; $i < $nousers; $i++) { |
|
339 |
/* on the same ip */ |
|
340 |
if($cpdb[$i][2] == $clientip) { |
|
341 |
captiveportal_logportalauth($cpdb[$i][4],$cpdb[$i][3],$cpdb[$i][2],"CONCURRENT LOGIN - REUSING OLD SESSION"); |
|
342 |
$sessionid = $cpdb[$i][5]; |
|
343 |
break; |
|
344 |
} |
|
345 |
elseif (($attributes['voucher']) && ($username != 'unauthenticated') && ($cpdb[$i][4] == $username)) { |
|
346 |
// user logged in with an active voucher. Check for how long and calculate |
|
347 |
// how much time we can give him (voucher credit - used time) |
|
348 |
$remaining_time = $cpdb[$i][0] + $cpdb[$i][7] - time(); |
|
349 |
if ($remaining_time < 0) // just in case. |
|
350 |
$remaining_time = 0; |
|
351 |
|
|
352 |
/* This user was already logged in so we disconnect the old one */ |
|
353 |
captiveportal_disconnect($cpdb[$i],$radiusservers,13); |
|
354 |
captiveportal_logportalauth($cpdb[$i][4],$cpdb[$i][3],$cpdb[$i][2],"CONCURRENT LOGIN - TERMINATING OLD SESSION"); |
|
355 |
unset($cpdb[$i]); |
|
356 |
break; |
|
357 |
} |
|
358 |
elseif ((isset($config['captiveportal']['noconcurrentlogins'])) && ($username != 'unauthenticated')) { |
|
359 |
/* on the same username */ |
|
360 |
if (strcasecmp($cpdb[$i][4], $username) == 0) { |
|
361 |
/* This user was already logged in so we disconnect the old one */ |
|
362 |
captiveportal_disconnect($cpdb[$i],$radiusservers,13); |
|
363 |
captiveportal_logportalauth($cpdb[$i][4],$cpdb[$i][3],$cpdb[$i][2],"CONCURRENT LOGIN - TERMINATING OLD SESSION"); |
|
364 |
unset($cpdb[$i]); |
|
365 |
break; |
|
366 |
} |
|
367 |
} |
|
368 |
} |
|
369 |
|
|
370 |
if ($attributes['voucher'] && $remaining_time <= 0) |
|
371 |
return 0; // voucher already used and no time left |
|
372 |
|
|
373 |
if (!isset($sessionid)) { |
|
374 |
/* generate unique session ID */ |
|
375 |
$tod = gettimeofday(); |
|
376 |
$sessionid = substr(md5(mt_rand() . $tod['sec'] . $tod['usec'] . $clientip . $clientmac), 0, 16); |
|
377 |
|
|
378 |
/* Add rules for traffic shaping |
|
379 |
* We don't need to add extra rules since traffic will pass due to the following kernel option |
|
380 |
* net.inet.ip.fw.one_pass: 1 |
|
381 |
*/ |
|
382 |
$peruserbw = isset($config['captiveportal']['peruserbw']); |
|
383 |
|
|
384 |
$bw_up = isset($attributes['bw_up']) ? trim($attributes['bw_up']) : $config['captiveportal']['bwdefaultup']; |
|
385 |
$bw_down = isset($attributes['bw_down']) ? trim($attributes['bw_down']) : $config['captiveportal']['bwdefaultdn']; |
|
386 |
|
|
387 |
if ($passthrumac) { |
|
388 |
$mac = array(); |
|
389 |
$mac['mac'] = $clientmac; |
|
390 |
if (isset($config['captiveportal']['passthrumacaddusername'])) |
|
391 |
$mac['username'] = $username; |
|
392 |
$mac['descr'] = "Auto added pass-through MAC for user {$username}"; |
|
393 |
if (!empty($bw_up)) |
|
394 |
$mac['bw_up'] = $bw_up; |
|
395 |
if (!empty($bw_down)) |
|
396 |
$mac['bw_down'] = $bw_down; |
|
397 |
if (!is_array($config['captiveportal']['passthrumac'])) |
|
398 |
$config['captiveportal']['passthrumac'] = array(); |
|
399 |
$config['captiveportal']['passthrumac'][] = $mac; |
|
400 |
$macrules = captiveportal_passthrumac_configure_entry($mac); |
|
401 |
file_put_contents("{$g['tmp_path']}/macentry.rules.tmp", $macrules); |
|
402 |
mwexec("/sbin/ipfw -q {$g['tmp_path']}/macentry.rules.tmp"); |
|
403 |
$writecfg = true; |
|
404 |
} else { |
|
405 |
if ($peruserbw && !empty($bw_up) && is_numeric($bw_up)) { |
|
406 |
$bw_up_pipeno = $ruleno + 20000; |
|
407 |
//$bw_up /= 1000; // Scale to Kbit/s |
|
408 |
mwexec("/sbin/ipfw pipe {$bw_up_pipeno} config bw {$bw_up}Kbit/s queue 100"); |
|
409 |
|
|
410 |
if (!isset($config['captiveportal']['nomacfilter'])) |
|
411 |
mwexec("/sbin/ipfw table 1 add {$clientip} mac {$clientmac} {$bw_up_pipeno}"); |
|
412 |
else |
|
413 |
mwexec("/sbin/ipfw table 1 add {$clientip} {$bw_up_pipeno}"); |
|
414 |
} else { |
|
415 |
if (!isset($config['captiveportal']['nomacfilter'])) |
|
416 |
mwexec("/sbin/ipfw table 1 add {$clientip} mac {$clientmac}"); |
|
417 |
else |
|
418 |
mwexec("/sbin/ipfw table 1 add {$clientip}"); |
|
419 |
} |
|
420 |
if ($peruserbw && !empty($bw_down) && is_numeric($bw_down)) { |
|
421 |
$bw_down_pipeno = $ruleno + 20001; |
|
422 |
//$bw_down /= 1000; // Scale to Kbit/s |
|
423 |
mwexec("/sbin/ipfw pipe {$bw_down_pipeno} config bw {$bw_down}Kbit/s queue 100"); |
|
424 |
|
|
425 |
if (!isset($config['captiveportal']['nomacfilter'])) |
|
426 |
mwexec("/sbin/ipfw table 2 add {$clientip} mac {$clientmac} {$bw_down_pipeno}"); |
|
427 |
else |
|
428 |
mwexec("/sbin/ipfw table 2 add {$clientip} {$bw_down_pipeno}"); |
|
429 |
} else { |
|
430 |
if (!isset($config['captiveportal']['nomacfilter'])) |
|
431 |
mwexec("/sbin/ipfw table 2 add {$clientip} mac {$clientmac}"); |
|
432 |
else |
|
433 |
mwexec("/sbin/ipfw table 2 add {$clientip}"); |
|
434 |
} |
|
435 |
|
|
436 |
if ($attributes['voucher']) |
|
437 |
$attributes['session_timeout'] = $remaining_time; |
|
438 |
|
|
439 |
/* encode password in Base64 just in case it contains commas */ |
|
440 |
$bpassword = base64_encode($password); |
|
441 |
$cpdb[] = array(time(), $ruleno, $clientip, $clientmac, $username, $sessionid, $bpassword, |
|
442 |
$attributes['session_timeout'], $attributes['idle_timeout'], $attributes['session_terminate_time']); |
|
443 |
|
|
444 |
if (isset($config['captiveportal']['radacct_enable']) && !empty($radiusservers)) { |
|
445 |
$acct_val = RADIUS_ACCOUNTING_START($ruleno, |
|
446 |
$username, $sessionid, $radiusservers, $clientip, $clientmac); |
|
447 |
if ($acct_val == 1) |
|
448 |
captiveportal_logportalauth($username,$clientmac,$clientip,$type,"RADIUS ACCOUNTING FAILED"); |
|
449 |
} |
|
450 |
|
|
451 |
/* rewrite information to database */ |
|
452 |
captiveportal_write_db($cpdb); |
|
453 |
} |
|
454 |
} |
|
455 |
|
|
456 |
if ($writecfg == true) |
|
457 |
write_config(); |
|
458 |
|
|
459 |
/* redirect user to desired destination */ |
|
460 |
if (!empty($attributes['url_redirection'])) |
|
461 |
$my_redirurl = $attributes['url_redirection']; |
|
462 |
else if ($config['captiveportal']['redirurl']) |
|
463 |
$my_redirurl = $config['captiveportal']['redirurl']; |
|
464 |
else |
|
465 |
$my_redirurl = $redirurl; |
|
466 |
|
|
467 |
if(isset($config['captiveportal']['logoutwin_enable']) && !$passthrumac) { |
|
468 |
|
|
469 |
if (isset($config['captiveportal']['httpslogin'])) |
|
470 |
$logouturl = "https://{$config['captiveportal']['httpsname']}:8001/"; |
|
471 |
else { |
|
472 |
$ifip = portal_ip_from_client_ip($clientip); |
|
473 |
if (!$ifip) |
|
474 |
$ourhostname = $config['system']['hostname'] . ":8000"; |
|
475 |
else |
|
476 |
$ourhostname = "{$ifip}:8000"; |
|
477 |
$logouturl = "http://{$ourhostname}/"; |
|
478 |
} |
|
479 |
|
|
480 |
if (isset($attributes['reply_message'])) |
|
481 |
$message = $attributes['reply_message']; |
|
482 |
else |
|
483 |
$message = 0; |
|
484 |
|
|
485 |
include("{$g['varetc_path']}/captiveportal-logout.html"); |
|
486 |
|
|
487 |
} else { |
|
488 |
header("Location: " . $my_redirurl); |
|
489 |
} |
|
490 |
|
|
491 |
return $sessionid; |
|
492 |
} |
|
493 |
|
|
494 |
|
|
495 |
|
|
496 |
/* remove a single client by session ID |
|
497 |
* by Dinesh Nair |
|
498 |
*/ |
|
499 |
function disconnect_client($sessionid, $logoutReason = "LOGOUT", $term_cause = 1) { |
|
500 |
global $g, $config; |
|
501 |
|
|
502 |
/* read database */ |
|
503 |
$cpdb = captiveportal_read_db(); |
|
504 |
|
|
505 |
$radiusservers = captiveportal_get_radius_servers(); |
|
506 |
|
|
507 |
/* find entry */ |
|
508 |
$dbcount = count($cpdb); |
|
509 |
for ($i = 0; $i < $dbcount; $i++) { |
|
510 |
if ($cpdb[$i][5] == $sessionid) { |
|
511 |
captiveportal_disconnect($cpdb[$i],$radiusservers, $term_cause); |
|
512 |
captiveportal_logportalauth($cpdb[$i][4],$cpdb[$i][3],$cpdb[$i][2],$logoutReason); |
|
513 |
unset($cpdb[$i]); |
|
514 |
break; |
|
515 |
} |
|
516 |
} |
|
517 |
|
|
518 |
/* write database */ |
|
519 |
captiveportal_write_db($cpdb); |
|
520 |
} |
|
521 |
|
|
522 |
/* |
|
523 |
* Used for when pass-through credits are enabled. |
|
524 |
* Returns true when there was at least one free login to deduct for the MAC. |
|
525 |
* Expired entries are removed as they are seen. |
|
526 |
* Active entries are updated according to the configuration. |
|
527 |
*/ |
|
528 |
function portal_consume_passthrough_credit($clientmac) { |
|
529 |
global $config; |
|
530 |
|
|
531 |
if (!empty($config['captiveportal']['freelogins_count']) && is_numeric($config['captiveportal']['freelogins_count'])) |
|
532 |
$freeloginscount = $config['captiveportal']['freelogins_count']; |
|
533 |
else |
|
534 |
return false; |
|
535 |
|
|
536 |
if (!empty($config['captiveportal']['freelogins_resettimeout']) && is_numeric($config['captiveportal']['freelogins_resettimeout'])) |
|
537 |
$resettimeout = $config['captiveportal']['freelogins_resettimeout']; |
|
538 |
else |
|
539 |
return false; |
|
540 |
|
|
541 |
if ($freeloginscount < 1 || $resettimeout <= 0 || !clientmac) |
|
542 |
return false; |
|
543 |
|
|
544 |
$updatetimeouts = isset($config['captiveportal']['freelogins_updatetimeouts']); |
|
545 |
|
|
546 |
/* |
|
547 |
* Read database of used MACs. Lines are a comma-separated list |
|
548 |
* of the time, MAC, then the count of pass-through credits remaining. |
|
549 |
*/ |
|
550 |
$usedmacs = captiveportal_read_usedmacs_db(); |
|
551 |
|
|
552 |
$currenttime = time(); |
|
553 |
$found = false; |
|
554 |
foreach ($usedmacs as $key => $usedmac) { |
|
555 |
$usedmac = explode(",", $usedmac); |
|
556 |
|
|
557 |
if ($usedmac[1] == $clientmac) { |
|
558 |
if ($usedmac[0] + ($resettimeout * 3600) > $currenttime) { |
|
559 |
if ($usedmac[2] < 1) { |
|
560 |
if ($updatetimeouts) { |
|
561 |
$usedmac[0] = $currenttime; |
|
562 |
unset($usedmacs[$key]); |
|
563 |
$usedmacs[] = implode(",", $usedmac); |
|
564 |
captiveportal_write_usedmacs_db($usedmacs); |
|
565 |
} |
|
566 |
|
|
567 |
return false; |
|
568 |
} else { |
|
569 |
$usedmac[2] -= 1; |
|
570 |
$usedmacs[$key] = implode(",", $usedmac); |
|
571 |
} |
|
572 |
|
|
573 |
$found = true; |
|
574 |
} else |
|
575 |
unset($usedmacs[$key]); |
|
576 |
|
|
577 |
break; |
|
578 |
} else if ($usedmac[0] + ($resettimeout * 3600) <= $currenttime) |
|
579 |
unset($usedmacs[$key]); |
|
580 |
} |
|
581 |
|
|
582 |
if (!$found) { |
|
583 |
$usedmac = array($currenttime, $clientmac, $freeloginscount - 1); |
|
584 |
$usedmacs[] = implode(",", $usedmac); |
|
585 |
} |
|
586 |
|
|
587 |
captiveportal_write_usedmacs_db($usedmacs); |
|
588 |
return true; |
|
589 |
} |
|
590 |
|
|
591 |
function captiveportal_read_usedmacs_db() { |
|
592 |
global $g; |
|
593 |
|
|
594 |
$cpumaclck = lock('captiveusedmacs'); |
|
595 |
if (file_exists("{$g['vardb_path']}/captiveportal_usedmacs.db")) { |
|
596 |
$usedmacs = file("{$g['vardb_path']}/captiveportal_usedmacs.db", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); |
|
597 |
if (!usedmacs) |
|
598 |
$usedmacs = array(); |
|
599 |
} else |
|
600 |
$usedmacs = array(); |
|
601 |
|
|
602 |
unlock($cpumaclck); |
|
603 |
return $usedmacs; |
|
604 |
} |
|
605 |
|
|
606 |
function captiveportal_write_usedmacs_db($usedmacs) { |
|
607 |
global $g; |
|
608 |
|
|
609 |
$cpumaclck = lock('captiveusedmacs', LOCK_EX); |
|
610 |
@file_put_contents("{$g['vardb_path']}/captiveportal_usedmacs.db", implode("\n", $usedmacs)); |
|
611 |
unlock($cpumaclck); |
|
612 |
} |
|
613 | 207 |
|
614 | 208 |
?> |
Also available in: Unified diff
Move all functions from index.php for captiveportal.inc