Project

General

Profile

« Previous | Next » 

Revision 0bd34ed6

Added by Scott Ullrich over 19 years ago

Sync w/ m0n0wall 1.21

View differences:

etc/inc/captiveportal.inc
3 3
	captiveportal.inc
4 4
	part of m0n0wall (http://m0n0.ch/wall)
5 5
	
6
	Copyright (C) 2003-2005 Manuel Kasper <mk@neon1.net>.
6
	Copyright (C) 2003-2006 Manuel Kasper <mk@neon1.net>.
7 7
	All rights reserved.
8 8
	
9 9
	Redistribution and use in source and binary forms, with or without
......
37 37
/* include all configuration functions */
38 38
require_once("functions.inc");
39 39
require_once("radius_authentication.inc");
40
require_once("radius_accounting.inc") ;
40
require_once("radius_accounting.inc");
41

  
42
$lockfile = "{$g['varrun_path']}/captiveportal.lock";
41 43

  
42 44
function captiveportal_configure() {
43 45
	global $config, $g;
......
65 67
		/* stop accounting on all clients */
66 68
		captiveportal_radius_stop_all();
67 69

  
70
		/* initialize minicron interval value */
71
		$croninterval = $config['captiveportal']['croninterval'] ? $config['captiveportal']['croninterval'] : 60;
72

  
73
		/* double check if the $croninterval is numeric and at least 10 seconds. If not we set it to 60 to avoid problems */
74
		if ((!is_numeric($croninterval)) || ($croninterval < 10)) { $croninterval = 60; }
75

  
68 76
		/* remove old information */
69 77
		unlink_if_exists("{$g['vardb_path']}/captiveportal.nextrule");
70 78
		unlink_if_exists("{$g['vardb_path']}/captiveportal.db");
......
95 103
   <tr><td>&nbsp;</td></tr>
96 104
   <tr>
97 105
     <td colspan="2">
98
	<center><input name="accept" type="submit" value="Continue"></center>	
106
	<center><input name="accept" type="submit" value="Continue"></center>
99 107
     </td>
100 108
   </tr>
101 109
</table>
......
104 112
</body>
105 113
</html>
106 114

  
115

  
116

  
107 117
EOD;
108 118
		}
109 119

  
......
141 151
			fwrite($fd, $errtext);
142 152
			fclose($fd);	
143 153
		}
154
		
155
		/* write elements */
156
		captiveportal_write_elements();
144 157

  
145 158
		/* load rules */
146 159
		mwexec("/sbin/ipfw -f delete set 1");
......
166 179
		mwexec("/sbin/sysctl net.link.ether.ipfw=1");
167 180
		
168 181
		chdir($g['captiveportal_path']);
169

  
170
		$memory = get_memory();
171
		$avail = $memory[0];
172
		if($avail > 0 and $avail < 60) {
173
			$procs = 16;
174
		} else if($avail > 60 and $avail < 120) {
175
			$procs = 24;
176
		} else if($avail > 120 and $avail < 160) {
177
			$procs = 32;
178
		} else if($avail > 160 and $avail < 250) {
179
			$procs = 48;
180
		} else if($avail > 250 and $avail < 380) {
181
			$procs = 56;
182
		} else if($avail > 380 and $avail < 500) {
183
			$procs = 72;
184
		} else if($avail > 500 and $avail < 680) {
185
			$procs = 80;
186
		} else {
187
			$procs = 16;
188
		}	
189 182
	
190 183
		/* TEMPORARY!  FAST_CGI reports _FALSE_ client ip
191 184
		 * 	       addresses.
......
196 189
			$cert = base64_decode($config['captiveportal']['certificate']);
197 190
			$key = base64_decode($config['captiveportal']['private-key']);
198 191
		}
192
		
193
		if ($config['captiveportal']['maxproc'])
194
			$maxproc = $config['captiveportal']['maxproc'];
195
		else
196
			$maxproc = 16;
199 197

  
200 198
		/* generate lighttpd configuration */
201 199
		system_generate_lighty_config("{$g['varetc_path']}/lighty-CaptivePortal.conf",
202 200
			$cert, $key, "lighty-CaptivePortal.pid", "8000", "/usr/local/captiveportal/",
203 201
				"cert-portal.pem", "1", $procs, $use_fastcgi, true);
204
	
202
					
205 203
		/* attempt to start lighttpd */
206 204
		$res = mwexec("/usr/local/sbin/lighttpd -f {$g['varetc_path']}/lighty-CaptivePortal.conf");
207
			
208
		/* start pruning process (interval = 60 seconds) */
209
		mwexec("/usr/local/bin/minicron 60 {$g['varrun_path']}/minicron.pid " .
205
		
206
		/* start pruning process (interval defaults to 60 seconds) */
207
		mwexec("/usr/local/bin/minicron $croninterval {$g['varrun_path']}/minicron.pid " .
210 208
			"/etc/rc.prunecaptiveportal");
211 209
		
212 210
		/* generate passthru mac database */
213 211
		captiveportal_passthrumac_configure();
214 212
		/* create allowed ip database and insert ipfw rules to make it so */
215 213
		captiveportal_allowedip_configure();
216

  
214
		
217 215
		/* generate radius server database */
218 216
		if ($config['captiveportal']['radiusip'] && (!isset($config['captiveportal']['auth_method']) ||
219 217
				($config['captiveportal']['auth_method'] == "radius"))) {
220 218
			$radiusip = $config['captiveportal']['radiusip'];
219
			$radiusip2 = ($config['captiveportal']['radiusip2']) ? $config['captiveportal']['radiusip2'] : null;
221 220

  
222 221
			if ($config['captiveportal']['radiusport'])
223 222
				$radiusport = $config['captiveportal']['radiusport'];
......
229 228
			else
230 229
				$radiusacctport = 1813;
231 230

  
231
			if ($config['captiveportal']['radiusport2'])
232
				$radiusport2 = $config['captiveportal']['radiusport2'];
233
			else
234
				$radiusport2 = 1812;
235

  
232 236
			$radiuskey = $config['captiveportal']['radiuskey'];
237
			$radiuskey2 = ($config['captiveportal']['radiuskey2']) ? $config['captiveportal']['radiuskey2'] : null;
233 238

  
234 239
			$fd = @fopen("{$g['vardb_path']}/captiveportal_radius.db", "w");
235 240
			if (!$fd) {
236 241
				printf("Error: cannot open radius DB file in captiveportal_configure().\n");
237 242
				return 1;
243
			} else if (isset($radiusip2, $radiuskey2)) {
244
				fwrite($fd,$radiusip . "," . $radiusport . "," . $radiusacctport . "," . $radiuskey . "\n"
245
					 . $radiusip2 . "," . $radiusport2 . "," . $radiusacctport . "," . $radiuskey2);
238 246
			} else {
239 247
				fwrite($fd,$radiusip . "," . $radiusport . "," . $radiusacctport . "," . $radiuskey);
240 248
			}
......
292 300
		$int = convert_friendly_interface_to_real_interface_name($ifname);
293 301
		$cprules .= "add 30 set 1 skipto 50000 all from any to any in via {$int} keep-state\n";
294 302
	}
295

  
303
	
296 304
	/* captive portal on LAN interface? */
297 305
	if ($cpifn == "lan") {
298 306
		/* add anti-lockout rules */
299 307
		$cprules .= <<<EOD
300
add 500 pass all from $cpip to any out via $cpif
308
add 500 set 1 pass all from $cpip to any out via $cpif
301 309
add 501 set 1 pass all from any to $cpip in via $cpif
302 310

  
303 311
EOD;
......
363 371
}
364 372

  
365 373
/* remove clients that have been around for longer than the specified amount of time */
366
/* db file structure: timestamp,ipfw_rule_no,clientip,clientmac,username,sessionid,password */
374
/* db file structure: 
375
timestamp,ipfw_rule_no,clientip,clientmac,username,sessionid,password,session_timeout,idle_timeout,session_terminate_time */
376

  
367 377
/* (password is in Base64 and only saved when reauthentication is enabled) */
368 378
function captiveportal_prune_old() {
369 379
	
370 380
	global $g, $config;
371
	
381

  
372 382
	/* check for expired entries */
373 383
	if ($config['captiveportal']['timeout'])
374 384
		$timeout = $config['captiveportal']['timeout'] * 60;
......
393 403
	for ($i = 0; $i < count($cpdb); $i++) {
394 404
		
395 405
		$timedout = false;
406
		$term_cause = 1;
396 407
		
397 408
		/* hard timeout? */
398 409
		if ($timeout) {
399
			if ((time() - $cpdb[$i][0]) >= $timeout)
400
				$timedout = true;	
410
			if ((time() - $cpdb[$i][0]) >= $timeout) {
411
				$timedout = true;
412
				$term_cause = 5; // Session-Timeout
413
			}
414
		}
415

  
416
		/* Session-Terminate-Time */
417
		if (!$timedout && !empty($cpdb[$i][9])) {
418
			if (time() >= $cpdb[$i][9]) {
419
				$timedout = true;
420
				$term_cause = 5; // Session-Timeout
421
			}
401 422
		}
402 423
		
424
		/* check if the radius idle_timeout attribute has been set and if its set change the idletimeout to this value */
425
		$idletimeout = (is_numeric($cpdb[$i][8])) ? $cpdb[$i][8] : $idletimeout;
403 426
		/* if an idle timeout is specified, get last activity timestamp from ipfw */
404 427
		if (!$timedout && $idletimeout) {
405 428
			$lastact = captiveportal_get_last_activity($cpdb[$i][1]);
406
			if ($lastact && ((time() - $lastact) >= $idletimeout))
429
			if ($lastact && ((time() - $lastact) >= $idletimeout)) {
430
				$timedout = true;
431
				$term_cause = 4; // Idle-Timeout
432
				$stop_time = $lastact; // Entry added to comply with WISPr
433
			}
434
		}
435

  
436
		/* if radius session_timeout is enabled and the session_timeout is not null, then check if the user should be logged out */
437
		if (!$timedout && isset($config['captiveportal']['radiussession_timeout']) && !empty($cpdb[$i][7])) {
438
			if (time() >= ($cpdb[$i][0] + $cpdb[$i][7])) {
407 439
				$timedout = true;
440
				$term_cause = 5; // Session-Timeout
441
			}
408 442
		}
409 443
		
410 444
		if ($timedout) {
411
			captiveportal_disconnect($cpdb[$i], $radiusservers);
445
			captiveportal_disconnect($cpdb[$i], $radiusservers,$term_cause,$stop_time);
412 446
			captiveportal_logportalauth($cpdb[$i][4], $cpdb[$i][3], $cpdb[$i][2], "TIMEOUT");
413 447
			unset($cpdb[$i]);
414 448
		}
......
427 461
										   $radiusservers[0]['ipaddr'],
428 462
										   $radiusservers[0]['acctport'],
429 463
										   $radiusservers[0]['key'],
430
										   $cpdb[$i][2]); //clientip
464
										   $cpdb[$i][2], // clientip
465
										   $cpdb[$i][3], // clientmac
466
										   10); // NAS Request
431 467
					exec("/sbin/ipfw zero {$cpdb[$i][1]}");
432
					RADIUS_ACCOUNTING_START($cpdb[$i][4],
433
											$cpdb[$i][5],
468
					RADIUS_ACCOUNTING_START($cpdb[$i][1], // ruleno
469
											$cpdb[$i][4], // username
470
											$cpdb[$i][5], // sessionid
434 471
											$radiusservers[0]['ipaddr'],
435 472
											$radiusservers[0]['acctport'],
436 473
											$radiusservers[0]['key'],
437
											$cpdb[$i][2]);
474
											$cpdb[$i][2], // clientip
475
											$cpdb[$i][3]); // clientmac
438 476
				} else if ($config['captiveportal']['reauthenticateacct'] == "interimupdate") {
439 477
					RADIUS_ACCOUNTING_STOP($cpdb[$i][1], // ruleno
440 478
										   $cpdb[$i][4], // username
......
443 481
										   $radiusservers[0]['ipaddr'],
444 482
										   $radiusservers[0]['acctport'],
445 483
										   $radiusservers[0]['key'],
446
										   $cpdb[$i][2], //clientip
447
										   true);
484
										   $cpdb[$i][2], // clientip
485
										   $cpdb[$i][3], // clientmac
486
										   10, // NAS Request
487
										   true); // Interim Updates
448 488
				}
449 489
			}
450 490
		
451 491
			/* check this user against RADIUS again */
452
			$auth_val = RADIUS_AUTHENTICATION($cpdb[$i][4],
453
										  base64_decode($cpdb[$i][6]),
454
							  			  $radiusservers[0]['ipaddr'],
455
							  			  $radiusservers[0]['port'],
456
							  			  $radiusservers[0]['key']);
492
			$auth_list = RADIUS_AUTHENTICATION($cpdb[$i][4], // username
493
										  base64_decode($cpdb[$i][6]), // password
494
							  			  $radiusservers,
495
										  $cpdb[$i][2], // clientip
496
										  $cpdb[$i][3], // clientmac
497
										  $cpdb[$i][1]); // ruleno
457 498
			
458
			if ($auth_val == 3) {
459
				captiveportal_disconnect($cpdb[$i], $radiusservers);
460
				captiveportal_logportalauth($cpdb[$i][4], $cpdb[$i][3], $cpdb[$i][2], "RADIUS_DISCONNECT");
499
			if ($auth_list['auth_val'] == 3) {
500
				captiveportal_disconnect($cpdb[$i], $radiusservers, 17);
501
				captiveportal_logportalauth($cpdb[$i][4], $cpdb[$i][3], $cpdb[$i][2], "RADIUS_DISCONNECT", $auth_list['reply_message']);
461 502
				unset($cpdb[$i]);
462 503
			}
463 504
		}
......
470 511
}
471 512

  
472 513
/* remove a single client according to the DB entry */
473
function captiveportal_disconnect($dbent, $radiusservers) {
514
function captiveportal_disconnect($dbent, $radiusservers,$term_cause = 1,$stop_time = null) {
474 515
	
475 516
	global $g, $config;
517

  
518
	$stop_time = (empty($stop_time)) ? time() : $stop_time;
476 519
	
477 520
	/* this client needs to be deleted - remove ipfw rules */
478 521
	if (isset($config['captiveportal']['radacct_enable']) && isset($radiusservers[0])) {
......
483 526
							   $radiusservers[0]['ipaddr'],
484 527
							   $radiusservers[0]['acctport'],
485 528
							   $radiusservers[0]['key'],
486
							   $dbent[2]); //clientip
529
							   $dbent[2], // clientip
530
							   $dbent[3], // clientmac
531
							   $term_cause, // Acct-Terminate-Cause
532
							   false,
533
							   $stop_time);
487 534
	}
488 535
	
489 536
	mwexec("/sbin/ipfw delete " . $dbent[1] . " " . ($dbent[1]+10000));
......
498 545
}
499 546

  
500 547
/* remove a single client by ipfw rule number */
501
function captiveportal_disconnect_client($id) {
548
function captiveportal_disconnect_client($id,$term_cause = 1) {
502 549
	
503 550
	global $g, $config;
504 551
	
......
511 558
	/* find entry */	
512 559
	for ($i = 0; $i < count($cpdb); $i++) {
513 560
		if ($cpdb[$i][1] == $id) {
514
			captiveportal_disconnect($cpdb[$i], $radiusservers);
561
			captiveportal_disconnect($cpdb[$i], $radiusservers, $term_cause);
515 562
			captiveportal_logportalauth($cpdb[$i][4], $cpdb[$i][3], $cpdb[$i][2], "DISCONNECT");
516 563
			unset($cpdb[$i]);
517 564
			break;
......
527 574
/* send RADIUS acct stop for all current clients */
528 575
function captiveportal_radius_stop_all() {
529 576
	global $g, $config;
577
	
578
	if (!isset($config['captiveportal']['radacct_enable']))
579
		return;
530 580

  
531 581
	captiveportal_lock();
532 582
	$cpdb = captiveportal_read_db();
......
542 592
								   $radiusservers[0]['ipaddr'],
543 593
								   $radiusservers[0]['acctport'],
544 594
								   $radiusservers[0]['key'],
545
								   $cpdb[$i][2]); //clientip
595
								   $cpdb[$i][2], // clientip
596
								   $cpdb[$i][3], // clientmac
597
								   7); // Admin Reboot
546 598
		}
547 599
	}
548 600
	captiveportal_unlock();
......
572 624
		
573 625
		fclose($fd); 
574 626
	}
575
	
627

  
576 628
	/*    pass through mac entries should always exist.  the reason
577 629
	 *    for this is because we do not have native mac address filtering
578 630
         *    mechanisms.  this allows us to filter by mac address easily
......
589 641
			mwexec("/sbin/ipfw add 50 skipto 29900 ip from any to any MAC any {$ptm['mac']} keep-state");
590 642
		}
591 643
	}
592
	
644

  
593 645
	captiveportal_unlock();
594 646
	
595 647
	return 0;
......
679 731
	return 0;
680 732
}
681 733

  
682
/* read captive portal DB into array */
683
function captiveportal_read_db() {
684
	
685
	global $g;
686
	
687
	$cpdb = array();
688
	$fd = @fopen("{$g['vardb_path']}/captiveportal.db", "r");
689
	if ($fd) {
690
		while (!feof($fd)) {
691
			$line = trim(fgets($fd));
692
			if ($line) {
693
				$cpdb[] = explode(",", $line);
694
			}	
695
		}
696
		fclose($fd);
697
	}
698
	return $cpdb;
699
}
700

  
701
/* write captive portal DB */
702
function captiveportal_write_db($cpdb) {
703
	
704
	global $g;
705
	
706
	$fd = @fopen("{$g['vardb_path']}/captiveportal.db", "w");
707
	if ($fd) {
708
		foreach ($cpdb as $cpent) {
709
			fwrite($fd, join(",", $cpent) . "\n");
710
		}
711
		fclose($fd);
712
	}
713
}
714

  
715 734
/* read RADIUS servers into array */
716 735
function captiveportal_get_radius_servers() {
717
	
718
	global $g;
719
	
720
	if (file_exists("{$g['vardb_path']}/captiveportal_radius.db")) {
721
	   	$fd = @fopen("{$g['vardb_path']}/captiveportal_radius.db","r");
722
		if ($fd) {
723
			$radiusservers = array();
724
			while (!feof($fd)) {
725
				$line = trim(fgets($fd));
726
				if ($line) {
727
					$radsrv = array();
728
					list($radsrv['ipaddr'],$radsrv['port'],$radsrv['acctport'],$radsrv['key']) = explode(",",$line);
729
					$radiusservers[] = $radsrv;
730
				}
731
			}
732
			fclose($fd);
733
			
734
			return $radiusservers;
735
		}
736
	}
737
	
738
	return false;
736

  
737
        global $g;
738

  
739
        if (file_exists("{$g['vardb_path']}/captiveportal_radius.db")) {
740
                $fd = @fopen("{$g['vardb_path']}/captiveportal_radius.db","r");
741
                if ($fd) {
742
                        $radiusservers = array();
743
                        while (!feof($fd)) {
744
                                $line = trim(fgets($fd));
745
                                if ($line) {
746
                                        $radsrv = array();
747
                                        list($radsrv['ipaddr'],$radsrv['port'],$radsrv['acctport'],$radsrv['key']) = explode(",",$line);
748
                                        $radiusservers[] = $radsrv;
749
                                }
750
                        }
751
                        fclose($fd);
752

  
753
                        return $radiusservers;
754
                }
755
        }
756

  
757
        return false;
739 758
}
740 759

  
741 760
/* lock captive portal information, decide that the lock file is stale after
742 761
   10 seconds */
743 762
function captiveportal_lock() {
744
	
745
	global $g;
746
	
747
	$lockfile = "{$g['varrun_path']}/captiveportal.lock";
748
	
749
	$n = 0;
750
	while ($n < 10) {
751
		/* open the lock file in append mode to avoid race condition */
752
		if ($fd = @fopen($lockfile, "x")) {
753
			/* succeeded */
754
			fclose($fd);
755
			return;
756
		} else {
757
			/* file locked, wait and try again */
758
			sleep(1);
759
			$n++;
760
		}
761
	}
763

  
764
        global $lockfile;
765

  
766
        $n = 0;
767
        while ($n < 10) {
768
                /* open the lock file in append mode to avoid race condition */
769
                if ($fd = @fopen($lockfile, "x")) {
770
                        /* succeeded */
771
                        fclose($fd);
772
                        return;
773
                } else {
774
                        /* file locked, wait and try again */
775
                        sleep(1);
776
                        $n++;
777
                }
778
        }
762 779
}
763 780

  
764
/* unlock configuration file */
781
/* unlock captive portal information file */
765 782
function captiveportal_unlock() {
766
	
767
	global $g;
768
	
769
	$lockfile = "{$g['varrun_path']}/captiveportal.lock";
770
	
771
	if (file_exists($lockfile))
772
		unlink($lockfile);
783

  
784
        global $lockfile;
785

  
786
        if (file_exists($lockfile))
787
                unlink($lockfile);
773 788
}
774 789

  
775 790
/* log successful captive portal authentication to syslog */
776 791
/* part of this code from php.net */
777
function captiveportal_logportalauth($user,$mac,$ip,$status) {
792
function captiveportal_logportalauth($user,$mac,$ip,$status, $message = null) {
778 793
	define_syslog_variables();
794
	$message = trim($message);
779 795
	openlog("logportalauth", LOG_PID, LOG_LOCAL4);
780 796
	// Log it
797
	if (!$message)
781 798
	syslog(LOG_INFO, "$status: $user, $mac, $ip");
799
	else
800
	syslog(LOG_INFO, "$status: $user, $mac, $ip, $message");
782 801
	closelog();
783 802
}
784 803

  
804
function radius($username,$password,$clientip,$clientmac,$type) {
805
	global $g, $config;
806

  
807
	$next_ruleno = get_next_ipfw_ruleno();
808
	$radiusservers = captiveportal_get_radius_servers();
809
	$radacct_enable = isset($config['captiveportal']['radacct_enable']);
810

  
811
	$auth_list = RADIUS_AUTHENTICATION($username,
812
					$password,
813
					$radiusservers,
814
					$clientip,
815
					$clientmac,
816
					$next_ruleno);
817

  
818
	if ($auth_list['auth_val'] == 2) {
819
		captiveportal_logportalauth($username,$clientmac,$clientip,$type);
820
		$sessionid = portal_allow($clientip,
821
					$clientmac,
822
					$username,
823
					$password,
824
					$auth_list['session_timeout'],
825
					$auth_list['idle_timeout'],
826
					$auth_list['url_redirection'],
827
					$auth_list['session_terminate_time']);
828

  
829
		if ($radacct_enable) {
830
			$auth_list['acct_val'] = RADIUS_ACCOUNTING_START($next_ruleno,
831
									$username,
832
									$sessionid,
833
									$radiusservers[0]['ipaddr'],
834
									$radiusservers[0]['acctport'],
835
									$radiusservers[0]['key'],
836
									$clientip,
837
									$clientmac);
838
			if ($auth_list['acct_val'] == 1) 
839
				captiveportal_logportalauth($username,$clientmac,$clientip,$type,"RADIUS ACCOUNTING FAILED");
840
		}
841
	}
842

  
843
	return $auth_list;
844

  
845
}
846

  
847
/* read captive portal DB into array */
848
function captiveportal_read_db() {
849

  
850
        global $g;
851

  
852
        $cpdb = array();
853
        $fd = @fopen("{$g['vardb_path']}/captiveportal.db", "r");
854
        if ($fd) {
855
                while (!feof($fd)) {
856
                        $line = trim(fgets($fd));
857
                        if ($line) {
858
                                $cpdb[] = explode(",", $line);
859
                        }
860
                }
861
                fclose($fd);
862
        }
863
        return $cpdb;
864
}
865

  
866
/* write captive portal DB */
867
function captiveportal_write_db($cpdb) {
868
                 
869
        global $g;
870
                
871
        $fd = @fopen("{$g['vardb_path']}/captiveportal.db", "w");
872
        if ($fd) { 
873
                foreach ($cpdb as $cpent) {
874
                        fwrite($fd, join(",", $cpent) . "\n");
875
                }       
876
                fclose($fd);
877
        }       
878
}
879

  
880
function captiveportal_write_elements() {
881
	global $g, $config;
882
	
883
	/* delete any existing elements */
884
	if (is_dir($g['captiveportal_element_path'])) {
885
		$dh = opendir($g['captiveportal_element_path']);
886
		while (($file = readdir($dh)) !== false) {
887
			if ($file != "." && $file != "..")
888
				unlink($g['captiveportal_element_path'] . "/" . $file);
889
		}
890
		closedir($dh);
891
	} else {
892
		mkdir($g['captiveportal_element_path']);
893
	}
894
	
895
	if (is_array($config['captiveportal']['element'])) {
896
	
897
		foreach ($config['captiveportal']['element'] as $data) {
898
			$fd = @fopen($g['captiveportal_element_path'] . '/' . $data['name'], "wb");
899
			if (!$fd) {
900
				printf("Error: cannot open '{$data['name']}' in captiveportal_write_elements().\n");
901
				return 1;
902
			}
903
			$decoded = base64_decode($data['content']);
904
			fwrite($fd,$decoded);
905
			fclose($fd);
906
		}
907
	}
908
	
909
	return 0;
910
}
911

  
785 912
?>
etc/inc/radius.inc
1
<?php
2
/* vim: set expandtab tabstop=4 shiftwidth=4: */
3
/*
4
Copyright (c) 2003, Michael Bretterklieber <michael@bretterklieber.com>
5
All rights reserved.
6

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

  
11
1. Redistributions of source code must retain the above copyright 
12
   notice, this list of conditions and the following disclaimer.
13
2. Redistributions in binary form must reproduce the above copyright 
14
   notice, this list of conditions and the following disclaimer in the 
15
   documentation and/or other materials provided with the distribution.
16
3. The names of the authors may not be used to endorse or promote products 
17
   derived from this software without specific prior written permission.
18

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

  
30
This code cannot simply be copied and put under the GNU Public License or 
31
any other GPL-like (LGPL, GPL2) License.
32

  
33
    $Id$
34

  
35
    This version of RADIUS.php has been modified by
36
    Jonathan De Graeve <jonathan@imelda.be> to integrate with M0n0wall <http://www.m0n0.ch/wall>
37

  
38
    $Id_jdg: 2005/12/22 14:22:42
39

  
40
    Changes made include:
41
    * StandardAttributes for M0n0wall use
42
    * Removed internal Session-Id creation
43
    * Adding of ReplyMessage to getAttributes()
44
    * Adding of listAttributes()
45
    * Adding of VENDOR Bay Networks (Nortel)
46
    * Adding of VENDOR Nomadix
47
    * Adding of VENDOR WISPr (Wi-Fi Alliance)
48
    
49
*/
50

  
51
require_once("PEAR.inc");
52

  
53
/**
54
* Client implementation of RADIUS. This are wrapper classes for
55
* the RADIUS PECL. 
56
* Provides RADIUS Authentication (RFC2865) and RADIUS Accounting (RFC2866).
57
*
58
* @package Auth_RADIUS
59
* @author  Michael Bretterklieber <michael@bretterklieber.com>
60
* @access  public
61
* @version $Revision$
62
*/
63

  
64
PEAR::loadExtension('radius');
65

  
66
/**
67
 * class Auth_RADIUS
68
 *
69
 * Abstract base class for RADIUS
70
 *
71
 * @package Auth_RADIUS 
72
 */
73
class Auth_RADIUS extends PEAR {
74

  
75
    /**
76
     * List of RADIUS servers.
77
     * @var  array
78
     * @see  addServer(), putServer()
79
     */
80
    var $_servers  = array();
81
    
82
    /**
83
     * Path to the configuration-file.
84
     * @var  string
85
     * @see  setConfigFile()
86
     */
87
    var $_configfile = null;
88
    
89
    /**
90
     * Resource.
91
     * @var  resource
92
     * @see  open(), close()
93
     */
94
    var $res = null;
95
    
96
    /**
97
     * Username for authentication and accounting requests.
98
     * @var  string
99
     */
100
    var $username = null;
101

  
102
    /**
103
     * Password for plaintext-authentication (PAP).
104
     * @var  string
105
     */
106
    var $password = null;
107

  
108
    /**
109
     * List of known attributes.
110
     * @var  array
111
     * @see  dumpAttributes(), getAttributes()
112
     */
113
    var $attributes = array();
114
    
115
    /**
116
     * List of raw attributes.
117
     * @var  array
118
     * @see  dumpAttributes(), getAttributes()
119
     */
120
    var $rawAttributes = array();
121

  
122
    /**
123
     * List of raw vendor specific attributes.
124
     * @var  array
125
     * @see  dumpAttributes(), getAttributes()
126
     */
127
    var $rawVendorAttributes = array();    
128
    
129
    /**
130
     * Constructor
131
     *
132
     * Loads the RADIUS PECL/extension
133
     *
134
     * @return void
135
     */
136
    function Auth_RADIUS() 
137
    {
138
        $this->PEAR();
139
    }
140
    
141
    /**
142
     * Adds a RADIUS server to the list of servers for requests.
143
     *
144
     * At most 10 servers may be specified.	When multiple servers 
145
     * are given, they are tried in round-robin fashion until a 
146
     * valid response is received
147
     *
148
     * @access public
149
     * @param  string  $servername   Servername or IP-Address
150
     * @param  integer $port         Portnumber
151
     * @param  string  $sharedSecret Shared secret
152
     * @param  integer $timeout      Timeout for each request
153
     * @param  integer $maxtries     Max. retries for each request          
154
     * @return void
155
     */
156
    function addServer($servername = 'localhost', $port = 0, $sharedSecret = 'testing123', $timeout = 5, $maxtries = 3) 
157
    {
158
        $this->_servers[] = array($servername, $port, $sharedSecret, $timeout, $maxtries);    
159
    }
160
    
161
    /**
162
     * Returns an error message, if an error occurred.
163
     *
164
     * @access public
165
     * @return string
166
     */
167
    function getError() 
168
    {
169
        return radius_strerror($this->res);
170
    }
171
    
172
    /**
173
     * Sets the configuration-file.
174
     *
175
     * @access public
176
     * @param  string  $file Path to the configuration file    
177
     * @return void
178
     */    
179
    function setConfigfile($file) 
180
    {
181
        $this->_configfile = $file;
182
    }
183

  
184
    /**
185
     * Puts an attribute.
186
     *
187
     * @access public
188
     * @param  integer $attrib       Attribute-number
189
     * @param  mixed   $port         Attribute-value
190
     * @param  type    $type         Attribute-type
191
     * @return bool  true on success, false on error
192
     */    
193
    function putAttribute($attrib, $value, $type = null) 
194
    {
195
        if ($type == null) {
196
            $type = gettype($value);
197
        }
198

  
199
        switch ($type) {
200
        case 'integer':
201
            return radius_put_int($this->res, $attrib, $value);
202
        
203
        case 'addr':
204
            return radius_put_addr($this->res, $attrib, $value);
205
            
206
        case 'string':
207
        default:
208
            return radius_put_attr($this->res, $attrib, $value);
209
        }
210

  
211
    }
212
    
213
    /**
214
     * Puts a vendor-specific attribute.
215
     *
216
     * @access public
217
     * @param  integer $vendor       Vendor (MSoft, Cisco, ...)
218
     * @param  integer $attrib       Attribute-number
219
     * @param  mixed   $port         Attribute-value
220
     * @param  type    $type         Attribute-type
221
     * @return bool  true on success, false on error
222
     */ 
223
    function putVendorAttribute($vendor, $attrib, $value, $type = null) 
224
    {
225
        
226
        if ($type == null) {
227
            $type = gettype($value);
228
        }
229
        
230
        switch ($type) {
231
        case 'integer':
232
            return radius_put_vendor_int($this->res, $vendor, $attrib, $value);
233
        
234
        case 'addr':
235
            return radius_put_vendor_addr($this->res, $vendor,$attrib, $value);
236
            
237
        case 'string':
238
        default:
239
            return radius_put_vendor_attr($this->res, $vendor, $attrib, $value);
240
        }
241
        
242
    }    
243

  
244
    /**
245
     * Prints known attributes received from the server.
246
     *
247
     * @access public
248
     */     
249
    function dumpAttributes()
250
    {
251
        foreach ($this->attributes as $name => $data) {
252
            echo "$name:$data<br>\n";
253
        }
254
    }
255

  
256
    /**
257
     * Return our know attributes array received from the server.
258
     *
259
     * @access public
260
     */
261
    function listAttributes()
262
    {
263
        return $this->attributes;
264
    }
265

  
266
    /**
267
     * Overwrite this. 
268
     *
269
     * @access public
270
     */         
271
    function open() 
272
    {
273
    }
274

  
275
    /**
276
     * Overwrite this.
277
     *
278
     * @access public
279
     */         
280
    function createRequest()
281
    {
282
    }
283
    
284
    /**
285
     * Puts standard attributes.
286
     *
287
     * @access public
288
     */ 
289
    function putStandardAttributes()
290
    {
291
        $this->putAttribute(RADIUS_NAS_PORT_TYPE, RADIUS_ETHERNET);
292
        $this->putAttribute(RADIUS_SERVICE_TYPE, RADIUS_LOGIN);
293
    }
294
    
295
    /**
296
     * Puts custom attributes.
297
     *
298
     * @access public
299
     */ 
300
    function putAuthAttributes()
301
    {
302
        if (isset($this->username)) {
303
            $this->putAttribute(RADIUS_USER_NAME, $this->username);        
304
        }
305
    }
306
    
307
    /**
308
     * Configures the radius library.
309
     *
310
     * @access public
311
     * @param  string  $servername   Servername or IP-Address
312
     * @param  integer $port         Portnumber
313
     * @param  string  $sharedSecret Shared secret
314
     * @param  integer $timeout      Timeout for each request
315
     * @param  integer $maxtries     Max. retries for each request          
316
     * @return bool  true on success, false on error
317
     * @see addServer()
318
     */      
319
    function putServer($servername, $port = 0, $sharedsecret = 'testing123', $timeout = 3, $maxtries = 3) 
320
    {
321
        if (!radius_add_server($this->res, $servername, $port, $sharedsecret, $timeout, $maxtries)) {
322
            return false;
323
        }
324
        return true;
325
    }
326
    
327
    /**
328
     * Configures the radius library via external configurationfile
329
     *
330
     * @access public
331
     * @param  string  $servername   Servername or IP-Address
332
     * @return bool  true on success, false on error
333
     */      
334
    function putConfigfile($file) 
335
    {
336
        if (!radius_config($this->res, $file)) {
337
            return false;
338
        }
339
        return true;
340
    }    
341
        
342
    /**
343
     * Initiates a RADIUS request. 
344
     *
345
     * @access public
346
     * @return bool  true on success, false on errors     
347
     */ 
348
    function start()
349
    {
350
        if (!$this->open()) {
351
            return false;
352
        }
353
        
354
        foreach ($this->_servers as $s) {
355
	        // Servername, port, sharedsecret, timeout, retries
356
            if (!$this->putServer($s[0], $s[1], $s[2], $s[3], $s[4])) {
357
                return false;
358
            }
359
        }
360
        
361
        if (!empty($this->_configfile)) {
362
            if (!$this->putConfigfile($this->_configfile)) {
363
                return false;
364
            }
365
        }
366
        
367
        $this->createRequest();
368
	$this->putStandardAttributes();
369
        $this->putAuthAttributes();
370
        return true;
371
    }
372
    
373
    /**
374
     * Sends a prepared RADIUS request and waits for a response
375
     *
376
     * @access public
377
     * @return mixed  true on success, false on reject, PEAR_Error on error
378
     */ 
379
    function send()
380
    {
381
        $req = radius_send_request($this->res);
382
        if (!$req) {
383
            return $this->raiseError('Error sending request: ' . $this->getError());
384
        }
385

  
386
        switch($req) {
387
        case RADIUS_ACCESS_ACCEPT:
388
            if (is_subclass_of($this, 'auth_radius_acct')) {
389
                return $this->raiseError('RADIUS_ACCESS_ACCEPT is unexpected for accounting');
390
            }
391
            return true;
392

  
393
        case RADIUS_ACCESS_REJECT:
394
            return false;
395
            
396
        case RADIUS_ACCOUNTING_RESPONSE:
397
            if (is_subclass_of($this, 'auth_radius_pap')) {
398
                return $this->raiseError('RADIUS_ACCOUNTING_RESPONSE is unexpected for authentication');
399
            }
400
            return true;
401

  
402
        default:
403
            return $this->raiseError("Unexpected return value: $req");
404
        }    
405
        
406
    }
407

  
408
    /**
409
     * Reads all received attributes after sending the request.
410
     *
411
     * This methos stores know attributes in the property attributes, 
412
     * all attributes (including known attibutes) are stored in rawAttributes 
413
     * or rawVendorAttributes.
414
     * NOTE: call this functio also even if the request was rejected, because the 
415
     * Server returns usualy an errormessage
416
     *
417
     * @access public
418
     * @return bool   true on success, false on error
419
     */     
420
    function getAttributes()
421
    {
422

  
423
        while ($attrib = radius_get_attr($this->res)) {
424

  
425
            if (!is_array($attrib)) {
426
                return false;
427
            }        
428

  
429
            $attr = $attrib['attr'];
430
            $data = $attrib['data'];
431

  
432
            $this->rawAttributes[$attr] = $data;
433

  
434
            switch ($attr) {
435
            case RADIUS_FRAMED_IP_ADDRESS:
436
                $this->attributes['framed_ip'] = radius_cvt_addr($data);
437
                break;
438

  
439
            case RADIUS_FRAMED_IP_NETMASK:
440
                $this->attributes['framed_mask'] = radius_cvt_addr($data);
441
                break;
442

  
443
            case RADIUS_FRAMED_MTU:
444
                $this->attributes['framed_mtu'] = radius_cvt_int($data);
445
                break;
446

  
447
            case RADIUS_FRAMED_COMPRESSION:
448
                $this->attributes['framed_compression'] = radius_cvt_int($data);
449
                break;
450

  
451
            case RADIUS_SESSION_TIMEOUT:
452
                $this->attributes['session_timeout'] = radius_cvt_int($data);
453
                break;
454

  
455
            case RADIUS_IDLE_TIMEOUT:
456
                $this->attributes['idle_timeout'] = radius_cvt_int($data);
457
                break;
458

  
459
            case RADIUS_SERVICE_TYPE:
460
                $this->attributes['service_type'] = radius_cvt_int($data);
461
                break;
462

  
463
            case RADIUS_CLASS:
464
                $this->attributes['class'] = radius_cvt_int($data);
465
                break;
466

  
467
            case RADIUS_FRAMED_PROTOCOL:
468
                $this->attributes['framed_protocol'] = radius_cvt_int($data);
469
                break;
470

  
471
            case RADIUS_FRAMED_ROUTING:
472
                $this->attributes['framed_routing'] = radius_cvt_int($data);
473
                break;
474

  
475
            case RADIUS_FILTER_ID:
476
                $this->attributes['filter_id'] = radius_cvt_string($data);
477
                break;
478

  
479
            case RADIUS_REPLY_MESSAGE:
480
                $this->attributes['reply_message'] = radius_cvt_string($data);
481
                break;
482

  
483
            case RADIUS_VENDOR_SPECIFIC:
484
                $attribv = radius_get_vendor_attr($data);
485
                if (!is_array($attribv)) {
486
                    return false;
487
                }
488
                    
489
                $vendor = $attribv['vendor'];
490
                $attrv = $attribv['attr'];
491
                $datav = $attribv['data'];
492
                
493
                $this->rawVendorAttributes[$vendor][$attrv] = $datav;
494

  
495
                if ($vendor == RADIUS_VENDOR_MICROSOFT) {
496

  
497
                    switch ($attrv) {
498
                    case RADIUS_MICROSOFT_MS_CHAP2_SUCCESS:
499
                        $this->attributes['ms_chap2_success'] = radius_cvt_string($datav);
500
                        break;
501

  
502
                    case RADIUS_MICROSOFT_MS_CHAP_ERROR:
503
                        $this->attributes['ms_chap_error'] = radius_cvt_string(substr($datav,1));
504
                        break;
505

  
506
                    case RADIUS_MICROSOFT_MS_CHAP_DOMAIN:
507
                        $this->attributes['ms_chap_domain'] = radius_cvt_string($datav);
508
                        break;
509

  
510
                    case RADIUS_MICROSOFT_MS_MPPE_ENCRYPTION_POLICY:
511
                        $this->attributes['ms_mppe_encryption_policy'] = radius_cvt_int($datav);
512
                        break;
513

  
514
                    case RADIUS_MICROSOFT_MS_MPPE_ENCRYPTION_TYPES:
515
                        $this->attributes['ms_mppe_encryption_types'] = radius_cvt_int($datav);
516
                        break;
517

  
518
                    case RADIUS_MICROSOFT_MS_CHAP_MPPE_KEYS:
519
                        $demangled = radius_demangle($this->res, $datav);
520
                        $this->attributes['ms_chap_mppe_lm_key'] = substr($demangled, 0, 8);
521
                        $this->attributes['ms_chap_mppe_nt_key'] = substr($demangled, 8, RADIUS_MPPE_KEY_LEN);
522
                        break;
523

  
524
                    case RADIUS_MICROSOFT_MS_MPPE_SEND_KEY:
525
                        $this->attributes['ms_chap_mppe_send_key'] = radius_demangle_mppe_key($this->res, $datav);
526
                        break;
527

  
528
                    case RADIUS_MICROSOFT_MS_MPPE_RECV_KEY:
529
                        $this->attributes['ms_chap_mppe_recv_key'] = radius_demangle_mppe_key($this->res, $datav);
530
                        break;
531

  
532
                    case RADIUS_MICROSOFT_MS_PRIMARY_DNS_SERVER:
533
                        $this->attributes['ms_primary_dns_server'] = radius_cvt_string($datav);
534
                        break;
535
                    }
536
                }
537

  
538
                if ($vendor == RADIUS_VENDOR_BAY) {
539

  
540
                    switch ($attrv) {
541
                    case RADIUS_BAY_CES_GROUP:
542
                        $this->attributes['ces_group'] = radius_cvt_string($datav);
543
                        break;
544
                    }
545
                }
546

  
547
                if ($vendor == 3309) {	/* RADIUS_VENDOR_NOMADIX */
548

  
549
                    switch ($attrv) {
550
                    case 1: /* RADIUS_NOMADIX_BW_UP */
551
                        $this->attributes['bw_up'] = radius_cvt_int($datav);
552
                        break;
553
                    case 2: /* RADIUS_NOMADIX_BW_DOWN */
554
                        $this->attributes['bw_down'] = radius_cvt_int($datav);
555
                        break;
556
                    case 3: /* RADIUS_NOMADIX_URL_REDIRECTION */
557
                        $this->attributes['url_redirection'] = radius_cvt_string($datav);
558
                        break;
559
                    case 5: /* RADIUS_NOMADIX_EXPIRATION */
560
                        $this->attributes['expiration'] = radius_cvt_string($datav);
561
                        break;
562
                    case 7: /* RADIUS_NOMADIX_MAXBYTESUP */
563
                        $this->attributes['maxbytesup'] = radius_cvt_int($datav);
564
                        break;
565
                    case 8: /* RADIUS_NOMADIX_MAXBYTESDOWN */
566
                        $this->attributes['maxbytesdown'] = radius_cvt_int($datav);
567
                        break;
568
                    case 10: /* RADIUS_NOMADIX_LOGOFF_URL */
569
                        $this->attributes['url_logoff'] = radius_cvt_string($datav);
570
                        break;
571
                    }
572
                } 
573

  
574
		if ($vendor == 14122) { /* RADIUS_VENDOR_WISPr Wi-Fi Alliance */
575

  
576
		    switch ($attrv) {
577
		    case 1: /* WISPr-Location-ID */
578
			$this->attributes['location_id'] = radius_cvt_string($datav);
579
			break;
580
		    case 2: /* WISPr-Location-Name */
581
			$this->attributes['location_name'] = radius_cvt_string($datav);
582
			break;
583
		    case 3: /* WISPr-Logoff-URL */
584
			$this->attributes['url_logoff'] = radius_cvt_string($datav);
585
			break;
586
		    case 4: /* WISPr-Redirection-URL */
587
			$this->attributes['url_redirection'] = radius_cvt_string($datav);
588
			break;
589
		    case 5: /* WISPr-Bandwidth-Min-Up */
590
			$this->attributes['bw_minbytesup'] = radius_cvt_int($datav);
591
			break;
592
		    case 6: /* WISPr-Bandwidth-Min-Down */
593
			$this->attributes['bw_minbytesdown'] = radius_cvt_int($datav);
594
			break;
595
		    case 7: /* WIPSr-Bandwidth-Max-Up */
596
			$this->attributes['bw_maxbytesup'] = radius_cvt_int($datav);
597
			break;
598
		    case 8: /* WISPr-Bandwidth-Max-Down */
599
			$this->attributes['bw_maxbytesdown'] = radius_cvt_int($datav);
600
			break;
601
		    case 9: /* WISPr-Session-Terminate-Time */
602
			$this->attributes['session_terminate_time'] = radius_cvt_string($datav);
603
			break;
604
		    case 10: /* WISPr-Session-Terminate-End-Of-Day */
605
			$this->attributes['session_terminate_endofday'] = radius_cvt_int($datav);
606
			break;
607
		    case 11: /* WISPr-Billing-Class-Of-Service */
608
			$this->attributes['billing_class_of_service'] = radius_cvt_string($datav);
609
			break;
610
		   }
611
		}
612

  
613
                break;
614
                
615
            }
616
        }    
617

  
618
        return true;
619
    }
620
    
621
    /**
622
     * Frees resources.
623
     *
624
     * Calling this method is always a good idea, because all security relevant
625
     * attributes are filled with Nullbytes to leave nothing in the mem.
626
     *
627
     * @access public
628
     */   
629
    function close()
630
    {
631
        if ($this->res != null) {
632
            radius_close($this->res);
633
            $this->res = null;
634
        }
635
        $this->username = str_repeat("\0", strlen($this->username));
636
        $this->password = str_repeat("\0", strlen($this->password));
637
    }
638
    
639
}
640

  
641
/**
642
 * class Auth_RADIUS_PAP
643
 *
644
 * Class for authenticating using PAP (Plaintext)
645
 * 
646
 * @package Auth_RADIUS 
647
 */
648
class Auth_RADIUS_PAP extends Auth_RADIUS 
649
{
650

  
651
    /**
652
     * Constructor
653
     *
654
     * @param  string  $username   Username
655
     * @param  string  $password   Password
656
     * @return void
657
     */
658
    function Auth_RADIUS_PAP($username = null, $password = null)
659
    {
660
        $this->Auth_RADIUS();
661
        $this->username = $username;
662
        $this->password = $password;
663
    }
664
    
665
    /**
666
     * Creates a RADIUS resource
667
     *
668
     * Creates a RADIUS resource for authentication. This should be the first
669
     * call before you make any other things with the library.
670
     *
671
     * @return bool   true on success, false on error
672
     */
673
    function open() 
674
    {
675
        $this->res = radius_auth_open();
676
        if (!$this->res) {
677
            return false;
678
        }
679
        return true;
680
    }
681
    
682
    /**
683
     * Creates an authentication request 
684
     *
685
     * Creates an authentication request.
686
     * You MUST call this method before you can put any attribute
687
     *
688
     * @return bool   true on success, false on error
689
     */
690
    function createRequest()
691
    {
692
        if (!radius_create_request($this->res, RADIUS_ACCESS_REQUEST)) {
693
            return false;
694
        }
695
        return true;
696
    }
697

  
698
    /**
699
     * Put authentication specific attributes 
700
     *
701
     * @return void
702
     */
703
    function putAuthAttributes()
704
    {
705
        if (isset($this->username)) {
706
            $this->putAttribute(RADIUS_USER_NAME, $this->username);        
707
        }
708
        if (isset($this->password)) {
709
            $this->putAttribute(RADIUS_USER_PASSWORD, $this->password);
710
        }
711
    }
712

  
713
}
714

  
715
/**
716
 * class Auth_RADIUS_CHAP_MD5
717
 *
718
 * Class for authenticating using CHAP-MD5 see RFC1994.
719
 * Instead og the plaintext password the challenge and 
720
 * the response are needed.
721
 * 
722
 * @package Auth_RADIUS 
723
 */
724
class Auth_RADIUS_CHAP_MD5 extends Auth_RADIUS_PAP
725
{
726
    /**
727
     * 8 Bytes binary challenge
728
     * @var  string
729
     */
730
    var $challenge = null;
731

  
732
    /**
733
     * 16 Bytes MD5 response binary
734
     * @var  string
735
     */
736
    var $response = null;
737
    
738
    /**
739
     * Id of the authentication request. Should incremented after every request.
740
     * @var  integer
741
     */
742
    var $chapid = 1;
743
    
744
    /**
745
     * Constructor
746
     *
747
     * @param  string  $username   Username
748
     * @param  string  $challenge  8 Bytes Challenge (binary)
749
     * @param  integer $chapid     Requestnumber
750
     * @return void
751
     */
752
    function Auth_RADIUS_CHAP_MD5($username = null, $challenge = null, $chapid = 1)
753
    {
754
        $this->Auth_RADIUS_PAP();
755
        $this->username = $username;
756
        $this->challenge = $challenge;
757
        $this->chapid = $chapid;
758
    }
759
    
760
    /**
761
     * Put CHAP-MD5 specific attributes
762
     *
763
     * For authenticating using CHAP-MD5 via RADIUS you have to put the challenge 
764
     * and the response. The chapid is inserted in the first byte of the response.
765
     *
766
     * @return void
767
     */
768
    function putAuthAttributes()
769
    {
770
        if (isset($this->username)) {
771
            $this->putAttribute(RADIUS_USER_NAME, $this->username);        
772
        }
773
        if (isset($this->response)) {
774
            $response = pack('C', $this->chapid) . $this->response;
775
            $this->putAttribute(RADIUS_CHAP_PASSWORD, $response);
776
        }
777
        if (isset($this->challenge)) {
778
            $this->putAttribute(RADIUS_CHAP_CHALLENGE, $this->challenge);
779
        }
780
    }
781
    
782
    /**
783
     * Frees resources.
784
     *
785
     * Calling this method is always a good idea, because all security relevant
786
     * attributes are filled with Nullbytes to leave nothing in the mem.
787
     *
788
     * @access public
789
     */   
790
    function close()
791
    {
792
        Auth_RADIUS_PAP::close();
793
        $this->challenge =  str_repeat("\0", strlen($this->challenge));
794
        $this->response =  str_repeat("\0", strlen($this->response));
795
    }    
796
    
797
}
798

  
799
/**
800
 * class Auth_RADIUS_MSCHAPv1
801
 *
802
 * Class for authenticating using MS-CHAPv1 see RFC2433
803
 * 
804
 * @package Auth_RADIUS 
805
 */
806
class Auth_RADIUS_MSCHAPv1 extends Auth_RADIUS_CHAP_MD5 
807
{
808
    /**
809
     * LAN-Manager-Response
810
     * @var  string
811
     */
812
    var $lmResponse = null;
813

  
814
    /**
815
     * Wether using deprecated LM-Responses or not.
816
     * 0 = use LM-Response, 1 = use NT-Response
817
     * @var  bool
818
     */
819
    var $flags = 1;
820
    
821
    /**
822
     * Put MS-CHAPv1 specific attributes 
823
     *
824
     * For authenticating using MS-CHAPv1 via RADIUS you have to put the challenge 
825
     * and the response. The response has this structure:
826
     * struct rad_mschapvalue {
827
     *   u_char ident;
828
     *   u_char flags;
829
     *   u_char lm_response[24];
830
     *   u_char response[24];
831
     * };
832
     * 
833
     * @return void
834
     */
835
    function putAuthAttributes()
836
    {
837
        if (isset($this->username)) {
838
            $this->putAttribute(RADIUS_USER_NAME, $this->username);        
839
        }
840
        if (isset($this->response) || isset($this->lmResponse)) {
841
            $lmResp = isset($this->lmResponse) ? $this->lmResponse : str_repeat ("\0", 24);
842
            $ntResp = isset($this->response)   ? $this->response :   str_repeat ("\0", 24);
843
            $resp = pack('CC', $this->chapid, $this->flags) . $lmResp . $ntResp;
844
            $this->putVendorAttribute(RADIUS_VENDOR_MICROSOFT, RADIUS_MICROSOFT_MS_CHAP_RESPONSE, $resp);
845
        }
846
        if (isset($this->challenge)) {        
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff