#include #ifdef __rtems__ #include #include "rtems-bsd-racoon-namespace.h" #endif /* __rtems__ */ /* $NetBSD: isakmp_frag.c,v 1.7 2017/07/23 05:40:27 christos Exp $ */ /* Id: isakmp_frag.c,v 1.4 2004/11/13 17:31:36 manubsd Exp */ /* * Copyright (C) 2004 Emmanuel Dreyfus * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #if TIME_WITH_SYS_TIME # include # include #else # if HAVE_SYS_TIME_H # include # else # include # endif #endif #include #ifdef HAVE_UNISTD_H #include #endif #include #include "var.h" #include "misc.h" #include "vmbuf.h" #include "plog.h" #include "sockmisc.h" #include "schedule.h" #include "debug.h" #include "isakmp_var.h" #include "isakmp.h" #include "handler.h" #include "isakmp_frag.h" #include "strnames.h" int isakmp_sendfrags(iph1, buf) struct ph1handle *iph1; vchar_t *buf; { struct isakmp *hdr; struct isakmp_frag *fraghdr; caddr_t data; caddr_t sdata; size_t datalen; size_t max_datalen; size_t fraglen; vchar_t *frag; unsigned int trailer; unsigned int fragnum = 0; size_t len; int etype; /* * Catch the exchange type for later: the fragments and the * fragmented packet must have the same exchange type. */ hdr = (struct isakmp *)buf->v; etype = hdr->etype; /* * We want to send a a packet smaller than ISAKMP_FRAG_MAXLEN * First compute the maximum data length that will fit in it */ max_datalen = ISAKMP_FRAG_MAXLEN - (sizeof(*hdr) + sizeof(*fraghdr) + sizeof(trailer)); sdata = buf->v; len = buf->l; while (len > 0) { fragnum++; if (len > max_datalen) datalen = max_datalen; else datalen = len; fraglen = sizeof(*hdr) + sizeof(*fraghdr) + datalen; if ((frag = vmalloc(fraglen)) == NULL) { plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n"); return -1; } set_isakmp_header1(frag, iph1, ISAKMP_NPTYPE_FRAG); hdr = (struct isakmp *)frag->v; hdr->etype = etype; fraghdr = (struct isakmp_frag *)(hdr + 1); fraghdr->unknown0 = htons(0); fraghdr->len = htons(fraglen - sizeof(*hdr)); fraghdr->unknown1 = htons(1); fraghdr->index = fragnum; if (len == datalen) fraghdr->flags = ISAKMP_FRAG_LAST; else fraghdr->flags = 0; data = (caddr_t)(fraghdr + 1); memcpy(data, sdata, datalen); if (isakmp_send(iph1, frag) < 0) { plog(LLV_ERROR, LOCATION, NULL, "isakmp_send failed\n"); return -1; } vfree(frag); len -= datalen; sdata += datalen; } return fragnum; } unsigned int vendorid_frag_cap(gen) struct isakmp_gen *gen; { int *hp; hp = (int *)(gen + 1); return ntohl(hp[MD5_DIGEST_LENGTH / sizeof(*hp)]); } static int isakmp_frag_insert(struct ph1handle *iph1, struct isakmp_frag_item *item) { struct isakmp_frag_item *pitem = NULL; struct isakmp_frag_item *citem = iph1->frag_chain; /* no frag yet, just insert at beginning of list */ if (iph1->frag_chain == NULL) { iph1->frag_chain = item; return 0; } do { /* duplicate fragment number, abort (CVE-2016-10396) */ if (citem->frag_num == item->frag_num) return -1; /* need to insert before current item */ if (citem->frag_num > item->frag_num) { if (pitem != NULL) pitem->frag_next = item; else /* insert at the beginning of the list */ iph1->frag_chain = item; item->frag_next = citem; return 0; } pitem = citem; citem = citem->frag_next; } while (citem != NULL); /* we reached the end of the list, insert */ pitem->frag_next = item; return 0; } int isakmp_frag_extract(iph1, msg) struct ph1handle *iph1; vchar_t *msg; { struct isakmp *isakmp; struct isakmp_frag *frag; struct isakmp_frag_item *item; vchar_t *buf; size_t len; int last_frag = 0; char *data; int i; if (msg->l < sizeof(*isakmp) + sizeof(*frag)) { plog(LLV_ERROR, LOCATION, NULL, "Message too short\n"); return -1; } isakmp = (struct isakmp *)msg->v; frag = (struct isakmp_frag *)(isakmp + 1); /* * frag->len is the frag payload data plus the frag payload header, * whose size is sizeof(*frag) */ if (msg->l < sizeof(*isakmp) + ntohs(frag->len) || ntohs(frag->len) < sizeof(*frag) + 1) { plog(LLV_ERROR, LOCATION, NULL, "Fragment too short\n"); return -1; } if ((buf = vmalloc(ntohs(frag->len) - sizeof(*frag))) == NULL) { plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n"); return -1; } if ((item = racoon_malloc(sizeof(*item))) == NULL) { plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n"); vfree(buf); return -1; } data = (char *)(frag + 1); memcpy(buf->v, data, buf->l); item->frag_num = frag->index; item->frag_last = (frag->flags & ISAKMP_FRAG_LAST); item->frag_next = NULL; item->frag_packet = buf; /* Check for the last frag before inserting the new item in the chain */ if (item->frag_last) { /* if we have the last fragment, indices must match */ if (iph1->frag_last_index != 0 && item->frag_last != iph1->frag_last_index) { plog(LLV_ERROR, LOCATION, NULL, "Repeated last fragment index mismatch\n"); racoon_free(item); vfree(buf); return -1; } last_frag = iph1->frag_last_index = item->frag_num; } /* insert fragment into chain */ if (isakmp_frag_insert(iph1, item) == -1) { plog(LLV_ERROR, LOCATION, NULL, "Repeated fragment index mismatch\n"); racoon_free(item); vfree(buf); return -1; } /* If we saw the last frag, check if the chain is complete * we have a sorted list now, so just walk through */ if (last_frag != 0) { item = iph1->frag_chain; for (i = 1; i <= last_frag; i++) { if (item->frag_num != i) break; item = item->frag_next; if (item == NULL) /* Not found */ break; } if (i > last_frag) /* It is complete */ return 1; } return 0; } vchar_t * isakmp_frag_reassembly(iph1) struct ph1handle *iph1; { struct isakmp_frag_item *item; size_t len = 0; vchar_t *buf = NULL; int frag_count = 0; int i; char *data; if ((item = iph1->frag_chain) == NULL) { plog(LLV_ERROR, LOCATION, NULL, "No fragment to reassemble\n"); goto out; } do { frag_count++; len += item->frag_packet->l; item = item->frag_next; } while (item != NULL); if ((buf = vmalloc(len)) == NULL) { plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n"); goto out; } data = buf->v; item = iph1->frag_chain; for (i = 1; i <= frag_count; i++) { if (item->frag_num != i) { plog(LLV_ERROR, LOCATION, NULL, "Missing fragment #%d\n", i); vfree(buf); buf = NULL; goto out; } memcpy(data, item->frag_packet->v, item->frag_packet->l); data += item->frag_packet->l; item = item->frag_next; } out: item = iph1->frag_chain; do { struct isakmp_frag_item *next_item; next_item = item->frag_next; vfree(item->frag_packet); racoon_free(item); item = next_item; } while (item != NULL); iph1->frag_chain = NULL; return buf; } vchar_t * isakmp_frag_addcap(buf, cap) vchar_t *buf; int cap; { int *capp; size_t len; /* If the capability has not been added, add room now */ len = buf->l; if (len == MD5_DIGEST_LENGTH) { if ((buf = vrealloc(buf, len + sizeof(cap))) == NULL) { plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n"); return NULL; } capp = (int *)(buf->v + len); *capp = htonl(0); } capp = (int *)(buf->v + MD5_DIGEST_LENGTH); *capp |= htonl(cap); return buf; } #ifdef __rtems__ #include "rtems-bsd-racoon-isakmp_frag-data.h" #endif /* __rtems__ */