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