Project

General

Profile

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

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

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

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

    
16
	2. Redistributions in binary form must reproduce the above copyright
17
	   notice, this list of conditions and the following disclaimer in the
18
	   documentation and/or other materials provided with the distribution.
19

    
20
	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
21
	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
22
	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23
	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
24
	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
	POSSIBILITY OF SUCH DAMAGE.
30

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

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

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

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

    
49
		if($g['booting']) 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'] && $config['captiveportal']['auth_method']=="radius") {
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
		if($g['booting']) print "done.\n";
241

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

    
258
	return 0;
259
}
260

    
261
function captiveportal_rules_generate() {
262
	global $config, $g;
263

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

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

    
271
	$cprules = "";
272

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

    
280
EOD;
281
	}
282

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

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

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

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

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

    
311
EOD;
312

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

    
318
EOD;
319
	}
320

    
321
	$cprules .= <<<EOD
322

    
323
# ... 10000-19899: rules per authenticated client go here...
324

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

    
332
# ... 20000-29899: layer2 block rules per authenticated client go here...
333

    
334
# pass everything else on layer2
335
add 29900 set 1 pass all from any to any layer2
336

    
337
EOD;
338

    
339
	return $cprules;
340
}
341

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

    
346
	global $g, $config;
347

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

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

    
359
	if (!$timeout && !$idletimeout)
360
		return;
361

    
362
	captiveportal_lock();
363

    
364
	/* read database */
365
	$cpdb = captiveportal_read_db();
366

    
367
	$radiusservers = captiveportal_get_radius_servers();
368

    
369
	for ($i = 0; $i < count($cpdb); $i++) {
370

    
371
		$timedout = false;
372

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

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

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

    
411
	/* write database */
412
	captiveportal_write_db($cpdb);
413

    
414
	captiveportal_unlock();
415
}
416

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

    
420
	global $g, $config;
421

    
422
	captiveportal_lock();
423

    
424
	/* read database */
425
	$cpdb = captiveportal_read_db();
426
	$radiusservers = captiveportal_get_radius_servers();
427

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

    
454
	/* write database */
455
	captiveportal_write_db($cpdb);
456

    
457
	captiveportal_unlock();
458
}
459

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

    
464
	captiveportal_lock() ;
465
	$cpdb = captiveportal_read_db() ;
466

    
467
	$radiusservers = captiveportal_get_radius_servers();
468

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

    
484
function captiveportal_passthrumac_configure() {
485
	global $config, $g;
486

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

    
492
	if (is_array($config['captiveportal']['passthrumac'])) {
493

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

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

    
505
		fclose($fd);
506
	}
507

    
508
	return 0;
509
}
510

    
511
function captiveportal_allowedip_configure() {
512
	global $config, $g;
513

    
514
	captiveportal_lock() ;
515

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

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

    
538
	if (is_array($config['captiveportal']['allowedip'])) {
539

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

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

    
563
		fclose($fd);
564

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

    
573
	captiveportal_unlock() ;
574
	return 0;
575
}
576

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

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

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

    
589
	return 0;
590
}
591

    
592
/* read captive portal DB into array */
593
function captiveportal_read_db() {
594

    
595
	global $g;
596

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

    
611
/* write captive portal DB */
612
function captiveportal_write_db($cpdb) {
613

    
614
	global $g;
615

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

    
625
/* read RADIUS servers into array */
626
function captiveportal_get_radius_servers() {
627

    
628
	global $g;
629

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

    
644
			return $radiusservers;
645
		}
646
	}
647

    
648
	return false;
649
}
650

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

    
655
	global $g;
656

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

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

    
674
/* unlock configuration file */
675
function captiveportal_unlock() {
676

    
677
	global $g;
678

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

    
681
	if (file_exists($lockfile))
682
		unlink($lockfile);
683
}
684

    
685
?>
(2-2/18)