You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

309 lines
8.8 KiB

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 <gremlin@portal-to-web.de> 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 <rse@engelschall.com>
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 <pam_service> | *** if USE_PAM defined
db <string> | *** if USE_DB defined
ldap <string> | *** if USE_LDAP defined
+ radius <string> | *** if USE_RADIUS defined
nopassword
*<login_spec> for host and default only allow external lists
@@ -89,6 +90,7 @@
pam <pam_service> | *** if USE_PAM defined
db <string> | *** if USE_DB defined
ldap <string> | *** if USE_LDAP defined
+ radius <string> | *** 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:
+ * <radius key server1>,<radius server1>,<radius key server2>,<radius server2>,
+ * ... ,<radius key server9>,<radius server9>
+ *
+ * Author:
+ * Martin Mersberger <gremlin@portal-to-web.de>
+ * 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 <stdio.h>
+#include <string.h>
+
+#include "tac_plus.h"
+#include "radius.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#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 */