/* * Log, audit and mail the denial message, optionally informing the user. */ bool log_denial(int status, bool inform_user) { const char *message; char *logline; int oldlocale; bool uid_changed, ret = true; debug_decl(log_denial, SUDOERS_DEBUG_LOGGING) /* Handle auditing first (audit_failure() handles the locale itself). */ if (ISSET(status, FLAG_NO_USER | FLAG_NO_HOST)) audit_failure(NewArgc, NewArgv, N_("No user or host")); else audit_failure(NewArgc, NewArgv, N_("validation failure")); /* Log and mail messages should be in the sudoers locale. */ sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale); /* Set error message. */ if (ISSET(status, FLAG_NO_USER)) message = _("user NOT in sudoers"); else if (ISSET(status, FLAG_NO_HOST)) message = _("user NOT authorized on host"); else message = _("command not allowed"); logline = new_logline(message, 0); if (logline == NULL) debug_return_bool(false); /* Become root if we are not already. */ uid_changed = set_perms(PERM_ROOT); if (should_mail(status)) send_mail("%s", logline); /* send mail based on status */ /* * Log via syslog and/or a file. */ if (def_syslog) do_syslog(def_syslog_badpri, logline); if (def_logfile && !do_logfile(logline)) ret = false; if (uid_changed) { if (!restore_perms()) ret = false; /* XXX - return -1 instead? */ } free(logline); /* Restore locale. */ sudoers_setlocale(oldlocale, NULL); /* Inform the user if they failed to authenticate (in their locale). */ if (inform_user) { sudoers_setlocale(SUDOERS_LOCALE_USER, &oldlocale); if (ISSET(status, FLAG_NO_USER)) { sudo_printf(SUDO_CONV_ERROR_MSG, _("%s is not in the sudoers " "file. This incident will be reported.\n"), user_name); } else if (ISSET(status, FLAG_NO_HOST)) { sudo_printf(SUDO_CONV_ERROR_MSG, _("%s is not allowed to run sudo " "on %s. This incident will be reported.\n"), user_name, user_srunhost); } else if (ISSET(status, FLAG_NO_CHECK)) { sudo_printf(SUDO_CONV_ERROR_MSG, _("Sorry, user %s may not run " "sudo on %s.\n"), user_name, user_srunhost); } else { sudo_printf(SUDO_CONV_ERROR_MSG, _("Sorry, user %s is not allowed " "to execute '%s%s%s' as %s%s%s on %s.\n"), user_name, user_cmnd, user_args ? " " : "", user_args ? user_args : "", list_pw ? list_pw->pw_name : runas_pw ? runas_pw->pw_name : user_name, runas_gr ? ":" : "", runas_gr ? runas_gr->gr_name : "", user_host); } sudoers_setlocale(oldlocale, NULL); } debug_return_bool(ret); }
int verify_user(struct passwd *pw, char *prompt) { int counter = def_passwd_tries + 1; int success = AUTH_FAILURE; int flags, status, standalone, rval; char *p; sudo_auth *auth; sigaction_t sa, osa; /* Enable suspend during password entry. */ sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; sa.sa_handler = SIG_DFL; (void) sigaction(SIGTSTP, &sa, &osa); /* Make sure we have at least one auth method. */ if (auth_switch[0].name == NULL) { audit_failure(NewArgv, "no authentication methods"); log_error(0, _("There are no authentication methods compiled into sudo! " "If you want to turn off authentication, use the " "--disable-authentication configure option.")); return -1; } /* Make sure we haven't mixed standalone and shared auth methods. */ standalone = IS_STANDALONE(&auth_switch[0]); if (standalone && auth_switch[1].name != NULL) { audit_failure(NewArgv, "invalid authentication methods"); log_error(0, _("Invalid authentication methods compiled into sudo! " "You may mix standalone and non-standalone authentication.")); return -1; } /* Set FLAG_ONEANDONLY if there is only one auth method. */ if (auth_switch[1].name == NULL) SET(auth_switch[0].flags, FLAG_ONEANDONLY); /* Initialize auth methods and unconfigure the method if necessary. */ for (auth = auth_switch; auth->name; auth++) { if (auth->init && !IS_DISABLED(auth)) { if (NEEDS_USER(auth)) set_perms(PERM_USER); status = (auth->init)(pw, &prompt, auth); if (status == AUTH_FAILURE) SET(auth->flags, FLAG_DISABLED); else if (status == AUTH_FATAL) { /* XXX log */ audit_failure(NewArgv, "authentication failure"); return -1; /* assume error msg already printed */ } if (NEEDS_USER(auth)) restore_perms(); } } while (--counter) { /* Do any per-method setup and unconfigure the method if needed */ for (auth = auth_switch; auth->name; auth++) { if (auth->setup && !IS_DISABLED(auth)) { if (NEEDS_USER(auth)) set_perms(PERM_USER); status = (auth->setup)(pw, &prompt, auth); if (status == AUTH_FAILURE) SET(auth->flags, FLAG_DISABLED); else if (status == AUTH_FATAL) {/* XXX log */ audit_failure(NewArgv, "authentication failure"); return -1; /* assume error msg already printed */ } if (NEEDS_USER(auth)) restore_perms(); } } /* Get the password unless the auth function will do it for us */ if (standalone) { p = prompt; } else { p = auth_getpass(prompt, def_passwd_timeout * 60, SUDO_CONV_PROMPT_ECHO_OFF); if (p == NULL) break; } /* Call authentication functions. */ for (auth = auth_switch; auth->name; auth++) { if (IS_DISABLED(auth)) continue; if (NEEDS_USER(auth)) set_perms(PERM_USER); success = auth->status = (auth->verify)(pw, p, auth); if (NEEDS_USER(auth)) restore_perms(); if (auth->status != AUTH_FAILURE) goto cleanup; } if (!standalone) zero_bytes(p, strlen(p)); pass_warn(); } cleanup: /* Call cleanup routines. */ for (auth = auth_switch; auth->name; auth++) { if (auth->cleanup && !IS_DISABLED(auth)) { if (NEEDS_USER(auth)) set_perms(PERM_USER); status = (auth->cleanup)(pw, auth); if (status == AUTH_FATAL) { /* XXX log */ audit_failure(NewArgv, "authentication failure"); return -1; /* assume error msg already printed */ } if (NEEDS_USER(auth)) restore_perms(); } } switch (success) { case AUTH_SUCCESS: (void) sigaction(SIGTSTP, &osa, NULL); rval = TRUE; break; case AUTH_INTR: case AUTH_FAILURE: if (counter != def_passwd_tries) { if (def_mail_badpass || def_mail_always) flags = 0; else flags = NO_MAIL; log_error(flags, ngettext("%d incorrect password attempt", "%d incorrect password attempts", def_passwd_tries - counter), def_passwd_tries - counter); } audit_failure(NewArgv, "authentication failure"); rval = FALSE; break; case AUTH_FATAL: default: audit_failure(NewArgv, "authentication failure"); rval = -1; break; } return rval; }