Project

General

Profile

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

    
6
	Copyright (C) 2003-2004 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

    
31
/* include all configuration functions */
32
require_once("functions.inc");
33
require_once("radius_accounting.inc") ;
34

    
35
function captiveportal_configure() {
36
	global $config, $g;
37

    
38
	if (isset($config['captiveportal']['enable']) &&
39
		(($config['captiveportal']['interface'] == "lan") ||
40
			isset($config['interfaces'][$config['captiveportal']['interface']]['enable']))) {
41

    
42
		if ($g['booting'])
43
			echo "Starting captive portal... ";
44

    
45
		/* kill any running mini_httpd */
46
		killbypid("{$g['varrun_path']}/mini_httpd.cp.pid");
47
		killbypid("{$g['varrun_path']}/mini_httpd.cps.pid");
48

    
49
		/* kill any running minicron */
50
		killbypid("{$g['varrun_path']}/minicron.pid");
51

    
52
		/* generate ipfw rules */
53
		$cprules = captiveportal_rules_generate();
54

    
55
		/* make sure ipfw is loaded */
56
		mwexec("/sbin/kldload ipfw");
57

    
58
		/* stop accounting on all clients */
59
		captiveportal_radius_stop_all() ;
60

    
61
		/* remove old information */
62
		unlink_if_exists("{$g['vardb_path']}/captiveportal.nextrule");
63
		unlink_if_exists("{$g['vardb_path']}/captiveportal.db");
64
		unlink_if_exists("{$g['vardb_path']}/captiveportal_mac.db");
65
		unlink_if_exists("{$g['vardb_path']}/captiveportal_ip.db");
66
		unlink_if_exists("{$g['vardb_path']}/captiveportal_radius.db");
67

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

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

    
109
EOD;
110
		}
111

    
112
		$fd = @fopen("{$g['varetc_path']}/captiveportal.html", "w");
113
		if ($fd) {
114
			fwrite($fd, $htmltext);
115
			fclose($fd);
116
		}
117

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

    
138
EOD;
139
		}
140

    
141
		$fd = @fopen("{$g['varetc_path']}/captiveportal-error.html", "w");
142
		if ($fd) {
143
			fwrite($fd, $errtext);
144
			fclose($fd);
145
		}
146

    
147
		/* load rules */
148
		mwexec("/sbin/ipfw -f delete set 1");
149
		mwexec("/sbin/ipfw -f delete set 2");
150
		mwexec("/sbin/ipfw -f delete set 3");
151

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

    
160
		fwrite($fd, $cprules);
161
		fclose($fd);
162

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

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

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

    
170
		chdir($g['captiveportal_path']);
171

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

    
176
		/* fire up another one for HTTPS if requested */
177
		if (isset($config['captiveportal']['httpslogin']) &&
178
			$config['captiveportal']['certificate'] && $config['captiveportal']['private-key']) {
179

    
180
			$cert = base64_decode($config['captiveportal']['certificate']);
181
			$key = base64_decode($config['captiveportal']['private-key']);
182

    
183
			$fd = fopen("{$g['varetc_path']}/cert-portal.pem", "w");
184
			if (!$fd) {
185
				printf("Error: cannot open cert-portal.pem in system_webgui_start().\n");
186
				return 1;
187
			}
188
			chmod("{$g['varetc_path']}/cert-portal.pem", 0600);
189
			fwrite($fd, $cert);
190
			fwrite($fd, "\n");
191
			fwrite($fd, $key);
192
			fclose($fd);
193

    
194
			mwexec("/usr/local/sbin/mini_httpd -S -a -M 0 -E {$g['varetc_path']}/cert-portal.pem" .
195
				" -u root -maxproc 16 -p 8001" .
196
				" -i {$g['varrun_path']}/mini_httpd.cps.pid");
197
		}
198

    
199
		/* start pruning process (interval = 60 seconds) */
200
		mwexec("/usr/local/bin/minicron 60 {$g['varrun_path']}/minicron.pid " .
201
			"/etc/rc.prunecaptiveportal");
202

    
203
		/* generate passthru mac database */
204
		captiveportal_passthrumac_configure() ;
205
		/* create allowed ip database and insert ipfw rules to make it so */
206
		captiveportal_allowedip_configure() ;
207

    
208
		/* generate radius server database */
209
		if($config['captiveportal']['radiusip']) {
210
			$radiusip = $config['captiveportal']['radiusip'] ;
211

    
212
			if($config['captiveportal']['radiusport'])
213
				$radiusport = $config['captiveportal']['radiusport'] ;
214
			else
215
				$radiusport = 1812;
216

    
217
			if($config['captiveportal']['radiusacctport'])
218
				$radiusacctport = $config['captiveportal']['radiusacctport'] ;
219
			else
220
				$radiusacctport = 1813;
221

    
222
			$radiuskey = $config['captiveportal']['radiuskey'];
223

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

    
234

    
235
		if ($g['booting'])
236
			echo "done\n";
237

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

    
254
	return 0;
255
}
256

    
257
function captiveportal_rules_generate() {
258
	global $config, $g;
259

    
260
	$cpifn = $config['captiveportal']['interface'];
261
	$cpif = $config['interfaces'][$cpifn]['if'];
262
	$cpip = $config['interfaces'][$cpifn]['ipaddr'];
263

    
264
	/* note: the captive portal daemon inserts all pass rules for authenticated
265
	   clients as skipto 50000 rules to make traffic shaping work */
266

    
267
	$cprules = "";
268

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

    
276
EOD;
277
	}
278

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

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

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

    
299
# allow access to our DNS forwarder
300
add 1300 set 1 pass udp from any to $cpip 53 in
301
add 1301 set 1 pass udp from $cpip 53 to any out
302

    
303
# allow access to our web server
304
add 1302 set 1 pass tcp from any to $cpip 8000 in
305
add 1303 set 1 pass tcp from $cpip 8000 to any out
306

    
307
EOD;
308

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

    
314
EOD;
315
	}
316

    
317
	$cprules .= <<<EOD
318

    
319
# ... 10000-19899: rules per authenticated client go here...
320

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

    
328
# ... 20000-29899: layer2 block rules per authenticated client go here...
329

    
330
# pass everything else on layer2
331
add 29900 set 1 pass all from any to any layer2
332

    
333
EOD;
334

    
335
	return $cprules;
336
}
337

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

    
342
	global $g, $config;
343

    
344
	/* check for expired entries */
345
	if ($config['captiveportal']['timeout'])
346
		$timeout = $config['captiveportal']['timeout'] * 60;
347
	else
348
		$timeout = 0;
349

    
350
	if ($config['captiveportal']['idletimeout'])
351
		$idletimeout = $config['captiveportal']['idletimeout'] * 60;
352
	else
353
		$idletimeout = 0;
354

    
355
	if (!$timeout && !$idletimeout)
356
		return;
357

    
358
	captiveportal_lock();
359

    
360
	/* read database */
361
	$cpdb = captiveportal_read_db();
362

    
363
	$radiusservers = captiveportal_get_radius_servers();
364

    
365
	for ($i = 0; $i < count($cpdb); $i++) {
366

    
367
		$timedout = false;
368

    
369
		/* hard timeout? */
370
		if ($timeout) {
371
			if ((time() - $cpdb[$i][0]) >= $timeout)
372
				$timedout = true;
373
		}
374

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

    
382
		if ($timedout) {
383
			/* this client needs to be deleted - remove ipfw rules */
384
			if (isset($config['captiveportal']['radacct_enable']) && isset($radiusservers[0])) {
385
				RADIUS_ACCOUNTING_STOP($cpdb[$i][1], // ruleno
386
									   $cpdb[$i][4], // username
387
									   $cpdb[$i][5], // sessionid
388
									   $cpdb[$i][0], // start time
389
									   $radiusservers[0]['ipaddr'],
390
									   $radiusservers[0]['acctport'],
391
									   $radiusservers[0]['key']);
392
			}
393
			mwexec("/sbin/ipfw delete " . $cpdb[$i][1] . " " . ($cpdb[$i][1]+10000));
394
			unset($cpdb[$i]);
395
		}
396
	}
397

    
398
	/* write database */
399
	captiveportal_write_db($cpdb);
400

    
401
	captiveportal_unlock();
402
}
403

    
404
/* remove a single client by ipfw rule number */
405
function captiveportal_disconnect_client($id) {
406

    
407
	global $g, $config;
408

    
409
	captiveportal_lock();
410

    
411
	/* read database */
412
	$cpdb = captiveportal_read_db();
413
	$radiusservers = captiveportal_get_radius_servers();
414

    
415
	/* find entry */
416
	for ($i = 0; $i < count($cpdb); $i++) {
417
		if ($cpdb[$i][1] == $id) {
418
			/* this client needs to be deleted - remove ipfw rules */
419
			if (isset($config['captiveportal']['radacct_enable']) && isset($radiusservers[0])) {
420
				RADIUS_ACCOUNTING_STOP($cpdb[$i][1], // ruleno
421
									   $cpdb[$i][4], // username
422
									   $cpdb[$i][5], // sessionid
423
									   $cpdb[$i][0], // start time
424
									   $radiusservers[0]['ipaddr'],
425
									   $radiusservers[0]['acctport'],
426
									   $radiusservers[0]['key']);
427
			}
428
			mwexec("/sbin/ipfw delete " . $cpdb[$i][1] . " " . ($cpdb[$i][1]+10000));
429
			unset($cpdb[$i]);
430
			break;
431
		}
432
	}
433

    
434
	/* write database */
435
	captiveportal_write_db($cpdb);
436

    
437
	captiveportal_unlock();
438
}
439

    
440
/* send RADIUS acct stop for all current clients */
441
function captiveportal_radius_stop_all() {
442
	global $g, $config;
443

    
444
	captiveportal_lock() ;
445
	$cpdb = captiveportal_read_db() ;
446

    
447
	$radiusservers = captiveportal_get_radius_servers();
448

    
449
	if (isset($radiusservers[0])) {
450
		for ($i = 0; $i < count($cpdb); $i++) {
451
			RADIUS_ACCOUNTING_STOP($cpdb[$i][1], // ruleno
452
								   $cpdb[$i][4], // username
453
								   $cpdb[$i][5], // sessionid
454
								   $cpdb[$i][0], // start time
455
								   $radiusservers[0]['ipaddr'],
456
								   $radiusservers[0]['acctport'],
457
								   $radiusservers[0]['key']);
458
		}
459
	}
460
	captiveportal_unlock() ;
461
}
462

    
463
function captiveportal_passthrumac_configure() {
464
	global $config, $g;
465

    
466
	/* clear out passthru macs, if necessary */
467
	if (file_exists("{$g['vardb_path']}/captiveportal_mac.db")) {
468
		unlink("{$g['vardb_path']}/captiveportal_mac.db");
469
	}
470

    
471
	if (is_array($config['captiveportal']['passthrumac'])) {
472

    
473
		$fd = @fopen("{$g['vardb_path']}/captiveportal_mac.db", "w");
474
		if (!$fd) {
475
			printf("Error: cannot open passthru mac DB file in captiveportal_passthrumac_configure().\n");
476
			return 1;
477
		}
478

    
479
		foreach ($config['captiveportal']['passthrumac'] as $macent) {
480
			/* record passthru mac so it can be recognized and let thru */
481
			fwrite($fd, $macent['mac'] . "\n");
482
		}
483

    
484
		fclose($fd);
485
	}
486

    
487
	return 0;
488
}
489

    
490
function captiveportal_allowedip_configure() {
491
	global $config, $g;
492

    
493
	captiveportal_lock() ;
494

    
495
	/* clear out existing allowed ips, if necessary */
496
	if (file_exists("{$g['vardb_path']}/captiveportal_ip.db")) {
497
		$fd = @fopen("{$g['vardb_path']}/captiveportal_ip.db", "r");
498
		if ($fd) {
499
			while (!feof($fd)) {
500
				$line = trim(fgets($fd));
501
				if($line) {
502
					list($ip,$rule) = explode(",",$line);
503
					mwexec("/sbin/ipfw delete $rule") ;
504
				}
505
			}
506
		}
507
		fclose($fd) ;
508
		unlink("{$g['vardb_path']}/captiveportal_ip.db");
509
	}
510

    
511
	/* get next ipfw rule number */
512
	if (file_exists("{$g['vardb_path']}/captiveportal.nextrule"))
513
		$ruleno = trim(file_get_contents("{$g['vardb_path']}/captiveportal.nextrule"));
514
	if (!$ruleno)
515
		$ruleno = 10000;	/* first rule number */
516

    
517
	if (is_array($config['captiveportal']['allowedip'])) {
518

    
519
		$fd = @fopen("{$g['vardb_path']}/captiveportal_ip.db", "w");
520
		if (!$fd) {
521
			printf("Error: cannot open allowed ip DB file in captiveportal_allowedip_configure().\n");
522
			captiveportal_unlock() ;
523
			return 1;
524
		}
525

    
526
		foreach ($config['captiveportal']['allowedip'] as $ipent) {
527
			/* record allowed ip so it can be recognized and removed later */
528
			fwrite($fd, $ipent['ip'] . "," . $ruleno ."\n");
529
			/* insert ipfw rule to allow ip thru */
530
			if($ipent['dir'] == "from") {
531
				mwexec("/sbin/ipfw add $ruleno set 2 skipto 50000 ip from ".$ipent['ip']." to any in") ;
532
				mwexec("/sbin/ipfw add $ruleno set 2 skipto 50000 ip from any to ".$ipent['ip']." out") ;
533
			} else {
534
				mwexec("/sbin/ipfw add $ruleno set 2 skipto 50000 ip from any to ".$ipent['ip']." in") ;
535
				mwexec("/sbin/ipfw add $ruleno set 2 skipto 50000 ip from ".$ipent['ip']." to any out") ;
536
			}
537
			$ruleno++ ;
538
			if ($ruleno > 19899)
539
				$ruleno = 10000;
540
		}
541

    
542
		fclose($fd);
543

    
544
		/* write next rule number */
545
		$fd = @fopen("{$g['vardb_path']}/captiveportal.nextrule", "w");
546
		if ($fd) {
547
			fwrite($fd, $ruleno);
548
			fclose($fd);
549
		}
550
	}
551

    
552
	captiveportal_unlock() ;
553
	return 0;
554
}
555

    
556
/* get last activity timestamp given ipfw rule number */
557
function captiveportal_get_last_activity($ruleno) {
558

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

    
561
	/* in */
562
	if ($ipfwoutput[0]) {
563
		$ri = explode(" ", $ipfwoutput[0]);
564
		if ($ri[1])
565
			return $ri[1];
566
	}
567

    
568
	return 0;
569
}
570

    
571
/* read captive portal DB into array */
572
function captiveportal_read_db() {
573

    
574
	global $g;
575

    
576
	$cpdb = array();
577
	$fd = @fopen("{$g['vardb_path']}/captiveportal.db", "r");
578
	if ($fd) {
579
		while (!feof($fd)) {
580
			$line = trim(fgets($fd));
581
			if ($line) {
582
				$cpdb[] = explode(",", $line);
583
			}
584
		}
585
		fclose($fd);
586
	}
587
	return $cpdb;
588
}
589

    
590
/* write captive portal DB */
591
function captiveportal_write_db($cpdb) {
592

    
593
	global $g;
594

    
595
	$fd = @fopen("{$g['vardb_path']}/captiveportal.db", "w");
596
	if ($fd) {
597
		foreach ($cpdb as $cpent) {
598
			fwrite($fd, join(",", $cpent) . "\n");
599
		}
600
		fclose($fd);
601
	}
602
}
603

    
604
/* read RADIUS servers into array */
605
function captiveportal_get_radius_servers() {
606

    
607
	global $g;
608

    
609
	if (file_exists("{$g['vardb_path']}/captiveportal_radius.db")) {
610
	   	$fd = @fopen("{$g['vardb_path']}/captiveportal_radius.db","r");
611
		if ($fd) {
612
			$radiusservers = array();
613
			while (!feof($fd)) {
614
				$line = trim(fgets($fd));
615
				if ($line) {
616
					$radsrv = array();
617
					list($radsrv['ipaddr'],$radsrv['port'],$radsrv['acctport'],$radsrv['key']) = explode(",",$line);
618
					$radiusservers[] = $radsrv;
619
				}
620
			}
621
			fclose($fd);
622

    
623
			return $radiusservers;
624
		}
625
	}
626

    
627
	return false;
628
}
629

    
630
/* lock captive portal information, decide that the lock file is stale after
631
   10 seconds */
632
function captiveportal_lock() {
633

    
634
	global $g;
635

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

    
638
	$n = 0;
639
	while ($n < 10) {
640
		/* open the lock file in append mode to avoid race condition */
641
		if ($fd = @fopen($lockfile, "x")) {
642
			/* succeeded */
643
			fclose($fd);
644
			return;
645
		} else {
646
			/* file locked, wait and try again */
647
			sleep(1);
648
			$n++;
649
		}
650
	}
651
}
652

    
653
/* unlock configuration file */
654
function captiveportal_unlock() {
655

    
656
	global $g;
657

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

    
660
	if (file_exists($lockfile))
661
		unlink($lockfile);
662
}
663

    
664
?>
(1-1/14)