Project

General

Profile

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