--- /dev/null Mon May 24 21:34:30 2004 +++ core/radius_api.php Mon May 24 21:34:27 2004 @@ -0,0 +1,236 @@ + + # + # Includes code from Edwin Groothuis + # Copyright 2000, 2001, 2002 by Edwin Groothuis. 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. All advertising materials mentioning features or use of this software + # must display the following acknowledgement: + # This product includes software developed by Edwin Groothuis. + # 4. Neither the name of Edwin Groothuis may be used to endorse or + # promote products derived from this software without specific + # prior written permission. + # + # 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 REGENTS 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. + + # -------------------------------------------------------- + # $Id: radius_api.php,v 1.6 2004/05/25 02:33:50 jcs Exp $ + # -------------------------------------------------------- + + ########################################################################### + # RADIUS Authentication API + ########################################################################### + + # -------------------- + # Wrapper for radius_doauth + function radius_authenticate( $p_user_id = '', $p_password = '') { + $t_username = user_get_field( $p_user_id, 'username' ); + + $t_server = config_get( 'radius_server' ); + $t_port = config_get( 'radius_port' ); + $t_secret = config_get( 'radius_secret' ); + $t_timeout = config_get( 'radius_timeout' ); + + $t_retval = radius_doauth( $t_username, $p_password, $t_server, $t_port, + $t_secret, $t_timeout ); + + # 2 == Access-Accept + # 3 == Access-Reject + if ( $t_retval == 2 ) + return true; + else + return false; + } + + # -------------------- + # Actual socket and verification routines + function radius_doauth( $p_username, $p_password, $p_server, $p_port = 1812, + $p_secret, $p_timeout = 3 ) { + $t_encpassword = ""; + + # store each octet of our server's ip in an array, to use as the nas + # client + $t_me = explode( ".", $_SERVER["SERVER_ADDR"] ); + + # copy + $t_temppassword = $p_password; + + # create socket + $t_radip = gethostbyname( $p_server ); + $t_socket = socket_create( AF_INET, SOCK_DGRAM, SOL_UDP ); + $t_retval = socket_connect( $t_socket, $t_radip, $p_port ); + + # generate 16 bytes of randomness + $t_authenticator = pack( "CCCCCCCCCCCCCCCC", + 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 ); + + # pad password a multiple of 16 bytes + if ( ( strlen( $t_temppassword ) % 16 ) != 0 ) + for ( $x = 16; $x > ( strlen( $t_temppassword ) % 16 ); $x-- ) + $t_temppassword .= "\0"; + + # cut up into 16-byte pieces, hash each one + for ( $x = 0; $x <= ( intval( strlen( $t_temppassword ) - 1) / 16); + $x++ ) { + $t_piece = substr( $t_temppassword, ( $x * 16 ), 16 ); + + if ( strlen( $t_encpassword ) ) + # instead of using the authenticator, we use 16 octets from the + # first xor + $t_encpassword .= radius_md5hash( $t_piece, $p_secret, + substr( $t_encpassword, ( $x - 1 ) * 16, 16 ) ); + else + $t_encpassword .= radius_md5hash( $t_piece, $p_secret, + $t_authenticator ); + } + + # length of entire packet, needed in the packet itself + $t_slen = 4 + 16 + 6 + ( 2 + strlen( $p_username ) ) + + ( 2 + strlen( $t_encpassword ) ) + 6 + 6; + + # unique request + $t_reqid = rand() % 256; + + # assemble the packet + $t_payload = pack( + "CCCC" . # code, ident, len + "a*" . # authenticator + "CCCCCC" . # service type + "CCa*" . # 1: username + "CCa*" . # 2: password + "CCCCCC" . # 4: nas ip + "CCCCCC", # 5: nas port + + 1, $t_reqid, $t_slen / 256, $t_slen % 256, # access-request + $t_authenticator, # authenticator + 6, 6, 0, 0, 0, 1, # service-type + 1, 2 + strlen( $p_username ), $p_username, # 1: username + 2, 2 + strlen( $t_encpassword ), $t_encpassword,# 2: password + 4, 6, $t_me[0], $t_me[1], $t_me[2], $t_me[3], # 4: our IP + 5, 6, 0, 0, 0, 0 ); # 5: nas port + + /* send it */ + socket_write( $t_socket, $t_payload, $t_slen ); + + if ( function_exists( "socket_select" ) ) { + # timeout after a specified amount of seconds + $t_read = array( $t_socket ); + if ( !socket_select( $t_read, $t_junk = NULL, $t_junk = NULL, + $p_timeout ) ) { + error_log( "RADIUS server " . $p_server . " did not respond " + . "within " . $timeout . " second" + . ( $timeout == 1 ? "" : "s" ) ); + + return -1; + } + } + + # get our response and clean up + $t_readdata = @socket_read( $t_socket, 4096 ); + socket_close( $t_socket ); + + if ( $t_readdata ) { + # 0, 1 - code + # 1, 1 - identifier + # 2, 2 - length + # 4, 16 - authenticator + # 20, ? - variable length attributes + + # pull out the identifier and make sure this is our request + if ( ord( substr( $t_readdata, 1, 1 ) ) != $t_reqid ) { + error_log( "Got RADIUS reply from " . $p_server . " for a request " + . "that wasn't ours" ); + + return -1; + } + + # pull out the authenticator + $t_checkauth = substr( $t_readdata, 4, 16 ); + + # encode the returned packet with our original authenticator and secret + $t_checkver = radius_md5bin( substr( $t_readdata, 0, 4) + . $t_authenticator . substr( $t_readdata, 20, + strlen( $t_readdata ) - 20 ) . $p_secret ); + + if ($t_checkver != $t_checkauth) { + # packet authentication failed, something broke along the way + error_log( "RADIUS authentication packet from " . $p_server + . " for user " . $p_username . " fails verification" ); + + return -1; + } + + # we have a successful return packet, return the code from the server + # 2 == Access-Accept, 3 == Access-Reject + return ord( substr( $t_readdata, 0, 1 ) ); + } else { + # no response + error_log( "RADIUS server " . $p_server . " responded with no " + . "answer" ); + + return -1; + } + } + + # -------------------- + # Hashing routine + function radius_md5hash( $p_password, $p_key, $p_random ) { + $t_keyrandom = $p_key . $p_random; + $t_checksum = md5( $t_keyrandom ); + + $t_output = ""; + + for ( $x = 0; $x <= 15; $x++ ) { + if ( ( 2 * $x ) > strlen( $t_checksum ) ) + $t_m = 0; + else + $t_m = hexdec( substr( $t_checksum, ( 2 * $x ), 2 ) ); + + if ($x > strlen( $p_password ) ) + $t_p = 0; + else + $t_p = ord( substr( $p_password, $x, 1 ) ); + + $t_c = $t_m ^ $t_p; + $t_output .= chr( $t_c ); + } + + return $t_output; + } + + # -------------------- + # Return a binary md5 digest of a string + function radius_md5bin( $p_string ) { + $t_md5digest = md5( $p_string ); + $t_binary = pack( "H" . strlen( $t_md5digest ), $t_md5digest ); + + return $t_binary; + } + +?> --- account_page.php.orig Sun Jan 11 01:16:04 2004 +++ account_page.php Mon May 24 21:25:31 2004 @@ -97,6 +97,18 @@ + + + + + + + + + + + + --- config_defaults_inc.php.orig Wed May 12 06:36:14 2004 +++ config_defaults_inc.php Mon May 24 21:25:31 2004 @@ -569,6 +569,15 @@ $g_ldap_bind_passwd = ''; $g_use_ldap_email = OFF; # Should we send to the LDAP email address or what MySql tells us + ############################# + # Mantis RADIUS Settings + ############################# + + $g_radius_server = 'radius.example.com'; + $g_radius_port = '1812'; + $g_radius_secret = 'supersecret'; + $g_radius_timeout = '3'; + ############################ # Status Settings ############################ --- config_inc.php.sample.orig Sun Feb 8 07:16:56 2004 +++ config_inc.php.sample Mon May 24 21:25:31 2004 @@ -49,7 +49,7 @@ $g_return_path_email = 'admin@example.com'; # --- login method ---------------- - # CRYPT or PLAIN or MD5 or LDAP or BASIC_AUTH + # CRYPT or PLAIN or MD5 or LDAP or RADIUS or BASIC_AUTH $g_login_method = MD5; # --- email vars ------------------ --- core/authentication_api.php.orig Thu Feb 5 06:15:16 2004 +++ core/authentication_api.php Mon May 24 21:25:31 2004 @@ -148,7 +148,11 @@ if ( LDAP == $t_configured_login_method ) { return ldap_authenticate( $p_user_id, $p_test_password ); } - + + if ( RADIUS == $t_configured_login_method ) { + return radius_authenticate( $p_user_id, $p_test_password ); + } + $t_password = user_get_field( $p_user_id, 'password' ); $t_login_methods = Array(MD5, CRYPT, PLAIN); --- core/constant_inc.php.orig Wed Feb 11 16:16:28 2004 +++ core/constant_inc.php Mon May 24 21:25:32 2004 @@ -96,6 +96,7 @@ define( 'MD5', 3 ); define( 'LDAP', 4 ); define( 'BASIC_AUTH', 5 ); + define( 'RADIUS', 6 ); # file upload methods define( 'DISK', 1 ); --- core/user_api.php.orig Sun Jan 11 01:16:10 2004 +++ core/user_api.php Mon May 24 21:25:32 2004 @@ -13,6 +13,7 @@ require_once( $t_core_dir . 'email_api.php' ); require_once( $t_core_dir . 'ldap_api.php' ); + require_once( $t_core_dir . 'radius_api.php' ); ########################################################################### # User API