xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/ipsecconf.c (revision 12655:1759b5b76e53)
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 /*
2212131Sdanmcd@opensolaris.org  * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
234235Smarkfen  */
244235Smarkfen 
254235Smarkfen #include <stdio.h>
264235Smarkfen #include <sys/types.h>
274235Smarkfen #include <sys/stat.h>
284235Smarkfen #include <strings.h>
294235Smarkfen #include <stropts.h>
304235Smarkfen #include <fcntl.h>
314235Smarkfen #include <stdlib.h>
324235Smarkfen #include <unistd.h>
334235Smarkfen #include <string.h>
344235Smarkfen #include <ctype.h>
354235Smarkfen #include <arpa/inet.h>
364235Smarkfen #include <locale.h>
374235Smarkfen #include <syslog.h>
384235Smarkfen #include <pwd.h>
394235Smarkfen #include <sys/param.h>
404235Smarkfen #include <sys/sysmacros.h>	/* MIN, MAX */
414235Smarkfen #include <sys/sockio.h>
424235Smarkfen #include <net/pfkeyv2.h>
434235Smarkfen #include <net/pfpolicy.h>
444235Smarkfen #include <inet/ipsec_impl.h>
454235Smarkfen #include <signal.h>
464235Smarkfen #include <errno.h>
474235Smarkfen #include <netdb.h>
484235Smarkfen #include <sys/socket.h>
494235Smarkfen #include <sys/systeminfo.h>
504235Smarkfen #include <nss_dbdefs.h>					/* NSS_BUFLEN_HOSTS */
514235Smarkfen #include <netinet/in.h>
524235Smarkfen #include <assert.h>
534235Smarkfen #include <inet/ip.h>
544235Smarkfen #include <ipsec_util.h>
554235Smarkfen #include <netinet/in_systm.h>
564235Smarkfen #include <netinet/ip_icmp.h>
574235Smarkfen #include <netinet/icmp6.h>
584235Smarkfen 
594235Smarkfen /*
604235Smarkfen  * Globals
614235Smarkfen  */
624235Smarkfen int lfd;
634235Smarkfen char *my_fmri;
644235Smarkfen FILE *debugfile = stderr;
654235Smarkfen 
664235Smarkfen #define	USAGE() if (!smf_managed) usage()
674235Smarkfen /*
684235Smarkfen  * Buffer length to read in pattern/properties.
694235Smarkfen  */
704235Smarkfen #define	MAXLEN			1024
714235Smarkfen 
724235Smarkfen /* Max length of tunnel interface string identifier */
734235Smarkfen #define	TUNNAMEMAXLEN		LIFNAMSIZ
744235Smarkfen 
754235Smarkfen /*
764235Smarkfen  * Used by parse_one and parse/parse_action to communicate
774235Smarkfen  * the errors. -1 is failure, which is not defined here.
784235Smarkfen  */
794235Smarkfen enum parse_errors {PARSE_SUCCESS, PARSE_EOF};
804235Smarkfen 
814235Smarkfen /*
824235Smarkfen  * For spdsock_get_ext() diagnostics.
834235Smarkfen  */
844235Smarkfen #define	SPDSOCK_DIAG_BUF_LEN	128
854235Smarkfen static char spdsock_diag_buf[SPDSOCK_DIAG_BUF_LEN];
864235Smarkfen 
874235Smarkfen /*
884235Smarkfen  * Define CURL here so that while you are reading
894235Smarkfen  * this code, it does not affect "vi" in pattern
904235Smarkfen  * matching.
914235Smarkfen  */
924235Smarkfen #define	CURL_BEGIN		'{'
934235Smarkfen #define	CURL_END		'}'
945120Smarkfen #define	BACK_SLASH		'\\'
954235Smarkfen #define	MAXARGS			20
964235Smarkfen #define	NOERROR			0
974235Smarkfen 
984235Smarkfen /*
994235Smarkfen  * IPSEC_CONF_ADD should start with 1, so that when multiple commands
1004235Smarkfen  * are given, we can fail the request.
1014235Smarkfen  */
1024235Smarkfen 
1034235Smarkfen enum ipsec_cmds {IPSEC_CONF_ADD = 1, IPSEC_CONF_DEL, IPSEC_CONF_VIEW,
10411278SMark.Fenwick@Sun.COM     IPSEC_CONF_FLUSH, IPSEC_CONF_LIST, IPSEC_CONF_SUB, IPSEC_CONF_REPLACE};
1054235Smarkfen 
1064235Smarkfen static const char policy_conf_file[] = "/var/run/ipsecpolicy.conf";
1074235Smarkfen static const char lock_file[] = "/var/run/ipsecconf.lock";
1084235Smarkfen static const char index_tag[] = "#INDEX";
1094235Smarkfen 
1104235Smarkfen #define	POLICY_CONF_FILE	policy_conf_file
1114235Smarkfen #define	LOCK_FILE		lock_file
1124235Smarkfen #define	INDEX_TAG		index_tag
1134235Smarkfen 
1144235Smarkfen /*
1154235Smarkfen  * Valid algorithm length.
1164235Smarkfen  */
1174235Smarkfen #define	VALID_ALG_LEN		40
1184235Smarkfen 
1194235Smarkfen /* Types of Error messages */
1204235Smarkfen typedef enum error_type {BAD_ERROR, DUP_ERROR, REQ_ERROR} error_type_t;
1214235Smarkfen 
1224235Smarkfen /* Error message human readable conversions */
1234235Smarkfen static char *sys_error_message(int);
1244235Smarkfen static void error_message(error_type_t, int, int);
1254235Smarkfen static int get_pf_pol_socket(void);
1264235Smarkfen 
1274235Smarkfen static int cmd;
1284235Smarkfen static char *filename;
1294235Smarkfen static char lo_buf[MAXLEN];			/* Leftover buffer */
1304235Smarkfen 
1314235Smarkfen /*
1324235Smarkfen  * The new SPD_EXT_TUN_NAME extension has a tunnel name in it.  Use the empty
1334235Smarkfen  * string ("", stored in the char value "all_polheads") for all policy heads
1344235Smarkfen  * (global and all tunnels).  Set interface_name to NULL for global-only, or
1354235Smarkfen  * specify a name of an IP-in-IP tunnel.
1364235Smarkfen  */
1374235Smarkfen static char *interface_name;
1384235Smarkfen static char all_polheads;	/* So we can easily get "". */
1394235Smarkfen 
1404235Smarkfen /* Error reporting stuff */
14112131Sdanmcd@opensolaris.org #define	CBUF_LEN		8192		/* Maximum size of the cmd */
1424235Smarkfen /*
1434235Smarkfen  * Following are used for reporting errors with arguments.
1444235Smarkfen  * We store the line numbers of each argument as we parse them,
1454235Smarkfen  * so that the error reporting is more specific. We can have only
1465120Smarkfen  * (MAXARGS - 1) arguments between any pair of CURL_BEGIN CURL_END.
1475120Smarkfen  * Because a single command can be made up of multiple action/property
1485120Smarkfen  * combinations, the maximum command size is (2 * (MAXARGS -1)) for each
1495120Smarkfen  * of patterns, properties and actions.
1504235Smarkfen  */
1515120Smarkfen #define	ARG_BUF_LEN		((2 * 3 * (MAXARGS - 1)) + 1)
1524235Smarkfen static int arg_indices[ARG_BUF_LEN];
1534235Smarkfen static int argindex;
1544235Smarkfen static int linecount;
1554235Smarkfen static char cbuf[CBUF_LEN];				/* Command buffer */
1564235Smarkfen static int cbuf_offset;
1574235Smarkfen 
1584235Smarkfen 
1594235Smarkfen #define	BYPASS_POLICY_BOOST		0x00800000
1604235Smarkfen #define	ESP_POLICY_BOOST		0x00400000
1614235Smarkfen #define	AH_POLICY_BOOST			0x00200000
1624235Smarkfen #define	INITIAL_BASE_PRIORITY		0x000fffff
1634235Smarkfen 
1644235Smarkfen /*
1654235Smarkfen  * the number used to order the
1664235Smarkfen  * rules starts at a certain base and
1674235Smarkfen  * goes down.  i.e. rules earlier in
1684235Smarkfen  * the file are checked first
1694235Smarkfen  */
1704235Smarkfen static uint32_t priority = INITIAL_BASE_PRIORITY;
1714235Smarkfen 
1724235Smarkfen #define	AH_AUTH		0
1734235Smarkfen #define	ESP_ENCR	1
1744235Smarkfen #define	ESP_AUTH	2
1754235Smarkfen 
1764235Smarkfen 
1774235Smarkfen /*
1784235Smarkfen  * for deleting adds on error
1794235Smarkfen  */
1804235Smarkfen 
1814235Smarkfen typedef struct d_list_s
1824235Smarkfen {
1834235Smarkfen 	struct d_list_s *next;
1844235Smarkfen 	int index;
1854235Smarkfen } d_list_t;
1864235Smarkfen 
1874235Smarkfen static d_list_t *d_list = NULL;
1884235Smarkfen static d_list_t *d_tail = NULL;
1894235Smarkfen 
1904235Smarkfen 
1914235Smarkfen /*
1924235Smarkfen  * Used for multi-homed source/dest hosts.
1934235Smarkfen  */
1944235Smarkfen static struct hostent *shp, *dhp;
1954235Smarkfen static unsigned int splen, dplen;
1964235Smarkfen static char tunif[TUNNAMEMAXLEN];
1974235Smarkfen static boolean_t has_saprefix, has_daprefix;
1984235Smarkfen static uint32_t seq_cnt = 0;
1994235Smarkfen 
2004235Smarkfen /* lexxed out action and related properties */
2014235Smarkfen typedef struct ap_s
2024235Smarkfen {
2034235Smarkfen 	char *act;
2044235Smarkfen 	char *prop[MAXARGS + 1];
2054235Smarkfen } ap_t;
2064235Smarkfen 
2074235Smarkfen 
2084235Smarkfen /* one lexxed out rule */
2094235Smarkfen typedef struct act_prop_s {
2105120Smarkfen 	char *pattern[MAXARGS + 1];
2114235Smarkfen 	ap_t ap[MAXARGS + 1];
2124235Smarkfen } act_prop_t;
2134235Smarkfen 
2144235Smarkfen typedef struct
2154235Smarkfen {
2164235Smarkfen 	uint8_t	 alg_id;
2174235Smarkfen 	uint32_t alg_minbits;
2184235Smarkfen 	uint32_t alg_maxbits;
2194235Smarkfen } algreq_t;
2204235Smarkfen 
2214235Smarkfen /* structure to hold all information for one act_prop_t */
2224235Smarkfen typedef struct ips_act_props_s {
2234235Smarkfen 	struct ips_act_props_s	*iap_next;
2244235Smarkfen 	struct ips_conf_s		*iap_head;
2254235Smarkfen 
2264235Smarkfen /*
2274235Smarkfen  * IPsec action types (in SPD_ATTR_TYPE attribute)
2284235Smarkfen  * SPD_ACTTYPE_DROP	0x0001
2294235Smarkfen  * SPD_ACTTYPE_PASS	0x0002
2304235Smarkfen  * SPD_ACTTYPE_IPSEC	0x0003
2314235Smarkfen  */
2324235Smarkfen 	uint16_t	iap_action;
2334235Smarkfen 	uint16_t	iap_act_tok;
2344235Smarkfen 
2354235Smarkfen /*
2364235Smarkfen  * Action ATTR flags (in SPD_ATTR_FLAGS attribute)
2374235Smarkfen  *	SPD_APPLY_AH		0x0001
2384235Smarkfen  *	SPD_APPLY_ESP		0x0002
2394235Smarkfen  *	SPD_APPLY_SE		0x0004  * self-encapsulation *
2404235Smarkfen  *	SPD_APPLY_COMP		0x0008	* compression; NYI *
2414235Smarkfen  *	SPD_APPLY_UNIQUE	0x0010	* unique per-flow SA *
2424235Smarkfen  *	SPD_APPLY_BYPASS	0x0020	* bypass policy *
2434235Smarkfen  */
2444235Smarkfen 	uint16_t	iap_attr;
2454235Smarkfen 	uint16_t	iap_attr_tok[5];
2464235Smarkfen 
2474235Smarkfen 	algreq_t	iap_aauth;
2484235Smarkfen 	algreq_t	iap_eencr;
2494235Smarkfen 	algreq_t	iap_eauth;
2504235Smarkfen 
2514235Smarkfen 	uint32_t iap_life_soft_time;
2524235Smarkfen 	uint32_t iap_life_hard_time;
2534235Smarkfen 	uint32_t iap_life_soft_bytes;
2544235Smarkfen 	uint32_t iap_life_hard_bytes;
2554235Smarkfen 
2564235Smarkfen } ips_act_props_t;
2574235Smarkfen 
2584235Smarkfen #define	V4_PART_OF_V6(v6)	v6._S6_un._S6_u32[3]
2594235Smarkfen 
2604235Smarkfen typedef struct ips_conf_s {
2614235Smarkfen 	/* selector */
2624235Smarkfen 	uint16_t patt_tok[8];
2634235Smarkfen 	uint8_t has_saddr;
2644235Smarkfen 	uint8_t has_daddr;
2654235Smarkfen 	uint8_t has_smask;
2664235Smarkfen 	uint8_t has_dmask;
2674235Smarkfen 	uint8_t has_type;
2684235Smarkfen 	uint8_t has_code;
2694235Smarkfen 	uint8_t has_negotiate;
2704235Smarkfen 	uint8_t has_tunnel;
2714235Smarkfen 	uint16_t swap;
2724235Smarkfen 
2734235Smarkfen 	struct in6_addr	ips_src_addr_v6;
2744235Smarkfen 	struct in6_addr	ips_src_mask_v6;
2754235Smarkfen 	struct in6_addr	ips_dst_addr_v6;
2764235Smarkfen 	struct in6_addr	ips_dst_mask_v6;
2774235Smarkfen 	uint8_t 		ips_src_mask_len;
2784235Smarkfen 	uint8_t 		ips_dst_mask_len;
2794235Smarkfen 	in_port_t		ips_src_port_min;
2804235Smarkfen 	in_port_t		ips_src_port_max;
2814235Smarkfen 	in_port_t		ips_dst_port_min;
2824235Smarkfen 	in_port_t		ips_dst_port_max;
2834235Smarkfen 	uint8_t			ips_icmp_type;
2844235Smarkfen 	uint8_t			ips_icmp_type_end;
2854235Smarkfen 	uint8_t			ips_icmp_code;
2864235Smarkfen 	uint8_t			ips_icmp_code_end;
2874235Smarkfen 	uint8_t			ips_ulp_prot;
2884235Smarkfen 	uint8_t			ips_ipsec_prot;
2894235Smarkfen 	uint8_t			ips_isv4;
2904235Smarkfen 	/*
2914235Smarkfen 	 * SPD_RULE_FLAG_INBOUND		0x0001
2924235Smarkfen 	 * SPD_RULE_FLAG_OUTBOUND		0x0002
2934235Smarkfen 	 */
2944235Smarkfen 	uint8_t			ips_dir;
2954235Smarkfen 	/*
2964235Smarkfen 	 * Keep track of tunnel separately due to explosion of ways to set
2974235Smarkfen 	 * inbound/outbound.
2984235Smarkfen 	 */
2994235Smarkfen 	boolean_t		ips_tunnel;
3004235Smarkfen 	uint64_t		ips_policy_index;
3014235Smarkfen 	uint32_t		ips_act_cnt;
3024235Smarkfen 	ips_act_props_t	*ips_acts;
3034235Smarkfen } ips_conf_t;
3044235Smarkfen 
3054235Smarkfen #define	ips_src_addr	V4_PART_OF_V6(ips_src_addr_v6)
3064235Smarkfen #define	ips_dst_addr	V4_PART_OF_V6(ips_dst_addr_v6)
3074235Smarkfen 
3084235Smarkfen static int ipsecconf_nflag;		/* Used only with -l option */
3094235Smarkfen static int ipsecconf_qflag;		/* Used only with -a|-r option */
3104235Smarkfen 
3114235Smarkfen typedef struct str_val {
3124235Smarkfen 	const char *string;
3134235Smarkfen 	int value;
3144235Smarkfen } str_val_t;
3154235Smarkfen 
3164235Smarkfen typedef struct str_tval {
3174235Smarkfen 	const char *string;
3184235Smarkfen 	int tok_val;
3194235Smarkfen 	int value;
3204235Smarkfen } str_tval_t;
3214235Smarkfen 
3224235Smarkfen static int	parse_int(const char *);
3234235Smarkfen static int	parse_index(const char *, char *);
3244235Smarkfen static int	attach_tunname(spd_if_t *);
3254235Smarkfen static void	usage(void);
3264235Smarkfen static int	ipsec_conf_del(int, boolean_t);
32711278SMark.Fenwick@Sun.COM static int	ipsec_conf_add(boolean_t, boolean_t, boolean_t);
3284235Smarkfen static int	ipsec_conf_sub(void);
3294235Smarkfen static int	ipsec_conf_flush(int);
3304235Smarkfen static int	ipsec_conf_view(void);
3314235Smarkfen static int	ipsec_conf_list(void);
3324235Smarkfen static int	lock(void);
3334235Smarkfen static int	unlock(int);
3344235Smarkfen static int	parse_one(FILE *, act_prop_t *);
3354235Smarkfen static void	reconfigure();
3364235Smarkfen static void	in_prefixlentomask(unsigned int, uchar_t *);
3374235Smarkfen static int	in_getprefixlen(char *);
3384235Smarkfen static int	parse_address(int, char *);
3394235Smarkfen #ifdef DEBUG_HEAVY
3404235Smarkfen static void	pfpol_msg_dump(spd_msg_t *msg, char *);
3414235Smarkfen #endif /* DEBUG_HEAVY */
3424235Smarkfen static void	print_pfpol_msg(spd_msg_t *);
3434235Smarkfen static int	pfp_delete_rule(uint64_t);
3444235Smarkfen static void	ipsec_conf_admin(uint8_t);
3454235Smarkfen static void	print_bit_range(int, int);
3464235Smarkfen static void	nuke_adds();
34712131Sdanmcd@opensolaris.org static boolean_t combined_mode(uint_t);
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
add_index(int index)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
block_all_signals()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
restore_all_signals()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 *
alloc_iap(ips_conf_t * parent)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
fetch_algorithms()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 *
emit_alg(struct spd_attribute * ap,int type,const algreq_t * ar,int algattr,int minbitattr,int maxbitattr)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 *
ips_act_props_to_action(struct spd_attribute * ap,uint32_t * rule_priorityp,const ips_act_props_t * act_ptr)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
alg_rangecheck(uint_t type,uint_t algid,const algreq_t * ar)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 *
ips_act_wild_props_to_action(struct spd_attribute * ap,uint32_t * rule_priorityp,uint16_t * act_cntp,const ips_act_props_t * act_ptr)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;
86712131Sdanmcd@opensolaris.org 	boolean_t use_ah, use_esp, use_espa, combined;
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 
91412131Sdanmcd@opensolaris.org 		combined = combined_mode(encr_alg);
91512131Sdanmcd@opensolaris.org 
9164235Smarkfen 		for (auth_idx = auth_min; auth_idx <= auth_max; auth_idx++) {
9174235Smarkfen 			auth_alg = WHICH_ALG(AH_AUTH, wild_auth, auth_idx);
9184235Smarkfen 
9194235Smarkfen 			if (use_ah &&
9204235Smarkfen 			    !alg_rangecheck(AH_AUTH, auth_alg,
9215120Smarkfen 			    &act_ptr->iap_aauth))
9224235Smarkfen 				continue;
9234235Smarkfen 
9244235Smarkfen 
9254235Smarkfen 			for (eauth_idx = eauth_min; eauth_idx <= eauth_max;
9264235Smarkfen 			    eauth_idx++) {
9274235Smarkfen 				eauth_alg = WHICH_ALG(ESP_AUTH, wild_eauth,
9284235Smarkfen 				    eauth_idx);
9294235Smarkfen 
93012131Sdanmcd@opensolaris.org 				if (!combined && use_espa &&
9314235Smarkfen 				    !alg_rangecheck(ESP_AUTH, eauth_alg,
9324235Smarkfen 				    &act_ptr->iap_eauth))
9334235Smarkfen 					continue;
9344235Smarkfen 
9354235Smarkfen 				tact.iap_eencr.alg_id = encr_alg;
9364235Smarkfen 				tact.iap_aauth.alg_id = auth_alg;
9374235Smarkfen 
93812131Sdanmcd@opensolaris.org 				/*
93912131Sdanmcd@opensolaris.org 				 * If the cipher is combined-mode don't do any
94012131Sdanmcd@opensolaris.org 				 * ESP authentication.
94112131Sdanmcd@opensolaris.org 				 */
94212131Sdanmcd@opensolaris.org 				tact.iap_eauth.alg_id =
94312131Sdanmcd@opensolaris.org 				    combined ? SADB_AALG_NONE : eauth_alg;
94412131Sdanmcd@opensolaris.org 
9454235Smarkfen 				(*act_cntp)++;
9464235Smarkfen 				ap = ips_act_props_to_action(ap,
9474235Smarkfen 				    rule_priorityp, &tact);
94812131Sdanmcd@opensolaris.org 
94912131Sdanmcd@opensolaris.org 				/* Stop now if the cipher is combined-mode. */
95012131Sdanmcd@opensolaris.org 				if (combined)
95112131Sdanmcd@opensolaris.org 					break;	/* Out of for loop. */
9524235Smarkfen 			}
9534235Smarkfen 		}
9544235Smarkfen 	}
9554235Smarkfen 
9564235Smarkfen #undef WHICH_ALG
9574235Smarkfen 
9584235Smarkfen 	return (ap);
9594235Smarkfen }
9604235Smarkfen 
9614235Smarkfen /* huge, but not safe since no length checking is done */
9624235Smarkfen #define	MAX_POL_MSG_LEN 16384
9634235Smarkfen 
9644235Smarkfen 
9654235Smarkfen /*
9664235Smarkfen  * hand in some ips_conf_t's, get back an
9674235Smarkfen  * iovec of pfpol messages.
9684235Smarkfen  * this function converts the internal ips_conf_t into
9694235Smarkfen  * a form that pf_pol can use.
9704235Smarkfen  * return 0 on success, 1 on failure
9714235Smarkfen  */
9724235Smarkfen static int
ips_conf_to_pfpol_msg(int ipsec_cmd,ips_conf_t * inConf,int num_ips,struct iovec * msg)9734235Smarkfen ips_conf_to_pfpol_msg(int ipsec_cmd, ips_conf_t *inConf, int num_ips,
9744235Smarkfen     struct iovec *msg)
9754235Smarkfen {
9764235Smarkfen 	int i;
9774235Smarkfen 	ips_conf_t *conf;
9784235Smarkfen 	uint64_t *scratch = NULL;
9794235Smarkfen 
9804235Smarkfen 	for (i = 0; i < num_ips; i++) {
9814235Smarkfen 		uint16_t *msg_len;
9824235Smarkfen 		uint16_t act_cnt = 0;
9834235Smarkfen 		uint64_t *next = NULL;
9844235Smarkfen 		spd_msg_t *spd_msg;
9854235Smarkfen 		spd_address_t *spd_address;
9864235Smarkfen 		struct spd_rule *spd_rule;
9874235Smarkfen 		struct spd_proto *spd_proto;
9884235Smarkfen 		struct spd_portrange *spd_portrange;
9894235Smarkfen 		struct spd_ext_actions *spd_ext_actions;
9904235Smarkfen 		struct spd_attribute *ap;
9914235Smarkfen 		struct spd_typecode *spd_typecode;
9924235Smarkfen 		spd_if_t *spd_if;
9934235Smarkfen 		ips_act_props_t *act_ptr;
9944235Smarkfen 		uint32_t rule_priority = 0;
9954235Smarkfen 
9964235Smarkfen 		scratch = calloc(1, MAX_POL_MSG_LEN);
9974235Smarkfen 		msg[i].iov_base = (char *)scratch;
9984235Smarkfen 		if (scratch == NULL) {
9994235Smarkfen 			warn(gettext("memory"));
10004235Smarkfen 			return (1);
10014235Smarkfen 		}
10024235Smarkfen 		conf = &(inConf[i]);
10034235Smarkfen 
10044235Smarkfen 		spd_msg = (spd_msg_t *)scratch;
10054235Smarkfen 		next = (uint64_t *)&(spd_msg[1]);
10064235Smarkfen 
10074235Smarkfen 		msg_len = &(spd_msg->spd_msg_len);
10084235Smarkfen 
10094235Smarkfen 		spd_msg->spd_msg_version = PF_POLICY_V1;
10104235Smarkfen 		spd_msg->spd_msg_pid = getpid();
10114235Smarkfen 		spd_msg->spd_msg_seq = ++seq_cnt;
10124235Smarkfen 
10134235Smarkfen 		switch (ipsec_cmd) {
10144235Smarkfen 		case SPD_ADDRULE:
10154235Smarkfen 			spd_msg->spd_msg_type = SPD_ADDRULE;
10164235Smarkfen 			break;
10174235Smarkfen 
10184235Smarkfen 		default:
10194235Smarkfen 			warnx("%s %d", gettext("bad command:"), ipsec_cmd);
10204235Smarkfen 			spd_msg->spd_msg_type = SPD_ADDRULE;
10214235Smarkfen 			break;
10224235Smarkfen 		}
10234235Smarkfen 
10244235Smarkfen 		/*
10254235Smarkfen 		 * SELECTOR
10264235Smarkfen 		 */
10274235Smarkfen 
10284235Smarkfen 		spd_msg->spd_msg_spdid = SPD_STANDBY;
10294235Smarkfen 
10304235Smarkfen 		/* rule */
10314235Smarkfen 		spd_rule = (struct spd_rule *)next;
10324235Smarkfen 
10334235Smarkfen 		spd_rule->spd_rule_len = SPD_8TO64(sizeof (struct spd_rule));
10344235Smarkfen 		spd_rule->spd_rule_type = SPD_EXT_RULE;
10354235Smarkfen 		spd_rule->spd_rule_flags = conf->ips_dir;
10364235Smarkfen 		if (conf->ips_tunnel)
10374235Smarkfen 			spd_rule->spd_rule_flags |= SPD_RULE_FLAG_TUNNEL;
10384235Smarkfen 
10394235Smarkfen 		next = (uint64_t *)&(spd_rule[1]);
10404235Smarkfen 
10414235Smarkfen 		/* proto */
10424235Smarkfen 		if (conf->ips_ulp_prot != 0) {
10434235Smarkfen 			spd_proto = (struct spd_proto *)next;
10444235Smarkfen 			spd_proto->spd_proto_len =
10455120Smarkfen 			    SPD_8TO64(sizeof (struct spd_proto));
10464235Smarkfen 			spd_proto->spd_proto_exttype = SPD_EXT_PROTO;
10474235Smarkfen 			spd_proto->spd_proto_number = conf->ips_ulp_prot;
10484235Smarkfen 			next = (uint64_t *)&(spd_proto[1]);
10494235Smarkfen 		}
10504235Smarkfen 
10514235Smarkfen 		/* tunnel */
10524235Smarkfen 		if (conf->has_tunnel != 0) {
10534235Smarkfen 			spd_if = (spd_if_t *)next;
10544235Smarkfen 			spd_if->spd_if_len =
10554235Smarkfen 			    SPD_8TO64(P2ROUNDUP(strlen(tunif) + 1, 8) +
10564235Smarkfen 			    sizeof (spd_if_t));
10574235Smarkfen 			spd_if->spd_if_exttype = SPD_EXT_TUN_NAME;
10584235Smarkfen 			(void) strlcpy((char *)spd_if->spd_if_name, tunif,
10595120Smarkfen 			    TUNNAMEMAXLEN);
10604235Smarkfen 			next = (uint64_t *)(spd_if) + spd_if->spd_if_len;
10614235Smarkfen 		}
10624235Smarkfen 
10634235Smarkfen 		/* icmp type/code */
10644235Smarkfen 		if (conf->ips_ulp_prot == IPPROTO_ICMP ||
10654235Smarkfen 		    conf->ips_ulp_prot == IPPROTO_ICMPV6) {
10664235Smarkfen 			if (conf->has_type) {
10674235Smarkfen 				spd_typecode = (struct spd_typecode *)next;
10684235Smarkfen 				spd_typecode->spd_typecode_len =
10694235Smarkfen 				    SPD_8TO64(sizeof (struct spd_typecode));
10704235Smarkfen 				spd_typecode->spd_typecode_exttype =
10714235Smarkfen 				    SPD_EXT_ICMP_TYPECODE;
10724235Smarkfen 				spd_typecode->spd_typecode_type =
10734235Smarkfen 				    conf->ips_icmp_type;
10744235Smarkfen 				spd_typecode->spd_typecode_type_end =
10754235Smarkfen 				    conf->ips_icmp_type_end;
10764235Smarkfen 				if (conf->has_code) {
10774235Smarkfen 					spd_typecode->spd_typecode_code =
10784235Smarkfen 					    conf->ips_icmp_code;
10794235Smarkfen 					spd_typecode->spd_typecode_code_end =
10804235Smarkfen 					    conf->ips_icmp_code_end;
10814235Smarkfen 				} else {
10824235Smarkfen 					spd_typecode->spd_typecode_code = 255;
10834235Smarkfen 					spd_typecode->spd_typecode_code_end
10844235Smarkfen 					    = 255;
10854235Smarkfen 				}
10864235Smarkfen 				next = (uint64_t *)&(spd_typecode[1]);
10874235Smarkfen 			}
10884235Smarkfen 		}
10894235Smarkfen 
10904235Smarkfen 		/* src port */
10914235Smarkfen 		if (conf->ips_src_port_min != 0 ||
10924235Smarkfen 		    conf->ips_src_port_max != 0) {
10934235Smarkfen 			spd_portrange = (struct spd_portrange *)next;
10944235Smarkfen 			spd_portrange->spd_ports_len =
10955120Smarkfen 			    SPD_8TO64(sizeof (struct spd_portrange));
10964235Smarkfen 			spd_portrange->spd_ports_exttype =
10975120Smarkfen 			    (conf->swap)?SPD_EXT_REMPORT:SPD_EXT_LCLPORT;
10984235Smarkfen 			spd_portrange->spd_ports_minport =
10995120Smarkfen 			    conf->ips_src_port_min;
11004235Smarkfen 			spd_portrange->spd_ports_maxport =
11015120Smarkfen 			    conf->ips_src_port_max;
11024235Smarkfen 			next = (uint64_t *)&(spd_portrange[1]);
11034235Smarkfen 		}
11044235Smarkfen 		/* dst port */
11054235Smarkfen 		if (conf->ips_dst_port_min != 0 ||
11064235Smarkfen 		    conf->ips_dst_port_max != 0) {
11074235Smarkfen 			spd_portrange = (struct spd_portrange *)next;
11084235Smarkfen 			spd_portrange->spd_ports_len =
11095120Smarkfen 			    SPD_8TO64(sizeof (struct spd_portrange));
11104235Smarkfen 			spd_portrange->spd_ports_exttype =
11115120Smarkfen 			    (conf->swap)?SPD_EXT_LCLPORT:SPD_EXT_REMPORT;
11124235Smarkfen 			spd_portrange->spd_ports_minport =
11135120Smarkfen 			    conf->ips_dst_port_min;
11144235Smarkfen 			spd_portrange->spd_ports_maxport =
11155120Smarkfen 			    conf->ips_dst_port_max;
11164235Smarkfen 			next = (uint64_t *)&(spd_portrange[1]);
11174235Smarkfen 		}
11184235Smarkfen 
11194235Smarkfen 		/* saddr */
11204235Smarkfen 		if (conf->has_saddr) {
11214235Smarkfen 			spd_address = (spd_address_t *)next;
11224235Smarkfen 			next = (uint64_t *)(spd_address + 1);
11234235Smarkfen 
11244235Smarkfen 			spd_address->spd_address_exttype =
11255120Smarkfen 			    (conf->swap)?SPD_EXT_REMADDR:SPD_EXT_LCLADDR;
11264235Smarkfen 			spd_address->spd_address_prefixlen =
11275120Smarkfen 			    conf->ips_src_mask_len;
11284235Smarkfen 
11294235Smarkfen 			if (conf->ips_isv4) {
11304235Smarkfen 				spd_address->spd_address_af = AF_INET;
11314235Smarkfen 				(void) memcpy(next, &(conf->ips_src_addr),
11325120Smarkfen 				    sizeof (ipaddr_t));
11334235Smarkfen 				spd_address->spd_address_len = 2;
11344235Smarkfen 				next += SPD_8TO64(sizeof (ipaddr_t) + 4);
11354235Smarkfen 				if (!conf->has_smask)
11364235Smarkfen 					spd_address->spd_address_prefixlen = 32;
11374235Smarkfen 			} else {
11384235Smarkfen 				spd_address->spd_address_af = AF_INET6;
11394235Smarkfen 				(void) memcpy(next, &(conf->ips_src_addr_v6),
11404235Smarkfen 				    sizeof (in6_addr_t));
11414235Smarkfen 				spd_address->spd_address_len = 3;
11424235Smarkfen 				next += SPD_8TO64(sizeof (in6_addr_t));
11434235Smarkfen 				if (!conf->has_smask)
11444235Smarkfen 					spd_address->spd_address_prefixlen
11455120Smarkfen 					    = 128;
11464235Smarkfen 			}
11474235Smarkfen 		}
11484235Smarkfen 
11494235Smarkfen 		/* daddr */
11504235Smarkfen 		if (conf->has_daddr) {
11514235Smarkfen 			spd_address = (spd_address_t *)next;
11524235Smarkfen 
11534235Smarkfen 			next = (uint64_t *)(spd_address + 1);
11544235Smarkfen 
11554235Smarkfen 			spd_address->spd_address_exttype =
11565120Smarkfen 			    (conf->swap)?SPD_EXT_LCLADDR:SPD_EXT_REMADDR;
11574235Smarkfen 			spd_address->spd_address_prefixlen =
11585120Smarkfen 			    conf->ips_dst_mask_len;
11594235Smarkfen 
11604235Smarkfen 			if (conf->ips_isv4) {
11614235Smarkfen 				spd_address->spd_address_af = AF_INET;
11624235Smarkfen 				(void) memcpy(next, &conf->ips_dst_addr,
11634235Smarkfen 				    sizeof (ipaddr_t));
11644235Smarkfen 				spd_address->spd_address_len = 2;
11654235Smarkfen 				/* "+ 4" below is for padding. */
11664235Smarkfen 				next += SPD_8TO64(sizeof (ipaddr_t) + 4);
11674235Smarkfen 				if (!conf->has_dmask)
11684235Smarkfen 					spd_address->spd_address_prefixlen = 32;
11694235Smarkfen 			} else {
11704235Smarkfen 				spd_address->spd_address_af = AF_INET6;
11714235Smarkfen 				(void) memcpy(next, &(conf->ips_dst_addr_v6),
11724235Smarkfen 				    sizeof (in6_addr_t));
11734235Smarkfen 				spd_address->spd_address_len = 3;
11744235Smarkfen 				next += SPD_8TO64(sizeof (in6_addr_t));
11754235Smarkfen 				if (!conf->has_dmask)
11764235Smarkfen 					spd_address->spd_address_prefixlen
11775120Smarkfen 					    = 128;
11784235Smarkfen 			}
11794235Smarkfen 		}
11804235Smarkfen 
11814235Smarkfen 		/* actions */
11824235Smarkfen 		spd_ext_actions = (struct spd_ext_actions *)next;
11834235Smarkfen 
11844235Smarkfen 		spd_ext_actions->spd_actions_exttype = SPD_EXT_ACTION;
11854235Smarkfen 
11864235Smarkfen 		act_ptr = conf->ips_acts;
11874235Smarkfen 		ap = (struct spd_attribute *)(&spd_ext_actions[1]);
11884235Smarkfen 
11894235Smarkfen 		rule_priority = priority--;
11904235Smarkfen 
11914235Smarkfen 		for (act_ptr = conf->ips_acts; act_ptr != NULL;
11924235Smarkfen 		    act_ptr = act_ptr->iap_next) {
11934235Smarkfen 			ap = ips_act_wild_props_to_action(ap, &rule_priority,
11944235Smarkfen 			    &act_cnt, act_ptr);
11954235Smarkfen 		}
11964235Smarkfen 		ap[-1].spd_attr_tag = SPD_ATTR_END;
11974235Smarkfen 
11984235Smarkfen 		next = (uint64_t *)ap;
11994235Smarkfen 
12004235Smarkfen 		spd_rule->spd_rule_priority = rule_priority;
12014235Smarkfen 
12024235Smarkfen 		msg[i].iov_len = (uintptr_t)next - (uintptr_t)msg[i].iov_base;
12034235Smarkfen 		*msg_len = (uint16_t)SPD_8TO64(msg[i].iov_len);
12044235Smarkfen 		spd_ext_actions->spd_actions_count = act_cnt;
12054235Smarkfen 		spd_ext_actions->spd_actions_len =
12064235Smarkfen 		    SPD_8TO64((uintptr_t)next - (uintptr_t)spd_ext_actions);
12074235Smarkfen #ifdef DEBUG_HEAVY
12084235Smarkfen 		printf("pfpol msg len in uint64_t's = %d\n", *msg_len);
12094235Smarkfen 		printf("pfpol test_len in bytes = %d\n", msg[i].iov_len);
12104235Smarkfen 		pfpol_msg_dump((spd_msg_t *)scratch,
12114235Smarkfen 		    "ips_conf_to_pfpol_msg");
12124235Smarkfen #endif
12134235Smarkfen 	}
12144235Smarkfen 
12154235Smarkfen #undef ATTR
12164235Smarkfen 	return (0);
12174235Smarkfen }
12184235Smarkfen 
12194235Smarkfen static int
get_pf_pol_socket(void)12204235Smarkfen get_pf_pol_socket(void)
12214235Smarkfen {
12224235Smarkfen 	int s = socket(PF_POLICY, SOCK_RAW, PF_POLICY_V1);
12234235Smarkfen 	if (s < 0) {
12244235Smarkfen 		if (errno == EPERM) {
12254235Smarkfen 			EXIT_BADPERM("Insufficient privileges to open "
12264235Smarkfen 			    "PF_POLICY socket.");
12274235Smarkfen 		} else {
12284235Smarkfen 			warn(gettext("(loading pf_policy) socket:"));
12294235Smarkfen 		}
12304235Smarkfen 	}
12314235Smarkfen 
12324235Smarkfen 	return (s);
12334235Smarkfen }
12344235Smarkfen 
12354235Smarkfen 
12364235Smarkfen static int
send_pf_pol_message(int ipsec_cmd,ips_conf_t * conf,int * diag)12374235Smarkfen send_pf_pol_message(int ipsec_cmd, ips_conf_t *conf, int *diag)
12384235Smarkfen {
12394235Smarkfen 	int retval;
12404235Smarkfen 	int cnt;
12414235Smarkfen 	int total_len;
12424235Smarkfen 	struct iovec polmsg;
12434235Smarkfen 	spd_msg_t *return_buf;
12444235Smarkfen 	spd_ext_t *exts[SPD_EXT_MAX+1];
12454235Smarkfen 	int fd = get_pf_pol_socket();
12464235Smarkfen 
12474235Smarkfen 	*diag = 0;
12484235Smarkfen 
12494235Smarkfen 	if (fd < 0)
12504235Smarkfen 		return (EBADF);
12514235Smarkfen 
12524235Smarkfen 	retval = ips_conf_to_pfpol_msg(ipsec_cmd, conf, 1, &polmsg);
12534235Smarkfen 
12544235Smarkfen 	if (retval) {
12554235Smarkfen 		(void) close(fd);
12564235Smarkfen 		return (ENOMEM);
12574235Smarkfen 	}
12584235Smarkfen 
12594235Smarkfen 	total_len = polmsg.iov_len;
12604235Smarkfen 
12614235Smarkfen 	cnt = writev(fd, &polmsg, 1);
12624235Smarkfen 
12634235Smarkfen #ifdef DEBUG_HEAVY
12644235Smarkfen 	(void) printf("cnt = %d\n", cnt);
12654235Smarkfen #endif
12664235Smarkfen 	if (cnt < 0) {
12674235Smarkfen 		warn(gettext("pf_pol write"));
12684235Smarkfen 	} else {
12694235Smarkfen 		return_buf = (spd_msg_t *)calloc(total_len, 1);
12704235Smarkfen 
12714235Smarkfen 		if (return_buf == NULL) {
12724235Smarkfen 			warn(gettext("memory"));
12734235Smarkfen 		} else {
12744235Smarkfen 			cnt = read(fd, (void*)return_buf, total_len);
12754235Smarkfen #ifdef	DEBUG_HEAVY
12764235Smarkfen 			(void) printf("pf_pol read: cnt = %d(%d)\n", cnt,
12774235Smarkfen 			    total_len);
12784235Smarkfen #endif
12794235Smarkfen 
12804235Smarkfen 			if (cnt > 8 && return_buf->spd_msg_errno) {
12814235Smarkfen 				*diag = return_buf->spd_msg_diagnostic;
12824235Smarkfen 				if (!ipsecconf_qflag) {
12834235Smarkfen 					warnx("%s: %s",
12844235Smarkfen 					    gettext("Kernel returned"),
12854235Smarkfen 					    sys_error_message(
12864235Smarkfen 					    return_buf->spd_msg_errno));
12874235Smarkfen 				}
12884235Smarkfen 				if (*diag != 0)
12894235Smarkfen 					(void) printf(gettext(
12904235Smarkfen 					    "\t(spdsock diagnostic: %s)\n"),
12914235Smarkfen 					    spdsock_diag(*diag));
12924235Smarkfen #ifdef DEBUG_HEAVY
12934235Smarkfen 				pfpol_msg_dump((spd_msg_t *)polmsg.iov_base,
12944235Smarkfen 				    "message in");
12954235Smarkfen 				pfpol_msg_dump(return_buf,
12964235Smarkfen 				    "send_pf_pol_message");
12974235Smarkfen #endif
12984235Smarkfen 				retval = return_buf->spd_msg_errno;
12994235Smarkfen 				free(return_buf);
13004235Smarkfen 				free(polmsg.iov_base);
13014235Smarkfen 				(void) close(fd);
13024235Smarkfen 				return (retval);
13034235Smarkfen 			}
13044235Smarkfen 
13054235Smarkfen 			retval = spdsock_get_ext(exts, return_buf,
13064235Smarkfen 			    return_buf->spd_msg_len, NULL, 0);
13074235Smarkfen 			/* ignore retval */
13084235Smarkfen 
13094235Smarkfen 			if (exts[SPD_EXT_RULE]) {
13104235Smarkfen 				conf->ips_policy_index =
13114235Smarkfen 				    ((struct spd_rule *)
13125120Smarkfen 				    exts[SPD_EXT_RULE])->spd_rule_index;
13134235Smarkfen 
13144235Smarkfen 				if (add_index(conf->ips_policy_index)) {
13154235Smarkfen 					free(return_buf);
13164235Smarkfen 					free(polmsg.iov_base);
13174235Smarkfen 					(void) close(fd);
13184235Smarkfen 					return (ENOMEM);
13194235Smarkfen 				}
13204235Smarkfen 			}
13214235Smarkfen 
13224235Smarkfen 			free(return_buf);
13234235Smarkfen 		}
13244235Smarkfen 	}
13254235Smarkfen 
13264235Smarkfen 	free(polmsg.iov_base);
13274235Smarkfen 	(void) close(fd);
13284235Smarkfen 
13294235Smarkfen 	return (0);
13304235Smarkfen 
13314235Smarkfen }
13324235Smarkfen 
13334235Smarkfen int
main(int argc,char * argv[])13344235Smarkfen main(int argc, char *argv[])
13354235Smarkfen {
13364235Smarkfen 	int ret, flushret;
13374235Smarkfen 	int c;
13384235Smarkfen 	int index;
13394235Smarkfen 	boolean_t smf_managed;
13404235Smarkfen 	boolean_t just_check = B_FALSE;
134111278SMark.Fenwick@Sun.COM 	boolean_t replace_policy = B_FALSE;
13424235Smarkfen 
13434235Smarkfen 	char *smf_warning = gettext(
13445120Smarkfen 	    "\n\tIPsec policy should be managed using smf(5). Modifying\n"
13455120Smarkfen 	    "\tthe IPsec policy from the command line while the 'policy'\n"
13465120Smarkfen 	    "\tservice is enabled could result in an inconsistent\n"
13475120Smarkfen 	    "\tsecurity policy.\n\n");
13484235Smarkfen 
13494235Smarkfen 	flushret = 0;
135011278SMark.Fenwick@Sun.COM 	cmd = 0;
13514235Smarkfen 
13524235Smarkfen 	(void) setlocale(LC_ALL, "");
13534235Smarkfen #if !defined(TEXT_DOMAIN)
13544235Smarkfen #define	TEXT_DOMAIN "SYS_TEST"
13554235Smarkfen #endif
13564235Smarkfen 	(void) textdomain(TEXT_DOMAIN);
13574235Smarkfen 
13584235Smarkfen 	openlog("ipsecconf", LOG_CONS, LOG_AUTH);
13594235Smarkfen 
13604235Smarkfen 	/*
13614235Smarkfen 	 * We don't immediately check for privilege here. This is done by IP
13624235Smarkfen 	 * when we open /dev/ip below.
13634235Smarkfen 	 */
13644235Smarkfen 
13654235Smarkfen 	if (argc == 1) {
13664235Smarkfen 		cmd = IPSEC_CONF_VIEW;
13674235Smarkfen 		goto done;
13684235Smarkfen 	}
13694235Smarkfen 	my_fmri = getenv("SMF_FMRI");
13704235Smarkfen 	if (my_fmri == NULL)
13714235Smarkfen 		smf_managed = B_FALSE;
13724235Smarkfen 	else
13734235Smarkfen 		smf_managed = B_TRUE;
13744235Smarkfen 
13754235Smarkfen 	while ((c = getopt(argc, argv, "nlfLFa:qd:r:i:c:")) != EOF) {
13764235Smarkfen 		switch (c) {
13774235Smarkfen 		case 'F':
13784235Smarkfen 			if (interface_name != NULL) {
13794235Smarkfen 				USAGE();
13804235Smarkfen 				EXIT_FATAL("interface name not required.");
13814235Smarkfen 			}
13824235Smarkfen 			/* Apply to all policy heads - global and tunnels. */
13834235Smarkfen 			interface_name = &all_polheads;
13844235Smarkfen 			/* FALLTHRU */
13854235Smarkfen 		case 'f':
138611278SMark.Fenwick@Sun.COM 			/*
138711278SMark.Fenwick@Sun.COM 			 * The policy flush command can be specified with -a
138811278SMark.Fenwick@Sun.COM 			 * to perform an atomic policy replace. It can't be
138911278SMark.Fenwick@Sun.COM 			 * specified with any other flags.
139011278SMark.Fenwick@Sun.COM 			 */
139111278SMark.Fenwick@Sun.COM 			if (cmd == IPSEC_CONF_ADD) {
139211278SMark.Fenwick@Sun.COM 				cmd = IPSEC_CONF_REPLACE;
139311278SMark.Fenwick@Sun.COM 				break;
139411278SMark.Fenwick@Sun.COM 			}
13954235Smarkfen 			if (cmd != 0) {
13964235Smarkfen 				USAGE();
13974235Smarkfen 				EXIT_FATAL("Multiple commands specified");
13984235Smarkfen 			}
13994235Smarkfen 			cmd = IPSEC_CONF_FLUSH;
14004235Smarkfen 			break;
14014235Smarkfen 		case 'L':
14024235Smarkfen 			if (interface_name != NULL) {
14034235Smarkfen 				USAGE();
14044235Smarkfen 				EXIT_FATAL("interface name not required.");
14054235Smarkfen 			}
14064235Smarkfen 			/* Apply to all policy heads - global and tunnels. */
14074235Smarkfen 			interface_name = &all_polheads;
14084235Smarkfen 			/* FALLTHRU */
14094235Smarkfen 		case 'l':
14104235Smarkfen 			/* Only one command at a time */
14114235Smarkfen 			if (cmd != 0) {
14124235Smarkfen 				USAGE();
14134235Smarkfen 				EXIT_FATAL("Multiple commands specified");
14144235Smarkfen 			}
14154235Smarkfen 			cmd = IPSEC_CONF_LIST;
14164235Smarkfen 			break;
14174235Smarkfen 		case 'c':
14184235Smarkfen 			just_check = B_TRUE;
14194235Smarkfen 			ipsecconf_qflag++;
14204235Smarkfen 			/* FALLTHRU */
14214235Smarkfen 		case 'a':
142211278SMark.Fenwick@Sun.COM 			if (cmd == IPSEC_CONF_FLUSH) {
142311278SMark.Fenwick@Sun.COM 				cmd = IPSEC_CONF_REPLACE;
142411278SMark.Fenwick@Sun.COM 				filename = optarg;
142511278SMark.Fenwick@Sun.COM 				break;
142611278SMark.Fenwick@Sun.COM 			}
14274235Smarkfen 			/* Only one command at a time, and no interface name */
14284235Smarkfen 			if (cmd != 0 || interface_name != NULL) {
14294235Smarkfen 				USAGE();
14304235Smarkfen 				EXIT_FATAL("Multiple commands or interface "
14314235Smarkfen 				    "not required.");
14324235Smarkfen 			}
14334235Smarkfen 			cmd = IPSEC_CONF_ADD;
14344235Smarkfen 			filename = optarg;
14354235Smarkfen 			break;
14364235Smarkfen 		case 'd':
14374235Smarkfen 			/*
14384235Smarkfen 			 * Only one command at a time.  Interface name is
14394235Smarkfen 			 * optional.
14404235Smarkfen 			 */
14414235Smarkfen 			if (cmd != 0) {
14424235Smarkfen 				USAGE();
14434235Smarkfen 				EXIT_FATAL("Multiple commands specified");
14444235Smarkfen 			}
14454235Smarkfen 			cmd = IPSEC_CONF_DEL;
14464235Smarkfen 			index = parse_index(optarg, NULL);
14474235Smarkfen 			break;
14484235Smarkfen 		case 'n' :
14494235Smarkfen 			ipsecconf_nflag++;
14504235Smarkfen 			break;
14514235Smarkfen 		case 'q' :
14524235Smarkfen 			ipsecconf_qflag++;
14534235Smarkfen 			break;
14544235Smarkfen 		case 'r' :
14554235Smarkfen 			/* Only one command at a time, and no interface name */
14564235Smarkfen 			if (cmd != 0 || interface_name != NULL) {
14574235Smarkfen 				USAGE();
14584235Smarkfen 				EXIT_FATAL("Multiple commands or interface "
14594235Smarkfen 				    "not required.");
14604235Smarkfen 			}
14614235Smarkfen 			cmd = IPSEC_CONF_SUB;
14624235Smarkfen 			filename = optarg;
14634235Smarkfen 			break;
14644235Smarkfen 		case 'i':
14654235Smarkfen 			if (interface_name != NULL) {
14664235Smarkfen 				EXIT_FATAL("Interface name already selected");
14674235Smarkfen 			}
14684235Smarkfen 			interface_name = optarg;
14694235Smarkfen 			/* Check for some cretin using the all-polheads name. */
14704235Smarkfen 			if (strlen(optarg) == 0) {
14714235Smarkfen 				USAGE();
14724235Smarkfen 				EXIT_FATAL("Invalid interface name.");
14734235Smarkfen 			}
14744235Smarkfen 			break;
14754235Smarkfen 		default :
14764235Smarkfen 			USAGE();
14774235Smarkfen 			EXIT_FATAL("Bad usage.");
14784235Smarkfen 		}
14794235Smarkfen 	}
14804235Smarkfen 
14814235Smarkfen done:
14824235Smarkfen 	ret = 0;
14834235Smarkfen 	lfd = lock();
14844235Smarkfen 
14854235Smarkfen 	/*
14864235Smarkfen 	 * ADD, FLUSH, DELETE needs to do two operations.
14874235Smarkfen 	 *
14884235Smarkfen 	 * 1) Update/delete/empty the POLICY_CONF_FILE.
14894235Smarkfen 	 * 2) Make an ioctl and tell IP to update its state.
14904235Smarkfen 	 *
14914235Smarkfen 	 * We already lock()ed so that only one instance of this
14924235Smarkfen 	 * program runs. We also need to make sure that the above
14934235Smarkfen 	 * operations are atomic i.e we don't want to update the file
14944235Smarkfen 	 * and get interrupted before we could tell IP. To make it
14954235Smarkfen 	 * atomic we block all the signals and restore them.
14964235Smarkfen 	 */
14974235Smarkfen 	switch (cmd) {
14984235Smarkfen 	case IPSEC_CONF_LIST:
14994235Smarkfen 		fetch_algorithms();
15004235Smarkfen 		ret = ipsec_conf_list();
15014235Smarkfen 		break;
15024235Smarkfen 	case IPSEC_CONF_FLUSH:
15034235Smarkfen 		if ((ret = block_all_signals()) == -1) {
15044235Smarkfen 			break;
15054235Smarkfen 		}
15064235Smarkfen 		if (!smf_managed && !ipsecconf_qflag)
15074235Smarkfen 			(void) fprintf(stdout, "%s", smf_warning);
15084235Smarkfen 		ret = ipsec_conf_flush(SPD_ACTIVE);
15094235Smarkfen 		(void) restore_all_signals();
15104235Smarkfen 		break;
15114235Smarkfen 	case IPSEC_CONF_VIEW:
15124235Smarkfen 		if (interface_name != NULL) {
15134235Smarkfen 			EXIT_FATAL("Cannot view for one interface only.");
15144235Smarkfen 		}
15154235Smarkfen 		ret = ipsec_conf_view();
15164235Smarkfen 		break;
15174235Smarkfen 	case IPSEC_CONF_DEL:
15184235Smarkfen 		if (index == -1) {
15194235Smarkfen 			warnx(gettext("Invalid index"));
15204235Smarkfen 			ret = -1;
15214235Smarkfen 			break;
15224235Smarkfen 		}
15234235Smarkfen 		if ((ret = block_all_signals()) == -1) {
15244235Smarkfen 			break;
15254235Smarkfen 		}
15264235Smarkfen 		if (!smf_managed && !ipsecconf_qflag)
15274235Smarkfen 			(void) fprintf(stdout, "%s", smf_warning);
15284235Smarkfen 		ret = ipsec_conf_del(index, B_FALSE);
15294235Smarkfen 		(void) restore_all_signals();
15304235Smarkfen 		flushret = ipsec_conf_flush(SPD_STANDBY);
15314235Smarkfen 		break;
153211278SMark.Fenwick@Sun.COM 	case IPSEC_CONF_REPLACE:
153311278SMark.Fenwick@Sun.COM 		replace_policy = B_TRUE;
153411278SMark.Fenwick@Sun.COM 		/* FALLTHRU */
15354235Smarkfen 	case IPSEC_CONF_ADD:
15364235Smarkfen 		/*
15374235Smarkfen 		 * The IPsec kernel modules should only be loaded
15384235Smarkfen 		 * if there is a policy to install, for this
15394235Smarkfen 		 * reason ipsec_conf_add() calls fetch_algorithms()
15404235Smarkfen 		 * and ipsec_conf_flush() only when appropriate.
15414235Smarkfen 		 */
15424235Smarkfen 		if ((ret = block_all_signals()) == -1) {
15434235Smarkfen 			break;
15444235Smarkfen 		}
15454235Smarkfen 		if (!smf_managed && !ipsecconf_qflag)
15464235Smarkfen 			(void) fprintf(stdout, "%s", smf_warning);
154711278SMark.Fenwick@Sun.COM 		ret = ipsec_conf_add(just_check, smf_managed, replace_policy);
15484235Smarkfen 		(void) restore_all_signals();
15494235Smarkfen 		break;
15504235Smarkfen 	case IPSEC_CONF_SUB:
15514235Smarkfen 		fetch_algorithms();
15524235Smarkfen 		if ((ret = block_all_signals()) == -1) {
15534235Smarkfen 			break;
15544235Smarkfen 		}
15554235Smarkfen 		if (!smf_managed && !ipsecconf_qflag)
15564235Smarkfen 			(void) fprintf(stdout, "%s", smf_warning);
15574235Smarkfen 		ret = ipsec_conf_sub();
15584235Smarkfen 		(void) restore_all_signals();
15594235Smarkfen 		flushret = ipsec_conf_flush(SPD_STANDBY);
15604235Smarkfen 		break;
15614235Smarkfen 	default :
15624235Smarkfen 		/* If no argument is given but a "-" */
15634235Smarkfen 		USAGE();
15644235Smarkfen 		EXIT_FATAL("Bad usage.");
15654235Smarkfen 	}
15664235Smarkfen 
15674235Smarkfen 	(void) unlock(lfd);
15684235Smarkfen 	if (ret != 0 || flushret != 0)
15694235Smarkfen 		ret = 1;
15704235Smarkfen 	return (ret);
15714235Smarkfen }
15724235Smarkfen 
15734235Smarkfen static void
perm_check(void)15744235Smarkfen perm_check(void)
15754235Smarkfen {
15764235Smarkfen 	if (errno == EACCES)
15774235Smarkfen 		EXIT_BADPERM("Insufficient privilege to run ipsecconf.");
15784235Smarkfen 	else
15794235Smarkfen 		warn(gettext("Cannot open lock file %s"), LOCK_FILE);
15804235Smarkfen 
15814235Smarkfen 	EXIT_BADPERM(NULL);
15824235Smarkfen }
15834235Smarkfen 
15844235Smarkfen static int
lock()15854235Smarkfen lock()
15864235Smarkfen {
15874235Smarkfen 	int fd;
15884235Smarkfen 	struct stat sbuf1;
15894235Smarkfen 	struct stat sbuf2;
15904235Smarkfen 
15914235Smarkfen 	/*
15924235Smarkfen 	 * Open the file with O_CREAT|O_EXCL. If it exists already, it
15934235Smarkfen 	 * will fail. If it already exists, check whether it looks like
15944235Smarkfen 	 * the one we created.
15954235Smarkfen 	 */
15964235Smarkfen 	(void) umask(0077);
15974235Smarkfen 	if ((fd = open(LOCK_FILE, O_EXCL|O_CREAT|O_RDWR, S_IRUSR|S_IWUSR))
15984235Smarkfen 	    == -1) {
15994235Smarkfen 		if (errno != EEXIST) {
16004235Smarkfen 			/* Some other problem. Will exit. */
16014235Smarkfen 			perm_check();
16024235Smarkfen 		}
16034235Smarkfen 
16044235Smarkfen 		/*
16054235Smarkfen 		 * open() returned an EEXIST error. We don't fail yet
16064235Smarkfen 		 * as it could be a residual from a previous
16074235Smarkfen 		 * execution.
16084235Smarkfen 		 * File exists. make sure it is OK. We need to lstat()
16094235Smarkfen 		 * as fstat() stats the file pointed to by the symbolic
16104235Smarkfen 		 * link.
16114235Smarkfen 		 */
16124235Smarkfen 		if (lstat(LOCK_FILE, &sbuf1) == -1) {
16134235Smarkfen 			EXIT_FATAL2("Cannot lstat lock file %s", LOCK_FILE);
16144235Smarkfen 		}
16154235Smarkfen 		/*
16164235Smarkfen 		 * Check whether it is a regular file and not a symbolic
16174235Smarkfen 		 * link. Its link count should be 1. The owner should be
16184235Smarkfen 		 * root and the file should be empty.
16194235Smarkfen 		 */
16204235Smarkfen 		if (!S_ISREG(sbuf1.st_mode) ||
16214235Smarkfen 		    sbuf1.st_nlink != 1 ||
16224235Smarkfen 		    sbuf1.st_uid != 0 ||
16234235Smarkfen 		    sbuf1.st_size != 0) {
16244235Smarkfen 			EXIT_FATAL2("Bad lock file %s", LOCK_FILE);
16254235Smarkfen 		}
16264235Smarkfen 		if ((fd = open(LOCK_FILE, O_CREAT|O_RDWR,
16274235Smarkfen 		    S_IRUSR|S_IWUSR)) == -1) {
16284235Smarkfen 			/* Will exit */
16294235Smarkfen 			perm_check();
16304235Smarkfen 		}
16314235Smarkfen 		/*
16324235Smarkfen 		 * Check whether we opened the file that we lstat()ed.
16334235Smarkfen 		 */
16344235Smarkfen 		if (fstat(fd, &sbuf2) == -1) {
16354235Smarkfen 			EXIT_FATAL2("Cannot lstat lock file %s", LOCK_FILE);
16364235Smarkfen 		}
16374235Smarkfen 		if (sbuf1.st_dev != sbuf2.st_dev ||
16384235Smarkfen 		    sbuf1.st_ino != sbuf2.st_ino) {
16394235Smarkfen 			/* File changed after we did the lstat() above */
16404235Smarkfen 			EXIT_FATAL2("Bad lock file %s", LOCK_FILE);
16414235Smarkfen 		}
16424235Smarkfen 	}
16434235Smarkfen 	if (lockf(fd, F_LOCK, 0) == -1) {
16444235Smarkfen 		EXIT_FATAL2("Cannot lockf %s", LOCK_FILE);
16454235Smarkfen 	}
16464235Smarkfen 	return (fd);
16474235Smarkfen }
16484235Smarkfen 
16494235Smarkfen static int
unlock(int fd)16504235Smarkfen unlock(int fd)
16514235Smarkfen {
16524235Smarkfen 	if (lockf(fd, F_ULOCK, 0) == -1) {
16534235Smarkfen 		warn("lockf");
16544235Smarkfen 		return (-1);
16554235Smarkfen 	}
16564235Smarkfen 	return (0);
16574235Smarkfen }
16584235Smarkfen 
16594235Smarkfen /* send in TOK_* */
16604235Smarkfen static void
print_pattern_string(int type)16614235Smarkfen print_pattern_string(int type)
16624235Smarkfen {
16634235Smarkfen 	int j;
16644235Smarkfen 
16654235Smarkfen 	for (j = 0; pattern_table[j].string != NULL; j++) {
16664235Smarkfen 		if (type == pattern_table[j].tok_val) {
16674235Smarkfen 			(void) printf("%s ", pattern_table[j].string);
16684235Smarkfen 			return;
16694235Smarkfen 		}
16704235Smarkfen 	}
16714235Smarkfen }
16724235Smarkfen 
16734235Smarkfen static void
print_icmp_typecode(uint8_t type,uint8_t type_end,uint8_t code,uint8_t code_end)16744235Smarkfen print_icmp_typecode(uint8_t type, uint8_t type_end, uint8_t code,
16754235Smarkfen     uint8_t code_end)
16764235Smarkfen {
16774235Smarkfen 	(void) printf("type %d", type);
16784235Smarkfen 	if (type_end != type)
16794235Smarkfen 		(void) printf("-%d ", type_end);
16804235Smarkfen 	else
16814235Smarkfen 		(void) printf(" ");
16824235Smarkfen 	if (code != 255) {
16834235Smarkfen 		(void) printf("code %d", code);
16844235Smarkfen 		if (code_end != code)
16854235Smarkfen 			(void) printf("-%d ", code_end);
16864235Smarkfen 		else
16874235Smarkfen 			(void) printf(" ");
16884235Smarkfen 	}
16894235Smarkfen }
16904235Smarkfen 
16914235Smarkfen 
16924235Smarkfen static void
print_spd_flags(uint32_t flags)16934235Smarkfen print_spd_flags(uint32_t flags)
16944235Smarkfen {
16954235Smarkfen 	flags &= (SPD_RULE_FLAG_INBOUND|SPD_RULE_FLAG_OUTBOUND);
16964235Smarkfen 
16974235Smarkfen 	if (flags == SPD_RULE_FLAG_OUTBOUND)
16984235Smarkfen 		(void) printf("dir out ");
16994235Smarkfen 	else if (flags == SPD_RULE_FLAG_INBOUND)
17004235Smarkfen 		(void) printf("dir in ");
17014235Smarkfen 	else if (flags == (SPD_RULE_FLAG_INBOUND|SPD_RULE_FLAG_OUTBOUND))
17024235Smarkfen 		(void) printf("dir both ");
17034235Smarkfen }
17044235Smarkfen 
17054235Smarkfen static void
print_bit_range(int min,int max)17064235Smarkfen print_bit_range(int min, int max)
17074235Smarkfen {
17084235Smarkfen 	if (min != 0 || (max != 0 && max != SPD_MAX_MAXBITS)) {
17094235Smarkfen 		(void) printf("(");
17104235Smarkfen 		if (min != 0)
17114235Smarkfen 			(void) printf("%d", min);
17124235Smarkfen 		if (min != 0 && max != 0 && min != max) {
17134235Smarkfen 			(void) printf("..");
17144235Smarkfen 			if (max != 0 && max != SPD_MAX_MAXBITS)
17154235Smarkfen 				(void) printf("%d", max);
17164235Smarkfen 		}
17174235Smarkfen 		(void) printf(")");
17184235Smarkfen 	}
17194235Smarkfen }
17204235Smarkfen 
17214235Smarkfen static void
print_alg(const char * tag,algreq_t * algreq,int proto_num)17224235Smarkfen print_alg(const char *tag, algreq_t *algreq, int proto_num)
17234235Smarkfen {
17244235Smarkfen 	int min = algreq->alg_minbits;
17254235Smarkfen 	int max = algreq->alg_maxbits;
17264235Smarkfen 	struct ipsecalgent *alg;
17274235Smarkfen 
17284235Smarkfen 	/*
17294235Smarkfen 	 * This function won't be called with alg_id == 0, so we don't
17304235Smarkfen 	 * have to worry about ANY vs. NONE here.
17314235Smarkfen 	 */
17324235Smarkfen 
17334235Smarkfen 	(void) printf("%s ", tag);
17344235Smarkfen 
17354235Smarkfen 	alg = getipsecalgbynum(algreq->alg_id, proto_num, NULL);
17364235Smarkfen 	if (alg == NULL) {
17374235Smarkfen 		(void) printf("%d", algreq->alg_id);
17384235Smarkfen 	} else {
17394235Smarkfen 		(void) printf("%s", alg->a_names[0]);
17404235Smarkfen 		freeipsecalgent(alg);
17414235Smarkfen 	}
17424235Smarkfen 
17434235Smarkfen 	print_bit_range(min, max);
17444235Smarkfen 	(void) printf(" ");
17454235Smarkfen }
17464235Smarkfen 
17474235Smarkfen static void
print_ulp(uint8_t proto)17484235Smarkfen print_ulp(uint8_t proto)
17494235Smarkfen {
17504235Smarkfen 	struct protoent *pe;
17514235Smarkfen 
17524235Smarkfen 	if (proto == 0)
17534235Smarkfen 		return;
17544235Smarkfen 
17554235Smarkfen 	print_pattern_string(TOK_ulp);
17564235Smarkfen 	pe = NULL;
17574235Smarkfen 	if (!ipsecconf_nflag) {
17584235Smarkfen 		pe = getprotobynumber(proto);
17594235Smarkfen 	}
17604235Smarkfen 	if (pe != NULL)
17614235Smarkfen 		(void) printf("%s ", pe->p_name);
17624235Smarkfen 	else
17634235Smarkfen 		(void) printf("%d ", proto);
17644235Smarkfen }
17654235Smarkfen 
17664235Smarkfen /* needs to do ranges */
17674235Smarkfen static void
print_port(uint16_t in_port,int type)17684235Smarkfen print_port(uint16_t in_port, int type)
17694235Smarkfen {
17704235Smarkfen 	in_port_t port = ntohs(in_port);
17714235Smarkfen 	struct servent *sp;
17724235Smarkfen 
17734235Smarkfen 	if (port == 0)
17744235Smarkfen 		return;
17754235Smarkfen 
17764235Smarkfen 	print_pattern_string(type);
17774235Smarkfen 	sp = NULL;
17784235Smarkfen 	if (!ipsecconf_nflag)
17794235Smarkfen 		sp = getservbyport(port, NULL);
17804235Smarkfen 
17814235Smarkfen 	if (sp != NULL)
17824235Smarkfen 		(void) printf("%s ", sp->s_name);
17834235Smarkfen 	else
17844235Smarkfen 		(void) printf("%d ", port);
17854235Smarkfen }
17864235Smarkfen 
17874235Smarkfen /*
17884235Smarkfen  * Print the address, given as "raw" input via the void pointer.
17894235Smarkfen  */
17904235Smarkfen static void
print_raw_address(void * input,boolean_t isv4)17914235Smarkfen print_raw_address(void *input, boolean_t isv4)
17924235Smarkfen {
17934235Smarkfen 	char  *cp;
17944235Smarkfen 	struct hostent *hp;
17954235Smarkfen 	char	domain[MAXHOSTNAMELEN + 1];
17964235Smarkfen 	struct in_addr addr;
17974235Smarkfen 	struct in6_addr addr6;
17984235Smarkfen 	char abuf[INET6_ADDRSTRLEN];
17994235Smarkfen 	int error_num;
18004235Smarkfen 	struct in6_addr in_addr;
18014235Smarkfen 	uchar_t *addr_ptr;
18024235Smarkfen 	sa_family_t af;
18034235Smarkfen 	int addr_len;
18044235Smarkfen 
18054235Smarkfen 	if (isv4) {
18064235Smarkfen 		af = AF_INET;
18074235Smarkfen 		(void) memcpy(&V4_PART_OF_V6(in_addr), input, 4);
18084235Smarkfen 		/* we don't print unspecified addresses */
18094235Smarkfen 		IN6_V4MAPPED_TO_INADDR(&in_addr, &addr);
18104235Smarkfen 		if (addr.s_addr == INADDR_ANY)
18114235Smarkfen 			return;
18124235Smarkfen 		addr_ptr = (uchar_t *)&addr.s_addr;
18134235Smarkfen 		addr_len = IPV4_ADDR_LEN;
18144235Smarkfen 	} else {
18154235Smarkfen 		(void) memcpy(&addr6, input, 16);
18164235Smarkfen 		af = AF_INET6;
18174235Smarkfen 		/* we don't print unspecified addresses */
18184235Smarkfen 		if (IN6_IS_ADDR_UNSPECIFIED(&addr6))
18194235Smarkfen 			return;
18204235Smarkfen 		addr_ptr = (uchar_t *)&addr6.s6_addr;
18214235Smarkfen 		addr_len = sizeof (struct in6_addr);
18224235Smarkfen 	}
18234235Smarkfen 
18244235Smarkfen 	cp = NULL;
18254235Smarkfen 	if (!ipsecconf_nflag) {
18264235Smarkfen 		if (sysinfo(SI_HOSTNAME, domain, MAXHOSTNAMELEN) != -1 &&
18275120Smarkfen 		    (cp = strchr(domain, '.')) != NULL) {
18284235Smarkfen 			(void) strlcpy(domain, cp + 1, sizeof (domain));
18294235Smarkfen 		} else {
18304235Smarkfen 			domain[0] = 0;
18314235Smarkfen 		}
18327174Spwernau 		cp = NULL;
18334235Smarkfen 		hp = getipnodebyaddr(addr_ptr, addr_len, af, &error_num);
18344235Smarkfen 		if (hp) {
18354235Smarkfen 			if ((cp = strchr(hp->h_name, '.')) != 0 &&
18365120Smarkfen 			    strcasecmp(cp + 1, domain) == 0)
18374235Smarkfen 				*cp = 0;
18384235Smarkfen 			cp = hp->h_name;
18394235Smarkfen 		}
18404235Smarkfen 	}
18414235Smarkfen 
18424235Smarkfen 	if (cp) {
18434235Smarkfen 		(void) printf("%s", cp);
18444235Smarkfen 	} else {
18454235Smarkfen 		(void) printf("%s", inet_ntop(af, addr_ptr, abuf,
18464235Smarkfen 		    INET6_ADDRSTRLEN));
18474235Smarkfen 	}
18484235Smarkfen }
18494235Smarkfen 
18504235Smarkfen /*
18514235Smarkfen  * Get the next SPD_DUMP message from the PF_POLICY socket.  A single
18524235Smarkfen  * read may contain multiple messages.  This function uses static buffers,
18534235Smarkfen  * and is therefore non-reentrant, so if you lift it for an MT application,
18544235Smarkfen  * be careful.
18554235Smarkfen  *
18564235Smarkfen  * Return NULL if there's an error.
18574235Smarkfen  */
18584235Smarkfen static spd_msg_t *
ipsec_read_dump(int pfd)18594235Smarkfen ipsec_read_dump(int pfd)
18604235Smarkfen {
18614235Smarkfen 	static uint64_t buf[SADB_8TO64(CBUF_LEN)];
18624235Smarkfen 	static uint64_t *offset;
18634235Smarkfen 	static int len;		/* In uint64_t units. */
18644235Smarkfen 	spd_msg_t *retval;
18654235Smarkfen 
18664235Smarkfen 	/* Assume offset and len are initialized to NULL and 0. */
18674235Smarkfen 
18684235Smarkfen 	if ((offset - len == buf) || (offset == NULL)) {
18694235Smarkfen 		/* read a new block from the socket. */
18704235Smarkfen 		len = read(pfd, &buf, sizeof (buf));
18714235Smarkfen 		if (len == -1) {
18724235Smarkfen 			warn(gettext("rule dump: bad read"));
18734235Smarkfen 			return (NULL);
18744235Smarkfen 		}
18754235Smarkfen 		offset = buf;
18764235Smarkfen 		len = SADB_8TO64(len);
18774235Smarkfen 	} /* Else I still have more messages from a previous read. */
18784235Smarkfen 
18794235Smarkfen 	retval = (spd_msg_t *)offset;
18804235Smarkfen 	offset += retval->spd_msg_len;
18814235Smarkfen 	if (offset > buf + len) {
18824235Smarkfen 		warnx(gettext("dump read: message corruption,"
18834235Smarkfen 		    " %d len exceeds %d boundary."),
18844235Smarkfen 		    SADB_64TO8((uintptr_t)(offset - buf)),
188512131Sdanmcd@opensolaris.org 		    SADB_64TO8((uintptr_t)(len)));
18864235Smarkfen 		return (NULL);
18874235Smarkfen 	}
18884235Smarkfen 
18894235Smarkfen 	return (retval);
18904235Smarkfen }
18914235Smarkfen 
18924235Smarkfen /*
18934235Smarkfen  * returns 0 on success
18944235Smarkfen  * -1 on read error
18954235Smarkfen  * >0  on invalid returned message
18964235Smarkfen  */
18974235Smarkfen 
18984235Smarkfen static int
ipsec_conf_list(void)18994235Smarkfen ipsec_conf_list(void)
19004235Smarkfen {
19014235Smarkfen 	int ret;
19024235Smarkfen 	int pfd;
19034235Smarkfen 	struct spd_msg *msg;
19044235Smarkfen 	int cnt;
19054235Smarkfen 	spd_msg_t *rmsg;
19064235Smarkfen 	spd_ext_t *exts[SPD_EXT_MAX+1];
19074235Smarkfen 	/*
19084235Smarkfen 	 * Add an extra 8 bytes of space (+1 uint64_t) to avoid truncation
19094235Smarkfen 	 * issues.
19104235Smarkfen 	 */
19114235Smarkfen 	uint64_t buffer[
19124235Smarkfen 	    SPD_8TO64(sizeof (*msg) + sizeof (spd_if_t) + LIFNAMSIZ) + 1];
19134235Smarkfen 
19144235Smarkfen 	pfd = get_pf_pol_socket();
19154235Smarkfen 
19164235Smarkfen 	if (pfd == -1) {
19174235Smarkfen 		warnx(gettext("Error getting list of policies from kernel"));
19184235Smarkfen 		return (-1);
19194235Smarkfen 	}
19204235Smarkfen 
19214235Smarkfen 	(void) memset(buffer, 0, sizeof (buffer));
19224235Smarkfen 	msg = (struct spd_msg *)buffer;
19234235Smarkfen 	msg->spd_msg_version = PF_POLICY_V1;
19244235Smarkfen 	msg->spd_msg_type = SPD_DUMP;
19254235Smarkfen 	msg->spd_msg_len = SPD_8TO64(sizeof (*msg));
19264235Smarkfen 
19274235Smarkfen 	msg->spd_msg_len += attach_tunname((spd_if_t *)(msg + 1));
19284235Smarkfen 
19294235Smarkfen 	cnt = write(pfd, msg, SPD_64TO8(msg->spd_msg_len));
19304235Smarkfen 
19314235Smarkfen 	if (cnt < 0) {
19324235Smarkfen 		warn(gettext("dump: invalid write() return"));
19334235Smarkfen 		(void) close(pfd);
19344235Smarkfen 		return (-1);
19354235Smarkfen 	}
19364235Smarkfen 
19374235Smarkfen 	rmsg = ipsec_read_dump(pfd);
19384235Smarkfen 
19394235Smarkfen 	if (rmsg == NULL || rmsg->spd_msg_errno != 0) {
19404235Smarkfen 		warnx("%s: %s", gettext("ruleset dump failed"),
19414235Smarkfen 		    (rmsg == NULL ?
19425120Smarkfen 		    gettext("read error") :
19435120Smarkfen 		    sys_error_message(rmsg->spd_msg_errno)));
19444235Smarkfen 		(void) close(pfd);
19454235Smarkfen 		return (-1);
19464235Smarkfen 	}
19474235Smarkfen 
19484235Smarkfen 
19494235Smarkfen 	for (;;) {
19504235Smarkfen 		/* read rule */
19514235Smarkfen 		rmsg = ipsec_read_dump(pfd);
19524235Smarkfen 
19534235Smarkfen 		if (rmsg == NULL) {
19544235Smarkfen 			(void) close(pfd);
19554235Smarkfen 			return (-1);
19564235Smarkfen 		}
19574235Smarkfen 
19584235Smarkfen 		if (rmsg->spd_msg_errno != 0) {
19594235Smarkfen 			warnx("%s: %s", gettext("dump read: bad message"),
19604235Smarkfen 			    sys_error_message(rmsg->spd_msg_errno));
19614235Smarkfen 			(void) close(pfd);
19624235Smarkfen 			return (-1);
19634235Smarkfen 		}
19644235Smarkfen 
19654235Smarkfen 		ret = spdsock_get_ext(exts, rmsg, rmsg->spd_msg_len,
19664235Smarkfen 		    spdsock_diag_buf, SPDSOCK_DIAG_BUF_LEN);
19674235Smarkfen 		if (ret != 0) {
19684235Smarkfen 			if (strlen(spdsock_diag_buf) != 0)
19694235Smarkfen 				warnx(spdsock_diag_buf);
19704235Smarkfen 			warnx("%s: %s", gettext("dump read: bad message"),
19714235Smarkfen 			    sys_error_message(rmsg->spd_msg_errno));
19724235Smarkfen 			(void) close(pfd);
19734235Smarkfen 			return (ret);
19744235Smarkfen 		}
19754235Smarkfen 
19764235Smarkfen 		/*
19774235Smarkfen 		 * End of dump..
19784235Smarkfen 		 */
19794235Smarkfen 		if (exts[SPD_EXT_RULESET] != NULL)
19804235Smarkfen 			break;	/* and return 0. */
19814235Smarkfen 
19824235Smarkfen 		print_pfpol_msg(rmsg);
19834235Smarkfen 	}
19844235Smarkfen 
19854235Smarkfen 	(void) close(pfd);
19864235Smarkfen 	return (0);
19874235Smarkfen }
19884235Smarkfen 
19894235Smarkfen static void
print_iap(ips_act_props_t * iap)19904235Smarkfen print_iap(ips_act_props_t *iap)
19914235Smarkfen {
19924235Smarkfen 
19934235Smarkfen 	/* action */
19944235Smarkfen 	switch (iap->iap_action) {
19954235Smarkfen 	case SPD_ACTTYPE_PASS:
19964235Smarkfen 		(void) printf("pass ");
19974235Smarkfen 		break;
19984235Smarkfen 	case SPD_ACTTYPE_DROP:
19994235Smarkfen 		(void) printf("drop ");
20004235Smarkfen 		break;
20014235Smarkfen 	case SPD_ACTTYPE_IPSEC:
20024235Smarkfen 		(void) printf("ipsec ");
20034235Smarkfen 		break;
20044235Smarkfen 	}
20054235Smarkfen 
20064235Smarkfen 	/* properties */
20074235Smarkfen 	(void) printf("%c ", CURL_BEGIN);
20084235Smarkfen 	if (iap->iap_action == SPD_ACTTYPE_IPSEC) {
20094235Smarkfen 		if (iap->iap_attr & SPD_APPLY_AH &&
20104235Smarkfen 		    iap->iap_aauth.alg_id != 0)
20114235Smarkfen 			print_alg("auth_algs", &iap->iap_aauth,
20124235Smarkfen 			    IPSEC_PROTO_AH);
20134235Smarkfen 
20144235Smarkfen 		if (iap->iap_attr & SPD_APPLY_ESP) {
20154235Smarkfen 			print_alg("encr_algs", &iap->iap_eencr,
20164235Smarkfen 			    IPSEC_PROTO_ESP);
20174235Smarkfen 			if (iap->iap_eauth.alg_id != 0)
20184235Smarkfen 				print_alg("encr_auth_algs", &iap->iap_eauth,
20194235Smarkfen 				    IPSEC_PROTO_AH);
20204235Smarkfen 		}
20214235Smarkfen 		if (iap->iap_attr & SPD_APPLY_UNIQUE)
20224235Smarkfen 			(void) printf("sa unique ");
20234235Smarkfen 		else
20244235Smarkfen 			(void) printf("sa shared ");
20254235Smarkfen 	}
20264235Smarkfen 	(void) printf("%c ", CURL_END);
20274235Smarkfen }
20284235Smarkfen 
20294235Smarkfen 
20304235Smarkfen static void
print_pfpol_msg(spd_msg_t * msg)20314235Smarkfen print_pfpol_msg(spd_msg_t *msg)
20324235Smarkfen {
20334235Smarkfen 	spd_ext_t *exts[SPD_EXT_MAX+1];
20344235Smarkfen 	spd_address_t *spd_address;
20354235Smarkfen 	struct spd_rule *spd_rule;
20364235Smarkfen 	struct spd_proto *spd_proto;
20374235Smarkfen 	struct spd_portrange *spd_portrange;
20384235Smarkfen 	struct spd_ext_actions *spd_ext_actions;
20394235Smarkfen 	struct spd_typecode *spd_typecode;
20404235Smarkfen 	struct spd_attribute *app;
20414235Smarkfen 	spd_if_t *spd_if;
20424235Smarkfen 	uint32_t rv;
20434235Smarkfen 	uint16_t act_count;
20444235Smarkfen 
20454235Smarkfen 	rv = spdsock_get_ext(exts, msg, msg->spd_msg_len, spdsock_diag_buf,
20464235Smarkfen 	    SPDSOCK_DIAG_BUF_LEN);
20474235Smarkfen 
20484235Smarkfen 	if (rv == KGE_OK && exts[SPD_EXT_RULE] != NULL) {
20494235Smarkfen 		spd_if = (spd_if_t *)exts[SPD_EXT_TUN_NAME];
20504235Smarkfen 		spd_rule = (struct spd_rule *)exts[SPD_EXT_RULE];
20514235Smarkfen 		if (spd_if == NULL) {
20524235Smarkfen 			(void) printf("%s %lld\n", INDEX_TAG,
20534235Smarkfen 			    spd_rule->spd_rule_index);
20544235Smarkfen 		} else {
20554235Smarkfen 			(void) printf("%s %s,%lld\n", INDEX_TAG,
20564235Smarkfen 			    (char *)spd_if->spd_if_name,
20574235Smarkfen 			    spd_rule->spd_rule_index);
20584235Smarkfen 		}
20594235Smarkfen 	} else {
20604235Smarkfen 		if (strlen(spdsock_diag_buf) != 0)
20614235Smarkfen 			warnx(spdsock_diag_buf);
20624235Smarkfen 		warnx(gettext("print_pfpol_msg: malformed PF_POLICY message."));
20634235Smarkfen 		return;
20644235Smarkfen 	}
20654235Smarkfen 
20664235Smarkfen 	(void) printf("%c ", CURL_BEGIN);
20674235Smarkfen 
20684235Smarkfen 	if (spd_if != NULL) {
20694235Smarkfen 		(void) printf("tunnel %s negotiate %s ",
20704235Smarkfen 		    (char *)spd_if->spd_if_name,
20714235Smarkfen 		    (spd_rule->spd_rule_flags & SPD_RULE_FLAG_TUNNEL) ?
20724235Smarkfen 		    "tunnel" : "transport");
20734235Smarkfen 	}
20744235Smarkfen 
20754235Smarkfen 	if (exts[SPD_EXT_PROTO] != NULL) {
20764235Smarkfen 		spd_proto = (struct spd_proto *)exts[SPD_EXT_PROTO];
20774235Smarkfen 		print_ulp(spd_proto->spd_proto_number);
20784235Smarkfen 	}
20794235Smarkfen 
20804235Smarkfen 	if (exts[SPD_EXT_LCLADDR] != NULL) {
20814235Smarkfen 		spd_address = (spd_address_t *)exts[SPD_EXT_LCLADDR];
20824235Smarkfen 
20834235Smarkfen 		(void) printf("laddr ");
20844235Smarkfen 		print_raw_address((spd_address + 1),
20854235Smarkfen 		    (spd_address->spd_address_len == 2));
20864235Smarkfen 		(void) printf("/%d ", spd_address->spd_address_prefixlen);
20874235Smarkfen 	}
20884235Smarkfen 
20894235Smarkfen 	if (exts[SPD_EXT_LCLPORT] != NULL) {
20904235Smarkfen 		spd_portrange = (struct spd_portrange *)exts[SPD_EXT_LCLPORT];
20914235Smarkfen 		if (spd_portrange->spd_ports_minport != 0) {
20924235Smarkfen 			print_port(spd_portrange->spd_ports_minport,
20934235Smarkfen 			    TOK_lport);
20944235Smarkfen 		}
20954235Smarkfen 	}
20964235Smarkfen 
20974235Smarkfen 
20984235Smarkfen 	if (exts[SPD_EXT_REMADDR] != NULL) {
20994235Smarkfen 		spd_address = (spd_address_t *)exts[SPD_EXT_REMADDR];
21004235Smarkfen 
21014235Smarkfen 		(void) printf("raddr ");
21024235Smarkfen 		print_raw_address((spd_address + 1),
21034235Smarkfen 		    (spd_address->spd_address_len == 2));
21044235Smarkfen 		(void) printf("/%d ", spd_address->spd_address_prefixlen);
21054235Smarkfen 	}
21064235Smarkfen 
21074235Smarkfen 	if (exts[SPD_EXT_REMPORT] != NULL) {
21084235Smarkfen 		spd_portrange =
21095120Smarkfen 		    (struct spd_portrange *)exts[SPD_EXT_REMPORT];
21104235Smarkfen 		if (spd_portrange->spd_ports_minport != 0) {
21114235Smarkfen 			print_port(
21125120Smarkfen 			    spd_portrange->spd_ports_minport, TOK_rport);
21134235Smarkfen 		}
21144235Smarkfen 	}
21154235Smarkfen 
21164235Smarkfen 	if (exts[SPD_EXT_ICMP_TYPECODE] != NULL) {
21174235Smarkfen 		spd_typecode =
21184235Smarkfen 		    (struct spd_typecode *)exts[SPD_EXT_ICMP_TYPECODE];
21194235Smarkfen 		print_icmp_typecode(spd_typecode->spd_typecode_type,
21204235Smarkfen 		    spd_typecode->spd_typecode_type_end,
21214235Smarkfen 		    spd_typecode->spd_typecode_code,
21224235Smarkfen 		    spd_typecode->spd_typecode_code_end);
21234235Smarkfen 	}
21244235Smarkfen 
21254235Smarkfen 	if (exts[SPD_EXT_RULE] != NULL) {
21264235Smarkfen 		spd_rule = (struct spd_rule *)exts[SPD_EXT_RULE];
21274235Smarkfen 		print_spd_flags(spd_rule->spd_rule_flags);
21284235Smarkfen 	}
21294235Smarkfen 
21304235Smarkfen 
21314235Smarkfen 	(void) printf("%c ", CURL_END);
21324235Smarkfen 
21334235Smarkfen 	if (exts[SPD_EXT_ACTION] != NULL) {
21344235Smarkfen 		ips_act_props_t iap;
21354235Smarkfen 		int or_needed = 0;
21364235Smarkfen 
21374235Smarkfen 		(void) memset(&iap, 0, sizeof (iap));
21384235Smarkfen 		spd_ext_actions =
21394235Smarkfen 		    (struct spd_ext_actions *)exts[SPD_EXT_ACTION];
21404235Smarkfen 		app = (struct spd_attribute *)(spd_ext_actions + 1);
21414235Smarkfen 
21424235Smarkfen 		for (act_count = 0;
21434235Smarkfen 		    act_count < spd_ext_actions->spd_actions_len -1;
21445120Smarkfen 		    act_count++) {
21454235Smarkfen 
21464235Smarkfen 			switch (app->spd_attr_tag) {
21474235Smarkfen 
21484235Smarkfen 			case SPD_ATTR_NOP:
21494235Smarkfen 				break;
21504235Smarkfen 
21514235Smarkfen 			case SPD_ATTR_END:
21524235Smarkfen 				/* print */
21534235Smarkfen 				if (or_needed) {
21544235Smarkfen 					(void) printf("or ");
21554235Smarkfen 				} else {
21564235Smarkfen 					or_needed = 1;
21574235Smarkfen 				}
21584235Smarkfen 				print_iap(&iap);
21594235Smarkfen 				break;
21604235Smarkfen 
21614235Smarkfen 			case SPD_ATTR_EMPTY:
21624235Smarkfen 				/* clear */
21634235Smarkfen 				(void) memset(&iap, 0, sizeof (iap));
21644235Smarkfen 				break;
21654235Smarkfen 
21664235Smarkfen 			case SPD_ATTR_NEXT:
21674235Smarkfen 				/* print */
21684235Smarkfen 				if (or_needed) {
21694235Smarkfen 					(void) printf("or ");
21704235Smarkfen 				} else {
21714235Smarkfen 					or_needed = 1;
21724235Smarkfen 				}
21734235Smarkfen 
21744235Smarkfen 				print_iap(&iap);
21754235Smarkfen 				break;
21764235Smarkfen 
21774235Smarkfen 			case SPD_ATTR_TYPE:
21784235Smarkfen 				iap.iap_action = app->spd_attr_value;
21794235Smarkfen 				break;
21804235Smarkfen 
21814235Smarkfen 			case SPD_ATTR_FLAGS:
21824235Smarkfen 				iap.iap_attr = app->spd_attr_value;
21834235Smarkfen 				break;
21844235Smarkfen 
21854235Smarkfen 			case SPD_ATTR_AH_AUTH:
21864235Smarkfen 				iap.iap_aauth.alg_id = app->spd_attr_value;
21874235Smarkfen 				break;
21884235Smarkfen 
21894235Smarkfen 			case SPD_ATTR_ESP_ENCR:
21904235Smarkfen 				iap.iap_eencr.alg_id = app->spd_attr_value;
21914235Smarkfen 				break;
21924235Smarkfen 
21934235Smarkfen 			case SPD_ATTR_ESP_AUTH:
21944235Smarkfen 				iap.iap_eauth.alg_id = app->spd_attr_value;
21954235Smarkfen 				break;
21964235Smarkfen 
21974235Smarkfen 			case SPD_ATTR_ENCR_MINBITS:
21984235Smarkfen 				iap.iap_eencr.alg_minbits = app->spd_attr_value;
21994235Smarkfen 				break;
22004235Smarkfen 
22014235Smarkfen 			case SPD_ATTR_ENCR_MAXBITS:
22024235Smarkfen 				iap.iap_eencr.alg_maxbits = app->spd_attr_value;
22034235Smarkfen 				break;
22044235Smarkfen 
22054235Smarkfen 			case SPD_ATTR_AH_MINBITS:
22064235Smarkfen 				iap.iap_aauth.alg_minbits = app->spd_attr_value;
22074235Smarkfen 				break;
22084235Smarkfen 
22094235Smarkfen 			case SPD_ATTR_AH_MAXBITS:
22104235Smarkfen 				iap.iap_aauth.alg_maxbits = app->spd_attr_value;
22114235Smarkfen 				break;
22124235Smarkfen 
22134235Smarkfen 			case SPD_ATTR_ESPA_MINBITS:
22144235Smarkfen 				iap.iap_eauth.alg_minbits = app->spd_attr_value;
22154235Smarkfen 				break;
22164235Smarkfen 
22174235Smarkfen 			case SPD_ATTR_ESPA_MAXBITS:
22184235Smarkfen 				iap.iap_eauth.alg_maxbits = app->spd_attr_value;
22194235Smarkfen 				break;
22204235Smarkfen 
22214235Smarkfen 			case SPD_ATTR_LIFE_SOFT_TIME:
22224235Smarkfen 			case SPD_ATTR_LIFE_HARD_TIME:
22234235Smarkfen 			case SPD_ATTR_LIFE_SOFT_BYTES:
22244235Smarkfen 			case SPD_ATTR_LIFE_HARD_BYTES:
22254235Smarkfen 			default:
22264235Smarkfen 				(void) printf("\tattr %d: %X-%d\n",
22274235Smarkfen 				    act_count,
22284235Smarkfen 				    app->spd_attr_tag,
22294235Smarkfen 				    app->spd_attr_value);
22304235Smarkfen 				break;
22314235Smarkfen 			}
22324235Smarkfen 			app++;
22334235Smarkfen 		}
22344235Smarkfen 	}
22354235Smarkfen 
22364235Smarkfen 	(void) printf("\n");
22374235Smarkfen }
22384235Smarkfen 
22394235Smarkfen #ifdef DEBUG_HEAVY
22404235Smarkfen static void
pfpol_msg_dump(spd_msg_t * msg,char * tag)22414235Smarkfen pfpol_msg_dump(spd_msg_t *msg, char *tag)
22424235Smarkfen {
22434235Smarkfen 	spd_ext_t *exts[SPD_EXT_MAX+1];
22444235Smarkfen 	uint32_t i;
22454235Smarkfen 	spd_address_t *spd_address;
22464235Smarkfen 	struct spd_rule *spd_rule;
22474235Smarkfen 	struct spd_proto *spd_proto;
22484235Smarkfen 	struct spd_portrange *spd_portrange;
22494235Smarkfen 	struct spd_typecode *spd_typecode;
22504235Smarkfen 	struct spd_ext_actions *spd_ext_actions;
22514235Smarkfen 	struct spd_attribute *app;
22524235Smarkfen 	spd_if_t *spd_if;
22534235Smarkfen 	char abuf[INET6_ADDRSTRLEN];
22544235Smarkfen 	uint32_t rv;
22554235Smarkfen 	uint16_t act_count;
22564235Smarkfen 
22574235Smarkfen 	rv = spdsock_get_ext(exts, msg, msg->spd_msg_len, NULL, 0);
22584235Smarkfen 	if (rv != KGE_OK)
22594235Smarkfen 		return;
22604235Smarkfen 
22614235Smarkfen 	(void) printf("===========%s==============\n", tag);
22624235Smarkfen 	(void) printf("pfpol_msg_dump %d\n-------------------\n", rv);
22634235Smarkfen 
22644235Smarkfen 	(void) printf("spd_msg_version:%d\n", msg->spd_msg_version);
22654235Smarkfen 	(void) printf("spd_msg_type:%d\n", msg->spd_msg_type);
22664235Smarkfen 	(void) printf("spd_msg_errno:%d\n", msg->spd_msg_errno);
22674235Smarkfen 	(void) printf("spd_msg_spdid:%d\n", msg->spd_msg_spdid);
22684235Smarkfen 	(void) printf("spd_msg_len:%d\n", msg->spd_msg_len);
22694235Smarkfen 	(void) printf("spd_msg_diagnostic:%d\n", msg->spd_msg_diagnostic);
22704235Smarkfen 	(void) printf("spd_msg_seq:%d\n", msg->spd_msg_seq);
22714235Smarkfen 	(void) printf("spd_msg_pid:%d\n", msg->spd_msg_pid);
22724235Smarkfen 
22734235Smarkfen 	for (i = 1; i <= SPD_EXT_MAX; i++) {
22744235Smarkfen 		if (exts[i] == NULL) {
22754235Smarkfen 			printf("skipped %d\n", i);
22764235Smarkfen 			continue;
22774235Smarkfen 		}
22784235Smarkfen 
22794235Smarkfen 		switch (i) {
22804235Smarkfen 		case SPD_EXT_TUN_NAME:
22814235Smarkfen 			spd_if = (spd_if_t *)exts[i];
22824235Smarkfen 			(void) printf("spd_if = %s\n", spd_if->spd_if_name);
22834235Smarkfen 			break;
22844235Smarkfen 
22854235Smarkfen 		case SPD_EXT_ICMP_TYPECODE:
22864235Smarkfen 			spd_typecode = (struct spd_typecode *)exts[i];
22874235Smarkfen 			(void) printf("icmp type %d-%d code %d-%d\n",
22884235Smarkfen 			    spd_typecode->spd_typecode_type,
22894235Smarkfen 			    spd_typecode->spd_typecode_type_end,
22904235Smarkfen 			    spd_typecode->spd_typecode_code,
22914235Smarkfen 			    spd_typecode->spd_typecode_code_end);
22924235Smarkfen 			break;
22934235Smarkfen 
22944235Smarkfen 		case SPD_EXT_LCLPORT:
22954235Smarkfen 			spd_portrange = (struct spd_portrange *)exts[i];
22964235Smarkfen 			(void) printf("local ports %d-%d\n",
22974235Smarkfen 			    spd_portrange->spd_ports_minport,
22984235Smarkfen 			    spd_portrange->spd_ports_maxport);
22994235Smarkfen 
23004235Smarkfen 			break;
23014235Smarkfen 
23024235Smarkfen 		case SPD_EXT_REMPORT:
23034235Smarkfen 			spd_portrange = (struct spd_portrange *)exts[i];
23044235Smarkfen 			(void) printf("remote ports %d-%d\n",
23054235Smarkfen 			    spd_portrange->spd_ports_minport,
23064235Smarkfen 			    spd_portrange->spd_ports_maxport);
23074235Smarkfen 
23084235Smarkfen 			break;
23094235Smarkfen 
23104235Smarkfen 		case SPD_EXT_PROTO:
23114235Smarkfen 			spd_proto = (struct spd_proto *)exts[i];
23124235Smarkfen 			(void) printf("proto:spd_proto_exttype %d\n",
23134235Smarkfen 			    spd_proto->spd_proto_exttype);
23144235Smarkfen 			(void) printf("proto:spd_proto_number %d\n",
23154235Smarkfen 			    spd_proto->spd_proto_number);
23164235Smarkfen 			break;
23174235Smarkfen 
23184235Smarkfen 		case SPD_EXT_LCLADDR:
23194235Smarkfen 		case SPD_EXT_REMADDR:
23204235Smarkfen 			spd_address = (spd_address_t *)exts[i];
23214235Smarkfen 			if (i == SPD_EXT_LCLADDR)
23224235Smarkfen 				(void) printf("local addr ");
23234235Smarkfen 			else
23244235Smarkfen 				(void) printf("remote addr ");
23254235Smarkfen 
23264235Smarkfen 
23274235Smarkfen 			(void) printf("%s\n",
23284235Smarkfen 			    inet_ntop(spd_address->spd_address_af,
23295120Smarkfen 			    (void *) (spd_address +1), abuf,
23305120Smarkfen 			    INET6_ADDRSTRLEN));
23314235Smarkfen 
23324235Smarkfen 			(void) printf("prefixlen: %d\n",
23334235Smarkfen 			    spd_address->spd_address_prefixlen);
23344235Smarkfen 			break;
23354235Smarkfen 
23364235Smarkfen 		case SPD_EXT_ACTION:
23374235Smarkfen 			spd_ext_actions = (struct spd_ext_actions *)exts[i];
23384235Smarkfen 			(void) printf("spd_ext_action\n");
23394235Smarkfen 			(void) printf("spd_actions_count %d\n",
23404235Smarkfen 			    spd_ext_actions->spd_actions_count);
23414235Smarkfen 			app = (struct spd_attribute *)(spd_ext_actions + 1);
23424235Smarkfen 
23434235Smarkfen 			for (act_count = 0;
23444235Smarkfen 			    act_count < spd_ext_actions->spd_actions_len -1;
23454235Smarkfen 			    act_count++) {
23464235Smarkfen 				(void) printf("\tattr %d: %X-%d\n", act_count,
23474235Smarkfen 				    app->spd_attr_tag, app->spd_attr_value);
23484235Smarkfen 				app++;
23494235Smarkfen 			}
23504235Smarkfen 
23514235Smarkfen 			break;
23524235Smarkfen 
23534235Smarkfen 		case SPD_EXT_RULE:
23544235Smarkfen 			spd_rule = (struct spd_rule *)exts[i];
23554235Smarkfen 			(void) printf("spd_rule_priority: 0x%x\n",
23564235Smarkfen 			    spd_rule->spd_rule_priority);
23574235Smarkfen 			(void) printf("spd_rule_flags: %d\n",
23584235Smarkfen 			    spd_rule->spd_rule_flags);
23594235Smarkfen 			break;
23604235Smarkfen 
23614235Smarkfen 		case SPD_EXT_RULESET:
23624235Smarkfen 			(void) printf("spd_ext_ruleset\n");
23634235Smarkfen 			break;
23644235Smarkfen 		default:
23654235Smarkfen 			(void) printf("default\n");
23664235Smarkfen 			break;
23674235Smarkfen 		}
23684235Smarkfen 	}
23694235Smarkfen 
23704235Smarkfen 	(void) printf("-------------------\n");
23714235Smarkfen 	(void) printf("=========================\n");
23724235Smarkfen }
23734235Smarkfen #endif /* DEBUG_HEAVY */
23744235Smarkfen 
23754235Smarkfen static int
ipsec_conf_view()23764235Smarkfen ipsec_conf_view()
23774235Smarkfen {
23784235Smarkfen 	char buf[MAXLEN];
23794235Smarkfen 	FILE *fp;
23804235Smarkfen 
23814235Smarkfen 	fp = fopen(POLICY_CONF_FILE, "r");
23824235Smarkfen 	if (fp == NULL) {
23834235Smarkfen 		if (errno == ENOENT) {
23844235Smarkfen 			/*
23854235Smarkfen 			 * The absence of POLICY_CONF_FILE should
23864235Smarkfen 			 * not cause the command to exit with a
23874235Smarkfen 			 * non-zero status, since this condition
23884235Smarkfen 			 * is valid when no policies were previously
23894235Smarkfen 			 * defined.
23904235Smarkfen 			 */
23914235Smarkfen 			return (0);
23924235Smarkfen 		}
23934235Smarkfen 		warn(gettext("%s cannot be opened"), POLICY_CONF_FILE);
23944235Smarkfen 		return (-1);
23954235Smarkfen 	}
23964235Smarkfen 	while (fgets(buf, MAXLEN, fp) != NULL) {
23974235Smarkfen 		/* Don't print removed entries */
23984235Smarkfen 		if (*buf == ';')
23994235Smarkfen 			continue;
24004235Smarkfen 		if (strlen(buf) != 0)
24014235Smarkfen 			buf[strlen(buf) - 1] = '\0';
24024235Smarkfen 		(void) puts(buf);
24034235Smarkfen 	}
24044235Smarkfen 	return (0);
24054235Smarkfen }
24064235Smarkfen 
24074235Smarkfen /*
24084235Smarkfen  * Delete nlines from start in the POLICY_CONF_FILE.
24094235Smarkfen  */
24104235Smarkfen static int
delete_from_file(int start,int nlines)24114235Smarkfen delete_from_file(int start, int nlines)
24124235Smarkfen {
24134235Smarkfen 	FILE *fp;
24144235Smarkfen 	char ibuf[MAXLEN];
24154235Smarkfen 	int len;
24164235Smarkfen 
24174235Smarkfen 	if ((fp = fopen(POLICY_CONF_FILE, "r+b")) == NULL) {
24184235Smarkfen 		warn(gettext("%s cannot be opened"), POLICY_CONF_FILE);
24194235Smarkfen 		return (-1);
24204235Smarkfen 	}
24214235Smarkfen 
24224235Smarkfen 	/*
24234235Smarkfen 	 * Insert a ";", read the line and discard it. Repeat
24244235Smarkfen 	 * this logic nlines - 1 times. For the last line there
24254235Smarkfen 	 * is just a newline character. We can't just insert a
24264235Smarkfen 	 * single ";" character instead of the newline character
24274235Smarkfen 	 * as it would affect the next line. Thus when we comment
24284235Smarkfen 	 * the last line we seek one less and insert a ";"
24294235Smarkfen 	 * character, which will replace the newline of the
24304235Smarkfen 	 * penultimate line with ; and newline of the last line
24314235Smarkfen 	 * will become part of the previous line.
24324235Smarkfen 	 */
24334235Smarkfen 	do {
24344235Smarkfen 		/*
24354235Smarkfen 		 * It is not enough to seek just once and expect the
24364235Smarkfen 		 * subsequent fgets below to take you to the right
24374235Smarkfen 		 * offset of the next line. fgets below seems to affect
24384235Smarkfen 		 * the offset. Thus we need to seek, replace with ";",
24394235Smarkfen 		 * and discard a line using fgets for every line.
24404235Smarkfen 		 */
24414235Smarkfen 		if (fseek(fp, start, SEEK_SET) == -1) {
24424235Smarkfen 			warn("fseek");
24434235Smarkfen 			return (-1);
24444235Smarkfen 		}
24454235Smarkfen 		if (fputc(';', fp) < 0) {
24464235Smarkfen 			warn("fputc");
24474235Smarkfen 			return (-1);
24484235Smarkfen 		}
24494235Smarkfen 		/*
24504235Smarkfen 		 * Flush the above ";" character before we do the fgets().
24514235Smarkfen 		 * Without this, fgets() gets confused with offsets.
24524235Smarkfen 		 */
24534235Smarkfen 		(void) fflush(fp);
24544235Smarkfen 		len = 0;
24554235Smarkfen 		while (fgets(ibuf, MAXLEN, fp) != NULL) {
24564235Smarkfen 			len += strlen(ibuf);
24574235Smarkfen 			if (ibuf[len - 1] == '\n') {
24584235Smarkfen 				/*
24594235Smarkfen 				 * We have read a complete line.
24604235Smarkfen 				 */
24614235Smarkfen 				break;
24624235Smarkfen 			}
24634235Smarkfen 		}
24644235Smarkfen 		/*
24654235Smarkfen 		 * We read the line after ";" character has been inserted.
24664235Smarkfen 		 * Thus len does not count ";". To advance to the next line
24674235Smarkfen 		 * increment by 1.
24684235Smarkfen 		 */
24694235Smarkfen 		start += (len + 1);
24704235Smarkfen 		/*
24714235Smarkfen 		 * If nlines == 2, we will be commenting out the last
24724235Smarkfen 		 * line next, which has only one newline character.
24734235Smarkfen 		 * If we blindly replace it with ";", it will  be
24744235Smarkfen 		 * read as part of the next line which could have
24754235Smarkfen 		 * a INDEX string and thus confusing ipsec_conf_view.
24764235Smarkfen 		 * Thus, we seek one less and replace the previous
24774235Smarkfen 		 * line's newline character with ";", and the
24784235Smarkfen 		 * last line's newline character will become part of
24794235Smarkfen 		 * the previous line.
24804235Smarkfen 		 */
24814235Smarkfen 		if (nlines == 2)
24824235Smarkfen 			start--;
24834235Smarkfen 	} while (--nlines != 0);
24844235Smarkfen 	(void) fclose(fp);
24854235Smarkfen 	if (nlines != 0)
24864235Smarkfen 		return (-1);
24874235Smarkfen 	else
24884235Smarkfen 		return (0);
24894235Smarkfen }
24904235Smarkfen 
24914235Smarkfen /*
24924235Smarkfen  * Delete an entry from the file by inserting a ";" at the
24934235Smarkfen  * beginning of the lines to be removed.
24944235Smarkfen  */
24954235Smarkfen static int
ipsec_conf_del(int policy_index,boolean_t ignore_spd)24964235Smarkfen ipsec_conf_del(int policy_index, boolean_t ignore_spd)
24974235Smarkfen {
24984235Smarkfen 	act_prop_t *act_props = malloc(sizeof (act_prop_t));
24994235Smarkfen 	char *buf;
25004235Smarkfen 	FILE *fp;
25014235Smarkfen 	char ibuf[MAXLEN];
25024235Smarkfen 	int ibuf_len, index_len, index;
25034235Smarkfen 	int ret = 0;
25044235Smarkfen 	int offset, prev_offset;
25054235Smarkfen 	int nlines;
25064235Smarkfen 	char lifname[LIFNAMSIZ];
25074235Smarkfen 
25084235Smarkfen 	if (act_props == NULL) {
25094235Smarkfen 		warn(gettext("memory"));
25104235Smarkfen 		return (-1);
25114235Smarkfen 	}
25124235Smarkfen 
25134235Smarkfen 	fp = fopen(POLICY_CONF_FILE, "r");
25144235Smarkfen 	if (fp == NULL) {
25154235Smarkfen 		warn(gettext("%s cannot be opened"), POLICY_CONF_FILE);
25164235Smarkfen 		free(act_props);
25174235Smarkfen 		return (-1);
25184235Smarkfen 	}
25194235Smarkfen 
25204235Smarkfen 	index_len = strlen(INDEX_TAG);
25214235Smarkfen 	index = 0;
25224235Smarkfen 	for (offset = prev_offset = 0; fgets(ibuf, MAXLEN, fp) != NULL;
25234235Smarkfen 	    offset += ibuf_len) {
25244235Smarkfen 		prev_offset = offset;
25254235Smarkfen 		ibuf_len = strlen(ibuf);
25264235Smarkfen 
25274235Smarkfen 		if (strncmp(ibuf, INDEX_TAG, index_len) != 0) {
25284235Smarkfen 			continue;
25294235Smarkfen 		}
25304235Smarkfen 
25314235Smarkfen 		/*
25324235Smarkfen 		 * This line contains INDEX_TAG
25334235Smarkfen 		 */
25344235Smarkfen 		buf = ibuf + index_len;
25354235Smarkfen 		buf++;			/* Skip the space */
25364235Smarkfen 		index = parse_index(buf, lifname);
25374235Smarkfen 		if (index == -1) {
25384235Smarkfen 			warnx(gettext("Invalid index in the file"));
25394235Smarkfen 			free(act_props);
25404235Smarkfen 			return (-1);
25414235Smarkfen 		}
25424235Smarkfen 		if (index == policy_index &&
25434235Smarkfen 		    (interface_name == NULL ||
25445120Smarkfen 		    strncmp(interface_name, lifname, LIFNAMSIZ) == 0)) {
25454235Smarkfen 			if (!ignore_spd) {
25464235Smarkfen 				ret = parse_one(fp, act_props);
25474235Smarkfen 				if (ret == -1) {
25484235Smarkfen 					warnx(gettext("Invalid policy entry "
25494235Smarkfen 					    "in the file"));
25504235Smarkfen 					free(act_props);
25514235Smarkfen 					return (-1);
25524235Smarkfen 				}
25534235Smarkfen 			}
25544235Smarkfen 			/*
25554235Smarkfen 			 * nlines is the number of lines we should comment
25564235Smarkfen 			 * out. linecount tells us how many lines this command
25574235Smarkfen 			 * spans. And we need to remove the line with INDEX
25584235Smarkfen 			 * and an extra line we added during ipsec_conf_add.
25594235Smarkfen 			 *
25604235Smarkfen 			 * NOTE : If somebody added a policy entry which does
25614235Smarkfen 			 * not have a newline, ipsec_conf_add() fills in the
25624235Smarkfen 			 * newline. Hence, there is always 2 extra lines
25634235Smarkfen 			 * to delete.
25644235Smarkfen 			 */
25654235Smarkfen 			nlines = linecount + 2;
25664235Smarkfen 			goto delete;
25674235Smarkfen 		}
25684235Smarkfen 	}
25694235Smarkfen 
25704235Smarkfen 	if (!ignore_spd)
25714235Smarkfen 		ret = pfp_delete_rule(policy_index);
25724235Smarkfen 
25734235Smarkfen 	if (ret != 0) {
25744235Smarkfen 		warnx(gettext("Deletion incomplete. Please "
25754235Smarkfen 		    "flush all the entries and re-configure :"));
25764235Smarkfen 		reconfigure();
25774235Smarkfen 		free(act_props);
25784235Smarkfen 		return (ret);
25794235Smarkfen 	}
25804235Smarkfen 	free(act_props);
25814235Smarkfen 	return (ret);
25824235Smarkfen 
25834235Smarkfen delete:
25844235Smarkfen 	/* Delete nlines from prev_offset */
25854235Smarkfen 	(void) fclose(fp);
25864235Smarkfen 	ret = delete_from_file(prev_offset, nlines);
25874235Smarkfen 
25884235Smarkfen 	if (ret != 0) {
25894235Smarkfen 		warnx(gettext("Deletion incomplete. Please "
25904235Smarkfen 		    "flush all the entries and re-configure :"));
25914235Smarkfen 		reconfigure();
25924235Smarkfen 		free(act_props);
25934235Smarkfen 		return (ret);
25944235Smarkfen 	}
25954235Smarkfen 
25964235Smarkfen 	if (!ignore_spd)
25974235Smarkfen 		ret = pfp_delete_rule(policy_index);
25984235Smarkfen 
25994235Smarkfen 	if (ret != 0) {
26004235Smarkfen 		warnx(gettext("Deletion incomplete. Please "
26014235Smarkfen 		    "flush all the entries and re-configure :"));
26024235Smarkfen 		reconfigure();
26034235Smarkfen 		free(act_props);
26044235Smarkfen 		return (ret);
26054235Smarkfen 	}
26064235Smarkfen 	free(act_props);
26074235Smarkfen 	return (0);
26084235Smarkfen }
26094235Smarkfen 
26104235Smarkfen static int
pfp_delete_rule(uint64_t index)26114235Smarkfen pfp_delete_rule(uint64_t index)
26124235Smarkfen {
26134235Smarkfen 	struct spd_msg *msg;
26144235Smarkfen 	struct spd_rule *rule;
26154235Smarkfen 	int sfd;
26164235Smarkfen 	int cnt, len, alloclen;
26174235Smarkfen 
26184235Smarkfen 	sfd = get_pf_pol_socket();
26194235Smarkfen 	if (sfd < 0) {
26204235Smarkfen 		warn(gettext("unable to open policy socket"));
26214235Smarkfen 		return (-1);
26224235Smarkfen 	}
26234235Smarkfen 
26244235Smarkfen 	/*
26254235Smarkfen 	 * Add an extra 8 bytes of space (+1 uint64_t) to avoid truncation
26264235Smarkfen 	 * issues.
26274235Smarkfen 	 */
26284235Smarkfen 	alloclen = sizeof (spd_msg_t) + sizeof (struct spd_rule) +
26294235Smarkfen 	    sizeof (spd_if_t) + LIFNAMSIZ + 8;
26304235Smarkfen 	msg = (spd_msg_t *)malloc(alloclen);
26314235Smarkfen 
26324235Smarkfen 	if (msg == NULL) {
26334235Smarkfen 		warn("malloc");
26344235Smarkfen 		return (-1);
26354235Smarkfen 	}
26364235Smarkfen 
26374235Smarkfen 	rule = (struct spd_rule *)(msg + 1);
26384235Smarkfen 
26394235Smarkfen 	(void) memset(msg, 0, alloclen);
26404235Smarkfen 	msg->spd_msg_version = PF_POLICY_V1;
26414235Smarkfen 	msg->spd_msg_type = SPD_DELETERULE;
26424235Smarkfen 	msg->spd_msg_len = SPD_8TO64(sizeof (spd_msg_t)
26434235Smarkfen 	    + sizeof (struct spd_rule));
26444235Smarkfen 
26454235Smarkfen 	rule->spd_rule_type = SPD_EXT_RULE;
26464235Smarkfen 	rule->spd_rule_len = SPD_8TO64(sizeof (struct spd_rule));
26474235Smarkfen 	rule->spd_rule_index = index;
26484235Smarkfen 
26494235Smarkfen 	msg->spd_msg_len += attach_tunname((spd_if_t *)(rule + 1));
26504235Smarkfen 
26514235Smarkfen 	len = SPD_64TO8(msg->spd_msg_len);
26524235Smarkfen 	cnt = write(sfd, msg, len);
26534235Smarkfen 
26544235Smarkfen 	if (cnt != len) {
26554235Smarkfen 		if (cnt < 0) {
2656*12655SVladimir.Kotal@Sun.COM 			warn(gettext("Delete failed: write"));
26574235Smarkfen 			(void) close(sfd);
26584235Smarkfen 			free(msg);
26594235Smarkfen 			return (-1);
26604235Smarkfen 		} else {
26614235Smarkfen 			(void) close(sfd);
26624235Smarkfen 			free(msg);
26634235Smarkfen 			warnx(gettext("Delete failed: short write"));
26644235Smarkfen 			return (-1);
26654235Smarkfen 		}
26664235Smarkfen 	}
26674235Smarkfen 
26684235Smarkfen 	cnt = read(sfd, msg, len);
26694235Smarkfen 	if (cnt != len) {
26704235Smarkfen 		if (cnt < 0) {
2671*12655SVladimir.Kotal@Sun.COM 			warn(gettext("Delete failed: read"));
26724235Smarkfen 			(void) close(sfd);
26734235Smarkfen 			free(msg);
26744235Smarkfen 			return (-1);
26754235Smarkfen 		} else {
26764235Smarkfen 			(void) close(sfd);
26774235Smarkfen 			free(msg);
26784235Smarkfen 			warnx(gettext("Delete failed while reading reply"));
26794235Smarkfen 			return (-1);
26804235Smarkfen 		}
26814235Smarkfen 	}
26824235Smarkfen 	(void) close(sfd);
26834235Smarkfen 	if (msg->spd_msg_errno != 0) {
26844235Smarkfen 		errno = msg->spd_msg_errno;
26854235Smarkfen 		warn(gettext("Delete failed: SPD_FLUSH"));
2686*12655SVladimir.Kotal@Sun.COM 		free(msg);
26874235Smarkfen 		return (-1);
26884235Smarkfen 	}
26894235Smarkfen 
26904235Smarkfen 	free(msg);
26914235Smarkfen 	return (0);
26924235Smarkfen }
26934235Smarkfen 
26944235Smarkfen static int
ipsec_conf_flush(int db)26954235Smarkfen ipsec_conf_flush(int db)
26964235Smarkfen {
26974235Smarkfen 	int pfd, cnt, len;
26984235Smarkfen 	int sfd;
26994235Smarkfen 	struct spd_msg *msg;
27004235Smarkfen 	/*
27014235Smarkfen 	 * Add an extra 8 bytes of space (+1 uint64_t) to avoid truncation
27024235Smarkfen 	 * issues.
27034235Smarkfen 	 */
27044235Smarkfen 	uint64_t buffer[
27054235Smarkfen 	    SPD_8TO64(sizeof (*msg) + sizeof (spd_if_t) + LIFNAMSIZ) + 1];
27064235Smarkfen 
27074235Smarkfen 	sfd = get_pf_pol_socket();
27084235Smarkfen 	if (sfd < 0) {
27094235Smarkfen 		warn(gettext("unable to open policy socket"));
27104235Smarkfen 		return (-1);
27114235Smarkfen 	}
27124235Smarkfen 
27134235Smarkfen 	(void) memset(buffer, 0, sizeof (buffer));
27144235Smarkfen 	msg = (struct spd_msg *)buffer;
27154235Smarkfen 	msg->spd_msg_version = PF_POLICY_V1;
27164235Smarkfen 	msg->spd_msg_type = SPD_FLUSH;
27174235Smarkfen 	msg->spd_msg_len = SPD_8TO64(sizeof (*msg));
27184235Smarkfen 	msg->spd_msg_spdid = db;
27194235Smarkfen 
27204235Smarkfen 	msg->spd_msg_len += attach_tunname((spd_if_t *)(msg + 1));
27214235Smarkfen 
27224235Smarkfen 	len = SPD_64TO8(msg->spd_msg_len);
27234235Smarkfen 	cnt = write(sfd, msg, len);
27244235Smarkfen 	if (cnt != len) {
27254235Smarkfen 		if (cnt < 0) {
27264235Smarkfen 			warn(gettext("Flush failed: write"));
27274235Smarkfen 			return (-1);
27284235Smarkfen 		} else {
27294235Smarkfen 			warnx(gettext("Flush failed: short write"));
27304235Smarkfen 			return (-1);
27314235Smarkfen 		}
27324235Smarkfen 	}
27334235Smarkfen 
27344235Smarkfen 	cnt = read(sfd, msg, len);
27354235Smarkfen 	if (cnt != len) {
27364235Smarkfen 		if (cnt < 0) {
27374235Smarkfen 			warn(gettext("Flush failed: read"));
27384235Smarkfen 			return (-1);
27394235Smarkfen 		} else {
27404235Smarkfen 			warnx(gettext("Flush failed while reading reply"));
27414235Smarkfen 			return (-1);
27424235Smarkfen 		}
27434235Smarkfen 	}
27444235Smarkfen 	(void) close(sfd);
27454235Smarkfen 	if (msg->spd_msg_errno != 0) {
27464235Smarkfen 		warnx("%s: %s", gettext("Flush failed: SPD_FLUSH"),
27474235Smarkfen 		    sys_error_message(msg->spd_msg_errno));
27484235Smarkfen 		return (-1);
27494235Smarkfen 	}
27504235Smarkfen 
27514235Smarkfen 	/* Truncate the file */
27524235Smarkfen 	if (db == SPD_ACTIVE) {
27534235Smarkfen 		if ((pfd = open(POLICY_CONF_FILE, O_TRUNC|O_RDWR)) == -1) {
27544235Smarkfen 			if (errno == ENOENT) {
27554235Smarkfen 				/*
27564235Smarkfen 				 * The absence of POLICY_CONF_FILE should
27574235Smarkfen 				 * not cause the command to exit with a
27584235Smarkfen 				 * non-zero status, since this condition
27594235Smarkfen 				 * is valid when no policies were previously
27604235Smarkfen 				 * defined.
27614235Smarkfen 				 */
27624235Smarkfen 				return (0);
27634235Smarkfen 			}
27644235Smarkfen 			warn(gettext("%s cannot be truncated"),
27654235Smarkfen 			    POLICY_CONF_FILE);
27664235Smarkfen 			return (-1);
27674235Smarkfen 		}
27684235Smarkfen 		(void) close(pfd);
27694235Smarkfen 	}
27704235Smarkfen 	return (0);
27714235Smarkfen }
27724235Smarkfen 
27734235Smarkfen /*
27744235Smarkfen  * function to send SPD_FLIP and SPD_CLONE messages
27754235Smarkfen  * Do it for ALL polheads for simplicity's sake.
27764235Smarkfen  */
27774235Smarkfen static void
ipsec_conf_admin(uint8_t type)27784235Smarkfen ipsec_conf_admin(uint8_t type)
27794235Smarkfen {
27804235Smarkfen 	int cnt;
27814235Smarkfen 	int sfd;
27824235Smarkfen 	struct spd_msg *msg;
27834235Smarkfen 	uint64_t buffer[
27844235Smarkfen 	    SPD_8TO64(sizeof (struct spd_msg) + sizeof (spd_if_t))];
27854235Smarkfen 	char *save_ifname;
27864235Smarkfen 
27874235Smarkfen 	sfd = get_pf_pol_socket();
27884235Smarkfen 	if (sfd < 0) {
27894235Smarkfen 		err(-1, gettext("unable to open policy socket"));
27904235Smarkfen 	}
27914235Smarkfen 
27924235Smarkfen 	(void) memset(buffer, 0, sizeof (buffer));
27934235Smarkfen 	msg = (struct spd_msg *)buffer;
27944235Smarkfen 	msg->spd_msg_version = PF_POLICY_V1;
27954235Smarkfen 	msg->spd_msg_type = type;
27964235Smarkfen 	msg->spd_msg_len = SPD_8TO64(sizeof (buffer));
27974235Smarkfen 
27984235Smarkfen 	save_ifname = interface_name;
27994235Smarkfen 	/* Apply to all policy heads - global and tunnels. */
28004235Smarkfen 	interface_name = &all_polheads;
28014235Smarkfen 	(void) attach_tunname((spd_if_t *)(msg + 1));
28024235Smarkfen 	interface_name = save_ifname;
28034235Smarkfen 
28044235Smarkfen 	cnt = write(sfd, msg, sizeof (buffer));
28054235Smarkfen 	if (cnt != sizeof (buffer)) {
28064235Smarkfen 		if (cnt < 0) {
28074235Smarkfen 			err(-1, gettext("admin failed: write"));
28084235Smarkfen 		} else {
28094235Smarkfen 			errx(-1, gettext("admin failed: short write"));
28104235Smarkfen 		}
28114235Smarkfen 	}
28124235Smarkfen 
28134235Smarkfen 	cnt = read(sfd, msg, sizeof (buffer));
28144235Smarkfen 	if (cnt != sizeof (buffer)) {
28154235Smarkfen 		if (cnt < 0) {
28164235Smarkfen 			err(-1, gettext("admin failed: read"));
28174235Smarkfen 		} else {
28184235Smarkfen 			errx(-1, gettext("admin failed while reading reply"));
28194235Smarkfen 		}
28204235Smarkfen 	}
28214235Smarkfen 	(void) close(sfd);
28224235Smarkfen 	if (msg->spd_msg_errno != 0) {
28234235Smarkfen 		errno = msg->spd_msg_errno;
28244235Smarkfen 		err(-1, gettext("admin failed"));
28254235Smarkfen 	}
28264235Smarkfen }
28274235Smarkfen 
28284235Smarkfen static void
reconfigure()28294235Smarkfen reconfigure()
28304235Smarkfen {
28314235Smarkfen 	(void) fprintf(stderr, gettext(
28325120Smarkfen 	    "\tipsecconf -f \n "
28335120Smarkfen 	    "\tipsecconf -a policy_file\n"));
28344235Smarkfen }
28354235Smarkfen 
28364235Smarkfen static void
usage(void)28374235Smarkfen usage(void)
28384235Smarkfen {
28394235Smarkfen 	(void) fprintf(stderr, gettext(
28404235Smarkfen 	"Usage:	ipsecconf\n"
28414235Smarkfen 	"\tipsecconf -a ([-]|<filename>) [-q]\n"
28424235Smarkfen 	"\tipsecconf -c <filename>\n"
28434235Smarkfen 	"\tipsecconf -r ([-]|<filename>) [-q]\n"
28444235Smarkfen 	"\tipsecconf -d [-i tunnel-interface] <index>\n"
28454235Smarkfen 	"\tipsecconf -d <tunnel-interface,index>\n"
28464235Smarkfen 	"\tipsecconf -l [-n] [-i tunnel-interface]\n"
28474235Smarkfen 	"\tipsecconf -f [-i tunnel-interface]\n"
28484235Smarkfen 	"\tipsecconf -L [-n]\n"
28494235Smarkfen 	"\tipsecconf -F\n"));
28504235Smarkfen }
28514235Smarkfen 
28524235Smarkfen /*
28534235Smarkfen  * a type consists of
28544235Smarkfen  * "type" <int>{ "-" <int>}
28554235Smarkfen  * or
28564235Smarkfen  * "type" keyword
28574235Smarkfen  *
28584235Smarkfen  * a code consists of
28594235Smarkfen  * "code" <int>{ "-" <int>}
28604235Smarkfen  * or
28614235Smarkfen  * "code" keyword
28624235Smarkfen  */
28634235Smarkfen 
28644235Smarkfen 
28654235Smarkfen static int
parse_type_code(const char * str,const str_val_t * table)28664235Smarkfen parse_type_code(const char *str, const str_val_t *table)
28674235Smarkfen {
28684235Smarkfen 	char *end1, *end2;
28694235Smarkfen 	int res1 = 0, res2 = 0;
28704235Smarkfen 	int i;
28714235Smarkfen 
28724235Smarkfen 	if (isdigit(str[0])) {
28734235Smarkfen 		res1 = strtol(str, &end1, 0);
28744235Smarkfen 
28754235Smarkfen 		if (end1 == str) {
28764235Smarkfen 			return (-1);
28774235Smarkfen 		}
28784235Smarkfen 
28794235Smarkfen 		if (res1 > 255 || res1 < 0) {
28804235Smarkfen 			return (-1);
28814235Smarkfen 		}
28824235Smarkfen 
28834235Smarkfen 		if (*end1 == '-') {
28844235Smarkfen 			end1++;
28854235Smarkfen 			res2 = strtol(end1, &end2, 0);
28864235Smarkfen 			if (res2 > 255 || res2 < 0) {
28874235Smarkfen 				return (-1);
28884235Smarkfen 			}
28894235Smarkfen 		} else {
28904235Smarkfen 			end2 = end1;
28914235Smarkfen 		}
28924235Smarkfen 
28934235Smarkfen 		while (isspace(*end2))
28944235Smarkfen 			end2++;
28954235Smarkfen 
28964235Smarkfen 		if (*end2 != '\0') {
28974235Smarkfen 			return (-1);
28984235Smarkfen 		}
28994235Smarkfen 
29004235Smarkfen 		return (res1 + (res2 << 8));
29014235Smarkfen 	}
29024235Smarkfen 
29034235Smarkfen 	for (i = 0; table[i].string; i++) {
29044235Smarkfen 		if (strcmp(str, table[i].string) == 0) {
29054235Smarkfen 			return (table[i].value);
29064235Smarkfen 		}
29074235Smarkfen 	}
29084235Smarkfen 
29094235Smarkfen 	return (-1);
29104235Smarkfen }
29114235Smarkfen 
29124235Smarkfen static int
parse_int(const char * str)29134235Smarkfen parse_int(const char *str)
29144235Smarkfen {
29154235Smarkfen 	char *end;
29164235Smarkfen 	int res;
29174235Smarkfen 
29184235Smarkfen 	res = strtol(str, &end, 0);
29194235Smarkfen 	if (end == str)
29204235Smarkfen 		return (-1);
29214235Smarkfen 	while (isspace(*end))
29224235Smarkfen 		end++;
29234235Smarkfen 	if (*end != '\0')
29244235Smarkfen 		return (-1);
29254235Smarkfen 	return (res);
29264235Smarkfen }
29274235Smarkfen 
29284235Smarkfen /*
29294235Smarkfen  * Parses <interface>,<index>.  Sets iname or the global interface_name (if
29304235Smarkfen  * iname == NULL) to <interface> and returns <index>.  Calls exit() if we have
29314235Smarkfen  * an interface_name already set.
29324235Smarkfen  */
29334235Smarkfen static int
parse_index(const char * str,char * iname)29344235Smarkfen parse_index(const char *str, char *iname)
29354235Smarkfen {
29364235Smarkfen 	char *intf, *num, *copy;
29374235Smarkfen 	int rc;
29384235Smarkfen 
29394235Smarkfen 	copy = strdup(str);
29404235Smarkfen 	if (copy == NULL) {
29414235Smarkfen 		EXIT_FATAL("Out of memory.");
29424235Smarkfen 	}
29434235Smarkfen 
29444235Smarkfen 	intf = strtok(copy, ",");
29454235Smarkfen 	/* Just want the rest of the string unmolested, so use "" for arg2. */
29464235Smarkfen 	num = strtok(NULL, "");
29474235Smarkfen 	if (num == NULL) {
29484235Smarkfen 		/* No comma found, just parse it like an int. */
29494235Smarkfen 		free(copy);
29504235Smarkfen 		return (parse_int(str));
29514235Smarkfen 	}
29524235Smarkfen 
29534235Smarkfen 	if (iname != NULL) {
29544235Smarkfen 		(void) strlcpy(iname, intf, LIFNAMSIZ);
29554235Smarkfen 	} else {
29564235Smarkfen 		if (interface_name != NULL) {
29574235Smarkfen 			EXIT_FATAL("Interface name already selected");
29584235Smarkfen 		}
29594235Smarkfen 
29604235Smarkfen 		interface_name = strdup(intf);
29614235Smarkfen 		if (interface_name == NULL) {
29624235Smarkfen 			EXIT_FATAL("Out of memory.");
29634235Smarkfen 		}
29644235Smarkfen 	}
29654235Smarkfen 
29664235Smarkfen 	rc = parse_int(num);
29674235Smarkfen 	free(copy);
29684235Smarkfen 	return (rc);
29694235Smarkfen }
29704235Smarkfen 
29714235Smarkfen /*
29724235Smarkfen  * Convert a mask to a prefix length.
29734235Smarkfen  * Returns prefix length on success, -1 otherwise.
29744235Smarkfen  */
29754235Smarkfen static int
in_getprefixlen(char * mask)29764235Smarkfen in_getprefixlen(char *mask)
29774235Smarkfen {
29784235Smarkfen 	int prefixlen;
29794235Smarkfen 	char *end;
29804235Smarkfen 
29814235Smarkfen 	prefixlen = (int)strtol(mask, &end, 10);
29824235Smarkfen 	if (prefixlen < 0) {
29834235Smarkfen 		return (-1);
29844235Smarkfen 	}
29854235Smarkfen 	if (mask == end) {
29864235Smarkfen 		return (-1);
29874235Smarkfen 	}
29884235Smarkfen 	if (*end != '\0') {
29894235Smarkfen 		return (-1);
29904235Smarkfen 	}
29914235Smarkfen 	return (prefixlen);
29924235Smarkfen }
29934235Smarkfen 
29944235Smarkfen /*
29954235Smarkfen  * Convert a prefix length to a mask.
29964235Smarkfen  * Assumes the mask array is zero'ed by the caller.
29974235Smarkfen  */
29984235Smarkfen static void
in_prefixlentomask(unsigned int prefixlen,uchar_t * mask)29994235Smarkfen in_prefixlentomask(unsigned int prefixlen, uchar_t *mask)
30004235Smarkfen {
30014235Smarkfen 	while (prefixlen > 0) {
30024235Smarkfen 		if (prefixlen >= 8) {
30034235Smarkfen 			*mask++ = 0xFF;
30044235Smarkfen 			prefixlen -= 8;
30054235Smarkfen 			continue;
30064235Smarkfen 		}
30074235Smarkfen 		*mask |= 1 << (8 - prefixlen);
30084235Smarkfen 		prefixlen--;
30094235Smarkfen 	}
30104235Smarkfen }
30114235Smarkfen 
30124235Smarkfen 
30134235Smarkfen static int
parse_address(int type,char * addr_str)30144235Smarkfen parse_address(int type, char *addr_str)
30154235Smarkfen {
30164235Smarkfen 	char *ptr;
30174235Smarkfen 	int prefix_len = 0;
30184235Smarkfen 	struct netent *ne = NULL;
30194235Smarkfen 	struct hostent *hp = NULL;
30204235Smarkfen 	int h_errno;
30214235Smarkfen 	struct in_addr netaddr;
30224235Smarkfen 	struct in6_addr *netaddr6;
30234235Smarkfen 	struct hostent *ne_hent;
30244235Smarkfen 	boolean_t	has_mask = B_FALSE;
30254235Smarkfen 
30264235Smarkfen 	ptr = strchr(addr_str, '/');
30274235Smarkfen 	if (ptr != NULL) {
30284235Smarkfen 		has_mask = B_TRUE;
30294235Smarkfen 		*ptr++ = NULL;
30304235Smarkfen 
30314235Smarkfen 		prefix_len = in_getprefixlen(ptr);
303212131Sdanmcd@opensolaris.org 		if (prefix_len < 0) {
303312131Sdanmcd@opensolaris.org 			warnx(gettext("Unparseable prefix: '%s'."), ptr);
30344235Smarkfen 			return (-1);
303512131Sdanmcd@opensolaris.org 		}
30364235Smarkfen 	}
30374235Smarkfen 
30384235Smarkfen 	/*
30394235Smarkfen 	 * getipnodebyname() is thread safe. This allows us to hold on to the
30404235Smarkfen 	 * returned hostent structure, which is pointed to by the shp and
30414235Smarkfen 	 * dhp globals for the source and destination addresses, respectively.
30424235Smarkfen 	 */
30434235Smarkfen 	hp = getipnodebyname(addr_str, AF_INET6, AI_DEFAULT | AI_ALL, &h_errno);
30444235Smarkfen 	if (hp != NULL) {
30454235Smarkfen 		/*
30464235Smarkfen 		 * We come here for both a hostname and
30474235Smarkfen 		 * any host address /network address.
30484235Smarkfen 		 */
30494235Smarkfen 		assert(hp->h_addrtype == AF_INET6);
30504235Smarkfen 	} else if ((ne = getnetbyname(addr_str)) != NULL) {
30514235Smarkfen 		switch (ne->n_addrtype) {
30524235Smarkfen 		case AF_INET:
30534235Smarkfen 			/*
30544235Smarkfen 			 * Allocate a struct hostent and initialize
30554235Smarkfen 			 * it with the address corresponding to the
30564235Smarkfen 			 * network number previously returned by
30574235Smarkfen 			 * getnetbyname(). Freed by do_address_adds()
30584235Smarkfen 			 * once the policy is defined.
30594235Smarkfen 			 */
30604235Smarkfen 			ne_hent = malloc(sizeof (struct hostent));
30614235Smarkfen 			if (ne_hent == NULL) {
30624235Smarkfen 				warn("malloc");
30634235Smarkfen 				return (-1);
30644235Smarkfen 			}
30654235Smarkfen 			ne_hent->h_addr_list = malloc(2*sizeof (char *));
30664235Smarkfen 			if (ne_hent->h_addr_list == NULL) {
30674235Smarkfen 				warn("malloc");
30684235Smarkfen 				free(ne_hent);
30694235Smarkfen 				return (-1);
30704235Smarkfen 			}
30714235Smarkfen 			netaddr6 = malloc(sizeof (struct in6_addr));
30724235Smarkfen 			if (netaddr6 == NULL) {
30734235Smarkfen 				warn("malloc");
30744235Smarkfen 				free(ne_hent->h_addr_list);
30754235Smarkfen 				free(ne_hent);
30764235Smarkfen 				return (-1);
30774235Smarkfen 			}
30784235Smarkfen 			ne_hent->h_addr_list[0] = (char *)netaddr6;
30794235Smarkfen 			ne_hent->h_addr_list[1] = NULL;
30804235Smarkfen 			netaddr = inet_makeaddr(ne->n_net, INADDR_ANY);
30814235Smarkfen 			IN6_INADDR_TO_V4MAPPED(&netaddr, netaddr6);
30824235Smarkfen 			hp = ne_hent;
30834235Smarkfen 			break;
30844235Smarkfen 		default:
308512131Sdanmcd@opensolaris.org 			warnx(gettext("Address type %d not supported."),
308612131Sdanmcd@opensolaris.org 			    ne->n_addrtype);
30874235Smarkfen 			return (-1);
30884235Smarkfen 		}
30894235Smarkfen 	} else {
309012131Sdanmcd@opensolaris.org 		warnx(gettext("Could not resolve address %s."), addr_str);
30914235Smarkfen 		return (-1);
30924235Smarkfen 	}
30934235Smarkfen 
30944235Smarkfen 	if (type == IPSEC_CONF_SRC_ADDRESS) {
30954235Smarkfen 		shp = hp;
30964235Smarkfen 		if (has_mask)
30974235Smarkfen 			splen = prefix_len;
30984235Smarkfen 		has_saprefix = has_mask;
30994235Smarkfen 	} else {
31004235Smarkfen 		dhp = hp;
31014235Smarkfen 		if (has_mask)
31024235Smarkfen 			dplen = prefix_len;
31034235Smarkfen 		has_daprefix = has_mask;
31044235Smarkfen 	}
31054235Smarkfen 
31064235Smarkfen 	return (0);
31074235Smarkfen }
31084235Smarkfen 
31094235Smarkfen /*
31104235Smarkfen  * Add port-only entries.  Make sure to add them in both the V6 and V4 tables!
31114235Smarkfen  */
31124235Smarkfen static int
do_port_adds(ips_conf_t * cptr)31134235Smarkfen do_port_adds(ips_conf_t *cptr)
31144235Smarkfen {
31154235Smarkfen 	int ret, diag;
31164235Smarkfen 
31174235Smarkfen 	assert(IN6_IS_ADDR_UNSPECIFIED(&cptr->ips_src_addr_v6));
31184235Smarkfen 	assert(IN6_IS_ADDR_UNSPECIFIED(&cptr->ips_dst_addr_v6));
31194235Smarkfen 
31204235Smarkfen #ifdef DEBUG_HEAVY
31214235Smarkfen 	(void) dump_conf(cptr);
31224235Smarkfen #endif
31234235Smarkfen 
31244235Smarkfen 	ret = send_pf_pol_message(SPD_ADDRULE, cptr, &diag);
31254235Smarkfen 	if (ret != 0 && !ipsecconf_qflag) {
31264235Smarkfen 		warnx(
31274235Smarkfen 		    gettext("Could not add IPv4 policy for sport %d, dport %d "
31285120Smarkfen 		    "- diagnostic %d - %s"), ntohs(cptr->ips_src_port_min),
31294235Smarkfen 		    ntohs(cptr->ips_dst_port_min), diag, spdsock_diag(diag));
31304235Smarkfen 	}
31314235Smarkfen 
31324235Smarkfen 	return (ret);
31334235Smarkfen }
31344235Smarkfen 
31354235Smarkfen /*
31364235Smarkfen  * Nuke a list of policy entries.
31374235Smarkfen  * rewrite this to use flipping
31384235Smarkfen  * d_list isn't freed because we will be
31394235Smarkfen  * exiting the program soon.
31404235Smarkfen  */
31414235Smarkfen static void
nuke_adds()31424235Smarkfen nuke_adds()
31434235Smarkfen {
31444235Smarkfen 	d_list_t *temp = d_list;
31454235Smarkfen 	FILE *policy_fp;
31464235Smarkfen 
31474235Smarkfen 	policy_fp = fopen(POLICY_CONF_FILE, "a");
31484235Smarkfen 	if (policy_fp == NULL) {
31494235Smarkfen 		warn(gettext("%s cannot be opened"), POLICY_CONF_FILE);
31505494Spwernau 	} else {
31515494Spwernau 		(void) fprintf(policy_fp, "\n\n");
31525494Spwernau 		(void) fflush(policy_fp);
31534235Smarkfen 	}
31544235Smarkfen 
31554235Smarkfen 	while (temp != NULL) {
31564235Smarkfen 		(void) ipsec_conf_del(temp->index, B_TRUE);
31574235Smarkfen 		temp = temp->next;
31584235Smarkfen 	}
31594235Smarkfen }
31604235Smarkfen 
31614235Smarkfen /*
31624235Smarkfen  * Set mask info from the specified prefix len. Fail if multihomed.
31634235Smarkfen  */
31644235Smarkfen static int
set_mask_info(struct hostent * hp,unsigned int plen,struct in6_addr * mask_v6)31654235Smarkfen set_mask_info(struct hostent *hp, unsigned int plen, struct in6_addr *mask_v6)
31664235Smarkfen {
31674235Smarkfen 	struct in6_addr addr;
31684235Smarkfen 	struct in_addr mask_v4;
31694235Smarkfen 
31704235Smarkfen 	if (hp->h_addr_list[1] != NULL) {
31714235Smarkfen 		return (EOPNOTSUPP);
31724235Smarkfen 	}
31734235Smarkfen 
31744235Smarkfen 	if (!IN6_IS_ADDR_UNSPECIFIED(mask_v6)) {
31754235Smarkfen 		return (EBUSY);
31764235Smarkfen 	}
31774235Smarkfen 
31784235Smarkfen 	bcopy(hp->h_addr_list[0], &addr, sizeof (struct in6_addr));
31794235Smarkfen 	if (IN6_IS_ADDR_V4MAPPED(&addr)) {
31804235Smarkfen 		if (plen > IP_ABITS) {
31814235Smarkfen 			return (ERANGE);
31824235Smarkfen 		}
31834235Smarkfen 		(void) memset(&mask_v4, 0, sizeof (mask_v4));
31844235Smarkfen 		in_prefixlentomask(plen, (uchar_t *)&mask_v4);
31854235Smarkfen 		IN6_INADDR_TO_V4MAPPED(&mask_v4, mask_v6);
31864235Smarkfen 	} else {
31874235Smarkfen 		if (plen > IPV6_ABITS) {
31884235Smarkfen 			return (ERANGE);
31894235Smarkfen 		}
31904235Smarkfen 		/* mask_v6 is already zero (unspecified), see test above */
31914235Smarkfen 		in_prefixlentomask(plen, (uchar_t *)mask_v6);
31924235Smarkfen 	}
31934235Smarkfen 	return (0);
31944235Smarkfen }
31954235Smarkfen 
31964235Smarkfen /*
31974235Smarkfen  * Initialize the specified IPv6 address with all f's.
31984235Smarkfen  */
31994235Smarkfen static void
init_addr_wildcard(struct in6_addr * addr_v6,boolean_t isv4)32004235Smarkfen init_addr_wildcard(struct in6_addr *addr_v6, boolean_t isv4)
32014235Smarkfen {
32024235Smarkfen 	if (isv4) {
32034235Smarkfen 		uint32_t addr_v4 = 0xffffffff;
32044235Smarkfen 		IN6_INADDR_TO_V4MAPPED((struct in_addr *)&addr_v4, addr_v6);
32054235Smarkfen 	} else {
32064235Smarkfen 		(void) memset(addr_v6, 0xff, sizeof (struct in6_addr));
32074235Smarkfen 	}
32084235Smarkfen }
32094235Smarkfen 
32104235Smarkfen /*
32114235Smarkfen  * Called at the end to actually add policy.  Handles single and multi-homed
32124235Smarkfen  * cases.
32134235Smarkfen  */
32144235Smarkfen static int
do_address_adds(ips_conf_t * cptr,int * diag)32154235Smarkfen do_address_adds(ips_conf_t *cptr, int *diag)
32164235Smarkfen {
32174235Smarkfen 	int i, j;
32184235Smarkfen 	int ret = 0;	/* For ioctl() call. */
32194235Smarkfen 	int rc = 0;	/* My own return code. */
32204235Smarkfen 	struct in6_addr zeroes = {0, 0, 0, 0};
32214235Smarkfen 	char *ptr[2];
32224235Smarkfen 	struct hostent hent;
32234235Smarkfen 	boolean_t isv4;
32244235Smarkfen 	int add_count = 0;
32254235Smarkfen 
32264235Smarkfen 	/*
32274235Smarkfen 	 * dst_hent may not be initialized if a destination
32284235Smarkfen 	 * address was not given. It will be initalized with just
32294235Smarkfen 	 * one address if a destination address was given. In both
32304235Smarkfen 	 * the cases, we initialize here with ipsc_dst_addr and enter
32314235Smarkfen 	 * the loop below.
32324235Smarkfen 	 */
32334235Smarkfen 	if (dhp == NULL) {
32344235Smarkfen 		assert(shp != NULL);
32354235Smarkfen 		hent.h_addr_list = ptr;
32364235Smarkfen 		ptr[0] = (char *)&zeroes.s6_addr;
32374235Smarkfen 		ptr[1] = NULL;
32384235Smarkfen 		dhp = &hent;
32394235Smarkfen 	} else if (shp == NULL) {
32404235Smarkfen 		assert(dhp != NULL);
32414235Smarkfen 		hent.h_addr_list = ptr;
32424235Smarkfen 		ptr[0] = (char *)&zeroes.s6_addr;
32434235Smarkfen 		ptr[1] = NULL;
32444235Smarkfen 		shp = &hent;
32454235Smarkfen 	}
32464235Smarkfen 
32474235Smarkfen 	/*
32484235Smarkfen 	 * Set mask info here.  Bail if multihomed and there's a prefix len.
32494235Smarkfen 	 */
32504235Smarkfen 	if (has_saprefix) {
32514235Smarkfen 		rc = set_mask_info(shp, splen, &cptr->ips_src_mask_v6);
32524235Smarkfen 		if (rc != 0)
32534235Smarkfen 			goto bail;
32544235Smarkfen 		cptr->ips_src_mask_len = splen;
32554235Smarkfen 	}
32564235Smarkfen 
32574235Smarkfen 	if (has_daprefix) {
32584235Smarkfen 		rc = set_mask_info(dhp, dplen, &cptr->ips_dst_mask_v6);
32594235Smarkfen 		if (rc != 0)
32604235Smarkfen 			goto bail;
32614235Smarkfen 		cptr->ips_dst_mask_len = dplen;
32624235Smarkfen 	}
32634235Smarkfen 
32644235Smarkfen 	for (i = 0; shp->h_addr_list[i] != NULL; i++) {
32654235Smarkfen 		bcopy(shp->h_addr_list[i], &cptr->ips_src_addr_v6,
32664235Smarkfen 		    sizeof (struct in6_addr));
32674235Smarkfen 		isv4 = cptr->ips_isv4 =
32684235Smarkfen 		    IN6_IS_ADDR_V4MAPPED(&cptr->ips_src_addr_v6);
32694235Smarkfen 		if (IN6_IS_ADDR_UNSPECIFIED(&cptr->ips_src_mask_v6) &&
32704235Smarkfen 		    shp != &hent) {
32714235Smarkfen 			init_addr_wildcard(&cptr->ips_src_mask_v6, isv4);
32724235Smarkfen 		}
32734235Smarkfen 
32744235Smarkfen 		for (j = 0; dhp->h_addr_list[j] != NULL; j++) {
32754235Smarkfen 			bcopy(dhp->h_addr_list[j], &cptr->ips_dst_addr_v6,
32764235Smarkfen 			    sizeof (struct in6_addr));
32774235Smarkfen 			if (IN6_IS_ADDR_UNSPECIFIED(&cptr->ips_src_addr_v6)) {
32784235Smarkfen 				/*
32794235Smarkfen 				 * Src was not specified, so update isv4 flag
32804235Smarkfen 				 * for this policy according to the family
32814235Smarkfen 				 * of the destination address.
32824235Smarkfen 				 */
32834235Smarkfen 				isv4 = cptr->ips_isv4 =
32844235Smarkfen 				    IN6_IS_ADDR_V4MAPPED(
32855120Smarkfen 				    &cptr->ips_dst_addr_v6);
32864235Smarkfen 			} else if ((dhp != &hent) && (isv4 !=
32874235Smarkfen 			    IN6_IS_ADDR_V4MAPPED(&cptr->ips_dst_addr_v6))) {
32884235Smarkfen 				/* v6/v4 mismatch. */
32894235Smarkfen 				continue;
32904235Smarkfen 			}
32914235Smarkfen 			if (IN6_IS_ADDR_UNSPECIFIED(&cptr->ips_dst_mask_v6) &&
32924235Smarkfen 			    dhp != &hent) {
32934235Smarkfen 				init_addr_wildcard(&cptr->ips_dst_mask_v6,
32944235Smarkfen 				    isv4);
32954235Smarkfen 			}
32964235Smarkfen 
32974235Smarkfen 			ret = send_pf_pol_message(SPD_ADDRULE, cptr, diag);
32984235Smarkfen 
32994235Smarkfen 			if (ret == 0) {
33004235Smarkfen 				add_count++;
33014235Smarkfen 			} else {
33024235Smarkfen 				/* For now, allow duplicate/overlap policies. */
33034235Smarkfen 				if (ret != EEXIST) {
33044235Smarkfen 					/*
33054235Smarkfen 					 * We have an error where we added
33064235Smarkfen 					 * some, but had errors with others.
33074235Smarkfen 					 * Undo the previous adds, and
33084235Smarkfen 					 * bail.
33094235Smarkfen 					 */
33104235Smarkfen 					rc = ret;
33114235Smarkfen 					goto bail;
33124235Smarkfen 				}
33134235Smarkfen 			}
33144235Smarkfen 
33154235Smarkfen 			bzero(&cptr->ips_dst_mask_v6,
33164235Smarkfen 			    sizeof (struct in6_addr));
33174235Smarkfen 		}
33184235Smarkfen 
33194235Smarkfen 		bzero(&cptr->ips_src_mask_v6, sizeof (struct in6_addr));
33204235Smarkfen 	}
33214235Smarkfen 
33224235Smarkfen bail:
33234235Smarkfen 	if (shp != &hent)
33244235Smarkfen 		freehostent(shp);
33254235Smarkfen 	shp = NULL;
33264235Smarkfen 	if (dhp != &hent)
33274235Smarkfen 		freehostent(dhp);
33284235Smarkfen 	dhp = NULL;
33294235Smarkfen 	splen = 0;
33304235Smarkfen 	dplen = 0;
33314235Smarkfen 
33324235Smarkfen 	if ((add_count == 0) && (rc == 0)) {
33334235Smarkfen 		/*
33344235Smarkfen 		 * No entries were added. We failed all adds
33354235Smarkfen 		 * because the entries already existed, or because
33364235Smarkfen 		 * no v4 or v6 src/dst pairs were found. Either way,
33374235Smarkfen 		 * we must fail here with an appropriate error
33384235Smarkfen 		 * to avoid a corresponding entry from being added
33394235Smarkfen 		 * to ipsecpolicy.conf.
33404235Smarkfen 		 */
33414235Smarkfen 		if ((ret == EEXIST)) {
33424235Smarkfen 			/* All adds failed with EEXIST */
33434235Smarkfen 			rc = EEXIST;
33444235Smarkfen 		} else {
33454235Smarkfen 			/* No matching v4 or v6 src/dst pairs */
33464235Smarkfen 			rc = ESRCH;
33474235Smarkfen 		}
33484235Smarkfen 	}
33494235Smarkfen 
33504235Smarkfen 	return (rc);
33514235Smarkfen }
33524235Smarkfen 
33534235Smarkfen static int
parse_mask(int type,char * mask_str,ips_conf_t * cptr)33544235Smarkfen parse_mask(int type, char *mask_str, ips_conf_t *cptr)
33554235Smarkfen {
33564235Smarkfen 	struct in_addr mask;
33574235Smarkfen 	struct in6_addr *mask6;
33584235Smarkfen 
33594235Smarkfen 	if (type == IPSEC_CONF_SRC_MASK) {
33604235Smarkfen 		mask6 = &cptr->ips_src_mask_v6;
33614235Smarkfen 	} else {
33624235Smarkfen 		mask6 = &cptr->ips_dst_mask_v6;
33634235Smarkfen 	}
33644235Smarkfen 
33654235Smarkfen 	if ((strncasecmp(mask_str, "0x", 2) == 0) &&
33664235Smarkfen 	    (strchr(mask_str, '.') == NULL)) {
33674235Smarkfen 		/* Is it in the form 0xff000000 ? */
33684235Smarkfen 		char *end;
33694235Smarkfen 
33704235Smarkfen 		mask.s_addr = strtoul(mask_str, &end, 0);
33714235Smarkfen 		if (end == mask_str) {
33724235Smarkfen 			return (-1);
33734235Smarkfen 		}
33744235Smarkfen 		if (*end != '\0') {
33754235Smarkfen 			return (-1);
33764235Smarkfen 		}
33774235Smarkfen 		mask.s_addr = htonl(mask.s_addr);
33784235Smarkfen 	} else {
33794235Smarkfen 		/*
33804235Smarkfen 		 * Since inet_addr() returns -1 on error, we have
33814235Smarkfen 		 * to convert a broadcast address ourselves.
33824235Smarkfen 		 */
33834235Smarkfen 		if (strcmp(mask_str, "255.255.255.255") == 0) {
33844235Smarkfen 			mask.s_addr = 0xffffffff;
33854235Smarkfen 		} else {
33864235Smarkfen 			mask.s_addr = inet_addr(mask_str);
33874235Smarkfen 			if (mask.s_addr == (unsigned int)-1)
33884235Smarkfen 				return (-1);
33894235Smarkfen 		}
33904235Smarkfen 	}
33914235Smarkfen 
33924235Smarkfen 	/* Should we check for non-contiguous masks ? */
33934235Smarkfen 	if (mask.s_addr == 0)
33944235Smarkfen 		return (-1);
33954235Smarkfen 	IN6_INADDR_TO_V4MAPPED(&mask, mask6);
33964235Smarkfen 
33974235Smarkfen 
33984235Smarkfen 	if (type == IPSEC_CONF_SRC_MASK) {
33994235Smarkfen 		cptr->ips_src_mask_len = in_masktoprefix(mask6->s6_addr,
34004235Smarkfen 		    B_TRUE);
34014235Smarkfen 	} else {
34024235Smarkfen 		cptr->ips_dst_mask_len = in_masktoprefix(mask6->s6_addr,
34034235Smarkfen 		    B_TRUE);
34044235Smarkfen 	}
34054235Smarkfen 
34064235Smarkfen 	return (0);
34074235Smarkfen }
34084235Smarkfen 
34094235Smarkfen static int
parse_port(int type,char * port_str,ips_conf_t * conf)34104235Smarkfen parse_port(int type, char *port_str, ips_conf_t *conf)
34114235Smarkfen {
34124235Smarkfen 	struct servent *sent;
34134235Smarkfen 	in_port_t port;
34144235Smarkfen 	int ret;
34154235Smarkfen 
34164235Smarkfen 	sent = getservbyname(port_str, NULL);
34174235Smarkfen 	if (sent == NULL) {
34184235Smarkfen 		ret = parse_int(port_str);
34194235Smarkfen 		if (ret < 0 || ret >= 65536) {
34204235Smarkfen 			return (-1);
34214235Smarkfen 		}
34224235Smarkfen 		port = htons((in_port_t)ret);
34234235Smarkfen 	} else {
34244235Smarkfen 		port = sent->s_port;
34254235Smarkfen 	}
34264235Smarkfen 	if (type == IPSEC_CONF_SRC_PORT) {
34274235Smarkfen 		conf->ips_src_port_min = conf->ips_src_port_max = port;
34284235Smarkfen 	} else {
34294235Smarkfen 		conf->ips_dst_port_min = conf->ips_dst_port_max = port;
34304235Smarkfen 	}
34314235Smarkfen 	return (0);
34324235Smarkfen }
34334235Smarkfen 
343410824SMark.Fenwick@Sun.COM static boolean_t
combined_mode(uint_t alg_id)343512131Sdanmcd@opensolaris.org combined_mode(uint_t alg_id)
343610824SMark.Fenwick@Sun.COM {
343710824SMark.Fenwick@Sun.COM 	struct ipsecalgent *alg;
343812131Sdanmcd@opensolaris.org 	boolean_t rc;
343912131Sdanmcd@opensolaris.org 
344012131Sdanmcd@opensolaris.org 	alg = getipsecalgbynum(alg_id, IPSEC_PROTO_ESP, NULL);
344112131Sdanmcd@opensolaris.org 	if (alg != NULL) {
344212131Sdanmcd@opensolaris.org 		rc = (ALG_FLAG_COMBINED & alg->a_alg_flags);
344310824SMark.Fenwick@Sun.COM 		freeipsecalgent(alg);
344412131Sdanmcd@opensolaris.org 	} else {
344512131Sdanmcd@opensolaris.org 		rc = B_FALSE;
344612131Sdanmcd@opensolaris.org 	}
344712131Sdanmcd@opensolaris.org 
344812131Sdanmcd@opensolaris.org 	return (rc);
344910824SMark.Fenwick@Sun.COM }
345010824SMark.Fenwick@Sun.COM 
34514235Smarkfen static int
valid_algorithm(int proto_num,const char * str)34524235Smarkfen valid_algorithm(int proto_num, const char *str)
34534235Smarkfen {
34544235Smarkfen 	const char *tmp;
34554235Smarkfen 	int ret;
34564235Smarkfen 	struct ipsecalgent *alg;
34574235Smarkfen 
34584235Smarkfen 	/* Short-circuit "none" */
34594235Smarkfen 	if (strncasecmp("none", str, 5) == 0)
34604235Smarkfen 		return (-2);
34614235Smarkfen 
34624235Smarkfen 	alg = getipsecalgbyname(str, proto_num, NULL);
34634235Smarkfen 	if (alg != NULL) {
34644235Smarkfen 		ret = alg->a_alg_num;
34654235Smarkfen 		freeipsecalgent(alg);
34664235Smarkfen 		return (ret);
34674235Smarkfen 	}
34684235Smarkfen 
34694235Smarkfen 	/*
34704235Smarkfen 	 * Look whether it could be a valid number.
34714235Smarkfen 	 * We support numbers also so that users can
34724235Smarkfen 	 * load algorithms as they need it. We can't
34734235Smarkfen 	 * check for validity of numbers here. It will
34744235Smarkfen 	 * be checked when the SA is negotiated/looked up.
34754235Smarkfen 	 * parse_int uses strtol(str), which converts 3DES
34764235Smarkfen 	 * to a valid number i.e looks only at initial
34774235Smarkfen 	 * number part. If we come here we should expect
34784235Smarkfen 	 * only a decimal number.
34794235Smarkfen 	 */
34804235Smarkfen 	tmp = str;
34814235Smarkfen 	while (*tmp) {
34824235Smarkfen 		if (!isdigit(*tmp))
34834235Smarkfen 			return (-1);
34844235Smarkfen 		tmp++;
34854235Smarkfen 	}
34864235Smarkfen 
34874235Smarkfen 	ret = parse_int(str);
34884235Smarkfen 	if (ret > 0 && ret <= 255)
34894235Smarkfen 		return (ret);
34904235Smarkfen 	else
34914235Smarkfen 		return (-1);
34924235Smarkfen }
34934235Smarkfen 
34944235Smarkfen static int
parse_ipsec_alg(char * str,ips_act_props_t * iap,int alg_type)34954235Smarkfen parse_ipsec_alg(char *str, ips_act_props_t *iap, int alg_type)
34964235Smarkfen {
34974235Smarkfen 	int alg_value;
349811136SMark.Fenwick@Sun.COM 	int remainder;
34994235Smarkfen 	char tstr[VALID_ALG_LEN];
35004235Smarkfen 	char *lens = NULL;
35014235Smarkfen 	char *l1_str;
35024235Smarkfen 	int l1 = 0;
35034235Smarkfen 	char *l2_str;
35044235Smarkfen 	int l2 = SPD_MAX_MAXBITS;
35054235Smarkfen 	algreq_t *ap;
35064235Smarkfen 	uint_t a_type;
35074235Smarkfen 
35084235Smarkfen 	fetch_algorithms();
35094235Smarkfen 
35104235Smarkfen 	/*
35114235Smarkfen 	 * Make sure that we get a null terminated string.
35124235Smarkfen 	 * For a bad input, we truncate at VALID_ALG_LEN.
35134235Smarkfen 	 */
351411136SMark.Fenwick@Sun.COM 	remainder = strlen(str);
35154235Smarkfen 	(void) strlcpy(tstr, str, VALID_ALG_LEN);
35164235Smarkfen 	lens = strtok(tstr, "()");
351711136SMark.Fenwick@Sun.COM 	remainder -= strlen(lens);
35184235Smarkfen 	lens = strtok(NULL, "()");
35194235Smarkfen 
35204235Smarkfen 	if (lens != NULL) {
35214235Smarkfen 		int len1 = 0;
35224235Smarkfen 		int len2 = SPD_MAX_MAXBITS;
35234235Smarkfen 		int len_all = strlen(lens);
35244235Smarkfen 		int dot_start = (lens[0] == '.');
352511136SMark.Fenwick@Sun.COM 
352611136SMark.Fenwick@Sun.COM 		/*
352711136SMark.Fenwick@Sun.COM 		 * Check to see if the keylength arg is at the end of the
352811136SMark.Fenwick@Sun.COM 		 * token, the "()" is 2 characters.
352911136SMark.Fenwick@Sun.COM 		 */
353011136SMark.Fenwick@Sun.COM 		remainder -= strlen(lens);
353111136SMark.Fenwick@Sun.COM 		if (remainder > 2)
353211136SMark.Fenwick@Sun.COM 			return (1);
353311136SMark.Fenwick@Sun.COM 
35344235Smarkfen 		l1_str = strtok(lens, ".");
35354235Smarkfen 		l2_str = strtok(NULL, ".");
35364235Smarkfen 		if (l1_str != NULL) {
35374235Smarkfen 			l1 = parse_int(l1_str);
35384235Smarkfen 			len1 = strlen(l1_str);
35394235Smarkfen 			if (len1 < 0)
35404235Smarkfen 				return (1);
35414235Smarkfen 		}
35424235Smarkfen 		if (l2_str != NULL) {
35434235Smarkfen 			l2 = parse_int(l2_str);
35444235Smarkfen 			len2 = strlen(l2_str);
35454235Smarkfen 			if (len2 < 0)
35464235Smarkfen 				return (1);
35474235Smarkfen 		}
35484235Smarkfen 
35494235Smarkfen 		if (len_all == len1) {
35504235Smarkfen 			/* alg(n) */
35514235Smarkfen 			l2 = l1;
35524235Smarkfen 		} else if (dot_start) {
35534235Smarkfen 			/* alg(..n) */
35544235Smarkfen 			l2 = l1;
35554235Smarkfen 			l1 = 0;
35564235Smarkfen 		} else if ((len_all - 2) == len1) {
35574235Smarkfen 			/* alg(n..) */
35584235Smarkfen 			l2 = SPD_MAX_MAXBITS;
35594235Smarkfen 		} /* else alg(n..m) */
35604235Smarkfen 	}
35614235Smarkfen 
35624235Smarkfen 	if (alg_type == SPD_ATTR_AH_AUTH ||
35634235Smarkfen 	    alg_type == SPD_ATTR_ESP_AUTH) {
35644235Smarkfen 		alg_value = valid_algorithm(IPSEC_PROTO_AH, tstr);
35654235Smarkfen 	} else {
35664235Smarkfen 		alg_value = valid_algorithm(IPSEC_PROTO_ESP, tstr);
35674235Smarkfen 	}
35684235Smarkfen 	if (alg_value < 0) {
35694235Smarkfen 		/* Invalid algorithm or "none" */
35704235Smarkfen 		return (alg_value);
35714235Smarkfen 	}
35724235Smarkfen 
35734235Smarkfen 	if (alg_type == SPD_ATTR_AH_AUTH) {
35744235Smarkfen 		a_type = AH_AUTH;
35754235Smarkfen 		iap->iap_attr |= SPD_APPLY_AH;
35764235Smarkfen 		ap = &(iap->iap_aauth);
35774235Smarkfen 	} else if (alg_type == SPD_ATTR_ESP_AUTH) {
35784235Smarkfen 		a_type = ESP_AUTH;
35794235Smarkfen 		iap->iap_attr |= SPD_APPLY_ESP|SPD_APPLY_ESPA;
35804235Smarkfen 		ap = &(iap->iap_eauth);
35814235Smarkfen 	} else {
35824235Smarkfen 		a_type = ESP_ENCR;
35834235Smarkfen 		iap->iap_attr |= SPD_APPLY_ESP;
35844235Smarkfen 		ap = &(iap->iap_eencr);
35854235Smarkfen 	}
35864235Smarkfen 
35874235Smarkfen 	ap->alg_id = alg_value;
35884235Smarkfen 	ap->alg_minbits = l1;
35894235Smarkfen 	ap->alg_maxbits = l2;
35904235Smarkfen 
35914235Smarkfen 	if (!alg_rangecheck(a_type, alg_value, ap))
35924235Smarkfen 		return (1);
35934235Smarkfen 
35944235Smarkfen 	return (0);
35954235Smarkfen }
35964235Smarkfen 
35974235Smarkfen static char *
sys_error_message(int syserr)35984235Smarkfen sys_error_message(int syserr)
35994235Smarkfen {
36004235Smarkfen 	char *mesg;
36014235Smarkfen 
36024235Smarkfen 	switch (syserr) {
36034235Smarkfen 	case EEXIST:
36044235Smarkfen 		mesg = gettext("Entry already exists");
36054235Smarkfen 		break;
36064235Smarkfen 	case ENOENT:
36074235Smarkfen 		mesg = gettext("Tunnel not found");
36084235Smarkfen 		break;
36094235Smarkfen 	case EINVAL:
36104235Smarkfen 		mesg = gettext("Invalid entry");
36114235Smarkfen 		break;
36124235Smarkfen 	default :
36134235Smarkfen 		mesg = strerror(syserr);
36144235Smarkfen 	}
36154235Smarkfen 	return (mesg);
36164235Smarkfen }
36174235Smarkfen 
36184235Smarkfen static void
error_message(error_type_t error,int type,int line)36194235Smarkfen error_message(error_type_t error, int type, int line)
36204235Smarkfen {
36214235Smarkfen 	char *mesg;
36224235Smarkfen 
36234235Smarkfen 	switch (type) {
36244235Smarkfen 	case IPSEC_CONF_SRC_ADDRESS:
36254235Smarkfen 		mesg = gettext("Source Address");
36264235Smarkfen 		break;
36274235Smarkfen 	case IPSEC_CONF_DST_ADDRESS:
36284235Smarkfen 		mesg = gettext("Destination Address");
36294235Smarkfen 		break;
36304235Smarkfen 	case IPSEC_CONF_SRC_PORT:
36314235Smarkfen 		mesg = gettext("Source Port");
36324235Smarkfen 		break;
36334235Smarkfen 	case IPSEC_CONF_DST_PORT:
36344235Smarkfen 		mesg = gettext("Destination Port");
36354235Smarkfen 		break;
36364235Smarkfen 	case IPSEC_CONF_SRC_MASK:
36374235Smarkfen 		mesg = gettext("Source Mask");
36384235Smarkfen 		break;
36394235Smarkfen 	case IPSEC_CONF_DST_MASK:
36404235Smarkfen 		mesg = gettext("Destination Mask");
36414235Smarkfen 		break;
36424235Smarkfen 	case IPSEC_CONF_ULP:
36434235Smarkfen 		mesg = gettext("Upper Layer Protocol");
36444235Smarkfen 		break;
36454235Smarkfen 	case IPSEC_CONF_IPSEC_AALGS:
36464235Smarkfen 		mesg = gettext("Authentication Algorithm");
36474235Smarkfen 		break;
36484235Smarkfen 	case IPSEC_CONF_IPSEC_EALGS:
36494235Smarkfen 		mesg = gettext("Encryption Algorithm");
36504235Smarkfen 		break;
36514235Smarkfen 	case IPSEC_CONF_IPSEC_EAALGS:
36524235Smarkfen 		mesg = gettext("ESP Authentication Algorithm");
36534235Smarkfen 		break;
36544235Smarkfen 	case IPSEC_CONF_IPSEC_SA:
36554235Smarkfen 		mesg = gettext("SA");
36564235Smarkfen 		break;
36574235Smarkfen 	case IPSEC_CONF_IPSEC_DIR:
36584235Smarkfen 		mesg = gettext("Direction");
36594235Smarkfen 		break;
36604235Smarkfen 	case IPSEC_CONF_ICMP_TYPE:
36614235Smarkfen 		mesg = gettext("ICMP type");
36624235Smarkfen 		break;
36634235Smarkfen 	case IPSEC_CONF_ICMP_CODE:
36644235Smarkfen 		mesg = gettext("ICMP code");
36654235Smarkfen 		break;
36664235Smarkfen 	case IPSEC_CONF_NEGOTIATE:
36674235Smarkfen 		mesg = gettext("Negotiate");
36684235Smarkfen 		break;
36694235Smarkfen 	case IPSEC_CONF_TUNNEL:
36704235Smarkfen 		mesg = gettext("Tunnel");
36714235Smarkfen 		break;
36724235Smarkfen 	default :
36734235Smarkfen 		return;
36744235Smarkfen 	}
36754235Smarkfen 	/*
36764235Smarkfen 	 * If we never read a newline character, we don't want
36774235Smarkfen 	 * to print 0.
36784235Smarkfen 	 */
36794235Smarkfen 	warnx(gettext("%s%s%s %s on line: %d"),
36804235Smarkfen 	    (error == BAD_ERROR) ? gettext("Bad") : "",
36814235Smarkfen 	    (error == DUP_ERROR) ? gettext("Duplicate") : "",
36824235Smarkfen 	    (error == REQ_ERROR) ? gettext("Requires") : "",
36834235Smarkfen 	    mesg,
36844235Smarkfen 	    (arg_indices[line] == 0) ? 1 : arg_indices[line]);
36854235Smarkfen }
36864235Smarkfen 
36874235Smarkfen static int
validate_properties(ips_act_props_t * cptr,boolean_t dir,boolean_t is_alg)36884235Smarkfen validate_properties(ips_act_props_t *cptr, boolean_t dir, boolean_t is_alg)
36894235Smarkfen {
36904235Smarkfen 	if (cptr->iap_action == SPD_ACTTYPE_PASS ||
36915120Smarkfen 	    cptr->iap_action == SPD_ACTTYPE_DROP) {
36924235Smarkfen 		if (!dir) {
36934235Smarkfen 			warnx(gettext("dir string "
36944235Smarkfen 			    "not found for bypass policy"));
36954235Smarkfen 		}
36964235Smarkfen 
36974235Smarkfen 		if (is_alg) {
36984235Smarkfen 			warnx(gettext("Algorithms found for bypass policy"));
36994235Smarkfen 			return (-1);
37004235Smarkfen 		}
37014235Smarkfen 		return (0);
37024235Smarkfen 	}
37034235Smarkfen 	if (!is_alg) {
37044235Smarkfen 		warnx(gettext("No IPsec algorithms given"));
37054235Smarkfen 		return (-1);
37064235Smarkfen 	}
37074235Smarkfen 	if (cptr->iap_attr == 0) {
37084235Smarkfen 		warnx(gettext("No SA attribute"));
37094235Smarkfen 		return (-1);
37104235Smarkfen 	}
37114235Smarkfen 	return (0);
37124235Smarkfen }
37134235Smarkfen 
37144235Smarkfen /*
37154235Smarkfen  * This function is called only to parse a single rule's worth of
37164235Smarkfen  * action strings.  This is called after parsing pattern and before
37174235Smarkfen  * parsing properties.  Thus we may have something in the leftover
37184235Smarkfen  * buffer while parsing the pattern, which we need to handle here.
37194235Smarkfen  */
37204235Smarkfen static int
parse_action(FILE * fp,char ** action,char ** leftover)37214235Smarkfen parse_action(FILE *fp, char **action, char **leftover)
37224235Smarkfen {
37234235Smarkfen 	char *cp;
37244235Smarkfen 	char ibuf[MAXLEN];
37254235Smarkfen 	char *tmp_buf;
37264235Smarkfen 	char *buf;
37274235Smarkfen 	boolean_t new_stuff;
37284235Smarkfen 
37294235Smarkfen 	if (*leftover != NULL) {
37304235Smarkfen 		buf = *leftover;
37314235Smarkfen 		new_stuff = B_FALSE;
37324235Smarkfen 		goto scan;
37334235Smarkfen 	}
37344235Smarkfen 	while (fgets(ibuf, MAXLEN, fp) != NULL) {
37354235Smarkfen 		new_stuff = B_TRUE;
37364235Smarkfen 		if (ibuf[strlen(ibuf) - 1] == '\n')
37374235Smarkfen 			linecount++;
37384235Smarkfen 		buf = ibuf;
37394235Smarkfen scan:
37404235Smarkfen 		/* Truncate at the beginning of a comment */
37414235Smarkfen 		cp = strchr(buf, '#');
37424235Smarkfen 		if (cp != NULL)
37434235Smarkfen 			*cp = NULL;
37444235Smarkfen 
37454235Smarkfen 		/* Skip any whitespace */
37464235Smarkfen 		while (*buf != NULL && isspace(*buf))
37474235Smarkfen 			buf++;
37484235Smarkfen 
37494235Smarkfen 		/* Empty line */
37504235Smarkfen 		if (*buf == NULL)
37514235Smarkfen 			continue;
37524235Smarkfen 
37534235Smarkfen 		/*
37544235Smarkfen 		 * Store the command for error reporting
37554235Smarkfen 		 * and ipsec_conf_add().
37564235Smarkfen 		 */
37574235Smarkfen 		if (new_stuff) {
37584235Smarkfen 			/*
37594235Smarkfen 			 * Check for buffer overflow including the null
37604235Smarkfen 			 * terminating character.
37614235Smarkfen 			 */
37624235Smarkfen 			int len = strlen(ibuf);
37634235Smarkfen 			if ((cbuf_offset + len + 1) >= CBUF_LEN)
37644235Smarkfen 				return (-1);
37655120Smarkfen 
37664235Smarkfen 			(void) strcpy(cbuf + cbuf_offset, ibuf);
37674235Smarkfen 			cbuf_offset += len;
37684235Smarkfen 		}
37694235Smarkfen 		/*
37704235Smarkfen 		 * Start of the non-empty non-space character.
37714235Smarkfen 		 */
37725120Smarkfen 		tmp_buf = buf;
37734235Smarkfen 
37744235Smarkfen 		/* Skip until next whitespace or CURL_BEGIN */
37754235Smarkfen 		while (*buf != NULL && !isspace(*buf) &&
37764235Smarkfen 		    *buf != CURL_BEGIN)
37774235Smarkfen 			buf++;
37784235Smarkfen 
37794235Smarkfen 		if (*buf != NULL) {
37805120Smarkfen 			if (tmp_buf == buf) /* No action token */
37815120Smarkfen 				goto error;
37824235Smarkfen 			if (*buf == CURL_BEGIN) {
37834235Smarkfen 				*buf = NULL;
37844235Smarkfen 				/* Allocate an extra byte for the null also */
37854235Smarkfen 				if ((*action = malloc(strlen(tmp_buf) + 1)) ==
37864235Smarkfen 				    NULL) {
37874235Smarkfen 					warn("malloc");
37884235Smarkfen 					return (ENOMEM);
37894235Smarkfen 				}
37904235Smarkfen 				(void) strcpy(*action, tmp_buf);
37914235Smarkfen 				*buf = CURL_BEGIN;
37924235Smarkfen 			} else {
37934235Smarkfen 				/* We have hit a space */
37944235Smarkfen 				*buf++ = NULL;
37954235Smarkfen 				/* Allocate an extra byte for the null also */
37964235Smarkfen 				if ((*action = malloc(strlen(tmp_buf) + 1)) ==
37974235Smarkfen 				    NULL) {
37984235Smarkfen 					warn("malloc");
37994235Smarkfen 					return (ENOMEM);
38004235Smarkfen 				}
38014235Smarkfen 				(void) strcpy(*action, tmp_buf);
38024235Smarkfen 			}
38034235Smarkfen 			/*
38044235Smarkfen 			 * Copy the rest of the line into the
38054235Smarkfen 			 * leftover buffer.
38064235Smarkfen 			 */
38074235Smarkfen 			if (*buf != NULL) {
38084235Smarkfen 				(void) strlcpy(lo_buf, buf, sizeof (lo_buf));
38094235Smarkfen 				*leftover = lo_buf;
38104235Smarkfen 			} else {
38114235Smarkfen 				*leftover = NULL;
38124235Smarkfen 			}
38134235Smarkfen 		} else {
38144235Smarkfen 			/* Allocate an extra byte for the null also */
38154235Smarkfen 			if ((*action = malloc(strlen(tmp_buf) + 1)) ==
38164235Smarkfen 			    NULL) {
38174235Smarkfen 				warn("malloc");
38184235Smarkfen 				return (ENOMEM);
38194235Smarkfen 			}
38204235Smarkfen 			(void) strcpy(*action, tmp_buf);
38214235Smarkfen 			*leftover = NULL;
38224235Smarkfen 		}
38235120Smarkfen 		if (argindex >= ARG_BUF_LEN) {
38245120Smarkfen 			warnx(gettext("(parsing one command) "
38255120Smarkfen 			    "Too many selectors before action."));
38264235Smarkfen 			return (-1);
38275120Smarkfen 		}
38284235Smarkfen 		arg_indices[argindex++] = linecount;
38294235Smarkfen 		return (PARSE_SUCCESS);
38304235Smarkfen 	}
38314235Smarkfen 	/*
38324235Smarkfen 	 * Return error, on an empty action field.
38334235Smarkfen 	 */
38345120Smarkfen error:
38355120Smarkfen 	warnx(gettext("(parsing one command) "
38365120Smarkfen 	    "Missing action token."));
38374235Smarkfen 	return (-1);
38384235Smarkfen }
38394235Smarkfen 
38404235Smarkfen /*
38414235Smarkfen  * This is called to parse pattern or properties that is enclosed
38424235Smarkfen  * between CURL_BEGIN and CURL_END.
38434235Smarkfen  */
38444235Smarkfen static int
parse_pattern_or_prop(FILE * fp,char * argvec[],char ** leftover)38454235Smarkfen parse_pattern_or_prop(FILE *fp, char *argvec[], char **leftover)
38464235Smarkfen {
38474235Smarkfen 	char *cp;
38484235Smarkfen 	int i = 0;
38494235Smarkfen 	boolean_t curl_begin_seen = B_FALSE;
38504235Smarkfen 	char ibuf[MAXLEN];
38514235Smarkfen 	char *tmp_buf;
38524235Smarkfen 	char *buf;
38534235Smarkfen 	boolean_t new_stuff;
38544235Smarkfen 
38554235Smarkfen 	/*
38564235Smarkfen 	 * When parsing properties, leftover buffer could have the
38574235Smarkfen 	 * leftovers of the previous fgets().
38584235Smarkfen 	 */
38594235Smarkfen 	if (*leftover != NULL) {
38604235Smarkfen 		buf = *leftover;
38614235Smarkfen 		new_stuff = B_FALSE;
38624235Smarkfen 		goto scan;
38634235Smarkfen 	}
38644235Smarkfen 	while (fgets(ibuf, MAXLEN, fp) != NULL) {
38654235Smarkfen 		new_stuff = B_TRUE;
38664235Smarkfen #ifdef DEBUG_HEAVY
38674235Smarkfen 		(void) printf("%s\n", ibuf);
38684235Smarkfen #endif
38694235Smarkfen 		if (ibuf[strlen(ibuf) - 1] == '\n')
38704235Smarkfen 			linecount++;
38714235Smarkfen 		buf = ibuf;
38724235Smarkfen scan:
38734235Smarkfen 		/* Truncate at the beginning of a comment */
38744235Smarkfen 		cp = strchr(buf, '#');
38754235Smarkfen 		if (cp != NULL)
38764235Smarkfen 			*cp = NULL;
38774235Smarkfen 
38784235Smarkfen 		/* Skip any whitespace */
38794235Smarkfen 		while (*buf != NULL && isspace(*buf))
38804235Smarkfen 			buf++;
38814235Smarkfen 
38824235Smarkfen 		/* Empty line */
38834235Smarkfen 		if (*buf == NULL)
38844235Smarkfen 			continue;
38854235Smarkfen 		/*
38864235Smarkfen 		 * Store the command for error reporting
38874235Smarkfen 		 * and ipsec_conf_add().
38884235Smarkfen 		 */
38894235Smarkfen 		if (new_stuff) {
38904235Smarkfen 			/*
38914235Smarkfen 			 * Check for buffer overflow including the null
38924235Smarkfen 			 * terminating character.
38934235Smarkfen 			 */
38944235Smarkfen 			int len = strlen(ibuf);
38954235Smarkfen 			if ((cbuf_offset + len + 1) >= CBUF_LEN)
38964235Smarkfen 				return (-1);
38974235Smarkfen 			(void) strcpy(cbuf + cbuf_offset, ibuf);
38984235Smarkfen 			cbuf_offset += len;
38994235Smarkfen 		}
39004235Smarkfen 		/*
39014235Smarkfen 		 * First non-space character should be
39024235Smarkfen 		 * a curly bracket.
39034235Smarkfen 		 */
39044235Smarkfen 		if (!curl_begin_seen) {
39054235Smarkfen 			if (*buf != CURL_BEGIN) {
39064235Smarkfen 				/*
39074235Smarkfen 				 * If we never read a newline character,
39084235Smarkfen 				 * we don't want to print 0.
39094235Smarkfen 				 */
39105120Smarkfen 				warnx(gettext("line %d : pattern must start "
39115120Smarkfen 				    "with \"%c\" character"),
39125120Smarkfen 				    (linecount == 0) ? 1 : linecount,
39135120Smarkfen 				    CURL_BEGIN);
39144235Smarkfen 				return (-1);
39154235Smarkfen 			}
39164235Smarkfen 			buf++;
39174235Smarkfen 			curl_begin_seen = B_TRUE;
39184235Smarkfen 		}
39194235Smarkfen 		/*
39204235Smarkfen 		 * Arguments are separated by white spaces or
39214235Smarkfen 		 * newlines. Scan till you see a CURL_END.
39224235Smarkfen 		 */
39234235Smarkfen 		while (*buf != NULL) {
39244235Smarkfen 			if (*buf == CURL_END) {
39254235Smarkfen ret:
39264235Smarkfen 				*buf++ = NULL;
39274235Smarkfen 				/*
39284235Smarkfen 				 * Copy the rest of the line into the
39294235Smarkfen 				 * leftover buffer if any.
39304235Smarkfen 				 */
39314235Smarkfen 				if (*buf != NULL) {
39324235Smarkfen 					(void) strlcpy(lo_buf, buf,
39334235Smarkfen 					    sizeof (lo_buf));
39344235Smarkfen 					*leftover = lo_buf;
39354235Smarkfen 				} else {
39364235Smarkfen 					*leftover = NULL;
39374235Smarkfen 				}
39384235Smarkfen 				return (PARSE_SUCCESS);
39394235Smarkfen 			}
39404235Smarkfen 			/*
39414235Smarkfen 			 * Skip any trailing whitespace until we see a
39424235Smarkfen 			 * non white-space character.
39434235Smarkfen 			 */
39444235Smarkfen 			while (*buf != NULL && isspace(*buf))
39454235Smarkfen 				buf++;
39464235Smarkfen 
39474235Smarkfen 			if (*buf == CURL_END)
39484235Smarkfen 				goto ret;
39494235Smarkfen 
39504235Smarkfen 			/* Scan the next line as this buffer is empty */
39514235Smarkfen 			if (*buf == NULL)
39524235Smarkfen 				break;
39534235Smarkfen 
39544235Smarkfen 			if (i >= MAXARGS) {
39554235Smarkfen 				warnx(
39564235Smarkfen 				    gettext("Number of Arguments exceeded %d"),
39574235Smarkfen 				    i);
39584235Smarkfen 				return (-1);
39594235Smarkfen 			}
39604235Smarkfen 			/*
39614235Smarkfen 			 * Non-empty, Non-space buffer.
39624235Smarkfen 			 */
39634235Smarkfen 			tmp_buf = buf++;
39644235Smarkfen 			/*
39654235Smarkfen 			 * Real scan of the argument takes place here.
39664235Smarkfen 			 * Skip past till space or CURL_END.
39674235Smarkfen 			 */
39684235Smarkfen 			while (*buf != NULL && !isspace(*buf) &&
39694235Smarkfen 			    *buf != CURL_END) {
39704235Smarkfen 				buf++;
39714235Smarkfen 			}
39724235Smarkfen 			/*
39734235Smarkfen 			 * Either a space or we have hit the CURL_END or
39744235Smarkfen 			 * the real end.
39754235Smarkfen 			 */
39764235Smarkfen 			if (*buf != NULL) {
39774235Smarkfen 				if (*buf == CURL_END) {
39784235Smarkfen 					*buf++ = NULL;
39794235Smarkfen 					if ((argvec[i] = malloc(strlen(tmp_buf)
39804235Smarkfen 					    + 1)) == NULL) {
39814235Smarkfen 						warn("malloc");
39824235Smarkfen 						return (ENOMEM);
39834235Smarkfen 					}
39844235Smarkfen 					if (strlen(tmp_buf) != 0) {
39854235Smarkfen 						(void) strcpy(argvec[i],
39864235Smarkfen 						    tmp_buf);
39874235Smarkfen 						if (argindex >= ARG_BUF_LEN)
39885120Smarkfen 							goto toomanyargs;
39894235Smarkfen 						arg_indices[argindex++] =
39904235Smarkfen 						    linecount;
39914235Smarkfen 					}
39924235Smarkfen 					/*
39934235Smarkfen 					 * Copy the rest of the line into the
39944235Smarkfen 					 * leftover buffer.
39954235Smarkfen 					 */
39964235Smarkfen 					if (*buf != NULL) {
39974235Smarkfen 						(void) strlcpy(lo_buf, buf,
39984235Smarkfen 						    sizeof (lo_buf));
39994235Smarkfen 						*leftover = lo_buf;
40004235Smarkfen 					} else {
40014235Smarkfen 						*leftover = NULL;
40024235Smarkfen 					}
40034235Smarkfen 					return (PARSE_SUCCESS);
40044235Smarkfen 				} else {
40054235Smarkfen 					*buf++ = NULL;
40064235Smarkfen 				}
40074235Smarkfen 			}
40084235Smarkfen 			/*
40094235Smarkfen 			 * Copy this argument and scan for the buffer more
40104235Smarkfen 			 * if it is non-empty. If it is empty scan for
40114235Smarkfen 			 * the next line.
40124235Smarkfen 			 */
40134235Smarkfen 			if ((argvec[i] = malloc(strlen(tmp_buf) + 1)) ==
40144235Smarkfen 			    NULL) {
40154235Smarkfen 				warn("malloc");
40164235Smarkfen 				return (ENOMEM);
40174235Smarkfen 			}
40184235Smarkfen 			(void) strcpy(argvec[i++], tmp_buf);
40195120Smarkfen 			if (argindex >= ARG_BUF_LEN) {
40205120Smarkfen 			/*
40215120Smarkfen 			 * The number of tokens in a single policy entry
40225120Smarkfen 			 * exceeds the number of buffers available to fully
40235120Smarkfen 			 * parse the policy entry.
40245120Smarkfen 			 */
40255120Smarkfen toomanyargs:
40265120Smarkfen 				warnx(gettext("(parsing one command) "
40275120Smarkfen 				    "Too many tokens in single policy entry."));
40284235Smarkfen 				return (-1);
40295120Smarkfen 			}
40304235Smarkfen 			arg_indices[argindex++] = linecount;
40314235Smarkfen 		}
40324235Smarkfen 	}
40334235Smarkfen 	/*
40344235Smarkfen 	 * If nothing is given in the file, it is okay.
40354235Smarkfen 	 * If something is given in the file and it is
40364235Smarkfen 	 * not CURL_BEGIN, we would have returned error
40374235Smarkfen 	 * above. If curl_begin_seen and we are here,
40384235Smarkfen 	 * something is wrong.
40394235Smarkfen 	 */
40405120Smarkfen 	if (curl_begin_seen) {
40415120Smarkfen 		warnx(gettext("(parsing one command) "
40425120Smarkfen 		    "Pattern or Properties incomplete."));
40434235Smarkfen 		return (-1);
40445120Smarkfen 	}
40454235Smarkfen 	return (PARSE_EOF);		/* Nothing more in the file */
40464235Smarkfen }
40474235Smarkfen 
40484235Smarkfen /*
40494235Smarkfen  * Parse one command i.e {pattern} action {properties}.
40504235Smarkfen  *
40514235Smarkfen  * {pattern} ( action {prop} | pass | drop ) (or ...)*
40524235Smarkfen  */
40534235Smarkfen static int
parse_one(FILE * fp,act_prop_t * act_props)40544235Smarkfen parse_one(FILE *fp, act_prop_t *act_props)
40554235Smarkfen {
40564235Smarkfen 	char *leftover;
40574235Smarkfen 	int ret;
40584235Smarkfen 	int i;
40594235Smarkfen 	int ap_num = 0;
40604235Smarkfen 	enum parse_state {pattern, action, prop } pstate;
40614235Smarkfen 
40624235Smarkfen 	has_daprefix = has_saprefix = B_FALSE;
40634235Smarkfen 
40644235Smarkfen 	(void) memset(act_props, 0, sizeof (act_prop_t));
40654235Smarkfen 	pstate = pattern;
40664235Smarkfen 
40674235Smarkfen 	ret = 0;
40684235Smarkfen 	leftover = NULL;
40694235Smarkfen 	argindex = 0;
40704235Smarkfen 	cbuf_offset = 0;
40714235Smarkfen 	assert(shp == NULL && dhp == NULL);
40724235Smarkfen 
40734235Smarkfen 	for (;;) {
40744235Smarkfen 		switch (pstate) {
40754235Smarkfen 		case pattern:
40764235Smarkfen 		{
40774235Smarkfen #ifdef DEBUG_HEAVY
40784235Smarkfen 			(void) printf("pattern\n");
40794235Smarkfen #endif
40804235Smarkfen 			ret = parse_pattern_or_prop(fp,
40814235Smarkfen 			    act_props->pattern, &leftover);
40824235Smarkfen 			if (ret == PARSE_EOF) {
40834235Smarkfen 				/* EOF reached */
40845120Smarkfen 				return (PARSE_EOF);
40854235Smarkfen 			}
40864235Smarkfen 			if (ret != 0) {
40875120Smarkfen 				ret = -1;
40884235Smarkfen 				goto err;
40894235Smarkfen 			}
40904235Smarkfen 			pstate = action;
40914235Smarkfen 			break;
40924235Smarkfen 		}
40934235Smarkfen 		case action:
40944235Smarkfen 		{
40954235Smarkfen #ifdef DEBUG_HEAVY
40964235Smarkfen 			(void) printf("action\n");
40974235Smarkfen #endif
40984235Smarkfen 			ret = parse_action(fp,
40994235Smarkfen 			    &act_props->ap[ap_num].act, &leftover);
41004235Smarkfen 			if (ret != 0) {
41015120Smarkfen 				ret = -1;
41024235Smarkfen 				goto err;
41034235Smarkfen 			}
41044235Smarkfen 
41054235Smarkfen 			/*
41064235Smarkfen 			 * Validate action now itself so that we don't
41074235Smarkfen 			 * proceed too much into the bad world.
41084235Smarkfen 			 */
41094235Smarkfen 			for (i = 0; action_table[i].string; i++) {
41104235Smarkfen 				if (strcmp(act_props->ap[ap_num].act,
41114235Smarkfen 				    action_table[i].string) == 0)
41124235Smarkfen 					break;
41134235Smarkfen 			}
41144235Smarkfen 
41154235Smarkfen 			if (action_table[i].tok_val == TOK_or) {
41164235Smarkfen 				/* hit an or, go again */
41174235Smarkfen 				break;
41184235Smarkfen 			}
41194235Smarkfen 
41204235Smarkfen 			if (action_table[i].string == NULL) {
41214235Smarkfen 				/*
41224235Smarkfen 				 * If we never read a newline
41234235Smarkfen 				 * character, we don't want
41244235Smarkfen 				 * to print 0.
41254235Smarkfen 				 */
41265120Smarkfen 				warnx(gettext("(parsing one command) "
41274235Smarkfen 				    "Invalid action on line %d: %s"),
41284235Smarkfen 				    (linecount == 0) ? 1 : linecount,
41294235Smarkfen 				    act_props->ap[ap_num].act);
41304235Smarkfen 				return (-1);
41314235Smarkfen 			}
41324235Smarkfen 
41334235Smarkfen 			pstate = prop;
41344235Smarkfen 			break;
41354235Smarkfen 		}
41364235Smarkfen 		case prop:
41374235Smarkfen 		{
41384235Smarkfen #ifdef DEBUG_HEAVY
41394235Smarkfen 			(void) printf("prop\n");
41404235Smarkfen #endif
41414235Smarkfen 			ret = parse_pattern_or_prop(fp,
41424235Smarkfen 			    act_props->ap[ap_num].prop, &leftover);
41434235Smarkfen 			if (ret != 0) {
41445120Smarkfen 				if (ret == PARSE_EOF) {
41455120Smarkfen 					warnx(gettext("(parsing one command) "
41465120Smarkfen 					    "Missing properties."));
41475120Smarkfen 				}
41485120Smarkfen 				ret = -1;
41494235Smarkfen 				goto err;
41504235Smarkfen 			}
41514235Smarkfen 
41524235Smarkfen 			if (leftover != NULL) {
41534235Smarkfen 				/* Accomodate spaces at the end */
41544235Smarkfen 				while (*leftover != NULL) {
41555120Smarkfen 					if (*leftover == BACK_SLASH) {
41565120Smarkfen 						warnx(gettext("Invalid line "
41575120Smarkfen 						    "continuation character."));
41585120Smarkfen 						ret = -1;
41595120Smarkfen 						goto err;
41605120Smarkfen 					}
41614235Smarkfen 					if (*leftover == 'o') {
41624235Smarkfen 						leftover++;
41634235Smarkfen 						if (*leftover == 'r') {
41644235Smarkfen 							leftover++;
41654235Smarkfen 							ap_num++;
41664235Smarkfen 							pstate = action;
41674235Smarkfen 							goto again;
41684235Smarkfen 						}
41694235Smarkfen 					}
41704235Smarkfen 					if (!isspace(*leftover)) {
41714235Smarkfen 						ret = -1;
41724235Smarkfen 						goto err;
41734235Smarkfen 					}
41744235Smarkfen 					leftover++;
41754235Smarkfen 				}
41764235Smarkfen 				return (0);
41774235Smarkfen 			}
41784235Smarkfen 			ap_num++;
41794235Smarkfen 			if (ap_num > MAXARGS)
41804235Smarkfen 				return (0);
41814235Smarkfen 			pstate = action; /* or */
41824235Smarkfen 			break;
41834235Smarkfen 		} /* case prop: */
41844235Smarkfen 		} /* switch(pstate) */
41854235Smarkfen 
41864235Smarkfen again:
41875120Smarkfen 		if (ap_num > MAXARGS) {
41885120Smarkfen 			warnx(gettext("Too many actions."));
41895120Smarkfen 			return (-1);
41905120Smarkfen 		}
41915120Smarkfen 	} /* for(;;) */
41924235Smarkfen err:
41934235Smarkfen 	if (ret != 0) {
41944235Smarkfen 		/*
41954235Smarkfen 		 * If we never read a newline character, we don't want
41964235Smarkfen 		 * to print 0.
41974235Smarkfen 		 */
41984235Smarkfen 		warnx(gettext("Error before or at line %d"),
41994235Smarkfen 		    (linecount == 0) ? 1 : linecount);
42004235Smarkfen 	}
42014235Smarkfen 	return (ret);
42024235Smarkfen }
42034235Smarkfen 
42044235Smarkfen /*
42054235Smarkfen  * convert an act_propts_t to an ips_conf_t
42064235Smarkfen  */
42074235Smarkfen 
42084235Smarkfen static int
form_ipsec_conf(act_prop_t * act_props,ips_conf_t * cptr)42094235Smarkfen form_ipsec_conf(act_prop_t *act_props, ips_conf_t *cptr)
42104235Smarkfen {
42114235Smarkfen 	int i, j, k;
42124235Smarkfen 	int tok_count = 0;
42134235Smarkfen 	struct protoent *pent;
42144235Smarkfen 	boolean_t saddr, daddr, ipsec_aalg, ipsec_ealg, ipsec_eaalg, dir;
421510372Sdanmcd@sun.com 	boolean_t old_style, new_style, auth_covered, is_no_alg;
421610824SMark.Fenwick@Sun.COM 	boolean_t is_combined_mode;
42174235Smarkfen 	struct in_addr mask;
42184235Smarkfen 	int line_no;
42194235Smarkfen 	int ret;
42204235Smarkfen 	int ap_num = 0;
42214235Smarkfen 	int type, code, type_end, code_end;
42224235Smarkfen #ifdef DEBUG_HEAVY
42234235Smarkfen 	/*
42244235Smarkfen 	 * pattern => act_props->pattern
42254235Smarkfen 	 * action => act_props->ap[].act
42264235Smarkfen 	 * properties => act_props->ap[].prop
42274235Smarkfen 	 */
42284235Smarkfen 	(void) printf("\npattern\n------------\n");
42294235Smarkfen 	for (i = 0; act_props->pattern[i] != NULL; i++)
42304235Smarkfen 		(void) printf("%s\n", act_props->pattern[i]);
42314235Smarkfen 	(void) printf("apz\n----------\n");
42324235Smarkfen 	for (j = 0; act_props->ap[j].act != NULL; j++) {
42334235Smarkfen 
42344235Smarkfen 		(void) printf("act%d->%s\n", j, act_props->ap[j].act);
42354235Smarkfen 		for (i = 0; act_props->ap[j].prop[i] != NULL; i++)
42364235Smarkfen 			(void) printf("%dprop%d->%s\n",
42374235Smarkfen 			    j, i, act_props->ap[j].prop[i]);
42384235Smarkfen 	}
42394235Smarkfen 	(void) printf("------------\n\n");
42404235Smarkfen #endif
42414235Smarkfen 
42424235Smarkfen 	(void) memset(cptr, 0, sizeof (ips_conf_t));
42434235Smarkfen 	saddr = daddr = ipsec_aalg = ipsec_ealg = ipsec_eaalg = dir = B_FALSE;
424410824SMark.Fenwick@Sun.COM 	old_style = new_style = is_no_alg = is_combined_mode = B_FALSE;
42454235Smarkfen 	/*
42464235Smarkfen 	 * Get the Pattern. NULL pattern is valid.
42474235Smarkfen 	 */
42484235Smarkfen 	for (i = 0, line_no = 0; act_props->pattern[i]; i++, line_no++) {
42494235Smarkfen 		for (j = 0; pattern_table[j].string; j++) {
42504235Smarkfen 			if (strcmp(act_props->pattern[i],
42514235Smarkfen 			    pattern_table[j].string) == 0)
42524235Smarkfen 				break;
42534235Smarkfen 		}
42544235Smarkfen 
42554235Smarkfen 		if (pattern_table[j].string == NULL) {
42564235Smarkfen 			/*
42574235Smarkfen 			 * If we never read a newline character, we don't want
42584235Smarkfen 			 * to print 0.
42594235Smarkfen 			 */
42604235Smarkfen 			warnx(gettext("Invalid pattern on line %d: %s"),
42614235Smarkfen 			    (arg_indices[line_no] == 0) ? 1 :
42624235Smarkfen 			    arg_indices[line_no], act_props->pattern[i]);
42634235Smarkfen 			return (-1);
42644235Smarkfen 		}
42654235Smarkfen 
42664235Smarkfen 		cptr->patt_tok[tok_count++] = pattern_table[j].tok_val;
42674235Smarkfen 
42684235Smarkfen 		switch (pattern_table[j].tok_val) {
42694235Smarkfen 
42704235Smarkfen 		case TOK_dir:
42714235Smarkfen 			i++, line_no++;
42724235Smarkfen 			if (act_props->pattern[i] == NULL) {
42734235Smarkfen 				error_message(BAD_ERROR,
42744235Smarkfen 				    IPSEC_CONF_IPSEC_DIR, line_no);
42754235Smarkfen 				return (-1);
42764235Smarkfen 			}
42774235Smarkfen 
42784235Smarkfen 			if (strncmp(act_props->pattern[i], "in", 2) == 0) {
42794235Smarkfen 				cptr->ips_dir = SPD_RULE_FLAG_INBOUND;
42804235Smarkfen 			} else if (strncmp(
42814235Smarkfen 			    act_props->pattern[i], "out", 3) == 0) {
42824235Smarkfen 				cptr->ips_dir = SPD_RULE_FLAG_OUTBOUND;
42834235Smarkfen 			} else if (strncmp(
42844235Smarkfen 			    act_props->pattern[i], "both", 4) == 0) {
42854235Smarkfen 				if (old_style) {
42864235Smarkfen 					error_message(BAD_ERROR,
42874235Smarkfen 					    IPSEC_CONF_IPSEC_DIR, line_no);
42884235Smarkfen 					return (-1);
42894235Smarkfen 				}
42904235Smarkfen 				new_style = B_TRUE;
42914235Smarkfen 				cptr->ips_dir =
42924235Smarkfen 				    SPD_RULE_FLAG_OUTBOUND |
42934235Smarkfen 				    SPD_RULE_FLAG_INBOUND;
42944235Smarkfen 			} else {
42954235Smarkfen 				error_message(BAD_ERROR,
42964235Smarkfen 				    IPSEC_CONF_IPSEC_DIR, line_no);
42974235Smarkfen 				return (-1);
42984235Smarkfen 			}
42994235Smarkfen 			dir = B_TRUE;
43004235Smarkfen 			break;
43014235Smarkfen 
43024235Smarkfen 		case TOK_local:
43034235Smarkfen 			if (old_style) {
43044235Smarkfen 				error_message(BAD_ERROR,
43054235Smarkfen 				    IPSEC_CONF_SRC_ADDRESS, line_no);
43064235Smarkfen 				return (-1);
43074235Smarkfen 			}
43084235Smarkfen 			new_style = B_TRUE;
43094235Smarkfen 
43104235Smarkfen 			if (saddr) {
43114235Smarkfen 				error_message(DUP_ERROR,
43124235Smarkfen 				    IPSEC_CONF_SRC_ADDRESS, line_no);
43134235Smarkfen 				return (-1);
43144235Smarkfen 			}
43154235Smarkfen 			/*
43164235Smarkfen 			 * Use this to detect duplicates rather
43174235Smarkfen 			 * than 0 like other cases, because 0 for
43184235Smarkfen 			 * address means INADDR_ANY.
43194235Smarkfen 			 */
43204235Smarkfen 			saddr = B_TRUE;
43214235Smarkfen 			cptr->has_saddr = 1;
43224235Smarkfen 			/*
43234235Smarkfen 			 * Advance to the string containing
43244235Smarkfen 			 * the address.
43254235Smarkfen 			 */
43264235Smarkfen 			i++, line_no++;
43274235Smarkfen 			if (act_props->pattern[i] == NULL) {
43284235Smarkfen 				error_message(BAD_ERROR,
43294235Smarkfen 				    IPSEC_CONF_SRC_ADDRESS, line_no);
43304235Smarkfen 				return (-1);
43314235Smarkfen 			}
43324235Smarkfen 			if (parse_address(IPSEC_CONF_SRC_ADDRESS,
43334235Smarkfen 			    act_props->pattern[i]) != 0) {
43344235Smarkfen 				error_message(BAD_ERROR,
43354235Smarkfen 				    IPSEC_CONF_SRC_ADDRESS, line_no);
43364235Smarkfen 				return (-1);
43374235Smarkfen 			}
43384235Smarkfen 			if (!cptr->has_smask)
43394235Smarkfen 				cptr->has_smask = has_saprefix;
43404235Smarkfen 
43414235Smarkfen 			break;
43424235Smarkfen 		case TOK_remote:
43434235Smarkfen 			if (old_style) {
43444235Smarkfen 				error_message(BAD_ERROR,
43454235Smarkfen 				    IPSEC_CONF_DST_ADDRESS, line_no);
43464235Smarkfen 				return (-1);
43474235Smarkfen 			}
43484235Smarkfen 			new_style = B_TRUE;
43494235Smarkfen 
43504235Smarkfen 			if (daddr) {
43514235Smarkfen 				error_message(DUP_ERROR,
43524235Smarkfen 				    IPSEC_CONF_DST_ADDRESS, line_no);
43534235Smarkfen 				return (-1);
43544235Smarkfen 			}
43554235Smarkfen 			/*
43564235Smarkfen 			 * Use this to detect duplicates rather
43574235Smarkfen 			 * than 0 like other cases, because 0 for
43584235Smarkfen 			 * address means INADDR_ANY.
43594235Smarkfen 			 */
43604235Smarkfen 			daddr = B_TRUE;
43614235Smarkfen 			cptr->has_daddr = 1;
43624235Smarkfen 			/*
43634235Smarkfen 			 * Advance to the string containing
43644235Smarkfen 			 * the address.
43654235Smarkfen 			 */
43664235Smarkfen 			i++, line_no++;
43674235Smarkfen 			if (act_props->pattern[i] == NULL) {
43684235Smarkfen 				error_message(BAD_ERROR,
43694235Smarkfen 				    IPSEC_CONF_DST_ADDRESS, line_no);
43704235Smarkfen 				return (-1);
43714235Smarkfen 			}
43724235Smarkfen 			if (parse_address(IPSEC_CONF_DST_ADDRESS,
43734235Smarkfen 			    act_props->pattern[i]) != 0) {
43744235Smarkfen 				error_message(BAD_ERROR,
43754235Smarkfen 				    IPSEC_CONF_DST_ADDRESS, line_no);
43764235Smarkfen 				return (-1);
43774235Smarkfen 			}
43784235Smarkfen 			if (!cptr->has_dmask)
43794235Smarkfen 				cptr->has_dmask = has_daprefix;
43804235Smarkfen 			break;
43814235Smarkfen 
43824235Smarkfen 		case TOK_saddr:
43834235Smarkfen 			if (new_style) {
43844235Smarkfen 				error_message(BAD_ERROR,
43854235Smarkfen 				    IPSEC_CONF_SRC_ADDRESS, line_no);
43864235Smarkfen 				return (-1);
43874235Smarkfen 			}
43884235Smarkfen 			old_style = B_TRUE;
43894235Smarkfen 
43904235Smarkfen 			if (saddr) {
43914235Smarkfen 				error_message(DUP_ERROR,
43924235Smarkfen 				    IPSEC_CONF_SRC_ADDRESS, line_no);
43934235Smarkfen 				return (-1);
43944235Smarkfen 			}
43954235Smarkfen 			/*
43964235Smarkfen 			 * Use this to detect duplicates rather
43974235Smarkfen 			 * than 0 like other cases, because 0 for
43984235Smarkfen 			 * address means INADDR_ANY.
43994235Smarkfen 			 */
44004235Smarkfen 			saddr = B_TRUE;
44014235Smarkfen 			cptr->has_saddr = 1;
44024235Smarkfen 			/*
44034235Smarkfen 			 * Advance to the string containing
44044235Smarkfen 			 * the address.
44054235Smarkfen 			 */
44064235Smarkfen 			i++, line_no++;
44074235Smarkfen 			if (act_props->pattern[i] == NULL) {
44084235Smarkfen 				error_message(BAD_ERROR,
44094235Smarkfen 				    IPSEC_CONF_SRC_ADDRESS, line_no);
44104235Smarkfen 				return (-1);
44114235Smarkfen 			}
44124235Smarkfen 
44134235Smarkfen 			if (parse_address(IPSEC_CONF_SRC_ADDRESS,
44144235Smarkfen 			    act_props->pattern[i]) != 0) {
44154235Smarkfen 				error_message(BAD_ERROR,
44164235Smarkfen 				    IPSEC_CONF_SRC_ADDRESS, line_no);
44174235Smarkfen 				return (-1);
44184235Smarkfen 			}
44194235Smarkfen 			/* shp or bhp? */
44204235Smarkfen 			if (!cptr->has_smask)
44214235Smarkfen 				cptr->has_smask = has_saprefix;
44224235Smarkfen 			break;
44234235Smarkfen 
44244235Smarkfen 		case TOK_daddr:
44254235Smarkfen 			if (new_style) {
44264235Smarkfen 				error_message(BAD_ERROR,
44274235Smarkfen 				    IPSEC_CONF_DST_ADDRESS, line_no);
44284235Smarkfen 				return (-1);
44294235Smarkfen 			}
44304235Smarkfen 			old_style = B_TRUE;
44314235Smarkfen 
44324235Smarkfen 			if (daddr) {
44334235Smarkfen 				error_message(DUP_ERROR,
44344235Smarkfen 				    IPSEC_CONF_DST_ADDRESS, line_no);
44354235Smarkfen 				return (-1);
44364235Smarkfen 			}
44374235Smarkfen 			/*
44384235Smarkfen 			 * Use this to detect duplicates rather
44394235Smarkfen 			 * than 0 like other cases, because 0 for
44404235Smarkfen 			 * address means INADDR_ANY.
44414235Smarkfen 			 */
44424235Smarkfen 			daddr = B_TRUE;
44434235Smarkfen 			cptr->has_daddr = 1;
44444235Smarkfen 			/*
44454235Smarkfen 			 * Advance to the string containing
44464235Smarkfen 			 * the address.
44474235Smarkfen 			 */
44484235Smarkfen 			i++, line_no++;
44494235Smarkfen 			if (act_props->pattern[i] == NULL) {
44504235Smarkfen 				error_message(BAD_ERROR,
44514235Smarkfen 				    IPSEC_CONF_DST_ADDRESS, line_no);
44524235Smarkfen 				return (-1);
44534235Smarkfen 			}
44544235Smarkfen 			if (parse_address(IPSEC_CONF_DST_ADDRESS,
44554235Smarkfen 			    act_props->pattern[i]) != 0) {
44564235Smarkfen 				error_message(BAD_ERROR,
44574235Smarkfen 				    IPSEC_CONF_DST_ADDRESS, line_no);
44584235Smarkfen 				return (-1);
44594235Smarkfen 			}
44604235Smarkfen 			if (!cptr->has_dmask)
44614235Smarkfen 				cptr->has_dmask = has_daprefix;
44624235Smarkfen 			break;
44634235Smarkfen 
44644235Smarkfen 		case TOK_sport:
44654235Smarkfen 			if (new_style) {
44664235Smarkfen 				error_message(BAD_ERROR,
44674235Smarkfen 				    IPSEC_CONF_SRC_PORT, line_no);
44684235Smarkfen 				return (-1);
44694235Smarkfen 			}
44704235Smarkfen 			old_style = B_TRUE;
44714235Smarkfen 
44724235Smarkfen 			if (cptr->ips_src_port_min != 0) {
44734235Smarkfen 				error_message(DUP_ERROR, IPSEC_CONF_SRC_PORT,
44744235Smarkfen 				    line_no);
44754235Smarkfen 				return (-1);
44764235Smarkfen 			}
44774235Smarkfen 			i++, line_no++;
44784235Smarkfen 			if (act_props->pattern[i] == NULL) {
44794235Smarkfen 				error_message(BAD_ERROR, IPSEC_CONF_SRC_PORT,
44804235Smarkfen 				    line_no);
44814235Smarkfen 				return (-1);
44824235Smarkfen 			}
44834235Smarkfen 			ret = parse_port(IPSEC_CONF_SRC_PORT,
44844235Smarkfen 			    act_props->pattern[i], cptr);
44854235Smarkfen 			if (ret != 0) {
44864235Smarkfen 				error_message(BAD_ERROR, IPSEC_CONF_SRC_PORT,
44874235Smarkfen 				    line_no);
44884235Smarkfen 				return (-1);
44894235Smarkfen 			}
44904235Smarkfen 			break;
44914235Smarkfen 		case TOK_dport:
44924235Smarkfen 			if (new_style) {
44934235Smarkfen 				error_message(BAD_ERROR,
44944235Smarkfen 				    IPSEC_CONF_DST_PORT, line_no);
44954235Smarkfen 				return (-1);
44964235Smarkfen 			}
44974235Smarkfen 			old_style = B_TRUE;
44984235Smarkfen 
44994235Smarkfen 			if (cptr->ips_dst_port_min != 0) {
45004235Smarkfen 				error_message(DUP_ERROR, IPSEC_CONF_DST_PORT,
45014235Smarkfen 				    line_no);
45024235Smarkfen 				return (-1);
45034235Smarkfen 			}
45044235Smarkfen 			i++, line_no++;
45054235Smarkfen 			if (act_props->pattern[i] == NULL) {
45064235Smarkfen 				error_message(BAD_ERROR, IPSEC_CONF_DST_PORT,
45074235Smarkfen 				    line_no);
45084235Smarkfen 				return (-1);
45094235Smarkfen 			}
45104235Smarkfen 			ret = parse_port(IPSEC_CONF_DST_PORT,
45114235Smarkfen 			    act_props->pattern[i],
45124235Smarkfen 			    cptr);
45134235Smarkfen 			if (ret != 0) {
45144235Smarkfen 				error_message(BAD_ERROR, IPSEC_CONF_DST_PORT,
45154235Smarkfen 				    line_no);
45164235Smarkfen 				return (-1);
45174235Smarkfen 			}
45184235Smarkfen 			break;
45194235Smarkfen 
45204235Smarkfen 		case TOK_lport:
45214235Smarkfen 			if (old_style) {
45224235Smarkfen 				error_message(BAD_ERROR,
45234235Smarkfen 				    IPSEC_CONF_SRC_PORT, line_no);
45244235Smarkfen 				return (-1);
45254235Smarkfen 			}
45264235Smarkfen 			new_style = B_TRUE;
45274235Smarkfen 
45284235Smarkfen 			if (cptr->ips_src_port_min != 0) {
45294235Smarkfen 				error_message(DUP_ERROR, IPSEC_CONF_SRC_PORT,
45304235Smarkfen 				    line_no);
45314235Smarkfen 				return (-1);
45324235Smarkfen 			}
45334235Smarkfen 			i++, line_no++;
45344235Smarkfen 			if (act_props->pattern[i] == NULL) {
45354235Smarkfen 				error_message(BAD_ERROR, IPSEC_CONF_SRC_PORT,
45364235Smarkfen 				    line_no);
45374235Smarkfen 				return (-1);
45384235Smarkfen 			}
45394235Smarkfen 			ret = parse_port(IPSEC_CONF_SRC_PORT,
45404235Smarkfen 			    act_props->pattern[i],
45414235Smarkfen 			    cptr);
45424235Smarkfen 			if (ret != 0) {
45434235Smarkfen 				error_message(BAD_ERROR, IPSEC_CONF_SRC_PORT,
45444235Smarkfen 				    line_no);
45454235Smarkfen 				return (-1);
45464235Smarkfen 			}
45474235Smarkfen 			break;
45484235Smarkfen 
45494235Smarkfen 		case TOK_rport:
45504235Smarkfen 			if (old_style) {
45514235Smarkfen 				error_message(BAD_ERROR,
45524235Smarkfen 				    IPSEC_CONF_DST_PORT, line_no);
45534235Smarkfen 				return (-1);
45544235Smarkfen 			}
45554235Smarkfen 			new_style = B_TRUE;
45564235Smarkfen 
45574235Smarkfen 			if (cptr->ips_dst_port_min != 0) {
45584235Smarkfen 				error_message(DUP_ERROR, IPSEC_CONF_DST_PORT,
45594235Smarkfen 				    line_no);
45604235Smarkfen 				return (-1);
45614235Smarkfen 			}
45624235Smarkfen 			i++, line_no++;
45634235Smarkfen 			if (act_props->pattern[i] == NULL) {
45644235Smarkfen 				error_message(BAD_ERROR, IPSEC_CONF_DST_PORT,
45654235Smarkfen 				    line_no);
45664235Smarkfen 				return (-1);
45674235Smarkfen 			}
45684235Smarkfen 			ret = parse_port(IPSEC_CONF_DST_PORT,
45694235Smarkfen 			    act_props->pattern[i],
45704235Smarkfen 			    cptr);
45714235Smarkfen 			if (ret != 0) {
45724235Smarkfen 				error_message(BAD_ERROR, IPSEC_CONF_DST_PORT,
45734235Smarkfen 				    line_no);
45744235Smarkfen 				return (-1);
45754235Smarkfen 			}
45764235Smarkfen 			break;
45774235Smarkfen 
45784235Smarkfen 		case TOK_smask:
45794235Smarkfen 			if (new_style) {
45804235Smarkfen 				error_message(BAD_ERROR,
45814235Smarkfen 				    IPSEC_CONF_SRC_MASK, line_no);
45824235Smarkfen 				return (-1);
45834235Smarkfen 			}
45844235Smarkfen 			old_style = B_TRUE;
45854235Smarkfen 			cptr->has_smask = B_TRUE;
45864235Smarkfen 
45874235Smarkfen 			IN6_V4MAPPED_TO_INADDR(&cptr->ips_src_mask_v6, &mask);
45884235Smarkfen 			if (mask.s_addr != 0) {
45894235Smarkfen 				error_message(DUP_ERROR, IPSEC_CONF_SRC_MASK,
45904235Smarkfen 				    line_no);
45914235Smarkfen 				return (-1);
45924235Smarkfen 			}
45934235Smarkfen 			i++, line_no++;
45944235Smarkfen 			if (act_props->pattern[i] == NULL) {
45954235Smarkfen 				error_message(BAD_ERROR, IPSEC_CONF_SRC_MASK,
45964235Smarkfen 				    line_no);
45974235Smarkfen 				return (-1);
45984235Smarkfen 			}
45994235Smarkfen 			ret = parse_mask(IPSEC_CONF_SRC_MASK,
46004235Smarkfen 			    act_props->pattern[i],
46014235Smarkfen 			    cptr);
46024235Smarkfen 			if (ret != 0) {
46034235Smarkfen 				error_message(BAD_ERROR, IPSEC_CONF_SRC_MASK,
46044235Smarkfen 				    line_no);
46054235Smarkfen 				return (-1);
46064235Smarkfen 			}
46074235Smarkfen 			break;
46084235Smarkfen 		case TOK_dmask:
46094235Smarkfen 			if (new_style) {
46104235Smarkfen 				error_message(BAD_ERROR,
46114235Smarkfen 				    IPSEC_CONF_DST_MASK, line_no);
46124235Smarkfen 				return (-1);
46134235Smarkfen 			}
46144235Smarkfen 			old_style = B_TRUE;
46154235Smarkfen 			cptr->has_dmask = B_TRUE;
46164235Smarkfen 
46174235Smarkfen 			IN6_V4MAPPED_TO_INADDR(&cptr->ips_dst_mask_v6, &mask);
46184235Smarkfen 			if (mask.s_addr != 0) {
46194235Smarkfen 				error_message(DUP_ERROR, IPSEC_CONF_DST_MASK,
46204235Smarkfen 				    line_no);
46214235Smarkfen 				return (-1);
46224235Smarkfen 			}
46234235Smarkfen 			i++, line_no++;
46244235Smarkfen 			if (act_props->pattern[i] == NULL) {
46254235Smarkfen 				error_message(BAD_ERROR, IPSEC_CONF_DST_MASK,
46264235Smarkfen 				    line_no);
46274235Smarkfen 				return (-1);
46284235Smarkfen 			}
46294235Smarkfen 			ret = parse_mask(IPSEC_CONF_DST_MASK,
46304235Smarkfen 			    act_props->pattern[i],
46314235Smarkfen 			    cptr);
46324235Smarkfen 			if (ret != 0) {
46334235Smarkfen 				error_message(BAD_ERROR, IPSEC_CONF_DST_MASK,
46344235Smarkfen 				    line_no);
46354235Smarkfen 				return (-1);
46364235Smarkfen 			}
46374235Smarkfen 			break;
46384235Smarkfen 		case TOK_ulp:
46394235Smarkfen 			if (cptr->ips_ulp_prot != 0) {
46404235Smarkfen 				error_message(DUP_ERROR,
46414235Smarkfen 				    IPSEC_CONF_ULP, line_no);
46424235Smarkfen 				return (-1);
46434235Smarkfen 			}
46444235Smarkfen 			i++, line_no++;
46454235Smarkfen 			if (act_props->pattern[i] == NULL) {
46464235Smarkfen 				error_message(BAD_ERROR,
46474235Smarkfen 				    IPSEC_CONF_ULP, line_no);
46484235Smarkfen 				return (-1);
46494235Smarkfen 			}
46504235Smarkfen 			pent = getprotobyname(act_props->pattern[i]);
46514235Smarkfen 			if (pent == NULL) {
46524235Smarkfen 				int ulp;
46534235Smarkfen 				ulp = parse_int(act_props->pattern[i]);
46544235Smarkfen 				if (ulp == -1) {
46554235Smarkfen 					error_message(BAD_ERROR,
46564235Smarkfen 					    IPSEC_CONF_ULP, line_no);
46574235Smarkfen 					return (-1);
46584235Smarkfen 				}
46594235Smarkfen 				cptr->ips_ulp_prot = ulp;
46604235Smarkfen 			} else {
46614235Smarkfen 				cptr->ips_ulp_prot = pent->p_proto;
46624235Smarkfen 			}
46634235Smarkfen 			break;
46644235Smarkfen 		case TOK_type:
46654235Smarkfen 			if (cptr->has_type) {
46664235Smarkfen 				error_message(DUP_ERROR,
46674235Smarkfen 				    IPSEC_CONF_ICMP_TYPE, line_no);
46684235Smarkfen 				return (-1);
46694235Smarkfen 			}
46704235Smarkfen 
46714235Smarkfen 			i++, line_no++;
46724235Smarkfen 			type = parse_type_code(act_props->pattern[i],
46734235Smarkfen 			    icmp_type_table);
46744235Smarkfen 
46754235Smarkfen 			if (type > 65536 || type < 0) {
46764235Smarkfen 				error_message(BAD_ERROR,
46774235Smarkfen 				    IPSEC_CONF_ICMP_TYPE, line_no);
46784235Smarkfen 				return (-1);
46794235Smarkfen 			}
46804235Smarkfen 
46814235Smarkfen 			type_end = type / 256;
46824235Smarkfen 			type = type % 256;
46834235Smarkfen 
46844235Smarkfen 			if (type_end < type)
46854235Smarkfen 				type_end = type;
46864235Smarkfen 
46874235Smarkfen 			cptr->has_type = 1;
46884235Smarkfen 			cptr->ips_icmp_type = (uint8_t)type;
46894235Smarkfen 			cptr->ips_icmp_type_end = (uint8_t)type_end;
46904235Smarkfen 			break;
46914235Smarkfen 		case TOK_code:
46924235Smarkfen 			if (!cptr->has_type) {
46934235Smarkfen 				error_message(BAD_ERROR,
46944235Smarkfen 				    IPSEC_CONF_ICMP_CODE, line_no);
46954235Smarkfen 				return (-1);
46964235Smarkfen 			}
46974235Smarkfen 
46984235Smarkfen 			if (cptr->has_code) {
46994235Smarkfen 				error_message(DUP_ERROR,
47004235Smarkfen 				    IPSEC_CONF_ICMP_CODE, line_no);
47014235Smarkfen 				return (-1);
47024235Smarkfen 			}
47034235Smarkfen 
47044235Smarkfen 			i++, line_no++;
47054235Smarkfen 
47064235Smarkfen 			code = parse_type_code(act_props->pattern[i],
47074235Smarkfen 			    icmp_code_table);
47084235Smarkfen 			if (type > 65536 || type < 0) {
47094235Smarkfen 				error_message(BAD_ERROR,
47104235Smarkfen 				    IPSEC_CONF_ICMP_CODE, line_no);
47114235Smarkfen 				return (-1);
47124235Smarkfen 			}
47134235Smarkfen 			code_end = code / 256;
47144235Smarkfen 			code = code % 256;
47154235Smarkfen 
47164235Smarkfen 			if (code_end < code)
47174235Smarkfen 				code_end = code;
47184235Smarkfen 
47194235Smarkfen 			cptr->has_code = 1;
47204235Smarkfen 			cptr->ips_icmp_code = (uint8_t)code;
47214235Smarkfen 			cptr->ips_icmp_code_end = (uint8_t)code_end;
47224235Smarkfen 			break;
47234235Smarkfen 		case TOK_tunnel:
47244235Smarkfen 			if (cptr->has_tunnel == 1) {
47254235Smarkfen 				error_message(BAD_ERROR,
47264235Smarkfen 				    IPSEC_CONF_TUNNEL, line_no);
47274235Smarkfen 				return (-1);
47284235Smarkfen 			}
47294235Smarkfen 			i++, line_no++;
47304235Smarkfen 			if (act_props->pattern[i] == NULL) {
47314235Smarkfen 				error_message(BAD_ERROR,
47324235Smarkfen 				    IPSEC_CONF_TUNNEL, line_no);
47334235Smarkfen 				return (-1);
47344235Smarkfen 			}
47354235Smarkfen 
47364235Smarkfen 			if (strlcpy(tunif, act_props->pattern[i],
47374235Smarkfen 			    TUNNAMEMAXLEN) >= TUNNAMEMAXLEN) {
47384235Smarkfen 				error_message(BAD_ERROR,
47394235Smarkfen 				    IPSEC_CONF_TUNNEL, line_no);
47404235Smarkfen 				return (-1);
47414235Smarkfen 			}
47424235Smarkfen 			cptr->has_tunnel = 1;
47434235Smarkfen 			break;
47444235Smarkfen 		case TOK_negotiate:
47454235Smarkfen 			if (cptr->has_negotiate == 1) {
47464235Smarkfen 				error_message(BAD_ERROR,
47474235Smarkfen 				    IPSEC_CONF_NEGOTIATE, line_no);
47484235Smarkfen 				return (-1);
47494235Smarkfen 			}
47504235Smarkfen 			i++, line_no++;
47514235Smarkfen 			if (act_props->pattern[i] == NULL) {
47524235Smarkfen 				error_message(BAD_ERROR,
47534235Smarkfen 				    IPSEC_CONF_NEGOTIATE, line_no);
47544235Smarkfen 				return (-1);
47554235Smarkfen 			}
47564235Smarkfen 
47574235Smarkfen 			if (strncmp(act_props->pattern[i], "tunnel", 6) == 0) {
47584235Smarkfen 				cptr->ips_tunnel = B_TRUE;
47594235Smarkfen 			} else if (strncmp(
47604235Smarkfen 			    act_props->pattern[i], "transport", 9) != 0) {
47614235Smarkfen 				error_message(BAD_ERROR,
47624235Smarkfen 				    IPSEC_CONF_NEGOTIATE, line_no);
47634235Smarkfen 				return (-1);
47644235Smarkfen 			}
47654235Smarkfen 			cptr->has_negotiate = 1;
47664235Smarkfen 			break;
47674235Smarkfen 		}
47684235Smarkfen 
47694235Smarkfen 	}
47704235Smarkfen 
47714235Smarkfen 	/* Sanity check that certain tokens occur together */
47724235Smarkfen 	if (cptr->has_tunnel + cptr->has_negotiate == 1) {
47734235Smarkfen 		if (cptr->has_negotiate == 0) {
47744235Smarkfen 			error_message(REQ_ERROR, IPSEC_CONF_NEGOTIATE, line_no);
47754235Smarkfen 		} else {
47764235Smarkfen 			error_message(REQ_ERROR, IPSEC_CONF_TUNNEL, line_no);
47774235Smarkfen 		}
47784235Smarkfen 		errx(1, gettext(
47794235Smarkfen 		    "tunnel and negotiate tokens must occur together"));
47804235Smarkfen 		return (-1);
47814235Smarkfen 	}
47824235Smarkfen 
47834235Smarkfen 	/*
47844235Smarkfen 	 * Get the actions.
47854235Smarkfen 	 */
47864235Smarkfen 
47874235Smarkfen 	for (ap_num = 0; act_props->ap[ap_num].act != NULL; ap_num++) {
47884235Smarkfen 		ips_act_props_t *iap;
47894235Smarkfen 
47904235Smarkfen 		if (ap_num > 0) {
47914235Smarkfen 			/* or's only with new style */
47924235Smarkfen 			if (old_style) {
47934235Smarkfen 				(void) printf("%s\n", gettext(
47944235Smarkfen 				    "or's only with new style"));
47954235Smarkfen 				return (-1);
47964235Smarkfen 			}
47974235Smarkfen 			new_style = B_TRUE;
47984235Smarkfen 		}
47994235Smarkfen 
480010372Sdanmcd@sun.com 		ipsec_aalg = ipsec_ealg = ipsec_eaalg = auth_covered = B_FALSE;
48014235Smarkfen 		tok_count = 0;
48024235Smarkfen 
48034235Smarkfen 		for (k = 0; action_table[k].string; k++) {
48044235Smarkfen 			if (strcmp(act_props->ap[ap_num].act,
48054235Smarkfen 			    action_table[k].string) == 0)
48064235Smarkfen 				break;
48074235Smarkfen 		}
48084235Smarkfen 		/*
48094235Smarkfen 		 * The following thing should never happen as
48104235Smarkfen 		 * we have already tested for its validity in parse.
48114235Smarkfen 		 */
48124235Smarkfen 		if (action_table[k].string == NULL) {
48134235Smarkfen 			warnx(gettext("(form act)Invalid action on line "
48144235Smarkfen 			    "%d: %s"), (arg_indices[line_no] == 0) ? 1 :
48154235Smarkfen 			    arg_indices[line_no],
48164235Smarkfen 			    act_props->ap[ap_num].act);
48174235Smarkfen 			warnx("%s", act_props->ap[ap_num].act);
48184235Smarkfen 			return (-1);
48194235Smarkfen 		}
48204235Smarkfen 
48214235Smarkfen 		/* we have a good action alloc an iap */
48224235Smarkfen 		iap = alloc_iap(cptr);
48234235Smarkfen 
48244235Smarkfen 		iap->iap_action = action_table[k].value;
48254235Smarkfen 		iap->iap_act_tok = action_table[k].tok_val;
48264235Smarkfen 
48274235Smarkfen 		switch (action_table[k].tok_val) {
48284235Smarkfen 		case TOK_apply:
48294235Smarkfen 			cptr->ips_dir = SPD_RULE_FLAG_OUTBOUND;
48304235Smarkfen 			break;
48314235Smarkfen 		case TOK_permit:
48324235Smarkfen 			cptr->ips_dir = SPD_RULE_FLAG_INBOUND;
48334235Smarkfen 			break;
48344235Smarkfen 		case TOK_ipsec:
48354235Smarkfen 			if (old_style) {
48364235Smarkfen 				/* Using saddr/daddr with ipsec action. */
48374235Smarkfen 				if (!dir) {
48384235Smarkfen 					/* No direction specified */
48394235Smarkfen 					error_message(REQ_ERROR,
48404235Smarkfen 					    IPSEC_CONF_IPSEC_DIR, line_no);
48414235Smarkfen 					return (-1);
48424235Smarkfen 				}
48434235Smarkfen 				if (cptr->ips_dir == SPD_RULE_FLAG_INBOUND)
48444235Smarkfen 					/*
48454235Smarkfen 					 * Need to swap addresses if
48464235Smarkfen 					 * 'dir in' or translation to
48474235Smarkfen 					 * laddr/raddr will be incorrect.
48484235Smarkfen 					 */
48494235Smarkfen 					cptr->swap = 1;
48504235Smarkfen 			}
48514235Smarkfen 			if (!dir)
48524235Smarkfen 				cptr->ips_dir =
48534235Smarkfen 				    SPD_RULE_FLAG_INBOUND
48544235Smarkfen 				    |SPD_RULE_FLAG_OUTBOUND;
48554235Smarkfen 			break;
48564235Smarkfen 		case TOK_bypass:
485710372Sdanmcd@sun.com 		case TOK_drop:
485810372Sdanmcd@sun.com 			is_no_alg = B_TRUE;
48594235Smarkfen 			break;
48604235Smarkfen 		}
48614235Smarkfen 
48624235Smarkfen 		line_no++;
48634235Smarkfen 		/*
48644235Smarkfen 		 * Get the properties. NULL properties is not valid.
48654235Smarkfen 		 * Later checks will catch it.
48664235Smarkfen 		 */
48674235Smarkfen 		for (i = 0; act_props->ap[ap_num].prop[i]; i++, line_no++) {
48684235Smarkfen 			for (j = 0; property_table[j].string; j++) {
48694235Smarkfen 				if (strcmp(act_props->ap[ap_num].prop[i],
48704235Smarkfen 				    property_table[j].string) == 0) {
48714235Smarkfen 					break;
48724235Smarkfen 				}
48734235Smarkfen 			}
48744235Smarkfen 			if (property_table[j].string == NULL) {
48754235Smarkfen 				warnx(gettext("Invalid properties on line "
48764235Smarkfen 				    "%d: %s"),
48775120Smarkfen 				    (arg_indices[line_no] == 0) ?
48784235Smarkfen 				    1 : arg_indices[line_no],
48794235Smarkfen 				    act_props->ap[ap_num].prop[i]);
48804235Smarkfen 				return (-1);
48814235Smarkfen 			}
48824235Smarkfen 
48834235Smarkfen 			iap->iap_attr_tok[tok_count++]
48844235Smarkfen 			    = property_table[j].value;
48854235Smarkfen 
48864235Smarkfen 			switch (property_table[j].value) {
48874235Smarkfen 			case SPD_ATTR_AH_AUTH:
48884235Smarkfen 				if (ipsec_aalg) {
48894235Smarkfen 					error_message(DUP_ERROR,
48904235Smarkfen 					    IPSEC_CONF_IPSEC_AALGS, line_no);
48914235Smarkfen 					return (-1);
48924235Smarkfen 				}
48934235Smarkfen 				i++, line_no++;
48944235Smarkfen 				if (act_props->ap[ap_num].prop[i] == NULL) {
48954235Smarkfen 					error_message(BAD_ERROR,
48964235Smarkfen 					    IPSEC_CONF_IPSEC_AALGS, line_no);
48974235Smarkfen 					return (-1);
48984235Smarkfen 				}
48994235Smarkfen 				ret = parse_ipsec_alg(
49004235Smarkfen 				    act_props->ap[ap_num].prop[i],
49014235Smarkfen 				    iap, SPD_ATTR_AH_AUTH);
49024235Smarkfen 				if (ret == -2) {
49034235Smarkfen 					/* "none" - ignore */
49044235Smarkfen 					break;
49054235Smarkfen 				}
49064235Smarkfen 				if (ret != 0) {
49074235Smarkfen 					error_message(BAD_ERROR,
49084235Smarkfen 					    IPSEC_CONF_IPSEC_AALGS, line_no);
49094235Smarkfen 					return (-1);
49104235Smarkfen 				}
49114235Smarkfen 				ipsec_aalg = B_TRUE;
491210372Sdanmcd@sun.com 				auth_covered = B_TRUE;
49134235Smarkfen 				break;
49144235Smarkfen 			case SPD_ATTR_ESP_ENCR:
49154235Smarkfen 				/*
49164235Smarkfen 				 * If this option was not given
49174235Smarkfen 				 * and encr_auth_algs was given,
49184235Smarkfen 				 * we provide null-encryption.  We do the
49194235Smarkfen 				 * setting after we parse all the options.
49204235Smarkfen 				 */
49214235Smarkfen 				if (ipsec_ealg) {
49224235Smarkfen 					error_message(DUP_ERROR,
49234235Smarkfen 					    IPSEC_CONF_IPSEC_EALGS, line_no);
49244235Smarkfen 					return (-1);
49254235Smarkfen 				}
49264235Smarkfen 				i++, line_no++;
49274235Smarkfen 				if (act_props->ap[ap_num].prop[i] == NULL) {
49284235Smarkfen 					error_message(BAD_ERROR,
49294235Smarkfen 					    IPSEC_CONF_IPSEC_EALGS, line_no);
49304235Smarkfen 					return (-1);
49314235Smarkfen 				}
49324235Smarkfen 				ret = parse_ipsec_alg(
49334235Smarkfen 				    act_props->ap[ap_num].prop[i],
49344235Smarkfen 				    iap, SPD_ATTR_ESP_ENCR);
49354235Smarkfen 				if (ret == -2) {
49364235Smarkfen 					/* "none" - ignore */
49374235Smarkfen 					break;
49384235Smarkfen 				}
49394235Smarkfen 				if (ret != 0) {
49404235Smarkfen 					error_message(BAD_ERROR,
49414235Smarkfen 					    IPSEC_CONF_IPSEC_EALGS, line_no);
49424235Smarkfen 					return (-1);
49434235Smarkfen 				}
494412131Sdanmcd@opensolaris.org 				is_combined_mode =
494512131Sdanmcd@opensolaris.org 				    combined_mode(iap->iap_eencr.alg_id);
49464235Smarkfen 				ipsec_ealg = B_TRUE;
49474235Smarkfen 				break;
49484235Smarkfen 			case SPD_ATTR_ESP_AUTH:
49494235Smarkfen 				/*
49504235Smarkfen 				 * If this option was not given and encr_algs
49514235Smarkfen 				 * option was given, we still pass a default
49524235Smarkfen 				 * value in ipsc_esp_auth_algs. This is to
49534235Smarkfen 				 * encourage the use of authentication with
49544235Smarkfen 				 * ESP.
49554235Smarkfen 				 */
49564235Smarkfen 				if (ipsec_eaalg) {
49574235Smarkfen 					error_message(DUP_ERROR,
49584235Smarkfen 					    IPSEC_CONF_IPSEC_EAALGS, line_no);
49594235Smarkfen 					return (-1);
49604235Smarkfen 				}
49614235Smarkfen 				i++, line_no++;
49624235Smarkfen 				if (act_props->ap[ap_num].prop[i] == NULL) {
49634235Smarkfen 					error_message(BAD_ERROR,
49644235Smarkfen 					    IPSEC_CONF_IPSEC_EAALGS, line_no);
49654235Smarkfen 					return (-1);
49664235Smarkfen 				}
49674235Smarkfen 				ret = parse_ipsec_alg(
49684235Smarkfen 				    act_props->ap[ap_num].prop[i],
49694235Smarkfen 				    iap, SPD_ATTR_ESP_AUTH);
49704235Smarkfen 				if (ret == -2) {
49714235Smarkfen 					/* "none" - ignore */
49724235Smarkfen 					break;
49734235Smarkfen 				}
49744235Smarkfen 				if (ret != 0) {
49754235Smarkfen 					error_message(BAD_ERROR,
49764235Smarkfen 					    IPSEC_CONF_IPSEC_EAALGS, line_no);
49774235Smarkfen 					return (-1);
49784235Smarkfen 				}
49794235Smarkfen 				ipsec_eaalg = B_TRUE;
498010372Sdanmcd@sun.com 				auth_covered = B_TRUE;
49814235Smarkfen 				break;
49824235Smarkfen 			case IPS_SA:
49834235Smarkfen 				i++, line_no++;
49844235Smarkfen 				if (act_props->ap[ap_num].prop[i] == NULL) {
49854235Smarkfen 					error_message(BAD_ERROR,
49864235Smarkfen 					    IPSEC_CONF_IPSEC_SA, line_no);
49874235Smarkfen 					return (-1);
49884235Smarkfen 				}
49894235Smarkfen 
49904235Smarkfen 				if (strcmp(act_props->ap[ap_num].prop[i],
49914235Smarkfen 				    "unique") == 0) {
49924235Smarkfen 					iap->iap_attr |= SPD_APPLY_UNIQUE;
49934235Smarkfen 				} else if (strcmp(act_props->ap[ap_num].prop[i],
49944235Smarkfen 				    "shared") != 0) {
49954235Smarkfen 					/* "shared" is default. */
49964235Smarkfen 					error_message(BAD_ERROR,
49974235Smarkfen 					    IPSEC_CONF_IPSEC_SA, line_no);
49984235Smarkfen 					return (-1);
49994235Smarkfen 				}
50004235Smarkfen 
50014235Smarkfen 				break;
50024235Smarkfen 			case IPS_DIR:
50034235Smarkfen 				if (dir) {
50044235Smarkfen 					error_message(DUP_ERROR,
50054235Smarkfen 					    IPSEC_CONF_IPSEC_DIR, line_no);
50064235Smarkfen 					return (-1);
50074235Smarkfen 				}
50084235Smarkfen 				if (new_style) {
50094235Smarkfen 					error_message(BAD_ERROR,
50104235Smarkfen 					    IPSEC_CONF_IPSEC_DIR, line_no);
50114235Smarkfen 					return (-1);
50124235Smarkfen 				}
50134235Smarkfen 				old_style = B_TRUE;
50144235Smarkfen 				dir = B_TRUE;
50154235Smarkfen 				i++, line_no++;
50164235Smarkfen 				if (act_props->ap[ap_num].prop[i] == NULL) {
50174235Smarkfen 					error_message(BAD_ERROR,
50184235Smarkfen 					    IPSEC_CONF_IPSEC_DIR, line_no);
50194235Smarkfen 					return (-1);
50204235Smarkfen 				}
50214235Smarkfen 				if (strcmp(act_props->ap[ap_num].prop[i],
50224235Smarkfen 				    "out") == 0) {
50234235Smarkfen 					cptr->ips_dir = SPD_RULE_FLAG_OUTBOUND;
50244235Smarkfen 				} else if (strcmp(act_props->ap[ap_num].prop[i],
50254235Smarkfen 				    "in") == 0) {
50264235Smarkfen 					cptr->ips_dir = SPD_RULE_FLAG_INBOUND;
50274235Smarkfen 				} else {
50284235Smarkfen 					error_message(BAD_ERROR,
50295120Smarkfen 					    IPSEC_CONF_IPSEC_DIR, line_no);
50304235Smarkfen 					return (-1);
50314235Smarkfen 				}
50324235Smarkfen 				if ((cptr->ips_dir & SPD_RULE_FLAG_INBOUND) &&
50335120Smarkfen 				    iap->iap_act_tok == TOK_apply) {
50344235Smarkfen 					warnx(gettext("Direction"
50354235Smarkfen 					    " in conflict with action"));
50364235Smarkfen 					return (-1);
50374235Smarkfen 				}
50384235Smarkfen 				if ((cptr->ips_dir & SPD_RULE_FLAG_OUTBOUND) &&
50395120Smarkfen 				    iap->iap_act_tok == TOK_permit) {
50404235Smarkfen 					warnx(gettext("Direction"
50414235Smarkfen 					    "in conflict with action"));
50424235Smarkfen 					return (-1);
50434235Smarkfen 				}
50444235Smarkfen 
50454235Smarkfen 				break;
50464235Smarkfen 			}
50474235Smarkfen 		}
50484235Smarkfen 
504910824SMark.Fenwick@Sun.COM 		if (is_combined_mode) {
505010824SMark.Fenwick@Sun.COM 			if (ipsec_eaalg) {
505110824SMark.Fenwick@Sun.COM 				warnx(gettext("ERROR: Rule on line %d: "
505210824SMark.Fenwick@Sun.COM 				    "Combined mode and esp authentication not "
505310824SMark.Fenwick@Sun.COM 				    "supported together."),
505410824SMark.Fenwick@Sun.COM 				    arg_indices[line_no] == 0 ? 1 :
505510824SMark.Fenwick@Sun.COM 				    arg_indices[line_no]);
505610824SMark.Fenwick@Sun.COM 				return (-1);
505710824SMark.Fenwick@Sun.COM 			}
505810824SMark.Fenwick@Sun.COM 			auth_covered = B_TRUE;
505910824SMark.Fenwick@Sun.COM 		}
506010372Sdanmcd@sun.com 		/* Warn here about no authentication! */
506110372Sdanmcd@sun.com 		if (!auth_covered && !is_no_alg) {
506210372Sdanmcd@sun.com 			warnx(gettext("DANGER:  Rule on line %d "
506310372Sdanmcd@sun.com 			    "has encryption with no authentication."),
506410372Sdanmcd@sun.com 			    arg_indices[line_no] == 0 ? 1 :
506510372Sdanmcd@sun.com 			    arg_indices[line_no]);
506610372Sdanmcd@sun.com 		}
506710372Sdanmcd@sun.com 
50684235Smarkfen 		if (!ipsec_ealg && ipsec_eaalg) {
50694235Smarkfen 			/*
50704235Smarkfen 			 * If the user has specified the auth alg to be used
50714235Smarkfen 			 * with encryption and did not provide a encryption
50724235Smarkfen 			 * algorithm, provide null encryption.
50734235Smarkfen 			 */
50744235Smarkfen 			iap->iap_eencr.alg_id = SADB_EALG_NULL;
50754235Smarkfen 			ipsec_ealg = B_TRUE;
50764235Smarkfen 		}
50774235Smarkfen 
50784235Smarkfen 		/* Set the level of IPSEC protection we want */
50794235Smarkfen 		if (ipsec_aalg && (ipsec_ealg || ipsec_eaalg)) {
50804235Smarkfen 			iap->iap_attr |= SPD_APPLY_AH|SPD_APPLY_ESP;
50814235Smarkfen 		} else if (ipsec_aalg) {
50824235Smarkfen 			iap->iap_attr |= SPD_APPLY_AH;
50834235Smarkfen 		} else if (ipsec_ealg || ipsec_eaalg) {
50844235Smarkfen 			iap->iap_attr |= SPD_APPLY_ESP;
50854235Smarkfen 		}
50864235Smarkfen 
50874235Smarkfen 		/* convert src/dst to local/remote */
50884235Smarkfen 		if (!new_style) {
50894235Smarkfen 			switch (cptr->ips_acts->iap_act_tok) {
50904235Smarkfen 			case TOK_apply:
50914235Smarkfen 				/* outbound */
50924235Smarkfen 				/* src=local, dst=remote */
50934235Smarkfen 				/* this is ok. */
50944235Smarkfen 				break;
50954235Smarkfen 
50964235Smarkfen 			case TOK_permit:
50974235Smarkfen 				/* inbound */
50984235Smarkfen 				/* src=remote, dst=local */
50994235Smarkfen 				/* switch */
51004235Smarkfen 				cptr->swap = 1;
51014235Smarkfen 				break;
51024235Smarkfen 			case TOK_bypass:
51034235Smarkfen 			case TOK_drop:
51044235Smarkfen 				/* check the direction for what to do */
51054235Smarkfen 				if (cptr->ips_dir == SPD_RULE_FLAG_INBOUND)
51064235Smarkfen 					cptr->swap = 1;
51074235Smarkfen 				break;
51084235Smarkfen 			default:
51094235Smarkfen 				break;
51104235Smarkfen 			}
51114235Smarkfen 		}
51124235Smarkfen 		/* Validate the properties */
51134235Smarkfen 		if (ret = validate_properties(iap, dir,
51144235Smarkfen 		    (ipsec_aalg || ipsec_ealg || ipsec_eaalg))) {
51154235Smarkfen 			return (ret);
51164235Smarkfen 		}
51174235Smarkfen 	}
51184235Smarkfen 
51194235Smarkfen 	return (0);
51204235Smarkfen 
51214235Smarkfen }
51224235Smarkfen 
51234235Smarkfen static int
print_cmd_buf(FILE * fp,int error)51244235Smarkfen print_cmd_buf(FILE *fp, int error)
51254235Smarkfen {
51264235Smarkfen 	*(cbuf + cbuf_offset) = '\0';
51274235Smarkfen 
51284235Smarkfen 	if (fp == stderr) {
51294235Smarkfen 		if (error != EEXIST) {
51304235Smarkfen 			warnx(gettext("Malformed command (fatal):\n%s"), cbuf);
51314235Smarkfen 			return (0);
51324235Smarkfen 		}
51334235Smarkfen 		if (ipsecconf_qflag) {
51344235Smarkfen 			return (0);
51354235Smarkfen 		}
51364235Smarkfen 		warnx(gettext("Duplicate policy entry (ignored):\n%s"), cbuf);
51374235Smarkfen 	} else {
51384235Smarkfen 		if (fprintf(fp, "%s", cbuf) == -1) {
51394235Smarkfen 			warn("fprintf");
51404235Smarkfen 			return (-1);
51414235Smarkfen 		}
51424235Smarkfen 	}
51434235Smarkfen 
51444235Smarkfen 	return (0);
51454235Smarkfen }
51464235Smarkfen 
51474235Smarkfen #ifdef	DEBUG
51484235Smarkfen 
51494235Smarkfen static uchar_t *
addr_ptr(int isv4,struct in6_addr * addr6,struct in_addr * addr4)51504235Smarkfen addr_ptr(int isv4, struct in6_addr *addr6, struct in_addr *addr4)
51514235Smarkfen {
51524235Smarkfen 	if (isv4) {
51534235Smarkfen 		IN6_V4MAPPED_TO_INADDR(addr6, addr4);
51544235Smarkfen 		return ((uchar_t *)&addr4->s_addr);
51554235Smarkfen 	} else {
51564235Smarkfen 		return ((uchar_t *)&addr6->s6_addr);
51574235Smarkfen 	}
51584235Smarkfen }
51594235Smarkfen 
51604235Smarkfen static void
dump_algreq(const char * tag,algreq_t * alg)51614235Smarkfen dump_algreq(const char *tag, algreq_t *alg)
51624235Smarkfen {
51634235Smarkfen 	(void) printf("%s algid %d, bits %d..%d\n",
51644235Smarkfen 	    tag, alg->alg_id, alg->alg_minbits, alg->alg_maxbits);
51654235Smarkfen }
51664235Smarkfen 
51674235Smarkfen static void
dump_conf(ips_conf_t * conf)51684235Smarkfen dump_conf(ips_conf_t *conf)
51694235Smarkfen {
51704235Smarkfen 	boolean_t isv4 = conf->ips_isv4;
51714235Smarkfen 	struct in_addr addr;
51724235Smarkfen 	char buf[INET6_ADDRSTRLEN];
51734235Smarkfen 	int af;
51744235Smarkfen 	ips_act_props_t *iap = conf->ips_acts;
51754235Smarkfen 
51764235Smarkfen 	af = isv4 ? AF_INET : AF_INET6;
51774235Smarkfen 
51784235Smarkfen 	(void) printf("Source Addr is %s\n",
51794235Smarkfen 	    inet_ntop(af, addr_ptr(isv4, &conf->ips_src_addr_v6, &addr),
51805120Smarkfen 	    buf, INET6_ADDRSTRLEN));
51814235Smarkfen 
51824235Smarkfen 	(void) printf("Dest Addr is %s\n",
51834235Smarkfen 	    inet_ntop(af, addr_ptr(isv4, &conf->ips_dst_addr_v6, &addr),
51845120Smarkfen 	    buf, INET6_ADDRSTRLEN));
51854235Smarkfen 
51864235Smarkfen 	(void) printf("Source Mask is %s\n",
51874235Smarkfen 	    inet_ntop(af, addr_ptr(isv4, &conf->ips_src_mask_v6, &addr),
51885120Smarkfen 	    buf, INET6_ADDRSTRLEN));
51894235Smarkfen 
51904235Smarkfen 	(void) printf("Dest Mask is %s\n",
51914235Smarkfen 	    inet_ntop(af, addr_ptr(isv4, &conf->ips_dst_mask_v6, &addr),
51925120Smarkfen 	    buf, INET6_ADDRSTRLEN));
51934235Smarkfen 
51944235Smarkfen 	(void) printf("Source port %d\n", ntohs(conf->ips_src_port_min));
51954235Smarkfen 	(void) printf("Dest port %d\n", ntohs(conf->ips_dst_port_min));
51964235Smarkfen 	(void) printf("ULP %d\n", conf->ips_ulp_prot);
51974235Smarkfen 
51984235Smarkfen 	(void) printf("ICMP type %d-%d code %d-%d", conf->ips_icmp_type,
51994235Smarkfen 	    conf->ips_icmp_type_end,
52004235Smarkfen 	    conf->ips_icmp_code,
52014235Smarkfen 	    conf->ips_icmp_code_end);
52024235Smarkfen 
52034235Smarkfen 	while (iap != NULL) {
52044235Smarkfen 		(void) printf("------------------------------------\n");
52054235Smarkfen 		(void) printf("IPsec act is %d\n", iap->iap_action);
52064235Smarkfen 		(void) printf("IPsec attr is %d\n", iap->iap_attr);
52074235Smarkfen 		dump_algreq("AH authentication", &iap->iap_aauth);
52084235Smarkfen 		dump_algreq("ESP authentication", &iap->iap_eauth);
52094235Smarkfen 		dump_algreq("ESP encryption", &iap->iap_eencr);
52104235Smarkfen 		(void) printf("------------------------------------\n");
52114235Smarkfen 		iap = iap->iap_next;
52124235Smarkfen 	}
52134235Smarkfen 
52144235Smarkfen 	(void) fflush(stdout);
52154235Smarkfen }
52164235Smarkfen #endif	/* DEBUG */
52174235Smarkfen 
52184235Smarkfen 
52194235Smarkfen static int
ipsec_conf_add(boolean_t just_check,boolean_t smf_managed,boolean_t replace)522011278SMark.Fenwick@Sun.COM ipsec_conf_add(boolean_t just_check, boolean_t smf_managed, boolean_t replace)
52214235Smarkfen {
52224235Smarkfen 	act_prop_t *act_props = malloc(sizeof (act_prop_t));
52234235Smarkfen 	ips_conf_t conf;
52244235Smarkfen 	FILE *fp, *policy_fp;
52254235Smarkfen 	int ret, flushret, i, j, diag, num_rules, good_rules;
52264235Smarkfen 	char *warning = gettext(
52275120Smarkfen 	    "\tWARNING : New policy entries that are being added may\n "
52285120Smarkfen 	    "\taffect the existing connections. Existing connections\n"
52295120Smarkfen 	    "\tthat are not subjected to policy constraints, may be\n"
52305120Smarkfen 	    "\tsubjected to policy constraints because of the new\n"
52315120Smarkfen 	    "\tpolicy. This can disrupt the communication of the\n"
52325120Smarkfen 	    "\texisting connections.\n\n");
52334235Smarkfen 
52344235Smarkfen 	boolean_t first_time = B_TRUE;
52354235Smarkfen 	num_rules = 0;
52364235Smarkfen 	good_rules = 0;
52374235Smarkfen 
52384235Smarkfen 	if (act_props == NULL) {
52394235Smarkfen 		warn(gettext("memory"));
52404235Smarkfen 		return (-1);
52414235Smarkfen 	}
52424235Smarkfen 
52434235Smarkfen 	if (strcmp(filename, "-") == 0)
52444235Smarkfen 		fp = stdin;
52454235Smarkfen 	else
52464235Smarkfen 		fp = fopen(filename, "r");
52474235Smarkfen 
52484235Smarkfen 	/*
52494235Smarkfen 	 * Treat the non-existence of a policy file as a special
52504235Smarkfen 	 * case when ipsecconf is being managed by smf(5).
52514235Smarkfen 	 * The assumption is the administrator has not yet
52524235Smarkfen 	 * created a policy file, this should not force the service
52534235Smarkfen 	 * into maintenance mode.
52544235Smarkfen 	 */
52554235Smarkfen 
52564235Smarkfen 	if (fp == NULL) {
52574235Smarkfen 		if (smf_managed) {
52584235Smarkfen 			(void) fprintf(stdout, gettext(
52594235Smarkfen 			    "Policy configuration file (%s) does not exist.\n"
52604235Smarkfen 			    "IPsec policy not configured.\n"), filename);
52614235Smarkfen 			return (0);
52624235Smarkfen 		}
52634235Smarkfen 		warn(gettext("%s : Policy config file cannot be opened"),
52644235Smarkfen 		    filename);
52654235Smarkfen 		usage();
52664235Smarkfen 		return (-1);
52674235Smarkfen 	}
52684235Smarkfen 	/*
52694235Smarkfen 	 * This will create the file if it does not exist.
52704235Smarkfen 	 * Make sure the umask is right.
52714235Smarkfen 	 */
52724235Smarkfen 	(void) umask(0022);
52734235Smarkfen 	policy_fp = fopen(POLICY_CONF_FILE, "a");
52744235Smarkfen 	if (policy_fp == NULL) {
52754235Smarkfen 		warn(gettext("%s cannot be opened"), POLICY_CONF_FILE);
52764235Smarkfen 		return (-1);
52774235Smarkfen 	}
52784235Smarkfen 
52794235Smarkfen 	/*
52804235Smarkfen 	 * Pattern, action, and properties are allocated in
52814235Smarkfen 	 * parse_pattern_or_prop and in parse_action (called by
52824235Smarkfen 	 * parse_one) as we parse arguments.
52834235Smarkfen 	 */
52845120Smarkfen 	while ((ret = parse_one(fp, act_props)) != PARSE_EOF) {
52855120Smarkfen 		num_rules++;
52865120Smarkfen 		if (ret != 0) {
52875120Smarkfen 			(void) print_cmd_buf(stderr, NOERROR);
52885120Smarkfen 			continue;
52895120Smarkfen 		}
52904235Smarkfen 
52914235Smarkfen 		/*
52924235Smarkfen 		 * If there is no action and parse returned success,
52934235Smarkfen 		 * it means that there is nothing to add.
52944235Smarkfen 		 */
52954235Smarkfen 		if (act_props->pattern[0] == NULL &&
52964235Smarkfen 		    act_props->ap[0].act == NULL)
52974235Smarkfen 				break;
52984235Smarkfen 
52994235Smarkfen 		ret = form_ipsec_conf(act_props, &conf);
53004235Smarkfen 		if (ret != 0) {
53014235Smarkfen 			warnx(gettext("form_ipsec_conf error"));
53024235Smarkfen 			(void) print_cmd_buf(stderr, NOERROR);
53034475Spwernau 			/* Reset globals before trying the next rule. */
53044475Spwernau 			if (shp != NULL) {
53054475Spwernau 				freehostent(shp);
53064475Spwernau 				shp = NULL;
53074475Spwernau 			}
53084475Spwernau 			if (dhp != NULL) {
53094475Spwernau 				freehostent(dhp);
53104475Spwernau 				dhp = NULL;
53114475Spwernau 			}
53124475Spwernau 			splen = 0;
53134475Spwernau 			dplen = 0;
53144235Smarkfen 			continue;
53154235Smarkfen 		}
53164235Smarkfen 
53174235Smarkfen 		good_rules++;
53184235Smarkfen 
53194235Smarkfen 		if (first_time) {
53204235Smarkfen 			/*
53214235Smarkfen 			 * Time to assume that there are valid policy entries.
53224235Smarkfen 			 * If the IPsec kernel modules are not loaded this
53234235Smarkfen 			 * will load them now.
53244235Smarkfen 			 */
53254235Smarkfen 			first_time = B_FALSE;
53264235Smarkfen 			fetch_algorithms();
53274235Smarkfen 			ipsec_conf_admin(SPD_CLONE);
532811278SMark.Fenwick@Sun.COM 
532911278SMark.Fenwick@Sun.COM 			/*
533011278SMark.Fenwick@Sun.COM 			 * The default behaviour for IPSEC_CONF_ADD is to append
533111278SMark.Fenwick@Sun.COM 			 * the new rules to the existing policy. If a new rule
533211278SMark.Fenwick@Sun.COM 			 * collides with an existing rule, the new rule won't be
533311278SMark.Fenwick@Sun.COM 			 * added.
533411278SMark.Fenwick@Sun.COM 			 *
533511278SMark.Fenwick@Sun.COM 			 * To perform an atomic policy replace, we really don't
533611278SMark.Fenwick@Sun.COM 			 * care what the existing policy was, just replace it
533711278SMark.Fenwick@Sun.COM 			 * with the new one. Remove all rules from the SPD_CLONE
533811278SMark.Fenwick@Sun.COM 			 * policy before checking the new rules.
533911278SMark.Fenwick@Sun.COM 			 */
534011278SMark.Fenwick@Sun.COM 			if (replace) {
534111278SMark.Fenwick@Sun.COM 				flushret = ipsec_conf_flush(SPD_STANDBY);
534211278SMark.Fenwick@Sun.COM 				if (flushret != 0)
534311278SMark.Fenwick@Sun.COM 					return (flushret);
534411278SMark.Fenwick@Sun.COM 			}
53454235Smarkfen 		}
53464235Smarkfen 
53474235Smarkfen 		/*
53484235Smarkfen 		 * shp, dhp, splen, and dplen are globals set by
53494235Smarkfen 		 * form_ipsec_conf() while parsing the addresses.
53504235Smarkfen 		 */
53514235Smarkfen 		if (shp == NULL && dhp == NULL) {
53524235Smarkfen 			switch (do_port_adds(&conf)) {
53534235Smarkfen 			case 0:
53544235Smarkfen 				/* no error */
53554235Smarkfen 				break;
53564235Smarkfen 			case EEXIST:
53574235Smarkfen 				/* duplicate entries, continue adds */
53584235Smarkfen 				(void) print_cmd_buf(stderr, EEXIST);
53594235Smarkfen 				goto next;
53604235Smarkfen 			default:
53614235Smarkfen 				/* other error, bail */
53624235Smarkfen 				ret = -1;
53634235Smarkfen 				goto bail;
53644235Smarkfen 			}
53654235Smarkfen 		} else {
53664235Smarkfen 			ret = do_address_adds(&conf, &diag);
53674235Smarkfen 			switch (ret) {
53684235Smarkfen 			case 0:
53694235Smarkfen 				/* no error. */
53704235Smarkfen 				break;
53714235Smarkfen 			case EEXIST:
53724235Smarkfen 				(void) print_cmd_buf(stderr, EEXIST);
53734235Smarkfen 				goto next;
53744235Smarkfen 			case EBUSY:
53754235Smarkfen 				warnx(gettext(
53765120Smarkfen 				    "Can't set mask and /NN prefix."));
53774235Smarkfen 				ret = -1;
53784235Smarkfen 				break;
53794235Smarkfen 			case ENOENT:
53804235Smarkfen 				warnx(gettext("Cannot find tunnel "
53814235Smarkfen 				    "interface %s."), interface_name);
53824235Smarkfen 				ret = -1;
53834235Smarkfen 				break;
53844235Smarkfen 			case EINVAL:
53854235Smarkfen 				/*
53864235Smarkfen 				 * PF_POLICY didn't like what we sent.  We
53874235Smarkfen 				 * can't check all input up here, but we
53884235Smarkfen 				 * do in-kernel.
53894235Smarkfen 				 */
53904235Smarkfen 				warnx(gettext("PF_POLICY invalid input:\n\t%s"),
53914235Smarkfen 				    spdsock_diag(diag));
53924235Smarkfen 				break;
53934235Smarkfen 			case EOPNOTSUPP:
53944235Smarkfen 				warnx(gettext("Can't set /NN"
53955120Smarkfen 				    " prefix on multi-host name."));
53964235Smarkfen 				ret = -1;
53974235Smarkfen 				break;
53984235Smarkfen 			case ERANGE:
53994235Smarkfen 				warnx(gettext("/NN prefix is too big!"));
54004235Smarkfen 				ret = -1;
54014235Smarkfen 				break;
54024235Smarkfen 			case ESRCH:
54034235Smarkfen 				warnx(gettext("No matching IPv4 or "
54045120Smarkfen 				    "IPv6 saddr/daddr pairs"));
54054235Smarkfen 				ret = -1;
54064235Smarkfen 				break;
54074235Smarkfen 			default:
54084235Smarkfen 				/* Should never get here. */
54094235Smarkfen 				errno = ret;
54104235Smarkfen 				warn(gettext("Misc. error"));
54114235Smarkfen 				ret = -1;
54124235Smarkfen 			}
54134235Smarkfen 			if (ret == -1)
54144235Smarkfen 				goto bail;
54154235Smarkfen 		}
54164235Smarkfen 
54174235Smarkfen 		/*
54184235Smarkfen 		 * Go ahead and add policy entries to config file.
54194235Smarkfen 		 * The # should help re-using the ipsecpolicy.conf
54204235Smarkfen 		 * for input again as # will be treated as comment.
54214235Smarkfen 		 */
54224235Smarkfen 		if (fprintf(policy_fp, "%s %lld \n", INDEX_TAG,
54234235Smarkfen 		    conf.ips_policy_index) == -1) {
54244235Smarkfen 			warn("fprintf");
54254235Smarkfen 			warnx(gettext("Addition incomplete, Please "
54264235Smarkfen 			    "flush all the entries and re-configure :"));
54274235Smarkfen 			reconfigure();
54284235Smarkfen 			ret = -1;
54294235Smarkfen 			break;
54304235Smarkfen 		}
54314235Smarkfen 		if (print_cmd_buf(policy_fp, NOERROR) == -1) {
54324235Smarkfen 			warnx(gettext("Addition incomplete. Please "
54334235Smarkfen 			    "flush all the entries and re-configure :"));
54344235Smarkfen 			reconfigure();
54354235Smarkfen 			ret = -1;
54364235Smarkfen 			break;
54374235Smarkfen 		}
54384235Smarkfen 		/*
54394235Smarkfen 		 * We add one newline by default to separate out the
54404235Smarkfen 		 * entries. If the last character is not a newline, we
54414235Smarkfen 		 * insert a newline for free. This makes sure that all
54424235Smarkfen 		 * entries look consistent in the file.
54434235Smarkfen 		 */
54444235Smarkfen 		if (*(cbuf + cbuf_offset - 1) == '\n') {
54454235Smarkfen 			if (fprintf(policy_fp, "\n") == -1) {
54464235Smarkfen 				warn("fprintf");
54474235Smarkfen 				warnx(gettext("Addition incomplete. "
54484235Smarkfen 				    "Please flush all the entries and "
54494235Smarkfen 				    "re-configure :"));
54504235Smarkfen 				reconfigure();
54514235Smarkfen 				ret = -1;
54524235Smarkfen 				break;
54534235Smarkfen 			}
54544235Smarkfen 		} else {
54554235Smarkfen 			if (fprintf(policy_fp, "\n\n") == -1) {
54564235Smarkfen 				warn("fprintf");
54574235Smarkfen 				warnx(gettext("Addition incomplete. "
54584235Smarkfen 				    "Please flush all the entries and "
54594235Smarkfen 				    "re-configure :"));
54604235Smarkfen 				reconfigure();
54614235Smarkfen 				ret = -1;
54624235Smarkfen 				break;
54634235Smarkfen 			}
54644235Smarkfen 		}
54654235Smarkfen next:
54664235Smarkfen 		/*
54674235Smarkfen 		 * Make sure this gets to the disk before
54684235Smarkfen 		 * we parse the next entry.
54694235Smarkfen 		 */
54704235Smarkfen 		(void) fflush(policy_fp);
54714235Smarkfen 		for (i = 0; act_props->pattern[i] != NULL; i++)
54724235Smarkfen 			free(act_props->pattern[i]);
54734235Smarkfen 		for (j = 0; act_props->ap[j].act != NULL; j++) {
54744235Smarkfen 			free(act_props->ap[j].act);
54754235Smarkfen 			for (i = 0; act_props->ap[j].prop[i] != NULL; i++)
54764235Smarkfen 				free(act_props->ap[j].prop[i]);
54774235Smarkfen 		}
54784235Smarkfen 	}
54795120Smarkfen 	if (ret == PARSE_EOF)
54805120Smarkfen 		ret = 0; /* Not an error */
54814235Smarkfen bail:
54824235Smarkfen 	if (ret == -1) {
54834235Smarkfen 		(void) print_cmd_buf(stderr, EINVAL);
54844235Smarkfen 		for (i = 0; act_props->pattern[i] != NULL; i++)
54854235Smarkfen 			free(act_props->pattern[i]);
54864235Smarkfen 		for (j = 0; act_props->ap[j].act != NULL; j++) {
54874235Smarkfen 			free(act_props->ap[j].act);
54884235Smarkfen 			for (i = 0; act_props->ap[j].prop[i] != NULL; i++)
54894235Smarkfen 				free(act_props->ap[j].prop[i]);
54904235Smarkfen 		}
54914235Smarkfen 	}
54924235Smarkfen #ifdef DEBUG_HEAVY
54934235Smarkfen 	(void) printf("ipsec_conf_add: ret val = %d\n", ret);
54944235Smarkfen 	(void) fflush(stdout);
54954235Smarkfen #endif
54965120Smarkfen 	if (num_rules == 0 && ret == 0) {
54974475Spwernau 		nuke_adds();
54984235Smarkfen 		(void) restore_all_signals();
54994235Smarkfen 		(void) unlock(lfd);
55004235Smarkfen 		EXIT_OK("Policy file does not contain any valid rules.");
55014235Smarkfen 	}
55024235Smarkfen 	if (num_rules != good_rules) {
55034235Smarkfen 		/* This is an error */
55044475Spwernau 		nuke_adds();
55054235Smarkfen 		(void) restore_all_signals();
55064235Smarkfen 		(void) unlock(lfd);
55074235Smarkfen 		EXIT_BADCONFIG2("%d policy rule(s) contained errors.",
55084235Smarkfen 		    num_rules - good_rules);
55094235Smarkfen 	}
55104235Smarkfen 	/* looks good, flip it in */
55114235Smarkfen 	if (ret == 0 && !just_check) {
55124235Smarkfen 		if (!ipsecconf_qflag) {
55134235Smarkfen 			(void) printf("%s", warning);
55144235Smarkfen 		}
55155120Smarkfen 		if (smf_managed)
55165120Smarkfen 			warnx(gettext("%d policy rules added."), good_rules);
55174235Smarkfen 		ipsec_conf_admin(SPD_FLIP);
55184235Smarkfen 	} else {
55194235Smarkfen 		nuke_adds();
55204235Smarkfen 		if (just_check) {
55215120Smarkfen 			(void) fprintf(stdout, gettext("IPsec configuration "
55225120Smarkfen 			    "does not contain any errors.\n"));
55234235Smarkfen 			(void) fprintf(stdout, gettext(
55244235Smarkfen 			    "IPsec policy was not modified.\n"));
55254235Smarkfen 			(void) fflush(stdout);
55264235Smarkfen 		}
55274235Smarkfen 	}
55284235Smarkfen 	flushret = ipsec_conf_flush(SPD_STANDBY);
55294235Smarkfen 	if (flushret != 0)
55304235Smarkfen 		return (flushret);
55314235Smarkfen 	return (ret);
55324235Smarkfen }
55334235Smarkfen 
55344235Smarkfen 
55354235Smarkfen static int
ipsec_conf_sub()55364235Smarkfen ipsec_conf_sub()
55374235Smarkfen {
55384235Smarkfen 	act_prop_t *act_props = malloc(sizeof (act_prop_t));
55394235Smarkfen 	FILE *remove_fp, *policy_fp;
55404235Smarkfen 	char rbuf[MAXLEN], pbuf[MAXLEN], /* remove buffer, and policy buffer */
55414235Smarkfen 	    *warning = gettext(
55425120Smarkfen 	    "\tWARNING: Policy entries that are being removed may\n"
55435120Smarkfen 	    "\taffect the existing connections.  Existing connections\n"
55445120Smarkfen 	    "\tthat are subjected to policy constraints may no longer\n"
55455120Smarkfen 	    "\tbe subjected to policy contraints because of its\n"
55465120Smarkfen 	    "\tremoval.  This can compromise security, and disrupt\n"
55475120Smarkfen 	    "\tthe communication of the existing connection.\n"
55485120Smarkfen 	    "\tConnections that are latched will remain unaffected\n"
55495120Smarkfen 	    "\tuntil they close.\n");
55504235Smarkfen 	int ret = 0;
55514235Smarkfen 	int index_len, pindex = 0; /* init value in case of pfile error */
55524235Smarkfen 
55534235Smarkfen 	if (act_props == NULL) {
55544235Smarkfen 		warn(gettext("memory"));
55554235Smarkfen 		return (-1);
55564235Smarkfen 	}
55574235Smarkfen 
55584235Smarkfen 	/* clone into standby DB */
55594235Smarkfen 	(void) ipsec_conf_admin(SPD_CLONE);
55604235Smarkfen 
55614235Smarkfen 	if (strcmp(filename, "-") == 0)
55624235Smarkfen 		remove_fp = stdin;
55634235Smarkfen 	else
55644235Smarkfen 		remove_fp = fopen(filename, "r");
55654235Smarkfen 
55664235Smarkfen 	if (remove_fp == NULL) {
55674235Smarkfen 		warn(gettext("%s : Input file cannot be opened"), filename);
55684235Smarkfen 		usage();
55694235Smarkfen 		free(act_props);
55704235Smarkfen 		return (-1);
55714235Smarkfen 	}
55724235Smarkfen 
55734235Smarkfen 	/* open policy file so we can locate the correct policy */
55744235Smarkfen 	(void) umask(0022);  /* in case it gets created! */
55754235Smarkfen 	policy_fp = fopen(POLICY_CONF_FILE, "r+");
55764235Smarkfen 	if (policy_fp == NULL) {
55774235Smarkfen 		warn(gettext("%s cannot be opened"), POLICY_CONF_FILE);
55784235Smarkfen 		(void) fclose(remove_fp);
55794235Smarkfen 		free(act_props);
55804235Smarkfen 		return (-1);
55814235Smarkfen 	}
55824235Smarkfen 
55834235Smarkfen 	/* don't print the warning if we're in q[uiet] mode */
55844235Smarkfen 	if (!ipsecconf_qflag)
55854235Smarkfen 		(void) printf("%s", warning);
55864235Smarkfen 
55874235Smarkfen 	/* this bit is done primarily so we can read what we write */
55884235Smarkfen 	index_len = strlen(INDEX_TAG);
55894235Smarkfen 
55904235Smarkfen 	/*
55914235Smarkfen 	 * We want to look for the policy in rbuf in the policy file.
55924235Smarkfen 	 * Go through the list of policies to remove, locating each one.
55934235Smarkfen 	 */
55944235Smarkfen 	while (fgets(rbuf, MAXLEN, remove_fp) != NULL) {
55954235Smarkfen 		char *buf;
55964235Smarkfen 		int offset, prev_offset, prev_prev_offset, nlines;
55974235Smarkfen 		fpos_t ipos;
55984235Smarkfen 		int pbuf_len = 0;
55994235Smarkfen 		char *tmp;
56004235Smarkfen 		/* skip blanks here (so we don't need to do it below)! */
56015120Smarkfen 		for (tmp = rbuf; (*tmp != '\0') && isspace(*tmp); )
56025120Smarkfen 			tmp++;
56035120Smarkfen 
56044235Smarkfen 		if (*tmp == '\0')
56055120Smarkfen 			continue; /* while(); */
56064235Smarkfen 
56074235Smarkfen 		/* skip the INDEX_TAG lines in the remove buffer */
56084235Smarkfen 		if (strncasecmp(rbuf, INDEX_TAG, index_len) == 0)
56094235Smarkfen 			continue;
56104235Smarkfen 
56114235Smarkfen 		/* skip commented lines */
56124235Smarkfen 		if (*tmp == '#')
56135120Smarkfen 			continue; /* while(); */
56144235Smarkfen 
56154235Smarkfen 		/*
56164235Smarkfen 		 * We start by presuming only good policies are in the pfile,
56174235Smarkfen 		 * and so only good policies from the rfile will match them.
56184235Smarkfen 		 * ipsec_conf_del ensures this later by calling parse_one() on
56194235Smarkfen 		 * pfile before it deletes the entry.
56204235Smarkfen 		 */
56214235Smarkfen 		for (offset = prev_offset = prev_prev_offset = 0;
56224235Smarkfen 		    fgets(pbuf, MAXLEN, policy_fp) != NULL;
56234235Smarkfen 		    offset += pbuf_len) {
56244235Smarkfen 			prev_offset = offset;
56254235Smarkfen 			pbuf_len = strlen(pbuf);
56264235Smarkfen 
56274235Smarkfen 			/* skip blank lines which seperate policy entries */
56284235Smarkfen 			if (pbuf[0] == '\n')
56294235Smarkfen 				continue;
56304235Smarkfen 
56314235Smarkfen 			/* if we found an index, save it */
56324235Smarkfen 			if (strncasecmp(pbuf, INDEX_TAG, index_len) == 0) {
56334235Smarkfen 				buf = pbuf + index_len;
56344235Smarkfen 				buf++;
56354235Smarkfen 				if ((pindex = parse_index(buf, NULL)) == -1) {
56364235Smarkfen 					/* bad index, we can't continue */
56374235Smarkfen 					warnx(gettext(
56385120Smarkfen 					    "Invalid index in the file"));
56394235Smarkfen 					(void) fclose(remove_fp);
56404235Smarkfen 					(void) fclose(policy_fp);
56414235Smarkfen 					free(act_props);
56424235Smarkfen 					return (-1);
56434235Smarkfen 				}
56444235Smarkfen 
56454235Smarkfen 				/* save this position in case it's the one */
56464235Smarkfen 				if (fgetpos(policy_fp, &ipos) != 0) {
56474235Smarkfen 					(void) fclose(remove_fp);
56484235Smarkfen 					(void) fclose(policy_fp);
56494235Smarkfen 					free(act_props);
56504235Smarkfen 					return (-1);
56514235Smarkfen 				}
56524235Smarkfen 			}
56534235Smarkfen 
56544235Smarkfen 			/* Does pbuf contain the remove policy? */
56554235Smarkfen 			if (strncasecmp(rbuf, pbuf, pbuf_len) == 0) {
56564235Smarkfen 				/* we found the one to remove! */
56574235Smarkfen 				if (pindex == 0) {
56584235Smarkfen 					warnx(gettext("Didn't find a valid "
56594235Smarkfen 					    "index for policy"));
56604235Smarkfen 					(void) fclose(remove_fp);
56614235Smarkfen 					(void) fclose(policy_fp);
56624235Smarkfen 					free(act_props);
56634235Smarkfen 					return (-1);
56644235Smarkfen 				}
56654235Smarkfen 
56664235Smarkfen 				/* off it - back up to the last INDEX! */
56674235Smarkfen 				if (fsetpos(policy_fp, &ipos) != 0) {
56684235Smarkfen 					(void) fclose(remove_fp);
56694235Smarkfen 					(void) fclose(policy_fp);
56704235Smarkfen 					free(act_props);
56714235Smarkfen 					return (-1);
56724235Smarkfen 				}
56734235Smarkfen 
56744235Smarkfen 				/* parse_one sets linecount = #lines to off */
56754235Smarkfen 				if (parse_one(policy_fp, act_props) == -1) {
56764235Smarkfen 					warnx(gettext("Invalid policy entry "
56774235Smarkfen 					    "in the file"));
56784235Smarkfen 					(void) fclose(remove_fp);
56794235Smarkfen 					(void) fclose(policy_fp);
56804235Smarkfen 					free(act_props);
56814235Smarkfen 					return (-1);
56824235Smarkfen 				}
56834235Smarkfen 
56844235Smarkfen 				nlines = linecount + 2;
56854235Smarkfen 				goto delete;
56864235Smarkfen 			}
56874235Smarkfen 			/*
56884235Smarkfen 			 * When we find a match, we want to pass the offset
56894235Smarkfen 			 * of the line that is before it - the INDEX_TAG line.
56904235Smarkfen 			 */
56914235Smarkfen 			prev_prev_offset = prev_offset;
56924235Smarkfen 		}
56934235Smarkfen 		/* Didn't find a match - look at the next remove policy */
56945120Smarkfen 		continue; /* while(); */
56954235Smarkfen 
56964235Smarkfen delete:
56974235Smarkfen 		(void) fclose(policy_fp);
56984235Smarkfen 
56994235Smarkfen 		if (delete_from_file(prev_prev_offset, nlines) != 0) {
57004235Smarkfen 			warnx(gettext("delete_from_file failure.  "
57014235Smarkfen 			    "Please flush all entries and re-configure :"));
57024235Smarkfen 			reconfigure();
57034235Smarkfen 			(void) fclose(remove_fp);
57044235Smarkfen 			free(act_props);
57054235Smarkfen 			return (-1);
57064235Smarkfen 		}
57074235Smarkfen 
57084235Smarkfen 		if (pfp_delete_rule(pindex) != 0) {
57094235Smarkfen 			warnx(gettext("Deletion incomplete. Please flush"
57104235Smarkfen 			    "all the entries and re-configure :"));
57114235Smarkfen 			reconfigure();
57124235Smarkfen 			(void) fclose(remove_fp);
57134235Smarkfen 			free(act_props);
57144235Smarkfen 			return (-1);
57154235Smarkfen 		}
57164235Smarkfen 
57174235Smarkfen 		/* reset the globals */
57184235Smarkfen 		linecount = 0;
57194235Smarkfen 		pindex = 0;
57204235Smarkfen 		/* free(NULL) also works. */
57214235Smarkfen 		free(interface_name);
57224235Smarkfen 		interface_name = NULL;
57234235Smarkfen 
57244235Smarkfen 		/* reopen for next pass, automagically starting over. */
57254235Smarkfen 		policy_fp = fopen(POLICY_CONF_FILE, "r");
57264235Smarkfen 		if (policy_fp == NULL) {
57274235Smarkfen 			warn(gettext("%s cannot be re-opened, can't continue"),
57284235Smarkfen 			    POLICY_CONF_FILE);
57294235Smarkfen 			(void) fclose(remove_fp);
57304235Smarkfen 			free(act_props);
57314235Smarkfen 			return (-1);
57324235Smarkfen 		}
57334235Smarkfen 
57344235Smarkfen 	} /* read next remove policy */
57354235Smarkfen 
57364235Smarkfen 	if ((ret = pfp_delete_rule(pindex)) != 0) {
57374235Smarkfen 		warnx(gettext("Removal incomplete.  Please flush "
57384235Smarkfen 		    "all the entries and re-configure :"));
57394235Smarkfen 		reconfigure();
57404235Smarkfen 		free(act_props);
57414235Smarkfen 		return (ret);
57424235Smarkfen 	}
57434235Smarkfen 
57444235Smarkfen 	/* nothing left to look for */
57454235Smarkfen 	(void) fclose(remove_fp);
57464235Smarkfen 	free(act_props);
57474235Smarkfen 
57484235Smarkfen 	return (0);
57494235Smarkfen }
57504235Smarkfen 
57514235Smarkfen /*
57524235Smarkfen  * Constructs a tunnel interface ID extension.  Returns the length
57534235Smarkfen  * of the extension in 64-bit-words.
57544235Smarkfen  */
57554235Smarkfen static int
attach_tunname(spd_if_t * tunname)57564235Smarkfen attach_tunname(spd_if_t *tunname)
57574235Smarkfen {
57584235Smarkfen 	if (tunname == NULL || interface_name == NULL)
57594235Smarkfen 		return (0);
57604235Smarkfen 
57614235Smarkfen 	tunname->spd_if_exttype = SPD_EXT_TUN_NAME;
57624235Smarkfen 	/*
57634235Smarkfen 	 * Use "-3" because there's 4 bytes in the message itself, and
57644235Smarkfen 	 * we lose one because of the '\0' terminator.
57654235Smarkfen 	 */
57664235Smarkfen 	tunname->spd_if_len = SPD_8TO64(
57674235Smarkfen 	    P2ROUNDUP(sizeof (*tunname) + strlen(interface_name) - 3, 8));
57684235Smarkfen 	(void) strlcpy((char *)tunname->spd_if_name, interface_name, LIFNAMSIZ);
57694235Smarkfen 	return (tunname->spd_if_len);
57704235Smarkfen }
5771