1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright 1998 Juniper Networks, Inc. 5 * All rights reserved. 6 * Copyright (c) 2001-2003 Networks Associates Technology, Inc. 7 * All rights reserved. 8 * 9 * Portions of this software were developed for the FreeBSD Project by 10 * ThinkSec AS and NAI Labs, the Security Research Division of Network 11 * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 12 * ("CBOSS"), as part of the DARPA CHATS research program. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 3. The name of the author may not be used to endorse or promote 23 * products derived from this software without specific prior written 24 * permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 */ 38 39 #include <sys/cdefs.h> 40 __FBSDID("$FreeBSD$"); 41 42 #include <sys/param.h> 43 44 #include <pwd.h> 45 #include <stdlib.h> 46 #include <string.h> 47 #include <syslog.h> 48 #include <taclib.h> 49 #include <unistd.h> 50 51 #define PAM_SM_AUTH 52 53 #include <security/pam_appl.h> 54 #include <security/pam_modules.h> 55 #include <security/pam_mod_misc.h> 56 57 #define PAM_OPT_CONF "conf" 58 #define PAM_OPT_TEMPLATE_USER "template_user" 59 60 typedef int (*set_func)(struct tac_handle *, const char *); 61 62 static int do_item(pam_handle_t *, struct tac_handle *, int, 63 set_func, const char *); 64 static char *get_msg(struct tac_handle *); 65 static int set_msg(struct tac_handle *, const char *); 66 67 static int 68 do_item(pam_handle_t *pamh, struct tac_handle *tach, int item, 69 set_func func, const char *funcname) 70 { 71 int retval; 72 const void *value; 73 74 retval = pam_get_item(pamh, item, &value); 75 if (retval != PAM_SUCCESS) 76 return retval; 77 if (value != NULL && (*func)(tach, (const char *)value) == -1) { 78 syslog(LOG_CRIT, "%s: %s", funcname, tac_strerror(tach)); 79 tac_close(tach); 80 return PAM_SERVICE_ERR; 81 } 82 return PAM_SUCCESS; 83 } 84 85 static char * 86 get_msg(struct tac_handle *tach) 87 { 88 char *msg; 89 90 msg = tac_get_msg(tach); 91 if (msg == NULL) { 92 syslog(LOG_CRIT, "tac_get_msg: %s", tac_strerror(tach)); 93 tac_close(tach); 94 return NULL; 95 } 96 return msg; 97 } 98 99 static int 100 set_msg(struct tac_handle *tach, const char *msg) 101 { 102 if (tac_set_msg(tach, msg) == -1) { 103 syslog(LOG_CRIT, "tac_set_msg: %s", tac_strerror(tach)); 104 tac_close(tach); 105 return -1; 106 } 107 return 0; 108 } 109 110 PAM_EXTERN int 111 pam_sm_authenticate(pam_handle_t *pamh, int flags __unused, 112 int argc __unused, const char *argv[] __unused) 113 { 114 int retval; 115 struct tac_handle *tach; 116 const char *conf_file, *template_user; 117 118 conf_file = openpam_get_option(pamh, PAM_OPT_CONF); 119 template_user = openpam_get_option(pamh, PAM_OPT_TEMPLATE_USER); 120 121 tach = tac_open(); 122 if (tach == NULL) { 123 syslog(LOG_CRIT, "tac_open failed"); 124 return (PAM_SERVICE_ERR); 125 } 126 if (tac_config(tach, conf_file) == -1) { 127 syslog(LOG_ALERT, "tac_config: %s", tac_strerror(tach)); 128 tac_close(tach); 129 return (PAM_SERVICE_ERR); 130 } 131 if (tac_create_authen(tach, TAC_AUTHEN_LOGIN, TAC_AUTHEN_TYPE_ASCII, 132 TAC_AUTHEN_SVC_LOGIN) == -1) { 133 syslog(LOG_CRIT, "tac_create_authen: %s", tac_strerror(tach)); 134 tac_close(tach); 135 return (PAM_SERVICE_ERR); 136 } 137 138 PAM_LOG("Done tac_open() ... tac_close()"); 139 140 retval = do_item(pamh, tach, PAM_USER, tac_set_user, "tac_set_user"); 141 if (retval != PAM_SUCCESS) 142 return (retval); 143 144 PAM_LOG("Done user"); 145 146 retval = do_item(pamh, tach, PAM_TTY, tac_set_port, "tac_set_port"); 147 if (retval != PAM_SUCCESS) 148 return (retval); 149 150 PAM_LOG("Done tty"); 151 152 retval = do_item(pamh, tach, PAM_RHOST, tac_set_rem_addr, 153 "tac_set_rem_addr"); 154 if (retval != PAM_SUCCESS) 155 return (retval); 156 157 for (;;) { 158 char *srvr_msg; 159 size_t msg_len; 160 const char *user_msg; 161 char *data_msg; 162 int sflags; 163 int status; 164 165 sflags = tac_send_authen(tach); 166 if (sflags == -1) { 167 syslog(LOG_CRIT, "tac_send_authen: %s", 168 tac_strerror(tach)); 169 tac_close(tach); 170 return (PAM_AUTHINFO_UNAVAIL); 171 } 172 status = TAC_AUTHEN_STATUS(sflags); 173 openpam_set_option(pamh, PAM_OPT_ECHO_PASS, 174 TAC_AUTHEN_NOECHO(sflags) ? NULL : ""); 175 switch (status) { 176 177 case TAC_AUTHEN_STATUS_PASS: 178 tac_close(tach); 179 if (template_user != NULL) { 180 const void *item; 181 const char *user; 182 183 PAM_LOG("Trying template user: %s", 184 template_user); 185 186 /* 187 * If the given user name doesn't exist in 188 * the local password database, change it 189 * to the value given in the "template_user" 190 * option. 191 */ 192 retval = pam_get_item(pamh, PAM_USER, &item); 193 if (retval != PAM_SUCCESS) 194 return (retval); 195 user = (const char *)item; 196 if (getpwnam(user) == NULL) { 197 pam_set_item(pamh, PAM_USER, 198 template_user); 199 PAM_LOG("Using template user"); 200 } 201 } 202 return (PAM_SUCCESS); 203 204 case TAC_AUTHEN_STATUS_FAIL: 205 tac_close(tach); 206 PAM_VERBOSE_ERROR("TACACS+ authentication failed"); 207 return (PAM_AUTH_ERR); 208 209 case TAC_AUTHEN_STATUS_GETUSER: 210 case TAC_AUTHEN_STATUS_GETPASS: 211 if ((srvr_msg = get_msg(tach)) == NULL) 212 return (PAM_SERVICE_ERR); 213 if (status == TAC_AUTHEN_STATUS_GETUSER) 214 retval = pam_get_user(pamh, &user_msg, 215 *srvr_msg ? srvr_msg : NULL); 216 else if (status == TAC_AUTHEN_STATUS_GETPASS) 217 retval = pam_get_authtok(pamh, 218 PAM_AUTHTOK, &user_msg, 219 *srvr_msg ? srvr_msg : "Password:"); 220 free(srvr_msg); 221 if (retval != PAM_SUCCESS) { 222 /* XXX - send a TACACS+ abort packet */ 223 tac_close(tach); 224 return (retval); 225 } 226 if (set_msg(tach, user_msg) == -1) 227 return (PAM_SERVICE_ERR); 228 break; 229 230 case TAC_AUTHEN_STATUS_GETDATA: 231 if ((srvr_msg = get_msg(tach)) == NULL) 232 return (PAM_SERVICE_ERR); 233 retval = pam_prompt(pamh, 234 openpam_get_option(pamh, PAM_OPT_ECHO_PASS) ? 235 PAM_PROMPT_ECHO_ON : PAM_PROMPT_ECHO_OFF, 236 &data_msg, "%s", *srvr_msg ? srvr_msg : "Data:"); 237 free(srvr_msg); 238 if (retval != PAM_SUCCESS) { 239 /* XXX - send a TACACS+ abort packet */ 240 tac_close(tach); 241 return (retval); 242 } 243 retval = set_msg(tach, data_msg); 244 memset(data_msg, 0, strlen(data_msg)); 245 free(data_msg); 246 if (retval == -1) 247 return (PAM_SERVICE_ERR); 248 break; 249 250 case TAC_AUTHEN_STATUS_ERROR: 251 srvr_msg = (char *)tac_get_data(tach, &msg_len); 252 if (srvr_msg != NULL && msg_len != 0) { 253 syslog(LOG_CRIT, "tac_send_authen:" 254 " server detected error: %s", srvr_msg); 255 free(srvr_msg); 256 } 257 else 258 syslog(LOG_CRIT, 259 "tac_send_authen: server detected error"); 260 tac_close(tach); 261 return (PAM_AUTHINFO_UNAVAIL); 262 break; 263 264 case TAC_AUTHEN_STATUS_RESTART: 265 case TAC_AUTHEN_STATUS_FOLLOW: 266 default: 267 syslog(LOG_CRIT, 268 "tac_send_authen: unexpected status %#x", status); 269 tac_close(tach); 270 return (PAM_AUTHINFO_UNAVAIL); 271 } 272 } 273 } 274 275 PAM_EXTERN int 276 pam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused, 277 int argc __unused, const char *argv[] __unused) 278 { 279 280 return (PAM_IGNORE); 281 } 282 283 PAM_MODULE_ENTRY("pam_tacplus"); 284