Project

General

Profile

Download (17.6 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
<head>
76
<title>m0n0wall captive portal</title>
77
</head>
78
<body>
79
<h2>m0n0wall captive portal</h2>
80
<p>This is the default captive portal page. Please upload your own custom HTML file on the <em>Services: Captive portal</em> screen in the m0n0wall webGUI.</p>
81
<form method="post" action="">
82
  <input name="accept" type="submit" value="Continue">
83
</form>
84
</body>
85
</html>
86

    
87
EOD;
88
		}
89

    
90
		$fd = @fopen("{$g['varetc_path']}/captiveportal.html", "w");
91
		if ($fd) {
92
			fwrite($fd, $htmltext);
93
			fclose($fd);	
94
		}
95
		
96
		/* write error page */
97
		if ($config['captiveportal']['page']['errtext'])
98
			$errtext = base64_decode($config['captiveportal']['page']['errtext']);
99
		else {
100
			/* example page */
101
			$errtext = <<<EOD
102
<html>
103
<head>
104
<title>Authentication error</title>
105
</head>
106
<body>
107
<font color="#cc0000"><h2>Authentication error</h2></font>
108
<b>
109
Username and/or password invalid.
110
<br><br>
111
<a href="javascript:history.back()">Go back</a>
112
</b>
113
</body>
114
</html>
115

    
116
EOD;
117
		}
118

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

    
125
		/* load rules */
126
		mwexec("/sbin/ipfw -f delete set 1");
127
		mwexec("/sbin/ipfw -f delete set 2");
128
		mwexec("/sbin/ipfw -f delete set 3");
129
		
130
		/* XXX - seems like ipfw cannot accept rules directly on stdin,
131
		   so we have to write them to a temporary file first */
132
		$fd = @fopen("{$g['tmp_path']}/ipfw.cp.rules", "w");
133
		if (!$fd) {
134
			printf("Cannot open ipfw.cp.rules in captiveportal_configure()\n");
135
			return 1;
136
		}
137
			
138
		fwrite($fd, $cprules);
139
		fclose($fd);
140
		
141
		mwexec("/sbin/ipfw {$g['tmp_path']}/ipfw.cp.rules");
142
		
143
		unlink("{$g['tmp_path']}/ipfw.cp.rules");
144
		
145
		/* filter on layer2 as well so we can check MAC addresses */
146
		mwexec("/sbin/sysctl net.link.ether.ipfw=1");
147
		
148
		chdir($g['captiveportal_path']);
149
		
150
		/* start web server */
151
		mwexec("/usr/local/sbin/mini_httpd -a -M 0 -u root -maxproc 16" .
152
			" -p 8000 -i {$g['varrun_path']}/mini_httpd.cp.pid");
153
		
154
		/* fire up another one for HTTPS if requested */
155
		if (isset($config['captiveportal']['httpslogin']) &&
156
			$config['captiveportal']['certificate'] && $config['captiveportal']['private-key']) {
157
			
158
			$cert = base64_decode($config['captiveportal']['certificate']);
159
			$key = base64_decode($config['captiveportal']['private-key']);
160
			
161
			$fd = fopen("{$g['varetc_path']}/cert-portal.pem", "w");
162
			if (!$fd) {
163
				printf("Error: cannot open cert-portal.pem in system_webgui_start().\n");
164
				return 1;
165
			}
166
			chmod("{$g['varetc_path']}/cert-portal.pem", 0600);
167
			fwrite($fd, $cert);
168
			fwrite($fd, "\n");
169
			fwrite($fd, $key);
170
			fclose($fd);
171
			
172
			mwexec("/usr/local/sbin/mini_httpd -S -a -M 0 -E {$g['varetc_path']}/cert-portal.pem" .
173
				" -u root -maxproc 16 -p 8001" .
174
				" -i {$g['varrun_path']}/mini_httpd.cps.pid");
175
		}
176
			
177
		/* start pruning process (interval = 60 seconds) */
178
		mwexec("/usr/local/bin/minicron 60 {$g['varrun_path']}/minicron.pid " .
179
			"/etc/rc.prunecaptiveportal");
180
		
181
		/* generate passthru mac database */
182
		captiveportal_passthrumac_configure() ;
183
		/* create allowed ip database and insert ipfw rules to make it so */
184
		captiveportal_allowedip_configure() ;
185

    
186
		/* generate radius server database */
187
		if($config['captiveportal']['radiusip']) {
188
			$radiusip = $config['captiveportal']['radiusip'] ;
189

    
190
			if($config['captiveportal']['radiusport'])
191
				$radiusport = $config['captiveportal']['radiusport'] ;
192
			else
193
				$radiusport = 1812;
194

    
195
			if($config['captiveportal']['radiusacctport'])
196
				$radiusacctport = $config['captiveportal']['radiusacctport'] ;
197
			else
198
				$radiusacctport = 1813;
199

    
200
			$radiuskey = $config['captiveportal']['radiuskey'];
201

    
202
			$fd = @fopen("{$g['vardb_path']}/captiveportal_radius.db", "w");
203
			if (!$fd) {
204
				printf("Error: cannot open radius DB file in captiveportal_configure().\n");
205
				return 1;
206
			} else {
207
				fwrite($fd,$radiusip . "," . $radiusport . "," . $radiusacctport . "," . $radiuskey) ;
208
			}
209
			fclose($fd) ;
210
		}
211

    
212

    
213
		if ($g['booting'])
214
			echo "done\n";
215
		
216
	} else {
217
		killbypid("{$g['varrun_path']}/mini_httpd.cp.pid");
218
		killbypid("{$g['varrun_path']}/minicron.pid");
219
		captiveportal_radius_stop_all() ;
220
		mwexec("/sbin/sysctl net.link.ether.ipfw=0");
221
		if (!isset($config['shaper']['enable'])) {
222
			/* unload ipfw */
223
			mwexec("/sbin/kldunload ipfw");
224
		} else {
225
			/* shaper is on - just remove our rules */
226
			mwexec("/sbin/ipfw -f delete set 1");
227
			mwexec("/sbin/ipfw -f delete set 2");
228
			mwexec("/sbin/ipfw -f delete set 3");
229
		}
230
	}
231
	
232
	return 0;
233
}
234

    
235
function captiveportal_rules_generate() {
236
	global $config, $g;
237
	
238
	$cpifn = $config['captiveportal']['interface'];
239
	$cpif = $config['interfaces'][$cpifn]['if'];
240
	$cpip = $config['interfaces'][$cpifn]['ipaddr'];
241

    
242
	/* note: the captive portal daemon inserts all pass rules for authenticated
243
	   clients as skipto 50000 rules to make traffic shaping work */
244

    
245
	$cprules = "";
246
	
247
	/* captive portal on LAN interface? */
248
	if ($cpifn == "lan") {
249
		/* add anti-lockout rules */
250
		$cprules .= <<<EOD
251
add 500 set 1 pass all from $cpip to any out via $cpif
252
add 501 set 1 pass all from any to $cpip in via $cpif
253

    
254
EOD;
255
	}
256

    
257
	$cprules .= <<<EOD
258
# skip to traffic shaper if not on captive portal interface
259
add 1000 set 1 skipto 50000 all from any to any not layer2 not via $cpif
260
# pass all layer2 traffic on other interfaces
261
add 1001 set 1 pass layer2 not via $cpif
262

    
263
# layer 2: pass ARP
264
add 1100 set 1 pass layer2 mac-type arp
265
# layer 2: block anything else non-IP
266
add 1101 set 1 deny layer2 not mac-type ip
267
# layer 2: check if MAC addresses of authenticated clients are correct
268
add 1102 set 1 skipto 20000 layer2
269

    
270
# allow access to our DHCP server (which needs to be able to ping clients as well)
271
add 1200 set 1 pass udp from any 68 to 255.255.255.255 67 in
272
add 1201 set 1 pass udp from any 68 to $cpip 67 in
273
add 1202 set 1 pass udp from $cpip 67 to any 68 out
274
add 1203 set 1 pass icmp from $cpip to any out icmptype 8
275
add 1204 set 1 pass icmp from any to $cpip in icmptype 0
276

    
277
# allow access to our DNS forwarder
278
add 1300 set 1 pass udp from any to $cpip 53 in
279
add 1301 set 1 pass udp from $cpip 53 to any out
280

    
281
# allow access to our web server
282
add 1302 set 1 pass tcp from any to $cpip 8000 in
283
add 1303 set 1 pass tcp from $cpip 8000 to any out
284

    
285
EOD;
286

    
287
	if (isset($config['captiveportal']['httpslogin'])) {
288
		$cprules .= <<<EOD
289
add 1304 set 1 pass tcp from any to $cpip 8001 in
290
add 1305 set 1 pass tcp from $cpip 8001 to any out
291

    
292
EOD;
293
	}
294
	
295
	$cprules .= <<<EOD
296

    
297
# ... 10000-19899: rules per authenticated client go here...
298

    
299
# redirect non-authenticated clients to captive portal
300
add 19900 set 1 fwd 127.0.0.1,8000 tcp from any to any 80 in
301
# let the responses from the captive portal web server back out
302
add 19901 set 1 pass tcp from any 80 to any out
303
# block everything else
304
add 19902 set 1 deny all from any to any
305

    
306
# ... 20000-29899: layer2 block rules per authenticated client go here...
307

    
308
# pass everything else on layer2
309
add 29900 set 1 pass all from any to any layer2
310

    
311
EOD;
312

    
313
	return $cprules;
314
}
315

    
316
/* remove clients that have been around for longer than the specified amount of time */
317
/* db file structure: timestamp,ipfw_rule_no,clientip,clientmac,username,sessionid */
318
function captiveportal_prune_old() {
319
	
320
	global $g, $config;
321
	
322
	/* check for expired entries */
323
	if ($config['captiveportal']['timeout'])
324
		$timeout = $config['captiveportal']['timeout'] * 60;
325
	else
326
		$timeout = 0;
327
		
328
	if ($config['captiveportal']['idletimeout'])
329
		$idletimeout = $config['captiveportal']['idletimeout'] * 60;
330
	else
331
		$idletimeout = 0;
332
	
333
	if (!$timeout && !$idletimeout)
334
		return;
335
	
336
	captiveportal_lock();
337
	
338
	/* read database */
339
	$cpdb = captiveportal_read_db();
340
	
341
	$radiusservers = captiveportal_get_radius_servers();
342
	
343
	for ($i = 0; $i < count($cpdb); $i++) {
344
		
345
		$timedout = false;
346
		
347
		/* hard timeout? */
348
		if ($timeout) {
349
			if ((time() - $cpdb[$i][0]) >= $timeout)
350
				$timedout = true;	
351
		}
352
		
353
		/* if an idle timeout is specified, get last activity timestamp from ipfw */
354
		if (!$timedout && $idletimeout) {
355
			$lastact = captiveportal_get_last_activity($cpdb[$i][1]);
356
			if ($lastact && ((time() - $lastact) >= $idletimeout))
357
				$timedout = true;
358
		}
359
		
360
		if ($timedout) {
361
			/* this client needs to be deleted - remove ipfw rules */
362
			if (isset($config['captiveportal']['radacct_enable']) && isset($radiusservers[0])) {
363
				RADIUS_ACCOUNTING_STOP($cpdb[$i][1], // ruleno
364
									   $cpdb[$i][4], // username
365
									   $cpdb[$i][5], // sessionid
366
									   $cpdb[$i][0], // start time
367
									   $radiusservers[0]['ipaddr'],
368
									   $radiusservers[0]['acctport'],
369
									   $radiusservers[0]['key']);
370
			}
371
			mwexec("/sbin/ipfw delete " . $cpdb[$i][1] . " " . ($cpdb[$i][1]+10000));
372
			unset($cpdb[$i]);
373
		}
374
	}
375
	
376
	/* write database */
377
	captiveportal_write_db($cpdb);
378
	
379
	captiveportal_unlock();
380
}
381

    
382
/* remove a single client by ipfw rule number */
383
function captiveportal_disconnect_client($id) {
384
	
385
	global $g, $config;
386
	
387
	captiveportal_lock();
388
	
389
	/* read database */
390
	$cpdb = captiveportal_read_db();
391
	$radiusservers = captiveportal_get_radius_servers();
392
	
393
	/* find entry */	
394
	for ($i = 0; $i < count($cpdb); $i++) {
395
		if ($cpdb[$i][1] == $id) {
396
			/* this client needs to be deleted - remove ipfw rules */
397
			if (isset($config['captiveportal']['radacct_enable']) && isset($radiusservers[0])) {
398
				RADIUS_ACCOUNTING_STOP($cpdb[$i][1], // ruleno
399
									   $cpdb[$i][4], // username
400
									   $cpdb[$i][5], // sessionid
401
									   $cpdb[$i][0], // start time
402
									   $radiusservers[0]['ipaddr'],
403
									   $radiusservers[0]['acctport'],
404
									   $radiusservers[0]['key']);
405
			}
406
			mwexec("/sbin/ipfw delete " . $cpdb[$i][1] . " " . ($cpdb[$i][1]+10000));
407
			unset($cpdb[$i]);
408
			break;
409
		}
410
	}
411
	
412
	/* write database */
413
	captiveportal_write_db($cpdb);
414
	
415
	captiveportal_unlock();
416
}
417

    
418
/* send RADIUS acct stop for all current clients */
419
function captiveportal_radius_stop_all() {
420
	global $g, $config;
421

    
422
	captiveportal_lock() ;
423
	$cpdb = captiveportal_read_db() ;
424
	
425
	$radiusservers = captiveportal_get_radius_servers();
426
	
427
	if (isset($radiusservers[0])) {
428
		for ($i = 0; $i < count($cpdb); $i++) {
429
			RADIUS_ACCOUNTING_STOP($cpdb[$i][1], // ruleno
430
								   $cpdb[$i][4], // username
431
								   $cpdb[$i][5], // sessionid
432
								   $cpdb[$i][0], // start time
433
								   $radiusservers[0]['ipaddr'],
434
								   $radiusservers[0]['acctport'],
435
								   $radiusservers[0]['key']);
436
		}
437
	}
438
	captiveportal_unlock() ;
439
}
440

    
441
function captiveportal_passthrumac_configure() {
442
	global $config, $g;
443
	
444
	/* clear out passthru macs, if necessary */
445
	if (file_exists("{$g['vardb_path']}/captiveportal_mac.db")) {
446
		unlink("{$g['vardb_path']}/captiveportal_mac.db");
447
	}
448
	
449
	if (is_array($config['captiveportal']['passthrumac'])) {
450
		
451
		$fd = @fopen("{$g['vardb_path']}/captiveportal_mac.db", "w");
452
		if (!$fd) {
453
			printf("Error: cannot open passthru mac DB file in captiveportal_passthrumac_configure().\n");
454
			return 1;		
455
		}
456
		
457
		foreach ($config['captiveportal']['passthrumac'] as $macent) {
458
			/* record passthru mac so it can be recognized and let thru */
459
			fwrite($fd, $macent['mac'] . "\n");
460
		}
461
		
462
		fclose($fd); 
463
	}
464
	
465
	return 0;
466
}
467

    
468
function captiveportal_allowedip_configure() {
469
	global $config, $g;
470
	
471
	captiveportal_lock() ;
472

    
473
	/* clear out existing allowed ips, if necessary */
474
	if (file_exists("{$g['vardb_path']}/captiveportal_ip.db")) {
475
		$fd = @fopen("{$g['vardb_path']}/captiveportal_ip.db", "r");
476
		if ($fd) {
477
			while (!feof($fd)) {
478
				$line = trim(fgets($fd));
479
				if($line) {
480
					list($ip,$rule) = explode(",",$line);
481
					mwexec("/sbin/ipfw delete $rule") ;
482
				}	
483
			}
484
		}
485
		fclose($fd) ;
486
		unlink("{$g['vardb_path']}/captiveportal_ip.db");
487
	}
488

    
489
	/* get next ipfw rule number */
490
	if (file_exists("{$g['vardb_path']}/captiveportal.nextrule"))
491
		$ruleno = trim(file_get_contents("{$g['vardb_path']}/captiveportal.nextrule"));
492
	if (!$ruleno)
493
		$ruleno = 10000;	/* first rule number */
494
	
495
	if (is_array($config['captiveportal']['allowedip'])) {
496
		
497
		$fd = @fopen("{$g['vardb_path']}/captiveportal_ip.db", "w");
498
		if (!$fd) {
499
			printf("Error: cannot open allowed ip DB file in captiveportal_allowedip_configure().\n");
500
			captiveportal_unlock() ;
501
			return 1;		
502
		}
503
		
504
		foreach ($config['captiveportal']['allowedip'] as $ipent) {
505
			/* record allowed ip so it can be recognized and removed later */
506
			fwrite($fd, $ipent['ip'] . "," . $ruleno ."\n");
507
			/* insert ipfw rule to allow ip thru */
508
			if($ipent['dir'] == "from") {
509
				mwexec("/sbin/ipfw add $ruleno set 2 skipto 50000 ip from ".$ipent['ip']." to any in") ;
510
				mwexec("/sbin/ipfw add $ruleno set 2 skipto 50000 ip from any to ".$ipent['ip']." out") ;
511
			} else {
512
				mwexec("/sbin/ipfw add $ruleno set 2 skipto 50000 ip from any to ".$ipent['ip']." in") ;
513
				mwexec("/sbin/ipfw add $ruleno set 2 skipto 50000 ip from ".$ipent['ip']." to any out") ;
514
			}
515
			$ruleno++ ;
516
			if ($ruleno > 19899)
517
				$ruleno = 10000;
518
		}
519
		
520
		fclose($fd); 
521

    
522
		/* write next rule number */
523
		$fd = @fopen("{$g['vardb_path']}/captiveportal.nextrule", "w");
524
		if ($fd) {
525
			fwrite($fd, $ruleno);
526
			fclose($fd);
527
		}
528
	}
529
	
530
	captiveportal_unlock() ;
531
	return 0;
532
}
533

    
534
/* get last activity timestamp given ipfw rule number */
535
function captiveportal_get_last_activity($ruleno) {
536
	
537
	exec("/sbin/ipfw -T list {$ruleno} 2>/dev/null", $ipfwoutput);
538
	
539
	/* in */
540
	if ($ipfwoutput[0]) {
541
		$ri = explode(" ", $ipfwoutput[0]);
542
		if ($ri[1])
543
			return $ri[1];
544
	}
545
	
546
	return 0;
547
}
548

    
549
/* read captive portal DB into array */
550
function captiveportal_read_db() {
551
	
552
	global $g;
553
	
554
	$cpdb = array();
555
	$fd = @fopen("{$g['vardb_path']}/captiveportal.db", "r");
556
	if ($fd) {
557
		while (!feof($fd)) {
558
			$line = trim(fgets($fd));
559
			if ($line) {
560
				$cpdb[] = explode(",", $line);
561
			}	
562
		}
563
		fclose($fd);
564
	}
565
	return $cpdb;
566
}
567

    
568
/* write captive portal DB */
569
function captiveportal_write_db($cpdb) {
570
	
571
	global $g;
572
	
573
	$fd = @fopen("{$g['vardb_path']}/captiveportal.db", "w");
574
	if ($fd) {
575
		foreach ($cpdb as $cpent) {
576
			fwrite($fd, join(",", $cpent) . "\n");
577
		}
578
		fclose($fd);
579
	}
580
}
581

    
582
/* read RADIUS servers into array */
583
function captiveportal_get_radius_servers() {
584
	
585
	global $g;
586
	
587
	if (file_exists("{$g['vardb_path']}/captiveportal_radius.db")) {
588
	   	$fd = @fopen("{$g['vardb_path']}/captiveportal_radius.db","r");
589
		if ($fd) {
590
			$radiusservers = array();
591
			while (!feof($fd)) {
592
				$line = trim(fgets($fd));
593
				if ($line) {
594
					$radsrv = array();
595
					list($radsrv['ipaddr'],$radsrv['port'],$radsrv['acctport'],$radsrv['key']) = explode(",",$line);
596
					$radiusservers[] = $radsrv;
597
				}
598
			}
599
			fclose($fd);
600
			
601
			return $radiusservers;
602
		}
603
	}
604
	
605
	return false;
606
}
607

    
608
/* lock captive portal information, decide that the lock file is stale after
609
   10 seconds */
610
function captiveportal_lock() {
611
	
612
	global $g;
613
	
614
	$lockfile = "{$g['varrun_path']}/captiveportal.lock";
615
	
616
	$n = 0;
617
	while ($n < 10) {
618
		/* open the lock file in append mode to avoid race condition */
619
		if ($fd = @fopen($lockfile, "x")) {
620
			/* succeeded */
621
			fclose($fd);
622
			return;
623
		} else {
624
			/* file locked, wait and try again */
625
			sleep(1);
626
			$n++;
627
		}
628
	}
629
}
630

    
631
/* unlock configuration file */
632
function captiveportal_unlock() {
633
	
634
	global $g;
635
	
636
	$lockfile = "{$g['varrun_path']}/captiveportal.lock";
637
	
638
	if (file_exists($lockfile))
639
		unlink($lockfile);
640
}
641

    
642
?>
(1-1/13)