1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
|
/*
* validate.c
*
* Validate a username/pw combination, using the /etc/shadow
* file.
*
* Two lines are read from stdin. The first is the user, and
* the second is the (unencrypted) password.
*
* We exit with 0 if they match, 1 otherwise.
* Errors are written to either stderr or the error log, or both.
*/
#include <stdio.h>
#include <shadow.h>
#include <string.h>
#include <time.h>
#include "validate.h"
#ifdef LOG_FAILED_ATTEMPTS
#include <sys/syslog.h>
#include <sys/sysmacros.h>
#endif
/* USE_XOPEN makes crypt available from unistd.h. */
#define __USE_XOPEN
#include <unistd.h>
static void stripreturn(char *str)
{
if (strlen(str)==0)
return;
str[(strlen(str)-1)] = '\0';
return;
}
int
main(int argc, char **argv)
{
FILE* fp;
FILE* fptemp;
struct spwd *ret = NULL;
char user[MAX_USERNAME_LENGTH+2];
char pw[MAX_PW_LENGTH+2];
char *cryptpw;
char *progname;
long int secs, days;
progname = argv[0];
if (argc!=1)
exit(1);
/* Read user,pw from fd */
fp = stdin;
fgets(user, MAX_USERNAME_LENGTH, fp);
fgets(pw, MAX_PW_LENGTH, fp);
/* Strip carriage return */
stripreturn(user);
stripreturn(pw);
ret = getspnam(user);
#ifdef LOG_FAILED_ATTEMPTS
openlog("mod_auth_shadow", LOG_ODELAY, LOG_AUTHPRIV);
#endif
if (!ret) {
/* Did the user not exist? Or can we not read /etc/shadow?
* Print a helpful message if the latter...
*/
fptemp = fopen("/etc/shadow","r");
if (!fptemp) {
fprintf(stderr,
"%s: No read access to /etc/shadow. This program must be suid or sgid.\n",
progname);
exit(1);
}
fclose(fptemp);
fprintf(stderr,"%s: Couldn't find user '%s'\n",progname, user);
#ifdef LOG_FAILED_ATTEMPTS
syslog(LOG_ERR,"FAILED VALIDATE: unknown user: %s",user);
#endif
if ( (SLEEP_SECONDS>0) && (sleep(SLEEP_SECONDS)!=0))
fprintf(stderr,"%s: Error sleeping for %d seconds.\n", progname,SLEEP_SECONDS);
exit(1);
}
cryptpw = crypt(pw,ret->sp_pwdp);
if (strcmp(cryptpw,ret->sp_pwdp)!=0){
#ifdef LOG_FAILED_ATTEMPTS
syslog(LOG_ERR,"VALIDATE: user: %s, Authentication failure",user);
#endif
if ( (SLEEP_SECONDS>0) && (sleep(SLEEP_SECONDS)!=0))
fprintf(stderr,"%s: Error sleeping for %d seconds.\n", progname,SLEEP_SECONDS);
fprintf(stderr,"%s: User %s: authentication failure\n",progname,user);
exit(1);
}
/*
* Check password expiration information. See shadow(5)
*/
secs = (long int) time(NULL);
days = secs / (24L * 60L * 60L);
/*
* An account is considered to be inactive and is disabled if the
* password is not changed within the specified number of days after the
* password expires.
*/
if ( ret->sp_max > 0
&& ret->sp_inact > 0
&& days > ret->sp_lstchg + ret->sp_max + ret->sp_inact) {
#ifdef LOG_FAILED_ATTEMPTS
syslog(LOG_ERR,"VALIDATE: user: %s, Account inactivity period expired",user);
#endif
if ( (SLEEP_SECONDS>0) && (sleep(SLEEP_SECONDS)!=0))
fprintf(stderr,"%s: Error sleeping for %d seconds.\n", progname,SLEEP_SECONDS);
fprintf(stderr,"%s: User %s: account inactivity period expired\n",progname,user);
exit(1);
}
/*
* An account will also be disabled on the specified day regardless of
* other password expiration information.
*/
if (ret->sp_expire > 0 && days > ret->sp_expire) {
#ifdef LOG_FAILED_ATTEMPTS
syslog(LOG_ERR,"VALIDATE: user: %s, Account expired",user);
#endif
if ( (SLEEP_SECONDS>0) && (sleep(SLEEP_SECONDS)!=0))
fprintf(stderr,"%s: Error sleeping for %d seconds.\n", progname,SLEEP_SECONDS);
fprintf(stderr,"%s: User %s: account expired\n",progname,user);
exit(1);
}
exit(0);
}
|