The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netgraph/ng_mppc.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * ng_mppc.c
    3  */
    4 
    5 /*-
    6  * Copyright (c) 1996-2000 Whistle Communications, Inc.
    7  * All rights reserved.
    8  * 
    9  * Subject to the following obligations and disclaimer of warranty, use and
   10  * redistribution of this software, in source or object code forms, with or
   11  * without modifications are expressly permitted by Whistle Communications;
   12  * provided, however, that:
   13  * 1. Any and all reproductions of the source or object code must include the
   14  *    copyright notice above and the following disclaimer of warranties; and
   15  * 2. No rights are granted, in any manner or form, to use Whistle
   16  *    Communications, Inc. trademarks, including the mark "WHISTLE
   17  *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
   18  *    such appears in the above copyright notice or in the software.
   19  * 
   20  * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
   21  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
   22  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
   23  * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
   24  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
   25  * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
   26  * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
   27  * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
   28  * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
   29  * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
   30  * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
   31  * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
   32  * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
   33  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   34  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   35  * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
   36  * OF SUCH DAMAGE.
   37  *
   38  * Author: Archie Cobbs <archie@freebsd.org>
   39  *
   40  * $Whistle: ng_mppc.c,v 1.4 1999/11/25 00:10:12 archie Exp $
   41  * $FreeBSD: releng/10.1/sys/netgraph/ng_mppc.c 267093 2014-06-05 05:36:55Z mav $
   42  */
   43 
   44 /*
   45  * Microsoft PPP compression (MPPC) and encryption (MPPE) netgraph node type.
   46  *
   47  * You must define one or both of the NETGRAPH_MPPC_COMPRESSION and/or
   48  * NETGRAPH_MPPC_ENCRYPTION options for this node type to be useful.
   49  */
   50 
   51 #include <sys/param.h>
   52 #include <sys/systm.h>
   53 #include <sys/kernel.h>
   54 #include <sys/mbuf.h>
   55 #include <sys/malloc.h>
   56 #include <sys/endian.h>
   57 #include <sys/errno.h>
   58 #include <sys/sysctl.h>
   59 #include <sys/syslog.h>
   60 
   61 #include <netgraph/ng_message.h>
   62 #include <netgraph/netgraph.h>
   63 #include <netgraph/ng_mppc.h>
   64 
   65 #include "opt_netgraph.h"
   66 
   67 #if !defined(NETGRAPH_MPPC_COMPRESSION) && !defined(NETGRAPH_MPPC_ENCRYPTION)
   68 #ifdef KLD_MODULE
   69 /* XXX NETGRAPH_MPPC_COMPRESSION isn't functional yet */
   70 #define NETGRAPH_MPPC_ENCRYPTION
   71 #else
   72 /* This case is indicative of an error in sys/conf files */
   73 #error Need either NETGRAPH_MPPC_COMPRESSION or NETGRAPH_MPPC_ENCRYPTION
   74 #endif
   75 #endif
   76 
   77 #ifdef NG_SEPARATE_MALLOC
   78 static MALLOC_DEFINE(M_NETGRAPH_MPPC, "netgraph_mppc", "netgraph mppc node");
   79 #else
   80 #define M_NETGRAPH_MPPC M_NETGRAPH
   81 #endif
   82 
   83 #ifdef NETGRAPH_MPPC_COMPRESSION
   84 /* XXX this file doesn't exist yet, but hopefully someday it will... */
   85 #include <net/mppc.h>
   86 #endif
   87 #ifdef NETGRAPH_MPPC_ENCRYPTION
   88 #include <crypto/rc4/rc4.h>
   89 #endif
   90 #include <crypto/sha1.h>
   91 
   92 /* Decompression blowup */
   93 #define MPPC_DECOMP_BUFSIZE     8092            /* allocate buffer this big */
   94 #define MPPC_DECOMP_SAFETY      100             /*   plus this much margin */
   95 
   96 /* MPPC/MPPE header length */
   97 #define MPPC_HDRLEN             2
   98 
   99 /* Key length */
  100 #define KEYLEN(b)               (((b) & MPPE_128) ? 16 : 8)
  101 
  102 /*
  103  * When packets are lost with MPPE, we may have to re-key arbitrarily
  104  * many times to 'catch up' to the new jumped-ahead sequence number.
  105  * Since this can be expensive, we pose a limit on how many re-keyings
  106  * we will do at one time to avoid a possible D.O.S. vulnerability.
  107  * This should instead be a configurable parameter.
  108  */
  109 #define MPPE_MAX_REKEY          1000
  110 
  111 SYSCTL_NODE(_net_graph, OID_AUTO, mppe, CTLFLAG_RW, 0, "MPPE");
  112 
  113 static int mppe_block_on_max_rekey = 0;
  114 TUNABLE_INT("net.graph.mppe.block_on_max_rekey", &mppe_block_on_max_rekey);
  115 SYSCTL_INT(_net_graph_mppe, OID_AUTO, block_on_max_rekey, CTLFLAG_RW,
  116     &mppe_block_on_max_rekey, 0, "Block node on max MPPE key re-calculations");
  117 
  118 static int mppe_log_max_rekey = 1;
  119 TUNABLE_INT("net.graph.mppe.log_max_rekey", &mppe_log_max_rekey);
  120 SYSCTL_INT(_net_graph_mppe, OID_AUTO, log_max_rekey, CTLFLAG_RW,
  121     &mppe_log_max_rekey, 0, "Log max MPPE key re-calculations event");
  122 
  123 static int mppe_max_rekey = MPPE_MAX_REKEY;
  124 TUNABLE_INT("net.graph.mppe.max_rekey", &mppe_max_rekey);
  125 SYSCTL_INT(_net_graph_mppe, OID_AUTO, max_rekey, CTLFLAG_RW,
  126     &mppe_max_rekey, 0, "Maximum number of MPPE key re-calculations");
  127 
  128 /* MPPC packet header bits */
  129 #define MPPC_FLAG_FLUSHED       0x8000          /* xmitter reset state */
  130 #define MPPC_FLAG_RESTART       0x4000          /* compress history restart */
  131 #define MPPC_FLAG_COMPRESSED    0x2000          /* packet is compresed */
  132 #define MPPC_FLAG_ENCRYPTED     0x1000          /* packet is encrypted */
  133 #define MPPC_CCOUNT_MASK        0x0fff          /* sequence number mask */
  134 
  135 #define MPPC_CCOUNT_INC(d)      ((d) = (((d) + 1) & MPPC_CCOUNT_MASK))
  136 
  137 #define MPPE_UPDATE_MASK        0xff            /* coherency count when we're */
  138 #define MPPE_UPDATE_FLAG        0xff            /*   supposed to update key */
  139 
  140 #define MPPC_COMP_OK            0x05
  141 #define MPPC_DECOMP_OK          0x05
  142 
  143 /* Per direction info */
  144 struct ng_mppc_dir {
  145         struct ng_mppc_config   cfg;            /* configuration */
  146         hook_p                  hook;           /* netgraph hook */
  147         u_int16_t               cc:12;          /* coherency count */
  148         u_char                  flushed;        /* clean history (xmit only) */
  149 #ifdef NETGRAPH_MPPC_COMPRESSION
  150         u_char                  *history;       /* compression history */
  151 #endif
  152 #ifdef NETGRAPH_MPPC_ENCRYPTION
  153         u_char                  key[MPPE_KEY_LEN];      /* session key */
  154         struct rc4_state        rc4;                    /* rc4 state */
  155 #endif
  156 };
  157 
  158 /* Node private data */
  159 struct ng_mppc_private {
  160         struct ng_mppc_dir      xmit;           /* compress/encrypt config */
  161         struct ng_mppc_dir      recv;           /* decompress/decrypt config */
  162         ng_ID_t                 ctrlnode;       /* path to controlling node */
  163 };
  164 typedef struct ng_mppc_private *priv_p;
  165 
  166 /* Netgraph node methods */
  167 static ng_constructor_t ng_mppc_constructor;
  168 static ng_rcvmsg_t      ng_mppc_rcvmsg;
  169 static ng_shutdown_t    ng_mppc_shutdown;
  170 static ng_newhook_t     ng_mppc_newhook;
  171 static ng_rcvdata_t     ng_mppc_rcvdata;
  172 static ng_disconnect_t  ng_mppc_disconnect;
  173 
  174 /* Helper functions */
  175 static int      ng_mppc_compress(node_p node,
  176                         struct mbuf **datap);
  177 static int      ng_mppc_decompress(node_p node,
  178                         struct mbuf **datap);
  179 #ifdef NETGRAPH_MPPC_ENCRYPTION
  180 static void     ng_mppc_getkey(const u_char *h, u_char *h2, int len);
  181 static void     ng_mppc_updatekey(u_int32_t bits,
  182                         u_char *key0, u_char *key, struct rc4_state *rc4);
  183 #endif
  184 static void     ng_mppc_reset_req(node_p node);
  185 
  186 /* Node type descriptor */
  187 static struct ng_type ng_mppc_typestruct = {
  188         .version =      NG_ABI_VERSION,
  189         .name =         NG_MPPC_NODE_TYPE,
  190         .constructor =  ng_mppc_constructor,
  191         .rcvmsg =       ng_mppc_rcvmsg,
  192         .shutdown =     ng_mppc_shutdown,
  193         .newhook =      ng_mppc_newhook,
  194         .rcvdata =      ng_mppc_rcvdata,
  195         .disconnect =   ng_mppc_disconnect,
  196 };
  197 NETGRAPH_INIT(mppc, &ng_mppc_typestruct);
  198 
  199 #ifdef NETGRAPH_MPPC_ENCRYPTION
  200 /* Depend on separate rc4 module */
  201 MODULE_DEPEND(ng_mppc, rc4, 1, 1, 1);
  202 #endif
  203 
  204 /* Fixed bit pattern to weaken keysize down to 40 or 56 bits */
  205 static const u_char ng_mppe_weakenkey[3] = { 0xd1, 0x26, 0x9e };
  206 
  207 #define ERROUT(x)       do { error = (x); goto done; } while (0)
  208 
  209 /************************************************************************
  210                         NETGRAPH NODE STUFF
  211  ************************************************************************/
  212 
  213 /*
  214  * Node type constructor
  215  */
  216 static int
  217 ng_mppc_constructor(node_p node)
  218 {
  219         priv_p priv;
  220 
  221         /* Allocate private structure */
  222         priv = malloc(sizeof(*priv), M_NETGRAPH_MPPC, M_WAITOK | M_ZERO);
  223 
  224         NG_NODE_SET_PRIVATE(node, priv);
  225 
  226         /* This node is not thread safe. */
  227         NG_NODE_FORCE_WRITER(node);
  228 
  229         /* Done */
  230         return (0);
  231 }
  232 
  233 /*
  234  * Give our OK for a hook to be added
  235  */
  236 static int
  237 ng_mppc_newhook(node_p node, hook_p hook, const char *name)
  238 {
  239         const priv_p priv = NG_NODE_PRIVATE(node);
  240         hook_p *hookPtr;
  241 
  242         /* Check hook name */
  243         if (strcmp(name, NG_MPPC_HOOK_COMP) == 0)
  244                 hookPtr = &priv->xmit.hook;
  245         else if (strcmp(name, NG_MPPC_HOOK_DECOMP) == 0)
  246                 hookPtr = &priv->recv.hook;
  247         else
  248                 return (EINVAL);
  249 
  250         /* See if already connected */
  251         if (*hookPtr != NULL)
  252                 return (EISCONN);
  253 
  254         /* OK */
  255         *hookPtr = hook;
  256         return (0);
  257 }
  258 
  259 /*
  260  * Receive a control message
  261  */
  262 static int
  263 ng_mppc_rcvmsg(node_p node, item_p item, hook_p lasthook)
  264 {
  265         const priv_p priv = NG_NODE_PRIVATE(node);
  266         struct ng_mesg *resp = NULL;
  267         int error = 0;
  268         struct ng_mesg *msg;
  269 
  270         NGI_GET_MSG(item, msg);
  271         switch (msg->header.typecookie) {
  272         case NGM_MPPC_COOKIE:
  273                 switch (msg->header.cmd) {
  274                 case NGM_MPPC_CONFIG_COMP:
  275                 case NGM_MPPC_CONFIG_DECOMP:
  276                     {
  277                         struct ng_mppc_config *const cfg
  278                             = (struct ng_mppc_config *)msg->data;
  279                         const int isComp =
  280                             msg->header.cmd == NGM_MPPC_CONFIG_COMP;
  281                         struct ng_mppc_dir *const d = isComp ?
  282                             &priv->xmit : &priv->recv;
  283 
  284                         /* Check configuration */
  285                         if (msg->header.arglen != sizeof(*cfg))
  286                                 ERROUT(EINVAL);
  287                         if (cfg->enable) {
  288                                 if ((cfg->bits & ~MPPC_VALID_BITS) != 0)
  289                                         ERROUT(EINVAL);
  290 #ifndef NETGRAPH_MPPC_COMPRESSION
  291                                 if ((cfg->bits & MPPC_BIT) != 0)
  292                                         ERROUT(EPROTONOSUPPORT);
  293 #endif
  294 #ifndef NETGRAPH_MPPC_ENCRYPTION
  295                                 if ((cfg->bits & MPPE_BITS) != 0)
  296                                         ERROUT(EPROTONOSUPPORT);
  297 #endif
  298                         } else
  299                                 cfg->bits = 0;
  300 
  301                         /* Save return address so we can send reset-req's */
  302                         if (!isComp)
  303                                 priv->ctrlnode = NGI_RETADDR(item);
  304 
  305                         /* Configuration is OK, reset to it */
  306                         d->cfg = *cfg;
  307 
  308 #ifdef NETGRAPH_MPPC_COMPRESSION
  309                         /* Initialize state buffers for compression */
  310                         if (d->history != NULL) {
  311                                 free(d->history, M_NETGRAPH_MPPC);
  312                                 d->history = NULL;
  313                         }
  314                         if ((cfg->bits & MPPC_BIT) != 0) {
  315                                 d->history = malloc(isComp ?
  316                                     MPPC_SizeOfCompressionHistory() :
  317                                     MPPC_SizeOfDecompressionHistory(),
  318                                     M_NETGRAPH_MPPC, M_NOWAIT);
  319                                 if (d->history == NULL)
  320                                         ERROUT(ENOMEM);
  321                                 if (isComp)
  322                                         MPPC_InitCompressionHistory(d->history);
  323                                 else {
  324                                         MPPC_InitDecompressionHistory(
  325                                             d->history);
  326                                 }
  327                         }
  328 #endif
  329 
  330 #ifdef NETGRAPH_MPPC_ENCRYPTION
  331                         /* Generate initial session keys for encryption */
  332                         if ((cfg->bits & MPPE_BITS) != 0) {
  333                                 const int keylen = KEYLEN(cfg->bits);
  334 
  335                                 bcopy(cfg->startkey, d->key, keylen);
  336                                 ng_mppc_getkey(cfg->startkey, d->key, keylen);
  337                                 if ((cfg->bits & MPPE_40) != 0)
  338                                         bcopy(&ng_mppe_weakenkey, d->key, 3);
  339                                 else if ((cfg->bits & MPPE_56) != 0)
  340                                         bcopy(&ng_mppe_weakenkey, d->key, 1);
  341                                 rc4_init(&d->rc4, d->key, keylen);
  342                         }
  343 #endif
  344 
  345                         /* Initialize other state */
  346                         d->cc = 0;
  347                         d->flushed = 0;
  348                         break;
  349                     }
  350 
  351                 case NGM_MPPC_RESETREQ:
  352                         ng_mppc_reset_req(node);
  353                         break;
  354 
  355                 default:
  356                         error = EINVAL;
  357                         break;
  358                 }
  359                 break;
  360         default:
  361                 error = EINVAL;
  362                 break;
  363         }
  364 done:
  365         NG_RESPOND_MSG(error, node, item, resp);
  366         NG_FREE_MSG(msg);
  367         return (error);
  368 }
  369 
  370 /*
  371  * Receive incoming data on our hook.
  372  */
  373 static int
  374 ng_mppc_rcvdata(hook_p hook, item_p item)
  375 {
  376         const node_p node = NG_HOOK_NODE(hook);
  377         const priv_p priv = NG_NODE_PRIVATE(node);
  378         int error;
  379         struct mbuf *m;
  380 
  381         NGI_GET_M(item, m);
  382         /* Compress and/or encrypt */
  383         if (hook == priv->xmit.hook) {
  384                 if (!priv->xmit.cfg.enable) {
  385                         NG_FREE_M(m);
  386                         NG_FREE_ITEM(item);
  387                         return (ENXIO);
  388                 }
  389                 if ((error = ng_mppc_compress(node, &m)) != 0) {
  390                         NG_FREE_ITEM(item);
  391                         return(error);
  392                 }
  393                 NG_FWD_NEW_DATA(error, item, priv->xmit.hook, m);
  394                 return (error);
  395         }
  396 
  397         /* Decompress and/or decrypt */
  398         if (hook == priv->recv.hook) {
  399                 if (!priv->recv.cfg.enable) {
  400                         NG_FREE_M(m);
  401                         NG_FREE_ITEM(item);
  402                         return (ENXIO);
  403                 }
  404                 if ((error = ng_mppc_decompress(node, &m)) != 0) {
  405                         NG_FREE_ITEM(item);
  406                         if (error == EINVAL && priv->ctrlnode != 0) {
  407                                 struct ng_mesg *msg;
  408 
  409                                 /* Need to send a reset-request */
  410                                 NG_MKMESSAGE(msg, NGM_MPPC_COOKIE,
  411                                     NGM_MPPC_RESETREQ, 0, M_NOWAIT);
  412                                 if (msg == NULL)
  413                                         return (error);
  414                                 NG_SEND_MSG_ID(error, node, msg,
  415                                         priv->ctrlnode, 0); 
  416                         }
  417                         return (error);
  418                 }
  419                 NG_FWD_NEW_DATA(error, item, priv->recv.hook, m);
  420                 return (error);
  421         }
  422 
  423         /* Oops */
  424         panic("%s: unknown hook", __func__);
  425 }
  426 
  427 /*
  428  * Destroy node
  429  */
  430 static int
  431 ng_mppc_shutdown(node_p node)
  432 {
  433         const priv_p priv = NG_NODE_PRIVATE(node);
  434 
  435         /* Take down netgraph node */
  436 #ifdef NETGRAPH_MPPC_COMPRESSION
  437         if (priv->xmit.history != NULL)
  438                 free(priv->xmit.history, M_NETGRAPH_MPPC);
  439         if (priv->recv.history != NULL)
  440                 free(priv->recv.history, M_NETGRAPH_MPPC);
  441 #endif
  442         bzero(priv, sizeof(*priv));
  443         free(priv, M_NETGRAPH_MPPC);
  444         NG_NODE_SET_PRIVATE(node, NULL);
  445         NG_NODE_UNREF(node);            /* let the node escape */
  446         return (0);
  447 }
  448 
  449 /*
  450  * Hook disconnection
  451  */
  452 static int
  453 ng_mppc_disconnect(hook_p hook)
  454 {
  455         const node_p node = NG_HOOK_NODE(hook);
  456         const priv_p priv = NG_NODE_PRIVATE(node);
  457 
  458         /* Zero out hook pointer */
  459         if (hook == priv->xmit.hook)
  460                 priv->xmit.hook = NULL;
  461         if (hook == priv->recv.hook)
  462                 priv->recv.hook = NULL;
  463 
  464         /* Go away if no longer connected */
  465         if ((NG_NODE_NUMHOOKS(node) == 0)
  466         && NG_NODE_IS_VALID(node))
  467                 ng_rmnode_self(node);
  468         return (0);
  469 }
  470 
  471 /************************************************************************
  472                         HELPER STUFF
  473  ************************************************************************/
  474 
  475 /*
  476  * Compress/encrypt a packet and put the result in a new mbuf at *resultp.
  477  * The original mbuf is not free'd.
  478  */
  479 static int
  480 ng_mppc_compress(node_p node, struct mbuf **datap)
  481 {
  482         const priv_p priv = NG_NODE_PRIVATE(node);
  483         struct ng_mppc_dir *const d = &priv->xmit;
  484         u_int16_t header;
  485         struct mbuf *m = *datap;
  486 
  487         /* We must own the mbuf chain exclusively to modify it. */
  488         m = m_unshare(m, M_NOWAIT);
  489         if (m == NULL)
  490                 return (ENOMEM);
  491 
  492         /* Initialize */
  493         header = d->cc;
  494 
  495         /* Always set the flushed bit in stateless mode */
  496         if (d->flushed || ((d->cfg.bits & MPPE_STATELESS) != 0)) {
  497                 header |= MPPC_FLAG_FLUSHED;
  498                 d->flushed = 0;
  499         }
  500 
  501         /* Compress packet (if compression enabled) */
  502 #ifdef NETGRAPH_MPPC_COMPRESSION
  503         if ((d->cfg.bits & MPPC_BIT) != 0) {
  504                 u_short flags = MPPC_MANDATORY_COMPRESS_FLAGS;
  505                 u_char *inbuf, *outbuf;
  506                 int outlen, inlen, ina;
  507                 u_char *source, *dest;
  508                 u_long sourceCnt, destCnt;
  509                 int rtn;
  510 
  511                 /* Work with contiguous regions of memory. */
  512                 inlen = m->m_pkthdr.len;
  513                 if (m->m_next == NULL) {
  514                         inbuf = mtod(m, u_char *);
  515                         ina = 0;
  516                 } else {
  517                         inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT);
  518                         if (inbuf == NULL)
  519                                 goto err1;
  520                         m_copydata(m, 0, inlen, (caddr_t)inbuf);
  521                         ina = 1;
  522                 }
  523 
  524                 outlen = MPPC_MAX_BLOWUP(inlen);
  525                 outbuf = malloc(outlen, M_NETGRAPH_MPPC, M_NOWAIT);
  526                 if (outbuf == NULL) {
  527                         if (ina)
  528                                 free(inbuf, M_NETGRAPH_MPPC);
  529 err1:
  530                         m_freem(m);
  531                         MPPC_InitCompressionHistory(d->history);
  532                         d->flushed = 1;
  533                         return (ENOMEM);
  534                 }
  535 
  536                 /* Prepare to compress */
  537                 source = inbuf;
  538                 sourceCnt = inlen;
  539                 dest = outbuf;
  540                 destCnt = outlen;
  541                 if ((d->cfg.bits & MPPE_STATELESS) == 0)
  542                         flags |= MPPC_SAVE_HISTORY;
  543 
  544                 /* Compress */
  545                 rtn = MPPC_Compress(&source, &dest, &sourceCnt,
  546                         &destCnt, d->history, flags, 0);
  547 
  548                 /* Check return value */
  549                 KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__));
  550                 if ((rtn & MPPC_EXPANDED) == 0
  551                     && (rtn & MPPC_COMP_OK) == MPPC_COMP_OK) {
  552                         outlen -= destCnt;     
  553                         header |= MPPC_FLAG_COMPRESSED;
  554                         if ((rtn & MPPC_RESTART_HISTORY) != 0)
  555                                 header |= MPPC_FLAG_RESTART;  
  556                                 
  557                         /* Replace m by the compresed one. */
  558                         m_copyback(m, 0, outlen, (caddr_t)outbuf);
  559                         if (m->m_pkthdr.len < outlen) {
  560                                 m_freem(m);
  561                                 m = NULL;
  562                         } else if (outlen < m->m_pkthdr.len)
  563                                 m_adj(m, outlen - m->m_pkthdr.len);
  564                 }
  565                 d->flushed = (rtn & MPPC_EXPANDED) != 0
  566                     || (flags & MPPC_SAVE_HISTORY) == 0;
  567 
  568                 if (ina)
  569                         free(inbuf, M_NETGRAPH_MPPC);
  570                 free(outbuf, M_NETGRAPH_MPPC);
  571 
  572                 /* Check mbuf chain reload result. */
  573                 if (m == NULL) {
  574                         if (!d->flushed) {
  575                                 MPPC_InitCompressionHistory(d->history);
  576                                 d->flushed = 1;
  577                         }
  578                         return (ENOMEM);
  579                 }
  580         }
  581 #endif
  582 
  583         /* Now encrypt packet (if encryption enabled) */
  584 #ifdef NETGRAPH_MPPC_ENCRYPTION
  585         if ((d->cfg.bits & MPPE_BITS) != 0) {
  586                 struct mbuf *m1;
  587 
  588                 /* Set header bits */
  589                 header |= MPPC_FLAG_ENCRYPTED;
  590 
  591                 /* Update key if it's time */
  592                 if ((d->cfg.bits & MPPE_STATELESS) != 0
  593                     || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) {
  594                         ng_mppc_updatekey(d->cfg.bits,
  595                             d->cfg.startkey, d->key, &d->rc4);
  596                 } else if ((header & MPPC_FLAG_FLUSHED) != 0) {
  597                         /* Need to reset key if we say we did 
  598                            and ng_mppc_updatekey wasn't called to do it also. */
  599                         rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
  600                 }
  601 
  602                 /* Encrypt packet */
  603                 m1 = m;
  604                 while (m1) {
  605                         rc4_crypt(&d->rc4, mtod(m1, u_char *),
  606                             mtod(m1, u_char *), m1->m_len);
  607                         m1 = m1->m_next;
  608                 }
  609         }
  610 #endif
  611 
  612         /* Update coherency count for next time (12 bit arithmetic) */
  613         MPPC_CCOUNT_INC(d->cc);
  614 
  615         /* Install header */
  616         M_PREPEND(m, MPPC_HDRLEN, M_NOWAIT);
  617         if (m != NULL)
  618                 be16enc(mtod(m, void *), header);
  619 
  620         *datap = m;
  621         return (*datap == NULL ? ENOBUFS : 0);
  622 }
  623 
  624 /*
  625  * Decompress/decrypt packet and put the result in a new mbuf at *resultp.
  626  * The original mbuf is not free'd.
  627  */
  628 static int
  629 ng_mppc_decompress(node_p node, struct mbuf **datap)
  630 {
  631         const priv_p priv = NG_NODE_PRIVATE(node);
  632         struct ng_mppc_dir *const d = &priv->recv;
  633         u_int16_t header, cc;
  634         u_int numLost;
  635         struct mbuf *m = *datap;
  636 
  637         /* We must own the mbuf chain exclusively to modify it. */
  638         m = m_unshare(m, M_NOWAIT);
  639         if (m == NULL)
  640                 return (ENOMEM);
  641 
  642         /* Pull off header */
  643         if (m->m_pkthdr.len < MPPC_HDRLEN) {
  644                 m_freem(m);
  645                 return (EINVAL);
  646         }
  647         header = be16dec(mtod(m, void *));
  648         cc = (header & MPPC_CCOUNT_MASK);
  649         m_adj(m, MPPC_HDRLEN);
  650 
  651         /* Check for an unexpected jump in the sequence number */
  652         numLost = ((cc - d->cc) & MPPC_CCOUNT_MASK);
  653 
  654         /* If flushed bit set, we can always handle packet */
  655         if ((header & MPPC_FLAG_FLUSHED) != 0) {
  656 #ifdef NETGRAPH_MPPC_COMPRESSION
  657                 if (d->history != NULL)
  658                         MPPC_InitDecompressionHistory(d->history);
  659 #endif
  660 #ifdef NETGRAPH_MPPC_ENCRYPTION
  661                 if ((d->cfg.bits & MPPE_BITS) != 0) {
  662                         u_int rekey;
  663 
  664                         /* How many times are we going to have to re-key? */
  665                         rekey = ((d->cfg.bits & MPPE_STATELESS) != 0) ?
  666                             numLost : (numLost / (MPPE_UPDATE_MASK + 1));
  667                         if (rekey > mppe_max_rekey) {
  668                             if (mppe_block_on_max_rekey) {
  669                                 if (mppe_log_max_rekey) {
  670                                     log(LOG_ERR, "%s: too many (%d) packets"
  671                                         " dropped, disabling node %p!\n",
  672                                         __func__, numLost, node);
  673                                 }
  674                                 priv->recv.cfg.enable = 0;
  675                                 goto failed;
  676                             } else {
  677                                 if (mppe_log_max_rekey) {
  678                                     log(LOG_ERR, "%s: %d packets"
  679                                         " dropped, node %p\n",
  680                                         __func__, numLost, node);
  681                                 }
  682                                 goto failed;
  683                             }
  684                         }
  685 
  686                         /* Re-key as necessary to catch up to peer */
  687                         while (d->cc != cc) {
  688                                 if ((d->cfg.bits & MPPE_STATELESS) != 0
  689                                     || (d->cc & MPPE_UPDATE_MASK)
  690                                       == MPPE_UPDATE_FLAG) {
  691                                         ng_mppc_updatekey(d->cfg.bits,
  692                                             d->cfg.startkey, d->key, &d->rc4);
  693                                 }
  694                                 MPPC_CCOUNT_INC(d->cc);
  695                         }
  696 
  697                         /* Reset key (except in stateless mode, see below) */
  698                         if ((d->cfg.bits & MPPE_STATELESS) == 0)
  699                                 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
  700                 }
  701 #endif
  702                 d->cc = cc;             /* skip over lost seq numbers */
  703                 numLost = 0;            /* act like no packets were lost */
  704         }
  705 
  706         /* Can't decode non-sequential packets without a flushed bit */
  707         if (numLost != 0)
  708                 goto failed;
  709 
  710         /* Decrypt packet */
  711         if ((header & MPPC_FLAG_ENCRYPTED) != 0) {
  712 #ifdef NETGRAPH_MPPC_ENCRYPTION
  713                 struct mbuf *m1;
  714 #endif
  715 
  716                 /* Are we not expecting encryption? */
  717                 if ((d->cfg.bits & MPPE_BITS) == 0) {
  718                         log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
  719                                 __func__, "encrypted");
  720                         goto failed;
  721                 }
  722 
  723 #ifdef NETGRAPH_MPPC_ENCRYPTION
  724                 /* Update key if it's time (always in stateless mode) */
  725                 if ((d->cfg.bits & MPPE_STATELESS) != 0
  726                     || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) {
  727                         ng_mppc_updatekey(d->cfg.bits,
  728                             d->cfg.startkey, d->key, &d->rc4);
  729                 }
  730 
  731                 /* Decrypt packet */
  732                 m1 = m;
  733                 while (m1 != NULL) {
  734                         rc4_crypt(&d->rc4, mtod(m1, u_char *),
  735                             mtod(m1, u_char *), m1->m_len);
  736                         m1 = m1->m_next;
  737                 }
  738 #endif
  739         } else {
  740 
  741                 /* Are we expecting encryption? */
  742                 if ((d->cfg.bits & MPPE_BITS) != 0) {
  743                         log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
  744                                 __func__, "unencrypted");
  745                         goto failed;
  746                 }
  747         }
  748 
  749         /* Update coherency count for next time (12 bit arithmetic) */
  750         MPPC_CCOUNT_INC(d->cc);
  751 
  752         /* Check for unexpected compressed packet */
  753         if ((header & MPPC_FLAG_COMPRESSED) != 0
  754             && (d->cfg.bits & MPPC_BIT) == 0) {
  755                 log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
  756                         __func__, "compressed");
  757 failed:
  758                 m_freem(m);
  759                 return (EINVAL);
  760         }
  761 
  762 #ifdef NETGRAPH_MPPC_COMPRESSION
  763         /* Decompress packet */
  764         if ((header & MPPC_FLAG_COMPRESSED) != 0) {
  765                 int flags = MPPC_MANDATORY_DECOMPRESS_FLAGS;
  766                 u_char *inbuf, *outbuf;
  767                 int inlen, outlen, ina;
  768                 u_char *source, *dest;
  769                 u_long sourceCnt, destCnt;
  770                 int rtn;
  771 
  772                 /* Copy payload into a contiguous region of memory. */
  773                 inlen = m->m_pkthdr.len;
  774                 if (m->m_next == NULL) {
  775                         inbuf = mtod(m, u_char *);
  776                         ina = 0;
  777                 } else {
  778                         inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT);
  779                         if (inbuf == NULL) {
  780                                 m_freem(m);
  781                                 return (ENOMEM);
  782                         }
  783                         m_copydata(m, 0, inlen, (caddr_t)inbuf);
  784                         ina = 1;
  785                 }
  786 
  787                 /* Allocate a buffer for decompressed data */
  788                 outbuf = malloc(MPPC_DECOMP_BUFSIZE + MPPC_DECOMP_SAFETY,
  789                     M_NETGRAPH_MPPC, M_NOWAIT);
  790                 if (outbuf == NULL) {
  791                         m_freem(m);
  792                         if (ina)
  793                                 free(inbuf, M_NETGRAPH_MPPC);
  794                         return (ENOMEM);
  795                 }
  796                 outlen = MPPC_DECOMP_BUFSIZE;
  797 
  798                 /* Prepare to decompress */
  799                 source = inbuf;
  800                 sourceCnt = inlen;
  801                 dest = outbuf;
  802                 destCnt = outlen;
  803                 if ((header & MPPC_FLAG_RESTART) != 0)
  804                         flags |= MPPC_RESTART_HISTORY;
  805 
  806                 /* Decompress */
  807                 rtn = MPPC_Decompress(&source, &dest,
  808                         &sourceCnt, &destCnt, d->history, flags);
  809 
  810                 /* Check return value */
  811                 KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__));
  812                 if ((rtn & MPPC_DEST_EXHAUSTED) != 0
  813                     || (rtn & MPPC_DECOMP_OK) != MPPC_DECOMP_OK) {
  814                         log(LOG_ERR, "%s: decomp returned 0x%x",
  815                             __func__, rtn);
  816                         if (ina)
  817                                 free(inbuf, M_NETGRAPH_MPPC);
  818                         free(outbuf, M_NETGRAPH_MPPC);
  819                         goto failed;
  820                 }
  821 
  822                 /* Replace compressed data with decompressed data */
  823                 if (ina)
  824                         free(inbuf, M_NETGRAPH_MPPC);
  825                 outlen -= destCnt;
  826         
  827                 m_copyback(m, 0, outlen, (caddr_t)outbuf);
  828                 if (m->m_pkthdr.len < outlen) {
  829                         m_freem(m);
  830                         m = NULL;
  831                 } else if (outlen < m->m_pkthdr.len)
  832                         m_adj(m, outlen - m->m_pkthdr.len);
  833                 free(outbuf, M_NETGRAPH_MPPC);
  834         }
  835 #endif
  836 
  837         /* Return result in an mbuf */
  838         *datap = m;
  839         return (*datap == NULL ? ENOBUFS : 0);
  840 }
  841 
  842 /*
  843  * The peer has sent us a CCP ResetRequest, so reset our transmit state.
  844  */
  845 static void
  846 ng_mppc_reset_req(node_p node)
  847 {   
  848         const priv_p priv = NG_NODE_PRIVATE(node);
  849         struct ng_mppc_dir *const d = &priv->xmit;
  850 
  851 #ifdef NETGRAPH_MPPC_COMPRESSION
  852         if (d->history != NULL)
  853                 MPPC_InitCompressionHistory(d->history);
  854 #endif
  855 #ifdef NETGRAPH_MPPC_ENCRYPTION
  856         if ((d->cfg.bits & MPPE_STATELESS) == 0)
  857                 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
  858 #endif
  859         d->flushed = 1;
  860 }   
  861 
  862 #ifdef NETGRAPH_MPPC_ENCRYPTION
  863 /*
  864  * Generate a new encryption key
  865  */
  866 static void
  867 ng_mppc_getkey(const u_char *h, u_char *h2, int len)
  868 {
  869         static const u_char pad1[40] =
  870             { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  871               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  872               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  873               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
  874         static const u_char pad2[40] =
  875             { 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
  876               0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
  877               0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
  878               0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2 };
  879         u_char hash[20];
  880         SHA1_CTX c;
  881 
  882         SHA1Init(&c);
  883         SHA1Update(&c, h, len);
  884         SHA1Update(&c, pad1, sizeof(pad1));
  885         SHA1Update(&c, h2, len);
  886         SHA1Update(&c, pad2, sizeof(pad2));
  887         SHA1Final(hash, &c);
  888         bcopy(hash, h2, len);
  889 }
  890 
  891 /*
  892  * Update the encryption key
  893  */
  894 static void
  895 ng_mppc_updatekey(u_int32_t bits,
  896         u_char *key0, u_char *key, struct rc4_state *rc4)
  897 { 
  898         const int keylen = KEYLEN(bits);
  899 
  900         ng_mppc_getkey(key0, key, keylen);
  901         rc4_init(rc4, key, keylen);
  902         rc4_crypt(rc4, key, key, keylen);
  903         if ((bits & MPPE_40) != 0)
  904                 bcopy(&ng_mppe_weakenkey, key, 3);
  905         else if ((bits & MPPE_56) != 0)
  906                 bcopy(&ng_mppe_weakenkey, key, 1);
  907         rc4_init(rc4, key, keylen);
  908 }
  909 #endif
  910 

Cache object: b73ec37d1464d5b1812f7888f91dcf36


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.