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