mirror of
git://git.gnu.org.ua/pam-modules.git
synced 2025-04-26 00:19:52 +03:00
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.
This commit is contained in:
parent
23b718d2a3
commit
6bba235d66
11 changed files with 740 additions and 50 deletions
46
Makefile.am
46
Makefile.am
|
@ -17,38 +17,36 @@
|
|||
AUTOMAKE_OPTIONS = gnits 1.8
|
||||
ACLOCAL_AMFLAGS = -I m4 -I imprimatur
|
||||
|
||||
if PAM_COND_FSHADOW
|
||||
FSHADOW_DIR=pam_fshadow
|
||||
endif
|
||||
if PAM_COND_REGEX
|
||||
REGEX_DIR=pam_regex
|
||||
endif
|
||||
if PAM_COND_LOG
|
||||
LOG_DIR=pam_log
|
||||
endif
|
||||
if PAM_COND_LDAPHOME
|
||||
LDAPHOME_DIR=pam_ldaphome
|
||||
endif
|
||||
if PAM_COND_UMOTD
|
||||
UMOTD_DIR=pam_umotd
|
||||
endif
|
||||
if PAM_COND_GROUPMEMBER
|
||||
GROUPMEMBER_DIR=pam_groupmember
|
||||
endif
|
||||
SUBDIRS = \
|
||||
imprimatur\
|
||||
doc\
|
||||
examples\
|
||||
lib\
|
||||
$(FSHADOW_DIR)\
|
||||
$(REGEX_DIR)\
|
||||
$(LOG_DIR)\
|
||||
pam_sql\
|
||||
$(LDAPHOME_DIR)\
|
||||
$(UMOTD_DIR)\
|
||||
$(GROUPMEMBER_DIR)\
|
||||
pamck
|
||||
|
||||
if PAM_COND_FSHADOW
|
||||
SUBDIRS += pam_fshadow
|
||||
endif
|
||||
if PAM_COND_REGEX
|
||||
SUBDIRS += pam_regex
|
||||
endif
|
||||
if PAM_COND_LOG
|
||||
SUBDIRS += pam_log
|
||||
endif
|
||||
if PAM_COND_LDAPHOME
|
||||
SUBDIRS += pam_ldaphome
|
||||
endif
|
||||
if PAM_COND_UMOTD
|
||||
SUBDIRS += pam_umotd
|
||||
endif
|
||||
if PAM_COND_GROUPMEMBER
|
||||
SUBDIRS += pam_groupmember
|
||||
endif
|
||||
if PAM_COND_INNETGR
|
||||
SUBDIRS += pam_innetgr
|
||||
endif
|
||||
|
||||
EXTRA_DIST=ChangeLog.svn
|
||||
|
||||
# Name of the previous ChangeLog file.
|
||||
|
|
22
NEWS
22
NEWS
|
@ -1,8 +1,24 @@
|
|||
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
|
||||
|
||||
|
@ -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
|
||||
|
|
20
configure.ac
20
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)
|
||||
|
|
|
@ -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){\
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
173
doc/pam_innetgr.8
Normal file
173
doc/pam_innetgr.8
Normal file
|
@ -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:
|
|
@ -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";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
22
pam_innetgr/Makefile.am
Normal file
22
pam_innetgr/Makefile.am
Normal file
|
@ -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\"
|
319
pam_innetgr/pam_innetgr.c
Normal file
319
pam_innetgr/pam_innetgr.c
Normal file
|
@ -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 */
|
||||
|
||||
|
|
@ -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,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue