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 = "
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; } } ?>