X-Git-Url: http://git.ozlabs.org/?p=ppp.git;a=blobdiff_plain;f=pppd%2Fccp.c;h=8ff92f3be179b6824050a833a88d57afe712fca9;hp=05cca767093158ca9b61d95360803ac3d92aa7fc;hb=05c09ae62d0b4ff67fb26c37a01e6a07bb593c0c;hpb=1e7bc3ea35208555bf233daacee9d85ded13f999 diff --git a/pppd/ccp.c b/pppd/ccp.c index 05cca76..8ff92f3 100644 --- a/pppd/ccp.c +++ b/pppd/ccp.c @@ -25,9 +25,7 @@ * OR MODIFICATIONS. */ -#ifndef lint -static char rcsid[] = "$Id: ccp.c,v 1.26 1999/03/16 22:54:38 paulus Exp $"; -#endif +#define RCSID "$Id: ccp.c,v 1.37 2002/06/24 12:57:15 dfs Exp $" #include #include @@ -37,45 +35,126 @@ static char rcsid[] = "$Id: ccp.c,v 1.26 1999/03/16 22:54:38 paulus Exp $"; #include "ccp.h" #include +#ifdef MPPE +#include "chap_ms.h" /* mppe_xxxx_key */ +#include "lcp.h" /* lcp_close(), lcp_fsm */ +#endif + +static const char rcsid[] = RCSID; + +/* + * Unfortunately there is a bug in zlib which means that using a + * size of 8 (window size = 256) for Deflate compression will cause + * buffer overruns and kernel crashes in the deflate module. + * Until this is fixed we only accept sizes in the range 9 .. 15. + * Thanks to James Carlson for pointing this out. + */ +#define DEFLATE_MIN_WORKS 9 + /* * Command-line options. */ static int setbsdcomp __P((char **)); 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" }, { "-ccp", o_bool, &ccp_protent.enabled_flag, - "Disable CCP negotiation" }, - { "bsdcomp", o_special, setbsdcomp, - "Request BSD-Compress packet compression" }, + "Disable CCP negotiation", OPT_ALIAS }, + + { "bsdcomp", o_special, (void *)setbsdcomp, + "Request BSD-Compress packet compression", + OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, bsd_value }, { "nobsdcomp", o_bool, &ccp_wantoptions[0].bsd_compress, - "don't allow BSD-Compress", OPT_A2COPY, + "don't allow BSD-Compress", OPT_PRIOSUB | OPT_A2CLR, &ccp_allowoptions[0].bsd_compress }, { "-bsdcomp", o_bool, &ccp_wantoptions[0].bsd_compress, - "don't allow BSD-Compress", OPT_A2COPY, + "don't allow BSD-Compress", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR, &ccp_allowoptions[0].bsd_compress }, - { "deflate", 1, setdeflate, - "request Deflate compression" }, + + { "deflate", o_special, (void *)setdeflate, + "request Deflate compression", + OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, deflate_value }, { "nodeflate", o_bool, &ccp_wantoptions[0].deflate, - "don't allow Deflate compression", OPT_A2COPY, + "don't allow Deflate compression", OPT_PRIOSUB | OPT_A2CLR, &ccp_allowoptions[0].deflate }, { "-deflate", o_bool, &ccp_wantoptions[0].deflate, - "don't allow Deflate compression", OPT_A2COPY, + "don't allow Deflate compression", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR, &ccp_allowoptions[0].deflate }, + { "nodeflatedraft", o_bool, &ccp_wantoptions[0].deflate_draft, "don't use draft deflate #", OPT_A2COPY, &ccp_allowoptions[0].deflate_draft }, + { "predictor1", o_bool, &ccp_wantoptions[0].predictor_1, - "request Predictor-1", 1, &ccp_allowoptions[0].predictor_1 }, + "request Predictor-1", OPT_PRIO | 1 }, { "nopredictor1", o_bool, &ccp_wantoptions[0].predictor_1, - "don't allow Predictor-1", OPT_A2COPY, + "don't allow Predictor-1", OPT_PRIOSUB | OPT_A2CLR, &ccp_allowoptions[0].predictor_1 }, { "-predictor1", o_bool, &ccp_wantoptions[0].predictor_1, - "don't allow Predictor-1", OPT_A2COPY, + "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 } }; @@ -158,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). @@ -207,6 +287,9 @@ setbsdcomp(argv) ccp_allowoptions[0].bsd_bits = abits; } else ccp_allowoptions[0].bsd_compress = 0; + slprintf(bsd_value, sizeof(bsd_value), + rbits == abits? "%d": "%d,%d", rbits, abits); + return 1; } @@ -234,6 +317,14 @@ setdeflate(argv) DEFLATE_MIN_SIZE, DEFLATE_MAX_SIZE); return 0; } + if (rbits == DEFLATE_MIN_SIZE || abits == DEFLATE_MIN_SIZE) { + if (rbits == DEFLATE_MIN_SIZE) + rbits = DEFLATE_MIN_WORKS; + if (abits == DEFLATE_MIN_SIZE) + abits = DEFLATE_MIN_WORKS; + warn("deflate option value of %d changed to %d to avoid zlib bug", + DEFLATE_MIN_SIZE, DEFLATE_MIN_WORKS); + } if (rbits > 0) { ccp_wantoptions[0].deflate = 1; ccp_wantoptions[0].deflate_size = rbits; @@ -244,10 +335,12 @@ setdeflate(argv) ccp_allowoptions[0].deflate_size = abits; } else ccp_allowoptions[0].deflate = 0; + slprintf(deflate_value, sizeof(deflate_value), + rbits == abits? "%d": "%d,%d", rbits, abits); + return 1; } - /* * ccp_init - initialize CCP. */ @@ -356,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) { + error("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, @@ -410,6 +510,13 @@ ccp_protrej(unit) { ccp_flags_set(unit, 0, 0); fsm_lowerdown(&ccp_fsm[unit]); + +#ifdef MPPE + if (ccp_gotoptions[unit].mppe) + error("MPPE required but peer negotiation failed"); + lcp_close(unit, "MPPE required but peer negotiation failed"); +#endif + } /* @@ -420,15 +527,92 @@ 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 &= (CHAP_MS_WITHPEER | CHAP_MS_PEER | + CHAP_MS2_WITHPEER | CHAP_MS2_PEER); + /* Count the mschap auths */ + auth_mschap_bits >>= CHAP_MS_SHIFT; + 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; + ccp_wantoptions[f->unit].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; @@ -440,7 +624,7 @@ ccp_resetci(f) if (go->deflate_correct) { opt_buf[0] = CI_DEFLATE; opt_buf[1] = CILEN_DEFLATE; - opt_buf[2] = DEFLATE_MAKE_OPT(DEFLATE_MIN_SIZE); + opt_buf[2] = DEFLATE_MAKE_OPT(DEFLATE_MIN_WORKS); opt_buf[3] = DEFLATE_CHK_SEQUENCE; if (ccp_test(f->unit, opt_buf, CILEN_DEFLATE, 0) <= 0) go->deflate_correct = 0; @@ -448,7 +632,7 @@ ccp_resetci(f) if (go->deflate_draft) { opt_buf[0] = CI_DEFLATE_DRAFT; opt_buf[1] = CILEN_DEFLATE; - opt_buf[2] = DEFLATE_MAKE_OPT(DEFLATE_MIN_SIZE); + opt_buf[2] = DEFLATE_MAKE_OPT(DEFLATE_MIN_WORKS); opt_buf[3] = DEFLATE_CHK_SEQUENCE; if (ccp_test(f->unit, opt_buf, CILEN_DEFLATE, 0) <= 0) go->deflate_draft = 0; @@ -482,7 +666,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); } /* @@ -500,21 +685,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_SIZE) { + } else if (res < 0) { go->deflate = 0; break; } @@ -533,22 +737,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? */ @@ -589,6 +792,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) @@ -666,6 +885,27 @@ 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) { + error("MPPE required but peer negotiation failed"); + 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) { @@ -675,7 +915,7 @@ ccp_nakci(f, p, len) * Stop asking for Deflate if we don't understand his suggestion. */ if (DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL - || DEFLATE_SIZE(p[2]) < DEFLATE_MIN_SIZE + || DEFLATE_SIZE(p[2]) < DEFLATE_MIN_WORKS || p[3] != DEFLATE_CHK_SEQUENCE) try.deflate = 0; else if (DEFLATE_SIZE(p[2]) < go->deflate_size) @@ -708,12 +948,9 @@ ccp_nakci(f, p, len) /* * Predictor-1 and 2 have no options, so they can't be Naked. * - * XXX What should we do with any remaining options? + * There may be remaining options but we ignore them. */ - if (len != 0) - return 0; - if (f->state != OPENED) *go = try; return 1; @@ -740,6 +977,15 @@ 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) { + error("MPPE required but peer refused"); + 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) { @@ -812,6 +1058,9 @@ ccp_reqci(f, p, lenp, dont_nak) int len, clen, type, nb; ccp_options *ho = &ccp_hisoptions[f->unit]; ccp_options *ao = &ccp_allowoptions[f->unit]; +#ifdef MPPE + bool seen_ci_mppe = 0; +#endif ret = CONFACK; retp = p0 = p; @@ -832,6 +1081,101 @@ 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; + } + seen_ci_mppe = 1; + 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 @@ -845,7 +1189,7 @@ ccp_reqci(f, p, lenp, dont_nak) ho->deflate_size = nb = DEFLATE_SIZE(p[2]); if (DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL || p[3] != DEFLATE_CHK_SEQUENCE - || nb > ao->deflate_size || nb < DEFLATE_MIN_SIZE) { + || nb > ao->deflate_size || nb < DEFLATE_MIN_WORKS) { newret = CONFNAK; if (!dont_nak) { p[2] = DEFLATE_MAKE_OPT(ao->deflate_size); @@ -866,7 +1210,7 @@ ccp_reqci(f, p, lenp, dont_nak) res = ccp_test(f->unit, p, CILEN_DEFLATE, 1); if (res > 0) break; /* it's OK now */ - if (res < 0 || nb == DEFLATE_MIN_SIZE || dont_nak) { + if (res < 0 || nb == DEFLATE_MIN_WORKS || dont_nak) { newret = CONFREJ; p[2] = DEFLATE_MAKE_OPT(ho->deflate_size); break; @@ -973,6 +1317,12 @@ ccp_reqci(f, p, lenp, dont_nak) else *lenp = retp - p0; } +#ifdef MPPE + if (ret == CONFREJ && ao->mppe && !seen_ci_mppe) { + error("MPPE required but peer negotiation failed"); + lcp_close(f->unit, "MPPE required but peer negotiation failed"); + } +#endif return ret; } @@ -988,6 +1338,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) @@ -1034,7 +1408,7 @@ ccp_up(f) if (go->method == ho->method) { notice("%s compression enabled", method_name(go, ho)); } else { - strlcpy(method1, sizeof(method1), method_name(go, NULL)); + strlcpy(method1, method_name(go, NULL), sizeof(method1)); notice("%s / %s compression enabled", method1, method_name(ho, NULL)); } @@ -1042,6 +1416,13 @@ ccp_up(f) notice("%s receive compression enabled", method_name(go, NULL)); } else if (ANY_COMPRESS(*ho)) notice("%s transmit compression enabled", method_name(ho, NULL)); +#ifdef MPPE + if (go->mppe) { + BZERO(mppe_recv_key, MPPE_MAX_KEY_LEN); + BZERO(mppe_send_key, MPPE_MAX_KEY_LEN); + start_networks(f->unit); /* Bring up IP et al */ + } +#endif } /* @@ -1055,6 +1436,16 @@ ccp_down(f) UNTIMEOUT(ccp_rack_timeout, f); ccp_localstate[f->unit] = 0; ccp_flags_set(f->unit, 1, 0); +#ifdef MPPE + if (ccp_gotoptions[f->unit].mppe) { + ccp_gotoptions[f->unit].mppe = 0; + if (lcp_fsm[f->unit].state == OPENED) { + /* If LCP is not already going down, make sure it does. */ + error("MPPE disabled"); + lcp_close(f->unit, "MPPE disabled"); + } + } +#endif } /* @@ -1111,6 +1502,27 @@ 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": ""); + if (mppe_opts & MPPE_OPT_UNKNOWN) + printer(arg, " (%.2x %.2x %.2x %.2x)", + p[2], p[3], p[4], p[5]); + p += CILEN_MPPE; + } + break; +#endif case CI_DEFLATE: case CI_DEFLATE_DRAFT: if (optlen >= CILEN_DEFLATE) { @@ -1153,7 +1565,7 @@ ccp_printpkt(p, plen, printer, arg) case TERMACK: case TERMREQ: if (len > 0 && *p >= ' ' && *p < 0x7f) { - print_string(p, len, printer, arg); + print_string((char *)p, len, printer, arg); p += len; len = 0; } @@ -1195,6 +1607,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.