1 /* $NetBSD: ipsec_dump_policy.c,v 1.7.6.1 2007/08/01 11:52:17 vanhu Exp $ */
2
3 /* Id: ipsec_dump_policy.c,v 1.10 2005/06/29 09:12:37 manubsd Exp */
4
5 /*
6 * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
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 #ifdef HAVE_CONFIG_H
35 #include "config.h"
36 #endif
37
38 #include <sys/types.h>
39 #include <sys/param.h>
40 #include <sys/socket.h>
41
42 #include <netinet/in.h>
43 #include PATH_IPSEC_H
44
45 #include <arpa/inet.h>
46
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <netdb.h>
51
52 #include "ipsec_strerror.h"
53 #include "libpfkey.h"
54
55 static const char *ipsp_dir_strs[] = {
56 "any", "in", "out", "fwd"
57 };
58
59 static const char *ipsp_policy_strs[] = {
60 "discard", "none", "ipsec", "entrust", "bypass",
61 };
62
63 static char *ipsec_dump_ipsecrequest __P((char *, size_t,
64 struct sadb_x_ipsecrequest *, size_t, int));
65 static char *ipsec_dump_policy1 __P((void *, const char *, int));
66 static int set_addresses __P((char *, size_t, struct sockaddr *,
67 struct sockaddr *, int));
68 static char *set_address __P((char *, size_t, struct sockaddr *, int));
69
70 /*
71 * policy is sadb_x_policy buffer.
72 * Must call free() later.
73 * When delimiter == NULL, alternatively ' '(space) is applied.
74 */
75 char *
ipsec_dump_policy(policy,delimiter)76 ipsec_dump_policy(policy, delimiter)
77 ipsec_policy_t policy;
78 __ipsec_const char *delimiter;
79 {
80 return ipsec_dump_policy1(policy, delimiter, 0);
81 }
82
83 char *
ipsec_dump_policy_withports(policy,delimiter)84 ipsec_dump_policy_withports(policy, delimiter)
85 void *policy;
86 const char *delimiter;
87 {
88 return ipsec_dump_policy1(policy, delimiter, 1);
89 }
90
91 static char *
ipsec_dump_policy1(policy,delimiter,withports)92 ipsec_dump_policy1(policy, delimiter, withports)
93 void *policy;
94 const char *delimiter;
95 int withports;
96 {
97 struct sadb_x_policy *xpl = policy;
98 struct sadb_x_ipsecrequest *xisr;
99 size_t off, buflen;
100 char *buf;
101 char isrbuf[1024];
102 char *newbuf;
103
104 #ifdef HAVE_PFKEY_POLICY_PRIORITY
105 int32_t priority_offset;
106 char *priority_str;
107 char operator;
108 #endif
109
110 /* sanity check */
111 if (policy == NULL)
112 return NULL;
113 if (xpl->sadb_x_policy_exttype != SADB_X_EXT_POLICY) {
114 __ipsec_errcode = EIPSEC_INVAL_EXTTYPE;
115 return NULL;
116 }
117
118 /* set delimiter */
119 if (delimiter == NULL)
120 delimiter = " ";
121
122 #ifdef HAVE_PFKEY_POLICY_PRIORITY
123 if (xpl->sadb_x_policy_priority == 0)
124 {
125 priority_offset = 0;
126 priority_str = "";
127 }
128 /* find which constant the priority is closest to */
129 else if (xpl->sadb_x_policy_priority <
130 (u_int32_t) (PRIORITY_DEFAULT / 4) * 3)
131 {
132 priority_offset = xpl->sadb_x_policy_priority - PRIORITY_HIGH;
133 priority_str = "prio high";
134 }
135 else if (xpl->sadb_x_policy_priority >=
136 (u_int32_t) (PRIORITY_DEFAULT / 4) * 3 &&
137 xpl->sadb_x_policy_priority <
138 (u_int32_t) (PRIORITY_DEFAULT / 4) * 5)
139 {
140 priority_offset = xpl->sadb_x_policy_priority - PRIORITY_DEFAULT;
141 priority_str = "prio def";
142 }
143 else
144 {
145 priority_offset = xpl->sadb_x_policy_priority - PRIORITY_LOW;
146 priority_str = "prio low";
147 }
148
149 /* fix sign to match the way it is input */
150 priority_offset *= -1;
151 if (priority_offset < 0)
152 {
153 operator = '-';
154 priority_offset *= -1;
155 }
156 else
157 {
158 operator = '+';
159 }
160 #endif
161
162 switch (xpl->sadb_x_policy_dir) {
163 case IPSEC_DIR_ANY:
164 case IPSEC_DIR_INBOUND:
165 case IPSEC_DIR_OUTBOUND:
166 #ifdef HAVE_POLICY_FWD
167 case IPSEC_DIR_FWD:
168 #endif
169 break;
170 default:
171 __ipsec_errcode = EIPSEC_INVAL_DIR;
172 return NULL;
173 }
174
175 switch (xpl->sadb_x_policy_type) {
176 case IPSEC_POLICY_DISCARD:
177 case IPSEC_POLICY_NONE:
178 case IPSEC_POLICY_IPSEC:
179 case IPSEC_POLICY_BYPASS:
180 case IPSEC_POLICY_ENTRUST:
181 break;
182 default:
183 __ipsec_errcode = EIPSEC_INVAL_POLICY;
184 return NULL;
185 }
186
187 buflen = strlen(ipsp_dir_strs[xpl->sadb_x_policy_dir])
188 + 1 /* space */
189 #ifdef HAVE_PFKEY_POLICY_PRIORITY
190 + strlen(priority_str)
191 + ((priority_offset != 0) ? 13 : 0) /* [space operator space int] */
192 + ((strlen(priority_str) != 0) ? 1 : 0) /* space */
193 #endif
194 + strlen(ipsp_policy_strs[xpl->sadb_x_policy_type])
195 + 1; /* NUL */
196
197 if ((buf = malloc(buflen)) == NULL) {
198 __ipsec_errcode = EIPSEC_NO_BUFS;
199 return NULL;
200 }
201 #ifdef HAVE_PFKEY_POLICY_PRIORITY
202 if (priority_offset != 0)
203 {
204 snprintf(buf, buflen, "%s %s %c %u %s",
205 ipsp_dir_strs[xpl->sadb_x_policy_dir], priority_str, operator,
206 priority_offset, ipsp_policy_strs[xpl->sadb_x_policy_type]);
207 }
208 else if (strlen (priority_str) != 0)
209 {
210 snprintf(buf, buflen, "%s %s %s",
211 ipsp_dir_strs[xpl->sadb_x_policy_dir], priority_str,
212 ipsp_policy_strs[xpl->sadb_x_policy_type]);
213 }
214 else
215 {
216 snprintf(buf, buflen, "%s %s",
217 ipsp_dir_strs[xpl->sadb_x_policy_dir],
218 ipsp_policy_strs[xpl->sadb_x_policy_type]);
219 }
220 #else
221 snprintf(buf, buflen, "%s %s", ipsp_dir_strs[xpl->sadb_x_policy_dir],
222 ipsp_policy_strs[xpl->sadb_x_policy_type]);
223 #endif
224
225 if (xpl->sadb_x_policy_type != IPSEC_POLICY_IPSEC) {
226 __ipsec_errcode = EIPSEC_NO_ERROR;
227 return buf;
228 }
229
230 /* count length of buffer for use */
231 off = sizeof(*xpl);
232 while (off < PFKEY_EXTLEN(xpl)) {
233 xisr = (void *)((caddr_t)(void *)xpl + off);
234 off += xisr->sadb_x_ipsecrequest_len;
235 }
236
237 /* validity check */
238 if (off != PFKEY_EXTLEN(xpl)) {
239 __ipsec_errcode = EIPSEC_INVAL_SADBMSG;
240 free(buf);
241 return NULL;
242 }
243
244 off = sizeof(*xpl);
245 while (off < PFKEY_EXTLEN(xpl)) {
246 int offset;
247 xisr = (void *)((caddr_t)(void *)xpl + off);
248
249 if (ipsec_dump_ipsecrequest(isrbuf, sizeof(isrbuf), xisr,
250 PFKEY_EXTLEN(xpl) - off, withports) == NULL) {
251 free(buf);
252 return NULL;
253 }
254
255 offset = strlen(buf);
256 buflen = offset + strlen(delimiter) + strlen(isrbuf) + 1;
257 newbuf = (char *)realloc(buf, buflen);
258 if (newbuf == NULL) {
259 __ipsec_errcode = EIPSEC_NO_BUFS;
260 free(buf);
261 return NULL;
262 }
263 buf = newbuf;
264 snprintf(buf+offset, buflen-offset, "%s%s", delimiter, isrbuf);
265
266 off += xisr->sadb_x_ipsecrequest_len;
267 }
268
269 __ipsec_errcode = EIPSEC_NO_ERROR;
270 return buf;
271 }
272
273 static char *
ipsec_dump_ipsecrequest(buf,len,xisr,bound,withports)274 ipsec_dump_ipsecrequest(buf, len, xisr, bound, withports)
275 char *buf;
276 size_t len;
277 struct sadb_x_ipsecrequest *xisr;
278 size_t bound; /* boundary */
279 int withports;
280 {
281 const char *proto, *mode, *level;
282 char abuf[NI_MAXHOST * 2 + 2];
283
284 if (xisr->sadb_x_ipsecrequest_len > bound) {
285 __ipsec_errcode = EIPSEC_INVAL_PROTO;
286 return NULL;
287 }
288
289 switch (xisr->sadb_x_ipsecrequest_proto) {
290 case IPPROTO_ESP:
291 proto = "esp";
292 break;
293 case IPPROTO_AH:
294 proto = "ah";
295 break;
296 case IPPROTO_IPCOMP:
297 proto = "ipcomp";
298 break;
299 default:
300 __ipsec_errcode = EIPSEC_INVAL_PROTO;
301 return NULL;
302 }
303
304 switch (xisr->sadb_x_ipsecrequest_mode) {
305 case IPSEC_MODE_ANY:
306 mode = "any";
307 break;
308 case IPSEC_MODE_TRANSPORT:
309 mode = "transport";
310 break;
311 case IPSEC_MODE_TUNNEL:
312 mode = "tunnel";
313 break;
314 default:
315 __ipsec_errcode = EIPSEC_INVAL_MODE;
316 return NULL;
317 }
318
319 abuf[0] = '\0';
320 if (xisr->sadb_x_ipsecrequest_len > sizeof(*xisr)) {
321 struct sockaddr *sa1, *sa2;
322 caddr_t p;
323
324 p = (void *)(xisr + 1);
325 sa1 = (void *)p;
326 sa2 = (void *)(p + sysdep_sa_len(sa1));
327 if (sizeof(*xisr) + sysdep_sa_len(sa1) + sysdep_sa_len(sa2) !=
328 xisr->sadb_x_ipsecrequest_len) {
329 __ipsec_errcode = EIPSEC_INVAL_ADDRESS;
330 return NULL;
331 }
332 if (set_addresses(abuf, sizeof(abuf),
333 sa1, sa2, withports) != 0) {
334 __ipsec_errcode = EIPSEC_INVAL_ADDRESS;
335 return NULL;
336 }
337 }
338
339 switch (xisr->sadb_x_ipsecrequest_level) {
340 case IPSEC_LEVEL_DEFAULT:
341 level = "default";
342 break;
343 case IPSEC_LEVEL_USE:
344 level = "use";
345 break;
346 case IPSEC_LEVEL_REQUIRE:
347 level = "require";
348 break;
349 case IPSEC_LEVEL_UNIQUE:
350 level = "unique";
351 break;
352 default:
353 __ipsec_errcode = EIPSEC_INVAL_LEVEL;
354 return NULL;
355 }
356
357 if (xisr->sadb_x_ipsecrequest_reqid == 0)
358 snprintf(buf, len, "%s/%s/%s/%s", proto, mode, abuf, level);
359 else {
360 int ch;
361
362 if (xisr->sadb_x_ipsecrequest_reqid > IPSEC_MANUAL_REQID_MAX)
363 ch = '#';
364 else
365 ch = ':';
366 snprintf(buf, len, "%s/%s/%s/%s%c%u", proto, mode, abuf, level,
367 ch, xisr->sadb_x_ipsecrequest_reqid);
368 }
369
370 return buf;
371 }
372
373 static int
set_addresses(buf,len,sa1,sa2,withports)374 set_addresses(buf, len, sa1, sa2, withports)
375 char *buf;
376 size_t len;
377 struct sockaddr *sa1;
378 struct sockaddr *sa2;
379 int withports;
380 {
381 char tmp1[NI_MAXHOST], tmp2[NI_MAXHOST];
382
383 if (set_address(tmp1, sizeof(tmp1), sa1, withports) == NULL ||
384 set_address(tmp2, sizeof(tmp2), sa2, withports) == NULL)
385 return -1;
386 if (strlen(tmp1) + 1 + strlen(tmp2) + 1 > len)
387 return -1;
388 snprintf(buf, len, "%s-%s", tmp1, tmp2);
389 return 0;
390 }
391
392 static char *
set_address(buf,len,sa,withports)393 set_address(buf, len, sa, withports)
394 char *buf;
395 size_t len;
396 struct sockaddr *sa;
397 int withports;
398 {
399 const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
400 char host[NI_MAXHOST];
401 char serv[NI_MAXSERV];
402
403 if (len < 1)
404 return NULL;
405 buf[0] = '\0';
406 if (getnameinfo(sa, (socklen_t)sysdep_sa_len(sa), host, sizeof(host),
407 serv, sizeof(serv), niflags) != 0)
408 return NULL;
409
410 if (withports)
411 snprintf(buf, len, "%s[%s]", host, serv);
412 else
413 snprintf(buf, len, "%s", host);
414
415 return buf;
416 }
417