Home | History | Annotate | Line # | Download | only in pppd
eap.c revision 1.4.8.1
      1  1.4.8.1    martin /*	$NetBSD: eap.c,v 1.4.8.1 2020/02/12 20:13:57 martin 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.4.8.1    martin __RCSID("$NetBSD: eap.c,v 1.4.8.1 2020/02/12 20:13:57 martin 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.4.8.1    martin 		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.4.8.1    martin 		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