diff options
-rw-r--r-- | etc/inc/PEAR.inc | 2 | ||||
-rw-r--r-- | etc/inc/captiveportal.inc | 29 | ||||
-rw-r--r-- | etc/inc/radius.inc | 148 | ||||
-rw-r--r-- | usr/local/captiveportal/radius_accounting.inc | 589 | ||||
-rw-r--r-- | usr/local/captiveportal/radius_authentication.inc | 302 | ||||
-rw-r--r-- | usr/local/etc/php.ini | 3 | ||||
-rw-r--r-- | usr/local/lib/php.ini | 1 | ||||
-rwxr-xr-x | usr/local/www/services_captiveportal.php | 53 |
8 files changed, 613 insertions, 514 deletions
diff --git a/etc/inc/PEAR.inc b/etc/inc/PEAR.inc index 74fc18d..5f5c758 100644 --- a/etc/inc/PEAR.inc +++ b/etc/inc/PEAR.inc @@ -1053,4 +1053,4 @@ class PEAR_Error * c-basic-offset: 4 * End: */ -?> +?>
\ No newline at end of file diff --git a/etc/inc/captiveportal.inc b/etc/inc/captiveportal.inc index f85ef54..064916b 100644 --- a/etc/inc/captiveportal.inc +++ b/etc/inc/captiveportal.inc @@ -38,6 +38,7 @@ require_once("functions.inc"); require_once("radius_authentication.inc"); require_once("radius_accounting.inc"); +require_once("radius.inc"); $lockfile = "{$g['varrun_path']}/captiveportal.lock"; @@ -990,4 +991,32 @@ function captiveportal_get_next_ipfw_ruleno($rulenos_start = 10000, $rulenos_ran return $ruleno; } +/** + * Get the NAS-Identifier + * + * We will use our local hostname to make up the nas_id + */ +function getNasID() +{ + exec("/bin/hostname", $nasId); + if(!$nasId[0]) + $nasId[0] = "pfSense"; + return $nasId[0]; +} + +/** + * Get the NAS-IP-Address based on the current wan address + * + * Use functions in interfaces.inc to find this out + * + */ + +function getNasIP() +{ + $nasIp = get_current_wan_address(); + if(!$nasIp) + $nasIp = "0.0.0.0"; + return $nasIp; +} + ?>
\ No newline at end of file diff --git a/etc/inc/radius.inc b/etc/inc/radius.inc index 5fe06f1..0077194 100644 --- a/etc/inc/radius.inc +++ b/etc/inc/radius.inc @@ -6,30 +6,30 @@ Copyright (c) 2003, Michael Bretterklieber <michael@bretterklieber.com> All rights reserved. - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: - 1. Redistributions of source code must retain the above copyright + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - 3. The names of the authors may not be used to endorse or promote products + 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - This code cannot simply be copied and put under the GNU Public License or + This code cannot simply be copied and put under the GNU Public License or any other GPL-like (LGPL, GPL2) License. This version of RADIUS.php has been modified by @@ -46,7 +46,7 @@ */ -require_once("pear.inc"); +require_once("PEAR.inc"); require_once("radius_authentication.inc"); require_once("radius_accounting.inc"); @@ -68,7 +68,7 @@ PEAR::loadExtension('radius'); * * Abstract base class for RADIUS * - * @package Auth_RADIUS + * @package Auth_RADIUS */ class Auth_RADIUS extends PEAR { @@ -133,7 +133,7 @@ class Auth_RADIUS extends PEAR { * * @return void */ - function Auth_RADIUS() + function Auth_RADIUS() { $this->PEAR(); } @@ -141,8 +141,8 @@ class Auth_RADIUS extends PEAR { /** * Adds a RADIUS server to the list of servers for requests. * - * At most 10 servers may be specified. When multiple servers - * are given, they are tried in round-robin fashion until a + * At most 10 servers may be specified. When multiple servers + * are given, they are tried in round-robin fashion until a * valid response is received * * @access public @@ -153,7 +153,7 @@ class Auth_RADIUS extends PEAR { * @param integer $maxtries Max. retries for each request * @return void */ - function addServer($servername = 'localhost', $port = 0, $sharedSecret = 'testing123', $timeout = 5, $maxtries = 3) + function addServer($servername = 'localhost', $port = 0, $sharedSecret = 'testing123', $timeout = 5, $maxtries = 3) { $this->_servers[] = array($servername, $port, $sharedSecret, $timeout, $maxtries); } @@ -164,7 +164,7 @@ class Auth_RADIUS extends PEAR { * @access public * @return string */ - function getError() + function getError() { return radius_strerror($this->res); } @@ -176,7 +176,7 @@ class Auth_RADIUS extends PEAR { * @param string $file Path to the configuration file * @return void */ - function setConfigfile($file) + function setConfigfile($file) { $this->_configfile = $file; } @@ -190,7 +190,7 @@ class Auth_RADIUS extends PEAR { * @param type $type Attribute-type * @return bool true on success, false on error */ - function putAttribute($attrib, $value, $type = null) + function putAttribute($attrib, $value, $type = null) { if ($type == null) { $type = gettype($value); @@ -220,8 +220,8 @@ class Auth_RADIUS extends PEAR { * @param mixed $port Attribute-value * @param type $type Attribute-type * @return bool true on success, false on error - */ - function putVendorAttribute($vendor, $attrib, $value, $type = null) + */ + function putVendorAttribute($vendor, $attrib, $value, $type = null) { if ($type == null) { @@ -265,11 +265,11 @@ class Auth_RADIUS extends PEAR { } /** - * Overwrite this. + * Overwrite this. * * @access public */ - function open() + function open() { } @@ -324,7 +324,7 @@ class Auth_RADIUS extends PEAR { * @return bool true on success, false on error * @see addServer() */ - function putServer($servername, $port = 0, $sharedsecret = 'testing123', $timeout = 3, $maxtries = 3) + function putServer($servername, $port = 0, $sharedsecret = 'testing123', $timeout = 3, $maxtries = 3) { if (!radius_add_server($this->res, $servername, $port, $sharedsecret, $timeout, $maxtries)) { return false; @@ -339,7 +339,7 @@ class Auth_RADIUS extends PEAR { * @param string $servername Servername or IP-Address * @return bool true on success, false on error */ - function putConfigfile($file) + function putConfigfile($file) { if (!radius_config($this->res, $file)) { return false; @@ -348,11 +348,11 @@ class Auth_RADIUS extends PEAR { } /** - * Initiates a RADIUS request. + * Initiates a RADIUS request. * * @access public - * @return bool true on success, false on errors - */ + * @return bool true on success, false on errors + */ function start() { if (!$this->open()) { @@ -432,7 +432,7 @@ class Auth_RADIUS extends PEAR { if (!is_array($attrib)) { return false; - } + } $attr = $attrib['attr']; $data = $attrib['data']; @@ -577,7 +577,7 @@ class Auth_RADIUS extends PEAR { $this->attributes['url_logoff'] = radius_cvt_string($datav); break; } - } + } if ($vendor == 14122) { /* RADIUS_VENDOR_WISPr Wi-Fi Alliance */ @@ -595,16 +595,16 @@ class Auth_RADIUS extends PEAR { $this->attributes['url_redirection'] = radius_cvt_string($datav); break; case 5: /* WISPr-Bandwidth-Min-Up */ - $this->attributes['bw_minbytesup'] = radius_cvt_int($datav); + $this->attributes['bw_up_min'] = radius_cvt_int($datav); break; case 6: /* WISPr-Bandwidth-Min-Down */ - $this->attributes['bw_minbytesdown'] = radius_cvt_int($datav); + $this->attributes['bw_down_min'] = radius_cvt_int($datav); break; case 7: /* WIPSr-Bandwidth-Max-Up */ - $this->attributes['bw_maxbytesup'] = radius_cvt_int($datav); + $this->attributes['bw_up'] = radius_cvt_int($datav); break; case 8: /* WISPr-Bandwidth-Max-Down */ - $this->attributes['bw_maxbytesdown'] = radius_cvt_int($datav); + $this->attributes['bw_down'] = radius_cvt_int($datav); break; case 9: /* WISPr-Session-Terminate-Time */ $this->attributes['session_terminate_time'] = radius_cvt_string($datav); @@ -651,9 +651,9 @@ class Auth_RADIUS extends PEAR { * * Class for authenticating using PAP (Plaintext) * - * @package Auth_RADIUS + * @package Auth_RADIUS */ -class Auth_RADIUS_PAP extends Auth_RADIUS +class Auth_RADIUS_PAP extends Auth_RADIUS { /** @@ -678,7 +678,7 @@ class Auth_RADIUS_PAP extends Auth_RADIUS * * @return bool true on success, false on error */ - function open() + function open() { $this->res = radius_auth_open(); if (!$this->res) { @@ -688,7 +688,7 @@ class Auth_RADIUS_PAP extends Auth_RADIUS } /** - * Creates an authentication request + * Creates an authentication request * * Creates an authentication request. * You MUST call this method before you can put any attribute @@ -704,7 +704,7 @@ class Auth_RADIUS_PAP extends Auth_RADIUS } /** - * Put authentication specific attributes + * Put authentication specific attributes * * @return void */ @@ -724,10 +724,10 @@ class Auth_RADIUS_PAP extends Auth_RADIUS * class Auth_RADIUS_CHAP_MD5 * * Class for authenticating using CHAP-MD5 see RFC1994. - * Instead og the plaintext password the challenge and + * Instead og the plaintext password the challenge and * the response are needed. * - * @package Auth_RADIUS + * @package Auth_RADIUS */ class Auth_RADIUS_CHAP_MD5 extends Auth_RADIUS_PAP { @@ -768,7 +768,7 @@ class Auth_RADIUS_CHAP_MD5 extends Auth_RADIUS_PAP /** * Put CHAP-MD5 specific attributes * - * For authenticating using CHAP-MD5 via RADIUS you have to put the challenge + * For authenticating using CHAP-MD5 via RADIUS you have to put the challenge * and the response. The chapid is inserted in the first byte of the response. * * @return void @@ -776,7 +776,7 @@ class Auth_RADIUS_CHAP_MD5 extends Auth_RADIUS_PAP function putAuthAttributes() { if (isset($this->username)) { - $this->putAttribute(RADIUS_USER_NAME, $this->username); + $this->putAttribute(RADIUS_USER_NAME, $this->username); } if (isset($this->response)) { $response = pack('C', $this->chapid) . $this->response; @@ -809,9 +809,9 @@ class Auth_RADIUS_CHAP_MD5 extends Auth_RADIUS_PAP * * Class for authenticating using MS-CHAPv1 see RFC2433 * - * @package Auth_RADIUS + * @package Auth_RADIUS */ -class Auth_RADIUS_MSCHAPv1 extends Auth_RADIUS_CHAP_MD5 +class Auth_RADIUS_MSCHAPv1 extends Auth_RADIUS_CHAP_MD5 { /** * LAN-Manager-Response @@ -827,9 +827,9 @@ class Auth_RADIUS_MSCHAPv1 extends Auth_RADIUS_CHAP_MD5 var $flags = 1; /** - * Put MS-CHAPv1 specific attributes + * Put MS-CHAPv1 specific attributes * - * For authenticating using MS-CHAPv1 via RADIUS you have to put the challenge + * For authenticating using MS-CHAPv1 via RADIUS you have to put the challenge * and the response. The response has this structure: * struct rad_mschapvalue { * u_char ident; @@ -862,9 +862,9 @@ class Auth_RADIUS_MSCHAPv1 extends Auth_RADIUS_CHAP_MD5 * * Class for authenticating using MS-CHAPv2 see RFC2759 * - * @package Auth_RADIUS + * @package Auth_RADIUS */ -class Auth_RADIUS_MSCHAPv2 extends Auth_RADIUS_MSCHAPv1 +class Auth_RADIUS_MSCHAPv2 extends Auth_RADIUS_MSCHAPv1 { /** * 16 Bytes binary challenge @@ -879,9 +879,9 @@ class Auth_RADIUS_MSCHAPv2 extends Auth_RADIUS_MSCHAPv1 var $peerChallenge = null; /** - * Put MS-CHAPv2 specific attributes + * Put MS-CHAPv2 specific attributes * - * For authenticating using MS-CHAPv1 via RADIUS you have to put the challenge + * For authenticating using MS-CHAPv1 via RADIUS you have to put the challenge * and the response. The response has this structure: * struct rad_mschapv2value { * u_char ident; @@ -896,11 +896,11 @@ class Auth_RADIUS_MSCHAPv2 extends Auth_RADIUS_MSCHAPv1 function putAuthAttributes() { if (isset($this->username)) { - $this->putAttribute(RADIUS_USER_NAME, $this->username); + $this->putAttribute(RADIUS_USER_NAME, $this->username); } if (isset($this->response) && isset($this->peerChallenge)) { - // Response: chapid, flags (1 = use NT Response), Peer challenge, reserved, Response - $resp = pack('CCa16a8a24',$this->chapid , 1, $this->peerChallenge, str_repeat("\0", 8), $this->response); + // Response: chapid, flags (1 = use NT Response), Peer challenge, reserved, Response + $resp = pack('CCa16a8a24',$this->chapid , 1, $this->peerChallenge, str_repeat("\0", 8), $this->response); $this->putVendorAttribute(RADIUS_VENDOR_MICROSOFT, RADIUS_MICROSOFT_MS_CHAP2_RESPONSE, $resp); } if (isset($this->challenge)) { @@ -915,7 +915,7 @@ class Auth_RADIUS_MSCHAPv2 extends Auth_RADIUS_MSCHAPv1 * attributes are filled with Nullbytes to leave nothing in the mem. * * @access public - */ + */ function close() { Auth_RADIUS_MSCHAPv1::close(); @@ -927,10 +927,10 @@ class Auth_RADIUS_MSCHAPv2 extends Auth_RADIUS_MSCHAPv1 * class Auth_RADIUS_Acct * * Class for RADIUS accounting - * - * @package Auth_RADIUS + * + * @package Auth_RADIUS */ -class Auth_RADIUS_Acct extends Auth_RADIUS +class Auth_RADIUS_Acct extends Auth_RADIUS { /** * Defines where the Authentication was made, possible values are: @@ -943,19 +943,19 @@ class Auth_RADIUS_Acct extends Auth_RADIUS * Defines the type of the accounting request, on of: * RADIUS_START, RADIUS_STOP, RADIUS_ACCOUNTING_ON, RADIUS_ACCOUNTING_OFF * @var integer - */ + */ var $status_type = null; /** * The time the user was logged in in seconds * @var integer - */ + */ var $session_time = null; /** * A uniq identifier for the session of the user, maybe the PHP-Session-Id * @var string - */ + */ var $session_id = null; /** @@ -998,7 +998,7 @@ class Auth_RADIUS_Acct extends Auth_RADIUS * * @return bool true on success, false on error */ - function open() + function open() { $this->res = radius_acct_open(); if (!$this->res) { @@ -1008,7 +1008,7 @@ class Auth_RADIUS_Acct extends Auth_RADIUS } /** - * Creates an accounting request + * Creates an accounting request * * Creates an accounting request. * You MUST call this method before you can put any attribute. @@ -1026,10 +1026,10 @@ class Auth_RADIUS_Acct extends Auth_RADIUS /** * Put attributes for accounting. * - * Here we put some accounting values. There many more attributes for accounting, + * Here we put some accounting values. There many more attributes for accounting, * but for web-applications only certain attributes make sense. * @return void - */ + */ function putAuthAttributes() { if (isset($this->username)) { @@ -1051,10 +1051,10 @@ class Auth_RADIUS_Acct extends Auth_RADIUS * class Auth_RADIUS_Acct_Start * * Class for RADIUS accounting. Its usualy used, after the user has logged in. - * + * * @package Auth_RADIUS */ -class Auth_RADIUS_Acct_Start extends Auth_RADIUS_Acct +class Auth_RADIUS_Acct_Start extends Auth_RADIUS_Acct { /** * Defines the type of the accounting request. @@ -1101,4 +1101,4 @@ class Auth_RADIUS_Acct_Update extends Auth_RADIUS_Acct var $status_type = RADIUS_UPDATE; } -?> +?>
\ No newline at end of file diff --git a/usr/local/captiveportal/radius_accounting.inc b/usr/local/captiveportal/radius_accounting.inc index 9744809..15325ae 100644 --- a/usr/local/captiveportal/radius_accounting.inc +++ b/usr/local/captiveportal/radius_accounting.inc @@ -1,293 +1,316 @@ <?php +/* vim: set expandtab tabstop=4 shiftwidth=4: */ /* - radius_accounting.inc - part of m0n0wall (http://m0n0.ch/wall) - - Copyright (C) 2004 Dinesh Nair <dinesh@alphaque.com> - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. - - // This version of radius_accounting.inc has been modified by - // Rob Parker <rob.parker@keycom.co.uk>. Changes made include: - // * now sends Framed-IP-Address (client IP) - // * now sends Called-Station-ID (NAS IP) - // * now sends Calling-Station-ID (client IP) + + $Id$ + + Copyright (c) 2006, Jonathan De Graeve <jonathan.de.graeve@imelda.be> + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + This code cannot simply be copied and put under the GNU Public License or + any other GPL-like (LGPL, GPL2) License. + + This code is made possible thx to samples made by Michael Bretterklieber <michael@bretterklieber.com> + author of the PHP PECL Radius package + */ -function RADIUS_ACCOUNTING_START($username,$sessionid,$radiusip,$radiusport,$radiuskey,$clientip) { - global $debug, $nasHostname, $errstr; - $sharedsecret=$radiuskey ; - # $debug = 1 ; - - exec("/bin/hostname", $nasHostname) ; - if(!$nasHostname[0]) - $nasHostname[0] = "m0n0wall" ; - - $errno = ""; - $fd = @fsockopen("udp://$radiusip",$radiusport,$errno,$errstr,3) ; - if(!$fd) - return 1 ; /* error return */ - - /* set 5 second timeout on socket i/o */ - stream_set_timeout($fd, 5) ; - - $nas_ip_address = get_nas_ip(); - - if(!isset($clientip)) { - //if there's no client ip, we'll need to use the NAS ip - $clientip=$nas_ip_address; - } - $ip_exp=explode(".",$clientip); - - if ($debug) - echo "<br>radius-port: $radiusport<br>radius-host: $radiusip<br>username: $username<hr>\n"; - - $thisidentifier=rand()%256; - - $length=4+ // header - 16+ // auth code - 6+ // service type - 2+strlen($username)+ // username - 2+strlen($nasHostname[0])+ // nasIdentifier - 6+ // nasPort - 6+ // nasPortType - 6+ // Acct Status Type - 6+ // Acct RADIUS Authenticated - 2+strlen($sessionid)+ // Acct SessionID - 6; // Framed-IP-Address - - // v v v v v v v v v 1 v - // Line # 1 2 3 4 5 6 7 8 9 0 E - $data=pack("CCCCNNNNCCCCCCCCa*CCa*CCCCCCCCCCCCCCCCCCCCCCCCCCa*CCCCCC", - 4,$thisidentifier,$length/256,$length%256, // header - 0,0,0,0, // authcode - 6,6,0,0,0,1, // service type - 1,2+strlen($username),$username, // username - 32,2+strlen($nasHostname[0]),$nasHostname[0], // nasIdentifier - 5,6,0,0,0,0, // nasPort - 61,6,0,0,0,15, // nasPortType = Ethernet - 40,6,0,0,0,1, // Acct Status Type = Start - 45,6,0,0,0,1, // Acct RADIUS Authenticated - 44,2+strlen($sessionid),$sessionid, // Acct Session ID - 8,6,$ip_exp[0],$ip_exp[1],$ip_exp[2],$ip_exp[3] //Framed-IP-Address - ); - - /* Generate Accounting Request Authenticator */ - $RA = md5($data.$radiuskey) ; - - // v v v v v v v v v 1 v - // Line # 1 2 3 4 5 6 7 8 9 0 E - $data=pack("CCCCH*CCCCCCCCa*CCa*CCCCCCCCCCCCCCCCCCCCCCCCCCa*CCCCCC", - 4,$thisidentifier,$length/256,$length%256, // header - $RA, // authcode - 6,6,0,0,0,1, // service type - 1,2+strlen($username),$username, // username - 32,2+strlen($nasHostname[0]),$nasHostname[0], // nasIdentifier - 5,6,0,0,0,0, // nasPort - 61,6,0,0,0,15, // nasPortType = Ethernet - 40,6,0,0,0,1, // Acct Status Type = Start - 45,6,0,0,0,1, // Acct RADIUS Authenticated - 44,2+strlen($sessionid),$sessionid, // Acct Session ID - 8,6,$ip_exp[0],$ip_exp[1],$ip_exp[2],$ip_exp[3] //Framed-IP-Address - ); - - if($debug) { - echo "username is $username with len " . strlen($username) ."\n" ; - echo "nasHostname is {$nasHostname[0]} with len " . strlen($nasHostname[0]) ."\n" ; - } - - $ret = fwrite($fd,$data) ; - if( !$ret || ($ret != $length) ) - return 1; /* error return */ - - if ($debug) - echo "<br>writing $length bytes<hr>\n"; - - $readdata = fgets($fd,2) ; /* read 1 byte */ - $status = socket_get_status($fd) ; - fclose($fd) ; - - if($status['timed_out']) - $retvalue = 1 ; - else - $retvalue = ord($readdata) ; - - return $retvalue ; - // 5 -> Accounting-Response - // See RFC2866 for this. +/* +RADIUS ACCOUNTING START +----------------------- +*/ + +function RADIUS_ACCOUNTING_START($ruleno,$username,$sessionid,$radiusip,$radiusport,$radiuskey,$clientip,$clientmac) { + + global $config; + + $retvalue = array(); + $nas_mac = mac_format(get_interface_mac($config['interfaces']['wan']['if'])); + $clientmac = mac_format($clientmac); + $nas_port = $ruleno - 10000; + $radiusvendor = $config['captiveportal']['radiusvendor'] ? $config['captiveportal']['radiusvendor'] : null; + + switch($radiusvendor) { + + case 'cisco': + $calledstationid = $clientmac; + $callingstationid = $clientip; + break; + + default: + $calledstationid = $nas_mac; + $callingstationid = $clientmac; + } + + // Create our instance + $racct = new Auth_RADIUS_Acct_Start; + + /* Different Authentication options + * + * Its possible todo other authentication methods but still do radius accounting + * + * RADIUS_AUTH_RADIUS => authenticated via Radius + * RADIUS_AUTH_LOCAL => authenticated local + * RADIUS_AUTH_REMOTE => authenticated remote + * + */ + $racct->authentic = RADIUS_AUTH_RADIUS; + + // Construct data package + $racct->username = $username; + $racct->addServer($radiusip, $radiusport, $radiuskey); + + if (PEAR::isError($racct->start())) { + $retvalue['acct_val'] = 1; + $retvalue['error'] = $racct->getMessage(); + if ($debug) + printf("Radius start: %s<br>\n", $retvalue['error']); + // If we encounter an error immediately stop this function and go back + $racct->close(); + return $retvalue; + + /* Old code: + * $status = $racct->start(); + * if(PEAR::isError($status)) { + * if ($debug) + * printf("Radius start: %s<br>\n", $status->getMessage()); + * exit; + * } + */ + } + + /* + * NAS_PORT_TYPE, int => RADIUS_ETHERNET (15), RADIUS_WIRELESS_OTHER (18), RADIUS_WIRELESS_IEEE_802_11 (19) + */ + + // Default attributes + $racct->putAttribute(RADIUS_SERVICE_TYPE, RADIUS_LOGIN); + $racct->putAttribute(RADIUS_NAS_PORT_TYPE, RADIUS_ETHERNET); + $racct->putAttribute(RADIUS_NAS_PORT, $nas_port); + $racct->putAttribute(RADIUS_ACCT_SESSION_ID, $sessionid); + + // Extra data to identify the client and nas + $racct->putAttribute(RADIUS_FRAMED_IP_ADDRESS, $clientip, "addr"); + $racct->putAttribute(RADIUS_CALLED_STATION_ID, $calledstationid); + $racct->putAttribute(RADIUS_CALLING_STATION_ID, $callingstationid); + + // Send request + $result = $racct->send(); + + // Evaluation of the response + // 5 -> Accounting-Response + // See RFC2866 for this. + if (PEAR::isError($result)) { + $retvalue['acct_val'] = 1; + $retvalue['error'] = $result->getMessage(); + if ($debug) + printf("Radius send failed: %s<br>\n", $retvalue['error']); + } else if ($result === true) { + $retvalue['acct_val'] = 5 ; + if ($debug) + printf("Radius Accounting succeeded<br>\n"); + } else { + $retvalue['acct_val'] = 1 ; + if ($debug) + printf("Radius Accounting rejected<br>\n"); + } + + // close OO RADIUS_ACCOUNTING + $racct->close(); + + return $retvalue ; + } -function RADIUS_ACCOUNTING_STOP($ruleno,$username,$sessionid,$start_time,$radiusip,$radiusport,$radiuskey,$clientip,$interimupdate=false) { - $sharedsecret=$radiuskey ; - global $debug, $errno, $ipfw, $errstr,$nasHostname; - $matches = ""; - # $debug = 1 ; - exec("/bin/hostname", $nasHostname) ; - if(!$nasHostname[0]) - $nasHostname[0] = "quewall" ; - - $input_pkts = $input_bytes = $output_pkts = $output_bytes = 0 ; - - exec("/sbin/ipfw show {$ruleno}", $ipfw) ; - preg_match("/(\d+)\s+(\d+)\s+(\d+)\s+skipto/", $ipfw[0], $matches) ; - $input_pkts = $matches[2] ; - $input_bytes = $matches[3] ; - - unset($matches) ; - preg_match("/(\d+)\s+(\d+)\s+(\d+)\s+skipto/", $ipfw[1], $matches) ; - $output_pkts = $matches[2] ; - $output_bytes = $matches[3] ; - - $fd = @fsockopen("udp://$radiusip",$radiusport,$errno,$errstr,3) ; - if(!$fd) - return 1 ; /* error return */ - - /* set 5 second timeout on socket i/o */ - stream_set_timeout($fd, 5) ; - - $nas_ip_address = get_nas_ip(); - - if(!isset($clientip)) { - //if there's no client ip, we'll need to use the NAS ip - $clientip=$nas_ip_address; - } - $ip_exp=explode(".",$clientip); - - if ($debug) - echo "<br>radius-port: $radiusport<br>radius-host: $radiusip<br>username: $username<hr>\n"; - - $thisidentifier=rand()%256; - - $length=4+ // header - 16+ // auth code - 6+ // service type - 2+strlen($username)+ // username - 2+strlen($nasHostname[0])+ // nasIdentifier - 6+ // nasPort - 6+ // nasPortType - 6+ // Acct Status Type - 6+ // Acct RADIUS Authenticated - 2+strlen($sessionid)+ // Acct SessionID - 6+ // Acct terminate - 6+ // Session time - 6+ // input bytes - 6+ // input packets - 6+ // output bytes - 6+ // output packets - 2+strlen($nas_ip_address)+ //Called-Station-ID - 2+strlen($clientip)+ //Calling-Station-ID - - 6; //Framed-IP-Address - - if ($interimupdate) - $acctstatustype = 3; - else - $acctstatustype = 2; - - // v v v v v v v v v 1 1 1 1 1 1 1 v - // Line # 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 E - $data=pack("CCCCNNNNCCCCCCCCa*CCa*CCCCCCCCCCCCCCCCCCCCCCCCCCa*CCNCCNCCNCCNCCNCCNCCa*CCa*CCCCCC", - 4,$thisidentifier,$length/256,$length%256, // header - 0,0,0,0, // authcode - 6,6,0,0,0,1, // service type - 1,2+strlen($username),$username, // username - 32,2+strlen($nasHostname[0]),$nasHostname[0], // nasIdentifier - 5,6,0,0,0,0, // nasPort - 61,6,0,0,0,15, // nasPortType = Ethernet - 40,6,0,0,0,$acctstatustype, // Acct Status Type - 45,6,0,0,0,1, // Acct RADIUS Authenticated - 44,2+strlen($sessionid),$sessionid, // Acct Session ID - 49,6,1, // Acct Terminate = User Request - 46,6,time() - $start_time, // Session Time - 42,6,$input_bytes, // Input Octets - 47,6,$input_pkts, // Input Packets - 43,6,$output_bytes, // Output Octets - 48,6,$output_pkts, // Output Packets - 30,2+strlen($nas_ip_address),$nas_ip_address, //Called-Station-ID - 31,2+strlen($clientip),$clientip, //Calling-Station-ID - - 8,6,$ip_exp[0],$ip_exp[1],$ip_exp[2],$ip_exp[3] //Framed-IP-Address - ); - - /* Generate Accounting Request Authenticator */ - $RA = md5($data.$radiuskey) ; - - // v v v v v v v v v 1 1 1 1 1 1 1 v - // Line # 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 E - $data=pack("CCCCH*CCCCCCCCa*CCa*CCCCCCCCCCCCCCCCCCCCCCCCCCa*CCNCCNCCNCCNCCNCCNCCa*CCa*CCCCCC", - 4,$thisidentifier,$length/256,$length%256, // header - $RA, // authcode - 6,6,0,0,0,1, // service type - 1,2+strlen($username),$username, // username - 32,2+strlen($nasHostname[0]),$nasHostname[0], // nasIdentifier - 5,6,0,0,0,0, // nasPort - 61,6,0,0,0,15, // nasPortType = Ethernet - 40,6,0,0,0,$acctstatustype, // Acct Status Type - 45,6,0,0,0,1, // Acct RADIUS Authenticated - 44,2+strlen($sessionid),$sessionid, // Acct Session ID - 49,6,1, // Acct Terminate = User Request - 46,6,time() - $start_time, // Session Time - 42,6,$input_bytes, // Input Octets - 47,6,$input_pkts, // Input Packets - 43,6,$output_bytes, // Output Octets - 48,6,$output_pkts, // Output Packets - 30,2+strlen($nas_ip_address),$nas_ip_address, //Called-Station-ID - 31,2+strlen($clientip),$clientip, //Calling-Station-ID - - 8,6,$ip_exp[0],$ip_exp[1],$ip_exp[2],$ip_exp[3] //Framed-IP-Address - ); - - if($debug) { - echo "username is $username with len " . strlen($username) ."\n" ; - echo "nasHostname is {$nasHostname[0]} with len " . strlen($nasHostname[0]) ."\n" ; - } - - $ret = fwrite($fd,$data) ; - if( !$ret || ($ret != $length) ) - return 1; /* error return */ - - if ($debug) - echo "<br>writing $length bytes<hr>\n"; - - $readdata = fgets($fd,2) ; /* read 1 byte */ - $status = socket_get_status($fd) ; - fclose($fd) ; - - if($status['timed_out']) - $retvalue = 1 ; - else - $retvalue = ord($readdata) ; - - return $retvalue ; - // 5 -> Accounting-Response - // See RFC2866 for this. +/* +RADIUS ACCOUNTING STOP/UPDATE +----------------------------- +*/ + +function RADIUS_ACCOUNTING_STOP($ruleno,$username,$sessionid,$start_time,$radiusip,$radiusport,$radiuskey,$clientip,$clientmac, $term_cause = 1, $interimupdate=false,$stop_time = null) { + + global $config; + + $retvalue = array(); + $nas_mac = mac_format(get_interface_mac($config['interfaces']['wan']['if'])); + $clientmac = mac_format($clientmac); + $nas_port = $ruleno - 10000; + $radiusvendor = $config['captiveportal']['radiusvendor'] ? $config['captiveportal']['radiusvendor'] : null; + $stop_time = (empty($stop_time)) ? time() : $stop_time; + $session_time = $stop_time - $start_time; + $volume = getVolume($ruleno); + $volume['input_bytes_radius'] = remainder($volume['input_bytes']); + $volume['input_gigawords'] = gigawords($volume['input_bytes']); + $volume['output_bytes_radius'] = remainder($volume['output_bytes']); + $volume['output_gigawords'] = gigawords($volume['output_bytes']); + + switch($radiusvendor) { + + case 'cisco': + $calledstationid = $clientmac; + $callingstationid = $clientip; + break; + + default: + $calledstationid = $nas_mac; + $callingstationid = $clientmac; + } + + // Create our instance, see if we should use Accounting Interim Updates or Accounting STOP messages + if ($interimupdate) + $racct = new Auth_RADIUS_Acct_Update; + else + $racct = new Auth_RADIUS_Acct_Stop; + + /* + * Currently disabled + Add support for more then one radiusserver. + At most 10 servers may be specified. + When multiple servers are given, they are tried in round-robin fashion until a valid response is received + + foreach ($radiusservers as $radsrv) { + + // Add a new server to our instance + $racct->addServer($radsrv['ipaddr'], $radsrv['port'], $radsrv['key']); + + } + */ + + // See RADIUS_ACCOUNTING_START for info + $racct->authentic = RADIUS_AUTH_RADIUS; + + // Construct data package + $racct->username = $username; + $racct->addServer($radiusip, $radiusport, $radiuskey); + // Set session_time + $racct->session_time = $session_time; + + if (PEAR::isError($racct->start())) { + $retvalue['acct_val'] = 1; + $retvalue['error'] = $racct->getMessage(); + if ($debug) + printf("Radius start: %s<br>\n", $retvalue['error']); + // If we encounter an error immediately stop this function and go back + $racct->close(); + return $retvalue; + } + + // The RADIUS PECL Package doesn't have this vars so we create them ourself + define("RADIUS_ACCT_INPUT_GIGAWORDS", "52"); + define("RADIUS_ACCT_OUTPUT_GIGAWORDS", "53"); + + // Default attributes + $racct->putAttribute(RADIUS_SERVICE_TYPE, RADIUS_LOGIN); + $racct->putAttribute(RADIUS_NAS_PORT_TYPE, RADIUS_ETHERNET); + $racct->putAttribute(RADIUS_NAS_PORT, $nas_port); + $racct->putAttribute(RADIUS_ACCT_SESSION_ID, $sessionid); + + // Extra data to identify the client and nas + $racct->putAttribute(RADIUS_FRAMED_IP_ADDRESS, $clientip, "addr"); + $racct->putAttribute(RADIUS_CALLED_STATION_ID, $calledstationid); + $racct->putAttribute(RADIUS_CALLING_STATION_ID, $callingstationid); + + // Volume stuff: Ingress + $racct->putAttribute(RADIUS_ACCT_INPUT_PACKETS, $volume['input_pkts'], "integer"); + $racct->putAttribute(RADIUS_ACCT_INPUT_OCTETS, $volume['input_bytes_radius'], "integer"); + $racct->putAttribute(RADIUS_ACCT_INPUT_GIGAWORDS, $volume['input_gigawords'], "integer"); + // Volume stuff: Outgress + $racct->putAttribute(RADIUS_ACCT_OUTPUT_PACKETS, $volume['output_pkts'], "integer"); + $racct->putAttribute(RADIUS_ACCT_OUTPUT_OCTETS, $volume['output_bytes_radius'], "integer"); + $racct->putAttribute(RADIUS_ACCT_OUTPUT_GIGAWORDS, $volume['output_gigawords'], "integer"); + + if (!$interimupdate) + $racct->putAttribute(RADIUS_ACCT_TERMINATE_CAUSE, $term_cause); + + // Send request + $result = $racct->send(); + + // Evaluation of the response + // 5 -> Accounting-Response + // See RFC2866 for this. + if (PEAR::isError($result)) { + $retvalue['acct_val'] = 1; + $retvalue['error'] = $result->getMessage(); + if ($debug) + printf("Radius send failed: %s<br>\n", $retvalue['error']); + } else if ($result === true) { + $retvalue['acct_val'] = 5 ; + if ($debug) + printf("Radius Accounting succeeded<br>\n"); + } else { + $retvalue['acct_val'] = 1 ; + if ($debug) + printf("Radius Accounting rejected<br>\n"); + } + + // close OO RADIUS_ACCOUNTING + $racct->close(); + + return $retvalue; + } -function get_nas_ip() { - global $config; - - /* static WAN IP address */ - return $config['interfaces']['wan']['ipaddr']; + +/** + * Radius Volume Helpers + * + */ + +function gigawords($bytes) { + + + /* + * RFC2866 Specifies a 32bit unsigned integer, which is a max of 4294967295 + * Currently there is a fault in the PECL radius_put_int function which can handle only 32bit signed integer. + */ + + // We use BCMath functions since normal integers don't work with so large numbers + $gigawords = bcdiv( bcsub( $bytes, remainder($bytes) ) , 4294967295) ; + + // We need to manually set this to a zero instead of NULL for put_int() safety + if (is_null($gigawords)) { + $gigawords = 0; + } + + return $gigawords; + +} + +function remainder($bytes) { + + // Calculate the bytes we are going to send to the radius + $bytes = bcmod($bytes, 4294967295); + + if (is_null($bytes)) { + $bytes = 0; + } + + + return $bytes; + } -?> +?>
\ No newline at end of file diff --git a/usr/local/captiveportal/radius_authentication.inc b/usr/local/captiveportal/radius_authentication.inc index 7417029..f826c20 100644 --- a/usr/local/captiveportal/radius_authentication.inc +++ b/usr/local/captiveportal/radius_authentication.inc @@ -1,152 +1,160 @@ <?php - // - // $Id$ - // - // radius authentication v1.0 by Edwin Groothuis (edwin@mavetju.org) - // - // If you didn't get this file via http://www.mavetju.org, please - // check for the availability of newer versions. - // - // See LICENSE for distribution issues. If this file isn't in - // the distribution, please inform me about it. - // - // If you want to use this script, fill in the configuration in - // radius_authentication.conf and call the function - // RADIUS_AUTHENTICATION() with the username and password - // provided by the user. If it returns a 2, the authentication - // was successfull! - - // If you want to use this, make sure that you have raw sockets - // enabled during compile-time: "./configure --enable-sockets". - - // This version has been modified by Dinesh Nair <dinesh@alphaque.com> - // for use in the m0n0wall distribution http://m0n0.ch/wall/ - // - // Changes include moving from raw sockets to fsockopen - // and the removal of dependency on external conf file - // An existing bug which resulted in a malformed RADIUS packet - // was also fixed and patches submitted to Edwin. This bug would - // have caused authentication to fail on every access. - -function RADIUS_AUTHENTICATION($username,$password,$radiusip,$radiusport,$radiuskey) { - $sharedsecret=$radiuskey ; - global $debug, $errno, $nasHostname, $errstr; - # $debug = 1 ; - - exec("/bin/hostname", $nasHostname) ; - if(!$nasHostname[0]) - $nasHostname[0] = "m0n0wall" ; - - $fd = @fsockopen("udp://$radiusip",$radiusport,$errno,$errstr,3) ; - if(!$fd) - return 1 ; /* error return */ - - /* set 5 second timeout on socket i/o */ - stream_set_timeout($fd, 5) ; - - if ($debug) - echo "<br>radius-port: $radiusport<br>radius-host: $radiusip<br>username: $username<hr>\n"; - - $RA=pack("CCCCCCCCCCCCCCCC", // auth code - 1+rand()%255, 1+rand()%255, 1+rand()%255, 1+rand()%255, - 1+rand()%255, 1+rand()%255, 1+rand()%255, 1+rand()%255, - 1+rand()%255, 1+rand()%255, 1+rand()%255, 1+rand()%255, - 1+rand()%255, 1+rand()%255, 1+rand()%255, 1+rand()%255); - - $encryptedpassword=Encrypt($password,$sharedsecret,$RA); - - $length=4+ // header - 16+ // auth code - 6+ // service type - 2+strlen($username)+ // username - 2+strlen($encryptedpassword)+ // userpassword - 2+strlen($nasHostname[0])+ // nasIdentifier - 6+ // nasPort - 6; // nasPortType - - $thisidentifier=rand()%256; - // v v v v v v v v v - // Line # 1 2 3 4 5 6 7 8 E - $data=pack("CCCCa*CCCCCCCCa*CCa*CCa*CCCCCCCCCCCC", - 1,$thisidentifier,$length/256,$length%256, // header - $RA, // authcode - 6,6,0,0,0,1, // service type - 1,2+strlen($username),$username, // username - 2,2+strlen($encryptedpassword),$encryptedpassword, // userpassword - 32,2+strlen($nasHostname[0]),$nasHostname[0], // nasIdentifier - 5,6,0,0,0,0, // nasPort - 61,6,0,0,0,15 // nasPortType = Ethernet - ); - - if($debug) { - echo "username is $username with len " . strlen($username) ."\n" ; - echo "encryptedpassword is $encryptedpassword with len " . strlen($encryptedpassword) ."\n" ; - echo "nasHostname is {$nasHostname[0]} with len " . strlen($nasHostname[0]) ."\n" ; - } - - $ret = fwrite($fd,$data) ; - if( !$ret || ($ret != $length) ) - return 1; /* error return */ - - if ($debug) - echo "<br>writing $length bytes<hr>\n"; - - $readdata = fgets($fd,2) ; /* read 1 byte */ - $status = socket_get_status($fd) ; - fclose($fd) ; - - if($status['timed_out']) - $retvalue = 1 ; - else - $retvalue = ord($readdata) ; - - return $retvalue ; - // 2 -> Access-Accept - // 3 -> Access-Reject - // See RFC2865 for this. -} +/* vim: set expandtab tabstop=4 shiftwidth=4: */ /* -* $password = users password -* $key = shared secret -* $RA = Request Authenticator (random value it seems like) + $Id$ + + Copyright (c) 2006, Jonathan De Graeve <jonathan.de.graeve@imelda.be> + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + This code cannot simply be copied and put under the GNU Public License or + any other GPL-like (LGPL, GPL2) License. + + This code is made possible thx to samples made by Michael Bretterklieber <michael@bretterklieber.com> + author of the PHP PECL Radius package + */ -function Encrypt($password,$key,$RA) { - global $debug; - - if ($debug) - echo "<br>key: $key<br>password: $password<hr>\n"; - - $output=""; - $passlen = strlen($password); - /* figure out the number of xor rounds we need to run through */ - for ($i=16; $i <= 128; $i += 16) { - if ($len <= $i) { - $rounds = $i/16; - break; - } - } - - $z = 0; // How many chars have we xor'd - for ($x=0; $x<=$rounds; $x++) { - $keyRA=$key.$RA; - $md5checksum=md5($keyRA); - - // Loop 16 times (md5() output / 2) - for ($i=0;$i<=15;$i++) { - // Convert md5 hex output to decimal (md5 lengths are 32 chars) - if (2*$i>32) $m=0; else $m=hexdec(substr($md5checksum,2*$i,2)); - // get the decimal character value for this character in the password - if ($z>$passlen-1) $p=0; else $p=ord(substr($password,$z,1)); - // xor the md5 character with the password character - $c=$m^$p; - // Convert back to 8-bit output - $output.=chr($c); - $z++; - } - $RA=$output; - } - - return $output; + +/* +RADIUS AUTHENTICATION +--------------------- +*/ + +function RADIUS_AUTHENTICATION($username,$password,$radiusservers,$clientip,$clientmac,$ruleno) { + + global $config; + + $retvalue = array(); + $nas_mac = mac_format(get_interface_mac($config['interfaces']['wan']['if'])); + $clientmac = mac_format($clientmac); + $nas_port = $ruleno - 10000; + $radiusvendor = $config['captiveportal']['radiusvendor'] ? $config['captiveportal']['radiusvendor'] : null; + // Do we even need to set it to NULL? + $retvalue['error'] = $retvalue['reply_message'] = $retvalue['url_redirection'] = $retvalue['session_timeout'] = $retvalue['idle_timeout'] = $retvalue['session_terminate_time'] = null; + + switch($radiusvendor) { + + case 'cisco': + $calledstationid = $clientmac; + $callingstationid = $clientip; + break; + + default: + $calledstationid = $nas_mac; + $callingstationid = $clientmac; + } + + // Create our instance + $rauth = new Auth_RADIUS_PAP($username, $password); + + /* + Add support for more then one radiusserver. + At most 10 servers may be specified. + When multiple servers are given, they are tried in round-robin fashion until a valid response is received + */ + + foreach ($radiusservers as $radsrv) { + + // Add a new server to our instance + $rauth->addServer($radsrv['ipaddr'], $radsrv['port'], $radsrv['key']); + + } + + // Construct data package + $rauth->username = $username; + $rauth->password = $password; + + if (PEAR::isError($rauth->start())) { + $retvalue['auth_val'] = 1; + $retvalue['error'] = $rauth->getError(); + if ($debug) + printf("Radius start: %s<br>\n", $retvalue['error']); + // If we encounter an error immediately stop this function and go back + $rauth->close(); + return $retvalue; + } + + // Default attributes + $rauth->putAttribute(RADIUS_SERVICE_TYPE, RADIUS_LOGIN); + $rauth->putAttribute(RADIUS_NAS_PORT_TYPE, RADIUS_ETHERNET); + $rauth->putAttribute(RADIUS_NAS_PORT, $nas_port); + + // Extra data to identify the client and nas + $rauth->putAttribute(RADIUS_FRAMED_IP_ADDRESS, $clientip, addr); + $rauth->putAttribute(RADIUS_CALLED_STATION_ID, $calledstationid); + $rauth->putAttribute(RADIUS_CALLING_STATION_ID, $callingstationid); + + // Send request + $result = $rauth->send(); + + // Evaluation of the response + // 1 -> Access-Request => We will use this value as an error indicator since we can't get a 1 back from the radius + // 2 -> Access-Accept + // 3 -> Access-Reject + // See RFC2865 for this. + if (PEAR::isError($result)) { + $retvalue['auth_val'] = 1; + $retvalue['error'] = $result->getMessage(); + if ($debug) + printf("Radius send failed: %s<br>\n", $retvalue['error']); + } else if ($result === true) { + $retvalue['auth_val'] = 2; + if ($debug) + printf("Radius Auth succeeded<br>\n"); + } else { + $retvalue['auth_val'] = 3; + if ($debug) + printf("Radius Auth rejected<br>\n"); + } + + // Get attributes, even if auth failed. + // We will push the results in the retvalue array + if (!$rauth->getAttributes()) { + $retvalue['error'] = $rauth->getError(); + if ($debug) + printf("Radius getAttributes: No attributes<br>\n", $retvalue['error']); + } else { + $retvalue = array_merge($retvalue,$rauth->listAttributes()); + if ($debug) { + if (!$rauth->listAttributes()) + printf("No Attributes<br>\n"); + else + print_r($rauth->listAttributes()); + } + // We convert the session_terminate_time to unixtimestamp if its set before returning the whole array to our caller + if (!empty($retvalue['session_terminate_time'])) { + $stt = &$retvalue['session_terminate_time']; + $stt = strtotime(preg_replace("/\+(\d+):(\d+)$/", " +\${1}\${2}", preg_replace("/(\d+)T(\d+)/", "\${1} \${2}",$stt))); + } + } + + // close OO RADIUS_AUTHENTICATION + $rauth->close(); + + return $retvalue; + } -?> +?>
\ No newline at end of file diff --git a/usr/local/etc/php.ini b/usr/local/etc/php.ini index 5ed6686..91802b5 100644 --- a/usr/local/etc/php.ini +++ b/usr/local/etc/php.ini @@ -13,4 +13,5 @@ include_path = ".:/etc/inc:/usr/local/www:/usr/local/captiveportal:/usr/local/pk apc.enabled="1" apc.enable_cli="1" apc.shm_size="30" -extension=apc.so
\ No newline at end of file +extension=apc.so +extension=radius.so diff --git a/usr/local/lib/php.ini b/usr/local/lib/php.ini index 3068a86..95a507d 100644 --- a/usr/local/lib/php.ini +++ b/usr/local/lib/php.ini @@ -14,3 +14,4 @@ apc.enabled="1" apc.enable_cli="1" apc.shm_size="30" extension=apc.so +extension=radius.so
\ No newline at end of file diff --git a/usr/local/www/services_captiveportal.php b/usr/local/www/services_captiveportal.php index 05d6ebb..5ab3d75 100755 --- a/usr/local/www/services_captiveportal.php +++ b/usr/local/www/services_captiveportal.php @@ -211,8 +211,8 @@ function enable_change(enable_change) { document.iform.radiusport2.disabled = radius_endis; document.iform.radiuskey.disabled = radius_endis; document.iform.radiuskey2.disabled = radius_endis; - //document.iform.radacct_enable.disabled = radius_endis; - //document.iform.reauthenticate.disabled = radius_endis; + document.iform.radacct_enable.disabled = radius_endis; + document.iform.reauthenticate.disabled = radius_endis; document.iform.auth_method[0].disabled = endis; document.iform.auth_method[1].disabled = endis; document.iform.auth_method[2].disabled = endis; @@ -229,14 +229,14 @@ function enable_change(enable_change) { document.iform.htmlfile.disabled = endis; document.iform.errfile.disabled = endis; - //document.iform.radiusacctport.disabled = (radius_endis || !document.iform.radacct_enable.checked) && !enable_change; + document.iform.radiusacctport.disabled = (radius_endis || !document.iform.radacct_enable.checked) && !enable_change; - document.iform.radmac_secret.disabled = (radius_endis || !document.iform.radmac_enable.checked) && !enable_change; + document.iform.radmac_secret.disabled = (radius_endis || !document.iform.radmac_enable.checked) && !enable_change; var reauthenticate_dis = (radius_endis || !document.iform.reauthenticate.checked) && !enable_change; - //document.iform.reauthenticateacct[0].disabled = reauthenticate_dis; - //document.iform.reauthenticateacct[1].disabled = reauthenticate_dis; - //document.iform.reauthenticateacct[2].disabled = reauthenticate_dis; + document.iform.reauthenticateacct[0].disabled = reauthenticate_dis; + document.iform.reauthenticateacct[1].disabled = reauthenticate_dis; + document.iform.reauthenticateacct[2].disabled = reauthenticate_dis; } //--> </script> @@ -387,7 +387,44 @@ to access after they've authenticated.</td> <tr> <td colspan="2" class="list" height="12"></td> </tr> - + <tr> + <td colspan="2" valign="top" class="optsect_t2">Accounting</td> + </tr> + <tr> + <td class="vncell"> </td> + <td class="vtable"><input name="radacct_enable" type="checkbox" id="radacct_enable" value="yes" onClick="enable_change(false)" <?php if($pconfig['radacct_enable']) echo "checked"; ?>> + <strong>send RADIUS accounting packets</strong><br> + If this is enabled, RADIUS accounting packets will be sent to the primary RADIUS server.</td> + </tr> + <tr> + <td class="vncell" valign="top">Accounting port</td> + <td class="vtable"><input name="radiusacctport" type="text" class="formfld" id="radiusacctport" size="5" value="<?=htmlspecialchars($pconfig['radiusacctport']);?>"><br> + Leave blank to use the default port (1813).</td> + </tr> + <tr> + <td colspan="2" class="list" height="12"></td> + </tr> + <tr> + <td colspan="2" valign="top" class="optsect_t2">Reauthentication</td> + </tr> + <tr> + <td class="vncell"> </td> + <td class="vtable"><input name="reauthenticate" type="checkbox" id="reauthenticate" value="yes" onClick="enable_change(false)" <?php if($pconfig['reauthenticate']) echo "checked"; ?>> + <strong>Reauthenticate connected users every minute</strong><br> + If reauthentication is enabled, Access-Requests will be sent to the RADIUS server for each user that is + logged in every minute. If an Access-Reject is received for a user, that user is disconnected from the captive portal immediately.</td> + </tr> + <tr> + <td class="vncell" valign="top">Accounting updates</td> + <td class="vtable"> + <input name="reauthenticateacct" type="radio" value="" <?php if(!$pconfig['reauthenticateacct']) echo "checked"; ?>> no accounting updates<br> + <input name="reauthenticateacct" type="radio" value="stopstart" <?php if($pconfig['reauthenticateacct'] == "stopstart") echo "checked"; ?>> stop/start accounting<br> + <input name="reauthenticateacct" type="radio" value="interimupdate" <?php if($pconfig['reauthenticateacct'] == "interimupdate") echo "checked"; ?>> interim update + </td> + </tr> + <tr> + <td colspan="2" class="list" height="12"></td> + </tr> <tr> <td colspan="2" valign="top" class="optsect_t2">RADIUS MAC authentication</td> </tr> |