]> git.ipfire.org Git - thirdparty/shadow.git/commitdiff
Supporting vendor given -shells- configuration file
authorStefan Schubert <schubi@suse.de>
Mon, 28 Nov 2022 16:18:09 +0000 (17:18 +0100)
committerSerge Hallyn <serge@hallyn.com>
Fri, 27 Jan 2023 04:45:32 +0000 (22:45 -0600)
configure.ac
man/chsh.1.xml
man/generate_mans.mak
man/shadow-man.xsl [new file with mode: 0644]
src/Makefile.am
src/chsh.c

index 7acc335268584dc27b095c3f29007b1f842ec9a1..c89acb8de69a245d76f391f85f5a8fa2f6867b04 100644 (file)
@@ -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
index 373aa92819fbaede3bf573109030d77df442f51e..db2d0cebafe3a75092b3697e41326ee413bb2120 100644 (file)
 
   <refsect1 id='note'>
     <title>NOTE</title>
-    <para>
+    <para condition="without_vendordir">
       The only restriction placed on the login shell is that the command
       name must be listed in <filename>/etc/shells</filename>, unless the
       invoker is the superuser, and then any value may be added. An
       changing to a restricted shell would prevent the user from ever
       changing her login shell back to its original value.
     </para>
+    <para condition="with_vendordir">
+      The only restriction placed on the login shell is that the command
+      name must be listed in <filename>/etc/shells</filename>.
+      If this file does not exist, the definitions are taken from the files
+      <filename>%vendordir%/shells</filename>,
+      <filename>%vendordir%/shells.d/*</filename> and
+      <filename>/etc/shells.d/*</filename> in that order.
+      If <filename>/etc/shells.d/@filename@</filename> exists, then
+      <filename>%vendordir%/shells.d/@filename@</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.
+    </para>
+    <para>
+      For this reason, placing <filename>/bin/rsh</filename> in
+      <filename>/etc/shells</filename> is discouraged since accidentally
+      changing to a restricted shell would prevent the user from ever
+      changing her login shell back to its original value.
+    </para>
   </refsect1>
 
   <refsect1 id='configuration' condition="no_pam">
       </varlistentry>
       <varlistentry>
        <term><filename>/etc/shells</filename></term>
-       <listitem>
+       <listitem condition="without_vendordir">
          <para>List of valid login shells.</para>
        </listitem>
+       <listitem condition="with_vendordir">
+         <para>User defined list of valid login shells.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry condition="with_vendordir">
+       <term><filename>%vendordir%/shells</filename></term>
+        <listitem>
+          <para>Default configuration file if
+         <filename>/etc/shells</filename> does not exist.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry condition="with_vendordir">
+        <term><filename>%vendordir%/shells.d</filename></term>
+        <listitem>
+          <para>Directory for additional vendor specific configuration files.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry condition="with_vendordir">
+        <term><filename>/etc/shells.d</filename></term>
+        <listitem>
+          <para>Directory for additional user defined configuration files.</para>
+        </listitem>
       </varlistentry>
       <varlistentry>
        <term><filename>/etc/login.defs</filename></term>
index a0721b85113baf4a56301597aef84cbeb7963713..7cadaa0dbd36efe32b01fcb96471bcb91ee48727 100644 (file)
@@ -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 (file)
index 0000000..a3408e6
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version='1.0'?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ss="http://docbook.sf.net/xmlns/string.subst/1.0" version="1.0">
+  <xsl:import href="http://docbook.sourceforge.net/release/xsl/current/manpages/profile-docbook.xsl"/>
+  <xsl:param name="vendordir"/>
+
+  <xsl:param name="man.string.subst.map.local.pre">
+    <ss:substitution oldstring="%vendordir%" newstring="{$vendordir}" />
+  </xsl:param>
+</xsl:stylesheet>
index d86a37581f2f6cc27a7667485724db91411d2ae8..f9ca47f1b576f7c7a1f35bc299a193b09eb59d9b 100644 (file)
@@ -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)
 
index 21d1c3ef8803e1c71b9518838e24eb93b2199560..fe0f46090f55aedaea1332cb8b9802fbb6833b92 100644 (file)
 #ifndef SHELLS_FILE
 #define SHELLS_FILE "/etc/shells"
 #endif
+
+#ifdef HAVE_VENDORDIR
+#include <libeconf.h>
+#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