diff --git a/MANIFEST b/MANIFEST index f2df42422..e9bbaa8f9 100644 --- a/MANIFEST +++ b/MANIFEST @@ -184,6 +184,7 @@ plugins/sudoers/iolog_path.c plugins/sudoers/ldap.c plugins/sudoers/linux_audit.c plugins/sudoers/linux_audit.h +plugins/sudoers/locale.c plugins/sudoers/logging.c plugins/sudoers/logging.h plugins/sudoers/logwrap.c diff --git a/plugins/sudoers/Makefile.in b/plugins/sudoers/Makefile.in index e0102b8ab..dd9bcd1ba 100644 --- a/plugins/sudoers/Makefile.in +++ b/plugins/sudoers/Makefile.in @@ -129,8 +129,8 @@ LIBPARSESUDOERS_OBJS = alias.lo audit.lo defaults.lo gram.lo match.lo \ SUDOERS_OBJS = $(AUTH_OBJS) boottime.lo check.lo env.lo find_path.lo \ goodpath.lo group_plugin.lo interfaces.lo iolog.lo \ - iolog_path.lo logging.lo logwrap.lo parse.lo policy.lo \ - prompt.lo set_perms.lo sudo_nss.lo sudoers.lo \ + iolog_path.lo locale.lo logging.lo logwrap.lo parse.lo \ + policy.lo prompt.lo set_perms.lo sudo_nss.lo sudoers.lo \ timestamp.lo @SUDOERS_OBJS@ VISUDO_OBJS = visudo.o goodpath.o find_path.o error.o @@ -613,6 +613,13 @@ linux_audit.lo: $(srcdir)/linux_audit.c $(top_builddir)/config.h \ $(incdir)/gettext.h $(incdir)/sudo_debug.h \ $(srcdir)/linux_audit.h $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(DEFS) $(srcdir)/linux_audit.c +locale.lo: $(srcdir)/locale.c $(top_builddir)/config.h $(srcdir)/sudoers.h \ + $(top_srcdir)/compat/stdbool.h $(top_builddir)/pathnames.h \ + $(incdir)/missing.h $(incdir)/error.h $(incdir)/alloc.h \ + $(incdir)/list.h $(incdir)/fileops.h $(srcdir)/defaults.h \ + $(devdir)/def_data.h $(srcdir)/logging.h $(srcdir)/sudo_nss.h \ + $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h $(incdir)/gettext.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(DEFS) $(srcdir)/locale.c logging.lo: $(srcdir)/logging.c $(top_builddir)/config.h $(srcdir)/sudoers.h \ $(top_srcdir)/compat/stdbool.h $(top_builddir)/pathnames.h \ $(incdir)/missing.h $(incdir)/error.h $(incdir)/alloc.h \ diff --git a/plugins/sudoers/env.c b/plugins/sudoers/env.c index bf974ce07..3307366e2 100644 --- a/plugins/sudoers/env.c +++ b/plugins/sudoers/env.c @@ -1113,7 +1113,21 @@ sudoers_hook_getenv(const char *name, char **value, void *closure) return SUDO_HOOK_RET_NEXT; in_progress = true; + + /* Hack to make GNU gettext() find the sudoers locale when needed. */ + if (*name == 'L' && sudoers_getlocale() == SUDOERS_LOCALE_SUDOERS) { + if (strcmp(name, "LANGUAGE") == 0 || strcmp(name, "LANG") == 0) { + *value = NULL; + goto done; + } + if (strcmp(name, "LC_ALL") == 0 || strcmp(name, "LC_MESSAGES") == 0) { + *value = def_sudoers_locale; + goto done; + } + } + *value = sudo_getenv_nodebug(name); +done: in_progress = false; return SUDO_HOOK_RET_STOP; } diff --git a/plugins/sudoers/locale.c b/plugins/sudoers/locale.c new file mode 100644 index 000000000..771b963c7 --- /dev/null +++ b/plugins/sudoers/locale.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 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 + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif /* STDC_HEADERS */ +#ifdef HAVE_STRING_H +# include +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +# include +#endif /* HAVE_STRINGS_H */ +#ifdef HAVE_SETLOCALE +# include +#endif + +#include "sudoers.h" + +#ifdef HAVE_SETLOCALE + +static int current_locale = SUDOERS_LOCALE_USER; + +int +sudoers_setlocale(int newlocale, int *prevlocale) +{ + char *res = NULL; + + switch (newlocale) { + case SUDOERS_LOCALE_USER: + if (prevlocale) + *prevlocale = current_locale; + if (current_locale != SUDOERS_LOCALE_USER) { + current_locale = SUDOERS_LOCALE_USER; + res = setlocale(LC_ALL, user_locale ? user_locale : ""); + } + break; + case SUDOERS_LOCALE_SUDOERS: + if (prevlocale) + *prevlocale = current_locale; + if (current_locale != SUDOERS_LOCALE_SUDOERS) { + current_locale = SUDOERS_LOCALE_SUDOERS; + res = setlocale(LC_ALL, def_sudoers_locale); + if (res == NULL) { + if (strcmp(def_sudoers_locale, "C") != 0) { + efree(def_sudoers_locale); + def_sudoers_locale = estrdup("C"); + res = setlocale(LC_ALL, "C"); + } + } + } + break; + } + return res ? 1 : 0; +} +#else +int +sudoers_setlocale(int newlocale, int *prevlocale) +{ + return 1; +} +#endif /* HAVE_SETLOCALE */ diff --git a/plugins/sudoers/logging.h b/plugins/sudoers/logging.h index 81b73c0c4..bed13f252 100644 --- a/plugins/sudoers/logging.h +++ b/plugins/sudoers/logging.h @@ -30,6 +30,12 @@ #define SLOG_FILE 0x02 #define SLOG_BOTH 0x03 +/* + * Values for sudoers_setlocale() + */ +#define SUDOERS_LOCALE_USER 0 +#define SUDOERS_LOCALE_SUDOERS 1 + /* Flags for log_error()/log_fatal() */ #define MSG_ONLY 0x01 #define USE_ERRNO 0x02 @@ -61,5 +67,6 @@ void log_failure(int status, int flags); 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); #endif /* _LOGGING_H */ diff --git a/plugins/sudoers/sudoers.c b/plugins/sudoers/sudoers.c index a112f0f5c..0f3ce0fe1 100644 --- a/plugins/sudoers/sudoers.c +++ b/plugins/sudoers/sudoers.c @@ -563,6 +563,10 @@ init_vars(char * const envp[]) (void) tzset(); /* set the timezone if applicable */ #endif /* HAVE_TZSET */ +#ifdef HAVE_SETLOCALE + user_locale = estrdup(setlocale(LC_ALL, NULL)); +#endif + for (ep = envp; *ep; ep++) { /* XXX - don't fill in if empty string */ switch (**ep) { diff --git a/plugins/sudoers/sudoers.h b/plugins/sudoers/sudoers.h index eeb257c43..1261b8af7 100644 --- a/plugins/sudoers/sudoers.h +++ b/plugins/sudoers/sudoers.h @@ -87,6 +87,7 @@ struct sudo_user { #endif const char *cwd; char *iolog_file; + char *locale; GETGROUPS_T *gids; int ngids; int closefrom; @@ -180,6 +181,7 @@ struct sudo_user { #define user_tty (sudo_user.tty) #define user_ttypath (sudo_user.ttypath) #define user_cwd (sudo_user.cwd) +#define user_locale (sudo_user.locale) #define user_cmnd (sudo_user.cmnd) #define user_args (sudo_user.cmnd_args) #define user_base (sudo_user.cmnd_base)