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

Cache object: 9c10973a7318771500d47b4899ddea0e


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