aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimo Weingärtner <timo@tiwe.de>2013-05-28 19:16:37 +0200
committerTimo Weingärtner <timo@tiwe.de>2013-05-28 19:16:37 +0200
commitc7344fa5ca42b3203ce7fc2ff8cb93b42bf78123 (patch)
treec4790500e80a2d34c4040ba21aae878a21223ee8
parent9316590e28c0087f65b220c492188871637aa424 (diff)
parent201e799f7a2fcba3af2c9214f25545460ef9b08a (diff)
downloadlibpam-pwdfile-c7344fa5ca42b3203ce7fc2ff8cb93b42bf78123.tar.gz
Merge tag 'v0.100' into debian
release 0.100 Conflicts: contrib/README.txt
-rw-r--r--CVS/Entries10
-rw-r--r--CVS/Repository1
-rw-r--r--CVS/Root1
-rw-r--r--INSTALL46
-rw-r--r--Makefile120
-rw-r--r--README86
-rw-r--r--bigcrypt.c101
-rw-r--r--bigcrypt.h1
-rw-r--r--changelog1
-rw-r--r--contrib/CVS/Entries6
-rw-r--r--contrib/CVS/Repository1
-rw-r--r--contrib/CVS/Root1
-rw-r--r--contrib/Makefile.standalone47
-rw-r--r--contrib/Makefile.standalone-0.9526
-rw-r--r--contrib/README.txt15
-rw-r--r--contrib/pam-pwdfile.spec44
-rw-r--r--contrib/warwick_duncan-cyrus_without_system_accounts.txt49
-rw-r--r--md5.c47
-rw-r--r--md5.h10
-rw-r--r--md5_crypt.c2
-rw-r--r--pam_pwdfile.c392
21 files changed, 222 insertions, 785 deletions
diff --git a/CVS/Entries b/CVS/Entries
deleted file mode 100644
index 7ba7172..0000000
--- a/CVS/Entries
+++ /dev/null
@@ -1,10 +0,0 @@
-/INSTALL/1.4/Tue Apr 17 21:18:15 2001//
-/Makefile/1.5/Sun Jun 9 21:01:46 2002//
-/README/1.12/Sat Dec 20 19:21:19 2003//
-/bigcrypt.c/1.1/Sat May 11 14:42:35 2002//
-/md5.c/1.1/Sat May 11 14:42:35 2002//
-/md5.h/1.1/Sat May 11 14:42:35 2002//
-/md5_crypt.c/1.1/Sat May 11 14:42:35 2002//
-/pam_pwdfile.c/1.18/Sat Dec 20 19:21:19 2003//
-D/contrib////
-/changelog/1.20/Sat Dec 20 19:30:57 2003//
diff --git a/CVS/Repository b/CVS/Repository
deleted file mode 100644
index 33653bf..0000000
--- a/CVS/Repository
+++ /dev/null
@@ -1 +0,0 @@
-pam_pwdfile
diff --git a/CVS/Root b/CVS/Root
deleted file mode 100644
index ee548db..0000000
--- a/CVS/Root
+++ /dev/null
@@ -1 +0,0 @@
-/home/cpbotha/work/cvsroot
diff --git a/INSTALL b/INSTALL
index f25d154..80846dd 100644
--- a/INSTALL
+++ b/INSTALL
@@ -1,39 +1,7 @@
-INSTALL for pam_pwdfile PAM module - Charl P. Botha <cpbotha@ieee.org>
-$Id: INSTALL,v 1.4 2001/04/17 21:18:15 cpbotha Exp $
----------------------------------------------------------------------------
-
-This file is the quick and dirty on how to get pam_pwdfile compiled on your
-system. As per usual, I can not be held responsible for the results of the
-application of this information.
-
-1. Get the Linux PAM source code tarball. Currently, this is at:
-http://www.us.kernel.org/pub/linux/libs/pam/pre/library/Linux-PAM-0.75.tar.bz2
-
-2. Extract the tarball somewhere convenient:
-bunzip2 -c Linux-PAM-0.75.tar.bz2 | tar -xvf -
-
-3. Prepare pam_pwdfile
-cd Linux-PAM-0.75/modules
-tar -xzvf /where/you/put/it/pam_pwdfile-x.y.tar.gz
-cd ..
-(x.y represents the pam_pwdfile version, e.g. 0.7)
-
-4. Prepare Linux-PAM
-rm default.defs
-ln -s defs/whatever.defs default.defs (on my system whatever == debian)
-
-5. in Linux-PAM-0.75/ do:
- make all
- NOTE: if you only need pam_pwdfile and some of the other modules are
- causing you problems during compilation, go and delete them (i.e.
- delete the whole module dir, e.g. rm -rf modules/pam_pwdb) and then
- restart make all in the top level directory.
-
-6. When you're done, there should be a pam_pwdfile.so in modules/pam_pwdfile;
- copy this into your pam modules directory. (this is /lib/security/ on my
- debian 2.2. system)
-
-7. You should now be operational. See the README for more info.
-
-Remember that pam_pwdfile is packaged as a .deb and is part of the official
-Debian distribution.
+* install needed packages (if not installed already):
+ * make
+ * C compiler (e.g. gcc or clang)
+ * libc development headers (package libc6-dev on Debian, glibc-headers on Hat)
+ * PAM development headers (package libpam-dev on Debian, pam-devel on Hat)
+* make
+* make install
diff --git a/Makefile b/Makefile
index 717434d..6905e9a 100644
--- a/Makefile
+++ b/Makefile
@@ -1,112 +1,34 @@
-# $Id: Makefile,v 1.5 2002/06/09 21:01:46 cpbotha Exp $
-#
-# This Makefile controls a build process of $(TITLE) module for
-# Linux-PAM. You should not modify this Makefile (unless you know
-# what you are doing!).
-#
+PAM_LIB_DIR ?= /lib/security
+INSTALL ?= install
+CFLAGS ?= -O2 -g -Wall -Wformat-security
-include ../../Make.Rules
+CPPFLAGS += -DUSE_CRYPT_R
+CFLAGS += -fPIC -fvisibility=hidden
+LDFLAGS += -Wl,-x -shared
-ifeq ($(HAVE_LIBCRYPT),yes)
- EXTRALS += -lcrypt
-endif
-
-TITLE=pam_pwdfile
-CFLAGS += -D_BSD_SOURCE
-
-md5_good.o: md5.c
- $(CC) $(CFLAGS) $(CPPFLAGS) -DHIGHFIRST -D'MD5Name(x)=Good##x' \
- $(TARGET_ARCH) -c $< -o $@
-
-md5_broken.o: md5.c
- $(CC) $(CFLAGS) $(CPPFLAGS) -D'MD5Name(x)=Broken##x' \
- $(TARGET_ARCH) -c $< -o $@
-
-md5_crypt_good.o: md5_crypt.c
- $(CC) $(CFLAGS) $(CPPFLAGS) -D'MD5Name(x)=Good##x' \
- $(TARGET_ARCH) -c $< -o $@
-
-md5_crypt_broken.o: md5_crypt.c
- $(CC) $(CFLAGS) $(CPPFLAGS) -D'MD5Name(x)=Broken##x' \
- $(TARGET_ARCH) -c $< -o $@
-
-##### The following mostly from Simple.Rules
-##### * modifications to first 5 definitions
-
-LIBFILES = $(TITLE) bigcrypt
-LIBSRC = $(addsuffix .c,$(LIBFILES)) md5.c md5_crypt.c
-LIBOBJ = $(addsuffix .o,$(LIBFILES))
-LIBOBJD = $(addprefix dynamic/,$(LIBOBJ)) md5_good.o md5_broken.o md5_crypt_good.o md5_crypt_broken.o
-LIBOBJS = $(addprefix static/,$(LIBOBJ)) md5_good.o md5_broken.o md5_crypt_good.o md5_crypt_broken.o
-
-ifdef DYNAMIC
+TITLE = pam_pwdfile
LIBSHARED = $(TITLE).so
-endif
+LDLIBS = -lcrypt -lpam
+LIBOBJ = $(TITLE).o md5_broken.o md5_crypt_broken.o bigcrypt.o
+CPPFLAGS_MD5_BROKEN = -DHIGHFIRST -D'MD5Name(x)=Broken\#\#x'
-ifdef STATIC
-LIBSTATIC = lib$(TITLE).o
-endif
-####################### don't edit below #######################
+all: $(LIBSHARED)
-all: dirs $(LIBSHARED) $(LIBSTATIC) register
+$(LIBSHARED): $(LIBOBJ)
+ $(CC) $(LDFLAGS) $(LIBOBJ) $(LDLIBS) -o $@
-dynamic/%.o : %.c
- $(CC) $(CFLAGS) $(DYNAMIC) $(TARGET_ARCH) -c $< -o $@
-static/%.o : %.c
- $(CC) $(CFLAGS) $(STATIC) $(TARGET_ARCH) -c $< -o $@
-
-dirs:
-ifdef DYNAMIC
- $(MKDIR) ./dynamic
-endif
-ifdef STATIC
- $(MKDIR) ./static
-endif
-
-register:
-ifdef STATIC
- ( cd .. ; ./register_static $(TITLE) $(TITLE)/$(LIBSTATIC) )
-endif
-
-ifdef DYNAMIC
-$(LIBOBJD): $(LIBSRC)
-endif
-
-ifdef DYNAMIC
-$(LIBSHARED): $(LIBOBJD)
- $(LD_D) -o $@ $(LIBOBJD) $(EXTRALS) $(NEED_LINK_LIB_C)
-endif
-
-ifdef STATIC
-$(LIBOBJS): $(LIBSRC)
-endif
+md5_broken.o: md5.c
+ $(CC) -c $(CPPFLAGS) $(CPPFLAGS_MD5_BROKEN) $(CFLAGS) $< -o $@
-ifdef STATIC
-$(LIBSTATIC): $(LIBOBJS)
- $(LD) -r -o $@ $(LIBOBJS) $(EXTRALS)
-endif
+md5_crypt_broken.o: md5_crypt.c
+ $(CC) -c $(CPPFLAGS) $(CPPFLAGS_MD5_BROKEN) $(CFLAGS) $< -o $@
-install: all
- $(MKDIR) $(FAKEROOT)$(SECUREDIR)
-ifdef DYNAMIC
- $(INSTALL) -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR)
-endif
- $(MODULE_SIMPLE_INSTALL)
-remove:
- rm -f $(FAKEROOT)$(SECUREDIR)/$(TITLE).so
- $(MODULE_SIMPLE_REMOVE)
+install: $(LIBSHARED)
+ $(INSTALL) -m 0755 -d $(DESTDIR)$(PAM_LIB_DIR)
+ $(INSTALL) -m 0755 $(LIBSHARED) $(DESTDIR)$(PAM_LIB_DIR)
clean:
- rm -f $(LIBOBJD) $(LIBOBJS) core *~
- $(MODULE_SIMPLE_CLEAN)
- rm -f *.a *.o *.so *.bak
- rm -rf dynamic static
- $(MODULE_SIMPLE_EXTRACLEAN)
-
-.c.o:
- $(CC) $(CFLAGS) -c $<
-
-
+ $(RM) *.o *.so
diff --git a/README b/README
index 3720bb8..568cf5a 100644
--- a/README
+++ b/README
@@ -1,48 +1,38 @@
-README for pam_pwdfile PAM module - Charl P. Botha <cpbotha@ieee.org>
-$Id: README,v 1.12 2003/12/20 19:21:19 cpbotha Exp $
----------------------------------------------------------------------------
-
-This is version 0.99 of pam_pwdfile.
-
-This pam module can be used for the authentication service only, in cases
-where one wants to use a different set of passwords than those in the main
-system password database. E.g. in our case we have an imap server running,
-and prefer to keep the imap passwords different from the system passwords
-for security reasons.
-
-The /etc/pam.d/imap looks like this (e.g.)
-#%PAM-1.0
-auth required /lib/security/pam_pwdfile.so pwdfile /etc/imap.passwd
-account required /lib/security/pam_pwdb.so
-
-At the moment the only parameters that pam_pwdfile.so parses for is
-"pwdfile", followed by the name of the ASCII password database, as in the
-above example. Also, thanks to Jacob Schroeder <jacob@quantec.de>,
-pam_pwdfile now supports password file locking. Adding a "flock" parameter
-activates this feature: pam_pwdfile uses and honours flock() file locking on
-the specified password file. Specifying "noflock" or no flock-type
-parameter at all deactivates this feature.
-
-Example:
-auth required /lib/security/pam_pwdfile.so pwdfile /etc/blah.passwd flock
-
-Like other PAM modules, pam_pwdfile causes a 2 second delay when an
-incorrect password is supplied. This is too discourage brute force testing;
-however, this behaviour can be disabled with a "nodelay" parameter. Thanks
-to Ethan Benson for this patch.
-
-The ASCII password file is simply a list of lines, each looking like this:
-username:crypted_passwd[13] in the case of vanilla crypted passwords and
-username:crypted_passwd[34] in the case of MD5 crypted passwords. The
-latter is thanks to Warwick Duncan <warwick@chemeng.uct.ac.za>. pam_pwdfile
-also handles bigcrypt passwords.
-
-Warwick has also written a utility for managing the password files that
-pam_pwdfile uses. Please see: http://eclipse.che.uct.ac.za/chpwdfile/
-
-Note that we still expect users to have accounts in the usual place, as we
-make use of the pam_pwdb.so module for the account service. This module is
-just so that one can have multiple sets of passwords for different services,
-e.g. with our /etc/imap.passwd. It is however possible with certain
-applications patched for pam (Cyrus IMAP server e.g.) that one does not need
-the users to exist in the system database.
+This pam module provides the authentication service using an own set of user/password pairs.
+
+CONFIGURATION
+=============
+
+simple PAM config
+-----------------
+
+Just add/change the config file for service to contain the line:
+
+auth required pam_pwdfile.so pwdfile=/path/to/passwd_file
+
+If your service does more with PAM than auth there will be a fallback to the service "other".
+If that is not what you want, you can use pam_permit.so or pam_deny.so for that:
+
+account required pam_permit.so
+session required pam_permit.so
+password required pam_deny.so
+
+
+options
+-------
+
+* pwdfile=<file>
+* debug: produce a bit of debug output
+* nodelay: don't tell the PAM stack to cause a delay on auth failure
+* flock: use a shared (read) advisory lock on pwdfile, you should better move new versions into place instead
+* legacy_crypt: turns on bigcrypt and "broken md5_crypt", you will only need that if you use password hashes from another system that uses those algorithms
+
+
+PASSWORD FILE
+=============
+
+The password file basically looks like passwd(5): one line for each user with two or more colon-separated fields.
+First field contains the username, the second the crypt()ed password.
+Other field are optional.
+
+crypt()ed passwords in various formats can be generated with mkpasswd from the whois package.
diff --git a/bigcrypt.c b/bigcrypt.c
index b1568d6..18024dc 100644
--- a/bigcrypt.c
+++ b/bigcrypt.c
@@ -24,11 +24,11 @@
* Andy Phillips <atp@mssl.ucl.ac.uk>
*/
+#define _XOPEN_SOURCE 700
+#include <unistd.h>
#include <string.h>
-#include <security/_pam_macros.h>
-char *crypt(const char *key, const char *salt);
-char *bigcrypt(const char *key, const char *salt);
+#include "bigcrypt.h"
/*
* Max cleartext password length in segments of 8 characters this
@@ -36,84 +36,39 @@ char *bigcrypt(const char *key, const char *salt);
* password).
*/
-#define MAX_PASS_LEN 16
+#define MAX_SEGMENTS 16
#define SEGMENT_SIZE 8
#define SALT_SIZE 2
-#define KEYBUF_SIZE ((MAX_PASS_LEN*SEGMENT_SIZE)+SALT_SIZE)
#define ESEGMENT_SIZE 11
-#define CBUF_SIZE ((MAX_PASS_LEN*ESEGMENT_SIZE)+SALT_SIZE+1)
-char *bigcrypt(const char *key, const char *salt)
-{
- static char dec_c2_cryptbuf[CBUF_SIZE]; /* static storage area */
+char *bigcrypt(char const * key, char const * salt) {
+ static char outbuf[MAX_SEGMENTS * ESEGMENT_SIZE + SALT_SIZE + 1]; /* static storage area */
- unsigned long int keylen, n_seg, j;
- char *cipher_ptr, *plaintext_ptr, *tmp_ptr, *salt_ptr;
- char keybuf[KEYBUF_SIZE + 1];
+ unsigned char n_seg, seg;
+ char * outptr;
- D(("called with key='%s', salt='%s'.", key, salt));
+ /* ensure NUL-termination */
+ memset(outbuf, 0, sizeof(outbuf));
- /* reset arrays */
- memset(keybuf, 0, KEYBUF_SIZE + 1);
- memset(dec_c2_cryptbuf, 0, CBUF_SIZE);
-
- /* fill KEYBUF_SIZE with key */
- strncpy(keybuf, key, KEYBUF_SIZE);
-
- /* deal with case that we are doing a password check for a
- conventially encrypted password: the salt will be
- SALT_SIZE+ESEGMENT_SIZE long. */
- if (strlen(salt) == (SALT_SIZE + ESEGMENT_SIZE))
- keybuf[SEGMENT_SIZE] = '\0'; /* terminate password early(?) */
-
- keylen = strlen(keybuf);
-
- if (!keylen) {
+ if (strlen(salt) == (SALT_SIZE + ESEGMENT_SIZE)) /* conventional crypt */
n_seg = 1;
- } else {
- /* work out how many segments */
- n_seg = 1 + ((keylen - 1) / SEGMENT_SIZE);
- }
-
- if (n_seg > MAX_PASS_LEN)
- n_seg = MAX_PASS_LEN; /* truncate at max length */
-
- /* set up some pointers */
- cipher_ptr = dec_c2_cryptbuf;
- plaintext_ptr = keybuf;
-
- /* do the first block with supplied salt */
- tmp_ptr = crypt(plaintext_ptr, salt); /* libc crypt() */
-
- /* and place in the static area */
- strncpy(cipher_ptr, tmp_ptr, 13);
- cipher_ptr += ESEGMENT_SIZE + SALT_SIZE;
- plaintext_ptr += SEGMENT_SIZE; /* first block of SEGMENT_SIZE */
-
- /* change the salt (1st 2 chars of previous block) - this was found
- by dowsing */
-
- salt_ptr = cipher_ptr - ESEGMENT_SIZE;
-
- /* so far this is identical to "return crypt(key, salt);", if
- there is more than one block encrypt them... */
-
- if (n_seg > 1) {
- for (j = 2; j <= n_seg; j++) {
-
- tmp_ptr = crypt(plaintext_ptr, salt_ptr);
-
- /* skip the salt for seg!=0 */
- strncpy(cipher_ptr, (tmp_ptr + SALT_SIZE), ESEGMENT_SIZE);
-
- cipher_ptr += ESEGMENT_SIZE;
- plaintext_ptr += SEGMENT_SIZE;
- salt_ptr = cipher_ptr - ESEGMENT_SIZE;
- }
+ else if (key[0] == '\0')
+ n_seg = 1;
+ else
+ n_seg = (strnlen(key, MAX_SEGMENTS * SEGMENT_SIZE) + SEGMENT_SIZE - 1) / SEGMENT_SIZE;
+
+ /* first block is special and just traditional crypt() */
+ outptr = outbuf;
+ strncpy(outptr, crypt(key, salt), SALT_SIZE + ESEGMENT_SIZE);
+
+ for (seg = 1, outptr += SALT_SIZE; seg < n_seg; ++seg) {
+ /* subsequent blocks use the previous output block for salt input */
+ salt = outptr;
+ key += SEGMENT_SIZE;
+ outptr += ESEGMENT_SIZE;
+ /* and omit the salt on output */
+ strncpy(outptr, crypt(key, salt) + SALT_SIZE, ESEGMENT_SIZE);
}
- D(("key=|%s|, salt=|%s|\nbuf=|%s|\n", key, salt, dec_c2_cryptbuf));
-
- /* this is the <NUL> terminated encrypted password */
- return dec_c2_cryptbuf;
+ return outbuf;
}
diff --git a/bigcrypt.h b/bigcrypt.h
new file mode 100644
index 0000000..a66a96e
--- /dev/null
+++ b/bigcrypt.h
@@ -0,0 +1 @@
+extern char *bigcrypt(const char *key, const char *salt);
diff --git a/changelog b/changelog
index ea86b63..9936e81 100644
--- a/changelog
+++ b/changelog
@@ -1,5 +1,4 @@
changelog for pam_pwdfile PAM module - Charl P. Botha <cpbotha@ieee.org>
-$Id: changelog,v 1.20 2003/12/20 19:30:57 cpbotha Exp $
---------------------------------------------------------------------------
0.99 : Sat Dec 20 20:30:37 CET 2003
diff --git a/contrib/CVS/Entries b/contrib/CVS/Entries
deleted file mode 100644
index ca36d1a..0000000
--- a/contrib/CVS/Entries
+++ /dev/null
@@ -1,6 +0,0 @@
-/Makefile.standalone/1.2/Mon Jul 7 15:09:41 2003//
-/Makefile.standalone-0.95/1.1/Mon Jul 7 15:09:41 2003//
-/README.txt/1.3/Mon Jul 7 15:09:41 2003//
-/pam-pwdfile.spec/1.1/Tue May 14 15:58:53 2002//
-/warwick_duncan-cyrus_without_system_accounts.txt/1.1/Fri Jan 17 14:10:48 2003//
-D
diff --git a/contrib/CVS/Repository b/contrib/CVS/Repository
deleted file mode 100644
index 00ebee3..0000000
--- a/contrib/CVS/Repository
+++ /dev/null
@@ -1 +0,0 @@
-pam_pwdfile/contrib
diff --git a/contrib/CVS/Root b/contrib/CVS/Root
deleted file mode 100644
index ee548db..0000000
--- a/contrib/CVS/Root
+++ /dev/null
@@ -1 +0,0 @@
-/home/cpbotha/work/cvsroot
diff --git a/contrib/Makefile.standalone b/contrib/Makefile.standalone
deleted file mode 100644
index 857eaff..0000000
--- a/contrib/Makefile.standalone
+++ /dev/null
@@ -1,47 +0,0 @@
-PAM_LIB_DIR = /lib/security
-CC = gcc
-LD = ld
-INSTALL = /usr/bin/install
-CFLAGS = -fPIC -O2 -c -g -Wall -Wformat-security
-LDFLAGS = -x --shared
-PAMLIB = -lpam
-CRYPTLIB = -lcrypt
-CPPFLAGS =
-
-all: pam_pwdfile.so
-
-pam_pwdfile.so: pam_pwdfile.o bigcrypt.o md5_good.o md5_crypt_good.o md5_broken.o md5_crypt_broken.o
- $(LD) $(LDFLAGS) -o pam_pwdfile.so pam_pwdfile.o md5_good.o md5_crypt_good.o md5_broken.o md5_crypt_broken.o bigcrypt.o $(PAMLIB) $(CRYPTLIB)
-
-pam_pwdfile.o: pam_pwdfile.c
- $(CC) $(CFLAGS) pam_pwdfile.c
-
-bigcrypt.o: bigcrypt.c
- $(CC) $(CFLAGS) bigcrypt.c
-
-
-md5_good.o: md5.c
- $(CC) $(CFLAGS) $(CPPFLAGS) -DHIGHFIRST -D'MD5Name(x)=Good##x' -c $< -o $@
-
-md5_broken.o: md5.c
- $(CC) $(CFLAGS) $(CPPFLAGS) -D'MD5Name(x)=Broken##x' \
- -c $< -o $@
-
-md5_crypt_good.o: md5_crypt.c
- $(CC) $(CFLAGS) $(CPPFLAGS) -D'MD5Name(x)=Good##x' \
- -c $< -o $@
-
-md5_crypt_broken.o: md5_crypt.c
- $(CC) $(CFLAGS) $(CPPFLAGS) -D'MD5Name(x)=Broken##x' \
- -c $< -o $@
-
-
-install: pam_pwdfile.so
- $(INSTALL) -m 0755 -d $(PAM_LIB_DIR)
- $(INSTALL) -m 0755 pam_pwdfile.so $(PAM_LIB_DIR)
-
-clean:
- rm -f pam_pwdfile.o pam_pwdfile.so
-
-spotless:
- rm -f pam_pwdfile.so pam_pwdfile.o *~ core
diff --git a/contrib/Makefile.standalone-0.95 b/contrib/Makefile.standalone-0.95
deleted file mode 100644
index 136f04a..0000000
--- a/contrib/Makefile.standalone-0.95
+++ /dev/null
@@ -1,26 +0,0 @@
-PAM_LIB_DIR = /lib/security
-CC = gcc
-LD = ld
-INSTALL = /usr/bin/install
-CFLAGS = -fPIC -O2 -c -g -Wall -Wformat-security
-LDFLAGS = -x --shared
-PAMLIB = -lpam
-CRYPTLIB = -lcrypt
-
-all: pam_pwdfile.so
-
-pam_pwdfile.so: pam_pwdfile.o
- $(LD) $(LDFLAGS) -o pam_pwdfile.so pam_pwdfile.o $(PAMLIB) $(CRYPTLIB)
-
-pam_pwdfile.o: pam_pwdfile.c
- $(CC) $(CFLAGS) pam_pwdfile.c
-
-install: pam_pwdfile.so
- $(INSTALL) -m 0755 -d $(PAM_LIB_DIR)
- $(INSTALL) -m 0755 pam_pwdfile.so $(PAM_LIB_DIR)
-
-clean:
- rm -f pam_pwdfile.o pam_pwdfile.so
-
-spotless:
- rm -f pam_pwdfile.so pam_pwdfile.o *~ core
diff --git a/contrib/README.txt b/contrib/README.txt
deleted file mode 100644
index 71efac7..0000000
--- a/contrib/README.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-$Id: README.txt,v 1.3 2003/07/07 15:09:41 cpbotha Exp $
-
-* Makefile.standalone-0.95 and pam-pwdfile.spec were contributed by Jason F.
- McBrayer <jason@xeran.com>. You can use these for building RPMs of
- pam_pwdfile; you should also be able to use the Makefile to build
- pam_pwdfile on other platforms _without_ the Linux-PAM hierarchy.
-
-* warwick_duncan-cyrus_without_system_accounts.txt is a short explanation by
- Warwick Duncan on how to get Cyrus IMAPD + pam_pwdfile to work WITHOUT
- having to create system accounts for IMAPD users.
-
-* Makefile.standalone was contributed by Gerald Richter and should be more
- up to date than Makefile.standalone-0.95. The primary difference is that
- Gerald's Makefile also takes into account the new md5 code.
-
diff --git a/contrib/pam-pwdfile.spec b/contrib/pam-pwdfile.spec
deleted file mode 100644
index cbcd88a..0000000
--- a/contrib/pam-pwdfile.spec
+++ /dev/null
@@ -1,44 +0,0 @@
-%define nam pam-pwdfile
-%define ver 0.95
-%define prefix /usr
-%define docdir %{prefix}/doc/%{nam}-%{ver}
-
-%define installer /usr/bin/install
-
-Summary: A PAM module that allows users to authenticate on htpasswd-type files separate from /etc/passwd.
-Name: pam-pwdfile
-Version: %{ver}
-Release: 1
-Copyright: LGPL
-Group: System Environment/Base
-Source0: %{nam}-%{ver}.tar.gz
-Source1: pam-pwdfile-Makefile.standalone
-URL: http://cpbotha.net/pam_pwdfile.html
-Distribution: Xeran Internal Packages
-Vendor: Xeran Technologies
-Packager: Jason F. McBrayer <jason@xeran.com>
-BuildRoot: /var/tmp/%{nam}-%{ver}-root
-BuildPrereq: pam
-Requires: pam
-
-%description
-This pam module can be used for the authentication service only, in cases
-where one wants to use a different set of passwords than those in the main
-system password database. E.g. in our case we have an imap server running,
-and prefer to keep the imap passwords different from the system passwords
-for security reasons.
-
-%prep
-%setup
-cp $RPM_SOURCE_DIR/pam-pwdfile-Makefile.standalone $RPM_BUILD_DIR/%{nam}-%{ver}/Makefile.standalone
-
-%build
-make -f Makefile.standalone
-
-%install
-make -f Makefile.standalone PAM_LIB_DIR="$RPM_BUILD_ROOT/lib/security" install
-
-%files
-%attr(0755, root, root) /lib/security/pam_pwdfile.so
-%attr(-, root, root) %doc README
-%attr(-, root, root) %doc changelog
diff --git a/contrib/warwick_duncan-cyrus_without_system_accounts.txt b/contrib/warwick_duncan-cyrus_without_system_accounts.txt
deleted file mode 100644
index 0144af1..0000000
--- a/contrib/warwick_duncan-cyrus_without_system_accounts.txt
+++ /dev/null
@@ -1,49 +0,0 @@
-On Tue, Jan 14, 2003 at 01:06:02AM +0100, Charl P. Botha wrote:
-[...]
-> ----- Forwarded message from Darren Gibbons -----
-[...]
-> It is however possible with certain applications patched for pam
-> (Cyrus IMAP server e.g.) that one does not need the users to
-> exist in the system database.
-[...]
-
-I've got it working with cyrus 2.0 and 2.1, so I'll give some pointers
-on both. When I say `cyrus x' I mean cyrus imapd version x and
-whichever version of sasl you need with it.
-
-Cyrus 2.0
----------
-
-- sasl must be configured with `--with-pam --enable-plain'; it doesn't
- hurt to add `--disable cram --disable-digest'
-- imapd must be configured with `--with-auth=unix' (sounds like you got
- that right)
-- in imapd.conf you need the line
- sasl_pwcheck_method: PAM
-- in /etc/pam.d/imap (on FreeBSD I believe you use /etc/pam.conf, but
- the idea is similar) you need
- auth required pam_pwdfile.so pwdfile /path/to/passwordfile
- account required pam_permit.so
-- make sure your password file is readable by user cyrus
-
-The idea of all this is to use the SASL PLAIN mechanism to get the
-password in plaintext and then get SASL to leave the authentication to
-PAM, which will use pam_pwdfile.
-
-Cyrus 2.1
----------
-
-- same as above, but different ;) in the details
-- sasl must be configured with `--with-pam --with-saslauthd
- --enable-plain' and I disable the rest (checkapop, digest, otp, krb4,
- etc.)
-- imapd should be configured with `--with-auth=unix'
-- in imapd.conf you need the line
- sasl_pwcheck_method: saslauthd
-- start up saslauthd with `saslauthd -a pam'
-- you need the /etc/pam.d/imap as above, as well as (an identical)
- /etc/pam.d/sieve if you use timsieved
-
-I think that about covers it. One tricky bit with SASL is to get the
-right mechanisms advertised; I do this by only compiling in support for
-PLAIN and LOGIN. If the rest don't exist they can't cause problems.
diff --git a/md5.c b/md5.c
index 26bafdb..542ff80 100644
--- a/md5.c
+++ b/md5.c
@@ -1,6 +1,4 @@
/*
- * $Id: md5.c,v 1.1 2002/05/11 14:42:35 cpbotha Exp $
- *
* This code implements the MD5 message-digest algorithm.
* The algorithm is due to Ron Rivest. This code was
* written by Colin Plumb in 1993, no copyright is claimed.
@@ -19,29 +17,17 @@
*/
#include <string.h>
+#include <byteswap.h>
#include "md5.h"
#ifndef HIGHFIRST
#define byteReverse(buf, len) /* Nothing */
#else
-static void byteReverse(unsigned char *buf, unsigned longs);
-
-#ifndef ASM_MD5
-/*
- * Note: this code is harmless on little-endian machines.
- */
-static void byteReverse(unsigned char *buf, unsigned longs)
-{
- uint32 t;
- do {
- t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
- ((unsigned) buf[1] << 8 | buf[0]);
- *(uint32 *) buf = t;
- buf += 4;
- } while (--longs);
+static void byteReverse(unsigned char *buf, unsigned longs) {
+ for (; longs; --longs, buf +=4)
+ *((uint32_t *) buf) = bswap_32(*((uint32_t *) buf));
}
#endif
-#endif
/*
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
@@ -64,12 +50,12 @@ void MD5Name(MD5Init)(struct MD5Context *ctx)
*/
void MD5Name(MD5Update)(struct MD5Context *ctx, unsigned const char *buf, unsigned len)
{
- uint32 t;
+ uint32_t t;
/* Update bitcount */
t = ctx->bits[0];
- if ((ctx->bits[0] = t + ((uint32) len << 3)) < t)
+ if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t)
ctx->bits[1]++; /* Carry from low to high */
ctx->bits[1] += len >> 29;
@@ -87,7 +73,7 @@ void MD5Name(MD5Update)(struct MD5Context *ctx, unsigned const char *buf, unsign
}
memcpy(p, buf, t);
byteReverse(ctx->in, 16);
- MD5Name(MD5Transform)(ctx->buf, (uint32 *) ctx->in);
+ MD5Name(MD5Transform)(ctx->buf, (uint32_t *) ctx->in);
buf += t;
len -= t;
}
@@ -96,7 +82,7 @@ void MD5Name(MD5Update)(struct MD5Context *ctx, unsigned const char *buf, unsign
while (len >= 64) {
memcpy(ctx->in, buf, 64);
byteReverse(ctx->in, 16);
- MD5Name(MD5Transform)(ctx->buf, (uint32 *) ctx->in);
+ MD5Name(MD5Transform)(ctx->buf, (uint32_t *) ctx->in);
buf += 64;
len -= 64;
}
@@ -131,7 +117,7 @@ void MD5Name(MD5Final)(unsigned char digest[16], struct MD5Context *ctx)
/* Two lots of padding: Pad the first block to 64 bytes */
memset(p, 0, count);
byteReverse(ctx->in, 16);
- MD5Name(MD5Transform)(ctx->buf, (uint32 *) ctx->in);
+ MD5Name(MD5Transform)(ctx->buf, (uint32_t *) ctx->in);
/* Now fill the next block with 56 bytes */
memset(ctx->in, 0, 56);
@@ -142,17 +128,14 @@ void MD5Name(MD5Final)(unsigned char digest[16], struct MD5Context *ctx)
byteReverse(ctx->in, 14);
/* Append length in bits and transform */
- ((uint32 *) ctx->in)[14] = ctx->bits[0];
- ((uint32 *) ctx->in)[15] = ctx->bits[1];
+ memcpy(ctx->in + 56, ctx->bits, 8);
- MD5Name(MD5Transform)(ctx->buf, (uint32 *) ctx->in);
+ MD5Name(MD5Transform)(ctx->buf, (uint32_t *) ctx->in);
byteReverse((unsigned char *) ctx->buf, 4);
memcpy(digest, ctx->buf, 16);
- memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
+ memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */
}
-#ifndef ASM_MD5
-
/* The four core functions - F1 is optimized somewhat */
/* #define F1(x, y, z) (x & y | ~x & z) */
@@ -170,9 +153,9 @@ void MD5Name(MD5Final)(unsigned char digest[16], struct MD5Context *ctx)
* reflect the addition of 16 longwords of new data. MD5Update blocks
* the data and converts bytes into longwords for this routine.
*/
-void MD5Name(MD5Transform)(uint32 buf[4], uint32 const in[16])
+void MD5Name(MD5Transform)(uint32_t buf[4], uint32_t const in[16])
{
- register uint32 a, b, c, d;
+ register uint32_t a, b, c, d;
a = buf[0];
b = buf[1];
@@ -252,5 +235,3 @@ void MD5Name(MD5Transform)(uint32 buf[4], uint32 const in[16])
buf[2] += c;
buf[3] += d;
}
-
-#endif
diff --git a/md5.h b/md5.h
index 103f168..b48edea 100644
--- a/md5.h
+++ b/md5.h
@@ -2,22 +2,22 @@
#ifndef MD5_H
#define MD5_H
-typedef unsigned int uint32;
+#include <stdint.h>
struct MD5Context {
- uint32 buf[4];
- uint32 bits[2];
+ uint32_t buf[4];
+ uint32_t bits[2];
unsigned char in[64];
};
void GoodMD5Init(struct MD5Context *);
void GoodMD5Update(struct MD5Context *, unsigned const char *, unsigned);
void GoodMD5Final(unsigned char digest[16], struct MD5Context *);
-void GoodMD5Transform(uint32 buf[4], uint32 const in[16]);
+void GoodMD5Transform(uint32_t buf[4], uint32_t const in[16]);
void BrokenMD5Init(struct MD5Context *);
void BrokenMD5Update(struct MD5Context *, unsigned const char *, unsigned);
void BrokenMD5Final(unsigned char digest[16], struct MD5Context *);
-void BrokenMD5Transform(uint32 buf[4], uint32 const in[16]);
+void BrokenMD5Transform(uint32_t buf[4], uint32_t const in[16]);
char *Goodcrypt_md5(const char *pw, const char *salt);
char *Brokencrypt_md5(const char *pw, const char *salt);
diff --git a/md5_crypt.c b/md5_crypt.c
index 389778a..639b1d3 100644
--- a/md5_crypt.c
+++ b/md5_crypt.c
@@ -1,6 +1,4 @@
/*
- * $Id: md5_crypt.c,v 1.1 2002/05/11 14:42:35 cpbotha Exp $
- *
* ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
diff --git a/pam_pwdfile.c b/pam_pwdfile.c
index ec2bd96..9b96fe3 100644
--- a/pam_pwdfile.c
+++ b/pam_pwdfile.c
@@ -1,13 +1,9 @@
/* pam_pwdfile.c copyright 1999-2003 by Charl P. Botha <cpbotha@ieee.org>
*
- * $Id: pam_pwdfile.c,v 1.18 2003/12/20 19:21:19 cpbotha Exp $
- *
* pam authentication module that can be pointed at any username/crypted
* text file so that pam using application can use an alternate set of
* passwords than specified in system password database
*
- * version 0.99
- *
* Copyright (c) Charl P. Botha, 1999-2003. All rights reserved
*
* Redistribution and use in source and binary forms, with or without
@@ -42,9 +38,20 @@
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#ifdef USE_CRYPT_R
+#define _GNU_SOURCE
+#include <crypt.h>
+#else
+#ifndef _XOPEN_SOURCE
+#define _XOPEN_SOURCE 700
+#endif
+#ifndef _BSD_SOURCE
+#define _BSD_SOURCE
+#endif
+#endif
+
#include <features.h>
#include <syslog.h>
-#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -54,44 +61,16 @@
#include <sys/wait.h>
#include <sys/file.h>
#include <unistd.h>
+#include <syslog.h>
#include <security/pam_appl.h>
#define PAM_SM_AUTH
#include <security/pam_modules.h>
+#include <security/pam_ext.h>
#include "md5.h"
-extern char *crypt(const char *key, const char *salt);
-extern char *bigcrypt(const char *key, const char *salt);
-
-#define PWDF_PARAM "pwdfile"
-#define FLOCK_PARAM "flock"
-#define NODELAY_PARAM "nodelay"
-#define PWDFN_LEN 256
-#define CRYPTED_DESPWD_LEN 13
-#define CRYPTED_MD5PWD_LEN 34
-#define CRYPTED_BCPWD_LEN 178
-
-#ifdef DEBUG
-# define D(a) a;
-#else
-# define D(a) {}
-#endif
-
-/* prototypes */
-int converse(pam_handle_t *, int, struct pam_message **, struct pam_response **);
-int _set_auth_tok(pam_handle_t *, int, int, const char **);
-
-/* logging function ripped from pam_listfile.c */
-static void _pam_log(int err, const char *format, ...) {
- va_list args;
-
- va_start(args, format);
- openlog("pam_pwdfile", LOG_CONS|LOG_PID, LOG_AUTH);
- vsyslog(err, format, args);
- va_end(args);
- closelog();
-}
+#include "bigcrypt.h"
static int lock_fd(int fd) {
int delay;
@@ -110,304 +89,148 @@ static int lock_fd(int fd) {
return -1;
}
-/* this function ripped from pam_unix/support.c */
-int converse( pam_handle_t *pamh,
- int nargs,
- struct pam_message **message,
- struct pam_response **response ) {
- int retval;
- struct pam_conv *conv;
-
- retval = pam_get_item( pamh, PAM_CONV, (const void **) &conv ) ;
- if ( retval == PAM_SUCCESS ) {
- retval = conv->conv( nargs,
- ( const struct pam_message ** ) message,
- response,
- conv->appdata_ptr );
- }
- return retval;
-}
-
-/* this function ripped from pam_unix/support.c */
-int _set_auth_tok( pam_handle_t *pamh,
- int flags, int argc,
- const char **argv ) {
- int retval;
- char *p;
-
- struct pam_message msg[1],*pmsg[1];
- struct pam_response *resp;
-
- /* set up conversation call */
-
- pmsg[0] = &msg[0];
- msg[0].msg_style = PAM_PROMPT_ECHO_OFF;
- msg[0].msg = "Password: ";
- resp = NULL;
-
- if ( ( retval = converse( pamh, 1 , pmsg, &resp ) ) != PAM_SUCCESS )
- return retval;
-
- if ( resp )
- {
- if ( ( flags & PAM_DISALLOW_NULL_AUTHTOK ) &&
- resp[0].resp == NULL )
- {
- free( resp );
- return PAM_AUTH_ERR;
- }
-
- p = resp[ 0 ].resp;
-
- /* This could be a memory leak. If resp[0].resp
- is malloc()ed, then it has to be free()ed!
- -- alex
- */
-
- resp[ 0 ].resp = NULL;
-
- }
- else
- return PAM_CONV_ERR;
-
- free( resp );
- pam_set_item( pamh, PAM_AUTHTOK, p );
- return PAM_SUCCESS;
-}
-
-
-/* puts the crypted password corresponding to user "name" in password,
- * from a file with lines consisting of: name:crypted_password
- * if unsucessful, returns 0
- */
-static int fgetpwnam(FILE *stream, const char *name, char *password) {
- char tempLine[256], *tpointer, *curname, *curpass, *fgr;
- int loopdone, pwdfound;
- int len;
-
- /* go to beginning of file */
- rewind(stream);
- /* some control variables */
- loopdone = pwdfound = 0;
- /* fgets should do this, but we make sure */
- tempLine[255] = '\0';
- /* iterate through lines in file, until end of file */
- do {
- /* get the current line */
- fgr = fgets(tempLine,255,stream);
- /* if it's valid, go on */
- if ( fgr != NULL) {
- /* first get the username out */
- tpointer = tempLine;
- curname = strsep(&tpointer,":");
- /* check to see if it's the right one */
- if (strcmp(curname,name)==0) {
- /* at least we know our loop is done */
- loopdone = 1;
- /* remove possible trailing newline */
- len = strlen(tpointer);
- if (tpointer[len - 1] == '\n')
- tpointer[len - 1] = '\0';
- /* get the password and put it in its place */
- curpass = strsep(&tpointer,":");
- if (curpass != NULL) {
- /* we use bigcrypt pwd len, as this is just a safe maximum */
- strncpy(password,curpass,CRYPTED_BCPWD_LEN+1);
- pwdfound = 1;
- } /* if (curpass... */
- } /* if (strcmp(curname... */
- } /* if (tempLine... */
- } while (fgr != NULL);
- return pwdfound;
-}
-
/* expected hook for auth service */
+__attribute__((visibility("default")))
PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags,
int argc, const char **argv) {
- int retval, pcnt, pwdfilename_found;
+ int i;
const char *name;
- char *password;
- char pwdfilename[PWDFN_LEN];
- char salt[12], stored_crypted_password[CRYPTED_BCPWD_LEN+1];
- char *crypted_password;
+ char const * password;
+ char const * pwdfilename = NULL;
+ char const * stored_crypted_password = NULL;
+ char const * crypted_password;
FILE *pwdfile;
int use_flock = 0;
int use_delay = 1;
- int temp_result = 0;
+ int legacy_crypt = 0;
+ int debug = 0;
+ char * linebuf = NULL;
+ size_t linebuflen;
+#ifdef USE_CRYPT_R
+ struct crypt_data crypt_buf;
+#endif
/* we require the pwdfile switch and argument to be present, else we don't work */
- /* pcnt is the parameter counter variable for iterating through argv */
- pcnt = pwdfilename_found = 0;
- do {
- /* see if the current parameter looks like "pwdfile" */
- if (strcmp(argv[pcnt],PWDF_PARAM)==0) {
- /* if argv is long enough, grab the subsequent parameter */
- if (pcnt+1 < argc) {
- /* make sure we can't overflow */
- strncpy(pwdfilename,argv[++pcnt],PWDFN_LEN);
- /* indicate that we've found it */
- pwdfilename_found = 1;
- }
- /* also check for "pwdfile=blah" */
- } else if (strncmp(argv[pcnt],PWDF_PARAM "=",sizeof(PWDF_PARAM "=")-1)==0) {
- /* make sure we can't overflow */
- strncpy(pwdfilename,argv[pcnt]+sizeof(PWDF_PARAM),PWDFN_LEN);
- /* indicate that we've found it */
- pwdfilename_found = 1;
- } else if (strcmp(argv[pcnt],FLOCK_PARAM)==0) {
- /* we have a "flock" parameter */
+ for (i = 0; i < argc; ++i) {
+ if (!strcmp(argv[i], "pwdfile") && i + 1 < argc)
+ pwdfilename = argv[++i];
+ else if (!strncmp(argv[i], "pwdfile=", strlen("pwdfile=")))
+ pwdfilename = argv[i] + strlen("pwdfile=");
+ else if (!strcmp(argv[i], "flock"))
use_flock = 1;
- } else if (strcmp(argv[pcnt],"no" FLOCK_PARAM)==0) {
- /* or a "noflock" parameter */
+ else if (!strcmp(argv[i], "noflock"))
use_flock = 0;
- } else if (strcmp(argv[pcnt],NODELAY_PARAM)==0) {
- /* no delay on authentication failure */
+ else if (!strcmp(argv[i], "nodelay"))
use_delay = 0;
- }
-
- } while (++pcnt < argc);
+ else if (!strcmp(argv[i], "debug"))
+ debug = 1;
+ else if (!strcmp(argv[i], "legacy_crypt"))
+ legacy_crypt = 1;
+ }
#ifdef HAVE_PAM_FAIL_DELAY
if (use_delay) {
- D(("setting delay"));
- (void) pam_fail_delay(pamh, 2000000); /* 2 sec delay for on failure */
+ if (debug) pam_syslog(pamh, LOG_DEBUG, "setting fail delay");
+ (void) pam_fail_delay(pamh, 2000000); /* 2 sec */
}
#endif
- /* for some or other reason, the password file wasn't specified */
- if (!pwdfilename_found) {
- _pam_log(LOG_ERR,"password file name not specified");
+ if (!pwdfilename) {
+ pam_syslog(pamh, LOG_ERR, "password file name not specified");
return PAM_AUTHINFO_UNAVAIL;
}
- /* DEBUG */
- D(_pam_log(LOG_ERR, "password filename extracted"));
-
- /* now try to open the password file */
- if ((pwdfile=fopen(pwdfilename,"r"))==NULL) {
- _pam_log(LOG_ERR,"couldn't open password file %s",pwdfilename);
- return PAM_AUTHINFO_UNAVAIL;
+ if (pam_get_user(pamh, &name, NULL) != PAM_SUCCESS) {
+ pam_syslog(pamh, LOG_ERR, "couldn't get username from PAM stack");
+ return PAM_AUTH_ERR;
}
+ if (debug) pam_syslog(pamh, LOG_DEBUG, "username is %s", name);
- /* set a lock on the password file */
- if (use_flock && lock_fd(fileno(pwdfile)) == -1) {
- _pam_log(LOG_ERR,"couldn't lock password file %s",pwdfilename);
+ if (!(pwdfile = fopen(pwdfilename, "r"))) {
+ pam_syslog(pamh, LOG_ALERT, "couldn't open password file %s", pwdfilename);
return PAM_AUTHINFO_UNAVAIL;
}
- /* get user name */
- if ((retval = pam_get_user(pamh,&name,"login: ")) != PAM_SUCCESS) {
- _pam_log(LOG_ERR, "username not found");
+ if (use_flock && lock_fd(fileno(pwdfile)) == -1) {
+ pam_syslog(pamh, LOG_ALERT, "couldn't lock password file %s", pwdfilename);
fclose(pwdfile);
- return retval;
+ return PAM_AUTHINFO_UNAVAIL;
}
-
- /* DEBUG */
- D(_pam_log(LOG_ERR,"username is %s", name));
-
- /* get password - code from pam_unix_auth.c */
- pam_get_item(pamh, PAM_AUTHTOK, (void *)&password);
- if (!password) {
- retval = _set_auth_tok(pamh, flags, argc, argv);
- if (retval!=PAM_SUCCESS) {
- fclose(pwdfile);
- return retval;
+ /* get the crypted password corresponding to this user out of pwdfile */
+ while (getline(&linebuf, &linebuflen, pwdfile) > 0) {
+ /* strsep changes its argument, make a copy */
+ char * nexttok = linebuf;
+
+ /* first field: username */
+ char * curtok = strsep(&nexttok, ":");
+
+ /* skip non-matching usernames */
+ if (strcmp(curtok, name))
+ continue;
+
+ /* second field: password (until next colon or newline) */
+ if ((curtok = strsep(&nexttok, ":\n"))) {
+ stored_crypted_password = curtok;
+ break;
}
}
- pam_get_item(pamh, PAM_AUTHTOK, (void *)&password);
+ fclose(pwdfile);
+ /* we keep linebuf (allocated by getline), stored_crypted_password is pointing into it */
+
+ if (!stored_crypted_password)
+ if (debug) pam_syslog(pamh, LOG_ERR, "user not found in password database");
- if ((retval = pam_get_item(pamh, PAM_AUTHTOK, (void *)&password)) != PAM_SUCCESS) {
- _pam_log(LOG_ERR, "auth token not found");
- fclose(pwdfile);
- return retval;
+ if (stored_crypted_password && !strlen(stored_crypted_password)) {
+ if (debug) pam_syslog(pamh, LOG_DEBUG, "user has empty password field");
+ free(linebuf);
+ return flags & PAM_DISALLOW_NULL_AUTHTOK ? PAM_AUTH_ERR : PAM_SUCCESS;
}
- /* DEBUG */
- D(_pam_log(LOG_ERR,"got password from user", password));
-
- /* now crypt password and compare to the user entry in the password file */
- /* first make sure password is long enough -- may I do this? */
- if (strlen(password)<2 || password==NULL) {
- _pam_log(LOG_ERR,"password too short or NULL");
- fclose(pwdfile);
+ if (pam_get_authtok(pamh, PAM_AUTHTOK, &password, NULL) != PAM_SUCCESS) {
+ pam_syslog(pamh, LOG_ERR, "couldn't get password from PAM stack");
+ free(linebuf);
return PAM_AUTH_ERR;
}
- /* get the crypted password corresponding to this user */
- if (!fgetpwnam(pwdfile, name, stored_crypted_password)) {
- _pam_log(LOG_ERR,"user not found in password database");
- fclose(pwdfile);
- return PAM_AUTHINFO_UNAVAIL;
+ if (!stored_crypted_password) {
+ free(linebuf);
+ return PAM_USER_UNKNOWN;
}
- /* DEBUG */
- D(_pam_log(LOG_ERR,"got crypted password == '%s'", stored_crypted_password));
-
+ if (debug) pam_syslog(pamh, LOG_DEBUG, "got crypted password == '%s'", stored_crypted_password);
- temp_result = 0;
+#ifdef USE_CRYPT_R
+ crypt_buf.initialized = 0;
+ if (!(crypted_password = crypt_r(password, stored_crypted_password, &crypt_buf))) {
+#else
+ if (!(crypted_password = crypt(password, stored_crypted_password))) {
+#endif
+ pam_syslog(pamh, LOG_ERR, "crypt() failed");
+ free(linebuf);
+ return PAM_AUTH_ERR;
+ }
- /* Extract the salt and set the passwd length, depending on MD5 or DES */
- if (strncmp(stored_crypted_password, "$1$", 3) == 0) {
- D(_pam_log(LOG_ERR,"password hash type is 'md5'"));
- /* get out the salt into "salt" */
- strncpy(salt, stored_crypted_password, 11);
- salt[11] = '\0';
- stored_crypted_password[CRYPTED_MD5PWD_LEN] = '\0';
- /* try both md5 crypts */
- crypted_password = Goodcrypt_md5(password, salt);
- if (strcmp(crypted_password, stored_crypted_password) == 0)
- {
- temp_result = 1;
- }
+ if (legacy_crypt && strcmp(crypted_password, stored_crypted_password)) {
+ if (!strncmp(stored_crypted_password, "$1$", 3))
+ crypted_password = Brokencrypt_md5(password, stored_crypted_password);
else
- {
- crypted_password = Brokencrypt_md5(password, salt);
- if (strcmp(crypted_password, stored_crypted_password) == 0)
- {
- temp_result = 1;
- }
- }
- } else {
- /* get the salt out into "salt" */
- strncpy(salt, stored_crypted_password, 2);
- salt[2] = '\0';
- stored_crypted_password[CRYPTED_BCPWD_LEN] = '\0';
-
- if (strlen(stored_crypted_password) <= CRYPTED_DESPWD_LEN) {
- D(_pam_log(LOG_ERR,"password hash type is 'crypt'"));
- crypted_password = crypt(password, salt);
- } else {
- D(_pam_log(LOG_ERR,"password hash type is 'bigcrypt'"));
- crypted_password = bigcrypt(password, salt);
- }
-
- if (strcmp(crypted_password, stored_crypted_password) == 0)
- {
- temp_result = 1;
- }
+ crypted_password = bigcrypt(password, stored_crypted_password);
}
-
- /* DEBUG */
- D(_pam_log(LOG_ERR,"user password crypted is '%s'", crypted_password));
-
- /* if things don't match up, complain */
- if (!temp_result)
- {
- _pam_log(LOG_ERR,"wrong password for user %s",name);
- fclose(pwdfile);
+
+ if (strcmp(crypted_password, stored_crypted_password)) {
+ pam_syslog(pamh, LOG_NOTICE, "wrong password for user %s", name);
+ free(linebuf);
return PAM_AUTH_ERR;
}
- /* DEBUG */
- D(_pam_log(LOG_ERR,"passwords match"));
-
- /* we've gotten here, i.e. authentication was sucessful! */
- fclose(pwdfile);
+ if (debug) pam_syslog(pamh, LOG_DEBUG, "passwords match");
+ free(linebuf);
return PAM_SUCCESS;
}
/* another expected hook */
+__attribute__((visibility("default")))
PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags,
int argc, const char **argv)
{
@@ -425,3 +248,4 @@ struct pam_module _pam_listfile_modstruct = {
NULL,
};
#endif
+/* vim:set ts=8 sw=4: */