diff options
-rw-r--r-- | configure.ac | 9 | ||||
-rw-r--r-- | modules/pam_shells/Makefile.am | 4 | ||||
-rw-r--r-- | modules/pam_shells/pam_shells.8.xml | 12 | ||||
-rw-r--r-- | modules/pam_shells/pam_shells.c | 73 |
4 files changed, 81 insertions, 17 deletions
diff --git a/configure.ac b/configure.ac index 2f74d1b4..0892049e 100644 --- a/configure.ac +++ b/configure.ac @@ -520,8 +520,7 @@ AC_ARG_ENABLE([econf], AS_HELP_STRING([--disable-econf], [do not use libeconf]), [WITH_ECONF=$enableval], WITH_ECONF=yes) if test "$WITH_ECONF" = "yes" ; then - PKG_CHECK_MODULES([ECONF], [libeconf], [], - [AC_CHECK_LIB([econf],[econf_readDirs],[ECONF_LIBS="-leconf"],[ECONF_LIBS=""])]) + AC_CHECK_LIB([econf],[econf_readDirsWithCallback],[ECONF_LIBS="-leconf"],[ECONF_LIBS=""]) if test -n "$ECONF_LIBS" ; then ECONF_CFLAGS="-DUSE_ECONF=1 $ECONF_CFLAGS" fi @@ -535,7 +534,11 @@ if test -n "$enable_vendordir"; then [Directory for distribution provided configuration files]) AC_DEFINE_UNQUOTED([VENDOR_SCONFIGDIR], ["$enable_vendordir/security"], [Directory for PAM modules distribution provided configuration files]) - STRINGPARAM_VENDORDIR="--stringparam vendordir '$enable_vendordir' --stringparam profile.condition 'with_vendordir'" + if test "$WITH_ECONF" = "yes" ; then + STRINGPARAM_VENDORDIR="--stringparam vendordir '$enable_vendordir' --stringparam profile.condition 'with_vendordir;with_vendordir_and_with_econf'" + else + STRINGPARAM_VENDORDIR="--stringparam vendordir '$enable_vendordir' --stringparam profile.condition 'with_vendordir;with_vendordir_and_without_econf" + fi else STRINGPARAM_VENDORDIR="--stringparam profile.condition 'without_vendordir'" fi diff --git a/modules/pam_shells/Makefile.am b/modules/pam_shells/Makefile.am index b91bada5..3ce3e1d0 100644 --- a/modules/pam_shells/Makefile.am +++ b/modules/pam_shells/Makefile.am @@ -18,14 +18,14 @@ securelibdir = $(SECUREDIR) secureconfdir = $(SCONFIGDIR) AM_CFLAGS = -I$(top_srcdir)/libpam/include -I$(top_srcdir)/libpamc/include \ - $(WARN_CFLAGS) + $(WARN_CFLAGS) $(ECONF_CFLAGS) AM_LDFLAGS = -no-undefined -avoid-version -module if HAVE_VERSIONING AM_LDFLAGS += -Wl,--version-script=$(srcdir)/../modules.map endif securelib_LTLIBRARIES = pam_shells.la -pam_shells_la_LIBADD = $(top_builddir)/libpam/libpam.la +pam_shells_la_LIBADD = $(top_builddir)/libpam/libpam.la $(ECONF_LIBS) if ENABLE_REGENERATE_MAN dist_noinst_DATA = README diff --git a/modules/pam_shells/pam_shells.8.xml b/modules/pam_shells/pam_shells.8.xml index 15f47671..73b4855a 100644 --- a/modules/pam_shells/pam_shells.8.xml +++ b/modules/pam_shells/pam_shells.8.xml @@ -29,9 +29,17 @@ pam_shells is a PAM module that only allows access to the system if the user's shell is listed in <filename>/etc/shells</filename>. </para> + + <para condition="with_vendordir_and_with_econf"> + If this file does not exist, entries are taken from files + <filename>%vendordir%/shells</filename>, + <filename>%vendordir%/shells.d/*</filename> and + <filename>/etc/shells.d/*</filename> in that order. + </para> + <para> - It also checks if <filename>/etc/shells</filename> is a plain - file and not world writable. + It also checks if needed files (e.g. <filename>/etc/shells</filename>) are plain + files and not world writable. </para> </refsect1> diff --git a/modules/pam_shells/pam_shells.c b/modules/pam_shells/pam_shells.c index dc8f4878..abebdd0c 100644 --- a/modules/pam_shells/pam_shells.c +++ b/modules/pam_shells/pam_shells.c @@ -13,27 +13,47 @@ #include <string.h> #include <stdio.h> #include <stdlib.h> +#include <stdbool.h> #include <sys/stat.h> #include <syslog.h> #include <unistd.h> +#if defined (USE_ECONF) && defined (VENDORDIR) +#include <libeconf.h> +#endif #include <security/pam_modules.h> #include <security/pam_modutil.h> #include <security/pam_ext.h> #define SHELL_FILE "/etc/shells" - +#define SHELLS "shells" +#define ETCDIR "/etc" #define DEFAULT_SHELL "/bin/sh" +static bool check_file(const char *filename, const void *pamh) +{ + struct stat sb; + + if (stat(filename, &sb)) { + pam_syslog(pamh, LOG_ERR, "Cannot stat %s: %m", filename); + return false; /* must have /etc/shells */ + } + + if ((sb.st_mode & S_IWOTH) || !S_ISREG(sb.st_mode)) { + pam_syslog(pamh, LOG_ERR, + "%s is either world writable or not a normal file", + filename); + return false; + } + return true; +} + static int perform_check(pam_handle_t *pamh) { int retval = PAM_AUTH_ERR; const char *userName; const char *userShell; - char shellFileLine[256]; - struct stat sb; struct passwd * pw; - FILE * shellFile; retval = pam_get_user(pamh, &userName, NULL); if (retval != PAM_SUCCESS) { @@ -48,18 +68,50 @@ static int perform_check(pam_handle_t *pamh) if (userShell[0] == '\0') userShell = DEFAULT_SHELL; - if (stat(SHELL_FILE,&sb)) { - pam_syslog(pamh, LOG_ERR, "Cannot stat %s: %m", SHELL_FILE); - return PAM_AUTH_ERR; /* must have /etc/shells */ +#if defined (USE_ECONF) && defined (VENDORDIR) + size_t size = 0; + econf_err error; + char **keys; + econf_file *key_file; + + error = econf_readDirsWithCallback(&key_file, + VENDORDIR, + ETCDIR, + SHELLS, + NULL, + "", /* key only */ + "#", /* comment */ + check_file, pamh); + if (error) { + pam_syslog(pamh, LOG_ERR, + "Cannot parse shell files: %s", + econf_errString(error)); + return PAM_AUTH_ERR; } - if ((sb.st_mode & S_IWOTH) || !S_ISREG(sb.st_mode)) { + error = econf_getKeys(key_file, NULL, &size, &keys); + if (error) { pam_syslog(pamh, LOG_ERR, - "%s is either world writable or not a normal file", - SHELL_FILE); + "Cannot evaluate entries in shell files: %s", + econf_errString(error)); + econf_free (key_file); return PAM_AUTH_ERR; } + retval = 1; + for (size_t i = 0; i < size; i++) { + retval = strcmp(keys[i], userShell); + if (!retval) + break; + } + econf_free (key_file); +#else + char shellFileLine[256]; + FILE * shellFile; + + if (!check_file(SHELL_FILE, pamh)) + return PAM_AUTH_ERR; + shellFile = fopen(SHELL_FILE,"r"); if (shellFile == NULL) { /* Check that we opened it successfully */ pam_syslog(pamh, LOG_ERR, "Error opening %s: %m", SHELL_FILE); @@ -75,6 +127,7 @@ static int perform_check(pam_handle_t *pamh) } fclose(shellFile); + #endif if (retval) { return PAM_AUTH_ERR; |