skeylogin.c revision 1.12 1 1.12 mycroft /* $NetBSD: skeylogin.c,v 1.12 2000/01/23 02:11:02 mycroft 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.1 deraadt if( len > 8 ) len = 8; /* Added 8/2/91 - nmh */
136 1.1 deraadt found = 0;
137 1.5 pk while (!feof(mp->keyfile)) {
138 1.1 deraadt recstart = ftell(mp->keyfile);
139 1.1 deraadt mp->recstart = recstart;
140 1.5 pk if (fgets(mp->buf,sizeof(mp->buf),mp->keyfile) != mp->buf) {
141 1.1 deraadt break;
142 1.1 deraadt }
143 1.1 deraadt rip(mp->buf);
144 1.5 pk if (mp->buf[0] == '#')
145 1.1 deraadt continue; /* Comment */
146 1.5 pk if ((mp->logname = strtok(mp->buf," \t")) == NULL)
147 1.1 deraadt continue;
148 1.5 pk if ((cp = strtok(NULL," \t")) == NULL)
149 1.1 deraadt continue;
150 1.1 deraadt mp->n = atoi(cp);
151 1.5 pk if ((mp->seed = strtok(NULL," \t")) == NULL)
152 1.1 deraadt continue;
153 1.5 pk if ((mp->val = strtok(NULL," \t")) == NULL)
154 1.1 deraadt continue;
155 1.5 pk if (strlen(mp->logname) == len
156 1.1 deraadt && strncmp(mp->logname,name,len) == 0){
157 1.1 deraadt found = 1;
158 1.1 deraadt break;
159 1.1 deraadt }
160 1.1 deraadt }
161 1.5 pk if (found) {
162 1.1 deraadt fseek(mp->keyfile,recstart,0);
163 1.1 deraadt return 0;
164 1.1 deraadt } else
165 1.1 deraadt return 1;
166 1.1 deraadt }
167 1.1 deraadt /* Verify response to a s/key challenge.
168 1.1 deraadt *
169 1.1 deraadt * Return codes:
170 1.1 deraadt * -1: Error of some sort; database unchanged
171 1.1 deraadt * 0: Verify successful, database updated
172 1.1 deraadt * 1: Verify failed, database unchanged
173 1.1 deraadt *
174 1.1 deraadt * The database file is always closed by this call.
175 1.1 deraadt */
176 1.1 deraadt int
177 1.1 deraadt skeyverify(mp,response)
178 1.5 pk struct skey *mp;
179 1.5 pk char *response;
180 1.1 deraadt {
181 1.1 deraadt char key[8];
182 1.1 deraadt char fkey[8];
183 1.1 deraadt char filekey[8];
184 1.1 deraadt time_t now;
185 1.1 deraadt struct tm *tm;
186 1.5 pk char tbuf[27];
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.5 pk if (response == NULL) {
193 1.1 deraadt fclose(mp->keyfile);
194 1.1 deraadt return -1;
195 1.1 deraadt }
196 1.5 pk rip(response);
197 1.1 deraadt
198 1.1 deraadt /* Convert response to binary */
199 1.5 pk 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.5 pk /*
211 1.5 pk * in order to make the window of update as short as possible
212 1.5 pk * we must do the comparison here and if OK write it back
213 1.5 pk * other wise the same password can be used twice to get in
214 1.5 pk * to the system
215 1.5 pk */
216 1.1 deraadt
217 1.1 deraadt setpriority(PRIO_PROCESS, 0, -4);
218 1.1 deraadt
219 1.1 deraadt /* reread the file record NOW*/
220 1.1 deraadt
221 1.1 deraadt fseek(mp->keyfile,mp->recstart,0);
222 1.5 pk if (fgets(mp->buf,sizeof(mp->buf),mp->keyfile) != mp->buf){
223 1.1 deraadt setpriority(PRIO_PROCESS, 0, 0);
224 1.1 deraadt fclose(mp->keyfile);
225 1.1 deraadt return -1;
226 1.1 deraadt }
227 1.1 deraadt rip(mp->buf);
228 1.1 deraadt mp->logname = strtok(mp->buf," \t");
229 1.12 mycroft (void) strtok(NULL," \t"); /* ignore counter */
230 1.1 deraadt mp->seed = strtok(NULL," \t");
231 1.1 deraadt mp->val = strtok(NULL," \t");
232 1.1 deraadt /* And convert file value to hex for comparison */
233 1.1 deraadt atob8(filekey,mp->val);
234 1.1 deraadt
235 1.1 deraadt /* Do actual comparison */
236 1.1 deraadt fflush (stdout);
237 1.1 deraadt
238 1.5 pk if (memcmp(filekey,fkey,8) != 0){
239 1.1 deraadt /* Wrong response */
240 1.1 deraadt setpriority(PRIO_PROCESS, 0, 0);
241 1.1 deraadt fclose(mp->keyfile);
242 1.1 deraadt return 1;
243 1.1 deraadt }
244 1.1 deraadt
245 1.5 pk /*
246 1.5 pk * Update key in database by overwriting entire record. Note
247 1.1 deraadt * that we must write exactly the same number of bytes as in
248 1.1 deraadt * the original record (note fixed width field for N)
249 1.1 deraadt */
250 1.1 deraadt btoa8(mp->val,key);
251 1.1 deraadt mp->n--;
252 1.1 deraadt fseek(mp->keyfile,mp->recstart,0);
253 1.5 pk fprintf(mp->keyfile, "%s %04d %-16s %s %-21s\n",
254 1.5 pk mp->logname,mp->n,mp->seed, mp->val, tbuf);
255 1.1 deraadt
256 1.1 deraadt fclose(mp->keyfile);
257 1.10 simonb
258 1.1 deraadt setpriority(PRIO_PROCESS, 0, 0);
259 1.1 deraadt return 0;
260 1.1 deraadt }
261 1.1 deraadt
262 1.1 deraadt
263 1.1 deraadt /*
264 1.1 deraadt * skey_haskey ()
265 1.1 deraadt *
266 1.1 deraadt * Returns: 1 user doesnt exist, -1 fle error, 0 user exists.
267 1.1 deraadt *
268 1.1 deraadt */
269 1.10 simonb
270 1.5 pk int
271 1.1 deraadt skey_haskey (username)
272 1.9 mycroft const char *username;
273 1.1 deraadt {
274 1.5 pk struct skey skey;
275 1.10 simonb
276 1.5 pk return (skeylookup (&skey, username));
277 1.1 deraadt }
278 1.10 simonb
279 1.1 deraadt /*
280 1.1 deraadt * skey_keyinfo ()
281 1.1 deraadt *
282 1.1 deraadt * Returns the current sequence number and
283 1.1 deraadt * seed for the passed user.
284 1.1 deraadt *
285 1.1 deraadt */
286 1.5 pk char *
287 1.5 pk skey_keyinfo (username)
288 1.9 mycroft const char *username;
289 1.1 deraadt {
290 1.5 pk int i;
291 1.5 pk static char str [50];
292 1.5 pk struct skey skey;
293 1.5 pk
294 1.7 mrg i = skeychallenge (&skey, username, str, sizeof str);
295 1.5 pk if (i == -1)
296 1.5 pk return 0;
297 1.1 deraadt
298 1.5 pk return str;
299 1.1 deraadt }
300 1.10 simonb
301 1.1 deraadt /*
302 1.1 deraadt * skey_passcheck ()
303 1.1 deraadt *
304 1.1 deraadt * Check to see if answer is the correct one to the current
305 1.1 deraadt * challenge.
306 1.1 deraadt *
307 1.1 deraadt * Returns: 0 success, -1 failure
308 1.1 deraadt *
309 1.1 deraadt */
310 1.10 simonb
311 1.5 pk int
312 1.1 deraadt skey_passcheck (username, passwd)
313 1.9 mycroft const char *username;
314 1.9 mycroft char *passwd;
315 1.1 deraadt {
316 1.5 pk int i;
317 1.5 pk struct skey skey;
318 1.5 pk
319 1.5 pk i = skeylookup (&skey, username);
320 1.5 pk if (i == -1 || i == 1)
321 1.5 pk return -1;
322 1.5 pk
323 1.5 pk if (skeyverify (&skey, passwd) == 0)
324 1.5 pk return skey.n;
325 1.5 pk
326 1.5 pk return -1;
327 1.1 deraadt }
328 1.1 deraadt
329 1.1 deraadt /*
330 1.1 deraadt * skey_authenticate ()
331 1.1 deraadt *
332 1.1 deraadt * Used when calling program will allow input of the user's
333 1.1 deraadt * response to the challenge.
334 1.1 deraadt *
335 1.1 deraadt * Returns: 0 success, -1 failure
336 1.1 deraadt *
337 1.1 deraadt */
338 1.10 simonb
339 1.5 pk int
340 1.1 deraadt skey_authenticate (username)
341 1.9 mycroft const char *username;
342 1.1 deraadt {
343 1.5 pk int i;
344 1.5 pk char pbuf[256], skeyprompt[50];
345 1.5 pk struct skey skey;
346 1.5 pk
347 1.5 pk /* Attempt a S/Key challenge */
348 1.7 mrg i = skeychallenge (&skey, username, skeyprompt, sizeof skeyprompt);
349 1.5 pk
350 1.5 pk if (i == -2)
351 1.5 pk return 0;
352 1.5 pk
353 1.5 pk printf("[%s]\n", skeyprompt);
354 1.5 pk fflush(stdout);
355 1.5 pk
356 1.5 pk printf("Response: ");
357 1.5 pk readskey(pbuf, sizeof (pbuf));
358 1.5 pk rip(pbuf);
359 1.5 pk
360 1.5 pk /* Is it a valid response? */
361 1.5 pk if (i == 0 && skeyverify (&skey, pbuf) == 0) {
362 1.5 pk if (skey.n < 5) {
363 1.5 pk printf ("\nWarning! Key initialization needed soon. ");
364 1.5 pk printf ("(%d logins left)\n", skey.n);
365 1.5 pk }
366 1.5 pk return 0;
367 1.5 pk }
368 1.5 pk return -1;
369 1.1 deraadt }
370