Home | History | Annotate | Line # | Download | only in racoon
      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