Relevant BUGIDs:

Purpose of commit:

Commit summary:
---------------

bugfix:

* Merge patches from Red Hat (Bug 477000 and other - kukuk)
* Fix pam_rhosts option parsing (Bug 922648 - kukuk)
This commit is contained in:
Thorsten Kukuk 2004-09-28 13:48:45 +00:00
parent 328d7328e5
commit 6fb0153746
23 changed files with 342 additions and 113 deletions

View File

@ -117,6 +117,8 @@ BerliOS Bugs are marked with (BerliOS #XXXX).
* Add the "broken_shadow" argument to pam_unix, for ignoring errors
reading shadow information (from Linux distributors - kukuk)
* Add patches to make PAM modules reentrant (Bug 440107 - kukuk)
* Merge patches from Red Hat (Bug 477000 and other - kukuk)
* Fix pam_rhosts option parsing (Bug 922648 - kukuk)
0.77: Mon Sep 23 10:25:42 PDT 2002

View File

@ -41,6 +41,7 @@ PIC=@PIC@
# Mode to install shared libraries with
SHLIBMODE=@SHLIBMODE@
# Mode to install man pages with
MANMODE=@MANMODE@
NEED_LINK_LIB_C=@PAM_NEEDS_LIBC@
@ -94,10 +95,12 @@ CRACKLIB_DICTPATH=@CRACKLIB_DICTPATH@
# generic build setup
OS=@OS@
CC=@CC@
CFLAGS=@CFLAGS@ $(WARNINGS) -D$(OS) $(OS_CFLAGS) $(HEADER_DIRS) @CONF_CFLAGS@
CFLAGS=$(WARNINGS) -D$(OS) @CFLAGS@ @CPPFLAGS@ $(OS_CFLAGS) $(HEADER_DIRS) @CONF_CFLAGS@
LDFLAGS=@LDFLAGS@
LD=@LD@
LD_D=@LD_D@
LD_L=@LD_L@
MV=@MV@
LDCONFIG=@LDCONFIG@
DYNTYPE=@DYNTYPE@
USESONAME=@USESONAME@
@ -112,6 +115,9 @@ CC_STATIC=@CC_STATIC@
LINKLIBS = $(NEED_LINK_LIB_C) $(LIBDL)
USESONAME=@USESONAME@
SOSWITCH=@SOSWITCH@
ifdef DYNAMIC
CFLAGS += $(PIC)
endif

View File

@ -11,9 +11,7 @@
DISTNAME=Linux-PAM
ifeq ($(shell test \! -f Make.Rules || echo yes),yes)
include Make.Rules
endif
-include Make.Rules
THINGSTOMAKE = libpam libpamc libpam_misc modules doc examples
@ -30,7 +28,7 @@ prep:
clean:
if [ ! -f Make.Rules ]; then touch Make.Rules ; fi
for i in $(THINGSTOMAKE) ; do $(MAKE) -C $$i clean ; done
rm -f security *~ *.orig *.rej Make.Rules #*#
rm -f security *~ *.orig *.rej #*#
distclean: clean
rm -f Make.Rules _pam_aconf.h
@ -75,4 +73,3 @@ release:
cd .. ; tar zvfc $(DISTNAME)-$(MAJOR_REL).$(MINOR_REL).tar.gz \
--exclude CVS --exclude .cvsignore --exclude '.#*' \
$(DISTNAME)-$(MAJOR_REL).$(MINOR_REL)/*

12
configure vendored
View File

@ -1347,8 +1347,8 @@ SHLIBMODE=755 ;
MANMODE=644 ;
USESONAME=yes ;
SOSWITCH='-Xlinker -soname -Xlinker ' ;
NEEDSONAME=no ;
SOSWITCH="-Wl,-soname -Wl," ;
NEEDSONAME=yes ;
LDCONFIG=/sbin/ldconfig ;
ac_ext=c
@ -6009,14 +6009,14 @@ if test "$GCC" = yes; then
### Example: -D_POSIX_SOURCE: needed on Linux but harms Solaris.
case $OS in
linux)
OS_CFLAGS="-ansi -D_POSIX_SOURCE -pedantic"
LD_D="gcc -shared -Xlinker -x"
OS_CFLAGS=
LD_D="$CC -shared $LDFLAGS"
WARNINGS="$GCC_WARNINGS"
PIC="-fPIC"
DYNTYPE=so
LD=gcc
LD_L="$LD -Xlinker -x -shared"
RANLIB=ranlib
LD_L="$CC -shared $LDFLAGS"
RANLIB=:
STRIP=strip
CC_STATIC="-Xlinker -export-dynamic"
;;

View File

@ -43,8 +43,8 @@ MANMODE=644 ; AC_SUBST(MANMODE)
dnl These are most likely platform specific - I think HPUX differs
USESONAME=yes ; AC_SUBST(USESONAME)
SOSWITCH='-Xlinker -soname -Xlinker ' ; AC_SUBST(SOSWITCH)
NEEDSONAME=no ; AC_SUBST(NEEDSONAME)
SOSWITCH="-Wl,-soname -Wl," ; AC_SUBST(SOSWITCH)
NEEDSONAME=yes ; AC_SUBST(NEEDSONAME)
LDCONFIG=/sbin/ldconfig ; AC_SUBST(LDCONFIG)
dnl Checks for programs.
@ -179,7 +179,7 @@ AC_CHECK_LIB(c, lckpwdf, HAVE_LCKPWDF=yes, HAVE_LCKPWDF=no)
AC_SUBST(HAVE_LCKPWDF)
dnl Checks for the existence of libdl - on BSD and Tru64 its part of libc
AC_CHECK_LIB(dl, dlopen, LIBDL=-ldl)
AC_CHECK_LIB(dl, dlopen, LIBDL=-ldl)
AC_SUBST(LIBDL)
dnl
@ -293,14 +293,14 @@ if test "$GCC" = yes; then
### Example: -D_POSIX_SOURCE: needed on Linux but harms Solaris.
case $OS in
linux)
OS_CFLAGS="-ansi -D_POSIX_SOURCE -pedantic"
LD_D="gcc -shared -Xlinker -x"
OS_CFLAGS=
LD_D="$CC -shared $LDFLAGS"
WARNINGS="$GCC_WARNINGS"
PIC="-fPIC"
DYNTYPE=so
LD=gcc
LD_L="$LD -Xlinker -x -shared"
RANLIB=ranlib
LD_L="$CC -shared $LDFLAGS"
RANLIB=:
STRIP=strip
CC_STATIC="-Xlinker -export-dynamic"
;;
@ -310,7 +310,7 @@ if test "$GCC" = yes; then
WARNINGS="$GCC_WARNINGS"
PIC="-fPIC"
DYNTYPE=so
LD=ld
LD=ld
LD_L="$LD -x -shared"
RANLIB=ranlib
STRIP=strip
@ -319,7 +319,7 @@ if test "$GCC" = yes; then
aix)
OS_CFLAGS=""
DYNTYPE=lo
LD=ld
LD=ld
LD_L=ld -bexpall -bM:SRE -bnoentry
LD_D="$LD_L"
RANLIB=ranlib

View File

@ -50,6 +50,8 @@ what is contained in that database.
<tt/icase/;
<tt/dump/;
<tt/db=XXXX/;
<tt/use_authtok/;
<tt/unknown_ok/;
<tag><bf>Description:</bf></tag>
@ -59,7 +61,7 @@ fields corresponding to the username keys are the passwords, in unencrypted form
so caution must be exercised over the access rights to the DB database itself..
The module will read the password from the user using the conversation mechanism. If
you are using this module on top of another authetication module (like <tt/pam_pwdb/;)
you are using this module on top of another authentication module (like <tt/pam_pwdb/;)
then you should tell that module to read the entered password from the PAM_AUTHTOK field, which is set by this module.
<p>
@ -85,6 +87,18 @@ use the database found on pathname XXXX. Note that Berkeley DB usually adds the
needed filename extension for you, so you should use something like <tt>/etc/foodata</tt>
instead of <tt>/etc/foodata.db</tt>.
<item> <tt/use_authtok/ -
use the authentication token previously obtained by another module that did the
conversation with the application. If this token can not be obtained then
the module will try to converse again. This option can be used for stacking
different modules that need to deal with the authentication tokens.
<item>
<tt/unknown_ok/ -
do not return error when checking for a user that is not in the database.
This can be used to stack more than one pam_userdb module that will check a
username/password pair in more than a database.
</itemize>
<tag><bf>Examples/suggested usage:</bf></tag>

View File

@ -268,7 +268,7 @@ that this enables.
be used, including RADIUS, NIS, NCP (which means that Novell
password databases can be used).
o pppd has a PAMified version (available from RedHat) Now it is
o pppd has a PAMified version (available from Red Hat) Now it is
possible to use a series of databases to authenticate ppp users.
In addition to the normal Linux-based password databases (such
as /etc/passwd and /etc/shadow), you can use PAM modules to

View File

@ -97,7 +97,7 @@ bootdir:
$(LIBPAM): $(DLIBOBJECTS)
ifeq ($(DYNAMIC_LIBPAM),yes)
ifeq ($(USESONAME),yes)
$(LD_L) $(SOSWITCH) $(LIBPAMNAME) -o $@ $(DLIBOBJECTS) \
$(LD_L) $(SOSWITCH)$(LIBPAMNAME) -o $@ $(DLIBOBJECTS) \
$(MODULES) $(LINKLIBS)
else
$(LD_L) -o $@ $(DLIBOBJECTS) $(MODULES) $(LINKLIBS)
@ -112,9 +112,11 @@ endif
$(LIBPAMSTATIC): $(SLIBOBJECTS)
ifeq ($(STATIC_LIBPAM),yes)
$(AR) cr $@ $(SLIBOBJECTS) $(MODULES)
$(AR) cru $@ $(SLIBOBJECTS) $(MODULES)
ifdef RANLIB
$(RANLIB) $@
endif
endif
install: all
$(MKDIR) $(FAKEROOT)$(INCLUDED) $(FAKEROOT)$(libdir)

View File

@ -60,9 +60,9 @@ static/%.o : %.c
$(LIBNAMED): $(DLIBOBJECTS)
ifeq ($(DYNAMIC_LIBPAM),yes)
ifeq ($(USESONAME),yes)
$(LD_L) $(SOSWITCH) $(LIBNAMEDNAME) -o $@ $(DLIBOBJECTS) $(MODULES) $(LINKLIBS)
$(LD_L) $(SOSWITCH)$(LIBNAMEDNAME) -o $@ $(DLIBOBJECTS) $(MODULES) $(LINKLIBS)
else
$(LD_L) -o $@ $(DLIBOBJECTS) $(MODULES)
$(LD_L) -o $@ $(DLIBOBJECTS) $(MODULES) $(LINKLIBS)
endif
ifeq ($(NEEDSONAME),yes)
rm -f $(LIBNAMEDFULL)
@ -74,9 +74,12 @@ endif
$(LIBNAMEDSTATIC): $(SLIBOBJECTS)
ifeq ($(STATIC_LIBPAM),yes)
$(AR) rcu $@ $(SLIBOBJECTS) $(MODULES)
ifdef RANLIB
$(AR) rc $@ $(SLIBOBJECTS) $(MODULES)
$(RANLIB) $@
endif
endif
install: all
$(MKDIR) $(FAKEROOT)$(INCLUDED)

View File

@ -59,7 +59,7 @@ static/%.o : %.c
$(LIBNAMED): $(DLIBOBJECTS)
ifeq ($(DYNAMIC_LIBPAM),yes)
ifeq ($(USESONAME),yes)
$(LD_L) $(SOSWITCH) $(LIBNAMEDNAME) -o $@ $(DLIBOBJECTS) $(MODULES) $(LINKLIBS)
$(LD_L) $(SOSWITCH)$(LIBNAMEDNAME) -o $@ $(DLIBOBJECTS) $(MODULES) $(LINKLIBS)
else
$(LD_L) -o $@ $(DLIBOBJECTS) $(MODULES)
endif
@ -73,9 +73,11 @@ endif
$(LIBNAMEDSTATIC): $(SLIBOBJECTS)
ifeq ($(STATIC_LIBPAM),yes)
$(AR) rc $@ $(SLIBOBJECTS) $(MODULES)
$(AR) rcu $@ $(SLIBOBJECTS) $(MODULES)
ifdef RANLIB
$(RANLIB) $@
endif
endif
install: all
$(MKDIR) $(FAKEROOT)$(INCLUDED)

View File

@ -8,7 +8,7 @@
include ../Make.Rules
MODDIRS=$(shell /bin/ls -d pam_*)
MODDIRS=$(shell /bin/ls -d pam_*/Makefile | cut -f1 -d/)
all:
@echo building the static modutil library

View File

@ -13,6 +13,8 @@
# $(MODULE_SIMPLE_EXTRAFILES) - other files to build (no .c suffix)
#
-include ../Make.Rules
LIBFILES = $(TITLE) $(MODULE_SIMPLE_EXTRAFILES)
LIBSRC = $(addsuffix .c,$(LIBFILES))
LIBOBJ = $(addsuffix .o,$(LIBFILES))

View File

@ -150,7 +150,7 @@ static int process_args(pam_handle_t *pamh
/* the "ARGS" variable */
#define ARGS_OFFSET 5 /* sizeof('ARGS='); */
#define ARGS_OFFSET 5 /* strlen('ARGS='); */
#define ARGS_NAME "ARGS="
size += ARGS_OFFSET;
@ -174,7 +174,7 @@ static int process_args(pam_handle_t *pamh
/* the "SERVICE" variable */
#define SERVICE_OFFSET 8 /* sizeof('SERVICE='); */
#define SERVICE_OFFSET 8 /* strlen('SERVICE='); */
#define SERVICE_NAME "SERVICE="
retval = pam_get_item(pamh, PAM_SERVICE, (const void **)&tmp);
@ -204,7 +204,7 @@ static int process_args(pam_handle_t *pamh
/* the "USER" variable */
#define USER_OFFSET 5 /* sizeof('USER='); */
#define USER_OFFSET 5 /* strlen('USER='); */
#define USER_NAME "USER="
tmp = NULL;
@ -231,7 +231,7 @@ static int process_args(pam_handle_t *pamh
/* the "USER" variable */
#define TYPE_OFFSET 5 /* sizeof('TYPE='); */
#define TYPE_OFFSET 5 /* strlen('TYPE='); */
#define TYPE_NAME "TYPE="
size = TYPE_OFFSET+strlen(type);

View File

@ -27,6 +27,9 @@ endif
include ../Simple.Rules
#else
#include ../dont_makefile
#endif
else
include ../dont_makefile

View File

@ -17,6 +17,9 @@ EXTRAS += -DCHKPWD_HELPER=\"$(SUPLEMENTED)/$(CHKPWD)\"
ifeq ($(HAVE_LIBCRYPT),yes)
EXTRALS += -lcrypt
endif
ifeq ($(HAVE_LIBNSL),yes)
EXTRALS += -lnsl
endif
TITLE=pam_pwdb
CHKPWD=pwdb_chkpwd
@ -53,7 +56,7 @@ info:
$(CHKPWD): pwdb_chkpwd.o md5_good.o md5_broken.o \
md5_crypt_good.o md5_crypt_broken.o
$(CC) -o $(CHKPWD) $^ -lpwdb
$(CC) $(CFLAGS) -o $(CHKPWD) $^ $(LDFLAGS) -lpwdb $(EXTRALS)
pwdb_chkpwd.o: pwdb_chkpwd.c pam_unix_md.-c bigcrypt.-c

View File

@ -178,7 +178,7 @@ static void set_option (struct _options *opts, const char *arg)
return;
}
if (strcmp(arg, "superuser=") == 0) {
if (strncmp(arg, "superuser=", sizeof("superuser=")-1) == 0) {
opts->superuser = arg+sizeof("superuser=")-1;
return;
}
@ -293,7 +293,7 @@ __icheckhost (pam_handle_t *pamh, struct _options *opts, U32 raddr
hp = gethostbyname(lhost);
if (hp == NULL)
return (0);
/* Spin through ip addresses. */
for (pp = hp->h_addr_list; *pp; ++pp)
if (!memcmp (&raddr, *pp, sizeof (U32)))
@ -408,7 +408,7 @@ __ivaliduser (pam_handle_t *pamh, struct _options *opts,
user = p; /* this is the user's name */
while (*p && !isspace(*p))
++p; /* find end of user's name */
} else
} else
user = p;
*p = '\0'; /* <nul> terminate username (+host?) */
@ -480,7 +480,7 @@ pam_iruserok(pam_handle_t *pamh,
No hosts.equiv file on system.
} */
}
if ( opts->opt_no_rhosts )
return 1;
@ -490,10 +490,10 @@ pam_iruserok(pam_handle_t *pamh,
pwd = _pammodutil_getpwnam(pamh, luser);
if (pwd == NULL) {
/*
/*
* luser is assumed to be valid because of an earlier check for uid = 0
* we don't log this error twice. However, this shouldn't happen !
* --cristiang
* --cristiang
*/
return(1);
}
@ -652,9 +652,9 @@ pam_ruserok (pam_handle_t *pamh,
*/
static int _pam_auth_rhosts (pam_handle_t *pamh,
int flags,
int flags,
int argc,
const char **argv)
const char **argv)
{
int retval;
const char *luser = NULL;
@ -745,9 +745,9 @@ static int _pam_auth_rhosts (pam_handle_t *pamh,
/* --- authentication management functions --- */
PAM_EXTERN
int pam_sm_authenticate (pam_handle_t *pamh,
int pam_sm_authenticate (pam_handle_t *pamh,
int flags,
int argc,
int argc,
const char **argv)
{
int retval;

View File

@ -18,6 +18,19 @@ include ../../Make.Rules
#USE_CRACKLIB=-D"USE_CRACKLIB"
#endif
ifeq ($(shell if [ -f /usr/lib/cracklib_dict.hwm ]; then echo yes ; fi),yes)
CRACKLIB_DICTPATH=/usr/lib/cracklib_dict
else
CRACKLIB_DICTPATH=/usr/share/dict/cracklib_dict
endif
EXTRAS += -DCRACKLIB_DICTS=\"$(CRACKLIB_DICTPATH)\"
ifeq ($(HAVE_LIBCRYPT),yes)
EXTRALS += -lcrypt
endif
ifeq ($(HAVE_LIBNSL),yes)
EXTRALS += -lnsl
endif
# do you want to use lckpwdf?
ifeq ($(WITH_LCKPWDF),yes)
USE_LCKPWDF=-D"USE_LCKPWDF"
@ -37,6 +50,8 @@ endif
CHKPWD=unix_chkpwd
BIGCRYPT=bigcrypt
EXTRAS += -DCHKPWD_HELPER=\"$(SUPLEMENTED)/$(CHKPWD)\"
LINK_PAMMODUTILS = -L../pammodutil -lpammodutil
@ -74,7 +89,8 @@ endif
########################### don't edit below #######################
all: dirs info $(PLUS) $(LIBSHARED) $(LIBSTATIC) $(CHKPWD) register
all: dirs info $(PLUS) $(LIBSHARED) $(LIBSTATIC) $(CHKPWD) $(BIGCRYPT) \
register
dynamic/%.o : %.c
$(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
@ -125,7 +141,10 @@ endif
$(CHKPWD): unix_chkpwd.o md5_good.o md5_broken.o \
md5_crypt_good.o md5_crypt_broken.o \
bigcrypt.o
$(CC) -o $(CHKPWD) $^ $(LDLIBS) $(LIBCRYPT)
$(CC) $(CFLAGS) -o $(CHKPWD) $^ $(LDLIBS) $(LIBCRYPT)
$(BIGCRYPT): bigcrypt_main.o bigcrypt.o
$(CC) -o $(BIGCRYPT) $^ $(LDLIBS) $(LIBCRYPT)
unix_chkpwd.o: unix_chkpwd.c
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@

View File

@ -0,0 +1,18 @@
#include <stdio.h>
#include <string.h>
extern const char *bigcrypt(const char *password, const char *salt);
int
main(int argc, char **argv)
{
if (argc < 3) {
fprintf(stderr, "Usage: %s password salt\n",
strchr(argv[0], '/') ?
(strchr(argv[0], '/') + 1) :
argv[0]);
return 0;
}
fprintf(stdout, "%s\n", bigcrypt(argv[1], argv[2]));
return 0;
}

View File

@ -1,6 +1,7 @@
pam_userdb:
Look up users in a .db database and verify their password against
what is contained in that database.
what is contained in that database. The database will have been
created using db_load.
RECOGNIZED ARGUMENTS:
debug write a message to syslog indicating success or
@ -8,7 +9,9 @@ RECOGNIZED ARGUMENTS:
db=[path] use the [path] database for performing lookup. There
is no default; the module will return PAM_IGNORE if
no database is provided.
no database is provided. Some versions of DB will
automatically append ".db" to whatever pathname you
supply here.
crypt=[mode] indicates whether encrypted or plaintext passwords
are stored in the database. If [mode] is "crypt",
@ -24,8 +27,28 @@ RECOGNIZED ARGUMENTS:
dump dump all the entries in the database to the log (eek,
don't do this by default!)
use_authtok use the authentication token previously obtained by
another module that did the conversation with the
application. If this token can not be obtained then
the module will try to converse again. This option can
be used for stacking different modules that need to
deal with the authentication tokens.
unknown_ok do not return error when checking for a user that is
not in the database. This can be used to stack more
than one pam_userdb module that will check a
username/password pair in more than a database.
key_only the username and password are concatenated together
in the database hash as 'username-password' with a
random value. if the concatenation of the username and
password with a dash in the middle returns any result,
the user is valid. this is useful in cases where
the username may not be unique but the username and
password pair are.
MODULE SERVICES PROVIDED:
auth _authetication and _setcred (blank)
auth _authentication and _setcred (blank)
EXAMPLE USE:
auth sufficient pam_userdb.so icase db=/tmp/dbtest.db

View File

@ -5,8 +5,6 @@
/* $Id */
/* Copyright at the end of the file */
#define _BSD_SOURCE
#include <stdlib.h>
#include <string.h>

View File

@ -7,7 +7,7 @@
use DB_File;
my $database = $ARGV[0];
die "Use: check,pl <database>\n" unless ($database);
die "Use: create.pl <database>\n" unless ($database);
print "Using database: $database\n";
my %lusers = ();

View File

@ -1,5 +1,5 @@
/* pam_userdb module */
/*
* $Id$
* Written by Cristian Gafton <gafton@redhat.com> 1996/09/10
@ -8,6 +8,7 @@
#include <security/_pam_aconf.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
@ -56,39 +57,53 @@ static void _pam_log(int err, const char *format, ...)
closelog();
}
char * database = NULL;
char * cryptmode = NULL;
static int ctrl = 0;
static int _pam_parse(int argc, const char **argv)
static int
_pam_parse (int argc, const char **argv,
char **database, char **cryptmode)
{
/* step through arguments */
for (ctrl = 0; argc-- > 0; ++argv) {
int ctrl;
/* generic options */
*database = NULL;
*cryptmode = NULL;
if (!strcmp(*argv,"debug"))
ctrl |= PAM_DEBUG_ARG;
else if (!strcasecmp(*argv, "icase"))
ctrl |= PAM_ICASE_ARG;
else if (!strcasecmp(*argv, "dump"))
ctrl |= PAM_DUMP_ARG;
else if (!strncasecmp(*argv,"db=", 3)) {
database = strdup((*argv) + 3);
if (database == NULL)
_pam_log(LOG_ERR, "pam_parse: could not parse argument \"%s\"",
*argv);
} else if (!strncasecmp(*argv,"crypt=", 6)) {
cryptmode = strdup((*argv) + 6);
if (cryptmode == NULL)
_pam_log(LOG_ERR, "pam_parse: could not parse argument \"%s\"",
*argv);
} else {
_pam_log(LOG_ERR, "pam_parse: unknown option; %s", *argv);
}
}
/* step through arguments */
for (ctrl = 0; argc-- > 0; ++argv)
{
/* generic options */
return ctrl;
if (!strcmp(*argv,"debug"))
ctrl |= PAM_DEBUG_ARG;
else if (!strcasecmp(*argv, "icase"))
ctrl |= PAM_ICASE_ARG;
else if (!strcasecmp(*argv, "dump"))
ctrl |= PAM_DUMP_ARG;
else if (!strcasecmp(*argv, "unknown_ok"))
ctrl |= PAM_UNKNOWN_OK_ARG;
else if (!strcasecmp(*argv, "key_only"))
ctrl |= PAM_KEY_ONLY_ARG;
else if (!strncasecmp(*argv,"db=", 3))
{
*database = strdup((*argv) + 3);
if ((*database == NULL) || (strlen (*database) == 0))
_pam_log(LOG_ERR,
"pam_parse: could not parse argument \"%s\"",
*argv);
}
else if (!strncasecmp(*argv,"crypt=", 6))
{
*cryptmode = strdup((*argv) + 6);
if ((*cryptmode == NULL) || (strlen (*cryptmode) == 0))
_pam_log(LOG_ERR,
"pam_parse: could not parse argument \"%s\"",
*argv);
}
else
{
_pam_log(LOG_ERR, "pam_parse: unknown option; %s", *argv);
}
}
return ctrl;
}
@ -101,7 +116,9 @@ static int _pam_parse(int argc, const char **argv)
* -1 = Password incorrect
* -2 = System error
*/
static int user_lookup(const char *user, const char *pass)
static int
user_lookup (const char *database, const char *cryptmode,
const char *user, const char *pass, int ctrl)
{
DBM *dbm;
datum key, data;
@ -114,7 +131,8 @@ static int user_lookup(const char *user, const char *pass)
return -2;
}
if (ctrl &PAM_DUMP_ARG) {
/* dump out the database contents for debugging */
if (ctrl & PAM_DUMP_ARG) {
_pam_log(LOG_INFO, "Database dump:");
for (key = dbm_firstkey(dbm); key.dptr != NULL;
key = dbm_nextkey(dbm)) {
@ -122,14 +140,19 @@ static int user_lookup(const char *user, const char *pass)
_pam_log(LOG_INFO, "key[len=%d] = `%s', data[len=%d] = `%s'",
key.dsize, key.dptr, data.dsize, data.dptr);
}
}
/* do some more init work */
}
/* do some more init work */
memset(&key, 0, sizeof(key));
memset(&data, 0, sizeof(data));
key.dptr = x_strdup(user);
key.dsize = strlen(user);
user = NULL;
if (ctrl & PAM_KEY_ONLY_ARG) {
key.dptr = malloc(strlen(user) + 1 + strlen(pass) + 1);
sprintf(key.dptr, "%s-%s", user, pass);
key.dsize = strlen(key.dptr);
} else {
key.dptr = x_strdup(user);
key.dsize = strlen(user);
}
if (key.dptr) {
data = dbm_fetch(dbm, key);
@ -144,7 +167,13 @@ static int user_lookup(const char *user, const char *pass)
if (data.dptr != NULL) {
int compare = 0;
if (ctrl & PAM_KEY_ONLY_ARG)
{
dbm_close (dbm);
return 0; /* found it, data contents don't matter */
}
if (strncasecmp(cryptmode, "crypt", 5) == 0) {
/* crypt(3) password storage */
@ -166,7 +195,7 @@ static int user_lookup(const char *user, const char *pass)
compare = strncasecmp (data.dptr, cryptpw, data.dsize);
} else {
compare = -2;
if (ctrl & PAM_DEBUG_ARG) {
if (ctrl & PAM_DEBUG_ARG) {
_pam_log(LOG_INFO, "crypt() returned NULL");
}
};
@ -174,20 +203,20 @@ static int user_lookup(const char *user, const char *pass)
};
} else {
/* Unknown password encryption method -
* default to plaintext password storage
*/
if (strlen(pass) != data.dsize) {
compare = 1;
compare = 1; /* wrong password len -> wrong password */
} else if (ctrl & PAM_ICASE_ARG) {
compare = strncasecmp(data.dptr, pass, data.dsize);
} else {
compare = strncmp(data.dptr, pass, data.dsize);
}
if (strncasecmp(cryptmode, "none", 4) && ctrl & PAM_DEBUG_ARG) {
if (strncasecmp(cryptmode, "none", 4) && ctrl & PAM_DEBUG_ARG) {
_pam_log(LOG_INFO, "invalid value for crypt parameter: %s",
cryptmode);
_pam_log(LOG_INFO, "defaulting to plaintext password mode");
@ -201,13 +230,58 @@ static int user_lookup(const char *user, const char *pass)
else
return -1; /* wrong */
} else {
if (ctrl & PAM_DEBUG_ARG) {
int saw_user = 0;
if (ctrl & PAM_DEBUG_ARG) {
_pam_log(LOG_INFO, "error returned by dbm_fetch: %s",
strerror(errno));
}
dbm_close(dbm);
/* probably we should check dbm_error() here */
return 1; /* not found */
if ((ctrl & PAM_KEY_ONLY_ARG) == 0) {
dbm_close(dbm);
return 1; /* not key_only, so no entry => no entry for the user */
}
/* now handle the key_only case */
for (key = dbm_firstkey(dbm);
key.dptr != NULL;
key = dbm_nextkey(dbm)) {
int compare;
/* first compare the user portion (case sensitive) */
compare = strncmp(key.dptr, user, strlen(user));
if (compare == 0) {
/* assume failure */
compare = -1;
/* if we have the divider where we expect it to be... */
if (key.dptr[strlen(user)] == '-') {
saw_user = 1;
if (key.dsize == strlen(user) + 1 + strlen(pass)) {
if (ctrl & PAM_ICASE_ARG) {
/* compare the password portion (case insensitive)*/
compare = strncasecmp(key.dptr + strlen(user) + 1,
pass,
strlen(pass));
} else {
/* compare the password portion (case sensitive) */
compare = strncmp(key.dptr + strlen(user) + 1,
pass,
strlen(pass));
}
}
}
if (compare == 0) {
dbm_close(dbm);
return 0; /* match */
}
}
}
dbm_close(dbm);
if (saw_user)
return -1; /* saw the user, but password mismatch */
else
return 1; /* not found */
}
/* NOT REACHED */
@ -222,10 +296,17 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags,
{
const char *username;
const char *password;
int retval = PAM_AUTH_ERR;
char *database = NULL;
char *cryptmode = NULL;
int retval = PAM_AUTH_ERR, ctrl;
/* parse arguments */
ctrl = _pam_parse(argc, argv);
ctrl = _pam_parse(argc, argv, &database, &cryptmode);
if ((database == NULL) || (strlen(database) == 0)) {
if (ctrl & PAM_DEBUG_ARG)
_pam_log(LOG_DEBUG,"can not get the database name");
return PAM_SERVICE_ERR;
}
/* Get the username */
retval = pam_get_user(pamh, &username, NULL);
@ -234,32 +315,47 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags,
_pam_log(LOG_DEBUG,"can not get the username");
return PAM_SERVICE_ERR;
}
/* Converse just to be sure we have the password */
/* Converse just to be sure we have a password */
retval = conversation(pamh);
if (retval != PAM_SUCCESS) {
_pam_log(LOG_ERR, "could not obtain password for `%s'",
username);
return -2;
return PAM_CONV_ERR;
}
/* Check if we got a password. The docs say that if we didn't have one,
* and use_authtok was specified as an argument, that we converse with the
* user anyway, so check for one and handle a failure for that case. If
* use_authtok wasn't specified, then we've already asked once and needn't
* do so again. */
retval = pam_get_item(pamh, PAM_AUTHTOK, (const void **) &password);
if ((retval != PAM_SUCCESS) && ((ctrl & PAM_USE_AUTHTOK_ARG) != 0)) {
retval = conversation(pamh);
if (retval != PAM_SUCCESS) {
_pam_log(LOG_ERR, "could not obtain password for `%s'",
username);
return PAM_CONV_ERR;
}
}
/* Get the password */
retval = pam_get_item(pamh, PAM_AUTHTOK, (const void **)&password);
if (retval != PAM_SUCCESS) {
_pam_log(LOG_ERR, "Could not retrive user's password");
_pam_log(LOG_ERR, "Could not retrieve user's password");
return -2;
}
if (ctrl & PAM_DEBUG_ARG)
_pam_log(LOG_INFO, "Verify user `%s' with password `%s'",
username, password);
/* Now use the username to look up password in the database file */
retval = user_lookup(username, password);
retval = user_lookup(database, cryptmode, username, password, ctrl);
switch (retval) {
case -2:
/* some sort of system error. The log was already printed */
return PAM_SERVICE_ERR;
return PAM_SERVICE_ERR;
case -1:
/* incorrect password */
_pam_log(LOG_WARNING,
@ -296,9 +392,47 @@ int pam_sm_setcred(pam_handle_t *pamh, int flags,
}
PAM_EXTERN
int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
int argc, const char **argv)
int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv)
{
const char *username;
char *database = NULL;
char *cryptmode = NULL;
int retval = PAM_AUTH_ERR, ctrl;
/* parse arguments */
ctrl = _pam_parse(argc, argv, &database, &cryptmode);
/* Get the username */
retval = pam_get_user(pamh, &username, NULL);
if ((retval != PAM_SUCCESS) || (!username)) {
if (ctrl & PAM_DEBUG_ARG)
_pam_log(LOG_DEBUG,"can not get the username");
return PAM_SERVICE_ERR;
}
/* Now use the username to look up password in the database file */
retval = user_lookup(database, cryptmode, username, "", ctrl);
switch (retval) {
case -2:
/* some sort of system error. The log was already printed */
return PAM_SERVICE_ERR;
case -1:
/* incorrect password, but we don't care */
/* FALL THROUGH */
case 0:
/* authentication succeeded. dumbest password ever. */
return PAM_SUCCESS;
case 1:
/* the user does not exist in the database */
return PAM_USER_UNKNOWN;
default:
/* we don't know anything about this return value */
_pam_log(LOG_ERR,
"internal module error (retval = %d, user = `%s'",
retval, username);
return PAM_SERVICE_ERR;
}
return PAM_SUCCESS;
}
@ -311,7 +445,7 @@ struct pam_module _pam_userdb_modstruct = {
"pam_userdb",
pam_sm_authenticate,
pam_sm_setcred,
NULL,
pam_sm_acct_mgmt,
NULL,
NULL,
NULL,

View File

@ -10,6 +10,9 @@
#define PAM_DEBUG_ARG 0x0001
#define PAM_ICASE_ARG 0x0002
#define PAM_DUMP_ARG 0x0004
#define PAM_USE_AUTHTOK_ARG 0x0008
#define PAM_UNKNOWN_OK_ARG 0x0010
#define PAM_KEY_ONLY_ARG 0x0020
/* Useful macros */
#define x_strdup(s) ( (s) ? strdup(s):NULL )