This patch adds RADIUS authentication support, allowing the TACACS+ server to authenticate against a RADIUS server. It is derived from an original "TACACS to RADIUS" patch from Martin Mersberger which can be found under http://www.portal-to-web.de/tacacs/. It was cleaned up and ported to the latest TACACS+ 4.4b1 version by Ralf S. Engelschal for inclusion into the OpenPKG "tacacs" package. Index: config.c --- config.c.orig 2003-04-08 03:37:02.000000000 +0200 +++ config.c 2003-10-24 17:01:35.000000000 +0200 @@ -77,6 +77,7 @@ pam | *** if USE_PAM defined db | *** if USE_DB defined ldap | *** if USE_LDAP defined + radius | *** if USE_RADIUS defined nopassword * for host and default only allow external lists @@ -89,6 +90,7 @@ pam | *** if USE_PAM defined db | *** if USE_DB defined ldap | *** if USE_LDAP defined + radius | *** if USE_RADIUS defined login *** use the same method as the login *** Added acct_spec 6/12/02 JRM @@ -964,6 +966,9 @@ #ifdef USE_PAM case S_pam: #endif +#ifdef USE_RADIUS + case S_radius: +#endif sym_get(0); authen_default = tac_strdup(sym_buf); break; @@ -1431,6 +1436,9 @@ #ifdef USE_PAM case S_pam: #endif /* USE_PAM */ +#ifdef USE_RADIUS + case S_radius: +#endif sym_get(0); host->login = tac_strdup(sym_buf); break; @@ -1494,6 +1502,9 @@ #ifdef USE_PAM case S_pam: #endif /* USE_PAM */ +#ifdef USE_RADIUS + case S_radius: +#endif sym_get(0); host->enable = tac_strdup(sym_buf); break; @@ -1743,6 +1754,9 @@ #ifdef USE_PAM case S_pam: #endif /* USE_PAM */ +#ifdef USE_RADIUS + case S_radius: +#endif sym_get(0); user->login = tac_strdup(sym_buf); break; @@ -1830,6 +1844,9 @@ #ifdef USE_PAM case S_pam: #endif /* USE_PAM */ +#ifdef USE_RADIUS + case S_radius: +#endif sym_get(0); user->enable = tac_strdup(sym_buf); break; Index: parse.c --- parse.c.orig 2003-03-03 15:30:26.000000000 +0100 +++ parse.c 2003-10-24 17:03:51.000000000 +0200 @@ -101,6 +101,9 @@ #ifdef USE_LDAP declare ("ldap", S_ldap); #endif +#ifdef USE_RADIUS + declare("radius", S_radius); +#endif declare("member", S_member); declare("message", S_message); declare("name", S_name); @@ -301,5 +304,9 @@ return("enable_deny"); case S_unix: return("unix"); +#ifdef USE_RADIUS + case S_radius: + return ("radius"); +#endif /*USE_PAM */ } } Index: parse.h --- parse.h.orig 2003-03-03 15:28:07.000000000 +0100 +++ parse.h 2003-10-24 17:02:26.000000000 +0200 @@ -108,3 +108,6 @@ #define S_unix 62 #define S_motd 63 #define S_accesslog 64 +#ifdef USE_RADIUS +#define S_radius 65 +#endif Index: pwlib.c --- pwlib.c.orig 2003-04-01 00:13:10.000000000 +0200 +++ pwlib.c 2003-10-24 17:06:25.000000000 +0200 @@ -37,6 +37,10 @@ #include "ldap.h" #endif /* LDAP */ +#ifdef USE_RADIUS +#include "radius.h" +#endif + /* Generic password verification routines for des, file and cleartext passwords */ @@ -47,7 +51,6 @@ static int unix_verify(char *user, char *supplied_passwd, struct authen_data *data); - void set_expiration_status(exp_date, data) char *exp_date; @@ -301,6 +304,17 @@ #endif /* USE_PAM */ +#ifdef USE_RADIUS + case S_radius: + if (radius_verify(name, passwd, cfg_login) == 1) { + data->status = TAC_PLUS_AUTHEN_STATUS_FAIL; + } else { + data->status = TAC_PLUS_AUTHEN_STATUS_PASS; + exp_date = NULL; /* no expire check for RADIUS */ + } + break; +#endif + case S_des: /* try to verify this des password */ if (!des_verify(passwd, cfg_login)) { Index: radius.h --- radius.h.orig 2003-10-24 16:58:03.000000000 +0200 +++ radius.h 2003-10-24 16:58:03.000000000 +0200 @@ -0,0 +1,6 @@ +#ifndef __RADIUS_H__ +#define __RADIUS_H__ + +extern radius_verify(char *, char *, char *); + +#endif /* __RADIUS_H__ */ Index: Makefile.in --- Makefile.in.orig 2003-04-11 04:30:25.000000000 +0200 +++ Makefile.in 2003-10-24 17:16:45.000000000 +0200 @@ -158,7 +158,7 @@ # $(use_o) has to be BEFORE $(conf_LDADD)! (for library dependencies) tac_plus_LDADD = $(use_o) $(conf_LDADD) tac_plus_DEPENDENCIES = $(use_o) -use = @COND_USE@ +use = @COND_USE@ radius.c use_o = $(filter %.o,$(use:.c=.o)) cond_USE_DB = db.c db.h db_author.c @@ -166,6 +166,7 @@ cond_DB_NULL = db_null.c cond_DB_PGSQL = db_pgsql.c cond_USE_LDAP = ldap.c +cond_USE_RADIUS = radius.c cond_MAXSESS = maxsess.c cond_MSCHAP = md4.c md4.h cond_SKEY = skey_fn.c @@ -181,6 +182,7 @@ $(cond_DB_NULL) \ $(cond_DB_PGSQL) \ $(cond_USE_LDAP) \ + $(cond_USE_RADIUS) \ $(cond_MAXSESS) \ $(cond_MSCHAP) \ $(cond_SKEY) \ Index: radius.c --- radius.c.orig 2003-10-24 16:58:03.000000000 +0200 +++ radius.c 2003-10-24 17:19:49.000000000 +0200 @@ -0,0 +1,117 @@ +/* + * Verify that this user/password is valid per a RADIUS server database + * Return 1 if verified, 0 otherwise. + * + * Format of connection string: + * ,,,, + * ... ,, + * + * Author: + * Martin Mersberger + * http://www.portal-to-web.de/tacacs + * + * Dependencies: + * You need to get the Juniper Networks libradius + * (included in FreeBSD >= 4.x) + * + * License: + * tac_radius is free software; you can redistribute it + * and/or modify it under the terms of the BSD License + */ + +#include "config.h" + +#if defined(USE_RADIUS) + +#include +#include + +#include "tac_plus.h" +#include "radius.h" + +#include +#include +#include +#include +#include "radlib.h" + +int radius_verify(char *user, char *users_passwd, char *str_conn) +{ + struct rad_handle *rh; + struct in_addr addr; + int res; + char *token, *cp; + char *server[10]; + char *key[10]; + int i, j; + char l_err[200]; + int err; + + /* open the radius handle */ + if ((rh = rad_auth_open()) == NULL ) { + report(LOG_ERR,"Can't open rad_open"); + return 1; + } + + /* split the line from the config file into pairs with radiusserver and radius key */ + cp = strdup(str_conn); + i = 0; + while ((token = strsep(&cp,",")) != NULL) { + if ((i % 2) == 0) { /* 0,2,4,... are the radius keys */ + key[i] = (char *)malloc(sizeof(token) + sizeof(char)); /* get some mem */ + sprintf(key[i], "%s\0", token); /* add the value gotten into a array */ + } else { + server[i-1] = (char *)malloc(sizeof(token) + sizeof(char)); /* 1,3,5... are the radius hosts */ + sprintf(server[i-1], "%s\0", token); /* malloc and add to array */ + } + i++; + } + + /* for each server and key pair gotten from the config file, do a rad_add_server */ + for (j = 0; j < i; j = j + 2) { + report(LOG_INFO, "verify_radius: before ldap_init: radiusserver = %s, radiuskey = %s", server[j],key[j]); + if ((rad_add_server(rh,server[j], 0, key[j], 2, 2)) != 0) { + report (LOG_ERR, "Error in rad_add_server for %s", server[j]); + return (1); + } + } + + /* create a radius request for ACCESS */ + if ((rad_create_request(rh ,RAD_ACCESS_REQUEST)) != 0) { + report (LOG_ERR, "Error in rad_create_request"); + return (1); + } + + /* prepare the radius request + * 1. make a in_addr from the requesting peer ip address + * 2. put in username + * 3. put in password + * 4. insert the in_addr into the rad_request + * 5. set the RAD_CONNECT_INFO to "via tacacs+" + */ + inet_aton(session.peer, &addr); + rad_put_string(rh, RAD_USER_NAME, user); + rad_put_string(rh, RAD_USER_PASSWORD, users_passwd); + rad_put_addr(rh, RAD_NAS_IP_ADDRESS,addr); + rad_put_string(rh, RAD_CONNECT_INFO," via TACACS+ server"); + + /* some debug messages before sending the radius request */ +#if 0 + report(LOG_INFO, "verify_radius: before rad_send: user = %s, passwd = %s", user, "********"); + report(LOG_INFO, "verify_radius: before rad_send: peer %s", session.peer); +#endif + + /* send the radius request and hope, that libradius does a good job */ + res = rad_send_request(rh); + + /* is the user authenticated? if yes, return 0, else 1 */ + if (res == RAD_ACCESS_ACCEPT ) { + report(LOG_INFO, "Request accepted\n"); + return 0; + } else { + report(LOG_INFO, "Request denied %i\n",res); + return 1; + } +} + +#endif /* RADIUS */