File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / mpd / src / ccp_mppc.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jul 22 08:44:29 2013 UTC (10 years, 11 months ago) by misho
Branches: mpd, MAIN
CVS tags: v5_8p7, v5_8p1_cross, v5_8p1, v5_8, v5_7p0, v5_7, v5_6, HEAD
5.7

    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>