pam_canonicalize_user: new module to canonicalize user name

This module uses the name of the user obtained via pam_get_user(3)
as a key to query the password database, and replaces PAM_USER
with the pw_name value that has been returned.

The main usage scenario is systems where a user name is used in several
distinct authentication systems, some of them being case sensitive while
others are not.

* configure.ac (AC_CONFIG_FILES): Add
modules/pam_canonicalize_user/Makefile.
* doc/sag/pam_canonicalize_user.xml: New file.
* doc/sag/Linux-PAM_SAG.xml: Add a reference to
pam_canonicalize_user.xml.
* modules/Makefile.am (SUBDIRS): Add pam_canonicalize_user.
* modules/pam_canonicalize_user/Makefile.am: New file.
* modules/pam_canonicalize_user/README.xml: New file.
* modules/pam_canonicalize_user/pam_canonicalize_user.8.xml: New file.
* modules/pam_canonicalize_user/pam_canonicalize_user.c: New file.
* modules/pam_canonicalize_user/tst-pam_canonicalize_user: New file.
This commit is contained in:
Dmitry V. Levin 2023-11-07 08:00:00 +00:00
parent 6a4bf999a7
commit 2cae0f5c67
9 changed files with 304 additions and 2 deletions

View File

@ -768,7 +768,8 @@ AC_CONFIG_FILES([Makefile libpam/Makefile libpamc/Makefile libpamc/test/Makefile
Make.xml.rules \
modules/Makefile \
modules/pam_access/Makefile \
modules/pam_debug/Makefile modules/pam_deny/Makefile \
modules/pam_canonicalize_user/Makefile \
modules/pam_debug/Makefile modules/pam_deny/Makefile \
modules/pam_echo/Makefile modules/pam_env/Makefile \
modules/pam_faildelay/Makefile modules/pam_faillock/Makefile \
modules/pam_filter/Makefile modules/pam_filter/upperLOWER/Makefile \

View File

@ -378,6 +378,7 @@ session required pam_warn.so
coming with Linux-PAM.
</para>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="pam_access.xml"/>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="pam_canonicalize_user.xml"/>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="pam_debug.xml"/>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="pam_deny.xml"/>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="pam_echo.xml"/>
@ -516,4 +517,4 @@ TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
</programlisting>
</chapter>
</book>
</book>

View File

@ -0,0 +1,24 @@
<section xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="sag-pam_canonicalize_user">
<title>pam_canonicalize_user - get user name and canonicalize it</title>
<cmdsynopsis sepchar=" ">
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="../../modules/pam_canonicalize_user/pam_canonicalize_user.8.xml" xpointer='xpointer(id("pam_canonicalize_user-cmdsynopsis")/*)'/>
</cmdsynopsis>
<section xml:id="sag-pam_canonicalize_user-description">
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="../../modules/pam_canonicalize_user/pam_canonicalize_user.8.xml" xpointer='xpointer(id("pam_canonicalize_user-description")/*)'/>
</section>
<section xml:id="sag-pam_canonicalize_user-options">
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="../../modules/pam_canonicalize_user/pam_canonicalize_user.8.xml" xpointer='xpointer(id("pam_canonicalize_user-options")/*)'/>
</section>
<section xml:id="sag-pam_canonicalize_user-types">
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="../../modules/pam_canonicalize_user/pam_canonicalize_user.8.xml" xpointer='xpointer(id("pam_canonicalize_user-types")/*)'/>
</section>
<section xml:id="sag-pam_canonicalize_user-return_values">
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="../../modules/pam_canonicalize_user/pam_canonicalize_user.8.xml" xpointer='xpointer(id("pam_canonicalize_user-return_values")/*)'/>
</section>
<section xml:id="sag-pam_canonicalize_user-examples">
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="../../modules/pam_canonicalize_user/pam_canonicalize_user.8.xml" xpointer='xpointer(id("pam_canonicalize_user-examples")/*)'/>
</section>
<section xml:id="sag-pam_canonicalize_user-author">
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="../../modules/pam_canonicalize_user/pam_canonicalize_user.8.xml" xpointer='xpointer(id("pam_canonicalize_user-author")/*)'/>
</section>
</section>

View File

@ -44,6 +44,7 @@ endif
SUBDIRS := \
pam_access \
pam_canonicalize_user \
pam_debug \
pam_deny \
pam_echo \

View File

@ -0,0 +1,33 @@
CLEANFILES = *~
MAINTAINERCLEANFILES = $(MANS) README
EXTRA_DIST = $(XMLS)
if HAVE_DOC
dist_man_MANS = pam_canonicalize_user.8
endif
XMLS = README.xml pam_canonicalize_user.8.xml
dist_check_SCRIPTS = tst-pam_canonicalize_user
TESTS = $(dist_check_SCRIPTS)
securelibdir = $(SECUREDIR)
if HAVE_VENDORDIR
secureconfdir = $(VENDOR_SCONFIGDIR)
else
secureconfdir = $(SCONFIGDIR)
endif
AM_CFLAGS = -I$(top_srcdir)/libpam/include -I$(top_srcdir)/libpamc/include \
$(WARN_CFLAGS)
AM_LDFLAGS = -no-undefined -avoid-version -module
if HAVE_VERSIONING
AM_LDFLAGS += -Wl,--version-script=$(srcdir)/../modules.map
endif
securelib_LTLIBRARIES = pam_canonicalize_user.la
pam_canonicalize_user_la_LIBADD = $(top_builddir)/libpam/libpam.la
if ENABLE_REGENERATE_MAN
dist_noinst_DATA = README
-include $(top_srcdir)/Make.xml.rules
endif

View File

@ -0,0 +1,27 @@
<article xmlns="http://docbook.org/ns/docbook" version="5.0">
<info>
<title>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="pam_canonicalize_user.8.xml" xpointer='xpointer(id("pam_canonicalize_user-name")/*)'/>
</title>
</info>
<section>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="pam_canonicalize_user.8.xml" xpointer='xpointer(id("pam_canonicalize_user-description")/*)'/>
</section>
<section>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="pam_canonicalize_user.8.xml" xpointer='xpointer(id("pam_canonicalize_user-options")/*)'/>
</section>
<section>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="pam_canonicalize_user.8.xml" xpointer='xpointer(id("pam_canonicalize_user-examples")/*)'/>
</section>
<section>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="pam_canonicalize_user.8.xml" xpointer='xpointer(id("pam_canonicalize_user-author")/*)'/>
</section>
</article>

View File

@ -0,0 +1,137 @@
<refentry xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="pam_canonicalize_user">
<refmeta>
<refentrytitle>pam_canonicalize_user</refentrytitle>
<manvolnum>8</manvolnum>
<refmiscinfo class="source">Linux-PAM</refmiscinfo>
<refmiscinfo class="manual">Linux-PAM Manual</refmiscinfo>
</refmeta>
<refnamediv xml:id="pam_canonicalize_user-name">
<refname>pam_canonicalize_user</refname>
<refpurpose>Get user name and canonicalize it</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis xml:id="pam_canonicalize_user-cmdsynopsis" sepchar=" ">
<command>pam_canonicalize_user.so</command>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1 xml:id="pam_canonicalize_user-description">
<title>DESCRIPTION</title>
<para>
This PAM module uses the name of the user obtained via
<citerefentry>
<refentrytitle>pam_get_user</refentrytitle><manvolnum>3</manvolnum>
</citerefentry>
as a key to query the password database, and replaces
<emphasis>PAM_USER</emphasis> with the <emphasis>pw_name</emphasis> value
that has been returned.
</para>
</refsect1>
<refsect1 xml:id="pam_canonicalize_user-options">
<title>OPTIONS</title>
<para>This module does not recognise any options.</para>
</refsect1>
<refsect1 xml:id="pam_canonicalize_user-types">
<title>MODULE TYPES PROVIDED</title>
<para>Only the <option>auth</option> module type is provided.</para>
</refsect1>
<refsect1 xml:id="pam_canonicalize_user-return_values">
<title>RETURN VALUES</title>
<variablelist>
<varlistentry>
<term>PAM_IGNORE</term>
<listitem>
<para>The user name was set successfully.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>PAM_USER_UNKNOWN</term>
<listitem>
<para>The user was not found.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>PAM_SYSTEM_ERR</term>
<listitem>
<para>The application did not supply neither a user name nor a conversation method.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>PAM_INCOMPLETE</term>
<listitem>
<para>The conversation method supplied by the application is waiting for an event.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>PAM_CONV_ERR</term>
<listitem>
<para>The conversation method supplied by the application failed to obtain the user name.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>PAM_ABORT</term>
<listitem>
<para>Error resuming an old conversation.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>PAM_BUF_ERR</term>
<listitem>
<para>Memory buffer error.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1 xml:id="pam_canonicalize_user-examples">
<title>EXAMPLES</title>
<para>
Prepend the PAM auth stack with the following line to canonicalize
the user name before the authentication:
<programlisting>
auth required pam_canonicalize_user.so
</programlisting>
</para>
</refsect1>
<refsect1 xml:id="pam_get_user-see_also">
<title>SEE ALSO</title>
<para>
<citerefentry>
<refentrytitle>pam_get_user</refentrytitle><manvolnum>3</manvolnum>
</citerefentry>,
<citerefentry>
<refentrytitle>pam_get_item</refentrytitle><manvolnum>3</manvolnum>
</citerefentry>,
<citerefentry>
<refentrytitle>pam_set_item</refentrytitle><manvolnum>3</manvolnum>
</citerefentry>,
<citerefentry>
<refentrytitle>getpwnam</refentrytitle><manvolnum>3</manvolnum>
</citerefentry>,
<citerefentry>
<refentrytitle>pam.conf</refentrytitle><manvolnum>5</manvolnum>
</citerefentry>,
<citerefentry>
<refentrytitle>pam.d</refentrytitle><manvolnum>5</manvolnum>
</citerefentry>,
<citerefentry>
<refentrytitle>pam</refentrytitle><manvolnum>8</manvolnum>
</citerefentry>
</para>
</refsect1>
<refsect1 xml:id="pam_canonicalize_user-author">
<title>AUTHOR</title>
<para>
pam_canonicalize_user was written by Dmitry V. Levin &lt;ldv@strace.io&gt;.
</para>
</refsect1>
</refentry>

View File

@ -0,0 +1,76 @@
/*
* pam_canonicalize_user - get user name and canonicalize it
*
* Copyright (c) 2023 Dmitry V. Levin <ldv@strace.io>
*
* 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.
*/
#include "config.h"
#include <string.h>
#include <syslog.h>
#include <security/pam_modules.h>
#include <security/pam_modutil.h>
#include <security/pam_ext.h>
int
pam_sm_authenticate(pam_handle_t *pamh UNUSED, int flags UNUSED,
int argc UNUSED, const char **argv UNUSED)
{
const char *user;
int rc = pam_get_user(pamh, &user, 0);
if (rc != PAM_SUCCESS) {
pam_syslog(pamh, LOG_NOTICE, "cannot determine user name: %s",
pam_strerror(pamh, rc));
return rc == PAM_CONV_AGAIN ? PAM_INCOMPLETE : rc;
}
struct passwd *pw = pam_modutil_getpwnam(pamh, user);
if (!pw) {
pam_syslog(pamh, LOG_NOTICE, "user unknown");
return PAM_USER_UNKNOWN;
}
if (strcmp(user, pw->pw_name) == 0)
return PAM_IGNORE;
rc = pam_set_item(pamh, PAM_USER, pw->pw_name);
return rc == PAM_SUCCESS ? PAM_IGNORE : rc;
}
int
pam_sm_setcred(pam_handle_t *pamh UNUSED, int flags UNUSED,
int argc UNUSED, const char **argv UNUSED)
{
return PAM_IGNORE;
}

View File

@ -0,0 +1,2 @@
#!/bin/sh
../../tests/tst-dlopen .libs/pam_canonicalize_user.so