1 /*
2 * upap.c - User/Password Authentication Protocol.
3 *
4 * Copyright (c) 2000 by Sun Microsystems, Inc.
5 * All rights reserved.
6 *
7 * Permission to use, copy, modify, and distribute this software and its
8 * documentation is hereby granted, provided that the above copyright
9 * notice appears in all copies.
10 *
11 * SUN MAKES NO REPRESENTATION OR WARRANTIES ABOUT THE SUITABILITY OF
12 * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
13 * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
14 * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
15 * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
16 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES
17 *
18 * Copyright (c) 1989 Carnegie Mellon University.
19 * All rights reserved.
20 *
21 * Redistribution and use in source and binary forms are permitted
22 * provided that the above copyright notice and this paragraph are
23 * duplicated in all such forms and that any documentation,
24 * advertising materials, and other materials related to such
25 * distribution and use acknowledge that the software was developed
26 * by Carnegie Mellon University. The name of the
27 * University may not be used to endorse or promote products derived
28 * from this software without specific prior written permission.
29 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
30 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
31 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
32 */
33
34 #pragma ident "%Z%%M% %I% %E% SMI"
35 #define RCSID "$Id: upap.c,v 1.23 1999/11/20 05:11:47 paulus Exp $"
36
37 #include <stdio.h>
38 #include <string.h>
39
40 #include "pppd.h"
41 #include "upap.h"
42
43 #if !defined(lint) && !defined(_lint)
44 static const char rcsid[] = RCSID;
45 #endif
46
47 static bool hide_password = 1;
48
49 /*
50 * Command-line options.
51 */
52 static option_t pap_option_list[] = {
53 { "hide-password", o_bool, &hide_password,
54 "Don't output passwords to log", 1 },
55 { "show-password", o_bool, &hide_password,
56 "Show password string in debug log messages", 0 },
57 { "pap-restart", o_int, &upap[0].us_timeouttime,
58 "Set retransmit timeout for PAP" },
59 { "pap-max-authreq", o_int, &upap[0].us_maxtransmits,
60 "Max number of PAP Authenticate-Request sent" },
61 { "pap-max-receive", o_int, &upap[0].us_maxreceives,
62 "Max allowable PAP Authenticate-Request received" },
63 { "pap-timeout", o_int, &upap[0].us_reqtimeout,
64 "Set time limit for peer PAP authentication" },
65 { NULL }
66 };
67
68 /*
69 * Protocol entry points.
70 */
71 static void upap_init __P((int));
72 static void upap_lowerup __P((int));
73 static void upap_lowerdown __P((int));
74 static void upap_input __P((int, u_char *, int));
75 static void upap_protrej __P((int));
76 static int upap_printpkt __P((u_char *, int,
77 void (*) __P((void *, const char *, ...)), void *));
78
79 struct protent pap_protent = {
80 PPP_PAP,
81 upap_init,
82 upap_input,
83 upap_protrej,
84 upap_lowerup,
85 upap_lowerdown,
86 NULL,
87 NULL,
88 upap_printpkt,
89 NULL,
90 1,
91 "PAP",
92 NULL,
93 pap_option_list,
94 NULL,
95 NULL,
96 NULL
97 };
98
99 upap_state upap[NUM_PPP]; /* UPAP state; one for each unit */
100
101 static void upap_timeout __P((void *));
102 static void upap_reqtimeout __P((void *));
103 static void upap_rauthreq __P((upap_state *, u_char *, int, int));
104 static void upap_rauthack __P((upap_state *, u_char *, int, int));
105 static void upap_rauthnak __P((upap_state *, u_char *, int, int));
106 static void upap_sauthreq __P((upap_state *));
107 static void upap_sresp __P((upap_state *, int, int, char *, int));
108
109 static const char *
pap_cstate(clientstate)110 pap_cstate(clientstate)
111 int clientstate;
112 {
113 static const char *cstate[] = { UPAPCS__NAMES };
114 static char buf[32];
115
116 if (clientstate < 0 || clientstate >= Dim(cstate)) {
117 (void) slprintf(buf, sizeof (buf), "Cli#%d", clientstate);
118 return ((const char *)buf);
119 }
120 return (cstate[clientstate]);
121 }
122
123 static const char *
pap_sstate(serverstate)124 pap_sstate(serverstate)
125 int serverstate;
126 {
127 static const char *sstate[] = { UPAPSS__NAMES };
128 static char buf[32];
129
130 if (serverstate < 0 || serverstate >= Dim(sstate)) {
131 (void) slprintf(buf, sizeof (buf), "Srv#%d", serverstate);
132 return ((const char *)buf);
133 }
134 return (sstate[serverstate]);
135 }
136
137 /*
138 * upap_init - Initialize a UPAP unit.
139 */
140 static void
upap_init(unit)141 upap_init(unit)
142 int unit;
143 {
144 upap_state *u = &upap[unit];
145
146 u->us_unit = unit;
147 u->us_user = NULL;
148 u->us_userlen = 0;
149 u->us_passwd = NULL;
150 u->us_clientstate = UPAPCS_INITIAL;
151 u->us_serverstate = UPAPSS_INITIAL;
152 u->us_id = 0;
153 u->us_timeouttime = UPAP_DEFTIMEOUT;
154 u->us_maxtransmits = 10;
155 u->us_reqtimeout = UPAP_DEFREQTIME;
156 u->us_maxreceives = 3;
157 u->us_msg = "";
158 u->us_msglen = 0;
159 }
160
161
162 /*
163 * upap_authwithpeer - Authenticate us with our peer (start client).
164 *
165 * Set new state and send authenticate's.
166 */
167 void
upap_authwithpeer(unit,user,password)168 upap_authwithpeer(unit, user, password)
169 int unit;
170 char *user, *password;
171 {
172 upap_state *u = &upap[unit];
173
174 /* Save the username and password we're given */
175 u->us_user = user;
176 u->us_userlen = strlen(user);
177 u->us_passwd = password;
178 u->us_transmits = 0;
179
180 /* Lower layer up yet? */
181 if (u->us_clientstate == UPAPCS_INITIAL ||
182 u->us_clientstate == UPAPCS_PENDING) {
183 u->us_clientstate = UPAPCS_PENDING;
184 return;
185 }
186
187 upap_sauthreq(u); /* Start protocol */
188 }
189
190
191 /*
192 * upap_authpeer - Authenticate our peer (start server).
193 *
194 * Set new state.
195 */
196 void
upap_authpeer(unit)197 upap_authpeer(unit)
198 int unit;
199 {
200 upap_state *u = &upap[unit];
201
202 /* Lower layer up yet? */
203 if (u->us_serverstate == UPAPSS_INITIAL ||
204 u->us_serverstate == UPAPSS_PENDING) {
205 u->us_serverstate = UPAPSS_PENDING;
206 return;
207 }
208
209 u->us_serverstate = UPAPSS_LISTEN;
210 u->us_receives = 0;
211 if (u->us_reqtimeout > 0)
212 TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);
213 }
214
215
216 /*
217 * upap_timeout - Retransmission timer for sending auth-reqs expired.
218 */
219 static void
upap_timeout(arg)220 upap_timeout(arg)
221 void *arg;
222 {
223 upap_state *u = (upap_state *) arg;
224
225 if (u->us_clientstate != UPAPCS_AUTHREQ)
226 return;
227
228 if (u->us_transmits >= u->us_maxtransmits) {
229 /* give up in disgust */
230 error("No response to %d PAP Authenticate-Requests", u->us_transmits);
231 u->us_clientstate = UPAPCS_BADAUTH;
232 auth_withpeer_fail(u->us_unit, PPP_PAP);
233 return;
234 }
235
236 upap_sauthreq(u); /* Send Authenticate-Request */
237 }
238
239
240 /*
241 * upap_reqtimeout - Give up waiting for the peer to send a valid auth-req.
242 */
243 static void
upap_reqtimeout(arg)244 upap_reqtimeout(arg)
245 void *arg;
246 {
247 upap_state *u = (upap_state *) arg;
248
249 if (u->us_serverstate != UPAPSS_LISTEN)
250 return; /* huh?? */
251
252 auth_peer_fail(u->us_unit, PPP_PAP);
253 u->us_serverstate = UPAPSS_BADAUTH;
254 }
255
256
257 /*
258 * upap_lowerup - The lower layer is up.
259 *
260 * Start authenticating if pending.
261 */
262 static void
upap_lowerup(unit)263 upap_lowerup(unit)
264 int unit;
265 {
266 upap_state *u = &upap[unit];
267
268 if (u->us_clientstate == UPAPCS_INITIAL)
269 u->us_clientstate = UPAPCS_CLOSED;
270 else if (u->us_clientstate == UPAPCS_PENDING) {
271 upap_sauthreq(u); /* send an auth-request */
272 }
273
274 if (u->us_serverstate == UPAPSS_INITIAL)
275 u->us_serverstate = UPAPSS_CLOSED;
276 else if (u->us_serverstate == UPAPSS_PENDING) {
277 u->us_serverstate = UPAPSS_LISTEN;
278 if (u->us_reqtimeout > 0)
279 TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);
280 }
281 }
282
283
284 /*
285 * upap_lowerdown - The lower layer is down.
286 *
287 * Cancel all timeouts.
288 */
289 static void
upap_lowerdown(unit)290 upap_lowerdown(unit)
291 int unit;
292 {
293 upap_state *u = &upap[unit];
294
295 /* Cancel timeouts */
296 if (u->us_clientstate == UPAPCS_AUTHREQ && u->us_timeouttime > 0)
297 UNTIMEOUT(upap_timeout, u);
298 if (u->us_serverstate == UPAPSS_LISTEN && u->us_reqtimeout > 0)
299 UNTIMEOUT(upap_reqtimeout, u);
300
301 u->us_clientstate = UPAPCS_INITIAL;
302 u->us_serverstate = UPAPSS_INITIAL;
303 }
304
305
306 /*
307 * upap_protrej - Peer doesn't speak this protocol.
308 *
309 * This shouldn't happen. In any case, pretend lower layer went down.
310 */
311 static void
upap_protrej(unit)312 upap_protrej(unit)
313 int unit;
314 {
315 upap_state *u = &upap[unit];
316
317 if (u->us_clientstate == UPAPCS_AUTHREQ) {
318 error("PAP authentication failed due to protocol-reject");
319 auth_withpeer_fail(unit, PPP_PAP);
320 }
321 if (u->us_serverstate == UPAPSS_LISTEN) {
322 error("PAP authentication of peer failed (protocol-reject)");
323 auth_peer_fail(unit, PPP_PAP);
324 }
325 upap_lowerdown(unit);
326 }
327
328
329 /*
330 * upap_input - Input UPAP packet.
331 */
332 static void
upap_input(unit,inpacket,l)333 upap_input(unit, inpacket, l)
334 int unit;
335 u_char *inpacket;
336 int l;
337 {
338 upap_state *u = &upap[unit];
339 u_char *inp;
340 u_char code, id;
341 int len;
342
343 /*
344 * Parse header (code, id and length).
345 * If packet too short, drop it.
346 */
347 inp = inpacket;
348 if (l < UPAP_HEADERLEN) {
349 error("PAP: packet is too small (%d < %d)", l, UPAP_HEADERLEN);
350 return;
351 }
352 GETCHAR(code, inp);
353 GETCHAR(id, inp);
354 GETSHORT(len, inp);
355 if ((len < UPAP_HEADERLEN) || (len > l)) {
356 error("PAP: packet has illegal length %d (%d..%d)", len,
357 UPAP_HEADERLEN, l);
358 return;
359 }
360 len -= UPAP_HEADERLEN;
361
362 /*
363 * Action depends on code.
364 */
365 switch (code) {
366 case UPAP_AUTHREQ:
367 upap_rauthreq(u, inp, id, len);
368 break;
369
370 case UPAP_AUTHACK:
371 upap_rauthack(u, inp, id, len);
372 break;
373
374 case UPAP_AUTHNAK:
375 upap_rauthnak(u, inp, id, len);
376 break;
377
378 default:
379 warn("Unknown PAP code (%d) received.", code);
380 break;
381 }
382 }
383
384
385 /*
386 * upap_rauth - Receive Authenticate.
387 */
388 static void
upap_rauthreq(u,inp,id,len)389 upap_rauthreq(u, inp, id, len)
390 upap_state *u;
391 u_char *inp;
392 int id;
393 int len;
394 {
395 u_char ruserlen, rpasswdlen;
396 char *ruser, *rpasswd;
397 int retcode;
398 char *msg;
399 int msglen;
400
401 if (u->us_serverstate < UPAPSS_LISTEN) {
402 info("PAP: discarded Authenticate-Request in state %s",
403 pap_sstate(u->us_serverstate));
404 return;
405 }
406
407 /*
408 * If we receive a duplicate authenticate-request, we are
409 * supposed to return the same status as for the first request.
410 */
411 if (u->us_serverstate == UPAPSS_OPEN) {
412 /* return auth-ack */
413 upap_sresp(u, UPAP_AUTHACK, id, u->us_msg, u->us_msglen);
414 return;
415 }
416 if (u->us_serverstate == UPAPSS_BADAUTH) {
417 /* return auth-nak */
418 upap_sresp(u, UPAP_AUTHNAK, id, u->us_msg, u->us_msglen);
419 return;
420 }
421
422 /*
423 * Parse user/passwd.
424 */
425 if (len < 1) {
426 error("PAP: rcvd short packet; no data");
427 return;
428 }
429 GETCHAR(ruserlen, inp);
430 len -= sizeof (u_char) + ruserlen + sizeof (u_char);
431 if (len < 0) {
432 error("PAP: rcvd short packet; peer name missing");
433 return;
434 }
435 ruser = (char *) inp;
436 INCPTR(ruserlen, inp);
437 GETCHAR(rpasswdlen, inp);
438 if (len < rpasswdlen) {
439 error("PAP: rcvd short packet; pass len %d < %d", len, rpasswdlen);
440 return;
441 }
442 rpasswd = (char *) inp;
443
444 /*
445 * Check the username and password given.
446 */
447 retcode = check_passwd(u->us_unit, ruser, ruserlen, rpasswd,
448 rpasswdlen, &msg);
449 BZERO(rpasswd, rpasswdlen);
450 msglen = strlen(msg);
451 if (msglen > 255)
452 msglen = 255;
453
454 u->us_msg = msg;
455 u->us_msglen = msglen;
456 upap_sresp(u, retcode, id, u->us_msg, u->us_msglen);
457
458 if (retcode == UPAP_AUTHACK) {
459 u->us_serverstate = UPAPSS_OPEN;
460 auth_peer_success(u->us_unit, PPP_PAP, ruser, ruserlen);
461 } else if (++u->us_receives >= u->us_maxreceives) {
462 u->us_serverstate = UPAPSS_BADAUTH;
463 auth_peer_fail(u->us_unit, PPP_PAP);
464 } else {
465 /* Just wait for a good one to arrive, or for time-out. */
466 return;
467 }
468
469 if (u->us_reqtimeout > 0)
470 UNTIMEOUT(upap_reqtimeout, u);
471 }
472
473
474 /*
475 * upap_rauthack - Receive Authenticate-Ack.
476 */
477 /*ARGSUSED*/
478 static void
upap_rauthack(u,inp,id,len)479 upap_rauthack(u, inp, id, len)
480 upap_state *u;
481 u_char *inp;
482 int id;
483 int len;
484 {
485 u_char msglen;
486 char *msg;
487
488 if (u->us_clientstate != UPAPCS_AUTHREQ) {
489 info("PAP: discarded Authenticate-Ack in state %s",
490 pap_cstate(u->us_clientstate));
491 return;
492 }
493
494 if (id != u->us_id) {
495 dbglog("PAP: discard Authenticate-Ack; ID %d != %d",
496 id, u->us_id);
497 return;
498 }
499
500 if (u->us_timeouttime > 0)
501 UNTIMEOUT(upap_timeout, u);
502
503 /*
504 * Parse message.
505 */
506 if (len < 1) {
507 info("PAP: Ignoring missing ack msg-length octet");
508 } else {
509 GETCHAR(msglen, inp);
510 if (msglen > 0) {
511 len -= sizeof (u_char);
512 if (len < msglen) {
513 error("PAP: Discarding short packet (%d < %d)", len, msglen);
514 return;
515 }
516 msg = (char *) inp;
517 PRINTMSG(msg, msglen);
518 }
519 }
520
521 u->us_clientstate = UPAPCS_OPEN;
522
523 auth_withpeer_success(u->us_unit, PPP_PAP);
524 }
525
526
527 /*
528 * upap_rauthnak - Receive Authenticate-Nakk.
529 */
530 /*ARGSUSED*/
531 static void
upap_rauthnak(u,inp,id,len)532 upap_rauthnak(u, inp, id, len)
533 upap_state *u;
534 u_char *inp;
535 int id;
536 int len;
537 {
538 u_char msglen;
539 char *msg;
540
541 if (u->us_clientstate != UPAPCS_AUTHREQ) {
542 info("PAP: discarded Authenticate-Nak in state %s",
543 pap_cstate(u->us_clientstate));
544 return;
545 }
546
547 if (id != u->us_id) {
548 dbglog("PAP: discard Authenticate-Ack; ID %d != %d",
549 id, u->us_id);
550 return;
551 }
552
553 if (u->us_timeouttime > 0)
554 UNTIMEOUT(upap_timeout, u);
555
556 /*
557 * Parse message.
558 */
559 if (len < 1) {
560 error("PAP: ignoring missing nak msg-length octet");
561 } else {
562 GETCHAR(msglen, inp);
563 if (msglen > 0) {
564 len -= sizeof (u_char);
565 if (len < msglen) {
566 error("PAP: Discarding short packet (%d < %d)", len, msglen);
567 return;
568 }
569 msg = (char *) inp;
570 PRINTMSG(msg, msglen);
571 }
572 }
573
574 /* Try to get a new password from the plugin. */
575 if (pap_passwd_hook != NULL) {
576 if (u->us_transmits < u->us_maxtransmits) {
577 if ((*pap_passwd_hook)(user, passwd) >= 0) {
578 upap_sauthreq(u);
579 return;
580 }
581 } else {
582 /* Tell plug-in that we're giving up. */
583 (void) (*pap_passwd_hook)(NULL, NULL);
584 }
585 }
586
587 u->us_clientstate = UPAPCS_BADAUTH;
588
589 error("PAP authentication failed");
590 auth_withpeer_fail(u->us_unit, PPP_PAP);
591 }
592
593
594 /*
595 * upap_sauthreq - Send an Authenticate-Request.
596 */
597 static void
upap_sauthreq(u)598 upap_sauthreq(u)
599 upap_state *u;
600 {
601 u_char *outp;
602 int pwlen;
603 int outlen;
604
605 pwlen = strllen(passwd, MAXSECRETLEN);
606 if (pwlen > 0xFF)
607 pwlen = 0xFF;
608 outlen = UPAP_HEADERLEN + 2 * sizeof (u_char) + u->us_userlen + pwlen;
609 outp = outpacket_buf;
610
611 MAKEHEADER(outp, PPP_PAP);
612
613 PUTCHAR(UPAP_AUTHREQ, outp);
614 PUTCHAR(++u->us_id, outp);
615 PUTSHORT(outlen, outp);
616 PUTCHAR(u->us_userlen, outp);
617 BCOPY(u->us_user, outp, u->us_userlen);
618 INCPTR(u->us_userlen, outp);
619 PUTCHAR(pwlen, outp);
620 BCOPY(u->us_passwd, outp, pwlen);
621
622 output(u->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
623
624 if (u->us_timeouttime > 0)
625 TIMEOUT(upap_timeout, u, u->us_timeouttime);
626 ++u->us_transmits;
627 u->us_clientstate = UPAPCS_AUTHREQ;
628 }
629
630
631 /*
632 * upap_sresp - Send a response (ack or nak).
633 */
634 static void
upap_sresp(u,code,id,msg,msglen)635 upap_sresp(u, code, id, msg, msglen)
636 upap_state *u;
637 u_char code, id;
638 char *msg;
639 int msglen;
640 {
641 u_char *outp;
642 int outlen;
643
644 outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen;
645 outp = outpacket_buf;
646 MAKEHEADER(outp, PPP_PAP);
647
648 PUTCHAR(code, outp);
649 PUTCHAR(id, outp);
650 PUTSHORT(outlen, outp);
651 PUTCHAR(msglen, outp);
652 BCOPY(msg, outp, msglen);
653 output(u->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
654 }
655
656 /*
657 * upap_printpkt - print the contents of a PAP packet.
658 */
659 static char *upap_codenames[] = {
660 "AuthReq", "AuthAck", "AuthNak"
661 };
662
663 static int
upap_printpkt(p,plen,printer,arg)664 upap_printpkt(p, plen, printer, arg)
665 u_char *p;
666 int plen;
667 void (*printer) __P((void *, const char *, ...));
668 void *arg;
669 {
670 int code, id, len;
671 int mlen, ulen, wlen;
672 char *user, *pwd, *msg;
673 u_char *pstart;
674
675 if (plen < UPAP_HEADERLEN)
676 return (0);
677 pstart = p;
678 GETCHAR(code, p);
679 GETCHAR(id, p);
680 GETSHORT(len, p);
681 if (len < UPAP_HEADERLEN || len > plen)
682 return (0);
683
684 if (code >= 1 && code <= Dim(upap_codenames))
685 printer(arg, " %s", upap_codenames[code-1]);
686 else
687 printer(arg, " code=0x%x", code);
688 printer(arg, " id=0x%x", id);
689 len -= UPAP_HEADERLEN;
690 switch (code) {
691 case UPAP_AUTHREQ:
692 if (len < 1)
693 break;
694 ulen = p[0];
695 if (len < ulen + 2)
696 break;
697 wlen = p[ulen + 1];
698 if (len < ulen + wlen + 2)
699 break;
700 user = (char *) (p + 1);
701 pwd = (char *) (p + ulen + 2);
702 p += ulen + wlen + 2;
703 len -= ulen + wlen + 2;
704 printer(arg, " user=");
705 print_string(user, ulen, printer, arg);
706 printer(arg, " password=");
707 if (!hide_password)
708 print_string(pwd, wlen, printer, arg);
709 else
710 printer(arg, "<hidden>");
711 break;
712 case UPAP_AUTHACK:
713 case UPAP_AUTHNAK:
714 if (len < 1)
715 break;
716 mlen = p[0];
717 if (len < mlen + 1)
718 break;
719 msg = (char *) (p + 1);
720 p += mlen + 1;
721 len -= mlen + 1;
722 printer(arg, " ");
723 print_string(msg, mlen, printer, arg);
724 break;
725 }
726
727 /* print the rest of the bytes in the packet */
728 for (; len > 0; --len) {
729 GETCHAR(code, p);
730 printer(arg, " %.2x", code);
731 }
732
733 return (p - pstart);
734 }
735