Project

General

Profile

Download (19.3 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
	captiveportal.inc
4
	part of m0n0wall (http://m0n0.ch/wall)
5

    
6
	Copyright (C) 2003-2005 Manuel Kasper <mk@neon1.net>.
7
	All rights reserved.
8

    
9
	Redistribution and use in source and binary forms, with or without
10
	modification, are permitted provided that the following conditions are met:
11

    
12
	1. Redistributions of source code must retain the above copyright notice,
13
	   this list of conditions and the following disclaimer.
14

    
15
	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

    
19
	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
	This version of captiveportal.inc has been modified by Rob Parker
31
	<rob.parker@keycom.co.uk> to include changes for per-user bandwidth management
32
	via returned RADIUS attributes. This page has been modified to delete any
33
	added rules which may have been created by other per-user code (index.php, etc).
34
	These changes are (c) 2004 Keycom PLC.
35
*/
36

    
37
/* include all configuration functions */
38
require_once("functions.inc");
39
require_once("radius_accounting.inc") ;
40

    
41
function captiveportal_configure() {
42
	global $config, $g;
43

    
44
	if (isset($config['captiveportal']['enable']) &&
45
		(($config['captiveportal']['interface'] == "lan") ||
46
			isset($config['interfaces'][$config['captiveportal']['interface']]['enable']))) {
47

    
48
		if ($g['booting'])
49
			echo "Starting captive portal... ";
50

    
51
		/* kill any running mini_httpd */
52
		killbypid("{$g['varrun_path']}/mini_httpd.cp.pid");
53
		killbypid("{$g['varrun_path']}/mini_httpd.cps.pid");
54

    
55
		/* kill any running minicron */
56
		killbypid("{$g['varrun_path']}/minicron.pid");
57

    
58
		/* generate ipfw rules */
59
		$cprules = captiveportal_rules_generate();
60

    
61
		/* make sure ipfw is loaded */
62
		mwexec("/sbin/kldload ipfw");
63

    
64
		/* stop accounting on all clients */
65
		captiveportal_radius_stop_all() ;
66

    
67
		/* remove old information */
68
		unlink_if_exists("{$g['vardb_path']}/captiveportal.nextrule");
69
		unlink_if_exists("{$g['vardb_path']}/captiveportal.db");
70
		unlink_if_exists("{$g['vardb_path']}/captiveportal_mac.db");
71
		unlink_if_exists("{$g['vardb_path']}/captiveportal_ip.db");
72
		unlink_if_exists("{$g['vardb_path']}/captiveportal_radius.db");
73

    
74
		/* write portal page */
75
		if ($config['captiveportal']['page']['htmltext'])
76
			$htmltext = base64_decode($config['captiveportal']['page']['htmltext']);
77
		else {
78
			/* example/template page */
79
			$htmltext = <<<EOD
80
<html>
81
<title>pfSense's captive portal</title>
82
<head>
83
 <STYLE type="text/css">
84
.listhdrr {
85
	background-color: #BBBBBB;
86
	padding-right: 16px;
87
	padding-left: 6px;
88
	font-weight: bold;
89
	border-right: 1px solid #999999;
90
	border-bottom: 1px solid #999999;
91
	font-size: 11px;
92
	padding-top: 5px;
93
	padding-bottom: 5px;
94
}
95

    
96
 </STYLE>
97
</head>
98
<body bgcolor="#990000">
99
<center>
100
<font color="white" face="arial" size="+1">Welcome to pfSense's captive portal!</font>
101
<p>
102
<form method="post" action="$PORTAL_ACTION$">
103
<table border="0" cellpadding="6" cellspacing="0">
104
<tr><td align="right" class="listhdrr"><font color="white">Username:</td><td class="listhdrr"><input name="auth_user" type="text"></td></tr>
105
<tr><td align="right" class="listhdrr"><font color="white">Password:</td><td class="listhdrr"><input name="auth_pass" type="password"></td></tr>
106
<input name="redirurl" type="hidden" value="$PORTAL_REDIRURL$">
107
</table>
108
<p>
109
<center><input name="accept" type="submit" value="Continue">
110
</form>
111
</center>
112
</body>
113
</html>
114

    
115
EOD;
116
		}
117

    
118
		$fd = @fopen("{$g['varetc_path']}/captiveportal.html", "w");
119
		if ($fd) {
120
			fwrite($fd, $htmltext);
121
			fclose($fd);
122
		}
123

    
124
		/* write error page */
125
		if ($config['captiveportal']['page']['errtext'])
126
			$errtext = base64_decode($config['captiveportal']['page']['errtext']);
127
		else {
128
			/* example page */
129
			$errtext = <<<EOD
130
<html>
131
<head>
132
<title>Authentication error</title>
133
</head>
134
<body>
135
<font color="#cc0000"><h2>Authentication error</h2></font>
136
<b>
137
Username and/or password invalid.
138
<br><br>
139
<a href="javascript:history.back()">Go back</a>
140
</b>
141
</body>
142
</html>
143

    
144
EOD;
145
		}
146

    
147
		$fd = @fopen("{$g['varetc_path']}/captiveportal-error.html", "w");
148
		if ($fd) {
149
			fwrite($fd, $errtext);
150
			fclose($fd);
151
		}
152

    
153
		/* load rules */
154
		mwexec("/sbin/ipfw -f delete set 1");
155
		mwexec("/sbin/ipfw -f delete set 2");
156
		mwexec("/sbin/ipfw -f delete set 3");
157

    
158
		/* XXX - seems like ipfw cannot accept rules directly on stdin,
159
		   so we have to write them to a temporary file first */
160
		$fd = @fopen("{$g['tmp_path']}/ipfw.cp.rules", "w");
161
		if (!$fd) {
162
			printf("Cannot open ipfw.cp.rules in captiveportal_configure()\n");
163
			return 1;
164
		}
165

    
166
		fwrite($fd, $cprules);
167
		fclose($fd);
168

    
169
		mwexec("/sbin/ipfw {$g['tmp_path']}/ipfw.cp.rules");
170

    
171
		unlink("{$g['tmp_path']}/ipfw.cp.rules");
172

    
173
		/* filter on layer2 as well so we can check MAC addresses */
174
		mwexec("/sbin/sysctl net.link.ether.ipfw=1");
175

    
176
		chdir($g['captiveportal_path']);
177

    
178
		/* start web server */
179
		mwexec("/usr/local/sbin/mini_httpd -a -M 0 -u root -maxproc 16" .
180
			" -p 8000 -i {$g['varrun_path']}/mini_httpd.cp.pid");
181

    
182
		/* fire up another one for HTTPS if requested */
183
		if (isset($config['captiveportal']['httpslogin']) &&
184
			$config['captiveportal']['certificate'] && $config['captiveportal']['private-key']) {
185

    
186
			$cert = base64_decode($config['captiveportal']['certificate']);
187
			$key = base64_decode($config['captiveportal']['private-key']);
188

    
189
			$fd = fopen("{$g['varetc_path']}/cert-portal.pem", "w");
190
			if (!$fd) {
191
				printf("Error: cannot open cert-portal.pem in system_webgui_start().\n");
192
				return 1;
193
			}
194
			chmod("{$g['varetc_path']}/cert-portal.pem", 0600);
195
			fwrite($fd, $cert);
196
			fwrite($fd, "\n");
197
			fwrite($fd, $key);
198
			fclose($fd);
199

    
200
			mwexec("/usr/local/sbin/mini_httpd -S -a -M 0 -E {$g['varetc_path']}/cert-portal.pem" .
201
				" -u root -maxproc 16 -p 8001" .
202
				" -i {$g['varrun_path']}/mini_httpd.cps.pid");
203
		}
204

    
205
		/* start pruning process (interval = 60 seconds) */
206
		mwexec("/usr/local/bin/minicron 60 {$g['varrun_path']}/minicron.pid " .
207
			"/etc/rc.prunecaptiveportal");
208

    
209
		/* generate passthru mac database */
210
		captiveportal_passthrumac_configure() ;
211
		/* create allowed ip database and insert ipfw rules to make it so */
212
		captiveportal_allowedip_configure() ;
213

    
214
		/* generate radius server database */
215
		if($config['captiveportal']['radiusip']) {
216
			$radiusip = $config['captiveportal']['radiusip'] ;
217

    
218
			if($config['captiveportal']['radiusport'])
219
				$radiusport = $config['captiveportal']['radiusport'] ;
220
			else
221
				$radiusport = 1812;
222

    
223
			if($config['captiveportal']['radiusacctport'])
224
				$radiusacctport = $config['captiveportal']['radiusacctport'] ;
225
			else
226
				$radiusacctport = 1813;
227

    
228
			$radiuskey = $config['captiveportal']['radiuskey'];
229

    
230
			$fd = @fopen("{$g['vardb_path']}/captiveportal_radius.db", "w");
231
			if (!$fd) {
232
				printf("Error: cannot open radius DB file in captiveportal_configure().\n");
233
				return 1;
234
			} else {
235
				fwrite($fd,$radiusip . "," . $radiusport . "," . $radiusacctport . "," . $radiuskey) ;
236
			}
237
			fclose($fd) ;
238
		}
239

    
240

    
241
		if ($g['booting'])
242
			echo "done\n";
243

    
244
	} else {
245
		killbypid("{$g['varrun_path']}/mini_httpd.cp.pid");
246
		killbypid("{$g['varrun_path']}/minicron.pid");
247
		captiveportal_radius_stop_all() ;
248
		mwexec("/sbin/sysctl net.link.ether.ipfw=0");
249
		if (!isset($config['shaper']['enable'])) {
250
			/* unload ipfw */
251
			mwexec("/sbin/kldunload ipfw");
252
		} else {
253
			/* shaper is on - just remove our rules */
254
			mwexec("/sbin/ipfw -f delete set 1");
255
			mwexec("/sbin/ipfw -f delete set 2");
256
			mwexec("/sbin/ipfw -f delete set 3");
257
		}
258
	}
259

    
260
	return 0;
261
}
262

    
263
function captiveportal_rules_generate() {
264
	global $config, $g;
265

    
266
	$cpifn = $config['captiveportal']['interface'];
267
	$cpif = $config['interfaces'][$cpifn]['if'];
268
	$cpip = $config['interfaces'][$cpifn]['ipaddr'];
269

    
270
	/* note: the captive portal daemon inserts all pass rules for authenticated
271
	   clients as skipto 50000 rules to make traffic shaping work */
272

    
273
	$cprules = "";
274

    
275
	/* captive portal on LAN interface? */
276
	if ($cpifn == "lan") {
277
		/* add anti-lockout rules */
278
		$cprules .= <<<EOD
279
add 500 set 1 pass all from $cpip to any out via $cpif
280
add 501 set 1 pass all from any to $cpip in via $cpif
281

    
282
EOD;
283
	}
284

    
285
	$cprules .= <<<EOD
286
# skip to traffic shaper if not on captive portal interface
287
add 1000 set 1 skipto 50000 all from any to any not layer2 not via $cpif
288
# pass all layer2 traffic on other interfaces
289
add 1001 set 1 pass layer2 not via $cpif
290

    
291
# layer 2: pass ARP
292
add 1100 set 1 pass layer2 mac-type arp
293
# layer 2: block anything else non-IP
294
add 1101 set 1 deny layer2 not mac-type ip
295
# layer 2: check if MAC addresses of authenticated clients are correct
296
add 1102 set 1 skipto 20000 layer2
297

    
298
# allow access to our DHCP server (which needs to be able to ping clients as well)
299
add 1200 set 1 pass udp from any 68 to 255.255.255.255 67 in
300
add 1201 set 1 pass udp from any 68 to $cpip 67 in
301
add 1202 set 1 pass udp from $cpip 67 to any 68 out
302
add 1203 set 1 pass icmp from $cpip to any out icmptype 8
303
add 1204 set 1 pass icmp from any to $cpip in icmptype 0
304

    
305
# allow access to our DNS forwarder
306
add 1300 set 1 pass udp from any to $cpip 53 in
307
add 1301 set 1 pass udp from $cpip 53 to any out
308

    
309
# allow access to our web server
310
add 1302 set 1 pass tcp from any to $cpip 8000 in
311
add 1303 set 1 pass tcp from $cpip 8000 to any out
312

    
313
EOD;
314

    
315
	if (isset($config['captiveportal']['httpslogin'])) {
316
		$cprules .= <<<EOD
317
add 1304 set 1 pass tcp from any to $cpip 8001 in
318
add 1305 set 1 pass tcp from $cpip 8001 to any out
319

    
320
EOD;
321
	}
322

    
323
	$cprules .= <<<EOD
324

    
325
# ... 10000-19899: rules per authenticated client go here...
326

    
327
# redirect non-authenticated clients to captive portal
328
add 19900 set 1 fwd 127.0.0.1,8000 tcp from any to any 80 in
329
# let the responses from the captive portal web server back out
330
add 19901 set 1 pass tcp from any 80 to any out
331
# block everything else
332
add 19902 set 1 deny all from any to any
333

    
334
# ... 20000-29899: layer2 block rules per authenticated client go here...
335

    
336
# pass everything else on layer2
337
add 29900 set 1 pass all from any to any layer2
338

    
339
EOD;
340

    
341
	return $cprules;
342
}
343

    
344
/* remove clients that have been around for longer than the specified amount of time */
345
/* db file structure: timestamp,ipfw_rule_no,clientip,clientmac,username,sessionid */
346
function captiveportal_prune_old() {
347

    
348
	global $g, $config;
349

    
350
	/* check for expired entries */
351
	if ($config['captiveportal']['timeout'])
352
		$timeout = $config['captiveportal']['timeout'] * 60;
353
	else
354
		$timeout = 0;
355

    
356
	if ($config['captiveportal']['idletimeout'])
357
		$idletimeout = $config['captiveportal']['idletimeout'] * 60;
358
	else
359
		$idletimeout = 0;
360

    
361
	if (!$timeout && !$idletimeout)
362
		return;
363

    
364
	captiveportal_lock();
365

    
366
	/* read database */
367
	$cpdb = captiveportal_read_db();
368

    
369
	$radiusservers = captiveportal_get_radius_servers();
370

    
371
	for ($i = 0; $i < count($cpdb); $i++) {
372

    
373
		$timedout = false;
374

    
375
		/* hard timeout? */
376
		if ($timeout) {
377
			if ((time() - $cpdb[$i][0]) >= $timeout)
378
				$timedout = true;
379
		}
380

    
381
		/* if an idle timeout is specified, get last activity timestamp from ipfw */
382
		if (!$timedout && $idletimeout) {
383
			$lastact = captiveportal_get_last_activity($cpdb[$i][1]);
384
			if ($lastact && ((time() - $lastact) >= $idletimeout))
385
				$timedout = true;
386
		}
387

    
388
		if ($timedout) {
389
			/* this client needs to be deleted - remove ipfw rules */
390
			if (isset($config['captiveportal']['radacct_enable']) && isset($radiusservers[0])) {
391
				RADIUS_ACCOUNTING_STOP($cpdb[$i][1], // ruleno
392
									   $cpdb[$i][4], // username
393
									   $cpdb[$i][5], // sessionid
394
									   $cpdb[$i][0], // start time
395
									   $radiusservers[0]['ipaddr'],
396
									   $radiusservers[0]['acctport'],
397
									   $radiusservers[0]['key'],
398
									   $cpdb[$i][2]); //clientip
399
				syslog(LOG_INFO,"Authenticated user $cpdb[$i][4] timed out");
400
			}
401
			//KEYCOM: we need to delete +40500 and +45500 as well...
402
			//these are the rule numbers we use to control traffic shaping for each logged in user via captive portal
403
			mwexec("/sbin/ipfw delete " . $cpdb[$i][1] . " " . ($cpdb[$i][1]+10000));
404
			//we only need to remove our rules if peruserbw is turned on.
405
			if(isset($config['captiveportal']['peruserbw'])) {
406
				mwexec("/sbin/ipfw delete " . ($cpdb[$i][1]+40500));
407
				mwexec("/sbin/ipfw delete " . ($cpdb[$i][1]+45500));
408
			}
409
			unset($cpdb[$i]);
410
		}
411
	}
412

    
413
	/* write database */
414
	captiveportal_write_db($cpdb);
415

    
416
	captiveportal_unlock();
417
}
418

    
419
/* remove a single client by ipfw rule number */
420
function captiveportal_disconnect_client($id) {
421

    
422
	global $g, $config;
423

    
424
	captiveportal_lock();
425

    
426
	/* read database */
427
	$cpdb = captiveportal_read_db();
428
	$radiusservers = captiveportal_get_radius_servers();
429

    
430
	/* find entry */
431
	for ($i = 0; $i < count($cpdb); $i++) {
432
		if ($cpdb[$i][1] == $id) {
433
			/* this client needs to be deleted - remove ipfw rules */
434
			if (isset($config['captiveportal']['radacct_enable']) && isset($radiusservers[0])) {
435
				RADIUS_ACCOUNTING_STOP($cpdb[$i][1], // ruleno
436
									   $cpdb[$i][4], // username
437
									   $cpdb[$i][5], // sessionid
438
									   $cpdb[$i][0], // start time
439
									   $radiusservers[0]['ipaddr'],
440
									   $radiusservers[0]['acctport'],
441
									   $radiusservers[0]['key'],
442
									   $cpdb[$i][2]); //clientip
443
				syslog(LOG_INFO,"Authenticated user $cpdb[$i][4] disconnected");
444
			}
445
			mwexec("/sbin/ipfw delete " . $cpdb[$i][1] . " " . ($cpdb[$i][1]+10000));
446
			//we only need to remove our rules if peruserbw is turned on.
447
			if(isset($config['captiveportal']['peruserbw'])) {
448
				mwexec("/sbin/ipfw delete " . ($cpdb[$i][1]+40500));
449
				mwexec("/sbin/ipfw delete " . ($cpdb[$i][1]+45500));
450
			}
451
			unset($cpdb[$i]);
452
			break;
453
		}
454
	}
455

    
456
	/* write database */
457
	captiveportal_write_db($cpdb);
458

    
459
	captiveportal_unlock();
460
}
461

    
462
/* send RADIUS acct stop for all current clients */
463
function captiveportal_radius_stop_all() {
464
	global $g, $config;
465

    
466
	captiveportal_lock() ;
467
	$cpdb = captiveportal_read_db() ;
468

    
469
	$radiusservers = captiveportal_get_radius_servers();
470

    
471
	if (isset($radiusservers[0])) {
472
		for ($i = 0; $i < count($cpdb); $i++) {
473
			RADIUS_ACCOUNTING_STOP($cpdb[$i][1], // ruleno
474
								   $cpdb[$i][4], // username
475
								   $cpdb[$i][5], // sessionid
476
								   $cpdb[$i][0], // start time
477
								   $radiusservers[0]['ipaddr'],
478
								   $radiusservers[0]['acctport'],
479
								   $radiusservers[0]['key'],
480
								   $cpdb[$i][2]); //clientip
481
		}
482
	}
483
	captiveportal_unlock() ;
484
}
485

    
486
function captiveportal_passthrumac_configure() {
487
	global $config, $g;
488

    
489
	/* clear out passthru macs, if necessary */
490
	if (file_exists("{$g['vardb_path']}/captiveportal_mac.db")) {
491
		unlink("{$g['vardb_path']}/captiveportal_mac.db");
492
	}
493

    
494
	if (is_array($config['captiveportal']['passthrumac'])) {
495

    
496
		$fd = @fopen("{$g['vardb_path']}/captiveportal_mac.db", "w");
497
		if (!$fd) {
498
			printf("Error: cannot open passthru mac DB file in captiveportal_passthrumac_configure().\n");
499
			return 1;
500
		}
501

    
502
		foreach ($config['captiveportal']['passthrumac'] as $macent) {
503
			/* record passthru mac so it can be recognized and let thru */
504
			fwrite($fd, $macent['mac'] . "\n");
505
		}
506

    
507
		fclose($fd);
508
	}
509

    
510
	return 0;
511
}
512

    
513
function captiveportal_allowedip_configure() {
514
	global $config, $g;
515

    
516
	captiveportal_lock() ;
517

    
518
	/* clear out existing allowed ips, if necessary */
519
	if (file_exists("{$g['vardb_path']}/captiveportal_ip.db")) {
520
		$fd = @fopen("{$g['vardb_path']}/captiveportal_ip.db", "r");
521
		if ($fd) {
522
			while (!feof($fd)) {
523
				$line = trim(fgets($fd));
524
				if($line) {
525
					list($ip,$rule) = explode(",",$line);
526
					mwexec("/sbin/ipfw delete $rule") ;
527
				}
528
			}
529
		}
530
		fclose($fd) ;
531
		unlink("{$g['vardb_path']}/captiveportal_ip.db");
532
	}
533

    
534
	/* get next ipfw rule number */
535
	if (file_exists("{$g['vardb_path']}/captiveportal.nextrule"))
536
		$ruleno = trim(file_get_contents("{$g['vardb_path']}/captiveportal.nextrule"));
537
	if (!$ruleno)
538
		$ruleno = 10000;	/* first rule number */
539

    
540
	if (is_array($config['captiveportal']['allowedip'])) {
541

    
542
		$fd = @fopen("{$g['vardb_path']}/captiveportal_ip.db", "w");
543
		if (!$fd) {
544
			printf("Error: cannot open allowed ip DB file in captiveportal_allowedip_configure().\n");
545
			captiveportal_unlock() ;
546
			return 1;
547
		}
548

    
549
		foreach ($config['captiveportal']['allowedip'] as $ipent) {
550
			/* record allowed ip so it can be recognized and removed later */
551
			fwrite($fd, $ipent['ip'] . "," . $ruleno ."\n");
552
			/* insert ipfw rule to allow ip thru */
553
			if($ipent['dir'] == "from") {
554
				mwexec("/sbin/ipfw add $ruleno set 2 skipto 50000 ip from ".$ipent['ip']." to any in") ;
555
				mwexec("/sbin/ipfw add $ruleno set 2 skipto 50000 ip from any to ".$ipent['ip']." out") ;
556
			} else {
557
				mwexec("/sbin/ipfw add $ruleno set 2 skipto 50000 ip from any to ".$ipent['ip']." in") ;
558
				mwexec("/sbin/ipfw add $ruleno set 2 skipto 50000 ip from ".$ipent['ip']." to any out") ;
559
			}
560
			$ruleno++ ;
561
			if ($ruleno > 19899)
562
				$ruleno = 10000;
563
		}
564

    
565
		fclose($fd);
566

    
567
		/* write next rule number */
568
		$fd = @fopen("{$g['vardb_path']}/captiveportal.nextrule", "w");
569
		if ($fd) {
570
			fwrite($fd, $ruleno);
571
			fclose($fd);
572
		}
573
	}
574

    
575
	captiveportal_unlock() ;
576
	return 0;
577
}
578

    
579
/* get last activity timestamp given ipfw rule number */
580
function captiveportal_get_last_activity($ruleno) {
581

    
582
	exec("/sbin/ipfw -T list {$ruleno} 2>/dev/null", $ipfwoutput);
583

    
584
	/* in */
585
	if ($ipfwoutput[0]) {
586
		$ri = explode(" ", $ipfwoutput[0]);
587
		if ($ri[1])
588
			return $ri[1];
589
	}
590

    
591
	return 0;
592
}
593

    
594
/* read captive portal DB into array */
595
function captiveportal_read_db() {
596

    
597
	global $g;
598

    
599
	$cpdb = array();
600
	$fd = @fopen("{$g['vardb_path']}/captiveportal.db", "r");
601
	if ($fd) {
602
		while (!feof($fd)) {
603
			$line = trim(fgets($fd));
604
			if ($line) {
605
				$cpdb[] = explode(",", $line);
606
			}
607
		}
608
		fclose($fd);
609
	}
610
	return $cpdb;
611
}
612

    
613
/* write captive portal DB */
614
function captiveportal_write_db($cpdb) {
615

    
616
	global $g;
617

    
618
	$fd = @fopen("{$g['vardb_path']}/captiveportal.db", "w");
619
	if ($fd) {
620
		foreach ($cpdb as $cpent) {
621
			fwrite($fd, join(",", $cpent) . "\n");
622
		}
623
		fclose($fd);
624
	}
625
}
626

    
627
/* read RADIUS servers into array */
628
function captiveportal_get_radius_servers() {
629

    
630
	global $g;
631

    
632
	if (file_exists("{$g['vardb_path']}/captiveportal_radius.db")) {
633
	   	$fd = @fopen("{$g['vardb_path']}/captiveportal_radius.db","r");
634
		if ($fd) {
635
			$radiusservers = array();
636
			while (!feof($fd)) {
637
				$line = trim(fgets($fd));
638
				if ($line) {
639
					$radsrv = array();
640
					list($radsrv['ipaddr'],$radsrv['port'],$radsrv['acctport'],$radsrv['key']) = explode(",",$line);
641
					$radiusservers[] = $radsrv;
642
				}
643
			}
644
			fclose($fd);
645

    
646
			return $radiusservers;
647
		}
648
	}
649

    
650
	return false;
651
}
652

    
653
/* lock captive portal information, decide that the lock file is stale after
654
   10 seconds */
655
function captiveportal_lock() {
656

    
657
	global $g;
658

    
659
	$lockfile = "{$g['varrun_path']}/captiveportal.lock";
660

    
661
	$n = 0;
662
	while ($n < 10) {
663
		/* open the lock file in append mode to avoid race condition */
664
		if ($fd = @fopen($lockfile, "x")) {
665
			/* succeeded */
666
			fclose($fd);
667
			return;
668
		} else {
669
			/* file locked, wait and try again */
670
			sleep(1);
671
			$n++;
672
		}
673
	}
674
}
675

    
676
/* unlock configuration file */
677
function captiveportal_unlock() {
678

    
679
	global $g;
680

    
681
	$lockfile = "{$g['varrun_path']}/captiveportal.lock";
682

    
683
	if (file_exists($lockfile))
684
		unlink($lockfile);
685
}
686

    
687
?>
(1-1/14)