Q: pam_permit and pam_debug may set PAM_USER to nobody
by Dmitry V. Levin
Hi,
At least since the very first git commit
ea488580c42e8918445a945484de3c8a5addc761
pam_permit sets PAM_USER to "nobody" when pam_get_user returns an empty
string as the user name.
I couldn't find any rationale for this behaviour,
and it doesn't make any sense to me.
Do you have any reason to keep it? If not, I'd rather remove it.
Likewise, pam_debug introduced lated by commit
6180f388df5004d5435cd6912445130cf260f94e
has exactly the same behaviour.
Other modules don't behave this way.
--
ldv
4 years
[PATCH 00/13] rework pam_localuser
by Dmitry V. Levin
This started as small fixes here and there, and ended up as a major
cleanup of the module. Now pam_localuser is the first module that
has a decent "make distcheck" coverage.
I've also pushed the series to ldv/pam_localuser branch.
Dmitry V. Levin (13):
pam_localuser: reject user names containing a colon
pam_localuser: reject user names that are too long
pam_localuser: return PAM_SERVICE_ERR instead of PAM_SYSTEM_ERR
pam_localuser: log unrecognized options
pam_localuser: get rid of a temporary buffer
pam_localuser: handle long lines in passwd files properly
pam_localuser: use BUFSIZ as the line buffer size
pam_localuser: open the passwd file after user name validation
pam_localuser: return PAM_INCOMPLETE when pam_get_user returns PAM_CONV_AGAIN
pam_localuser: remove unused includes
pam_localuser: re-format pam_sm_* function declarations
pam_localuser: refactor pam_sm_authenticate
pam_localuser: add a test for file= option
modules/pam_localuser/Makefile.am | 5 +-
modules/pam_localuser/pam_localuser.c | 182 +++++++++++-------
.../pam_localuser/tst-pam_localuser-file.c | 173 +++++++++++++++++
3 files changed, 292 insertions(+), 68 deletions(-)
create mode 100644 modules/pam_localuser/tst-pam_localuser-file.c
--
ldv
4 years, 1 month
[PATCH 0/4] Introduce return value tests for modules
by Dmitry V. Levin
pam_start_confdir opens the way for "make distcheck" coverage.
Let's start with return value tests for a few simple modules.
I've also rebased ldv/pam_localuser branch on top of this series.
Dmitry V. Levin (4):
Introduce test_assert.h
pam_deny: add a test for return values
pam_permit: add a test for return values
pam_debug: add a test for return values
libpam/Makefile.am | 2 +-
libpam/include/test_assert.h | 56 +++++++++++++++++++
modules/pam_debug/Makefile.am | 7 ++-
modules/pam_debug/tst-pam_debug-retval.c | 65 ++++++++++++++++++++++
modules/pam_deny/Makefile.am | 5 +-
modules/pam_deny/tst-pam_deny-retval.c | 58 +++++++++++++++++++
modules/pam_permit/Makefile.am | 5 +-
modules/pam_permit/tst-pam_permit-retval.c | 58 +++++++++++++++++++
8 files changed, 251 insertions(+), 5 deletions(-)
create mode 100644 libpam/include/test_assert.h
create mode 100644 modules/pam_debug/tst-pam_debug-retval.c
create mode 100644 modules/pam_deny/tst-pam_deny-retval.c
create mode 100644 modules/pam_permit/tst-pam_permit-retval.c
--
ldv
4 years, 1 month
Q: actionN documentation does not match the code
by Dmitry V. Levin
On Mon, Apr 12, 2010 at 01:55:22PM +0000, Thorsten Kukuk wrote:
> ========== files committed ===============
>
> Linux-PAM/doc/man
> pam.conf-syntax.xml 1.6 -> 1.7
>
> ============= commit log =================
>
> Update of /cvsroot/pam/Linux-PAM/doc/man
> In directory sfp-cvsdas-2.v30.ch3.sourceforge.com:/tmp/cvs-serv9747/doc/man
>
> Modified Files:
> pam.conf-syntax.xml
> Log Message:
> Relevant BUGIDs:
>
> Purpose of commit: enhancement
>
> Commit summary:
> ---------------
>
> 2010-04-12 Thorsten Kukuk <kukuk(a)thkukuk.de>
>
> * doc/man/pam.conf-syntax.xml: Better documentation of
> "actionN". Patch from Michal Soltys <soltys(a)ziu.info>.
The corresponding commit 871a6e14d65c3c446ae0af51166dabc7a47a2b56 changes
the documentation to state the following:
N (an unsigned integer)
equivalent to ok with the side effect of jumping over the next N modules
in the stack. Note that N equal to 0 is not allowed (and it would be
identical to ok in such case).
According to _pam_dispatch_aux, this is not what's actually implemented:
"equivalent to ok" is happening with cached chains only (e.g.
pam_setcred and pam_close_session, see libpam/pam_dispatch.c:260),
with all the rest it's rather "equivalent to ignore".
Should we change the documentation to match the implementation?
--
ldv
4 years, 1 month
[PATCH] pam_securetty: forward error values returned by pam_get_user
by Dmitry V. Levin
Starting with commit c2c601f5340a59c5c62193d55b555d384380ea38,
pam_get_user is guaranteed to return one of the following values:
PAM_SUCCESS, PAM_BUF_ERR, PAM_CONV_AGAIN, or PAM_CONV_ERR.
If pam_get_user returned PAM_SUCCESS, the user name is guaranteed
to be non-NULL.
* modules/pam_securetty/pam_securetty.c (pam_sm_authenticate): Do not
replace non-PAM_CONV_AGAIN error values returned by pam_get_user with
PAM_SERVICE_ERR. Do not check the user name returned by pam_get_user
when the latter returned PAM_SUCCESS.
* modules/pam_securetty/pam_securetty.8.xml (RETURN VALUES): Document
new return values.
---
modules/pam_securetty/pam_securetty.8.xml | 22 +++++++++++++++++++---
modules/pam_securetty/pam_securetty.c | 4 ++--
2 files changed, 21 insertions(+), 5 deletions(-)
diff --git a/modules/pam_securetty/pam_securetty.8.xml b/modules/pam_securetty/pam_securetty.8.xml
index b5e83691..e49d572b 100644
--- a/modules/pam_securetty/pam_securetty.8.xml
+++ b/modules/pam_securetty/pam_securetty.8.xml
@@ -114,13 +114,29 @@
</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>PAM_BUF_ERR</term>
+ <listitem>
+ <para>
+ Memory buffer error.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>PAM_CONV_ERR</term>
+ <listitem>
+ <para>
+ The conversation method supplied by the application
+ failed to obtain the username.
+ </para>
+ </listitem>
+ </varlistentry>
<varlistentry>
<term>PAM_INCOMPLETE</term>
<listitem>
<para>
- An application error occurred. pam_securetty was not able
- to get information it required from the application that
- called it.
+ The conversation method supplied by the application
+ returned PAM_CONV_AGAIN.
</para>
</listitem>
</varlistentry>
diff --git a/modules/pam_securetty/pam_securetty.c b/modules/pam_securetty/pam_securetty.c
index 9a2835ef..5f52d3a9 100644
--- a/modules/pam_securetty/pam_securetty.c
+++ b/modules/pam_securetty/pam_securetty.c
@@ -83,9 +83,9 @@ securetty_perform_check (pam_handle_t *pamh, int ctrl,
}
retval = pam_get_user(pamh, &username, NULL);
- if (retval != PAM_SUCCESS || username == NULL) {
+ if (retval != PAM_SUCCESS) {
pam_syslog(pamh, LOG_WARNING, "cannot determine username");
- return (retval == PAM_CONV_AGAIN ? PAM_INCOMPLETE:PAM_SERVICE_ERR);
+ return (retval == PAM_CONV_AGAIN ? PAM_INCOMPLETE : retval);
}
user_pwd = pam_modutil_getpwnam(pamh, username);
--
ldv
4 years, 1 month
[PATCH] pam_faillock: return PAM_INCOMPLETE when pam_get_user returns PAM_CONV_AGAIN
by Dmitry V. Levin
Give the application a chance to handle PAM_INCOMPLETE.
* modules/pam_faillock/pam_faillock.c (get_pam_user): Return
PAM_INCOMPLETE instead of PAM_CONV_AGAIN when pam_get_user returns
PAM_CONV_AGAIN.
* modules/pam_faillock/pam_faillock.8.xml (RETURN VALUES): Document it.
---
modules/pam_faillock/pam_faillock.8.xml | 9 +++++++++
modules/pam_faillock/pam_faillock.c | 2 +-
2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/modules/pam_faillock/pam_faillock.8.xml b/modules/pam_faillock/pam_faillock.8.xml
index d7f2a3ce..c734c28c 100644
--- a/modules/pam_faillock/pam_faillock.8.xml
+++ b/modules/pam_faillock/pam_faillock.8.xml
@@ -170,6 +170,15 @@
</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>PAM_INCOMPLETE</term>
+ <listitem>
+ <para>
+ The conversation method supplied by the application
+ returned PAM_CONV_AGAIN.
+ </para>
+ </listitem>
+ </varlistentry>
<varlistentry>
<term>PAM_SUCCESS</term>
<listitem>
diff --git a/modules/pam_faillock/pam_faillock.c b/modules/pam_faillock/pam_faillock.c
index e340a83c..142cf7e3 100644
--- a/modules/pam_faillock/pam_faillock.c
+++ b/modules/pam_faillock/pam_faillock.c
@@ -394,7 +394,7 @@ get_pam_user(pam_handle_t *pamh, struct options *opts)
struct passwd *pwd;
if ((rv=pam_get_user(pamh, &user, NULL)) != PAM_SUCCESS) {
- return rv;
+ return rv == PAM_CONV_AGAIN ? PAM_INCOMPLETE : rv;
}
if (*user == '\0') {
--
ldv
4 years, 1 month
Q: deprecating modules
by Dmitry V. Levin
Hi,
I suggest to start a formal procedure of deprecating modules.
For example, we could use a simple 3-step deprecation algorithm:
- declare a module as deprecated in the upcoming release N,
- do not build it by default right after release N,
- remove it from the tree right after release N+1.
I suggest starting with pam_tally (obsoleted by in-tree pam_tally2),
pam_tally2 (obsoleted by out-of-tree pam_faillock), and pam_cracklib
(obsoleted by out-of-tree pam_passwdqc and pam_pwquality), this means
declaring them as deprecated in 1.4.0 release.
This would mean making Linux-PAM releases more regular and more often,
e.g. twice a year.
Comments?
--
ldv
4 years, 1 month
[PATCH 9/4] pam_faildelay: add a test for return values
by Dmitry V. Levin
* modules/pam_faildelay/tst-pam_faildelay-retval.c: New file.
* modules/pam_faildelay/Makefile.am (TESTS): Add $(check_PROGRAMS).
(check_PROGRAMS, tst_pam_faildelay_retval_LDADD): New variables.
---
modules/pam_faildelay/Makefile.am | 5 +-
.../pam_faildelay/tst-pam_faildelay-retval.c | 88 +++++++++++++++++++
2 files changed, 92 insertions(+), 1 deletion(-)
create mode 100644 modules/pam_faildelay/tst-pam_faildelay-retval.c
diff --git a/modules/pam_faildelay/Makefile.am b/modules/pam_faildelay/Makefile.am
index a630c2bd..3a49a117 100644
--- a/modules/pam_faildelay/Makefile.am
+++ b/modules/pam_faildelay/Makefile.am
@@ -12,7 +12,7 @@ dist_man_MANS = pam_faildelay.8
endif
XMLS = README.xml pam_faildelay.8.xml
dist_check_SCRIPTS = tst-pam_faildelay
-TESTS = $(dist_check_SCRIPTS)
+TESTS = $(dist_check_SCRIPTS) $(check_PROGRAMS)
securelibdir = $(SECUREDIR)
secureconfdir = $(SCONFIGDIR)
@@ -27,6 +27,9 @@ endif
securelib_LTLIBRARIES = pam_faildelay.la
pam_faildelay_la_LIBADD = $(top_builddir)/libpam/libpam.la
+check_PROGRAMS = tst-pam_faildelay-retval
+tst_pam_faildelay_retval_LDADD = $(top_builddir)/libpam/libpam.la
+
if ENABLE_REGENERATE_MAN
dist_noinst_DATA = README
-include $(top_srcdir)/Make.xml.rules
diff --git a/modules/pam_faildelay/tst-pam_faildelay-retval.c b/modules/pam_faildelay/tst-pam_faildelay-retval.c
new file mode 100644
index 00000000..cbd8f2a8
--- /dev/null
+++ b/modules/pam_faildelay/tst-pam_faildelay-retval.c
@@ -0,0 +1,88 @@
+/*
+ * Check pam_faildelay return values.
+ *
+ * Copyright (c) 2020 Dmitry V. Levin <ldv(a)altlinux.org>
+ */
+
+#include "test_assert.h"
+
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <security/pam_appl.h>
+
+#define MODULE_NAME "pam_faildelay"
+#define TEST_NAME "tst-" MODULE_NAME "-retval"
+
+static const char service_file[] = TEST_NAME ".service";
+static const char user_name[] = "";
+static struct pam_conv conv;
+
+int
+main(void)
+{
+ pam_handle_t *pamh = NULL;
+ FILE *fp;
+ char cwd[PATH_MAX];
+
+ ASSERT_NE(NULL, getcwd(cwd, sizeof(cwd)));
+
+ /* PAM_IGNORE -> PAM_PERM_DENIED */
+ ASSERT_NE(NULL, fp = fopen(service_file, "w"));
+ ASSERT_LT(0, fprintf(fp, "#%%PAM-1.0\n"
+ "auth required %s/.libs/%s.so delay=1\n"
+ "account required %s/.libs/%s.so delay=1\n"
+ "password required %s/.libs/%s.so delay=1\n"
+ "session required %s/.libs/%s.so delay=1\n",
+ cwd, MODULE_NAME,
+ cwd, MODULE_NAME,
+ cwd, MODULE_NAME,
+ cwd, MODULE_NAME));
+ ASSERT_EQ(0, fclose(fp));
+
+ ASSERT_EQ(PAM_SUCCESS,
+ pam_start_confdir(service_file, user_name, &conv, ".", &pamh));
+ ASSERT_NE(NULL, pamh);
+ ASSERT_EQ(PAM_PERM_DENIED, pam_authenticate(pamh, 0));
+ ASSERT_EQ(PAM_PERM_DENIED, pam_setcred(pamh, 0));
+ ASSERT_EQ(PAM_MODULE_UNKNOWN, pam_acct_mgmt(pamh, 0));
+ ASSERT_EQ(PAM_MODULE_UNKNOWN, pam_chauthtok(pamh, 0));
+ ASSERT_EQ(PAM_MODULE_UNKNOWN, pam_open_session(pamh, 0));
+ ASSERT_EQ(PAM_MODULE_UNKNOWN, pam_close_session(pamh, 0));
+ ASSERT_EQ(PAM_SUCCESS, pam_end(pamh, 0));
+ pamh = NULL;
+
+ /* PAM_IGNORE -> PAM_SUCCESS */
+ ASSERT_NE(NULL, fp = fopen(service_file, "w"));
+ ASSERT_LT(0, fprintf(fp, "#%%PAM-1.0\n"
+ "auth required %s/.libs/%s.so delay=1\n"
+ "auth required %s/../pam_permit/.libs/pam_permit.so\n"
+ "account required %s/.libs/%s.so delay=1\n"
+ "account required %s/../pam_permit/.libs/pam_permit.so\n"
+ "password required %s/.libs/%s.so delay=1\n"
+ "password required %s/../pam_permit/.libs/pam_permit.so\n"
+ "session required %s/.libs/%s.so delay=1\n"
+ "session required %s/../pam_permit/.libs/pam_permit.so\n",
+ cwd, MODULE_NAME, cwd,
+ cwd, MODULE_NAME, cwd,
+ cwd, MODULE_NAME, cwd,
+ cwd, MODULE_NAME, cwd));
+ ASSERT_EQ(0, fclose(fp));
+
+ ASSERT_EQ(PAM_SUCCESS,
+ pam_start_confdir(service_file, user_name, &conv, ".", &pamh));
+ ASSERT_NE(NULL, pamh);
+ ASSERT_EQ(PAM_SUCCESS, pam_authenticate(pamh, 0));
+ ASSERT_EQ(PAM_SUCCESS, pam_setcred(pamh, 0));
+ ASSERT_EQ(PAM_MODULE_UNKNOWN, pam_acct_mgmt(pamh, 0));
+ ASSERT_EQ(PAM_MODULE_UNKNOWN, pam_chauthtok(pamh, 0));
+ ASSERT_EQ(PAM_MODULE_UNKNOWN, pam_open_session(pamh, 0));
+ ASSERT_EQ(PAM_MODULE_UNKNOWN, pam_close_session(pamh, 0));
+ ASSERT_EQ(PAM_SUCCESS, pam_end(pamh, 0));
+ pamh = NULL;
+
+ ASSERT_EQ(0, unlink(service_file));
+
+ return 0;
+}
--
ldv
4 years, 1 month
[PATCH 8/4] pam_rootok: add a test for return values
by Dmitry V. Levin
* modules/pam_rootok/tst-pam_rootok-retval.c: New file.
* modules/pam_rootok/Makefile.am (TESTS): Add $(check_PROGRAMS).
(check_PROGRAMS, tst_pam_rootok_retval_LDADD): New variables.
---
modules/pam_rootok/Makefile.am | 5 +-
modules/pam_rootok/tst-pam_rootok-retval.c | 72 ++++++++++++++++++++++
2 files changed, 76 insertions(+), 1 deletion(-)
create mode 100644 modules/pam_rootok/tst-pam_rootok-retval.c
diff --git a/modules/pam_rootok/Makefile.am b/modules/pam_rootok/Makefile.am
index 727a3950..787218b4 100644
--- a/modules/pam_rootok/Makefile.am
+++ b/modules/pam_rootok/Makefile.am
@@ -12,7 +12,7 @@ dist_man_MANS = pam_rootok.8
endif
XMLS = README.xml pam_rootok.8.xml
dist_check_SCRIPTS = tst-pam_rootok
-TESTS = $(dist_check_SCRIPTS)
+TESTS = $(dist_check_SCRIPTS) $(check_PROGRAMS)
securelibdir = $(SECUREDIR)
secureconfdir = $(SCONFIGDIR)
@@ -27,6 +27,9 @@ endif
securelib_LTLIBRARIES = pam_rootok.la
pam_rootok_la_LIBADD = $(top_builddir)/libpam/libpam.la @LIBSELINUX@ @LIBAUDIT@
+check_PROGRAMS = tst-pam_rootok-retval
+tst_pam_rootok_retval_LDADD = $(top_builddir)/libpam/libpam.la
+
if ENABLE_REGENERATE_MAN
dist_noinst_DATA = README
-include $(top_srcdir)/Make.xml.rules
diff --git a/modules/pam_rootok/tst-pam_rootok-retval.c b/modules/pam_rootok/tst-pam_rootok-retval.c
new file mode 100644
index 00000000..b1797013
--- /dev/null
+++ b/modules/pam_rootok/tst-pam_rootok-retval.c
@@ -0,0 +1,72 @@
+/*
+ * Check pam_rootok return values.
+ *
+ * Copyright (c) 2020 Dmitry V. Levin <ldv(a)altlinux.org>
+ */
+
+#include "test_assert.h"
+
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <security/pam_appl.h>
+
+#define MODULE_NAME "pam_rootok"
+#define TEST_NAME "tst-" MODULE_NAME "-retval"
+
+static const char service_file[] = TEST_NAME ".service";
+static const char user_name[] = "";
+static struct pam_conv conv;
+
+int
+main(void)
+{
+ pam_handle_t *pamh = NULL;
+ FILE *fp;
+ char cwd[PATH_MAX];
+
+ ASSERT_NE(NULL, getcwd(cwd, sizeof(cwd)));
+
+ ASSERT_NE(NULL, fp = fopen(service_file, "w"));
+ ASSERT_LT(0, fprintf(fp, "#%%PAM-1.0\n"
+ "auth required %s/.libs/%s.so\n"
+ "account required %s/.libs/%s.so\n"
+ "password required %s/.libs/%s.so\n"
+ "session required %s/.libs/%s.so\n",
+ cwd, MODULE_NAME,
+ cwd, MODULE_NAME,
+ cwd, MODULE_NAME,
+ cwd, MODULE_NAME));
+ ASSERT_EQ(0, fclose(fp));
+
+ ASSERT_EQ(PAM_SUCCESS,
+ pam_start_confdir(service_file, user_name, &conv, ".", &pamh));
+ ASSERT_NE(NULL, pamh);
+ ASSERT_EQ(PAM_SUCCESS, pam_setcred(pamh, 0));
+ ASSERT_EQ(PAM_SUCCESS, pam_end(pamh, 0));
+ pamh = NULL;
+
+ ASSERT_EQ(PAM_SUCCESS,
+ pam_start_confdir(service_file, user_name, &conv, ".", &pamh));
+ ASSERT_NE(NULL, pamh);
+ if (getuid() == 0) {
+ ASSERT_EQ(PAM_SUCCESS, pam_authenticate(pamh, 0));
+ ASSERT_EQ(PAM_SUCCESS, pam_setcred(pamh, 0));
+ ASSERT_EQ(PAM_SUCCESS, pam_acct_mgmt(pamh, 0));
+ ASSERT_EQ(PAM_SUCCESS, pam_chauthtok(pamh, 0));
+ } else {
+ ASSERT_EQ(PAM_AUTH_ERR, pam_authenticate(pamh, 0));
+ ASSERT_EQ(PAM_PERM_DENIED, pam_setcred(pamh, 0));
+ ASSERT_EQ(PAM_AUTH_ERR, pam_acct_mgmt(pamh, 0));
+ ASSERT_EQ(PAM_AUTH_ERR, pam_chauthtok(pamh, 0));
+ }
+ ASSERT_EQ(PAM_MODULE_UNKNOWN, pam_open_session(pamh, 0));
+ ASSERT_EQ(PAM_MODULE_UNKNOWN, pam_close_session(pamh, 0));
+ ASSERT_EQ(PAM_SUCCESS, pam_end(pamh, 0));
+ pamh = NULL;
+
+ ASSERT_EQ(0, unlink(service_file));
+
+ return 0;
+}
--
ldv
4 years, 1 month
[PATCH 7/4] pam_nologin: add a test for return values
by Dmitry V. Levin
* modules/pam_nologin/tst-pam_nologin-retval.c: New file.
* modules/pam_nologin/Makefile.am (TESTS): Add $(check_PROGRAMS).
(check_PROGRAMS, tst_pam_nologin_retval_LDADD): New variables.
---
modules/pam_nologin/Makefile.am | 5 +-
modules/pam_nologin/tst-pam_nologin-retval.c | 226 +++++++++++++++++++
2 files changed, 230 insertions(+), 1 deletion(-)
create mode 100644 modules/pam_nologin/tst-pam_nologin-retval.c
diff --git a/modules/pam_nologin/Makefile.am b/modules/pam_nologin/Makefile.am
index e2d00725..d1ec2035 100644
--- a/modules/pam_nologin/Makefile.am
+++ b/modules/pam_nologin/Makefile.am
@@ -12,7 +12,7 @@ dist_man_MANS = pam_nologin.8
endif
XMLS = README.xml pam_nologin.8.xml
dist_check_SCRIPTS = tst-pam_nologin
-TESTS = $(dist_check_SCRIPTS)
+TESTS = $(dist_check_SCRIPTS) $(check_PROGRAMS)
securelibdir = $(SECUREDIR)
secureconfdir = $(SCONFIGDIR)
@@ -27,6 +27,9 @@ endif
securelib_LTLIBRARIES = pam_nologin.la
pam_nologin_la_LIBADD = $(top_builddir)/libpam/libpam.la
+check_PROGRAMS = tst-pam_nologin-retval
+tst_pam_nologin_retval_LDADD = $(top_builddir)/libpam/libpam.la
+
if ENABLE_REGENERATE_MAN
dist_noinst_DATA = README
-include $(top_srcdir)/Make.xml.rules
diff --git a/modules/pam_nologin/tst-pam_nologin-retval.c b/modules/pam_nologin/tst-pam_nologin-retval.c
new file mode 100644
index 00000000..0046eec3
--- /dev/null
+++ b/modules/pam_nologin/tst-pam_nologin-retval.c
@@ -0,0 +1,226 @@
+/*
+ * Check pam_nologin return values.
+ *
+ * Copyright (c) 2020 Dmitry V. Levin <ldv(a)altlinux.org>
+ */
+
+#include "test_assert.h"
+
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <security/pam_appl.h>
+
+#define MODULE_NAME "pam_nologin"
+#define TEST_NAME "tst-" MODULE_NAME "-retval"
+
+static const char service_file[] = TEST_NAME ".service";
+static const char missing_file[] = TEST_NAME ".missing";
+static const char empty_file[] = "/dev/null";
+static const char user_name[] = "";
+static struct pam_conv conv;
+
+int
+main(void)
+{
+ pam_handle_t *pamh = NULL;
+ FILE *fp;
+ struct passwd *pw;
+ char cwd[PATH_MAX];
+
+ ASSERT_NE(NULL, getcwd(cwd, sizeof(cwd)));
+
+ /* PAM_IGNORE -> PAM_PERM_DENIED */
+ ASSERT_NE(NULL, fp = fopen(service_file, "w"));
+ ASSERT_LT(0, fprintf(fp, "#%%PAM-1.0\n"
+ "auth required %s/.libs/%s.so file=%s\n"
+ "account required %s/.libs/%s.so file=%s\n"
+ "password required %s/.libs/%s.so file=%s\n"
+ "session required %s/.libs/%s.so file=%s\n",
+ cwd, MODULE_NAME, missing_file,
+ cwd, MODULE_NAME, missing_file,
+ cwd, MODULE_NAME, missing_file,
+ cwd, MODULE_NAME, missing_file));
+ ASSERT_EQ(0, fclose(fp));
+
+ ASSERT_EQ(PAM_SUCCESS,
+ pam_start_confdir(service_file, user_name, &conv, ".", &pamh));
+ ASSERT_NE(NULL, pamh);
+ ASSERT_EQ(PAM_PERM_DENIED, pam_authenticate(pamh, 0));
+ ASSERT_EQ(PAM_PERM_DENIED, pam_setcred(pamh, 0));
+ ASSERT_EQ(PAM_PERM_DENIED, pam_acct_mgmt(pamh, 0));
+ ASSERT_EQ(PAM_MODULE_UNKNOWN, pam_chauthtok(pamh, 0));
+ ASSERT_EQ(PAM_MODULE_UNKNOWN, pam_open_session(pamh, 0));
+ ASSERT_EQ(PAM_MODULE_UNKNOWN, pam_close_session(pamh, 0));
+ ASSERT_EQ(PAM_SUCCESS, pam_end(pamh, 0));
+ pamh = NULL;
+
+ /* PAM_IGNORE -> PAM_SUCCESS */
+ ASSERT_NE(NULL, fp = fopen(service_file, "w"));
+ ASSERT_LT(0, fprintf(fp, "#%%PAM-1.0\n"
+ "auth required %s/.libs/%s.so file=%s\n"
+ "auth required %s/../pam_permit/.libs/pam_permit.so\n"
+ "account required %s/.libs/%s.so file=%s\n"
+ "account required %s/../pam_permit/.libs/pam_permit.so\n"
+ "password required %s/.libs/%s.so file=%s\n"
+ "password required %s/../pam_permit/.libs/pam_permit.so\n"
+ "session required %s/.libs/%s.so file=%s\n"
+ "session required %s/../pam_permit/.libs/pam_permit.so\n",
+ cwd, MODULE_NAME, missing_file, cwd,
+ cwd, MODULE_NAME, missing_file, cwd,
+ cwd, MODULE_NAME, missing_file, cwd,
+ cwd, MODULE_NAME, missing_file, cwd));
+ ASSERT_EQ(0, fclose(fp));
+
+ ASSERT_EQ(PAM_SUCCESS,
+ pam_start_confdir(service_file, user_name, &conv, ".", &pamh));
+ ASSERT_NE(NULL, pamh);
+ ASSERT_EQ(PAM_SUCCESS, pam_authenticate(pamh, 0));
+ ASSERT_EQ(PAM_SUCCESS, pam_setcred(pamh, 0));
+ ASSERT_EQ(PAM_SUCCESS, pam_acct_mgmt(pamh, 0));
+ ASSERT_EQ(PAM_MODULE_UNKNOWN, pam_chauthtok(pamh, 0));
+ ASSERT_EQ(PAM_MODULE_UNKNOWN, pam_open_session(pamh, 0));
+ ASSERT_EQ(PAM_MODULE_UNKNOWN, pam_close_session(pamh, 0));
+ ASSERT_EQ(PAM_SUCCESS, pam_end(pamh, 0));
+ pamh = NULL;
+
+ /* successok -> PAM_SUCCESS */
+ ASSERT_NE(NULL, fp = fopen(service_file, "w"));
+ ASSERT_LT(0, fprintf(fp, "#%%PAM-1.0\n"
+ "auth required %s/.libs/%s.so successok file=%s\n"
+ "account required %s/.libs/%s.so successok file=%s\n"
+ "password required %s/.libs/%s.so successok file=%s\n"
+ "session required %s/.libs/%s.so successok file=%s\n",
+ cwd, MODULE_NAME, missing_file,
+ cwd, MODULE_NAME, missing_file,
+ cwd, MODULE_NAME, missing_file,
+ cwd, MODULE_NAME, missing_file));
+ ASSERT_EQ(0, fclose(fp));
+
+ ASSERT_EQ(PAM_SUCCESS,
+ pam_start_confdir(service_file, user_name, &conv, ".", &pamh));
+ ASSERT_NE(NULL, pamh);
+ ASSERT_EQ(PAM_SUCCESS, pam_authenticate(pamh, 0));
+ ASSERT_EQ(PAM_SUCCESS, pam_setcred(pamh, 0));
+ ASSERT_EQ(PAM_SUCCESS, pam_acct_mgmt(pamh, 0));
+ ASSERT_EQ(PAM_MODULE_UNKNOWN, pam_chauthtok(pamh, 0));
+ ASSERT_EQ(PAM_MODULE_UNKNOWN, pam_open_session(pamh, 0));
+ ASSERT_EQ(PAM_MODULE_UNKNOWN, pam_close_session(pamh, 0));
+ ASSERT_EQ(PAM_SUCCESS, pam_end(pamh, 0));
+ pamh = NULL;
+
+ /* PAM_USER_UNKNOWN */
+ ASSERT_NE(NULL, fp = fopen(service_file, "w"));
+ ASSERT_LT(0, fprintf(fp, "#%%PAM-1.0\n"
+ "auth required %s/.libs/%s.so file=%s\n"
+ "account required %s/.libs/%s.so file=%s\n"
+ "password required %s/.libs/%s.so file=%s\n"
+ "session required %s/.libs/%s.so file=%s\n",
+ cwd, MODULE_NAME, empty_file,
+ cwd, MODULE_NAME, empty_file,
+ cwd, MODULE_NAME, empty_file,
+ cwd, MODULE_NAME, empty_file));
+ ASSERT_EQ(0, fclose(fp));
+
+ ASSERT_EQ(PAM_SUCCESS,
+ pam_start_confdir(service_file, user_name, &conv, ".", &pamh));
+ ASSERT_NE(NULL, pamh);
+ ASSERT_EQ(PAM_USER_UNKNOWN, pam_authenticate(pamh, 0));
+ ASSERT_EQ(PAM_PERM_DENIED, pam_setcred(pamh, 0));
+ ASSERT_EQ(PAM_USER_UNKNOWN, pam_acct_mgmt(pamh, 0));
+ ASSERT_EQ(PAM_MODULE_UNKNOWN, pam_chauthtok(pamh, 0));
+ ASSERT_EQ(PAM_MODULE_UNKNOWN, pam_open_session(pamh, 0));
+ ASSERT_EQ(PAM_MODULE_UNKNOWN, pam_close_session(pamh, 0));
+ ASSERT_EQ(PAM_SUCCESS, pam_end(pamh, 0));
+ pamh = NULL;
+
+ /* uid == 0 */
+ if ((pw = getpwuid(0)) != NULL) {
+ /* successok -> PAM_SUCCESS */
+ ASSERT_NE(NULL, fp = fopen(service_file, "w"));
+ ASSERT_LT(0, fprintf(fp, "#%%PAM-1.0\n"
+ "auth required %s/.libs/%s.so successok file=%s\n"
+ "account required %s/.libs/%s.so successok file=%s\n"
+ "password required %s/.libs/%s.so successok file=%s\n"
+ "session required %s/.libs/%s.so successok file=%s\n",
+ cwd, MODULE_NAME, empty_file,
+ cwd, MODULE_NAME, empty_file,
+ cwd, MODULE_NAME, empty_file,
+ cwd, MODULE_NAME, empty_file));
+ ASSERT_EQ(0, fclose(fp));
+
+ ASSERT_EQ(PAM_SUCCESS,
+ pam_start_confdir(service_file, pw->pw_name,
+ &conv, ".", &pamh));
+ ASSERT_NE(NULL, pamh);
+ ASSERT_EQ(PAM_SUCCESS, pam_authenticate(pamh, 0));
+ ASSERT_EQ(PAM_SUCCESS, pam_setcred(pamh, 0));
+ ASSERT_EQ(PAM_SUCCESS, pam_acct_mgmt(pamh, 0));
+ ASSERT_EQ(PAM_MODULE_UNKNOWN, pam_chauthtok(pamh, 0));
+ ASSERT_EQ(PAM_MODULE_UNKNOWN, pam_open_session(pamh, 0));
+ ASSERT_EQ(PAM_MODULE_UNKNOWN, pam_close_session(pamh, 0));
+ ASSERT_EQ(PAM_SUCCESS, pam_end(pamh, 0));
+ pamh = NULL;
+
+ /* PAM_SYSTEM_ERR */
+ ASSERT_NE(NULL, fp = fopen(service_file, "w"));
+ ASSERT_LT(0, fprintf(fp, "#%%PAM-1.0\n"
+ "auth required %s/.libs/%s.so file=%s\n"
+ "account required %s/.libs/%s.so file=%s\n"
+ "password required %s/.libs/%s.so file=%s\n"
+ "session required %s/.libs/%s.so file=%s\n",
+ cwd, MODULE_NAME, ".",
+ cwd, MODULE_NAME, ".",
+ cwd, MODULE_NAME, ".",
+ cwd, MODULE_NAME, "."));
+ ASSERT_EQ(0, fclose(fp));
+
+ ASSERT_EQ(PAM_SUCCESS,
+ pam_start_confdir(service_file, pw->pw_name,
+ &conv, ".", &pamh));
+ ASSERT_NE(NULL, pamh);
+ ASSERT_EQ(PAM_SYSTEM_ERR, pam_authenticate(pamh, 0));
+ ASSERT_EQ(PAM_PERM_DENIED, pam_setcred(pamh, 0));
+ ASSERT_EQ(PAM_SYSTEM_ERR, pam_acct_mgmt(pamh, 0));
+ ASSERT_EQ(PAM_MODULE_UNKNOWN, pam_chauthtok(pamh, 0));
+ ASSERT_EQ(PAM_MODULE_UNKNOWN, pam_open_session(pamh, 0));
+ ASSERT_EQ(PAM_MODULE_UNKNOWN, pam_close_session(pamh, 0));
+ ASSERT_EQ(PAM_SUCCESS, pam_end(pamh, 0));
+ pamh = NULL;
+ }
+
+ /* uid != 0 */
+ if (geteuid() != 0 && (pw = getpwuid(geteuid())) != NULL) {
+ /* PAM_AUTH_ERR */
+ ASSERT_NE(NULL, fp = fopen(service_file, "w"));
+ ASSERT_LT(0, fprintf(fp, "#%%PAM-1.0\n"
+ "auth required %s/.libs/%s.so file=%s\n"
+ "account required %s/.libs/%s.so file=%s\n"
+ "password required %s/.libs/%s.so file=%s\n"
+ "session required %s/.libs/%s.so file=%s\n",
+ cwd, MODULE_NAME, empty_file,
+ cwd, MODULE_NAME, empty_file,
+ cwd, MODULE_NAME, empty_file,
+ cwd, MODULE_NAME, empty_file));
+ ASSERT_EQ(0, fclose(fp));
+
+ ASSERT_EQ(PAM_SUCCESS,
+ pam_start_confdir(service_file, pw->pw_name,
+ &conv, ".", &pamh));
+ ASSERT_NE(NULL, pamh);
+ ASSERT_EQ(PAM_AUTH_ERR, pam_authenticate(pamh, 0));
+ ASSERT_EQ(PAM_PERM_DENIED, pam_setcred(pamh, 0));
+ ASSERT_EQ(PAM_AUTH_ERR, pam_acct_mgmt(pamh, 0));
+ ASSERT_EQ(PAM_MODULE_UNKNOWN, pam_chauthtok(pamh, 0));
+ ASSERT_EQ(PAM_MODULE_UNKNOWN, pam_open_session(pamh, 0));
+ ASSERT_EQ(PAM_MODULE_UNKNOWN, pam_close_session(pamh, 0));
+ ASSERT_EQ(PAM_SUCCESS, pam_end(pamh, 0));
+ pamh = NULL;
+ }
+
+ ASSERT_EQ(0, unlink(service_file));
+
+ return 0;
+}
--
ldv
4 years, 1 month