Project

General

Profile

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