diff options
Diffstat (limited to 'contrib/libpam/modules/pam_unix/pam_unix_passwd.c')
-rw-r--r-- | contrib/libpam/modules/pam_unix/pam_unix_passwd.c | 813 |
1 files changed, 813 insertions, 0 deletions
diff --git a/contrib/libpam/modules/pam_unix/pam_unix_passwd.c b/contrib/libpam/modules/pam_unix/pam_unix_passwd.c new file mode 100644 index 0000000..de1345e --- /dev/null +++ b/contrib/libpam/modules/pam_unix/pam_unix_passwd.c @@ -0,0 +1,813 @@ + +/* Main coding by Elliot Lee <sopwith@redhat.com>, Red Hat Software. + Copyright (C) 1996. */ + +/* + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + How it works: + Gets in username (has to be done) from the calling program + Does authentication of user (only if we are not running as root) + Gets new password/checks for sanity + Sets it. + */ + +#define PAM_SM_PASSWORD + +/* #define DEBUG 1 */ + +#include <stdio.h> +#include <sys/time.h> +#define _BSD_SOURCE +#define _SVID_SOURCE +#include <errno.h> +#define __USE_BSD +#define _BSD_SOURCE +#include <pwd.h> +#include <sys/types.h> + +/* why not defined? */ +void setpwent(void); +void endpwent(void); +int chmod(const char *path, mode_t mode); +struct passwd *fgetpwent(FILE *stream); +int putpwent(const struct passwd *p, FILE *stream); + +#include <unistd.h> +char *crypt(const char *key, const char *salt); +#ifdef USE_CRACKLIB +#include <crack.h> +#endif +#include <ctype.h> +#include <stdlib.h> +#include <stdio.h> +#include <syslog.h> +#include <string.h> +#include <stdarg.h> +#include <malloc.h> +#include <security/_pam_macros.h> + +#ifndef LINUX /* AGM added this as of 0.2 */ +#include <security/pam_appl.h> +#endif /* ditto */ +#include <security/pam_modules.h> +#ifdef HAVE_SHADOW_H +#include <shadow.h> +#endif + +#define MAX_PASSWD_TRIES 3 +#define OLD_PASSWORD_PROMPT "Password: " +#define NEW_PASSWORD_PROMPT "New password: " +#define AGAIN_PASSWORD_PROMPT "New password (again): " +#define PW_TMPFILE "/etc/npasswd" +#define SH_TMPFILE "/etc/nshadow" +#define CRACKLIB_DICTS "/usr/lib/cracklib_dict" + +/* Various flags for the getpass routine to send back in... */ +#define PPW_EXPIRED 1 +#define PPW_EXPIRING 2 +#define PPW_WILLEXPIRE 4 +#define PPW_NOSUCHUSER 8 +#define PPW_SHADOW 16 +#define PPW_TOOEARLY 32 +#define PPW_ERROR 64 + +#ifndef DO_TEST +#define STATIC static +#else +#define STATIC +#endif +/* Sets a password for the specified user to the specified password + Returns flags PPW_*, or'd. */ +STATIC int _do_setpass(char *forwho, char *towhat, int flags); +/* Gets a password for the specified user + Returns flags PPW_*, or'd. */ +STATIC int _do_getpass(char *forwho, char **theirpass); +/* Checks whether the password entered is same as listed in the database + 'entered' should not be crypt()'d or anything (it should be as the + user entered it...), 'listed' should be as it is listed in the + password database file */ +STATIC int _do_checkpass(const char *entered, char *listed); + +/* sends a one-way message to the user, either error or info... */ +STATIC int conv_sendmsg(struct pam_conv *aconv, const char *message, int style); +/* sends a message and returns the results of the conversation */ +STATIC int conv_getitem(struct pam_conv *aconv, char *message, int style, + char **result); + +PAM_EXTERN +int pam_sm_chauthtok( pam_handle_t *pamh, + int flags, + int argc, + const char **argv); + +static void _pam_log(int err, const char *format, ...) +{ + va_list args; + + va_start(args, format); + openlog("PAM-unix_passwd", LOG_CONS|LOG_PID, LOG_AUTH); + vsyslog(err, format, args); + va_end(args); + closelog(); +} + +#ifdef NEED_LCKPWDF +/* This is a hack, but until libc and glibc both include this function + * by default (libc only includes it if nys is not being used, at the + * moment, and glibc doesn't appear to have it at all) we need to have + * it here, too. :-( + * + * This should not become an official part of PAM. + * + * BEGIN_HACK +*/ + +/* + * lckpwdf.c -- prevent simultaneous updates of password files + * + * Before modifying any of the password files, call lckpwdf(). It may block + * for up to 15 seconds trying to get the lock. Return value is 0 on success + * or -1 on failure. When you are done, call ulckpwdf() to release the lock. + * The lock is also released automatically when the process exits. Only one + * process at a time may hold the lock. + * + * These functions are supposed to be conformant with AT&T SVID Issue 3. + * + * Written by Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>, + * public domain. + */ + +#include <fcntl.h> +#include <signal.h> + +#define LOCKFILE "/etc/.pwd.lock" +#define TIMEOUT 15 + +static int lockfd = -1; + +static int +set_close_on_exec(int fd) +{ + int flags = fcntl(fd, F_GETFD, 0); + if (flags == -1) + return -1; + flags |= FD_CLOEXEC; + return fcntl(fd, F_SETFD, flags); +} + +static int +do_lock(int fd) +{ + struct flock fl; + + memset(&fl, 0, sizeof fl); + fl.l_type = F_WRLCK; + fl.l_whence = SEEK_SET; + return fcntl(fd, F_SETLKW, &fl); +} + +static void +alarm_catch(int sig) +{ +/* does nothing, but fcntl F_SETLKW will fail with EINTR */ +} + +static int lckpwdf(void) +{ + struct sigaction act, oldact; + sigset_t set, oldset; + + if (lockfd != -1) + return -1; + + lockfd = open(LOCKFILE, O_CREAT | O_WRONLY, 0600); + if (lockfd == -1) + return -1; + if (set_close_on_exec(lockfd) == -1) + goto cleanup_fd; + + memset(&act, 0, sizeof act); + act.sa_handler = alarm_catch; + act.sa_flags = 0; + sigfillset(&act.sa_mask); + if (sigaction(SIGALRM, &act, &oldact) == -1) + goto cleanup_fd; + + sigemptyset(&set); + sigaddset(&set, SIGALRM); + if (sigprocmask(SIG_UNBLOCK, &set, &oldset) == -1) + goto cleanup_sig; + + alarm(TIMEOUT); + if (do_lock(lockfd) == -1) + goto cleanup_alarm; + alarm(0); + sigprocmask(SIG_SETMASK, &oldset, NULL); + sigaction(SIGALRM, &oldact, NULL); + return 0; + +cleanup_alarm: + alarm(0); + sigprocmask(SIG_SETMASK, &oldset, NULL); +cleanup_sig: + sigaction(SIGALRM, &oldact, NULL); +cleanup_fd: + close(lockfd); + lockfd = -1; + return -1; +} + +static int +ulckpwdf(void) +{ + unlink(LOCKFILE); + if (lockfd == -1) + return -1; + + if (close(lockfd) == -1) { + lockfd = -1; + return -1; + } + lockfd = -1; + return 0; +} +/* END_HACK */ +#endif + +#define PAM_FAIL_CHECK if(retval != PAM_SUCCESS) { return retval; } + +PAM_EXTERN +int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv) +{ + char *usrname, *curpass, *newpass; /* pointers to the username, + current password, and new password */ + + struct pam_conv *appconv; /* conversation with the app */ + struct pam_message msg, *pmsg; /* Misc for conversations */ + struct pam_response *resp; + + int retval=0; /* Gets the return values for all our function calls */ + unsigned int pflags=0; /* Holds the flags from our getpass & setpass + functions */ + + const char *cmiscptr; /* Utility variables, used for different purposes at + different times */ + char *miscptr; /* Utility variables, used for different purposes at + different times */ + unsigned int miscint; + int fascist = 1; /* Be fascist by default. If compiled with cracklib, + call cracklib. Otherwise just check length... */ + + char argbuf[256],argval[256]; + int i; + + + retval = pam_get_item(pamh,PAM_CONV,(const void **) &appconv); + PAM_FAIL_CHECK; + + retval = pam_get_item(pamh,PAM_USER,(const void **) &usrname); + PAM_FAIL_CHECK; + if(flags & PAM_PRELIM_CHECK) { + pflags = _do_getpass(usrname,&miscptr); + if(pflags & PPW_NOSUCHUSER) + return PAM_USER_UNKNOWN; + else if(pflags & ~(PPW_SHADOW|PPW_EXPIRING|PPW_WILLEXPIRE)) + return PAM_AUTHTOK_ERR; + else + return PAM_SUCCESS; + } /* else... */ +#ifdef DEBUG + fprintf(stderr,"Got username of %s\n",usrname); +#endif + if((usrname == NULL) || (strlen(usrname) < 1)) { + /* The app is supposed to get us the username! */ + retval = PAM_USER_UNKNOWN; + PAM_FAIL_CHECK; + } + + for(i=0; i < argc; i++) { + { + char *tmp = x_strdup(argv[i]); + strncpy(argbuf,strtok(tmp ,"="),255); + strncpy(argval,strtok(NULL,"="),255); + free(tmp); + } + + /* For PC functionality use "strict" -- historically "fascist" */ + if(!strcmp(argbuf,"strict") || !strcmp(argbuf, "fascist")) + + if(!strcmp(argval,"true")) + fascist = 1; + else if(!strcmp(argval,"false")) + fascist = 0; + else + return PAM_SERVICE_ERR; + else { + _pam_log(LOG_ERR,"Unknown option: %s",argbuf); + return PAM_SERVICE_ERR; + } + } + + + /* Now we have all the initial information we need from the app to + set things up (we assume that getting the username succeeded...) */ + retval = pam_get_item(pamh,PAM_OLDAUTHTOK,(const void **) &curpass); + PAM_FAIL_CHECK; + if(getuid()) { /* If this is being run by root, we don't need to get their + old password. + note */ + /* If we haven't been given a password yet, prompt for one... */ + miscint=0; + while((curpass == NULL) && (miscint++ < MAX_PASSWD_TRIES)) { + pflags = _do_getpass(usrname,&miscptr); + if(pflags & PPW_NOSUCHUSER) + return PAM_USER_UNKNOWN; /* If the user that was passed in doesn't + exist, say so and exit (app passes in + username) */ + + /* Get the password from the user... */ + pmsg = &msg; + + msg.msg_style = PAM_PROMPT_ECHO_OFF; + msg.msg = OLD_PASSWORD_PROMPT; + resp = NULL; + + retval = appconv->conv(1, (const struct pam_message **) &pmsg, + &resp, appconv->appdata_ptr); + + PAM_FAIL_CHECK; + curpass = resp->resp; + free (resp); + if(_do_checkpass(curpass?curpass:"",miscptr)) { + int abortme = 0; + + /* password is incorrect... */ + if (curpass && curpass[0] == '\0') { + /* ...and it was zero-length; user wishes to abort change */ + abortme = 1; + } + if (curpass) { free (curpass); } + curpass = NULL; + if (abortme) { + conv_sendmsg(appconv,"Password change aborted.",PAM_ERROR_MSG); + return PAM_AUTHTOK_ERR; + } + } + } + + if(curpass == NULL) + return PAM_AUTH_ERR; /* They didn't seem to enter the right password + for three tries - error */ + pam_set_item(pamh, PAM_OLDAUTHTOK, (void *)curpass); + } else { +#ifdef DEBUG + fprintf(stderr,"I am ROOT!\n"); +#endif + pflags = _do_getpass(usrname,&curpass); + if(curpass == NULL) + curpass = x_strdup(""); + } + if(pflags & PPW_TOOEARLY) { + conv_sendmsg(appconv,"You must wait longer to change your password", + PAM_ERROR_MSG); + return PAM_AUTHTOK_ERR; + } + if(pflags & PPW_WILLEXPIRE) + conv_sendmsg(appconv,"Your password is about to expire",PAM_TEXT_INFO); + else if(pflags & PPW_EXPIRED) + return PAM_ACCT_EXPIRED; /* If their account has expired, we can't auth + them to change their password */ + if(!(pflags & PPW_EXPIRING) && (flags & PAM_CHANGE_EXPIRED_AUTHTOK)) + return PAM_SUCCESS; + /* If we haven't been given a password yet, prompt for one... */ + miscint=0; + pam_get_item(pamh,PAM_AUTHTOK,(const void **)&newpass); + cmiscptr = NULL; + while((newpass == NULL) && (miscint++ < MAX_PASSWD_TRIES)) { + + /* Get the password from the user... */ + pmsg = &msg; + + msg.msg_style = PAM_PROMPT_ECHO_OFF; + msg.msg = NEW_PASSWORD_PROMPT; + resp = NULL; + + retval = appconv->conv(1, (const struct pam_message **) &pmsg, + &resp, appconv->appdata_ptr); + + PAM_FAIL_CHECK; + newpass = resp->resp; + free (resp); + +#ifdef DEBUG + if(newpass) + fprintf(stderr,"Got password of %s\n",newpass); + else + fprintf(stderr,"No new password...\n"); +#endif + if (newpass[0] == '\0') { free (newpass); newpass = (char *) 0; } + cmiscptr=NULL; + if(newpass) { +#ifdef USE_CRACKLIB + if(fascist && getuid()) + cmiscptr = FascistCheck(newpass,CRACKLIB_DICTS); +#else + if(fascist && getuid() && strlen(newpass) < 6) + cmiscptr = "You must choose a longer password"; +#endif + if(curpass) + if(!strcmp(curpass,newpass)) { + cmiscptr="You must choose a new password."; + newpass=NULL; + } + } else { + /* We want to abort the password change */ + conv_sendmsg(appconv,"Password change aborted",PAM_ERROR_MSG); + return PAM_AUTHTOK_ERR; + } + if(!cmiscptr) { + /* We ask them to enter their password again... */ + /* Get the password from the user... */ + pmsg = &msg; + + msg.msg_style = PAM_PROMPT_ECHO_OFF; + msg.msg = AGAIN_PASSWORD_PROMPT; + resp = NULL; + + retval = appconv->conv(1, (const struct pam_message **) &pmsg, + &resp, appconv->appdata_ptr); + + PAM_FAIL_CHECK; + miscptr = resp->resp; + free (resp); + if (miscptr[0] == '\0') { free (miscptr); miscptr = (char *) 0; } + if(!miscptr) { /* Aborting password change... */ + conv_sendmsg(appconv,"Password change aborted",PAM_ERROR_MSG); + return PAM_AUTHTOK_ERR; + } + if(!strcmp(newpass,miscptr)) { + miscptr=NULL; + break; + } + conv_sendmsg(appconv,"You must enter the same password twice.", + PAM_ERROR_MSG); + miscptr=NULL; + newpass=NULL; + } + else { + conv_sendmsg(appconv,cmiscptr,PAM_ERROR_MSG); + newpass = NULL; + } + } + if(cmiscptr) { + /* conv_sendmsg(appconv,cmiscptr,PAM_ERROR_MSG); */ + return PAM_AUTHTOK_ERR; + } else if(newpass == NULL) + return PAM_AUTHTOK_ERR; /* They didn't seem to enter the right password + for three tries - error */ +#ifdef DEBUG + printf("Changing password for sure!\n"); +#endif + /* From now on, we are bound and determined to get their password + changed :-) */ + pam_set_item(pamh, PAM_AUTHTOK, (void *)newpass); + retval = _do_setpass(usrname,newpass,pflags); +#ifdef DEBUG + fprintf(stderr,"retval was %d\n",retval); +#endif + if(retval & ~PPW_SHADOW) { + conv_sendmsg(appconv,"Error: Password NOT changed",PAM_ERROR_MSG); + return PAM_AUTHTOK_ERR; + } else { + conv_sendmsg(appconv,"Password changed",PAM_TEXT_INFO); + return PAM_SUCCESS; + } +} + +/* _do_checkpass() returns 0 on success, non-0 on failure */ +STATIC int _do_checkpass(const char *entered, char *listed) +{ + char salt[3]; + if ((strlen(listed) == 0) &&(strlen(entered) == 0)) { + /* no password in database; no password entered */ + return (0); + } + salt[0]=listed[0]; salt[1]=listed[1]; salt[2]='\0'; + return strcmp(crypt(entered,salt),listed); +} + +STATIC char mksalt(int seed) { + int num = seed % 64; + + if (num < 26) + return 'a' + num; + else if (num < 52) + return 'A' + (num - 26); + else if (num < 62) + return '0' + (num - 52); + else if (num == 63) + return '.'; + else + return '/'; +} + +STATIC int _do_setpass(char *forwho, char *towhat,int flags) +{ + struct passwd *pwd=NULL, *tmpent=NULL; + FILE *pwfile,*opwfile; + char thesalt[3]; + int retval=0; + struct timeval time1; + int err = 0; +#ifdef HAVE_SHADOW_H + struct spwd *spwdent=NULL, *stmpent=NULL; +#endif + if(flags & PPW_SHADOW) { retval |= PPW_SHADOW; } + gettimeofday(&time1, NULL); + srand(time1.tv_usec); + thesalt[0]=mksalt(rand()); + thesalt[1]=mksalt(rand()); + thesalt[2]='\0'; + + /* lock the entire password subsystem */ +#ifdef USE_LCKPWDF + lckpwdf(); +#endif + setpwent(); + pwd = getpwnam(forwho); +#ifdef DEBUG + printf("Got %p, for %s (salt %s)\n",pwd, + forwho,thesalt); +#endif + if(pwd == NULL) + return PPW_NOSUCHUSER; + endpwent(); + +#ifdef HAVE_SHADOW_H + if(flags & PPW_SHADOW) { + spwdent = getspnam(forwho); + if(spwdent == NULL) + return PPW_NOSUCHUSER; + spwdent->sp_pwdp = towhat; + spwdent->sp_lstchg = time(NULL)/(60*60*24); + pwfile = fopen(SH_TMPFILE,"w"); + opwfile = fopen("/etc/shadow","r"); + if(pwfile == NULL || opwfile == NULL) + return PPW_ERROR; + chown(SH_TMPFILE,0,0); + chmod(SH_TMPFILE,0600); + stmpent=fgetspent(opwfile); + while(stmpent) { + if(!strcmp(stmpent->sp_namp,forwho)) { + stmpent->sp_pwdp = crypt(towhat,thesalt); + stmpent->sp_lstchg = time(NULL)/(60*60*24); +#ifdef DEBUG + fprintf(stderr,"Set password %s for %s\n",stmpent->sp_pwdp, + forwho); +#endif + } + if (putspent(stmpent,pwfile)) { + fprintf(stderr, "error writing entry to shadow file: %s\n", + strerror(errno)); + err = 1; + retval = PPW_ERROR; + break; + } + stmpent=fgetspent(opwfile); + } + fclose(opwfile); + + if (fclose(pwfile)) { + fprintf(stderr, "error writing entries to shadow file: %s\n", + strerror(errno)); + retval = PPW_ERROR; + err = 1; + } + + if (!err) + rename(SH_TMPFILE,"/etc/shadow"); + else + unlink(SH_TMPFILE); + } else { + pwd->pw_passwd = towhat; + pwfile = fopen(PW_TMPFILE,"w"); + opwfile = fopen("/etc/passwd","r"); + if(pwfile == NULL || opwfile == NULL) + return PPW_ERROR; + chown(PW_TMPFILE,0,0); + chmod(PW_TMPFILE,0644); + tmpent=fgetpwent(opwfile); + while(tmpent) { + if(!strcmp(tmpent->pw_name,forwho)) { + tmpent->pw_passwd = crypt(towhat,thesalt); + } + if (putpwent(tmpent,pwfile)) { + fprintf(stderr, "error writing entry to password file: %s\n", + strerror(errno)); + err = 1; + retval = PPW_ERROR; + break; + } + tmpent=fgetpwent(opwfile); + } + fclose(opwfile); + + if (fclose(pwfile)) { + fprintf(stderr, "error writing entries to password file: %s\n", + strerror(errno)); + retval = PPW_ERROR; + err = 1; + } + + if (!err) + rename(PW_TMPFILE,"/etc/passwd"); + else + unlink(PW_TMPFILE); + } +#else + pwd->pw_passwd = towhat; + pwfile = fopen(PW_TMPFILE,"w"); + opwfile = fopen("/etc/passwd","r"); + if(pwfile == NULL || opwfile == NULL) + return PPW_ERROR; + chown(PW_TMPFILE,0,0); + chmod(PW_TMPFILE,0644); + tmpent=fgetpwent(opwfile); + while(tmpent) { + if(!strcmp(tmpent->pw_name,forwho)) { + tmpent->pw_passwd = crypt(towhat,thesalt); + } + if (putpwent(tmpent,pwfile)) { + fprintf(stderr, "error writing entry to shadow file: %s\n", + strerror(errno)); + err = 1; + retval = PPW_ERROR; + break; + } + tmpent=fgetpwent(opwfile); + } + fclose(opwfile); + + if (fclose(pwfile)) { + fprintf(stderr, "error writing entries to password file: %s\n", + strerror(errno)); + retval = PPW_ERROR; + err = 1; + } + + if (!err) + rename(PW_TMPFILE,"/etc/passwd"); + else + unlink(PW_TMPFILE); +#endif + /* unlock the entire password subsystem */ +#ifdef USE_LCKPWDF + ulckpwdf(); +#endif + return retval; +} + +STATIC int _do_getpass(char *forwho, char **theirpass) +{ + struct passwd *pwd=NULL; /* Password and shadow password */ +#ifdef HAVE_SHADOW_H + struct spwd *spwdent=NULL; /* file entries for the user */ + time_t curdays; +#endif + int retval=0; + /* UNIX passwords area */ + setpwent(); + pwd = getpwnam(forwho); /* Get password file entry... */ + endpwent(); + if(pwd == NULL) + return PPW_NOSUCHUSER; /* We don't need to do the rest... */ +#ifdef HAVE_SHADOW_H + if(!strcmp(pwd->pw_passwd,"x")) { + /* ...and shadow password file entry for this user, if shadowing + is enabled */ + retval |= PPW_SHADOW; + setspent(); + spwdent = getspnam(forwho); + endspent(); + if(spwdent == NULL) + return PPW_NOSUCHUSER; + *theirpass = x_strdup(spwdent->sp_pwdp); + + /* We have the user's information, now let's check if their account + has expired (60 * 60 * 24 = number of seconds in a day) */ + + /* Get the current number of days since 1970 */ + curdays = time(NULL)/(60*60*24); + if((curdays < (spwdent->sp_lstchg + spwdent->sp_min)) + && (spwdent->sp_min != -1)) + retval |= PPW_TOOEARLY; + else if((curdays + > (spwdent->sp_lstchg + spwdent->sp_max + spwdent->sp_inact)) + && (spwdent->sp_max != -1) && (spwdent->sp_inact != -1)) + /* Their password change has been put off too long, + OR their account has just plain expired */ + retval |= PPW_EXPIRED; + else if((curdays > (spwdent->sp_lstchg + spwdent->sp_max)) + && (spwdent->sp_max != -1)) + /* Their passwd needs to be changed */ + retval |= PPW_EXPIRING; + else if((curdays > (spwdent->sp_lstchg + + spwdent->sp_max - spwdent->sp_warn)) + && (spwdent->sp_max != -1) && (spwdent->sp_warn != -1)) + retval |= PPW_WILLEXPIRE; +/* if(spwdent->sp_lstchg < 0) + retval &= ~(PPW_WILLEXPIRE | PPW_EXPIRING | PPW_EXPIRED); + if(spwdent->sp_max < 0) + retval &= ~(PPW_EXPIRING | PPW_EXPIRED); */ + } else { + *theirpass = (char *)x_strdup(pwd->pw_passwd); + } + +#else + *theirpass = (char *) x_strdup(pwd->pw_passwd); +#endif + + return retval; +} + +STATIC int conv_sendmsg(struct pam_conv *aconv, const char *message, int style) +{ + struct pam_message msg,*pmsg; + struct pam_response *resp; + int retval; + + /* Get the password from the user... */ + pmsg = &msg; + + msg.msg_style = style; + msg.msg = message; + resp = NULL; + + retval = aconv->conv(1, (const struct pam_message **) &pmsg, + &resp, aconv->appdata_ptr); + if (resp) { + _pam_drop_reply(resp, 1); + } + return retval; +} + + +STATIC int conv_getitem(struct pam_conv *aconv, char *message, int style, + char **result) +{ + struct pam_message msg,*pmsg; + struct pam_response *resp; + int retval; + + D(("called.")); + + /* Get the password from the user... */ + pmsg = &msg; + msg.msg_style = style; + msg.msg = message; + resp = NULL; + + retval = aconv->conv(1, (const struct pam_message **) &pmsg, + &resp, aconv->appdata_ptr); + if(retval != PAM_SUCCESS) + return retval; + if(resp != NULL) { + *result = resp->resp; free(resp); + return PAM_SUCCESS; + } + else + return PAM_SERVICE_ERR; +} |