Project

General

Profile

Download (13.8 KB) Statistics
| Branch: | Tag: | Revision:
1 ec920231 Scott Ullrich
<?php 
2 5b237745 Scott Ullrich
/*
3 6e865a74 Scott Ullrich
	index.php
4
	part of m0n0wall (http://m0n0.ch/wall)
5
	
6
	Copyright (C) 2003-2005 Manuel Kasper <mk@neon1.net>.
7 5b237745 Scott Ullrich
	All rights reserved.
8 ec920231 Scott Ullrich
	
9 5b237745 Scott Ullrich
	Redistribution and use in source and binary forms, with or without
10
	modification, are permitted provided that the following conditions are met:
11 ec920231 Scott Ullrich
	
12 5b237745 Scott Ullrich
	1. Redistributions of source code must retain the above copyright notice,
13
	   this list of conditions and the following disclaimer.
14 ec920231 Scott Ullrich
	
15 5b237745 Scott Ullrich
	2. Redistributions in binary form must reproduce the above copyright
16
	   notice, this list of conditions and the following disclaimer in the
17
	   documentation and/or other materials provided with the distribution.
18 ec920231 Scott Ullrich
	
19 5b237745 Scott Ullrich
	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
20
	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
21
	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22
	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
23
	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28
	POSSIBILITY OF SUCH DAMAGE.
29
*/
30
31
require("globals.inc");
32
require("util.inc");
33
require("config.inc");
34 6e865a74 Scott Ullrich
require("radius_authentication.inc");
35
require("radius_accounting.inc");
36 5b237745 Scott Ullrich
37
header("Expires: 0");
38
header("Cache-Control: no-store, no-cache, must-revalidate");
39
header("Cache-Control: post-check=0, pre-check=0", false);
40
header("Pragma: no-cache");
41
42
$orig_host = $_ENV['HTTP_HOST'];
43 eb0f441c Scott Ullrich
$orig_request = $_GET['redirurl'];
44 5b237745 Scott Ullrich
$lockfile = "{$g['varrun_path']}/captiveportal.lock";
45 6fa4bdc6 Scott Ullrich
$clientip = $_SERVER['REMOTE_ADDR'];
46 5b237745 Scott Ullrich
47
if (!$clientip) {
48
	/* not good - bail out */
49
	exit;
50
}
51
52
/* find MAC address for client */
53
$clientmac = arp_get_mac_by_ip($clientip);
54
if (!$clientmac && !isset($config['captiveportal']['nomacfilter'])) {
55
	/* unable to find MAC address - shouldn't happen! - bail out */
56
	exit;
57
}
58
59 6e865a74 Scott Ullrich
if ($clientmac && portal_mac_fixed($clientmac)) {
60
	/* punch hole in ipfw for pass thru mac addresses */
61 f8dea008 Scott Ullrich
	portal_allow($clientip, $clientmac, "unauthenticated");
62 5b237745 Scott Ullrich
63
} else if ($_POST['accept'] && file_exists("{$g['vardb_path']}/captiveportal_radius.db")) {
64
65
	/* authenticate against radius server */
66
	$radiusservers = captiveportal_get_radius_servers();
67 ec920231 Scott Ullrich
	
68 5b237745 Scott Ullrich
	if ($_POST['auth_user'] && $_POST['auth_pass']) {
69
		$auth_val = RADIUS_AUTHENTICATION($_POST['auth_user'],
70
										  $_POST['auth_pass'],
71
							  			  $radiusservers[0]['ipaddr'],
72
							  			  $radiusservers[0]['port'],
73
							  			  $radiusservers[0]['key']);
74
		if ($auth_val == 2) {
75 6e865a74 Scott Ullrich
			captiveportal_logportalauth($_POST['auth_user'],$clientmac,$clientip,"LOGIN");
76
			$sessionid = portal_allow($clientip, $clientmac, $_POST['auth_user'], $_POST['auth_pass']);
77 5b237745 Scott Ullrich
			if (isset($config['captiveportal']['radacct_enable']) && isset($radiusservers[0])) {
78
				$auth_val = RADIUS_ACCOUNTING_START($_POST['auth_user'],
79
													$sessionid,
80
													$radiusservers[0]['ipaddr'],
81
													$radiusservers[0]['acctport'],
82 7faeda46 Scott Ullrich
													$radiusservers[0]['key'],
83
													$clientip);
84 5b237745 Scott Ullrich
			}
85
		} else {
86 6e865a74 Scott Ullrich
			captiveportal_logportalauth($_POST['auth_user'],$clientmac,$clientip,"FAILURE");
87 5b237745 Scott Ullrich
			readfile("{$g['varetc_path']}/captiveportal-error.html");
88
		}
89
	} else {
90
		readfile("{$g['varetc_path']}/captiveportal-error.html");
91
	}
92 6e865a74 Scott Ullrich
	
93
} else if ($_POST['accept'] && $config['captiveportal']['auth_method'] == "local") {
94 5b237745 Scott Ullrich
95 7faeda46 Scott Ullrich
	//check against local usermanager
96 6e865a74 Scott Ullrich
	$userdb = &$config['captiveportal']['user'];
97
98
	$loginok = false;
99
100 7faeda46 Scott Ullrich
	//erase expired accounts
101 6e865a74 Scott Ullrich
	if (is_array($userdb)) {
102
		$moddb = false;
103
		for ($i = 0; $i < count($userdb); $i++) {
104
			if ($userdb[$i]['expirationdate'] && (strtotime("-1 day") > strtotime($userdb[$i]['expirationdate']))) {
105
				unset($userdb[$i]);
106
				$moddb = true;
107
			}
108
		}
109
		if ($moddb)
110
			write_config();
111
			
112
		$userdb = &$config['captiveportal']['user'];
113
		
114
		for ($i = 0; $i < count($userdb); $i++) {
115
			if (($userdb[$i]['name'] == $_POST['auth_user']) && ($userdb[$i]['password'] == md5($_POST['auth_pass']))) {
116
				$loginok = true;
117
				break;
118
			}
119
		}
120 7faeda46 Scott Ullrich
	}
121 6e865a74 Scott Ullrich
122
	if ($loginok){
123
		captiveportal_logportalauth($_POST['auth_user'],$clientmac,$clientip,"LOGIN");
124
		portal_allow($clientip, $clientmac,$_POST['auth_user'],0,0);
125 7faeda46 Scott Ullrich
	} else {
126 6e865a74 Scott Ullrich
		captiveportal_logportalauth($_POST['auth_user'],$clientmac,$clientip,"FAILURE");
127 7faeda46 Scott Ullrich
		readfile("{$g['varetc_path']}/captiveportal-error.html");
128
	}
129 5b237745 Scott Ullrich
} else if ($_POST['accept'] && $clientip) {
130 f8dea008 Scott Ullrich
	portal_allow($clientip, $clientmac, "unauthenticated");
131 5b237745 Scott Ullrich
} else if ($_POST['logout_id']) {
132
	disconnect_client($_POST['logout_id']);
133
	echo <<<EOD
134
<HTML>
135
<HEAD><TITLE>Disconnecting...</TITLE></HEAD>
136
<BODY BGCOLOR="#435370">
137
<SPAN STYLE="color: #ffffff; font-family: Tahoma, Verdana, Arial, Helvetica, sans-serif; font-size: 11px;">
138 f0a12c87 Scott Ullrich
<B>You've been disconnected.</B>
139 5b237745 Scott Ullrich
</SPAN>
140
<SCRIPT LANGUAGE="JavaScript">
141
<!--
142
setTimeout('window.close();',5000) ;
143
-->
144
</SCRIPT>
145
</BODY>
146
</HTML>
147
148
EOD;
149
} else if (($_ENV['SERVER_PORT'] != 8001) && isset($config['captiveportal']['httpslogin'])) {
150
	/* redirect to HTTPS login page */
151
	header("Location: https://{$config['captiveportal']['httpsname']}:8001/?redirurl=" . urlencode("http://{$orig_host}{$orig_request}"));
152
} else {
153
	/* display captive portal page */
154
	$htmltext = file_get_contents("{$g['varetc_path']}/captiveportal.html");
155 ec920231 Scott Ullrich
	
156 5b237745 Scott Ullrich
	/* substitute variables */
157
	if (isset($config['captiveportal']['httpslogin']))
158
		$htmltext = str_replace("\$PORTAL_ACTION\$", "https://{$config['captiveportal']['httpsname']}:8001/", $htmltext);
159
	else
160 6e865a74 Scott Ullrich
		$htmltext = str_replace("\$PORTAL_ACTION\$", "http://{$config['interfaces'][$config['captiveportal']['interface']]['ipaddr']}:8000/", $htmltext);
161 ec920231 Scott Ullrich
	
162 5b237745 Scott Ullrich
	if (preg_match("/redirurl=(.*)/", $orig_request, $matches))
163
		$redirurl = urldecode($matches[1]);
164
	else
165
		$redirurl = "http://{$orig_host}{$orig_request}";
166
	$htmltext = str_replace("\$PORTAL_REDIRURL\$", htmlspecialchars($redirurl), $htmltext);
167 08d82407 Scott Ullrich
		
168 5b237745 Scott Ullrich
	echo $htmltext;
169
}
170
171 eb0f441c Scott Ullrich
172 5b237745 Scott Ullrich
exit;
173
174
function portal_mac_fixed($clientmac) {
175
	global $g ;
176 ec920231 Scott Ullrich
	
177 5b237745 Scott Ullrich
	/* open captive portal mac db */
178
	if (file_exists("{$g['vardb_path']}/captiveportal_mac.db")) {
179
		$fd = @fopen("{$g['vardb_path']}/captiveportal_mac.db","r") ;
180
		if (!$fd) {
181
			return FALSE;
182
		}
183
		while (!feof($fd)) {
184
			$mac = trim(fgets($fd)) ;
185
			if(strcasecmp($clientmac, $mac) == 0) {
186
				fclose($fd) ;
187
				return TRUE ;
188
			}
189
		}
190
		fclose($fd) ;
191
	}
192
	return FALSE ;
193 ec920231 Scott Ullrich
}	
194 5b237745 Scott Ullrich
195 6e865a74 Scott Ullrich
function portal_allow($clientip,$clientmac,$clientuser,$password = "") {
196 5b237745 Scott Ullrich
197
	global $orig_host, $orig_request, $g, $config;
198
199
	/* user has accepted AUP - let him in */
200
	portal_lock();
201 6e865a74 Scott Ullrich
	
202
	/* get next ipfw rule number */
203
	if (file_exists("{$g['vardb_path']}/captiveportal.nextrule"))
204
		$ruleno = trim(file_get_contents("{$g['vardb_path']}/captiveportal.nextrule"));
205
	if (!$ruleno)
206
		$ruleno = 10000;	/* first rule number */
207 5b237745 Scott Ullrich
208 6e865a74 Scott Ullrich
	$saved_ruleno = $ruleno;
209 ec920231 Scott Ullrich
	
210 5b237745 Scott Ullrich
	/* generate unique session ID */
211
	$tod = gettimeofday();
212
	$sessionid = substr(md5(mt_rand() . $tod['sec'] . $tod['usec'] . $clientip . $clientmac), 0, 16);
213 6e865a74 Scott Ullrich
	
214
	/* add ipfw rules for layer 3 */
215
	exec("/sbin/ipfw add $ruleno set 2 skipto 50000 ip from $clientip to any in");
216
	exec("/sbin/ipfw add $ruleno set 2 skipto 50000 ip from any to $clientip out");
217
	
218
	/* add ipfw rules for layer 2 */
219
	if (!isset($config['captiveportal']['nomacfilter'])) {
220
		$l2ruleno = $ruleno + 10000;
221
		exec("/sbin/ipfw add $l2ruleno set 3 deny all from $clientip to any not MAC any $clientmac layer2 in");
222
		exec("/sbin/ipfw add $l2ruleno set 3 deny all from any to $clientip not MAC $clientmac any layer2 out");
223
	}
224
	
225 5b237745 Scott Ullrich
	/* read in client database */
226
	$cpdb = array();
227
228
	$fd = @fopen("{$g['vardb_path']}/captiveportal.db", "r");
229
	if ($fd) {
230
		while (!feof($fd)) {
231
			$line = trim(fgets($fd)) ;
232
			if($line) {
233
				$cpdb[] = explode(",",$line);
234 ec920231 Scott Ullrich
			}	
235 5b237745 Scott Ullrich
		}
236
		fclose($fd);
237
	}
238 ec920231 Scott Ullrich
	
239 5b237745 Scott Ullrich
	$radiusservers = captiveportal_get_radius_servers();
240
241
	/* find an existing entry and delete it */
242
	for ($i = 0; $i < count($cpdb); $i++) {
243
		if(!strcasecmp($cpdb[$i][2],$clientip)) {
244
			if(isset($config['captiveportal']['radacct_enable']) && isset($radiusservers[0])) {
245
				RADIUS_ACCOUNTING_STOP($cpdb[$i][1], // ruleno
246
									   $cpdb[$i][4], // username
247
									   $cpdb[$i][5], // sessionid
248
									   $cpdb[$i][0], // start time
249
									   $radiusservers[0]['ipaddr'],
250
									   $radiusservers[0]['acctport'],
251 7faeda46 Scott Ullrich
									   $radiusservers[0]['key'],
252
									   $clientip);
253
			}
254 6e865a74 Scott Ullrich
			mwexec("/sbin/ipfw delete " . $cpdb[$i][1] . " " . ($cpdb[$i][1]+10000));
255 5b237745 Scott Ullrich
			unset($cpdb[$i]);
256
			break;
257
		}
258 ec920231 Scott Ullrich
	}	
259 5b237745 Scott Ullrich
260
	/* rewrite information to database */
261
	$fd = @fopen("{$g['vardb_path']}/captiveportal.db", "w");
262
	if ($fd) {
263
		foreach ($cpdb as $cpent) {
264
			fwrite($fd, join(",", $cpent) . "\n");
265
		}
266
		/* write in this new entry */
267 6e865a74 Scott Ullrich
		/* encode password in Base64 just in case it contains commas */
268
		$bpassword = base64_encode($password);
269
		fwrite($fd, time().",{$ruleno},{$clientip},{$clientmac},{$clientuser},{$sessionid},{$bpassword}\n") ;
270 5b237745 Scott Ullrich
		fclose($fd);
271
	}
272 ec920231 Scott Ullrich
	
273 5b237745 Scott Ullrich
	/* write next rule number */
274
	$fd = @fopen("{$g['vardb_path']}/captiveportal.nextrule", "w");
275
	if ($fd) {
276
		$ruleno++;
277
		if ($ruleno > 19899)
278
			$ruleno = 10000;	/* wrap around */
279
		fwrite($fd, $ruleno);
280
		fclose($fd);
281
	}
282 ec920231 Scott Ullrich
	
283 5b237745 Scott Ullrich
	portal_unlock();
284 ec920231 Scott Ullrich
	
285 5b237745 Scott Ullrich
	/* redirect user to desired destination */
286
	if ($config['captiveportal']['redirurl'])
287
		$redirurl = $config['captiveportal']['redirurl'];
288
	else if ($_POST['redirurl'])
289
		$redirurl = $_POST['redirurl'];
290
	else
291
		$redirurl = "http://{$orig_host}{$orig_request}";
292 ec920231 Scott Ullrich
	
293 5b237745 Scott Ullrich
	if(isset($config['captiveportal']['logoutwin_enable'])) {
294 ec920231 Scott Ullrich
		
295 5b237745 Scott Ullrich
		if (isset($config['captiveportal']['httpslogin']))
296
			$logouturl = "https://{$config['captiveportal']['httpsname']}:8001/";
297
		else
298
			$logouturl = "http://{$config['interfaces'][$config['captiveportal']['interface']]['ipaddr']}:8000/";
299 ec920231 Scott Ullrich
		
300 5b237745 Scott Ullrich
		echo <<<EOD
301
<HTML>
302
<HEAD><TITLE>Redirecting...</TITLE></HEAD>
303
<BODY>
304
<SPAN STYLE="font-family: Tahoma, Verdana, Arial, Helvetica, sans-serif; font-size: 11px;">
305
<B>Redirecting to <A HREF="{$redirurl}">{$redirurl}</A>...</B>
306
</SPAN>
307
<SCRIPT LANGUAGE="JavaScript">
308
<!--
309
LogoutWin = window.open('', 'Logout', 'toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=0,width=256,height=64');
310
if (LogoutWin) {
311
	LogoutWin.document.write('<HTML>');
312
	LogoutWin.document.write('<HEAD><TITLE>Logout</TITLE></HEAD>') ;
313
	LogoutWin.document.write('<BODY BGCOLOR="#435370">');
314
	LogoutWin.document.write('<DIV ALIGN="center" STYLE="color: #ffffff; font-family: Tahoma, Verdana, Arial, Helvetica, sans-serif; font-size: 11px;">') ;
315
	LogoutWin.document.write('<B>Click the button below to disconnect</B><P>');
316
	LogoutWin.document.write('<FORM METHOD="POST" ACTION="{$logouturl}">');
317
	LogoutWin.document.write('<INPUT NAME="logout_id" TYPE="hidden" VALUE="{$sessionid}">');
318
	LogoutWin.document.write('<INPUT NAME="logout" TYPE="submit" VALUE="Logout">');
319
	LogoutWin.document.write('</FORM>');
320
	LogoutWin.document.write('</DIV></BODY>');
321
	LogoutWin.document.write('</HTML>');
322
	LogoutWin.document.close();
323
}
324
325
document.location.href="{$redirurl}";
326
-->
327
</SCRIPT>
328
</BODY>
329
</HTML>
330
331
EOD;
332
	} else {
333 ec920231 Scott Ullrich
		header("Location: " . $redirurl); 
334 5b237745 Scott Ullrich
	}
335 ec920231 Scott Ullrich
	
336 5b237745 Scott Ullrich
	return $sessionid;
337
}
338
339
/* read RADIUS servers into array */
340
function captiveportal_get_radius_servers() {
341 ec920231 Scott Ullrich
	
342 5b237745 Scott Ullrich
	global $g;
343 ec920231 Scott Ullrich
	
344 5b237745 Scott Ullrich
	if (file_exists("{$g['vardb_path']}/captiveportal_radius.db")) {
345
	   	$fd = @fopen("{$g['vardb_path']}/captiveportal_radius.db","r");
346
		if ($fd) {
347
			$radiusservers = array();
348
			while (!feof($fd)) {
349
				$line = trim(fgets($fd));
350
				if ($line) {
351
					$radsrv = array();
352
					list($radsrv['ipaddr'],$radsrv['port'],$radsrv['acctport'],$radsrv['key']) = explode(",",$line);
353
					$radiusservers[] = $radsrv;
354
				}
355
			}
356
			fclose($fd);
357 ec920231 Scott Ullrich
			
358 5b237745 Scott Ullrich
			return $radiusservers;
359
		}
360
	}
361 ec920231 Scott Ullrich
	
362 5b237745 Scott Ullrich
	return false;
363
}
364
365
/* lock captive portal information, decide that the lock file is stale after
366
   10 seconds */
367
function portal_lock() {
368 ec920231 Scott Ullrich
	
369 5b237745 Scott Ullrich
	global $lockfile;
370 ec920231 Scott Ullrich
	
371 5b237745 Scott Ullrich
	$n = 0;
372
	while ($n < 10) {
373
		/* open the lock file in append mode to avoid race condition */
374
		if ($fd = @fopen($lockfile, "x")) {
375
			/* succeeded */
376
			fclose($fd);
377
			return;
378
		} else {
379
			/* file locked, wait and try again */
380
			sleep(1);
381
			$n++;
382
		}
383
	}
384
}
385
386
/* unlock captive portal information file */
387
function portal_unlock() {
388 ec920231 Scott Ullrich
	
389 5b237745 Scott Ullrich
	global $lockfile;
390 ec920231 Scott Ullrich
	
391 5b237745 Scott Ullrich
	if (file_exists($lockfile))
392
		unlink($lockfile);
393
}
394
395
/* remove a single client by session ID
396
   by Dinesh Nair
397
 */
398
function disconnect_client($sessionid) {
399 ec920231 Scott Ullrich
	
400 5b237745 Scott Ullrich
	global $g, $config;
401 ec920231 Scott Ullrich
	
402 5b237745 Scott Ullrich
	portal_lock();
403 ec920231 Scott Ullrich
	
404 5b237745 Scott Ullrich
	/* read database */
405
	$cpdb = array() ;
406
	$fd = @fopen("{$g['vardb_path']}/captiveportal.db", "r");
407
	if ($fd) {
408
		while (!feof($fd)) {
409
			$line = trim(fgets($fd)) ;
410
			if($line) {
411
				$cpdb[] = explode(",",$line);
412 ec920231 Scott Ullrich
			}	
413 5b237745 Scott Ullrich
		}
414
		fclose($fd);
415
	}
416 ec920231 Scott Ullrich
	
417 5b237745 Scott Ullrich
	$radiusservers = captiveportal_get_radius_servers();
418 ec920231 Scott Ullrich
	
419
	/* find entry */	
420 5b237745 Scott Ullrich
	for ($i = 0; $i < count($cpdb); $i++) {
421
		if ($cpdb[$i][5] == $sessionid) {
422 6e865a74 Scott Ullrich
			/* this client needs to be deleted - remove ipfw rules */
423 5b237745 Scott Ullrich
			if(isset($config['captiveportal']['radacct_enable']) && isset($radiusservers[0])) {
424
				RADIUS_ACCOUNTING_STOP($cpdb[$i][1], // ruleno
425
									   $cpdb[$i][4], // username
426
									   $cpdb[$i][5], // sessionid
427
									   $cpdb[$i][0], // start time
428
									   $radiusservers[0]['ipaddr'],
429
									   $radiusservers[0]['acctport'],
430 7faeda46 Scott Ullrich
									   $radiusservers[0]['key'],
431 6e865a74 Scott Ullrich
									   $cpdb[$i][2]);
432 5b237745 Scott Ullrich
			}
433 6e865a74 Scott Ullrich
			mwexec("/sbin/ipfw delete " . $cpdb[$i][1] . " " . ($cpdb[$i][1]+10000));
434
			captiveportal_logportalauth($cpdb[$i][4],$cpdb[$i][3],$cpdb[$i][2],"LOGOUT");
435 5b237745 Scott Ullrich
			unset($cpdb[$i]);
436
			break;
437
		}
438
	}
439 ec920231 Scott Ullrich
	
440 5b237745 Scott Ullrich
	/* rewrite information to database */
441
	$fd = @fopen("{$g['vardb_path']}/captiveportal.db", "w");
442
	if ($fd) {
443
		foreach ($cpdb as $cpent) {
444
			fwrite($fd, join(",", $cpent) . "\n");
445
		}
446
		fclose($fd);
447
	}
448 ec920231 Scott Ullrich
	
449 5b237745 Scott Ullrich
	portal_unlock();
450
}
451 6e865a74 Scott Ullrich
452
/* log successful captive portal authentication to syslog */
453
/* part of this code from php.net */
454
function captiveportal_logportalauth($user,$mac,$ip,$status) {
455
	define_syslog_variables();
456
	openlog("logportalauth", LOG_PID, LOG_LOCAL4);
457
	// Log it
458
	syslog(LOG_INFO, "$status: $user, $mac, $ip");
459
	closelog();
460
}
461
462
?>