pam_tacplus.c revision 93984
141227Sjdp/*- 241227Sjdp * Copyright 1998 Juniper Networks, Inc. 341227Sjdp * All rights reserved. 493984Sdes * Copyright (c) 2001,2002 Networks Associates Technology, Inc. 587398Sdes * All rights reserved. 641227Sjdp * 787398Sdes * Portions of this software were developed for the FreeBSD Project by 887398Sdes * ThinkSec AS and NAI Labs, the Security Research Division of Network 987398Sdes * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 1087398Sdes * ("CBOSS"), as part of the DARPA CHATS research program. 1187398Sdes * 1241227Sjdp * Redistribution and use in source and binary forms, with or without 1341227Sjdp * modification, are permitted provided that the following conditions 1441227Sjdp * are met: 1541227Sjdp * 1. Redistributions of source code must retain the above copyright 1641227Sjdp * notice, this list of conditions and the following disclaimer. 1741227Sjdp * 2. Redistributions in binary form must reproduce the above copyright 1841227Sjdp * notice, this list of conditions and the following disclaimer in the 1941227Sjdp * documentation and/or other materials provided with the distribution. 2087398Sdes * 3. The name of the author may not be used to endorse or promote 2187398Sdes * products derived from this software without specific prior written 2287398Sdes * permission. 2341227Sjdp * 2441227Sjdp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2541227Sjdp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2641227Sjdp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2741227Sjdp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2841227Sjdp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2941227Sjdp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3041227Sjdp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3141227Sjdp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3241227Sjdp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3341227Sjdp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3441227Sjdp * SUCH DAMAGE. 3541227Sjdp */ 3641227Sjdp 3784218Sdillon#include <sys/cdefs.h> 3884218Sdillon__FBSDID("$FreeBSD: head/lib/libpam/modules/pam_tacplus/pam_tacplus.c 93984 2002-04-06 19:30:04Z des $"); 3984218Sdillon 4041227Sjdp#include <sys/param.h> 4141227Sjdp 4241227Sjdp#include <pwd.h> 4341227Sjdp#include <stdlib.h> 4441227Sjdp#include <string.h> 4541227Sjdp#include <syslog.h> 4641227Sjdp#include <taclib.h> 4741227Sjdp#include <unistd.h> 4841227Sjdp 4941227Sjdp#define PAM_SM_AUTH 5087398Sdes#define PAM_SM_ACCOUNT 5187398Sdes#define PAM_SM_SESSION 5287398Sdes#define PAM_SM_PASSWORD 5387398Sdes 5490229Sdes#include <security/pam_appl.h> 5541227Sjdp#include <security/pam_modules.h> 5690229Sdes#include <security/pam_mod_misc.h> 5741227Sjdp 5879476Smarkmenum { PAM_OPT_CONF=PAM_OPT_STD_MAX, PAM_OPT_TEMPLATE_USER }; 5941227Sjdp 6079476Smarkmstatic struct opttab other_options[] = { 6179476Smarkm { "conf", PAM_OPT_CONF }, 6279476Smarkm { "template_user", PAM_OPT_TEMPLATE_USER }, 6379476Smarkm { NULL, 0 } 6479476Smarkm}; 6579476Smarkm 6641227Sjdptypedef int (*set_func)(struct tac_handle *, const char *); 6741227Sjdp 6841227Sjdpstatic int do_item(pam_handle_t *, struct tac_handle *, int, 6941227Sjdp set_func, const char *); 7041227Sjdpstatic char *get_msg(struct tac_handle *); 7141227Sjdpstatic int set_msg(struct tac_handle *, const char *); 7241227Sjdp 7341227Sjdpstatic int 7441227Sjdpdo_item(pam_handle_t *pamh, struct tac_handle *tach, int item, 7541227Sjdp set_func func, const char *funcname) 7641227Sjdp{ 7741227Sjdp int retval; 7841227Sjdp const void *value; 7941227Sjdp 8079476Smarkm retval = pam_get_item(pamh, item, &value); 8179476Smarkm if (retval != PAM_SUCCESS) 8241227Sjdp return retval; 8341227Sjdp if (value != NULL && (*func)(tach, (const char *)value) == -1) { 8441227Sjdp syslog(LOG_CRIT, "%s: %s", funcname, tac_strerror(tach)); 8541227Sjdp tac_close(tach); 8641227Sjdp return PAM_SERVICE_ERR; 8741227Sjdp } 8841227Sjdp return PAM_SUCCESS; 8941227Sjdp} 9041227Sjdp 9141227Sjdpstatic char * 9241227Sjdpget_msg(struct tac_handle *tach) 9341227Sjdp{ 9441227Sjdp char *msg; 9541227Sjdp 9679476Smarkm msg = tac_get_msg(tach); 9779476Smarkm if (msg == NULL) { 9841227Sjdp syslog(LOG_CRIT, "tac_get_msg: %s", tac_strerror(tach)); 9941227Sjdp tac_close(tach); 10041227Sjdp return NULL; 10141227Sjdp } 10241227Sjdp return msg; 10341227Sjdp} 10441227Sjdp 10541227Sjdpstatic int 10641227Sjdpset_msg(struct tac_handle *tach, const char *msg) 10741227Sjdp{ 10841227Sjdp if (tac_set_msg(tach, msg) == -1) { 10941227Sjdp syslog(LOG_CRIT, "tac_set_msg: %s", tac_strerror(tach)); 11041227Sjdp tac_close(tach); 11141227Sjdp return -1; 11241227Sjdp } 11341227Sjdp return 0; 11441227Sjdp} 11541227Sjdp 11641227SjdpPAM_EXTERN int 11789760Smarkmpam_sm_authenticate(pam_handle_t *pamh, int flags __unused, int argc, 11841227Sjdp const char **argv) 11941227Sjdp{ 12079476Smarkm struct options options; 12141227Sjdp int retval; 12241227Sjdp struct tac_handle *tach; 12379476Smarkm char *conf_file; 12479476Smarkm char *template_user; 12541227Sjdp 12679476Smarkm pam_std_option(&options, other_options, argc, argv); 12741227Sjdp 12879476Smarkm PAM_LOG("Options processed"); 12941227Sjdp 13079476Smarkm conf_file = NULL; 13179476Smarkm pam_test_option(&options, PAM_OPT_CONF, &conf_file); 13279476Smarkm template_user = NULL; 13379476Smarkm pam_test_option(&options, PAM_OPT_TEMPLATE_USER, &template_user); 13479476Smarkm 13579476Smarkm tach = tac_open(); 13679476Smarkm if (tach == NULL) { 13741227Sjdp syslog(LOG_CRIT, "tac_open failed"); 13879476Smarkm PAM_RETURN(PAM_SERVICE_ERR); 13941227Sjdp } 14041227Sjdp if (tac_config(tach, conf_file) == -1) { 14141227Sjdp syslog(LOG_ALERT, "tac_config: %s", tac_strerror(tach)); 14241227Sjdp tac_close(tach); 14379476Smarkm PAM_RETURN(PAM_SERVICE_ERR); 14441227Sjdp } 14541227Sjdp if (tac_create_authen(tach, TAC_AUTHEN_LOGIN, TAC_AUTHEN_TYPE_ASCII, 14641227Sjdp TAC_AUTHEN_SVC_LOGIN) == -1) { 14741227Sjdp syslog(LOG_CRIT, "tac_create_authen: %s", tac_strerror(tach)); 14841227Sjdp tac_close(tach); 14979476Smarkm PAM_RETURN(PAM_SERVICE_ERR); 15041227Sjdp } 15179476Smarkm 15279476Smarkm PAM_LOG("Done tac_open() ... tac_close()"); 15379476Smarkm 15479476Smarkm retval = do_item(pamh, tach, PAM_USER, tac_set_user, "tac_set_user"); 15579476Smarkm if (retval != PAM_SUCCESS) 15679476Smarkm PAM_RETURN(retval); 15779476Smarkm 15879476Smarkm PAM_LOG("Done user"); 15979476Smarkm 16079476Smarkm retval = do_item(pamh, tach, PAM_TTY, tac_set_port, "tac_set_port"); 16179476Smarkm if (retval != PAM_SUCCESS) 16279476Smarkm PAM_RETURN(retval); 16379476Smarkm 16479476Smarkm PAM_LOG("Done tty"); 16579476Smarkm 16679476Smarkm retval = do_item(pamh, tach, PAM_RHOST, tac_set_rem_addr, 16779476Smarkm "tac_set_rem_addr"); 16879476Smarkm if (retval != PAM_SUCCESS) 16979476Smarkm PAM_RETURN(retval); 17079476Smarkm 17141227Sjdp for ( ; ; ) { 17241227Sjdp char *srvr_msg; 17341227Sjdp size_t msg_len; 17441227Sjdp const char *user_msg; 17541227Sjdp char *data_msg; 17641227Sjdp int sflags; 17741227Sjdp int status; 17841227Sjdp 17979476Smarkm sflags = tac_send_authen(tach); 18079476Smarkm if (sflags == -1) { 18141227Sjdp syslog(LOG_CRIT, "tac_send_authen: %s", 18241227Sjdp tac_strerror(tach)); 18341227Sjdp tac_close(tach); 18479476Smarkm PAM_RETURN(PAM_AUTHINFO_UNAVAIL); 18541227Sjdp } 18641227Sjdp status = TAC_AUTHEN_STATUS(sflags); 18779476Smarkm if (!TAC_AUTHEN_NOECHO(sflags)) 18879476Smarkm pam_set_option(&options, PAM_OPT_ECHO_PASS); 18941227Sjdp switch (status) { 19041227Sjdp 19141227Sjdp case TAC_AUTHEN_STATUS_PASS: 19241227Sjdp tac_close(tach); 19341227Sjdp if (template_user != NULL) { 19441227Sjdp const void *item; 19541227Sjdp const char *user; 19641227Sjdp 19779476Smarkm PAM_LOG("Trying template user: %s", 19879476Smarkm template_user); 19979476Smarkm 20041227Sjdp /* 20141227Sjdp * If the given user name doesn't exist in 20241227Sjdp * the local password database, change it 20341227Sjdp * to the value given in the "template_user" 20441227Sjdp * option. 20541227Sjdp */ 20641227Sjdp retval = pam_get_item(pamh, PAM_USER, &item); 20741227Sjdp if (retval != PAM_SUCCESS) 20879476Smarkm PAM_RETURN(retval); 20941227Sjdp user = (const char *)item; 21079476Smarkm if (getpwnam(user) == NULL) { 21141227Sjdp pam_set_item(pamh, PAM_USER, 21241227Sjdp template_user); 21379476Smarkm PAM_LOG("Using template user"); 21479476Smarkm } 21541227Sjdp } 21679476Smarkm PAM_RETURN(PAM_SUCCESS); 21741227Sjdp 21841227Sjdp case TAC_AUTHEN_STATUS_FAIL: 21941227Sjdp tac_close(tach); 22081473Smarkm PAM_VERBOSE_ERROR("TACACS+ authentication failed"); 22179476Smarkm PAM_RETURN(PAM_AUTH_ERR); 22241227Sjdp 22341227Sjdp case TAC_AUTHEN_STATUS_GETUSER: 22441227Sjdp case TAC_AUTHEN_STATUS_GETPASS: 22541227Sjdp if ((srvr_msg = get_msg(tach)) == NULL) 22679476Smarkm PAM_RETURN(PAM_SERVICE_ERR); 22741227Sjdp if (status == TAC_AUTHEN_STATUS_GETUSER) 22841227Sjdp retval = pam_get_user(pamh, &user_msg, 22993984Sdes *srvr_msg ? srvr_msg : NULL); 23041227Sjdp else if (status == TAC_AUTHEN_STATUS_GETPASS) 23193984Sdes retval = pam_get_authtok(pamh, 23293984Sdes PAM_AUTHTOK, &user_msg, 23393984Sdes *srvr_msg ? srvr_msg : "Password:"); 23441227Sjdp free(srvr_msg); 23541227Sjdp if (retval != PAM_SUCCESS) { 23641227Sjdp /* XXX - send a TACACS+ abort packet */ 23741227Sjdp tac_close(tach); 23879476Smarkm PAM_RETURN(retval); 23941227Sjdp } 24041227Sjdp if (set_msg(tach, user_msg) == -1) 24179476Smarkm PAM_RETURN(PAM_SERVICE_ERR); 24241227Sjdp break; 24341227Sjdp 24441227Sjdp case TAC_AUTHEN_STATUS_GETDATA: 24541227Sjdp if ((srvr_msg = get_msg(tach)) == NULL) 24679476Smarkm PAM_RETURN(PAM_SERVICE_ERR); 24741227Sjdp retval = pam_prompt(pamh, 24879476Smarkm pam_test_option(&options, PAM_OPT_ECHO_PASS, NULL) 24991714Sdes ? PAM_PROMPT_ECHO_ON : PAM_PROMPT_ECHO_OFF, 25093984Sdes &data_msg, "%s", *srvr_msg ? srvr_msg : "Data:"); 25141227Sjdp free(srvr_msg); 25241227Sjdp if (retval != PAM_SUCCESS) { 25341227Sjdp /* XXX - send a TACACS+ abort packet */ 25441227Sjdp tac_close(tach); 25579476Smarkm PAM_RETURN(retval); 25641227Sjdp } 25741227Sjdp retval = set_msg(tach, data_msg); 25841227Sjdp memset(data_msg, 0, strlen(data_msg)); 25941227Sjdp free(data_msg); 26041227Sjdp if (retval == -1) 26179476Smarkm PAM_RETURN(PAM_SERVICE_ERR); 26241227Sjdp break; 26341227Sjdp 26441227Sjdp case TAC_AUTHEN_STATUS_ERROR: 26541227Sjdp srvr_msg = (char *)tac_get_data(tach, &msg_len); 26641227Sjdp if (srvr_msg != NULL && msg_len != 0) { 26741227Sjdp syslog(LOG_CRIT, "tac_send_authen:" 26841227Sjdp " server detected error: %s", srvr_msg); 26941227Sjdp free(srvr_msg); 27079476Smarkm } 27179476Smarkm else 27241227Sjdp syslog(LOG_CRIT, 27341227Sjdp "tac_send_authen: server detected error"); 27441227Sjdp tac_close(tach); 27579476Smarkm PAM_RETURN(PAM_AUTHINFO_UNAVAIL); 27641227Sjdp break; 27741227Sjdp 27841227Sjdp case TAC_AUTHEN_STATUS_RESTART: 27941227Sjdp case TAC_AUTHEN_STATUS_FOLLOW: 28041227Sjdp default: 28141227Sjdp syslog(LOG_CRIT, 28241227Sjdp "tac_send_authen: unexpected status %#x", status); 28341227Sjdp tac_close(tach); 28479476Smarkm PAM_RETURN(PAM_AUTHINFO_UNAVAIL); 28541227Sjdp } 28641227Sjdp } 28741227Sjdp} 28841227Sjdp 28941227SjdpPAM_EXTERN int 29089760Smarkmpam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused, int argc, const char **argv) 29141227Sjdp{ 29287398Sdes struct options options; 29387398Sdes 29487398Sdes pam_std_option(&options, NULL, argc, argv); 29587398Sdes 29687398Sdes PAM_LOG("Options processed"); 29787398Sdes 29887398Sdes PAM_RETURN(PAM_IGNORE); 29941227Sjdp} 30042917Sjdp 30187398SdesPAM_EXTERN int 30289760Smarkmpam_sm_acct_mgmt(pam_handle_t *pamh __unused, int flags __unused, int argc ,const char **argv) 30387398Sdes{ 30487398Sdes struct options options; 30587398Sdes 30687398Sdes pam_std_option(&options, NULL, argc, argv); 30787398Sdes 30887398Sdes PAM_LOG("Options processed"); 30987398Sdes 31087398Sdes PAM_RETURN(PAM_IGNORE); 31187398Sdes} 31287398Sdes 31387398SdesPAM_EXTERN int 31489760Smarkmpam_sm_chauthtok(pam_handle_t *pamh __unused, int flags __unused, int argc, const char **argv) 31587398Sdes{ 31687398Sdes struct options options; 31787398Sdes 31887398Sdes pam_std_option(&options, NULL, argc, argv); 31987398Sdes 32087398Sdes PAM_LOG("Options processed"); 32187398Sdes 32287398Sdes PAM_RETURN(PAM_IGNORE); 32387398Sdes} 32487398Sdes 32587398SdesPAM_EXTERN int 32689760Smarkmpam_sm_open_session(pam_handle_t *pamh __unused, int flags __unused, int argc, const char **argv) 32787398Sdes{ 32887398Sdes struct options options; 32987398Sdes 33087398Sdes pam_std_option(&options, NULL, argc, argv); 33187398Sdes 33287398Sdes PAM_LOG("Options processed"); 33387398Sdes 33487398Sdes PAM_RETURN(PAM_IGNORE); 33587398Sdes} 33687398Sdes 33787398SdesPAM_EXTERN int 33889760Smarkmpam_sm_close_session(pam_handle_t *pamh __unused, int flags __unused, int argc, const char **argv) 33987398Sdes{ 34087398Sdes struct options options; 34187398Sdes 34287398Sdes pam_std_option(&options, NULL, argc, argv); 34387398Sdes 34487398Sdes PAM_LOG("Options processed"); 34587398Sdes 34687398Sdes PAM_RETURN(PAM_IGNORE); 34787398Sdes} 34887398Sdes 34942917SjdpPAM_MODULE_ENTRY("pam_tacplus"); 350