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/8.2/sys/netgraph/ng_mppc.c 206661 2010-04-15 12:46:16Z 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/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 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_NOWAIT | M_ZERO);
  205         if (priv == NULL)
  206                 return (ENOMEM);
  207 
  208         NG_NODE_SET_PRIVATE(node, priv);
  209 
  210         /* This node is not thread safe. */
  211         NG_NODE_FORCE_WRITER(node);
  212 
  213         /* Done */
  214         return (0);
  215 }
  216 
  217 /*
  218  * Give our OK for a hook to be added
  219  */
  220 static int
  221 ng_mppc_newhook(node_p node, hook_p hook, const char *name)
  222 {
  223         const priv_p priv = NG_NODE_PRIVATE(node);
  224         hook_p *hookPtr;
  225 
  226         /* Check hook name */
  227         if (strcmp(name, NG_MPPC_HOOK_COMP) == 0)
  228                 hookPtr = &priv->xmit.hook;
  229         else if (strcmp(name, NG_MPPC_HOOK_DECOMP) == 0)
  230                 hookPtr = &priv->recv.hook;
  231         else
  232                 return (EINVAL);
  233 
  234         /* See if already connected */
  235         if (*hookPtr != NULL)
  236                 return (EISCONN);
  237 
  238         /* OK */
  239         *hookPtr = hook;
  240         return (0);
  241 }
  242 
  243 /*
  244  * Receive a control message
  245  */
  246 static int
  247 ng_mppc_rcvmsg(node_p node, item_p item, hook_p lasthook)
  248 {
  249         const priv_p priv = NG_NODE_PRIVATE(node);
  250         struct ng_mesg *resp = NULL;
  251         int error = 0;
  252         struct ng_mesg *msg;
  253 
  254         NGI_GET_MSG(item, msg);
  255         switch (msg->header.typecookie) {
  256         case NGM_MPPC_COOKIE:
  257                 switch (msg->header.cmd) {
  258                 case NGM_MPPC_CONFIG_COMP:
  259                 case NGM_MPPC_CONFIG_DECOMP:
  260                     {
  261                         struct ng_mppc_config *const cfg
  262                             = (struct ng_mppc_config *)msg->data;
  263                         const int isComp =
  264                             msg->header.cmd == NGM_MPPC_CONFIG_COMP;
  265                         struct ng_mppc_dir *const d = isComp ?
  266                             &priv->xmit : &priv->recv;
  267 
  268                         /* Check configuration */
  269                         if (msg->header.arglen != sizeof(*cfg))
  270                                 ERROUT(EINVAL);
  271                         if (cfg->enable) {
  272                                 if ((cfg->bits & ~MPPC_VALID_BITS) != 0)
  273                                         ERROUT(EINVAL);
  274 #ifndef NETGRAPH_MPPC_COMPRESSION
  275                                 if ((cfg->bits & MPPC_BIT) != 0)
  276                                         ERROUT(EPROTONOSUPPORT);
  277 #endif
  278 #ifndef NETGRAPH_MPPC_ENCRYPTION
  279                                 if ((cfg->bits & MPPE_BITS) != 0)
  280                                         ERROUT(EPROTONOSUPPORT);
  281 #endif
  282                         } else
  283                                 cfg->bits = 0;
  284 
  285                         /* Save return address so we can send reset-req's */
  286                         if (!isComp)
  287                                 priv->ctrlnode = NGI_RETADDR(item);
  288 
  289                         /* Configuration is OK, reset to it */
  290                         d->cfg = *cfg;
  291 
  292 #ifdef NETGRAPH_MPPC_COMPRESSION
  293                         /* Initialize state buffers for compression */
  294                         if (d->history != NULL) {
  295                                 free(d->history, M_NETGRAPH_MPPC);
  296                                 d->history = NULL;
  297                         }
  298                         if ((cfg->bits & MPPC_BIT) != 0) {
  299                                 d->history = malloc(isComp ?
  300                                     MPPC_SizeOfCompressionHistory() :
  301                                     MPPC_SizeOfDecompressionHistory(),
  302                                     M_NETGRAPH_MPPC, M_NOWAIT);
  303                                 if (d->history == NULL)
  304                                         ERROUT(ENOMEM);
  305                                 if (isComp)
  306                                         MPPC_InitCompressionHistory(d->history);
  307                                 else {
  308                                         MPPC_InitDecompressionHistory(
  309                                             d->history);
  310                                 }
  311                         }
  312 #endif
  313 
  314 #ifdef NETGRAPH_MPPC_ENCRYPTION
  315                         /* Generate initial session keys for encryption */
  316                         if ((cfg->bits & MPPE_BITS) != 0) {
  317                                 const int keylen = KEYLEN(cfg->bits);
  318 
  319                                 bcopy(cfg->startkey, d->key, keylen);
  320                                 ng_mppc_getkey(cfg->startkey, d->key, keylen);
  321                                 if ((cfg->bits & MPPE_40) != 0)
  322                                         bcopy(&ng_mppe_weakenkey, d->key, 3);
  323                                 else if ((cfg->bits & MPPE_56) != 0)
  324                                         bcopy(&ng_mppe_weakenkey, d->key, 1);
  325                                 rc4_init(&d->rc4, d->key, keylen);
  326                         }
  327 #endif
  328 
  329                         /* Initialize other state */
  330                         d->cc = 0;
  331                         d->flushed = 0;
  332                         break;
  333                     }
  334 
  335                 case NGM_MPPC_RESETREQ:
  336                         ng_mppc_reset_req(node);
  337                         break;
  338 
  339                 default:
  340                         error = EINVAL;
  341                         break;
  342                 }
  343                 break;
  344         default:
  345                 error = EINVAL;
  346                 break;
  347         }
  348 done:
  349         NG_RESPOND_MSG(error, node, item, resp);
  350         NG_FREE_MSG(msg);
  351         return (error);
  352 }
  353 
  354 /*
  355  * Receive incoming data on our hook.
  356  */
  357 static int
  358 ng_mppc_rcvdata(hook_p hook, item_p item)
  359 {
  360         const node_p node = NG_HOOK_NODE(hook);
  361         const priv_p priv = NG_NODE_PRIVATE(node);
  362         int error;
  363         struct mbuf *m;
  364 
  365         NGI_GET_M(item, m);
  366         /* Compress and/or encrypt */
  367         if (hook == priv->xmit.hook) {
  368                 if (!priv->xmit.cfg.enable) {
  369                         NG_FREE_M(m);
  370                         NG_FREE_ITEM(item);
  371                         return (ENXIO);
  372                 }
  373                 if ((error = ng_mppc_compress(node, &m)) != 0) {
  374                         NG_FREE_ITEM(item);
  375                         return(error);
  376                 }
  377                 NG_FWD_NEW_DATA(error, item, priv->xmit.hook, m);
  378                 return (error);
  379         }
  380 
  381         /* Decompress and/or decrypt */
  382         if (hook == priv->recv.hook) {
  383                 if (!priv->recv.cfg.enable) {
  384                         NG_FREE_M(m);
  385                         NG_FREE_ITEM(item);
  386                         return (ENXIO);
  387                 }
  388                 if ((error = ng_mppc_decompress(node, &m)) != 0) {
  389                         NG_FREE_ITEM(item);
  390                         if (error == EINVAL && priv->ctrlnode != 0) {
  391                                 struct ng_mesg *msg;
  392 
  393                                 /* Need to send a reset-request */
  394                                 NG_MKMESSAGE(msg, NGM_MPPC_COOKIE,
  395                                     NGM_MPPC_RESETREQ, 0, M_NOWAIT);
  396                                 if (msg == NULL)
  397                                         return (error);
  398                                 NG_SEND_MSG_ID(error, node, msg,
  399                                         priv->ctrlnode, 0); 
  400                         }
  401                         return (error);
  402                 }
  403                 NG_FWD_NEW_DATA(error, item, priv->recv.hook, m);
  404                 return (error);
  405         }
  406 
  407         /* Oops */
  408         panic("%s: unknown hook", __func__);
  409 #ifdef RESTARTABLE_PANICS
  410         return (EINVAL);
  411 #endif
  412 }
  413 
  414 /*
  415  * Destroy node
  416  */
  417 static int
  418 ng_mppc_shutdown(node_p node)
  419 {
  420         const priv_p priv = NG_NODE_PRIVATE(node);
  421 
  422         /* Take down netgraph node */
  423 #ifdef NETGRAPH_MPPC_COMPRESSION
  424         if (priv->xmit.history != NULL)
  425                 free(priv->xmit.history, M_NETGRAPH_MPPC);
  426         if (priv->recv.history != NULL)
  427                 free(priv->recv.history, M_NETGRAPH_MPPC);
  428 #endif
  429         bzero(priv, sizeof(*priv));
  430         free(priv, M_NETGRAPH_MPPC);
  431         NG_NODE_SET_PRIVATE(node, NULL);
  432         NG_NODE_UNREF(node);            /* let the node escape */
  433         return (0);
  434 }
  435 
  436 /*
  437  * Hook disconnection
  438  */
  439 static int
  440 ng_mppc_disconnect(hook_p hook)
  441 {
  442         const node_p node = NG_HOOK_NODE(hook);
  443         const priv_p priv = NG_NODE_PRIVATE(node);
  444 
  445         /* Zero out hook pointer */
  446         if (hook == priv->xmit.hook)
  447                 priv->xmit.hook = NULL;
  448         if (hook == priv->recv.hook)
  449                 priv->recv.hook = NULL;
  450 
  451         /* Go away if no longer connected */
  452         if ((NG_NODE_NUMHOOKS(node) == 0)
  453         && NG_NODE_IS_VALID(node))
  454                 ng_rmnode_self(node);
  455         return (0);
  456 }
  457 
  458 /************************************************************************
  459                         HELPER STUFF
  460  ************************************************************************/
  461 
  462 /*
  463  * Compress/encrypt a packet and put the result in a new mbuf at *resultp.
  464  * The original mbuf is not free'd.
  465  */
  466 static int
  467 ng_mppc_compress(node_p node, struct mbuf **datap)
  468 {
  469         const priv_p priv = NG_NODE_PRIVATE(node);
  470         struct ng_mppc_dir *const d = &priv->xmit;
  471         u_int16_t header;
  472         struct mbuf *m = *datap;
  473 
  474         /* We must own the mbuf chain exclusively to modify it. */
  475         m = m_unshare(m, M_DONTWAIT);
  476         if (m == NULL)
  477                 return (ENOMEM);
  478 
  479         /* Initialize */
  480         header = d->cc;
  481 
  482         /* Always set the flushed bit in stateless mode */
  483         if (d->flushed || ((d->cfg.bits & MPPE_STATELESS) != 0)) {
  484                 header |= MPPC_FLAG_FLUSHED;
  485                 d->flushed = 0;
  486         }
  487 
  488         /* Compress packet (if compression enabled) */
  489 #ifdef NETGRAPH_MPPC_COMPRESSION
  490         if ((d->cfg.bits & MPPC_BIT) != 0) {
  491                 u_short flags = MPPC_MANDATORY_COMPRESS_FLAGS;
  492                 u_char *inbuf, *outbuf;
  493                 int outlen, inlen, ina;
  494                 u_char *source, *dest;
  495                 u_long sourceCnt, destCnt;
  496                 int rtn;
  497 
  498                 /* Work with contiguous regions of memory. */
  499                 inlen = m->m_pkthdr.len;
  500                 if (m->m_next == NULL) {
  501                         inbuf = mtod(m, u_char *);
  502                         ina = 0;
  503                 } else {
  504                         inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT);
  505                         if (inbuf == NULL)
  506                                 goto err1;
  507                         m_copydata(m, 0, inlen, (caddr_t)inbuf);
  508                         ina = 1;
  509                 }
  510 
  511                 outlen = MPPC_MAX_BLOWUP(inlen);
  512                 outbuf = malloc(outlen, M_NETGRAPH_MPPC, M_NOWAIT);
  513                 if (outbuf == NULL) {
  514                         if (ina)
  515                                 free(inbuf, M_NETGRAPH_MPPC);
  516 err1:
  517                         m_freem(m);
  518                         MPPC_InitCompressionHistory(d->history);
  519                         d->flushed = 1;
  520                         return (ENOMEM);
  521                 }
  522 
  523                 /* Prepare to compress */
  524                 source = inbuf;
  525                 sourceCnt = inlen;
  526                 dest = outbuf;
  527                 destCnt = outlen;
  528                 if ((d->cfg.bits & MPPE_STATELESS) == 0)
  529                         flags |= MPPC_SAVE_HISTORY;
  530 
  531                 /* Compress */
  532                 rtn = MPPC_Compress(&source, &dest, &sourceCnt,
  533                         &destCnt, d->history, flags, 0);
  534 
  535                 /* Check return value */
  536                 KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__));
  537                 if ((rtn & MPPC_EXPANDED) == 0
  538                     && (rtn & MPPC_COMP_OK) == MPPC_COMP_OK) {
  539                         outlen -= destCnt;     
  540                         header |= MPPC_FLAG_COMPRESSED;
  541                         if ((rtn & MPPC_RESTART_HISTORY) != 0)
  542                                 header |= MPPC_FLAG_RESTART;  
  543                                 
  544                         /* Replace m by the compresed one. */
  545                         m_copyback(m, 0, outlen, (caddr_t)outbuf);
  546                         if (m->m_pkthdr.len < outlen) {
  547                                 m_freem(m);
  548                                 m = NULL;
  549                         } else if (outlen < m->m_pkthdr.len)
  550                                 m_adj(m, outlen - m->m_pkthdr.len);
  551                 }
  552                 d->flushed = (rtn & MPPC_EXPANDED) != 0
  553                     || (flags & MPPC_SAVE_HISTORY) == 0;
  554 
  555                 if (ina)
  556                         free(inbuf, M_NETGRAPH_MPPC);
  557                 free(outbuf, M_NETGRAPH_MPPC);
  558 
  559                 /* Check mbuf chain reload result. */
  560                 if (m == NULL) {
  561                         if (!d->flushed) {
  562                                 MPPC_InitCompressionHistory(d->history);
  563                                 d->flushed = 1;
  564                         }
  565                         return (ENOMEM);
  566                 }
  567         }
  568 #endif
  569 
  570         /* Now encrypt packet (if encryption enabled) */
  571 #ifdef NETGRAPH_MPPC_ENCRYPTION
  572         if ((d->cfg.bits & MPPE_BITS) != 0) {
  573                 struct mbuf *m1;
  574 
  575                 /* Set header bits */
  576                 header |= MPPC_FLAG_ENCRYPTED;
  577 
  578                 /* Update key if it's time */
  579                 if ((d->cfg.bits & MPPE_STATELESS) != 0
  580                     || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) {
  581                         ng_mppc_updatekey(d->cfg.bits,
  582                             d->cfg.startkey, d->key, &d->rc4);
  583                 } else if ((header & MPPC_FLAG_FLUSHED) != 0) {
  584                         /* Need to reset key if we say we did 
  585                            and ng_mppc_updatekey wasn't called to do it also. */
  586                         rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
  587                 }
  588 
  589                 /* Encrypt packet */
  590                 m1 = m;
  591                 while (m1) {
  592                         rc4_crypt(&d->rc4, mtod(m1, u_char *),
  593                             mtod(m1, u_char *), m1->m_len);
  594                         m1 = m1->m_next;
  595                 }
  596         }
  597 #endif
  598 
  599         /* Update coherency count for next time (12 bit arithmetic) */
  600         MPPC_CCOUNT_INC(d->cc);
  601 
  602         /* Install header */
  603         M_PREPEND(m, MPPC_HDRLEN, M_DONTWAIT);
  604         if (m != NULL)
  605                 be16enc(mtod(m, void *), header);
  606 
  607         *datap = m;
  608         return (*datap == NULL ? ENOBUFS : 0);
  609 }
  610 
  611 /*
  612  * Decompress/decrypt packet and put the result in a new mbuf at *resultp.
  613  * The original mbuf is not free'd.
  614  */
  615 static int
  616 ng_mppc_decompress(node_p node, struct mbuf **datap)
  617 {
  618         const priv_p priv = NG_NODE_PRIVATE(node);
  619         struct ng_mppc_dir *const d = &priv->recv;
  620         u_int16_t header, cc;
  621         u_int numLost;
  622         struct mbuf *m = *datap;
  623 
  624         /* We must own the mbuf chain exclusively to modify it. */
  625         m = m_unshare(m, M_DONTWAIT);
  626         if (m == NULL)
  627                 return (ENOMEM);
  628 
  629         /* Pull off header */
  630         if (m->m_pkthdr.len < MPPC_HDRLEN) {
  631                 m_freem(m);
  632                 return (EINVAL);
  633         }
  634         header = be16dec(mtod(m, void *));
  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: f36abef2fd8e6bba7b29bc4885e14d36


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