pam_tacplus.c revision 90229
1169689Skan/*- 2169689Skan * Copyright 1998 Juniper Networks, Inc. 3169689Skan * All rights reserved. 4169689Skan * Copyright (c) 2001 Networks Associates Technologies, Inc. 5169689Skan * All rights reserved. 6169689Skan * 7169689Skan * Portions of this software were developed for the FreeBSD Project by 8169689Skan * ThinkSec AS and NAI Labs, the Security Research Division of Network 9169689Skan * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 10169689Skan * ("CBOSS"), as part of the DARPA CHATS research program. 11169689Skan * 12169689Skan * Redistribution and use in source and binary forms, with or without 13169689Skan * modification, are permitted provided that the following conditions 14169689Skan * are met: 15169689Skan * 1. Redistributions of source code must retain the above copyright 16169689Skan * notice, this list of conditions and the following disclaimer. 17169689Skan * 2. Redistributions in binary form must reproduce the above copyright 18169689Skan * notice, this list of conditions and the following disclaimer in the 19169689Skan * documentation and/or other materials provided with the distribution. 20169689Skan * 3. The name of the author may not be used to endorse or promote 21169689Skan * products derived from this software without specific prior written 22169689Skan * permission. 23169689Skan * 24169689Skan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 25169689Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26169689Skan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27169689Skan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 28169689Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29169689Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30169689Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31169689Skan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32169689Skan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33169689Skan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34169689Skan * SUCH DAMAGE. 35169689Skan */ 36169689Skan 37169689Skan#include <sys/cdefs.h> 38169689Skan__FBSDID("$FreeBSD: head/lib/libpam/modules/pam_tacplus/pam_tacplus.c 90229 2002-02-05 06:08:26Z des $"); 39169689Skan 40169689Skan#include <sys/param.h> 41169689Skan 42169689Skan#include <pwd.h> 43169689Skan#include <stdlib.h> 44169689Skan#include <string.h> 45169689Skan#include <syslog.h> 46169689Skan#include <taclib.h> 47169689Skan#include <unistd.h> 48169689Skan 49169689Skan#define PAM_SM_AUTH 50169689Skan#define PAM_SM_ACCOUNT 51169689Skan#define PAM_SM_SESSION 52169689Skan#define PAM_SM_PASSWORD 53169689Skan 54169689Skan#include <security/pam_appl.h> 55169689Skan#include <security/pam_modules.h> 56169689Skan#include <security/pam_mod_misc.h> 57169689Skan 58169689Skanenum { PAM_OPT_CONF=PAM_OPT_STD_MAX, PAM_OPT_TEMPLATE_USER }; 59169689Skan 60169689Skanstatic struct opttab other_options[] = { 61169689Skan { "conf", PAM_OPT_CONF }, 62169689Skan { "template_user", PAM_OPT_TEMPLATE_USER }, 63169689Skan { NULL, 0 } 64169689Skan}; 65169689Skan 66169689Skantypedef int (*set_func)(struct tac_handle *, const char *); 67169689Skan 68169689Skanstatic int do_item(pam_handle_t *, struct tac_handle *, int, 69169689Skan set_func, const char *); 70169689Skanstatic char *get_msg(struct tac_handle *); 71169689Skanstatic int set_msg(struct tac_handle *, const char *); 72169689Skan 73169689Skanstatic int 74169689Skando_item(pam_handle_t *pamh, struct tac_handle *tach, int item, 75169689Skan set_func func, const char *funcname) 76169689Skan{ 77169689Skan int retval; 78169689Skan const void *value; 79169689Skan 80169689Skan retval = pam_get_item(pamh, item, &value); 81169689Skan if (retval != PAM_SUCCESS) 82169689Skan return retval; 83169689Skan if (value != NULL && (*func)(tach, (const char *)value) == -1) { 84169689Skan syslog(LOG_CRIT, "%s: %s", funcname, tac_strerror(tach)); 85169689Skan tac_close(tach); 86169689Skan return PAM_SERVICE_ERR; 87169689Skan } 88169689Skan return PAM_SUCCESS; 89169689Skan} 90169689Skan 91169689Skanstatic char * 92169689Skanget_msg(struct tac_handle *tach) 93169689Skan{ 94169689Skan char *msg; 95169689Skan 96169689Skan msg = tac_get_msg(tach); 97169689Skan if (msg == NULL) { 98169689Skan syslog(LOG_CRIT, "tac_get_msg: %s", tac_strerror(tach)); 99169689Skan tac_close(tach); 100169689Skan return NULL; 101169689Skan } 102169689Skan return msg; 103169689Skan} 104169689Skan 105169689Skanstatic int 106169689Skanset_msg(struct tac_handle *tach, const char *msg) 107169689Skan{ 108169689Skan if (tac_set_msg(tach, msg) == -1) { 109169689Skan syslog(LOG_CRIT, "tac_set_msg: %s", tac_strerror(tach)); 110169689Skan tac_close(tach); 111169689Skan return -1; 112169689Skan } 113169689Skan return 0; 114169689Skan} 115169689Skan 116169689SkanPAM_EXTERN int 117169689Skanpam_sm_authenticate(pam_handle_t *pamh, int flags __unused, int argc, 118169689Skan const char **argv) 119169689Skan{ 120169689Skan struct options options; 121169689Skan int retval; 122169689Skan struct tac_handle *tach; 123169689Skan char *conf_file; 124169689Skan char *template_user; 125169689Skan 126169689Skan pam_std_option(&options, other_options, argc, argv); 127169689Skan 128169689Skan PAM_LOG("Options processed"); 129169689Skan 130169689Skan conf_file = NULL; 131169689Skan pam_test_option(&options, PAM_OPT_CONF, &conf_file); 132169689Skan template_user = NULL; 133169689Skan pam_test_option(&options, PAM_OPT_TEMPLATE_USER, &template_user); 134169689Skan 135169689Skan tach = tac_open(); 136169689Skan if (tach == NULL) { 137169689Skan syslog(LOG_CRIT, "tac_open failed"); 138169689Skan PAM_RETURN(PAM_SERVICE_ERR); 139169689Skan } 140169689Skan if (tac_config(tach, conf_file) == -1) { 141169689Skan syslog(LOG_ALERT, "tac_config: %s", tac_strerror(tach)); 142169689Skan tac_close(tach); 143169689Skan PAM_RETURN(PAM_SERVICE_ERR); 144169689Skan } 145169689Skan if (tac_create_authen(tach, TAC_AUTHEN_LOGIN, TAC_AUTHEN_TYPE_ASCII, 146169689Skan TAC_AUTHEN_SVC_LOGIN) == -1) { 147169689Skan syslog(LOG_CRIT, "tac_create_authen: %s", tac_strerror(tach)); 148169689Skan tac_close(tach); 149169689Skan PAM_RETURN(PAM_SERVICE_ERR); 150169689Skan } 151169689Skan 152169689Skan PAM_LOG("Done tac_open() ... tac_close()"); 153169689Skan 154169689Skan retval = do_item(pamh, tach, PAM_USER, tac_set_user, "tac_set_user"); 155169689Skan if (retval != PAM_SUCCESS) 156169689Skan PAM_RETURN(retval); 157169689Skan 158169689Skan PAM_LOG("Done user"); 159169689Skan 160169689Skan retval = do_item(pamh, tach, PAM_TTY, tac_set_port, "tac_set_port"); 161169689Skan if (retval != PAM_SUCCESS) 162169689Skan PAM_RETURN(retval); 163169689Skan 164169689Skan PAM_LOG("Done tty"); 165169689Skan 166169689Skan retval = do_item(pamh, tach, PAM_RHOST, tac_set_rem_addr, 167169689Skan "tac_set_rem_addr"); 168169689Skan if (retval != PAM_SUCCESS) 169169689Skan PAM_RETURN(retval); 170169689Skan 171169689Skan for ( ; ; ) { 172169689Skan char *srvr_msg; 173169689Skan size_t msg_len; 174169689Skan const char *user_msg; 175169689Skan char *data_msg; 176169689Skan int sflags; 177169689Skan int status; 178169689Skan 179169689Skan sflags = tac_send_authen(tach); 180169689Skan if (sflags == -1) { 181169689Skan syslog(LOG_CRIT, "tac_send_authen: %s", 182169689Skan tac_strerror(tach)); 183169689Skan tac_close(tach); 184169689Skan PAM_RETURN(PAM_AUTHINFO_UNAVAIL); 185169689Skan } 186169689Skan status = TAC_AUTHEN_STATUS(sflags); 187169689Skan if (!TAC_AUTHEN_NOECHO(sflags)) 188169689Skan pam_set_option(&options, PAM_OPT_ECHO_PASS); 189169689Skan switch (status) { 190169689Skan 191169689Skan case TAC_AUTHEN_STATUS_PASS: 192169689Skan tac_close(tach); 193169689Skan if (template_user != NULL) { 194169689Skan const void *item; 195169689Skan const char *user; 196169689Skan 197169689Skan PAM_LOG("Trying template user: %s", 198169689Skan template_user); 199169689Skan 200169689Skan /* 201169689Skan * If the given user name doesn't exist in 202169689Skan * the local password database, change it 203169689Skan * to the value given in the "template_user" 204169689Skan * option. 205169689Skan */ 206169689Skan retval = pam_get_item(pamh, PAM_USER, &item); 207169689Skan if (retval != PAM_SUCCESS) 208169689Skan PAM_RETURN(retval); 209169689Skan user = (const char *)item; 210169689Skan if (getpwnam(user) == NULL) { 211169689Skan pam_set_item(pamh, PAM_USER, 212169689Skan template_user); 213169689Skan PAM_LOG("Using template user"); 214169689Skan } 215169689Skan } 216169689Skan PAM_RETURN(PAM_SUCCESS); 217169689Skan 218169689Skan case TAC_AUTHEN_STATUS_FAIL: 219169689Skan tac_close(tach); 220169689Skan PAM_VERBOSE_ERROR("TACACS+ authentication failed"); 221169689Skan PAM_RETURN(PAM_AUTH_ERR); 222169689Skan 223169689Skan case TAC_AUTHEN_STATUS_GETUSER: 224169689Skan case TAC_AUTHEN_STATUS_GETPASS: 225169689Skan if ((srvr_msg = get_msg(tach)) == NULL) 226169689Skan PAM_RETURN(PAM_SERVICE_ERR); 227169689Skan if (status == TAC_AUTHEN_STATUS_GETUSER) 228169689Skan retval = pam_get_user(pamh, &user_msg, 229169689Skan srvr_msg[0] != '\0' ? srvr_msg : NULL); 230169689Skan else if (status == TAC_AUTHEN_STATUS_GETPASS) 231169689Skan retval = pam_get_pass(pamh, &user_msg, 232169689Skan srvr_msg[0] != '\0' ? srvr_msg : 233169689Skan "Password:", &options); 234169689Skan free(srvr_msg); 235169689Skan if (retval != PAM_SUCCESS) { 236169689Skan /* XXX - send a TACACS+ abort packet */ 237169689Skan tac_close(tach); 238169689Skan PAM_RETURN(retval); 239169689Skan } 240169689Skan if (set_msg(tach, user_msg) == -1) 241169689Skan PAM_RETURN(PAM_SERVICE_ERR); 242169689Skan break; 243169689Skan 244169689Skan case TAC_AUTHEN_STATUS_GETDATA: 245169689Skan if ((srvr_msg = get_msg(tach)) == NULL) 246169689Skan PAM_RETURN(PAM_SERVICE_ERR); 247169689Skan retval = pam_prompt(pamh, 248169689Skan pam_test_option(&options, PAM_OPT_ECHO_PASS, NULL) 249169689Skan ? PAM_PROMPT_ECHO_ON : PAM_PROMPT_ECHO_OFF, 250169689Skan srvr_msg[0] != '\0' ? srvr_msg : "Data:", 251169689Skan &data_msg); 252169689Skan free(srvr_msg); 253169689Skan if (retval != PAM_SUCCESS) { 254169689Skan /* XXX - send a TACACS+ abort packet */ 255169689Skan tac_close(tach); 256169689Skan PAM_RETURN(retval); 257169689Skan } 258169689Skan retval = set_msg(tach, data_msg); 259169689Skan memset(data_msg, 0, strlen(data_msg)); 260169689Skan free(data_msg); 261169689Skan if (retval == -1) 262169689Skan PAM_RETURN(PAM_SERVICE_ERR); 263169689Skan break; 264169689Skan 265169689Skan case TAC_AUTHEN_STATUS_ERROR: 266169689Skan srvr_msg = (char *)tac_get_data(tach, &msg_len); 267169689Skan if (srvr_msg != NULL && msg_len != 0) { 268169689Skan syslog(LOG_CRIT, "tac_send_authen:" 269169689Skan " server detected error: %s", srvr_msg); 270169689Skan free(srvr_msg); 271169689Skan } 272169689Skan else 273169689Skan syslog(LOG_CRIT, 274169689Skan "tac_send_authen: server detected error"); 275169689Skan tac_close(tach); 276169689Skan PAM_RETURN(PAM_AUTHINFO_UNAVAIL); 277169689Skan break; 278169689Skan 279169689Skan case TAC_AUTHEN_STATUS_RESTART: 280169689Skan case TAC_AUTHEN_STATUS_FOLLOW: 281169689Skan default: 282169689Skan syslog(LOG_CRIT, 283169689Skan "tac_send_authen: unexpected status %#x", status); 284169689Skan tac_close(tach); 285169689Skan PAM_RETURN(PAM_AUTHINFO_UNAVAIL); 286169689Skan } 287169689Skan } 288169689Skan} 289169689Skan 290169689SkanPAM_EXTERN int 291169689Skanpam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused, int argc, const char **argv) 292169689Skan{ 293169689Skan struct options options; 294169689Skan 295169689Skan pam_std_option(&options, NULL, argc, argv); 296169689Skan 297169689Skan PAM_LOG("Options processed"); 298169689Skan 299169689Skan PAM_RETURN(PAM_IGNORE); 300169689Skan} 301169689Skan 302169689SkanPAM_EXTERN int 303169689Skanpam_sm_acct_mgmt(pam_handle_t *pamh __unused, int flags __unused, int argc ,const char **argv) 304169689Skan{ 305169689Skan struct options options; 306169689Skan 307169689Skan pam_std_option(&options, NULL, argc, argv); 308169689Skan 309169689Skan PAM_LOG("Options processed"); 310169689Skan 311169689Skan PAM_RETURN(PAM_IGNORE); 312169689Skan} 313169689Skan 314169689SkanPAM_EXTERN int 315169689Skanpam_sm_chauthtok(pam_handle_t *pamh __unused, int flags __unused, int argc, const char **argv) 316169689Skan{ 317169689Skan struct options options; 318169689Skan 319169689Skan pam_std_option(&options, NULL, argc, argv); 320169689Skan 321169689Skan PAM_LOG("Options processed"); 322169689Skan 323169689Skan PAM_RETURN(PAM_IGNORE); 324169689Skan} 325169689Skan 326169689SkanPAM_EXTERN int 327169689Skanpam_sm_open_session(pam_handle_t *pamh __unused, int flags __unused, int argc, const char **argv) 328169689Skan{ 329169689Skan struct options options; 330169689Skan 331169689Skan pam_std_option(&options, NULL, argc, argv); 332169689Skan 333169689Skan PAM_LOG("Options processed"); 334169689Skan 335169689Skan PAM_RETURN(PAM_IGNORE); 336169689Skan} 337169689Skan 338169689SkanPAM_EXTERN int 339169689Skanpam_sm_close_session(pam_handle_t *pamh __unused, int flags __unused, int argc, const char **argv) 340169689Skan{ 341169689Skan struct options options; 342169689Skan 343169689Skan pam_std_option(&options, NULL, argc, argv); 344169689Skan 345169689Skan PAM_LOG("Options processed"); 346169689Skan 347169689Skan PAM_RETURN(PAM_IGNORE); 348169689Skan} 349169689Skan 350169689SkanPAM_MODULE_ENTRY("pam_tacplus"); 351169689Skan