]> git.pld-linux.org Git - packages/ppp.git/blame - ppp-2.4.3-mppe-mppc-1.1.patch
- release 3
[packages/ppp.git] / ppp-2.4.3-mppe-mppc-1.1.patch
CommitLineData
1b28c30e
JK
1diff -ruN ppp-2.4.3.orig/include/linux/ppp-comp.h ppp-2.4.3/include/linux/ppp-comp.h
2--- ppp-2.4.3.orig/include/linux/ppp-comp.h 2002-12-06 10:49:15.000000000 +0100
3+++ ppp-2.4.3/include/linux/ppp-comp.h 2004-11-21 13:54:09.000000000 +0100
4@@ -36,7 +36,7 @@
5 */
6
7 /*
8- * ==FILEVERSION 20020319==
9+ * ==FILEVERSION 20020715==
10 *
11 * NOTE TO MAINTAINERS:
12 * If you modify this file at all, please set the above date.
13@@ -86,7 +86,7 @@
14
15 /* Compress a packet */
16 int (*compress) (void *state, unsigned char *rptr,
17- unsigned char *obuf, int isize, int osize);
18+ unsigned char *obuf, int isize, int osize);
19
20 /* Return compression statistics */
21 void (*comp_stat) (void *state, struct compstat *stats);
22@@ -107,7 +107,7 @@
23
24 /* Decompress a packet. */
25 int (*decompress) (void *state, unsigned char *ibuf, int isize,
26- unsigned char *obuf, int osize);
27+ unsigned char *obuf, int osize);
28
29 /* Update state for an incompressible packet received */
30 void (*incomp) (void *state, unsigned char *ibuf, int icnt);
31@@ -288,6 +288,33 @@
32 opts |= MPPE_OPT_UNKNOWN; \
33 } while (/* CONSTCOND */ 0)
34
35+/* MPPE/MPPC definitions by J.D.*/
36+#define MPPE_STATELESS MPPE_H_BIT /* configuration bit H */
37+#define MPPE_40BIT MPPE_L_BIT /* configuration bit L */
38+#define MPPE_56BIT MPPE_M_BIT /* configuration bit M */
39+#define MPPE_128BIT MPPE_S_BIT /* configuration bit S */
40+#define MPPE_MPPC MPPE_C_BIT /* configuration bit C */
41+
42+/*
43+ * Definitions for Stac LZS.
44+ */
45+
46+#define CI_LZS 17 /* config option for Stac LZS */
47+#define CILEN_LZS 5 /* length of config option */
48+
49+#define LZS_OVHD 4 /* max. LZS overhead */
50+#define LZS_HIST_LEN 2048 /* LZS history size */
51+#define LZS_MAX_CCOUNT 0x0FFF /* max. coherency counter value */
52+
53+#define LZS_MODE_NONE 0
54+#define LZS_MODE_LCB 1
55+#define LZS_MODE_CRC 2
56+#define LZS_MODE_SEQ 3
57+#define LZS_MODE_EXT 4
58+
59+#define LZS_EXT_BIT_FLUSHED 0x80 /* bit A */
60+#define LZS_EXT_BIT_COMP 0x20 /* bit C */
61+
62 /*
63 * Definitions for other, as yet unsupported, compression methods.
64 */
65diff -ruN ppp-2.4.3.orig/include/net/ppp-comp.h ppp-2.4.3/include/net/ppp-comp.h
66--- ppp-2.4.3.orig/include/net/ppp-comp.h 2002-12-06 10:49:15.000000000 +0100
67+++ ppp-2.4.3/include/net/ppp-comp.h 2004-11-21 13:54:09.000000000 +0100
68@@ -255,6 +255,33 @@
69 opts |= MPPE_OPT_UNKNOWN; \
70 } while (/* CONSTCOND */ 0)
71
72+/* MPPE/MPPC definitions by J.D.*/
73+#define MPPE_STATELESS MPPE_H_BIT /* configuration bit H */
74+#define MPPE_40BIT MPPE_L_BIT /* configuration bit L */
75+#define MPPE_56BIT MPPE_M_BIT /* configuration bit M */
76+#define MPPE_128BIT MPPE_S_BIT /* configuration bit S */
77+#define MPPE_MPPC MPPE_C_BIT /* configuration bit C */
78+
79+/*
80+ * Definitions for Stac LZS.
81+ */
82+
83+#define CI_LZS 17 /* config option for Stac LZS */
84+#define CILEN_LZS 5 /* length of config option */
85+
86+#define LZS_OVHD 4 /* max. LZS overhead */
87+#define LZS_HIST_LEN 2048 /* LZS history size */
88+#define LZS_MAX_CCOUNT 0x0FFF /* max. coherency counter value */
89+
90+#define LZS_MODE_NONE 0
91+#define LZS_MODE_LCB 1
92+#define LZS_MODE_CRC 2
93+#define LZS_MODE_SEQ 3
94+#define LZS_MODE_EXT 4
95+
96+#define LZS_EXT_BIT_FLUSHED 0x80 /* bit A */
97+#define LZS_EXT_BIT_COMP 0x20 /* bit C */
98+
99 /*
100 * Definitions for other, as yet unsupported, compression methods.
101 */
e01c21c5
JB
102--- ppp-2.4.4/pppd/ccp.c.orig 2005-07-09 02:23:05.000000000 +0200
103+++ ppp-2.4.4/pppd/ccp.c 2006-07-21 23:34:12.121546000 +0200
1b28c30e
JK
104@@ -62,12 +62,10 @@
105 static char bsd_value[8];
106 static char deflate_value[8];
107
108-/*
109- * Option variables.
110- */
111 #ifdef MPPE
112-bool refuse_mppe_stateful = 1; /* Allow stateful mode? */
113-#endif
114+static int setmppe(char **);
115+static int setnomppe(void);
116+#endif /* MPPE */
117
118 static option_t ccp_option_list[] = {
119 { "noccp", o_bool, &ccp_protent.enabled_flag,
120@@ -108,54 +106,36 @@
121 "don't allow Predictor-1", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR,
122 &ccp_allowoptions[0].predictor_1 },
123
124+ { "lzs", o_bool, &ccp_wantoptions[0].lzs,
125+ "request Stac LZS", 1, &ccp_allowoptions[0].lzs, OPT_PRIO },
126+ { "+lzs", o_bool, &ccp_wantoptions[0].lzs,
127+ "request Stac LZS", 1, &ccp_allowoptions[0].lzs, OPT_ALIAS | OPT_PRIO },
128+ { "nolzs", o_bool, &ccp_wantoptions[0].lzs,
129+ "don't allow Stac LZS", OPT_PRIOSUB | OPT_A2CLR,
130+ &ccp_allowoptions[0].lzs },
131+ { "-lzs", o_bool, &ccp_wantoptions[0].lzs,
132+ "don't allow Stac LZS", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR,
133+ &ccp_allowoptions[0].lzs },
134+
135 #ifdef MPPE
136- /* MPPE options are symmetrical ... we only set wantoptions here */
137- { "require-mppe", o_bool, &ccp_wantoptions[0].mppe,
138- "require MPPE encryption",
139- OPT_PRIO | MPPE_OPT_40 | MPPE_OPT_128 },
140- { "+mppe", o_bool, &ccp_wantoptions[0].mppe,
141- "require MPPE encryption",
142- OPT_ALIAS | OPT_PRIO | MPPE_OPT_40 | MPPE_OPT_128 },
143- { "nomppe", o_bool, &ccp_wantoptions[0].mppe,
144- "don't allow MPPE encryption", OPT_PRIO },
145- { "-mppe", o_bool, &ccp_wantoptions[0].mppe,
146- "don't allow MPPE encryption", OPT_ALIAS | OPT_PRIO },
147-
148- /* We use ccp_allowoptions[0].mppe as a junk var ... it is reset later */
149- { "require-mppe-40", o_bool, &ccp_allowoptions[0].mppe,
150- "require MPPE 40-bit encryption", OPT_PRIO | OPT_A2OR | MPPE_OPT_40,
151- &ccp_wantoptions[0].mppe },
152- { "+mppe-40", o_bool, &ccp_allowoptions[0].mppe,
153- "require MPPE 40-bit encryption", OPT_PRIO | OPT_A2OR | MPPE_OPT_40,
154- &ccp_wantoptions[0].mppe },
155- { "nomppe-40", o_bool, &ccp_allowoptions[0].mppe,
156- "don't allow MPPE 40-bit encryption",
157- OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_40, &ccp_wantoptions[0].mppe },
158- { "-mppe-40", o_bool, &ccp_allowoptions[0].mppe,
159- "don't allow MPPE 40-bit encryption",
160- OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_40,
161- &ccp_wantoptions[0].mppe },
162-
163- { "require-mppe-128", o_bool, &ccp_allowoptions[0].mppe,
164- "require MPPE 128-bit encryption", OPT_PRIO | OPT_A2OR | MPPE_OPT_128,
165- &ccp_wantoptions[0].mppe },
166- { "+mppe-128", o_bool, &ccp_allowoptions[0].mppe,
167- "require MPPE 128-bit encryption",
168- OPT_ALIAS | OPT_PRIO | OPT_A2OR | MPPE_OPT_128,
169- &ccp_wantoptions[0].mppe },
170- { "nomppe-128", o_bool, &ccp_allowoptions[0].mppe,
171- "don't allow MPPE 128-bit encryption",
172- OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_128, &ccp_wantoptions[0].mppe },
173- { "-mppe-128", o_bool, &ccp_allowoptions[0].mppe,
174- "don't allow MPPE 128-bit encryption",
175- OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_128,
176- &ccp_wantoptions[0].mppe },
177-
178- /* strange one; we always request stateless, but will we allow stateful? */
179- { "mppe-stateful", o_bool, &refuse_mppe_stateful,
180- "allow MPPE stateful mode", OPT_PRIO },
181- { "nomppe-stateful", o_bool, &refuse_mppe_stateful,
182- "disallow MPPE stateful mode", OPT_PRIO | 1 },
183+ { "mppc", o_bool, &ccp_wantoptions[0].mppc,
184+ "request MPPC compression", 1, &ccp_allowoptions[0].mppc },
185+ { "+mppc", o_bool, &ccp_wantoptions[0].mppc,
186+ "request MPPC compression", 1, &ccp_allowoptions[0].mppc, OPT_ALIAS },
187+ { "nomppc", o_bool, &ccp_wantoptions[0].mppc,
188+ "don't allow MPPC compression", OPT_PRIOSUB | OPT_A2CLR,
189+ &ccp_allowoptions[0].mppc },
190+ { "-mppc", o_bool, &ccp_wantoptions[0].mppc,
191+ "don't allow MPPC compression", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR,
192+ &ccp_allowoptions[0].mppc },
193+ { "mppe", o_special, (void *)setmppe,
194+ "request MPPE encryption" },
195+ { "+mppe", o_special, (void *)setmppe,
196+ "request MPPE encryption" },
197+ { "nomppe", o_special_noarg, (void *)setnomppe,
198+ "don't allow MPPE encryption" },
199+ { "-mppe", o_special_noarg, (void *)setnomppe,
200+ "don't allow MPPE encryption" },
201 #endif /* MPPE */
202
203 { NULL }
204@@ -241,7 +221,7 @@
205 */
206 #define ANY_COMPRESS(opt) ((opt).deflate || (opt).bsd_compress \
207 || (opt).predictor_1 || (opt).predictor_2 \
208- || (opt).mppe)
209+ || (opt).lzs || (opt).mppc || (opt).mppe)
210
211 /*
212 * Local state (mainly for handling reset-reqs and reset-acks).
213@@ -344,6 +324,100 @@
214 return 1;
215 }
216
217+#ifdef MPPE
218+/*
219+ * Functions called from config options
220+ */
221+/*
222+ MPPE suboptions:
223+ required - require MPPE; disconnect if peer doesn't support it
224+ stateless - use stateless mode
225+ no40 - disable 40 bit keys
226+ no56 - disable 56 bit keys
227+ no128 - disable 128 bit keys
228+*/
229+int setmppe(char **argv)
230+{
231+ int i;
232+ char *str, cmdbuf[16];
233+
234+ ccp_allowoptions[0].mppe = 1;
235+ ccp_allowoptions[0].mppe_40 = 1;
236+ ccp_allowoptions[0].mppe_56 = 1;
237+ ccp_allowoptions[0].mppe_128 = 1;
238+ ccp_allowoptions[0].mppe_stateless = 0;
239+ ccp_wantoptions[0].mppe = 0;
240+
241+ str = *argv;
242+
243+ while (1) {
244+ i = 0;
245+ memset(cmdbuf, '\0', 16);
246+ while ((i < 16) && (*str != ',') && (*str != '\0'))
247+ cmdbuf[i++] = *str++;
248+ cmdbuf[i] = '\0';
249+ if (!strncasecmp(cmdbuf, "no40", strlen("no40"))) {
250+ ccp_allowoptions[0].mppe_40 = 0;
251+ goto next_param;
252+ } else if (!strncasecmp(cmdbuf, "no56", strlen("no56"))) {
253+ ccp_allowoptions[0].mppe_56 = 0;
254+ goto next_param;
255+ } else if (!strncasecmp(cmdbuf, "no128", strlen("no128"))) {
256+ ccp_allowoptions[0].mppe_128 = 0;
257+ goto next_param;
258+ } else if (!strncasecmp(cmdbuf, "stateless", strlen("stateless"))) {
259+ ccp_allowoptions[0].mppe_stateless = 1;
260+ goto next_param;
261+ } else if (!strncasecmp(cmdbuf, "required", strlen("required"))) {
262+ ccp_wantoptions[0].mppe = 1;
263+ goto next_param;
264+ } else {
265+ option_error("invalid parameter '%s' for mppe option", cmdbuf);
266+ return 0;
267+ }
268+
269+ next_param:
270+ if (*str == ',') {
271+ str++;
272+ continue;
273+ }
274+ if (*str == '\0') {
275+ if (!(ccp_allowoptions[0].mppe_40 || ccp_allowoptions[0].mppe_56 ||
276+ ccp_allowoptions[0].mppe_128)) {
277+ if (ccp_wantoptions[0].mppe == 1) {
278+ option_error("You require MPPE but you have switched off "
279+ "all encryption key lengths.");
280+ return 0;
281+ }
282+ ccp_wantoptions[0].mppe = ccp_allowoptions[0].mppe = 0;
283+ ccp_wantoptions[0].mppe_stateless =
284+ ccp_allowoptions[0].mppe_stateless = 0;
285+ } else {
286+ ccp_allowoptions[0].mppe = 1;
287+ ccp_wantoptions[0].mppe_stateless =
288+ ccp_allowoptions[0].mppe_stateless;
289+ if (ccp_wantoptions[0].mppe == 1) {
290+ ccp_wantoptions[0].mppe_40 = ccp_allowoptions[0].mppe_40;
291+ ccp_wantoptions[0].mppe_56 = ccp_allowoptions[0].mppe_56;
292+ ccp_wantoptions[0].mppe_128 = ccp_allowoptions[0].mppe_128;
293+ }
294+ }
295+ return 1;
296+ }
297+ }
298+}
299+
300+int setnomppe(void)
301+{
302+ ccp_wantoptions[0].mppe = ccp_allowoptions[0].mppe = 0;
303+ ccp_wantoptions[0].mppe_40 = ccp_allowoptions[0].mppe_40 = 0;
304+ ccp_wantoptions[0].mppe_56 = ccp_allowoptions[0].mppe_56 = 0;
305+ ccp_wantoptions[0].mppe_128 = ccp_allowoptions[0].mppe_128 = 0;
306+ ccp_wantoptions[0].mppe_stateless = ccp_allowoptions[0].mppe_stateless = 0;
307+ return 1;
308+}
309+#endif /* MPPE */
310+
311 /*
312 * ccp_init - initialize CCP.
313 */
314@@ -378,6 +452,30 @@
315 ccp_allowoptions[0].bsd_bits = BSD_MAX_BITS;
316
317 ccp_allowoptions[0].predictor_1 = 1;
318+
319+ ccp_wantoptions[0].lzs = 0; /* Stac LZS - will be enabled in the future */
320+ ccp_wantoptions[0].lzs_mode = LZS_MODE_SEQ;
321+ ccp_wantoptions[0].lzs_hists = 1;
322+ ccp_allowoptions[0].lzs = 0; /* Stac LZS - will be enabled in the future */
323+ ccp_allowoptions[0].lzs_mode = LZS_MODE_SEQ;
324+ ccp_allowoptions[0].lzs_hists = 1;
325+
326+#ifdef MPPE
327+ /* by default allow and request MPPC... */
328+ ccp_wantoptions[0].mppc = ccp_allowoptions[0].mppc = 1;
329+
330+ /* ... and allow but don't request MPPE */
331+ ccp_allowoptions[0].mppe = 1;
332+ ccp_allowoptions[0].mppe_40 = 1;
333+ ccp_allowoptions[0].mppe_56 = 1;
334+ ccp_allowoptions[0].mppe_128 = 1;
335+ ccp_allowoptions[0].mppe_stateless = 1;
336+ ccp_wantoptions[0].mppe = 0;
337+ ccp_wantoptions[0].mppe_40 = 0;
338+ ccp_wantoptions[0].mppe_56 = 0;
339+ ccp_wantoptions[0].mppe_128 = 0;
340+ ccp_wantoptions[0].mppe_stateless = 0;
341+#endif /* MPPE */
342 }
343
344 /*
345@@ -455,11 +553,11 @@
346 if (oldstate == OPENED && p[0] == TERMREQ && f->state != OPENED) {
347 notice("Compression disabled by peer.");
348 #ifdef MPPE
349- if (ccp_gotoptions[unit].mppe) {
350+ if (ccp_wantoptions[unit].mppe) {
351 error("MPPE disabled, closing LCP");
352 lcp_close(unit, "MPPE disabled by peer");
353 }
354-#endif
355+#endif /* MPPE */
356 }
357
358 /*
359@@ -487,6 +585,15 @@
360 break;
361 /* send a reset-ack, which the transmitter will see and
362 reset its compression state. */
363+
364+ /* In case of MPPE/MPPC or LZS we shouldn't send CCP_RESETACK,
365+ but we do it in order to reset compressor; CCP_RESETACK is
366+ then silently discarded. See functions ppp_send_frame and
367+ ppp_ccp_peek in ppp_generic.c (Linux only !!!). All the
368+ confusion is caused by the fact that CCP code is splited
369+ into two parts - one part is handled by pppd, the other one
370+ is handled by kernel. */
371+
372 fsm_sdata(f, CCP_RESETACK, id, NULL, 0);
373 break;
374
375@@ -515,12 +622,11 @@
376 fsm_lowerdown(&ccp_fsm[unit]);
377
378 #ifdef MPPE
379- if (ccp_gotoptions[unit].mppe) {
380+ if (ccp_wantoptions[unit].mppe) {
381 error("MPPE required but peer negotiation failed");
382 lcp_close(unit, "MPPE required but peer negotiation failed");
383 }
384-#endif
385-
386+#endif /* MPPE */
387 }
388
389 /*
390@@ -537,7 +643,7 @@
391 all_rejected[f->unit] = 0;
392
393 #ifdef MPPE
394- if (go->mppe) {
395+ if (go->mppe || go->mppc) {
396 ccp_options *ao = &ccp_allowoptions[f->unit];
397 int auth_mschap_bits = auth_done[f->unit];
398 int numbits;
399@@ -551,80 +657,109 @@
400 * NB: If MPPE is required, all other compression opts are invalid.
401 * So, we return right away if we can't do it.
402 */
403+ if (ccp_wantoptions[f->unit].mppe) {
404+ /* Leave only the mschap auth bits set */
405+ auth_mschap_bits &= (CHAP_MS_WITHPEER | CHAP_MS_PEER |
406+ CHAP_MS2_WITHPEER | CHAP_MS2_PEER);
407+ /* Count the mschap auths */
408+ auth_mschap_bits >>= CHAP_MS_SHIFT;
409+ numbits = 0;
410+ do {
411+ numbits += auth_mschap_bits & 1;
412+ auth_mschap_bits >>= 1;
413+ } while (auth_mschap_bits);
414+ if (numbits > 1) {
415+ error("MPPE required, but auth done in both directions.");
416+ lcp_close(f->unit, "MPPE required but not available");
417+ return;
418+ }
419+ if (!numbits) {
420+ error("MPPE required, but MS-CHAP[v2] auth not performed.");
421+ lcp_close(f->unit, "MPPE required but not available");
422+ return;
423+ }
424
425- /* Leave only the mschap auth bits set */
426- auth_mschap_bits &= (CHAP_MS_WITHPEER | CHAP_MS_PEER |
427- CHAP_MS2_WITHPEER | CHAP_MS2_PEER);
428- /* Count the mschap auths */
429- auth_mschap_bits >>= CHAP_MS_SHIFT;
430- numbits = 0;
431- do {
432- numbits += auth_mschap_bits & 1;
433- auth_mschap_bits >>= 1;
434- } while (auth_mschap_bits);
435- if (numbits > 1) {
436- error("MPPE required, but auth done in both directions.");
437- lcp_close(f->unit, "MPPE required but not available");
438- return;
439- }
440- if (!numbits) {
441- error("MPPE required, but MS-CHAP[v2] auth not performed.");
442- lcp_close(f->unit, "MPPE required but not available");
443- return;
444- }
445-
446- /* A plugin (eg radius) may not have obtained key material. */
447- if (!mppe_keys_set) {
448- error("MPPE required, but keys are not available. "
449- "Possible plugin problem?");
450- lcp_close(f->unit, "MPPE required but not available");
451- return;
452- }
453-
454- /* LM auth not supported for MPPE */
455- if (auth_done[f->unit] & (CHAP_MS_WITHPEER | CHAP_MS_PEER)) {
456- /* This might be noise */
457- if (go->mppe & MPPE_OPT_40) {
458- notice("Disabling 40-bit MPPE; MS-CHAP LM not supported");
459- go->mppe &= ~MPPE_OPT_40;
460- ccp_wantoptions[f->unit].mppe &= ~MPPE_OPT_40;
461+ /* A plugin (eg radius) may not have obtained key material. */
462+ if (!mppe_keys_set) {
463+ error("MPPE required, but keys are not available. "
464+ "Possible plugin problem?");
465+ lcp_close(f->unit, "MPPE required but not available");
466+ return;
467 }
468 }
469
470- /* Last check: can we actually negotiate something? */
471- if (!(go->mppe & (MPPE_OPT_40 | MPPE_OPT_128))) {
472- /* Could be misconfig, could be 40-bit disabled above. */
473- error("MPPE required, but both 40-bit and 128-bit disabled.");
474- lcp_close(f->unit, "MPPE required but not available");
475- return;
476+ /*
477+ * Check whether the kernel knows about the various
478+ * compression methods we might request. Key material
479+ * unimportant here.
480+ */
481+ if (go->mppc) {
482+ opt_buf[0] = CI_MPPE;
483+ opt_buf[1] = CILEN_MPPE;
484+ opt_buf[2] = 0;
485+ opt_buf[3] = 0;
486+ opt_buf[4] = 0;
487+ opt_buf[5] = MPPE_MPPC;
488+ if (ccp_test(f->unit, opt_buf, CILEN_MPPE, 0) <= 0)
489+ go->mppc = 0;
490+ }
491+ if (go->mppe_40) {
492+ opt_buf[0] = CI_MPPE;
493+ opt_buf[1] = CILEN_MPPE;
494+ opt_buf[2] = MPPE_STATELESS;
495+ opt_buf[3] = 0;
496+ opt_buf[4] = 0;
497+ opt_buf[5] = MPPE_40BIT;
498+ if (ccp_test(f->unit, opt_buf, CILEN_MPPE + MPPE_MAX_KEY_LEN, 0) <= 0)
499+ go->mppe_40 = 0;
500+ }
501+ if (go->mppe_56) {
502+ opt_buf[0] = CI_MPPE;
503+ opt_buf[1] = CILEN_MPPE;
504+ opt_buf[2] = MPPE_STATELESS;
505+ opt_buf[3] = 0;
506+ opt_buf[4] = 0;
507+ opt_buf[5] = MPPE_56BIT;
508+ if (ccp_test(f->unit, opt_buf, CILEN_MPPE + MPPE_MAX_KEY_LEN, 0) <= 0)
509+ go->mppe_56 = 0;
510+ }
511+ if (go->mppe_128) {
512+ opt_buf[0] = CI_MPPE;
513+ opt_buf[1] = CILEN_MPPE;
514+ opt_buf[2] = MPPE_STATELESS;
515+ opt_buf[3] = 0;
516+ opt_buf[4] = 0;
517+ opt_buf[5] = MPPE_128BIT;
518+ if (ccp_test(f->unit, opt_buf, CILEN_MPPE + MPPE_MAX_KEY_LEN, 0) <= 0)
519+ go->mppe_128 = 0;
520+ }
521+ if (!go->mppe_40 && !go->mppe_56 && !go->mppe_128) {
522+ if (ccp_wantoptions[f->unit].mppe) {
523+ error("MPPE required, but kernel has no support.");
524+ lcp_close(f->unit, "MPPE required but not available");
525+ }
526+ go->mppe = go->mppe_stateless = 0;
527+ } else {
528+ /* MPPE is not compatible with other compression types */
529+ if (ccp_wantoptions[f->unit].mppe) {
530+ ao->bsd_compress = go->bsd_compress = 0;
531+ ao->predictor_1 = go->predictor_1 = 0;
532+ ao->predictor_2 = go->predictor_2 = 0;
533+ ao->deflate = go->deflate = 0;
534+ ao->lzs = go->lzs = 0;
535+ }
536 }
537-
538- /* sync options */
539- ao->mppe = go->mppe;
540- /* MPPE is not compatible with other compression types */
541- ao->bsd_compress = go->bsd_compress = 0;
542- ao->predictor_1 = go->predictor_1 = 0;
543- ao->predictor_2 = go->predictor_2 = 0;
544- ao->deflate = go->deflate = 0;
545 }
546 #endif /* MPPE */
547-
548- /*
549- * Check whether the kernel knows about the various
550- * compression methods we might request.
551- */
552-#ifdef MPPE
553- if (go->mppe) {
554- opt_buf[0] = CI_MPPE;
555- opt_buf[1] = CILEN_MPPE;
556- MPPE_OPTS_TO_CI(go->mppe, &opt_buf[2]);
557- /* Key material unimportant here. */
558- if (ccp_test(f->unit, opt_buf, CILEN_MPPE + MPPE_MAX_KEY_LEN, 0) <= 0) {
559- error("MPPE required, but kernel has no support.");
560- lcp_close(f->unit, "MPPE required but not available");
561- }
562+ if (go->lzs) {
563+ opt_buf[0] = CI_LZS;
564+ opt_buf[1] = CILEN_LZS;
565+ opt_buf[2] = go->lzs_hists >> 8;
566+ opt_buf[3] = go->lzs_hists & 0xff;
567+ opt_buf[4] = LZS_MODE_SEQ;
568+ if (ccp_test(f->unit, opt_buf, CILEN_LZS, 0) <= 0)
569+ go->lzs = 0;
570 }
571-#endif
572 if (go->bsd_compress) {
573 opt_buf[0] = CI_BSD_COMPRESS;
574 opt_buf[1] = CILEN_BSD_COMPRESS;
575@@ -679,7 +814,8 @@
576 + (go->deflate? CILEN_DEFLATE: 0)
577 + (go->predictor_1? CILEN_PREDICTOR_1: 0)
578 + (go->predictor_2? CILEN_PREDICTOR_2: 0)
579- + (go->mppe? CILEN_MPPE: 0);
580+ + (go->lzs? CILEN_LZS: 0)
581+ + ((go->mppe || go->mppc)? CILEN_MPPE: 0);
582 }
583
584 /*
585@@ -693,6 +829,8 @@
586 {
587 int res;
588 ccp_options *go = &ccp_gotoptions[f->unit];
589+ ccp_options *ao = &ccp_allowoptions[f->unit];
590+ ccp_options *wo = &ccp_wantoptions[f->unit];
591 u_char *p0 = p;
592
593 /*
594@@ -701,22 +839,43 @@
595 * in case it gets Acked.
596 */
597 #ifdef MPPE
598- if (go->mppe) {
599+ if (go->mppe || go->mppc || (!wo->mppe && ao->mppe)) {
600 u_char opt_buf[CILEN_MPPE + MPPE_MAX_KEY_LEN];
601
602- p[0] = opt_buf[0] = CI_MPPE;
603- p[1] = opt_buf[1] = CILEN_MPPE;
604- MPPE_OPTS_TO_CI(go->mppe, &p[2]);
605- MPPE_OPTS_TO_CI(go->mppe, &opt_buf[2]);
606+ p[0] = CI_MPPE;
607+ p[1] = CILEN_MPPE;
608+ p[2] = (go->mppe_stateless ? MPPE_STATELESS : 0);
609+ p[3] = 0;
610+ p[4] = 0;
611+ p[5] = (go->mppe_40 ? MPPE_40BIT : 0) | (go->mppe_56 ? MPPE_56BIT : 0) |
612+ (go->mppe_128 ? MPPE_128BIT : 0) | (go->mppc ? MPPE_MPPC : 0);
613+
614+ BCOPY(p, opt_buf, CILEN_MPPE);
615 BCOPY(mppe_recv_key, &opt_buf[CILEN_MPPE], MPPE_MAX_KEY_LEN);
616 res = ccp_test(f->unit, opt_buf, CILEN_MPPE + MPPE_MAX_KEY_LEN, 0);
617- if (res > 0)
618+ if (res > 0) {
619 p += CILEN_MPPE;
620- else
621+ } else {
622 /* This shouldn't happen, we've already tested it! */
623- lcp_close(f->unit, "MPPE required but not available in kernel");
624+ go->mppe = go->mppe_40 = go->mppe_56 = go->mppe_128 =
625+ go->mppe_stateless = go->mppc = 0;
626+ if (ccp_wantoptions[f->unit].mppe)
627+ lcp_close(f->unit, "MPPE required but not available in kernel");
628+ }
629+ }
630+#endif /* MPPE */
631+ if (go->lzs) {
632+ p[0] = CI_LZS;
633+ p[1] = CILEN_LZS;
634+ p[2] = go->lzs_hists >> 8;
635+ p[3] = go->lzs_hists & 0xff;
636+ p[4] = LZS_MODE_SEQ;
637+ res = ccp_test(f->unit, p, CILEN_LZS, 0);
638+ if (res > 0) {
639+ p += CILEN_LZS;
640+ } else
641+ go->lzs = 0;
642 }
643-#endif
644 if (go->deflate) {
645 p[0] = go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT;
646 p[1] = CILEN_DEFLATE;
647@@ -802,7 +961,7 @@
648
649 /*
650 * ccp_ackci - process a received configure-ack, and return
651- * 1 iff the packet was OK.
652+ * 1 if the packet was OK.
653 */
654 static int
655 ccp_ackci(f, p, len)
656@@ -811,24 +970,44 @@
657 int len;
658 {
659 ccp_options *go = &ccp_gotoptions[f->unit];
660+ ccp_options *ao = &ccp_allowoptions[f->unit];
661+ ccp_options *wo = &ccp_wantoptions[f->unit];
662 u_char *p0 = p;
663
664 #ifdef MPPE
665- if (go->mppe) {
666- u_char opt_buf[CILEN_MPPE];
667-
668- opt_buf[0] = CI_MPPE;
669- opt_buf[1] = CILEN_MPPE;
670- MPPE_OPTS_TO_CI(go->mppe, &opt_buf[2]);
671- if (len < CILEN_MPPE || memcmp(opt_buf, p, CILEN_MPPE))
672+ if (go->mppe || go->mppc || (!wo->mppe && ao->mppe)) {
673+ if (len < CILEN_MPPE
674+ || p[1] != CILEN_MPPE || p[0] != CI_MPPE
675+ || p[2] != (go->mppe_stateless ? MPPE_STATELESS : 0)
676+ || p[3] != 0
677+ || p[4] != 0
678+ || (p[5] != ((go->mppe_40 ? MPPE_40BIT : 0) |
679+ (go->mppc ? MPPE_MPPC : 0))
680+ && p[5] != ((go->mppe_56 ? MPPE_56BIT : 0) |
681+ (go->mppc ? MPPE_MPPC : 0))
682+ && p[5] != ((go->mppe_128 ? MPPE_128BIT : 0) |
683+ (go->mppc ? MPPE_MPPC : 0))))
684 return 0;
685+ if (go->mppe_40 || go->mppe_56 || go->mppe_128)
686+ go->mppe = 1;
687 p += CILEN_MPPE;
688 len -= CILEN_MPPE;
689+ /* Cope with first/fast ack */
690+ if (p == p0 && len == 0)
691+ return 1;
692+ }
693+#endif /* MPPE */
694+ if (go->lzs) {
695+ if (len < CILEN_LZS || p[0] != CI_LZS || p[1] != CILEN_LZS
696+ || p[2] != go->lzs_hists>>8 || p[3] != (go->lzs_hists&0xff)
697+ || p[4] != LZS_MODE_SEQ)
698+ return 0;
699+ p += CILEN_LZS;
700+ len -= CILEN_LZS;
701 /* XXX Cope with first/fast ack */
702- if (len == 0)
703+ if (p == p0 && len == 0)
704 return 1;
705 }
706-#endif
707 if (go->deflate) {
708 if (len < CILEN_DEFLATE
709 || p[0] != (go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT)
710@@ -891,7 +1070,7 @@
711
712 /*
713 * ccp_nakci - process received configure-nak.
714- * Returns 1 iff the nak was OK.
715+ * Returns 1 if the nak was OK.
716 */
717 static int
718 ccp_nakci(f, p, len, treat_as_reject)
e01c21c5
JB
719@@ -901,6 +1080,8 @@
720 int treat_as_reject;
1b28c30e
JK
721 {
722 ccp_options *go = &ccp_gotoptions[f->unit];
723+ ccp_options *ao = &ccp_allowoptions[f->unit];
724+ ccp_options *wo = &ccp_wantoptions[f->unit];
725 ccp_options no; /* options we've seen already */
726 ccp_options try; /* options to ask for next time */
727
e01c21c5 728@@ -908,28 +1089,100 @@
1b28c30e
JK
729 try = *go;
730
731 #ifdef MPPE
732- if (go->mppe && len >= CILEN_MPPE
733- && p[0] == CI_MPPE && p[1] == CILEN_MPPE) {
734- no.mppe = 1;
735- /*
736- * Peer wants us to use a different strength or other setting.
737- * Fail if we aren't willing to use his suggestion.
738- */
739- MPPE_CI_TO_OPTS(&p[2], try.mppe);
740- if ((try.mppe & MPPE_OPT_STATEFUL) && refuse_mppe_stateful) {
741- error("Refusing MPPE stateful mode offered by peer");
742- try.mppe = 0;
743- } else if (((go->mppe | MPPE_OPT_STATEFUL) & try.mppe) != try.mppe) {
744- /* Peer must have set options we didn't request (suggest) */
745- try.mppe = 0;
746- }
747+ if ((go->mppe || go->mppc || (!wo->mppe && ao->mppe)) &&
748+ len >= CILEN_MPPE && p[0] == CI_MPPE && p[1] == CILEN_MPPE) {
749
750- if (!try.mppe) {
751- error("MPPE required but peer negotiation failed");
752- lcp_close(f->unit, "MPPE required but peer negotiation failed");
753+ if (go->mppc) {
754+ no.mppc = 1;
755+ if (!(p[5] & MPPE_MPPC))
756+ try.mppc = 0;
757+ }
758+
759+ if (go->mppe)
760+ no.mppe = 1;
761+ if (go->mppe_40)
762+ no.mppe_40 = 1;
763+ if (go->mppe_56)
764+ no.mppe_56 = 1;
765+ if (go->mppe_128)
766+ no.mppe_128 = 1;
767+ if (go->mppe_stateless)
768+ no.mppe_stateless = 1;
769+
770+ if (ao->mppe_40) {
771+ if ((p[5] & MPPE_40BIT))
772+ try.mppe_40 = 1;
773+ else
774+ try.mppe_40 = (p[5] == 0) ? 1 : 0;
775+ }
776+ if (ao->mppe_56) {
777+ if ((p[5] & MPPE_56BIT))
778+ try.mppe_56 = 1;
779+ else
780+ try.mppe_56 = (p[5] == 0) ? 1 : 0;
781+ }
782+ if (ao->mppe_128) {
783+ if ((p[5] & MPPE_128BIT))
784+ try.mppe_128 = 1;
785+ else
786+ try.mppe_128 = (p[5] == 0) ? 1 : 0;
787+ }
788+
789+ if (ao->mppe_stateless) {
790+ if ((p[2] & MPPE_STATELESS) || wo->mppe_stateless)
791+ try.mppe_stateless = 1;
792+ else
793+ try.mppe_stateless = 0;
794+ }
795+
796+ if (!try.mppe_56 && !try.mppe_40 && !try.mppe_128) {
797+ try.mppe = try.mppe_stateless = 0;
798+ if (wo->mppe) {
799+ /* we require encryption, but peer doesn't support it
800+ so we close connection */
801+ wo->mppc = wo->mppe = wo->mppe_stateless = wo->mppe_40 =
802+ wo->mppe_56 = wo->mppe_128 = 0;
803+ lcp_close(f->unit, "MPPE required but cannot negotiate MPPE "
804+ "key length");
805+ }
806+ }
807+ if (wo->mppe && (wo->mppe_40 != try.mppe_40) &&
808+ (wo->mppe_56 != try.mppe_56) && (wo->mppe_128 != try.mppe_128)) {
809+ /* cannot negotiate key length */
810+ wo->mppc = wo->mppe = wo->mppe_stateless = wo->mppe_40 =
811+ wo->mppe_56 = wo->mppe_128 = 0;
812+ lcp_close(f->unit, "Cannot negotiate MPPE key length");
813 }
814+ if (try.mppe_40 && try.mppe_56 && try.mppe_128)
815+ try.mppe_40 = try.mppe_56 = 0;
816+ else
817+ if (try.mppe_56 && try.mppe_128)
818+ try.mppe_56 = 0;
819+ else
820+ if (try.mppe_40 && try.mppe_128)
821+ try.mppe_40 = 0;
822+ else
823+ if (try.mppe_40 && try.mppe_56)
824+ try.mppe_40 = 0;
825+
826+ p += CILEN_MPPE;
827+ len -= CILEN_MPPE;
828 }
829 #endif /* MPPE */
830+
831+ if (go->lzs && len >= CILEN_LZS && p[0] == CI_LZS && p[1] == CILEN_LZS) {
832+ no.lzs = 1;
833+ if (((p[2]<<8)|p[3]) > 1 || (p[4] != LZS_MODE_SEQ &&
834+ p[4] != LZS_MODE_EXT))
835+ try.lzs = 0;
836+ else {
837+ try.lzs_mode = p[4];
838+ try.lzs_hists = (p[2] << 8) | p[3];
839+ }
840+ p += CILEN_LZS;
841+ len -= CILEN_LZS;
842+ }
843+
844 if (go->deflate && len >= CILEN_DEFLATE
845 && p[0] == (go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT)
846 && p[1] == CILEN_DEFLATE) {
e01c21c5 847@@ -1002,14 +1255,50 @@
1b28c30e
JK
848 return -1;
849
850 #ifdef MPPE
851- if (go->mppe && len >= CILEN_MPPE
852+ if ((go->mppe || go->mppc) && len >= CILEN_MPPE
853 && p[0] == CI_MPPE && p[1] == CILEN_MPPE) {
854- error("MPPE required but peer refused");
855- lcp_close(f->unit, "MPPE required but peer refused");
856+ ccp_options *wo = &ccp_wantoptions[f->unit];
857+ if (p[2] != (go->mppe_stateless ? MPPE_STATELESS : 0) ||
858+ p[3] != 0 ||
859+ p[4] != 0 ||
860+ p[5] != ((go->mppe_40 ? MPPE_40BIT : 0) |
861+ (go->mppe_56 ? MPPE_56BIT : 0) |
862+ (go->mppe_128 ? MPPE_128BIT : 0) |
863+ (go->mppc ? MPPE_MPPC : 0)))
864+ return 0;
865+ if (go->mppc)
866+ try.mppc = 0;
867+ if (go->mppe) {
868+ try.mppe = 0;
869+ if (go->mppe_40)
870+ try.mppe_40 = 0;
871+ if (go->mppe_56)
872+ try.mppe_56 = 0;
873+ if (go->mppe_128)
874+ try.mppe_128 = 0;
875+ if (go->mppe_stateless)
876+ try.mppe_stateless = 0;
877+ if (!try.mppe_56 && !try.mppe_40 && !try.mppe_128)
878+ try.mppe = try.mppe_stateless = 0;
879+ if (wo->mppe) { /* we want MPPE but cannot negotiate key length */
880+ wo->mppc = wo->mppe = wo->mppe_stateless = wo->mppe_40 =
881+ wo->mppe_56 = wo->mppe_128 = 0;
882+ lcp_close(f->unit, "MPPE required but cannot negotiate MPPE "
883+ "key length");
884+ }
885+ }
886 p += CILEN_MPPE;
887 len -= CILEN_MPPE;
888 }
889-#endif
890+#endif /* MPPE */
891+ if (go->lzs && len >= CILEN_LZS && p[0] == CI_LZS && p[1] == CILEN_LZS) {
892+ if (p[2] != go->lzs_hists>>8 || p[3] != (go->lzs_hists&0xff)
893+ || p[4] != go->lzs_mode)
894+ return 0;
895+ try.lzs = 0;
896+ p += CILEN_LZS;
897+ len -= CILEN_LZS;
898+ }
899 if (go->deflate_correct && len >= CILEN_DEFLATE
900 && p[0] == CI_DEFLATE && p[1] == CILEN_DEFLATE) {
901 if (p[2] != DEFLATE_MAKE_OPT(go->deflate_size)
e01c21c5 902@@ -1073,14 +1362,15 @@
1b28c30e
JK
903 int dont_nak;
904 {
905 int ret, newret, res;
906- u_char *p0, *retp;
907+ u_char *p0, *retp, p2, p5;
908 int len, clen, type, nb;
909 ccp_options *ho = &ccp_hisoptions[f->unit];
910 ccp_options *ao = &ccp_allowoptions[f->unit];
911+ ccp_options *wo = &ccp_wantoptions[f->unit];
912 #ifdef MPPE
913- bool rej_for_ci_mppe = 1; /* Are we rejecting based on a bad/missing */
914- /* CI_MPPE, or due to other options? */
915-#endif
916+ u_char opt_buf[CILEN_MPPE + MPPE_MAX_KEY_LEN];
917+/* int mtu; */
918+#endif /* MPPE */
919
920 ret = CONFACK;
921 retp = p0 = p;
e01c21c5 922@@ -1103,106 +1393,307 @@
1b28c30e
JK
923 switch (type) {
924 #ifdef MPPE
925 case CI_MPPE:
926- if (!ao->mppe || clen != CILEN_MPPE) {
927+ if ((!ao->mppc && !ao->mppe) || clen != CILEN_MPPE) {
928 newret = CONFREJ;
929 break;
930 }
931- MPPE_CI_TO_OPTS(&p[2], ho->mppe);
932
933- /* Nak if anything unsupported or unknown are set. */
934- if (ho->mppe & MPPE_OPT_UNSUPPORTED) {
935- newret = CONFNAK;
936- ho->mppe &= ~MPPE_OPT_UNSUPPORTED;
937- }
938- if (ho->mppe & MPPE_OPT_UNKNOWN) {
939+ p2 = p[2];
940+ p5 = p[5];
941+ /* not sure what they want, tell 'em what we got */
942+ if (((p[2] & ~MPPE_STATELESS) != 0 || p[3] != 0 || p[4] != 0 ||
943+ (p[5] & ~(MPPE_40BIT | MPPE_56BIT | MPPE_128BIT |
944+ MPPE_MPPC)) != 0 || p[5] == 0) ||
945+ (p[2] == 0 && p[3] == 0 && p[4] == 0 && p[5] == 0)) {
946 newret = CONFNAK;
947- ho->mppe &= ~MPPE_OPT_UNKNOWN;
948+ p[2] = (wo->mppe_stateless ? MPPE_STATELESS : 0);
949+ p[3] = 0;
950+ p[4] = 0;
951+ p[5] = (wo->mppe_40 ? MPPE_40BIT : 0) |
952+ (wo->mppe_56 ? MPPE_56BIT : 0) |
953+ (wo->mppe_128 ? MPPE_128BIT : 0) |
954+ (wo->mppc ? MPPE_MPPC : 0);
955+ break;
956 }
957
958- /* Check state opt */
959- if (ho->mppe & MPPE_OPT_STATEFUL) {
960- /*
961- * We can Nak and request stateless, but it's a
962- * lot easier to just assume the peer will request
963- * it if he can do it; stateful mode is bad over
964- * the Internet -- which is where we expect MPPE.
965- */
966- if (refuse_mppe_stateful) {
967- error("Refusing MPPE stateful mode offered by peer");
968+ if ((p[5] & MPPE_MPPC)) {
969+ if (ao->mppc) {
970+ ho->mppc = 1;
971+ BCOPY(p, opt_buf, CILEN_MPPE);
972+ opt_buf[2] = opt_buf[3] = opt_buf[4] = 0;
973+ opt_buf[5] = MPPE_MPPC;
974+ if (ccp_test(f->unit, opt_buf, CILEN_MPPE, 1) <= 0) {
975+ ho->mppc = 0;
976+ p[5] &= ~MPPE_MPPC;
977+ newret = CONFNAK;
978+ }
979+ } else {
980 newret = CONFREJ;
981- break;
982+ if (wo->mppe || ao->mppe) {
983+ p[5] &= ~MPPE_MPPC;
984+ newret = CONFNAK;
985+ }
986+ }
987+ }
988+
989+ if (ao->mppe)
990+ ho->mppe = 1;
991+
992+ if ((p[2] & MPPE_STATELESS)) {
993+ if (ao->mppe_stateless) {
994+ if (wo->mppe_stateless)
995+ ho->mppe_stateless = 1;
996+ else {
997+ newret = CONFNAK;
998+ if (!dont_nak)
999+ p[2] &= ~MPPE_STATELESS;
1000+ }
1001+ } else {
1002+ newret = CONFNAK;
1003+ if (!dont_nak)
1004+ p[2] &= ~MPPE_STATELESS;
1005+ }
1006+ } else {
1007+ if (wo->mppe_stateless && !dont_nak) {
1008+ wo->mppe_stateless = 0;
1009+ newret = CONFNAK;
1010+ p[2] |= MPPE_STATELESS;
1011 }
1012 }
1013
1014- /* Find out which of {S,L} are set. */
1015- if ((ho->mppe & MPPE_OPT_128)
1016- && (ho->mppe & MPPE_OPT_40)) {
1017- /* Both are set, negotiate the strongest. */
1018+ if ((p[5] & ~MPPE_MPPC) == (MPPE_40BIT|MPPE_56BIT|MPPE_128BIT)) {
1019 newret = CONFNAK;
1020- if (ao->mppe & MPPE_OPT_128)
1021- ho->mppe &= ~MPPE_OPT_40;
1022- else if (ao->mppe & MPPE_OPT_40)
1023- ho->mppe &= ~MPPE_OPT_128;
1024- else {
1025- newret = CONFREJ;
1026- break;
1027+ if (ao->mppe_128) {
1028+ ho->mppe_128 = 1;
1029+ p[5] &= ~(MPPE_40BIT|MPPE_56BIT);
1030+ BCOPY(p, opt_buf, CILEN_MPPE);
1031+ BCOPY(mppe_send_key, &opt_buf[CILEN_MPPE],
1032+ MPPE_MAX_KEY_LEN);
1033+ if (ccp_test(f->unit, opt_buf, CILEN_MPPE +
1034+ MPPE_MAX_KEY_LEN, 1) <= 0) {
1035+ ho->mppe_128 = 0;
1036+ p[5] |= (MPPE_40BIT|MPPE_56BIT);
1037+ p[5] &= ~MPPE_128BIT;
1038+ goto check_mppe_56_40;
1039+ }
1040+ goto check_mppe;
1041 }
1042- } else if (ho->mppe & MPPE_OPT_128) {
1043- if (!(ao->mppe & MPPE_OPT_128)) {
1044- newret = CONFREJ;
1045- break;
1046+ p[5] &= ~MPPE_128BIT;
1047+ goto check_mppe_56_40;
1048+ }
1049+ if ((p[5] & ~MPPE_MPPC) == (MPPE_56BIT|MPPE_128BIT)) {
1050+ newret = CONFNAK;
1051+ if (ao->mppe_128) {
1052+ ho->mppe_128 = 1;
1053+ p[5] &= ~MPPE_56BIT;
1054+ BCOPY(p, opt_buf, CILEN_MPPE);
1055+ BCOPY(mppe_send_key, &opt_buf[CILEN_MPPE],
1056+ MPPE_MAX_KEY_LEN);
1057+ if (ccp_test(f->unit, opt_buf, CILEN_MPPE +
1058+ MPPE_MAX_KEY_LEN, 1) <= 0) {
1059+ ho->mppe_128 = 0;
1060+ p[5] |= MPPE_56BIT;
1061+ p[5] &= ~MPPE_128BIT;
1062+ goto check_mppe_56;
1063+ }
1064+ goto check_mppe;
1065 }
1066- } else if (ho->mppe & MPPE_OPT_40) {
1067- if (!(ao->mppe & MPPE_OPT_40)) {
1068- newret = CONFREJ;
1069- break;
1070+ p[5] &= ~MPPE_128BIT;
1071+ goto check_mppe_56;
1072+ }
1073+ if ((p[5] & ~MPPE_MPPC) == (MPPE_40BIT|MPPE_128BIT)) {
1074+ newret = CONFNAK;
1075+ if (ao->mppe_128) {
1076+ ho->mppe_128 = 1;
1077+ p[5] &= ~MPPE_40BIT;
1078+ BCOPY(p, opt_buf, CILEN_MPPE);
1079+ BCOPY(mppe_send_key, &opt_buf[CILEN_MPPE],
1080+ MPPE_MAX_KEY_LEN);
1081+ if (ccp_test(f->unit, opt_buf, CILEN_MPPE +
1082+ MPPE_MAX_KEY_LEN, 1) <= 0) {
1083+ ho->mppe_128 = 0;
1084+ p[5] |= MPPE_40BIT;
1085+ p[5] &= ~MPPE_128BIT;
1086+ goto check_mppe_40;
1087+ }
1088+ goto check_mppe;
1089+ }
1090+ p[5] &= ~MPPE_128BIT;
1091+ goto check_mppe_40;
1092+ }
1093+ if ((p[5] & ~MPPE_MPPC) == MPPE_128BIT) {
1094+ if (ao->mppe_128) {
1095+ ho->mppe_128 = 1;
1096+ BCOPY(p, opt_buf, CILEN_MPPE);
1097+ BCOPY(mppe_send_key, &opt_buf[CILEN_MPPE],
1098+ MPPE_MAX_KEY_LEN);
1099+ if (ccp_test(f->unit, opt_buf, CILEN_MPPE +
1100+ MPPE_MAX_KEY_LEN, 1) <= 0) {
1101+ ho->mppe_128 = 0;
1102+ p[5] &= ~MPPE_128BIT;
1103+ newret = CONFNAK;
1104+ }
1105+ goto check_mppe;
1106+ }
1107+ p[5] &= ~MPPE_128BIT;
1108+ newret = CONFNAK;
1109+ goto check_mppe;
1110+ }
1111+ check_mppe_56_40:
1112+ if ((p[5] & ~MPPE_MPPC) == (MPPE_40BIT|MPPE_56BIT)) {
1113+ newret = CONFNAK;
1114+ if (ao->mppe_56) {
1115+ ho->mppe_56 = 1;
1116+ p[5] &= ~MPPE_40BIT;
1117+ BCOPY(p, opt_buf, CILEN_MPPE);
1118+ BCOPY(mppe_send_key, &opt_buf[CILEN_MPPE],
1119+ MPPE_MAX_KEY_LEN);
1120+ if (ccp_test(f->unit, opt_buf, CILEN_MPPE +
1121+ MPPE_MAX_KEY_LEN, 1) <= 0) {
1122+ ho->mppe_56 = 0;
1123+ p[5] |= MPPE_40BIT;
1124+ p[5] &= ~MPPE_56BIT;
1125+ newret = CONFNAK;
1126+ goto check_mppe_40;
1127+ }
1128+ goto check_mppe;
1129+ }
1130+ p[5] &= ~MPPE_56BIT;
1131+ goto check_mppe_40;
1132+ }
1133+ check_mppe_56:
1134+ if ((p[5] & ~MPPE_MPPC) == MPPE_56BIT) {
1135+ if (ao->mppe_56) {
1136+ ho->mppe_56 = 1;
1137+ BCOPY(p, opt_buf, CILEN_MPPE);
1138+ BCOPY(mppe_send_key, &opt_buf[CILEN_MPPE],
1139+ MPPE_MAX_KEY_LEN);
1140+ if (ccp_test(f->unit, opt_buf, CILEN_MPPE +
1141+ MPPE_MAX_KEY_LEN, 1) <= 0) {
1142+ ho->mppe_56 = 0;
1143+ p[5] &= ~MPPE_56BIT;
1144+ newret = CONFNAK;
1145+ }
1146+ goto check_mppe;
1147+ }
1148+ p[5] &= ~MPPE_56BIT;
1149+ newret = CONFNAK;
1150+ goto check_mppe;
1151+ }
1152+ check_mppe_40:
1153+ if ((p[5] & ~MPPE_MPPC) == MPPE_40BIT) {
1154+ if (ao->mppe_40) {
1155+ ho->mppe_40 = 1;
1156+ BCOPY(p, opt_buf, CILEN_MPPE);
1157+ BCOPY(mppe_send_key, &opt_buf[CILEN_MPPE],
1158+ MPPE_MAX_KEY_LEN);
1159+ if (ccp_test(f->unit, opt_buf, CILEN_MPPE +
1160+ MPPE_MAX_KEY_LEN, 1) <= 0) {
1161+ ho->mppe_40 = 0;
1162+ p[5] &= ~MPPE_40BIT;
1163+ newret = CONFNAK;
1164+ }
1165+ goto check_mppe;
1166+ }
1167+ p[5] &= ~MPPE_40BIT;
1168+ }
1169+
1170+ check_mppe:
1171+ if (!ho->mppe_40 && !ho->mppe_56 && !ho->mppe_128) {
1172+ if (wo->mppe_40 || wo->mppe_56 || wo->mppe_128) {
1173+ newret = CONFNAK;
1174+ p[2] |= (wo->mppe_stateless ? MPPE_STATELESS : 0);
1175+ p[5] |= (wo->mppe_40 ? MPPE_40BIT : 0) |
1176+ (wo->mppe_56 ? MPPE_56BIT : 0) |
1177+ (wo->mppe_128 ? MPPE_128BIT : 0) |
1178+ (wo->mppc ? MPPE_MPPC : 0);
1179+ } else {
1180+ ho->mppe = ho->mppe_stateless = 0;
1181 }
1182 } else {
1183- /* Neither are set. */
e01c21c5 1184- /* We cannot accept this. */
1b28c30e
JK
1185+ /* MPPE is not compatible with other compression types */
1186+ if (wo->mppe) {
1187+ ao->bsd_compress = 0;
1188+ ao->predictor_1 = 0;
1189+ ao->predictor_2 = 0;
1190+ ao->deflate = 0;
1191+ ao->lzs = 0;
1192+ }
1193+ }
1194+ if ((!ho->mppc || !ao->mppc) && !ho->mppe) {
1195+ p[2] = p2;
1196+ p[5] = p5;
e01c21c5
JB
1197 newret = CONFNAK;
1198 /* Give the peer our idea of what can be used,
1199 so it can choose and confirm */
1200 ho->mppe = ao->mppe;
1b28c30e
JK
1201 }
1202
1203- /* rebuild the opts */
1204- MPPE_OPTS_TO_CI(ho->mppe, &p[2]);
1205- if (newret == CONFACK) {
1206- u_char opt_buf[CILEN_MPPE + MPPE_MAX_KEY_LEN];
1207- int mtu;
1208-
1209- BCOPY(p, opt_buf, CILEN_MPPE);
1210- BCOPY(mppe_send_key, &opt_buf[CILEN_MPPE],
1211- MPPE_MAX_KEY_LEN);
1212- if (ccp_test(f->unit, opt_buf,
1213- CILEN_MPPE + MPPE_MAX_KEY_LEN, 1) <= 0) {
1214- /* This shouldn't happen, we've already tested it! */
1215- error("MPPE required, but kernel has no support.");
1216- lcp_close(f->unit, "MPPE required but not available");
1217- newret = CONFREJ;
1218- break;
1219- }
1220- /*
1221- * We need to decrease the interface MTU by MPPE_PAD
1222- * because MPPE frames **grow**. The kernel [must]
1223- * allocate MPPE_PAD extra bytes in xmit buffers.
1224- */
1225- mtu = netif_get_mtu(f->unit);
1226- if (mtu)
1227- netif_set_mtu(f->unit, mtu - MPPE_PAD);
1228- else
1229- newret = CONFREJ;
1230- }
1231+ /*
1232+ * I have commented the code below because according to RFC1547
1233+ * MTU is only information for higher level protocols about
1234+ * "the maximum allowable length for a packet (q.v.) transmitted
1235+ * over a point-to-point link without incurring network layer
1236+ * fragmentation." Of course a PPP implementation should be able
1237+ * to handle overhead added by MPPE - in our case apropriate code
1238+ * is located in drivers/net/ppp_generic.c in the kernel sources.
1239+ *
1240+ * According to RFC1661:
1241+ * - when negotiated MRU is less than 1500 octets, a PPP
1242+ * implementation must still be able to receive at least 1500
1243+ * octets,
1244+ * - when PFC is negotiated, a PPP implementation is still
1245+ * required to receive frames with uncompressed protocol field.
1246+ *
1247+ * So why not to handle MPPE overhead without changing MTU value?
1248+ * I am sure that RFC3078, unfortunately silently, assumes that.
1249+ */
1250
1251 /*
1252- * We have accepted MPPE or are willing to negotiate
1253- * MPPE parameters. A CONFREJ is due to subsequent
1254- * (non-MPPE) processing.
1255+ * We need to decrease the interface MTU by MPPE_PAD
1256+ * because MPPE frames **grow**. The kernel [must]
1257+ * allocate MPPE_PAD extra bytes in xmit buffers.
1258 */
1259- rej_for_ci_mppe = 0;
1260+/*
1261+ mtu = netif_get_mtu(f->unit);
1262+ if (mtu) {
1263+ netif_set_mtu(f->unit, mtu - MPPE_PAD);
1264+ } else {
1265+ newret = CONFREJ;
1266+ if (ccp_wantoptions[f->unit].mppe) {
1267+ error("Cannot adjust MTU needed by MPPE.");
1268+ lcp_close(f->unit, "Cannot adjust MTU needed by MPPE.");
1269+ }
1270+ }
1271+*/
1272 break;
1273 #endif /* MPPE */
1274+
1275+ case CI_LZS:
1276+ if (!ao->lzs || clen != CILEN_LZS) {
1277+ newret = CONFREJ;
1278+ break;
1279+ }
1280+
1281+ ho->lzs = 1;
1282+ ho->lzs_hists = (p[2] << 8) | p[3];
1283+ ho->lzs_mode = p[4];
1284+ if ((ho->lzs_hists != ao->lzs_hists) ||
1285+ (ho->lzs_mode != ao->lzs_mode)) {
1286+ newret = CONFNAK;
1287+ if (!dont_nak) {
1288+ p[2] = ao->lzs_hists >> 8;
1289+ p[3] = ao->lzs_hists & 0xff;
1290+ p[4] = ao->lzs_mode;
1291+ } else
1292+ break;
1293+ }
1294+
1295+ if (p == p0 && ccp_test(f->unit, p, CILEN_LZS, 1) <= 0) {
1296+ newret = CONFREJ;
1297+ }
1298+ break;
1299+
1300 case CI_DEFLATE:
1301 case CI_DEFLATE_DRAFT:
1302 if (!ao->deflate || clen != CILEN_DEFLATE
e01c21c5 1303@@ -1344,12 +1835,6 @@
1b28c30e
JK
1304 else
1305 *lenp = retp - p0;
1306 }
1307-#ifdef MPPE
1308- if (ret == CONFREJ && ao->mppe && rej_for_ci_mppe) {
1309- error("MPPE required but peer negotiation failed");
1310- lcp_close(f->unit, "MPPE required but peer negotiation failed");
1311- }
1312-#endif
1313 return ret;
1314 }
1315
e01c21c5 1316@@ -1371,24 +1856,35 @@
1b28c30e
JK
1317 char *p = result;
1318 char *q = result + sizeof(result); /* 1 past result */
1319
1320- slprintf(p, q - p, "MPPE ");
1321- p += 5;
1322- if (opt->mppe & MPPE_OPT_128) {
1323- slprintf(p, q - p, "128-bit ");
1324- p += 8;
1325- }
1326- if (opt->mppe & MPPE_OPT_40) {
1327- slprintf(p, q - p, "40-bit ");
1328- p += 7;
1329- }
1330- if (opt->mppe & MPPE_OPT_STATEFUL)
1331- slprintf(p, q - p, "stateful");
1332- else
1333- slprintf(p, q - p, "stateless");
1334-
1335+ if (opt->mppe) {
1336+ if (opt->mppc) {
1337+ slprintf(p, q - p, "MPPC/MPPE ");
1338+ p += 10;
1339+ } else {
1340+ slprintf(p, q - p, "MPPE ");
1341+ p += 5;
1342+ }
1343+ if (opt->mppe_128) {
1344+ slprintf(p, q - p, "128-bit ");
1345+ p += 8;
1346+ } else if (opt->mppe_56) {
1347+ slprintf(p, q - p, "56-bit ");
1348+ p += 7;
1349+ } else if (opt->mppe_40) {
1350+ slprintf(p, q - p, "40-bit ");
1351+ p += 7;
1352+ }
1353+ if (opt->mppe_stateless)
1354+ slprintf(p, q - p, "stateless");
1355+ else
1356+ slprintf(p, q - p, "stateful");
1357+ } else if (opt->mppc)
1358+ slprintf(p, q - p, "MPPC");
1359 break;
1360 }
1361-#endif
1362+#endif /* MPPE */
1363+ case CI_LZS:
1364+ return "Stac LZS";
1365 case CI_DEFLATE:
1366 case CI_DEFLATE_DRAFT:
1367 if (opt2 != NULL && opt2->deflate_size != opt->deflate_size)
e01c21c5 1368@@ -1444,12 +1940,12 @@
1b28c30e
JK
1369 } else if (ANY_COMPRESS(*ho))
1370 notice("%s transmit compression enabled", method_name(ho, NULL));
1371 #ifdef MPPE
1372- if (go->mppe) {
1373+ if (go->mppe || go->mppc) {
1374 BZERO(mppe_recv_key, MPPE_MAX_KEY_LEN);
1375 BZERO(mppe_send_key, MPPE_MAX_KEY_LEN);
1376 continue_networks(f->unit); /* Bring up IP et al */
1377 }
1378-#endif
1379+#endif /* MPPE */
1380 }
1381
1382 /*
e01c21c5 1383@@ -1472,7 +1968,7 @@
1b28c30e
JK
1384 lcp_close(f->unit, "MPPE disabled");
1385 }
1386 }
1387-#endif
1388+#endif /* MPPE */
1389 }
1390
1391 /*
e01c21c5 1392@@ -1532,24 +2028,28 @@
1b28c30e
JK
1393 #ifdef MPPE
1394 case CI_MPPE:
1395 if (optlen >= CILEN_MPPE) {
1396- u_char mppe_opts;
1397-
1398- MPPE_CI_TO_OPTS(&p[2], mppe_opts);
1399- printer(arg, "mppe %s %s %s %s %s %s%s",
1400- (p[2] & MPPE_H_BIT)? "+H": "-H",
1401- (p[5] & MPPE_M_BIT)? "+M": "-M",
1402- (p[5] & MPPE_S_BIT)? "+S": "-S",
1403- (p[5] & MPPE_L_BIT)? "+L": "-L",
1404+ printer(arg, "mppe %s %s %s %s %s %s",
1405+ (p[2] & MPPE_STATELESS)? "+H": "-H",
1406+ (p[5] & MPPE_56BIT)? "+M": "-M",
1407+ (p[5] & MPPE_128BIT)? "+S": "-S",
1408+ (p[5] & MPPE_40BIT)? "+L": "-L",
1409 (p[5] & MPPE_D_BIT)? "+D": "-D",
1410- (p[5] & MPPE_C_BIT)? "+C": "-C",
1411- (mppe_opts & MPPE_OPT_UNKNOWN)? " +U": "");
1412- if (mppe_opts & MPPE_OPT_UNKNOWN)
1413+ (p[5] & MPPE_MPPC)? "+C": "-C");
1414+ if ((p[5] & ~(MPPE_56BIT | MPPE_128BIT | MPPE_40BIT |
1415+ MPPE_D_BIT | MPPE_MPPC)) ||
1416+ (p[2] & ~MPPE_STATELESS))
1417 printer(arg, " (%.2x %.2x %.2x %.2x)",
1418 p[2], p[3], p[4], p[5]);
1419 p += CILEN_MPPE;
1420 }
1421 break;
1422-#endif
1423+#endif /* MPPE */
1424+ case CI_LZS:
1425+ if (optlen >= CILEN_LZS) {
1426+ printer(arg, "lzs %.2x %.2x %.2x", p[2], p[3], p[4]);
1427+ p += CILEN_LZS;
1428+ }
1429+ break;
1430 case CI_DEFLATE:
1431 case CI_DEFLATE_DRAFT:
1432 if (optlen >= CILEN_DEFLATE) {
e01c21c5 1433@@ -1635,6 +2135,7 @@
1b28c30e
JK
1434 error("Lost compression sync: disabling compression");
1435 ccp_close(unit, "Lost compression sync");
1436 #ifdef MPPE
1437+ /* My module dosn't need this. J.D., 2003-07-06 */
1438 /*
1439 * If we were doing MPPE, we must also take the link down.
1440 */
e01c21c5 1441@@ -1642,9 +2143,18 @@
1b28c30e
JK
1442 error("Too many MPPE errors, closing LCP");
1443 lcp_close(unit, "Too many MPPE errors");
1444 }
1445-#endif
1446+#endif /* MPPE */
1447 } else {
1448 /*
1449+ * When LZS or MPPE/MPPC is negotiated we just send CCP_RESETREQ
1450+ * and don't wait for CCP_RESETACK
1451+ */
1452+ if ((ccp_gotoptions[f->unit].method == CI_LZS) ||
1453+ (ccp_gotoptions[f->unit].method == CI_MPPE)) {
1454+ fsm_sdata(f, CCP_RESETREQ, f->reqid = ++f->id, NULL, 0);
1455+ return;
1456+ }
1457+ /*
1458 * Send a reset-request to reset the peer's compressor.
1459 * We don't do that if we are still waiting for an
1460 * acknowledgement to a previous reset-request.
e01c21c5 1461@@ -1675,4 +2185,3 @@
1b28c30e
JK
1462 } else
1463 ccp_localstate[f->unit] &= ~RACK_PENDING;
1464 }
1465-
1466diff -ruN ppp-2.4.3.orig/pppd/ccp.h ppp-2.4.3/pppd/ccp.h
1467--- ppp-2.4.3.orig/pppd/ccp.h 2004-11-04 11:02:26.000000000 +0100
1468+++ ppp-2.4.3/pppd/ccp.h 2004-11-21 13:54:09.000000000 +0100
1469@@ -37,9 +37,17 @@
1470 bool predictor_2; /* do Predictor-2? */
1471 bool deflate_correct; /* use correct code for deflate? */
1472 bool deflate_draft; /* use draft RFC code for deflate? */
1473+ bool lzs; /* do Stac LZS? */
1474+ bool mppc; /* do MPPC? */
1475 bool mppe; /* do MPPE? */
1476+ bool mppe_40; /* allow 40 bit encryption? */
1477+ bool mppe_56; /* allow 56 bit encryption? */
1478+ bool mppe_128; /* allow 128 bit encryption? */
1479+ bool mppe_stateless; /* allow stateless encryption */
1480 u_short bsd_bits; /* # bits/code for BSD Compress */
1481 u_short deflate_size; /* lg(window size) for Deflate */
1482+ u_short lzs_mode; /* LZS check mode */
1483+ u_short lzs_hists; /* number of LZS histories */
1484 short method; /* code for chosen compression method */
1485 } ccp_options;
1486
1487diff -ruN ppp-2.4.3.orig/pppd/chap_ms.c ppp-2.4.3/pppd/chap_ms.c
1488--- ppp-2.4.3.orig/pppd/chap_ms.c 2004-11-12 10:57:43.000000000 +0100
1489+++ ppp-2.4.3/pppd/chap_ms.c 2004-11-21 13:54:09.000000000 +0100
1490@@ -895,13 +895,17 @@
1491 /*
1492 * Disable undesirable encryption types. Note that we don't ENABLE
1493 * any encryption types, to avoid overriding manual configuration.
1494+ *
1495+ * It seems that 56 bit keys are unsupported in MS-RADIUS (see RFC 2548)
1496 */
1497 switch(types) {
1498 case MPPE_ENC_TYPES_RC4_40:
1499- ccp_wantoptions[0].mppe &= ~MPPE_OPT_128; /* disable 128-bit */
1500+ ccp_wantoptions[0].mppe_128 = 0; /* disable 128-bit */
1501+ ccp_wantoptions[0].mppe_56 = 0; /* disable 56-bit */
1502 break;
1503 case MPPE_ENC_TYPES_RC4_128:
1504- ccp_wantoptions[0].mppe &= ~MPPE_OPT_40; /* disable 40-bit */
1505+ ccp_wantoptions[0].mppe_56 = 0; /* disable 56-bit */
1506+ ccp_wantoptions[0].mppe_40 = 0; /* disable 40-bit */
1507 break;
1508 default:
1509 break;
1510diff -ruN ppp-2.4.3.orig/pppd/pppd.8 ppp-2.4.3/pppd/pppd.8
1511--- ppp-2.4.3.orig/pppd/pppd.8 2004-11-13 13:22:49.000000000 +0100
1512+++ ppp-2.4.3/pppd/pppd.8 2004-11-21 14:24:47.000000000 +0100
1513@@ -622,9 +622,29 @@
1514 Enables the use of PPP multilink; this is an alias for the `multilink'
1515 option. This option is currently only available under Linux.
1516 .TP
1517-.B mppe\-stateful
1518-Allow MPPE to use stateful mode. Stateless mode is still attempted first.
1519-The default is to disallow stateful mode.
1520+.B mppc
1521+Enables MPPC (Microsoft Point to Point Compression). This is the default.
1522+.TP
1523+.B mppe \fIsubopt1[,subopt2[,subopt3[..]]]
1524+Modify MPPE (Microsoft Point to Point Encryption) parameters. In order
1525+for MPPE to successfully come up, you must have authenticated with either
1526+MS-CHAP or MS-CHAPv2. By default MPPE is optional, it means that pppd will
1527+not propose MPPE to the peer, but will negotiate MPPE if peer wants that.
1528+You can change this using \fIrequired\fR suboption.
1529+This option is presently only supported under Linux, and only if your
1530+kernel has been configured to include MPPE support.
1531+.IP
1532+MPPE suboptions:
1533+.br
1534+\fIrequired\fR - require MPPE; disconnect if peer doesn't support it,
1535+.br
1536+\fIstateless\fR - try to negotiate stateless mode; default is stateful,
1537+.br
1538+\fIno40\fR - disable 40 bit keys,
1539+.br
1540+\fIno56\fR - disable 56 bit keys,
1541+.br
1542+\fIno128\fR - disable 128 bit keys
1543 .TP
1544 .B mpshortseq
1545 Enables the use of short (12-bit) sequence numbers in multilink
1546@@ -757,17 +777,11 @@
1547 Disables the use of PPP multilink. This option is currently only
1548 available under Linux.
1549 .TP
1550-.B nomppe
1551-Disables MPPE (Microsoft Point to Point Encryption). This is the default.
1552-.TP
1553-.B nomppe\-40
1554-Disable 40-bit encryption with MPPE.
1555+.B nomppc
1556+Disables MPPC (Microsoft Point to Point Compression).
1557 .TP
1558-.B nomppe\-128
1559-Disable 128-bit encryption with MPPE.
1560-.TP
1561-.B nomppe\-stateful
1562-Disable MPPE stateful mode. This is the default.
1563+.B nomppe
1564+Disables MPPE (Microsoft Point to Point Encryption).
1565 .TP
1566 .B nompshortseq
1567 Disables the use of short (12-bit) sequence numbers in the PPP
1568@@ -948,19 +962,6 @@
1569 Require the peer to authenticate itself using CHAP [Challenge
1570 Handshake Authentication Protocol] authentication.
1571 .TP
1572-.B require\-mppe
1573-Require the use of MPPE (Microsoft Point to Point Encryption). This
1574-option disables all other compression types. This option enables
1575-both 40-bit and 128-bit encryption. In order for MPPE to successfully
1576-come up, you must have authenticated with either MS\-CHAP or MS\-CHAPv2.
1577-This option is presently only supported under Linux, and only if your
1578-kernel has been configured to include MPPE support.
1579-.TP
1580-.B require\-mppe\-40
1581-Require the use of MPPE, with 40-bit encryption.
1582-.TP
1583-.B require\-mppe\-128
1584-Require the use of MPPE, with 128-bit encryption.
1585 .TP
1586 .B require\-mschap
1587 Require the peer to authenticate itself using MS\-CHAP [Microsoft Challenge
This page took 0.307564 seconds and 4 git commands to generate.