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