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