dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / cmd-inet / usr.bin / pppd / upap.c
blob4fe387d4524ccfee689a6f4907a60dd3662c6c42
1 /*
2 * upap.c - User/Password Authentication Protocol.
4 * Copyright (c) 2000 by Sun Microsystems, Inc.
5 * All rights reserved.
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.
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
18 * Copyright (c) 1989 Carnegie Mellon University.
19 * All rights reserved.
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.
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 $"
37 #include <stdio.h>
38 #include <string.h>
40 #include "pppd.h"
41 #include "upap.h"
43 static const char rcsid[] = RCSID;
45 static bool hide_password = 1;
48 * Command-line options.
50 static option_t pap_option_list[] = {
51 { "hide-password", o_bool, &hide_password,
52 "Don't output passwords to log", 1 },
53 { "show-password", o_bool, &hide_password,
54 "Show password string in debug log messages", 0 },
55 { "pap-restart", o_int, &upap[0].us_timeouttime,
56 "Set retransmit timeout for PAP" },
57 { "pap-max-authreq", o_int, &upap[0].us_maxtransmits,
58 "Max number of PAP Authenticate-Request sent" },
59 { "pap-max-receive", o_int, &upap[0].us_maxreceives,
60 "Max allowable PAP Authenticate-Request received" },
61 { "pap-timeout", o_int, &upap[0].us_reqtimeout,
62 "Set time limit for peer PAP authentication" },
63 { NULL }
67 * Protocol entry points.
69 static void upap_init __P((int));
70 static void upap_lowerup __P((int));
71 static void upap_lowerdown __P((int));
72 static void upap_input __P((int, u_char *, int));
73 static void upap_protrej __P((int));
74 static int upap_printpkt __P((u_char *, int,
75 void (*) __P((void *, const char *, ...)), void *));
77 struct protent pap_protent = {
78 PPP_PAP,
79 upap_init,
80 upap_input,
81 upap_protrej,
82 upap_lowerup,
83 upap_lowerdown,
84 NULL,
85 NULL,
86 upap_printpkt,
87 NULL,
89 "PAP",
90 NULL,
91 pap_option_list,
92 NULL,
93 NULL,
94 NULL
97 upap_state upap[NUM_PPP]; /* UPAP state; one for each unit */
99 static void upap_timeout __P((void *));
100 static void upap_reqtimeout __P((void *));
101 static void upap_rauthreq __P((upap_state *, u_char *, int, int));
102 static void upap_rauthack __P((upap_state *, u_char *, int, int));
103 static void upap_rauthnak __P((upap_state *, u_char *, int, int));
104 static void upap_sauthreq __P((upap_state *));
105 static void upap_sresp __P((upap_state *, int, int, char *, int));
107 static const char *
108 pap_cstate(clientstate)
109 int clientstate;
111 static const char *cstate[] = { UPAPCS__NAMES };
112 static char buf[32];
114 if (clientstate < 0 || clientstate >= Dim(cstate)) {
115 (void) slprintf(buf, sizeof (buf), "Cli#%d", clientstate);
116 return ((const char *)buf);
118 return (cstate[clientstate]);
121 static const char *
122 pap_sstate(serverstate)
123 int serverstate;
125 static const char *sstate[] = { UPAPSS__NAMES };
126 static char buf[32];
128 if (serverstate < 0 || serverstate >= Dim(sstate)) {
129 (void) slprintf(buf, sizeof (buf), "Srv#%d", serverstate);
130 return ((const char *)buf);
132 return (sstate[serverstate]);
136 * upap_init - Initialize a UPAP unit.
138 static void
139 upap_init(unit)
140 int unit;
142 upap_state *u = &upap[unit];
144 u->us_unit = unit;
145 u->us_user = NULL;
146 u->us_userlen = 0;
147 u->us_passwd = NULL;
148 u->us_clientstate = UPAPCS_INITIAL;
149 u->us_serverstate = UPAPSS_INITIAL;
150 u->us_id = 0;
151 u->us_timeouttime = UPAP_DEFTIMEOUT;
152 u->us_maxtransmits = 10;
153 u->us_reqtimeout = UPAP_DEFREQTIME;
154 u->us_maxreceives = 3;
155 u->us_msg = "";
156 u->us_msglen = 0;
161 * upap_authwithpeer - Authenticate us with our peer (start client).
163 * Set new state and send authenticate's.
165 void
166 upap_authwithpeer(unit, user, password)
167 int unit;
168 char *user, *password;
170 upap_state *u = &upap[unit];
172 /* Save the username and password we're given */
173 u->us_user = user;
174 u->us_userlen = strlen(user);
175 u->us_passwd = password;
176 u->us_transmits = 0;
178 /* Lower layer up yet? */
179 if (u->us_clientstate == UPAPCS_INITIAL ||
180 u->us_clientstate == UPAPCS_PENDING) {
181 u->us_clientstate = UPAPCS_PENDING;
182 return;
185 upap_sauthreq(u); /* Start protocol */
190 * upap_authpeer - Authenticate our peer (start server).
192 * Set new state.
194 void
195 upap_authpeer(unit)
196 int unit;
198 upap_state *u = &upap[unit];
200 /* Lower layer up yet? */
201 if (u->us_serverstate == UPAPSS_INITIAL ||
202 u->us_serverstate == UPAPSS_PENDING) {
203 u->us_serverstate = UPAPSS_PENDING;
204 return;
207 u->us_serverstate = UPAPSS_LISTEN;
208 u->us_receives = 0;
209 if (u->us_reqtimeout > 0)
210 TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);
215 * upap_timeout - Retransmission timer for sending auth-reqs expired.
217 static void
218 upap_timeout(arg)
219 void *arg;
221 upap_state *u = (upap_state *) arg;
223 if (u->us_clientstate != UPAPCS_AUTHREQ)
224 return;
226 if (u->us_transmits >= u->us_maxtransmits) {
227 /* give up in disgust */
228 error("No response to %d PAP Authenticate-Requests", u->us_transmits);
229 u->us_clientstate = UPAPCS_BADAUTH;
230 auth_withpeer_fail(u->us_unit, PPP_PAP);
231 return;
234 upap_sauthreq(u); /* Send Authenticate-Request */
239 * upap_reqtimeout - Give up waiting for the peer to send a valid auth-req.
241 static void
242 upap_reqtimeout(arg)
243 void *arg;
245 upap_state *u = (upap_state *) arg;
247 if (u->us_serverstate != UPAPSS_LISTEN)
248 return; /* huh?? */
250 auth_peer_fail(u->us_unit, PPP_PAP);
251 u->us_serverstate = UPAPSS_BADAUTH;
256 * upap_lowerup - The lower layer is up.
258 * Start authenticating if pending.
260 static void
261 upap_lowerup(unit)
262 int unit;
264 upap_state *u = &upap[unit];
266 if (u->us_clientstate == UPAPCS_INITIAL)
267 u->us_clientstate = UPAPCS_CLOSED;
268 else if (u->us_clientstate == UPAPCS_PENDING) {
269 upap_sauthreq(u); /* send an auth-request */
272 if (u->us_serverstate == UPAPSS_INITIAL)
273 u->us_serverstate = UPAPSS_CLOSED;
274 else if (u->us_serverstate == UPAPSS_PENDING) {
275 u->us_serverstate = UPAPSS_LISTEN;
276 if (u->us_reqtimeout > 0)
277 TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);
283 * upap_lowerdown - The lower layer is down.
285 * Cancel all timeouts.
287 static void
288 upap_lowerdown(unit)
289 int unit;
291 upap_state *u = &upap[unit];
293 /* Cancel timeouts */
294 if (u->us_clientstate == UPAPCS_AUTHREQ && u->us_timeouttime > 0)
295 UNTIMEOUT(upap_timeout, u);
296 if (u->us_serverstate == UPAPSS_LISTEN && u->us_reqtimeout > 0)
297 UNTIMEOUT(upap_reqtimeout, u);
299 u->us_clientstate = UPAPCS_INITIAL;
300 u->us_serverstate = UPAPSS_INITIAL;
305 * upap_protrej - Peer doesn't speak this protocol.
307 * This shouldn't happen. In any case, pretend lower layer went down.
309 static void
310 upap_protrej(unit)
311 int unit;
313 upap_state *u = &upap[unit];
315 if (u->us_clientstate == UPAPCS_AUTHREQ) {
316 error("PAP authentication failed due to protocol-reject");
317 auth_withpeer_fail(unit, PPP_PAP);
319 if (u->us_serverstate == UPAPSS_LISTEN) {
320 error("PAP authentication of peer failed (protocol-reject)");
321 auth_peer_fail(unit, PPP_PAP);
323 upap_lowerdown(unit);
328 * upap_input - Input UPAP packet.
330 static void
331 upap_input(unit, inpacket, l)
332 int unit;
333 u_char *inpacket;
334 int l;
336 upap_state *u = &upap[unit];
337 u_char *inp;
338 u_char code, id;
339 int len;
342 * Parse header (code, id and length).
343 * If packet too short, drop it.
345 inp = inpacket;
346 if (l < UPAP_HEADERLEN) {
347 error("PAP: packet is too small (%d < %d)", l, UPAP_HEADERLEN);
348 return;
350 GETCHAR(code, inp);
351 GETCHAR(id, inp);
352 GETSHORT(len, inp);
353 if ((len < UPAP_HEADERLEN) || (len > l)) {
354 error("PAP: packet has illegal length %d (%d..%d)", len,
355 UPAP_HEADERLEN, l);
356 return;
358 len -= UPAP_HEADERLEN;
361 * Action depends on code.
363 switch (code) {
364 case UPAP_AUTHREQ:
365 upap_rauthreq(u, inp, id, len);
366 break;
368 case UPAP_AUTHACK:
369 upap_rauthack(u, inp, id, len);
370 break;
372 case UPAP_AUTHNAK:
373 upap_rauthnak(u, inp, id, len);
374 break;
376 default:
377 warn("Unknown PAP code (%d) received.", code);
378 break;
384 * upap_rauth - Receive Authenticate.
386 static void
387 upap_rauthreq(u, inp, id, len)
388 upap_state *u;
389 u_char *inp;
390 int id;
391 int len;
393 u_char ruserlen, rpasswdlen;
394 char *ruser, *rpasswd;
395 int retcode;
396 char *msg;
397 int msglen;
399 if (u->us_serverstate < UPAPSS_LISTEN) {
400 info("PAP: discarded Authenticate-Request in state %s",
401 pap_sstate(u->us_serverstate));
402 return;
406 * If we receive a duplicate authenticate-request, we are
407 * supposed to return the same status as for the first request.
409 if (u->us_serverstate == UPAPSS_OPEN) {
410 /* return auth-ack */
411 upap_sresp(u, UPAP_AUTHACK, id, u->us_msg, u->us_msglen);
412 return;
414 if (u->us_serverstate == UPAPSS_BADAUTH) {
415 /* return auth-nak */
416 upap_sresp(u, UPAP_AUTHNAK, id, u->us_msg, u->us_msglen);
417 return;
421 * Parse user/passwd.
423 if (len < 1) {
424 error("PAP: rcvd short packet; no data");
425 return;
427 GETCHAR(ruserlen, inp);
428 len -= sizeof (u_char) + ruserlen + sizeof (u_char);
429 if (len < 0) {
430 error("PAP: rcvd short packet; peer name missing");
431 return;
433 ruser = (char *) inp;
434 INCPTR(ruserlen, inp);
435 GETCHAR(rpasswdlen, inp);
436 if (len < rpasswdlen) {
437 error("PAP: rcvd short packet; pass len %d < %d", len, rpasswdlen);
438 return;
440 rpasswd = (char *) inp;
443 * Check the username and password given.
445 retcode = check_passwd(u->us_unit, ruser, ruserlen, rpasswd,
446 rpasswdlen, &msg);
447 BZERO(rpasswd, rpasswdlen);
448 msglen = strlen(msg);
449 if (msglen > 255)
450 msglen = 255;
452 u->us_msg = msg;
453 u->us_msglen = msglen;
454 upap_sresp(u, retcode, id, u->us_msg, u->us_msglen);
456 if (retcode == UPAP_AUTHACK) {
457 u->us_serverstate = UPAPSS_OPEN;
458 auth_peer_success(u->us_unit, PPP_PAP, ruser, ruserlen);
459 } else if (++u->us_receives >= u->us_maxreceives) {
460 u->us_serverstate = UPAPSS_BADAUTH;
461 auth_peer_fail(u->us_unit, PPP_PAP);
462 } else {
463 /* Just wait for a good one to arrive, or for time-out. */
464 return;
467 if (u->us_reqtimeout > 0)
468 UNTIMEOUT(upap_reqtimeout, u);
473 * upap_rauthack - Receive Authenticate-Ack.
475 /*ARGSUSED*/
476 static void
477 upap_rauthack(u, inp, id, len)
478 upap_state *u;
479 u_char *inp;
480 int id;
481 int len;
483 u_char msglen;
484 char *msg;
486 if (u->us_clientstate != UPAPCS_AUTHREQ) {
487 info("PAP: discarded Authenticate-Ack in state %s",
488 pap_cstate(u->us_clientstate));
489 return;
492 if (id != u->us_id) {
493 dbglog("PAP: discard Authenticate-Ack; ID %d != %d",
494 id, u->us_id);
495 return;
498 if (u->us_timeouttime > 0)
499 UNTIMEOUT(upap_timeout, u);
502 * Parse message.
504 if (len < 1) {
505 info("PAP: Ignoring missing ack msg-length octet");
506 } else {
507 GETCHAR(msglen, inp);
508 if (msglen > 0) {
509 len -= sizeof (u_char);
510 if (len < msglen) {
511 error("PAP: Discarding short packet (%d < %d)", len, msglen);
512 return;
514 msg = (char *) inp;
515 PRINTMSG(msg, msglen);
519 u->us_clientstate = UPAPCS_OPEN;
521 auth_withpeer_success(u->us_unit, PPP_PAP);
526 * upap_rauthnak - Receive Authenticate-Nakk.
528 /*ARGSUSED*/
529 static void
530 upap_rauthnak(u, inp, id, len)
531 upap_state *u;
532 u_char *inp;
533 int id;
534 int len;
536 u_char msglen;
537 char *msg;
539 if (u->us_clientstate != UPAPCS_AUTHREQ) {
540 info("PAP: discarded Authenticate-Nak in state %s",
541 pap_cstate(u->us_clientstate));
542 return;
545 if (id != u->us_id) {
546 dbglog("PAP: discard Authenticate-Ack; ID %d != %d",
547 id, u->us_id);
548 return;
551 if (u->us_timeouttime > 0)
552 UNTIMEOUT(upap_timeout, u);
555 * Parse message.
557 if (len < 1) {
558 error("PAP: ignoring missing nak msg-length octet");
559 } else {
560 GETCHAR(msglen, inp);
561 if (msglen > 0) {
562 len -= sizeof (u_char);
563 if (len < msglen) {
564 error("PAP: Discarding short packet (%d < %d)", len, msglen);
565 return;
567 msg = (char *) inp;
568 PRINTMSG(msg, msglen);
572 /* Try to get a new password from the plugin. */
573 if (pap_passwd_hook != NULL) {
574 if (u->us_transmits < u->us_maxtransmits) {
575 if ((*pap_passwd_hook)(user, passwd) >= 0) {
576 upap_sauthreq(u);
577 return;
579 } else {
580 /* Tell plug-in that we're giving up. */
581 (void) (*pap_passwd_hook)(NULL, NULL);
585 u->us_clientstate = UPAPCS_BADAUTH;
587 error("PAP authentication failed");
588 auth_withpeer_fail(u->us_unit, PPP_PAP);
593 * upap_sauthreq - Send an Authenticate-Request.
595 static void
596 upap_sauthreq(u)
597 upap_state *u;
599 u_char *outp;
600 int pwlen;
601 int outlen;
603 pwlen = strllen(passwd, MAXSECRETLEN);
604 if (pwlen > 0xFF)
605 pwlen = 0xFF;
606 outlen = UPAP_HEADERLEN + 2 * sizeof (u_char) + u->us_userlen + pwlen;
607 outp = outpacket_buf;
609 MAKEHEADER(outp, PPP_PAP);
611 PUTCHAR(UPAP_AUTHREQ, outp);
612 PUTCHAR(++u->us_id, outp);
613 PUTSHORT(outlen, outp);
614 PUTCHAR(u->us_userlen, outp);
615 BCOPY(u->us_user, outp, u->us_userlen);
616 INCPTR(u->us_userlen, outp);
617 PUTCHAR(pwlen, outp);
618 BCOPY(u->us_passwd, outp, pwlen);
620 output(u->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
622 if (u->us_timeouttime > 0)
623 TIMEOUT(upap_timeout, u, u->us_timeouttime);
624 ++u->us_transmits;
625 u->us_clientstate = UPAPCS_AUTHREQ;
630 * upap_sresp - Send a response (ack or nak).
632 static void
633 upap_sresp(u, code, id, msg, msglen)
634 upap_state *u;
635 u_char code, id;
636 char *msg;
637 int msglen;
639 u_char *outp;
640 int outlen;
642 outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen;
643 outp = outpacket_buf;
644 MAKEHEADER(outp, PPP_PAP);
646 PUTCHAR(code, outp);
647 PUTCHAR(id, outp);
648 PUTSHORT(outlen, outp);
649 PUTCHAR(msglen, outp);
650 BCOPY(msg, outp, msglen);
651 output(u->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
655 * upap_printpkt - print the contents of a PAP packet.
657 static char *upap_codenames[] = {
658 "AuthReq", "AuthAck", "AuthNak"
661 static int
662 upap_printpkt(p, plen, printer, arg)
663 u_char *p;
664 int plen;
665 void (*printer) __P((void *, const char *, ...));
666 void *arg;
668 int code, id, len;
669 int mlen, ulen, wlen;
670 char *user, *pwd, *msg;
671 u_char *pstart;
673 if (plen < UPAP_HEADERLEN)
674 return (0);
675 pstart = p;
676 GETCHAR(code, p);
677 GETCHAR(id, p);
678 GETSHORT(len, p);
679 if (len < UPAP_HEADERLEN || len > plen)
680 return (0);
682 if (code >= 1 && code <= Dim(upap_codenames))
683 printer(arg, " %s", upap_codenames[code-1]);
684 else
685 printer(arg, " code=0x%x", code);
686 printer(arg, " id=0x%x", id);
687 len -= UPAP_HEADERLEN;
688 switch (code) {
689 case UPAP_AUTHREQ:
690 if (len < 1)
691 break;
692 ulen = p[0];
693 if (len < ulen + 2)
694 break;
695 wlen = p[ulen + 1];
696 if (len < ulen + wlen + 2)
697 break;
698 user = (char *) (p + 1);
699 pwd = (char *) (p + ulen + 2);
700 p += ulen + wlen + 2;
701 len -= ulen + wlen + 2;
702 printer(arg, " user=");
703 print_string(user, ulen, printer, arg);
704 printer(arg, " password=");
705 if (!hide_password)
706 print_string(pwd, wlen, printer, arg);
707 else
708 printer(arg, "<hidden>");
709 break;
710 case UPAP_AUTHACK:
711 case UPAP_AUTHNAK:
712 if (len < 1)
713 break;
714 mlen = p[0];
715 if (len < mlen + 1)
716 break;
717 msg = (char *) (p + 1);
718 p += mlen + 1;
719 len -= mlen + 1;
720 printer(arg, " ");
721 print_string(msg, mlen, printer, arg);
722 break;
725 /* print the rest of the bytes in the packet */
726 for (; len > 0; --len) {
727 GETCHAR(code, p);
728 printer(arg, " %.2x", code);
731 return (p - pstart);