diff -ru poppassd-1.8.5-orig/Makefile poppassd-1.8.5-new/Makefile --- poppassd-1.8.5-orig/Makefile 2004-12-02 15:27:29.000000000 +0100 +++ poppassd-1.8.5-new/Makefile 2014-09-14 01:16:41.000000000 +0200 @@ -1,5 +1,5 @@ BINDIR = /usr/sbin -CFLAGS = -O2 +CFLAGS = -O2 -Wall CC=gcc poppassd: poppassd.c Makefile diff -ru poppassd-1.8.5-orig/poppassd.c poppassd-1.8.5-new/poppassd.c --- poppassd-1.8.5-orig/poppassd.c 2004-12-02 15:27:43.000000000 +0100 +++ poppassd-1.8.5-new/poppassd.c 2014-09-14 12:05:00.930443413 +0200 @@ -36,8 +36,8 @@ #define VERSION "1.8.5" #define BAD_PASS_DELAY 3 /* delay in seconds after bad 'Old password' */ -#define POP_MIN_UID 100 /* minimum UID which is allowed to change - password via poppassd */ +#define POP_MIN_UID 500 /* minimum UID which is allowed to change password + via poppassd (RHEL7/Centos7, Fedora 16+ use UID_MIN=1000 (/etc/login.defs) */ /* These need to be quoted because they are only used as * parts of format strings for sscanf; actual lengths are smaller @@ -53,6 +53,9 @@ #include #include +/* Warning: non-GNU Unices probably do not know FNM_CASEFOLD flag! */ +#define _GNU_SOURCE /* need the fnmatch FNM_CASEFOLD flag */ +#include #include #include #include @@ -104,7 +107,6 @@ void ReadFromClient (char *line) { char *sp; - int i; bzero(line, BUFSIZE); fgets (line, BUFSIZE-1, stdin); @@ -123,7 +125,7 @@ struct pam_response **resp; void *appdata_ptr; { - int i; + int i,ret; struct pam_response *r = malloc(sizeof(struct pam_response) * num_msg); if(num_msg <= 0) @@ -131,7 +133,7 @@ if(r == NULL) return(PAM_CONV_ERR); - + ret=PAM_SUCCESS; for(i=0; imsg_style == PAM_ERROR_MSG) { WriteToClient ("500 PAM error: %s", msg[i]->msg); @@ -141,6 +143,7 @@ * anything more, so set pop_state to invalid */ pop_state = POP_SKIPASS; + ret=PAM_CONV_ERR; } r[i].resp_retcode = 0; @@ -150,20 +153,27 @@ switch(pop_state) { case POP_OLDPASS: r[i].resp = strdup(oldpass); break; - case POP_NEWPASS: r[i].resp = strdup(newpass); + case POP_NEWPASS: + if (fnmatch("*new password*", msg[i]->msg, FNM_CASEFOLD) == 0){ + r[i].resp = strdup(newpass); + } else { + r[i].resp = strdup(oldpass); + } break; case POP_SKIPASS: r[i].resp = NULL; + ret=PAM_CONV_ERR; break; default: syslog(LOG_ERR, "PAM error: too many switches (state=%d)", pop_state); } } else { r[i].resp = strdup(""); + ret=PAM_CONV_ERR; } } *resp = r; - return PAM_SUCCESS; + return ret; } const struct pam_conv pam_conv = { @@ -175,16 +185,9 @@ { char line[BUFSIZE]; char user[BUFSIZE]; - char emess[BUFSIZE]; - char *slavedev; struct passwd *pw, *getpwnam(); - struct spwd *sp; - int c, master; - pid_t pid, wpid; - int wstat; - int ret; + int pamret; pam_handle_t *pamh=NULL; - char *item=oldpass; *user = *oldpass = *newpass = 0; @@ -222,10 +225,11 @@ WriteToClient("500 Password required."); exit(1); } - if(pam_authenticate(pamh, 0) != PAM_SUCCESS) + pamret = pam_authenticate(pamh, 0); + if(pamret != PAM_SUCCESS) { WriteToClient ("500 Old password is incorrect."); - syslog(LOG_ERR, "old password is incorrect for user %s", user); + syslog(LOG_ERR, "old password is incorrect (pam_authenticate error %i) for user %s", pamret, user); /* pause to make brute force attacks harder */ sleep(BAD_PASS_DELAY); exit(1); @@ -252,11 +256,12 @@ exit(1); } - if(pam_chauthtok(pamh, 0) != PAM_SUCCESS) { - WriteToClient("500 Server error, password not changed"); + pamret = pam_chauthtok(pamh, PAM_SILENT); + if(pamret != PAM_SUCCESS) { + WriteToClient("500 Server pam_chauthtok error %i, password not changed", pamret); exit(1); } else { - syslog(LOG_ERR, "changed POP3 password for %s", user); + syslog(LOG_ERR, "changed password for %s", user); WriteToClient("200 Password changed, thank-you."); ReadFromClient (line); if (strncmp(line, "quit", 4) != 0) { @@ -270,4 +275,3 @@ closelog(); exit(0); } -