Annotation of embedaddon/mpd/src/ccp_mppc.c, revision 1.1.1.2
1.1 misho 1:
2: /*
3: * ccp_mppc.c
4: *
5: * Written by Archie Cobbs <archie@freebsd.org>
6: * Copyright (c) 1998-1999 Whistle Communications, Inc. All rights reserved.
7: * See ``COPYRIGHT.whistle''
8: */
9:
10: #include "defs.h"
11:
12: #ifdef CCP_MPPC
13:
14: #include "ppp.h"
15: #include "ccp.h"
16: #include "msoft.h"
17: #include "ngfunc.h"
18: #include "bund.h"
19: #include <md4.h>
20:
21: #include <netgraph/ng_message.h>
22: #include <netgraph.h>
23:
24: /*
25: * This implements both MPPC compression and MPPE encryption.
26: */
27:
28: /*
29: * DEFINITIONS
30: */
31:
32: /* #define DEBUG_KEYS */
33:
34: #define MPPC_SUPPORTED (MPPC_BIT | MPPE_BITS | MPPE_STATELESS)
35:
36: /* Set menu options */
37: enum {
38: SET_ACCEPT,
39: SET_DENY,
40: SET_ENABLE,
41: SET_DISABLE,
42: SET_YES,
43: SET_NO
44: };
45:
46: enum {
47: MPPC_CONF_COMPRESS,
48: MPPC_CONF_40,
49: MPPC_CONF_56,
50: MPPC_CONF_128,
51: MPPC_CONF_STATELESS,
52: MPPC_CONF_POLICY
53: };
54:
55: /*
56: * INTERNAL FUNCTIONS
57: */
58:
59: static int MppcInit(Bund b, int dir);
60: static int MppcConfigure(Bund b);
61: static char *MppcDescribe(Bund b, int xmit, char *buf, size_t len);
62: static int MppcSubtractBloat(Bund b, int size);
63: static void MppcCleanup(Bund b, int dir);
64: static u_char *MppcBuildConfigReq(Bund b, u_char *cp, int *ok);
65: static void MppcDecodeConfigReq(Fsm fp, FsmOption opt, int mode);
66: static Mbuf MppcRecvResetReq(Bund b, int id, Mbuf bp, int *noAck);
67: static char *MppcDescribeBits(u_int32_t bits, char *buf, size_t len);
68: static int MppcNegotiated(Bund b, int xmit);
1.1.1.2 ! misho 69: static int MppcSetCommand(Context ctx, int ac, const char *const av[], const void *arg);
1.1 misho 70:
71: /* Encryption stuff */
72: static void MppeInitKey(Bund b, MppcInfo mppc, int dir);
73: static void MppeInitKeyv2(Bund b, MppcInfo mppc, int dir);
74: static short MppcEnabledMppeType(Bund b, short type);
75: static short MppcAcceptableMppeType(Bund b, short type);
76: static int MppcKeyAvailable(Bund b, short type);
77:
78: #ifdef DEBUG_KEYS
79: static void KeyDebug(const u_char *data, int len, const char *fmt, ...);
80: #define KEYDEBUG(x) KeyDebug x
81: #else
82: #define KEYDEBUG(x)
83: #endif
84:
85: /*
86: * GLOBAL VARIABLES
87: */
88:
89: static const struct confinfo gConfList[] = {
90: { 1, MPPC_CONF_COMPRESS, "compress" },
91: { 1, MPPC_CONF_40, "e40" },
92: { 1, MPPC_CONF_56, "e56" },
93: { 1, MPPC_CONF_128, "e128" },
94: { 1, MPPC_CONF_STATELESS, "stateless" },
95: { 0, MPPC_CONF_POLICY, "policy" },
96: { 0, 0, NULL },
97: };
98:
99: const struct comptype gCompMppcInfo = {
100: "mppc",
101: CCP_TY_MPPC,
102: 1,
103: MppcInit,
104: MppcConfigure,
105: NULL,
106: MppcDescribe,
107: MppcSubtractBloat,
108: MppcCleanup,
109: MppcBuildConfigReq,
110: MppcDecodeConfigReq,
111: NULL,
112: MppcRecvResetReq,
113: NULL,
114: MppcNegotiated,
115: NULL,
116: NULL,
117: NULL,
118: };
119:
120: const struct cmdtab MppcSetCmds[] = {
121: { "accept [opt ...]", "Accept option",
122: MppcSetCommand, NULL, 2, (void *) SET_ACCEPT },
123: { "deny [opt ...]", "Deny option",
124: MppcSetCommand, NULL, 2, (void *) SET_DENY },
125: { "enable [opt ...]", "Enable option",
126: MppcSetCommand, NULL, 2, (void *) SET_ENABLE },
127: { "disable [opt ...]", "Disable option",
128: MppcSetCommand, NULL, 2, (void *) SET_DISABLE },
129: { "yes [opt ...]", "Enable and accept option",
130: MppcSetCommand, NULL, 2, (void *) SET_YES },
131: { "no [opt ...]", "Disable and deny option",
132: MppcSetCommand, NULL, 2, (void *) SET_NO },
1.1.1.2 ! misho 133: { NULL, NULL, NULL, NULL, 0, NULL },
1.1 misho 134: };
135:
136: int MPPCPresent = 0;
137: int MPPEPresent = 0;
138:
139: /*
140: * MppcInit()
141: */
142:
143: static int
144: MppcInit(Bund b, int dir)
145: {
146: MppcInfo const mppc = &b->ccp.mppc;
147: struct ng_mppc_config conf;
148: struct ngm_mkpeer mp;
149: char path[NG_PATHSIZ];
150: const char *mppchook, *ppphook;
151: int mschap;
152: int cmd;
153: ng_ID_t id;
154:
155: /* Which type of MS-CHAP did we do? */
156: mschap = b->params.msoft.chap_alg;
157:
158: /* Initialize configuration structure */
159: memset(&conf, 0, sizeof(conf));
160: conf.enable = 1;
161: if (dir == COMP_DIR_XMIT) {
162: cmd = NGM_MPPC_CONFIG_COMP;
163: ppphook = NG_PPP_HOOK_COMPRESS;
164: mppchook = NG_MPPC_HOOK_COMP;
165: conf.bits = mppc->xmit_bits;
166: if (conf.bits & MPPE_BITS) {
167: if (mschap == CHAP_ALG_MSOFT)
168: MppeInitKey(b, mppc, dir);
169: else
170: MppeInitKeyv2(b, mppc, dir);
171: memcpy(conf.startkey, mppc->xmit_key0, sizeof(conf.startkey));
172: }
173: } else {
174: cmd = NGM_MPPC_CONFIG_DECOMP;
175: ppphook = NG_PPP_HOOK_DECOMPRESS;
176: mppchook = NG_MPPC_HOOK_DECOMP;
177: conf.bits = mppc->recv_bits;
178: if (conf.bits & MPPE_BITS) {
179: if (mschap == CHAP_ALG_MSOFT)
180: MppeInitKey(b, mppc, dir);
181: else
182: MppeInitKeyv2(b, mppc, dir);
183: memcpy(conf.startkey, mppc->recv_key0, sizeof(conf.startkey));
184: }
185: }
186:
187: /* Attach a new MPPC node to the PPP node */
188: snprintf(path, sizeof(path), "[%x]:", b->nodeID);
189: strcpy(mp.type, NG_MPPC_NODE_TYPE);
190: strcpy(mp.ourhook, ppphook);
191: strcpy(mp.peerhook, mppchook);
192: if (NgSendMsg(gCcpCsock, path,
193: NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) {
194: Perror("[%s] can't create %s node", b->name, mp.type);
195: return(-1);
196: }
197:
198: strlcat(path, ppphook, sizeof(path));
199:
1.1.1.2 ! misho 200: if ((id = NgGetNodeID(-1, path)) == 0) {
! 201: Perror("[%s] Cannot get %s node id", b->name, NG_MPPC_NODE_TYPE);
! 202: goto fail;
! 203: }
! 204:
1.1 misho 205: if (dir == COMP_DIR_XMIT) {
206: b->ccp.comp_node_id = id;
207: } else {
208: b->ccp.decomp_node_id = id;
209: }
210:
211: /* Configure MPPC node */
212: snprintf(path, sizeof(path), "[%x]:", id);
213: if (NgSendMsg(gCcpCsock, path,
214: NGM_MPPC_COOKIE, cmd, &conf, sizeof(conf)) < 0) {
215: Perror("[%s] can't config %s node at %s",
216: b->name, NG_MPPC_NODE_TYPE, path);
1.1.1.2 ! misho 217: goto fail;
1.1 misho 218: }
219:
220: /* Done */
221: return(0);
1.1.1.2 ! misho 222:
! 223: fail:
! 224: NgFuncShutdownNode(gCcpCsock, b->name, path);
! 225: return(-1);
1.1 misho 226: }
227:
228: static int
229: MppcConfigure(Bund b)
230: {
231: MppcInfo const mppc = &b->ccp.mppc;
232:
233: mppc->peer_reject = 0;
234: mppc->recv_bits = 0;
235: mppc->xmit_bits = 0;
236:
237: if (Enabled(&mppc->options, MPPC_CONF_COMPRESS)
238: && MPPCPresent)
239: return (0);
240:
241: if (MppcEnabledMppeType(b, 40) || MppcAcceptableMppeType(b, 40))
242: return (0);
243: if (MppcEnabledMppeType(b, 56) || MppcAcceptableMppeType(b, 56))
244: return (0);
245: if (MppcEnabledMppeType(b, 128) || MppcAcceptableMppeType(b, 128))
246: return (0);
247:
248: return (-1);
249: }
250:
251: /*
252: * MppcDescribe()
253: */
254:
255: static char *
256: MppcDescribe(Bund b, int dir, char *buf, size_t len)
257: {
258: MppcInfo const mppc = &b->ccp.mppc;
259:
260: switch (dir) {
261: case COMP_DIR_XMIT:
262: return(MppcDescribeBits(mppc->xmit_bits, buf, len));
263: case COMP_DIR_RECV:
264: return(MppcDescribeBits(mppc->recv_bits, buf, len));
265: default:
266: assert(0);
267: return(NULL);
268: }
269: }
270:
271: /*
272: * MppcSubtractBloat()
273: */
274:
275: static int
276: MppcSubtractBloat(Bund b, int size)
277: {
278:
279: /* Account for MPPC header */
280: size -= 2;
281:
282: /* Account for possible expansion with MPPC compression */
283: if ((b->ccp.mppc.xmit_bits & MPPC_BIT) != 0) {
284: int l, h, size0 = size;
285:
286: while (1) {
287: l = MPPC_MAX_BLOWUP(size0);
288: h = MPPC_MAX_BLOWUP(size0 + 1);
289: if (l > size) {
290: size0 -= 20;
291: } else if (h > size) {
292: size = size0;
293: break;
294: } else {
295: size0++;
296: }
297: }
298: }
299:
300: /* Done */
301: return(size);
302: }
303:
304: /*
305: * MppcNegotiated()
306: */
307:
308: static int
309: MppcNegotiated(Bund b, int dir)
310: {
311: MppcInfo const mppc = &b->ccp.mppc;
312:
313: switch (dir) {
314: case COMP_DIR_XMIT:
315: return(mppc->xmit_bits != 0);
316: case COMP_DIR_RECV:
317: return(mppc->recv_bits != 0);
318: default:
319: assert(0);
320: return(0);
321: }
322: }
323:
324: /*
325: * MppcCleanup()
326: */
327:
328: static void
329: MppcCleanup(Bund b, int dir)
330: {
331: char path[NG_PATHSIZ];
332:
333: /* Remove node */
334: if (dir == COMP_DIR_XMIT) {
335: snprintf(path, sizeof(path), "[%x]:", b->ccp.comp_node_id);
336: b->ccp.comp_node_id = 0;
337: } else {
338: snprintf(path, sizeof(path), "[%x]:", b->ccp.decomp_node_id);
339: b->ccp.decomp_node_id = 0;
340: }
341: NgFuncShutdownNode(gCcpCsock, b->name, path);
342: }
343:
344: /*
345: * MppcBuildConfigReq()
346: */
347:
348: static u_char *
349: MppcBuildConfigReq(Bund b, u_char *cp, int *ok)
350: {
351: MppcInfo const mppc = &b->ccp.mppc;
352: u_int32_t bits = 0;
353:
354: /* Compression */
355: if (Enabled(&mppc->options, MPPC_CONF_COMPRESS)
356: && !MPPC_PEER_REJECTED(mppc, MPPC_CONF_COMPRESS)
357: && MPPCPresent)
358: bits |= MPPC_BIT;
359:
360: /* Encryption */
361: if (MppcEnabledMppeType(b, 40)
362: && !MPPC_PEER_REJECTED(mppc, MPPC_CONF_40))
363: bits |= MPPE_40;
364: if (MppcEnabledMppeType(b, 56)
365: && !MPPC_PEER_REJECTED(mppc, MPPC_CONF_56))
366: bits |= MPPE_56;
367: if (MppcEnabledMppeType(b, 128)
368: && !MPPC_PEER_REJECTED(mppc, MPPC_CONF_128))
369: bits |= MPPE_128;
370:
371: /* Stateless mode */
372: if (Enabled(&mppc->options, MPPC_CONF_STATELESS)
373: && !MPPC_PEER_REJECTED(mppc, MPPC_CONF_STATELESS)
374: && bits != 0)
375: bits |= MPPE_STATELESS;
376:
377: /* Ship it */
378: mppc->xmit_bits = bits;
379: if (bits != 0) {
380: cp = FsmConfValue(cp, CCP_TY_MPPC, -4, &bits);
381: *ok = 1;
382: } else {
383: *ok = 0;
384: }
385: return(cp);
386: }
387:
388: /*
389: * MppcDecodeConfigReq()
390: */
391:
392: static void
393: MppcDecodeConfigReq(Fsm fp, FsmOption opt, int mode)
394: {
395: Bund b = (Bund)fp->arg;
396: MppcInfo const mppc = &b->ccp.mppc;
397: u_int32_t orig_bits;
398: u_int32_t bits;
399: char buf[64];
400:
401: /* Get bits */
402: memcpy(&orig_bits, opt->data, 4);
403: orig_bits = ntohl(orig_bits);
404: bits = orig_bits;
405:
406: /* Sanity check */
407: if (opt->len != 6) {
408: Log(LG_CCP, ("[%s] bogus length %d", b->name, opt->len));
409: if (mode == MODE_REQ)
410: FsmRej(fp, opt);
411: return;
412: }
413:
414: /* Display it */
415: Log(LG_CCP, ("[%s] 0x%08x:%s", b->name, bits, MppcDescribeBits(bits, buf, sizeof(buf))));
416:
417: /* Deal with it */
418: switch (mode) {
419: case MODE_REQ:
420:
421: /* Check for supported bits */
422: if (bits & ~MPPC_SUPPORTED) {
423: Log(LG_CCP, ("[%s] Bits 0x%08x not supported", b->name, bits & ~MPPC_SUPPORTED));
424: bits &= MPPC_SUPPORTED;
425: }
426:
427: /* Check compression */
428: if (!Acceptable(&mppc->options, MPPC_CONF_COMPRESS) || !MPPCPresent)
429: bits &= ~MPPC_BIT;
430:
431: /* Check encryption */
432: if (!MppcAcceptableMppeType(b, 40))
433: bits &= ~MPPE_40;
434: if (!MppcAcceptableMppeType(b, 56))
435: bits &= ~MPPE_56;
436: if (!MppcAcceptableMppeType(b, 128))
437: bits &= ~MPPE_128;
438:
439: /* Choose the strongest encryption available */
440: if (bits & MPPE_128)
441: bits &= ~(MPPE_40|MPPE_56);
442: else if (bits & MPPE_56)
443: bits &= ~MPPE_40;
444:
445: /* It doesn't really make sense to encrypt in only one direction.
446: Also, Win95/98 PPTP can't handle uni-directional encryption. So
447: if the remote side doesn't request encryption, try to prompt it.
448: This is broken wrt. normal PPP negotiation: typical Microsoft. */
449: if ((bits & MPPE_BITS) == 0) {
450: if (MppcAcceptableMppeType(b, 40)) bits |= MPPE_40;
451: if (MppcAcceptableMppeType(b, 56)) bits |= MPPE_56;
452: if (MppcAcceptableMppeType(b, 128)) bits |= MPPE_128;
453: }
454:
455: /* Stateless mode */
456: if ((bits & MPPE_STATELESS) &&
457: (!Acceptable(&mppc->options, MPPC_CONF_STATELESS)
458: || (bits & (MPPE_BITS|MPPC_BIT)) == 0))
459: bits &= ~MPPE_STATELESS;
460:
461: /* See if what we want equals what was sent */
462: mppc->recv_bits = bits;
463: if (bits) {
464: if (bits != orig_bits) {
465: bits = htonl(bits);
466: memcpy(opt->data, &bits, 4);
467: FsmNak(fp, opt);
468: }
469: else
470: FsmAck(fp, opt);
471: }
472: else
473: FsmRej(fp, opt);
474: break;
475:
476: case MODE_NAK:
477: if (!(bits & MPPC_BIT))
478: MPPC_PEER_REJ(mppc, MPPC_CONF_COMPRESS);
479: if (!(bits & MPPE_40))
480: MPPC_PEER_REJ(mppc, MPPC_CONF_40);
481: if (!(bits & MPPE_56))
482: MPPC_PEER_REJ(mppc, MPPC_CONF_56);
483: if (!(bits & MPPE_128))
484: MPPC_PEER_REJ(mppc, MPPC_CONF_128);
485: if (!(bits & MPPE_STATELESS))
486: MPPC_PEER_REJ(mppc, MPPC_CONF_STATELESS);
487: break;
488: }
489: }
490:
491: /*
492: * MppcRecvResetReq()
493: */
494:
495: static Mbuf
496: MppcRecvResetReq(Bund b, int id, Mbuf bp, int *noAck)
497: {
498: char path[NG_PATHSIZ];
1.1.1.2 ! misho 499:
! 500: (void)id;
! 501: (void)bp;
! 502:
1.1 misho 503: /* Forward ResetReq to the MPPC compression node */
504: snprintf(path, sizeof(path), "[%x]:", b->ccp.comp_node_id);
505: if (NgSendMsg(gCcpCsock, path,
506: NGM_MPPC_COOKIE, NGM_MPPC_RESETREQ, NULL, 0) < 0) {
507: Perror("[%s] reset-req to %s node", b->name, NG_MPPC_NODE_TYPE);
508: }
509:
510: /* No ResetAck required for MPPC */
511: if (noAck)
512: *noAck = 1;
513: return(NULL);
514: }
515:
516: /*
517: * MppcDescribeBits()
518: */
519:
520: static char *
521: MppcDescribeBits(u_int32_t bits, char *buf, size_t len)
522: {
523: *buf = 0;
524: if (bits & MPPC_BIT)
525: snprintf(buf + strlen(buf), len - strlen(buf), "MPPC");
526: if (bits & MPPE_BITS) {
527: snprintf(buf + strlen(buf), len - strlen(buf), "%sMPPE(", (*buf)?", ":"");
528: if (bits & MPPE_40) {
529: snprintf(buf + strlen(buf), len - strlen(buf), "40");
530: if (bits & (MPPE_56|MPPE_128))
531: snprintf(buf + strlen(buf), len - strlen(buf), ", ");
532: }
533: if (bits & MPPE_56) {
534: snprintf(buf + strlen(buf), len - strlen(buf), "56");
535: if ((bits & MPPE_128))
536: snprintf(buf + strlen(buf), len - strlen(buf), ", ");
537: }
538: if (bits & MPPE_128)
539: snprintf(buf + strlen(buf), len - strlen(buf), "128");
540: snprintf(buf + strlen(buf), len - strlen(buf), " bits)");
541: }
542: if (bits & MPPE_STATELESS)
543: snprintf(buf + strlen(buf), len - strlen(buf), "%sstateless", (*buf)?", ":"");
544: return(buf);
545: }
546:
547: static short
548: MppcEnabledMppeType(Bund b, short type)
549: {
550: MppcInfo const mppc = &b->ccp.mppc;
551: short ret;
552:
553: /* Check if we have kernel support */
554: if (!MPPEPresent)
555: return (0);
556:
557: /* Check if we are able to calculate key */
558: if (!MppcKeyAvailable(b, type))
559: return (0);
560:
561: switch (type) {
562: case 40:
563: if (Enabled(&mppc->options, MPPC_CONF_POLICY)) {
564: ret = (b->params.msoft.types & MPPE_TYPE_40BIT) &&
565: !MPPC_PEER_REJECTED(mppc, MPPC_CONF_40);
566: } else {
567: ret = Enabled(&mppc->options, MPPC_CONF_40) &&
568: !MPPC_PEER_REJECTED(mppc, MPPC_CONF_40);
569: }
570: break;
571:
572: case 56:
573: if (Enabled(&mppc->options, MPPC_CONF_POLICY)) {
574: ret = (b->params.msoft.types & MPPE_TYPE_56BIT) &&
575: !MPPC_PEER_REJECTED(mppc, MPPC_CONF_56);
576: } else {
577: ret = Enabled(&mppc->options, MPPC_CONF_56) &&
578: !MPPC_PEER_REJECTED(mppc, MPPC_CONF_56);
579: }
580: break;
581:
582: case 128:
583: default:
584: if (Enabled(&mppc->options, MPPC_CONF_POLICY)) {
585: ret = (b->params.msoft.types & MPPE_TYPE_128BIT) &&
586: !MPPC_PEER_REJECTED(mppc, MPPC_CONF_128);
587: } else {
588: ret = Enabled(&mppc->options, MPPC_CONF_128) &&
589: !MPPC_PEER_REJECTED(mppc, MPPC_CONF_128);
590: }
591: }
592:
593: return ret;
594: }
595:
596: static short
597: MppcAcceptableMppeType(Bund b, short type)
598: {
599: MppcInfo const mppc = &b->ccp.mppc;
600: short ret;
601:
602: /* Check if we have kernel support */
603: if (!MPPEPresent)
604: return (0);
605:
606: /* Check if we are able to calculate key */
607: if (!MppcKeyAvailable(b, type))
608: return (0);
609:
610: switch (type) {
611: case 40:
612: if (Enabled(&mppc->options, MPPC_CONF_POLICY)) {
613: ret = b->params.msoft.types & MPPE_TYPE_40BIT;
614: } else {
615: ret = Acceptable(&mppc->options, MPPC_CONF_40);
616: }
617: break;
618:
619: case 56:
620: if (Enabled(&mppc->options, MPPC_CONF_POLICY)) {
621: ret = b->params.msoft.types & MPPE_TYPE_56BIT;
622: } else {
623: ret = Acceptable(&mppc->options, MPPC_CONF_56);
624: }
625: break;
626:
627: case 128:
628: default:
629: if (Enabled(&mppc->options, MPPC_CONF_POLICY)) {
630: ret = b->params.msoft.types & MPPE_TYPE_128BIT;
631: } else {
632: ret = Acceptable(&mppc->options, MPPC_CONF_128);
633: }
634: }
635:
636: return ret;
637: }
638:
639: #define KEYLEN(b) (((b) & MPPE_128) ? 16 : 8)
640:
641: /*
642: * MppeInitKey()
643: */
644:
645: static void
646: MppeInitKey(Bund b, MppcInfo mppc, int dir)
647: {
648: u_int32_t const bits = (dir == COMP_DIR_XMIT) ?
649: mppc->xmit_bits : mppc->recv_bits;
650: u_char *const key0 = (dir == COMP_DIR_XMIT) ?
651: mppc->xmit_key0 : mppc->recv_key0;
652: u_char hash[MPPE_KEY_LEN];
653: u_char *chal;
654:
655: /* The secret comes from the originating caller's credentials */
656: chal = b->params.msoft.msChal;
657:
658: /* Compute basis for the session key (ie, "start key" or key0) */
659: if (bits & MPPE_128) {
660: memcpy(hash, b->params.msoft.nt_hash_hash, sizeof(hash));
661: KEYDEBUG((hash, sizeof(hash), "NT Password Hash Hash"));
662: KEYDEBUG((chal, CHAP_MSOFT_CHAL_LEN, "Challenge"));
663: MsoftGetStartKey(chal, hash);
664: KEYDEBUG((hash, sizeof(hash), "NT StartKey"));
665: } else {
666: memcpy(hash, b->params.msoft.lm_hash, 8);
667: KEYDEBUG((hash, sizeof(hash), "LM StartKey"));
668: }
669: memcpy(key0, hash, MPPE_KEY_LEN);
670: KEYDEBUG((key0, (bits & MPPE_128) ? 16 : 8, "InitialKey"));
671: return;
672: }
673:
674: /*
675: * MppeInitKeyv2()
676: */
677:
678: static void
679: MppeInitKeyv2(Bund b, MppcInfo mppc, int dir)
680: {
681: u_char *const key0 = (dir == COMP_DIR_XMIT) ?
682: mppc->xmit_key0 : mppc->recv_key0;
683: u_char hash[MPPE_KEY_LEN];
684: u_char *resp;
685:
686: if (b->params.msoft.has_keys)
687: {
688: memcpy(mppc->xmit_key0, b->params.msoft.xmit_key, MPPE_KEY_LEN);
689: memcpy(mppc->recv_key0, b->params.msoft.recv_key, MPPE_KEY_LEN);
690: return;
691: }
692:
693: /* The secret comes from the originating caller's credentials */
694: resp = b->params.msoft.ntResp;
695:
696: /* Compute basis for the session key (ie, "start key" or key0) */
697: memcpy(hash, b->params.msoft.nt_hash_hash, sizeof(hash));
698: KEYDEBUG((hash, sizeof(hash), "NT Password Hash Hash"));
699: KEYDEBUG((resp, CHAP_MSOFTv2_CHAL_LEN, "Response"));
700: MsoftGetMasterKey(resp, hash);
701: KEYDEBUG((hash, sizeof(hash), "GetMasterKey"));
702: MsoftGetAsymetricStartKey(hash,
703: (dir == COMP_DIR_RECV) ^
704: (b->originate == LINK_ORIGINATE_LOCAL));
705: KEYDEBUG((hash, sizeof(hash), "GetAsymmetricKey"));
706: memcpy(key0, hash, MPPE_KEY_LEN);
707: KEYDEBUG((key0, MPPE_KEY_LEN, "InitialKey"));
708: return;
709: }
710:
711: #ifdef DEBUG_KEYS
712:
713: /*
714: * KeyDebug()
715: */
716:
717: static void
718: KeyDebug(const u_char *data, int len, const char *fmt, ...)
719: {
720: char buf[100];
721: int k;
722: va_list args;
723:
724: va_start(args, fmt);
725: vsnprintf(buf, sizeof(buf), fmt, args);
726: va_end(args);
727: snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ":");
728: for (k = 0; k < len; k++) {
729: snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
730: " %02x", (u_char) data[k]);
731: }
732: Log(LG_ERR, ("%s", buf));
733: }
734:
735: #endif /* DEBUG_KEYS */
736:
737: static int
738: MppcKeyAvailable(Bund b, short type) {
739:
740: if (b->params.msoft.chap_alg == CHAP_ALG_MSOFT) {
741: if (((type == 128) && (!b->params.msoft.has_nt_hash)) ||
742: ((type != 128) && (!b->params.msoft.has_lm_hash))) {
743: return (0);
744: }
745: } else {
746: if (!b->params.msoft.has_keys && !b->params.msoft.has_nt_hash) {
747: return (0);
748: }
749: }
750: return (1);
751: }
752:
753: /*
754: * MppcTestCap()
755: */
756:
757: int
758: MppcTestCap(void)
759: {
760: struct ng_mppc_config conf;
761: struct ngm_mkpeer mp;
762: int cs, ds;
763:
764: /* Create a netgraph socket node */
765: if (NgMkSockNode(NULL, &cs, &ds) < 0) {
766: Perror("MppcTestCap: can't create socket node");
767: return(-1);
768: }
769:
770: /* Attach a new MPPC node */
771: strcpy(mp.type, NG_MPPC_NODE_TYPE);
772: strcpy(mp.ourhook, "mppc");
773: strcpy(mp.peerhook, NG_MPPC_HOOK_COMP);
774: if (NgSendMsg(cs, ".",
775: NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) {
776: Perror("MppcTestCap: can't create %s node", mp.type);
777: goto done;
778: }
779:
780: /* Initialize configuration structure */
781: memset(&conf, 0, sizeof(conf));
782: conf.enable = 1;
783: conf.bits = MPPC_BIT;
784:
785: /* Configure MPPC node */
786: if (NgSendMsg(cs, "mppc",
787: NGM_MPPC_COOKIE, NGM_MPPC_CONFIG_COMP, &conf, sizeof(conf)) < 0) {
788: if (errno != EPROTONOSUPPORT) {
789: Perror("MppcTestCap: can't config %s node", NG_MPPC_NODE_TYPE);
790: }
791: } else
792: MPPCPresent = 1;
793:
794: conf.bits = MPPE_128;
795:
796: /* Configure MPPC node */
797: if (NgSendMsg(cs, "mppc",
798: NGM_MPPC_COOKIE, NGM_MPPC_CONFIG_COMP, &conf, sizeof(conf)) < 0) {
799: if (errno != EPROTONOSUPPORT) {
800: Perror("MppcTestCap: can't config %s node", NG_MPPC_NODE_TYPE);
801: }
802: } else
803: MPPEPresent = 1;
804:
805: /* Done */
806: done:
807: close(cs);
808: close(ds);
809: return(0);
810: }
811:
812: /*
813: * MppcStat()
814: */
815:
816: int
1.1.1.2 ! misho 817: MppcStat(Context ctx, int ac, const char *const av[], const void *arg)
1.1 misho 818: {
819: MppcInfo const mppc = &ctx->bund->ccp.mppc;
820:
1.1.1.2 ! misho 821: (void)ac;
! 822: (void)av;
! 823: (void)arg;
! 824:
1.1 misho 825: Printf("MPPC options:\r\n");
826: OptStat(ctx, &mppc->options, gConfList);
827:
828: return(0);
829: }
830:
831: /*
832: * MppcSetCommand()
833: */
834:
835: static int
1.1.1.2 ! misho 836: MppcSetCommand(Context ctx, int ac, const char *const av[], const void *arg)
1.1 misho 837: {
838: MppcInfo const mppc = &ctx->bund->ccp.mppc;
839:
840: if (ac == 0)
841: return(-1);
842: switch ((intptr_t)arg) {
843: case SET_ACCEPT:
844: AcceptCommand(ac, av, &mppc->options, gConfList);
845: break;
846:
847: case SET_DENY:
848: DenyCommand(ac, av, &mppc->options, gConfList);
849: break;
850:
851: case SET_ENABLE:
852: EnableCommand(ac, av, &mppc->options, gConfList);
853: break;
854:
855: case SET_DISABLE:
856: DisableCommand(ac, av, &mppc->options, gConfList);
857: break;
858:
859: case SET_YES:
860: YesCommand(ac, av, &mppc->options, gConfList);
861: break;
862:
863: case SET_NO:
864: NoCommand(ac, av, &mppc->options, gConfList);
865: break;
866:
867: default:
868: assert(0);
869: }
870: return(0);
871: }
872:
873: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>