Project

General

Profile

Download (22.9 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
    $Id$
4
    part of m0n0wall (http://m0n0.ch/wall)
5

    
6
    Copyrigth (C) 2009	    Ermal Lu?i
7
    Copyright (C) 2003-2006 Manuel Kasper <mk@neon1.net>.
8
    All rights reserved.
9

    
10
    Redistribution and use in source and binary forms, with or without
11
    modification, are permitted provided that the following conditions are met:
12

    
13
    1. Redistributions of source code must retain the above copyright notice,
14
       this list of conditions and the following disclaimer.
15

    
16
    2. Redistributions in binary form must reproduce the above copyright
17
       notice, this list of conditions and the following disclaimer in the
18
       documentation and/or other materials provided with the distribution.
19

    
20
    THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
21
    INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
22
    AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23
    AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
24
    OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
    POSSIBILITY OF SUCH DAMAGE.
30
*/
31
/*
32
	pfSense_BUILDER_BINARIES:	/sbin/ipfw	
33
	pfSense_MODULE:	captiveportal
34
*/
35

    
36
require_once("auth.inc");
37
require_once("functions.inc");
38
require_once("captiveportal.inc");
39

    
40
$errormsg = "Invalid credentials specified.";
41

    
42
header("Expires: 0");
43
header("Cache-Control: no-store, no-cache, must-revalidate");
44
header("Cache-Control: post-check=0, pre-check=0", false);
45
header("Pragma: no-cache");
46
header("Connection: close");
47

    
48
$orig_host = $_ENV['HTTP_HOST'];
49
$orig_request = $_REQUEST['redirurl'];
50
$clientip = $_SERVER['REMOTE_ADDR'];
51

    
52
if (!$clientip) {
53
	/* not good - bail out */
54
	log_error("Captive portal could not determine client's IP address.");
55
	$error_message = "An error occurred.  Please check the system logs for more information.";
56
	portal_reply_page($redirurl, "error", $errormsg);
57
	exit;
58
}
59

    
60
if (isset($config['captiveportal']['httpslogin']))
61
    $ourhostname = $config['captiveportal']['httpsname'] . ":8001";
62
else {
63
    $ifip = portal_ip_from_client_ip($clientip);
64
    if (!$ifip)
65
    	$ourhostname = $config['system']['hostname'] . ":8000";
66
    else
67
    	$ourhostname = "{$ifip}:8000";
68
}
69

    
70
if ($orig_host != $ourhostname) {
71
    /* the client thinks it's connected to the desired web server, but instead
72
       it's connected to us. Issue a redirect... */
73

    
74
    if (isset($config['captiveportal']['httpslogin']))
75
        header("Location: https://{$ourhostname}/index.php?redirurl=" . urlencode("http://{$orig_host}{$orig_request}"));
76
    else
77
        header("Location: http://{$ourhostname}/index.php?redirurl=" . urlencode("http://{$orig_host}{$orig_request}"));
78

    
79
    exit;
80
}
81
if (preg_match("/redirurl=(.*)/", $orig_request, $matches))
82
    $redirurl = urldecode($matches[1]);
83
if ($_POST['redirurl'])
84
    $redirurl = $_POST['redirurl'];
85
if (!empty($config['captiveportal']['redirurl']))
86
	$redirurl = $config['captiveportal']['redirurl'];
87

    
88
$macfilter = !isset($config['captiveportal']['nomacfilter']);
89
$passthrumac = isset($config['captiveportal']['passthrumacadd']);
90

    
91
/* find MAC address for client */
92
$clientmac = arp_get_mac_by_ip($clientip);
93
if (!$clientmac && ($macfilter || $passthrumac)) {
94
    /* unable to find MAC address - shouldn't happen! - bail out */
95
    captiveportal_logportalauth("unauthenticated","noclientmac",$clientip,"ERROR");
96
    echo "An error occurred.  Please check the system logs for more information.";
97
    log_error("Captive portal could not determine client's MAC address.  Disable MAC address filtering in captive portal if you do not need this functionality.");
98
    exit;
99
}
100

    
101
/* find out if we need RADIUS + RADIUSMAC or not */
102
if (file_exists("{$g['vardb_path']}/captiveportal_radius.db")) {
103
    $radius_enable = TRUE;
104
    if (isset($config['captiveportal']['radmac_enable']))
105
        $radmac_enable = TRUE;
106
}
107

    
108
if ($_POST['logout_id']) {
109
	echo <<<EOD
110
<HTML>
111
<HEAD><TITLE>Disconnecting...</TITLE></HEAD>
112
<BODY BGCOLOR="#435370">
113
<SPAN STYLE="color: #ffffff; font-family: Tahoma, Verdana, Arial, Helvetica, sans-serif; font-size: 11px;">
114
<B>You have been disconnected.</B>
115
</SPAN>
116
<SCRIPT LANGUAGE="JavaScript">
117
<!--
118
setTimeout('window.close();',5000) ;
119
-->
120
</SCRIPT>
121
</BODY>
122
</HTML>
123

    
124
EOD;
125
	disconnect_client($_POST['logout_id']);
126
	exit;
127
} else if ($clientmac && $radmac_enable && portal_mac_radius($clientmac,$clientip)) {
128
    /* radius functions handle everything so we exit here since we're done */
129
    exit;
130

    
131
} else if (portal_consume_passthrough_credit($clientmac)) {
132
    /* allow the client through if it had a pass-through credit for its MAC */
133
    captiveportal_logportalauth("unauthenticated",$clientmac,$clientip,"ACCEPT");
134
    portal_allow($clientip, $clientmac, "unauthenticated");
135

    
136
} else if ($_POST['accept'] && $_POST['auth_voucher']) {
137

    
138
    $voucher = trim($_POST['auth_voucher']);
139
    $timecredit = voucher_auth($voucher);
140
    // $timecredit contains either a credit in minutes or an error message
141
    if ($timecredit > 0) {  // voucher is valid. Remaining minutes returned
142
        // if multiple vouchers given, use the first as username
143
        $a_vouchers = split("[\t\n\r ]+",$voucher);
144
        $voucher = $a_vouchers[0];
145
        $attr = array( 'voucher' => 1,
146
                'session_timeout' => $timecredit*60,
147
                'session_terminate_time' => 0);
148
        if (portal_allow($clientip, $clientmac,$voucher,null,$attr)) {
149

    
150
            // YES: user is good for $timecredit minutes.
151
            captiveportal_logportalauth($voucher,$clientmac,$clientip,"Voucher login good for $timecredit min.");
152
        } else {
153
            portal_reply_page($redirurl, "error", $config['voucher']['msgexpired'] ? $config['voucher']['msgexpired']: $errormsg);
154
        }
155
    } else if (-1 == $timecredit) {  // valid but expired
156
        captiveportal_logportalauth($voucher,$clientmac,$clientip,"FAILURE","voucher expired");
157
        portal_reply_page($redirurl, "error", $config['voucher']['msgexpired'] ? $config['voucher']['msgexpired']: $errormsg);
158
    } else {
159
        captiveportal_logportalauth($voucher,$clientmac,$clientip,"FAILURE");
160
        portal_reply_page($redirurl, "error", $config['voucher']['msgnoaccess'] ? $config['voucher']['msgnoaccess'] : $errormsg);
161
    }
162

    
163
} else if ($_POST['accept'] && $radius_enable) {
164

    
165
    if ($_POST['auth_user'] && $_POST['auth_pass']) {
166
        $auth_list = radius($_POST['auth_user'],$_POST['auth_pass'],$clientip,$clientmac,"USER LOGIN");
167
	$type = "error";
168
	if (!empty($auth_list['url_redirection'])) {
169
		$redirurl = $auth_list['url_redirection'];
170
		$type = "redir";
171
	}
172

    
173
        if ($auth_list['auth_val'] == 1) {
174
            captiveportal_logportalauth($_POST['auth_user'],$clientmac,$clientip,"ERROR",$auth_list['error']);
175
 	    portal_reply_page($redirurl, $type, $auth_list['error'] ? $auth_list['error'] : $errormsg);
176
        }
177
        else if ($auth_list['auth_val'] == 3) {
178
            captiveportal_logportalauth($_POST['auth_user'],$clientmac,$clientip,"FAILURE",$auth_list['reply_message']);
179
            portal_reply_page($redirurl, $type, $auth_list['reply_message'] ? $auth_list['reply_message'] : $errormsg);
180
        }
181
    } else {
182
        captiveportal_logportalauth($_POST['auth_user'],$clientmac,$clientip,"ERROR");
183
        portal_reply_page($redirurl, "error", $errormsg);
184
    }
185

    
186
} else if ($_POST['accept'] && $config['captiveportal']['auth_method'] == "local") {
187

    
188
	//check against local user manager
189
	$loginok = local_backed($_POST['auth_user'], $_POST['auth_pass']);
190
    if ($loginok){
191
        captiveportal_logportalauth($_POST['auth_user'],$clientmac,$clientip,"LOGIN");
192
        portal_allow($clientip, $clientmac,$_POST['auth_user']);
193
    } else {
194
        captiveportal_logportalauth($_POST['auth_user'],$clientmac,$clientip,"FAILURE");
195
        portal_reply_page($redirurl, "error", $errormsg);
196
    }
197
} else if ($_POST['accept'] && $clientip) {
198
    captiveportal_logportalauth("unauthenticated",$clientmac,$clientip,"ACCEPT");
199
    portal_allow($clientip, $clientmac, "unauthenticated");
200
} else {
201
    /* display captive portal page */
202
    portal_reply_page($redirurl, "login",null,$clientmac,$clientip);
203
}
204

    
205
exit;
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

    
614
?>
(1-1/3)