for Cisco's tac_plus.F4.0.4.alpha release from ftp-eng.cisco.com/pub/tacacs/
Then I added account checking into the authentication so pam based account restrictions such as pam_tally work (I wanted account lockout on 3 authentication failures).
I also incorporated an update in config.c that I think will make configuration
less confusing:
When compiled with pam support
default authentication = file name_of_passwordfilebecomes invalid and
default authentication = pam name_of_serviceis the expected syntax. This requires the configuration file to reflect the underlying behaviour introduced in patch version 0.2.
Lastly I changed some default file paths in Makefile and several
things in tac_plus.init in an attempt
to conform to newer unix and linux conventions.
As with CISCO's software these patches are provided ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
Cisco - Pam adds great flexibility to tacacs+ so I hope you will consider merging this patch into your source code. If not perhaps someone out there (Max?) will find it a home so it may still be useful to others.
Red Hat - How about including a nice tacacs+ rpm WITH pam support in powertools?
-Chris
diff -Naur tac_plus.F4.0.4.alpha/Makefile tac_plus.F4.0.4.alpha-PAM-0.4/Makefile --- tac_plus.F4.0.4.alpha/Makefile Sun Jun 18 13:26:54 2000 +++ tac_plus.F4.0.4.alpha-PAM-0.4/Makefile Fri Feb 2 17:27:15 2001 @@ -33,8 +33,8 @@ # OS=-DMIPS # For Solaris (SUNOS 5.3, 5.4, 5.5, 5.6) uncomment the following two lines -OS=-DSOLARIS -OSLIBS=-lsocket -lnsl +#OS=-DSOLARIS +#OSLIBS=-lsocket -lnsl # For FreeBSD # OS=-DFREEBSD @@ -49,9 +49,13 @@ # # On REDHAT 5.0 systems, or systems that use the new glibc, # you might instead need the following: -# OS=-DLINUX -DGLIBC -# OSLIBS=-lcrypt +OS=-DLINUX -DGLIBC +OSLIBS=-lcrypt + +#For PAM +DEFINES = -DUSE_PAM +OSLIBS+= -lpam -ldl -lc # Athough invoked as root, most of the time you don't want tac_plus to # be running as root. If USERID and GROUPID are set, tac_plus will @@ -69,7 +73,7 @@ # INCLUDES = -I../crimelab/skey/src # Debugging flags -DEBUG = -g +DEBUG = -O3 # Enforce a limit on maximum sessions per user. See the user's guide # for more information. @@ -85,7 +89,7 @@ # possible), containing its process id. Uncomment and modify the # following line to change this filename -# PIDFILE = -DTAC_PLUS_PIDFILE=\"/var/run/tac_plus.pid\" +PIDFILE = -DTAC_PLUS_PIDFILE=\"/var/run/tac_plus.pid\" # # End of customisable section of Makefile @@ -99,7 +103,7 @@ do_author.c dump.c encrypt.c expire.c $(MSCHAP_MD4_SRC) md5.c \ packet.c report.c sendauth.c tac_plus.c utils.c pw.c hash.c \ parse.c regexp.c programs.c enable.c pwlib.c default_fn.c \ - skey_fn.c default_v0_fn.c sendpass.c maxsess.c + skey_fn.c default_v0_fn.c sendpass.c maxsess.c tac_pam_auth.c OBJS = $(SRCS:.c=.o) @@ -130,8 +134,11 @@ -rm -f *.o *~ *.BAK tac_plus generate_passwd install: - cp tac_plus /usr/local/bin - cp tac_plus.1 /usr/man/manl/tac_plus.1 + cp tac_plus /usr/local/sbin + cp tac_plus.1 /usr/share/man/man1/tac_plus.1 + @echo "You may also wish to:" + @echo " copy start script 'tac_plus.init' to /etc/init.d/tacacs and edit" + @echo " copy sample configuration 'tac_plus.conf' to /etc/tacacs/tac_plus.cfg and edit" depend: makedepend $(CFLAGS) $(SRCS) diff -Naur tac_plus.F4.0.4.alpha/README.PAM tac_plus.F4.0.4.alpha-PAM-0.4/README.PAM --- tac_plus.F4.0.4.alpha/README.PAM Wed Dec 31 19:00:00 1969 +++ tac_plus.F4.0.4.alpha-PAM-0.4/README.PAM Fri Feb 2 17:19:20 2001 @@ -0,0 +1,46 @@ +Tacacs+ with PAM Authentication support. + +patch version 0.4 (2 February 2001) by Chris Johnson <cjohnson@mint.net> +Now calls pam_acct_mgmt so the 'account' configuration in pam can restrict access +depending on your pam configuration. I added this to make pam_tally work for account +lockout on n authentication failures. But others may wish to apply time-of-day, account +expiration, etc. (Pam is great!) + +Also took default authentication a step further: + If -DUSE_PAM then it must be of the form "default authentication = pam name_of_service" + Else it must be of the form "default authentication = file name_of_passwordfile" +This only affects configuration syntax - requiring the configuration to reflect the +underlying behaviour. + +patch version 0.3 (17 November 1999) +tac_pam_auth is MT-safe now. +Tacacs reports pam error strings. +More examples into the tac_plus.conf. Corrected the version number at start-up. + +patch version 0.2 (31 August 1999) +Pammified default authentication. If -DUSE_PAM used, I hope that PAM is the default +system authentication method. The PAM service used is the name of the passwd_file (???). +Yes, it's terrible, but I have not time to spend for changing +default authentication = file /etc/passwd + in +default authentication = pam name_of_service..........any volunteer ??? +As usual, look at the tac_plus.conf file. + +patch version 0.1 (August 1999) +I introduced an optional new authentication method via PAM. This makes authentication +modular and external to the tacacs+ code. +I have not implemented pam-authorization because the existence of pre and post authorization +calls. +In order to pass tacacs+ attributes to the pam modules, I use the PAM_RUSER item +for storing the rem_addr. Have a look to tac_pam_auth.c for the details. +As you can see, pam-authentication only works for pap and login authentication-types: +I would like to extend it to the default authentication case, but the code seems so +cryptic:-(....... +You can choose the pam service by the configuration file, for a simple example look +into tac_plus.conf. + + + +Max Liccardo <ravel@tiscalinet.it> + + diff -Naur tac_plus.F4.0.4.alpha/config.c tac_plus.F4.0.4.alpha-PAM-0.4/config.c --- tac_plus.F4.0.4.alpha/config.c Sun Jun 18 13:26:53 2000 +++ tac_plus.F4.0.4.alpha-PAM-0.4/config.c Fri Feb 2 18:09:06 2001 @@ -49,8 +49,11 @@ <password_spec> := file <filename> | skey | - cleartext <password> | + cleartext <password> | des <password> | +#ifdef USE_PAM + pam <pam_service> | +#endif nopassword <user_attr> := name = <string> | @@ -64,6 +67,9 @@ #endif pap = cleartext <string> | pap = des <string> | +#ifdef USE_PAM + pap = pam <pam_service> | +#endif opap = cleartext <string> | global = cleartext <string> | msg = <string> @@ -545,9 +551,32 @@ } parse(S_authentication); parse(S_separator); - parse(S_file); - authen_default = tac_strdup(sym_buf); - sym_get(); + switch (sym_code) { + default: + parse_error( +#ifdef USE_PAM + "Expecting default authentication pam on line %d but found %s", + sym_line, sym_buf); +#else + "Expecting default authentication file on line %d but found %s", + sym_line, sym_buf); +#endif + return (1); + +#ifdef USE_PAM + case S_pam: + parse(S_pam); + authen_default = tac_strdup(sym_buf); + sym_get(); + continue; +#else + case S_file: + parse(S_file); + authen_default = tac_strdup(sym_buf); + sym_get(); + continue; +#endif + } continue; case S_authorization: @@ -707,16 +736,25 @@ case S_file: case S_cleartext: case S_des: +#ifdef USE_PAM + case S_pam: +#endif /* USE_PAM */ sprintf(buf, "%s ", sym_buf); sym_get(); strcat(buf, sym_buf); user->login = tac_strdup(buf); break; - + default: +#ifdef USE_PAM + parse_error( + "expecting 'file', 'cleartext', 'pam', 'nopassword', 'skey', or 'des' keyword after 'login =' on line %d", + sym_line); +#else parse_error( "expecting 'file', 'cleartext', 'nopassword', 'skey', or 'des' keyword after 'login =' on line %d", sym_line); +#endif /* USE_PAM */ } sym_get(); continue; @@ -734,16 +772,29 @@ case S_cleartext: case S_des: +#ifdef USE_PAM + case S_pam: +#endif /*USE_PAM */ sprintf(buf, "%s ", sym_buf); sym_get(); strcat(buf, sym_buf); user->pap = tac_strdup(buf); + break; + + sprintf(buf, "%s ", sym_buf); + user->pap = tac_strdup(buf); break; default: +#ifdef USE_PAM + parse_error( + "expecting 'cleartext', 'pam', or 'des' keyword after 'pap =' on line %d", + sym_line); +#else parse_error( "expecting 'cleartext', or 'des' keyword after 'pap =' on line %d", sym_line); +#endif /*USE_PAM */ } sym_get(); continue; diff -Naur tac_plus.F4.0.4.alpha/parse.c tac_plus.F4.0.4.alpha-PAM-0.4/parse.c --- tac_plus.F4.0.4.alpha/parse.c Sun Jun 18 13:26:53 2000 +++ tac_plus.F4.0.4.alpha-PAM-0.4/parse.c Thu Feb 1 14:25:34 2001 @@ -72,6 +72,9 @@ declare("ms-chap", S_mschap); #endif /* MSCHAP */ declare("cleartext", S_cleartext); +#ifdef USE_PAM + declare("pam", S_pam); +#endif /*USE_PAM */ declare("nopassword", S_nopasswd); declare("cmd", S_cmd); declare("default", S_default); @@ -183,6 +186,10 @@ return ("opap"); case S_cleartext: return ("cleartext"); +#ifdef USE_PAM + case S_pam: + return ("pam"); +#endif /*USE_PAM */ case S_nopasswd: return("nopassword"); case S_des: diff -Naur tac_plus.F4.0.4.alpha/parse.h tac_plus.F4.0.4.alpha-PAM-0.4/parse.h --- tac_plus.F4.0.4.alpha/parse.h Sun Jun 18 13:26:54 2000 +++ tac_plus.F4.0.4.alpha-PAM-0.4/parse.h Thu Feb 1 14:25:35 2001 @@ -76,3 +76,6 @@ #ifdef MSCHAP #define S_mschap 42 #endif /* MSCHAP */ +#ifdef USE_PAM +#define S_pam 43 +#endif /*USE_PAM */ diff -Naur tac_plus.F4.0.4.alpha/pwlib.c tac_plus.F4.0.4.alpha-PAM-0.4/pwlib.c --- tac_plus.F4.0.4.alpha/pwlib.c Sun Jun 18 13:26:54 2000 +++ tac_plus.F4.0.4.alpha-PAM-0.4/pwlib.c Thu Feb 1 14:25:35 2001 @@ -25,6 +25,11 @@ #include <shadow.h> #endif +#ifdef USE_PAM +int +tac_pam_auth(char *UserName,char *Password,struct authen_data *data,char *Service); +#endif /* USE_PAM */ + /* Generic password verification routines for des, file and cleartext passwords */ @@ -120,7 +125,27 @@ if (!cfg_passwd) { char *file = cfg_get_authen_default(); if (file) { +#ifdef USE_PAM + if (debug & DEBUG_PASSWD_FLAG) + report(LOG_DEBUG, "verify daemon %s == NAS %s", p, passwd); + if (tac_pam_auth(name, passwd, data,file)) { + if (debug & DEBUG_PASSWD_FLAG) + report(LOG_DEBUG, "Password is incorrect"); + data->status = TAC_PLUS_AUTHEN_STATUS_FAIL; + return(0); + } else { + data->status = TAC_PLUS_AUTHEN_STATUS_PASS; + + if (debug & DEBUG_PASSWD_FLAG) + report(LOG_DEBUG, "Password is correct"); + } + + exp_date = cfg_get_expires(name, recurse); + set_expiration_status(exp_date, data); + return (data->status == TAC_PLUS_AUTHEN_STATUS_PASS); +#else return (passwd_file_verify(name, passwd, data, file)); +#endif /* USE_PAM */ } /* otherwise, we fail */ @@ -131,6 +156,7 @@ /* We have a configured password. Deal with it depending on its type */ + p = tac_find_substring("cleartext ", cfg_passwd); if (p) { if (debug & DEBUG_PASSWD_FLAG) @@ -152,6 +178,31 @@ set_expiration_status(exp_date, data); return (data->status == TAC_PLUS_AUTHEN_STATUS_PASS); } + +#ifdef USE_PAM + p = tac_find_substring("pam ", cfg_passwd); + if (p) { + if (debug & DEBUG_PASSWD_FLAG) + report(LOG_DEBUG, "verify daemon %s == NAS %s", p, passwd); + + if (tac_pam_auth(name, passwd, data,p)) { + if (debug & DEBUG_PASSWD_FLAG) + report(LOG_DEBUG, "Password is incorrect"); + data->status = TAC_PLUS_AUTHEN_STATUS_FAIL; + return(0); + } else { + data->status = TAC_PLUS_AUTHEN_STATUS_PASS; + + if (debug & DEBUG_PASSWD_FLAG) + report(LOG_DEBUG, "Password is correct"); + } + + exp_date = cfg_get_expires(name, recurse); + set_expiration_status(exp_date, data); + return (data->status == TAC_PLUS_AUTHEN_STATUS_PASS); + } + +#endif /* USE_PAM */ p = tac_find_substring("des ", cfg_passwd); if (p) { diff -Naur tac_plus.F4.0.4.alpha/tac_pam_auth.c tac_plus.F4.0.4.alpha-PAM-0.4/tac_pam_auth.c --- tac_plus.F4.0.4.alpha/tac_pam_auth.c Wed Dec 31 19:00:00 1969 +++ tac_plus.F4.0.4.alpha-PAM-0.4/tac_pam_auth.c Fri Feb 2 16:39:32 2001 @@ -0,0 +1,148 @@ +/* tac_pam_auth.c + * A simple pam authentication routine written by Max Liccardo <ravel@tiscalinet.it> + * 2 February 2001 - Add pam_acct_mgmt() so account must also be permitted access to succeed + * - Chris Johnson <cjohnson@mint.net> + * PAM_RUSER=username/rem_addr. + */ + + +/* + This program was contributed by Shane Watts + [modifications by AGM] + [modifications by CKJ] + + The following samples are based on references to 'login pam tacacs-nas' for + some user or group in the tac_plus configuration file. Any pam service that + is referenced in your tacacs configuration must have a definition in your pam + configuration. + + You need to add the following (or equivalent) to the /etc/pam.conf file. + # check authorization + tacacs-nas auth required /usr/lib/security/pam_unix_auth.so + tacacs-nas account required /usr/lib/security/pam_unix_acct.so + + Account restrictions now apply. The following is a more modern sample + /etc/pam.d/tacacs-nas file which forces an account lockout after 3 bad passwords: + #%PAM-1.0 + auth required /lib/security/pam_tally.so no_magic_root + auth required /lib/security/pam_stack.so service=system-auth + account required /lib/security/pam_tally.so no_magic_root deny=3 reset + account required /lib/security/pam_stack.so service=system-auth + + */ + +#ifdef USE_PAM + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <security/pam_appl.h> +#include "tac_plus.h" + +typedef struct +{ + char *UserName; + char *Passwd; +} UserCred; + + +static int fconv(int num_msg, const struct pam_message **msg, + struct pam_response **resp,void *appdata_ptr) +{ + int i; + UserCred *lUserCred; + + + lUserCred = appdata_ptr; + + if(lUserCred == NULL) + { + report(LOG_ERR,"argh....maybe a SunOs 5.6 ???"); + return(PAM_CONV_ERR); + } + + + *resp = (struct pam_response *) calloc(num_msg,sizeof(struct pam_response)); + + for(i=0;i<num_msg;i++) + { + switch(msg[i]->msg_style) + { + case PAM_PROMPT_ECHO_OFF: + resp[i]->resp = strdup(lUserCred->Passwd); + break; + + case PAM_PROMPT_ECHO_ON: + resp[i]->resp = strdup(lUserCred->UserName); + break; + + default: + report(LOG_DEBUG,"conv default"); + break; + } + resp[i]->resp_retcode = 0; + } + + return(PAM_SUCCESS); +} + + + + +int +tac_pam_auth(char *aszUserName,char *aszPassword,struct authen_data *data, + char *aszService) +{ + pam_handle_t *pamh=NULL; + int retval; + char *lpszRemoteUser; /* Username/NAC address */ + struct pam_conv s_conv; + UserCred s_UserCred; + + + s_UserCred.UserName = aszUserName; + s_UserCred.Passwd = aszPassword; + + s_conv.conv = fconv; + s_conv.appdata_ptr = (void *) &s_UserCred; + + + if((lpszRemoteUser = calloc(strlen(aszUserName)+strlen(data->NAS_id->NAC_address)+2,sizeof(char))) == NULL) + { + report(LOG_ERR,"cannot malloc"); + return(1); + } + + retval = pam_start(aszService,aszUserName , &s_conv, &pamh); + + if (retval != PAM_SUCCESS) + { + report(LOG_ERR, "cannot start pam-authentication"); + pamh = NULL; + return(1); + } + + sprintf(lpszRemoteUser,"%s:%s",aszUserName,data->NAS_id->NAC_address); + + pam_set_item(pamh,PAM_RUSER,lpszRemoteUser); + pam_set_item(pamh,PAM_RHOST,data->NAS_id->NAS_name); + pam_set_item(pamh,PAM_TTY,data->NAS_id->NAS_port); + + free(lpszRemoteUser); + + retval = pam_authenticate(pamh,0); /* is user really user? */ + if (retval == PAM_SUCCESS) retval = pam_acct_mgmt(pamh,0); /* permitted access? */ + + if(retval != PAM_SUCCESS) + report(LOG_ERR, "%s",pam_strerror(pamh,retval)); + + if (pam_end(pamh,retval) != PAM_SUCCESS) { /* close Linux-PAM */ + pamh = NULL; + return(1); + } + + return ( retval == PAM_SUCCESS ? 0:1 ); /* indicate success */ +} + + +#endif /* USE_PAM */ diff -Naur tac_plus.F4.0.4.alpha/tac_plus.conf tac_plus.F4.0.4.alpha-PAM-0.4/tac_plus.conf --- tac_plus.F4.0.4.alpha/tac_plus.conf Wed Dec 31 19:00:00 1969 +++ tac_plus.F4.0.4.alpha-PAM-0.4/tac_plus.conf Fri Feb 2 17:33:24 2001 @@ -0,0 +1,25 @@ +#tac_plus.conf - a simple configuration file + +key = "Cisco" + +# in PAM mode, we're using the pam tacacs-login service +default authentication = pam tacacs-login +# otherwise, we're using the mypw password file +#default authentication = file /etc/tacacs/mypw + +accounting file = "/var/log/tactest.acct" + +user=DEFAULT { + default service = permit +} + +# repeat as necessary for each user +user=test { + default service = permit +# in order to work, you need the file /etc/pam.d/tacacs-login or a "tacacs-login" entry into the /etc/pam.conf file + login = pam tacacs-login + +# in order to work, you need the file /etc/pam.d/tacacs-pap or a "tacacs-pap" entry into the /etc/pam.conf file + pap = pam tacacs-pap +} + diff -Naur tac_plus.F4.0.4.alpha/tac_plus.h tac_plus.F4.0.4.alpha-PAM-0.4/tac_plus.h --- tac_plus.F4.0.4.alpha/tac_plus.h Sun Jun 18 13:26:54 2000 +++ tac_plus.F4.0.4.alpha-PAM-0.4/tac_plus.h Thu Feb 1 14:25:35 2001 @@ -69,7 +69,7 @@ */ /* #define REARMSIGNAL */ -#define VERSION "F4.0.4.alpha" +#define VERSION "F4.0.4.alpha-PAM-0.3" /* * System definitions. diff -Naur tac_plus.F4.0.4.alpha/tac_plus.init tac_plus.F4.0.4.alpha-PAM-0.4/tac_plus.init --- tac_plus.F4.0.4.alpha/tac_plus.init Wed Dec 31 19:00:00 1969 +++ tac_plus.F4.0.4.alpha-PAM-0.4/tac_plus.init Fri Feb 2 18:08:42 2001 @@ -0,0 +1,79 @@ +#!/bin/sh +# +# description: Cisco's tacacs+ access, authorization, and accounting server. +# chkconfig: 345 15 85 +# + +# Source function library. +. /etc/rc.d/init.d/functions + +# Source networking configuration. +. /etc/sysconfig/network + +# Check that networking is up. +[ ${NETWORKING} = "no" ] && exit 0 + +[ -f /usr/local/sbin/tac_plus ] || exit 0 + +[ -f /etc/tacacs/tac_plus.cfg ] || exit 0 + +# =========================================================================== +# Normally, only messages at error level or above are written to the log. +# To write TACACS+ info messages to the log, this option takes a parameter +# based on a sum of the following options: +# number information about +# 1 general +# 2 parsing +# 4 forking +# 8 authorization +# 16 authentication +# 32 passwords +# 64 accounting +# 128 configuration +# 256 packet +# 512 hex +# 1024 md5 hash +# 2048 xor +# 4096 clean +# 8192 subst +# +# For more information on the various debug flags, see your Cisco manual. + +DEBUG_LEVEL=255 +#DEBUG_LEVEL=31 +# See how we were called. +case "$1" in + start) + # Start daemons. + echo -n "Starting tacacs+: " + /usr/local/sbin/tac_plus -C /etc/tacacs/tac_plus.cfg \ + -l /var/log/tacacs/tac_plus.log \ + -w /var/log/tacacs/tac_plus.who \ + -d $DEBUG_LEVEL && \ + success || failure + echo + touch /var/lock/subsys/tacacs + ;; + stop) + # Stop daemons. + echo -n "Shutting down tacacs+: " + killproc tac_plus + rm -f /var/lock/subsys/tacacs + echo + ;; + status) + status tac_plus + exit $? + ;; + restart) + $0 stop + $0 start + exit $? + ;; + reload) + kill -USR1 `cat /var/run/tac_plus.pid` + ;; + *) + echo "Usage: tacacs {start|stop|status|restart|reload}" + exit 1 +esac