Project

General

Profile

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