Annotation of embedaddon/mpd/src/ccp_mppc.c, revision 1.1
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);
! 69: static int MppcSetCommand(Context ctx, int ac, char *av[], void *arg);
! 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 },
! 133: { NULL },
! 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:
! 200: id = NgGetNodeID(-1, path);
! 201: if (dir == COMP_DIR_XMIT) {
! 202: b->ccp.comp_node_id = id;
! 203: } else {
! 204: b->ccp.decomp_node_id = id;
! 205: }
! 206:
! 207: /* Configure MPPC node */
! 208: snprintf(path, sizeof(path), "[%x]:", id);
! 209: if (NgSendMsg(gCcpCsock, path,
! 210: NGM_MPPC_COOKIE, cmd, &conf, sizeof(conf)) < 0) {
! 211: Perror("[%s] can't config %s node at %s",
! 212: b->name, NG_MPPC_NODE_TYPE, path);
! 213: NgFuncShutdownNode(gCcpCsock, b->name, path);
! 214: return(-1);
! 215: }
! 216:
! 217: /* Done */
! 218: return(0);
! 219: }
! 220:
! 221: static int
! 222: MppcConfigure(Bund b)
! 223: {
! 224: MppcInfo const mppc = &b->ccp.mppc;
! 225:
! 226: mppc->peer_reject = 0;
! 227: mppc->recv_bits = 0;
! 228: mppc->xmit_bits = 0;
! 229:
! 230: if (Enabled(&mppc->options, MPPC_CONF_COMPRESS)
! 231: && MPPCPresent)
! 232: return (0);
! 233:
! 234: if (MppcEnabledMppeType(b, 40) || MppcAcceptableMppeType(b, 40))
! 235: return (0);
! 236: if (MppcEnabledMppeType(b, 56) || MppcAcceptableMppeType(b, 56))
! 237: return (0);
! 238: if (MppcEnabledMppeType(b, 128) || MppcAcceptableMppeType(b, 128))
! 239: return (0);
! 240:
! 241: return (-1);
! 242: }
! 243:
! 244: /*
! 245: * MppcDescribe()
! 246: */
! 247:
! 248: static char *
! 249: MppcDescribe(Bund b, int dir, char *buf, size_t len)
! 250: {
! 251: MppcInfo const mppc = &b->ccp.mppc;
! 252:
! 253: switch (dir) {
! 254: case COMP_DIR_XMIT:
! 255: return(MppcDescribeBits(mppc->xmit_bits, buf, len));
! 256: case COMP_DIR_RECV:
! 257: return(MppcDescribeBits(mppc->recv_bits, buf, len));
! 258: default:
! 259: assert(0);
! 260: return(NULL);
! 261: }
! 262: }
! 263:
! 264: /*
! 265: * MppcSubtractBloat()
! 266: */
! 267:
! 268: static int
! 269: MppcSubtractBloat(Bund b, int size)
! 270: {
! 271:
! 272: /* Account for MPPC header */
! 273: size -= 2;
! 274:
! 275: /* Account for possible expansion with MPPC compression */
! 276: if ((b->ccp.mppc.xmit_bits & MPPC_BIT) != 0) {
! 277: int l, h, size0 = size;
! 278:
! 279: while (1) {
! 280: l = MPPC_MAX_BLOWUP(size0);
! 281: h = MPPC_MAX_BLOWUP(size0 + 1);
! 282: if (l > size) {
! 283: size0 -= 20;
! 284: } else if (h > size) {
! 285: size = size0;
! 286: break;
! 287: } else {
! 288: size0++;
! 289: }
! 290: }
! 291: }
! 292:
! 293: /* Done */
! 294: return(size);
! 295: }
! 296:
! 297: /*
! 298: * MppcNegotiated()
! 299: */
! 300:
! 301: static int
! 302: MppcNegotiated(Bund b, int dir)
! 303: {
! 304: MppcInfo const mppc = &b->ccp.mppc;
! 305:
! 306: switch (dir) {
! 307: case COMP_DIR_XMIT:
! 308: return(mppc->xmit_bits != 0);
! 309: case COMP_DIR_RECV:
! 310: return(mppc->recv_bits != 0);
! 311: default:
! 312: assert(0);
! 313: return(0);
! 314: }
! 315: }
! 316:
! 317: /*
! 318: * MppcCleanup()
! 319: */
! 320:
! 321: static void
! 322: MppcCleanup(Bund b, int dir)
! 323: {
! 324: char path[NG_PATHSIZ];
! 325:
! 326: /* Remove node */
! 327: if (dir == COMP_DIR_XMIT) {
! 328: snprintf(path, sizeof(path), "[%x]:", b->ccp.comp_node_id);
! 329: b->ccp.comp_node_id = 0;
! 330: } else {
! 331: snprintf(path, sizeof(path), "[%x]:", b->ccp.decomp_node_id);
! 332: b->ccp.decomp_node_id = 0;
! 333: }
! 334: NgFuncShutdownNode(gCcpCsock, b->name, path);
! 335: }
! 336:
! 337: /*
! 338: * MppcBuildConfigReq()
! 339: */
! 340:
! 341: static u_char *
! 342: MppcBuildConfigReq(Bund b, u_char *cp, int *ok)
! 343: {
! 344: MppcInfo const mppc = &b->ccp.mppc;
! 345: u_int32_t bits = 0;
! 346:
! 347: /* Compression */
! 348: if (Enabled(&mppc->options, MPPC_CONF_COMPRESS)
! 349: && !MPPC_PEER_REJECTED(mppc, MPPC_CONF_COMPRESS)
! 350: && MPPCPresent)
! 351: bits |= MPPC_BIT;
! 352:
! 353: /* Encryption */
! 354: if (MppcEnabledMppeType(b, 40)
! 355: && !MPPC_PEER_REJECTED(mppc, MPPC_CONF_40))
! 356: bits |= MPPE_40;
! 357: if (MppcEnabledMppeType(b, 56)
! 358: && !MPPC_PEER_REJECTED(mppc, MPPC_CONF_56))
! 359: bits |= MPPE_56;
! 360: if (MppcEnabledMppeType(b, 128)
! 361: && !MPPC_PEER_REJECTED(mppc, MPPC_CONF_128))
! 362: bits |= MPPE_128;
! 363:
! 364: /* Stateless mode */
! 365: if (Enabled(&mppc->options, MPPC_CONF_STATELESS)
! 366: && !MPPC_PEER_REJECTED(mppc, MPPC_CONF_STATELESS)
! 367: && bits != 0)
! 368: bits |= MPPE_STATELESS;
! 369:
! 370: /* Ship it */
! 371: mppc->xmit_bits = bits;
! 372: if (bits != 0) {
! 373: cp = FsmConfValue(cp, CCP_TY_MPPC, -4, &bits);
! 374: *ok = 1;
! 375: } else {
! 376: *ok = 0;
! 377: }
! 378: return(cp);
! 379: }
! 380:
! 381: /*
! 382: * MppcDecodeConfigReq()
! 383: */
! 384:
! 385: static void
! 386: MppcDecodeConfigReq(Fsm fp, FsmOption opt, int mode)
! 387: {
! 388: Bund b = (Bund)fp->arg;
! 389: MppcInfo const mppc = &b->ccp.mppc;
! 390: u_int32_t orig_bits;
! 391: u_int32_t bits;
! 392: char buf[64];
! 393:
! 394: /* Get bits */
! 395: memcpy(&orig_bits, opt->data, 4);
! 396: orig_bits = ntohl(orig_bits);
! 397: bits = orig_bits;
! 398:
! 399: /* Sanity check */
! 400: if (opt->len != 6) {
! 401: Log(LG_CCP, ("[%s] bogus length %d", b->name, opt->len));
! 402: if (mode == MODE_REQ)
! 403: FsmRej(fp, opt);
! 404: return;
! 405: }
! 406:
! 407: /* Display it */
! 408: Log(LG_CCP, ("[%s] 0x%08x:%s", b->name, bits, MppcDescribeBits(bits, buf, sizeof(buf))));
! 409:
! 410: /* Deal with it */
! 411: switch (mode) {
! 412: case MODE_REQ:
! 413:
! 414: /* Check for supported bits */
! 415: if (bits & ~MPPC_SUPPORTED) {
! 416: Log(LG_CCP, ("[%s] Bits 0x%08x not supported", b->name, bits & ~MPPC_SUPPORTED));
! 417: bits &= MPPC_SUPPORTED;
! 418: }
! 419:
! 420: /* Check compression */
! 421: if (!Acceptable(&mppc->options, MPPC_CONF_COMPRESS) || !MPPCPresent)
! 422: bits &= ~MPPC_BIT;
! 423:
! 424: /* Check encryption */
! 425: if (!MppcAcceptableMppeType(b, 40))
! 426: bits &= ~MPPE_40;
! 427: if (!MppcAcceptableMppeType(b, 56))
! 428: bits &= ~MPPE_56;
! 429: if (!MppcAcceptableMppeType(b, 128))
! 430: bits &= ~MPPE_128;
! 431:
! 432: /* Choose the strongest encryption available */
! 433: if (bits & MPPE_128)
! 434: bits &= ~(MPPE_40|MPPE_56);
! 435: else if (bits & MPPE_56)
! 436: bits &= ~MPPE_40;
! 437:
! 438: /* It doesn't really make sense to encrypt in only one direction.
! 439: Also, Win95/98 PPTP can't handle uni-directional encryption. So
! 440: if the remote side doesn't request encryption, try to prompt it.
! 441: This is broken wrt. normal PPP negotiation: typical Microsoft. */
! 442: if ((bits & MPPE_BITS) == 0) {
! 443: if (MppcAcceptableMppeType(b, 40)) bits |= MPPE_40;
! 444: if (MppcAcceptableMppeType(b, 56)) bits |= MPPE_56;
! 445: if (MppcAcceptableMppeType(b, 128)) bits |= MPPE_128;
! 446: }
! 447:
! 448: /* Stateless mode */
! 449: if ((bits & MPPE_STATELESS) &&
! 450: (!Acceptable(&mppc->options, MPPC_CONF_STATELESS)
! 451: || (bits & (MPPE_BITS|MPPC_BIT)) == 0))
! 452: bits &= ~MPPE_STATELESS;
! 453:
! 454: /* See if what we want equals what was sent */
! 455: mppc->recv_bits = bits;
! 456: if (bits) {
! 457: if (bits != orig_bits) {
! 458: bits = htonl(bits);
! 459: memcpy(opt->data, &bits, 4);
! 460: FsmNak(fp, opt);
! 461: }
! 462: else
! 463: FsmAck(fp, opt);
! 464: }
! 465: else
! 466: FsmRej(fp, opt);
! 467: break;
! 468:
! 469: case MODE_NAK:
! 470: if (!(bits & MPPC_BIT))
! 471: MPPC_PEER_REJ(mppc, MPPC_CONF_COMPRESS);
! 472: if (!(bits & MPPE_40))
! 473: MPPC_PEER_REJ(mppc, MPPC_CONF_40);
! 474: if (!(bits & MPPE_56))
! 475: MPPC_PEER_REJ(mppc, MPPC_CONF_56);
! 476: if (!(bits & MPPE_128))
! 477: MPPC_PEER_REJ(mppc, MPPC_CONF_128);
! 478: if (!(bits & MPPE_STATELESS))
! 479: MPPC_PEER_REJ(mppc, MPPC_CONF_STATELESS);
! 480: break;
! 481: }
! 482: }
! 483:
! 484: /*
! 485: * MppcRecvResetReq()
! 486: */
! 487:
! 488: static Mbuf
! 489: MppcRecvResetReq(Bund b, int id, Mbuf bp, int *noAck)
! 490: {
! 491: char path[NG_PATHSIZ];
! 492: /* Forward ResetReq to the MPPC compression node */
! 493: snprintf(path, sizeof(path), "[%x]:", b->ccp.comp_node_id);
! 494: if (NgSendMsg(gCcpCsock, path,
! 495: NGM_MPPC_COOKIE, NGM_MPPC_RESETREQ, NULL, 0) < 0) {
! 496: Perror("[%s] reset-req to %s node", b->name, NG_MPPC_NODE_TYPE);
! 497: }
! 498:
! 499: /* No ResetAck required for MPPC */
! 500: if (noAck)
! 501: *noAck = 1;
! 502: return(NULL);
! 503: }
! 504:
! 505: /*
! 506: * MppcDescribeBits()
! 507: */
! 508:
! 509: static char *
! 510: MppcDescribeBits(u_int32_t bits, char *buf, size_t len)
! 511: {
! 512: *buf = 0;
! 513: if (bits & MPPC_BIT)
! 514: snprintf(buf + strlen(buf), len - strlen(buf), "MPPC");
! 515: if (bits & MPPE_BITS) {
! 516: snprintf(buf + strlen(buf), len - strlen(buf), "%sMPPE(", (*buf)?", ":"");
! 517: if (bits & MPPE_40) {
! 518: snprintf(buf + strlen(buf), len - strlen(buf), "40");
! 519: if (bits & (MPPE_56|MPPE_128))
! 520: snprintf(buf + strlen(buf), len - strlen(buf), ", ");
! 521: }
! 522: if (bits & MPPE_56) {
! 523: snprintf(buf + strlen(buf), len - strlen(buf), "56");
! 524: if ((bits & MPPE_128))
! 525: snprintf(buf + strlen(buf), len - strlen(buf), ", ");
! 526: }
! 527: if (bits & MPPE_128)
! 528: snprintf(buf + strlen(buf), len - strlen(buf), "128");
! 529: snprintf(buf + strlen(buf), len - strlen(buf), " bits)");
! 530: }
! 531: if (bits & MPPE_STATELESS)
! 532: snprintf(buf + strlen(buf), len - strlen(buf), "%sstateless", (*buf)?", ":"");
! 533: return(buf);
! 534: }
! 535:
! 536: static short
! 537: MppcEnabledMppeType(Bund b, short type)
! 538: {
! 539: MppcInfo const mppc = &b->ccp.mppc;
! 540: short ret;
! 541:
! 542: /* Check if we have kernel support */
! 543: if (!MPPEPresent)
! 544: return (0);
! 545:
! 546: /* Check if we are able to calculate key */
! 547: if (!MppcKeyAvailable(b, type))
! 548: return (0);
! 549:
! 550: switch (type) {
! 551: case 40:
! 552: if (Enabled(&mppc->options, MPPC_CONF_POLICY)) {
! 553: ret = (b->params.msoft.types & MPPE_TYPE_40BIT) &&
! 554: !MPPC_PEER_REJECTED(mppc, MPPC_CONF_40);
! 555: } else {
! 556: ret = Enabled(&mppc->options, MPPC_CONF_40) &&
! 557: !MPPC_PEER_REJECTED(mppc, MPPC_CONF_40);
! 558: }
! 559: break;
! 560:
! 561: case 56:
! 562: if (Enabled(&mppc->options, MPPC_CONF_POLICY)) {
! 563: ret = (b->params.msoft.types & MPPE_TYPE_56BIT) &&
! 564: !MPPC_PEER_REJECTED(mppc, MPPC_CONF_56);
! 565: } else {
! 566: ret = Enabled(&mppc->options, MPPC_CONF_56) &&
! 567: !MPPC_PEER_REJECTED(mppc, MPPC_CONF_56);
! 568: }
! 569: break;
! 570:
! 571: case 128:
! 572: default:
! 573: if (Enabled(&mppc->options, MPPC_CONF_POLICY)) {
! 574: ret = (b->params.msoft.types & MPPE_TYPE_128BIT) &&
! 575: !MPPC_PEER_REJECTED(mppc, MPPC_CONF_128);
! 576: } else {
! 577: ret = Enabled(&mppc->options, MPPC_CONF_128) &&
! 578: !MPPC_PEER_REJECTED(mppc, MPPC_CONF_128);
! 579: }
! 580: }
! 581:
! 582: return ret;
! 583: }
! 584:
! 585: static short
! 586: MppcAcceptableMppeType(Bund b, short type)
! 587: {
! 588: MppcInfo const mppc = &b->ccp.mppc;
! 589: short ret;
! 590:
! 591: /* Check if we have kernel support */
! 592: if (!MPPEPresent)
! 593: return (0);
! 594:
! 595: /* Check if we are able to calculate key */
! 596: if (!MppcKeyAvailable(b, type))
! 597: return (0);
! 598:
! 599: switch (type) {
! 600: case 40:
! 601: if (Enabled(&mppc->options, MPPC_CONF_POLICY)) {
! 602: ret = b->params.msoft.types & MPPE_TYPE_40BIT;
! 603: } else {
! 604: ret = Acceptable(&mppc->options, MPPC_CONF_40);
! 605: }
! 606: break;
! 607:
! 608: case 56:
! 609: if (Enabled(&mppc->options, MPPC_CONF_POLICY)) {
! 610: ret = b->params.msoft.types & MPPE_TYPE_56BIT;
! 611: } else {
! 612: ret = Acceptable(&mppc->options, MPPC_CONF_56);
! 613: }
! 614: break;
! 615:
! 616: case 128:
! 617: default:
! 618: if (Enabled(&mppc->options, MPPC_CONF_POLICY)) {
! 619: ret = b->params.msoft.types & MPPE_TYPE_128BIT;
! 620: } else {
! 621: ret = Acceptable(&mppc->options, MPPC_CONF_128);
! 622: }
! 623: }
! 624:
! 625: return ret;
! 626: }
! 627:
! 628: #define KEYLEN(b) (((b) & MPPE_128) ? 16 : 8)
! 629:
! 630: /*
! 631: * MppeInitKey()
! 632: */
! 633:
! 634: static void
! 635: MppeInitKey(Bund b, MppcInfo mppc, int dir)
! 636: {
! 637: u_int32_t const bits = (dir == COMP_DIR_XMIT) ?
! 638: mppc->xmit_bits : mppc->recv_bits;
! 639: u_char *const key0 = (dir == COMP_DIR_XMIT) ?
! 640: mppc->xmit_key0 : mppc->recv_key0;
! 641: u_char hash[MPPE_KEY_LEN];
! 642: u_char *chal;
! 643:
! 644: /* The secret comes from the originating caller's credentials */
! 645: chal = b->params.msoft.msChal;
! 646:
! 647: /* Compute basis for the session key (ie, "start key" or key0) */
! 648: if (bits & MPPE_128) {
! 649: memcpy(hash, b->params.msoft.nt_hash_hash, sizeof(hash));
! 650: KEYDEBUG((hash, sizeof(hash), "NT Password Hash Hash"));
! 651: KEYDEBUG((chal, CHAP_MSOFT_CHAL_LEN, "Challenge"));
! 652: MsoftGetStartKey(chal, hash);
! 653: KEYDEBUG((hash, sizeof(hash), "NT StartKey"));
! 654: } else {
! 655: memcpy(hash, b->params.msoft.lm_hash, 8);
! 656: KEYDEBUG((hash, sizeof(hash), "LM StartKey"));
! 657: }
! 658: memcpy(key0, hash, MPPE_KEY_LEN);
! 659: KEYDEBUG((key0, (bits & MPPE_128) ? 16 : 8, "InitialKey"));
! 660: return;
! 661: }
! 662:
! 663: /*
! 664: * MppeInitKeyv2()
! 665: */
! 666:
! 667: static void
! 668: MppeInitKeyv2(Bund b, MppcInfo mppc, int dir)
! 669: {
! 670: u_char *const key0 = (dir == COMP_DIR_XMIT) ?
! 671: mppc->xmit_key0 : mppc->recv_key0;
! 672: u_char hash[MPPE_KEY_LEN];
! 673: u_char *resp;
! 674:
! 675: if (b->params.msoft.has_keys)
! 676: {
! 677: memcpy(mppc->xmit_key0, b->params.msoft.xmit_key, MPPE_KEY_LEN);
! 678: memcpy(mppc->recv_key0, b->params.msoft.recv_key, MPPE_KEY_LEN);
! 679: return;
! 680: }
! 681:
! 682: /* The secret comes from the originating caller's credentials */
! 683: resp = b->params.msoft.ntResp;
! 684:
! 685: /* Compute basis for the session key (ie, "start key" or key0) */
! 686: memcpy(hash, b->params.msoft.nt_hash_hash, sizeof(hash));
! 687: KEYDEBUG((hash, sizeof(hash), "NT Password Hash Hash"));
! 688: KEYDEBUG((resp, CHAP_MSOFTv2_CHAL_LEN, "Response"));
! 689: MsoftGetMasterKey(resp, hash);
! 690: KEYDEBUG((hash, sizeof(hash), "GetMasterKey"));
! 691: MsoftGetAsymetricStartKey(hash,
! 692: (dir == COMP_DIR_RECV) ^
! 693: (b->originate == LINK_ORIGINATE_LOCAL));
! 694: KEYDEBUG((hash, sizeof(hash), "GetAsymmetricKey"));
! 695: memcpy(key0, hash, MPPE_KEY_LEN);
! 696: KEYDEBUG((key0, MPPE_KEY_LEN, "InitialKey"));
! 697: return;
! 698: }
! 699:
! 700: #ifdef DEBUG_KEYS
! 701:
! 702: /*
! 703: * KeyDebug()
! 704: */
! 705:
! 706: static void
! 707: KeyDebug(const u_char *data, int len, const char *fmt, ...)
! 708: {
! 709: char buf[100];
! 710: int k;
! 711: va_list args;
! 712:
! 713: va_start(args, fmt);
! 714: vsnprintf(buf, sizeof(buf), fmt, args);
! 715: va_end(args);
! 716: snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ":");
! 717: for (k = 0; k < len; k++) {
! 718: snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
! 719: " %02x", (u_char) data[k]);
! 720: }
! 721: Log(LG_ERR, ("%s", buf));
! 722: }
! 723:
! 724: #endif /* DEBUG_KEYS */
! 725:
! 726: static int
! 727: MppcKeyAvailable(Bund b, short type) {
! 728:
! 729: if (b->params.msoft.chap_alg == CHAP_ALG_MSOFT) {
! 730: if (((type == 128) && (!b->params.msoft.has_nt_hash)) ||
! 731: ((type != 128) && (!b->params.msoft.has_lm_hash))) {
! 732: return (0);
! 733: }
! 734: } else {
! 735: if (!b->params.msoft.has_keys && !b->params.msoft.has_nt_hash) {
! 736: return (0);
! 737: }
! 738: }
! 739: return (1);
! 740: }
! 741:
! 742: /*
! 743: * MppcTestCap()
! 744: */
! 745:
! 746: int
! 747: MppcTestCap(void)
! 748: {
! 749: struct ng_mppc_config conf;
! 750: struct ngm_mkpeer mp;
! 751: int cs, ds;
! 752:
! 753: /* Create a netgraph socket node */
! 754: if (NgMkSockNode(NULL, &cs, &ds) < 0) {
! 755: Perror("MppcTestCap: can't create socket node");
! 756: return(-1);
! 757: }
! 758:
! 759: /* Attach a new MPPC node */
! 760: strcpy(mp.type, NG_MPPC_NODE_TYPE);
! 761: strcpy(mp.ourhook, "mppc");
! 762: strcpy(mp.peerhook, NG_MPPC_HOOK_COMP);
! 763: if (NgSendMsg(cs, ".",
! 764: NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) {
! 765: Perror("MppcTestCap: can't create %s node", mp.type);
! 766: goto done;
! 767: }
! 768:
! 769: /* Initialize configuration structure */
! 770: memset(&conf, 0, sizeof(conf));
! 771: conf.enable = 1;
! 772: conf.bits = MPPC_BIT;
! 773:
! 774: /* Configure MPPC node */
! 775: if (NgSendMsg(cs, "mppc",
! 776: NGM_MPPC_COOKIE, NGM_MPPC_CONFIG_COMP, &conf, sizeof(conf)) < 0) {
! 777: if (errno != EPROTONOSUPPORT) {
! 778: Perror("MppcTestCap: can't config %s node", NG_MPPC_NODE_TYPE);
! 779: }
! 780: } else
! 781: MPPCPresent = 1;
! 782:
! 783: conf.bits = MPPE_128;
! 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: MPPEPresent = 1;
! 793:
! 794: /* Done */
! 795: done:
! 796: close(cs);
! 797: close(ds);
! 798: return(0);
! 799: }
! 800:
! 801: /*
! 802: * MppcStat()
! 803: */
! 804:
! 805: int
! 806: MppcStat(Context ctx, int ac, char *av[], void *arg)
! 807: {
! 808: MppcInfo const mppc = &ctx->bund->ccp.mppc;
! 809:
! 810: Printf("MPPC options:\r\n");
! 811: OptStat(ctx, &mppc->options, gConfList);
! 812:
! 813: return(0);
! 814: }
! 815:
! 816: /*
! 817: * MppcSetCommand()
! 818: */
! 819:
! 820: static int
! 821: MppcSetCommand(Context ctx, int ac, char *av[], void *arg)
! 822: {
! 823: MppcInfo const mppc = &ctx->bund->ccp.mppc;
! 824:
! 825: if (ac == 0)
! 826: return(-1);
! 827: switch ((intptr_t)arg) {
! 828: case SET_ACCEPT:
! 829: AcceptCommand(ac, av, &mppc->options, gConfList);
! 830: break;
! 831:
! 832: case SET_DENY:
! 833: DenyCommand(ac, av, &mppc->options, gConfList);
! 834: break;
! 835:
! 836: case SET_ENABLE:
! 837: EnableCommand(ac, av, &mppc->options, gConfList);
! 838: break;
! 839:
! 840: case SET_DISABLE:
! 841: DisableCommand(ac, av, &mppc->options, gConfList);
! 842: break;
! 843:
! 844: case SET_YES:
! 845: YesCommand(ac, av, &mppc->options, gConfList);
! 846: break;
! 847:
! 848: case SET_NO:
! 849: NoCommand(ac, av, &mppc->options, gConfList);
! 850: break;
! 851:
! 852: default:
! 853: assert(0);
! 854: }
! 855: return(0);
! 856: }
! 857:
! 858: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>