* 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
# Mode to install shared libraries with
SHLIBMODE=@SHLIBMODE@
+# Mode to install man pages with
MANMODE=@MANMODE@
NEED_LINK_LIB_C=@PAM_NEEDS_LIBC@
# 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@
LINKLIBS = $(NEED_LINK_LIB_C) $(LIBDL)
+USESONAME=@USESONAME@
+SOSWITCH=@SOSWITCH@
+
ifdef DYNAMIC
CFLAGS += $(PIC)
endif
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
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
cd .. ; tar zvfc $(DISTNAME)-$(MAJOR_REL).$(MINOR_REL).tar.gz \
--exclude CVS --exclude .cvsignore --exclude '.#*' \
$(DISTNAME)-$(MAJOR_REL).$(MINOR_REL)/*
-
MANMODE=644 ;
USESONAME=yes ;
-SOSWITCH='-Xlinker -soname -Xlinker ' ;
-NEEDSONAME=no ;
+SOSWITCH="-Wl,-soname -Wl," ;
+NEEDSONAME=yes ;
LDCONFIG=/sbin/ldconfig ;
ac_ext=c
### 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"
;;
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.
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
### 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"
;;
WARNINGS="$GCC_WARNINGS"
PIC="-fPIC"
DYNTYPE=so
- LD=ld
+ LD=ld
LD_L="$LD -x -shared"
RANLIB=ranlib
STRIP=strip
aix)
OS_CFLAGS=""
DYNTYPE=lo
- LD=ld
+ LD=ld
LD_L=ld -bexpall -bM:SRE -bnoentry
LD_D="$LD_L"
RANLIB=ranlib
<tt/icase/;
<tt/dump/;
<tt/db=XXXX/;
+<tt/use_authtok/;
+<tt/unknown_ok/;
<tag><bf>Description:</bf></tag>
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>
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>
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
$(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)
$(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)
$(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)
$(LIBNAMEDSTATIC): $(SLIBOBJECTS)
ifeq ($(STATIC_LIBPAM),yes)
+ $(AR) rcu $@ $(SLIBOBJECTS) $(MODULES)
+ifdef RANLIB
$(AR) rc $@ $(SLIBOBJECTS) $(MODULES)
$(RANLIB) $@
endif
+endif
install: all
$(MKDIR) $(FAKEROOT)$(INCLUDED)
$(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
$(LIBNAMEDSTATIC): $(SLIBOBJECTS)
ifeq ($(STATIC_LIBPAM),yes)
- $(AR) rc $@ $(SLIBOBJECTS) $(MODULES)
+ $(AR) rcu $@ $(SLIBOBJECTS) $(MODULES)
+ifdef RANLIB
$(RANLIB) $@
endif
+endif
install: all
$(MKDIR) $(FAKEROOT)$(INCLUDED)
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
# $(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))
/* the "ARGS" variable */
-#define ARGS_OFFSET 5 /* sizeof('ARGS='); */
+#define ARGS_OFFSET 5 /* strlen('ARGS='); */
#define ARGS_NAME "ARGS="
size += ARGS_OFFSET;
/* 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);
/* the "USER" variable */
-#define USER_OFFSET 5 /* sizeof('USER='); */
+#define USER_OFFSET 5 /* strlen('USER='); */
#define USER_NAME "USER="
tmp = NULL;
/* the "USER" variable */
-#define TYPE_OFFSET 5 /* sizeof('TYPE='); */
+#define TYPE_OFFSET 5 /* strlen('TYPE='); */
#define TYPE_NAME "TYPE="
size = TYPE_OFFSET+strlen(type);
include ../Simple.Rules
+#else
+#include ../dont_makefile
+#endif
else
include ../dont_makefile
ifeq ($(HAVE_LIBCRYPT),yes)
EXTRALS += -lcrypt
endif
+ifeq ($(HAVE_LIBNSL),yes)
+ EXTRALS += -lnsl
+endif
TITLE=pam_pwdb
CHKPWD=pwdb_chkpwd
$(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
return;
}
- if (strcmp(arg, "superuser=") == 0) {
+ if (strncmp(arg, "superuser=", sizeof("superuser=")-1) == 0) {
opts->superuser = arg+sizeof("superuser=")-1;
return;
}
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)))
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?) */
No hosts.equiv file on system.
} */
}
-
+
if ( opts->opt_no_rhosts )
return 1;
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);
}
*/
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;
/* --- 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;
#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"
CHKPWD=unix_chkpwd
+BIGCRYPT=bigcrypt
+
EXTRAS += -DCHKPWD_HELPER=\"$(SUPLEMENTED)/$(CHKPWD)\"
LINK_PAMMODUTILS = -L../pammodutil -lpammodutil
########################### 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 $@
$(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 $@
--- /dev/null
+#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;
+}
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
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",
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
/* $Id */
/* Copyright at the end of the file */
-#define _BSD_SOURCE
-
#include <stdlib.h>
#include <string.h>
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 = ();
/* pam_userdb module */
-
+
/*
* $Id$
* Written by Cristian Gafton <gafton@redhat.com> 1996/09/10
#include <security/_pam_aconf.h>
+#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
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) {
-
- /* generic options */
-
- 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);
- }
- }
+ int ctrl;
+
+ *database = NULL;
+ *cryptmode = NULL;
+
+ /* step through arguments */
+ for (ctrl = 0; argc-- > 0; ++argv)
+ {
+ /* generic options */
+
+ 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;
+ return ctrl;
}
* -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;
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)) {
_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);
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 */
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");
}
};
};
} 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");
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 */
{
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);
_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,
}
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;
}
"pam_userdb",
pam_sm_authenticate,
pam_sm_setcred,
- NULL,
+ pam_sm_acct_mgmt,
NULL,
NULL,
NULL,
#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 )