1/* $NetBSD: isakmp_frag.c,v 1.4.6.1 2009/04/22 11:25:35 tteras Exp $ */ 2 3/* Id: isakmp_frag.c,v 1.4 2004/11/13 17:31:36 manubsd Exp */ 4 5/* 6 * Copyright (C) 2004 Emmanuel Dreyfus 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the project nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#include "config.h" 35 36#include <sys/types.h> 37#include <sys/param.h> 38#include <sys/socket.h> 39#include <sys/queue.h> 40 41#include <netinet/in.h> 42#include <arpa/inet.h> 43 44#include <openssl/md5.h> 45 46#include <stdlib.h> 47#include <stdio.h> 48#include <fcntl.h> 49#include <string.h> 50#include <errno.h> 51#if TIME_WITH_SYS_TIME 52# include <sys/time.h> 53# include <time.h> 54#else 55# if HAVE_SYS_TIME_H 56# include <sys/time.h> 57# else 58# include <time.h> 59# endif 60#endif 61#include <netdb.h> 62#ifdef HAVE_UNISTD_H 63#include <unistd.h> 64#endif 65#include <ctype.h> 66 67#include "var.h" 68#include "misc.h" 69#include "vmbuf.h" 70#include "plog.h" 71#include "sockmisc.h" 72#include "schedule.h" 73#include "debug.h" 74 75#include "isakmp_var.h" 76#include "isakmp.h" 77#include "handler.h" 78#include "isakmp_frag.h" 79#include "strnames.h" 80 81int 82isakmp_sendfrags(iph1, buf) 83 struct ph1handle *iph1; 84 vchar_t *buf; 85{ 86 struct isakmp *hdr; 87 struct isakmp_frag *fraghdr; 88 caddr_t data; 89 caddr_t sdata; 90 size_t datalen; 91 size_t max_datalen; 92 size_t fraglen; 93 vchar_t *frag; 94 unsigned int trailer; 95 unsigned int fragnum = 0; 96 size_t len; 97 int etype; 98 99 /* 100 * Catch the exchange type for later: the fragments and the 101 * fragmented packet must have the same exchange type. 102 */ 103 hdr = (struct isakmp *)buf->v; 104 etype = hdr->etype; 105 106 /* 107 * We want to send a a packet smaller than ISAKMP_FRAG_MAXLEN 108 * First compute the maximum data length that will fit in it 109 */ 110 max_datalen = ISAKMP_FRAG_MAXLEN - 111 (sizeof(*hdr) + sizeof(*fraghdr) + sizeof(trailer)); 112 113 sdata = buf->v; 114 len = buf->l; 115 116 while (len > 0) { 117 fragnum++; 118 119 if (len > max_datalen) 120 datalen = max_datalen; 121 else 122 datalen = len; 123 124 fraglen = sizeof(*hdr) 125 + sizeof(*fraghdr) 126 + datalen; 127 128 if ((frag = vmalloc(fraglen)) == NULL) { 129 plog(LLV_ERROR, LOCATION, NULL, 130 "Cannot allocate memory\n"); 131 return -1; 132 } 133 134 set_isakmp_header1(frag, iph1, ISAKMP_NPTYPE_FRAG); 135 hdr = (struct isakmp *)frag->v; 136 hdr->etype = etype; 137 138 fraghdr = (struct isakmp_frag *)(hdr + 1); 139 fraghdr->unknown0 = htons(0); 140 fraghdr->len = htons(fraglen - sizeof(*hdr)); 141 fraghdr->unknown1 = htons(1); 142 fraghdr->index = fragnum; 143 if (len == datalen) 144 fraghdr->flags = ISAKMP_FRAG_LAST; 145 else 146 fraghdr->flags = 0; 147 148 data = (caddr_t)(fraghdr + 1); 149 memcpy(data, sdata, datalen); 150 151 if (isakmp_send(iph1, frag) < 0) { 152 plog(LLV_ERROR, LOCATION, NULL, "isakmp_send failed\n"); 153 return -1; 154 } 155 156 vfree(frag); 157 158 len -= datalen; 159 sdata += datalen; 160 } 161 162 return fragnum; 163} 164 165unsigned int 166vendorid_frag_cap(gen) 167 struct isakmp_gen *gen; 168{ 169 int *hp; 170 171 hp = (int *)(gen + 1); 172 173 return ntohl(hp[MD5_DIGEST_LENGTH / sizeof(*hp)]); 174} 175 176int 177isakmp_frag_extract(iph1, msg) 178 struct ph1handle *iph1; 179 vchar_t *msg; 180{ 181 struct isakmp *isakmp; 182 struct isakmp_frag *frag; 183 struct isakmp_frag_item *item; 184 vchar_t *buf; 185 size_t len; 186 int last_frag = 0; 187 char *data; 188 int i; 189 190 if (msg->l < sizeof(*isakmp) + sizeof(*frag)) { 191 plog(LLV_ERROR, LOCATION, NULL, "Message too short\n"); 192 return -1; 193 } 194 195 isakmp = (struct isakmp *)msg->v; 196 frag = (struct isakmp_frag *)(isakmp + 1); 197 198 /* 199 * frag->len is the frag payload data plus the frag payload header, 200 * whose size is sizeof(*frag) 201 */ 202 if (msg->l < sizeof(*isakmp) + ntohs(frag->len) || 203 ntohs(frag->len) < sizeof(*frag) + 1) { 204 plog(LLV_ERROR, LOCATION, NULL, "Fragment too short\n"); 205 return -1; 206 } 207 208 if ((buf = vmalloc(ntohs(frag->len) - sizeof(*frag))) == NULL) { 209 plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n"); 210 return -1; 211 } 212 213 if ((item = racoon_malloc(sizeof(*item))) == NULL) { 214 plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n"); 215 vfree(buf); 216 return -1; 217 } 218 219 data = (char *)(frag + 1); 220 memcpy(buf->v, data, buf->l); 221 222 item->frag_num = frag->index; 223 item->frag_last = (frag->flags & ISAKMP_FRAG_LAST); 224 item->frag_next = NULL; 225 item->frag_packet = buf; 226 227 /* Look for the last frag while inserting the new item in the chain */ 228 if (item->frag_last) 229 last_frag = item->frag_num; 230 231 if (iph1->frag_chain == NULL) { 232 iph1->frag_chain = item; 233 } else { 234 struct isakmp_frag_item *current; 235 236 current = iph1->frag_chain; 237 while (current->frag_next) { 238 if (current->frag_last) 239 last_frag = item->frag_num; 240 current = current->frag_next; 241 } 242 current->frag_next = item; 243 } 244 245 /* If we saw the last frag, check if the chain is complete */ 246 if (last_frag != 0) { 247 for (i = 1; i <= last_frag; i++) { 248 item = iph1->frag_chain; 249 do { 250 if (item->frag_num == i) 251 break; 252 item = item->frag_next; 253 } while (item != NULL); 254 255 if (item == NULL) /* Not found */ 256 break; 257 } 258 259 if (item != NULL) /* It is complete */ 260 return 1; 261 } 262 263 return 0; 264} 265 266vchar_t * 267isakmp_frag_reassembly(iph1) 268 struct ph1handle *iph1; 269{ 270 struct isakmp_frag_item *item; 271 size_t len = 0; 272 vchar_t *buf = NULL; 273 int frag_count = 0; 274 int i; 275 char *data; 276 277 if ((item = iph1->frag_chain) == NULL) { 278 plog(LLV_ERROR, LOCATION, NULL, "No fragment to reassemble\n"); 279 goto out; 280 } 281 282 do { 283 frag_count++; 284 len += item->frag_packet->l; 285 item = item->frag_next; 286 } while (item != NULL); 287 288 if ((buf = vmalloc(len)) == NULL) { 289 plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n"); 290 goto out; 291 } 292 data = buf->v; 293 294 for (i = 1; i <= frag_count; i++) { 295 item = iph1->frag_chain; 296 do { 297 if (item->frag_num == i) 298 break; 299 item = item->frag_next; 300 } while (item != NULL); 301 302 if (item == NULL) { 303 plog(LLV_ERROR, LOCATION, NULL, 304 "Missing fragment #%d\n", i); 305 vfree(buf); 306 buf = NULL; 307 goto out; 308 } 309 memcpy(data, item->frag_packet->v, item->frag_packet->l); 310 data += item->frag_packet->l; 311 } 312 313out: 314 item = iph1->frag_chain; 315 do { 316 struct isakmp_frag_item *next_item; 317 318 next_item = item->frag_next; 319 320 vfree(item->frag_packet); 321 racoon_free(item); 322 323 item = next_item; 324 } while (item != NULL); 325 326 iph1->frag_chain = NULL; 327 328 return buf; 329} 330 331vchar_t * 332isakmp_frag_addcap(buf, cap) 333 vchar_t *buf; 334 int cap; 335{ 336 int *capp; 337 size_t len; 338 339 /* If the capability has not been added, add room now */ 340 len = buf->l; 341 if (len == MD5_DIGEST_LENGTH) { 342 if ((buf = vrealloc(buf, len + sizeof(cap))) == NULL) { 343 plog(LLV_ERROR, LOCATION, NULL, 344 "Cannot allocate memory\n"); 345 return NULL; 346 } 347 capp = (int *)(buf->v + len); 348 *capp = htonl(0); 349 } 350 351 capp = (int *)(buf->v + MD5_DIGEST_LENGTH); 352 *capp |= htonl(cap); 353 354 return buf; 355} 356 357