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 */