aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2018-08-12 19:20:04 +0300
committerSergey Poznyakoff <gray@gnu.org>2018-08-12 19:20:04 +0300
commit6bba235d667f25a9ae6bcd1c560b0ae28ea16505 (patch)
tree0d9e26952d7ae381f7dd78e6954fdda366a9eed7
parent23b718d2a385bb07bcbd4584a694e9e75050098b (diff)
downloadpam-modules-6bba235d667f25a9ae6bcd1c560b0ae28ea16505.tar.gz
pam-modules-6bba235d667f25a9ae6bcd1c560b0ae28ea16505.tar.bz2
New module pam_innetgr.
* Makefile.am: Add new module. * NEWS: Upgrade * configure.ac: Add configuration for pam_innetgr * pam_innetgr/Makefile.am: New file. * pam_innetgr/pam_innetgr.c: New file. * doc/Makefile.am: Add pam_innetgr.8 * doc/pam-modules.texi: Document pam_innetgr. * doc/pam_innetgr.8: New file. * examples/ldappubkey: Bugfixes (publickeyattribute setting): Accept a list of attributes (publickeyfilter): New setting.
-rw-r--r--Makefile.am36
-rw-r--r--NEWS22
-rw-r--r--configure.ac20
-rw-r--r--doc/Makefile.am3
-rw-r--r--doc/pam-modules.texi116
-rw-r--r--doc/pam_innetgr.8173
-rwxr-xr-xexamples/ldappubkey65
-rw-r--r--pam_groupmember/pam_groupmember.c2
-rw-r--r--pam_innetgr/Makefile.am22
-rw-r--r--pam_innetgr/pam_innetgr.c319
-rw-r--r--pam_umotd/pam_umotd.c2
11 files changed, 735 insertions, 45 deletions
diff --git a/Makefile.am b/Makefile.am
index 0b5c6d5..f2f416b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -17,37 +17,35 @@
AUTOMAKE_OPTIONS = gnits 1.8
ACLOCAL_AMFLAGS = -I m4 -I imprimatur
+SUBDIRS = \
+ imprimatur\
+ doc\
+ examples\
+ lib\
+ pam_sql\
+ pamck
+
if PAM_COND_FSHADOW
- FSHADOW_DIR=pam_fshadow
+ SUBDIRS += pam_fshadow
endif
if PAM_COND_REGEX
- REGEX_DIR=pam_regex
+ SUBDIRS += pam_regex
endif
if PAM_COND_LOG
- LOG_DIR=pam_log
+ SUBDIRS += pam_log
endif
if PAM_COND_LDAPHOME
- LDAPHOME_DIR=pam_ldaphome
+ SUBDIRS += pam_ldaphome
endif
if PAM_COND_UMOTD
- UMOTD_DIR=pam_umotd
+ SUBDIRS += pam_umotd
endif
if PAM_COND_GROUPMEMBER
- GROUPMEMBER_DIR=pam_groupmember
+ SUBDIRS += pam_groupmember
+endif
+if PAM_COND_INNETGR
+ SUBDIRS += pam_innetgr
endif
-SUBDIRS = \
- imprimatur\
- doc\
- examples\
- lib\
- $(FSHADOW_DIR)\
- $(REGEX_DIR)\
- $(LOG_DIR)\
- pam_sql\
- $(LDAPHOME_DIR)\
- $(UMOTD_DIR)\
- $(GROUPMEMBER_DIR)\
- pamck
EXTRA_DIST=ChangeLog.svn
diff --git a/NEWS b/NEWS
index 0a530e2..22ba9df 100644
--- a/NEWS
+++ b/NEWS
@@ -1,9 +1,25 @@
-pam-modules -- history of user-visible changes. 2018-01-02
-Copyright (C) 2001, 2004-2005, 2007-2012, 2015, 2018 Sergey Poznyakoff
+pam-modules -- history of user-visible changes. 2018-08-12
See the end of file for copying conditions.
Please send pam-modules bug reports to <bug-pam-modules@gnu.org.ua>
+Version 2.2.90 (git)
+
+* New module pam_innetgr
+
+This module checks if the current hostname and the name of the user
+trying to log in are mentioned in a triple of the specified NIS
+netgroup.
+
+* The ldappubkey utility imporoved.
+
+The PublicKeyAttribute setting accepts a whitespace-separated list of
+attribute names.
+
+The new setting PublicKeyFilter can be used to supply a LDAP filter
+expression to use in place of the default.
+
+
Version 2.2, 2018-01-02
* Improve pam_fshadow
@@ -223,7 +239,7 @@ Version 0.1
=========================================================================
Copyright information:
-Copyright (C) 2001, 2004-2005, 2007-2015 Sergey Poznyakoff
+Copyright (C) 2001, 2004-2005, 2007-2012, 2015, 2018 Sergey Poznyakoff
Permission is granted to anyone to make or distribute verbatim copies
of this document as received, in any medium, provided that the
diff --git a/configure.ac b/configure.ac
index 0a4eb33..6869248 100644
--- a/configure.ac
+++ b/configure.ac
@@ -16,7 +16,7 @@
AC_PREREQ(2.63)
-AC_INIT(pam-modules, 2.2, bug-pam-modules@gnu.org.ua)
+AC_INIT(pam-modules, 2.2.90, bug-pam-modules@gnu.org.ua)
AC_CONFIG_SRCDIR(pam_fshadow/pam_fshadow.c)
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([m4])
@@ -171,6 +171,18 @@ yes)
esac
])
+#
+AC_CHECK_FUNCS([getdomainname])
+PM_ENABLE(innetgr,[
+case $build_innetgr in
+probe)
+ AC_CHECK_FUNC([innetgr],[build_innetgr=yes],[build_innetgr=no])
+ ;;
+yes)
+ AC_CHECK_FUNC([innetgr],[],[AC_MSG_ERROR([cannot build the requested module pam_innetgr because function innetgr is not present in libc])])
+ ;;
+esac])
+
## *****************
## debugging support
## *****************
@@ -219,7 +231,7 @@ delim="-------------------------------------------------------------------"
echo $delim | tr '-' '*'
echo "Modules to build:"
res=
-for module in fshadow regex log pgsql mysql ldaphome umotd groupmember
+for module in fshadow regex log pgsql mysql ldaphome umotd groupmember innetgr
do
modname=pam_$module
eval enable=\${build_$module}
@@ -242,7 +254,8 @@ build_pgsql=$build_pgsql
build_mysql=$build_mysql
build_ldaphome=$build_ldaphome
build_umotd=$build_umotd
-build_groupmember=$build_groupmember])
+build_groupmember=$build_groupmember
+build_innetgr=$build_innetgr])
AC_OUTPUT(Makefile
doc/Makefile
@@ -255,4 +268,5 @@ AC_OUTPUT(Makefile
pam_ldaphome/Makefile
pam_umotd/Makefile
pam_groupmember/Makefile
+ pam_innetgr/Makefile
pamck/Makefile)
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 3d588e3..368d3b0 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -43,6 +43,9 @@ endif
if PAM_COND_GROUPMEMBER
dist_man_MANS += pam_groupmember.8
endif
+if PAM_COND_INNETGR
+ dist_man_MANS += pam_innetgr.8
+endif
config.so: $(top_srcdir)/configure.ac $(top_srcdir)/doc/Makefile.am
$(AM_V_GEN){\
diff --git a/doc/pam-modules.texi b/doc/pam-modules.texi
index 31f69ed..840a4c1 100644
--- a/doc/pam-modules.texi
+++ b/doc/pam-modules.texi
@@ -31,10 +31,11 @@
session management.
* pam_log: (pam-modules)log. Format and log arbitrary
messages to syslog.
-* pam_ldaphome (pam-modules)ldaphome Maintain home directories and
+* pam_ldaphome (pam-modules)ldaphome. Maintain home directories and
SSH keys od LDAP users.
-* pam_umotd (pam-modules)umotd Display a user-specific MOTD.
-* pam_groupmember (pam_modules)groupmember Test group membership.
+* pam_umotd (pam-modules)umotd. Display a user-specific MOTD.
+* pam_groupmember (pam_modules)groupmember. Test group membership.
+* pam_innetgr (pam-modules)innetgr. Check NIS netgroup.
* pamck: (pam-modules)pamck. Verify PAM Access.
* usergitconfig: (pam-modules)usergitconfig. Initialize user @file{.gitconfig} file.
* ldappubkey: (pam-modules)ldappubkey. Get user's public ssh keys from the LDAP database.
@@ -90,6 +91,7 @@ Individual modules
* ldaphome:: Maintain home directories and SSH keys of LDAP users.
* umotd:: Display a user-specific MOTD.
* groupmember:: Test group membership.
+* innetgr:: Check NIS netgroup.
* Reporting Bugs:: How to Report a Bug.
@@ -1670,11 +1672,33 @@ LDAP record is searched using the following filter:
@end example
@end deffn
-@deffn {ldap.conf} publickeyattribute @var{attr}
-Name of the attribute which holds the public key. Default is
+@deffn {ldap.conf} publickeyattribute @var{attr} [@var{attr}...]
+List of attributes that hold the public keys. Default is
@samp{grayPublicKey} (@pxref{ldap-schema}).
@end deffn
+@deffn {ldap.conf} publickeyfilter @var{filter}
+LDAP filter used to retrieve the objects that contain public keys. The
+@var{filter} string can contain the following variables:
+
+@table @asis
+@item $uid
+The value of the @samp{uid} setting (see above).
+
+@item $arg
+First command line argument.
+
+@item $hostname
+Full hostname of the machine.
+@end table
+
+The default value is:
+@example
+ (&(objectClass=posixAccount)($uid=$arg))
+@end example
+@end deffn
+
+
@node usergitconfig
@section usergitconfig
@cindex usergitconfig
@@ -1854,6 +1878,88 @@ sign.
Default is @samp{allow}.
@end table
+@node innetgr
+@chapter Check NIS netgroup
+@set MODULE pam_innetgr
+@prindex pam_innetgr
+@cindex netgroups
+@cindex NIS
+
+The @command{pam_innetgr} module checks if the user and current host
+match a triple in the NIS netgroup supplied via the @samp{netgroup}
+argument. It returns success if so, and @samp{PAM_AUTH_ERR} otherwise.
+
+Another possible return values are: @samp{PAM_AUTHINFO_UNAVAIL}, if
+the input information was not sufficient (e.g. the username was not
+supplied, or the module was unable to determine the host or domain
+name), and @samp{PAM_SERVICE_ERR}, if a generic error condition (such
+as a lack of memory) occurred.
+
+In order to determine host and domain name parts, the following
+approach is used. First, the @samp{gethostname} function is called to
+obtain the hostname part. If the @samp{getdomainname} function is
+available, it is used to determine the domain part. If the resulting
+domain part is @samp{NULL} or the string @samp{(none)}, the
+@samp{gethostbyname} function is invoked with the hostname as its
+argument. The returned name (technically speaking, the @samp{h_name}
+member of the @samp{struct hostent}) is used as the canonical name of
+the server. It is split on the first occurrence of the dot character.
+The second part is used as the domain name. The options described
+below control this process.
+
+This module can be used in any PAM service stack.
+
+@menu
+* summary of pam_innetgr options::
+@end menu
+
+@node summary of pam_innetgr options
+@section Summary of @command{pam_innetgr} options
+
+The following table summarizes the options specific for this
+module. @xref{common options}, for the list of common options.
+
+@table @option
+@opsummary{netgroup}
+@item netgroup=@var{name}
+Name of the netgroup to use. This option is mandatory.
+
+@opsummary{hostname}
+@item hostname=@var{string}
+Defines the hostname of the current host. By default it is determined
+using the @code{gethostname} system call.
+
+@opsummary{domainname}
+@item domainname=@var{string}
+Defines the domainname of the current host.
+
+@opsummary{nogetdomainname}
+@item nogetdomainname
+Disable the use of @code{getdomainname} libc function. By default it
+is used to determine the domain name. If it fails or returns a string
+@samp{(none)}, than the module tries to get the fully qualified name
+of the server and uses the part after the first dot as the domain
+name. Using the @samp{nogetdomainname} option instructs it to always
+use the latter method.
+
+Never use this option together with @samp{noresove}.
+
+@opsummary{noresolve}
+@item noresolve
+Don't fallback to obtaining the fully qualified domain name of the
+host from DNS in order to obtain the domain part. This means that
+if @code{getdomainname} call fails or is not available on your system,
+the module will return @code{PAM_SERVICE_ERR}.
+
+Never use this option together with @samp{nogetdomainname}.
+
+@opsummary{sense}
+@item sense=@{allow|deny@}
+ What to do on success. The value @samp{allow} means to return
+@code{PAM_SUCCESS}, @samp{deny} means to return @code{PAM_AUTH_ERR}.
+Default is @samp{allow}.
+@end table
+
@node Reporting Bugs
@chapter How to Report a Bug
diff --git a/doc/pam_innetgr.8 b/doc/pam_innetgr.8
new file mode 100644
index 0000000..335409d
--- /dev/null
+++ b/doc/pam_innetgr.8
@@ -0,0 +1,173 @@
+.\" This file is part of PAM-Modules -*- nroff -*-
+.\" Copyright (C) 2018 Sergey Poznyakoff
+.\"
+.\" PAM-Modules 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, or (at your option)
+.\" any later version.
+.\"
+.\" PAM-Modules 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 PAM-Modules. If not, see <http://www.gnu.org/licenses/>.
+.TH PAM_INNETGR 8 "August 12, 2018" "PAM-MODULES" "Pam-Modules User Reference"
+.SH NAME
+pam_innetgr \- test NIS netgroup match
+.SH SYNOPSIS
+.nh
+.na
+\fBpam_innetgr\fR\
+ \fBnetgroup=\fINAME\fR\
+ [\fBhostname=\fINAME\fR]\
+ [\fBdomainname=\fINAME\fR]\
+ [\fBnogetdomainname\fR]\
+ [\fBnoresolve\fR]\
+ [\fBsense=\fISENSE\fR]\
+ [\fBdebug\fR[\fB=\fINUMBER\fR]]\
+ [\fBwaitdebug\fR]\
+ [\fBaudit\fR]
+.ad
+.hy
+.SH DESCRIPTION
+The \fBpam_innetgr\fR module checks if the user and current host
+match a triple in the NIS netgroup supplied via the \fBnetgroup\fR
+argument. It returns success if so, and \fBPAM_AUTH_ERR\fR otherwise.
+
+Another possible return values are: \fBPAM_AUTHINFO_UNAVAIL\fR, if
+the username was not supplied or the module was unable to determine
+the host or domain name, and \fBPAM_SERVICE_ERR\fR, if a generic error
+condition (such as a lack of memory) occurred.
+
+In order to determine host and domain name parts, the following
+approach is used. First, the
+.BR gethostname (2)
+function is called to obtain the hostname part. If the
+.BR getdomainname (2)
+function is available, it is used to determine the
+domain part. If the resulting domain part is NULL or the string "(none)", the
+.BR gethostbyname (2)
+function is invoked with the hostname as its
+argument. The returned name (technically speaking, the \fBh_name\fR
+member of the \fBstruct hostent\fR) is used as the canonical name of
+the server. It is split on the first occurrence of the dot character.
+The second part is used as the domain name. The options described below
+control this process.
+.SH OPTIONS
+.TP
+\fBnetgroup=\fISTRING\fR
+Name of the netgroup to use. This option is mandatory.
+.TP
+\fBhostname=\fISTRING\fR
+Defines the hostname of the current host. By default it is determined
+using the
+.BR gethostname (2)
+system call.
+.TP
+\fBdomainname=\fISTRING\fR
+Defines the domainname of the current host.
+.TP
+.B nogetdomainname
+Disable the use of
+.BR getdomainname (2)
+system call.
+.sp
+Never use this option together \fBnoresove\fR.
+.TP
+.B noresolve
+Don't fallback to obtaining the fully qualified domain name of the
+host from DNS in order to obtain the domain part. This means that
+if \fBgetdomainname\fR call fails or is not available on your system,
+the module will return \fBPAM_SERVICE_ERR\fR.
+.sp
+Never use this option together with \fBnogetdomainname\fR.
+.TP
+\fBsense=allow\fR|\fBdeny\fR
+What to do if the user name matches the expression given by the
+\fBregex\fR option. The value \fBallow\fR (the default) instructs the
+module to return \fBPAM_SUCCESS\fR, the \fBdeny\fR instructs it to
+return \fBPAM_AUTH_ERR\fR.
+.TP
+\fBdebug\fR[\fB=\fINUMBER\fR]
+Set debugging level (0 <= \fINUMBER\fR <= 100).
+.TP
+\fBaudit\fR
+Log full debugging information (equivalent to \fBdebug=100\fR).
+.TP
+\fBwaitdebug=\fIN\fR
+Wait for \fIN\fR seconds before starting up. This option is intended
+to facilitate attaching to the module with
+.BR gdb (1).
+It is available only if the package was configured with
+the \fB\-\-enable\-debug\fR option.
+.SH MODULE TYPES PROVIDED
+All module types (\fBaccount\fR, \fBauth\fR, \fBpassword\fR and
+\fBsession\fR) are provided.
+.SH RETURN VALUES
+.TP
+.B PAM_SUCCESS
+Successful return.
+.TP
+.B PAM_AUTH_ERR
+Authentication failed.
+.TP
+.B PAM_AUTHINFO_UNAVAIL
+The input information is not sufficient.
+.TP
+.B PAM_SERVICE_ERR
+A generic error condition (such as lack of memory) was encountered.
+.TP
+.B PAM_USER_UNKNOWN
+Supplied username not found.
+.SH EXAMPLES
+auth required pam_innetgr.so netgroup=grnam
+.SH NOTE
+This manpage is a short description of \fBpam_innetgr\fR. For a detailed
+discussion, including examples and usage recommendations, refer to the
+\fBPAM-modules Manual\fR available in texinfo format. If the \fBinfo\fR
+reader and the tar documentation are properly installed on your
+system, the command
+.PP
+.RS +4
+.B info pam-modules
+.RE
+.PP
+should give you access to the complete manual.
+.PP
+You can also view the manual using the info mode in
+.BR emacs (1),
+or find it in various formats online at
+.PP
+.RS +4
+.B http://www.gnu.org.ua/software/pam-modules/manual
+.RE
+.PP
+If any discrepancies occur between this manpage and the
+\fBPAM-modules Manual\fR, the later shall be considered the authoritative
+source.
+.SH "SEE ALSO"
+.BR pam.conf (5),
+.BR pam.d (5),
+.BR pam (8).
+.SH AUTHORS
+Sergey Poznyakoff <gray@gnu.org>
+.SH "BUG REPORTS"
+Report bugs to <bug\-pam\-modules@gnu.org.ua>.
+.SH COPYRIGHT
+Copyright \(co 2018 Sergey Poznyakoff
+.br
+.na
+License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
+.br
+.ad
+This is free software: you are free to change and redistribute it.
+There is NO WARRANTY, to the extent permitted by law.
+.\" Local variables:
+.\" eval: (add-hook 'write-file-functions 'time-stamp)
+.\" time-stamp-start: ".TH [A-Z_][A-Z0-9_.\\-]* [0-9] \""
+.\" time-stamp-format: "%:B %:d, %:y"
+.\" time-stamp-end: "\""
+.\" time-stamp-line-limit: 20
+.\" end:
diff --git a/examples/ldappubkey b/examples/ldappubkey
index cecfaa6..5bf2828 100755
--- a/examples/ldappubkey
+++ b/examples/ldappubkey
@@ -17,6 +17,7 @@
use strict;
use Net::LDAP;
+use Sys::Hostname;
=head1 NAME
@@ -62,8 +63,8 @@ Specifies the password to use with B<binddn>.
=item B<uid> I<ATTR>
-Name of the attribute to use instead of B<uid>. The LDAP record is searched
-using the filter B<(&(objectClass=posixAccount)(I<ATTR>=I<LOGIN>))>.
+Name of the attribute to use instead of B<uid>. LDAP records are searched
+using the filter defined with the B<PublicKeyFilter> attribute (see below).
=item B<ssl start_tls>
@@ -98,9 +99,34 @@ Specifies acceptable cipher suite and preference order.
Specifies what checks to perform on server certificates in a TLS session.
I<LEVEL> is one of B<never>, B<allow>, B<try>, B<demand> or B<hard>.
-=item B<publickeyattribute> I<ATTR>
+=item B<PublicKeyAttribute> I<ATTR> [I<ATTR>...]
-Name of the attribute which holds the public key. Default is B<grayPublicKey>.
+List of attributes that hold the public key. Default is C<grayPublicKey>.
+
+=item B<PublicKeyFilter> I<FILTER>
+
+LDAP filter used to retrieve the objects that may contain public keys. The
+I<FILTER> string can contain the following variables
+
+=over 8
+
+=item B<$uid>
+
+The value of B<uid> setting (see above).
+
+=item B<$arg>
+
+First command line argument.
+
+=item B<$hostname>
+
+Full hostname of the machine.
+
+=back
+
+Default value is:
+
+ (&(objectClass=posixAccount)($uid=$arg))
=back
@@ -151,7 +177,8 @@ Sergey Poznyakoff <gray@gnu.org>
# ###################################
my %config = ('uri' => 'ldap://127.0.0.1', 'uid' => 'uid',
- 'publickeyattribute' => 'grayPublicKey');
+ 'publickeyattribute' => 'grayPublicKey',
+ 'publickeyfilter' => '(&(objectClass=posixAccount)($uid=$arg))');
sub read_config_file($) {
my $config_file = shift;
@@ -164,14 +191,23 @@ sub read_config_file($) {
chomp;
s/^\s+//;
s/\s+$//;
- s/#.*//;
+ s/#.*//;
next if ($_ eq "");
- my @kwp = split(/\s*\s+\s*/, $_, 2);
+ my @kwp = split(/\s+/, $_, 2);
$config{lc($kwp[0])} = $kwp[1];
}
close($file);
}
+sub get_fqdn_hostname {
+ my $name = hostname();
+ if (my ($fqdn) = gethostbyname($name)) {
+ return $fqdn;
+ } else {
+ return $name;
+ }
+}
+
sub assert {
my $mesg = shift;
my $action = shift;
@@ -236,17 +272,20 @@ if (defined($config{'binddn'})) {
}
assert($ldap->bind(@bindargs), "binding to the server");
-my $attr = $config{'publickeyattribute'};
-my $filter = "(&(objectClass=posixAccount)($config{'uid'}=$ARGV[0]))";
+my @attrs = split /\s+/, $config{'publickeyattribute'};
+my $filter = $config{'publickeyfilter'};
+my $uid = "$config{'uid'}";
+my $arg = $ARGV[0];
+my $hostname = get_fqdn_hostname();
+$filter =~ s/(?<!\\)(\$(?:uid|arg|hostname))/$1/eeg;
my $res = assert($ldap->search(base => $config{'base'},
filter => $filter,
- attr => [ $attr ] ),
+ attrs => \@attrs ),
"searching for $filter in $config{'base'}");
-foreach my $entry ($res->entry(0)) {
- my $keyref = $entry->get_value($attr, asref => 1);
- for (@{$keyref}) {
+foreach my $entry ($res->entries()) {
+ for (map { my $a = $entry->get_value($_, asref => 1); $a ? @$a : () } @attrs) {
print "$_\n";
}
}
diff --git a/pam_groupmember/pam_groupmember.c b/pam_groupmember/pam_groupmember.c
index ec66d50..ba418d0 100644
--- a/pam_groupmember/pam_groupmember.c
+++ b/pam_groupmember/pam_groupmember.c
@@ -241,7 +241,7 @@ pam_sm_close_session (pam_handle_t *pamh, int flags, int argc,
/* static module data */
struct pam_module _pam_log_modstruct = {
- "pam_log",
+ "pam_groupmember",
pam_sm_authenticate,
pam_sm_setcred,
pam_sm_acct_mgmt,
diff --git a/pam_innetgr/Makefile.am b/pam_innetgr/Makefile.am
new file mode 100644
index 0000000..1e5c7f8
--- /dev/null
+++ b/pam_innetgr/Makefile.am
@@ -0,0 +1,22 @@
+# This file is part of pam-modules.
+# Copyright (C) 2018 Sergey Poznyakoff
+#
+# 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, 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, see <http://www.gnu.org/licenses/>.
+
+include $(top_srcdir)/Make.rules
+
+pamdir=@PAMDIR@
+pam_LTLIBRARIES = pam_innetgr.la
+pam_innetgr_la_SOURCES = pam_innetgr.c
+AM_CPPFLAGS += -DMODULE_NAME=\"pam_innetgr\"
diff --git a/pam_innetgr/pam_innetgr.c b/pam_innetgr/pam_innetgr.c
new file mode 100644
index 0000000..f1f5e5d
--- /dev/null
+++ b/pam_innetgr/pam_innetgr.c
@@ -0,0 +1,319 @@
+/* This file is part of pam-modules.
+ Copyright (C) 2018 Sergey Poznyakoff
+
+ 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, see <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE__PAM_ACONF_H
+#include <security/_pam_aconf.h>
+#endif
+#include <stdlib.h>
+#include <netdb.h>
+#include "graypam.h"
+
+#ifndef LINUX_PAM
+#include <security/pam_appl.h>
+#endif
+#include <security/pam_modules.h>
+
+static long debug_level;
+char const *host_name;
+char const *domain_name;
+char const *netgroup_name;
+int use_getdomainname;
+int use_resolve;
+enum {
+ SENSE_ALLOW,
+ SENSE_DENY
+};
+const char *sense_choice[] = { "allow", "deny", NULL };
+static int sense;
+
+struct pam_opt pam_opt[] = {
+ { PAM_OPTSTR(debug), pam_opt_long, &debug_level },
+ { PAM_OPTSTR(debug), pam_opt_const, &debug_level, { 1 } },
+ { PAM_OPTSTR(audit), pam_opt_const, &debug_level, { 100 } },
+ { PAM_OPTSTR(waitdebug), pam_opt_null, NULL, { 0 },
+ gray_wait_debug_fun },
+ { PAM_OPTSTR(netgroup), pam_opt_string, &netgroup_name },
+ { PAM_OPTSTR(hostname), pam_opt_string, &host_name },
+ { PAM_OPTSTR(domainname), pam_opt_string, &domain_name },
+ { PAM_OPTSTR(getdomainname), pam_opt_bool, &use_getdomainname },
+ { PAM_OPTSTR(resolve), pam_opt_bool, &use_resolve },
+ { PAM_OPTSTR(sense), pam_opt_enum, &sense, { enumstr: sense_choice } },
+ { NULL }
+};
+
+#ifndef MAXHOSTNAMELEN
+# define MAXHOSTNAMELEN 64
+#endif
+#ifndef SIZE_T_MAX
+# define SIZE_T_MAX ((size_t)-1)
+#endif
+
+int
+xgetname (int (*getfn)(char *, size_t), char **storage)
+{
+ char *buffer = NULL;
+ size_t size = 0;
+ char *p;
+
+ while (1) {
+ if (size == 0) {
+ size = MAXHOSTNAMELEN;
+ p = malloc(size);
+ } else if (SIZE_T_MAX / 3 * 2 <= size) {
+ p = NULL;
+ } else {
+ size += (size + 1) / 2;
+ p = realloc(buffer, size);
+ }
+ if (!p) {
+ free(buffer);
+ errno = ENOMEM;
+ return -1;
+ }
+ buffer = p;
+ buffer[size - 1] = 0;
+ if (getfn(buffer, size - 1) == 0) {
+ if (!buffer[size - 1])
+ break;
+ } else if (errno != 0
+ && errno != ENAMETOOLONG
+ && errno != EINVAL
+ && errno != ENOMEM) {
+ int rc = errno;
+ free(buffer);
+ errno = rc;
+ return -1;
+ }
+ }
+ *storage = buffer;
+
+ return 0;
+}
+
+int
+stripdomain(char *hostname, char const *domainname)
+{
+ size_t hlen, dlen;
+
+ if (!domainname)
+ return -1;
+ hlen = strlen(hostname);
+ dlen = strlen(domainname);
+ if (hlen > dlen + 1
+ && hostname[hlen - dlen - 1] == '.'
+ && strcasecmp(hostname + hlen - dlen, domainname) == 0) {
+ hostname[hlen - dlen - 1] = 0;
+ return 0;
+ }
+ return -1;
+}
+
+int
+get_host_domain_names(char **host_name_ptr, char **domain_name_ptr)
+{
+ char *hostname;
+ char *domainname = NULL;
+
+ if (xgetname(gethostname, &hostname))
+ return -1;
+#if HAVE_GETDOMAINNAME
+ if (use_getdomainname) {
+ if (xgetname(getdomainname, &domainname)) {
+ _pam_log(LOG_ERR, "getdomainname: %s", strerror(errno));
+ } else if (strcmp (domainname, "(none)") == 0) {
+ free(domainname);
+ domainname = NULL;
+ }
+ }
+#endif
+ if (domainname) {
+ stripdomain(hostname, domainname);
+ } else if (use_resolve) {
+ char *p = strchr(hostname, '.');
+ if (!p) {
+ struct hostent *hp = gethostbyname(hostname);
+ if (hp) {
+ size_t len = strlen(hp->h_name);
+ p = realloc(hostname, len + 1);
+ if (!p) {
+ free(hostname);
+ errno = ENOMEM;
+ return -1;
+ }
+ hostname = p;
+ strcpy(hostname, hp->h_name);
+ p = strchr(hostname, '.');
+ }
+ }
+ if (p) {
+ *p++ = 0;
+ domainname = strdup(p);
+ if (!domainname) {
+ int rc = errno;
+ _pam_log(LOG_ERR, "getdomainname: %s",
+ strerror(errno));
+ free(hostname);
+ errno = rc;
+ return -1;
+ }
+ }
+ }
+
+ *host_name_ptr = hostname;
+ *domain_name_ptr = domainname;
+
+ return 0;
+}
+
+static int
+check_netgroup0(pam_handle_t *pamh, int argc, const char **argv,
+ const char *func)
+{
+ int rc;
+ char *host_name_buf = NULL;
+ char *domain_name_buf = NULL;
+ char const *user_name;
+
+ debug_level = 0;
+ host_name = NULL;
+ domain_name = NULL;
+ netgroup_name = NULL;
+ use_getdomainname = 1;
+ use_resolve = 1;
+ sense = SENSE_ALLOW;
+
+ gray_pam_init(PAM_AUTHINFO_UNAVAIL);
+ gray_log_init(0, MODULE_NAME, LOG_AUTHPRIV);
+ gray_parseopt(pam_opt, argc, argv);
+ if (!netgroup_name) {
+ _pam_log(LOG_ERR, "no netgroup name given");
+ return PAM_AUTHINFO_UNAVAIL;
+ }
+
+ /*
+ * get username
+ */
+ rc = pam_get_user(pamh, &user_name, "login: ");
+ if (rc == PAM_SUCCESS) {
+ DEBUG(10, ("username [%s] obtained", user_name));
+ } else {
+ _pam_log(LOG_NOTICE, "can't get username");
+ return PAM_AUTHINFO_UNAVAIL;
+ }
+
+ if (!host_name || !domain_name) {
+ if (get_host_domain_names (&host_name_buf, &domain_name_buf)) {
+ _pam_log(LOG_ERR, "%s", strerror(errno));
+ return PAM_SERVICE_ERR;
+ }
+ if (!host_name) {
+ if (!host_name_buf) {
+ _pam_log(LOG_NOTICE, "can't get hostname");
+ return PAM_AUTHINFO_UNAVAIL;
+ }
+ host_name = host_name_buf;
+ }
+ if (!domain_name) {
+ if (!domain_name_buf) {
+ _pam_log(LOG_NOTICE, "can't get domainname");
+ return PAM_AUTHINFO_UNAVAIL;
+ }
+ domain_name = domain_name_buf;
+ }
+ }
+
+ DEBUG(1,("checking (%s, %s, %s)",
+ host_name, user_name, domain_name));
+
+ rc = innetgr(netgroup_name, host_name, user_name, domain_name);
+
+ DEBUG(1,("netgroup %s, triple (%s, %s, %s): %d", netgroup_name,
+ host_name, user_name, domain_name, rc));
+
+ free(host_name_buf);
+ free(domain_name_buf);
+
+ if (sense == SENSE_DENY)
+ rc = !rc;
+ return rc ? PAM_SUCCESS : PAM_AUTH_ERR;
+}
+
+static int
+check_netgroup(pam_handle_t *pamh, int argc, const char **argv,
+ const char *func)
+{
+ int rc;
+
+ DEBUG(90,("enter %s", func));
+ rc = check_netgroup0(pamh, argc, argv, __FUNCTION__);
+ DEBUG(90,("leave %s=%d", func, rc));
+ return rc;
+}
+
+PAM_EXTERN int
+pam_sm_authenticate(pam_handle_t *pamh,
+ int flags,
+ int argc,
+ const char **argv)
+{
+ return check_netgroup(pamh, argc, argv, __FUNCTION__);
+}
+
+PAM_EXTERN int
+pam_sm_chauthtok(pam_handle_t *pamh,int flags,int argc,const char **argv)
+{
+ return check_netgroup(pamh, argc, argv, __FUNCTION__);
+}
+
+PAM_EXTERN int
+pam_sm_acct_mgmt (pam_handle_t *pamh, int flags, int argc, const char **argv)
+{
+ return check_netgroup(pamh, argc, argv, __FUNCTION__);
+}
+
+PAM_EXTERN int
+pam_sm_open_session (pam_handle_t *pamh, int flags, int argc,
+ const char **argv)
+{
+ return check_netgroup(pamh, argc, argv, __FUNCTION__);
+}
+
+PAM_EXTERN int
+pam_sm_close_session (pam_handle_t *pamh, int flags, int argc,
+ const char **argv)
+{
+ return check_netgroup(pamh, argc, argv, __FUNCTION__);
+}
+
+#ifdef PAM_STATIC
+
+/* static module data */
+
+struct pam_module _pam_log_modstruct = {
+ MODULE_NAME,
+ pam_sm_authenticate,
+ pam_sm_setcred,
+ pam_sm_acct_mgmt,
+ pam_sm_open_session,
+ pam_sm_close_session,
+ pam_sm_chauthtok,
+};
+
+#endif
+
+/* end of module definition */
+
+
diff --git a/pam_umotd/pam_umotd.c b/pam_umotd/pam_umotd.c
index a489e24..b14ffab 100644
--- a/pam_umotd/pam_umotd.c
+++ b/pam_umotd/pam_umotd.c
@@ -385,7 +385,7 @@ pam_sm_close_session(pam_handle_t *pamh, int flags, int argc, const char **argv)
/* static module data */
struct pam_module _pam_motd_modstruct = {
- "pam_motd",
+ "pam_umotd",
NULL,
NULL,
NULL,

Return to:

Send suggestions and report system problems to the System administrator.