Home | History | Annotate | Download | only in racoon
      1 /*	$NetBSD: isakmp_unity.c,v 1.7 2006/10/09 06:17:20 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 * newentry;
    309 
    310 	/*
    311 	 * allocate new netentry and copy
    312          * new splitnet network data
    313 	 */
    314 	newentry = (struct unity_netentry *)
    315 		racoon_malloc(sizeof(struct unity_netentry));
    316 	if (newentry == NULL)
    317 		return -1;
    318 
    319 	memcpy(&newentry->network,network,
    320 		sizeof(struct unity_network));
    321 	newentry->next = NULL;
    322 
    323 	/*
    324 	 * locate the last netentry in our
    325 	 * splitnet list and add our entry
    326 	 */
    327 	if (*list == NULL)
    328 		*list = newentry;
    329 	else {
    330 		struct unity_netentry * tmpentry = *list;
    331 		while (tmpentry->next != NULL)
    332 			tmpentry = tmpentry->next;
    333 		tmpentry->next = newentry;
    334 	}
    335 
    336 	(*count)++;
    337 
    338 	return 0;
    339 }
    340 
    341 void splitnet_list_free(list, count)
    342 	struct unity_netentry * list;
    343 	int *count;
    344 {
    345 	struct unity_netentry * netentry = list;
    346 	struct unity_netentry * delentry;
    347 
    348 	*count = 0;
    349 
    350 	while (netentry != NULL) {
    351 		delentry = netentry;
    352 		netentry = netentry->next;
    353 		racoon_free(delentry);
    354 	}
    355 }
    356 
    357 char * splitnet_list_2str(list, splitnet_ipaddr)
    358 	struct unity_netentry * list;
    359 	enum splinet_ipaddr splitnet_ipaddr;
    360 {
    361 	struct unity_netentry * netentry;
    362 	char tmp1[40];
    363 	char tmp2[40];
    364 	char * str;
    365 	int len;
    366 
    367 	/* determine string length */
    368 	len = 1;
    369 	netentry = list;
    370 	while (netentry != NULL) {
    371 
    372 		inet_ntop(AF_INET, &netentry->network.addr4, tmp1, 40);
    373 		inet_ntop(AF_INET, &netentry->network.mask4, tmp2, 40);
    374 		len += strlen(tmp1);
    375 		len += strlen(tmp2);
    376 		len += 2;
    377 
    378 		netentry = netentry->next;
    379 	}
    380 
    381 	/* allocate network list string */
    382 	str = racoon_malloc(len);
    383 	if (str == NULL)
    384 		return NULL;
    385 
    386 	/* create network list string */
    387 	len = 0;
    388 	netentry = list;
    389 	while (netentry != NULL) {
    390 
    391 		inet_ntop(AF_INET, &netentry->network.addr4, tmp1, 40);
    392 		inet_ntop(AF_INET, &netentry->network.mask4, tmp2, 40);
    393 		if (splitnet_ipaddr == CIDR) {
    394 			uint32_t tmp3;
    395 			int cidrmask;
    396 
    397 			tmp3 = ntohl(netentry->network.mask4.s_addr);
    398 			for (cidrmask = 0; tmp3 != 0; cidrmask++)
    399 				tmp3 <<= 1;
    400 			len += sprintf(str+len, "%s/%d ", tmp1, cidrmask);
    401 		} else {
    402 			len += sprintf(str+len, "%s/%s ", tmp1, tmp2);
    403 		}
    404 
    405 		netentry = netentry->next;
    406 	}
    407 
    408 	str[len]=0;
    409 
    410 	return str;
    411 }
    412