ipsec_dump_policy.c revision 84208
1/*	$KAME: ipsec_dump_policy.c,v 1.11 2000/05/07 05:29:47 itojun Exp $	*/
2
3/*
4 * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33__FBSDID("$FreeBSD: head/lib/libipsec/ipsec_dump_policy.c 84208 2001-09-30 21:43:45Z dillon $");
34
35#include <sys/types.h>
36#include <sys/param.h>
37#include <sys/socket.h>
38
39#include <netkey/key_var.h>
40#include <netinet/in.h>
41#include <netinet6/ipsec.h>
42
43#include <arpa/inet.h>
44
45#include <stdio.h>
46#include <stdlib.h>
47#include <string.h>
48#include <netdb.h>
49
50#include "ipsec_strerror.h"
51
52static const char *ipsp_dir_strs[] = {
53	"any", "in", "out",
54};
55
56static const char *ipsp_policy_strs[] = {
57	"discard", "none", "ipsec", "entrust", "bypass",
58};
59
60static char *ipsec_dump_ipsecrequest __P((char *, size_t,
61	struct sadb_x_ipsecrequest *, size_t));
62static int set_addresses __P((char *, size_t, struct sockaddr *,
63	struct sockaddr *));
64static char *set_address __P((char *, size_t, struct sockaddr *));
65
66/*
67 * policy is sadb_x_policy buffer.
68 * Must call free() later.
69 * When delimiter == NULL, alternatively ' '(space) is applied.
70 */
71char *
72ipsec_dump_policy(policy, delimiter)
73	caddr_t policy;
74	char *delimiter;
75{
76	struct sadb_x_policy *xpl = (struct sadb_x_policy *)policy;
77	struct sadb_x_ipsecrequest *xisr;
78	size_t off, buflen;
79	char *buf;
80	char isrbuf[1024];
81	char *newbuf;
82
83	/* sanity check */
84	if (policy == NULL)
85		return NULL;
86	if (xpl->sadb_x_policy_exttype != SADB_X_EXT_POLICY) {
87		__ipsec_errcode = EIPSEC_INVAL_EXTTYPE;
88		return NULL;
89	}
90
91	/* set delimiter */
92	if (delimiter == NULL)
93		delimiter = " ";
94
95	switch (xpl->sadb_x_policy_dir) {
96	case IPSEC_DIR_ANY:
97	case IPSEC_DIR_INBOUND:
98	case IPSEC_DIR_OUTBOUND:
99		break;
100	default:
101		__ipsec_errcode = EIPSEC_INVAL_DIR;
102		return NULL;
103	}
104
105	switch (xpl->sadb_x_policy_type) {
106	case IPSEC_POLICY_DISCARD:
107	case IPSEC_POLICY_NONE:
108	case IPSEC_POLICY_IPSEC:
109	case IPSEC_POLICY_BYPASS:
110	case IPSEC_POLICY_ENTRUST:
111		break;
112	default:
113		__ipsec_errcode = EIPSEC_INVAL_POLICY;
114		return NULL;
115	}
116
117	buflen = strlen(ipsp_dir_strs[xpl->sadb_x_policy_dir])
118		+ 1	/* space */
119		+ strlen(ipsp_policy_strs[xpl->sadb_x_policy_type])
120		+ 1;	/* NUL */
121
122	if ((buf = malloc(buflen)) == NULL) {
123		__ipsec_errcode = EIPSEC_NO_BUFS;
124		return NULL;
125	}
126	snprintf(buf, buflen, "%s %s", ipsp_dir_strs[xpl->sadb_x_policy_dir],
127	    ipsp_policy_strs[xpl->sadb_x_policy_type]);
128
129	if (xpl->sadb_x_policy_type != IPSEC_POLICY_IPSEC) {
130		__ipsec_errcode = EIPSEC_NO_ERROR;
131		return buf;
132	}
133
134	/* count length of buffer for use */
135	off = sizeof(*xpl);
136	while (off < PFKEY_EXTLEN(xpl)) {
137		xisr = (struct sadb_x_ipsecrequest *)((caddr_t)xpl + off);
138		off += xisr->sadb_x_ipsecrequest_len;
139	}
140
141	/* validity check */
142	if (off != PFKEY_EXTLEN(xpl)) {
143		__ipsec_errcode = EIPSEC_INVAL_SADBMSG;
144		free(buf);
145		return NULL;
146	}
147
148	off = sizeof(*xpl);
149	while (off < PFKEY_EXTLEN(xpl)) {
150		xisr = (struct sadb_x_ipsecrequest *)((caddr_t)xpl + off);
151
152		if (ipsec_dump_ipsecrequest(isrbuf, sizeof(isrbuf), xisr,
153		    PFKEY_EXTLEN(xpl) - off) == NULL) {
154			free(buf);
155			return NULL;
156		}
157
158		buflen = strlen(buf) + strlen(delimiter) + strlen(isrbuf) + 1;
159		newbuf = (char *)realloc(buf, buflen);
160		if (newbuf == NULL) {
161			__ipsec_errcode = EIPSEC_NO_BUFS;
162			free(buf);
163			return NULL;
164		}
165		buf = newbuf;
166		snprintf(buf, buflen, "%s%s%s", buf, delimiter, isrbuf);
167
168		off += xisr->sadb_x_ipsecrequest_len;
169	}
170
171	__ipsec_errcode = EIPSEC_NO_ERROR;
172	return buf;
173}
174
175static char *
176ipsec_dump_ipsecrequest(buf, len, xisr, bound)
177	char *buf;
178	size_t len;
179	struct sadb_x_ipsecrequest *xisr;
180	size_t bound;	/* boundary */
181{
182	const char *proto, *mode, *level;
183	char abuf[NI_MAXHOST * 2 + 2];
184
185	if (xisr->sadb_x_ipsecrequest_len > bound) {
186		__ipsec_errcode = EIPSEC_INVAL_PROTO;
187		return NULL;
188	}
189
190	switch (xisr->sadb_x_ipsecrequest_proto) {
191	case IPPROTO_ESP:
192		proto = "esp";
193		break;
194	case IPPROTO_AH:
195		proto = "ah";
196		break;
197	case IPPROTO_IPCOMP:
198		proto = "ipcomp";
199		break;
200	default:
201		__ipsec_errcode = EIPSEC_INVAL_PROTO;
202		return NULL;
203	}
204
205	switch (xisr->sadb_x_ipsecrequest_mode) {
206	case IPSEC_MODE_ANY:
207		mode = "any";
208		break;
209	case IPSEC_MODE_TRANSPORT:
210		mode = "transport";
211		break;
212	case IPSEC_MODE_TUNNEL:
213		mode = "tunnel";
214		break;
215	default:
216		__ipsec_errcode = EIPSEC_INVAL_MODE;
217		return NULL;
218	}
219
220	abuf[0] = '\0';
221	if (xisr->sadb_x_ipsecrequest_len > sizeof(*xisr)) {
222		struct sockaddr *sa1, *sa2;
223		caddr_t p;
224
225		p = (caddr_t)(xisr + 1);
226		sa1 = (struct sockaddr *)p;
227		sa2 = (struct sockaddr *)(p + sa1->sa_len);
228		if (sizeof(*xisr) + sa1->sa_len + sa2->sa_len !=
229		    xisr->sadb_x_ipsecrequest_len) {
230			__ipsec_errcode = EIPSEC_INVAL_ADDRESS;
231			return NULL;
232		}
233		if (set_addresses(abuf, sizeof(abuf), sa1, sa2) != 0) {
234			__ipsec_errcode = EIPSEC_INVAL_ADDRESS;
235			return NULL;
236		}
237	}
238
239	switch (xisr->sadb_x_ipsecrequest_level) {
240	case IPSEC_LEVEL_DEFAULT:
241		level = "default";
242		break;
243	case IPSEC_LEVEL_USE:
244		level = "use";
245		break;
246	case IPSEC_LEVEL_REQUIRE:
247		level = "require";
248		break;
249	case IPSEC_LEVEL_UNIQUE:
250		level = "unique";
251		break;
252	default:
253		__ipsec_errcode = EIPSEC_INVAL_LEVEL;
254		return NULL;
255	}
256
257	if (xisr->sadb_x_ipsecrequest_reqid == 0)
258		snprintf(buf, len, "%s/%s/%s/%s", proto, mode, abuf, level);
259	else {
260		int ch;
261
262		if (xisr->sadb_x_ipsecrequest_reqid > IPSEC_MANUAL_REQID_MAX)
263			ch = '#';
264		else
265			ch = ':';
266		snprintf(buf, len, "%s/%s/%s/%s%c%d", proto, mode, abuf, level,
267		    ch, xisr->sadb_x_ipsecrequest_reqid);
268	}
269
270	return buf;
271}
272
273static int
274set_addresses(buf, len, sa1, sa2)
275	char *buf;
276	size_t len;
277	struct sockaddr *sa1;
278	struct sockaddr *sa2;
279{
280	char tmp1[NI_MAXHOST], tmp2[NI_MAXHOST];
281
282	if (set_address(tmp1, sizeof(tmp1), sa1) == NULL ||
283	    set_address(tmp2, sizeof(tmp2), sa2) == NULL)
284		return -1;
285	if (strlen(tmp1) + 1 + strlen(tmp2) + 1 > len)
286		return -1;
287	snprintf(buf, len, "%s-%s", tmp1, tmp2);
288	return 0;
289}
290
291static char *
292set_address(buf, len, sa)
293	char *buf;
294	size_t len;
295	struct sockaddr *sa;
296{
297#ifdef NI_WITHSCOPEID
298	const int niflags = NI_NUMERICHOST | NI_WITHSCOPEID;
299#else
300	const int niflags = NI_NUMERICHOST;
301#endif
302
303	if (len < 1)
304		return NULL;
305	buf[0] = '\0';
306	if (getnameinfo(sa, sa->sa_len, buf, len, NULL, 0, niflags) != 0)
307		return NULL;
308	return buf;
309}
310