From fbce1a480fda4c97b21c87fb39096d23db6eedfb Mon Sep 17 00:00:00 2001 From: Timo Weingärtner Date: Thu, 25 Apr 2013 14:27:07 +0200 Subject: apply visibility patch by Peter Palfrader --- pam_pwdfile.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'pam_pwdfile.c') diff --git a/pam_pwdfile.c b/pam_pwdfile.c index 2d020a9..c8cae75 100644 --- a/pam_pwdfile.c +++ b/pam_pwdfile.c @@ -222,6 +222,7 @@ static int fgetpwnam(FILE *stream, const char *name, char *password) { } /* 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; @@ -408,6 +409,7 @@ PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, } /* another expected hook */ +__attribute__((visibility("default"))) PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) { -- cgit v1.2.3 From 629c03d7775e1f4b5c0fdee358c6773f70e91961 Mon Sep 17 00:00:00 2001 From: Timo Weingärtner Date: Fri, 26 Apr 2013 12:57:56 +0200 Subject: add debug module option and use pam_syslog also: * remove some unnessesary comments * add vim settings for unusual indentation --- bigcrypt.c | 5 ----- pam_pwdfile.c | 71 ++++++++++++++++++++--------------------------------------- 2 files changed, 24 insertions(+), 52 deletions(-) (limited to 'pam_pwdfile.c') diff --git a/bigcrypt.c b/bigcrypt.c index b1568d6..28d042a 100644 --- a/bigcrypt.c +++ b/bigcrypt.c @@ -25,7 +25,6 @@ */ #include -#include char *crypt(const char *key, const char *salt); char *bigcrypt(const char *key, const char *salt); @@ -51,8 +50,6 @@ char *bigcrypt(const char *key, const char *salt) char *cipher_ptr, *plaintext_ptr, *tmp_ptr, *salt_ptr; char keybuf[KEYBUF_SIZE + 1]; - D(("called with key='%s', salt='%s'.", key, salt)); - /* reset arrays */ memset(keybuf, 0, KEYBUF_SIZE + 1); memset(dec_c2_cryptbuf, 0, CBUF_SIZE); @@ -111,9 +108,7 @@ char *bigcrypt(const char *key, const char *salt) salt_ptr = cipher_ptr - ESEGMENT_SIZE; } } - D(("key=|%s|, salt=|%s|\nbuf=|%s|\n", key, salt, dec_c2_cryptbuf)); /* this is the terminated encrypted password */ - return dec_c2_cryptbuf; } diff --git a/pam_pwdfile.c b/pam_pwdfile.c index c8cae75..d8c9e69 100644 --- a/pam_pwdfile.c +++ b/pam_pwdfile.c @@ -44,7 +44,6 @@ #include #include -#include #include #include #include @@ -54,11 +53,13 @@ #include #include #include +#include #include #define PAM_SM_AUTH #include +#include #include "md5.h" extern char *crypt(const char *key, const char *salt); @@ -72,27 +73,10 @@ extern char *bigcrypt(const char *key, const char *salt); #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(); -} - static int lock_fd(int fd) { int delay; @@ -235,6 +219,7 @@ PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int use_flock = 0; int use_delay = 1; int temp_result = 0; + int debug = 0; /* 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 */ @@ -264,48 +249,45 @@ PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, } else if (strcmp(argv[pcnt],NODELAY_PARAM)==0) { /* no delay on authentication failure */ use_delay = 0; + } else if (strcmp(argv[pcnt], "debug") == 0) { + debug = 1; } } while (++pcnt < argc); #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"); + pam_syslog(pamh, LOG_ERR, "password file name not specified"); return PAM_AUTHINFO_UNAVAIL; } - /* DEBUG */ - D(_pam_log(LOG_ERR, "password filename extracted")); + if (debug) pam_syslog(pamh, LOG_DEBUG, "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); + pam_syslog(pamh, LOG_ALERT, "couldn't open password file %s", pwdfilename); return PAM_AUTHINFO_UNAVAIL; } - /* 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); + pam_syslog(pamh, LOG_ALERT, "couldn't lock 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"); + pam_syslog(pamh, LOG_ERR, "username not found"); fclose(pwdfile); return retval; } - - /* DEBUG */ - D(_pam_log(LOG_ERR,"username is %s", name)); + if (debug) pam_syslog(pamh, LOG_DEBUG, "username is %s", name); /* get password - code from pam_unix_auth.c */ pam_get_item(pamh, PAM_AUTHTOK, (void *)&password); @@ -319,38 +301,34 @@ PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, pam_get_item(pamh, PAM_AUTHTOK, (void *)&password); if ((retval = pam_get_item(pamh, PAM_AUTHTOK, (void *)&password)) != PAM_SUCCESS) { - _pam_log(LOG_ERR, "auth token not found"); + pam_syslog(pamh, LOG_ERR, "auth token not found"); fclose(pwdfile); return retval; } - /* 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"); + pam_syslog(pamh, LOG_ERR, "password too short or NULL"); fclose(pwdfile); 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"); + pam_syslog(pamh, LOG_ERR, "user not found in password database"); fclose(pwdfile); return PAM_AUTHINFO_UNAVAIL; } - /* 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; /* 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'")); + if (debug) pam_syslog(pamh, LOG_ERR, "password hash type is 'md5'"); /* get out the salt into "salt" */ strncpy(salt, stored_crypted_password, 11); salt[11] = '\0'; @@ -376,10 +354,10 @@ PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, 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'")); + if (debug) pam_syslog(pamh, LOG_DEBUG, "password hash type is 'crypt'"); crypted_password = crypt(password, salt); } else { - D(_pam_log(LOG_ERR,"password hash type is 'bigcrypt'")); + if (debug) pam_syslog(pamh, LOG_DEBUG, "password hash type is 'bigcrypt'"); crypted_password = bigcrypt(password, salt); } @@ -389,19 +367,17 @@ PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, } } - /* DEBUG */ - D(_pam_log(LOG_ERR,"user password crypted is '%s'", crypted_password)); + if (debug) pam_syslog(pamh, LOG_DEBUG, "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); + pam_syslog(pamh, LOG_NOTICE, "wrong password for user %s", name); fclose(pwdfile); return PAM_AUTH_ERR; } - /* DEBUG */ - D(_pam_log(LOG_ERR,"passwords match")); + if (debug) pam_syslog(pamh, LOG_DEBUG, "passwords match"); /* we've gotten here, i.e. authentication was sucessful! */ fclose(pwdfile); @@ -427,3 +403,4 @@ struct pam_module _pam_listfile_modstruct = { NULL, }; #endif +/* vim:set ts=8 sw=4: */ -- cgit v1.2.3 From 86c95423b2908869ee42f9f40896a0bb0b773cf4 Mon Sep 17 00:00:00 2001 From: Timo Weingärtner Date: Sat, 27 Apr 2013 23:55:20 +0200 Subject: rework argument parsing * don't copy pwdfile argument, we don't need to modify it * replace sizeof() with strlen() as that is easier to understand and the compiler can also optimize it away * expand DEFINE's so we can get rid of the comments --- pam_pwdfile.c | 48 +++++++++++++----------------------------------- 1 file changed, 13 insertions(+), 35 deletions(-) (limited to 'pam_pwdfile.c') diff --git a/pam_pwdfile.c b/pam_pwdfile.c index d8c9e69..21e37d9 100644 --- a/pam_pwdfile.c +++ b/pam_pwdfile.c @@ -65,10 +65,6 @@ 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 @@ -209,10 +205,10 @@ static int fgetpwnam(FILE *stream, const char *name, char *password) { __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 retval, i; const char *name; char *password; - char pwdfilename[PWDFN_LEN]; + char const * pwdfilename = NULL; char salt[12], stored_crypted_password[CRYPTED_BCPWD_LEN+1]; char *crypted_password; FILE *pwdfile; @@ -222,38 +218,20 @@ PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int debug = 0; /* 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; - } else if (strcmp(argv[pcnt], "debug") == 0) { + else if (!strcmp(argv[i], "debug")) debug = 1; - } - - } while (++pcnt < argc); + } #ifdef HAVE_PAM_FAIL_DELAY if (use_delay) { @@ -262,7 +240,7 @@ PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, } #endif - if (!pwdfilename_found) { + if (!pwdfilename) { pam_syslog(pamh, LOG_ERR, "password file name not specified"); return PAM_AUTHINFO_UNAVAIL; } -- cgit v1.2.3 From 0437f4656f1d5a541b4ab951c457fae19f8deee4 Mon Sep 17 00:00:00 2001 From: Timo Weingärtner Date: Sun, 28 Apr 2013 17:15:15 +0200 Subject: use pam_get_authtok this also gets it right with use_first_pass also use the default prompt for the username --- pam_pwdfile.c | 87 +++-------------------------------------------------------- 1 file changed, 3 insertions(+), 84 deletions(-) (limited to 'pam_pwdfile.c') diff --git a/pam_pwdfile.c b/pam_pwdfile.c index 21e37d9..cd4d941 100644 --- a/pam_pwdfile.c +++ b/pam_pwdfile.c @@ -69,10 +69,6 @@ extern char *bigcrypt(const char *key, const char *salt); #define CRYPTED_MD5PWD_LEN 34 #define CRYPTED_BCPWD_LEN 178 -/* prototypes */ -int converse(pam_handle_t *, int, struct pam_message **, struct pam_response **); -int _set_auth_tok(pam_handle_t *, int, int, const char **); - static int lock_fd(int fd) { int delay; @@ -90,72 +86,6 @@ 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 @@ -207,7 +137,7 @@ PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) { int retval, i; const char *name; - char *password; + char const * password; char const * pwdfilename = NULL; char salt[12], stored_crypted_password[CRYPTED_BCPWD_LEN+1]; char *crypted_password; @@ -259,7 +189,7 @@ PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, } /* get user name */ - if ((retval = pam_get_user(pamh,&name,"login: ")) != PAM_SUCCESS) { + if ((retval = pam_get_user(pamh, &name, NULL)) != PAM_SUCCESS) { pam_syslog(pamh, LOG_ERR, "username not found"); fclose(pwdfile); return retval; @@ -267,18 +197,7 @@ PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, if (debug) pam_syslog(pamh, LOG_DEBUG, "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; - } - } - pam_get_item(pamh, PAM_AUTHTOK, (void *)&password); - - if ((retval = pam_get_item(pamh, PAM_AUTHTOK, (void *)&password)) != PAM_SUCCESS) { + if ((retval = pam_get_authtok(pamh, PAM_AUTHTOK, &password, NULL)) != PAM_SUCCESS) { pam_syslog(pamh, LOG_ERR, "auth token not found"); fclose(pwdfile); return retval; -- cgit v1.2.3 From 138c589dd4cdf68659bfa643e5659fa1200f6081 Mon Sep 17 00:00:00 2001 From: Timo Weingärtner Date: Mon, 29 Apr 2013 13:06:26 +0200 Subject: rework pwdfile reading * drop rewind(), we read the file just once * use getline() to get rid of the fixed-size buffer * let strsep() also handle the newline * stop at the first line containing the user instead of using the last --- pam_pwdfile.c | 60 +++++++++++++++++++++++++---------------------------------- 1 file changed, 25 insertions(+), 35 deletions(-) (limited to 'pam_pwdfile.c') diff --git a/pam_pwdfile.c b/pam_pwdfile.c index cd4d941..80cd893 100644 --- a/pam_pwdfile.c +++ b/pam_pwdfile.c @@ -91,43 +91,33 @@ static int lock_fd(int fd) { * 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; + char * linebuf = NULL; + size_t linebuflen; + int pwdfound = 0; - /* 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); + while (getline(&linebuf, &linebuflen, stream) > 0) { + /* strsep changes its argument, make a copy */ + char * nexttok = linebuf; + + /* first field: username */ + char * curtok = strsep(&nexttok, ":"); + + /* skip non-matchin usernames */ + if (strcmp(curtok, name)) + continue; + + /* second field: password (until next colon or newline) */ + curtok = strsep(&nexttok, ":\n"); + + if (curtok) { + /* we use bigcrypt pwd len, as this is just a safe maximum */ + strncpy(password, curtok, CRYPTED_BCPWD_LEN + 1); + pwdfound = 1; + break; + } + } + free(linebuf); /* allocated by getline */ return pwdfound; } -- cgit v1.2.3 From 88dd2b1a22cd06fc401a8ddadd41114cebe159d5 Mon Sep 17 00:00:00 2001 From: Timo Weingärtner Date: Fri, 10 May 2013 21:27:56 +0200 Subject: include proper headers for crypt() this also prepares for crypt_r() --- bigcrypt.c | 5 +++-- bigcrypt.h | 1 + pam_pwdfile.c | 15 +++++++++++++-- 3 files changed, 17 insertions(+), 4 deletions(-) create mode 100644 bigcrypt.h (limited to 'pam_pwdfile.c') diff --git a/bigcrypt.c b/bigcrypt.c index 28d042a..c1486fa 100644 --- a/bigcrypt.c +++ b/bigcrypt.c @@ -24,10 +24,11 @@ * Andy Phillips */ +#define _XOPEN_SOURCE +#include #include -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 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/pam_pwdfile.c b/pam_pwdfile.c index 80cd893..34ce78d 100644 --- a/pam_pwdfile.c +++ b/pam_pwdfile.c @@ -42,6 +42,18 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ +#ifdef USE_CRYPT_R +#define _GNU_SOURCE +#include +#else +#ifndef _XOPEN_SOURCE +#define _XOPEN_SOURCE 700 +#endif +#ifndef _BSD_SOURCE +#define _BSD_SOURCE +#endif +#endif + #include #include #include @@ -62,8 +74,7 @@ #include #include "md5.h" -extern char *crypt(const char *key, const char *salt); -extern char *bigcrypt(const char *key, const char *salt); +#include "bigcrypt.h" #define CRYPTED_DESPWD_LEN 13 #define CRYPTED_MD5PWD_LEN 34 -- cgit v1.2.3 From ce9367b3202477b3cc914cabfe0cb2a856f3a51d Mon Sep 17 00:00:00 2001 From: Timo Weingärtner Date: Fri, 10 May 2013 21:30:05 +0200 Subject: major overhaul * merge fgetpwnam into pam_sm_authenticate * handle empty password field * fix a fd and memory leak if pwdfile opening succeeds but locking fails * use crypt_r (enabled via USE_CRYPT_R) * rely on crypt() to handle newer crypt variants (including "good" md5 crypt) * make bigcrypt and broken md5 crypt optional * add some const's --- Makefile | 10 +--- pam_pwdfile.c | 185 +++++++++++++++++++++------------------------------------- 2 files changed, 70 insertions(+), 125 deletions(-) (limited to 'pam_pwdfile.c') diff --git a/Makefile b/Makefile index 06e1637..5b60784 100644 --- a/Makefile +++ b/Makefile @@ -2,14 +2,14 @@ PAM_LIB_DIR ?= $(DESTDIR)/lib/security INSTALL ?= install CFLAGS ?= -O2 -g -Wall -Wformat-security +CPPFLAGS += -DUSE_CRYPT_R CFLAGS += -fPIC -fvisibility=hidden LDFLAGS += -Wl,-x -shared TITLE = pam_pwdfile LIBSHARED = $(TITLE).so LDLIBS = -lcrypt -lpam -LIBOBJ = $(TITLE).o md5_good.o md5_broken.o md5_crypt_good.o md5_crypt_broken.o bigcrypt.o -CPPFLAGS_MD5_GOOD = -D'MD5Name(x)=Good\#\#x' +LIBOBJ = $(TITLE).o md5_broken.o md5_crypt_broken.o bigcrypt.o CPPFLAGS_MD5_BROKEN = -DHIGHFIRST -D'MD5Name(x)=Broken\#\#x' @@ -19,15 +19,9 @@ $(LIBSHARED): $(LIBOBJ) $(CC) $(LDFLAGS) $(LIBOBJ) $(LDLIBS) -o $@ -md5_good.o: md5.c - $(CC) -c $(CPPFLAGS) $(CPPFLAGS_MD5_GOOD) $(CFLAGS) $< -o $@ - md5_broken.o: md5.c $(CC) -c $(CPPFLAGS) $(CPPFLAGS_MD5_BROKEN) $(CFLAGS) $< -o $@ -md5_crypt_good.o: md5_crypt.c - $(CC) -c $(CPPFLAGS) $(CPPFLAGS_MD5_GOOD) $(CFLAGS) $< -o $@ - md5_crypt_broken.o: md5_crypt.c $(CC) -c $(CPPFLAGS) $(CPPFLAGS_MD5_BROKEN) $(CFLAGS) $< -o $@ diff --git a/pam_pwdfile.c b/pam_pwdfile.c index 34ce78d..4e8805d 100644 --- a/pam_pwdfile.c +++ b/pam_pwdfile.c @@ -76,10 +76,6 @@ #include "md5.h" #include "bigcrypt.h" -#define CRYPTED_DESPWD_LEN 13 -#define CRYPTED_MD5PWD_LEN 34 -#define CRYPTED_BCPWD_LEN 178 - static int lock_fd(int fd) { int delay; @@ -97,56 +93,26 @@ static int lock_fd(int fd) { return -1; } -/* 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 * linebuf = NULL; - size_t linebuflen; - int pwdfound = 0; - - /* iterate through lines in file, until end of file */ - while (getline(&linebuf, &linebuflen, stream) > 0) { - /* strsep changes its argument, make a copy */ - char * nexttok = linebuf; - - /* first field: username */ - char * curtok = strsep(&nexttok, ":"); - - /* skip non-matchin usernames */ - if (strcmp(curtok, name)) - continue; - - /* second field: password (until next colon or newline) */ - curtok = strsep(&nexttok, ":\n"); - - if (curtok) { - /* we use bigcrypt pwd len, as this is just a safe maximum */ - strncpy(password, curtok, CRYPTED_BCPWD_LEN + 1); - pwdfound = 1; - break; - } - } - free(linebuf); /* allocated by getline */ - 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, i; + int i; const char *name; char const * password; char const * pwdfilename = NULL; - char salt[12], stored_crypted_password[CRYPTED_BCPWD_LEN+1]; - char *crypted_password; + 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 */ for (i = 0; i < argc; ++i) { @@ -162,6 +128,8 @@ PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, use_delay = 0; else if (!strcmp(argv[i], "debug")) debug = 1; + else if (!strcmp(argv[i], "legacy_crypt")) + legacy_crypt = 1; } #ifdef HAVE_PAM_FAIL_DELAY @@ -176,109 +144,92 @@ PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, return PAM_AUTHINFO_UNAVAIL; } - if (debug) pam_syslog(pamh, LOG_DEBUG, "password filename extracted"); + 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); - /* now try to open the password file */ - if ((pwdfile=fopen(pwdfilename,"r"))==NULL) { + if (!(pwdfile = fopen(pwdfilename, "r"))) { pam_syslog(pamh, LOG_ALERT, "couldn't open password file %s", pwdfilename); return PAM_AUTHINFO_UNAVAIL; } if (use_flock && lock_fd(fileno(pwdfile)) == -1) { pam_syslog(pamh, LOG_ALERT, "couldn't lock password file %s", pwdfilename); + fclose(pwdfile); return PAM_AUTHINFO_UNAVAIL; } - /* get user name */ - if ((retval = pam_get_user(pamh, &name, NULL)) != PAM_SUCCESS) { - pam_syslog(pamh, LOG_ERR, "username not found"); - 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; + } } + 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 (debug) pam_syslog(pamh, LOG_DEBUG, "username is %s", name); - - if ((retval = pam_get_authtok(pamh, PAM_AUTHTOK, &password, NULL)) != PAM_SUCCESS) { - pam_syslog(pamh, 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; } - /* 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_syslog(pamh, 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_syslog(pamh, LOG_ERR, "user not found in password database"); - fclose(pwdfile); - return PAM_AUTHINFO_UNAVAIL; + if (!stored_crypted_password) { + free(linebuf); + return PAM_USER_UNKNOWN; } if (debug) pam_syslog(pamh, LOG_DEBUG, "got crypted password == '%s'", stored_crypted_password); +#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; + } - temp_result = 0; - - /* Extract the salt and set the passwd length, depending on MD5 or DES */ - if (strncmp(stored_crypted_password, "$1$", 3) == 0) { - if (debug) pam_syslog(pamh, 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) { - if (debug) pam_syslog(pamh, LOG_DEBUG, "password hash type is 'crypt'"); - crypted_password = crypt(password, salt); - } else { - if (debug) pam_syslog(pamh, LOG_DEBUG, "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); } - - if (debug) pam_syslog(pamh, LOG_DEBUG, "user password crypted is '%s'", crypted_password); - - /* if things don't match up, complain */ - if (!temp_result) - { + + if (strcmp(crypted_password, stored_crypted_password)) { pam_syslog(pamh, LOG_NOTICE, "wrong password for user %s", name); - fclose(pwdfile); + free(linebuf); return PAM_AUTH_ERR; } if (debug) pam_syslog(pamh, LOG_DEBUG, "passwords match"); - - /* we've gotten here, i.e. authentication was sucessful! */ - fclose(pwdfile); + free(linebuf); return PAM_SUCCESS; } -- cgit v1.2.3 From e493c1467bbaebfbaf2a9a6b1da3398b76232ce5 Mon Sep 17 00:00:00 2001 From: Timo Weingärtner Date: Tue, 14 May 2013 20:22:36 +0200 Subject: remove CVS $Id line and static version number --- INSTALL | 1 - README | 3 --- changelog | 1 - contrib/README.txt | 2 -- md5.c | 2 -- md5_crypt.c | 2 -- pam_pwdfile.c | 4 ---- 7 files changed, 15 deletions(-) (limited to 'pam_pwdfile.c') diff --git a/INSTALL b/INSTALL index 97ed833..5fe4680 100644 --- a/INSTALL +++ b/INSTALL @@ -1,5 +1,4 @@ INSTALL for pam_pwdfile PAM module - Charl P. Botha -$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 diff --git a/README b/README index d5c82f9..4f07913 100644 --- a/README +++ b/README @@ -1,9 +1,6 @@ README for pam_pwdfile PAM module - Charl P. Botha -$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, diff --git a/changelog b/changelog index e545376..9936e81 100644 --- a/changelog +++ b/changelog @@ -1,5 +1,4 @@ changelog for pam_pwdfile PAM module - Charl P. Botha -$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/README.txt b/contrib/README.txt index a8c8462..1c0f886 100644 --- a/contrib/README.txt +++ b/contrib/README.txt @@ -1,5 +1,3 @@ -$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 . You can use these for building RPMs of pam_pwdfile; you should also be able to use the Makefile to build diff --git a/md5.c b/md5.c index 3565e55..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. diff --git a/md5_crypt.c b/md5_crypt.c index 7871b45..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): * wrote this file. As long as you retain this notice you diff --git a/pam_pwdfile.c b/pam_pwdfile.c index 4e8805d..9b96fe3 100644 --- a/pam_pwdfile.c +++ b/pam_pwdfile.c @@ -1,13 +1,9 @@ /* pam_pwdfile.c copyright 1999-2003 by Charl P. Botha * - * $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 -- cgit v1.2.3