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

Cache object: b13b93744712655a2b838a660f56452c


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