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