Project

General

Profile

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