From 6fb01537462a326a139f0c2d975145b26cd54bbe Mon Sep 17 00:00:00 2001 From: Thorsten Kukuk Date: Tue, 28 Sep 2004 13:48:45 +0000 Subject: [PATCH] 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) --- CHANGELOG | 2 + Make.Rules.in | 8 +- Makefile | 7 +- configure | 12 +- configure.in | 18 +- doc/modules/pam_userdb.sgml | 16 +- doc/pam_source.sgml | 2 +- libpam/Makefile | 6 +- libpam_misc/Makefile | 7 +- libpamc/Makefile | 6 +- modules/Makefile | 2 +- modules/Simple.Rules | 2 + modules/pam_filter/pam_filter.c | 8 +- modules/pam_limits/Makefile | 3 + modules/pam_pwdb/Makefile | 5 +- modules/pam_rhosts/pam_rhosts_auth.c | 20 +-- modules/pam_unix/Makefile | 23 ++- modules/pam_unix/bigcrypt_main.c | 18 ++ modules/pam_userdb/README | 29 ++- modules/pam_userdb/conv.c | 2 - modules/pam_userdb/create.pl | 2 +- modules/pam_userdb/pam_userdb.c | 258 ++++++++++++++++++++------- modules/pam_userdb/pam_userdb.h | 3 + 23 files changed, 344 insertions(+), 115 deletions(-) create mode 100644 modules/pam_unix/bigcrypt_main.c diff --git a/CHANGELOG b/CHANGELOG index 377d80bc..82b9ab91 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -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 diff --git a/Make.Rules.in b/Make.Rules.in index 781bbd03..722d028f 100644 --- a/Make.Rules.in +++ b/Make.Rules.in @@ -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 diff --git a/Makefile b/Makefile index 562802d3..71136952 100644 --- a/Makefile +++ b/Makefile @@ -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)/* - diff --git a/configure b/configure index 555f16a7..27756779 100755 --- a/configure +++ b/configure @@ -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" ;; diff --git a/configure.in b/configure.in index 73734335..d673e3af 100644 --- a/configure.in +++ b/configure.in @@ -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 diff --git a/doc/modules/pam_userdb.sgml b/doc/modules/pam_userdb.sgml index bdbf80b8..155a2668 100644 --- a/doc/modules/pam_userdb.sgml +++ b/doc/modules/pam_userdb.sgml @@ -50,6 +50,8 @@ what is contained in that database. Description: @@ -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 @@ -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 /etc/foodata instead of /etc/foodata.db. + + Examples/suggested usage: diff --git a/doc/pam_source.sgml b/doc/pam_source.sgml index 2ea9a7c9..8e641032 100644 --- a/doc/pam_source.sgml +++ b/doc/pam_source.sgml @@ -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 diff --git a/libpam/Makefile b/libpam/Makefile index 6728d635..2a55577f 100644 --- a/libpam/Makefile +++ b/libpam/Makefile @@ -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) diff --git a/libpam_misc/Makefile b/libpam_misc/Makefile index 88364a24..bb7ec27c 100644 --- a/libpam_misc/Makefile +++ b/libpam_misc/Makefile @@ -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) diff --git a/libpamc/Makefile b/libpamc/Makefile index 0a302534..f15aadd8 100644 --- a/libpamc/Makefile +++ b/libpamc/Makefile @@ -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) diff --git a/modules/Makefile b/modules/Makefile index 93891029..d16dedcf 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -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 diff --git a/modules/Simple.Rules b/modules/Simple.Rules index 97f419a8..c12ede3a 100644 --- a/modules/Simple.Rules +++ b/modules/Simple.Rules @@ -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)) diff --git a/modules/pam_filter/pam_filter.c b/modules/pam_filter/pam_filter.c index e9a0494b..d3462f40 100644 --- a/modules/pam_filter/pam_filter.c +++ b/modules/pam_filter/pam_filter.c @@ -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); diff --git a/modules/pam_limits/Makefile b/modules/pam_limits/Makefile index 0a481fe8..5aeb73ce 100644 --- a/modules/pam_limits/Makefile +++ b/modules/pam_limits/Makefile @@ -27,6 +27,9 @@ endif include ../Simple.Rules +#else +#include ../dont_makefile +#endif else include ../dont_makefile diff --git a/modules/pam_pwdb/Makefile b/modules/pam_pwdb/Makefile index 2b581dcd..fa0e1b02 100644 --- a/modules/pam_pwdb/Makefile +++ b/modules/pam_pwdb/Makefile @@ -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 diff --git a/modules/pam_rhosts/pam_rhosts_auth.c b/modules/pam_rhosts/pam_rhosts_auth.c index 374318dc..b41b708d 100644 --- a/modules/pam_rhosts/pam_rhosts_auth.c +++ b/modules/pam_rhosts/pam_rhosts_auth.c @@ -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'; /* 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; diff --git a/modules/pam_unix/Makefile b/modules/pam_unix/Makefile index 3fe0e8ae..24ffd4b5 100644 --- a/modules/pam_unix/Makefile +++ b/modules/pam_unix/Makefile @@ -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 $@ diff --git a/modules/pam_unix/bigcrypt_main.c b/modules/pam_unix/bigcrypt_main.c new file mode 100644 index 00000000..70819072 --- /dev/null +++ b/modules/pam_unix/bigcrypt_main.c @@ -0,0 +1,18 @@ +#include +#include + +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; +} diff --git a/modules/pam_userdb/README b/modules/pam_userdb/README index 9fa6519d..fc56cfa0 100644 --- a/modules/pam_userdb/README +++ b/modules/pam_userdb/README @@ -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 diff --git a/modules/pam_userdb/conv.c b/modules/pam_userdb/conv.c index 0f13d03a..de5d12f2 100644 --- a/modules/pam_userdb/conv.c +++ b/modules/pam_userdb/conv.c @@ -5,8 +5,6 @@ /* $Id */ /* Copyright at the end of the file */ -#define _BSD_SOURCE - #include #include diff --git a/modules/pam_userdb/create.pl b/modules/pam_userdb/create.pl index 046b55f0..224204b7 100644 --- a/modules/pam_userdb/create.pl +++ b/modules/pam_userdb/create.pl @@ -7,7 +7,7 @@ use DB_File; my $database = $ARGV[0]; -die "Use: check,pl \n" unless ($database); +die "Use: create.pl \n" unless ($database); print "Using database: $database\n"; my %lusers = (); diff --git a/modules/pam_userdb/pam_userdb.c b/modules/pam_userdb/pam_userdb.c index 30f1e578..a0a5b8b5 100644 --- a/modules/pam_userdb/pam_userdb.c +++ b/modules/pam_userdb/pam_userdb.c @@ -1,5 +1,5 @@ /* pam_userdb module */ - + /* * $Id$ * Written by Cristian Gafton 1996/09/10 @@ -8,6 +8,7 @@ #include +#include #include #include #include @@ -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) { - - /* 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; } @@ -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, diff --git a/modules/pam_userdb/pam_userdb.h b/modules/pam_userdb/pam_userdb.h index 911a7622..a371fa9f 100644 --- a/modules/pam_userdb/pam_userdb.h +++ b/modules/pam_userdb/pam_userdb.h @@ -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 ) -- 2.40.0