1 /* $NetBSD: isakmp_frag.c,v 1.3 2005/11/21 14:20:29 manu 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 81 int 82 isakmp_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 165 unsigned int 166 vendorid_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 176 int 177 isakmp_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 plog(LLV_ERROR, LOCATION, NULL, "Fragment too short\n"); 204 return -1; 205 } 206 207 if ((buf = vmalloc(ntohs(frag->len) - sizeof(*frag))) == NULL) { 208 plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n"); 209 return -1; 210 } 211 212 if ((item = racoon_malloc(sizeof(*item))) == NULL) { 213 plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n"); 214 vfree(buf); 215 return -1; 216 } 217 218 data = (char *)(frag + 1); 219 memcpy(buf->v, data, buf->l); 220 221 item->frag_num = frag->index; 222 item->frag_last = (frag->flags & ISAKMP_FRAG_LAST); 223 item->frag_next = NULL; 224 item->frag_packet = buf; 225 226 /* Look for the last frag while inserting the new item in the chain */ 227 if (item->frag_last) 228 last_frag = item->frag_num; 229 230 if (iph1->frag_chain == NULL) { 231 iph1->frag_chain = item; 232 } else { 233 struct isakmp_frag_item *current; 234 235 current = iph1->frag_chain; 236 while (current->frag_next) { 237 if (current->frag_last) 238 last_frag = item->frag_num; 239 current = current->frag_next; 240 } 241 current->frag_next = item; 242 } 243 244 /* If we saw the last frag, check if the chain is complete */ 245 if (last_frag != 0) { 246 for (i = 1; i <= last_frag; i++) { 247 item = iph1->frag_chain; 248 do { 249 if (item->frag_num == i) 250 break; 251 item = item->frag_next; 252 } while (item != NULL); 253 254 if (item == NULL) /* Not found */ 255 break; 256 } 257 258 if (item != NULL) /* It is complete */ 259 return 1; 260 } 261 262 return 0; 263 } 264 265 vchar_t * 266 isakmp_frag_reassembly(iph1) 267 struct ph1handle *iph1; 268 { 269 struct isakmp_frag_item *item; 270 size_t len = 0; 271 vchar_t *buf = NULL; 272 int frag_count = 0; 273 int i; 274 char *data; 275 276 if ((item = iph1->frag_chain) == NULL) { 277 plog(LLV_ERROR, LOCATION, NULL, "No fragment to reassemble\n"); 278 goto out; 279 } 280 281 do { 282 frag_count++; 283 len += item->frag_packet->l; 284 item = item->frag_next; 285 } while (item != NULL); 286 287 if ((buf = vmalloc(len)) == NULL) { 288 plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n"); 289 goto out; 290 } 291 data = buf->v; 292 293 for (i = 1; i <= frag_count; i++) { 294 item = iph1->frag_chain; 295 do { 296 if (item->frag_num == i) 297 break; 298 item = item->frag_next; 299 } while (item != NULL); 300 301 if (item == NULL) { 302 plog(LLV_ERROR, LOCATION, NULL, 303 "Missing fragment #%d\n", i); 304 vfree(buf); 305 buf = NULL; 306 goto out; 307 } 308 memcpy(data, item->frag_packet->v, item->frag_packet->l); 309 data += item->frag_packet->l; 310 } 311 312 out: 313 item = iph1->frag_chain; 314 do { 315 struct isakmp_frag_item *next_item; 316 317 next_item = item->frag_next; 318 319 vfree(item->frag_packet); 320 racoon_free(item); 321 322 item = next_item; 323 } while (item != NULL); 324 325 iph1->frag_chain = NULL; 326 327 return buf; 328 } 329 330 vchar_t * 331 isakmp_frag_addcap(buf, cap) 332 vchar_t *buf; 333 int cap; 334 { 335 int *capp; 336 size_t len; 337 338 /* If the capability has not been added, add room now */ 339 len = buf->l; 340 if (len == MD5_DIGEST_LENGTH) { 341 if ((buf = vrealloc(buf, len + sizeof(cap))) == NULL) { 342 plog(LLV_ERROR, LOCATION, NULL, 343 "Cannot allocate memory\n"); 344 return NULL; 345 } 346 capp = (int *)(buf->v + len); 347 *capp = htonl(0); 348 } 349 350 capp = (int *)(buf->v + MD5_DIGEST_LENGTH); 351 *capp |= htonl(cap); 352 353 return buf; 354 } 355 356