Home | History | Annotate | Download | only in libipsec
      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 *
     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 *
     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 *
     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 *
    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
    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 *
    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