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

Cache object: c625ececa67b47f94ae9de90d6dbc7c6


[ 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.