xref: /netbsd-src/crypto/dist/ipsec-tools/src/racoon/isakmp_unity.c (revision aa9b8479a9901179c6212ea440e55b523ca5fdd2)
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 *
isakmp_unity_req(iph1,attr)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
isakmp_unity_reply(iph1,attr)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 *
isakmp_cfg_split(iph1,attr,netentry,count)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 
splitnet_list_add(list,network,count)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 
splitnet_list_free(list,count)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 
splitnet_list_2str(list,splitnet_ipaddr)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