Annotation of embedaddon/sudo/plugins/sudoers/auth/sudo_auth.c, revision 1.1
1.1 ! misho 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 "sudoers.h"
! 48: #include "sudo_auth.h"
! 49: #include "insults.h"
! 50:
! 51: static sudo_auth auth_switch[] = {
! 52: /* Standalone entries first */
! 53: #ifdef HAVE_PAM
! 54: AUTH_ENTRY("pam", FLAG_STANDALONE, pam_init, NULL, pam_verify, pam_cleanup, pam_begin_session, pam_end_session)
! 55: #endif
! 56: #ifdef HAVE_SECURID
! 57: AUTH_ENTRY("SecurId", FLAG_STANDALONE, securid_init, securid_setup, securid_verify, NULL, NULL, NULL)
! 58: #endif
! 59: #ifdef HAVE_SIA_SES_INIT
! 60: AUTH_ENTRY("sia", FLAG_STANDALONE, NULL, sia_setup, sia_verify, sia_cleanup, NULL, NULL)
! 61: #endif
! 62: #ifdef HAVE_AIXAUTH
! 63: AUTH_ENTRY("aixauth", FLAG_STANDALONE, NULL, NULL, aixauth_verify, aixauth_cleanup, NULL, NULL)
! 64: #endif
! 65: #ifdef HAVE_FWTK
! 66: AUTH_ENTRY("fwtk", FLAG_STANDALONE, fwtk_init, NULL, fwtk_verify, fwtk_cleanup, NULL, NULL)
! 67: #endif
! 68: #ifdef HAVE_BSD_AUTH_H
! 69: AUTH_ENTRY("bsdauth", FLAG_STANDALONE, bsdauth_init, NULL, bsdauth_verify, bsdauth_cleanup, NULL, NULL)
! 70: #endif
! 71:
! 72: /* Non-standalone entries */
! 73: #ifndef WITHOUT_PASSWD
! 74: AUTH_ENTRY("passwd", 0, passwd_init, NULL, passwd_verify, passwd_cleanup, NULL, NULL)
! 75: #endif
! 76: #if defined(HAVE_GETPRPWNAM) && !defined(WITHOUT_PASSWD)
! 77: AUTH_ENTRY("secureware", 0, secureware_init, NULL, secureware_verify, secureware_cleanup, NULL, NULL)
! 78: #endif
! 79: #ifdef HAVE_AFS
! 80: AUTH_ENTRY("afs", 0, NULL, NULL, afs_verify, NULL, NULL, NULL)
! 81: #endif
! 82: #ifdef HAVE_DCE
! 83: AUTH_ENTRY("dce", 0, NULL, NULL, dce_verify, NULL, NULL, NULL)
! 84: #endif
! 85: #ifdef HAVE_KERB4
! 86: AUTH_ENTRY("kerb4", 0, kerb4_init, NULL, kerb4_verify, NULL, NULL, NULL)
! 87: #endif
! 88: #ifdef HAVE_KERB5
! 89: AUTH_ENTRY("kerb5", 0, kerb5_init, kerb5_setup, kerb5_verify, kerb5_cleanup, NULL, NULL)
! 90: #endif
! 91: #ifdef HAVE_SKEY
! 92: AUTH_ENTRY("S/Key", 0, NULL, rfc1938_setup, rfc1938_verify, NULL, NULL, NULL)
! 93: #endif
! 94: #ifdef HAVE_OPIE
! 95: AUTH_ENTRY("OPIE", 0, NULL, rfc1938_setup, rfc1938_verify, NULL, NULL, NULL)
! 96: #endif
! 97: AUTH_ENTRY(NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL)
! 98: };
! 99:
! 100: static int standalone;
! 101:
! 102: extern char **NewArgv; /* XXX - for auditing */
! 103:
! 104: static void pass_warn(void);
! 105:
! 106: int
! 107: sudo_auth_init(struct passwd *pw)
! 108: {
! 109: sudo_auth *auth;
! 110: int status = AUTH_SUCCESS;
! 111:
! 112: if (auth_switch[0].name == NULL)
! 113: return TRUE;
! 114:
! 115: /* Make sure we haven't mixed standalone and shared auth methods. */
! 116: standalone = IS_STANDALONE(&auth_switch[0]);
! 117: if (standalone && auth_switch[1].name != NULL) {
! 118: audit_failure(NewArgv, "invalid authentication methods");
! 119: log_error(0, _("Invalid authentication methods compiled into sudo! "
! 120: "You may mix standalone and non-standalone authentication."));
! 121: return -1;
! 122: }
! 123:
! 124: /* Set FLAG_ONEANDONLY if there is only one auth method. */
! 125: if (auth_switch[1].name == NULL)
! 126: SET(auth_switch[0].flags, FLAG_ONEANDONLY);
! 127:
! 128: /* Initialize auth methods and unconfigure the method if necessary. */
! 129: for (auth = auth_switch; auth->name; auth++) {
! 130: if (auth->init && !IS_DISABLED(auth)) {
! 131: if (NEEDS_USER(auth))
! 132: set_perms(PERM_USER);
! 133:
! 134: status = (auth->init)(pw, auth);
! 135:
! 136: if (NEEDS_USER(auth))
! 137: restore_perms();
! 138:
! 139: if (status == AUTH_FAILURE)
! 140: SET(auth->flags, FLAG_DISABLED);
! 141: else if (status == AUTH_FATAL) {
! 142: /* XXX log */
! 143: audit_failure(NewArgv, "authentication failure");
! 144: break; /* assume error msg already printed */
! 145: }
! 146: }
! 147: }
! 148: return status == AUTH_FATAL ? -1 : TRUE;
! 149: }
! 150:
! 151: int
! 152: sudo_auth_cleanup(struct passwd *pw)
! 153: {
! 154: sudo_auth *auth;
! 155: int status = AUTH_SUCCESS;
! 156:
! 157: /* Call cleanup routines. */
! 158: for (auth = auth_switch; auth->name; auth++) {
! 159: if (auth->cleanup && !IS_DISABLED(auth)) {
! 160: if (NEEDS_USER(auth))
! 161: set_perms(PERM_USER);
! 162:
! 163: status = (auth->cleanup)(pw, auth);
! 164:
! 165: if (NEEDS_USER(auth))
! 166: restore_perms();
! 167:
! 168: if (status == AUTH_FATAL) {
! 169: /* XXX log */
! 170: audit_failure(NewArgv, "authentication failure");
! 171: break; /* assume error msg already printed */
! 172: }
! 173: }
! 174: }
! 175: return status == AUTH_FATAL ? -1 : TRUE;
! 176: }
! 177:
! 178: int
! 179: verify_user(struct passwd *pw, char *prompt)
! 180: {
! 181: int counter = def_passwd_tries + 1;
! 182: int success = AUTH_FAILURE;
! 183: int flags, status, rval;
! 184: char *p;
! 185: sudo_auth *auth;
! 186: sigaction_t sa, osa;
! 187:
! 188: /* Enable suspend during password entry. */
! 189: sigemptyset(&sa.sa_mask);
! 190: sa.sa_flags = SA_RESTART;
! 191: sa.sa_handler = SIG_DFL;
! 192: (void) sigaction(SIGTSTP, &sa, &osa);
! 193:
! 194: /* Make sure we have at least one auth method. */
! 195: /* XXX - check FLAG_DISABLED too */
! 196: if (auth_switch[0].name == NULL) {
! 197: audit_failure(NewArgv, "no authentication methods");
! 198: log_error(0,
! 199: _("There are no authentication methods compiled into sudo! "
! 200: "If you want to turn off authentication, use the "
! 201: "--disable-authentication configure option."));
! 202: return -1;
! 203: }
! 204:
! 205: while (--counter) {
! 206: /* Do any per-method setup and unconfigure the method if needed */
! 207: for (auth = auth_switch; auth->name; auth++) {
! 208: if (auth->setup && !IS_DISABLED(auth)) {
! 209: if (NEEDS_USER(auth))
! 210: set_perms(PERM_USER);
! 211:
! 212: status = (auth->setup)(pw, &prompt, auth);
! 213:
! 214: if (NEEDS_USER(auth))
! 215: restore_perms();
! 216:
! 217: if (status == AUTH_FAILURE)
! 218: SET(auth->flags, FLAG_DISABLED);
! 219: else if (status == AUTH_FATAL) {
! 220: /* XXX log */
! 221: audit_failure(NewArgv, "authentication failure");
! 222: return -1; /* assume error msg already printed */
! 223: }
! 224: }
! 225: }
! 226:
! 227: /* Get the password unless the auth function will do it for us */
! 228: if (standalone) {
! 229: p = prompt;
! 230: } else {
! 231: p = auth_getpass(prompt, def_passwd_timeout * 60,
! 232: SUDO_CONV_PROMPT_ECHO_OFF);
! 233: if (p == NULL)
! 234: break;
! 235: }
! 236:
! 237: /* Call authentication functions. */
! 238: for (auth = auth_switch; auth->name; auth++) {
! 239: if (IS_DISABLED(auth))
! 240: continue;
! 241:
! 242: if (NEEDS_USER(auth))
! 243: set_perms(PERM_USER);
! 244:
! 245: success = auth->status = (auth->verify)(pw, p, auth);
! 246:
! 247: if (NEEDS_USER(auth))
! 248: restore_perms();
! 249:
! 250: if (auth->status != AUTH_FAILURE)
! 251: goto done;
! 252: }
! 253: if (!standalone)
! 254: zero_bytes(p, strlen(p));
! 255: pass_warn();
! 256: }
! 257:
! 258: done:
! 259: switch (success) {
! 260: case AUTH_SUCCESS:
! 261: (void) sigaction(SIGTSTP, &osa, NULL);
! 262: rval = TRUE;
! 263: break;
! 264: case AUTH_INTR:
! 265: case AUTH_FAILURE:
! 266: if (counter != def_passwd_tries) {
! 267: if (def_mail_badpass || def_mail_always)
! 268: flags = 0;
! 269: else
! 270: flags = NO_MAIL;
! 271: log_error(flags, ngettext("%d incorrect password attempt",
! 272: "%d incorrect password attempts",
! 273: def_passwd_tries - counter), def_passwd_tries - counter);
! 274: }
! 275: audit_failure(NewArgv, "authentication failure");
! 276: rval = FALSE;
! 277: break;
! 278: case AUTH_FATAL:
! 279: default:
! 280: audit_failure(NewArgv, "authentication failure");
! 281: rval = -1;
! 282: break;
! 283: }
! 284:
! 285: return rval;
! 286: }
! 287:
! 288: int
! 289: sudo_auth_begin_session(struct passwd *pw)
! 290: {
! 291: sudo_auth *auth;
! 292: int status;
! 293:
! 294: for (auth = auth_switch; auth->name; auth++) {
! 295: if (auth->begin_session && !IS_DISABLED(auth)) {
! 296: status = (auth->begin_session)(pw, auth);
! 297: if (status == AUTH_FATAL) {
! 298: /* XXX log */
! 299: audit_failure(NewArgv, "authentication failure");
! 300: return -1; /* assume error msg already printed */
! 301: }
! 302: }
! 303: }
! 304: return TRUE;
! 305: }
! 306:
! 307: int
! 308: sudo_auth_end_session(struct passwd *pw)
! 309: {
! 310: sudo_auth *auth;
! 311: int status;
! 312:
! 313: for (auth = auth_switch; auth->name; auth++) {
! 314: if (auth->end_session && !IS_DISABLED(auth)) {
! 315: status = (auth->end_session)(pw, auth);
! 316: if (status == AUTH_FATAL) {
! 317: /* XXX log */
! 318: return -1; /* assume error msg already printed */
! 319: }
! 320: }
! 321: }
! 322: return TRUE;
! 323: }
! 324:
! 325: static void
! 326: pass_warn(void)
! 327: {
! 328: const char *warning = def_badpass_message;
! 329:
! 330: #ifdef INSULT
! 331: if (def_insults)
! 332: warning = INSULT;
! 333: #endif
! 334: sudo_printf(SUDO_CONV_ERROR_MSG, "%s\n", warning);
! 335: }
! 336:
! 337: char *
! 338: auth_getpass(const char *prompt, int timeout, int type)
! 339: {
! 340: struct sudo_conv_message msg;
! 341: struct sudo_conv_reply repl;
! 342:
! 343: /* Mask user input if pwfeedback set and echo is off. */
! 344: if (type == SUDO_CONV_PROMPT_ECHO_OFF && def_pwfeedback)
! 345: type = SUDO_CONV_PROMPT_MASK;
! 346:
! 347: /* If visiblepw set, do not error out if there is no tty. */
! 348: if (def_visiblepw)
! 349: type |= SUDO_CONV_PROMPT_ECHO_OK;
! 350:
! 351: /* Call conversation function */
! 352: memset(&msg, 0, sizeof(msg));
! 353: msg.msg_type = type;
! 354: msg.timeout = def_passwd_timeout * 60;
! 355: msg.msg = prompt;
! 356: memset(&repl, 0, sizeof(repl));
! 357: sudo_conv(1, &msg, &repl);
! 358: /* XXX - check for ENOTTY? */
! 359: return repl.reply;
! 360: }
! 361:
! 362: void
! 363: dump_auth_methods(void)
! 364: {
! 365: sudo_auth *auth;
! 366:
! 367: sudo_printf(SUDO_CONV_INFO_MSG, _("Authentication methods:"));
! 368: for (auth = auth_switch; auth->name; auth++)
! 369: sudo_printf(SUDO_CONV_INFO_MSG, " '%s'", auth->name);
! 370: sudo_printf(SUDO_CONV_INFO_MSG, "\n");
! 371: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>