Move /var/svc/log to /var/log/svc
[unleashed/lotheac.git] / usr / src / cmd / cmd-inet / usr.bin / pppd / upap.c
blob585f57d31f44b198ee477f144e15fa8a5f339897
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 #include <stdio.h>
35 #include <string.h>
37 #include "pppd.h"
38 #include "upap.h"
40 static bool hide_password = 1;
43 * Command-line options.
45 static option_t pap_option_list[] = {
46 { "hide-password", o_bool, &hide_password,
47 "Don't output passwords to log", 1 },
48 { "show-password", o_bool, &hide_password,
49 "Show password string in debug log messages", 0 },
50 { "pap-restart", o_int, &upap[0].us_timeouttime,
51 "Set retransmit timeout for PAP" },
52 { "pap-max-authreq", o_int, &upap[0].us_maxtransmits,
53 "Max number of PAP Authenticate-Request sent" },
54 { "pap-max-receive", o_int, &upap[0].us_maxreceives,
55 "Max allowable PAP Authenticate-Request received" },
56 { "pap-timeout", o_int, &upap[0].us_reqtimeout,
57 "Set time limit for peer PAP authentication" },
58 { NULL }
62 * Protocol entry points.
64 static void upap_init __P((int));
65 static void upap_lowerup __P((int));
66 static void upap_lowerdown __P((int));
67 static void upap_input __P((int, u_char *, int));
68 static void upap_protrej __P((int));
69 static int upap_printpkt __P((u_char *, int,
70 void (*) __P((void *, const char *, ...)), void *));
72 struct protent pap_protent = {
73 PPP_PAP,
74 upap_init,
75 upap_input,
76 upap_protrej,
77 upap_lowerup,
78 upap_lowerdown,
79 NULL,
80 NULL,
81 upap_printpkt,
82 NULL,
84 "PAP",
85 NULL,
86 pap_option_list,
87 NULL,
88 NULL,
89 NULL
92 upap_state upap[NUM_PPP]; /* UPAP state; one for each unit */
94 static void upap_timeout __P((void *));
95 static void upap_reqtimeout __P((void *));
96 static void upap_rauthreq __P((upap_state *, u_char *, int, int));
97 static void upap_rauthack __P((upap_state *, u_char *, int, int));
98 static void upap_rauthnak __P((upap_state *, u_char *, int, int));
99 static void upap_sauthreq __P((upap_state *));
100 static void upap_sresp __P((upap_state *, int, int, char *, int));
102 static const char *
103 pap_cstate(clientstate)
104 int clientstate;
106 static const char *cstate[] = { UPAPCS__NAMES };
107 static char buf[32];
109 if (clientstate < 0 || clientstate >= Dim(cstate)) {
110 (void) slprintf(buf, sizeof (buf), "Cli#%d", clientstate);
111 return ((const char *)buf);
113 return (cstate[clientstate]);
116 static const char *
117 pap_sstate(serverstate)
118 int serverstate;
120 static const char *sstate[] = { UPAPSS__NAMES };
121 static char buf[32];
123 if (serverstate < 0 || serverstate >= Dim(sstate)) {
124 (void) slprintf(buf, sizeof (buf), "Srv#%d", serverstate);
125 return ((const char *)buf);
127 return (sstate[serverstate]);
131 * upap_init - Initialize a UPAP unit.
133 static void
134 upap_init(unit)
135 int unit;
137 upap_state *u = &upap[unit];
139 u->us_unit = unit;
140 u->us_user = NULL;
141 u->us_userlen = 0;
142 u->us_passwd = NULL;
143 u->us_clientstate = UPAPCS_INITIAL;
144 u->us_serverstate = UPAPSS_INITIAL;
145 u->us_id = 0;
146 u->us_timeouttime = UPAP_DEFTIMEOUT;
147 u->us_maxtransmits = 10;
148 u->us_reqtimeout = UPAP_DEFREQTIME;
149 u->us_maxreceives = 3;
150 u->us_msg = "";
151 u->us_msglen = 0;
156 * upap_authwithpeer - Authenticate us with our peer (start client).
158 * Set new state and send authenticate's.
160 void
161 upap_authwithpeer(unit, user, password)
162 int unit;
163 char *user, *password;
165 upap_state *u = &upap[unit];
167 /* Save the username and password we're given */
168 u->us_user = user;
169 u->us_userlen = strlen(user);
170 u->us_passwd = password;
171 u->us_transmits = 0;
173 /* Lower layer up yet? */
174 if (u->us_clientstate == UPAPCS_INITIAL ||
175 u->us_clientstate == UPAPCS_PENDING) {
176 u->us_clientstate = UPAPCS_PENDING;
177 return;
180 upap_sauthreq(u); /* Start protocol */
185 * upap_authpeer - Authenticate our peer (start server).
187 * Set new state.
189 void
190 upap_authpeer(unit)
191 int unit;
193 upap_state *u = &upap[unit];
195 /* Lower layer up yet? */
196 if (u->us_serverstate == UPAPSS_INITIAL ||
197 u->us_serverstate == UPAPSS_PENDING) {
198 u->us_serverstate = UPAPSS_PENDING;
199 return;
202 u->us_serverstate = UPAPSS_LISTEN;
203 u->us_receives = 0;
204 if (u->us_reqtimeout > 0)
205 TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);
210 * upap_timeout - Retransmission timer for sending auth-reqs expired.
212 static void
213 upap_timeout(arg)
214 void *arg;
216 upap_state *u = (upap_state *) arg;
218 if (u->us_clientstate != UPAPCS_AUTHREQ)
219 return;
221 if (u->us_transmits >= u->us_maxtransmits) {
222 /* give up in disgust */
223 error("No response to %d PAP Authenticate-Requests", u->us_transmits);
224 u->us_clientstate = UPAPCS_BADAUTH;
225 auth_withpeer_fail(u->us_unit, PPP_PAP);
226 return;
229 upap_sauthreq(u); /* Send Authenticate-Request */
234 * upap_reqtimeout - Give up waiting for the peer to send a valid auth-req.
236 static void
237 upap_reqtimeout(arg)
238 void *arg;
240 upap_state *u = (upap_state *) arg;
242 if (u->us_serverstate != UPAPSS_LISTEN)
243 return; /* huh?? */
245 auth_peer_fail(u->us_unit, PPP_PAP);
246 u->us_serverstate = UPAPSS_BADAUTH;
251 * upap_lowerup - The lower layer is up.
253 * Start authenticating if pending.
255 static void
256 upap_lowerup(unit)
257 int unit;
259 upap_state *u = &upap[unit];
261 if (u->us_clientstate == UPAPCS_INITIAL)
262 u->us_clientstate = UPAPCS_CLOSED;
263 else if (u->us_clientstate == UPAPCS_PENDING) {
264 upap_sauthreq(u); /* send an auth-request */
267 if (u->us_serverstate == UPAPSS_INITIAL)
268 u->us_serverstate = UPAPSS_CLOSED;
269 else if (u->us_serverstate == UPAPSS_PENDING) {
270 u->us_serverstate = UPAPSS_LISTEN;
271 if (u->us_reqtimeout > 0)
272 TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);
278 * upap_lowerdown - The lower layer is down.
280 * Cancel all timeouts.
282 static void
283 upap_lowerdown(unit)
284 int unit;
286 upap_state *u = &upap[unit];
288 /* Cancel timeouts */
289 if (u->us_clientstate == UPAPCS_AUTHREQ && u->us_timeouttime > 0)
290 UNTIMEOUT(upap_timeout, u);
291 if (u->us_serverstate == UPAPSS_LISTEN && u->us_reqtimeout > 0)
292 UNTIMEOUT(upap_reqtimeout, u);
294 u->us_clientstate = UPAPCS_INITIAL;
295 u->us_serverstate = UPAPSS_INITIAL;
300 * upap_protrej - Peer doesn't speak this protocol.
302 * This shouldn't happen. In any case, pretend lower layer went down.
304 static void
305 upap_protrej(unit)
306 int unit;
308 upap_state *u = &upap[unit];
310 if (u->us_clientstate == UPAPCS_AUTHREQ) {
311 error("PAP authentication failed due to protocol-reject");
312 auth_withpeer_fail(unit, PPP_PAP);
314 if (u->us_serverstate == UPAPSS_LISTEN) {
315 error("PAP authentication of peer failed (protocol-reject)");
316 auth_peer_fail(unit, PPP_PAP);
318 upap_lowerdown(unit);
323 * upap_input - Input UPAP packet.
325 static void
326 upap_input(unit, inpacket, l)
327 int unit;
328 u_char *inpacket;
329 int l;
331 upap_state *u = &upap[unit];
332 u_char *inp;
333 u_char code, id;
334 int len;
337 * Parse header (code, id and length).
338 * If packet too short, drop it.
340 inp = inpacket;
341 if (l < UPAP_HEADERLEN) {
342 error("PAP: packet is too small (%d < %d)", l, UPAP_HEADERLEN);
343 return;
345 GETCHAR(code, inp);
346 GETCHAR(id, inp);
347 GETSHORT(len, inp);
348 if ((len < UPAP_HEADERLEN) || (len > l)) {
349 error("PAP: packet has illegal length %d (%d..%d)", len,
350 UPAP_HEADERLEN, l);
351 return;
353 len -= UPAP_HEADERLEN;
356 * Action depends on code.
358 switch (code) {
359 case UPAP_AUTHREQ:
360 upap_rauthreq(u, inp, id, len);
361 break;
363 case UPAP_AUTHACK:
364 upap_rauthack(u, inp, id, len);
365 break;
367 case UPAP_AUTHNAK:
368 upap_rauthnak(u, inp, id, len);
369 break;
371 default:
372 warn("Unknown PAP code (%d) received.", code);
373 break;
379 * upap_rauth - Receive Authenticate.
381 static void
382 upap_rauthreq(u, inp, id, len)
383 upap_state *u;
384 u_char *inp;
385 int id;
386 int len;
388 u_char ruserlen, rpasswdlen;
389 char *ruser, *rpasswd;
390 int retcode;
391 char *msg;
392 int msglen;
394 if (u->us_serverstate < UPAPSS_LISTEN) {
395 info("PAP: discarded Authenticate-Request in state %s",
396 pap_sstate(u->us_serverstate));
397 return;
401 * If we receive a duplicate authenticate-request, we are
402 * supposed to return the same status as for the first request.
404 if (u->us_serverstate == UPAPSS_OPEN) {
405 /* return auth-ack */
406 upap_sresp(u, UPAP_AUTHACK, id, u->us_msg, u->us_msglen);
407 return;
409 if (u->us_serverstate == UPAPSS_BADAUTH) {
410 /* return auth-nak */
411 upap_sresp(u, UPAP_AUTHNAK, id, u->us_msg, u->us_msglen);
412 return;
416 * Parse user/passwd.
418 if (len < 1) {
419 error("PAP: rcvd short packet; no data");
420 return;
422 GETCHAR(ruserlen, inp);
423 len -= sizeof (u_char) + ruserlen + sizeof (u_char);
424 if (len < 0) {
425 error("PAP: rcvd short packet; peer name missing");
426 return;
428 ruser = (char *) inp;
429 INCPTR(ruserlen, inp);
430 GETCHAR(rpasswdlen, inp);
431 if (len < rpasswdlen) {
432 error("PAP: rcvd short packet; pass len %d < %d", len, rpasswdlen);
433 return;
435 rpasswd = (char *) inp;
438 * Check the username and password given.
440 retcode = check_passwd(u->us_unit, ruser, ruserlen, rpasswd,
441 rpasswdlen, &msg);
442 BZERO(rpasswd, rpasswdlen);
443 msglen = strlen(msg);
444 if (msglen > 255)
445 msglen = 255;
447 u->us_msg = msg;
448 u->us_msglen = msglen;
449 upap_sresp(u, retcode, id, u->us_msg, u->us_msglen);
451 if (retcode == UPAP_AUTHACK) {
452 u->us_serverstate = UPAPSS_OPEN;
453 auth_peer_success(u->us_unit, PPP_PAP, ruser, ruserlen);
454 } else if (++u->us_receives >= u->us_maxreceives) {
455 u->us_serverstate = UPAPSS_BADAUTH;
456 auth_peer_fail(u->us_unit, PPP_PAP);
457 } else {
458 /* Just wait for a good one to arrive, or for time-out. */
459 return;
462 if (u->us_reqtimeout > 0)
463 UNTIMEOUT(upap_reqtimeout, u);
468 * upap_rauthack - Receive Authenticate-Ack.
470 /*ARGSUSED*/
471 static void
472 upap_rauthack(u, inp, id, len)
473 upap_state *u;
474 u_char *inp;
475 int id;
476 int len;
478 u_char msglen;
479 char *msg;
481 if (u->us_clientstate != UPAPCS_AUTHREQ) {
482 info("PAP: discarded Authenticate-Ack in state %s",
483 pap_cstate(u->us_clientstate));
484 return;
487 if (id != u->us_id) {
488 dbglog("PAP: discard Authenticate-Ack; ID %d != %d",
489 id, u->us_id);
490 return;
493 if (u->us_timeouttime > 0)
494 UNTIMEOUT(upap_timeout, u);
497 * Parse message.
499 if (len < 1) {
500 info("PAP: Ignoring missing ack msg-length octet");
501 } else {
502 GETCHAR(msglen, inp);
503 if (msglen > 0) {
504 len -= sizeof (u_char);
505 if (len < msglen) {
506 error("PAP: Discarding short packet (%d < %d)", len, msglen);
507 return;
509 msg = (char *) inp;
510 PRINTMSG(msg, msglen);
514 u->us_clientstate = UPAPCS_OPEN;
516 auth_withpeer_success(u->us_unit, PPP_PAP);
521 * upap_rauthnak - Receive Authenticate-Nakk.
523 /*ARGSUSED*/
524 static void
525 upap_rauthnak(u, inp, id, len)
526 upap_state *u;
527 u_char *inp;
528 int id;
529 int len;
531 u_char msglen;
532 char *msg;
534 if (u->us_clientstate != UPAPCS_AUTHREQ) {
535 info("PAP: discarded Authenticate-Nak in state %s",
536 pap_cstate(u->us_clientstate));
537 return;
540 if (id != u->us_id) {
541 dbglog("PAP: discard Authenticate-Ack; ID %d != %d",
542 id, u->us_id);
543 return;
546 if (u->us_timeouttime > 0)
547 UNTIMEOUT(upap_timeout, u);
550 * Parse message.
552 if (len < 1) {
553 error("PAP: ignoring missing nak msg-length octet");
554 } else {
555 GETCHAR(msglen, inp);
556 if (msglen > 0) {
557 len -= sizeof (u_char);
558 if (len < msglen) {
559 error("PAP: Discarding short packet (%d < %d)", len, msglen);
560 return;
562 msg = (char *) inp;
563 PRINTMSG(msg, msglen);
567 /* Try to get a new password from the plugin. */
568 if (pap_passwd_hook != NULL) {
569 if (u->us_transmits < u->us_maxtransmits) {
570 if ((*pap_passwd_hook)(user, passwd) >= 0) {
571 upap_sauthreq(u);
572 return;
574 } else {
575 /* Tell plug-in that we're giving up. */
576 (void) (*pap_passwd_hook)(NULL, NULL);
580 u->us_clientstate = UPAPCS_BADAUTH;
582 error("PAP authentication failed");
583 auth_withpeer_fail(u->us_unit, PPP_PAP);
588 * upap_sauthreq - Send an Authenticate-Request.
590 static void
591 upap_sauthreq(u)
592 upap_state *u;
594 u_char *outp;
595 int pwlen;
596 int outlen;
598 pwlen = strllen(passwd, MAXSECRETLEN);
599 if (pwlen > 0xFF)
600 pwlen = 0xFF;
601 outlen = UPAP_HEADERLEN + 2 * sizeof (u_char) + u->us_userlen + pwlen;
602 outp = outpacket_buf;
604 MAKEHEADER(outp, PPP_PAP);
606 PUTCHAR(UPAP_AUTHREQ, outp);
607 PUTCHAR(++u->us_id, outp);
608 PUTSHORT(outlen, outp);
609 PUTCHAR(u->us_userlen, outp);
610 BCOPY(u->us_user, outp, u->us_userlen);
611 INCPTR(u->us_userlen, outp);
612 PUTCHAR(pwlen, outp);
613 BCOPY(u->us_passwd, outp, pwlen);
615 output(u->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
617 if (u->us_timeouttime > 0)
618 TIMEOUT(upap_timeout, u, u->us_timeouttime);
619 ++u->us_transmits;
620 u->us_clientstate = UPAPCS_AUTHREQ;
625 * upap_sresp - Send a response (ack or nak).
627 static void
628 upap_sresp(u, code, id, msg, msglen)
629 upap_state *u;
630 u_char code, id;
631 char *msg;
632 int msglen;
634 u_char *outp;
635 int outlen;
637 outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen;
638 outp = outpacket_buf;
639 MAKEHEADER(outp, PPP_PAP);
641 PUTCHAR(code, outp);
642 PUTCHAR(id, outp);
643 PUTSHORT(outlen, outp);
644 PUTCHAR(msglen, outp);
645 BCOPY(msg, outp, msglen);
646 output(u->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
650 * upap_printpkt - print the contents of a PAP packet.
652 static char *upap_codenames[] = {
653 "AuthReq", "AuthAck", "AuthNak"
656 static int
657 upap_printpkt(p, plen, printer, arg)
658 u_char *p;
659 int plen;
660 void (*printer) __P((void *, const char *, ...));
661 void *arg;
663 int code, id, len;
664 int mlen, ulen, wlen;
665 char *user, *pwd, *msg;
666 u_char *pstart;
668 if (plen < UPAP_HEADERLEN)
669 return (0);
670 pstart = p;
671 GETCHAR(code, p);
672 GETCHAR(id, p);
673 GETSHORT(len, p);
674 if (len < UPAP_HEADERLEN || len > plen)
675 return (0);
677 if (code >= 1 && code <= Dim(upap_codenames))
678 printer(arg, " %s", upap_codenames[code-1]);
679 else
680 printer(arg, " code=0x%x", code);
681 printer(arg, " id=0x%x", id);
682 len -= UPAP_HEADERLEN;
683 switch (code) {
684 case UPAP_AUTHREQ:
685 if (len < 1)
686 break;
687 ulen = p[0];
688 if (len < ulen + 2)
689 break;
690 wlen = p[ulen + 1];
691 if (len < ulen + wlen + 2)
692 break;
693 user = (char *) (p + 1);
694 pwd = (char *) (p + ulen + 2);
695 p += ulen + wlen + 2;
696 len -= ulen + wlen + 2;
697 printer(arg, " user=");
698 print_string(user, ulen, printer, arg);
699 printer(arg, " password=");
700 if (!hide_password)
701 print_string(pwd, wlen, printer, arg);
702 else
703 printer(arg, "<hidden>");
704 break;
705 case UPAP_AUTHACK:
706 case UPAP_AUTHNAK:
707 if (len < 1)
708 break;
709 mlen = p[0];
710 if (len < mlen + 1)
711 break;
712 msg = (char *) (p + 1);
713 p += mlen + 1;
714 len -= mlen + 1;
715 printer(arg, " ");
716 print_string(msg, mlen, printer, arg);
717 break;
720 /* print the rest of the bytes in the packet */
721 for (; len > 0; --len) {
722 GETCHAR(code, p);
723 printer(arg, " %.2x", code);
726 return (p - pstart);