New API call pam_start_confdir()

To load PAM stack configurations from specified directory
This commit is contained in:
Tomas Mraz 2020-02-24 18:19:57 +01:00
parent bba3a4f67e
commit 7a84910896
11 changed files with 187 additions and 10 deletions

4
NEWS
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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() */

View File

@ -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);
}

View File

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

1
tests/confdir Normal file
View File

@ -0,0 +1 @@
# This is an empty pam service file for tst-pam_start_confdir

View File

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