Home | History | Annotate | Line # | Download | only in libskey
skeylogin.c revision 1.1
      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.1  deraadt  * $Id: skeylogin.c,v 1.1 1994/05/21 05:46:16 deraadt 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.1  deraadt 	if(stat(KEYFILE,&statbuf) == -1 && errno == ENOENT){
    116  1.1  deraadt 		mp->keyfile = fopen(KEYFILE,"w+");
    117  1.1  deraadt 	} else {
    118  1.1  deraadt 		/* Otherwise open normally for update */
    119  1.1  deraadt 		mp->keyfile = fopen(KEYFILE,"r+");
    120  1.1  deraadt 	}
    121  1.1  deraadt 	if(mp->keyfile == NULL)
    122  1.1  deraadt 		return -1;
    123  1.1  deraadt 
    124  1.1  deraadt 	/* Look up user name in database */
    125  1.1  deraadt 	len = strlen(name);
    126  1.1  deraadt 	if( len > 8 ) len = 8;		/*  Added 8/2/91  -  nmh */
    127  1.1  deraadt 	found = 0;
    128  1.1  deraadt 	while(!feof(mp->keyfile)){
    129  1.1  deraadt 		recstart = ftell(mp->keyfile);
    130  1.1  deraadt 		mp->recstart = recstart;
    131  1.1  deraadt 		if(fgets(mp->buf,sizeof(mp->buf),mp->keyfile) != mp->buf){
    132  1.1  deraadt 			break;
    133  1.1  deraadt 		}
    134  1.1  deraadt 		rip(mp->buf);
    135  1.1  deraadt 		if(mp->buf[0] == '#')
    136  1.1  deraadt 			continue;	/* Comment */
    137  1.1  deraadt 		if((mp->logname = strtok(mp->buf," \t")) == NULL)
    138  1.1  deraadt 			continue;
    139  1.1  deraadt 		if((cp = strtok(NULL," \t")) == NULL)
    140  1.1  deraadt 			continue;
    141  1.1  deraadt 		mp->n = atoi(cp);
    142  1.1  deraadt 		if((mp->seed = strtok(NULL," \t")) == NULL)
    143  1.1  deraadt 			continue;
    144  1.1  deraadt 		if((mp->val = strtok(NULL," \t")) == NULL)
    145  1.1  deraadt 			continue;
    146  1.1  deraadt 		if(strlen(mp->logname) == len
    147  1.1  deraadt 		 && strncmp(mp->logname,name,len) == 0){
    148  1.1  deraadt 			found = 1;
    149  1.1  deraadt 			break;
    150  1.1  deraadt 		}
    151  1.1  deraadt 	}
    152  1.1  deraadt 	if(found){
    153  1.1  deraadt 		fseek(mp->keyfile,recstart,0);
    154  1.1  deraadt 		return 0;
    155  1.1  deraadt 	} else
    156  1.1  deraadt 		return 1;
    157  1.1  deraadt }
    158  1.1  deraadt /* Verify response to a s/key challenge.
    159  1.1  deraadt  *
    160  1.1  deraadt  * Return codes:
    161  1.1  deraadt  * -1: Error of some sort; database unchanged
    162  1.1  deraadt  *  0:  Verify successful, database updated
    163  1.1  deraadt  *  1:  Verify failed, database unchanged
    164  1.1  deraadt  *
    165  1.1  deraadt  * The database file is always closed by this call.
    166  1.1  deraadt  */
    167  1.1  deraadt int
    168  1.1  deraadt skeyverify(mp,response)
    169  1.1  deraadt struct skey *mp;
    170  1.1  deraadt char *response;
    171  1.1  deraadt {
    172  1.1  deraadt  struct timeval startval;
    173  1.1  deraadt  struct timeval endval;
    174  1.1  deraadt long microsec;
    175  1.1  deraadt 	char key[8];
    176  1.1  deraadt 	char fkey[8];
    177  1.1  deraadt 	char filekey[8];
    178  1.1  deraadt 	time_t now;
    179  1.1  deraadt 	struct tm *tm;
    180  1.1  deraadt 	char tbuf[27],buf[60];
    181  1.1  deraadt 	char me[80];
    182  1.1  deraadt 	int rval;
    183  1.1  deraadt 	char *cp;
    184  1.1  deraadt 
    185  1.1  deraadt 	time(&now);
    186  1.1  deraadt 	tm = localtime(&now);
    187  1.1  deraadt 	strftime(tbuf, sizeof(tbuf), " %b %d,%Y %T", tm);
    188  1.1  deraadt 
    189  1.1  deraadt 	if(response == NULL){
    190  1.1  deraadt 		fclose(mp->keyfile);
    191  1.1  deraadt 		return -1;
    192  1.1  deraadt 	}
    193  1.1  deraadt 	rip (response);
    194  1.1  deraadt 
    195  1.1  deraadt 	/* Convert response to binary */
    196  1.1  deraadt 	if(etob(key, response) != 1 && atob8(key, response) != 0){
    197  1.1  deraadt 		/* Neither english words or ascii hex */
    198  1.1  deraadt 		fclose(mp->keyfile);
    199  1.1  deraadt 		return -1;
    200  1.1  deraadt 	}
    201  1.1  deraadt 
    202  1.1  deraadt 	/* Compute fkey = f(key) */
    203  1.1  deraadt 	memcpy(fkey,key,sizeof(key));
    204  1.1  deraadt         fflush (stdout);
    205  1.1  deraadt 
    206  1.1  deraadt 	f(fkey);
    207  1.1  deraadt 	/* in order to make the window of update as short as possible
    208  1.1  deraadt            we must do the comparison here and if OK write it back
    209  1.1  deraadt            other wise the same password can be used twice to get in
    210  1.1  deraadt   	   to the system
    211  1.1  deraadt 	*/
    212  1.1  deraadt 
    213  1.1  deraadt 	setpriority(PRIO_PROCESS, 0, -4);
    214  1.1  deraadt 
    215  1.1  deraadt 	/* reread the file record NOW*/
    216  1.1  deraadt 
    217  1.1  deraadt 	fseek(mp->keyfile,mp->recstart,0);
    218  1.1  deraadt 	if(fgets(mp->buf,sizeof(mp->buf),mp->keyfile) != mp->buf){
    219  1.1  deraadt 		setpriority(PRIO_PROCESS, 0, 0);
    220  1.1  deraadt 		fclose(mp->keyfile);
    221  1.1  deraadt 		return -1;
    222  1.1  deraadt 	}
    223  1.1  deraadt 	rip(mp->buf);
    224  1.1  deraadt 	mp->logname = strtok(mp->buf," \t");
    225  1.1  deraadt 	cp = strtok(NULL," \t") ;
    226  1.1  deraadt 	mp->seed = strtok(NULL," \t");
    227  1.1  deraadt 	mp->val = strtok(NULL," \t");
    228  1.1  deraadt 	/* And convert file value to hex for comparison */
    229  1.1  deraadt 	atob8(filekey,mp->val);
    230  1.1  deraadt 
    231  1.1  deraadt 	/* Do actual comparison */
    232  1.1  deraadt         fflush (stdout);
    233  1.1  deraadt 
    234  1.1  deraadt 	if(memcmp(filekey,fkey,8) != 0){
    235  1.1  deraadt 		/* Wrong response */
    236  1.1  deraadt 		setpriority(PRIO_PROCESS, 0, 0);
    237  1.1  deraadt 		fclose(mp->keyfile);
    238  1.1  deraadt 		return 1;
    239  1.1  deraadt 	}
    240  1.1  deraadt 
    241  1.1  deraadt 	/* Update key in database by overwriting entire record. Note
    242  1.1  deraadt 	 * that we must write exactly the same number of bytes as in
    243  1.1  deraadt 	 * the original record (note fixed width field for N)
    244  1.1  deraadt 	 */
    245  1.1  deraadt 	btoa8(mp->val,key);
    246  1.1  deraadt 	mp->n--;
    247  1.1  deraadt 	fseek(mp->keyfile,mp->recstart,0);
    248  1.1  deraadt 	fprintf(mp->keyfile,"%s %04d %-16s %s %-21s\n",mp->logname,mp->n,mp->seed,
    249  1.1  deraadt 	 mp->val, tbuf);
    250  1.1  deraadt 
    251  1.1  deraadt 	fclose(mp->keyfile);
    252  1.1  deraadt 
    253  1.1  deraadt 	setpriority(PRIO_PROCESS, 0, 0);
    254  1.1  deraadt 	return 0;
    255  1.1  deraadt }
    256  1.1  deraadt 
    257  1.1  deraadt 
    258  1.1  deraadt /* Convert 8-byte hex-ascii string to binary array
    259  1.1  deraadt  * Returns 0 on success, -1 on error
    260  1.1  deraadt  */
    261  1.1  deraadt atob8(out,in)
    262  1.1  deraadt register char *out,*in;
    263  1.1  deraadt {
    264  1.1  deraadt 	register int i;
    265  1.1  deraadt 	register int val;
    266  1.1  deraadt 
    267  1.1  deraadt 	if (in == NULL || out == NULL)
    268  1.1  deraadt 		return -1;
    269  1.1  deraadt 
    270  1.1  deraadt 	for(i=0;i<8;i++){
    271  1.1  deraadt 		if((in = skipspace(in)) == NULL)
    272  1.1  deraadt 			return -1;
    273  1.1  deraadt 		if((val = htoi(*in++)) == -1)
    274  1.1  deraadt 			return -1;
    275  1.1  deraadt 		*out = val << 4;
    276  1.1  deraadt 
    277  1.1  deraadt 		if((in = skipspace(in)) == NULL)
    278  1.1  deraadt 			return -1;
    279  1.1  deraadt 		if((val = htoi(*in++)) == -1)
    280  1.1  deraadt 			return -1;
    281  1.1  deraadt 		*out++ |= val;
    282  1.1  deraadt 	}
    283  1.1  deraadt 	return 0;
    284  1.1  deraadt }
    285  1.1  deraadt 
    286  1.1  deraadt char *
    287  1.1  deraadt skipspace(cp)
    288  1.1  deraadt register char *cp;
    289  1.1  deraadt {
    290  1.1  deraadt 	while(*cp == ' ' || *cp == '\t')
    291  1.1  deraadt 		cp++;
    292  1.1  deraadt 
    293  1.1  deraadt 	if(*cp == '\0')
    294  1.1  deraadt 		return NULL;
    295  1.1  deraadt 	else
    296  1.1  deraadt 		return cp;
    297  1.1  deraadt }
    298  1.1  deraadt 
    299  1.1  deraadt /* Convert 8-byte binary array to hex-ascii string */
    300  1.1  deraadt int
    301  1.1  deraadt btoa8(out,in)
    302  1.1  deraadt register char *out,*in;
    303  1.1  deraadt {
    304  1.1  deraadt 	register int i;
    305  1.1  deraadt 
    306  1.1  deraadt 	if(in == NULL || out == NULL)
    307  1.1  deraadt 		return -1;
    308  1.1  deraadt 
    309  1.1  deraadt 	for(i=0;i<8;i++){
    310  1.1  deraadt 		sprintf(out,"%02x",*in++ & 0xff);
    311  1.1  deraadt 		out += 2;
    312  1.1  deraadt 	}
    313  1.1  deraadt 	return 0;
    314  1.1  deraadt }
    315  1.1  deraadt 
    316  1.1  deraadt 
    317  1.1  deraadt /* Convert hex digit to binary integer */
    318  1.1  deraadt int
    319  1.1  deraadt htoi(c)
    320  1.1  deraadt register char c;
    321  1.1  deraadt {
    322  1.1  deraadt 	if('0' <= c && c <= '9')
    323  1.1  deraadt 		return c - '0';
    324  1.1  deraadt 	if('a' <= c && c <= 'f')
    325  1.1  deraadt 		return 10 + c - 'a';
    326  1.1  deraadt 	if('A' <= c && c <= 'F')
    327  1.1  deraadt 		return 10 + c - 'A';
    328  1.1  deraadt 	return -1;
    329  1.1  deraadt }
    330  1.1  deraadt 
    331  1.1  deraadt /*
    332  1.1  deraadt  * skey_haskey ()
    333  1.1  deraadt  *
    334  1.1  deraadt  * Returns: 1 user doesnt exist, -1 fle error, 0 user exists.
    335  1.1  deraadt  *
    336  1.1  deraadt  */
    337  1.1  deraadt 
    338  1.1  deraadt skey_haskey (username)
    339  1.1  deraadt   char *username;
    340  1.1  deraadt {
    341  1.1  deraadt   int i;
    342  1.1  deraadt   struct skey skey;
    343  1.1  deraadt 
    344  1.1  deraadt   return (skeylookup (&skey, username));
    345  1.1  deraadt }
    346  1.1  deraadt 
    347  1.1  deraadt /*
    348  1.1  deraadt  * skey_keyinfo ()
    349  1.1  deraadt  *
    350  1.1  deraadt  * Returns the current sequence number and
    351  1.1  deraadt  * seed for the passed user.
    352  1.1  deraadt  *
    353  1.1  deraadt  */
    354  1.1  deraadt char *skey_keyinfo (username)
    355  1.1  deraadt   char *username;
    356  1.1  deraadt {
    357  1.1  deraadt   int i;
    358  1.1  deraadt   static char str [50];
    359  1.1  deraadt 
    360  1.1  deraadt   struct skey skey;
    361  1.1  deraadt 
    362  1.1  deraadt   i = skeychallenge (&skey, username, str);
    363  1.1  deraadt   if (i == -1)
    364  1.1  deraadt      return 0;
    365  1.1  deraadt 
    366  1.1  deraadt   return str;
    367  1.1  deraadt }
    368  1.1  deraadt 
    369  1.1  deraadt /*
    370  1.1  deraadt  * skey_passcheck ()
    371  1.1  deraadt  *
    372  1.1  deraadt  * Check to see if answer is the correct one to the current
    373  1.1  deraadt  * challenge.
    374  1.1  deraadt  *
    375  1.1  deraadt  * Returns: 0 success, -1 failure
    376  1.1  deraadt  *
    377  1.1  deraadt  */
    378  1.1  deraadt 
    379  1.1  deraadt skey_passcheck (username, passwd)
    380  1.1  deraadt   char *username, *passwd;
    381  1.1  deraadt {
    382  1.1  deraadt   int i;
    383  1.1  deraadt   struct skey skey;
    384  1.1  deraadt 
    385  1.1  deraadt   i = skeylookup (&skey, username);
    386  1.1  deraadt 
    387  1.1  deraadt   if (i == -1 || i == 1)
    388  1.1  deraadt       return -1;
    389  1.1  deraadt 
    390  1.1  deraadt   if (skeyverify (&skey, passwd) == 0)
    391  1.1  deraadt       return skey.n;
    392  1.1  deraadt 
    393  1.1  deraadt   return -1;
    394  1.1  deraadt }
    395  1.1  deraadt 
    396  1.1  deraadt /*
    397  1.1  deraadt  * skey_authenticate ()
    398  1.1  deraadt  *
    399  1.1  deraadt  * Used when calling program will allow input of the user's
    400  1.1  deraadt  * response to the challenge.
    401  1.1  deraadt  *
    402  1.1  deraadt  * Returns: 0 success, -1 failure
    403  1.1  deraadt  *
    404  1.1  deraadt  */
    405  1.1  deraadt 
    406  1.1  deraadt skey_authenticate (username)
    407  1.1  deraadt   char *username;
    408  1.1  deraadt {
    409  1.1  deraadt   int i;
    410  1.1  deraadt   char pbuf [256], skeyprompt [50];
    411  1.1  deraadt   struct skey skey;
    412  1.1  deraadt 
    413  1.1  deraadt   /* Attempt a S/Key challenge */
    414  1.1  deraadt   i = skeychallenge (&skey, username, skeyprompt);
    415  1.1  deraadt 
    416  1.1  deraadt   if (i == -2)
    417  1.1  deraadt     return 0;
    418  1.1  deraadt 
    419  1.1  deraadt   printf ("[%s]\n", skeyprompt);
    420  1.1  deraadt   fflush (stdout);
    421  1.1  deraadt 
    422  1.1  deraadt   printf ("Response: ");
    423  1.1  deraadt   readpass (pbuf, sizeof (pbuf));
    424  1.1  deraadt   rip (pbuf);
    425  1.1  deraadt 
    426  1.1  deraadt   /* Is it a valid response? */
    427  1.1  deraadt   if (i == 0 && skeyverify (&skey, pbuf) == 0)
    428  1.1  deraadt   {
    429  1.1  deraadt     if (skey.n < 5)
    430  1.1  deraadt     {
    431  1.1  deraadt       printf ("\nWarning! Key initialization needed soon.  ");
    432  1.1  deraadt       printf ("(%d logins left)\n", skey.n);
    433  1.1  deraadt     }
    434  1.1  deraadt     return 0;
    435  1.1  deraadt   }
    436  1.1  deraadt   return -1;
    437  1.1  deraadt }
    438  1.1  deraadt 
    439