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:
Sergey Poznyakoff 2018-08-12 19:20:04 +03:00
parent 23b718d2a3
commit 6bba235d66
11 changed files with 740 additions and 50 deletions

View file

@ -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
View file

@ -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

View file

@ -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)

View file

@ -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){\

View file

@ -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
View 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:

View file

@ -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";
}
}

View file

@ -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
View 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
View 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 */

View file

@ -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,