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