17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * chap.c - Challenge Handshake Authentication Protocol. 37c478bd9Sstevel@tonic-gate * 4*f53eecf5SJames Carlson * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 5*f53eecf5SJames Carlson * Use is subject to license terms. 67c478bd9Sstevel@tonic-gate * 77c478bd9Sstevel@tonic-gate * Copyright (c) 1993 The Australian National University. 87c478bd9Sstevel@tonic-gate * All rights reserved. 97c478bd9Sstevel@tonic-gate * 107c478bd9Sstevel@tonic-gate * Redistribution and use in source and binary forms are permitted 117c478bd9Sstevel@tonic-gate * provided that the above copyright notice and this paragraph are 127c478bd9Sstevel@tonic-gate * duplicated in all such forms and that any documentation, 137c478bd9Sstevel@tonic-gate * advertising materials, and other materials related to such 147c478bd9Sstevel@tonic-gate * distribution and use acknowledge that the software was developed 157c478bd9Sstevel@tonic-gate * by the Australian National University. The name of the University 167c478bd9Sstevel@tonic-gate * may not be used to endorse or promote products derived from this 177c478bd9Sstevel@tonic-gate * software without specific prior written permission. 187c478bd9Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 197c478bd9Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 207c478bd9Sstevel@tonic-gate * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 217c478bd9Sstevel@tonic-gate * 227c478bd9Sstevel@tonic-gate * Copyright (c) 1991 Gregory M. Christy. 237c478bd9Sstevel@tonic-gate * All rights reserved. 247c478bd9Sstevel@tonic-gate * 257c478bd9Sstevel@tonic-gate * Redistribution and use in source and binary forms are permitted 267c478bd9Sstevel@tonic-gate * provided that the above copyright notice and this paragraph are 277c478bd9Sstevel@tonic-gate * duplicated in all such forms and that any documentation, 287c478bd9Sstevel@tonic-gate * advertising materials, and other materials related to such 297c478bd9Sstevel@tonic-gate * distribution and use acknowledge that the software was developed 307c478bd9Sstevel@tonic-gate * by Gregory M. Christy. The name of the author may not be used to 317c478bd9Sstevel@tonic-gate * endorse or promote products derived from this software without 327c478bd9Sstevel@tonic-gate * specific prior written permission. 337c478bd9Sstevel@tonic-gate * 347c478bd9Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 357c478bd9Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 367c478bd9Sstevel@tonic-gate * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 377c478bd9Sstevel@tonic-gate */ 387c478bd9Sstevel@tonic-gate 397c478bd9Sstevel@tonic-gate #define RCSID "$Id: chap.c,v 1.24 1999/11/15 01:51:50 paulus Exp $" 407c478bd9Sstevel@tonic-gate 417c478bd9Sstevel@tonic-gate /* 427c478bd9Sstevel@tonic-gate * TODO: 437c478bd9Sstevel@tonic-gate */ 447c478bd9Sstevel@tonic-gate 457c478bd9Sstevel@tonic-gate #include <stdio.h> 467c478bd9Sstevel@tonic-gate #include <string.h> 477c478bd9Sstevel@tonic-gate #include <stdlib.h> 487c478bd9Sstevel@tonic-gate #include <sys/types.h> 497c478bd9Sstevel@tonic-gate #include <sys/time.h> 507c478bd9Sstevel@tonic-gate 517c478bd9Sstevel@tonic-gate #include "pppd.h" 527c478bd9Sstevel@tonic-gate #include "chap.h" 537c478bd9Sstevel@tonic-gate #include "md5.h" 547c478bd9Sstevel@tonic-gate #if defined(CHAPMS) || defined(CHAPMSV2) 557c478bd9Sstevel@tonic-gate #include "chap_ms.h" 567c478bd9Sstevel@tonic-gate #endif 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate #if !defined(lint) && !defined(_lint) 597c478bd9Sstevel@tonic-gate static const char rcsid[] = RCSID; 607c478bd9Sstevel@tonic-gate #endif 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate /* 637c478bd9Sstevel@tonic-gate * Command-line options. 647c478bd9Sstevel@tonic-gate */ 657c478bd9Sstevel@tonic-gate static option_t chap_option_list[] = { 667c478bd9Sstevel@tonic-gate { "chap-restart", o_int, &chap[0].timeouttime, 677c478bd9Sstevel@tonic-gate "Set CHAP Challenge retry interval" }, 687c478bd9Sstevel@tonic-gate { "chap-max-challenge", o_int, &chap[0].max_transmits, 697c478bd9Sstevel@tonic-gate "Max number of Challenges sent without a valid response" }, 707c478bd9Sstevel@tonic-gate { "chap-interval", o_int, &chap[0].chal_interval, 717c478bd9Sstevel@tonic-gate "Set interval for rechallenge" }, 727c478bd9Sstevel@tonic-gate #if defined(CHAPMS) && defined(MSLANMAN) 737c478bd9Sstevel@tonic-gate { "ms-lanman", o_bool, &ms_lanman, 747c478bd9Sstevel@tonic-gate "Use obsolete LAN Manager password when using MS-CHAP", 1 }, 757c478bd9Sstevel@tonic-gate #endif 767c478bd9Sstevel@tonic-gate { NULL } 777c478bd9Sstevel@tonic-gate }; 787c478bd9Sstevel@tonic-gate 797c478bd9Sstevel@tonic-gate /* 807c478bd9Sstevel@tonic-gate * Protocol entry points. 817c478bd9Sstevel@tonic-gate */ 827c478bd9Sstevel@tonic-gate static void ChapInit __P((int)); 837c478bd9Sstevel@tonic-gate static void ChapLowerUp __P((int)); 847c478bd9Sstevel@tonic-gate static void ChapLowerDown __P((int)); 857c478bd9Sstevel@tonic-gate static void ChapInput __P((int, u_char *, int)); 867c478bd9Sstevel@tonic-gate static void ChapProtocolReject __P((int)); 877c478bd9Sstevel@tonic-gate static int ChapPrintPkt __P((u_char *, int, 887c478bd9Sstevel@tonic-gate void (*) __P((void *, const char *, ...)), void *)); 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate struct protent chap_protent = { 917c478bd9Sstevel@tonic-gate PPP_CHAP, /* PPP protocol number */ 927c478bd9Sstevel@tonic-gate ChapInit, /* Initialization procedure */ 937c478bd9Sstevel@tonic-gate ChapInput, /* Process a received packet */ 947c478bd9Sstevel@tonic-gate ChapProtocolReject, /* Process a received protocol-reject */ 957c478bd9Sstevel@tonic-gate ChapLowerUp, /* Lower layer has come up */ 967c478bd9Sstevel@tonic-gate ChapLowerDown, /* Lower layer has gone down */ 977c478bd9Sstevel@tonic-gate NULL, /* Open the protocol */ 987c478bd9Sstevel@tonic-gate NULL, /* Close the protocol */ 997c478bd9Sstevel@tonic-gate ChapPrintPkt, /* Print a packet in readable form */ 1007c478bd9Sstevel@tonic-gate NULL, /* Process a received data packet */ 1017c478bd9Sstevel@tonic-gate 1, /* 0 iff protocol is disabled */ 1027c478bd9Sstevel@tonic-gate "CHAP", /* Text name of protocol */ 1037c478bd9Sstevel@tonic-gate NULL, /* Text name of corresponding data protocol */ 1047c478bd9Sstevel@tonic-gate chap_option_list, /* List of command-line options */ 1057c478bd9Sstevel@tonic-gate NULL, /* Check requested options, assign defaults */ 1067c478bd9Sstevel@tonic-gate NULL, /* Configure interface for demand-dial */ 1077c478bd9Sstevel@tonic-gate NULL /* Say whether to bring up link for this pkt */ 1087c478bd9Sstevel@tonic-gate }; 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate /* Not static'd for plug-ins */ 1117c478bd9Sstevel@tonic-gate chap_state chap[NUM_PPP]; /* CHAP state; one for each unit */ 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate static void ChapChallengeTimeout __P((void *)); 1147c478bd9Sstevel@tonic-gate static void ChapResponseTimeout __P((void *)); 1157c478bd9Sstevel@tonic-gate static void ChapReceiveChallenge __P((chap_state *, u_char *, int, int)); 1167c478bd9Sstevel@tonic-gate static void ChapRechallenge __P((void *)); 1177c478bd9Sstevel@tonic-gate static void ChapReceiveResponse __P((chap_state *, u_char *, int, int)); 1187c478bd9Sstevel@tonic-gate static void ChapReceiveSuccess __P((chap_state *, u_char *, int, int)); 1197c478bd9Sstevel@tonic-gate static void ChapReceiveFailure __P((chap_state *, u_char *, int, int)); 1207c478bd9Sstevel@tonic-gate static void ChapSendStatus __P((chap_state *, int)); 1217c478bd9Sstevel@tonic-gate static void ChapSendChallenge __P((chap_state *)); 1227c478bd9Sstevel@tonic-gate static void ChapSendResponse __P((chap_state *)); 1237c478bd9Sstevel@tonic-gate static void ChapGenChallenge __P((chap_state *)); 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate static const char * 1267c478bd9Sstevel@tonic-gate chap_cstate(int clientstate) 1277c478bd9Sstevel@tonic-gate { 1287c478bd9Sstevel@tonic-gate static const char *cstate[] = { CHAPCS__LIST }; 1297c478bd9Sstevel@tonic-gate static char buf[32]; 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate if (clientstate < 0 || clientstate >= Dim(cstate)) { 1327c478bd9Sstevel@tonic-gate (void) slprintf(buf, sizeof(buf), "#%d", clientstate); 1337c478bd9Sstevel@tonic-gate return (buf); 1347c478bd9Sstevel@tonic-gate } 1357c478bd9Sstevel@tonic-gate return cstate[clientstate]; 1367c478bd9Sstevel@tonic-gate } 1377c478bd9Sstevel@tonic-gate 1387c478bd9Sstevel@tonic-gate static const char * 1397c478bd9Sstevel@tonic-gate chap_sstate(int serverstate) 1407c478bd9Sstevel@tonic-gate { 1417c478bd9Sstevel@tonic-gate static const char *sstate[] = { CHAPSS__LIST }; 1427c478bd9Sstevel@tonic-gate static char buf[32]; 1437c478bd9Sstevel@tonic-gate 1447c478bd9Sstevel@tonic-gate if (serverstate < 0 || serverstate >= Dim(sstate)) { 1457c478bd9Sstevel@tonic-gate (void) slprintf(buf, sizeof(buf), "#%d", serverstate); 1467c478bd9Sstevel@tonic-gate return (buf); 1477c478bd9Sstevel@tonic-gate } 1487c478bd9Sstevel@tonic-gate return sstate[serverstate]; 1497c478bd9Sstevel@tonic-gate } 1507c478bd9Sstevel@tonic-gate 1517c478bd9Sstevel@tonic-gate /* 1527c478bd9Sstevel@tonic-gate * ChapInit - Initialize a CHAP unit. 1537c478bd9Sstevel@tonic-gate */ 1547c478bd9Sstevel@tonic-gate static void 1557c478bd9Sstevel@tonic-gate ChapInit(unit) 1567c478bd9Sstevel@tonic-gate int unit; 1577c478bd9Sstevel@tonic-gate { 1587c478bd9Sstevel@tonic-gate chap_state *cstate = &chap[unit]; 1597c478bd9Sstevel@tonic-gate 1607c478bd9Sstevel@tonic-gate BZERO(cstate, sizeof(*cstate)); 1617c478bd9Sstevel@tonic-gate cstate->unit = unit; 1627c478bd9Sstevel@tonic-gate cstate->clientstate = CHAPCS_INITIAL; 1637c478bd9Sstevel@tonic-gate cstate->serverstate = CHAPSS_INITIAL; 1647c478bd9Sstevel@tonic-gate cstate->timeouttime = CHAP_DEFTIMEOUT; 1657c478bd9Sstevel@tonic-gate cstate->max_transmits = CHAP_DEFTRANSMITS; 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate /* XXX save get_first_hwaddr() here. */ 1687c478bd9Sstevel@tonic-gate /* random number generator is initialized in magic_init */ 1697c478bd9Sstevel@tonic-gate } 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate 1727c478bd9Sstevel@tonic-gate /* 1737c478bd9Sstevel@tonic-gate * ChapAuthWithPeer - Authenticate us with our peer (start client). 1747c478bd9Sstevel@tonic-gate * 1757c478bd9Sstevel@tonic-gate */ 1767c478bd9Sstevel@tonic-gate void 1777c478bd9Sstevel@tonic-gate ChapAuthWithPeer(unit, our_name, digest) 1787c478bd9Sstevel@tonic-gate int unit; 1797c478bd9Sstevel@tonic-gate char *our_name; 1807c478bd9Sstevel@tonic-gate int digest; 1817c478bd9Sstevel@tonic-gate { 1827c478bd9Sstevel@tonic-gate chap_state *cstate = &chap[unit]; 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate cstate->resp_name = our_name; 1857c478bd9Sstevel@tonic-gate cstate->resp_type = digest; 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate if (cstate->clientstate == CHAPCS_INITIAL || 1887c478bd9Sstevel@tonic-gate cstate->clientstate == CHAPCS_PENDING) { 1897c478bd9Sstevel@tonic-gate /* lower layer isn't up - wait until later */ 1907c478bd9Sstevel@tonic-gate cstate->clientstate = CHAPCS_PENDING; 1917c478bd9Sstevel@tonic-gate return; 1927c478bd9Sstevel@tonic-gate } 1937c478bd9Sstevel@tonic-gate 1947c478bd9Sstevel@tonic-gate /* 1957c478bd9Sstevel@tonic-gate * We get here as a result of LCP coming up. 1967c478bd9Sstevel@tonic-gate * So even if CHAP was open before, we will 1977c478bd9Sstevel@tonic-gate * have to re-authenticate ourselves. 1987c478bd9Sstevel@tonic-gate */ 1997c478bd9Sstevel@tonic-gate cstate->clientstate = CHAPCS_LISTEN; 2007c478bd9Sstevel@tonic-gate } 2017c478bd9Sstevel@tonic-gate 2027c478bd9Sstevel@tonic-gate 2037c478bd9Sstevel@tonic-gate /* 2047c478bd9Sstevel@tonic-gate * ChapAuthPeer - Authenticate our peer (start server). 2057c478bd9Sstevel@tonic-gate */ 2067c478bd9Sstevel@tonic-gate void 2077c478bd9Sstevel@tonic-gate ChapAuthPeer(unit, our_name, digest) 2087c478bd9Sstevel@tonic-gate int unit; 2097c478bd9Sstevel@tonic-gate char *our_name; 2107c478bd9Sstevel@tonic-gate int digest; 2117c478bd9Sstevel@tonic-gate { 2127c478bd9Sstevel@tonic-gate chap_state *cstate = &chap[unit]; 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate cstate->chal_name = our_name; 2157c478bd9Sstevel@tonic-gate cstate->chal_type = digest; 2167c478bd9Sstevel@tonic-gate 2177c478bd9Sstevel@tonic-gate if (cstate->serverstate == CHAPSS_INITIAL || 2187c478bd9Sstevel@tonic-gate cstate->serverstate == CHAPSS_PENDING) { 2197c478bd9Sstevel@tonic-gate /* lower layer isn't up - wait until later */ 2207c478bd9Sstevel@tonic-gate cstate->serverstate = CHAPSS_PENDING; 2217c478bd9Sstevel@tonic-gate return; 2227c478bd9Sstevel@tonic-gate } 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate ChapGenChallenge(cstate); 2257c478bd9Sstevel@tonic-gate ChapSendChallenge(cstate); /* crank it up dude! */ 2267c478bd9Sstevel@tonic-gate cstate->serverstate = CHAPSS_INITIAL_CHAL; 2277c478bd9Sstevel@tonic-gate } 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate /* 2317c478bd9Sstevel@tonic-gate * ChapChallengeTimeout - Timeout expired on sending challenge. 2327c478bd9Sstevel@tonic-gate */ 2337c478bd9Sstevel@tonic-gate static void 2347c478bd9Sstevel@tonic-gate ChapChallengeTimeout(arg) 2357c478bd9Sstevel@tonic-gate void *arg; 2367c478bd9Sstevel@tonic-gate { 2377c478bd9Sstevel@tonic-gate chap_state *cstate = (chap_state *) arg; 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate /* if we aren't sending challenges, don't worry. then again we */ 2407c478bd9Sstevel@tonic-gate /* probably shouldn't be here either */ 2417c478bd9Sstevel@tonic-gate if (cstate->serverstate != CHAPSS_INITIAL_CHAL && 2427c478bd9Sstevel@tonic-gate cstate->serverstate != CHAPSS_RECHALLENGE) 2437c478bd9Sstevel@tonic-gate return; 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate if (cstate->chal_transmits >= cstate->max_transmits) { 2467c478bd9Sstevel@tonic-gate /* give up on peer */ 2477c478bd9Sstevel@tonic-gate error("Peer failed to respond to CHAP challenge"); 2487c478bd9Sstevel@tonic-gate cstate->serverstate = CHAPSS_BADAUTH; 2497c478bd9Sstevel@tonic-gate auth_peer_fail(cstate->unit, PPP_CHAP); 2507c478bd9Sstevel@tonic-gate return; 2517c478bd9Sstevel@tonic-gate } 2527c478bd9Sstevel@tonic-gate 2537c478bd9Sstevel@tonic-gate ChapSendChallenge(cstate); /* Re-send challenge */ 2547c478bd9Sstevel@tonic-gate } 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate /* 2587c478bd9Sstevel@tonic-gate * ChapResponseTimeout - Timeout expired on sending response. 2597c478bd9Sstevel@tonic-gate */ 2607c478bd9Sstevel@tonic-gate static void 2617c478bd9Sstevel@tonic-gate ChapResponseTimeout(arg) 2627c478bd9Sstevel@tonic-gate void *arg; 2637c478bd9Sstevel@tonic-gate { 2647c478bd9Sstevel@tonic-gate chap_state *cstate = (chap_state *) arg; 2657c478bd9Sstevel@tonic-gate 2667c478bd9Sstevel@tonic-gate /* if we aren't sending a response, don't worry. */ 2677c478bd9Sstevel@tonic-gate if (cstate->clientstate != CHAPCS_RESPONSE) 2687c478bd9Sstevel@tonic-gate return; 2697c478bd9Sstevel@tonic-gate 2707c478bd9Sstevel@tonic-gate ChapSendResponse(cstate); /* re-send response */ 2717c478bd9Sstevel@tonic-gate } 2727c478bd9Sstevel@tonic-gate 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate /* 2757c478bd9Sstevel@tonic-gate * ChapRechallenge - Time to challenge the peer again. 2767c478bd9Sstevel@tonic-gate */ 2777c478bd9Sstevel@tonic-gate static void 2787c478bd9Sstevel@tonic-gate ChapRechallenge(arg) 2797c478bd9Sstevel@tonic-gate void *arg; 2807c478bd9Sstevel@tonic-gate { 2817c478bd9Sstevel@tonic-gate chap_state *cstate = (chap_state *) arg; 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate /* if we aren't sending a response, don't worry. */ 2847c478bd9Sstevel@tonic-gate if (cstate->serverstate != CHAPSS_OPEN) 2857c478bd9Sstevel@tonic-gate return; 2867c478bd9Sstevel@tonic-gate 2877c478bd9Sstevel@tonic-gate ChapGenChallenge(cstate); 2887c478bd9Sstevel@tonic-gate ChapSendChallenge(cstate); 2897c478bd9Sstevel@tonic-gate cstate->serverstate = CHAPSS_RECHALLENGE; 2907c478bd9Sstevel@tonic-gate } 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate 2937c478bd9Sstevel@tonic-gate /* 2947c478bd9Sstevel@tonic-gate * ChapLowerUp - The lower layer is up. 2957c478bd9Sstevel@tonic-gate * 2967c478bd9Sstevel@tonic-gate * Start up if we have pending requests. 2977c478bd9Sstevel@tonic-gate */ 2987c478bd9Sstevel@tonic-gate static void 2997c478bd9Sstevel@tonic-gate ChapLowerUp(unit) 3007c478bd9Sstevel@tonic-gate int unit; 3017c478bd9Sstevel@tonic-gate { 3027c478bd9Sstevel@tonic-gate chap_state *cstate = &chap[unit]; 3037c478bd9Sstevel@tonic-gate 3047c478bd9Sstevel@tonic-gate if (cstate->clientstate == CHAPCS_INITIAL) 3057c478bd9Sstevel@tonic-gate cstate->clientstate = CHAPCS_CLOSED; 3067c478bd9Sstevel@tonic-gate else if (cstate->clientstate == CHAPCS_PENDING) 3077c478bd9Sstevel@tonic-gate cstate->clientstate = CHAPCS_LISTEN; 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate if (cstate->serverstate == CHAPSS_INITIAL) 3107c478bd9Sstevel@tonic-gate cstate->serverstate = CHAPSS_CLOSED; 3117c478bd9Sstevel@tonic-gate else if (cstate->serverstate == CHAPSS_PENDING) { 3127c478bd9Sstevel@tonic-gate ChapGenChallenge(cstate); 3137c478bd9Sstevel@tonic-gate ChapSendChallenge(cstate); 3147c478bd9Sstevel@tonic-gate cstate->serverstate = CHAPSS_INITIAL_CHAL; 3157c478bd9Sstevel@tonic-gate } 3167c478bd9Sstevel@tonic-gate } 3177c478bd9Sstevel@tonic-gate 3187c478bd9Sstevel@tonic-gate 3197c478bd9Sstevel@tonic-gate /* 3207c478bd9Sstevel@tonic-gate * ChapLowerDown - The lower layer is down. 3217c478bd9Sstevel@tonic-gate * 3227c478bd9Sstevel@tonic-gate * Cancel all timeouts. 3237c478bd9Sstevel@tonic-gate */ 3247c478bd9Sstevel@tonic-gate static void 3257c478bd9Sstevel@tonic-gate ChapLowerDown(unit) 3267c478bd9Sstevel@tonic-gate int unit; 3277c478bd9Sstevel@tonic-gate { 3287c478bd9Sstevel@tonic-gate chap_state *cstate = &chap[unit]; 3297c478bd9Sstevel@tonic-gate 3307c478bd9Sstevel@tonic-gate /* Timeout(s) pending? Cancel if so. */ 3317c478bd9Sstevel@tonic-gate if (cstate->serverstate == CHAPSS_INITIAL_CHAL || 3327c478bd9Sstevel@tonic-gate cstate->serverstate == CHAPSS_RECHALLENGE) 3337c478bd9Sstevel@tonic-gate UNTIMEOUT(ChapChallengeTimeout, cstate); 3347c478bd9Sstevel@tonic-gate else if (cstate->serverstate == CHAPSS_OPEN 3357c478bd9Sstevel@tonic-gate && cstate->chal_interval != 0) 3367c478bd9Sstevel@tonic-gate UNTIMEOUT(ChapRechallenge, cstate); 3377c478bd9Sstevel@tonic-gate if (cstate->clientstate == CHAPCS_RESPONSE) 3387c478bd9Sstevel@tonic-gate UNTIMEOUT(ChapResponseTimeout, cstate); 3397c478bd9Sstevel@tonic-gate 3407c478bd9Sstevel@tonic-gate cstate->clientstate = CHAPCS_INITIAL; 3417c478bd9Sstevel@tonic-gate cstate->serverstate = CHAPSS_INITIAL; 3427c478bd9Sstevel@tonic-gate } 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate 3457c478bd9Sstevel@tonic-gate /* 3467c478bd9Sstevel@tonic-gate * ChapProtocolReject - Peer doesn't grok CHAP. 3477c478bd9Sstevel@tonic-gate */ 3487c478bd9Sstevel@tonic-gate static void 3497c478bd9Sstevel@tonic-gate ChapProtocolReject(unit) 3507c478bd9Sstevel@tonic-gate int unit; 3517c478bd9Sstevel@tonic-gate { 3527c478bd9Sstevel@tonic-gate chap_state *cstate = &chap[unit]; 3537c478bd9Sstevel@tonic-gate 3547c478bd9Sstevel@tonic-gate if (cstate->serverstate != CHAPSS_INITIAL && 3557c478bd9Sstevel@tonic-gate cstate->serverstate != CHAPSS_CLOSED) 3567c478bd9Sstevel@tonic-gate auth_peer_fail(unit, PPP_CHAP); 3577c478bd9Sstevel@tonic-gate if (cstate->clientstate != CHAPCS_INITIAL && 3587c478bd9Sstevel@tonic-gate cstate->clientstate != CHAPCS_CLOSED) 3597c478bd9Sstevel@tonic-gate auth_withpeer_fail(unit, PPP_CHAP); 3607c478bd9Sstevel@tonic-gate ChapLowerDown(unit); /* shutdown chap */ 3617c478bd9Sstevel@tonic-gate } 3627c478bd9Sstevel@tonic-gate 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate /* 3657c478bd9Sstevel@tonic-gate * ChapInput - Input CHAP packet. 3667c478bd9Sstevel@tonic-gate */ 3677c478bd9Sstevel@tonic-gate static void 3687c478bd9Sstevel@tonic-gate ChapInput(unit, inpacket, packet_len) 3697c478bd9Sstevel@tonic-gate int unit; 3707c478bd9Sstevel@tonic-gate u_char *inpacket; 3717c478bd9Sstevel@tonic-gate int packet_len; 3727c478bd9Sstevel@tonic-gate { 3737c478bd9Sstevel@tonic-gate chap_state *cstate = &chap[unit]; 3747c478bd9Sstevel@tonic-gate u_char *inp; 3757c478bd9Sstevel@tonic-gate u_char code, id; 3767c478bd9Sstevel@tonic-gate int len; 3777c478bd9Sstevel@tonic-gate 3787c478bd9Sstevel@tonic-gate /* 3797c478bd9Sstevel@tonic-gate * Parse header (code, id and length). 3807c478bd9Sstevel@tonic-gate * If packet too short, drop it. 3817c478bd9Sstevel@tonic-gate */ 3827c478bd9Sstevel@tonic-gate inp = inpacket; 3837c478bd9Sstevel@tonic-gate if (packet_len < CHAP_HEADERLEN) { 3847c478bd9Sstevel@tonic-gate error("CHAP: packet is too small (%d < %d)", packet_len, 3857c478bd9Sstevel@tonic-gate CHAP_HEADERLEN); 3867c478bd9Sstevel@tonic-gate return; 3877c478bd9Sstevel@tonic-gate } 3887c478bd9Sstevel@tonic-gate GETCHAR(code, inp); 3897c478bd9Sstevel@tonic-gate GETCHAR(id, inp); 3907c478bd9Sstevel@tonic-gate GETSHORT(len, inp); 3917c478bd9Sstevel@tonic-gate if (len < CHAP_HEADERLEN || len > packet_len) { 3927c478bd9Sstevel@tonic-gate error("CHAP: packet has illegal length %d (%d..%d)", 3937c478bd9Sstevel@tonic-gate len, CHAP_HEADERLEN, packet_len); 3947c478bd9Sstevel@tonic-gate return; 3957c478bd9Sstevel@tonic-gate } 3967c478bd9Sstevel@tonic-gate len -= CHAP_HEADERLEN; 3977c478bd9Sstevel@tonic-gate 3987c478bd9Sstevel@tonic-gate /* 3997c478bd9Sstevel@tonic-gate * Action depends on code (as in fact it usually does :-). 4007c478bd9Sstevel@tonic-gate */ 4017c478bd9Sstevel@tonic-gate switch (code) { 4027c478bd9Sstevel@tonic-gate case CHAP_CHALLENGE: 4037c478bd9Sstevel@tonic-gate ChapReceiveChallenge(cstate, inp, id, len); 4047c478bd9Sstevel@tonic-gate break; 4057c478bd9Sstevel@tonic-gate 4067c478bd9Sstevel@tonic-gate case CHAP_RESPONSE: 4077c478bd9Sstevel@tonic-gate ChapReceiveResponse(cstate, inp, id, len); 4087c478bd9Sstevel@tonic-gate break; 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate case CHAP_FAILURE: 4117c478bd9Sstevel@tonic-gate ChapReceiveFailure(cstate, inp, id, len); 4127c478bd9Sstevel@tonic-gate break; 4137c478bd9Sstevel@tonic-gate 4147c478bd9Sstevel@tonic-gate case CHAP_SUCCESS: 4157c478bd9Sstevel@tonic-gate ChapReceiveSuccess(cstate, inp, id, len); 4167c478bd9Sstevel@tonic-gate break; 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate default: 4197c478bd9Sstevel@tonic-gate /* CHAP does not define a code reject. */ 4207c478bd9Sstevel@tonic-gate warn("Unknown CHAP code (%d) received.", code); 4217c478bd9Sstevel@tonic-gate break; 4227c478bd9Sstevel@tonic-gate } 4237c478bd9Sstevel@tonic-gate } 4247c478bd9Sstevel@tonic-gate 4257c478bd9Sstevel@tonic-gate 4267c478bd9Sstevel@tonic-gate /* 4277c478bd9Sstevel@tonic-gate * ChapReceiveChallenge - Receive Challenge and send Response. 4287c478bd9Sstevel@tonic-gate */ 4297c478bd9Sstevel@tonic-gate static void 4307c478bd9Sstevel@tonic-gate ChapReceiveChallenge(cstate, inp, id, len) 4317c478bd9Sstevel@tonic-gate chap_state *cstate; 4327c478bd9Sstevel@tonic-gate u_char *inp; 4337c478bd9Sstevel@tonic-gate int id; 4347c478bd9Sstevel@tonic-gate int len; 4357c478bd9Sstevel@tonic-gate { 4367c478bd9Sstevel@tonic-gate int rchallenge_len; 4377c478bd9Sstevel@tonic-gate u_char *rchallenge; 4387c478bd9Sstevel@tonic-gate int secret_len; 4397c478bd9Sstevel@tonic-gate char rhostname[MAXNAMELEN]; 4407c478bd9Sstevel@tonic-gate char secret[MAXSECRETLEN]; 4417c478bd9Sstevel@tonic-gate MD5_CTX mdContext; 4427c478bd9Sstevel@tonic-gate u_char hash[MD5_SIGNATURE_SIZE]; 4437c478bd9Sstevel@tonic-gate int fake_response = 0; 4447c478bd9Sstevel@tonic-gate 4457c478bd9Sstevel@tonic-gate if (cstate->clientstate == CHAPCS_CLOSED || 4467c478bd9Sstevel@tonic-gate cstate->clientstate == CHAPCS_PENDING) { 4477c478bd9Sstevel@tonic-gate if (debug) 4487c478bd9Sstevel@tonic-gate dbglog("CHAP Challenge unexpectedly received in state %s", 4497c478bd9Sstevel@tonic-gate chap_cstate(cstate->clientstate)); 4507c478bd9Sstevel@tonic-gate return; 4517c478bd9Sstevel@tonic-gate } 4527c478bd9Sstevel@tonic-gate 4537c478bd9Sstevel@tonic-gate if (len < 2) { 4547c478bd9Sstevel@tonic-gate error("CHAP: Challenge message length %d", len); 4557c478bd9Sstevel@tonic-gate return; 4567c478bd9Sstevel@tonic-gate } 4577c478bd9Sstevel@tonic-gate 4587c478bd9Sstevel@tonic-gate GETCHAR(rchallenge_len, inp); 4597c478bd9Sstevel@tonic-gate len -= sizeof (u_char) + rchallenge_len; /* now name field length */ 4607c478bd9Sstevel@tonic-gate if (len < 0) { 4617c478bd9Sstevel@tonic-gate error("CHAP: Challenge truncated"); 4627c478bd9Sstevel@tonic-gate return; 4637c478bd9Sstevel@tonic-gate } 4647c478bd9Sstevel@tonic-gate rchallenge = inp; 4657c478bd9Sstevel@tonic-gate INCPTR(rchallenge_len, inp); 4667c478bd9Sstevel@tonic-gate 4677c478bd9Sstevel@tonic-gate if (len >= sizeof(rhostname)) 4687c478bd9Sstevel@tonic-gate len = sizeof(rhostname) - 1; 4697c478bd9Sstevel@tonic-gate if (len > 0) { 4707c478bd9Sstevel@tonic-gate BCOPY(inp, rhostname, len); 4717c478bd9Sstevel@tonic-gate } 4727c478bd9Sstevel@tonic-gate rhostname[len] = '\0'; 4737c478bd9Sstevel@tonic-gate 4747c478bd9Sstevel@tonic-gate #ifdef CHECK_CHALLENGE_LENGTH 4757c478bd9Sstevel@tonic-gate if (rchallenge_len < CHECK_CHALLENGE_LENGTH) { 4767c478bd9Sstevel@tonic-gate warn("CHAP: Challenge from %s unreasonably short (%d octets)", 4777c478bd9Sstevel@tonic-gate rhostname, rchallenge_len); 4787c478bd9Sstevel@tonic-gate fake_response = 1; 4797c478bd9Sstevel@tonic-gate } 4807c478bd9Sstevel@tonic-gate #endif 4817c478bd9Sstevel@tonic-gate 4827c478bd9Sstevel@tonic-gate /* XXX compare against saved get_first_hwaddr() here. */ 4837c478bd9Sstevel@tonic-gate 4847c478bd9Sstevel@tonic-gate /* Microsoft NT doesn't send a name in the CHAP Challenge message */ 4857c478bd9Sstevel@tonic-gate if (explicit_remote || 4867c478bd9Sstevel@tonic-gate (remote_name[0] != '\0' && rhostname[0] == '\0')) { 4877c478bd9Sstevel@tonic-gate (void) strlcpy(rhostname, remote_name, sizeof(rhostname)); 4887c478bd9Sstevel@tonic-gate if (debug) 4897c478bd9Sstevel@tonic-gate dbglog("CHAP: Peer gave no name; using '%q' as remote name", 4907c478bd9Sstevel@tonic-gate rhostname); 4917c478bd9Sstevel@tonic-gate } 4927c478bd9Sstevel@tonic-gate 4937c478bd9Sstevel@tonic-gate if (cstate->peercname[0] == '\0') { 4947c478bd9Sstevel@tonic-gate (void) strlcpy(cstate->peercname, rhostname, 4957c478bd9Sstevel@tonic-gate sizeof (cstate->peercname)); 4967c478bd9Sstevel@tonic-gate } else if (strcmp(rhostname, cstate->peercname) != 0) { 497*f53eecf5SJames Carlson if (++cstate->rename_count == 1) { 498*f53eecf5SJames Carlson info("CHAP: peer challenge name changed from '%q' to '%q'", 4997c478bd9Sstevel@tonic-gate cstate->peercname, rhostname); 500*f53eecf5SJames Carlson (void) strlcpy(cstate->peercname, rhostname, 501*f53eecf5SJames Carlson sizeof (cstate->peercname)); 502*f53eecf5SJames Carlson } else { 503*f53eecf5SJames Carlson fake_response = 1; 504*f53eecf5SJames Carlson if (cstate->rename_count == 2) 505*f53eecf5SJames Carlson warn("CHAP: peer challenge name changed again to '%q'", 506*f53eecf5SJames Carlson rhostname); 507*f53eecf5SJames Carlson } 5087c478bd9Sstevel@tonic-gate } 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate /* get secret for authenticating ourselves with the specified host */ 5117c478bd9Sstevel@tonic-gate if (!get_secret(cstate->unit, cstate->resp_name, rhostname, 5127c478bd9Sstevel@tonic-gate secret, &secret_len, 0)) { 5137c478bd9Sstevel@tonic-gate secret_len = 0; /* assume null secret if can't find one */ 5147c478bd9Sstevel@tonic-gate warn("No CHAP secret found for authenticating us (%q) to %q", 5157c478bd9Sstevel@tonic-gate cstate->resp_name, rhostname); 5167c478bd9Sstevel@tonic-gate } 5177c478bd9Sstevel@tonic-gate 5187c478bd9Sstevel@tonic-gate /* cancel response send timeout if necessary */ 5197c478bd9Sstevel@tonic-gate if (cstate->clientstate == CHAPCS_RESPONSE) 5207c478bd9Sstevel@tonic-gate UNTIMEOUT(ChapResponseTimeout, cstate); 5217c478bd9Sstevel@tonic-gate 5227c478bd9Sstevel@tonic-gate cstate->resp_id = id; 5237c478bd9Sstevel@tonic-gate cstate->resp_transmits = 0; 5247c478bd9Sstevel@tonic-gate 5257c478bd9Sstevel@tonic-gate /* generate MD based on negotiated type */ 5267c478bd9Sstevel@tonic-gate switch (cstate->resp_type) { 5277c478bd9Sstevel@tonic-gate 5287c478bd9Sstevel@tonic-gate case CHAP_DIGEST_MD5: 5297c478bd9Sstevel@tonic-gate MD5Init(&mdContext); 5307c478bd9Sstevel@tonic-gate MD5Update(&mdContext, &cstate->resp_id, 1); 5317c478bd9Sstevel@tonic-gate MD5Update(&mdContext, (u_char *)secret, (unsigned)secret_len); 5327c478bd9Sstevel@tonic-gate MD5Update(&mdContext, rchallenge, rchallenge_len); 5337c478bd9Sstevel@tonic-gate MD5Final(hash, &mdContext); 5347c478bd9Sstevel@tonic-gate if (fake_response) { 5357c478bd9Sstevel@tonic-gate for (len = 0; len < MD5_SIGNATURE_SIZE; len++) 5367c478bd9Sstevel@tonic-gate cstate->response[len] = (char) (drand48() * 0xff); 5377c478bd9Sstevel@tonic-gate } else { 5387c478bd9Sstevel@tonic-gate BCOPY(hash, cstate->response, MD5_SIGNATURE_SIZE); 5397c478bd9Sstevel@tonic-gate } 5407c478bd9Sstevel@tonic-gate cstate->resp_length = MD5_SIGNATURE_SIZE; 5417c478bd9Sstevel@tonic-gate break; 5427c478bd9Sstevel@tonic-gate 5437c478bd9Sstevel@tonic-gate #ifdef CHAPMS 5447c478bd9Sstevel@tonic-gate case CHAP_MICROSOFT: 5457c478bd9Sstevel@tonic-gate ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len); 5467c478bd9Sstevel@tonic-gate break; 5477c478bd9Sstevel@tonic-gate #endif 5487c478bd9Sstevel@tonic-gate 5497c478bd9Sstevel@tonic-gate #ifdef CHAPMSV2 5507c478bd9Sstevel@tonic-gate case CHAP_MICROSOFT_V2: 5517c478bd9Sstevel@tonic-gate ChapMSv2(cstate, rchallenge, rchallenge_len, secret, secret_len); 5527c478bd9Sstevel@tonic-gate break; 5537c478bd9Sstevel@tonic-gate #endif 5547c478bd9Sstevel@tonic-gate 5557c478bd9Sstevel@tonic-gate default: 5567c478bd9Sstevel@tonic-gate error("CHAP: unknown digest type %d", cstate->resp_type); 5577c478bd9Sstevel@tonic-gate return; 5587c478bd9Sstevel@tonic-gate } 5597c478bd9Sstevel@tonic-gate 5607c478bd9Sstevel@tonic-gate BZERO(secret, sizeof(secret)); 5617c478bd9Sstevel@tonic-gate ChapSendResponse(cstate); 5627c478bd9Sstevel@tonic-gate } 5637c478bd9Sstevel@tonic-gate 5647c478bd9Sstevel@tonic-gate 5657c478bd9Sstevel@tonic-gate /* 5667c478bd9Sstevel@tonic-gate * ChapReceiveResponse - Receive and process response. 5677c478bd9Sstevel@tonic-gate */ 5687c478bd9Sstevel@tonic-gate static void 5697c478bd9Sstevel@tonic-gate ChapReceiveResponse(cstate, inp, id, len) 5707c478bd9Sstevel@tonic-gate chap_state *cstate; 5717c478bd9Sstevel@tonic-gate u_char *inp; 5727c478bd9Sstevel@tonic-gate int id; 5737c478bd9Sstevel@tonic-gate int len; 5747c478bd9Sstevel@tonic-gate { 5757c478bd9Sstevel@tonic-gate u_char *remmd, remmd_len; 5767c478bd9Sstevel@tonic-gate int secret_len, old_state; 5777c478bd9Sstevel@tonic-gate int code; 5787c478bd9Sstevel@tonic-gate char rhostname[MAXNAMELEN], *rhn; 5797c478bd9Sstevel@tonic-gate MD5_CTX mdContext; 5807c478bd9Sstevel@tonic-gate char secret[MAXSECRETLEN]; 5817c478bd9Sstevel@tonic-gate u_char hash[MD5_SIGNATURE_SIZE]; 5827c478bd9Sstevel@tonic-gate 5837c478bd9Sstevel@tonic-gate if (cstate->serverstate == CHAPSS_CLOSED || 5847c478bd9Sstevel@tonic-gate cstate->serverstate == CHAPSS_PENDING) { 5857c478bd9Sstevel@tonic-gate if (debug) 5867c478bd9Sstevel@tonic-gate dbglog("CHAP Response unexpectedly received in state %s", 5877c478bd9Sstevel@tonic-gate chap_sstate(cstate->serverstate)); 5887c478bd9Sstevel@tonic-gate return; 5897c478bd9Sstevel@tonic-gate } 5907c478bd9Sstevel@tonic-gate 5917c478bd9Sstevel@tonic-gate if (id != cstate->chal_id) { 5927c478bd9Sstevel@tonic-gate if (debug) 5937c478bd9Sstevel@tonic-gate dbglog("CHAP: discard response %d; expecting %d", id, 5947c478bd9Sstevel@tonic-gate cstate->chal_id); 5957c478bd9Sstevel@tonic-gate return; /* doesn't match ID of last challenge */ 5967c478bd9Sstevel@tonic-gate } 5977c478bd9Sstevel@tonic-gate 5987c478bd9Sstevel@tonic-gate /* 5997c478bd9Sstevel@tonic-gate * If we have received a duplicate or bogus Response, 6007c478bd9Sstevel@tonic-gate * we have to send the same answer (Success/Failure) 6017c478bd9Sstevel@tonic-gate * as we did for the first Response we saw. 6027c478bd9Sstevel@tonic-gate */ 6037c478bd9Sstevel@tonic-gate if (cstate->serverstate == CHAPSS_OPEN) { 6047c478bd9Sstevel@tonic-gate if (debug) 6057c478bd9Sstevel@tonic-gate dbglog("CHAP ignoring response and resending success message"); 6067c478bd9Sstevel@tonic-gate ChapSendStatus(cstate, CHAP_SUCCESS); 6077c478bd9Sstevel@tonic-gate return; 6087c478bd9Sstevel@tonic-gate } 6097c478bd9Sstevel@tonic-gate if (cstate->serverstate == CHAPSS_BADAUTH) { 6107c478bd9Sstevel@tonic-gate if (debug) 6117c478bd9Sstevel@tonic-gate dbglog("CHAP ignoring response and resending failure message"); 6127c478bd9Sstevel@tonic-gate ChapSendStatus(cstate, CHAP_FAILURE); 6137c478bd9Sstevel@tonic-gate return; 6147c478bd9Sstevel@tonic-gate } 6157c478bd9Sstevel@tonic-gate 6167c478bd9Sstevel@tonic-gate if (len < 2) { 6177c478bd9Sstevel@tonic-gate error("CHAP: Response message length %d", len); 6187c478bd9Sstevel@tonic-gate return; 6197c478bd9Sstevel@tonic-gate } 6207c478bd9Sstevel@tonic-gate GETCHAR(remmd_len, inp); /* get length of MD */ 6217c478bd9Sstevel@tonic-gate remmd = inp; /* get pointer to MD */ 6227c478bd9Sstevel@tonic-gate INCPTR(remmd_len, inp); 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate len -= sizeof (u_char) + remmd_len; 6257c478bd9Sstevel@tonic-gate if (len < 0) { 6267c478bd9Sstevel@tonic-gate error("CHAP: Response truncated"); 6277c478bd9Sstevel@tonic-gate return; 6287c478bd9Sstevel@tonic-gate } 6297c478bd9Sstevel@tonic-gate 6307c478bd9Sstevel@tonic-gate UNTIMEOUT(ChapChallengeTimeout, cstate); 6317c478bd9Sstevel@tonic-gate 6327c478bd9Sstevel@tonic-gate if (len >= sizeof(rhostname)) 6337c478bd9Sstevel@tonic-gate len = sizeof(rhostname) - 1; 6347c478bd9Sstevel@tonic-gate BCOPY(inp, rhostname, len); 6357c478bd9Sstevel@tonic-gate rhostname[len] = '\0'; 6367c478bd9Sstevel@tonic-gate 6377c478bd9Sstevel@tonic-gate /* 6387c478bd9Sstevel@tonic-gate * Get secret for authenticating them with us, 6397c478bd9Sstevel@tonic-gate * do the hash ourselves, and compare the result. 6407c478bd9Sstevel@tonic-gate */ 6417c478bd9Sstevel@tonic-gate code = CHAP_FAILURE; 6427c478bd9Sstevel@tonic-gate rhn = (explicit_remote? remote_name: rhostname); 6437c478bd9Sstevel@tonic-gate if (cstate->serverstate == CHAPSS_RECHALLENGE && 6447c478bd9Sstevel@tonic-gate strcmp(rhostname, peer_authname) != 0) { 6457c478bd9Sstevel@tonic-gate warn("Peer changed his name from '%q' to '%q' on rechallenge", 6467c478bd9Sstevel@tonic-gate peer_authname, rhostname); 6477c478bd9Sstevel@tonic-gate } else if (!get_secret(cstate->unit, rhn, cstate->chal_name, secret, 6487c478bd9Sstevel@tonic-gate &secret_len, 1)) { 6497c478bd9Sstevel@tonic-gate warn("No CHAP secret found for authenticating %q to us (%q)", 6507c478bd9Sstevel@tonic-gate rhn, cstate->chal_name); 6517c478bd9Sstevel@tonic-gate } else { 6527c478bd9Sstevel@tonic-gate 6537c478bd9Sstevel@tonic-gate /* generate MD based on negotiated type */ 6547c478bd9Sstevel@tonic-gate switch (cstate->chal_type) { 6557c478bd9Sstevel@tonic-gate 6567c478bd9Sstevel@tonic-gate case CHAP_DIGEST_MD5: /* only MD5 is defined for now */ 6577c478bd9Sstevel@tonic-gate if (remmd_len != MD5_SIGNATURE_SIZE) 6587c478bd9Sstevel@tonic-gate break; /* it's not even the right length */ 6597c478bd9Sstevel@tonic-gate MD5Init(&mdContext); 6607c478bd9Sstevel@tonic-gate MD5Update(&mdContext, &cstate->chal_id, 1); 6617c478bd9Sstevel@tonic-gate MD5Update(&mdContext, (u_char *)secret, secret_len); 6627c478bd9Sstevel@tonic-gate MD5Update(&mdContext, cstate->challenge, cstate->chal_len); 6637c478bd9Sstevel@tonic-gate MD5Final(hash, &mdContext); 6647c478bd9Sstevel@tonic-gate 6657c478bd9Sstevel@tonic-gate /* compare local and remote MDs and send the appropriate status */ 6667c478bd9Sstevel@tonic-gate if (memcmp (hash, remmd, MD5_SIGNATURE_SIZE) == 0) 6677c478bd9Sstevel@tonic-gate code = CHAP_SUCCESS; /* they are the same! */ 6687c478bd9Sstevel@tonic-gate break; 6697c478bd9Sstevel@tonic-gate 6707c478bd9Sstevel@tonic-gate #ifdef CHAPMS 6717c478bd9Sstevel@tonic-gate case CHAP_MICROSOFT: 6727c478bd9Sstevel@tonic-gate if (ChapMSValidate(cstate, remmd, remmd_len, secret, 6737c478bd9Sstevel@tonic-gate secret_len)) 6747c478bd9Sstevel@tonic-gate code = CHAP_SUCCESS; 6757c478bd9Sstevel@tonic-gate break; 6767c478bd9Sstevel@tonic-gate #endif 6777c478bd9Sstevel@tonic-gate 6787c478bd9Sstevel@tonic-gate #ifdef CHAPMSV2 6797c478bd9Sstevel@tonic-gate case CHAP_MICROSOFT_V2: 6807c478bd9Sstevel@tonic-gate if (ChapMSv2Validate(cstate, rhostname, remmd, remmd_len, 6817c478bd9Sstevel@tonic-gate secret, secret_len)) 6827c478bd9Sstevel@tonic-gate code = CHAP_SUCCESS; 6837c478bd9Sstevel@tonic-gate break; 6847c478bd9Sstevel@tonic-gate #endif 6857c478bd9Sstevel@tonic-gate 6867c478bd9Sstevel@tonic-gate default: 6877c478bd9Sstevel@tonic-gate error("CHAP: unknown digest type %d", cstate->chal_type); 6887c478bd9Sstevel@tonic-gate } 6897c478bd9Sstevel@tonic-gate } 6907c478bd9Sstevel@tonic-gate 6917c478bd9Sstevel@tonic-gate BZERO(secret, sizeof(secret)); 6927c478bd9Sstevel@tonic-gate ChapSendStatus(cstate, code); 6937c478bd9Sstevel@tonic-gate 6947c478bd9Sstevel@tonic-gate if (code == CHAP_SUCCESS) { 6957c478bd9Sstevel@tonic-gate old_state = cstate->serverstate; 6967c478bd9Sstevel@tonic-gate cstate->serverstate = CHAPSS_OPEN; 6977c478bd9Sstevel@tonic-gate if (old_state == CHAPSS_INITIAL_CHAL) { 6987c478bd9Sstevel@tonic-gate auth_peer_success(cstate->unit, PPP_CHAP, rhostname, len); 6997c478bd9Sstevel@tonic-gate } 7007c478bd9Sstevel@tonic-gate if (cstate->chal_interval != 0) 7017c478bd9Sstevel@tonic-gate TIMEOUT(ChapRechallenge, cstate, cstate->chal_interval); 7027c478bd9Sstevel@tonic-gate if (old_state == CHAPSS_INITIAL_CHAL) 7037c478bd9Sstevel@tonic-gate notice("CHAP peer authentication succeeded for %q", rhostname); 7047c478bd9Sstevel@tonic-gate else if (debug) 7057c478bd9Sstevel@tonic-gate dbglog("CHAP peer reauthentication succeeded for %q", rhostname); 7067c478bd9Sstevel@tonic-gate } else { 7077c478bd9Sstevel@tonic-gate error("CHAP peer %sauthentication failed for remote host %q", 7087c478bd9Sstevel@tonic-gate (cstate->serverstate == CHAPSS_INITIAL_CHAL ? "" : "re"), 7097c478bd9Sstevel@tonic-gate rhostname); 7107c478bd9Sstevel@tonic-gate cstate->serverstate = CHAPSS_BADAUTH; 7117c478bd9Sstevel@tonic-gate auth_peer_fail(cstate->unit, PPP_CHAP); 7127c478bd9Sstevel@tonic-gate } 7137c478bd9Sstevel@tonic-gate } 7147c478bd9Sstevel@tonic-gate 7157c478bd9Sstevel@tonic-gate /* 7167c478bd9Sstevel@tonic-gate * ChapReceiveSuccess - Receive Success 7177c478bd9Sstevel@tonic-gate */ 7187c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 7197c478bd9Sstevel@tonic-gate static void 7207c478bd9Sstevel@tonic-gate ChapReceiveSuccess(cstate, inp, id, len) 7217c478bd9Sstevel@tonic-gate chap_state *cstate; 7227c478bd9Sstevel@tonic-gate u_char *inp; 7237c478bd9Sstevel@tonic-gate u_char id; 7247c478bd9Sstevel@tonic-gate int len; 7257c478bd9Sstevel@tonic-gate { 7267c478bd9Sstevel@tonic-gate 7277c478bd9Sstevel@tonic-gate if (cstate->clientstate == CHAPCS_OPEN) { 7287c478bd9Sstevel@tonic-gate /* presumably an answer to a duplicate response */ 7297c478bd9Sstevel@tonic-gate if (debug) 7307c478bd9Sstevel@tonic-gate dbglog("CHAP duplicate Success message ignored"); 7317c478bd9Sstevel@tonic-gate return; 7327c478bd9Sstevel@tonic-gate } 7337c478bd9Sstevel@tonic-gate 7347c478bd9Sstevel@tonic-gate if (cstate->clientstate != CHAPCS_RESPONSE) { 7357c478bd9Sstevel@tonic-gate /* don't know what this is */ 7367c478bd9Sstevel@tonic-gate if (debug) 7377c478bd9Sstevel@tonic-gate dbglog("CHAP Success unexpectedly received in state %s", 7387c478bd9Sstevel@tonic-gate chap_cstate(cstate->clientstate)); 7397c478bd9Sstevel@tonic-gate return; 7407c478bd9Sstevel@tonic-gate } 7417c478bd9Sstevel@tonic-gate 7427c478bd9Sstevel@tonic-gate UNTIMEOUT(ChapResponseTimeout, cstate); 7437c478bd9Sstevel@tonic-gate 7447c478bd9Sstevel@tonic-gate /* 7457c478bd9Sstevel@tonic-gate * Print message. 7467c478bd9Sstevel@tonic-gate */ 7477c478bd9Sstevel@tonic-gate if (len > 0) 7487c478bd9Sstevel@tonic-gate PRINTMSG(inp, len); 7497c478bd9Sstevel@tonic-gate 7507c478bd9Sstevel@tonic-gate cstate->clientstate = CHAPCS_OPEN; 7517c478bd9Sstevel@tonic-gate 7527c478bd9Sstevel@tonic-gate auth_withpeer_success(cstate->unit, PPP_CHAP); 7537c478bd9Sstevel@tonic-gate } 7547c478bd9Sstevel@tonic-gate 7557c478bd9Sstevel@tonic-gate 7567c478bd9Sstevel@tonic-gate /* 7577c478bd9Sstevel@tonic-gate * ChapReceiveFailure - Receive failure. 7587c478bd9Sstevel@tonic-gate */ 7597c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 7607c478bd9Sstevel@tonic-gate static void 7617c478bd9Sstevel@tonic-gate ChapReceiveFailure(cstate, inp, id, len) 7627c478bd9Sstevel@tonic-gate chap_state *cstate; 7637c478bd9Sstevel@tonic-gate u_char *inp; 7647c478bd9Sstevel@tonic-gate u_char id; 7657c478bd9Sstevel@tonic-gate int len; 7667c478bd9Sstevel@tonic-gate { 7677c478bd9Sstevel@tonic-gate if (cstate->clientstate != CHAPCS_RESPONSE) { 7687c478bd9Sstevel@tonic-gate /* don't know what this is */ 7697c478bd9Sstevel@tonic-gate if (debug) 7707c478bd9Sstevel@tonic-gate dbglog("CHAP Failure unexpectedly received in state %s", 7717c478bd9Sstevel@tonic-gate chap_cstate(cstate->clientstate)); 7727c478bd9Sstevel@tonic-gate return; 7737c478bd9Sstevel@tonic-gate } 7747c478bd9Sstevel@tonic-gate 7757c478bd9Sstevel@tonic-gate UNTIMEOUT(ChapResponseTimeout, cstate); 7767c478bd9Sstevel@tonic-gate 7777c478bd9Sstevel@tonic-gate /* 7787c478bd9Sstevel@tonic-gate * Print message. 7797c478bd9Sstevel@tonic-gate */ 7807c478bd9Sstevel@tonic-gate if (len > 0) 7817c478bd9Sstevel@tonic-gate PRINTMSG(inp, len); 7827c478bd9Sstevel@tonic-gate 7837c478bd9Sstevel@tonic-gate error("CHAP authentication failed"); 7847c478bd9Sstevel@tonic-gate auth_withpeer_fail(cstate->unit, PPP_CHAP); 7857c478bd9Sstevel@tonic-gate } 7867c478bd9Sstevel@tonic-gate 7877c478bd9Sstevel@tonic-gate 7887c478bd9Sstevel@tonic-gate /* 7897c478bd9Sstevel@tonic-gate * ChapSendChallenge - Send an Authenticate challenge. 7907c478bd9Sstevel@tonic-gate */ 7917c478bd9Sstevel@tonic-gate static void 7927c478bd9Sstevel@tonic-gate ChapSendChallenge(cstate) 7937c478bd9Sstevel@tonic-gate chap_state *cstate; 7947c478bd9Sstevel@tonic-gate { 7957c478bd9Sstevel@tonic-gate u_char *outp; 7967c478bd9Sstevel@tonic-gate int chal_len, name_len; 7977c478bd9Sstevel@tonic-gate int outlen; 7987c478bd9Sstevel@tonic-gate 7997c478bd9Sstevel@tonic-gate chal_len = cstate->chal_len; 8007c478bd9Sstevel@tonic-gate name_len = strlen(cstate->chal_name); 8017c478bd9Sstevel@tonic-gate outlen = CHAP_HEADERLEN + sizeof (u_char) + chal_len + name_len; 8027c478bd9Sstevel@tonic-gate outp = outpacket_buf; 8037c478bd9Sstevel@tonic-gate 8047c478bd9Sstevel@tonic-gate MAKEHEADER(outp, PPP_CHAP); /* paste in a CHAP header */ 8057c478bd9Sstevel@tonic-gate 8067c478bd9Sstevel@tonic-gate PUTCHAR(CHAP_CHALLENGE, outp); 8077c478bd9Sstevel@tonic-gate PUTCHAR(cstate->chal_id, outp); 8087c478bd9Sstevel@tonic-gate PUTSHORT(outlen, outp); 8097c478bd9Sstevel@tonic-gate 8107c478bd9Sstevel@tonic-gate PUTCHAR(chal_len, outp); /* put length of challenge */ 8117c478bd9Sstevel@tonic-gate BCOPY(cstate->challenge, outp, chal_len); 8127c478bd9Sstevel@tonic-gate INCPTR(chal_len, outp); 8137c478bd9Sstevel@tonic-gate 8147c478bd9Sstevel@tonic-gate BCOPY(cstate->chal_name, outp, name_len); /* append hostname */ 8157c478bd9Sstevel@tonic-gate 8167c478bd9Sstevel@tonic-gate output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN); 8177c478bd9Sstevel@tonic-gate 8187c478bd9Sstevel@tonic-gate TIMEOUT(ChapChallengeTimeout, cstate, cstate->timeouttime); 8197c478bd9Sstevel@tonic-gate ++cstate->chal_transmits; 8207c478bd9Sstevel@tonic-gate } 8217c478bd9Sstevel@tonic-gate 8227c478bd9Sstevel@tonic-gate 8237c478bd9Sstevel@tonic-gate /* 8247c478bd9Sstevel@tonic-gate * ChapSendStatus - Send a status response (ack or nak). 8257c478bd9Sstevel@tonic-gate */ 8267c478bd9Sstevel@tonic-gate static void 8277c478bd9Sstevel@tonic-gate ChapSendStatus(cstate, code) 8287c478bd9Sstevel@tonic-gate chap_state *cstate; 8297c478bd9Sstevel@tonic-gate int code; 8307c478bd9Sstevel@tonic-gate { 8317c478bd9Sstevel@tonic-gate u_char *outp; 8327c478bd9Sstevel@tonic-gate int outlen, msglen; 8337c478bd9Sstevel@tonic-gate char msg[256], *msgp; 8347c478bd9Sstevel@tonic-gate 8357c478bd9Sstevel@tonic-gate if ((msgp = cstate->stat_message) != NULL) { 8367c478bd9Sstevel@tonic-gate msglen = cstate->stat_length; 8377c478bd9Sstevel@tonic-gate } else { 8387c478bd9Sstevel@tonic-gate if (code == CHAP_SUCCESS) 8397c478bd9Sstevel@tonic-gate (void) slprintf(msg, sizeof(msg), "Welcome to %s.", hostname); 8407c478bd9Sstevel@tonic-gate else 8417c478bd9Sstevel@tonic-gate (void) slprintf(msg, sizeof(msg), "I don't like you. Go 'way."); 8427c478bd9Sstevel@tonic-gate msglen = strlen(msg); 8437c478bd9Sstevel@tonic-gate msgp = msg; 8447c478bd9Sstevel@tonic-gate } 8457c478bd9Sstevel@tonic-gate 8467c478bd9Sstevel@tonic-gate outlen = CHAP_HEADERLEN + msglen; 8477c478bd9Sstevel@tonic-gate outp = outpacket_buf; 8487c478bd9Sstevel@tonic-gate 8497c478bd9Sstevel@tonic-gate MAKEHEADER(outp, PPP_CHAP); /* paste in a header */ 8507c478bd9Sstevel@tonic-gate 8517c478bd9Sstevel@tonic-gate PUTCHAR(code, outp); 8527c478bd9Sstevel@tonic-gate PUTCHAR(cstate->chal_id, outp); 8537c478bd9Sstevel@tonic-gate PUTSHORT(outlen, outp); 8547c478bd9Sstevel@tonic-gate BCOPY(msgp, outp, msglen); 8557c478bd9Sstevel@tonic-gate output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN); 8567c478bd9Sstevel@tonic-gate } 8577c478bd9Sstevel@tonic-gate 8587c478bd9Sstevel@tonic-gate /* 8597c478bd9Sstevel@tonic-gate * ChapGenChallenge is used to generate a pseudo-random challenge string of 8607c478bd9Sstevel@tonic-gate * a pseudo-random length between min_len and max_len. The challenge 8617c478bd9Sstevel@tonic-gate * string and its length are stored in *cstate, and various other fields of 8627c478bd9Sstevel@tonic-gate * *cstate are initialized. 8637c478bd9Sstevel@tonic-gate */ 8647c478bd9Sstevel@tonic-gate 8657c478bd9Sstevel@tonic-gate static void 8667c478bd9Sstevel@tonic-gate ChapGenChallenge(cstate) 8677c478bd9Sstevel@tonic-gate chap_state *cstate; 8687c478bd9Sstevel@tonic-gate { 8697c478bd9Sstevel@tonic-gate int chal_len; 8707c478bd9Sstevel@tonic-gate u_char *ptr = cstate->challenge; 8717c478bd9Sstevel@tonic-gate int i; 8727c478bd9Sstevel@tonic-gate 8737c478bd9Sstevel@tonic-gate /* pick a random challenge length between MIN_CHALLENGE_LENGTH and 8747c478bd9Sstevel@tonic-gate MAX_CHALLENGE_LENGTH */ 8757c478bd9Sstevel@tonic-gate chal_len = (unsigned) ((drand48() * 8767c478bd9Sstevel@tonic-gate (MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) + 8777c478bd9Sstevel@tonic-gate MIN_CHALLENGE_LENGTH); 8787c478bd9Sstevel@tonic-gate cstate->chal_len = chal_len; 8797c478bd9Sstevel@tonic-gate cstate->chal_id = ++cstate->id; 8807c478bd9Sstevel@tonic-gate cstate->chal_transmits = 0; 8817c478bd9Sstevel@tonic-gate 8827c478bd9Sstevel@tonic-gate /* XXX tack on saved get_first_hwaddr() here. */ 8837c478bd9Sstevel@tonic-gate 8847c478bd9Sstevel@tonic-gate /* generate a random string */ 8857c478bd9Sstevel@tonic-gate for (i = 0; i < chal_len; i++) 8867c478bd9Sstevel@tonic-gate *ptr++ = (char) (drand48() * 0xff); 8877c478bd9Sstevel@tonic-gate } 8887c478bd9Sstevel@tonic-gate 8897c478bd9Sstevel@tonic-gate /* 8907c478bd9Sstevel@tonic-gate * ChapSendResponse - send a response packet with values as specified 8917c478bd9Sstevel@tonic-gate * in *cstate. 8927c478bd9Sstevel@tonic-gate */ 8937c478bd9Sstevel@tonic-gate /* ARGSUSED */ 8947c478bd9Sstevel@tonic-gate static void 8957c478bd9Sstevel@tonic-gate ChapSendResponse(cstate) 8967c478bd9Sstevel@tonic-gate chap_state *cstate; 8977c478bd9Sstevel@tonic-gate { 8987c478bd9Sstevel@tonic-gate u_char *outp; 8997c478bd9Sstevel@tonic-gate int outlen, md_len, name_len; 9007c478bd9Sstevel@tonic-gate 9017c478bd9Sstevel@tonic-gate md_len = cstate->resp_length; 9027c478bd9Sstevel@tonic-gate name_len = strlen(cstate->resp_name); 9037c478bd9Sstevel@tonic-gate outlen = CHAP_HEADERLEN + sizeof (u_char) + md_len + name_len; 9047c478bd9Sstevel@tonic-gate outp = outpacket_buf; 9057c478bd9Sstevel@tonic-gate 9067c478bd9Sstevel@tonic-gate MAKEHEADER(outp, PPP_CHAP); 9077c478bd9Sstevel@tonic-gate 9087c478bd9Sstevel@tonic-gate PUTCHAR(CHAP_RESPONSE, outp); /* we are a response */ 9097c478bd9Sstevel@tonic-gate PUTCHAR(cstate->resp_id, outp); /* copy id from challenge packet */ 9107c478bd9Sstevel@tonic-gate PUTSHORT(outlen, outp); /* packet length */ 9117c478bd9Sstevel@tonic-gate 9127c478bd9Sstevel@tonic-gate PUTCHAR(md_len, outp); /* length of MD */ 9137c478bd9Sstevel@tonic-gate BCOPY(cstate->response, outp, md_len); /* copy MD to buffer */ 9147c478bd9Sstevel@tonic-gate INCPTR(md_len, outp); 9157c478bd9Sstevel@tonic-gate 9167c478bd9Sstevel@tonic-gate BCOPY(cstate->resp_name, outp, name_len); /* append our name */ 9177c478bd9Sstevel@tonic-gate 9187c478bd9Sstevel@tonic-gate /* send the packet */ 9197c478bd9Sstevel@tonic-gate output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN); 9207c478bd9Sstevel@tonic-gate 9217c478bd9Sstevel@tonic-gate cstate->clientstate = CHAPCS_RESPONSE; 9227c478bd9Sstevel@tonic-gate TIMEOUT(ChapResponseTimeout, cstate, cstate->timeouttime); 9237c478bd9Sstevel@tonic-gate ++cstate->resp_transmits; 9247c478bd9Sstevel@tonic-gate } 9257c478bd9Sstevel@tonic-gate 9267c478bd9Sstevel@tonic-gate /* 9277c478bd9Sstevel@tonic-gate * ChapPrintPkt - print the contents of a CHAP packet. 9287c478bd9Sstevel@tonic-gate */ 9297c478bd9Sstevel@tonic-gate static char *ChapCodenames[] = { 9307c478bd9Sstevel@tonic-gate "Challenge", "Response", "Success", "Failure" 9317c478bd9Sstevel@tonic-gate }; 9327c478bd9Sstevel@tonic-gate 9337c478bd9Sstevel@tonic-gate static int 9347c478bd9Sstevel@tonic-gate ChapPrintPkt(p, plen, printer, arg) 9357c478bd9Sstevel@tonic-gate u_char *p; 9367c478bd9Sstevel@tonic-gate int plen; 9377c478bd9Sstevel@tonic-gate void (*printer) __P((void *, const char *, ...)); 9387c478bd9Sstevel@tonic-gate void *arg; 9397c478bd9Sstevel@tonic-gate { 9407c478bd9Sstevel@tonic-gate int code, id, len; 9417c478bd9Sstevel@tonic-gate int clen, nlen; 9427c478bd9Sstevel@tonic-gate u_char x; 9437c478bd9Sstevel@tonic-gate 9447c478bd9Sstevel@tonic-gate if (plen < CHAP_HEADERLEN) 9457c478bd9Sstevel@tonic-gate return 0; 9467c478bd9Sstevel@tonic-gate GETCHAR(code, p); 9477c478bd9Sstevel@tonic-gate GETCHAR(id, p); 9487c478bd9Sstevel@tonic-gate GETSHORT(len, p); 9497c478bd9Sstevel@tonic-gate if (len < CHAP_HEADERLEN || len > plen) 9507c478bd9Sstevel@tonic-gate return 0; 9517c478bd9Sstevel@tonic-gate 9527c478bd9Sstevel@tonic-gate if (code >= 1 && code <= sizeof(ChapCodenames) / sizeof(char *)) 9537c478bd9Sstevel@tonic-gate printer(arg, " %s", ChapCodenames[code-1]); 9547c478bd9Sstevel@tonic-gate else 9557c478bd9Sstevel@tonic-gate printer(arg, " code=0x%x", code); 9567c478bd9Sstevel@tonic-gate printer(arg, " id=0x%x", id); 9577c478bd9Sstevel@tonic-gate len -= CHAP_HEADERLEN; 9587c478bd9Sstevel@tonic-gate switch (code) { 9597c478bd9Sstevel@tonic-gate case CHAP_CHALLENGE: 9607c478bd9Sstevel@tonic-gate case CHAP_RESPONSE: 9617c478bd9Sstevel@tonic-gate if (len < 1) 9627c478bd9Sstevel@tonic-gate break; 9637c478bd9Sstevel@tonic-gate clen = p[0]; 9647c478bd9Sstevel@tonic-gate if (len < clen + 1) 9657c478bd9Sstevel@tonic-gate break; 9667c478bd9Sstevel@tonic-gate ++p; 9677c478bd9Sstevel@tonic-gate nlen = len - clen - 1; 9687c478bd9Sstevel@tonic-gate printer(arg, " <"); 9697c478bd9Sstevel@tonic-gate for (; clen > 0; --clen) { 9707c478bd9Sstevel@tonic-gate GETCHAR(x, p); 9717c478bd9Sstevel@tonic-gate printer(arg, "%.2x", x); 9727c478bd9Sstevel@tonic-gate } 9737c478bd9Sstevel@tonic-gate printer(arg, ">, name = "); 9747c478bd9Sstevel@tonic-gate print_string((char *)p, nlen, printer, arg); 9757c478bd9Sstevel@tonic-gate break; 9767c478bd9Sstevel@tonic-gate case CHAP_FAILURE: 9777c478bd9Sstevel@tonic-gate case CHAP_SUCCESS: 9787c478bd9Sstevel@tonic-gate printer(arg, " "); 9797c478bd9Sstevel@tonic-gate print_string((char *)p, len, printer, arg); 9807c478bd9Sstevel@tonic-gate break; 9817c478bd9Sstevel@tonic-gate default: 9827c478bd9Sstevel@tonic-gate for (clen = len; clen > 0; --clen) { 9837c478bd9Sstevel@tonic-gate GETCHAR(x, p); 9847c478bd9Sstevel@tonic-gate printer(arg, " %.2x", x); 9857c478bd9Sstevel@tonic-gate } 9867c478bd9Sstevel@tonic-gate } 9877c478bd9Sstevel@tonic-gate 9887c478bd9Sstevel@tonic-gate return len + CHAP_HEADERLEN; 9897c478bd9Sstevel@tonic-gate } 990