2 * upap.c - User/Password Authentication Protocol.
4 * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
18 * 3. The name "Carnegie Mellon University" must not be used to
19 * endorse or promote products derived from this software without
20 * prior written permission. For permission or any legal
21 * details, please contact
22 * Office of Technology Transfer
23 * Carnegie Mellon University
25 * Pittsburgh, PA 15213-3890
26 * (412) 268-4387, fax: (412) 268-7395
27 * tech-transfer@andrew.cmu.edu
29 * 4. Redistributions of any form whatsoever must retain the following
31 * "This product includes software developed by Computing Services
32 * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
34 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
35 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
36 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
37 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
38 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
39 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
40 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
43 #define RCSID "$Id: upap.c,v 1.30 2005/07/13 10:41:58 paulus Exp $"
56 static bool hide_password = 1;
59 * Command-line options.
61 static option_t pap_option_list[] = {
62 { "hide-password", o_bool, &hide_password,
63 "Don't output passwords to log", OPT_PRIO | 1 },
64 { "show-password", o_bool, &hide_password,
65 "Show password string in debug log messages", OPT_PRIOSUB | 0 },
67 { "pap-restart", o_int, &upap[0].us_timeouttime,
68 "Set retransmit timeout for PAP", OPT_PRIO },
69 { "pap-max-authreq", o_int, &upap[0].us_maxtransmits,
70 "Set max number of transmissions for auth-reqs", OPT_PRIO },
71 { "pap-timeout", o_int, &upap[0].us_reqtimeout,
72 "Set time limit for peer PAP authentication", OPT_PRIO },
78 * Protocol entry points.
80 static void upap_init __P((int));
81 static void upap_lowerup __P((int));
82 static void upap_lowerdown __P((int));
83 static void upap_input __P((int, u_char *, int));
84 static void upap_protrej __P((int));
85 static int upap_printpkt __P((u_char *, int,
86 void (*) __P((void *, char *, ...)), void *));
88 struct protent pap_protent = {
108 upap_state upap[NUM_PPP]; /* UPAP state; one for each unit */
110 static void upap_timeout __P((void *));
111 static void upap_reqtimeout __P((void *));
112 static void upap_rauthreq __P((upap_state *, u_char *, int, int));
113 static void upap_rauthack __P((upap_state *, u_char *, int, int));
114 static void upap_rauthnak __P((upap_state *, u_char *, int, int));
115 static void upap_sauthreq __P((upap_state *));
116 static void upap_sresp __P((upap_state *, int, int, char *, int));
120 * upap_init - Initialize a UPAP unit.
126 upap_state *u = &upap[unit];
133 u->us_clientstate = UPAPCS_INITIAL;
134 u->us_serverstate = UPAPSS_INITIAL;
136 u->us_timeouttime = UPAP_DEFTIMEOUT;
137 u->us_maxtransmits = 10;
138 u->us_reqtimeout = UPAP_DEFREQTIME;
143 * upap_authwithpeer - Authenticate us with our peer (start client).
145 * Set new state and send authenticate's.
148 upap_authwithpeer(unit, user, password)
150 char *user, *password;
152 upap_state *u = &upap[unit];
154 /* Save the username and password we're given */
156 u->us_userlen = strlen(user);
157 u->us_passwd = password;
158 u->us_passwdlen = strlen(password);
161 /* Lower layer up yet? */
162 if (u->us_clientstate == UPAPCS_INITIAL ||
163 u->us_clientstate == UPAPCS_PENDING) {
164 u->us_clientstate = UPAPCS_PENDING;
168 upap_sauthreq(u); /* Start protocol */
173 * upap_authpeer - Authenticate our peer (start server).
181 upap_state *u = &upap[unit];
183 /* Lower layer up yet? */
184 if (u->us_serverstate == UPAPSS_INITIAL ||
185 u->us_serverstate == UPAPSS_PENDING) {
186 u->us_serverstate = UPAPSS_PENDING;
190 u->us_serverstate = UPAPSS_LISTEN;
191 if (u->us_reqtimeout > 0)
192 TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);
197 * upap_timeout - Retransmission timer for sending auth-reqs expired.
203 upap_state *u = (upap_state *) arg;
205 if (u->us_clientstate != UPAPCS_AUTHREQ)
208 if (u->us_transmits >= u->us_maxtransmits) {
209 /* give up in disgust */
210 error("No response to PAP authenticate-requests");
211 u->us_clientstate = UPAPCS_BADAUTH;
212 auth_withpeer_fail(u->us_unit, PPP_PAP);
216 upap_sauthreq(u); /* Send Authenticate-Request */
221 * upap_reqtimeout - Give up waiting for the peer to send an auth-req.
227 upap_state *u = (upap_state *) arg;
229 if (u->us_serverstate != UPAPSS_LISTEN)
232 auth_peer_fail(u->us_unit, PPP_PAP);
233 u->us_serverstate = UPAPSS_BADAUTH;
238 * upap_lowerup - The lower layer is up.
240 * Start authenticating if pending.
246 upap_state *u = &upap[unit];
248 if (u->us_clientstate == UPAPCS_INITIAL)
249 u->us_clientstate = UPAPCS_CLOSED;
250 else if (u->us_clientstate == UPAPCS_PENDING) {
251 upap_sauthreq(u); /* send an auth-request */
254 if (u->us_serverstate == UPAPSS_INITIAL)
255 u->us_serverstate = UPAPSS_CLOSED;
256 else if (u->us_serverstate == UPAPSS_PENDING) {
257 u->us_serverstate = UPAPSS_LISTEN;
258 if (u->us_reqtimeout > 0)
259 TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);
265 * upap_lowerdown - The lower layer is down.
267 * Cancel all timeouts.
273 upap_state *u = &upap[unit];
275 if (u->us_clientstate == UPAPCS_AUTHREQ) /* Timeout pending? */
276 UNTIMEOUT(upap_timeout, u); /* Cancel timeout */
277 if (u->us_serverstate == UPAPSS_LISTEN && u->us_reqtimeout > 0)
278 UNTIMEOUT(upap_reqtimeout, u);
280 u->us_clientstate = UPAPCS_INITIAL;
281 u->us_serverstate = UPAPSS_INITIAL;
286 * upap_protrej - Peer doesn't speak this protocol.
288 * This shouldn't happen. In any case, pretend lower layer went down.
294 upap_state *u = &upap[unit];
296 if (u->us_clientstate == UPAPCS_AUTHREQ) {
297 error("PAP authentication failed due to protocol-reject");
298 auth_withpeer_fail(unit, PPP_PAP);
300 if (u->us_serverstate == UPAPSS_LISTEN) {
301 error("PAP authentication of peer failed (protocol-reject)");
302 auth_peer_fail(unit, PPP_PAP);
304 upap_lowerdown(unit);
309 * upap_input - Input UPAP packet.
312 upap_input(unit, inpacket, l)
317 upap_state *u = &upap[unit];
323 * Parse header (code, id and length).
324 * If packet too short, drop it.
327 if (l < UPAP_HEADERLEN) {
328 UPAPDEBUG(("pap_input: rcvd short header."));
334 if (len < UPAP_HEADERLEN) {
335 UPAPDEBUG(("pap_input: rcvd illegal length."));
339 UPAPDEBUG(("pap_input: rcvd short packet."));
342 len -= UPAP_HEADERLEN;
345 * Action depends on code.
349 upap_rauthreq(u, inp, id, len);
353 upap_rauthack(u, inp, id, len);
357 upap_rauthnak(u, inp, id, len);
360 default: /* XXX Need code reject */
367 * upap_rauth - Receive Authenticate.
370 upap_rauthreq(u, inp, id, len)
376 u_char ruserlen, rpasswdlen;
377 char *ruser, *rpasswd;
383 if (u->us_serverstate < UPAPSS_LISTEN)
387 * If we receive a duplicate authenticate-request, we are
388 * supposed to return the same status as for the first request.
390 if (u->us_serverstate == UPAPSS_OPEN) {
391 upap_sresp(u, UPAP_AUTHACK, id, "", 0); /* return auth-ack */
394 if (u->us_serverstate == UPAPSS_BADAUTH) {
395 upap_sresp(u, UPAP_AUTHNAK, id, "", 0); /* return auth-nak */
403 UPAPDEBUG(("pap_rauth: rcvd short packet."));
406 GETCHAR(ruserlen, inp);
407 len -= sizeof (u_char) + ruserlen + sizeof (u_char);
409 UPAPDEBUG(("pap_rauth: rcvd short packet."));
412 ruser = (char *) inp;
413 INCPTR(ruserlen, inp);
414 GETCHAR(rpasswdlen, inp);
415 if (len < rpasswdlen) {
416 UPAPDEBUG(("pap_rauth: rcvd short packet."));
419 rpasswd = (char *) inp;
422 * Check the username and password given.
424 retcode = check_passwd(u->us_unit, ruser, ruserlen, rpasswd,
426 BZERO(rpasswd, rpasswdlen);
429 * Check remote number authorization. A plugin may have filled in
430 * the remote number or added an allowed number, and rather than
431 * return an authenticate failure, is leaving it for us to verify.
433 if (retcode == UPAP_AUTHACK) {
434 if (!auth_number()) {
435 /* We do not want to leak info about the pap result. */
436 retcode = UPAP_AUTHNAK; /* XXX exit value will be "wrong" */
437 warn("calling number %q is not authorized", remote_number);
441 msglen = strlen(msg);
444 upap_sresp(u, retcode, id, msg, msglen);
446 /* Null terminate and clean remote name. */
447 slprintf(rhostname, sizeof(rhostname), "%.*v", ruserlen, ruser);
449 if (retcode == UPAP_AUTHACK) {
450 u->us_serverstate = UPAPSS_OPEN;
451 notice("PAP peer authentication succeeded for %q", rhostname);
452 auth_peer_success(u->us_unit, PPP_PAP, 0, ruser, ruserlen);
454 u->us_serverstate = UPAPSS_BADAUTH;
455 warn("PAP peer authentication failed for %q", rhostname);
456 auth_peer_fail(u->us_unit, PPP_PAP);
459 if (u->us_reqtimeout > 0)
460 UNTIMEOUT(upap_reqtimeout, u);
465 * upap_rauthack - Receive Authenticate-Ack.
468 upap_rauthack(u, inp, id, len)
477 if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */
484 UPAPDEBUG(("pap_rauthack: ignoring missing msg-length."));
486 GETCHAR(msglen, inp);
488 len -= sizeof (u_char);
490 UPAPDEBUG(("pap_rauthack: rcvd short packet."));
494 PRINTMSG(msg, msglen);
498 u->us_clientstate = UPAPCS_OPEN;
500 auth_withpeer_success(u->us_unit, PPP_PAP, 0);
505 * upap_rauthnak - Receive Authenticate-Nak.
508 upap_rauthnak(u, inp, id, len)
517 if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */
524 UPAPDEBUG(("pap_rauthnak: ignoring missing msg-length."));
526 GETCHAR(msglen, inp);
528 len -= sizeof (u_char);
530 UPAPDEBUG(("pap_rauthnak: rcvd short packet."));
534 PRINTMSG(msg, msglen);
538 u->us_clientstate = UPAPCS_BADAUTH;
540 error("PAP authentication failed");
541 auth_withpeer_fail(u->us_unit, PPP_PAP);
546 * upap_sauthreq - Send an Authenticate-Request.
555 outlen = UPAP_HEADERLEN + 2 * sizeof (u_char) +
556 u->us_userlen + u->us_passwdlen;
557 outp = outpacket_buf;
559 MAKEHEADER(outp, PPP_PAP);
561 PUTCHAR(UPAP_AUTHREQ, outp);
562 PUTCHAR(++u->us_id, outp);
563 PUTSHORT(outlen, outp);
564 PUTCHAR(u->us_userlen, outp);
565 BCOPY(u->us_user, outp, u->us_userlen);
566 INCPTR(u->us_userlen, outp);
567 PUTCHAR(u->us_passwdlen, outp);
568 BCOPY(u->us_passwd, outp, u->us_passwdlen);
570 output(u->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
572 TIMEOUT(upap_timeout, u, u->us_timeouttime);
574 u->us_clientstate = UPAPCS_AUTHREQ;
579 * upap_sresp - Send a response (ack or nak).
582 upap_sresp(u, code, id, msg, msglen)
591 outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen;
592 outp = outpacket_buf;
593 MAKEHEADER(outp, PPP_PAP);
597 PUTSHORT(outlen, outp);
598 PUTCHAR(msglen, outp);
599 BCOPY(msg, outp, msglen);
600 output(u->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
604 * upap_printpkt - print the contents of a PAP packet.
606 static char *upap_codenames[] = {
607 "AuthReq", "AuthAck", "AuthNak"
611 upap_printpkt(p, plen, printer, arg)
614 void (*printer) __P((void *, char *, ...));
618 int mlen, ulen, wlen;
619 char *user, *pwd, *msg;
622 if (plen < UPAP_HEADERLEN)
628 if (len < UPAP_HEADERLEN || len > plen)
631 if (code >= 1 && code <= sizeof(upap_codenames) / sizeof(char *))
632 printer(arg, " %s", upap_codenames[code-1]);
634 printer(arg, " code=0x%x", code);
635 printer(arg, " id=0x%x", id);
636 len -= UPAP_HEADERLEN;
645 if (len < ulen + wlen + 2)
647 user = (char *) (p + 1);
648 pwd = (char *) (p + ulen + 2);
649 p += ulen + wlen + 2;
650 len -= ulen + wlen + 2;
651 printer(arg, " user=");
652 print_string(user, ulen, printer, arg);
653 printer(arg, " password=");
655 print_string(pwd, wlen, printer, arg);
657 printer(arg, "<hidden>");
666 msg = (char *) (p + 1);
670 print_string(msg, mlen, printer, arg);
674 /* print the rest of the bytes in the packet */
675 for (; len > 0; --len) {
677 printer(arg, " %.2x", code);