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