Supporting vendor given -shells- configuration file

This commit is contained in:
Stefan Schubert 2022-11-28 17:18:09 +01:00 committed by Serge Hallyn
parent b2d202cb5d
commit a27d5c51f1
6 changed files with 126 additions and 10 deletions

View File

@ -317,6 +317,8 @@ AC_SEARCH_LIBS(gethostbyname, nsl)
AC_CHECK_LIB([econf],[econf_readDirs],[LIBECONF="-leconf"],[LIBECONF=""]) AC_CHECK_LIB([econf],[econf_readDirs],[LIBECONF="-leconf"],[LIBECONF=""])
if test -n "$LIBECONF"; then if test -n "$LIBECONF"; then
AC_DEFINE_UNQUOTED([VENDORDIR], ["$enable_vendordir"],
[Directory for distribution provided configuration files])
ECONF_CPPFLAGS="-DUSE_ECONF=1" ECONF_CPPFLAGS="-DUSE_ECONF=1"
AC_ARG_ENABLE([vendordir], AC_ARG_ENABLE([vendordir],
AS_HELP_STRING([--enable-vendordir=DIR], [Directory for distribution provided configuration files]),,[]) AS_HELP_STRING([--enable-vendordir=DIR], [Directory for distribution provided configuration files]),,[])
@ -324,6 +326,9 @@ fi
AC_SUBST(ECONF_CPPFLAGS) AC_SUBST(ECONF_CPPFLAGS)
AC_SUBST(LIBECONF) AC_SUBST(LIBECONF)
AC_SUBST([VENDORDIR], [$enable_vendordir]) 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]) AM_CONDITIONAL([HAVE_VENDORDIR], [test "x$enable_vendordir" != x])
if test "$enable_shadowgrp" = "yes"; then if test "$enable_shadowgrp" = "yes"; then
@ -740,4 +745,5 @@ echo " sssd support: $with_sssd"
echo " subordinate IDs support: $enable_subids" echo " subordinate IDs support: $enable_subids"
echo " use file caps: $with_fcaps" echo " use file caps: $with_fcaps"
echo " install su: $with_su" echo " install su: $with_su"
echo " enabled vendor dir: $enable_vendordir"
echo echo

View File

@ -115,7 +115,7 @@
<refsect1 id='note'> <refsect1 id='note'>
<title>NOTE</title> <title>NOTE</title>
<para> <para condition="without_vendordir">
The only restriction placed on the login shell is that the command The only restriction placed on the login shell is that the command
name must be listed in <filename>/etc/shells</filename>, unless the name must be listed in <filename>/etc/shells</filename>, unless the
invoker is the superuser, and then any value may be added. An 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 to a restricted shell would prevent the user from ever
changing her login shell back to its original value. changing her login shell back to its original value.
</para> </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>
<refsect1 id='configuration' condition="no_pam"> <refsect1 id='configuration' condition="no_pam">
@ -151,9 +170,31 @@
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term><filename>/etc/shells</filename></term> <term><filename>/etc/shells</filename></term>
<listitem> <listitem condition="without_vendordir">
<para>List of valid login shells.</para> <para>List of valid login shells.</para>
</listitem> </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>
<varlistentry> <varlistentry>
<term><filename>/etc/login.defs</filename></term> <term><filename>/etc/login.defs</filename></term>

View File

@ -1,3 +1,8 @@
if HAVE_VENDORDIR
VENDORDIR_COND=with_vendordir
else
VENDORDIR_COND=without_vendordir
endif
if USE_PAM if USE_PAM
PAM_COND=pam PAM_COND=pam
else else
@ -35,11 +40,12 @@ if ENABLE_REGENERATE_MAN
fi fi
man1/% man3/% man5/% man8/%: %.xml-config Makefile config.xml 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" \ --param "man.authors.section.enabled" "0" \
--stringparam "man.output.base.dir" "" \ --stringparam "man.output.base.dir" "" \
--stringparam vendordir "$(VENDORDIR)" \
--param "man.output.in.separate.dir" "1" \ --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: clean-local:
rm -rf man1 man3 man5 man8 rm -rf man1 man3 man5 man8

9
man/shadow-man.xsl Normal file
View File

@ -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>

View File

@ -11,7 +11,8 @@ AM_CPPFLAGS = \
-I${top_srcdir}/lib \ -I${top_srcdir}/lib \
-I$(top_srcdir)/libmisc \ -I$(top_srcdir)/libmisc \
-I$(top_srcdir) \ -I$(top_srcdir) \
-DLOCALEDIR=\"$(datadir)/locale\" -DLOCALEDIR=\"$(datadir)/locale\" \
$(ECONF_CPPFLAGS)
AM_CFLAGS = $(LIBBSD_CFLAGS) AM_CFLAGS = $(LIBBSD_CFLAGS)

View File

@ -33,6 +33,13 @@
#ifndef SHELLS_FILE #ifndef SHELLS_FILE
#define SHELLS_FILE "/etc/shells" #define SHELLS_FILE "/etc/shells"
#endif #endif
#ifdef HAVE_VENDORDIR
#include <libeconf.h>
#define SHELLS "shells"
#define ETCDIR "/etc"
#endif
/* /*
* Global variables * Global variables
*/ */
@ -127,17 +134,59 @@ static bool is_restricted_shell (const char *sh)
* If getusershell() is available (Linux, *BSD, possibly others), use it * If getusershell() is available (Linux, *BSD, possibly others), use it
* instead of re-implementing it. * instead of re-implementing it.
*/ */
#ifdef HAVE_VENDORDIR
static bool shell_is_listed (const char *sh) static bool shell_is_listed (const char *sh)
{ {
char *cp;
bool found = false; bool found = false;
#ifndef HAVE_GETUSERSHELL size_t size = 0;
char buf[BUFSIZ]; econf_err error;
FILE *fp; char **keys;
#endif 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 #ifdef HAVE_GETUSERSHELL
char *cp;
setusershell (); setusershell ();
while ((cp = getusershell ())) { while ((cp = getusershell ())) {
if (strcmp (cp, sh) == 0) { if (strcmp (cp, sh) == 0) {
@ -147,6 +196,9 @@ static bool shell_is_listed (const char *sh)
} }
endusershell (); endusershell ();
#else #else
char buf[BUFSIZ];
FILE *fp;
fp = fopen (SHELLS_FILE, "r"); fp = fopen (SHELLS_FILE, "r");
if (NULL == fp) { if (NULL == fp) {
return false; return false;
@ -171,6 +223,7 @@ static bool shell_is_listed (const char *sh)
#endif #endif
return found; return found;
} }
#endif /* with HAVE_VENDORDIR */
/* /*
* process_flags - parse the command line options * process_flags - parse the command line options