diff options
author | Dave Olson <olson@cumulusnetworks.com> | 2017-06-15 12:47:29 -0700 |
---|---|---|
committer | Dave Olson <olson@cumulusnetworks.com> | 2017-06-15 19:48:50 -0700 |
commit | e3408e0814517e6ad898c525125cf62aad40d60b (patch) | |
tree | d2e5f6eaca0ae5c2cfbce17024da7415743e0260 | |
download | libnss-mapuser-e3408e0814517e6ad898c525125cf62aad40d60b.tar.gz libnss-mapuser-e3408e0814517e6ad898c525125cf62aad40d60b.zip |
Initial version of libnss-mapuser package
See README for details
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | AUTHORS | 2 | ||||
-rw-r--r-- | LICENSE | 249 | ||||
-rw-r--r-- | Makefile | 52 | ||||
-rw-r--r-- | README | 52 | ||||
-rw-r--r-- | debian/README.source | 10 | ||||
-rw-r--r-- | debian/changelog | 8 | ||||
-rw-r--r-- | debian/compat | 1 | ||||
-rw-r--r-- | debian/control | 16 | ||||
-rw-r--r-- | debian/copyright | 24 | ||||
-rw-r--r-- | debian/libnss-mapuser.lintian-overrides | 10 | ||||
-rw-r--r-- | debian/libnss-mapuser.postinst | 45 | ||||
-rw-r--r-- | debian/libnss-mapuser.prerm | 9 | ||||
-rw-r--r-- | debian/libnss-mapuser.symbols | 5 | ||||
-rw-r--r-- | debian/mapuser | 6 | ||||
-rwxr-xr-x | debian/rules | 24 | ||||
-rw-r--r-- | debian/source/format | 1 | ||||
-rw-r--r-- | map_common.c | 265 | ||||
-rw-r--r-- | map_common.h | 60 | ||||
-rw-r--r-- | mapuser_nss.conf | 32 | ||||
-rw-r--r-- | nss_mapname.c | 75 | ||||
-rw-r--r-- | nss_mapuid.c | 221 | ||||
-rwxr-xr-x | pam_script_ses_close | 62 | ||||
-rwxr-xr-x | pam_script_ses_open | 62 |
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 @@ -0,0 +1,2 @@ +Author: + Dave Olson <olson@cumulusnetworks.com> @@ -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 @@ -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 + |