1 /* Login code for S/KEY Authentication. S/KEY is a trademark
4 * Mink is the former name of the S/KEY authentication system.
5 * Many references for mink may still be found in this program.
7 * $FreeBSD: src/lib/libskey/skeylogin.c,v 1.14.6.1 2000/07/18 11:38:24 sheldonh Exp $
10 #include <sys/param.h>
13 #include <sys/resource.h>
23 #include "pathnames.h"
25 static char *skipspace __P((char *));
27 #define setpriority(x,y,z) /* nothing */
29 static const char *month[12] = {
30 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
31 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
34 /* Look up skey info for user 'name'. If successful, fill in the caller's
35 * skey structure and return 0. If unsuccessful (e.g., if name is unknown)
36 * return -1. If an optional challenge string buffer is given, update it.
38 * The file read/write pointer is left at the start of the
49 rval = skeylookup(mp,name);
51 case -1: /* File error */
53 case 0: /* Lookup succeeded */
55 sprintf(ss, "s/key %d %s",mp->n - 1,mp->seed);
59 case 1: /* User not found */
63 return -1; /* Can't happen */
66 /* Return a skey challenge string for user 'name'. If successful,
67 * fill in the caller's skey structure and return 0. If unsuccessful
68 * (e.g., if name is unknown) return -1.
70 * The file read/write pointer is left at the start of the
74 skeychallenge(mp,name, ss)
81 rval = skeylookup(mp,name);
83 case -1: /* File error */
85 case 0: /* Lookup succeeded, issue challenge */
86 sprintf(ss, "s/key %d %s",mp->n - 1,mp->seed);
88 case 1: /* User not found */
92 return -1; /* Can't happen */
95 /* Find an entry in the One-time Password database.
97 * -1: error in opening database
98 * 0: entry found, file R/W pointer positioned at beginning of record
99 * 1: entry not found, file R/W pointer positioned at EOF
113 /* See if the _PATH_SKEYFILE exists, and create it if not */
114 if(stat(_PATH_SKEYFILE,&statbuf) == -1 && errno == ENOENT){
115 oldmask = umask(S_IRWXG|S_IRWXO);
116 mp->keyfile = fopen(_PATH_SKEYFILE,"w+");
117 (void)umask(oldmask);
119 /* Otherwise open normally for update */
120 mp->keyfile = fopen(_PATH_SKEYFILE,"r+");
122 if(mp->keyfile == NULL)
125 /* Look up user name in database */
127 if(len > UT_NAMESIZE)
130 while(!feof(mp->keyfile)){
131 recstart = ftell(mp->keyfile);
132 mp->recstart = recstart;
133 if(fgets(mp->buf,sizeof(mp->buf),mp->keyfile) != mp->buf){
137 if(mp->buf[0] == '#')
138 continue; /* Comment */
140 while ((cp = strsep(&p, " \t")) != NULL && *cp == '\0')
142 if((mp->logname = cp) == NULL)
144 while ((cp = strsep(&p, " \t")) != NULL && *cp == '\0')
149 while ((cp = strsep(&p, " \t")) != NULL && *cp == '\0')
151 if((mp->seed = cp) == NULL)
153 while ((cp = strsep(&p, " \t")) != NULL && *cp == '\0')
155 if((mp->val = cp) == NULL)
157 if(strlen(mp->logname) == len
158 && strncmp(mp->logname,name,len) == 0){
164 fseek(mp->keyfile,recstart,0);
169 /* Verify response to a s/key challenge.
172 * -1: Error of some sort; database unchanged
173 * 0: Verify successful, database updated
174 * 1: Verify failed, database unchanged
176 * The database file is always closed by this call.
179 skeyverify(mp,response)
188 char tbuf[27], fbuf[20];
192 tm = localtime(&now);
193 /* can't use %b here, because it can be in national form */
194 strftime(fbuf, sizeof(fbuf), "%d,%Y %T", tm);
195 snprintf(tbuf, sizeof(tbuf), " %s %s", month[tm->tm_mon], fbuf);
197 if(response == NULL){
203 /* Convert response to binary */
204 if(etob(key,response) != 1 && atob8(key,response) != 0){
205 /* Neither english words or ascii hex */
210 /* Compute fkey = f(key) */
211 memcpy(fkey,key,sizeof(key));
213 /* in order to make the window of update as short as possible
214 we must do the comparison here and if OK write it back
215 other wise the same password can be used twice to get in
219 setpriority(PRIO_PROCESS, 0, -4);
221 /* reread the file record NOW*/
223 fseek(mp->keyfile,mp->recstart,0);
224 if(fgets(mp->buf,sizeof(mp->buf),mp->keyfile) != mp->buf){
225 setpriority(PRIO_PROCESS, 0, 0);
231 while ((cp = strsep(&p, " \t")) != NULL && *cp == '\0')
234 while ((cp = strsep(&p, " \t")) != NULL && *cp == '\0')
236 while ((cp = strsep(&p, " \t")) != NULL && *cp == '\0')
239 while ((cp = strsep(&p, " \t")) != NULL && *cp == '\0')
242 /* And convert file value to hex for comparison */
243 atob8(filekey,mp->val);
245 /* Do actual comparison */
246 if(memcmp(filekey,fkey,8) != 0){
248 setpriority(PRIO_PROCESS, 0, 0);
253 /* Update key in database by overwriting entire record. Note
254 * that we must write exactly the same number of bytes as in
255 * the original record (note fixed width field for N)
259 fseek(mp->keyfile,mp->recstart,0);
260 fprintf(mp->keyfile,"%s %04d %-16s %s %-21s\n",mp->logname,mp->n,mp->seed,
265 setpriority(PRIO_PROCESS, 0, 0);
270 /* Convert 8-byte hex-ascii string to binary array
271 * Returns 0 on success, -1 on error
275 register char *out,*in;
280 if(in == NULL || out == NULL)
284 if((in = skipspace(in)) == NULL)
286 if((val = htoi(*in++)) == -1)
290 if((in = skipspace(in)) == NULL)
292 if((val = htoi(*in++)) == -1)
304 while(*cp == ' ' || *cp == '\t')
313 /* Convert 8-byte binary array to hex-ascii string */
316 register char *out,*in;
320 if(in == NULL || out == NULL)
324 sprintf(out,"%02x",*in++ & 0xff);
331 /* Convert hex digit to binary integer */
336 if('0' <= c && c <= '9')
338 if('a' <= c && c <= 'f')
340 if('A' <= c && c <= 'F')