From: David F. Skoll Date: Tue, 2 Apr 2002 13:55:00 +0000 (+0000) Subject: First large MPPE patch from Frank Cusack. X-Git-Tag: ppp-2.4.7~427 X-Git-Url: http://git.ozlabs.org/?p=ppp.git;a=commitdiff_plain;h=b38527fb14af5ebe3d2559e2f861575c722a1ce9 First large MPPE patch from Frank Cusack. --- diff --git a/README.MSCHAP81 b/README.MSCHAP81 index 1d415a9..c8e83f3 100644 --- a/README.MSCHAP81 +++ b/README.MSCHAP81 @@ -16,7 +16,7 @@ as plaintext-equivalent. (Well, the Change-Password packet is arguably an advantage.) It does introduce a significant weakness if the LM hash is used. Additionally, the format of the failure packet potentially gives information to an attacker. The weakness of the LM hash is partly -address in RFC 2433, which deprecates its use. +addressed in RFC 2433, which deprecates its use. MS-CHAPv2 adds 2 benefits to MS-CHAP. (1) The LM hash is no longer used. (2) Mutual authentication is required. Note that the mutual diff --git a/include/linux/ppp-comp.h b/include/linux/ppp-comp.h index 92aa645..091a575 100644 --- a/include/linux/ppp-comp.h +++ b/include/linux/ppp-comp.h @@ -24,11 +24,11 @@ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, * OR MODIFICATIONS. * - * $Id: ppp-comp.h,v 1.8 1999/07/23 06:53:40 paulus Exp $ + * $Id: ppp-comp.h,v 1.9 2002/04/02 13:54:59 dfs Exp $ */ /* - * ==FILEVERSION 980319== + * ==FILEVERSION 20020319== * * NOTE TO MAINTAINERS: * If you modify this file at all, please set the above date. @@ -186,6 +186,100 @@ struct compressor { + DEFLATE_METHOD_VAL) #define DEFLATE_CHK_SEQUENCE 0 +/* + * Definitions for MPPE. + */ + +#define CI_MPPE 18 /* config option for MPPE */ +#define CILEN_MPPE 6 /* length of config option */ + +#define MPPE_PAD 4 /* MPPE growth per frame */ +#define MPPE_MAX_KEY_LEN 16 /* largest key length (128-bit) */ + +/* option bits for ccp_options.mppe */ +#define MPPE_OPT_40 0x01 /* 40 bit */ +#define MPPE_OPT_128 0x02 /* 128 bit */ +#define MPPE_OPT_STATEFUL 0x04 /* stateful mode */ +/* unsupported opts */ +#define MPPE_OPT_56 0x08 /* 56 bit */ +#define MPPE_OPT_MPPC 0x10 /* MPPC compression */ +#define MPPE_OPT_D 0x20 /* Unknown */ +#define MPPE_OPT_UNSUPPORTED (MPPE_OPT_56|MPPE_OPT_MPPC|MPPE_OPT_D) +#define MPPE_OPT_UNKNOWN 0x40 /* Bits !defined in RFC 3078 were set */ + +/* + * This is not nice ... the alternative is a bitfield struct though. + * And unfortunately, we cannot share the same bits for the option + * names above since C and H are the same bit. We could do a u_int32 + * but then we have to do a htonl() all the time and/or we still need + * to know which octet is which. + */ +#define MPPE_C_BIT 0x01 /* MPPC */ +#define MPPE_D_BIT 0x10 /* Obsolete, usage unknown */ +#define MPPE_L_BIT 0x20 /* 40-bit */ +#define MPPE_S_BIT 0x40 /* 128-bit */ +#define MPPE_M_BIT 0x80 /* 56-bit, not supported */ +#define MPPE_H_BIT 0x01 /* Stateless (in a different byte) */ + +/* Does not include H bit; used for least significant octet only. */ +#define MPPE_ALL_BITS (MPPE_D_BIT|MPPE_L_BIT|MPPE_S_BIT|MPPE_M_BIT|MPPE_H_BIT) + +/* Build a CI from mppe opts (see RFC 3078) */ +#define MPPE_OPTS_TO_CI(opts, ci) \ + do { \ + u_char *ptr = ci; /* u_char[4] */ \ + \ + /* H bit */ \ + if (opts & MPPE_OPT_STATEFUL) \ + *ptr++ = 0x0; \ + else \ + *ptr++ = MPPE_H_BIT; \ + *ptr++ = 0; \ + *ptr++ = 0; \ + \ + /* S,L bits */ \ + *ptr = 0; \ + if (opts & MPPE_OPT_128) \ + *ptr |= MPPE_S_BIT; \ + if (opts & MPPE_OPT_40) \ + *ptr |= MPPE_L_BIT; \ + /* M,D,C bits not supported */ \ + } while (/* CONSTCOND */ 0) + +/* The reverse of the above */ +#define MPPE_CI_TO_OPTS(ci, opts) \ + do { \ + u_char *ptr = ci; /* u_char[4] */ \ + \ + opts = 0; \ + \ + /* H bit */ \ + if (!(ptr[0] & MPPE_H_BIT)) \ + opts |= MPPE_OPT_STATEFUL; \ + \ + /* S,L bits */ \ + if (ptr[3] & MPPE_S_BIT) \ + opts |= MPPE_OPT_128; \ + if (ptr[3] & MPPE_L_BIT) \ + opts |= MPPE_OPT_40; \ + \ + /* M,D,C bits */ \ + if (ptr[3] & MPPE_M_BIT) \ + opts |= MPPE_OPT_56; \ + if (ptr[3] & MPPE_D_BIT) \ + opts |= MPPE_OPT_D; \ + if (ptr[3] & MPPE_C_BIT) \ + opts |= MPPE_OPT_MPPC; \ + \ + /* Other bits */ \ + if (ptr[0] & ~MPPE_H_BIT) \ + opts |= MPPE_OPT_UNKNOWN; \ + if (ptr[1] || ptr[2]) \ + opts |= MPPE_OPT_UNKNOWN; \ + if (ptr[3] & ~MPPE_ALL_BITS) \ + opts |= MPPE_OPT_UNKNOWN; \ + } while (/* CONSTCOND */ 0) + /* * Definitions for other, as yet unsupported, compression methods. */ diff --git a/include/net/ppp-comp.h b/include/net/ppp-comp.h index fe62a61..10fc3bc 100644 --- a/include/net/ppp-comp.h +++ b/include/net/ppp-comp.h @@ -24,7 +24,7 @@ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, * OR MODIFICATIONS. * - * $Id: ppp-comp.h,v 1.11 1998/03/25 03:33:34 paulus Exp $ + * $Id: ppp-comp.h,v 1.12 2002/04/02 13:54:59 dfs Exp $ */ #ifndef _NET_PPP_COMP_H @@ -154,6 +154,99 @@ struct compressor { + DEFLATE_METHOD_VAL) #define DEFLATE_CHK_SEQUENCE 0 +/* + * Definitions for MPPE. + */ +#define CI_MPPE 18 /* config option for MPPE */ +#define CILEN_MPPE 6 /* length of config option */ + +#define MPPE_PAD 4 /* MPPE growth per frame */ +#define MPPE_MAX_KEY_LEN 16 /* largest key length (128-bit) */ + +/* option bits for ccp_options.mppe */ +#define MPPE_OPT_40 0x01 /* 40 bit */ +#define MPPE_OPT_128 0x02 /* 128 bit */ +#define MPPE_OPT_STATEFUL 0x04 /* stateful mode */ +/* unsupported opts */ +#define MPPE_OPT_56 0x08 /* 56 bit */ +#define MPPE_OPT_MPPC 0x10 /* MPPC compression */ +#define MPPE_OPT_D 0x20 /* Unknown */ +#define MPPE_OPT_UNSUPPORTED (MPPE_OPT_56|MPPE_OPT_MPPC|MPPE_OPT_D) +#define MPPE_OPT_UNKNOWN 0x40 /* Bits !defined in RFC 3078 were set */ + +/* + * This is not nice ... the alternative is a bitfield struct though. + * And unfortunately, we cannot share the same bits for the option + * names above since C and H are the same bit. We could do a u_int32 + * but then we have to do a htonl() all the time and/or we still need + * to know which octet is which. + */ +#define MPPE_C_BIT 0x01 /* MPPC */ +#define MPPE_D_BIT 0x10 /* Obsolete, usage unknown */ +#define MPPE_L_BIT 0x20 /* 40-bit */ +#define MPPE_S_BIT 0x40 /* 128-bit */ +#define MPPE_M_BIT 0x80 /* 56-bit, not supported */ +#define MPPE_H_BIT 0x01 /* Stateless (in a different byte) */ + +/* Does not include H bit; used for least significant octet only. */ +#define MPPE_ALL_BITS (MPPE_D_BIT|MPPE_L_BIT|MPPE_S_BIT|MPPE_M_BIT|MPPE_H_BIT) + +/* Build a CI from mppe opts (see RFC 3078) */ +#define MPPE_OPTS_TO_CI(opts, ci) \ + do { \ + u_char *ptr = ci; /* u_char[4] */ \ + \ + /* H bit */ \ + if (opts & MPPE_OPT_STATEFUL) \ + *ptr++ = 0x0; \ + else \ + *ptr++ = MPPE_H_BIT; \ + *ptr++ = 0; \ + *ptr++ = 0; \ + \ + /* S,L bits */ \ + *ptr = 0; \ + if (opts & MPPE_OPT_128) \ + *ptr |= MPPE_S_BIT; \ + if (opts & MPPE_OPT_40) \ + *ptr |= MPPE_L_BIT; \ + /* M,D,C bits not supported */ \ + } while (/* CONSTCOND */ 0) + +/* The reverse of the above */ +#define MPPE_CI_TO_OPTS(ci, opts) \ + do { \ + u_char *ptr = ci; /* u_char[4] */ \ + \ + opts = 0; \ + \ + /* H bit */ \ + if (!(ptr[0] & MPPE_H_BIT)) \ + opts |= MPPE_OPT_STATEFUL; \ + \ + /* S,L bits */ \ + if (ptr[3] & MPPE_S_BIT) \ + opts |= MPPE_OPT_128; \ + if (ptr[3] & MPPE_L_BIT) \ + opts |= MPPE_OPT_40; \ + \ + /* M,D,C bits */ \ + if (ptr[3] & MPPE_M_BIT) \ + opts |= MPPE_OPT_56; \ + if (ptr[3] & MPPE_D_BIT) \ + opts |= MPPE_OPT_D; \ + if (ptr[3] & MPPE_C_BIT) \ + opts |= MPPE_OPT_MPPC; \ + \ + /* Other bits */ \ + if (ptr[0] & ~MPPE_H_BIT) \ + opts |= MPPE_OPT_UNKNOWN; \ + if (ptr[1] || ptr[2]) \ + opts |= MPPE_OPT_UNKNOWN; \ + if (ptr[3] & ~MPPE_ALL_BITS) \ + opts |= MPPE_OPT_UNKNOWN; \ + } while (/* CONSTCOND */ 0) + /* * Definitions for other, as yet unsupported, compression methods. */ diff --git a/pppd/Makefile.linux b/pppd/Makefile.linux index aea5fb9..57b6b08 100644 --- a/pppd/Makefile.linux +++ b/pppd/Makefile.linux @@ -1,6 +1,6 @@ # # pppd makefile for Linux -# $Id: Makefile.linux,v 1.46 2002/03/05 15:14:04 dfs Exp $ +# $Id: Makefile.linux,v 1.47 2002/04/02 13:54:59 dfs Exp $ # # Default installation locations @@ -34,9 +34,12 @@ LIBS += -lcrypt endif # Uncomment the next 2 lines to include support for Microsoft's -# MS-CHAP authentication protocol. Also, edit plugins/radius/Makefile. +# MS-CHAP authentication protocol. Also, edit plugins/radius/Makefile.linux. CHAPMS=y USE_CRYPT=y +# Uncomment the next line to include support for MPPE. CHAPMS (above) must +# also be enabled. Also, edit plugins/radius/Makefile.linux. +MPPE=y ifneq ($(wildcard /usr/lib/libcrypt.*),) HAVE_CRYPT_H=y endif @@ -83,6 +86,9 @@ PPPDOBJS += md4.o chap_ms.o ifdef MSLANMAN CFLAGS += -DMSLANMAN=1 endif +ifdef MPPE +CFLAGS += -DMPPE=1 +endif endif ifdef HAS_SHADOW diff --git a/pppd/auth.c b/pppd/auth.c index 61b50e5..67f1278 100644 --- a/pppd/auth.c +++ b/pppd/auth.c @@ -32,7 +32,7 @@ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ -#define RCSID "$Id: auth.c,v 1.75 2002/03/05 15:14:04 dfs Exp $" +#define RCSID "$Id: auth.c,v 1.76 2002/04/02 13:54:59 dfs Exp $" #include #include @@ -91,6 +91,9 @@ char peer_authname[MAXNAMELEN]; /* Records which authentication operations haven't completed yet. */ static int auth_pending[NUM_PPP]; +/* Records which authentication operations have been completed. */ +int auth_done[NUM_PPP]; + /* Set if we have successfully called plogin() */ static int logged_in; @@ -184,12 +187,6 @@ char remote_name[MAXNAMELEN]; /* Peer's name for authentication */ static char *uafname; /* name of most recent +ua file */ -/* Bits in auth_pending[] */ -#define PAP_WITHPEER 1 -#define PAP_PEER 2 -#define CHAP_WITHPEER 4 -#define CHAP_PEER 8 - extern char *crypt __P((const char *, const char *)); /* Prototypes for procedures local to this file. */ @@ -552,6 +549,7 @@ link_established(unit) auth |= PAP_WITHPEER; } auth_pending[unit] = auth; + auth_done[unit] = 0; if (!auth) network_phase(unit); @@ -653,8 +651,8 @@ auth_peer_fail(unit, protocol) * The peer has been successfully authenticated using `protocol'. */ void -auth_peer_success(unit, protocol, name, namelen) - int unit, protocol; +auth_peer_success(unit, protocol, prot_flavor, name, namelen) + int unit, protocol, prot_flavor; char *name; int namelen; { @@ -663,6 +661,19 @@ auth_peer_success(unit, protocol, name, namelen) switch (protocol) { case PPP_CHAP: bit = CHAP_PEER; + switch (prot_flavor) { + case CHAP_DIGEST_MD5: + bit |= CHAP_MD5_PEER; + break; +#ifdef CHAPMS + case CHAP_MICROSOFT: + bit |= CHAP_MS_PEER; + break; + case CHAP_MICROSOFT_V2: + bit |= CHAP_MS2_PEER; + break; +#endif + } break; case PPP_PAP: bit = PAP_PEER; @@ -681,6 +692,9 @@ auth_peer_success(unit, protocol, name, namelen) peer_authname[namelen] = 0; script_setenv("PEERNAME", peer_authname, 0); + /* Save the authentication method for later. */ + auth_done[unit] |= bit; + /* * If there is no more authentication still to be done, * proceed to the network (or callback) phase. @@ -712,14 +726,27 @@ auth_withpeer_fail(unit, protocol) * We have successfully authenticated ourselves with the peer using `protocol'. */ void -auth_withpeer_success(unit, protocol) - int unit, protocol; +auth_withpeer_success(unit, protocol, prot_flavor) + int unit, protocol, prot_flavor; { int bit; switch (protocol) { case PPP_CHAP: bit = CHAP_WITHPEER; + switch (prot_flavor) { + case CHAP_DIGEST_MD5: + bit |= CHAP_MD5_WITHPEER; + break; +#ifdef CHAPMS + case CHAP_MICROSOFT: + bit |= CHAP_MS_WITHPEER; + break; + case CHAP_MICROSOFT_V2: + bit |= CHAP_MS2_WITHPEER; + break; +#endif + } break; case PPP_PAP: if (passwd_from_file) @@ -731,6 +758,9 @@ auth_withpeer_success(unit, protocol) bit = 0; } + /* Save the authentication method for later. */ + auth_done[unit] |= bit; + /* * If there is no more authentication still being done, * proceed to the network (or callback) phase. diff --git a/pppd/ccp.c b/pppd/ccp.c index 6cbdafd..fa8a5a0 100644 --- a/pppd/ccp.c +++ b/pppd/ccp.c @@ -25,7 +25,7 @@ * OR MODIFICATIONS. */ -#define RCSID "$Id: ccp.c,v 1.33 2002/03/06 15:00:30 dfs Exp $" +#define RCSID "$Id: ccp.c,v 1.34 2002/04/02 13:54:59 dfs Exp $" #include #include @@ -35,6 +35,11 @@ #include "ccp.h" #include +#ifdef MPPE +#include "chap_ms.h" /* mppe_xx_key */ +#include "lcp.h" /* lcp_close() */ +#endif + static const char rcsid[] = RCSID; /* @@ -54,6 +59,13 @@ static int setdeflate __P((char **)); static char bsd_value[8]; static char deflate_value[8]; +/* + * Option variables. + */ +#ifdef MPPE +bool refuse_mppe_stateful = 1; /* Allow stateful mode? */ +#endif + static option_t ccp_option_list[] = { { "noccp", o_bool, &ccp_protent.enabled_flag, "Disable CCP negotiation" }, @@ -93,6 +105,56 @@ static option_t ccp_option_list[] = { "don't allow Predictor-1", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR, &ccp_allowoptions[0].predictor_1 }, +#ifdef MPPE + /* MPPE options are symmetrical ... we only set wantoptions here */ + { "require-mppe", o_bool, &ccp_wantoptions[0].mppe, + "require MPPE encryption", + OPT_PRIO | MPPE_OPT_40 | MPPE_OPT_128 }, + { "+mppe", o_bool, &ccp_wantoptions[0].mppe, + "require MPPE encryption", + OPT_ALIAS | OPT_PRIO | MPPE_OPT_40 | MPPE_OPT_128 }, + { "nomppe", o_bool, &ccp_wantoptions[0].mppe, + "don't allow MPPE encryption", OPT_PRIO }, + { "-mppe", o_bool, &ccp_wantoptions[0].mppe, + "don't allow MPPE encryption", OPT_ALIAS | OPT_PRIO }, + + /* We use ccp_allowoptions[0].mppe as a junk var ... it is reset later */ + { "require-mppe-40", o_bool, &ccp_allowoptions[0].mppe, + "require MPPE 40-bit encryption", OPT_PRIO | OPT_A2OR | MPPE_OPT_40, + &ccp_wantoptions[0].mppe }, + { "+mppe-40", o_bool, &ccp_allowoptions[0].mppe, + "require MPPE 40-bit encryption", OPT_PRIO | OPT_A2OR | MPPE_OPT_40, + &ccp_wantoptions[0].mppe }, + { "nomppe-40", o_bool, &ccp_allowoptions[0].mppe, + "don't allow MPPE 40-bit encryption", + OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_40, &ccp_wantoptions[0].mppe }, + { "-mppe-40", o_bool, &ccp_allowoptions[0].mppe, + "don't allow MPPE 40-bit encryption", + OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_40, + &ccp_wantoptions[0].mppe }, + + { "require-mppe-128", o_bool, &ccp_allowoptions[0].mppe, + "require MPPE 128-bit encryption", OPT_PRIO | OPT_A2OR | MPPE_OPT_128, + &ccp_wantoptions[0].mppe }, + { "+mppe-128", o_bool, &ccp_allowoptions[0].mppe, + "require MPPE 128-bit encryption", + OPT_ALIAS | OPT_PRIO | OPT_A2OR | MPPE_OPT_128, + &ccp_wantoptions[0].mppe }, + { "nomppe-128", o_bool, &ccp_allowoptions[0].mppe, + "don't allow MPPE 128-bit encryption", + OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_128, &ccp_wantoptions[0].mppe }, + { "-mppe-128", o_bool, &ccp_allowoptions[0].mppe, + "don't allow MPPE 128-bit encryption", + OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_128, + &ccp_wantoptions[0].mppe }, + + /* strange one; we always request stateless, but will we allow stateful? */ + { "mppe-stateful", o_bool, &refuse_mppe_stateful, + "allow MPPE stateful mode", OPT_PRIO }, + { "nomppe-stateful", o_bool, &refuse_mppe_stateful, + "disallow MPPE stateful mode", OPT_PRIO | 1 }, +#endif /* MPPE */ + { NULL } }; @@ -175,7 +237,8 @@ static fsm_callbacks ccp_callbacks = { * Do we want / did we get any compression? */ #define ANY_COMPRESS(opt) ((opt).deflate || (opt).bsd_compress \ - || (opt).predictor_1 || (opt).predictor_2) + || (opt).predictor_1 || (opt).predictor_2 \ + || (opt).mppe) /* * Local state (mainly for handling reset-reqs and reset-acks). @@ -386,8 +449,15 @@ ccp_input(unit, p, len) */ oldstate = f->state; fsm_input(f, p, len); - if (oldstate == OPENED && p[0] == TERMREQ && f->state != OPENED) + if (oldstate == OPENED && p[0] == TERMREQ && f->state != OPENED) { notice("Compression disabled by peer."); +#ifdef MPPE + if (ccp_gotoptions[unit].mppe) { + notice("MPPE disabled, closing LCP"); + lcp_close(unit, "MPPE disabled by peer"); + } +#endif + } /* * If we get a terminate-ack and we're not asking for compression, @@ -450,15 +520,91 @@ ccp_resetci(f) fsm *f; { ccp_options *go = &ccp_gotoptions[f->unit]; - u_char opt_buf[16]; + u_char opt_buf[CCP_MAX_OPTION_LENGTH]; *go = ccp_wantoptions[f->unit]; all_rejected[f->unit] = 0; +#ifdef MPPE + if (go->mppe) { + ccp_options *ao = &ccp_allowoptions[f->unit]; + int auth_mschap_bits = auth_done[f->unit]; + int numbits; + + /* + * Start with a basic sanity check: mschap[v2] auth must be in + * exactly one direction. RFC 3079 says that the keys are + * 'derived from the credentials of the peer that initiated the call', + * however the PPP protocol doesn't have such a concept, and pppd + * cannot get this info externally. Instead we do the best we can. + * NB: If MPPE is required, all other compression opts are invalid. + * So, we return right away if we can't do it. + */ + + /* Leave only the mschap auth bits set */ + auth_mschap_bits &= ~(PAP_WITHPEER | PAP_PEER | + CHAP_WITHPEER | CHAP_PEER | + CHAP_MD5_WITHPEER | CHAP_MD5_PEER); + /* Count the mschap auths */ + numbits = 0; + do { + numbits += auth_mschap_bits & 1; + auth_mschap_bits >>= 1; + } while (auth_mschap_bits); + if (numbits > 1) { + error("MPPE required, but auth done in both directions."); + lcp_close(f->unit, "MPPE required but not available"); + return; + } + if (!numbits) { + error("MPPE required, but MS-CHAP[v2] auth not performed."); + lcp_close(f->unit, "MPPE required but not available"); + return; + } + + /* LM auth not supported for MPPE */ + if (auth_done[f->unit] & (CHAP_MS_WITHPEER | CHAP_MS_PEER)) { + /* This might be noise */ + if (go->mppe & MPPE_OPT_40) { + notice("Disabling 40-bit MPPE; MS-CHAP LM not supported"); + go->mppe &= ~MPPE_OPT_40; + } + } + + /* Last check: can we actually negotiate something? */ + if (!(go->mppe & (MPPE_OPT_40 | MPPE_OPT_128))) { + /* Could be misconfig, could be 40-bit disabled above. */ + error("MPPE required, but both 40-bit and 128-bit disabled."); + lcp_close(f->unit, "MPPE required but not available"); + return; + } + + /* sync options */ + ao->mppe = go->mppe; + /* MPPE is not compatible with other compression types */ + ao->bsd_compress = go->bsd_compress = 0; + ao->predictor_1 = go->predictor_1 = 0; + ao->predictor_2 = go->predictor_2 = 0; + ao->deflate = go->deflate = 0; + } +#endif /* MPPE */ + /* * Check whether the kernel knows about the various * compression methods we might request. */ +#ifdef MPPE + if (go->mppe) { + opt_buf[0] = CI_MPPE; + opt_buf[1] = CILEN_MPPE; + MPPE_OPTS_TO_CI(go->mppe, &opt_buf[2]); + /* Key material unimportant here. */ + if (ccp_test(f->unit, opt_buf, CILEN_MPPE + MPPE_MAX_KEY_LEN, 0) <= 0) { + error("MPPE required, but kernel has no support."); + lcp_close(f->unit, "MPPE required but not available"); + } + } +#endif if (go->bsd_compress) { opt_buf[0] = CI_BSD_COMPRESS; opt_buf[1] = CILEN_BSD_COMPRESS; @@ -512,7 +658,8 @@ ccp_cilen(f) return (go->bsd_compress? CILEN_BSD_COMPRESS: 0) + (go->deflate? CILEN_DEFLATE: 0) + (go->predictor_1? CILEN_PREDICTOR_1: 0) - + (go->predictor_2? CILEN_PREDICTOR_2: 0); + + (go->predictor_2? CILEN_PREDICTOR_2: 0) + + (go->mppe? CILEN_MPPE: 0); } /* @@ -530,21 +677,40 @@ ccp_addci(f, p, lenp) /* * Add the compression types that we can receive, in decreasing - * preference order. Get the kernel to allocate the first one - * in case it gets Acked. + * preference order. */ +#ifdef MPPE + if (go->mppe) { + u_char opt_buf[CILEN_MPPE + MPPE_MAX_KEY_LEN]; + + p[0] = opt_buf[0] = CI_MPPE; + p[1] = opt_buf[1] = CILEN_MPPE; + MPPE_OPTS_TO_CI(go->mppe, &p[2]); + MPPE_OPTS_TO_CI(go->mppe, &opt_buf[2]); + BCOPY(mppe_recv_key, &opt_buf[CILEN_MPPE], MPPE_MAX_KEY_LEN); + res = ccp_test(f->unit, opt_buf, CILEN_MPPE + MPPE_MAX_KEY_LEN, 0); + if (res > 0) + p += CILEN_MPPE; + else + /* This shouldn't happen, we've already tested it! */ + lcp_close(f->unit, "MPPE required but not available in kernel"); + } +#endif if (go->deflate) { p[0] = go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT; p[1] = CILEN_DEFLATE; p[2] = DEFLATE_MAKE_OPT(go->deflate_size); p[3] = DEFLATE_CHK_SEQUENCE; for (;;) { + if (go->deflate_size < DEFLATE_MIN_WORKS) { + go->deflate = 0; + break; + } res = ccp_test(f->unit, p, CILEN_DEFLATE, 0); if (res > 0) { p += CILEN_DEFLATE; break; - } - if (res < 0 || go->deflate_size <= DEFLATE_MIN_WORKS) { + } else if (res < 0) { go->deflate = 0; break; } @@ -563,22 +729,21 @@ ccp_addci(f, p, lenp) p[0] = CI_BSD_COMPRESS; p[1] = CILEN_BSD_COMPRESS; p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits); - if (p != p0) { - p += CILEN_BSD_COMPRESS; /* not the first option */ - } else { - for (;;) { - res = ccp_test(f->unit, p, CILEN_BSD_COMPRESS, 0); - if (res > 0) { - p += CILEN_BSD_COMPRESS; - break; - } - if (res < 0 || go->bsd_bits <= BSD_MIN_BITS) { - go->bsd_compress = 0; - break; - } - --go->bsd_bits; - p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits); + for (;;) { + if (go->bsd_bits < BSD_MIN_BITS) { + go->bsd_compress = 0; + break; + } + res = ccp_test(f->unit, p, CILEN_BSD_COMPRESS, 0); + if (res > 0) { + p += CILEN_BSD_COMPRESS; + break; + } else if (res < 0) { + go->bsd_compress = 0; + break; } + --go->bsd_bits; + p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits); } } /* XXX Should Predictor 2 be preferable to Predictor 1? */ @@ -619,6 +784,22 @@ ccp_ackci(f, p, len) ccp_options *go = &ccp_gotoptions[f->unit]; u_char *p0 = p; +#ifdef MPPE + if (go->mppe) { + u_char opt_buf[CILEN_MPPE]; + + opt_buf[0] = CI_MPPE; + opt_buf[1] = CILEN_MPPE; + MPPE_OPTS_TO_CI(go->mppe, &opt_buf[2]); + if (len < CILEN_MPPE || memcmp(opt_buf, p, CILEN_MPPE)) + return 0; + p += CILEN_MPPE; + len -= CILEN_MPPE; + /* XXX Cope with first/fast ack */ + if (len == 0) + return 1; + } +#endif if (go->deflate) { if (len < CILEN_DEFLATE || p[0] != (go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT) @@ -696,6 +877,25 @@ ccp_nakci(f, p, len) memset(&no, 0, sizeof(no)); try = *go; +#ifdef MPPE + if (go->mppe && len >= CILEN_MPPE + && p[0] == CI_MPPE && p[1] == CILEN_MPPE) { + no.mppe = 1; + /* + * Peer wants us to use a different strength or other setting. + * Fail if we aren't willing to use his suggestion. + */ + MPPE_CI_TO_OPTS(&p[2], try.mppe); + if ((try.mppe & MPPE_OPT_STATEFUL) && refuse_mppe_stateful) + try.mppe = 0; + else if ((go->mppe & try.mppe) != try.mppe) + /* Peer must have set options we didn't request (suggest) */ + try.mppe = 0; + + if (!try.mppe) + lcp_close(f->unit, "MPPE required but peer negotiation failed"); + } +#endif /* MPPE */ if (go->deflate && len >= CILEN_DEFLATE && p[0] == (go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT) && p[1] == CILEN_DEFLATE) { @@ -767,6 +967,14 @@ ccp_rejci(f, p, len) if (len == 0 && all_rejected[f->unit]) return -1; +#ifdef MPPE + if (go->mppe && len >= CILEN_MPPE + && p[0] == CI_MPPE && p[1] == CILEN_MPPE) { + lcp_close(f->unit, "MPPE required but peer refused"); + p += CILEN_MPPE; + len -= CILEN_MPPE; + } +#endif if (go->deflate && len >= CILEN_DEFLATE && p[0] == (go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT) && p[1] == CILEN_DEFLATE) { @@ -859,6 +1067,100 @@ ccp_reqci(f, p, lenp, dont_nak) clen = p[1]; switch (type) { +#ifdef MPPE + case CI_MPPE: + if (!ao->mppe || clen != CILEN_MPPE) { + newret = CONFREJ; + break; + } + MPPE_CI_TO_OPTS(&p[2], ho->mppe); + + /* Nak if anything unsupported or unknown are set. */ + if (ho->mppe & MPPE_OPT_UNSUPPORTED) { + newret = CONFNAK; + ho->mppe &= ~MPPE_OPT_UNSUPPORTED; + } + if (ho->mppe & MPPE_OPT_UNKNOWN) { + newret = CONFNAK; + ho->mppe &= ~MPPE_OPT_UNKNOWN; + } + + /* Check state opt */ + if (ho->mppe & MPPE_OPT_STATEFUL) { + if (refuse_mppe_stateful) { + /* + * We can Nak and request stateless, but it's a + * lot easier to just assume the peer will request + * it if he can do it; stateful mode is bad over + * the Internet -- which is where we expect MPPE. + */ + newret = CONFREJ; + break; + } else { + newret = CONFNAK; + } + } + + /* Find out which of {S,L} are set. */ + if ((ho->mppe & MPPE_OPT_128) + && (ho->mppe & MPPE_OPT_40)) { + /* Both are set, negotiate the strongest. */ + newret = CONFNAK; + if (ao->mppe & MPPE_OPT_128) + ho->mppe &= ~MPPE_OPT_40; + else if (ao->mppe & MPPE_OPT_40) + ho->mppe &= ~MPPE_OPT_128; + else { + newret = CONFREJ; + break; + } + } else if (ho->mppe & MPPE_OPT_128) { + if (!(ao->mppe & MPPE_OPT_128)) { + newret = CONFREJ; + break; + } + } else if (ho->mppe & MPPE_OPT_40) { + if (!(ao->mppe & MPPE_OPT_40)) { + newret = CONFREJ; + break; + } + } else { + /* Neither are set. */ + newret = CONFREJ; + break; + } + + /* rebuild the opts */ + MPPE_OPTS_TO_CI(ho->mppe, &p[2]); + if (newret == CONFACK) { + u_char opt_buf[CILEN_MPPE + MPPE_MAX_KEY_LEN]; + int mtu; + + BCOPY(p, opt_buf, CILEN_MPPE); + BCOPY(mppe_send_key, &opt_buf[CILEN_MPPE], + MPPE_MAX_KEY_LEN); + if (ccp_test(f->unit, opt_buf, + CILEN_MPPE + MPPE_MAX_KEY_LEN, 1) <= 0) { + /* This shouldn't happen, we've already tested it! */ + error("MPPE required, but kernel has no support."); + lcp_close(f->unit, "MPPE required but not available"); + newret = CONFREJ; + break; + } + /* + * We need to decrease the interface MTU by MPPE_PAD + * because MPPE frames **grow**. The kernel [must] + * allocate MPPE_PAD extra bytes in xmit buffers. + */ + mtu = netif_get_mtu(f->unit); + if (mtu) + netif_set_mtu(f->unit, mtu - MPPE_PAD); + else + newret = CONFREJ; + } + + break; +#endif /* MPPE */ case CI_DEFLATE: case CI_DEFLATE_DRAFT: if (!ao->deflate || clen != CILEN_DEFLATE @@ -1000,6 +1302,8 @@ ccp_reqci(f, p, lenp, dont_nak) else *lenp = retp - p0; } + if (ret == CONFREJ && ao->mppe) + lcp_close(f->unit, "MPPE required but peer negotiation failed"); return ret; } @@ -1015,6 +1319,30 @@ method_name(opt, opt2) if (!ANY_COMPRESS(*opt)) return "(none)"; switch (opt->method) { +#ifdef MPPE + case CI_MPPE: + { + char *p = result; + char *q = result + sizeof(result); /* 1 past result */ + + slprintf(p, q - p, "MPPE "); + p += 5; + if (opt->mppe & MPPE_OPT_128) { + slprintf(p, q - p, "128-bit "); + p += 8; + } + if (opt->mppe & MPPE_OPT_40) { + slprintf(p, q - p, "40-bit "); + p += 7; + } + if (opt->mppe & MPPE_OPT_STATEFUL) + slprintf(p, q - p, "stateful"); + else + slprintf(p, q - p, "stateless"); + + break; + } +#endif case CI_DEFLATE: case CI_DEFLATE_DRAFT: if (opt2 != NULL && opt2->deflate_size != opt->deflate_size) @@ -1138,6 +1466,24 @@ ccp_printpkt(p, plen, printer, arg) len -= optlen; optend = p + optlen; switch (code) { +#ifdef MPPE + case CI_MPPE: + if (optlen >= CILEN_MPPE) { + u_char mppe_opts; + + MPPE_CI_TO_OPTS(&p[2], mppe_opts); + printer(arg, "mppe %s %s %s %s %s %s%s", + (p[2] & MPPE_H_BIT)? "+H": "-H", + (p[5] & MPPE_M_BIT)? "+M": "-M", + (p[5] & MPPE_S_BIT)? "+S": "-S", + (p[5] & MPPE_L_BIT)? "+L": "-L", + (p[5] & MPPE_D_BIT)? "+D": "-D", + (p[5] & MPPE_C_BIT)? "+C": "-C", + (mppe_opts & MPPE_OPT_UNKNOWN)? " +U": ""); + p += CILEN_MPPE; + } + break; +#endif case CI_DEFLATE: case CI_DEFLATE_DRAFT: if (optlen >= CILEN_DEFLATE) { @@ -1222,6 +1568,15 @@ ccp_datainput(unit, pkt, len) */ error("Lost compression sync: disabling compression"); ccp_close(unit, "Lost compression sync"); +#ifdef MPPE + /* + * If we were doing MPPE, we must also take the link down. + */ + if (ccp_gotoptions[unit].mppe) { + error("Too many MPPE errors, closing LCP"); + lcp_close(unit, "Too many MPPE errors"); + } +#endif } else { /* * Send a reset-request to reset the peer's compressor. diff --git a/pppd/ccp.h b/pppd/ccp.h index c28a5b8..f796995 100644 --- a/pppd/ccp.h +++ b/pppd/ccp.h @@ -24,7 +24,7 @@ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, * OR MODIFICATIONS. * - * $Id: ccp.h,v 1.9 1998/11/07 06:59:26 paulus Exp $ + * $Id: ccp.h,v 1.10 2002/04/02 13:54:59 dfs Exp $ */ typedef struct ccp_options { @@ -34,6 +34,7 @@ typedef struct ccp_options { bool predictor_2; /* do Predictor-2? */ bool deflate_correct; /* use correct code for deflate? */ bool deflate_draft; /* use draft RFC code for deflate? */ + bool mppe; /* do MPPE? */ u_short bsd_bits; /* # bits/code for BSD Compress */ u_short deflate_size; /* lg(window size) for Deflate */ short method; /* code for chosen compression method */ diff --git a/pppd/chap.c b/pppd/chap.c index 21b0280..114ed4d 100644 --- a/pppd/chap.c +++ b/pppd/chap.c @@ -33,7 +33,7 @@ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ -#define RCSID "$Id: chap.c,v 1.29 2002/03/05 15:14:04 dfs Exp $" +#define RCSID "$Id: chap.c,v 1.30 2002/04/02 13:54:59 dfs Exp $" /* * TODO: @@ -66,6 +66,14 @@ int (*chap_auth_hook) __P((char *user, static const char rcsid[] = RCSID; +#ifdef CHAPMS +/* For MPPE debug */ +/* Use "[]|}{?/><,`!2&&(" (sans quotes) for RFC 3079 MS-CHAPv2 test value */ +static char *mschap_challenge = NULL; +/* Use "!@\#$%^&*()_+:3|~" (sans quotes, backslash is to escape #) for ... */ +static char *mschap2_peer_challenge = NULL; +#endif + /* * Command-line options. */ @@ -79,6 +87,12 @@ static option_t chap_option_list[] = { #ifdef MSLANMAN { "ms-lanman", o_bool, &ms_lanman, "Use LanMan passwd when using MS-CHAP", 1 }, +#endif +#ifdef DEBUGMPPEKEY + { "mschap-challenge", o_string, &mschap_challenge, + "specify CHAP challenge" }, + { "mschap2-peer-challenge", o_string, &mschap2_peer_challenge, + "specify CHAP peer challenge" }, #endif { NULL } }; @@ -490,8 +504,11 @@ ChapReceiveChallenge(cstate, inp, id, len) break; case CHAP_MICROSOFT_V2: - ChapMS2(cstate, rchallenge, NULL, cstate->resp_name, secret, secret_len, - (MS_Chap2Response *) cstate->response, cstate->earesponse); + ChapMS2(cstate, rchallenge, + mschap2_peer_challenge? mschap2_peer_challenge: NULL, + cstate->resp_name, secret, secret_len, + (MS_Chap2Response *) cstate->response, cstate->earesponse, + MS_CHAP2_AUTHENTICATEE); cstate->resp_length = MS_CHAP2_RESPONSE_LEN; break; #endif /* CHAPMS */ @@ -649,7 +666,7 @@ ChapReceiveResponse(cstate, inp, id, len) ChapMS2(cstate, cstate->challenge, rmd->PeerChallenge, (explicit_remote? remote_name: rhostname), secret, secret_len, &md, - cstate->saresponse); + cstate->saresponse, MS_CHAP2_AUTHENTICATOR); /* compare MDs and send the appropriate status */ if (memcmp(md.NTResp, rmd->NTResp, sizeof(md.NTResp)) == 0) @@ -671,7 +688,8 @@ ChapReceiveResponse(cstate, inp, id, len) old_state = cstate->serverstate; cstate->serverstate = CHAPSS_OPEN; if (old_state == CHAPSS_INITIAL_CHAL) { - auth_peer_success(cstate->unit, PPP_CHAP, rhostname, len); + auth_peer_success(cstate->unit, PPP_CHAP, cstate->chal_type, + rhostname, len); } if (cstate->chal_interval != 0) TIMEOUT(ChapRechallenge, cstate, cstate->chal_interval); @@ -746,7 +764,7 @@ ChapReceiveSuccess(cstate, inp, id, len) cstate->clientstate = CHAPCS_OPEN; - auth_withpeer_success(cstate->unit, PPP_CHAP); + auth_withpeer_success(cstate->unit, PPP_CHAP, cstate->resp_type); } @@ -786,7 +804,7 @@ ChapReceiveFailure(cstate, inp, id, len) #ifdef CHAPMS if ((cstate->resp_type == CHAP_MICROSOFT_V2) || (cstate->resp_type == CHAP_MICROSOFT)) { - long error; + int error; /* * Deal with MS-CHAP formatted failure messages; just print the @@ -794,7 +812,7 @@ ChapReceiveFailure(cstate, inp, id, len) * to use M=, but it shouldn't hurt. See ChapSendStatus(). */ if (!strncmp(p, "E=", 2)) - error = strtol(p, NULL, 10); /* Remember the error code. */ + error = (int) strtol(p, NULL, 10); /* Remember the error code. */ else goto print_msg; /* Message is badly formatted. */ @@ -803,7 +821,7 @@ ChapReceiveFailure(cstate, inp, id, len) p += 3; } else { /* No M=; use the error code. */ - switch(error - MS_CHAP_ERROR_BASE) { + switch(error) { case MS_CHAP_ERROR_RESTRICTED_LOGON_HOURS: p = "Restricted logon hours"; break; @@ -1023,9 +1041,15 @@ ChapGenChallenge(cstate) cstate->chal_id = ++cstate->id; cstate->chal_transmits = 0; - /* generate a random string */ - for (i = 0; i < chal_len; i++) - *ptr++ = (char) (drand48() * 0xff); +#ifdef CHAPMS + if (mschap_challenge) + for (i = 0; i < chal_len; i++) + *ptr++ = mschap_challenge[i]; + else +#endif + /* generate a random string */ + for (i = 0; i < chal_len; i++) + *ptr++ = (char) (drand48() * 0xff); } /* diff --git a/pppd/chap_ms.c b/pppd/chap_ms.c index d10b99a..318c0b6 100644 --- a/pppd/chap_ms.c +++ b/pppd/chap_ms.c @@ -34,11 +34,13 @@ /* * Modifications by Frank Cusack, frank@google.com, March 2002. * - * Implemented MS-CHAPv2 functionality. Heavily based on - * sample implementation in RFC 2759. + * Implemented MS-CHAPv2 functionality, heavily based on sample + * implementation in RFC 2759. Implemented MPPE functionality, + * heavily based on sample implementation in RFC 3079. + * Copyright (c) 2002 Google, Inc. */ -#define RCSID "$Id: chap_ms.c,v 1.18 2002/03/05 15:14:04 dfs Exp $" +#define RCSID "$Id: chap_ms.c,v 1.19 2002/04/02 13:54:59 dfs Exp $" #ifdef CHAPMS @@ -88,6 +90,11 @@ static void Expand __P((u_char *, u_char *)); static void Collapse __P((u_char *, u_char *)); #endif +#ifdef MPPE +static void Set_Start_Key __P((u_char *, char *, int)); +static void SetMasterKeys __P((char *, int, u_char[24], int)); +#endif + extern double drand48 __P((void)); #ifdef MSLANMAN @@ -95,6 +102,11 @@ bool ms_lanman = 0; /* Use LanMan password instead of NT */ /* Has meaning only with MS-CHAP challenges */ #endif +#ifdef MPPE +u_char mppe_send_key[MPPE_MAX_KEY_LEN]; +u_char mppe_recv_key[MPPE_MAX_KEY_LEN]; +#endif + static void ChallengeResponse(u_char *challenge, u_char PasswordHash[MD4_SIGNATURE_SIZE], @@ -356,16 +368,16 @@ GenerateAuthenticatorResponse(char *secret, int secret_len, * "Magic" constants used in response generation, from RFC 2759. */ u_char Magic1[39] = /* "Magic server to client signing constant" */ - {0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65, - 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67, - 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74}; + { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65, + 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67, + 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 }; u_char Magic2[41] = /* "Pad to make it do more than one iteration" */ - {0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B, - 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F, - 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E, - 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F, - 0x6E}; + { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B, + 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F, + 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E, + 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F, + 0x6E }; int i; SHA1_CTX sha1Context; @@ -400,6 +412,148 @@ GenerateAuthenticatorResponse(char *secret, int secret_len, } +#ifdef MPPE +/* + * Set mppe_xxxx_key from the NTPasswordHashHash. + * RFC 2548 (RADIUS support) requires us to export this function (ugh). + */ +void +mppe_set_keys(u_char *rchallenge, u_char PasswordHashHash[MD4_SIGNATURE_SIZE]) +{ + SHA1_CTX sha1Context; + u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */ + + SHA1_Init(&sha1Context); + SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE); + SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE); + SHA1_Update(&sha1Context, rchallenge, 8); + SHA1_Final(Digest, &sha1Context); + + /* Same key in both directions. */ + BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key)); + BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key)); +} + +/* + * Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079) + */ +static void +Set_Start_Key(u_char *rchallenge, char *secret, int secret_len) +{ + u_char unicodePassword[MAX_NT_PASSWORD * 2]; + u_char PasswordHash[MD4_SIGNATURE_SIZE]; + u_char PasswordHashHash[MD4_SIGNATURE_SIZE]; + + /* Hash (x2) the Unicode version of the secret (== password). */ + ascii2unicode(secret, secret_len, unicodePassword); + NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); + NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash); + + mppe_set_keys(rchallenge, PasswordHashHash); +} + +/* + * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079) + */ +static void +SetMasterKeys(char *secret, int secret_len, u_char NTResponse[24], int IsServer) +{ + SHA1_CTX sha1Context; + u_char unicodePassword[MAX_NT_PASSWORD * 2]; + u_char PasswordHash[MD4_SIGNATURE_SIZE]; + u_char PasswordHashHash[MD4_SIGNATURE_SIZE]; + u_char MasterKey[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */ + u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */ + + u_char SHApad1[40] = + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + u_char SHApad2[40] = + { 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, + 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, + 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, + 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 }; + + /* "This is the MPPE Master Key" */ + u_char Magic1[27] = + { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d, + 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 }; + /* "On the client side, this is the send key; " + "on the server side, it is the receive key." */ + u_char Magic2[84] = + { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, + 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79, + 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65, + 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, + 0x6b, 0x65, 0x79, 0x2e }; + /* "On the client side, this is the receive key; " + "on the server side, it is the send key." */ + u_char Magic3[84] = + { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, + 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, + 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, + 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, + 0x6b, 0x65, 0x79, 0x2e }; + u_char *s; + + /* Hash (x2) the Unicode version of the secret (== password). */ + ascii2unicode(secret, secret_len, unicodePassword); + NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); + NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash); + + SHA1_Init(&sha1Context); + SHA1_Update(&sha1Context, PasswordHashHash, sizeof(PasswordHashHash)); + SHA1_Update(&sha1Context, NTResponse, 24); + SHA1_Update(&sha1Context, Magic1, sizeof(Magic1)); + SHA1_Final(MasterKey, &sha1Context); + + /* + * generate send key + */ + if (IsServer) + s = Magic3; + else + s = Magic2; + SHA1_Init(&sha1Context); + SHA1_Update(&sha1Context, MasterKey, 16); + SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1)); + SHA1_Update(&sha1Context, s, 84); + SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2)); + SHA1_Final(Digest, &sha1Context); + + BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key)); + + /* + * generate recv key + */ + if (IsServer) + s = Magic2; + else + s = Magic3; + SHA1_Init(&sha1Context); + SHA1_Update(&sha1Context, MasterKey, 16); + SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1)); + SHA1_Update(&sha1Context, s, 84); + SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2)); + SHA1_Final(Digest, &sha1Context); + + BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key)); +} + +#endif /* MPPE */ + + void ChapMS(chap_state *cstate, u_char *rchallenge, char *secret, int secret_len, MS_ChapResponse *response) @@ -407,7 +561,7 @@ ChapMS(chap_state *cstate, u_char *rchallenge, char *secret, int secret_len, #if 0 CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'", secret_len, secret)); #endif - BZERO(response, sizeof(response)); + BZERO(response, sizeof(*response)); /* Calculate both always */ ChapMS_NT(rchallenge, secret, secret_len, response->NTResp); @@ -421,6 +575,9 @@ ChapMS(chap_state *cstate, u_char *rchallenge, char *secret, int secret_len, response->UseNT[0] = 1; #endif +#ifdef MPPE + Set_Start_Key(rchallenge, secret, secret_len); +#endif } @@ -428,7 +585,8 @@ ChapMS(chap_state *cstate, u_char *rchallenge, char *secret, int secret_len, * If PeerChallenge is NULL, one is generated and response->PeerChallenge * is filled in. Call this way when generating a response. * If PeerChallenge is supplied, it is copied into response->PeerChallenge. - * Call this way when verifying a response. + * Call this way when verifying a response (or debugging). + * Do not call with PeerChallenge = response->PeerChallenge. * * response->PeerChallenge is then used for calculation of the * Authenticator Response. @@ -436,12 +594,13 @@ ChapMS(chap_state *cstate, u_char *rchallenge, char *secret, int secret_len, void ChapMS2(chap_state *cstate, u_char *rchallenge, u_char *PeerChallenge, char *user, char *secret, int secret_len, MS_Chap2Response *response, - u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1]) + u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1], int authenticator) { + /* ARGSUSED */ u_char *p = response->PeerChallenge; int i; - BZERO(response, sizeof(response)); + BZERO(response, sizeof(*response)); /* Generate the Peer-Challenge if requested, or copy it if supplied. */ if (!PeerChallenge) @@ -459,6 +618,9 @@ ChapMS2(chap_state *cstate, u_char *rchallenge, u_char *PeerChallenge, GenerateAuthenticatorResponse(secret, secret_len, response->NTResp, response->PeerChallenge, rchallenge, user, authResponse); +#ifdef MPPE + SetMasterKeys(secret, secret_len, response->NTResp, authenticator); +#endif } diff --git a/pppd/chap_ms.h b/pppd/chap_ms.h index a8a1395..ec69586 100644 --- a/pppd/chap_ms.h +++ b/pppd/chap_ms.h @@ -19,7 +19,7 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: chap_ms.h,v 1.5 2002/03/05 15:14:04 dfs Exp $ + * $Id: chap_ms.h,v 1.6 2002/04/02 13:54:59 dfs Exp $ */ #ifndef __CHAPMS_INCLUDE__ @@ -30,17 +30,13 @@ #define MS_CHAP_RESPONSE_LEN 49 /* Response length for MS-CHAP */ #define MS_CHAP2_RESPONSE_LEN 49 /* Response length for MS-CHAPv2 */ -/* - * E=eeeeeeeeee error codes for MS-CHAP failure messages. - * Offset by 646 (the minimum code) for switch() handling on older compilers. - */ -#define MS_CHAP_ERROR_BASE 646 -#define MS_CHAP_ERROR_RESTRICTED_LOGON_HOURS (646 - MS_CHAP_ERROR_BASE) -#define MS_CHAP_ERROR_ACCT_DISABLED (647 - MS_CHAP_ERROR_BASE) -#define MS_CHAP_ERROR_PASSWD_EXPIRED (648 - MS_CHAP_ERROR_BASE) -#define MS_CHAP_ERROR_NO_DIALIN_PERMISSION (649 - MS_CHAP_ERROR_BASE) -#define MS_CHAP_ERROR_AUTHENTICATION_FAILURE (691 - MS_CHAP_ERROR_BASE) -#define MS_CHAP_ERROR_CHANGING_PASSWORD (709 - MS_CHAP_ERROR_BASE) +/* E=eeeeeeeeee error codes for MS-CHAP failure messages. */ +#define MS_CHAP_ERROR_RESTRICTED_LOGON_HOURS 646 +#define MS_CHAP_ERROR_ACCT_DISABLED 647 +#define MS_CHAP_ERROR_PASSWD_EXPIRED 648 +#define MS_CHAP_ERROR_NO_DIALIN_PERMISSION 649 +#define MS_CHAP_ERROR_AUTHENTICATION_FAILURE 691 +#define MS_CHAP_ERROR_CHANGING_PASSWORD 709 /* * Use MS_CHAP_RESPONSE_LEN, rather than sizeof(MS_ChapResponse), @@ -63,9 +59,23 @@ typedef struct { u_char Flags[1]; /* Must be zero */ } MS_Chap2Response; +#ifdef MPPE +#include /* MPPE_MAX_KEY_LEN */ +extern u_char mppe_send_key[MPPE_MAX_KEY_LEN]; +extern u_char mppe_recv_key[MPPE_MAX_KEY_LEN]; +#endif + +/* Are we the authenticator or authenticatee? For MS-CHAPv2 key derivation. */ +#define MS_CHAP2_AUTHENTICATEE 0 +#define MS_CHAP2_AUTHENTICATOR 1 + +#include "chap.h" /* chap_state, et al */ void ChapMS __P((chap_state *, u_char *, char *, int, MS_ChapResponse *)); void ChapMS2 __P((chap_state *, u_char *, u_char *, char *, char *, int, - MS_Chap2Response *, u_char[MS_AUTH_RESPONSE_LENGTH+1])); + MS_Chap2Response *, u_char[MS_AUTH_RESPONSE_LENGTH+1], int)); +#ifdef MPPE +void mppe_set_keys __P((u_char *, u_char[MD4_SIGNATURE_SIZE])); +#endif #define __CHAPMS_INCLUDE__ #endif /* __CHAPMS_INCLUDE__ */ diff --git a/pppd/options.c b/pppd/options.c index 3779b28..b20f075 100644 --- a/pppd/options.c +++ b/pppd/options.c @@ -17,7 +17,7 @@ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ -#define RCSID "$Id: options.c,v 1.82 2002/03/01 14:39:18 dfs Exp $" +#define RCSID "$Id: options.c,v 1.83 2002/04/02 13:54:59 dfs Exp $" #include #include @@ -627,6 +627,8 @@ process_option(opt, cmd, argv) *(bool *)(opt->addr2) = 0; else if (opt->addr2 && (opt->flags & OPT_A2CLRB)) *(u_char *)(opt->addr2) &= ~v; + else if (opt->addr2 && (opt->flags & OPT_A2OR)) + *(u_char *)(opt->addr2) |= v; if (opt->addr3 && (opt->flags & OPT_A3OR)) *(u_char *)(opt->addr3) |= v; break; @@ -730,7 +732,7 @@ process_option(opt, cmd, argv) } if (opt->addr2 && (opt->flags & (OPT_A2COPY|OPT_ENABLE - |OPT_A2PRINTER|OPT_A2STRVAL|OPT_A2LIST)) == 0) + |OPT_A2PRINTER|OPT_A2STRVAL|OPT_A2LIST|OPT_A2OR)) == 0) *(bool *)(opt->addr2) = !(opt->flags & OPT_A2CLR); mainopt->source = option_source; diff --git a/pppd/plugins/radius/radius.c b/pppd/plugins/radius/radius.c index 06f59ff..c36bdf7 100644 --- a/pppd/plugins/radius/radius.c +++ b/pppd/plugins/radius/radius.c @@ -21,7 +21,7 @@ * ***********************************************************************/ static char const RCSID[] = -"$Id: radius.c,v 1.7 2002/03/12 00:28:56 dfs Exp $"; +"$Id: radius.c,v 1.8 2002/04/02 13:55:00 dfs Exp $"; #include "pppd.h" #include "chap.h" diff --git a/pppd/pppd.8 b/pppd/pppd.8 index f6adc5d..6befb31 100644 --- a/pppd/pppd.8 +++ b/pppd/pppd.8 @@ -1,5 +1,5 @@ .\" manual page [] for pppd 2.4 -.\" $Id: pppd.8,v 1.61 2002/03/05 15:14:04 dfs Exp $ +.\" $Id: pppd.8,v 1.62 2002/04/02 13:54:59 dfs Exp $ .\" SH section heading .\" SS subsection heading .\" LP paragraph @@ -561,6 +561,10 @@ control, as for the \fIcrtscts\fR option. Enables the use of PPP multilink; this is an alias for the `multilink' option. This option is currently only available under Linux. .TP +.B mppe-stateful +Allow MPPE to use stateful mode. Stateless mode is still attempted first. +The default is to disallow stateful mode. +.TP .B mpshortseq Enables the use of short (12-bit) sequence numbers in multilink headers, as opposed to 24-bit sequence numbers. This option is only @@ -703,6 +707,18 @@ peer is buggy. Disables the use of PPP multilink. This option is currently only available under Linux. .TP +.B nomppe +Disables MPPE (Microsoft Point to Point Encryption). This is the default. +.TP +.B nomppe-40 +Disable 40\-bit encryption with MPPE. +.TP +.B nomppe-128 +Disable 128\-bit encryption with MPPE. +.TP +.B nomppe-stateful +Disabled MPPE stateful mode. This is the default. +.TP .B nompshortseq Disables the use of short (12-bit) sequence numbers in the PPP multilink protocol, forcing the use of 24-bit sequence numbers. This @@ -869,6 +885,18 @@ peer using PAP. Require the peer to authenticate itself using CHAP [Challenge Handshake Authentication Protocol] authentication. .TP +.B require-mppe +Require the use of MPPE (Microsoft Point to Point Encryption). This +option disables all other compression types. This option enables +both 40\-bit and 128\-bit encryption. In order for MPPE to successfully +come up, you must have authenticated with either MS-CHAP or MS-CHAPv2. +.TP +.B require-mppe-40 +Require the use of MPPE, with 40\-bit encryption. +.TP +.B require-mppe-128 +Require the use of MPPE, with 128\-bit encryption. +.TP .B require-mschap Require the peer to authenticate itself using MS-CHAP [Microsft Challenge Handshake Authentication Protocol] authentication. diff --git a/pppd/pppd.h b/pppd/pppd.h index d75a6fd..a9b780a 100644 --- a/pppd/pppd.h +++ b/pppd/pppd.h @@ -16,7 +16,7 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: pppd.h,v 1.66 2002/03/01 14:39:18 dfs Exp $ + * $Id: pppd.h,v 1.67 2002/04/02 13:54:59 dfs Exp $ */ /* @@ -95,6 +95,7 @@ typedef struct { #define OPT_NOARG 0x200 /* option doesn't take argument */ #define OPT_OR 0x400 /* OR in argument to value */ #define OPT_INC 0x800 /* increment value */ +#define OPT_A2OR 0x800 /* for o_bool, OR arg to *(u_char *)addr2 */ #define OPT_PRIV 0x1000 /* privileged option */ #define OPT_STATIC 0x2000 /* string option goes into static array */ #define OPT_LLIMIT 0x4000 /* check value against lower limit */ @@ -198,6 +199,7 @@ extern int baud_rate; /* Current link speed in bits/sec */ extern char *progname; /* Name of this program */ extern int redirect_stderr;/* Connector's stderr should go to file */ extern char peer_authname[];/* Authenticated name of peer */ +extern int auth_done[NUM_PPP]; /* Methods actually used for auth */ extern int privileged; /* We were run by real-uid root */ extern int need_holdoff; /* Need holdoff period after link terminates */ extern char **script_env; /* Environment variables for scripts */ @@ -295,6 +297,21 @@ extern bool ms_lanman; /* Use LanMan password instead of NT */ /* Has meaning only with MS-CHAP challenges */ #endif +/* Values for auth_pending, auth_done */ +#define PAP_WITHPEER 0x1 +#define PAP_PEER 0x2 +#define CHAP_WITHPEER 0x4 +#define CHAP_PEER 0x8 +/* Values for auth_done only */ +#define CHAP_MD5_WITHPEER 0x10 +#define CHAP_MD5_PEER 0x20 +#ifdef CHAPMS +#define CHAP_MS_WITHPEER 0x40 +#define CHAP_MS_PEER 0x80 +#define CHAP_MS2_WITHPEER 0x100 +#define CHAP_MS2_PEER 0x200 +#endif + extern char *current_option; /* the name of the option being parsed */ extern int privileged_option; /* set iff the current option came from root */ extern char *option_source; /* string saying where the option came from */ @@ -467,11 +484,11 @@ void np_down __P((int, int)); /* a network protocol has gone down */ void np_finished __P((int, int)); /* a network protocol no longer needs link */ void auth_peer_fail __P((int, int)); /* peer failed to authenticate itself */ -void auth_peer_success __P((int, int, char *, int)); +void auth_peer_success __P((int, int, int, char *, int)); /* peer successfully authenticated itself */ void auth_withpeer_fail __P((int, int)); /* we failed to authenticate ourselves */ -void auth_withpeer_success __P((int, int)); +void auth_withpeer_success __P((int, int, int)); /* we successfully authenticated ourselves */ void auth_check_options __P((void)); /* check authentication options supplied */ @@ -542,6 +559,7 @@ int get_idle_time __P((int, struct ppp_idle *)); int get_ppp_stats __P((int, struct pppd_stats *)); /* Return link statistics */ void netif_set_mtu __P((int, int)); /* Set PPP interface MTU */ +int netif_get_mtu __P((int)); /* Get PPP interface MTU */ int sifvjcomp __P((int, int, int, int)); /* Configure VJ TCP header compression */ int sifup __P((int)); /* Configure i/f up for one protocol */ diff --git a/pppd/sha1.c b/pppd/sha1.c index b56a7c9..b8701b4 100644 --- a/pppd/sha1.c +++ b/pppd/sha1.c @@ -20,6 +20,9 @@ #include /* htonl() */ #include "sha1.h" +static void +SHA1_Transform(unsigned long[5], const unsigned char[64]); + #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) /* blk0() and blk() perform the initial expand. */ @@ -38,7 +41,8 @@ /* Hash a single 512-bit block. This is the core of the algorithm. */ -void SHA1_Transform(unsigned long state[5], const unsigned char buffer[64]) +static void +SHA1_Transform(unsigned long state[5], const unsigned char buffer[64]) { unsigned long a, b, c, d, e; typedef union { @@ -94,7 +98,8 @@ void SHA1_Transform(unsigned long state[5], const unsigned char buffer[64]) /* SHA1Init - Initialize new context */ -void SHA1_Init(SHA1_CTX *context) +void +SHA1_Init(SHA1_CTX *context) { /* SHA1 initialization constants */ context->state[0] = 0x67452301; @@ -108,7 +113,8 @@ void SHA1_Init(SHA1_CTX *context) /* Run your data through this. */ -void SHA1_Update(SHA1_CTX *context, const unsigned char *data, unsigned int len) +void +SHA1_Update(SHA1_CTX *context, const unsigned char *data, unsigned int len) { unsigned int i, j; @@ -132,7 +138,8 @@ void SHA1_Update(SHA1_CTX *context, const unsigned char *data, unsigned int len) /* Add padding and return the message digest. */ -void SHA1_Final(unsigned char digest[20], SHA1_CTX *context) +void +SHA1_Final(unsigned char digest[20], SHA1_CTX *context) { unsigned long i, j; unsigned char finalcount[8]; diff --git a/pppd/sha1.h b/pppd/sha1.h index 6727afb..dff8da8 100644 --- a/pppd/sha1.h +++ b/pppd/sha1.h @@ -10,10 +10,9 @@ typedef struct { #define SHA1_SIGNATURE_SIZE 20 -void SHA1_Transform(unsigned long[5], const unsigned char[64]); -void SHA1_Init(SHA1_CTX *); -void SHA1_Update(SHA1_CTX *, const unsigned char *, unsigned int); -void SHA1_Final(unsigned char[20], SHA1_CTX *); +extern void SHA1_Init(SHA1_CTX *); +extern void SHA1_Update(SHA1_CTX *, const unsigned char *, unsigned int); +extern void SHA1_Final(unsigned char[SHA1_SIGNATURE_SIZE], SHA1_CTX *); #define __SHA1_INCLUDE_ #endif /* __SHA1_INCLUDE_ */ diff --git a/pppd/sys-linux.c b/pppd/sys-linux.c index 76fda67..5f40b06 100644 --- a/pppd/sys-linux.c +++ b/pppd/sys-linux.c @@ -1088,6 +1088,24 @@ netif_set_mtu(int unit, int mtu) error("ioctl(SIOCSIFMTU): %m (line %d)", __LINE__); } +/* + * netif_get_mtu - get the MTU on the PPP network interface. + */ +int +netif_get_mtu(int unit) +{ + struct ifreq ifr; + + memset (&ifr, '\0', sizeof (ifr)); + strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); + + if (ifunit >= 0 && ioctl(sock_fd, SIOCGIFMTU, (caddr_t) &ifr) < 0) { + error("ioctl(SIOCGIFMTU): %m (line %d)", __LINE__); + return 0; + } + return ifr.ifr_mtu; +} + /******************************************************************** * * tty_send_config - configure the transmit characteristics of @@ -1175,7 +1193,8 @@ void tty_recv_config (int mru,u_int32_t asyncmap,int pcomp,int accomp) * is acceptable for use. */ -int ccp_test (int unit, u_char *opt_ptr, int opt_len, int for_transmit) +int +ccp_test(int unit, u_char *opt_ptr, int opt_len, int for_transmit) { struct ppp_option_data data; diff --git a/pppd/upap.c b/pppd/upap.c index ad13e39..d3d9d9f 100644 --- a/pppd/upap.c +++ b/pppd/upap.c @@ -17,7 +17,7 @@ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ -#define RCSID "$Id: upap.c,v 1.24 2001/03/08 05:11:16 paulus Exp $" +#define RCSID "$Id: upap.c,v 1.25 2002/04/02 13:54:59 dfs Exp $" /* * TODO: @@ -409,7 +409,7 @@ upap_rauthreq(u, inp, id, len) if (retcode == UPAP_AUTHACK) { u->us_serverstate = UPAPSS_OPEN; - auth_peer_success(u->us_unit, PPP_PAP, ruser, ruserlen); + auth_peer_success(u->us_unit, PPP_PAP, 0, ruser, ruserlen); } else { u->us_serverstate = UPAPSS_BADAUTH; auth_peer_fail(u->us_unit, PPP_PAP); @@ -456,7 +456,7 @@ upap_rauthack(u, inp, id, len) u->us_clientstate = UPAPCS_OPEN; - auth_withpeer_success(u->us_unit, PPP_PAP); + auth_withpeer_success(u->us_unit, PPP_PAP, 0); }