From a0c53bd7511a6537dafa5d4c2812f77713e16544 Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Thu, 8 Nov 2012 15:37:44 -0500 Subject: [PATCH] Call gettext inside log_error et al instead of having the caller do it. This way we can display any messages to the user in their own locale but log in the sudoers local. --- plugins/sudoers/auth/bsdauth.c | 8 +-- plugins/sudoers/auth/kerb5.c | 18 ++--- plugins/sudoers/auth/pam.c | 14 ++-- plugins/sudoers/auth/sia.c | 2 +- plugins/sudoers/auth/sudo_auth.c | 4 +- plugins/sudoers/check.c | 6 +- plugins/sudoers/env.c | 2 +- plugins/sudoers/iolog.c | 34 +++++----- plugins/sudoers/locale.c | 6 ++ plugins/sudoers/logging.c | 113 +++++++++++++++++++++---------- plugins/sudoers/logging.h | 1 + plugins/sudoers/parse.c | 4 +- plugins/sudoers/set_perms.c | 2 +- plugins/sudoers/sudoers.c | 34 +++++----- plugins/sudoers/timestamp.c | 40 +++++------ 15 files changed, 167 insertions(+), 121 deletions(-) diff --git a/plugins/sudoers/auth/bsdauth.c b/plugins/sudoers/auth/bsdauth.c index 3597e56ee..e2cbb0581 100644 --- a/plugins/sudoers/auth/bsdauth.c +++ b/plugins/sudoers/auth/bsdauth.c @@ -75,13 +75,13 @@ bsdauth_init(struct passwd *pw, sudo_auth *auth) state.lc = login_getclass(pw->pw_uid ? LOGIN_DEFCLASS : LOGIN_DEFROOTCLASS); if (state.lc == NULL) { log_error(USE_ERRNO|NO_MAIL, - _("unable to get login class for user %s"), pw->pw_name); + N_("unable to get login class for user %s"), pw->pw_name); debug_return_int(AUTH_FATAL); } if ((state.as = auth_open()) == NULL) { log_error(USE_ERRNO|NO_MAIL, - _("unable to begin bsd authentication")); + N_("unable to begin bsd authentication")); login_close(state.lc); debug_return_int(AUTH_FATAL); } @@ -89,7 +89,7 @@ bsdauth_init(struct passwd *pw, sudo_auth *auth) /* XXX - maybe sanity check the auth style earlier? */ login_style = login_getstyle(state.lc, login_style, "auth-sudo"); if (login_style == NULL) { - log_error(NO_MAIL, _("invalid authentication type")); + log_error(NO_MAIL, N_("invalid authentication type")); auth_close(state.as); login_close(state.lc); debug_return_int(AUTH_FATAL); @@ -98,7 +98,7 @@ bsdauth_init(struct passwd *pw, sudo_auth *auth) if (auth_setitem(state.as, AUTHV_STYLE, login_style) < 0 || auth_setitem(state.as, AUTHV_NAME, pw->pw_name) < 0 || auth_setitem(state.as, AUTHV_CLASS, login_class) < 0) { - log_error(NO_MAIL, _("unable to setup authentication")); + log_error(NO_MAIL, N_("unable to setup authentication")); auth_close(state.as); login_close(state.lc); debug_return_int(AUTH_FATAL); diff --git a/plugins/sudoers/auth/kerb5.c b/plugins/sudoers/auth/kerb5.c index ab47c190c..0ccdb0e75 100644 --- a/plugins/sudoers/auth/kerb5.c +++ b/plugins/sudoers/auth/kerb5.c @@ -114,7 +114,7 @@ sudo_krb5_setup(struct passwd *pw, char **promptp, sudo_auth *auth) */ if ((error = krb5_unparse_name(sudo_context, princ, &pname))) { log_error(NO_MAIL, - _("%s: unable to unparse princ ('%s'): %s"), auth->name, + N_("%s: unable to unparse princ ('%s'): %s"), auth->name, pw->pw_name, error_message(error)); debug_return_int(AUTH_FAILURE); } @@ -157,7 +157,7 @@ sudo_krb5_init(struct passwd *pw, sudo_auth *auth) error = krb5_parse_name(sudo_context, pname, &(sudo_krb5_data.princ)); if (error) { log_error(NO_MAIL, - _("%s: unable to parse '%s': %s"), auth->name, pname, + N_("%s: unable to parse '%s': %s"), auth->name, pname, error_message(error)); goto done; } @@ -167,7 +167,7 @@ sudo_krb5_init(struct passwd *pw, sudo_auth *auth) if ((error = krb5_cc_resolve(sudo_context, cache_name, &(sudo_krb5_data.ccache)))) { log_error(NO_MAIL, - _("%s: unable to resolve ccache: %s"), auth->name, + N_("%s: unable to resolve ccache: %s"), auth->name, error_message(error)); goto done; } @@ -215,7 +215,7 @@ sudo_krb5_verify(struct passwd *pw, char *pass, sudo_auth *auth) error = krb5_get_init_creds_opt_alloc(sudo_context, &opts); if (error) { log_error(NO_MAIL, - _("%s: unable to allocate options: %s"), auth->name, + N_("%s: unable to allocate options: %s"), auth->name, error_message(error)); goto done; } @@ -231,7 +231,7 @@ sudo_krb5_verify(struct passwd *pw, char *pass, sudo_auth *auth) /* Don't print error if just a bad password */ if (error != KRB5KRB_AP_ERR_BAD_INTEGRITY) log_error(NO_MAIL, - _("%s: unable to get credentials: %s"), auth->name, + N_("%s: unable to get credentials: %s"), auth->name, error_message(error)); goto done; } @@ -244,11 +244,11 @@ sudo_krb5_verify(struct passwd *pw, char *pass, sudo_auth *auth) /* Store cred in cred cache. */ if ((error = krb5_cc_initialize(sudo_context, ccache, princ))) { log_error(NO_MAIL, - _("%s: unable to initialize ccache: %s"), auth->name, + N_("%s: unable to initialize ccache: %s"), auth->name, error_message(error)); } else if ((error = krb5_cc_store_cred(sudo_context, ccache, creds))) { log_error(NO_MAIL, - _("%s: unable to store cred in ccache: %s"), auth->name, + N_("%s: unable to store cred in ccache: %s"), auth->name, error_message(error)); } @@ -313,7 +313,7 @@ verify_krb_v5_tgt(krb5_context sudo_context, krb5_creds *cred, char *auth_name) if ((error = krb5_sname_to_principal(sudo_context, NULL, NULL, KRB5_NT_SRV_HST, &server))) { log_error(NO_MAIL, - _("%s: unable to get host principal: %s"), auth_name, + N_("%s: unable to get host principal: %s"), auth_name, error_message(error)); debug_return_int(-1); } @@ -328,7 +328,7 @@ verify_krb_v5_tgt(krb5_context sudo_context, krb5_creds *cred, char *auth_name) krb5_free_principal(sudo_context, server); if (error) log_error(NO_MAIL, - _("%s: Cannot verify TGT! Possible attack!: %s"), + N_("%s: Cannot verify TGT! Possible attack!: %s"), auth_name, error_message(error)); debug_return_int(error); } diff --git a/plugins/sudoers/auth/pam.c b/plugins/sudoers/auth/pam.c index 0ede54088..6ec97c6ce 100644 --- a/plugins/sudoers/auth/pam.c +++ b/plugins/sudoers/auth/pam.c @@ -97,7 +97,7 @@ sudo_pam_init(struct passwd *pw, sudo_auth *auth) #endif pam_status = pam_start("sudo", pw->pw_name, &pam_conv, &pamh); if (pam_status != PAM_SUCCESS) { - log_error(USE_ERRNO|NO_MAIL, _("unable to initialize PAM")); + log_error(USE_ERRNO|NO_MAIL, N_("unable to initialize PAM")); debug_return_int(AUTH_FATAL); } @@ -141,26 +141,26 @@ sudo_pam_verify(struct passwd *pw, char *prompt, sudo_auth *auth) case PAM_SUCCESS: debug_return_int(AUTH_SUCCESS); case PAM_AUTH_ERR: - log_error(NO_MAIL, _("account validation failure, " + log_error(NO_MAIL, N_("account validation failure, " "is your account locked?")); debug_return_int(AUTH_FATAL); case PAM_NEW_AUTHTOK_REQD: - log_error(NO_MAIL, _("Account or password is " + log_error(NO_MAIL, N_("Account or password is " "expired, reset your password and try again")); *pam_status = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK); if (*pam_status == PAM_SUCCESS) debug_return_int(AUTH_SUCCESS); if ((s = pam_strerror(pamh, *pam_status))) - log_error(NO_MAIL, _("pam_chauthtok: %s"), s); + log_error(NO_MAIL, N_("pam_chauthtok: %s"), s); debug_return_int(AUTH_FAILURE); case PAM_AUTHTOK_EXPIRED: log_error(NO_MAIL, - _("Password expired, contact your system administrator")); + N_("Password expired, contact your system administrator")); debug_return_int(AUTH_FATAL); case PAM_ACCT_EXPIRED: log_error(NO_MAIL, - _("Account expired or PAM config lacks an \"account\" " + N_("Account expired or PAM config lacks an \"account\" " "section for sudo, contact your system administrator")); debug_return_int(AUTH_FATAL); } @@ -177,7 +177,7 @@ sudo_pam_verify(struct passwd *pw, char *prompt, sudo_auth *auth) debug_return_int(AUTH_FAILURE); default: if ((s = pam_strerror(pamh, *pam_status))) - log_error(NO_MAIL, _("pam_authenticate: %s"), s); + log_error(NO_MAIL, N_("pam_authenticate: %s"), s); debug_return_int(AUTH_FATAL); } } diff --git a/plugins/sudoers/auth/sia.c b/plugins/sudoers/auth/sia.c index d9f685e17..a9f847eda 100644 --- a/plugins/sudoers/auth/sia.c +++ b/plugins/sudoers/auth/sia.c @@ -106,7 +106,7 @@ sudo_sia_setup(struct passwd *pw, char **promptp, sudo_auth *auth) if (sia_ses_init(&siah, sudo_argc, sudo_argv, NULL, pw->pw_name, user_ttypath, 1, NULL) != SIASUCCESS) { log_error(USE_ERRNO|NO_MAIL, - _("unable to initialize SIA session")); + N_("unable to initialize SIA session")); debug_return_int(AUTH_FATAL); } diff --git a/plugins/sudoers/auth/sudo_auth.c b/plugins/sudoers/auth/sudo_auth.c index 79bb12543..e23954221 100644 --- a/plugins/sudoers/auth/sudo_auth.c +++ b/plugins/sudoers/auth/sudo_auth.c @@ -118,7 +118,7 @@ sudo_auth_init(struct passwd *pw) standalone = IS_STANDALONE(&auth_switch[0]); if (standalone && auth_switch[1].name != NULL) { audit_failure(NewArgv, N_("invalid authentication methods")); - log_fatal(0, _("Invalid authentication methods compiled into sudo! " + log_fatal(0, N_("Invalid authentication methods compiled into sudo! " "You may mix standalone and non-standalone authentication.")); debug_return_int(-1); } @@ -203,7 +203,7 @@ verify_user(struct passwd *pw, char *prompt, int validated) if (auth_switch[0].name == NULL) { audit_failure(NewArgv, N_("no authentication methods")); log_error(0, - _("There are no authentication methods compiled into sudo! " + N_("There are no authentication methods compiled into sudo! " "If you want to turn off authentication, use the " "--disable-authentication configure option.")); debug_return_int(-1); diff --git a/plugins/sudoers/check.c b/plugins/sudoers/check.c index 978dad2c0..cb2e35679 100644 --- a/plugins/sudoers/check.c +++ b/plugins/sudoers/check.c @@ -208,13 +208,13 @@ get_authpw(void) if (def_rootpw) { if ((pw = sudo_getpwuid(ROOT_UID)) == NULL) - log_fatal(0, _("unknown uid: %u"), ROOT_UID); + log_fatal(0, N_("unknown uid: %u"), ROOT_UID); } else if (def_runaspw) { if ((pw = sudo_getpwnam(def_runas_default)) == NULL) - log_fatal(0, _("unknown user: %s"), def_runas_default); + log_fatal(0, N_("unknown user: %s"), def_runas_default); } else if (def_targetpw) { if (runas_pw->pw_name == NULL) - log_fatal(NO_MAIL|MSG_ONLY, _("unknown uid: %u"), + log_fatal(NO_MAIL|MSG_ONLY, N_("unknown uid: %u"), (unsigned int) runas_pw->pw_uid); sudo_pw_addref(runas_pw); pw = runas_pw; diff --git a/plugins/sudoers/env.c b/plugins/sudoers/env.c index 3307366e2..ca0b0f422 100644 --- a/plugins/sudoers/env.c +++ b/plugins/sudoers/env.c @@ -1010,7 +1010,7 @@ validate_env_vars(char * const env_vars[]) if (bad != NULL) { bad[blen - 2] = '\0'; /* remove trailing ", " */ log_fatal(NO_MAIL, - _("sorry, you are not allowed to set the following environment variables: %s"), bad); + N_("sorry, you are not allowed to set the following environment variables: %s"), bad); /* NOTREACHED */ efree(bad); } diff --git a/plugins/sudoers/iolog.c b/plugins/sudoers/iolog.c index 4332d035b..bd526caa5 100644 --- a/plugins/sudoers/iolog.c +++ b/plugins/sudoers/iolog.c @@ -119,9 +119,9 @@ mkdir_parents(char *path) *slash = '\0'; if (stat(path, &sb) != 0) { if (mkdir(path, S_IRWXU) != 0) - log_fatal(USE_ERRNO, _("unable to mkdir %s"), path); + log_fatal(USE_ERRNO, N_("unable to mkdir %s"), path); } else if (!S_ISDIR(sb.st_mode)) { - log_fatal(0, _("%s: %s"), path, strerror(ENOTDIR)); + log_fatal(0, N_("%s: %s"), path, strerror(ENOTDIR)); } *slash = '/'; } @@ -152,9 +152,9 @@ io_nextid(char *iolog_dir, char *iolog_dir_fallback, char sessid[7]) mkdir_parents(iolog_dir); if (stat(iolog_dir, &sb) != 0) { if (mkdir(iolog_dir, S_IRWXU) != 0) - log_fatal(USE_ERRNO, _("unable to mkdir %s"), iolog_dir); + log_fatal(USE_ERRNO, N_("unable to mkdir %s"), iolog_dir); } else if (!S_ISDIR(sb.st_mode)) { - log_fatal(0, _("%s exists but is not a directory (0%o)"), + log_fatal(0, N_("%s exists but is not a directory (0%o)"), iolog_dir, (unsigned int) sb.st_mode); } @@ -168,7 +168,7 @@ io_nextid(char *iolog_dir, char *iolog_dir_fallback, char sessid[7]) } fd = open(pathbuf, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR); if (fd == -1) - log_fatal(USE_ERRNO, _("unable to open %s"), pathbuf); + log_fatal(USE_ERRNO, N_("unable to open %s"), pathbuf); lock_file(fd, SUDO_LOCK); /* @@ -201,10 +201,10 @@ io_nextid(char *iolog_dir, char *iolog_dir_fallback, char sessid[7]) nread = read(fd, buf, sizeof(buf)); if (nread != 0) { if (nread == -1) - log_fatal(USE_ERRNO, _("unable to read %s"), pathbuf); + log_fatal(USE_ERRNO, N_("unable to read %s"), pathbuf); id = strtoul(buf, &ep, 36); if (buf == ep || id >= SESSID_MAX) - log_fatal(0, _("invalid sequence number %s"), pathbuf); + log_fatal(0, N_("invalid sequence number %s"), pathbuf); } } id++; @@ -225,7 +225,7 @@ io_nextid(char *iolog_dir, char *iolog_dir_fallback, char sessid[7]) /* Rewind and overwrite old seq file. */ if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1 || write(fd, buf, 7) != 7) - log_fatal(USE_ERRNO, _("unable to write to %s"), pathbuf); + log_fatal(USE_ERRNO, N_("unable to write to %s"), pathbuf); close(fd); debug_return; @@ -254,10 +254,10 @@ mkdir_iopath(const char *iolog_path, char *pathbuf, size_t pathsize) mkdir_parents(pathbuf); if (len >= 6 && strcmp(&pathbuf[len - 6], "XXXXXX") == 0) { if (mkdtemp(pathbuf) == NULL) - log_fatal(USE_ERRNO, _("unable to create %s"), pathbuf); + log_fatal(USE_ERRNO, N_("unable to create %s"), pathbuf); } else { if (mkdir(pathbuf, S_IRWXU) != 0) - log_fatal(USE_ERRNO, _("unable to create %s"), pathbuf); + log_fatal(USE_ERRNO, N_("unable to create %s"), pathbuf); } debug_return_size_t(len); @@ -522,18 +522,18 @@ sudoers_io_open(unsigned int version, sudo_conv_t conversation, */ io_logfile = open_io_fd(pathbuf, len, "/log", false); if (io_logfile == NULL) - log_fatal(USE_ERRNO, _("unable to create %s"), pathbuf); + log_fatal(USE_ERRNO, N_("unable to create %s"), pathbuf); io_fds[IOFD_TIMING].v = open_io_fd(pathbuf, len, "/timing", iolog_compress); if (io_fds[IOFD_TIMING].v == NULL) - log_fatal(USE_ERRNO, _("unable to create %s"), pathbuf); + log_fatal(USE_ERRNO, N_("unable to create %s"), pathbuf); if (details.iolog_ttyin) { io_fds[IOFD_TTYIN].v = open_io_fd(pathbuf, len, "/ttyin", iolog_compress); if (io_fds[IOFD_TTYIN].v == NULL) - log_fatal(USE_ERRNO, _("unable to create %s"), pathbuf); + log_fatal(USE_ERRNO, N_("unable to create %s"), pathbuf); } else { sudoers_io.log_ttyin = NULL; } @@ -541,7 +541,7 @@ sudoers_io_open(unsigned int version, sudo_conv_t conversation, io_fds[IOFD_STDIN].v = open_io_fd(pathbuf, len, "/stdin", iolog_compress); if (io_fds[IOFD_STDIN].v == NULL) - log_fatal(USE_ERRNO, _("unable to create %s"), pathbuf); + log_fatal(USE_ERRNO, N_("unable to create %s"), pathbuf); } else { sudoers_io.log_stdin = NULL; } @@ -549,7 +549,7 @@ sudoers_io_open(unsigned int version, sudo_conv_t conversation, io_fds[IOFD_TTYOUT].v = open_io_fd(pathbuf, len, "/ttyout", iolog_compress); if (io_fds[IOFD_TTYOUT].v == NULL) - log_fatal(USE_ERRNO, _("unable to create %s"), pathbuf); + log_fatal(USE_ERRNO, N_("unable to create %s"), pathbuf); } else { sudoers_io.log_ttyout = NULL; } @@ -557,7 +557,7 @@ sudoers_io_open(unsigned int version, sudo_conv_t conversation, io_fds[IOFD_STDOUT].v = open_io_fd(pathbuf, len, "/stdout", iolog_compress); if (io_fds[IOFD_STDOUT].v == NULL) - log_fatal(USE_ERRNO, _("unable to create %s"), pathbuf); + log_fatal(USE_ERRNO, N_("unable to create %s"), pathbuf); } else { sudoers_io.log_stdout = NULL; } @@ -565,7 +565,7 @@ sudoers_io_open(unsigned int version, sudo_conv_t conversation, io_fds[IOFD_STDERR].v = open_io_fd(pathbuf, len, "/stderr", iolog_compress); if (io_fds[IOFD_STDERR].v == NULL) - log_fatal(USE_ERRNO, _("unable to create %s"), pathbuf); + log_fatal(USE_ERRNO, N_("unable to create %s"), pathbuf); } else { sudoers_io.log_stderr = NULL; } diff --git a/plugins/sudoers/locale.c b/plugins/sudoers/locale.c index 771b963c7..e82bb3ece 100644 --- a/plugins/sudoers/locale.c +++ b/plugins/sudoers/locale.c @@ -42,6 +42,12 @@ static int current_locale = SUDOERS_LOCALE_USER; +int +sudoers_getlocale(void) +{ + return current_locale; +} + int sudoers_setlocale(int newlocale, int *prevlocale) { diff --git a/plugins/sudoers/logging.c b/plugins/sudoers/logging.c index b6b265dcb..7e5288323 100644 --- a/plugins/sudoers/logging.c +++ b/plugins/sudoers/logging.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994-1996, 1998-2011 Todd C. Miller + * Copyright (c) 1994-1996, 1998-2012 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -61,6 +61,13 @@ #include "sudoers.h" +#ifndef va_copy +# define va_copy(d, s) memcpy(&(d), &(s), sizeof(d)); +#endif + +/* Special message for log_error() so we know to use ngettext() */ +#define INCORRECT_PASSWORD_ATTEMPT ((char *)0x01) + static void do_syslog(int, char *); static void do_logfile(char *); static void send_mail(const char *fmt, ...); @@ -235,15 +242,20 @@ do_logfile(char *msg) void log_denial(int status, bool inform_user) { - char *logline, *message; + const char *message; + char *logline; + int oldlocale; debug_decl(log_denial, SUDO_DEBUG_LOGGING) - /* Handle auditing first. */ + /* Handle auditing first (audit_failure() handles the locale itself). */ if (ISSET(status, FLAG_NO_USER | FLAG_NO_HOST)) audit_failure(NewArgv, N_("No user or host")); else audit_failure(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"); @@ -257,8 +269,23 @@ log_denial(int status, bool inform_user) if (should_mail(status)) send_mail("%s", logline); /* send mail based on status */ - /* Inform the user if they failed to authenticate. */ + /* + * Log via syslog and/or a file. + */ + if (def_syslog) + do_syslog(def_syslog_badpri, logline); + if (def_logfile) + do_logfile(logline); + + efree(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); @@ -278,17 +305,8 @@ log_denial(int status, bool inform_user) runas_pw->pw_name : user_name, runas_gr ? ":" : "", runas_gr ? runas_gr->gr_name : "", user_host); } + sudoers_setlocale(oldlocale, NULL); } - - /* - * Log via syslog and/or a file. - */ - if (def_syslog) - do_syslog(def_syslog_badpri, logline); - if (def_logfile) - do_logfile(logline); - - efree(logline); debug_return; } @@ -357,12 +375,10 @@ log_auth_failure(int status, int tries) /* * If sudoers denied the command we'll log that separately. */ - if (ISSET(status, FLAG_BAD_PASSWORD)) { - log_error(flags, ngettext("%d incorrect password attempt", - "%d incorrect password attempts", tries), tries); - } else if (ISSET(status, FLAG_NON_INTERACTIVE)) { - log_error(flags, _("a password is required")); - } + if (ISSET(status, FLAG_BAD_PASSWORD)) + log_error(flags, INCORRECT_PASSWORD_ATTEMPT, tries); + else if (ISSET(status, FLAG_NON_INTERACTIVE)) + log_error(flags, N_("a password is required")); debug_return; } @@ -399,32 +415,36 @@ log_allowed(int status) static void vlog_error(int flags, const char *fmt, va_list ap) { - int serrno = errno; + int oldlocale, serrno = errno; char *logline, *message; + va_list ap2; debug_decl(vlog_error, SUDO_DEBUG_LOGGING) - /* Expand printf-style format + args. */ - evasprintf(&message, fmt, ap); - /* Become root if we are not already to avoid user interference */ set_perms(PERM_ROOT|PERM_NOEXIT); - if (ISSET(flags, MSG_ONLY)) - logline = message; - else - logline = new_logline(message, ISSET(flags, USE_ERRNO) ? serrno : 0); + /* Need extra copy of ap for warning() below. */ + if (!ISSET(flags, NO_STDERR)) + va_copy(ap2, ap); - /* - * Tell the user. - */ - if (!ISSET(flags, NO_STDERR)) { - if (ISSET(flags, USE_ERRNO)) - warning("%s", message); - else - warningx("%s", message); + /* Log messages should be in the sudoers locale. */ + sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale); + + /* Expand printf-style format + args (with a special case). */ + if (fmt == INCORRECT_PASSWORD_ATTEMPT) { + int tries = va_arg(ap, int); + easprintf(&message, ngettext("%d incorrect password attempt", + "%d incorrect password attempts", tries), tries); + } else { + evasprintf(&message, _(fmt), ap); } - if (logline != message) + + if (ISSET(flags, MSG_ONLY)) { + logline = message; + } else { + logline = new_logline(message, ISSET(flags, USE_ERRNO) ? serrno : 0); efree(message); + } /* * Send a copy of the error via mail. @@ -444,8 +464,27 @@ vlog_error(int flags, const char *fmt, va_list ap) efree(logline); + sudoers_setlocale(oldlocale, NULL); + restore_perms(); + /* + * Tell the user (in their locale). + */ + if (!ISSET(flags, NO_STDERR)) { + if (fmt == INCORRECT_PASSWORD_ATTEMPT) { + int tries = va_arg(ap2, int); + warningx(ngettext("%d incorrect password attempt", + "%d incorrect password attempts", tries), tries); + } else { + if (ISSET(flags, USE_ERRNO)) + vwarning(fmt, ap2); + else + vwarningx(fmt, ap2); + } + va_end(ap2); + } + debug_return; } diff --git a/plugins/sudoers/logging.h b/plugins/sudoers/logging.h index bed13f252..290839a10 100644 --- a/plugins/sudoers/logging.h +++ b/plugins/sudoers/logging.h @@ -68,5 +68,6 @@ void log_error(int flags, const char *fmt, ...) __printflike(2, 3); void log_fatal(int flags, const char *fmt, ...) __printflike(2, 3) __attribute__((__noreturn__)); void writeln_wrap(FILE *fp, char *line, size_t len, size_t maxlen); int sudoers_setlocale(int newlocale, int *prevlocale); +int sudoers_getlocale(void); #endif /* _LOGGING_H */ diff --git a/plugins/sudoers/parse.c b/plugins/sudoers/parse.c index 7172ea9a3..f5addf0a6 100644 --- a/plugins/sudoers/parse.c +++ b/plugins/sudoers/parse.c @@ -120,10 +120,10 @@ sudo_file_parse(struct sudo_nss *nss) sudoersin = nss->handle; if (sudoersparse() != 0 || parse_error) { if (errorlineno != -1) { - log_error(0, _("parse error in %s near line %d"), + log_error(0, N_("parse error in %s near line %d"), errorfile, errorlineno); } else { - log_error(0, _("parse error in %s"), errorfile); + log_error(0, N_("parse error in %s"), errorfile); } debug_return_int(-1); } diff --git a/plugins/sudoers/set_perms.c b/plugins/sudoers/set_perms.c index be665dae3..d91640ab4 100644 --- a/plugins/sudoers/set_perms.c +++ b/plugins/sudoers/set_perms.c @@ -1539,7 +1539,7 @@ runas_setgroups(void) aix_restoreauthdb(); #endif if (sudo_setgroups(grlist->ngids, grlist->gids) < 0) - log_fatal(USE_ERRNO|MSG_ONLY, _("unable to set runas group vector")); + log_fatal(USE_ERRNO|MSG_ONLY, N_("unable to set runas group vector")); debug_return_ptr(grlist); } #endif /* HAVE_SETRESUID || HAVE_SETREUID || HAVE_SETEUID */ diff --git a/plugins/sudoers/sudoers.c b/plugins/sudoers/sudoers.c index d37863f47..a76f12055 100644 --- a/plugins/sudoers/sudoers.c +++ b/plugins/sudoers/sudoers.c @@ -162,7 +162,7 @@ sudoers_policy_init(void *info, char * const envp[]) if (nss->open(nss) == 0 && nss->parse(nss) == 0) { sources++; if (nss->setdefs(nss) != 0) - log_error(NO_STDERR, _("problem with defaults entries")); + log_error(NO_STDERR, N_("problem with defaults entries")); } else { tq_remove(snl, nss); } @@ -196,7 +196,7 @@ sudoers_policy_init(void *info, char * const envp[]) set_runaspw(runas_user ? runas_user : def_runas_default); if (!update_defaults(SETDEF_RUNAS)) - log_error(NO_STDERR, _("problem with defaults entries")); + log_error(NO_STDERR, N_("problem with defaults entries")); if (def_fqdn) set_fqdn(); /* deferred until after sudoers is parsed */ @@ -333,7 +333,7 @@ sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[], timestamp_uid = pw->pw_uid; sudo_pw_delref(pw); } else { - log_error(0, _("timestamp owner (%s): No such user"), + log_error(0, N_("timestamp owner (%s): No such user"), def_timestampowner); timestamp_uid = ROOT_UID; } @@ -595,7 +595,7 @@ init_vars(char * const envp[]) /* Need to make a fake struct passwd for the call to log_fatal(). */ sudo_user.pw = sudo_fakepwnamid(user_name, user_uid, user_gid); - log_fatal(0, _("unknown uid: %u"), (unsigned int) user_uid); + log_fatal(0, N_("unknown uid: %u"), (unsigned int) user_uid); /* NOTREACHED */ } } @@ -694,7 +694,7 @@ set_cmnd(void) user_base = user_cmnd; if (!update_defaults(SETDEF_CMND)) - log_error(NO_STDERR, _("problem with defaults entries")); + log_error(NO_STDERR, N_("problem with defaults entries")); debug_return_int(rval); } @@ -729,10 +729,10 @@ open_sudoers(const char *sudoers, bool doedit, bool *keepopen) * the user with a reasonable error message (unlike the lexer). */ if ((fp = fopen(sudoers, "r")) == NULL) { - log_error(USE_ERRNO, _("unable to open %s"), sudoers); + log_error(USE_ERRNO, N_("unable to open %s"), sudoers); } else { if (sb.st_size != 0 && fgetc(fp) == EOF) { - log_error(USE_ERRNO, _("unable to read %s"), + log_error(USE_ERRNO, N_("unable to read %s"), sudoers); fclose(fp); fp = NULL; @@ -744,20 +744,20 @@ open_sudoers(const char *sudoers, bool doedit, bool *keepopen) } break; case SUDO_PATH_MISSING: - log_error(USE_ERRNO, _("unable to stat %s"), sudoers); + log_error(USE_ERRNO, N_("unable to stat %s"), sudoers); break; case SUDO_PATH_BAD_TYPE: - log_error(0, _("%s is not a regular file"), sudoers); + log_error(0, N_("%s is not a regular file"), sudoers); break; case SUDO_PATH_WRONG_OWNER: - log_error(0, _("%s is owned by uid %u, should be %u"), + log_error(0, N_("%s is owned by uid %u, should be %u"), sudoers, (unsigned int) sb.st_uid, (unsigned int) sudoers_uid); break; case SUDO_PATH_WORLD_WRITABLE: - log_error(0, _("%s is world writable"), sudoers); + log_error(0, N_("%s is world writable"), sudoers); break; case SUDO_PATH_GROUP_WRITABLE: - log_error(0, _("%s is owned by gid %u, should be %u"), + log_error(0, N_("%s is owned by gid %u, should be %u"), sudoers, (unsigned int) sb.st_gid, (unsigned int) sudoers_gid); break; default: @@ -801,9 +801,9 @@ set_loginclass(struct passwd *pw) * corrupted we want the admin to be able to use sudo to fix it. */ if (login_class) - log_fatal(errflags, _("unknown login class: %s"), login_class); + log_fatal(errflags, N_("unknown login class: %s"), login_class); else - log_error(errflags, _("unknown login class: %s"), login_class); + log_error(errflags, N_("unknown login class: %s"), login_class); def_use_loginclass = false; } login_close(lc); @@ -835,7 +835,7 @@ set_fqdn(void) hint.ai_family = PF_UNSPEC; hint.ai_flags = AI_FQDN; if (getaddrinfo(user_host, NULL, &hint, &res0) != 0) { - log_error(MSG_ONLY, _("unable to resolve host %s"), user_host); + log_error(MSG_ONLY, N_("unable to resolve host %s"), user_host); } else { if (user_shost != user_host) efree(user_shost); @@ -866,7 +866,7 @@ set_runaspw(const char *user) runas_pw = sudo_fakepwnam(user, runas_gr ? runas_gr->gr_gid : 0); } else { if ((runas_pw = sudo_getpwnam(user)) == NULL) - log_fatal(NO_MAIL|MSG_ONLY, _("unknown user: %s"), user); + log_fatal(NO_MAIL|MSG_ONLY, N_("unknown user: %s"), user); } debug_return; } @@ -887,7 +887,7 @@ set_runasgr(const char *group) runas_gr = sudo_fakegrnam(group); } else { if ((runas_gr = sudo_getgrnam(group)) == NULL) - log_fatal(NO_MAIL|MSG_ONLY, _("unknown group: %s"), group); + log_fatal(NO_MAIL|MSG_ONLY, N_("unknown group: %s"), group); } debug_return; } diff --git a/plugins/sudoers/timestamp.c b/plugins/sudoers/timestamp.c index b4fc4bc21..84f1f2cef 100644 --- a/plugins/sudoers/timestamp.c +++ b/plugins/sudoers/timestamp.c @@ -125,7 +125,7 @@ build_timestamp(void) debug_return_int(len); bad: - log_fatal(0, _("timestamp path too long: %s"), + log_fatal(0, N_("timestamp path too long: %s"), *timestampfile ? timestampfile : timestampdir); /* NOTREACHED */ debug_return_int(-1); @@ -151,17 +151,17 @@ update_timestamp(void) */ int fd = open(timestampfile, O_WRONLY|O_CREAT, 0600); if (fd == -1) - log_error(USE_ERRNO, _("unable to open %s"), timestampfile); + log_error(USE_ERRNO, N_("unable to open %s"), timestampfile); else { lock_file(fd, SUDO_LOCK); if (write(fd, &tty_info, sizeof(tty_info)) != sizeof(tty_info)) - log_error(USE_ERRNO, _("unable to write to %s"), timestampfile); + log_error(USE_ERRNO, N_("unable to write to %s"), timestampfile); close(fd); } } else { if (touch(-1, timestampdir, NULL) == -1) { if (mkdir(timestampdir, 0700) == -1) { - log_error(USE_ERRNO, _("unable to mkdir %s"), + log_error(USE_ERRNO, N_("unable to mkdir %s"), timestampdir); } } @@ -196,15 +196,15 @@ timestamp_status_internal(bool removing) */ if (lstat(dirparent, &sb) == 0) { if (!S_ISDIR(sb.st_mode)) - log_error(0, _("%s exists but is not a directory (0%o)"), + log_error(0, N_("%s exists but is not a directory (0%o)"), dirparent, (unsigned int) sb.st_mode); else if (sb.st_uid != timestamp_uid) - log_error(0, _("%s owned by uid %u, should be uid %u"), + log_error(0, N_("%s owned by uid %u, should be uid %u"), dirparent, (unsigned int) sb.st_uid, (unsigned int) timestamp_uid); else if ((sb.st_mode & 0000022)) log_error(0, - _("%s writable by non-owner (0%o), should be mode 0700"), + N_("%s writable by non-owner (0%o), should be mode 0700"), dirparent, (unsigned int) sb.st_mode); else { if ((sb.st_mode & 0000777) != 0700) @@ -212,12 +212,12 @@ timestamp_status_internal(bool removing) status = TS_MISSING; } } else if (errno != ENOENT) { - log_error(USE_ERRNO, _("unable to stat %s"), dirparent); + log_error(USE_ERRNO, N_("unable to stat %s"), dirparent); } else { /* No dirparent, try to make one. */ if (!removing) { if (mkdir(dirparent, S_IRWXU)) - log_error(USE_ERRNO, _("unable to mkdir %s"), + log_error(USE_ERRNO, N_("unable to mkdir %s"), dirparent); else status = TS_MISSING; @@ -240,15 +240,15 @@ timestamp_status_internal(bool removing) if (unlink(timestampdir) == 0) status = TS_MISSING; } else - log_error(0, _("%s exists but is not a directory (0%o)"), + log_error(0, N_("%s exists but is not a directory (0%o)"), timestampdir, (unsigned int) sb.st_mode); } else if (sb.st_uid != timestamp_uid) - log_error(0, _("%s owned by uid %u, should be uid %u"), + log_error(0, N_("%s owned by uid %u, should be uid %u"), timestampdir, (unsigned int) sb.st_uid, (unsigned int) timestamp_uid); else if ((sb.st_mode & 0000022)) log_error(0, - _("%s writable by non-owner (0%o), should be mode 0700"), + N_("%s writable by non-owner (0%o), should be mode 0700"), timestampdir, (unsigned int) sb.st_mode); else { if ((sb.st_mode & 0000777) != 0700) @@ -256,7 +256,7 @@ timestamp_status_internal(bool removing) status = TS_OLD; /* do date check later */ } } else if (errno != ENOENT) { - log_error(USE_ERRNO, _("unable to stat %s"), timestampdir); + log_error(USE_ERRNO, N_("unable to stat %s"), timestampdir); } else status = TS_MISSING; @@ -267,7 +267,7 @@ timestamp_status_internal(bool removing) if (status == TS_MISSING && *timestampfile && !removing) { if (mkdir(timestampdir, S_IRWXU) == -1) { status = TS_ERROR; - log_error(USE_ERRNO, _("unable to mkdir %s"), timestampdir); + log_error(USE_ERRNO, N_("unable to mkdir %s"), timestampdir); } } @@ -282,19 +282,19 @@ timestamp_status_internal(bool removing) if (lstat(timestampfile, &sb) == 0) { if (!S_ISREG(sb.st_mode)) { status = TS_ERROR; - log_error(0, _("%s exists but is not a regular file (0%o)"), + log_error(0, N_("%s exists but is not a regular file (0%o)"), timestampfile, (unsigned int) sb.st_mode); } else { /* If bad uid or file mode, complain and kill the bogus file. */ if (sb.st_uid != timestamp_uid) { log_error(0, - _("%s owned by uid %u, should be uid %u"), + N_("%s owned by uid %u, should be uid %u"), timestampfile, (unsigned int) sb.st_uid, (unsigned int) timestamp_uid); (void) unlink(timestampfile); } else if ((sb.st_mode & 0000022)) { log_error(0, - _("%s writable by non-owner (0%o), should be mode 0600"), + N_("%s writable by non-owner (0%o), should be mode 0600"), timestampfile, (unsigned int) sb.st_mode); (void) unlink(timestampfile); } else { @@ -324,7 +324,7 @@ timestamp_status_internal(bool removing) } } } else if (errno != ENOENT) { - log_error(USE_ERRNO, _("unable to stat %s"), timestampfile); + log_error(USE_ERRNO, N_("unable to stat %s"), timestampfile); status = TS_ERROR; } } @@ -348,7 +348,7 @@ timestamp_status_internal(bool removing) if (mtime.tv_sec > now + 60 * def_timestamp_timeout * 2) { time_t tv_sec = (time_t)mtime.tv_sec; log_error(0, - _("timestamp too far in the future: %20.20s"), + N_("timestamp too far in the future: %20.20s"), 4 + ctime(&tv_sec)); if (*timestampfile) (void) unlink(timestampfile); @@ -400,7 +400,7 @@ remove_timestamp(bool remove) status = rmdir(timestampdir); if (status == -1 && errno != ENOENT) { log_error(0, - _("unable to remove %s (%s), will reset to the epoch"), + N_("unable to remove %s (%s), will reset to the epoch"), path, strerror(errno)); remove = false; } -- 2.40.0