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