summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS4
-rw-r--r--doc/man/pam_start.3.xml22
-rw-r--r--libpam/Makefile.am2
-rw-r--r--libpam/include/security/pam_appl.h5
-rw-r--r--libpam/libpam.map5
-rw-r--r--libpam/pam_handlers.c20
-rw-r--r--libpam/pam_private.h1
-rw-r--r--libpam/pam_start.c36
-rw-r--r--tests/Makefile.am2
-rw-r--r--tests/confdir1
-rw-r--r--tests/tst-pam_start_confdir.c99
11 files changed, 187 insertions, 10 deletions
diff --git a/NEWS b/NEWS
index c00a75a1..23e606b4 100644
--- a/NEWS
+++ b/NEWS
@@ -29,7 +29,9 @@ Release 1.4.0
* pam_unix: Support for (gost-)yescrypt hashing methods
* pam_unix: Use bcrypt b-variant when it bcrypt is chosen
* pam_usertype: New module to tell if uid is in login.defs ranges
-
+* Added new API call pam_start_confdir() for special applications that
+ cannot use the system-default PAM configuration paths and need to
+ explicitly specify another path
Release 1.3.1
* pam_motd: add support for a motd.d directory
diff --git a/doc/man/pam_start.3.xml b/doc/man/pam_start.3.xml
index 50a65a47..1d544e64 100644
--- a/doc/man/pam_start.3.xml
+++ b/doc/man/pam_start.3.xml
@@ -12,6 +12,7 @@
<refnamediv id="pam_start-name">
<refname>pam_start</refname>
+ <refname>pam_start_confdir</refname>
<refpurpose>initialization of PAM transaction</refpurpose>
</refnamediv>
@@ -27,6 +28,14 @@
<paramdef>const struct pam_conv *<parameter>pam_conversation</parameter></paramdef>
<paramdef>pam_handle_t **<parameter>pamh</parameter></paramdef>
</funcprototype>
+ <funcprototype>
+ <funcdef>int <function>pam_start_confdir</function></funcdef>
+ <paramdef>const char *<parameter>service_name</parameter></paramdef>
+ <paramdef>const char *<parameter>user</parameter></paramdef>
+ <paramdef>const struct pam_conv *<parameter>pam_conversation</parameter></paramdef>
+ <paramdef>const char *<parameter>confdir</parameter></paramdef>
+ <paramdef>pam_handle_t **<parameter>pamh</parameter></paramdef>
+ </funcprototype>
</funcsynopsis>
</refsynopsisdiv>
@@ -87,6 +96,17 @@
same time as long as <function>pam_end</function> was not called on
it before.
</para>
+
+ <para>
+ The <function>pam_start_confdir</function> function behaves
+ like the <function>pam_start</function> function but it also
+ allows setting <emphasis>confdir</emphasis> argument with
+ a path to a directory to override the default
+ (<filename>/etc/pam.d</filename>) path for service policy
+ files. If the <emphasis>confdir</emphasis> is NULL, the function
+ works exactly the same as <function>pam_start</function>.
+ </para>
+
</refsect1>
<refsect1 id="pam_start-return_values">
<title>RETURN VALUES</title>
@@ -111,7 +131,7 @@
<term>PAM_SUCCESS</term>
<listitem>
<para>
- Transaction was successful created.
+ Transaction was successfully started.
</para>
</listitem>
</varlistentry>
diff --git a/libpam/Makefile.am b/libpam/Makefile.am
index 9d5c844d..bd3dc5d3 100644
--- a/libpam/Makefile.am
+++ b/libpam/Makefile.am
@@ -25,7 +25,7 @@ include_HEADERS = include/security/_pam_compat.h \
noinst_HEADERS = pam_prelude.h pam_private.h pam_tokens.h \
pam_modutil_private.h include/pam_cc_compat.h
-libpam_la_LDFLAGS = -no-undefined -version-info 84:2:84
+libpam_la_LDFLAGS = -no-undefined -version-info 85:1:85
libpam_la_LIBADD = @LIBAUDIT@ $(LIBPRELUDE_LIBS) $(ECONF_LIBS) @LIBDL@
if HAVE_VERSIONING
diff --git a/libpam/include/security/pam_appl.h b/libpam/include/security/pam_appl.h
index d4172c69..cf97a493 100644
--- a/libpam/include/security/pam_appl.h
+++ b/libpam/include/security/pam_appl.h
@@ -24,6 +24,11 @@ pam_start(const char *service_name, const char *user,
const struct pam_conv *pam_conversation,
pam_handle_t **pamh);
+extern int PAM_NONNULL((1,3,5))
+pam_start_confdir(const char *service_name, const char *user,
+ const struct pam_conv *pam_conversation,
+ const char *confdir, pam_handle_t **pamh);
+
extern int PAM_NONNULL((1))
pam_end(pam_handle_t *pamh, int pam_status);
diff --git a/libpam/libpam.map b/libpam/libpam.map
index 74fb55b2..c9690a91 100644
--- a/libpam/libpam.map
+++ b/libpam/libpam.map
@@ -77,3 +77,8 @@ LIBPAM_MODUTIL_1.3.2 {
global:
pam_modutil_search_key;
} LIBPAM_MODUTIL_1.1.9;
+
+LIBPAM_1.4 {
+ global:
+ pam_start_confdir;
+} LIBPAM_1.0;
diff --git a/libpam/pam_handlers.c b/libpam/pam_handlers.c
index 8e513da3..5dff58c2 100644
--- a/libpam/pam_handlers.c
+++ b/libpam/pam_handlers.c
@@ -285,7 +285,7 @@ _pam_open_config_file(pam_handle_t *pamh
, PAM_CONFIG_DIST2_DF
#endif
};
- char *p;
+ char *p = NULL;
FILE *f;
size_t i;
@@ -296,14 +296,21 @@ _pam_open_config_file(pam_handle_t *pamh
pam_syslog(pamh, LOG_CRIT, "strdup failed");
return PAM_BUF_ERR;
}
+ } else if (pamh->confdir != NULL) {
+ if (asprintf (&p, "%s/%s", pamh->confdir, service) < 0) {
+ pam_syslog(pamh, LOG_CRIT, "asprintf failed");
+ return PAM_BUF_ERR;
+ }
+ }
- f = fopen(service, "r");
+ if (p != NULL) {
+ D(("opening %s", p));
+ f = fopen(p, "r");
if (f != NULL) {
*path = p;
*file = f;
return PAM_SUCCESS;
}
-
_pam_drop(p);
return PAM_ABORT;
}
@@ -313,6 +320,7 @@ _pam_open_config_file(pam_handle_t *pamh
pam_syslog(pamh, LOG_CRIT, "asprintf failed");
return PAM_BUF_ERR;
}
+
D(("opening %s", p));
f = fopen(p, "r");
if (f != NULL) {
@@ -438,7 +446,8 @@ int _pam_init_handlers(pam_handle_t *pamh)
struct stat test_d;
/* Is there a PAM_CONFIG_D directory? */
- if ((stat(PAM_CONFIG_D, &test_d) == 0 && S_ISDIR(test_d.st_mode)) ||
+ if (pamh->confdir != NULL ||
+ (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))
#ifdef PAM_CONFIG_DIST2_D
|| (stat(PAM_CONFIG_DIST2_D, &test_d) == 0
@@ -471,7 +480,8 @@ int _pam_init_handlers(pam_handle_t *pamh)
#ifdef PAM_READ_BOTH_CONFS
D(("checking %s", PAM_CONFIG));
- if ((f = fopen(PAM_CONFIG,"r")) != NULL) {
+ if (pamh->confdir == NULL
+ && (f = fopen(PAM_CONFIG,"r")) != NULL) {
retval = _pam_parse_conf_file(pamh, f, NULL, PAM_T_ANY, 0, 1);
fclose(f);
} else
diff --git a/libpam/pam_private.h b/libpam/pam_private.h
index ed02bb02..69d2ef44 100644
--- a/libpam/pam_private.h
+++ b/libpam/pam_private.h
@@ -178,6 +178,7 @@ struct pam_handle {
int audit_state; /* keep track of reported audit messages */
#endif
int authtok_verified;
+ char *confdir;
};
/* Values for select arg to _pam_dispatch() */
diff --git a/libpam/pam_start.c b/libpam/pam_start.c
index e27c64bb..59d06224 100644
--- a/libpam/pam_start.c
+++ b/libpam/pam_start.c
@@ -15,10 +15,11 @@
#include <string.h>
#include <syslog.h>
-int pam_start (
+static int _pam_start_internal (
const char *service_name,
const char *user,
const struct pam_conv *pam_conversation,
+ const char *confdir,
pam_handle_t **pamh)
{
D(("called pam_start: [%s] [%s] [%p] [%p]"
@@ -80,6 +81,18 @@ int pam_start (
} else
(*pamh)->user = NULL;
+ if (confdir) {
+ if (((*pamh)->confdir = _pam_strdup(confdir)) == NULL) {
+ pam_syslog(*pamh, LOG_CRIT,
+ "pam_start: _pam_strdup failed for confdir");
+ _pam_drop((*pamh)->service_name);
+ _pam_drop((*pamh)->user);
+ _pam_drop(*pamh);
+ return (PAM_BUF_ERR);
+ }
+ } else
+ (*pamh)->confdir = NULL;
+
(*pamh)->tty = NULL;
(*pamh)->prompt = NULL; /* prompt for pam_get_user() */
(*pamh)->ruser = NULL;
@@ -140,3 +153,24 @@ int pam_start (
return PAM_SUCCESS;
}
+
+int pam_start_confdir (
+ const char *service_name,
+ const char *user,
+ const struct pam_conv *pam_conversation,
+ const char *confdir,
+ pam_handle_t **pamh)
+{
+ return _pam_start_internal(service_name, user, pam_conversation,
+ confdir, pamh);
+}
+
+int pam_start (
+ const char *service_name,
+ const char *user,
+ const struct pam_conv *pam_conversation,
+ pam_handle_t **pamh)
+{
+ return _pam_start_internal(service_name, user, pam_conversation,
+ NULL, pamh);
+}
diff --git a/tests/Makefile.am b/tests/Makefile.am
index c44a2ee7..5b0e78d7 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -12,7 +12,7 @@ TESTS = tst-pam_start tst-pam_end tst-pam_fail_delay tst-pam_open_session \
tst-pam_close_session tst-pam_acct_mgmt tst-pam_authenticate \
tst-pam_chauthtok tst-pam_setcred tst-pam_get_item tst-pam_set_item \
tst-pam_getenvlist tst-pam_get_user tst-pam_set_data \
- tst-pam_mkargv
+ tst-pam_mkargv tst-pam_start_confdir
check_PROGRAMS = ${TESTS} tst-dlopen
diff --git a/tests/confdir b/tests/confdir
new file mode 100644
index 00000000..3883c869
--- /dev/null
+++ b/tests/confdir
@@ -0,0 +1 @@
+# This is an empty pam service file for tst-pam_start_confdir
diff --git a/tests/tst-pam_start_confdir.c b/tests/tst-pam_start_confdir.c
new file mode 100644
index 00000000..e40b6e70
--- /dev/null
+++ b/tests/tst-pam_start_confdir.c
@@ -0,0 +1,99 @@
+/*
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions. (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <security/pam_appl.h>
+
+
+int
+main (void)
+{
+ const char *service = "confdir";
+ const char *xservice = "nonexistent-service";
+ const char *user = "root";
+ const char *confdir;
+ const char *xconfdir = "/nonexistent-confdir";
+ struct pam_conv conv;
+ pam_handle_t *pamh;
+ int retval;
+
+ confdir = getenv("srcdir");
+
+ if (confdir == NULL)
+ {
+ fprintf (stderr, "Error: srcdir not set\n");
+ return 1;
+ }
+
+ /* 1: check with valid arguments */
+ retval = pam_start_confdir (service, user, &conv, confdir, &pamh);
+ if (retval != PAM_SUCCESS)
+ {
+ fprintf (stderr, "pam_start_confdir (%s, %s, &conv, %s, &pamh) returned %d\n",
+ service, user, confdir, retval);
+ return 1;
+ }
+ else if (pamh == NULL)
+ {
+ fprintf (stderr, "pam_start_confdir (%s, %s, &conv, %s, &pamh) returned NULL for pamh\n",
+ service, user, confdir);
+ return 1;
+ }
+
+ /* 2: check with invalid service */
+ retval = pam_start_confdir (xservice, user, &conv, confdir, &pamh);
+ if (retval == PAM_SUCCESS)
+ {
+ fprintf (stderr, "pam_start_confdir (%s, %s, &conv, %s, &pamh) incorrectly succeeded\n",
+ xservice, user, confdir);
+ return 1;
+ }
+
+ /* 3: check with invalid confdir */
+ retval = pam_start_confdir (service, user, &conv, xconfdir, &pamh);
+ if (retval == PAM_SUCCESS)
+ {
+ fprintf (stderr, "pam_start_confdir (%s, %s, &conv, %s, &pamh) incorrectly succeeded\n",
+ service, user, xconfdir);
+ return 1;
+ }
+
+ return 0;
+}