mirror of
https://github.com/e107inc/e107.git
synced 2025-01-17 20:58:30 +01:00
251 lines
7.3 KiB
PHP
251 lines
7.3 KiB
PHP
<?php
|
|
/*
|
|
+ ----------------------------------------------------------------------------+
|
|
| e107 website system
|
|
|
|
|
| Copyright (C) 2008-2009 e107 Inc (e107.org)
|
|
| http://e107.org
|
|
|
|
|
|
|
|
| Released under the terms and conditions of the
|
|
| GNU General Public License (http://gnu.org).
|
|
|
|
|
| $Source: /cvs_backup/e107_0.8/e107_plugins/alt_auth/radius_auth.php,v $
|
|
| $Revision$
|
|
| $Date$
|
|
| $Author$
|
|
+----------------------------------------------------------------------------+
|
|
|
|
RFC2865 is the main RADIUS standard - http://www.faqs.org/rfcs/rfc2865
|
|
|
|
Potential enhancements:
|
|
- Multiple servers (done, but not tested)
|
|
- Configurable port (probably not necessary)
|
|
- Configurable timeout
|
|
- Configurable retries
|
|
|
|
Error recfrom: 10054 - winsock error for 'connection reset'
|
|
*/
|
|
|
|
define('RADIUS_DEBUG',FALSE);
|
|
|
|
class auth_login extends alt_auth_base
|
|
{
|
|
private $server;
|
|
private $secret;
|
|
private $port;
|
|
private $usr;
|
|
private $pwd;
|
|
private $connection; // Handle to use on successful creation
|
|
public $Available = FALSE; // Flag indicates whether DB connection available
|
|
public $ErrorText; // e107 error string on exit
|
|
|
|
|
|
/**
|
|
* Read configuration, initialise connection to LDAP database
|
|
*
|
|
* @return int AUTH_xxxx result code
|
|
*/
|
|
function __construct()
|
|
{
|
|
$this->copyAttribs = array();
|
|
$radius = $this->altAuthGetParams('radius');
|
|
|
|
$this->server = explode(',',$radius['radius_server']);
|
|
$this->port = 1812; // Assume fixed port number for now - 1812 (UDP) is listed for servers, 1645 for authentification. (1646, 1813 for accounting)
|
|
// (A Microsoft app note says 1812 is the RFC2026-compliant port number. (http://support.microsoft.com/kb/230786)
|
|
// $this->port = 1645;
|
|
$this->secret = explode(',',$radius['radius_secret']);
|
|
if ((count($this->server) > 1) && (count($this->secret) == 1))
|
|
{
|
|
$this->secret = array();
|
|
foreach ($this->server as $k => $v)
|
|
{
|
|
$this->secret[$k] = $radius['radius_secret']; // Same secret for all servers, if only one entered
|
|
}
|
|
}
|
|
$this->ErrorText = '';
|
|
if(!function_exists('radius_auth_open'))
|
|
{
|
|
return AUTH_NORESOURCE;
|
|
}
|
|
|
|
if(!$this -> connect())
|
|
{
|
|
return AUTH_NOCONNECT;
|
|
}
|
|
$this->Available = TRUE;
|
|
return AUTH_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Retrieve and construct error strings
|
|
*/
|
|
function makeErrorText($extra = '')
|
|
{
|
|
$this->ErrorText = $extra.radius_strerror($this->connection) ;
|
|
if (!RADIUS_DEBUG) return;
|
|
$text = "<br />Server: {$this->server} Stored secret: ".radius_server_secret($this->connection)." Port: {$this->port}";
|
|
$this->ErrorText .= $text;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Try to connect to a radius server
|
|
*
|
|
* @return boolean TRUE for success, FALSE for failure
|
|
*/
|
|
function connect()
|
|
{
|
|
if (!($this->connection = radius_auth_open()))
|
|
{
|
|
$this->makeErrorText('RADIUS open failed: ') ;
|
|
return FALSE;
|
|
}
|
|
foreach ($this->server as $k => $s)
|
|
{
|
|
if (!radius_add_server($this->connection, $s, $this->port, $this->secret[$k], 15, 1)) // fixed 15 second timeout, one try ATM
|
|
{
|
|
$this->makeErrorText('RADIUS add server failed: ') ;
|
|
return FALSE;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Close the connection to the Radius server
|
|
*/
|
|
function close()
|
|
{
|
|
if ( !radius_close( $this->connection)) // (Not strictly necessary, but tidy)
|
|
{
|
|
$this->makeErrorText('RADIUS close error: ') ;
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Validate login credentials
|
|
*
|
|
* @param string $uname - The user name requesting access
|
|
* @param string $pass - Password to use (usually plain text)
|
|
* @param pointer &$newvals - pointer to array to accept other data read from database
|
|
* @param boolean $connect_only - TRUE to simply connect to the server
|
|
*
|
|
* @return integer result (AUTH_xxxx)
|
|
*
|
|
* On a successful login, &$newvals array is filled with the requested data from the server
|
|
*/
|
|
function login($uname, $pass, &$newvals, $connect_only = FALSE)
|
|
{
|
|
// Create authentification request
|
|
if (!radius_create_request($this->connection,RADIUS_ACCESS_REQUEST))
|
|
{
|
|
$this->makeErrorText('RADIUS failed authentification request: ') ;
|
|
return AUTH_NOCONNECT;
|
|
}
|
|
|
|
if (trim($pass) == '') return AUTH_BADPASSWORD; // Pick up a blank password - always expect one
|
|
|
|
// Attach username and password
|
|
if (!radius_put_attr($this->connection,RADIUS_USER_NAME,$uname)
|
|
|| !radius_put_attr($this->connection,RADIUS_USER_PASSWORD,$pass))
|
|
{
|
|
$this->makeErrorText('RADIUS could not attach username/password: ') ;
|
|
return AUTH_NOCONNECT;
|
|
}
|
|
|
|
// Finally, send request to server
|
|
switch (radius_send_request($this->connection))
|
|
{
|
|
case RADIUS_ACCESS_ACCEPT : // Valid username/password
|
|
break;
|
|
case RADIUS_ACCESS_CHALLENGE : // CHAP response required - not currently implemented
|
|
$this->makeErrorText('CHAP not supported');
|
|
return AUTH_NOUSER;
|
|
case RADIUS_ACCESS_REJECT : // Specifically rejected
|
|
default: // Catch-all
|
|
$this->makeErrorText('RADIUS validation error: ') ;
|
|
return AUTH_NOUSER;
|
|
}
|
|
|
|
// User accepted here.
|
|
|
|
if ($connect_only) return AUTH_SUCCESS;
|
|
return AUTH_SUCCESS; // Not interested in any attributes returned ATM, so done.
|
|
|
|
|
|
|
|
// See if we get any attributes - not really any use to us unless we implement CHAP, so disabled ATM
|
|
$attribs = array();
|
|
while ($resa = radius_get_attr($this->connection))
|
|
{
|
|
if (!is_array($resa))
|
|
{
|
|
$this->makeErrorText("Error getting attribute: ");
|
|
exit;
|
|
}
|
|
// Decode attribute according to type (this isn't an exhaustive list)
|
|
// Codes: 2, 3, 4, 5, 30, 31, 32, 60, 61 should never be received by us
|
|
// Codes 17, 21 not assigned
|
|
switch ($resa['attr'])
|
|
{
|
|
case 8 : // IP address to be set (255.255.255.254 indicates 'allocate your own address')
|
|
case 9 : // Subnet mask
|
|
case 14 : // Login-IP host
|
|
$attribs[$resa['attr']] = radius_cvt_addr($resa['data']);
|
|
break;
|
|
case 6 : // Service type (integer bitmap)
|
|
case 7 : // Protocol (integer bitmap)
|
|
case 10 : // Routing method (integer)
|
|
case 12 : // Framed MTU
|
|
case 13 : // Compression method
|
|
case 15 : // Login service (bitmap)
|
|
case 16 : // Login TCP port
|
|
case 23 : // Framed IPX network (0xFFFFFFFE indicates 'allocate your own')
|
|
case 27 : // Session timeout - maximum connection/login time in seconds
|
|
case 28 : // Idle timeout in seconds
|
|
case 29 : // Termination action
|
|
case 37 : // AppleTalk link number
|
|
case 38 : // AppleTalk network
|
|
case 62 : // Max ports
|
|
case 63 : // Login LAT port
|
|
$attribs[$resa['attr']] = radius_cvt_int($resa['data']);
|
|
break;
|
|
case 1 : // User name
|
|
case 11 : // Filter ID - could get several of these
|
|
case 18 : // Reply message (text, various purposes)
|
|
case 19 : // Callback number
|
|
case 20 : // Callback ID
|
|
case 22 : // Framed route - could get several of these
|
|
case 24 : // State - used in CHAP
|
|
case 25 : // Class
|
|
case 26 : // Vendor-specific
|
|
case 33 : // Proxy State
|
|
case 34 : // Login LAT service
|
|
case 35 : // Login LAT node
|
|
case 36 : // Login LAT group
|
|
case 39 : // AppleTalk zone
|
|
default :
|
|
$attribs[$resa['attr']] = radius_cvt_string($resa['data']); // Default to string type
|
|
}
|
|
printf("Got Attr: %d => %d Bytes %s\n", $resa['attr'], strlen($attribs[$resa['attr']]), $attribs[$resa['attr']]);
|
|
}
|
|
|
|
return AUTH_SUCCESS;
|
|
}
|
|
}
|
|
|