diff options
author | Timo Weingärtner <timo@tiwe.de> | 2013-05-28 19:16:37 +0200 |
---|---|---|
committer | Timo Weingärtner <timo@tiwe.de> | 2013-05-28 19:16:37 +0200 |
commit | c7344fa5ca42b3203ce7fc2ff8cb93b42bf78123 (patch) | |
tree | c4790500e80a2d34c4040ba21aae878a21223ee8 | |
parent | 9316590e28c0087f65b220c492188871637aa424 (diff) | |
parent | 201e799f7a2fcba3af2c9214f25545460ef9b08a (diff) | |
download | libpam-pwdfile-c7344fa5ca42b3203ce7fc2ff8cb93b42bf78123.tar.gz |
Merge tag 'v0.100' into debian
release 0.100
Conflicts:
contrib/README.txt
-rw-r--r-- | CVS/Entries | 10 | ||||
-rw-r--r-- | CVS/Repository | 1 | ||||
-rw-r--r-- | CVS/Root | 1 | ||||
-rw-r--r-- | INSTALL | 46 | ||||
-rw-r--r-- | Makefile | 120 | ||||
-rw-r--r-- | README | 86 | ||||
-rw-r--r-- | bigcrypt.c | 101 | ||||
-rw-r--r-- | bigcrypt.h | 1 | ||||
-rw-r--r-- | changelog | 1 | ||||
-rw-r--r-- | contrib/CVS/Entries | 6 | ||||
-rw-r--r-- | contrib/CVS/Repository | 1 | ||||
-rw-r--r-- | contrib/CVS/Root | 1 | ||||
-rw-r--r-- | contrib/Makefile.standalone | 47 | ||||
-rw-r--r-- | contrib/Makefile.standalone-0.95 | 26 | ||||
-rw-r--r-- | contrib/README.txt | 15 | ||||
-rw-r--r-- | contrib/pam-pwdfile.spec | 44 | ||||
-rw-r--r-- | contrib/warwick_duncan-cyrus_without_system_accounts.txt | 49 | ||||
-rw-r--r-- | md5.c | 47 | ||||
-rw-r--r-- | md5.h | 10 | ||||
-rw-r--r-- | md5_crypt.c | 2 | ||||
-rw-r--r-- | pam_pwdfile.c | 392 |
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 @@ -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 @@ -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 @@ -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. @@ -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); @@ -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. @@ -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 @@ -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: */ |