eap.c revision 1.5 1 1.5 christos /* $NetBSD: eap.c,v 1.5 2020/02/12 01:51:52 christos Exp $ */
2 1.1 christos /*
3 1.1 christos * eap.c - Extensible Authentication Protocol for PPP (RFC 2284)
4 1.1 christos *
5 1.1 christos * Copyright (c) 2001 by Sun Microsystems, Inc.
6 1.1 christos * All rights reserved.
7 1.1 christos *
8 1.1 christos * Non-exclusive rights to redistribute, modify, translate, and use
9 1.1 christos * this software in source and binary forms, in whole or in part, is
10 1.1 christos * hereby granted, provided that the above copyright notice is
11 1.1 christos * duplicated in any source form, and that neither the name of the
12 1.1 christos * copyright holder nor the author is used to endorse or promote
13 1.1 christos * products derived from this software.
14 1.1 christos *
15 1.1 christos * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16 1.1 christos * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17 1.1 christos * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18 1.1 christos *
19 1.1 christos * Original version by James Carlson
20 1.1 christos *
21 1.1 christos * This implementation of EAP supports MD5-Challenge and SRP-SHA1
22 1.1 christos * authentication styles. Note that support of MD5-Challenge is a
23 1.1 christos * requirement of RFC 2284, and that it's essentially just a
24 1.1 christos * reimplementation of regular RFC 1994 CHAP using EAP messages.
25 1.1 christos *
26 1.1 christos * As an authenticator ("server"), there are multiple phases for each
27 1.1 christos * style. In the first phase of each style, the unauthenticated peer
28 1.1 christos * name is queried using the EAP Identity request type. If the
29 1.1 christos * "remotename" option is used, then this phase is skipped, because
30 1.1 christos * the peer's name is presumed to be known.
31 1.1 christos *
32 1.1 christos * For MD5-Challenge, there are two phases, and the second phase
33 1.1 christos * consists of sending the challenge itself and handling the
34 1.1 christos * associated response.
35 1.1 christos *
36 1.1 christos * For SRP-SHA1, there are four phases. The second sends 's', 'N',
37 1.1 christos * and 'g'. The reply contains 'A'. The third sends 'B', and the
38 1.1 christos * reply contains 'M1'. The forth sends the 'M2' value.
39 1.1 christos *
40 1.1 christos * As an authenticatee ("client"), there's just a single phase --
41 1.1 christos * responding to the queries generated by the peer. EAP is an
42 1.1 christos * authenticator-driven protocol.
43 1.1 christos *
44 1.1 christos * Based on draft-ietf-pppext-eap-srp-03.txt.
45 1.1 christos */
46 1.1 christos
47 1.2 christos #include <sys/cdefs.h>
48 1.2 christos #if 0
49 1.1 christos #define RCSID "Id: eap.c,v 1.4 2004/11/09 22:39:25 paulus Exp "
50 1.2 christos static const char rcsid[] = RCSID;
51 1.2 christos #else
52 1.5 christos __RCSID("$NetBSD: eap.c,v 1.5 2020/02/12 01:51:52 christos Exp $");
53 1.2 christos #endif
54 1.1 christos
55 1.1 christos /*
56 1.1 christos * TODO:
57 1.1 christos */
58 1.1 christos
59 1.1 christos #include <stdio.h>
60 1.1 christos #include <stdlib.h>
61 1.1 christos #include <string.h>
62 1.1 christos #include <unistd.h>
63 1.1 christos #include <pwd.h>
64 1.1 christos #include <sys/types.h>
65 1.1 christos #include <sys/stat.h>
66 1.1 christos #include <fcntl.h>
67 1.1 christos #include <assert.h>
68 1.1 christos #include <errno.h>
69 1.2 christos #include <md5.h>
70 1.1 christos
71 1.1 christos #include "pppd.h"
72 1.1 christos #include "pathnames.h"
73 1.1 christos #include "eap.h"
74 1.1 christos
75 1.1 christos #ifdef USE_SRP
76 1.1 christos #include <t_pwd.h>
77 1.1 christos #include <t_server.h>
78 1.1 christos #include <t_client.h>
79 1.1 christos #include "pppcrypt.h"
80 1.1 christos #endif /* USE_SRP */
81 1.1 christos
82 1.1 christos #ifndef SHA_DIGESTSIZE
83 1.1 christos #define SHA_DIGESTSIZE 20
84 1.1 christos #endif
85 1.1 christos
86 1.1 christos
87 1.1 christos eap_state eap_states[NUM_PPP]; /* EAP state; one for each unit */
88 1.1 christos #ifdef USE_SRP
89 1.1 christos static char *pn_secret = NULL; /* Pseudonym generating secret */
90 1.1 christos #endif
91 1.1 christos
92 1.1 christos /*
93 1.1 christos * Command-line options.
94 1.1 christos */
95 1.1 christos static option_t eap_option_list[] = {
96 1.1 christos { "eap-restart", o_int, &eap_states[0].es_server.ea_timeout,
97 1.1 christos "Set retransmit timeout for EAP Requests (server)" },
98 1.1 christos { "eap-max-sreq", o_int, &eap_states[0].es_server.ea_maxrequests,
99 1.1 christos "Set max number of EAP Requests sent (server)" },
100 1.1 christos { "eap-timeout", o_int, &eap_states[0].es_client.ea_timeout,
101 1.1 christos "Set time limit for peer EAP authentication" },
102 1.1 christos { "eap-max-rreq", o_int, &eap_states[0].es_client.ea_maxrequests,
103 1.1 christos "Set max number of EAP Requests allows (client)" },
104 1.1 christos { "eap-interval", o_int, &eap_states[0].es_rechallenge,
105 1.1 christos "Set interval for EAP rechallenge" },
106 1.1 christos #ifdef USE_SRP
107 1.1 christos { "srp-interval", o_int, &eap_states[0].es_lwrechallenge,
108 1.1 christos "Set interval for SRP lightweight rechallenge" },
109 1.1 christos { "srp-pn-secret", o_string, &pn_secret,
110 1.1 christos "Long term pseudonym generation secret" },
111 1.1 christos { "srp-use-pseudonym", o_bool, &eap_states[0].es_usepseudo,
112 1.1 christos "Use pseudonym if offered one by server", 1 },
113 1.1 christos #endif
114 1.1 christos { NULL }
115 1.1 christos };
116 1.1 christos
117 1.1 christos /*
118 1.1 christos * Protocol entry points.
119 1.1 christos */
120 1.1 christos static void eap_init __P((int unit));
121 1.1 christos static void eap_input __P((int unit, u_char *inp, int inlen));
122 1.1 christos static void eap_protrej __P((int unit));
123 1.1 christos static void eap_lowerup __P((int unit));
124 1.1 christos static void eap_lowerdown __P((int unit));
125 1.1 christos static int eap_printpkt __P((u_char *inp, int inlen,
126 1.1 christos void (*)(void *arg, char *fmt, ...), void *arg));
127 1.1 christos
128 1.1 christos struct protent eap_protent = {
129 1.1 christos PPP_EAP, /* protocol number */
130 1.1 christos eap_init, /* initialization procedure */
131 1.1 christos eap_input, /* process a received packet */
132 1.1 christos eap_protrej, /* process a received protocol-reject */
133 1.1 christos eap_lowerup, /* lower layer has gone up */
134 1.1 christos eap_lowerdown, /* lower layer has gone down */
135 1.1 christos NULL, /* open the protocol */
136 1.1 christos NULL, /* close the protocol */
137 1.1 christos eap_printpkt, /* print a packet in readable form */
138 1.1 christos NULL, /* process a received data packet */
139 1.1 christos 1, /* protocol enabled */
140 1.1 christos "EAP", /* text name of protocol */
141 1.1 christos NULL, /* text name of corresponding data protocol */
142 1.1 christos eap_option_list, /* list of command-line options */
143 1.1 christos NULL, /* check requested options; assign defaults */
144 1.1 christos NULL, /* configure interface for demand-dial */
145 1.1 christos NULL /* say whether to bring up link for this pkt */
146 1.1 christos };
147 1.1 christos
148 1.1 christos /*
149 1.1 christos * A well-known 2048 bit modulus.
150 1.1 christos */
151 1.2 christos #ifdef USE_SRP
152 1.1 christos static const u_char wkmodulus[] = {
153 1.1 christos 0xAC, 0x6B, 0xDB, 0x41, 0x32, 0x4A, 0x9A, 0x9B,
154 1.1 christos 0xF1, 0x66, 0xDE, 0x5E, 0x13, 0x89, 0x58, 0x2F,
155 1.1 christos 0xAF, 0x72, 0xB6, 0x65, 0x19, 0x87, 0xEE, 0x07,
156 1.1 christos 0xFC, 0x31, 0x92, 0x94, 0x3D, 0xB5, 0x60, 0x50,
157 1.1 christos 0xA3, 0x73, 0x29, 0xCB, 0xB4, 0xA0, 0x99, 0xED,
158 1.1 christos 0x81, 0x93, 0xE0, 0x75, 0x77, 0x67, 0xA1, 0x3D,
159 1.1 christos 0xD5, 0x23, 0x12, 0xAB, 0x4B, 0x03, 0x31, 0x0D,
160 1.1 christos 0xCD, 0x7F, 0x48, 0xA9, 0xDA, 0x04, 0xFD, 0x50,
161 1.1 christos 0xE8, 0x08, 0x39, 0x69, 0xED, 0xB7, 0x67, 0xB0,
162 1.1 christos 0xCF, 0x60, 0x95, 0x17, 0x9A, 0x16, 0x3A, 0xB3,
163 1.1 christos 0x66, 0x1A, 0x05, 0xFB, 0xD5, 0xFA, 0xAA, 0xE8,
164 1.1 christos 0x29, 0x18, 0xA9, 0x96, 0x2F, 0x0B, 0x93, 0xB8,
165 1.1 christos 0x55, 0xF9, 0x79, 0x93, 0xEC, 0x97, 0x5E, 0xEA,
166 1.1 christos 0xA8, 0x0D, 0x74, 0x0A, 0xDB, 0xF4, 0xFF, 0x74,
167 1.1 christos 0x73, 0x59, 0xD0, 0x41, 0xD5, 0xC3, 0x3E, 0xA7,
168 1.1 christos 0x1D, 0x28, 0x1E, 0x44, 0x6B, 0x14, 0x77, 0x3B,
169 1.1 christos 0xCA, 0x97, 0xB4, 0x3A, 0x23, 0xFB, 0x80, 0x16,
170 1.1 christos 0x76, 0xBD, 0x20, 0x7A, 0x43, 0x6C, 0x64, 0x81,
171 1.1 christos 0xF1, 0xD2, 0xB9, 0x07, 0x87, 0x17, 0x46, 0x1A,
172 1.1 christos 0x5B, 0x9D, 0x32, 0xE6, 0x88, 0xF8, 0x77, 0x48,
173 1.1 christos 0x54, 0x45, 0x23, 0xB5, 0x24, 0xB0, 0xD5, 0x7D,
174 1.1 christos 0x5E, 0xA7, 0x7A, 0x27, 0x75, 0xD2, 0xEC, 0xFA,
175 1.1 christos 0x03, 0x2C, 0xFB, 0xDB, 0xF5, 0x2F, 0xB3, 0x78,
176 1.1 christos 0x61, 0x60, 0x27, 0x90, 0x04, 0xE5, 0x7A, 0xE6,
177 1.1 christos 0xAF, 0x87, 0x4E, 0x73, 0x03, 0xCE, 0x53, 0x29,
178 1.1 christos 0x9C, 0xCC, 0x04, 0x1C, 0x7B, 0xC3, 0x08, 0xD8,
179 1.1 christos 0x2A, 0x56, 0x98, 0xF3, 0xA8, 0xD0, 0xC3, 0x82,
180 1.1 christos 0x71, 0xAE, 0x35, 0xF8, 0xE9, 0xDB, 0xFB, 0xB6,
181 1.1 christos 0x94, 0xB5, 0xC8, 0x03, 0xD8, 0x9F, 0x7A, 0xE4,
182 1.1 christos 0x35, 0xDE, 0x23, 0x6D, 0x52, 0x5F, 0x54, 0x75,
183 1.1 christos 0x9B, 0x65, 0xE3, 0x72, 0xFC, 0xD6, 0x8E, 0xF2,
184 1.1 christos 0x0F, 0xA7, 0x11, 0x1F, 0x9E, 0x4A, 0xFF, 0x73
185 1.1 christos };
186 1.2 christos #endif
187 1.1 christos
188 1.1 christos /* Local forward declarations. */
189 1.1 christos static void eap_server_timeout __P((void *arg));
190 1.2 christos static const char *eap_state_name __P((enum eap_state_code));
191 1.2 christos static void eap_client_timeout __P((void *arg));
192 1.2 christos static void eap_send_failure __P((eap_state *));
193 1.2 christos static void eap_send_success __P((eap_state *));
194 1.2 christos static void eap_figure_next_state __P((eap_state *, int));
195 1.2 christos static void eap_send_request __P((eap_state *));
196 1.2 christos static void eap_rechallenge __P((void *));
197 1.2 christos static void srp_lwrechallenge __P((void *));
198 1.2 christos static void eap_send_response __P((eap_state *, u_char, u_char, const u_char *, int));
199 1.2 christos static void eap_chap_response __P((eap_state *, u_char, const u_char *, const char *, int));
200 1.2 christos static void eap_send_nak __P((eap_state *,u_char,u_char));
201 1.2 christos static void eap_request __P((eap_state *, u_char *, int, int));
202 1.2 christos static void eap_response __P((eap_state *, u_char *, int, int));
203 1.2 christos static void eap_success __P((eap_state *, u_char *, int, int));
204 1.2 christos static void eap_failure __P((eap_state *, u_char *, int, int));
205 1.1 christos
206 1.1 christos /*
207 1.1 christos * Convert EAP state code to printable string for debug.
208 1.1 christos */
209 1.1 christos static const char *
210 1.1 christos eap_state_name(esc)
211 1.1 christos enum eap_state_code esc;
212 1.1 christos {
213 1.1 christos static const char *state_names[] = { EAP_STATES };
214 1.1 christos
215 1.1 christos return (state_names[(int)esc]);
216 1.1 christos }
217 1.1 christos
218 1.1 christos /*
219 1.1 christos * eap_init - Initialize state for an EAP user. This is currently
220 1.1 christos * called once by main() during start-up.
221 1.1 christos */
222 1.1 christos static void
223 1.1 christos eap_init(unit)
224 1.1 christos int unit;
225 1.1 christos {
226 1.1 christos eap_state *esp = &eap_states[unit];
227 1.1 christos
228 1.1 christos BZERO(esp, sizeof (*esp));
229 1.1 christos esp->es_unit = unit;
230 1.1 christos esp->es_server.ea_timeout = EAP_DEFTIMEOUT;
231 1.1 christos esp->es_server.ea_maxrequests = EAP_DEFTRANSMITS;
232 1.1 christos esp->es_server.ea_id = (u_char)(drand48() * 0x100);
233 1.1 christos esp->es_client.ea_timeout = EAP_DEFREQTIME;
234 1.1 christos esp->es_client.ea_maxrequests = EAP_DEFALLOWREQ;
235 1.1 christos }
236 1.1 christos
237 1.1 christos /*
238 1.1 christos * eap_client_timeout - Give up waiting for the peer to send any
239 1.1 christos * Request messages.
240 1.1 christos */
241 1.1 christos static void
242 1.1 christos eap_client_timeout(arg)
243 1.1 christos void *arg;
244 1.1 christos {
245 1.1 christos eap_state *esp = (eap_state *) arg;
246 1.1 christos
247 1.1 christos if (!eap_client_active(esp))
248 1.1 christos return;
249 1.1 christos
250 1.1 christos error("EAP: timeout waiting for Request from peer");
251 1.1 christos auth_withpeer_fail(esp->es_unit, PPP_EAP);
252 1.1 christos esp->es_client.ea_state = eapBadAuth;
253 1.1 christos }
254 1.1 christos
255 1.1 christos /*
256 1.1 christos * eap_authwithpeer - Authenticate to our peer (behave as client).
257 1.1 christos *
258 1.1 christos * Start client state and wait for requests. This is called only
259 1.1 christos * after eap_lowerup.
260 1.1 christos */
261 1.1 christos void
262 1.1 christos eap_authwithpeer(unit, localname)
263 1.1 christos int unit;
264 1.1 christos char *localname;
265 1.1 christos {
266 1.1 christos eap_state *esp = &eap_states[unit];
267 1.1 christos
268 1.1 christos /* Save the peer name we're given */
269 1.1 christos esp->es_client.ea_name = localname;
270 1.1 christos esp->es_client.ea_namelen = strlen(localname);
271 1.1 christos
272 1.1 christos esp->es_client.ea_state = eapListen;
273 1.1 christos
274 1.1 christos /*
275 1.1 christos * Start a timer so that if the other end just goes
276 1.1 christos * silent, we don't sit here waiting forever.
277 1.1 christos */
278 1.1 christos if (esp->es_client.ea_timeout > 0)
279 1.1 christos TIMEOUT(eap_client_timeout, (void *)esp,
280 1.1 christos esp->es_client.ea_timeout);
281 1.1 christos }
282 1.1 christos
283 1.1 christos /*
284 1.1 christos * Format a standard EAP Failure message and send it to the peer.
285 1.1 christos * (Server operation)
286 1.1 christos */
287 1.1 christos static void
288 1.1 christos eap_send_failure(esp)
289 1.1 christos eap_state *esp;
290 1.1 christos {
291 1.1 christos u_char *outp;
292 1.1 christos
293 1.1 christos outp = outpacket_buf;
294 1.1 christos
295 1.1 christos MAKEHEADER(outp, PPP_EAP);
296 1.1 christos
297 1.1 christos PUTCHAR(EAP_FAILURE, outp);
298 1.1 christos esp->es_server.ea_id++;
299 1.1 christos PUTCHAR(esp->es_server.ea_id, outp);
300 1.1 christos PUTSHORT(EAP_HEADERLEN, outp);
301 1.1 christos
302 1.1 christos output(esp->es_unit, outpacket_buf, EAP_HEADERLEN + PPP_HDRLEN);
303 1.1 christos
304 1.1 christos esp->es_server.ea_state = eapBadAuth;
305 1.1 christos auth_peer_fail(esp->es_unit, PPP_EAP);
306 1.1 christos }
307 1.1 christos
308 1.1 christos /*
309 1.1 christos * Format a standard EAP Success message and send it to the peer.
310 1.1 christos * (Server operation)
311 1.1 christos */
312 1.1 christos static void
313 1.1 christos eap_send_success(esp)
314 1.1 christos eap_state *esp;
315 1.1 christos {
316 1.1 christos u_char *outp;
317 1.1 christos
318 1.1 christos outp = outpacket_buf;
319 1.1 christos
320 1.1 christos MAKEHEADER(outp, PPP_EAP);
321 1.1 christos
322 1.1 christos PUTCHAR(EAP_SUCCESS, outp);
323 1.1 christos esp->es_server.ea_id++;
324 1.1 christos PUTCHAR(esp->es_server.ea_id, outp);
325 1.1 christos PUTSHORT(EAP_HEADERLEN, outp);
326 1.1 christos
327 1.1 christos output(esp->es_unit, outpacket_buf, PPP_HDRLEN + EAP_HEADERLEN);
328 1.1 christos
329 1.1 christos auth_peer_success(esp->es_unit, PPP_EAP, 0,
330 1.1 christos esp->es_server.ea_peer, esp->es_server.ea_peerlen);
331 1.1 christos }
332 1.1 christos
333 1.1 christos #ifdef USE_SRP
334 1.1 christos /*
335 1.1 christos * Set DES key according to pseudonym-generating secret and current
336 1.1 christos * date.
337 1.1 christos */
338 1.1 christos static bool
339 1.1 christos pncrypt_setkey(int timeoffs)
340 1.1 christos {
341 1.1 christos struct tm *tp;
342 1.1 christos char tbuf[9];
343 1.1 christos SHA1_CTX ctxt;
344 1.1 christos u_char dig[SHA_DIGESTSIZE];
345 1.1 christos time_t reftime;
346 1.1 christos
347 1.1 christos if (pn_secret == NULL)
348 1.1 christos return (0);
349 1.1 christos reftime = time(NULL) + timeoffs;
350 1.1 christos tp = localtime(&reftime);
351 1.1 christos SHA1Init(&ctxt);
352 1.1 christos SHA1Update(&ctxt, pn_secret, strlen(pn_secret));
353 1.1 christos strftime(tbuf, sizeof (tbuf), "%Y%m%d", tp);
354 1.1 christos SHA1Update(&ctxt, tbuf, strlen(tbuf));
355 1.1 christos SHA1Final(dig, &ctxt);
356 1.1 christos return (DesSetkey(dig));
357 1.1 christos }
358 1.1 christos
359 1.1 christos static char base64[] =
360 1.1 christos "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
361 1.1 christos
362 1.1 christos struct b64state {
363 1.1 christos u_int32_t bs_bits;
364 1.1 christos int bs_offs;
365 1.1 christos };
366 1.1 christos
367 1.1 christos static int
368 1.1 christos b64enc(bs, inp, inlen, outp)
369 1.1 christos struct b64state *bs;
370 1.1 christos u_char *inp;
371 1.1 christos int inlen;
372 1.1 christos u_char *outp;
373 1.1 christos {
374 1.1 christos int outlen = 0;
375 1.1 christos
376 1.1 christos while (inlen > 0) {
377 1.1 christos bs->bs_bits = (bs->bs_bits << 8) | *inp++;
378 1.1 christos inlen--;
379 1.1 christos bs->bs_offs += 8;
380 1.1 christos if (bs->bs_offs >= 24) {
381 1.1 christos *outp++ = base64[(bs->bs_bits >> 18) & 0x3F];
382 1.1 christos *outp++ = base64[(bs->bs_bits >> 12) & 0x3F];
383 1.1 christos *outp++ = base64[(bs->bs_bits >> 6) & 0x3F];
384 1.1 christos *outp++ = base64[bs->bs_bits & 0x3F];
385 1.1 christos outlen += 4;
386 1.1 christos bs->bs_offs = 0;
387 1.1 christos bs->bs_bits = 0;
388 1.1 christos }
389 1.1 christos }
390 1.1 christos return (outlen);
391 1.1 christos }
392 1.1 christos
393 1.1 christos static int
394 1.1 christos b64flush(bs, outp)
395 1.1 christos struct b64state *bs;
396 1.1 christos u_char *outp;
397 1.1 christos {
398 1.1 christos int outlen = 0;
399 1.1 christos
400 1.1 christos if (bs->bs_offs == 8) {
401 1.1 christos *outp++ = base64[(bs->bs_bits >> 2) & 0x3F];
402 1.1 christos *outp++ = base64[(bs->bs_bits << 4) & 0x3F];
403 1.1 christos outlen = 2;
404 1.1 christos } else if (bs->bs_offs == 16) {
405 1.1 christos *outp++ = base64[(bs->bs_bits >> 10) & 0x3F];
406 1.1 christos *outp++ = base64[(bs->bs_bits >> 4) & 0x3F];
407 1.1 christos *outp++ = base64[(bs->bs_bits << 2) & 0x3F];
408 1.1 christos outlen = 3;
409 1.1 christos }
410 1.1 christos bs->bs_offs = 0;
411 1.1 christos bs->bs_bits = 0;
412 1.1 christos return (outlen);
413 1.1 christos }
414 1.1 christos
415 1.1 christos static int
416 1.1 christos b64dec(bs, inp, inlen, outp)
417 1.1 christos struct b64state *bs;
418 1.1 christos u_char *inp;
419 1.1 christos int inlen;
420 1.1 christos u_char *outp;
421 1.1 christos {
422 1.1 christos int outlen = 0;
423 1.1 christos char *cp;
424 1.1 christos
425 1.1 christos while (inlen > 0) {
426 1.1 christos if ((cp = strchr(base64, *inp++)) == NULL)
427 1.1 christos break;
428 1.1 christos bs->bs_bits = (bs->bs_bits << 6) | (cp - base64);
429 1.1 christos inlen--;
430 1.1 christos bs->bs_offs += 6;
431 1.1 christos if (bs->bs_offs >= 8) {
432 1.1 christos *outp++ = bs->bs_bits >> (bs->bs_offs - 8);
433 1.1 christos outlen++;
434 1.1 christos bs->bs_offs -= 8;
435 1.1 christos }
436 1.1 christos }
437 1.1 christos return (outlen);
438 1.1 christos }
439 1.1 christos #endif /* USE_SRP */
440 1.1 christos
441 1.1 christos /*
442 1.1 christos * Assume that current waiting server state is complete and figure
443 1.1 christos * next state to use based on available authentication data. 'status'
444 1.1 christos * indicates if there was an error in handling the last query. It is
445 1.1 christos * 0 for success and non-zero for failure.
446 1.1 christos */
447 1.1 christos static void
448 1.1 christos eap_figure_next_state(esp, status)
449 1.1 christos eap_state *esp;
450 1.1 christos int status;
451 1.1 christos {
452 1.1 christos #ifdef USE_SRP
453 1.1 christos unsigned char secbuf[MAXWORDLEN], clear[8], *sp, *dp;
454 1.1 christos struct t_pw tpw;
455 1.1 christos struct t_confent *tce, mytce;
456 1.1 christos char *cp, *cp2;
457 1.1 christos struct t_server *ts;
458 1.1 christos int id, i, plen, toffs;
459 1.1 christos u_char vals[2];
460 1.1 christos struct b64state bs;
461 1.1 christos #endif /* USE_SRP */
462 1.1 christos
463 1.1 christos esp->es_server.ea_timeout = esp->es_savedtime;
464 1.1 christos switch (esp->es_server.ea_state) {
465 1.1 christos case eapBadAuth:
466 1.1 christos return;
467 1.1 christos
468 1.1 christos case eapIdentify:
469 1.1 christos #ifdef USE_SRP
470 1.1 christos /* Discard any previous session. */
471 1.1 christos ts = (struct t_server *)esp->es_server.ea_session;
472 1.1 christos if (ts != NULL) {
473 1.1 christos t_serverclose(ts);
474 1.1 christos esp->es_server.ea_session = NULL;
475 1.1 christos esp->es_server.ea_skey = NULL;
476 1.1 christos }
477 1.1 christos #endif /* USE_SRP */
478 1.1 christos if (status != 0) {
479 1.1 christos esp->es_server.ea_state = eapBadAuth;
480 1.1 christos break;
481 1.1 christos }
482 1.1 christos #ifdef USE_SRP
483 1.1 christos /* If we've got a pseudonym, try to decode to real name. */
484 1.1 christos if (esp->es_server.ea_peerlen > SRP_PSEUDO_LEN &&
485 1.1 christos strncmp(esp->es_server.ea_peer, SRP_PSEUDO_ID,
486 1.1 christos SRP_PSEUDO_LEN) == 0 &&
487 1.1 christos (esp->es_server.ea_peerlen - SRP_PSEUDO_LEN) * 3 / 4 <
488 1.1 christos sizeof (secbuf)) {
489 1.1 christos BZERO(&bs, sizeof (bs));
490 1.1 christos plen = b64dec(&bs,
491 1.1 christos esp->es_server.ea_peer + SRP_PSEUDO_LEN,
492 1.1 christos esp->es_server.ea_peerlen - SRP_PSEUDO_LEN,
493 1.1 christos secbuf);
494 1.1 christos toffs = 0;
495 1.1 christos for (i = 0; i < 5; i++) {
496 1.1 christos pncrypt_setkey(toffs);
497 1.1 christos toffs -= 86400;
498 1.1 christos if (!DesDecrypt(secbuf, clear)) {
499 1.1 christos dbglog("no DES here; cannot decode "
500 1.1 christos "pseudonym");
501 1.1 christos return;
502 1.1 christos }
503 1.1 christos id = *(unsigned char *)clear;
504 1.1 christos if (id + 1 <= plen && id + 9 > plen)
505 1.1 christos break;
506 1.1 christos }
507 1.1 christos if (plen % 8 == 0 && i < 5) {
508 1.1 christos /*
509 1.1 christos * Note that this is always shorter than the
510 1.1 christos * original stored string, so there's no need
511 1.1 christos * to realloc.
512 1.1 christos */
513 1.1 christos if ((i = plen = *(unsigned char *)clear) > 7)
514 1.1 christos i = 7;
515 1.1 christos esp->es_server.ea_peerlen = plen;
516 1.1 christos dp = (unsigned char *)esp->es_server.ea_peer;
517 1.1 christos BCOPY(clear + 1, dp, i);
518 1.1 christos plen -= i;
519 1.1 christos dp += i;
520 1.1 christos sp = secbuf + 8;
521 1.1 christos while (plen > 0) {
522 1.1 christos (void) DesDecrypt(sp, dp);
523 1.1 christos sp += 8;
524 1.1 christos dp += 8;
525 1.1 christos plen -= 8;
526 1.1 christos }
527 1.1 christos esp->es_server.ea_peer[
528 1.1 christos esp->es_server.ea_peerlen] = '\0';
529 1.1 christos dbglog("decoded pseudonym to \"%.*q\"",
530 1.1 christos esp->es_server.ea_peerlen,
531 1.1 christos esp->es_server.ea_peer);
532 1.1 christos } else {
533 1.1 christos dbglog("failed to decode real name");
534 1.1 christos /* Stay in eapIdentfy state; requery */
535 1.1 christos break;
536 1.1 christos }
537 1.1 christos }
538 1.1 christos /* Look up user in secrets database. */
539 1.1 christos if (get_srp_secret(esp->es_unit, esp->es_server.ea_peer,
540 1.1 christos esp->es_server.ea_name, (char *)secbuf, 1) != 0) {
541 1.1 christos /* Set up default in case SRP entry is bad */
542 1.1 christos esp->es_server.ea_state = eapMD5Chall;
543 1.1 christos /* Get t_confent based on index in srp-secrets */
544 1.1 christos id = strtol((char *)secbuf, &cp, 10);
545 1.1 christos if (*cp++ != ':' || id < 0)
546 1.1 christos break;
547 1.1 christos if (id == 0) {
548 1.1 christos mytce.index = 0;
549 1.1 christos mytce.modulus.data = (u_char *)wkmodulus;
550 1.1 christos mytce.modulus.len = sizeof (wkmodulus);
551 1.1 christos mytce.generator.data = (u_char *)"\002";
552 1.1 christos mytce.generator.len = 1;
553 1.1 christos tce = &mytce;
554 1.1 christos } else if ((tce = gettcid(id)) != NULL) {
555 1.1 christos /*
556 1.1 christos * Client will have to verify this modulus/
557 1.1 christos * generator combination, and that will take
558 1.1 christos * a while. Lengthen the timeout here.
559 1.1 christos */
560 1.1 christos if (esp->es_server.ea_timeout > 0 &&
561 1.1 christos esp->es_server.ea_timeout < 30)
562 1.1 christos esp->es_server.ea_timeout = 30;
563 1.1 christos } else {
564 1.1 christos break;
565 1.1 christos }
566 1.1 christos if ((cp2 = strchr(cp, ':')) == NULL)
567 1.1 christos break;
568 1.1 christos *cp2++ = '\0';
569 1.1 christos tpw.pebuf.name = esp->es_server.ea_peer;
570 1.1 christos tpw.pebuf.password.len = t_fromb64((char *)tpw.pwbuf,
571 1.1 christos cp);
572 1.1 christos tpw.pebuf.password.data = tpw.pwbuf;
573 1.1 christos tpw.pebuf.salt.len = t_fromb64((char *)tpw.saltbuf,
574 1.1 christos cp2);
575 1.1 christos tpw.pebuf.salt.data = tpw.saltbuf;
576 1.1 christos if ((ts = t_serveropenraw(&tpw.pebuf, tce)) == NULL)
577 1.1 christos break;
578 1.1 christos esp->es_server.ea_session = (void *)ts;
579 1.1 christos esp->es_server.ea_state = eapSRP1;
580 1.1 christos vals[0] = esp->es_server.ea_id + 1;
581 1.1 christos vals[1] = EAPT_SRP;
582 1.1 christos t_serveraddexdata(ts, vals, 2);
583 1.1 christos /* Generate B; must call before t_servergetkey() */
584 1.1 christos t_servergenexp(ts);
585 1.1 christos break;
586 1.1 christos }
587 1.1 christos #endif /* USE_SRP */
588 1.1 christos esp->es_server.ea_state = eapMD5Chall;
589 1.1 christos break;
590 1.1 christos
591 1.1 christos case eapSRP1:
592 1.1 christos #ifdef USE_SRP
593 1.1 christos ts = (struct t_server *)esp->es_server.ea_session;
594 1.1 christos if (ts != NULL && status != 0) {
595 1.1 christos t_serverclose(ts);
596 1.1 christos esp->es_server.ea_session = NULL;
597 1.1 christos esp->es_server.ea_skey = NULL;
598 1.1 christos }
599 1.1 christos #endif /* USE_SRP */
600 1.1 christos if (status == 1) {
601 1.1 christos esp->es_server.ea_state = eapMD5Chall;
602 1.1 christos } else if (status != 0 || esp->es_server.ea_session == NULL) {
603 1.1 christos esp->es_server.ea_state = eapBadAuth;
604 1.1 christos } else {
605 1.1 christos esp->es_server.ea_state = eapSRP2;
606 1.1 christos }
607 1.1 christos break;
608 1.1 christos
609 1.1 christos case eapSRP2:
610 1.1 christos #ifdef USE_SRP
611 1.1 christos ts = (struct t_server *)esp->es_server.ea_session;
612 1.1 christos if (ts != NULL && status != 0) {
613 1.1 christos t_serverclose(ts);
614 1.1 christos esp->es_server.ea_session = NULL;
615 1.1 christos esp->es_server.ea_skey = NULL;
616 1.1 christos }
617 1.1 christos #endif /* USE_SRP */
618 1.1 christos if (status != 0 || esp->es_server.ea_session == NULL) {
619 1.1 christos esp->es_server.ea_state = eapBadAuth;
620 1.1 christos } else {
621 1.1 christos esp->es_server.ea_state = eapSRP3;
622 1.1 christos }
623 1.1 christos break;
624 1.1 christos
625 1.1 christos case eapSRP3:
626 1.1 christos case eapSRP4:
627 1.1 christos #ifdef USE_SRP
628 1.1 christos ts = (struct t_server *)esp->es_server.ea_session;
629 1.1 christos if (ts != NULL && status != 0) {
630 1.1 christos t_serverclose(ts);
631 1.1 christos esp->es_server.ea_session = NULL;
632 1.1 christos esp->es_server.ea_skey = NULL;
633 1.1 christos }
634 1.1 christos #endif /* USE_SRP */
635 1.1 christos if (status != 0 || esp->es_server.ea_session == NULL) {
636 1.1 christos esp->es_server.ea_state = eapBadAuth;
637 1.1 christos } else {
638 1.1 christos esp->es_server.ea_state = eapOpen;
639 1.1 christos }
640 1.1 christos break;
641 1.1 christos
642 1.1 christos case eapMD5Chall:
643 1.1 christos if (status != 0) {
644 1.1 christos esp->es_server.ea_state = eapBadAuth;
645 1.1 christos } else {
646 1.1 christos esp->es_server.ea_state = eapOpen;
647 1.1 christos }
648 1.1 christos break;
649 1.1 christos
650 1.1 christos default:
651 1.1 christos esp->es_server.ea_state = eapBadAuth;
652 1.1 christos break;
653 1.1 christos }
654 1.1 christos if (esp->es_server.ea_state == eapBadAuth)
655 1.1 christos eap_send_failure(esp);
656 1.1 christos }
657 1.1 christos
658 1.1 christos /*
659 1.1 christos * Format an EAP Request message and send it to the peer. Message
660 1.1 christos * type depends on current state. (Server operation)
661 1.1 christos */
662 1.1 christos static void
663 1.1 christos eap_send_request(esp)
664 1.1 christos eap_state *esp;
665 1.1 christos {
666 1.1 christos u_char *outp;
667 1.1 christos u_char *lenloc;
668 1.1 christos u_char *ptr;
669 1.1 christos int outlen;
670 1.1 christos int challen;
671 1.1 christos char *str;
672 1.1 christos #ifdef USE_SRP
673 1.1 christos struct t_server *ts;
674 1.1 christos u_char clear[8], cipher[8], dig[SHA_DIGESTSIZE], *optr, *cp;
675 1.1 christos int i, j;
676 1.1 christos struct b64state b64;
677 1.1 christos SHA1_CTX ctxt;
678 1.1 christos #endif /* USE_SRP */
679 1.1 christos
680 1.1 christos /* Handle both initial auth and restart */
681 1.1 christos if (esp->es_server.ea_state < eapIdentify &&
682 1.1 christos esp->es_server.ea_state != eapInitial) {
683 1.1 christos esp->es_server.ea_state = eapIdentify;
684 1.1 christos if (explicit_remote) {
685 1.1 christos /*
686 1.1 christos * If we already know the peer's
687 1.1 christos * unauthenticated name, then there's no
688 1.1 christos * reason to ask. Go to next state instead.
689 1.1 christos */
690 1.1 christos esp->es_server.ea_peer = remote_name;
691 1.1 christos esp->es_server.ea_peerlen = strlen(remote_name);
692 1.1 christos eap_figure_next_state(esp, 0);
693 1.1 christos }
694 1.1 christos }
695 1.1 christos
696 1.1 christos if (esp->es_server.ea_maxrequests > 0 &&
697 1.1 christos esp->es_server.ea_requests >= esp->es_server.ea_maxrequests) {
698 1.1 christos if (esp->es_server.ea_responses > 0)
699 1.1 christos error("EAP: too many Requests sent");
700 1.1 christos else
701 1.1 christos error("EAP: no response to Requests");
702 1.1 christos eap_send_failure(esp);
703 1.1 christos return;
704 1.1 christos }
705 1.1 christos
706 1.1 christos outp = outpacket_buf;
707 1.1 christos
708 1.1 christos MAKEHEADER(outp, PPP_EAP);
709 1.1 christos
710 1.1 christos PUTCHAR(EAP_REQUEST, outp);
711 1.1 christos PUTCHAR(esp->es_server.ea_id, outp);
712 1.1 christos lenloc = outp;
713 1.1 christos INCPTR(2, outp);
714 1.1 christos
715 1.1 christos switch (esp->es_server.ea_state) {
716 1.1 christos case eapIdentify:
717 1.1 christos PUTCHAR(EAPT_IDENTITY, outp);
718 1.1 christos str = "Name";
719 1.1 christos challen = strlen(str);
720 1.1 christos BCOPY(str, outp, challen);
721 1.1 christos INCPTR(challen, outp);
722 1.1 christos break;
723 1.1 christos
724 1.1 christos case eapMD5Chall:
725 1.1 christos PUTCHAR(EAPT_MD5CHAP, outp);
726 1.1 christos /*
727 1.1 christos * pick a random challenge length between
728 1.1 christos * MIN_CHALLENGE_LENGTH and MAX_CHALLENGE_LENGTH
729 1.1 christos */
730 1.1 christos challen = (drand48() *
731 1.1 christos (MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) +
732 1.1 christos MIN_CHALLENGE_LENGTH;
733 1.1 christos PUTCHAR(challen, outp);
734 1.1 christos esp->es_challen = challen;
735 1.1 christos ptr = esp->es_challenge;
736 1.1 christos while (--challen >= 0)
737 1.1 christos *ptr++ = (u_char) (drand48() * 0x100);
738 1.1 christos BCOPY(esp->es_challenge, outp, esp->es_challen);
739 1.1 christos INCPTR(esp->es_challen, outp);
740 1.1 christos BCOPY(esp->es_server.ea_name, outp, esp->es_server.ea_namelen);
741 1.1 christos INCPTR(esp->es_server.ea_namelen, outp);
742 1.1 christos break;
743 1.1 christos
744 1.1 christos #ifdef USE_SRP
745 1.1 christos case eapSRP1:
746 1.1 christos PUTCHAR(EAPT_SRP, outp);
747 1.1 christos PUTCHAR(EAPSRP_CHALLENGE, outp);
748 1.1 christos
749 1.1 christos PUTCHAR(esp->es_server.ea_namelen, outp);
750 1.1 christos BCOPY(esp->es_server.ea_name, outp, esp->es_server.ea_namelen);
751 1.1 christos INCPTR(esp->es_server.ea_namelen, outp);
752 1.1 christos
753 1.1 christos ts = (struct t_server *)esp->es_server.ea_session;
754 1.1 christos assert(ts != NULL);
755 1.1 christos PUTCHAR(ts->s.len, outp);
756 1.1 christos BCOPY(ts->s.data, outp, ts->s.len);
757 1.1 christos INCPTR(ts->s.len, outp);
758 1.1 christos
759 1.1 christos if (ts->g.len == 1 && ts->g.data[0] == 2) {
760 1.1 christos PUTCHAR(0, outp);
761 1.1 christos } else {
762 1.1 christos PUTCHAR(ts->g.len, outp);
763 1.1 christos BCOPY(ts->g.data, outp, ts->g.len);
764 1.1 christos INCPTR(ts->g.len, outp);
765 1.1 christos }
766 1.1 christos
767 1.1 christos if (ts->n.len != sizeof (wkmodulus) ||
768 1.1 christos BCMP(ts->n.data, wkmodulus, sizeof (wkmodulus)) != 0) {
769 1.1 christos BCOPY(ts->n.data, outp, ts->n.len);
770 1.1 christos INCPTR(ts->n.len, outp);
771 1.1 christos }
772 1.1 christos break;
773 1.1 christos
774 1.1 christos case eapSRP2:
775 1.1 christos PUTCHAR(EAPT_SRP, outp);
776 1.1 christos PUTCHAR(EAPSRP_SKEY, outp);
777 1.1 christos
778 1.1 christos ts = (struct t_server *)esp->es_server.ea_session;
779 1.1 christos assert(ts != NULL);
780 1.1 christos BCOPY(ts->B.data, outp, ts->B.len);
781 1.1 christos INCPTR(ts->B.len, outp);
782 1.1 christos break;
783 1.1 christos
784 1.1 christos case eapSRP3:
785 1.1 christos PUTCHAR(EAPT_SRP, outp);
786 1.1 christos PUTCHAR(EAPSRP_SVALIDATOR, outp);
787 1.1 christos PUTLONG(SRPVAL_EBIT, outp);
788 1.1 christos ts = (struct t_server *)esp->es_server.ea_session;
789 1.1 christos assert(ts != NULL);
790 1.1 christos BCOPY(t_serverresponse(ts), outp, SHA_DIGESTSIZE);
791 1.1 christos INCPTR(SHA_DIGESTSIZE, outp);
792 1.1 christos
793 1.1 christos if (pncrypt_setkey(0)) {
794 1.1 christos /* Generate pseudonym */
795 1.1 christos optr = outp;
796 1.1 christos cp = (unsigned char *)esp->es_server.ea_peer;
797 1.1 christos if ((j = i = esp->es_server.ea_peerlen) > 7)
798 1.1 christos j = 7;
799 1.1 christos clear[0] = i;
800 1.1 christos BCOPY(cp, clear + 1, j);
801 1.1 christos i -= j;
802 1.1 christos cp += j;
803 1.1 christos if (!DesEncrypt(clear, cipher)) {
804 1.1 christos dbglog("no DES here; not generating pseudonym");
805 1.1 christos break;
806 1.1 christos }
807 1.1 christos BZERO(&b64, sizeof (b64));
808 1.1 christos outp++; /* space for pseudonym length */
809 1.1 christos outp += b64enc(&b64, cipher, 8, outp);
810 1.1 christos while (i >= 8) {
811 1.1 christos (void) DesEncrypt(cp, cipher);
812 1.1 christos outp += b64enc(&b64, cipher, 8, outp);
813 1.1 christos cp += 8;
814 1.1 christos i -= 8;
815 1.1 christos }
816 1.1 christos if (i > 0) {
817 1.1 christos BCOPY(cp, clear, i);
818 1.1 christos cp += i;
819 1.1 christos while (i < 8) {
820 1.1 christos *cp++ = drand48() * 0x100;
821 1.1 christos i++;
822 1.1 christos }
823 1.1 christos (void) DesEncrypt(clear, cipher);
824 1.1 christos outp += b64enc(&b64, cipher, 8, outp);
825 1.1 christos }
826 1.1 christos outp += b64flush(&b64, outp);
827 1.1 christos
828 1.1 christos /* Set length and pad out to next 20 octet boundary */
829 1.1 christos i = outp - optr - 1;
830 1.1 christos *optr = i;
831 1.1 christos i %= SHA_DIGESTSIZE;
832 1.1 christos if (i != 0) {
833 1.1 christos while (i < SHA_DIGESTSIZE) {
834 1.1 christos *outp++ = drand48() * 0x100;
835 1.1 christos i++;
836 1.1 christos }
837 1.1 christos }
838 1.1 christos
839 1.1 christos /* Obscure the pseudonym with SHA1 hash */
840 1.1 christos SHA1Init(&ctxt);
841 1.1 christos SHA1Update(&ctxt, &esp->es_server.ea_id, 1);
842 1.1 christos SHA1Update(&ctxt, esp->es_server.ea_skey,
843 1.1 christos SESSION_KEY_LEN);
844 1.1 christos SHA1Update(&ctxt, esp->es_server.ea_peer,
845 1.1 christos esp->es_server.ea_peerlen);
846 1.1 christos while (optr < outp) {
847 1.1 christos SHA1Final(dig, &ctxt);
848 1.1 christos cp = dig;
849 1.1 christos while (cp < dig + SHA_DIGESTSIZE)
850 1.1 christos *optr++ ^= *cp++;
851 1.1 christos SHA1Init(&ctxt);
852 1.1 christos SHA1Update(&ctxt, &esp->es_server.ea_id, 1);
853 1.1 christos SHA1Update(&ctxt, esp->es_server.ea_skey,
854 1.1 christos SESSION_KEY_LEN);
855 1.1 christos SHA1Update(&ctxt, optr - SHA_DIGESTSIZE,
856 1.1 christos SHA_DIGESTSIZE);
857 1.1 christos }
858 1.1 christos }
859 1.1 christos break;
860 1.1 christos
861 1.1 christos case eapSRP4:
862 1.1 christos PUTCHAR(EAPT_SRP, outp);
863 1.1 christos PUTCHAR(EAPSRP_LWRECHALLENGE, outp);
864 1.1 christos challen = MIN_CHALLENGE_LENGTH +
865 1.1 christos ((MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH) * drand48());
866 1.1 christos esp->es_challen = challen;
867 1.1 christos ptr = esp->es_challenge;
868 1.1 christos while (--challen >= 0)
869 1.1 christos *ptr++ = drand48() * 0x100;
870 1.1 christos BCOPY(esp->es_challenge, outp, esp->es_challen);
871 1.1 christos INCPTR(esp->es_challen, outp);
872 1.1 christos break;
873 1.1 christos #endif /* USE_SRP */
874 1.1 christos
875 1.1 christos default:
876 1.1 christos return;
877 1.1 christos }
878 1.1 christos
879 1.1 christos outlen = (outp - outpacket_buf) - PPP_HDRLEN;
880 1.1 christos PUTSHORT(outlen, lenloc);
881 1.1 christos
882 1.1 christos output(esp->es_unit, outpacket_buf, outlen + PPP_HDRLEN);
883 1.1 christos
884 1.1 christos esp->es_server.ea_requests++;
885 1.1 christos
886 1.1 christos if (esp->es_server.ea_timeout > 0)
887 1.1 christos TIMEOUT(eap_server_timeout, esp, esp->es_server.ea_timeout);
888 1.1 christos }
889 1.1 christos
890 1.1 christos /*
891 1.1 christos * eap_authpeer - Authenticate our peer (behave as server).
892 1.1 christos *
893 1.1 christos * Start server state and send first request. This is called only
894 1.1 christos * after eap_lowerup.
895 1.1 christos */
896 1.1 christos void
897 1.1 christos eap_authpeer(unit, localname)
898 1.1 christos int unit;
899 1.1 christos char *localname;
900 1.1 christos {
901 1.1 christos eap_state *esp = &eap_states[unit];
902 1.1 christos
903 1.1 christos /* Save the name we're given. */
904 1.1 christos esp->es_server.ea_name = localname;
905 1.1 christos esp->es_server.ea_namelen = strlen(localname);
906 1.1 christos
907 1.1 christos esp->es_savedtime = esp->es_server.ea_timeout;
908 1.1 christos
909 1.1 christos /* Lower layer up yet? */
910 1.1 christos if (esp->es_server.ea_state == eapInitial ||
911 1.1 christos esp->es_server.ea_state == eapPending) {
912 1.1 christos esp->es_server.ea_state = eapPending;
913 1.1 christos return;
914 1.1 christos }
915 1.1 christos
916 1.1 christos esp->es_server.ea_state = eapPending;
917 1.1 christos
918 1.1 christos /* ID number not updated here intentionally; hashed into M1 */
919 1.1 christos eap_send_request(esp);
920 1.1 christos }
921 1.1 christos
922 1.1 christos /*
923 1.1 christos * eap_server_timeout - Retransmission timer for sending Requests
924 1.1 christos * expired.
925 1.1 christos */
926 1.1 christos static void
927 1.1 christos eap_server_timeout(arg)
928 1.1 christos void *arg;
929 1.1 christos {
930 1.1 christos eap_state *esp = (eap_state *) arg;
931 1.1 christos
932 1.1 christos if (!eap_server_active(esp))
933 1.1 christos return;
934 1.1 christos
935 1.1 christos /* EAP ID number must not change on timeout. */
936 1.1 christos eap_send_request(esp);
937 1.1 christos }
938 1.1 christos
939 1.1 christos /*
940 1.1 christos * When it's time to send rechallenge the peer, this timeout is
941 1.1 christos * called. Once the rechallenge is successful, the response handler
942 1.1 christos * will restart the timer. If it fails, then the link is dropped.
943 1.1 christos */
944 1.1 christos static void
945 1.1 christos eap_rechallenge(arg)
946 1.1 christos void *arg;
947 1.1 christos {
948 1.1 christos eap_state *esp = (eap_state *)arg;
949 1.1 christos
950 1.1 christos if (esp->es_server.ea_state != eapOpen &&
951 1.1 christos esp->es_server.ea_state != eapSRP4)
952 1.1 christos return;
953 1.1 christos
954 1.1 christos esp->es_server.ea_requests = 0;
955 1.1 christos esp->es_server.ea_state = eapIdentify;
956 1.1 christos eap_figure_next_state(esp, 0);
957 1.1 christos esp->es_server.ea_id++;
958 1.1 christos eap_send_request(esp);
959 1.1 christos }
960 1.1 christos
961 1.1 christos static void
962 1.1 christos srp_lwrechallenge(arg)
963 1.1 christos void *arg;
964 1.1 christos {
965 1.1 christos eap_state *esp = (eap_state *)arg;
966 1.1 christos
967 1.1 christos if (esp->es_server.ea_state != eapOpen ||
968 1.1 christos esp->es_server.ea_type != EAPT_SRP)
969 1.1 christos return;
970 1.1 christos
971 1.1 christos esp->es_server.ea_requests = 0;
972 1.1 christos esp->es_server.ea_state = eapSRP4;
973 1.1 christos esp->es_server.ea_id++;
974 1.1 christos eap_send_request(esp);
975 1.1 christos }
976 1.1 christos
977 1.1 christos /*
978 1.1 christos * eap_lowerup - The lower layer is now up.
979 1.1 christos *
980 1.1 christos * This is called before either eap_authpeer or eap_authwithpeer. See
981 1.1 christos * link_established() in auth.c. All that's necessary here is to
982 1.1 christos * return to closed state so that those two routines will do the right
983 1.1 christos * thing.
984 1.1 christos */
985 1.1 christos static void
986 1.1 christos eap_lowerup(unit)
987 1.1 christos int unit;
988 1.1 christos {
989 1.1 christos eap_state *esp = &eap_states[unit];
990 1.1 christos
991 1.1 christos /* Discard any (possibly authenticated) peer name. */
992 1.1 christos if (esp->es_server.ea_peer != NULL &&
993 1.1 christos esp->es_server.ea_peer != remote_name)
994 1.1 christos free(esp->es_server.ea_peer);
995 1.1 christos esp->es_server.ea_peer = NULL;
996 1.1 christos if (esp->es_client.ea_peer != NULL)
997 1.1 christos free(esp->es_client.ea_peer);
998 1.1 christos esp->es_client.ea_peer = NULL;
999 1.1 christos
1000 1.1 christos esp->es_client.ea_state = eapClosed;
1001 1.1 christos esp->es_server.ea_state = eapClosed;
1002 1.1 christos }
1003 1.1 christos
1004 1.1 christos /*
1005 1.1 christos * eap_lowerdown - The lower layer is now down.
1006 1.1 christos *
1007 1.1 christos * Cancel all timeouts and return to initial state.
1008 1.1 christos */
1009 1.1 christos static void
1010 1.1 christos eap_lowerdown(unit)
1011 1.1 christos int unit;
1012 1.1 christos {
1013 1.1 christos eap_state *esp = &eap_states[unit];
1014 1.1 christos
1015 1.1 christos if (eap_client_active(esp) && esp->es_client.ea_timeout > 0) {
1016 1.1 christos UNTIMEOUT(eap_client_timeout, (void *)esp);
1017 1.1 christos }
1018 1.1 christos if (eap_server_active(esp)) {
1019 1.1 christos if (esp->es_server.ea_timeout > 0) {
1020 1.1 christos UNTIMEOUT(eap_server_timeout, (void *)esp);
1021 1.1 christos }
1022 1.1 christos } else {
1023 1.1 christos if ((esp->es_server.ea_state == eapOpen ||
1024 1.1 christos esp->es_server.ea_state == eapSRP4) &&
1025 1.1 christos esp->es_rechallenge > 0) {
1026 1.1 christos UNTIMEOUT(eap_rechallenge, (void *)esp);
1027 1.1 christos }
1028 1.1 christos if (esp->es_server.ea_state == eapOpen &&
1029 1.1 christos esp->es_lwrechallenge > 0) {
1030 1.1 christos UNTIMEOUT(srp_lwrechallenge, (void *)esp);
1031 1.1 christos }
1032 1.1 christos }
1033 1.1 christos
1034 1.1 christos esp->es_client.ea_state = esp->es_server.ea_state = eapInitial;
1035 1.1 christos esp->es_client.ea_requests = esp->es_server.ea_requests = 0;
1036 1.1 christos }
1037 1.1 christos
1038 1.1 christos /*
1039 1.1 christos * eap_protrej - Peer doesn't speak this protocol.
1040 1.1 christos *
1041 1.1 christos * This shouldn't happen. If it does, it represents authentication
1042 1.1 christos * failure.
1043 1.1 christos */
1044 1.1 christos static void
1045 1.1 christos eap_protrej(unit)
1046 1.1 christos int unit;
1047 1.1 christos {
1048 1.1 christos eap_state *esp = &eap_states[unit];
1049 1.1 christos
1050 1.1 christos if (eap_client_active(esp)) {
1051 1.1 christos error("EAP authentication failed due to Protocol-Reject");
1052 1.1 christos auth_withpeer_fail(unit, PPP_EAP);
1053 1.1 christos }
1054 1.1 christos if (eap_server_active(esp)) {
1055 1.1 christos error("EAP authentication of peer failed on Protocol-Reject");
1056 1.1 christos auth_peer_fail(unit, PPP_EAP);
1057 1.1 christos }
1058 1.1 christos eap_lowerdown(unit);
1059 1.1 christos }
1060 1.1 christos
1061 1.1 christos /*
1062 1.1 christos * Format and send a regular EAP Response message.
1063 1.1 christos */
1064 1.1 christos static void
1065 1.2 christos eap_send_response(eap_state *esp, u_char id, u_char typenum,
1066 1.2 christos const u_char *str, int lenstr)
1067 1.1 christos {
1068 1.1 christos u_char *outp;
1069 1.1 christos int msglen;
1070 1.1 christos
1071 1.1 christos outp = outpacket_buf;
1072 1.1 christos
1073 1.1 christos MAKEHEADER(outp, PPP_EAP);
1074 1.1 christos
1075 1.1 christos PUTCHAR(EAP_RESPONSE, outp);
1076 1.1 christos PUTCHAR(id, outp);
1077 1.1 christos esp->es_client.ea_id = id;
1078 1.1 christos msglen = EAP_HEADERLEN + sizeof (u_char) + lenstr;
1079 1.1 christos PUTSHORT(msglen, outp);
1080 1.1 christos PUTCHAR(typenum, outp);
1081 1.1 christos if (lenstr > 0) {
1082 1.1 christos BCOPY(str, outp, lenstr);
1083 1.1 christos }
1084 1.1 christos
1085 1.1 christos output(esp->es_unit, outpacket_buf, PPP_HDRLEN + msglen);
1086 1.1 christos }
1087 1.1 christos
1088 1.1 christos /*
1089 1.1 christos * Format and send an MD5-Challenge EAP Response message.
1090 1.1 christos */
1091 1.1 christos static void
1092 1.2 christos eap_chap_response(eap_state *esp, u_char id, const u_char *hash,
1093 1.2 christos const char *name, int namelen)
1094 1.1 christos {
1095 1.1 christos u_char *outp;
1096 1.1 christos int msglen;
1097 1.1 christos
1098 1.1 christos outp = outpacket_buf;
1099 1.1 christos
1100 1.1 christos MAKEHEADER(outp, PPP_EAP);
1101 1.1 christos
1102 1.1 christos PUTCHAR(EAP_RESPONSE, outp);
1103 1.1 christos PUTCHAR(id, outp);
1104 1.1 christos esp->es_client.ea_id = id;
1105 1.1 christos msglen = EAP_HEADERLEN + 2 * sizeof (u_char) + MD5_SIGNATURE_SIZE +
1106 1.1 christos namelen;
1107 1.1 christos PUTSHORT(msglen, outp);
1108 1.1 christos PUTCHAR(EAPT_MD5CHAP, outp);
1109 1.1 christos PUTCHAR(MD5_SIGNATURE_SIZE, outp);
1110 1.1 christos BCOPY(hash, outp, MD5_SIGNATURE_SIZE);
1111 1.1 christos INCPTR(MD5_SIGNATURE_SIZE, outp);
1112 1.1 christos if (namelen > 0) {
1113 1.1 christos BCOPY(name, outp, namelen);
1114 1.1 christos }
1115 1.1 christos
1116 1.1 christos output(esp->es_unit, outpacket_buf, PPP_HDRLEN + msglen);
1117 1.1 christos }
1118 1.1 christos
1119 1.1 christos #ifdef USE_SRP
1120 1.1 christos /*
1121 1.1 christos * Format and send a SRP EAP Response message.
1122 1.1 christos */
1123 1.1 christos static void
1124 1.1 christos eap_srp_response(esp, id, subtypenum, str, lenstr)
1125 1.1 christos eap_state *esp;
1126 1.1 christos u_char id;
1127 1.1 christos u_char subtypenum;
1128 1.1 christos u_char *str;
1129 1.1 christos int lenstr;
1130 1.1 christos {
1131 1.1 christos u_char *outp;
1132 1.1 christos int msglen;
1133 1.1 christos
1134 1.1 christos outp = outpacket_buf;
1135 1.1 christos
1136 1.1 christos MAKEHEADER(outp, PPP_EAP);
1137 1.1 christos
1138 1.1 christos PUTCHAR(EAP_RESPONSE, outp);
1139 1.1 christos PUTCHAR(id, outp);
1140 1.1 christos esp->es_client.ea_id = id;
1141 1.1 christos msglen = EAP_HEADERLEN + 2 * sizeof (u_char) + lenstr;
1142 1.1 christos PUTSHORT(msglen, outp);
1143 1.1 christos PUTCHAR(EAPT_SRP, outp);
1144 1.1 christos PUTCHAR(subtypenum, outp);
1145 1.1 christos if (lenstr > 0) {
1146 1.1 christos BCOPY(str, outp, lenstr);
1147 1.1 christos }
1148 1.1 christos
1149 1.1 christos output(esp->es_unit, outpacket_buf, PPP_HDRLEN + msglen);
1150 1.1 christos }
1151 1.1 christos
1152 1.1 christos /*
1153 1.1 christos * Format and send a SRP EAP Client Validator Response message.
1154 1.1 christos */
1155 1.1 christos static void
1156 1.1 christos eap_srpval_response(esp, id, flags, str)
1157 1.1 christos eap_state *esp;
1158 1.1 christos u_char id;
1159 1.1 christos u_int32_t flags;
1160 1.1 christos u_char *str;
1161 1.1 christos {
1162 1.1 christos u_char *outp;
1163 1.1 christos int msglen;
1164 1.1 christos
1165 1.1 christos outp = outpacket_buf;
1166 1.1 christos
1167 1.1 christos MAKEHEADER(outp, PPP_EAP);
1168 1.1 christos
1169 1.1 christos PUTCHAR(EAP_RESPONSE, outp);
1170 1.1 christos PUTCHAR(id, outp);
1171 1.1 christos esp->es_client.ea_id = id;
1172 1.1 christos msglen = EAP_HEADERLEN + 2 * sizeof (u_char) + sizeof (u_int32_t) +
1173 1.1 christos SHA_DIGESTSIZE;
1174 1.1 christos PUTSHORT(msglen, outp);
1175 1.1 christos PUTCHAR(EAPT_SRP, outp);
1176 1.1 christos PUTCHAR(EAPSRP_CVALIDATOR, outp);
1177 1.1 christos PUTLONG(flags, outp);
1178 1.1 christos BCOPY(str, outp, SHA_DIGESTSIZE);
1179 1.1 christos
1180 1.1 christos output(esp->es_unit, outpacket_buf, PPP_HDRLEN + msglen);
1181 1.1 christos }
1182 1.1 christos #endif /* USE_SRP */
1183 1.1 christos
1184 1.1 christos static void
1185 1.2 christos eap_send_nak(eap_state *esp, u_char id, u_char type)
1186 1.1 christos {
1187 1.1 christos u_char *outp;
1188 1.1 christos int msglen;
1189 1.1 christos
1190 1.1 christos outp = outpacket_buf;
1191 1.1 christos
1192 1.1 christos MAKEHEADER(outp, PPP_EAP);
1193 1.1 christos
1194 1.1 christos PUTCHAR(EAP_RESPONSE, outp);
1195 1.1 christos PUTCHAR(id, outp);
1196 1.1 christos esp->es_client.ea_id = id;
1197 1.1 christos msglen = EAP_HEADERLEN + 2 * sizeof (u_char);
1198 1.1 christos PUTSHORT(msglen, outp);
1199 1.1 christos PUTCHAR(EAPT_NAK, outp);
1200 1.1 christos PUTCHAR(type, outp);
1201 1.1 christos
1202 1.1 christos output(esp->es_unit, outpacket_buf, PPP_HDRLEN + msglen);
1203 1.1 christos }
1204 1.1 christos
1205 1.1 christos #ifdef USE_SRP
1206 1.1 christos static char *
1207 1.1 christos name_of_pn_file()
1208 1.1 christos {
1209 1.1 christos char *user, *path, *file;
1210 1.1 christos struct passwd *pw;
1211 1.1 christos size_t pl;
1212 1.1 christos static bool pnlogged = 0;
1213 1.1 christos
1214 1.1 christos pw = getpwuid(getuid());
1215 1.1 christos if (pw == NULL || (user = pw->pw_dir) == NULL || user[0] == 0) {
1216 1.1 christos errno = EINVAL;
1217 1.1 christos return (NULL);
1218 1.1 christos }
1219 1.1 christos file = _PATH_PSEUDONYM;
1220 1.1 christos pl = strlen(user) + strlen(file) + 2;
1221 1.1 christos path = malloc(pl);
1222 1.1 christos if (path == NULL)
1223 1.1 christos return (NULL);
1224 1.1 christos (void) slprintf(path, pl, "%s/%s", user, file);
1225 1.1 christos if (!pnlogged) {
1226 1.1 christos dbglog("pseudonym file: %s", path);
1227 1.1 christos pnlogged = 1;
1228 1.1 christos }
1229 1.1 christos return (path);
1230 1.1 christos }
1231 1.1 christos
1232 1.1 christos static int
1233 1.1 christos open_pn_file(modebits)
1234 1.1 christos mode_t modebits;
1235 1.1 christos {
1236 1.1 christos char *path;
1237 1.1 christos int fd, err;
1238 1.1 christos
1239 1.1 christos if ((path = name_of_pn_file()) == NULL)
1240 1.1 christos return (-1);
1241 1.1 christos fd = open(path, modebits, S_IRUSR | S_IWUSR);
1242 1.1 christos err = errno;
1243 1.1 christos free(path);
1244 1.1 christos errno = err;
1245 1.1 christos return (fd);
1246 1.1 christos }
1247 1.1 christos
1248 1.1 christos static void
1249 1.1 christos remove_pn_file()
1250 1.1 christos {
1251 1.1 christos char *path;
1252 1.1 christos
1253 1.1 christos if ((path = name_of_pn_file()) != NULL) {
1254 1.1 christos (void) unlink(path);
1255 1.1 christos (void) free(path);
1256 1.1 christos }
1257 1.1 christos }
1258 1.1 christos
1259 1.1 christos static void
1260 1.1 christos write_pseudonym(esp, inp, len, id)
1261 1.1 christos eap_state *esp;
1262 1.1 christos u_char *inp;
1263 1.1 christos int len, id;
1264 1.1 christos {
1265 1.1 christos u_char val;
1266 1.1 christos u_char *datp, *digp;
1267 1.1 christos SHA1_CTX ctxt;
1268 1.1 christos u_char dig[SHA_DIGESTSIZE];
1269 1.1 christos int dsize, fd, olen = len;
1270 1.1 christos
1271 1.1 christos /*
1272 1.1 christos * Do the decoding by working backwards. This eliminates the need
1273 1.1 christos * to save the decoded output in a separate buffer.
1274 1.1 christos */
1275 1.1 christos val = id;
1276 1.1 christos while (len > 0) {
1277 1.1 christos if ((dsize = len % SHA_DIGESTSIZE) == 0)
1278 1.1 christos dsize = SHA_DIGESTSIZE;
1279 1.1 christos len -= dsize;
1280 1.1 christos datp = inp + len;
1281 1.1 christos SHA1Init(&ctxt);
1282 1.1 christos SHA1Update(&ctxt, &val, 1);
1283 1.1 christos SHA1Update(&ctxt, esp->es_client.ea_skey, SESSION_KEY_LEN);
1284 1.1 christos if (len > 0) {
1285 1.1 christos SHA1Update(&ctxt, datp, SHA_DIGESTSIZE);
1286 1.1 christos } else {
1287 1.1 christos SHA1Update(&ctxt, esp->es_client.ea_name,
1288 1.1 christos esp->es_client.ea_namelen);
1289 1.1 christos }
1290 1.1 christos SHA1Final(dig, &ctxt);
1291 1.1 christos for (digp = dig; digp < dig + SHA_DIGESTSIZE; digp++)
1292 1.1 christos *datp++ ^= *digp;
1293 1.1 christos }
1294 1.1 christos
1295 1.1 christos /* Now check that the result is sane */
1296 1.1 christos if (olen <= 0 || *inp + 1 > olen) {
1297 1.1 christos dbglog("EAP: decoded pseudonym is unusable <%.*B>", olen, inp);
1298 1.1 christos return;
1299 1.1 christos }
1300 1.1 christos
1301 1.1 christos /* Save it away */
1302 1.1 christos fd = open_pn_file(O_WRONLY | O_CREAT | O_TRUNC);
1303 1.1 christos if (fd < 0) {
1304 1.1 christos dbglog("EAP: error saving pseudonym: %m");
1305 1.1 christos return;
1306 1.1 christos }
1307 1.1 christos len = write(fd, inp + 1, *inp);
1308 1.1 christos if (close(fd) != -1 && len == *inp) {
1309 1.1 christos dbglog("EAP: saved pseudonym");
1310 1.1 christos esp->es_usedpseudo = 0;
1311 1.1 christos } else {
1312 1.1 christos dbglog("EAP: failed to save pseudonym");
1313 1.1 christos remove_pn_file();
1314 1.1 christos }
1315 1.1 christos }
1316 1.1 christos #endif /* USE_SRP */
1317 1.1 christos
1318 1.1 christos /*
1319 1.1 christos * eap_request - Receive EAP Request message (client mode).
1320 1.1 christos */
1321 1.1 christos static void
1322 1.1 christos eap_request(esp, inp, id, len)
1323 1.1 christos eap_state *esp;
1324 1.1 christos u_char *inp;
1325 1.1 christos int id;
1326 1.1 christos int len;
1327 1.1 christos {
1328 1.1 christos u_char typenum;
1329 1.1 christos u_char vallen;
1330 1.1 christos int secret_len;
1331 1.1 christos char secret[MAXWORDLEN];
1332 1.1 christos char rhostname[256];
1333 1.1 christos MD5_CTX mdContext;
1334 1.1 christos u_char hash[MD5_SIGNATURE_SIZE];
1335 1.1 christos #ifdef USE_SRP
1336 1.1 christos struct t_client *tc;
1337 1.1 christos struct t_num sval, gval, Nval, *Ap, Bval;
1338 1.1 christos u_char vals[2];
1339 1.1 christos SHA1_CTX ctxt;
1340 1.1 christos u_char dig[SHA_DIGESTSIZE];
1341 1.1 christos int fd;
1342 1.1 christos #endif /* USE_SRP */
1343 1.1 christos
1344 1.1 christos /*
1345 1.1 christos * Note: we update es_client.ea_id *only if* a Response
1346 1.1 christos * message is being generated. Otherwise, we leave it the
1347 1.1 christos * same for duplicate detection purposes.
1348 1.1 christos */
1349 1.1 christos
1350 1.1 christos esp->es_client.ea_requests++;
1351 1.1 christos if (esp->es_client.ea_maxrequests != 0 &&
1352 1.1 christos esp->es_client.ea_requests > esp->es_client.ea_maxrequests) {
1353 1.1 christos info("EAP: received too many Request messages");
1354 1.1 christos if (esp->es_client.ea_timeout > 0) {
1355 1.1 christos UNTIMEOUT(eap_client_timeout, (void *)esp);
1356 1.1 christos }
1357 1.1 christos auth_withpeer_fail(esp->es_unit, PPP_EAP);
1358 1.1 christos return;
1359 1.1 christos }
1360 1.1 christos
1361 1.1 christos if (len <= 0) {
1362 1.1 christos error("EAP: empty Request message discarded");
1363 1.1 christos return;
1364 1.1 christos }
1365 1.1 christos
1366 1.1 christos GETCHAR(typenum, inp);
1367 1.1 christos len--;
1368 1.1 christos
1369 1.1 christos switch (typenum) {
1370 1.1 christos case EAPT_IDENTITY:
1371 1.1 christos if (len > 0)
1372 1.1 christos info("EAP: Identity prompt \"%.*q\"", len, inp);
1373 1.1 christos #ifdef USE_SRP
1374 1.1 christos if (esp->es_usepseudo &&
1375 1.1 christos (esp->es_usedpseudo == 0 ||
1376 1.1 christos (esp->es_usedpseudo == 1 &&
1377 1.1 christos id == esp->es_client.ea_id))) {
1378 1.1 christos esp->es_usedpseudo = 1;
1379 1.1 christos /* Try to get a pseudonym */
1380 1.1 christos if ((fd = open_pn_file(O_RDONLY)) >= 0) {
1381 1.1 christos strcpy(rhostname, SRP_PSEUDO_ID);
1382 1.1 christos len = read(fd, rhostname + SRP_PSEUDO_LEN,
1383 1.1 christos sizeof (rhostname) - SRP_PSEUDO_LEN);
1384 1.1 christos /* XXX NAI unsupported */
1385 1.1 christos if (len > 0) {
1386 1.1 christos eap_send_response(esp, id, typenum,
1387 1.1 christos rhostname, len + SRP_PSEUDO_LEN);
1388 1.1 christos }
1389 1.1 christos (void) close(fd);
1390 1.1 christos if (len > 0)
1391 1.1 christos break;
1392 1.1 christos }
1393 1.1 christos }
1394 1.1 christos /* Stop using pseudonym now. */
1395 1.1 christos if (esp->es_usepseudo && esp->es_usedpseudo != 2) {
1396 1.1 christos remove_pn_file();
1397 1.1 christos esp->es_usedpseudo = 2;
1398 1.1 christos }
1399 1.1 christos #endif /* USE_SRP */
1400 1.1 christos eap_send_response(esp, id, typenum, esp->es_client.ea_name,
1401 1.1 christos esp->es_client.ea_namelen);
1402 1.1 christos break;
1403 1.1 christos
1404 1.1 christos case EAPT_NOTIFICATION:
1405 1.1 christos if (len > 0)
1406 1.1 christos info("EAP: Notification \"%.*q\"", len, inp);
1407 1.1 christos eap_send_response(esp, id, typenum, NULL, 0);
1408 1.1 christos break;
1409 1.1 christos
1410 1.1 christos case EAPT_NAK:
1411 1.1 christos /*
1412 1.1 christos * Avoid the temptation to send Response Nak in reply
1413 1.1 christos * to Request Nak here. It can only lead to trouble.
1414 1.1 christos */
1415 1.1 christos warn("EAP: unexpected Nak in Request; ignored");
1416 1.1 christos /* Return because we're waiting for something real. */
1417 1.1 christos return;
1418 1.1 christos
1419 1.1 christos case EAPT_MD5CHAP:
1420 1.1 christos if (len < 1) {
1421 1.1 christos error("EAP: received MD5-Challenge with no data");
1422 1.1 christos /* Bogus request; wait for something real. */
1423 1.1 christos return;
1424 1.1 christos }
1425 1.1 christos GETCHAR(vallen, inp);
1426 1.1 christos len--;
1427 1.1 christos if (vallen < 8 || vallen > len) {
1428 1.1 christos error("EAP: MD5-Challenge with bad length %d (8..%d)",
1429 1.1 christos vallen, len);
1430 1.1 christos /* Try something better. */
1431 1.1 christos eap_send_nak(esp, id, EAPT_SRP);
1432 1.1 christos break;
1433 1.1 christos }
1434 1.1 christos
1435 1.1 christos /* Not so likely to happen. */
1436 1.5 christos if (len - vallen >= sizeof (rhostname)) {
1437 1.1 christos dbglog("EAP: trimming really long peer name down");
1438 1.1 christos BCOPY(inp + vallen, rhostname, sizeof (rhostname) - 1);
1439 1.1 christos rhostname[sizeof (rhostname) - 1] = '\0';
1440 1.1 christos } else {
1441 1.1 christos BCOPY(inp + vallen, rhostname, len - vallen);
1442 1.1 christos rhostname[len - vallen] = '\0';
1443 1.1 christos }
1444 1.1 christos
1445 1.1 christos /* In case the remote doesn't give us his name. */
1446 1.1 christos if (explicit_remote ||
1447 1.1 christos (remote_name[0] != '\0' && vallen == len))
1448 1.1 christos strlcpy(rhostname, remote_name, sizeof (rhostname));
1449 1.1 christos
1450 1.1 christos /*
1451 1.1 christos * Get the secret for authenticating ourselves with
1452 1.1 christos * the specified host.
1453 1.1 christos */
1454 1.1 christos if (!get_secret(esp->es_unit, esp->es_client.ea_name,
1455 1.1 christos rhostname, secret, &secret_len, 0)) {
1456 1.1 christos dbglog("EAP: no MD5 secret for auth to %q", rhostname);
1457 1.1 christos eap_send_nak(esp, id, EAPT_SRP);
1458 1.1 christos break;
1459 1.1 christos }
1460 1.2 christos MD5Init(&mdContext);
1461 1.1 christos typenum = id;
1462 1.2 christos MD5Update(&mdContext, &typenum, 1);
1463 1.2 christos MD5Update(&mdContext, secret, secret_len);
1464 1.1 christos BZERO(secret, sizeof (secret));
1465 1.2 christos MD5Update(&mdContext, inp, vallen);
1466 1.2 christos MD5Final(hash, &mdContext);
1467 1.1 christos eap_chap_response(esp, id, hash, esp->es_client.ea_name,
1468 1.1 christos esp->es_client.ea_namelen);
1469 1.1 christos break;
1470 1.1 christos
1471 1.1 christos #ifdef USE_SRP
1472 1.1 christos case EAPT_SRP:
1473 1.1 christos if (len < 1) {
1474 1.1 christos error("EAP: received empty SRP Request");
1475 1.1 christos /* Bogus request; wait for something real. */
1476 1.1 christos return;
1477 1.1 christos }
1478 1.1 christos
1479 1.1 christos /* Get subtype */
1480 1.1 christos GETCHAR(vallen, inp);
1481 1.1 christos len--;
1482 1.1 christos switch (vallen) {
1483 1.1 christos case EAPSRP_CHALLENGE:
1484 1.1 christos tc = NULL;
1485 1.1 christos if (esp->es_client.ea_session != NULL) {
1486 1.1 christos tc = (struct t_client *)esp->es_client.
1487 1.1 christos ea_session;
1488 1.1 christos /*
1489 1.1 christos * If this is a new challenge, then start
1490 1.1 christos * over with a new client session context.
1491 1.1 christos * Otherwise, just resend last response.
1492 1.1 christos */
1493 1.1 christos if (id != esp->es_client.ea_id) {
1494 1.1 christos t_clientclose(tc);
1495 1.1 christos esp->es_client.ea_session = NULL;
1496 1.1 christos tc = NULL;
1497 1.1 christos }
1498 1.1 christos }
1499 1.1 christos /* No session key just yet */
1500 1.1 christos esp->es_client.ea_skey = NULL;
1501 1.1 christos if (tc == NULL) {
1502 1.1 christos GETCHAR(vallen, inp);
1503 1.1 christos len--;
1504 1.1 christos if (vallen >= len) {
1505 1.1 christos error("EAP: badly-formed SRP Challenge"
1506 1.1 christos " (name)");
1507 1.1 christos /* Ignore badly-formed messages */
1508 1.1 christos return;
1509 1.1 christos }
1510 1.1 christos BCOPY(inp, rhostname, vallen);
1511 1.1 christos rhostname[vallen] = '\0';
1512 1.1 christos INCPTR(vallen, inp);
1513 1.1 christos len -= vallen;
1514 1.1 christos
1515 1.1 christos /*
1516 1.1 christos * In case the remote doesn't give us his name,
1517 1.1 christos * use configured name.
1518 1.1 christos */
1519 1.1 christos if (explicit_remote ||
1520 1.1 christos (remote_name[0] != '\0' && vallen == 0)) {
1521 1.1 christos strlcpy(rhostname, remote_name,
1522 1.1 christos sizeof (rhostname));
1523 1.1 christos }
1524 1.1 christos
1525 1.1 christos if (esp->es_client.ea_peer != NULL)
1526 1.1 christos free(esp->es_client.ea_peer);
1527 1.1 christos esp->es_client.ea_peer = strdup(rhostname);
1528 1.1 christos esp->es_client.ea_peerlen = strlen(rhostname);
1529 1.1 christos
1530 1.1 christos GETCHAR(vallen, inp);
1531 1.1 christos len--;
1532 1.1 christos if (vallen >= len) {
1533 1.1 christos error("EAP: badly-formed SRP Challenge"
1534 1.1 christos " (s)");
1535 1.1 christos /* Ignore badly-formed messages */
1536 1.1 christos return;
1537 1.1 christos }
1538 1.1 christos sval.data = inp;
1539 1.1 christos sval.len = vallen;
1540 1.1 christos INCPTR(vallen, inp);
1541 1.1 christos len -= vallen;
1542 1.1 christos
1543 1.1 christos GETCHAR(vallen, inp);
1544 1.1 christos len--;
1545 1.1 christos if (vallen > len) {
1546 1.1 christos error("EAP: badly-formed SRP Challenge"
1547 1.1 christos " (g)");
1548 1.1 christos /* Ignore badly-formed messages */
1549 1.1 christos return;
1550 1.1 christos }
1551 1.1 christos /* If no generator present, then use value 2 */
1552 1.1 christos if (vallen == 0) {
1553 1.1 christos gval.data = (u_char *)"\002";
1554 1.1 christos gval.len = 1;
1555 1.1 christos } else {
1556 1.1 christos gval.data = inp;
1557 1.1 christos gval.len = vallen;
1558 1.1 christos }
1559 1.1 christos INCPTR(vallen, inp);
1560 1.1 christos len -= vallen;
1561 1.1 christos
1562 1.1 christos /*
1563 1.1 christos * If no modulus present, then use well-known
1564 1.1 christos * value.
1565 1.1 christos */
1566 1.1 christos if (len == 0) {
1567 1.1 christos Nval.data = (u_char *)wkmodulus;
1568 1.1 christos Nval.len = sizeof (wkmodulus);
1569 1.1 christos } else {
1570 1.1 christos Nval.data = inp;
1571 1.1 christos Nval.len = len;
1572 1.1 christos }
1573 1.1 christos tc = t_clientopen(esp->es_client.ea_name,
1574 1.1 christos &Nval, &gval, &sval);
1575 1.1 christos if (tc == NULL) {
1576 1.1 christos eap_send_nak(esp, id, EAPT_MD5CHAP);
1577 1.1 christos break;
1578 1.1 christos }
1579 1.1 christos esp->es_client.ea_session = (void *)tc;
1580 1.1 christos
1581 1.1 christos /* Add Challenge ID & type to verifier */
1582 1.1 christos vals[0] = id;
1583 1.1 christos vals[1] = EAPT_SRP;
1584 1.1 christos t_clientaddexdata(tc, vals, 2);
1585 1.1 christos }
1586 1.1 christos Ap = t_clientgenexp(tc);
1587 1.1 christos eap_srp_response(esp, id, EAPSRP_CKEY, Ap->data,
1588 1.1 christos Ap->len);
1589 1.1 christos break;
1590 1.1 christos
1591 1.1 christos case EAPSRP_SKEY:
1592 1.1 christos tc = (struct t_client *)esp->es_client.ea_session;
1593 1.1 christos if (tc == NULL) {
1594 1.1 christos warn("EAP: peer sent Subtype 2 without 1");
1595 1.1 christos eap_send_nak(esp, id, EAPT_MD5CHAP);
1596 1.1 christos break;
1597 1.1 christos }
1598 1.1 christos if (esp->es_client.ea_skey != NULL) {
1599 1.1 christos /*
1600 1.1 christos * ID number should not change here. Warn
1601 1.1 christos * if it does (but otherwise ignore).
1602 1.1 christos */
1603 1.1 christos if (id != esp->es_client.ea_id) {
1604 1.1 christos warn("EAP: ID changed from %d to %d "
1605 1.1 christos "in SRP Subtype 2 rexmit",
1606 1.1 christos esp->es_client.ea_id, id);
1607 1.1 christos }
1608 1.1 christos } else {
1609 1.1 christos if (get_srp_secret(esp->es_unit,
1610 1.1 christos esp->es_client.ea_name,
1611 1.1 christos esp->es_client.ea_peer, secret, 0) == 0) {
1612 1.1 christos /*
1613 1.1 christos * Can't work with this peer because
1614 1.1 christos * the secret is missing. Just give
1615 1.1 christos * up.
1616 1.1 christos */
1617 1.1 christos eap_send_nak(esp, id, EAPT_MD5CHAP);
1618 1.1 christos break;
1619 1.1 christos }
1620 1.1 christos Bval.data = inp;
1621 1.1 christos Bval.len = len;
1622 1.1 christos t_clientpasswd(tc, secret);
1623 1.1 christos BZERO(secret, sizeof (secret));
1624 1.1 christos esp->es_client.ea_skey =
1625 1.1 christos t_clientgetkey(tc, &Bval);
1626 1.1 christos if (esp->es_client.ea_skey == NULL) {
1627 1.1 christos /* Server is rogue; stop now */
1628 1.1 christos error("EAP: SRP server is rogue");
1629 1.1 christos goto client_failure;
1630 1.1 christos }
1631 1.1 christos }
1632 1.1 christos eap_srpval_response(esp, id, SRPVAL_EBIT,
1633 1.1 christos t_clientresponse(tc));
1634 1.1 christos break;
1635 1.1 christos
1636 1.1 christos case EAPSRP_SVALIDATOR:
1637 1.1 christos tc = (struct t_client *)esp->es_client.ea_session;
1638 1.1 christos if (tc == NULL || esp->es_client.ea_skey == NULL) {
1639 1.1 christos warn("EAP: peer sent Subtype 3 without 1/2");
1640 1.1 christos eap_send_nak(esp, id, EAPT_MD5CHAP);
1641 1.1 christos break;
1642 1.1 christos }
1643 1.1 christos /*
1644 1.1 christos * If we're already open, then this ought to be a
1645 1.1 christos * duplicate. Otherwise, check that the server is
1646 1.1 christos * who we think it is.
1647 1.1 christos */
1648 1.1 christos if (esp->es_client.ea_state == eapOpen) {
1649 1.1 christos if (id != esp->es_client.ea_id) {
1650 1.1 christos warn("EAP: ID changed from %d to %d "
1651 1.1 christos "in SRP Subtype 3 rexmit",
1652 1.1 christos esp->es_client.ea_id, id);
1653 1.1 christos }
1654 1.1 christos } else {
1655 1.1 christos len -= sizeof (u_int32_t) + SHA_DIGESTSIZE;
1656 1.1 christos if (len < 0 || t_clientverify(tc, inp +
1657 1.1 christos sizeof (u_int32_t)) != 0) {
1658 1.1 christos error("EAP: SRP server verification "
1659 1.1 christos "failed");
1660 1.1 christos goto client_failure;
1661 1.1 christos }
1662 1.1 christos GETLONG(esp->es_client.ea_keyflags, inp);
1663 1.1 christos /* Save pseudonym if user wants it. */
1664 1.1 christos if (len > 0 && esp->es_usepseudo) {
1665 1.1 christos INCPTR(SHA_DIGESTSIZE, inp);
1666 1.1 christos write_pseudonym(esp, inp, len, id);
1667 1.1 christos }
1668 1.1 christos }
1669 1.1 christos /*
1670 1.1 christos * We've verified our peer. We're now mostly done,
1671 1.1 christos * except for waiting on the regular EAP Success
1672 1.1 christos * message.
1673 1.1 christos */
1674 1.1 christos eap_srp_response(esp, id, EAPSRP_ACK, NULL, 0);
1675 1.1 christos break;
1676 1.1 christos
1677 1.1 christos case EAPSRP_LWRECHALLENGE:
1678 1.1 christos if (len < 4) {
1679 1.1 christos warn("EAP: malformed Lightweight rechallenge");
1680 1.1 christos return;
1681 1.1 christos }
1682 1.1 christos SHA1Init(&ctxt);
1683 1.1 christos vals[0] = id;
1684 1.1 christos SHA1Update(&ctxt, vals, 1);
1685 1.1 christos SHA1Update(&ctxt, esp->es_client.ea_skey,
1686 1.1 christos SESSION_KEY_LEN);
1687 1.1 christos SHA1Update(&ctxt, inp, len);
1688 1.1 christos SHA1Update(&ctxt, esp->es_client.ea_name,
1689 1.1 christos esp->es_client.ea_namelen);
1690 1.1 christos SHA1Final(dig, &ctxt);
1691 1.1 christos eap_srp_response(esp, id, EAPSRP_LWRECHALLENGE, dig,
1692 1.1 christos SHA_DIGESTSIZE);
1693 1.1 christos break;
1694 1.1 christos
1695 1.1 christos default:
1696 1.1 christos error("EAP: unknown SRP Subtype %d", vallen);
1697 1.1 christos eap_send_nak(esp, id, EAPT_MD5CHAP);
1698 1.1 christos break;
1699 1.1 christos }
1700 1.1 christos break;
1701 1.1 christos #endif /* USE_SRP */
1702 1.1 christos
1703 1.1 christos default:
1704 1.1 christos info("EAP: unknown authentication type %d; Naking", typenum);
1705 1.1 christos eap_send_nak(esp, id, EAPT_SRP);
1706 1.1 christos break;
1707 1.1 christos }
1708 1.1 christos
1709 1.1 christos if (esp->es_client.ea_timeout > 0) {
1710 1.1 christos UNTIMEOUT(eap_client_timeout, (void *)esp);
1711 1.1 christos TIMEOUT(eap_client_timeout, (void *)esp,
1712 1.1 christos esp->es_client.ea_timeout);
1713 1.1 christos }
1714 1.1 christos return;
1715 1.1 christos
1716 1.1 christos #ifdef USE_SRP
1717 1.1 christos client_failure:
1718 1.1 christos esp->es_client.ea_state = eapBadAuth;
1719 1.1 christos if (esp->es_client.ea_timeout > 0) {
1720 1.1 christos UNTIMEOUT(eap_client_timeout, (void *)esp);
1721 1.1 christos }
1722 1.1 christos esp->es_client.ea_session = NULL;
1723 1.1 christos t_clientclose(tc);
1724 1.1 christos auth_withpeer_fail(esp->es_unit, PPP_EAP);
1725 1.1 christos #endif /* USE_SRP */
1726 1.1 christos }
1727 1.1 christos
1728 1.1 christos /*
1729 1.1 christos * eap_response - Receive EAP Response message (server mode).
1730 1.1 christos */
1731 1.1 christos static void
1732 1.1 christos eap_response(esp, inp, id, len)
1733 1.1 christos eap_state *esp;
1734 1.1 christos u_char *inp;
1735 1.1 christos int id;
1736 1.1 christos int len;
1737 1.1 christos {
1738 1.1 christos u_char typenum;
1739 1.1 christos u_char vallen;
1740 1.1 christos int secret_len;
1741 1.1 christos char secret[MAXSECRETLEN];
1742 1.1 christos char rhostname[256];
1743 1.1 christos MD5_CTX mdContext;
1744 1.1 christos u_char hash[MD5_SIGNATURE_SIZE];
1745 1.1 christos #ifdef USE_SRP
1746 1.1 christos struct t_server *ts;
1747 1.1 christos struct t_num A;
1748 1.1 christos SHA1_CTX ctxt;
1749 1.1 christos u_char dig[SHA_DIGESTSIZE];
1750 1.1 christos #endif /* USE_SRP */
1751 1.1 christos
1752 1.1 christos if (esp->es_server.ea_id != id) {
1753 1.1 christos dbglog("EAP: discarding Response %d; expected ID %d", id,
1754 1.1 christos esp->es_server.ea_id);
1755 1.1 christos return;
1756 1.1 christos }
1757 1.1 christos
1758 1.1 christos esp->es_server.ea_responses++;
1759 1.1 christos
1760 1.1 christos if (len <= 0) {
1761 1.1 christos error("EAP: empty Response message discarded");
1762 1.1 christos return;
1763 1.1 christos }
1764 1.1 christos
1765 1.1 christos GETCHAR(typenum, inp);
1766 1.1 christos len--;
1767 1.1 christos
1768 1.1 christos switch (typenum) {
1769 1.1 christos case EAPT_IDENTITY:
1770 1.1 christos if (esp->es_server.ea_state != eapIdentify) {
1771 1.1 christos dbglog("EAP discarding unwanted Identify \"%.q\"", len,
1772 1.1 christos inp);
1773 1.1 christos break;
1774 1.1 christos }
1775 1.1 christos info("EAP: unauthenticated peer name \"%.*q\"", len, inp);
1776 1.1 christos if (esp->es_server.ea_peer != NULL &&
1777 1.1 christos esp->es_server.ea_peer != remote_name)
1778 1.1 christos free(esp->es_server.ea_peer);
1779 1.1 christos esp->es_server.ea_peer = malloc(len + 1);
1780 1.1 christos if (esp->es_server.ea_peer == NULL) {
1781 1.1 christos esp->es_server.ea_peerlen = 0;
1782 1.1 christos eap_figure_next_state(esp, 1);
1783 1.1 christos break;
1784 1.1 christos }
1785 1.1 christos BCOPY(inp, esp->es_server.ea_peer, len);
1786 1.1 christos esp->es_server.ea_peer[len] = '\0';
1787 1.1 christos esp->es_server.ea_peerlen = len;
1788 1.1 christos eap_figure_next_state(esp, 0);
1789 1.1 christos break;
1790 1.1 christos
1791 1.1 christos case EAPT_NOTIFICATION:
1792 1.1 christos dbglog("EAP unexpected Notification; response discarded");
1793 1.1 christos break;
1794 1.1 christos
1795 1.1 christos case EAPT_NAK:
1796 1.1 christos if (len < 1) {
1797 1.1 christos info("EAP: Nak Response with no suggested protocol");
1798 1.1 christos eap_figure_next_state(esp, 1);
1799 1.1 christos break;
1800 1.1 christos }
1801 1.1 christos
1802 1.1 christos GETCHAR(vallen, inp);
1803 1.1 christos len--;
1804 1.1 christos
1805 1.1 christos if (!explicit_remote && esp->es_server.ea_state == eapIdentify){
1806 1.1 christos /* Peer cannot Nak Identify Request */
1807 1.1 christos eap_figure_next_state(esp, 1);
1808 1.1 christos break;
1809 1.1 christos }
1810 1.1 christos
1811 1.1 christos switch (vallen) {
1812 1.1 christos case EAPT_SRP:
1813 1.1 christos /* Run through SRP validator selection again. */
1814 1.1 christos esp->es_server.ea_state = eapIdentify;
1815 1.1 christos eap_figure_next_state(esp, 0);
1816 1.1 christos break;
1817 1.1 christos
1818 1.1 christos case EAPT_MD5CHAP:
1819 1.1 christos esp->es_server.ea_state = eapMD5Chall;
1820 1.1 christos break;
1821 1.1 christos
1822 1.1 christos default:
1823 1.1 christos dbglog("EAP: peer requesting unknown Type %d", vallen);
1824 1.1 christos switch (esp->es_server.ea_state) {
1825 1.1 christos case eapSRP1:
1826 1.1 christos case eapSRP2:
1827 1.1 christos case eapSRP3:
1828 1.1 christos esp->es_server.ea_state = eapMD5Chall;
1829 1.1 christos break;
1830 1.1 christos case eapMD5Chall:
1831 1.1 christos case eapSRP4:
1832 1.1 christos esp->es_server.ea_state = eapIdentify;
1833 1.1 christos eap_figure_next_state(esp, 0);
1834 1.1 christos break;
1835 1.1 christos default:
1836 1.1 christos break;
1837 1.1 christos }
1838 1.1 christos break;
1839 1.1 christos }
1840 1.1 christos break;
1841 1.1 christos
1842 1.1 christos case EAPT_MD5CHAP:
1843 1.1 christos if (esp->es_server.ea_state != eapMD5Chall) {
1844 1.1 christos error("EAP: unexpected MD5-Response");
1845 1.1 christos eap_figure_next_state(esp, 1);
1846 1.1 christos break;
1847 1.1 christos }
1848 1.1 christos if (len < 1) {
1849 1.1 christos error("EAP: received MD5-Response with no data");
1850 1.1 christos eap_figure_next_state(esp, 1);
1851 1.1 christos break;
1852 1.1 christos }
1853 1.1 christos GETCHAR(vallen, inp);
1854 1.1 christos len--;
1855 1.1 christos if (vallen != 16 || vallen > len) {
1856 1.1 christos error("EAP: MD5-Response with bad length %d", vallen);
1857 1.1 christos eap_figure_next_state(esp, 1);
1858 1.1 christos break;
1859 1.1 christos }
1860 1.1 christos
1861 1.1 christos /* Not so likely to happen. */
1862 1.5 christos if (len - vallen >= sizeof (rhostname)) {
1863 1.1 christos dbglog("EAP: trimming really long peer name down");
1864 1.1 christos BCOPY(inp + vallen, rhostname, sizeof (rhostname) - 1);
1865 1.1 christos rhostname[sizeof (rhostname) - 1] = '\0';
1866 1.1 christos } else {
1867 1.1 christos BCOPY(inp + vallen, rhostname, len - vallen);
1868 1.1 christos rhostname[len - vallen] = '\0';
1869 1.1 christos }
1870 1.1 christos
1871 1.1 christos /* In case the remote doesn't give us his name. */
1872 1.1 christos if (explicit_remote ||
1873 1.1 christos (remote_name[0] != '\0' && vallen == len))
1874 1.1 christos strlcpy(rhostname, remote_name, sizeof (rhostname));
1875 1.1 christos
1876 1.1 christos /*
1877 1.1 christos * Get the secret for authenticating the specified
1878 1.1 christos * host.
1879 1.1 christos */
1880 1.1 christos if (!get_secret(esp->es_unit, rhostname,
1881 1.1 christos esp->es_server.ea_name, secret, &secret_len, 1)) {
1882 1.1 christos dbglog("EAP: no MD5 secret for auth of %q", rhostname);
1883 1.1 christos eap_send_failure(esp);
1884 1.1 christos break;
1885 1.1 christos }
1886 1.2 christos MD5Init(&mdContext);
1887 1.2 christos MD5Update(&mdContext, &esp->es_server.ea_id, 1);
1888 1.2 christos MD5Update(&mdContext, secret, secret_len);
1889 1.1 christos BZERO(secret, sizeof (secret));
1890 1.2 christos MD5Update(&mdContext, esp->es_challenge, esp->es_challen);
1891 1.2 christos MD5Final(hash, &mdContext);
1892 1.1 christos if (BCMP(hash, inp, MD5_SIGNATURE_SIZE) != 0) {
1893 1.1 christos eap_send_failure(esp);
1894 1.1 christos break;
1895 1.1 christos }
1896 1.1 christos esp->es_server.ea_type = EAPT_MD5CHAP;
1897 1.1 christos eap_send_success(esp);
1898 1.1 christos eap_figure_next_state(esp, 0);
1899 1.1 christos if (esp->es_rechallenge != 0)
1900 1.1 christos TIMEOUT(eap_rechallenge, esp, esp->es_rechallenge);
1901 1.1 christos break;
1902 1.1 christos
1903 1.1 christos #ifdef USE_SRP
1904 1.1 christos case EAPT_SRP:
1905 1.1 christos if (len < 1) {
1906 1.1 christos error("EAP: empty SRP Response");
1907 1.1 christos eap_figure_next_state(esp, 1);
1908 1.1 christos break;
1909 1.1 christos }
1910 1.1 christos GETCHAR(typenum, inp);
1911 1.1 christos len--;
1912 1.1 christos switch (typenum) {
1913 1.1 christos case EAPSRP_CKEY:
1914 1.1 christos if (esp->es_server.ea_state != eapSRP1) {
1915 1.1 christos error("EAP: unexpected SRP Subtype 1 Response");
1916 1.1 christos eap_figure_next_state(esp, 1);
1917 1.1 christos break;
1918 1.1 christos }
1919 1.1 christos A.data = inp;
1920 1.1 christos A.len = len;
1921 1.1 christos ts = (struct t_server *)esp->es_server.ea_session;
1922 1.1 christos assert(ts != NULL);
1923 1.1 christos esp->es_server.ea_skey = t_servergetkey(ts, &A);
1924 1.1 christos if (esp->es_server.ea_skey == NULL) {
1925 1.1 christos /* Client's A value is bogus; terminate now */
1926 1.1 christos error("EAP: bogus A value from client");
1927 1.1 christos eap_send_failure(esp);
1928 1.1 christos } else {
1929 1.1 christos eap_figure_next_state(esp, 0);
1930 1.1 christos }
1931 1.1 christos break;
1932 1.1 christos
1933 1.1 christos case EAPSRP_CVALIDATOR:
1934 1.1 christos if (esp->es_server.ea_state != eapSRP2) {
1935 1.1 christos error("EAP: unexpected SRP Subtype 2 Response");
1936 1.1 christos eap_figure_next_state(esp, 1);
1937 1.1 christos break;
1938 1.1 christos }
1939 1.1 christos if (len < sizeof (u_int32_t) + SHA_DIGESTSIZE) {
1940 1.1 christos error("EAP: M1 length %d < %d", len,
1941 1.1 christos sizeof (u_int32_t) + SHA_DIGESTSIZE);
1942 1.1 christos eap_figure_next_state(esp, 1);
1943 1.1 christos break;
1944 1.1 christos }
1945 1.1 christos GETLONG(esp->es_server.ea_keyflags, inp);
1946 1.1 christos ts = (struct t_server *)esp->es_server.ea_session;
1947 1.1 christos assert(ts != NULL);
1948 1.1 christos if (t_serververify(ts, inp)) {
1949 1.1 christos info("EAP: unable to validate client identity");
1950 1.1 christos eap_send_failure(esp);
1951 1.1 christos break;
1952 1.1 christos }
1953 1.1 christos eap_figure_next_state(esp, 0);
1954 1.1 christos break;
1955 1.1 christos
1956 1.1 christos case EAPSRP_ACK:
1957 1.1 christos if (esp->es_server.ea_state != eapSRP3) {
1958 1.1 christos error("EAP: unexpected SRP Subtype 3 Response");
1959 1.1 christos eap_send_failure(esp);
1960 1.1 christos break;
1961 1.1 christos }
1962 1.1 christos esp->es_server.ea_type = EAPT_SRP;
1963 1.1 christos eap_send_success(esp);
1964 1.1 christos eap_figure_next_state(esp, 0);
1965 1.1 christos if (esp->es_rechallenge != 0)
1966 1.1 christos TIMEOUT(eap_rechallenge, esp,
1967 1.1 christos esp->es_rechallenge);
1968 1.1 christos if (esp->es_lwrechallenge != 0)
1969 1.1 christos TIMEOUT(srp_lwrechallenge, esp,
1970 1.1 christos esp->es_lwrechallenge);
1971 1.1 christos break;
1972 1.1 christos
1973 1.1 christos case EAPSRP_LWRECHALLENGE:
1974 1.1 christos if (esp->es_server.ea_state != eapSRP4) {
1975 1.1 christos info("EAP: unexpected SRP Subtype 4 Response");
1976 1.1 christos return;
1977 1.1 christos }
1978 1.1 christos if (len != SHA_DIGESTSIZE) {
1979 1.1 christos error("EAP: bad Lightweight rechallenge "
1980 1.1 christos "response");
1981 1.1 christos return;
1982 1.1 christos }
1983 1.1 christos SHA1Init(&ctxt);
1984 1.1 christos vallen = id;
1985 1.1 christos SHA1Update(&ctxt, &vallen, 1);
1986 1.1 christos SHA1Update(&ctxt, esp->es_server.ea_skey,
1987 1.1 christos SESSION_KEY_LEN);
1988 1.1 christos SHA1Update(&ctxt, esp->es_challenge, esp->es_challen);
1989 1.1 christos SHA1Update(&ctxt, esp->es_server.ea_peer,
1990 1.1 christos esp->es_server.ea_peerlen);
1991 1.1 christos SHA1Final(dig, &ctxt);
1992 1.1 christos if (BCMP(dig, inp, SHA_DIGESTSIZE) != 0) {
1993 1.1 christos error("EAP: failed Lightweight rechallenge");
1994 1.1 christos eap_send_failure(esp);
1995 1.1 christos break;
1996 1.1 christos }
1997 1.1 christos esp->es_server.ea_state = eapOpen;
1998 1.1 christos if (esp->es_lwrechallenge != 0)
1999 1.1 christos TIMEOUT(srp_lwrechallenge, esp,
2000 1.1 christos esp->es_lwrechallenge);
2001 1.1 christos break;
2002 1.1 christos }
2003 1.1 christos break;
2004 1.1 christos #endif /* USE_SRP */
2005 1.1 christos
2006 1.1 christos default:
2007 1.1 christos /* This can't happen. */
2008 1.1 christos error("EAP: unknown Response type %d; ignored", typenum);
2009 1.1 christos return;
2010 1.1 christos }
2011 1.1 christos
2012 1.1 christos if (esp->es_server.ea_timeout > 0) {
2013 1.1 christos UNTIMEOUT(eap_server_timeout, (void *)esp);
2014 1.1 christos }
2015 1.1 christos
2016 1.1 christos if (esp->es_server.ea_state != eapBadAuth &&
2017 1.1 christos esp->es_server.ea_state != eapOpen) {
2018 1.1 christos esp->es_server.ea_id++;
2019 1.1 christos eap_send_request(esp);
2020 1.1 christos }
2021 1.1 christos }
2022 1.1 christos
2023 1.1 christos /*
2024 1.1 christos * eap_success - Receive EAP Success message (client mode).
2025 1.1 christos */
2026 1.1 christos static void
2027 1.1 christos eap_success(esp, inp, id, len)
2028 1.1 christos eap_state *esp;
2029 1.1 christos u_char *inp;
2030 1.1 christos int id;
2031 1.1 christos int len;
2032 1.1 christos {
2033 1.1 christos if (esp->es_client.ea_state != eapOpen && !eap_client_active(esp)) {
2034 1.1 christos dbglog("EAP unexpected success message in state %s (%d)",
2035 1.1 christos eap_state_name(esp->es_client.ea_state),
2036 1.1 christos esp->es_client.ea_state);
2037 1.1 christos return;
2038 1.1 christos }
2039 1.1 christos
2040 1.1 christos if (esp->es_client.ea_timeout > 0) {
2041 1.1 christos UNTIMEOUT(eap_client_timeout, (void *)esp);
2042 1.1 christos }
2043 1.1 christos
2044 1.1 christos if (len > 0) {
2045 1.1 christos /* This is odd. The spec doesn't allow for this. */
2046 1.1 christos PRINTMSG(inp, len);
2047 1.1 christos }
2048 1.1 christos
2049 1.1 christos esp->es_client.ea_state = eapOpen;
2050 1.1 christos auth_withpeer_success(esp->es_unit, PPP_EAP, 0);
2051 1.1 christos }
2052 1.1 christos
2053 1.1 christos /*
2054 1.1 christos * eap_failure - Receive EAP Failure message (client mode).
2055 1.1 christos */
2056 1.1 christos static void
2057 1.1 christos eap_failure(esp, inp, id, len)
2058 1.1 christos eap_state *esp;
2059 1.1 christos u_char *inp;
2060 1.1 christos int id;
2061 1.1 christos int len;
2062 1.1 christos {
2063 1.1 christos if (!eap_client_active(esp)) {
2064 1.1 christos dbglog("EAP unexpected failure message in state %s (%d)",
2065 1.1 christos eap_state_name(esp->es_client.ea_state),
2066 1.1 christos esp->es_client.ea_state);
2067 1.1 christos }
2068 1.1 christos
2069 1.1 christos if (esp->es_client.ea_timeout > 0) {
2070 1.1 christos UNTIMEOUT(eap_client_timeout, (void *)esp);
2071 1.1 christos }
2072 1.1 christos
2073 1.1 christos if (len > 0) {
2074 1.1 christos /* This is odd. The spec doesn't allow for this. */
2075 1.1 christos PRINTMSG(inp, len);
2076 1.1 christos }
2077 1.1 christos
2078 1.1 christos esp->es_client.ea_state = eapBadAuth;
2079 1.1 christos
2080 1.1 christos error("EAP: peer reports authentication failure");
2081 1.1 christos auth_withpeer_fail(esp->es_unit, PPP_EAP);
2082 1.1 christos }
2083 1.1 christos
2084 1.1 christos /*
2085 1.1 christos * eap_input - Handle received EAP message.
2086 1.1 christos */
2087 1.1 christos static void
2088 1.1 christos eap_input(unit, inp, inlen)
2089 1.1 christos int unit;
2090 1.1 christos u_char *inp;
2091 1.1 christos int inlen;
2092 1.1 christos {
2093 1.1 christos eap_state *esp = &eap_states[unit];
2094 1.1 christos u_char code, id;
2095 1.1 christos int len;
2096 1.1 christos
2097 1.1 christos /*
2098 1.1 christos * Parse header (code, id and length). If packet too short,
2099 1.1 christos * drop it.
2100 1.1 christos */
2101 1.1 christos if (inlen < EAP_HEADERLEN) {
2102 1.1 christos error("EAP: packet too short: %d < %d", inlen, EAP_HEADERLEN);
2103 1.1 christos return;
2104 1.1 christos }
2105 1.1 christos GETCHAR(code, inp);
2106 1.1 christos GETCHAR(id, inp);
2107 1.1 christos GETSHORT(len, inp);
2108 1.1 christos if (len < EAP_HEADERLEN || len > inlen) {
2109 1.1 christos error("EAP: packet has illegal length field %d (%d..%d)", len,
2110 1.1 christos EAP_HEADERLEN, inlen);
2111 1.1 christos return;
2112 1.1 christos }
2113 1.1 christos len -= EAP_HEADERLEN;
2114 1.1 christos
2115 1.1 christos /* Dispatch based on message code */
2116 1.1 christos switch (code) {
2117 1.1 christos case EAP_REQUEST:
2118 1.1 christos eap_request(esp, inp, id, len);
2119 1.1 christos break;
2120 1.1 christos
2121 1.1 christos case EAP_RESPONSE:
2122 1.1 christos eap_response(esp, inp, id, len);
2123 1.1 christos break;
2124 1.1 christos
2125 1.1 christos case EAP_SUCCESS:
2126 1.1 christos eap_success(esp, inp, id, len);
2127 1.1 christos break;
2128 1.1 christos
2129 1.1 christos case EAP_FAILURE:
2130 1.1 christos eap_failure(esp, inp, id, len);
2131 1.1 christos break;
2132 1.1 christos
2133 1.1 christos default: /* XXX Need code reject */
2134 1.1 christos /* Note: it's not legal to send EAP Nak here. */
2135 1.1 christos warn("EAP: unknown code %d received", code);
2136 1.1 christos break;
2137 1.1 christos }
2138 1.1 christos }
2139 1.1 christos
2140 1.1 christos /*
2141 1.1 christos * eap_printpkt - print the contents of an EAP packet.
2142 1.1 christos */
2143 1.1 christos static char *eap_codenames[] = {
2144 1.1 christos "Request", "Response", "Success", "Failure"
2145 1.1 christos };
2146 1.1 christos
2147 1.1 christos static char *eap_typenames[] = {
2148 1.1 christos "Identity", "Notification", "Nak", "MD5-Challenge",
2149 1.1 christos "OTP", "Generic-Token", NULL, NULL,
2150 1.1 christos "RSA", "DSS", "KEA", "KEA-Validate",
2151 1.1 christos "TLS", "Defender", "Windows 2000", "Arcot",
2152 1.1 christos "Cisco", "Nokia", "SRP"
2153 1.1 christos };
2154 1.1 christos
2155 1.1 christos static int
2156 1.1 christos eap_printpkt(inp, inlen, printer, arg)
2157 1.1 christos u_char *inp;
2158 1.1 christos int inlen;
2159 1.1 christos void (*printer) __P((void *, char *, ...));
2160 1.1 christos void *arg;
2161 1.1 christos {
2162 1.1 christos int code, id, len, rtype, vallen;
2163 1.1 christos u_char *pstart;
2164 1.1 christos u_int32_t uval;
2165 1.1 christos
2166 1.1 christos if (inlen < EAP_HEADERLEN)
2167 1.1 christos return (0);
2168 1.1 christos pstart = inp;
2169 1.1 christos GETCHAR(code, inp);
2170 1.1 christos GETCHAR(id, inp);
2171 1.1 christos GETSHORT(len, inp);
2172 1.1 christos if (len < EAP_HEADERLEN || len > inlen)
2173 1.1 christos return (0);
2174 1.1 christos
2175 1.1 christos if (code >= 1 && code <= sizeof(eap_codenames) / sizeof(char *))
2176 1.1 christos printer(arg, " %s", eap_codenames[code-1]);
2177 1.1 christos else
2178 1.1 christos printer(arg, " code=0x%x", code);
2179 1.1 christos printer(arg, " id=0x%x", id);
2180 1.1 christos len -= EAP_HEADERLEN;
2181 1.1 christos switch (code) {
2182 1.1 christos case EAP_REQUEST:
2183 1.1 christos if (len < 1) {
2184 1.1 christos printer(arg, " <missing type>");
2185 1.1 christos break;
2186 1.1 christos }
2187 1.1 christos GETCHAR(rtype, inp);
2188 1.1 christos len--;
2189 1.1 christos if (rtype >= 1 &&
2190 1.1 christos rtype <= sizeof (eap_typenames) / sizeof (char *))
2191 1.1 christos printer(arg, " %s", eap_typenames[rtype-1]);
2192 1.1 christos else
2193 1.1 christos printer(arg, " type=0x%x", rtype);
2194 1.1 christos switch (rtype) {
2195 1.1 christos case EAPT_IDENTITY:
2196 1.1 christos case EAPT_NOTIFICATION:
2197 1.1 christos if (len > 0) {
2198 1.1 christos printer(arg, " <Message ");
2199 1.1 christos print_string((char *)inp, len, printer, arg);
2200 1.1 christos printer(arg, ">");
2201 1.1 christos INCPTR(len, inp);
2202 1.1 christos len = 0;
2203 1.1 christos } else {
2204 1.1 christos printer(arg, " <No message>");
2205 1.1 christos }
2206 1.1 christos break;
2207 1.1 christos
2208 1.1 christos case EAPT_MD5CHAP:
2209 1.1 christos if (len <= 0)
2210 1.1 christos break;
2211 1.1 christos GETCHAR(vallen, inp);
2212 1.1 christos len--;
2213 1.1 christos if (vallen > len)
2214 1.1 christos goto truncated;
2215 1.1 christos printer(arg, " <Value%.*B>", vallen, inp);
2216 1.1 christos INCPTR(vallen, inp);
2217 1.1 christos len -= vallen;
2218 1.1 christos if (len > 0) {
2219 1.1 christos printer(arg, " <Name ");
2220 1.1 christos print_string((char *)inp, len, printer, arg);
2221 1.1 christos printer(arg, ">");
2222 1.1 christos INCPTR(len, inp);
2223 1.1 christos len = 0;
2224 1.1 christos } else {
2225 1.1 christos printer(arg, " <No name>");
2226 1.1 christos }
2227 1.1 christos break;
2228 1.1 christos
2229 1.1 christos case EAPT_SRP:
2230 1.1 christos if (len < 3)
2231 1.1 christos goto truncated;
2232 1.1 christos GETCHAR(vallen, inp);
2233 1.1 christos len--;
2234 1.1 christos printer(arg, "-%d", vallen);
2235 1.1 christos switch (vallen) {
2236 1.1 christos case EAPSRP_CHALLENGE:
2237 1.1 christos GETCHAR(vallen, inp);
2238 1.1 christos len--;
2239 1.1 christos if (vallen >= len)
2240 1.1 christos goto truncated;
2241 1.1 christos if (vallen > 0) {
2242 1.1 christos printer(arg, " <Name ");
2243 1.1 christos print_string((char *)inp, vallen, printer,
2244 1.1 christos arg);
2245 1.1 christos printer(arg, ">");
2246 1.1 christos } else {
2247 1.1 christos printer(arg, " <No name>");
2248 1.1 christos }
2249 1.1 christos INCPTR(vallen, inp);
2250 1.1 christos len -= vallen;
2251 1.1 christos GETCHAR(vallen, inp);
2252 1.1 christos len--;
2253 1.1 christos if (vallen >= len)
2254 1.1 christos goto truncated;
2255 1.1 christos printer(arg, " <s%.*B>", vallen, inp);
2256 1.1 christos INCPTR(vallen, inp);
2257 1.1 christos len -= vallen;
2258 1.1 christos GETCHAR(vallen, inp);
2259 1.1 christos len--;
2260 1.1 christos if (vallen > len)
2261 1.1 christos goto truncated;
2262 1.1 christos if (vallen == 0) {
2263 1.1 christos printer(arg, " <Default g=2>");
2264 1.1 christos } else {
2265 1.1 christos printer(arg, " <g%.*B>", vallen, inp);
2266 1.1 christos }
2267 1.1 christos INCPTR(vallen, inp);
2268 1.1 christos len -= vallen;
2269 1.1 christos if (len == 0) {
2270 1.1 christos printer(arg, " <Default N>");
2271 1.1 christos } else {
2272 1.1 christos printer(arg, " <N%.*B>", len, inp);
2273 1.1 christos INCPTR(len, inp);
2274 1.1 christos len = 0;
2275 1.1 christos }
2276 1.1 christos break;
2277 1.1 christos
2278 1.1 christos case EAPSRP_SKEY:
2279 1.1 christos printer(arg, " <B%.*B>", len, inp);
2280 1.1 christos INCPTR(len, inp);
2281 1.1 christos len = 0;
2282 1.1 christos break;
2283 1.1 christos
2284 1.1 christos case EAPSRP_SVALIDATOR:
2285 1.1 christos if (len < sizeof (u_int32_t))
2286 1.1 christos break;
2287 1.1 christos GETLONG(uval, inp);
2288 1.1 christos len -= sizeof (u_int32_t);
2289 1.1 christos if (uval & SRPVAL_EBIT) {
2290 1.1 christos printer(arg, " E");
2291 1.1 christos uval &= ~SRPVAL_EBIT;
2292 1.1 christos }
2293 1.1 christos if (uval != 0) {
2294 1.1 christos printer(arg, " f<%X>", uval);
2295 1.1 christos }
2296 1.1 christos if ((vallen = len) > SHA_DIGESTSIZE)
2297 1.1 christos vallen = SHA_DIGESTSIZE;
2298 1.1 christos printer(arg, " <M2%.*B%s>", len, inp,
2299 1.1 christos len < SHA_DIGESTSIZE ? "?" : "");
2300 1.1 christos INCPTR(vallen, inp);
2301 1.1 christos len -= vallen;
2302 1.1 christos if (len > 0) {
2303 1.1 christos printer(arg, " <PN%.*B>", len, inp);
2304 1.1 christos INCPTR(len, inp);
2305 1.1 christos len = 0;
2306 1.1 christos }
2307 1.1 christos break;
2308 1.1 christos
2309 1.1 christos case EAPSRP_LWRECHALLENGE:
2310 1.1 christos printer(arg, " <Challenge%.*B>", len, inp);
2311 1.1 christos INCPTR(len, inp);
2312 1.1 christos len = 0;
2313 1.1 christos break;
2314 1.1 christos }
2315 1.1 christos break;
2316 1.1 christos }
2317 1.1 christos break;
2318 1.1 christos
2319 1.1 christos case EAP_RESPONSE:
2320 1.1 christos if (len < 1)
2321 1.1 christos break;
2322 1.1 christos GETCHAR(rtype, inp);
2323 1.1 christos len--;
2324 1.1 christos if (rtype >= 1 &&
2325 1.1 christos rtype <= sizeof (eap_typenames) / sizeof (char *))
2326 1.1 christos printer(arg, " %s", eap_typenames[rtype-1]);
2327 1.1 christos else
2328 1.1 christos printer(arg, " type=0x%x", rtype);
2329 1.1 christos switch (rtype) {
2330 1.1 christos case EAPT_IDENTITY:
2331 1.1 christos if (len > 0) {
2332 1.1 christos printer(arg, " <Name ");
2333 1.1 christos print_string((char *)inp, len, printer, arg);
2334 1.1 christos printer(arg, ">");
2335 1.1 christos INCPTR(len, inp);
2336 1.1 christos len = 0;
2337 1.1 christos }
2338 1.1 christos break;
2339 1.1 christos
2340 1.1 christos case EAPT_NAK:
2341 1.1 christos if (len <= 0) {
2342 1.1 christos printer(arg, " <missing hint>");
2343 1.1 christos break;
2344 1.1 christos }
2345 1.1 christos GETCHAR(rtype, inp);
2346 1.1 christos len--;
2347 1.1 christos printer(arg, " <Suggested-type %02X", rtype);
2348 1.1 christos if (rtype >= 1 &&
2349 1.1 christos rtype < sizeof (eap_typenames) / sizeof (char *))
2350 1.1 christos printer(arg, " (%s)", eap_typenames[rtype-1]);
2351 1.1 christos printer(arg, ">");
2352 1.1 christos break;
2353 1.1 christos
2354 1.1 christos case EAPT_MD5CHAP:
2355 1.1 christos if (len <= 0) {
2356 1.1 christos printer(arg, " <missing length>");
2357 1.1 christos break;
2358 1.1 christos }
2359 1.1 christos GETCHAR(vallen, inp);
2360 1.1 christos len--;
2361 1.1 christos if (vallen > len)
2362 1.1 christos goto truncated;
2363 1.1 christos printer(arg, " <Value%.*B>", vallen, inp);
2364 1.1 christos INCPTR(vallen, inp);
2365 1.1 christos len -= vallen;
2366 1.1 christos if (len > 0) {
2367 1.1 christos printer(arg, " <Name ");
2368 1.1 christos print_string((char *)inp, len, printer, arg);
2369 1.1 christos printer(arg, ">");
2370 1.1 christos INCPTR(len, inp);
2371 1.1 christos len = 0;
2372 1.1 christos } else {
2373 1.1 christos printer(arg, " <No name>");
2374 1.1 christos }
2375 1.1 christos break;
2376 1.1 christos
2377 1.1 christos case EAPT_SRP:
2378 1.1 christos if (len < 1)
2379 1.1 christos goto truncated;
2380 1.1 christos GETCHAR(vallen, inp);
2381 1.1 christos len--;
2382 1.1 christos printer(arg, "-%d", vallen);
2383 1.1 christos switch (vallen) {
2384 1.1 christos case EAPSRP_CKEY:
2385 1.1 christos printer(arg, " <A%.*B>", len, inp);
2386 1.1 christos INCPTR(len, inp);
2387 1.1 christos len = 0;
2388 1.1 christos break;
2389 1.1 christos
2390 1.1 christos case EAPSRP_CVALIDATOR:
2391 1.1 christos if (len < sizeof (u_int32_t))
2392 1.1 christos break;
2393 1.1 christos GETLONG(uval, inp);
2394 1.1 christos len -= sizeof (u_int32_t);
2395 1.1 christos if (uval & SRPVAL_EBIT) {
2396 1.1 christos printer(arg, " E");
2397 1.1 christos uval &= ~SRPVAL_EBIT;
2398 1.1 christos }
2399 1.1 christos if (uval != 0) {
2400 1.1 christos printer(arg, " f<%X>", uval);
2401 1.1 christos }
2402 1.1 christos printer(arg, " <M1%.*B%s>", len, inp,
2403 1.1 christos len == SHA_DIGESTSIZE ? "" : "?");
2404 1.1 christos INCPTR(len, inp);
2405 1.1 christos len = 0;
2406 1.1 christos break;
2407 1.1 christos
2408 1.1 christos case EAPSRP_ACK:
2409 1.1 christos break;
2410 1.1 christos
2411 1.1 christos case EAPSRP_LWRECHALLENGE:
2412 1.1 christos printer(arg, " <Response%.*B%s>", len, inp,
2413 1.1 christos len == SHA_DIGESTSIZE ? "" : "?");
2414 1.1 christos if ((vallen = len) > SHA_DIGESTSIZE)
2415 1.1 christos vallen = SHA_DIGESTSIZE;
2416 1.1 christos INCPTR(vallen, inp);
2417 1.1 christos len -= vallen;
2418 1.1 christos break;
2419 1.1 christos }
2420 1.1 christos break;
2421 1.1 christos }
2422 1.1 christos break;
2423 1.1 christos
2424 1.1 christos case EAP_SUCCESS: /* No payload expected for these! */
2425 1.1 christos case EAP_FAILURE:
2426 1.1 christos break;
2427 1.1 christos
2428 1.1 christos truncated:
2429 1.1 christos printer(arg, " <truncated>");
2430 1.1 christos break;
2431 1.1 christos }
2432 1.1 christos
2433 1.1 christos if (len > 8)
2434 1.1 christos printer(arg, "%8B...", inp);
2435 1.1 christos else if (len > 0)
2436 1.1 christos printer(arg, "%.*B", len, inp);
2437 1.1 christos INCPTR(len, inp);
2438 1.1 christos
2439 1.1 christos return (inp - pstart);
2440 1.1 christos }
2441