From a27d5c51f1f34b0c3d965482de400447c072de96 Mon Sep 17 00:00:00 2001 From: Stefan Schubert Date: Mon, 28 Nov 2022 17:18:09 +0100 Subject: [PATCH] Supporting vendor given -shells- configuration file --- configure.ac | 6 +++++ man/chsh.1.xml | 45 +++++++++++++++++++++++++++++-- man/generate_mans.mak | 10 +++++-- man/shadow-man.xsl | 9 +++++++ src/Makefile.am | 3 ++- src/chsh.c | 63 +++++++++++++++++++++++++++++++++++++++---- 6 files changed, 126 insertions(+), 10 deletions(-) create mode 100644 man/shadow-man.xsl diff --git a/configure.ac b/configure.ac index 7acc3352..c89acb8d 100644 --- a/configure.ac +++ b/configure.ac @@ -317,6 +317,8 @@ AC_SEARCH_LIBS(gethostbyname, nsl) AC_CHECK_LIB([econf],[econf_readDirs],[LIBECONF="-leconf"],[LIBECONF=""]) if test -n "$LIBECONF"; then + AC_DEFINE_UNQUOTED([VENDORDIR], ["$enable_vendordir"], + [Directory for distribution provided configuration files]) ECONF_CPPFLAGS="-DUSE_ECONF=1" AC_ARG_ENABLE([vendordir], AS_HELP_STRING([--enable-vendordir=DIR], [Directory for distribution provided configuration files]),,[]) @@ -324,6 +326,9 @@ fi AC_SUBST(ECONF_CPPFLAGS) AC_SUBST(LIBECONF) AC_SUBST([VENDORDIR], [$enable_vendordir]) +if test "x$enable_vendordir" != x; then + AC_DEFINE(HAVE_VENDORDIR, 1, [Define to support vendor settings.]) +fi AM_CONDITIONAL([HAVE_VENDORDIR], [test "x$enable_vendordir" != x]) if test "$enable_shadowgrp" = "yes"; then @@ -740,4 +745,5 @@ echo " sssd support: $with_sssd" echo " subordinate IDs support: $enable_subids" echo " use file caps: $with_fcaps" echo " install su: $with_su" +echo " enabled vendor dir: $enable_vendordir" echo diff --git a/man/chsh.1.xml b/man/chsh.1.xml index 373aa928..db2d0ceb 100644 --- a/man/chsh.1.xml +++ b/man/chsh.1.xml @@ -115,7 +115,7 @@ NOTE - + The only restriction placed on the login shell is that the command name must be listed in /etc/shells, unless the invoker is the superuser, and then any value may be added. An @@ -125,6 +125,25 @@ changing to a restricted shell would prevent the user from ever changing her login shell back to its original value. + + The only restriction placed on the login shell is that the command + name must be listed in /etc/shells. + If this file does not exist, the definitions are taken from the files + %vendordir%/shells, + %vendordir%/shells.d/* and + /etc/shells.d/* in that order. + If /etc/shells.d/@filename@ exists, then + %vendordir%/shells.d/@filename@ will not be used. + If the invoker is the superuser any value may be added regardless what is + defined in the configuration files. + An account with a restricted login shell may not change her login shell. + + + For this reason, placing /bin/rsh in + /etc/shells is discouraged since accidentally + changing to a restricted shell would prevent the user from ever + changing her login shell back to its original value. + @@ -151,9 +170,31 @@ /etc/shells - + List of valid login shells. + + User defined list of valid login shells. + + + + %vendordir%/shells + + Default configuration file if + /etc/shells does not exist. + + + + %vendordir%/shells.d + + Directory for additional vendor specific configuration files. + + + + /etc/shells.d + + Directory for additional user defined configuration files. + /etc/login.defs diff --git a/man/generate_mans.mak b/man/generate_mans.mak index a0721b85..7cadaa0d 100644 --- a/man/generate_mans.mak +++ b/man/generate_mans.mak @@ -1,3 +1,8 @@ +if HAVE_VENDORDIR +VENDORDIR_COND=with_vendordir +else +VENDORDIR_COND=without_vendordir +endif if USE_PAM PAM_COND=pam else @@ -35,11 +40,12 @@ if ENABLE_REGENERATE_MAN fi man1/% man3/% man5/% man8/%: %.xml-config Makefile config.xml - $(XSLTPROC) --stringparam profile.condition "$(PAM_COND);$(SHADOWGRP_COND);$(TCB_COND);$(SHA_CRYPT_COND);$(SUBIDS_COND)" \ + $(XSLTPROC) --stringparam profile.condition "$(PAM_COND);$(SHADOWGRP_COND);$(TCB_COND);$(SHA_CRYPT_COND);$(SUBIDS_COND);$(VENDORDIR_COND)" \ --param "man.authors.section.enabled" "0" \ --stringparam "man.output.base.dir" "" \ + --stringparam vendordir "$(VENDORDIR)" \ --param "man.output.in.separate.dir" "1" \ - -nonet http://docbook.sourceforge.net/release/xsl/current/manpages/profile-docbook.xsl $< + -nonet $(top_builddir)/man/shadow-man.xsl $< clean-local: rm -rf man1 man3 man5 man8 diff --git a/man/shadow-man.xsl b/man/shadow-man.xsl new file mode 100644 index 00000000..a3408e6c --- /dev/null +++ b/man/shadow-man.xsl @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/Makefile.am b/src/Makefile.am index d86a3758..f9ca47f1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -11,7 +11,8 @@ AM_CPPFLAGS = \ -I${top_srcdir}/lib \ -I$(top_srcdir)/libmisc \ -I$(top_srcdir) \ - -DLOCALEDIR=\"$(datadir)/locale\" + -DLOCALEDIR=\"$(datadir)/locale\" \ + $(ECONF_CPPFLAGS) AM_CFLAGS = $(LIBBSD_CFLAGS) diff --git a/src/chsh.c b/src/chsh.c index 21d1c3ef..fe0f4609 100644 --- a/src/chsh.c +++ b/src/chsh.c @@ -33,6 +33,13 @@ #ifndef SHELLS_FILE #define SHELLS_FILE "/etc/shells" #endif + +#ifdef HAVE_VENDORDIR +#include +#define SHELLS "shells" +#define ETCDIR "/etc" +#endif + /* * Global variables */ @@ -127,17 +134,59 @@ static bool is_restricted_shell (const char *sh) * If getusershell() is available (Linux, *BSD, possibly others), use it * instead of re-implementing it. */ + +#ifdef HAVE_VENDORDIR static bool shell_is_listed (const char *sh) { - char *cp; bool found = false; -#ifndef HAVE_GETUSERSHELL - char buf[BUFSIZ]; - FILE *fp; -#endif + size_t size = 0; + econf_err error; + char **keys; + econf_file *key_file; + + error = econf_readDirs(&key_file, + VENDORDIR, + ETCDIR, + SHELLS, + NULL, + "", /* key only */ + "#" /* comment */); + if (error) { + fprintf (stderr, + _("Cannot parse shell files: %s"), + econf_errString(error)); + fail_exit (1); + } + + error = econf_getKeys(key_file, NULL, &size, &keys); + if (error) { + fprintf (stderr, + _("Cannot evaluate entries in shell files: %s"), + econf_errString(error)); + econf_free (key_file); + fail_exit (1); + } + + for (size_t i = 0; i < size; i++) { + if (strcmp (keys[i], sh) == 0) { + found = true; + break; + } + } + econf_free (key_file); + + return found; +} + +#else /* without HAVE_VENDORDIR */ + +static bool shell_is_listed (const char *sh) +{ + bool found = false; #ifdef HAVE_GETUSERSHELL + char *cp; setusershell (); while ((cp = getusershell ())) { if (strcmp (cp, sh) == 0) { @@ -147,6 +196,9 @@ static bool shell_is_listed (const char *sh) } endusershell (); #else + char buf[BUFSIZ]; + FILE *fp; + fp = fopen (SHELLS_FILE, "r"); if (NULL == fp) { return false; @@ -171,6 +223,7 @@ static bool shell_is_listed (const char *sh) #endif return found; } +#endif /* with HAVE_VENDORDIR */ /* * process_flags - parse the command line options