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