Project

General

Profile

« Previous | Next » 

Revision ac631bba

Added by Luiz Gustavo S. Costa over 14 years ago

Move all functions from index.php for captiveportal.inc

View differences:

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