1/* 2 * Copyright (c) 1999-2005, 2008-2010 Todd C. Miller <Todd.Miller@courtesan.com> 3 * 4 * Permission to use, copy, modify, and distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 * 16 * Sponsored in part by the Defense Advanced Research Projects 17 * Agency (DARPA) and Air Force Research Laboratory, Air Force 18 * Materiel Command, USAF, under agreement number F39502-99-1-0512. 19 */ 20 21#include <config.h> 22 23#include <sys/types.h> 24#include <sys/param.h> 25#include <stdio.h> 26#ifdef STDC_HEADERS 27# include <stdlib.h> 28# include <stddef.h> 29#else 30# ifdef HAVE_STDLIB_H 31# include <stdlib.h> 32# endif 33#endif /* STDC_HEADERS */ 34#ifdef HAVE_STRING_H 35# include <string.h> 36#endif /* HAVE_STRING_H */ 37#ifdef HAVE_STRINGS_H 38# include <strings.h> 39#endif /* HAVE_STRINGS_H */ 40#ifdef HAVE_UNISTD_H 41# include <unistd.h> 42#endif /* HAVE_UNISTD_H */ 43#include <pwd.h> 44#include <time.h> 45#include <signal.h> 46 47#include "sudo.h" 48#include "sudo_auth.h" 49#include "insults.h" 50 51extern char **NewArgv; /* XXX */ 52 53sudo_auth auth_switch[] = { 54#ifdef AUTH_STANDALONE 55 AUTH_STANDALONE 56#else 57# ifndef WITHOUT_PASSWD 58 AUTH_ENTRY(0, "passwd", passwd_init, NULL, passwd_verify, passwd_cleanup) 59# endif 60# if defined(HAVE_GETPRPWNAM) && !defined(WITHOUT_PASSWD) 61 AUTH_ENTRY(0, "secureware", secureware_init, NULL, secureware_verify, secureware_cleanup) 62# endif 63# ifdef HAVE_AFS 64 AUTH_ENTRY(0, "afs", NULL, NULL, afs_verify, NULL) 65# endif 66# ifdef HAVE_DCE 67 AUTH_ENTRY(0, "dce", NULL, NULL, dce_verify, NULL) 68# endif 69# ifdef HAVE_KERB4 70 AUTH_ENTRY(0, "kerb4", kerb4_init, NULL, kerb4_verify, NULL) 71# endif 72# ifdef HAVE_KERB5 73 AUTH_ENTRY(0, "kerb5", kerb5_init, kerb5_setup, kerb5_verify, kerb5_cleanup) 74# endif 75# ifdef HAVE_SKEY 76 AUTH_ENTRY(0, "S/Key", NULL, rfc1938_setup, rfc1938_verify, NULL) 77# endif 78# ifdef HAVE_OPIE 79 AUTH_ENTRY(0, "OPIE", NULL, rfc1938_setup, rfc1938_verify, NULL) 80# endif 81#endif /* AUTH_STANDALONE */ 82 AUTH_ENTRY(0, NULL, NULL, NULL, NULL, NULL) 83}; 84 85/* 86 * Initialize sudoers authentication method(s). 87 * Returns 0 on success and -1 on error. 88 */ 89int 90sudo_auth_init(pw) 91 struct passwd *pw; 92{ 93 sudo_auth *auth; 94 int status = AUTH_SUCCESS; 95 96 if (auth_switch[0].name == NULL) 97 return 0; 98 99 /* Set FLAG_ONEANDONLY if there is only one auth method. */ 100 if (auth_switch[1].name == NULL) 101 SET(auth_switch[0].flags, FLAG_ONEANDONLY); 102 103 /* Initialize auth methods and unconfigure the method if necessary. */ 104 for (auth = auth_switch; auth->name; auth++) { 105 if (auth->init && IS_CONFIGURED(auth)) { 106 if (NEEDS_USER(auth)) 107 set_perms(PERM_USER); 108 109 status = (auth->init)(pw, auth); 110 111 if (NEEDS_USER(auth)) 112 set_perms(PERM_ROOT); 113 114 /* Disable if it failed to init unless there was a fatal error. */ 115 if (status == AUTH_FAILURE) 116 CLR(auth->flags, FLAG_CONFIGURED); 117 else if (status == AUTH_FATAL) 118 break; /* assume error msg already printed */ 119 } 120 } 121 return status == AUTH_FATAL ? -1 : 0; 122} 123 124/* 125 * Cleanup all authentication methods. 126 * Returns 0 on success and -1 on error. 127 */ 128int 129sudo_auth_cleanup(pw) 130 struct passwd *pw; 131{ 132 sudo_auth *auth; 133 int status = AUTH_SUCCESS; 134 135 /* Call cleanup routines. */ 136 for (auth = auth_switch; auth->name; auth++) { 137 if (auth->cleanup && IS_CONFIGURED(auth)) { 138 if (NEEDS_USER(auth)) 139 set_perms(PERM_USER); 140 141 status = (auth->cleanup)(pw, auth); 142 143 if (NEEDS_USER(auth)) 144 set_perms(PERM_ROOT); 145 146 if (status == AUTH_FATAL) 147 break; /* assume error msg already printed */ 148 } 149 } 150 return status == AUTH_FATAL ? -1 : 0; 151} 152 153/* 154 * Verify the specified user. 155 * Returns TRUE if verified, FALSE if not or -1 on error. 156 */ 157int 158verify_user(pw, prompt, validated) 159 struct passwd *pw; 160 char *prompt; 161 int validated; 162{ 163 int counter = def_passwd_tries + 1; 164 int success = AUTH_FAILURE; 165 int status, rval; 166 char *p; 167 sudo_auth *auth; 168 sigaction_t sa, osa; 169 170 /* Enable suspend during password entry. */ 171 sigemptyset(&sa.sa_mask); 172 sa.sa_flags = SA_RESTART; 173 sa.sa_handler = SIG_DFL; 174 (void) sigaction(SIGTSTP, &sa, &osa); 175 176 /* Make sure we have at least one auth method. */ 177 /* XXX - check FLAG_DISABLED too */ 178 if (auth_switch[0].name == NULL) { 179 audit_failure(NewArgv, "no authentication methods"); 180 log_error(0, "%s %s %s", 181 "There are no authentication methods compiled into sudo!", 182 "If you want to turn off authentication, use the", 183 "--disable-authentication configure option."); 184 return -1; 185 } 186 187 while (--counter) { 188 /* Do any per-method setup and unconfigure the method if needed */ 189 for (auth = auth_switch; auth->name; auth++) { 190 if (auth->setup && IS_CONFIGURED(auth)) { 191 if (NEEDS_USER(auth)) 192 set_perms(PERM_USER); 193 194 status = (auth->setup)(pw, &prompt, auth); 195 196 if (NEEDS_USER(auth)) 197 set_perms(PERM_ROOT); 198 199 if (status == AUTH_FAILURE) 200 CLR(auth->flags, FLAG_CONFIGURED); 201 else if (status == AUTH_FATAL) { 202 goto done; /* assume error msg already printed */ 203 } 204 } 205 } 206 207 /* Get the password unless the auth function will do it for us */ 208#ifdef AUTH_STANDALONE 209 p = prompt; 210#else 211 p = (char *) tgetpass(prompt, def_passwd_timeout * 60, 212 tgetpass_flags); 213#endif /* AUTH_STANDALONE */ 214 215 /* Call authentication functions. */ 216 for (auth = auth_switch; p && auth->name; auth++) { 217 if (!IS_CONFIGURED(auth)) 218 continue; 219 220 if (NEEDS_USER(auth)) 221 set_perms(PERM_USER); 222 223 success = auth->status = (auth->verify)(pw, (char *)p, auth); 224 225 if (NEEDS_USER(auth)) 226 set_perms(PERM_ROOT); 227 228 if (auth->status != AUTH_FAILURE) 229 goto done; 230 } 231#ifndef AUTH_STANDALONE 232 if (p == NULL) 233 break; 234 zero_bytes(p, strlen(p)); 235#endif 236 if (!ISSET(tgetpass_flags, TGP_ASKPASS)) 237 pass_warn(stderr); 238 } 239 240done: 241 switch (success) { 242 case AUTH_SUCCESS: 243 (void) sigaction(SIGTSTP, &osa, NULL); 244 rval = TRUE; 245 break; 246 case AUTH_INTR: 247 case AUTH_FAILURE: 248 if (counter != def_passwd_tries) 249 validated |= FLAG_BAD_PASSWORD; 250 log_auth_failure(validated, def_passwd_tries - counter); 251 rval = FALSE; 252 break; 253 case AUTH_FATAL: 254 default: 255 log_auth_failure(validated | FLAG_AUTH_ERROR, 0); 256 rval = -1; 257 break; 258 } 259 return rval; 260} 261 262void 263pass_warn(fp) 264 FILE *fp; 265{ 266 267#ifdef INSULT 268 if (def_insults) 269 (void) fprintf(fp, "%s\n", INSULT); 270 else 271#endif 272 (void) fprintf(fp, "%s\n", def_badpass_message); 273} 274 275void 276dump_auth_methods() 277{ 278 sudo_auth *auth; 279 280 (void) fputs("Authentication methods:", stdout); 281 for (auth = auth_switch; auth->name; auth++) 282 (void) printf(" '%s'", auth->name); 283 (void) putchar('\n'); 284} 285