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