--- /dev/null	Mon May 24 21:34:30 2004
+++ core/radius_api.php	Mon May 24 21:34:27 2004
@@ -0,0 +1,236 @@
+<?php
+	# $DLS: radius_api.php,v 1.6 2004/05/25 02:33:50 jcs Exp $
+	#
+	# Copyright (c) 2004, DLS Internet Services
+	# Written by Joshua Stein <jcs@eng.dls.net>
+	#
+	# Includes code from Edwin Groothuis <edwin@mavetju.org>
+	# 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 @@
 		</td>
 	</tr>
 
+<?php } elseif ( RADIUS == config_get( 'login_method' ) ) { ?>
+
+	<!-- Username -->
+	<tr class="row-1">
+		<td class="category" width="25%">
+			<?php echo lang_get( 'username' ) ?>
+		</td>
+		<td width="75%">
+			<?php echo $u_username ?>
+		</td>
+	</tr>
+
 <?php } else { ?> <!-- Without LDAP -->
 
 	<!-- Username -->
--- 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
