]> granicus.if.org Git - sudo/commitdiff
Add simple locale switching to make it easy to switch from the
authorTodd C. Miller <Todd.Miller@courtesan.com>
Thu, 8 Nov 2012 20:37:43 +0000 (15:37 -0500)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Thu, 8 Nov 2012 20:37:43 +0000 (15:37 -0500)
user's locale to the sudoers locale without making excessive
setlocale() calls when we don't need to.

MANIFEST
plugins/sudoers/Makefile.in
plugins/sudoers/env.c
plugins/sudoers/locale.c [new file with mode: 0644]
plugins/sudoers/logging.h
plugins/sudoers/sudoers.c
plugins/sudoers/sudoers.h

index f2df424220b25e842b51b014757930102292a332..e9bbaa8f9853bac9100a5cd2904497fd5aee9363 100644 (file)
--- 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
index e0102b8abf3af5c29fc6b951c3042b9adee8fe2f..dd9bcd1bab27f1d693f367d515748d38478fd222 100644 (file)
@@ -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 \
index bf974ce070b164b13e12bc5ed968a3b187316a6f..3307366e24fb5a2e0a8800a722b395ab4b0f5045 100644 (file)
@@ -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 (file)
index 0000000..771b963
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2012 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * 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 <config.h>
+
+#include <sys/types.h>
+#include <stdio.h>
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif /* STDC_HEADERS */
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_SETLOCALE
+# include <locale.h>
+#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 */
index 81b73c0c4faf048f44866283886e4b0f1c2fd89b..bed13f252bab133c24ff0c82a2088cb8f2c77614 100644 (file)
 #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 */
index a112f0f5c3273bd3f5bce11529b4595d9658eb86..0f3ce0fe1590e984a8eebbc92a7875fba02b8e6e 100644 (file)
@@ -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) {
index eeb257c43cdddeba139fb8889f066ef5fb1f4ff2..1261b8af762276e17d9754085bd87d629958d157 100644 (file)
@@ -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)