1*5d5fbe79SDavid van Moolenbroek /*
2*5d5fbe79SDavid van Moolenbroek * chap-new.c - New CHAP implementation.
3*5d5fbe79SDavid van Moolenbroek *
4*5d5fbe79SDavid van Moolenbroek * Copyright (c) 2003 Paul Mackerras. All rights reserved.
5*5d5fbe79SDavid van Moolenbroek *
6*5d5fbe79SDavid van Moolenbroek * Redistribution and use in source and binary forms, with or without
7*5d5fbe79SDavid van Moolenbroek * modification, are permitted provided that the following conditions
8*5d5fbe79SDavid van Moolenbroek * are met:
9*5d5fbe79SDavid van Moolenbroek *
10*5d5fbe79SDavid van Moolenbroek * 1. Redistributions of source code must retain the above copyright
11*5d5fbe79SDavid van Moolenbroek * notice, this list of conditions and the following disclaimer.
12*5d5fbe79SDavid van Moolenbroek *
13*5d5fbe79SDavid van Moolenbroek * 2. The name(s) of the authors of this software must not be used to
14*5d5fbe79SDavid van Moolenbroek * endorse or promote products derived from this software without
15*5d5fbe79SDavid van Moolenbroek * prior written permission.
16*5d5fbe79SDavid van Moolenbroek *
17*5d5fbe79SDavid van Moolenbroek * 3. Redistributions of any form whatsoever must retain the following
18*5d5fbe79SDavid van Moolenbroek * acknowledgment:
19*5d5fbe79SDavid van Moolenbroek * "This product includes software developed by Paul Mackerras
20*5d5fbe79SDavid van Moolenbroek * <paulus@samba.org>".
21*5d5fbe79SDavid van Moolenbroek *
22*5d5fbe79SDavid van Moolenbroek * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
23*5d5fbe79SDavid van Moolenbroek * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
24*5d5fbe79SDavid van Moolenbroek * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
25*5d5fbe79SDavid van Moolenbroek * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
26*5d5fbe79SDavid van Moolenbroek * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
27*5d5fbe79SDavid van Moolenbroek * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
28*5d5fbe79SDavid van Moolenbroek * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
29*5d5fbe79SDavid van Moolenbroek */
30*5d5fbe79SDavid van Moolenbroek
31*5d5fbe79SDavid van Moolenbroek #include "netif/ppp/ppp_opts.h"
32*5d5fbe79SDavid van Moolenbroek #if PPP_SUPPORT && CHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */
33*5d5fbe79SDavid van Moolenbroek
34*5d5fbe79SDavid van Moolenbroek #if 0 /* UNUSED */
35*5d5fbe79SDavid van Moolenbroek #include <stdlib.h>
36*5d5fbe79SDavid van Moolenbroek #include <string.h>
37*5d5fbe79SDavid van Moolenbroek #endif /* UNUSED */
38*5d5fbe79SDavid van Moolenbroek
39*5d5fbe79SDavid van Moolenbroek #include "netif/ppp/ppp_impl.h"
40*5d5fbe79SDavid van Moolenbroek
41*5d5fbe79SDavid van Moolenbroek #if 0 /* UNUSED */
42*5d5fbe79SDavid van Moolenbroek #include "session.h"
43*5d5fbe79SDavid van Moolenbroek #endif /* UNUSED */
44*5d5fbe79SDavid van Moolenbroek
45*5d5fbe79SDavid van Moolenbroek #include "netif/ppp/chap-new.h"
46*5d5fbe79SDavid van Moolenbroek #include "netif/ppp/chap-md5.h"
47*5d5fbe79SDavid van Moolenbroek #if MSCHAP_SUPPORT
48*5d5fbe79SDavid van Moolenbroek #include "netif/ppp/chap_ms.h"
49*5d5fbe79SDavid van Moolenbroek #endif
50*5d5fbe79SDavid van Moolenbroek #include "netif/ppp/magic.h"
51*5d5fbe79SDavid van Moolenbroek
52*5d5fbe79SDavid van Moolenbroek #if 0 /* UNUSED */
53*5d5fbe79SDavid van Moolenbroek /* Hook for a plugin to validate CHAP challenge */
54*5d5fbe79SDavid van Moolenbroek int (*chap_verify_hook)(const char *name, const char *ourname, int id,
55*5d5fbe79SDavid van Moolenbroek const struct chap_digest_type *digest,
56*5d5fbe79SDavid van Moolenbroek const unsigned char *challenge, const unsigned char *response,
57*5d5fbe79SDavid van Moolenbroek char *message, int message_space) = NULL;
58*5d5fbe79SDavid van Moolenbroek #endif /* UNUSED */
59*5d5fbe79SDavid van Moolenbroek
60*5d5fbe79SDavid van Moolenbroek #if PPP_OPTIONS
61*5d5fbe79SDavid van Moolenbroek /*
62*5d5fbe79SDavid van Moolenbroek * Command-line options.
63*5d5fbe79SDavid van Moolenbroek */
64*5d5fbe79SDavid van Moolenbroek static option_t chap_option_list[] = {
65*5d5fbe79SDavid van Moolenbroek { "chap-restart", o_int, &chap_timeout_time,
66*5d5fbe79SDavid van Moolenbroek "Set timeout for CHAP", OPT_PRIO },
67*5d5fbe79SDavid van Moolenbroek { "chap-max-challenge", o_int, &pcb->settings.chap_max_transmits,
68*5d5fbe79SDavid van Moolenbroek "Set max #xmits for challenge", OPT_PRIO },
69*5d5fbe79SDavid van Moolenbroek { "chap-interval", o_int, &pcb->settings.chap_rechallenge_time,
70*5d5fbe79SDavid van Moolenbroek "Set interval for rechallenge", OPT_PRIO },
71*5d5fbe79SDavid van Moolenbroek { NULL }
72*5d5fbe79SDavid van Moolenbroek };
73*5d5fbe79SDavid van Moolenbroek #endif /* PPP_OPTIONS */
74*5d5fbe79SDavid van Moolenbroek
75*5d5fbe79SDavid van Moolenbroek
76*5d5fbe79SDavid van Moolenbroek /* Values for flags in chap_client_state and chap_server_state */
77*5d5fbe79SDavid van Moolenbroek #define LOWERUP 1
78*5d5fbe79SDavid van Moolenbroek #define AUTH_STARTED 2
79*5d5fbe79SDavid van Moolenbroek #define AUTH_DONE 4
80*5d5fbe79SDavid van Moolenbroek #define AUTH_FAILED 8
81*5d5fbe79SDavid van Moolenbroek #define TIMEOUT_PENDING 0x10
82*5d5fbe79SDavid van Moolenbroek #define CHALLENGE_VALID 0x20
83*5d5fbe79SDavid van Moolenbroek
84*5d5fbe79SDavid van Moolenbroek /*
85*5d5fbe79SDavid van Moolenbroek * Prototypes.
86*5d5fbe79SDavid van Moolenbroek */
87*5d5fbe79SDavid van Moolenbroek static void chap_init(ppp_pcb *pcb);
88*5d5fbe79SDavid van Moolenbroek static void chap_lowerup(ppp_pcb *pcb);
89*5d5fbe79SDavid van Moolenbroek static void chap_lowerdown(ppp_pcb *pcb);
90*5d5fbe79SDavid van Moolenbroek #if PPP_SERVER
91*5d5fbe79SDavid van Moolenbroek static void chap_timeout(void *arg);
92*5d5fbe79SDavid van Moolenbroek static void chap_generate_challenge(ppp_pcb *pcb);
93*5d5fbe79SDavid van Moolenbroek static void chap_handle_response(ppp_pcb *pcb, int code,
94*5d5fbe79SDavid van Moolenbroek unsigned char *pkt, int len);
95*5d5fbe79SDavid van Moolenbroek static int chap_verify_response(ppp_pcb *pcb, const char *name, const char *ourname, int id,
96*5d5fbe79SDavid van Moolenbroek const struct chap_digest_type *digest,
97*5d5fbe79SDavid van Moolenbroek const unsigned char *challenge, const unsigned char *response,
98*5d5fbe79SDavid van Moolenbroek char *message, int message_space);
99*5d5fbe79SDavid van Moolenbroek #endif /* PPP_SERVER */
100*5d5fbe79SDavid van Moolenbroek static void chap_respond(ppp_pcb *pcb, int id,
101*5d5fbe79SDavid van Moolenbroek unsigned char *pkt, int len);
102*5d5fbe79SDavid van Moolenbroek static void chap_handle_status(ppp_pcb *pcb, int code, int id,
103*5d5fbe79SDavid van Moolenbroek unsigned char *pkt, int len);
104*5d5fbe79SDavid van Moolenbroek static void chap_protrej(ppp_pcb *pcb);
105*5d5fbe79SDavid van Moolenbroek static void chap_input(ppp_pcb *pcb, unsigned char *pkt, int pktlen);
106*5d5fbe79SDavid van Moolenbroek #if PRINTPKT_SUPPORT
107*5d5fbe79SDavid van Moolenbroek static int chap_print_pkt(const unsigned char *p, int plen,
108*5d5fbe79SDavid van Moolenbroek void (*printer) (void *, const char *, ...), void *arg);
109*5d5fbe79SDavid van Moolenbroek #endif /* PRINTPKT_SUPPORT */
110*5d5fbe79SDavid van Moolenbroek
111*5d5fbe79SDavid van Moolenbroek /* List of digest types that we know about */
112*5d5fbe79SDavid van Moolenbroek static const struct chap_digest_type* const chap_digests[] = {
113*5d5fbe79SDavid van Moolenbroek &md5_digest,
114*5d5fbe79SDavid van Moolenbroek #if MSCHAP_SUPPORT
115*5d5fbe79SDavid van Moolenbroek &chapms_digest,
116*5d5fbe79SDavid van Moolenbroek &chapms2_digest,
117*5d5fbe79SDavid van Moolenbroek #endif /* MSCHAP_SUPPORT */
118*5d5fbe79SDavid van Moolenbroek NULL
119*5d5fbe79SDavid van Moolenbroek };
120*5d5fbe79SDavid van Moolenbroek
121*5d5fbe79SDavid van Moolenbroek /*
122*5d5fbe79SDavid van Moolenbroek * chap_init - reset to initial state.
123*5d5fbe79SDavid van Moolenbroek */
chap_init(ppp_pcb * pcb)124*5d5fbe79SDavid van Moolenbroek static void chap_init(ppp_pcb *pcb) {
125*5d5fbe79SDavid van Moolenbroek LWIP_UNUSED_ARG(pcb);
126*5d5fbe79SDavid van Moolenbroek
127*5d5fbe79SDavid van Moolenbroek #if 0 /* Not necessary, everything is cleared in ppp_new() */
128*5d5fbe79SDavid van Moolenbroek memset(&pcb->chap_client, 0, sizeof(chap_client_state));
129*5d5fbe79SDavid van Moolenbroek #if PPP_SERVER
130*5d5fbe79SDavid van Moolenbroek memset(&pcb->chap_server, 0, sizeof(chap_server_state));
131*5d5fbe79SDavid van Moolenbroek #endif /* PPP_SERVER */
132*5d5fbe79SDavid van Moolenbroek #endif /* 0 */
133*5d5fbe79SDavid van Moolenbroek }
134*5d5fbe79SDavid van Moolenbroek
135*5d5fbe79SDavid van Moolenbroek /*
136*5d5fbe79SDavid van Moolenbroek * chap_lowerup - we can start doing stuff now.
137*5d5fbe79SDavid van Moolenbroek */
chap_lowerup(ppp_pcb * pcb)138*5d5fbe79SDavid van Moolenbroek static void chap_lowerup(ppp_pcb *pcb) {
139*5d5fbe79SDavid van Moolenbroek
140*5d5fbe79SDavid van Moolenbroek pcb->chap_client.flags |= LOWERUP;
141*5d5fbe79SDavid van Moolenbroek #if PPP_SERVER
142*5d5fbe79SDavid van Moolenbroek pcb->chap_server.flags |= LOWERUP;
143*5d5fbe79SDavid van Moolenbroek if (pcb->chap_server.flags & AUTH_STARTED)
144*5d5fbe79SDavid van Moolenbroek chap_timeout(pcb);
145*5d5fbe79SDavid van Moolenbroek #endif /* PPP_SERVER */
146*5d5fbe79SDavid van Moolenbroek }
147*5d5fbe79SDavid van Moolenbroek
chap_lowerdown(ppp_pcb * pcb)148*5d5fbe79SDavid van Moolenbroek static void chap_lowerdown(ppp_pcb *pcb) {
149*5d5fbe79SDavid van Moolenbroek
150*5d5fbe79SDavid van Moolenbroek pcb->chap_client.flags = 0;
151*5d5fbe79SDavid van Moolenbroek #if PPP_SERVER
152*5d5fbe79SDavid van Moolenbroek if (pcb->chap_server.flags & TIMEOUT_PENDING)
153*5d5fbe79SDavid van Moolenbroek UNTIMEOUT(chap_timeout, pcb);
154*5d5fbe79SDavid van Moolenbroek pcb->chap_server.flags = 0;
155*5d5fbe79SDavid van Moolenbroek #endif /* PPP_SERVER */
156*5d5fbe79SDavid van Moolenbroek }
157*5d5fbe79SDavid van Moolenbroek
158*5d5fbe79SDavid van Moolenbroek #if PPP_SERVER
159*5d5fbe79SDavid van Moolenbroek /*
160*5d5fbe79SDavid van Moolenbroek * chap_auth_peer - Start authenticating the peer.
161*5d5fbe79SDavid van Moolenbroek * If the lower layer is already up, we start sending challenges,
162*5d5fbe79SDavid van Moolenbroek * otherwise we wait for the lower layer to come up.
163*5d5fbe79SDavid van Moolenbroek */
chap_auth_peer(ppp_pcb * pcb,const char * our_name,int digest_code)164*5d5fbe79SDavid van Moolenbroek void chap_auth_peer(ppp_pcb *pcb, const char *our_name, int digest_code) {
165*5d5fbe79SDavid van Moolenbroek const struct chap_digest_type *dp;
166*5d5fbe79SDavid van Moolenbroek int i;
167*5d5fbe79SDavid van Moolenbroek
168*5d5fbe79SDavid van Moolenbroek if (pcb->chap_server.flags & AUTH_STARTED) {
169*5d5fbe79SDavid van Moolenbroek ppp_error("CHAP: peer authentication already started!");
170*5d5fbe79SDavid van Moolenbroek return;
171*5d5fbe79SDavid van Moolenbroek }
172*5d5fbe79SDavid van Moolenbroek for (i = 0; (dp = chap_digests[i]) != NULL; ++i)
173*5d5fbe79SDavid van Moolenbroek if (dp->code == digest_code)
174*5d5fbe79SDavid van Moolenbroek break;
175*5d5fbe79SDavid van Moolenbroek if (dp == NULL)
176*5d5fbe79SDavid van Moolenbroek ppp_fatal("CHAP digest 0x%x requested but not available",
177*5d5fbe79SDavid van Moolenbroek digest_code);
178*5d5fbe79SDavid van Moolenbroek
179*5d5fbe79SDavid van Moolenbroek pcb->chap_server.digest = dp;
180*5d5fbe79SDavid van Moolenbroek pcb->chap_server.name = our_name;
181*5d5fbe79SDavid van Moolenbroek /* Start with a random ID value */
182*5d5fbe79SDavid van Moolenbroek pcb->chap_server.id = magic();
183*5d5fbe79SDavid van Moolenbroek pcb->chap_server.flags |= AUTH_STARTED;
184*5d5fbe79SDavid van Moolenbroek if (pcb->chap_server.flags & LOWERUP)
185*5d5fbe79SDavid van Moolenbroek chap_timeout(pcb);
186*5d5fbe79SDavid van Moolenbroek }
187*5d5fbe79SDavid van Moolenbroek #endif /* PPP_SERVER */
188*5d5fbe79SDavid van Moolenbroek
189*5d5fbe79SDavid van Moolenbroek /*
190*5d5fbe79SDavid van Moolenbroek * chap_auth_with_peer - Prepare to authenticate ourselves to the peer.
191*5d5fbe79SDavid van Moolenbroek * There isn't much to do until we receive a challenge.
192*5d5fbe79SDavid van Moolenbroek */
chap_auth_with_peer(ppp_pcb * pcb,const char * our_name,int digest_code)193*5d5fbe79SDavid van Moolenbroek void chap_auth_with_peer(ppp_pcb *pcb, const char *our_name, int digest_code) {
194*5d5fbe79SDavid van Moolenbroek const struct chap_digest_type *dp;
195*5d5fbe79SDavid van Moolenbroek int i;
196*5d5fbe79SDavid van Moolenbroek
197*5d5fbe79SDavid van Moolenbroek if(NULL == our_name)
198*5d5fbe79SDavid van Moolenbroek return;
199*5d5fbe79SDavid van Moolenbroek
200*5d5fbe79SDavid van Moolenbroek if (pcb->chap_client.flags & AUTH_STARTED) {
201*5d5fbe79SDavid van Moolenbroek ppp_error("CHAP: authentication with peer already started!");
202*5d5fbe79SDavid van Moolenbroek return;
203*5d5fbe79SDavid van Moolenbroek }
204*5d5fbe79SDavid van Moolenbroek for (i = 0; (dp = chap_digests[i]) != NULL; ++i)
205*5d5fbe79SDavid van Moolenbroek if (dp->code == digest_code)
206*5d5fbe79SDavid van Moolenbroek break;
207*5d5fbe79SDavid van Moolenbroek
208*5d5fbe79SDavid van Moolenbroek if (dp == NULL)
209*5d5fbe79SDavid van Moolenbroek ppp_fatal("CHAP digest 0x%x requested but not available",
210*5d5fbe79SDavid van Moolenbroek digest_code);
211*5d5fbe79SDavid van Moolenbroek
212*5d5fbe79SDavid van Moolenbroek pcb->chap_client.digest = dp;
213*5d5fbe79SDavid van Moolenbroek pcb->chap_client.name = our_name;
214*5d5fbe79SDavid van Moolenbroek pcb->chap_client.flags |= AUTH_STARTED;
215*5d5fbe79SDavid van Moolenbroek }
216*5d5fbe79SDavid van Moolenbroek
217*5d5fbe79SDavid van Moolenbroek #if PPP_SERVER
218*5d5fbe79SDavid van Moolenbroek /*
219*5d5fbe79SDavid van Moolenbroek * chap_timeout - It's time to send another challenge to the peer.
220*5d5fbe79SDavid van Moolenbroek * This could be either a retransmission of a previous challenge,
221*5d5fbe79SDavid van Moolenbroek * or a new challenge to start re-authentication.
222*5d5fbe79SDavid van Moolenbroek */
chap_timeout(void * arg)223*5d5fbe79SDavid van Moolenbroek static void chap_timeout(void *arg) {
224*5d5fbe79SDavid van Moolenbroek ppp_pcb *pcb = (ppp_pcb*)arg;
225*5d5fbe79SDavid van Moolenbroek struct pbuf *p;
226*5d5fbe79SDavid van Moolenbroek
227*5d5fbe79SDavid van Moolenbroek pcb->chap_server.flags &= ~TIMEOUT_PENDING;
228*5d5fbe79SDavid van Moolenbroek if ((pcb->chap_server.flags & CHALLENGE_VALID) == 0) {
229*5d5fbe79SDavid van Moolenbroek pcb->chap_server.challenge_xmits = 0;
230*5d5fbe79SDavid van Moolenbroek chap_generate_challenge(pcb);
231*5d5fbe79SDavid van Moolenbroek pcb->chap_server.flags |= CHALLENGE_VALID;
232*5d5fbe79SDavid van Moolenbroek } else if (pcb->chap_server.challenge_xmits >= pcb->settings.chap_max_transmits) {
233*5d5fbe79SDavid van Moolenbroek pcb->chap_server.flags &= ~CHALLENGE_VALID;
234*5d5fbe79SDavid van Moolenbroek pcb->chap_server.flags |= AUTH_DONE | AUTH_FAILED;
235*5d5fbe79SDavid van Moolenbroek auth_peer_fail(pcb, PPP_CHAP);
236*5d5fbe79SDavid van Moolenbroek return;
237*5d5fbe79SDavid van Moolenbroek }
238*5d5fbe79SDavid van Moolenbroek
239*5d5fbe79SDavid van Moolenbroek p = pbuf_alloc(PBUF_RAW, (u16_t)(pcb->chap_server.challenge_pktlen), PPP_CTRL_PBUF_TYPE);
240*5d5fbe79SDavid van Moolenbroek if(NULL == p)
241*5d5fbe79SDavid van Moolenbroek return;
242*5d5fbe79SDavid van Moolenbroek if(p->tot_len != p->len) {
243*5d5fbe79SDavid van Moolenbroek pbuf_free(p);
244*5d5fbe79SDavid van Moolenbroek return;
245*5d5fbe79SDavid van Moolenbroek }
246*5d5fbe79SDavid van Moolenbroek MEMCPY(p->payload, pcb->chap_server.challenge, pcb->chap_server.challenge_pktlen);
247*5d5fbe79SDavid van Moolenbroek ppp_write(pcb, p);
248*5d5fbe79SDavid van Moolenbroek ++pcb->chap_server.challenge_xmits;
249*5d5fbe79SDavid van Moolenbroek pcb->chap_server.flags |= TIMEOUT_PENDING;
250*5d5fbe79SDavid van Moolenbroek TIMEOUT(chap_timeout, arg, pcb->settings.chap_timeout_time);
251*5d5fbe79SDavid van Moolenbroek }
252*5d5fbe79SDavid van Moolenbroek
253*5d5fbe79SDavid van Moolenbroek /*
254*5d5fbe79SDavid van Moolenbroek * chap_generate_challenge - generate a challenge string and format
255*5d5fbe79SDavid van Moolenbroek * the challenge packet in pcb->chap_server.challenge_pkt.
256*5d5fbe79SDavid van Moolenbroek */
chap_generate_challenge(ppp_pcb * pcb)257*5d5fbe79SDavid van Moolenbroek static void chap_generate_challenge(ppp_pcb *pcb) {
258*5d5fbe79SDavid van Moolenbroek int clen = 1, nlen, len;
259*5d5fbe79SDavid van Moolenbroek unsigned char *p;
260*5d5fbe79SDavid van Moolenbroek
261*5d5fbe79SDavid van Moolenbroek p = pcb->chap_server.challenge;
262*5d5fbe79SDavid van Moolenbroek MAKEHEADER(p, PPP_CHAP);
263*5d5fbe79SDavid van Moolenbroek p += CHAP_HDRLEN;
264*5d5fbe79SDavid van Moolenbroek pcb->chap_server.digest->generate_challenge(pcb, p);
265*5d5fbe79SDavid van Moolenbroek clen = *p;
266*5d5fbe79SDavid van Moolenbroek nlen = strlen(pcb->chap_server.name);
267*5d5fbe79SDavid van Moolenbroek memcpy(p + 1 + clen, pcb->chap_server.name, nlen);
268*5d5fbe79SDavid van Moolenbroek
269*5d5fbe79SDavid van Moolenbroek len = CHAP_HDRLEN + 1 + clen + nlen;
270*5d5fbe79SDavid van Moolenbroek pcb->chap_server.challenge_pktlen = PPP_HDRLEN + len;
271*5d5fbe79SDavid van Moolenbroek
272*5d5fbe79SDavid van Moolenbroek p = pcb->chap_server.challenge + PPP_HDRLEN;
273*5d5fbe79SDavid van Moolenbroek p[0] = CHAP_CHALLENGE;
274*5d5fbe79SDavid van Moolenbroek p[1] = ++pcb->chap_server.id;
275*5d5fbe79SDavid van Moolenbroek p[2] = len >> 8;
276*5d5fbe79SDavid van Moolenbroek p[3] = len;
277*5d5fbe79SDavid van Moolenbroek }
278*5d5fbe79SDavid van Moolenbroek
279*5d5fbe79SDavid van Moolenbroek /*
280*5d5fbe79SDavid van Moolenbroek * chap_handle_response - check the response to our challenge.
281*5d5fbe79SDavid van Moolenbroek */
chap_handle_response(ppp_pcb * pcb,int id,unsigned char * pkt,int len)282*5d5fbe79SDavid van Moolenbroek static void chap_handle_response(ppp_pcb *pcb, int id,
283*5d5fbe79SDavid van Moolenbroek unsigned char *pkt, int len) {
284*5d5fbe79SDavid van Moolenbroek int response_len, ok, mlen;
285*5d5fbe79SDavid van Moolenbroek const unsigned char *response;
286*5d5fbe79SDavid van Moolenbroek unsigned char *outp;
287*5d5fbe79SDavid van Moolenbroek struct pbuf *p;
288*5d5fbe79SDavid van Moolenbroek const char *name = NULL; /* initialized to shut gcc up */
289*5d5fbe79SDavid van Moolenbroek #if 0 /* UNUSED */
290*5d5fbe79SDavid van Moolenbroek int (*verifier)(const char *, const char *, int, const struct chap_digest_type *,
291*5d5fbe79SDavid van Moolenbroek const unsigned char *, const unsigned char *, char *, int);
292*5d5fbe79SDavid van Moolenbroek #endif /* UNUSED */
293*5d5fbe79SDavid van Moolenbroek char rname[MAXNAMELEN+1];
294*5d5fbe79SDavid van Moolenbroek char message[256];
295*5d5fbe79SDavid van Moolenbroek
296*5d5fbe79SDavid van Moolenbroek if ((pcb->chap_server.flags & LOWERUP) == 0)
297*5d5fbe79SDavid van Moolenbroek return;
298*5d5fbe79SDavid van Moolenbroek if (id != pcb->chap_server.challenge[PPP_HDRLEN+1] || len < 2)
299*5d5fbe79SDavid van Moolenbroek return;
300*5d5fbe79SDavid van Moolenbroek if (pcb->chap_server.flags & CHALLENGE_VALID) {
301*5d5fbe79SDavid van Moolenbroek response = pkt;
302*5d5fbe79SDavid van Moolenbroek GETCHAR(response_len, pkt);
303*5d5fbe79SDavid van Moolenbroek len -= response_len + 1; /* length of name */
304*5d5fbe79SDavid van Moolenbroek name = (char *)pkt + response_len;
305*5d5fbe79SDavid van Moolenbroek if (len < 0)
306*5d5fbe79SDavid van Moolenbroek return;
307*5d5fbe79SDavid van Moolenbroek
308*5d5fbe79SDavid van Moolenbroek if (pcb->chap_server.flags & TIMEOUT_PENDING) {
309*5d5fbe79SDavid van Moolenbroek pcb->chap_server.flags &= ~TIMEOUT_PENDING;
310*5d5fbe79SDavid van Moolenbroek UNTIMEOUT(chap_timeout, pcb);
311*5d5fbe79SDavid van Moolenbroek }
312*5d5fbe79SDavid van Moolenbroek #if PPP_REMOTENAME
313*5d5fbe79SDavid van Moolenbroek if (pcb->settings.explicit_remote) {
314*5d5fbe79SDavid van Moolenbroek name = pcb->remote_name;
315*5d5fbe79SDavid van Moolenbroek } else
316*5d5fbe79SDavid van Moolenbroek #endif /* PPP_REMOTENAME */
317*5d5fbe79SDavid van Moolenbroek {
318*5d5fbe79SDavid van Moolenbroek /* Null terminate and clean remote name. */
319*5d5fbe79SDavid van Moolenbroek ppp_slprintf(rname, sizeof(rname), "%.*v", len, name);
320*5d5fbe79SDavid van Moolenbroek name = rname;
321*5d5fbe79SDavid van Moolenbroek }
322*5d5fbe79SDavid van Moolenbroek
323*5d5fbe79SDavid van Moolenbroek #if 0 /* UNUSED */
324*5d5fbe79SDavid van Moolenbroek if (chap_verify_hook)
325*5d5fbe79SDavid van Moolenbroek verifier = chap_verify_hook;
326*5d5fbe79SDavid van Moolenbroek else
327*5d5fbe79SDavid van Moolenbroek verifier = chap_verify_response;
328*5d5fbe79SDavid van Moolenbroek ok = (*verifier)(name, pcb->chap_server.name, id, pcb->chap_server.digest,
329*5d5fbe79SDavid van Moolenbroek pcb->chap_server.challenge + PPP_HDRLEN + CHAP_HDRLEN,
330*5d5fbe79SDavid van Moolenbroek response, pcb->chap_server.message, sizeof(pcb->chap_server.message));
331*5d5fbe79SDavid van Moolenbroek #endif /* UNUSED */
332*5d5fbe79SDavid van Moolenbroek ok = chap_verify_response(pcb, name, pcb->chap_server.name, id, pcb->chap_server.digest,
333*5d5fbe79SDavid van Moolenbroek pcb->chap_server.challenge + PPP_HDRLEN + CHAP_HDRLEN,
334*5d5fbe79SDavid van Moolenbroek response, message, sizeof(message));
335*5d5fbe79SDavid van Moolenbroek #if 0 /* UNUSED */
336*5d5fbe79SDavid van Moolenbroek if (!ok || !auth_number()) {
337*5d5fbe79SDavid van Moolenbroek #endif /* UNUSED */
338*5d5fbe79SDavid van Moolenbroek if (!ok) {
339*5d5fbe79SDavid van Moolenbroek pcb->chap_server.flags |= AUTH_FAILED;
340*5d5fbe79SDavid van Moolenbroek ppp_warn("Peer %q failed CHAP authentication", name);
341*5d5fbe79SDavid van Moolenbroek }
342*5d5fbe79SDavid van Moolenbroek } else if ((pcb->chap_server.flags & AUTH_DONE) == 0)
343*5d5fbe79SDavid van Moolenbroek return;
344*5d5fbe79SDavid van Moolenbroek
345*5d5fbe79SDavid van Moolenbroek /* send the response */
346*5d5fbe79SDavid van Moolenbroek mlen = strlen(message);
347*5d5fbe79SDavid van Moolenbroek len = CHAP_HDRLEN + mlen;
348*5d5fbe79SDavid van Moolenbroek p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN +len), PPP_CTRL_PBUF_TYPE);
349*5d5fbe79SDavid van Moolenbroek if(NULL == p)
350*5d5fbe79SDavid van Moolenbroek return;
351*5d5fbe79SDavid van Moolenbroek if(p->tot_len != p->len) {
352*5d5fbe79SDavid van Moolenbroek pbuf_free(p);
353*5d5fbe79SDavid van Moolenbroek return;
354*5d5fbe79SDavid van Moolenbroek }
355*5d5fbe79SDavid van Moolenbroek
356*5d5fbe79SDavid van Moolenbroek outp = (unsigned char *)p->payload;
357*5d5fbe79SDavid van Moolenbroek MAKEHEADER(outp, PPP_CHAP);
358*5d5fbe79SDavid van Moolenbroek
359*5d5fbe79SDavid van Moolenbroek outp[0] = (pcb->chap_server.flags & AUTH_FAILED)? CHAP_FAILURE: CHAP_SUCCESS;
360*5d5fbe79SDavid van Moolenbroek outp[1] = id;
361*5d5fbe79SDavid van Moolenbroek outp[2] = len >> 8;
362*5d5fbe79SDavid van Moolenbroek outp[3] = len;
363*5d5fbe79SDavid van Moolenbroek if (mlen > 0)
364*5d5fbe79SDavid van Moolenbroek memcpy(outp + CHAP_HDRLEN, message, mlen);
365*5d5fbe79SDavid van Moolenbroek ppp_write(pcb, p);
366*5d5fbe79SDavid van Moolenbroek
367*5d5fbe79SDavid van Moolenbroek if (pcb->chap_server.flags & CHALLENGE_VALID) {
368*5d5fbe79SDavid van Moolenbroek pcb->chap_server.flags &= ~CHALLENGE_VALID;
369*5d5fbe79SDavid van Moolenbroek if (!(pcb->chap_server.flags & AUTH_DONE) && !(pcb->chap_server.flags & AUTH_FAILED)) {
370*5d5fbe79SDavid van Moolenbroek
371*5d5fbe79SDavid van Moolenbroek #if 0 /* UNUSED */
372*5d5fbe79SDavid van Moolenbroek /*
373*5d5fbe79SDavid van Moolenbroek * Auth is OK, so now we need to check session restrictions
374*5d5fbe79SDavid van Moolenbroek * to ensure everything is OK, but only if we used a
375*5d5fbe79SDavid van Moolenbroek * plugin, and only if we're configured to check. This
376*5d5fbe79SDavid van Moolenbroek * allows us to do PAM checks on PPP servers that
377*5d5fbe79SDavid van Moolenbroek * authenticate against ActiveDirectory, and use AD for
378*5d5fbe79SDavid van Moolenbroek * account info (like when using Winbind integrated with
379*5d5fbe79SDavid van Moolenbroek * PAM).
380*5d5fbe79SDavid van Moolenbroek */
381*5d5fbe79SDavid van Moolenbroek if (session_mgmt &&
382*5d5fbe79SDavid van Moolenbroek session_check(name, NULL, devnam, NULL) == 0) {
383*5d5fbe79SDavid van Moolenbroek pcb->chap_server.flags |= AUTH_FAILED;
384*5d5fbe79SDavid van Moolenbroek ppp_warn("Peer %q failed CHAP Session verification", name);
385*5d5fbe79SDavid van Moolenbroek }
386*5d5fbe79SDavid van Moolenbroek #endif /* UNUSED */
387*5d5fbe79SDavid van Moolenbroek
388*5d5fbe79SDavid van Moolenbroek }
389*5d5fbe79SDavid van Moolenbroek if (pcb->chap_server.flags & AUTH_FAILED) {
390*5d5fbe79SDavid van Moolenbroek auth_peer_fail(pcb, PPP_CHAP);
391*5d5fbe79SDavid van Moolenbroek } else {
392*5d5fbe79SDavid van Moolenbroek if ((pcb->chap_server.flags & AUTH_DONE) == 0)
393*5d5fbe79SDavid van Moolenbroek auth_peer_success(pcb, PPP_CHAP,
394*5d5fbe79SDavid van Moolenbroek pcb->chap_server.digest->code,
395*5d5fbe79SDavid van Moolenbroek name, strlen(name));
396*5d5fbe79SDavid van Moolenbroek if (pcb->settings.chap_rechallenge_time) {
397*5d5fbe79SDavid van Moolenbroek pcb->chap_server.flags |= TIMEOUT_PENDING;
398*5d5fbe79SDavid van Moolenbroek TIMEOUT(chap_timeout, pcb,
399*5d5fbe79SDavid van Moolenbroek pcb->settings.chap_rechallenge_time);
400*5d5fbe79SDavid van Moolenbroek }
401*5d5fbe79SDavid van Moolenbroek }
402*5d5fbe79SDavid van Moolenbroek pcb->chap_server.flags |= AUTH_DONE;
403*5d5fbe79SDavid van Moolenbroek }
404*5d5fbe79SDavid van Moolenbroek }
405*5d5fbe79SDavid van Moolenbroek
406*5d5fbe79SDavid van Moolenbroek /*
407*5d5fbe79SDavid van Moolenbroek * chap_verify_response - check whether the peer's response matches
408*5d5fbe79SDavid van Moolenbroek * what we think it should be. Returns 1 if it does (authentication
409*5d5fbe79SDavid van Moolenbroek * succeeded), or 0 if it doesn't.
410*5d5fbe79SDavid van Moolenbroek */
411*5d5fbe79SDavid van Moolenbroek static int chap_verify_response(ppp_pcb *pcb, const char *name, const char *ourname, int id,
412*5d5fbe79SDavid van Moolenbroek const struct chap_digest_type *digest,
413*5d5fbe79SDavid van Moolenbroek const unsigned char *challenge, const unsigned char *response,
414*5d5fbe79SDavid van Moolenbroek char *message, int message_space) {
415*5d5fbe79SDavid van Moolenbroek int ok;
416*5d5fbe79SDavid van Moolenbroek unsigned char secret[MAXSECRETLEN];
417*5d5fbe79SDavid van Moolenbroek int secret_len;
418*5d5fbe79SDavid van Moolenbroek
419*5d5fbe79SDavid van Moolenbroek /* Get the secret that the peer is supposed to know */
420*5d5fbe79SDavid van Moolenbroek if (!get_secret(pcb, name, ourname, (char *)secret, &secret_len, 1)) {
421*5d5fbe79SDavid van Moolenbroek ppp_error("No CHAP secret found for authenticating %q", name);
422*5d5fbe79SDavid van Moolenbroek return 0;
423*5d5fbe79SDavid van Moolenbroek }
424*5d5fbe79SDavid van Moolenbroek ok = digest->verify_response(pcb, id, name, secret, secret_len, challenge,
425*5d5fbe79SDavid van Moolenbroek response, message, message_space);
426*5d5fbe79SDavid van Moolenbroek memset(secret, 0, sizeof(secret));
427*5d5fbe79SDavid van Moolenbroek
428*5d5fbe79SDavid van Moolenbroek return ok;
429*5d5fbe79SDavid van Moolenbroek }
430*5d5fbe79SDavid van Moolenbroek #endif /* PPP_SERVER */
431*5d5fbe79SDavid van Moolenbroek
432*5d5fbe79SDavid van Moolenbroek /*
433*5d5fbe79SDavid van Moolenbroek * chap_respond - Generate and send a response to a challenge.
434*5d5fbe79SDavid van Moolenbroek */
435*5d5fbe79SDavid van Moolenbroek static void chap_respond(ppp_pcb *pcb, int id,
436*5d5fbe79SDavid van Moolenbroek unsigned char *pkt, int len) {
437*5d5fbe79SDavid van Moolenbroek int clen, nlen;
438*5d5fbe79SDavid van Moolenbroek int secret_len;
439*5d5fbe79SDavid van Moolenbroek struct pbuf *p;
440*5d5fbe79SDavid van Moolenbroek u_char *outp;
441*5d5fbe79SDavid van Moolenbroek char rname[MAXNAMELEN+1];
442*5d5fbe79SDavid van Moolenbroek char secret[MAXSECRETLEN+1];
443*5d5fbe79SDavid van Moolenbroek
444*5d5fbe79SDavid van Moolenbroek p = pbuf_alloc(PBUF_RAW, (u16_t)(RESP_MAX_PKTLEN), PPP_CTRL_PBUF_TYPE);
445*5d5fbe79SDavid van Moolenbroek if(NULL == p)
446*5d5fbe79SDavid van Moolenbroek return;
447*5d5fbe79SDavid van Moolenbroek if(p->tot_len != p->len) {
448*5d5fbe79SDavid van Moolenbroek pbuf_free(p);
449*5d5fbe79SDavid van Moolenbroek return;
450*5d5fbe79SDavid van Moolenbroek }
451*5d5fbe79SDavid van Moolenbroek
452*5d5fbe79SDavid van Moolenbroek if ((pcb->chap_client.flags & (LOWERUP | AUTH_STARTED)) != (LOWERUP | AUTH_STARTED))
453*5d5fbe79SDavid van Moolenbroek return; /* not ready */
454*5d5fbe79SDavid van Moolenbroek if (len < 2 || len < pkt[0] + 1)
455*5d5fbe79SDavid van Moolenbroek return; /* too short */
456*5d5fbe79SDavid van Moolenbroek clen = pkt[0];
457*5d5fbe79SDavid van Moolenbroek nlen = len - (clen + 1);
458*5d5fbe79SDavid van Moolenbroek
459*5d5fbe79SDavid van Moolenbroek /* Null terminate and clean remote name. */
460*5d5fbe79SDavid van Moolenbroek ppp_slprintf(rname, sizeof(rname), "%.*v", nlen, pkt + clen + 1);
461*5d5fbe79SDavid van Moolenbroek
462*5d5fbe79SDavid van Moolenbroek #if PPP_REMOTENAME
463*5d5fbe79SDavid van Moolenbroek /* Microsoft doesn't send their name back in the PPP packet */
464*5d5fbe79SDavid van Moolenbroek if (pcb->settings.explicit_remote || (pcb->settings.remote_name[0] != 0 && rname[0] == 0))
465*5d5fbe79SDavid van Moolenbroek strlcpy(rname, pcb->settings.remote_name, sizeof(rname));
466*5d5fbe79SDavid van Moolenbroek #endif /* PPP_REMOTENAME */
467*5d5fbe79SDavid van Moolenbroek
468*5d5fbe79SDavid van Moolenbroek /* get secret for authenticating ourselves with the specified host */
469*5d5fbe79SDavid van Moolenbroek if (!get_secret(pcb, pcb->chap_client.name, rname, secret, &secret_len, 0)) {
470*5d5fbe79SDavid van Moolenbroek secret_len = 0; /* assume null secret if can't find one */
471*5d5fbe79SDavid van Moolenbroek ppp_warn("No CHAP secret found for authenticating us to %q", rname);
472*5d5fbe79SDavid van Moolenbroek }
473*5d5fbe79SDavid van Moolenbroek
474*5d5fbe79SDavid van Moolenbroek outp = (u_char*)p->payload;
475*5d5fbe79SDavid van Moolenbroek MAKEHEADER(outp, PPP_CHAP);
476*5d5fbe79SDavid van Moolenbroek outp += CHAP_HDRLEN;
477*5d5fbe79SDavid van Moolenbroek
478*5d5fbe79SDavid van Moolenbroek pcb->chap_client.digest->make_response(pcb, outp, id, pcb->chap_client.name, pkt,
479*5d5fbe79SDavid van Moolenbroek secret, secret_len, pcb->chap_client.priv);
480*5d5fbe79SDavid van Moolenbroek memset(secret, 0, secret_len);
481*5d5fbe79SDavid van Moolenbroek
482*5d5fbe79SDavid van Moolenbroek clen = *outp;
483*5d5fbe79SDavid van Moolenbroek nlen = strlen(pcb->chap_client.name);
484*5d5fbe79SDavid van Moolenbroek memcpy(outp + clen + 1, pcb->chap_client.name, nlen);
485*5d5fbe79SDavid van Moolenbroek
486*5d5fbe79SDavid van Moolenbroek outp = (u_char*)p->payload + PPP_HDRLEN;
487*5d5fbe79SDavid van Moolenbroek len = CHAP_HDRLEN + clen + 1 + nlen;
488*5d5fbe79SDavid van Moolenbroek outp[0] = CHAP_RESPONSE;
489*5d5fbe79SDavid van Moolenbroek outp[1] = id;
490*5d5fbe79SDavid van Moolenbroek outp[2] = len >> 8;
491*5d5fbe79SDavid van Moolenbroek outp[3] = len;
492*5d5fbe79SDavid van Moolenbroek
493*5d5fbe79SDavid van Moolenbroek pbuf_realloc(p, PPP_HDRLEN + len);
494*5d5fbe79SDavid van Moolenbroek ppp_write(pcb, p);
495*5d5fbe79SDavid van Moolenbroek }
496*5d5fbe79SDavid van Moolenbroek
497*5d5fbe79SDavid van Moolenbroek static void chap_handle_status(ppp_pcb *pcb, int code, int id,
498*5d5fbe79SDavid van Moolenbroek unsigned char *pkt, int len) {
499*5d5fbe79SDavid van Moolenbroek const char *msg = NULL;
500*5d5fbe79SDavid van Moolenbroek LWIP_UNUSED_ARG(id);
501*5d5fbe79SDavid van Moolenbroek
502*5d5fbe79SDavid van Moolenbroek if ((pcb->chap_client.flags & (AUTH_DONE|AUTH_STARTED|LOWERUP))
503*5d5fbe79SDavid van Moolenbroek != (AUTH_STARTED|LOWERUP))
504*5d5fbe79SDavid van Moolenbroek return;
505*5d5fbe79SDavid van Moolenbroek pcb->chap_client.flags |= AUTH_DONE;
506*5d5fbe79SDavid van Moolenbroek
507*5d5fbe79SDavid van Moolenbroek if (code == CHAP_SUCCESS) {
508*5d5fbe79SDavid van Moolenbroek /* used for MS-CHAP v2 mutual auth, yuck */
509*5d5fbe79SDavid van Moolenbroek if (pcb->chap_client.digest->check_success != NULL) {
510*5d5fbe79SDavid van Moolenbroek if (!(*pcb->chap_client.digest->check_success)(pcb, pkt, len, pcb->chap_client.priv))
511*5d5fbe79SDavid van Moolenbroek code = CHAP_FAILURE;
512*5d5fbe79SDavid van Moolenbroek } else
513*5d5fbe79SDavid van Moolenbroek msg = "CHAP authentication succeeded";
514*5d5fbe79SDavid van Moolenbroek } else {
515*5d5fbe79SDavid van Moolenbroek if (pcb->chap_client.digest->handle_failure != NULL)
516*5d5fbe79SDavid van Moolenbroek (*pcb->chap_client.digest->handle_failure)(pcb, pkt, len);
517*5d5fbe79SDavid van Moolenbroek else
518*5d5fbe79SDavid van Moolenbroek msg = "CHAP authentication failed";
519*5d5fbe79SDavid van Moolenbroek }
520*5d5fbe79SDavid van Moolenbroek if (msg) {
521*5d5fbe79SDavid van Moolenbroek if (len > 0)
522*5d5fbe79SDavid van Moolenbroek ppp_info("%s: %.*v", msg, len, pkt);
523*5d5fbe79SDavid van Moolenbroek else
524*5d5fbe79SDavid van Moolenbroek ppp_info("%s", msg);
525*5d5fbe79SDavid van Moolenbroek }
526*5d5fbe79SDavid van Moolenbroek if (code == CHAP_SUCCESS)
527*5d5fbe79SDavid van Moolenbroek auth_withpeer_success(pcb, PPP_CHAP, pcb->chap_client.digest->code);
528*5d5fbe79SDavid van Moolenbroek else {
529*5d5fbe79SDavid van Moolenbroek pcb->chap_client.flags |= AUTH_FAILED;
530*5d5fbe79SDavid van Moolenbroek ppp_error("CHAP authentication failed");
531*5d5fbe79SDavid van Moolenbroek auth_withpeer_fail(pcb, PPP_CHAP);
532*5d5fbe79SDavid van Moolenbroek }
533*5d5fbe79SDavid van Moolenbroek }
534*5d5fbe79SDavid van Moolenbroek
535*5d5fbe79SDavid van Moolenbroek static void chap_input(ppp_pcb *pcb, unsigned char *pkt, int pktlen) {
536*5d5fbe79SDavid van Moolenbroek unsigned char code, id;
537*5d5fbe79SDavid van Moolenbroek int len;
538*5d5fbe79SDavid van Moolenbroek
539*5d5fbe79SDavid van Moolenbroek if (pktlen < CHAP_HDRLEN)
540*5d5fbe79SDavid van Moolenbroek return;
541*5d5fbe79SDavid van Moolenbroek GETCHAR(code, pkt);
542*5d5fbe79SDavid van Moolenbroek GETCHAR(id, pkt);
543*5d5fbe79SDavid van Moolenbroek GETSHORT(len, pkt);
544*5d5fbe79SDavid van Moolenbroek if (len < CHAP_HDRLEN || len > pktlen)
545*5d5fbe79SDavid van Moolenbroek return;
546*5d5fbe79SDavid van Moolenbroek len -= CHAP_HDRLEN;
547*5d5fbe79SDavid van Moolenbroek
548*5d5fbe79SDavid van Moolenbroek switch (code) {
549*5d5fbe79SDavid van Moolenbroek case CHAP_CHALLENGE:
550*5d5fbe79SDavid van Moolenbroek chap_respond(pcb, id, pkt, len);
551*5d5fbe79SDavid van Moolenbroek break;
552*5d5fbe79SDavid van Moolenbroek #if PPP_SERVER
553*5d5fbe79SDavid van Moolenbroek case CHAP_RESPONSE:
554*5d5fbe79SDavid van Moolenbroek chap_handle_response(pcb, id, pkt, len);
555*5d5fbe79SDavid van Moolenbroek break;
556*5d5fbe79SDavid van Moolenbroek #endif /* PPP_SERVER */
557*5d5fbe79SDavid van Moolenbroek case CHAP_FAILURE:
558*5d5fbe79SDavid van Moolenbroek case CHAP_SUCCESS:
559*5d5fbe79SDavid van Moolenbroek chap_handle_status(pcb, code, id, pkt, len);
560*5d5fbe79SDavid van Moolenbroek break;
561*5d5fbe79SDavid van Moolenbroek default:
562*5d5fbe79SDavid van Moolenbroek break;
563*5d5fbe79SDavid van Moolenbroek }
564*5d5fbe79SDavid van Moolenbroek }
565*5d5fbe79SDavid van Moolenbroek
566*5d5fbe79SDavid van Moolenbroek static void chap_protrej(ppp_pcb *pcb) {
567*5d5fbe79SDavid van Moolenbroek
568*5d5fbe79SDavid van Moolenbroek #if PPP_SERVER
569*5d5fbe79SDavid van Moolenbroek if (pcb->chap_server.flags & TIMEOUT_PENDING) {
570*5d5fbe79SDavid van Moolenbroek pcb->chap_server.flags &= ~TIMEOUT_PENDING;
571*5d5fbe79SDavid van Moolenbroek UNTIMEOUT(chap_timeout, pcb);
572*5d5fbe79SDavid van Moolenbroek }
573*5d5fbe79SDavid van Moolenbroek if (pcb->chap_server.flags & AUTH_STARTED) {
574*5d5fbe79SDavid van Moolenbroek pcb->chap_server.flags = 0;
575*5d5fbe79SDavid van Moolenbroek auth_peer_fail(pcb, PPP_CHAP);
576*5d5fbe79SDavid van Moolenbroek }
577*5d5fbe79SDavid van Moolenbroek #endif /* PPP_SERVER */
578*5d5fbe79SDavid van Moolenbroek if ((pcb->chap_client.flags & (AUTH_STARTED|AUTH_DONE)) == AUTH_STARTED) {
579*5d5fbe79SDavid van Moolenbroek pcb->chap_client.flags &= ~AUTH_STARTED;
580*5d5fbe79SDavid van Moolenbroek ppp_error("CHAP authentication failed due to protocol-reject");
581*5d5fbe79SDavid van Moolenbroek auth_withpeer_fail(pcb, PPP_CHAP);
582*5d5fbe79SDavid van Moolenbroek }
583*5d5fbe79SDavid van Moolenbroek }
584*5d5fbe79SDavid van Moolenbroek
585*5d5fbe79SDavid van Moolenbroek #if PRINTPKT_SUPPORT
586*5d5fbe79SDavid van Moolenbroek /*
587*5d5fbe79SDavid van Moolenbroek * chap_print_pkt - print the contents of a CHAP packet.
588*5d5fbe79SDavid van Moolenbroek */
589*5d5fbe79SDavid van Moolenbroek static const char* const chap_code_names[] = {
590*5d5fbe79SDavid van Moolenbroek "Challenge", "Response", "Success", "Failure"
591*5d5fbe79SDavid van Moolenbroek };
592*5d5fbe79SDavid van Moolenbroek
593*5d5fbe79SDavid van Moolenbroek static int chap_print_pkt(const unsigned char *p, int plen,
594*5d5fbe79SDavid van Moolenbroek void (*printer) (void *, const char *, ...), void *arg) {
595*5d5fbe79SDavid van Moolenbroek int code, id, len;
596*5d5fbe79SDavid van Moolenbroek int clen, nlen;
597*5d5fbe79SDavid van Moolenbroek unsigned char x;
598*5d5fbe79SDavid van Moolenbroek
599*5d5fbe79SDavid van Moolenbroek if (plen < CHAP_HDRLEN)
600*5d5fbe79SDavid van Moolenbroek return 0;
601*5d5fbe79SDavid van Moolenbroek GETCHAR(code, p);
602*5d5fbe79SDavid van Moolenbroek GETCHAR(id, p);
603*5d5fbe79SDavid van Moolenbroek GETSHORT(len, p);
604*5d5fbe79SDavid van Moolenbroek if (len < CHAP_HDRLEN || len > plen)
605*5d5fbe79SDavid van Moolenbroek return 0;
606*5d5fbe79SDavid van Moolenbroek
607*5d5fbe79SDavid van Moolenbroek if (code >= 1 && code <= (int)LWIP_ARRAYSIZE(chap_code_names))
608*5d5fbe79SDavid van Moolenbroek printer(arg, " %s", chap_code_names[code-1]);
609*5d5fbe79SDavid van Moolenbroek else
610*5d5fbe79SDavid van Moolenbroek printer(arg, " code=0x%x", code);
611*5d5fbe79SDavid van Moolenbroek printer(arg, " id=0x%x", id);
612*5d5fbe79SDavid van Moolenbroek len -= CHAP_HDRLEN;
613*5d5fbe79SDavid van Moolenbroek switch (code) {
614*5d5fbe79SDavid van Moolenbroek case CHAP_CHALLENGE:
615*5d5fbe79SDavid van Moolenbroek case CHAP_RESPONSE:
616*5d5fbe79SDavid van Moolenbroek if (len < 1)
617*5d5fbe79SDavid van Moolenbroek break;
618*5d5fbe79SDavid van Moolenbroek clen = p[0];
619*5d5fbe79SDavid van Moolenbroek if (len < clen + 1)
620*5d5fbe79SDavid van Moolenbroek break;
621*5d5fbe79SDavid van Moolenbroek ++p;
622*5d5fbe79SDavid van Moolenbroek nlen = len - clen - 1;
623*5d5fbe79SDavid van Moolenbroek printer(arg, " <");
624*5d5fbe79SDavid van Moolenbroek for (; clen > 0; --clen) {
625*5d5fbe79SDavid van Moolenbroek GETCHAR(x, p);
626*5d5fbe79SDavid van Moolenbroek printer(arg, "%.2x", x);
627*5d5fbe79SDavid van Moolenbroek }
628*5d5fbe79SDavid van Moolenbroek printer(arg, ">, name = ");
629*5d5fbe79SDavid van Moolenbroek ppp_print_string(p, nlen, printer, arg);
630*5d5fbe79SDavid van Moolenbroek break;
631*5d5fbe79SDavid van Moolenbroek case CHAP_FAILURE:
632*5d5fbe79SDavid van Moolenbroek case CHAP_SUCCESS:
633*5d5fbe79SDavid van Moolenbroek printer(arg, " ");
634*5d5fbe79SDavid van Moolenbroek ppp_print_string(p, len, printer, arg);
635*5d5fbe79SDavid van Moolenbroek break;
636*5d5fbe79SDavid van Moolenbroek default:
637*5d5fbe79SDavid van Moolenbroek for (clen = len; clen > 0; --clen) {
638*5d5fbe79SDavid van Moolenbroek GETCHAR(x, p);
639*5d5fbe79SDavid van Moolenbroek printer(arg, " %.2x", x);
640*5d5fbe79SDavid van Moolenbroek }
641*5d5fbe79SDavid van Moolenbroek /* no break */
642*5d5fbe79SDavid van Moolenbroek }
643*5d5fbe79SDavid van Moolenbroek
644*5d5fbe79SDavid van Moolenbroek return len + CHAP_HDRLEN;
645*5d5fbe79SDavid van Moolenbroek }
646*5d5fbe79SDavid van Moolenbroek #endif /* PRINTPKT_SUPPORT */
647*5d5fbe79SDavid van Moolenbroek
648*5d5fbe79SDavid van Moolenbroek const struct protent chap_protent = {
649*5d5fbe79SDavid van Moolenbroek PPP_CHAP,
650*5d5fbe79SDavid van Moolenbroek chap_init,
651*5d5fbe79SDavid van Moolenbroek chap_input,
652*5d5fbe79SDavid van Moolenbroek chap_protrej,
653*5d5fbe79SDavid van Moolenbroek chap_lowerup,
654*5d5fbe79SDavid van Moolenbroek chap_lowerdown,
655*5d5fbe79SDavid van Moolenbroek NULL, /* open */
656*5d5fbe79SDavid van Moolenbroek NULL, /* close */
657*5d5fbe79SDavid van Moolenbroek #if PRINTPKT_SUPPORT
658*5d5fbe79SDavid van Moolenbroek chap_print_pkt,
659*5d5fbe79SDavid van Moolenbroek #endif /* PRINTPKT_SUPPORT */
660*5d5fbe79SDavid van Moolenbroek #if PPP_DATAINPUT
661*5d5fbe79SDavid van Moolenbroek NULL, /* datainput */
662*5d5fbe79SDavid van Moolenbroek #endif /* PPP_DATAINPUT */
663*5d5fbe79SDavid van Moolenbroek #if PRINTPKT_SUPPORT
664*5d5fbe79SDavid van Moolenbroek "CHAP", /* name */
665*5d5fbe79SDavid van Moolenbroek NULL, /* data_name */
666*5d5fbe79SDavid van Moolenbroek #endif /* PRINTPKT_SUPPORT */
667*5d5fbe79SDavid van Moolenbroek #if PPP_OPTIONS
668*5d5fbe79SDavid van Moolenbroek chap_option_list,
669*5d5fbe79SDavid van Moolenbroek NULL, /* check_options */
670*5d5fbe79SDavid van Moolenbroek #endif /* PPP_OPTIONS */
671*5d5fbe79SDavid van Moolenbroek #if DEMAND_SUPPORT
672*5d5fbe79SDavid van Moolenbroek NULL,
673*5d5fbe79SDavid van Moolenbroek NULL
674*5d5fbe79SDavid van Moolenbroek #endif /* DEMAND_SUPPORT */
675*5d5fbe79SDavid van Moolenbroek };
676*5d5fbe79SDavid van Moolenbroek
677*5d5fbe79SDavid van Moolenbroek #endif /* PPP_SUPPORT && CHAP_SUPPORT */
678