Project

General

Profile

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