Project

General

Profile

Download (69.8 KB) Statistics
| Branch: | Tag: | Revision:
1 5b237745 Scott Ullrich
<?php
2
/*
3
	captiveportal.inc
4 b260c8e0 Scott Ullrich
	part of pfSense (http://www.pfSense.org)
5 5060dea7 Scott Ullrich
	Copyright (C) 2004-2011 Scott Ullrich <sullrich@gmail.com>
6 fad4d451 Ermal
	Copyright (C) 2009-2012 Ermal Lu?i <eri@pfsense.org>
7 0bd34ed6 Scott Ullrich
	Copyright (C) 2003-2006 Manuel Kasper <mk@neon1.net>.
8 5060dea7 Scott Ullrich
9
	originally part of m0n0wall (http://m0n0.ch/wall)
10 5b237745 Scott Ullrich
	All rights reserved.
11 36254e4a Scott Ullrich
12 5b237745 Scott Ullrich
	Redistribution and use in source and binary forms, with or without
13
	modification, are permitted provided that the following conditions are met:
14 36254e4a Scott Ullrich
15 5b237745 Scott Ullrich
	1. Redistributions of source code must retain the above copyright notice,
16
	   this list of conditions and the following disclaimer.
17 36254e4a Scott Ullrich
18 5b237745 Scott Ullrich
	2. Redistributions in binary form must reproduce the above copyright
19
	   notice, this list of conditions and the following disclaimer in the
20
	   documentation and/or other materials provided with the distribution.
21 36254e4a Scott Ullrich
22 5b237745 Scott Ullrich
	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23
	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
24
	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25
	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
26
	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31
	POSSIBILITY OF SUCH DAMAGE.
32 ca83c6ea Scott Ullrich
33 9699028a Scott Ullrich
	This version of captiveportal.inc has been modified by Rob Parker
34
	<rob.parker@keycom.co.uk> to include changes for per-user bandwidth management
35
	via returned RADIUS attributes. This page has been modified to delete any
36
	added rules which may have been created by other per-user code (index.php, etc).
37
	These changes are (c) 2004 Keycom PLC.
38 523855b0 Scott Ullrich
	
39 3a4b0147 Ermal
	pfSense_BUILDER_BINARIES:	/sbin/ipfw	/sbin/sysctl
40 5060dea7 Scott Ullrich
	pfSense_BUILDER_BINARIES:	/usr/local/sbin/lighttpd	/usr/local/bin/minicron /sbin/pfctl
41
	pfSense_BUILDER_BINARIES:	/bin/hostname	/bin/cp 
42
	pfSense_MODULE: captiveportal
43 9699028a Scott Ullrich
*/
44 36254e4a Scott Ullrich
45 5b237745 Scott Ullrich
/* include all configuration functions */
46 a55cdcc0 Ermal Lu?i
require_once("config.inc");
47
require_once("functions.inc");
48 71fdaecd Ermal
require_once("filter.inc");
49 856e58a6 Scott Ullrich
require_once("radius.inc");
50 156487ed Ermal Lu?i
require_once("voucher.inc");
51 0bd34ed6 Scott Ullrich
52 023aa1f2 Scott Ullrich
function get_default_captive_portal_html() {
53 b4792bf8 Ermal
	global $config, $g, $cpzone;
54 0e296bce Ermal
55
	$htmltext = <<<EOD
56 023aa1f2 Scott Ullrich
<html> 
57 0e296bce Ermal
<body> 
58
<form method="post" action="\$PORTAL_ACTION\$"> 
59
	<input name="redirurl" type="hidden" value="\$PORTAL_REDIRURL\$">
60
	<input name="zone" type="hidden" value="\$PORTAL_ZONE\$">
61
	<center>
62
	<table cellpadding="6" cellspacing="0" width="550" height="380" style="border:1px solid #000000">
63
	<tr height="10" bgcolor="#990000">
64
		<td style="border-bottom:1px solid #000000">
65
			<font color='white'>
66
			<b>
67
				{$g['product_name']} captive portal
68
			</b>
69
			</font>
70
		</td>
71
	</tr>
72
	<tr>
73
		<td>
74
			<div id="mainlevel">
75 023aa1f2 Scott Ullrich
			<center>
76 0e296bce Ermal
			<table width="100%" border="0" cellpadding="5" cellspacing="0">
77
			<tr>
78
				<td>
79
					<center>
80
					<div id="mainarea">
81
					<center>
82
					<table width="100%" border="0" cellpadding="5" cellspacing="5">
83 023aa1f2 Scott Ullrich
					<tr>
84
						<td>
85 0e296bce Ermal
							<div id="maindivarea">
86
							<center>
87
								<div id='statusbox'>
88
									<font color='red' face='arial' size='+1'>
89
									<b>
90
										\$PORTAL_MESSAGE\$
91
									</b>
92
									</font>
93
								</div>
94
								<br/>
95
								<div id='loginbox'>
96
								<table>
97 87e7fdea bcyrill
									<tr><td colspan="2"><center>Welcome to the {$g['product_name']} Captive Portal!</td></tr>
98
									<tr><td>&nbsp;</td></tr>
99
									<tr><td align="right">Username:</td><td><input name="auth_user" type="text" style="border: 1px dashed;"></td></tr>
100
									<tr><td align="right">Password:</td><td><input name="auth_pass" type="password" style="border: 1px dashed;"></td></tr>
101
									<tr><td>&nbsp;</td></tr>
102 0e296bce Ermal
103
EOD;
104
105
	if(isset($config['voucher'][$cpzone]['enable'])) {
106
	$htmltext .= <<<EOD
107 87e7fdea bcyrill
									<tr>
108
										<td align="right">Enter Voucher Code: </td>
109
										<td><input name="auth_voucher" type="text" style="border:1px dashed;" size="22"></td>
110
									</tr>
111 36254e4a Scott Ullrich
112 023aa1f2 Scott Ullrich
EOD;
113 c2056357 Scott Ullrich
	}
114 0bd34ed6 Scott Ullrich
115 0e296bce Ermal
	$htmltext .= <<<EOD
116 87e7fdea bcyrill
									<tr>
117
										<td colspan="2"><center><input name="accept" type="submit" value="Continue"></center></td>
118
									</tr>
119 0e296bce Ermal
								</table>
120
								</div>
121
							</center>
122 b260c8e0 Scott Ullrich
							</div>
123
						</td>
124
					</tr>
125 0e296bce Ermal
					</table>
126
					</center>
127
					</div>
128
					</center>
129
				</td>
130
			</tr>
131
			</table>
132 b260c8e0 Scott Ullrich
			</center>
133 0e296bce Ermal
			</div>
134
		</td>
135
	</tr>
136
	</table>
137
	</center>
138
</form>
139
</body> 
140 5b237745 Scott Ullrich
</html>
141
142 023aa1f2 Scott Ullrich
EOD;
143 0bd34ed6 Scott Ullrich
144 023aa1f2 Scott Ullrich
	return $htmltext;
145
}
146 0bd34ed6 Scott Ullrich
147 3a4b0147 Ermal
function captiveportal_load_modules() {
148 87e7fdea bcyrill
	global $config;
149 3a4b0147 Ermal
150
	mute_kernel_msgs();
151 87e7fdea bcyrill
	if (!is_module_loaded("ipfw.ko")) {
152
		mwexec("/sbin/kldload ipfw");
153
		/* make sure ipfw is not on pfil hooks */
154
		mwexec("/sbin/sysctl net.inet.ip.pfil.inbound=\"pf\" net.inet6.ip6.pfil.inbound=\"pf\"" .
155
		       " net.inet.ip.pfil.outbound=\"pf\" net.inet6.ip6.pfil.outbound=\"pf\"");
156 aea56408 Ermal
		/* Activate layer2 filtering */
157
		mwexec("/sbin/sysctl net.link.ether.ipfw=1 net.inet.ip.fw.one_pass=1");
158 87e7fdea bcyrill
	}
159 c06bdb94 Ermal
160 3a4b0147 Ermal
	/* Always load dummynet now that even allowed ip and mac passthrough use it. */
161
	if (!is_module_loaded("dummynet.ko")) {
162
		mwexec("/sbin/kldload dummynet");
163
		mwexec("/sbin/sysctl net.inet.ip.dummynet.io_fast=1 net.inet.ip.dummynet.hash_size=256");
164
	}
165
	unmute_kernel_msgs();
166
167 87e7fdea bcyrill
	/* XXX: This are not used in pfSense, if needed can be tuned 
168
	if($config['system']['maximumstates'] <> "" && is_numeric($config['system']['maximumstates'])) {
169
			mwexec("sysctl net.inet.ip.fw.dyn_max={$config['system']['maximumstates']}");
170
	} else {
171
			mwexec("sysctl net.inet.ip.fw.dyn_max=10000");
172
	}
173 3a4b0147 Ermal
	*/
174
}
175
176 023aa1f2 Scott Ullrich
function captiveportal_configure() {
177 b4792bf8 Ermal
	global $config, $cpzone;
178 023aa1f2 Scott Ullrich
179 b4792bf8 Ermal
	if (is_array($config['captiveportal'])) {
180
		foreach ($config['captiveportal'] as $cpkey => $cp) {
181
			$cpzone = $cpkey;
182
			captiveportal_configure_zone($cp);
183
		}
184
	} else
185
		mwexec("/sbin/sysctl net.link.ether.ipfw=0");
186
}
187
188
function captiveportal_configure_zone($cpcfg) {
189
	global $config, $g, $cpzone;
190
191
	$captiveportallck = lock("captiveportal{$cpzone}", LOCK_EX);
192 023aa1f2 Scott Ullrich
	
193 b4792bf8 Ermal
	if (isset($cpcfg['enable'])) {
194 023aa1f2 Scott Ullrich
195 37e67d04 Ermal
		if ($g['booting']) {
196 b4792bf8 Ermal
			echo "Starting captive portal({$cpcfg['zone']})... ";
197 023aa1f2 Scott Ullrich
198 37e67d04 Ermal
			/* remove old information */
199 26ee5aaf Ermal
			unlink_if_exists("{$g['vardb_path']}/captiveportal{$cpzone}.db");
200 37e67d04 Ermal
		} else
201
			captiveportal_syslog("Reconfiguring captive portal({$cpcfg['zone']}).");
202 023aa1f2 Scott Ullrich
203 37e67d04 Ermal
		/* init ipfw rules */
204
		captiveportal_init_rules(true);
205 023aa1f2 Scott Ullrich
206
		/* kill any running minicron */
207 b4792bf8 Ermal
		killbypid("{$g['varrun_path']}/cp_prunedb_{$cpzone}.pid");
208
209 023aa1f2 Scott Ullrich
		/* initialize minicron interval value */
210 b4792bf8 Ermal
		$croninterval = $cpcfg['croninterval'] ? $cpcfg['croninterval'] : 60;
211 023aa1f2 Scott Ullrich
212
		/* double check if the $croninterval is numeric and at least 10 seconds. If not we set it to 60 to avoid problems */
213 eb7aa263 Ermal
		if ((!is_numeric($croninterval)) || ($croninterval < 10))
214
			$croninterval = 60;
215 023aa1f2 Scott Ullrich
216
		/* write portal page */
217 6cf64278 Ermal
		if (is_array($cpcfg['page']) && $cpcfg['page']['htmltext'])
218 b4792bf8 Ermal
			$htmltext = base64_decode($cpcfg['page']['htmltext']);
219 023aa1f2 Scott Ullrich
		else {
220
			/* example/template page */
221
			$htmltext = get_default_captive_portal_html();
222 5b237745 Scott Ullrich
		}
223
224 b4792bf8 Ermal
		$fd = @fopen("{$g['varetc_path']}/captiveportal_{$cpzone}.html", "w");
225 5b237745 Scott Ullrich
		if ($fd) {
226 7a7e94a7 Scott Ullrich
			// Special case handling.  Convert so that we can pass this page
227
			// through the PHP interpreter later without clobbering the vars.
228 b4792bf8 Ermal
			$htmltext = str_replace("\$PORTAL_ZONE\$", "#PORTAL_ZONE#", $htmltext);
229 7a7e94a7 Scott Ullrich
			$htmltext = str_replace("\$PORTAL_REDIRURL\$", "#PORTAL_REDIRURL#", $htmltext);
230
			$htmltext = str_replace("\$PORTAL_MESSAGE\$", "#PORTAL_MESSAGE#", $htmltext);
231
			$htmltext = str_replace("\$CLIENT_MAC\$", "#CLIENT_MAC#", $htmltext);
232
			$htmltext = str_replace("\$CLIENT_IP\$", "#CLIENT_IP#", $htmltext);
233
			$htmltext = str_replace("\$ORIGINAL_PORTAL_IP\$", "#ORIGINAL_PORTAL_IP#", $htmltext);
234
			$htmltext = str_replace("\$PORTAL_ACTION\$", "#PORTAL_ACTION#", $htmltext);
235 b4792bf8 Ermal
			if($cpcfg['preauthurl']) {
236
				$htmltext = str_replace("\$PORTAL_REDIRURL\$", "{$cpcfg['preauthurl']}", $htmltext);
237
				$htmltext = str_replace("#PORTAL_REDIRURL#", "{$cpcfg['preauthurl']}", $htmltext);
238 c4e228f3 Scott Ullrich
			}
239 5b237745 Scott Ullrich
			fwrite($fd, $htmltext);
240 36254e4a Scott Ullrich
			fclose($fd);
241 5b237745 Scott Ullrich
		}
242 2e62a7c4 Ermal
		unset($htmltext);
243 36254e4a Scott Ullrich
244 5b237745 Scott Ullrich
		/* write error page */
245 c535b28c Ermal
		if (is_array($cpcfg['page']) && $cpcfg['page']['errtext'])
246 b4792bf8 Ermal
			$errtext = base64_decode($cpcfg['page']['errtext']);
247 5b237745 Scott Ullrich
		else {
248 a34b8b3b Ermal
			/* example page  */
249
			$errtext = get_default_captive_portal_html();
250 5b237745 Scott Ullrich
		}
251
252 b4792bf8 Ermal
		$fd = @fopen("{$g['varetc_path']}/captiveportal-{$cpzone}-error.html", "w");
253 5b237745 Scott Ullrich
		if ($fd) {
254 7a7e94a7 Scott Ullrich
			// Special case handling.  Convert so that we can pass this page
255
			// through the PHP interpreter later without clobbering the vars.
256 b4792bf8 Ermal
			$errtext = str_replace("\$PORTAL_ZONE\$", "#PORTAL_ZONE#", $errtext);
257 7a7e94a7 Scott Ullrich
			$errtext = str_replace("\$PORTAL_REDIRURL\$", "#PORTAL_REDIRURL#", $errtext);
258
			$errtext = str_replace("\$PORTAL_MESSAGE\$", "#PORTAL_MESSAGE#", $errtext);
259
			$errtext = str_replace("\$CLIENT_MAC\$", "#CLIENT_MAC#", $errtext);
260
			$errtext = str_replace("\$CLIENT_IP\$", "#CLIENT_IP#", $errtext);
261
			$errtext = str_replace("\$ORIGINAL_PORTAL_IP\$", "#ORIGINAL_PORTAL_IP#", $errtext);
262
			$errtext = str_replace("\$PORTAL_ACTION\$", "#PORTAL_ACTION#", $errtext);
263 b4792bf8 Ermal
			if($cpcfg['preauthurl']) {
264
				$errtext = str_replace("\$PORTAL_REDIRURL\$", "{$cpcfg['preauthurl']}", $errtext);
265
				$errtext = str_replace("#PORTAL_REDIRURL#", "{$cpcfg['preauthurl']}", $errtext);
266 c4e228f3 Scott Ullrich
			}
267 5b237745 Scott Ullrich
			fwrite($fd, $errtext);
268 36254e4a Scott Ullrich
			fclose($fd);
269 5b237745 Scott Ullrich
		}
270 2e62a7c4 Ermal
		unset($errtext);
271 36254e4a Scott Ullrich
272 b4792bf8 Ermal
		/* write logout page */
273 6cf64278 Ermal
		if (is_array($cpcfg['page']) && $cpcfg['page']['logouttext'])
274 b4792bf8 Ermal
			$logouttext = base64_decode($cpcfg['page']['logouttext']);
275 5b87b24e Ermal
		else {
276
			/* example page */
277
			$logouttext = <<<EOD
278
<HTML>
279
<HEAD><TITLE>Redirecting...</TITLE></HEAD>
280
<BODY>
281
<SPAN STYLE="font-family: Tahoma, Verdana, Arial, Helvetica, sans-serif; font-size: 11px;">
282 6991e1a6 Erik Fonnesbeck
<B>Redirecting to <A HREF="<?=\$my_redirurl;?>"><?=\$my_redirurl;?></A>...</B>
283 5b87b24e Ermal
</SPAN>
284
<SCRIPT LANGUAGE="JavaScript">
285
<!--
286
LogoutWin = window.open('', 'Logout', 'toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=0,width=256,height=64');
287
if (LogoutWin) {
288 5060dea7 Scott Ullrich
	LogoutWin.document.write('<HTML>');
289
	LogoutWin.document.write('<HEAD><TITLE>Logout</TITLE></HEAD>') ;
290
	LogoutWin.document.write('<BODY BGCOLOR="#435370">');
291
	LogoutWin.document.write('<DIV ALIGN="center" STYLE="color: #ffffff; font-family: Tahoma, Verdana, Arial, Helvetica, sans-serif; font-size: 11px;">') ;
292
	LogoutWin.document.write('<B>Click the button below to disconnect</B><P>');
293
	LogoutWin.document.write('<FORM METHOD="POST" ACTION="<?=\$logouturl;?>">');
294
	LogoutWin.document.write('<INPUT NAME="logout_id" TYPE="hidden" VALUE="<?=\$sessionid;?>">');
295 b4792bf8 Ermal
	LogoutWin.document.write('<INPUT NAME="zone" TYPE="hidden" VALUE="<?=\$cpzone;?>">');
296 5060dea7 Scott Ullrich
	LogoutWin.document.write('<INPUT NAME="logout" TYPE="submit" VALUE="Logout">');
297
	LogoutWin.document.write('</FORM>');
298
	LogoutWin.document.write('</DIV></BODY>');
299
	LogoutWin.document.write('</HTML>');
300
	LogoutWin.document.close();
301 5b87b24e Ermal
}
302
303 6991e1a6 Erik Fonnesbeck
document.location.href="<?=\$my_redirurl;?>";
304 5b87b24e Ermal
-->
305
</SCRIPT>
306
</BODY>
307
</HTML>
308
309
EOD;
310
		}
311
312 b4792bf8 Ermal
		$fd = @fopen("{$g['varetc_path']}/captiveportal-{$cpzone}-logout.html", "w");
313 5b87b24e Ermal
		if ($fd) {
314
			fwrite($fd, $logouttext);
315
			fclose($fd);
316
		}
317 2e62a7c4 Ermal
		unset($logouttext);
318
319 0bd34ed6 Scott Ullrich
		/* write elements */
320
		captiveportal_write_elements();
321 5b237745 Scott Ullrich
322 37e67d04 Ermal
		/* kill any running mini_httpd */
323
		killbypid("{$g['varrun_path']}/lighty-{$cpzone}-CaptivePortal.pid");
324
		killbypid("{$g['varrun_path']}/lighty-{$cpzone}-CaptivePortal-SSL.pid");
325
326 769e254e Ermal
		/* start up the webserving daemon */
327 e3cf528e bcyrill
		captiveportal_init_webgui_zone($cpcfg);
328 36254e4a Scott Ullrich
329 aa69dbd2 Scott Ullrich
		/* Kill any existing prunecaptiveportal processes */
330 8b34498c Ermal
		if (file_exists("{$g['varrun_path']}/cp_prunedb_{$cpzone}.pid"))
331 b4792bf8 Ermal
			killbypid("{$g['varrun_path']}/cp_prunedb_{$cpzone}.pid");
332 aa69dbd2 Scott Ullrich
333 0bd34ed6 Scott Ullrich
		/* start pruning process (interval defaults to 60 seconds) */
334 b4792bf8 Ermal
		mwexec("/usr/local/bin/minicron $croninterval {$g['varrun_path']}/cp_prunedb_{$cpzone}.pid " .
335
			"/etc/rc.prunecaptiveportal {$cpzone}");
336 36254e4a Scott Ullrich
337 d99f7864 Scott Ullrich
		/* generate radius server database */
338 37e67d04 Ermal
		unlink_if_exists("{$g['vardb_path']}/captiveportal_radius_{$cpzone}.db");
339 d31bc32a Ermal
		captiveportal_init_radius_servers();
340 36254e4a Scott Ullrich
341 e35ab948 Michael Newton
		if ($g['booting']) {
342
			/* send Accounting-On to server */
343
			captiveportal_send_server_accounting();
344 b4792bf8 Ermal
			echo "done\n";
345 e35ab948 Michael Newton
		}
346 36254e4a Scott Ullrich
347 5b237745 Scott Ullrich
	} else {
348 b4792bf8 Ermal
		killbypid("{$g['varrun_path']}/lighty-{$cpzone}-CaptivePortal.pid");
349
		killbypid("{$g['varrun_path']}/lighty-{$cpzone}-CaptivePortal-SSL.pid");
350
		killbypid("{$g['varrun_path']}/cp_prunedb_{$cpzone}.pid");
351
		@unlink("{$g['varetc_path']}/captiveportal_{$cpzone}.html");
352
		@unlink("{$g['varetc_path']}/captiveportal-{$cpzone}-error.html");
353
		@unlink("{$g['varetc_path']}/captiveportal-{$cpzone}-logout.html");
354 f8cb8685 Ermal
355
		captiveportal_radius_stop_all();
356
357 62f20eab Michael Newton
		/* send Accounting-Off to server */
358
		if (!$g['booting']) {
359
			captiveportal_send_server_accounting(true);
360
		}
361
362 8b34498c Ermal
		/* remove old information */
363 26ee5aaf Ermal
		unlink_if_exists("{$g['vardb_path']}/captiveportal{$cpzone}.db");
364 8b34498c Ermal
		unlink_if_exists("{$g['vardb_path']}/captiveportal_radius_{$cpzone}.db");
365 12ee8fe4 Scott Ullrich
366 b4792bf8 Ermal
		mwexec("/usr/local/sbin/ipfw_context -d {$cpzone}", true);
367
368
		if (empty($config['captiveportal']))
369
			mwexec("/sbin/sysctl net.link.ether.ipfw=0");
370 c06bdb94 Ermal
		else {
371
			/* Deactivate ipfw(4) if not needed */
372
			$cpactive = false;
373
			foreach ($config['captiveportal'] as $cpkey => $cp) {
374
				if (isset($cp['enable'])) {
375
					$cpactive = true;
376
					break;
377
				}
378
			}
379
			if ($cpactive === false)
380
				mwexec("/sbin/sysctl net.link.ether.ipfw=0");
381
				
382
		}
383 3db19cf1 Scott Ullrich
	}
384 36254e4a Scott Ullrich
385 f8b11310 Ermal Lu?i
	unlock($captiveportallck);
386 c3214b80 Scott Ullrich
	
387 5b237745 Scott Ullrich
	return 0;
388
}
389
390 769e254e Ermal
function captiveportal_init_webgui() {
391 b4792bf8 Ermal
	global $config, $cpzone;
392 769e254e Ermal
393 b4792bf8 Ermal
	if (is_array($config['captiveportal'])) {
394 e3cf528e bcyrill
		foreach ($config['captiveportal'] as $cpkey => $cp) {
395 b4792bf8 Ermal
			$cpzone = $cpkey;
396 e3cf528e bcyrill
			captiveportal_init_webgui_zone($cp);
397 b4792bf8 Ermal
		}
398
	}
399
}
400 769e254e Ermal
401 e3cf528e bcyrill
function captiveportal_init_webgui_zonename($zone) {
402
	global $config, $cpzone;
403
	
404
	if (isset($config['captiveportal'][$zone])) {
405
		$cpzone = $zone;
406
		captiveportal_init_webgui_zone($config['captiveportal'][$zone]);
407
	}
408
}
409
410
function captiveportal_init_webgui_zone($cpcfg) {
411 b4792bf8 Ermal
	global $g, $config, $cpzone;
412
413 e3cf528e bcyrill
	if (!isset($cpcfg['enable']))
414 b4792bf8 Ermal
		return;
415
416
	if (isset($cpcfg['httpslogin'])) {
417 36f6ed35 bcyrill
		$cert = lookup_cert($cpcfg['certref']);
418 adca02c4 bcyrill
		$crt = base64_decode($cert['crt']);
419
		$key = base64_decode($cert['prv']);
420
		$ca = ca_chain($cert);
421 87e7fdea bcyrill
422 769e254e Ermal
		/* generate lighttpd configuration */
423 470d24a3 Darren Embry
		$listenporthttps = $cpcfg['listenporthttps'] ? $cpcfg['listenporthttps'] : ($cpcfg['zoneid'] + 1);
424 b4792bf8 Ermal
		system_generate_lighty_config("{$g['varetc_path']}/lighty-{$cpzone}-CaptivePortal-SSL.conf",
425 adca02c4 bcyrill
			$crt, $key, $ca, "lighty-{$cpzone}-CaptivePortal-SSL.pid", $listenporthttps, "/usr/local/captiveportal",
426 a96f2d3d Ermal
			"cert-{$cpzone}-portal.pem", "ca-{$cpzone}-portal.pem", $cpzone);
427 769e254e Ermal
	}
428
429
	/* generate lighttpd configuration */
430 470d24a3 Darren Embry
	$listenporthttp = $cpcfg['listenporthttp'] ? $cpcfg['listenporthttp'] : $cpcfg['zoneid'];
431 b4792bf8 Ermal
	system_generate_lighty_config("{$g['varetc_path']}/lighty-{$cpzone}-CaptivePortal.conf",
432 470d24a3 Darren Embry
		"", "", "", "lighty-{$cpzone}-CaptivePortal.pid", $listenporthttp, "/usr/local/captiveportal",
433 a96f2d3d Ermal
		"", "", $cpzone);
434 769e254e Ermal
435 fe2eb995 Ermal
	@unlink("{$g['varrun']}/lighty-{$cpzone}-CaptivePortal.pid");
436 769e254e Ermal
	/* attempt to start lighttpd */
437 b4792bf8 Ermal
	$res = mwexec("/usr/local/sbin/lighttpd -f {$g['varetc_path']}/lighty-{$cpzone}-CaptivePortal.conf");
438 769e254e Ermal
439
	/* fire up https instance */
440 fe2eb995 Ermal
	if (isset($cpcfg['httpslogin'])) {
441
		@unlink("{$g['varrun']}/lighty-{$cpzone}-CaptivePortal-SSL.pid");
442 b4792bf8 Ermal
		$res = mwexec("/usr/local/sbin/lighttpd -f {$g['varetc_path']}/lighty-{$cpzone}-CaptivePortal-SSL.conf");
443 fe2eb995 Ermal
	}
444 769e254e Ermal
}
445
446 847e5e82 Scott Ullrich
/* reinit will disconnect all users, be careful! */
447 1d9e9cca Ermal
function captiveportal_init_rules($reinit = false) {
448 b4792bf8 Ermal
	global $config, $g, $cpzone;
449 36254e4a Scott Ullrich
450 b4792bf8 Ermal
	if (!isset($config['captiveportal'][$cpzone]['enable']))
451 769e254e Ermal
		return;
452
453 3a4b0147 Ermal
	captiveportal_load_modules();
454 c06bdb94 Ermal
	mwexec("/usr/local/sbin/ipfw_context -a {$cpzone}", true);
455 3a4b0147 Ermal
456 769e254e Ermal
	$cpips = array();
457
	$ifaces = get_configured_interface_list();
458 b4792bf8 Ermal
	$cpinterfaces = explode(",", $config['captiveportal'][$cpzone]['interface']);
459 769e254e Ermal
	$firsttime = 0;
460
	foreach ($cpinterfaces as $cpifgrp) {
461
		if (!isset($ifaces[$cpifgrp]))
462
			continue;
463
		$tmpif = get_real_interface($cpifgrp);
464
		if (!empty($tmpif)) {
465
			$cpipm = get_interface_ip($cpifgrp);
466
			if (is_ipaddr($cpipm)) {
467
				$carpif = link_ip_to_carp_interface($cpipm);
468
				if (!empty($carpif)) {
469
					$carpsif = explode(" ", $carpif);
470
					foreach ($carpsif as $cpcarp) {
471 b4792bf8 Ermal
						mwexec("/usr/local/sbin/ipfw_context -a {$cpzone} -n {$cpcarp}", true);
472 769e254e Ermal
						$carpip = find_interface_ip($cpcarp);
473
						if (is_ipaddr($carpip))
474
							$cpips[] = $carpip;
475
					}
476
				}
477
				$cpips[] = $cpipm;
478
			}
479 8b34498c Ermal
			mwexec("/usr/local/sbin/ipfw_context -a {$cpzone} -n {$tmpif}", true);
480 769e254e Ermal
		}
481
	}
482
	if (count($cpips) > 0) {
483
		$cpactive = true;
484 8b34498c Ermal
	} else
485 769e254e Ermal
		return false;
486
487 eade409a Ermal
	if ($reinit == false)
488 b4792bf8 Ermal
		$captiveportallck = lock("captiveportal{$cpzone}");
489 eade409a Ermal
490 ec509679 Ermal
	$cprules =	"add 65291 allow pfsync from any to any\n";
491
	$cprules .= "add 65292 allow carp from any to any\n";
492 181a843c Scott Ullrich
493 3db19cf1 Scott Ullrich
	$cprules .= <<<EOD
494
# layer 2: pass ARP
495 ec509679 Ermal
add 65301 pass layer2 mac-type arp,rarp
496 b9d1d810 Scott Ullrich
# pfsense requires for WPA
497 ec509679 Ermal
add 65302 pass layer2 mac-type 0x888e,0x88c7
498 ee79fcda Ermal
# PPP Over Ethernet Session Stage/Discovery Stage
499 ec509679 Ermal
add 65303 pass layer2 mac-type 0x8863,0x8864
500 684c787e Scott Ullrich
501 ee79fcda Ermal
# layer 2: block anything else non-IP(v4/v6)
502 ec509679 Ermal
add 65307 deny layer2 not mac-type ip,ipv6
503 3db19cf1 Scott Ullrich
504
EOD;
505
506 b01792a0 Ermal
	$rulenum = 65310;
507 fb516dda Chris Buechler
	$ipcount = 0;
508 0ba17c67 Ermal
	$ips = "";
509 fb516dda Chris Buechler
	foreach ($cpips as $cpip) {
510
		if($ipcount == 0) {
511
			$ips = "{$cpip} ";
512
		} else {
513
			$ips .= "or {$cpip} ";
514
		}
515
		$ipcount++;
516
	}
517 0ba17c67 Ermal
	$ips = "{ 255.255.255.255 or {$ips} }";
518 ec509679 Ermal
	$cprules .= "add {$rulenum} pass ip from any to {$ips} in\n";
519 2f27dffd Ermal
	$rulenum++;
520 ec509679 Ermal
	$cprules .= "add {$rulenum} pass ip from {$ips} to any out\n";
521 2f27dffd Ermal
	$rulenum++;
522 ec509679 Ermal
	$cprules .= "add {$rulenum} pass icmp from {$ips} to any out icmptype 0\n";
523 2f27dffd Ermal
	$rulenum++;
524 ec509679 Ermal
	$cprules .= "add {$rulenum} pass icmp from any to {$ips} in icmptype 8 \n";
525 2f27dffd Ermal
	$rulenum++;
526 b01792a0 Ermal
	/* Allowed ips */
527 aea56408 Ermal
	$cprules .= "add {$rulenum} pipe tablearg ip from table(3) to any in\n";
528 b01792a0 Ermal
	$rulenum++;
529 aea56408 Ermal
	$cprules .= "add {$rulenum} pipe tablearg ip from any to table(4) out\n";
530 b01792a0 Ermal
	$rulenum++;
531
532
	/* Authenticated users rules. */
533 ec509679 Ermal
	$cprules .= "add {$rulenum} pipe tablearg ip from table(1) to any in\n";
534 10b9dfcf Ermal
	$rulenum++;
535 ec509679 Ermal
	$cprules .= "add {$rulenum} pipe tablearg ip from any to table(2) out\n";
536 10b9dfcf Ermal
	$rulenum++;
537 bb58ed63 Ermal
538 470d24a3 Darren Embry
	$listenporthttp =
539
		$config['captiveportal'][$cpzone]['listenporthttp'] ?
540
		$config['captiveportal'][$cpzone]['listenporthttp'] :
541
		$config['captiveportal'][$cpzone]['zoneid'];
542 06a45374 Ermal
543 d61cbd50 bcyrill
	if (isset($config['captiveportal'][$cpzone]['httpslogin'])) {
544 06a45374 Ermal
		$listenporthttps = $listenporthttp + 1;
545 ec509679 Ermal
		$cprules .= "add 65531 fwd 127.0.0.1,{$listenporthttps} tcp from any to any dst-port 443 in\n";
546 06a45374 Ermal
	}
547 f9f71ad3 Ermal Lu?i
	
548 b4792bf8 Ermal
	$cprules .= <<<EOD
549 5480497a Scott Ullrich
550 d44bccc7 Scott Ullrich
# redirect non-authenticated clients to captive portal
551 ec509679 Ermal
add 65532 fwd 127.0.0.1,{$listenporthttp} tcp from any to any dst-port 80 in 
552 3db19cf1 Scott Ullrich
# let the responses from the captive portal web server back out
553 ec509679 Ermal
add 65533 pass tcp from any to any out
554 3db19cf1 Scott Ullrich
# block everything else
555 ec509679 Ermal
add 65534 deny all from any to any
556 3db19cf1 Scott Ullrich
557
EOD;
558
559 769e254e Ermal
	/* generate passthru mac database */
560
	$cprules .= captiveportal_passthrumac_configure(true);
561
	$cprules .= "\n";
562 55c18b30 Scott Ullrich
563 769e254e Ermal
	/* allowed ipfw rules to make allowed ip work */
564
	$cprules .= captiveportal_allowedip_configure();
565
566 55c18b30 Scott Ullrich
	/* allowed ipfw rules to make allowed hostnames work */
567
	$cprules .= captiveportal_allowedhostname_configure();
568
	
569 769e254e Ermal
	/* load rules */
570 37e67d04 Ermal
	$cprules = "flush\n{$cprules}";
571 b4792bf8 Ermal
	file_put_contents("{$g['tmp_path']}/ipfw_{$cpzone}.cp.rules", $cprules);
572 287f7e26 Ermal
	mwexec("/sbin/ipfw -x {$cpzone} -q {$g['tmp_path']}/ipfw_{$cpzone}.cp.rules", true);
573 b4792bf8 Ermal
	//@unlink("{$g['tmp_path']}/ipfw_{$cpzone}.cp.rules");
574 c06bdb94 Ermal
	unset($cprules, $tmprules);
575 eade409a Ermal
576
	if ($reinit == false)
577
		unlock($captiveportallck);
578 3db19cf1 Scott Ullrich
}
579
580 f1f58a6f Ermal
/* 
581
 * Remove clients that have been around for longer than the specified amount of time
582 eb7aa263 Ermal
 * db file structure:
583 338c0941 Ermal
 * timestamp,ipfw_rule_no,clientip,clientmac,username,sessionid,password,session_timeout,idle_timeout,session_terminate_time,interim_interval
584 eb7aa263 Ermal
 * (password is in Base64 and only saved when reauthentication is enabled)
585
 */
586 5b237745 Scott Ullrich
function captiveportal_prune_old() {
587 b4792bf8 Ermal
	global $g, $config, $cpzone;
588
589
	if (empty($cpzone))
590
		return;
591 23c4f978 Scott Ullrich
592 f1f58a6f Ermal
	$cpcfg = $config['captiveportal'][$cpzone];
593
	$vcpcfg = $config['voucher'][$cpzone];
594
595 5060dea7 Scott Ullrich
	/* check for expired entries */
596 f1f58a6f Ermal
	$idletimeout = 0;
597
	$timeout = 0;
598
	if (!empty($cpcfg['timeout']) && is_numeric($cpcfg['timeout']))
599
		$timeout = $cpcfg['timeout'] * 60;
600
601
	if (!empty($cpcfg['idletimeout']) && is_numeric($cpcfg['idletimeout']))
602
		$idletimeout = $cpcfg['idletimeout'] * 60;
603
604
	/* Is there any job to do? */
605 87e7fdea bcyrill
	if (!$timeout && !$idletimeout && !isset($cpcfg['reauthenticate']) &&
606 f1f58a6f Ermal
	    !isset($cpcfg['radiussession_timeout']) && !isset($vcpcfg['enable']))
607 5060dea7 Scott Ullrich
		return;
608
609 ebc0e4b6 Ermal
	$radiussrvs = captiveportal_get_radius_servers();
610 006802ab Ermal
611 26ee5aaf Ermal
	/* Read database */
612
	/* NOTE: while this can be simplified in non radius case keep as is for now */
613 5060dea7 Scott Ullrich
	$cpdb = captiveportal_read_db();
614 0bd34ed6 Scott Ullrich
615 f1f58a6f Ermal
	/*
616
	 * To make sure we iterate over ALL accounts on every run the count($cpdb) is moved
617
	 * outside of the loop. Otherwise the loop would evaluate count() on every iteration
618
	 * and since $i would increase and count() would decrement they would meet before we
619
	 * had a chance to iterate over all accounts.
620 5060dea7 Scott Ullrich
	 */
621
	$unsetindexes = array();
622 5ebe85e9 Ermal
	$voucher_needs_sync = false;
623 b09c2d86 Ermal
	/* 
624
	 * Snapshot the time here to use for calculation to speed up the process.
625
	 * If something is missed next run will catch it!
626
	 */
627
	$pruning_time = time();
628
	$stop_time = $pruning_time;
629 3e5c0ab7 Ermal
	foreach ($cpdb as $cpentry) {
630 5060dea7 Scott Ullrich
631
		$timedout = false;
632
		$term_cause = 1;
633 5705c60a Renato Botelho
		if (empty($cpentry[10]))
634
			$cpentry[10] = 'first';
635
		$radiusservers = $radiussrvs[$cpentry[10]];
636 5060dea7 Scott Ullrich
637
		/* hard timeout? */
638
		if ($timeout) {
639 5705c60a Renato Botelho
			if (($pruning_time - $cpentry[0]) >= $timeout) {
640 5060dea7 Scott Ullrich
				$timedout = true;
641 5705c60a Renato Botelho
				$term_cause = 5; // Session-Timeout
642 5060dea7 Scott Ullrich
			}
643 eb7aa263 Ermal
		}
644 23c4f978 Scott Ullrich
645 5060dea7 Scott Ullrich
		/* Session-Terminate-Time */
646 5705c60a Renato Botelho
		if (!$timedout && !empty($cpentry[9])) {
647
			if ($pruning_time >= $cpentry[9]) {
648 5060dea7 Scott Ullrich
				$timedout = true;
649 5705c60a Renato Botelho
				$term_cause = 5; // Session-Timeout
650 5060dea7 Scott Ullrich
			}
651
		}
652
653
		/* check if the radius idle_timeout attribute has been set and if its set change the idletimeout to this value */
654 5705c60a Renato Botelho
		$uidletimeout = (is_numeric($cpentry[8])) ? $cpentry[8] : $idletimeout;
655 5060dea7 Scott Ullrich
		/* if an idle timeout is specified, get last activity timestamp from ipfw */
656 1a1967d6 Ermal
		if (!$timedout && $uidletimeout > 0) {
657 5705c60a Renato Botelho
			$lastact = captiveportal_get_last_activity($cpentry[2]);
658 5060dea7 Scott Ullrich
			/*	If the user has logged on but not sent any traffic they will never be logged out.
659
			 *	We "fix" this by setting lastact to the login timestamp. 
660 f56a73f1 Scott Ullrich
			 */
661 5705c60a Renato Botelho
			$lastact = $lastact ? $lastact : $cpentry[0];
662 b09c2d86 Ermal
			if ($lastact && (($pruning_time - $lastact) >= $uidletimeout)) {
663 5060dea7 Scott Ullrich
				$timedout = true;
664 5705c60a Renato Botelho
				$term_cause = 4; // Idle-Timeout
665 5060dea7 Scott Ullrich
				$stop_time = $lastact; // Entry added to comply with WISPr
666
			}
667 336e3c1c Charlie
		}
668
669 5060dea7 Scott Ullrich
		/* if vouchers are configured, activate session timeouts */
670 5705c60a Renato Botelho
		if (!$timedout && isset($vcpcfg['enable']) && !empty($cpentry[7])) {
671
			if ($pruning_time >= ($cpentry[0] + $cpentry[7])) {
672 5060dea7 Scott Ullrich
				$timedout = true;
673 5705c60a Renato Botelho
				$term_cause = 5; // Session-Timeout
674 5ebe85e9 Ermal
				$voucher_needs_sync = true;
675 5060dea7 Scott Ullrich
			}
676
		}
677
678
		/* if radius session_timeout is enabled and the session_timeout is not null, then check if the user should be logged out */
679 5705c60a Renato Botelho
		if (!$timedout && isset($cpcfg['radiussession_timeout']) && !empty($cpentry[7])) {
680
			if ($pruning_time >= ($cpentry[0] + $cpentry[7])) {
681 5060dea7 Scott Ullrich
				$timedout = true;
682 5705c60a Renato Botelho
				$term_cause = 5; // Session-Timeout
683 5060dea7 Scott Ullrich
			}
684
		}
685
686
		if ($timedout) {
687 3e5c0ab7 Ermal
			captiveportal_disconnect($cpentry, $radiusservers,$term_cause,$stop_time);
688 5705c60a Renato Botelho
			captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], "TIMEOUT");
689
			$unsetindexes[] = $cpentry[5];
690 5060dea7 Scott Ullrich
		}
691
692
		/* do periodic RADIUS reauthentication? */
693
		if (!$timedout && !empty($radiusservers)) {
694 f1f58a6f Ermal
			if (isset($cpcfg['radacct_enable'])) {
695
				if ($cpcfg['reauthenticateacct'] == "stopstart") {
696 5060dea7 Scott Ullrich
					/* stop and restart accounting */
697 5705c60a Renato Botelho
					RADIUS_ACCOUNTING_STOP($cpentry[1], // ruleno
698
						$cpentry[4], // username
699
						$cpentry[5], // sessionid
700
						$cpentry[0], // start time
701 5060dea7 Scott Ullrich
						$radiusservers,
702 5705c60a Renato Botelho
						$cpentry[2], // clientip
703
						$cpentry[3], // clientmac
704
						10); // NAS Request
705 6cbda317 Ermal
					pfSense_ipfw_Tableaction($cpzone, IP_FW_TABLE_ZERO_ENTRY_STATS, 1, $cpentry[2]);
706
					pfSense_ipfw_Tableaction($cpzone, IP_FW_TABLE_ZERO_ENTRY_STATS, 2, $cpentry[2]);
707 5705c60a Renato Botelho
					RADIUS_ACCOUNTING_START($cpentry[1], // ruleno
708
						$cpentry[4], // username
709
						$cpentry[5], // sessionid
710 5060dea7 Scott Ullrich
						$radiusservers,
711 5705c60a Renato Botelho
						$cpentry[2], // clientip
712
						$cpentry[3]); // clientmac
713 f1f58a6f Ermal
				} else if ($cpcfg['reauthenticateacct'] == "interimupdate") {
714 5705c60a Renato Botelho
					$session_time = $pruning_time - $cpentry[0];
715
					if (!empty($cpentry[10]) && $cpentry[10] > 60)
716
						$interval = $cpentry[10];
717 338c0941 Ermal
					else
718
						$interval = 0;
719
					$past_interval_min = ($session_time > $interval);
720
					$within_interval = ($session_time % $interval >= 0 && $session_time % $interval <= 59);
721
					if (($interval > 0 && $past_interval_min && $within_interval) || $interval === 0) {
722 5705c60a Renato Botelho
						RADIUS_ACCOUNTING_STOP($cpentry[1], // ruleno
723
							$cpentry[4], // username
724
							$cpentry[5], // sessionid
725
							$cpentry[0], // start time
726 338c0941 Ermal
							$radiusservers,
727 5705c60a Renato Botelho
							$cpentry[2], // clientip
728
							$cpentry[3], // clientmac
729
							10, // NAS Request
730
							true); // Interim Updates
731 338c0941 Ermal
					}
732 5060dea7 Scott Ullrich
				}
733
			}
734 23c4f978 Scott Ullrich
735 5060dea7 Scott Ullrich
			/* check this user against RADIUS again */
736 f1f58a6f Ermal
			if (isset($cpcfg['reauthenticate'])) {
737 5705c60a Renato Botelho
				$auth_list = RADIUS_AUTHENTICATION($cpentry[4], // username
738
					base64_decode($cpentry[6]), // password
739 5060dea7 Scott Ullrich
					$radiusservers,
740 5705c60a Renato Botelho
					$cpentry[2], // clientip
741
					$cpentry[3], // clientmac
742
					$cpentry[1]); // ruleno
743 5060dea7 Scott Ullrich
				if ($auth_list['auth_val'] == 3) {
744 5705c60a Renato Botelho
					captiveportal_disconnect($cpentry, $radiusservers, 17);
745
					captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], "RADIUS_DISCONNECT", $auth_list['reply_message']);
746
					$unsetindexes[] = $cpentry[5];
747 aec0f2fd Ermal
				} else if ($auth_list['auth_val'] == 2)
748
					captiveportal_reapply_attributes($cpentry, $auth_list);
749 5060dea7 Scott Ullrich
			}
750
		}
751
	}
752 f32eae2d Ermal
	unset($cpdb);
753 23c4f978 Scott Ullrich
754 522f1cc7 Ermal
	captiveportal_prune_old_automac();
755
756 5ebe85e9 Ermal
	if ($voucher_needs_sync == true)
757
		/* Triger a sync of the vouchers on config */
758
		send_event("service sync vouchers");
759
760 5060dea7 Scott Ullrich
	/* write database */
761 e92916d6 Ermal
	if (!empty($unsetindexes))
762 26ee5aaf Ermal
		captiveportal_remove_entries($unsetindexes);
763 5b237745 Scott Ullrich
}
764
765 522f1cc7 Ermal
function captiveportal_prune_old_automac() {
766
	global $g, $config, $cpzone;
767
768
	if (is_array($config['captiveportal'][$cpzone]['passthrumac']) && isset($config['captiveportal'][$cpzone]['passthrumacaddusername'])) {
769
		$tmpvoucherdb = array();
770
		$macrules = "";
771
		$writecfg = false;
772
		foreach ($config['captiveportal'][$cpzone]['passthrumac'] as $eid => $emac) {
773
			if ($emac['logintype'] == "voucher") {
774
				if (isset($tmpvoucherdb[$emac['username']])) {
775
					$temac = $config['captiveportal'][$cpzone]['passthrumac'][$tmpvoucherdb[$emac['username']]];
776
					$ruleno = captiveportal_get_ipfw_passthru_ruleno($temac['mac']);
777 aea56408 Ermal
					$pipeno = captiveportal_get_dn_passthru_ruleno($temac['mac']);
778 522f1cc7 Ermal
					if ($ruleno) {
779 aea56408 Ermal
						captiveportal_free_ipfw_ruleno($ruleno);
780 522f1cc7 Ermal
						$macrules .= "delete {$ruleno}";
781
						++$ruleno;
782
						$macrules .= "delete {$ruleno}";
783
					}
784 aea56408 Ermal
					if ($pipeno) {
785
						captiveportal_free_dn_ruleno($pipeno);
786
						$macrules .= "pipe delete {$pipeno}\n";
787
						++$pipeno;
788
						$macrules .= "pipe delete {$pipeno}\n";
789
					}
790 522f1cc7 Ermal
					$writecfg = true;
791
					captiveportal_logportalauth($temac['username'], $temac['mac'], $temac['ip'], "DUPLICATE {$temac['username']} LOGIN - TERMINATING OLD SESSION");
792
					unset($config['captiveportal'][$cpzone]['passthrumac'][$tmpvoucherdb[$emac['username']]]);
793
				}
794
				$tmpvoucherdb[$emac['username']] = $eid;
795
				if (voucher_auth($emac['username']) <= 0) {
796
					$ruleno = captiveportal_get_ipfw_passthru_ruleno($emac['mac']);
797 aea56408 Ermal
					$pipeno = captiveportal_get_dn_passthru_ruleno($emac['mac']);
798 522f1cc7 Ermal
					if ($ruleno) {
799 aea56408 Ermal
						captiveportal_free_ipfw_ruleno($ruleno);
800 522f1cc7 Ermal
						$macrules .= "delete {$ruleno}";
801
						++$ruleno;
802
						$macrules .= "delete {$ruleno}";
803
					}
804 aea56408 Ermal
					if ($pipeno) {
805
						captiveportal_free_dn_ruleno($pipeno);
806
						$macrules .= "pipe delete {$pipeno}\n";
807
						++$pipeno;
808
						$macrules .= "pipe delete {$pipeno}\n";
809
					}
810 522f1cc7 Ermal
					$writecfg = true;
811
					captiveportal_logportalauth($emac['username'], $emac['mac'], $emac['ip'], "EXPIRED {$emac['username']} LOGIN - TERMINATING SESSION");
812
					unset($config['captiveportal'][$cpzone]['passthrumac'][$eid]);
813
				}
814
			}
815
		}
816
		if (!empty($macrules)) {
817
			@file_put_contents("{$g['tmp_path']}/macentry.prunerules.tmp", $macrules);
818 2e62a7c4 Ermal
			unset($macrules);
819 287f7e26 Ermal
			mwexec("/sbin/ipfw -x {$cpzone} -q {$g['tmp_path']}/macentry.prunerules.tmp");
820 522f1cc7 Ermal
		}
821
		if ($writecfg === true)
822
			write_config("Prune session for auto-added macs");
823
	}
824
}
825
826 3db19cf1 Scott Ullrich
/* remove a single client according to the DB entry */
827 0bd34ed6 Scott Ullrich
function captiveportal_disconnect($dbent, $radiusservers,$term_cause = 1,$stop_time = null) {
828 b4792bf8 Ermal
	global $g, $config, $cpzone;
829 d99f7864 Scott Ullrich
830
	$stop_time = (empty($stop_time)) ? time() : $stop_time;
831
832
	/* this client needs to be deleted - remove ipfw rules */
833 b4792bf8 Ermal
	if (isset($config['captiveportal'][$cpzone]['radacct_enable']) && !empty($radiusservers)) {
834 5705c60a Renato Botelho
		RADIUS_ACCOUNTING_STOP($dbent[1], // ruleno
835
			$dbent[4], // username
836
			$dbent[5], // sessionid
837
			$dbent[0], // start time
838 5060dea7 Scott Ullrich
			$radiusservers,
839 5705c60a Renato Botelho
			$dbent[2], // clientip
840
			$dbent[3], // clientmac
841 5060dea7 Scott Ullrich
			$term_cause, // Acct-Terminate-Cause
842
			false,
843
			$stop_time);
844 d99f7864 Scott Ullrich
	}
845 32c392aa Ermal
	
846 5705c60a Renato Botelho
	if (is_ipaddr($dbent[2])) {
847 ddd69ea9 bcyrill
		/* Delete client's ip entry from tables 1 and 2. */
848 5705c60a Renato Botelho
		pfSense_ipfw_Tableaction($cpzone, IP_FW_TABLE_DEL, 1, $dbent[2]);
849
		pfSense_ipfw_Tableaction($cpzone, IP_FW_TABLE_DEL, 2, $dbent[2]);
850 32c392aa Ermal
		/* XXX: Redundant?! Ensure all pf(4) states are killed. */
851 5705c60a Renato Botelho
		pfSense_kill_states($dbent[2]);
852
		pfSense_kill_srcstates($dbent[2]);
853 32c392aa Ermal
	}
854 f9f71ad3 Ermal Lu?i
855
	/* 
856
	* These are the pipe numbers we use to control traffic shaping for each logged in user via captive portal
857
	* We could get an error if the pipe doesn't exist but everything should still be fine
858
	*/
859 5705c60a Renato Botelho
	if (!empty($dbent[1])) {
860
		pfSense_pipe_action("pipe delete {$dbent[1]}");
861
		pfSense_pipe_action("pipe delete " . ($dbent[1]+1));
862 7a7abeba Scott Ullrich
863 6cbda317 Ermal
		/* Release the ruleno so it can be reallocated to new clients. */
864 5705c60a Renato Botelho
		captiveportal_free_dn_ruleno($dbent[1]);
865 6cbda317 Ermal
	}
866 d322e3b3 Scott Ullrich
867
	// XMLRPC Call over to the master Voucher node
868 b4792bf8 Ermal
	if(!empty($config['voucher'][$cpzone]['vouchersyncdbip'])) {
869
		$syncip   = $config['voucher'][$cpzone]['vouchersyncdbip'];
870
		$syncport = $config['voucher'][$cpzone]['vouchersyncport'];
871
		$syncpass = $config['voucher'][$cpzone]['vouchersyncpass'];
872
		$vouchersyncusername = $config['voucher'][$cpzone]['vouchersyncusername'];
873 f989aa5b Ermal
		$remote_status = xmlrpc_sync_voucher_disconnect($dbent, $syncip, $syncport, $syncpass, $vouchersyncusername, $term_cause, $stop_time);
874 d322e3b3 Scott Ullrich
	}
875
876 3db19cf1 Scott Ullrich
}
877 12ee8fe4 Scott Ullrich
878 006802ab Ermal
/* remove a single client by sessionid */
879
function captiveportal_disconnect_client($sessionid, $term_cause = 1, $logoutReason = "LOGOUT") {
880 26ee5aaf Ermal
	global $g, $config;
881 36254e4a Scott Ullrich
882 d99f7864 Scott Ullrich
	$radiusservers = captiveportal_get_radius_servers();
883 006802ab Ermal
884
	/* read database */
885 5038fb53 bcyrill
	$result = captiveportal_read_db("WHERE sessionid = '{$sessionid}'");
886 d99f7864 Scott Ullrich
887
	/* find entry */
888 5038fb53 bcyrill
	if (!empty($result)) {
889 26ee5aaf Ermal
		captiveportal_write_db("DELETE FROM captiveportal WHERE sessionid = '{$sessionid}'");
890
891 5038fb53 bcyrill
		foreach ($result as $cpentry) {
892 5705c60a Renato Botelho
			if (empty($cpentry[10]))
893
				$cpentry[10] = 'first';
894
			captiveportal_disconnect($cpentry, $radiusservers[$cpentry[10]], $term_cause);
895
			captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], "DISCONNECT");
896 5038fb53 bcyrill
		}
897
		unset($result);
898 26ee5aaf Ermal
	}
899 5b237745 Scott Ullrich
}
900
901
/* send RADIUS acct stop for all current clients */
902 d31bc32a Ermal
function captiveportal_radius_stop_all() {
903 b4792bf8 Ermal
	global $config, $cpzone;
904 d99f7864 Scott Ullrich
905 b4792bf8 Ermal
	if (!isset($config['captiveportal'][$cpzone]['radacct_enable']))
906 d99f7864 Scott Ullrich
		return;
907
908
	$radiusservers = captiveportal_get_radius_servers();
909 40b48c6c Ermal Lu?i
	if (!empty($radiusservers)) {
910 d31bc32a Ermal
		$cpdb = captiveportal_read_db();
911
		foreach ($cpdb as $cpentry) {
912 5705c60a Renato Botelho
			if (empty($cpentry[10]))
913
				$cpentry[10] = 'first';
914
			if (!empty($radiusservers[$cpentry[10]])) {
915
				RADIUS_ACCOUNTING_STOP($cpentry[1], // ruleno
916
					$cpentry[4], // username
917
					$cpentry[5], // sessionid
918
					$cpentry[0], // start time
919
					$radiusservers[$cpentry[10]],
920
					$cpentry[2], // clientip
921
					$cpentry[3], // clientmac
922
					7); // Admin Reboot
923 ebc0e4b6 Ermal
			}
924 d99f7864 Scott Ullrich
		}
925
	}
926 5b237745 Scott Ullrich
}
927
928 d5ae560d Ermal
function captiveportal_passthrumac_configure_entry($macent) {
929 aea56408 Ermal
930
	$bwUp = empty($macent['bw_up']) ? 0 : $macent['bw_up'];
931
	$bwDown = empty($macent['bw_down']) ? 0 : $macent['bw_down'];
932 d5ae560d Ermal
933 10b9dfcf Ermal
	$ruleno = captiveportal_get_next_ipfw_ruleno();
934 aea56408 Ermal
	$pipeno = captiveportal_get_next_dn_ruleno();
935 d5ae560d Ermal
936 aea56408 Ermal
	$rules = "";
937
	$pipeup = $pipeno;
938 0674bc42 Ermal
	pfSense_pipe_action("pipe {$pipeup} config bw {$bwUp}Kbit/s queue 100 buckets 16");
939 aea56408 Ermal
	$pipedown = $pipeno + 1;
940 0674bc42 Ermal
	pfSense_pipe_action("pipe {$pipedown} config bw {$bwDown}Kbit/s queue 100 buckets 16");
941 aea56408 Ermal
	$rules .= "add {$ruleno} pipe {$pipeup} ip from any to any MAC {$macent['mac']} any\n";
942 d5ae560d Ermal
	$ruleno++;
943 aea56408 Ermal
	$rules .= "add {$ruleno} pipe {$pipedown} ip from any to any MAC any {$macent['mac']}\n";
944 d5ae560d Ermal
945
	return $rules;
946
}
947
948 dedf51a2 Ermal Lu?i
function captiveportal_passthrumac_configure($lock = false) {
949 b4792bf8 Ermal
	global $config, $g, $cpzone;
950 36254e4a Scott Ullrich
951 d5ae560d Ermal
	$rules = "";
952 36254e4a Scott Ullrich
953 b4792bf8 Ermal
	if (is_array($config['captiveportal'][$cpzone]['passthrumac'])) {
954 1dbe445a Ermal
		$macdb = array();
955 b4792bf8 Ermal
		foreach ($config['captiveportal'][$cpzone]['passthrumac'] as $macent) {
956 d5ae560d Ermal
			$rules .= captiveportal_passthrumac_configure_entry($macent);
957 b4792bf8 Ermal
			$macdb[$macent['mac']][$cpzone]['active']  = true;
958 1dbe445a Ermal
959 5b237745 Scott Ullrich
		}
960
	}
961 0bd34ed6 Scott Ullrich
962 d5ae560d Ermal
	return $rules;
963 5b237745 Scott Ullrich
}
964
965 fac13a5e Ermal
function captiveportal_passthrumac_findbyname($username) {
966 b4792bf8 Ermal
	global $config, $cpzone;
967 fac13a5e Ermal
968 b4792bf8 Ermal
	if (is_array($config['captiveportal'][$cpzone]['passthrumac'])) {
969
		foreach ($config['captiveportal'][$cpzone]['passthrumac'] as $macent) {
970 fac13a5e Ermal
			if ($macent['username'] == $username)
971
				return $macent;
972
		}
973
	}
974
	return NULL;
975
}
976
977 b01792a0 Ermal
/* 
978
 * table (3=IN)/(4=OUT) hold allowed ip's without bw limits
979
 */
980 1272429c Ermal
function captiveportal_allowedip_configure_entry($ipent, $ishostname = false) {
981 1b584e3f Ermal
	global $g;
982 b01792a0 Ermal
983 8b73cc7e Scott Ullrich
	/*  Instead of copying this entire function for something
984
	 *  easy such as hostname vs ip address add this check
985
	 */
986 bb58ed63 Ermal
	if ($ishostname === true) {
987 1b584e3f Ermal
		if (!$g['booting']) {
988
			$ipaddress = gethostbyname($ipent['hostname']);
989
			if (!is_ipaddr($ipaddress)) 
990
				return;
991
		}
992 bb58ed63 Ermal
	} else
993
		$ipaddress = $ipent['ip'];
994 0b108eda Scott Ullrich
995 b01792a0 Ermal
	$rules = "";
996 1272429c Ermal
	$cp_filterdns_conf = "";
997 aea56408 Ermal
	$enBwup = empty($ipent['bw_up']) ? 0 : intval($ipent['bw_up']);
998
	$enBwdown = empty($ipent['bw_down']) ? 0 : intval($ipent['bw_down']);
999 b01792a0 Ermal
1000 aea56408 Ermal
	$pipeno = captiveportal_get_next_dn_ruleno();
1001 657d2c66 Ermal
	pfSense_pipe_action("pipe {$pipeno} config bw {$enBwup}Kbit/s queue 100 buckets 16");
1002 aea56408 Ermal
	$pipedown = $pipeno + 1;
1003 657d2c66 Ermal
	pfSense_pipe_action("pipe {$pipedown} config bw {$enBwdown}Kbit/s queue 100 buckets 16");
1004 1272429c Ermal
	if ($ishostname === true) {
1005
		$cp_filterdns_conf .= "ipfw {$ipent['hostname']} 3 pipe {$pipeno}\n";
1006
		$cp_filterdns_conf .= "ipfw {$ipent['hostname']} 4 pipe {$pipedown}\n";
1007 1b584e3f Ermal
		if (!is_ipaddr($ipaddress))
1008
			return array("", $cp_filterdns_conf);
1009 1272429c Ermal
	}
1010 d6a0379d Ermal
	$subnet = "";
1011
	if (!empty($ipent['sn']))
1012
		$subnet = "/{$ipent['sn']}";
1013 aea56408 Ermal
	$rules .= "table 3 add {$ipaddress}{$subnet} {$pipeno}\n";
1014
	$rules .= "table 4 add {$ipaddress}{$subnet} {$pipedown}\n";
1015 b01792a0 Ermal
1016 1272429c Ermal
	if ($ishostname === true)
1017
		return array($rules, $cp_filterdns_conf);
1018
	else
1019
		return $rules;
1020 f23a6091 Scott Ullrich
}
1021
1022
function captiveportal_allowedhostname_configure() {
1023 b4792bf8 Ermal
	global $config, $g, $cpzone;
1024 f23a6091 Scott Ullrich
1025 1272429c Ermal
	$rules = "";
1026 b4792bf8 Ermal
	if (is_array($config['captiveportal'][$cpzone]['allowedhostname'])) {
1027 1272429c Ermal
		$rules = "\n# captiveportal_allowedhostname_configure()\n";
1028
		$cp_filterdns_conf = "";
1029
		foreach ($config['captiveportal'][$cpzone]['allowedhostname'] as $hostnameent) {
1030
			$tmprules = captiveportal_allowedip_configure_entry($hostnameent, true);
1031
			$rules .= $tmprules[0];
1032
			$cp_filterdns_conf .= $tmprules[1];
1033
		}
1034
		$cp_filterdns_filename = "{$g['varetc_path']}/filterdns-{$cpzone}-captiveportal.conf";
1035
		@file_put_contents($cp_filterdns_filename, $cp_filterdns_conf);
1036
		unset($cp_filterdns_conf);
1037 081320a4 Ermal
		if (isvalidpid("{$g['varrun_path']}/filterdns-{$cpzone}-cpah.pid"))
1038
			sigkillbypid("{$g['varrun_path']}/filterdns-{$cpzone}-cpah.pid", "HUP");
1039 bb58ed63 Ermal
		else
1040 081320a4 Ermal
			mwexec("/usr/local/sbin/filterdns -p {$g['varrun_path']}/filterdns-{$cpzone}-cpah.pid -i 300 -c {$cp_filterdns_filename} -y {$cpzone} -d 1");
1041 7b5eab84 bcyrill
	} else {
1042
		killbypid("{$g['varrun_path']}/filterdns-{$cpzone}-cpah.pid");
1043
		@unlink("{$g['varrun_path']}/filterdns-{$cpzone}-cpah.pid");
1044 55c18b30 Scott Ullrich
	}
1045 1272429c Ermal
1046 f23a6091 Scott Ullrich
	return $rules;
1047
}
1048
1049 cb0a2913 Ermal Lu?i
function captiveportal_allowedip_configure() {
1050 b4792bf8 Ermal
	global $config, $g, $cpzone;
1051 36254e4a Scott Ullrich
1052 6ce61a8f Ermal
	$rules = "";
1053 b4792bf8 Ermal
	if (is_array($config['captiveportal'][$cpzone]['allowedip'])) {
1054
		foreach ($config['captiveportal'][$cpzone]['allowedip'] as $ipent) 
1055 b01792a0 Ermal
			$rules .= captiveportal_allowedip_configure_entry($ipent);
1056 cb0a2913 Ermal Lu?i
	}
1057 36254e4a Scott Ullrich
1058 6ce61a8f Ermal
	return $rules;
1059 5b237745 Scott Ullrich
}
1060
1061 2d53158f stompro
/* get last activity timestamp given client IP address */
1062 f9f71ad3 Ermal Lu?i
function captiveportal_get_last_activity($ip) {
1063 b4792bf8 Ermal
	global $cpzone;
1064 36254e4a Scott Ullrich
1065 1272429c Ermal
	$ipfwoutput = pfSense_ipfw_getTablestats($cpzone, 1, $ip);
1066 f9f71ad3 Ermal Lu?i
	/* Reading only from one of the tables is enough of approximation. */
1067 1272429c Ermal
	if (is_array($ipfwoutput)) {
1068
		return $ipfwoutput['timestamp'];
1069 d99f7864 Scott Ullrich
	}
1070 36254e4a Scott Ullrich
1071 d99f7864 Scott Ullrich
	return 0;
1072 5b237745 Scott Ullrich
}
1073
1074 d31bc32a Ermal
function captiveportal_init_radius_servers() {
1075 b4792bf8 Ermal
	global $config, $g, $cpzone;
1076 d31bc32a Ermal
1077
	/* generate radius server database */
1078 b4792bf8 Ermal
	if ($config['captiveportal'][$cpzone]['radiusip'] && (!isset($config['captiveportal'][$cpzone]['auth_method']) ||
1079
		($config['captiveportal'][$cpzone]['auth_method'] == "radius"))) {
1080
		$radiusip = $config['captiveportal'][$cpzone]['radiusip'];
1081
		$radiusip2 = ($config['captiveportal'][$cpzone]['radiusip2']) ? $config['captiveportal'][$cpzone]['radiusip2'] : null;
1082 7468a29f jim-p
		$radiusip3 = ($config['captiveportal'][$cpzone]['radiusip3']) ? $config['captiveportal'][$cpzone]['radiusip3'] : null;
1083
		$radiusip4 = ($config['captiveportal'][$cpzone]['radiusip4']) ? $config['captiveportal'][$cpzone]['radiusip4'] : null;
1084 d31bc32a Ermal
1085 b4792bf8 Ermal
		if ($config['captiveportal'][$cpzone]['radiusport'])
1086
			$radiusport = $config['captiveportal'][$cpzone]['radiusport'];
1087 d31bc32a Ermal
		else
1088
			$radiusport = 1812;
1089 b4792bf8 Ermal
		if ($config['captiveportal'][$cpzone]['radiusacctport'])
1090
			$radiusacctport = $config['captiveportal'][$cpzone]['radiusacctport'];
1091 d31bc32a Ermal
		else
1092
			$radiusacctport = 1813;
1093 b4792bf8 Ermal
		if ($config['captiveportal'][$cpzone]['radiusport2'])
1094
			$radiusport2 = $config['captiveportal'][$cpzone]['radiusport2'];
1095 d31bc32a Ermal
		else
1096
			$radiusport2 = 1812;
1097 7468a29f jim-p
		if ($config['captiveportal'][$cpzone]['radiusport3'])
1098
			$radiusport3 = $config['captiveportal'][$cpzone]['radiusport3'];
1099 ebc0e4b6 Ermal
		else
1100
			$radiusport3 = 1812;
1101 7468a29f jim-p
		if ($config['captiveportal'][$cpzone]['radiusport4'])
1102
			$radiusport4 = $config['captiveportal'][$cpzone]['radiusport4'];
1103 ebc0e4b6 Ermal
		else
1104
			$radiusport4 = 1812;
1105
1106 b4792bf8 Ermal
		$radiuskey = $config['captiveportal'][$cpzone]['radiuskey'];
1107 dbce0c2c bcyrill
		$radiuskey2 = $config['captiveportal'][$cpzone]['radiuskey2'];
1108
		$radiuskey3 = $config['captiveportal'][$cpzone]['radiuskey3'];
1109
		$radiuskey4 = $config['captiveportal'][$cpzone]['radiuskey4'];
1110 d31bc32a Ermal
1111 b4792bf8 Ermal
		$cprdsrvlck = lock("captiveportalradius{$cpzone}", LOCK_EX);
1112
		$fd = @fopen("{$g['vardb_path']}/captiveportal_radius_{$cpzone}.db", "w");
1113 d31bc32a Ermal
		if (!$fd) {
1114
			captiveportal_syslog("Error: cannot open radius DB file in captiveportal_configure().\n");
1115
			unlock($cprdsrvlck);
1116
			return 1;
1117 ebc0e4b6 Ermal
		}
1118 dbce0c2c bcyrill
		if (isset($radiusip))
1119 ebc0e4b6 Ermal
			fwrite($fd,$radiusip . "," . $radiusport . "," . $radiusacctport . "," . $radiuskey . ",first");
1120 dbce0c2c bcyrill
		if (isset($radiusip2))
1121 ebc0e4b6 Ermal
			fwrite($fd,"\n" . $radiusip2 . "," . $radiusport2 . "," . $radiusacctport . "," . $radiuskey2 . ",first");
1122 dbce0c2c bcyrill
		if (isset($radiusip3))
1123 ebc0e4b6 Ermal
			fwrite($fd,"\n" . $radiusip3 . "," . $radiusport3 . "," . $radiusacctport . "," . $radiuskey3 . ",second");
1124 dbce0c2c bcyrill
		if (isset($radiusip4))
1125 ebc0e4b6 Ermal
			fwrite($fd,"\n" . $radiusip4 . "," . $radiusport4 . "," . $radiusacctport . "," . $radiuskey4 . ",second");
1126
		
1127
1128 d31bc32a Ermal
		fclose($fd);
1129
		unlock($cprdsrvlck);
1130
	}
1131
}
1132
1133 5b237745 Scott Ullrich
/* read RADIUS servers into array */
1134
function captiveportal_get_radius_servers() {
1135 b4792bf8 Ermal
	global $g, $cpzone;
1136 ac07425a Ermal
1137 b4792bf8 Ermal
	$cprdsrvlck = lock("captiveportalradius{$cpzone}");
1138
	if (file_exists("{$g['vardb_path']}/captiveportal_radius_{$cpzone}.db")) {
1139 ac07425a Ermal
		$radiusservers = array();
1140 b4792bf8 Ermal
		$cpradiusdb = file("{$g['vardb_path']}/captiveportal_radius_{$cpzone}.db", 
1141 ac07425a Ermal
		FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
1142
		if ($cpradiusdb) {
1143
			foreach($cpradiusdb as $cpradiusentry) {
1144
				$line = trim($cpradiusentry);
1145
				if ($line) {
1146
					$radsrv = array();
1147 ebc0e4b6 Ermal
						list($radsrv['ipaddr'],$radsrv['port'],$radsrv['acctport'],$radsrv['key'], $context) = explode(",",$line);
1148
				}
1149
				if (empty($context)) {
1150
					if (!is_array($radiusservers['first']))
1151
						$radiusservers['first'] = array();
1152
					$radiusservers['first'] = $radsrv;
1153
				} else {
1154
					if (!is_array($radiusservers[$context]))
1155
						$radiusservers[$context] = array();
1156
					$radiusservers[$context][] = $radsrv;
1157 5060dea7 Scott Ullrich
				}
1158
			}
1159 2f70eac7 Ermal Lu?i
		}
1160 60b66b60 Ermal
		unlock($cprdsrvlck);
1161 ac07425a Ermal
		return $radiusservers;
1162
	}
1163
1164
	unlock($cprdsrvlck);
1165
	return false;
1166 5b237745 Scott Ullrich
}
1167
1168 3db19cf1 Scott Ullrich
/* log successful captive portal authentication to syslog */
1169
/* part of this code from php.net */
1170 0bd34ed6 Scott Ullrich
function captiveportal_logportalauth($user,$mac,$ip,$status, $message = null) {
1171 d99f7864 Scott Ullrich
	// Log it
1172
	if (!$message)
1173 f56a73f1 Scott Ullrich
		$message = "$status: $user, $mac, $ip";
1174 d31bc32a Ermal
	else {
1175
		$message = trim($message);
1176 f56a73f1 Scott Ullrich
		$message = "$status: $user, $mac, $ip, $message";
1177 d31bc32a Ermal
	}
1178 f56a73f1 Scott Ullrich
	captiveportal_syslog($message);
1179
}
1180
1181
/* log simple messages to syslog */
1182
function captiveportal_syslog($message) {
1183
	$message = trim($message);
1184
	openlog("logportalauth", LOG_PID, LOG_LOCAL4);
1185
	// Log it
1186
	syslog(LOG_INFO, $message);
1187 d99f7864 Scott Ullrich
	closelog();
1188 3db19cf1 Scott Ullrich
}
1189
1190 ebc0e4b6 Ermal
function radius($username,$password,$clientip,$clientmac,$type, $radiusctx = null) {
1191 5060dea7 Scott Ullrich
	global $g, $config;
1192 d44bccc7 Scott Ullrich
1193 aea56408 Ermal
	$pipeno = captiveportal_get_next_dn_ruleno();
1194 2f70eac7 Ermal Lu?i
1195 5060dea7 Scott Ullrich
	/* If the pool is empty, return appropriate message and fail authentication */
1196 aea56408 Ermal
	if (is_null($pipeno)) {
1197 5060dea7 Scott Ullrich
		$auth_list = array();
1198
		$auth_list['auth_val'] = 1;
1199
		$auth_list['error'] = "System reached maximum login capacity";
1200
		return $auth_list;
1201
	}
1202 9befcca7 Ermal Lu?i
1203 5060dea7 Scott Ullrich
	$radiusservers = captiveportal_get_radius_servers();
1204 d44bccc7 Scott Ullrich
1205 ebc0e4b6 Ermal
	if (is_null($radiusctx))
1206
		$radiusctx = 'first';
1207
1208 5060dea7 Scott Ullrich
	$auth_list = RADIUS_AUTHENTICATION($username,
1209
		$password,
1210 ebc0e4b6 Ermal
		$radiusservers[$radiusctx],
1211 5060dea7 Scott Ullrich
		$clientip,
1212
		$clientmac,
1213 aea56408 Ermal
		$pipeno);
1214 5060dea7 Scott Ullrich
1215
	if ($auth_list['auth_val'] == 2) {
1216
		captiveportal_logportalauth($username,$clientmac,$clientip,$type);
1217
		$sessionid = portal_allow($clientip,
1218
			$clientmac,
1219
			$username,
1220
			$password,
1221
			$auth_list,
1222 aea56408 Ermal
			$pipeno,
1223 ebc0e4b6 Ermal
			$radiusctx);
1224 5060dea7 Scott Ullrich
	}
1225 0bd34ed6 Scott Ullrich
1226 5060dea7 Scott Ullrich
	return $auth_list;
1227 0bd34ed6 Scott Ullrich
}
1228
1229 26ee5aaf Ermal
function captiveportal_opendb() {
1230 b4792bf8 Ermal
	global $g, $cpzone;
1231 5060dea7 Scott Ullrich
1232 26ee5aaf Ermal
	if (file_exists("{$g['vardb_path']}/captiveportal{$cpzone}.db"))
1233
		$DB = @sqlite_open("{$g['vardb_path']}/captiveportal{$cpzone}.db");
1234
	else {
1235
		$errormsg = "";
1236
		$DB = @sqlite_open("{$g['vardb_path']}/captiveportal{$cpzone}.db");
1237 5705c60a Renato Botelho
		if (@sqlite_exec($DB, "CREATE TABLE captiveportal (allow_time INTEGER, pipeno INTEGER, ip TEXT, mac TEXT, username TEXT, sessionid TEXT, bpassword TEXT, session_timeout INTEGER, idle_timeout INTEGER, session_terminate_time INTEGER, interim_interval INTEGER) ", $errormsg)) {
1238 a19ea478 Ermal
			@sqlite_exec($DB, "CREATE UNIQUE INDEX idx_active ON captiveportal (sessionid, username)");
1239
			@sqlite_exec($DB, "CREATE INDEX user ON captiveportal (username)");
1240
			@sqlite_exec($DB, "CREATE INDEX ip ON captiveportal (ip)");
1241 26ee5aaf Ermal
			@sqlite_exec($DB, "CREATE INDEX starttime ON captiveportal (allow_time)");
1242
			@sqlite_exec($DB, "CREATE INDEX serviceid ON captiveportal (serviceid)");
1243
		} else
1244
			captiveportal_syslog("Error during table {$cpzone} creation. Error message: {$errormsg}");
1245 006802ab Ermal
	}
1246 26ee5aaf Ermal
1247
	return $DB;
1248 0bd34ed6 Scott Ullrich
}
1249
1250 26ee5aaf Ermal
/* read captive portal DB into array */
1251
function captiveportal_read_db($query = "") {
1252 5060dea7 Scott Ullrich
1253 26ee5aaf Ermal
	$DB = captiveportal_opendb();
1254
	if ($DB) {
1255
		sqlite_exec($DB, "BEGIN");
1256 08d93848 bcyrill
		if (!empty($query))
1257 5705c60a Renato Botelho
			$cpdb = @sqlite_array_query($DB, "SELECT * FROM captiveportal {$query}", SQLITE_NUM);
1258 26ee5aaf Ermal
		else {
1259 5705c60a Renato Botelho
			$response = @sqlite_unbuffered_query($DB, "SELECT * FROM captiveportal", SQLITE_NUM);
1260
			$cpdb = @sqlite_fetch_all($response, SQLITE_NUM);
1261 5c0b5f64 Ermal
		}
1262 26ee5aaf Ermal
		sqlite_exec($DB, "END");
1263
		@sqlite_close($DB);
1264 006802ab Ermal
	}
1265 26ee5aaf Ermal
	if (!$cpdb)
1266
		$cpdb = array();
1267
1268
	return $cpdb;
1269
}
1270
1271
function captiveportal_remove_entries($remove) {
1272
1273
	if (!is_array($remove) || empty($remove))
1274
		return;
1275
1276 1974c2d6 bcyrill
	$query = "DELETE FROM captiveportal WHERE sessionid in (";
1277 be0a33ef bcyrill
	foreach($remove as $idx => $unindex) {
1278 26ee5aaf Ermal
		$query .= "'{$unindex}'";
1279
		if ($idx < (count($remove) - 1))
1280
			$query .= ",";
1281 006802ab Ermal
	}
1282 26ee5aaf Ermal
	$query .= ")";
1283
	captiveportal_write_db($query);
1284
}
1285
1286
/* write captive portal DB */
1287
function captiveportal_write_db($queries) {
1288
	global $g;
1289
1290
	if (is_array($queries))
1291
		$query = implode(";", $queries);
1292
	else
1293
		$query = $queries;
1294
1295
	$DB = captiveportal_opendb();
1296
	if ($DB) {
1297
		$error_msg = "";
1298
		sqlite_exec($DB, "BEGIN TRANSACTION");
1299
		$result = @sqlite_exec($DB, $query, $error_msg);
1300
		if (!$result)
1301
			captiveportal_syslog("Trying to modify DB returned error: {$error_msg}");
1302
		else
1303
			sqlite_exec($DB, "END TRANSACTION");
1304
		@sqlite_close($DB);
1305
		return $result;
1306
	} else
1307
		return true;
1308 0bd34ed6 Scott Ullrich
}
1309
1310
function captiveportal_write_elements() {
1311 b4792bf8 Ermal
	global $g, $config, $cpzone;
1312 5060dea7 Scott Ullrich
	
1313 b4792bf8 Ermal
	$cpcfg = $config['captiveportal'][$cpzone];
1314
1315 769e254e Ermal
	/* delete any existing elements */
1316
	if (is_dir($g['captiveportal_element_path'])) {
1317
		$dh = opendir($g['captiveportal_element_path']);
1318
		while (($file = readdir($dh)) !== false) {
1319
			if ($file != "." && $file != "..")
1320
				unlink($g['captiveportal_element_path'] . "/" . $file);
1321
		}
1322
		closedir($dh);
1323 5060dea7 Scott Ullrich
	} else {
1324 769e254e Ermal
		@mkdir($g['captiveportal_element_path']);
1325 5060dea7 Scott Ullrich
	}
1326 769e254e Ermal
1327 b4792bf8 Ermal
	if (is_array($cpcfg['element'])) {
1328 1fadb31d Scott Ullrich
		conf_mount_rw();
1329 b4792bf8 Ermal
		foreach ($cpcfg['element'] as $data) {
1330 3760b867 Ermal
			if (!@file_put_contents("{$g['captiveportal_element_path']}/{$data['name']}", base64_decode($data['content']))) {
1331 fdc55311 Carlos Eduardo Ramos
				printf(gettext("Error: cannot open '%s' in captiveportal_write_elements()%s"), $data['name'], "\n");
1332 1fadb31d Scott Ullrich
				return 1;
1333
			}
1334
			unlink_if_exists("{$g['captiveportal_path']}/{$data['name']}");
1335 3760b867 Ermal
			@symlink("{$g['captiveportal_element_path']}/{$data['name']}", "{$g['captiveportal_path']}/{$data['name']}");
1336 1fadb31d Scott Ullrich
		}
1337
		conf_mount_ro();
1338
	}
1339 5060dea7 Scott Ullrich
	
1340 769e254e Ermal
	return 0;
1341 0bd34ed6 Scott Ullrich
}
1342
1343 aea56408 Ermal
function captiveportal_get_next_dn_ruleno($rulenos_start = 2000, $rulenos_range_max = 64500) {
1344
	global $config, $g;
1345 6ce61a8f Ermal
1346 aea56408 Ermal
	$cpruleslck = lock("captiveportalrulesdn", LOCK_EX);
1347
	$ruleno = 0;
1348
	if (file_exists("{$g['vardb_path']}/captiveportaldn.rules")) {
1349
		$rules = unserialize(file_get_contents("{$g['vardb_path']}/captiveportaldn.rules"));
1350
		for ($ridx = $rulenos_start; $ridx < $rulenos_range_max; $ridx++) {
1351
			if ($rules[$ridx]) {
1352
				$ridx++;
1353
				continue;
1354
			}
1355
			$ruleno = $ridx;
1356
			$rules[$ridx] = "used";
1357
			$rules[++$ridx] = "used";
1358
			break;
1359
		}
1360
	} else {
1361 fe3693cb Ermal
		$rules = array_pad(array(), $rulenos_range_max, false);
1362 aea56408 Ermal
		$rules[$rulenos_start] = "used";
1363
		$rules[++$rulenos_start] = "used";
1364
		$ruleno = $rulenos_start;
1365
	}
1366
	file_put_contents("{$g['vardb_path']}/captiveportaldn.rules", serialize($rules));
1367
	unlock($cpruleslck);
1368
1369
	return $ruleno;
1370
}
1371
1372
function captiveportal_free_dn_ruleno($ruleno) {
1373 87e7fdea bcyrill
	global $config, $g;
1374
1375
	$cpruleslck = lock("captiveportalrulesdn", LOCK_EX);
1376
	if (file_exists("{$g['vardb_path']}/captiveportaldn.rules")) {
1377
		$rules = unserialize(file_get_contents("{$g['vardb_path']}/captiveportaldn.rules"));
1378
		$rules[$ruleno] = false;
1379
		$rules[++$ruleno] = false;
1380
		file_put_contents("{$g['vardb_path']}/captiveportaldn.rules", serialize($rules));
1381
	}
1382
	unlock($cpruleslck);
1383 aea56408 Ermal
}
1384
1385
function captiveportal_get_dn_passthru_ruleno($value) {
1386 b273dd26 Ermal
	global $config, $g, $cpzone;
1387
1388
	$cpcfg = $config['captiveportal'][$cpzone];
1389
	if(!isset($cpcfg['enable']))
1390
		return NULL;
1391 aea56408 Ermal
1392 fe7e987e Ermal
	$cpruleslck = lock("captiveportalrulesdn", LOCK_EX);
1393
	if (file_exists("{$g['vardb_path']}/captiveportaldn.rules")) {
1394
		$rules = unserialize(file_get_contents("{$g['vardb_path']}/captiveportaldn.rules"));
1395 287f7e26 Ermal
		$ruleno = intval(`/sbin/ipfw -x {$cpzone} show | /usr/bin/grep {$value} |  /usr/bin/grep -v grep | /usr/bin/cut -d " " -f 5 | /usr/bin/head -n 1`);
1396 aea56408 Ermal
		if ($rules[$ruleno]) {
1397
			unlock($cpruleslck);
1398
			return $ruleno;
1399
		}
1400
	}
1401
1402
	unlock($cpruleslck);
1403
	return NULL;
1404 6ce61a8f Ermal
}
1405
1406 920cafaf Scott Ullrich
/*
1407
 * This function will calculate the lowest free firewall ruleno
1408 f9f71ad3 Ermal Lu?i
 * within the range specified based on the actual logged on users
1409 920cafaf Scott Ullrich
 *
1410
 */
1411 aea56408 Ermal
function captiveportal_get_next_ipfw_ruleno($rulenos_start = 2, $rulenos_range_max = 64500) {
1412 b4792bf8 Ermal
	global $config, $g, $cpzone;
1413 6ce61a8f Ermal
1414 b4792bf8 Ermal
	$cpcfg = $config['captiveportal'][$cpzone];
1415
	if(!isset($cpcfg['enable']))
1416 01d57b8c Scott Ullrich
		return NULL;
1417 6ce61a8f Ermal
1418 b4792bf8 Ermal
	$cpruleslck = lock("captiveportalrules{$cpzone}", LOCK_EX);
1419 f9f71ad3 Ermal Lu?i
	$ruleno = 0;
1420 b4792bf8 Ermal
	if (file_exists("{$g['vardb_path']}/captiveportal_{$cpzone}.rules")) {
1421
		$rules = unserialize(file_get_contents("{$g['vardb_path']}/captiveportal_{$cpzone}.rules"));
1422 6ce61a8f Ermal
		for ($ridx = 2; $ridx < ($rulenos_range_max - $rulenos_start); $ridx++) {
1423
			if ($rules[$ridx]) {
1424
				/* 
1425 5060dea7 Scott Ullrich
				 * This allows our traffic shaping pipes to be the in pipe the same as ruleno 
1426 10b9dfcf Ermal
				 * and the out pipe ruleno + 1.
1427 5060dea7 Scott Ullrich
				 */
1428 10b9dfcf Ermal
				$ridx++;
1429 6ce61a8f Ermal
				continue;
1430
			}
1431
			$ruleno = $ridx;
1432
			$rules[$ridx] = "used";
1433 10b9dfcf Ermal
			$rules[++$ridx] = "used";
1434 6ce61a8f Ermal
			break;
1435
		}
1436
	} else {
1437 fe3693cb Ermal
		$rules = array_pad(array(), $rulenos_range_max, false);
1438 aea56408 Ermal
		$rules[$rulenos_start] = "used";
1439
		$rules[++$rulenos_start] = "used";
1440 6ce61a8f Ermal
		$ruleno = 2;
1441
	}
1442 b4792bf8 Ermal
	file_put_contents("{$g['vardb_path']}/captiveportal_{$cpzone}.rules", serialize($rules));
1443 d31bc32a Ermal
	unlock($cpruleslck);
1444 6ce61a8f Ermal
	return $ruleno;
1445
}
1446
1447 aea56408 Ermal
function captiveportal_free_ipfw_ruleno($ruleno) {
1448 b4792bf8 Ermal
	global $config, $g, $cpzone;
1449 6ce61a8f Ermal
1450 b4792bf8 Ermal
	$cpcfg = $config['captiveportal'][$cpzone];
1451
	if(!isset($cpcfg['enable']))
1452 6ce61a8f Ermal
		return NULL;
1453
1454 b4792bf8 Ermal
	$cpruleslck = lock("captiveportalrules{$cpzone}", LOCK_EX);
1455
	if (file_exists("{$g['vardb_path']}/captiveportal_{$cpzone}.rules")) {
1456
		$rules = unserialize(file_get_contents("{$g['vardb_path']}/captiveportal_{$cpzone}.rules"));
1457 6ce61a8f Ermal
		$rules[$ruleno] = false;
1458 10b9dfcf Ermal
		$rules[++$ruleno] = false;
1459 b4792bf8 Ermal
		file_put_contents("{$g['vardb_path']}/captiveportal_{$cpzone}.rules", serialize($rules));
1460 f9f71ad3 Ermal Lu?i
	}
1461 d31bc32a Ermal
	unlock($cpruleslck);
1462 6ce61a8f Ermal
}
1463
1464 d5ae560d Ermal
function captiveportal_get_ipfw_passthru_ruleno($value) {
1465 b4792bf8 Ermal
	global $config, $g, $cpzone;
1466 6ce61a8f Ermal
1467 b4792bf8 Ermal
	$cpcfg = $config['captiveportal'][$cpzone];
1468
	if(!isset($cpcfg['enable']))
1469
		return NULL;
1470 6ce61a8f Ermal
1471 b4792bf8 Ermal
	$cpruleslck = lock("captiveportalrules{$cpzone}", LOCK_EX);
1472
	if (file_exists("{$g['vardb_path']}/captiveportal_{$cpzone}.rules")) {
1473
		$rules = unserialize(file_get_contents("{$g['vardb_path']}/captiveportal_{$cpzone}.rules"));
1474 287f7e26 Ermal
		$ruleno = intval(`/sbin/ipfw -x {$cpzone} show | /usr/bin/grep {$value} |  /usr/bin/grep -v grep | /usr/bin/cut -d " " -f 1 | /usr/bin/head -n 1`);
1475 d31bc32a Ermal
		if ($rules[$ruleno]) {
1476
			unlock($cpruleslck);
1477 6ce61a8f Ermal
			return $ruleno;
1478 d31bc32a Ermal
		}
1479 5060dea7 Scott Ullrich
	}
1480 6ce61a8f Ermal
1481 d31bc32a Ermal
	unlock($cpruleslck);
1482 f9f71ad3 Ermal Lu?i
	return NULL;
1483 920cafaf Scott Ullrich
}
1484
1485 360d815d Scott Ullrich
/**
1486
 * This function will calculate the traffic produced by a client
1487
 * based on its firewall rule
1488
 *
1489
 * Point of view: NAS
1490
 *
1491
 * Input means: from the client
1492
 * Output means: to the client
1493
 *
1494
 */
1495
1496 f9f71ad3 Ermal Lu?i
function getVolume($ip) {
1497 f48abba2 Michael Newton
	global $config, $cpzone;
1498 360d815d Scott Ullrich
1499 f48abba2 Michael Newton
	$reverse = empty($config['captiveportal'][$cpzone]['reverseacct']) ? false : true;
1500 5060dea7 Scott Ullrich
	$volume = array();
1501
	// Initialize vars properly, since we don't want NULL vars
1502
	$volume['input_pkts'] = $volume['input_bytes'] = $volume['output_pkts'] = $volume['output_bytes'] = 0 ;
1503 360d815d Scott Ullrich
1504 1272429c Ermal
	$ipfw = pfSense_ipfw_getTablestats($cpzone, 1, $ip);
1505
	if (is_array($ipfw)) {
1506 f48abba2 Michael Newton
		if ($reverse) {
1507
			$volume['output_pkts'] = $ipfw['packets'];
1508
			$volume['output_bytes'] = $ipfw['bytes'];
1509
		}
1510
		else {
1511
			$volume['input_pkts'] = $ipfw['packets'];
1512
			$volume['input_bytes'] = $ipfw['bytes'];
1513
		}
1514 5060dea7 Scott Ullrich
	}
1515 f9f71ad3 Ermal Lu?i
1516 1272429c Ermal
	$ipfw = pfSense_ipfw_getTablestats($cpzone, 2, $ip);
1517
	if (is_array($ipfw)) {
1518 f48abba2 Michael Newton
		if ($reverse) {
1519
			$volume['input_pkts'] = $ipfw['packets'];
1520
			$volume['input_bytes'] = $ipfw['bytes'];
1521
		}
1522
		else {
1523
			$volume['output_pkts'] = $ipfw['packets'];
1524
			$volume['output_bytes'] = $ipfw['bytes'];
1525
		}
1526 5060dea7 Scott Ullrich
	}
1527 360d815d Scott Ullrich
1528 5060dea7 Scott Ullrich
	return $volume;
1529 360d815d Scott Ullrich
}
1530
1531 856e58a6 Scott Ullrich
/**
1532
 * Get the NAS-IP-Address based on the current wan address
1533
 *
1534
 * Use functions in interfaces.inc to find this out
1535
 *
1536
 */
1537
1538
function getNasIP()
1539
{
1540 b4792bf8 Ermal
	global $config, $cpzone;
1541 64c0462b Ermal
1542 b4792bf8 Ermal
	if (empty($config['captiveportal'][$cpzone]['radiussrcip_attribute'])) {
1543 5060dea7 Scott Ullrich
			$nasIp = get_interface_ip();
1544
	} else {
1545 b4792bf8 Ermal
		if (is_ipaddr($config['captiveportal'][$cpzone]['radiussrcip_attribute']))
1546
			$nasIp = $config['captiveportal'][$cpzone]['radiussrcip_attribute'];
1547 5060dea7 Scott Ullrich
		else
1548 b4792bf8 Ermal
			$nasIp = get_interface_ip($config['captiveportal'][$cpzone]['radiussrcip_attribute']);
1549 36ff7f81 Ermal
	}
1550 64c0462b Ermal
		
1551 5060dea7 Scott Ullrich
	if(!is_ipaddr($nasIp))
1552
		$nasIp = "0.0.0.0";
1553 64c0462b Ermal
1554
	return $nasIp;
1555 856e58a6 Scott Ullrich
}
1556
1557 f8b11310 Ermal Lu?i
function portal_ip_from_client_ip($cliip) {
1558 b4792bf8 Ermal
	global $config, $cpzone;
1559 f8b11310 Ermal Lu?i
1560 45bef774 bcyrill
	$isipv6 = is_ipaddrv6($cliip);
1561 b4792bf8 Ermal
	$interfaces = explode(",", $config['captiveportal'][$cpzone]['interface']);
1562 f8b11310 Ermal Lu?i
	foreach ($interfaces as $cpif) {
1563 45bef774 bcyrill
		if ($isipv6) {
1564
			$ip = get_interface_ipv6($cpif);
1565
			$sn = get_interface_subnetv6($cpif);
1566
		} else {
1567
			$ip = get_interface_ip($cpif);
1568
			$sn = get_interface_subnet($cpif);
1569
		}
1570 f8b11310 Ermal Lu?i
		if (ip_in_subnet($cliip, "{$ip}/{$sn}"))
1571
			return $ip;
1572
	}
1573
1574 45bef774 bcyrill
	$inet = ($isipv6) ? '-inet6' : '-inet';
1575
	$iface = exec_command("/sbin/route -n get {$inet} {$cliip} | /usr/bin/awk '/interface/ { print \$2; };'");
1576 f86fa91c jim-p
	$iface = trim($iface, "\n");
1577
	if (!empty($iface)) {
1578 45bef774 bcyrill
		$ip = ($isipv6) ? find_interface_ipv6($iface) : find_interface_ip($iface);
1579 f86fa91c jim-p
		if (is_ipaddr($ip))
1580
			return $ip;
1581
	}
1582
1583 cc125e13 Chris Buechler
	// doesn't match up to any particular interface
1584
	// so let's set the portal IP to what PHP says 
1585
	// the server IP issuing the request is. 
1586
	// allows same behavior as 1.2.x where IP isn't 
1587
	// in the subnet of any CP interface (static routes, etc.)
1588
	// rather than forcing to DNS hostname resolution
1589
	$ip = $_SERVER['SERVER_ADDR'];
1590
	if (is_ipaddr($ip))
1591
		return $ip;
1592
1593 f8b11310 Ermal Lu?i
	return false;
1594
}
1595
1596 de132ae3 bcyrill
function portal_hostname_from_client_ip($cliip) {
1597
	global $config, $cpzone;
1598
1599
	$cpcfg = $config['captiveportal'][$cpzone];
1600
1601
	if (isset($cpcfg['httpslogin'])) {
1602
		$listenporthttps = $cpcfg['listenporthttps'] ? $cpcfg['listenporthttps'] : ($cpcfg['zoneid'] + 1);
1603
		$ourhostname = $cpcfg['httpsname'];
1604
		
1605
		if ($listenporthttps != 443)
1606
			$ourhostname .= ":" . $listenporthttps;
1607
	} else {
1608
		$listenporthttp  = $cpcfg['listenporthttp']  ? $cpcfg['listenporthttp']  : $cpcfg['zoneid'];
1609
		$ifip = portal_ip_from_client_ip($cliip);
1610
		if (!$ifip)
1611
			$ourhostname = "{$config['system']['hostname']}.{$config['system']['domain']}";
1612
		else
1613
			$ourhostname = (is_ipaddrv6($ifip)) ? "[{$ifip}]" : "{$ifip}";
1614
		
1615
		if ($listenporthttp != 80)
1616
			$ourhostname .= ":" . $listenporthttp;
1617
	}
1618 d5ac388b bcyrill
	
1619
	return $ourhostname;
1620 de132ae3 bcyrill
}
1621
1622 ac631bba lgcosta
/* functions move from index.php */
1623
1624
function portal_reply_page($redirurl, $type = null, $message = null, $clientmac = null, $clientip = null, $username = null, $password = null) {
1625 b4792bf8 Ermal
	global $g, $config, $cpzone;
1626 ac631bba lgcosta
1627
	/* Get captive portal layout */
1628
	if ($type == "redir") {
1629
		header("Location: {$redirurl}");
1630
		return;
1631
	} else if ($type == "login")
1632 b4792bf8 Ermal
		$htmltext = get_include_contents("{$g['varetc_path']}/captiveportal_{$cpzone}.html");
1633 ac631bba lgcosta
	else
1634 b4792bf8 Ermal
		$htmltext = get_include_contents("{$g['varetc_path']}/captiveportal-{$cpzone}-error.html");
1635
1636
	$cpcfg = $config['captiveportal'][$cpzone];
1637 ac631bba lgcosta
1638
	/* substitute the PORTAL_REDIRURL variable */
1639 de132ae3 bcyrill
	if ($cpcfg['preauthurl']) {
1640
		$htmltext = str_replace("\$PORTAL_REDIRURL\$", "{$cpcfg['preauthurl']}", $htmltext);
1641
		$htmltext = str_replace("#PORTAL_REDIRURL#", "{$cpcfg['preauthurl']}", $htmltext);
1642 ac631bba lgcosta
	}
1643
1644
	/* substitute other variables */
1645 de132ae3 bcyrill
	$ourhostname = portal_hostname_from_client_ip($clientip);
1646
	$protocol = (isset($cpcfg['httpslogin'])) ? 'https://' : 'http://';
1647
	$htmltext = str_replace("\$PORTAL_ACTION\$", "{$protocol}{$ourhostname}/", $htmltext);
1648
	$htmltext = str_replace("#PORTAL_ACTION#", "{$protocol}{$ourhostname}/", $htmltext);
1649 ac631bba lgcosta
1650 b4792bf8 Ermal
	$htmltext = str_replace("\$PORTAL_ZONE\$", htmlspecialchars($cpzone), $htmltext);
1651 ac631bba lgcosta
	$htmltext = str_replace("\$PORTAL_REDIRURL\$", htmlspecialchars($redirurl), $htmltext);
1652
	$htmltext = str_replace("\$PORTAL_MESSAGE\$", htmlspecialchars($message), $htmltext);
1653
	$htmltext = str_replace("\$CLIENT_MAC\$", htmlspecialchars($clientmac), $htmltext);
1654
	$htmltext = str_replace("\$CLIENT_IP\$", htmlspecialchars($clientip), $htmltext);
1655
1656
	// Special handling case for captive portal master page so that it can be ran 
1657
	// through the PHP interpreter using the include method above.  We convert the
1658
	// $VARIABLE$ case to #VARIABLE# in /etc/inc/captiveportal.inc before writing out.
1659 b4792bf8 Ermal
	$htmltext = str_replace("#PORTAL_ZONE#", htmlspecialchars($cpzone), $htmltext);
1660 ac631bba lgcosta
	$htmltext = str_replace("#PORTAL_REDIRURL#", htmlspecialchars($redirurl), $htmltext);
1661
	$htmltext = str_replace("#PORTAL_MESSAGE#", htmlspecialchars($message), $htmltext);
1662
	$htmltext = str_replace("#CLIENT_MAC#", htmlspecialchars($clientmac), $htmltext);
1663
	$htmltext = str_replace("#CLIENT_IP#", htmlspecialchars($clientip), $htmltext);
1664
	$htmltext = str_replace("#USERNAME#", htmlspecialchars($username), $htmltext);
1665
	$htmltext = str_replace("#PASSWORD#", htmlspecialchars($password), $htmltext);
1666
1667 87e7fdea bcyrill
	echo $htmltext;
1668 ac631bba lgcosta
}
1669
1670
function portal_mac_radius($clientmac,$clientip) {
1671 87e7fdea bcyrill
	global $config, $cpzone;
1672 ac631bba lgcosta
1673 87e7fdea bcyrill
	$radmac_secret = $config['captiveportal'][$cpzone]['radmac_secret'];
1674 ac631bba lgcosta
1675 87e7fdea bcyrill
	/* authentication against the radius server */
1676
	$username = mac_format($clientmac);
1677
	$auth_list = radius($username,$radmac_secret,$clientip,$clientmac,"MACHINE LOGIN");
1678
	if ($auth_list['auth_val'] == 2)
1679
		return TRUE;
1680 ac631bba lgcosta
1681 87e7fdea bcyrill
	if (!empty($auth_list['url_redirection']))
1682
		portal_reply_page($auth_list['url_redirection'], "redir");
1683
1684
	return FALSE;
1685 ac631bba lgcosta
}
1686
1687 aec0f2fd Ermal
function captiveportal_reapply_attributes($cpentry, $attributes) {
1688 2ec063f9 Warren Baker
	global $config, $cpzone, $g;
1689 87e7fdea bcyrill
1690 10b9dfcf Ermal
	$dwfaultbw_up = isset($config['captiveportal'][$cpzone]['bwdefaultup']) ? $config['captiveportal'][$cpzone]['bwdefaultup'] : 0;
1691
	$dwfaultbw_down = isset($config['captiveportal'][$cpzone]['bwdefaultdn']) ? $config['captiveportal'][$cpzone]['bwdefaultdn'] : 0;
1692 87e7fdea bcyrill
	$bw_up = isset($attributes['bw_up']) ? round(intval($attributes['bw_up'])/1000, 2) : $dwfaultbw_up;
1693
	$bw_down = isset($attributes['bw_down']) ? round(intval($attributes['bw_down'])/1000, 2) : $dwfaultbw_down;
1694 5705c60a Renato Botelho
	$bw_up_pipeno = $cpentry[1];
1695
	$bw_down_pipeno = $cpentry[1]+1;
1696 aec0f2fd Ermal
1697 dcf68058 Ermal
	pfSense_pipe_action("pipe {$bw_up_pipeno} config bw {$bw_up}Kbit/s queue 100 buckets 16");
1698
	pfSense_pipe_action("pipe {$bw_down_pipeno} config bw {$bw_down}Kbit/s queue 100 buckets 16");
1699 10b9dfcf Ermal
	//captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], "RADIUS_BANDWIDTH_REAPPLY", "{$bw_up}/{$bw_down}");
1700 aec0f2fd Ermal
1701 87e7fdea bcyrill
	unset($bw_up_pipeno, $bw_down_pipeno, $bw_up, $bw_down);
1702 aec0f2fd Ermal
}
1703
1704 aea56408 Ermal
function portal_allow($clientip,$clientmac,$username,$password = null, $attributes = null, $pipeno = null, $radiusctx = null)  {
1705 b4792bf8 Ermal
	global $redirurl, $g, $config, $type, $passthrumac, $_POST, $cpzone;
1706 ac631bba lgcosta
1707
	// Ensure we create an array if we are missing attributes
1708
	if (!is_array($attributes))
1709
		$attributes = array();
1710
1711 26ee5aaf Ermal
	unset($sessionid);
1712 ac631bba lgcosta
1713 006802ab Ermal
	/* Do not allow concurrent login execution. */
1714 b4792bf8 Ermal
	$cpdblck = lock("captiveportaldb{$cpzone}", LOCK_EX);
1715 006802ab Ermal
1716 ac631bba lgcosta
	if ($attributes['voucher'])
1717
		$remaining_time = $attributes['session_timeout'];
1718
1719
	$writecfg = false;
1720
	/* Find an existing session */
1721 b4792bf8 Ermal
	if ((isset($config['captiveportal'][$cpzone]['noconcurrentlogins'])) && $passthrumac) {
1722
		if (isset($config['captiveportal'][$cpzone]['passthrumacadd'])) {
1723 ac631bba lgcosta
			$mac = captiveportal_passthrumac_findbyname($username);
1724
			if (!empty($mac)) {
1725
				if ($_POST['replacemacpassthru']) {
1726 b4792bf8 Ermal
					foreach ($config['captiveportal'][$cpzone]['passthrumac'] as $idx => $macent) {
1727 ac631bba lgcosta
						if ($macent['mac'] == $mac['mac']) {
1728
							$macrules = "";
1729
							$ruleno = captiveportal_get_ipfw_passthru_ruleno($mac['mac']);
1730 aea56408 Ermal
							$pipeno = captiveportal_get_dn_passthru_ruleno($mac['mac']);
1731 87e7fdea bcyrill
							if ($ruleno) {
1732 aea56408 Ermal
								captiveportal_free_ipfw_ruleno($ruleno);
1733 87e7fdea bcyrill
								$macrules .= "delete {$ruleno}\n";
1734 ac631bba lgcosta
								++$ruleno;
1735 87e7fdea bcyrill
								$macrules .= "delete {$ruleno}\n";
1736
							}
1737 aea56408 Ermal
							if ($pipeno) {
1738
								captiveportal_free_dn_ruleno($pipeno);
1739 87e7fdea bcyrill
								$macrules .= "pipe delete {$pipeno}\n";
1740 aea56408 Ermal
								++$pipeno;
1741 87e7fdea bcyrill
								$macrules .= "pipe delete {$pipeno}\n";
1742 aea56408 Ermal
							}
1743 b4792bf8 Ermal
							unset($config['captiveportal'][$cpzone]['passthrumac'][$idx]);
1744 ac631bba lgcosta
							$mac['mac'] = $clientmac;
1745 b4792bf8 Ermal
							$config['captiveportal'][$cpzone]['passthrumac'][] = $mac;
1746 ac631bba lgcosta
							$macrules .= captiveportal_passthrumac_configure_entry($mac);
1747 b4792bf8 Ermal
							file_put_contents("{$g['tmp_path']}/macentry_{$cpzone}.rules.tmp", $macrules);
1748 287f7e26 Ermal
							mwexec("/sbin/ipfw -x {$cpzone} -q {$g['tmp_path']}/macentry_{$cpzone}.rules.tmp");
1749 ac631bba lgcosta
							$writecfg = true;
1750
							$sessionid = true;
1751
							break;
1752
						}
1753
					}
1754 87e7fdea bcyrill
				} else {
1755 ac631bba lgcosta
					portal_reply_page($redirurl, "error", "Username: {$username} is already authenticated using another MAC address.",
1756
						$clientmac, $clientip, $username, $password);
1757 ee79fcda Ermal
					unlock($cpdblck);
1758 aea56408 Ermal
					return;
1759 ac631bba lgcosta
				}
1760
			}
1761
		}
1762
	}
1763
1764 26ee5aaf Ermal
	/* read in client database */
1765
	$query = "WHERE ip = '{$clientip}'";
1766
	$tmpusername = strtolower($username);
1767 4586abb7 bcyrill
	if (isset($config['captiveportal'][$cpzone]['noconcurrentlogins']))
1768 26ee5aaf Ermal
		$query .= " OR (username != 'unauthenticated' AND lower(username) = '{$tmpusername}')";
1769
	$cpdb = captiveportal_read_db($query);
1770
1771 ebc0e4b6 Ermal
	/* Snapshot the timestamp */
1772 b09c2d86 Ermal
	$allow_time = time();
1773 26ee5aaf Ermal
	$radiusservers = captiveportal_get_radius_servers();
1774
	$unsetindexes = array();
1775 ebc0e4b6 Ermal
	if (is_null($radiusctx))
1776
		$radiusctx = 'first';
1777 26ee5aaf Ermal
1778
	foreach ($cpdb as $cpentry) {
1779 5705c60a Renato Botelho
		if (empty($cpentry[10]))
1780
			$cpentry[10] = 'first';
1781 ac631bba lgcosta
		/* on the same ip */
1782 5705c60a Renato Botelho
		if ($cpentry[2] == $clientip) {
1783
			if (isset($config['captiveportal'][$cpzone]['nomacfilter']) || $cpentry[3] == $clientmac)
1784
				captiveportal_logportalauth($cpentry[4],$cpentry[3],$cpentry[2],"CONCURRENT LOGIN - REUSING OLD SESSION");
1785 2890cae5 Ermal
			else
1786 5705c60a Renato Botelho
				captiveportal_logportalauth($cpentry[4],$cpentry[3],$cpentry[2],"CONCURRENT LOGIN - REUSING IP {$cpentry[2]} WITH DIFFERENT MAC ADDRESS {$cpentry[3]}");
1787
			$sessionid = $cpentry[5];
1788 ac631bba lgcosta
			break;
1789
		}
1790 5705c60a Renato Botelho
		elseif (($attributes['voucher']) && ($username != 'unauthenticated') && ($cpentry[4] == $username)) {
1791 ac631bba lgcosta
			// user logged in with an active voucher. Check for how long and calculate 
1792
			// how much time we can give him (voucher credit - used time)
1793 5705c60a Renato Botelho
			$remaining_time = $cpentry[0] + $cpentry[7] - $allow_time;
1794
			if ($remaining_time < 0)    // just in case. 
1795 ac631bba lgcosta
				$remaining_time = 0;
1796
1797
			/* This user was already logged in so we disconnect the old one */
1798 5705c60a Renato Botelho
			captiveportal_disconnect($cpentry,$radiusservers[$cpentry[10]],13);
1799
			captiveportal_logportalauth($cpentry[4],$cpentry[3],$cpentry[2],"CONCURRENT LOGIN - TERMINATING OLD SESSION");
1800
			$unsetindexes[] = $cpentry[5];
1801 ac631bba lgcosta
			break;
1802
		}
1803 b4792bf8 Ermal
		elseif ((isset($config['captiveportal'][$cpzone]['noconcurrentlogins'])) && ($username != 'unauthenticated')) {
1804 ac631bba lgcosta
			/* on the same username */
1805 5705c60a Renato Botelho
			if (strcasecmp($cpentry[4], $username) == 0) {
1806 ac631bba lgcosta
				/* This user was already logged in so we disconnect the old one */
1807 5705c60a Renato Botelho
				captiveportal_disconnect($cpentry,$radiusservers[$cpentry[10]],13);
1808
				captiveportal_logportalauth($cpentry[4],$cpentry[3],$cpentry[2],"CONCURRENT LOGIN - TERMINATING OLD SESSION");
1809
				$unsetindexes[] = $cpentry[5];
1810 ac631bba lgcosta
				break;
1811
			}
1812
		}
1813
	}
1814 f32eae2d Ermal
	unset($cpdb);
1815 ac631bba lgcosta
1816 26ee5aaf Ermal
	if (!empty($unsetindexes))
1817
		captiveportal_remove_entries($unsetindexes);
1818
1819 ac631bba lgcosta
	if ($attributes['voucher'] && $remaining_time <= 0)
1820
		return 0;       // voucher already used and no time left
1821
1822
	if (!isset($sessionid)) {
1823
		/* generate unique session ID */
1824
		$tod = gettimeofday();
1825
		$sessionid = substr(md5(mt_rand() . $tod['sec'] . $tod['usec'] . $clientip . $clientmac), 0, 16);
1826
1827
		if ($passthrumac) {
1828
			$mac = array();
1829
			$mac['mac'] = $clientmac;
1830 522f1cc7 Ermal
			$mac['ip'] = $clientip; /* Used only for logging */
1831
			if (isset($config['captiveportal'][$cpzone]['passthrumacaddusername'])) {
1832 ac631bba lgcosta
				$mac['username'] = $username;
1833 522f1cc7 Ermal
				if ($attributes['voucher'])
1834
					$mac['logintype'] = "voucher";
1835
			}
1836 ac631bba lgcosta
			$mac['descr'] =  "Auto added pass-through MAC for user {$username}";
1837
			if (!empty($bw_up))
1838
				$mac['bw_up'] = $bw_up;
1839
			if (!empty($bw_down))
1840
				$mac['bw_down'] = $bw_down;
1841 b4792bf8 Ermal
			if (!is_array($config['captiveportal'][$cpzone]['passthrumac']))
1842
				$config['captiveportal'][$cpzone]['passthrumac'] = array();
1843
			$config['captiveportal'][$cpzone]['passthrumac'][] = $mac;
1844 006802ab Ermal
			unlock($cpdblck);
1845 ac631bba lgcosta
			$macrules = captiveportal_passthrumac_configure_entry($mac);
1846 b4792bf8 Ermal
			file_put_contents("{$g['tmp_path']}/macentry_{$cpzone}.rules.tmp", $macrules);
1847 287f7e26 Ermal
			mwexec("/sbin/ipfw -x {$cpzone}-q {$g['tmp_path']}/macentry_{$cpzone}.rules.tmp");
1848 ac631bba lgcosta
			$writecfg = true;
1849
		} else {
1850 aea56408 Ermal
			/* See if a pipeno is passed, if not start sessions because this means there isn't one atm */
1851
			if (is_null($pipeno))
1852
				$pipeno = captiveportal_get_next_dn_ruleno();
1853
1854
			/* if the pool is empty, return appropriate message and exit */
1855
			if (is_null($pipeno)) {
1856
				portal_reply_page($redirurl, "error", "System reached maximum login capacity");
1857
				log_error("WARNING!  Captive portal has reached maximum login capacity");
1858
				unlock($cpdblck);
1859
				return;
1860
			}
1861
1862 553abb0d Ermal
			$dwfaultbw_up = isset($config['captiveportal'][$cpzone]['bwdefaultup']) ? $config['captiveportal'][$cpzone]['bwdefaultup'] : 0;
1863
			$dwfaultbw_down = isset($config['captiveportal'][$cpzone]['bwdefaultdn']) ? $config['captiveportal'][$cpzone]['bwdefaultdn'] : 0;
1864
			$bw_up = isset($attributes['bw_up']) ? round(intval($attributes['bw_up'])/1000, 2) : $dwfaultbw_up;
1865
			$bw_down = isset($attributes['bw_down']) ? round(intval($attributes['bw_down'])/1000, 2) : $dwfaultbw_down;
1866
1867 aea56408 Ermal
			$bw_up_pipeno = $pipeno;
1868
			$bw_down_pipeno = $pipeno + 1;
1869 10b9dfcf Ermal
			//$bw_up /= 1000; // Scale to Kbit/s
1870 dcf68058 Ermal
			pfSense_pipe_action("pipe {$bw_up_pipeno} config bw {$bw_up}Kbit/s queue 100 buckets 16");
1871
			pfSense_pipe_action("pipe {$bw_down_pipeno} config bw {$bw_down}Kbit/s queue 100 buckets 16");
1872 ac631bba lgcosta
1873 60884727 bcyrill
			$clientsn = (is_ipaddrv6($clientip)) ? 128 : 32;
1874 10b9dfcf Ermal
			if (!isset($config['captiveportal'][$cpzone]['nomacfilter']))
1875 60884727 bcyrill
				pfSense_ipfw_Tableaction($cpzone, IP_FW_TABLE_ADD, 1, $clientip, $clientsn, $clientmac, $bw_up_pipeno);
1876 10b9dfcf Ermal
			else
1877 60884727 bcyrill
				pfSense_ipfw_Tableaction($cpzone, IP_FW_TABLE_ADD, 1, $clientip, $clientsn, NULL, $bw_up_pipeno);
1878 10b9dfcf Ermal
1879
			if (!isset($config['captiveportal'][$cpzone]['nomacfilter']))
1880 287f7e26 Ermal
				pfSense_ipfw_Tableaction($cpzone, IP_FW_TABLE_ADD, 2, $clientip, $clientsn, $clientmac, $bw_down_pipeno);
1881 10b9dfcf Ermal
			else
1882 287f7e26 Ermal
				pfSense_ipfw_Tableaction($cpzone, IP_FW_TABLE_ADD, 2, $clientip, $clientsn, NULL, $bw_down_pipeno);
1883 ac631bba lgcosta
1884
			if ($attributes['voucher'])
1885
				$attributes['session_timeout'] = $remaining_time;
1886 1974c2d6 bcyrill
			
1887
			/* handle empty attributes */
1888
			$session_timeout = (!empty($attributes['session_timeout'])) ? $attributes['session_timeout'] : 'NULL';
1889
			$idle_timeout = (!empty($attributes['idle_timeout'])) ? $attributes['idle_timeout'] : 'NULL';
1890
			$session_terminate_time = (!empty($attributes['session_terminate_time'])) ? $attributes['session_terminate_time'] : 'NULL';
1891 338c0941 Ermal
			$interim_interval = (!empty($attributes['interim_interval'])) ? $attributes['interim_interval'] : 'NULL';
1892 1974c2d6 bcyrill
1893
			/* escape username */
1894
			$safe_username = sqlite_escape_string($username);
1895 ac631bba lgcosta
1896
			/* encode password in Base64 just in case it contains commas */
1897
			$bpassword = base64_encode($password);
1898 5705c60a Renato Botelho
			$insertquery  = "INSERT INTO captiveportal (allow_time, pipeno, ip, mac, username, sessionid, bpassword, session_timeout, idle_timeout, session_terminate_time, interim_interval) ";
1899 1974c2d6 bcyrill
			$insertquery .= "VALUES ({$allow_time}, {$pipeno}, '{$clientip}', '{$clientmac}', '{$safe_username}', '{$sessionid}', '{$bpassword}', ";
1900 5705c60a Renato Botelho
			$insertquery .= "{$session_timeout}, {$idle_timeout}, {$session_terminate_time}, {$interim_interval})";
1901 ac631bba lgcosta
1902 26ee5aaf Ermal
			/* store information to database */
1903
			captiveportal_write_db($insertquery);
1904 006802ab Ermal
			unlock($cpdblck);
1905
1906 ebc0e4b6 Ermal
			if (isset($config['captiveportal'][$cpzone]['radacct_enable']) && !empty($radiusservers[$radiusctx])) {
1907 87e7fdea bcyrill
				$acct_val = RADIUS_ACCOUNTING_START($pipeno, $username, $sessionid, $radiusservers[$radiusctx], $clientip, $clientmac);
1908 ac631bba lgcosta
				if ($acct_val == 1)
1909
					captiveportal_logportalauth($username,$clientmac,$clientip,$type,"RADIUS ACCOUNTING FAILED");
1910
			}
1911
		}
1912 006802ab Ermal
	} else
1913
		unlock($cpdblck);
1914 ac631bba lgcosta
1915
	if ($writecfg == true)
1916
		write_config();
1917
1918
	/* redirect user to desired destination */
1919
	if (!empty($attributes['url_redirection']))
1920
		$my_redirurl = $attributes['url_redirection'];
1921 b4792bf8 Ermal
	else if (!empty($config['captiveportal'][$cpzone]['redirurl']))
1922
		$my_redirurl = $config['captiveportal'][$cpzone]['redirurl'];
1923 ac631bba lgcosta
	else
1924
		$my_redirurl = $redirurl;
1925
1926 b4792bf8 Ermal
	if(isset($config['captiveportal'][$cpzone]['logoutwin_enable']) && !$passthrumac) {
1927 de132ae3 bcyrill
		$ourhostname = portal_hostname_from_client_ip($clientip);
1928
		$protocol = (isset($config['captiveportal'][$cpzone]['httpslogin'])) ? 'https://' : 'http://';
1929
		$logouturl = "{$protocol}{$ourhostname}/";
1930 ac631bba lgcosta
1931
		if (isset($attributes['reply_message']))
1932
			$message = $attributes['reply_message'];
1933
		else
1934
			$message = 0;
1935
1936 b4792bf8 Ermal
		include("{$g['varetc_path']}/captiveportal-{$cpzone}-logout.html");
1937 ac631bba lgcosta
1938
	} else {
1939
		header("Location: " . $my_redirurl);
1940
	}
1941
1942
	return $sessionid;
1943
}
1944
1945
1946
/*
1947
 * Used for when pass-through credits are enabled.
1948
 * Returns true when there was at least one free login to deduct for the MAC.
1949
 * Expired entries are removed as they are seen.
1950
 * Active entries are updated according to the configuration.
1951
 */
1952
function portal_consume_passthrough_credit($clientmac) {
1953 b4792bf8 Ermal
	global $config, $cpzone;
1954 ac631bba lgcosta
1955 b4792bf8 Ermal
	if (!empty($config['captiveportal'][$cpzone]['freelogins_count']) && is_numeric($config['captiveportal'][$cpzone]['freelogins_count']))
1956
		$freeloginscount = $config['captiveportal'][$cpzone]['freelogins_count'];
1957 ac631bba lgcosta
	else
1958
		return false;
1959
1960 b4792bf8 Ermal
	if (!empty($config['captiveportal'][$cpzone]['freelogins_resettimeout']) && is_numeric($config['captiveportal'][$cpzone]['freelogins_resettimeout']))
1961
		$resettimeout = $config['captiveportal'][$cpzone]['freelogins_resettimeout'];
1962 ac631bba lgcosta
	else
1963
		return false;
1964
1965 17e7a243 Scott Ullrich
	if ($freeloginscount < 1 || $resettimeout <= 0 || !$clientmac)
1966 ac631bba lgcosta
		return false;
1967
1968 b4792bf8 Ermal
	$updatetimeouts = isset($config['captiveportal'][$cpzone]['freelogins_updatetimeouts']);
1969 ac631bba lgcosta
1970
	/*
1971
	 * Read database of used MACs.  Lines are a comma-separated list
1972
	 * of the time, MAC, then the count of pass-through credits remaining.
1973
	 */
1974
	$usedmacs = captiveportal_read_usedmacs_db();
1975
1976
	$currenttime = time();
1977
	$found = false;
1978
	foreach ($usedmacs as $key => $usedmac) {
1979
		$usedmac = explode(",", $usedmac);
1980
1981
		if ($usedmac[1] == $clientmac) {
1982
			if ($usedmac[0] + ($resettimeout * 3600) > $currenttime) {
1983
				if ($usedmac[2] < 1) {
1984
					if ($updatetimeouts) {
1985
						$usedmac[0] = $currenttime;
1986
						unset($usedmacs[$key]);
1987
						$usedmacs[] = implode(",", $usedmac);
1988
						captiveportal_write_usedmacs_db($usedmacs);
1989
					}
1990
1991
					return false;
1992
				} else {
1993
					$usedmac[2] -= 1;
1994
					$usedmacs[$key] = implode(",", $usedmac);
1995
				}
1996
1997
				$found = true;
1998
			} else
1999
				unset($usedmacs[$key]);
2000
2001
			break;
2002
		} else if ($usedmac[0] + ($resettimeout * 3600) <= $currenttime)
2003
				unset($usedmacs[$key]);
2004
	}
2005
2006
	if (!$found) {
2007
		$usedmac = array($currenttime, $clientmac, $freeloginscount - 1);
2008
		$usedmacs[] = implode(",", $usedmac);
2009
	}
2010
2011
	captiveportal_write_usedmacs_db($usedmacs);
2012
	return true;
2013
}
2014
2015
function captiveportal_read_usedmacs_db() {
2016 b4792bf8 Ermal
	global $g, $cpzone;
2017 ac631bba lgcosta
2018 b4792bf8 Ermal
	$cpumaclck = lock("captiveusedmacs{$cpzone}");
2019
	if (file_exists("{$g['vardb_path']}/captiveportal_usedmacs_{$cpzone}.db")) {
2020
		$usedmacs = file("{$g['vardb_path']}/captiveportal_usedmacs_{$cpzone}.db", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
2021 da666ca8 Scott Ullrich
		if (!$usedmacs)
2022 ac631bba lgcosta
			$usedmacs = array();
2023
	} else
2024
		$usedmacs = array();
2025
2026
	unlock($cpumaclck);
2027
	return $usedmacs;
2028
}
2029
2030
function captiveportal_write_usedmacs_db($usedmacs) {
2031 b4792bf8 Ermal
	global $g, $cpzone;
2032 ac631bba lgcosta
2033 b4792bf8 Ermal
	$cpumaclck = lock("captiveusedmacs{$cpzone}", LOCK_EX);
2034
	@file_put_contents("{$g['vardb_path']}/captiveportal_usedmacs_{$cpzone}.db", implode("\n", $usedmacs));
2035 ac631bba lgcosta
	unlock($cpumaclck);
2036
}
2037
2038 62f20eab Michael Newton
function captiveportal_send_server_accounting($off = false) {
2039
	global $cpzone, $config;
2040
2041
	if (!isset($config['captiveportal'][$cpzone]['radacct_enable'])) {
2042
		return;
2043
	}
2044
	if ($off) {
2045
		$racct = new Auth_RADIUS_Acct_Off;
2046
	} else {
2047
		$racct = new Auth_RADIUS_Acct_On;
2048
	}
2049
	$radiusservers = captiveportal_get_radius_servers();
2050
	if (empty($radiusservers)) {
2051
		return;
2052
	}
2053
	foreach ($radiusservers['first'] as $radsrv) {
2054
		// Add a new server to our instance
2055
		$racct->addServer($radsrv['ipaddr'], $radsrv['acctport'], $radsrv['key']);
2056
	}
2057
	if (PEAR::isError($racct->start())) {
2058
		$retvalue['acct_val'] = 1;
2059
		$retvalue['error'] = $racct->getMessage();
2060
2061
		// If we encounter an error immediately stop this function and go back
2062
		$racct->close();
2063
		return $retvalue;
2064
	}
2065
	// Send request
2066
	$result = $racct->send();
2067
	// Evaluation of the response
2068
	// 5 -> Accounting-Response
2069
	// See RFC2866 for this.
2070
	if (PEAR::isError($result)) {
2071
		$retvalue['acct_val'] = 1;
2072
		$retvalue['error'] = $result->getMessage();
2073
	} else if ($result === true) {
2074
		$retvalue['acct_val'] = 5 ;
2075
	} else {
2076
		$retvalue['acct_val'] = 1 ;
2077
	}
2078
2079
	$racct->close();
2080
	return $retvalue;
2081
}
2082 64c0462b Ermal
?>