xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/ipsecconf.c (revision 10372:2a69958cda3f)
14235Smarkfen /*
24235Smarkfen  * CDDL HEADER START
34235Smarkfen  *
44235Smarkfen  * The contents of this file are subject to the terms of the
54235Smarkfen  * Common Development and Distribution License (the "License").
64235Smarkfen  * You may not use this file except in compliance with the License.
74235Smarkfen  *
84235Smarkfen  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
94235Smarkfen  * or http://www.opensolaris.org/os/licensing.
104235Smarkfen  * See the License for the specific language governing permissions
114235Smarkfen  * and limitations under the License.
124235Smarkfen  *
134235Smarkfen  * When distributing Covered Code, include this CDDL HEADER in each
144235Smarkfen  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
154235Smarkfen  * If applicable, add the following below this CDDL HEADER, with the
164235Smarkfen  * fields enclosed by brackets "[]" replaced with your own identifying
174235Smarkfen  * information: Portions Copyright [yyyy] [name of copyright owner]
184235Smarkfen  *
194235Smarkfen  * CDDL HEADER END
204235Smarkfen  */
214235Smarkfen /*
22*10372Sdanmcd@sun.com  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
234235Smarkfen  * Use is subject to license terms.
244235Smarkfen  */
254235Smarkfen 
264235Smarkfen #include <stdio.h>
274235Smarkfen #include <sys/types.h>
284235Smarkfen #include <sys/stat.h>
294235Smarkfen #include <strings.h>
304235Smarkfen #include <stropts.h>
314235Smarkfen #include <fcntl.h>
324235Smarkfen #include <stdlib.h>
334235Smarkfen #include <unistd.h>
344235Smarkfen #include <string.h>
354235Smarkfen #include <ctype.h>
364235Smarkfen #include <arpa/inet.h>
374235Smarkfen #include <locale.h>
384235Smarkfen #include <syslog.h>
394235Smarkfen #include <pwd.h>
404235Smarkfen #include <sys/param.h>
414235Smarkfen #include <sys/sysmacros.h>	/* MIN, MAX */
424235Smarkfen #include <sys/sockio.h>
434235Smarkfen #include <net/pfkeyv2.h>
444235Smarkfen #include <net/pfpolicy.h>
454235Smarkfen #include <inet/ipsec_impl.h>
464235Smarkfen #include <signal.h>
474235Smarkfen #include <errno.h>
484235Smarkfen #include <netdb.h>
494235Smarkfen #include <sys/socket.h>
504235Smarkfen #include <sys/systeminfo.h>
514235Smarkfen #include <nss_dbdefs.h>					/* NSS_BUFLEN_HOSTS */
524235Smarkfen #include <netinet/in.h>
534235Smarkfen #include <assert.h>
544235Smarkfen #include <inet/ip.h>
554235Smarkfen #include <ipsec_util.h>
564235Smarkfen #include <netinet/in_systm.h>
574235Smarkfen #include <netinet/ip_icmp.h>
584235Smarkfen #include <netinet/icmp6.h>
594235Smarkfen 
604235Smarkfen /*
614235Smarkfen  * Globals
624235Smarkfen  */
634235Smarkfen int lfd;
644235Smarkfen char *my_fmri;
654235Smarkfen FILE *debugfile = stderr;
664235Smarkfen 
674235Smarkfen #define	USAGE() if (!smf_managed) usage()
684235Smarkfen /*
694235Smarkfen  * Buffer length to read in pattern/properties.
704235Smarkfen  */
714235Smarkfen #define	MAXLEN			1024
724235Smarkfen 
734235Smarkfen /* Max length of tunnel interface string identifier */
744235Smarkfen #define	TUNNAMEMAXLEN		LIFNAMSIZ
754235Smarkfen 
764235Smarkfen /*
774235Smarkfen  * Used by parse_one and parse/parse_action to communicate
784235Smarkfen  * the errors. -1 is failure, which is not defined here.
794235Smarkfen  */
804235Smarkfen enum parse_errors {PARSE_SUCCESS, PARSE_EOF};
814235Smarkfen 
824235Smarkfen /*
834235Smarkfen  * For spdsock_get_ext() diagnostics.
844235Smarkfen  */
854235Smarkfen #define	SPDSOCK_DIAG_BUF_LEN	128
864235Smarkfen static char spdsock_diag_buf[SPDSOCK_DIAG_BUF_LEN];
874235Smarkfen 
884235Smarkfen /*
894235Smarkfen  * Define CURL here so that while you are reading
904235Smarkfen  * this code, it does not affect "vi" in pattern
914235Smarkfen  * matching.
924235Smarkfen  */
934235Smarkfen #define	CURL_BEGIN		'{'
944235Smarkfen #define	CURL_END		'}'
955120Smarkfen #define	BACK_SLASH		'\\'
964235Smarkfen #define	MAXARGS			20
974235Smarkfen #define	NOERROR			0
984235Smarkfen 
994235Smarkfen /*
1004235Smarkfen  * IPSEC_CONF_ADD should start with 1, so that when multiple commands
1014235Smarkfen  * are given, we can fail the request.
1024235Smarkfen  */
1034235Smarkfen 
1044235Smarkfen enum ipsec_cmds {IPSEC_CONF_ADD = 1, IPSEC_CONF_DEL, IPSEC_CONF_VIEW,
1054235Smarkfen     IPSEC_CONF_FLUSH, IPSEC_CONF_LIST, IPSEC_CONF_SUB};
1064235Smarkfen 
1074235Smarkfen static const char policy_conf_file[] = "/var/run/ipsecpolicy.conf";
1084235Smarkfen static const char lock_file[] = "/var/run/ipsecconf.lock";
1094235Smarkfen static const char index_tag[] = "#INDEX";
1104235Smarkfen 
1114235Smarkfen #define	POLICY_CONF_FILE	policy_conf_file
1124235Smarkfen #define	LOCK_FILE		lock_file
1134235Smarkfen #define	INDEX_TAG		index_tag
1144235Smarkfen 
1154235Smarkfen /*
1164235Smarkfen  * Valid algorithm length.
1174235Smarkfen  */
1184235Smarkfen #define	VALID_ALG_LEN		40
1194235Smarkfen 
1204235Smarkfen /* Types of Error messages */
1214235Smarkfen typedef enum error_type {BAD_ERROR, DUP_ERROR, REQ_ERROR} error_type_t;
1224235Smarkfen 
1234235Smarkfen /* Error message human readable conversions */
1244235Smarkfen static char *sys_error_message(int);
1254235Smarkfen static void error_message(error_type_t, int, int);
1264235Smarkfen static int get_pf_pol_socket(void);
1274235Smarkfen 
1284235Smarkfen static int cmd;
1294235Smarkfen static char *filename;
1304235Smarkfen static char lo_buf[MAXLEN];			/* Leftover buffer */
1314235Smarkfen 
1324235Smarkfen /*
1334235Smarkfen  * The new SPD_EXT_TUN_NAME extension has a tunnel name in it.  Use the empty
1344235Smarkfen  * string ("", stored in the char value "all_polheads") for all policy heads
1354235Smarkfen  * (global and all tunnels).  Set interface_name to NULL for global-only, or
1364235Smarkfen  * specify a name of an IP-in-IP tunnel.
1374235Smarkfen  */
1384235Smarkfen static char *interface_name;
1394235Smarkfen static char all_polheads;	/* So we can easily get "". */
1404235Smarkfen 
1414235Smarkfen /* Error reporting stuff */
1424235Smarkfen #define	CBUF_LEN		4096		/* Maximum size of the cmd */
1434235Smarkfen /*
1444235Smarkfen  * Following are used for reporting errors with arguments.
1454235Smarkfen  * We store the line numbers of each argument as we parse them,
1464235Smarkfen  * so that the error reporting is more specific. We can have only
1475120Smarkfen  * (MAXARGS - 1) arguments between any pair of CURL_BEGIN CURL_END.
1485120Smarkfen  * Because a single command can be made up of multiple action/property
1495120Smarkfen  * combinations, the maximum command size is (2 * (MAXARGS -1)) for each
1505120Smarkfen  * of patterns, properties and actions.
1514235Smarkfen  */
1525120Smarkfen #define	ARG_BUF_LEN		((2 * 3 * (MAXARGS - 1)) + 1)
1534235Smarkfen static int arg_indices[ARG_BUF_LEN];
1544235Smarkfen static int argindex;
1554235Smarkfen static int linecount;
1564235Smarkfen static char cbuf[CBUF_LEN];				/* Command buffer */
1574235Smarkfen static int cbuf_offset;
1584235Smarkfen 
1594235Smarkfen 
1604235Smarkfen #define	BYPASS_POLICY_BOOST		0x00800000
1614235Smarkfen #define	ESP_POLICY_BOOST		0x00400000
1624235Smarkfen #define	AH_POLICY_BOOST			0x00200000
1634235Smarkfen #define	INITIAL_BASE_PRIORITY		0x000fffff
1644235Smarkfen 
1654235Smarkfen /*
1664235Smarkfen  * the number used to order the
1674235Smarkfen  * rules starts at a certain base and
1684235Smarkfen  * goes down.  i.e. rules earlier in
1694235Smarkfen  * the file are checked first
1704235Smarkfen  */
1714235Smarkfen static uint32_t priority = INITIAL_BASE_PRIORITY;
1724235Smarkfen 
1734235Smarkfen #define	AH_AUTH		0
1744235Smarkfen #define	ESP_ENCR	1
1754235Smarkfen #define	ESP_AUTH	2
1764235Smarkfen 
1774235Smarkfen 
1784235Smarkfen /*
1794235Smarkfen  * for deleting adds on error
1804235Smarkfen  */
1814235Smarkfen 
1824235Smarkfen typedef struct d_list_s
1834235Smarkfen {
1844235Smarkfen 	struct d_list_s *next;
1854235Smarkfen 	int index;
1864235Smarkfen } d_list_t;
1874235Smarkfen 
1884235Smarkfen static d_list_t *d_list = NULL;
1894235Smarkfen static d_list_t *d_tail = NULL;
1904235Smarkfen 
1914235Smarkfen 
1924235Smarkfen /*
1934235Smarkfen  * Used for multi-homed source/dest hosts.
1944235Smarkfen  */
1954235Smarkfen static struct hostent *shp, *dhp;
1964235Smarkfen static unsigned int splen, dplen;
1974235Smarkfen static char tunif[TUNNAMEMAXLEN];
1984235Smarkfen static boolean_t has_saprefix, has_daprefix;
1994235Smarkfen static uint32_t seq_cnt = 0;
2004235Smarkfen 
2014235Smarkfen /* lexxed out action and related properties */
2024235Smarkfen typedef struct ap_s
2034235Smarkfen {
2044235Smarkfen 	char *act;
2054235Smarkfen 	char *prop[MAXARGS + 1];
2064235Smarkfen } ap_t;
2074235Smarkfen 
2084235Smarkfen 
2094235Smarkfen /* one lexxed out rule */
2104235Smarkfen typedef struct act_prop_s {
2115120Smarkfen 	char *pattern[MAXARGS + 1];
2124235Smarkfen 	ap_t ap[MAXARGS + 1];
2134235Smarkfen } act_prop_t;
2144235Smarkfen 
2154235Smarkfen typedef struct
2164235Smarkfen {
2174235Smarkfen 	uint8_t	 alg_id;
2184235Smarkfen 	uint32_t alg_minbits;
2194235Smarkfen 	uint32_t alg_maxbits;
2204235Smarkfen } algreq_t;
2214235Smarkfen 
2224235Smarkfen /* structure to hold all information for one act_prop_t */
2234235Smarkfen typedef struct ips_act_props_s {
2244235Smarkfen 	struct ips_act_props_s	*iap_next;
2254235Smarkfen 	struct ips_conf_s		*iap_head;
2264235Smarkfen 
2274235Smarkfen /*
2284235Smarkfen  * IPsec action types (in SPD_ATTR_TYPE attribute)
2294235Smarkfen  * SPD_ACTTYPE_DROP	0x0001
2304235Smarkfen  * SPD_ACTTYPE_PASS	0x0002
2314235Smarkfen  * SPD_ACTTYPE_IPSEC	0x0003
2324235Smarkfen  */
2334235Smarkfen 	uint16_t	iap_action;
2344235Smarkfen 	uint16_t	iap_act_tok;
2354235Smarkfen 
2364235Smarkfen /*
2374235Smarkfen  * Action ATTR flags (in SPD_ATTR_FLAGS attribute)
2384235Smarkfen  *	SPD_APPLY_AH		0x0001
2394235Smarkfen  *	SPD_APPLY_ESP		0x0002
2404235Smarkfen  *	SPD_APPLY_SE		0x0004  * self-encapsulation *
2414235Smarkfen  *	SPD_APPLY_COMP		0x0008	* compression; NYI *
2424235Smarkfen  *	SPD_APPLY_UNIQUE	0x0010	* unique per-flow SA *
2434235Smarkfen  *	SPD_APPLY_BYPASS	0x0020	* bypass policy *
2444235Smarkfen  */
2454235Smarkfen 	uint16_t	iap_attr;
2464235Smarkfen 	uint16_t	iap_attr_tok[5];
2474235Smarkfen 
2484235Smarkfen 	algreq_t	iap_aauth;
2494235Smarkfen 	algreq_t	iap_eencr;
2504235Smarkfen 	algreq_t	iap_eauth;
2514235Smarkfen 
2524235Smarkfen 	uint32_t iap_life_soft_time;
2534235Smarkfen 	uint32_t iap_life_hard_time;
2544235Smarkfen 	uint32_t iap_life_soft_bytes;
2554235Smarkfen 	uint32_t iap_life_hard_bytes;
2564235Smarkfen 
2574235Smarkfen } ips_act_props_t;
2584235Smarkfen 
2594235Smarkfen #define	V4_PART_OF_V6(v6)	v6._S6_un._S6_u32[3]
2604235Smarkfen 
2614235Smarkfen typedef struct ips_conf_s {
2624235Smarkfen 	/* selector */
2634235Smarkfen 	uint16_t patt_tok[8];
2644235Smarkfen 	uint8_t has_saddr;
2654235Smarkfen 	uint8_t has_daddr;
2664235Smarkfen 	uint8_t has_smask;
2674235Smarkfen 	uint8_t has_dmask;
2684235Smarkfen 	uint8_t has_type;
2694235Smarkfen 	uint8_t has_code;
2704235Smarkfen 	uint8_t has_negotiate;
2714235Smarkfen 	uint8_t has_tunnel;
2724235Smarkfen 	uint16_t swap;
2734235Smarkfen 
2744235Smarkfen 	struct in6_addr	ips_src_addr_v6;
2754235Smarkfen 	struct in6_addr	ips_src_mask_v6;
2764235Smarkfen 	struct in6_addr	ips_dst_addr_v6;
2774235Smarkfen 	struct in6_addr	ips_dst_mask_v6;
2784235Smarkfen 	uint8_t 		ips_src_mask_len;
2794235Smarkfen 	uint8_t 		ips_dst_mask_len;
2804235Smarkfen 	in_port_t		ips_src_port_min;
2814235Smarkfen 	in_port_t		ips_src_port_max;
2824235Smarkfen 	in_port_t		ips_dst_port_min;
2834235Smarkfen 	in_port_t		ips_dst_port_max;
2844235Smarkfen 	uint8_t			ips_icmp_type;
2854235Smarkfen 	uint8_t			ips_icmp_type_end;
2864235Smarkfen 	uint8_t			ips_icmp_code;
2874235Smarkfen 	uint8_t			ips_icmp_code_end;
2884235Smarkfen 	uint8_t			ips_ulp_prot;
2894235Smarkfen 	uint8_t			ips_ipsec_prot;
2904235Smarkfen 	uint8_t			ips_isv4;
2914235Smarkfen 	/*
2924235Smarkfen 	 * SPD_RULE_FLAG_INBOUND		0x0001
2934235Smarkfen 	 * SPD_RULE_FLAG_OUTBOUND		0x0002
2944235Smarkfen 	 */
2954235Smarkfen 	uint8_t			ips_dir;
2964235Smarkfen 	/*
2974235Smarkfen 	 * Keep track of tunnel separately due to explosion of ways to set
2984235Smarkfen 	 * inbound/outbound.
2994235Smarkfen 	 */
3004235Smarkfen 	boolean_t		ips_tunnel;
3014235Smarkfen 	uint64_t		ips_policy_index;
3024235Smarkfen 	uint32_t		ips_act_cnt;
3034235Smarkfen 	ips_act_props_t	*ips_acts;
3044235Smarkfen } ips_conf_t;
3054235Smarkfen 
3064235Smarkfen #define	ips_src_addr	V4_PART_OF_V6(ips_src_addr_v6)
3074235Smarkfen #define	ips_dst_addr	V4_PART_OF_V6(ips_dst_addr_v6)
3084235Smarkfen 
3094235Smarkfen static int ipsecconf_nflag;		/* Used only with -l option */
3104235Smarkfen static int ipsecconf_qflag;		/* Used only with -a|-r option */
3114235Smarkfen 
3124235Smarkfen typedef struct str_val {
3134235Smarkfen 	const char *string;
3144235Smarkfen 	int value;
3154235Smarkfen } str_val_t;
3164235Smarkfen 
3174235Smarkfen typedef struct str_tval {
3184235Smarkfen 	const char *string;
3194235Smarkfen 	int tok_val;
3204235Smarkfen 	int value;
3214235Smarkfen } str_tval_t;
3224235Smarkfen 
3234235Smarkfen static int	parse_int(const char *);
3244235Smarkfen static int	parse_index(const char *, char *);
3254235Smarkfen static int	attach_tunname(spd_if_t *);
3264235Smarkfen static void	usage(void);
3274235Smarkfen static int	ipsec_conf_del(int, boolean_t);
3284235Smarkfen static int	ipsec_conf_add(boolean_t, boolean_t);
3294235Smarkfen static int	ipsec_conf_sub(void);
3304235Smarkfen static int	ipsec_conf_flush(int);
3314235Smarkfen static int	ipsec_conf_view(void);
3324235Smarkfen static int	ipsec_conf_list(void);
3334235Smarkfen static int	lock(void);
3344235Smarkfen static int	unlock(int);
3354235Smarkfen static int	parse_one(FILE *, act_prop_t *);
3364235Smarkfen static void	reconfigure();
3374235Smarkfen static void	in_prefixlentomask(unsigned int, uchar_t *);
3384235Smarkfen static int	in_getprefixlen(char *);
3394235Smarkfen static int	parse_address(int, char *);
3404235Smarkfen #ifdef DEBUG_HEAVY
3414235Smarkfen static void	pfpol_msg_dump(spd_msg_t *msg, char *);
3424235Smarkfen #endif /* DEBUG_HEAVY */
3434235Smarkfen static void	print_pfpol_msg(spd_msg_t *);
3444235Smarkfen static int	pfp_delete_rule(uint64_t);
3454235Smarkfen static void	ipsec_conf_admin(uint8_t);
3464235Smarkfen static void	print_bit_range(int, int);
3474235Smarkfen static void	nuke_adds();
3484235Smarkfen 
3494235Smarkfen #ifdef DEBUG
3504235Smarkfen static void	dump_conf(ips_conf_t *);
3514235Smarkfen #endif
3524235Smarkfen 
3534235Smarkfen typedef struct
3544235Smarkfen {
3554235Smarkfen 	uint32_t	id;
3564235Smarkfen 	uint32_t	minkeybits;
3574235Smarkfen 	uint32_t	maxkeybits;
3584235Smarkfen 	uint32_t	defkeybits;
3594235Smarkfen 	uint32_t	incr;
3604235Smarkfen } alginfo_t;
3614235Smarkfen 
3624235Smarkfen static int ipsec_nalgs[3];
3634235Smarkfen static alginfo_t known_algs[3][256];
3644235Smarkfen 
3654235Smarkfen #define	IPS_SRC_MASK SPD_EXT_LCLADDR + 100
3664235Smarkfen #define	IPS_DST_MASK SPD_EXT_REMADDR + 100
3674235Smarkfen 
3684235Smarkfen /*
3694235Smarkfen  * if inbound, src=remote, dst=local
3704235Smarkfen  * if outbound, src=local, dst=remote
3714235Smarkfen  */
3724235Smarkfen 
3734235Smarkfen #define	TOK_saddr	1
3744235Smarkfen #define	TOK_daddr	2
3754235Smarkfen #define	TOK_sport	3
3764235Smarkfen #define	TOK_dport	4
3774235Smarkfen #define	TOK_smask	5
3784235Smarkfen #define	TOK_dmask	6
3794235Smarkfen #define	TOK_ulp	7
3804235Smarkfen #define	TOK_local	8
3814235Smarkfen #define	TOK_lport	9
3824235Smarkfen #define	TOK_remote	10
3834235Smarkfen #define	TOK_rport	11
3844235Smarkfen #define	TOK_dir 	12
3854235Smarkfen #define	TOK_type	13
3864235Smarkfen #define	TOK_code	14
3874235Smarkfen #define	TOK_negotiate	15
3884235Smarkfen #define	TOK_tunnel	16
3894235Smarkfen 
3904235Smarkfen #define	IPS_SA SPD_ATTR_END
3914235Smarkfen #define	IPS_DIR SPD_ATTR_EMPTY
3924235Smarkfen #define	IPS_NEG SPD_ATTR_NOP
3934235Smarkfen 
3944235Smarkfen 
3954235Smarkfen static str_tval_t pattern_table[] = {
3964235Smarkfen 	{"saddr", 		TOK_saddr,		SPD_EXT_LCLADDR},
3974235Smarkfen 	{"src",			TOK_saddr,		SPD_EXT_LCLADDR},
3984235Smarkfen 	{"srcaddr",		TOK_saddr,		SPD_EXT_LCLADDR},
3994235Smarkfen 	{"daddr", 		TOK_daddr,		SPD_EXT_REMADDR},
4004235Smarkfen 	{"dst",			TOK_daddr,		SPD_EXT_REMADDR},
4014235Smarkfen 	{"dstaddr",		TOK_daddr,		SPD_EXT_REMADDR},
4024235Smarkfen 	{"sport", 		TOK_sport,		SPD_EXT_LCLPORT},
4034235Smarkfen 	{"dport", 		TOK_dport,		SPD_EXT_REMPORT},
4044235Smarkfen 	{"smask", 		TOK_smask,		IPS_SRC_MASK},
4054235Smarkfen 	{"dmask", 		TOK_dmask,		IPS_DST_MASK},
4064235Smarkfen 	{"ulp", 		TOK_ulp,		SPD_EXT_PROTO},
4074235Smarkfen 	{"proto", 		TOK_ulp,		SPD_EXT_PROTO},
4084235Smarkfen 	{"local",		TOK_local,		SPD_EXT_LCLADDR},
4094235Smarkfen 	{"laddr",		TOK_local,		SPD_EXT_LCLADDR},
4104235Smarkfen 	{"lport",		TOK_lport,		SPD_EXT_LCLPORT},
4114235Smarkfen 	{"remote",		TOK_remote,		SPD_EXT_REMADDR},
4124235Smarkfen 	{"raddr",		TOK_remote,		SPD_EXT_REMADDR},
4134235Smarkfen 	{"rport",		TOK_rport,		SPD_EXT_REMPORT},
4144235Smarkfen 	{"dir",			TOK_dir,		IPS_DIR},
4154235Smarkfen 	{"type",		TOK_type,		SPD_EXT_ICMP_TYPECODE},
4164235Smarkfen 	{"code",		TOK_code,		SPD_EXT_ICMP_TYPECODE},
4174235Smarkfen 	{"negotiate",		TOK_negotiate,		IPS_NEG},
4184235Smarkfen 	{"tunnel",		TOK_tunnel,		SPD_EXT_TUN_NAME},
4194235Smarkfen 	{NULL, 			0,				0},
4204235Smarkfen };
4214235Smarkfen 
4224235Smarkfen #define	TOK_apply	1
4234235Smarkfen #define	TOK_permit	2
4244235Smarkfen #define	TOK_ipsec	3
4254235Smarkfen #define	TOK_bypass	4
4264235Smarkfen #define	TOK_drop	5
4274235Smarkfen #define	TOK_or		6
4284235Smarkfen 
4294235Smarkfen static str_tval_t action_table[] = {
4304235Smarkfen 	{"apply", 		TOK_apply,		SPD_ACTTYPE_IPSEC},
4314235Smarkfen 	{"permit", 		TOK_permit,		SPD_ACTTYPE_IPSEC},
4324235Smarkfen 	{"ipsec", 		TOK_ipsec,		SPD_ACTTYPE_IPSEC},
4334235Smarkfen 	{"bypass", 		TOK_bypass,		SPD_ACTTYPE_PASS},
4344235Smarkfen 	{"pass", 		TOK_bypass,		SPD_ACTTYPE_PASS},
4354235Smarkfen 	{"drop", 		TOK_drop,		SPD_ACTTYPE_DROP},
4364235Smarkfen 	{"or",			TOK_or,			0},
4374235Smarkfen 	{NULL, 			0,				0},
4384235Smarkfen };
4394235Smarkfen 
4404235Smarkfen static str_val_t property_table[] = {
4414235Smarkfen 	{"auth_algs", 		SPD_ATTR_AH_AUTH},
4424235Smarkfen 	{"encr_algs", 		SPD_ATTR_ESP_ENCR},
4434235Smarkfen 	{"encr_auth_algs",	SPD_ATTR_ESP_AUTH},
4444235Smarkfen 	{"sa",				IPS_SA},
4454235Smarkfen 	{"dir",				IPS_DIR},
4464235Smarkfen 	{NULL,				0},
4474235Smarkfen };
4484235Smarkfen 
4494235Smarkfen static str_val_t icmp_type_table[] = {
4504235Smarkfen 	{"unreach",	ICMP_UNREACH},
4514235Smarkfen 	{"echo",	ICMP_ECHO},
4524235Smarkfen 	{"echorep",	ICMP_ECHOREPLY},
4534235Smarkfen 	{"squench",	ICMP_SOURCEQUENCH},
4544235Smarkfen 	{"redir",	ICMP_REDIRECT},
4554235Smarkfen 	{"timex",	ICMP_TIMXCEED},
4564235Smarkfen 	{"paramprob",	ICMP_PARAMPROB},
4574235Smarkfen 	{"timest",	ICMP_TSTAMP},
4584235Smarkfen 	{"timestrep",	ICMP_TSTAMPREPLY},
4594235Smarkfen 	{"inforeq",	ICMP_IREQ},
4604235Smarkfen 	{"inforep",	ICMP_IREQREPLY},
4614235Smarkfen 	{"maskreq",	ICMP_MASKREQ},
4624235Smarkfen 	{"maskrep",	ICMP_MASKREPLY},
4634235Smarkfen 	{"unreach6",	ICMP6_DST_UNREACH},
4644235Smarkfen 	{"pkttoobig6",	ICMP6_PACKET_TOO_BIG},
4654235Smarkfen 	{"timex6",	ICMP6_TIME_EXCEEDED},
4664235Smarkfen 	{"paramprob6",	ICMP6_PARAM_PROB},
4674235Smarkfen 	{"echo6", 	ICMP6_ECHO_REQUEST},
4684235Smarkfen 	{"echorep6",	ICMP6_ECHO_REPLY},
4694235Smarkfen 	{"router-sol6",	ND_ROUTER_SOLICIT},
4704235Smarkfen 	{"router-ad6",	ND_ROUTER_ADVERT},
4714235Smarkfen 	{"neigh-sol6",	ND_NEIGHBOR_SOLICIT},
4724235Smarkfen 	{"neigh-ad6",	ND_NEIGHBOR_ADVERT},
4734235Smarkfen 	{"redir6",	ND_REDIRECT},
4744235Smarkfen 	{NULL,		0},
4754235Smarkfen };
4764235Smarkfen 
4774235Smarkfen static str_val_t icmp_code_table[] = {
4784235Smarkfen 	{"net-unr",		ICMP_UNREACH_NET},
4794235Smarkfen 	{"host-unr",		ICMP_UNREACH_HOST},
4804235Smarkfen 	{"proto-unr",		ICMP_UNREACH_PROTOCOL},
4814235Smarkfen 	{"port-unr",		ICMP_UNREACH_PORT},
4824235Smarkfen 	{"needfrag",		ICMP_UNREACH_NEEDFRAG},
4834235Smarkfen 	{"srcfail",		ICMP_UNREACH_SRCFAIL},
4844235Smarkfen 	{"net-unk",		ICMP_UNREACH_NET_UNKNOWN},
4854235Smarkfen 	{"host-unk",		ICMP_UNREACH_HOST_UNKNOWN},
4864235Smarkfen 	{"isolate",		ICMP_UNREACH_ISOLATED},
4874235Smarkfen 	{"net-prohib",		ICMP_UNREACH_NET_PROHIB},
4884235Smarkfen 	{"host-prohib",		ICMP_UNREACH_HOST_PROHIB},
4894235Smarkfen 	{"net-tos",		ICMP_UNREACH_TOSNET},
4904235Smarkfen 	{"host-tos",		ICMP_UNREACH_TOSHOST},
4914235Smarkfen 	{"filter-prohib",	ICMP_UNREACH_FILTER_PROHIB},
4924235Smarkfen 	{"host-preced",		ICMP_UNREACH_HOST_PRECEDENCE},
4934235Smarkfen 	{"cutoff-preced",	ICMP_UNREACH_PRECEDENCE_CUTOFF},
4944235Smarkfen 	{"no-route6",		ICMP6_DST_UNREACH_NOROUTE},
4954235Smarkfen 	{"adm-prohib6",		ICMP6_DST_UNREACH_ADMIN},
4964235Smarkfen 	{"addr-unr6",		ICMP6_DST_UNREACH_ADDR},
4974235Smarkfen 	{"port-unr6",		ICMP6_DST_UNREACH_NOPORT},
4984235Smarkfen 	{"hop-limex6",		ICMP6_TIME_EXCEED_TRANSIT},
4994235Smarkfen 	{"frag-re-timex6",	ICMP6_TIME_EXCEED_REASSEMBLY},
5004235Smarkfen 	{"err-head6",		ICMP6_PARAMPROB_HEADER},
5014235Smarkfen 	{"unrec-head6",		ICMP6_PARAMPROB_NEXTHEADER},
5024235Smarkfen 	{"unreq-opt6",		ICMP6_PARAMPROB_OPTION},
5034235Smarkfen 	{NULL,			0},
5044235Smarkfen };
5054235Smarkfen 
5064235Smarkfen static sigset_t set, oset;
5074235Smarkfen 
5084235Smarkfen 
5094235Smarkfen static boolean_t
5104235Smarkfen add_index(int index)
5114235Smarkfen {
5124235Smarkfen 	d_list_t *temp = malloc(sizeof (d_list_t));
5134235Smarkfen 
5144235Smarkfen 	if (temp == NULL) {
5154235Smarkfen 		warn("malloc");
5164235Smarkfen 		return (B_TRUE);
5174235Smarkfen 	}
5184235Smarkfen 
5194235Smarkfen 	temp->index = index;
5204235Smarkfen 	temp->next = NULL;
5214235Smarkfen 
5224235Smarkfen 	if (d_tail == NULL) {
5234235Smarkfen 		d_list = d_tail = temp;
5244235Smarkfen 		return (B_FALSE);
5254235Smarkfen 	}
5264235Smarkfen 
5274235Smarkfen 	d_tail->next = temp;
5284235Smarkfen 	d_tail = temp;
5294235Smarkfen 
5304235Smarkfen 	return (B_FALSE);
5314235Smarkfen }
5324235Smarkfen 
5334235Smarkfen static int
5344235Smarkfen block_all_signals()
5354235Smarkfen {
5364235Smarkfen 	if (sigfillset(&set) == -1) {
5374235Smarkfen 		warn("sigfillset");
5384235Smarkfen 		return (-1);
5394235Smarkfen 	}
5404235Smarkfen 	if (sigprocmask(SIG_SETMASK, &set, &oset) == -1) {
5414235Smarkfen 		warn("sigprocmask");
5424235Smarkfen 		return (-1);
5434235Smarkfen 	}
5444235Smarkfen 	return (0);
5454235Smarkfen }
5464235Smarkfen 
5474235Smarkfen static int
5484235Smarkfen restore_all_signals()
5494235Smarkfen {
5504235Smarkfen 	if (sigprocmask(SIG_SETMASK, &oset, NULL) == -1) {
5514235Smarkfen 		warn("sigprocmask");
5524235Smarkfen 		return (-1);
5534235Smarkfen 	}
5544235Smarkfen 	return (0);
5554235Smarkfen }
5564235Smarkfen 
5574235Smarkfen /* allocate an ips_act_props_t and link it in correctly */
5584235Smarkfen static ips_act_props_t *
5594235Smarkfen alloc_iap(ips_conf_t *parent)
5604235Smarkfen {
5614235Smarkfen 	ips_act_props_t *ret;
5624235Smarkfen 	ips_act_props_t *next = parent->ips_acts;
5634235Smarkfen 	ips_act_props_t *current = NULL;
5644235Smarkfen 
5654235Smarkfen 	ret = (ips_act_props_t *)calloc(sizeof (ips_act_props_t), 1);
5664235Smarkfen 
5674235Smarkfen 	if (ret == NULL)
5684235Smarkfen 		return (NULL);
5694235Smarkfen 
5704235Smarkfen 	ret->iap_head = parent;
5714235Smarkfen 
5724235Smarkfen 	while (next != NULL) {
5734235Smarkfen 		current = next;
5744235Smarkfen 		next = next->iap_next;
5754235Smarkfen 	}
5764235Smarkfen 
5774235Smarkfen 	if (current != NULL)
5784235Smarkfen 		current->iap_next = ret;
5794235Smarkfen 	else
5804235Smarkfen 		parent->ips_acts = ret;
5814235Smarkfen 
5824235Smarkfen 	parent->ips_act_cnt++;
5834235Smarkfen 
5844235Smarkfen 	return (ret);
5854235Smarkfen }
5864235Smarkfen 
5874235Smarkfen /*
5884235Smarkfen  * This function exit()s if it fails.
5894235Smarkfen  */
5904235Smarkfen static void
5914235Smarkfen fetch_algorithms()
5924235Smarkfen {
5934235Smarkfen 	struct spd_msg msg;
5944235Smarkfen 	struct spd_ext_actions *actp;
5954235Smarkfen 	struct spd_attribute *attr, *endattr;
5964235Smarkfen 	spd_ext_t *exts[SPD_EXT_MAX+1];
5974235Smarkfen 	uint64_t reply_buf[256];
5984235Smarkfen 	int sfd;
5994235Smarkfen 	int cnt, retval;
6004235Smarkfen 	uint64_t *start, *end;
6014235Smarkfen 	alginfo_t alg = {0, 0, 0, 0, 0};
6024235Smarkfen 	uint_t algtype;
6034235Smarkfen 	static boolean_t has_run = B_FALSE;
6044235Smarkfen 
6054235Smarkfen 	if (has_run)
6064235Smarkfen 		return;
6074235Smarkfen 	else
6084235Smarkfen 		has_run = B_TRUE;
6094235Smarkfen 
6104235Smarkfen 	sfd = get_pf_pol_socket();
6114235Smarkfen 	if (sfd < 0) {
6124235Smarkfen 		err(-1, gettext("unable to open policy socket"));
6134235Smarkfen 	}
6144235Smarkfen 
6154235Smarkfen 	(void) memset(&msg, 0, sizeof (msg));
6164235Smarkfen 	msg.spd_msg_version = PF_POLICY_V1;
6174235Smarkfen 	msg.spd_msg_type = SPD_ALGLIST;
6184235Smarkfen 	msg.spd_msg_len = SPD_8TO64(sizeof (msg));
6194235Smarkfen 
6204235Smarkfen 	cnt = write(sfd, &msg, sizeof (msg));
6214235Smarkfen 	if (cnt != sizeof (msg)) {
6224235Smarkfen 		if (cnt < 0) {
6234235Smarkfen 			err(-1, gettext("alglist failed: write"));
6244235Smarkfen 		} else {
6254235Smarkfen 			errx(-1, gettext("alglist failed: short write"));
6264235Smarkfen 		}
6274235Smarkfen 	}
6284235Smarkfen 
6294235Smarkfen 	cnt = read(sfd, reply_buf, sizeof (reply_buf));
6304235Smarkfen 
6314235Smarkfen 	retval = spdsock_get_ext(exts, (spd_msg_t *)reply_buf, SPD_8TO64(cnt),
6324235Smarkfen 	    spdsock_diag_buf, SPDSOCK_DIAG_BUF_LEN);
6334235Smarkfen 
6344235Smarkfen 	if (retval == KGE_LEN && exts[0]->spd_ext_len == 0) {
6354235Smarkfen 		/*
6364235Smarkfen 		 * No algorithms are defined in the kernel, which caused
6374235Smarkfen 		 * the extension length to be zero, and spdsock_get_ext()
6384235Smarkfen 		 * to fail with a KGE_LEN error. This is not an error
6394235Smarkfen 		 * condition, so we return nicely.
6404235Smarkfen 		 */
6415494Spwernau 		(void) close(sfd);
6424235Smarkfen 		return;
6434235Smarkfen 	} else if (retval != 0) {
6444235Smarkfen 		if (strlen(spdsock_diag_buf) != 0)
6454235Smarkfen 			warnx(spdsock_diag_buf);
6464235Smarkfen 		err(1, gettext("fetch_algorithms failed"));
6474235Smarkfen 	}
6484235Smarkfen 
6494235Smarkfen 	if (!exts[SPD_EXT_ACTION]) {
6504235Smarkfen 		errx(1, gettext("fetch_algorithms: action missing?!"));
6514235Smarkfen 	}
6524235Smarkfen 
6534235Smarkfen 	actp = (struct spd_ext_actions *)exts[SPD_EXT_ACTION];
6544235Smarkfen 	start = (uint64_t *)actp;
6554235Smarkfen 	end = (start + actp->spd_actions_len);
6564235Smarkfen 	endattr = (struct spd_attribute *)end;
6574235Smarkfen 	attr = (struct spd_attribute *)&actp[1];
6584235Smarkfen 
6594235Smarkfen 	algtype = 0;
6604235Smarkfen 
6614235Smarkfen 	while (attr < endattr) {
6624235Smarkfen 		switch (attr->spd_attr_tag) {
6634235Smarkfen 		case SPD_ATTR_NOP:
6644235Smarkfen 		case SPD_ATTR_EMPTY:
6654235Smarkfen 			break;
6664235Smarkfen 		case SPD_ATTR_END:
6674235Smarkfen 			attr = endattr;
6684235Smarkfen 			/* FALLTHRU */
6694235Smarkfen 		case SPD_ATTR_NEXT:
6704235Smarkfen 			known_algs[algtype][ipsec_nalgs[algtype]] = alg;
6714235Smarkfen 			ipsec_nalgs[algtype]++;
6724235Smarkfen 			break;
6734235Smarkfen 
6744235Smarkfen 		case SPD_ATTR_ENCR_MINBITS:
6754235Smarkfen 		case SPD_ATTR_AH_MINBITS:
6764235Smarkfen 		case SPD_ATTR_ESPA_MINBITS:
6774235Smarkfen 			alg.minkeybits = attr->spd_attr_value;
6784235Smarkfen 			break;
6794235Smarkfen 
6804235Smarkfen 		case SPD_ATTR_ENCR_MAXBITS:
6814235Smarkfen 		case SPD_ATTR_AH_MAXBITS:
6824235Smarkfen 		case SPD_ATTR_ESPA_MAXBITS:
6834235Smarkfen 			alg.maxkeybits = attr->spd_attr_value;
6844235Smarkfen 			break;
6854235Smarkfen 
6864235Smarkfen 		case SPD_ATTR_ENCR_DEFBITS:
6874235Smarkfen 		case SPD_ATTR_AH_DEFBITS:
6884235Smarkfen 		case SPD_ATTR_ESPA_DEFBITS:
6894235Smarkfen 			alg.defkeybits = attr->spd_attr_value;
6904235Smarkfen 			break;
6914235Smarkfen 
6924235Smarkfen 		case SPD_ATTR_ENCR_INCRBITS:
6934235Smarkfen 		case SPD_ATTR_AH_INCRBITS:
6944235Smarkfen 		case SPD_ATTR_ESPA_INCRBITS:
6954235Smarkfen 			alg.incr = attr->spd_attr_value;
6964235Smarkfen 			break;
6974235Smarkfen 
6984235Smarkfen 		case SPD_ATTR_AH_AUTH:
6994235Smarkfen 		case SPD_ATTR_ESP_AUTH:
7004235Smarkfen 		case SPD_ATTR_ESP_ENCR:
7014235Smarkfen 			alg.id = attr->spd_attr_value;
7024235Smarkfen 			algtype = attr->spd_attr_tag - SPD_ATTR_AH_AUTH;
7034235Smarkfen 			break;
7044235Smarkfen 		}
7054235Smarkfen 		attr++;
7064235Smarkfen 	}
7074235Smarkfen 
7084235Smarkfen 	(void) close(sfd);
7094235Smarkfen }
7104235Smarkfen 
7114235Smarkfen /* data dependant transform (act_cnt) */
7124235Smarkfen #define	ATTR(ap, tag, value) \
7134235Smarkfen do { (ap)->spd_attr_tag = (tag); \
7144235Smarkfen 	(ap)->spd_attr_value = (value); \
7154235Smarkfen 	ap++; } while (0)
7164235Smarkfen 
7174235Smarkfen static struct spd_attribute *
7184235Smarkfen emit_alg(struct spd_attribute *ap, int type, const algreq_t *ar,
7194235Smarkfen     int algattr, int minbitattr, int maxbitattr)
7204235Smarkfen {
7214235Smarkfen 	int id = ar->alg_id;
7224235Smarkfen 	int minbits, i;
7234235Smarkfen 
7244235Smarkfen 	if (id != 0) {
7254235Smarkfen 		/* LINTED E_CONST_COND */
7264235Smarkfen 		ATTR(ap, algattr, ar->alg_id);
7274235Smarkfen 
7284235Smarkfen 		minbits = ar->alg_minbits;
7294235Smarkfen 		if (minbits == 0) {
7304235Smarkfen 			for (i = 0; i < ipsec_nalgs[type]; i++) {
7314235Smarkfen 				if (known_algs[type][i].id == id)
7324235Smarkfen 					break;
7334235Smarkfen 			}
7344235Smarkfen 			if (i < ipsec_nalgs[type])
7354235Smarkfen 				minbits = known_algs[type][i].defkeybits;
7364235Smarkfen 		}
7374235Smarkfen 		if (minbits != 0)
7384235Smarkfen 			/* LINTED E_CONST_COND */
7394235Smarkfen 			ATTR(ap, minbitattr, minbits);
7404235Smarkfen 		if (ar->alg_maxbits != SPD_MAX_MAXBITS)
7414235Smarkfen 			/* LINTED E_CONST_COND */
7424235Smarkfen 			ATTR(ap, maxbitattr, ar->alg_maxbits);
7434235Smarkfen 	}
7444235Smarkfen 
7454235Smarkfen 	return (ap);
7464235Smarkfen }
7474235Smarkfen 
7484235Smarkfen 
7494235Smarkfen 
7504235Smarkfen static struct spd_attribute *
7514235Smarkfen ips_act_props_to_action(struct spd_attribute *ap, uint32_t *rule_priorityp,
7524235Smarkfen     const ips_act_props_t *act_ptr)
7534235Smarkfen {
7544235Smarkfen 	uint32_t rule_priority = *rule_priorityp;
7554235Smarkfen 
7564235Smarkfen 	/* LINTED E_CONST_COND */
7574235Smarkfen 	ATTR(ap, SPD_ATTR_EMPTY, 0);
7584235Smarkfen 
7594235Smarkfen 	/* type */
7604235Smarkfen 	/* LINTED E_CONST_COND */
7614235Smarkfen 	ATTR(ap, SPD_ATTR_TYPE, act_ptr->iap_action);
7624235Smarkfen 
7634235Smarkfen 	if (act_ptr->iap_action == SPD_ACTTYPE_PASS)
7644235Smarkfen 		rule_priority |= BYPASS_POLICY_BOOST;
7654235Smarkfen 
7664235Smarkfen 	/* flags */
7674235Smarkfen 	if (act_ptr->iap_attr != 0)
7684235Smarkfen 		/* LINTED E_CONST_COND */
7694235Smarkfen 		ATTR(ap, SPD_ATTR_FLAGS, act_ptr->iap_attr);
7704235Smarkfen 
7714235Smarkfen 	/* esp */
7724235Smarkfen 	if (act_ptr->iap_attr & SPD_APPLY_ESP) {
7734235Smarkfen 		rule_priority |= ESP_POLICY_BOOST;
7744235Smarkfen 
7754235Smarkfen 		/* encr */
7764235Smarkfen 		ap = emit_alg(ap, ESP_ENCR, &act_ptr->iap_eencr,
7774235Smarkfen 		    SPD_ATTR_ESP_ENCR,
7784235Smarkfen 		    SPD_ATTR_ENCR_MINBITS, SPD_ATTR_ENCR_MAXBITS);
7794235Smarkfen 
7804235Smarkfen 		/* auth */
7814235Smarkfen 		ap = emit_alg(ap, ESP_AUTH, &act_ptr->iap_eauth,
7824235Smarkfen 		    SPD_ATTR_ESP_AUTH,
7834235Smarkfen 		    SPD_ATTR_ESPA_MINBITS, SPD_ATTR_ESPA_MAXBITS);
7844235Smarkfen 	}
7854235Smarkfen 
7864235Smarkfen 	/* ah */
7874235Smarkfen 	if (act_ptr->iap_attr & SPD_APPLY_AH) {
7884235Smarkfen 		rule_priority |= AH_POLICY_BOOST;
7894235Smarkfen 		/* auth */
7904235Smarkfen 		ap = emit_alg(ap, AH_AUTH, &act_ptr->iap_aauth,
7914235Smarkfen 		    SPD_ATTR_AH_AUTH,
7924235Smarkfen 		    SPD_ATTR_AH_MINBITS, SPD_ATTR_AH_MAXBITS);
7934235Smarkfen 	}
7944235Smarkfen 
7954235Smarkfen 	/* lifetimes */
7964235Smarkfen 	if (act_ptr->iap_life_soft_time != 0)
7974235Smarkfen 		/* LINTED E_CONST_COND */
7984235Smarkfen 		ATTR(ap, SPD_ATTR_LIFE_SOFT_TIME, act_ptr->iap_life_soft_time);
7994235Smarkfen 	if (act_ptr->iap_life_hard_time != 0)
8004235Smarkfen 		/* LINTED E_CONST_COND */
8014235Smarkfen 		ATTR(ap, SPD_ATTR_LIFE_HARD_TIME, act_ptr->iap_life_hard_time);
8024235Smarkfen 	if (act_ptr->iap_life_soft_bytes != 0)
8034235Smarkfen 		/* LINTED E_CONST_COND */
8044235Smarkfen 		ATTR(ap, SPD_ATTR_LIFE_SOFT_BYTES,
8054235Smarkfen 		    act_ptr->iap_life_soft_bytes);
8064235Smarkfen 	if (act_ptr->iap_life_hard_bytes != 0)
8074235Smarkfen 		/* LINTED E_CONST_COND */
8084235Smarkfen 		ATTR(ap, SPD_ATTR_LIFE_HARD_BYTES,
8094235Smarkfen 		    act_ptr->iap_life_hard_bytes);
8104235Smarkfen 
8114235Smarkfen 	/* LINTED E_CONST_COND */
8124235Smarkfen 	ATTR(ap, SPD_ATTR_NEXT, 0);
8134235Smarkfen 
8144235Smarkfen 	*rule_priorityp = rule_priority;
8154235Smarkfen 
8164235Smarkfen 	return (ap);
8174235Smarkfen }
8184235Smarkfen 
8194235Smarkfen static boolean_t
8204235Smarkfen alg_rangecheck(uint_t type, uint_t algid, const algreq_t *ar)
8214235Smarkfen {
8224235Smarkfen 	int i;
8234235Smarkfen 	uint_t minbits = ar->alg_minbits;
8244235Smarkfen 	uint_t maxbits = ar->alg_maxbits;
8254235Smarkfen 
8264235Smarkfen 	for (i = 0; i < ipsec_nalgs[type]; i++) {
8274235Smarkfen 		if (known_algs[type][i].id == algid)
8284235Smarkfen 			break;
8294235Smarkfen 	}
8304235Smarkfen 
8314235Smarkfen 	if (i >= ipsec_nalgs[type]) {
8324235Smarkfen 		/*
8334235Smarkfen 		 * The kernel (where we populate known_algs from) doesn't
8344235Smarkfen 		 * return the id's associated with NONE algorithms so we
8354235Smarkfen 		 * test here if this was the reason the algorithm wasn't
8364235Smarkfen 		 * found before wrongly failing.
8374235Smarkfen 		 */
8384235Smarkfen 		if (((type == ESP_ENCR) && (algid == SADB_EALG_NONE)) ||
8394235Smarkfen 		    ((type == ESP_AUTH) && (algid == SADB_AALG_NONE)) ||
8404235Smarkfen 		    ((type == AH_AUTH) && (algid == SADB_AALG_NONE))) {
8414235Smarkfen 			return (B_TRUE);
8424235Smarkfen 		} else {
8434235Smarkfen 			return (B_FALSE); /* not found */
8444235Smarkfen 		}
8454235Smarkfen 	}
8464235Smarkfen 
8474235Smarkfen 	if ((minbits == 0) && (maxbits == 0))
8484235Smarkfen 		return (B_TRUE);
8494235Smarkfen 
8504235Smarkfen 	minbits = MAX(minbits, known_algs[type][i].minkeybits);
8514235Smarkfen 	maxbits = MIN(maxbits, known_algs[type][i].maxkeybits);
8524235Smarkfen 
8534235Smarkfen 	/* we could also check key increments here.. */
8544235Smarkfen 	return (minbits <= maxbits); /* non-null intersection */
8554235Smarkfen }
8564235Smarkfen 
8574235Smarkfen /*
8584235Smarkfen  * Inspired by uts/common/inet/spd.c:ipsec_act_wildcard_expand()
8594235Smarkfen  */
8604235Smarkfen 
8614235Smarkfen static struct spd_attribute *
8624235Smarkfen ips_act_wild_props_to_action(struct spd_attribute *ap,
8634235Smarkfen     uint32_t *rule_priorityp, uint16_t *act_cntp,
8644235Smarkfen     const ips_act_props_t *act_ptr)
8654235Smarkfen {
8664235Smarkfen 	ips_act_props_t tact = *act_ptr;
8674235Smarkfen 	boolean_t use_ah, use_esp, use_espa;
8684235Smarkfen 	boolean_t wild_auth, wild_encr, wild_eauth;
8694235Smarkfen 	uint_t	auth_alg, auth_idx, auth_min, auth_max;
8704235Smarkfen 	uint_t	eauth_alg, eauth_idx, eauth_min, eauth_max;
8714235Smarkfen 	uint_t  encr_alg, encr_idx, encr_min, encr_max;
8724235Smarkfen 
8734235Smarkfen 	use_ah = !!(act_ptr->iap_attr & SPD_APPLY_AH);
8744235Smarkfen 	use_esp = !!(act_ptr->iap_attr & SPD_APPLY_ESP);
8754235Smarkfen 	use_espa = !!(act_ptr->iap_attr & SPD_APPLY_ESPA);
8764235Smarkfen 	auth_alg = act_ptr->iap_aauth.alg_id;
8774235Smarkfen 	eauth_alg = act_ptr->iap_eauth.alg_id;
8784235Smarkfen 	encr_alg = act_ptr->iap_eencr.alg_id;
8794235Smarkfen 
8804235Smarkfen 	wild_auth = use_ah && (auth_alg == SADB_AALG_NONE);
8814235Smarkfen 	wild_eauth = use_espa && (eauth_alg == SADB_AALG_NONE);
8824235Smarkfen 	wild_encr = use_esp && (encr_alg == SADB_EALG_NONE);
8834235Smarkfen 
8844235Smarkfen 	auth_min = auth_max = auth_alg;
8854235Smarkfen 	eauth_min = eauth_max = eauth_alg;
8864235Smarkfen 	encr_min = encr_max = encr_alg;
8874235Smarkfen 
8884235Smarkfen 	/*
8894235Smarkfen 	 * set up for explosion.. for each dimension, expand output
8904235Smarkfen 	 * size by the explosion factor.
8914235Smarkfen 	 */
8924235Smarkfen 	if (wild_auth) {
8934235Smarkfen 		auth_min = 0;
8944235Smarkfen 		auth_max = ipsec_nalgs[AH_AUTH] - 1;
8954235Smarkfen 	}
8964235Smarkfen 	if (wild_eauth) {
8974235Smarkfen 		eauth_min = 0;
8984235Smarkfen 		eauth_max = ipsec_nalgs[ESP_AUTH] - 1;
8994235Smarkfen 	}
9004235Smarkfen 	if (wild_encr) {
9014235Smarkfen 		encr_min = 0;
9024235Smarkfen 		encr_max = ipsec_nalgs[ESP_ENCR] - 1;
9034235Smarkfen 	}
9044235Smarkfen 
9054235Smarkfen #define	WHICH_ALG(type, wild, idx) ((wild)?(known_algs[type][idx].id):(idx))
9064235Smarkfen 
9074235Smarkfen 	for (encr_idx = encr_min; encr_idx <= encr_max; encr_idx++) {
9084235Smarkfen 		encr_alg = WHICH_ALG(ESP_ENCR, wild_encr, encr_idx);
9094235Smarkfen 
9104235Smarkfen 		if (use_esp &&
9114235Smarkfen 		    !alg_rangecheck(ESP_ENCR, encr_alg, &act_ptr->iap_eencr))
9124235Smarkfen 			continue;
9134235Smarkfen 
9144235Smarkfen 		for (auth_idx = auth_min; auth_idx <= auth_max; auth_idx++) {
9154235Smarkfen 			auth_alg = WHICH_ALG(AH_AUTH, wild_auth, auth_idx);
9164235Smarkfen 
9174235Smarkfen 			if (use_ah &&
9184235Smarkfen 			    !alg_rangecheck(AH_AUTH, auth_alg,
9195120Smarkfen 			    &act_ptr->iap_aauth))
9204235Smarkfen 				continue;
9214235Smarkfen 
9224235Smarkfen 
9234235Smarkfen 			for (eauth_idx = eauth_min; eauth_idx <= eauth_max;
9244235Smarkfen 			    eauth_idx++) {
9254235Smarkfen 				eauth_alg = WHICH_ALG(ESP_AUTH, wild_eauth,
9264235Smarkfen 				    eauth_idx);
9274235Smarkfen 
9284235Smarkfen 				if (use_espa &&
9294235Smarkfen 				    !alg_rangecheck(ESP_AUTH, eauth_alg,
9304235Smarkfen 				    &act_ptr->iap_eauth))
9314235Smarkfen 					continue;
9324235Smarkfen 
9334235Smarkfen 				tact.iap_eencr.alg_id = encr_alg;
9344235Smarkfen 				tact.iap_eauth.alg_id = eauth_alg;
9354235Smarkfen 				tact.iap_aauth.alg_id = auth_alg;
9364235Smarkfen 
9374235Smarkfen 				(*act_cntp)++;
9384235Smarkfen 				ap = ips_act_props_to_action(ap,
9394235Smarkfen 				    rule_priorityp, &tact);
9404235Smarkfen 			}
9414235Smarkfen 		}
9424235Smarkfen 	}
9434235Smarkfen 
9444235Smarkfen #undef WHICH_ALG
9454235Smarkfen 
9464235Smarkfen 	return (ap);
9474235Smarkfen }
9484235Smarkfen 
9494235Smarkfen /* huge, but not safe since no length checking is done */
9504235Smarkfen #define	MAX_POL_MSG_LEN 16384
9514235Smarkfen 
9524235Smarkfen 
9534235Smarkfen /*
9544235Smarkfen  * hand in some ips_conf_t's, get back an
9554235Smarkfen  * iovec of pfpol messages.
9564235Smarkfen  * this function converts the internal ips_conf_t into
9574235Smarkfen  * a form that pf_pol can use.
9584235Smarkfen  * return 0 on success, 1 on failure
9594235Smarkfen  */
9604235Smarkfen static int
9614235Smarkfen ips_conf_to_pfpol_msg(int ipsec_cmd, ips_conf_t *inConf, int num_ips,
9624235Smarkfen     struct iovec *msg)
9634235Smarkfen {
9644235Smarkfen 	int i;
9654235Smarkfen 	ips_conf_t *conf;
9664235Smarkfen 	uint64_t *scratch = NULL;
9674235Smarkfen 
9684235Smarkfen 	for (i = 0; i < num_ips; i++) {
9694235Smarkfen 		uint16_t *msg_len;
9704235Smarkfen 		uint16_t act_cnt = 0;
9714235Smarkfen 		uint64_t *next = NULL;
9724235Smarkfen 		spd_msg_t *spd_msg;
9734235Smarkfen 		spd_address_t *spd_address;
9744235Smarkfen 		struct spd_rule *spd_rule;
9754235Smarkfen 		struct spd_proto *spd_proto;
9764235Smarkfen 		struct spd_portrange *spd_portrange;
9774235Smarkfen 		struct spd_ext_actions *spd_ext_actions;
9784235Smarkfen 		struct spd_attribute *ap;
9794235Smarkfen 		struct spd_typecode *spd_typecode;
9804235Smarkfen 		spd_if_t *spd_if;
9814235Smarkfen 		ips_act_props_t *act_ptr;
9824235Smarkfen 		uint32_t rule_priority = 0;
9834235Smarkfen 
9844235Smarkfen 		scratch = calloc(1, MAX_POL_MSG_LEN);
9854235Smarkfen 		msg[i].iov_base = (char *)scratch;
9864235Smarkfen 		if (scratch == NULL) {
9874235Smarkfen 			warn(gettext("memory"));
9884235Smarkfen 			return (1);
9894235Smarkfen 		}
9904235Smarkfen 		conf = &(inConf[i]);
9914235Smarkfen 
9924235Smarkfen 		spd_msg = (spd_msg_t *)scratch;
9934235Smarkfen 		next = (uint64_t *)&(spd_msg[1]);
9944235Smarkfen 
9954235Smarkfen 		msg_len = &(spd_msg->spd_msg_len);
9964235Smarkfen 
9974235Smarkfen 		spd_msg->spd_msg_version = PF_POLICY_V1;
9984235Smarkfen 		spd_msg->spd_msg_pid = getpid();
9994235Smarkfen 		spd_msg->spd_msg_seq = ++seq_cnt;
10004235Smarkfen 
10014235Smarkfen 		switch (ipsec_cmd) {
10024235Smarkfen 		case SPD_ADDRULE:
10034235Smarkfen 			spd_msg->spd_msg_type = SPD_ADDRULE;
10044235Smarkfen 			break;
10054235Smarkfen 
10064235Smarkfen 		default:
10074235Smarkfen 			warnx("%s %d", gettext("bad command:"), ipsec_cmd);
10084235Smarkfen 			spd_msg->spd_msg_type = SPD_ADDRULE;
10094235Smarkfen 			break;
10104235Smarkfen 		}
10114235Smarkfen 
10124235Smarkfen 		/*
10134235Smarkfen 		 * SELECTOR
10144235Smarkfen 		 */
10154235Smarkfen 
10164235Smarkfen 		spd_msg->spd_msg_spdid = SPD_STANDBY;
10174235Smarkfen 
10184235Smarkfen 		/* rule */
10194235Smarkfen 		spd_rule = (struct spd_rule *)next;
10204235Smarkfen 
10214235Smarkfen 		spd_rule->spd_rule_len = SPD_8TO64(sizeof (struct spd_rule));
10224235Smarkfen 		spd_rule->spd_rule_type = SPD_EXT_RULE;
10234235Smarkfen 		spd_rule->spd_rule_flags = conf->ips_dir;
10244235Smarkfen 		if (conf->ips_tunnel)
10254235Smarkfen 			spd_rule->spd_rule_flags |= SPD_RULE_FLAG_TUNNEL;
10264235Smarkfen 
10274235Smarkfen 		next = (uint64_t *)&(spd_rule[1]);
10284235Smarkfen 
10294235Smarkfen 		/* proto */
10304235Smarkfen 		if (conf->ips_ulp_prot != 0) {
10314235Smarkfen 			spd_proto = (struct spd_proto *)next;
10324235Smarkfen 			spd_proto->spd_proto_len =
10335120Smarkfen 			    SPD_8TO64(sizeof (struct spd_proto));
10344235Smarkfen 			spd_proto->spd_proto_exttype = SPD_EXT_PROTO;
10354235Smarkfen 			spd_proto->spd_proto_number = conf->ips_ulp_prot;
10364235Smarkfen 			next = (uint64_t *)&(spd_proto[1]);
10374235Smarkfen 		}
10384235Smarkfen 
10394235Smarkfen 		/* tunnel */
10404235Smarkfen 		if (conf->has_tunnel != 0) {
10414235Smarkfen 			spd_if = (spd_if_t *)next;
10424235Smarkfen 			spd_if->spd_if_len =
10434235Smarkfen 			    SPD_8TO64(P2ROUNDUP(strlen(tunif) + 1, 8) +
10444235Smarkfen 			    sizeof (spd_if_t));
10454235Smarkfen 			spd_if->spd_if_exttype = SPD_EXT_TUN_NAME;
10464235Smarkfen 			(void) strlcpy((char *)spd_if->spd_if_name, tunif,
10475120Smarkfen 			    TUNNAMEMAXLEN);
10484235Smarkfen 			next = (uint64_t *)(spd_if) + spd_if->spd_if_len;
10494235Smarkfen 		}
10504235Smarkfen 
10514235Smarkfen 		/* icmp type/code */
10524235Smarkfen 		if (conf->ips_ulp_prot == IPPROTO_ICMP ||
10534235Smarkfen 		    conf->ips_ulp_prot == IPPROTO_ICMPV6) {
10544235Smarkfen 			if (conf->has_type) {
10554235Smarkfen 				spd_typecode = (struct spd_typecode *)next;
10564235Smarkfen 				spd_typecode->spd_typecode_len =
10574235Smarkfen 				    SPD_8TO64(sizeof (struct spd_typecode));
10584235Smarkfen 				spd_typecode->spd_typecode_exttype =
10594235Smarkfen 				    SPD_EXT_ICMP_TYPECODE;
10604235Smarkfen 				spd_typecode->spd_typecode_type =
10614235Smarkfen 				    conf->ips_icmp_type;
10624235Smarkfen 				spd_typecode->spd_typecode_type_end =
10634235Smarkfen 				    conf->ips_icmp_type_end;
10644235Smarkfen 				if (conf->has_code) {
10654235Smarkfen 					spd_typecode->spd_typecode_code =
10664235Smarkfen 					    conf->ips_icmp_code;
10674235Smarkfen 					spd_typecode->spd_typecode_code_end =
10684235Smarkfen 					    conf->ips_icmp_code_end;
10694235Smarkfen 				} else {
10704235Smarkfen 					spd_typecode->spd_typecode_code = 255;
10714235Smarkfen 					spd_typecode->spd_typecode_code_end
10724235Smarkfen 					    = 255;
10734235Smarkfen 				}
10744235Smarkfen 				next = (uint64_t *)&(spd_typecode[1]);
10754235Smarkfen 			}
10764235Smarkfen 		}
10774235Smarkfen 
10784235Smarkfen 		/* src port */
10794235Smarkfen 		if (conf->ips_src_port_min != 0 ||
10804235Smarkfen 		    conf->ips_src_port_max != 0) {
10814235Smarkfen 			spd_portrange = (struct spd_portrange *)next;
10824235Smarkfen 			spd_portrange->spd_ports_len =
10835120Smarkfen 			    SPD_8TO64(sizeof (struct spd_portrange));
10844235Smarkfen 			spd_portrange->spd_ports_exttype =
10855120Smarkfen 			    (conf->swap)?SPD_EXT_REMPORT:SPD_EXT_LCLPORT;
10864235Smarkfen 			spd_portrange->spd_ports_minport =
10875120Smarkfen 			    conf->ips_src_port_min;
10884235Smarkfen 			spd_portrange->spd_ports_maxport =
10895120Smarkfen 			    conf->ips_src_port_max;
10904235Smarkfen 			next = (uint64_t *)&(spd_portrange[1]);
10914235Smarkfen 		}
10924235Smarkfen 		/* dst port */
10934235Smarkfen 		if (conf->ips_dst_port_min != 0 ||
10944235Smarkfen 		    conf->ips_dst_port_max != 0) {
10954235Smarkfen 			spd_portrange = (struct spd_portrange *)next;
10964235Smarkfen 			spd_portrange->spd_ports_len =
10975120Smarkfen 			    SPD_8TO64(sizeof (struct spd_portrange));
10984235Smarkfen 			spd_portrange->spd_ports_exttype =
10995120Smarkfen 			    (conf->swap)?SPD_EXT_LCLPORT:SPD_EXT_REMPORT;
11004235Smarkfen 			spd_portrange->spd_ports_minport =
11015120Smarkfen 			    conf->ips_dst_port_min;
11024235Smarkfen 			spd_portrange->spd_ports_maxport =
11035120Smarkfen 			    conf->ips_dst_port_max;
11044235Smarkfen 			next = (uint64_t *)&(spd_portrange[1]);
11054235Smarkfen 		}
11064235Smarkfen 
11074235Smarkfen 		/* saddr */
11084235Smarkfen 		if (conf->has_saddr) {
11094235Smarkfen 			spd_address = (spd_address_t *)next;
11104235Smarkfen 			next = (uint64_t *)(spd_address + 1);
11114235Smarkfen 
11124235Smarkfen 			spd_address->spd_address_exttype =
11135120Smarkfen 			    (conf->swap)?SPD_EXT_REMADDR:SPD_EXT_LCLADDR;
11144235Smarkfen 			spd_address->spd_address_prefixlen =
11155120Smarkfen 			    conf->ips_src_mask_len;
11164235Smarkfen 
11174235Smarkfen 			if (conf->ips_isv4) {
11184235Smarkfen 				spd_address->spd_address_af = AF_INET;
11194235Smarkfen 				(void) memcpy(next, &(conf->ips_src_addr),
11205120Smarkfen 				    sizeof (ipaddr_t));
11214235Smarkfen 				spd_address->spd_address_len = 2;
11224235Smarkfen 				next += SPD_8TO64(sizeof (ipaddr_t) + 4);
11234235Smarkfen 				if (!conf->has_smask)
11244235Smarkfen 					spd_address->spd_address_prefixlen = 32;
11254235Smarkfen 			} else {
11264235Smarkfen 				spd_address->spd_address_af = AF_INET6;
11274235Smarkfen 				(void) memcpy(next, &(conf->ips_src_addr_v6),
11284235Smarkfen 				    sizeof (in6_addr_t));
11294235Smarkfen 				spd_address->spd_address_len = 3;
11304235Smarkfen 				next += SPD_8TO64(sizeof (in6_addr_t));
11314235Smarkfen 				if (!conf->has_smask)
11324235Smarkfen 					spd_address->spd_address_prefixlen
11335120Smarkfen 					    = 128;
11344235Smarkfen 			}
11354235Smarkfen 		}
11364235Smarkfen 
11374235Smarkfen 		/* daddr */
11384235Smarkfen 		if (conf->has_daddr) {
11394235Smarkfen 			spd_address = (spd_address_t *)next;
11404235Smarkfen 
11414235Smarkfen 			next = (uint64_t *)(spd_address + 1);
11424235Smarkfen 
11434235Smarkfen 			spd_address->spd_address_exttype =
11445120Smarkfen 			    (conf->swap)?SPD_EXT_LCLADDR:SPD_EXT_REMADDR;
11454235Smarkfen 			spd_address->spd_address_prefixlen =
11465120Smarkfen 			    conf->ips_dst_mask_len;
11474235Smarkfen 
11484235Smarkfen 			if (conf->ips_isv4) {
11494235Smarkfen 				spd_address->spd_address_af = AF_INET;
11504235Smarkfen 				(void) memcpy(next, &conf->ips_dst_addr,
11514235Smarkfen 				    sizeof (ipaddr_t));
11524235Smarkfen 				spd_address->spd_address_len = 2;
11534235Smarkfen 				/* "+ 4" below is for padding. */
11544235Smarkfen 				next += SPD_8TO64(sizeof (ipaddr_t) + 4);
11554235Smarkfen 				if (!conf->has_dmask)
11564235Smarkfen 					spd_address->spd_address_prefixlen = 32;
11574235Smarkfen 			} else {
11584235Smarkfen 				spd_address->spd_address_af = AF_INET6;
11594235Smarkfen 				(void) memcpy(next, &(conf->ips_dst_addr_v6),
11604235Smarkfen 				    sizeof (in6_addr_t));
11614235Smarkfen 				spd_address->spd_address_len = 3;
11624235Smarkfen 				next += SPD_8TO64(sizeof (in6_addr_t));
11634235Smarkfen 				if (!conf->has_dmask)
11644235Smarkfen 					spd_address->spd_address_prefixlen
11655120Smarkfen 					    = 128;
11664235Smarkfen 			}
11674235Smarkfen 		}
11684235Smarkfen 
11694235Smarkfen 		/* actions */
11704235Smarkfen 		spd_ext_actions = (struct spd_ext_actions *)next;
11714235Smarkfen 
11724235Smarkfen 		spd_ext_actions->spd_actions_exttype = SPD_EXT_ACTION;
11734235Smarkfen 
11744235Smarkfen 		act_ptr = conf->ips_acts;
11754235Smarkfen 		ap = (struct spd_attribute *)(&spd_ext_actions[1]);
11764235Smarkfen 
11774235Smarkfen 		rule_priority = priority--;
11784235Smarkfen 
11794235Smarkfen 		for (act_ptr = conf->ips_acts; act_ptr != NULL;
11804235Smarkfen 		    act_ptr = act_ptr->iap_next) {
11814235Smarkfen 			ap = ips_act_wild_props_to_action(ap, &rule_priority,
11824235Smarkfen 			    &act_cnt, act_ptr);
11834235Smarkfen 		}
11844235Smarkfen 		ap[-1].spd_attr_tag = SPD_ATTR_END;
11854235Smarkfen 
11864235Smarkfen 		next = (uint64_t *)ap;
11874235Smarkfen 
11884235Smarkfen 		spd_rule->spd_rule_priority = rule_priority;
11894235Smarkfen 
11904235Smarkfen 		msg[i].iov_len = (uintptr_t)next - (uintptr_t)msg[i].iov_base;
11914235Smarkfen 		*msg_len = (uint16_t)SPD_8TO64(msg[i].iov_len);
11924235Smarkfen 		spd_ext_actions->spd_actions_count = act_cnt;
11934235Smarkfen 		spd_ext_actions->spd_actions_len =
11944235Smarkfen 		    SPD_8TO64((uintptr_t)next - (uintptr_t)spd_ext_actions);
11954235Smarkfen #ifdef DEBUG_HEAVY
11964235Smarkfen 		printf("pfpol msg len in uint64_t's = %d\n", *msg_len);
11974235Smarkfen 		printf("pfpol test_len in bytes = %d\n", msg[i].iov_len);
11984235Smarkfen 		pfpol_msg_dump((spd_msg_t *)scratch,
11994235Smarkfen 		    "ips_conf_to_pfpol_msg");
12004235Smarkfen #endif
12014235Smarkfen 	}
12024235Smarkfen 
12034235Smarkfen #undef ATTR
12044235Smarkfen 	return (0);
12054235Smarkfen }
12064235Smarkfen 
12074235Smarkfen static int
12084235Smarkfen get_pf_pol_socket(void)
12094235Smarkfen {
12104235Smarkfen 	int s = socket(PF_POLICY, SOCK_RAW, PF_POLICY_V1);
12114235Smarkfen 	if (s < 0) {
12124235Smarkfen 		if (errno == EPERM) {
12134235Smarkfen 			EXIT_BADPERM("Insufficient privileges to open "
12144235Smarkfen 			    "PF_POLICY socket.");
12154235Smarkfen 		} else {
12164235Smarkfen 			warn(gettext("(loading pf_policy) socket:"));
12174235Smarkfen 		}
12184235Smarkfen 	}
12194235Smarkfen 
12204235Smarkfen 	return (s);
12214235Smarkfen }
12224235Smarkfen 
12234235Smarkfen 
12244235Smarkfen static int
12254235Smarkfen send_pf_pol_message(int ipsec_cmd, ips_conf_t *conf, int *diag)
12264235Smarkfen {
12274235Smarkfen 	int retval;
12284235Smarkfen 	int cnt;
12294235Smarkfen 	int total_len;
12304235Smarkfen 	struct iovec polmsg;
12314235Smarkfen 	spd_msg_t *return_buf;
12324235Smarkfen 	spd_ext_t *exts[SPD_EXT_MAX+1];
12334235Smarkfen 	int fd = get_pf_pol_socket();
12344235Smarkfen 
12354235Smarkfen 	*diag = 0;
12364235Smarkfen 
12374235Smarkfen 	if (fd < 0)
12384235Smarkfen 		return (EBADF);
12394235Smarkfen 
12404235Smarkfen 	retval = ips_conf_to_pfpol_msg(ipsec_cmd, conf, 1, &polmsg);
12414235Smarkfen 
12424235Smarkfen 	if (retval) {
12434235Smarkfen 		(void) close(fd);
12444235Smarkfen 		return (ENOMEM);
12454235Smarkfen 	}
12464235Smarkfen 
12474235Smarkfen 	total_len = polmsg.iov_len;
12484235Smarkfen 
12494235Smarkfen 	cnt = writev(fd, &polmsg, 1);
12504235Smarkfen 
12514235Smarkfen #ifdef DEBUG_HEAVY
12524235Smarkfen 	(void) printf("cnt = %d\n", cnt);
12534235Smarkfen #endif
12544235Smarkfen 	if (cnt < 0) {
12554235Smarkfen 		warn(gettext("pf_pol write"));
12564235Smarkfen 	} else {
12574235Smarkfen 		return_buf = (spd_msg_t *)calloc(total_len, 1);
12584235Smarkfen 
12594235Smarkfen 		if (return_buf == NULL) {
12604235Smarkfen 			warn(gettext("memory"));
12614235Smarkfen 		} else {
12624235Smarkfen 			cnt = read(fd, (void*)return_buf, total_len);
12634235Smarkfen #ifdef	DEBUG_HEAVY
12644235Smarkfen 			(void) printf("pf_pol read: cnt = %d(%d)\n", cnt,
12654235Smarkfen 			    total_len);
12664235Smarkfen #endif
12674235Smarkfen 
12684235Smarkfen 			if (cnt > 8 && return_buf->spd_msg_errno) {
12694235Smarkfen 				*diag = return_buf->spd_msg_diagnostic;
12704235Smarkfen 				if (!ipsecconf_qflag) {
12714235Smarkfen 					warnx("%s: %s",
12724235Smarkfen 					    gettext("Kernel returned"),
12734235Smarkfen 					    sys_error_message(
12744235Smarkfen 					    return_buf->spd_msg_errno));
12754235Smarkfen 				}
12764235Smarkfen 				if (*diag != 0)
12774235Smarkfen 					(void) printf(gettext(
12784235Smarkfen 					    "\t(spdsock diagnostic: %s)\n"),
12794235Smarkfen 					    spdsock_diag(*diag));
12804235Smarkfen #ifdef DEBUG_HEAVY
12814235Smarkfen 				pfpol_msg_dump((spd_msg_t *)polmsg.iov_base,
12824235Smarkfen 				    "message in");
12834235Smarkfen 				pfpol_msg_dump(return_buf,
12844235Smarkfen 				    "send_pf_pol_message");
12854235Smarkfen #endif
12864235Smarkfen 				retval = return_buf->spd_msg_errno;
12874235Smarkfen 				free(return_buf);
12884235Smarkfen 				free(polmsg.iov_base);
12894235Smarkfen 				(void) close(fd);
12904235Smarkfen 				return (retval);
12914235Smarkfen 			}
12924235Smarkfen 
12934235Smarkfen 			retval = spdsock_get_ext(exts, return_buf,
12944235Smarkfen 			    return_buf->spd_msg_len, NULL, 0);
12954235Smarkfen 			/* ignore retval */
12964235Smarkfen 
12974235Smarkfen 			if (exts[SPD_EXT_RULE]) {
12984235Smarkfen 				conf->ips_policy_index =
12994235Smarkfen 				    ((struct spd_rule *)
13005120Smarkfen 				    exts[SPD_EXT_RULE])->spd_rule_index;
13014235Smarkfen 
13024235Smarkfen 				if (add_index(conf->ips_policy_index)) {
13034235Smarkfen 					free(return_buf);
13044235Smarkfen 					free(polmsg.iov_base);
13054235Smarkfen 					(void) close(fd);
13064235Smarkfen 					return (ENOMEM);
13074235Smarkfen 				}
13084235Smarkfen 			}
13094235Smarkfen 
13104235Smarkfen 			free(return_buf);
13114235Smarkfen 		}
13124235Smarkfen 	}
13134235Smarkfen 
13144235Smarkfen 	free(polmsg.iov_base);
13154235Smarkfen 	(void) close(fd);
13164235Smarkfen 
13174235Smarkfen 	return (0);
13184235Smarkfen 
13194235Smarkfen }
13204235Smarkfen 
13214235Smarkfen int
13224235Smarkfen main(int argc, char *argv[])
13234235Smarkfen {
13244235Smarkfen 	int ret, flushret;
13254235Smarkfen 	int c;
13264235Smarkfen 	int index;
13274235Smarkfen 	boolean_t smf_managed;
13284235Smarkfen 	boolean_t just_check = B_FALSE;
13294235Smarkfen 
13304235Smarkfen 	char *smf_warning = gettext(
13315120Smarkfen 	    "\n\tIPsec policy should be managed using smf(5). Modifying\n"
13325120Smarkfen 	    "\tthe IPsec policy from the command line while the 'policy'\n"
13335120Smarkfen 	    "\tservice is enabled could result in an inconsistent\n"
13345120Smarkfen 	    "\tsecurity policy.\n\n");
13354235Smarkfen 
13364235Smarkfen 	flushret = 0;
13374235Smarkfen 
13384235Smarkfen 	(void) setlocale(LC_ALL, "");
13394235Smarkfen #if !defined(TEXT_DOMAIN)
13404235Smarkfen #define	TEXT_DOMAIN "SYS_TEST"
13414235Smarkfen #endif
13424235Smarkfen 	(void) textdomain(TEXT_DOMAIN);
13434235Smarkfen 
13444235Smarkfen 	openlog("ipsecconf", LOG_CONS, LOG_AUTH);
13454235Smarkfen 
13464235Smarkfen 	/*
13474235Smarkfen 	 * We don't immediately check for privilege here. This is done by IP
13484235Smarkfen 	 * when we open /dev/ip below.
13494235Smarkfen 	 */
13504235Smarkfen 
13514235Smarkfen 	if (argc == 1) {
13524235Smarkfen 		cmd = IPSEC_CONF_VIEW;
13534235Smarkfen 		goto done;
13544235Smarkfen 	}
13554235Smarkfen 	my_fmri = getenv("SMF_FMRI");
13564235Smarkfen 	if (my_fmri == NULL)
13574235Smarkfen 		smf_managed = B_FALSE;
13584235Smarkfen 	else
13594235Smarkfen 		smf_managed = B_TRUE;
13604235Smarkfen 
13614235Smarkfen 	while ((c = getopt(argc, argv, "nlfLFa:qd:r:i:c:")) != EOF) {
13624235Smarkfen 		switch (c) {
13634235Smarkfen 		case 'F':
13644235Smarkfen 			if (interface_name != NULL) {
13654235Smarkfen 				USAGE();
13664235Smarkfen 				EXIT_FATAL("interface name not required.");
13674235Smarkfen 			}
13684235Smarkfen 			/* Apply to all policy heads - global and tunnels. */
13694235Smarkfen 			interface_name = &all_polheads;
13704235Smarkfen 			/* FALLTHRU */
13714235Smarkfen 		case 'f':
13724235Smarkfen 			/* Only one command at a time */
13734235Smarkfen 			if (cmd != 0) {
13744235Smarkfen 				USAGE();
13754235Smarkfen 				EXIT_FATAL("Multiple commands specified");
13764235Smarkfen 			}
13774235Smarkfen 			cmd = IPSEC_CONF_FLUSH;
13784235Smarkfen 			break;
13794235Smarkfen 		case 'L':
13804235Smarkfen 			if (interface_name != NULL) {
13814235Smarkfen 				USAGE();
13824235Smarkfen 				EXIT_FATAL("interface name not required.");
13834235Smarkfen 			}
13844235Smarkfen 			/* Apply to all policy heads - global and tunnels. */
13854235Smarkfen 			interface_name = &all_polheads;
13864235Smarkfen 			/* FALLTHRU */
13874235Smarkfen 		case 'l':
13884235Smarkfen 			/* Only one command at a time */
13894235Smarkfen 			if (cmd != 0) {
13904235Smarkfen 				USAGE();
13914235Smarkfen 				EXIT_FATAL("Multiple commands specified");
13924235Smarkfen 			}
13934235Smarkfen 			cmd = IPSEC_CONF_LIST;
13944235Smarkfen 			break;
13954235Smarkfen 		case 'c':
13964235Smarkfen 			just_check = B_TRUE;
13974235Smarkfen 			ipsecconf_qflag++;
13984235Smarkfen 			/* FALLTHRU */
13994235Smarkfen 		case 'a':
14004235Smarkfen 			/* Only one command at a time, and no interface name */
14014235Smarkfen 			if (cmd != 0 || interface_name != NULL) {
14024235Smarkfen 				USAGE();
14034235Smarkfen 				EXIT_FATAL("Multiple commands or interface "
14044235Smarkfen 				    "not required.");
14054235Smarkfen 			}
14064235Smarkfen 			cmd = IPSEC_CONF_ADD;
14074235Smarkfen 			filename = optarg;
14084235Smarkfen 			break;
14094235Smarkfen 		case 'd':
14104235Smarkfen 			/*
14114235Smarkfen 			 * Only one command at a time.  Interface name is
14124235Smarkfen 			 * optional.
14134235Smarkfen 			 */
14144235Smarkfen 			if (cmd != 0) {
14154235Smarkfen 				USAGE();
14164235Smarkfen 				EXIT_FATAL("Multiple commands specified");
14174235Smarkfen 			}
14184235Smarkfen 			cmd = IPSEC_CONF_DEL;
14194235Smarkfen 			index = parse_index(optarg, NULL);
14204235Smarkfen 			break;
14214235Smarkfen 		case 'n' :
14224235Smarkfen 			ipsecconf_nflag++;
14234235Smarkfen 			break;
14244235Smarkfen 		case 'q' :
14254235Smarkfen 			ipsecconf_qflag++;
14264235Smarkfen 			break;
14274235Smarkfen 		case 'r' :
14284235Smarkfen 			/* Only one command at a time, and no interface name */
14294235Smarkfen 			if (cmd != 0 || interface_name != NULL) {
14304235Smarkfen 				USAGE();
14314235Smarkfen 				EXIT_FATAL("Multiple commands or interface "
14324235Smarkfen 				    "not required.");
14334235Smarkfen 			}
14344235Smarkfen 			cmd = IPSEC_CONF_SUB;
14354235Smarkfen 			filename = optarg;
14364235Smarkfen 			break;
14374235Smarkfen 		case 'i':
14384235Smarkfen 			if (interface_name != NULL) {
14394235Smarkfen 				EXIT_FATAL("Interface name already selected");
14404235Smarkfen 			}
14414235Smarkfen 			interface_name = optarg;
14424235Smarkfen 			/* Check for some cretin using the all-polheads name. */
14434235Smarkfen 			if (strlen(optarg) == 0) {
14444235Smarkfen 				USAGE();
14454235Smarkfen 				EXIT_FATAL("Invalid interface name.");
14464235Smarkfen 			}
14474235Smarkfen 			break;
14484235Smarkfen 		default :
14494235Smarkfen 			USAGE();
14504235Smarkfen 			EXIT_FATAL("Bad usage.");
14514235Smarkfen 		}
14524235Smarkfen 	}
14534235Smarkfen 
14544235Smarkfen done:
14554235Smarkfen 	ret = 0;
14564235Smarkfen 	lfd = lock();
14574235Smarkfen 
14584235Smarkfen 	/*
14594235Smarkfen 	 * ADD, FLUSH, DELETE needs to do two operations.
14604235Smarkfen 	 *
14614235Smarkfen 	 * 1) Update/delete/empty the POLICY_CONF_FILE.
14624235Smarkfen 	 * 2) Make an ioctl and tell IP to update its state.
14634235Smarkfen 	 *
14644235Smarkfen 	 * We already lock()ed so that only one instance of this
14654235Smarkfen 	 * program runs. We also need to make sure that the above
14664235Smarkfen 	 * operations are atomic i.e we don't want to update the file
14674235Smarkfen 	 * and get interrupted before we could tell IP. To make it
14684235Smarkfen 	 * atomic we block all the signals and restore them.
14694235Smarkfen 	 */
14704235Smarkfen 	switch (cmd) {
14714235Smarkfen 	case IPSEC_CONF_LIST:
14724235Smarkfen 		fetch_algorithms();
14734235Smarkfen 		ret = ipsec_conf_list();
14744235Smarkfen 		break;
14754235Smarkfen 	case IPSEC_CONF_FLUSH:
14764235Smarkfen 		if ((ret = block_all_signals()) == -1) {
14774235Smarkfen 			break;
14784235Smarkfen 		}
14794235Smarkfen 		if (!smf_managed && !ipsecconf_qflag)
14804235Smarkfen 			(void) fprintf(stdout, "%s", smf_warning);
14814235Smarkfen 		ret = ipsec_conf_flush(SPD_ACTIVE);
14824235Smarkfen 		(void) restore_all_signals();
14834235Smarkfen 		break;
14844235Smarkfen 	case IPSEC_CONF_VIEW:
14854235Smarkfen 		if (interface_name != NULL) {
14864235Smarkfen 			EXIT_FATAL("Cannot view for one interface only.");
14874235Smarkfen 		}
14884235Smarkfen 		ret = ipsec_conf_view();
14894235Smarkfen 		break;
14904235Smarkfen 	case IPSEC_CONF_DEL:
14914235Smarkfen 		if (index == -1) {
14924235Smarkfen 			warnx(gettext("Invalid index"));
14934235Smarkfen 			ret = -1;
14944235Smarkfen 			break;
14954235Smarkfen 		}
14964235Smarkfen 		if ((ret = block_all_signals()) == -1) {
14974235Smarkfen 			break;
14984235Smarkfen 		}
14994235Smarkfen 		if (!smf_managed && !ipsecconf_qflag)
15004235Smarkfen 			(void) fprintf(stdout, "%s", smf_warning);
15014235Smarkfen 		ret = ipsec_conf_del(index, B_FALSE);
15024235Smarkfen 		(void) restore_all_signals();
15034235Smarkfen 		flushret = ipsec_conf_flush(SPD_STANDBY);
15044235Smarkfen 		break;
15054235Smarkfen 	case IPSEC_CONF_ADD:
15064235Smarkfen 		/*
15074235Smarkfen 		 * The IPsec kernel modules should only be loaded
15084235Smarkfen 		 * if there is a policy to install, for this
15094235Smarkfen 		 * reason ipsec_conf_add() calls fetch_algorithms()
15104235Smarkfen 		 * and ipsec_conf_flush() only when appropriate.
15114235Smarkfen 		 */
15124235Smarkfen 		if ((ret = block_all_signals()) == -1) {
15134235Smarkfen 			break;
15144235Smarkfen 		}
15154235Smarkfen 		if (!smf_managed && !ipsecconf_qflag)
15164235Smarkfen 			(void) fprintf(stdout, "%s", smf_warning);
15174235Smarkfen 		ret = ipsec_conf_add(just_check, smf_managed);
15184235Smarkfen 		(void) restore_all_signals();
15194235Smarkfen 		break;
15204235Smarkfen 	case IPSEC_CONF_SUB:
15214235Smarkfen 		fetch_algorithms();
15224235Smarkfen 		if ((ret = block_all_signals()) == -1) {
15234235Smarkfen 			break;
15244235Smarkfen 		}
15254235Smarkfen 		if (!smf_managed && !ipsecconf_qflag)
15264235Smarkfen 			(void) fprintf(stdout, "%s", smf_warning);
15274235Smarkfen 		ret = ipsec_conf_sub();
15284235Smarkfen 		(void) restore_all_signals();
15294235Smarkfen 		flushret = ipsec_conf_flush(SPD_STANDBY);
15304235Smarkfen 		break;
15314235Smarkfen 	default :
15324235Smarkfen 		/* If no argument is given but a "-" */
15334235Smarkfen 		USAGE();
15344235Smarkfen 		EXIT_FATAL("Bad usage.");
15354235Smarkfen 	}
15364235Smarkfen 
15374235Smarkfen 	(void) unlock(lfd);
15384235Smarkfen 	if (ret != 0 || flushret != 0)
15394235Smarkfen 		ret = 1;
15404235Smarkfen 	return (ret);
15414235Smarkfen }
15424235Smarkfen 
15434235Smarkfen static void
15444235Smarkfen perm_check(void)
15454235Smarkfen {
15464235Smarkfen 	if (errno == EACCES)
15474235Smarkfen 		EXIT_BADPERM("Insufficient privilege to run ipsecconf.");
15484235Smarkfen 	else
15494235Smarkfen 		warn(gettext("Cannot open lock file %s"), LOCK_FILE);
15504235Smarkfen 
15514235Smarkfen 	EXIT_BADPERM(NULL);
15524235Smarkfen }
15534235Smarkfen 
15544235Smarkfen static int
15554235Smarkfen lock()
15564235Smarkfen {
15574235Smarkfen 	int fd;
15584235Smarkfen 	struct stat sbuf1;
15594235Smarkfen 	struct stat sbuf2;
15604235Smarkfen 
15614235Smarkfen 	/*
15624235Smarkfen 	 * Open the file with O_CREAT|O_EXCL. If it exists already, it
15634235Smarkfen 	 * will fail. If it already exists, check whether it looks like
15644235Smarkfen 	 * the one we created.
15654235Smarkfen 	 */
15664235Smarkfen 	(void) umask(0077);
15674235Smarkfen 	if ((fd = open(LOCK_FILE, O_EXCL|O_CREAT|O_RDWR, S_IRUSR|S_IWUSR))
15684235Smarkfen 	    == -1) {
15694235Smarkfen 		if (errno != EEXIST) {
15704235Smarkfen 			/* Some other problem. Will exit. */
15714235Smarkfen 			perm_check();
15724235Smarkfen 		}
15734235Smarkfen 
15744235Smarkfen 		/*
15754235Smarkfen 		 * open() returned an EEXIST error. We don't fail yet
15764235Smarkfen 		 * as it could be a residual from a previous
15774235Smarkfen 		 * execution.
15784235Smarkfen 		 * File exists. make sure it is OK. We need to lstat()
15794235Smarkfen 		 * as fstat() stats the file pointed to by the symbolic
15804235Smarkfen 		 * link.
15814235Smarkfen 		 */
15824235Smarkfen 		if (lstat(LOCK_FILE, &sbuf1) == -1) {
15834235Smarkfen 			EXIT_FATAL2("Cannot lstat lock file %s", LOCK_FILE);
15844235Smarkfen 		}
15854235Smarkfen 		/*
15864235Smarkfen 		 * Check whether it is a regular file and not a symbolic
15874235Smarkfen 		 * link. Its link count should be 1. The owner should be
15884235Smarkfen 		 * root and the file should be empty.
15894235Smarkfen 		 */
15904235Smarkfen 		if (!S_ISREG(sbuf1.st_mode) ||
15914235Smarkfen 		    sbuf1.st_nlink != 1 ||
15924235Smarkfen 		    sbuf1.st_uid != 0 ||
15934235Smarkfen 		    sbuf1.st_size != 0) {
15944235Smarkfen 			EXIT_FATAL2("Bad lock file %s", LOCK_FILE);
15954235Smarkfen 		}
15964235Smarkfen 		if ((fd = open(LOCK_FILE, O_CREAT|O_RDWR,
15974235Smarkfen 		    S_IRUSR|S_IWUSR)) == -1) {
15984235Smarkfen 			/* Will exit */
15994235Smarkfen 			perm_check();
16004235Smarkfen 		}
16014235Smarkfen 		/*
16024235Smarkfen 		 * Check whether we opened the file that we lstat()ed.
16034235Smarkfen 		 */
16044235Smarkfen 		if (fstat(fd, &sbuf2) == -1) {
16054235Smarkfen 			EXIT_FATAL2("Cannot lstat lock file %s", LOCK_FILE);
16064235Smarkfen 		}
16074235Smarkfen 		if (sbuf1.st_dev != sbuf2.st_dev ||
16084235Smarkfen 		    sbuf1.st_ino != sbuf2.st_ino) {
16094235Smarkfen 			/* File changed after we did the lstat() above */
16104235Smarkfen 			EXIT_FATAL2("Bad lock file %s", LOCK_FILE);
16114235Smarkfen 		}
16124235Smarkfen 	}
16134235Smarkfen 	if (lockf(fd, F_LOCK, 0) == -1) {
16144235Smarkfen 		EXIT_FATAL2("Cannot lockf %s", LOCK_FILE);
16154235Smarkfen 	}
16164235Smarkfen 	return (fd);
16174235Smarkfen }
16184235Smarkfen 
16194235Smarkfen static int
16204235Smarkfen unlock(int fd)
16214235Smarkfen {
16224235Smarkfen 	if (lockf(fd, F_ULOCK, 0) == -1) {
16234235Smarkfen 		warn("lockf");
16244235Smarkfen 		return (-1);
16254235Smarkfen 	}
16264235Smarkfen 	return (0);
16274235Smarkfen }
16284235Smarkfen 
16294235Smarkfen /* send in TOK_* */
16304235Smarkfen static void
16314235Smarkfen print_pattern_string(int type)
16324235Smarkfen {
16334235Smarkfen 	int j;
16344235Smarkfen 
16354235Smarkfen 	for (j = 0; pattern_table[j].string != NULL; j++) {
16364235Smarkfen 		if (type == pattern_table[j].tok_val) {
16374235Smarkfen 			(void) printf("%s ", pattern_table[j].string);
16384235Smarkfen 			return;
16394235Smarkfen 		}
16404235Smarkfen 	}
16414235Smarkfen }
16424235Smarkfen 
16434235Smarkfen static void
16444235Smarkfen print_icmp_typecode(uint8_t type, uint8_t type_end, uint8_t code,
16454235Smarkfen     uint8_t code_end)
16464235Smarkfen {
16474235Smarkfen 	(void) printf("type %d", type);
16484235Smarkfen 	if (type_end != type)
16494235Smarkfen 		(void) printf("-%d ", type_end);
16504235Smarkfen 	else
16514235Smarkfen 		(void) printf(" ");
16524235Smarkfen 	if (code != 255) {
16534235Smarkfen 		(void) printf("code %d", code);
16544235Smarkfen 		if (code_end != code)
16554235Smarkfen 			(void) printf("-%d ", code_end);
16564235Smarkfen 		else
16574235Smarkfen 			(void) printf(" ");
16584235Smarkfen 	}
16594235Smarkfen }
16604235Smarkfen 
16614235Smarkfen 
16624235Smarkfen static void
16634235Smarkfen print_spd_flags(uint32_t flags)
16644235Smarkfen {
16654235Smarkfen 	flags &= (SPD_RULE_FLAG_INBOUND|SPD_RULE_FLAG_OUTBOUND);
16664235Smarkfen 
16674235Smarkfen 	if (flags == SPD_RULE_FLAG_OUTBOUND)
16684235Smarkfen 		(void) printf("dir out ");
16694235Smarkfen 	else if (flags == SPD_RULE_FLAG_INBOUND)
16704235Smarkfen 		(void) printf("dir in ");
16714235Smarkfen 	else if (flags == (SPD_RULE_FLAG_INBOUND|SPD_RULE_FLAG_OUTBOUND))
16724235Smarkfen 		(void) printf("dir both ");
16734235Smarkfen }
16744235Smarkfen 
16754235Smarkfen static void
16764235Smarkfen print_bit_range(int min, int max)
16774235Smarkfen {
16784235Smarkfen 	if (min != 0 || (max != 0 && max != SPD_MAX_MAXBITS)) {
16794235Smarkfen 		(void) printf("(");
16804235Smarkfen 		if (min != 0)
16814235Smarkfen 			(void) printf("%d", min);
16824235Smarkfen 		if (min != 0 && max != 0 && min != max) {
16834235Smarkfen 			(void) printf("..");
16844235Smarkfen 			if (max != 0 && max != SPD_MAX_MAXBITS)
16854235Smarkfen 				(void) printf("%d", max);
16864235Smarkfen 		}
16874235Smarkfen 		(void) printf(")");
16884235Smarkfen 	}
16894235Smarkfen }
16904235Smarkfen 
16914235Smarkfen static void
16924235Smarkfen print_alg(const char *tag, algreq_t *algreq, int proto_num)
16934235Smarkfen {
16944235Smarkfen 	int min = algreq->alg_minbits;
16954235Smarkfen 	int max = algreq->alg_maxbits;
16964235Smarkfen 	struct ipsecalgent *alg;
16974235Smarkfen 
16984235Smarkfen 	/*
16994235Smarkfen 	 * This function won't be called with alg_id == 0, so we don't
17004235Smarkfen 	 * have to worry about ANY vs. NONE here.
17014235Smarkfen 	 */
17024235Smarkfen 
17034235Smarkfen 	(void) printf("%s ", tag);
17044235Smarkfen 
17054235Smarkfen 	alg = getipsecalgbynum(algreq->alg_id, proto_num, NULL);
17064235Smarkfen 	if (alg == NULL) {
17074235Smarkfen 		(void) printf("%d", algreq->alg_id);
17084235Smarkfen 	} else {
17094235Smarkfen 		(void) printf("%s", alg->a_names[0]);
17104235Smarkfen 		freeipsecalgent(alg);
17114235Smarkfen 	}
17124235Smarkfen 
17134235Smarkfen 	print_bit_range(min, max);
17144235Smarkfen 	(void) printf(" ");
17154235Smarkfen }
17164235Smarkfen 
17174235Smarkfen static void
17184235Smarkfen print_ulp(uint8_t proto)
17194235Smarkfen {
17204235Smarkfen 	struct protoent *pe;
17214235Smarkfen 
17224235Smarkfen 	if (proto == 0)
17234235Smarkfen 		return;
17244235Smarkfen 
17254235Smarkfen 	print_pattern_string(TOK_ulp);
17264235Smarkfen 	pe = NULL;
17274235Smarkfen 	if (!ipsecconf_nflag) {
17284235Smarkfen 		pe = getprotobynumber(proto);
17294235Smarkfen 	}
17304235Smarkfen 	if (pe != NULL)
17314235Smarkfen 		(void) printf("%s ", pe->p_name);
17324235Smarkfen 	else
17334235Smarkfen 		(void) printf("%d ", proto);
17344235Smarkfen }
17354235Smarkfen 
17364235Smarkfen /* needs to do ranges */
17374235Smarkfen static void
17384235Smarkfen print_port(uint16_t in_port, int type)
17394235Smarkfen {
17404235Smarkfen 	in_port_t port = ntohs(in_port);
17414235Smarkfen 	struct servent *sp;
17424235Smarkfen 
17434235Smarkfen 	if (port == 0)
17444235Smarkfen 		return;
17454235Smarkfen 
17464235Smarkfen 	print_pattern_string(type);
17474235Smarkfen 	sp = NULL;
17484235Smarkfen 	if (!ipsecconf_nflag)
17494235Smarkfen 		sp = getservbyport(port, NULL);
17504235Smarkfen 
17514235Smarkfen 	if (sp != NULL)
17524235Smarkfen 		(void) printf("%s ", sp->s_name);
17534235Smarkfen 	else
17544235Smarkfen 		(void) printf("%d ", port);
17554235Smarkfen }
17564235Smarkfen 
17574235Smarkfen /*
17584235Smarkfen  * Print the address, given as "raw" input via the void pointer.
17594235Smarkfen  */
17604235Smarkfen static void
17614235Smarkfen print_raw_address(void *input, boolean_t isv4)
17624235Smarkfen {
17634235Smarkfen 	char  *cp;
17644235Smarkfen 	struct hostent *hp;
17654235Smarkfen 	char	domain[MAXHOSTNAMELEN + 1];
17664235Smarkfen 	struct in_addr addr;
17674235Smarkfen 	struct in6_addr addr6;
17684235Smarkfen 	char abuf[INET6_ADDRSTRLEN];
17694235Smarkfen 	int error_num;
17704235Smarkfen 	struct in6_addr in_addr;
17714235Smarkfen 	uchar_t *addr_ptr;
17724235Smarkfen 	sa_family_t af;
17734235Smarkfen 	int addr_len;
17744235Smarkfen 
17754235Smarkfen 	if (isv4) {
17764235Smarkfen 		af = AF_INET;
17774235Smarkfen 		(void) memcpy(&V4_PART_OF_V6(in_addr), input, 4);
17784235Smarkfen 		/* we don't print unspecified addresses */
17794235Smarkfen 		IN6_V4MAPPED_TO_INADDR(&in_addr, &addr);
17804235Smarkfen 		if (addr.s_addr == INADDR_ANY)
17814235Smarkfen 			return;
17824235Smarkfen 		addr_ptr = (uchar_t *)&addr.s_addr;
17834235Smarkfen 		addr_len = IPV4_ADDR_LEN;
17844235Smarkfen 	} else {
17854235Smarkfen 		(void) memcpy(&addr6, input, 16);
17864235Smarkfen 		af = AF_INET6;
17874235Smarkfen 		/* we don't print unspecified addresses */
17884235Smarkfen 		if (IN6_IS_ADDR_UNSPECIFIED(&addr6))
17894235Smarkfen 			return;
17904235Smarkfen 		addr_ptr = (uchar_t *)&addr6.s6_addr;
17914235Smarkfen 		addr_len = sizeof (struct in6_addr);
17924235Smarkfen 	}
17934235Smarkfen 
17944235Smarkfen 	cp = NULL;
17954235Smarkfen 	if (!ipsecconf_nflag) {
17964235Smarkfen 		if (sysinfo(SI_HOSTNAME, domain, MAXHOSTNAMELEN) != -1 &&
17975120Smarkfen 		    (cp = strchr(domain, '.')) != NULL) {
17984235Smarkfen 			(void) strlcpy(domain, cp + 1, sizeof (domain));
17994235Smarkfen 		} else {
18004235Smarkfen 			domain[0] = 0;
18014235Smarkfen 		}
18027174Spwernau 		cp = NULL;
18034235Smarkfen 		hp = getipnodebyaddr(addr_ptr, addr_len, af, &error_num);
18044235Smarkfen 		if (hp) {
18054235Smarkfen 			if ((cp = strchr(hp->h_name, '.')) != 0 &&
18065120Smarkfen 			    strcasecmp(cp + 1, domain) == 0)
18074235Smarkfen 				*cp = 0;
18084235Smarkfen 			cp = hp->h_name;
18094235Smarkfen 		}
18104235Smarkfen 	}
18114235Smarkfen 
18124235Smarkfen 	if (cp) {
18134235Smarkfen 		(void) printf("%s", cp);
18144235Smarkfen 	} else {
18154235Smarkfen 		(void) printf("%s", inet_ntop(af, addr_ptr, abuf,
18164235Smarkfen 		    INET6_ADDRSTRLEN));
18174235Smarkfen 	}
18184235Smarkfen }
18194235Smarkfen 
18204235Smarkfen /*
18214235Smarkfen  * Get the next SPD_DUMP message from the PF_POLICY socket.  A single
18224235Smarkfen  * read may contain multiple messages.  This function uses static buffers,
18234235Smarkfen  * and is therefore non-reentrant, so if you lift it for an MT application,
18244235Smarkfen  * be careful.
18254235Smarkfen  *
18264235Smarkfen  * Return NULL if there's an error.
18274235Smarkfen  */
18284235Smarkfen static spd_msg_t *
18294235Smarkfen ipsec_read_dump(int pfd)
18304235Smarkfen {
18314235Smarkfen 	static uint64_t buf[SADB_8TO64(CBUF_LEN)];
18324235Smarkfen 	static uint64_t *offset;
18334235Smarkfen 	static int len;		/* In uint64_t units. */
18344235Smarkfen 	spd_msg_t *retval;
18354235Smarkfen 
18364235Smarkfen 	/* Assume offset and len are initialized to NULL and 0. */
18374235Smarkfen 
18384235Smarkfen 	if ((offset - len == buf) || (offset == NULL)) {
18394235Smarkfen 		/* read a new block from the socket. */
18404235Smarkfen 		len = read(pfd, &buf, sizeof (buf));
18414235Smarkfen 		if (len == -1) {
18424235Smarkfen 			warn(gettext("rule dump: bad read"));
18434235Smarkfen 			return (NULL);
18444235Smarkfen 		}
18454235Smarkfen 		offset = buf;
18464235Smarkfen 		len = SADB_8TO64(len);
18474235Smarkfen 	} /* Else I still have more messages from a previous read. */
18484235Smarkfen 
18494235Smarkfen 	retval = (spd_msg_t *)offset;
18504235Smarkfen 	offset += retval->spd_msg_len;
18514235Smarkfen 	if (offset > buf + len) {
18524235Smarkfen 		warnx(gettext("dump read: message corruption,"
18534235Smarkfen 		    " %d len exceeds %d boundary."),
18544235Smarkfen 		    SADB_64TO8((uintptr_t)(offset - buf)),
18554235Smarkfen 		    SADB_64TO8((uintptr_t)(buf + len)));
18564235Smarkfen 		return (NULL);
18574235Smarkfen 	}
18584235Smarkfen 
18594235Smarkfen 	return (retval);
18604235Smarkfen }
18614235Smarkfen 
18624235Smarkfen /*
18634235Smarkfen  * returns 0 on success
18644235Smarkfen  * -1 on read error
18654235Smarkfen  * >0  on invalid returned message
18664235Smarkfen  */
18674235Smarkfen 
18684235Smarkfen static int
18694235Smarkfen ipsec_conf_list(void)
18704235Smarkfen {
18714235Smarkfen 	int ret;
18724235Smarkfen 	int pfd;
18734235Smarkfen 	struct spd_msg *msg;
18744235Smarkfen 	int cnt;
18754235Smarkfen 	spd_msg_t *rmsg;
18764235Smarkfen 	spd_ext_t *exts[SPD_EXT_MAX+1];
18774235Smarkfen 	/*
18784235Smarkfen 	 * Add an extra 8 bytes of space (+1 uint64_t) to avoid truncation
18794235Smarkfen 	 * issues.
18804235Smarkfen 	 */
18814235Smarkfen 	uint64_t buffer[
18824235Smarkfen 	    SPD_8TO64(sizeof (*msg) + sizeof (spd_if_t) + LIFNAMSIZ) + 1];
18834235Smarkfen 
18844235Smarkfen 	pfd = get_pf_pol_socket();
18854235Smarkfen 
18864235Smarkfen 	if (pfd == -1) {
18874235Smarkfen 		warnx(gettext("Error getting list of policies from kernel"));
18884235Smarkfen 		return (-1);
18894235Smarkfen 	}
18904235Smarkfen 
18914235Smarkfen 	(void) memset(buffer, 0, sizeof (buffer));
18924235Smarkfen 	msg = (struct spd_msg *)buffer;
18934235Smarkfen 	msg->spd_msg_version = PF_POLICY_V1;
18944235Smarkfen 	msg->spd_msg_type = SPD_DUMP;
18954235Smarkfen 	msg->spd_msg_len = SPD_8TO64(sizeof (*msg));
18964235Smarkfen 
18974235Smarkfen 	msg->spd_msg_len += attach_tunname((spd_if_t *)(msg + 1));
18984235Smarkfen 
18994235Smarkfen 	cnt = write(pfd, msg, SPD_64TO8(msg->spd_msg_len));
19004235Smarkfen 
19014235Smarkfen 	if (cnt < 0) {
19024235Smarkfen 		warn(gettext("dump: invalid write() return"));
19034235Smarkfen 		(void) close(pfd);
19044235Smarkfen 		return (-1);
19054235Smarkfen 	}
19064235Smarkfen 
19074235Smarkfen 	rmsg = ipsec_read_dump(pfd);
19084235Smarkfen 
19094235Smarkfen 	if (rmsg == NULL || rmsg->spd_msg_errno != 0) {
19104235Smarkfen 		warnx("%s: %s", gettext("ruleset dump failed"),
19114235Smarkfen 		    (rmsg == NULL ?
19125120Smarkfen 		    gettext("read error") :
19135120Smarkfen 		    sys_error_message(rmsg->spd_msg_errno)));
19144235Smarkfen 		(void) close(pfd);
19154235Smarkfen 		return (-1);
19164235Smarkfen 	}
19174235Smarkfen 
19184235Smarkfen 
19194235Smarkfen 	for (;;) {
19204235Smarkfen 		/* read rule */
19214235Smarkfen 		rmsg = ipsec_read_dump(pfd);
19224235Smarkfen 
19234235Smarkfen 		if (rmsg == NULL) {
19244235Smarkfen 			(void) close(pfd);
19254235Smarkfen 			return (-1);
19264235Smarkfen 		}
19274235Smarkfen 
19284235Smarkfen 		if (rmsg->spd_msg_errno != 0) {
19294235Smarkfen 			warnx("%s: %s", gettext("dump read: bad message"),
19304235Smarkfen 			    sys_error_message(rmsg->spd_msg_errno));
19314235Smarkfen 			(void) close(pfd);
19324235Smarkfen 			return (-1);
19334235Smarkfen 		}
19344235Smarkfen 
19354235Smarkfen 		ret = spdsock_get_ext(exts, rmsg, rmsg->spd_msg_len,
19364235Smarkfen 		    spdsock_diag_buf, SPDSOCK_DIAG_BUF_LEN);
19374235Smarkfen 		if (ret != 0) {
19384235Smarkfen 			if (strlen(spdsock_diag_buf) != 0)
19394235Smarkfen 				warnx(spdsock_diag_buf);
19404235Smarkfen 			warnx("%s: %s", gettext("dump read: bad message"),
19414235Smarkfen 			    sys_error_message(rmsg->spd_msg_errno));
19424235Smarkfen 			(void) close(pfd);
19434235Smarkfen 			return (ret);
19444235Smarkfen 		}
19454235Smarkfen 
19464235Smarkfen 		/*
19474235Smarkfen 		 * End of dump..
19484235Smarkfen 		 */
19494235Smarkfen 		if (exts[SPD_EXT_RULESET] != NULL)
19504235Smarkfen 			break;	/* and return 0. */
19514235Smarkfen 
19524235Smarkfen 		print_pfpol_msg(rmsg);
19534235Smarkfen 	}
19544235Smarkfen 
19554235Smarkfen 	(void) close(pfd);
19564235Smarkfen 	return (0);
19574235Smarkfen }
19584235Smarkfen 
19594235Smarkfen static void
19604235Smarkfen print_iap(ips_act_props_t *iap)
19614235Smarkfen {
19624235Smarkfen 
19634235Smarkfen 	/* action */
19644235Smarkfen 	switch (iap->iap_action) {
19654235Smarkfen 	case SPD_ACTTYPE_PASS:
19664235Smarkfen 		(void) printf("pass ");
19674235Smarkfen 		break;
19684235Smarkfen 	case SPD_ACTTYPE_DROP:
19694235Smarkfen 		(void) printf("drop ");
19704235Smarkfen 		break;
19714235Smarkfen 	case SPD_ACTTYPE_IPSEC:
19724235Smarkfen 		(void) printf("ipsec ");
19734235Smarkfen 		break;
19744235Smarkfen 	}
19754235Smarkfen 
19764235Smarkfen 	/* properties */
19774235Smarkfen 	(void) printf("%c ", CURL_BEGIN);
19784235Smarkfen 	if (iap->iap_action == SPD_ACTTYPE_IPSEC) {
19794235Smarkfen 		if (iap->iap_attr & SPD_APPLY_AH &&
19804235Smarkfen 		    iap->iap_aauth.alg_id != 0)
19814235Smarkfen 			print_alg("auth_algs", &iap->iap_aauth,
19824235Smarkfen 			    IPSEC_PROTO_AH);
19834235Smarkfen 
19844235Smarkfen 		if (iap->iap_attr & SPD_APPLY_ESP) {
19854235Smarkfen 			print_alg("encr_algs", &iap->iap_eencr,
19864235Smarkfen 			    IPSEC_PROTO_ESP);
19874235Smarkfen 			if (iap->iap_eauth.alg_id != 0)
19884235Smarkfen 				print_alg("encr_auth_algs", &iap->iap_eauth,
19894235Smarkfen 				    IPSEC_PROTO_AH);
19904235Smarkfen 		}
19914235Smarkfen 		if (iap->iap_attr & SPD_APPLY_UNIQUE)
19924235Smarkfen 			(void) printf("sa unique ");
19934235Smarkfen 		else
19944235Smarkfen 			(void) printf("sa shared ");
19954235Smarkfen 	}
19964235Smarkfen 	(void) printf("%c ", CURL_END);
19974235Smarkfen }
19984235Smarkfen 
19994235Smarkfen 
20004235Smarkfen static void
20014235Smarkfen print_pfpol_msg(spd_msg_t *msg)
20024235Smarkfen {
20034235Smarkfen 	spd_ext_t *exts[SPD_EXT_MAX+1];
20044235Smarkfen 	spd_address_t *spd_address;
20054235Smarkfen 	struct spd_rule *spd_rule;
20064235Smarkfen 	struct spd_proto *spd_proto;
20074235Smarkfen 	struct spd_portrange *spd_portrange;
20084235Smarkfen 	struct spd_ext_actions *spd_ext_actions;
20094235Smarkfen 	struct spd_typecode *spd_typecode;
20104235Smarkfen 	struct spd_attribute *app;
20114235Smarkfen 	spd_if_t *spd_if;
20124235Smarkfen 	uint32_t rv;
20134235Smarkfen 	uint16_t act_count;
20144235Smarkfen 
20154235Smarkfen 	rv = spdsock_get_ext(exts, msg, msg->spd_msg_len, spdsock_diag_buf,
20164235Smarkfen 	    SPDSOCK_DIAG_BUF_LEN);
20174235Smarkfen 
20184235Smarkfen 	if (rv == KGE_OK && exts[SPD_EXT_RULE] != NULL) {
20194235Smarkfen 		spd_if = (spd_if_t *)exts[SPD_EXT_TUN_NAME];
20204235Smarkfen 		spd_rule = (struct spd_rule *)exts[SPD_EXT_RULE];
20214235Smarkfen 		if (spd_if == NULL) {
20224235Smarkfen 			(void) printf("%s %lld\n", INDEX_TAG,
20234235Smarkfen 			    spd_rule->spd_rule_index);
20244235Smarkfen 		} else {
20254235Smarkfen 			(void) printf("%s %s,%lld\n", INDEX_TAG,
20264235Smarkfen 			    (char *)spd_if->spd_if_name,
20274235Smarkfen 			    spd_rule->spd_rule_index);
20284235Smarkfen 		}
20294235Smarkfen 	} else {
20304235Smarkfen 		if (strlen(spdsock_diag_buf) != 0)
20314235Smarkfen 			warnx(spdsock_diag_buf);
20324235Smarkfen 		warnx(gettext("print_pfpol_msg: malformed PF_POLICY message."));
20334235Smarkfen 		return;
20344235Smarkfen 	}
20354235Smarkfen 
20364235Smarkfen 	(void) printf("%c ", CURL_BEGIN);
20374235Smarkfen 
20384235Smarkfen 	if (spd_if != NULL) {
20394235Smarkfen 		(void) printf("tunnel %s negotiate %s ",
20404235Smarkfen 		    (char *)spd_if->spd_if_name,
20414235Smarkfen 		    (spd_rule->spd_rule_flags & SPD_RULE_FLAG_TUNNEL) ?
20424235Smarkfen 		    "tunnel" : "transport");
20434235Smarkfen 	}
20444235Smarkfen 
20454235Smarkfen 	if (exts[SPD_EXT_PROTO] != NULL) {
20464235Smarkfen 		spd_proto = (struct spd_proto *)exts[SPD_EXT_PROTO];
20474235Smarkfen 		print_ulp(spd_proto->spd_proto_number);
20484235Smarkfen 	}
20494235Smarkfen 
20504235Smarkfen 	if (exts[SPD_EXT_LCLADDR] != NULL) {
20514235Smarkfen 		spd_address = (spd_address_t *)exts[SPD_EXT_LCLADDR];
20524235Smarkfen 
20534235Smarkfen 		(void) printf("laddr ");
20544235Smarkfen 		print_raw_address((spd_address + 1),
20554235Smarkfen 		    (spd_address->spd_address_len == 2));
20564235Smarkfen 		(void) printf("/%d ", spd_address->spd_address_prefixlen);
20574235Smarkfen 	}
20584235Smarkfen 
20594235Smarkfen 	if (exts[SPD_EXT_LCLPORT] != NULL) {
20604235Smarkfen 		spd_portrange = (struct spd_portrange *)exts[SPD_EXT_LCLPORT];
20614235Smarkfen 		if (spd_portrange->spd_ports_minport != 0) {
20624235Smarkfen 			print_port(spd_portrange->spd_ports_minport,
20634235Smarkfen 			    TOK_lport);
20644235Smarkfen 		}
20654235Smarkfen 	}
20664235Smarkfen 
20674235Smarkfen 
20684235Smarkfen 	if (exts[SPD_EXT_REMADDR] != NULL) {
20694235Smarkfen 		spd_address = (spd_address_t *)exts[SPD_EXT_REMADDR];
20704235Smarkfen 
20714235Smarkfen 		(void) printf("raddr ");
20724235Smarkfen 		print_raw_address((spd_address + 1),
20734235Smarkfen 		    (spd_address->spd_address_len == 2));
20744235Smarkfen 		(void) printf("/%d ", spd_address->spd_address_prefixlen);
20754235Smarkfen 	}
20764235Smarkfen 
20774235Smarkfen 	if (exts[SPD_EXT_REMPORT] != NULL) {
20784235Smarkfen 		spd_portrange =
20795120Smarkfen 		    (struct spd_portrange *)exts[SPD_EXT_REMPORT];
20804235Smarkfen 		if (spd_portrange->spd_ports_minport != 0) {
20814235Smarkfen 			print_port(
20825120Smarkfen 			    spd_portrange->spd_ports_minport, TOK_rport);
20834235Smarkfen 		}
20844235Smarkfen 	}
20854235Smarkfen 
20864235Smarkfen 	if (exts[SPD_EXT_ICMP_TYPECODE] != NULL) {
20874235Smarkfen 		spd_typecode =
20884235Smarkfen 		    (struct spd_typecode *)exts[SPD_EXT_ICMP_TYPECODE];
20894235Smarkfen 		print_icmp_typecode(spd_typecode->spd_typecode_type,
20904235Smarkfen 		    spd_typecode->spd_typecode_type_end,
20914235Smarkfen 		    spd_typecode->spd_typecode_code,
20924235Smarkfen 		    spd_typecode->spd_typecode_code_end);
20934235Smarkfen 	}
20944235Smarkfen 
20954235Smarkfen 	if (exts[SPD_EXT_RULE] != NULL) {
20964235Smarkfen 		spd_rule = (struct spd_rule *)exts[SPD_EXT_RULE];
20974235Smarkfen 		print_spd_flags(spd_rule->spd_rule_flags);
20984235Smarkfen 	}
20994235Smarkfen 
21004235Smarkfen 
21014235Smarkfen 	(void) printf("%c ", CURL_END);
21024235Smarkfen 
21034235Smarkfen 	if (exts[SPD_EXT_ACTION] != NULL) {
21044235Smarkfen 		ips_act_props_t iap;
21054235Smarkfen 		int or_needed = 0;
21064235Smarkfen 
21074235Smarkfen 		(void) memset(&iap, 0, sizeof (iap));
21084235Smarkfen 		spd_ext_actions =
21094235Smarkfen 		    (struct spd_ext_actions *)exts[SPD_EXT_ACTION];
21104235Smarkfen 		app = (struct spd_attribute *)(spd_ext_actions + 1);
21114235Smarkfen 
21124235Smarkfen 		for (act_count = 0;
21134235Smarkfen 		    act_count < spd_ext_actions->spd_actions_len -1;
21145120Smarkfen 		    act_count++) {
21154235Smarkfen 
21164235Smarkfen 			switch (app->spd_attr_tag) {
21174235Smarkfen 
21184235Smarkfen 			case SPD_ATTR_NOP:
21194235Smarkfen 				break;
21204235Smarkfen 
21214235Smarkfen 			case SPD_ATTR_END:
21224235Smarkfen 				/* print */
21234235Smarkfen 				if (or_needed) {
21244235Smarkfen 					(void) printf("or ");
21254235Smarkfen 				} else {
21264235Smarkfen 					or_needed = 1;
21274235Smarkfen 				}
21284235Smarkfen 				print_iap(&iap);
21294235Smarkfen 				break;
21304235Smarkfen 
21314235Smarkfen 			case SPD_ATTR_EMPTY:
21324235Smarkfen 				/* clear */
21334235Smarkfen 				(void) memset(&iap, 0, sizeof (iap));
21344235Smarkfen 				break;
21354235Smarkfen 
21364235Smarkfen 			case SPD_ATTR_NEXT:
21374235Smarkfen 				/* print */
21384235Smarkfen 				if (or_needed) {
21394235Smarkfen 					(void) printf("or ");
21404235Smarkfen 				} else {
21414235Smarkfen 					or_needed = 1;
21424235Smarkfen 				}
21434235Smarkfen 
21444235Smarkfen 				print_iap(&iap);
21454235Smarkfen 				break;
21464235Smarkfen 
21474235Smarkfen 			case SPD_ATTR_TYPE:
21484235Smarkfen 				iap.iap_action = app->spd_attr_value;
21494235Smarkfen 				break;
21504235Smarkfen 
21514235Smarkfen 			case SPD_ATTR_FLAGS:
21524235Smarkfen 				iap.iap_attr = app->spd_attr_value;
21534235Smarkfen 				break;
21544235Smarkfen 
21554235Smarkfen 			case SPD_ATTR_AH_AUTH:
21564235Smarkfen 				iap.iap_aauth.alg_id = app->spd_attr_value;
21574235Smarkfen 				break;
21584235Smarkfen 
21594235Smarkfen 			case SPD_ATTR_ESP_ENCR:
21604235Smarkfen 				iap.iap_eencr.alg_id = app->spd_attr_value;
21614235Smarkfen 				break;
21624235Smarkfen 
21634235Smarkfen 			case SPD_ATTR_ESP_AUTH:
21644235Smarkfen 				iap.iap_eauth.alg_id = app->spd_attr_value;
21654235Smarkfen 				break;
21664235Smarkfen 
21674235Smarkfen 			case SPD_ATTR_ENCR_MINBITS:
21684235Smarkfen 				iap.iap_eencr.alg_minbits = app->spd_attr_value;
21694235Smarkfen 				break;
21704235Smarkfen 
21714235Smarkfen 			case SPD_ATTR_ENCR_MAXBITS:
21724235Smarkfen 				iap.iap_eencr.alg_maxbits = app->spd_attr_value;
21734235Smarkfen 				break;
21744235Smarkfen 
21754235Smarkfen 			case SPD_ATTR_AH_MINBITS:
21764235Smarkfen 				iap.iap_aauth.alg_minbits = app->spd_attr_value;
21774235Smarkfen 				break;
21784235Smarkfen 
21794235Smarkfen 			case SPD_ATTR_AH_MAXBITS:
21804235Smarkfen 				iap.iap_aauth.alg_maxbits = app->spd_attr_value;
21814235Smarkfen 				break;
21824235Smarkfen 
21834235Smarkfen 			case SPD_ATTR_ESPA_MINBITS:
21844235Smarkfen 				iap.iap_eauth.alg_minbits = app->spd_attr_value;
21854235Smarkfen 				break;
21864235Smarkfen 
21874235Smarkfen 			case SPD_ATTR_ESPA_MAXBITS:
21884235Smarkfen 				iap.iap_eauth.alg_maxbits = app->spd_attr_value;
21894235Smarkfen 				break;
21904235Smarkfen 
21914235Smarkfen 			case SPD_ATTR_LIFE_SOFT_TIME:
21924235Smarkfen 			case SPD_ATTR_LIFE_HARD_TIME:
21934235Smarkfen 			case SPD_ATTR_LIFE_SOFT_BYTES:
21944235Smarkfen 			case SPD_ATTR_LIFE_HARD_BYTES:
21954235Smarkfen 			default:
21964235Smarkfen 				(void) printf("\tattr %d: %X-%d\n",
21974235Smarkfen 				    act_count,
21984235Smarkfen 				    app->spd_attr_tag,
21994235Smarkfen 				    app->spd_attr_value);
22004235Smarkfen 				break;
22014235Smarkfen 			}
22024235Smarkfen 			app++;
22034235Smarkfen 		}
22044235Smarkfen 	}
22054235Smarkfen 
22064235Smarkfen 	(void) printf("\n");
22074235Smarkfen }
22084235Smarkfen 
22094235Smarkfen #ifdef DEBUG_HEAVY
22104235Smarkfen static void
22114235Smarkfen pfpol_msg_dump(spd_msg_t *msg, char *tag)
22124235Smarkfen {
22134235Smarkfen 	spd_ext_t *exts[SPD_EXT_MAX+1];
22144235Smarkfen 	uint32_t i;
22154235Smarkfen 	spd_address_t *spd_address;
22164235Smarkfen 	struct spd_rule *spd_rule;
22174235Smarkfen 	struct spd_proto *spd_proto;
22184235Smarkfen 	struct spd_portrange *spd_portrange;
22194235Smarkfen 	struct spd_typecode *spd_typecode;
22204235Smarkfen 	struct spd_ext_actions *spd_ext_actions;
22214235Smarkfen 	struct spd_attribute *app;
22224235Smarkfen 	spd_if_t *spd_if;
22234235Smarkfen 	char abuf[INET6_ADDRSTRLEN];
22244235Smarkfen 	uint32_t rv;
22254235Smarkfen 	uint16_t act_count;
22264235Smarkfen 
22274235Smarkfen 	rv = spdsock_get_ext(exts, msg, msg->spd_msg_len, NULL, 0);
22284235Smarkfen 	if (rv != KGE_OK)
22294235Smarkfen 		return;
22304235Smarkfen 
22314235Smarkfen 	(void) printf("===========%s==============\n", tag);
22324235Smarkfen 	(void) printf("pfpol_msg_dump %d\n-------------------\n", rv);
22334235Smarkfen 
22344235Smarkfen 	(void) printf("spd_msg_version:%d\n", msg->spd_msg_version);
22354235Smarkfen 	(void) printf("spd_msg_type:%d\n", msg->spd_msg_type);
22364235Smarkfen 	(void) printf("spd_msg_errno:%d\n", msg->spd_msg_errno);
22374235Smarkfen 	(void) printf("spd_msg_spdid:%d\n", msg->spd_msg_spdid);
22384235Smarkfen 	(void) printf("spd_msg_len:%d\n", msg->spd_msg_len);
22394235Smarkfen 	(void) printf("spd_msg_diagnostic:%d\n", msg->spd_msg_diagnostic);
22404235Smarkfen 	(void) printf("spd_msg_seq:%d\n", msg->spd_msg_seq);
22414235Smarkfen 	(void) printf("spd_msg_pid:%d\n", msg->spd_msg_pid);
22424235Smarkfen 
22434235Smarkfen 	for (i = 1; i <= SPD_EXT_MAX; i++) {
22444235Smarkfen 		if (exts[i] == NULL) {
22454235Smarkfen 			printf("skipped %d\n", i);
22464235Smarkfen 			continue;
22474235Smarkfen 		}
22484235Smarkfen 
22494235Smarkfen 		switch (i) {
22504235Smarkfen 		case SPD_EXT_TUN_NAME:
22514235Smarkfen 			spd_if = (spd_if_t *)exts[i];
22524235Smarkfen 			(void) printf("spd_if = %s\n", spd_if->spd_if_name);
22534235Smarkfen 			break;
22544235Smarkfen 
22554235Smarkfen 		case SPD_EXT_ICMP_TYPECODE:
22564235Smarkfen 			spd_typecode = (struct spd_typecode *)exts[i];
22574235Smarkfen 			(void) printf("icmp type %d-%d code %d-%d\n",
22584235Smarkfen 			    spd_typecode->spd_typecode_type,
22594235Smarkfen 			    spd_typecode->spd_typecode_type_end,
22604235Smarkfen 			    spd_typecode->spd_typecode_code,
22614235Smarkfen 			    spd_typecode->spd_typecode_code_end);
22624235Smarkfen 			break;
22634235Smarkfen 
22644235Smarkfen 		case SPD_EXT_LCLPORT:
22654235Smarkfen 			spd_portrange = (struct spd_portrange *)exts[i];
22664235Smarkfen 			(void) printf("local ports %d-%d\n",
22674235Smarkfen 			    spd_portrange->spd_ports_minport,
22684235Smarkfen 			    spd_portrange->spd_ports_maxport);
22694235Smarkfen 
22704235Smarkfen 			break;
22714235Smarkfen 
22724235Smarkfen 		case SPD_EXT_REMPORT:
22734235Smarkfen 			spd_portrange = (struct spd_portrange *)exts[i];
22744235Smarkfen 			(void) printf("remote ports %d-%d\n",
22754235Smarkfen 			    spd_portrange->spd_ports_minport,
22764235Smarkfen 			    spd_portrange->spd_ports_maxport);
22774235Smarkfen 
22784235Smarkfen 			break;
22794235Smarkfen 
22804235Smarkfen 		case SPD_EXT_PROTO:
22814235Smarkfen 			spd_proto = (struct spd_proto *)exts[i];
22824235Smarkfen 			(void) printf("proto:spd_proto_exttype %d\n",
22834235Smarkfen 			    spd_proto->spd_proto_exttype);
22844235Smarkfen 			(void) printf("proto:spd_proto_number %d\n",
22854235Smarkfen 			    spd_proto->spd_proto_number);
22864235Smarkfen 			break;
22874235Smarkfen 
22884235Smarkfen 		case SPD_EXT_LCLADDR:
22894235Smarkfen 		case SPD_EXT_REMADDR:
22904235Smarkfen 			spd_address = (spd_address_t *)exts[i];
22914235Smarkfen 			if (i == SPD_EXT_LCLADDR)
22924235Smarkfen 				(void) printf("local addr ");
22934235Smarkfen 			else
22944235Smarkfen 				(void) printf("remote addr ");
22954235Smarkfen 
22964235Smarkfen 
22974235Smarkfen 			(void) printf("%s\n",
22984235Smarkfen 			    inet_ntop(spd_address->spd_address_af,
22995120Smarkfen 			    (void *) (spd_address +1), abuf,
23005120Smarkfen 			    INET6_ADDRSTRLEN));
23014235Smarkfen 
23024235Smarkfen 			(void) printf("prefixlen: %d\n",
23034235Smarkfen 			    spd_address->spd_address_prefixlen);
23044235Smarkfen 			break;
23054235Smarkfen 
23064235Smarkfen 		case SPD_EXT_ACTION:
23074235Smarkfen 			spd_ext_actions = (struct spd_ext_actions *)exts[i];
23084235Smarkfen 			(void) printf("spd_ext_action\n");
23094235Smarkfen 			(void) printf("spd_actions_count %d\n",
23104235Smarkfen 			    spd_ext_actions->spd_actions_count);
23114235Smarkfen 			app = (struct spd_attribute *)(spd_ext_actions + 1);
23124235Smarkfen 
23134235Smarkfen 			for (act_count = 0;
23144235Smarkfen 			    act_count < spd_ext_actions->spd_actions_len -1;
23154235Smarkfen 			    act_count++) {
23164235Smarkfen 				(void) printf("\tattr %d: %X-%d\n", act_count,
23174235Smarkfen 				    app->spd_attr_tag, app->spd_attr_value);
23184235Smarkfen 				app++;
23194235Smarkfen 			}
23204235Smarkfen 
23214235Smarkfen 			break;
23224235Smarkfen 
23234235Smarkfen 		case SPD_EXT_RULE:
23244235Smarkfen 			spd_rule = (struct spd_rule *)exts[i];
23254235Smarkfen 			(void) printf("spd_rule_priority: 0x%x\n",
23264235Smarkfen 			    spd_rule->spd_rule_priority);
23274235Smarkfen 			(void) printf("spd_rule_flags: %d\n",
23284235Smarkfen 			    spd_rule->spd_rule_flags);
23294235Smarkfen 			break;
23304235Smarkfen 
23314235Smarkfen 		case SPD_EXT_RULESET:
23324235Smarkfen 			(void) printf("spd_ext_ruleset\n");
23334235Smarkfen 			break;
23344235Smarkfen 		default:
23354235Smarkfen 			(void) printf("default\n");
23364235Smarkfen 			break;
23374235Smarkfen 		}
23384235Smarkfen 	}
23394235Smarkfen 
23404235Smarkfen 	(void) printf("-------------------\n");
23414235Smarkfen 	(void) printf("=========================\n");
23424235Smarkfen }
23434235Smarkfen #endif /* DEBUG_HEAVY */
23444235Smarkfen 
23454235Smarkfen static int
23464235Smarkfen ipsec_conf_view()
23474235Smarkfen {
23484235Smarkfen 	char buf[MAXLEN];
23494235Smarkfen 	FILE *fp;
23504235Smarkfen 
23514235Smarkfen 	fp = fopen(POLICY_CONF_FILE, "r");
23524235Smarkfen 	if (fp == NULL) {
23534235Smarkfen 		if (errno == ENOENT) {
23544235Smarkfen 			/*
23554235Smarkfen 			 * The absence of POLICY_CONF_FILE should
23564235Smarkfen 			 * not cause the command to exit with a
23574235Smarkfen 			 * non-zero status, since this condition
23584235Smarkfen 			 * is valid when no policies were previously
23594235Smarkfen 			 * defined.
23604235Smarkfen 			 */
23614235Smarkfen 			return (0);
23624235Smarkfen 		}
23634235Smarkfen 		warn(gettext("%s cannot be opened"), POLICY_CONF_FILE);
23644235Smarkfen 		return (-1);
23654235Smarkfen 	}
23664235Smarkfen 	while (fgets(buf, MAXLEN, fp) != NULL) {
23674235Smarkfen 		/* Don't print removed entries */
23684235Smarkfen 		if (*buf == ';')
23694235Smarkfen 			continue;
23704235Smarkfen 		if (strlen(buf) != 0)
23714235Smarkfen 			buf[strlen(buf) - 1] = '\0';
23724235Smarkfen 		(void) puts(buf);
23734235Smarkfen 	}
23744235Smarkfen 	return (0);
23754235Smarkfen }
23764235Smarkfen 
23774235Smarkfen /*
23784235Smarkfen  * Delete nlines from start in the POLICY_CONF_FILE.
23794235Smarkfen  */
23804235Smarkfen static int
23814235Smarkfen delete_from_file(int start, int nlines)
23824235Smarkfen {
23834235Smarkfen 	FILE *fp;
23844235Smarkfen 	char ibuf[MAXLEN];
23854235Smarkfen 	int len;
23864235Smarkfen 
23874235Smarkfen 	if ((fp = fopen(POLICY_CONF_FILE, "r+b")) == NULL) {
23884235Smarkfen 		warn(gettext("%s cannot be opened"), POLICY_CONF_FILE);
23894235Smarkfen 		return (-1);
23904235Smarkfen 	}
23914235Smarkfen 
23924235Smarkfen 	/*
23934235Smarkfen 	 * Insert a ";", read the line and discard it. Repeat
23944235Smarkfen 	 * this logic nlines - 1 times. For the last line there
23954235Smarkfen 	 * is just a newline character. We can't just insert a
23964235Smarkfen 	 * single ";" character instead of the newline character
23974235Smarkfen 	 * as it would affect the next line. Thus when we comment
23984235Smarkfen 	 * the last line we seek one less and insert a ";"
23994235Smarkfen 	 * character, which will replace the newline of the
24004235Smarkfen 	 * penultimate line with ; and newline of the last line
24014235Smarkfen 	 * will become part of the previous line.
24024235Smarkfen 	 */
24034235Smarkfen 	do {
24044235Smarkfen 		/*
24054235Smarkfen 		 * It is not enough to seek just once and expect the
24064235Smarkfen 		 * subsequent fgets below to take you to the right
24074235Smarkfen 		 * offset of the next line. fgets below seems to affect
24084235Smarkfen 		 * the offset. Thus we need to seek, replace with ";",
24094235Smarkfen 		 * and discard a line using fgets for every line.
24104235Smarkfen 		 */
24114235Smarkfen 		if (fseek(fp, start, SEEK_SET) == -1) {
24124235Smarkfen 			warn("fseek");
24134235Smarkfen 			return (-1);
24144235Smarkfen 		}
24154235Smarkfen 		if (fputc(';', fp) < 0) {
24164235Smarkfen 			warn("fputc");
24174235Smarkfen 			return (-1);
24184235Smarkfen 		}
24194235Smarkfen 		/*
24204235Smarkfen 		 * Flush the above ";" character before we do the fgets().
24214235Smarkfen 		 * Without this, fgets() gets confused with offsets.
24224235Smarkfen 		 */
24234235Smarkfen 		(void) fflush(fp);
24244235Smarkfen 		len = 0;
24254235Smarkfen 		while (fgets(ibuf, MAXLEN, fp) != NULL) {
24264235Smarkfen 			len += strlen(ibuf);
24274235Smarkfen 			if (ibuf[len - 1] == '\n') {
24284235Smarkfen 				/*
24294235Smarkfen 				 * We have read a complete line.
24304235Smarkfen 				 */
24314235Smarkfen 				break;
24324235Smarkfen 			}
24334235Smarkfen 		}
24344235Smarkfen 		/*
24354235Smarkfen 		 * We read the line after ";" character has been inserted.
24364235Smarkfen 		 * Thus len does not count ";". To advance to the next line
24374235Smarkfen 		 * increment by 1.
24384235Smarkfen 		 */
24394235Smarkfen 		start += (len + 1);
24404235Smarkfen 		/*
24414235Smarkfen 		 * If nlines == 2, we will be commenting out the last
24424235Smarkfen 		 * line next, which has only one newline character.
24434235Smarkfen 		 * If we blindly replace it with ";", it will  be
24444235Smarkfen 		 * read as part of the next line which could have
24454235Smarkfen 		 * a INDEX string and thus confusing ipsec_conf_view.
24464235Smarkfen 		 * Thus, we seek one less and replace the previous
24474235Smarkfen 		 * line's newline character with ";", and the
24484235Smarkfen 		 * last line's newline character will become part of
24494235Smarkfen 		 * the previous line.
24504235Smarkfen 		 */
24514235Smarkfen 		if (nlines == 2)
24524235Smarkfen 			start--;
24534235Smarkfen 	} while (--nlines != 0);
24544235Smarkfen 	(void) fclose(fp);
24554235Smarkfen 	if (nlines != 0)
24564235Smarkfen 		return (-1);
24574235Smarkfen 	else
24584235Smarkfen 		return (0);
24594235Smarkfen }
24604235Smarkfen 
24614235Smarkfen /*
24624235Smarkfen  * Delete an entry from the file by inserting a ";" at the
24634235Smarkfen  * beginning of the lines to be removed.
24644235Smarkfen  */
24654235Smarkfen static int
24664235Smarkfen ipsec_conf_del(int policy_index, boolean_t ignore_spd)
24674235Smarkfen {
24684235Smarkfen 	act_prop_t *act_props = malloc(sizeof (act_prop_t));
24694235Smarkfen 	char *buf;
24704235Smarkfen 	FILE *fp;
24714235Smarkfen 	char ibuf[MAXLEN];
24724235Smarkfen 	int ibuf_len, index_len, index;
24734235Smarkfen 	int ret = 0;
24744235Smarkfen 	int offset, prev_offset;
24754235Smarkfen 	int nlines;
24764235Smarkfen 	char lifname[LIFNAMSIZ];
24774235Smarkfen 
24784235Smarkfen 	if (act_props == NULL) {
24794235Smarkfen 		warn(gettext("memory"));
24804235Smarkfen 		return (-1);
24814235Smarkfen 	}
24824235Smarkfen 
24834235Smarkfen 	fp = fopen(POLICY_CONF_FILE, "r");
24844235Smarkfen 	if (fp == NULL) {
24854235Smarkfen 		warn(gettext("%s cannot be opened"), POLICY_CONF_FILE);
24864235Smarkfen 		free(act_props);
24874235Smarkfen 		return (-1);
24884235Smarkfen 	}
24894235Smarkfen 
24904235Smarkfen 	index_len = strlen(INDEX_TAG);
24914235Smarkfen 	index = 0;
24924235Smarkfen 	for (offset = prev_offset = 0; fgets(ibuf, MAXLEN, fp) != NULL;
24934235Smarkfen 	    offset += ibuf_len) {
24944235Smarkfen 		prev_offset = offset;
24954235Smarkfen 		ibuf_len = strlen(ibuf);
24964235Smarkfen 
24974235Smarkfen 		if (strncmp(ibuf, INDEX_TAG, index_len) != 0) {
24984235Smarkfen 			continue;
24994235Smarkfen 		}
25004235Smarkfen 
25014235Smarkfen 		/*
25024235Smarkfen 		 * This line contains INDEX_TAG
25034235Smarkfen 		 */
25044235Smarkfen 		buf = ibuf + index_len;
25054235Smarkfen 		buf++;			/* Skip the space */
25064235Smarkfen 		index = parse_index(buf, lifname);
25074235Smarkfen 		if (index == -1) {
25084235Smarkfen 			warnx(gettext("Invalid index in the file"));
25094235Smarkfen 			free(act_props);
25104235Smarkfen 			return (-1);
25114235Smarkfen 		}
25124235Smarkfen 		if (index == policy_index &&
25134235Smarkfen 		    (interface_name == NULL ||
25145120Smarkfen 		    strncmp(interface_name, lifname, LIFNAMSIZ) == 0)) {
25154235Smarkfen 			if (!ignore_spd) {
25164235Smarkfen 				ret = parse_one(fp, act_props);
25174235Smarkfen 				if (ret == -1) {
25184235Smarkfen 					warnx(gettext("Invalid policy entry "
25194235Smarkfen 					    "in the file"));
25204235Smarkfen 					free(act_props);
25214235Smarkfen 					return (-1);
25224235Smarkfen 				}
25234235Smarkfen 			}
25244235Smarkfen 			/*
25254235Smarkfen 			 * nlines is the number of lines we should comment
25264235Smarkfen 			 * out. linecount tells us how many lines this command
25274235Smarkfen 			 * spans. And we need to remove the line with INDEX
25284235Smarkfen 			 * and an extra line we added during ipsec_conf_add.
25294235Smarkfen 			 *
25304235Smarkfen 			 * NOTE : If somebody added a policy entry which does
25314235Smarkfen 			 * not have a newline, ipsec_conf_add() fills in the
25324235Smarkfen 			 * newline. Hence, there is always 2 extra lines
25334235Smarkfen 			 * to delete.
25344235Smarkfen 			 */
25354235Smarkfen 			nlines = linecount + 2;
25364235Smarkfen 			goto delete;
25374235Smarkfen 		}
25384235Smarkfen 	}
25394235Smarkfen 
25404235Smarkfen 	if (!ignore_spd)
25414235Smarkfen 		ret = pfp_delete_rule(policy_index);
25424235Smarkfen 
25434235Smarkfen 	if (ret != 0) {
25444235Smarkfen 		warnx(gettext("Deletion incomplete. Please "
25454235Smarkfen 		    "flush all the entries and re-configure :"));
25464235Smarkfen 		reconfigure();
25474235Smarkfen 		free(act_props);
25484235Smarkfen 		return (ret);
25494235Smarkfen 	}
25504235Smarkfen 	free(act_props);
25514235Smarkfen 	return (ret);
25524235Smarkfen 
25534235Smarkfen delete:
25544235Smarkfen 	/* Delete nlines from prev_offset */
25554235Smarkfen 	(void) fclose(fp);
25564235Smarkfen 	ret = delete_from_file(prev_offset, nlines);
25574235Smarkfen 
25584235Smarkfen 	if (ret != 0) {
25594235Smarkfen 		warnx(gettext("Deletion incomplete. Please "
25604235Smarkfen 		    "flush all the entries and re-configure :"));
25614235Smarkfen 		reconfigure();
25624235Smarkfen 		free(act_props);
25634235Smarkfen 		return (ret);
25644235Smarkfen 	}
25654235Smarkfen 
25664235Smarkfen 	if (!ignore_spd)
25674235Smarkfen 		ret = pfp_delete_rule(policy_index);
25684235Smarkfen 
25694235Smarkfen 	if (ret != 0) {
25704235Smarkfen 		warnx(gettext("Deletion incomplete. Please "
25714235Smarkfen 		    "flush all the entries and re-configure :"));
25724235Smarkfen 		reconfigure();
25734235Smarkfen 		free(act_props);
25744235Smarkfen 		return (ret);
25754235Smarkfen 	}
25764235Smarkfen 	free(act_props);
25774235Smarkfen 	return (0);
25784235Smarkfen }
25794235Smarkfen 
25804235Smarkfen static int
25814235Smarkfen pfp_delete_rule(uint64_t index)
25824235Smarkfen {
25834235Smarkfen 	struct spd_msg *msg;
25844235Smarkfen 	struct spd_rule *rule;
25854235Smarkfen 	int sfd;
25864235Smarkfen 	int cnt, len, alloclen;
25874235Smarkfen 
25884235Smarkfen 	sfd = get_pf_pol_socket();
25894235Smarkfen 	if (sfd < 0) {
25904235Smarkfen 		warn(gettext("unable to open policy socket"));
25914235Smarkfen 		return (-1);
25924235Smarkfen 	}
25934235Smarkfen 
25944235Smarkfen 	/*
25954235Smarkfen 	 * Add an extra 8 bytes of space (+1 uint64_t) to avoid truncation
25964235Smarkfen 	 * issues.
25974235Smarkfen 	 */
25984235Smarkfen 	alloclen = sizeof (spd_msg_t) + sizeof (struct spd_rule) +
25994235Smarkfen 	    sizeof (spd_if_t) + LIFNAMSIZ + 8;
26004235Smarkfen 	msg = (spd_msg_t *)malloc(alloclen);
26014235Smarkfen 
26024235Smarkfen 	if (msg == NULL) {
26034235Smarkfen 		warn("malloc");
26044235Smarkfen 		return (-1);
26054235Smarkfen 	}
26064235Smarkfen 
26074235Smarkfen 	rule = (struct spd_rule *)(msg + 1);
26084235Smarkfen 
26094235Smarkfen 	(void) memset(msg, 0, alloclen);
26104235Smarkfen 	msg->spd_msg_version = PF_POLICY_V1;
26114235Smarkfen 	msg->spd_msg_type = SPD_DELETERULE;
26124235Smarkfen 	msg->spd_msg_len = SPD_8TO64(sizeof (spd_msg_t)
26134235Smarkfen 	    + sizeof (struct spd_rule));
26144235Smarkfen 
26154235Smarkfen 	rule->spd_rule_type = SPD_EXT_RULE;
26164235Smarkfen 	rule->spd_rule_len = SPD_8TO64(sizeof (struct spd_rule));
26174235Smarkfen 	rule->spd_rule_index = index;
26184235Smarkfen 
26194235Smarkfen 	msg->spd_msg_len += attach_tunname((spd_if_t *)(rule + 1));
26204235Smarkfen 
26214235Smarkfen 	len = SPD_64TO8(msg->spd_msg_len);
26224235Smarkfen 	cnt = write(sfd, msg, len);
26234235Smarkfen 
26244235Smarkfen 	if (cnt != len) {
26254235Smarkfen 		if (cnt < 0) {
26264235Smarkfen 			(void) close(sfd);
26274235Smarkfen 			free(msg);
26284235Smarkfen 			warn(gettext("Delete failed: write"));
26294235Smarkfen 			return (-1);
26304235Smarkfen 		} else {
26314235Smarkfen 			(void) close(sfd);
26324235Smarkfen 			free(msg);
26334235Smarkfen 			warnx(gettext("Delete failed: short write"));
26344235Smarkfen 			return (-1);
26354235Smarkfen 		}
26364235Smarkfen 	}
26374235Smarkfen 
26384235Smarkfen 	cnt = read(sfd, msg, len);
26394235Smarkfen 	if (cnt != len) {
26404235Smarkfen 		if (cnt < 0) {
26414235Smarkfen 			(void) close(sfd);
26424235Smarkfen 			free(msg);
26434235Smarkfen 			warn(gettext("Delete failed: read"));
26444235Smarkfen 			return (-1);
26454235Smarkfen 		} else {
26464235Smarkfen 			(void) close(sfd);
26474235Smarkfen 			free(msg);
26484235Smarkfen 			warnx(gettext("Delete failed while reading reply"));
26494235Smarkfen 			return (-1);
26504235Smarkfen 		}
26514235Smarkfen 	}
26524235Smarkfen 	(void) close(sfd);
26534235Smarkfen 	if (msg->spd_msg_errno != 0) {
26544235Smarkfen 		free(msg);
26554235Smarkfen 		errno = msg->spd_msg_errno;
26564235Smarkfen 		warn(gettext("Delete failed: SPD_FLUSH"));
26574235Smarkfen 		return (-1);
26584235Smarkfen 	}
26594235Smarkfen 
26604235Smarkfen 	free(msg);
26614235Smarkfen 	return (0);
26624235Smarkfen }
26634235Smarkfen 
26644235Smarkfen static int
26654235Smarkfen ipsec_conf_flush(int db)
26664235Smarkfen {
26674235Smarkfen 	int pfd, cnt, len;
26684235Smarkfen 	int sfd;
26694235Smarkfen 	struct spd_msg *msg;
26704235Smarkfen 	/*
26714235Smarkfen 	 * Add an extra 8 bytes of space (+1 uint64_t) to avoid truncation
26724235Smarkfen 	 * issues.
26734235Smarkfen 	 */
26744235Smarkfen 	uint64_t buffer[
26754235Smarkfen 	    SPD_8TO64(sizeof (*msg) + sizeof (spd_if_t) + LIFNAMSIZ) + 1];
26764235Smarkfen 
26774235Smarkfen 	sfd = get_pf_pol_socket();
26784235Smarkfen 	if (sfd < 0) {
26794235Smarkfen 		warn(gettext("unable to open policy socket"));
26804235Smarkfen 		return (-1);
26814235Smarkfen 	}
26824235Smarkfen 
26834235Smarkfen 	(void) memset(buffer, 0, sizeof (buffer));
26844235Smarkfen 	msg = (struct spd_msg *)buffer;
26854235Smarkfen 	msg->spd_msg_version = PF_POLICY_V1;
26864235Smarkfen 	msg->spd_msg_type = SPD_FLUSH;
26874235Smarkfen 	msg->spd_msg_len = SPD_8TO64(sizeof (*msg));
26884235Smarkfen 	msg->spd_msg_spdid = db;
26894235Smarkfen 
26904235Smarkfen 	msg->spd_msg_len += attach_tunname((spd_if_t *)(msg + 1));
26914235Smarkfen 
26924235Smarkfen 	len = SPD_64TO8(msg->spd_msg_len);
26934235Smarkfen 	cnt = write(sfd, msg, len);
26944235Smarkfen 	if (cnt != len) {
26954235Smarkfen 		if (cnt < 0) {
26964235Smarkfen 			warn(gettext("Flush failed: write"));
26974235Smarkfen 			return (-1);
26984235Smarkfen 		} else {
26994235Smarkfen 			warnx(gettext("Flush failed: short write"));
27004235Smarkfen 			return (-1);
27014235Smarkfen 		}
27024235Smarkfen 	}
27034235Smarkfen 
27044235Smarkfen 	cnt = read(sfd, msg, len);
27054235Smarkfen 	if (cnt != len) {
27064235Smarkfen 		if (cnt < 0) {
27074235Smarkfen 			warn(gettext("Flush failed: read"));
27084235Smarkfen 			return (-1);
27094235Smarkfen 		} else {
27104235Smarkfen 			warnx(gettext("Flush failed while reading reply"));
27114235Smarkfen 			return (-1);
27124235Smarkfen 		}
27134235Smarkfen 	}
27144235Smarkfen 	(void) close(sfd);
27154235Smarkfen 	if (msg->spd_msg_errno != 0) {
27164235Smarkfen 		warnx("%s: %s", gettext("Flush failed: SPD_FLUSH"),
27174235Smarkfen 		    sys_error_message(msg->spd_msg_errno));
27184235Smarkfen 		return (-1);
27194235Smarkfen 	}
27204235Smarkfen 
27214235Smarkfen 	/* Truncate the file */
27224235Smarkfen 	if (db == SPD_ACTIVE) {
27234235Smarkfen 		if ((pfd = open(POLICY_CONF_FILE, O_TRUNC|O_RDWR)) == -1) {
27244235Smarkfen 			if (errno == ENOENT) {
27254235Smarkfen 				/*
27264235Smarkfen 				 * The absence of POLICY_CONF_FILE should
27274235Smarkfen 				 * not cause the command to exit with a
27284235Smarkfen 				 * non-zero status, since this condition
27294235Smarkfen 				 * is valid when no policies were previously
27304235Smarkfen 				 * defined.
27314235Smarkfen 				 */
27324235Smarkfen 				return (0);
27334235Smarkfen 			}
27344235Smarkfen 			warn(gettext("%s cannot be truncated"),
27354235Smarkfen 			    POLICY_CONF_FILE);
27364235Smarkfen 			return (-1);
27374235Smarkfen 		}
27384235Smarkfen 		(void) close(pfd);
27394235Smarkfen 	}
27404235Smarkfen 	return (0);
27414235Smarkfen }
27424235Smarkfen 
27434235Smarkfen /*
27444235Smarkfen  * function to send SPD_FLIP and SPD_CLONE messages
27454235Smarkfen  * Do it for ALL polheads for simplicity's sake.
27464235Smarkfen  */
27474235Smarkfen static void
27484235Smarkfen ipsec_conf_admin(uint8_t type)
27494235Smarkfen {
27504235Smarkfen 	int cnt;
27514235Smarkfen 	int sfd;
27524235Smarkfen 	struct spd_msg *msg;
27534235Smarkfen 	uint64_t buffer[
27544235Smarkfen 	    SPD_8TO64(sizeof (struct spd_msg) + sizeof (spd_if_t))];
27554235Smarkfen 	char *save_ifname;
27564235Smarkfen 
27574235Smarkfen 	sfd = get_pf_pol_socket();
27584235Smarkfen 	if (sfd < 0) {
27594235Smarkfen 		err(-1, gettext("unable to open policy socket"));
27604235Smarkfen 	}
27614235Smarkfen 
27624235Smarkfen 	(void) memset(buffer, 0, sizeof (buffer));
27634235Smarkfen 	msg = (struct spd_msg *)buffer;
27644235Smarkfen 	msg->spd_msg_version = PF_POLICY_V1;
27654235Smarkfen 	msg->spd_msg_type = type;
27664235Smarkfen 	msg->spd_msg_len = SPD_8TO64(sizeof (buffer));
27674235Smarkfen 
27684235Smarkfen 	save_ifname = interface_name;
27694235Smarkfen 	/* Apply to all policy heads - global and tunnels. */
27704235Smarkfen 	interface_name = &all_polheads;
27714235Smarkfen 	(void) attach_tunname((spd_if_t *)(msg + 1));
27724235Smarkfen 	interface_name = save_ifname;
27734235Smarkfen 
27744235Smarkfen 	cnt = write(sfd, msg, sizeof (buffer));
27754235Smarkfen 	if (cnt != sizeof (buffer)) {
27764235Smarkfen 		if (cnt < 0) {
27774235Smarkfen 			err(-1, gettext("admin failed: write"));
27784235Smarkfen 		} else {
27794235Smarkfen 			errx(-1, gettext("admin failed: short write"));
27804235Smarkfen 		}
27814235Smarkfen 	}
27824235Smarkfen 
27834235Smarkfen 	cnt = read(sfd, msg, sizeof (buffer));
27844235Smarkfen 	if (cnt != sizeof (buffer)) {
27854235Smarkfen 		if (cnt < 0) {
27864235Smarkfen 			err(-1, gettext("admin failed: read"));
27874235Smarkfen 		} else {
27884235Smarkfen 			errx(-1, gettext("admin failed while reading reply"));
27894235Smarkfen 		}
27904235Smarkfen 	}
27914235Smarkfen 	(void) close(sfd);
27924235Smarkfen 	if (msg->spd_msg_errno != 0) {
27934235Smarkfen 		errno = msg->spd_msg_errno;
27944235Smarkfen 		err(-1, gettext("admin failed"));
27954235Smarkfen 	}
27964235Smarkfen }
27974235Smarkfen 
27984235Smarkfen static void
27994235Smarkfen reconfigure()
28004235Smarkfen {
28014235Smarkfen 	(void) fprintf(stderr, gettext(
28025120Smarkfen 	    "\tipsecconf -f \n "
28035120Smarkfen 	    "\tipsecconf -a policy_file\n"));
28044235Smarkfen }
28054235Smarkfen 
28064235Smarkfen static void
28074235Smarkfen usage(void)
28084235Smarkfen {
28094235Smarkfen 	(void) fprintf(stderr, gettext(
28104235Smarkfen 	"Usage:	ipsecconf\n"
28114235Smarkfen 	"\tipsecconf -a ([-]|<filename>) [-q]\n"
28124235Smarkfen 	"\tipsecconf -c <filename>\n"
28134235Smarkfen 	"\tipsecconf -r ([-]|<filename>) [-q]\n"
28144235Smarkfen 	"\tipsecconf -d [-i tunnel-interface] <index>\n"
28154235Smarkfen 	"\tipsecconf -d <tunnel-interface,index>\n"
28164235Smarkfen 	"\tipsecconf -l [-n] [-i tunnel-interface]\n"
28174235Smarkfen 	"\tipsecconf -f [-i tunnel-interface]\n"
28184235Smarkfen 	"\tipsecconf -L [-n]\n"
28194235Smarkfen 	"\tipsecconf -F\n"));
28204235Smarkfen }
28214235Smarkfen 
28224235Smarkfen /*
28234235Smarkfen  * a type consists of
28244235Smarkfen  * "type" <int>{ "-" <int>}
28254235Smarkfen  * or
28264235Smarkfen  * "type" keyword
28274235Smarkfen  *
28284235Smarkfen  * a code consists of
28294235Smarkfen  * "code" <int>{ "-" <int>}
28304235Smarkfen  * or
28314235Smarkfen  * "code" keyword
28324235Smarkfen  */
28334235Smarkfen 
28344235Smarkfen 
28354235Smarkfen static int
28364235Smarkfen parse_type_code(const char *str, const str_val_t *table)
28374235Smarkfen {
28384235Smarkfen 	char *end1, *end2;
28394235Smarkfen 	int res1 = 0, res2 = 0;
28404235Smarkfen 	int i;
28414235Smarkfen 
28424235Smarkfen 	if (isdigit(str[0])) {
28434235Smarkfen 		res1 = strtol(str, &end1, 0);
28444235Smarkfen 
28454235Smarkfen 		if (end1 == str) {
28464235Smarkfen 			return (-1);
28474235Smarkfen 		}
28484235Smarkfen 
28494235Smarkfen 		if (res1 > 255 || res1 < 0) {
28504235Smarkfen 			return (-1);
28514235Smarkfen 		}
28524235Smarkfen 
28534235Smarkfen 		if (*end1 == '-') {
28544235Smarkfen 			end1++;
28554235Smarkfen 			res2 = strtol(end1, &end2, 0);
28564235Smarkfen 			if (res2 > 255 || res2 < 0) {
28574235Smarkfen 				return (-1);
28584235Smarkfen 			}
28594235Smarkfen 		} else {
28604235Smarkfen 			end2 = end1;
28614235Smarkfen 		}
28624235Smarkfen 
28634235Smarkfen 		while (isspace(*end2))
28644235Smarkfen 			end2++;
28654235Smarkfen 
28664235Smarkfen 		if (*end2 != '\0') {
28674235Smarkfen 			return (-1);
28684235Smarkfen 		}
28694235Smarkfen 
28704235Smarkfen 		return (res1 + (res2 << 8));
28714235Smarkfen 	}
28724235Smarkfen 
28734235Smarkfen 	for (i = 0; table[i].string; i++) {
28744235Smarkfen 		if (strcmp(str, table[i].string) == 0) {
28754235Smarkfen 			return (table[i].value);
28764235Smarkfen 		}
28774235Smarkfen 	}
28784235Smarkfen 
28794235Smarkfen 	return (-1);
28804235Smarkfen }
28814235Smarkfen 
28824235Smarkfen static int
28834235Smarkfen parse_int(const char *str)
28844235Smarkfen {
28854235Smarkfen 	char *end;
28864235Smarkfen 	int res;
28874235Smarkfen 
28884235Smarkfen 	res = strtol(str, &end, 0);
28894235Smarkfen 	if (end == str)
28904235Smarkfen 		return (-1);
28914235Smarkfen 	while (isspace(*end))
28924235Smarkfen 		end++;
28934235Smarkfen 	if (*end != '\0')
28944235Smarkfen 		return (-1);
28954235Smarkfen 	return (res);
28964235Smarkfen }
28974235Smarkfen 
28984235Smarkfen /*
28994235Smarkfen  * Parses <interface>,<index>.  Sets iname or the global interface_name (if
29004235Smarkfen  * iname == NULL) to <interface> and returns <index>.  Calls exit() if we have
29014235Smarkfen  * an interface_name already set.
29024235Smarkfen  */
29034235Smarkfen static int
29044235Smarkfen parse_index(const char *str, char *iname)
29054235Smarkfen {
29064235Smarkfen 	char *intf, *num, *copy;
29074235Smarkfen 	int rc;
29084235Smarkfen 
29094235Smarkfen 	copy = strdup(str);
29104235Smarkfen 	if (copy == NULL) {
29114235Smarkfen 		EXIT_FATAL("Out of memory.");
29124235Smarkfen 	}
29134235Smarkfen 
29144235Smarkfen 	intf = strtok(copy, ",");
29154235Smarkfen 	/* Just want the rest of the string unmolested, so use "" for arg2. */
29164235Smarkfen 	num = strtok(NULL, "");
29174235Smarkfen 	if (num == NULL) {
29184235Smarkfen 		/* No comma found, just parse it like an int. */
29194235Smarkfen 		free(copy);
29204235Smarkfen 		return (parse_int(str));
29214235Smarkfen 	}
29224235Smarkfen 
29234235Smarkfen 	if (iname != NULL) {
29244235Smarkfen 		(void) strlcpy(iname, intf, LIFNAMSIZ);
29254235Smarkfen 	} else {
29264235Smarkfen 		if (interface_name != NULL) {
29274235Smarkfen 			EXIT_FATAL("Interface name already selected");
29284235Smarkfen 		}
29294235Smarkfen 
29304235Smarkfen 		interface_name = strdup(intf);
29314235Smarkfen 		if (interface_name == NULL) {
29324235Smarkfen 			EXIT_FATAL("Out of memory.");
29334235Smarkfen 		}
29344235Smarkfen 	}
29354235Smarkfen 
29364235Smarkfen 	rc = parse_int(num);
29374235Smarkfen 	free(copy);
29384235Smarkfen 	return (rc);
29394235Smarkfen }
29404235Smarkfen 
29414235Smarkfen /*
29424235Smarkfen  * Convert a mask to a prefix length.
29434235Smarkfen  * Returns prefix length on success, -1 otherwise.
29444235Smarkfen  */
29454235Smarkfen static int
29464235Smarkfen in_getprefixlen(char *mask)
29474235Smarkfen {
29484235Smarkfen 	int prefixlen;
29494235Smarkfen 	char *end;
29504235Smarkfen 
29514235Smarkfen 	prefixlen = (int)strtol(mask, &end, 10);
29524235Smarkfen 	if (prefixlen < 0) {
29534235Smarkfen 		return (-1);
29544235Smarkfen 	}
29554235Smarkfen 	if (mask == end) {
29564235Smarkfen 		return (-1);
29574235Smarkfen 	}
29584235Smarkfen 	if (*end != '\0') {
29594235Smarkfen 		return (-1);
29604235Smarkfen 	}
29614235Smarkfen 	return (prefixlen);
29624235Smarkfen }
29634235Smarkfen 
29644235Smarkfen /*
29654235Smarkfen  * Convert a prefix length to a mask.
29664235Smarkfen  * Assumes the mask array is zero'ed by the caller.
29674235Smarkfen  */
29684235Smarkfen static void
29694235Smarkfen in_prefixlentomask(unsigned int prefixlen, uchar_t *mask)
29704235Smarkfen {
29714235Smarkfen 	while (prefixlen > 0) {
29724235Smarkfen 		if (prefixlen >= 8) {
29734235Smarkfen 			*mask++ = 0xFF;
29744235Smarkfen 			prefixlen -= 8;
29754235Smarkfen 			continue;
29764235Smarkfen 		}
29774235Smarkfen 		*mask |= 1 << (8 - prefixlen);
29784235Smarkfen 		prefixlen--;
29794235Smarkfen 	}
29804235Smarkfen }
29814235Smarkfen 
29824235Smarkfen 
29834235Smarkfen static int
29844235Smarkfen parse_address(int type, char *addr_str)
29854235Smarkfen {
29864235Smarkfen 	char *ptr;
29874235Smarkfen 	int prefix_len = 0;
29884235Smarkfen 	struct netent *ne = NULL;
29894235Smarkfen 	struct hostent *hp = NULL;
29904235Smarkfen 	int h_errno;
29914235Smarkfen 	struct in_addr netaddr;
29924235Smarkfen 	struct in6_addr *netaddr6;
29934235Smarkfen 	struct hostent *ne_hent;
29944235Smarkfen 	boolean_t	has_mask = B_FALSE;
29954235Smarkfen 
29964235Smarkfen 	ptr = strchr(addr_str, '/');
29974235Smarkfen 	if (ptr != NULL) {
29984235Smarkfen 		has_mask = B_TRUE;
29994235Smarkfen 		*ptr++ = NULL;
30004235Smarkfen 
30014235Smarkfen 		prefix_len = in_getprefixlen(ptr);
30024235Smarkfen 		if (prefix_len < 0)
30034235Smarkfen 			return (-1);
30044235Smarkfen 	}
30054235Smarkfen 
30064235Smarkfen 	/*
30074235Smarkfen 	 * getipnodebyname() is thread safe. This allows us to hold on to the
30084235Smarkfen 	 * returned hostent structure, which is pointed to by the shp and
30094235Smarkfen 	 * dhp globals for the source and destination addresses, respectively.
30104235Smarkfen 	 */
30114235Smarkfen 	hp = getipnodebyname(addr_str, AF_INET6, AI_DEFAULT | AI_ALL, &h_errno);
30124235Smarkfen 	if (hp != NULL) {
30134235Smarkfen 		/*
30144235Smarkfen 		 * We come here for both a hostname and
30154235Smarkfen 		 * any host address /network address.
30164235Smarkfen 		 */
30174235Smarkfen 		assert(hp->h_addrtype == AF_INET6);
30184235Smarkfen 	} else if ((ne = getnetbyname(addr_str)) != NULL) {
30194235Smarkfen 		switch (ne->n_addrtype) {
30204235Smarkfen 		case AF_INET:
30214235Smarkfen 			/*
30224235Smarkfen 			 * Allocate a struct hostent and initialize
30234235Smarkfen 			 * it with the address corresponding to the
30244235Smarkfen 			 * network number previously returned by
30254235Smarkfen 			 * getnetbyname(). Freed by do_address_adds()
30264235Smarkfen 			 * once the policy is defined.
30274235Smarkfen 			 */
30284235Smarkfen 			ne_hent = malloc(sizeof (struct hostent));
30294235Smarkfen 			if (ne_hent == NULL) {
30304235Smarkfen 				warn("malloc");
30314235Smarkfen 				return (-1);
30324235Smarkfen 			}
30334235Smarkfen 			ne_hent->h_addr_list = malloc(2*sizeof (char *));
30344235Smarkfen 			if (ne_hent->h_addr_list == NULL) {
30354235Smarkfen 				warn("malloc");
30364235Smarkfen 				free(ne_hent);
30374235Smarkfen 				return (-1);
30384235Smarkfen 			}
30394235Smarkfen 			netaddr6 = malloc(sizeof (struct in6_addr));
30404235Smarkfen 			if (netaddr6 == NULL) {
30414235Smarkfen 				warn("malloc");
30424235Smarkfen 				free(ne_hent->h_addr_list);
30434235Smarkfen 				free(ne_hent);
30444235Smarkfen 				return (-1);
30454235Smarkfen 			}
30464235Smarkfen 			ne_hent->h_addr_list[0] = (char *)netaddr6;
30474235Smarkfen 			ne_hent->h_addr_list[1] = NULL;
30484235Smarkfen 			netaddr = inet_makeaddr(ne->n_net, INADDR_ANY);
30494235Smarkfen 			IN6_INADDR_TO_V4MAPPED(&netaddr, netaddr6);
30504235Smarkfen 			hp = ne_hent;
30514235Smarkfen 			break;
30524235Smarkfen 		default:
30534235Smarkfen 			warnx("Address type %d not supported.", ne->n_addrtype);
30544235Smarkfen 			return (-1);
30554235Smarkfen 		}
30564235Smarkfen 	} else {
30574235Smarkfen 		return (-1);
30584235Smarkfen 	}
30594235Smarkfen 
30604235Smarkfen 	if (type == IPSEC_CONF_SRC_ADDRESS) {
30614235Smarkfen 		shp = hp;
30624235Smarkfen 		if (has_mask)
30634235Smarkfen 			splen = prefix_len;
30644235Smarkfen 		has_saprefix = has_mask;
30654235Smarkfen 	} else {
30664235Smarkfen 		dhp = hp;
30674235Smarkfen 		if (has_mask)
30684235Smarkfen 			dplen = prefix_len;
30694235Smarkfen 		has_daprefix = has_mask;
30704235Smarkfen 	}
30714235Smarkfen 
30724235Smarkfen 	return (0);
30734235Smarkfen }
30744235Smarkfen 
30754235Smarkfen /*
30764235Smarkfen  * Add port-only entries.  Make sure to add them in both the V6 and V4 tables!
30774235Smarkfen  */
30784235Smarkfen static int
30794235Smarkfen do_port_adds(ips_conf_t *cptr)
30804235Smarkfen {
30814235Smarkfen 	int ret, diag;
30824235Smarkfen 
30834235Smarkfen 	assert(IN6_IS_ADDR_UNSPECIFIED(&cptr->ips_src_addr_v6));
30844235Smarkfen 	assert(IN6_IS_ADDR_UNSPECIFIED(&cptr->ips_dst_addr_v6));
30854235Smarkfen 
30864235Smarkfen #ifdef DEBUG_HEAVY
30874235Smarkfen 	(void) dump_conf(cptr);
30884235Smarkfen #endif
30894235Smarkfen 
30904235Smarkfen 	ret = send_pf_pol_message(SPD_ADDRULE, cptr, &diag);
30914235Smarkfen 	if (ret != 0 && !ipsecconf_qflag) {
30924235Smarkfen 		warnx(
30934235Smarkfen 		    gettext("Could not add IPv4 policy for sport %d, dport %d "
30945120Smarkfen 		    "- diagnostic %d - %s"), ntohs(cptr->ips_src_port_min),
30954235Smarkfen 		    ntohs(cptr->ips_dst_port_min), diag, spdsock_diag(diag));
30964235Smarkfen 	}
30974235Smarkfen 
30984235Smarkfen 	return (ret);
30994235Smarkfen }
31004235Smarkfen 
31014235Smarkfen /*
31024235Smarkfen  * Nuke a list of policy entries.
31034235Smarkfen  * rewrite this to use flipping
31044235Smarkfen  * d_list isn't freed because we will be
31054235Smarkfen  * exiting the program soon.
31064235Smarkfen  */
31074235Smarkfen static void
31084235Smarkfen nuke_adds()
31094235Smarkfen {
31104235Smarkfen 	d_list_t *temp = d_list;
31114235Smarkfen 	FILE *policy_fp;
31124235Smarkfen 
31134235Smarkfen 	policy_fp = fopen(POLICY_CONF_FILE, "a");
31144235Smarkfen 	if (policy_fp == NULL) {
31154235Smarkfen 		warn(gettext("%s cannot be opened"), POLICY_CONF_FILE);
31165494Spwernau 	} else {
31175494Spwernau 		(void) fprintf(policy_fp, "\n\n");
31185494Spwernau 		(void) fflush(policy_fp);
31194235Smarkfen 	}
31204235Smarkfen 
31214235Smarkfen 	while (temp != NULL) {
31224235Smarkfen 		(void) ipsec_conf_del(temp->index, B_TRUE);
31234235Smarkfen 		temp = temp->next;
31244235Smarkfen 	}
31254235Smarkfen }
31264235Smarkfen 
31274235Smarkfen /*
31284235Smarkfen  * Set mask info from the specified prefix len. Fail if multihomed.
31294235Smarkfen  */
31304235Smarkfen static int
31314235Smarkfen set_mask_info(struct hostent *hp, unsigned int plen, struct in6_addr *mask_v6)
31324235Smarkfen {
31334235Smarkfen 	struct in6_addr addr;
31344235Smarkfen 	struct in_addr mask_v4;
31354235Smarkfen 
31364235Smarkfen 	if (hp->h_addr_list[1] != NULL) {
31374235Smarkfen 		return (EOPNOTSUPP);
31384235Smarkfen 	}
31394235Smarkfen 
31404235Smarkfen 	if (!IN6_IS_ADDR_UNSPECIFIED(mask_v6)) {
31414235Smarkfen 		return (EBUSY);
31424235Smarkfen 	}
31434235Smarkfen 
31444235Smarkfen 	bcopy(hp->h_addr_list[0], &addr, sizeof (struct in6_addr));
31454235Smarkfen 	if (IN6_IS_ADDR_V4MAPPED(&addr)) {
31464235Smarkfen 		if (plen > IP_ABITS) {
31474235Smarkfen 			return (ERANGE);
31484235Smarkfen 		}
31494235Smarkfen 		(void) memset(&mask_v4, 0, sizeof (mask_v4));
31504235Smarkfen 		in_prefixlentomask(plen, (uchar_t *)&mask_v4);
31514235Smarkfen 		IN6_INADDR_TO_V4MAPPED(&mask_v4, mask_v6);
31524235Smarkfen 	} else {
31534235Smarkfen 		if (plen > IPV6_ABITS) {
31544235Smarkfen 			return (ERANGE);
31554235Smarkfen 		}
31564235Smarkfen 		/* mask_v6 is already zero (unspecified), see test above */
31574235Smarkfen 		in_prefixlentomask(plen, (uchar_t *)mask_v6);
31584235Smarkfen 	}
31594235Smarkfen 	return (0);
31604235Smarkfen }
31614235Smarkfen 
31624235Smarkfen /*
31634235Smarkfen  * Initialize the specified IPv6 address with all f's.
31644235Smarkfen  */
31654235Smarkfen static void
31664235Smarkfen init_addr_wildcard(struct in6_addr *addr_v6, boolean_t isv4)
31674235Smarkfen {
31684235Smarkfen 	if (isv4) {
31694235Smarkfen 		uint32_t addr_v4 = 0xffffffff;
31704235Smarkfen 		IN6_INADDR_TO_V4MAPPED((struct in_addr *)&addr_v4, addr_v6);
31714235Smarkfen 	} else {
31724235Smarkfen 		(void) memset(addr_v6, 0xff, sizeof (struct in6_addr));
31734235Smarkfen 	}
31744235Smarkfen }
31754235Smarkfen 
31764235Smarkfen /*
31774235Smarkfen  * Called at the end to actually add policy.  Handles single and multi-homed
31784235Smarkfen  * cases.
31794235Smarkfen  */
31804235Smarkfen static int
31814235Smarkfen do_address_adds(ips_conf_t *cptr, int *diag)
31824235Smarkfen {
31834235Smarkfen 	int i, j;
31844235Smarkfen 	int ret = 0;	/* For ioctl() call. */
31854235Smarkfen 	int rc = 0;	/* My own return code. */
31864235Smarkfen 	struct in6_addr zeroes = {0, 0, 0, 0};
31874235Smarkfen 	char *ptr[2];
31884235Smarkfen 	struct hostent hent;
31894235Smarkfen 	boolean_t isv4;
31904235Smarkfen 	int add_count = 0;
31914235Smarkfen 
31924235Smarkfen 	/*
31934235Smarkfen 	 * dst_hent may not be initialized if a destination
31944235Smarkfen 	 * address was not given. It will be initalized with just
31954235Smarkfen 	 * one address if a destination address was given. In both
31964235Smarkfen 	 * the cases, we initialize here with ipsc_dst_addr and enter
31974235Smarkfen 	 * the loop below.
31984235Smarkfen 	 */
31994235Smarkfen 	if (dhp == NULL) {
32004235Smarkfen 		assert(shp != NULL);
32014235Smarkfen 		hent.h_addr_list = ptr;
32024235Smarkfen 		ptr[0] = (char *)&zeroes.s6_addr;
32034235Smarkfen 		ptr[1] = NULL;
32044235Smarkfen 		dhp = &hent;
32054235Smarkfen 	} else if (shp == NULL) {
32064235Smarkfen 		assert(dhp != NULL);
32074235Smarkfen 		hent.h_addr_list = ptr;
32084235Smarkfen 		ptr[0] = (char *)&zeroes.s6_addr;
32094235Smarkfen 		ptr[1] = NULL;
32104235Smarkfen 		shp = &hent;
32114235Smarkfen 	}
32124235Smarkfen 
32134235Smarkfen 	/*
32144235Smarkfen 	 * Set mask info here.  Bail if multihomed and there's a prefix len.
32154235Smarkfen 	 */
32164235Smarkfen 	if (has_saprefix) {
32174235Smarkfen 		rc = set_mask_info(shp, splen, &cptr->ips_src_mask_v6);
32184235Smarkfen 		if (rc != 0)
32194235Smarkfen 			goto bail;
32204235Smarkfen 		cptr->ips_src_mask_len = splen;
32214235Smarkfen 	}
32224235Smarkfen 
32234235Smarkfen 	if (has_daprefix) {
32244235Smarkfen 		rc = set_mask_info(dhp, dplen, &cptr->ips_dst_mask_v6);
32254235Smarkfen 		if (rc != 0)
32264235Smarkfen 			goto bail;
32274235Smarkfen 		cptr->ips_dst_mask_len = dplen;
32284235Smarkfen 	}
32294235Smarkfen 
32304235Smarkfen 	for (i = 0; shp->h_addr_list[i] != NULL; i++) {
32314235Smarkfen 		bcopy(shp->h_addr_list[i], &cptr->ips_src_addr_v6,
32324235Smarkfen 		    sizeof (struct in6_addr));
32334235Smarkfen 		isv4 = cptr->ips_isv4 =
32344235Smarkfen 		    IN6_IS_ADDR_V4MAPPED(&cptr->ips_src_addr_v6);
32354235Smarkfen 		if (IN6_IS_ADDR_UNSPECIFIED(&cptr->ips_src_mask_v6) &&
32364235Smarkfen 		    shp != &hent) {
32374235Smarkfen 			init_addr_wildcard(&cptr->ips_src_mask_v6, isv4);
32384235Smarkfen 		}
32394235Smarkfen 
32404235Smarkfen 		for (j = 0; dhp->h_addr_list[j] != NULL; j++) {
32414235Smarkfen 			bcopy(dhp->h_addr_list[j], &cptr->ips_dst_addr_v6,
32424235Smarkfen 			    sizeof (struct in6_addr));
32434235Smarkfen 			if (IN6_IS_ADDR_UNSPECIFIED(&cptr->ips_src_addr_v6)) {
32444235Smarkfen 				/*
32454235Smarkfen 				 * Src was not specified, so update isv4 flag
32464235Smarkfen 				 * for this policy according to the family
32474235Smarkfen 				 * of the destination address.
32484235Smarkfen 				 */
32494235Smarkfen 				isv4 = cptr->ips_isv4 =
32504235Smarkfen 				    IN6_IS_ADDR_V4MAPPED(
32515120Smarkfen 				    &cptr->ips_dst_addr_v6);
32524235Smarkfen 			} else if ((dhp != &hent) && (isv4 !=
32534235Smarkfen 			    IN6_IS_ADDR_V4MAPPED(&cptr->ips_dst_addr_v6))) {
32544235Smarkfen 				/* v6/v4 mismatch. */
32554235Smarkfen 				continue;
32564235Smarkfen 			}
32574235Smarkfen 			if (IN6_IS_ADDR_UNSPECIFIED(&cptr->ips_dst_mask_v6) &&
32584235Smarkfen 			    dhp != &hent) {
32594235Smarkfen 				init_addr_wildcard(&cptr->ips_dst_mask_v6,
32604235Smarkfen 				    isv4);
32614235Smarkfen 			}
32624235Smarkfen 
32634235Smarkfen 			ret = send_pf_pol_message(SPD_ADDRULE, cptr, diag);
32644235Smarkfen 
32654235Smarkfen 			if (ret == 0) {
32664235Smarkfen 				add_count++;
32674235Smarkfen 			} else {
32684235Smarkfen 				/* For now, allow duplicate/overlap policies. */
32694235Smarkfen 				if (ret != EEXIST) {
32704235Smarkfen 					/*
32714235Smarkfen 					 * We have an error where we added
32724235Smarkfen 					 * some, but had errors with others.
32734235Smarkfen 					 * Undo the previous adds, and
32744235Smarkfen 					 * bail.
32754235Smarkfen 					 */
32764235Smarkfen 					rc = ret;
32774235Smarkfen 					goto bail;
32784235Smarkfen 				}
32794235Smarkfen 			}
32804235Smarkfen 
32814235Smarkfen 			bzero(&cptr->ips_dst_mask_v6,
32824235Smarkfen 			    sizeof (struct in6_addr));
32834235Smarkfen 		}
32844235Smarkfen 
32854235Smarkfen 		bzero(&cptr->ips_src_mask_v6, sizeof (struct in6_addr));
32864235Smarkfen 	}
32874235Smarkfen 
32884235Smarkfen bail:
32894235Smarkfen 	if (shp != &hent)
32904235Smarkfen 		freehostent(shp);
32914235Smarkfen 	shp = NULL;
32924235Smarkfen 	if (dhp != &hent)
32934235Smarkfen 		freehostent(dhp);
32944235Smarkfen 	dhp = NULL;
32954235Smarkfen 	splen = 0;
32964235Smarkfen 	dplen = 0;
32974235Smarkfen 
32984235Smarkfen 	if ((add_count == 0) && (rc == 0)) {
32994235Smarkfen 		/*
33004235Smarkfen 		 * No entries were added. We failed all adds
33014235Smarkfen 		 * because the entries already existed, or because
33024235Smarkfen 		 * no v4 or v6 src/dst pairs were found. Either way,
33034235Smarkfen 		 * we must fail here with an appropriate error
33044235Smarkfen 		 * to avoid a corresponding entry from being added
33054235Smarkfen 		 * to ipsecpolicy.conf.
33064235Smarkfen 		 */
33074235Smarkfen 		if ((ret == EEXIST)) {
33084235Smarkfen 			/* All adds failed with EEXIST */
33094235Smarkfen 			rc = EEXIST;
33104235Smarkfen 		} else {
33114235Smarkfen 			/* No matching v4 or v6 src/dst pairs */
33124235Smarkfen 			rc = ESRCH;
33134235Smarkfen 		}
33144235Smarkfen 	}
33154235Smarkfen 
33164235Smarkfen 	return (rc);
33174235Smarkfen }
33184235Smarkfen 
33194235Smarkfen static int
33204235Smarkfen parse_mask(int type, char *mask_str, ips_conf_t *cptr)
33214235Smarkfen {
33224235Smarkfen 	struct in_addr mask;
33234235Smarkfen 	struct in6_addr *mask6;
33244235Smarkfen 
33254235Smarkfen 	if (type == IPSEC_CONF_SRC_MASK) {
33264235Smarkfen 		mask6 = &cptr->ips_src_mask_v6;
33274235Smarkfen 	} else {
33284235Smarkfen 		mask6 = &cptr->ips_dst_mask_v6;
33294235Smarkfen 	}
33304235Smarkfen 
33314235Smarkfen 	if ((strncasecmp(mask_str, "0x", 2) == 0) &&
33324235Smarkfen 	    (strchr(mask_str, '.') == NULL)) {
33334235Smarkfen 		/* Is it in the form 0xff000000 ? */
33344235Smarkfen 		char *end;
33354235Smarkfen 
33364235Smarkfen 		mask.s_addr = strtoul(mask_str, &end, 0);
33374235Smarkfen 		if (end == mask_str) {
33384235Smarkfen 			return (-1);
33394235Smarkfen 		}
33404235Smarkfen 		if (*end != '\0') {
33414235Smarkfen 			return (-1);
33424235Smarkfen 		}
33434235Smarkfen 		mask.s_addr = htonl(mask.s_addr);
33444235Smarkfen 	} else {
33454235Smarkfen 		/*
33464235Smarkfen 		 * Since inet_addr() returns -1 on error, we have
33474235Smarkfen 		 * to convert a broadcast address ourselves.
33484235Smarkfen 		 */
33494235Smarkfen 		if (strcmp(mask_str, "255.255.255.255") == 0) {
33504235Smarkfen 			mask.s_addr = 0xffffffff;
33514235Smarkfen 		} else {
33524235Smarkfen 			mask.s_addr = inet_addr(mask_str);
33534235Smarkfen 			if (mask.s_addr == (unsigned int)-1)
33544235Smarkfen 				return (-1);
33554235Smarkfen 		}
33564235Smarkfen 	}
33574235Smarkfen 
33584235Smarkfen 	/* Should we check for non-contiguous masks ? */
33594235Smarkfen 	if (mask.s_addr == 0)
33604235Smarkfen 		return (-1);
33614235Smarkfen 	IN6_INADDR_TO_V4MAPPED(&mask, mask6);
33624235Smarkfen 
33634235Smarkfen 
33644235Smarkfen 	if (type == IPSEC_CONF_SRC_MASK) {
33654235Smarkfen 		cptr->ips_src_mask_len = in_masktoprefix(mask6->s6_addr,
33664235Smarkfen 		    B_TRUE);
33674235Smarkfen 	} else {
33684235Smarkfen 		cptr->ips_dst_mask_len = in_masktoprefix(mask6->s6_addr,
33694235Smarkfen 		    B_TRUE);
33704235Smarkfen 	}
33714235Smarkfen 
33724235Smarkfen 	return (0);
33734235Smarkfen }
33744235Smarkfen 
33754235Smarkfen static int
33764235Smarkfen parse_port(int type, char *port_str, ips_conf_t *conf)
33774235Smarkfen {
33784235Smarkfen 	struct servent *sent;
33794235Smarkfen 	in_port_t port;
33804235Smarkfen 	int ret;
33814235Smarkfen 
33824235Smarkfen 	sent = getservbyname(port_str, NULL);
33834235Smarkfen 	if (sent == NULL) {
33844235Smarkfen 		ret = parse_int(port_str);
33854235Smarkfen 		if (ret < 0 || ret >= 65536) {
33864235Smarkfen 			return (-1);
33874235Smarkfen 		}
33884235Smarkfen 		port = htons((in_port_t)ret);
33894235Smarkfen 	} else {
33904235Smarkfen 		port = sent->s_port;
33914235Smarkfen 	}
33924235Smarkfen 	if (type == IPSEC_CONF_SRC_PORT) {
33934235Smarkfen 		conf->ips_src_port_min = conf->ips_src_port_max = port;
33944235Smarkfen 	} else {
33954235Smarkfen 		conf->ips_dst_port_min = conf->ips_dst_port_max = port;
33964235Smarkfen 	}
33974235Smarkfen 	return (0);
33984235Smarkfen }
33994235Smarkfen 
34004235Smarkfen static int
34014235Smarkfen valid_algorithm(int proto_num, const char *str)
34024235Smarkfen {
34034235Smarkfen 	const char *tmp;
34044235Smarkfen 	int ret;
34054235Smarkfen 	struct ipsecalgent *alg;
34064235Smarkfen 
34074235Smarkfen 	/* Short-circuit "none" */
34084235Smarkfen 	if (strncasecmp("none", str, 5) == 0)
34094235Smarkfen 		return (-2);
34104235Smarkfen 
34114235Smarkfen 	alg = getipsecalgbyname(str, proto_num, NULL);
34124235Smarkfen 	if (alg != NULL) {
34134235Smarkfen 		ret = alg->a_alg_num;
34144235Smarkfen 		freeipsecalgent(alg);
34154235Smarkfen 		return (ret);
34164235Smarkfen 	}
34174235Smarkfen 
34184235Smarkfen 	/*
34194235Smarkfen 	 * Look whether it could be a valid number.
34204235Smarkfen 	 * We support numbers also so that users can
34214235Smarkfen 	 * load algorithms as they need it. We can't
34224235Smarkfen 	 * check for validity of numbers here. It will
34234235Smarkfen 	 * be checked when the SA is negotiated/looked up.
34244235Smarkfen 	 * parse_int uses strtol(str), which converts 3DES
34254235Smarkfen 	 * to a valid number i.e looks only at initial
34264235Smarkfen 	 * number part. If we come here we should expect
34274235Smarkfen 	 * only a decimal number.
34284235Smarkfen 	 */
34294235Smarkfen 	tmp = str;
34304235Smarkfen 	while (*tmp) {
34314235Smarkfen 		if (!isdigit(*tmp))
34324235Smarkfen 			return (-1);
34334235Smarkfen 		tmp++;
34344235Smarkfen 	}
34354235Smarkfen 
34364235Smarkfen 	ret = parse_int(str);
34374235Smarkfen 	if (ret > 0 && ret <= 255)
34384235Smarkfen 		return (ret);
34394235Smarkfen 	else
34404235Smarkfen 		return (-1);
34414235Smarkfen }
34424235Smarkfen 
34434235Smarkfen static int
34444235Smarkfen parse_ipsec_alg(char *str, ips_act_props_t *iap, int alg_type)
34454235Smarkfen {
34464235Smarkfen 	int alg_value;
34474235Smarkfen 	char tstr[VALID_ALG_LEN];
34484235Smarkfen 	char *lens = NULL;
34494235Smarkfen 	char *l1_str;
34504235Smarkfen 	int l1 = 0;
34514235Smarkfen 	char *l2_str;
34524235Smarkfen 	int l2 = SPD_MAX_MAXBITS;
34534235Smarkfen 	algreq_t *ap;
34544235Smarkfen 	uint_t a_type;
34554235Smarkfen 
34564235Smarkfen 	fetch_algorithms();
34574235Smarkfen 
34584235Smarkfen 	/*
34594235Smarkfen 	 * Make sure that we get a null terminated string.
34604235Smarkfen 	 * For a bad input, we truncate at VALID_ALG_LEN.
34614235Smarkfen 	 */
34624235Smarkfen 	(void) strlcpy(tstr, str, VALID_ALG_LEN);
34634235Smarkfen 	lens = strtok(tstr, "()");
34644235Smarkfen 	lens = strtok(NULL, "()");
34654235Smarkfen 
34664235Smarkfen 	if (lens != NULL) {
34674235Smarkfen 		int len1 = 0;
34684235Smarkfen 		int len2 = SPD_MAX_MAXBITS;
34694235Smarkfen 		int len_all = strlen(lens);
34704235Smarkfen 		int dot_start = (lens[0] == '.');
34714235Smarkfen 		l1_str = strtok(lens, ".");
34724235Smarkfen 		l2_str = strtok(NULL, ".");
34734235Smarkfen 		if (l1_str != NULL) {
34744235Smarkfen 			l1 = parse_int(l1_str);
34754235Smarkfen 			len1 = strlen(l1_str);
34764235Smarkfen 			if (len1 < 0)
34774235Smarkfen 				return (1);
34784235Smarkfen 		}
34794235Smarkfen 		if (l2_str != NULL) {
34804235Smarkfen 			l2 = parse_int(l2_str);
34814235Smarkfen 			len2 = strlen(l2_str);
34824235Smarkfen 			if (len2 < 0)
34834235Smarkfen 				return (1);
34844235Smarkfen 		}
34854235Smarkfen 
34864235Smarkfen 		if (len_all == len1) {
34874235Smarkfen 			/* alg(n) */
34884235Smarkfen 			l2 = l1;
34894235Smarkfen 		} else if (dot_start) {
34904235Smarkfen 			/* alg(..n) */
34914235Smarkfen 			l2 = l1;
34924235Smarkfen 			l1 = 0;
34934235Smarkfen 		} else if ((len_all - 2) == len1) {
34944235Smarkfen 			/* alg(n..) */
34954235Smarkfen 			l2 = SPD_MAX_MAXBITS;
34964235Smarkfen 		} /* else alg(n..m) */
34974235Smarkfen 	}
34984235Smarkfen 
34994235Smarkfen 	if (alg_type == SPD_ATTR_AH_AUTH ||
35004235Smarkfen 	    alg_type == SPD_ATTR_ESP_AUTH) {
35014235Smarkfen 		alg_value = valid_algorithm(IPSEC_PROTO_AH, tstr);
35024235Smarkfen 	} else {
35034235Smarkfen 		alg_value = valid_algorithm(IPSEC_PROTO_ESP, tstr);
35044235Smarkfen 	}
35054235Smarkfen 	if (alg_value < 0) {
35064235Smarkfen 		/* Invalid algorithm or "none" */
35074235Smarkfen 		return (alg_value);
35084235Smarkfen 	}
35094235Smarkfen 
35104235Smarkfen 	if (alg_type == SPD_ATTR_AH_AUTH) {
35114235Smarkfen 		a_type = AH_AUTH;
35124235Smarkfen 		iap->iap_attr |= SPD_APPLY_AH;
35134235Smarkfen 		ap = &(iap->iap_aauth);
35144235Smarkfen 	} else if (alg_type == SPD_ATTR_ESP_AUTH) {
35154235Smarkfen 		a_type = ESP_AUTH;
35164235Smarkfen 		iap->iap_attr |= SPD_APPLY_ESP|SPD_APPLY_ESPA;
35174235Smarkfen 		ap = &(iap->iap_eauth);
35184235Smarkfen 	} else {
35194235Smarkfen 		a_type = ESP_ENCR;
35204235Smarkfen 		iap->iap_attr |= SPD_APPLY_ESP;
35214235Smarkfen 		ap = &(iap->iap_eencr);
35224235Smarkfen 	}
35234235Smarkfen 
35244235Smarkfen 	ap->alg_id = alg_value;
35254235Smarkfen 	ap->alg_minbits = l1;
35264235Smarkfen 	ap->alg_maxbits = l2;
35274235Smarkfen 
35284235Smarkfen 	if (!alg_rangecheck(a_type, alg_value, ap))
35294235Smarkfen 		return (1);
35304235Smarkfen 
35314235Smarkfen 	return (0);
35324235Smarkfen }
35334235Smarkfen 
35344235Smarkfen static char *
35354235Smarkfen sys_error_message(int syserr)
35364235Smarkfen {
35374235Smarkfen 	char *mesg;
35384235Smarkfen 
35394235Smarkfen 	switch (syserr) {
35404235Smarkfen 	case EEXIST:
35414235Smarkfen 		mesg = gettext("Entry already exists");
35424235Smarkfen 		break;
35434235Smarkfen 	case ENOENT:
35444235Smarkfen 		mesg = gettext("Tunnel not found");
35454235Smarkfen 		break;
35464235Smarkfen 	case EINVAL:
35474235Smarkfen 		mesg = gettext("Invalid entry");
35484235Smarkfen 		break;
35494235Smarkfen 	default :
35504235Smarkfen 		mesg = strerror(syserr);
35514235Smarkfen 	}
35524235Smarkfen 	return (mesg);
35534235Smarkfen }
35544235Smarkfen 
35554235Smarkfen static void
35564235Smarkfen error_message(error_type_t error, int type, int line)
35574235Smarkfen {
35584235Smarkfen 	char *mesg;
35594235Smarkfen 
35604235Smarkfen 	switch (type) {
35614235Smarkfen 	case IPSEC_CONF_SRC_ADDRESS:
35624235Smarkfen 		mesg = gettext("Source Address");
35634235Smarkfen 		break;
35644235Smarkfen 	case IPSEC_CONF_DST_ADDRESS:
35654235Smarkfen 		mesg = gettext("Destination Address");
35664235Smarkfen 		break;
35674235Smarkfen 	case IPSEC_CONF_SRC_PORT:
35684235Smarkfen 		mesg = gettext("Source Port");
35694235Smarkfen 		break;
35704235Smarkfen 	case IPSEC_CONF_DST_PORT:
35714235Smarkfen 		mesg = gettext("Destination Port");
35724235Smarkfen 		break;
35734235Smarkfen 	case IPSEC_CONF_SRC_MASK:
35744235Smarkfen 		mesg = gettext("Source Mask");
35754235Smarkfen 		break;
35764235Smarkfen 	case IPSEC_CONF_DST_MASK:
35774235Smarkfen 		mesg = gettext("Destination Mask");
35784235Smarkfen 		break;
35794235Smarkfen 	case IPSEC_CONF_ULP:
35804235Smarkfen 		mesg = gettext("Upper Layer Protocol");
35814235Smarkfen 		break;
35824235Smarkfen 	case IPSEC_CONF_IPSEC_AALGS:
35834235Smarkfen 		mesg = gettext("Authentication Algorithm");
35844235Smarkfen 		break;
35854235Smarkfen 	case IPSEC_CONF_IPSEC_EALGS:
35864235Smarkfen 		mesg = gettext("Encryption Algorithm");
35874235Smarkfen 		break;
35884235Smarkfen 	case IPSEC_CONF_IPSEC_EAALGS:
35894235Smarkfen 		mesg = gettext("ESP Authentication Algorithm");
35904235Smarkfen 		break;
35914235Smarkfen 	case IPSEC_CONF_IPSEC_SA:
35924235Smarkfen 		mesg = gettext("SA");
35934235Smarkfen 		break;
35944235Smarkfen 	case IPSEC_CONF_IPSEC_DIR:
35954235Smarkfen 		mesg = gettext("Direction");
35964235Smarkfen 		break;
35974235Smarkfen 	case IPSEC_CONF_ICMP_TYPE:
35984235Smarkfen 		mesg = gettext("ICMP type");
35994235Smarkfen 		break;
36004235Smarkfen 	case IPSEC_CONF_ICMP_CODE:
36014235Smarkfen 		mesg = gettext("ICMP code");
36024235Smarkfen 		break;
36034235Smarkfen 	case IPSEC_CONF_NEGOTIATE:
36044235Smarkfen 		mesg = gettext("Negotiate");
36054235Smarkfen 		break;
36064235Smarkfen 	case IPSEC_CONF_TUNNEL:
36074235Smarkfen 		mesg = gettext("Tunnel");
36084235Smarkfen 		break;
36094235Smarkfen 	default :
36104235Smarkfen 		return;
36114235Smarkfen 	}
36124235Smarkfen 	/*
36134235Smarkfen 	 * If we never read a newline character, we don't want
36144235Smarkfen 	 * to print 0.
36154235Smarkfen 	 */
36164235Smarkfen 	warnx(gettext("%s%s%s %s on line: %d"),
36174235Smarkfen 	    (error == BAD_ERROR) ? gettext("Bad") : "",
36184235Smarkfen 	    (error == DUP_ERROR) ? gettext("Duplicate") : "",
36194235Smarkfen 	    (error == REQ_ERROR) ? gettext("Requires") : "",
36204235Smarkfen 	    mesg,
36214235Smarkfen 	    (arg_indices[line] == 0) ? 1 : arg_indices[line]);
36224235Smarkfen }
36234235Smarkfen 
36244235Smarkfen static int
36254235Smarkfen validate_properties(ips_act_props_t *cptr, boolean_t dir, boolean_t is_alg)
36264235Smarkfen {
36274235Smarkfen 	if (cptr->iap_action == SPD_ACTTYPE_PASS ||
36285120Smarkfen 	    cptr->iap_action == SPD_ACTTYPE_DROP) {
36294235Smarkfen 		if (!dir) {
36304235Smarkfen 			warnx(gettext("dir string "
36314235Smarkfen 			    "not found for bypass policy"));
36324235Smarkfen 		}
36334235Smarkfen 
36344235Smarkfen 		if (is_alg) {
36354235Smarkfen 			warnx(gettext("Algorithms found for bypass policy"));
36364235Smarkfen 			return (-1);
36374235Smarkfen 		}
36384235Smarkfen 		return (0);
36394235Smarkfen 	}
36404235Smarkfen 	if (!is_alg) {
36414235Smarkfen 		warnx(gettext("No IPsec algorithms given"));
36424235Smarkfen 		return (-1);
36434235Smarkfen 	}
36444235Smarkfen 	if (cptr->iap_attr == 0) {
36454235Smarkfen 		warnx(gettext("No SA attribute"));
36464235Smarkfen 		return (-1);
36474235Smarkfen 	}
36484235Smarkfen 	return (0);
36494235Smarkfen }
36504235Smarkfen 
36514235Smarkfen /*
36524235Smarkfen  * This function is called only to parse a single rule's worth of
36534235Smarkfen  * action strings.  This is called after parsing pattern and before
36544235Smarkfen  * parsing properties.  Thus we may have something in the leftover
36554235Smarkfen  * buffer while parsing the pattern, which we need to handle here.
36564235Smarkfen  */
36574235Smarkfen static int
36584235Smarkfen parse_action(FILE *fp, char **action, char **leftover)
36594235Smarkfen {
36604235Smarkfen 	char *cp;
36614235Smarkfen 	char ibuf[MAXLEN];
36624235Smarkfen 	char *tmp_buf;
36634235Smarkfen 	char *buf;
36644235Smarkfen 	boolean_t new_stuff;
36654235Smarkfen 
36664235Smarkfen 	if (*leftover != NULL) {
36674235Smarkfen 		buf = *leftover;
36684235Smarkfen 		new_stuff = B_FALSE;
36694235Smarkfen 		goto scan;
36704235Smarkfen 	}
36714235Smarkfen 	while (fgets(ibuf, MAXLEN, fp) != NULL) {
36724235Smarkfen 		new_stuff = B_TRUE;
36734235Smarkfen 		if (ibuf[strlen(ibuf) - 1] == '\n')
36744235Smarkfen 			linecount++;
36754235Smarkfen 		buf = ibuf;
36764235Smarkfen scan:
36774235Smarkfen 		/* Truncate at the beginning of a comment */
36784235Smarkfen 		cp = strchr(buf, '#');
36794235Smarkfen 		if (cp != NULL)
36804235Smarkfen 			*cp = NULL;
36814235Smarkfen 
36824235Smarkfen 		/* Skip any whitespace */
36834235Smarkfen 		while (*buf != NULL && isspace(*buf))
36844235Smarkfen 			buf++;
36854235Smarkfen 
36864235Smarkfen 		/* Empty line */
36874235Smarkfen 		if (*buf == NULL)
36884235Smarkfen 			continue;
36894235Smarkfen 
36904235Smarkfen 		/*
36914235Smarkfen 		 * Store the command for error reporting
36924235Smarkfen 		 * and ipsec_conf_add().
36934235Smarkfen 		 */
36944235Smarkfen 		if (new_stuff) {
36954235Smarkfen 			/*
36964235Smarkfen 			 * Check for buffer overflow including the null
36974235Smarkfen 			 * terminating character.
36984235Smarkfen 			 */
36994235Smarkfen 			int len = strlen(ibuf);
37004235Smarkfen 			if ((cbuf_offset + len + 1) >= CBUF_LEN)
37014235Smarkfen 				return (-1);
37025120Smarkfen 
37034235Smarkfen 			(void) strcpy(cbuf + cbuf_offset, ibuf);
37044235Smarkfen 			cbuf_offset += len;
37054235Smarkfen 		}
37064235Smarkfen 		/*
37074235Smarkfen 		 * Start of the non-empty non-space character.
37084235Smarkfen 		 */
37095120Smarkfen 		tmp_buf = buf;
37104235Smarkfen 
37114235Smarkfen 		/* Skip until next whitespace or CURL_BEGIN */
37124235Smarkfen 		while (*buf != NULL && !isspace(*buf) &&
37134235Smarkfen 		    *buf != CURL_BEGIN)
37144235Smarkfen 			buf++;
37154235Smarkfen 
37164235Smarkfen 		if (*buf != NULL) {
37175120Smarkfen 			if (tmp_buf == buf) /* No action token */
37185120Smarkfen 				goto error;
37194235Smarkfen 			if (*buf == CURL_BEGIN) {
37204235Smarkfen 				*buf = NULL;
37214235Smarkfen 				/* Allocate an extra byte for the null also */
37224235Smarkfen 				if ((*action = malloc(strlen(tmp_buf) + 1)) ==
37234235Smarkfen 				    NULL) {
37244235Smarkfen 					warn("malloc");
37254235Smarkfen 					return (ENOMEM);
37264235Smarkfen 				}
37274235Smarkfen 				(void) strcpy(*action, tmp_buf);
37284235Smarkfen 				*buf = CURL_BEGIN;
37294235Smarkfen 			} else {
37304235Smarkfen 				/* We have hit a space */
37314235Smarkfen 				*buf++ = NULL;
37324235Smarkfen 				/* Allocate an extra byte for the null also */
37334235Smarkfen 				if ((*action = malloc(strlen(tmp_buf) + 1)) ==
37344235Smarkfen 				    NULL) {
37354235Smarkfen 					warn("malloc");
37364235Smarkfen 					return (ENOMEM);
37374235Smarkfen 				}
37384235Smarkfen 				(void) strcpy(*action, tmp_buf);
37394235Smarkfen 			}
37404235Smarkfen 			/*
37414235Smarkfen 			 * Copy the rest of the line into the
37424235Smarkfen 			 * leftover buffer.
37434235Smarkfen 			 */
37444235Smarkfen 			if (*buf != NULL) {
37454235Smarkfen 				(void) strlcpy(lo_buf, buf, sizeof (lo_buf));
37464235Smarkfen 				*leftover = lo_buf;
37474235Smarkfen 			} else {
37484235Smarkfen 				*leftover = NULL;
37494235Smarkfen 			}
37504235Smarkfen 		} else {
37514235Smarkfen 			/* Allocate an extra byte for the null also */
37524235Smarkfen 			if ((*action = malloc(strlen(tmp_buf) + 1)) ==
37534235Smarkfen 			    NULL) {
37544235Smarkfen 				warn("malloc");
37554235Smarkfen 				return (ENOMEM);
37564235Smarkfen 			}
37574235Smarkfen 			(void) strcpy(*action, tmp_buf);
37584235Smarkfen 			*leftover = NULL;
37594235Smarkfen 		}
37605120Smarkfen 		if (argindex >= ARG_BUF_LEN) {
37615120Smarkfen 			warnx(gettext("(parsing one command) "
37625120Smarkfen 			    "Too many selectors before action."));
37634235Smarkfen 			return (-1);
37645120Smarkfen 		}
37654235Smarkfen 		arg_indices[argindex++] = linecount;
37664235Smarkfen 		return (PARSE_SUCCESS);
37674235Smarkfen 	}
37684235Smarkfen 	/*
37694235Smarkfen 	 * Return error, on an empty action field.
37704235Smarkfen 	 */
37715120Smarkfen error:
37725120Smarkfen 	warnx(gettext("(parsing one command) "
37735120Smarkfen 	    "Missing action token."));
37744235Smarkfen 	return (-1);
37754235Smarkfen }
37764235Smarkfen 
37774235Smarkfen /*
37784235Smarkfen  * This is called to parse pattern or properties that is enclosed
37794235Smarkfen  * between CURL_BEGIN and CURL_END.
37804235Smarkfen  */
37814235Smarkfen static int
37824235Smarkfen parse_pattern_or_prop(FILE *fp, char *argvec[], char **leftover)
37834235Smarkfen {
37844235Smarkfen 	char *cp;
37854235Smarkfen 	int i = 0;
37864235Smarkfen 	boolean_t curl_begin_seen = B_FALSE;
37874235Smarkfen 	char ibuf[MAXLEN];
37884235Smarkfen 	char *tmp_buf;
37894235Smarkfen 	char *buf;
37904235Smarkfen 	boolean_t new_stuff;
37914235Smarkfen 
37924235Smarkfen 	/*
37934235Smarkfen 	 * When parsing properties, leftover buffer could have the
37944235Smarkfen 	 * leftovers of the previous fgets().
37954235Smarkfen 	 */
37964235Smarkfen 	if (*leftover != NULL) {
37974235Smarkfen 		buf = *leftover;
37984235Smarkfen 		new_stuff = B_FALSE;
37994235Smarkfen 		goto scan;
38004235Smarkfen 	}
38014235Smarkfen 	while (fgets(ibuf, MAXLEN, fp) != NULL) {
38024235Smarkfen 		new_stuff = B_TRUE;
38034235Smarkfen #ifdef DEBUG_HEAVY
38044235Smarkfen 		(void) printf("%s\n", ibuf);
38054235Smarkfen #endif
38064235Smarkfen 		if (ibuf[strlen(ibuf) - 1] == '\n')
38074235Smarkfen 			linecount++;
38084235Smarkfen 		buf = ibuf;
38094235Smarkfen scan:
38104235Smarkfen 		/* Truncate at the beginning of a comment */
38114235Smarkfen 		cp = strchr(buf, '#');
38124235Smarkfen 		if (cp != NULL)
38134235Smarkfen 			*cp = NULL;
38144235Smarkfen 
38154235Smarkfen 		/* Skip any whitespace */
38164235Smarkfen 		while (*buf != NULL && isspace(*buf))
38174235Smarkfen 			buf++;
38184235Smarkfen 
38194235Smarkfen 		/* Empty line */
38204235Smarkfen 		if (*buf == NULL)
38214235Smarkfen 			continue;
38224235Smarkfen 		/*
38234235Smarkfen 		 * Store the command for error reporting
38244235Smarkfen 		 * and ipsec_conf_add().
38254235Smarkfen 		 */
38264235Smarkfen 		if (new_stuff) {
38274235Smarkfen 			/*
38284235Smarkfen 			 * Check for buffer overflow including the null
38294235Smarkfen 			 * terminating character.
38304235Smarkfen 			 */
38314235Smarkfen 			int len = strlen(ibuf);
38324235Smarkfen 			if ((cbuf_offset + len + 1) >= CBUF_LEN)
38334235Smarkfen 				return (-1);
38344235Smarkfen 			(void) strcpy(cbuf + cbuf_offset, ibuf);
38354235Smarkfen 			cbuf_offset += len;
38364235Smarkfen 		}
38374235Smarkfen 		/*
38384235Smarkfen 		 * First non-space character should be
38394235Smarkfen 		 * a curly bracket.
38404235Smarkfen 		 */
38414235Smarkfen 		if (!curl_begin_seen) {
38424235Smarkfen 			if (*buf != CURL_BEGIN) {
38434235Smarkfen 				/*
38444235Smarkfen 				 * If we never read a newline character,
38454235Smarkfen 				 * we don't want to print 0.
38464235Smarkfen 				 */
38475120Smarkfen 				warnx(gettext("line %d : pattern must start "
38485120Smarkfen 				    "with \"%c\" character"),
38495120Smarkfen 				    (linecount == 0) ? 1 : linecount,
38505120Smarkfen 				    CURL_BEGIN);
38514235Smarkfen 				return (-1);
38524235Smarkfen 			}
38534235Smarkfen 			buf++;
38544235Smarkfen 			curl_begin_seen = B_TRUE;
38554235Smarkfen 		}
38564235Smarkfen 		/*
38574235Smarkfen 		 * Arguments are separated by white spaces or
38584235Smarkfen 		 * newlines. Scan till you see a CURL_END.
38594235Smarkfen 		 */
38604235Smarkfen 		while (*buf != NULL) {
38614235Smarkfen 			if (*buf == CURL_END) {
38624235Smarkfen ret:
38634235Smarkfen 				*buf++ = NULL;
38644235Smarkfen 				/*
38654235Smarkfen 				 * Copy the rest of the line into the
38664235Smarkfen 				 * leftover buffer if any.
38674235Smarkfen 				 */
38684235Smarkfen 				if (*buf != NULL) {
38694235Smarkfen 					(void) strlcpy(lo_buf, buf,
38704235Smarkfen 					    sizeof (lo_buf));
38714235Smarkfen 					*leftover = lo_buf;
38724235Smarkfen 				} else {
38734235Smarkfen 					*leftover = NULL;
38744235Smarkfen 				}
38754235Smarkfen 				return (PARSE_SUCCESS);
38764235Smarkfen 			}
38774235Smarkfen 			/*
38784235Smarkfen 			 * Skip any trailing whitespace until we see a
38794235Smarkfen 			 * non white-space character.
38804235Smarkfen 			 */
38814235Smarkfen 			while (*buf != NULL && isspace(*buf))
38824235Smarkfen 				buf++;
38834235Smarkfen 
38844235Smarkfen 			if (*buf == CURL_END)
38854235Smarkfen 				goto ret;
38864235Smarkfen 
38874235Smarkfen 			/* Scan the next line as this buffer is empty */
38884235Smarkfen 			if (*buf == NULL)
38894235Smarkfen 				break;
38904235Smarkfen 
38914235Smarkfen 			if (i >= MAXARGS) {
38924235Smarkfen 				warnx(
38934235Smarkfen 				    gettext("Number of Arguments exceeded %d"),
38944235Smarkfen 				    i);
38954235Smarkfen 				return (-1);
38964235Smarkfen 			}
38974235Smarkfen 			/*
38984235Smarkfen 			 * Non-empty, Non-space buffer.
38994235Smarkfen 			 */
39004235Smarkfen 			tmp_buf = buf++;
39014235Smarkfen 			/*
39024235Smarkfen 			 * Real scan of the argument takes place here.
39034235Smarkfen 			 * Skip past till space or CURL_END.
39044235Smarkfen 			 */
39054235Smarkfen 			while (*buf != NULL && !isspace(*buf) &&
39064235Smarkfen 			    *buf != CURL_END) {
39074235Smarkfen 				buf++;
39084235Smarkfen 			}
39094235Smarkfen 			/*
39104235Smarkfen 			 * Either a space or we have hit the CURL_END or
39114235Smarkfen 			 * the real end.
39124235Smarkfen 			 */
39134235Smarkfen 			if (*buf != NULL) {
39144235Smarkfen 				if (*buf == CURL_END) {
39154235Smarkfen 					*buf++ = NULL;
39164235Smarkfen 					if ((argvec[i] = malloc(strlen(tmp_buf)
39174235Smarkfen 					    + 1)) == NULL) {
39184235Smarkfen 						warn("malloc");
39194235Smarkfen 						return (ENOMEM);
39204235Smarkfen 					}
39214235Smarkfen 					if (strlen(tmp_buf) != 0) {
39224235Smarkfen 						(void) strcpy(argvec[i],
39234235Smarkfen 						    tmp_buf);
39244235Smarkfen 						if (argindex >= ARG_BUF_LEN)
39255120Smarkfen 							goto toomanyargs;
39264235Smarkfen 						arg_indices[argindex++] =
39274235Smarkfen 						    linecount;
39284235Smarkfen 					}
39294235Smarkfen 					/*
39304235Smarkfen 					 * Copy the rest of the line into the
39314235Smarkfen 					 * leftover buffer.
39324235Smarkfen 					 */
39334235Smarkfen 					if (*buf != NULL) {
39344235Smarkfen 						(void) strlcpy(lo_buf, buf,
39354235Smarkfen 						    sizeof (lo_buf));
39364235Smarkfen 						*leftover = lo_buf;
39374235Smarkfen 					} else {
39384235Smarkfen 						*leftover = NULL;
39394235Smarkfen 					}
39404235Smarkfen 					return (PARSE_SUCCESS);
39414235Smarkfen 				} else {
39424235Smarkfen 					*buf++ = NULL;
39434235Smarkfen 				}
39444235Smarkfen 			}
39454235Smarkfen 			/*
39464235Smarkfen 			 * Copy this argument and scan for the buffer more
39474235Smarkfen 			 * if it is non-empty. If it is empty scan for
39484235Smarkfen 			 * the next line.
39494235Smarkfen 			 */
39504235Smarkfen 			if ((argvec[i] = malloc(strlen(tmp_buf) + 1)) ==
39514235Smarkfen 			    NULL) {
39524235Smarkfen 				warn("malloc");
39534235Smarkfen 				return (ENOMEM);
39544235Smarkfen 			}
39554235Smarkfen 			(void) strcpy(argvec[i++], tmp_buf);
39565120Smarkfen 			if (argindex >= ARG_BUF_LEN) {
39575120Smarkfen 			/*
39585120Smarkfen 			 * The number of tokens in a single policy entry
39595120Smarkfen 			 * exceeds the number of buffers available to fully
39605120Smarkfen 			 * parse the policy entry.
39615120Smarkfen 			 */
39625120Smarkfen toomanyargs:
39635120Smarkfen 				warnx(gettext("(parsing one command) "
39645120Smarkfen 				    "Too many tokens in single policy entry."));
39654235Smarkfen 				return (-1);
39665120Smarkfen 			}
39674235Smarkfen 			arg_indices[argindex++] = linecount;
39684235Smarkfen 		}
39694235Smarkfen 	}
39704235Smarkfen 	/*
39714235Smarkfen 	 * If nothing is given in the file, it is okay.
39724235Smarkfen 	 * If something is given in the file and it is
39734235Smarkfen 	 * not CURL_BEGIN, we would have returned error
39744235Smarkfen 	 * above. If curl_begin_seen and we are here,
39754235Smarkfen 	 * something is wrong.
39764235Smarkfen 	 */
39775120Smarkfen 	if (curl_begin_seen) {
39785120Smarkfen 		warnx(gettext("(parsing one command) "
39795120Smarkfen 		    "Pattern or Properties incomplete."));
39804235Smarkfen 		return (-1);
39815120Smarkfen 	}
39824235Smarkfen 	return (PARSE_EOF);		/* Nothing more in the file */
39834235Smarkfen }
39844235Smarkfen 
39854235Smarkfen /*
39864235Smarkfen  * Parse one command i.e {pattern} action {properties}.
39874235Smarkfen  *
39884235Smarkfen  * {pattern} ( action {prop} | pass | drop ) (or ...)*
39894235Smarkfen  */
39904235Smarkfen static int
39914235Smarkfen parse_one(FILE *fp, act_prop_t *act_props)
39924235Smarkfen {
39934235Smarkfen 	char *leftover;
39944235Smarkfen 	int ret;
39954235Smarkfen 	int i;
39964235Smarkfen 	int ap_num = 0;
39974235Smarkfen 	enum parse_state {pattern, action, prop } pstate;
39984235Smarkfen 
39994235Smarkfen 	has_daprefix = has_saprefix = B_FALSE;
40004235Smarkfen 
40014235Smarkfen 	(void) memset(act_props, 0, sizeof (act_prop_t));
40024235Smarkfen 	pstate = pattern;
40034235Smarkfen 
40044235Smarkfen 	ret = 0;
40054235Smarkfen 	leftover = NULL;
40064235Smarkfen 	argindex = 0;
40074235Smarkfen 	cbuf_offset = 0;
40084235Smarkfen 	assert(shp == NULL && dhp == NULL);
40094235Smarkfen 
40104235Smarkfen 	for (;;) {
40114235Smarkfen 		switch (pstate) {
40124235Smarkfen 		case pattern:
40134235Smarkfen 		{
40144235Smarkfen #ifdef DEBUG_HEAVY
40154235Smarkfen 			(void) printf("pattern\n");
40164235Smarkfen #endif
40174235Smarkfen 			ret = parse_pattern_or_prop(fp,
40184235Smarkfen 			    act_props->pattern, &leftover);
40194235Smarkfen 			if (ret == PARSE_EOF) {
40204235Smarkfen 				/* EOF reached */
40215120Smarkfen 				return (PARSE_EOF);
40224235Smarkfen 			}
40234235Smarkfen 			if (ret != 0) {
40245120Smarkfen 				ret = -1;
40254235Smarkfen 				goto err;
40264235Smarkfen 			}
40274235Smarkfen 			pstate = action;
40284235Smarkfen 			break;
40294235Smarkfen 		}
40304235Smarkfen 		case action:
40314235Smarkfen 		{
40324235Smarkfen #ifdef DEBUG_HEAVY
40334235Smarkfen 			(void) printf("action\n");
40344235Smarkfen #endif
40354235Smarkfen 			ret = parse_action(fp,
40364235Smarkfen 			    &act_props->ap[ap_num].act, &leftover);
40374235Smarkfen 			if (ret != 0) {
40385120Smarkfen 				ret = -1;
40394235Smarkfen 				goto err;
40404235Smarkfen 			}
40414235Smarkfen 
40424235Smarkfen 			/*
40434235Smarkfen 			 * Validate action now itself so that we don't
40444235Smarkfen 			 * proceed too much into the bad world.
40454235Smarkfen 			 */
40464235Smarkfen 			for (i = 0; action_table[i].string; i++) {
40474235Smarkfen 				if (strcmp(act_props->ap[ap_num].act,
40484235Smarkfen 				    action_table[i].string) == 0)
40494235Smarkfen 					break;
40504235Smarkfen 			}
40514235Smarkfen 
40524235Smarkfen 			if (action_table[i].tok_val == TOK_or) {
40534235Smarkfen 				/* hit an or, go again */
40544235Smarkfen 				break;
40554235Smarkfen 			}
40564235Smarkfen 
40574235Smarkfen 			if (action_table[i].string == NULL) {
40584235Smarkfen 				/*
40594235Smarkfen 				 * If we never read a newline
40604235Smarkfen 				 * character, we don't want
40614235Smarkfen 				 * to print 0.
40624235Smarkfen 				 */
40635120Smarkfen 				warnx(gettext("(parsing one command) "
40644235Smarkfen 				    "Invalid action on line %d: %s"),
40654235Smarkfen 				    (linecount == 0) ? 1 : linecount,
40664235Smarkfen 				    act_props->ap[ap_num].act);
40674235Smarkfen 				return (-1);
40684235Smarkfen 			}
40694235Smarkfen 
40704235Smarkfen 			pstate = prop;
40714235Smarkfen 			break;
40724235Smarkfen 		}
40734235Smarkfen 		case prop:
40744235Smarkfen 		{
40754235Smarkfen #ifdef DEBUG_HEAVY
40764235Smarkfen 			(void) printf("prop\n");
40774235Smarkfen #endif
40784235Smarkfen 			ret = parse_pattern_or_prop(fp,
40794235Smarkfen 			    act_props->ap[ap_num].prop, &leftover);
40804235Smarkfen 			if (ret != 0) {
40815120Smarkfen 				if (ret == PARSE_EOF) {
40825120Smarkfen 					warnx(gettext("(parsing one command) "
40835120Smarkfen 					    "Missing properties."));
40845120Smarkfen 				}
40855120Smarkfen 				ret = -1;
40864235Smarkfen 				goto err;
40874235Smarkfen 			}
40884235Smarkfen 
40894235Smarkfen 			if (leftover != NULL) {
40904235Smarkfen 				/* Accomodate spaces at the end */
40914235Smarkfen 				while (*leftover != NULL) {
40925120Smarkfen 					if (*leftover == BACK_SLASH) {
40935120Smarkfen 						warnx(gettext("Invalid line "
40945120Smarkfen 						    "continuation character."));
40955120Smarkfen 						ret = -1;
40965120Smarkfen 						goto err;
40975120Smarkfen 					}
40984235Smarkfen 					if (*leftover == 'o') {
40994235Smarkfen 						leftover++;
41004235Smarkfen 						if (*leftover == 'r') {
41014235Smarkfen 							leftover++;
41024235Smarkfen 							ap_num++;
41034235Smarkfen 							pstate = action;
41044235Smarkfen 							goto again;
41054235Smarkfen 						}
41064235Smarkfen 					}
41074235Smarkfen 					if (!isspace(*leftover)) {
41084235Smarkfen 						ret = -1;
41094235Smarkfen 						goto err;
41104235Smarkfen 					}
41114235Smarkfen 					leftover++;
41124235Smarkfen 				}
41134235Smarkfen 				return (0);
41144235Smarkfen 			}
41154235Smarkfen 			ap_num++;
41164235Smarkfen 			if (ap_num > MAXARGS)
41174235Smarkfen 				return (0);
41184235Smarkfen 			pstate = action; /* or */
41194235Smarkfen 			break;
41204235Smarkfen 		} /* case prop: */
41214235Smarkfen 		} /* switch(pstate) */
41224235Smarkfen 
41234235Smarkfen again:
41245120Smarkfen 		if (ap_num > MAXARGS) {
41255120Smarkfen 			warnx(gettext("Too many actions."));
41265120Smarkfen 			return (-1);
41275120Smarkfen 		}
41285120Smarkfen 	} /* for(;;) */
41294235Smarkfen err:
41304235Smarkfen 	if (ret != 0) {
41314235Smarkfen 		/*
41324235Smarkfen 		 * If we never read a newline character, we don't want
41334235Smarkfen 		 * to print 0.
41344235Smarkfen 		 */
41354235Smarkfen 		warnx(gettext("Error before or at line %d"),
41364235Smarkfen 		    (linecount == 0) ? 1 : linecount);
41374235Smarkfen 	}
41384235Smarkfen 	return (ret);
41394235Smarkfen }
41404235Smarkfen 
41414235Smarkfen /*
41424235Smarkfen  * convert an act_propts_t to an ips_conf_t
41434235Smarkfen  */
41444235Smarkfen 
41454235Smarkfen static int
41464235Smarkfen form_ipsec_conf(act_prop_t *act_props, ips_conf_t *cptr)
41474235Smarkfen {
41484235Smarkfen 	int i, j, k;
41494235Smarkfen 	int tok_count = 0;
41504235Smarkfen 	struct protoent *pent;
41514235Smarkfen 	boolean_t saddr, daddr, ipsec_aalg, ipsec_ealg, ipsec_eaalg, dir;
4152*10372Sdanmcd@sun.com 	boolean_t old_style, new_style, auth_covered, is_no_alg;
41534235Smarkfen 	struct in_addr mask;
41544235Smarkfen 	int line_no;
41554235Smarkfen 	int ret;
41564235Smarkfen 	int ap_num = 0;
41574235Smarkfen 	int type, code, type_end, code_end;
41584235Smarkfen #ifdef DEBUG_HEAVY
41594235Smarkfen 	/*
41604235Smarkfen 	 * pattern => act_props->pattern
41614235Smarkfen 	 * action => act_props->ap[].act
41624235Smarkfen 	 * properties => act_props->ap[].prop
41634235Smarkfen 	 */
41644235Smarkfen 	(void) printf("\npattern\n------------\n");
41654235Smarkfen 	for (i = 0; act_props->pattern[i] != NULL; i++)
41664235Smarkfen 		(void) printf("%s\n", act_props->pattern[i]);
41674235Smarkfen 	(void) printf("apz\n----------\n");
41684235Smarkfen 	for (j = 0; act_props->ap[j].act != NULL; j++) {
41694235Smarkfen 
41704235Smarkfen 		(void) printf("act%d->%s\n", j, act_props->ap[j].act);
41714235Smarkfen 		for (i = 0; act_props->ap[j].prop[i] != NULL; i++)
41724235Smarkfen 			(void) printf("%dprop%d->%s\n",
41734235Smarkfen 			    j, i, act_props->ap[j].prop[i]);
41744235Smarkfen 	}
41754235Smarkfen 	(void) printf("------------\n\n");
41764235Smarkfen #endif
41774235Smarkfen 
41784235Smarkfen 	(void) memset(cptr, 0, sizeof (ips_conf_t));
41794235Smarkfen 	saddr = daddr = ipsec_aalg = ipsec_ealg = ipsec_eaalg = dir = B_FALSE;
4180*10372Sdanmcd@sun.com 	old_style = new_style = is_no_alg = B_FALSE;
41814235Smarkfen 	/*
41824235Smarkfen 	 * Get the Pattern. NULL pattern is valid.
41834235Smarkfen 	 */
41844235Smarkfen 	for (i = 0, line_no = 0; act_props->pattern[i]; i++, line_no++) {
41854235Smarkfen 		for (j = 0; pattern_table[j].string; j++) {
41864235Smarkfen 			if (strcmp(act_props->pattern[i],
41874235Smarkfen 			    pattern_table[j].string) == 0)
41884235Smarkfen 				break;
41894235Smarkfen 		}
41904235Smarkfen 
41914235Smarkfen 		if (pattern_table[j].string == NULL) {
41924235Smarkfen 			/*
41934235Smarkfen 			 * If we never read a newline character, we don't want
41944235Smarkfen 			 * to print 0.
41954235Smarkfen 			 */
41964235Smarkfen 			warnx(gettext("Invalid pattern on line %d: %s"),
41974235Smarkfen 			    (arg_indices[line_no] == 0) ? 1 :
41984235Smarkfen 			    arg_indices[line_no], act_props->pattern[i]);
41994235Smarkfen 			return (-1);
42004235Smarkfen 		}
42014235Smarkfen 
42024235Smarkfen 		cptr->patt_tok[tok_count++] = pattern_table[j].tok_val;
42034235Smarkfen 
42044235Smarkfen 		switch (pattern_table[j].tok_val) {
42054235Smarkfen 
42064235Smarkfen 		case TOK_dir:
42074235Smarkfen 			i++, line_no++;
42084235Smarkfen 			if (act_props->pattern[i] == NULL) {
42094235Smarkfen 				error_message(BAD_ERROR,
42104235Smarkfen 				    IPSEC_CONF_IPSEC_DIR, line_no);
42114235Smarkfen 				return (-1);
42124235Smarkfen 			}
42134235Smarkfen 
42144235Smarkfen 			if (strncmp(act_props->pattern[i], "in", 2) == 0) {
42154235Smarkfen 				cptr->ips_dir = SPD_RULE_FLAG_INBOUND;
42164235Smarkfen 			} else if (strncmp(
42174235Smarkfen 			    act_props->pattern[i], "out", 3) == 0) {
42184235Smarkfen 				cptr->ips_dir = SPD_RULE_FLAG_OUTBOUND;
42194235Smarkfen 			} else if (strncmp(
42204235Smarkfen 			    act_props->pattern[i], "both", 4) == 0) {
42214235Smarkfen 				if (old_style) {
42224235Smarkfen 					error_message(BAD_ERROR,
42234235Smarkfen 					    IPSEC_CONF_IPSEC_DIR, line_no);
42244235Smarkfen 					return (-1);
42254235Smarkfen 				}
42264235Smarkfen 				new_style = B_TRUE;
42274235Smarkfen 				cptr->ips_dir =
42284235Smarkfen 				    SPD_RULE_FLAG_OUTBOUND |
42294235Smarkfen 				    SPD_RULE_FLAG_INBOUND;
42304235Smarkfen 			} else {
42314235Smarkfen 				error_message(BAD_ERROR,
42324235Smarkfen 				    IPSEC_CONF_IPSEC_DIR, line_no);
42334235Smarkfen 				return (-1);
42344235Smarkfen 			}
42354235Smarkfen 			dir = B_TRUE;
42364235Smarkfen 			break;
42374235Smarkfen 
42384235Smarkfen 		case TOK_local:
42394235Smarkfen 			if (old_style) {
42404235Smarkfen 				error_message(BAD_ERROR,
42414235Smarkfen 				    IPSEC_CONF_SRC_ADDRESS, line_no);
42424235Smarkfen 				return (-1);
42434235Smarkfen 			}
42444235Smarkfen 			new_style = B_TRUE;
42454235Smarkfen 
42464235Smarkfen 			if (saddr) {
42474235Smarkfen 				error_message(DUP_ERROR,
42484235Smarkfen 				    IPSEC_CONF_SRC_ADDRESS, line_no);
42494235Smarkfen 				return (-1);
42504235Smarkfen 			}
42514235Smarkfen 			/*
42524235Smarkfen 			 * Use this to detect duplicates rather
42534235Smarkfen 			 * than 0 like other cases, because 0 for
42544235Smarkfen 			 * address means INADDR_ANY.
42554235Smarkfen 			 */
42564235Smarkfen 			saddr = B_TRUE;
42574235Smarkfen 			cptr->has_saddr = 1;
42584235Smarkfen 			/*
42594235Smarkfen 			 * Advance to the string containing
42604235Smarkfen 			 * the address.
42614235Smarkfen 			 */
42624235Smarkfen 			i++, line_no++;
42634235Smarkfen 			if (act_props->pattern[i] == NULL) {
42644235Smarkfen 				error_message(BAD_ERROR,
42654235Smarkfen 				    IPSEC_CONF_SRC_ADDRESS, line_no);
42664235Smarkfen 				return (-1);
42674235Smarkfen 			}
42684235Smarkfen 			if (parse_address(IPSEC_CONF_SRC_ADDRESS,
42694235Smarkfen 			    act_props->pattern[i]) != 0) {
42704235Smarkfen 				error_message(BAD_ERROR,
42714235Smarkfen 				    IPSEC_CONF_SRC_ADDRESS, line_no);
42724235Smarkfen 				return (-1);
42734235Smarkfen 			}
42744235Smarkfen 			if (!cptr->has_smask)
42754235Smarkfen 				cptr->has_smask = has_saprefix;
42764235Smarkfen 
42774235Smarkfen 			break;
42784235Smarkfen 		case TOK_remote:
42794235Smarkfen 			if (old_style) {
42804235Smarkfen 				error_message(BAD_ERROR,
42814235Smarkfen 				    IPSEC_CONF_DST_ADDRESS, line_no);
42824235Smarkfen 				return (-1);
42834235Smarkfen 			}
42844235Smarkfen 			new_style = B_TRUE;
42854235Smarkfen 
42864235Smarkfen 			if (daddr) {
42874235Smarkfen 				error_message(DUP_ERROR,
42884235Smarkfen 				    IPSEC_CONF_DST_ADDRESS, line_no);
42894235Smarkfen 				return (-1);
42904235Smarkfen 			}
42914235Smarkfen 			/*
42924235Smarkfen 			 * Use this to detect duplicates rather
42934235Smarkfen 			 * than 0 like other cases, because 0 for
42944235Smarkfen 			 * address means INADDR_ANY.
42954235Smarkfen 			 */
42964235Smarkfen 			daddr = B_TRUE;
42974235Smarkfen 			cptr->has_daddr = 1;
42984235Smarkfen 			/*
42994235Smarkfen 			 * Advance to the string containing
43004235Smarkfen 			 * the address.
43014235Smarkfen 			 */
43024235Smarkfen 			i++, line_no++;
43034235Smarkfen 			if (act_props->pattern[i] == NULL) {
43044235Smarkfen 				error_message(BAD_ERROR,
43054235Smarkfen 				    IPSEC_CONF_DST_ADDRESS, line_no);
43064235Smarkfen 				return (-1);
43074235Smarkfen 			}
43084235Smarkfen 			if (parse_address(IPSEC_CONF_DST_ADDRESS,
43094235Smarkfen 			    act_props->pattern[i]) != 0) {
43104235Smarkfen 				error_message(BAD_ERROR,
43114235Smarkfen 				    IPSEC_CONF_DST_ADDRESS, line_no);
43124235Smarkfen 				return (-1);
43134235Smarkfen 			}
43144235Smarkfen 			if (!cptr->has_dmask)
43154235Smarkfen 				cptr->has_dmask = has_daprefix;
43164235Smarkfen 			break;
43174235Smarkfen 
43184235Smarkfen 		case TOK_saddr:
43194235Smarkfen 			if (new_style) {
43204235Smarkfen 				error_message(BAD_ERROR,
43214235Smarkfen 				    IPSEC_CONF_SRC_ADDRESS, line_no);
43224235Smarkfen 				return (-1);
43234235Smarkfen 			}
43244235Smarkfen 			old_style = B_TRUE;
43254235Smarkfen 
43264235Smarkfen 			if (saddr) {
43274235Smarkfen 				error_message(DUP_ERROR,
43284235Smarkfen 				    IPSEC_CONF_SRC_ADDRESS, line_no);
43294235Smarkfen 				return (-1);
43304235Smarkfen 			}
43314235Smarkfen 			/*
43324235Smarkfen 			 * Use this to detect duplicates rather
43334235Smarkfen 			 * than 0 like other cases, because 0 for
43344235Smarkfen 			 * address means INADDR_ANY.
43354235Smarkfen 			 */
43364235Smarkfen 			saddr = B_TRUE;
43374235Smarkfen 			cptr->has_saddr = 1;
43384235Smarkfen 			/*
43394235Smarkfen 			 * Advance to the string containing
43404235Smarkfen 			 * the address.
43414235Smarkfen 			 */
43424235Smarkfen 			i++, line_no++;
43434235Smarkfen 			if (act_props->pattern[i] == NULL) {
43444235Smarkfen 				error_message(BAD_ERROR,
43454235Smarkfen 				    IPSEC_CONF_SRC_ADDRESS, line_no);
43464235Smarkfen 				return (-1);
43474235Smarkfen 			}
43484235Smarkfen 
43494235Smarkfen 			if (parse_address(IPSEC_CONF_SRC_ADDRESS,
43504235Smarkfen 			    act_props->pattern[i]) != 0) {
43514235Smarkfen 				error_message(BAD_ERROR,
43524235Smarkfen 				    IPSEC_CONF_SRC_ADDRESS, line_no);
43534235Smarkfen 				return (-1);
43544235Smarkfen 			}
43554235Smarkfen 			/* shp or bhp? */
43564235Smarkfen 			if (!cptr->has_smask)
43574235Smarkfen 				cptr->has_smask = has_saprefix;
43584235Smarkfen 			break;
43594235Smarkfen 
43604235Smarkfen 		case TOK_daddr:
43614235Smarkfen 			if (new_style) {
43624235Smarkfen 				error_message(BAD_ERROR,
43634235Smarkfen 				    IPSEC_CONF_DST_ADDRESS, line_no);
43644235Smarkfen 				return (-1);
43654235Smarkfen 			}
43664235Smarkfen 			old_style = B_TRUE;
43674235Smarkfen 
43684235Smarkfen 			if (daddr) {
43694235Smarkfen 				error_message(DUP_ERROR,
43704235Smarkfen 				    IPSEC_CONF_DST_ADDRESS, line_no);
43714235Smarkfen 				return (-1);
43724235Smarkfen 			}
43734235Smarkfen 			/*
43744235Smarkfen 			 * Use this to detect duplicates rather
43754235Smarkfen 			 * than 0 like other cases, because 0 for
43764235Smarkfen 			 * address means INADDR_ANY.
43774235Smarkfen 			 */
43784235Smarkfen 			daddr = B_TRUE;
43794235Smarkfen 			cptr->has_daddr = 1;
43804235Smarkfen 			/*
43814235Smarkfen 			 * Advance to the string containing
43824235Smarkfen 			 * the address.
43834235Smarkfen 			 */
43844235Smarkfen 			i++, line_no++;
43854235Smarkfen 			if (act_props->pattern[i] == NULL) {
43864235Smarkfen 				error_message(BAD_ERROR,
43874235Smarkfen 				    IPSEC_CONF_DST_ADDRESS, line_no);
43884235Smarkfen 				return (-1);
43894235Smarkfen 			}
43904235Smarkfen 			if (parse_address(IPSEC_CONF_DST_ADDRESS,
43914235Smarkfen 			    act_props->pattern[i]) != 0) {
43924235Smarkfen 				error_message(BAD_ERROR,
43934235Smarkfen 				    IPSEC_CONF_DST_ADDRESS, line_no);
43944235Smarkfen 				return (-1);
43954235Smarkfen 			}
43964235Smarkfen 			if (!cptr->has_dmask)
43974235Smarkfen 				cptr->has_dmask = has_daprefix;
43984235Smarkfen 			break;
43994235Smarkfen 
44004235Smarkfen 		case TOK_sport:
44014235Smarkfen 			if (new_style) {
44024235Smarkfen 				error_message(BAD_ERROR,
44034235Smarkfen 				    IPSEC_CONF_SRC_PORT, line_no);
44044235Smarkfen 				return (-1);
44054235Smarkfen 			}
44064235Smarkfen 			old_style = B_TRUE;
44074235Smarkfen 
44084235Smarkfen 			if (cptr->ips_src_port_min != 0) {
44094235Smarkfen 				error_message(DUP_ERROR, IPSEC_CONF_SRC_PORT,
44104235Smarkfen 				    line_no);
44114235Smarkfen 				return (-1);
44124235Smarkfen 			}
44134235Smarkfen 			i++, line_no++;
44144235Smarkfen 			if (act_props->pattern[i] == NULL) {
44154235Smarkfen 				error_message(BAD_ERROR, IPSEC_CONF_SRC_PORT,
44164235Smarkfen 				    line_no);
44174235Smarkfen 				return (-1);
44184235Smarkfen 			}
44194235Smarkfen 			ret = parse_port(IPSEC_CONF_SRC_PORT,
44204235Smarkfen 			    act_props->pattern[i], cptr);
44214235Smarkfen 			if (ret != 0) {
44224235Smarkfen 				error_message(BAD_ERROR, IPSEC_CONF_SRC_PORT,
44234235Smarkfen 				    line_no);
44244235Smarkfen 				return (-1);
44254235Smarkfen 			}
44264235Smarkfen 			break;
44274235Smarkfen 		case TOK_dport:
44284235Smarkfen 			if (new_style) {
44294235Smarkfen 				error_message(BAD_ERROR,
44304235Smarkfen 				    IPSEC_CONF_DST_PORT, line_no);
44314235Smarkfen 				return (-1);
44324235Smarkfen 			}
44334235Smarkfen 			old_style = B_TRUE;
44344235Smarkfen 
44354235Smarkfen 			if (cptr->ips_dst_port_min != 0) {
44364235Smarkfen 				error_message(DUP_ERROR, IPSEC_CONF_DST_PORT,
44374235Smarkfen 				    line_no);
44384235Smarkfen 				return (-1);
44394235Smarkfen 			}
44404235Smarkfen 			i++, line_no++;
44414235Smarkfen 			if (act_props->pattern[i] == NULL) {
44424235Smarkfen 				error_message(BAD_ERROR, IPSEC_CONF_DST_PORT,
44434235Smarkfen 				    line_no);
44444235Smarkfen 				return (-1);
44454235Smarkfen 			}
44464235Smarkfen 			ret = parse_port(IPSEC_CONF_DST_PORT,
44474235Smarkfen 			    act_props->pattern[i],
44484235Smarkfen 			    cptr);
44494235Smarkfen 			if (ret != 0) {
44504235Smarkfen 				error_message(BAD_ERROR, IPSEC_CONF_DST_PORT,
44514235Smarkfen 				    line_no);
44524235Smarkfen 				return (-1);
44534235Smarkfen 			}
44544235Smarkfen 			break;
44554235Smarkfen 
44564235Smarkfen 		case TOK_lport:
44574235Smarkfen 			if (old_style) {
44584235Smarkfen 				error_message(BAD_ERROR,
44594235Smarkfen 				    IPSEC_CONF_SRC_PORT, line_no);
44604235Smarkfen 				return (-1);
44614235Smarkfen 			}
44624235Smarkfen 			new_style = B_TRUE;
44634235Smarkfen 
44644235Smarkfen 			if (cptr->ips_src_port_min != 0) {
44654235Smarkfen 				error_message(DUP_ERROR, IPSEC_CONF_SRC_PORT,
44664235Smarkfen 				    line_no);
44674235Smarkfen 				return (-1);
44684235Smarkfen 			}
44694235Smarkfen 			i++, line_no++;
44704235Smarkfen 			if (act_props->pattern[i] == NULL) {
44714235Smarkfen 				error_message(BAD_ERROR, IPSEC_CONF_SRC_PORT,
44724235Smarkfen 				    line_no);
44734235Smarkfen 				return (-1);
44744235Smarkfen 			}
44754235Smarkfen 			ret = parse_port(IPSEC_CONF_SRC_PORT,
44764235Smarkfen 			    act_props->pattern[i],
44774235Smarkfen 			    cptr);
44784235Smarkfen 			if (ret != 0) {
44794235Smarkfen 				error_message(BAD_ERROR, IPSEC_CONF_SRC_PORT,
44804235Smarkfen 				    line_no);
44814235Smarkfen 				return (-1);
44824235Smarkfen 			}
44834235Smarkfen 			break;
44844235Smarkfen 
44854235Smarkfen 		case TOK_rport:
44864235Smarkfen 			if (old_style) {
44874235Smarkfen 				error_message(BAD_ERROR,
44884235Smarkfen 				    IPSEC_CONF_DST_PORT, line_no);
44894235Smarkfen 				return (-1);
44904235Smarkfen 			}
44914235Smarkfen 			new_style = B_TRUE;
44924235Smarkfen 
44934235Smarkfen 			if (cptr->ips_dst_port_min != 0) {
44944235Smarkfen 				error_message(DUP_ERROR, IPSEC_CONF_DST_PORT,
44954235Smarkfen 				    line_no);
44964235Smarkfen 				return (-1);
44974235Smarkfen 			}
44984235Smarkfen 			i++, line_no++;
44994235Smarkfen 			if (act_props->pattern[i] == NULL) {
45004235Smarkfen 				error_message(BAD_ERROR, IPSEC_CONF_DST_PORT,
45014235Smarkfen 				    line_no);
45024235Smarkfen 				return (-1);
45034235Smarkfen 			}
45044235Smarkfen 			ret = parse_port(IPSEC_CONF_DST_PORT,
45054235Smarkfen 			    act_props->pattern[i],
45064235Smarkfen 			    cptr);
45074235Smarkfen 			if (ret != 0) {
45084235Smarkfen 				error_message(BAD_ERROR, IPSEC_CONF_DST_PORT,
45094235Smarkfen 				    line_no);
45104235Smarkfen 				return (-1);
45114235Smarkfen 			}
45124235Smarkfen 			break;
45134235Smarkfen 
45144235Smarkfen 		case TOK_smask:
45154235Smarkfen 			if (new_style) {
45164235Smarkfen 				error_message(BAD_ERROR,
45174235Smarkfen 				    IPSEC_CONF_SRC_MASK, line_no);
45184235Smarkfen 				return (-1);
45194235Smarkfen 			}
45204235Smarkfen 			old_style = B_TRUE;
45214235Smarkfen 			cptr->has_smask = B_TRUE;
45224235Smarkfen 
45234235Smarkfen 			IN6_V4MAPPED_TO_INADDR(&cptr->ips_src_mask_v6, &mask);
45244235Smarkfen 			if (mask.s_addr != 0) {
45254235Smarkfen 				error_message(DUP_ERROR, IPSEC_CONF_SRC_MASK,
45264235Smarkfen 				    line_no);
45274235Smarkfen 				return (-1);
45284235Smarkfen 			}
45294235Smarkfen 			i++, line_no++;
45304235Smarkfen 			if (act_props->pattern[i] == NULL) {
45314235Smarkfen 				error_message(BAD_ERROR, IPSEC_CONF_SRC_MASK,
45324235Smarkfen 				    line_no);
45334235Smarkfen 				return (-1);
45344235Smarkfen 			}
45354235Smarkfen 			ret = parse_mask(IPSEC_CONF_SRC_MASK,
45364235Smarkfen 			    act_props->pattern[i],
45374235Smarkfen 			    cptr);
45384235Smarkfen 			if (ret != 0) {
45394235Smarkfen 				error_message(BAD_ERROR, IPSEC_CONF_SRC_MASK,
45404235Smarkfen 				    line_no);
45414235Smarkfen 				return (-1);
45424235Smarkfen 			}
45434235Smarkfen 			break;
45444235Smarkfen 		case TOK_dmask:
45454235Smarkfen 			if (new_style) {
45464235Smarkfen 				error_message(BAD_ERROR,
45474235Smarkfen 				    IPSEC_CONF_DST_MASK, line_no);
45484235Smarkfen 				return (-1);
45494235Smarkfen 			}
45504235Smarkfen 			old_style = B_TRUE;
45514235Smarkfen 			cptr->has_dmask = B_TRUE;
45524235Smarkfen 
45534235Smarkfen 			IN6_V4MAPPED_TO_INADDR(&cptr->ips_dst_mask_v6, &mask);
45544235Smarkfen 			if (mask.s_addr != 0) {
45554235Smarkfen 				error_message(DUP_ERROR, IPSEC_CONF_DST_MASK,
45564235Smarkfen 				    line_no);
45574235Smarkfen 				return (-1);
45584235Smarkfen 			}
45594235Smarkfen 			i++, line_no++;
45604235Smarkfen 			if (act_props->pattern[i] == NULL) {
45614235Smarkfen 				error_message(BAD_ERROR, IPSEC_CONF_DST_MASK,
45624235Smarkfen 				    line_no);
45634235Smarkfen 				return (-1);
45644235Smarkfen 			}
45654235Smarkfen 			ret = parse_mask(IPSEC_CONF_DST_MASK,
45664235Smarkfen 			    act_props->pattern[i],
45674235Smarkfen 			    cptr);
45684235Smarkfen 			if (ret != 0) {
45694235Smarkfen 				error_message(BAD_ERROR, IPSEC_CONF_DST_MASK,
45704235Smarkfen 				    line_no);
45714235Smarkfen 				return (-1);
45724235Smarkfen 			}
45734235Smarkfen 			break;
45744235Smarkfen 		case TOK_ulp:
45754235Smarkfen 			if (cptr->ips_ulp_prot != 0) {
45764235Smarkfen 				error_message(DUP_ERROR,
45774235Smarkfen 				    IPSEC_CONF_ULP, line_no);
45784235Smarkfen 				return (-1);
45794235Smarkfen 			}
45804235Smarkfen 			i++, line_no++;
45814235Smarkfen 			if (act_props->pattern[i] == NULL) {
45824235Smarkfen 				error_message(BAD_ERROR,
45834235Smarkfen 				    IPSEC_CONF_ULP, line_no);
45844235Smarkfen 				return (-1);
45854235Smarkfen 			}
45864235Smarkfen 			pent = getprotobyname(act_props->pattern[i]);
45874235Smarkfen 			if (pent == NULL) {
45884235Smarkfen 				int ulp;
45894235Smarkfen 				ulp = parse_int(act_props->pattern[i]);
45904235Smarkfen 				if (ulp == -1) {
45914235Smarkfen 					error_message(BAD_ERROR,
45924235Smarkfen 					    IPSEC_CONF_ULP, line_no);
45934235Smarkfen 					return (-1);
45944235Smarkfen 				}
45954235Smarkfen 				cptr->ips_ulp_prot = ulp;
45964235Smarkfen 			} else {
45974235Smarkfen 				cptr->ips_ulp_prot = pent->p_proto;
45984235Smarkfen 			}
45994235Smarkfen 			break;
46004235Smarkfen 		case TOK_type:
46014235Smarkfen 			if (cptr->has_type) {
46024235Smarkfen 				error_message(DUP_ERROR,
46034235Smarkfen 				    IPSEC_CONF_ICMP_TYPE, line_no);
46044235Smarkfen 				return (-1);
46054235Smarkfen 			}
46064235Smarkfen 
46074235Smarkfen 			i++, line_no++;
46084235Smarkfen 			type = parse_type_code(act_props->pattern[i],
46094235Smarkfen 			    icmp_type_table);
46104235Smarkfen 
46114235Smarkfen 			if (type > 65536 || type < 0) {
46124235Smarkfen 				error_message(BAD_ERROR,
46134235Smarkfen 				    IPSEC_CONF_ICMP_TYPE, line_no);
46144235Smarkfen 				return (-1);
46154235Smarkfen 			}
46164235Smarkfen 
46174235Smarkfen 			type_end = type / 256;
46184235Smarkfen 			type = type % 256;
46194235Smarkfen 
46204235Smarkfen 			if (type_end < type)
46214235Smarkfen 				type_end = type;
46224235Smarkfen 
46234235Smarkfen 			cptr->has_type = 1;
46244235Smarkfen 			cptr->ips_icmp_type = (uint8_t)type;
46254235Smarkfen 			cptr->ips_icmp_type_end = (uint8_t)type_end;
46264235Smarkfen 			break;
46274235Smarkfen 		case TOK_code:
46284235Smarkfen 			if (!cptr->has_type) {
46294235Smarkfen 				error_message(BAD_ERROR,
46304235Smarkfen 				    IPSEC_CONF_ICMP_CODE, line_no);
46314235Smarkfen 				return (-1);
46324235Smarkfen 			}
46334235Smarkfen 
46344235Smarkfen 			if (cptr->has_code) {
46354235Smarkfen 				error_message(DUP_ERROR,
46364235Smarkfen 				    IPSEC_CONF_ICMP_CODE, line_no);
46374235Smarkfen 				return (-1);
46384235Smarkfen 			}
46394235Smarkfen 
46404235Smarkfen 			i++, line_no++;
46414235Smarkfen 
46424235Smarkfen 			code = parse_type_code(act_props->pattern[i],
46434235Smarkfen 			    icmp_code_table);
46444235Smarkfen 			if (type > 65536 || type < 0) {
46454235Smarkfen 				error_message(BAD_ERROR,
46464235Smarkfen 				    IPSEC_CONF_ICMP_CODE, line_no);
46474235Smarkfen 				return (-1);
46484235Smarkfen 			}
46494235Smarkfen 			code_end = code / 256;
46504235Smarkfen 			code = code % 256;
46514235Smarkfen 
46524235Smarkfen 			if (code_end < code)
46534235Smarkfen 				code_end = code;
46544235Smarkfen 
46554235Smarkfen 			cptr->has_code = 1;
46564235Smarkfen 			cptr->ips_icmp_code = (uint8_t)code;
46574235Smarkfen 			cptr->ips_icmp_code_end = (uint8_t)code_end;
46584235Smarkfen 			break;
46594235Smarkfen 		case TOK_tunnel:
46604235Smarkfen 			if (cptr->has_tunnel == 1) {
46614235Smarkfen 				error_message(BAD_ERROR,
46624235Smarkfen 				    IPSEC_CONF_TUNNEL, line_no);
46634235Smarkfen 				return (-1);
46644235Smarkfen 			}
46654235Smarkfen 			i++, line_no++;
46664235Smarkfen 			if (act_props->pattern[i] == NULL) {
46674235Smarkfen 				error_message(BAD_ERROR,
46684235Smarkfen 				    IPSEC_CONF_TUNNEL, line_no);
46694235Smarkfen 				return (-1);
46704235Smarkfen 			}
46714235Smarkfen 
46724235Smarkfen 			if (strlcpy(tunif, act_props->pattern[i],
46734235Smarkfen 			    TUNNAMEMAXLEN) >= TUNNAMEMAXLEN) {
46744235Smarkfen 				error_message(BAD_ERROR,
46754235Smarkfen 				    IPSEC_CONF_TUNNEL, line_no);
46764235Smarkfen 				return (-1);
46774235Smarkfen 			}
46784235Smarkfen 			cptr->has_tunnel = 1;
46794235Smarkfen 			break;
46804235Smarkfen 		case TOK_negotiate:
46814235Smarkfen 			if (cptr->has_negotiate == 1) {
46824235Smarkfen 				error_message(BAD_ERROR,
46834235Smarkfen 				    IPSEC_CONF_NEGOTIATE, line_no);
46844235Smarkfen 				return (-1);
46854235Smarkfen 			}
46864235Smarkfen 			i++, line_no++;
46874235Smarkfen 			if (act_props->pattern[i] == NULL) {
46884235Smarkfen 				error_message(BAD_ERROR,
46894235Smarkfen 				    IPSEC_CONF_NEGOTIATE, line_no);
46904235Smarkfen 				return (-1);
46914235Smarkfen 			}
46924235Smarkfen 
46934235Smarkfen 			if (strncmp(act_props->pattern[i], "tunnel", 6) == 0) {
46944235Smarkfen 				cptr->ips_tunnel = B_TRUE;
46954235Smarkfen 			} else if (strncmp(
46964235Smarkfen 			    act_props->pattern[i], "transport", 9) != 0) {
46974235Smarkfen 				error_message(BAD_ERROR,
46984235Smarkfen 				    IPSEC_CONF_NEGOTIATE, line_no);
46994235Smarkfen 				return (-1);
47004235Smarkfen 			}
47014235Smarkfen 			cptr->has_negotiate = 1;
47024235Smarkfen 			break;
47034235Smarkfen 		}
47044235Smarkfen 
47054235Smarkfen 	}
47064235Smarkfen 
47074235Smarkfen 	/* Sanity check that certain tokens occur together */
47084235Smarkfen 	if (cptr->has_tunnel + cptr->has_negotiate == 1) {
47094235Smarkfen 		if (cptr->has_negotiate == 0) {
47104235Smarkfen 			error_message(REQ_ERROR, IPSEC_CONF_NEGOTIATE, line_no);
47114235Smarkfen 		} else {
47124235Smarkfen 			error_message(REQ_ERROR, IPSEC_CONF_TUNNEL, line_no);
47134235Smarkfen 		}
47144235Smarkfen 		errx(1, gettext(
47154235Smarkfen 		    "tunnel and negotiate tokens must occur together"));
47164235Smarkfen 		return (-1);
47174235Smarkfen 	}
47184235Smarkfen 
47194235Smarkfen 	/*
47204235Smarkfen 	 * Get the actions.
47214235Smarkfen 	 */
47224235Smarkfen 
47234235Smarkfen 	for (ap_num = 0; act_props->ap[ap_num].act != NULL; ap_num++) {
47244235Smarkfen 		ips_act_props_t *iap;
47254235Smarkfen 
47264235Smarkfen 		if (ap_num > 0) {
47274235Smarkfen 			/* or's only with new style */
47284235Smarkfen 			if (old_style) {
47294235Smarkfen 				(void) printf("%s\n", gettext(
47304235Smarkfen 				    "or's only with new style"));
47314235Smarkfen 				return (-1);
47324235Smarkfen 			}
47334235Smarkfen 			new_style = B_TRUE;
47344235Smarkfen 		}
47354235Smarkfen 
4736*10372Sdanmcd@sun.com 		ipsec_aalg = ipsec_ealg = ipsec_eaalg = auth_covered = B_FALSE;
47374235Smarkfen 		tok_count = 0;
47384235Smarkfen 
47394235Smarkfen 		for (k = 0; action_table[k].string; k++) {
47404235Smarkfen 			if (strcmp(act_props->ap[ap_num].act,
47414235Smarkfen 			    action_table[k].string) == 0)
47424235Smarkfen 				break;
47434235Smarkfen 		}
47444235Smarkfen 		/*
47454235Smarkfen 		 * The following thing should never happen as
47464235Smarkfen 		 * we have already tested for its validity in parse.
47474235Smarkfen 		 */
47484235Smarkfen 		if (action_table[k].string == NULL) {
47494235Smarkfen 			warnx(gettext("(form act)Invalid action on line "
47504235Smarkfen 			    "%d: %s"), (arg_indices[line_no] == 0) ? 1 :
47514235Smarkfen 			    arg_indices[line_no],
47524235Smarkfen 			    act_props->ap[ap_num].act);
47534235Smarkfen 			warnx("%s", act_props->ap[ap_num].act);
47544235Smarkfen 			return (-1);
47554235Smarkfen 		}
47564235Smarkfen 
47574235Smarkfen 		/* we have a good action alloc an iap */
47584235Smarkfen 		iap = alloc_iap(cptr);
47594235Smarkfen 
47604235Smarkfen 		iap->iap_action = action_table[k].value;
47614235Smarkfen 		iap->iap_act_tok = action_table[k].tok_val;
47624235Smarkfen 
47634235Smarkfen 		switch (action_table[k].tok_val) {
47644235Smarkfen 		case TOK_apply:
47654235Smarkfen 			cptr->ips_dir = SPD_RULE_FLAG_OUTBOUND;
47664235Smarkfen 			break;
47674235Smarkfen 		case TOK_permit:
47684235Smarkfen 			cptr->ips_dir = SPD_RULE_FLAG_INBOUND;
47694235Smarkfen 			break;
47704235Smarkfen 		case TOK_ipsec:
47714235Smarkfen 			if (old_style) {
47724235Smarkfen 				/* Using saddr/daddr with ipsec action. */
47734235Smarkfen 				if (!dir) {
47744235Smarkfen 					/* No direction specified */
47754235Smarkfen 					error_message(REQ_ERROR,
47764235Smarkfen 					    IPSEC_CONF_IPSEC_DIR, line_no);
47774235Smarkfen 					return (-1);
47784235Smarkfen 				}
47794235Smarkfen 				if (cptr->ips_dir == SPD_RULE_FLAG_INBOUND)
47804235Smarkfen 					/*
47814235Smarkfen 					 * Need to swap addresses if
47824235Smarkfen 					 * 'dir in' or translation to
47834235Smarkfen 					 * laddr/raddr will be incorrect.
47844235Smarkfen 					 */
47854235Smarkfen 					cptr->swap = 1;
47864235Smarkfen 			}
47874235Smarkfen 			if (!dir)
47884235Smarkfen 				cptr->ips_dir =
47894235Smarkfen 				    SPD_RULE_FLAG_INBOUND
47904235Smarkfen 				    |SPD_RULE_FLAG_OUTBOUND;
47914235Smarkfen 			break;
47924235Smarkfen 		case TOK_bypass:
4793*10372Sdanmcd@sun.com 		case TOK_drop:
4794*10372Sdanmcd@sun.com 			is_no_alg = B_TRUE;
47954235Smarkfen 			break;
47964235Smarkfen 		}
47974235Smarkfen 
47984235Smarkfen 		line_no++;
47994235Smarkfen 		/*
48004235Smarkfen 		 * Get the properties. NULL properties is not valid.
48014235Smarkfen 		 * Later checks will catch it.
48024235Smarkfen 		 */
48034235Smarkfen 		for (i = 0; act_props->ap[ap_num].prop[i]; i++, line_no++) {
48044235Smarkfen 			for (j = 0; property_table[j].string; j++) {
48054235Smarkfen 				if (strcmp(act_props->ap[ap_num].prop[i],
48064235Smarkfen 				    property_table[j].string) == 0) {
48074235Smarkfen 					break;
48084235Smarkfen 				}
48094235Smarkfen 			}
48104235Smarkfen 			if (property_table[j].string == NULL) {
48114235Smarkfen 				warnx(gettext("Invalid properties on line "
48124235Smarkfen 				    "%d: %s"),
48135120Smarkfen 				    (arg_indices[line_no] == 0) ?
48144235Smarkfen 				    1 : arg_indices[line_no],
48154235Smarkfen 				    act_props->ap[ap_num].prop[i]);
48164235Smarkfen 				return (-1);
48174235Smarkfen 			}
48184235Smarkfen 
48194235Smarkfen 			iap->iap_attr_tok[tok_count++]
48204235Smarkfen 			    = property_table[j].value;
48214235Smarkfen 
48224235Smarkfen 			switch (property_table[j].value) {
48234235Smarkfen 			case SPD_ATTR_AH_AUTH:
48244235Smarkfen 				if (ipsec_aalg) {
48254235Smarkfen 					error_message(DUP_ERROR,
48264235Smarkfen 					    IPSEC_CONF_IPSEC_AALGS, line_no);
48274235Smarkfen 					return (-1);
48284235Smarkfen 				}
48294235Smarkfen 				i++, line_no++;
48304235Smarkfen 				if (act_props->ap[ap_num].prop[i] == NULL) {
48314235Smarkfen 					error_message(BAD_ERROR,
48324235Smarkfen 					    IPSEC_CONF_IPSEC_AALGS, line_no);
48334235Smarkfen 					return (-1);
48344235Smarkfen 				}
48354235Smarkfen 				ret = parse_ipsec_alg(
48364235Smarkfen 				    act_props->ap[ap_num].prop[i],
48374235Smarkfen 				    iap, SPD_ATTR_AH_AUTH);
48384235Smarkfen 				if (ret == -2) {
48394235Smarkfen 					/* "none" - ignore */
48404235Smarkfen 					break;
48414235Smarkfen 				}
48424235Smarkfen 				if (ret != 0) {
48434235Smarkfen 					error_message(BAD_ERROR,
48444235Smarkfen 					    IPSEC_CONF_IPSEC_AALGS, line_no);
48454235Smarkfen 					return (-1);
48464235Smarkfen 				}
48474235Smarkfen 				ipsec_aalg = B_TRUE;
4848*10372Sdanmcd@sun.com 				auth_covered = B_TRUE;
48494235Smarkfen 				break;
48504235Smarkfen 			case SPD_ATTR_ESP_ENCR:
48514235Smarkfen 				/*
48524235Smarkfen 				 * If this option was not given
48534235Smarkfen 				 * and encr_auth_algs was given,
48544235Smarkfen 				 * we provide null-encryption.  We do the
48554235Smarkfen 				 * setting after we parse all the options.
48564235Smarkfen 				 */
48574235Smarkfen 				if (ipsec_ealg) {
48584235Smarkfen 					error_message(DUP_ERROR,
48594235Smarkfen 					    IPSEC_CONF_IPSEC_EALGS, line_no);
48604235Smarkfen 					return (-1);
48614235Smarkfen 				}
48624235Smarkfen 				i++, line_no++;
48634235Smarkfen 				if (act_props->ap[ap_num].prop[i] == NULL) {
48644235Smarkfen 					error_message(BAD_ERROR,
48654235Smarkfen 					    IPSEC_CONF_IPSEC_EALGS, line_no);
48664235Smarkfen 					return (-1);
48674235Smarkfen 				}
48684235Smarkfen 				ret = parse_ipsec_alg(
48694235Smarkfen 				    act_props->ap[ap_num].prop[i],
48704235Smarkfen 				    iap, SPD_ATTR_ESP_ENCR);
48714235Smarkfen 				if (ret == -2) {
48724235Smarkfen 					/* "none" - ignore */
48734235Smarkfen 					break;
48744235Smarkfen 				}
48754235Smarkfen 				if (ret != 0) {
48764235Smarkfen 					error_message(BAD_ERROR,
48774235Smarkfen 					    IPSEC_CONF_IPSEC_EALGS, line_no);
48784235Smarkfen 					return (-1);
48794235Smarkfen 				}
4880*10372Sdanmcd@sun.com 				/*
4881*10372Sdanmcd@sun.com 				 * XXX FUTURE TODO -- set auth_covered here
4882*10372Sdanmcd@sun.com 				 * if the encryption algorithm is self-
4883*10372Sdanmcd@sun.com 				 * authenticating, e.g. AES-CCM/GCM.
4884*10372Sdanmcd@sun.com 				 */
48854235Smarkfen 				ipsec_ealg = B_TRUE;
48864235Smarkfen 				break;
48874235Smarkfen 			case SPD_ATTR_ESP_AUTH:
48884235Smarkfen 				/*
48894235Smarkfen 				 * If this option was not given and encr_algs
48904235Smarkfen 				 * option was given, we still pass a default
48914235Smarkfen 				 * value in ipsc_esp_auth_algs. This is to
48924235Smarkfen 				 * encourage the use of authentication with
48934235Smarkfen 				 * ESP.
48944235Smarkfen 				 */
48954235Smarkfen 				if (ipsec_eaalg) {
48964235Smarkfen 					error_message(DUP_ERROR,
48974235Smarkfen 					    IPSEC_CONF_IPSEC_EAALGS, line_no);
48984235Smarkfen 					return (-1);
48994235Smarkfen 				}
4900*10372Sdanmcd@sun.com 				/*
4901*10372Sdanmcd@sun.com 				 * XXX FUTURE QUESTION -- error if
4902*10372Sdanmcd@sun.com 				 * auth_covered and ipsec_aalg false
4903*10372Sdanmcd@sun.com 				 * (e.g. AES-CCM/GCM)?
4904*10372Sdanmcd@sun.com 				 */
49054235Smarkfen 				i++, line_no++;
49064235Smarkfen 				if (act_props->ap[ap_num].prop[i] == NULL) {
49074235Smarkfen 					error_message(BAD_ERROR,
49084235Smarkfen 					    IPSEC_CONF_IPSEC_EAALGS, line_no);
49094235Smarkfen 					return (-1);
49104235Smarkfen 				}
49114235Smarkfen 				ret = parse_ipsec_alg(
49124235Smarkfen 				    act_props->ap[ap_num].prop[i],
49134235Smarkfen 				    iap, SPD_ATTR_ESP_AUTH);
49144235Smarkfen 				if (ret == -2) {
49154235Smarkfen 					/* "none" - ignore */
49164235Smarkfen 					break;
49174235Smarkfen 				}
49184235Smarkfen 				if (ret != 0) {
49194235Smarkfen 					error_message(BAD_ERROR,
49204235Smarkfen 					    IPSEC_CONF_IPSEC_EAALGS, line_no);
49214235Smarkfen 					return (-1);
49224235Smarkfen 				}
49234235Smarkfen 				ipsec_eaalg = B_TRUE;
4924*10372Sdanmcd@sun.com 				auth_covered = B_TRUE;
49254235Smarkfen 				break;
49264235Smarkfen 			case IPS_SA:
49274235Smarkfen 				i++, line_no++;
49284235Smarkfen 				if (act_props->ap[ap_num].prop[i] == NULL) {
49294235Smarkfen 					error_message(BAD_ERROR,
49304235Smarkfen 					    IPSEC_CONF_IPSEC_SA, line_no);
49314235Smarkfen 					return (-1);
49324235Smarkfen 				}
49334235Smarkfen 
49344235Smarkfen 				if (strcmp(act_props->ap[ap_num].prop[i],
49354235Smarkfen 				    "unique") == 0) {
49364235Smarkfen 					iap->iap_attr |= SPD_APPLY_UNIQUE;
49374235Smarkfen 				} else if (strcmp(act_props->ap[ap_num].prop[i],
49384235Smarkfen 				    "shared") != 0) {
49394235Smarkfen 					/* "shared" is default. */
49404235Smarkfen 					error_message(BAD_ERROR,
49414235Smarkfen 					    IPSEC_CONF_IPSEC_SA, line_no);
49424235Smarkfen 					return (-1);
49434235Smarkfen 				}
49444235Smarkfen 
49454235Smarkfen 				break;
49464235Smarkfen 			case IPS_DIR:
49474235Smarkfen 				if (dir) {
49484235Smarkfen 					error_message(DUP_ERROR,
49494235Smarkfen 					    IPSEC_CONF_IPSEC_DIR, line_no);
49504235Smarkfen 					return (-1);
49514235Smarkfen 				}
49524235Smarkfen 				if (new_style) {
49534235Smarkfen 					error_message(BAD_ERROR,
49544235Smarkfen 					    IPSEC_CONF_IPSEC_DIR, line_no);
49554235Smarkfen 					return (-1);
49564235Smarkfen 				}
49574235Smarkfen 				old_style = B_TRUE;
49584235Smarkfen 				dir = B_TRUE;
49594235Smarkfen 				i++, line_no++;
49604235Smarkfen 				if (act_props->ap[ap_num].prop[i] == NULL) {
49614235Smarkfen 					error_message(BAD_ERROR,
49624235Smarkfen 					    IPSEC_CONF_IPSEC_DIR, line_no);
49634235Smarkfen 					return (-1);
49644235Smarkfen 				}
49654235Smarkfen 				if (strcmp(act_props->ap[ap_num].prop[i],
49664235Smarkfen 				    "out") == 0) {
49674235Smarkfen 					cptr->ips_dir = SPD_RULE_FLAG_OUTBOUND;
49684235Smarkfen 				} else if (strcmp(act_props->ap[ap_num].prop[i],
49694235Smarkfen 				    "in") == 0) {
49704235Smarkfen 					cptr->ips_dir = SPD_RULE_FLAG_INBOUND;
49714235Smarkfen 				} else {
49724235Smarkfen 					error_message(BAD_ERROR,
49735120Smarkfen 					    IPSEC_CONF_IPSEC_DIR, line_no);
49744235Smarkfen 					return (-1);
49754235Smarkfen 				}
49764235Smarkfen 				if ((cptr->ips_dir & SPD_RULE_FLAG_INBOUND) &&
49775120Smarkfen 				    iap->iap_act_tok == TOK_apply) {
49784235Smarkfen 					warnx(gettext("Direction"
49794235Smarkfen 					    " in conflict with action"));
49804235Smarkfen 					return (-1);
49814235Smarkfen 				}
49824235Smarkfen 				if ((cptr->ips_dir & SPD_RULE_FLAG_OUTBOUND) &&
49835120Smarkfen 				    iap->iap_act_tok == TOK_permit) {
49844235Smarkfen 					warnx(gettext("Direction"
49854235Smarkfen 					    "in conflict with action"));
49864235Smarkfen 					return (-1);
49874235Smarkfen 				}
49884235Smarkfen 
49894235Smarkfen 				break;
49904235Smarkfen 			}
49914235Smarkfen 		}
49924235Smarkfen 
4993*10372Sdanmcd@sun.com 		/* Warn here about no authentication! */
4994*10372Sdanmcd@sun.com 		if (!auth_covered && !is_no_alg) {
4995*10372Sdanmcd@sun.com 			warnx(gettext("DANGER:  Rule on line %d "
4996*10372Sdanmcd@sun.com 			    "has encryption with no authentication."),
4997*10372Sdanmcd@sun.com 			    arg_indices[line_no] == 0 ? 1 :
4998*10372Sdanmcd@sun.com 			    arg_indices[line_no]);
4999*10372Sdanmcd@sun.com 		}
5000*10372Sdanmcd@sun.com 
50014235Smarkfen 		if (!ipsec_ealg && ipsec_eaalg) {
50024235Smarkfen 			/*
50034235Smarkfen 			 * If the user has specified the auth alg to be used
50044235Smarkfen 			 * with encryption and did not provide a encryption
50054235Smarkfen 			 * algorithm, provide null encryption.
50064235Smarkfen 			 */
50074235Smarkfen 			iap->iap_eencr.alg_id = SADB_EALG_NULL;
50084235Smarkfen 			ipsec_ealg = B_TRUE;
50094235Smarkfen 		}
50104235Smarkfen 
50114235Smarkfen 		/* Set the level of IPSEC protection we want */
50124235Smarkfen 		if (ipsec_aalg && (ipsec_ealg || ipsec_eaalg)) {
50134235Smarkfen 			iap->iap_attr |= SPD_APPLY_AH|SPD_APPLY_ESP;
50144235Smarkfen 		} else if (ipsec_aalg) {
50154235Smarkfen 			iap->iap_attr |= SPD_APPLY_AH;
50164235Smarkfen 		} else if (ipsec_ealg || ipsec_eaalg) {
50174235Smarkfen 			iap->iap_attr |= SPD_APPLY_ESP;
50184235Smarkfen 		}
50194235Smarkfen 
50204235Smarkfen 		/* convert src/dst to local/remote */
50214235Smarkfen 		if (!new_style) {
50224235Smarkfen 			switch (cptr->ips_acts->iap_act_tok) {
50234235Smarkfen 			case TOK_apply:
50244235Smarkfen 				/* outbound */
50254235Smarkfen 				/* src=local, dst=remote */
50264235Smarkfen 				/* this is ok. */
50274235Smarkfen 				break;
50284235Smarkfen 
50294235Smarkfen 			case TOK_permit:
50304235Smarkfen 				/* inbound */
50314235Smarkfen 				/* src=remote, dst=local */
50324235Smarkfen 				/* switch */
50334235Smarkfen 				cptr->swap = 1;
50344235Smarkfen 				break;
50354235Smarkfen 			case TOK_bypass:
50364235Smarkfen 			case TOK_drop:
50374235Smarkfen 				/* check the direction for what to do */
50384235Smarkfen 				if (cptr->ips_dir == SPD_RULE_FLAG_INBOUND)
50394235Smarkfen 					cptr->swap = 1;
50404235Smarkfen 				break;
50414235Smarkfen 			default:
50424235Smarkfen 				break;
50434235Smarkfen 			}
50444235Smarkfen 		}
50454235Smarkfen 		/* Validate the properties */
50464235Smarkfen 		if (ret = validate_properties(iap, dir,
50474235Smarkfen 		    (ipsec_aalg || ipsec_ealg || ipsec_eaalg))) {
50484235Smarkfen 			return (ret);
50494235Smarkfen 		}
50504235Smarkfen 	}
50514235Smarkfen 
50524235Smarkfen 	return (0);
50534235Smarkfen 
50544235Smarkfen }
50554235Smarkfen 
50564235Smarkfen static int
50574235Smarkfen print_cmd_buf(FILE *fp, int error)
50584235Smarkfen {
50594235Smarkfen 	*(cbuf + cbuf_offset) = '\0';
50604235Smarkfen 
50614235Smarkfen 	if (fp == stderr) {
50624235Smarkfen 		if (error != EEXIST) {
50634235Smarkfen 			warnx(gettext("Malformed command (fatal):\n%s"), cbuf);
50644235Smarkfen 			return (0);
50654235Smarkfen 		}
50664235Smarkfen 		if (ipsecconf_qflag) {
50674235Smarkfen 			return (0);
50684235Smarkfen 		}
50694235Smarkfen 		warnx(gettext("Duplicate policy entry (ignored):\n%s"), cbuf);
50704235Smarkfen 	} else {
50714235Smarkfen 		if (fprintf(fp, "%s", cbuf) == -1) {
50724235Smarkfen 			warn("fprintf");
50734235Smarkfen 			return (-1);
50744235Smarkfen 		}
50754235Smarkfen 	}
50764235Smarkfen 
50774235Smarkfen 	return (0);
50784235Smarkfen }
50794235Smarkfen 
50804235Smarkfen #ifdef	DEBUG
50814235Smarkfen 
50824235Smarkfen static uchar_t *
50834235Smarkfen addr_ptr(int isv4, struct in6_addr *addr6, struct in_addr *addr4)
50844235Smarkfen {
50854235Smarkfen 	if (isv4) {
50864235Smarkfen 		IN6_V4MAPPED_TO_INADDR(addr6, addr4);
50874235Smarkfen 		return ((uchar_t *)&addr4->s_addr);
50884235Smarkfen 	} else {
50894235Smarkfen 		return ((uchar_t *)&addr6->s6_addr);
50904235Smarkfen 	}
50914235Smarkfen }
50924235Smarkfen 
50934235Smarkfen static void
50944235Smarkfen dump_algreq(const char *tag, algreq_t *alg)
50954235Smarkfen {
50964235Smarkfen 	(void) printf("%s algid %d, bits %d..%d\n",
50974235Smarkfen 	    tag, alg->alg_id, alg->alg_minbits, alg->alg_maxbits);
50984235Smarkfen }
50994235Smarkfen 
51004235Smarkfen static void
51014235Smarkfen dump_conf(ips_conf_t *conf)
51024235Smarkfen {
51034235Smarkfen 	boolean_t isv4 = conf->ips_isv4;
51044235Smarkfen 	struct in_addr addr;
51054235Smarkfen 	char buf[INET6_ADDRSTRLEN];
51064235Smarkfen 	int af;
51074235Smarkfen 	ips_act_props_t *iap = conf->ips_acts;
51084235Smarkfen 
51094235Smarkfen 	af = isv4 ? AF_INET : AF_INET6;
51104235Smarkfen 
51114235Smarkfen 	(void) printf("Source Addr is %s\n",
51124235Smarkfen 	    inet_ntop(af, addr_ptr(isv4, &conf->ips_src_addr_v6, &addr),
51135120Smarkfen 	    buf, INET6_ADDRSTRLEN));
51144235Smarkfen 
51154235Smarkfen 	(void) printf("Dest Addr is %s\n",
51164235Smarkfen 	    inet_ntop(af, addr_ptr(isv4, &conf->ips_dst_addr_v6, &addr),
51175120Smarkfen 	    buf, INET6_ADDRSTRLEN));
51184235Smarkfen 
51194235Smarkfen 	(void) printf("Source Mask is %s\n",
51204235Smarkfen 	    inet_ntop(af, addr_ptr(isv4, &conf->ips_src_mask_v6, &addr),
51215120Smarkfen 	    buf, INET6_ADDRSTRLEN));
51224235Smarkfen 
51234235Smarkfen 	(void) printf("Dest Mask is %s\n",
51244235Smarkfen 	    inet_ntop(af, addr_ptr(isv4, &conf->ips_dst_mask_v6, &addr),
51255120Smarkfen 	    buf, INET6_ADDRSTRLEN));
51264235Smarkfen 
51274235Smarkfen 	(void) printf("Source port %d\n", ntohs(conf->ips_src_port_min));
51284235Smarkfen 	(void) printf("Dest port %d\n", ntohs(conf->ips_dst_port_min));
51294235Smarkfen 	(void) printf("ULP %d\n", conf->ips_ulp_prot);
51304235Smarkfen 
51314235Smarkfen 	(void) printf("ICMP type %d-%d code %d-%d", conf->ips_icmp_type,
51324235Smarkfen 	    conf->ips_icmp_type_end,
51334235Smarkfen 	    conf->ips_icmp_code,
51344235Smarkfen 	    conf->ips_icmp_code_end);
51354235Smarkfen 
51364235Smarkfen 	while (iap != NULL) {
51374235Smarkfen 		(void) printf("------------------------------------\n");
51384235Smarkfen 		(void) printf("IPsec act is %d\n", iap->iap_action);
51394235Smarkfen 		(void) printf("IPsec attr is %d\n", iap->iap_attr);
51404235Smarkfen 		dump_algreq("AH authentication", &iap->iap_aauth);
51414235Smarkfen 		dump_algreq("ESP authentication", &iap->iap_eauth);
51424235Smarkfen 		dump_algreq("ESP encryption", &iap->iap_eencr);
51434235Smarkfen 		(void) printf("------------------------------------\n");
51444235Smarkfen 		iap = iap->iap_next;
51454235Smarkfen 	}
51464235Smarkfen 
51474235Smarkfen 	(void) fflush(stdout);
51484235Smarkfen }
51494235Smarkfen #endif	/* DEBUG */
51504235Smarkfen 
51514235Smarkfen 
51524235Smarkfen static int
51534235Smarkfen ipsec_conf_add(boolean_t just_check, boolean_t smf_managed)
51544235Smarkfen {
51554235Smarkfen 	act_prop_t *act_props = malloc(sizeof (act_prop_t));
51564235Smarkfen 	ips_conf_t conf;
51574235Smarkfen 	FILE *fp, *policy_fp;
51584235Smarkfen 	int ret, flushret, i, j, diag, num_rules, good_rules;
51594235Smarkfen 	char *warning = gettext(
51605120Smarkfen 	    "\tWARNING : New policy entries that are being added may\n "
51615120Smarkfen 	    "\taffect the existing connections. Existing connections\n"
51625120Smarkfen 	    "\tthat are not subjected to policy constraints, may be\n"
51635120Smarkfen 	    "\tsubjected to policy constraints because of the new\n"
51645120Smarkfen 	    "\tpolicy. This can disrupt the communication of the\n"
51655120Smarkfen 	    "\texisting connections.\n\n");
51664235Smarkfen 
51674235Smarkfen 	boolean_t first_time = B_TRUE;
51684235Smarkfen 	num_rules = 0;
51694235Smarkfen 	good_rules = 0;
51704235Smarkfen 
51714235Smarkfen 	if (act_props == NULL) {
51724235Smarkfen 		warn(gettext("memory"));
51734235Smarkfen 		return (-1);
51744235Smarkfen 	}
51754235Smarkfen 
51764235Smarkfen 	if (strcmp(filename, "-") == 0)
51774235Smarkfen 		fp = stdin;
51784235Smarkfen 	else
51794235Smarkfen 		fp = fopen(filename, "r");
51804235Smarkfen 
51814235Smarkfen 	/*
51824235Smarkfen 	 * Treat the non-existence of a policy file as a special
51834235Smarkfen 	 * case when ipsecconf is being managed by smf(5).
51844235Smarkfen 	 * The assumption is the administrator has not yet
51854235Smarkfen 	 * created a policy file, this should not force the service
51864235Smarkfen 	 * into maintenance mode.
51874235Smarkfen 	 */
51884235Smarkfen 
51894235Smarkfen 	if (fp == NULL) {
51904235Smarkfen 		if (smf_managed) {
51914235Smarkfen 			(void) fprintf(stdout, gettext(
51924235Smarkfen 			    "Policy configuration file (%s) does not exist.\n"
51934235Smarkfen 			    "IPsec policy not configured.\n"), filename);
51944235Smarkfen 			return (0);
51954235Smarkfen 		}
51964235Smarkfen 		warn(gettext("%s : Policy config file cannot be opened"),
51974235Smarkfen 		    filename);
51984235Smarkfen 		usage();
51994235Smarkfen 		return (-1);
52004235Smarkfen 	}
52014235Smarkfen 	/*
52024235Smarkfen 	 * This will create the file if it does not exist.
52034235Smarkfen 	 * Make sure the umask is right.
52044235Smarkfen 	 */
52054235Smarkfen 	(void) umask(0022);
52064235Smarkfen 	policy_fp = fopen(POLICY_CONF_FILE, "a");
52074235Smarkfen 	if (policy_fp == NULL) {
52084235Smarkfen 		warn(gettext("%s cannot be opened"), POLICY_CONF_FILE);
52094235Smarkfen 		return (-1);
52104235Smarkfen 	}
52114235Smarkfen 
52124235Smarkfen 	/*
52134235Smarkfen 	 * Pattern, action, and properties are allocated in
52144235Smarkfen 	 * parse_pattern_or_prop and in parse_action (called by
52154235Smarkfen 	 * parse_one) as we parse arguments.
52164235Smarkfen 	 */
52175120Smarkfen 	while ((ret = parse_one(fp, act_props)) != PARSE_EOF) {
52185120Smarkfen 		num_rules++;
52195120Smarkfen 		if (ret != 0) {
52205120Smarkfen 			(void) print_cmd_buf(stderr, NOERROR);
52215120Smarkfen 			continue;
52225120Smarkfen 		}
52234235Smarkfen 
52244235Smarkfen 		/*
52254235Smarkfen 		 * If there is no action and parse returned success,
52264235Smarkfen 		 * it means that there is nothing to add.
52274235Smarkfen 		 */
52284235Smarkfen 		if (act_props->pattern[0] == NULL &&
52294235Smarkfen 		    act_props->ap[0].act == NULL)
52304235Smarkfen 				break;
52314235Smarkfen 
52324235Smarkfen 		ret = form_ipsec_conf(act_props, &conf);
52334235Smarkfen 		if (ret != 0) {
52344235Smarkfen 			warnx(gettext("form_ipsec_conf error"));
52354235Smarkfen 			(void) print_cmd_buf(stderr, NOERROR);
52364475Spwernau 			/* Reset globals before trying the next rule. */
52374475Spwernau 			if (shp != NULL) {
52384475Spwernau 				freehostent(shp);
52394475Spwernau 				shp = NULL;
52404475Spwernau 			}
52414475Spwernau 			if (dhp != NULL) {
52424475Spwernau 				freehostent(dhp);
52434475Spwernau 				dhp = NULL;
52444475Spwernau 			}
52454475Spwernau 			splen = 0;
52464475Spwernau 			dplen = 0;
52474235Smarkfen 			continue;
52484235Smarkfen 		}
52494235Smarkfen 
52504235Smarkfen 		good_rules++;
52514235Smarkfen 
52524235Smarkfen 		if (first_time) {
52534235Smarkfen 			/*
52544235Smarkfen 			 * Time to assume that there are valid policy entries.
52554235Smarkfen 			 * If the IPsec kernel modules are not loaded this
52564235Smarkfen 			 * will load them now.
52574235Smarkfen 			 */
52584235Smarkfen 			first_time = B_FALSE;
52594235Smarkfen 			fetch_algorithms();
52604235Smarkfen 			ipsec_conf_admin(SPD_CLONE);
52614235Smarkfen 		}
52624235Smarkfen 
52634235Smarkfen 		/*
52644235Smarkfen 		 * shp, dhp, splen, and dplen are globals set by
52654235Smarkfen 		 * form_ipsec_conf() while parsing the addresses.
52664235Smarkfen 		 */
52674235Smarkfen 		if (shp == NULL && dhp == NULL) {
52684235Smarkfen 			switch (do_port_adds(&conf)) {
52694235Smarkfen 			case 0:
52704235Smarkfen 				/* no error */
52714235Smarkfen 				break;
52724235Smarkfen 			case EEXIST:
52734235Smarkfen 				/* duplicate entries, continue adds */
52744235Smarkfen 				(void) print_cmd_buf(stderr, EEXIST);
52754235Smarkfen 				goto next;
52764235Smarkfen 			default:
52774235Smarkfen 				/* other error, bail */
52784235Smarkfen 				ret = -1;
52794235Smarkfen 				goto bail;
52804235Smarkfen 			}
52814235Smarkfen 		} else {
52824235Smarkfen 			ret = do_address_adds(&conf, &diag);
52834235Smarkfen 			switch (ret) {
52844235Smarkfen 			case 0:
52854235Smarkfen 				/* no error. */
52864235Smarkfen 				break;
52874235Smarkfen 			case EEXIST:
52884235Smarkfen 				(void) print_cmd_buf(stderr, EEXIST);
52894235Smarkfen 				goto next;
52904235Smarkfen 			case EBUSY:
52914235Smarkfen 				warnx(gettext(
52925120Smarkfen 				    "Can't set mask and /NN prefix."));
52934235Smarkfen 				ret = -1;
52944235Smarkfen 				break;
52954235Smarkfen 			case ENOENT:
52964235Smarkfen 				warnx(gettext("Cannot find tunnel "
52974235Smarkfen 				    "interface %s."), interface_name);
52984235Smarkfen 				ret = -1;
52994235Smarkfen 				break;
53004235Smarkfen 			case EINVAL:
53014235Smarkfen 				/*
53024235Smarkfen 				 * PF_POLICY didn't like what we sent.  We
53034235Smarkfen 				 * can't check all input up here, but we
53044235Smarkfen 				 * do in-kernel.
53054235Smarkfen 				 */
53064235Smarkfen 				warnx(gettext("PF_POLICY invalid input:\n\t%s"),
53074235Smarkfen 				    spdsock_diag(diag));
53084235Smarkfen 				break;
53094235Smarkfen 			case EOPNOTSUPP:
53104235Smarkfen 				warnx(gettext("Can't set /NN"
53115120Smarkfen 				    " prefix on multi-host name."));
53124235Smarkfen 				ret = -1;
53134235Smarkfen 				break;
53144235Smarkfen 			case ERANGE:
53154235Smarkfen 				warnx(gettext("/NN prefix is too big!"));
53164235Smarkfen 				ret = -1;
53174235Smarkfen 				break;
53184235Smarkfen 			case ESRCH:
53194235Smarkfen 				warnx(gettext("No matching IPv4 or "
53205120Smarkfen 				    "IPv6 saddr/daddr pairs"));
53214235Smarkfen 				ret = -1;
53224235Smarkfen 				break;
53234235Smarkfen 			default:
53244235Smarkfen 				/* Should never get here. */
53254235Smarkfen 				errno = ret;
53264235Smarkfen 				warn(gettext("Misc. error"));
53274235Smarkfen 				ret = -1;
53284235Smarkfen 			}
53294235Smarkfen 			if (ret == -1)
53304235Smarkfen 				goto bail;
53314235Smarkfen 		}
53324235Smarkfen 
53334235Smarkfen 		/*
53344235Smarkfen 		 * Go ahead and add policy entries to config file.
53354235Smarkfen 		 * The # should help re-using the ipsecpolicy.conf
53364235Smarkfen 		 * for input again as # will be treated as comment.
53374235Smarkfen 		 */
53384235Smarkfen 		if (fprintf(policy_fp, "%s %lld \n", INDEX_TAG,
53394235Smarkfen 		    conf.ips_policy_index) == -1) {
53404235Smarkfen 			warn("fprintf");
53414235Smarkfen 			warnx(gettext("Addition incomplete, Please "
53424235Smarkfen 			    "flush all the entries and re-configure :"));
53434235Smarkfen 			reconfigure();
53444235Smarkfen 			ret = -1;
53454235Smarkfen 			break;
53464235Smarkfen 		}
53474235Smarkfen 		if (print_cmd_buf(policy_fp, NOERROR) == -1) {
53484235Smarkfen 			warnx(gettext("Addition incomplete. Please "
53494235Smarkfen 			    "flush all the entries and re-configure :"));
53504235Smarkfen 			reconfigure();
53514235Smarkfen 			ret = -1;
53524235Smarkfen 			break;
53534235Smarkfen 		}
53544235Smarkfen 		/*
53554235Smarkfen 		 * We add one newline by default to separate out the
53564235Smarkfen 		 * entries. If the last character is not a newline, we
53574235Smarkfen 		 * insert a newline for free. This makes sure that all
53584235Smarkfen 		 * entries look consistent in the file.
53594235Smarkfen 		 */
53604235Smarkfen 		if (*(cbuf + cbuf_offset - 1) == '\n') {
53614235Smarkfen 			if (fprintf(policy_fp, "\n") == -1) {
53624235Smarkfen 				warn("fprintf");
53634235Smarkfen 				warnx(gettext("Addition incomplete. "
53644235Smarkfen 				    "Please flush all the entries and "
53654235Smarkfen 				    "re-configure :"));
53664235Smarkfen 				reconfigure();
53674235Smarkfen 				ret = -1;
53684235Smarkfen 				break;
53694235Smarkfen 			}
53704235Smarkfen 		} else {
53714235Smarkfen 			if (fprintf(policy_fp, "\n\n") == -1) {
53724235Smarkfen 				warn("fprintf");
53734235Smarkfen 				warnx(gettext("Addition incomplete. "
53744235Smarkfen 				    "Please flush all the entries and "
53754235Smarkfen 				    "re-configure :"));
53764235Smarkfen 				reconfigure();
53774235Smarkfen 				ret = -1;
53784235Smarkfen 				break;
53794235Smarkfen 			}
53804235Smarkfen 		}
53814235Smarkfen next:
53824235Smarkfen 		/*
53834235Smarkfen 		 * Make sure this gets to the disk before
53844235Smarkfen 		 * we parse the next entry.
53854235Smarkfen 		 */
53864235Smarkfen 		(void) fflush(policy_fp);
53874235Smarkfen 		for (i = 0; act_props->pattern[i] != NULL; i++)
53884235Smarkfen 			free(act_props->pattern[i]);
53894235Smarkfen 		for (j = 0; act_props->ap[j].act != NULL; j++) {
53904235Smarkfen 			free(act_props->ap[j].act);
53914235Smarkfen 			for (i = 0; act_props->ap[j].prop[i] != NULL; i++)
53924235Smarkfen 				free(act_props->ap[j].prop[i]);
53934235Smarkfen 		}
53944235Smarkfen 	}
53955120Smarkfen 	if (ret == PARSE_EOF)
53965120Smarkfen 		ret = 0; /* Not an error */
53974235Smarkfen bail:
53984235Smarkfen 	if (ret == -1) {
53994235Smarkfen 		(void) print_cmd_buf(stderr, EINVAL);
54004235Smarkfen 		for (i = 0; act_props->pattern[i] != NULL; i++)
54014235Smarkfen 			free(act_props->pattern[i]);
54024235Smarkfen 		for (j = 0; act_props->ap[j].act != NULL; j++) {
54034235Smarkfen 			free(act_props->ap[j].act);
54044235Smarkfen 			for (i = 0; act_props->ap[j].prop[i] != NULL; i++)
54054235Smarkfen 				free(act_props->ap[j].prop[i]);
54064235Smarkfen 		}
54074235Smarkfen 	}
54084235Smarkfen #ifdef DEBUG_HEAVY
54094235Smarkfen 	(void) printf("ipsec_conf_add: ret val = %d\n", ret);
54104235Smarkfen 	(void) fflush(stdout);
54114235Smarkfen #endif
54125120Smarkfen 	if (num_rules == 0 && ret == 0) {
54134475Spwernau 		nuke_adds();
54144235Smarkfen 		(void) restore_all_signals();
54154235Smarkfen 		(void) unlock(lfd);
54164235Smarkfen 		EXIT_OK("Policy file does not contain any valid rules.");
54174235Smarkfen 	}
54184235Smarkfen 	if (num_rules != good_rules) {
54194235Smarkfen 		/* This is an error */
54204475Spwernau 		nuke_adds();
54214235Smarkfen 		(void) restore_all_signals();
54224235Smarkfen 		(void) unlock(lfd);
54234235Smarkfen 		EXIT_BADCONFIG2("%d policy rule(s) contained errors.",
54244235Smarkfen 		    num_rules - good_rules);
54254235Smarkfen 	}
54264235Smarkfen 	/* looks good, flip it in */
54274235Smarkfen 	if (ret == 0 && !just_check) {
54284235Smarkfen 		if (!ipsecconf_qflag) {
54294235Smarkfen 			(void) printf("%s", warning);
54304235Smarkfen 		}
54315120Smarkfen 		if (smf_managed)
54325120Smarkfen 			warnx(gettext("%d policy rules added."), good_rules);
54334235Smarkfen 		ipsec_conf_admin(SPD_FLIP);
54344235Smarkfen 	} else {
54354235Smarkfen 		nuke_adds();
54364235Smarkfen 		if (just_check) {
54375120Smarkfen 			(void) fprintf(stdout, gettext("IPsec configuration "
54385120Smarkfen 			    "does not contain any errors.\n"));
54394235Smarkfen 			(void) fprintf(stdout, gettext(
54404235Smarkfen 			    "IPsec policy was not modified.\n"));
54414235Smarkfen 			(void) fflush(stdout);
54424235Smarkfen 		}
54434235Smarkfen 	}
54444235Smarkfen 	flushret = ipsec_conf_flush(SPD_STANDBY);
54454235Smarkfen 	if (flushret != 0)
54464235Smarkfen 		return (flushret);
54474235Smarkfen 	return (ret);
54484235Smarkfen }
54494235Smarkfen 
54504235Smarkfen 
54514235Smarkfen static int
54524235Smarkfen ipsec_conf_sub()
54534235Smarkfen {
54544235Smarkfen 	act_prop_t *act_props = malloc(sizeof (act_prop_t));
54554235Smarkfen 	FILE *remove_fp, *policy_fp;
54564235Smarkfen 	char rbuf[MAXLEN], pbuf[MAXLEN], /* remove buffer, and policy buffer */
54574235Smarkfen 	    *warning = gettext(
54585120Smarkfen 	    "\tWARNING: Policy entries that are being removed may\n"
54595120Smarkfen 	    "\taffect the existing connections.  Existing connections\n"
54605120Smarkfen 	    "\tthat are subjected to policy constraints may no longer\n"
54615120Smarkfen 	    "\tbe subjected to policy contraints because of its\n"
54625120Smarkfen 	    "\tremoval.  This can compromise security, and disrupt\n"
54635120Smarkfen 	    "\tthe communication of the existing connection.\n"
54645120Smarkfen 	    "\tConnections that are latched will remain unaffected\n"
54655120Smarkfen 	    "\tuntil they close.\n");
54664235Smarkfen 	int ret = 0;
54674235Smarkfen 	int index_len, pindex = 0; /* init value in case of pfile error */
54684235Smarkfen 
54694235Smarkfen 	if (act_props == NULL) {
54704235Smarkfen 		warn(gettext("memory"));
54714235Smarkfen 		return (-1);
54724235Smarkfen 	}
54734235Smarkfen 
54744235Smarkfen 	/* clone into standby DB */
54754235Smarkfen 	(void) ipsec_conf_admin(SPD_CLONE);
54764235Smarkfen 
54774235Smarkfen 	if (strcmp(filename, "-") == 0)
54784235Smarkfen 		remove_fp = stdin;
54794235Smarkfen 	else
54804235Smarkfen 		remove_fp = fopen(filename, "r");
54814235Smarkfen 
54824235Smarkfen 	if (remove_fp == NULL) {
54834235Smarkfen 		warn(gettext("%s : Input file cannot be opened"), filename);
54844235Smarkfen 		usage();
54854235Smarkfen 		free(act_props);
54864235Smarkfen 		return (-1);
54874235Smarkfen 	}
54884235Smarkfen 
54894235Smarkfen 	/* open policy file so we can locate the correct policy */
54904235Smarkfen 	(void) umask(0022);  /* in case it gets created! */
54914235Smarkfen 	policy_fp = fopen(POLICY_CONF_FILE, "r+");
54924235Smarkfen 	if (policy_fp == NULL) {
54934235Smarkfen 		warn(gettext("%s cannot be opened"), POLICY_CONF_FILE);
54944235Smarkfen 		(void) fclose(remove_fp);
54954235Smarkfen 		free(act_props);
54964235Smarkfen 		return (-1);
54974235Smarkfen 	}
54984235Smarkfen 
54994235Smarkfen 	/* don't print the warning if we're in q[uiet] mode */
55004235Smarkfen 	if (!ipsecconf_qflag)
55014235Smarkfen 		(void) printf("%s", warning);
55024235Smarkfen 
55034235Smarkfen 	/* this bit is done primarily so we can read what we write */
55044235Smarkfen 	index_len = strlen(INDEX_TAG);
55054235Smarkfen 
55064235Smarkfen 	/*
55074235Smarkfen 	 * We want to look for the policy in rbuf in the policy file.
55084235Smarkfen 	 * Go through the list of policies to remove, locating each one.
55094235Smarkfen 	 */
55104235Smarkfen 	while (fgets(rbuf, MAXLEN, remove_fp) != NULL) {
55114235Smarkfen 		char *buf;
55124235Smarkfen 		int offset, prev_offset, prev_prev_offset, nlines;
55134235Smarkfen 		fpos_t ipos;
55144235Smarkfen 		int pbuf_len = 0;
55154235Smarkfen 		char *tmp;
55164235Smarkfen 		/* skip blanks here (so we don't need to do it below)! */
55175120Smarkfen 		for (tmp = rbuf; (*tmp != '\0') && isspace(*tmp); )
55185120Smarkfen 			tmp++;
55195120Smarkfen 
55204235Smarkfen 		if (*tmp == '\0')
55215120Smarkfen 			continue; /* while(); */
55224235Smarkfen 
55234235Smarkfen 		/* skip the INDEX_TAG lines in the remove buffer */
55244235Smarkfen 		if (strncasecmp(rbuf, INDEX_TAG, index_len) == 0)
55254235Smarkfen 			continue;
55264235Smarkfen 
55274235Smarkfen 		/* skip commented lines */
55284235Smarkfen 		if (*tmp == '#')
55295120Smarkfen 			continue; /* while(); */
55304235Smarkfen 
55314235Smarkfen 		/*
55324235Smarkfen 		 * We start by presuming only good policies are in the pfile,
55334235Smarkfen 		 * and so only good policies from the rfile will match them.
55344235Smarkfen 		 * ipsec_conf_del ensures this later by calling parse_one() on
55354235Smarkfen 		 * pfile before it deletes the entry.
55364235Smarkfen 		 */
55374235Smarkfen 		for (offset = prev_offset = prev_prev_offset = 0;
55384235Smarkfen 		    fgets(pbuf, MAXLEN, policy_fp) != NULL;
55394235Smarkfen 		    offset += pbuf_len) {
55404235Smarkfen 			prev_offset = offset;
55414235Smarkfen 			pbuf_len = strlen(pbuf);
55424235Smarkfen 
55434235Smarkfen 			/* skip blank lines which seperate policy entries */
55444235Smarkfen 			if (pbuf[0] == '\n')
55454235Smarkfen 				continue;
55464235Smarkfen 
55474235Smarkfen 			/* if we found an index, save it */
55484235Smarkfen 			if (strncasecmp(pbuf, INDEX_TAG, index_len) == 0) {
55494235Smarkfen 				buf = pbuf + index_len;
55504235Smarkfen 				buf++;
55514235Smarkfen 				if ((pindex = parse_index(buf, NULL)) == -1) {
55524235Smarkfen 					/* bad index, we can't continue */
55534235Smarkfen 					warnx(gettext(
55545120Smarkfen 					    "Invalid index in the file"));
55554235Smarkfen 					(void) fclose(remove_fp);
55564235Smarkfen 					(void) fclose(policy_fp);
55574235Smarkfen 					free(act_props);
55584235Smarkfen 					return (-1);
55594235Smarkfen 				}
55604235Smarkfen 
55614235Smarkfen 				/* save this position in case it's the one */
55624235Smarkfen 				if (fgetpos(policy_fp, &ipos) != 0) {
55634235Smarkfen 					(void) fclose(remove_fp);
55644235Smarkfen 					(void) fclose(policy_fp);
55654235Smarkfen 					free(act_props);
55664235Smarkfen 					return (-1);
55674235Smarkfen 				}
55684235Smarkfen 			}
55694235Smarkfen 
55704235Smarkfen 			/* Does pbuf contain the remove policy? */
55714235Smarkfen 			if (strncasecmp(rbuf, pbuf, pbuf_len) == 0) {
55724235Smarkfen 				/* we found the one to remove! */
55734235Smarkfen 				if (pindex == 0) {
55744235Smarkfen 					warnx(gettext("Didn't find a valid "
55754235Smarkfen 					    "index for policy"));
55764235Smarkfen 					(void) fclose(remove_fp);
55774235Smarkfen 					(void) fclose(policy_fp);
55784235Smarkfen 					free(act_props);
55794235Smarkfen 					return (-1);
55804235Smarkfen 				}
55814235Smarkfen 
55824235Smarkfen 				/* off it - back up to the last INDEX! */
55834235Smarkfen 				if (fsetpos(policy_fp, &ipos) != 0) {
55844235Smarkfen 					(void) fclose(remove_fp);
55854235Smarkfen 					(void) fclose(policy_fp);
55864235Smarkfen 					free(act_props);
55874235Smarkfen 					return (-1);
55884235Smarkfen 				}
55894235Smarkfen 
55904235Smarkfen 				/* parse_one sets linecount = #lines to off */
55914235Smarkfen 				if (parse_one(policy_fp, act_props) == -1) {
55924235Smarkfen 					warnx(gettext("Invalid policy entry "
55934235Smarkfen 					    "in the file"));
55944235Smarkfen 					(void) fclose(remove_fp);
55954235Smarkfen 					(void) fclose(policy_fp);
55964235Smarkfen 					free(act_props);
55974235Smarkfen 					return (-1);
55984235Smarkfen 				}
55994235Smarkfen 
56004235Smarkfen 				nlines = linecount + 2;
56014235Smarkfen 				goto delete;
56024235Smarkfen 			}
56034235Smarkfen 			/*
56044235Smarkfen 			 * When we find a match, we want to pass the offset
56054235Smarkfen 			 * of the line that is before it - the INDEX_TAG line.
56064235Smarkfen 			 */
56074235Smarkfen 			prev_prev_offset = prev_offset;
56084235Smarkfen 		}
56094235Smarkfen 		/* Didn't find a match - look at the next remove policy */
56105120Smarkfen 		continue; /* while(); */
56114235Smarkfen 
56124235Smarkfen delete:
56134235Smarkfen 		(void) fclose(policy_fp);
56144235Smarkfen 
56154235Smarkfen 		if (delete_from_file(prev_prev_offset, nlines) != 0) {
56164235Smarkfen 			warnx(gettext("delete_from_file failure.  "
56174235Smarkfen 			    "Please flush all entries and re-configure :"));
56184235Smarkfen 			reconfigure();
56194235Smarkfen 			(void) fclose(remove_fp);
56204235Smarkfen 			free(act_props);
56214235Smarkfen 			return (-1);
56224235Smarkfen 		}
56234235Smarkfen 
56244235Smarkfen 		if (pfp_delete_rule(pindex) != 0) {
56254235Smarkfen 			warnx(gettext("Deletion incomplete. Please flush"
56264235Smarkfen 			    "all the entries and re-configure :"));
56274235Smarkfen 			reconfigure();
56284235Smarkfen 			(void) fclose(remove_fp);
56294235Smarkfen 			free(act_props);
56304235Smarkfen 			return (-1);
56314235Smarkfen 		}
56324235Smarkfen 
56334235Smarkfen 		/* reset the globals */
56344235Smarkfen 		linecount = 0;
56354235Smarkfen 		pindex = 0;
56364235Smarkfen 		/* free(NULL) also works. */
56374235Smarkfen 		free(interface_name);
56384235Smarkfen 		interface_name = NULL;
56394235Smarkfen 
56404235Smarkfen 		/* reopen for next pass, automagically starting over. */
56414235Smarkfen 		policy_fp = fopen(POLICY_CONF_FILE, "r");
56424235Smarkfen 		if (policy_fp == NULL) {
56434235Smarkfen 			warn(gettext("%s cannot be re-opened, can't continue"),
56444235Smarkfen 			    POLICY_CONF_FILE);
56454235Smarkfen 			(void) fclose(remove_fp);
56464235Smarkfen 			free(act_props);
56474235Smarkfen 			return (-1);
56484235Smarkfen 		}
56494235Smarkfen 
56504235Smarkfen 	} /* read next remove policy */
56514235Smarkfen 
56524235Smarkfen 	if ((ret = pfp_delete_rule(pindex)) != 0) {
56534235Smarkfen 		warnx(gettext("Removal incomplete.  Please flush "
56544235Smarkfen 		    "all the entries and re-configure :"));
56554235Smarkfen 		reconfigure();
56564235Smarkfen 		free(act_props);
56574235Smarkfen 		return (ret);
56584235Smarkfen 	}
56594235Smarkfen 
56604235Smarkfen 	/* nothing left to look for */
56614235Smarkfen 	(void) fclose(remove_fp);
56624235Smarkfen 	free(act_props);
56634235Smarkfen 
56644235Smarkfen 	return (0);
56654235Smarkfen }
56664235Smarkfen 
56674235Smarkfen /*
56684235Smarkfen  * Constructs a tunnel interface ID extension.  Returns the length
56694235Smarkfen  * of the extension in 64-bit-words.
56704235Smarkfen  */
56714235Smarkfen static int
56724235Smarkfen attach_tunname(spd_if_t *tunname)
56734235Smarkfen {
56744235Smarkfen 	if (tunname == NULL || interface_name == NULL)
56754235Smarkfen 		return (0);
56764235Smarkfen 
56774235Smarkfen 	tunname->spd_if_exttype = SPD_EXT_TUN_NAME;
56784235Smarkfen 	/*
56794235Smarkfen 	 * Use "-3" because there's 4 bytes in the message itself, and
56804235Smarkfen 	 * we lose one because of the '\0' terminator.
56814235Smarkfen 	 */
56824235Smarkfen 	tunname->spd_if_len = SPD_8TO64(
56834235Smarkfen 	    P2ROUNDUP(sizeof (*tunname) + strlen(interface_name) - 3, 8));
56844235Smarkfen 	(void) strlcpy((char *)tunname->spd_if_name, interface_name, LIFNAMSIZ);
56854235Smarkfen 	return (tunname->spd_if_len);
56864235Smarkfen }
5687