11556Srgrimes/*	$KAME: ipsec_dump_policy.c,v 1.13 2002/06/27 14:35:11 itojun Exp $	*/
21556Srgrimes
31556Srgrimes/*
41556Srgrimes * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
51556Srgrimes * All rights reserved.
61556Srgrimes *
71556Srgrimes * Redistribution and use in source and binary forms, with or without
81556Srgrimes * modification, are permitted provided that the following conditions
91556Srgrimes * are met:
101556Srgrimes * 1. Redistributions of source code must retain the above copyright
111556Srgrimes *    notice, this list of conditions and the following disclaimer.
121556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
131556Srgrimes *    notice, this list of conditions and the following disclaimer in the
141556Srgrimes *    documentation and/or other materials provided with the distribution.
151556Srgrimes * 3. Neither the name of the project nor the names of its contributors
161556Srgrimes *    may be used to endorse or promote products derived from this software
171556Srgrimes *    without specific prior written permission.
181556Srgrimes *
191556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
201556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
211556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
221556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
231556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
241556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
251556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
261556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
271556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
281556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
291556Srgrimes * SUCH DAMAGE.
301556Srgrimes */
311556Srgrimes
321556Srgrimes#include <sys/cdefs.h>
331556Srgrimes__FBSDID("$FreeBSD$");
3436150Scharnier
3536150Scharnier#include <sys/types.h>
3636150Scharnier#include <sys/param.h>
371556Srgrimes#include <sys/socket.h>
3899110Sobrien
3999110Sobrien#include <netipsec/key_var.h>
401556Srgrimes#include <netinet/in.h>
4117987Speter#include <netipsec/ipsec.h>
4296922Stjr
4317987Speter#include <arpa/inet.h>
4417987Speter
4517987Speter#include <stdio.h>
4617987Speter#include <stdlib.h>
4717987Speter#include <string.h>
4817987Speter#include <netdb.h>
4917987Speter
501556Srgrimes#include "ipsec_strerror.h"
511556Srgrimes
521556Srgrimesstatic const char *ipsp_dir_strs[] = {
531556Srgrimes	"any", "in", "out",
541556Srgrimes};
551556Srgrimes
561556Srgrimesstatic const char *ipsp_policy_strs[] = {
571556Srgrimes	"discard", "none", "ipsec", "entrust", "bypass",
581556Srgrimes};
591556Srgrimes
601556Srgrimesstatic char *ipsec_dump_ipsecrequest(char *, size_t,
611556Srgrimes	struct sadb_x_ipsecrequest *, size_t);
6296922Stjrstatic int set_addresses(char *, size_t, struct sockaddr *, struct sockaddr *);
631556Srgrimesstatic char *set_address(char *, size_t, struct sockaddr *);
641556Srgrimes
651556Srgrimes/*
66199953Sjilles * policy is sadb_x_policy buffer.
671556Srgrimes * Must call free() later.
681556Srgrimes * When delimiter == NULL, alternatively ' '(space) is applied.
691556Srgrimes */
701556Srgrimeschar *
711556Srgrimesipsec_dump_policy(policy, delimiter)
721556Srgrimes	caddr_t policy;
73100315Stjr	char *delimiter;
741556Srgrimes{
751556Srgrimes	struct sadb_x_policy *xpl = (struct sadb_x_policy *)policy;
761556Srgrimes	struct sadb_x_ipsecrequest *xisr;
771556Srgrimes	size_t off, buflen;
781556Srgrimes	char *buf;
798855Srgrimes	char isrbuf[1024];
801556Srgrimes	char *newbuf;
811556Srgrimes
828855Srgrimes	/* sanity check */
831556Srgrimes	if (policy == NULL)
84117261Sdds		return NULL;
851556Srgrimes	if (xpl->sadb_x_policy_exttype != SADB_X_EXT_POLICY) {
8690111Simp		__ipsec_errcode = EIPSEC_INVAL_EXTTYPE;
8790111Simp		return NULL;
881556Srgrimes	}
891556Srgrimes
901556Srgrimes	/* set delimiter */
911556Srgrimes	if (delimiter == NULL)
921556Srgrimes		delimiter = " ";
931556Srgrimes
941556Srgrimes	switch (xpl->sadb_x_policy_dir) {
951556Srgrimes	case IPSEC_DIR_ANY:
961556Srgrimes	case IPSEC_DIR_INBOUND:
971556Srgrimes	case IPSEC_DIR_OUTBOUND:
981556Srgrimes		break;
9990111Simp	default:
10090111Simp		__ipsec_errcode = EIPSEC_INVAL_DIR;
1011556Srgrimes		return NULL;
10217987Speter	}
1031556Srgrimes
1041556Srgrimes	switch (xpl->sadb_x_policy_type) {
10520425Ssteve	case IPSEC_POLICY_DISCARD:
1061556Srgrimes	case IPSEC_POLICY_NONE:
1071556Srgrimes	case IPSEC_POLICY_IPSEC:
1081556Srgrimes	case IPSEC_POLICY_BYPASS:
1091556Srgrimes	case IPSEC_POLICY_ENTRUST:
1101556Srgrimes		break;
1111556Srgrimes	default:
1121556Srgrimes		__ipsec_errcode = EIPSEC_INVAL_POLICY;
1131556Srgrimes		return NULL;
1141556Srgrimes	}
1151556Srgrimes
1161556Srgrimes	buflen = strlen(ipsp_dir_strs[xpl->sadb_x_policy_dir])
1171556Srgrimes		+ 1	/* space */
1181556Srgrimes		+ strlen(ipsp_policy_strs[xpl->sadb_x_policy_type])
11911601Sjoerg		+ 1;	/* NUL */
12011601Sjoerg
12120425Ssteve	if ((buf = malloc(buflen)) == NULL) {
12225231Ssteve		__ipsec_errcode = EIPSEC_NO_BUFS;
1231556Srgrimes		return NULL;
1241556Srgrimes	}
12525231Ssteve	snprintf(buf, buflen, "%s %s", ipsp_dir_strs[xpl->sadb_x_policy_dir],
12625231Ssteve	    ipsp_policy_strs[xpl->sadb_x_policy_type]);
12725231Ssteve
128199953Sjilles	if (xpl->sadb_x_policy_type != IPSEC_POLICY_IPSEC) {
129199953Sjilles		__ipsec_errcode = EIPSEC_NO_ERROR;
13025231Ssteve		return buf;
13125231Ssteve	}
13225231Ssteve
13325231Ssteve	/* count length of buffer for use */
13425231Ssteve	off = sizeof(*xpl);
135199953Sjilles	while (off < PFKEY_EXTLEN(xpl)) {
136199953Sjilles		xisr = (struct sadb_x_ipsecrequest *)((caddr_t)xpl + off);
137199953Sjilles		off += xisr->sadb_x_ipsecrequest_len;
1381556Srgrimes	}
1391556Srgrimes
14025231Ssteve	/* validity check */
14125231Ssteve	if (off != PFKEY_EXTLEN(xpl)) {
142199953Sjilles		__ipsec_errcode = EIPSEC_INVAL_SADBMSG;
1431556Srgrimes		free(buf);
1441556Srgrimes		return NULL;
1451556Srgrimes	}
1461556Srgrimes
1471556Srgrimes	off = sizeof(*xpl);
1481556Srgrimes	while (off < PFKEY_EXTLEN(xpl)) {
1491556Srgrimes		xisr = (struct sadb_x_ipsecrequest *)((caddr_t)xpl + off);
1501556Srgrimes
1511556Srgrimes		if (ipsec_dump_ipsecrequest(isrbuf, sizeof(isrbuf), xisr,
15290111Simp		    PFKEY_EXTLEN(xpl) - off) == NULL) {
15390111Simp			free(buf);
15496922Stjr			return NULL;
1551556Srgrimes		}
1561556Srgrimes
1571556Srgrimes		buflen = strlen(buf) + strlen(delimiter) + strlen(isrbuf) + 1;
1581556Srgrimes		newbuf = (char *)realloc(buf, buflen);
1591556Srgrimes		if (newbuf == NULL) {
1601556Srgrimes			__ipsec_errcode = EIPSEC_NO_BUFS;
161199660Sjilles			free(buf);
162199660Sjilles			return NULL;
163199660Sjilles		}
164199660Sjilles		buf = newbuf;
165199660Sjilles		snprintf(buf + strlen(buf), buflen - strlen(buf),
1661556Srgrimes		    "%s%s", delimiter, isrbuf);
1671556Srgrimes
1681556Srgrimes		off += xisr->sadb_x_ipsecrequest_len;
1691556Srgrimes	}
1701556Srgrimes
1711556Srgrimes	__ipsec_errcode = EIPSEC_NO_ERROR;
1721556Srgrimes	return buf;
173104132Stjr}
1741556Srgrimes
1751556Srgrimesstatic char *
176124780Sdesipsec_dump_ipsecrequest(buf, len, xisr, bound)
1771556Srgrimes	char *buf;
1781556Srgrimes	size_t len;
1791556Srgrimes	struct sadb_x_ipsecrequest *xisr;
18066612Sbrian	size_t bound;	/* boundary */
18166612Sbrian{
18266612Sbrian	const char *proto, *mode, *level;
183104132Stjr	char abuf[NI_MAXHOST * 2 + 2];
18466612Sbrian
1851556Srgrimes	if (xisr->sadb_x_ipsecrequest_len > bound) {
186194560Sjilles		__ipsec_errcode = EIPSEC_INVAL_PROTO;
187194560Sjilles		return NULL;
188194560Sjilles	}
189194560Sjilles
190194560Sjilles	switch (xisr->sadb_x_ipsecrequest_proto) {
191194560Sjilles	case IPPROTO_ESP:
192194560Sjilles		proto = "esp";
193194560Sjilles		break;
194194560Sjilles	case IPPROTO_AH:
195194560Sjilles		proto = "ah";
196194560Sjilles		break;
197194560Sjilles	case IPPROTO_IPCOMP:
198194560Sjilles		proto = "ipcomp";
199194560Sjilles		break;
200194560Sjilles	case IPPROTO_TCP:
201194560Sjilles		proto = "tcp";
202194560Sjilles		break;
203194560Sjilles	default:
204194560Sjilles		__ipsec_errcode = EIPSEC_INVAL_PROTO;
20596922Stjr		return NULL;
20696922Stjr	}
20796922Stjr
208104132Stjr	switch (xisr->sadb_x_ipsecrequest_mode) {
20996922Stjr	case IPSEC_MODE_ANY:
2101556Srgrimes		mode = "any";
2111556Srgrimes		break;
2121556Srgrimes	case IPSEC_MODE_TRANSPORT:
213104132Stjr		mode = "transport";
2141556Srgrimes		break;
2151556Srgrimes	case IPSEC_MODE_TUNNEL:
2161556Srgrimes		mode = "tunnel";
2171556Srgrimes		break;
2181556Srgrimes	default:
2191556Srgrimes		__ipsec_errcode = EIPSEC_INVAL_MODE;
220124780Sdes		return NULL;
221124780Sdes	}
222124780Sdes
22399645Stjr	abuf[0] = '\0';
224124780Sdes	if (xisr->sadb_x_ipsecrequest_len > sizeof(*xisr)) {
2251556Srgrimes		struct sockaddr *sa1, *sa2;
2261556Srgrimes		caddr_t p;
2271556Srgrimes
2281556Srgrimes		p = (caddr_t)(xisr + 1);
2291556Srgrimes		sa1 = (struct sockaddr *)p;
2301556Srgrimes		sa2 = (struct sockaddr *)(p + sa1->sa_len);
2311556Srgrimes		if (sizeof(*xisr) + sa1->sa_len + sa2->sa_len !=
2321556Srgrimes		    xisr->sadb_x_ipsecrequest_len) {
2331556Srgrimes			__ipsec_errcode = EIPSEC_INVAL_ADDRESS;
2341556Srgrimes			return NULL;
2351556Srgrimes		}
2361556Srgrimes		if (set_addresses(abuf, sizeof(abuf), sa1, sa2) != 0) {
2371556Srgrimes			__ipsec_errcode = EIPSEC_INVAL_ADDRESS;
2381556Srgrimes			return NULL;
2391556Srgrimes		}
2401556Srgrimes	}
2411556Srgrimes
2421556Srgrimes	switch (xisr->sadb_x_ipsecrequest_level) {
2431556Srgrimes	case IPSEC_LEVEL_DEFAULT:
24490111Simp		level = "default";
24590111Simp		break;
2461556Srgrimes	case IPSEC_LEVEL_USE:
24717987Speter		level = "use";
2481556Srgrimes		break;
2491556Srgrimes	case IPSEC_LEVEL_REQUIRE:
25053891Scracauer		level = "require";
2511556Srgrimes		break;
2521556Srgrimes	case IPSEC_LEVEL_UNIQUE:
2531556Srgrimes		level = "unique";
2541556Srgrimes		break;
2551556Srgrimes	default:
2561556Srgrimes		__ipsec_errcode = EIPSEC_INVAL_LEVEL;
2571556Srgrimes		return NULL;
2581556Srgrimes	}
2591556Srgrimes
2601556Srgrimes	if (xisr->sadb_x_ipsecrequest_reqid == 0)
2611556Srgrimes		snprintf(buf, len, "%s/%s/%s/%s", proto, mode, abuf, level);
2621556Srgrimes	else {
2631556Srgrimes		int ch;
2641556Srgrimes
2651556Srgrimes		if (xisr->sadb_x_ipsecrequest_reqid > IPSEC_MANUAL_REQID_MAX)
2661556Srgrimes			ch = '#';
2671556Srgrimes		else
2681556Srgrimes			ch = ':';
2691556Srgrimes		snprintf(buf, len, "%s/%s/%s/%s%c%u", proto, mode, abuf, level,
2701556Srgrimes		    ch, xisr->sadb_x_ipsecrequest_reqid);
2711556Srgrimes	}
2721556Srgrimes
2731556Srgrimes	return buf;
2741556Srgrimes}
2751556Srgrimes
2761556Srgrimesstatic int
2771556Srgrimesset_addresses(buf, len, sa1, sa2)
2781556Srgrimes	char *buf;
2791556Srgrimes	size_t len;
2801556Srgrimes	struct sockaddr *sa1;
2811556Srgrimes	struct sockaddr *sa2;
2821556Srgrimes{
28390111Simp	char tmp1[NI_MAXHOST], tmp2[NI_MAXHOST];
28490111Simp
28525231Ssteve	if (set_address(tmp1, sizeof(tmp1), sa1) == NULL ||
2861556Srgrimes	    set_address(tmp2, sizeof(tmp2), sa2) == NULL)
2871556Srgrimes		return -1;
2881556Srgrimes	if (strlen(tmp1) + 1 + strlen(tmp2) + 1 > len)
2891556Srgrimes		return -1;
2901556Srgrimes	snprintf(buf, len, "%s-%s", tmp1, tmp2);
2911556Srgrimes	return 0;
2921556Srgrimes}
293124780Sdes
2941556Srgrimesstatic char *
295124780Sdesset_address(buf, len, sa)
296124780Sdes	char *buf;
2971556Srgrimes	size_t len;
2981556Srgrimes	struct sockaddr *sa;
2991556Srgrimes{
3001556Srgrimes	const int niflags = NI_NUMERICHOST;
3011556Srgrimes
3021556Srgrimes	if (len < 1)
3031556Srgrimes		return NULL;
3041556Srgrimes	buf[0] = '\0';
3051556Srgrimes	if (getnameinfo(sa, sa->sa_len, buf, len, NULL, 0, niflags) != 0)
3061556Srgrimes		return NULL;
3071556Srgrimes	return buf;
3081556Srgrimes}
3091556Srgrimes