1 /* $NetBSD: isakmp_unity.c,v 1.9 2007/10/19 03:37:19 manu Exp $ */ 2 3 /* Id: isakmp_unity.c,v 1.10 2006/07/31 04:49:23 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 <stdlib.h> 45 #include <stdio.h> 46 #include <fcntl.h> 47 #include <string.h> 48 #include <errno.h> 49 #if TIME_WITH_SYS_TIME 50 # include <sys/time.h> 51 # include <time.h> 52 #else 53 # if HAVE_SYS_TIME_H 54 # include <sys/time.h> 55 # else 56 # include <time.h> 57 # endif 58 #endif 59 #include <netdb.h> 60 #ifdef HAVE_UNISTD_H 61 #include <unistd.h> 62 #endif 63 #include <ctype.h> 64 #include <resolv.h> 65 66 #include "var.h" 67 #include "misc.h" 68 #include "vmbuf.h" 69 #include "plog.h" 70 #include "sockmisc.h" 71 #include "schedule.h" 72 #include "debug.h" 73 74 #include "isakmp_var.h" 75 #include "isakmp.h" 76 #include "handler.h" 77 #include "isakmp_xauth.h" 78 #include "isakmp_unity.h" 79 #include "isakmp_cfg.h" 80 #include "strnames.h" 81 82 static vchar_t *isakmp_cfg_split(struct ph1handle *, 83 struct isakmp_data *, struct unity_netentry*,int); 84 85 vchar_t * 86 isakmp_unity_req(iph1, attr) 87 struct ph1handle *iph1; 88 struct isakmp_data *attr; 89 { 90 int type; 91 vchar_t *reply_attr = NULL; 92 93 if ((iph1->mode_cfg->flags & ISAKMP_CFG_VENDORID_UNITY) == 0) { 94 plog(LLV_ERROR, LOCATION, NULL, 95 "Unity mode config request but the peer " 96 "did not declare itself as unity compliant\n"); 97 return NULL; 98 } 99 100 type = ntohs(attr->type); 101 102 /* Handle short attributes */ 103 if ((type & ISAKMP_GEN_MASK) == ISAKMP_GEN_TV) { 104 type &= ~ISAKMP_GEN_MASK; 105 106 plog(LLV_DEBUG, LOCATION, NULL, 107 "Short attribute %s = %d\n", 108 s_isakmp_cfg_type(type), ntohs(attr->lorv)); 109 110 switch (type) { 111 default: 112 plog(LLV_DEBUG, LOCATION, NULL, 113 "Ignored short attribute %s\n", 114 s_isakmp_cfg_type(type)); 115 break; 116 } 117 118 return reply_attr; 119 } 120 121 switch(type) { 122 case UNITY_BANNER: { 123 #define MAXMOTD 65536 124 char buf[MAXMOTD + 1]; 125 int fd; 126 char *filename = &isakmp_cfg_config.motd[0]; 127 int len; 128 129 if ((fd = open(filename, O_RDONLY, 0)) == -1) { 130 plog(LLV_ERROR, LOCATION, NULL, 131 "Cannot open \"%s\"\n", filename); 132 return NULL; 133 } 134 135 if ((len = read(fd, buf, MAXMOTD)) == -1) { 136 plog(LLV_ERROR, LOCATION, NULL, 137 "Cannot read \"%s\"\n", filename); 138 close(fd); 139 return NULL; 140 } 141 close(fd); 142 143 buf[len] = '\0'; 144 reply_attr = isakmp_cfg_string(iph1, attr, buf); 145 146 break; 147 } 148 149 case UNITY_PFS: 150 reply_attr = isakmp_cfg_short(iph1, attr, 151 isakmp_cfg_config.pfs_group); 152 break; 153 154 case UNITY_SAVE_PASSWD: 155 reply_attr = isakmp_cfg_short(iph1, attr, 156 isakmp_cfg_config.save_passwd); 157 break; 158 159 case UNITY_DDNS_HOSTNAME: 160 reply_attr = isakmp_cfg_copy(iph1, attr); 161 break; 162 163 case UNITY_DEF_DOMAIN: 164 reply_attr = isakmp_cfg_string(iph1, 165 attr, isakmp_cfg_config.default_domain); 166 break; 167 168 case UNITY_SPLIT_INCLUDE: 169 if(isakmp_cfg_config.splitnet_type == UNITY_SPLIT_INCLUDE) 170 reply_attr = isakmp_cfg_split(iph1, attr, 171 isakmp_cfg_config.splitnet_list, 172 isakmp_cfg_config.splitnet_count); 173 else 174 return NULL; 175 break; 176 case UNITY_LOCAL_LAN: 177 if(isakmp_cfg_config.splitnet_type == UNITY_LOCAL_LAN) 178 reply_attr = isakmp_cfg_split(iph1, attr, 179 isakmp_cfg_config.splitnet_list, 180 isakmp_cfg_config.splitnet_count); 181 else 182 return NULL; 183 break; 184 case UNITY_SPLITDNS_NAME: 185 reply_attr = isakmp_cfg_varlen(iph1, attr, 186 isakmp_cfg_config.splitdns_list, 187 isakmp_cfg_config.splitdns_len); 188 break; 189 case UNITY_FW_TYPE: 190 case UNITY_NATT_PORT: 191 case UNITY_BACKUP_SERVERS: 192 default: 193 plog(LLV_DEBUG, LOCATION, NULL, 194 "Ignored attribute %s\n", s_isakmp_cfg_type(type)); 195 return NULL; 196 break; 197 } 198 199 return reply_attr; 200 } 201 202 void 203 isakmp_unity_reply(iph1, attr) 204 struct ph1handle *iph1; 205 struct isakmp_data *attr; 206 { 207 int type = ntohs(attr->type); 208 int alen = ntohs(attr->lorv); 209 210 struct unity_network *network = (struct unity_network *)(attr + 1); 211 int index = 0; 212 int count = 0; 213 214 switch(type) { 215 case UNITY_SPLIT_INCLUDE: 216 { 217 if (alen) 218 count = alen / sizeof(struct unity_network); 219 220 for(;index < count; index++) 221 splitnet_list_add( 222 &iph1->mode_cfg->split_include, 223 &network[index], 224 &iph1->mode_cfg->include_count); 225 226 iph1->mode_cfg->flags |= ISAKMP_CFG_GOT_SPLIT_INCLUDE; 227 break; 228 } 229 case UNITY_LOCAL_LAN: 230 { 231 if (alen) 232 count = alen / sizeof(struct unity_network); 233 234 for(;index < count; index++) 235 splitnet_list_add( 236 &iph1->mode_cfg->split_local, 237 &network[index], 238 &iph1->mode_cfg->local_count); 239 240 iph1->mode_cfg->flags |= ISAKMP_CFG_GOT_SPLIT_LOCAL; 241 break; 242 } 243 case UNITY_SPLITDNS_NAME: 244 case UNITY_BANNER: 245 case UNITY_SAVE_PASSWD: 246 case UNITY_NATT_PORT: 247 case UNITY_PFS: 248 case UNITY_FW_TYPE: 249 case UNITY_BACKUP_SERVERS: 250 case UNITY_DDNS_HOSTNAME: 251 default: 252 plog(LLV_WARNING, LOCATION, NULL, 253 "Ignored attribute %s\n", 254 s_isakmp_cfg_type(type)); 255 break; 256 } 257 return; 258 } 259 260 static vchar_t * 261 isakmp_cfg_split(iph1, attr, netentry, count) 262 struct ph1handle *iph1; 263 struct isakmp_data *attr; 264 struct unity_netentry *netentry; 265 int count; 266 { 267 vchar_t *buffer; 268 struct isakmp_data *new; 269 struct unity_network * network; 270 size_t len; 271 int index = 0; 272 273 char tmp1[40]; 274 char tmp2[40]; 275 276 len = sizeof(struct unity_network) * count; 277 if ((buffer = vmalloc(sizeof(*attr) + len)) == NULL) { 278 plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n"); 279 return NULL; 280 } 281 282 new = (struct isakmp_data *)buffer->v; 283 new->type = attr->type; 284 new->lorv = htons(len); 285 286 network = (struct unity_network *)(new + 1); 287 for (; index < count; index++) { 288 289 memcpy(&network[index], 290 &netentry->network, 291 sizeof(struct unity_network)); 292 293 inet_ntop(AF_INET, &netentry->network.addr4, tmp1, 40); 294 inet_ntop(AF_INET, &netentry->network.mask4, tmp2, 40); 295 plog(LLV_DEBUG, LOCATION, NULL, "splitnet: %s/%s\n", tmp1, tmp2); 296 297 netentry = netentry->next; 298 } 299 300 return buffer; 301 } 302 303 int splitnet_list_add(list, network, count) 304 struct unity_netentry ** list; 305 struct unity_network * network; 306 int *count; 307 { 308 struct unity_netentry * nentry; 309 310 /* 311 * search for network in current list 312 * to avoid adding duplicates 313 */ 314 for (nentry = *list; nentry != NULL; nentry = nentry->next) 315 if (memcmp(&nentry->network, network, 316 sizeof(struct unity_network)) == 0) 317 return 0; /* it's a dupe */ 318 319 /* 320 * allocate new netentry and copy 321 * new splitnet network data 322 */ 323 nentry = (struct unity_netentry *) 324 racoon_malloc(sizeof(struct unity_netentry)); 325 if (nentry == NULL) 326 return -1; 327 328 memcpy(&nentry->network,network, 329 sizeof(struct unity_network)); 330 nentry->next = NULL; 331 332 /* 333 * locate the last netentry in our 334 * splitnet list and add our entry 335 */ 336 if (*list == NULL) 337 *list = nentry; 338 else { 339 struct unity_netentry * tmpentry = *list; 340 while (tmpentry->next != NULL) 341 tmpentry = tmpentry->next; 342 tmpentry->next = nentry; 343 } 344 345 (*count)++; 346 347 return 0; 348 } 349 350 void splitnet_list_free(list, count) 351 struct unity_netentry * list; 352 int *count; 353 { 354 struct unity_netentry * netentry = list; 355 struct unity_netentry * delentry; 356 357 *count = 0; 358 359 while (netentry != NULL) { 360 delentry = netentry; 361 netentry = netentry->next; 362 racoon_free(delentry); 363 } 364 } 365 366 char * splitnet_list_2str(list, splitnet_ipaddr) 367 struct unity_netentry * list; 368 enum splinet_ipaddr splitnet_ipaddr; 369 { 370 struct unity_netentry * netentry; 371 char tmp1[40]; 372 char tmp2[40]; 373 char * str; 374 int len; 375 376 /* determine string length */ 377 len = 0; 378 netentry = list; 379 while (netentry != NULL) { 380 381 inet_ntop(AF_INET, &netentry->network.addr4, tmp1, 40); 382 inet_ntop(AF_INET, &netentry->network.mask4, tmp2, 40); 383 len += strlen(tmp1); 384 len += strlen(tmp2); 385 len += 2; 386 387 netentry = netentry->next; 388 } 389 390 /* allocate network list string */ 391 str = racoon_malloc(len); 392 if (str == NULL) 393 return NULL; 394 395 /* create network list string */ 396 len = 0; 397 netentry = list; 398 while (netentry != NULL) { 399 400 inet_ntop(AF_INET, &netentry->network.addr4, tmp1, 40); 401 inet_ntop(AF_INET, &netentry->network.mask4, tmp2, 40); 402 if (splitnet_ipaddr == CIDR) { 403 uint32_t tmp3; 404 int cidrmask; 405 406 tmp3 = ntohl(netentry->network.mask4.s_addr); 407 for (cidrmask = 0; tmp3 != 0; cidrmask++) 408 tmp3 <<= 1; 409 len += sprintf(str+len, "%s/%d ", tmp1, cidrmask); 410 } else { 411 len += sprintf(str+len, "%s/%s ", tmp1, tmp2); 412 } 413 414 netentry = netentry->next; 415 } 416 417 str[len-1]=0; 418 419 return str; 420 } 421