From a24d86b32cec6157a0ed13aaca39ccfab855c4f3 Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Thu, 8 Dec 2011 17:17:25 -0500 Subject: [PATCH] When running a login shell with a login_class specified, use LOGIN_SETENV instead of rolling our own login.conf setenv support since FreeBSD's login.conf has more than just setenv capabilities. This requires us to swap the plugin-provided envp for the global environ before calling setusercontext() and then stash the resulting environ pointer back into the command details, which is kind of a hack. --- MANIFEST | 1 - configure | 1 - configure.in | 1 - mkdep.pl | 2 +- plugins/sudoers/Makefile.in | 9 -- plugins/sudoers/env.c | 3 +- plugins/sudoers/login_class.c | 227 ---------------------------------- plugins/sudoers/sudoers.c | 13 +- plugins/sudoers/sudoers.h | 5 - src/sudo.c | 25 +++- 10 files changed, 27 insertions(+), 260 deletions(-) delete mode 100644 plugins/sudoers/login_class.c diff --git a/MANIFEST b/MANIFEST index 7f2ff00d7..e3d6f352a 100644 --- a/MANIFEST +++ b/MANIFEST @@ -179,7 +179,6 @@ plugins/sudoers/linux_audit.c plugins/sudoers/linux_audit.h plugins/sudoers/logging.c plugins/sudoers/logging.h -plugins/sudoers/login_class.c plugins/sudoers/logwrap.c plugins/sudoers/match.c plugins/sudoers/match_addr.c diff --git a/configure b/configure index 7561536ea..718013fdf 100755 --- a/configure +++ b/configure @@ -15445,7 +15445,6 @@ _ACEOF SUDOERS_LIBS="${SUDOERS_LIBS} -lutil" ;; esac - SUDOERS_OBJS="${SUDOERS_OBJS} login_class.lo" fi diff --git a/configure.in b/configure.in index 57374bbca..86512b3d0 100644 --- a/configure.in +++ b/configure.in @@ -1990,7 +1990,6 @@ if test ${with_logincap-'no'} != "no"; then SUDOERS_LIBS="${SUDOERS_LIBS} -lutil" ;; esac - SUDOERS_OBJS="${SUDOERS_OBJS} login_class.lo" ]) fi if test ${with_project-'no'} != "no"; then diff --git a/mkdep.pl b/mkdep.pl index abf46f519..55006ba99 100755 --- a/mkdep.pl +++ b/mkdep.pl @@ -52,7 +52,7 @@ sub mkdep { $makefile =~ s:\@DEV\@::g; $makefile =~ s:\@COMMON_OBJS\@:aix.lo:; $makefile =~ s:\@SUDO_OBJS\@:preload.o selinux.o sesh.o sudo_noexec.lo:; - $makefile =~ s:\@SUDOERS_OBJS\@:bsm_audit.lo linux_audit.lo ldap.lo plugin_error.lo login_class.lo:; + $makefile =~ s:\@SUDOERS_OBJS\@:bsm_audit.lo linux_audit.lo ldap.lo plugin_error.lo:; # XXX - fill in AUTH_OBJS from contents of the auth dir instead $makefile =~ s:\@AUTH_OBJS\@:afs.lo aix_auth.lo bsdauth.lo dce.lo fwtk.lo getspwuid.lo kerb5.lo pam.lo passwd.lo rfc1938.lo secureware.lo securid5.lo sia.lo:; $makefile =~ s:\@LTLIBOBJS\@:closefrom.lo dlopen.lo fnmatch.lo getcwd.lo getgrouplist.lo getline.lo getprogname.lo glob.lo isblank.lo memrchr.lo mksiglist.lo mktemp.lo nanosleep.lo setenv.lo siglist.lo snprintf.lo strlcat.lo strlcpy.lo strsignal.lo unsetenv.lo utimes.lo globtest.o fnm_test.o:; diff --git a/plugins/sudoers/Makefile.in b/plugins/sudoers/Makefile.in index 7438586a8..3881a6143 100644 --- a/plugins/sudoers/Makefile.in +++ b/plugins/sudoers/Makefile.in @@ -579,15 +579,6 @@ logging.lo: $(srcdir)/logging.c $(top_builddir)/config.h $(srcdir)/sudoers.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) $(DEFS) $(srcdir)/logging.c -login_class.lo: $(srcdir)/login_class.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) $(DEFS) $(srcdir)/login_class.c logwrap.lo: $(srcdir)/logwrap.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 66bcd5e48..725212036 100644 --- a/plugins/sudoers/env.c +++ b/plugins/sudoers/env.c @@ -98,6 +98,7 @@ struct environment { /* * Prototypes */ +static void sudo_setenv(const char *, const char *, int); static void sudo_putenv(char *, int, int); /* @@ -239,7 +240,7 @@ env_get(void) * (not environ) and it always overwrites. The dupcheck param determines * whether we need to verify that the variable is not already set. */ -void +static void sudo_setenv(const char *var, const char *val, int dupcheck) { char *estring; diff --git a/plugins/sudoers/login_class.c b/plugins/sudoers/login_class.c deleted file mode 100644 index 34270d521..000000000 --- a/plugins/sudoers/login_class.c +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright (c) 2004, 2011 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_STRING_H */ -#ifdef HAVE_UNISTD_H -# include -#endif /* HAVE_UNISTD_H */ -#include - -#include - -#include "sudoers.h" - -/* - * Check whether or not a tilde in a string should be expanded. - * We only do expansion for things like "~", "~/...", ~me", "~me/...". - */ -#define tilde_valid(s, u, l) \ - ((s)[1] == '/' || (s)[1] == '\0' || \ - (strncmp((s)+1, u, l) == 0 && ((s)[l+1] == '/' || (s)[l+1] == '\0'))) - -/* - * Make a copy of a string, expanding '~' to the user's homedir, '$' to the - * login name and other escape sequences as per cgetstr(3). - */ -static char * -expandstr(const char *ostr, const struct passwd *pwd) -{ - size_t n, olen, nlen, ulen, dlen; - const char *ep, *eo, *op; - char *nstr, *np; - int ch; - - /* calculate the size of the new string */ - ulen = strlen(pwd->pw_name); - dlen = strlen(pwd->pw_dir); - olen = nlen = strlen(ostr); - for (op = ostr, ep = ostr + olen; op < ep; op++) { - switch (*op) { - case '~': - if (!tilde_valid(op, pwd->pw_name, ulen)) - break; - if (op[1] != '/' && op[1] != '\0') { - op += ulen; /* ~username */ - nlen = nlen - ulen - 1 + dlen; - } else - nlen += dlen - 1; - break; - case '$': - nlen += ulen - 1; - break; - case '^': - /* control char */ - if (*++op != '\0') - nlen--; - break; - case '\\': - if (op[1] == '\0') - break; - /* - * Byte in octal notation (\123) or an escaped char (\t) - */ - eo = op + 4; - do { - op++; - nlen--; - } while (op < eo && *op >= '0' && *op <= '7'); - break; - } - } - np = nstr = emalloc(++nlen); - - for (op = ostr, ep = ostr + olen; op < ep; op++) { - switch ((ch = *op)) { - case '~': - if (!tilde_valid(op, pwd->pw_name, ulen)) - break; - if (op[1] != '/' && op[1] != '\0') - op += ulen; /* ~username */ - strlcpy(np, pwd->pw_dir, nlen); - nlen -= dlen; - np += dlen; - continue; - case '$': - strlcpy(np, pwd->pw_name, nlen); - nlen -= ulen; - np += ulen; - continue; - case '^': - if (op[1] != '\0') - ch = *++op & 037; - break; - case '\\': - if (op[1] == '\0') - break; - switch(*++op) { - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - /* byte in octal up to 3 digits long */ - ch = 0; - n = 3; - do { - ch = ch * 8 + (*op++ - '0'); - } while (--n && *op >= '0' && *op <= '7'); - break; - case 'b': case 'B': - ch = '\b'; - break; - case 't': case 'T': - ch = '\t'; - break; - case 'n': case 'N': - ch = '\n'; - break; - case 'f': case 'F': - ch = '\f'; - break; - case 'r': case 'R': - ch = '\r'; - break; - case 'e': case 'E': - ch = '\033'; - break; - case 'c': case 'C': - ch = ':'; - break; - default: - ch = *op; - break; - } - break; - } - *np++ = ch; - nlen--; - } - *np = '\0'; - return (nstr); -} - -/* - * Set an environment variable, substituting for ~ and $ - */ -static void -login_setenv(char *name, char *ovalue, const struct passwd *pwd) -{ - char *value = NULL; - - if (*ovalue != '\0') - value = expandstr(ovalue, pwd); - sudo_setenv(name, value ? value : ovalue, 1); - efree(value); -} - -/* - * Look up "setenv" for this user in login.conf and set the comma-separated - * list of environment variables, expanding '~' and '$'. - */ -int -sudo_login_setenv(login_cap_t *lc, const struct passwd *pwd) -{ - char *beg, *end, *ep, *list, *value; - int len; - - if (lc == NULL || lc->lc_cap == NULL) - return (-1); /* impossible */ - - if ((len = cgetustr(lc->lc_cap, "setenv", &list)) <= 0) - return (0); - - for (beg = end = list, ep = list + len + 1; end < ep; end++) { - switch (*end) { - case '\\': - if (*(end + 1) == ',') - end++; /* skip escaped comma */ - continue; - case ',': - case '\0': - *end = '\0'; - if (beg == end) { - beg++; - continue; - } - break; - default: - continue; - } - - if ((value = strchr(beg, '=')) != NULL) - *value++ = '\0'; - else - value = ""; - login_setenv(beg, value, pwd); - beg = end + 1; - } - efree(list); - return (0); -} diff --git a/plugins/sudoers/sudoers.c b/plugins/sudoers/sudoers.c index 6d64ac613..3dd6b856b 100644 --- a/plugins/sudoers/sudoers.c +++ b/plugins/sudoers/sudoers.c @@ -127,9 +127,6 @@ static char *runas_group; static struct sudo_nss_list *snl; static const char *interfaces_string; static sigaction_t saved_sa_int, saved_sa_quit, saved_sa_tstp; -#ifdef HAVE_LOGIN_CAP_H -static login_cap_t *lc; -#endif /* XXX - must be extern for audit bits of sudo_auth.c */ int NewArgc; @@ -595,16 +592,8 @@ sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[], #if defined(__linux__) || defined(_AIX) /* Insert system-wide environment variables. */ read_env_file(_PATH_ENVIRONMENT, true); -#elif defined(HAVE_LOGIN_CAP_H) - /* Insert login class-specific environment variables. */ - if (lc != NULL) - sudo_login_setenv(lc, runas_pw); #endif } -#ifdef HAVE_LOGIN_CAP_H - login_close(lc); - lc = NULL; -#endif /* Insert system-wide environment variables. */ if (def_env_file) @@ -1015,6 +1004,7 @@ static void set_loginclass(struct passwd *pw) { int errflags; + login_cap_t *lc; debug_decl(set_loginclass, SUDO_DEBUG_PLUGIN) if (!def_use_loginclass) @@ -1047,6 +1037,7 @@ set_loginclass(struct passwd *pw) log_error(errflags, _("unknown login class: %s"), login_class); def_use_loginclass = false; } + login_close(lc); debug_return; } #else diff --git a/plugins/sudoers/sudoers.h b/plugins/sudoers/sudoers.h index 6c7878b28..1d4f3e9d4 100644 --- a/plugins/sudoers/sudoers.h +++ b/plugins/sudoers/sudoers.h @@ -197,7 +197,6 @@ struct lbuf; struct passwd; struct stat; struct timeval; -struct login_cap; /* * Function prototypes @@ -306,7 +305,6 @@ void init_envtables(void); void insert_env_vars(char * const envp[]); void read_env_file(const char *, int); void rebuild_env(void); -void sudo_setenv(const char *var, const char *val, int dupcheck); void validate_env_vars(char * const envp[]); /* fmt_string.c */ @@ -330,9 +328,6 @@ int group_plugin_query(const char *user, const char *group, /* setgroups.c */ int sudo_setgroups(int ngids, const GETGROUPS_T *gids); -/* login_cap.c */ -int sudo_login_setenv(struct login_cap *lc, const struct passwd *pwd); - #ifndef _SUDO_MAIN extern struct sudo_user sudo_user; extern struct passwd *list_pw; diff --git a/src/sudo.c b/src/sudo.c index b0b81d5b0..e7924cdba 100644 --- a/src/sudo.c +++ b/src/sudo.c @@ -103,6 +103,7 @@ struct plugin_container_list io_plugins; struct user_details user_details; const char *list_user, *runas_user, *runas_group; /* extern for parse_args.c */ int debug_level; +static int sudo_mode; /* * Local functions @@ -153,10 +154,14 @@ static struct rlimit corelimit; static struct rlimit nproclimit; #endif +#ifdef HAVE_LOGIN_CAP_H +extern char **environ; +#endif + int main(int argc, char *argv[], char *envp[]) { - int nargc, ok, sudo_mode, exitcode = 0; + int nargc, ok, exitcode = 0; char **nargv, **settings, **env_add; char **user_info, **command_info, **argv_out, **user_env_out; struct plugin_container *plugin, *next; @@ -951,7 +956,8 @@ exec_setup(struct command_details *details, const char *ptyname, int ptyfd) login_cap_t *lc; /* - * We only use setusercontext() to set the nice value and rlimits. + * We only use setusercontext() to set the nice value and rlimits + * unless this is a login shell (sudo -i). */ lc = login_getclass((char *)details->login_class); if (!lc) { @@ -959,7 +965,16 @@ exec_setup(struct command_details *details, const char *ptyname, int ptyfd) errno = ENOENT; goto done; } - flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY; + if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) { + /* Set everything except user, group and login name. */ + flags = LOGIN_SETALL; + CLR(flags, LOGIN_SETGROUP|LOGIN_SETLOGIN|LOGIN_SETUSER); + CLR(details->flags, CD_SET_UMASK); /* LOGIN_UMASK instead */ + /* Swap in the plugin-supplied environment for LOGIN_SETENV */ + environ = details->envp; + } else { + flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY; + } if (setusercontext(lc, pw, pw->pw_uid, flags)) { if (pw->pw_uid != ROOT_UID) { warning(_("unable to set user context")); @@ -967,6 +982,10 @@ exec_setup(struct command_details *details, const char *ptyname, int ptyfd) } else warning(_("unable to set user context")); } + if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) { + /* Stash the updated environment pointer in command details */ + details->envp = environ; + } } #endif /* HAVE_LOGIN_CAP_H */ } -- 2.40.0