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 /* Option names, including the "=" sign. */ 44 #define OPT_CONF "conf=" 45 #define OPT_TMPL "template_user=" 46 47 typedef int (*set_func)(struct tac_handle *, const char *); 48 49 static int do_item(pam_handle_t *, struct tac_handle *, int, 50 set_func, const char *); 51 static char *get_msg(struct tac_handle *); 52 static int set_msg(struct tac_handle *, const char *); 53 54 static int 55 do_item(pam_handle_t *pamh, struct tac_handle *tach, int item, 56 set_func func, const char *funcname) 57 { 58 int retval; 59 const void *value; 60 61 if ((retval = pam_get_item(pamh, item, &value)) != PAM_SUCCESS) 62 return retval; 63 if (value != NULL && (*func)(tach, (const char *)value) == -1) { 64 syslog(LOG_CRIT, "%s: %s", funcname, tac_strerror(tach)); 65 tac_close(tach); 66 return PAM_SERVICE_ERR; 67 } 68 return PAM_SUCCESS; 69 } 70 71 static char * 72 get_msg(struct tac_handle *tach) 73 { 74 char *msg; 75 76 if ((msg = tac_get_msg(tach)) == NULL) { 77 syslog(LOG_CRIT, "tac_get_msg: %s", tac_strerror(tach)); 78 tac_close(tach); 79 return NULL; 80 } 81 return msg; 82 } 83 84 static int 85 set_msg(struct tac_handle *tach, const char *msg) 86 { 87 if (tac_set_msg(tach, msg) == -1) { 88 syslog(LOG_CRIT, "tac_set_msg: %s", tac_strerror(tach)); 89 tac_close(tach); 90 return -1; 91 } 92 return 0; 93 } 94 95 PAM_EXTERN int 96 pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, 97 const char **argv) 98 { 99 int retval; 100 struct tac_handle *tach; 101 const char *conf_file = NULL; 102 const char *template_user = NULL; 103 int options = 0; 104 int i; 105 106 for (i = 0; i < argc; i++) { 107 size_t len; 108 109 pam_std_option(&options, argv[i]); 110 if (strncmp(argv[i], OPT_CONF, (len = strlen(OPT_CONF))) == 0) 111 conf_file = argv[i] + len; 112 else if (strncmp(argv[i], OPT_TMPL, 113 (len = strlen(OPT_TMPL))) == 0) 114 template_user = argv[i] + len; 115 } 116 117 if ((tach = tac_open()) == NULL) { 118 syslog(LOG_CRIT, "tac_open failed"); 119 return PAM_SERVICE_ERR; 120 } 121 if (tac_config(tach, conf_file) == -1) { 122 syslog(LOG_ALERT, "tac_config: %s", tac_strerror(tach)); 123 tac_close(tach); 124 return PAM_SERVICE_ERR; 125 } 126 if (tac_create_authen(tach, TAC_AUTHEN_LOGIN, TAC_AUTHEN_TYPE_ASCII, 127 TAC_AUTHEN_SVC_LOGIN) == -1) { 128 syslog(LOG_CRIT, "tac_create_authen: %s", tac_strerror(tach)); 129 tac_close(tach); 130 return PAM_SERVICE_ERR; 131 } 132 if ((retval = do_item(pamh, tach, PAM_USER, 133 tac_set_user, "tac_set_user")) != PAM_SUCCESS) 134 return retval; 135 if ((retval = do_item(pamh, tach, PAM_TTY, 136 tac_set_port, "tac_set_port")) != PAM_SUCCESS) 137 return retval; 138 if ((retval = do_item(pamh, tach, PAM_RHOST, 139 tac_set_rem_addr, "tac_set_rem_addr")) != PAM_SUCCESS) 140 return retval; 141 for ( ; ; ) { 142 char *srvr_msg; 143 size_t msg_len; 144 const char *user_msg; 145 char *data_msg; 146 int sflags; 147 int status; 148 int echo; 149 150 if ((sflags = tac_send_authen(tach)) == -1) { 151 syslog(LOG_CRIT, "tac_send_authen: %s", 152 tac_strerror(tach)); 153 tac_close(tach); 154 return PAM_AUTHINFO_UNAVAIL; 155 } 156 status = TAC_AUTHEN_STATUS(sflags); 157 echo = TAC_AUTHEN_NOECHO(sflags) ? 0 : PAM_OPT_ECHO_PASS; 158 switch (status) { 159 160 case TAC_AUTHEN_STATUS_PASS: 161 tac_close(tach); 162 if (template_user != NULL) { 163 const void *item; 164 const char *user; 165 166 /* 167 * If the given user name doesn't exist in 168 * the local password database, change it 169 * to the value given in the "template_user" 170 * option. 171 */ 172 retval = pam_get_item(pamh, PAM_USER, &item); 173 if (retval != PAM_SUCCESS) 174 return retval; 175 user = (const char *)item; 176 if (getpwnam(user) == NULL) 177 pam_set_item(pamh, PAM_USER, 178 template_user); 179 } 180 return PAM_SUCCESS; 181 182 case TAC_AUTHEN_STATUS_FAIL: 183 tac_close(tach); 184 return PAM_AUTH_ERR; 185 186 case TAC_AUTHEN_STATUS_GETUSER: 187 case TAC_AUTHEN_STATUS_GETPASS: 188 if ((srvr_msg = get_msg(tach)) == NULL) 189 return PAM_SERVICE_ERR; 190 if (status == TAC_AUTHEN_STATUS_GETUSER) 191 retval = pam_get_user(pamh, &user_msg, 192 srvr_msg[0] != '\0' ? srvr_msg : NULL); 193 else if (status == TAC_AUTHEN_STATUS_GETPASS) 194 retval = pam_get_pass(pamh, &user_msg, 195 srvr_msg[0] != '\0' ? srvr_msg : 196 "Password:", options | echo); 197 free(srvr_msg); 198 if (retval != PAM_SUCCESS) { 199 /* XXX - send a TACACS+ abort packet */ 200 tac_close(tach); 201 return retval; 202 } 203 if (set_msg(tach, user_msg) == -1) 204 return PAM_SERVICE_ERR; 205 break; 206 207 case TAC_AUTHEN_STATUS_GETDATA: 208 if ((srvr_msg = get_msg(tach)) == NULL) 209 return PAM_SERVICE_ERR; 210 retval = pam_prompt(pamh, 211 (options|echo) & PAM_OPT_ECHO_PASS ? 212 PAM_PROMPT_ECHO_ON : PAM_PROMPT_ECHO_OFF, 213 srvr_msg[0] != '\0' ? srvr_msg : "Data:", 214 &data_msg); 215 free(srvr_msg); 216 if (retval != PAM_SUCCESS) { 217 /* XXX - send a TACACS+ abort packet */ 218 tac_close(tach); 219 return retval; 220 } 221 retval = set_msg(tach, data_msg); 222 memset(data_msg, 0, strlen(data_msg)); 223 free(data_msg); 224 if (retval == -1) 225 return PAM_SERVICE_ERR; 226 break; 227 228 case TAC_AUTHEN_STATUS_ERROR: 229 srvr_msg = (char *)tac_get_data(tach, &msg_len); 230 if (srvr_msg != NULL && msg_len != 0) { 231 syslog(LOG_CRIT, "tac_send_authen:" 232 " server detected error: %s", srvr_msg); 233 free(srvr_msg); 234 } else 235 syslog(LOG_CRIT, 236 "tac_send_authen: server detected error"); 237 tac_close(tach); 238 return PAM_AUTHINFO_UNAVAIL; 239 break; 240 241 case TAC_AUTHEN_STATUS_RESTART: 242 case TAC_AUTHEN_STATUS_FOLLOW: 243 default: 244 syslog(LOG_CRIT, 245 "tac_send_authen: unexpected status %#x", status); 246 tac_close(tach); 247 return PAM_AUTHINFO_UNAVAIL; 248 } 249 } 250 } 251 252 PAM_EXTERN int 253 pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) 254 { 255 return PAM_SUCCESS; 256 } 257 258 PAM_MODULE_ENTRY("pam_tacplus"); 259