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