skeylogin.c revision 1.10 1 1.10 simonb /* $NetBSD: skeylogin.c,v 1.10 1999/07/02 15:45:23 simonb 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.1 deraadt */
43 1.1 deraadt int
44 1.1 deraadt getskeyprompt(mp,name,prompt)
45 1.5 pk struct skey *mp;
46 1.5 pk char *name;
47 1.5 pk char *prompt;
48 1.1 deraadt {
49 1.1 deraadt int rval;
50 1.1 deraadt
51 1.1 deraadt sevenbit(name);
52 1.1 deraadt rval = skeylookup(mp,name);
53 1.7 mrg #if 0
54 1.7 mrg strcpy(prompt, "s/key 55 latour1\n");
55 1.7 mrg #endif
56 1.5 pk 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.7 mrg sprintf(prompt,"s/key %d %s\n",mp->n - 1,mp->seed); /* XXX: sprintf (getskeyprompt()) appears unused */
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.5 pk }
68 1.5 pk
69 1.1 deraadt /* Return a skey challenge string for user 'name'. If successful,
70 1.1 deraadt * fill in the caller's skey structure and return 0. If unsuccessful
71 1.1 deraadt * (e.g., if name is unknown) return -1.
72 1.1 deraadt *
73 1.1 deraadt * The file read/write pointer is left at the start of the
74 1.1 deraadt * record.
75 1.1 deraadt */
76 1.1 deraadt int
77 1.7 mrg skeychallenge(mp,name, ss, sslen)
78 1.5 pk struct skey *mp;
79 1.9 mycroft const char *name;
80 1.5 pk char *ss;
81 1.7 mrg int sslen;
82 1.1 deraadt {
83 1.1 deraadt int rval;
84 1.1 deraadt
85 1.1 deraadt rval = skeylookup(mp,name);
86 1.1 deraadt switch(rval){
87 1.1 deraadt case -1: /* File error */
88 1.1 deraadt return -1;
89 1.1 deraadt case 0: /* Lookup succeeded, issue challenge */
90 1.7 mrg (void)snprintf(ss, sslen, "s/key %d %s",mp->n - 1,mp->seed);
91 1.1 deraadt return 0;
92 1.1 deraadt case 1: /* User not found */
93 1.1 deraadt fclose(mp->keyfile);
94 1.1 deraadt return -1;
95 1.1 deraadt }
96 1.1 deraadt return -1; /* Can't happen */
97 1.10 simonb }
98 1.1 deraadt
99 1.1 deraadt /* Find an entry in the One-time Password database.
100 1.1 deraadt * Return codes:
101 1.1 deraadt * -1: error in opening database
102 1.1 deraadt * 0: entry found, file R/W pointer positioned at beginning of record
103 1.1 deraadt * 1: entry not found, file R/W pointer positioned at EOF
104 1.1 deraadt */
105 1.1 deraadt int
106 1.1 deraadt skeylookup(mp,name)
107 1.5 pk struct skey *mp;
108 1.9 mycroft const char *name;
109 1.1 deraadt {
110 1.1 deraadt int found;
111 1.1 deraadt int len;
112 1.8 christos long recstart = 0;
113 1.1 deraadt char *cp;
114 1.1 deraadt struct stat statbuf;
115 1.1 deraadt
116 1.5 pk /* See if the _PATH_KEYFILE exists, and create it if not */
117 1.2 deraadt
118 1.5 pk if (stat(_PATH_KEYFILE,&statbuf) == -1 && errno == ENOENT) {
119 1.5 pk mp->keyfile = fopen(_PATH_KEYFILE,"w+");
120 1.5 pk if (mp->keyfile)
121 1.5 pk chmod(_PATH_KEYFILE, 0644);
122 1.1 deraadt } else {
123 1.1 deraadt /* Otherwise open normally for update */
124 1.5 pk mp->keyfile = fopen(_PATH_KEYFILE,"r+");
125 1.1 deraadt }
126 1.5 pk if (mp->keyfile == NULL)
127 1.1 deraadt return -1;
128 1.1 deraadt
129 1.1 deraadt /* Look up user name in database */
130 1.1 deraadt len = strlen(name);
131 1.1 deraadt if( len > 8 ) len = 8; /* Added 8/2/91 - nmh */
132 1.1 deraadt found = 0;
133 1.5 pk while (!feof(mp->keyfile)) {
134 1.1 deraadt recstart = ftell(mp->keyfile);
135 1.1 deraadt mp->recstart = recstart;
136 1.5 pk if (fgets(mp->buf,sizeof(mp->buf),mp->keyfile) != mp->buf) {
137 1.1 deraadt break;
138 1.1 deraadt }
139 1.1 deraadt rip(mp->buf);
140 1.5 pk if (mp->buf[0] == '#')
141 1.1 deraadt continue; /* Comment */
142 1.5 pk if ((mp->logname = strtok(mp->buf," \t")) == NULL)
143 1.1 deraadt continue;
144 1.5 pk if ((cp = strtok(NULL," \t")) == NULL)
145 1.1 deraadt continue;
146 1.1 deraadt mp->n = atoi(cp);
147 1.5 pk if ((mp->seed = strtok(NULL," \t")) == NULL)
148 1.1 deraadt continue;
149 1.5 pk if ((mp->val = strtok(NULL," \t")) == NULL)
150 1.1 deraadt continue;
151 1.5 pk if (strlen(mp->logname) == len
152 1.1 deraadt && strncmp(mp->logname,name,len) == 0){
153 1.1 deraadt found = 1;
154 1.1 deraadt break;
155 1.1 deraadt }
156 1.1 deraadt }
157 1.5 pk if (found) {
158 1.1 deraadt fseek(mp->keyfile,recstart,0);
159 1.1 deraadt return 0;
160 1.1 deraadt } else
161 1.1 deraadt return 1;
162 1.1 deraadt }
163 1.1 deraadt /* Verify response to a s/key challenge.
164 1.1 deraadt *
165 1.1 deraadt * Return codes:
166 1.1 deraadt * -1: Error of some sort; database unchanged
167 1.1 deraadt * 0: Verify successful, database updated
168 1.1 deraadt * 1: Verify failed, database unchanged
169 1.1 deraadt *
170 1.1 deraadt * The database file is always closed by this call.
171 1.1 deraadt */
172 1.1 deraadt int
173 1.1 deraadt skeyverify(mp,response)
174 1.5 pk struct skey *mp;
175 1.5 pk char *response;
176 1.1 deraadt {
177 1.1 deraadt char key[8];
178 1.1 deraadt char fkey[8];
179 1.1 deraadt char filekey[8];
180 1.1 deraadt time_t now;
181 1.1 deraadt struct tm *tm;
182 1.5 pk char tbuf[27];
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.5 pk if (response == NULL) {
190 1.1 deraadt fclose(mp->keyfile);
191 1.1 deraadt return -1;
192 1.1 deraadt }
193 1.5 pk rip(response);
194 1.1 deraadt
195 1.1 deraadt /* Convert response to binary */
196 1.5 pk 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.5 pk /*
208 1.5 pk * in order to make the window of update as short as possible
209 1.5 pk * we must do the comparison here and if OK write it back
210 1.5 pk * other wise the same password can be used twice to get in
211 1.5 pk * to the system
212 1.5 pk */
213 1.1 deraadt
214 1.1 deraadt setpriority(PRIO_PROCESS, 0, -4);
215 1.1 deraadt
216 1.1 deraadt /* reread the file record NOW*/
217 1.1 deraadt
218 1.1 deraadt fseek(mp->keyfile,mp->recstart,0);
219 1.5 pk if (fgets(mp->buf,sizeof(mp->buf),mp->keyfile) != mp->buf){
220 1.1 deraadt setpriority(PRIO_PROCESS, 0, 0);
221 1.1 deraadt fclose(mp->keyfile);
222 1.1 deraadt return -1;
223 1.1 deraadt }
224 1.1 deraadt rip(mp->buf);
225 1.1 deraadt mp->logname = strtok(mp->buf," \t");
226 1.1 deraadt cp = strtok(NULL," \t") ;
227 1.1 deraadt mp->seed = strtok(NULL," \t");
228 1.1 deraadt mp->val = strtok(NULL," \t");
229 1.1 deraadt /* And convert file value to hex for comparison */
230 1.1 deraadt atob8(filekey,mp->val);
231 1.1 deraadt
232 1.1 deraadt /* Do actual comparison */
233 1.1 deraadt fflush (stdout);
234 1.1 deraadt
235 1.5 pk if (memcmp(filekey,fkey,8) != 0){
236 1.1 deraadt /* Wrong response */
237 1.1 deraadt setpriority(PRIO_PROCESS, 0, 0);
238 1.1 deraadt fclose(mp->keyfile);
239 1.1 deraadt return 1;
240 1.1 deraadt }
241 1.1 deraadt
242 1.5 pk /*
243 1.5 pk * Update key in database by overwriting entire record. Note
244 1.1 deraadt * that we must write exactly the same number of bytes as in
245 1.1 deraadt * the original record (note fixed width field for N)
246 1.1 deraadt */
247 1.1 deraadt btoa8(mp->val,key);
248 1.1 deraadt mp->n--;
249 1.1 deraadt fseek(mp->keyfile,mp->recstart,0);
250 1.5 pk fprintf(mp->keyfile, "%s %04d %-16s %s %-21s\n",
251 1.5 pk mp->logname,mp->n,mp->seed, mp->val, tbuf);
252 1.1 deraadt
253 1.1 deraadt fclose(mp->keyfile);
254 1.10 simonb
255 1.1 deraadt setpriority(PRIO_PROCESS, 0, 0);
256 1.1 deraadt return 0;
257 1.1 deraadt }
258 1.1 deraadt
259 1.1 deraadt
260 1.1 deraadt /*
261 1.1 deraadt * skey_haskey ()
262 1.1 deraadt *
263 1.1 deraadt * Returns: 1 user doesnt exist, -1 fle error, 0 user exists.
264 1.1 deraadt *
265 1.1 deraadt */
266 1.10 simonb
267 1.5 pk int
268 1.1 deraadt skey_haskey (username)
269 1.9 mycroft const char *username;
270 1.1 deraadt {
271 1.5 pk struct skey skey;
272 1.10 simonb
273 1.5 pk return (skeylookup (&skey, username));
274 1.1 deraadt }
275 1.10 simonb
276 1.1 deraadt /*
277 1.1 deraadt * skey_keyinfo ()
278 1.1 deraadt *
279 1.1 deraadt * Returns the current sequence number and
280 1.1 deraadt * seed for the passed user.
281 1.1 deraadt *
282 1.1 deraadt */
283 1.5 pk char *
284 1.5 pk skey_keyinfo (username)
285 1.9 mycroft const char *username;
286 1.1 deraadt {
287 1.5 pk int i;
288 1.5 pk static char str [50];
289 1.5 pk struct skey skey;
290 1.5 pk
291 1.7 mrg i = skeychallenge (&skey, username, str, sizeof str);
292 1.5 pk if (i == -1)
293 1.5 pk return 0;
294 1.1 deraadt
295 1.5 pk return str;
296 1.1 deraadt }
297 1.10 simonb
298 1.1 deraadt /*
299 1.1 deraadt * skey_passcheck ()
300 1.1 deraadt *
301 1.1 deraadt * Check to see if answer is the correct one to the current
302 1.1 deraadt * challenge.
303 1.1 deraadt *
304 1.1 deraadt * Returns: 0 success, -1 failure
305 1.1 deraadt *
306 1.1 deraadt */
307 1.10 simonb
308 1.5 pk int
309 1.1 deraadt skey_passcheck (username, passwd)
310 1.9 mycroft const char *username;
311 1.9 mycroft char *passwd;
312 1.1 deraadt {
313 1.5 pk int i;
314 1.5 pk struct skey skey;
315 1.5 pk
316 1.5 pk i = skeylookup (&skey, username);
317 1.5 pk if (i == -1 || i == 1)
318 1.5 pk return -1;
319 1.5 pk
320 1.5 pk if (skeyverify (&skey, passwd) == 0)
321 1.5 pk return skey.n;
322 1.5 pk
323 1.5 pk return -1;
324 1.1 deraadt }
325 1.1 deraadt
326 1.1 deraadt /*
327 1.1 deraadt * skey_authenticate ()
328 1.1 deraadt *
329 1.1 deraadt * Used when calling program will allow input of the user's
330 1.1 deraadt * response to the challenge.
331 1.1 deraadt *
332 1.1 deraadt * Returns: 0 success, -1 failure
333 1.1 deraadt *
334 1.1 deraadt */
335 1.10 simonb
336 1.5 pk int
337 1.1 deraadt skey_authenticate (username)
338 1.9 mycroft const char *username;
339 1.1 deraadt {
340 1.5 pk int i;
341 1.5 pk char pbuf[256], skeyprompt[50];
342 1.5 pk struct skey skey;
343 1.5 pk
344 1.5 pk /* Attempt a S/Key challenge */
345 1.7 mrg i = skeychallenge (&skey, username, skeyprompt, sizeof skeyprompt);
346 1.5 pk
347 1.5 pk if (i == -2)
348 1.5 pk return 0;
349 1.5 pk
350 1.5 pk printf("[%s]\n", skeyprompt);
351 1.5 pk fflush(stdout);
352 1.5 pk
353 1.5 pk printf("Response: ");
354 1.5 pk readskey(pbuf, sizeof (pbuf));
355 1.5 pk rip(pbuf);
356 1.5 pk
357 1.5 pk /* Is it a valid response? */
358 1.5 pk if (i == 0 && skeyverify (&skey, pbuf) == 0) {
359 1.5 pk if (skey.n < 5) {
360 1.5 pk printf ("\nWarning! Key initialization needed soon. ");
361 1.5 pk printf ("(%d logins left)\n", skey.n);
362 1.5 pk }
363 1.5 pk return 0;
364 1.5 pk }
365 1.5 pk return -1;
366 1.1 deraadt }
367