xref: /illumos-gate/usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/ipsecconf.c (revision 3abcb969a84282d264ee4b135cd8e228b9a21415)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
592913378Spwernau  * Common Development and Distribution License (the "License").
692913378Spwernau  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22e3320f40Smarkfen  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <stdio.h>
297c478bd9Sstevel@tonic-gate #include <sys/types.h>
307c478bd9Sstevel@tonic-gate #include <sys/stat.h>
317c478bd9Sstevel@tonic-gate #include <strings.h>
327c478bd9Sstevel@tonic-gate #include <stropts.h>
337c478bd9Sstevel@tonic-gate #include <fcntl.h>
347c478bd9Sstevel@tonic-gate #include <stdlib.h>
357c478bd9Sstevel@tonic-gate #include <unistd.h>
367c478bd9Sstevel@tonic-gate #include <string.h>
377c478bd9Sstevel@tonic-gate #include <ctype.h>
387c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
397c478bd9Sstevel@tonic-gate #include <locale.h>
407c478bd9Sstevel@tonic-gate #include <syslog.h>
417c478bd9Sstevel@tonic-gate #include <pwd.h>
427c478bd9Sstevel@tonic-gate #include <sys/param.h>
437c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>	/* MIN, MAX */
447c478bd9Sstevel@tonic-gate #include <sys/sockio.h>
457c478bd9Sstevel@tonic-gate #include <net/pfkeyv2.h>
467c478bd9Sstevel@tonic-gate #include <net/pfpolicy.h>
477c478bd9Sstevel@tonic-gate #include <inet/ipsec_impl.h>
487c478bd9Sstevel@tonic-gate #include <signal.h>
497c478bd9Sstevel@tonic-gate #include <errno.h>
507c478bd9Sstevel@tonic-gate #include <netdb.h>
517c478bd9Sstevel@tonic-gate #include <sys/socket.h>
527c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h>
537c478bd9Sstevel@tonic-gate #include <nss_dbdefs.h>					/* NSS_BUFLEN_HOSTS */
547c478bd9Sstevel@tonic-gate #include <netinet/in.h>
557c478bd9Sstevel@tonic-gate #include <assert.h>
567c478bd9Sstevel@tonic-gate #include <inet/ip.h>
577c478bd9Sstevel@tonic-gate #include <ipsec_util.h>
587c478bd9Sstevel@tonic-gate #include <netinet/in_systm.h>
597c478bd9Sstevel@tonic-gate #include <netinet/ip_icmp.h>
607c478bd9Sstevel@tonic-gate #include <netinet/icmp6.h>
617c478bd9Sstevel@tonic-gate 
62e3320f40Smarkfen /*
63e3320f40Smarkfen  * Globals
64e3320f40Smarkfen  */
65e3320f40Smarkfen int lfd;
66e3320f40Smarkfen char *my_fmri;
67e3320f40Smarkfen FILE *debugfile = stderr;
68e3320f40Smarkfen 
69e3320f40Smarkfen #define	USAGE() if (!smf_managed) usage()
707c478bd9Sstevel@tonic-gate /*
717c478bd9Sstevel@tonic-gate  * Buffer length to read in pattern/properties.
727c478bd9Sstevel@tonic-gate  */
737c478bd9Sstevel@tonic-gate #define	MAXLEN			1024
747c478bd9Sstevel@tonic-gate 
758810c16bSdanmcd /* Max length of tunnel interface string identifier */
768810c16bSdanmcd #define	TUNNAMEMAXLEN		LIFNAMSIZ
778810c16bSdanmcd 
787c478bd9Sstevel@tonic-gate /*
797c478bd9Sstevel@tonic-gate  * Used by parse_one and parse/parse_action to communicate
807c478bd9Sstevel@tonic-gate  * the errors. -1 is failure, which is not defined here.
817c478bd9Sstevel@tonic-gate  */
827c478bd9Sstevel@tonic-gate enum parse_errors {PARSE_SUCCESS, PARSE_EOF};
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate /*
857c478bd9Sstevel@tonic-gate  * For spdsock_get_ext() diagnostics.
867c478bd9Sstevel@tonic-gate  */
877c478bd9Sstevel@tonic-gate #define	SPDSOCK_DIAG_BUF_LEN	128
887c478bd9Sstevel@tonic-gate static char spdsock_diag_buf[SPDSOCK_DIAG_BUF_LEN];
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate /*
917c478bd9Sstevel@tonic-gate  * Define CURL here so that while you are reading
927c478bd9Sstevel@tonic-gate  * this code, it does not affect "vi" in pattern
937c478bd9Sstevel@tonic-gate  * matching.
947c478bd9Sstevel@tonic-gate  */
957c478bd9Sstevel@tonic-gate #define	CURL_BEGIN		'{'
967c478bd9Sstevel@tonic-gate #define	CURL_END		'}'
97d5751483Smarkfen #define	BACK_SLASH		'\\'
987c478bd9Sstevel@tonic-gate #define	MAXARGS			20
9943c889d3Smarkfen #define	NOERROR			0
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate /*
1027c478bd9Sstevel@tonic-gate  * IPSEC_CONF_ADD should start with 1, so that when multiple commands
1037c478bd9Sstevel@tonic-gate  * are given, we can fail the request.
1047c478bd9Sstevel@tonic-gate  */
1057c478bd9Sstevel@tonic-gate 
106eeda67c6Sjojemann enum ipsec_cmds {IPSEC_CONF_ADD = 1, IPSEC_CONF_DEL, IPSEC_CONF_VIEW,
1077c478bd9Sstevel@tonic-gate     IPSEC_CONF_FLUSH, IPSEC_CONF_LIST, IPSEC_CONF_SUB};
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate static const char policy_conf_file[] = "/var/run/ipsecpolicy.conf";
1107c478bd9Sstevel@tonic-gate static const char lock_file[] = "/var/run/ipsecconf.lock";
1117c478bd9Sstevel@tonic-gate static const char index_tag[] = "#INDEX";
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate #define	POLICY_CONF_FILE	policy_conf_file
1147c478bd9Sstevel@tonic-gate #define	LOCK_FILE		lock_file
1157c478bd9Sstevel@tonic-gate #define	INDEX_TAG		index_tag
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate /*
1187c478bd9Sstevel@tonic-gate  * Valid algorithm length.
1197c478bd9Sstevel@tonic-gate  */
1207c478bd9Sstevel@tonic-gate #define	VALID_ALG_LEN		40
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate /* Types of Error messages */
123eeda67c6Sjojemann typedef enum error_type {BAD_ERROR, DUP_ERROR, REQ_ERROR} error_type_t;
1247c478bd9Sstevel@tonic-gate 
1258810c16bSdanmcd /* Error message human readable conversions */
1268810c16bSdanmcd static char *sys_error_message(int);
1278810c16bSdanmcd static void error_message(error_type_t, int, int);
128e3320f40Smarkfen static int get_pf_pol_socket(void);
1298810c16bSdanmcd 
1307c478bd9Sstevel@tonic-gate static int cmd;
1317c478bd9Sstevel@tonic-gate static char *filename;
1327c478bd9Sstevel@tonic-gate static char lo_buf[MAXLEN];			/* Leftover buffer */
1337c478bd9Sstevel@tonic-gate 
1348810c16bSdanmcd /*
1358810c16bSdanmcd  * The new SPD_EXT_TUN_NAME extension has a tunnel name in it.  Use the empty
1368810c16bSdanmcd  * string ("", stored in the char value "all_polheads") for all policy heads
1378810c16bSdanmcd  * (global and all tunnels).  Set interface_name to NULL for global-only, or
1388810c16bSdanmcd  * specify a name of an IP-in-IP tunnel.
1398810c16bSdanmcd  */
1408810c16bSdanmcd static char *interface_name;
1418810c16bSdanmcd static char all_polheads;	/* So we can easily get "". */
1428810c16bSdanmcd 
1437c478bd9Sstevel@tonic-gate /* Error reporting stuff */
1447c478bd9Sstevel@tonic-gate #define	CBUF_LEN		4096		/* Maximum size of the cmd */
1457c478bd9Sstevel@tonic-gate /*
1467c478bd9Sstevel@tonic-gate  * Following are used for reporting errors with arguments.
1477c478bd9Sstevel@tonic-gate  * We store the line numbers of each argument as we parse them,
1487c478bd9Sstevel@tonic-gate  * so that the error reporting is more specific. We can have only
149d5751483Smarkfen  * (MAXARGS - 1) arguments between any pair of CURL_BEGIN CURL_END.
150d5751483Smarkfen  * Because a single command can be made up of multiple action/property
151d5751483Smarkfen  * combinations, the maximum command size is (2 * (MAXARGS -1)) for each
152d5751483Smarkfen  * of patterns, properties and actions.
1537c478bd9Sstevel@tonic-gate  */
154d5751483Smarkfen #define	ARG_BUF_LEN		((2 * 3 * (MAXARGS - 1)) + 1)
1557c478bd9Sstevel@tonic-gate static int arg_indices[ARG_BUF_LEN];
1567c478bd9Sstevel@tonic-gate static int argindex;
1577c478bd9Sstevel@tonic-gate static int linecount;
1587c478bd9Sstevel@tonic-gate static char cbuf[CBUF_LEN];				/* Command buffer */
1597c478bd9Sstevel@tonic-gate static int cbuf_offset;
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate #define	BYPASS_POLICY_BOOST		0x00800000
1637c478bd9Sstevel@tonic-gate #define	ESP_POLICY_BOOST		0x00400000
1647c478bd9Sstevel@tonic-gate #define	AH_POLICY_BOOST			0x00200000
1657c478bd9Sstevel@tonic-gate #define	INITIAL_BASE_PRIORITY		0x000fffff
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate /*
1687c478bd9Sstevel@tonic-gate  * the number used to order the
1697c478bd9Sstevel@tonic-gate  * rules starts at a certain base and
1707c478bd9Sstevel@tonic-gate  * goes down.  i.e. rules earlier in
1717c478bd9Sstevel@tonic-gate  * the file are checked first
1727c478bd9Sstevel@tonic-gate  */
1737c478bd9Sstevel@tonic-gate static uint32_t priority = INITIAL_BASE_PRIORITY;
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate #define	AH_AUTH		0
1767c478bd9Sstevel@tonic-gate #define	ESP_ENCR	1
1777c478bd9Sstevel@tonic-gate #define	ESP_AUTH	2
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate /*
1817c478bd9Sstevel@tonic-gate  * for deleting adds on error
1827c478bd9Sstevel@tonic-gate  */
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate typedef struct d_list_s
1857c478bd9Sstevel@tonic-gate {
1867c478bd9Sstevel@tonic-gate 	struct d_list_s *next;
1877c478bd9Sstevel@tonic-gate 	int index;
1887c478bd9Sstevel@tonic-gate } d_list_t;
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate static d_list_t *d_list = NULL;
1917c478bd9Sstevel@tonic-gate static d_list_t *d_tail = NULL;
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate /*
1957c478bd9Sstevel@tonic-gate  * Used for multi-homed source/dest hosts.
1967c478bd9Sstevel@tonic-gate  */
1977c478bd9Sstevel@tonic-gate static struct hostent *shp, *dhp;
1987c478bd9Sstevel@tonic-gate static unsigned int splen, dplen;
1998810c16bSdanmcd static char tunif[TUNNAMEMAXLEN];
2007c478bd9Sstevel@tonic-gate static boolean_t has_saprefix, has_daprefix;
2017c478bd9Sstevel@tonic-gate static uint32_t seq_cnt = 0;
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate /* lexxed out action and related properties */
2047c478bd9Sstevel@tonic-gate typedef struct ap_s
2057c478bd9Sstevel@tonic-gate {
2067c478bd9Sstevel@tonic-gate 	char *act;
2077c478bd9Sstevel@tonic-gate 	char *prop[MAXARGS + 1];
2087c478bd9Sstevel@tonic-gate } ap_t;
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate /* one lexxed out rule */
2127c478bd9Sstevel@tonic-gate typedef struct act_prop_s {
213d5751483Smarkfen 	char *pattern[MAXARGS + 1];
2147c478bd9Sstevel@tonic-gate 	ap_t ap[MAXARGS + 1];
2157c478bd9Sstevel@tonic-gate } act_prop_t;
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate typedef struct
2187c478bd9Sstevel@tonic-gate {
2197c478bd9Sstevel@tonic-gate 	uint8_t	 alg_id;
2207c478bd9Sstevel@tonic-gate 	uint32_t alg_minbits;
2217c478bd9Sstevel@tonic-gate 	uint32_t alg_maxbits;
2227c478bd9Sstevel@tonic-gate } algreq_t;
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate /* structure to hold all information for one act_prop_t */
2257c478bd9Sstevel@tonic-gate typedef struct ips_act_props_s {
2267c478bd9Sstevel@tonic-gate 	struct ips_act_props_s	*iap_next;
2277c478bd9Sstevel@tonic-gate 	struct ips_conf_s		*iap_head;
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate /*
2307c478bd9Sstevel@tonic-gate  * IPsec action types (in SPD_ATTR_TYPE attribute)
2317c478bd9Sstevel@tonic-gate  * SPD_ACTTYPE_DROP	0x0001
2327c478bd9Sstevel@tonic-gate  * SPD_ACTTYPE_PASS	0x0002
2337c478bd9Sstevel@tonic-gate  * SPD_ACTTYPE_IPSEC	0x0003
2347c478bd9Sstevel@tonic-gate  */
2357c478bd9Sstevel@tonic-gate 	uint16_t	iap_action;
2367c478bd9Sstevel@tonic-gate 	uint16_t	iap_act_tok;
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate /*
2397c478bd9Sstevel@tonic-gate  * Action ATTR flags (in SPD_ATTR_FLAGS attribute)
2407c478bd9Sstevel@tonic-gate  *	SPD_APPLY_AH		0x0001
2417c478bd9Sstevel@tonic-gate  *	SPD_APPLY_ESP		0x0002
2427c478bd9Sstevel@tonic-gate  *	SPD_APPLY_SE		0x0004  * self-encapsulation *
2437c478bd9Sstevel@tonic-gate  *	SPD_APPLY_COMP		0x0008	* compression; NYI *
2447c478bd9Sstevel@tonic-gate  *	SPD_APPLY_UNIQUE	0x0010	* unique per-flow SA *
2457c478bd9Sstevel@tonic-gate  *	SPD_APPLY_BYPASS	0x0020	* bypass policy *
2467c478bd9Sstevel@tonic-gate  */
2477c478bd9Sstevel@tonic-gate 	uint16_t	iap_attr;
2487c478bd9Sstevel@tonic-gate 	uint16_t	iap_attr_tok[5];
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate 	algreq_t	iap_aauth;
2517c478bd9Sstevel@tonic-gate 	algreq_t	iap_eencr;
2527c478bd9Sstevel@tonic-gate 	algreq_t	iap_eauth;
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate 	uint32_t iap_life_soft_time;
2557c478bd9Sstevel@tonic-gate 	uint32_t iap_life_hard_time;
2567c478bd9Sstevel@tonic-gate 	uint32_t iap_life_soft_bytes;
2577c478bd9Sstevel@tonic-gate 	uint32_t iap_life_hard_bytes;
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate } ips_act_props_t;
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate #define	V4_PART_OF_V6(v6)	v6._S6_un._S6_u32[3]
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate typedef struct ips_conf_s {
2647c478bd9Sstevel@tonic-gate 	/* selector */
2657c478bd9Sstevel@tonic-gate 	uint16_t patt_tok[8];
2667c478bd9Sstevel@tonic-gate 	uint8_t has_saddr;
2677c478bd9Sstevel@tonic-gate 	uint8_t has_daddr;
2687c478bd9Sstevel@tonic-gate 	uint8_t has_smask;
2697c478bd9Sstevel@tonic-gate 	uint8_t has_dmask;
2707c478bd9Sstevel@tonic-gate 	uint8_t has_type;
2717c478bd9Sstevel@tonic-gate 	uint8_t has_code;
2728810c16bSdanmcd 	uint8_t has_negotiate;
2738810c16bSdanmcd 	uint8_t has_tunnel;
2747c478bd9Sstevel@tonic-gate 	uint16_t swap;
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 	struct in6_addr	ips_src_addr_v6;
2777c478bd9Sstevel@tonic-gate 	struct in6_addr	ips_src_mask_v6;
2787c478bd9Sstevel@tonic-gate 	struct in6_addr	ips_dst_addr_v6;
2797c478bd9Sstevel@tonic-gate 	struct in6_addr	ips_dst_mask_v6;
2807c478bd9Sstevel@tonic-gate 	uint8_t 		ips_src_mask_len;
2817c478bd9Sstevel@tonic-gate 	uint8_t 		ips_dst_mask_len;
2827c478bd9Sstevel@tonic-gate 	in_port_t		ips_src_port_min;
2837c478bd9Sstevel@tonic-gate 	in_port_t		ips_src_port_max;
2847c478bd9Sstevel@tonic-gate 	in_port_t		ips_dst_port_min;
2857c478bd9Sstevel@tonic-gate 	in_port_t		ips_dst_port_max;
2867c478bd9Sstevel@tonic-gate 	uint8_t			ips_icmp_type;
2877c478bd9Sstevel@tonic-gate 	uint8_t			ips_icmp_type_end;
2887c478bd9Sstevel@tonic-gate 	uint8_t			ips_icmp_code;
2897c478bd9Sstevel@tonic-gate 	uint8_t			ips_icmp_code_end;
2907c478bd9Sstevel@tonic-gate 	uint8_t			ips_ulp_prot;
2917c478bd9Sstevel@tonic-gate 	uint8_t			ips_ipsec_prot;
2927c478bd9Sstevel@tonic-gate 	uint8_t			ips_isv4;
2937c478bd9Sstevel@tonic-gate 	/*
2947c478bd9Sstevel@tonic-gate 	 * SPD_RULE_FLAG_INBOUND		0x0001
2957c478bd9Sstevel@tonic-gate 	 * SPD_RULE_FLAG_OUTBOUND		0x0002
2967c478bd9Sstevel@tonic-gate 	 */
2977c478bd9Sstevel@tonic-gate 	uint8_t			ips_dir;
2988810c16bSdanmcd 	/*
2998810c16bSdanmcd 	 * Keep track of tunnel separately due to explosion of ways to set
3008810c16bSdanmcd 	 * inbound/outbound.
3018810c16bSdanmcd 	 */
3028810c16bSdanmcd 	boolean_t		ips_tunnel;
3037c478bd9Sstevel@tonic-gate 	uint64_t		ips_policy_index;
3047c478bd9Sstevel@tonic-gate 	uint32_t		ips_act_cnt;
3057c478bd9Sstevel@tonic-gate 	ips_act_props_t	*ips_acts;
3067c478bd9Sstevel@tonic-gate } ips_conf_t;
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate #define	ips_src_addr	V4_PART_OF_V6(ips_src_addr_v6)
3097c478bd9Sstevel@tonic-gate #define	ips_dst_addr	V4_PART_OF_V6(ips_dst_addr_v6)
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate static int ipsecconf_nflag;		/* Used only with -l option */
3127c478bd9Sstevel@tonic-gate static int ipsecconf_qflag;		/* Used only with -a|-r option */
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate typedef struct str_val {
3157c478bd9Sstevel@tonic-gate 	const char *string;
3167c478bd9Sstevel@tonic-gate 	int value;
3177c478bd9Sstevel@tonic-gate } str_val_t;
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate typedef struct str_tval {
3207c478bd9Sstevel@tonic-gate 	const char *string;
3217c478bd9Sstevel@tonic-gate 	int tok_val;
3227c478bd9Sstevel@tonic-gate 	int value;
3237c478bd9Sstevel@tonic-gate } str_tval_t;
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate static int	parse_int(const char *);
3268810c16bSdanmcd static int	parse_index(const char *, char *);
3278810c16bSdanmcd static int	attach_tunname(spd_if_t *);
3287c478bd9Sstevel@tonic-gate static void	usage(void);
3297c478bd9Sstevel@tonic-gate static int	ipsec_conf_del(int, boolean_t);
330e3320f40Smarkfen static int	ipsec_conf_add(boolean_t, boolean_t);
3317c478bd9Sstevel@tonic-gate static int	ipsec_conf_sub(void);
3327c478bd9Sstevel@tonic-gate static int	ipsec_conf_flush(int);
3337c478bd9Sstevel@tonic-gate static int	ipsec_conf_view(void);
3347c478bd9Sstevel@tonic-gate static int	ipsec_conf_list(void);
3357c478bd9Sstevel@tonic-gate static int	lock(void);
3367c478bd9Sstevel@tonic-gate static int	unlock(int);
3377c478bd9Sstevel@tonic-gate static int	parse_one(FILE *, act_prop_t *);
3387c478bd9Sstevel@tonic-gate static void	reconfigure();
3397c478bd9Sstevel@tonic-gate static void	in_prefixlentomask(unsigned int, uchar_t *);
3408810c16bSdanmcd static int	in_getprefixlen(char *);
3417c478bd9Sstevel@tonic-gate static int	parse_address(int, char *);
3427c478bd9Sstevel@tonic-gate #ifdef DEBUG_HEAVY
3437c478bd9Sstevel@tonic-gate static void	pfpol_msg_dump(spd_msg_t *msg, char *);
3447c478bd9Sstevel@tonic-gate #endif /* DEBUG_HEAVY */
3457c478bd9Sstevel@tonic-gate static void	print_pfpol_msg(spd_msg_t *);
3467c478bd9Sstevel@tonic-gate static int	pfp_delete_rule(uint64_t);
3477c478bd9Sstevel@tonic-gate static void	ipsec_conf_admin(uint8_t);
3487c478bd9Sstevel@tonic-gate static void	print_bit_range(int, int);
3497c478bd9Sstevel@tonic-gate static void	nuke_adds();
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate #ifdef DEBUG
3527c478bd9Sstevel@tonic-gate static void	dump_conf(ips_conf_t *);
3537c478bd9Sstevel@tonic-gate #endif
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate typedef struct
3567c478bd9Sstevel@tonic-gate {
3577c478bd9Sstevel@tonic-gate 	uint32_t	id;
3587c478bd9Sstevel@tonic-gate 	uint32_t	minkeybits;
3597c478bd9Sstevel@tonic-gate 	uint32_t	maxkeybits;
3607c478bd9Sstevel@tonic-gate 	uint32_t	defkeybits;
3617c478bd9Sstevel@tonic-gate 	uint32_t	incr;
3627c478bd9Sstevel@tonic-gate } alginfo_t;
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate static int ipsec_nalgs[3];
3657c478bd9Sstevel@tonic-gate static alginfo_t known_algs[3][256];
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate #define	IPS_SRC_MASK SPD_EXT_LCLADDR + 100
3687c478bd9Sstevel@tonic-gate #define	IPS_DST_MASK SPD_EXT_REMADDR + 100
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate /*
3717c478bd9Sstevel@tonic-gate  * if inbound, src=remote, dst=local
3727c478bd9Sstevel@tonic-gate  * if outbound, src=local, dst=remote
3737c478bd9Sstevel@tonic-gate  */
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate #define	TOK_saddr	1
3767c478bd9Sstevel@tonic-gate #define	TOK_daddr	2
3777c478bd9Sstevel@tonic-gate #define	TOK_sport	3
3787c478bd9Sstevel@tonic-gate #define	TOK_dport	4
3797c478bd9Sstevel@tonic-gate #define	TOK_smask	5
3807c478bd9Sstevel@tonic-gate #define	TOK_dmask	6
3817c478bd9Sstevel@tonic-gate #define	TOK_ulp	7
3827c478bd9Sstevel@tonic-gate #define	TOK_local	8
3837c478bd9Sstevel@tonic-gate #define	TOK_lport	9
3847c478bd9Sstevel@tonic-gate #define	TOK_remote	10
3857c478bd9Sstevel@tonic-gate #define	TOK_rport	11
3867c478bd9Sstevel@tonic-gate #define	TOK_dir 	12
3877c478bd9Sstevel@tonic-gate #define	TOK_type	13
3887c478bd9Sstevel@tonic-gate #define	TOK_code	14
3898810c16bSdanmcd #define	TOK_negotiate	15
3908810c16bSdanmcd #define	TOK_tunnel	16
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate #define	IPS_SA SPD_ATTR_END
3937c478bd9Sstevel@tonic-gate #define	IPS_DIR SPD_ATTR_EMPTY
3948810c16bSdanmcd #define	IPS_NEG SPD_ATTR_NOP
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate static str_tval_t pattern_table[] = {
3987c478bd9Sstevel@tonic-gate 	{"saddr", 		TOK_saddr,		SPD_EXT_LCLADDR},
3997c478bd9Sstevel@tonic-gate 	{"src",			TOK_saddr,		SPD_EXT_LCLADDR},
4007c478bd9Sstevel@tonic-gate 	{"srcaddr",		TOK_saddr,		SPD_EXT_LCLADDR},
4017c478bd9Sstevel@tonic-gate 	{"daddr", 		TOK_daddr,		SPD_EXT_REMADDR},
4027c478bd9Sstevel@tonic-gate 	{"dst",			TOK_daddr,		SPD_EXT_REMADDR},
4037c478bd9Sstevel@tonic-gate 	{"dstaddr",		TOK_daddr,		SPD_EXT_REMADDR},
4047c478bd9Sstevel@tonic-gate 	{"sport", 		TOK_sport,		SPD_EXT_LCLPORT},
4057c478bd9Sstevel@tonic-gate 	{"dport", 		TOK_dport,		SPD_EXT_REMPORT},
4067c478bd9Sstevel@tonic-gate 	{"smask", 		TOK_smask,		IPS_SRC_MASK},
4077c478bd9Sstevel@tonic-gate 	{"dmask", 		TOK_dmask,		IPS_DST_MASK},
4087c478bd9Sstevel@tonic-gate 	{"ulp", 		TOK_ulp,		SPD_EXT_PROTO},
4097c478bd9Sstevel@tonic-gate 	{"proto", 		TOK_ulp,		SPD_EXT_PROTO},
4107c478bd9Sstevel@tonic-gate 	{"local",		TOK_local,		SPD_EXT_LCLADDR},
4117c478bd9Sstevel@tonic-gate 	{"laddr",		TOK_local,		SPD_EXT_LCLADDR},
4127c478bd9Sstevel@tonic-gate 	{"lport",		TOK_lport,		SPD_EXT_LCLPORT},
4137c478bd9Sstevel@tonic-gate 	{"remote",		TOK_remote,		SPD_EXT_REMADDR},
4147c478bd9Sstevel@tonic-gate 	{"raddr",		TOK_remote,		SPD_EXT_REMADDR},
4157c478bd9Sstevel@tonic-gate 	{"rport",		TOK_rport,		SPD_EXT_REMPORT},
4167c478bd9Sstevel@tonic-gate 	{"dir",			TOK_dir,		IPS_DIR},
4177c478bd9Sstevel@tonic-gate 	{"type",		TOK_type,		SPD_EXT_ICMP_TYPECODE},
4187c478bd9Sstevel@tonic-gate 	{"code",		TOK_code,		SPD_EXT_ICMP_TYPECODE},
4198810c16bSdanmcd 	{"negotiate",		TOK_negotiate,		IPS_NEG},
4208810c16bSdanmcd 	{"tunnel",		TOK_tunnel,		SPD_EXT_TUN_NAME},
4217c478bd9Sstevel@tonic-gate 	{NULL, 			0,				0},
4227c478bd9Sstevel@tonic-gate };
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate #define	TOK_apply	1
4257c478bd9Sstevel@tonic-gate #define	TOK_permit	2
4267c478bd9Sstevel@tonic-gate #define	TOK_ipsec	3
4277c478bd9Sstevel@tonic-gate #define	TOK_bypass	4
4287c478bd9Sstevel@tonic-gate #define	TOK_drop	5
4297c478bd9Sstevel@tonic-gate #define	TOK_or		6
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate static str_tval_t action_table[] = {
4327c478bd9Sstevel@tonic-gate 	{"apply", 		TOK_apply,		SPD_ACTTYPE_IPSEC},
4337c478bd9Sstevel@tonic-gate 	{"permit", 		TOK_permit,		SPD_ACTTYPE_IPSEC},
4347c478bd9Sstevel@tonic-gate 	{"ipsec", 		TOK_ipsec,		SPD_ACTTYPE_IPSEC},
4357c478bd9Sstevel@tonic-gate 	{"bypass", 		TOK_bypass,		SPD_ACTTYPE_PASS},
4367c478bd9Sstevel@tonic-gate 	{"pass", 		TOK_bypass,		SPD_ACTTYPE_PASS},
4377c478bd9Sstevel@tonic-gate 	{"drop", 		TOK_drop,		SPD_ACTTYPE_DROP},
4387c478bd9Sstevel@tonic-gate 	{"or",			TOK_or,			0},
4397c478bd9Sstevel@tonic-gate 	{NULL, 			0,				0},
4407c478bd9Sstevel@tonic-gate };
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate static str_val_t property_table[] = {
4437c478bd9Sstevel@tonic-gate 	{"auth_algs", 		SPD_ATTR_AH_AUTH},
4447c478bd9Sstevel@tonic-gate 	{"encr_algs", 		SPD_ATTR_ESP_ENCR},
4457c478bd9Sstevel@tonic-gate 	{"encr_auth_algs",	SPD_ATTR_ESP_AUTH},
4467c478bd9Sstevel@tonic-gate 	{"sa",				IPS_SA},
4477c478bd9Sstevel@tonic-gate 	{"dir",				IPS_DIR},
4487c478bd9Sstevel@tonic-gate 	{NULL,				0},
4497c478bd9Sstevel@tonic-gate };
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate static str_val_t icmp_type_table[] = {
4527c478bd9Sstevel@tonic-gate 	{"unreach",	ICMP_UNREACH},
4537c478bd9Sstevel@tonic-gate 	{"echo",	ICMP_ECHO},
4547c478bd9Sstevel@tonic-gate 	{"echorep",	ICMP_ECHOREPLY},
4557c478bd9Sstevel@tonic-gate 	{"squench",	ICMP_SOURCEQUENCH},
4567c478bd9Sstevel@tonic-gate 	{"redir",	ICMP_REDIRECT},
4577c478bd9Sstevel@tonic-gate 	{"timex",	ICMP_TIMXCEED},
4587c478bd9Sstevel@tonic-gate 	{"paramprob",	ICMP_PARAMPROB},
4597c478bd9Sstevel@tonic-gate 	{"timest",	ICMP_TSTAMP},
4607c478bd9Sstevel@tonic-gate 	{"timestrep",	ICMP_TSTAMPREPLY},
4617c478bd9Sstevel@tonic-gate 	{"inforeq",	ICMP_IREQ},
4627c478bd9Sstevel@tonic-gate 	{"inforep",	ICMP_IREQREPLY},
4637c478bd9Sstevel@tonic-gate 	{"maskreq",	ICMP_MASKREQ},
4647c478bd9Sstevel@tonic-gate 	{"maskrep",	ICMP_MASKREPLY},
4657c478bd9Sstevel@tonic-gate 	{"unreach6",	ICMP6_DST_UNREACH},
4667c478bd9Sstevel@tonic-gate 	{"pkttoobig6",	ICMP6_PACKET_TOO_BIG},
4677c478bd9Sstevel@tonic-gate 	{"timex6",	ICMP6_TIME_EXCEEDED},
4687c478bd9Sstevel@tonic-gate 	{"paramprob6",	ICMP6_PARAM_PROB},
4697c478bd9Sstevel@tonic-gate 	{"echo6", 	ICMP6_ECHO_REQUEST},
4707c478bd9Sstevel@tonic-gate 	{"echorep6",	ICMP6_ECHO_REPLY},
4717c478bd9Sstevel@tonic-gate 	{"router-sol6",	ND_ROUTER_SOLICIT},
4727c478bd9Sstevel@tonic-gate 	{"router-ad6",	ND_ROUTER_ADVERT},
4737c478bd9Sstevel@tonic-gate 	{"neigh-sol6",	ND_NEIGHBOR_SOLICIT},
4747c478bd9Sstevel@tonic-gate 	{"neigh-ad6",	ND_NEIGHBOR_ADVERT},
4757c478bd9Sstevel@tonic-gate 	{"redir6",	ND_REDIRECT},
4767c478bd9Sstevel@tonic-gate 	{NULL,		0},
4777c478bd9Sstevel@tonic-gate };
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate static str_val_t icmp_code_table[] = {
4807c478bd9Sstevel@tonic-gate 	{"net-unr",		ICMP_UNREACH_NET},
4817c478bd9Sstevel@tonic-gate 	{"host-unr",		ICMP_UNREACH_HOST},
4827c478bd9Sstevel@tonic-gate 	{"proto-unr",		ICMP_UNREACH_PROTOCOL},
4837c478bd9Sstevel@tonic-gate 	{"port-unr",		ICMP_UNREACH_PORT},
4847c478bd9Sstevel@tonic-gate 	{"needfrag",		ICMP_UNREACH_NEEDFRAG},
4857c478bd9Sstevel@tonic-gate 	{"srcfail",		ICMP_UNREACH_SRCFAIL},
4867c478bd9Sstevel@tonic-gate 	{"net-unk",		ICMP_UNREACH_NET_UNKNOWN},
4877c478bd9Sstevel@tonic-gate 	{"host-unk",		ICMP_UNREACH_HOST_UNKNOWN},
4887c478bd9Sstevel@tonic-gate 	{"isolate",		ICMP_UNREACH_ISOLATED},
4897c478bd9Sstevel@tonic-gate 	{"net-prohib",		ICMP_UNREACH_NET_PROHIB},
4907c478bd9Sstevel@tonic-gate 	{"host-prohib",		ICMP_UNREACH_HOST_PROHIB},
4917c478bd9Sstevel@tonic-gate 	{"net-tos",		ICMP_UNREACH_TOSNET},
4927c478bd9Sstevel@tonic-gate 	{"host-tos",		ICMP_UNREACH_TOSHOST},
4937c478bd9Sstevel@tonic-gate 	{"filter-prohib",	ICMP_UNREACH_FILTER_PROHIB},
4947c478bd9Sstevel@tonic-gate 	{"host-preced",		ICMP_UNREACH_HOST_PRECEDENCE},
4957c478bd9Sstevel@tonic-gate 	{"cutoff-preced",	ICMP_UNREACH_PRECEDENCE_CUTOFF},
4967c478bd9Sstevel@tonic-gate 	{"no-route6",		ICMP6_DST_UNREACH_NOROUTE},
4977c478bd9Sstevel@tonic-gate 	{"adm-prohib6",		ICMP6_DST_UNREACH_ADMIN},
4987c478bd9Sstevel@tonic-gate 	{"addr-unr6",		ICMP6_DST_UNREACH_ADDR},
4997c478bd9Sstevel@tonic-gate 	{"port-unr6",		ICMP6_DST_UNREACH_NOPORT},
5007c478bd9Sstevel@tonic-gate 	{"hop-limex6",		ICMP6_TIME_EXCEED_TRANSIT},
5017c478bd9Sstevel@tonic-gate 	{"frag-re-timex6",	ICMP6_TIME_EXCEED_REASSEMBLY},
5027c478bd9Sstevel@tonic-gate 	{"err-head6",		ICMP6_PARAMPROB_HEADER},
5037c478bd9Sstevel@tonic-gate 	{"unrec-head6",		ICMP6_PARAMPROB_NEXTHEADER},
5047c478bd9Sstevel@tonic-gate 	{"unreq-opt6",		ICMP6_PARAMPROB_OPTION},
5057c478bd9Sstevel@tonic-gate 	{NULL,			0},
5067c478bd9Sstevel@tonic-gate };
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate static sigset_t set, oset;
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate static boolean_t
5127c478bd9Sstevel@tonic-gate add_index(int index)
5137c478bd9Sstevel@tonic-gate {
5147c478bd9Sstevel@tonic-gate 	d_list_t *temp = malloc(sizeof (d_list_t));
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate 	if (temp == NULL) {
5177c478bd9Sstevel@tonic-gate 		warn("malloc");
5187c478bd9Sstevel@tonic-gate 		return (B_TRUE);
5197c478bd9Sstevel@tonic-gate 	}
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 	temp->index = index;
5227c478bd9Sstevel@tonic-gate 	temp->next = NULL;
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 	if (d_tail == NULL) {
5257c478bd9Sstevel@tonic-gate 		d_list = d_tail = temp;
5267c478bd9Sstevel@tonic-gate 		return (B_FALSE);
5277c478bd9Sstevel@tonic-gate 	}
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 	d_tail->next = temp;
5307c478bd9Sstevel@tonic-gate 	d_tail = temp;
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate 	return (B_FALSE);
5337c478bd9Sstevel@tonic-gate }
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate static int
5367c478bd9Sstevel@tonic-gate block_all_signals()
5377c478bd9Sstevel@tonic-gate {
5387c478bd9Sstevel@tonic-gate 	if (sigfillset(&set) == -1) {
5397c478bd9Sstevel@tonic-gate 		warn("sigfillset");
5407c478bd9Sstevel@tonic-gate 		return (-1);
5417c478bd9Sstevel@tonic-gate 	}
5427c478bd9Sstevel@tonic-gate 	if (sigprocmask(SIG_SETMASK, &set, &oset) == -1) {
5437c478bd9Sstevel@tonic-gate 		warn("sigprocmask");
5447c478bd9Sstevel@tonic-gate 		return (-1);
5457c478bd9Sstevel@tonic-gate 	}
5467c478bd9Sstevel@tonic-gate 	return (0);
5477c478bd9Sstevel@tonic-gate }
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate static int
5507c478bd9Sstevel@tonic-gate restore_all_signals()
5517c478bd9Sstevel@tonic-gate {
5527c478bd9Sstevel@tonic-gate 	if (sigprocmask(SIG_SETMASK, &oset, NULL) == -1) {
5537c478bd9Sstevel@tonic-gate 		warn("sigprocmask");
5547c478bd9Sstevel@tonic-gate 		return (-1);
5557c478bd9Sstevel@tonic-gate 	}
5567c478bd9Sstevel@tonic-gate 	return (0);
5577c478bd9Sstevel@tonic-gate }
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate /* allocate an ips_act_props_t and link it in correctly */
5607c478bd9Sstevel@tonic-gate static ips_act_props_t *
5617c478bd9Sstevel@tonic-gate alloc_iap(ips_conf_t *parent)
5627c478bd9Sstevel@tonic-gate {
5637c478bd9Sstevel@tonic-gate 	ips_act_props_t *ret;
5647c478bd9Sstevel@tonic-gate 	ips_act_props_t *next = parent->ips_acts;
5657c478bd9Sstevel@tonic-gate 	ips_act_props_t *current = NULL;
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate 	ret = (ips_act_props_t *)calloc(sizeof (ips_act_props_t), 1);
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate 	if (ret == NULL)
5707c478bd9Sstevel@tonic-gate 		return (NULL);
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate 	ret->iap_head = parent;
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate 	while (next != NULL) {
5757c478bd9Sstevel@tonic-gate 		current = next;
5767c478bd9Sstevel@tonic-gate 		next = next->iap_next;
5777c478bd9Sstevel@tonic-gate 	}
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate 	if (current != NULL)
5807c478bd9Sstevel@tonic-gate 		current->iap_next = ret;
5817c478bd9Sstevel@tonic-gate 	else
5827c478bd9Sstevel@tonic-gate 		parent->ips_acts = ret;
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate 	parent->ips_act_cnt++;
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate 	return (ret);
5877c478bd9Sstevel@tonic-gate }
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate /*
5907c478bd9Sstevel@tonic-gate  * This function exit()s if it fails.
5917c478bd9Sstevel@tonic-gate  */
5927c478bd9Sstevel@tonic-gate static void
5937c478bd9Sstevel@tonic-gate fetch_algorithms()
5947c478bd9Sstevel@tonic-gate {
5957c478bd9Sstevel@tonic-gate 	struct spd_msg msg;
5967c478bd9Sstevel@tonic-gate 	struct spd_ext_actions *actp;
5977c478bd9Sstevel@tonic-gate 	struct spd_attribute *attr, *endattr;
5987c478bd9Sstevel@tonic-gate 	spd_ext_t *exts[SPD_EXT_MAX+1];
5997c478bd9Sstevel@tonic-gate 	uint64_t reply_buf[256];
600e3320f40Smarkfen 	int sfd;
6017c478bd9Sstevel@tonic-gate 	int cnt, retval;
6027c478bd9Sstevel@tonic-gate 	uint64_t *start, *end;
6037c478bd9Sstevel@tonic-gate 	alginfo_t alg = {0, 0, 0, 0, 0};
6047c478bd9Sstevel@tonic-gate 	uint_t algtype;
6057c478bd9Sstevel@tonic-gate 	static boolean_t has_run = B_FALSE;
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate 	if (has_run)
6087c478bd9Sstevel@tonic-gate 		return;
6097c478bd9Sstevel@tonic-gate 	else
6107c478bd9Sstevel@tonic-gate 		has_run = B_TRUE;
6117c478bd9Sstevel@tonic-gate 
612e3320f40Smarkfen 	sfd = get_pf_pol_socket();
6137c478bd9Sstevel@tonic-gate 	if (sfd < 0) {
6147c478bd9Sstevel@tonic-gate 		err(-1, gettext("unable to open policy socket"));
6157c478bd9Sstevel@tonic-gate 	}
6167c478bd9Sstevel@tonic-gate 
6177c478bd9Sstevel@tonic-gate 	(void) memset(&msg, 0, sizeof (msg));
6187c478bd9Sstevel@tonic-gate 	msg.spd_msg_version = PF_POLICY_V1;
6197c478bd9Sstevel@tonic-gate 	msg.spd_msg_type = SPD_ALGLIST;
6207c478bd9Sstevel@tonic-gate 	msg.spd_msg_len = SPD_8TO64(sizeof (msg));
6217c478bd9Sstevel@tonic-gate 
6227c478bd9Sstevel@tonic-gate 	cnt = write(sfd, &msg, sizeof (msg));
6237c478bd9Sstevel@tonic-gate 	if (cnt != sizeof (msg)) {
6247c478bd9Sstevel@tonic-gate 		if (cnt < 0) {
6257c478bd9Sstevel@tonic-gate 			err(-1, gettext("alglist failed: write"));
6267c478bd9Sstevel@tonic-gate 		} else {
6278810c16bSdanmcd 			errx(-1, gettext("alglist failed: short write"));
6287c478bd9Sstevel@tonic-gate 		}
6297c478bd9Sstevel@tonic-gate 	}
6307c478bd9Sstevel@tonic-gate 
6317c478bd9Sstevel@tonic-gate 	cnt = read(sfd, reply_buf, sizeof (reply_buf));
6327c478bd9Sstevel@tonic-gate 
6337c478bd9Sstevel@tonic-gate 	retval = spdsock_get_ext(exts, (spd_msg_t *)reply_buf, SPD_8TO64(cnt),
6347c478bd9Sstevel@tonic-gate 	    spdsock_diag_buf, SPDSOCK_DIAG_BUF_LEN);
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate 	if (retval == KGE_LEN && exts[0]->spd_ext_len == 0) {
6377c478bd9Sstevel@tonic-gate 		/*
6387c478bd9Sstevel@tonic-gate 		 * No algorithms are defined in the kernel, which caused
6397c478bd9Sstevel@tonic-gate 		 * the extension length to be zero, and spdsock_get_ext()
6407c478bd9Sstevel@tonic-gate 		 * to fail with a KGE_LEN error. This is not an error
6417c478bd9Sstevel@tonic-gate 		 * condition, so we return nicely.
6427c478bd9Sstevel@tonic-gate 		 */
643*3abcb969Spwernau 		(void) close(sfd);
6447c478bd9Sstevel@tonic-gate 		return;
6457c478bd9Sstevel@tonic-gate 	} else if (retval != 0) {
6467c478bd9Sstevel@tonic-gate 		if (strlen(spdsock_diag_buf) != 0)
6477c478bd9Sstevel@tonic-gate 			warnx(spdsock_diag_buf);
6487c478bd9Sstevel@tonic-gate 		err(1, gettext("fetch_algorithms failed"));
6497c478bd9Sstevel@tonic-gate 	}
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate 	if (!exts[SPD_EXT_ACTION]) {
6527c478bd9Sstevel@tonic-gate 		errx(1, gettext("fetch_algorithms: action missing?!"));
6537c478bd9Sstevel@tonic-gate 	}
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate 	actp = (struct spd_ext_actions *)exts[SPD_EXT_ACTION];
6567c478bd9Sstevel@tonic-gate 	start = (uint64_t *)actp;
6577c478bd9Sstevel@tonic-gate 	end = (start + actp->spd_actions_len);
6587c478bd9Sstevel@tonic-gate 	endattr = (struct spd_attribute *)end;
6597c478bd9Sstevel@tonic-gate 	attr = (struct spd_attribute *)&actp[1];
6607c478bd9Sstevel@tonic-gate 
6617c478bd9Sstevel@tonic-gate 	algtype = 0;
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate 	while (attr < endattr) {
6647c478bd9Sstevel@tonic-gate 		switch (attr->spd_attr_tag) {
6657c478bd9Sstevel@tonic-gate 		case SPD_ATTR_NOP:
6667c478bd9Sstevel@tonic-gate 		case SPD_ATTR_EMPTY:
6677c478bd9Sstevel@tonic-gate 			break;
6687c478bd9Sstevel@tonic-gate 		case SPD_ATTR_END:
6697c478bd9Sstevel@tonic-gate 			attr = endattr;
6707c478bd9Sstevel@tonic-gate 			/* FALLTHRU */
6717c478bd9Sstevel@tonic-gate 		case SPD_ATTR_NEXT:
6727c478bd9Sstevel@tonic-gate 			known_algs[algtype][ipsec_nalgs[algtype]] = alg;
6737c478bd9Sstevel@tonic-gate 			ipsec_nalgs[algtype]++;
6747c478bd9Sstevel@tonic-gate 			break;
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate 		case SPD_ATTR_ENCR_MINBITS:
6777c478bd9Sstevel@tonic-gate 		case SPD_ATTR_AH_MINBITS:
6787c478bd9Sstevel@tonic-gate 		case SPD_ATTR_ESPA_MINBITS:
6797c478bd9Sstevel@tonic-gate 			alg.minkeybits = attr->spd_attr_value;
6807c478bd9Sstevel@tonic-gate 			break;
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate 		case SPD_ATTR_ENCR_MAXBITS:
6837c478bd9Sstevel@tonic-gate 		case SPD_ATTR_AH_MAXBITS:
6847c478bd9Sstevel@tonic-gate 		case SPD_ATTR_ESPA_MAXBITS:
6857c478bd9Sstevel@tonic-gate 			alg.maxkeybits = attr->spd_attr_value;
6867c478bd9Sstevel@tonic-gate 			break;
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate 		case SPD_ATTR_ENCR_DEFBITS:
6897c478bd9Sstevel@tonic-gate 		case SPD_ATTR_AH_DEFBITS:
6907c478bd9Sstevel@tonic-gate 		case SPD_ATTR_ESPA_DEFBITS:
6917c478bd9Sstevel@tonic-gate 			alg.defkeybits = attr->spd_attr_value;
6927c478bd9Sstevel@tonic-gate 			break;
6937c478bd9Sstevel@tonic-gate 
6947c478bd9Sstevel@tonic-gate 		case SPD_ATTR_ENCR_INCRBITS:
6957c478bd9Sstevel@tonic-gate 		case SPD_ATTR_AH_INCRBITS:
6967c478bd9Sstevel@tonic-gate 		case SPD_ATTR_ESPA_INCRBITS:
6977c478bd9Sstevel@tonic-gate 			alg.incr = attr->spd_attr_value;
6987c478bd9Sstevel@tonic-gate 			break;
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate 		case SPD_ATTR_AH_AUTH:
7017c478bd9Sstevel@tonic-gate 		case SPD_ATTR_ESP_AUTH:
7027c478bd9Sstevel@tonic-gate 		case SPD_ATTR_ESP_ENCR:
7037c478bd9Sstevel@tonic-gate 			alg.id = attr->spd_attr_value;
7047c478bd9Sstevel@tonic-gate 			algtype = attr->spd_attr_tag - SPD_ATTR_AH_AUTH;
7057c478bd9Sstevel@tonic-gate 			break;
7067c478bd9Sstevel@tonic-gate 		}
7077c478bd9Sstevel@tonic-gate 		attr++;
7087c478bd9Sstevel@tonic-gate 	}
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate 	(void) close(sfd);
7117c478bd9Sstevel@tonic-gate }
7127c478bd9Sstevel@tonic-gate 
7137c478bd9Sstevel@tonic-gate /* data dependant transform (act_cnt) */
7147c478bd9Sstevel@tonic-gate #define	ATTR(ap, tag, value) \
7157c478bd9Sstevel@tonic-gate do { (ap)->spd_attr_tag = (tag); \
7167c478bd9Sstevel@tonic-gate 	(ap)->spd_attr_value = (value); \
7177c478bd9Sstevel@tonic-gate 	ap++; } while (0)
7187c478bd9Sstevel@tonic-gate 
7197c478bd9Sstevel@tonic-gate static struct spd_attribute *
7207c478bd9Sstevel@tonic-gate emit_alg(struct spd_attribute *ap, int type, const algreq_t *ar,
7217c478bd9Sstevel@tonic-gate     int algattr, int minbitattr, int maxbitattr)
7227c478bd9Sstevel@tonic-gate {
7237c478bd9Sstevel@tonic-gate 	int id = ar->alg_id;
7247c478bd9Sstevel@tonic-gate 	int minbits, i;
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 	if (id != 0) {
7277c478bd9Sstevel@tonic-gate 		/* LINTED E_CONST_COND */
7287c478bd9Sstevel@tonic-gate 		ATTR(ap, algattr, ar->alg_id);
7297c478bd9Sstevel@tonic-gate 
7307c478bd9Sstevel@tonic-gate 		minbits = ar->alg_minbits;
7317c478bd9Sstevel@tonic-gate 		if (minbits == 0) {
7327c478bd9Sstevel@tonic-gate 			for (i = 0; i < ipsec_nalgs[type]; i++) {
7337c478bd9Sstevel@tonic-gate 				if (known_algs[type][i].id == id)
7347c478bd9Sstevel@tonic-gate 					break;
7357c478bd9Sstevel@tonic-gate 			}
7367c478bd9Sstevel@tonic-gate 			if (i < ipsec_nalgs[type])
7377c478bd9Sstevel@tonic-gate 				minbits = known_algs[type][i].defkeybits;
7387c478bd9Sstevel@tonic-gate 		}
7397c478bd9Sstevel@tonic-gate 		if (minbits != 0)
7407c478bd9Sstevel@tonic-gate 			/* LINTED E_CONST_COND */
7417c478bd9Sstevel@tonic-gate 			ATTR(ap, minbitattr, minbits);
7427c478bd9Sstevel@tonic-gate 		if (ar->alg_maxbits != SPD_MAX_MAXBITS)
7437c478bd9Sstevel@tonic-gate 			/* LINTED E_CONST_COND */
7447c478bd9Sstevel@tonic-gate 			ATTR(ap, maxbitattr, ar->alg_maxbits);
7457c478bd9Sstevel@tonic-gate 	}
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate 	return (ap);
7487c478bd9Sstevel@tonic-gate }
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate static struct spd_attribute *
7537c478bd9Sstevel@tonic-gate ips_act_props_to_action(struct spd_attribute *ap, uint32_t *rule_priorityp,
7547c478bd9Sstevel@tonic-gate     const ips_act_props_t *act_ptr)
7557c478bd9Sstevel@tonic-gate {
7567c478bd9Sstevel@tonic-gate 	uint32_t rule_priority = *rule_priorityp;
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 	/* LINTED E_CONST_COND */
7597c478bd9Sstevel@tonic-gate 	ATTR(ap, SPD_ATTR_EMPTY, 0);
7607c478bd9Sstevel@tonic-gate 
7617c478bd9Sstevel@tonic-gate 	/* type */
7627c478bd9Sstevel@tonic-gate 	/* LINTED E_CONST_COND */
7637c478bd9Sstevel@tonic-gate 	ATTR(ap, SPD_ATTR_TYPE, act_ptr->iap_action);
7647c478bd9Sstevel@tonic-gate 
7657c478bd9Sstevel@tonic-gate 	if (act_ptr->iap_action == SPD_ACTTYPE_PASS)
7667c478bd9Sstevel@tonic-gate 		rule_priority |= BYPASS_POLICY_BOOST;
7677c478bd9Sstevel@tonic-gate 
7687c478bd9Sstevel@tonic-gate 	/* flags */
7697c478bd9Sstevel@tonic-gate 	if (act_ptr->iap_attr != 0)
7707c478bd9Sstevel@tonic-gate 		/* LINTED E_CONST_COND */
7717c478bd9Sstevel@tonic-gate 		ATTR(ap, SPD_ATTR_FLAGS, act_ptr->iap_attr);
7727c478bd9Sstevel@tonic-gate 
7737c478bd9Sstevel@tonic-gate 	/* esp */
7747c478bd9Sstevel@tonic-gate 	if (act_ptr->iap_attr & SPD_APPLY_ESP) {
7757c478bd9Sstevel@tonic-gate 		rule_priority |= ESP_POLICY_BOOST;
7767c478bd9Sstevel@tonic-gate 
7777c478bd9Sstevel@tonic-gate 		/* encr */
7787c478bd9Sstevel@tonic-gate 		ap = emit_alg(ap, ESP_ENCR, &act_ptr->iap_eencr,
7797c478bd9Sstevel@tonic-gate 		    SPD_ATTR_ESP_ENCR,
7807c478bd9Sstevel@tonic-gate 		    SPD_ATTR_ENCR_MINBITS, SPD_ATTR_ENCR_MAXBITS);
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate 		/* auth */
7837c478bd9Sstevel@tonic-gate 		ap = emit_alg(ap, ESP_AUTH, &act_ptr->iap_eauth,
7847c478bd9Sstevel@tonic-gate 		    SPD_ATTR_ESP_AUTH,
7857c478bd9Sstevel@tonic-gate 		    SPD_ATTR_ESPA_MINBITS, SPD_ATTR_ESPA_MAXBITS);
7867c478bd9Sstevel@tonic-gate 	}
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate 	/* ah */
7897c478bd9Sstevel@tonic-gate 	if (act_ptr->iap_attr & SPD_APPLY_AH) {
7907c478bd9Sstevel@tonic-gate 		rule_priority |= AH_POLICY_BOOST;
7917c478bd9Sstevel@tonic-gate 		/* auth */
7927c478bd9Sstevel@tonic-gate 		ap = emit_alg(ap, AH_AUTH, &act_ptr->iap_aauth,
7937c478bd9Sstevel@tonic-gate 		    SPD_ATTR_AH_AUTH,
7947c478bd9Sstevel@tonic-gate 		    SPD_ATTR_AH_MINBITS, SPD_ATTR_AH_MAXBITS);
7957c478bd9Sstevel@tonic-gate 	}
7967c478bd9Sstevel@tonic-gate 
7977c478bd9Sstevel@tonic-gate 	/* lifetimes */
7987c478bd9Sstevel@tonic-gate 	if (act_ptr->iap_life_soft_time != 0)
7997c478bd9Sstevel@tonic-gate 		/* LINTED E_CONST_COND */
8007c478bd9Sstevel@tonic-gate 		ATTR(ap, SPD_ATTR_LIFE_SOFT_TIME, act_ptr->iap_life_soft_time);
8017c478bd9Sstevel@tonic-gate 	if (act_ptr->iap_life_hard_time != 0)
8027c478bd9Sstevel@tonic-gate 		/* LINTED E_CONST_COND */
8037c478bd9Sstevel@tonic-gate 		ATTR(ap, SPD_ATTR_LIFE_HARD_TIME, act_ptr->iap_life_hard_time);
8047c478bd9Sstevel@tonic-gate 	if (act_ptr->iap_life_soft_bytes != 0)
8057c478bd9Sstevel@tonic-gate 		/* LINTED E_CONST_COND */
8067c478bd9Sstevel@tonic-gate 		ATTR(ap, SPD_ATTR_LIFE_SOFT_BYTES,
8077c478bd9Sstevel@tonic-gate 		    act_ptr->iap_life_soft_bytes);
8087c478bd9Sstevel@tonic-gate 	if (act_ptr->iap_life_hard_bytes != 0)
8097c478bd9Sstevel@tonic-gate 		/* LINTED E_CONST_COND */
8107c478bd9Sstevel@tonic-gate 		ATTR(ap, SPD_ATTR_LIFE_HARD_BYTES,
8117c478bd9Sstevel@tonic-gate 		    act_ptr->iap_life_hard_bytes);
8127c478bd9Sstevel@tonic-gate 
8137c478bd9Sstevel@tonic-gate 	/* LINTED E_CONST_COND */
8147c478bd9Sstevel@tonic-gate 	ATTR(ap, SPD_ATTR_NEXT, 0);
8157c478bd9Sstevel@tonic-gate 
8167c478bd9Sstevel@tonic-gate 	*rule_priorityp = rule_priority;
8177c478bd9Sstevel@tonic-gate 
8187c478bd9Sstevel@tonic-gate 	return (ap);
8197c478bd9Sstevel@tonic-gate }
8207c478bd9Sstevel@tonic-gate 
8217c478bd9Sstevel@tonic-gate static boolean_t
8227c478bd9Sstevel@tonic-gate alg_rangecheck(uint_t type, uint_t algid, const algreq_t *ar)
8237c478bd9Sstevel@tonic-gate {
8247c478bd9Sstevel@tonic-gate 	int i;
8257c478bd9Sstevel@tonic-gate 	uint_t minbits = ar->alg_minbits;
8267c478bd9Sstevel@tonic-gate 	uint_t maxbits = ar->alg_maxbits;
8277c478bd9Sstevel@tonic-gate 
8287c478bd9Sstevel@tonic-gate 	for (i = 0; i < ipsec_nalgs[type]; i++) {
8297c478bd9Sstevel@tonic-gate 		if (known_algs[type][i].id == algid)
8307c478bd9Sstevel@tonic-gate 			break;
8317c478bd9Sstevel@tonic-gate 	}
8327c478bd9Sstevel@tonic-gate 
8337c478bd9Sstevel@tonic-gate 	if (i >= ipsec_nalgs[type]) {
8347c478bd9Sstevel@tonic-gate 		/*
8357c478bd9Sstevel@tonic-gate 		 * The kernel (where we populate known_algs from) doesn't
8367c478bd9Sstevel@tonic-gate 		 * return the id's associated with NONE algorithms so we
8377c478bd9Sstevel@tonic-gate 		 * test here if this was the reason the algorithm wasn't
8387c478bd9Sstevel@tonic-gate 		 * found before wrongly failing.
8397c478bd9Sstevel@tonic-gate 		 */
8407c478bd9Sstevel@tonic-gate 		if (((type == ESP_ENCR) && (algid == SADB_EALG_NONE)) ||
8417c478bd9Sstevel@tonic-gate 		    ((type == ESP_AUTH) && (algid == SADB_AALG_NONE)) ||
8427c478bd9Sstevel@tonic-gate 		    ((type == AH_AUTH) && (algid == SADB_AALG_NONE))) {
8437c478bd9Sstevel@tonic-gate 			return (B_TRUE);
8447c478bd9Sstevel@tonic-gate 		} else {
8457c478bd9Sstevel@tonic-gate 			return (B_FALSE); /* not found */
8467c478bd9Sstevel@tonic-gate 		}
8477c478bd9Sstevel@tonic-gate 	}
8487c478bd9Sstevel@tonic-gate 
8497c478bd9Sstevel@tonic-gate 	if ((minbits == 0) && (maxbits == 0))
8507c478bd9Sstevel@tonic-gate 		return (B_TRUE);
8517c478bd9Sstevel@tonic-gate 
8527c478bd9Sstevel@tonic-gate 	minbits = MAX(minbits, known_algs[type][i].minkeybits);
8537c478bd9Sstevel@tonic-gate 	maxbits = MIN(maxbits, known_algs[type][i].maxkeybits);
8547c478bd9Sstevel@tonic-gate 
8557c478bd9Sstevel@tonic-gate 	/* we could also check key increments here.. */
8567c478bd9Sstevel@tonic-gate 	return (minbits <= maxbits); /* non-null intersection */
8577c478bd9Sstevel@tonic-gate }
8587c478bd9Sstevel@tonic-gate 
8597c478bd9Sstevel@tonic-gate /*
8607c478bd9Sstevel@tonic-gate  * Inspired by uts/common/inet/spd.c:ipsec_act_wildcard_expand()
8617c478bd9Sstevel@tonic-gate  */
8627c478bd9Sstevel@tonic-gate 
8637c478bd9Sstevel@tonic-gate static struct spd_attribute *
8647c478bd9Sstevel@tonic-gate ips_act_wild_props_to_action(struct spd_attribute *ap,
8657c478bd9Sstevel@tonic-gate     uint32_t *rule_priorityp, uint16_t *act_cntp,
8667c478bd9Sstevel@tonic-gate     const ips_act_props_t *act_ptr)
8677c478bd9Sstevel@tonic-gate {
8687c478bd9Sstevel@tonic-gate 	ips_act_props_t tact = *act_ptr;
8697c478bd9Sstevel@tonic-gate 	boolean_t use_ah, use_esp, use_espa;
8707c478bd9Sstevel@tonic-gate 	boolean_t wild_auth, wild_encr, wild_eauth;
8717c478bd9Sstevel@tonic-gate 	uint_t	auth_alg, auth_idx, auth_min, auth_max;
8727c478bd9Sstevel@tonic-gate 	uint_t	eauth_alg, eauth_idx, eauth_min, eauth_max;
8737c478bd9Sstevel@tonic-gate 	uint_t  encr_alg, encr_idx, encr_min, encr_max;
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate 	use_ah = !!(act_ptr->iap_attr & SPD_APPLY_AH);
8767c478bd9Sstevel@tonic-gate 	use_esp = !!(act_ptr->iap_attr & SPD_APPLY_ESP);
8777c478bd9Sstevel@tonic-gate 	use_espa = !!(act_ptr->iap_attr & SPD_APPLY_ESPA);
8787c478bd9Sstevel@tonic-gate 	auth_alg = act_ptr->iap_aauth.alg_id;
8797c478bd9Sstevel@tonic-gate 	eauth_alg = act_ptr->iap_eauth.alg_id;
8807c478bd9Sstevel@tonic-gate 	encr_alg = act_ptr->iap_eencr.alg_id;
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate 	wild_auth = use_ah && (auth_alg == SADB_AALG_NONE);
8837c478bd9Sstevel@tonic-gate 	wild_eauth = use_espa && (eauth_alg == SADB_AALG_NONE);
8847c478bd9Sstevel@tonic-gate 	wild_encr = use_esp && (encr_alg == SADB_EALG_NONE);
8857c478bd9Sstevel@tonic-gate 
8867c478bd9Sstevel@tonic-gate 	auth_min = auth_max = auth_alg;
8877c478bd9Sstevel@tonic-gate 	eauth_min = eauth_max = eauth_alg;
8887c478bd9Sstevel@tonic-gate 	encr_min = encr_max = encr_alg;
8897c478bd9Sstevel@tonic-gate 
8907c478bd9Sstevel@tonic-gate 	/*
8917c478bd9Sstevel@tonic-gate 	 * set up for explosion.. for each dimension, expand output
8927c478bd9Sstevel@tonic-gate 	 * size by the explosion factor.
8937c478bd9Sstevel@tonic-gate 	 */
8947c478bd9Sstevel@tonic-gate 	if (wild_auth) {
8957c478bd9Sstevel@tonic-gate 		auth_min = 0;
8967c478bd9Sstevel@tonic-gate 		auth_max = ipsec_nalgs[AH_AUTH] - 1;
8977c478bd9Sstevel@tonic-gate 	}
8987c478bd9Sstevel@tonic-gate 	if (wild_eauth) {
8997c478bd9Sstevel@tonic-gate 		eauth_min = 0;
9007c478bd9Sstevel@tonic-gate 		eauth_max = ipsec_nalgs[ESP_AUTH] - 1;
9017c478bd9Sstevel@tonic-gate 	}
9027c478bd9Sstevel@tonic-gate 	if (wild_encr) {
9037c478bd9Sstevel@tonic-gate 		encr_min = 0;
9047c478bd9Sstevel@tonic-gate 		encr_max = ipsec_nalgs[ESP_ENCR] - 1;
9057c478bd9Sstevel@tonic-gate 	}
9067c478bd9Sstevel@tonic-gate 
9077c478bd9Sstevel@tonic-gate #define	WHICH_ALG(type, wild, idx) ((wild)?(known_algs[type][idx].id):(idx))
9087c478bd9Sstevel@tonic-gate 
9097c478bd9Sstevel@tonic-gate 	for (encr_idx = encr_min; encr_idx <= encr_max; encr_idx++) {
9107c478bd9Sstevel@tonic-gate 		encr_alg = WHICH_ALG(ESP_ENCR, wild_encr, encr_idx);
9117c478bd9Sstevel@tonic-gate 
9127c478bd9Sstevel@tonic-gate 		if (use_esp &&
9137c478bd9Sstevel@tonic-gate 		    !alg_rangecheck(ESP_ENCR, encr_alg, &act_ptr->iap_eencr))
9147c478bd9Sstevel@tonic-gate 			continue;
9157c478bd9Sstevel@tonic-gate 
9167c478bd9Sstevel@tonic-gate 		for (auth_idx = auth_min; auth_idx <= auth_max; auth_idx++) {
9177c478bd9Sstevel@tonic-gate 			auth_alg = WHICH_ALG(AH_AUTH, wild_auth, auth_idx);
9187c478bd9Sstevel@tonic-gate 
9197c478bd9Sstevel@tonic-gate 			if (use_ah &&
9207c478bd9Sstevel@tonic-gate 			    !alg_rangecheck(AH_AUTH, auth_alg,
921d5751483Smarkfen 			    &act_ptr->iap_aauth))
9227c478bd9Sstevel@tonic-gate 				continue;
9237c478bd9Sstevel@tonic-gate 
9247c478bd9Sstevel@tonic-gate 
9257c478bd9Sstevel@tonic-gate 			for (eauth_idx = eauth_min; eauth_idx <= eauth_max;
9267c478bd9Sstevel@tonic-gate 			    eauth_idx++) {
9277c478bd9Sstevel@tonic-gate 				eauth_alg = WHICH_ALG(ESP_AUTH, wild_eauth,
9287c478bd9Sstevel@tonic-gate 				    eauth_idx);
9297c478bd9Sstevel@tonic-gate 
9307c478bd9Sstevel@tonic-gate 				if (use_espa &&
9317c478bd9Sstevel@tonic-gate 				    !alg_rangecheck(ESP_AUTH, eauth_alg,
9327c478bd9Sstevel@tonic-gate 				    &act_ptr->iap_eauth))
9337c478bd9Sstevel@tonic-gate 					continue;
9347c478bd9Sstevel@tonic-gate 
9357c478bd9Sstevel@tonic-gate 				tact.iap_eencr.alg_id = encr_alg;
9367c478bd9Sstevel@tonic-gate 				tact.iap_eauth.alg_id = eauth_alg;
9377c478bd9Sstevel@tonic-gate 				tact.iap_aauth.alg_id = auth_alg;
9387c478bd9Sstevel@tonic-gate 
9397c478bd9Sstevel@tonic-gate 				(*act_cntp)++;
9407c478bd9Sstevel@tonic-gate 				ap = ips_act_props_to_action(ap,
9417c478bd9Sstevel@tonic-gate 				    rule_priorityp, &tact);
9427c478bd9Sstevel@tonic-gate 			}
9437c478bd9Sstevel@tonic-gate 		}
9447c478bd9Sstevel@tonic-gate 	}
9457c478bd9Sstevel@tonic-gate 
9467c478bd9Sstevel@tonic-gate #undef WHICH_ALG
9477c478bd9Sstevel@tonic-gate 
9487c478bd9Sstevel@tonic-gate 	return (ap);
9497c478bd9Sstevel@tonic-gate }
9507c478bd9Sstevel@tonic-gate 
9517c478bd9Sstevel@tonic-gate /* huge, but not safe since no length checking is done */
9527c478bd9Sstevel@tonic-gate #define	MAX_POL_MSG_LEN 16384
9537c478bd9Sstevel@tonic-gate 
9547c478bd9Sstevel@tonic-gate 
9557c478bd9Sstevel@tonic-gate /*
9567c478bd9Sstevel@tonic-gate  * hand in some ips_conf_t's, get back an
9577c478bd9Sstevel@tonic-gate  * iovec of pfpol messages.
9587c478bd9Sstevel@tonic-gate  * this function converts the internal ips_conf_t into
9597c478bd9Sstevel@tonic-gate  * a form that pf_pol can use.
9607c478bd9Sstevel@tonic-gate  * return 0 on success, 1 on failure
9617c478bd9Sstevel@tonic-gate  */
9627c478bd9Sstevel@tonic-gate static int
9637c478bd9Sstevel@tonic-gate ips_conf_to_pfpol_msg(int ipsec_cmd, ips_conf_t *inConf, int num_ips,
9647c478bd9Sstevel@tonic-gate     struct iovec *msg)
9657c478bd9Sstevel@tonic-gate {
9667c478bd9Sstevel@tonic-gate 	int i;
9677c478bd9Sstevel@tonic-gate 	ips_conf_t *conf;
9687c478bd9Sstevel@tonic-gate 	uint64_t *scratch = NULL;
9697c478bd9Sstevel@tonic-gate 
9707c478bd9Sstevel@tonic-gate 	for (i = 0; i < num_ips; i++) {
9717c478bd9Sstevel@tonic-gate 		uint16_t *msg_len;
9727c478bd9Sstevel@tonic-gate 		uint16_t act_cnt = 0;
9737c478bd9Sstevel@tonic-gate 		uint64_t *next = NULL;
9747c478bd9Sstevel@tonic-gate 		spd_msg_t *spd_msg;
9757c478bd9Sstevel@tonic-gate 		spd_address_t *spd_address;
9767c478bd9Sstevel@tonic-gate 		struct spd_rule *spd_rule;
9777c478bd9Sstevel@tonic-gate 		struct spd_proto *spd_proto;
9787c478bd9Sstevel@tonic-gate 		struct spd_portrange *spd_portrange;
9797c478bd9Sstevel@tonic-gate 		struct spd_ext_actions *spd_ext_actions;
9807c478bd9Sstevel@tonic-gate 		struct spd_attribute *ap;
9817c478bd9Sstevel@tonic-gate 		struct spd_typecode *spd_typecode;
9828810c16bSdanmcd 		spd_if_t *spd_if;
9837c478bd9Sstevel@tonic-gate 		ips_act_props_t *act_ptr;
9847c478bd9Sstevel@tonic-gate 		uint32_t rule_priority = 0;
9857c478bd9Sstevel@tonic-gate 
9867c478bd9Sstevel@tonic-gate 		scratch = calloc(1, MAX_POL_MSG_LEN);
9877c478bd9Sstevel@tonic-gate 		msg[i].iov_base = (char *)scratch;
9887c478bd9Sstevel@tonic-gate 		if (scratch == NULL) {
9897c478bd9Sstevel@tonic-gate 			warn(gettext("memory"));
9907c478bd9Sstevel@tonic-gate 			return (1);
9917c478bd9Sstevel@tonic-gate 		}
9927c478bd9Sstevel@tonic-gate 		conf = &(inConf[i]);
9937c478bd9Sstevel@tonic-gate 
9947c478bd9Sstevel@tonic-gate 		spd_msg = (spd_msg_t *)scratch;
9957c478bd9Sstevel@tonic-gate 		next = (uint64_t *)&(spd_msg[1]);
9967c478bd9Sstevel@tonic-gate 
9977c478bd9Sstevel@tonic-gate 		msg_len = &(spd_msg->spd_msg_len);
9987c478bd9Sstevel@tonic-gate 
9997c478bd9Sstevel@tonic-gate 		spd_msg->spd_msg_version = PF_POLICY_V1;
10007c478bd9Sstevel@tonic-gate 		spd_msg->spd_msg_pid = getpid();
10017c478bd9Sstevel@tonic-gate 		spd_msg->spd_msg_seq = ++seq_cnt;
10027c478bd9Sstevel@tonic-gate 
10037c478bd9Sstevel@tonic-gate 		switch (ipsec_cmd) {
10047c478bd9Sstevel@tonic-gate 		case SPD_ADDRULE:
10057c478bd9Sstevel@tonic-gate 			spd_msg->spd_msg_type = SPD_ADDRULE;
10067c478bd9Sstevel@tonic-gate 			break;
10077c478bd9Sstevel@tonic-gate 
10087c478bd9Sstevel@tonic-gate 		default:
10097c478bd9Sstevel@tonic-gate 			warnx("%s %d", gettext("bad command:"), ipsec_cmd);
10107c478bd9Sstevel@tonic-gate 			spd_msg->spd_msg_type = SPD_ADDRULE;
10117c478bd9Sstevel@tonic-gate 			break;
10127c478bd9Sstevel@tonic-gate 		}
10137c478bd9Sstevel@tonic-gate 
10147c478bd9Sstevel@tonic-gate 		/*
10157c478bd9Sstevel@tonic-gate 		 * SELECTOR
10167c478bd9Sstevel@tonic-gate 		 */
10177c478bd9Sstevel@tonic-gate 
10187c478bd9Sstevel@tonic-gate 		spd_msg->spd_msg_spdid = SPD_STANDBY;
10197c478bd9Sstevel@tonic-gate 
10207c478bd9Sstevel@tonic-gate 		/* rule */
10217c478bd9Sstevel@tonic-gate 		spd_rule = (struct spd_rule *)next;
10227c478bd9Sstevel@tonic-gate 
10237c478bd9Sstevel@tonic-gate 		spd_rule->spd_rule_len = SPD_8TO64(sizeof (struct spd_rule));
10247c478bd9Sstevel@tonic-gate 		spd_rule->spd_rule_type = SPD_EXT_RULE;
10257c478bd9Sstevel@tonic-gate 		spd_rule->spd_rule_flags = conf->ips_dir;
10268810c16bSdanmcd 		if (conf->ips_tunnel)
10278810c16bSdanmcd 			spd_rule->spd_rule_flags |= SPD_RULE_FLAG_TUNNEL;
10287c478bd9Sstevel@tonic-gate 
10297c478bd9Sstevel@tonic-gate 		next = (uint64_t *)&(spd_rule[1]);
10307c478bd9Sstevel@tonic-gate 
10317c478bd9Sstevel@tonic-gate 		/* proto */
10327c478bd9Sstevel@tonic-gate 		if (conf->ips_ulp_prot != 0) {
10337c478bd9Sstevel@tonic-gate 			spd_proto = (struct spd_proto *)next;
10347c478bd9Sstevel@tonic-gate 			spd_proto->spd_proto_len =
1035d5751483Smarkfen 			    SPD_8TO64(sizeof (struct spd_proto));
10367c478bd9Sstevel@tonic-gate 			spd_proto->spd_proto_exttype = SPD_EXT_PROTO;
10377c478bd9Sstevel@tonic-gate 			spd_proto->spd_proto_number = conf->ips_ulp_prot;
10387c478bd9Sstevel@tonic-gate 			next = (uint64_t *)&(spd_proto[1]);
10397c478bd9Sstevel@tonic-gate 		}
10407c478bd9Sstevel@tonic-gate 
10418810c16bSdanmcd 		/* tunnel */
10428810c16bSdanmcd 		if (conf->has_tunnel != 0) {
10438810c16bSdanmcd 			spd_if = (spd_if_t *)next;
10448810c16bSdanmcd 			spd_if->spd_if_len =
10458810c16bSdanmcd 			    SPD_8TO64(P2ROUNDUP(strlen(tunif) + 1, 8) +
10468810c16bSdanmcd 			    sizeof (spd_if_t));
10478810c16bSdanmcd 			spd_if->spd_if_exttype = SPD_EXT_TUN_NAME;
10488810c16bSdanmcd 			(void) strlcpy((char *)spd_if->spd_if_name, tunif,
1049d5751483Smarkfen 			    TUNNAMEMAXLEN);
10508810c16bSdanmcd 			next = (uint64_t *)(spd_if) + spd_if->spd_if_len;
10518810c16bSdanmcd 		}
10528810c16bSdanmcd 
10537c478bd9Sstevel@tonic-gate 		/* icmp type/code */
10547c478bd9Sstevel@tonic-gate 		if (conf->ips_ulp_prot == IPPROTO_ICMP ||
10557c478bd9Sstevel@tonic-gate 		    conf->ips_ulp_prot == IPPROTO_ICMPV6) {
10567c478bd9Sstevel@tonic-gate 			if (conf->has_type) {
10577c478bd9Sstevel@tonic-gate 				spd_typecode = (struct spd_typecode *)next;
10587c478bd9Sstevel@tonic-gate 				spd_typecode->spd_typecode_len =
10597c478bd9Sstevel@tonic-gate 				    SPD_8TO64(sizeof (struct spd_typecode));
10607c478bd9Sstevel@tonic-gate 				spd_typecode->spd_typecode_exttype =
10617c478bd9Sstevel@tonic-gate 				    SPD_EXT_ICMP_TYPECODE;
10627c478bd9Sstevel@tonic-gate 				spd_typecode->spd_typecode_type =
10637c478bd9Sstevel@tonic-gate 				    conf->ips_icmp_type;
10647c478bd9Sstevel@tonic-gate 				spd_typecode->spd_typecode_type_end =
10657c478bd9Sstevel@tonic-gate 				    conf->ips_icmp_type_end;
10667c478bd9Sstevel@tonic-gate 				if (conf->has_code) {
10677c478bd9Sstevel@tonic-gate 					spd_typecode->spd_typecode_code =
10687c478bd9Sstevel@tonic-gate 					    conf->ips_icmp_code;
10697c478bd9Sstevel@tonic-gate 					spd_typecode->spd_typecode_code_end =
10707c478bd9Sstevel@tonic-gate 					    conf->ips_icmp_code_end;
10717c478bd9Sstevel@tonic-gate 				} else {
10727c478bd9Sstevel@tonic-gate 					spd_typecode->spd_typecode_code = 255;
10737c478bd9Sstevel@tonic-gate 					spd_typecode->spd_typecode_code_end
10747c478bd9Sstevel@tonic-gate 					    = 255;
10757c478bd9Sstevel@tonic-gate 				}
10767c478bd9Sstevel@tonic-gate 				next = (uint64_t *)&(spd_typecode[1]);
10777c478bd9Sstevel@tonic-gate 			}
10787c478bd9Sstevel@tonic-gate 		}
10797c478bd9Sstevel@tonic-gate 
10807c478bd9Sstevel@tonic-gate 		/* src port */
10817c478bd9Sstevel@tonic-gate 		if (conf->ips_src_port_min != 0 ||
10827c478bd9Sstevel@tonic-gate 		    conf->ips_src_port_max != 0) {
10837c478bd9Sstevel@tonic-gate 			spd_portrange = (struct spd_portrange *)next;
10847c478bd9Sstevel@tonic-gate 			spd_portrange->spd_ports_len =
1085d5751483Smarkfen 			    SPD_8TO64(sizeof (struct spd_portrange));
10867c478bd9Sstevel@tonic-gate 			spd_portrange->spd_ports_exttype =
1087d5751483Smarkfen 			    (conf->swap)?SPD_EXT_REMPORT:SPD_EXT_LCLPORT;
10887c478bd9Sstevel@tonic-gate 			spd_portrange->spd_ports_minport =
1089d5751483Smarkfen 			    conf->ips_src_port_min;
10907c478bd9Sstevel@tonic-gate 			spd_portrange->spd_ports_maxport =
1091d5751483Smarkfen 			    conf->ips_src_port_max;
10927c478bd9Sstevel@tonic-gate 			next = (uint64_t *)&(spd_portrange[1]);
10937c478bd9Sstevel@tonic-gate 		}
10947c478bd9Sstevel@tonic-gate 		/* dst port */
10957c478bd9Sstevel@tonic-gate 		if (conf->ips_dst_port_min != 0 ||
10967c478bd9Sstevel@tonic-gate 		    conf->ips_dst_port_max != 0) {
10977c478bd9Sstevel@tonic-gate 			spd_portrange = (struct spd_portrange *)next;
10987c478bd9Sstevel@tonic-gate 			spd_portrange->spd_ports_len =
1099d5751483Smarkfen 			    SPD_8TO64(sizeof (struct spd_portrange));
11007c478bd9Sstevel@tonic-gate 			spd_portrange->spd_ports_exttype =
1101d5751483Smarkfen 			    (conf->swap)?SPD_EXT_LCLPORT:SPD_EXT_REMPORT;
11027c478bd9Sstevel@tonic-gate 			spd_portrange->spd_ports_minport =
1103d5751483Smarkfen 			    conf->ips_dst_port_min;
11047c478bd9Sstevel@tonic-gate 			spd_portrange->spd_ports_maxport =
1105d5751483Smarkfen 			    conf->ips_dst_port_max;
11067c478bd9Sstevel@tonic-gate 			next = (uint64_t *)&(spd_portrange[1]);
11077c478bd9Sstevel@tonic-gate 		}
11087c478bd9Sstevel@tonic-gate 
11097c478bd9Sstevel@tonic-gate 		/* saddr */
11107c478bd9Sstevel@tonic-gate 		if (conf->has_saddr) {
11117c478bd9Sstevel@tonic-gate 			spd_address = (spd_address_t *)next;
11127c478bd9Sstevel@tonic-gate 			next = (uint64_t *)(spd_address + 1);
11137c478bd9Sstevel@tonic-gate 
11147c478bd9Sstevel@tonic-gate 			spd_address->spd_address_exttype =
1115d5751483Smarkfen 			    (conf->swap)?SPD_EXT_REMADDR:SPD_EXT_LCLADDR;
11167c478bd9Sstevel@tonic-gate 			spd_address->spd_address_prefixlen =
1117d5751483Smarkfen 			    conf->ips_src_mask_len;
11187c478bd9Sstevel@tonic-gate 
11197c478bd9Sstevel@tonic-gate 			if (conf->ips_isv4) {
11207c478bd9Sstevel@tonic-gate 				spd_address->spd_address_af = AF_INET;
11217c478bd9Sstevel@tonic-gate 				(void) memcpy(next, &(conf->ips_src_addr),
1122d5751483Smarkfen 				    sizeof (ipaddr_t));
11237c478bd9Sstevel@tonic-gate 				spd_address->spd_address_len = 2;
11247c478bd9Sstevel@tonic-gate 				next += SPD_8TO64(sizeof (ipaddr_t) + 4);
11257c478bd9Sstevel@tonic-gate 				if (!conf->has_smask)
11267c478bd9Sstevel@tonic-gate 					spd_address->spd_address_prefixlen = 32;
11277c478bd9Sstevel@tonic-gate 			} else {
11287c478bd9Sstevel@tonic-gate 				spd_address->spd_address_af = AF_INET6;
11297c478bd9Sstevel@tonic-gate 				(void) memcpy(next, &(conf->ips_src_addr_v6),
11307c478bd9Sstevel@tonic-gate 				    sizeof (in6_addr_t));
11317c478bd9Sstevel@tonic-gate 				spd_address->spd_address_len = 3;
11327c478bd9Sstevel@tonic-gate 				next += SPD_8TO64(sizeof (in6_addr_t));
11337c478bd9Sstevel@tonic-gate 				if (!conf->has_smask)
11347c478bd9Sstevel@tonic-gate 					spd_address->spd_address_prefixlen
1135d5751483Smarkfen 					    = 128;
11367c478bd9Sstevel@tonic-gate 			}
11377c478bd9Sstevel@tonic-gate 		}
11387c478bd9Sstevel@tonic-gate 
11397c478bd9Sstevel@tonic-gate 		/* daddr */
11407c478bd9Sstevel@tonic-gate 		if (conf->has_daddr) {
11417c478bd9Sstevel@tonic-gate 			spd_address = (spd_address_t *)next;
11427c478bd9Sstevel@tonic-gate 
11437c478bd9Sstevel@tonic-gate 			next = (uint64_t *)(spd_address + 1);
11447c478bd9Sstevel@tonic-gate 
11457c478bd9Sstevel@tonic-gate 			spd_address->spd_address_exttype =
1146d5751483Smarkfen 			    (conf->swap)?SPD_EXT_LCLADDR:SPD_EXT_REMADDR;
11477c478bd9Sstevel@tonic-gate 			spd_address->spd_address_prefixlen =
1148d5751483Smarkfen 			    conf->ips_dst_mask_len;
11497c478bd9Sstevel@tonic-gate 
11507c478bd9Sstevel@tonic-gate 			if (conf->ips_isv4) {
11517c478bd9Sstevel@tonic-gate 				spd_address->spd_address_af = AF_INET;
11527c478bd9Sstevel@tonic-gate 				(void) memcpy(next, &conf->ips_dst_addr,
11537c478bd9Sstevel@tonic-gate 				    sizeof (ipaddr_t));
11547c478bd9Sstevel@tonic-gate 				spd_address->spd_address_len = 2;
11557c478bd9Sstevel@tonic-gate 				/* "+ 4" below is for padding. */
11567c478bd9Sstevel@tonic-gate 				next += SPD_8TO64(sizeof (ipaddr_t) + 4);
11577c478bd9Sstevel@tonic-gate 				if (!conf->has_dmask)
11587c478bd9Sstevel@tonic-gate 					spd_address->spd_address_prefixlen = 32;
11597c478bd9Sstevel@tonic-gate 			} else {
11607c478bd9Sstevel@tonic-gate 				spd_address->spd_address_af = AF_INET6;
11617c478bd9Sstevel@tonic-gate 				(void) memcpy(next, &(conf->ips_dst_addr_v6),
11627c478bd9Sstevel@tonic-gate 				    sizeof (in6_addr_t));
11637c478bd9Sstevel@tonic-gate 				spd_address->spd_address_len = 3;
11647c478bd9Sstevel@tonic-gate 				next += SPD_8TO64(sizeof (in6_addr_t));
11657c478bd9Sstevel@tonic-gate 				if (!conf->has_dmask)
11667c478bd9Sstevel@tonic-gate 					spd_address->spd_address_prefixlen
1167d5751483Smarkfen 					    = 128;
11687c478bd9Sstevel@tonic-gate 			}
11697c478bd9Sstevel@tonic-gate 		}
11707c478bd9Sstevel@tonic-gate 
11717c478bd9Sstevel@tonic-gate 		/* actions */
11727c478bd9Sstevel@tonic-gate 		spd_ext_actions = (struct spd_ext_actions *)next;
11737c478bd9Sstevel@tonic-gate 
11747c478bd9Sstevel@tonic-gate 		spd_ext_actions->spd_actions_exttype = SPD_EXT_ACTION;
11757c478bd9Sstevel@tonic-gate 
11767c478bd9Sstevel@tonic-gate 		act_ptr = conf->ips_acts;
11777c478bd9Sstevel@tonic-gate 		ap = (struct spd_attribute *)(&spd_ext_actions[1]);
11787c478bd9Sstevel@tonic-gate 
11797c478bd9Sstevel@tonic-gate 		rule_priority = priority--;
11807c478bd9Sstevel@tonic-gate 
11817c478bd9Sstevel@tonic-gate 		for (act_ptr = conf->ips_acts; act_ptr != NULL;
11827c478bd9Sstevel@tonic-gate 		    act_ptr = act_ptr->iap_next) {
11837c478bd9Sstevel@tonic-gate 			ap = ips_act_wild_props_to_action(ap, &rule_priority,
11847c478bd9Sstevel@tonic-gate 			    &act_cnt, act_ptr);
11857c478bd9Sstevel@tonic-gate 		}
11867c478bd9Sstevel@tonic-gate 		ap[-1].spd_attr_tag = SPD_ATTR_END;
11877c478bd9Sstevel@tonic-gate 
11887c478bd9Sstevel@tonic-gate 		next = (uint64_t *)ap;
11897c478bd9Sstevel@tonic-gate 
11907c478bd9Sstevel@tonic-gate 		spd_rule->spd_rule_priority = rule_priority;
11917c478bd9Sstevel@tonic-gate 
11927c478bd9Sstevel@tonic-gate 		msg[i].iov_len = (uintptr_t)next - (uintptr_t)msg[i].iov_base;
11937c478bd9Sstevel@tonic-gate 		*msg_len = (uint16_t)SPD_8TO64(msg[i].iov_len);
11947c478bd9Sstevel@tonic-gate 		spd_ext_actions->spd_actions_count = act_cnt;
11957c478bd9Sstevel@tonic-gate 		spd_ext_actions->spd_actions_len =
11967c478bd9Sstevel@tonic-gate 		    SPD_8TO64((uintptr_t)next - (uintptr_t)spd_ext_actions);
11977c478bd9Sstevel@tonic-gate #ifdef DEBUG_HEAVY
11987c478bd9Sstevel@tonic-gate 		printf("pfpol msg len in uint64_t's = %d\n", *msg_len);
11997c478bd9Sstevel@tonic-gate 		printf("pfpol test_len in bytes = %d\n", msg[i].iov_len);
12007c478bd9Sstevel@tonic-gate 		pfpol_msg_dump((spd_msg_t *)scratch,
12017c478bd9Sstevel@tonic-gate 		    "ips_conf_to_pfpol_msg");
12027c478bd9Sstevel@tonic-gate #endif
12037c478bd9Sstevel@tonic-gate 	}
12047c478bd9Sstevel@tonic-gate 
12057c478bd9Sstevel@tonic-gate #undef ATTR
12067c478bd9Sstevel@tonic-gate 	return (0);
12077c478bd9Sstevel@tonic-gate }
12087c478bd9Sstevel@tonic-gate 
12097c478bd9Sstevel@tonic-gate static int
12107c478bd9Sstevel@tonic-gate get_pf_pol_socket(void)
12117c478bd9Sstevel@tonic-gate {
12127c478bd9Sstevel@tonic-gate 	int s = socket(PF_POLICY, SOCK_RAW, PF_POLICY_V1);
12137c478bd9Sstevel@tonic-gate 	if (s < 0) {
1214e3320f40Smarkfen 		if (errno == EPERM) {
1215e3320f40Smarkfen 			EXIT_BADPERM("Insufficient privileges to open "
1216e3320f40Smarkfen 			    "PF_POLICY socket.");
1217e3320f40Smarkfen 		} else {
1218e3320f40Smarkfen 			warn(gettext("(loading pf_policy) socket:"));
1219e3320f40Smarkfen 		}
12207c478bd9Sstevel@tonic-gate 	}
12217c478bd9Sstevel@tonic-gate 
12227c478bd9Sstevel@tonic-gate 	return (s);
12237c478bd9Sstevel@tonic-gate }
12247c478bd9Sstevel@tonic-gate 
12257c478bd9Sstevel@tonic-gate 
12267c478bd9Sstevel@tonic-gate static int
12278810c16bSdanmcd send_pf_pol_message(int ipsec_cmd, ips_conf_t *conf, int *diag)
12287c478bd9Sstevel@tonic-gate {
12297c478bd9Sstevel@tonic-gate 	int retval;
12307c478bd9Sstevel@tonic-gate 	int cnt;
12317c478bd9Sstevel@tonic-gate 	int total_len;
12327c478bd9Sstevel@tonic-gate 	struct iovec polmsg;
12337c478bd9Sstevel@tonic-gate 	spd_msg_t *return_buf;
12347c478bd9Sstevel@tonic-gate 	spd_ext_t *exts[SPD_EXT_MAX+1];
12357c478bd9Sstevel@tonic-gate 	int fd = get_pf_pol_socket();
12367c478bd9Sstevel@tonic-gate 
12378810c16bSdanmcd 	*diag = 0;
12388810c16bSdanmcd 
12397c478bd9Sstevel@tonic-gate 	if (fd < 0)
124043c889d3Smarkfen 		return (EBADF);
12417c478bd9Sstevel@tonic-gate 
12427c478bd9Sstevel@tonic-gate 	retval = ips_conf_to_pfpol_msg(ipsec_cmd, conf, 1, &polmsg);
12437c478bd9Sstevel@tonic-gate 
12447c478bd9Sstevel@tonic-gate 	if (retval) {
12457c478bd9Sstevel@tonic-gate 		(void) close(fd);
124643c889d3Smarkfen 		return (ENOMEM);
12477c478bd9Sstevel@tonic-gate 	}
12487c478bd9Sstevel@tonic-gate 
12497c478bd9Sstevel@tonic-gate 	total_len = polmsg.iov_len;
12507c478bd9Sstevel@tonic-gate 
12517c478bd9Sstevel@tonic-gate 	cnt = writev(fd, &polmsg, 1);
12527c478bd9Sstevel@tonic-gate 
12537c478bd9Sstevel@tonic-gate #ifdef DEBUG_HEAVY
12547c478bd9Sstevel@tonic-gate 	(void) printf("cnt = %d\n", cnt);
12557c478bd9Sstevel@tonic-gate #endif
12567c478bd9Sstevel@tonic-gate 	if (cnt < 0) {
12577c478bd9Sstevel@tonic-gate 		warn(gettext("pf_pol write"));
12587c478bd9Sstevel@tonic-gate 	} else {
12597c478bd9Sstevel@tonic-gate 		return_buf = (spd_msg_t *)calloc(total_len, 1);
12607c478bd9Sstevel@tonic-gate 
12617c478bd9Sstevel@tonic-gate 		if (return_buf == NULL) {
12627c478bd9Sstevel@tonic-gate 			warn(gettext("memory"));
12637c478bd9Sstevel@tonic-gate 		} else {
12647c478bd9Sstevel@tonic-gate 			cnt = read(fd, (void*)return_buf, total_len);
12657c478bd9Sstevel@tonic-gate #ifdef	DEBUG_HEAVY
12667c478bd9Sstevel@tonic-gate 			(void) printf("pf_pol read: cnt = %d(%d)\n", cnt,
12677c478bd9Sstevel@tonic-gate 			    total_len);
12687c478bd9Sstevel@tonic-gate #endif
12697c478bd9Sstevel@tonic-gate 
12707c478bd9Sstevel@tonic-gate 			if (cnt > 8 && return_buf->spd_msg_errno) {
12718810c16bSdanmcd 				*diag = return_buf->spd_msg_diagnostic;
127243c889d3Smarkfen 				if (!ipsecconf_qflag) {
127343c889d3Smarkfen 					warnx("%s: %s",
12748810c16bSdanmcd 					    gettext("Kernel returned"),
12758810c16bSdanmcd 					    sys_error_message(
127643c889d3Smarkfen 					    return_buf->spd_msg_errno));
127743c889d3Smarkfen 				}
12788810c16bSdanmcd 				if (*diag != 0)
12798810c16bSdanmcd 					(void) printf(gettext(
12808810c16bSdanmcd 					    "\t(spdsock diagnostic: %s)\n"),
12818810c16bSdanmcd 					    spdsock_diag(*diag));
12827c478bd9Sstevel@tonic-gate #ifdef DEBUG_HEAVY
12837c478bd9Sstevel@tonic-gate 				pfpol_msg_dump((spd_msg_t *)polmsg.iov_base,
12847c478bd9Sstevel@tonic-gate 				    "message in");
12857c478bd9Sstevel@tonic-gate 				pfpol_msg_dump(return_buf,
12867c478bd9Sstevel@tonic-gate 				    "send_pf_pol_message");
12877c478bd9Sstevel@tonic-gate #endif
128843c889d3Smarkfen 				retval = return_buf->spd_msg_errno;
12897c478bd9Sstevel@tonic-gate 				free(return_buf);
12907c478bd9Sstevel@tonic-gate 				free(polmsg.iov_base);
12917c478bd9Sstevel@tonic-gate 				(void) close(fd);
129243c889d3Smarkfen 				return (retval);
12937c478bd9Sstevel@tonic-gate 			}
12947c478bd9Sstevel@tonic-gate 
12957c478bd9Sstevel@tonic-gate 			retval = spdsock_get_ext(exts, return_buf,
12967c478bd9Sstevel@tonic-gate 			    return_buf->spd_msg_len, NULL, 0);
12977c478bd9Sstevel@tonic-gate 			/* ignore retval */
12987c478bd9Sstevel@tonic-gate 
12997c478bd9Sstevel@tonic-gate 			if (exts[SPD_EXT_RULE]) {
13007c478bd9Sstevel@tonic-gate 				conf->ips_policy_index =
13017c478bd9Sstevel@tonic-gate 				    ((struct spd_rule *)
1302d5751483Smarkfen 				    exts[SPD_EXT_RULE])->spd_rule_index;
13037c478bd9Sstevel@tonic-gate 
13047c478bd9Sstevel@tonic-gate 				if (add_index(conf->ips_policy_index)) {
13057c478bd9Sstevel@tonic-gate 					free(return_buf);
13067c478bd9Sstevel@tonic-gate 					free(polmsg.iov_base);
13077c478bd9Sstevel@tonic-gate 					(void) close(fd);
130843c889d3Smarkfen 					return (ENOMEM);
13097c478bd9Sstevel@tonic-gate 				}
13107c478bd9Sstevel@tonic-gate 			}
13117c478bd9Sstevel@tonic-gate 
13127c478bd9Sstevel@tonic-gate 			free(return_buf);
13137c478bd9Sstevel@tonic-gate 		}
13147c478bd9Sstevel@tonic-gate 	}
13157c478bd9Sstevel@tonic-gate 
13167c478bd9Sstevel@tonic-gate 	free(polmsg.iov_base);
13177c478bd9Sstevel@tonic-gate 	(void) close(fd);
13187c478bd9Sstevel@tonic-gate 
13197c478bd9Sstevel@tonic-gate 	return (0);
13207c478bd9Sstevel@tonic-gate 
13217c478bd9Sstevel@tonic-gate }
13227c478bd9Sstevel@tonic-gate 
13237c478bd9Sstevel@tonic-gate int
13247c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
13257c478bd9Sstevel@tonic-gate {
13267c478bd9Sstevel@tonic-gate 	int ret, flushret;
13277c478bd9Sstevel@tonic-gate 	int c;
13287c478bd9Sstevel@tonic-gate 	int index;
1329e3320f40Smarkfen 	boolean_t smf_managed;
1330e3320f40Smarkfen 	boolean_t just_check = B_FALSE;
1331e3320f40Smarkfen 
1332e3320f40Smarkfen 	char *smf_warning = gettext(
1333d5751483Smarkfen 	    "\n\tIPsec policy should be managed using smf(5). Modifying\n"
1334d5751483Smarkfen 	    "\tthe IPsec policy from the command line while the 'policy'\n"
1335d5751483Smarkfen 	    "\tservice is enabled could result in an inconsistent\n"
1336d5751483Smarkfen 	    "\tsecurity policy.\n\n");
1337e3320f40Smarkfen 
1338e3320f40Smarkfen 	flushret = 0;
13397c478bd9Sstevel@tonic-gate 
13407c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
13417c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
13427c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
13437c478bd9Sstevel@tonic-gate #endif
13447c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
13457c478bd9Sstevel@tonic-gate 
13467c478bd9Sstevel@tonic-gate 	openlog("ipsecconf", LOG_CONS, LOG_AUTH);
13477c478bd9Sstevel@tonic-gate 
13487c478bd9Sstevel@tonic-gate 	/*
13497c478bd9Sstevel@tonic-gate 	 * We don't immediately check for privilege here. This is done by IP
13507c478bd9Sstevel@tonic-gate 	 * when we open /dev/ip below.
13517c478bd9Sstevel@tonic-gate 	 */
13527c478bd9Sstevel@tonic-gate 
13537c478bd9Sstevel@tonic-gate 	if (argc == 1) {
13547c478bd9Sstevel@tonic-gate 		cmd = IPSEC_CONF_VIEW;
13557c478bd9Sstevel@tonic-gate 		goto done;
13567c478bd9Sstevel@tonic-gate 	}
1357e3320f40Smarkfen 	my_fmri = getenv("SMF_FMRI");
1358e3320f40Smarkfen 	if (my_fmri == NULL)
1359e3320f40Smarkfen 		smf_managed = B_FALSE;
1360e3320f40Smarkfen 	else
1361e3320f40Smarkfen 		smf_managed = B_TRUE;
1362e3320f40Smarkfen 
1363e3320f40Smarkfen 	while ((c = getopt(argc, argv, "nlfLFa:qd:r:i:c:")) != EOF) {
13647c478bd9Sstevel@tonic-gate 		switch (c) {
13658810c16bSdanmcd 		case 'F':
13668810c16bSdanmcd 			if (interface_name != NULL) {
1367e3320f40Smarkfen 				USAGE();
1368e3320f40Smarkfen 				EXIT_FATAL("interface name not required.");
13698810c16bSdanmcd 			}
13708810c16bSdanmcd 			/* Apply to all policy heads - global and tunnels. */
13718810c16bSdanmcd 			interface_name = &all_polheads;
13728810c16bSdanmcd 			/* FALLTHRU */
13737c478bd9Sstevel@tonic-gate 		case 'f':
13747c478bd9Sstevel@tonic-gate 			/* Only one command at a time */
13757c478bd9Sstevel@tonic-gate 			if (cmd != 0) {
1376e3320f40Smarkfen 				USAGE();
1377e3320f40Smarkfen 				EXIT_FATAL("Multiple commands specified");
13787c478bd9Sstevel@tonic-gate 			}
13797c478bd9Sstevel@tonic-gate 			cmd = IPSEC_CONF_FLUSH;
13807c478bd9Sstevel@tonic-gate 			break;
13818810c16bSdanmcd 		case 'L':
13828810c16bSdanmcd 			if (interface_name != NULL) {
1383e3320f40Smarkfen 				USAGE();
1384e3320f40Smarkfen 				EXIT_FATAL("interface name not required.");
13858810c16bSdanmcd 			}
13868810c16bSdanmcd 			/* Apply to all policy heads - global and tunnels. */
13878810c16bSdanmcd 			interface_name = &all_polheads;
13888810c16bSdanmcd 			/* FALLTHRU */
13897c478bd9Sstevel@tonic-gate 		case 'l':
13907c478bd9Sstevel@tonic-gate 			/* Only one command at a time */
13917c478bd9Sstevel@tonic-gate 			if (cmd != 0) {
1392e3320f40Smarkfen 				USAGE();
1393e3320f40Smarkfen 				EXIT_FATAL("Multiple commands specified");
13947c478bd9Sstevel@tonic-gate 			}
13957c478bd9Sstevel@tonic-gate 			cmd = IPSEC_CONF_LIST;
13967c478bd9Sstevel@tonic-gate 			break;
1397e3320f40Smarkfen 		case 'c':
1398e3320f40Smarkfen 			just_check = B_TRUE;
1399e3320f40Smarkfen 			ipsecconf_qflag++;
1400e3320f40Smarkfen 			/* FALLTHRU */
14017c478bd9Sstevel@tonic-gate 		case 'a':
14028810c16bSdanmcd 			/* Only one command at a time, and no interface name */
14038810c16bSdanmcd 			if (cmd != 0 || interface_name != NULL) {
1404e3320f40Smarkfen 				USAGE();
1405e3320f40Smarkfen 				EXIT_FATAL("Multiple commands or interface "
1406e3320f40Smarkfen 				    "not required.");
14077c478bd9Sstevel@tonic-gate 			}
14087c478bd9Sstevel@tonic-gate 			cmd = IPSEC_CONF_ADD;
14097c478bd9Sstevel@tonic-gate 			filename = optarg;
14107c478bd9Sstevel@tonic-gate 			break;
14117c478bd9Sstevel@tonic-gate 		case 'd':
14128810c16bSdanmcd 			/*
14138810c16bSdanmcd 			 * Only one command at a time.  Interface name is
14148810c16bSdanmcd 			 * optional.
14158810c16bSdanmcd 			 */
14167c478bd9Sstevel@tonic-gate 			if (cmd != 0) {
1417e3320f40Smarkfen 				USAGE();
1418e3320f40Smarkfen 				EXIT_FATAL("Multiple commands specified");
14197c478bd9Sstevel@tonic-gate 			}
14207c478bd9Sstevel@tonic-gate 			cmd = IPSEC_CONF_DEL;
14218810c16bSdanmcd 			index = parse_index(optarg, NULL);
14227c478bd9Sstevel@tonic-gate 			break;
14237c478bd9Sstevel@tonic-gate 		case 'n' :
14247c478bd9Sstevel@tonic-gate 			ipsecconf_nflag++;
14257c478bd9Sstevel@tonic-gate 			break;
14267c478bd9Sstevel@tonic-gate 		case 'q' :
14277c478bd9Sstevel@tonic-gate 			ipsecconf_qflag++;
14287c478bd9Sstevel@tonic-gate 			break;
14297c478bd9Sstevel@tonic-gate 		case 'r' :
14308810c16bSdanmcd 			/* Only one command at a time, and no interface name */
14318810c16bSdanmcd 			if (cmd != 0 || interface_name != NULL) {
1432e3320f40Smarkfen 				USAGE();
1433e3320f40Smarkfen 				EXIT_FATAL("Multiple commands or interface "
1434e3320f40Smarkfen 				    "not required.");
14357c478bd9Sstevel@tonic-gate 			}
14367c478bd9Sstevel@tonic-gate 			cmd = IPSEC_CONF_SUB;
14377c478bd9Sstevel@tonic-gate 			filename = optarg;
14387c478bd9Sstevel@tonic-gate 			break;
14398810c16bSdanmcd 		case 'i':
14408810c16bSdanmcd 			if (interface_name != NULL) {
1441e3320f40Smarkfen 				EXIT_FATAL("Interface name already selected");
14428810c16bSdanmcd 			}
14438810c16bSdanmcd 			interface_name = optarg;
14448810c16bSdanmcd 			/* Check for some cretin using the all-polheads name. */
14458810c16bSdanmcd 			if (strlen(optarg) == 0) {
1446e3320f40Smarkfen 				USAGE();
1447e3320f40Smarkfen 				EXIT_FATAL("Invalid interface name.");
14488810c16bSdanmcd 			}
14498810c16bSdanmcd 			break;
14507c478bd9Sstevel@tonic-gate 		default :
1451e3320f40Smarkfen 			USAGE();
1452e3320f40Smarkfen 			EXIT_FATAL("Bad usage.");
14537c478bd9Sstevel@tonic-gate 		}
14547c478bd9Sstevel@tonic-gate 	}
14557c478bd9Sstevel@tonic-gate 
14567c478bd9Sstevel@tonic-gate done:
14577c478bd9Sstevel@tonic-gate 	ret = 0;
14587c478bd9Sstevel@tonic-gate 	lfd = lock();
14597c478bd9Sstevel@tonic-gate 
14607c478bd9Sstevel@tonic-gate 	/*
14617c478bd9Sstevel@tonic-gate 	 * ADD, FLUSH, DELETE needs to do two operations.
14627c478bd9Sstevel@tonic-gate 	 *
14637c478bd9Sstevel@tonic-gate 	 * 1) Update/delete/empty the POLICY_CONF_FILE.
14647c478bd9Sstevel@tonic-gate 	 * 2) Make an ioctl and tell IP to update its state.
14657c478bd9Sstevel@tonic-gate 	 *
14667c478bd9Sstevel@tonic-gate 	 * We already lock()ed so that only one instance of this
14677c478bd9Sstevel@tonic-gate 	 * program runs. We also need to make sure that the above
14687c478bd9Sstevel@tonic-gate 	 * operations are atomic i.e we don't want to update the file
14697c478bd9Sstevel@tonic-gate 	 * and get interrupted before we could tell IP. To make it
14707c478bd9Sstevel@tonic-gate 	 * atomic we block all the signals and restore them.
14717c478bd9Sstevel@tonic-gate 	 */
14727c478bd9Sstevel@tonic-gate 	switch (cmd) {
14737c478bd9Sstevel@tonic-gate 	case IPSEC_CONF_LIST:
14747c478bd9Sstevel@tonic-gate 		fetch_algorithms();
14757c478bd9Sstevel@tonic-gate 		ret = ipsec_conf_list();
14767c478bd9Sstevel@tonic-gate 		break;
14777c478bd9Sstevel@tonic-gate 	case IPSEC_CONF_FLUSH:
14787c478bd9Sstevel@tonic-gate 		if ((ret = block_all_signals()) == -1) {
14797c478bd9Sstevel@tonic-gate 			break;
14807c478bd9Sstevel@tonic-gate 		}
1481e3320f40Smarkfen 		if (!smf_managed && !ipsecconf_qflag)
1482e3320f40Smarkfen 			(void) fprintf(stdout, "%s", smf_warning);
14837c478bd9Sstevel@tonic-gate 		ret = ipsec_conf_flush(SPD_ACTIVE);
14847c478bd9Sstevel@tonic-gate 		(void) restore_all_signals();
14857c478bd9Sstevel@tonic-gate 		break;
14867c478bd9Sstevel@tonic-gate 	case IPSEC_CONF_VIEW:
14878810c16bSdanmcd 		if (interface_name != NULL) {
1488e3320f40Smarkfen 			EXIT_FATAL("Cannot view for one interface only.");
14898810c16bSdanmcd 		}
14907c478bd9Sstevel@tonic-gate 		ret = ipsec_conf_view();
14917c478bd9Sstevel@tonic-gate 		break;
14927c478bd9Sstevel@tonic-gate 	case IPSEC_CONF_DEL:
14937c478bd9Sstevel@tonic-gate 		if (index == -1) {
14947c478bd9Sstevel@tonic-gate 			warnx(gettext("Invalid index"));
14957c478bd9Sstevel@tonic-gate 			ret = -1;
14967c478bd9Sstevel@tonic-gate 			break;
14977c478bd9Sstevel@tonic-gate 		}
14987c478bd9Sstevel@tonic-gate 		if ((ret = block_all_signals()) == -1) {
14997c478bd9Sstevel@tonic-gate 			break;
15007c478bd9Sstevel@tonic-gate 		}
1501e3320f40Smarkfen 		if (!smf_managed && !ipsecconf_qflag)
1502e3320f40Smarkfen 			(void) fprintf(stdout, "%s", smf_warning);
15037c478bd9Sstevel@tonic-gate 		ret = ipsec_conf_del(index, B_FALSE);
15047c478bd9Sstevel@tonic-gate 		(void) restore_all_signals();
1505e3320f40Smarkfen 		flushret = ipsec_conf_flush(SPD_STANDBY);
15067c478bd9Sstevel@tonic-gate 		break;
15077c478bd9Sstevel@tonic-gate 	case IPSEC_CONF_ADD:
1508e3320f40Smarkfen 		/*
1509e3320f40Smarkfen 		 * The IPsec kernel modules should only be loaded
1510e3320f40Smarkfen 		 * if there is a policy to install, for this
1511e3320f40Smarkfen 		 * reason ipsec_conf_add() calls fetch_algorithms()
1512e3320f40Smarkfen 		 * and ipsec_conf_flush() only when appropriate.
1513e3320f40Smarkfen 		 */
15147c478bd9Sstevel@tonic-gate 		if ((ret = block_all_signals()) == -1) {
15157c478bd9Sstevel@tonic-gate 			break;
15167c478bd9Sstevel@tonic-gate 		}
1517e3320f40Smarkfen 		if (!smf_managed && !ipsecconf_qflag)
1518e3320f40Smarkfen 			(void) fprintf(stdout, "%s", smf_warning);
1519e3320f40Smarkfen 		ret = ipsec_conf_add(just_check, smf_managed);
15207c478bd9Sstevel@tonic-gate 		(void) restore_all_signals();
15217c478bd9Sstevel@tonic-gate 		break;
15227c478bd9Sstevel@tonic-gate 	case IPSEC_CONF_SUB:
15237c478bd9Sstevel@tonic-gate 		fetch_algorithms();
15247c478bd9Sstevel@tonic-gate 		if ((ret = block_all_signals()) == -1) {
15257c478bd9Sstevel@tonic-gate 			break;
15267c478bd9Sstevel@tonic-gate 		}
1527e3320f40Smarkfen 		if (!smf_managed && !ipsecconf_qflag)
1528e3320f40Smarkfen 			(void) fprintf(stdout, "%s", smf_warning);
15297c478bd9Sstevel@tonic-gate 		ret = ipsec_conf_sub();
15307c478bd9Sstevel@tonic-gate 		(void) restore_all_signals();
1531e3320f40Smarkfen 		flushret = ipsec_conf_flush(SPD_STANDBY);
15327c478bd9Sstevel@tonic-gate 		break;
15337c478bd9Sstevel@tonic-gate 	default :
15347c478bd9Sstevel@tonic-gate 		/* If no argument is given but a "-" */
1535e3320f40Smarkfen 		USAGE();
1536e3320f40Smarkfen 		EXIT_FATAL("Bad usage.");
15377c478bd9Sstevel@tonic-gate 	}
15387c478bd9Sstevel@tonic-gate 
15397c478bd9Sstevel@tonic-gate 	(void) unlock(lfd);
15407c478bd9Sstevel@tonic-gate 	if (ret != 0 || flushret != 0)
15417c478bd9Sstevel@tonic-gate 		ret = 1;
15427c478bd9Sstevel@tonic-gate 	return (ret);
15437c478bd9Sstevel@tonic-gate }
15447c478bd9Sstevel@tonic-gate 
1545e3320f40Smarkfen static void
15467c478bd9Sstevel@tonic-gate perm_check(void)
15477c478bd9Sstevel@tonic-gate {
1548e3320f40Smarkfen 	if (errno == EACCES)
1549e3320f40Smarkfen 		EXIT_BADPERM("Insufficient privilege to run ipsecconf.");
15507c478bd9Sstevel@tonic-gate 	else
1551e3320f40Smarkfen 		warn(gettext("Cannot open lock file %s"), LOCK_FILE);
1552e3320f40Smarkfen 
1553e3320f40Smarkfen 	EXIT_BADPERM(NULL);
15547c478bd9Sstevel@tonic-gate }
15557c478bd9Sstevel@tonic-gate 
15567c478bd9Sstevel@tonic-gate static int
15577c478bd9Sstevel@tonic-gate lock()
15587c478bd9Sstevel@tonic-gate {
15597c478bd9Sstevel@tonic-gate 	int fd;
15607c478bd9Sstevel@tonic-gate 	struct stat sbuf1;
15617c478bd9Sstevel@tonic-gate 	struct stat sbuf2;
15627c478bd9Sstevel@tonic-gate 
15637c478bd9Sstevel@tonic-gate 	/*
15647c478bd9Sstevel@tonic-gate 	 * Open the file with O_CREAT|O_EXCL. If it exists already, it
15657c478bd9Sstevel@tonic-gate 	 * will fail. If it already exists, check whether it looks like
15667c478bd9Sstevel@tonic-gate 	 * the one we created.
15677c478bd9Sstevel@tonic-gate 	 */
15687c478bd9Sstevel@tonic-gate 	(void) umask(0077);
15697c478bd9Sstevel@tonic-gate 	if ((fd = open(LOCK_FILE, O_EXCL|O_CREAT|O_RDWR, S_IRUSR|S_IWUSR))
15707c478bd9Sstevel@tonic-gate 	    == -1) {
15717c478bd9Sstevel@tonic-gate 		if (errno != EEXIST) {
1572e3320f40Smarkfen 			/* Some other problem. Will exit. */
1573e3320f40Smarkfen 			perm_check();
15747c478bd9Sstevel@tonic-gate 		}
15757c478bd9Sstevel@tonic-gate 
15767c478bd9Sstevel@tonic-gate 		/*
15777c478bd9Sstevel@tonic-gate 		 * open() returned an EEXIST error. We don't fail yet
15787c478bd9Sstevel@tonic-gate 		 * as it could be a residual from a previous
157943c889d3Smarkfen 		 * execution.
15807c478bd9Sstevel@tonic-gate 		 * File exists. make sure it is OK. We need to lstat()
15817c478bd9Sstevel@tonic-gate 		 * as fstat() stats the file pointed to by the symbolic
15827c478bd9Sstevel@tonic-gate 		 * link.
15837c478bd9Sstevel@tonic-gate 		 */
15847c478bd9Sstevel@tonic-gate 		if (lstat(LOCK_FILE, &sbuf1) == -1) {
1585e3320f40Smarkfen 			EXIT_FATAL2("Cannot lstat lock file %s", LOCK_FILE);
15867c478bd9Sstevel@tonic-gate 		}
15877c478bd9Sstevel@tonic-gate 		/*
15887c478bd9Sstevel@tonic-gate 		 * Check whether it is a regular file and not a symbolic
15897c478bd9Sstevel@tonic-gate 		 * link. Its link count should be 1. The owner should be
15907c478bd9Sstevel@tonic-gate 		 * root and the file should be empty.
15917c478bd9Sstevel@tonic-gate 		 */
15924bc0a2efScasper 		if (!S_ISREG(sbuf1.st_mode) ||
15937c478bd9Sstevel@tonic-gate 		    sbuf1.st_nlink != 1 ||
15947c478bd9Sstevel@tonic-gate 		    sbuf1.st_uid != 0 ||
15957c478bd9Sstevel@tonic-gate 		    sbuf1.st_size != 0) {
1596e3320f40Smarkfen 			EXIT_FATAL2("Bad lock file %s", LOCK_FILE);
15977c478bd9Sstevel@tonic-gate 		}
15987c478bd9Sstevel@tonic-gate 		if ((fd = open(LOCK_FILE, O_CREAT|O_RDWR,
15997c478bd9Sstevel@tonic-gate 		    S_IRUSR|S_IWUSR)) == -1) {
1600e3320f40Smarkfen 			/* Will exit */
1601e3320f40Smarkfen 			perm_check();
16027c478bd9Sstevel@tonic-gate 		}
16037c478bd9Sstevel@tonic-gate 		/*
16047c478bd9Sstevel@tonic-gate 		 * Check whether we opened the file that we lstat()ed.
16057c478bd9Sstevel@tonic-gate 		 */
16067c478bd9Sstevel@tonic-gate 		if (fstat(fd, &sbuf2) == -1) {
1607e3320f40Smarkfen 			EXIT_FATAL2("Cannot lstat lock file %s", LOCK_FILE);
16087c478bd9Sstevel@tonic-gate 		}
16097c478bd9Sstevel@tonic-gate 		if (sbuf1.st_dev != sbuf2.st_dev ||
16107c478bd9Sstevel@tonic-gate 		    sbuf1.st_ino != sbuf2.st_ino) {
16117c478bd9Sstevel@tonic-gate 			/* File changed after we did the lstat() above */
1612e3320f40Smarkfen 			EXIT_FATAL2("Bad lock file %s", LOCK_FILE);
16137c478bd9Sstevel@tonic-gate 		}
16147c478bd9Sstevel@tonic-gate 	}
16157c478bd9Sstevel@tonic-gate 	if (lockf(fd, F_LOCK, 0) == -1) {
1616e3320f40Smarkfen 		EXIT_FATAL2("Cannot lockf %s", LOCK_FILE);
16177c478bd9Sstevel@tonic-gate 	}
16187c478bd9Sstevel@tonic-gate 	return (fd);
16197c478bd9Sstevel@tonic-gate }
16207c478bd9Sstevel@tonic-gate 
16217c478bd9Sstevel@tonic-gate static int
16227c478bd9Sstevel@tonic-gate unlock(int fd)
16237c478bd9Sstevel@tonic-gate {
16247c478bd9Sstevel@tonic-gate 	if (lockf(fd, F_ULOCK, 0) == -1) {
16257c478bd9Sstevel@tonic-gate 		warn("lockf");
16267c478bd9Sstevel@tonic-gate 		return (-1);
16277c478bd9Sstevel@tonic-gate 	}
16287c478bd9Sstevel@tonic-gate 	return (0);
16297c478bd9Sstevel@tonic-gate }
16307c478bd9Sstevel@tonic-gate 
16317c478bd9Sstevel@tonic-gate /* send in TOK_* */
16327c478bd9Sstevel@tonic-gate static void
16337c478bd9Sstevel@tonic-gate print_pattern_string(int type)
16347c478bd9Sstevel@tonic-gate {
16357c478bd9Sstevel@tonic-gate 	int j;
16367c478bd9Sstevel@tonic-gate 
16377c478bd9Sstevel@tonic-gate 	for (j = 0; pattern_table[j].string != NULL; j++) {
16387c478bd9Sstevel@tonic-gate 		if (type == pattern_table[j].tok_val) {
16397c478bd9Sstevel@tonic-gate 			(void) printf("%s ", pattern_table[j].string);
16407c478bd9Sstevel@tonic-gate 			return;
16417c478bd9Sstevel@tonic-gate 		}
16427c478bd9Sstevel@tonic-gate 	}
16437c478bd9Sstevel@tonic-gate }
16447c478bd9Sstevel@tonic-gate 
16457c478bd9Sstevel@tonic-gate static void
16467c478bd9Sstevel@tonic-gate print_icmp_typecode(uint8_t type, uint8_t type_end, uint8_t code,
16477c478bd9Sstevel@tonic-gate     uint8_t code_end)
16487c478bd9Sstevel@tonic-gate {
16497c478bd9Sstevel@tonic-gate 	(void) printf("type %d", type);
16507c478bd9Sstevel@tonic-gate 	if (type_end != type)
16517c478bd9Sstevel@tonic-gate 		(void) printf("-%d ", type_end);
16527c478bd9Sstevel@tonic-gate 	else
16537c478bd9Sstevel@tonic-gate 		(void) printf(" ");
16547c478bd9Sstevel@tonic-gate 	if (code != 255) {
16557c478bd9Sstevel@tonic-gate 		(void) printf("code %d", code);
16567c478bd9Sstevel@tonic-gate 		if (code_end != code)
16577c478bd9Sstevel@tonic-gate 			(void) printf("-%d ", code_end);
16587c478bd9Sstevel@tonic-gate 		else
16597c478bd9Sstevel@tonic-gate 			(void) printf(" ");
16607c478bd9Sstevel@tonic-gate 	}
16617c478bd9Sstevel@tonic-gate }
16627c478bd9Sstevel@tonic-gate 
16637c478bd9Sstevel@tonic-gate 
16647c478bd9Sstevel@tonic-gate static void
16657c478bd9Sstevel@tonic-gate print_spd_flags(uint32_t flags)
16667c478bd9Sstevel@tonic-gate {
16677c478bd9Sstevel@tonic-gate 	flags &= (SPD_RULE_FLAG_INBOUND|SPD_RULE_FLAG_OUTBOUND);
16687c478bd9Sstevel@tonic-gate 
16697c478bd9Sstevel@tonic-gate 	if (flags == SPD_RULE_FLAG_OUTBOUND)
16707c478bd9Sstevel@tonic-gate 		(void) printf("dir out ");
16717c478bd9Sstevel@tonic-gate 	else if (flags == SPD_RULE_FLAG_INBOUND)
16727c478bd9Sstevel@tonic-gate 		(void) printf("dir in ");
16737c478bd9Sstevel@tonic-gate 	else if (flags == (SPD_RULE_FLAG_INBOUND|SPD_RULE_FLAG_OUTBOUND))
16747c478bd9Sstevel@tonic-gate 		(void) printf("dir both ");
16757c478bd9Sstevel@tonic-gate }
16767c478bd9Sstevel@tonic-gate 
16777c478bd9Sstevel@tonic-gate static void
16787c478bd9Sstevel@tonic-gate print_bit_range(int min, int max)
16797c478bd9Sstevel@tonic-gate {
16807c478bd9Sstevel@tonic-gate 	if (min != 0 || (max != 0 && max != SPD_MAX_MAXBITS)) {
16817c478bd9Sstevel@tonic-gate 		(void) printf("(");
16827c478bd9Sstevel@tonic-gate 		if (min != 0)
16837c478bd9Sstevel@tonic-gate 			(void) printf("%d", min);
16847c478bd9Sstevel@tonic-gate 		if (min != 0 && max != 0 && min != max) {
16857c478bd9Sstevel@tonic-gate 			(void) printf("..");
16867c478bd9Sstevel@tonic-gate 			if (max != 0 && max != SPD_MAX_MAXBITS)
16877c478bd9Sstevel@tonic-gate 				(void) printf("%d", max);
16887c478bd9Sstevel@tonic-gate 		}
16897c478bd9Sstevel@tonic-gate 		(void) printf(")");
16907c478bd9Sstevel@tonic-gate 	}
16917c478bd9Sstevel@tonic-gate }
16927c478bd9Sstevel@tonic-gate 
16937c478bd9Sstevel@tonic-gate static void
16947c478bd9Sstevel@tonic-gate print_alg(const char *tag, algreq_t *algreq, int proto_num)
16957c478bd9Sstevel@tonic-gate {
16967c478bd9Sstevel@tonic-gate 	int min = algreq->alg_minbits;
16977c478bd9Sstevel@tonic-gate 	int max = algreq->alg_maxbits;
16987c478bd9Sstevel@tonic-gate 	struct ipsecalgent *alg;
16997c478bd9Sstevel@tonic-gate 
17007c478bd9Sstevel@tonic-gate 	/*
17017c478bd9Sstevel@tonic-gate 	 * This function won't be called with alg_id == 0, so we don't
17027c478bd9Sstevel@tonic-gate 	 * have to worry about ANY vs. NONE here.
17037c478bd9Sstevel@tonic-gate 	 */
17047c478bd9Sstevel@tonic-gate 
17057c478bd9Sstevel@tonic-gate 	(void) printf("%s ", tag);
17067c478bd9Sstevel@tonic-gate 
17077c478bd9Sstevel@tonic-gate 	alg = getipsecalgbynum(algreq->alg_id, proto_num, NULL);
17087c478bd9Sstevel@tonic-gate 	if (alg == NULL) {
17097c478bd9Sstevel@tonic-gate 		(void) printf("%d", algreq->alg_id);
17107c478bd9Sstevel@tonic-gate 	} else {
17117c478bd9Sstevel@tonic-gate 		(void) printf("%s", alg->a_names[0]);
17127c478bd9Sstevel@tonic-gate 		freeipsecalgent(alg);
17137c478bd9Sstevel@tonic-gate 	}
17147c478bd9Sstevel@tonic-gate 
17157c478bd9Sstevel@tonic-gate 	print_bit_range(min, max);
17167c478bd9Sstevel@tonic-gate 	(void) printf(" ");
17177c478bd9Sstevel@tonic-gate }
17187c478bd9Sstevel@tonic-gate 
17197c478bd9Sstevel@tonic-gate static void
17207c478bd9Sstevel@tonic-gate print_ulp(uint8_t proto)
17217c478bd9Sstevel@tonic-gate {
17227c478bd9Sstevel@tonic-gate 	struct protoent *pe;
17237c478bd9Sstevel@tonic-gate 
17247c478bd9Sstevel@tonic-gate 	if (proto == 0)
17257c478bd9Sstevel@tonic-gate 		return;
17267c478bd9Sstevel@tonic-gate 
17277c478bd9Sstevel@tonic-gate 	print_pattern_string(TOK_ulp);
17287c478bd9Sstevel@tonic-gate 	pe = NULL;
17297c478bd9Sstevel@tonic-gate 	if (!ipsecconf_nflag) {
17307c478bd9Sstevel@tonic-gate 		pe = getprotobynumber(proto);
17317c478bd9Sstevel@tonic-gate 	}
17327c478bd9Sstevel@tonic-gate 	if (pe != NULL)
17337c478bd9Sstevel@tonic-gate 		(void) printf("%s ", pe->p_name);
17347c478bd9Sstevel@tonic-gate 	else
17357c478bd9Sstevel@tonic-gate 		(void) printf("%d ", proto);
17367c478bd9Sstevel@tonic-gate }
17377c478bd9Sstevel@tonic-gate 
17387c478bd9Sstevel@tonic-gate /* needs to do ranges */
17397c478bd9Sstevel@tonic-gate static void
17407c478bd9Sstevel@tonic-gate print_port(uint16_t in_port, int type)
17417c478bd9Sstevel@tonic-gate {
17427c478bd9Sstevel@tonic-gate 	in_port_t port = ntohs(in_port);
17437c478bd9Sstevel@tonic-gate 	struct servent *sp;
17447c478bd9Sstevel@tonic-gate 
17457c478bd9Sstevel@tonic-gate 	if (port == 0)
17467c478bd9Sstevel@tonic-gate 		return;
17477c478bd9Sstevel@tonic-gate 
17487c478bd9Sstevel@tonic-gate 	print_pattern_string(type);
17497c478bd9Sstevel@tonic-gate 	sp = NULL;
17507c478bd9Sstevel@tonic-gate 	if (!ipsecconf_nflag)
17517c478bd9Sstevel@tonic-gate 		sp = getservbyport(port, NULL);
17527c478bd9Sstevel@tonic-gate 
17537c478bd9Sstevel@tonic-gate 	if (sp != NULL)
17547c478bd9Sstevel@tonic-gate 		(void) printf("%s ", sp->s_name);
17557c478bd9Sstevel@tonic-gate 	else
17567c478bd9Sstevel@tonic-gate 		(void) printf("%d ", port);
17577c478bd9Sstevel@tonic-gate }
17587c478bd9Sstevel@tonic-gate 
17597c478bd9Sstevel@tonic-gate /*
17608810c16bSdanmcd  * Print the address, given as "raw" input via the void pointer.
17617c478bd9Sstevel@tonic-gate  */
17627c478bd9Sstevel@tonic-gate static void
17638810c16bSdanmcd print_raw_address(void *input, boolean_t isv4)
17647c478bd9Sstevel@tonic-gate {
17657c478bd9Sstevel@tonic-gate 	char  *cp;
17667c478bd9Sstevel@tonic-gate 	struct hostent *hp;
17677c478bd9Sstevel@tonic-gate 	char	domain[MAXHOSTNAMELEN + 1];
17687c478bd9Sstevel@tonic-gate 	struct in_addr addr;
17697c478bd9Sstevel@tonic-gate 	struct in6_addr addr6;
17707c478bd9Sstevel@tonic-gate 	char abuf[INET6_ADDRSTRLEN];
17717c478bd9Sstevel@tonic-gate 	int error_num;
17727c478bd9Sstevel@tonic-gate 	struct in6_addr in_addr;
17737c478bd9Sstevel@tonic-gate 	uchar_t *addr_ptr;
17747c478bd9Sstevel@tonic-gate 	sa_family_t af;
17757c478bd9Sstevel@tonic-gate 	int addr_len;
17767c478bd9Sstevel@tonic-gate 
17777c478bd9Sstevel@tonic-gate 	if (isv4) {
17787c478bd9Sstevel@tonic-gate 		af = AF_INET;
17797c478bd9Sstevel@tonic-gate 		(void) memcpy(&V4_PART_OF_V6(in_addr), input, 4);
17807c478bd9Sstevel@tonic-gate 		/* we don't print unspecified addresses */
17817c478bd9Sstevel@tonic-gate 		IN6_V4MAPPED_TO_INADDR(&in_addr, &addr);
17827c478bd9Sstevel@tonic-gate 		if (addr.s_addr == INADDR_ANY)
17837c478bd9Sstevel@tonic-gate 			return;
17847c478bd9Sstevel@tonic-gate 		addr_ptr = (uchar_t *)&addr.s_addr;
17857c478bd9Sstevel@tonic-gate 		addr_len = IPV4_ADDR_LEN;
17867c478bd9Sstevel@tonic-gate 	} else {
17877c478bd9Sstevel@tonic-gate 		(void) memcpy(&addr6, input, 16);
17887c478bd9Sstevel@tonic-gate 		af = AF_INET6;
17897c478bd9Sstevel@tonic-gate 		/* we don't print unspecified addresses */
17907c478bd9Sstevel@tonic-gate 		if (IN6_IS_ADDR_UNSPECIFIED(&addr6))
17917c478bd9Sstevel@tonic-gate 			return;
17927c478bd9Sstevel@tonic-gate 		addr_ptr = (uchar_t *)&addr6.s6_addr;
17937c478bd9Sstevel@tonic-gate 		addr_len = sizeof (struct in6_addr);
17947c478bd9Sstevel@tonic-gate 	}
17957c478bd9Sstevel@tonic-gate 
17967c478bd9Sstevel@tonic-gate 	cp = NULL;
17977c478bd9Sstevel@tonic-gate 	if (!ipsecconf_nflag) {
17987c478bd9Sstevel@tonic-gate 		if (sysinfo(SI_HOSTNAME, domain, MAXHOSTNAMELEN) != -1 &&
1799d5751483Smarkfen 		    (cp = strchr(domain, '.')) != NULL) {
1800e3320f40Smarkfen 			(void) strlcpy(domain, cp + 1, sizeof (domain));
18017c478bd9Sstevel@tonic-gate 		} else {
18027c478bd9Sstevel@tonic-gate 			domain[0] = 0;
18037c478bd9Sstevel@tonic-gate 		}
18047c478bd9Sstevel@tonic-gate 		hp = getipnodebyaddr(addr_ptr, addr_len, af, &error_num);
18057c478bd9Sstevel@tonic-gate 		if (hp) {
18067c478bd9Sstevel@tonic-gate 			if ((cp = strchr(hp->h_name, '.')) != 0 &&
1807d5751483Smarkfen 			    strcasecmp(cp + 1, domain) == 0)
18087c478bd9Sstevel@tonic-gate 				*cp = 0;
18097c478bd9Sstevel@tonic-gate 			cp = hp->h_name;
18107c478bd9Sstevel@tonic-gate 		}
18117c478bd9Sstevel@tonic-gate 	}
18127c478bd9Sstevel@tonic-gate 
18137c478bd9Sstevel@tonic-gate 	if (cp) {
18147c478bd9Sstevel@tonic-gate 		(void) printf("%s", cp);
18157c478bd9Sstevel@tonic-gate 	} else {
18167c478bd9Sstevel@tonic-gate 		(void) printf("%s", inet_ntop(af, addr_ptr, abuf,
18177c478bd9Sstevel@tonic-gate 		    INET6_ADDRSTRLEN));
18187c478bd9Sstevel@tonic-gate 	}
18197c478bd9Sstevel@tonic-gate }
18207c478bd9Sstevel@tonic-gate 
18217c478bd9Sstevel@tonic-gate /*
18227c478bd9Sstevel@tonic-gate  * Get the next SPD_DUMP message from the PF_POLICY socket.  A single
18237c478bd9Sstevel@tonic-gate  * read may contain multiple messages.  This function uses static buffers,
18247c478bd9Sstevel@tonic-gate  * and is therefore non-reentrant, so if you lift it for an MT application,
18257c478bd9Sstevel@tonic-gate  * be careful.
18267c478bd9Sstevel@tonic-gate  *
18277c478bd9Sstevel@tonic-gate  * Return NULL if there's an error.
18287c478bd9Sstevel@tonic-gate  */
18297c478bd9Sstevel@tonic-gate static spd_msg_t *
18307c478bd9Sstevel@tonic-gate ipsec_read_dump(int pfd)
18317c478bd9Sstevel@tonic-gate {
18327c478bd9Sstevel@tonic-gate 	static uint64_t buf[SADB_8TO64(CBUF_LEN)];
18337c478bd9Sstevel@tonic-gate 	static uint64_t *offset;
18347c478bd9Sstevel@tonic-gate 	static int len;		/* In uint64_t units. */
18357c478bd9Sstevel@tonic-gate 	spd_msg_t *retval;
18367c478bd9Sstevel@tonic-gate 
18377c478bd9Sstevel@tonic-gate 	/* Assume offset and len are initialized to NULL and 0. */
18387c478bd9Sstevel@tonic-gate 
18397c478bd9Sstevel@tonic-gate 	if ((offset - len == buf) || (offset == NULL)) {
18407c478bd9Sstevel@tonic-gate 		/* read a new block from the socket. */
18417c478bd9Sstevel@tonic-gate 		len = read(pfd, &buf, sizeof (buf));
18427c478bd9Sstevel@tonic-gate 		if (len == -1) {
18437c478bd9Sstevel@tonic-gate 			warn(gettext("rule dump: bad read"));
18447c478bd9Sstevel@tonic-gate 			return (NULL);
18457c478bd9Sstevel@tonic-gate 		}
18467c478bd9Sstevel@tonic-gate 		offset = buf;
18477c478bd9Sstevel@tonic-gate 		len = SADB_8TO64(len);
18487c478bd9Sstevel@tonic-gate 	} /* Else I still have more messages from a previous read. */
18497c478bd9Sstevel@tonic-gate 
18507c478bd9Sstevel@tonic-gate 	retval = (spd_msg_t *)offset;
18517c478bd9Sstevel@tonic-gate 	offset += retval->spd_msg_len;
18527c478bd9Sstevel@tonic-gate 	if (offset > buf + len) {
18537c478bd9Sstevel@tonic-gate 		warnx(gettext("dump read: message corruption,"
18547c478bd9Sstevel@tonic-gate 		    " %d len exceeds %d boundary."),
18557c478bd9Sstevel@tonic-gate 		    SADB_64TO8((uintptr_t)(offset - buf)),
18567c478bd9Sstevel@tonic-gate 		    SADB_64TO8((uintptr_t)(buf + len)));
18577c478bd9Sstevel@tonic-gate 		return (NULL);
18587c478bd9Sstevel@tonic-gate 	}
18597c478bd9Sstevel@tonic-gate 
18607c478bd9Sstevel@tonic-gate 	return (retval);
18617c478bd9Sstevel@tonic-gate }
18627c478bd9Sstevel@tonic-gate 
18637c478bd9Sstevel@tonic-gate /*
18647c478bd9Sstevel@tonic-gate  * returns 0 on success
18657c478bd9Sstevel@tonic-gate  * -1 on read error
18667c478bd9Sstevel@tonic-gate  * >0  on invalid returned message
18677c478bd9Sstevel@tonic-gate  */
18687c478bd9Sstevel@tonic-gate 
18697c478bd9Sstevel@tonic-gate static int
18707c478bd9Sstevel@tonic-gate ipsec_conf_list(void)
18717c478bd9Sstevel@tonic-gate {
18727c478bd9Sstevel@tonic-gate 	int ret;
18737c478bd9Sstevel@tonic-gate 	int pfd;
18748810c16bSdanmcd 	struct spd_msg *msg;
18757c478bd9Sstevel@tonic-gate 	int cnt;
18767c478bd9Sstevel@tonic-gate 	spd_msg_t *rmsg;
18777c478bd9Sstevel@tonic-gate 	spd_ext_t *exts[SPD_EXT_MAX+1];
18788810c16bSdanmcd 	/*
18798810c16bSdanmcd 	 * Add an extra 8 bytes of space (+1 uint64_t) to avoid truncation
18808810c16bSdanmcd 	 * issues.
18818810c16bSdanmcd 	 */
18828810c16bSdanmcd 	uint64_t buffer[
18838810c16bSdanmcd 	    SPD_8TO64(sizeof (*msg) + sizeof (spd_if_t) + LIFNAMSIZ) + 1];
18847c478bd9Sstevel@tonic-gate 
18857c478bd9Sstevel@tonic-gate 	pfd = get_pf_pol_socket();
18867c478bd9Sstevel@tonic-gate 
18877c478bd9Sstevel@tonic-gate 	if (pfd == -1) {
18887c478bd9Sstevel@tonic-gate 		warnx(gettext("Error getting list of policies from kernel"));
18897c478bd9Sstevel@tonic-gate 		return (-1);
18907c478bd9Sstevel@tonic-gate 	}
18917c478bd9Sstevel@tonic-gate 
18928810c16bSdanmcd 	(void) memset(buffer, 0, sizeof (buffer));
18938810c16bSdanmcd 	msg = (struct spd_msg *)buffer;
18948810c16bSdanmcd 	msg->spd_msg_version = PF_POLICY_V1;
18958810c16bSdanmcd 	msg->spd_msg_type = SPD_DUMP;
18968810c16bSdanmcd 	msg->spd_msg_len = SPD_8TO64(sizeof (*msg));
18977c478bd9Sstevel@tonic-gate 
18988810c16bSdanmcd 	msg->spd_msg_len += attach_tunname((spd_if_t *)(msg + 1));
18998810c16bSdanmcd 
19008810c16bSdanmcd 	cnt = write(pfd, msg, SPD_64TO8(msg->spd_msg_len));
19017c478bd9Sstevel@tonic-gate 
19027c478bd9Sstevel@tonic-gate 	if (cnt < 0) {
19037c478bd9Sstevel@tonic-gate 		warn(gettext("dump: invalid write() return"));
19047c478bd9Sstevel@tonic-gate 		(void) close(pfd);
19057c478bd9Sstevel@tonic-gate 		return (-1);
19067c478bd9Sstevel@tonic-gate 	}
19077c478bd9Sstevel@tonic-gate 
19087c478bd9Sstevel@tonic-gate 	rmsg = ipsec_read_dump(pfd);
19097c478bd9Sstevel@tonic-gate 
19107c478bd9Sstevel@tonic-gate 	if (rmsg == NULL || rmsg->spd_msg_errno != 0) {
19117c478bd9Sstevel@tonic-gate 		warnx("%s: %s", gettext("ruleset dump failed"),
19127c478bd9Sstevel@tonic-gate 		    (rmsg == NULL ?
1913d5751483Smarkfen 		    gettext("read error") :
1914d5751483Smarkfen 		    sys_error_message(rmsg->spd_msg_errno)));
19157c478bd9Sstevel@tonic-gate 		(void) close(pfd);
19167c478bd9Sstevel@tonic-gate 		return (-1);
19177c478bd9Sstevel@tonic-gate 	}
19187c478bd9Sstevel@tonic-gate 
19197c478bd9Sstevel@tonic-gate 
19207c478bd9Sstevel@tonic-gate 	for (;;) {
19217c478bd9Sstevel@tonic-gate 		/* read rule */
19227c478bd9Sstevel@tonic-gate 		rmsg = ipsec_read_dump(pfd);
19237c478bd9Sstevel@tonic-gate 
19247c478bd9Sstevel@tonic-gate 		if (rmsg == NULL) {
19257c478bd9Sstevel@tonic-gate 			(void) close(pfd);
19267c478bd9Sstevel@tonic-gate 			return (-1);
19277c478bd9Sstevel@tonic-gate 		}
19287c478bd9Sstevel@tonic-gate 
19297c478bd9Sstevel@tonic-gate 		if (rmsg->spd_msg_errno != 0) {
19307c478bd9Sstevel@tonic-gate 			warnx("%s: %s", gettext("dump read: bad message"),
19318810c16bSdanmcd 			    sys_error_message(rmsg->spd_msg_errno));
19327c478bd9Sstevel@tonic-gate 			(void) close(pfd);
19337c478bd9Sstevel@tonic-gate 			return (-1);
19347c478bd9Sstevel@tonic-gate 		}
19357c478bd9Sstevel@tonic-gate 
19367c478bd9Sstevel@tonic-gate 		ret = spdsock_get_ext(exts, rmsg, rmsg->spd_msg_len,
19377c478bd9Sstevel@tonic-gate 		    spdsock_diag_buf, SPDSOCK_DIAG_BUF_LEN);
19387c478bd9Sstevel@tonic-gate 		if (ret != 0) {
19397c478bd9Sstevel@tonic-gate 			if (strlen(spdsock_diag_buf) != 0)
19407c478bd9Sstevel@tonic-gate 				warnx(spdsock_diag_buf);
19417c478bd9Sstevel@tonic-gate 			warnx("%s: %s", gettext("dump read: bad message"),
19428810c16bSdanmcd 			    sys_error_message(rmsg->spd_msg_errno));
19437c478bd9Sstevel@tonic-gate 			(void) close(pfd);
19447c478bd9Sstevel@tonic-gate 			return (ret);
19457c478bd9Sstevel@tonic-gate 		}
19467c478bd9Sstevel@tonic-gate 
19477c478bd9Sstevel@tonic-gate 		/*
19487c478bd9Sstevel@tonic-gate 		 * End of dump..
19497c478bd9Sstevel@tonic-gate 		 */
19507c478bd9Sstevel@tonic-gate 		if (exts[SPD_EXT_RULESET] != NULL)
19517c478bd9Sstevel@tonic-gate 			break;	/* and return 0. */
19527c478bd9Sstevel@tonic-gate 
19537c478bd9Sstevel@tonic-gate 		print_pfpol_msg(rmsg);
19547c478bd9Sstevel@tonic-gate 	}
19557c478bd9Sstevel@tonic-gate 
19567c478bd9Sstevel@tonic-gate 	(void) close(pfd);
19577c478bd9Sstevel@tonic-gate 	return (0);
19587c478bd9Sstevel@tonic-gate }
19597c478bd9Sstevel@tonic-gate 
19607c478bd9Sstevel@tonic-gate static void
19617c478bd9Sstevel@tonic-gate print_iap(ips_act_props_t *iap)
19627c478bd9Sstevel@tonic-gate {
19637c478bd9Sstevel@tonic-gate 
19647c478bd9Sstevel@tonic-gate 	/* action */
19657c478bd9Sstevel@tonic-gate 	switch (iap->iap_action) {
19667c478bd9Sstevel@tonic-gate 	case SPD_ACTTYPE_PASS:
19677c478bd9Sstevel@tonic-gate 		(void) printf("pass ");
19687c478bd9Sstevel@tonic-gate 		break;
19697c478bd9Sstevel@tonic-gate 	case SPD_ACTTYPE_DROP:
19707c478bd9Sstevel@tonic-gate 		(void) printf("drop ");
19717c478bd9Sstevel@tonic-gate 		break;
19727c478bd9Sstevel@tonic-gate 	case SPD_ACTTYPE_IPSEC:
19737c478bd9Sstevel@tonic-gate 		(void) printf("ipsec ");
19747c478bd9Sstevel@tonic-gate 		break;
19757c478bd9Sstevel@tonic-gate 	}
19767c478bd9Sstevel@tonic-gate 
19777c478bd9Sstevel@tonic-gate 	/* properties */
19787c478bd9Sstevel@tonic-gate 	(void) printf("%c ", CURL_BEGIN);
19797c478bd9Sstevel@tonic-gate 	if (iap->iap_action == SPD_ACTTYPE_IPSEC) {
19807c478bd9Sstevel@tonic-gate 		if (iap->iap_attr & SPD_APPLY_AH &&
19817c478bd9Sstevel@tonic-gate 		    iap->iap_aauth.alg_id != 0)
19827c478bd9Sstevel@tonic-gate 			print_alg("auth_algs", &iap->iap_aauth,
19837c478bd9Sstevel@tonic-gate 			    IPSEC_PROTO_AH);
19847c478bd9Sstevel@tonic-gate 
19857c478bd9Sstevel@tonic-gate 		if (iap->iap_attr & SPD_APPLY_ESP) {
19867c478bd9Sstevel@tonic-gate 			print_alg("encr_algs", &iap->iap_eencr,
19877c478bd9Sstevel@tonic-gate 			    IPSEC_PROTO_ESP);
19887c478bd9Sstevel@tonic-gate 			if (iap->iap_eauth.alg_id != 0)
19897c478bd9Sstevel@tonic-gate 				print_alg("encr_auth_algs", &iap->iap_eauth,
19907c478bd9Sstevel@tonic-gate 				    IPSEC_PROTO_AH);
19917c478bd9Sstevel@tonic-gate 		}
19927c478bd9Sstevel@tonic-gate 		if (iap->iap_attr & SPD_APPLY_UNIQUE)
19937c478bd9Sstevel@tonic-gate 			(void) printf("sa unique ");
19947c478bd9Sstevel@tonic-gate 		else
19957c478bd9Sstevel@tonic-gate 			(void) printf("sa shared ");
19967c478bd9Sstevel@tonic-gate 	}
19977c478bd9Sstevel@tonic-gate 	(void) printf("%c ", CURL_END);
19987c478bd9Sstevel@tonic-gate }
19997c478bd9Sstevel@tonic-gate 
20007c478bd9Sstevel@tonic-gate 
20017c478bd9Sstevel@tonic-gate static void
20027c478bd9Sstevel@tonic-gate print_pfpol_msg(spd_msg_t *msg)
20037c478bd9Sstevel@tonic-gate {
20047c478bd9Sstevel@tonic-gate 	spd_ext_t *exts[SPD_EXT_MAX+1];
20057c478bd9Sstevel@tonic-gate 	spd_address_t *spd_address;
20067c478bd9Sstevel@tonic-gate 	struct spd_rule *spd_rule;
20077c478bd9Sstevel@tonic-gate 	struct spd_proto *spd_proto;
20087c478bd9Sstevel@tonic-gate 	struct spd_portrange *spd_portrange;
20097c478bd9Sstevel@tonic-gate 	struct spd_ext_actions *spd_ext_actions;
20107c478bd9Sstevel@tonic-gate 	struct spd_typecode *spd_typecode;
20117c478bd9Sstevel@tonic-gate 	struct spd_attribute *app;
20128810c16bSdanmcd 	spd_if_t *spd_if;
20137c478bd9Sstevel@tonic-gate 	uint32_t rv;
20147c478bd9Sstevel@tonic-gate 	uint16_t act_count;
20157c478bd9Sstevel@tonic-gate 
20167c478bd9Sstevel@tonic-gate 	rv = spdsock_get_ext(exts, msg, msg->spd_msg_len, spdsock_diag_buf,
20177c478bd9Sstevel@tonic-gate 	    SPDSOCK_DIAG_BUF_LEN);
20187c478bd9Sstevel@tonic-gate 
20197c478bd9Sstevel@tonic-gate 	if (rv == KGE_OK && exts[SPD_EXT_RULE] != NULL) {
20208810c16bSdanmcd 		spd_if = (spd_if_t *)exts[SPD_EXT_TUN_NAME];
20217c478bd9Sstevel@tonic-gate 		spd_rule = (struct spd_rule *)exts[SPD_EXT_RULE];
20228810c16bSdanmcd 		if (spd_if == NULL) {
20238810c16bSdanmcd 			(void) printf("%s %lld\n", INDEX_TAG,
20248810c16bSdanmcd 			    spd_rule->spd_rule_index);
20258810c16bSdanmcd 		} else {
20268810c16bSdanmcd 			(void) printf("%s %s,%lld\n", INDEX_TAG,
20278810c16bSdanmcd 			    (char *)spd_if->spd_if_name,
20288810c16bSdanmcd 			    spd_rule->spd_rule_index);
20298810c16bSdanmcd 		}
20307c478bd9Sstevel@tonic-gate 	} else {
20317c478bd9Sstevel@tonic-gate 		if (strlen(spdsock_diag_buf) != 0)
20327c478bd9Sstevel@tonic-gate 			warnx(spdsock_diag_buf);
20337c478bd9Sstevel@tonic-gate 		warnx(gettext("print_pfpol_msg: malformed PF_POLICY message."));
20347c478bd9Sstevel@tonic-gate 		return;
20357c478bd9Sstevel@tonic-gate 	}
20367c478bd9Sstevel@tonic-gate 
20377c478bd9Sstevel@tonic-gate 	(void) printf("%c ", CURL_BEGIN);
20387c478bd9Sstevel@tonic-gate 
20398810c16bSdanmcd 	if (spd_if != NULL) {
20408810c16bSdanmcd 		(void) printf("tunnel %s negotiate %s ",
20418810c16bSdanmcd 		    (char *)spd_if->spd_if_name,
20428810c16bSdanmcd 		    (spd_rule->spd_rule_flags & SPD_RULE_FLAG_TUNNEL) ?
20438810c16bSdanmcd 		    "tunnel" : "transport");
20448810c16bSdanmcd 	}
20458810c16bSdanmcd 
20467c478bd9Sstevel@tonic-gate 	if (exts[SPD_EXT_PROTO] != NULL) {
20477c478bd9Sstevel@tonic-gate 		spd_proto = (struct spd_proto *)exts[SPD_EXT_PROTO];
20487c478bd9Sstevel@tonic-gate 		print_ulp(spd_proto->spd_proto_number);
20497c478bd9Sstevel@tonic-gate 	}
20507c478bd9Sstevel@tonic-gate 
20517c478bd9Sstevel@tonic-gate 	if (exts[SPD_EXT_LCLADDR] != NULL) {
20527c478bd9Sstevel@tonic-gate 		spd_address = (spd_address_t *)exts[SPD_EXT_LCLADDR];
20537c478bd9Sstevel@tonic-gate 
20547c478bd9Sstevel@tonic-gate 		(void) printf("laddr ");
20558810c16bSdanmcd 		print_raw_address((spd_address + 1),
20568810c16bSdanmcd 		    (spd_address->spd_address_len == 2));
20577c478bd9Sstevel@tonic-gate 		(void) printf("/%d ", spd_address->spd_address_prefixlen);
20587c478bd9Sstevel@tonic-gate 	}
20597c478bd9Sstevel@tonic-gate 
20607c478bd9Sstevel@tonic-gate 	if (exts[SPD_EXT_LCLPORT] != NULL) {
20617c478bd9Sstevel@tonic-gate 		spd_portrange = (struct spd_portrange *)exts[SPD_EXT_LCLPORT];
20627c478bd9Sstevel@tonic-gate 		if (spd_portrange->spd_ports_minport != 0) {
20637c478bd9Sstevel@tonic-gate 			print_port(spd_portrange->spd_ports_minport,
20647c478bd9Sstevel@tonic-gate 			    TOK_lport);
20657c478bd9Sstevel@tonic-gate 		}
20667c478bd9Sstevel@tonic-gate 	}
20677c478bd9Sstevel@tonic-gate 
20687c478bd9Sstevel@tonic-gate 
20697c478bd9Sstevel@tonic-gate 	if (exts[SPD_EXT_REMADDR] != NULL) {
20707c478bd9Sstevel@tonic-gate 		spd_address = (spd_address_t *)exts[SPD_EXT_REMADDR];
20717c478bd9Sstevel@tonic-gate 
20727c478bd9Sstevel@tonic-gate 		(void) printf("raddr ");
20738810c16bSdanmcd 		print_raw_address((spd_address + 1),
20748810c16bSdanmcd 		    (spd_address->spd_address_len == 2));
20757c478bd9Sstevel@tonic-gate 		(void) printf("/%d ", spd_address->spd_address_prefixlen);
20767c478bd9Sstevel@tonic-gate 	}
20777c478bd9Sstevel@tonic-gate 
20787c478bd9Sstevel@tonic-gate 	if (exts[SPD_EXT_REMPORT] != NULL) {
20797c478bd9Sstevel@tonic-gate 		spd_portrange =
2080d5751483Smarkfen 		    (struct spd_portrange *)exts[SPD_EXT_REMPORT];
20817c478bd9Sstevel@tonic-gate 		if (spd_portrange->spd_ports_minport != 0) {
20827c478bd9Sstevel@tonic-gate 			print_port(
2083d5751483Smarkfen 			    spd_portrange->spd_ports_minport, TOK_rport);
20847c478bd9Sstevel@tonic-gate 		}
20857c478bd9Sstevel@tonic-gate 	}
20867c478bd9Sstevel@tonic-gate 
20877c478bd9Sstevel@tonic-gate 	if (exts[SPD_EXT_ICMP_TYPECODE] != NULL) {
20887c478bd9Sstevel@tonic-gate 		spd_typecode =
20897c478bd9Sstevel@tonic-gate 		    (struct spd_typecode *)exts[SPD_EXT_ICMP_TYPECODE];
20907c478bd9Sstevel@tonic-gate 		print_icmp_typecode(spd_typecode->spd_typecode_type,
20917c478bd9Sstevel@tonic-gate 		    spd_typecode->spd_typecode_type_end,
20927c478bd9Sstevel@tonic-gate 		    spd_typecode->spd_typecode_code,
20937c478bd9Sstevel@tonic-gate 		    spd_typecode->spd_typecode_code_end);
20947c478bd9Sstevel@tonic-gate 	}
20957c478bd9Sstevel@tonic-gate 
20967c478bd9Sstevel@tonic-gate 	if (exts[SPD_EXT_RULE] != NULL) {
20977c478bd9Sstevel@tonic-gate 		spd_rule = (struct spd_rule *)exts[SPD_EXT_RULE];
20987c478bd9Sstevel@tonic-gate 		print_spd_flags(spd_rule->spd_rule_flags);
20997c478bd9Sstevel@tonic-gate 	}
21007c478bd9Sstevel@tonic-gate 
21017c478bd9Sstevel@tonic-gate 
21027c478bd9Sstevel@tonic-gate 	(void) printf("%c ", CURL_END);
21037c478bd9Sstevel@tonic-gate 
21047c478bd9Sstevel@tonic-gate 	if (exts[SPD_EXT_ACTION] != NULL) {
21057c478bd9Sstevel@tonic-gate 		ips_act_props_t iap;
21067c478bd9Sstevel@tonic-gate 		int or_needed = 0;
21077c478bd9Sstevel@tonic-gate 
21087c478bd9Sstevel@tonic-gate 		(void) memset(&iap, 0, sizeof (iap));
21097c478bd9Sstevel@tonic-gate 		spd_ext_actions =
21107c478bd9Sstevel@tonic-gate 		    (struct spd_ext_actions *)exts[SPD_EXT_ACTION];
21117c478bd9Sstevel@tonic-gate 		app = (struct spd_attribute *)(spd_ext_actions + 1);
21127c478bd9Sstevel@tonic-gate 
21137c478bd9Sstevel@tonic-gate 		for (act_count = 0;
21147c478bd9Sstevel@tonic-gate 		    act_count < spd_ext_actions->spd_actions_len -1;
2115d5751483Smarkfen 		    act_count++) {
21167c478bd9Sstevel@tonic-gate 
21177c478bd9Sstevel@tonic-gate 			switch (app->spd_attr_tag) {
21187c478bd9Sstevel@tonic-gate 
21197c478bd9Sstevel@tonic-gate 			case SPD_ATTR_NOP:
21207c478bd9Sstevel@tonic-gate 				break;
21217c478bd9Sstevel@tonic-gate 
21227c478bd9Sstevel@tonic-gate 			case SPD_ATTR_END:
21237c478bd9Sstevel@tonic-gate 				/* print */
21247c478bd9Sstevel@tonic-gate 				if (or_needed) {
21257c478bd9Sstevel@tonic-gate 					(void) printf("or ");
21267c478bd9Sstevel@tonic-gate 				} else {
21277c478bd9Sstevel@tonic-gate 					or_needed = 1;
21287c478bd9Sstevel@tonic-gate 				}
21297c478bd9Sstevel@tonic-gate 				print_iap(&iap);
21307c478bd9Sstevel@tonic-gate 				break;
21317c478bd9Sstevel@tonic-gate 
21327c478bd9Sstevel@tonic-gate 			case SPD_ATTR_EMPTY:
21337c478bd9Sstevel@tonic-gate 				/* clear */
21347c478bd9Sstevel@tonic-gate 				(void) memset(&iap, 0, sizeof (iap));
21357c478bd9Sstevel@tonic-gate 				break;
21367c478bd9Sstevel@tonic-gate 
21377c478bd9Sstevel@tonic-gate 			case SPD_ATTR_NEXT:
21387c478bd9Sstevel@tonic-gate 				/* print */
21397c478bd9Sstevel@tonic-gate 				if (or_needed) {
21407c478bd9Sstevel@tonic-gate 					(void) printf("or ");
21417c478bd9Sstevel@tonic-gate 				} else {
21427c478bd9Sstevel@tonic-gate 					or_needed = 1;
21437c478bd9Sstevel@tonic-gate 				}
21447c478bd9Sstevel@tonic-gate 
21457c478bd9Sstevel@tonic-gate 				print_iap(&iap);
21467c478bd9Sstevel@tonic-gate 				break;
21477c478bd9Sstevel@tonic-gate 
21487c478bd9Sstevel@tonic-gate 			case SPD_ATTR_TYPE:
21497c478bd9Sstevel@tonic-gate 				iap.iap_action = app->spd_attr_value;
21507c478bd9Sstevel@tonic-gate 				break;
21517c478bd9Sstevel@tonic-gate 
21527c478bd9Sstevel@tonic-gate 			case SPD_ATTR_FLAGS:
21537c478bd9Sstevel@tonic-gate 				iap.iap_attr = app->spd_attr_value;
21547c478bd9Sstevel@tonic-gate 				break;
21557c478bd9Sstevel@tonic-gate 
21567c478bd9Sstevel@tonic-gate 			case SPD_ATTR_AH_AUTH:
21577c478bd9Sstevel@tonic-gate 				iap.iap_aauth.alg_id = app->spd_attr_value;
21587c478bd9Sstevel@tonic-gate 				break;
21597c478bd9Sstevel@tonic-gate 
21607c478bd9Sstevel@tonic-gate 			case SPD_ATTR_ESP_ENCR:
21617c478bd9Sstevel@tonic-gate 				iap.iap_eencr.alg_id = app->spd_attr_value;
21627c478bd9Sstevel@tonic-gate 				break;
21637c478bd9Sstevel@tonic-gate 
21647c478bd9Sstevel@tonic-gate 			case SPD_ATTR_ESP_AUTH:
21657c478bd9Sstevel@tonic-gate 				iap.iap_eauth.alg_id = app->spd_attr_value;
21667c478bd9Sstevel@tonic-gate 				break;
21677c478bd9Sstevel@tonic-gate 
21687c478bd9Sstevel@tonic-gate 			case SPD_ATTR_ENCR_MINBITS:
21697c478bd9Sstevel@tonic-gate 				iap.iap_eencr.alg_minbits = app->spd_attr_value;
21707c478bd9Sstevel@tonic-gate 				break;
21717c478bd9Sstevel@tonic-gate 
21727c478bd9Sstevel@tonic-gate 			case SPD_ATTR_ENCR_MAXBITS:
21737c478bd9Sstevel@tonic-gate 				iap.iap_eencr.alg_maxbits = app->spd_attr_value;
21747c478bd9Sstevel@tonic-gate 				break;
21757c478bd9Sstevel@tonic-gate 
21767c478bd9Sstevel@tonic-gate 			case SPD_ATTR_AH_MINBITS:
21777c478bd9Sstevel@tonic-gate 				iap.iap_aauth.alg_minbits = app->spd_attr_value;
21787c478bd9Sstevel@tonic-gate 				break;
21797c478bd9Sstevel@tonic-gate 
21807c478bd9Sstevel@tonic-gate 			case SPD_ATTR_AH_MAXBITS:
21817c478bd9Sstevel@tonic-gate 				iap.iap_aauth.alg_maxbits = app->spd_attr_value;
21827c478bd9Sstevel@tonic-gate 				break;
21837c478bd9Sstevel@tonic-gate 
21847c478bd9Sstevel@tonic-gate 			case SPD_ATTR_ESPA_MINBITS:
21857c478bd9Sstevel@tonic-gate 				iap.iap_eauth.alg_minbits = app->spd_attr_value;
21867c478bd9Sstevel@tonic-gate 				break;
21877c478bd9Sstevel@tonic-gate 
21887c478bd9Sstevel@tonic-gate 			case SPD_ATTR_ESPA_MAXBITS:
21897c478bd9Sstevel@tonic-gate 				iap.iap_eauth.alg_maxbits = app->spd_attr_value;
21907c478bd9Sstevel@tonic-gate 				break;
21917c478bd9Sstevel@tonic-gate 
21927c478bd9Sstevel@tonic-gate 			case SPD_ATTR_LIFE_SOFT_TIME:
21937c478bd9Sstevel@tonic-gate 			case SPD_ATTR_LIFE_HARD_TIME:
21947c478bd9Sstevel@tonic-gate 			case SPD_ATTR_LIFE_SOFT_BYTES:
21957c478bd9Sstevel@tonic-gate 			case SPD_ATTR_LIFE_HARD_BYTES:
21967c478bd9Sstevel@tonic-gate 			default:
21977c478bd9Sstevel@tonic-gate 				(void) printf("\tattr %d: %X-%d\n",
21987c478bd9Sstevel@tonic-gate 				    act_count,
21997c478bd9Sstevel@tonic-gate 				    app->spd_attr_tag,
22007c478bd9Sstevel@tonic-gate 				    app->spd_attr_value);
22017c478bd9Sstevel@tonic-gate 				break;
22027c478bd9Sstevel@tonic-gate 			}
22037c478bd9Sstevel@tonic-gate 			app++;
22047c478bd9Sstevel@tonic-gate 		}
22057c478bd9Sstevel@tonic-gate 	}
22067c478bd9Sstevel@tonic-gate 
22077c478bd9Sstevel@tonic-gate 	(void) printf("\n");
22087c478bd9Sstevel@tonic-gate }
22097c478bd9Sstevel@tonic-gate 
22107c478bd9Sstevel@tonic-gate #ifdef DEBUG_HEAVY
22117c478bd9Sstevel@tonic-gate static void
22127c478bd9Sstevel@tonic-gate pfpol_msg_dump(spd_msg_t *msg, char *tag)
22137c478bd9Sstevel@tonic-gate {
22147c478bd9Sstevel@tonic-gate 	spd_ext_t *exts[SPD_EXT_MAX+1];
22157c478bd9Sstevel@tonic-gate 	uint32_t i;
22167c478bd9Sstevel@tonic-gate 	spd_address_t *spd_address;
22177c478bd9Sstevel@tonic-gate 	struct spd_rule *spd_rule;
22187c478bd9Sstevel@tonic-gate 	struct spd_proto *spd_proto;
22197c478bd9Sstevel@tonic-gate 	struct spd_portrange *spd_portrange;
22207c478bd9Sstevel@tonic-gate 	struct spd_typecode *spd_typecode;
22217c478bd9Sstevel@tonic-gate 	struct spd_ext_actions *spd_ext_actions;
22227c478bd9Sstevel@tonic-gate 	struct spd_attribute *app;
22238810c16bSdanmcd 	spd_if_t *spd_if;
22247c478bd9Sstevel@tonic-gate 	char abuf[INET6_ADDRSTRLEN];
22257c478bd9Sstevel@tonic-gate 	uint32_t rv;
22267c478bd9Sstevel@tonic-gate 	uint16_t act_count;
22277c478bd9Sstevel@tonic-gate 
22287c478bd9Sstevel@tonic-gate 	rv = spdsock_get_ext(exts, msg, msg->spd_msg_len, NULL, 0);
22297c478bd9Sstevel@tonic-gate 	if (rv != KGE_OK)
22307c478bd9Sstevel@tonic-gate 		return;
22317c478bd9Sstevel@tonic-gate 
22327c478bd9Sstevel@tonic-gate 	(void) printf("===========%s==============\n", tag);
22337c478bd9Sstevel@tonic-gate 	(void) printf("pfpol_msg_dump %d\n-------------------\n", rv);
22347c478bd9Sstevel@tonic-gate 
22357c478bd9Sstevel@tonic-gate 	(void) printf("spd_msg_version:%d\n", msg->spd_msg_version);
22367c478bd9Sstevel@tonic-gate 	(void) printf("spd_msg_type:%d\n", msg->spd_msg_type);
22377c478bd9Sstevel@tonic-gate 	(void) printf("spd_msg_errno:%d\n", msg->spd_msg_errno);
22387c478bd9Sstevel@tonic-gate 	(void) printf("spd_msg_spdid:%d\n", msg->spd_msg_spdid);
22397c478bd9Sstevel@tonic-gate 	(void) printf("spd_msg_len:%d\n", msg->spd_msg_len);
22407c478bd9Sstevel@tonic-gate 	(void) printf("spd_msg_diagnostic:%d\n", msg->spd_msg_diagnostic);
22417c478bd9Sstevel@tonic-gate 	(void) printf("spd_msg_seq:%d\n", msg->spd_msg_seq);
22427c478bd9Sstevel@tonic-gate 	(void) printf("spd_msg_pid:%d\n", msg->spd_msg_pid);
22437c478bd9Sstevel@tonic-gate 
22447c478bd9Sstevel@tonic-gate 	for (i = 1; i <= SPD_EXT_MAX; i++) {
22457c478bd9Sstevel@tonic-gate 		if (exts[i] == NULL) {
22467c478bd9Sstevel@tonic-gate 			printf("skipped %d\n", i);
22477c478bd9Sstevel@tonic-gate 			continue;
22487c478bd9Sstevel@tonic-gate 		}
22497c478bd9Sstevel@tonic-gate 
22507c478bd9Sstevel@tonic-gate 		switch (i) {
22518810c16bSdanmcd 		case SPD_EXT_TUN_NAME:
22528810c16bSdanmcd 			spd_if = (spd_if_t *)exts[i];
22538810c16bSdanmcd 			(void) printf("spd_if = %s\n", spd_if->spd_if_name);
22548810c16bSdanmcd 			break;
22558810c16bSdanmcd 
22567c478bd9Sstevel@tonic-gate 		case SPD_EXT_ICMP_TYPECODE:
22577c478bd9Sstevel@tonic-gate 			spd_typecode = (struct spd_typecode *)exts[i];
22587c478bd9Sstevel@tonic-gate 			(void) printf("icmp type %d-%d code %d-%d\n",
22597c478bd9Sstevel@tonic-gate 			    spd_typecode->spd_typecode_type,
22607c478bd9Sstevel@tonic-gate 			    spd_typecode->spd_typecode_type_end,
22617c478bd9Sstevel@tonic-gate 			    spd_typecode->spd_typecode_code,
22627c478bd9Sstevel@tonic-gate 			    spd_typecode->spd_typecode_code_end);
22637c478bd9Sstevel@tonic-gate 			break;
22647c478bd9Sstevel@tonic-gate 
22657c478bd9Sstevel@tonic-gate 		case SPD_EXT_LCLPORT:
22667c478bd9Sstevel@tonic-gate 			spd_portrange = (struct spd_portrange *)exts[i];
22677c478bd9Sstevel@tonic-gate 			(void) printf("local ports %d-%d\n",
22687c478bd9Sstevel@tonic-gate 			    spd_portrange->spd_ports_minport,
22697c478bd9Sstevel@tonic-gate 			    spd_portrange->spd_ports_maxport);
22707c478bd9Sstevel@tonic-gate 
22717c478bd9Sstevel@tonic-gate 			break;
22727c478bd9Sstevel@tonic-gate 
22737c478bd9Sstevel@tonic-gate 		case SPD_EXT_REMPORT:
22747c478bd9Sstevel@tonic-gate 			spd_portrange = (struct spd_portrange *)exts[i];
22757c478bd9Sstevel@tonic-gate 			(void) printf("remote ports %d-%d\n",
22767c478bd9Sstevel@tonic-gate 			    spd_portrange->spd_ports_minport,
22777c478bd9Sstevel@tonic-gate 			    spd_portrange->spd_ports_maxport);
22787c478bd9Sstevel@tonic-gate 
22797c478bd9Sstevel@tonic-gate 			break;
22807c478bd9Sstevel@tonic-gate 
22817c478bd9Sstevel@tonic-gate 		case SPD_EXT_PROTO:
22827c478bd9Sstevel@tonic-gate 			spd_proto = (struct spd_proto *)exts[i];
22837c478bd9Sstevel@tonic-gate 			(void) printf("proto:spd_proto_exttype %d\n",
22847c478bd9Sstevel@tonic-gate 			    spd_proto->spd_proto_exttype);
22857c478bd9Sstevel@tonic-gate 			(void) printf("proto:spd_proto_number %d\n",
22867c478bd9Sstevel@tonic-gate 			    spd_proto->spd_proto_number);
22877c478bd9Sstevel@tonic-gate 			break;
22887c478bd9Sstevel@tonic-gate 
22897c478bd9Sstevel@tonic-gate 		case SPD_EXT_LCLADDR:
22907c478bd9Sstevel@tonic-gate 		case SPD_EXT_REMADDR:
22917c478bd9Sstevel@tonic-gate 			spd_address = (spd_address_t *)exts[i];
22927c478bd9Sstevel@tonic-gate 			if (i == SPD_EXT_LCLADDR)
22937c478bd9Sstevel@tonic-gate 				(void) printf("local addr ");
22947c478bd9Sstevel@tonic-gate 			else
22957c478bd9Sstevel@tonic-gate 				(void) printf("remote addr ");
22967c478bd9Sstevel@tonic-gate 
22977c478bd9Sstevel@tonic-gate 
22987c478bd9Sstevel@tonic-gate 			(void) printf("%s\n",
22997c478bd9Sstevel@tonic-gate 			    inet_ntop(spd_address->spd_address_af,
2300d5751483Smarkfen 			    (void *) (spd_address +1), abuf,
2301d5751483Smarkfen 			    INET6_ADDRSTRLEN));
23027c478bd9Sstevel@tonic-gate 
23037c478bd9Sstevel@tonic-gate 			(void) printf("prefixlen: %d\n",
23047c478bd9Sstevel@tonic-gate 			    spd_address->spd_address_prefixlen);
23057c478bd9Sstevel@tonic-gate 			break;
23067c478bd9Sstevel@tonic-gate 
23077c478bd9Sstevel@tonic-gate 		case SPD_EXT_ACTION:
23087c478bd9Sstevel@tonic-gate 			spd_ext_actions = (struct spd_ext_actions *)exts[i];
23097c478bd9Sstevel@tonic-gate 			(void) printf("spd_ext_action\n");
23107c478bd9Sstevel@tonic-gate 			(void) printf("spd_actions_count %d\n",
23117c478bd9Sstevel@tonic-gate 			    spd_ext_actions->spd_actions_count);
23127c478bd9Sstevel@tonic-gate 			app = (struct spd_attribute *)(spd_ext_actions + 1);
23137c478bd9Sstevel@tonic-gate 
23147c478bd9Sstevel@tonic-gate 			for (act_count = 0;
23157c478bd9Sstevel@tonic-gate 			    act_count < spd_ext_actions->spd_actions_len -1;
23167c478bd9Sstevel@tonic-gate 			    act_count++) {
23177c478bd9Sstevel@tonic-gate 				(void) printf("\tattr %d: %X-%d\n", act_count,
23187c478bd9Sstevel@tonic-gate 				    app->spd_attr_tag, app->spd_attr_value);
23197c478bd9Sstevel@tonic-gate 				app++;
23207c478bd9Sstevel@tonic-gate 			}
23217c478bd9Sstevel@tonic-gate 
23227c478bd9Sstevel@tonic-gate 			break;
23237c478bd9Sstevel@tonic-gate 
23247c478bd9Sstevel@tonic-gate 		case SPD_EXT_RULE:
23257c478bd9Sstevel@tonic-gate 			spd_rule = (struct spd_rule *)exts[i];
23267c478bd9Sstevel@tonic-gate 			(void) printf("spd_rule_priority: 0x%x\n",
23277c478bd9Sstevel@tonic-gate 			    spd_rule->spd_rule_priority);
23287c478bd9Sstevel@tonic-gate 			(void) printf("spd_rule_flags: %d\n",
23297c478bd9Sstevel@tonic-gate 			    spd_rule->spd_rule_flags);
23307c478bd9Sstevel@tonic-gate 			break;
23317c478bd9Sstevel@tonic-gate 
23327c478bd9Sstevel@tonic-gate 		case SPD_EXT_RULESET:
23337c478bd9Sstevel@tonic-gate 			(void) printf("spd_ext_ruleset\n");
23347c478bd9Sstevel@tonic-gate 			break;
23357c478bd9Sstevel@tonic-gate 		default:
23367c478bd9Sstevel@tonic-gate 			(void) printf("default\n");
23377c478bd9Sstevel@tonic-gate 			break;
23387c478bd9Sstevel@tonic-gate 		}
23397c478bd9Sstevel@tonic-gate 	}
23407c478bd9Sstevel@tonic-gate 
23417c478bd9Sstevel@tonic-gate 	(void) printf("-------------------\n");
23427c478bd9Sstevel@tonic-gate 	(void) printf("=========================\n");
23437c478bd9Sstevel@tonic-gate }
23447c478bd9Sstevel@tonic-gate #endif /* DEBUG_HEAVY */
23457c478bd9Sstevel@tonic-gate 
23467c478bd9Sstevel@tonic-gate static int
23477c478bd9Sstevel@tonic-gate ipsec_conf_view()
23487c478bd9Sstevel@tonic-gate {
23497c478bd9Sstevel@tonic-gate 	char buf[MAXLEN];
23507c478bd9Sstevel@tonic-gate 	FILE *fp;
23517c478bd9Sstevel@tonic-gate 
23527c478bd9Sstevel@tonic-gate 	fp = fopen(POLICY_CONF_FILE, "r");
23537c478bd9Sstevel@tonic-gate 	if (fp == NULL) {
23547c478bd9Sstevel@tonic-gate 		if (errno == ENOENT) {
23557c478bd9Sstevel@tonic-gate 			/*
23567c478bd9Sstevel@tonic-gate 			 * The absence of POLICY_CONF_FILE should
23577c478bd9Sstevel@tonic-gate 			 * not cause the command to exit with a
23587c478bd9Sstevel@tonic-gate 			 * non-zero status, since this condition
23597c478bd9Sstevel@tonic-gate 			 * is valid when no policies were previously
23607c478bd9Sstevel@tonic-gate 			 * defined.
23617c478bd9Sstevel@tonic-gate 			 */
23627c478bd9Sstevel@tonic-gate 			return (0);
23637c478bd9Sstevel@tonic-gate 		}
23647c478bd9Sstevel@tonic-gate 		warn(gettext("%s cannot be opened"), POLICY_CONF_FILE);
23657c478bd9Sstevel@tonic-gate 		return (-1);
23667c478bd9Sstevel@tonic-gate 	}
23677c478bd9Sstevel@tonic-gate 	while (fgets(buf, MAXLEN, fp) != NULL) {
23687c478bd9Sstevel@tonic-gate 		/* Don't print removed entries */
23697c478bd9Sstevel@tonic-gate 		if (*buf == ';')
23707c478bd9Sstevel@tonic-gate 			continue;
23717c478bd9Sstevel@tonic-gate 		if (strlen(buf) != 0)
23727c478bd9Sstevel@tonic-gate 			buf[strlen(buf) - 1] = '\0';
23737c478bd9Sstevel@tonic-gate 		(void) puts(buf);
23747c478bd9Sstevel@tonic-gate 	}
23757c478bd9Sstevel@tonic-gate 	return (0);
23767c478bd9Sstevel@tonic-gate }
23777c478bd9Sstevel@tonic-gate 
23787c478bd9Sstevel@tonic-gate /*
23797c478bd9Sstevel@tonic-gate  * Delete nlines from start in the POLICY_CONF_FILE.
23807c478bd9Sstevel@tonic-gate  */
23817c478bd9Sstevel@tonic-gate static int
23827c478bd9Sstevel@tonic-gate delete_from_file(int start, int nlines)
23837c478bd9Sstevel@tonic-gate {
23847c478bd9Sstevel@tonic-gate 	FILE *fp;
23857c478bd9Sstevel@tonic-gate 	char ibuf[MAXLEN];
23867c478bd9Sstevel@tonic-gate 	int len;
23877c478bd9Sstevel@tonic-gate 
23887c478bd9Sstevel@tonic-gate 	if ((fp = fopen(POLICY_CONF_FILE, "r+b")) == NULL) {
23897c478bd9Sstevel@tonic-gate 		warn(gettext("%s cannot be opened"), POLICY_CONF_FILE);
23907c478bd9Sstevel@tonic-gate 		return (-1);
23917c478bd9Sstevel@tonic-gate 	}
23927c478bd9Sstevel@tonic-gate 
23937c478bd9Sstevel@tonic-gate 	/*
23947c478bd9Sstevel@tonic-gate 	 * Insert a ";", read the line and discard it. Repeat
23957c478bd9Sstevel@tonic-gate 	 * this logic nlines - 1 times. For the last line there
23967c478bd9Sstevel@tonic-gate 	 * is just a newline character. We can't just insert a
23977c478bd9Sstevel@tonic-gate 	 * single ";" character instead of the newline character
23987c478bd9Sstevel@tonic-gate 	 * as it would affect the next line. Thus when we comment
23997c478bd9Sstevel@tonic-gate 	 * the last line we seek one less and insert a ";"
24007c478bd9Sstevel@tonic-gate 	 * character, which will replace the newline of the
24017c478bd9Sstevel@tonic-gate 	 * penultimate line with ; and newline of the last line
24027c478bd9Sstevel@tonic-gate 	 * will become part of the previous line.
24037c478bd9Sstevel@tonic-gate 	 */
24047c478bd9Sstevel@tonic-gate 	do {
24057c478bd9Sstevel@tonic-gate 		/*
24067c478bd9Sstevel@tonic-gate 		 * It is not enough to seek just once and expect the
24077c478bd9Sstevel@tonic-gate 		 * subsequent fgets below to take you to the right
24087c478bd9Sstevel@tonic-gate 		 * offset of the next line. fgets below seems to affect
24097c478bd9Sstevel@tonic-gate 		 * the offset. Thus we need to seek, replace with ";",
24107c478bd9Sstevel@tonic-gate 		 * and discard a line using fgets for every line.
24117c478bd9Sstevel@tonic-gate 		 */
24127c478bd9Sstevel@tonic-gate 		if (fseek(fp, start, SEEK_SET) == -1) {
24137c478bd9Sstevel@tonic-gate 			warn("fseek");
24147c478bd9Sstevel@tonic-gate 			return (-1);
24157c478bd9Sstevel@tonic-gate 		}
24167c478bd9Sstevel@tonic-gate 		if (fputc(';', fp) < 0) {
24177c478bd9Sstevel@tonic-gate 			warn("fputc");
24187c478bd9Sstevel@tonic-gate 			return (-1);
24197c478bd9Sstevel@tonic-gate 		}
24207c478bd9Sstevel@tonic-gate 		/*
24217c478bd9Sstevel@tonic-gate 		 * Flush the above ";" character before we do the fgets().
24227c478bd9Sstevel@tonic-gate 		 * Without this, fgets() gets confused with offsets.
24237c478bd9Sstevel@tonic-gate 		 */
24247c478bd9Sstevel@tonic-gate 		(void) fflush(fp);
24257c478bd9Sstevel@tonic-gate 		len = 0;
24267c478bd9Sstevel@tonic-gate 		while (fgets(ibuf, MAXLEN, fp) != NULL) {
24277c478bd9Sstevel@tonic-gate 			len += strlen(ibuf);
24287c478bd9Sstevel@tonic-gate 			if (ibuf[len - 1] == '\n') {
24297c478bd9Sstevel@tonic-gate 				/*
24307c478bd9Sstevel@tonic-gate 				 * We have read a complete line.
24317c478bd9Sstevel@tonic-gate 				 */
24327c478bd9Sstevel@tonic-gate 				break;
24337c478bd9Sstevel@tonic-gate 			}
24347c478bd9Sstevel@tonic-gate 		}
24357c478bd9Sstevel@tonic-gate 		/*
24367c478bd9Sstevel@tonic-gate 		 * We read the line after ";" character has been inserted.
24377c478bd9Sstevel@tonic-gate 		 * Thus len does not count ";". To advance to the next line
24387c478bd9Sstevel@tonic-gate 		 * increment by 1.
24397c478bd9Sstevel@tonic-gate 		 */
24407c478bd9Sstevel@tonic-gate 		start += (len + 1);
24417c478bd9Sstevel@tonic-gate 		/*
24427c478bd9Sstevel@tonic-gate 		 * If nlines == 2, we will be commenting out the last
24437c478bd9Sstevel@tonic-gate 		 * line next, which has only one newline character.
24447c478bd9Sstevel@tonic-gate 		 * If we blindly replace it with ";", it will  be
24457c478bd9Sstevel@tonic-gate 		 * read as part of the next line which could have
24467c478bd9Sstevel@tonic-gate 		 * a INDEX string and thus confusing ipsec_conf_view.
24477c478bd9Sstevel@tonic-gate 		 * Thus, we seek one less and replace the previous
24487c478bd9Sstevel@tonic-gate 		 * line's newline character with ";", and the
24497c478bd9Sstevel@tonic-gate 		 * last line's newline character will become part of
24507c478bd9Sstevel@tonic-gate 		 * the previous line.
24517c478bd9Sstevel@tonic-gate 		 */
24527c478bd9Sstevel@tonic-gate 		if (nlines == 2)
24537c478bd9Sstevel@tonic-gate 			start--;
24547c478bd9Sstevel@tonic-gate 	} while (--nlines != 0);
24557c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
24567c478bd9Sstevel@tonic-gate 	if (nlines != 0)
24577c478bd9Sstevel@tonic-gate 		return (-1);
24587c478bd9Sstevel@tonic-gate 	else
24597c478bd9Sstevel@tonic-gate 		return (0);
24607c478bd9Sstevel@tonic-gate }
24617c478bd9Sstevel@tonic-gate 
24627c478bd9Sstevel@tonic-gate /*
24637c478bd9Sstevel@tonic-gate  * Delete an entry from the file by inserting a ";" at the
24647c478bd9Sstevel@tonic-gate  * beginning of the lines to be removed.
24657c478bd9Sstevel@tonic-gate  */
24667c478bd9Sstevel@tonic-gate static int
24677c478bd9Sstevel@tonic-gate ipsec_conf_del(int policy_index, boolean_t ignore_spd)
24687c478bd9Sstevel@tonic-gate {
24697c478bd9Sstevel@tonic-gate 	act_prop_t *act_props = malloc(sizeof (act_prop_t));
24707c478bd9Sstevel@tonic-gate 	char *buf;
24717c478bd9Sstevel@tonic-gate 	FILE *fp;
24727c478bd9Sstevel@tonic-gate 	char ibuf[MAXLEN];
24737c478bd9Sstevel@tonic-gate 	int ibuf_len, index_len, index;
24747c478bd9Sstevel@tonic-gate 	int ret = 0;
24757c478bd9Sstevel@tonic-gate 	int offset, prev_offset;
24767c478bd9Sstevel@tonic-gate 	int nlines;
24778810c16bSdanmcd 	char lifname[LIFNAMSIZ];
24787c478bd9Sstevel@tonic-gate 
24797c478bd9Sstevel@tonic-gate 	if (act_props == NULL) {
24807c478bd9Sstevel@tonic-gate 		warn(gettext("memory"));
24817c478bd9Sstevel@tonic-gate 		return (-1);
24827c478bd9Sstevel@tonic-gate 	}
24837c478bd9Sstevel@tonic-gate 
24847c478bd9Sstevel@tonic-gate 	fp = fopen(POLICY_CONF_FILE, "r");
24857c478bd9Sstevel@tonic-gate 	if (fp == NULL) {
24867c478bd9Sstevel@tonic-gate 		warn(gettext("%s cannot be opened"), POLICY_CONF_FILE);
24877c478bd9Sstevel@tonic-gate 		free(act_props);
24887c478bd9Sstevel@tonic-gate 		return (-1);
24897c478bd9Sstevel@tonic-gate 	}
24907c478bd9Sstevel@tonic-gate 
24917c478bd9Sstevel@tonic-gate 	index_len = strlen(INDEX_TAG);
24927c478bd9Sstevel@tonic-gate 	index = 0;
24937c478bd9Sstevel@tonic-gate 	for (offset = prev_offset = 0; fgets(ibuf, MAXLEN, fp) != NULL;
24947c478bd9Sstevel@tonic-gate 	    offset += ibuf_len) {
24957c478bd9Sstevel@tonic-gate 		prev_offset = offset;
24967c478bd9Sstevel@tonic-gate 		ibuf_len = strlen(ibuf);
24977c478bd9Sstevel@tonic-gate 
24987c478bd9Sstevel@tonic-gate 		if (strncmp(ibuf, INDEX_TAG, index_len) != 0) {
24997c478bd9Sstevel@tonic-gate 			continue;
25007c478bd9Sstevel@tonic-gate 		}
25017c478bd9Sstevel@tonic-gate 
25027c478bd9Sstevel@tonic-gate 		/*
25037c478bd9Sstevel@tonic-gate 		 * This line contains INDEX_TAG
25047c478bd9Sstevel@tonic-gate 		 */
25057c478bd9Sstevel@tonic-gate 		buf = ibuf + index_len;
25067c478bd9Sstevel@tonic-gate 		buf++;			/* Skip the space */
25078810c16bSdanmcd 		index = parse_index(buf, lifname);
25087c478bd9Sstevel@tonic-gate 		if (index == -1) {
25097c478bd9Sstevel@tonic-gate 			warnx(gettext("Invalid index in the file"));
25107c478bd9Sstevel@tonic-gate 			free(act_props);
25117c478bd9Sstevel@tonic-gate 			return (-1);
25127c478bd9Sstevel@tonic-gate 		}
25138810c16bSdanmcd 		if (index == policy_index &&
25148810c16bSdanmcd 		    (interface_name == NULL ||
2515d5751483Smarkfen 		    strncmp(interface_name, lifname, LIFNAMSIZ) == 0)) {
25167c478bd9Sstevel@tonic-gate 			if (!ignore_spd) {
25177c478bd9Sstevel@tonic-gate 				ret = parse_one(fp, act_props);
25187c478bd9Sstevel@tonic-gate 				if (ret == -1) {
25197c478bd9Sstevel@tonic-gate 					warnx(gettext("Invalid policy entry "
25207c478bd9Sstevel@tonic-gate 					    "in the file"));
25217c478bd9Sstevel@tonic-gate 					free(act_props);
25227c478bd9Sstevel@tonic-gate 					return (-1);
25237c478bd9Sstevel@tonic-gate 				}
25247c478bd9Sstevel@tonic-gate 			}
25257c478bd9Sstevel@tonic-gate 			/*
25267c478bd9Sstevel@tonic-gate 			 * nlines is the number of lines we should comment
25277c478bd9Sstevel@tonic-gate 			 * out. linecount tells us how many lines this command
25287c478bd9Sstevel@tonic-gate 			 * spans. And we need to remove the line with INDEX
25297c478bd9Sstevel@tonic-gate 			 * and an extra line we added during ipsec_conf_add.
25307c478bd9Sstevel@tonic-gate 			 *
25317c478bd9Sstevel@tonic-gate 			 * NOTE : If somebody added a policy entry which does
25327c478bd9Sstevel@tonic-gate 			 * not have a newline, ipsec_conf_add() fills in the
25337c478bd9Sstevel@tonic-gate 			 * newline. Hence, there is always 2 extra lines
25347c478bd9Sstevel@tonic-gate 			 * to delete.
25357c478bd9Sstevel@tonic-gate 			 */
25367c478bd9Sstevel@tonic-gate 			nlines = linecount + 2;
25377c478bd9Sstevel@tonic-gate 			goto delete;
25387c478bd9Sstevel@tonic-gate 		}
25397c478bd9Sstevel@tonic-gate 	}
25407c478bd9Sstevel@tonic-gate 
25417c478bd9Sstevel@tonic-gate 	if (!ignore_spd)
25427c478bd9Sstevel@tonic-gate 		ret = pfp_delete_rule(policy_index);
25437c478bd9Sstevel@tonic-gate 
25447c478bd9Sstevel@tonic-gate 	if (ret != 0) {
25457c478bd9Sstevel@tonic-gate 		warnx(gettext("Deletion incomplete. Please "
25467c478bd9Sstevel@tonic-gate 		    "flush all the entries and re-configure :"));
25477c478bd9Sstevel@tonic-gate 		reconfigure();
25487c478bd9Sstevel@tonic-gate 		free(act_props);
25497c478bd9Sstevel@tonic-gate 		return (ret);
25507c478bd9Sstevel@tonic-gate 	}
25517c478bd9Sstevel@tonic-gate 	free(act_props);
25527c478bd9Sstevel@tonic-gate 	return (ret);
25537c478bd9Sstevel@tonic-gate 
25547c478bd9Sstevel@tonic-gate delete:
25557c478bd9Sstevel@tonic-gate 	/* Delete nlines from prev_offset */
25567c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
25577c478bd9Sstevel@tonic-gate 	ret = delete_from_file(prev_offset, nlines);
25587c478bd9Sstevel@tonic-gate 
25597c478bd9Sstevel@tonic-gate 	if (ret != 0) {
25607c478bd9Sstevel@tonic-gate 		warnx(gettext("Deletion incomplete. Please "
25617c478bd9Sstevel@tonic-gate 		    "flush all the entries and re-configure :"));
25627c478bd9Sstevel@tonic-gate 		reconfigure();
25637c478bd9Sstevel@tonic-gate 		free(act_props);
25647c478bd9Sstevel@tonic-gate 		return (ret);
25657c478bd9Sstevel@tonic-gate 	}
25667c478bd9Sstevel@tonic-gate 
25677c478bd9Sstevel@tonic-gate 	if (!ignore_spd)
25687c478bd9Sstevel@tonic-gate 		ret = pfp_delete_rule(policy_index);
25697c478bd9Sstevel@tonic-gate 
25707c478bd9Sstevel@tonic-gate 	if (ret != 0) {
25717c478bd9Sstevel@tonic-gate 		warnx(gettext("Deletion incomplete. Please "
25727c478bd9Sstevel@tonic-gate 		    "flush all the entries and re-configure :"));
25737c478bd9Sstevel@tonic-gate 		reconfigure();
25747c478bd9Sstevel@tonic-gate 		free(act_props);
25757c478bd9Sstevel@tonic-gate 		return (ret);
25767c478bd9Sstevel@tonic-gate 	}
25777c478bd9Sstevel@tonic-gate 	free(act_props);
25787c478bd9Sstevel@tonic-gate 	return (0);
25797c478bd9Sstevel@tonic-gate }
25807c478bd9Sstevel@tonic-gate 
25817c478bd9Sstevel@tonic-gate static int
25827c478bd9Sstevel@tonic-gate pfp_delete_rule(uint64_t index)
25837c478bd9Sstevel@tonic-gate {
25847c478bd9Sstevel@tonic-gate 	struct spd_msg *msg;
25857c478bd9Sstevel@tonic-gate 	struct spd_rule *rule;
2586e3320f40Smarkfen 	int sfd;
25878810c16bSdanmcd 	int cnt, len, alloclen;
25887c478bd9Sstevel@tonic-gate 
2589e3320f40Smarkfen 	sfd = get_pf_pol_socket();
25907c478bd9Sstevel@tonic-gate 	if (sfd < 0) {
25917c478bd9Sstevel@tonic-gate 		warn(gettext("unable to open policy socket"));
25927c478bd9Sstevel@tonic-gate 		return (-1);
25937c478bd9Sstevel@tonic-gate 	}
25947c478bd9Sstevel@tonic-gate 
25958810c16bSdanmcd 	/*
25968810c16bSdanmcd 	 * Add an extra 8 bytes of space (+1 uint64_t) to avoid truncation
25978810c16bSdanmcd 	 * issues.
25988810c16bSdanmcd 	 */
25998810c16bSdanmcd 	alloclen = sizeof (spd_msg_t) + sizeof (struct spd_rule) +
26008810c16bSdanmcd 	    sizeof (spd_if_t) + LIFNAMSIZ + 8;
26018810c16bSdanmcd 	msg = (spd_msg_t *)malloc(alloclen);
26027c478bd9Sstevel@tonic-gate 
26037c478bd9Sstevel@tonic-gate 	if (msg == NULL) {
26047c478bd9Sstevel@tonic-gate 		warn("malloc");
26057c478bd9Sstevel@tonic-gate 		return (-1);
26067c478bd9Sstevel@tonic-gate 	}
26077c478bd9Sstevel@tonic-gate 
26087c478bd9Sstevel@tonic-gate 	rule = (struct spd_rule *)(msg + 1);
26097c478bd9Sstevel@tonic-gate 
26108810c16bSdanmcd 	(void) memset(msg, 0, alloclen);
26117c478bd9Sstevel@tonic-gate 	msg->spd_msg_version = PF_POLICY_V1;
26127c478bd9Sstevel@tonic-gate 	msg->spd_msg_type = SPD_DELETERULE;
26137c478bd9Sstevel@tonic-gate 	msg->spd_msg_len = SPD_8TO64(sizeof (spd_msg_t)
26147c478bd9Sstevel@tonic-gate 	    + sizeof (struct spd_rule));
26157c478bd9Sstevel@tonic-gate 
26167c478bd9Sstevel@tonic-gate 	rule->spd_rule_type = SPD_EXT_RULE;
26177c478bd9Sstevel@tonic-gate 	rule->spd_rule_len = SPD_8TO64(sizeof (struct spd_rule));
26187c478bd9Sstevel@tonic-gate 	rule->spd_rule_index = index;
26197c478bd9Sstevel@tonic-gate 
26208810c16bSdanmcd 	msg->spd_msg_len += attach_tunname((spd_if_t *)(rule + 1));
26217c478bd9Sstevel@tonic-gate 
26228810c16bSdanmcd 	len = SPD_64TO8(msg->spd_msg_len);
26238810c16bSdanmcd 	cnt = write(sfd, msg, len);
26248810c16bSdanmcd 
26258810c16bSdanmcd 	if (cnt != len) {
26267c478bd9Sstevel@tonic-gate 		if (cnt < 0) {
26277c478bd9Sstevel@tonic-gate 			(void) close(sfd);
26287c478bd9Sstevel@tonic-gate 			free(msg);
26297c478bd9Sstevel@tonic-gate 			warn(gettext("Delete failed: write"));
26307c478bd9Sstevel@tonic-gate 			return (-1);
26317c478bd9Sstevel@tonic-gate 		} else {
26327c478bd9Sstevel@tonic-gate 			(void) close(sfd);
26337c478bd9Sstevel@tonic-gate 			free(msg);
26347c478bd9Sstevel@tonic-gate 			warnx(gettext("Delete failed: short write"));
26357c478bd9Sstevel@tonic-gate 			return (-1);
26367c478bd9Sstevel@tonic-gate 		}
26377c478bd9Sstevel@tonic-gate 	}
26387c478bd9Sstevel@tonic-gate 
26398810c16bSdanmcd 	cnt = read(sfd, msg, len);
26408810c16bSdanmcd 	if (cnt != len) {
26417c478bd9Sstevel@tonic-gate 		if (cnt < 0) {
26427c478bd9Sstevel@tonic-gate 			(void) close(sfd);
26437c478bd9Sstevel@tonic-gate 			free(msg);
26447c478bd9Sstevel@tonic-gate 			warn(gettext("Delete failed: read"));
26457c478bd9Sstevel@tonic-gate 			return (-1);
26467c478bd9Sstevel@tonic-gate 		} else {
26477c478bd9Sstevel@tonic-gate 			(void) close(sfd);
26487c478bd9Sstevel@tonic-gate 			free(msg);
26497c478bd9Sstevel@tonic-gate 			warnx(gettext("Delete failed while reading reply"));
26507c478bd9Sstevel@tonic-gate 			return (-1);
26517c478bd9Sstevel@tonic-gate 		}
26527c478bd9Sstevel@tonic-gate 	}
26537c478bd9Sstevel@tonic-gate 	(void) close(sfd);
26547c478bd9Sstevel@tonic-gate 	if (msg->spd_msg_errno != 0) {
26557c478bd9Sstevel@tonic-gate 		free(msg);
26567c478bd9Sstevel@tonic-gate 		errno = msg->spd_msg_errno;
26577c478bd9Sstevel@tonic-gate 		warn(gettext("Delete failed: SPD_FLUSH"));
26587c478bd9Sstevel@tonic-gate 		return (-1);
26597c478bd9Sstevel@tonic-gate 	}
26607c478bd9Sstevel@tonic-gate 
26617c478bd9Sstevel@tonic-gate 	free(msg);
26627c478bd9Sstevel@tonic-gate 	return (0);
26637c478bd9Sstevel@tonic-gate }
26647c478bd9Sstevel@tonic-gate 
26657c478bd9Sstevel@tonic-gate static int
26667c478bd9Sstevel@tonic-gate ipsec_conf_flush(int db)
26677c478bd9Sstevel@tonic-gate {
26688810c16bSdanmcd 	int pfd, cnt, len;
2669e3320f40Smarkfen 	int sfd;
26708810c16bSdanmcd 	struct spd_msg *msg;
26718810c16bSdanmcd 	/*
26728810c16bSdanmcd 	 * Add an extra 8 bytes of space (+1 uint64_t) to avoid truncation
26738810c16bSdanmcd 	 * issues.
26748810c16bSdanmcd 	 */
26758810c16bSdanmcd 	uint64_t buffer[
26768810c16bSdanmcd 	    SPD_8TO64(sizeof (*msg) + sizeof (spd_if_t) + LIFNAMSIZ) + 1];
26777c478bd9Sstevel@tonic-gate 
2678e3320f40Smarkfen 	sfd = get_pf_pol_socket();
26797c478bd9Sstevel@tonic-gate 	if (sfd < 0) {
26807c478bd9Sstevel@tonic-gate 		warn(gettext("unable to open policy socket"));
26817c478bd9Sstevel@tonic-gate 		return (-1);
26827c478bd9Sstevel@tonic-gate 	}
26837c478bd9Sstevel@tonic-gate 
26848810c16bSdanmcd 	(void) memset(buffer, 0, sizeof (buffer));
26858810c16bSdanmcd 	msg = (struct spd_msg *)buffer;
26868810c16bSdanmcd 	msg->spd_msg_version = PF_POLICY_V1;
26878810c16bSdanmcd 	msg->spd_msg_type = SPD_FLUSH;
26888810c16bSdanmcd 	msg->spd_msg_len = SPD_8TO64(sizeof (*msg));
26898810c16bSdanmcd 	msg->spd_msg_spdid = db;
26907c478bd9Sstevel@tonic-gate 
26918810c16bSdanmcd 	msg->spd_msg_len += attach_tunname((spd_if_t *)(msg + 1));
26928810c16bSdanmcd 
26938810c16bSdanmcd 	len = SPD_64TO8(msg->spd_msg_len);
26948810c16bSdanmcd 	cnt = write(sfd, msg, len);
26958810c16bSdanmcd 	if (cnt != len) {
26967c478bd9Sstevel@tonic-gate 		if (cnt < 0) {
26977c478bd9Sstevel@tonic-gate 			warn(gettext("Flush failed: write"));
26987c478bd9Sstevel@tonic-gate 			return (-1);
26997c478bd9Sstevel@tonic-gate 		} else {
27007c478bd9Sstevel@tonic-gate 			warnx(gettext("Flush failed: short write"));
27017c478bd9Sstevel@tonic-gate 			return (-1);
27027c478bd9Sstevel@tonic-gate 		}
27037c478bd9Sstevel@tonic-gate 	}
27047c478bd9Sstevel@tonic-gate 
27058810c16bSdanmcd 	cnt = read(sfd, msg, len);
27068810c16bSdanmcd 	if (cnt != len) {
27077c478bd9Sstevel@tonic-gate 		if (cnt < 0) {
27087c478bd9Sstevel@tonic-gate 			warn(gettext("Flush failed: read"));
27097c478bd9Sstevel@tonic-gate 			return (-1);
27107c478bd9Sstevel@tonic-gate 		} else {
27117c478bd9Sstevel@tonic-gate 			warnx(gettext("Flush failed while reading reply"));
27127c478bd9Sstevel@tonic-gate 			return (-1);
27137c478bd9Sstevel@tonic-gate 		}
27147c478bd9Sstevel@tonic-gate 	}
27157c478bd9Sstevel@tonic-gate 	(void) close(sfd);
27168810c16bSdanmcd 	if (msg->spd_msg_errno != 0) {
27177c478bd9Sstevel@tonic-gate 		warnx("%s: %s", gettext("Flush failed: SPD_FLUSH"),
27188810c16bSdanmcd 		    sys_error_message(msg->spd_msg_errno));
27197c478bd9Sstevel@tonic-gate 		return (-1);
27207c478bd9Sstevel@tonic-gate 	}
27217c478bd9Sstevel@tonic-gate 
27227c478bd9Sstevel@tonic-gate 	/* Truncate the file */
27237c478bd9Sstevel@tonic-gate 	if (db == SPD_ACTIVE) {
27247c478bd9Sstevel@tonic-gate 		if ((pfd = open(POLICY_CONF_FILE, O_TRUNC|O_RDWR)) == -1) {
27257c478bd9Sstevel@tonic-gate 			if (errno == ENOENT) {
27267c478bd9Sstevel@tonic-gate 				/*
27277c478bd9Sstevel@tonic-gate 				 * The absence of POLICY_CONF_FILE should
27287c478bd9Sstevel@tonic-gate 				 * not cause the command to exit with a
27297c478bd9Sstevel@tonic-gate 				 * non-zero status, since this condition
27307c478bd9Sstevel@tonic-gate 				 * is valid when no policies were previously
27317c478bd9Sstevel@tonic-gate 				 * defined.
27327c478bd9Sstevel@tonic-gate 				 */
27337c478bd9Sstevel@tonic-gate 				return (0);
27347c478bd9Sstevel@tonic-gate 			}
27357c478bd9Sstevel@tonic-gate 			warn(gettext("%s cannot be truncated"),
27367c478bd9Sstevel@tonic-gate 			    POLICY_CONF_FILE);
27377c478bd9Sstevel@tonic-gate 			return (-1);
27387c478bd9Sstevel@tonic-gate 		}
27397c478bd9Sstevel@tonic-gate 		(void) close(pfd);
27407c478bd9Sstevel@tonic-gate 	}
27417c478bd9Sstevel@tonic-gate 	return (0);
27427c478bd9Sstevel@tonic-gate }
27437c478bd9Sstevel@tonic-gate 
27448810c16bSdanmcd /*
27458810c16bSdanmcd  * function to send SPD_FLIP and SPD_CLONE messages
27468810c16bSdanmcd  * Do it for ALL polheads for simplicity's sake.
27478810c16bSdanmcd  */
27487c478bd9Sstevel@tonic-gate static void
27497c478bd9Sstevel@tonic-gate ipsec_conf_admin(uint8_t type)
27507c478bd9Sstevel@tonic-gate {
27517c478bd9Sstevel@tonic-gate 	int cnt;
2752e3320f40Smarkfen 	int sfd;
27538810c16bSdanmcd 	struct spd_msg *msg;
27548810c16bSdanmcd 	uint64_t buffer[
27558810c16bSdanmcd 	    SPD_8TO64(sizeof (struct spd_msg) + sizeof (spd_if_t))];
27568810c16bSdanmcd 	char *save_ifname;
27577c478bd9Sstevel@tonic-gate 
2758e3320f40Smarkfen 	sfd = get_pf_pol_socket();
27597c478bd9Sstevel@tonic-gate 	if (sfd < 0) {
27607c478bd9Sstevel@tonic-gate 		err(-1, gettext("unable to open policy socket"));
27617c478bd9Sstevel@tonic-gate 	}
27627c478bd9Sstevel@tonic-gate 
27638810c16bSdanmcd 	(void) memset(buffer, 0, sizeof (buffer));
27648810c16bSdanmcd 	msg = (struct spd_msg *)buffer;
27658810c16bSdanmcd 	msg->spd_msg_version = PF_POLICY_V1;
27668810c16bSdanmcd 	msg->spd_msg_type = type;
27678810c16bSdanmcd 	msg->spd_msg_len = SPD_8TO64(sizeof (buffer));
27687c478bd9Sstevel@tonic-gate 
27698810c16bSdanmcd 	save_ifname = interface_name;
27708810c16bSdanmcd 	/* Apply to all policy heads - global and tunnels. */
27718810c16bSdanmcd 	interface_name = &all_polheads;
27728810c16bSdanmcd 	(void) attach_tunname((spd_if_t *)(msg + 1));
27738810c16bSdanmcd 	interface_name = save_ifname;
27748810c16bSdanmcd 
27758810c16bSdanmcd 	cnt = write(sfd, msg, sizeof (buffer));
27768810c16bSdanmcd 	if (cnt != sizeof (buffer)) {
27777c478bd9Sstevel@tonic-gate 		if (cnt < 0) {
27787c478bd9Sstevel@tonic-gate 			err(-1, gettext("admin failed: write"));
27797c478bd9Sstevel@tonic-gate 		} else {
27807c478bd9Sstevel@tonic-gate 			errx(-1, gettext("admin failed: short write"));
27817c478bd9Sstevel@tonic-gate 		}
27827c478bd9Sstevel@tonic-gate 	}
27837c478bd9Sstevel@tonic-gate 
27848810c16bSdanmcd 	cnt = read(sfd, msg, sizeof (buffer));
27858810c16bSdanmcd 	if (cnt != sizeof (buffer)) {
27867c478bd9Sstevel@tonic-gate 		if (cnt < 0) {
27877c478bd9Sstevel@tonic-gate 			err(-1, gettext("admin failed: read"));
27887c478bd9Sstevel@tonic-gate 		} else {
27897c478bd9Sstevel@tonic-gate 			errx(-1, gettext("admin failed while reading reply"));
27907c478bd9Sstevel@tonic-gate 		}
27917c478bd9Sstevel@tonic-gate 	}
27927c478bd9Sstevel@tonic-gate 	(void) close(sfd);
27938810c16bSdanmcd 	if (msg->spd_msg_errno != 0) {
27948810c16bSdanmcd 		errno = msg->spd_msg_errno;
27957c478bd9Sstevel@tonic-gate 		err(-1, gettext("admin failed"));
27967c478bd9Sstevel@tonic-gate 	}
27977c478bd9Sstevel@tonic-gate }
27987c478bd9Sstevel@tonic-gate 
27997c478bd9Sstevel@tonic-gate static void
28007c478bd9Sstevel@tonic-gate reconfigure()
28017c478bd9Sstevel@tonic-gate {
28027c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
2803d5751483Smarkfen 	    "\tipsecconf -f \n "
2804d5751483Smarkfen 	    "\tipsecconf -a policy_file\n"));
28057c478bd9Sstevel@tonic-gate }
28067c478bd9Sstevel@tonic-gate 
28077c478bd9Sstevel@tonic-gate static void
28087c478bd9Sstevel@tonic-gate usage(void)
28097c478bd9Sstevel@tonic-gate {
28107c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
28118810c16bSdanmcd 	"Usage:	ipsecconf\n"
28128810c16bSdanmcd 	"\tipsecconf -a ([-]|<filename>) [-q]\n"
2813e3320f40Smarkfen 	"\tipsecconf -c <filename>\n"
28148810c16bSdanmcd 	"\tipsecconf -r ([-]|<filename>) [-q]\n"
28158810c16bSdanmcd 	"\tipsecconf -d [-i tunnel-interface] <index>\n"
28168810c16bSdanmcd 	"\tipsecconf -d <tunnel-interface,index>\n"
28178810c16bSdanmcd 	"\tipsecconf -l [-n] [-i tunnel-interface]\n"
28188810c16bSdanmcd 	"\tipsecconf -f [-i tunnel-interface]\n"
28198810c16bSdanmcd 	"\tipsecconf -L [-n]\n"
28208810c16bSdanmcd 	"\tipsecconf -F\n"));
28217c478bd9Sstevel@tonic-gate }
28227c478bd9Sstevel@tonic-gate 
28237c478bd9Sstevel@tonic-gate /*
28247c478bd9Sstevel@tonic-gate  * a type consists of
28257c478bd9Sstevel@tonic-gate  * "type" <int>{ "-" <int>}
28267c478bd9Sstevel@tonic-gate  * or
28277c478bd9Sstevel@tonic-gate  * "type" keyword
28287c478bd9Sstevel@tonic-gate  *
28297c478bd9Sstevel@tonic-gate  * a code consists of
28307c478bd9Sstevel@tonic-gate  * "code" <int>{ "-" <int>}
28317c478bd9Sstevel@tonic-gate  * or
28327c478bd9Sstevel@tonic-gate  * "code" keyword
28337c478bd9Sstevel@tonic-gate  */
28347c478bd9Sstevel@tonic-gate 
28357c478bd9Sstevel@tonic-gate 
28367c478bd9Sstevel@tonic-gate static int
28377c478bd9Sstevel@tonic-gate parse_type_code(const char *str, const str_val_t *table)
28387c478bd9Sstevel@tonic-gate {
28397c478bd9Sstevel@tonic-gate 	char *end1, *end2;
28407c478bd9Sstevel@tonic-gate 	int res1 = 0, res2 = 0;
28417c478bd9Sstevel@tonic-gate 	int i;
28427c478bd9Sstevel@tonic-gate 
28437c478bd9Sstevel@tonic-gate 	if (isdigit(str[0])) {
28447c478bd9Sstevel@tonic-gate 		res1 = strtol(str, &end1, 0);
28457c478bd9Sstevel@tonic-gate 
28467c478bd9Sstevel@tonic-gate 		if (end1 == str) {
28477c478bd9Sstevel@tonic-gate 			return (-1);
28487c478bd9Sstevel@tonic-gate 		}
28497c478bd9Sstevel@tonic-gate 
28507c478bd9Sstevel@tonic-gate 		if (res1 > 255 || res1 < 0) {
28517c478bd9Sstevel@tonic-gate 			return (-1);
28527c478bd9Sstevel@tonic-gate 		}
28537c478bd9Sstevel@tonic-gate 
28547c478bd9Sstevel@tonic-gate 		if (*end1 == '-') {
28557c478bd9Sstevel@tonic-gate 			end1++;
28567c478bd9Sstevel@tonic-gate 			res2 = strtol(end1, &end2, 0);
28577c478bd9Sstevel@tonic-gate 			if (res2 > 255 || res2 < 0) {
28587c478bd9Sstevel@tonic-gate 				return (-1);
28597c478bd9Sstevel@tonic-gate 			}
28607c478bd9Sstevel@tonic-gate 		} else {
28617c478bd9Sstevel@tonic-gate 			end2 = end1;
28627c478bd9Sstevel@tonic-gate 		}
28637c478bd9Sstevel@tonic-gate 
28647c478bd9Sstevel@tonic-gate 		while (isspace(*end2))
28657c478bd9Sstevel@tonic-gate 			end2++;
28667c478bd9Sstevel@tonic-gate 
28677c478bd9Sstevel@tonic-gate 		if (*end2 != '\0') {
28687c478bd9Sstevel@tonic-gate 			return (-1);
28697c478bd9Sstevel@tonic-gate 		}
28707c478bd9Sstevel@tonic-gate 
28717c478bd9Sstevel@tonic-gate 		return (res1 + (res2 << 8));
28727c478bd9Sstevel@tonic-gate 	}
28737c478bd9Sstevel@tonic-gate 
28747c478bd9Sstevel@tonic-gate 	for (i = 0; table[i].string; i++) {
28757c478bd9Sstevel@tonic-gate 		if (strcmp(str, table[i].string) == 0) {
28767c478bd9Sstevel@tonic-gate 			return (table[i].value);
28777c478bd9Sstevel@tonic-gate 		}
28787c478bd9Sstevel@tonic-gate 	}
28797c478bd9Sstevel@tonic-gate 
28807c478bd9Sstevel@tonic-gate 	return (-1);
28817c478bd9Sstevel@tonic-gate }
28827c478bd9Sstevel@tonic-gate 
28837c478bd9Sstevel@tonic-gate static int
28847c478bd9Sstevel@tonic-gate parse_int(const char *str)
28857c478bd9Sstevel@tonic-gate {
28867c478bd9Sstevel@tonic-gate 	char *end;
28877c478bd9Sstevel@tonic-gate 	int res;
28887c478bd9Sstevel@tonic-gate 
28897c478bd9Sstevel@tonic-gate 	res = strtol(str, &end, 0);
28907c478bd9Sstevel@tonic-gate 	if (end == str)
28917c478bd9Sstevel@tonic-gate 		return (-1);
28927c478bd9Sstevel@tonic-gate 	while (isspace(*end))
28937c478bd9Sstevel@tonic-gate 		end++;
28947c478bd9Sstevel@tonic-gate 	if (*end != '\0')
28957c478bd9Sstevel@tonic-gate 		return (-1);
28967c478bd9Sstevel@tonic-gate 	return (res);
28977c478bd9Sstevel@tonic-gate }
28987c478bd9Sstevel@tonic-gate 
28997c478bd9Sstevel@tonic-gate /*
29008810c16bSdanmcd  * Parses <interface>,<index>.  Sets iname or the global interface_name (if
29018810c16bSdanmcd  * iname == NULL) to <interface> and returns <index>.  Calls exit() if we have
29028810c16bSdanmcd  * an interface_name already set.
29037c478bd9Sstevel@tonic-gate  */
29048810c16bSdanmcd static int
29058810c16bSdanmcd parse_index(const char *str, char *iname)
29067c478bd9Sstevel@tonic-gate {
29078810c16bSdanmcd 	char *intf, *num, *copy;
29088810c16bSdanmcd 	int rc;
29097c478bd9Sstevel@tonic-gate 
29108810c16bSdanmcd 	copy = strdup(str);
29118810c16bSdanmcd 	if (copy == NULL) {
2912e3320f40Smarkfen 		EXIT_FATAL("Out of memory.");
29137c478bd9Sstevel@tonic-gate 	}
29148810c16bSdanmcd 
29158810c16bSdanmcd 	intf = strtok(copy, ",");
29168810c16bSdanmcd 	/* Just want the rest of the string unmolested, so use "" for arg2. */
29178810c16bSdanmcd 	num = strtok(NULL, "");
29188810c16bSdanmcd 	if (num == NULL) {
29198810c16bSdanmcd 		/* No comma found, just parse it like an int. */
29208810c16bSdanmcd 		free(copy);
29218810c16bSdanmcd 		return (parse_int(str));
29227c478bd9Sstevel@tonic-gate 	}
29238810c16bSdanmcd 
29248810c16bSdanmcd 	if (iname != NULL) {
29258810c16bSdanmcd 		(void) strlcpy(iname, intf, LIFNAMSIZ);
29268810c16bSdanmcd 	} else {
29278810c16bSdanmcd 		if (interface_name != NULL) {
2928e3320f40Smarkfen 			EXIT_FATAL("Interface name already selected");
29298810c16bSdanmcd 		}
29308810c16bSdanmcd 
29318810c16bSdanmcd 		interface_name = strdup(intf);
29328810c16bSdanmcd 		if (interface_name == NULL) {
2933e3320f40Smarkfen 			EXIT_FATAL("Out of memory.");
29348810c16bSdanmcd 		}
29357c478bd9Sstevel@tonic-gate 	}
29368810c16bSdanmcd 
29378810c16bSdanmcd 	rc = parse_int(num);
29388810c16bSdanmcd 	free(copy);
29398810c16bSdanmcd 	return (rc);
29407c478bd9Sstevel@tonic-gate }
29417c478bd9Sstevel@tonic-gate 
29427c478bd9Sstevel@tonic-gate /*
29438810c16bSdanmcd  * Convert a mask to a prefix length.
29448810c16bSdanmcd  * Returns prefix length on success, -1 otherwise.
29457c478bd9Sstevel@tonic-gate  */
29467c478bd9Sstevel@tonic-gate static int
29478810c16bSdanmcd in_getprefixlen(char *mask)
29487c478bd9Sstevel@tonic-gate {
29498810c16bSdanmcd 	int prefixlen;
29508810c16bSdanmcd 	char *end;
29517c478bd9Sstevel@tonic-gate 
29528810c16bSdanmcd 	prefixlen = (int)strtol(mask, &end, 10);
29538810c16bSdanmcd 	if (prefixlen < 0) {
29548810c16bSdanmcd 		return (-1);
29557c478bd9Sstevel@tonic-gate 	}
29568810c16bSdanmcd 	if (mask == end) {
29578810c16bSdanmcd 		return (-1);
29587c478bd9Sstevel@tonic-gate 	}
29598810c16bSdanmcd 	if (*end != '\0') {
29608810c16bSdanmcd 		return (-1);
29617c478bd9Sstevel@tonic-gate 	}
29628810c16bSdanmcd 	return (prefixlen);
29637c478bd9Sstevel@tonic-gate }
29647c478bd9Sstevel@tonic-gate 
29657c478bd9Sstevel@tonic-gate /*
29667c478bd9Sstevel@tonic-gate  * Convert a prefix length to a mask.
29677c478bd9Sstevel@tonic-gate  * Assumes the mask array is zero'ed by the caller.
29687c478bd9Sstevel@tonic-gate  */
29697c478bd9Sstevel@tonic-gate static void
29707c478bd9Sstevel@tonic-gate in_prefixlentomask(unsigned int prefixlen, uchar_t *mask)
29717c478bd9Sstevel@tonic-gate {
29727c478bd9Sstevel@tonic-gate 	while (prefixlen > 0) {
29737c478bd9Sstevel@tonic-gate 		if (prefixlen >= 8) {
29747c478bd9Sstevel@tonic-gate 			*mask++ = 0xFF;
29757c478bd9Sstevel@tonic-gate 			prefixlen -= 8;
29767c478bd9Sstevel@tonic-gate 			continue;
29777c478bd9Sstevel@tonic-gate 		}
29787c478bd9Sstevel@tonic-gate 		*mask |= 1 << (8 - prefixlen);
29797c478bd9Sstevel@tonic-gate 		prefixlen--;
29807c478bd9Sstevel@tonic-gate 	}
29817c478bd9Sstevel@tonic-gate }
29827c478bd9Sstevel@tonic-gate 
29837c478bd9Sstevel@tonic-gate 
29847c478bd9Sstevel@tonic-gate static int
29857c478bd9Sstevel@tonic-gate parse_address(int type, char *addr_str)
29867c478bd9Sstevel@tonic-gate {
29877c478bd9Sstevel@tonic-gate 	char *ptr;
29888810c16bSdanmcd 	int prefix_len = 0;
29897c478bd9Sstevel@tonic-gate 	struct netent *ne = NULL;
29907c478bd9Sstevel@tonic-gate 	struct hostent *hp = NULL;
29917c478bd9Sstevel@tonic-gate 	int h_errno;
29927c478bd9Sstevel@tonic-gate 	struct in_addr netaddr;
29937c478bd9Sstevel@tonic-gate 	struct in6_addr *netaddr6;
29947c478bd9Sstevel@tonic-gate 	struct hostent *ne_hent;
29957c478bd9Sstevel@tonic-gate 	boolean_t	has_mask = B_FALSE;
29967c478bd9Sstevel@tonic-gate 
29977c478bd9Sstevel@tonic-gate 	ptr = strchr(addr_str, '/');
29987c478bd9Sstevel@tonic-gate 	if (ptr != NULL) {
29997c478bd9Sstevel@tonic-gate 		has_mask = B_TRUE;
30007c478bd9Sstevel@tonic-gate 		*ptr++ = NULL;
30017c478bd9Sstevel@tonic-gate 
30027c478bd9Sstevel@tonic-gate 		prefix_len = in_getprefixlen(ptr);
30038810c16bSdanmcd 		if (prefix_len < 0)
30047c478bd9Sstevel@tonic-gate 			return (-1);
30057c478bd9Sstevel@tonic-gate 	}
30067c478bd9Sstevel@tonic-gate 
30077c478bd9Sstevel@tonic-gate 	/*
30087c478bd9Sstevel@tonic-gate 	 * getipnodebyname() is thread safe. This allows us to hold on to the
30097c478bd9Sstevel@tonic-gate 	 * returned hostent structure, which is pointed to by the shp and
30107c478bd9Sstevel@tonic-gate 	 * dhp globals for the source and destination addresses, respectively.
30117c478bd9Sstevel@tonic-gate 	 */
30127c478bd9Sstevel@tonic-gate 	hp = getipnodebyname(addr_str, AF_INET6, AI_DEFAULT | AI_ALL, &h_errno);
30137c478bd9Sstevel@tonic-gate 	if (hp != NULL) {
30147c478bd9Sstevel@tonic-gate 		/*
30157c478bd9Sstevel@tonic-gate 		 * We come here for both a hostname and
30167c478bd9Sstevel@tonic-gate 		 * any host address /network address.
30177c478bd9Sstevel@tonic-gate 		 */
30187c478bd9Sstevel@tonic-gate 		assert(hp->h_addrtype == AF_INET6);
30197c478bd9Sstevel@tonic-gate 	} else if ((ne = getnetbyname(addr_str)) != NULL) {
30207c478bd9Sstevel@tonic-gate 		switch (ne->n_addrtype) {
30217c478bd9Sstevel@tonic-gate 		case AF_INET:
30227c478bd9Sstevel@tonic-gate 			/*
30237c478bd9Sstevel@tonic-gate 			 * Allocate a struct hostent and initialize
30247c478bd9Sstevel@tonic-gate 			 * it with the address corresponding to the
30257c478bd9Sstevel@tonic-gate 			 * network number previously returned by
30267c478bd9Sstevel@tonic-gate 			 * getnetbyname(). Freed by do_address_adds()
30277c478bd9Sstevel@tonic-gate 			 * once the policy is defined.
30287c478bd9Sstevel@tonic-gate 			 */
30297c478bd9Sstevel@tonic-gate 			ne_hent = malloc(sizeof (struct hostent));
30307c478bd9Sstevel@tonic-gate 			if (ne_hent == NULL) {
30317c478bd9Sstevel@tonic-gate 				warn("malloc");
30327c478bd9Sstevel@tonic-gate 				return (-1);
30337c478bd9Sstevel@tonic-gate 			}
30347c478bd9Sstevel@tonic-gate 			ne_hent->h_addr_list = malloc(2*sizeof (char *));
30357c478bd9Sstevel@tonic-gate 			if (ne_hent->h_addr_list == NULL) {
30367c478bd9Sstevel@tonic-gate 				warn("malloc");
30377c478bd9Sstevel@tonic-gate 				free(ne_hent);
30387c478bd9Sstevel@tonic-gate 				return (-1);
30397c478bd9Sstevel@tonic-gate 			}
30407c478bd9Sstevel@tonic-gate 			netaddr6 = malloc(sizeof (struct in6_addr));
30417c478bd9Sstevel@tonic-gate 			if (netaddr6 == NULL) {
30427c478bd9Sstevel@tonic-gate 				warn("malloc");
30437c478bd9Sstevel@tonic-gate 				free(ne_hent->h_addr_list);
30447c478bd9Sstevel@tonic-gate 				free(ne_hent);
30457c478bd9Sstevel@tonic-gate 				return (-1);
30467c478bd9Sstevel@tonic-gate 			}
30477c478bd9Sstevel@tonic-gate 			ne_hent->h_addr_list[0] = (char *)netaddr6;
30487c478bd9Sstevel@tonic-gate 			ne_hent->h_addr_list[1] = NULL;
30497c478bd9Sstevel@tonic-gate 			netaddr = inet_makeaddr(ne->n_net, INADDR_ANY);
30507c478bd9Sstevel@tonic-gate 			IN6_INADDR_TO_V4MAPPED(&netaddr, netaddr6);
30517c478bd9Sstevel@tonic-gate 			hp = ne_hent;
30527c478bd9Sstevel@tonic-gate 			break;
30537c478bd9Sstevel@tonic-gate 		default:
30547c478bd9Sstevel@tonic-gate 			warnx("Address type %d not supported.", ne->n_addrtype);
30557c478bd9Sstevel@tonic-gate 			return (-1);
30567c478bd9Sstevel@tonic-gate 		}
30577c478bd9Sstevel@tonic-gate 	} else {
30587c478bd9Sstevel@tonic-gate 		return (-1);
30597c478bd9Sstevel@tonic-gate 	}
30607c478bd9Sstevel@tonic-gate 
30617c478bd9Sstevel@tonic-gate 	if (type == IPSEC_CONF_SRC_ADDRESS) {
30627c478bd9Sstevel@tonic-gate 		shp = hp;
30637c478bd9Sstevel@tonic-gate 		if (has_mask)
30647c478bd9Sstevel@tonic-gate 			splen = prefix_len;
30657c478bd9Sstevel@tonic-gate 		has_saprefix = has_mask;
30667c478bd9Sstevel@tonic-gate 	} else {
30677c478bd9Sstevel@tonic-gate 		dhp = hp;
30687c478bd9Sstevel@tonic-gate 		if (has_mask)
30697c478bd9Sstevel@tonic-gate 			dplen = prefix_len;
30707c478bd9Sstevel@tonic-gate 		has_daprefix = has_mask;
30717c478bd9Sstevel@tonic-gate 	}
30727c478bd9Sstevel@tonic-gate 
30737c478bd9Sstevel@tonic-gate 	return (0);
30747c478bd9Sstevel@tonic-gate }
30757c478bd9Sstevel@tonic-gate 
30767c478bd9Sstevel@tonic-gate /*
30777c478bd9Sstevel@tonic-gate  * Add port-only entries.  Make sure to add them in both the V6 and V4 tables!
30787c478bd9Sstevel@tonic-gate  */
30797c478bd9Sstevel@tonic-gate static int
30807c478bd9Sstevel@tonic-gate do_port_adds(ips_conf_t *cptr)
30817c478bd9Sstevel@tonic-gate {
30828810c16bSdanmcd 	int ret, diag;
30837c478bd9Sstevel@tonic-gate 
30847c478bd9Sstevel@tonic-gate 	assert(IN6_IS_ADDR_UNSPECIFIED(&cptr->ips_src_addr_v6));
30857c478bd9Sstevel@tonic-gate 	assert(IN6_IS_ADDR_UNSPECIFIED(&cptr->ips_dst_addr_v6));
30867c478bd9Sstevel@tonic-gate 
30877c478bd9Sstevel@tonic-gate #ifdef DEBUG_HEAVY
30887c478bd9Sstevel@tonic-gate 	(void) dump_conf(cptr);
30897c478bd9Sstevel@tonic-gate #endif
30907c478bd9Sstevel@tonic-gate 
30918810c16bSdanmcd 	ret = send_pf_pol_message(SPD_ADDRULE, cptr, &diag);
309243c889d3Smarkfen 	if (ret != 0 && !ipsecconf_qflag) {
30937c478bd9Sstevel@tonic-gate 		warnx(
30948810c16bSdanmcd 		    gettext("Could not add IPv4 policy for sport %d, dport %d "
3095d5751483Smarkfen 		    "- diagnostic %d - %s"), ntohs(cptr->ips_src_port_min),
30968810c16bSdanmcd 		    ntohs(cptr->ips_dst_port_min), diag, spdsock_diag(diag));
30977c478bd9Sstevel@tonic-gate 	}
30987c478bd9Sstevel@tonic-gate 
309943c889d3Smarkfen 	return (ret);
31007c478bd9Sstevel@tonic-gate }
31017c478bd9Sstevel@tonic-gate 
31027c478bd9Sstevel@tonic-gate /*
31037c478bd9Sstevel@tonic-gate  * Nuke a list of policy entries.
31047c478bd9Sstevel@tonic-gate  * rewrite this to use flipping
31057c478bd9Sstevel@tonic-gate  * d_list isn't freed because we will be
31067c478bd9Sstevel@tonic-gate  * exiting the program soon.
31077c478bd9Sstevel@tonic-gate  */
31087c478bd9Sstevel@tonic-gate static void
31097c478bd9Sstevel@tonic-gate nuke_adds()
31107c478bd9Sstevel@tonic-gate {
31117c478bd9Sstevel@tonic-gate 	d_list_t *temp = d_list;
31127c478bd9Sstevel@tonic-gate 	FILE *policy_fp;
31137c478bd9Sstevel@tonic-gate 
31147c478bd9Sstevel@tonic-gate 	policy_fp = fopen(POLICY_CONF_FILE, "a");
31157c478bd9Sstevel@tonic-gate 	if (policy_fp == NULL) {
31167c478bd9Sstevel@tonic-gate 		warn(gettext("%s cannot be opened"), POLICY_CONF_FILE);
3117*3abcb969Spwernau 	} else {
3118*3abcb969Spwernau 		(void) fprintf(policy_fp, "\n\n");
3119*3abcb969Spwernau 		(void) fflush(policy_fp);
31207c478bd9Sstevel@tonic-gate 	}
31217c478bd9Sstevel@tonic-gate 
31227c478bd9Sstevel@tonic-gate 	while (temp != NULL) {
31237c478bd9Sstevel@tonic-gate 		(void) ipsec_conf_del(temp->index, B_TRUE);
31247c478bd9Sstevel@tonic-gate 		temp = temp->next;
31257c478bd9Sstevel@tonic-gate 	}
31267c478bd9Sstevel@tonic-gate }
31277c478bd9Sstevel@tonic-gate 
31287c478bd9Sstevel@tonic-gate /*
31297c478bd9Sstevel@tonic-gate  * Set mask info from the specified prefix len. Fail if multihomed.
31307c478bd9Sstevel@tonic-gate  */
31317c478bd9Sstevel@tonic-gate static int
31327c478bd9Sstevel@tonic-gate set_mask_info(struct hostent *hp, unsigned int plen, struct in6_addr *mask_v6)
31337c478bd9Sstevel@tonic-gate {
31347c478bd9Sstevel@tonic-gate 	struct in6_addr addr;
31357c478bd9Sstevel@tonic-gate 	struct in_addr mask_v4;
31367c478bd9Sstevel@tonic-gate 
31377c478bd9Sstevel@tonic-gate 	if (hp->h_addr_list[1] != NULL) {
31388810c16bSdanmcd 		return (EOPNOTSUPP);
31397c478bd9Sstevel@tonic-gate 	}
31407c478bd9Sstevel@tonic-gate 
31417c478bd9Sstevel@tonic-gate 	if (!IN6_IS_ADDR_UNSPECIFIED(mask_v6)) {
31427c478bd9Sstevel@tonic-gate 		return (EBUSY);
31437c478bd9Sstevel@tonic-gate 	}
31447c478bd9Sstevel@tonic-gate 
31457c478bd9Sstevel@tonic-gate 	bcopy(hp->h_addr_list[0], &addr, sizeof (struct in6_addr));
31467c478bd9Sstevel@tonic-gate 	if (IN6_IS_ADDR_V4MAPPED(&addr)) {
31477c478bd9Sstevel@tonic-gate 		if (plen > IP_ABITS) {
31487c478bd9Sstevel@tonic-gate 			return (ERANGE);
31497c478bd9Sstevel@tonic-gate 		}
31507c478bd9Sstevel@tonic-gate 		(void) memset(&mask_v4, 0, sizeof (mask_v4));
31517c478bd9Sstevel@tonic-gate 		in_prefixlentomask(plen, (uchar_t *)&mask_v4);
31527c478bd9Sstevel@tonic-gate 		IN6_INADDR_TO_V4MAPPED(&mask_v4, mask_v6);
31537c478bd9Sstevel@tonic-gate 	} else {
31547c478bd9Sstevel@tonic-gate 		if (plen > IPV6_ABITS) {
31557c478bd9Sstevel@tonic-gate 			return (ERANGE);
31567c478bd9Sstevel@tonic-gate 		}
31577c478bd9Sstevel@tonic-gate 		/* mask_v6 is already zero (unspecified), see test above */
31587c478bd9Sstevel@tonic-gate 		in_prefixlentomask(plen, (uchar_t *)mask_v6);
31597c478bd9Sstevel@tonic-gate 	}
31607c478bd9Sstevel@tonic-gate 	return (0);
31617c478bd9Sstevel@tonic-gate }
31627c478bd9Sstevel@tonic-gate 
31637c478bd9Sstevel@tonic-gate /*
31647c478bd9Sstevel@tonic-gate  * Initialize the specified IPv6 address with all f's.
31657c478bd9Sstevel@tonic-gate  */
31667c478bd9Sstevel@tonic-gate static void
31677c478bd9Sstevel@tonic-gate init_addr_wildcard(struct in6_addr *addr_v6, boolean_t isv4)
31687c478bd9Sstevel@tonic-gate {
31697c478bd9Sstevel@tonic-gate 	if (isv4) {
31707c478bd9Sstevel@tonic-gate 		uint32_t addr_v4 = 0xffffffff;
31717c478bd9Sstevel@tonic-gate 		IN6_INADDR_TO_V4MAPPED((struct in_addr *)&addr_v4, addr_v6);
31727c478bd9Sstevel@tonic-gate 	} else {
31737c478bd9Sstevel@tonic-gate 		(void) memset(addr_v6, 0xff, sizeof (struct in6_addr));
31747c478bd9Sstevel@tonic-gate 	}
31757c478bd9Sstevel@tonic-gate }
31767c478bd9Sstevel@tonic-gate 
31777c478bd9Sstevel@tonic-gate /*
31787c478bd9Sstevel@tonic-gate  * Called at the end to actually add policy.  Handles single and multi-homed
31797c478bd9Sstevel@tonic-gate  * cases.
31807c478bd9Sstevel@tonic-gate  */
31817c478bd9Sstevel@tonic-gate static int
31828810c16bSdanmcd do_address_adds(ips_conf_t *cptr, int *diag)
31837c478bd9Sstevel@tonic-gate {
31847c478bd9Sstevel@tonic-gate 	int i, j;
31857c478bd9Sstevel@tonic-gate 	int ret = 0;	/* For ioctl() call. */
31867c478bd9Sstevel@tonic-gate 	int rc = 0;	/* My own return code. */
31877c478bd9Sstevel@tonic-gate 	struct in6_addr zeroes = {0, 0, 0, 0};
31887c478bd9Sstevel@tonic-gate 	char *ptr[2];
31897c478bd9Sstevel@tonic-gate 	struct hostent hent;
31907c478bd9Sstevel@tonic-gate 	boolean_t isv4;
31917c478bd9Sstevel@tonic-gate 	int add_count = 0;
31927c478bd9Sstevel@tonic-gate 
31937c478bd9Sstevel@tonic-gate 	/*
31947c478bd9Sstevel@tonic-gate 	 * dst_hent may not be initialized if a destination
31957c478bd9Sstevel@tonic-gate 	 * address was not given. It will be initalized with just
31967c478bd9Sstevel@tonic-gate 	 * one address if a destination address was given. In both
31977c478bd9Sstevel@tonic-gate 	 * the cases, we initialize here with ipsc_dst_addr and enter
31987c478bd9Sstevel@tonic-gate 	 * the loop below.
31997c478bd9Sstevel@tonic-gate 	 */
32007c478bd9Sstevel@tonic-gate 	if (dhp == NULL) {
32017c478bd9Sstevel@tonic-gate 		assert(shp != NULL);
32027c478bd9Sstevel@tonic-gate 		hent.h_addr_list = ptr;
32037c478bd9Sstevel@tonic-gate 		ptr[0] = (char *)&zeroes.s6_addr;
32047c478bd9Sstevel@tonic-gate 		ptr[1] = NULL;
32057c478bd9Sstevel@tonic-gate 		dhp = &hent;
32067c478bd9Sstevel@tonic-gate 	} else if (shp == NULL) {
32077c478bd9Sstevel@tonic-gate 		assert(dhp != NULL);
32087c478bd9Sstevel@tonic-gate 		hent.h_addr_list = ptr;
32097c478bd9Sstevel@tonic-gate 		ptr[0] = (char *)&zeroes.s6_addr;
32107c478bd9Sstevel@tonic-gate 		ptr[1] = NULL;
32117c478bd9Sstevel@tonic-gate 		shp = &hent;
32127c478bd9Sstevel@tonic-gate 	}
32137c478bd9Sstevel@tonic-gate 
32147c478bd9Sstevel@tonic-gate 	/*
32157c478bd9Sstevel@tonic-gate 	 * Set mask info here.  Bail if multihomed and there's a prefix len.
32167c478bd9Sstevel@tonic-gate 	 */
32177c478bd9Sstevel@tonic-gate 	if (has_saprefix) {
32187c478bd9Sstevel@tonic-gate 		rc = set_mask_info(shp, splen, &cptr->ips_src_mask_v6);
32197c478bd9Sstevel@tonic-gate 		if (rc != 0)
32207c478bd9Sstevel@tonic-gate 			goto bail;
32217c478bd9Sstevel@tonic-gate 		cptr->ips_src_mask_len = splen;
32227c478bd9Sstevel@tonic-gate 	}
32237c478bd9Sstevel@tonic-gate 
32247c478bd9Sstevel@tonic-gate 	if (has_daprefix) {
32257c478bd9Sstevel@tonic-gate 		rc = set_mask_info(dhp, dplen, &cptr->ips_dst_mask_v6);
32267c478bd9Sstevel@tonic-gate 		if (rc != 0)
32277c478bd9Sstevel@tonic-gate 			goto bail;
32287c478bd9Sstevel@tonic-gate 		cptr->ips_dst_mask_len = dplen;
32297c478bd9Sstevel@tonic-gate 	}
32307c478bd9Sstevel@tonic-gate 
32317c478bd9Sstevel@tonic-gate 	for (i = 0; shp->h_addr_list[i] != NULL; i++) {
32327c478bd9Sstevel@tonic-gate 		bcopy(shp->h_addr_list[i], &cptr->ips_src_addr_v6,
32337c478bd9Sstevel@tonic-gate 		    sizeof (struct in6_addr));
32347c478bd9Sstevel@tonic-gate 		isv4 = cptr->ips_isv4 =
32357c478bd9Sstevel@tonic-gate 		    IN6_IS_ADDR_V4MAPPED(&cptr->ips_src_addr_v6);
32367c478bd9Sstevel@tonic-gate 		if (IN6_IS_ADDR_UNSPECIFIED(&cptr->ips_src_mask_v6) &&
32377c478bd9Sstevel@tonic-gate 		    shp != &hent) {
32387c478bd9Sstevel@tonic-gate 			init_addr_wildcard(&cptr->ips_src_mask_v6, isv4);
32397c478bd9Sstevel@tonic-gate 		}
32407c478bd9Sstevel@tonic-gate 
32417c478bd9Sstevel@tonic-gate 		for (j = 0; dhp->h_addr_list[j] != NULL; j++) {
32427c478bd9Sstevel@tonic-gate 			bcopy(dhp->h_addr_list[j], &cptr->ips_dst_addr_v6,
32437c478bd9Sstevel@tonic-gate 			    sizeof (struct in6_addr));
32447c478bd9Sstevel@tonic-gate 			if (IN6_IS_ADDR_UNSPECIFIED(&cptr->ips_src_addr_v6)) {
32457c478bd9Sstevel@tonic-gate 				/*
32467c478bd9Sstevel@tonic-gate 				 * Src was not specified, so update isv4 flag
32477c478bd9Sstevel@tonic-gate 				 * for this policy according to the family
32487c478bd9Sstevel@tonic-gate 				 * of the destination address.
32497c478bd9Sstevel@tonic-gate 				 */
32507c478bd9Sstevel@tonic-gate 				isv4 = cptr->ips_isv4 =
32517c478bd9Sstevel@tonic-gate 				    IN6_IS_ADDR_V4MAPPED(
3252d5751483Smarkfen 				    &cptr->ips_dst_addr_v6);
32537c478bd9Sstevel@tonic-gate 			} else if ((dhp != &hent) && (isv4 !=
32547c478bd9Sstevel@tonic-gate 			    IN6_IS_ADDR_V4MAPPED(&cptr->ips_dst_addr_v6))) {
32557c478bd9Sstevel@tonic-gate 				/* v6/v4 mismatch. */
32567c478bd9Sstevel@tonic-gate 				continue;
32577c478bd9Sstevel@tonic-gate 			}
32587c478bd9Sstevel@tonic-gate 			if (IN6_IS_ADDR_UNSPECIFIED(&cptr->ips_dst_mask_v6) &&
32597c478bd9Sstevel@tonic-gate 			    dhp != &hent) {
32607c478bd9Sstevel@tonic-gate 				init_addr_wildcard(&cptr->ips_dst_mask_v6,
32617c478bd9Sstevel@tonic-gate 				    isv4);
32627c478bd9Sstevel@tonic-gate 			}
32637c478bd9Sstevel@tonic-gate 
32648810c16bSdanmcd 			ret = send_pf_pol_message(SPD_ADDRULE, cptr, diag);
32657c478bd9Sstevel@tonic-gate 
326643c889d3Smarkfen 			if (ret == 0) {
326743c889d3Smarkfen 				add_count++;
326843c889d3Smarkfen 			} else {
32697c478bd9Sstevel@tonic-gate 				/* For now, allow duplicate/overlap policies. */
327043c889d3Smarkfen 				if (ret != EEXIST) {
32717c478bd9Sstevel@tonic-gate 					/*
32727c478bd9Sstevel@tonic-gate 					 * We have an error where we added
32737c478bd9Sstevel@tonic-gate 					 * some, but had errors with others.
32747c478bd9Sstevel@tonic-gate 					 * Undo the previous adds, and
32757c478bd9Sstevel@tonic-gate 					 * bail.
32767c478bd9Sstevel@tonic-gate 					 */
327743c889d3Smarkfen 					rc = ret;
32787c478bd9Sstevel@tonic-gate 					goto bail;
32797c478bd9Sstevel@tonic-gate 				}
32807c478bd9Sstevel@tonic-gate 			}
32817c478bd9Sstevel@tonic-gate 
32827c478bd9Sstevel@tonic-gate 			bzero(&cptr->ips_dst_mask_v6,
32837c478bd9Sstevel@tonic-gate 			    sizeof (struct in6_addr));
32847c478bd9Sstevel@tonic-gate 		}
32857c478bd9Sstevel@tonic-gate 
32867c478bd9Sstevel@tonic-gate 		bzero(&cptr->ips_src_mask_v6, sizeof (struct in6_addr));
32877c478bd9Sstevel@tonic-gate 	}
32887c478bd9Sstevel@tonic-gate 
32897c478bd9Sstevel@tonic-gate bail:
32907c478bd9Sstevel@tonic-gate 	if (shp != &hent)
32917c478bd9Sstevel@tonic-gate 		freehostent(shp);
32927c478bd9Sstevel@tonic-gate 	shp = NULL;
32937c478bd9Sstevel@tonic-gate 	if (dhp != &hent)
32947c478bd9Sstevel@tonic-gate 		freehostent(dhp);
32957c478bd9Sstevel@tonic-gate 	dhp = NULL;
32967c478bd9Sstevel@tonic-gate 	splen = 0;
32977c478bd9Sstevel@tonic-gate 	dplen = 0;
32987c478bd9Sstevel@tonic-gate 
32997c478bd9Sstevel@tonic-gate 	if ((add_count == 0) && (rc == 0)) {
33007c478bd9Sstevel@tonic-gate 		/*
33017c478bd9Sstevel@tonic-gate 		 * No entries were added. We failed all adds
33027c478bd9Sstevel@tonic-gate 		 * because the entries already existed, or because
33037c478bd9Sstevel@tonic-gate 		 * no v4 or v6 src/dst pairs were found. Either way,
33047c478bd9Sstevel@tonic-gate 		 * we must fail here with an appropriate error
33057c478bd9Sstevel@tonic-gate 		 * to avoid a corresponding entry from being added
33067c478bd9Sstevel@tonic-gate 		 * to ipsecpolicy.conf.
33077c478bd9Sstevel@tonic-gate 		 */
330843c889d3Smarkfen 		if ((ret == EEXIST)) {
33097c478bd9Sstevel@tonic-gate 			/* All adds failed with EEXIST */
33107c478bd9Sstevel@tonic-gate 			rc = EEXIST;
33117c478bd9Sstevel@tonic-gate 		} else {
33127c478bd9Sstevel@tonic-gate 			/* No matching v4 or v6 src/dst pairs */
33137c478bd9Sstevel@tonic-gate 			rc = ESRCH;
33147c478bd9Sstevel@tonic-gate 		}
33157c478bd9Sstevel@tonic-gate 	}
33167c478bd9Sstevel@tonic-gate 
33177c478bd9Sstevel@tonic-gate 	return (rc);
33187c478bd9Sstevel@tonic-gate }
33197c478bd9Sstevel@tonic-gate 
33207c478bd9Sstevel@tonic-gate static int
33217c478bd9Sstevel@tonic-gate parse_mask(int type, char *mask_str, ips_conf_t *cptr)
33227c478bd9Sstevel@tonic-gate {
33237c478bd9Sstevel@tonic-gate 	struct in_addr mask;
33247c478bd9Sstevel@tonic-gate 	struct in6_addr *mask6;
33257c478bd9Sstevel@tonic-gate 
33267c478bd9Sstevel@tonic-gate 	if (type == IPSEC_CONF_SRC_MASK) {
33277c478bd9Sstevel@tonic-gate 		mask6 = &cptr->ips_src_mask_v6;
33287c478bd9Sstevel@tonic-gate 	} else {
33297c478bd9Sstevel@tonic-gate 		mask6 = &cptr->ips_dst_mask_v6;
33307c478bd9Sstevel@tonic-gate 	}
33317c478bd9Sstevel@tonic-gate 
33327c478bd9Sstevel@tonic-gate 	if ((strncasecmp(mask_str, "0x", 2) == 0) &&
33337c478bd9Sstevel@tonic-gate 	    (strchr(mask_str, '.') == NULL)) {
33347c478bd9Sstevel@tonic-gate 		/* Is it in the form 0xff000000 ? */
33357c478bd9Sstevel@tonic-gate 		char *end;
33367c478bd9Sstevel@tonic-gate 
33377c478bd9Sstevel@tonic-gate 		mask.s_addr = strtoul(mask_str, &end, 0);
33387c478bd9Sstevel@tonic-gate 		if (end == mask_str) {
33397c478bd9Sstevel@tonic-gate 			return (-1);
33407c478bd9Sstevel@tonic-gate 		}
33417c478bd9Sstevel@tonic-gate 		if (*end != '\0') {
33427c478bd9Sstevel@tonic-gate 			return (-1);
33437c478bd9Sstevel@tonic-gate 		}
33447c478bd9Sstevel@tonic-gate 		mask.s_addr = htonl(mask.s_addr);
33457c478bd9Sstevel@tonic-gate 	} else {
33467c478bd9Sstevel@tonic-gate 		/*
33477c478bd9Sstevel@tonic-gate 		 * Since inet_addr() returns -1 on error, we have
33487c478bd9Sstevel@tonic-gate 		 * to convert a broadcast address ourselves.
33497c478bd9Sstevel@tonic-gate 		 */
33507c478bd9Sstevel@tonic-gate 		if (strcmp(mask_str, "255.255.255.255") == 0) {
33517c478bd9Sstevel@tonic-gate 			mask.s_addr = 0xffffffff;
33527c478bd9Sstevel@tonic-gate 		} else {
33537c478bd9Sstevel@tonic-gate 			mask.s_addr = inet_addr(mask_str);
33547c478bd9Sstevel@tonic-gate 			if (mask.s_addr == (unsigned int)-1)
33557c478bd9Sstevel@tonic-gate 				return (-1);
33567c478bd9Sstevel@tonic-gate 		}
33577c478bd9Sstevel@tonic-gate 	}
33587c478bd9Sstevel@tonic-gate 
33597c478bd9Sstevel@tonic-gate 	/* Should we check for non-contiguous masks ? */
33607c478bd9Sstevel@tonic-gate 	if (mask.s_addr == 0)
33617c478bd9Sstevel@tonic-gate 		return (-1);
33627c478bd9Sstevel@tonic-gate 	IN6_INADDR_TO_V4MAPPED(&mask, mask6);
33637c478bd9Sstevel@tonic-gate 
33647c478bd9Sstevel@tonic-gate 
33657c478bd9Sstevel@tonic-gate 	if (type == IPSEC_CONF_SRC_MASK) {
33667c478bd9Sstevel@tonic-gate 		cptr->ips_src_mask_len = in_masktoprefix(mask6->s6_addr,
33677c478bd9Sstevel@tonic-gate 		    B_TRUE);
33687c478bd9Sstevel@tonic-gate 	} else {
33697c478bd9Sstevel@tonic-gate 		cptr->ips_dst_mask_len = in_masktoprefix(mask6->s6_addr,
33707c478bd9Sstevel@tonic-gate 		    B_TRUE);
33717c478bd9Sstevel@tonic-gate 	}
33727c478bd9Sstevel@tonic-gate 
33737c478bd9Sstevel@tonic-gate 	return (0);
33747c478bd9Sstevel@tonic-gate }
33757c478bd9Sstevel@tonic-gate 
33767c478bd9Sstevel@tonic-gate static int
33777c478bd9Sstevel@tonic-gate parse_port(int type, char *port_str, ips_conf_t *conf)
33787c478bd9Sstevel@tonic-gate {
33797c478bd9Sstevel@tonic-gate 	struct servent *sent;
33807c478bd9Sstevel@tonic-gate 	in_port_t port;
33817c478bd9Sstevel@tonic-gate 	int ret;
33827c478bd9Sstevel@tonic-gate 
33837c478bd9Sstevel@tonic-gate 	sent = getservbyname(port_str, NULL);
33847c478bd9Sstevel@tonic-gate 	if (sent == NULL) {
33857c478bd9Sstevel@tonic-gate 		ret = parse_int(port_str);
33867c478bd9Sstevel@tonic-gate 		if (ret < 0 || ret >= 65536) {
33877c478bd9Sstevel@tonic-gate 			return (-1);
33887c478bd9Sstevel@tonic-gate 		}
33897c478bd9Sstevel@tonic-gate 		port = htons((in_port_t)ret);
33907c478bd9Sstevel@tonic-gate 	} else {
33917c478bd9Sstevel@tonic-gate 		port = sent->s_port;
33927c478bd9Sstevel@tonic-gate 	}
33937c478bd9Sstevel@tonic-gate 	if (type == IPSEC_CONF_SRC_PORT) {
33947c478bd9Sstevel@tonic-gate 		conf->ips_src_port_min = conf->ips_src_port_max = port;
33957c478bd9Sstevel@tonic-gate 	} else {
33967c478bd9Sstevel@tonic-gate 		conf->ips_dst_port_min = conf->ips_dst_port_max = port;
33977c478bd9Sstevel@tonic-gate 	}
33987c478bd9Sstevel@tonic-gate 	return (0);
33997c478bd9Sstevel@tonic-gate }
34007c478bd9Sstevel@tonic-gate 
34017c478bd9Sstevel@tonic-gate static int
34027c478bd9Sstevel@tonic-gate valid_algorithm(int proto_num, const char *str)
34037c478bd9Sstevel@tonic-gate {
34047c478bd9Sstevel@tonic-gate 	const char *tmp;
34057c478bd9Sstevel@tonic-gate 	int ret;
34067c478bd9Sstevel@tonic-gate 	struct ipsecalgent *alg;
34077c478bd9Sstevel@tonic-gate 
3408c758f97fSpwernau 	/* Short-circuit "none" */
3409c758f97fSpwernau 	if (strncasecmp("none", str, 5) == 0)
3410c758f97fSpwernau 		return (-2);
3411c758f97fSpwernau 
34127c478bd9Sstevel@tonic-gate 	alg = getipsecalgbyname(str, proto_num, NULL);
34137c478bd9Sstevel@tonic-gate 	if (alg != NULL) {
34147c478bd9Sstevel@tonic-gate 		ret = alg->a_alg_num;
34157c478bd9Sstevel@tonic-gate 		freeipsecalgent(alg);
34167c478bd9Sstevel@tonic-gate 		return (ret);
34177c478bd9Sstevel@tonic-gate 	}
34187c478bd9Sstevel@tonic-gate 
34197c478bd9Sstevel@tonic-gate 	/*
34207c478bd9Sstevel@tonic-gate 	 * Look whether it could be a valid number.
34217c478bd9Sstevel@tonic-gate 	 * We support numbers also so that users can
34227c478bd9Sstevel@tonic-gate 	 * load algorithms as they need it. We can't
34237c478bd9Sstevel@tonic-gate 	 * check for validity of numbers here. It will
34247c478bd9Sstevel@tonic-gate 	 * be checked when the SA is negotiated/looked up.
34257c478bd9Sstevel@tonic-gate 	 * parse_int uses strtol(str), which converts 3DES
34267c478bd9Sstevel@tonic-gate 	 * to a valid number i.e looks only at initial
34277c478bd9Sstevel@tonic-gate 	 * number part. If we come here we should expect
34287c478bd9Sstevel@tonic-gate 	 * only a decimal number.
34297c478bd9Sstevel@tonic-gate 	 */
34307c478bd9Sstevel@tonic-gate 	tmp = str;
34317c478bd9Sstevel@tonic-gate 	while (*tmp) {
34327c478bd9Sstevel@tonic-gate 		if (!isdigit(*tmp))
34337c478bd9Sstevel@tonic-gate 			return (-1);
34347c478bd9Sstevel@tonic-gate 		tmp++;
34357c478bd9Sstevel@tonic-gate 	}
34367c478bd9Sstevel@tonic-gate 
34377c478bd9Sstevel@tonic-gate 	ret = parse_int(str);
34387c478bd9Sstevel@tonic-gate 	if (ret > 0 && ret <= 255)
34397c478bd9Sstevel@tonic-gate 		return (ret);
34407c478bd9Sstevel@tonic-gate 	else
34417c478bd9Sstevel@tonic-gate 		return (-1);
34427c478bd9Sstevel@tonic-gate }
34437c478bd9Sstevel@tonic-gate 
34447c478bd9Sstevel@tonic-gate static int
34457c478bd9Sstevel@tonic-gate parse_ipsec_alg(char *str, ips_act_props_t *iap, int alg_type)
34467c478bd9Sstevel@tonic-gate {
34477c478bd9Sstevel@tonic-gate 	int alg_value;
34487c478bd9Sstevel@tonic-gate 	char tstr[VALID_ALG_LEN];
34497c478bd9Sstevel@tonic-gate 	char *lens = NULL;
34507c478bd9Sstevel@tonic-gate 	char *l1_str;
34517c478bd9Sstevel@tonic-gate 	int l1 = 0;
34527c478bd9Sstevel@tonic-gate 	char *l2_str;
34537c478bd9Sstevel@tonic-gate 	int l2 = SPD_MAX_MAXBITS;
34547c478bd9Sstevel@tonic-gate 	algreq_t *ap;
34557c478bd9Sstevel@tonic-gate 	uint_t a_type;
34567c478bd9Sstevel@tonic-gate 
34577c478bd9Sstevel@tonic-gate 	fetch_algorithms();
34587c478bd9Sstevel@tonic-gate 
34597c478bd9Sstevel@tonic-gate 	/*
34607c478bd9Sstevel@tonic-gate 	 * Make sure that we get a null terminated string.
34617c478bd9Sstevel@tonic-gate 	 * For a bad input, we truncate at VALID_ALG_LEN.
34627c478bd9Sstevel@tonic-gate 	 */
34638810c16bSdanmcd 	(void) strlcpy(tstr, str, VALID_ALG_LEN);
34647c478bd9Sstevel@tonic-gate 	lens = strtok(tstr, "()");
34657c478bd9Sstevel@tonic-gate 	lens = strtok(NULL, "()");
34667c478bd9Sstevel@tonic-gate 
34677c478bd9Sstevel@tonic-gate 	if (lens != NULL) {
34687c478bd9Sstevel@tonic-gate 		int len1 = 0;
34697c478bd9Sstevel@tonic-gate 		int len2 = SPD_MAX_MAXBITS;
34707c478bd9Sstevel@tonic-gate 		int len_all = strlen(lens);
34717c478bd9Sstevel@tonic-gate 		int dot_start = (lens[0] == '.');
34727c478bd9Sstevel@tonic-gate 		l1_str = strtok(lens, ".");
34737c478bd9Sstevel@tonic-gate 		l2_str = strtok(NULL, ".");
34747c478bd9Sstevel@tonic-gate 		if (l1_str != NULL) {
34757c478bd9Sstevel@tonic-gate 			l1 = parse_int(l1_str);
34767c478bd9Sstevel@tonic-gate 			len1 = strlen(l1_str);
34777c478bd9Sstevel@tonic-gate 			if (len1 < 0)
34787c478bd9Sstevel@tonic-gate 				return (1);
34797c478bd9Sstevel@tonic-gate 		}
34807c478bd9Sstevel@tonic-gate 		if (l2_str != NULL) {
34817c478bd9Sstevel@tonic-gate 			l2 = parse_int(l2_str);
34827c478bd9Sstevel@tonic-gate 			len2 = strlen(l2_str);
34837c478bd9Sstevel@tonic-gate 			if (len2 < 0)
34847c478bd9Sstevel@tonic-gate 				return (1);
34857c478bd9Sstevel@tonic-gate 		}
34867c478bd9Sstevel@tonic-gate 
34877c478bd9Sstevel@tonic-gate 		if (len_all == len1) {
34887c478bd9Sstevel@tonic-gate 			/* alg(n) */
34897c478bd9Sstevel@tonic-gate 			l2 = l1;
34907c478bd9Sstevel@tonic-gate 		} else if (dot_start) {
34917c478bd9Sstevel@tonic-gate 			/* alg(..n) */
34927c478bd9Sstevel@tonic-gate 			l2 = l1;
34937c478bd9Sstevel@tonic-gate 			l1 = 0;
34947c478bd9Sstevel@tonic-gate 		} else if ((len_all - 2) == len1) {
34957c478bd9Sstevel@tonic-gate 			/* alg(n..) */
34967c478bd9Sstevel@tonic-gate 			l2 = SPD_MAX_MAXBITS;
34977c478bd9Sstevel@tonic-gate 		} /* else alg(n..m) */
34987c478bd9Sstevel@tonic-gate 	}
34997c478bd9Sstevel@tonic-gate 
35007c478bd9Sstevel@tonic-gate 	if (alg_type == SPD_ATTR_AH_AUTH ||
35017c478bd9Sstevel@tonic-gate 	    alg_type == SPD_ATTR_ESP_AUTH) {
35027c478bd9Sstevel@tonic-gate 		alg_value = valid_algorithm(IPSEC_PROTO_AH, tstr);
35037c478bd9Sstevel@tonic-gate 	} else {
35047c478bd9Sstevel@tonic-gate 		alg_value = valid_algorithm(IPSEC_PROTO_ESP, tstr);
35057c478bd9Sstevel@tonic-gate 	}
3506c758f97fSpwernau 	if (alg_value < 0) {
3507c758f97fSpwernau 		/* Invalid algorithm or "none" */
3508c758f97fSpwernau 		return (alg_value);
35097c478bd9Sstevel@tonic-gate 	}
35107c478bd9Sstevel@tonic-gate 
35117c478bd9Sstevel@tonic-gate 	if (alg_type == SPD_ATTR_AH_AUTH) {
35127c478bd9Sstevel@tonic-gate 		a_type = AH_AUTH;
35137c478bd9Sstevel@tonic-gate 		iap->iap_attr |= SPD_APPLY_AH;
35147c478bd9Sstevel@tonic-gate 		ap = &(iap->iap_aauth);
35157c478bd9Sstevel@tonic-gate 	} else if (alg_type == SPD_ATTR_ESP_AUTH) {
35167c478bd9Sstevel@tonic-gate 		a_type = ESP_AUTH;
35177c478bd9Sstevel@tonic-gate 		iap->iap_attr |= SPD_APPLY_ESP|SPD_APPLY_ESPA;
35187c478bd9Sstevel@tonic-gate 		ap = &(iap->iap_eauth);
35197c478bd9Sstevel@tonic-gate 	} else {
35207c478bd9Sstevel@tonic-gate 		a_type = ESP_ENCR;
35217c478bd9Sstevel@tonic-gate 		iap->iap_attr |= SPD_APPLY_ESP;
35227c478bd9Sstevel@tonic-gate 		ap = &(iap->iap_eencr);
35237c478bd9Sstevel@tonic-gate 	}
35247c478bd9Sstevel@tonic-gate 
35257c478bd9Sstevel@tonic-gate 	ap->alg_id = alg_value;
35267c478bd9Sstevel@tonic-gate 	ap->alg_minbits = l1;
35277c478bd9Sstevel@tonic-gate 	ap->alg_maxbits = l2;
35287c478bd9Sstevel@tonic-gate 
35297c478bd9Sstevel@tonic-gate 	if (!alg_rangecheck(a_type, alg_value, ap))
3530c758f97fSpwernau 		return (1);
35317c478bd9Sstevel@tonic-gate 
35327c478bd9Sstevel@tonic-gate 	return (0);
35337c478bd9Sstevel@tonic-gate }
35347c478bd9Sstevel@tonic-gate 
35358810c16bSdanmcd static char *
35368810c16bSdanmcd sys_error_message(int syserr)
35378810c16bSdanmcd {
35388810c16bSdanmcd 	char *mesg;
35398810c16bSdanmcd 
35408810c16bSdanmcd 	switch (syserr) {
35418810c16bSdanmcd 	case EEXIST:
35428810c16bSdanmcd 		mesg = gettext("Entry already exists");
35438810c16bSdanmcd 		break;
35448810c16bSdanmcd 	case ENOENT:
35458810c16bSdanmcd 		mesg = gettext("Tunnel not found");
35468810c16bSdanmcd 		break;
35478810c16bSdanmcd 	case EINVAL:
35488810c16bSdanmcd 		mesg = gettext("Invalid entry");
35498810c16bSdanmcd 		break;
35508810c16bSdanmcd 	default :
35518810c16bSdanmcd 		mesg = strerror(syserr);
35528810c16bSdanmcd 	}
35538810c16bSdanmcd 	return (mesg);
35548810c16bSdanmcd }
35558810c16bSdanmcd 
35567c478bd9Sstevel@tonic-gate static void
35577c478bd9Sstevel@tonic-gate error_message(error_type_t error, int type, int line)
35587c478bd9Sstevel@tonic-gate {
35597c478bd9Sstevel@tonic-gate 	char *mesg;
35607c478bd9Sstevel@tonic-gate 
35617c478bd9Sstevel@tonic-gate 	switch (type) {
35627c478bd9Sstevel@tonic-gate 	case IPSEC_CONF_SRC_ADDRESS:
35637c478bd9Sstevel@tonic-gate 		mesg = gettext("Source Address");
35647c478bd9Sstevel@tonic-gate 		break;
35657c478bd9Sstevel@tonic-gate 	case IPSEC_CONF_DST_ADDRESS:
35667c478bd9Sstevel@tonic-gate 		mesg = gettext("Destination Address");
35677c478bd9Sstevel@tonic-gate 		break;
35687c478bd9Sstevel@tonic-gate 	case IPSEC_CONF_SRC_PORT:
35697c478bd9Sstevel@tonic-gate 		mesg = gettext("Source Port");
35707c478bd9Sstevel@tonic-gate 		break;
35717c478bd9Sstevel@tonic-gate 	case IPSEC_CONF_DST_PORT:
35727c478bd9Sstevel@tonic-gate 		mesg = gettext("Destination Port");
35737c478bd9Sstevel@tonic-gate 		break;
35747c478bd9Sstevel@tonic-gate 	case IPSEC_CONF_SRC_MASK:
35757c478bd9Sstevel@tonic-gate 		mesg = gettext("Source Mask");
35767c478bd9Sstevel@tonic-gate 		break;
35777c478bd9Sstevel@tonic-gate 	case IPSEC_CONF_DST_MASK:
35787c478bd9Sstevel@tonic-gate 		mesg = gettext("Destination Mask");
35797c478bd9Sstevel@tonic-gate 		break;
35807c478bd9Sstevel@tonic-gate 	case IPSEC_CONF_ULP:
35817c478bd9Sstevel@tonic-gate 		mesg = gettext("Upper Layer Protocol");
35827c478bd9Sstevel@tonic-gate 		break;
35837c478bd9Sstevel@tonic-gate 	case IPSEC_CONF_IPSEC_AALGS:
35847c478bd9Sstevel@tonic-gate 		mesg = gettext("Authentication Algorithm");
35857c478bd9Sstevel@tonic-gate 		break;
35867c478bd9Sstevel@tonic-gate 	case IPSEC_CONF_IPSEC_EALGS:
35877c478bd9Sstevel@tonic-gate 		mesg = gettext("Encryption Algorithm");
35887c478bd9Sstevel@tonic-gate 		break;
35897c478bd9Sstevel@tonic-gate 	case IPSEC_CONF_IPSEC_EAALGS:
35907c478bd9Sstevel@tonic-gate 		mesg = gettext("ESP Authentication Algorithm");
35917c478bd9Sstevel@tonic-gate 		break;
35927c478bd9Sstevel@tonic-gate 	case IPSEC_CONF_IPSEC_SA:
35937c478bd9Sstevel@tonic-gate 		mesg = gettext("SA");
35947c478bd9Sstevel@tonic-gate 		break;
35957c478bd9Sstevel@tonic-gate 	case IPSEC_CONF_IPSEC_DIR:
35967c478bd9Sstevel@tonic-gate 		mesg = gettext("Direction");
35977c478bd9Sstevel@tonic-gate 		break;
35987c478bd9Sstevel@tonic-gate 	case IPSEC_CONF_ICMP_TYPE:
35997c478bd9Sstevel@tonic-gate 		mesg = gettext("ICMP type");
36007c478bd9Sstevel@tonic-gate 		break;
36017c478bd9Sstevel@tonic-gate 	case IPSEC_CONF_ICMP_CODE:
36027c478bd9Sstevel@tonic-gate 		mesg = gettext("ICMP code");
36037c478bd9Sstevel@tonic-gate 		break;
36048810c16bSdanmcd 	case IPSEC_CONF_NEGOTIATE:
36058810c16bSdanmcd 		mesg = gettext("Negotiate");
36068810c16bSdanmcd 		break;
36078810c16bSdanmcd 	case IPSEC_CONF_TUNNEL:
36088810c16bSdanmcd 		mesg = gettext("Tunnel");
36098810c16bSdanmcd 		break;
36107c478bd9Sstevel@tonic-gate 	default :
36117c478bd9Sstevel@tonic-gate 		return;
36127c478bd9Sstevel@tonic-gate 	}
36137c478bd9Sstevel@tonic-gate 	/*
36147c478bd9Sstevel@tonic-gate 	 * If we never read a newline character, we don't want
36157c478bd9Sstevel@tonic-gate 	 * to print 0.
36167c478bd9Sstevel@tonic-gate 	 */
3617eeda67c6Sjojemann 	warnx(gettext("%s%s%s %s on line: %d"),
3618eeda67c6Sjojemann 	    (error == BAD_ERROR) ? gettext("Bad") : "",
3619eeda67c6Sjojemann 	    (error == DUP_ERROR) ? gettext("Duplicate") : "",
3620eeda67c6Sjojemann 	    (error == REQ_ERROR) ? gettext("Requires") : "",
3621eeda67c6Sjojemann 	    mesg,
36227c478bd9Sstevel@tonic-gate 	    (arg_indices[line] == 0) ? 1 : arg_indices[line]);
36237c478bd9Sstevel@tonic-gate }
36247c478bd9Sstevel@tonic-gate 
36257c478bd9Sstevel@tonic-gate static int
36267c478bd9Sstevel@tonic-gate validate_properties(ips_act_props_t *cptr, boolean_t dir, boolean_t is_alg)
36277c478bd9Sstevel@tonic-gate {
36287c478bd9Sstevel@tonic-gate 	if (cptr->iap_action == SPD_ACTTYPE_PASS ||
3629d5751483Smarkfen 	    cptr->iap_action == SPD_ACTTYPE_DROP) {
36307c478bd9Sstevel@tonic-gate 		if (!dir) {
36317c478bd9Sstevel@tonic-gate 			warnx(gettext("dir string "
36327c478bd9Sstevel@tonic-gate 			    "not found for bypass policy"));
36337c478bd9Sstevel@tonic-gate 		}
36347c478bd9Sstevel@tonic-gate 
36357c478bd9Sstevel@tonic-gate 		if (is_alg) {
36367c478bd9Sstevel@tonic-gate 			warnx(gettext("Algorithms found for bypass policy"));
36377c478bd9Sstevel@tonic-gate 			return (-1);
36387c478bd9Sstevel@tonic-gate 		}
36397c478bd9Sstevel@tonic-gate 		return (0);
36407c478bd9Sstevel@tonic-gate 	}
36417c478bd9Sstevel@tonic-gate 	if (!is_alg) {
36428810c16bSdanmcd 		warnx(gettext("No IPsec algorithms given"));
36437c478bd9Sstevel@tonic-gate 		return (-1);
36447c478bd9Sstevel@tonic-gate 	}
36457c478bd9Sstevel@tonic-gate 	if (cptr->iap_attr == 0) {
36467c478bd9Sstevel@tonic-gate 		warnx(gettext("No SA attribute"));
36477c478bd9Sstevel@tonic-gate 		return (-1);
36487c478bd9Sstevel@tonic-gate 	}
36497c478bd9Sstevel@tonic-gate 	return (0);
36507c478bd9Sstevel@tonic-gate }
36517c478bd9Sstevel@tonic-gate 
36527c478bd9Sstevel@tonic-gate /*
36537c478bd9Sstevel@tonic-gate  * This function is called only to parse a single rule's worth of
36547c478bd9Sstevel@tonic-gate  * action strings.  This is called after parsing pattern and before
36557c478bd9Sstevel@tonic-gate  * parsing properties.  Thus we may have something in the leftover
36567c478bd9Sstevel@tonic-gate  * buffer while parsing the pattern, which we need to handle here.
36577c478bd9Sstevel@tonic-gate  */
36587c478bd9Sstevel@tonic-gate static int
36597c478bd9Sstevel@tonic-gate parse_action(FILE *fp, char **action, char **leftover)
36607c478bd9Sstevel@tonic-gate {
36617c478bd9Sstevel@tonic-gate 	char *cp;
36627c478bd9Sstevel@tonic-gate 	char ibuf[MAXLEN];
36637c478bd9Sstevel@tonic-gate 	char *tmp_buf;
36647c478bd9Sstevel@tonic-gate 	char *buf;
36657c478bd9Sstevel@tonic-gate 	boolean_t new_stuff;
36667c478bd9Sstevel@tonic-gate 
36677c478bd9Sstevel@tonic-gate 	if (*leftover != NULL) {
36687c478bd9Sstevel@tonic-gate 		buf = *leftover;
36697c478bd9Sstevel@tonic-gate 		new_stuff = B_FALSE;
36707c478bd9Sstevel@tonic-gate 		goto scan;
36717c478bd9Sstevel@tonic-gate 	}
36727c478bd9Sstevel@tonic-gate 	while (fgets(ibuf, MAXLEN, fp) != NULL) {
36737c478bd9Sstevel@tonic-gate 		new_stuff = B_TRUE;
36747c478bd9Sstevel@tonic-gate 		if (ibuf[strlen(ibuf) - 1] == '\n')
36757c478bd9Sstevel@tonic-gate 			linecount++;
36767c478bd9Sstevel@tonic-gate 		buf = ibuf;
36777c478bd9Sstevel@tonic-gate scan:
36787c478bd9Sstevel@tonic-gate 		/* Truncate at the beginning of a comment */
36797c478bd9Sstevel@tonic-gate 		cp = strchr(buf, '#');
36807c478bd9Sstevel@tonic-gate 		if (cp != NULL)
36817c478bd9Sstevel@tonic-gate 			*cp = NULL;
36827c478bd9Sstevel@tonic-gate 
36837c478bd9Sstevel@tonic-gate 		/* Skip any whitespace */
36847c478bd9Sstevel@tonic-gate 		while (*buf != NULL && isspace(*buf))
36857c478bd9Sstevel@tonic-gate 			buf++;
36867c478bd9Sstevel@tonic-gate 
36877c478bd9Sstevel@tonic-gate 		/* Empty line */
36887c478bd9Sstevel@tonic-gate 		if (*buf == NULL)
36897c478bd9Sstevel@tonic-gate 			continue;
36907c478bd9Sstevel@tonic-gate 
36917c478bd9Sstevel@tonic-gate 		/*
36927c478bd9Sstevel@tonic-gate 		 * Store the command for error reporting
36937c478bd9Sstevel@tonic-gate 		 * and ipsec_conf_add().
36947c478bd9Sstevel@tonic-gate 		 */
36957c478bd9Sstevel@tonic-gate 		if (new_stuff) {
36967c478bd9Sstevel@tonic-gate 			/*
36977c478bd9Sstevel@tonic-gate 			 * Check for buffer overflow including the null
36987c478bd9Sstevel@tonic-gate 			 * terminating character.
36997c478bd9Sstevel@tonic-gate 			 */
37007c478bd9Sstevel@tonic-gate 			int len = strlen(ibuf);
37017c478bd9Sstevel@tonic-gate 			if ((cbuf_offset + len + 1) >= CBUF_LEN)
37027c478bd9Sstevel@tonic-gate 				return (-1);
3703d5751483Smarkfen 
37047c478bd9Sstevel@tonic-gate 			(void) strcpy(cbuf + cbuf_offset, ibuf);
37057c478bd9Sstevel@tonic-gate 			cbuf_offset += len;
37067c478bd9Sstevel@tonic-gate 		}
37077c478bd9Sstevel@tonic-gate 		/*
37087c478bd9Sstevel@tonic-gate 		 * Start of the non-empty non-space character.
37097c478bd9Sstevel@tonic-gate 		 */
3710d5751483Smarkfen 		tmp_buf = buf;
37117c478bd9Sstevel@tonic-gate 
37127c478bd9Sstevel@tonic-gate 		/* Skip until next whitespace or CURL_BEGIN */
37137c478bd9Sstevel@tonic-gate 		while (*buf != NULL && !isspace(*buf) &&
37147c478bd9Sstevel@tonic-gate 		    *buf != CURL_BEGIN)
37157c478bd9Sstevel@tonic-gate 			buf++;
37167c478bd9Sstevel@tonic-gate 
37177c478bd9Sstevel@tonic-gate 		if (*buf != NULL) {
3718d5751483Smarkfen 			if (tmp_buf == buf) /* No action token */
3719d5751483Smarkfen 				goto error;
37207c478bd9Sstevel@tonic-gate 			if (*buf == CURL_BEGIN) {
37217c478bd9Sstevel@tonic-gate 				*buf = NULL;
37227c478bd9Sstevel@tonic-gate 				/* Allocate an extra byte for the null also */
37237c478bd9Sstevel@tonic-gate 				if ((*action = malloc(strlen(tmp_buf) + 1)) ==
37247c478bd9Sstevel@tonic-gate 				    NULL) {
37257c478bd9Sstevel@tonic-gate 					warn("malloc");
37267c478bd9Sstevel@tonic-gate 					return (ENOMEM);
37277c478bd9Sstevel@tonic-gate 				}
37287c478bd9Sstevel@tonic-gate 				(void) strcpy(*action, tmp_buf);
37297c478bd9Sstevel@tonic-gate 				*buf = CURL_BEGIN;
37307c478bd9Sstevel@tonic-gate 			} else {
37317c478bd9Sstevel@tonic-gate 				/* We have hit a space */
37327c478bd9Sstevel@tonic-gate 				*buf++ = NULL;
37337c478bd9Sstevel@tonic-gate 				/* Allocate an extra byte for the null also */
37347c478bd9Sstevel@tonic-gate 				if ((*action = malloc(strlen(tmp_buf) + 1)) ==
37357c478bd9Sstevel@tonic-gate 				    NULL) {
37367c478bd9Sstevel@tonic-gate 					warn("malloc");
37377c478bd9Sstevel@tonic-gate 					return (ENOMEM);
37387c478bd9Sstevel@tonic-gate 				}
37397c478bd9Sstevel@tonic-gate 				(void) strcpy(*action, tmp_buf);
37407c478bd9Sstevel@tonic-gate 			}
37417c478bd9Sstevel@tonic-gate 			/*
37427c478bd9Sstevel@tonic-gate 			 * Copy the rest of the line into the
37437c478bd9Sstevel@tonic-gate 			 * leftover buffer.
37447c478bd9Sstevel@tonic-gate 			 */
37457c478bd9Sstevel@tonic-gate 			if (*buf != NULL) {
3746e3320f40Smarkfen 				(void) strlcpy(lo_buf, buf, sizeof (lo_buf));
37477c478bd9Sstevel@tonic-gate 				*leftover = lo_buf;
37487c478bd9Sstevel@tonic-gate 			} else {
37497c478bd9Sstevel@tonic-gate 				*leftover = NULL;
37507c478bd9Sstevel@tonic-gate 			}
37517c478bd9Sstevel@tonic-gate 		} else {
37527c478bd9Sstevel@tonic-gate 			/* Allocate an extra byte for the null also */
37537c478bd9Sstevel@tonic-gate 			if ((*action = malloc(strlen(tmp_buf) + 1)) ==
37547c478bd9Sstevel@tonic-gate 			    NULL) {
37557c478bd9Sstevel@tonic-gate 				warn("malloc");
37567c478bd9Sstevel@tonic-gate 				return (ENOMEM);
37577c478bd9Sstevel@tonic-gate 			}
37587c478bd9Sstevel@tonic-gate 			(void) strcpy(*action, tmp_buf);
37597c478bd9Sstevel@tonic-gate 			*leftover = NULL;
37607c478bd9Sstevel@tonic-gate 		}
3761d5751483Smarkfen 		if (argindex >= ARG_BUF_LEN) {
3762d5751483Smarkfen 			warnx(gettext("(parsing one command) "
3763d5751483Smarkfen 			    "Too many selectors before action."));
37647c478bd9Sstevel@tonic-gate 			return (-1);
3765d5751483Smarkfen 		}
37667c478bd9Sstevel@tonic-gate 		arg_indices[argindex++] = linecount;
37677c478bd9Sstevel@tonic-gate 		return (PARSE_SUCCESS);
37687c478bd9Sstevel@tonic-gate 	}
37697c478bd9Sstevel@tonic-gate 	/*
37707c478bd9Sstevel@tonic-gate 	 * Return error, on an empty action field.
37717c478bd9Sstevel@tonic-gate 	 */
3772d5751483Smarkfen error:
3773d5751483Smarkfen 	warnx(gettext("(parsing one command) "
3774d5751483Smarkfen 	    "Missing action token."));
37757c478bd9Sstevel@tonic-gate 	return (-1);
37767c478bd9Sstevel@tonic-gate }
37777c478bd9Sstevel@tonic-gate 
37787c478bd9Sstevel@tonic-gate /*
37797c478bd9Sstevel@tonic-gate  * This is called to parse pattern or properties that is enclosed
37807c478bd9Sstevel@tonic-gate  * between CURL_BEGIN and CURL_END.
37817c478bd9Sstevel@tonic-gate  */
37827c478bd9Sstevel@tonic-gate static int
37837c478bd9Sstevel@tonic-gate parse_pattern_or_prop(FILE *fp, char *argvec[], char **leftover)
37847c478bd9Sstevel@tonic-gate {
37857c478bd9Sstevel@tonic-gate 	char *cp;
37867c478bd9Sstevel@tonic-gate 	int i = 0;
37877c478bd9Sstevel@tonic-gate 	boolean_t curl_begin_seen = B_FALSE;
37887c478bd9Sstevel@tonic-gate 	char ibuf[MAXLEN];
37897c478bd9Sstevel@tonic-gate 	char *tmp_buf;
37907c478bd9Sstevel@tonic-gate 	char *buf;
37917c478bd9Sstevel@tonic-gate 	boolean_t new_stuff;
37927c478bd9Sstevel@tonic-gate 
37937c478bd9Sstevel@tonic-gate 	/*
37947c478bd9Sstevel@tonic-gate 	 * When parsing properties, leftover buffer could have the
37957c478bd9Sstevel@tonic-gate 	 * leftovers of the previous fgets().
37967c478bd9Sstevel@tonic-gate 	 */
37977c478bd9Sstevel@tonic-gate 	if (*leftover != NULL) {
37987c478bd9Sstevel@tonic-gate 		buf = *leftover;
37997c478bd9Sstevel@tonic-gate 		new_stuff = B_FALSE;
38007c478bd9Sstevel@tonic-gate 		goto scan;
38017c478bd9Sstevel@tonic-gate 	}
38027c478bd9Sstevel@tonic-gate 	while (fgets(ibuf, MAXLEN, fp) != NULL) {
38037c478bd9Sstevel@tonic-gate 		new_stuff = B_TRUE;
38047c478bd9Sstevel@tonic-gate #ifdef DEBUG_HEAVY
38057c478bd9Sstevel@tonic-gate 		(void) printf("%s\n", ibuf);
38067c478bd9Sstevel@tonic-gate #endif
38077c478bd9Sstevel@tonic-gate 		if (ibuf[strlen(ibuf) - 1] == '\n')
38087c478bd9Sstevel@tonic-gate 			linecount++;
38097c478bd9Sstevel@tonic-gate 		buf = ibuf;
38107c478bd9Sstevel@tonic-gate scan:
38117c478bd9Sstevel@tonic-gate 		/* Truncate at the beginning of a comment */
38127c478bd9Sstevel@tonic-gate 		cp = strchr(buf, '#');
38137c478bd9Sstevel@tonic-gate 		if (cp != NULL)
38147c478bd9Sstevel@tonic-gate 			*cp = NULL;
38157c478bd9Sstevel@tonic-gate 
38167c478bd9Sstevel@tonic-gate 		/* Skip any whitespace */
38177c478bd9Sstevel@tonic-gate 		while (*buf != NULL && isspace(*buf))
38187c478bd9Sstevel@tonic-gate 			buf++;
38197c478bd9Sstevel@tonic-gate 
38207c478bd9Sstevel@tonic-gate 		/* Empty line */
38217c478bd9Sstevel@tonic-gate 		if (*buf == NULL)
38227c478bd9Sstevel@tonic-gate 			continue;
38237c478bd9Sstevel@tonic-gate 		/*
38247c478bd9Sstevel@tonic-gate 		 * Store the command for error reporting
38257c478bd9Sstevel@tonic-gate 		 * and ipsec_conf_add().
38267c478bd9Sstevel@tonic-gate 		 */
38277c478bd9Sstevel@tonic-gate 		if (new_stuff) {
38287c478bd9Sstevel@tonic-gate 			/*
38297c478bd9Sstevel@tonic-gate 			 * Check for buffer overflow including the null
38307c478bd9Sstevel@tonic-gate 			 * terminating character.
38317c478bd9Sstevel@tonic-gate 			 */
38327c478bd9Sstevel@tonic-gate 			int len = strlen(ibuf);
38337c478bd9Sstevel@tonic-gate 			if ((cbuf_offset + len + 1) >= CBUF_LEN)
38347c478bd9Sstevel@tonic-gate 				return (-1);
38357c478bd9Sstevel@tonic-gate 			(void) strcpy(cbuf + cbuf_offset, ibuf);
38367c478bd9Sstevel@tonic-gate 			cbuf_offset += len;
38377c478bd9Sstevel@tonic-gate 		}
38387c478bd9Sstevel@tonic-gate 		/*
38397c478bd9Sstevel@tonic-gate 		 * First non-space character should be
38407c478bd9Sstevel@tonic-gate 		 * a curly bracket.
38417c478bd9Sstevel@tonic-gate 		 */
38427c478bd9Sstevel@tonic-gate 		if (!curl_begin_seen) {
38437c478bd9Sstevel@tonic-gate 			if (*buf != CURL_BEGIN) {
38447c478bd9Sstevel@tonic-gate 				/*
38457c478bd9Sstevel@tonic-gate 				 * If we never read a newline character,
38467c478bd9Sstevel@tonic-gate 				 * we don't want to print 0.
38477c478bd9Sstevel@tonic-gate 				 */
3848d5751483Smarkfen 				warnx(gettext("line %d : pattern must start "
3849d5751483Smarkfen 				    "with \"%c\" character"),
3850d5751483Smarkfen 				    (linecount == 0) ? 1 : linecount,
3851d5751483Smarkfen 				    CURL_BEGIN);
38527c478bd9Sstevel@tonic-gate 				return (-1);
38537c478bd9Sstevel@tonic-gate 			}
38547c478bd9Sstevel@tonic-gate 			buf++;
38557c478bd9Sstevel@tonic-gate 			curl_begin_seen = B_TRUE;
38567c478bd9Sstevel@tonic-gate 		}
38577c478bd9Sstevel@tonic-gate 		/*
38587c478bd9Sstevel@tonic-gate 		 * Arguments are separated by white spaces or
38597c478bd9Sstevel@tonic-gate 		 * newlines. Scan till you see a CURL_END.
38607c478bd9Sstevel@tonic-gate 		 */
38617c478bd9Sstevel@tonic-gate 		while (*buf != NULL) {
38627c478bd9Sstevel@tonic-gate 			if (*buf == CURL_END) {
38637c478bd9Sstevel@tonic-gate ret:
38647c478bd9Sstevel@tonic-gate 				*buf++ = NULL;
38657c478bd9Sstevel@tonic-gate 				/*
38667c478bd9Sstevel@tonic-gate 				 * Copy the rest of the line into the
38677c478bd9Sstevel@tonic-gate 				 * leftover buffer if any.
38687c478bd9Sstevel@tonic-gate 				 */
38697c478bd9Sstevel@tonic-gate 				if (*buf != NULL) {
3870e3320f40Smarkfen 					(void) strlcpy(lo_buf, buf,
3871e3320f40Smarkfen 					    sizeof (lo_buf));
38727c478bd9Sstevel@tonic-gate 					*leftover = lo_buf;
38737c478bd9Sstevel@tonic-gate 				} else {
38747c478bd9Sstevel@tonic-gate 					*leftover = NULL;
38757c478bd9Sstevel@tonic-gate 				}
38767c478bd9Sstevel@tonic-gate 				return (PARSE_SUCCESS);
38777c478bd9Sstevel@tonic-gate 			}
38787c478bd9Sstevel@tonic-gate 			/*
38797c478bd9Sstevel@tonic-gate 			 * Skip any trailing whitespace until we see a
38807c478bd9Sstevel@tonic-gate 			 * non white-space character.
38817c478bd9Sstevel@tonic-gate 			 */
38827c478bd9Sstevel@tonic-gate 			while (*buf != NULL && isspace(*buf))
38837c478bd9Sstevel@tonic-gate 				buf++;
38847c478bd9Sstevel@tonic-gate 
38857c478bd9Sstevel@tonic-gate 			if (*buf == CURL_END)
38867c478bd9Sstevel@tonic-gate 				goto ret;
38877c478bd9Sstevel@tonic-gate 
38887c478bd9Sstevel@tonic-gate 			/* Scan the next line as this buffer is empty */
38897c478bd9Sstevel@tonic-gate 			if (*buf == NULL)
38907c478bd9Sstevel@tonic-gate 				break;
38917c478bd9Sstevel@tonic-gate 
38927c478bd9Sstevel@tonic-gate 			if (i >= MAXARGS) {
38937c478bd9Sstevel@tonic-gate 				warnx(
38947c478bd9Sstevel@tonic-gate 				    gettext("Number of Arguments exceeded %d"),
38957c478bd9Sstevel@tonic-gate 				    i);
38967c478bd9Sstevel@tonic-gate 				return (-1);
38977c478bd9Sstevel@tonic-gate 			}
38987c478bd9Sstevel@tonic-gate 			/*
38997c478bd9Sstevel@tonic-gate 			 * Non-empty, Non-space buffer.
39007c478bd9Sstevel@tonic-gate 			 */
39017c478bd9Sstevel@tonic-gate 			tmp_buf = buf++;
39027c478bd9Sstevel@tonic-gate 			/*
39037c478bd9Sstevel@tonic-gate 			 * Real scan of the argument takes place here.
39047c478bd9Sstevel@tonic-gate 			 * Skip past till space or CURL_END.
39057c478bd9Sstevel@tonic-gate 			 */
39067c478bd9Sstevel@tonic-gate 			while (*buf != NULL && !isspace(*buf) &&
39077c478bd9Sstevel@tonic-gate 			    *buf != CURL_END) {
39087c478bd9Sstevel@tonic-gate 				buf++;
39097c478bd9Sstevel@tonic-gate 			}
39107c478bd9Sstevel@tonic-gate 			/*
39117c478bd9Sstevel@tonic-gate 			 * Either a space or we have hit the CURL_END or
39127c478bd9Sstevel@tonic-gate 			 * the real end.
39137c478bd9Sstevel@tonic-gate 			 */
39147c478bd9Sstevel@tonic-gate 			if (*buf != NULL) {
39157c478bd9Sstevel@tonic-gate 				if (*buf == CURL_END) {
39167c478bd9Sstevel@tonic-gate 					*buf++ = NULL;
39177c478bd9Sstevel@tonic-gate 					if ((argvec[i] = malloc(strlen(tmp_buf)
39187c478bd9Sstevel@tonic-gate 					    + 1)) == NULL) {
39197c478bd9Sstevel@tonic-gate 						warn("malloc");
39207c478bd9Sstevel@tonic-gate 						return (ENOMEM);
39217c478bd9Sstevel@tonic-gate 					}
39222eaf37a5Smarkfen 					if (strlen(tmp_buf) != 0) {
39232eaf37a5Smarkfen 						(void) strcpy(argvec[i],
39242eaf37a5Smarkfen 						    tmp_buf);
39252eaf37a5Smarkfen 						if (argindex >= ARG_BUF_LEN)
3926d5751483Smarkfen 							goto toomanyargs;
39272eaf37a5Smarkfen 						arg_indices[argindex++] =
39282eaf37a5Smarkfen 						    linecount;
39292eaf37a5Smarkfen 					}
39307c478bd9Sstevel@tonic-gate 					/*
39317c478bd9Sstevel@tonic-gate 					 * Copy the rest of the line into the
39327c478bd9Sstevel@tonic-gate 					 * leftover buffer.
39337c478bd9Sstevel@tonic-gate 					 */
39347c478bd9Sstevel@tonic-gate 					if (*buf != NULL) {
3935e3320f40Smarkfen 						(void) strlcpy(lo_buf, buf,
3936e3320f40Smarkfen 						    sizeof (lo_buf));
39377c478bd9Sstevel@tonic-gate 						*leftover = lo_buf;
39387c478bd9Sstevel@tonic-gate 					} else {
39397c478bd9Sstevel@tonic-gate 						*leftover = NULL;
39407c478bd9Sstevel@tonic-gate 					}
39417c478bd9Sstevel@tonic-gate 					return (PARSE_SUCCESS);
39427c478bd9Sstevel@tonic-gate 				} else {
39437c478bd9Sstevel@tonic-gate 					*buf++ = NULL;
39447c478bd9Sstevel@tonic-gate 				}
39457c478bd9Sstevel@tonic-gate 			}
39467c478bd9Sstevel@tonic-gate 			/*
39477c478bd9Sstevel@tonic-gate 			 * Copy this argument and scan for the buffer more
39487c478bd9Sstevel@tonic-gate 			 * if it is non-empty. If it is empty scan for
39497c478bd9Sstevel@tonic-gate 			 * the next line.
39507c478bd9Sstevel@tonic-gate 			 */
39517c478bd9Sstevel@tonic-gate 			if ((argvec[i] = malloc(strlen(tmp_buf) + 1)) ==
39527c478bd9Sstevel@tonic-gate 			    NULL) {
39537c478bd9Sstevel@tonic-gate 				warn("malloc");
39547c478bd9Sstevel@tonic-gate 				return (ENOMEM);
39557c478bd9Sstevel@tonic-gate 			}
39567c478bd9Sstevel@tonic-gate 			(void) strcpy(argvec[i++], tmp_buf);
3957d5751483Smarkfen 			if (argindex >= ARG_BUF_LEN) {
3958d5751483Smarkfen 			/*
3959d5751483Smarkfen 			 * The number of tokens in a single policy entry
3960d5751483Smarkfen 			 * exceeds the number of buffers available to fully
3961d5751483Smarkfen 			 * parse the policy entry.
3962d5751483Smarkfen 			 */
3963d5751483Smarkfen toomanyargs:
3964d5751483Smarkfen 				warnx(gettext("(parsing one command) "
3965d5751483Smarkfen 				    "Too many tokens in single policy entry."));
39667c478bd9Sstevel@tonic-gate 				return (-1);
3967d5751483Smarkfen 			}
39687c478bd9Sstevel@tonic-gate 			arg_indices[argindex++] = linecount;
39697c478bd9Sstevel@tonic-gate 		}
39707c478bd9Sstevel@tonic-gate 	}
39717c478bd9Sstevel@tonic-gate 	/*
39727c478bd9Sstevel@tonic-gate 	 * If nothing is given in the file, it is okay.
39737c478bd9Sstevel@tonic-gate 	 * If something is given in the file and it is
39747c478bd9Sstevel@tonic-gate 	 * not CURL_BEGIN, we would have returned error
39757c478bd9Sstevel@tonic-gate 	 * above. If curl_begin_seen and we are here,
39767c478bd9Sstevel@tonic-gate 	 * something is wrong.
39777c478bd9Sstevel@tonic-gate 	 */
3978d5751483Smarkfen 	if (curl_begin_seen) {
3979d5751483Smarkfen 		warnx(gettext("(parsing one command) "
3980d5751483Smarkfen 		    "Pattern or Properties incomplete."));
39817c478bd9Sstevel@tonic-gate 		return (-1);
3982d5751483Smarkfen 	}
39837c478bd9Sstevel@tonic-gate 	return (PARSE_EOF);		/* Nothing more in the file */
39847c478bd9Sstevel@tonic-gate }
39857c478bd9Sstevel@tonic-gate 
39867c478bd9Sstevel@tonic-gate /*
39877c478bd9Sstevel@tonic-gate  * Parse one command i.e {pattern} action {properties}.
39887c478bd9Sstevel@tonic-gate  *
39897c478bd9Sstevel@tonic-gate  * {pattern} ( action {prop} | pass | drop ) (or ...)*
39907c478bd9Sstevel@tonic-gate  */
39917c478bd9Sstevel@tonic-gate static int
39927c478bd9Sstevel@tonic-gate parse_one(FILE *fp, act_prop_t *act_props)
39937c478bd9Sstevel@tonic-gate {
39947c478bd9Sstevel@tonic-gate 	char *leftover;
39957c478bd9Sstevel@tonic-gate 	int ret;
39967c478bd9Sstevel@tonic-gate 	int i;
39977c478bd9Sstevel@tonic-gate 	int ap_num = 0;
39987c478bd9Sstevel@tonic-gate 	enum parse_state {pattern, action, prop } pstate;
39997c478bd9Sstevel@tonic-gate 
40007c478bd9Sstevel@tonic-gate 	has_daprefix = has_saprefix = B_FALSE;
40017c478bd9Sstevel@tonic-gate 
40027c478bd9Sstevel@tonic-gate 	(void) memset(act_props, 0, sizeof (act_prop_t));
40037c478bd9Sstevel@tonic-gate 	pstate = pattern;
40047c478bd9Sstevel@tonic-gate 
40057c478bd9Sstevel@tonic-gate 	ret = 0;
40067c478bd9Sstevel@tonic-gate 	leftover = NULL;
40077c478bd9Sstevel@tonic-gate 	argindex = 0;
40087c478bd9Sstevel@tonic-gate 	cbuf_offset = 0;
40097c478bd9Sstevel@tonic-gate 	assert(shp == NULL && dhp == NULL);
40107c478bd9Sstevel@tonic-gate 
40117c478bd9Sstevel@tonic-gate 	for (;;) {
40127c478bd9Sstevel@tonic-gate 		switch (pstate) {
40137c478bd9Sstevel@tonic-gate 		case pattern:
40147c478bd9Sstevel@tonic-gate 		{
40157c478bd9Sstevel@tonic-gate #ifdef DEBUG_HEAVY
40167c478bd9Sstevel@tonic-gate 			(void) printf("pattern\n");
40177c478bd9Sstevel@tonic-gate #endif
40187c478bd9Sstevel@tonic-gate 			ret = parse_pattern_or_prop(fp,
40197c478bd9Sstevel@tonic-gate 			    act_props->pattern, &leftover);
40207c478bd9Sstevel@tonic-gate 			if (ret == PARSE_EOF) {
40217c478bd9Sstevel@tonic-gate 				/* EOF reached */
4022d5751483Smarkfen 				return (PARSE_EOF);
40237c478bd9Sstevel@tonic-gate 			}
40247c478bd9Sstevel@tonic-gate 			if (ret != 0) {
4025d5751483Smarkfen 				ret = -1;
40267c478bd9Sstevel@tonic-gate 				goto err;
40277c478bd9Sstevel@tonic-gate 			}
40287c478bd9Sstevel@tonic-gate 			pstate = action;
40297c478bd9Sstevel@tonic-gate 			break;
40307c478bd9Sstevel@tonic-gate 		}
40317c478bd9Sstevel@tonic-gate 		case action:
40327c478bd9Sstevel@tonic-gate 		{
40337c478bd9Sstevel@tonic-gate #ifdef DEBUG_HEAVY
40347c478bd9Sstevel@tonic-gate 			(void) printf("action\n");
40357c478bd9Sstevel@tonic-gate #endif
40367c478bd9Sstevel@tonic-gate 			ret = parse_action(fp,
40377c478bd9Sstevel@tonic-gate 			    &act_props->ap[ap_num].act, &leftover);
40387c478bd9Sstevel@tonic-gate 			if (ret != 0) {
4039d5751483Smarkfen 				ret = -1;
40407c478bd9Sstevel@tonic-gate 				goto err;
40417c478bd9Sstevel@tonic-gate 			}
40427c478bd9Sstevel@tonic-gate 
40437c478bd9Sstevel@tonic-gate 			/*
40447c478bd9Sstevel@tonic-gate 			 * Validate action now itself so that we don't
40457c478bd9Sstevel@tonic-gate 			 * proceed too much into the bad world.
40467c478bd9Sstevel@tonic-gate 			 */
40477c478bd9Sstevel@tonic-gate 			for (i = 0; action_table[i].string; i++) {
40487c478bd9Sstevel@tonic-gate 				if (strcmp(act_props->ap[ap_num].act,
40497c478bd9Sstevel@tonic-gate 				    action_table[i].string) == 0)
40507c478bd9Sstevel@tonic-gate 					break;
40517c478bd9Sstevel@tonic-gate 			}
40527c478bd9Sstevel@tonic-gate 
40537c478bd9Sstevel@tonic-gate 			if (action_table[i].tok_val == TOK_or) {
40547c478bd9Sstevel@tonic-gate 				/* hit an or, go again */
40557c478bd9Sstevel@tonic-gate 				break;
40567c478bd9Sstevel@tonic-gate 			}
40577c478bd9Sstevel@tonic-gate 
40587c478bd9Sstevel@tonic-gate 			if (action_table[i].string == NULL) {
40597c478bd9Sstevel@tonic-gate 				/*
40607c478bd9Sstevel@tonic-gate 				 * If we never read a newline
40617c478bd9Sstevel@tonic-gate 				 * character, we don't want
40627c478bd9Sstevel@tonic-gate 				 * to print 0.
40637c478bd9Sstevel@tonic-gate 				 */
4064d5751483Smarkfen 				warnx(gettext("(parsing one command) "
40657c478bd9Sstevel@tonic-gate 				    "Invalid action on line %d: %s"),
40667c478bd9Sstevel@tonic-gate 				    (linecount == 0) ? 1 : linecount,
40677c478bd9Sstevel@tonic-gate 				    act_props->ap[ap_num].act);
40687c478bd9Sstevel@tonic-gate 				return (-1);
40697c478bd9Sstevel@tonic-gate 			}
40707c478bd9Sstevel@tonic-gate 
40717c478bd9Sstevel@tonic-gate 			pstate = prop;
40727c478bd9Sstevel@tonic-gate 			break;
40737c478bd9Sstevel@tonic-gate 		}
40747c478bd9Sstevel@tonic-gate 		case prop:
40757c478bd9Sstevel@tonic-gate 		{
40767c478bd9Sstevel@tonic-gate #ifdef DEBUG_HEAVY
40777c478bd9Sstevel@tonic-gate 			(void) printf("prop\n");
40787c478bd9Sstevel@tonic-gate #endif
40797c478bd9Sstevel@tonic-gate 			ret = parse_pattern_or_prop(fp,
40807c478bd9Sstevel@tonic-gate 			    act_props->ap[ap_num].prop, &leftover);
40817c478bd9Sstevel@tonic-gate 			if (ret != 0) {
4082d5751483Smarkfen 				if (ret == PARSE_EOF) {
4083d5751483Smarkfen 					warnx(gettext("(parsing one command) "
4084d5751483Smarkfen 					    "Missing properties."));
4085d5751483Smarkfen 				}
4086d5751483Smarkfen 				ret = -1;
40877c478bd9Sstevel@tonic-gate 				goto err;
40887c478bd9Sstevel@tonic-gate 			}
40897c478bd9Sstevel@tonic-gate 
40907c478bd9Sstevel@tonic-gate 			if (leftover != NULL) {
40917c478bd9Sstevel@tonic-gate 				/* Accomodate spaces at the end */
40927c478bd9Sstevel@tonic-gate 				while (*leftover != NULL) {
4093d5751483Smarkfen 					if (*leftover == BACK_SLASH) {
4094d5751483Smarkfen 						warnx(gettext("Invalid line "
4095d5751483Smarkfen 						    "continuation character."));
4096d5751483Smarkfen 						ret = -1;
4097d5751483Smarkfen 						goto err;
4098d5751483Smarkfen 					}
40997c478bd9Sstevel@tonic-gate 					if (*leftover == 'o') {
41007c478bd9Sstevel@tonic-gate 						leftover++;
41017c478bd9Sstevel@tonic-gate 						if (*leftover == 'r') {
41027c478bd9Sstevel@tonic-gate 							leftover++;
41037c478bd9Sstevel@tonic-gate 							ap_num++;
41047c478bd9Sstevel@tonic-gate 							pstate = action;
41057c478bd9Sstevel@tonic-gate 							goto again;
41067c478bd9Sstevel@tonic-gate 						}
41077c478bd9Sstevel@tonic-gate 					}
41087c478bd9Sstevel@tonic-gate 					if (!isspace(*leftover)) {
41097c478bd9Sstevel@tonic-gate 						ret = -1;
41107c478bd9Sstevel@tonic-gate 						goto err;
41117c478bd9Sstevel@tonic-gate 					}
41127c478bd9Sstevel@tonic-gate 					leftover++;
41137c478bd9Sstevel@tonic-gate 				}
41147c478bd9Sstevel@tonic-gate 				return (0);
41157c478bd9Sstevel@tonic-gate 			}
41167c478bd9Sstevel@tonic-gate 			ap_num++;
41177c478bd9Sstevel@tonic-gate 			if (ap_num > MAXARGS)
41187c478bd9Sstevel@tonic-gate 				return (0);
41197c478bd9Sstevel@tonic-gate 			pstate = action; /* or */
41207c478bd9Sstevel@tonic-gate 			break;
41217c478bd9Sstevel@tonic-gate 		} /* case prop: */
41227c478bd9Sstevel@tonic-gate 		} /* switch(pstate) */
41237c478bd9Sstevel@tonic-gate 
41247c478bd9Sstevel@tonic-gate again:
4125d5751483Smarkfen 		if (ap_num > MAXARGS) {
4126d5751483Smarkfen 			warnx(gettext("Too many actions."));
4127d5751483Smarkfen 			return (-1);
4128d5751483Smarkfen 		}
4129d5751483Smarkfen 	} /* for(;;) */
41307c478bd9Sstevel@tonic-gate err:
41317c478bd9Sstevel@tonic-gate 	if (ret != 0) {
41327c478bd9Sstevel@tonic-gate 		/*
41337c478bd9Sstevel@tonic-gate 		 * If we never read a newline character, we don't want
41347c478bd9Sstevel@tonic-gate 		 * to print 0.
41357c478bd9Sstevel@tonic-gate 		 */
41367c478bd9Sstevel@tonic-gate 		warnx(gettext("Error before or at line %d"),
41377c478bd9Sstevel@tonic-gate 		    (linecount == 0) ? 1 : linecount);
41387c478bd9Sstevel@tonic-gate 	}
41397c478bd9Sstevel@tonic-gate 	return (ret);
41407c478bd9Sstevel@tonic-gate }
41417c478bd9Sstevel@tonic-gate 
41427c478bd9Sstevel@tonic-gate /*
41437c478bd9Sstevel@tonic-gate  * convert an act_propts_t to an ips_conf_t
41447c478bd9Sstevel@tonic-gate  */
41457c478bd9Sstevel@tonic-gate 
41467c478bd9Sstevel@tonic-gate static int
41477c478bd9Sstevel@tonic-gate form_ipsec_conf(act_prop_t *act_props, ips_conf_t *cptr)
41487c478bd9Sstevel@tonic-gate {
41497c478bd9Sstevel@tonic-gate 	int i, j, k;
41507c478bd9Sstevel@tonic-gate 	int tok_count = 0;
41517c478bd9Sstevel@tonic-gate 	struct protoent *pent;
41527c478bd9Sstevel@tonic-gate 	boolean_t saddr, daddr, ipsec_aalg, ipsec_ealg, ipsec_eaalg, dir;
41537c478bd9Sstevel@tonic-gate 	boolean_t old_style, new_style;
41547c478bd9Sstevel@tonic-gate 	struct in_addr mask;
41557c478bd9Sstevel@tonic-gate 	int line_no;
41567c478bd9Sstevel@tonic-gate 	int ret;
41577c478bd9Sstevel@tonic-gate 	int ap_num = 0;
41587c478bd9Sstevel@tonic-gate 	int type, code, type_end, code_end;
41597c478bd9Sstevel@tonic-gate #ifdef DEBUG_HEAVY
41607c478bd9Sstevel@tonic-gate 	/*
41617c478bd9Sstevel@tonic-gate 	 * pattern => act_props->pattern
41627c478bd9Sstevel@tonic-gate 	 * action => act_props->ap[].act
41637c478bd9Sstevel@tonic-gate 	 * properties => act_props->ap[].prop
41647c478bd9Sstevel@tonic-gate 	 */
41657c478bd9Sstevel@tonic-gate 	(void) printf("\npattern\n------------\n");
41667c478bd9Sstevel@tonic-gate 	for (i = 0; act_props->pattern[i] != NULL; i++)
41677c478bd9Sstevel@tonic-gate 		(void) printf("%s\n", act_props->pattern[i]);
41687c478bd9Sstevel@tonic-gate 	(void) printf("apz\n----------\n");
41697c478bd9Sstevel@tonic-gate 	for (j = 0; act_props->ap[j].act != NULL; j++) {
41707c478bd9Sstevel@tonic-gate 
41717c478bd9Sstevel@tonic-gate 		(void) printf("act%d->%s\n", j, act_props->ap[j].act);
41727c478bd9Sstevel@tonic-gate 		for (i = 0; act_props->ap[j].prop[i] != NULL; i++)
41737c478bd9Sstevel@tonic-gate 			(void) printf("%dprop%d->%s\n",
41747c478bd9Sstevel@tonic-gate 			    j, i, act_props->ap[j].prop[i]);
41757c478bd9Sstevel@tonic-gate 	}
41767c478bd9Sstevel@tonic-gate 	(void) printf("------------\n\n");
41777c478bd9Sstevel@tonic-gate #endif
41787c478bd9Sstevel@tonic-gate 
41797c478bd9Sstevel@tonic-gate 	(void) memset(cptr, 0, sizeof (ips_conf_t));
41807c478bd9Sstevel@tonic-gate 	saddr = daddr = ipsec_aalg = ipsec_ealg = ipsec_eaalg = dir = B_FALSE;
41817c478bd9Sstevel@tonic-gate 	old_style = new_style = B_FALSE;
41827c478bd9Sstevel@tonic-gate 	/*
41837c478bd9Sstevel@tonic-gate 	 * Get the Pattern. NULL pattern is valid.
41847c478bd9Sstevel@tonic-gate 	 */
41857c478bd9Sstevel@tonic-gate 	for (i = 0, line_no = 0; act_props->pattern[i]; i++, line_no++) {
41867c478bd9Sstevel@tonic-gate 		for (j = 0; pattern_table[j].string; j++) {
41877c478bd9Sstevel@tonic-gate 			if (strcmp(act_props->pattern[i],
41887c478bd9Sstevel@tonic-gate 			    pattern_table[j].string) == 0)
41897c478bd9Sstevel@tonic-gate 				break;
41907c478bd9Sstevel@tonic-gate 		}
41917c478bd9Sstevel@tonic-gate 
41927c478bd9Sstevel@tonic-gate 		if (pattern_table[j].string == NULL) {
41937c478bd9Sstevel@tonic-gate 			/*
41947c478bd9Sstevel@tonic-gate 			 * If we never read a newline character, we don't want
41957c478bd9Sstevel@tonic-gate 			 * to print 0.
41967c478bd9Sstevel@tonic-gate 			 */
41977c478bd9Sstevel@tonic-gate 			warnx(gettext("Invalid pattern on line %d: %s"),
41987c478bd9Sstevel@tonic-gate 			    (arg_indices[line_no] == 0) ? 1 :
41997c478bd9Sstevel@tonic-gate 			    arg_indices[line_no], act_props->pattern[i]);
42007c478bd9Sstevel@tonic-gate 			return (-1);
42017c478bd9Sstevel@tonic-gate 		}
42027c478bd9Sstevel@tonic-gate 
42037c478bd9Sstevel@tonic-gate 		cptr->patt_tok[tok_count++] = pattern_table[j].tok_val;
42047c478bd9Sstevel@tonic-gate 
42057c478bd9Sstevel@tonic-gate 		switch (pattern_table[j].tok_val) {
42067c478bd9Sstevel@tonic-gate 
42077c478bd9Sstevel@tonic-gate 		case TOK_dir:
42087c478bd9Sstevel@tonic-gate 			i++, line_no++;
42097c478bd9Sstevel@tonic-gate 			if (act_props->pattern[i] == NULL) {
42107c478bd9Sstevel@tonic-gate 				error_message(BAD_ERROR,
42117c478bd9Sstevel@tonic-gate 				    IPSEC_CONF_IPSEC_DIR, line_no);
42127c478bd9Sstevel@tonic-gate 				return (-1);
42137c478bd9Sstevel@tonic-gate 			}
42147c478bd9Sstevel@tonic-gate 
42157c478bd9Sstevel@tonic-gate 			if (strncmp(act_props->pattern[i], "in", 2) == 0) {
42167c478bd9Sstevel@tonic-gate 				cptr->ips_dir = SPD_RULE_FLAG_INBOUND;
42177c478bd9Sstevel@tonic-gate 			} else if (strncmp(
42187c478bd9Sstevel@tonic-gate 			    act_props->pattern[i], "out", 3) == 0) {
42197c478bd9Sstevel@tonic-gate 				cptr->ips_dir = SPD_RULE_FLAG_OUTBOUND;
42207c478bd9Sstevel@tonic-gate 			} else if (strncmp(
42217c478bd9Sstevel@tonic-gate 			    act_props->pattern[i], "both", 4) == 0) {
42227c478bd9Sstevel@tonic-gate 				if (old_style) {
42237c478bd9Sstevel@tonic-gate 					error_message(BAD_ERROR,
42247c478bd9Sstevel@tonic-gate 					    IPSEC_CONF_IPSEC_DIR, line_no);
42257c478bd9Sstevel@tonic-gate 					return (-1);
42267c478bd9Sstevel@tonic-gate 				}
42277c478bd9Sstevel@tonic-gate 				new_style = B_TRUE;
42287c478bd9Sstevel@tonic-gate 				cptr->ips_dir =
42297c478bd9Sstevel@tonic-gate 				    SPD_RULE_FLAG_OUTBOUND |
42307c478bd9Sstevel@tonic-gate 				    SPD_RULE_FLAG_INBOUND;
42317c478bd9Sstevel@tonic-gate 			} else {
42327c478bd9Sstevel@tonic-gate 				error_message(BAD_ERROR,
42337c478bd9Sstevel@tonic-gate 				    IPSEC_CONF_IPSEC_DIR, line_no);
42347c478bd9Sstevel@tonic-gate 				return (-1);
42357c478bd9Sstevel@tonic-gate 			}
42367c478bd9Sstevel@tonic-gate 			dir = B_TRUE;
42377c478bd9Sstevel@tonic-gate 			break;
42387c478bd9Sstevel@tonic-gate 
42397c478bd9Sstevel@tonic-gate 		case TOK_local:
42407c478bd9Sstevel@tonic-gate 			if (old_style) {
42417c478bd9Sstevel@tonic-gate 				error_message(BAD_ERROR,
42427c478bd9Sstevel@tonic-gate 				    IPSEC_CONF_SRC_ADDRESS, line_no);
42437c478bd9Sstevel@tonic-gate 				return (-1);
42447c478bd9Sstevel@tonic-gate 			}
42457c478bd9Sstevel@tonic-gate 			new_style = B_TRUE;
42467c478bd9Sstevel@tonic-gate 
42477c478bd9Sstevel@tonic-gate 			if (saddr) {
42487c478bd9Sstevel@tonic-gate 				error_message(DUP_ERROR,
42497c478bd9Sstevel@tonic-gate 				    IPSEC_CONF_SRC_ADDRESS, line_no);
42507c478bd9Sstevel@tonic-gate 				return (-1);
42517c478bd9Sstevel@tonic-gate 			}
42527c478bd9Sstevel@tonic-gate 			/*
42537c478bd9Sstevel@tonic-gate 			 * Use this to detect duplicates rather
42547c478bd9Sstevel@tonic-gate 			 * than 0 like other cases, because 0 for
42557c478bd9Sstevel@tonic-gate 			 * address means INADDR_ANY.
42567c478bd9Sstevel@tonic-gate 			 */
42577c478bd9Sstevel@tonic-gate 			saddr = B_TRUE;
42587c478bd9Sstevel@tonic-gate 			cptr->has_saddr = 1;
42597c478bd9Sstevel@tonic-gate 			/*
42607c478bd9Sstevel@tonic-gate 			 * Advance to the string containing
42617c478bd9Sstevel@tonic-gate 			 * the address.
42627c478bd9Sstevel@tonic-gate 			 */
42637c478bd9Sstevel@tonic-gate 			i++, line_no++;
42647c478bd9Sstevel@tonic-gate 			if (act_props->pattern[i] == NULL) {
42657c478bd9Sstevel@tonic-gate 				error_message(BAD_ERROR,
42667c478bd9Sstevel@tonic-gate 				    IPSEC_CONF_SRC_ADDRESS, line_no);
42677c478bd9Sstevel@tonic-gate 				return (-1);
42687c478bd9Sstevel@tonic-gate 			}
42697c478bd9Sstevel@tonic-gate 			if (parse_address(IPSEC_CONF_SRC_ADDRESS,
42707c478bd9Sstevel@tonic-gate 			    act_props->pattern[i]) != 0) {
42717c478bd9Sstevel@tonic-gate 				error_message(BAD_ERROR,
42727c478bd9Sstevel@tonic-gate 				    IPSEC_CONF_SRC_ADDRESS, line_no);
42737c478bd9Sstevel@tonic-gate 				return (-1);
42747c478bd9Sstevel@tonic-gate 			}
42757c478bd9Sstevel@tonic-gate 			if (!cptr->has_smask)
42767c478bd9Sstevel@tonic-gate 				cptr->has_smask = has_saprefix;
42777c478bd9Sstevel@tonic-gate 
42787c478bd9Sstevel@tonic-gate 			break;
42797c478bd9Sstevel@tonic-gate 		case TOK_remote:
42807c478bd9Sstevel@tonic-gate 			if (old_style) {
42817c478bd9Sstevel@tonic-gate 				error_message(BAD_ERROR,
42827c478bd9Sstevel@tonic-gate 				    IPSEC_CONF_DST_ADDRESS, line_no);
42837c478bd9Sstevel@tonic-gate 				return (-1);
42847c478bd9Sstevel@tonic-gate 			}
42857c478bd9Sstevel@tonic-gate 			new_style = B_TRUE;
42867c478bd9Sstevel@tonic-gate 
42877c478bd9Sstevel@tonic-gate 			if (daddr) {
42887c478bd9Sstevel@tonic-gate 				error_message(DUP_ERROR,
42897c478bd9Sstevel@tonic-gate 				    IPSEC_CONF_DST_ADDRESS, line_no);
42907c478bd9Sstevel@tonic-gate 				return (-1);
42917c478bd9Sstevel@tonic-gate 			}
42927c478bd9Sstevel@tonic-gate 			/*
42937c478bd9Sstevel@tonic-gate 			 * Use this to detect duplicates rather
42947c478bd9Sstevel@tonic-gate 			 * than 0 like other cases, because 0 for
42957c478bd9Sstevel@tonic-gate 			 * address means INADDR_ANY.
42967c478bd9Sstevel@tonic-gate 			 */
42977c478bd9Sstevel@tonic-gate 			daddr = B_TRUE;
42987c478bd9Sstevel@tonic-gate 			cptr->has_daddr = 1;
42997c478bd9Sstevel@tonic-gate 			/*
43007c478bd9Sstevel@tonic-gate 			 * Advance to the string containing
43017c478bd9Sstevel@tonic-gate 			 * the address.
43027c478bd9Sstevel@tonic-gate 			 */
43037c478bd9Sstevel@tonic-gate 			i++, line_no++;
43047c478bd9Sstevel@tonic-gate 			if (act_props->pattern[i] == NULL) {
43057c478bd9Sstevel@tonic-gate 				error_message(BAD_ERROR,
43067c478bd9Sstevel@tonic-gate 				    IPSEC_CONF_DST_ADDRESS, line_no);
43077c478bd9Sstevel@tonic-gate 				return (-1);
43087c478bd9Sstevel@tonic-gate 			}
43097c478bd9Sstevel@tonic-gate 			if (parse_address(IPSEC_CONF_DST_ADDRESS,
43107c478bd9Sstevel@tonic-gate 			    act_props->pattern[i]) != 0) {
43117c478bd9Sstevel@tonic-gate 				error_message(BAD_ERROR,
43127c478bd9Sstevel@tonic-gate 				    IPSEC_CONF_DST_ADDRESS, line_no);
43137c478bd9Sstevel@tonic-gate 				return (-1);
43147c478bd9Sstevel@tonic-gate 			}
43157c478bd9Sstevel@tonic-gate 			if (!cptr->has_dmask)
43167c478bd9Sstevel@tonic-gate 				cptr->has_dmask = has_daprefix;
43177c478bd9Sstevel@tonic-gate 			break;
43187c478bd9Sstevel@tonic-gate 
43197c478bd9Sstevel@tonic-gate 		case TOK_saddr:
43207c478bd9Sstevel@tonic-gate 			if (new_style) {
43217c478bd9Sstevel@tonic-gate 				error_message(BAD_ERROR,
43227c478bd9Sstevel@tonic-gate 				    IPSEC_CONF_SRC_ADDRESS, line_no);
43237c478bd9Sstevel@tonic-gate 				return (-1);
43247c478bd9Sstevel@tonic-gate 			}
43257c478bd9Sstevel@tonic-gate 			old_style = B_TRUE;
43267c478bd9Sstevel@tonic-gate 
43277c478bd9Sstevel@tonic-gate 			if (saddr) {
43287c478bd9Sstevel@tonic-gate 				error_message(DUP_ERROR,
43297c478bd9Sstevel@tonic-gate 				    IPSEC_CONF_SRC_ADDRESS, line_no);
43307c478bd9Sstevel@tonic-gate 				return (-1);
43317c478bd9Sstevel@tonic-gate 			}
43327c478bd9Sstevel@tonic-gate 			/*
43337c478bd9Sstevel@tonic-gate 			 * Use this to detect duplicates rather
43347c478bd9Sstevel@tonic-gate 			 * than 0 like other cases, because 0 for
43357c478bd9Sstevel@tonic-gate 			 * address means INADDR_ANY.
43367c478bd9Sstevel@tonic-gate 			 */
43377c478bd9Sstevel@tonic-gate 			saddr = B_TRUE;
43387c478bd9Sstevel@tonic-gate 			cptr->has_saddr = 1;
43397c478bd9Sstevel@tonic-gate 			/*
43407c478bd9Sstevel@tonic-gate 			 * Advance to the string containing
43417c478bd9Sstevel@tonic-gate 			 * the address.
43427c478bd9Sstevel@tonic-gate 			 */
43437c478bd9Sstevel@tonic-gate 			i++, line_no++;
43447c478bd9Sstevel@tonic-gate 			if (act_props->pattern[i] == NULL) {
43457c478bd9Sstevel@tonic-gate 				error_message(BAD_ERROR,
43467c478bd9Sstevel@tonic-gate 				    IPSEC_CONF_SRC_ADDRESS, line_no);
43477c478bd9Sstevel@tonic-gate 				return (-1);
43487c478bd9Sstevel@tonic-gate 			}
43497c478bd9Sstevel@tonic-gate 
43507c478bd9Sstevel@tonic-gate 			if (parse_address(IPSEC_CONF_SRC_ADDRESS,
43517c478bd9Sstevel@tonic-gate 			    act_props->pattern[i]) != 0) {
43527c478bd9Sstevel@tonic-gate 				error_message(BAD_ERROR,
43537c478bd9Sstevel@tonic-gate 				    IPSEC_CONF_SRC_ADDRESS, line_no);
43547c478bd9Sstevel@tonic-gate 				return (-1);
43557c478bd9Sstevel@tonic-gate 			}
43567c478bd9Sstevel@tonic-gate 			/* shp or bhp? */
43577c478bd9Sstevel@tonic-gate 			if (!cptr->has_smask)
43587c478bd9Sstevel@tonic-gate 				cptr->has_smask = has_saprefix;
43597c478bd9Sstevel@tonic-gate 			break;
43607c478bd9Sstevel@tonic-gate 
43617c478bd9Sstevel@tonic-gate 		case TOK_daddr:
43627c478bd9Sstevel@tonic-gate 			if (new_style) {
43637c478bd9Sstevel@tonic-gate 				error_message(BAD_ERROR,
43647c478bd9Sstevel@tonic-gate 				    IPSEC_CONF_DST_ADDRESS, line_no);
43657c478bd9Sstevel@tonic-gate 				return (-1);
43667c478bd9Sstevel@tonic-gate 			}
43677c478bd9Sstevel@tonic-gate 			old_style = B_TRUE;
43687c478bd9Sstevel@tonic-gate 
43697c478bd9Sstevel@tonic-gate 			if (daddr) {
43707c478bd9Sstevel@tonic-gate 				error_message(DUP_ERROR,
43717c478bd9Sstevel@tonic-gate 				    IPSEC_CONF_DST_ADDRESS, line_no);
43727c478bd9Sstevel@tonic-gate 				return (-1);
43737c478bd9Sstevel@tonic-gate 			}
43747c478bd9Sstevel@tonic-gate 			/*
43757c478bd9Sstevel@tonic-gate 			 * Use this to detect duplicates rather
43767c478bd9Sstevel@tonic-gate 			 * than 0 like other cases, because 0 for
43777c478bd9Sstevel@tonic-gate 			 * address means INADDR_ANY.
43787c478bd9Sstevel@tonic-gate 			 */
43797c478bd9Sstevel@tonic-gate 			daddr = B_TRUE;
43807c478bd9Sstevel@tonic-gate 			cptr->has_daddr = 1;
43817c478bd9Sstevel@tonic-gate 			/*
43827c478bd9Sstevel@tonic-gate 			 * Advance to the string containing
43837c478bd9Sstevel@tonic-gate 			 * the address.
43847c478bd9Sstevel@tonic-gate 			 */
43857c478bd9Sstevel@tonic-gate 			i++, line_no++;
43867c478bd9Sstevel@tonic-gate 			if (act_props->pattern[i] == NULL) {
43877c478bd9Sstevel@tonic-gate 				error_message(BAD_ERROR,
43887c478bd9Sstevel@tonic-gate 				    IPSEC_CONF_DST_ADDRESS, line_no);
43897c478bd9Sstevel@tonic-gate 				return (-1);
43907c478bd9Sstevel@tonic-gate 			}
43917c478bd9Sstevel@tonic-gate 			if (parse_address(IPSEC_CONF_DST_ADDRESS,
43927c478bd9Sstevel@tonic-gate 			    act_props->pattern[i]) != 0) {
43937c478bd9Sstevel@tonic-gate 				error_message(BAD_ERROR,
43947c478bd9Sstevel@tonic-gate 				    IPSEC_CONF_DST_ADDRESS, line_no);
43957c478bd9Sstevel@tonic-gate 				return (-1);
43967c478bd9Sstevel@tonic-gate 			}
43977c478bd9Sstevel@tonic-gate 			if (!cptr->has_dmask)
43987c478bd9Sstevel@tonic-gate 				cptr->has_dmask = has_daprefix;
43997c478bd9Sstevel@tonic-gate 			break;
44007c478bd9Sstevel@tonic-gate 
44017c478bd9Sstevel@tonic-gate 		case TOK_sport:
44027c478bd9Sstevel@tonic-gate 			if (new_style) {
44037c478bd9Sstevel@tonic-gate 				error_message(BAD_ERROR,
44047c478bd9Sstevel@tonic-gate 				    IPSEC_CONF_SRC_PORT, line_no);
44057c478bd9Sstevel@tonic-gate 				return (-1);
44067c478bd9Sstevel@tonic-gate 			}
44077c478bd9Sstevel@tonic-gate 			old_style = B_TRUE;
44087c478bd9Sstevel@tonic-gate 
44097c478bd9Sstevel@tonic-gate 			if (cptr->ips_src_port_min != 0) {
44107c478bd9Sstevel@tonic-gate 				error_message(DUP_ERROR, IPSEC_CONF_SRC_PORT,
44117c478bd9Sstevel@tonic-gate 				    line_no);
44127c478bd9Sstevel@tonic-gate 				return (-1);
44137c478bd9Sstevel@tonic-gate 			}
44147c478bd9Sstevel@tonic-gate 			i++, line_no++;
44157c478bd9Sstevel@tonic-gate 			if (act_props->pattern[i] == NULL) {
44167c478bd9Sstevel@tonic-gate 				error_message(BAD_ERROR, IPSEC_CONF_SRC_PORT,
44177c478bd9Sstevel@tonic-gate 				    line_no);
44187c478bd9Sstevel@tonic-gate 				return (-1);
44197c478bd9Sstevel@tonic-gate 			}
44207c478bd9Sstevel@tonic-gate 			ret = parse_port(IPSEC_CONF_SRC_PORT,
44217c478bd9Sstevel@tonic-gate 			    act_props->pattern[i], cptr);
44227c478bd9Sstevel@tonic-gate 			if (ret != 0) {
44237c478bd9Sstevel@tonic-gate 				error_message(BAD_ERROR, IPSEC_CONF_SRC_PORT,
44247c478bd9Sstevel@tonic-gate 				    line_no);
44257c478bd9Sstevel@tonic-gate 				return (-1);
44267c478bd9Sstevel@tonic-gate 			}
44277c478bd9Sstevel@tonic-gate 			break;
44287c478bd9Sstevel@tonic-gate 		case TOK_dport:
44297c478bd9Sstevel@tonic-gate 			if (new_style) {
44307c478bd9Sstevel@tonic-gate 				error_message(BAD_ERROR,
44317c478bd9Sstevel@tonic-gate 				    IPSEC_CONF_DST_PORT, line_no);
44327c478bd9Sstevel@tonic-gate 				return (-1);
44337c478bd9Sstevel@tonic-gate 			}
44347c478bd9Sstevel@tonic-gate 			old_style = B_TRUE;
44357c478bd9Sstevel@tonic-gate 
44367c478bd9Sstevel@tonic-gate 			if (cptr->ips_dst_port_min != 0) {
44377c478bd9Sstevel@tonic-gate 				error_message(DUP_ERROR, IPSEC_CONF_DST_PORT,
44387c478bd9Sstevel@tonic-gate 				    line_no);
44397c478bd9Sstevel@tonic-gate 				return (-1);
44407c478bd9Sstevel@tonic-gate 			}
44417c478bd9Sstevel@tonic-gate 			i++, line_no++;
44427c478bd9Sstevel@tonic-gate 			if (act_props->pattern[i] == NULL) {
44437c478bd9Sstevel@tonic-gate 				error_message(BAD_ERROR, IPSEC_CONF_DST_PORT,
44447c478bd9Sstevel@tonic-gate 				    line_no);
44457c478bd9Sstevel@tonic-gate 				return (-1);
44467c478bd9Sstevel@tonic-gate 			}
44477c478bd9Sstevel@tonic-gate 			ret = parse_port(IPSEC_CONF_DST_PORT,
44487c478bd9Sstevel@tonic-gate 			    act_props->pattern[i],
44497c478bd9Sstevel@tonic-gate 			    cptr);
44507c478bd9Sstevel@tonic-gate 			if (ret != 0) {
44517c478bd9Sstevel@tonic-gate 				error_message(BAD_ERROR, IPSEC_CONF_DST_PORT,
44527c478bd9Sstevel@tonic-gate 				    line_no);
44537c478bd9Sstevel@tonic-gate 				return (-1);
44547c478bd9Sstevel@tonic-gate 			}
44557c478bd9Sstevel@tonic-gate 			break;
44567c478bd9Sstevel@tonic-gate 
44577c478bd9Sstevel@tonic-gate 		case TOK_lport:
44587c478bd9Sstevel@tonic-gate 			if (old_style) {
44597c478bd9Sstevel@tonic-gate 				error_message(BAD_ERROR,
44607c478bd9Sstevel@tonic-gate 				    IPSEC_CONF_SRC_PORT, line_no);
44617c478bd9Sstevel@tonic-gate 				return (-1);
44627c478bd9Sstevel@tonic-gate 			}
44637c478bd9Sstevel@tonic-gate 			new_style = B_TRUE;
44647c478bd9Sstevel@tonic-gate 
44657c478bd9Sstevel@tonic-gate 			if (cptr->ips_src_port_min != 0) {
44667c478bd9Sstevel@tonic-gate 				error_message(DUP_ERROR, IPSEC_CONF_SRC_PORT,
44677c478bd9Sstevel@tonic-gate 				    line_no);
44687c478bd9Sstevel@tonic-gate 				return (-1);
44697c478bd9Sstevel@tonic-gate 			}
44707c478bd9Sstevel@tonic-gate 			i++, line_no++;
44717c478bd9Sstevel@tonic-gate 			if (act_props->pattern[i] == NULL) {
44727c478bd9Sstevel@tonic-gate 				error_message(BAD_ERROR, IPSEC_CONF_SRC_PORT,
44737c478bd9Sstevel@tonic-gate 				    line_no);
44747c478bd9Sstevel@tonic-gate 				return (-1);
44757c478bd9Sstevel@tonic-gate 			}
44767c478bd9Sstevel@tonic-gate 			ret = parse_port(IPSEC_CONF_SRC_PORT,
44777c478bd9Sstevel@tonic-gate 			    act_props->pattern[i],
44787c478bd9Sstevel@tonic-gate 			    cptr);
44797c478bd9Sstevel@tonic-gate 			if (ret != 0) {
44807c478bd9Sstevel@tonic-gate 				error_message(BAD_ERROR, IPSEC_CONF_SRC_PORT,
44817c478bd9Sstevel@tonic-gate 				    line_no);
44827c478bd9Sstevel@tonic-gate 				return (-1);
44837c478bd9Sstevel@tonic-gate 			}
44847c478bd9Sstevel@tonic-gate 			break;
44857c478bd9Sstevel@tonic-gate 
44867c478bd9Sstevel@tonic-gate 		case TOK_rport:
44877c478bd9Sstevel@tonic-gate 			if (old_style) {
44887c478bd9Sstevel@tonic-gate 				error_message(BAD_ERROR,
44897c478bd9Sstevel@tonic-gate 				    IPSEC_CONF_DST_PORT, line_no);
44907c478bd9Sstevel@tonic-gate 				return (-1);
44917c478bd9Sstevel@tonic-gate 			}
44927c478bd9Sstevel@tonic-gate 			new_style = B_TRUE;
44937c478bd9Sstevel@tonic-gate 
44947c478bd9Sstevel@tonic-gate 			if (cptr->ips_dst_port_min != 0) {
44957c478bd9Sstevel@tonic-gate 				error_message(DUP_ERROR, IPSEC_CONF_DST_PORT,
44967c478bd9Sstevel@tonic-gate 				    line_no);
44977c478bd9Sstevel@tonic-gate 				return (-1);
44987c478bd9Sstevel@tonic-gate 			}
44997c478bd9Sstevel@tonic-gate 			i++, line_no++;
45007c478bd9Sstevel@tonic-gate 			if (act_props->pattern[i] == NULL) {
45017c478bd9Sstevel@tonic-gate 				error_message(BAD_ERROR, IPSEC_CONF_DST_PORT,
45027c478bd9Sstevel@tonic-gate 				    line_no);
45037c478bd9Sstevel@tonic-gate 				return (-1);
45047c478bd9Sstevel@tonic-gate 			}
45057c478bd9Sstevel@tonic-gate 			ret = parse_port(IPSEC_CONF_DST_PORT,
45067c478bd9Sstevel@tonic-gate 			    act_props->pattern[i],
45077c478bd9Sstevel@tonic-gate 			    cptr);
45087c478bd9Sstevel@tonic-gate 			if (ret != 0) {
45097c478bd9Sstevel@tonic-gate 				error_message(BAD_ERROR, IPSEC_CONF_DST_PORT,
45107c478bd9Sstevel@tonic-gate 				    line_no);
45117c478bd9Sstevel@tonic-gate 				return (-1);
45127c478bd9Sstevel@tonic-gate 			}
45137c478bd9Sstevel@tonic-gate 			break;
45147c478bd9Sstevel@tonic-gate 
45157c478bd9Sstevel@tonic-gate 		case TOK_smask:
45167c478bd9Sstevel@tonic-gate 			if (new_style) {
45177c478bd9Sstevel@tonic-gate 				error_message(BAD_ERROR,
45187c478bd9Sstevel@tonic-gate 				    IPSEC_CONF_SRC_MASK, line_no);
45197c478bd9Sstevel@tonic-gate 				return (-1);
45207c478bd9Sstevel@tonic-gate 			}
45217c478bd9Sstevel@tonic-gate 			old_style = B_TRUE;
45227c478bd9Sstevel@tonic-gate 			cptr->has_smask = B_TRUE;
45237c478bd9Sstevel@tonic-gate 
45247c478bd9Sstevel@tonic-gate 			IN6_V4MAPPED_TO_INADDR(&cptr->ips_src_mask_v6, &mask);
45257c478bd9Sstevel@tonic-gate 			if (mask.s_addr != 0) {
45267c478bd9Sstevel@tonic-gate 				error_message(DUP_ERROR, IPSEC_CONF_SRC_MASK,
45277c478bd9Sstevel@tonic-gate 				    line_no);
45287c478bd9Sstevel@tonic-gate 				return (-1);
45297c478bd9Sstevel@tonic-gate 			}
45307c478bd9Sstevel@tonic-gate 			i++, line_no++;
45317c478bd9Sstevel@tonic-gate 			if (act_props->pattern[i] == NULL) {
45327c478bd9Sstevel@tonic-gate 				error_message(BAD_ERROR, IPSEC_CONF_SRC_MASK,
45337c478bd9Sstevel@tonic-gate 				    line_no);
45347c478bd9Sstevel@tonic-gate 				return (-1);
45357c478bd9Sstevel@tonic-gate 			}
45367c478bd9Sstevel@tonic-gate 			ret = parse_mask(IPSEC_CONF_SRC_MASK,
45377c478bd9Sstevel@tonic-gate 			    act_props->pattern[i],
45387c478bd9Sstevel@tonic-gate 			    cptr);
45397c478bd9Sstevel@tonic-gate 			if (ret != 0) {
45407c478bd9Sstevel@tonic-gate 				error_message(BAD_ERROR, IPSEC_CONF_SRC_MASK,
45417c478bd9Sstevel@tonic-gate 				    line_no);
45427c478bd9Sstevel@tonic-gate 				return (-1);
45437c478bd9Sstevel@tonic-gate 			}
45447c478bd9Sstevel@tonic-gate 			break;
45457c478bd9Sstevel@tonic-gate 		case TOK_dmask:
45467c478bd9Sstevel@tonic-gate 			if (new_style) {
45477c478bd9Sstevel@tonic-gate 				error_message(BAD_ERROR,
45487c478bd9Sstevel@tonic-gate 				    IPSEC_CONF_DST_MASK, line_no);
45497c478bd9Sstevel@tonic-gate 				return (-1);
45507c478bd9Sstevel@tonic-gate 			}
45517c478bd9Sstevel@tonic-gate 			old_style = B_TRUE;
45527c478bd9Sstevel@tonic-gate 			cptr->has_dmask = B_TRUE;
45537c478bd9Sstevel@tonic-gate 
45547c478bd9Sstevel@tonic-gate 			IN6_V4MAPPED_TO_INADDR(&cptr->ips_dst_mask_v6, &mask);
45557c478bd9Sstevel@tonic-gate 			if (mask.s_addr != 0) {
45567c478bd9Sstevel@tonic-gate 				error_message(DUP_ERROR, IPSEC_CONF_DST_MASK,
45577c478bd9Sstevel@tonic-gate 				    line_no);
45587c478bd9Sstevel@tonic-gate 				return (-1);
45597c478bd9Sstevel@tonic-gate 			}
45607c478bd9Sstevel@tonic-gate 			i++, line_no++;
45617c478bd9Sstevel@tonic-gate 			if (act_props->pattern[i] == NULL) {
45627c478bd9Sstevel@tonic-gate 				error_message(BAD_ERROR, IPSEC_CONF_DST_MASK,
45637c478bd9Sstevel@tonic-gate 				    line_no);
45647c478bd9Sstevel@tonic-gate 				return (-1);
45657c478bd9Sstevel@tonic-gate 			}
45667c478bd9Sstevel@tonic-gate 			ret = parse_mask(IPSEC_CONF_DST_MASK,
45677c478bd9Sstevel@tonic-gate 			    act_props->pattern[i],
45687c478bd9Sstevel@tonic-gate 			    cptr);
45697c478bd9Sstevel@tonic-gate 			if (ret != 0) {
45707c478bd9Sstevel@tonic-gate 				error_message(BAD_ERROR, IPSEC_CONF_DST_MASK,
45717c478bd9Sstevel@tonic-gate 				    line_no);
45727c478bd9Sstevel@tonic-gate 				return (-1);
45737c478bd9Sstevel@tonic-gate 			}
45747c478bd9Sstevel@tonic-gate 			break;
45757c478bd9Sstevel@tonic-gate 		case TOK_ulp:
45767c478bd9Sstevel@tonic-gate 			if (cptr->ips_ulp_prot != 0) {
45777c478bd9Sstevel@tonic-gate 				error_message(DUP_ERROR,
45787c478bd9Sstevel@tonic-gate 				    IPSEC_CONF_ULP, line_no);
45797c478bd9Sstevel@tonic-gate 				return (-1);
45807c478bd9Sstevel@tonic-gate 			}
45817c478bd9Sstevel@tonic-gate 			i++, line_no++;
45827c478bd9Sstevel@tonic-gate 			if (act_props->pattern[i] == NULL) {
45837c478bd9Sstevel@tonic-gate 				error_message(BAD_ERROR,
45847c478bd9Sstevel@tonic-gate 				    IPSEC_CONF_ULP, line_no);
45857c478bd9Sstevel@tonic-gate 				return (-1);
45867c478bd9Sstevel@tonic-gate 			}
45877c478bd9Sstevel@tonic-gate 			pent = getprotobyname(act_props->pattern[i]);
45887c478bd9Sstevel@tonic-gate 			if (pent == NULL) {
45897c478bd9Sstevel@tonic-gate 				int ulp;
45907c478bd9Sstevel@tonic-gate 				ulp = parse_int(act_props->pattern[i]);
45917c478bd9Sstevel@tonic-gate 				if (ulp == -1) {
45927c478bd9Sstevel@tonic-gate 					error_message(BAD_ERROR,
45937c478bd9Sstevel@tonic-gate 					    IPSEC_CONF_ULP, line_no);
45947c478bd9Sstevel@tonic-gate 					return (-1);
45957c478bd9Sstevel@tonic-gate 				}
45967c478bd9Sstevel@tonic-gate 				cptr->ips_ulp_prot = ulp;
45977c478bd9Sstevel@tonic-gate 			} else {
45987c478bd9Sstevel@tonic-gate 				cptr->ips_ulp_prot = pent->p_proto;
45997c478bd9Sstevel@tonic-gate 			}
46007c478bd9Sstevel@tonic-gate 			break;
46017c478bd9Sstevel@tonic-gate 		case TOK_type:
46027c478bd9Sstevel@tonic-gate 			if (cptr->has_type) {
46037c478bd9Sstevel@tonic-gate 				error_message(DUP_ERROR,
46047c478bd9Sstevel@tonic-gate 				    IPSEC_CONF_ICMP_TYPE, line_no);
46057c478bd9Sstevel@tonic-gate 				return (-1);
46067c478bd9Sstevel@tonic-gate 			}
46077c478bd9Sstevel@tonic-gate 
46087c478bd9Sstevel@tonic-gate 			i++, line_no++;
46097c478bd9Sstevel@tonic-gate 			type = parse_type_code(act_props->pattern[i],
46107c478bd9Sstevel@tonic-gate 			    icmp_type_table);
46117c478bd9Sstevel@tonic-gate 
46127c478bd9Sstevel@tonic-gate 			if (type > 65536 || type < 0) {
46137c478bd9Sstevel@tonic-gate 				error_message(BAD_ERROR,
46147c478bd9Sstevel@tonic-gate 				    IPSEC_CONF_ICMP_TYPE, line_no);
46157c478bd9Sstevel@tonic-gate 				return (-1);
46167c478bd9Sstevel@tonic-gate 			}
46177c478bd9Sstevel@tonic-gate 
46187c478bd9Sstevel@tonic-gate 			type_end = type / 256;
46197c478bd9Sstevel@tonic-gate 			type = type % 256;
46207c478bd9Sstevel@tonic-gate 
46217c478bd9Sstevel@tonic-gate 			if (type_end < type)
46227c478bd9Sstevel@tonic-gate 				type_end = type;
46237c478bd9Sstevel@tonic-gate 
46247c478bd9Sstevel@tonic-gate 			cptr->has_type = 1;
46257c478bd9Sstevel@tonic-gate 			cptr->ips_icmp_type = (uint8_t)type;
46267c478bd9Sstevel@tonic-gate 			cptr->ips_icmp_type_end = (uint8_t)type_end;
46277c478bd9Sstevel@tonic-gate 			break;
46287c478bd9Sstevel@tonic-gate 		case TOK_code:
46297c478bd9Sstevel@tonic-gate 			if (!cptr->has_type) {
46307c478bd9Sstevel@tonic-gate 				error_message(BAD_ERROR,
46317c478bd9Sstevel@tonic-gate 				    IPSEC_CONF_ICMP_CODE, line_no);
46327c478bd9Sstevel@tonic-gate 				return (-1);
46337c478bd9Sstevel@tonic-gate 			}
46347c478bd9Sstevel@tonic-gate 
46357c478bd9Sstevel@tonic-gate 			if (cptr->has_code) {
46367c478bd9Sstevel@tonic-gate 				error_message(DUP_ERROR,
46377c478bd9Sstevel@tonic-gate 				    IPSEC_CONF_ICMP_CODE, line_no);
46387c478bd9Sstevel@tonic-gate 				return (-1);
46397c478bd9Sstevel@tonic-gate 			}
46407c478bd9Sstevel@tonic-gate 
46417c478bd9Sstevel@tonic-gate 			i++, line_no++;
46427c478bd9Sstevel@tonic-gate 
46437c478bd9Sstevel@tonic-gate 			code = parse_type_code(act_props->pattern[i],
46447c478bd9Sstevel@tonic-gate 			    icmp_code_table);
46457c478bd9Sstevel@tonic-gate 			if (type > 65536 || type < 0) {
46467c478bd9Sstevel@tonic-gate 				error_message(BAD_ERROR,
46477c478bd9Sstevel@tonic-gate 				    IPSEC_CONF_ICMP_CODE, line_no);
46487c478bd9Sstevel@tonic-gate 				return (-1);
46497c478bd9Sstevel@tonic-gate 			}
46507c478bd9Sstevel@tonic-gate 			code_end = code / 256;
46517c478bd9Sstevel@tonic-gate 			code = code % 256;
46527c478bd9Sstevel@tonic-gate 
46537c478bd9Sstevel@tonic-gate 			if (code_end < code)
46547c478bd9Sstevel@tonic-gate 				code_end = code;
46557c478bd9Sstevel@tonic-gate 
46567c478bd9Sstevel@tonic-gate 			cptr->has_code = 1;
46577c478bd9Sstevel@tonic-gate 			cptr->ips_icmp_code = (uint8_t)code;
46587c478bd9Sstevel@tonic-gate 			cptr->ips_icmp_code_end = (uint8_t)code_end;
46597c478bd9Sstevel@tonic-gate 			break;
46608810c16bSdanmcd 		case TOK_tunnel:
46618810c16bSdanmcd 			if (cptr->has_tunnel == 1) {
46628810c16bSdanmcd 				error_message(BAD_ERROR,
46638810c16bSdanmcd 				    IPSEC_CONF_TUNNEL, line_no);
46648810c16bSdanmcd 				return (-1);
46658810c16bSdanmcd 			}
46668810c16bSdanmcd 			i++, line_no++;
46678810c16bSdanmcd 			if (act_props->pattern[i] == NULL) {
46688810c16bSdanmcd 				error_message(BAD_ERROR,
46698810c16bSdanmcd 				    IPSEC_CONF_TUNNEL, line_no);
46708810c16bSdanmcd 				return (-1);
46718810c16bSdanmcd 			}
46728810c16bSdanmcd 
46738810c16bSdanmcd 			if (strlcpy(tunif, act_props->pattern[i],
46748810c16bSdanmcd 			    TUNNAMEMAXLEN) >= TUNNAMEMAXLEN) {
46758810c16bSdanmcd 				error_message(BAD_ERROR,
46768810c16bSdanmcd 				    IPSEC_CONF_TUNNEL, line_no);
46778810c16bSdanmcd 				return (-1);
46788810c16bSdanmcd 			}
46798810c16bSdanmcd 			cptr->has_tunnel = 1;
46808810c16bSdanmcd 			break;
46818810c16bSdanmcd 		case TOK_negotiate:
46828810c16bSdanmcd 			if (cptr->has_negotiate == 1) {
46838810c16bSdanmcd 				error_message(BAD_ERROR,
46848810c16bSdanmcd 				    IPSEC_CONF_NEGOTIATE, line_no);
46858810c16bSdanmcd 				return (-1);
46868810c16bSdanmcd 			}
46878810c16bSdanmcd 			i++, line_no++;
46888810c16bSdanmcd 			if (act_props->pattern[i] == NULL) {
46898810c16bSdanmcd 				error_message(BAD_ERROR,
46908810c16bSdanmcd 				    IPSEC_CONF_NEGOTIATE, line_no);
46918810c16bSdanmcd 				return (-1);
46928810c16bSdanmcd 			}
46938810c16bSdanmcd 
46948810c16bSdanmcd 			if (strncmp(act_props->pattern[i], "tunnel", 6) == 0) {
46958810c16bSdanmcd 				cptr->ips_tunnel = B_TRUE;
46968810c16bSdanmcd 			} else if (strncmp(
46978810c16bSdanmcd 			    act_props->pattern[i], "transport", 9) != 0) {
46988810c16bSdanmcd 				error_message(BAD_ERROR,
46998810c16bSdanmcd 				    IPSEC_CONF_NEGOTIATE, line_no);
47008810c16bSdanmcd 				return (-1);
47018810c16bSdanmcd 			}
47028810c16bSdanmcd 			cptr->has_negotiate = 1;
47038810c16bSdanmcd 			break;
47047c478bd9Sstevel@tonic-gate 		}
47058810c16bSdanmcd 
47068810c16bSdanmcd 	}
47078810c16bSdanmcd 
47088810c16bSdanmcd 	/* Sanity check that certain tokens occur together */
47098810c16bSdanmcd 	if (cptr->has_tunnel + cptr->has_negotiate == 1) {
47108810c16bSdanmcd 		if (cptr->has_negotiate == 0) {
47118810c16bSdanmcd 			error_message(REQ_ERROR, IPSEC_CONF_NEGOTIATE, line_no);
47128810c16bSdanmcd 		} else {
47138810c16bSdanmcd 			error_message(REQ_ERROR, IPSEC_CONF_TUNNEL, line_no);
47148810c16bSdanmcd 		}
47158810c16bSdanmcd 		errx(1, gettext(
47168810c16bSdanmcd 		    "tunnel and negotiate tokens must occur together"));
47178810c16bSdanmcd 		return (-1);
47187c478bd9Sstevel@tonic-gate 	}
47197c478bd9Sstevel@tonic-gate 
47207c478bd9Sstevel@tonic-gate 	/*
47217c478bd9Sstevel@tonic-gate 	 * Get the actions.
47227c478bd9Sstevel@tonic-gate 	 */
47237c478bd9Sstevel@tonic-gate 
47247c478bd9Sstevel@tonic-gate 	for (ap_num = 0; act_props->ap[ap_num].act != NULL; ap_num++) {
47257c478bd9Sstevel@tonic-gate 		ips_act_props_t *iap;
47267c478bd9Sstevel@tonic-gate 
47277c478bd9Sstevel@tonic-gate 		if (ap_num > 0) {
47287c478bd9Sstevel@tonic-gate 			/* or's only with new style */
47297c478bd9Sstevel@tonic-gate 			if (old_style) {
47307c478bd9Sstevel@tonic-gate 				(void) printf("%s\n", gettext(
47317c478bd9Sstevel@tonic-gate 				    "or's only with new style"));
47327c478bd9Sstevel@tonic-gate 				return (-1);
47337c478bd9Sstevel@tonic-gate 			}
47347c478bd9Sstevel@tonic-gate 			new_style = B_TRUE;
47357c478bd9Sstevel@tonic-gate 		}
47367c478bd9Sstevel@tonic-gate 
47377c478bd9Sstevel@tonic-gate 		ipsec_aalg = ipsec_ealg = ipsec_eaalg = B_FALSE;
47387c478bd9Sstevel@tonic-gate 		tok_count = 0;
47397c478bd9Sstevel@tonic-gate 
47407c478bd9Sstevel@tonic-gate 		for (k = 0; action_table[k].string; k++) {
47417c478bd9Sstevel@tonic-gate 			if (strcmp(act_props->ap[ap_num].act,
47427c478bd9Sstevel@tonic-gate 			    action_table[k].string) == 0)
47437c478bd9Sstevel@tonic-gate 				break;
47447c478bd9Sstevel@tonic-gate 		}
47457c478bd9Sstevel@tonic-gate 		/*
47467c478bd9Sstevel@tonic-gate 		 * The following thing should never happen as
47477c478bd9Sstevel@tonic-gate 		 * we have already tested for its validity in parse.
47487c478bd9Sstevel@tonic-gate 		 */
47497c478bd9Sstevel@tonic-gate 		if (action_table[k].string == NULL) {
47507c478bd9Sstevel@tonic-gate 			warnx(gettext("(form act)Invalid action on line "
47517c478bd9Sstevel@tonic-gate 			    "%d: %s"), (arg_indices[line_no] == 0) ? 1 :
47527c478bd9Sstevel@tonic-gate 			    arg_indices[line_no],
47537c478bd9Sstevel@tonic-gate 			    act_props->ap[ap_num].act);
47547c478bd9Sstevel@tonic-gate 			warnx("%s", act_props->ap[ap_num].act);
47557c478bd9Sstevel@tonic-gate 			return (-1);
47567c478bd9Sstevel@tonic-gate 		}
47577c478bd9Sstevel@tonic-gate 
47587c478bd9Sstevel@tonic-gate 		/* we have a good action alloc an iap */
47597c478bd9Sstevel@tonic-gate 		iap = alloc_iap(cptr);
47607c478bd9Sstevel@tonic-gate 
47617c478bd9Sstevel@tonic-gate 		iap->iap_action = action_table[k].value;
47627c478bd9Sstevel@tonic-gate 		iap->iap_act_tok = action_table[k].tok_val;
47637c478bd9Sstevel@tonic-gate 
47647c478bd9Sstevel@tonic-gate 		switch (action_table[k].tok_val) {
47657c478bd9Sstevel@tonic-gate 		case TOK_apply:
47667c478bd9Sstevel@tonic-gate 			cptr->ips_dir = SPD_RULE_FLAG_OUTBOUND;
47677c478bd9Sstevel@tonic-gate 			break;
47687c478bd9Sstevel@tonic-gate 		case TOK_permit:
47697c478bd9Sstevel@tonic-gate 			cptr->ips_dir = SPD_RULE_FLAG_INBOUND;
47707c478bd9Sstevel@tonic-gate 			break;
47717c478bd9Sstevel@tonic-gate 		case TOK_ipsec:
4772eeda67c6Sjojemann 			if (old_style) {
4773eeda67c6Sjojemann 				/* Using saddr/daddr with ipsec action. */
4774eeda67c6Sjojemann 				if (!dir) {
4775eeda67c6Sjojemann 					/* No direction specified */
4776eeda67c6Sjojemann 					error_message(REQ_ERROR,
4777eeda67c6Sjojemann 					    IPSEC_CONF_IPSEC_DIR, line_no);
4778eeda67c6Sjojemann 					return (-1);
4779eeda67c6Sjojemann 				}
4780eeda67c6Sjojemann 				if (cptr->ips_dir == SPD_RULE_FLAG_INBOUND)
4781eeda67c6Sjojemann 					/*
4782eeda67c6Sjojemann 					 * Need to swap addresses if
4783eeda67c6Sjojemann 					 * 'dir in' or translation to
4784eeda67c6Sjojemann 					 * laddr/raddr will be incorrect.
4785eeda67c6Sjojemann 					 */
4786eeda67c6Sjojemann 					cptr->swap = 1;
4787eeda67c6Sjojemann 			}
47887c478bd9Sstevel@tonic-gate 			if (!dir)
47897c478bd9Sstevel@tonic-gate 				cptr->ips_dir =
47907c478bd9Sstevel@tonic-gate 				    SPD_RULE_FLAG_INBOUND
47917c478bd9Sstevel@tonic-gate 				    |SPD_RULE_FLAG_OUTBOUND;
47927c478bd9Sstevel@tonic-gate 			break;
47937c478bd9Sstevel@tonic-gate 		case TOK_bypass:
47947c478bd9Sstevel@tonic-gate 			/* do something? */
47957c478bd9Sstevel@tonic-gate 			break;
47967c478bd9Sstevel@tonic-gate 		}
47977c478bd9Sstevel@tonic-gate 
47987c478bd9Sstevel@tonic-gate 		line_no++;
47997c478bd9Sstevel@tonic-gate 		/*
48007c478bd9Sstevel@tonic-gate 		 * Get the properties. NULL properties is not valid.
48017c478bd9Sstevel@tonic-gate 		 * Later checks will catch it.
48027c478bd9Sstevel@tonic-gate 		 */
48037c478bd9Sstevel@tonic-gate 		for (i = 0; act_props->ap[ap_num].prop[i]; i++, line_no++) {
48047c478bd9Sstevel@tonic-gate 			for (j = 0; property_table[j].string; j++) {
48057c478bd9Sstevel@tonic-gate 				if (strcmp(act_props->ap[ap_num].prop[i],
48067c478bd9Sstevel@tonic-gate 				    property_table[j].string) == 0) {
48077c478bd9Sstevel@tonic-gate 					break;
48087c478bd9Sstevel@tonic-gate 				}
48097c478bd9Sstevel@tonic-gate 			}
48107c478bd9Sstevel@tonic-gate 			if (property_table[j].string == NULL) {
48117c478bd9Sstevel@tonic-gate 				warnx(gettext("Invalid properties on line "
48127c478bd9Sstevel@tonic-gate 				    "%d: %s"),
4813d5751483Smarkfen 				    (arg_indices[line_no] == 0) ?
48147c478bd9Sstevel@tonic-gate 				    1 : arg_indices[line_no],
48157c478bd9Sstevel@tonic-gate 				    act_props->ap[ap_num].prop[i]);
48167c478bd9Sstevel@tonic-gate 				return (-1);
48177c478bd9Sstevel@tonic-gate 			}
48187c478bd9Sstevel@tonic-gate 
48197c478bd9Sstevel@tonic-gate 			iap->iap_attr_tok[tok_count++]
48207c478bd9Sstevel@tonic-gate 			    = property_table[j].value;
48217c478bd9Sstevel@tonic-gate 
48227c478bd9Sstevel@tonic-gate 			switch (property_table[j].value) {
48237c478bd9Sstevel@tonic-gate 			case SPD_ATTR_AH_AUTH:
48247c478bd9Sstevel@tonic-gate 				if (ipsec_aalg) {
48257c478bd9Sstevel@tonic-gate 					error_message(DUP_ERROR,
48267c478bd9Sstevel@tonic-gate 					    IPSEC_CONF_IPSEC_AALGS, line_no);
48277c478bd9Sstevel@tonic-gate 					return (-1);
48287c478bd9Sstevel@tonic-gate 				}
48297c478bd9Sstevel@tonic-gate 				i++, line_no++;
48307c478bd9Sstevel@tonic-gate 				if (act_props->ap[ap_num].prop[i] == NULL) {
48317c478bd9Sstevel@tonic-gate 					error_message(BAD_ERROR,
48327c478bd9Sstevel@tonic-gate 					    IPSEC_CONF_IPSEC_AALGS, line_no);
48337c478bd9Sstevel@tonic-gate 					return (-1);
48347c478bd9Sstevel@tonic-gate 				}
48357c478bd9Sstevel@tonic-gate 				ret = parse_ipsec_alg(
48367c478bd9Sstevel@tonic-gate 				    act_props->ap[ap_num].prop[i],
48377c478bd9Sstevel@tonic-gate 				    iap, SPD_ATTR_AH_AUTH);
4838c758f97fSpwernau 				if (ret == -2) {
4839c758f97fSpwernau 					/* "none" - ignore */
4840c758f97fSpwernau 					break;
4841c758f97fSpwernau 				}
48427c478bd9Sstevel@tonic-gate 				if (ret != 0) {
48437c478bd9Sstevel@tonic-gate 					error_message(BAD_ERROR,
48447c478bd9Sstevel@tonic-gate 					    IPSEC_CONF_IPSEC_AALGS, line_no);
48457c478bd9Sstevel@tonic-gate 					return (-1);
48467c478bd9Sstevel@tonic-gate 				}
48477c478bd9Sstevel@tonic-gate 				ipsec_aalg = B_TRUE;
48487c478bd9Sstevel@tonic-gate 				break;
48497c478bd9Sstevel@tonic-gate 			case SPD_ATTR_ESP_ENCR:
48507c478bd9Sstevel@tonic-gate 				/*
48517c478bd9Sstevel@tonic-gate 				 * If this option was not given
48527c478bd9Sstevel@tonic-gate 				 * and encr_auth_algs was given,
48537c478bd9Sstevel@tonic-gate 				 * we provide null-encryption.  We do the
48547c478bd9Sstevel@tonic-gate 				 * setting after we parse all the options.
48557c478bd9Sstevel@tonic-gate 				 */
48567c478bd9Sstevel@tonic-gate 				if (ipsec_ealg) {
48577c478bd9Sstevel@tonic-gate 					error_message(DUP_ERROR,
48587c478bd9Sstevel@tonic-gate 					    IPSEC_CONF_IPSEC_EALGS, line_no);
48597c478bd9Sstevel@tonic-gate 					return (-1);
48607c478bd9Sstevel@tonic-gate 				}
48617c478bd9Sstevel@tonic-gate 				i++, line_no++;
48627c478bd9Sstevel@tonic-gate 				if (act_props->ap[ap_num].prop[i] == NULL) {
48637c478bd9Sstevel@tonic-gate 					error_message(BAD_ERROR,
48647c478bd9Sstevel@tonic-gate 					    IPSEC_CONF_IPSEC_EALGS, line_no);
48657c478bd9Sstevel@tonic-gate 					return (-1);
48667c478bd9Sstevel@tonic-gate 				}
48677c478bd9Sstevel@tonic-gate 				ret = parse_ipsec_alg(
48687c478bd9Sstevel@tonic-gate 				    act_props->ap[ap_num].prop[i],
48697c478bd9Sstevel@tonic-gate 				    iap, SPD_ATTR_ESP_ENCR);
4870c758f97fSpwernau 				if (ret == -2) {
4871c758f97fSpwernau 					/* "none" - ignore */
4872c758f97fSpwernau 					break;
4873c758f97fSpwernau 				}
48747c478bd9Sstevel@tonic-gate 				if (ret != 0) {
48757c478bd9Sstevel@tonic-gate 					error_message(BAD_ERROR,
48767c478bd9Sstevel@tonic-gate 					    IPSEC_CONF_IPSEC_EALGS, line_no);
48777c478bd9Sstevel@tonic-gate 					return (-1);
48787c478bd9Sstevel@tonic-gate 				}
48797c478bd9Sstevel@tonic-gate 				ipsec_ealg = B_TRUE;
48807c478bd9Sstevel@tonic-gate 				break;
48817c478bd9Sstevel@tonic-gate 			case SPD_ATTR_ESP_AUTH:
48827c478bd9Sstevel@tonic-gate 				/*
48837c478bd9Sstevel@tonic-gate 				 * If this option was not given and encr_algs
48847c478bd9Sstevel@tonic-gate 				 * option was given, we still pass a default
48857c478bd9Sstevel@tonic-gate 				 * value in ipsc_esp_auth_algs. This is to
48867c478bd9Sstevel@tonic-gate 				 * encourage the use of authentication with
48877c478bd9Sstevel@tonic-gate 				 * ESP.
48887c478bd9Sstevel@tonic-gate 				 */
48897c478bd9Sstevel@tonic-gate 				if (ipsec_eaalg) {
48907c478bd9Sstevel@tonic-gate 					error_message(DUP_ERROR,
48917c478bd9Sstevel@tonic-gate 					    IPSEC_CONF_IPSEC_EAALGS, line_no);
48927c478bd9Sstevel@tonic-gate 					return (-1);
48937c478bd9Sstevel@tonic-gate 				}
48947c478bd9Sstevel@tonic-gate 				i++, line_no++;
48957c478bd9Sstevel@tonic-gate 				if (act_props->ap[ap_num].prop[i] == NULL) {
48967c478bd9Sstevel@tonic-gate 					error_message(BAD_ERROR,
48977c478bd9Sstevel@tonic-gate 					    IPSEC_CONF_IPSEC_EAALGS, line_no);
48987c478bd9Sstevel@tonic-gate 					return (-1);
48997c478bd9Sstevel@tonic-gate 				}
49007c478bd9Sstevel@tonic-gate 				ret = parse_ipsec_alg(
49017c478bd9Sstevel@tonic-gate 				    act_props->ap[ap_num].prop[i],
49027c478bd9Sstevel@tonic-gate 				    iap, SPD_ATTR_ESP_AUTH);
4903c758f97fSpwernau 				if (ret == -2) {
4904c758f97fSpwernau 					/* "none" - ignore */
4905c758f97fSpwernau 					break;
4906c758f97fSpwernau 				}
49077c478bd9Sstevel@tonic-gate 				if (ret != 0) {
49087c478bd9Sstevel@tonic-gate 					error_message(BAD_ERROR,
49097c478bd9Sstevel@tonic-gate 					    IPSEC_CONF_IPSEC_EAALGS, line_no);
49107c478bd9Sstevel@tonic-gate 					return (-1);
49117c478bd9Sstevel@tonic-gate 				}
49127c478bd9Sstevel@tonic-gate 				ipsec_eaalg = B_TRUE;
49137c478bd9Sstevel@tonic-gate 				break;
49147c478bd9Sstevel@tonic-gate 			case IPS_SA:
49157c478bd9Sstevel@tonic-gate 				i++, line_no++;
49167c478bd9Sstevel@tonic-gate 				if (act_props->ap[ap_num].prop[i] == NULL) {
49177c478bd9Sstevel@tonic-gate 					error_message(BAD_ERROR,
49187c478bd9Sstevel@tonic-gate 					    IPSEC_CONF_IPSEC_SA, line_no);
49197c478bd9Sstevel@tonic-gate 					return (-1);
49207c478bd9Sstevel@tonic-gate 				}
49217c478bd9Sstevel@tonic-gate 
49227c478bd9Sstevel@tonic-gate 				if (strcmp(act_props->ap[ap_num].prop[i],
49237c478bd9Sstevel@tonic-gate 				    "unique") == 0) {
49247c478bd9Sstevel@tonic-gate 					iap->iap_attr |= SPD_APPLY_UNIQUE;
49257c478bd9Sstevel@tonic-gate 				} else if (strcmp(act_props->ap[ap_num].prop[i],
49267c478bd9Sstevel@tonic-gate 				    "shared") != 0) {
49277c478bd9Sstevel@tonic-gate 					/* "shared" is default. */
49287c478bd9Sstevel@tonic-gate 					error_message(BAD_ERROR,
49297c478bd9Sstevel@tonic-gate 					    IPSEC_CONF_IPSEC_SA, line_no);
49307c478bd9Sstevel@tonic-gate 					return (-1);
49317c478bd9Sstevel@tonic-gate 				}
49327c478bd9Sstevel@tonic-gate 
49337c478bd9Sstevel@tonic-gate 				break;
49347c478bd9Sstevel@tonic-gate 			case IPS_DIR:
49357c478bd9Sstevel@tonic-gate 				if (dir) {
49367c478bd9Sstevel@tonic-gate 					error_message(DUP_ERROR,
49377c478bd9Sstevel@tonic-gate 					    IPSEC_CONF_IPSEC_DIR, line_no);
49387c478bd9Sstevel@tonic-gate 					return (-1);
49397c478bd9Sstevel@tonic-gate 				}
49407c478bd9Sstevel@tonic-gate 				if (new_style) {
49417c478bd9Sstevel@tonic-gate 					error_message(BAD_ERROR,
49427c478bd9Sstevel@tonic-gate 					    IPSEC_CONF_IPSEC_DIR, line_no);
49437c478bd9Sstevel@tonic-gate 					return (-1);
49447c478bd9Sstevel@tonic-gate 				}
49457c478bd9Sstevel@tonic-gate 				old_style = B_TRUE;
49467c478bd9Sstevel@tonic-gate 				dir = B_TRUE;
49477c478bd9Sstevel@tonic-gate 				i++, line_no++;
49487c478bd9Sstevel@tonic-gate 				if (act_props->ap[ap_num].prop[i] == NULL) {
49497c478bd9Sstevel@tonic-gate 					error_message(BAD_ERROR,
49507c478bd9Sstevel@tonic-gate 					    IPSEC_CONF_IPSEC_DIR, line_no);
49517c478bd9Sstevel@tonic-gate 					return (-1);
49527c478bd9Sstevel@tonic-gate 				}
49537c478bd9Sstevel@tonic-gate 				if (strcmp(act_props->ap[ap_num].prop[i],
49547c478bd9Sstevel@tonic-gate 				    "out") == 0) {
49557c478bd9Sstevel@tonic-gate 					cptr->ips_dir = SPD_RULE_FLAG_OUTBOUND;
49567c478bd9Sstevel@tonic-gate 				} else if (strcmp(act_props->ap[ap_num].prop[i],
49577c478bd9Sstevel@tonic-gate 				    "in") == 0) {
49587c478bd9Sstevel@tonic-gate 					cptr->ips_dir = SPD_RULE_FLAG_INBOUND;
49597c478bd9Sstevel@tonic-gate 				} else {
49607c478bd9Sstevel@tonic-gate 					error_message(BAD_ERROR,
4961d5751483Smarkfen 					    IPSEC_CONF_IPSEC_DIR, line_no);
49627c478bd9Sstevel@tonic-gate 					return (-1);
49637c478bd9Sstevel@tonic-gate 				}
49647c478bd9Sstevel@tonic-gate 				if ((cptr->ips_dir & SPD_RULE_FLAG_INBOUND) &&
4965d5751483Smarkfen 				    iap->iap_act_tok == TOK_apply) {
49667c478bd9Sstevel@tonic-gate 					warnx(gettext("Direction"
49677c478bd9Sstevel@tonic-gate 					    " in conflict with action"));
49687c478bd9Sstevel@tonic-gate 					return (-1);
49697c478bd9Sstevel@tonic-gate 				}
49707c478bd9Sstevel@tonic-gate 				if ((cptr->ips_dir & SPD_RULE_FLAG_OUTBOUND) &&
4971d5751483Smarkfen 				    iap->iap_act_tok == TOK_permit) {
49727c478bd9Sstevel@tonic-gate 					warnx(gettext("Direction"
49737c478bd9Sstevel@tonic-gate 					    "in conflict with action"));
49747c478bd9Sstevel@tonic-gate 					return (-1);
49757c478bd9Sstevel@tonic-gate 				}
49767c478bd9Sstevel@tonic-gate 
49777c478bd9Sstevel@tonic-gate 				break;
49787c478bd9Sstevel@tonic-gate 			}
49797c478bd9Sstevel@tonic-gate 		}
49807c478bd9Sstevel@tonic-gate 
49817c478bd9Sstevel@tonic-gate 		if (!ipsec_ealg && ipsec_eaalg) {
49827c478bd9Sstevel@tonic-gate 			/*
49837c478bd9Sstevel@tonic-gate 			 * If the user has specified the auth alg to be used
49847c478bd9Sstevel@tonic-gate 			 * with encryption and did not provide a encryption
49857c478bd9Sstevel@tonic-gate 			 * algorithm, provide null encryption.
49867c478bd9Sstevel@tonic-gate 			 */
49877c478bd9Sstevel@tonic-gate 			iap->iap_eencr.alg_id = SADB_EALG_NULL;
49887c478bd9Sstevel@tonic-gate 			ipsec_ealg = B_TRUE;
49897c478bd9Sstevel@tonic-gate 		}
49907c478bd9Sstevel@tonic-gate 
49917c478bd9Sstevel@tonic-gate 		/* Set the level of IPSEC protection we want */
49927c478bd9Sstevel@tonic-gate 		if (ipsec_aalg && (ipsec_ealg || ipsec_eaalg)) {
49937c478bd9Sstevel@tonic-gate 			iap->iap_attr |= SPD_APPLY_AH|SPD_APPLY_ESP;
49947c478bd9Sstevel@tonic-gate 		} else if (ipsec_aalg) {
49957c478bd9Sstevel@tonic-gate 			iap->iap_attr |= SPD_APPLY_AH;
49967c478bd9Sstevel@tonic-gate 		} else if (ipsec_ealg || ipsec_eaalg) {
49977c478bd9Sstevel@tonic-gate 			iap->iap_attr |= SPD_APPLY_ESP;
49987c478bd9Sstevel@tonic-gate 		}
49997c478bd9Sstevel@tonic-gate 
50007c478bd9Sstevel@tonic-gate 		/* convert src/dst to local/remote */
50017c478bd9Sstevel@tonic-gate 		if (!new_style) {
50027c478bd9Sstevel@tonic-gate 			switch (cptr->ips_acts->iap_act_tok) {
50037c478bd9Sstevel@tonic-gate 			case TOK_apply:
50047c478bd9Sstevel@tonic-gate 				/* outbound */
50057c478bd9Sstevel@tonic-gate 				/* src=local, dst=remote */
50067c478bd9Sstevel@tonic-gate 				/* this is ok. */
50077c478bd9Sstevel@tonic-gate 				break;
50087c478bd9Sstevel@tonic-gate 
50097c478bd9Sstevel@tonic-gate 			case TOK_permit:
50107c478bd9Sstevel@tonic-gate 				/* inbound */
50117c478bd9Sstevel@tonic-gate 				/* src=remote, dst=local */
50127c478bd9Sstevel@tonic-gate 				/* switch */
50137c478bd9Sstevel@tonic-gate 				cptr->swap = 1;
50147c478bd9Sstevel@tonic-gate 				break;
50157c478bd9Sstevel@tonic-gate 			case TOK_bypass:
50167c478bd9Sstevel@tonic-gate 			case TOK_drop:
50177c478bd9Sstevel@tonic-gate 				/* check the direction for what to do */
50187c478bd9Sstevel@tonic-gate 				if (cptr->ips_dir == SPD_RULE_FLAG_INBOUND)
50197c478bd9Sstevel@tonic-gate 					cptr->swap = 1;
50207c478bd9Sstevel@tonic-gate 				break;
50217c478bd9Sstevel@tonic-gate 			default:
50227c478bd9Sstevel@tonic-gate 				break;
50237c478bd9Sstevel@tonic-gate 			}
50247c478bd9Sstevel@tonic-gate 		}
50257c478bd9Sstevel@tonic-gate 		/* Validate the properties */
50267c478bd9Sstevel@tonic-gate 		if (ret = validate_properties(iap, dir,
50277c478bd9Sstevel@tonic-gate 		    (ipsec_aalg || ipsec_ealg || ipsec_eaalg))) {
50287c478bd9Sstevel@tonic-gate 			return (ret);
50297c478bd9Sstevel@tonic-gate 		}
50307c478bd9Sstevel@tonic-gate 	}
50317c478bd9Sstevel@tonic-gate 
50327c478bd9Sstevel@tonic-gate 	return (0);
50337c478bd9Sstevel@tonic-gate 
50347c478bd9Sstevel@tonic-gate }
50357c478bd9Sstevel@tonic-gate 
50367c478bd9Sstevel@tonic-gate static int
503743c889d3Smarkfen print_cmd_buf(FILE *fp, int error)
50387c478bd9Sstevel@tonic-gate {
50397c478bd9Sstevel@tonic-gate 	*(cbuf + cbuf_offset) = '\0';
50407c478bd9Sstevel@tonic-gate 
50417c478bd9Sstevel@tonic-gate 	if (fp == stderr) {
5042e3320f40Smarkfen 		if (error != EEXIST) {
5043e3320f40Smarkfen 			warnx(gettext("Malformed command (fatal):\n%s"), cbuf);
504443c889d3Smarkfen 			return (0);
504543c889d3Smarkfen 		}
5046e3320f40Smarkfen 		if (ipsecconf_qflag) {
5047e3320f40Smarkfen 			return (0);
50487c478bd9Sstevel@tonic-gate 		}
5049e3320f40Smarkfen 		warnx(gettext("Duplicate policy entry (ignored):\n%s"), cbuf);
50507c478bd9Sstevel@tonic-gate 	} else {
50517c478bd9Sstevel@tonic-gate 		if (fprintf(fp, "%s", cbuf) == -1) {
50527c478bd9Sstevel@tonic-gate 			warn("fprintf");
50537c478bd9Sstevel@tonic-gate 			return (-1);
50547c478bd9Sstevel@tonic-gate 		}
50557c478bd9Sstevel@tonic-gate 	}
50567c478bd9Sstevel@tonic-gate 
50577c478bd9Sstevel@tonic-gate 	return (0);
50587c478bd9Sstevel@tonic-gate }
50597c478bd9Sstevel@tonic-gate 
50607c478bd9Sstevel@tonic-gate #ifdef	DEBUG
50617c478bd9Sstevel@tonic-gate 
50627c478bd9Sstevel@tonic-gate static uchar_t *
50637c478bd9Sstevel@tonic-gate addr_ptr(int isv4, struct in6_addr *addr6, struct in_addr *addr4)
50647c478bd9Sstevel@tonic-gate {
50657c478bd9Sstevel@tonic-gate 	if (isv4) {
50667c478bd9Sstevel@tonic-gate 		IN6_V4MAPPED_TO_INADDR(addr6, addr4);
50677c478bd9Sstevel@tonic-gate 		return ((uchar_t *)&addr4->s_addr);
50687c478bd9Sstevel@tonic-gate 	} else {
50697c478bd9Sstevel@tonic-gate 		return ((uchar_t *)&addr6->s6_addr);
50707c478bd9Sstevel@tonic-gate 	}
50717c478bd9Sstevel@tonic-gate }
50727c478bd9Sstevel@tonic-gate 
50737c478bd9Sstevel@tonic-gate static void
50747c478bd9Sstevel@tonic-gate dump_algreq(const char *tag, algreq_t *alg)
50757c478bd9Sstevel@tonic-gate {
50767c478bd9Sstevel@tonic-gate 	(void) printf("%s algid %d, bits %d..%d\n",
50777c478bd9Sstevel@tonic-gate 	    tag, alg->alg_id, alg->alg_minbits, alg->alg_maxbits);
50787c478bd9Sstevel@tonic-gate }
50797c478bd9Sstevel@tonic-gate 
50807c478bd9Sstevel@tonic-gate static void
50817c478bd9Sstevel@tonic-gate dump_conf(ips_conf_t *conf)
50827c478bd9Sstevel@tonic-gate {
50837c478bd9Sstevel@tonic-gate 	boolean_t isv4 = conf->ips_isv4;
50847c478bd9Sstevel@tonic-gate 	struct in_addr addr;
50857c478bd9Sstevel@tonic-gate 	char buf[INET6_ADDRSTRLEN];
50867c478bd9Sstevel@tonic-gate 	int af;
50877c478bd9Sstevel@tonic-gate 	ips_act_props_t *iap = conf->ips_acts;
50887c478bd9Sstevel@tonic-gate 
50897c478bd9Sstevel@tonic-gate 	af = isv4 ? AF_INET : AF_INET6;
50907c478bd9Sstevel@tonic-gate 
50917c478bd9Sstevel@tonic-gate 	(void) printf("Source Addr is %s\n",
50927c478bd9Sstevel@tonic-gate 	    inet_ntop(af, addr_ptr(isv4, &conf->ips_src_addr_v6, &addr),
5093d5751483Smarkfen 	    buf, INET6_ADDRSTRLEN));
50947c478bd9Sstevel@tonic-gate 
50957c478bd9Sstevel@tonic-gate 	(void) printf("Dest Addr is %s\n",
50967c478bd9Sstevel@tonic-gate 	    inet_ntop(af, addr_ptr(isv4, &conf->ips_dst_addr_v6, &addr),
5097d5751483Smarkfen 	    buf, INET6_ADDRSTRLEN));
50987c478bd9Sstevel@tonic-gate 
50997c478bd9Sstevel@tonic-gate 	(void) printf("Source Mask is %s\n",
51007c478bd9Sstevel@tonic-gate 	    inet_ntop(af, addr_ptr(isv4, &conf->ips_src_mask_v6, &addr),
5101d5751483Smarkfen 	    buf, INET6_ADDRSTRLEN));
51027c478bd9Sstevel@tonic-gate 
51037c478bd9Sstevel@tonic-gate 	(void) printf("Dest Mask is %s\n",
51047c478bd9Sstevel@tonic-gate 	    inet_ntop(af, addr_ptr(isv4, &conf->ips_dst_mask_v6, &addr),
5105d5751483Smarkfen 	    buf, INET6_ADDRSTRLEN));
51067c478bd9Sstevel@tonic-gate 
510792913378Spwernau 	(void) printf("Source port %d\n", ntohs(conf->ips_src_port_min));
510892913378Spwernau 	(void) printf("Dest port %d\n", ntohs(conf->ips_dst_port_min));
51097c478bd9Sstevel@tonic-gate 	(void) printf("ULP %d\n", conf->ips_ulp_prot);
51107c478bd9Sstevel@tonic-gate 
51117c478bd9Sstevel@tonic-gate 	(void) printf("ICMP type %d-%d code %d-%d", conf->ips_icmp_type,
51127c478bd9Sstevel@tonic-gate 	    conf->ips_icmp_type_end,
51137c478bd9Sstevel@tonic-gate 	    conf->ips_icmp_code,
51147c478bd9Sstevel@tonic-gate 	    conf->ips_icmp_code_end);
51157c478bd9Sstevel@tonic-gate 
51167c478bd9Sstevel@tonic-gate 	while (iap != NULL) {
51177c478bd9Sstevel@tonic-gate 		(void) printf("------------------------------------\n");
5118e3320f40Smarkfen 		(void) printf("IPsec act is %d\n", iap->iap_action);
5119e3320f40Smarkfen 		(void) printf("IPsec attr is %d\n", iap->iap_attr);
51207c478bd9Sstevel@tonic-gate 		dump_algreq("AH authentication", &iap->iap_aauth);
51217c478bd9Sstevel@tonic-gate 		dump_algreq("ESP authentication", &iap->iap_eauth);
51227c478bd9Sstevel@tonic-gate 		dump_algreq("ESP encryption", &iap->iap_eencr);
51237c478bd9Sstevel@tonic-gate 		(void) printf("------------------------------------\n");
51247c478bd9Sstevel@tonic-gate 		iap = iap->iap_next;
51257c478bd9Sstevel@tonic-gate 	}
51267c478bd9Sstevel@tonic-gate 
5127e3320f40Smarkfen 	(void) fflush(stdout);
51287c478bd9Sstevel@tonic-gate }
51297c478bd9Sstevel@tonic-gate #endif	/* DEBUG */
51307c478bd9Sstevel@tonic-gate 
51317c478bd9Sstevel@tonic-gate 
51327c478bd9Sstevel@tonic-gate static int
5133e3320f40Smarkfen ipsec_conf_add(boolean_t just_check, boolean_t smf_managed)
51347c478bd9Sstevel@tonic-gate {
51357c478bd9Sstevel@tonic-gate 	act_prop_t *act_props = malloc(sizeof (act_prop_t));
51367c478bd9Sstevel@tonic-gate 	ips_conf_t conf;
51377c478bd9Sstevel@tonic-gate 	FILE *fp, *policy_fp;
5138e3320f40Smarkfen 	int ret, flushret, i, j, diag, num_rules, good_rules;
51397c478bd9Sstevel@tonic-gate 	char *warning = gettext(
5140d5751483Smarkfen 	    "\tWARNING : New policy entries that are being added may\n "
5141d5751483Smarkfen 	    "\taffect the existing connections. Existing connections\n"
5142d5751483Smarkfen 	    "\tthat are not subjected to policy constraints, may be\n"
5143d5751483Smarkfen 	    "\tsubjected to policy constraints because of the new\n"
5144d5751483Smarkfen 	    "\tpolicy. This can disrupt the communication of the\n"
5145d5751483Smarkfen 	    "\texisting connections.\n\n");
51467c478bd9Sstevel@tonic-gate 
5147e3320f40Smarkfen 	boolean_t first_time = B_TRUE;
5148e3320f40Smarkfen 	num_rules = 0;
5149e3320f40Smarkfen 	good_rules = 0;
5150e3320f40Smarkfen 
51517c478bd9Sstevel@tonic-gate 	if (act_props == NULL) {
51527c478bd9Sstevel@tonic-gate 		warn(gettext("memory"));
51537c478bd9Sstevel@tonic-gate 		return (-1);
51547c478bd9Sstevel@tonic-gate 	}
51557c478bd9Sstevel@tonic-gate 
51567c478bd9Sstevel@tonic-gate 	if (strcmp(filename, "-") == 0)
51577c478bd9Sstevel@tonic-gate 		fp = stdin;
51587c478bd9Sstevel@tonic-gate 	else
51597c478bd9Sstevel@tonic-gate 		fp = fopen(filename, "r");
51607c478bd9Sstevel@tonic-gate 
5161e3320f40Smarkfen 	/*
5162e3320f40Smarkfen 	 * Treat the non-existence of a policy file as a special
5163e3320f40Smarkfen 	 * case when ipsecconf is being managed by smf(5).
5164e3320f40Smarkfen 	 * The assumption is the administrator has not yet
5165e3320f40Smarkfen 	 * created a policy file, this should not force the service
5166e3320f40Smarkfen 	 * into maintenance mode.
5167e3320f40Smarkfen 	 */
5168e3320f40Smarkfen 
51697c478bd9Sstevel@tonic-gate 	if (fp == NULL) {
5170e3320f40Smarkfen 		if (smf_managed) {
5171e3320f40Smarkfen 			(void) fprintf(stdout, gettext(
5172e3320f40Smarkfen 			    "Policy configuration file (%s) does not exist.\n"
5173e3320f40Smarkfen 			    "IPsec policy not configured.\n"), filename);
5174e3320f40Smarkfen 			return (0);
5175e3320f40Smarkfen 		}
5176e3320f40Smarkfen 		warn(gettext("%s : Policy config file cannot be opened"),
5177e3320f40Smarkfen 		    filename);
51787c478bd9Sstevel@tonic-gate 		usage();
51797c478bd9Sstevel@tonic-gate 		return (-1);
51807c478bd9Sstevel@tonic-gate 	}
51817c478bd9Sstevel@tonic-gate 	/*
51827c478bd9Sstevel@tonic-gate 	 * This will create the file if it does not exist.
51837c478bd9Sstevel@tonic-gate 	 * Make sure the umask is right.
51847c478bd9Sstevel@tonic-gate 	 */
51857c478bd9Sstevel@tonic-gate 	(void) umask(0022);
51867c478bd9Sstevel@tonic-gate 	policy_fp = fopen(POLICY_CONF_FILE, "a");
51877c478bd9Sstevel@tonic-gate 	if (policy_fp == NULL) {
51887c478bd9Sstevel@tonic-gate 		warn(gettext("%s cannot be opened"), POLICY_CONF_FILE);
51897c478bd9Sstevel@tonic-gate 		return (-1);
51907c478bd9Sstevel@tonic-gate 	}
51917c478bd9Sstevel@tonic-gate 
51927c478bd9Sstevel@tonic-gate 	/*
51937c478bd9Sstevel@tonic-gate 	 * Pattern, action, and properties are allocated in
51947c478bd9Sstevel@tonic-gate 	 * parse_pattern_or_prop and in parse_action (called by
51957c478bd9Sstevel@tonic-gate 	 * parse_one) as we parse arguments.
51967c478bd9Sstevel@tonic-gate 	 */
5197d5751483Smarkfen 	while ((ret = parse_one(fp, act_props)) != PARSE_EOF) {
5198d5751483Smarkfen 		num_rules++;
5199d5751483Smarkfen 		if (ret != 0) {
5200d5751483Smarkfen 			(void) print_cmd_buf(stderr, NOERROR);
5201d5751483Smarkfen 			continue;
5202d5751483Smarkfen 		}
52037c478bd9Sstevel@tonic-gate 
52047c478bd9Sstevel@tonic-gate 		/*
52057c478bd9Sstevel@tonic-gate 		 * If there is no action and parse returned success,
52067c478bd9Sstevel@tonic-gate 		 * it means that there is nothing to add.
52077c478bd9Sstevel@tonic-gate 		 */
52087c478bd9Sstevel@tonic-gate 		if (act_props->pattern[0] == NULL &&
52097c478bd9Sstevel@tonic-gate 		    act_props->ap[0].act == NULL)
52107c478bd9Sstevel@tonic-gate 				break;
52117c478bd9Sstevel@tonic-gate 
52127c478bd9Sstevel@tonic-gate 		ret = form_ipsec_conf(act_props, &conf);
52137c478bd9Sstevel@tonic-gate 		if (ret != 0) {
52147c478bd9Sstevel@tonic-gate 			warnx(gettext("form_ipsec_conf error"));
5215e3320f40Smarkfen 			(void) print_cmd_buf(stderr, NOERROR);
5216eec550adSpwernau 			/* Reset globals before trying the next rule. */
5217eec550adSpwernau 			if (shp != NULL) {
5218eec550adSpwernau 				freehostent(shp);
5219eec550adSpwernau 				shp = NULL;
5220eec550adSpwernau 			}
5221eec550adSpwernau 			if (dhp != NULL) {
5222eec550adSpwernau 				freehostent(dhp);
5223eec550adSpwernau 				dhp = NULL;
5224eec550adSpwernau 			}
5225eec550adSpwernau 			splen = 0;
5226eec550adSpwernau 			dplen = 0;
5227e3320f40Smarkfen 			continue;
5228e3320f40Smarkfen 		}
5229e3320f40Smarkfen 
5230e3320f40Smarkfen 		good_rules++;
5231e3320f40Smarkfen 
5232e3320f40Smarkfen 		if (first_time) {
5233e3320f40Smarkfen 			/*
5234e3320f40Smarkfen 			 * Time to assume that there are valid policy entries.
5235e3320f40Smarkfen 			 * If the IPsec kernel modules are not loaded this
5236e3320f40Smarkfen 			 * will load them now.
5237e3320f40Smarkfen 			 */
5238e3320f40Smarkfen 			first_time = B_FALSE;
5239e3320f40Smarkfen 			fetch_algorithms();
5240e3320f40Smarkfen 			ipsec_conf_admin(SPD_CLONE);
52417c478bd9Sstevel@tonic-gate 		}
52427c478bd9Sstevel@tonic-gate 
52437c478bd9Sstevel@tonic-gate 		/*
52447c478bd9Sstevel@tonic-gate 		 * shp, dhp, splen, and dplen are globals set by
52457c478bd9Sstevel@tonic-gate 		 * form_ipsec_conf() while parsing the addresses.
52467c478bd9Sstevel@tonic-gate 		 */
52477c478bd9Sstevel@tonic-gate 		if (shp == NULL && dhp == NULL) {
52487c478bd9Sstevel@tonic-gate 			switch (do_port_adds(&conf)) {
52497c478bd9Sstevel@tonic-gate 			case 0:
52507c478bd9Sstevel@tonic-gate 				/* no error */
52517c478bd9Sstevel@tonic-gate 				break;
52527c478bd9Sstevel@tonic-gate 			case EEXIST:
52537c478bd9Sstevel@tonic-gate 				/* duplicate entries, continue adds */
525443c889d3Smarkfen 				(void) print_cmd_buf(stderr, EEXIST);
52557c478bd9Sstevel@tonic-gate 				goto next;
52567c478bd9Sstevel@tonic-gate 			default:
52577c478bd9Sstevel@tonic-gate 				/* other error, bail */
52587c478bd9Sstevel@tonic-gate 				ret = -1;
52597c478bd9Sstevel@tonic-gate 				goto bail;
52607c478bd9Sstevel@tonic-gate 			}
52617c478bd9Sstevel@tonic-gate 		} else {
52628810c16bSdanmcd 			ret = do_address_adds(&conf, &diag);
52637c478bd9Sstevel@tonic-gate 			switch (ret) {
52647c478bd9Sstevel@tonic-gate 			case 0:
52657c478bd9Sstevel@tonic-gate 				/* no error. */
52667c478bd9Sstevel@tonic-gate 				break;
52677c478bd9Sstevel@tonic-gate 			case EEXIST:
526843c889d3Smarkfen 				(void) print_cmd_buf(stderr, EEXIST);
52697c478bd9Sstevel@tonic-gate 				goto next;
52707c478bd9Sstevel@tonic-gate 			case EBUSY:
52717c478bd9Sstevel@tonic-gate 				warnx(gettext(
5272d5751483Smarkfen 				    "Can't set mask and /NN prefix."));
52737c478bd9Sstevel@tonic-gate 				ret = -1;
52747c478bd9Sstevel@tonic-gate 				break;
52758810c16bSdanmcd 			case ENOENT:
52768810c16bSdanmcd 				warnx(gettext("Cannot find tunnel "
52778810c16bSdanmcd 				    "interface %s."), interface_name);
52788810c16bSdanmcd 				ret = -1;
52798810c16bSdanmcd 				break;
52807c478bd9Sstevel@tonic-gate 			case EINVAL:
52818810c16bSdanmcd 				/*
52828810c16bSdanmcd 				 * PF_POLICY didn't like what we sent.  We
52838810c16bSdanmcd 				 * can't check all input up here, but we
52848810c16bSdanmcd 				 * do in-kernel.
52858810c16bSdanmcd 				 */
52868810c16bSdanmcd 				warnx(gettext("PF_POLICY invalid input:\n\t%s"),
52878810c16bSdanmcd 				    spdsock_diag(diag));
52888810c16bSdanmcd 				break;
52898810c16bSdanmcd 			case EOPNOTSUPP:
52907c478bd9Sstevel@tonic-gate 				warnx(gettext("Can't set /NN"
5291d5751483Smarkfen 				    " prefix on multi-host name."));
52927c478bd9Sstevel@tonic-gate 				ret = -1;
52937c478bd9Sstevel@tonic-gate 				break;
52947c478bd9Sstevel@tonic-gate 			case ERANGE:
52957c478bd9Sstevel@tonic-gate 				warnx(gettext("/NN prefix is too big!"));
52967c478bd9Sstevel@tonic-gate 				ret = -1;
52977c478bd9Sstevel@tonic-gate 				break;
52987c478bd9Sstevel@tonic-gate 			case ESRCH:
52997c478bd9Sstevel@tonic-gate 				warnx(gettext("No matching IPv4 or "
5300d5751483Smarkfen 				    "IPv6 saddr/daddr pairs"));
53017c478bd9Sstevel@tonic-gate 				ret = -1;
53027c478bd9Sstevel@tonic-gate 				break;
53037c478bd9Sstevel@tonic-gate 			default:
53047c478bd9Sstevel@tonic-gate 				/* Should never get here. */
53057c478bd9Sstevel@tonic-gate 				errno = ret;
53067c478bd9Sstevel@tonic-gate 				warn(gettext("Misc. error"));
53077c478bd9Sstevel@tonic-gate 				ret = -1;
53087c478bd9Sstevel@tonic-gate 			}
53097c478bd9Sstevel@tonic-gate 			if (ret == -1)
53107c478bd9Sstevel@tonic-gate 				goto bail;
53117c478bd9Sstevel@tonic-gate 		}
53127c478bd9Sstevel@tonic-gate 
53137c478bd9Sstevel@tonic-gate 		/*
531443c889d3Smarkfen 		 * Go ahead and add policy entries to config file.
53157c478bd9Sstevel@tonic-gate 		 * The # should help re-using the ipsecpolicy.conf
53167c478bd9Sstevel@tonic-gate 		 * for input again as # will be treated as comment.
53177c478bd9Sstevel@tonic-gate 		 */
53187c478bd9Sstevel@tonic-gate 		if (fprintf(policy_fp, "%s %lld \n", INDEX_TAG,
53197c478bd9Sstevel@tonic-gate 		    conf.ips_policy_index) == -1) {
53207c478bd9Sstevel@tonic-gate 			warn("fprintf");
53217c478bd9Sstevel@tonic-gate 			warnx(gettext("Addition incomplete, Please "
53227c478bd9Sstevel@tonic-gate 			    "flush all the entries and re-configure :"));
53237c478bd9Sstevel@tonic-gate 			reconfigure();
53247c478bd9Sstevel@tonic-gate 			ret = -1;
53257c478bd9Sstevel@tonic-gate 			break;
53267c478bd9Sstevel@tonic-gate 		}
532743c889d3Smarkfen 		if (print_cmd_buf(policy_fp, NOERROR) == -1) {
53287c478bd9Sstevel@tonic-gate 			warnx(gettext("Addition incomplete. Please "
53297c478bd9Sstevel@tonic-gate 			    "flush all the entries and re-configure :"));
53307c478bd9Sstevel@tonic-gate 			reconfigure();
53317c478bd9Sstevel@tonic-gate 			ret = -1;
53327c478bd9Sstevel@tonic-gate 			break;
53337c478bd9Sstevel@tonic-gate 		}
53347c478bd9Sstevel@tonic-gate 		/*
53357c478bd9Sstevel@tonic-gate 		 * We add one newline by default to separate out the
53367c478bd9Sstevel@tonic-gate 		 * entries. If the last character is not a newline, we
53377c478bd9Sstevel@tonic-gate 		 * insert a newline for free. This makes sure that all
53387c478bd9Sstevel@tonic-gate 		 * entries look consistent in the file.
53397c478bd9Sstevel@tonic-gate 		 */
53407c478bd9Sstevel@tonic-gate 		if (*(cbuf + cbuf_offset - 1) == '\n') {
53417c478bd9Sstevel@tonic-gate 			if (fprintf(policy_fp, "\n") == -1) {
53427c478bd9Sstevel@tonic-gate 				warn("fprintf");
53437c478bd9Sstevel@tonic-gate 				warnx(gettext("Addition incomplete. "
53447c478bd9Sstevel@tonic-gate 				    "Please flush all the entries and "
53457c478bd9Sstevel@tonic-gate 				    "re-configure :"));
53467c478bd9Sstevel@tonic-gate 				reconfigure();
53477c478bd9Sstevel@tonic-gate 				ret = -1;
53487c478bd9Sstevel@tonic-gate 				break;
53497c478bd9Sstevel@tonic-gate 			}
53507c478bd9Sstevel@tonic-gate 		} else {
53517c478bd9Sstevel@tonic-gate 			if (fprintf(policy_fp, "\n\n") == -1) {
53527c478bd9Sstevel@tonic-gate 				warn("fprintf");
53537c478bd9Sstevel@tonic-gate 				warnx(gettext("Addition incomplete. "
53547c478bd9Sstevel@tonic-gate 				    "Please flush all the entries and "
53557c478bd9Sstevel@tonic-gate 				    "re-configure :"));
53567c478bd9Sstevel@tonic-gate 				reconfigure();
53577c478bd9Sstevel@tonic-gate 				ret = -1;
53587c478bd9Sstevel@tonic-gate 				break;
53597c478bd9Sstevel@tonic-gate 			}
53607c478bd9Sstevel@tonic-gate 		}
5361e3320f40Smarkfen next:
53627c478bd9Sstevel@tonic-gate 		/*
53637c478bd9Sstevel@tonic-gate 		 * Make sure this gets to the disk before
53647c478bd9Sstevel@tonic-gate 		 * we parse the next entry.
53657c478bd9Sstevel@tonic-gate 		 */
53667c478bd9Sstevel@tonic-gate 		(void) fflush(policy_fp);
53677c478bd9Sstevel@tonic-gate 		for (i = 0; act_props->pattern[i] != NULL; i++)
53687c478bd9Sstevel@tonic-gate 			free(act_props->pattern[i]);
53697c478bd9Sstevel@tonic-gate 		for (j = 0; act_props->ap[j].act != NULL; j++) {
53707c478bd9Sstevel@tonic-gate 			free(act_props->ap[j].act);
53717c478bd9Sstevel@tonic-gate 			for (i = 0; act_props->ap[j].prop[i] != NULL; i++)
53727c478bd9Sstevel@tonic-gate 				free(act_props->ap[j].prop[i]);
53737c478bd9Sstevel@tonic-gate 		}
53747c478bd9Sstevel@tonic-gate 	}
5375d5751483Smarkfen 	if (ret == PARSE_EOF)
5376d5751483Smarkfen 		ret = 0; /* Not an error */
53777c478bd9Sstevel@tonic-gate bail:
53787c478bd9Sstevel@tonic-gate 	if (ret == -1) {
537943c889d3Smarkfen 		(void) print_cmd_buf(stderr, EINVAL);
53807c478bd9Sstevel@tonic-gate 		for (i = 0; act_props->pattern[i] != NULL; i++)
53817c478bd9Sstevel@tonic-gate 			free(act_props->pattern[i]);
53827c478bd9Sstevel@tonic-gate 		for (j = 0; act_props->ap[j].act != NULL; j++) {
53837c478bd9Sstevel@tonic-gate 			free(act_props->ap[j].act);
53847c478bd9Sstevel@tonic-gate 			for (i = 0; act_props->ap[j].prop[i] != NULL; i++)
53857c478bd9Sstevel@tonic-gate 				free(act_props->ap[j].prop[i]);
53867c478bd9Sstevel@tonic-gate 		}
53877c478bd9Sstevel@tonic-gate 	}
53887c478bd9Sstevel@tonic-gate #ifdef DEBUG_HEAVY
53897c478bd9Sstevel@tonic-gate 	(void) printf("ipsec_conf_add: ret val = %d\n", ret);
5390e3320f40Smarkfen 	(void) fflush(stdout);
53917c478bd9Sstevel@tonic-gate #endif
5392d5751483Smarkfen 	if (num_rules == 0 && ret == 0) {
5393eec550adSpwernau 		nuke_adds();
5394e3320f40Smarkfen 		(void) restore_all_signals();
5395e3320f40Smarkfen 		(void) unlock(lfd);
5396e3320f40Smarkfen 		EXIT_OK("Policy file does not contain any valid rules.");
5397e3320f40Smarkfen 	}
5398e3320f40Smarkfen 	if (num_rules != good_rules) {
5399e3320f40Smarkfen 		/* This is an error */
5400eec550adSpwernau 		nuke_adds();
5401e3320f40Smarkfen 		(void) restore_all_signals();
5402e3320f40Smarkfen 		(void) unlock(lfd);
5403e3320f40Smarkfen 		EXIT_BADCONFIG2("%d policy rule(s) contained errors.",
5404e3320f40Smarkfen 		    num_rules - good_rules);
5405e3320f40Smarkfen 	}
54067c478bd9Sstevel@tonic-gate 	/* looks good, flip it in */
5407e3320f40Smarkfen 	if (ret == 0 && !just_check) {
5408e3320f40Smarkfen 		if (!ipsecconf_qflag) {
5409e3320f40Smarkfen 			(void) printf("%s", warning);
5410e3320f40Smarkfen 		}
5411d5751483Smarkfen 		if (smf_managed)
5412d5751483Smarkfen 			warnx(gettext("%d policy rules added."), good_rules);
54137c478bd9Sstevel@tonic-gate 		ipsec_conf_admin(SPD_FLIP);
5414e3320f40Smarkfen 	} else {
54157c478bd9Sstevel@tonic-gate 		nuke_adds();
5416e3320f40Smarkfen 		if (just_check) {
5417d5751483Smarkfen 			(void) fprintf(stdout, gettext("IPsec configuration "
5418d5751483Smarkfen 			    "does not contain any errors.\n"));
5419e3320f40Smarkfen 			(void) fprintf(stdout, gettext(
5420e3320f40Smarkfen 			    "IPsec policy was not modified.\n"));
5421e3320f40Smarkfen 			(void) fflush(stdout);
5422e3320f40Smarkfen 		}
5423e3320f40Smarkfen 	}
5424e3320f40Smarkfen 	flushret = ipsec_conf_flush(SPD_STANDBY);
5425e3320f40Smarkfen 	if (flushret != 0)
5426e3320f40Smarkfen 		return (flushret);
54277c478bd9Sstevel@tonic-gate 	return (ret);
54287c478bd9Sstevel@tonic-gate }
54297c478bd9Sstevel@tonic-gate 
54307c478bd9Sstevel@tonic-gate 
54317c478bd9Sstevel@tonic-gate static int
54327c478bd9Sstevel@tonic-gate ipsec_conf_sub()
54337c478bd9Sstevel@tonic-gate {
54347c478bd9Sstevel@tonic-gate 	act_prop_t *act_props = malloc(sizeof (act_prop_t));
54357c478bd9Sstevel@tonic-gate 	FILE *remove_fp, *policy_fp;
54367c478bd9Sstevel@tonic-gate 	char rbuf[MAXLEN], pbuf[MAXLEN], /* remove buffer, and policy buffer */
54377c478bd9Sstevel@tonic-gate 	    *warning = gettext(
5438d5751483Smarkfen 	    "\tWARNING: Policy entries that are being removed may\n"
5439d5751483Smarkfen 	    "\taffect the existing connections.  Existing connections\n"
5440d5751483Smarkfen 	    "\tthat are subjected to policy constraints may no longer\n"
5441d5751483Smarkfen 	    "\tbe subjected to policy contraints because of its\n"
5442d5751483Smarkfen 	    "\tremoval.  This can compromise security, and disrupt\n"
5443d5751483Smarkfen 	    "\tthe communication of the existing connection.\n"
5444d5751483Smarkfen 	    "\tConnections that are latched will remain unaffected\n"
5445d5751483Smarkfen 	    "\tuntil they close.\n");
54467c478bd9Sstevel@tonic-gate 	int ret = 0;
54477c478bd9Sstevel@tonic-gate 	int index_len, pindex = 0; /* init value in case of pfile error */
54487c478bd9Sstevel@tonic-gate 
54497c478bd9Sstevel@tonic-gate 	if (act_props == NULL) {
54507c478bd9Sstevel@tonic-gate 		warn(gettext("memory"));
54517c478bd9Sstevel@tonic-gate 		return (-1);
54527c478bd9Sstevel@tonic-gate 	}
54537c478bd9Sstevel@tonic-gate 
54547c478bd9Sstevel@tonic-gate 	/* clone into standby DB */
54557c478bd9Sstevel@tonic-gate 	(void) ipsec_conf_admin(SPD_CLONE);
54567c478bd9Sstevel@tonic-gate 
54577c478bd9Sstevel@tonic-gate 	if (strcmp(filename, "-") == 0)
54587c478bd9Sstevel@tonic-gate 		remove_fp = stdin;
54597c478bd9Sstevel@tonic-gate 	else
54607c478bd9Sstevel@tonic-gate 		remove_fp = fopen(filename, "r");
54617c478bd9Sstevel@tonic-gate 
54627c478bd9Sstevel@tonic-gate 	if (remove_fp == NULL) {
54637c478bd9Sstevel@tonic-gate 		warn(gettext("%s : Input file cannot be opened"), filename);
54647c478bd9Sstevel@tonic-gate 		usage();
54657c478bd9Sstevel@tonic-gate 		free(act_props);
54667c478bd9Sstevel@tonic-gate 		return (-1);
54677c478bd9Sstevel@tonic-gate 	}
54687c478bd9Sstevel@tonic-gate 
54697c478bd9Sstevel@tonic-gate 	/* open policy file so we can locate the correct policy */
54707c478bd9Sstevel@tonic-gate 	(void) umask(0022);  /* in case it gets created! */
54717c478bd9Sstevel@tonic-gate 	policy_fp = fopen(POLICY_CONF_FILE, "r+");
54727c478bd9Sstevel@tonic-gate 	if (policy_fp == NULL) {
54737c478bd9Sstevel@tonic-gate 		warn(gettext("%s cannot be opened"), POLICY_CONF_FILE);
54747c478bd9Sstevel@tonic-gate 		(void) fclose(remove_fp);
54757c478bd9Sstevel@tonic-gate 		free(act_props);
54767c478bd9Sstevel@tonic-gate 		return (-1);
54777c478bd9Sstevel@tonic-gate 	}
54787c478bd9Sstevel@tonic-gate 
54797c478bd9Sstevel@tonic-gate 	/* don't print the warning if we're in q[uiet] mode */
54807c478bd9Sstevel@tonic-gate 	if (!ipsecconf_qflag)
54817c478bd9Sstevel@tonic-gate 		(void) printf("%s", warning);
54827c478bd9Sstevel@tonic-gate 
54837c478bd9Sstevel@tonic-gate 	/* this bit is done primarily so we can read what we write */
54847c478bd9Sstevel@tonic-gate 	index_len = strlen(INDEX_TAG);
54857c478bd9Sstevel@tonic-gate 
54867c478bd9Sstevel@tonic-gate 	/*
54877c478bd9Sstevel@tonic-gate 	 * We want to look for the policy in rbuf in the policy file.
54887c478bd9Sstevel@tonic-gate 	 * Go through the list of policies to remove, locating each one.
54897c478bd9Sstevel@tonic-gate 	 */
54907c478bd9Sstevel@tonic-gate 	while (fgets(rbuf, MAXLEN, remove_fp) != NULL) {
54917c478bd9Sstevel@tonic-gate 		char *buf;
54927c478bd9Sstevel@tonic-gate 		int offset, prev_offset, prev_prev_offset, nlines;
54937c478bd9Sstevel@tonic-gate 		fpos_t ipos;
54947c478bd9Sstevel@tonic-gate 		int pbuf_len = 0;
54957c478bd9Sstevel@tonic-gate 		char *tmp;
54967c478bd9Sstevel@tonic-gate 		/* skip blanks here (so we don't need to do it below)! */
5497d5751483Smarkfen 		for (tmp = rbuf; (*tmp != '\0') && isspace(*tmp); )
5498d5751483Smarkfen 			tmp++;
5499d5751483Smarkfen 
55007c478bd9Sstevel@tonic-gate 		if (*tmp == '\0')
5501d5751483Smarkfen 			continue; /* while(); */
55027c478bd9Sstevel@tonic-gate 
55037c478bd9Sstevel@tonic-gate 		/* skip the INDEX_TAG lines in the remove buffer */
55047c478bd9Sstevel@tonic-gate 		if (strncasecmp(rbuf, INDEX_TAG, index_len) == 0)
55057c478bd9Sstevel@tonic-gate 			continue;
55067c478bd9Sstevel@tonic-gate 
55077c478bd9Sstevel@tonic-gate 		/* skip commented lines */
55087c478bd9Sstevel@tonic-gate 		if (*tmp == '#')
5509d5751483Smarkfen 			continue; /* while(); */
55107c478bd9Sstevel@tonic-gate 
55117c478bd9Sstevel@tonic-gate 		/*
55127c478bd9Sstevel@tonic-gate 		 * We start by presuming only good policies are in the pfile,
55137c478bd9Sstevel@tonic-gate 		 * and so only good policies from the rfile will match them.
55147c478bd9Sstevel@tonic-gate 		 * ipsec_conf_del ensures this later by calling parse_one() on
55157c478bd9Sstevel@tonic-gate 		 * pfile before it deletes the entry.
55167c478bd9Sstevel@tonic-gate 		 */
55177c478bd9Sstevel@tonic-gate 		for (offset = prev_offset = prev_prev_offset = 0;
55187c478bd9Sstevel@tonic-gate 		    fgets(pbuf, MAXLEN, policy_fp) != NULL;
55197c478bd9Sstevel@tonic-gate 		    offset += pbuf_len) {
55207c478bd9Sstevel@tonic-gate 			prev_offset = offset;
55217c478bd9Sstevel@tonic-gate 			pbuf_len = strlen(pbuf);
55227c478bd9Sstevel@tonic-gate 
55237c478bd9Sstevel@tonic-gate 			/* skip blank lines which seperate policy entries */
55247c478bd9Sstevel@tonic-gate 			if (pbuf[0] == '\n')
55257c478bd9Sstevel@tonic-gate 				continue;
55267c478bd9Sstevel@tonic-gate 
55277c478bd9Sstevel@tonic-gate 			/* if we found an index, save it */
55287c478bd9Sstevel@tonic-gate 			if (strncasecmp(pbuf, INDEX_TAG, index_len) == 0) {
55297c478bd9Sstevel@tonic-gate 				buf = pbuf + index_len;
55307c478bd9Sstevel@tonic-gate 				buf++;
55318810c16bSdanmcd 				if ((pindex = parse_index(buf, NULL)) == -1) {
55327c478bd9Sstevel@tonic-gate 					/* bad index, we can't continue */
55337c478bd9Sstevel@tonic-gate 					warnx(gettext(
5534d5751483Smarkfen 					    "Invalid index in the file"));
55357c478bd9Sstevel@tonic-gate 					(void) fclose(remove_fp);
55367c478bd9Sstevel@tonic-gate 					(void) fclose(policy_fp);
55377c478bd9Sstevel@tonic-gate 					free(act_props);
55387c478bd9Sstevel@tonic-gate 					return (-1);
55397c478bd9Sstevel@tonic-gate 				}
55407c478bd9Sstevel@tonic-gate 
55417c478bd9Sstevel@tonic-gate 				/* save this position in case it's the one */
55427c478bd9Sstevel@tonic-gate 				if (fgetpos(policy_fp, &ipos) != 0) {
55437c478bd9Sstevel@tonic-gate 					(void) fclose(remove_fp);
55447c478bd9Sstevel@tonic-gate 					(void) fclose(policy_fp);
55457c478bd9Sstevel@tonic-gate 					free(act_props);
55467c478bd9Sstevel@tonic-gate 					return (-1);
55477c478bd9Sstevel@tonic-gate 				}
55487c478bd9Sstevel@tonic-gate 			}
55497c478bd9Sstevel@tonic-gate 
55507c478bd9Sstevel@tonic-gate 			/* Does pbuf contain the remove policy? */
55517c478bd9Sstevel@tonic-gate 			if (strncasecmp(rbuf, pbuf, pbuf_len) == 0) {
55527c478bd9Sstevel@tonic-gate 				/* we found the one to remove! */
55537c478bd9Sstevel@tonic-gate 				if (pindex == 0) {
55547c478bd9Sstevel@tonic-gate 					warnx(gettext("Didn't find a valid "
55557c478bd9Sstevel@tonic-gate 					    "index for policy"));
55567c478bd9Sstevel@tonic-gate 					(void) fclose(remove_fp);
55577c478bd9Sstevel@tonic-gate 					(void) fclose(policy_fp);
55587c478bd9Sstevel@tonic-gate 					free(act_props);
55597c478bd9Sstevel@tonic-gate 					return (-1);
55607c478bd9Sstevel@tonic-gate 				}
55617c478bd9Sstevel@tonic-gate 
55627c478bd9Sstevel@tonic-gate 				/* off it - back up to the last INDEX! */
55637c478bd9Sstevel@tonic-gate 				if (fsetpos(policy_fp, &ipos) != 0) {
55647c478bd9Sstevel@tonic-gate 					(void) fclose(remove_fp);
55657c478bd9Sstevel@tonic-gate 					(void) fclose(policy_fp);
55667c478bd9Sstevel@tonic-gate 					free(act_props);
55677c478bd9Sstevel@tonic-gate 					return (-1);
55687c478bd9Sstevel@tonic-gate 				}
55697c478bd9Sstevel@tonic-gate 
55707c478bd9Sstevel@tonic-gate 				/* parse_one sets linecount = #lines to off */
55717c478bd9Sstevel@tonic-gate 				if (parse_one(policy_fp, act_props) == -1) {
55727c478bd9Sstevel@tonic-gate 					warnx(gettext("Invalid policy entry "
55737c478bd9Sstevel@tonic-gate 					    "in the file"));
55747c478bd9Sstevel@tonic-gate 					(void) fclose(remove_fp);
55757c478bd9Sstevel@tonic-gate 					(void) fclose(policy_fp);
55767c478bd9Sstevel@tonic-gate 					free(act_props);
55777c478bd9Sstevel@tonic-gate 					return (-1);
55787c478bd9Sstevel@tonic-gate 				}
55797c478bd9Sstevel@tonic-gate 
55807c478bd9Sstevel@tonic-gate 				nlines = linecount + 2;
55817c478bd9Sstevel@tonic-gate 				goto delete;
55827c478bd9Sstevel@tonic-gate 			}
55837c478bd9Sstevel@tonic-gate 			/*
55847c478bd9Sstevel@tonic-gate 			 * When we find a match, we want to pass the offset
55857c478bd9Sstevel@tonic-gate 			 * of the line that is before it - the INDEX_TAG line.
55867c478bd9Sstevel@tonic-gate 			 */
55877c478bd9Sstevel@tonic-gate 			prev_prev_offset = prev_offset;
55887c478bd9Sstevel@tonic-gate 		}
55897c478bd9Sstevel@tonic-gate 		/* Didn't find a match - look at the next remove policy */
5590d5751483Smarkfen 		continue; /* while(); */
55917c478bd9Sstevel@tonic-gate 
55927c478bd9Sstevel@tonic-gate delete:
55937c478bd9Sstevel@tonic-gate 		(void) fclose(policy_fp);
55947c478bd9Sstevel@tonic-gate 
55957c478bd9Sstevel@tonic-gate 		if (delete_from_file(prev_prev_offset, nlines) != 0) {
55967c478bd9Sstevel@tonic-gate 			warnx(gettext("delete_from_file failure.  "
55977c478bd9Sstevel@tonic-gate 			    "Please flush all entries and re-configure :"));
55987c478bd9Sstevel@tonic-gate 			reconfigure();
55997c478bd9Sstevel@tonic-gate 			(void) fclose(remove_fp);
56007c478bd9Sstevel@tonic-gate 			free(act_props);
56017c478bd9Sstevel@tonic-gate 			return (-1);
56027c478bd9Sstevel@tonic-gate 		}
56037c478bd9Sstevel@tonic-gate 
56047c478bd9Sstevel@tonic-gate 		if (pfp_delete_rule(pindex) != 0) {
56057c478bd9Sstevel@tonic-gate 			warnx(gettext("Deletion incomplete. Please flush"
56067c478bd9Sstevel@tonic-gate 			    "all the entries and re-configure :"));
56077c478bd9Sstevel@tonic-gate 			reconfigure();
56087c478bd9Sstevel@tonic-gate 			(void) fclose(remove_fp);
56097c478bd9Sstevel@tonic-gate 			free(act_props);
56107c478bd9Sstevel@tonic-gate 			return (-1);
56117c478bd9Sstevel@tonic-gate 		}
56127c478bd9Sstevel@tonic-gate 
56137c478bd9Sstevel@tonic-gate 		/* reset the globals */
56147c478bd9Sstevel@tonic-gate 		linecount = 0;
56157c478bd9Sstevel@tonic-gate 		pindex = 0;
56168810c16bSdanmcd 		/* free(NULL) also works. */
56178810c16bSdanmcd 		free(interface_name);
56188810c16bSdanmcd 		interface_name = NULL;
56197c478bd9Sstevel@tonic-gate 
56207c478bd9Sstevel@tonic-gate 		/* reopen for next pass, automagically starting over. */
56217c478bd9Sstevel@tonic-gate 		policy_fp = fopen(POLICY_CONF_FILE, "r");
56227c478bd9Sstevel@tonic-gate 		if (policy_fp == NULL) {
56237c478bd9Sstevel@tonic-gate 			warn(gettext("%s cannot be re-opened, can't continue"),
56247c478bd9Sstevel@tonic-gate 			    POLICY_CONF_FILE);
56257c478bd9Sstevel@tonic-gate 			(void) fclose(remove_fp);
56267c478bd9Sstevel@tonic-gate 			free(act_props);
56277c478bd9Sstevel@tonic-gate 			return (-1);
56287c478bd9Sstevel@tonic-gate 		}
56297c478bd9Sstevel@tonic-gate 
56307c478bd9Sstevel@tonic-gate 	} /* read next remove policy */
56317c478bd9Sstevel@tonic-gate 
56327c478bd9Sstevel@tonic-gate 	if ((ret = pfp_delete_rule(pindex)) != 0) {
56337c478bd9Sstevel@tonic-gate 		warnx(gettext("Removal incomplete.  Please flush "
56347c478bd9Sstevel@tonic-gate 		    "all the entries and re-configure :"));
56357c478bd9Sstevel@tonic-gate 		reconfigure();
56367c478bd9Sstevel@tonic-gate 		free(act_props);
56377c478bd9Sstevel@tonic-gate 		return (ret);
56387c478bd9Sstevel@tonic-gate 	}
56397c478bd9Sstevel@tonic-gate 
56407c478bd9Sstevel@tonic-gate 	/* nothing left to look for */
56417c478bd9Sstevel@tonic-gate 	(void) fclose(remove_fp);
56427c478bd9Sstevel@tonic-gate 	free(act_props);
56437c478bd9Sstevel@tonic-gate 
56447c478bd9Sstevel@tonic-gate 	return (0);
56457c478bd9Sstevel@tonic-gate }
56468810c16bSdanmcd 
56478810c16bSdanmcd /*
56488810c16bSdanmcd  * Constructs a tunnel interface ID extension.  Returns the length
56498810c16bSdanmcd  * of the extension in 64-bit-words.
56508810c16bSdanmcd  */
56518810c16bSdanmcd static int
56528810c16bSdanmcd attach_tunname(spd_if_t *tunname)
56538810c16bSdanmcd {
56548810c16bSdanmcd 	if (tunname == NULL || interface_name == NULL)
56558810c16bSdanmcd 		return (0);
56568810c16bSdanmcd 
56578810c16bSdanmcd 	tunname->spd_if_exttype = SPD_EXT_TUN_NAME;
56588810c16bSdanmcd 	/*
56598810c16bSdanmcd 	 * Use "-3" because there's 4 bytes in the message itself, and
56608810c16bSdanmcd 	 * we lose one because of the '\0' terminator.
56618810c16bSdanmcd 	 */
56628810c16bSdanmcd 	tunname->spd_if_len = SPD_8TO64(
56638810c16bSdanmcd 	    P2ROUNDUP(sizeof (*tunname) + strlen(interface_name) - 3, 8));
56648810c16bSdanmcd 	(void) strlcpy((char *)tunname->spd_if_name, interface_name, LIFNAMSIZ);
56658810c16bSdanmcd 	return (tunname->spd_if_len);
56668810c16bSdanmcd }
5667