]> granicus.if.org Git - linux-pam/commitdiff
Add support for a vendor directory and libeconf (#136)
authorThorsten Kukuk <5908016+thkukuk@users.noreply.github.com>
Mon, 16 Sep 2019 15:17:49 +0000 (17:17 +0200)
committerGitHub <noreply@github.com>
Mon, 16 Sep 2019 15:17:49 +0000 (17:17 +0200)
With this, it is possible for Linux distributors to store their
supplied default configuration files somewhere below /usr, while
/etc only contains the changes made by the user. The new option
--enable-vendordir defines where Linux-PAM should additional look
for pam.d/*, login.defs and securetty if this files are not in /etc.
libeconf is a key/value configuration file reading library, which
handles the split of configuration files in different locations
and merges them transparently for the application.

14 files changed:
Make.xml.rules
configure.ac
doc/Makefile.am
doc/custom-html.xsl [new file with mode: 0644]
doc/custom-man.xsl [new file with mode: 0644]
doc/man/Makefile.am
doc/man/pam.8.xml
libpam/Makefile.am
libpam/pam_handlers.c
libpam/pam_modutil_searchkey.c
libpam/pam_private.h
modules/pam_securetty/Makefile.am
modules/pam_securetty/pam_securetty.8.xml
modules/pam_securetty/pam_securetty.c

index bee30cda3f37f80ac95434e946fa86d3194f670a..d19a02ef349641230af306f22409d04f7694a270 100644 (file)
@@ -3,22 +3,22 @@
 #
 
 README: README.xml
-       $(XSLTPROC) --path $(srcdir) --xinclude --stringparam generate.toc "none" --nonet http://docbook.sourceforge.net/release/xsl/current/html/docbook.xsl $< | $(BROWSER) > $(srcdir)/$@
+       $(XSLTPROC) --path $(srcdir) --xinclude --stringparam generate.toc "none" $(XSLTPROC_CUSTOM) --nonet $(top_srcdir)/doc/custom-html.xsl $< | $(BROWSER) > $(srcdir)/$@
 
 %.1: %.1.xml
        $(XMLLINT) --nonet --xinclude --postvalid --noout $<
-       $(XSLTPROC) -o $(srcdir)/$@ --path $(srcdir) --xinclude --nonet http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $<
+       $(XSLTPROC) -o $(srcdir)/$@ --path $(srcdir) --xinclude $(XSLTPROC_CUSTOM) --nonet $(top_srcdir)/doc/custom-man.xsl $<
 
 %.3: %.3.xml
        $(XMLLINT) --nonet --xinclude --postvalid --noout $<
-       $(XSLTPROC) -o $(srcdir)/$@ --path $(srcdir) --xinclude --nonet http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $<
+       $(XSLTPROC) -o $(srcdir)/$@ --path $(srcdir) --xinclude $(XSLTPROC_CUSTOM) --nonet $(top_srcdir)/doc/custom-man.xsl $<
 
 %.5: %.5.xml
        $(XMLLINT) --nonet --xinclude --postvalid --noout $<
-       $(XSLTPROC) -o $(srcdir)/$@ --path $(srcdir) --xinclude --nonet http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $<
+       $(XSLTPROC) -o $(srcdir)/$@ --path $(srcdir) --xinclude $(XSLTPROC_CUSTOM) --nonet $(top_srcdir)/doc/custom-man.xsl $<
 
 %.8: %.8.xml
        $(XMLLINT) --nonet --xinclude --postvalid --noout $<
-       $(XSLTPROC) -o $(srcdir)/$@ --path $(srcdir) --xinclude --nonet http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $<
+       $(XSLTPROC) -o $(srcdir)/$@ --path $(srcdir) --xinclude $(XSLTPROC_CUSTOM) --nonet $(top_srcdir)/doc/custom-man.xsl $<
 
 #CLEANFILES += $(man_MANS) README
index e4995fc9499e1690c12891881681bc565d899ff2..62b98c73451d301386d252473618195d4b5ae80e 100644 (file)
@@ -504,6 +504,23 @@ if test ! -z "$LIBSELINUX" ; then
     LIBS=$BACKUP_LIBS
 fi
 
+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=""])])
+  if test -n "$ECONF_LIBS" ; then
+    ECONF_CFLAGS="-DUSE_ECONF=1 $ECONF_CFLAGS"
+  fi
+fi
+AC_SUBST([ECONF_CFLAGS])
+AC_SUBST([ECONF_LIBS])
+AC_ARG_ENABLE([vendordir],
+  AS_HELP_STRING([--enable-vendordir=DIR], [Directory for distribution provided configuration files]),,[])
+AC_SUBST([VENDORDIR], [$enable_vendordir])
+AM_CONDITIONAL([HAVE_VENDORDIR], [test "x$enable_vendordir" != x])
+
 dnl Checks for header files.
 AC_HEADER_DIRENT
 AC_HEADER_STDC
index f4762f2d01e400fc9114e2ebf131fe2bfb93d90f..38319f5be68b1ee4c00348cdba651852bc1c2ef3 100644 (file)
@@ -8,6 +8,8 @@ CLEANFILES = *~
 
 dist_html_DATA = index.html
 
+EXTRA_DIST = custom-html.xsl custom-man.xsl
+
 #######################################################
 
 releasedocs: all
diff --git a/doc/custom-html.xsl b/doc/custom-html.xsl
new file mode 100644 (file)
index 0000000..081beaf
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version='1.0'?> <!--*-nxml-*-->
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:ss="http://docbook.sf.net/xmlns/string.subst/1.0"
+  xmlns:exsl="http://exslt.org/common" version="1.0">
+
+  <xsl:import href="http://docbook.sourceforge.net/release/xsl/current/html/docbook.xsl"/>
+  <xsl:param name="vendordir"/>
+
+  <xsl:template match="filename">
+    <xsl:variable name="replacements">
+      <ss:substitution oldstring="%vendordir%" newstring="{$vendordir}" />
+    </xsl:variable>
+    <xsl:call-template name="apply-string-subst-map">
+      <xsl:with-param name="content" select="."/>
+      <xsl:with-param name="map.contents" select="exsl:node-set($replacements)/*" />
+    </xsl:call-template>
+  </xsl:template>
+</xsl:stylesheet>
+
diff --git a/doc/custom-man.xsl b/doc/custom-man.xsl
new file mode 100644 (file)
index 0000000..bf01d58
--- /dev/null
@@ -0,0 +1,10 @@
+<?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/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 78c891dfbcf1af2389f1dcd1f2e04d6998cc74a9..8e76897e0a02b4ac14eb97b3d19edc7353506a51 100644 (file)
@@ -59,5 +59,10 @@ pam.d.5: pam.conf.5
 pam_get_item.3: pam_item_types_std.inc.xml pam_item_types_ext.inc.xml
 pam_set_data.3: pam_item_types_std.inc.xml pam_item_types_ext.inc.xml
 pam.conf.5: pam.conf-desc.xml pam.conf-dir.xml pam.conf-syntax.xml
+if HAVE_VENDORDIR
+XSLTPROC_CUSTOM = --stringparam vendordir $(VENDORDIR)
+else
+XSLTPROC_CUSTOM = --stringparam vendordir "<vendordir>"
+endif
 -include $(top_srcdir)/Make.xml.rules
 endif
index 9839defb260eafa2b914cbbe60311a34bbfc660f..464af0e538d9203bfac4d95c636ed32d9e13e22f 100644 (file)
 
     <para>
       Vendor-supplied PAM configuration files might be installed in
-      the system directory <filename>/usr/lib/pam.d/</filename> instead
+      the system directory <filename>/usr/lib/pam.d/</filename> or
+      a configurable vendor specific directory instead
       of the machine configuration directory <filename>/etc/pam.d/</filename>.
       If no machine configuration file is found, the vendor-supplied file
       is used. All files in <filename>/etc/pam.d/</filename> override
-      files with the same name in <filename>/usr/lib/pam.d/</filename>.
+      files with the same name in other directories.
     </para>
 
 <para>From the point of view of the system administrator, for whom this
@@ -157,6 +158,18 @@ closing hook for modules to affect the services available to a user.</para>
           </para>
         </listitem>
       </varlistentry>
+      <varlistentry>
+        <term><filename>%vendordir%/pam.d</filename></term>
+        <listitem>
+          <para>
+            the <emphasis remap='B'>Linux-PAM</emphasis> vendor configuration
+           directory. Files in <filename>/etc/pam.d</filename> and
+           <filename>/usr/lib/pam.d</filename> override files with the same
+           name in this directory. Only available if Linux-PAM was compiled
+           with vendordir enabled.
+          </para>
+        </listitem>
+      </varlistentry>
     </variablelist>
   </refsect1>
 
index 875031ed4fe4f06cae43425eaf2b7e3a2a2a77b1..ba57b98ed561ba8f2616e9d9d07aaeeb840f1353 100644 (file)
@@ -3,10 +3,14 @@
 #
 
 AM_CFLAGS = -DDEFAULT_MODULE_PATH=\"$(SECUREDIR)/\" -DLIBPAM_COMPILE \
-       -I$(srcdir)/include $(LIBPRELUDE_CFLAGS) -DPAM_VERSION=\"$(VERSION)\"
+       -I$(srcdir)/include $(LIBPRELUDE_CFLAGS) $(ECONF_CFLAGS) \
+       -DPAM_VERSION=\"$(VERSION)\" -DSYSCONFDIR=\"$(sysconfdir)\"
 if HAVE_LIBSELINUX
   AM_CFLAGS += -D"WITH_SELINUX"
 endif
+if HAVE_VENDORDIR
+  AM_CFLAGS += -DVENDORDIR=\"$(VENDORDIR)\"
+endif
 
 CLEANFILES = *~
 
@@ -21,7 +25,7 @@ noinst_HEADERS = pam_prelude.h pam_private.h pam_tokens.h \
                pam_modutil_private.h
 
 libpam_la_LDFLAGS = -no-undefined -version-info 84:2:84
-libpam_la_LIBADD = @LIBAUDIT@ $(LIBPRELUDE_LIBS) @LIBDL@
+libpam_la_LIBADD = @LIBAUDIT@ $(LIBPRELUDE_LIBS) $(ECONF_LIBS) @LIBDL@
 
 if HAVE_VERSIONING
   libpam_la_LDFLAGS += -Wl,--version-script=$(srcdir)/libpam.map
index 106ef7c255ec006612f311543fbb07a610cabac7..8e513da38e36036c5ebf272c711782a853a25cd0 100644 (file)
@@ -280,9 +280,14 @@ _pam_open_config_file(pam_handle_t *pamh
                        , char **path
                        , FILE **file)
 {
+    const char *pamd_dirs[] = { PAM_CONFIG_DF, PAM_CONFIG_DIST_DF
+#ifdef VENDORDIR
+                               , PAM_CONFIG_DIST2_DF
+#endif
+    };
     char *p;
     FILE *f;
-    int err = 0;
+    size_t i;
 
     /* Absolute path */
     if (service[0] == '/') {
@@ -303,33 +308,20 @@ _pam_open_config_file(pam_handle_t *pamh
        return PAM_ABORT;
     }
 
-    /* Local Machine Configuration /etc/pam.d/ */
-    if (asprintf (&p, PAM_CONFIG_DF, service) < 0) {
-       pam_syslog(pamh, LOG_CRIT, "asprintf failed");
-       return PAM_BUF_ERR;
-    }
-    D(("opening %s", p));
-    f = fopen(p, "r");
-    if (f != NULL) {
-           *path = p;
-           *file = f;
-           return PAM_SUCCESS;
-    }
-
-    /* System Configuration /usr/lib/pam.d/ */
-    _pam_drop(p);
-    if (asprintf (&p, PAM_CONFIG_DIST_DF, service) < 0) {
-       pam_syslog(pamh, LOG_CRIT, "asprintf failed");
-       return PAM_BUF_ERR;
-    }
-    D(("opening %s", p));
-    f = fopen(p, "r");
-    if (f != NULL) {
+    for (i = 0; i < sizeof (pamd_dirs)/sizeof (char *); i++) {
+        if (asprintf (&p, pamd_dirs[i], service) < 0) {
+           pam_syslog(pamh, LOG_CRIT, "asprintf failed");
+           return PAM_BUF_ERR;
+       }
+       D(("opening %s", p));
+       f = fopen(p, "r");
+       if (f != NULL) {
            *path = p;
            *file = f;
            return PAM_SUCCESS;
+       }
+       _pam_drop(p);
     }
-    _pam_drop(p);
 
     return PAM_ABORT;
 }
@@ -447,7 +439,12 @@ int _pam_init_handlers(pam_handle_t *pamh)
 
        /* Is there a PAM_CONFIG_D directory? */
        if ((stat(PAM_CONFIG_D, &test_d) == 0 && S_ISDIR(test_d.st_mode)) ||
-           (stat(PAM_CONFIG_DIST_D, &test_d) == 0 && S_ISDIR(test_d.st_mode))) {
+           (stat(PAM_CONFIG_DIST_D, &test_d) == 0 && S_ISDIR(test_d.st_mode))
+#ifdef PAM_CONFIG_DIST2_D
+           || (stat(PAM_CONFIG_DIST2_D, &test_d) == 0
+               && S_ISDIR(test_d.st_mode))
+#endif
+          ) {
            char *path = NULL;
            int read_something=0;
 
index 338b44fde9a20aeb684c16685e44b088301fbc72..4e565974b18000f7b3f29de88a5eb666d345115e 100644 (file)
 #include <string.h>
 #include <stdlib.h>
 #include <ctype.h>
+#ifdef USE_ECONF
+#include <libeconf.h>
+#endif
 
 #define BUF_SIZE 8192
 
+#ifdef USE_ECONF
+#define LOGIN_DEFS "/etc/login.defs"
+
+#ifndef VENDORDIR
+#define VENDORDIR NULL
+#endif
+
+static char *
+econf_search_key (const char *name, const char *suffix, const char *key)
+{
+       econf_file *key_file = NULL;
+       char *val;
+
+       if (econf_readDirs (&key_file, VENDORDIR, SYSCONFDIR, name, suffix,
+                           " \t", "#"))
+               return NULL;
+
+       if (econf_getStringValue (key_file, NULL, key, &val)) {
+               econf_free (key_file);
+               return NULL;
+       }
+
+       econf_free (key_file);
+
+       return val;
+}
+
+#endif
+
 /* lookup a value for key in login.defs file or similar key value format */
 char *
 pam_modutil_search_key(pam_handle_t *pamh UNUSED,
@@ -27,6 +59,11 @@ pam_modutil_search_key(pam_handle_t *pamh UNUSED,
        size_t buflen = 0;
        char *retval = NULL;
 
+#ifdef USE_ECONF
+       if (strcmp (file_name, LOGIN_DEFS) == 0)
+               return econf_search_key ("login", ".defs", key);
+#endif
+
        fp = fopen(file_name, "r");
        if (NULL == fp)
                return NULL;
index 58a26f58075627889e657471c1075cdfa1b3265d..8cb775289c17a12d74296f4a356f52ee9cdfe64d 100644 (file)
 #define PAM_CONFIG_DF      "/etc/pam.d/%s"
 #define PAM_CONFIG_DIST_D  "/usr/lib/pam.d"
 #define PAM_CONFIG_DIST_DF "/usr/lib/pam.d/%s"
+#ifdef VENDORDIR
+#define PAM_CONFIG_DIST2_D  VENDORDIR"/pam.d"
+#define PAM_CONFIG_DIST2_DF VENDORDIR"/pam.d/%s"
+#endif
+
 
 #define PAM_DEFAULT_SERVICE        "other"     /* lower case */
 
index 30cc879a787a4369a6454b6f5ddaa079373c15be..9bcbbd95c137f333e8da9f21e9b0e9c9f83756b8 100644 (file)
@@ -20,6 +20,9 @@ AM_LDFLAGS = -no-undefined -avoid-version -module
 if HAVE_VERSIONING
   AM_LDFLAGS += -Wl,--version-script=$(srcdir)/../modules.map
 endif
+if HAVE_VENDORDIR
+  AM_CFLAGS += -DVENDORDIR=\"$(VENDORDIR)\"
+endif
 
 securelib_LTLIBRARIES = pam_securetty.la
 pam_securetty_la_LIBADD = $(top_builddir)/libpam/libpam.la
@@ -27,5 +30,10 @@ pam_securetty_la_LIBADD = $(top_builddir)/libpam/libpam.la
 if ENABLE_REGENERATE_MAN
 noinst_DATA = README
 README: pam_securetty.8.xml
+if HAVE_VENDORDIR
+XSLTPROC_CUSTOM = --stringparam vendordir $(VENDORDIR)
+else
+XSLTPROC_CUSTOM = --stringparam vendordir "<vendordir>"
+endif
 -include $(top_srcdir)/Make.xml.rules
 endif
index 48215f5ffe97d4d9b08186e099c2ace88f764376..b5e8369187b76b05c85b4a50bd4c92d23f9c811b 100644 (file)
     <para>
       pam_securetty is a PAM module that allows root logins only if the
       user is logging in on a "secure" tty, as defined by the listing
-      in <filename>/etc/securetty</filename>. pam_securetty also checks
-      to make sure that <filename>/etc/securetty</filename> is a plain
-      file and not world writable. It will also allow root logins on
+      in the <filename>securetty</filename> file. pam_securetty checks at
+      first, if <filename>/etc/securetty</filename> exists. If not and
+      it was built with vendordir support, it will use
+      <filename>%vendordir%/securetty</filename>. pam_securetty also
+      checks that the <filename>securetty</filename> files are plain
+      files and not world writable. It will also allow root logins on
       the tty specified with <option>console=</option> switch on the
       kernel command line and on ttys from the
       <filename>/sys/class/tty/console/active</filename>.
@@ -73,7 +76,7 @@
             Do not automatically allow root logins on the kernel console
             device, as specified on the kernel command line or by the sys file,
             if it is not also specified in the
-            <filename>/etc/securetty</filename> file.
+            <filename>securetty</filename> file.
           </para>
         </listitem>
       </varlistentry>
           <para>
             Authentication is rejected. Either root is attempting to
             log in via an unacceptable device, or the
-            <filename>/etc/securetty</filename> file is world writable or
+            <filename>securetty</filename> file is world writable or
             not a normal file.
           </para>
         </listitem>
           <para>
             An error occurred while the module was determining the
             user's name or tty, or the module could not open
-            <filename>/etc/securetty</filename>.
+            the <filename>securetty</filename> file.
           </para>
         </listitem>
       </varlistentry>
index cb1da252648a4d73eab1745bc3556caf8c8ed486..e8a9273b82c8bc0e8edc6a176d9fa74cd4dfa9a2 100644 (file)
@@ -1,6 +1,9 @@
 /* pam_securetty module */
 
 #define SECURETTY_FILE "/etc/securetty"
+#ifdef VENDORDIR
+#define SECURETTY2_FILE VENDORDIR"/securetty"
+#endif
 #define TTY_PREFIX     "/dev/"
 #define CMDLINE_FILE   "/proc/cmdline"
 #define CONSOLEACTIVE_FILE     "/sys/class/tty/console/active"
@@ -25,6 +28,7 @@
 #include <string.h>
 #include <ctype.h>
 #include <limits.h>
+#include <errno.h>
 
 /*
  * here, we make a definition for the externally accessible function
@@ -70,6 +74,7 @@ securetty_perform_check (pam_handle_t *pamh, int ctrl,
                         const char *function_name)
 {
     int retval = PAM_AUTH_ERR;
+    const char *securettyfile;
     const char *username;
     const char *uttyname;
     const void *void_uttyname;
@@ -111,10 +116,27 @@ securetty_perform_check (pam_handle_t *pamh, int ctrl,
     }
 
     if (stat(SECURETTY_FILE, &ttyfileinfo)) {
+#ifdef VENDORDIR
+      if (errno == ENOENT) {
+       if (stat(SECURETTY2_FILE, &ttyfileinfo)) {
+         pam_syslog(pamh, LOG_NOTICE,
+                    "Couldn't open %s: %m", SECURETTY2_FILE);
+         return PAM_SUCCESS; /* for compatibility with old securetty handling,
+                                this needs to succeed.  But we still log the
+                                error. */
+       }
+       securettyfile = SECURETTY2_FILE;
+      } else {
+#endif
        pam_syslog(pamh, LOG_NOTICE, "Couldn't open %s: %m", SECURETTY_FILE);
        return PAM_SUCCESS; /* for compatibility with old securetty handling,
                               this needs to succeed.  But we still log the
                               error. */
+#ifdef VENDORDIR
+      }
+#endif
+    } else {
+      securettyfile = SECURETTY_FILE;
     }
 
     if ((ttyfileinfo.st_mode & S_IWOTH) || !S_ISREG(ttyfileinfo.st_mode)) {
@@ -122,13 +144,13 @@ securetty_perform_check (pam_handle_t *pamh, int ctrl,
           normal file, return error */
        pam_syslog(pamh, LOG_ERR,
                   "%s is either world writable or not a normal file",
-                  SECURETTY_FILE);
+                  securettyfile);
        return PAM_AUTH_ERR;
     }
 
-    ttyfile = fopen(SECURETTY_FILE,"r");
+    ttyfile = fopen(securettyfile,"r");
     if (ttyfile == NULL) { /* Check that we opened it successfully */
-       pam_syslog(pamh, LOG_ERR, "Error opening %s: %m", SECURETTY_FILE);
+       pam_syslog(pamh, LOG_ERR, "Error opening %s: %m", securettyfile);
        return PAM_SERVICE_ERR;
     }