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 #include "netif/ppp/ppp_opts.h"
44 #if PPP_SUPPORT && PAP_SUPPORT /* don't build if not configured for use in lwipopts.h */
55 #include "netif/ppp/ppp_impl.h"
57 #include "netif/ppp/upap.h"
61 * Command-line options.
63 static option_t pap_option_list[] = {
64 { "hide-password", o_bool, &hide_password,
65 "Don't output passwords to log", OPT_PRIO | 1 },
66 { "show-password", o_bool, &hide_password,
67 "Show password string in debug log messages", OPT_PRIOSUB | 0 },
69 { "pap-restart", o_int, &upap[0].us_timeouttime,
70 "Set retransmit timeout for PAP", OPT_PRIO },
71 { "pap-max-authreq", o_int, &upap[0].us_maxtransmits,
72 "Set max number of transmissions for auth-reqs", OPT_PRIO },
73 { "pap-timeout", o_int, &upap[0].us_reqtimeout,
74 "Set time limit for peer PAP authentication", OPT_PRIO },
78 #endif /* PPP_OPTIONS */
81 * Protocol entry points.
83 static void upap_init(ppp_pcb *pcb);
84 static void upap_lowerup(ppp_pcb *pcb);
85 static void upap_lowerdown(ppp_pcb *pcb);
86 static void upap_input(ppp_pcb *pcb, u_char *inpacket, int l);
87 static void upap_protrej(ppp_pcb *pcb);
89 static int upap_printpkt(const u_char *p, int plen, void (*printer) (void *, const char *, ...), void *arg);
90 #endif /* PRINTPKT_SUPPORT */
92 const struct protent pap_protent = {
103 #endif /* PRINTPKT_SUPPORT */
106 #endif /* PPP_DATAINPUT */
110 #endif /* PRINTPKT_SUPPORT */
114 #endif /* PPP_OPTIONS */
118 #endif /* DEMAND_SUPPORT */
121 static void upap_timeout(void *arg);
123 static void upap_reqtimeout(void *arg);
124 static void upap_rauthreq(ppp_pcb *pcb, u_char *inp, int id, int len);
125 #endif /* PPP_SERVER */
126 static void upap_rauthack(ppp_pcb *pcb, u_char *inp, int id, int len);
127 static void upap_rauthnak(ppp_pcb *pcb, u_char *inp, int id, int len);
128 static void upap_sauthreq(ppp_pcb *pcb);
130 static void upap_sresp(ppp_pcb *pcb, u_char code, u_char id, const char *msg, int msglen);
131 #endif /* PPP_SERVER */
135 * upap_init - Initialize a UPAP unit.
137 static void upap_init(ppp_pcb *pcb) {
138 pcb->upap.us_user = NULL;
139 pcb->upap.us_userlen = 0;
140 pcb->upap.us_passwd = NULL;
141 pcb->upap.us_passwdlen = 0;
142 pcb->upap.us_clientstate = UPAPCS_INITIAL;
144 pcb->upap.us_serverstate = UPAPSS_INITIAL;
145 #endif /* PPP_SERVER */
151 * upap_authwithpeer - Authenticate us with our peer (start client).
153 * Set new state and send authenticate's.
155 void upap_authwithpeer(ppp_pcb *pcb, const char *user, const char *password) {
157 if(!user || !password)
160 /* Save the username and password we're given */
161 pcb->upap.us_user = user;
162 pcb->upap.us_userlen = LWIP_MIN(strlen(user), 0xff);
163 pcb->upap.us_passwd = password;
164 pcb->upap.us_passwdlen = LWIP_MIN(strlen(password), 0xff);
165 pcb->upap.us_transmits = 0;
167 /* Lower layer up yet? */
168 if (pcb->upap.us_clientstate == UPAPCS_INITIAL ||
169 pcb->upap.us_clientstate == UPAPCS_PENDING) {
170 pcb->upap.us_clientstate = UPAPCS_PENDING;
174 upap_sauthreq(pcb); /* Start protocol */
179 * upap_authpeer - Authenticate our peer (start server).
183 void upap_authpeer(ppp_pcb *pcb) {
185 /* Lower layer up yet? */
186 if (pcb->upap.us_serverstate == UPAPSS_INITIAL ||
187 pcb->upap.us_serverstate == UPAPSS_PENDING) {
188 pcb->upap.us_serverstate = UPAPSS_PENDING;
192 pcb->upap.us_serverstate = UPAPSS_LISTEN;
193 if (pcb->settings.pap_req_timeout > 0)
194 TIMEOUT(upap_reqtimeout, pcb, pcb->settings.pap_req_timeout);
196 #endif /* PPP_SERVER */
199 * upap_timeout - Retransmission timer for sending auth-reqs expired.
201 static void upap_timeout(void *arg) {
202 ppp_pcb *pcb = (ppp_pcb*)arg;
204 if (pcb->upap.us_clientstate != UPAPCS_AUTHREQ)
207 if (pcb->upap.us_transmits >= pcb->settings.pap_max_transmits) {
208 /* give up in disgust */
209 ppp_error("No response to PAP authenticate-requests");
210 pcb->upap.us_clientstate = UPAPCS_BADAUTH;
211 auth_withpeer_fail(pcb, PPP_PAP);
215 upap_sauthreq(pcb); /* Send Authenticate-Request */
221 * upap_reqtimeout - Give up waiting for the peer to send an auth-req.
223 static void upap_reqtimeout(void *arg) {
224 ppp_pcb *pcb = (ppp_pcb*)arg;
226 if (pcb->upap.us_serverstate != UPAPSS_LISTEN)
229 auth_peer_fail(pcb, PPP_PAP);
230 pcb->upap.us_serverstate = UPAPSS_BADAUTH;
232 #endif /* PPP_SERVER */
236 * upap_lowerup - The lower layer is up.
238 * Start authenticating if pending.
240 static void upap_lowerup(ppp_pcb *pcb) {
242 if (pcb->upap.us_clientstate == UPAPCS_INITIAL)
243 pcb->upap.us_clientstate = UPAPCS_CLOSED;
244 else if (pcb->upap.us_clientstate == UPAPCS_PENDING) {
245 upap_sauthreq(pcb); /* send an auth-request */
249 if (pcb->upap.us_serverstate == UPAPSS_INITIAL)
250 pcb->upap.us_serverstate = UPAPSS_CLOSED;
251 else if (pcb->upap.us_serverstate == UPAPSS_PENDING) {
252 pcb->upap.us_serverstate = UPAPSS_LISTEN;
253 if (pcb->settings.pap_req_timeout > 0)
254 TIMEOUT(upap_reqtimeout, pcb, pcb->settings.pap_req_timeout);
256 #endif /* PPP_SERVER */
261 * upap_lowerdown - The lower layer is down.
263 * Cancel all timeouts.
265 static void upap_lowerdown(ppp_pcb *pcb) {
267 if (pcb->upap.us_clientstate == UPAPCS_AUTHREQ) /* Timeout pending? */
268 UNTIMEOUT(upap_timeout, pcb); /* Cancel timeout */
270 if (pcb->upap.us_serverstate == UPAPSS_LISTEN && pcb->settings.pap_req_timeout > 0)
271 UNTIMEOUT(upap_reqtimeout, pcb);
272 #endif /* PPP_SERVER */
274 pcb->upap.us_clientstate = UPAPCS_INITIAL;
276 pcb->upap.us_serverstate = UPAPSS_INITIAL;
277 #endif /* PPP_SERVER */
282 * upap_protrej - Peer doesn't speak this protocol.
284 * This shouldn't happen. In any case, pretend lower layer went down.
286 static void upap_protrej(ppp_pcb *pcb) {
288 if (pcb->upap.us_clientstate == UPAPCS_AUTHREQ) {
289 ppp_error("PAP authentication failed due to protocol-reject");
290 auth_withpeer_fail(pcb, PPP_PAP);
293 if (pcb->upap.us_serverstate == UPAPSS_LISTEN) {
294 ppp_error("PAP authentication of peer failed (protocol-reject)");
295 auth_peer_fail(pcb, PPP_PAP);
297 #endif /* PPP_SERVER */
303 * upap_input - Input UPAP packet.
305 static void upap_input(ppp_pcb *pcb, u_char *inpacket, int l) {
311 * Parse header (code, id and length).
312 * If packet too short, drop it.
315 if (l < UPAP_HEADERLEN) {
316 UPAPDEBUG(("pap_input: rcvd short header."));
322 if (len < UPAP_HEADERLEN) {
323 UPAPDEBUG(("pap_input: rcvd illegal length."));
327 UPAPDEBUG(("pap_input: rcvd short packet."));
330 len -= UPAP_HEADERLEN;
333 * Action depends on code.
338 upap_rauthreq(pcb, inp, id, len);
339 #endif /* PPP_SERVER */
343 upap_rauthack(pcb, inp, id, len);
347 upap_rauthnak(pcb, inp, id, len);
350 default: /* XXX Need code reject */
357 * upap_rauth - Receive Authenticate.
359 static void upap_rauthreq(ppp_pcb *pcb, u_char *inp, int id, int len) {
360 u_char ruserlen, rpasswdlen;
368 if (pcb->upap.us_serverstate < UPAPSS_LISTEN)
372 * If we receive a duplicate authenticate-request, we are
373 * supposed to return the same status as for the first request.
375 if (pcb->upap.us_serverstate == UPAPSS_OPEN) {
376 upap_sresp(pcb, UPAP_AUTHACK, id, "", 0); /* return auth-ack */
379 if (pcb->upap.us_serverstate == UPAPSS_BADAUTH) {
380 upap_sresp(pcb, UPAP_AUTHNAK, id, "", 0); /* return auth-nak */
388 UPAPDEBUG(("pap_rauth: rcvd short packet."));
391 GETCHAR(ruserlen, inp);
392 len -= sizeof (u_char) + ruserlen + sizeof (u_char);
394 UPAPDEBUG(("pap_rauth: rcvd short packet."));
397 ruser = (char *) inp;
398 INCPTR(ruserlen, inp);
399 GETCHAR(rpasswdlen, inp);
400 if (len < rpasswdlen) {
401 UPAPDEBUG(("pap_rauth: rcvd short packet."));
405 rpasswd = (char *) inp;
408 * Check the username and password given.
410 retcode = UPAP_AUTHNAK;
411 if (auth_check_passwd(pcb, ruser, ruserlen, rpasswd, rpasswdlen, &msg, &msglen)) {
412 retcode = UPAP_AUTHACK;
414 BZERO(rpasswd, rpasswdlen);
418 * Check remote number authorization. A plugin may have filled in
419 * the remote number or added an allowed number, and rather than
420 * return an authenticate failure, is leaving it for us to verify.
422 if (retcode == UPAP_AUTHACK) {
423 if (!auth_number()) {
424 /* We do not want to leak info about the pap result. */
425 retcode = UPAP_AUTHNAK; /* XXX exit value will be "wrong" */
426 warn("calling number %q is not authorized", remote_number);
430 msglen = strlen(msg);
435 upap_sresp(pcb, retcode, id, msg, msglen);
437 /* Null terminate and clean remote name. */
438 ppp_slprintf(rhostname, sizeof(rhostname), "%.*v", ruserlen, ruser);
440 if (retcode == UPAP_AUTHACK) {
441 pcb->upap.us_serverstate = UPAPSS_OPEN;
442 ppp_notice("PAP peer authentication succeeded for %q", rhostname);
443 auth_peer_success(pcb, PPP_PAP, 0, ruser, ruserlen);
445 pcb->upap.us_serverstate = UPAPSS_BADAUTH;
446 ppp_warn("PAP peer authentication failed for %q", rhostname);
447 auth_peer_fail(pcb, PPP_PAP);
450 if (pcb->settings.pap_req_timeout > 0)
451 UNTIMEOUT(upap_reqtimeout, pcb);
453 #endif /* PPP_SERVER */
456 * upap_rauthack - Receive Authenticate-Ack.
458 static void upap_rauthack(ppp_pcb *pcb, u_char *inp, int id, int len) {
463 if (pcb->upap.us_clientstate != UPAPCS_AUTHREQ) /* XXX */
470 UPAPDEBUG(("pap_rauthack: ignoring missing msg-length."));
472 GETCHAR(msglen, inp);
474 len -= sizeof (u_char);
476 UPAPDEBUG(("pap_rauthack: rcvd short packet."));
480 PRINTMSG(msg, msglen);
484 pcb->upap.us_clientstate = UPAPCS_OPEN;
486 auth_withpeer_success(pcb, PPP_PAP, 0);
491 * upap_rauthnak - Receive Authenticate-Nak.
493 static void upap_rauthnak(ppp_pcb *pcb, u_char *inp, int id, int len) {
498 if (pcb->upap.us_clientstate != UPAPCS_AUTHREQ) /* XXX */
505 UPAPDEBUG(("pap_rauthnak: ignoring missing msg-length."));
507 GETCHAR(msglen, inp);
509 len -= sizeof (u_char);
511 UPAPDEBUG(("pap_rauthnak: rcvd short packet."));
515 PRINTMSG(msg, msglen);
519 pcb->upap.us_clientstate = UPAPCS_BADAUTH;
521 ppp_error("PAP authentication failed");
522 auth_withpeer_fail(pcb, PPP_PAP);
527 * upap_sauthreq - Send an Authenticate-Request.
529 static void upap_sauthreq(ppp_pcb *pcb) {
534 outlen = UPAP_HEADERLEN + 2 * sizeof (u_char) +
535 pcb->upap.us_userlen + pcb->upap.us_passwdlen;
536 p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN +outlen), PPP_CTRL_PBUF_TYPE);
539 if(p->tot_len != p->len) {
544 outp = (u_char*)p->payload;
545 MAKEHEADER(outp, PPP_PAP);
547 PUTCHAR(UPAP_AUTHREQ, outp);
548 PUTCHAR(++pcb->upap.us_id, outp);
549 PUTSHORT(outlen, outp);
550 PUTCHAR(pcb->upap.us_userlen, outp);
551 MEMCPY(outp, pcb->upap.us_user, pcb->upap.us_userlen);
552 INCPTR(pcb->upap.us_userlen, outp);
553 PUTCHAR(pcb->upap.us_passwdlen, outp);
554 MEMCPY(outp, pcb->upap.us_passwd, pcb->upap.us_passwdlen);
558 TIMEOUT(upap_timeout, pcb, pcb->settings.pap_timeout_time);
559 ++pcb->upap.us_transmits;
560 pcb->upap.us_clientstate = UPAPCS_AUTHREQ;
565 * upap_sresp - Send a response (ack or nak).
567 static void upap_sresp(ppp_pcb *pcb, u_char code, u_char id, const char *msg, int msglen) {
572 outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen;
573 p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN +outlen), PPP_CTRL_PBUF_TYPE);
576 if(p->tot_len != p->len) {
581 outp = (u_char*)p->payload;
582 MAKEHEADER(outp, PPP_PAP);
586 PUTSHORT(outlen, outp);
587 PUTCHAR(msglen, outp);
588 MEMCPY(outp, msg, msglen);
592 #endif /* PPP_SERVER */
596 * upap_printpkt - print the contents of a PAP packet.
598 static const char* const upap_codenames[] = {
599 "AuthReq", "AuthAck", "AuthNak"
602 static int upap_printpkt(const u_char *p, int plen, void (*printer) (void *, const char *, ...), void *arg) {
604 int mlen, ulen, wlen;
605 const u_char *user, *pwd, *msg;
606 const u_char *pstart;
608 if (plen < UPAP_HEADERLEN)
614 if (len < UPAP_HEADERLEN || len > plen)
617 if (code >= 1 && code <= (int)LWIP_ARRAYSIZE(upap_codenames))
618 printer(arg, " %s", upap_codenames[code-1]);
620 printer(arg, " code=0x%x", code);
621 printer(arg, " id=0x%x", id);
622 len -= UPAP_HEADERLEN;
631 if (len < ulen + wlen + 2)
633 user = (const u_char *) (p + 1);
634 pwd = (const u_char *) (p + ulen + 2);
635 p += ulen + wlen + 2;
636 len -= ulen + wlen + 2;
637 printer(arg, " user=");
638 ppp_print_string(user, ulen, printer, arg);
639 printer(arg, " password=");
640 /* FIXME: require ppp_pcb struct as printpkt() argument */
642 if (!pcb->settings.hide_password)
644 ppp_print_string(pwd, wlen, printer, arg);
647 printer(arg, "<hidden>");
657 msg = (const u_char *) (p + 1);
661 ppp_print_string(msg, mlen, printer, arg);
667 /* print the rest of the bytes in the packet */
668 for (; len > 0; --len) {
670 printer(arg, " %.2x", code);
675 #endif /* PRINTPKT_SUPPORT */
677 #endif /* PPP_SUPPORT && PAP_SUPPORT */