summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
authorStefan Schubert <schubi@suse.de>2022-11-16 18:37:14 +0100
committerThorsten Kukuk <5908016+thkukuk@users.noreply.github.com>2022-12-12 10:15:12 +0100
commitd71de05146d03c271bd5507724d24d1ad17c2be5 (patch)
treee536e38bf8809dbe89c6d4a4532a1e0b41032cd1 /modules
parente4917734c63ef6e887b3c4760771a14f75b9eb1f (diff)
downloadlinux-pam-git-d71de05146d03c271bd5507724d24d1ad17c2be5.tar.gz
pam_shells: Use the vendor directory as fallback for a distribution provided default config if there is no one in /etc.
If pam will be compiled with the option --enable-vendordir=<vendor_dir> and NOT defined --disable-econf, the files which define valid login shells will be parsed in following order: - <vendor_dir>/shells - <vendor_dir>/shells.d/* - /etc/shells.d/shells But all files in <vendor_dir> will be ingnored if the user has defined his own file /etc/shells. This commit solves issue: https://github.com/linux-pam/linux-pam/issues/498
Diffstat (limited to 'modules')
-rw-r--r--modules/pam_shells/Makefile.am4
-rw-r--r--modules/pam_shells/pam_shells.8.xml12
-rw-r--r--modules/pam_shells/pam_shells.c73
3 files changed, 75 insertions, 14 deletions
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;