1/* 2 * Copyright (c) 2000-2005, 2007-2008, 2010 3 * Todd C. Miller <Todd.Miller@courtesan.com> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 * 17 * Sponsored in part by the Defense Advanced Research Projects 18 * Agency (DARPA) and Air Force Research Laboratory, Air Force 19 * Materiel Command, USAF, under agreement number F39502-99-1-0512. 20 */ 21 22#include <config.h> 23 24#include <sys/types.h> 25#include <sys/param.h> 26#include <stdio.h> 27#ifdef STDC_HEADERS 28# include <stdlib.h> 29# include <stddef.h> 30#else 31# ifdef HAVE_STDLIB_H 32# include <stdlib.h> 33# endif 34#endif /* STDC_HEADERS */ 35#ifdef HAVE_STRING_H 36# include <string.h> 37#endif /* HAVE_STRING_H */ 38#ifdef HAVE_STRINGS_H 39# include <strings.h> 40#endif /* HAVE_STRING_H */ 41#ifdef HAVE_UNISTD_H 42# include <unistd.h> 43#endif /* HAVE_UNISTD_H */ 44#include <ctype.h> 45#include <pwd.h> 46#include <signal.h> 47 48#include <login_cap.h> 49#include <bsd_auth.h> 50 51#include "sudo.h" 52#include "sudo_auth.h" 53 54#ifndef LOGIN_DEFROOTCLASS 55# define LOGIN_DEFROOTCLASS "daemon" 56#endif 57 58extern char *login_style; /* from sudo.c */ 59 60struct bsdauth_state { 61 auth_session_t *as; 62 login_cap_t *lc; 63}; 64 65int 66bsdauth_init(pw, auth) 67 struct passwd *pw; 68 sudo_auth *auth; 69{ 70 static struct bsdauth_state state; 71 72 /* Get login class based on auth user, which may not be invoking user. */ 73 if (pw->pw_class && *pw->pw_class) 74 state.lc = login_getclass(pw->pw_class); 75 else 76 state.lc = login_getclass(pw->pw_uid ? LOGIN_DEFCLASS : LOGIN_DEFROOTCLASS); 77 if (state.lc == NULL) { 78 log_error(USE_ERRNO|NO_MAIL, 79 "unable to get login class for user %s", pw->pw_name); 80 return AUTH_FATAL; 81 } 82 83 if ((state.as = auth_open()) == NULL) { 84 log_error(USE_ERRNO|NO_MAIL, 85 "unable to begin bsd authentication"); 86 login_close(state.lc); 87 return AUTH_FATAL; 88 } 89 90 /* XXX - maybe sanity check the auth style earlier? */ 91 login_style = login_getstyle(state.lc, login_style, "auth-sudo"); 92 if (login_style == NULL) { 93 log_error(NO_MAIL, "invalid authentication type"); 94 auth_close(state.as); 95 login_close(state.lc); 96 return AUTH_FATAL; 97 } 98 99 if (auth_setitem(state.as, AUTHV_STYLE, login_style) < 0 || 100 auth_setitem(state.as, AUTHV_NAME, pw->pw_name) < 0 || 101 auth_setitem(state.as, AUTHV_CLASS, login_class) < 0) { 102 log_error(NO_MAIL, "unable to setup authentication"); 103 auth_close(state.as); 104 login_close(state.lc); 105 return AUTH_FATAL; 106 } 107 108 auth->data = (void *) &state; 109 return AUTH_SUCCESS; 110} 111 112int 113bsdauth_verify(pw, prompt, auth) 114 struct passwd *pw; 115 char *prompt; 116 sudo_auth *auth; 117{ 118 char *pass; 119 char *s; 120 size_t len; 121 int authok = 0; 122 sigaction_t sa, osa; 123 auth_session_t *as = ((struct bsdauth_state *) auth->data)->as; 124 125 /* save old signal handler */ 126 sigemptyset(&sa.sa_mask); 127 sa.sa_flags = SA_RESTART; 128 sa.sa_handler = SIG_DFL; 129 (void) sigaction(SIGCHLD, &sa, &osa); 130 131 /* 132 * If there is a challenge then print that instead of the normal 133 * prompt. If the user just hits return we prompt again with echo 134 * turned on, which is useful for challenge/response things like 135 * S/Key. 136 */ 137 if ((s = auth_challenge(as)) == NULL) { 138 pass = tgetpass(prompt, def_passwd_timeout * 60, tgetpass_flags); 139 } else { 140 pass = tgetpass(s, def_passwd_timeout * 60, tgetpass_flags); 141 if (pass && *pass == '\0') { 142 if ((prompt = strrchr(s, '\n'))) 143 prompt++; 144 else 145 prompt = s; 146 147 /* 148 * Append '[echo on]' to the last line of the challenge and 149 * reprompt with echo turned on. 150 */ 151 len = strlen(prompt) - 1; 152 while (isspace(prompt[len]) || prompt[len] == ':') 153 prompt[len--] = '\0'; 154 easprintf(&s, "%s [echo on]: ", prompt); 155 pass = tgetpass(s, def_passwd_timeout * 60, 156 tgetpass_flags | TGP_ECHO); 157 free(s); 158 } 159 } 160 161 if (pass) { 162 authok = auth_userresponse(as, pass, 1); 163 zero_bytes(pass, strlen(pass)); 164 } 165 166 /* restore old signal handler */ 167 (void) sigaction(SIGCHLD, &osa, NULL); 168 169 if (authok) 170 return AUTH_SUCCESS; 171 172 if (!pass) 173 return AUTH_INTR; 174 175 if ((s = auth_getvalue(as, "errormsg")) != NULL) 176 log_error(NO_MAIL, "%s", s); 177 return AUTH_FAILURE; 178} 179 180int 181bsdauth_cleanup(pw, auth) 182 struct passwd *pw; 183 sudo_auth *auth; 184{ 185 struct bsdauth_state *state = auth->data; 186 187 if (state != NULL) { 188 auth_close(state->as); 189 login_close(state->lc); 190 } 191 192 return AUTH_SUCCESS; 193} 194