summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Olson <olson@cumulusnetworks.com>2017-06-15 12:47:29 -0700
committerDave Olson <olson@cumulusnetworks.com>2017-06-15 19:48:50 -0700
commite3408e0814517e6ad898c525125cf62aad40d60b (patch)
treed2e5f6eaca0ae5c2cfbce17024da7415743e0260
downloadlibnss-mapuser-e3408e0814517e6ad898c525125cf62aad40d60b.tar.gz
libnss-mapuser-e3408e0814517e6ad898c525125cf62aad40d60b.zip
Initial version of libnss-mapuser package
See README for details
-rw-r--r--.gitignore3
-rw-r--r--AUTHORS2
-rw-r--r--LICENSE249
-rw-r--r--Makefile52
-rw-r--r--README52
-rw-r--r--debian/README.source10
-rw-r--r--debian/changelog8
-rw-r--r--debian/compat1
-rw-r--r--debian/control16
-rw-r--r--debian/copyright24
-rw-r--r--debian/libnss-mapuser.lintian-overrides10
-rw-r--r--debian/libnss-mapuser.postinst45
-rw-r--r--debian/libnss-mapuser.prerm9
-rw-r--r--debian/libnss-mapuser.symbols5
-rw-r--r--debian/mapuser6
-rwxr-xr-xdebian/rules24
-rw-r--r--debian/source/format1
-rw-r--r--map_common.c265
-rw-r--r--map_common.h60
-rw-r--r--mapuser_nss.conf32
-rw-r--r--nss_mapname.c75
-rw-r--r--nss_mapuid.c221
-rwxr-xr-xpam_script_ses_close62
-rwxr-xr-xpam_script_ses_open62
24 files changed, 1294 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..794e7a1
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+*.o
+*.so
+.*.swp
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..1c2cce9
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,2 @@
+Author:
+ Dave Olson <olson@cumulusnetworks.com>
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..665d53a
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,249 @@
+GNU GENERAL PUBLIC LICENSE
+
+Version 2, June 1991
+
+Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+
+Everyone is permitted to copy and distribute verbatim copies of this license
+document, but changing it is not allowed.
+
+Preamble
+
+The licenses for most software are designed to take away your freedom to share and
+change it. By contrast, the GNU General Public License is intended to guarantee your
+freedom to share and change free software--to make sure the software is free for all
+its users. This General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to using it.
+(Some other Free Software Foundation software is covered by the GNU Lesser General
+Public License instead.) You can apply it to your programs, too.
+
+When we speak of free software, we are referring to freedom, not price. Our General
+Public Licenses are designed to make sure that you have the freedom to distribute
+copies of free software (and charge for this service if you wish), that you receive
+source code or can get it if you want it, that you can change the software or use
+pieces of it in new free programs; and that you know you can do these things.
+
+To protect your rights, we need to make restrictions that forbid anyone to deny you
+these rights or to ask you to surrender the rights. These restrictions translate to
+certain responsibilities for you if you distribute copies of the software, or if you
+modify it.
+
+For example, if you distribute copies of such a program, whether gratis or for a
+fee, you must give the recipients all the rights that you have. You must make sure
+that they, too, receive or can get the source code. And you must show them these
+terms so they know their rights.
+
+We protect your rights with two steps: (1) copyright the software, and (2) offer you
+this license which gives you legal permission to copy, distribute and/or modify the
+software.
+
+Also, for each author's protection and ours, we want to make certain that everyone
+understands that there is no warranty for this free software. If the software is
+modified by someone else and passed on, we want its recipients to know that what
+they have is not the original, so that any problems introduced by others will not
+reflect on the original authors' reputations.
+
+Finally, any free program is threatened constantly by software patents. We wish to
+avoid the danger that redistributors of a free program will individually obtain
+patent licenses, in effect making the program proprietary. To prevent this, we have
+made it clear that any patent must be licensed for everyone's free use or not
+licensed at all.
+
+The precise terms and conditions for copying, distribution and modification follow.
+
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+0. This License applies to any program or other work which contains a notice placed
+by the copyright holder saying it may be distributed under the terms of this General
+Public License. The "Program", below, refers to any such program or work, and a
+"work based on the Program" means either the Program or any derivative work under
+copyright law: that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another language.
+(Hereinafter, translation is included without limitation in the term
+"modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not covered by this
+License; they are outside its scope. The act of running the Program is not
+restricted, and the output from the Program is covered only if its contents
+constitute a work based on the Program (independent of having been made by running
+the Program). Whether that is true depends on what the Program does.
+
+1. You may copy and distribute verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and appropriately publish
+on each copy an appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any warranty; and
+give any other recipients of the Program a copy of this License along with the
+Program.
+
+You may charge a fee for the physical act of transferring a copy, and you may at
+your option offer warranty protection in exchange for a fee.
+
+2. You may modify your copy or copies of the Program or any portion of it, thus
+forming a work based on the Program, and copy and distribute such modifications or
+work under the terms of Section 1 above, provided that you also meet all of these
+conditions:
+
+ a) You must cause the modified files to carry prominent notices stating that you
+ changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in whole or in
+ part contains or is derived from the Program or any part thereof, to be licensed
+ as a whole at no charge to all third parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively when run, you
+ must cause it, when started running for such interactive use in the most
+ ordinary way, to print or display an announcement including an appropriate
+ copyright notice and a notice that there is no warranty (or else, saying that
+ you provide a warranty) and that users may redistribute the program under these
+ conditions, and telling the user how to view a copy of this License. (Exception:
+ if the Program itself is interactive but does not normally print such an
+ announcement, your work based on the Program is not required to print an
+ announcement.)
+
+These requirements apply to the modified work as a whole. If identifiable sections
+of that work are not derived from the Program, and can be reasonably considered
+independent and separate works in themselves, then this License, and its terms, do
+not apply to those sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based on the
+Program, the distribution of the whole must be on the terms of this License, whose
+permissions for other licensees extend to the entire whole, and thus to each and
+every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest your rights to
+work written entirely by you; rather, the intent is to exercise the right to control
+the distribution of derivative or collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program with the
+Program (or with a work based on the Program) on a volume of a storage or
+distribution medium does not bring the other work under the scope of this License.
+
+3. You may copy and distribute the Program (or a work based on it, under Section 2)
+in object code or executable form under the terms of Sections 1 and 2 above provided
+that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable source code,
+ which must be distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three years, to give
+ any third party, for a charge no more than your cost of physically performing
+ source distribution, a complete machine-readable copy of the corresponding
+ source code, to be distributed under the terms of Sections 1 and 2 above on a
+ medium customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer to distribute
+ corresponding source code. (This alternative is allowed only for noncommercial
+ distribution and only if you received the program in object code or executable
+ form with such an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for making
+modifications to it. For an executable work, complete source code means all the
+source code for all modules it contains, plus any associated interface definition
+files, plus the scripts used to control compilation and installation of the
+executable. However, as a special exception, the source code distributed need not
+include anything that is normally distributed (in either source or binary form) with
+the major components (compiler, kernel, and so on) of the operating system on which
+the executable runs, unless that component itself accompanies the executable.
+
+If distribution of executable or object code is made by offering access to copy from
+a designated place, then offering equivalent access to copy the source code from the
+same place counts as distribution of the source code, even though third parties are
+not compelled to copy the source along with the object code.
+
+4. You may not copy, modify, sublicense, or distribute the Program except as
+expressly provided under this License. Any attempt otherwise to copy, modify,
+sublicense or distribute the Program is void, and will automatically terminate your
+rights under this License. However, parties who have received copies, or rights,
+from you under this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+5. You are not required to accept this License, since you have not signed it.
+However, nothing else grants you permission to modify or distribute the Program or
+its derivative works. These actions are prohibited by law if you do not accept this
+License. Therefore, by modifying or distributing the Program (or any work based on
+the Program), you indicate your acceptance of this License to do so, and all its
+terms and conditions for copying, distributing or modifying the Program or works
+based on it.
+
+6. Each time you redistribute the Program (or any work based on the Program), the
+recipient automatically receives a license from the original licensor to copy,
+distribute or modify the Program subject to these terms and conditions. You may not
+impose any further restrictions on the recipients' exercise of the rights granted
+herein. You are not responsible for enforcing compliance by third parties to this
+License.
+
+7. If, as a consequence of a court judgment or allegation of patent infringement or
+for any other reason (not limited to patent issues), conditions are imposed on you
+(whether by court order, agreement or otherwise) that contradict the conditions of
+this License, they do not excuse you from the conditions of this License. If you
+cannot distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may not
+distribute the Program at all. For example, if a patent license would not permit
+royalty-free redistribution of the Program by all those who receive copies directly
+or indirectly through you, then the only way you could satisfy both it and this
+License would be to refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under any particular
+circumstance, the balance of the section is intended to apply and the section as a
+whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any patents or other
+property right claims or to contest validity of any such claims; this section has
+the sole purpose of protecting the integrity of the free software distribution
+system, which is implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed through that system
+in reliance on consistent application of that system; it is up to the author/donor
+to decide if he or she is willing to distribute software through any other system
+and a licensee cannot impose that choice.
+
+This section is intended to make thoroughly clear what is believed to be a
+consequence of the rest of this License.
+
+8. If the distribution and/or use of the Program is restricted in certain countries
+either by patents or by copyrighted interfaces, the original copyright holder who
+places the Program under this License may add an explicit geographical distribution
+limitation excluding those countries, so that distribution is permitted only in or
+among countries not thus excluded. In such case, this License incorporates the
+limitation as if written in the body of this License.
+
+9. The Free Software Foundation may publish revised and/or new versions of the
+General Public License from time to time. Such new versions will be similar in
+spirit to the present version, but may differ in detail to address new problems or
+concerns.
+
+Each version is given a distinguishing version number. If the Program specifies a
+version number of this License which applies to it and "any later version", you have
+the option of following the terms and conditions either of that version or of any
+later version published by the Free Software Foundation. If the Program does not
+specify a version number of this License, you may choose any version ever published
+by the Free Software Foundation.
+
+10. If you wish to incorporate parts of the Program into other free programs whose
+distribution conditions are different, write to the author to ask for permission.
+For software which is copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our decision will be
+guided by the two goals of preserving the free status of all derivatives of our free
+software and of promoting the sharing and reuse of software generally.
+
+NO WARRANTY
+
+11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE
+PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN
+WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS"
+WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH
+YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY
+SERVICING, REPAIR OR CORRECTION.
+
+12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY
+COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM
+AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL,
+INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE
+OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE
+WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+END OF TERMS AND CONDITIONS
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..2ff73a6
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,52 @@
+
+NAME_SOURCE=nss_mapname.c map_common.c
+NSSNAMELIB =libnss_mapname.so.2
+UID_SOURCE=nss_mapuid.c map_common.c
+NSSUIDLIB =libnss_mapuid.so.2
+
+# set to x86_64-linux-gnu, arm-linux-gnueabi, etc. by packaging tools
+# If not set, just install directly to /lib
+LIBDIR=/lib/${DEB_TARGET_GNU_TYPE}
+
+CC = gcc
+
+ifneq (,$(filter noopt,$(DEB_BUILD_OPTIONS)))
+ OPTFLAGS = -O2
+else
+ OPTFLAGS = -g3 -O0
+endif
+ifeq (,$(filter nostrip,$(DEB_BUILD_OPTIONS)))
+ STRIP = strip
+ FVISIBILITY = -fvisibility=hidden
+else
+ STRIP=echo Nostrip
+ FVISIBILITY = -fvisibility=default
+endif
+
+CPPFLAGS = -D_FORTIFY_SOURCE=2
+CFLAGS = $(CPPFLAGS) ${OPTFLAGS} -fPIC -fstack-protector-strong \
+ -Wformat -Werror=format-security -Wall $(FVISIBILITY)
+LDFLAGS = -shared -fPIC -DPIC \
+ -Wl,-z -Wl,relro -Wl,-z -Wl,now -Wl,-soname -Wl,$@
+
+all: $(NSSNAMELIB) $(NSSUIDLIB)
+
+$(NSSUIDLIB): $(UID_SOURCE:.c=.o)
+ $(CC) $(LDFLAGS) $^ -o $@
+
+$(NSSNAMELIB): $(NAME_SOURCE:.c=.o)
+ $(CC) $(LDFLAGS) $^ -o $@
+
+install: all
+ install -m 755 -d $(DESTDIR)/$(LIBDIR) $(DESTDIR)/etc
+ install -m 644 $(NSSNAMELIB) $(NSSUIDLIB) $(DESTDIR)$(LIBDIR)
+ $(STRIP) --strip-all --keep-symbol=_nss_mapname_getpwnam_r \
+ $(DESTDIR)$(LIBDIR)/${NSSNAMELIB}
+ $(STRIP) --strip-all --keep-symbol=_nss_mapuid_getpwuid_r \
+ $(DESTDIR)$(LIBDIR)/${NSSUIDLIB}
+ install -m 644 mapuser_nss.conf $(DESTDIR)/etc/
+
+clean:
+ rm -f *.o $(NSSNAMELIB) $(NSSUIDLIB)
+
+.PHONY: all install clean distclean
diff --git a/README b/README
new file mode 100644
index 0000000..eb3ac40
--- /dev/null
+++ b/README
@@ -0,0 +1,52 @@
+libnss_mapuser v1.0.1
+Dave Olson <olson@cumulusnetworks.com>
+June 15, 2017
+
+This NSS module has one and only one purpose. It allows getpwnam() and getpwuid()
+lookups for arbitrary usernames, with explict matching to a named account.
+The mapped lookup is only done if the requested name is not already present
+in /etc/passwd (no other lookup, such as LDAP, is done).
+
+It exists as two separate plugins, because the name lookup should be last
+in the passwd database lookup in nsswitch.conf (so any other valid lookup
+matches first), while the UID lookup should be first, so that a lookup on
+the UID of the mapped user returns the mapped name.
+
+It's intended for use with authentication mechanisms such as RADIUS, where
+it is not possible to determine if a username is valid without authenticating
+at the same time.
+
+The mapping is done to a single account specified in the configuration
+file /etc/mapuser_nss.conf.
+
+The returned passwd field is always filled in as 'x', so that authentication
+of the base account is not possible through PAM. Only the mapped accounts
+are able to login, typically through PAM, such as pam_radius.so.
+
+The GECOS field is filled in as 'USERNAME mapped user' and the home directory
+uses the same path as the user from /etc/passwd, with the last component replaced
+by the passed in username. The uid, gid, and shell fields are copied directly
+from the map_user account passwd dataa.
+
+For example, if the passed in username is 'olsonr', the result of running
+ getent -s mapuser passwd olsonr
+will be something like this:
+ olsonr:x:1017:1017:olsonr mapped user:/home/olsonr:/bin/bash
+if the map_user field is set to radius_user, and the radius_user entry in
+/etc/passwd is:
+ radius_user:x:1017:1017:radius_user,,,:/home/radius_user:/bin/bash
+
+This package will create the radius_user account with adduser if it does not
+already exist, and that is the default mapping in the configuration, and will
+add the group radius_users with the addgroup command.
+
+The mapping can be changed in the configuration file /etc/mapuser_nss.conf.
+In that case, the account must already exist, or should be created with
+a command similar to:
+ adduser --quiet --firstuid 1000 --disabled-login --ingroup GROUP \
+ --gecos "radius user" USERNAME
+
+On install, this package will edit /etc/nsswitch.conf to add the two plugins,
+so that it looks similar to:
+ passwd: mapuid compat mapname
+if these plugins are not already present.
diff --git a/debian/README.source b/debian/README.source
new file mode 100644
index 0000000..d19f825
--- /dev/null
+++ b/debian/README.source
@@ -0,0 +1,10 @@
+libnss-mapuser for Debian
+-------------------------
+Build this package with:
+$ debian/rules binary
+or
+$ DEB_BUILD_PROG_OPTS="-S" debian/rules arch-build
+
+
+ -- Dave Olson <olson@cumulusnetworks.com> Tue, 3 Nov 2015 15:58:30 -0700
+
diff --git a/debian/changelog b/debian/changelog
new file mode 100644
index 0000000..93d0996
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,8 @@
+libnss-mapuser (1.0.0) unstable; urgency=low
+
+ * Initial version to do successful NSS lookups on any username,
+ and matching uid lookups back to the original name.
+ Used for RADIUS users, so they do not need to be in local files
+ (or LDAP, etc.)
+
+ -- dev-support <dev-support@cumulusnetworks.com> Thu, 25 May 2017 20:59:49 -0700
diff --git a/debian/compat b/debian/compat
new file mode 100644
index 0000000..ec63514
--- /dev/null
+++ b/debian/compat
@@ -0,0 +1 @@
+9
diff --git a/debian/control b/debian/control
new file mode 100644
index 0000000..b727069
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,16 @@
+Source: libnss-mapuser
+Priority: optional
+Maintainer: dev-support <dev-support@cumulusnetworks.com>
+Build-Depends: debhelper (>= 9), dpkg-dev (>= 1.16.1), git
+Section: libs
+Standards-Version: 3.9.6
+Homepage: http://www.cumulusnetworks.com
+
+Package: libnss-mapuser
+Architecture: any
+Depends: ${shlibs:Depends}, adduser
+Description: NSS modules to map any requested username to a local account
+ Performs getpwname and getpwuid lookups via NSS for systems like RADIUS
+ where it is not possible to do a username lookup without authentication
+ (with a password or similar). Used to allow ssh and other login
+ mechanisms via RADIUS without having a local account.
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 0000000..cc8f9f1
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,24 @@
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: libnss-mapuser
+Source: http://www.cumulusnetworks.com
+
+License: GPL-2+
+ This package is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+ .
+ This package is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+ .
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>
+ .
+ On Debian systems, the complete text of the GNU General
+ Public License version 2 can be found in "/usr/share/common-licenses/GPL-2".
+
+Files: *
+License: GPL-2+
+Copyright: 2017 Cumulus Networks, Inc. All rights reserved.,
diff --git a/debian/libnss-mapuser.lintian-overrides b/debian/libnss-mapuser.lintian-overrides
new file mode 100644
index 0000000..5217b23
--- /dev/null
+++ b/debian/libnss-mapuser.lintian-overrides
@@ -0,0 +1,10 @@
+libnss-mapuser: native-package-with-dash-version
+libnss-mapuser: package-name-doesnt-match-sonames libnss-mapname2 libnss-mapuid2
+libnss-mapuser: new-package-should-close-itp-bug
+# messages say "source", but using "source" causes "malformed" warning.
+# So these don't actually work, but leaving them here to document the intent
+libnss-mapuser binary: diff-contains-git-control-dir .git
+libnss-mapuser binary: unsupported-source-format 3.0 (git)
+# we don't use misc-depends, and adding it produces a build warning
+# about it not being needed
+libnss-mapuser binary: debhelper-but-no-misc-depends libnss-mapuser
diff --git a/debian/libnss-mapuser.postinst b/debian/libnss-mapuser.postinst
new file mode 100644
index 0000000..b46e66d
--- /dev/null
+++ b/debian/libnss-mapuser.postinst
@@ -0,0 +1,45 @@
+#!/bin/sh
+# postinst script for libnss-mapuser
+#
+# see: dh_installdeb(1)
+
+set -e
+
+case "$1" in
+ configure)
+ # Add mapname and user to /etc/nsswitch.conf, since it's necessary
+ # for this package. uid must be first, and mapname must be last
+ # so uids for mapped users return the mapped name, and on the name,
+ # we only want to map if no other matches were found
+ ( set +e;
+ rgroup=radius_users
+ if [ -e "/etc/nsswitch.conf" ]; then
+ sed -i -e '/ mapname/b' \
+ -e '/^passwd/s/[ \t][ \t]*/&mapuid /' \
+ -e '/^passwd.*#/s/#.*/ mapname &/' \
+ -e '/^passwd[^#]*$/s/$/ mapname &/' \
+ /etc/nsswitch.conf
+ fi
+ addgroup --quiet $rgroup 2>&1 | grep -v 'already exists'
+ adduser --quiet --firstuid 1000 --disabled-login --ingroup $rgroup \
+ --gecos "radius user" radius_user 2>&1 | grep -v 'already exists'
+ exit 0
+ )
+ ;;
+
+ abort-upgrade|abort-remove|abort-deconfigure)
+ ;;
+
+ *)
+ echo "postinst called with unknown argument \`$1'" >&2
+ exit 1
+ ;;
+esac
+
+# needed for install, upgrade, remove, and purge, including aborts
+pam-auth-update --package
+
+
+#DEBHELPER#
+
+exit 0
diff --git a/debian/libnss-mapuser.prerm b/debian/libnss-mapuser.prerm
new file mode 100644
index 0000000..c9bb6b1
--- /dev/null
+++ b/debian/libnss-mapuser.prerm
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+set -e
+
+if [ "$1" = remove ]; then
+ pam-auth-update --package --remove mapuser
+fi
+
+#DEBHELPER#
diff --git a/debian/libnss-mapuser.symbols b/debian/libnss-mapuser.symbols
new file mode 100644
index 0000000..2254c2e
--- /dev/null
+++ b/debian/libnss-mapuser.symbols
@@ -0,0 +1,5 @@
+libnss_mapname.so.2 libnss-mapuser #MINVER#
+ _nss_mapname_getpwnam_r@Base 1.0.0
+
+libnss_mapuid.so.2 libnss-mapuser #MINVER#
+ _nss_mapuid_getpwuid_r@Base 1.0.0
diff --git a/debian/mapuser b/debian/mapuser
new file mode 100644
index 0000000..69d2137
--- /dev/null
+++ b/debian/mapuser
@@ -0,0 +1,6 @@
+Name: libnss-mapuser uses this to maintain the session uid => user mapping
+Default: yes
+Priority: 257
+Session-Type: Additional
+Session:
+ optional pam_script.so dir=/usr/share/mapuser
diff --git a/debian/rules b/debian/rules
new file mode 100755
index 0000000..ed7dbc0
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,24 @@
+#!/usr/bin/make -f
+# See debhelper(7) (uncomment to enable)
+# output every command that modifies files on the build system.
+DH_VERBOSE = 1
+
+# see EXAMPLES in dpkg-buildflags(1) and read /usr/share/dpkg/*
+DPKG_EXPORT_BUILDFLAGS = 1
+include /usr/share/dpkg/default.mk
+
+# see FEATURE AREAS in dpkg-buildflags(1)
+export DEB_BUILD_MAINT_OPTIONS = hardening=+all
+
+%:
+ dh $@
+
+# No configuration needed
+override_dh_auto_configure:
+
+override_dh_install:
+ dh_installdirs /usr/share/pam-configs /usr/share/mapuser
+ install -p -m 755 pam_script_ses* debian/libnss-mapuser/usr/share/mapuser
+ install -p -m 444 debian/mapuser \
+ debian/libnss-mapuser/usr/share/pam-configs/
+ dh_install
diff --git a/debian/source/format b/debian/source/format
new file mode 100644
index 0000000..af745b3
--- /dev/null
+++ b/debian/source/format
@@ -0,0 +1 @@
+3.0 (git)
diff --git a/map_common.c b/map_common.c
new file mode 100644
index 0000000..c274853
--- /dev/null
+++ b/map_common.c
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2017 Cumulus Networks, Inc.
+ * All rights reserved.
+ * Author: Dave Olson <olson@cumulusnetworks.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program - see the file COPYING.
+ */
+
+/*
+ * This is common code used by the nss_mapuser and nss_mapuid NSS
+ * plugin library. None of it's symbols are public, they are stripped
+ * during the linking phase (made internal only).
+ */
+
+
+#include "map_common.h"
+#include <sys/stat.h>
+
+static const char config_file[] = "/etc/mapuser_nss.conf";
+
+#define DEF_MIN_UID 1001 /* fail lookups on uid's below this value */
+
+/* set from configuration file parsing; stripped from exported symbols
+ * in build, so local to the shared lib. */
+char *exclude_users; /* don't lookup these users */
+char *mappeduser;
+uid_t min_uid = DEF_MIN_UID;
+int debug;
+
+static int conf_parsed = 0;
+static const char *libname; /* for syslogs, set in each library */
+
+/* reset all config variables when we are going to re-parse */
+static void
+reset_config(void)
+{
+ /* reset the config variables that we use, freeing memory where needed */
+ if(exclude_users) {
+ (void)free(exclude_users);
+ exclude_users = NULL;
+ }
+ if(mappeduser) {
+ (void)free(mappeduser);
+ mappeduser = NULL;
+ }
+ debug = 0;
+ min_uid = DEF_MIN_UID;
+}
+
+/*
+ * return 0 on succesful parsing (at least no hard errors), 1 if
+ * an error, and 2 if already parsed and no change to config file
+ */
+int
+nss_mapuser_config(int *errnop, const char *lname)
+{
+ FILE *conf;
+ char lbuf[256];
+ static struct stat lastconf;
+
+ if(conf_parsed) {
+ struct stat st, *lst = &lastconf;
+ /*
+ * check to see if the config file(s) have changed since last time,
+ * in case we are part of a long-lived daemon. If any changed,
+ * reparse. If not, return the appropriate status (err or OK)
+ */
+ if (stat(config_file, &st) && st.st_ino == lst->st_ino &&
+ st.st_mtime == lst->st_mtime && st.st_ctime == lst->st_ctime)
+ return 2; /* nothing to reparse */
+ reset_config();
+ conf_parsed = 0;
+ if (debug && conf_parsed)
+ syslog(LOG_DEBUG, "%s: Configuration file changed, re-initializing",
+ libname);
+ }
+
+ libname = lname;
+
+ conf = fopen(config_file, "r");
+ if(conf == NULL) {
+ *errnop = errno;
+ syslog(LOG_NOTICE, "%s: can't open config file %s: %m",
+ libname, config_file);
+ return 1;
+ }
+ if (fstat(fileno(conf), &lastconf) != 0)
+ memset(&lastconf, 0, sizeof lastconf); /* avoid stale data, no warning */
+
+ while(fgets(lbuf, sizeof lbuf, conf)) {
+ if(*lbuf == '#' || isspace(*lbuf))
+ continue; /* skip comments, white space lines, etc. */
+ strtok(lbuf, " \t\n\r\f"); /* terminate buffer at first whitespace */
+ if(!strncmp(lbuf, "debug=", 6))
+ debug = strtoul(lbuf+6, NULL, 0);
+ else if(!strncmp(lbuf, "exclude_users=", 14)) {
+ /*
+ * Don't lookup users in this comma-separated list for both
+ * robustness and performnce. Typically root and other commonly
+ * used local users. If set, we also look up the uids
+ * locally, and won't do remote lookup on those uids either.
+ */
+ exclude_users = strdup(lbuf+14);
+ }
+ else if(!strncmp(lbuf, "mapped_user=", 12)) {
+ /* the user we are mapping to */
+ mappeduser = strdup(lbuf+12);
+ }
+ else if(!strncmp(lbuf, "min_uid=", 8)) {
+ /*
+ * Don't lookup uids that are local, typically set to either
+ * 0 or smallest always local user's uid
+ */
+ unsigned long uid;
+ char *valid;
+ uid = strtoul(lbuf+8, &valid, 0);
+ if (valid > (lbuf+8))
+ min_uid = (uid_t)uid;
+ }
+ else if(debug) /* ignore unrecognized lines, unless debug on */
+ syslog(LOG_WARNING, "%s: unrecognized parameter: %s",
+ libname, lbuf);
+ }
+ fclose(conf);
+ conf_parsed = 1;
+
+ return mappeduser ? 0 : 1; /* can't do anything without this */
+}
+
+/*
+ * copy a passwd structure and it's strings, using the provided buffer
+ * for the strings.
+ * usename is used for the new pw_name, the last part of the homedir,
+ * and the GECOS field.
+ * For strings, if pointer is null, use an empty string.
+ * Returns 0 if everything fit, otherwise 1.
+ */
+int
+pwcopy(char *buf, size_t len, struct passwd *srcpw, struct passwd *destpw,
+ const char *usename)
+{
+ int needlen, cnt, origlen = len;
+ char *shell;
+
+ if(!mappeduser) {
+ if(debug)
+ syslog(LOG_DEBUG, "%s: empty mapped_user, failing", libname);
+ return 1;
+ }
+ if(!usename) { /* this should never happen */
+ if(debug)
+ syslog(LOG_DEBUG, "%s: empty username, failing", libname);
+ return 1;
+ }
+
+ needlen = 2 * strlen(usename) + 2 + /* pw_name and pw_gecos */
+ srcpw->pw_dir ? strlen(srcpw->pw_dir) + 1 : 1 +
+ srcpw->pw_shell ? strlen(srcpw->pw_shell) + 1 : 1 +
+ 2 + /* for 'x' in the passwd field */
+ 12; /* for the "Mapped user" in the gecos field */
+ if(needlen > len) {
+ if(debug)
+ syslog(LOG_DEBUG, "%s provided password buffer too small (%ld<%d)",
+ libname, (long)len, needlen);
+ return 1;
+ }
+
+ destpw->pw_uid = srcpw->pw_uid;
+ destpw->pw_gid = srcpw->pw_gid;
+
+ cnt = snprintf(buf, len, "%s", usename);
+ destpw->pw_name = buf;
+ cnt++; /* allow for null byte also */
+ buf += cnt;
+ len -= cnt;
+ cnt = snprintf(buf, len, "%s", "x");
+ destpw->pw_passwd = buf;
+ cnt++;
+ buf += cnt;
+ len -= cnt;
+ cnt = snprintf(buf, len, "%s", srcpw->pw_shell ? srcpw->pw_shell : "");
+ destpw->pw_shell = buf;
+ shell = strrchr(buf, '/');
+ shell = shell ? shell+1 : buf;
+ cnt++;
+ buf += cnt;
+ len -= cnt;
+ cnt = snprintf(buf, len, "%s mapped user", usename);
+ destpw->pw_gecos = buf;
+ cnt++;
+ buf += cnt;
+ len -= cnt;
+ if (usename) {
+ char *slash, dbuf[strlen(srcpw->pw_dir) + strlen(usename)];
+ snprintf(dbuf, sizeof dbuf, "%s", srcpw->pw_dir ? srcpw->pw_dir : "");
+ slash = strrchr(dbuf, '/');
+ if (slash) {
+ slash++;
+ snprintf(slash, sizeof dbuf - (slash-dbuf), "%s", usename);
+ }
+ cnt = snprintf(buf, len, "%s", dbuf);
+ }
+ else
+ cnt = snprintf(buf, len, "%s", srcpw->pw_dir ? srcpw->pw_dir : "");
+ destpw->pw_dir = buf;
+ cnt++;
+ buf += cnt;
+ len -= cnt;
+ if(len < 0) {
+ if(debug)
+ syslog(LOG_DEBUG, "%s provided password buffer too small (%ld<%d)",
+ libname, (long)origlen, origlen-(int)len);
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * This passes in a fixed
+ * name for UID lookups, where we have the mapped name from the
+ * map file.
+ * returns 0 on success
+ */
+int
+get_pw_mapuser(const char *name, struct pwbuf *pb)
+{
+ FILE *pwfile;
+ struct passwd *ent;
+ int ret = 1;
+
+
+ pwfile = fopen("/etc/passwd", "r");
+ if(!pwfile) {
+ syslog(LOG_WARNING, "%s: failed to open /etc/passwd: %m",
+ libname);
+ return 1;
+ }
+
+ pb->pw->pw_name = NULL; /* be paranoid */
+ for(ret = 1; ret && (ent = fgetpwent(pwfile)); ) {
+ if(!ent->pw_name)
+ continue; /* shouldn't happen */
+ if(!strcmp(ent->pw_name, mappeduser)) {
+ ret = pwcopy(pb->buf, pb->buflen, ent, pb->pw, name);
+ break;
+ }
+ }
+ fclose(pwfile);
+ if(ret)
+ *pb->errnop = ERANGE;
+
+ return ret;
+}
diff --git a/map_common.h b/map_common.h
new file mode 100644
index 0000000..b4213a5
--- /dev/null
+++ b/map_common.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2017 Cumulus Networks, Inc.
+ * All rights reserved.
+ * Author: Dave Olson <olson@cumulusnetworks.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program - see the file COPYING.
+ */
+
+/*
+ * This is the header file for the common code used by the nss_mapuser and
+ * nss_mapuid NSS plugin library. None of it's symbols are public, they are
+ * stripped during the linking phase (made internal only).
+ */
+
+
+#include <string.h>
+#include <syslog.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <pwd.h>
+#include <errno.h>
+#include <ctype.h>
+#include <nss.h>
+
+
+/*
+ * pwbuf is used to reduce number of arguments passed around; the strings in
+ * the passwd struct need to point into this buffer.
+ */
+struct pwbuf {
+ char *name;
+ char *buf;
+ struct passwd *pw;
+ int *errnop;
+ size_t buflen;
+};
+
+/* configuration variables. */
+extern char *exclude_users;
+extern char *mappeduser;
+extern uid_t min_uid;
+extern int debug;
+
+extern int nss_mapuser_config(int *errnop, const char *lname);
+extern int pwcopy(char *buf, size_t len, struct passwd *srcpw, struct passwd *destpw,
+ const char *usename);
+extern int get_pw_mapuser(const char *name, struct pwbuf *pb);
+
diff --git a/mapuser_nss.conf b/mapuser_nss.conf
new file mode 100644
index 0000000..c422b3e
--- /dev/null
+++ b/mapuser_nss.conf
@@ -0,0 +1,32 @@
+# This file is part of the libnss-mapuser pacakge.
+# This file should be world readable. It does not contain any security
+# sensitive information.
+#
+# Edit /etc/nsswitch.conf to add mapuer to the passwd lookup, similar to this
+# where mapuser must be the be prior to compat, since uid lookups would
+# otherwise always match via compat
+# passwd: mapuser compat
+
+# if set, errors and other issues are logged with syslog
+# debug=1
+
+# min_uid is the minimum uid to lookup. Setting this to 0
+# means uid 0 (root) is never looked up, good for robustness and performance
+# Cumulus Linux ships with it set to 1001, so we never lookup system
+# users, or the standard "cumulus" account. You may want to change this
+# to the value of the radius_user account.
+min_uid=1001
+
+# This is a comma separated list of usernames that are never mapped
+# because they are standard accounts. They cause an early not found
+# return.
+#
+# "*" is not a wild card. While it's not a legal username, it turns out
+# that during pathname completion, bash can do an NSS lookup on "*"
+# To avoid server round trip delays, or worse, unreachable server delays
+# on filename completion, we include "*" in the exclusion list.
+exclude_users=root,cumulus,man,ntp,sshd,frr,snmp,nobody,*
+
+# Map all usernames to the radius_user account (use the uid, gid, shell, and
+# base of the home directory from the cumulus entry in /etc/passwd).
+mapped_user=radius_user
diff --git a/nss_mapname.c b/nss_mapname.c
new file mode 100644
index 0000000..ea9b7f2
--- /dev/null
+++ b/nss_mapname.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2017 Cumulus Networks, Inc.
+ * All rights reserved.
+ * Author: Dave Olson <olson@cumulusnetworks.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program - see the file COPYING.
+ */
+
+/*
+ * This plugin implements getpwnam_r for NSS to map any user
+ * name to a fixed account (from the configuration file). The
+ * fixed account is used to get the base of the home directory,
+ * and for the uid and gid. All other fields are replaced, and
+ * the password is always returned as 'x' (disabled). The assumption
+ * is that any authentication and authorization will be done via PAM
+ * using some mechanism other than the local password file.
+ *
+ * Because it will match any account, this should always be the
+ * last module in /etc/nsswitch.conf for the passwd entry
+ *
+ * The home dir returned is the mapped user homedir with the last component
+ * replaced with the username being looked up.
+ *
+ * See nss_mapuid.c for the matching getpwuid_r for UIDs.
+ */
+
+
+#include "map_common.h"
+
+
+static const char *nssname = "nss_mapuser"; /* for syslogs */
+
+/*
+ * This is an NSS entry point.
+ * We map any username given to the account listed in the configuration file
+ * We only fail if we can't read the configuration file, or the username
+ * in the configuration file can't be found in the /etc/passwd file.
+ * Because we always have a positive reply, it's important that this
+ * be the last NSS module for passwd lookups.
+ */
+__attribute__ ((visibility ("default")))
+enum nss_status _nss_mapname_getpwnam_r(const char *name, struct passwd *pw,
+ char *buffer, size_t buflen, int *errnop)
+{
+ enum nss_status status = NSS_STATUS_NOTFOUND;
+ struct pwbuf pbuf;
+
+ if (nss_mapuser_config(errnop, nssname) == 1) {
+ syslog(LOG_NOTICE, "%s: bad configuration", nssname);
+ return status;
+ }
+
+ /* marshal the args for the lower level functions */
+ pbuf.name = (char *)name;
+ pbuf.pw = pw;
+ pbuf.buf = buffer;
+ pbuf.buflen = buflen;
+ pbuf.errnop = errnop;
+
+ if(!get_pw_mapuser(name, &pbuf))
+ status = NSS_STATUS_SUCCESS;
+
+ return status;
+}
diff --git a/nss_mapuid.c b/nss_mapuid.c
new file mode 100644
index 0000000..a3f71f0
--- /dev/null
+++ b/nss_mapuid.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2017 Cumulus Networks, Inc.
+ * All rights reserved.
+ * Author: Dave Olson <olson@cumulusnetworks.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program - see the file COPYING.
+ */
+
+
+/*
+ * This plugin implements getpwuid_r for NSS to map a UID back to
+ * a mapped username account, set up via nss_mapuser.
+ *
+ * A fixed account is used to get the base of the home directory,
+ * and for the uid and gid. All other fields are replaced, and
+ * the password is always returned as 'x' (disabled). The assumption
+ * is that any authentication and authorization will be done via PAM
+ * using some mechanism other than the local password file.
+ *
+ * Since this should match first whenever a mapped user's UID is being
+ * looked up, this module should appear first in in nsswitch.conf for
+ * the passwd database.
+ *
+ * It implements getpwuid_r for UIDs if and only if a mapped user is currently
+ * logged in This means that if you do, e.g.:
+ * ls -ld ~SomeUserName
+ * you will sometimes get a mapped username, and other times get the name of the
+ * fixed account in the configuration file, depending on whether a mapped user
+ * is logged in or not.
+ *
+ * See nss_mapuser.c for the matching getpwnam_r for UIDs.
+ */
+
+#include "map_common.h"
+#include <sys/types.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <ctype.h>
+
+
+static const char *nssname = "nss_mapuid"; /* for syslogs */
+static const char dbdir[] = "/run/mapuser/";
+
+/*
+ * Read the requested session file (in the dbdir by intent), verify the
+ * uid matches, and setup the passwd structure with the username found
+ * in the file.
+ */
+static int chk_session_file(char *sfile, uid_t uid, struct pwbuf *pb)
+{
+ char rbuf[256], user[64];
+ FILE *mapf;
+ uid_t auid = 0;
+ int ret = 1;
+
+ mapf = fopen(sfile, "r");
+ if (!mapf) {
+ if( debug)
+ syslog(LOG_DEBUG, "%s: session map file %s open fails: %m",
+ nssname, sfile);
+ return ret;
+ }
+ user[0] = '\0';
+ while(fgets(rbuf, sizeof rbuf, mapf)) {
+ strtok(rbuf, " \t\n\r\f"); /* terminate buffer at first whitespace */
+ if(!strncmp("user=", rbuf, 5)) { /* should precede auid */
+ snprintf(user, sizeof user, "%s", rbuf+5);
+ if (auid) /* found out of order, but now have both */
+ break;
+ }
+ else if(!strncmp("auid=", rbuf, 5)) {
+ uid_t fuid = (uid_t)strtoul(rbuf+5, NULL, 10);
+ if (fuid && uid == fuid) {
+ auid = fuid;
+ if (user[0])
+ break; /* normal ordering, else keep looking for user */
+ }
+ }
+ }
+ fclose(mapf);
+
+ if (auid && user[0]) /* otherwise not a match */
+ ret = get_pw_mapuser(user, pb); /* should always succeed */
+
+ return ret;
+}
+
+/* find mapping for this sessionid */
+static int
+find_mapped_name(struct pwbuf *pb, uid_t uid, uint32_t session)
+{
+ char sessfile[sizeof dbdir + 11];
+
+ snprintf(sessfile, sizeof sessfile, "%s%u", dbdir, session);
+ return chk_session_file(sessfile, uid, pb);
+}
+
+static int find_mappingfile(struct pwbuf *pb, uid_t uid)
+{
+ DIR *dir;
+ struct dirent *ent;
+ int ret = 1;
+
+ dir = opendir(dbdir);
+ if (!dir) { /* can happen if no mapped users logged in */
+ if (debug > 1)
+ syslog(LOG_DEBUG, "%s: Unable to open mapping directory %s: %m",
+ nssname, dbdir);
+ return 1;
+ }
+
+ /* Loop through all numeric files in dbdir, check for matching uid */
+ while (ret && (ent = readdir(dir))) {
+ char sessfile[sizeof dbdir + 11];
+ if (!isdigit(ent->d_name[0])) /* sanity check on session file */
+ continue;
+ snprintf(sessfile, sizeof sessfile, "%s%s", dbdir, ent->d_name);
+ ret = chk_session_file(sessfile, uid, pb);
+ }
+ if (ret && debug)
+ syslog(LOG_DEBUG, "%s: uid %u mapping not found in map files",
+ nssname, uid);
+ closedir(dir);
+ return ret;
+}
+
+static uint32_t
+get_sessionid(void)
+{
+ int fd = -1, cnt;
+ uint32_t id = 0U;
+ static char buf[12];
+
+ fd = open("/proc/self/sessionid", O_RDONLY);
+ if(fd != -1) {
+ cnt = read(fd, buf, sizeof(buf));
+ close(fd);
+ }
+ if(fd != -1 && cnt > 0) {
+ id = strtoul(buf, NULL, 0);
+ }
+ return id;
+}
+
+/*
+ * This is an NSS entry point.
+ * We implement getpwuid(), for anything that wants to get the original
+ * login name from the uid.
+ * If it matches an entry in the map, we use that data to replace
+ * the data from the local passwd file (not via NSS).
+ * locally from the map.
+ *
+ * This can be made to work 2 different ways, and we need to choose
+ * one, or make it configurable.
+ *
+ * 1) Given a valid session id, and a mapped user logged in,
+ * we'll match only that user. That is, we can only do the lookup
+ * successfully for child processes of the mapped login, and
+ * only while still logged in (map entry is valid).
+ *
+ * For now, if session are set, I try them, and if that lookup
+ * fails, try the wildcard.
+ *
+ * Only works while the UID is in use for a mapped user, and only
+ * for processes invoked from that session. Other callers will
+ * just get the files, ldap, etc. entry for the UID
+ * Returns the first match if multiple mapped users.
+ */
+__attribute__ ((visibility ("default")))
+enum nss_status _nss_mapuid_getpwuid_r(uid_t uid, struct passwd *pw,
+ char *buffer, size_t buflen, int *errnop)
+{
+ struct pwbuf pb;
+ enum nss_status status = NSS_STATUS_NOTFOUND;
+ uint32_t session;
+
+ /* this can happen for permission reasons, do don't complain except
+ * at debug */
+ if (nss_mapuser_config(errnop, nssname) == 1) {
+ return status; /* syslog already done */
+ }
+
+
+ if (min_uid != ~0U && uid < min_uid) {
+ if(debug > 1)
+ syslog(LOG_DEBUG, "%s: uid %u < min_uid %u, don't lookup",
+ nssname, uid, min_uid);
+ return status;
+ }
+
+ /* marshal the args for the lower level functions */
+ pb.pw = pw;
+ pb.buf = buffer;
+ pb.buflen = buflen;
+ pb.errnop = errnop;
+ pb.name = NULL;
+
+ /* session needs to be set to lookup this user. May also be set
+ * for other users.
+ */
+ session = get_sessionid();
+ if(session && !find_mapped_name(&pb, uid, session))
+ status = NSS_STATUS_SUCCESS;
+ if(status != NSS_STATUS_SUCCESS) {
+ /* lookup by some other user or unrelated process, try dir lookup */
+ if (!find_mappingfile(&pb, uid))
+ status = NSS_STATUS_SUCCESS;
+ }
+ return status;
+}
diff --git a/pam_script_ses_close b/pam_script_ses_close
new file mode 100755
index 0000000..a59664c
--- /dev/null
+++ b/pam_script_ses_close
@@ -0,0 +1,62 @@
+#! /bin/bash
+# Copyright 2017 Cumulus Networks, Inc. All rights reserved
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+
+# This script is invoked via pam_script.so for session close, to
+# clean up the mapping setup on session open. The info is used
+# in the libnss_mapuser getpwuid() entry point.
+
+# auid is currently unused, but must match the uid of the mapped_user
+# in the libnss_mapuser database for this to be valid
+
+# For this to work, pam_loginuid.so must be used, so both the
+# loginuid and the sessionid are unique values > 0
+
+dbdir=/run/mapuser
+mkdir -p $dbdir
+
+read sess < /proc/$$/sessionid
+read auid < /proc/$$/loginuid
+
+# never map root user, or when loginuid isn't set, or when
+# we aren't doing mapping (env variable not set)
+if [ "$auid" -eq 0 ]; then exit 0; fi
+
+# for debugging, if needed
+# logger -t mapuser $0 called with $PAM_USER pid=$$ session="$sess" auid="$auid"
+
+if [ "$sess" -le 0 ] ; then
+ logger -t $0 sessionid not set, no mapuser cleanup for \
+ PID $$ user $PAM_USER
+ exit 0 # never trigger an error
+fi
+
+file=$dbdir/$sess
+[ -e $file ] && {
+ IFS='=
+' read tag fauid <<< $(grep '^auid=' $file)
+ IFS='=
+' read tag fsess <<< $(grep '^session=' $file)
+ # If info doesn't match, report it, but clean up anyway.
+ [ "$auid" != "$fauid" -o "$sess" != "$fsess" ] &&
+ logger -t $0 "Session $sess mismatch auid $auid,$fauid session $sess,$fsess"
+
+ rm -f $file
+ }
+
+# always succeed, this should not cause sessions shutdown errors
+exit 0
diff --git a/pam_script_ses_open b/pam_script_ses_open
new file mode 100755
index 0000000..6bdf57e
--- /dev/null
+++ b/pam_script_ses_open
@@ -0,0 +1,62 @@
+#! /bin/bash
+# Copyright 2017 Cumulus Networks, Inc. All rights reserved
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+
+# This script is invoked via pam_script.so for session open, used for mapping
+# RADIUS usernames to the mapped uid, for libnss_mapuser getpwuid() entry
+# point.
+
+# auid is currently unused, but must match the uid of the mapped_user
+# in the libnss_mapuser database for this to be valid
+
+# For this to work, pam_loginuid.so must be used, so both the
+# loginuid and the sessionid are unique values > 0
+
+umask 022 # want everything world-readable.
+
+dbdir=/run/mapuser
+mkdir -p $dbdir
+
+read sess < /proc/$$/sessionid
+read auid < /proc/$$/loginuid
+
+# for debugging, if needed
+# logger -t mapuser $0 called with $PAM_USER pid=$$ session="$sess" auid="$auid"
+
+# never map root user, or when loginuid isn't set, or when
+# we aren't doing mapping (env variable not set)
+if [ "$auid" -eq 0 ]; then exit 0; fi
+
+# handle this one differently, since it means something is
+# configured wrong.
+if [ "$sess" -le 0 ] ; then
+ logger -t $0 sessionid not set, no mapping possible for \
+ PID $$ user $PAM_USER
+ exit 0 # still allow the session
+fi
+
+# if user's home directory doesn't exist, create it and populate
+# it with the standard skeleton files.
+hdir=$(eval echo ~$PAM_USER)
+[ -d "$hdir" ] || /sbin/mkhomedir_helper $PAM_USER
+
+date +"%FT%T.%N%nuser=$PAM_USER%npid=$$%nauid=$auid%nsession=$sess%nhome=$hdir" \
+ > $dbdir/$sess
+
+# always succeed, this should not block sessions on errors
+exit 0
+