1 /*
2 * upap.c - User/Password Authentication Protocol.
3 *
4 * Copyright (c) 1989 Carnegie Mellon University.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms are permitted
8 * provided that the above copyright notice and this paragraph are
9 * duplicated in all such forms and that any documentation,
10 * advertising materials, and other materials related to such
11 * distribution and use acknowledge that the software was developed
12 * by Carnegie Mellon University. The name of the
13 * University may not be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18 */
19
20 #ifndef lint
21 static char rcsid[] = "$Id: upap.c,v 1.2 1994/04/11 07:13:44 paulus Exp $";
22 #endif
23
24 /*
25 * TODO:
26 */
27
28 #include <stdio.h>
29 #include <sys/types.h>
30 #include <sys/time.h>
31 #include <syslog.h>
32
33 #include "ppp.h"
34 #include "pppd.h"
35 #include "upap.h"
36
37
38 upap_state upap[NPPP]; /* UPAP state; one for each unit */
39
40
41 static void upap_timeout __ARGS((caddr_t));
42 static void upap_rauthreq __ARGS((upap_state *, u_char *, int, int));
43 static void upap_rauthack __ARGS((upap_state *, u_char *, int, int));
44 static void upap_rauthnak __ARGS((upap_state *, u_char *, int, int));
45 static void upap_sauthreq __ARGS((upap_state *));
46 static void upap_sresp __ARGS((upap_state *, int, int, char *, int));
47
48
49 /*
50 * upap_init - Initialize a UPAP unit.
51 */
52 void
upap_init(unit)53 upap_init(unit)
54 int unit;
55 {
56 upap_state *u = &upap[unit];
57
58 u->us_unit = unit;
59 u->us_user = NULL;
60 u->us_userlen = 0;
61 u->us_passwd = NULL;
62 u->us_passwdlen = 0;
63 u->us_clientstate = UPAPCS_INITIAL;
64 u->us_serverstate = UPAPSS_INITIAL;
65 u->us_id = 0;
66 u->us_timeouttime = UPAP_DEFTIMEOUT;
67 u->us_maxtransmits = 10;
68 }
69
70
71 /*
72 * upap_authwithpeer - Authenticate us with our peer (start client).
73 *
74 * Set new state and send authenticate's.
75 */
76 void
upap_authwithpeer(unit,user,password)77 upap_authwithpeer(unit, user, password)
78 int unit;
79 char *user, *password;
80 {
81 upap_state *u = &upap[unit];
82
83 /* Save the username and password we're given */
84 u->us_user = user;
85 u->us_userlen = strlen(user);
86 u->us_passwd = password;
87 u->us_passwdlen = strlen(password);
88 u->us_transmits = 0;
89
90 /* Lower layer up yet? */
91 if (u->us_clientstate == UPAPCS_INITIAL ||
92 u->us_clientstate == UPAPCS_PENDING) {
93 u->us_clientstate = UPAPCS_PENDING;
94 return;
95 }
96
97 upap_sauthreq(u); /* Start protocol */
98 }
99
100
101 /*
102 * upap_authpeer - Authenticate our peer (start server).
103 *
104 * Set new state.
105 */
106 void
upap_authpeer(unit)107 upap_authpeer(unit)
108 int unit;
109 {
110 upap_state *u = &upap[unit];
111
112 /* Lower layer up yet? */
113 if (u->us_serverstate == UPAPSS_INITIAL ||
114 u->us_serverstate == UPAPSS_PENDING) {
115 u->us_serverstate = UPAPSS_PENDING;
116 return;
117 }
118
119 u->us_serverstate = UPAPSS_LISTEN;
120 }
121
122
123 /*
124 * upap_timeout - Timeout expired.
125 */
126 static void
upap_timeout(arg)127 upap_timeout(arg)
128 caddr_t arg;
129 {
130 upap_state *u = (upap_state *) arg;
131
132 if (u->us_clientstate != UPAPCS_AUTHREQ)
133 return;
134
135 if (u->us_transmits >= u->us_maxtransmits) {
136 /* give up in disgust */
137 syslog(LOG_ERR, "No response to PAP authenticate-requests");
138 u->us_clientstate = UPAPCS_BADAUTH;
139 auth_withpeer_fail(u->us_unit, UPAP);
140 return;
141 }
142
143 upap_sauthreq(u); /* Send Authenticate-Request */
144 }
145
146
147 /*
148 * upap_lowerup - The lower layer is up.
149 *
150 * Start authenticating if pending.
151 */
152 void
upap_lowerup(unit)153 upap_lowerup(unit)
154 int unit;
155 {
156 upap_state *u = &upap[unit];
157
158 if (u->us_clientstate == UPAPCS_INITIAL)
159 u->us_clientstate = UPAPCS_CLOSED;
160 else if (u->us_clientstate == UPAPCS_PENDING) {
161 upap_sauthreq(u); /* send an auth-request */
162 }
163
164 if (u->us_serverstate == UPAPSS_INITIAL)
165 u->us_serverstate = UPAPSS_CLOSED;
166 else if (u->us_serverstate == UPAPSS_PENDING)
167 u->us_serverstate = UPAPSS_LISTEN;
168 }
169
170
171 /*
172 * upap_lowerdown - The lower layer is down.
173 *
174 * Cancel all timeouts.
175 */
176 void
upap_lowerdown(unit)177 upap_lowerdown(unit)
178 int unit;
179 {
180 upap_state *u = &upap[unit];
181
182 if (u->us_clientstate == UPAPCS_AUTHREQ) /* Timeout pending? */
183 UNTIMEOUT(upap_timeout, (caddr_t) u); /* Cancel timeout */
184
185 u->us_clientstate = UPAPCS_INITIAL;
186 u->us_serverstate = UPAPSS_INITIAL;
187 }
188
189
190 /*
191 * upap_protrej - Peer doesn't speak this protocol.
192 *
193 * This shouldn't happen. In any case, pretend lower layer went down.
194 */
195 void
upap_protrej(unit)196 upap_protrej(unit)
197 int unit;
198 {
199 upap_state *u = &upap[unit];
200
201 if (u->us_clientstate == UPAPCS_AUTHREQ) {
202 syslog(LOG_ERR, "PAP authentication failed due to protocol-reject");
203 auth_withpeer_fail(unit, UPAP);
204 }
205 if (u->us_serverstate == UPAPSS_LISTEN) {
206 syslog(LOG_ERR, "PAP authentication of peer failed (protocol-reject)");
207 auth_peer_fail(unit, UPAP);
208 }
209 upap_lowerdown(unit);
210 }
211
212
213 /*
214 * upap_input - Input UPAP packet.
215 */
216 void
upap_input(unit,inpacket,l)217 upap_input(unit, inpacket, l)
218 int unit;
219 u_char *inpacket;
220 int l;
221 {
222 upap_state *u = &upap[unit];
223 u_char *inp;
224 u_char code, id;
225 int len;
226
227 /*
228 * Parse header (code, id and length).
229 * If packet too short, drop it.
230 */
231 inp = inpacket;
232 if (l < UPAP_HEADERLEN) {
233 UPAPDEBUG((LOG_INFO, "upap_input: rcvd short header."));
234 return;
235 }
236 GETCHAR(code, inp);
237 GETCHAR(id, inp);
238 GETSHORT(len, inp);
239 if (len < UPAP_HEADERLEN) {
240 UPAPDEBUG((LOG_INFO, "upap_input: rcvd illegal length."));
241 return;
242 }
243 if (len > l) {
244 UPAPDEBUG((LOG_INFO, "upap_input: rcvd short packet."));
245 return;
246 }
247 len -= UPAP_HEADERLEN;
248
249 /*
250 * Action depends on code.
251 */
252 switch (code) {
253 case UPAP_AUTHREQ:
254 upap_rauthreq(u, inp, id, len);
255 break;
256
257 case UPAP_AUTHACK:
258 upap_rauthack(u, inp, id, len);
259 break;
260
261 case UPAP_AUTHNAK:
262 upap_rauthnak(u, inp, id, len);
263 break;
264
265 default: /* XXX Need code reject */
266 break;
267 }
268 }
269
270
271 /*
272 * upap_rauth - Receive Authenticate.
273 */
274 static void
upap_rauthreq(u,inp,id,len)275 upap_rauthreq(u, inp, id, len)
276 upap_state *u;
277 u_char *inp;
278 int id;
279 int len;
280 {
281 u_char ruserlen, rpasswdlen;
282 char *ruser, *rpasswd;
283 int retcode;
284 char *msg;
285 int msglen;
286
287 UPAPDEBUG((LOG_INFO, "upap_rauth: Rcvd id %d.", id));
288
289 if (u->us_serverstate < UPAPSS_LISTEN)
290 return;
291
292 /*
293 * If we receive a duplicate authenticate-request, we are
294 * supposed to return the same status as for the first request.
295 */
296 if (u->us_serverstate == UPAPSS_OPEN) {
297 upap_sresp(u, UPAP_AUTHACK, id, "", 0); /* return auth-ack */
298 return;
299 }
300 if (u->us_serverstate == UPAPSS_BADAUTH) {
301 upap_sresp(u, UPAP_AUTHNAK, id, "", 0); /* return auth-nak */
302 return;
303 }
304
305 /*
306 * Parse user/passwd.
307 */
308 if (len < sizeof (u_char)) {
309 UPAPDEBUG((LOG_INFO, "upap_rauth: rcvd short packet."));
310 return;
311 }
312 GETCHAR(ruserlen, inp);
313 len -= sizeof (u_char) + ruserlen + sizeof (u_char);
314 if (len < 0) {
315 UPAPDEBUG((LOG_INFO, "upap_rauth: rcvd short packet."));
316 return;
317 }
318 ruser = (char *) inp;
319 INCPTR(ruserlen, inp);
320 GETCHAR(rpasswdlen, inp);
321 if (len < rpasswdlen) {
322 UPAPDEBUG((LOG_INFO, "upap_rauth: rcvd short packet."));
323 return;
324 }
325 rpasswd = (char *) inp;
326
327 /*
328 * Check the username and password given.
329 */
330 retcode = check_passwd(u->us_unit, ruser, ruserlen, rpasswd,
331 rpasswdlen, &msg, &msglen);
332
333 upap_sresp(u, retcode, id, msg, msglen);
334
335 if (retcode == UPAP_AUTHACK) {
336 u->us_serverstate = UPAPSS_OPEN;
337 auth_peer_success(u->us_unit, UPAP);
338 } else {
339 u->us_serverstate = UPAPSS_BADAUTH;
340 auth_peer_fail(u->us_unit, UPAP);
341 }
342 }
343
344
345 /*
346 * upap_rauthack - Receive Authenticate-Ack.
347 */
348 static void
upap_rauthack(u,inp,id,len)349 upap_rauthack(u, inp, id, len)
350 upap_state *u;
351 u_char *inp;
352 int id;
353 int len;
354 {
355 u_char msglen;
356 char *msg;
357
358 UPAPDEBUG((LOG_INFO, "upap_rauthack: Rcvd id %d.", id));
359 if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */
360 return;
361
362 /*
363 * Parse message.
364 */
365 if (len < sizeof (u_char)) {
366 UPAPDEBUG((LOG_INFO, "upap_rauthack: rcvd short packet."));
367 return;
368 }
369 GETCHAR(msglen, inp);
370 len -= sizeof (u_char);
371 if (len < msglen) {
372 UPAPDEBUG((LOG_INFO, "upap_rauthack: rcvd short packet."));
373 return;
374 }
375 msg = (char *) inp;
376 PRINTMSG(msg, msglen);
377
378 u->us_clientstate = UPAPCS_OPEN;
379
380 auth_withpeer_success(u->us_unit, UPAP);
381 }
382
383
384 /*
385 * upap_rauthnak - Receive Authenticate-Nakk.
386 */
387 static void
upap_rauthnak(u,inp,id,len)388 upap_rauthnak(u, inp, id, len)
389 upap_state *u;
390 u_char *inp;
391 int id;
392 int len;
393 {
394 u_char msglen;
395 char *msg;
396
397 UPAPDEBUG((LOG_INFO, "upap_rauthnak: Rcvd id %d.", id));
398 if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */
399 return;
400
401 /*
402 * Parse message.
403 */
404 if (len < sizeof (u_char)) {
405 UPAPDEBUG((LOG_INFO, "upap_rauthnak: rcvd short packet."));
406 return;
407 }
408 GETCHAR(msglen, inp);
409 len -= sizeof (u_char);
410 if (len < msglen) {
411 UPAPDEBUG((LOG_INFO, "upap_rauthnak: rcvd short packet."));
412 return;
413 }
414 msg = (char *) inp;
415 PRINTMSG(msg, msglen);
416
417 u->us_clientstate = UPAPCS_BADAUTH;
418
419 syslog(LOG_ERR, "PAP authentication failed");
420 auth_withpeer_fail(u->us_unit, UPAP);
421 }
422
423
424 /*
425 * upap_sauthreq - Send an Authenticate-Request.
426 */
427 static void
upap_sauthreq(u)428 upap_sauthreq(u)
429 upap_state *u;
430 {
431 u_char *outp;
432 int outlen;
433
434 outlen = UPAP_HEADERLEN + 2 * sizeof (u_char) +
435 u->us_userlen + u->us_passwdlen;
436 outp = outpacket_buf;
437
438 MAKEHEADER(outp, UPAP);
439
440 PUTCHAR(UPAP_AUTHREQ, outp);
441 PUTCHAR(++u->us_id, outp);
442 PUTSHORT(outlen, outp);
443 PUTCHAR(u->us_userlen, outp);
444 BCOPY(u->us_user, outp, u->us_userlen);
445 INCPTR(u->us_userlen, outp);
446 PUTCHAR(u->us_passwdlen, outp);
447 BCOPY(u->us_passwd, outp, u->us_passwdlen);
448
449 output(u->us_unit, outpacket_buf, outlen + DLLHEADERLEN);
450
451 UPAPDEBUG((LOG_INFO, "upap_sauth: Sent id %d.", u->us_id));
452
453 TIMEOUT(upap_timeout, (caddr_t) u, u->us_timeouttime);
454 ++u->us_transmits;
455 u->us_clientstate = UPAPCS_AUTHREQ;
456 }
457
458
459 /*
460 * upap_sresp - Send a response (ack or nak).
461 */
462 static void
upap_sresp(u,code,id,msg,msglen)463 upap_sresp(u, code, id, msg, msglen)
464 upap_state *u;
465 u_char code, id;
466 char *msg;
467 int msglen;
468 {
469 u_char *outp;
470 int outlen;
471
472 outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen;
473 outp = outpacket_buf;
474 MAKEHEADER(outp, UPAP);
475
476 PUTCHAR(code, outp);
477 PUTCHAR(id, outp);
478 PUTSHORT(outlen, outp);
479 PUTCHAR(msglen, outp);
480 BCOPY(msg, outp, msglen);
481 output(u->us_unit, outpacket_buf, outlen + DLLHEADERLEN);
482
483 UPAPDEBUG((LOG_INFO, "upap_sresp: Sent code %d, id %d.", code, id));
484 }
485
486 /*
487 * upap_printpkt - print the contents of a PAP packet.
488 */
489 char *upap_codenames[] = {
490 "AuthReq", "AuthAck", "AuthNak"
491 };
492
493 int
upap_printpkt(p,plen,printer,arg)494 upap_printpkt(p, plen, printer, arg)
495 u_char *p;
496 int plen;
497 void (*printer) __ARGS((void *, char *, ...));
498 void *arg;
499 {
500 int code, id, len;
501 int mlen, ulen, wlen;
502 char *user, *pwd, *msg;
503 u_char *pstart;
504
505 if (plen < UPAP_HEADERLEN)
506 return 0;
507 pstart = p;
508 GETCHAR(code, p);
509 GETCHAR(id, p);
510 GETSHORT(len, p);
511 if (len < UPAP_HEADERLEN || len > plen)
512 return 0;
513
514 if (code >= 1 && code <= sizeof(upap_codenames) / sizeof(char *))
515 printer(arg, " %s", upap_codenames[code-1]);
516 else
517 printer(arg, " code=0x%x", code);
518 printer(arg, " id=0x%x", id);
519 len -= UPAP_HEADERLEN;
520 switch (code) {
521 case UPAP_AUTHREQ:
522 if (len < 1)
523 break;
524 ulen = p[0];
525 if (len < ulen + 2)
526 break;
527 wlen = p[ulen + 1];
528 if (len < ulen + wlen + 2)
529 break;
530 user = (char *) (p + 1);
531 pwd = (char *) (p + ulen + 2);
532 p += ulen + wlen + 2;
533 len -= ulen + wlen + 2;
534 printer(arg, " user=");
535 print_string(user, ulen, printer, arg);
536 printer(arg, " password=");
537 print_string(pwd, wlen, printer, arg);
538 break;
539 case UPAP_AUTHACK:
540 case UPAP_AUTHNAK:
541 if (len < 1)
542 break;
543 mlen = p[0];
544 if (len < mlen + 1)
545 break;
546 msg = (char *) (p + 1);
547 p += mlen + 1;
548 len -= mlen + 1;
549 printer(arg, "msg=");
550 print_string(msg, mlen, printer, arg);
551 break;
552 }
553
554 /* print the rest of the bytes in the packet */
555 for (; len > 0; --len) {
556 GETCHAR(code, p);
557 printer(arg, " %.2x", code);
558 }
559
560 return p - pstart;
561 }
562