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 *
isakmp_unity_req(iph1,attr)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
isakmp_unity_reply(iph1,attr)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 *
isakmp_cfg_split(iph1,attr,netentry,count)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 
splitnet_list_add(list,network,count)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 
splitnet_list_free(list,count)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 
splitnet_list_2str(list,splitnet_ipaddr)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