Home | History | Annotate | Line # | Download | only in libskey
skeylogin.c revision 1.4
      1  1.1  deraadt /* S/KEY v1.1b (skeylogin.c)
      2  1.1  deraadt  *
      3  1.1  deraadt  * Authors:
      4  1.1  deraadt  *          Neil M. Haller <nmh (at) thumper.bellcore.com>
      5  1.1  deraadt  *          Philip R. Karn <karn (at) chicago.qualcomm.com>
      6  1.1  deraadt  *          John S. Walden <jsw (at) thumper.bellcore.com>
      7  1.1  deraadt  *          Scott Chasin <chasin (at) crimelab.com>
      8  1.1  deraadt  *
      9  1.1  deraadt  * S/KEY verification check, lookups, and authentication.
     10  1.1  deraadt  *
     11  1.4      cgd  * $Id: skeylogin.c,v 1.4 1995/05/17 20:24:39 cgd Exp $
     12  1.1  deraadt  */
     13  1.1  deraadt 
     14  1.1  deraadt #include <sys/param.h>
     15  1.1  deraadt #ifdef	QUOTA
     16  1.1  deraadt #include <sys/quota.h>
     17  1.1  deraadt #endif
     18  1.1  deraadt #include <sys/stat.h>
     19  1.1  deraadt #include <sys/time.h>
     20  1.1  deraadt #include <sys/timeb.h>
     21  1.1  deraadt #include <sys/resource.h>
     22  1.1  deraadt 
     23  1.1  deraadt 
     24  1.1  deraadt #include <stdio.h>
     25  1.1  deraadt #include <string.h>
     26  1.1  deraadt #include <sys/types.h>
     27  1.1  deraadt #include <sys/stat.h>
     28  1.1  deraadt #include <time.h>
     29  1.1  deraadt #include <errno.h>
     30  1.1  deraadt #include "skey.h"
     31  1.1  deraadt 
     32  1.1  deraadt #define	KEYFILE	"/etc/skeykeys"
     33  1.1  deraadt 
     34  1.1  deraadt char *skipspace();
     35  1.1  deraadt int skeylookup __ARGS((struct skey *mp,char *name));
     36  1.1  deraadt 
     37  1.1  deraadt 
     38  1.1  deraadt /* Issue a skey challenge for user 'name'. If successful,
     39  1.1  deraadt  * fill in the caller's skey structure and return 0. If unsuccessful
     40  1.1  deraadt  * (e.g., if name is unknown) return -1.
     41  1.1  deraadt  *
     42  1.1  deraadt  * The file read/write pointer is left at the start of the
     43  1.1  deraadt  * record.
     44  1.1  deraadt  */
     45  1.1  deraadt int
     46  1.1  deraadt getskeyprompt(mp,name,prompt)
     47  1.1  deraadt struct skey *mp;
     48  1.1  deraadt char *name;
     49  1.1  deraadt char *prompt;
     50  1.1  deraadt {
     51  1.1  deraadt 	int rval;
     52  1.1  deraadt 
     53  1.1  deraadt 	sevenbit(name);
     54  1.1  deraadt 	rval = skeylookup(mp,name);
     55  1.1  deraadt 	strcpy(prompt,"s/key 55 latour1\n");
     56  1.1  deraadt 	switch(rval){
     57  1.1  deraadt 	case -1:	/* File error */
     58  1.1  deraadt 		return -1;
     59  1.1  deraadt 	case 0:		/* Lookup succeeded, return challenge */
     60  1.1  deraadt 		sprintf(prompt,"s/key %d %s\n",mp->n - 1,mp->seed);
     61  1.1  deraadt 		return 0;
     62  1.1  deraadt 	case 1:		/* User not found */
     63  1.1  deraadt 		fclose(mp->keyfile);
     64  1.1  deraadt 		return -1;
     65  1.1  deraadt 	}
     66  1.1  deraadt 	return -1;	/* Can't happen */
     67  1.1  deraadt }
     68  1.1  deraadt /* Return  a skey challenge string for user 'name'. If successful,
     69  1.1  deraadt  * fill in the caller's skey structure and return 0. If unsuccessful
     70  1.1  deraadt  * (e.g., if name is unknown) return -1.
     71  1.1  deraadt  *
     72  1.1  deraadt  * The file read/write pointer is left at the start of the
     73  1.1  deraadt  * record.
     74  1.1  deraadt  */
     75  1.1  deraadt int
     76  1.1  deraadt skeychallenge(mp,name, ss)
     77  1.1  deraadt struct skey *mp;
     78  1.1  deraadt char *name;
     79  1.1  deraadt char *ss;
     80  1.1  deraadt {
     81  1.1  deraadt 	int rval;
     82  1.1  deraadt 
     83  1.1  deraadt 	rval = skeylookup(mp,name);
     84  1.1  deraadt 	switch(rval){
     85  1.1  deraadt 	case -1:	/* File error */
     86  1.1  deraadt 		return -1;
     87  1.1  deraadt 	case 0:		/* Lookup succeeded, issue challenge */
     88  1.1  deraadt                 sprintf(ss, "s/key %d %s",mp->n - 1,mp->seed);
     89  1.1  deraadt 		return 0;
     90  1.1  deraadt 	case 1:		/* User not found */
     91  1.1  deraadt 		fclose(mp->keyfile);
     92  1.1  deraadt 		return -1;
     93  1.1  deraadt 	}
     94  1.1  deraadt 	return -1;	/* Can't happen */
     95  1.1  deraadt }
     96  1.1  deraadt 
     97  1.1  deraadt /* Find an entry in the One-time Password database.
     98  1.1  deraadt  * Return codes:
     99  1.1  deraadt  * -1: error in opening database
    100  1.1  deraadt  *  0: entry found, file R/W pointer positioned at beginning of record
    101  1.1  deraadt  *  1: entry not found, file R/W pointer positioned at EOF
    102  1.1  deraadt  */
    103  1.1  deraadt int
    104  1.1  deraadt skeylookup(mp,name)
    105  1.1  deraadt struct skey *mp;
    106  1.1  deraadt char *name;
    107  1.1  deraadt {
    108  1.1  deraadt 	int found;
    109  1.1  deraadt 	int len;
    110  1.1  deraadt 	long recstart;
    111  1.1  deraadt 	char *cp;
    112  1.1  deraadt 	struct stat statbuf;
    113  1.1  deraadt 
    114  1.1  deraadt 	/* See if the KEYFILE exists, and create it if not */
    115  1.2  deraadt 
    116  1.2  deraadt 	if(stat(KEYFILE,&statbuf) == -1 && errno == ENOENT) {
    117  1.1  deraadt 		mp->keyfile = fopen(KEYFILE,"w+");
    118  1.2  deraadt 		if(mp->keyfile)
    119  1.3  deraadt 			chmod(KEYFILE, 0644);
    120  1.1  deraadt 	} else {
    121  1.1  deraadt 		/* Otherwise open normally for update */
    122  1.1  deraadt 		mp->keyfile = fopen(KEYFILE,"r+");
    123  1.1  deraadt 	}
    124  1.1  deraadt 	if(mp->keyfile == NULL)
    125  1.1  deraadt 		return -1;
    126  1.1  deraadt 
    127  1.1  deraadt 	/* Look up user name in database */
    128  1.1  deraadt 	len = strlen(name);
    129  1.1  deraadt 	if( len > 8 ) len = 8;		/*  Added 8/2/91  -  nmh */
    130  1.1  deraadt 	found = 0;
    131  1.1  deraadt 	while(!feof(mp->keyfile)){
    132  1.1  deraadt 		recstart = ftell(mp->keyfile);
    133  1.1  deraadt 		mp->recstart = recstart;
    134  1.1  deraadt 		if(fgets(mp->buf,sizeof(mp->buf),mp->keyfile) != mp->buf){
    135  1.1  deraadt 			break;
    136  1.1  deraadt 		}
    137  1.1  deraadt 		rip(mp->buf);
    138  1.1  deraadt 		if(mp->buf[0] == '#')
    139  1.1  deraadt 			continue;	/* Comment */
    140  1.1  deraadt 		if((mp->logname = strtok(mp->buf," \t")) == NULL)
    141  1.1  deraadt 			continue;
    142  1.1  deraadt 		if((cp = strtok(NULL," \t")) == NULL)
    143  1.1  deraadt 			continue;
    144  1.1  deraadt 		mp->n = atoi(cp);
    145  1.1  deraadt 		if((mp->seed = strtok(NULL," \t")) == NULL)
    146  1.1  deraadt 			continue;
    147  1.1  deraadt 		if((mp->val = strtok(NULL," \t")) == NULL)
    148  1.1  deraadt 			continue;
    149  1.1  deraadt 		if(strlen(mp->logname) == len
    150  1.1  deraadt 		 && strncmp(mp->logname,name,len) == 0){
    151  1.1  deraadt 			found = 1;
    152  1.1  deraadt 			break;
    153  1.1  deraadt 		}
    154  1.1  deraadt 	}
    155  1.1  deraadt 	if(found){
    156  1.1  deraadt 		fseek(mp->keyfile,recstart,0);
    157  1.1  deraadt 		return 0;
    158  1.1  deraadt 	} else
    159  1.1  deraadt 		return 1;
    160  1.1  deraadt }
    161  1.1  deraadt /* Verify response to a s/key challenge.
    162  1.1  deraadt  *
    163  1.1  deraadt  * Return codes:
    164  1.1  deraadt  * -1: Error of some sort; database unchanged
    165  1.1  deraadt  *  0:  Verify successful, database updated
    166  1.1  deraadt  *  1:  Verify failed, database unchanged
    167  1.1  deraadt  *
    168  1.1  deraadt  * The database file is always closed by this call.
    169  1.1  deraadt  */
    170  1.1  deraadt int
    171  1.1  deraadt skeyverify(mp,response)
    172  1.1  deraadt struct skey *mp;
    173  1.1  deraadt char *response;
    174  1.1  deraadt {
    175  1.1  deraadt  struct timeval startval;
    176  1.1  deraadt  struct timeval endval;
    177  1.1  deraadt long microsec;
    178  1.1  deraadt 	char key[8];
    179  1.1  deraadt 	char fkey[8];
    180  1.1  deraadt 	char filekey[8];
    181  1.1  deraadt 	time_t now;
    182  1.1  deraadt 	struct tm *tm;
    183  1.1  deraadt 	char tbuf[27],buf[60];
    184  1.1  deraadt 	char me[80];
    185  1.1  deraadt 	int rval;
    186  1.1  deraadt 	char *cp;
    187  1.1  deraadt 
    188  1.1  deraadt 	time(&now);
    189  1.1  deraadt 	tm = localtime(&now);
    190  1.1  deraadt 	strftime(tbuf, sizeof(tbuf), " %b %d,%Y %T", tm);
    191  1.1  deraadt 
    192  1.1  deraadt 	if(response == NULL){
    193  1.1  deraadt 		fclose(mp->keyfile);
    194  1.1  deraadt 		return -1;
    195  1.1  deraadt 	}
    196  1.1  deraadt 	rip (response);
    197  1.1  deraadt 
    198  1.1  deraadt 	/* Convert response to binary */
    199  1.1  deraadt 	if(etob(key, response) != 1 && atob8(key, response) != 0){
    200  1.1  deraadt 		/* Neither english words or ascii hex */
    201  1.1  deraadt 		fclose(mp->keyfile);
    202  1.1  deraadt 		return -1;
    203  1.1  deraadt 	}
    204  1.1  deraadt 
    205  1.1  deraadt 	/* Compute fkey = f(key) */
    206  1.1  deraadt 	memcpy(fkey,key,sizeof(key));
    207  1.1  deraadt         fflush (stdout);
    208  1.1  deraadt 
    209  1.1  deraadt 	f(fkey);
    210  1.1  deraadt 	/* in order to make the window of update as short as possible
    211  1.1  deraadt            we must do the comparison here and if OK write it back
    212  1.1  deraadt            other wise the same password can be used twice to get in
    213  1.1  deraadt   	   to the system
    214  1.1  deraadt 	*/
    215  1.1  deraadt 
    216  1.1  deraadt 	setpriority(PRIO_PROCESS, 0, -4);
    217  1.1  deraadt 
    218  1.1  deraadt 	/* reread the file record NOW*/
    219  1.1  deraadt 
    220  1.1  deraadt 	fseek(mp->keyfile,mp->recstart,0);
    221  1.1  deraadt 	if(fgets(mp->buf,sizeof(mp->buf),mp->keyfile) != mp->buf){
    222  1.1  deraadt 		setpriority(PRIO_PROCESS, 0, 0);
    223  1.1  deraadt 		fclose(mp->keyfile);
    224  1.1  deraadt 		return -1;
    225  1.1  deraadt 	}
    226  1.1  deraadt 	rip(mp->buf);
    227  1.1  deraadt 	mp->logname = strtok(mp->buf," \t");
    228  1.1  deraadt 	cp = strtok(NULL," \t") ;
    229  1.1  deraadt 	mp->seed = strtok(NULL," \t");
    230  1.1  deraadt 	mp->val = strtok(NULL," \t");
    231  1.1  deraadt 	/* And convert file value to hex for comparison */
    232  1.1  deraadt 	atob8(filekey,mp->val);
    233  1.1  deraadt 
    234  1.1  deraadt 	/* Do actual comparison */
    235  1.1  deraadt         fflush (stdout);
    236  1.1  deraadt 
    237  1.1  deraadt 	if(memcmp(filekey,fkey,8) != 0){
    238  1.1  deraadt 		/* Wrong response */
    239  1.1  deraadt 		setpriority(PRIO_PROCESS, 0, 0);
    240  1.1  deraadt 		fclose(mp->keyfile);
    241  1.1  deraadt 		return 1;
    242  1.1  deraadt 	}
    243  1.1  deraadt 
    244  1.1  deraadt 	/* Update key in database by overwriting entire record. Note
    245  1.1  deraadt 	 * that we must write exactly the same number of bytes as in
    246  1.1  deraadt 	 * the original record (note fixed width field for N)
    247  1.1  deraadt 	 */
    248  1.1  deraadt 	btoa8(mp->val,key);
    249  1.1  deraadt 	mp->n--;
    250  1.1  deraadt 	fseek(mp->keyfile,mp->recstart,0);
    251  1.1  deraadt 	fprintf(mp->keyfile,"%s %04d %-16s %s %-21s\n",mp->logname,mp->n,mp->seed,
    252  1.1  deraadt 	 mp->val, tbuf);
    253  1.1  deraadt 
    254  1.1  deraadt 	fclose(mp->keyfile);
    255  1.1  deraadt 
    256  1.1  deraadt 	setpriority(PRIO_PROCESS, 0, 0);
    257  1.1  deraadt 	return 0;
    258  1.1  deraadt }
    259  1.1  deraadt 
    260  1.1  deraadt 
    261  1.1  deraadt /* Convert 8-byte hex-ascii string to binary array
    262  1.1  deraadt  * Returns 0 on success, -1 on error
    263  1.1  deraadt  */
    264  1.1  deraadt atob8(out,in)
    265  1.1  deraadt register char *out,*in;
    266  1.1  deraadt {
    267  1.1  deraadt 	register int i;
    268  1.1  deraadt 	register int val;
    269  1.1  deraadt 
    270  1.1  deraadt 	if (in == NULL || out == NULL)
    271  1.1  deraadt 		return -1;
    272  1.1  deraadt 
    273  1.1  deraadt 	for(i=0;i<8;i++){
    274  1.1  deraadt 		if((in = skipspace(in)) == NULL)
    275  1.1  deraadt 			return -1;
    276  1.1  deraadt 		if((val = htoi(*in++)) == -1)
    277  1.1  deraadt 			return -1;
    278  1.1  deraadt 		*out = val << 4;
    279  1.1  deraadt 
    280  1.1  deraadt 		if((in = skipspace(in)) == NULL)
    281  1.1  deraadt 			return -1;
    282  1.1  deraadt 		if((val = htoi(*in++)) == -1)
    283  1.1  deraadt 			return -1;
    284  1.1  deraadt 		*out++ |= val;
    285  1.1  deraadt 	}
    286  1.1  deraadt 	return 0;
    287  1.1  deraadt }
    288  1.1  deraadt 
    289  1.1  deraadt char *
    290  1.1  deraadt skipspace(cp)
    291  1.1  deraadt register char *cp;
    292  1.1  deraadt {
    293  1.1  deraadt 	while(*cp == ' ' || *cp == '\t')
    294  1.1  deraadt 		cp++;
    295  1.1  deraadt 
    296  1.1  deraadt 	if(*cp == '\0')
    297  1.1  deraadt 		return NULL;
    298  1.1  deraadt 	else
    299  1.1  deraadt 		return cp;
    300  1.1  deraadt }
    301  1.1  deraadt 
    302  1.1  deraadt /* Convert 8-byte binary array to hex-ascii string */
    303  1.1  deraadt int
    304  1.1  deraadt btoa8(out,in)
    305  1.1  deraadt register char *out,*in;
    306  1.1  deraadt {
    307  1.1  deraadt 	register int i;
    308  1.1  deraadt 
    309  1.1  deraadt 	if(in == NULL || out == NULL)
    310  1.1  deraadt 		return -1;
    311  1.1  deraadt 
    312  1.1  deraadt 	for(i=0;i<8;i++){
    313  1.1  deraadt 		sprintf(out,"%02x",*in++ & 0xff);
    314  1.1  deraadt 		out += 2;
    315  1.1  deraadt 	}
    316  1.1  deraadt 	return 0;
    317  1.1  deraadt }
    318  1.1  deraadt 
    319  1.1  deraadt 
    320  1.1  deraadt /* Convert hex digit to binary integer */
    321  1.1  deraadt int
    322  1.1  deraadt htoi(c)
    323  1.1  deraadt register char c;
    324  1.1  deraadt {
    325  1.1  deraadt 	if('0' <= c && c <= '9')
    326  1.1  deraadt 		return c - '0';
    327  1.1  deraadt 	if('a' <= c && c <= 'f')
    328  1.1  deraadt 		return 10 + c - 'a';
    329  1.1  deraadt 	if('A' <= c && c <= 'F')
    330  1.1  deraadt 		return 10 + c - 'A';
    331  1.1  deraadt 	return -1;
    332  1.1  deraadt }
    333  1.1  deraadt 
    334  1.1  deraadt /*
    335  1.1  deraadt  * skey_haskey ()
    336  1.1  deraadt  *
    337  1.1  deraadt  * Returns: 1 user doesnt exist, -1 fle error, 0 user exists.
    338  1.1  deraadt  *
    339  1.1  deraadt  */
    340  1.1  deraadt 
    341  1.1  deraadt skey_haskey (username)
    342  1.1  deraadt   char *username;
    343  1.1  deraadt {
    344  1.1  deraadt   int i;
    345  1.1  deraadt   struct skey skey;
    346  1.1  deraadt 
    347  1.1  deraadt   return (skeylookup (&skey, username));
    348  1.1  deraadt }
    349  1.1  deraadt 
    350  1.1  deraadt /*
    351  1.1  deraadt  * skey_keyinfo ()
    352  1.1  deraadt  *
    353  1.1  deraadt  * Returns the current sequence number and
    354  1.1  deraadt  * seed for the passed user.
    355  1.1  deraadt  *
    356  1.1  deraadt  */
    357  1.1  deraadt char *skey_keyinfo (username)
    358  1.1  deraadt   char *username;
    359  1.1  deraadt {
    360  1.1  deraadt   int i;
    361  1.1  deraadt   static char str [50];
    362  1.1  deraadt 
    363  1.1  deraadt   struct skey skey;
    364  1.1  deraadt 
    365  1.1  deraadt   i = skeychallenge (&skey, username, str);
    366  1.1  deraadt   if (i == -1)
    367  1.1  deraadt      return 0;
    368  1.1  deraadt 
    369  1.1  deraadt   return str;
    370  1.1  deraadt }
    371  1.1  deraadt 
    372  1.1  deraadt /*
    373  1.1  deraadt  * skey_passcheck ()
    374  1.1  deraadt  *
    375  1.1  deraadt  * Check to see if answer is the correct one to the current
    376  1.1  deraadt  * challenge.
    377  1.1  deraadt  *
    378  1.1  deraadt  * Returns: 0 success, -1 failure
    379  1.1  deraadt  *
    380  1.1  deraadt  */
    381  1.1  deraadt 
    382  1.1  deraadt skey_passcheck (username, passwd)
    383  1.1  deraadt   char *username, *passwd;
    384  1.1  deraadt {
    385  1.1  deraadt   int i;
    386  1.1  deraadt   struct skey skey;
    387  1.1  deraadt 
    388  1.1  deraadt   i = skeylookup (&skey, username);
    389  1.1  deraadt 
    390  1.1  deraadt   if (i == -1 || i == 1)
    391  1.1  deraadt       return -1;
    392  1.1  deraadt 
    393  1.1  deraadt   if (skeyverify (&skey, passwd) == 0)
    394  1.1  deraadt       return skey.n;
    395  1.1  deraadt 
    396  1.1  deraadt   return -1;
    397  1.1  deraadt }
    398  1.1  deraadt 
    399  1.1  deraadt /*
    400  1.1  deraadt  * skey_authenticate ()
    401  1.1  deraadt  *
    402  1.1  deraadt  * Used when calling program will allow input of the user's
    403  1.1  deraadt  * response to the challenge.
    404  1.1  deraadt  *
    405  1.1  deraadt  * Returns: 0 success, -1 failure
    406  1.1  deraadt  *
    407  1.1  deraadt  */
    408  1.1  deraadt 
    409  1.1  deraadt skey_authenticate (username)
    410  1.1  deraadt   char *username;
    411  1.1  deraadt {
    412  1.1  deraadt   int i;
    413  1.1  deraadt   char pbuf [256], skeyprompt [50];
    414  1.1  deraadt   struct skey skey;
    415  1.1  deraadt 
    416  1.1  deraadt   /* Attempt a S/Key challenge */
    417  1.1  deraadt   i = skeychallenge (&skey, username, skeyprompt);
    418  1.1  deraadt 
    419  1.1  deraadt   if (i == -2)
    420  1.1  deraadt     return 0;
    421  1.1  deraadt 
    422  1.1  deraadt   printf ("[%s]\n", skeyprompt);
    423  1.1  deraadt   fflush (stdout);
    424  1.1  deraadt 
    425  1.1  deraadt   printf ("Response: ");
    426  1.4      cgd   readskey (pbuf, sizeof (pbuf));
    427  1.1  deraadt   rip (pbuf);
    428  1.1  deraadt 
    429  1.1  deraadt   /* Is it a valid response? */
    430  1.1  deraadt   if (i == 0 && skeyverify (&skey, pbuf) == 0)
    431  1.1  deraadt   {
    432  1.1  deraadt     if (skey.n < 5)
    433  1.1  deraadt     {
    434  1.1  deraadt       printf ("\nWarning! Key initialization needed soon.  ");
    435  1.1  deraadt       printf ("(%d logins left)\n", skey.n);
    436  1.1  deraadt     }
    437  1.1  deraadt     return 0;
    438  1.1  deraadt   }
    439  1.1  deraadt   return -1;
    440  1.1  deraadt }
    441  1.1  deraadt 
    442