Home | History | Annotate | Download | only in ipsecutils
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #include <stdio.h>
     27 #include <sys/types.h>
     28 #include <sys/stat.h>
     29 #include <strings.h>
     30 #include <stropts.h>
     31 #include <fcntl.h>
     32 #include <stdlib.h>
     33 #include <unistd.h>
     34 #include <string.h>
     35 #include <ctype.h>
     36 #include <arpa/inet.h>
     37 #include <locale.h>
     38 #include <syslog.h>
     39 #include <pwd.h>
     40 #include <sys/param.h>
     41 #include <sys/sysmacros.h>	/* MIN, MAX */
     42 #include <sys/sockio.h>
     43 #include <net/pfkeyv2.h>
     44 #include <net/pfpolicy.h>
     45 #include <inet/ipsec_impl.h>
     46 #include <signal.h>
     47 #include <errno.h>
     48 #include <netdb.h>
     49 #include <sys/socket.h>
     50 #include <sys/systeminfo.h>
     51 #include <nss_dbdefs.h>					/* NSS_BUFLEN_HOSTS */
     52 #include <netinet/in.h>
     53 #include <assert.h>
     54 #include <inet/ip.h>
     55 #include <ipsec_util.h>
     56 #include <netinet/in_systm.h>
     57 #include <netinet/ip_icmp.h>
     58 #include <netinet/icmp6.h>
     59 
     60 /*
     61  * Globals
     62  */
     63 int lfd;
     64 char *my_fmri;
     65 FILE *debugfile = stderr;
     66 
     67 #define	USAGE() if (!smf_managed) usage()
     68 /*
     69  * Buffer length to read in pattern/properties.
     70  */
     71 #define	MAXLEN			1024
     72 
     73 /* Max length of tunnel interface string identifier */
     74 #define	TUNNAMEMAXLEN		LIFNAMSIZ
     75 
     76 /*
     77  * Used by parse_one and parse/parse_action to communicate
     78  * the errors. -1 is failure, which is not defined here.
     79  */
     80 enum parse_errors {PARSE_SUCCESS, PARSE_EOF};
     81 
     82 /*
     83  * For spdsock_get_ext() diagnostics.
     84  */
     85 #define	SPDSOCK_DIAG_BUF_LEN	128
     86 static char spdsock_diag_buf[SPDSOCK_DIAG_BUF_LEN];
     87 
     88 /*
     89  * Define CURL here so that while you are reading
     90  * this code, it does not affect "vi" in pattern
     91  * matching.
     92  */
     93 #define	CURL_BEGIN		'{'
     94 #define	CURL_END		'}'
     95 #define	BACK_SLASH		'\\'
     96 #define	MAXARGS			20
     97 #define	NOERROR			0
     98 
     99 /*
    100  * IPSEC_CONF_ADD should start with 1, so that when multiple commands
    101  * are given, we can fail the request.
    102  */
    103 
    104 enum ipsec_cmds {IPSEC_CONF_ADD = 1, IPSEC_CONF_DEL, IPSEC_CONF_VIEW,
    105     IPSEC_CONF_FLUSH, IPSEC_CONF_LIST, IPSEC_CONF_SUB, IPSEC_CONF_REPLACE};
    106 
    107 static const char policy_conf_file[] = "/var/run/ipsecpolicy.conf";
    108 static const char lock_file[] = "/var/run/ipsecconf.lock";
    109 static const char index_tag[] = "#INDEX";
    110 
    111 #define	POLICY_CONF_FILE	policy_conf_file
    112 #define	LOCK_FILE		lock_file
    113 #define	INDEX_TAG		index_tag
    114 
    115 /*
    116  * Valid algorithm length.
    117  */
    118 #define	VALID_ALG_LEN		40
    119 
    120 /* Types of Error messages */
    121 typedef enum error_type {BAD_ERROR, DUP_ERROR, REQ_ERROR} error_type_t;
    122 
    123 /* Error message human readable conversions */
    124 static char *sys_error_message(int);
    125 static void error_message(error_type_t, int, int);
    126 static int get_pf_pol_socket(void);
    127 
    128 static int cmd;
    129 static char *filename;
    130 static char lo_buf[MAXLEN];			/* Leftover buffer */
    131 
    132 /*
    133  * The new SPD_EXT_TUN_NAME extension has a tunnel name in it.  Use the empty
    134  * string ("", stored in the char value "all_polheads") for all policy heads
    135  * (global and all tunnels).  Set interface_name to NULL for global-only, or
    136  * specify a name of an IP-in-IP tunnel.
    137  */
    138 static char *interface_name;
    139 static char all_polheads;	/* So we can easily get "". */
    140 
    141 /* Error reporting stuff */
    142 #define	CBUF_LEN		4096		/* Maximum size of the cmd */
    143 /*
    144  * Following are used for reporting errors with arguments.
    145  * We store the line numbers of each argument as we parse them,
    146  * so that the error reporting is more specific. We can have only
    147  * (MAXARGS - 1) arguments between any pair of CURL_BEGIN CURL_END.
    148  * Because a single command can be made up of multiple action/property
    149  * combinations, the maximum command size is (2 * (MAXARGS -1)) for each
    150  * of patterns, properties and actions.
    151  */
    152 #define	ARG_BUF_LEN		((2 * 3 * (MAXARGS - 1)) + 1)
    153 static int arg_indices[ARG_BUF_LEN];
    154 static int argindex;
    155 static int linecount;
    156 static char cbuf[CBUF_LEN];				/* Command buffer */
    157 static int cbuf_offset;
    158 
    159 
    160 #define	BYPASS_POLICY_BOOST		0x00800000
    161 #define	ESP_POLICY_BOOST		0x00400000
    162 #define	AH_POLICY_BOOST			0x00200000
    163 #define	INITIAL_BASE_PRIORITY		0x000fffff
    164 
    165 /*
    166  * the number used to order the
    167  * rules starts at a certain base and
    168  * goes down.  i.e. rules earlier in
    169  * the file are checked first
    170  */
    171 static uint32_t priority = INITIAL_BASE_PRIORITY;
    172 
    173 #define	AH_AUTH		0
    174 #define	ESP_ENCR	1
    175 #define	ESP_AUTH	2
    176 
    177 
    178 /*
    179  * for deleting adds on error
    180  */
    181 
    182 typedef struct d_list_s
    183 {
    184 	struct d_list_s *next;
    185 	int index;
    186 } d_list_t;
    187 
    188 static d_list_t *d_list = NULL;
    189 static d_list_t *d_tail = NULL;
    190 
    191 
    192 /*
    193  * Used for multi-homed source/dest hosts.
    194  */
    195 static struct hostent *shp, *dhp;
    196 static unsigned int splen, dplen;
    197 static char tunif[TUNNAMEMAXLEN];
    198 static boolean_t has_saprefix, has_daprefix;
    199 static uint32_t seq_cnt = 0;
    200 
    201 /* lexxed out action and related properties */
    202 typedef struct ap_s
    203 {
    204 	char *act;
    205 	char *prop[MAXARGS + 1];
    206 } ap_t;
    207 
    208 
    209 /* one lexxed out rule */
    210 typedef struct act_prop_s {
    211 	char *pattern[MAXARGS + 1];
    212 	ap_t ap[MAXARGS + 1];
    213 } act_prop_t;
    214 
    215 typedef struct
    216 {
    217 	uint8_t	 alg_id;
    218 	uint32_t alg_minbits;
    219 	uint32_t alg_maxbits;
    220 } algreq_t;
    221 
    222 /* structure to hold all information for one act_prop_t */
    223 typedef struct ips_act_props_s {
    224 	struct ips_act_props_s	*iap_next;
    225 	struct ips_conf_s		*iap_head;
    226 
    227 /*
    228  * IPsec action types (in SPD_ATTR_TYPE attribute)
    229  * SPD_ACTTYPE_DROP	0x0001
    230  * SPD_ACTTYPE_PASS	0x0002
    231  * SPD_ACTTYPE_IPSEC	0x0003
    232  */
    233 	uint16_t	iap_action;
    234 	uint16_t	iap_act_tok;
    235 
    236 /*
    237  * Action ATTR flags (in SPD_ATTR_FLAGS attribute)
    238  *	SPD_APPLY_AH		0x0001
    239  *	SPD_APPLY_ESP		0x0002
    240  *	SPD_APPLY_SE		0x0004  * self-encapsulation *
    241  *	SPD_APPLY_COMP		0x0008	* compression; NYI *
    242  *	SPD_APPLY_UNIQUE	0x0010	* unique per-flow SA *
    243  *	SPD_APPLY_BYPASS	0x0020	* bypass policy *
    244  */
    245 	uint16_t	iap_attr;
    246 	uint16_t	iap_attr_tok[5];
    247 
    248 	algreq_t	iap_aauth;
    249 	algreq_t	iap_eencr;
    250 	algreq_t	iap_eauth;
    251 
    252 	uint32_t iap_life_soft_time;
    253 	uint32_t iap_life_hard_time;
    254 	uint32_t iap_life_soft_bytes;
    255 	uint32_t iap_life_hard_bytes;
    256 
    257 } ips_act_props_t;
    258 
    259 #define	V4_PART_OF_V6(v6)	v6._S6_un._S6_u32[3]
    260 
    261 typedef struct ips_conf_s {
    262 	/* selector */
    263 	uint16_t patt_tok[8];
    264 	uint8_t has_saddr;
    265 	uint8_t has_daddr;
    266 	uint8_t has_smask;
    267 	uint8_t has_dmask;
    268 	uint8_t has_type;
    269 	uint8_t has_code;
    270 	uint8_t has_negotiate;
    271 	uint8_t has_tunnel;
    272 	uint16_t swap;
    273 
    274 	struct in6_addr	ips_src_addr_v6;
    275 	struct in6_addr	ips_src_mask_v6;
    276 	struct in6_addr	ips_dst_addr_v6;
    277 	struct in6_addr	ips_dst_mask_v6;
    278 	uint8_t 		ips_src_mask_len;
    279 	uint8_t 		ips_dst_mask_len;
    280 	in_port_t		ips_src_port_min;
    281 	in_port_t		ips_src_port_max;
    282 	in_port_t		ips_dst_port_min;
    283 	in_port_t		ips_dst_port_max;
    284 	uint8_t			ips_icmp_type;
    285 	uint8_t			ips_icmp_type_end;
    286 	uint8_t			ips_icmp_code;
    287 	uint8_t			ips_icmp_code_end;
    288 	uint8_t			ips_ulp_prot;
    289 	uint8_t			ips_ipsec_prot;
    290 	uint8_t			ips_isv4;
    291 	/*
    292 	 * SPD_RULE_FLAG_INBOUND		0x0001
    293 	 * SPD_RULE_FLAG_OUTBOUND		0x0002
    294 	 */
    295 	uint8_t			ips_dir;
    296 	/*
    297 	 * Keep track of tunnel separately due to explosion of ways to set
    298 	 * inbound/outbound.
    299 	 */
    300 	boolean_t		ips_tunnel;
    301 	uint64_t		ips_policy_index;
    302 	uint32_t		ips_act_cnt;
    303 	ips_act_props_t	*ips_acts;
    304 } ips_conf_t;
    305 
    306 #define	ips_src_addr	V4_PART_OF_V6(ips_src_addr_v6)
    307 #define	ips_dst_addr	V4_PART_OF_V6(ips_dst_addr_v6)
    308 
    309 static int ipsecconf_nflag;		/* Used only with -l option */
    310 static int ipsecconf_qflag;		/* Used only with -a|-r option */
    311 
    312 typedef struct str_val {
    313 	const char *string;
    314 	int value;
    315 } str_val_t;
    316 
    317 typedef struct str_tval {
    318 	const char *string;
    319 	int tok_val;
    320 	int value;
    321 } str_tval_t;
    322 
    323 static int	parse_int(const char *);
    324 static int	parse_index(const char *, char *);
    325 static int	attach_tunname(spd_if_t *);
    326 static void	usage(void);
    327 static int	ipsec_conf_del(int, boolean_t);
    328 static int	ipsec_conf_add(boolean_t, boolean_t, boolean_t);
    329 static int	ipsec_conf_sub(void);
    330 static int	ipsec_conf_flush(int);
    331 static int	ipsec_conf_view(void);
    332 static int	ipsec_conf_list(void);
    333 static int	lock(void);
    334 static int	unlock(int);
    335 static int	parse_one(FILE *, act_prop_t *);
    336 static void	reconfigure();
    337 static void	in_prefixlentomask(unsigned int, uchar_t *);
    338 static int	in_getprefixlen(char *);
    339 static int	parse_address(int, char *);
    340 #ifdef DEBUG_HEAVY
    341 static void	pfpol_msg_dump(spd_msg_t *msg, char *);
    342 #endif /* DEBUG_HEAVY */
    343 static void	print_pfpol_msg(spd_msg_t *);
    344 static int	pfp_delete_rule(uint64_t);
    345 static void	ipsec_conf_admin(uint8_t);
    346 static void	print_bit_range(int, int);
    347 static void	nuke_adds();
    348 
    349 #ifdef DEBUG
    350 static void	dump_conf(ips_conf_t *);
    351 #endif
    352 
    353 typedef struct
    354 {
    355 	uint32_t	id;
    356 	uint32_t	minkeybits;
    357 	uint32_t	maxkeybits;
    358 	uint32_t	defkeybits;
    359 	uint32_t	incr;
    360 } alginfo_t;
    361 
    362 static int ipsec_nalgs[3];
    363 static alginfo_t known_algs[3][256];
    364 
    365 #define	IPS_SRC_MASK SPD_EXT_LCLADDR + 100
    366 #define	IPS_DST_MASK SPD_EXT_REMADDR + 100
    367 
    368 /*
    369  * if inbound, src=remote, dst=local
    370  * if outbound, src=local, dst=remote
    371  */
    372 
    373 #define	TOK_saddr	1
    374 #define	TOK_daddr	2
    375 #define	TOK_sport	3
    376 #define	TOK_dport	4
    377 #define	TOK_smask	5
    378 #define	TOK_dmask	6
    379 #define	TOK_ulp	7
    380 #define	TOK_local	8
    381 #define	TOK_lport	9
    382 #define	TOK_remote	10
    383 #define	TOK_rport	11
    384 #define	TOK_dir 	12
    385 #define	TOK_type	13
    386 #define	TOK_code	14
    387 #define	TOK_negotiate	15
    388 #define	TOK_tunnel	16
    389 
    390 #define	IPS_SA SPD_ATTR_END
    391 #define	IPS_DIR SPD_ATTR_EMPTY
    392 #define	IPS_NEG SPD_ATTR_NOP
    393 
    394 
    395 static str_tval_t pattern_table[] = {
    396 	{"saddr", 		TOK_saddr,		SPD_EXT_LCLADDR},
    397 	{"src",			TOK_saddr,		SPD_EXT_LCLADDR},
    398 	{"srcaddr",		TOK_saddr,		SPD_EXT_LCLADDR},
    399 	{"daddr", 		TOK_daddr,		SPD_EXT_REMADDR},
    400 	{"dst",			TOK_daddr,		SPD_EXT_REMADDR},
    401 	{"dstaddr",		TOK_daddr,		SPD_EXT_REMADDR},
    402 	{"sport", 		TOK_sport,		SPD_EXT_LCLPORT},
    403 	{"dport", 		TOK_dport,		SPD_EXT_REMPORT},
    404 	{"smask", 		TOK_smask,		IPS_SRC_MASK},
    405 	{"dmask", 		TOK_dmask,		IPS_DST_MASK},
    406 	{"ulp", 		TOK_ulp,		SPD_EXT_PROTO},
    407 	{"proto", 		TOK_ulp,		SPD_EXT_PROTO},
    408 	{"local",		TOK_local,		SPD_EXT_LCLADDR},
    409 	{"laddr",		TOK_local,		SPD_EXT_LCLADDR},
    410 	{"lport",		TOK_lport,		SPD_EXT_LCLPORT},
    411 	{"remote",		TOK_remote,		SPD_EXT_REMADDR},
    412 	{"raddr",		TOK_remote,		SPD_EXT_REMADDR},
    413 	{"rport",		TOK_rport,		SPD_EXT_REMPORT},
    414 	{"dir",			TOK_dir,		IPS_DIR},
    415 	{"type",		TOK_type,		SPD_EXT_ICMP_TYPECODE},
    416 	{"code",		TOK_code,		SPD_EXT_ICMP_TYPECODE},
    417 	{"negotiate",		TOK_negotiate,		IPS_NEG},
    418 	{"tunnel",		TOK_tunnel,		SPD_EXT_TUN_NAME},
    419 	{NULL, 			0,				0},
    420 };
    421 
    422 #define	TOK_apply	1
    423 #define	TOK_permit	2
    424 #define	TOK_ipsec	3
    425 #define	TOK_bypass	4
    426 #define	TOK_drop	5
    427 #define	TOK_or		6
    428 
    429 static str_tval_t action_table[] = {
    430 	{"apply", 		TOK_apply,		SPD_ACTTYPE_IPSEC},
    431 	{"permit", 		TOK_permit,		SPD_ACTTYPE_IPSEC},
    432 	{"ipsec", 		TOK_ipsec,		SPD_ACTTYPE_IPSEC},
    433 	{"bypass", 		TOK_bypass,		SPD_ACTTYPE_PASS},
    434 	{"pass", 		TOK_bypass,		SPD_ACTTYPE_PASS},
    435 	{"drop", 		TOK_drop,		SPD_ACTTYPE_DROP},
    436 	{"or",			TOK_or,			0},
    437 	{NULL, 			0,				0},
    438 };
    439 
    440 static str_val_t property_table[] = {
    441 	{"auth_algs", 		SPD_ATTR_AH_AUTH},
    442 	{"encr_algs", 		SPD_ATTR_ESP_ENCR},
    443 	{"encr_auth_algs",	SPD_ATTR_ESP_AUTH},
    444 	{"sa",				IPS_SA},
    445 	{"dir",				IPS_DIR},
    446 	{NULL,				0},
    447 };
    448 
    449 static str_val_t icmp_type_table[] = {
    450 	{"unreach",	ICMP_UNREACH},
    451 	{"echo",	ICMP_ECHO},
    452 	{"echorep",	ICMP_ECHOREPLY},
    453 	{"squench",	ICMP_SOURCEQUENCH},
    454 	{"redir",	ICMP_REDIRECT},
    455 	{"timex",	ICMP_TIMXCEED},
    456 	{"paramprob",	ICMP_PARAMPROB},
    457 	{"timest",	ICMP_TSTAMP},
    458 	{"timestrep",	ICMP_TSTAMPREPLY},
    459 	{"inforeq",	ICMP_IREQ},
    460 	{"inforep",	ICMP_IREQREPLY},
    461 	{"maskreq",	ICMP_MASKREQ},
    462 	{"maskrep",	ICMP_MASKREPLY},
    463 	{"unreach6",	ICMP6_DST_UNREACH},
    464 	{"pkttoobig6",	ICMP6_PACKET_TOO_BIG},
    465 	{"timex6",	ICMP6_TIME_EXCEEDED},
    466 	{"paramprob6",	ICMP6_PARAM_PROB},
    467 	{"echo6", 	ICMP6_ECHO_REQUEST},
    468 	{"echorep6",	ICMP6_ECHO_REPLY},
    469 	{"router-sol6",	ND_ROUTER_SOLICIT},
    470 	{"router-ad6",	ND_ROUTER_ADVERT},
    471 	{"neigh-sol6",	ND_NEIGHBOR_SOLICIT},
    472 	{"neigh-ad6",	ND_NEIGHBOR_ADVERT},
    473 	{"redir6",	ND_REDIRECT},
    474 	{NULL,		0},
    475 };
    476 
    477 static str_val_t icmp_code_table[] = {
    478 	{"net-unr",		ICMP_UNREACH_NET},
    479 	{"host-unr",		ICMP_UNREACH_HOST},
    480 	{"proto-unr",		ICMP_UNREACH_PROTOCOL},
    481 	{"port-unr",		ICMP_UNREACH_PORT},
    482 	{"needfrag",		ICMP_UNREACH_NEEDFRAG},
    483 	{"srcfail",		ICMP_UNREACH_SRCFAIL},
    484 	{"net-unk",		ICMP_UNREACH_NET_UNKNOWN},
    485 	{"host-unk",		ICMP_UNREACH_HOST_UNKNOWN},
    486 	{"isolate",		ICMP_UNREACH_ISOLATED},
    487 	{"net-prohib",		ICMP_UNREACH_NET_PROHIB},
    488 	{"host-prohib",		ICMP_UNREACH_HOST_PROHIB},
    489 	{"net-tos",		ICMP_UNREACH_TOSNET},
    490 	{"host-tos",		ICMP_UNREACH_TOSHOST},
    491 	{"filter-prohib",	ICMP_UNREACH_FILTER_PROHIB},
    492 	{"host-preced",		ICMP_UNREACH_HOST_PRECEDENCE},
    493 	{"cutoff-preced",	ICMP_UNREACH_PRECEDENCE_CUTOFF},
    494 	{"no-route6",		ICMP6_DST_UNREACH_NOROUTE},
    495 	{"adm-prohib6",		ICMP6_DST_UNREACH_ADMIN},
    496 	{"addr-unr6",		ICMP6_DST_UNREACH_ADDR},
    497 	{"port-unr6",		ICMP6_DST_UNREACH_NOPORT},
    498 	{"hop-limex6",		ICMP6_TIME_EXCEED_TRANSIT},
    499 	{"frag-re-timex6",	ICMP6_TIME_EXCEED_REASSEMBLY},
    500 	{"err-head6",		ICMP6_PARAMPROB_HEADER},
    501 	{"unrec-head6",		ICMP6_PARAMPROB_NEXTHEADER},
    502 	{"unreq-opt6",		ICMP6_PARAMPROB_OPTION},
    503 	{NULL,			0},
    504 };
    505 
    506 static sigset_t set, oset;
    507 
    508 
    509 static boolean_t
    510 add_index(int index)
    511 {
    512 	d_list_t *temp = malloc(sizeof (d_list_t));
    513 
    514 	if (temp == NULL) {
    515 		warn("malloc");
    516 		return (B_TRUE);
    517 	}
    518 
    519 	temp->index = index;
    520 	temp->next = NULL;
    521 
    522 	if (d_tail == NULL) {
    523 		d_list = d_tail = temp;
    524 		return (B_FALSE);
    525 	}
    526 
    527 	d_tail->next = temp;
    528 	d_tail = temp;
    529 
    530 	return (B_FALSE);
    531 }
    532 
    533 static int
    534 block_all_signals()
    535 {
    536 	if (sigfillset(&set) == -1) {
    537 		warn("sigfillset");
    538 		return (-1);
    539 	}
    540 	if (sigprocmask(SIG_SETMASK, &set, &oset) == -1) {
    541 		warn("sigprocmask");
    542 		return (-1);
    543 	}
    544 	return (0);
    545 }
    546 
    547 static int
    548 restore_all_signals()
    549 {
    550 	if (sigprocmask(SIG_SETMASK, &oset, NULL) == -1) {
    551 		warn("sigprocmask");
    552 		return (-1);
    553 	}
    554 	return (0);
    555 }
    556 
    557 /* allocate an ips_act_props_t and link it in correctly */
    558 static ips_act_props_t *
    559 alloc_iap(ips_conf_t *parent)
    560 {
    561 	ips_act_props_t *ret;
    562 	ips_act_props_t *next = parent->ips_acts;
    563 	ips_act_props_t *current = NULL;
    564 
    565 	ret = (ips_act_props_t *)calloc(sizeof (ips_act_props_t), 1);
    566 
    567 	if (ret == NULL)
    568 		return (NULL);
    569 
    570 	ret->iap_head = parent;
    571 
    572 	while (next != NULL) {
    573 		current = next;
    574 		next = next->iap_next;
    575 	}
    576 
    577 	if (current != NULL)
    578 		current->iap_next = ret;
    579 	else
    580 		parent->ips_acts = ret;
    581 
    582 	parent->ips_act_cnt++;
    583 
    584 	return (ret);
    585 }
    586 
    587 /*
    588  * This function exit()s if it fails.
    589  */
    590 static void
    591 fetch_algorithms()
    592 {
    593 	struct spd_msg msg;
    594 	struct spd_ext_actions *actp;
    595 	struct spd_attribute *attr, *endattr;
    596 	spd_ext_t *exts[SPD_EXT_MAX+1];
    597 	uint64_t reply_buf[256];
    598 	int sfd;
    599 	int cnt, retval;
    600 	uint64_t *start, *end;
    601 	alginfo_t alg = {0, 0, 0, 0, 0};
    602 	uint_t algtype;
    603 	static boolean_t has_run = B_FALSE;
    604 
    605 	if (has_run)
    606 		return;
    607 	else
    608 		has_run = B_TRUE;
    609 
    610 	sfd = get_pf_pol_socket();
    611 	if (sfd < 0) {
    612 		err(-1, gettext("unable to open policy socket"));
    613 	}
    614 
    615 	(void) memset(&msg, 0, sizeof (msg));
    616 	msg.spd_msg_version = PF_POLICY_V1;
    617 	msg.spd_msg_type = SPD_ALGLIST;
    618 	msg.spd_msg_len = SPD_8TO64(sizeof (msg));
    619 
    620 	cnt = write(sfd, &msg, sizeof (msg));
    621 	if (cnt != sizeof (msg)) {
    622 		if (cnt < 0) {
    623 			err(-1, gettext("alglist failed: write"));
    624 		} else {
    625 			errx(-1, gettext("alglist failed: short write"));
    626 		}
    627 	}
    628 
    629 	cnt = read(sfd, reply_buf, sizeof (reply_buf));
    630 
    631 	retval = spdsock_get_ext(exts, (spd_msg_t *)reply_buf, SPD_8TO64(cnt),
    632 	    spdsock_diag_buf, SPDSOCK_DIAG_BUF_LEN);
    633 
    634 	if (retval == KGE_LEN && exts[0]->spd_ext_len == 0) {
    635 		/*
    636 		 * No algorithms are defined in the kernel, which caused
    637 		 * the extension length to be zero, and spdsock_get_ext()
    638 		 * to fail with a KGE_LEN error. This is not an error
    639 		 * condition, so we return nicely.
    640 		 */
    641 		(void) close(sfd);
    642 		return;
    643 	} else if (retval != 0) {
    644 		if (strlen(spdsock_diag_buf) != 0)
    645 			warnx(spdsock_diag_buf);
    646 		err(1, gettext("fetch_algorithms failed"));
    647 	}
    648 
    649 	if (!exts[SPD_EXT_ACTION]) {
    650 		errx(1, gettext("fetch_algorithms: action missing?!"));
    651 	}
    652 
    653 	actp = (struct spd_ext_actions *)exts[SPD_EXT_ACTION];
    654 	start = (uint64_t *)actp;
    655 	end = (start + actp->spd_actions_len);
    656 	endattr = (struct spd_attribute *)end;
    657 	attr = (struct spd_attribute *)&actp[1];
    658 
    659 	algtype = 0;
    660 
    661 	while (attr < endattr) {
    662 		switch (attr->spd_attr_tag) {
    663 		case SPD_ATTR_NOP:
    664 		case SPD_ATTR_EMPTY:
    665 			break;
    666 		case SPD_ATTR_END:
    667 			attr = endattr;
    668 			/* FALLTHRU */
    669 		case SPD_ATTR_NEXT:
    670 			known_algs[algtype][ipsec_nalgs[algtype]] = alg;
    671 			ipsec_nalgs[algtype]++;
    672 			break;
    673 
    674 		case SPD_ATTR_ENCR_MINBITS:
    675 		case SPD_ATTR_AH_MINBITS:
    676 		case SPD_ATTR_ESPA_MINBITS:
    677 			alg.minkeybits = attr->spd_attr_value;
    678 			break;
    679 
    680 		case SPD_ATTR_ENCR_MAXBITS:
    681 		case SPD_ATTR_AH_MAXBITS:
    682 		case SPD_ATTR_ESPA_MAXBITS:
    683 			alg.maxkeybits = attr->spd_attr_value;
    684 			break;
    685 
    686 		case SPD_ATTR_ENCR_DEFBITS:
    687 		case SPD_ATTR_AH_DEFBITS:
    688 		case SPD_ATTR_ESPA_DEFBITS:
    689 			alg.defkeybits = attr->spd_attr_value;
    690 			break;
    691 
    692 		case SPD_ATTR_ENCR_INCRBITS:
    693 		case SPD_ATTR_AH_INCRBITS:
    694 		case SPD_ATTR_ESPA_INCRBITS:
    695 			alg.incr = attr->spd_attr_value;
    696 			break;
    697 
    698 		case SPD_ATTR_AH_AUTH:
    699 		case SPD_ATTR_ESP_AUTH:
    700 		case SPD_ATTR_ESP_ENCR:
    701 			alg.id = attr->spd_attr_value;
    702 			algtype = attr->spd_attr_tag - SPD_ATTR_AH_AUTH;
    703 			break;
    704 		}
    705 		attr++;
    706 	}
    707 
    708 	(void) close(sfd);
    709 }
    710 
    711 /* data dependant transform (act_cnt) */
    712 #define	ATTR(ap, tag, value) \
    713 do { (ap)->spd_attr_tag = (tag); \
    714 	(ap)->spd_attr_value = (value); \
    715 	ap++; } while (0)
    716 
    717 static struct spd_attribute *
    718 emit_alg(struct spd_attribute *ap, int type, const algreq_t *ar,
    719     int algattr, int minbitattr, int maxbitattr)
    720 {
    721 	int id = ar->alg_id;
    722 	int minbits, i;
    723 
    724 	if (id != 0) {
    725 		/* LINTED E_CONST_COND */
    726 		ATTR(ap, algattr, ar->alg_id);
    727 
    728 		minbits = ar->alg_minbits;
    729 		if (minbits == 0) {
    730 			for (i = 0; i < ipsec_nalgs[type]; i++) {
    731 				if (known_algs[type][i].id == id)
    732 					break;
    733 			}
    734 			if (i < ipsec_nalgs[type])
    735 				minbits = known_algs[type][i].defkeybits;
    736 		}
    737 		if (minbits != 0)
    738 			/* LINTED E_CONST_COND */
    739 			ATTR(ap, minbitattr, minbits);
    740 		if (ar->alg_maxbits != SPD_MAX_MAXBITS)
    741 			/* LINTED E_CONST_COND */
    742 			ATTR(ap, maxbitattr, ar->alg_maxbits);
    743 	}
    744 
    745 	return (ap);
    746 }
    747 
    748 
    749 
    750 static struct spd_attribute *
    751 ips_act_props_to_action(struct spd_attribute *ap, uint32_t *rule_priorityp,
    752     const ips_act_props_t *act_ptr)
    753 {
    754 	uint32_t rule_priority = *rule_priorityp;
    755 
    756 	/* LINTED E_CONST_COND */
    757 	ATTR(ap, SPD_ATTR_EMPTY, 0);
    758 
    759 	/* type */
    760 	/* LINTED E_CONST_COND */
    761 	ATTR(ap, SPD_ATTR_TYPE, act_ptr->iap_action);
    762 
    763 	if (act_ptr->iap_action == SPD_ACTTYPE_PASS)
    764 		rule_priority |= BYPASS_POLICY_BOOST;
    765 
    766 	/* flags */
    767 	if (act_ptr->iap_attr != 0)
    768 		/* LINTED E_CONST_COND */
    769 		ATTR(ap, SPD_ATTR_FLAGS, act_ptr->iap_attr);
    770 
    771 	/* esp */
    772 	if (act_ptr->iap_attr & SPD_APPLY_ESP) {
    773 		rule_priority |= ESP_POLICY_BOOST;
    774 
    775 		/* encr */
    776 		ap = emit_alg(ap, ESP_ENCR, &act_ptr->iap_eencr,
    777 		    SPD_ATTR_ESP_ENCR,
    778 		    SPD_ATTR_ENCR_MINBITS, SPD_ATTR_ENCR_MAXBITS);
    779 
    780 		/* auth */
    781 		ap = emit_alg(ap, ESP_AUTH, &act_ptr->iap_eauth,
    782 		    SPD_ATTR_ESP_AUTH,
    783 		    SPD_ATTR_ESPA_MINBITS, SPD_ATTR_ESPA_MAXBITS);
    784 	}
    785 
    786 	/* ah */
    787 	if (act_ptr->iap_attr & SPD_APPLY_AH) {
    788 		rule_priority |= AH_POLICY_BOOST;
    789 		/* auth */
    790 		ap = emit_alg(ap, AH_AUTH, &act_ptr->iap_aauth,
    791 		    SPD_ATTR_AH_AUTH,
    792 		    SPD_ATTR_AH_MINBITS, SPD_ATTR_AH_MAXBITS);
    793 	}
    794 
    795 	/* lifetimes */
    796 	if (act_ptr->iap_life_soft_time != 0)
    797 		/* LINTED E_CONST_COND */
    798 		ATTR(ap, SPD_ATTR_LIFE_SOFT_TIME, act_ptr->iap_life_soft_time);
    799 	if (act_ptr->iap_life_hard_time != 0)
    800 		/* LINTED E_CONST_COND */
    801 		ATTR(ap, SPD_ATTR_LIFE_HARD_TIME, act_ptr->iap_life_hard_time);
    802 	if (act_ptr->iap_life_soft_bytes != 0)
    803 		/* LINTED E_CONST_COND */
    804 		ATTR(ap, SPD_ATTR_LIFE_SOFT_BYTES,
    805 		    act_ptr->iap_life_soft_bytes);
    806 	if (act_ptr->iap_life_hard_bytes != 0)
    807 		/* LINTED E_CONST_COND */
    808 		ATTR(ap, SPD_ATTR_LIFE_HARD_BYTES,
    809 		    act_ptr->iap_life_hard_bytes);
    810 
    811 	/* LINTED E_CONST_COND */
    812 	ATTR(ap, SPD_ATTR_NEXT, 0);
    813 
    814 	*rule_priorityp = rule_priority;
    815 
    816 	return (ap);
    817 }
    818 
    819 static boolean_t
    820 alg_rangecheck(uint_t type, uint_t algid, const algreq_t *ar)
    821 {
    822 	int i;
    823 	uint_t minbits = ar->alg_minbits;
    824 	uint_t maxbits = ar->alg_maxbits;
    825 
    826 	for (i = 0; i < ipsec_nalgs[type]; i++) {
    827 		if (known_algs[type][i].id == algid)
    828 			break;
    829 	}
    830 
    831 	if (i >= ipsec_nalgs[type]) {
    832 		/*
    833 		 * The kernel (where we populate known_algs from) doesn't
    834 		 * return the id's associated with NONE algorithms so we
    835 		 * test here if this was the reason the algorithm wasn't
    836 		 * found before wrongly failing.
    837 		 */
    838 		if (((type == ESP_ENCR) && (algid == SADB_EALG_NONE)) ||
    839 		    ((type == ESP_AUTH) && (algid == SADB_AALG_NONE)) ||
    840 		    ((type == AH_AUTH) && (algid == SADB_AALG_NONE))) {
    841 			return (B_TRUE);
    842 		} else {
    843 			return (B_FALSE); /* not found */
    844 		}
    845 	}
    846 
    847 	if ((minbits == 0) && (maxbits == 0))
    848 		return (B_TRUE);
    849 
    850 	minbits = MAX(minbits, known_algs[type][i].minkeybits);
    851 	maxbits = MIN(maxbits, known_algs[type][i].maxkeybits);
    852 
    853 	/* we could also check key increments here.. */
    854 	return (minbits <= maxbits); /* non-null intersection */
    855 }
    856 
    857 /*
    858  * Inspired by uts/common/inet/spd.c:ipsec_act_wildcard_expand()
    859  */
    860 
    861 static struct spd_attribute *
    862 ips_act_wild_props_to_action(struct spd_attribute *ap,
    863     uint32_t *rule_priorityp, uint16_t *act_cntp,
    864     const ips_act_props_t *act_ptr)
    865 {
    866 	ips_act_props_t tact = *act_ptr;
    867 	boolean_t use_ah, use_esp, use_espa;
    868 	boolean_t wild_auth, wild_encr, wild_eauth;
    869 	uint_t	auth_alg, auth_idx, auth_min, auth_max;
    870 	uint_t	eauth_alg, eauth_idx, eauth_min, eauth_max;
    871 	uint_t  encr_alg, encr_idx, encr_min, encr_max;
    872 
    873 	use_ah = !!(act_ptr->iap_attr & SPD_APPLY_AH);
    874 	use_esp = !!(act_ptr->iap_attr & SPD_APPLY_ESP);
    875 	use_espa = !!(act_ptr->iap_attr & SPD_APPLY_ESPA);
    876 	auth_alg = act_ptr->iap_aauth.alg_id;
    877 	eauth_alg = act_ptr->iap_eauth.alg_id;
    878 	encr_alg = act_ptr->iap_eencr.alg_id;
    879 
    880 	wild_auth = use_ah && (auth_alg == SADB_AALG_NONE);
    881 	wild_eauth = use_espa && (eauth_alg == SADB_AALG_NONE);
    882 	wild_encr = use_esp && (encr_alg == SADB_EALG_NONE);
    883 
    884 	auth_min = auth_max = auth_alg;
    885 	eauth_min = eauth_max = eauth_alg;
    886 	encr_min = encr_max = encr_alg;
    887 
    888 	/*
    889 	 * set up for explosion.. for each dimension, expand output
    890 	 * size by the explosion factor.
    891 	 */
    892 	if (wild_auth) {
    893 		auth_min = 0;
    894 		auth_max = ipsec_nalgs[AH_AUTH] - 1;
    895 	}
    896 	if (wild_eauth) {
    897 		eauth_min = 0;
    898 		eauth_max = ipsec_nalgs[ESP_AUTH] - 1;
    899 	}
    900 	if (wild_encr) {
    901 		encr_min = 0;
    902 		encr_max = ipsec_nalgs[ESP_ENCR] - 1;
    903 	}
    904 
    905 #define	WHICH_ALG(type, wild, idx) ((wild)?(known_algs[type][idx].id):(idx))
    906 
    907 	for (encr_idx = encr_min; encr_idx <= encr_max; encr_idx++) {
    908 		encr_alg = WHICH_ALG(ESP_ENCR, wild_encr, encr_idx);
    909 
    910 		if (use_esp &&
    911 		    !alg_rangecheck(ESP_ENCR, encr_alg, &act_ptr->iap_eencr))
    912 			continue;
    913 
    914 		for (auth_idx = auth_min; auth_idx <= auth_max; auth_idx++) {
    915 			auth_alg = WHICH_ALG(AH_AUTH, wild_auth, auth_idx);
    916 
    917 			if (use_ah &&
    918 			    !alg_rangecheck(AH_AUTH, auth_alg,
    919 			    &act_ptr->iap_aauth))
    920 				continue;
    921 
    922 
    923 			for (eauth_idx = eauth_min; eauth_idx <= eauth_max;
    924 			    eauth_idx++) {
    925 				eauth_alg = WHICH_ALG(ESP_AUTH, wild_eauth,
    926 				    eauth_idx);
    927 
    928 				if (use_espa &&
    929 				    !alg_rangecheck(ESP_AUTH, eauth_alg,
    930 				    &act_ptr->iap_eauth))
    931 					continue;
    932 
    933 				tact.iap_eencr.alg_id = encr_alg;
    934 				tact.iap_eauth.alg_id = eauth_alg;
    935 				tact.iap_aauth.alg_id = auth_alg;
    936 
    937 				(*act_cntp)++;
    938 				ap = ips_act_props_to_action(ap,
    939 				    rule_priorityp, &tact);
    940 			}
    941 		}
    942 	}
    943 
    944 #undef WHICH_ALG
    945 
    946 	return (ap);
    947 }
    948 
    949 /* huge, but not safe since no length checking is done */
    950 #define	MAX_POL_MSG_LEN 16384
    951 
    952 
    953 /*
    954  * hand in some ips_conf_t's, get back an
    955  * iovec of pfpol messages.
    956  * this function converts the internal ips_conf_t into
    957  * a form that pf_pol can use.
    958  * return 0 on success, 1 on failure
    959  */
    960 static int
    961 ips_conf_to_pfpol_msg(int ipsec_cmd, ips_conf_t *inConf, int num_ips,
    962     struct iovec *msg)
    963 {
    964 	int i;
    965 	ips_conf_t *conf;
    966 	uint64_t *scratch = NULL;
    967 
    968 	for (i = 0; i < num_ips; i++) {
    969 		uint16_t *msg_len;
    970 		uint16_t act_cnt = 0;
    971 		uint64_t *next = NULL;
    972 		spd_msg_t *spd_msg;
    973 		spd_address_t *spd_address;
    974 		struct spd_rule *spd_rule;
    975 		struct spd_proto *spd_proto;
    976 		struct spd_portrange *spd_portrange;
    977 		struct spd_ext_actions *spd_ext_actions;
    978 		struct spd_attribute *ap;
    979 		struct spd_typecode *spd_typecode;
    980 		spd_if_t *spd_if;
    981 		ips_act_props_t *act_ptr;
    982 		uint32_t rule_priority = 0;
    983 
    984 		scratch = calloc(1, MAX_POL_MSG_LEN);
    985 		msg[i].iov_base = (char *)scratch;
    986 		if (scratch == NULL) {
    987 			warn(gettext("memory"));
    988 			return (1);
    989 		}
    990 		conf = &(inConf[i]);
    991 
    992 		spd_msg = (spd_msg_t *)scratch;
    993 		next = (uint64_t *)&(spd_msg[1]);
    994 
    995 		msg_len = &(spd_msg->spd_msg_len);
    996 
    997 		spd_msg->spd_msg_version = PF_POLICY_V1;
    998 		spd_msg->spd_msg_pid = getpid();
    999 		spd_msg->spd_msg_seq = ++seq_cnt;
   1000 
   1001 		switch (ipsec_cmd) {
   1002 		case SPD_ADDRULE:
   1003 			spd_msg->spd_msg_type = SPD_ADDRULE;
   1004 			break;
   1005 
   1006 		default:
   1007 			warnx("%s %d", gettext("bad command:"), ipsec_cmd);
   1008 			spd_msg->spd_msg_type = SPD_ADDRULE;
   1009 			break;
   1010 		}
   1011 
   1012 		/*
   1013 		 * SELECTOR
   1014 		 */
   1015 
   1016 		spd_msg->spd_msg_spdid = SPD_STANDBY;
   1017 
   1018 		/* rule */
   1019 		spd_rule = (struct spd_rule *)next;
   1020 
   1021 		spd_rule->spd_rule_len = SPD_8TO64(sizeof (struct spd_rule));
   1022 		spd_rule->spd_rule_type = SPD_EXT_RULE;
   1023 		spd_rule->spd_rule_flags = conf->ips_dir;
   1024 		if (conf->ips_tunnel)
   1025 			spd_rule->spd_rule_flags |= SPD_RULE_FLAG_TUNNEL;
   1026 
   1027 		next = (uint64_t *)&(spd_rule[1]);
   1028 
   1029 		/* proto */
   1030 		if (conf->ips_ulp_prot != 0) {
   1031 			spd_proto = (struct spd_proto *)next;
   1032 			spd_proto->spd_proto_len =
   1033 			    SPD_8TO64(sizeof (struct spd_proto));
   1034 			spd_proto->spd_proto_exttype = SPD_EXT_PROTO;
   1035 			spd_proto->spd_proto_number = conf->ips_ulp_prot;
   1036 			next = (uint64_t *)&(spd_proto[1]);
   1037 		}
   1038 
   1039 		/* tunnel */
   1040 		if (conf->has_tunnel != 0) {
   1041 			spd_if = (spd_if_t *)next;
   1042 			spd_if->spd_if_len =
   1043 			    SPD_8TO64(P2ROUNDUP(strlen(tunif) + 1, 8) +
   1044 			    sizeof (spd_if_t));
   1045 			spd_if->spd_if_exttype = SPD_EXT_TUN_NAME;
   1046 			(void) strlcpy((char *)spd_if->spd_if_name, tunif,
   1047 			    TUNNAMEMAXLEN);
   1048 			next = (uint64_t *)(spd_if) + spd_if->spd_if_len;
   1049 		}
   1050 
   1051 		/* icmp type/code */
   1052 		if (conf->ips_ulp_prot == IPPROTO_ICMP ||
   1053 		    conf->ips_ulp_prot == IPPROTO_ICMPV6) {
   1054 			if (conf->has_type) {
   1055 				spd_typecode = (struct spd_typecode *)next;
   1056 				spd_typecode->spd_typecode_len =
   1057 				    SPD_8TO64(sizeof (struct spd_typecode));
   1058 				spd_typecode->spd_typecode_exttype =
   1059 				    SPD_EXT_ICMP_TYPECODE;
   1060 				spd_typecode->spd_typecode_type =
   1061 				    conf->ips_icmp_type;
   1062 				spd_typecode->spd_typecode_type_end =
   1063 				    conf->ips_icmp_type_end;
   1064 				if (conf->has_code) {
   1065 					spd_typecode->spd_typecode_code =
   1066 					    conf->ips_icmp_code;
   1067 					spd_typecode->spd_typecode_code_end =
   1068 					    conf->ips_icmp_code_end;
   1069 				} else {
   1070 					spd_typecode->spd_typecode_code = 255;
   1071 					spd_typecode->spd_typecode_code_end
   1072 					    = 255;
   1073 				}
   1074 				next = (uint64_t *)&(spd_typecode[1]);
   1075 			}
   1076 		}
   1077 
   1078 		/* src port */
   1079 		if (conf->ips_src_port_min != 0 ||
   1080 		    conf->ips_src_port_max != 0) {
   1081 			spd_portrange = (struct spd_portrange *)next;
   1082 			spd_portrange->spd_ports_len =
   1083 			    SPD_8TO64(sizeof (struct spd_portrange));
   1084 			spd_portrange->spd_ports_exttype =
   1085 			    (conf->swap)?SPD_EXT_REMPORT:SPD_EXT_LCLPORT;
   1086 			spd_portrange->spd_ports_minport =
   1087 			    conf->ips_src_port_min;
   1088 			spd_portrange->spd_ports_maxport =
   1089 			    conf->ips_src_port_max;
   1090 			next = (uint64_t *)&(spd_portrange[1]);
   1091 		}
   1092 		/* dst port */
   1093 		if (conf->ips_dst_port_min != 0 ||
   1094 		    conf->ips_dst_port_max != 0) {
   1095 			spd_portrange = (struct spd_portrange *)next;
   1096 			spd_portrange->spd_ports_len =
   1097 			    SPD_8TO64(sizeof (struct spd_portrange));
   1098 			spd_portrange->spd_ports_exttype =
   1099 			    (conf->swap)?SPD_EXT_LCLPORT:SPD_EXT_REMPORT;
   1100 			spd_portrange->spd_ports_minport =
   1101 			    conf->ips_dst_port_min;
   1102 			spd_portrange->spd_ports_maxport =
   1103 			    conf->ips_dst_port_max;
   1104 			next = (uint64_t *)&(spd_portrange[1]);
   1105 		}
   1106 
   1107 		/* saddr */
   1108 		if (conf->has_saddr) {
   1109 			spd_address = (spd_address_t *)next;
   1110 			next = (uint64_t *)(spd_address + 1);
   1111 
   1112 			spd_address->spd_address_exttype =
   1113 			    (conf->swap)?SPD_EXT_REMADDR:SPD_EXT_LCLADDR;
   1114 			spd_address->spd_address_prefixlen =
   1115 			    conf->ips_src_mask_len;
   1116 
   1117 			if (conf->ips_isv4) {
   1118 				spd_address->spd_address_af = AF_INET;
   1119 				(void) memcpy(next, &(conf->ips_src_addr),
   1120 				    sizeof (ipaddr_t));
   1121 				spd_address->spd_address_len = 2;
   1122 				next += SPD_8TO64(sizeof (ipaddr_t) + 4);
   1123 				if (!conf->has_smask)
   1124 					spd_address->spd_address_prefixlen = 32;
   1125 			} else {
   1126 				spd_address->spd_address_af = AF_INET6;
   1127 				(void) memcpy(next, &(conf->ips_src_addr_v6),
   1128 				    sizeof (in6_addr_t));
   1129 				spd_address->spd_address_len = 3;
   1130 				next += SPD_8TO64(sizeof (in6_addr_t));
   1131 				if (!conf->has_smask)
   1132 					spd_address->spd_address_prefixlen
   1133 					    = 128;
   1134 			}
   1135 		}
   1136 
   1137 		/* daddr */
   1138 		if (conf->has_daddr) {
   1139 			spd_address = (spd_address_t *)next;
   1140 
   1141 			next = (uint64_t *)(spd_address + 1);
   1142 
   1143 			spd_address->spd_address_exttype =
   1144 			    (conf->swap)?SPD_EXT_LCLADDR:SPD_EXT_REMADDR;
   1145 			spd_address->spd_address_prefixlen =
   1146 			    conf->ips_dst_mask_len;
   1147 
   1148 			if (conf->ips_isv4) {
   1149 				spd_address->spd_address_af = AF_INET;
   1150 				(void) memcpy(next, &conf->ips_dst_addr,
   1151 				    sizeof (ipaddr_t));
   1152 				spd_address->spd_address_len = 2;
   1153 				/* "+ 4" below is for padding. */
   1154 				next += SPD_8TO64(sizeof (ipaddr_t) + 4);
   1155 				if (!conf->has_dmask)
   1156 					spd_address->spd_address_prefixlen = 32;
   1157 			} else {
   1158 				spd_address->spd_address_af = AF_INET6;
   1159 				(void) memcpy(next, &(conf->ips_dst_addr_v6),
   1160 				    sizeof (in6_addr_t));
   1161 				spd_address->spd_address_len = 3;
   1162 				next += SPD_8TO64(sizeof (in6_addr_t));
   1163 				if (!conf->has_dmask)
   1164 					spd_address->spd_address_prefixlen
   1165 					    = 128;
   1166 			}
   1167 		}
   1168 
   1169 		/* actions */
   1170 		spd_ext_actions = (struct spd_ext_actions *)next;
   1171 
   1172 		spd_ext_actions->spd_actions_exttype = SPD_EXT_ACTION;
   1173 
   1174 		act_ptr = conf->ips_acts;
   1175 		ap = (struct spd_attribute *)(&spd_ext_actions[1]);
   1176 
   1177 		rule_priority = priority--;
   1178 
   1179 		for (act_ptr = conf->ips_acts; act_ptr != NULL;
   1180 		    act_ptr = act_ptr->iap_next) {
   1181 			ap = ips_act_wild_props_to_action(ap, &rule_priority,
   1182 			    &act_cnt, act_ptr);
   1183 		}
   1184 		ap[-1].spd_attr_tag = SPD_ATTR_END;
   1185 
   1186 		next = (uint64_t *)ap;
   1187 
   1188 		spd_rule->spd_rule_priority = rule_priority;
   1189 
   1190 		msg[i].iov_len = (uintptr_t)next - (uintptr_t)msg[i].iov_base;
   1191 		*msg_len = (uint16_t)SPD_8TO64(msg[i].iov_len);
   1192 		spd_ext_actions->spd_actions_count = act_cnt;
   1193 		spd_ext_actions->spd_actions_len =
   1194 		    SPD_8TO64((uintptr_t)next - (uintptr_t)spd_ext_actions);
   1195 #ifdef DEBUG_HEAVY
   1196 		printf("pfpol msg len in uint64_t's = %d\n", *msg_len);
   1197 		printf("pfpol test_len in bytes = %d\n", msg[i].iov_len);
   1198 		pfpol_msg_dump((spd_msg_t *)scratch,
   1199 		    "ips_conf_to_pfpol_msg");
   1200 #endif
   1201 	}
   1202 
   1203 #undef ATTR
   1204 	return (0);
   1205 }
   1206 
   1207 static int
   1208 get_pf_pol_socket(void)
   1209 {
   1210 	int s = socket(PF_POLICY, SOCK_RAW, PF_POLICY_V1);
   1211 	if (s < 0) {
   1212 		if (errno == EPERM) {
   1213 			EXIT_BADPERM("Insufficient privileges to open "
   1214 			    "PF_POLICY socket.");
   1215 		} else {
   1216 			warn(gettext("(loading pf_policy) socket:"));
   1217 		}
   1218 	}
   1219 
   1220 	return (s);
   1221 }
   1222 
   1223 
   1224 static int
   1225 send_pf_pol_message(int ipsec_cmd, ips_conf_t *conf, int *diag)
   1226 {
   1227 	int retval;
   1228 	int cnt;
   1229 	int total_len;
   1230 	struct iovec polmsg;
   1231 	spd_msg_t *return_buf;
   1232 	spd_ext_t *exts[SPD_EXT_MAX+1];
   1233 	int fd = get_pf_pol_socket();
   1234 
   1235 	*diag = 0;
   1236 
   1237 	if (fd < 0)
   1238 		return (EBADF);
   1239 
   1240 	retval = ips_conf_to_pfpol_msg(ipsec_cmd, conf, 1, &polmsg);
   1241 
   1242 	if (retval) {
   1243 		(void) close(fd);
   1244 		return (ENOMEM);
   1245 	}
   1246 
   1247 	total_len = polmsg.iov_len;
   1248 
   1249 	cnt = writev(fd, &polmsg, 1);
   1250 
   1251 #ifdef DEBUG_HEAVY
   1252 	(void) printf("cnt = %d\n", cnt);
   1253 #endif
   1254 	if (cnt < 0) {
   1255 		warn(gettext("pf_pol write"));
   1256 	} else {
   1257 		return_buf = (spd_msg_t *)calloc(total_len, 1);
   1258 
   1259 		if (return_buf == NULL) {
   1260 			warn(gettext("memory"));
   1261 		} else {
   1262 			cnt = read(fd, (void*)return_buf, total_len);
   1263 #ifdef	DEBUG_HEAVY
   1264 			(void) printf("pf_pol read: cnt = %d(%d)\n", cnt,
   1265 			    total_len);
   1266 #endif
   1267 
   1268 			if (cnt > 8 && return_buf->spd_msg_errno) {
   1269 				*diag = return_buf->spd_msg_diagnostic;
   1270 				if (!ipsecconf_qflag) {
   1271 					warnx("%s: %s",
   1272 					    gettext("Kernel returned"),
   1273 					    sys_error_message(
   1274 					    return_buf->spd_msg_errno));
   1275 				}
   1276 				if (*diag != 0)
   1277 					(void) printf(gettext(
   1278 					    "\t(spdsock diagnostic: %s)\n"),
   1279 					    spdsock_diag(*diag));
   1280 #ifdef DEBUG_HEAVY
   1281 				pfpol_msg_dump((spd_msg_t *)polmsg.iov_base,
   1282 				    "message in");
   1283 				pfpol_msg_dump(return_buf,
   1284 				    "send_pf_pol_message");
   1285 #endif
   1286 				retval = return_buf->spd_msg_errno;
   1287 				free(return_buf);
   1288 				free(polmsg.iov_base);
   1289 				(void) close(fd);
   1290 				return (retval);
   1291 			}
   1292 
   1293 			retval = spdsock_get_ext(exts, return_buf,
   1294 			    return_buf->spd_msg_len, NULL, 0);
   1295 			/* ignore retval */
   1296 
   1297 			if (exts[SPD_EXT_RULE]) {
   1298 				conf->ips_policy_index =
   1299 				    ((struct spd_rule *)
   1300 				    exts[SPD_EXT_RULE])->spd_rule_index;
   1301 
   1302 				if (add_index(conf->ips_policy_index)) {
   1303 					free(return_buf);
   1304 					free(polmsg.iov_base);
   1305 					(void) close(fd);
   1306 					return (ENOMEM);
   1307 				}
   1308 			}
   1309 
   1310 			free(return_buf);
   1311 		}
   1312 	}
   1313 
   1314 	free(polmsg.iov_base);
   1315 	(void) close(fd);
   1316 
   1317 	return (0);
   1318 
   1319 }
   1320 
   1321 int
   1322 main(int argc, char *argv[])
   1323 {
   1324 	int ret, flushret;
   1325 	int c;
   1326 	int index;
   1327 	boolean_t smf_managed;
   1328 	boolean_t just_check = B_FALSE;
   1329 	boolean_t replace_policy = B_FALSE;
   1330 
   1331 	char *smf_warning = gettext(
   1332 	    "\n\tIPsec policy should be managed using smf(5). Modifying\n"
   1333 	    "\tthe IPsec policy from the command line while the 'policy'\n"
   1334 	    "\tservice is enabled could result in an inconsistent\n"
   1335 	    "\tsecurity policy.\n\n");
   1336 
   1337 	flushret = 0;
   1338 	cmd = 0;
   1339 
   1340 	(void) setlocale(LC_ALL, "");
   1341 #if !defined(TEXT_DOMAIN)
   1342 #define	TEXT_DOMAIN "SYS_TEST"
   1343 #endif
   1344 	(void) textdomain(TEXT_DOMAIN);
   1345 
   1346 	openlog("ipsecconf", LOG_CONS, LOG_AUTH);
   1347 
   1348 	/*
   1349 	 * We don't immediately check for privilege here. This is done by IP
   1350 	 * when we open /dev/ip below.
   1351 	 */
   1352 
   1353 	if (argc == 1) {
   1354 		cmd = IPSEC_CONF_VIEW;
   1355 		goto done;
   1356 	}
   1357 	my_fmri = getenv("SMF_FMRI");
   1358 	if (my_fmri == NULL)
   1359 		smf_managed = B_FALSE;
   1360 	else
   1361 		smf_managed = B_TRUE;
   1362 
   1363 	while ((c = getopt(argc, argv, "nlfLFa:qd:r:i:c:")) != EOF) {
   1364 		switch (c) {
   1365 		case 'F':
   1366 			if (interface_name != NULL) {
   1367 				USAGE();
   1368 				EXIT_FATAL("interface name not required.");
   1369 			}
   1370 			/* Apply to all policy heads - global and tunnels. */
   1371 			interface_name = &all_polheads;
   1372 			/* FALLTHRU */
   1373 		case 'f':
   1374 			/*
   1375 			 * The policy flush command can be specified with -a
   1376 			 * to perform an atomic policy replace. It can't be
   1377 			 * specified with any other flags.
   1378 			 */
   1379 			if (cmd == IPSEC_CONF_ADD) {
   1380 				cmd = IPSEC_CONF_REPLACE;
   1381 				break;
   1382 			}
   1383 			if (cmd != 0) {
   1384 				USAGE();
   1385 				EXIT_FATAL("Multiple commands specified");
   1386 			}
   1387 			cmd = IPSEC_CONF_FLUSH;
   1388 			break;
   1389 		case 'L':
   1390 			if (interface_name != NULL) {
   1391 				USAGE();
   1392 				EXIT_FATAL("interface name not required.");
   1393 			}
   1394 			/* Apply to all policy heads - global and tunnels. */
   1395 			interface_name = &all_polheads;
   1396 			/* FALLTHRU */
   1397 		case 'l':
   1398 			/* Only one command at a time */
   1399 			if (cmd != 0) {
   1400 				USAGE();
   1401 				EXIT_FATAL("Multiple commands specified");
   1402 			}
   1403 			cmd = IPSEC_CONF_LIST;
   1404 			break;
   1405 		case 'c':
   1406 			just_check = B_TRUE;
   1407 			ipsecconf_qflag++;
   1408 			/* FALLTHRU */
   1409 		case 'a':
   1410 			if (cmd == IPSEC_CONF_FLUSH) {
   1411 				cmd = IPSEC_CONF_REPLACE;
   1412 				filename = optarg;
   1413 				break;
   1414 			}
   1415 			/* Only one command at a time, and no interface name */
   1416 			if (cmd != 0 || interface_name != NULL) {
   1417 				USAGE();
   1418 				EXIT_FATAL("Multiple commands or interface "
   1419 				    "not required.");
   1420 			}
   1421 			cmd = IPSEC_CONF_ADD;
   1422 			filename = optarg;
   1423 			break;
   1424 		case 'd':
   1425 			/*
   1426 			 * Only one command at a time.  Interface name is
   1427 			 * optional.
   1428 			 */
   1429 			if (cmd != 0) {
   1430 				USAGE();
   1431 				EXIT_FATAL("Multiple commands specified");
   1432 			}
   1433 			cmd = IPSEC_CONF_DEL;
   1434 			index = parse_index(optarg, NULL);
   1435 			break;
   1436 		case 'n' :
   1437 			ipsecconf_nflag++;
   1438 			break;
   1439 		case 'q' :
   1440 			ipsecconf_qflag++;
   1441 			break;
   1442 		case 'r' :
   1443 			/* Only one command at a time, and no interface name */
   1444 			if (cmd != 0 || interface_name != NULL) {
   1445 				USAGE();
   1446 				EXIT_FATAL("Multiple commands or interface "
   1447 				    "not required.");
   1448 			}
   1449 			cmd = IPSEC_CONF_SUB;
   1450 			filename = optarg;
   1451 			break;
   1452 		case 'i':
   1453 			if (interface_name != NULL) {
   1454 				EXIT_FATAL("Interface name already selected");
   1455 			}
   1456 			interface_name = optarg;
   1457 			/* Check for some cretin using the all-polheads name. */
   1458 			if (strlen(optarg) == 0) {
   1459 				USAGE();
   1460 				EXIT_FATAL("Invalid interface name.");
   1461 			}
   1462 			break;
   1463 		default :
   1464 			USAGE();
   1465 			EXIT_FATAL("Bad usage.");
   1466 		}
   1467 	}
   1468 
   1469 done:
   1470 	ret = 0;
   1471 	lfd = lock();
   1472 
   1473 	/*
   1474 	 * ADD, FLUSH, DELETE needs to do two operations.
   1475 	 *
   1476 	 * 1) Update/delete/empty the POLICY_CONF_FILE.
   1477 	 * 2) Make an ioctl and tell IP to update its state.
   1478 	 *
   1479 	 * We already lock()ed so that only one instance of this
   1480 	 * program runs. We also need to make sure that the above
   1481 	 * operations are atomic i.e we don't want to update the file
   1482 	 * and get interrupted before we could tell IP. To make it
   1483 	 * atomic we block all the signals and restore them.
   1484 	 */
   1485 	switch (cmd) {
   1486 	case IPSEC_CONF_LIST:
   1487 		fetch_algorithms();
   1488 		ret = ipsec_conf_list();
   1489 		break;
   1490 	case IPSEC_CONF_FLUSH:
   1491 		if ((ret = block_all_signals()) == -1) {
   1492 			break;
   1493 		}
   1494 		if (!smf_managed && !ipsecconf_qflag)
   1495 			(void) fprintf(stdout, "%s", smf_warning);
   1496 		ret = ipsec_conf_flush(SPD_ACTIVE);
   1497 		(void) restore_all_signals();
   1498 		break;
   1499 	case IPSEC_CONF_VIEW:
   1500 		if (interface_name != NULL) {
   1501 			EXIT_FATAL("Cannot view for one interface only.");
   1502 		}
   1503 		ret = ipsec_conf_view();
   1504 		break;
   1505 	case IPSEC_CONF_DEL:
   1506 		if (index == -1) {
   1507 			warnx(gettext("Invalid index"));
   1508 			ret = -1;
   1509 			break;
   1510 		}
   1511 		if ((ret = block_all_signals()) == -1) {
   1512 			break;
   1513 		}
   1514 		if (!smf_managed && !ipsecconf_qflag)
   1515 			(void) fprintf(stdout, "%s", smf_warning);
   1516 		ret = ipsec_conf_del(index, B_FALSE);
   1517 		(void) restore_all_signals();
   1518 		flushret = ipsec_conf_flush(SPD_STANDBY);
   1519 		break;
   1520 	case IPSEC_CONF_REPLACE:
   1521 		replace_policy = B_TRUE;
   1522 		/* FALLTHRU */
   1523 	case IPSEC_CONF_ADD:
   1524 		/*
   1525 		 * The IPsec kernel modules should only be loaded
   1526 		 * if there is a policy to install, for this
   1527 		 * reason ipsec_conf_add() calls fetch_algorithms()
   1528 		 * and ipsec_conf_flush() only when appropriate.
   1529 		 */
   1530 		if ((ret = block_all_signals()) == -1) {
   1531 			break;
   1532 		}
   1533 		if (!smf_managed && !ipsecconf_qflag)
   1534 			(void) fprintf(stdout, "%s", smf_warning);
   1535 		ret = ipsec_conf_add(just_check, smf_managed, replace_policy);
   1536 		(void) restore_all_signals();
   1537 		break;
   1538 	case IPSEC_CONF_SUB:
   1539 		fetch_algorithms();
   1540 		if ((ret = block_all_signals()) == -1) {
   1541 			break;
   1542 		}
   1543 		if (!smf_managed && !ipsecconf_qflag)
   1544 			(void) fprintf(stdout, "%s", smf_warning);
   1545 		ret = ipsec_conf_sub();
   1546 		(void) restore_all_signals();
   1547 		flushret = ipsec_conf_flush(SPD_STANDBY);
   1548 		break;
   1549 	default :
   1550 		/* If no argument is given but a "-" */
   1551 		USAGE();
   1552 		EXIT_FATAL("Bad usage.");
   1553 	}
   1554 
   1555 	(void) unlock(lfd);
   1556 	if (ret != 0 || flushret != 0)
   1557 		ret = 1;
   1558 	return (ret);
   1559 }
   1560 
   1561 static void
   1562 perm_check(void)
   1563 {
   1564 	if (errno == EACCES)
   1565 		EXIT_BADPERM("Insufficient privilege to run ipsecconf.");
   1566 	else
   1567 		warn(gettext("Cannot open lock file %s"), LOCK_FILE);
   1568 
   1569 	EXIT_BADPERM(NULL);
   1570 }
   1571 
   1572 static int
   1573 lock()
   1574 {
   1575 	int fd;
   1576 	struct stat sbuf1;
   1577 	struct stat sbuf2;
   1578 
   1579 	/*
   1580 	 * Open the file with O_CREAT|O_EXCL. If it exists already, it
   1581 	 * will fail. If it already exists, check whether it looks like
   1582 	 * the one we created.
   1583 	 */
   1584 	(void) umask(0077);
   1585 	if ((fd = open(LOCK_FILE, O_EXCL|O_CREAT|O_RDWR, S_IRUSR|S_IWUSR))
   1586 	    == -1) {
   1587 		if (errno != EEXIST) {
   1588 			/* Some other problem. Will exit. */
   1589 			perm_check();
   1590 		}
   1591 
   1592 		/*
   1593 		 * open() returned an EEXIST error. We don't fail yet
   1594 		 * as it could be a residual from a previous
   1595 		 * execution.
   1596 		 * File exists. make sure it is OK. We need to lstat()
   1597 		 * as fstat() stats the file pointed to by the symbolic
   1598 		 * link.
   1599 		 */
   1600 		if (lstat(LOCK_FILE, &sbuf1) == -1) {
   1601 			EXIT_FATAL2("Cannot lstat lock file %s", LOCK_FILE);
   1602 		}
   1603 		/*
   1604 		 * Check whether it is a regular file and not a symbolic
   1605 		 * link. Its link count should be 1. The owner should be
   1606 		 * root and the file should be empty.
   1607 		 */
   1608 		if (!S_ISREG(sbuf1.st_mode) ||
   1609 		    sbuf1.st_nlink != 1 ||
   1610 		    sbuf1.st_uid != 0 ||
   1611 		    sbuf1.st_size != 0) {
   1612 			EXIT_FATAL2("Bad lock file %s", LOCK_FILE);
   1613 		}
   1614 		if ((fd = open(LOCK_FILE, O_CREAT|O_RDWR,
   1615 		    S_IRUSR|S_IWUSR)) == -1) {
   1616 			/* Will exit */
   1617 			perm_check();
   1618 		}
   1619 		/*
   1620 		 * Check whether we opened the file that we lstat()ed.
   1621 		 */
   1622 		if (fstat(fd, &sbuf2) == -1) {
   1623 			EXIT_FATAL2("Cannot lstat lock file %s", LOCK_FILE);
   1624 		}
   1625 		if (sbuf1.st_dev != sbuf2.st_dev ||
   1626 		    sbuf1.st_ino != sbuf2.st_ino) {
   1627 			/* File changed after we did the lstat() above */
   1628 			EXIT_FATAL2("Bad lock file %s", LOCK_FILE);
   1629 		}
   1630 	}
   1631 	if (lockf(fd, F_LOCK, 0) == -1) {
   1632 		EXIT_FATAL2("Cannot lockf %s", LOCK_FILE);
   1633 	}
   1634 	return (fd);
   1635 }
   1636 
   1637 static int
   1638 unlock(int fd)
   1639 {
   1640 	if (lockf(fd, F_ULOCK, 0) == -1) {
   1641 		warn("lockf");
   1642 		return (-1);
   1643 	}
   1644 	return (0);
   1645 }
   1646 
   1647 /* send in TOK_* */
   1648 static void
   1649 print_pattern_string(int type)
   1650 {
   1651 	int j;
   1652 
   1653 	for (j = 0; pattern_table[j].string != NULL; j++) {
   1654 		if (type == pattern_table[j].tok_val) {
   1655 			(void) printf("%s ", pattern_table[j].string);
   1656 			return;
   1657 		}
   1658 	}
   1659 }
   1660 
   1661 static void
   1662 print_icmp_typecode(uint8_t type, uint8_t type_end, uint8_t code,
   1663     uint8_t code_end)
   1664 {
   1665 	(void) printf("type %d", type);
   1666 	if (type_end != type)
   1667 		(void) printf("-%d ", type_end);
   1668 	else
   1669 		(void) printf(" ");
   1670 	if (code != 255) {
   1671 		(void) printf("code %d", code);
   1672 		if (code_end != code)
   1673 			(void) printf("-%d ", code_end);
   1674 		else
   1675 			(void) printf(" ");
   1676 	}
   1677 }
   1678 
   1679 
   1680 static void
   1681 print_spd_flags(uint32_t flags)
   1682 {
   1683 	flags &= (SPD_RULE_FLAG_INBOUND|SPD_RULE_FLAG_OUTBOUND);
   1684 
   1685 	if (flags == SPD_RULE_FLAG_OUTBOUND)
   1686 		(void) printf("dir out ");
   1687 	else if (flags == SPD_RULE_FLAG_INBOUND)
   1688 		(void) printf("dir in ");
   1689 	else if (flags == (SPD_RULE_FLAG_INBOUND|SPD_RULE_FLAG_OUTBOUND))
   1690 		(void) printf("dir both ");
   1691 }
   1692 
   1693 static void
   1694 print_bit_range(int min, int max)
   1695 {
   1696 	if (min != 0 || (max != 0 && max != SPD_MAX_MAXBITS)) {
   1697 		(void) printf("(");
   1698 		if (min != 0)
   1699 			(void) printf("%d", min);
   1700 		if (min != 0 && max != 0 && min != max) {
   1701 			(void) printf("..");
   1702 			if (max != 0 && max != SPD_MAX_MAXBITS)
   1703 				(void) printf("%d", max);
   1704 		}
   1705 		(void) printf(")");
   1706 	}
   1707 }
   1708 
   1709 static void
   1710 print_alg(const char *tag, algreq_t *algreq, int proto_num)
   1711 {
   1712 	int min = algreq->alg_minbits;
   1713 	int max = algreq->alg_maxbits;
   1714 	struct ipsecalgent *alg;
   1715 
   1716 	/*
   1717 	 * This function won't be called with alg_id == 0, so we don't
   1718 	 * have to worry about ANY vs. NONE here.
   1719 	 */
   1720 
   1721 	(void) printf("%s ", tag);
   1722 
   1723 	alg = getipsecalgbynum(algreq->alg_id, proto_num, NULL);
   1724 	if (alg == NULL) {
   1725 		(void) printf("%d", algreq->alg_id);
   1726 	} else {
   1727 		(void) printf("%s", alg->a_names[0]);
   1728 		freeipsecalgent(alg);
   1729 	}
   1730 
   1731 	print_bit_range(min, max);
   1732 	(void) printf(" ");
   1733 }
   1734 
   1735 static void
   1736 print_ulp(uint8_t proto)
   1737 {
   1738 	struct protoent *pe;
   1739 
   1740 	if (proto == 0)
   1741 		return;
   1742 
   1743 	print_pattern_string(TOK_ulp);
   1744 	pe = NULL;
   1745 	if (!ipsecconf_nflag) {
   1746 		pe = getprotobynumber(proto);
   1747 	}
   1748 	if (pe != NULL)
   1749 		(void) printf("%s ", pe->p_name);
   1750 	else
   1751 		(void) printf("%d ", proto);
   1752 }
   1753 
   1754 /* needs to do ranges */
   1755 static void
   1756 print_port(uint16_t in_port, int type)
   1757 {
   1758 	in_port_t port = ntohs(in_port);
   1759 	struct servent *sp;
   1760 
   1761 	if (port == 0)
   1762 		return;
   1763 
   1764 	print_pattern_string(type);
   1765 	sp = NULL;
   1766 	if (!ipsecconf_nflag)
   1767 		sp = getservbyport(port, NULL);
   1768 
   1769 	if (sp != NULL)
   1770 		(void) printf("%s ", sp->s_name);
   1771 	else
   1772 		(void) printf("%d ", port);
   1773 }
   1774 
   1775 /*
   1776  * Print the address, given as "raw" input via the void pointer.
   1777  */
   1778 static void
   1779 print_raw_address(void *input, boolean_t isv4)
   1780 {
   1781 	char  *cp;
   1782 	struct hostent *hp;
   1783 	char	domain[MAXHOSTNAMELEN + 1];
   1784 	struct in_addr addr;
   1785 	struct in6_addr addr6;
   1786 	char abuf[INET6_ADDRSTRLEN];
   1787 	int error_num;
   1788 	struct in6_addr in_addr;
   1789 	uchar_t *addr_ptr;
   1790 	sa_family_t af;
   1791 	int addr_len;
   1792 
   1793 	if (isv4) {
   1794 		af = AF_INET;
   1795 		(void) memcpy(&V4_PART_OF_V6(in_addr), input, 4);
   1796 		/* we don't print unspecified addresses */
   1797 		IN6_V4MAPPED_TO_INADDR(&in_addr, &addr);
   1798 		if (addr.s_addr == INADDR_ANY)
   1799 			return;
   1800 		addr_ptr = (uchar_t *)&addr.s_addr;
   1801 		addr_len = IPV4_ADDR_LEN;
   1802 	} else {
   1803 		(void) memcpy(&addr6, input, 16);
   1804 		af = AF_INET6;
   1805 		/* we don't print unspecified addresses */
   1806 		if (IN6_IS_ADDR_UNSPECIFIED(&addr6))
   1807 			return;
   1808 		addr_ptr = (uchar_t *)&addr6.s6_addr;
   1809 		addr_len = sizeof (struct in6_addr);
   1810 	}
   1811 
   1812 	cp = NULL;
   1813 	if (!ipsecconf_nflag) {
   1814 		if (sysinfo(SI_HOSTNAME, domain, MAXHOSTNAMELEN) != -1 &&
   1815 		    (cp = strchr(domain, '.')) != NULL) {
   1816 			(void) strlcpy(domain, cp + 1, sizeof (domain));
   1817 		} else {
   1818 			domain[0] = 0;
   1819 		}
   1820 		cp = NULL;
   1821 		hp = getipnodebyaddr(addr_ptr, addr_len, af, &error_num);
   1822 		if (hp) {
   1823 			if ((cp = strchr(hp->h_name, '.')) != 0 &&
   1824 			    strcasecmp(cp + 1, domain) == 0)
   1825 				*cp = 0;
   1826 			cp = hp->h_name;
   1827 		}
   1828 	}
   1829 
   1830 	if (cp) {
   1831 		(void) printf("%s", cp);
   1832 	} else {
   1833 		(void) printf("%s", inet_ntop(af, addr_ptr, abuf,
   1834 		    INET6_ADDRSTRLEN));
   1835 	}
   1836 }
   1837 
   1838 /*
   1839  * Get the next SPD_DUMP message from the PF_POLICY socket.  A single
   1840  * read may contain multiple messages.  This function uses static buffers,
   1841  * and is therefore non-reentrant, so if you lift it for an MT application,
   1842  * be careful.
   1843  *
   1844  * Return NULL if there's an error.
   1845  */
   1846 static spd_msg_t *
   1847 ipsec_read_dump(int pfd)
   1848 {
   1849 	static uint64_t buf[SADB_8TO64(CBUF_LEN)];
   1850 	static uint64_t *offset;
   1851 	static int len;		/* In uint64_t units. */
   1852 	spd_msg_t *retval;
   1853 
   1854 	/* Assume offset and len are initialized to NULL and 0. */
   1855 
   1856 	if ((offset - len == buf) || (offset == NULL)) {
   1857 		/* read a new block from the socket. */
   1858 		len = read(pfd, &buf, sizeof (buf));
   1859 		if (len == -1) {
   1860 			warn(gettext("rule dump: bad read"));
   1861 			return (NULL);
   1862 		}
   1863 		offset = buf;
   1864 		len = SADB_8TO64(len);
   1865 	} /* Else I still have more messages from a previous read. */
   1866 
   1867 	retval = (spd_msg_t *)offset;
   1868 	offset += retval->spd_msg_len;
   1869 	if (offset > buf + len) {
   1870 		warnx(gettext("dump read: message corruption,"
   1871 		    " %d len exceeds %d boundary."),
   1872 		    SADB_64TO8((uintptr_t)(offset - buf)),
   1873 		    SADB_64TO8((uintptr_t)(buf + len)));
   1874 		return (NULL);
   1875 	}
   1876 
   1877 	return (retval);
   1878 }
   1879 
   1880 /*
   1881  * returns 0 on success
   1882  * -1 on read error
   1883  * >0  on invalid returned message
   1884  */
   1885 
   1886 static int
   1887 ipsec_conf_list(void)
   1888 {
   1889 	int ret;
   1890 	int pfd;
   1891 	struct spd_msg *msg;
   1892 	int cnt;
   1893 	spd_msg_t *rmsg;
   1894 	spd_ext_t *exts[SPD_EXT_MAX+1];
   1895 	/*
   1896 	 * Add an extra 8 bytes of space (+1 uint64_t) to avoid truncation
   1897 	 * issues.
   1898 	 */
   1899 	uint64_t buffer[
   1900 	    SPD_8TO64(sizeof (*msg) + sizeof (spd_if_t) + LIFNAMSIZ) + 1];
   1901 
   1902 	pfd = get_pf_pol_socket();
   1903 
   1904 	if (pfd == -1) {
   1905 		warnx(gettext("Error getting list of policies from kernel"));
   1906 		return (-1);
   1907 	}
   1908 
   1909 	(void) memset(buffer, 0, sizeof (buffer));
   1910 	msg = (struct spd_msg *)buffer;
   1911 	msg->spd_msg_version = PF_POLICY_V1;
   1912 	msg->spd_msg_type = SPD_DUMP;
   1913 	msg->spd_msg_len = SPD_8TO64(sizeof (*msg));
   1914 
   1915 	msg->spd_msg_len += attach_tunname((spd_if_t *)(msg + 1));
   1916 
   1917 	cnt = write(pfd, msg, SPD_64TO8(msg->spd_msg_len));
   1918 
   1919 	if (cnt < 0) {
   1920 		warn(gettext("dump: invalid write() return"));
   1921 		(void) close(pfd);
   1922 		return (-1);
   1923 	}
   1924 
   1925 	rmsg = ipsec_read_dump(pfd);
   1926 
   1927 	if (rmsg == NULL || rmsg->spd_msg_errno != 0) {
   1928 		warnx("%s: %s", gettext("ruleset dump failed"),
   1929 		    (rmsg == NULL ?
   1930 		    gettext("read error") :
   1931 		    sys_error_message(rmsg->spd_msg_errno)));
   1932 		(void) close(pfd);
   1933 		return (-1);
   1934 	}
   1935 
   1936 
   1937 	for (;;) {
   1938 		/* read rule */
   1939 		rmsg = ipsec_read_dump(pfd);
   1940 
   1941 		if (rmsg == NULL) {
   1942 			(void) close(pfd);
   1943 			return (-1);
   1944 		}
   1945 
   1946 		if (rmsg->spd_msg_errno != 0) {
   1947 			warnx("%s: %s", gettext("dump read: bad message"),
   1948 			    sys_error_message(rmsg->spd_msg_errno));
   1949 			(void) close(pfd);
   1950 			return (-1);
   1951 		}
   1952 
   1953 		ret = spdsock_get_ext(exts, rmsg, rmsg->spd_msg_len,
   1954 		    spdsock_diag_buf, SPDSOCK_DIAG_BUF_LEN);
   1955 		if (ret != 0) {
   1956 			if (strlen(spdsock_diag_buf) != 0)
   1957 				warnx(spdsock_diag_buf);
   1958 			warnx("%s: %s", gettext("dump read: bad message"),
   1959 			    sys_error_message(rmsg->spd_msg_errno));
   1960 			(void) close(pfd);
   1961 			return (ret);
   1962 		}
   1963 
   1964 		/*
   1965 		 * End of dump..
   1966 		 */
   1967 		if (exts[SPD_EXT_RULESET] != NULL)
   1968 			break;	/* and return 0. */
   1969 
   1970 		print_pfpol_msg(rmsg);
   1971 	}
   1972 
   1973 	(void) close(pfd);
   1974 	return (0);
   1975 }
   1976 
   1977 static void
   1978 print_iap(ips_act_props_t *iap)
   1979 {
   1980 
   1981 	/* action */
   1982 	switch (iap->iap_action) {
   1983 	case SPD_ACTTYPE_PASS:
   1984 		(void) printf("pass ");
   1985 		break;
   1986 	case SPD_ACTTYPE_DROP:
   1987 		(void) printf("drop ");
   1988 		break;
   1989 	case SPD_ACTTYPE_IPSEC:
   1990 		(void) printf("ipsec ");
   1991 		break;
   1992 	}
   1993 
   1994 	/* properties */
   1995 	(void) printf("%c ", CURL_BEGIN);
   1996 	if (iap->iap_action == SPD_ACTTYPE_IPSEC) {
   1997 		if (iap->iap_attr & SPD_APPLY_AH &&
   1998 		    iap->iap_aauth.alg_id != 0)
   1999 			print_alg("auth_algs", &iap->iap_aauth,
   2000 			    IPSEC_PROTO_AH);
   2001 
   2002 		if (iap->iap_attr & SPD_APPLY_ESP) {
   2003 			print_alg("encr_algs", &iap->iap_eencr,
   2004 			    IPSEC_PROTO_ESP);
   2005 			if (iap->iap_eauth.alg_id != 0)
   2006 				print_alg("encr_auth_algs", &iap->iap_eauth,
   2007 				    IPSEC_PROTO_AH);
   2008 		}
   2009 		if (iap->iap_attr & SPD_APPLY_UNIQUE)
   2010 			(void) printf("sa unique ");
   2011 		else
   2012 			(void) printf("sa shared ");
   2013 	}
   2014 	(void) printf("%c ", CURL_END);
   2015 }
   2016 
   2017 
   2018 static void
   2019 print_pfpol_msg(spd_msg_t *msg)
   2020 {
   2021 	spd_ext_t *exts[SPD_EXT_MAX+1];
   2022 	spd_address_t *spd_address;
   2023 	struct spd_rule *spd_rule;
   2024 	struct spd_proto *spd_proto;
   2025 	struct spd_portrange *spd_portrange;
   2026 	struct spd_ext_actions *spd_ext_actions;
   2027 	struct spd_typecode *spd_typecode;
   2028 	struct spd_attribute *app;
   2029 	spd_if_t *spd_if;
   2030 	uint32_t rv;
   2031 	uint16_t act_count;
   2032 
   2033 	rv = spdsock_get_ext(exts, msg, msg->spd_msg_len, spdsock_diag_buf,
   2034 	    SPDSOCK_DIAG_BUF_LEN);
   2035 
   2036 	if (rv == KGE_OK && exts[SPD_EXT_RULE] != NULL) {
   2037 		spd_if = (spd_if_t *)exts[SPD_EXT_TUN_NAME];
   2038 		spd_rule = (struct spd_rule *)exts[SPD_EXT_RULE];
   2039 		if (spd_if == NULL) {
   2040 			(void) printf("%s %lld\n", INDEX_TAG,
   2041 			    spd_rule->spd_rule_index);
   2042 		} else {
   2043 			(void) printf("%s %s,%lld\n", INDEX_TAG,
   2044 			    (char *)spd_if->spd_if_name,
   2045 			    spd_rule->spd_rule_index);
   2046 		}
   2047 	} else {
   2048 		if (strlen(spdsock_diag_buf) != 0)
   2049 			warnx(spdsock_diag_buf);
   2050 		warnx(gettext("print_pfpol_msg: malformed PF_POLICY message."));
   2051 		return;
   2052 	}
   2053 
   2054 	(void) printf("%c ", CURL_BEGIN);
   2055 
   2056 	if (spd_if != NULL) {
   2057 		(void) printf("tunnel %s negotiate %s ",
   2058 		    (char *)spd_if->spd_if_name,
   2059 		    (spd_rule->spd_rule_flags & SPD_RULE_FLAG_TUNNEL) ?
   2060 		    "tunnel" : "transport");
   2061 	}
   2062 
   2063 	if (exts[SPD_EXT_PROTO] != NULL) {
   2064 		spd_proto = (struct spd_proto *)exts[SPD_EXT_PROTO];
   2065 		print_ulp(spd_proto->spd_proto_number);
   2066 	}
   2067 
   2068 	if (exts[SPD_EXT_LCLADDR] != NULL) {
   2069 		spd_address = (spd_address_t *)exts[SPD_EXT_LCLADDR];
   2070 
   2071 		(void) printf("laddr ");
   2072 		print_raw_address((spd_address + 1),
   2073 		    (spd_address->spd_address_len == 2));
   2074 		(void) printf("/%d ", spd_address->spd_address_prefixlen);
   2075 	}
   2076 
   2077 	if (exts[SPD_EXT_LCLPORT] != NULL) {
   2078 		spd_portrange = (struct spd_portrange *)exts[SPD_EXT_LCLPORT];
   2079 		if (spd_portrange->spd_ports_minport != 0) {
   2080 			print_port(spd_portrange->spd_ports_minport,
   2081 			    TOK_lport);
   2082 		}
   2083 	}
   2084 
   2085 
   2086 	if (exts[SPD_EXT_REMADDR] != NULL) {
   2087 		spd_address = (spd_address_t *)exts[SPD_EXT_REMADDR];
   2088 
   2089 		(void) printf("raddr ");
   2090 		print_raw_address((spd_address + 1),
   2091 		    (spd_address->spd_address_len == 2));
   2092 		(void) printf("/%d ", spd_address->spd_address_prefixlen);
   2093 	}
   2094 
   2095 	if (exts[SPD_EXT_REMPORT] != NULL) {
   2096 		spd_portrange =
   2097 		    (struct spd_portrange *)exts[SPD_EXT_REMPORT];
   2098 		if (spd_portrange->spd_ports_minport != 0) {
   2099 			print_port(
   2100 			    spd_portrange->spd_ports_minport, TOK_rport);
   2101 		}
   2102 	}
   2103 
   2104 	if (exts[SPD_EXT_ICMP_TYPECODE] != NULL) {
   2105 		spd_typecode =
   2106 		    (struct spd_typecode *)exts[SPD_EXT_ICMP_TYPECODE];
   2107 		print_icmp_typecode(spd_typecode->spd_typecode_type,
   2108 		    spd_typecode->spd_typecode_type_end,
   2109 		    spd_typecode->spd_typecode_code,
   2110 		    spd_typecode->spd_typecode_code_end);
   2111 	}
   2112 
   2113 	if (exts[SPD_EXT_RULE] != NULL) {
   2114 		spd_rule = (struct spd_rule *)exts[SPD_EXT_RULE];
   2115 		print_spd_flags(spd_rule->spd_rule_flags);
   2116 	}
   2117 
   2118 
   2119 	(void) printf("%c ", CURL_END);
   2120 
   2121 	if (exts[SPD_EXT_ACTION] != NULL) {
   2122 		ips_act_props_t iap;
   2123 		int or_needed = 0;
   2124 
   2125 		(void) memset(&iap, 0, sizeof (iap));
   2126 		spd_ext_actions =
   2127 		    (struct spd_ext_actions *)exts[SPD_EXT_ACTION];
   2128 		app = (struct spd_attribute *)(spd_ext_actions + 1);
   2129 
   2130 		for (act_count = 0;
   2131 		    act_count < spd_ext_actions->spd_actions_len -1;
   2132 		    act_count++) {
   2133 
   2134 			switch (app->spd_attr_tag) {
   2135 
   2136 			case SPD_ATTR_NOP:
   2137 				break;
   2138 
   2139 			case SPD_ATTR_END:
   2140 				/* print */
   2141 				if (or_needed) {
   2142 					(void) printf("or ");
   2143 				} else {
   2144 					or_needed = 1;
   2145 				}
   2146 				print_iap(&iap);
   2147 				break;
   2148 
   2149 			case SPD_ATTR_EMPTY:
   2150 				/* clear */
   2151 				(void) memset(&iap, 0, sizeof (iap));
   2152 				break;
   2153 
   2154 			case SPD_ATTR_NEXT:
   2155 				/* print */
   2156 				if (or_needed) {
   2157 					(void) printf("or ");
   2158 				} else {
   2159 					or_needed = 1;
   2160 				}
   2161 
   2162 				print_iap(&iap);
   2163 				break;
   2164 
   2165 			case SPD_ATTR_TYPE:
   2166 				iap.iap_action = app->spd_attr_value;
   2167 				break;
   2168 
   2169 			case SPD_ATTR_FLAGS:
   2170 				iap.iap_attr = app->spd_attr_value;
   2171 				break;
   2172 
   2173 			case SPD_ATTR_AH_AUTH:
   2174 				iap.iap_aauth.alg_id = app->spd_attr_value;
   2175 				break;
   2176 
   2177 			case SPD_ATTR_ESP_ENCR:
   2178 				iap.iap_eencr.alg_id = app->spd_attr_value;
   2179 				break;
   2180 
   2181 			case SPD_ATTR_ESP_AUTH:
   2182 				iap.iap_eauth.alg_id = app->spd_attr_value;
   2183 				break;
   2184 
   2185 			case SPD_ATTR_ENCR_MINBITS:
   2186 				iap.iap_eencr.alg_minbits = app->spd_attr_value;
   2187 				break;
   2188 
   2189 			case SPD_ATTR_ENCR_MAXBITS:
   2190 				iap.iap_eencr.alg_maxbits = app->spd_attr_value;
   2191 				break;
   2192 
   2193 			case SPD_ATTR_AH_MINBITS:
   2194 				iap.iap_aauth.alg_minbits = app->spd_attr_value;
   2195 				break;
   2196 
   2197 			case SPD_ATTR_AH_MAXBITS:
   2198 				iap.iap_aauth.alg_maxbits = app->spd_attr_value;
   2199 				break;
   2200 
   2201 			case SPD_ATTR_ESPA_MINBITS:
   2202 				iap.iap_eauth.alg_minbits = app->spd_attr_value;
   2203 				break;
   2204 
   2205 			case SPD_ATTR_ESPA_MAXBITS:
   2206 				iap.iap_eauth.alg_maxbits = app->spd_attr_value;
   2207 				break;
   2208 
   2209 			case SPD_ATTR_LIFE_SOFT_TIME:
   2210 			case SPD_ATTR_LIFE_HARD_TIME:
   2211 			case SPD_ATTR_LIFE_SOFT_BYTES:
   2212 			case SPD_ATTR_LIFE_HARD_BYTES:
   2213 			default:
   2214 				(void) printf("\tattr %d: %X-%d\n",
   2215 				    act_count,
   2216 				    app->spd_attr_tag,
   2217 				    app->spd_attr_value);
   2218 				break;
   2219 			}
   2220 			app++;
   2221 		}
   2222 	}
   2223 
   2224 	(void) printf("\n");
   2225 }
   2226 
   2227 #ifdef DEBUG_HEAVY
   2228 static void
   2229 pfpol_msg_dump(spd_msg_t *msg, char *tag)
   2230 {
   2231 	spd_ext_t *exts[SPD_EXT_MAX+1];
   2232 	uint32_t i;
   2233 	spd_address_t *spd_address;
   2234 	struct spd_rule *spd_rule;
   2235 	struct spd_proto *spd_proto;
   2236 	struct spd_portrange *spd_portrange;
   2237 	struct spd_typecode *spd_typecode;
   2238 	struct spd_ext_actions *spd_ext_actions;
   2239 	struct spd_attribute *app;
   2240 	spd_if_t *spd_if;
   2241 	char abuf[INET6_ADDRSTRLEN];
   2242 	uint32_t rv;
   2243 	uint16_t act_count;
   2244 
   2245 	rv = spdsock_get_ext(exts, msg, msg->spd_msg_len, NULL, 0);
   2246 	if (rv != KGE_OK)
   2247 		return;
   2248 
   2249 	(void) printf("===========%s==============\n", tag);
   2250 	(void) printf("pfpol_msg_dump %d\n-------------------\n", rv);
   2251 
   2252 	(void) printf("spd_msg_version:%d\n", msg->spd_msg_version);
   2253 	(void) printf("spd_msg_type:%d\n", msg->spd_msg_type);
   2254 	(void) printf("spd_msg_errno:%d\n", msg->spd_msg_errno);
   2255 	(void) printf("spd_msg_spdid:%d\n", msg->spd_msg_spdid);
   2256 	(void) printf("spd_msg_len:%d\n", msg->spd_msg_len);
   2257 	(void) printf("spd_msg_diagnostic:%d\n", msg->spd_msg_diagnostic);
   2258 	(void) printf("spd_msg_seq:%d\n", msg->spd_msg_seq);
   2259 	(void) printf("spd_msg_pid:%d\n", msg->spd_msg_pid);
   2260 
   2261 	for (i = 1; i <= SPD_EXT_MAX; i++) {
   2262 		if (exts[i] == NULL) {
   2263 			printf("skipped %d\n", i);
   2264 			continue;
   2265 		}
   2266 
   2267 		switch (i) {
   2268 		case SPD_EXT_TUN_NAME:
   2269 			spd_if = (spd_if_t *)exts[i];
   2270 			(void) printf("spd_if = %s\n", spd_if->spd_if_name);
   2271 			break;
   2272 
   2273 		case SPD_EXT_ICMP_TYPECODE:
   2274 			spd_typecode = (struct spd_typecode *)exts[i];
   2275 			(void) printf("icmp type %d-%d code %d-%d\n",
   2276 			    spd_typecode->spd_typecode_type,
   2277 			    spd_typecode->spd_typecode_type_end,
   2278 			    spd_typecode->spd_typecode_code,
   2279 			    spd_typecode->spd_typecode_code_end);
   2280 			break;
   2281 
   2282 		case SPD_EXT_LCLPORT:
   2283 			spd_portrange = (struct spd_portrange *)exts[i];
   2284 			(void) printf("local ports %d-%d\n",
   2285 			    spd_portrange->spd_ports_minport,
   2286 			    spd_portrange->spd_ports_maxport);
   2287 
   2288 			break;
   2289 
   2290 		case SPD_EXT_REMPORT:
   2291 			spd_portrange = (struct spd_portrange *)exts[i];
   2292 			(void) printf("remote ports %d-%d\n",
   2293 			    spd_portrange->spd_ports_minport,
   2294 			    spd_portrange->spd_ports_maxport);
   2295 
   2296 			break;
   2297 
   2298 		case SPD_EXT_PROTO:
   2299 			spd_proto = (struct spd_proto *)exts[i];
   2300 			(void) printf("proto:spd_proto_exttype %d\n",
   2301 			    spd_proto->spd_proto_exttype);
   2302 			(void) printf("proto:spd_proto_number %d\n",
   2303 			    spd_proto->spd_proto_number);
   2304 			break;
   2305 
   2306 		case SPD_EXT_LCLADDR:
   2307 		case SPD_EXT_REMADDR:
   2308 			spd_address = (spd_address_t *)exts[i];
   2309 			if (i == SPD_EXT_LCLADDR)
   2310 				(void) printf("local addr ");
   2311 			else
   2312 				(void) printf("remote addr ");
   2313 
   2314 
   2315 			(void) printf("%s\n",
   2316 			    inet_ntop(spd_address->spd_address_af,
   2317 			    (void *) (spd_address +1), abuf,
   2318 			    INET6_ADDRSTRLEN));
   2319 
   2320 			(void) printf("prefixlen: %d\n",
   2321 			    spd_address->spd_address_prefixlen);
   2322 			break;
   2323 
   2324 		case SPD_EXT_ACTION:
   2325 			spd_ext_actions = (struct spd_ext_actions *)exts[i];
   2326 			(void) printf("spd_ext_action\n");
   2327 			(void) printf("spd_actions_count %d\n",
   2328 			    spd_ext_actions->spd_actions_count);
   2329 			app = (struct spd_attribute *)(spd_ext_actions + 1);
   2330 
   2331 			for (act_count = 0;
   2332 			    act_count < spd_ext_actions->spd_actions_len -1;
   2333 			    act_count++) {
   2334 				(void) printf("\tattr %d: %X-%d\n", act_count,
   2335 				    app->spd_attr_tag, app->spd_attr_value);
   2336 				app++;
   2337 			}
   2338 
   2339 			break;
   2340 
   2341 		case SPD_EXT_RULE:
   2342 			spd_rule = (struct spd_rule *)exts[i];
   2343 			(void) printf("spd_rule_priority: 0x%x\n",
   2344 			    spd_rule->spd_rule_priority);
   2345 			(void) printf("spd_rule_flags: %d\n",
   2346 			    spd_rule->spd_rule_flags);
   2347 			break;
   2348 
   2349 		case SPD_EXT_RULESET:
   2350 			(void) printf("spd_ext_ruleset\n");
   2351 			break;
   2352 		default:
   2353 			(void) printf("default\n");
   2354 			break;
   2355 		}
   2356 	}
   2357 
   2358 	(void) printf("-------------------\n");
   2359 	(void) printf("=========================\n");
   2360 }
   2361 #endif /* DEBUG_HEAVY */
   2362 
   2363 static int
   2364 ipsec_conf_view()
   2365 {
   2366 	char buf[MAXLEN];
   2367 	FILE *fp;
   2368 
   2369 	fp = fopen(POLICY_CONF_FILE, "r");
   2370 	if (fp == NULL) {
   2371 		if (errno == ENOENT) {
   2372 			/*
   2373 			 * The absence of POLICY_CONF_FILE should
   2374 			 * not cause the command to exit with a
   2375 			 * non-zero status, since this condition
   2376 			 * is valid when no policies were previously
   2377 			 * defined.
   2378 			 */
   2379 			return (0);
   2380 		}
   2381 		warn(gettext("%s cannot be opened"), POLICY_CONF_FILE);
   2382 		return (-1);
   2383 	}
   2384 	while (fgets(buf, MAXLEN, fp) != NULL) {
   2385 		/* Don't print removed entries */
   2386 		if (*buf == ';')
   2387 			continue;
   2388 		if (strlen(buf) != 0)
   2389 			buf[strlen(buf) - 1] = '\0';
   2390 		(void) puts(buf);
   2391 	}
   2392 	return (0);
   2393 }
   2394 
   2395 /*
   2396  * Delete nlines from start in the POLICY_CONF_FILE.
   2397  */
   2398 static int
   2399 delete_from_file(int start, int nlines)
   2400 {
   2401 	FILE *fp;
   2402 	char ibuf[MAXLEN];
   2403 	int len;
   2404 
   2405 	if ((fp = fopen(POLICY_CONF_FILE, "r+b")) == NULL) {
   2406 		warn(gettext("%s cannot be opened"), POLICY_CONF_FILE);
   2407 		return (-1);
   2408 	}
   2409 
   2410 	/*
   2411 	 * Insert a ";", read the line and discard it. Repeat
   2412 	 * this logic nlines - 1 times. For the last line there
   2413 	 * is just a newline character. We can't just insert a
   2414 	 * single ";" character instead of the newline character
   2415 	 * as it would affect the next line. Thus when we comment
   2416 	 * the last line we seek one less and insert a ";"
   2417 	 * character, which will replace the newline of the
   2418 	 * penultimate line with ; and newline of the last line
   2419 	 * will become part of the previous line.
   2420 	 */
   2421 	do {
   2422 		/*
   2423 		 * It is not enough to seek just once and expect the
   2424 		 * subsequent fgets below to take you to the right
   2425 		 * offset of the next line. fgets below seems to affect
   2426 		 * the offset. Thus we need to seek, replace with ";",
   2427 		 * and discard a line using fgets for every line.
   2428 		 */
   2429 		if (fseek(fp, start, SEEK_SET) == -1) {
   2430 			warn("fseek");
   2431 			return (-1);
   2432 		}
   2433 		if (fputc(';', fp) < 0) {
   2434 			warn("fputc");
   2435 			return (-1);
   2436 		}
   2437 		/*
   2438 		 * Flush the above ";" character before we do the fgets().
   2439 		 * Without this, fgets() gets confused with offsets.
   2440 		 */
   2441 		(void) fflush(fp);
   2442 		len = 0;
   2443 		while (fgets(ibuf, MAXLEN, fp) != NULL) {
   2444 			len += strlen(ibuf);
   2445 			if (ibuf[len - 1] == '\n') {
   2446 				/*
   2447 				 * We have read a complete line.
   2448 				 */
   2449 				break;
   2450 			}
   2451 		}
   2452 		/*
   2453 		 * We read the line after ";" character has been inserted.
   2454 		 * Thus len does not count ";". To advance to the next line
   2455 		 * increment by 1.
   2456 		 */
   2457 		start += (len + 1);
   2458 		/*
   2459 		 * If nlines == 2, we will be commenting out the last
   2460 		 * line next, which has only one newline character.
   2461 		 * If we blindly replace it with ";", it will  be
   2462 		 * read as part of the next line which could have
   2463 		 * a INDEX string and thus confusing ipsec_conf_view.
   2464 		 * Thus, we seek one less and replace the previous
   2465 		 * line's newline character with ";", and the
   2466 		 * last line's newline character will become part of
   2467 		 * the previous line.
   2468 		 */
   2469 		if (nlines == 2)
   2470 			start--;
   2471 	} while (--nlines != 0);
   2472 	(void) fclose(fp);
   2473 	if (nlines != 0)
   2474 		return (-1);
   2475 	else
   2476 		return (0);
   2477 }
   2478 
   2479 /*
   2480  * Delete an entry from the file by inserting a ";" at the
   2481  * beginning of the lines to be removed.
   2482  */
   2483 static int
   2484 ipsec_conf_del(int policy_index, boolean_t ignore_spd)
   2485 {
   2486 	act_prop_t *act_props = malloc(sizeof (act_prop_t));
   2487 	char *buf;
   2488 	FILE *fp;
   2489 	char ibuf[MAXLEN];
   2490 	int ibuf_len, index_len, index;
   2491 	int ret = 0;
   2492 	int offset, prev_offset;
   2493 	int nlines;
   2494 	char lifname[LIFNAMSIZ];
   2495 
   2496 	if (act_props == NULL) {
   2497 		warn(gettext("memory"));
   2498 		return (-1);
   2499 	}
   2500 
   2501 	fp = fopen(POLICY_CONF_FILE, "r");
   2502 	if (fp == NULL) {
   2503 		warn(gettext("%s cannot be opened"), POLICY_CONF_FILE);
   2504 		free(act_props);
   2505 		return (-1);
   2506 	}
   2507 
   2508 	index_len = strlen(INDEX_TAG);
   2509 	index = 0;
   2510 	for (offset = prev_offset = 0; fgets(ibuf, MAXLEN, fp) != NULL;
   2511 	    offset += ibuf_len) {
   2512 		prev_offset = offset;
   2513 		ibuf_len = strlen(ibuf);
   2514 
   2515 		if (strncmp(ibuf, INDEX_TAG, index_len) != 0) {
   2516 			continue;
   2517 		}
   2518 
   2519 		/*
   2520 		 * This line contains INDEX_TAG
   2521 		 */
   2522 		buf = ibuf + index_len;
   2523 		buf++;			/* Skip the space */
   2524 		index = parse_index(buf, lifname);
   2525 		if (index == -1) {
   2526 			warnx(gettext("Invalid index in the file"));
   2527 			free(act_props);
   2528 			return (-1);
   2529 		}
   2530 		if (index == policy_index &&
   2531 		    (interface_name == NULL ||
   2532 		    strncmp(interface_name, lifname, LIFNAMSIZ) == 0)) {
   2533 			if (!ignore_spd) {
   2534 				ret = parse_one(fp, act_props);
   2535 				if (ret == -1) {
   2536 					warnx(gettext("Invalid policy entry "
   2537 					    "in the file"));
   2538 					free(act_props);
   2539 					return (-1);
   2540 				}
   2541 			}
   2542 			/*
   2543 			 * nlines is the number of lines we should comment
   2544 			 * out. linecount tells us how many lines this command
   2545 			 * spans. And we need to remove the line with INDEX
   2546 			 * and an extra line we added during ipsec_conf_add.
   2547 			 *
   2548 			 * NOTE : If somebody added a policy entry which does
   2549 			 * not have a newline, ipsec_conf_add() fills in the
   2550 			 * newline. Hence, there is always 2 extra lines
   2551 			 * to delete.
   2552 			 */
   2553 			nlines = linecount + 2;
   2554 			goto delete;
   2555 		}
   2556 	}
   2557 
   2558 	if (!ignore_spd)
   2559 		ret = pfp_delete_rule(policy_index);
   2560 
   2561 	if (ret != 0) {
   2562 		warnx(gettext("Deletion incomplete. Please "
   2563 		    "flush all the entries and re-configure :"));
   2564 		reconfigure();
   2565 		free(act_props);
   2566 		return (ret);
   2567 	}
   2568 	free(act_props);
   2569 	return (ret);
   2570 
   2571 delete:
   2572 	/* Delete nlines from prev_offset */
   2573 	(void) fclose(fp);
   2574 	ret = delete_from_file(prev_offset, nlines);
   2575 
   2576 	if (ret != 0) {
   2577 		warnx(gettext("Deletion incomplete. Please "
   2578 		    "flush all the entries and re-configure :"));
   2579 		reconfigure();
   2580 		free(act_props);
   2581 		return (ret);
   2582 	}
   2583 
   2584 	if (!ignore_spd)
   2585 		ret = pfp_delete_rule(policy_index);
   2586 
   2587 	if (ret != 0) {
   2588 		warnx(gettext("Deletion incomplete. Please "
   2589 		    "flush all the entries and re-configure :"));
   2590 		reconfigure();
   2591 		free(act_props);
   2592 		return (ret);
   2593 	}
   2594 	free(act_props);
   2595 	return (0);
   2596 }
   2597 
   2598 static int
   2599 pfp_delete_rule(uint64_t index)
   2600 {
   2601 	struct spd_msg *msg;
   2602 	struct spd_rule *rule;
   2603 	int sfd;
   2604 	int cnt, len, alloclen;
   2605 
   2606 	sfd = get_pf_pol_socket();
   2607 	if (sfd < 0) {
   2608 		warn(gettext("unable to open policy socket"));
   2609 		return (-1);
   2610 	}
   2611 
   2612 	/*
   2613 	 * Add an extra 8 bytes of space (+1 uint64_t) to avoid truncation
   2614 	 * issues.
   2615 	 */
   2616 	alloclen = sizeof (spd_msg_t) + sizeof (struct spd_rule) +
   2617 	    sizeof (spd_if_t) + LIFNAMSIZ + 8;
   2618 	msg = (spd_msg_t *)malloc(alloclen);
   2619 
   2620 	if (msg == NULL) {
   2621 		warn("malloc");
   2622 		return (-1);
   2623 	}
   2624 
   2625 	rule = (struct spd_rule *)(msg + 1);
   2626 
   2627 	(void) memset(msg, 0, alloclen);
   2628 	msg->spd_msg_version = PF_POLICY_V1;
   2629 	msg->spd_msg_type = SPD_DELETERULE;
   2630 	msg->spd_msg_len = SPD_8TO64(sizeof (spd_msg_t)
   2631 	    + sizeof (struct spd_rule));
   2632 
   2633 	rule->spd_rule_type = SPD_EXT_RULE;
   2634 	rule->spd_rule_len = SPD_8TO64(sizeof (struct spd_rule));
   2635 	rule->spd_rule_index = index;
   2636 
   2637 	msg->spd_msg_len += attach_tunname((spd_if_t *)(rule + 1));
   2638 
   2639 	len = SPD_64TO8(msg->spd_msg_len);
   2640 	cnt = write(sfd, msg, len);
   2641 
   2642 	if (cnt != len) {
   2643 		if (cnt < 0) {
   2644 			(void) close(sfd);
   2645 			free(msg);
   2646 			warn(gettext("Delete failed: write"));
   2647 			return (-1);
   2648 		} else {
   2649 			(void) close(sfd);
   2650 			free(msg);
   2651 			warnx(gettext("Delete failed: short write"));
   2652 			return (-1);
   2653 		}
   2654 	}
   2655 
   2656 	cnt = read(sfd, msg, len);
   2657 	if (cnt != len) {
   2658 		if (cnt < 0) {
   2659 			(void) close(sfd);
   2660 			free(msg);
   2661 			warn(gettext("Delete failed: read"));
   2662 			return (-1);
   2663 		} else {
   2664 			(void) close(sfd);
   2665 			free(msg);
   2666 			warnx(gettext("Delete failed while reading reply"));
   2667 			return (-1);
   2668 		}
   2669 	}
   2670 	(void) close(sfd);
   2671 	if (msg->spd_msg_errno != 0) {
   2672 		free(msg);
   2673 		errno = msg->spd_msg_errno;
   2674 		warn(gettext("Delete failed: SPD_FLUSH"));
   2675 		return (-1);
   2676 	}
   2677 
   2678 	free(msg);
   2679 	return (0);
   2680 }
   2681 
   2682 static int
   2683 ipsec_conf_flush(int db)
   2684 {
   2685 	int pfd, cnt, len;
   2686 	int sfd;
   2687 	struct spd_msg *msg;
   2688 	/*
   2689 	 * Add an extra 8 bytes of space (+1 uint64_t) to avoid truncation
   2690 	 * issues.
   2691 	 */
   2692 	uint64_t buffer[
   2693 	    SPD_8TO64(sizeof (*msg) + sizeof (spd_if_t) + LIFNAMSIZ) + 1];
   2694 
   2695 	sfd = get_pf_pol_socket();
   2696 	if (sfd < 0) {
   2697 		warn(gettext("unable to open policy socket"));
   2698 		return (-1);
   2699 	}
   2700 
   2701 	(void) memset(buffer, 0, sizeof (buffer));
   2702 	msg = (struct spd_msg *)buffer;
   2703 	msg->spd_msg_version = PF_POLICY_V1;
   2704 	msg->spd_msg_type = SPD_FLUSH;
   2705 	msg->spd_msg_len = SPD_8TO64(sizeof (*msg));
   2706 	msg->spd_msg_spdid = db;
   2707 
   2708 	msg->spd_msg_len += attach_tunname((spd_if_t *)(msg + 1));
   2709 
   2710 	len = SPD_64TO8(msg->spd_msg_len);
   2711 	cnt = write(sfd, msg, len);
   2712 	if (cnt != len) {
   2713 		if (cnt < 0) {
   2714 			warn(gettext("Flush failed: write"));
   2715 			return (-1);
   2716 		} else {
   2717 			warnx(gettext("Flush failed: short write"));
   2718 			return (-1);
   2719 		}
   2720 	}
   2721 
   2722 	cnt = read(sfd, msg, len);
   2723 	if (cnt != len) {
   2724 		if (cnt < 0) {
   2725 			warn(gettext("Flush failed: read"));
   2726 			return (-1);
   2727 		} else {
   2728 			warnx(gettext("Flush failed while reading reply"));
   2729 			return (-1);
   2730 		}
   2731 	}
   2732 	(void) close(sfd);
   2733 	if (msg->spd_msg_errno != 0) {
   2734 		warnx("%s: %s", gettext("Flush failed: SPD_FLUSH"),
   2735 		    sys_error_message(msg->spd_msg_errno));
   2736 		return (-1);
   2737 	}
   2738 
   2739 	/* Truncate the file */
   2740 	if (db == SPD_ACTIVE) {
   2741 		if ((pfd = open(POLICY_CONF_FILE, O_TRUNC|O_RDWR)) == -1) {
   2742 			if (errno == ENOENT) {
   2743 				/*
   2744 				 * The absence of POLICY_CONF_FILE should
   2745 				 * not cause the command to exit with a
   2746 				 * non-zero status, since this condition
   2747 				 * is valid when no policies were previously
   2748 				 * defined.
   2749 				 */
   2750 				return (0);
   2751 			}
   2752 			warn(gettext("%s cannot be truncated"),
   2753 			    POLICY_CONF_FILE);
   2754 			return (-1);
   2755 		}
   2756 		(void) close(pfd);
   2757 	}
   2758 	return (0);
   2759 }
   2760 
   2761 /*
   2762  * function to send SPD_FLIP and SPD_CLONE messages
   2763  * Do it for ALL polheads for simplicity's sake.
   2764  */
   2765 static void
   2766 ipsec_conf_admin(uint8_t type)
   2767 {
   2768 	int cnt;
   2769 	int sfd;
   2770 	struct spd_msg *msg;
   2771 	uint64_t buffer[
   2772 	    SPD_8TO64(sizeof (struct spd_msg) + sizeof (spd_if_t))];
   2773 	char *save_ifname;
   2774 
   2775 	sfd = get_pf_pol_socket();
   2776 	if (sfd < 0) {
   2777 		err(-1, gettext("unable to open policy socket"));
   2778 	}
   2779 
   2780 	(void) memset(buffer, 0, sizeof (buffer));
   2781 	msg = (struct spd_msg *)buffer;
   2782 	msg->spd_msg_version = PF_POLICY_V1;
   2783 	msg->spd_msg_type = type;
   2784 	msg->spd_msg_len = SPD_8TO64(sizeof (buffer));
   2785 
   2786 	save_ifname = interface_name;
   2787 	/* Apply to all policy heads - global and tunnels. */
   2788 	interface_name = &all_polheads;
   2789 	(void) attach_tunname((spd_if_t *)(msg + 1));
   2790 	interface_name = save_ifname;
   2791 
   2792 	cnt = write(sfd, msg, sizeof (buffer));
   2793 	if (cnt != sizeof (buffer)) {
   2794 		if (cnt < 0) {
   2795 			err(-1, gettext("admin failed: write"));
   2796 		} else {
   2797 			errx(-1, gettext("admin failed: short write"));
   2798 		}
   2799 	}
   2800 
   2801 	cnt = read(sfd, msg, sizeof (buffer));
   2802 	if (cnt != sizeof (buffer)) {
   2803 		if (cnt < 0) {
   2804 			err(-1, gettext("admin failed: read"));
   2805 		} else {
   2806 			errx(-1, gettext("admin failed while reading reply"));
   2807 		}
   2808 	}
   2809 	(void) close(sfd);
   2810 	if (msg->spd_msg_errno != 0) {
   2811 		errno = msg->spd_msg_errno;
   2812 		err(-1, gettext("admin failed"));
   2813 	}
   2814 }
   2815 
   2816 static void
   2817 reconfigure()
   2818 {
   2819 	(void) fprintf(stderr, gettext(
   2820 	    "\tipsecconf -f \n "
   2821 	    "\tipsecconf -a policy_file\n"));
   2822 }
   2823 
   2824 static void
   2825 usage(void)
   2826 {
   2827 	(void) fprintf(stderr, gettext(
   2828 	"Usage:	ipsecconf\n"
   2829 	"\tipsecconf -a ([-]|<filename>) [-q]\n"
   2830 	"\tipsecconf -c <filename>\n"
   2831 	"\tipsecconf -r ([-]|<filename>) [-q]\n"
   2832 	"\tipsecconf -d [-i tunnel-interface] <index>\n"
   2833 	"\tipsecconf -d <tunnel-interface,index>\n"
   2834 	"\tipsecconf -l [-n] [-i tunnel-interface]\n"
   2835 	"\tipsecconf -f [-i tunnel-interface]\n"
   2836 	"\tipsecconf -L [-n]\n"
   2837 	"\tipsecconf -F\n"));
   2838 }
   2839 
   2840 /*
   2841  * a type consists of
   2842  * "type" <int>{ "-" <int>}
   2843  * or
   2844  * "type" keyword
   2845  *
   2846  * a code consists of
   2847  * "code" <int>{ "-" <int>}
   2848  * or
   2849  * "code" keyword
   2850  */
   2851 
   2852 
   2853 static int
   2854 parse_type_code(const char *str, const str_val_t *table)
   2855 {
   2856 	char *end1, *end2;
   2857 	int res1 = 0, res2 = 0;
   2858 	int i;
   2859 
   2860 	if (isdigit(str[0])) {
   2861 		res1 = strtol(str, &end1, 0);
   2862 
   2863 		if (end1 == str) {
   2864 			return (-1);
   2865 		}
   2866 
   2867 		if (res1 > 255 || res1 < 0) {
   2868 			return (-1);
   2869 		}
   2870 
   2871 		if (*end1 == '-') {
   2872 			end1++;
   2873 			res2 = strtol(end1, &end2, 0);
   2874 			if (res2 > 255 || res2 < 0) {
   2875 				return (-1);
   2876 			}
   2877 		} else {
   2878 			end2 = end1;
   2879 		}
   2880 
   2881 		while (isspace(*end2))
   2882 			end2++;
   2883 
   2884 		if (*end2 != '\0') {
   2885 			return (-1);
   2886 		}
   2887 
   2888 		return (res1 + (res2 << 8));
   2889 	}
   2890 
   2891 	for (i = 0; table[i].string; i++) {
   2892 		if (strcmp(str, table[i].string) == 0) {
   2893 			return (table[i].value);
   2894 		}
   2895 	}
   2896 
   2897 	return (-1);
   2898 }
   2899 
   2900 static int
   2901 parse_int(const char *str)
   2902 {
   2903 	char *end;
   2904 	int res;
   2905 
   2906 	res = strtol(str, &end, 0);
   2907 	if (end == str)
   2908 		return (-1);
   2909 	while (isspace(*end))
   2910 		end++;
   2911 	if (*end != '\0')
   2912 		return (-1);
   2913 	return (res);
   2914 }
   2915 
   2916 /*
   2917  * Parses <interface>,<index>.  Sets iname or the global interface_name (if
   2918  * iname == NULL) to <interface> and returns <index>.  Calls exit() if we have
   2919  * an interface_name already set.
   2920  */
   2921 static int
   2922 parse_index(const char *str, char *iname)
   2923 {
   2924 	char *intf, *num, *copy;
   2925 	int rc;
   2926 
   2927 	copy = strdup(str);
   2928 	if (copy == NULL) {
   2929 		EXIT_FATAL("Out of memory.");
   2930 	}
   2931 
   2932 	intf = strtok(copy, ",");
   2933 	/* Just want the rest of the string unmolested, so use "" for arg2. */
   2934 	num = strtok(NULL, "");
   2935 	if (num == NULL) {
   2936 		/* No comma found, just parse it like an int. */
   2937 		free(copy);
   2938 		return (parse_int(str));
   2939 	}
   2940 
   2941 	if (iname != NULL) {
   2942 		(void) strlcpy(iname, intf, LIFNAMSIZ);
   2943 	} else {
   2944 		if (interface_name != NULL) {
   2945 			EXIT_FATAL("Interface name already selected");
   2946 		}
   2947 
   2948 		interface_name = strdup(intf);
   2949 		if (interface_name == NULL) {
   2950 			EXIT_FATAL("Out of memory.");
   2951 		}
   2952 	}
   2953 
   2954 	rc = parse_int(num);
   2955 	free(copy);
   2956 	return (rc);
   2957 }
   2958 
   2959 /*
   2960  * Convert a mask to a prefix length.
   2961  * Returns prefix length on success, -1 otherwise.
   2962  */
   2963 static int
   2964 in_getprefixlen(char *mask)
   2965 {
   2966 	int prefixlen;
   2967 	char *end;
   2968 
   2969 	prefixlen = (int)strtol(mask, &end, 10);
   2970 	if (prefixlen < 0) {
   2971 		return (-1);
   2972 	}
   2973 	if (mask == end) {
   2974 		return (-1);
   2975 	}
   2976 	if (*end != '\0') {
   2977 		return (-1);
   2978 	}
   2979 	return (prefixlen);
   2980 }
   2981 
   2982 /*
   2983  * Convert a prefix length to a mask.
   2984  * Assumes the mask array is zero'ed by the caller.
   2985  */
   2986 static void
   2987 in_prefixlentomask(unsigned int prefixlen, uchar_t *mask)
   2988 {
   2989 	while (prefixlen > 0) {
   2990 		if (prefixlen >= 8) {
   2991 			*mask++ = 0xFF;
   2992 			prefixlen -= 8;
   2993 			continue;
   2994 		}
   2995 		*mask |= 1 << (8 - prefixlen);
   2996 		prefixlen--;
   2997 	}
   2998 }
   2999 
   3000 
   3001 static int
   3002 parse_address(int type, char *addr_str)
   3003 {
   3004 	char *ptr;
   3005 	int prefix_len = 0;
   3006 	struct netent *ne = NULL;
   3007 	struct hostent *hp = NULL;
   3008 	int h_errno;
   3009 	struct in_addr netaddr;
   3010 	struct in6_addr *netaddr6;
   3011 	struct hostent *ne_hent;
   3012 	boolean_t	has_mask = B_FALSE;
   3013 
   3014 	ptr = strchr(addr_str, '/');
   3015 	if (ptr != NULL) {
   3016 		has_mask = B_TRUE;
   3017 		*ptr++ = NULL;
   3018 
   3019 		prefix_len = in_getprefixlen(ptr);
   3020 		if (prefix_len < 0)
   3021 			return (-1);
   3022 	}
   3023 
   3024 	/*
   3025 	 * getipnodebyname() is thread safe. This allows us to hold on to the
   3026 	 * returned hostent structure, which is pointed to by the shp and
   3027 	 * dhp globals for the source and destination addresses, respectively.
   3028 	 */
   3029 	hp = getipnodebyname(addr_str, AF_INET6, AI_DEFAULT | AI_ALL, &h_errno);
   3030 	if (hp != NULL) {
   3031 		/*
   3032 		 * We come here for both a hostname and
   3033 		 * any host address /network address.
   3034 		 */
   3035 		assert(hp->h_addrtype == AF_INET6);
   3036 	} else if ((ne = getnetbyname(addr_str)) != NULL) {
   3037 		switch (ne->n_addrtype) {
   3038 		case AF_INET:
   3039 			/*
   3040 			 * Allocate a struct hostent and initialize
   3041 			 * it with the address corresponding to the
   3042 			 * network number previously returned by
   3043 			 * getnetbyname(). Freed by do_address_adds()
   3044 			 * once the policy is defined.
   3045 			 */
   3046 			ne_hent = malloc(sizeof (struct hostent));
   3047 			if (ne_hent == NULL) {
   3048 				warn("malloc");
   3049 				return (-1);
   3050 			}
   3051 			ne_hent->h_addr_list = malloc(2*sizeof (char *));
   3052 			if (ne_hent->h_addr_list == NULL) {
   3053 				warn("malloc");
   3054 				free(ne_hent);
   3055 				return (-1);
   3056 			}
   3057 			netaddr6 = malloc(sizeof (struct in6_addr));
   3058 			if (netaddr6 == NULL) {
   3059 				warn("malloc");
   3060 				free(ne_hent->h_addr_list);
   3061 				free(ne_hent);
   3062 				return (-1);
   3063 			}
   3064 			ne_hent->h_addr_list[0] = (char *)netaddr6;
   3065 			ne_hent->h_addr_list[1] = NULL;
   3066 			netaddr = inet_makeaddr(ne->n_net, INADDR_ANY);
   3067 			IN6_INADDR_TO_V4MAPPED(&netaddr, netaddr6);
   3068 			hp = ne_hent;
   3069 			break;
   3070 		default:
   3071 			warnx("Address type %d not supported.", ne->n_addrtype);
   3072 			return (-1);
   3073 		}
   3074 	} else {
   3075 		return (-1);
   3076 	}
   3077 
   3078 	if (type == IPSEC_CONF_SRC_ADDRESS) {
   3079 		shp = hp;
   3080 		if (has_mask)
   3081 			splen = prefix_len;
   3082 		has_saprefix = has_mask;
   3083 	} else {
   3084 		dhp = hp;
   3085 		if (has_mask)
   3086 			dplen = prefix_len;
   3087 		has_daprefix = has_mask;
   3088 	}
   3089 
   3090 	return (0);
   3091 }
   3092 
   3093 /*
   3094  * Add port-only entries.  Make sure to add them in both the V6 and V4 tables!
   3095  */
   3096 static int
   3097 do_port_adds(ips_conf_t *cptr)
   3098 {
   3099 	int ret, diag;
   3100 
   3101 	assert(IN6_IS_ADDR_UNSPECIFIED(&cptr->ips_src_addr_v6));
   3102 	assert(IN6_IS_ADDR_UNSPECIFIED(&cptr->ips_dst_addr_v6));
   3103 
   3104 #ifdef DEBUG_HEAVY
   3105 	(void) dump_conf(cptr);
   3106 #endif
   3107 
   3108 	ret = send_pf_pol_message(SPD_ADDRULE, cptr, &diag);
   3109 	if (ret != 0 && !ipsecconf_qflag) {
   3110 		warnx(
   3111 		    gettext("Could not add IPv4 policy for sport %d, dport %d "
   3112 		    "- diagnostic %d - %s"), ntohs(cptr->ips_src_port_min),
   3113 		    ntohs(cptr->ips_dst_port_min), diag, spdsock_diag(diag));
   3114 	}
   3115 
   3116 	return (ret);
   3117 }
   3118 
   3119 /*
   3120  * Nuke a list of policy entries.
   3121  * rewrite this to use flipping
   3122  * d_list isn't freed because we will be
   3123  * exiting the program soon.
   3124  */
   3125 static void
   3126 nuke_adds()
   3127 {
   3128 	d_list_t *temp = d_list;
   3129 	FILE *policy_fp;
   3130 
   3131 	policy_fp = fopen(POLICY_CONF_FILE, "a");
   3132 	if (policy_fp == NULL) {
   3133 		warn(gettext("%s cannot be opened"), POLICY_CONF_FILE);
   3134 	} else {
   3135 		(void) fprintf(policy_fp, "\n\n");
   3136 		(void) fflush(policy_fp);
   3137 	}
   3138 
   3139 	while (temp != NULL) {
   3140 		(void) ipsec_conf_del(temp->index, B_TRUE);
   3141 		temp = temp->next;
   3142 	}
   3143 }
   3144 
   3145 /*
   3146  * Set mask info from the specified prefix len. Fail if multihomed.
   3147  */
   3148 static int
   3149 set_mask_info(struct hostent *hp, unsigned int plen, struct in6_addr *mask_v6)
   3150 {
   3151 	struct in6_addr addr;
   3152 	struct in_addr mask_v4;
   3153 
   3154 	if (hp->h_addr_list[1] != NULL) {
   3155 		return (EOPNOTSUPP);
   3156 	}
   3157 
   3158 	if (!IN6_IS_ADDR_UNSPECIFIED(mask_v6)) {
   3159 		return (EBUSY);
   3160 	}
   3161 
   3162 	bcopy(hp->h_addr_list[0], &addr, sizeof (struct in6_addr));
   3163 	if (IN6_IS_ADDR_V4MAPPED(&addr)) {
   3164 		if (plen > IP_ABITS) {
   3165 			return (ERANGE);
   3166 		}
   3167 		(void) memset(&mask_v4, 0, sizeof (mask_v4));
   3168 		in_prefixlentomask(plen, (uchar_t *)&mask_v4);
   3169 		IN6_INADDR_TO_V4MAPPED(&mask_v4, mask_v6);
   3170 	} else {
   3171 		if (plen > IPV6_ABITS) {
   3172 			return (ERANGE);
   3173 		}
   3174 		/* mask_v6 is already zero (unspecified), see test above */
   3175 		in_prefixlentomask(plen, (uchar_t *)mask_v6);
   3176 	}
   3177 	return (0);
   3178 }
   3179 
   3180 /*
   3181  * Initialize the specified IPv6 address with all f's.
   3182  */
   3183 static void
   3184 init_addr_wildcard(struct in6_addr *addr_v6, boolean_t isv4)
   3185 {
   3186 	if (isv4) {
   3187 		uint32_t addr_v4 = 0xffffffff;
   3188 		IN6_INADDR_TO_V4MAPPED((struct in_addr *)&addr_v4, addr_v6);
   3189 	} else {
   3190 		(void) memset(addr_v6, 0xff, sizeof (struct in6_addr));
   3191 	}
   3192 }
   3193 
   3194 /*
   3195  * Called at the end to actually add policy.  Handles single and multi-homed
   3196  * cases.
   3197  */
   3198 static int
   3199 do_address_adds(ips_conf_t *cptr, int *diag)
   3200 {
   3201 	int i, j;
   3202 	int ret = 0;	/* For ioctl() call. */
   3203 	int rc = 0;	/* My own return code. */
   3204 	struct in6_addr zeroes = {0, 0, 0, 0};
   3205 	char *ptr[2];
   3206 	struct hostent hent;
   3207 	boolean_t isv4;
   3208 	int add_count = 0;
   3209 
   3210 	/*
   3211 	 * dst_hent may not be initialized if a destination
   3212 	 * address was not given. It will be initalized with just
   3213 	 * one address if a destination address was given. In both
   3214 	 * the cases, we initialize here with ipsc_dst_addr and enter
   3215 	 * the loop below.
   3216 	 */
   3217 	if (dhp == NULL) {
   3218 		assert(shp != NULL);
   3219 		hent.h_addr_list = ptr;
   3220 		ptr[0] = (char *)&zeroes.s6_addr;
   3221 		ptr[1] = NULL;
   3222 		dhp = &hent;
   3223 	} else if (shp == NULL) {
   3224 		assert(dhp != NULL);
   3225 		hent.h_addr_list = ptr;
   3226 		ptr[0] = (char *)&zeroes.s6_addr;
   3227 		ptr[1] = NULL;
   3228 		shp = &hent;
   3229 	}
   3230 
   3231 	/*
   3232 	 * Set mask info here.  Bail if multihomed and there's a prefix len.
   3233 	 */
   3234 	if (has_saprefix) {
   3235 		rc = set_mask_info(shp, splen, &cptr->ips_src_mask_v6);
   3236 		if (rc != 0)
   3237 			goto bail;
   3238 		cptr->ips_src_mask_len = splen;
   3239 	}
   3240 
   3241 	if (has_daprefix) {
   3242 		rc = set_mask_info(dhp, dplen, &cptr->ips_dst_mask_v6);
   3243 		if (rc != 0)
   3244 			goto bail;
   3245 		cptr->ips_dst_mask_len = dplen;
   3246 	}
   3247 
   3248 	for (i = 0; shp->h_addr_list[i] != NULL; i++) {
   3249 		bcopy(shp->h_addr_list[i], &cptr->ips_src_addr_v6,
   3250 		    sizeof (struct in6_addr));
   3251 		isv4 = cptr->ips_isv4 =
   3252 		    IN6_IS_ADDR_V4MAPPED(&cptr->ips_src_addr_v6);
   3253 		if (IN6_IS_ADDR_UNSPECIFIED(&cptr->ips_src_mask_v6) &&
   3254 		    shp != &hent) {
   3255 			init_addr_wildcard(&cptr->ips_src_mask_v6, isv4);
   3256 		}
   3257 
   3258 		for (j = 0; dhp->h_addr_list[j] != NULL; j++) {
   3259 			bcopy(dhp->h_addr_list[j], &cptr->ips_dst_addr_v6,
   3260 			    sizeof (struct in6_addr));
   3261 			if (IN6_IS_ADDR_UNSPECIFIED(&cptr->ips_src_addr_v6)) {
   3262 				/*
   3263 				 * Src was not specified, so update isv4 flag
   3264 				 * for this policy according to the family
   3265 				 * of the destination address.
   3266 				 */
   3267 				isv4 = cptr->ips_isv4 =
   3268 				    IN6_IS_ADDR_V4MAPPED(
   3269 				    &cptr->ips_dst_addr_v6);
   3270 			} else if ((dhp != &hent) && (isv4 !=
   3271 			    IN6_IS_ADDR_V4MAPPED(&cptr->ips_dst_addr_v6))) {
   3272 				/* v6/v4 mismatch. */
   3273 				continue;
   3274 			}
   3275 			if (IN6_IS_ADDR_UNSPECIFIED(&cptr->ips_dst_mask_v6) &&
   3276 			    dhp != &hent) {
   3277 				init_addr_wildcard(&cptr->ips_dst_mask_v6,
   3278 				    isv4);
   3279 			}
   3280 
   3281 			ret = send_pf_pol_message(SPD_ADDRULE, cptr, diag);
   3282 
   3283 			if (ret == 0) {
   3284 				add_count++;
   3285 			} else {
   3286 				/* For now, allow duplicate/overlap policies. */
   3287 				if (ret != EEXIST) {
   3288 					/*
   3289 					 * We have an error where we added
   3290 					 * some, but had errors with others.
   3291 					 * Undo the previous adds, and
   3292 					 * bail.
   3293 					 */
   3294 					rc = ret;
   3295 					goto bail;
   3296 				}
   3297 			}
   3298 
   3299 			bzero(&cptr->ips_dst_mask_v6,
   3300 			    sizeof (struct in6_addr));
   3301 		}
   3302 
   3303 		bzero(&cptr->ips_src_mask_v6, sizeof (struct in6_addr));
   3304 	}
   3305 
   3306 bail:
   3307 	if (shp != &hent)
   3308 		freehostent(shp);
   3309 	shp = NULL;
   3310 	if (dhp != &hent)
   3311 		freehostent(dhp);
   3312 	dhp = NULL;
   3313 	splen = 0;
   3314 	dplen = 0;
   3315 
   3316 	if ((add_count == 0) && (rc == 0)) {
   3317 		/*
   3318 		 * No entries were added. We failed all adds
   3319 		 * because the entries already existed, or because
   3320 		 * no v4 or v6 src/dst pairs were found. Either way,
   3321 		 * we must fail here with an appropriate error
   3322 		 * to avoid a corresponding entry from being added
   3323 		 * to ipsecpolicy.conf.
   3324 		 */
   3325 		if ((ret == EEXIST)) {
   3326 			/* All adds failed with EEXIST */
   3327 			rc = EEXIST;
   3328 		} else {
   3329 			/* No matching v4 or v6 src/dst pairs */
   3330 			rc = ESRCH;
   3331 		}
   3332 	}
   3333 
   3334 	return (rc);
   3335 }
   3336 
   3337 static int
   3338 parse_mask(int type, char *mask_str, ips_conf_t *cptr)
   3339 {
   3340 	struct in_addr mask;
   3341 	struct in6_addr *mask6;
   3342 
   3343 	if (type == IPSEC_CONF_SRC_MASK) {
   3344 		mask6 = &cptr->ips_src_mask_v6;
   3345 	} else {
   3346 		mask6 = &cptr->ips_dst_mask_v6;
   3347 	}
   3348 
   3349 	if ((strncasecmp(mask_str, "0x", 2) == 0) &&
   3350 	    (strchr(mask_str, '.') == NULL)) {
   3351 		/* Is it in the form 0xff000000 ? */
   3352 		char *end;
   3353 
   3354 		mask.s_addr = strtoul(mask_str, &end, 0);
   3355 		if (end == mask_str) {
   3356 			return (-1);
   3357 		}
   3358 		if (*end != '\0') {
   3359 			return (-1);
   3360 		}
   3361 		mask.s_addr = htonl(mask.s_addr);
   3362 	} else {
   3363 		/*
   3364 		 * Since inet_addr() returns -1 on error, we have
   3365 		 * to convert a broadcast address ourselves.
   3366 		 */
   3367 		if (strcmp(mask_str, "255.255.255.255") == 0) {
   3368 			mask.s_addr = 0xffffffff;
   3369 		} else {
   3370 			mask.s_addr = inet_addr(mask_str);
   3371 			if (mask.s_addr == (unsigned int)-1)
   3372 				return (-1);
   3373 		}
   3374 	}
   3375 
   3376 	/* Should we check for non-contiguous masks ? */
   3377 	if (mask.s_addr == 0)
   3378 		return (-1);
   3379 	IN6_INADDR_TO_V4MAPPED(&mask, mask6);
   3380 
   3381 
   3382 	if (type == IPSEC_CONF_SRC_MASK) {
   3383 		cptr->ips_src_mask_len = in_masktoprefix(mask6->s6_addr,
   3384 		    B_TRUE);
   3385 	} else {
   3386 		cptr->ips_dst_mask_len = in_masktoprefix(mask6->s6_addr,
   3387 		    B_TRUE);
   3388 	}
   3389 
   3390 	return (0);
   3391 }
   3392 
   3393 static int
   3394 parse_port(int type, char *port_str, ips_conf_t *conf)
   3395 {
   3396 	struct servent *sent;
   3397 	in_port_t port;
   3398 	int ret;
   3399 
   3400 	sent = getservbyname(port_str, NULL);
   3401 	if (sent == NULL) {
   3402 		ret = parse_int(port_str);
   3403 		if (ret < 0 || ret >= 65536) {
   3404 			return (-1);
   3405 		}
   3406 		port = htons((in_port_t)ret);
   3407 	} else {
   3408 		port = sent->s_port;
   3409 	}
   3410 	if (type == IPSEC_CONF_SRC_PORT) {
   3411 		conf->ips_src_port_min = conf->ips_src_port_max = port;
   3412 	} else {
   3413 		conf->ips_dst_port_min = conf->ips_dst_port_max = port;
   3414 	}
   3415 	return (0);
   3416 }
   3417 
   3418 static boolean_t
   3419 combined_mode(ips_act_props_t *iap)
   3420 {
   3421 	struct ipsecalgent *alg;
   3422 
   3423 	alg = getipsecalgbynum(iap->iap_eencr.alg_id, IPSEC_PROTO_ESP, NULL);
   3424 	if (alg != NULL)
   3425 		freeipsecalgent(alg);
   3426 
   3427 	return (ALG_FLAG_COMBINED & alg->a_alg_flags);
   3428 }
   3429 
   3430 static int
   3431 valid_algorithm(int proto_num, const char *str)
   3432 {
   3433 	const char *tmp;
   3434 	int ret;
   3435 	struct ipsecalgent *alg;
   3436 
   3437 	/* Short-circuit "none" */
   3438 	if (strncasecmp("none", str, 5) == 0)
   3439 		return (-2);
   3440 
   3441 	alg = getipsecalgbyname(str, proto_num, NULL);
   3442 	if (alg != NULL) {
   3443 		ret = alg->a_alg_num;
   3444 		freeipsecalgent(alg);
   3445 		return (ret);
   3446 	}
   3447 
   3448 	/*
   3449 	 * Look whether it could be a valid number.
   3450 	 * We support numbers also so that users can
   3451 	 * load algorithms as they need it. We can't
   3452 	 * check for validity of numbers here. It will
   3453 	 * be checked when the SA is negotiated/looked up.
   3454 	 * parse_int uses strtol(str), which converts 3DES
   3455 	 * to a valid number i.e looks only at initial
   3456 	 * number part. If we come here we should expect
   3457 	 * only a decimal number.
   3458 	 */
   3459 	tmp = str;
   3460 	while (*tmp) {
   3461 		if (!isdigit(*tmp))
   3462 			return (-1);
   3463 		tmp++;
   3464 	}
   3465 
   3466 	ret = parse_int(str);
   3467 	if (ret > 0 && ret <= 255)
   3468 		return (ret);
   3469 	else
   3470 		return (-1);
   3471 }
   3472 
   3473 static int
   3474 parse_ipsec_alg(char *str, ips_act_props_t *iap, int alg_type)
   3475 {
   3476 	int alg_value;
   3477 	int remainder;
   3478 	char tstr[VALID_ALG_LEN];
   3479 	char *lens = NULL;
   3480 	char *l1_str;
   3481 	int l1 = 0;
   3482 	char *l2_str;
   3483 	int l2 = SPD_MAX_MAXBITS;
   3484 	algreq_t *ap;
   3485 	uint_t a_type;
   3486 
   3487 	fetch_algorithms();
   3488 
   3489 	/*
   3490 	 * Make sure that we get a null terminated string.
   3491 	 * For a bad input, we truncate at VALID_ALG_LEN.
   3492 	 */
   3493 	remainder = strlen(str);
   3494 	(void) strlcpy(tstr, str, VALID_ALG_LEN);
   3495 	lens = strtok(tstr, "()");
   3496 	remainder -= strlen(lens);
   3497 	lens = strtok(NULL, "()");
   3498 
   3499 	if (lens != NULL) {
   3500 		int len1 = 0;
   3501 		int len2 = SPD_MAX_MAXBITS;
   3502 		int len_all = strlen(lens);
   3503 		int dot_start = (lens[0] == '.');
   3504 
   3505 		/*
   3506 		 * Check to see if the keylength arg is at the end of the
   3507 		 * token, the "()" is 2 characters.
   3508 		 */
   3509 		remainder -= strlen(lens);
   3510 		if (remainder > 2)
   3511 			return (1);
   3512 
   3513 		l1_str = strtok(lens, ".");
   3514 		l2_str = strtok(NULL, ".");
   3515 		if (l1_str != NULL) {
   3516 			l1 = parse_int(l1_str);
   3517 			len1 = strlen(l1_str);
   3518 			if (len1 < 0)
   3519 				return (1);
   3520 		}
   3521 		if (l2_str != NULL) {
   3522 			l2 = parse_int(l2_str);
   3523 			len2 = strlen(l2_str);
   3524 			if (len2 < 0)
   3525 				return (1);
   3526 		}
   3527 
   3528 		if (len_all == len1) {
   3529 			/* alg(n) */
   3530 			l2 = l1;
   3531 		} else if (dot_start) {
   3532 			/* alg(..n) */
   3533 			l2 = l1;
   3534 			l1 = 0;
   3535 		} else if ((len_all - 2) == len1) {
   3536 			/* alg(n..) */
   3537 			l2 = SPD_MAX_MAXBITS;
   3538 		} /* else alg(n..m) */
   3539 	}
   3540 
   3541 	if (alg_type == SPD_ATTR_AH_AUTH ||
   3542 	    alg_type == SPD_ATTR_ESP_AUTH) {
   3543 		alg_value = valid_algorithm(IPSEC_PROTO_AH, tstr);
   3544 	} else {
   3545 		alg_value = valid_algorithm(IPSEC_PROTO_ESP, tstr);
   3546 	}
   3547 	if (alg_value < 0) {
   3548 		/* Invalid algorithm or "none" */
   3549 		return (alg_value);
   3550 	}
   3551 
   3552 	if (alg_type == SPD_ATTR_AH_AUTH) {
   3553 		a_type = AH_AUTH;
   3554 		iap->iap_attr |= SPD_APPLY_AH;
   3555 		ap = &(iap->iap_aauth);
   3556 	} else if (alg_type == SPD_ATTR_ESP_AUTH) {
   3557 		a_type = ESP_AUTH;
   3558 		iap->iap_attr |= SPD_APPLY_ESP|SPD_APPLY_ESPA;
   3559 		ap = &(iap->iap_eauth);
   3560 	} else {
   3561 		a_type = ESP_ENCR;
   3562 		iap->iap_attr |= SPD_APPLY_ESP;
   3563 		ap = &(iap->iap_eencr);
   3564 	}
   3565 
   3566 	ap->alg_id = alg_value;
   3567 	ap->alg_minbits = l1;
   3568 	ap->alg_maxbits = l2;
   3569 
   3570 	if (!alg_rangecheck(a_type, alg_value, ap))
   3571 		return (1);
   3572 
   3573 	return (0);
   3574 }
   3575 
   3576 static char *
   3577 sys_error_message(int syserr)
   3578 {
   3579 	char *mesg;
   3580 
   3581 	switch (syserr) {
   3582 	case EEXIST:
   3583 		mesg = gettext("Entry already exists");
   3584 		break;
   3585 	case ENOENT:
   3586 		mesg = gettext("Tunnel not found");
   3587 		break;
   3588 	case EINVAL:
   3589 		mesg = gettext("Invalid entry");
   3590 		break;
   3591 	default :
   3592 		mesg = strerror(syserr);
   3593 	}
   3594 	return (mesg);
   3595 }
   3596 
   3597 static void
   3598 error_message(error_type_t error, int type, int line)
   3599 {
   3600 	char *mesg;
   3601 
   3602 	switch (type) {
   3603 	case IPSEC_CONF_SRC_ADDRESS:
   3604 		mesg = gettext("Source Address");
   3605 		break;
   3606 	case IPSEC_CONF_DST_ADDRESS:
   3607 		mesg = gettext("Destination Address");
   3608 		break;
   3609 	case IPSEC_CONF_SRC_PORT:
   3610 		mesg = gettext("Source Port");
   3611 		break;
   3612 	case IPSEC_CONF_DST_PORT:
   3613 		mesg = gettext("Destination Port");
   3614 		break;
   3615 	case IPSEC_CONF_SRC_MASK:
   3616 		mesg = gettext("Source Mask");
   3617 		break;
   3618 	case IPSEC_CONF_DST_MASK:
   3619 		mesg = gettext("Destination Mask");
   3620 		break;
   3621 	case IPSEC_CONF_ULP:
   3622 		mesg = gettext("Upper Layer Protocol");
   3623 		break;
   3624 	case IPSEC_CONF_IPSEC_AALGS:
   3625 		mesg = gettext("Authentication Algorithm");
   3626 		break;
   3627 	case IPSEC_CONF_IPSEC_EALGS:
   3628 		mesg = gettext("Encryption Algorithm");
   3629 		break;
   3630 	case IPSEC_CONF_IPSEC_EAALGS:
   3631 		mesg = gettext("ESP Authentication Algorithm");
   3632 		break;
   3633 	case IPSEC_CONF_IPSEC_SA:
   3634 		mesg = gettext("SA");
   3635 		break;
   3636 	case IPSEC_CONF_IPSEC_DIR:
   3637 		mesg = gettext("Direction");
   3638 		break;
   3639 	case IPSEC_CONF_ICMP_TYPE:
   3640 		mesg = gettext("ICMP type");
   3641 		break;
   3642 	case IPSEC_CONF_ICMP_CODE:
   3643 		mesg = gettext("ICMP code");
   3644 		break;
   3645 	case IPSEC_CONF_NEGOTIATE:
   3646 		mesg = gettext("Negotiate");
   3647 		break;
   3648 	case IPSEC_CONF_TUNNEL:
   3649 		mesg = gettext("Tunnel");
   3650 		break;
   3651 	default :
   3652 		return;
   3653 	}
   3654 	/*
   3655 	 * If we never read a newline character, we don't want
   3656 	 * to print 0.
   3657 	 */
   3658 	warnx(gettext("%s%s%s %s on line: %d"),
   3659 	    (error == BAD_ERROR) ? gettext("Bad") : "",
   3660 	    (error == DUP_ERROR) ? gettext("Duplicate") : "",
   3661 	    (error == REQ_ERROR) ? gettext("Requires") : "",
   3662 	    mesg,
   3663 	    (arg_indices[line] == 0) ? 1 : arg_indices[line]);
   3664 }
   3665 
   3666 static int
   3667 validate_properties(ips_act_props_t *cptr, boolean_t dir, boolean_t is_alg)
   3668 {
   3669 	if (cptr->iap_action == SPD_ACTTYPE_PASS ||
   3670 	    cptr->iap_action == SPD_ACTTYPE_DROP) {
   3671 		if (!dir) {
   3672 			warnx(gettext("dir string "
   3673 			    "not found for bypass policy"));
   3674 		}
   3675 
   3676 		if (is_alg) {
   3677 			warnx(gettext("Algorithms found for bypass policy"));
   3678 			return (-1);
   3679 		}
   3680 		return (0);
   3681 	}
   3682 	if (!is_alg) {
   3683 		warnx(gettext("No IPsec algorithms given"));
   3684 		return (-1);
   3685 	}
   3686 	if (cptr->iap_attr == 0) {
   3687 		warnx(gettext("No SA attribute"));
   3688 		return (-1);
   3689 	}
   3690 	return (0);
   3691 }
   3692 
   3693 /*
   3694  * This function is called only to parse a single rule's worth of
   3695  * action strings.  This is called after parsing pattern and before
   3696  * parsing properties.  Thus we may have something in the leftover
   3697  * buffer while parsing the pattern, which we need to handle here.
   3698  */
   3699 static int
   3700 parse_action(FILE *fp, char **action, char **leftover)
   3701 {
   3702 	char *cp;
   3703 	char ibuf[MAXLEN];
   3704 	char *tmp_buf;
   3705 	char *buf;
   3706 	boolean_t new_stuff;
   3707 
   3708 	if (*leftover != NULL) {
   3709 		buf = *leftover;
   3710 		new_stuff = B_FALSE;
   3711 		goto scan;
   3712 	}
   3713 	while (fgets(ibuf, MAXLEN, fp) != NULL) {
   3714 		new_stuff = B_TRUE;
   3715 		if (ibuf[strlen(ibuf) - 1] == '\n')
   3716 			linecount++;
   3717 		buf = ibuf;
   3718 scan:
   3719 		/* Truncate at the beginning of a comment */
   3720 		cp = strchr(buf, '#');
   3721 		if (cp != NULL)
   3722 			*cp = NULL;
   3723 
   3724 		/* Skip any whitespace */
   3725 		while (*buf != NULL && isspace(*buf))
   3726 			buf++;
   3727 
   3728 		/* Empty line */
   3729 		if (*buf == NULL)
   3730 			continue;
   3731 
   3732 		/*
   3733 		 * Store the command for error reporting
   3734 		 * and ipsec_conf_add().
   3735 		 */
   3736 		if (new_stuff) {
   3737 			/*
   3738 			 * Check for buffer overflow including the null
   3739 			 * terminating character.
   3740 			 */
   3741 			int len = strlen(ibuf);
   3742 			if ((cbuf_offset + len + 1) >= CBUF_LEN)
   3743 				return (-1);
   3744 
   3745 			(void) strcpy(cbuf + cbuf_offset, ibuf);
   3746 			cbuf_offset += len;
   3747 		}
   3748 		/*
   3749 		 * Start of the non-empty non-space character.
   3750 		 */
   3751 		tmp_buf = buf;
   3752 
   3753 		/* Skip until next whitespace or CURL_BEGIN */
   3754 		while (*buf != NULL && !isspace(*buf) &&
   3755 		    *buf != CURL_BEGIN)
   3756 			buf++;
   3757 
   3758 		if (*buf != NULL) {
   3759 			if (tmp_buf == buf) /* No action token */
   3760 				goto error;
   3761 			if (*buf == CURL_BEGIN) {
   3762 				*buf = NULL;
   3763 				/* Allocate an extra byte for the null also */
   3764 				if ((*action = malloc(strlen(tmp_buf) + 1)) ==
   3765 				    NULL) {
   3766 					warn("malloc");
   3767 					return (ENOMEM);
   3768 				}
   3769 				(void) strcpy(*action, tmp_buf);
   3770 				*buf = CURL_BEGIN;
   3771 			} else {
   3772 				/* We have hit a space */
   3773 				*buf++ = NULL;
   3774 				/* Allocate an extra byte for the null also */
   3775 				if ((*action = malloc(strlen(tmp_buf) + 1)) ==
   3776 				    NULL) {
   3777 					warn("malloc");
   3778 					return (ENOMEM);
   3779 				}
   3780 				(void) strcpy(*action, tmp_buf);
   3781 			}
   3782 			/*
   3783 			 * Copy the rest of the line into the
   3784 			 * leftover buffer.
   3785 			 */
   3786 			if (*buf != NULL) {
   3787 				(void) strlcpy(lo_buf, buf, sizeof (lo_buf));
   3788 				*leftover = lo_buf;
   3789 			} else {
   3790 				*leftover = NULL;
   3791 			}
   3792 		} else {
   3793 			/* Allocate an extra byte for the null also */
   3794 			if ((*action = malloc(strlen(tmp_buf) + 1)) ==
   3795 			    NULL) {
   3796 				warn("malloc");
   3797 				return (ENOMEM);
   3798 			}
   3799 			(void) strcpy(*action, tmp_buf);
   3800 			*leftover = NULL;
   3801 		}
   3802 		if (argindex >= ARG_BUF_LEN) {
   3803 			warnx(gettext("(parsing one command) "
   3804 			    "Too many selectors before action."));
   3805 			return (-1);
   3806 		}
   3807 		arg_indices[argindex++] = linecount;
   3808 		return (PARSE_SUCCESS);
   3809 	}
   3810 	/*
   3811 	 * Return error, on an empty action field.
   3812 	 */
   3813 error:
   3814 	warnx(gettext("(parsing one command) "
   3815 	    "Missing action token."));
   3816 	return (-1);
   3817 }
   3818 
   3819 /*
   3820  * This is called to parse pattern or properties that is enclosed
   3821  * between CURL_BEGIN and CURL_END.
   3822  */
   3823 static int
   3824 parse_pattern_or_prop(FILE *fp, char *argvec[], char **leftover)
   3825 {
   3826 	char *cp;
   3827 	int i = 0;
   3828 	boolean_t curl_begin_seen = B_FALSE;
   3829 	char ibuf[MAXLEN];
   3830 	char *tmp_buf;
   3831 	char *buf;
   3832 	boolean_t new_stuff;
   3833 
   3834 	/*
   3835 	 * When parsing properties, leftover buffer could have the
   3836 	 * leftovers of the previous fgets().
   3837 	 */
   3838 	if (*leftover != NULL) {
   3839 		buf = *leftover;
   3840 		new_stuff = B_FALSE;
   3841 		goto scan;
   3842 	}
   3843 	while (fgets(ibuf, MAXLEN, fp) != NULL) {
   3844 		new_stuff = B_TRUE;
   3845 #ifdef DEBUG_HEAVY
   3846 		(void) printf("%s\n", ibuf);
   3847 #endif
   3848 		if (ibuf[strlen(ibuf) - 1] == '\n')
   3849 			linecount++;
   3850 		buf = ibuf;
   3851 scan:
   3852 		/* Truncate at the beginning of a comment */
   3853 		cp = strchr(buf, '#');
   3854 		if (cp != NULL)
   3855 			*cp = NULL;
   3856 
   3857 		/* Skip any whitespace */
   3858 		while (*buf != NULL && isspace(*buf))
   3859 			buf++;
   3860 
   3861 		/* Empty line */
   3862 		if (*buf == NULL)
   3863 			continue;
   3864 		/*
   3865 		 * Store the command for error reporting
   3866 		 * and ipsec_conf_add().
   3867 		 */
   3868 		if (new_stuff) {
   3869 			/*
   3870 			 * Check for buffer overflow including the null
   3871 			 * terminating character.
   3872 			 */
   3873 			int len = strlen(ibuf);
   3874 			if ((cbuf_offset + len + 1) >= CBUF_LEN)
   3875 				return (-1);
   3876 			(void) strcpy(cbuf + cbuf_offset, ibuf);
   3877 			cbuf_offset += len;
   3878 		}
   3879 		/*
   3880 		 * First non-space character should be
   3881 		 * a curly bracket.
   3882 		 */
   3883 		if (!curl_begin_seen) {
   3884 			if (*buf != CURL_BEGIN) {
   3885 				/*
   3886 				 * If we never read a newline character,
   3887 				 * we don't want to print 0.
   3888 				 */
   3889 				warnx(gettext("line %d : pattern must start "
   3890 				    "with \"%c\" character"),
   3891 				    (linecount == 0) ? 1 : linecount,
   3892 				    CURL_BEGIN);
   3893 				return (-1);
   3894 			}
   3895 			buf++;
   3896 			curl_begin_seen = B_TRUE;
   3897 		}
   3898 		/*
   3899 		 * Arguments are separated by white spaces or
   3900 		 * newlines. Scan till you see a CURL_END.
   3901 		 */
   3902 		while (*buf != NULL) {
   3903 			if (*buf == CURL_END) {
   3904 ret:
   3905 				*buf++ = NULL;
   3906 				/*
   3907 				 * Copy the rest of the line into the
   3908 				 * leftover buffer if any.
   3909 				 */
   3910 				if (*buf != NULL) {
   3911 					(void) strlcpy(lo_buf, buf,
   3912 					    sizeof (lo_buf));
   3913 					*leftover = lo_buf;
   3914 				} else {
   3915 					*leftover = NULL;
   3916 				}
   3917 				return (PARSE_SUCCESS);
   3918 			}
   3919 			/*
   3920 			 * Skip any trailing whitespace until we see a
   3921 			 * non white-space character.
   3922 			 */
   3923 			while (*buf != NULL && isspace(*buf))
   3924 				buf++;
   3925 
   3926 			if (*buf == CURL_END)
   3927 				goto ret;
   3928 
   3929 			/* Scan the next line as this buffer is empty */
   3930 			if (*buf == NULL)
   3931 				break;
   3932 
   3933 			if (i >= MAXARGS) {
   3934 				warnx(
   3935 				    gettext("Number of Arguments exceeded %d"),
   3936 				    i);
   3937 				return (-1);
   3938 			}
   3939 			/*
   3940 			 * Non-empty, Non-space buffer.
   3941 			 */
   3942 			tmp_buf = buf++;
   3943 			/*
   3944 			 * Real scan of the argument takes place here.
   3945 			 * Skip past till space or CURL_END.
   3946 			 */
   3947 			while (*buf != NULL && !isspace(*buf) &&
   3948 			    *buf != CURL_END) {
   3949 				buf++;
   3950 			}
   3951 			/*
   3952 			 * Either a space or we have hit the CURL_END or
   3953 			 * the real end.
   3954 			 */
   3955 			if (*buf != NULL) {
   3956 				if (*buf == CURL_END) {
   3957 					*buf++ = NULL;
   3958 					if ((argvec[i] = malloc(strlen(tmp_buf)
   3959 					    + 1)) == NULL) {
   3960 						warn("malloc");
   3961 						return (ENOMEM);
   3962 					}
   3963 					if (strlen(tmp_buf) != 0) {
   3964 						(void) strcpy(argvec[i],
   3965 						    tmp_buf);
   3966 						if (argindex >= ARG_BUF_LEN)
   3967 							goto toomanyargs;
   3968 						arg_indices[argindex++] =
   3969 						    linecount;
   3970 					}
   3971 					/*
   3972 					 * Copy the rest of the line into the
   3973 					 * leftover buffer.
   3974 					 */
   3975 					if (*buf != NULL) {
   3976 						(void) strlcpy(lo_buf, buf,
   3977 						    sizeof (lo_buf));
   3978 						*leftover = lo_buf;
   3979 					} else {
   3980 						*leftover = NULL;
   3981 					}
   3982 					return (PARSE_SUCCESS);
   3983 				} else {
   3984 					*buf++ = NULL;
   3985 				}
   3986 			}
   3987 			/*
   3988 			 * Copy this argument and scan for the buffer more
   3989 			 * if it is non-empty. If it is empty scan for
   3990 			 * the next line.
   3991 			 */
   3992 			if ((argvec[i] = malloc(strlen(tmp_buf) + 1)) ==
   3993 			    NULL) {
   3994 				warn("malloc");
   3995 				return (ENOMEM);
   3996 			}
   3997 			(void) strcpy(argvec[i++], tmp_buf);
   3998 			if (argindex >= ARG_BUF_LEN) {
   3999 			/*
   4000 			 * The number of tokens in a single policy entry
   4001 			 * exceeds the number of buffers available to fully
   4002 			 * parse the policy entry.
   4003 			 */
   4004 toomanyargs:
   4005 				warnx(gettext("(parsing one command) "
   4006 				    "Too many tokens in single policy entry."));
   4007 				return (-1);
   4008 			}
   4009 			arg_indices[argindex++] = linecount;
   4010 		}
   4011 	}
   4012 	/*
   4013 	 * If nothing is given in the file, it is okay.
   4014 	 * If something is given in the file and it is
   4015 	 * not CURL_BEGIN, we would have returned error
   4016 	 * above. If curl_begin_seen and we are here,
   4017 	 * something is wrong.
   4018 	 */
   4019 	if (curl_begin_seen) {
   4020 		warnx(gettext("(parsing one command) "
   4021 		    "Pattern or Properties incomplete."));
   4022 		return (-1);
   4023 	}
   4024 	return (PARSE_EOF);		/* Nothing more in the file */
   4025 }
   4026 
   4027 /*
   4028  * Parse one command i.e {pattern} action {properties}.
   4029  *
   4030  * {pattern} ( action {prop} | pass | drop ) (or ...)*
   4031  */
   4032 static int
   4033 parse_one(FILE *fp, act_prop_t *act_props)
   4034 {
   4035 	char *leftover;
   4036 	int ret;
   4037 	int i;
   4038 	int ap_num = 0;
   4039 	enum parse_state {pattern, action, prop } pstate;
   4040 
   4041 	has_daprefix = has_saprefix = B_FALSE;
   4042 
   4043 	(void) memset(act_props, 0, sizeof (act_prop_t));
   4044 	pstate = pattern;
   4045 
   4046 	ret = 0;
   4047 	leftover = NULL;
   4048 	argindex = 0;
   4049 	cbuf_offset = 0;
   4050 	assert(shp == NULL && dhp == NULL);
   4051 
   4052 	for (;;) {
   4053 		switch (pstate) {
   4054 		case pattern:
   4055 		{
   4056 #ifdef DEBUG_HEAVY
   4057 			(void) printf("pattern\n");
   4058 #endif
   4059 			ret = parse_pattern_or_prop(fp,
   4060 			    act_props->pattern, &leftover);
   4061 			if (ret == PARSE_EOF) {
   4062 				/* EOF reached */
   4063 				return (PARSE_EOF);
   4064 			}
   4065 			if (ret != 0) {
   4066 				ret = -1;
   4067 				goto err;
   4068 			}
   4069 			pstate = action;
   4070 			break;
   4071 		}
   4072 		case action:
   4073 		{
   4074 #ifdef DEBUG_HEAVY
   4075 			(void) printf("action\n");
   4076 #endif
   4077 			ret = parse_action(fp,
   4078 			    &act_props->ap[ap_num].act, &leftover);
   4079 			if (ret != 0) {
   4080 				ret = -1;
   4081 				goto err;
   4082 			}
   4083 
   4084 			/*
   4085 			 * Validate action now itself so that we don't
   4086 			 * proceed too much into the bad world.
   4087 			 */
   4088 			for (i = 0; action_table[i].string; i++) {
   4089 				if (strcmp(act_props->ap[ap_num].act,
   4090 				    action_table[i].string) == 0)
   4091 					break;
   4092 			}
   4093 
   4094 			if (action_table[i].tok_val == TOK_or) {
   4095 				/* hit an or, go again */
   4096 				break;
   4097 			}
   4098 
   4099 			if (action_table[i].string == NULL) {
   4100 				/*
   4101 				 * If we never read a newline
   4102 				 * character, we don't want
   4103 				 * to print 0.
   4104 				 */
   4105 				warnx(gettext("(parsing one command) "
   4106 				    "Invalid action on line %d: %s"),
   4107 				    (linecount == 0) ? 1 : linecount,
   4108 				    act_props->ap[ap_num].act);
   4109 				return (-1);
   4110 			}
   4111 
   4112 			pstate = prop;
   4113 			break;
   4114 		}
   4115 		case prop:
   4116 		{
   4117 #ifdef DEBUG_HEAVY
   4118 			(void) printf("prop\n");
   4119 #endif
   4120 			ret = parse_pattern_or_prop(fp,
   4121 			    act_props->ap[ap_num].prop, &leftover);
   4122 			if (ret != 0) {
   4123 				if (ret == PARSE_EOF) {
   4124 					warnx(gettext("(parsing one command) "
   4125 					    "Missing properties."));
   4126 				}
   4127 				ret = -1;
   4128 				goto err;
   4129 			}
   4130 
   4131 			if (leftover != NULL) {
   4132 				/* Accomodate spaces at the end */
   4133 				while (*leftover != NULL) {
   4134 					if (*leftover == BACK_SLASH) {
   4135 						warnx(gettext("Invalid line "
   4136 						    "continuation character."));
   4137 						ret = -1;
   4138 						goto err;
   4139 					}
   4140 					if (*leftover == 'o') {
   4141 						leftover++;
   4142 						if (*leftover == 'r') {
   4143 							leftover++;
   4144 							ap_num++;
   4145 							pstate = action;
   4146 							goto again;
   4147 						}
   4148 					}
   4149 					if (!isspace(*leftover)) {
   4150 						ret = -1;
   4151 						goto err;
   4152 					}
   4153 					leftover++;
   4154 				}
   4155 				return (0);
   4156 			}
   4157 			ap_num++;
   4158 			if (ap_num > MAXARGS)
   4159 				return (0);
   4160 			pstate = action; /* or */
   4161 			break;
   4162 		} /* case prop: */
   4163 		} /* switch(pstate) */
   4164 
   4165 again:
   4166 		if (ap_num > MAXARGS) {
   4167 			warnx(gettext("Too many actions."));
   4168 			return (-1);
   4169 		}
   4170 	} /* for(;;) */
   4171 err:
   4172 	if (ret != 0) {
   4173 		/*
   4174 		 * If we never read a newline character, we don't want
   4175 		 * to print 0.
   4176 		 */
   4177 		warnx(gettext("Error before or at line %d"),
   4178 		    (linecount == 0) ? 1 : linecount);
   4179 	}
   4180 	return (ret);
   4181 }
   4182 
   4183 /*
   4184  * convert an act_propts_t to an ips_conf_t
   4185  */
   4186 
   4187 static int
   4188 form_ipsec_conf(act_prop_t *act_props, ips_conf_t *cptr)
   4189 {
   4190 	int i, j, k;
   4191 	int tok_count = 0;
   4192 	struct protoent *pent;
   4193 	boolean_t saddr, daddr, ipsec_aalg, ipsec_ealg, ipsec_eaalg, dir;
   4194 	boolean_t old_style, new_style, auth_covered, is_no_alg;
   4195 	boolean_t is_combined_mode;
   4196 	struct in_addr mask;
   4197 	int line_no;
   4198 	int ret;
   4199 	int ap_num = 0;
   4200 	int type, code, type_end, code_end;
   4201 #ifdef DEBUG_HEAVY
   4202 	/*
   4203 	 * pattern => act_props->pattern
   4204 	 * action => act_props->ap[].act
   4205 	 * properties => act_props->ap[].prop
   4206 	 */
   4207 	(void) printf("\npattern\n------------\n");
   4208 	for (i = 0; act_props->pattern[i] != NULL; i++)
   4209 		(void) printf("%s\n", act_props->pattern[i]);
   4210 	(void) printf("apz\n----------\n");
   4211 	for (j = 0; act_props->ap[j].act != NULL; j++) {
   4212 
   4213 		(void) printf("act%d->%s\n", j, act_props->ap[j].act);
   4214 		for (i = 0; act_props->ap[j].prop[i] != NULL; i++)
   4215 			(void) printf("%dprop%d->%s\n",
   4216 			    j, i, act_props->ap[j].prop[i]);
   4217 	}
   4218 	(void) printf("------------\n\n");
   4219 #endif
   4220 
   4221 	(void) memset(cptr, 0, sizeof (ips_conf_t));
   4222 	saddr = daddr = ipsec_aalg = ipsec_ealg = ipsec_eaalg = dir = B_FALSE;
   4223 	old_style = new_style = is_no_alg = is_combined_mode = B_FALSE;
   4224 	/*
   4225 	 * Get the Pattern. NULL pattern is valid.
   4226 	 */
   4227 	for (i = 0, line_no = 0; act_props->pattern[i]; i++, line_no++) {
   4228 		for (j = 0; pattern_table[j].string; j++) {
   4229 			if (strcmp(act_props->pattern[i],
   4230 			    pattern_table[j].string) == 0)
   4231 				break;
   4232 		}
   4233 
   4234 		if (pattern_table[j].string == NULL) {
   4235 			/*
   4236 			 * If we never read a newline character, we don't want
   4237 			 * to print 0.
   4238 			 */
   4239 			warnx(gettext("Invalid pattern on line %d: %s"),
   4240 			    (arg_indices[line_no] == 0) ? 1 :
   4241 			    arg_indices[line_no], act_props->pattern[i]);
   4242 			return (-1);
   4243 		}
   4244 
   4245 		cptr->patt_tok[tok_count++] = pattern_table[j].tok_val;
   4246 
   4247 		switch (pattern_table[j].tok_val) {
   4248 
   4249 		case TOK_dir:
   4250 			i++, line_no++;
   4251 			if (act_props->pattern[i] == NULL) {
   4252 				error_message(BAD_ERROR,
   4253 				    IPSEC_CONF_IPSEC_DIR, line_no);
   4254 				return (-1);
   4255 			}
   4256 
   4257 			if (strncmp(act_props->pattern[i], "in", 2) == 0) {
   4258 				cptr->ips_dir = SPD_RULE_FLAG_INBOUND;
   4259 			} else if (strncmp(
   4260 			    act_props->pattern[i], "out", 3) == 0) {
   4261 				cptr->ips_dir = SPD_RULE_FLAG_OUTBOUND;
   4262 			} else if (strncmp(
   4263 			    act_props->pattern[i], "both", 4) == 0) {
   4264 				if (old_style) {
   4265 					error_message(BAD_ERROR,
   4266 					    IPSEC_CONF_IPSEC_DIR, line_no);
   4267 					return (-1);
   4268 				}
   4269 				new_style = B_TRUE;
   4270 				cptr->ips_dir =
   4271 				    SPD_RULE_FLAG_OUTBOUND |
   4272 				    SPD_RULE_FLAG_INBOUND;
   4273 			} else {
   4274 				error_message(BAD_ERROR,
   4275 				    IPSEC_CONF_IPSEC_DIR, line_no);
   4276 				return (-1);
   4277 			}
   4278 			dir = B_TRUE;
   4279 			break;
   4280 
   4281 		case TOK_local:
   4282 			if (old_style) {
   4283 				error_message(BAD_ERROR,
   4284 				    IPSEC_CONF_SRC_ADDRESS, line_no);
   4285 				return (-1);
   4286 			}
   4287 			new_style = B_TRUE;
   4288 
   4289 			if (saddr) {
   4290 				error_message(DUP_ERROR,
   4291 				    IPSEC_CONF_SRC_ADDRESS, line_no);
   4292 				return (-1);
   4293 			}
   4294 			/*
   4295 			 * Use this to detect duplicates rather
   4296 			 * than 0 like other cases, because 0 for
   4297 			 * address means INADDR_ANY.
   4298 			 */
   4299 			saddr = B_TRUE;
   4300 			cptr->has_saddr = 1;
   4301 			/*
   4302 			 * Advance to the string containing
   4303 			 * the address.
   4304 			 */
   4305 			i++, line_no++;
   4306 			if (act_props->pattern[i] == NULL) {
   4307 				error_message(BAD_ERROR,
   4308 				    IPSEC_CONF_SRC_ADDRESS, line_no);
   4309 				return (-1);
   4310 			}
   4311 			if (parse_address(IPSEC_CONF_SRC_ADDRESS,
   4312 			    act_props->pattern[i]) != 0) {
   4313 				error_message(BAD_ERROR,
   4314 				    IPSEC_CONF_SRC_ADDRESS, line_no);
   4315 				return (-1);
   4316 			}
   4317 			if (!cptr->has_smask)
   4318 				cptr->has_smask = has_saprefix;
   4319 
   4320 			break;
   4321 		case TOK_remote:
   4322 			if (old_style) {
   4323 				error_message(BAD_ERROR,
   4324 				    IPSEC_CONF_DST_ADDRESS, line_no);
   4325 				return (-1);
   4326 			}
   4327 			new_style = B_TRUE;
   4328 
   4329 			if (daddr) {
   4330 				error_message(DUP_ERROR,
   4331 				    IPSEC_CONF_DST_ADDRESS, line_no);
   4332 				return (-1);
   4333 			}
   4334 			/*
   4335 			 * Use this to detect duplicates rather
   4336 			 * than 0 like other cases, because 0 for
   4337 			 * address means INADDR_ANY.
   4338 			 */
   4339 			daddr = B_TRUE;
   4340 			cptr->has_daddr = 1;
   4341 			/*
   4342 			 * Advance to the string containing
   4343 			 * the address.
   4344 			 */
   4345 			i++, line_no++;
   4346 			if (act_props->pattern[i] == NULL) {
   4347 				error_message(BAD_ERROR,
   4348 				    IPSEC_CONF_DST_ADDRESS, line_no);
   4349 				return (-1);
   4350 			}
   4351 			if (parse_address(IPSEC_CONF_DST_ADDRESS,
   4352 			    act_props->pattern[i]) != 0) {
   4353 				error_message(BAD_ERROR,
   4354 				    IPSEC_CONF_DST_ADDRESS, line_no);
   4355 				return (-1);
   4356 			}
   4357 			if (!cptr->has_dmask)
   4358 				cptr->has_dmask = has_daprefix;
   4359 			break;
   4360 
   4361 		case TOK_saddr:
   4362 			if (new_style) {
   4363 				error_message(BAD_ERROR,
   4364 				    IPSEC_CONF_SRC_ADDRESS, line_no);
   4365 				return (-1);
   4366 			}
   4367 			old_style = B_TRUE;
   4368 
   4369 			if (saddr) {
   4370 				error_message(DUP_ERROR,
   4371 				    IPSEC_CONF_SRC_ADDRESS, line_no);
   4372 				return (-1);
   4373 			}
   4374 			/*
   4375 			 * Use this to detect duplicates rather
   4376 			 * than 0 like other cases, because 0 for
   4377 			 * address means INADDR_ANY.
   4378 			 */
   4379 			saddr = B_TRUE;
   4380 			cptr->has_saddr = 1;
   4381 			/*
   4382 			 * Advance to the string containing
   4383 			 * the address.
   4384 			 */
   4385 			i++, line_no++;
   4386 			if (act_props->pattern[i] == NULL) {
   4387 				error_message(BAD_ERROR,
   4388 				    IPSEC_CONF_SRC_ADDRESS, line_no);
   4389 				return (-1);
   4390 			}
   4391 
   4392 			if (parse_address(IPSEC_CONF_SRC_ADDRESS,
   4393 			    act_props->pattern[i]) != 0) {
   4394 				error_message(BAD_ERROR,
   4395 				    IPSEC_CONF_SRC_ADDRESS, line_no);
   4396 				return (-1);
   4397 			}
   4398 			/* shp or bhp? */
   4399 			if (!cptr->has_smask)
   4400 				cptr->has_smask = has_saprefix;
   4401 			break;
   4402 
   4403 		case TOK_daddr:
   4404 			if (new_style) {
   4405 				error_message(BAD_ERROR,
   4406 				    IPSEC_CONF_DST_ADDRESS, line_no);
   4407 				return (-1);
   4408 			}
   4409 			old_style = B_TRUE;
   4410 
   4411 			if (daddr) {
   4412 				error_message(DUP_ERROR,
   4413 				    IPSEC_CONF_DST_ADDRESS, line_no);
   4414 				return (-1);
   4415 			}
   4416 			/*
   4417 			 * Use this to detect duplicates rather
   4418 			 * than 0 like other cases, because 0 for
   4419 			 * address means INADDR_ANY.
   4420 			 */
   4421 			daddr = B_TRUE;
   4422 			cptr->has_daddr = 1;
   4423 			/*
   4424 			 * Advance to the string containing
   4425 			 * the address.
   4426 			 */
   4427 			i++, line_no++;
   4428 			if (act_props->pattern[i] == NULL) {
   4429 				error_message(BAD_ERROR,
   4430 				    IPSEC_CONF_DST_ADDRESS, line_no);
   4431 				return (-1);
   4432 			}
   4433 			if (parse_address(IPSEC_CONF_DST_ADDRESS,
   4434 			    act_props->pattern[i]) != 0) {
   4435 				error_message(BAD_ERROR,
   4436 				    IPSEC_CONF_DST_ADDRESS, line_no);
   4437 				return (-1);
   4438 			}
   4439 			if (!cptr->has_dmask)
   4440 				cptr->has_dmask = has_daprefix;
   4441 			break;
   4442 
   4443 		case TOK_sport:
   4444 			if (new_style) {
   4445 				error_message(BAD_ERROR,
   4446 				    IPSEC_CONF_SRC_PORT, line_no);
   4447 				return (-1);
   4448 			}
   4449 			old_style = B_TRUE;
   4450 
   4451 			if (cptr->ips_src_port_min != 0) {
   4452 				error_message(DUP_ERROR, IPSEC_CONF_SRC_PORT,
   4453 				    line_no);
   4454 				return (-1);
   4455 			}
   4456 			i++, line_no++;
   4457 			if (act_props->pattern[i] == NULL) {
   4458 				error_message(BAD_ERROR, IPSEC_CONF_SRC_PORT,
   4459 				    line_no);
   4460 				return (-1);
   4461 			}
   4462 			ret = parse_port(IPSEC_CONF_SRC_PORT,
   4463 			    act_props->pattern[i], cptr);
   4464 			if (ret != 0) {
   4465 				error_message(BAD_ERROR, IPSEC_CONF_SRC_PORT,
   4466 				    line_no);
   4467 				return (-1);
   4468 			}
   4469 			break;
   4470 		case TOK_dport:
   4471 			if (new_style) {
   4472 				error_message(BAD_ERROR,
   4473 				    IPSEC_CONF_DST_PORT, line_no);
   4474 				return (-1);
   4475 			}
   4476 			old_style = B_TRUE;
   4477 
   4478 			if (cptr->ips_dst_port_min != 0) {
   4479 				error_message(DUP_ERROR, IPSEC_CONF_DST_PORT,
   4480 				    line_no);
   4481 				return (-1);
   4482 			}
   4483 			i++, line_no++;
   4484 			if (act_props->pattern[i] == NULL) {
   4485 				error_message(BAD_ERROR, IPSEC_CONF_DST_PORT,
   4486 				    line_no);
   4487 				return (-1);
   4488 			}
   4489 			ret = parse_port(IPSEC_CONF_DST_PORT,
   4490 			    act_props->pattern[i],
   4491 			    cptr);
   4492 			if (ret != 0) {
   4493 				error_message(BAD_ERROR, IPSEC_CONF_DST_PORT,
   4494 				    line_no);
   4495 				return (-1);
   4496 			}
   4497 			break;
   4498 
   4499 		case TOK_lport:
   4500 			if (old_style) {
   4501 				error_message(BAD_ERROR,
   4502 				    IPSEC_CONF_SRC_PORT, line_no);
   4503 				return (-1);
   4504 			}
   4505 			new_style = B_TRUE;
   4506 
   4507 			if (cptr->ips_src_port_min != 0) {
   4508 				error_message(DUP_ERROR, IPSEC_CONF_SRC_PORT,
   4509 				    line_no);
   4510 				return (-1);
   4511 			}
   4512 			i++, line_no++;
   4513 			if (act_props->pattern[i] == NULL) {
   4514 				error_message(BAD_ERROR, IPSEC_CONF_SRC_PORT,
   4515 				    line_no);
   4516 				return (-1);
   4517 			}
   4518 			ret = parse_port(IPSEC_CONF_SRC_PORT,
   4519 			    act_props->pattern[i],
   4520 			    cptr);
   4521 			if (ret != 0) {
   4522 				error_message(BAD_ERROR, IPSEC_CONF_SRC_PORT,
   4523 				    line_no);
   4524 				return (-1);
   4525 			}
   4526 			break;
   4527 
   4528 		case TOK_rport:
   4529 			if (old_style) {
   4530 				error_message(BAD_ERROR,
   4531 				    IPSEC_CONF_DST_PORT, line_no);
   4532 				return (-1);
   4533 			}
   4534 			new_style = B_TRUE;
   4535 
   4536 			if (cptr->ips_dst_port_min != 0) {
   4537 				error_message(DUP_ERROR, IPSEC_CONF_DST_PORT,
   4538 				    line_no);
   4539 				return (-1);
   4540 			}
   4541 			i++, line_no++;
   4542 			if (act_props->pattern[i] == NULL) {
   4543 				error_message(BAD_ERROR, IPSEC_CONF_DST_PORT,
   4544 				    line_no);
   4545 				return (-1);
   4546 			}
   4547 			ret = parse_port(IPSEC_CONF_DST_PORT,
   4548 			    act_props->pattern[i],
   4549 			    cptr);
   4550 			if (ret != 0) {
   4551 				error_message(BAD_ERROR, IPSEC_CONF_DST_PORT,
   4552 				    line_no);
   4553 				return (-1);
   4554 			}
   4555 			break;
   4556 
   4557 		case TOK_smask:
   4558 			if (new_style) {
   4559 				error_message(BAD_ERROR,
   4560 				    IPSEC_CONF_SRC_MASK, line_no);
   4561 				return (-1);
   4562 			}
   4563 			old_style = B_TRUE;
   4564 			cptr->has_smask = B_TRUE;
   4565 
   4566 			IN6_V4MAPPED_TO_INADDR(&cptr->ips_src_mask_v6, &mask);
   4567 			if (mask.s_addr != 0) {
   4568 				error_message(DUP_ERROR, IPSEC_CONF_SRC_MASK,
   4569 				    line_no);
   4570 				return (-1);
   4571 			}
   4572 			i++, line_no++;
   4573 			if (act_props->pattern[i] == NULL) {
   4574 				error_message(BAD_ERROR, IPSEC_CONF_SRC_MASK,
   4575 				    line_no);
   4576 				return (-1);
   4577 			}
   4578 			ret = parse_mask(IPSEC_CONF_SRC_MASK,
   4579 			    act_props->pattern[i],
   4580 			    cptr);
   4581 			if (ret != 0) {
   4582 				error_message(BAD_ERROR, IPSEC_CONF_SRC_MASK,
   4583 				    line_no);
   4584 				return (-1);
   4585 			}
   4586 			break;
   4587 		case TOK_dmask:
   4588 			if (new_style) {
   4589 				error_message(BAD_ERROR,
   4590 				    IPSEC_CONF_DST_MASK, line_no);
   4591 				return (-1);
   4592 			}
   4593 			old_style = B_TRUE;
   4594 			cptr->has_dmask = B_TRUE;
   4595 
   4596 			IN6_V4MAPPED_TO_INADDR(&cptr->ips_dst_mask_v6, &mask);
   4597 			if (mask.s_addr != 0) {
   4598 				error_message(DUP_ERROR, IPSEC_CONF_DST_MASK,
   4599 				    line_no);
   4600 				return (-1);
   4601 			}
   4602 			i++, line_no++;
   4603 			if (act_props->pattern[i] == NULL) {
   4604 				error_message(BAD_ERROR, IPSEC_CONF_DST_MASK,
   4605 				    line_no);
   4606 				return (-1);
   4607 			}
   4608 			ret = parse_mask(IPSEC_CONF_DST_MASK,
   4609 			    act_props->pattern[i],
   4610 			    cptr);
   4611 			if (ret != 0) {
   4612 				error_message(BAD_ERROR, IPSEC_CONF_DST_MASK,
   4613 				    line_no);
   4614 				return (-1);
   4615 			}
   4616 			break;
   4617 		case TOK_ulp:
   4618 			if (cptr->ips_ulp_prot != 0) {
   4619 				error_message(DUP_ERROR,
   4620 				    IPSEC_CONF_ULP, line_no);
   4621 				return (-1);
   4622 			}
   4623 			i++, line_no++;
   4624 			if (act_props->pattern[i] == NULL) {
   4625 				error_message(BAD_ERROR,
   4626 				    IPSEC_CONF_ULP, line_no);
   4627 				return (-1);
   4628 			}
   4629 			pent = getprotobyname(act_props->pattern[i]);
   4630 			if (pent == NULL) {
   4631 				int ulp;
   4632 				ulp = parse_int(act_props->pattern[i]);
   4633 				if (ulp == -1) {
   4634 					error_message(BAD_ERROR,
   4635 					    IPSEC_CONF_ULP, line_no);
   4636 					return (-1);
   4637 				}
   4638 				cptr->ips_ulp_prot = ulp;
   4639 			} else {
   4640 				cptr->ips_ulp_prot = pent->p_proto;
   4641 			}
   4642 			break;
   4643 		case TOK_type:
   4644 			if (cptr->has_type) {
   4645 				error_message(DUP_ERROR,
   4646 				    IPSEC_CONF_ICMP_TYPE, line_no);
   4647 				return (-1);
   4648 			}
   4649 
   4650 			i++, line_no++;
   4651 			type = parse_type_code(act_props->pattern[i],
   4652 			    icmp_type_table);
   4653 
   4654 			if (type > 65536 || type < 0) {
   4655 				error_message(BAD_ERROR,
   4656 				    IPSEC_CONF_ICMP_TYPE, line_no);
   4657 				return (-1);
   4658 			}
   4659 
   4660 			type_end = type / 256;
   4661 			type = type % 256;
   4662 
   4663 			if (type_end < type)
   4664 				type_end = type;
   4665 
   4666 			cptr->has_type = 1;
   4667 			cptr->ips_icmp_type = (uint8_t)type;
   4668 			cptr->ips_icmp_type_end = (uint8_t)type_end;
   4669 			break;
   4670 		case TOK_code:
   4671 			if (!cptr->has_type) {
   4672 				error_message(BAD_ERROR,
   4673 				    IPSEC_CONF_ICMP_CODE, line_no);
   4674 				return (-1);
   4675 			}
   4676 
   4677 			if (cptr->has_code) {
   4678 				error_message(DUP_ERROR,
   4679 				    IPSEC_CONF_ICMP_CODE, line_no);
   4680 				return (-1);
   4681 			}
   4682 
   4683 			i++, line_no++;
   4684 
   4685 			code = parse_type_code(act_props->pattern[i],
   4686 			    icmp_code_table);
   4687 			if (type > 65536 || type < 0) {
   4688 				error_message(BAD_ERROR,
   4689 				    IPSEC_CONF_ICMP_CODE, line_no);
   4690 				return (-1);
   4691 			}
   4692 			code_end = code / 256;
   4693 			code = code % 256;
   4694 
   4695 			if (code_end < code)
   4696 				code_end = code;
   4697 
   4698 			cptr->has_code = 1;
   4699 			cptr->ips_icmp_code = (uint8_t)code;
   4700 			cptr->ips_icmp_code_end = (uint8_t)code_end;
   4701 			break;
   4702 		case TOK_tunnel:
   4703 			if (cptr->has_tunnel == 1) {
   4704 				error_message(BAD_ERROR,
   4705 				    IPSEC_CONF_TUNNEL, line_no);
   4706 				return (-1);
   4707 			}
   4708 			i++, line_no++;
   4709 			if (act_props->pattern[i] == NULL) {
   4710 				error_message(BAD_ERROR,
   4711 				    IPSEC_CONF_TUNNEL, line_no);
   4712 				return (-1);
   4713 			}
   4714 
   4715 			if (strlcpy(tunif, act_props->pattern[i],
   4716 			    TUNNAMEMAXLEN) >= TUNNAMEMAXLEN) {
   4717 				error_message(BAD_ERROR,
   4718 				    IPSEC_CONF_TUNNEL, line_no);
   4719 				return (-1);
   4720 			}
   4721 			cptr->has_tunnel = 1;
   4722 			break;
   4723 		case TOK_negotiate:
   4724 			if (cptr->has_negotiate == 1) {
   4725 				error_message(BAD_ERROR,
   4726 				    IPSEC_CONF_NEGOTIATE, line_no);
   4727 				return (-1);
   4728 			}
   4729 			i++, line_no++;
   4730 			if (act_props->pattern[i] == NULL) {
   4731 				error_message(BAD_ERROR,
   4732 				    IPSEC_CONF_NEGOTIATE, line_no);
   4733 				return (-1);
   4734 			}
   4735 
   4736 			if (strncmp(act_props->pattern[i], "tunnel", 6) == 0) {
   4737 				cptr->ips_tunnel = B_TRUE;
   4738 			} else if (strncmp(
   4739 			    act_props->pattern[i], "transport", 9) != 0) {
   4740 				error_message(BAD_ERROR,
   4741 				    IPSEC_CONF_NEGOTIATE, line_no);
   4742 				return (-1);
   4743 			}
   4744 			cptr->has_negotiate = 1;
   4745 			break;
   4746 		}
   4747 
   4748 	}
   4749 
   4750 	/* Sanity check that certain tokens occur together */
   4751 	if (cptr->has_tunnel + cptr->has_negotiate == 1) {
   4752 		if (cptr->has_negotiate == 0) {
   4753 			error_message(REQ_ERROR, IPSEC_CONF_NEGOTIATE, line_no);
   4754 		} else {
   4755 			error_message(REQ_ERROR, IPSEC_CONF_TUNNEL, line_no);
   4756 		}
   4757 		errx(1, gettext(
   4758 		    "tunnel and negotiate tokens must occur together"));
   4759 		return (-1);
   4760 	}
   4761 
   4762 	/*
   4763 	 * Get the actions.
   4764 	 */
   4765 
   4766 	for (ap_num = 0; act_props->ap[ap_num].act != NULL; ap_num++) {
   4767 		ips_act_props_t *iap;
   4768 
   4769 		if (ap_num > 0) {
   4770 			/* or's only with new style */
   4771 			if (old_style) {
   4772 				(void) printf("%s\n", gettext(
   4773 				    "or's only with new style"));
   4774 				return (-1);
   4775 			}
   4776 			new_style = B_TRUE;
   4777 		}
   4778 
   4779 		ipsec_aalg = ipsec_ealg = ipsec_eaalg = auth_covered = B_FALSE;
   4780 		tok_count = 0;
   4781 
   4782 		for (k = 0; action_table[k].string; k++) {
   4783 			if (strcmp(act_props->ap[ap_num].act,
   4784 			    action_table[k].string) == 0)
   4785 				break;
   4786 		}
   4787 		/*
   4788 		 * The following thing should never happen as
   4789 		 * we have already tested for its validity in parse.
   4790 		 */
   4791 		if (action_table[k].string == NULL) {
   4792 			warnx(gettext("(form act)Invalid action on line "
   4793 			    "%d: %s"), (arg_indices[line_no] == 0) ? 1 :
   4794 			    arg_indices[line_no],
   4795 			    act_props->ap[ap_num].act);
   4796 			warnx("%s", act_props->ap[ap_num].act);
   4797 			return (-1);
   4798 		}
   4799 
   4800 		/* we have a good action alloc an iap */
   4801 		iap = alloc_iap(cptr);
   4802 
   4803 		iap->iap_action = action_table[k].value;
   4804 		iap->iap_act_tok = action_table[k].tok_val;
   4805 
   4806 		switch (action_table[k].tok_val) {
   4807 		case TOK_apply:
   4808 			cptr->ips_dir = SPD_RULE_FLAG_OUTBOUND;
   4809 			break;
   4810 		case TOK_permit:
   4811 			cptr->ips_dir = SPD_RULE_FLAG_INBOUND;
   4812 			break;
   4813 		case TOK_ipsec:
   4814 			if (old_style) {
   4815 				/* Using saddr/daddr with ipsec action. */
   4816 				if (!dir) {
   4817 					/* No direction specified */
   4818 					error_message(REQ_ERROR,
   4819 					    IPSEC_CONF_IPSEC_DIR, line_no);
   4820 					return (-1);
   4821 				}
   4822 				if (cptr->ips_dir == SPD_RULE_FLAG_INBOUND)
   4823 					/*
   4824 					 * Need to swap addresses if
   4825 					 * 'dir in' or translation to
   4826 					 * laddr/raddr will be incorrect.
   4827 					 */
   4828 					cptr->swap = 1;
   4829 			}
   4830 			if (!dir)
   4831 				cptr->ips_dir =
   4832 				    SPD_RULE_FLAG_INBOUND
   4833 				    |SPD_RULE_FLAG_OUTBOUND;
   4834 			break;
   4835 		case TOK_bypass:
   4836 		case TOK_drop:
   4837 			is_no_alg = B_TRUE;
   4838 			break;
   4839 		}
   4840 
   4841 		line_no++;
   4842 		/*
   4843 		 * Get the properties. NULL properties is not valid.
   4844 		 * Later checks will catch it.
   4845 		 */
   4846 		for (i = 0; act_props->ap[ap_num].prop[i]; i++, line_no++) {
   4847 			for (j = 0; property_table[j].string; j++) {
   4848 				if (strcmp(act_props->ap[ap_num].prop[i],
   4849 				    property_table[j].string) == 0) {
   4850 					break;
   4851 				}
   4852 			}
   4853 			if (property_table[j].string == NULL) {
   4854 				warnx(gettext("Invalid properties on line "
   4855 				    "%d: %s"),
   4856 				    (arg_indices[line_no] == 0) ?
   4857 				    1 : arg_indices[line_no],
   4858 				    act_props->ap[ap_num].prop[i]);
   4859 				return (-1);
   4860 			}
   4861 
   4862 			iap->iap_attr_tok[tok_count++]
   4863 			    = property_table[j].value;
   4864 
   4865 			switch (property_table[j].value) {
   4866 			case SPD_ATTR_AH_AUTH:
   4867 				if (ipsec_aalg) {
   4868 					error_message(DUP_ERROR,
   4869 					    IPSEC_CONF_IPSEC_AALGS, line_no);
   4870 					return (-1);
   4871 				}
   4872 				i++, line_no++;
   4873 				if (act_props->ap[ap_num].prop[i] == NULL) {
   4874 					error_message(BAD_ERROR,
   4875 					    IPSEC_CONF_IPSEC_AALGS, line_no);
   4876 					return (-1);
   4877 				}
   4878 				ret = parse_ipsec_alg(
   4879 				    act_props->ap[ap_num].prop[i],
   4880 				    iap, SPD_ATTR_AH_AUTH);
   4881 				if (ret == -2) {
   4882 					/* "none" - ignore */
   4883 					break;
   4884 				}
   4885 				if (ret != 0) {
   4886 					error_message(BAD_ERROR,
   4887 					    IPSEC_CONF_IPSEC_AALGS, line_no);
   4888 					return (-1);
   4889 				}
   4890 				ipsec_aalg = B_TRUE;
   4891 				auth_covered = B_TRUE;
   4892 				break;
   4893 			case SPD_ATTR_ESP_ENCR:
   4894 				/*
   4895 				 * If this option was not given
   4896 				 * and encr_auth_algs was given,
   4897 				 * we provide null-encryption.  We do the
   4898 				 * setting after we parse all the options.
   4899 				 */
   4900 				if (ipsec_ealg) {
   4901 					error_message(DUP_ERROR,
   4902 					    IPSEC_CONF_IPSEC_EALGS, line_no);
   4903 					return (-1);
   4904 				}
   4905 				i++, line_no++;
   4906 				if (act_props->ap[ap_num].prop[i] == NULL) {
   4907 					error_message(BAD_ERROR,
   4908 					    IPSEC_CONF_IPSEC_EALGS, line_no);
   4909 					return (-1);
   4910 				}
   4911 				ret = parse_ipsec_alg(
   4912 				    act_props->ap[ap_num].prop[i],
   4913 				    iap, SPD_ATTR_ESP_ENCR);
   4914 				if (ret == -2) {
   4915 					/* "none" - ignore */
   4916 					break;
   4917 				}
   4918 				if (ret != 0) {
   4919 					error_message(BAD_ERROR,
   4920 					    IPSEC_CONF_IPSEC_EALGS, line_no);
   4921 					return (-1);
   4922 				}
   4923 				is_combined_mode = combined_mode(iap);
   4924 				ipsec_ealg = B_TRUE;
   4925 				break;
   4926 			case SPD_ATTR_ESP_AUTH:
   4927 				/*
   4928 				 * If this option was not given and encr_algs
   4929 				 * option was given, we still pass a default
   4930 				 * value in ipsc_esp_auth_algs. This is to
   4931 				 * encourage the use of authentication with
   4932 				 * ESP.
   4933 				 */
   4934 				if (ipsec_eaalg) {
   4935 					error_message(DUP_ERROR,
   4936 					    IPSEC_CONF_IPSEC_EAALGS, line_no);
   4937 					return (-1);
   4938 				}
   4939 				i++, line_no++;
   4940 				if (act_props->ap[ap_num].prop[i] == NULL) {
   4941 					error_message(BAD_ERROR,
   4942 					    IPSEC_CONF_IPSEC_EAALGS, line_no);
   4943 					return (-1);
   4944 				}
   4945 				ret = parse_ipsec_alg(
   4946 				    act_props->ap[ap_num].prop[i],
   4947 				    iap, SPD_ATTR_ESP_AUTH);
   4948 				if (ret == -2) {
   4949 					/* "none" - ignore */
   4950 					break;
   4951 				}
   4952 				if (ret != 0) {
   4953 					error_message(BAD_ERROR,
   4954 					    IPSEC_CONF_IPSEC_EAALGS, line_no);
   4955 					return (-1);
   4956 				}
   4957 				ipsec_eaalg = B_TRUE;
   4958 				auth_covered = B_TRUE;
   4959 				break;
   4960 			case IPS_SA:
   4961 				i++, line_no++;
   4962 				if (act_props->ap[ap_num].prop[i] == NULL) {
   4963 					error_message(BAD_ERROR,
   4964 					    IPSEC_CONF_IPSEC_SA, line_no);
   4965 					return (-1);
   4966 				}
   4967 
   4968 				if (strcmp(act_props->ap[ap_num].prop[i],
   4969 				    "unique") == 0) {
   4970 					iap->iap_attr |= SPD_APPLY_UNIQUE;
   4971 				} else if (strcmp(act_props->ap[ap_num].prop[i],
   4972 				    "shared") != 0) {
   4973 					/* "shared" is default. */
   4974 					error_message(BAD_ERROR,
   4975 					    IPSEC_CONF_IPSEC_SA, line_no);
   4976 					return (-1);
   4977 				}
   4978 
   4979 				break;
   4980 			case IPS_DIR:
   4981 				if (dir) {
   4982 					error_message(DUP_ERROR,
   4983 					    IPSEC_CONF_IPSEC_DIR, line_no);
   4984 					return (-1);
   4985 				}
   4986 				if (new_style) {
   4987 					error_message(BAD_ERROR,
   4988 					    IPSEC_CONF_IPSEC_DIR, line_no);
   4989 					return (-1);
   4990 				}
   4991 				old_style = B_TRUE;
   4992 				dir = B_TRUE;
   4993 				i++, line_no++;
   4994 				if (act_props->ap[ap_num].prop[i] == NULL) {
   4995 					error_message(BAD_ERROR,
   4996 					    IPSEC_CONF_IPSEC_DIR, line_no);
   4997 					return (-1);
   4998 				}
   4999 				if (strcmp(act_props->ap[ap_num].prop[i],
   5000 				    "out") == 0) {
   5001 					cptr->ips_dir = SPD_RULE_FLAG_OUTBOUND;
   5002 				} else if (strcmp(act_props->ap[ap_num].prop[i],
   5003 				    "in") == 0) {
   5004 					cptr->ips_dir = SPD_RULE_FLAG_INBOUND;
   5005 				} else {
   5006 					error_message(BAD_ERROR,
   5007 					    IPSEC_CONF_IPSEC_DIR, line_no);
   5008 					return (-1);
   5009 				}
   5010 				if ((cptr->ips_dir & SPD_RULE_FLAG_INBOUND) &&
   5011 				    iap->iap_act_tok == TOK_apply) {
   5012 					warnx(gettext("Direction"
   5013 					    " in conflict with action"));
   5014 					return (-1);
   5015 				}
   5016 				if ((cptr->ips_dir & SPD_RULE_FLAG_OUTBOUND) &&
   5017 				    iap->iap_act_tok == TOK_permit) {
   5018 					warnx(gettext("Direction"
   5019 					    "in conflict with action"));
   5020 					return (-1);
   5021 				}
   5022 
   5023 				break;
   5024 			}
   5025 		}
   5026 
   5027 		if (is_combined_mode) {
   5028 			if (ipsec_eaalg) {
   5029 				warnx(gettext("ERROR: Rule on line %d: "
   5030 				    "Combined mode and esp authentication not "
   5031 				    "supported together."),
   5032 				    arg_indices[line_no] == 0 ? 1 :
   5033 				    arg_indices[line_no]);
   5034 				return (-1);
   5035 			}
   5036 			auth_covered = B_TRUE;
   5037 		}
   5038 		/* Warn here about no authentication! */
   5039 		if (!auth_covered && !is_no_alg) {
   5040 			warnx(gettext("DANGER:  Rule on line %d "
   5041 			    "has encryption with no authentication."),
   5042 			    arg_indices[line_no] == 0 ? 1 :
   5043 			    arg_indices[line_no]);
   5044 		}
   5045 
   5046 		if (!ipsec_ealg && ipsec_eaalg) {
   5047 			/*
   5048 			 * If the user has specified the auth alg to be used
   5049 			 * with encryption and did not provide a encryption
   5050 			 * algorithm, provide null encryption.
   5051 			 */
   5052 			iap->iap_eencr.alg_id = SADB_EALG_NULL;
   5053 			ipsec_ealg = B_TRUE;
   5054 		}
   5055 
   5056 		/* Set the level of IPSEC protection we want */
   5057 		if (ipsec_aalg && (ipsec_ealg || ipsec_eaalg)) {
   5058 			iap->iap_attr |= SPD_APPLY_AH|SPD_APPLY_ESP;
   5059 		} else if (ipsec_aalg) {
   5060 			iap->iap_attr |= SPD_APPLY_AH;
   5061 		} else if (ipsec_ealg || ipsec_eaalg) {
   5062 			iap->iap_attr |= SPD_APPLY_ESP;
   5063 		}
   5064 
   5065 		/* convert src/dst to local/remote */
   5066 		if (!new_style) {
   5067 			switch (cptr->ips_acts->iap_act_tok) {
   5068 			case TOK_apply:
   5069 				/* outbound */
   5070 				/* src=local, dst=remote */
   5071 				/* this is ok. */
   5072 				break;
   5073 
   5074 			case TOK_permit:
   5075 				/* inbound */
   5076 				/* src=remote, dst=local */
   5077 				/* switch */
   5078 				cptr->swap = 1;
   5079 				break;
   5080 			case TOK_bypass:
   5081 			case TOK_drop:
   5082 				/* check the direction for what to do */
   5083 				if (cptr->ips_dir == SPD_RULE_FLAG_INBOUND)
   5084 					cptr->swap = 1;
   5085 				break;
   5086 			default:
   5087 				break;
   5088 			}
   5089 		}
   5090 		/* Validate the properties */
   5091 		if (ret = validate_properties(iap, dir,
   5092 		    (ipsec_aalg || ipsec_ealg || ipsec_eaalg))) {
   5093 			return (ret);
   5094 		}
   5095 	}
   5096 
   5097 	return (0);
   5098 
   5099 }
   5100 
   5101 static int
   5102 print_cmd_buf(FILE *fp, int error)
   5103 {
   5104 	*(cbuf + cbuf_offset) = '\0';
   5105 
   5106 	if (fp == stderr) {
   5107 		if (error != EEXIST) {
   5108 			warnx(gettext("Malformed command (fatal):\n%s"), cbuf);
   5109 			return (0);
   5110 		}
   5111 		if (ipsecconf_qflag) {
   5112 			return (0);
   5113 		}
   5114 		warnx(gettext("Duplicate policy entry (ignored):\n%s"), cbuf);
   5115 	} else {
   5116 		if (fprintf(fp, "%s", cbuf) == -1) {
   5117 			warn("fprintf");
   5118 			return (-1);
   5119 		}
   5120 	}
   5121 
   5122 	return (0);
   5123 }
   5124 
   5125 #ifdef	DEBUG
   5126 
   5127 static uchar_t *
   5128 addr_ptr(int isv4, struct in6_addr *addr6, struct in_addr *addr4)
   5129 {
   5130 	if (isv4) {
   5131 		IN6_V4MAPPED_TO_INADDR(addr6, addr4);
   5132 		return ((uchar_t *)&addr4->s_addr);
   5133 	} else {
   5134 		return ((uchar_t *)&addr6->s6_addr);
   5135 	}
   5136 }
   5137 
   5138 static void
   5139 dump_algreq(const char *tag, algreq_t *alg)
   5140 {
   5141 	(void) printf("%s algid %d, bits %d..%d\n",
   5142 	    tag, alg->alg_id, alg->alg_minbits, alg->alg_maxbits);
   5143 }
   5144 
   5145 static void
   5146 dump_conf(ips_conf_t *conf)
   5147 {
   5148 	boolean_t isv4 = conf->ips_isv4;
   5149 	struct in_addr addr;
   5150 	char buf[INET6_ADDRSTRLEN];
   5151 	int af;
   5152 	ips_act_props_t *iap = conf->ips_acts;
   5153 
   5154 	af = isv4 ? AF_INET : AF_INET6;
   5155 
   5156 	(void) printf("Source Addr is %s\n",
   5157 	    inet_ntop(af, addr_ptr(isv4, &conf->ips_src_addr_v6, &addr),
   5158 	    buf, INET6_ADDRSTRLEN));
   5159 
   5160 	(void) printf("Dest Addr is %s\n",
   5161 	    inet_ntop(af, addr_ptr(isv4, &conf->ips_dst_addr_v6, &addr),
   5162 	    buf, INET6_ADDRSTRLEN));
   5163 
   5164 	(void) printf("Source Mask is %s\n",
   5165 	    inet_ntop(af, addr_ptr(isv4, &conf->ips_src_mask_v6, &addr),
   5166 	    buf, INET6_ADDRSTRLEN));
   5167 
   5168 	(void) printf("Dest Mask is %s\n",
   5169 	    inet_ntop(af, addr_ptr(isv4, &conf->ips_dst_mask_v6, &addr),
   5170 	    buf, INET6_ADDRSTRLEN));
   5171 
   5172 	(void) printf("Source port %d\n", ntohs(conf->ips_src_port_min));
   5173 	(void) printf("Dest port %d\n", ntohs(conf->ips_dst_port_min));
   5174 	(void) printf("ULP %d\n", conf->ips_ulp_prot);
   5175 
   5176 	(void) printf("ICMP type %d-%d code %d-%d", conf->ips_icmp_type,
   5177 	    conf->ips_icmp_type_end,
   5178 	    conf->ips_icmp_code,
   5179 	    conf->ips_icmp_code_end);
   5180 
   5181 	while (iap != NULL) {
   5182 		(void) printf("------------------------------------\n");
   5183 		(void) printf("IPsec act is %d\n", iap->iap_action);
   5184 		(void) printf("IPsec attr is %d\n", iap->iap_attr);
   5185 		dump_algreq("AH authentication", &iap->iap_aauth);
   5186 		dump_algreq("ESP authentication", &iap->iap_eauth);
   5187 		dump_algreq("ESP encryption", &iap->iap_eencr);
   5188 		(void) printf("------------------------------------\n");
   5189 		iap = iap->iap_next;
   5190 	}
   5191 
   5192 	(void) fflush(stdout);
   5193 }
   5194 #endif	/* DEBUG */
   5195 
   5196 
   5197 static int
   5198 ipsec_conf_add(boolean_t just_check, boolean_t smf_managed, boolean_t replace)
   5199 {
   5200 	act_prop_t *act_props = malloc(sizeof (act_prop_t));
   5201 	ips_conf_t conf;
   5202 	FILE *fp, *policy_fp;
   5203 	int ret, flushret, i, j, diag, num_rules, good_rules;
   5204 	char *warning = gettext(
   5205 	    "\tWARNING : New policy entries that are being added may\n "
   5206 	    "\taffect the existing connections. Existing connections\n"
   5207 	    "\tthat are not subjected to policy constraints, may be\n"
   5208 	    "\tsubjected to policy constraints because of the new\n"
   5209 	    "\tpolicy. This can disrupt the communication of the\n"
   5210 	    "\texisting connections.\n\n");
   5211 
   5212 	boolean_t first_time = B_TRUE;
   5213 	num_rules = 0;
   5214 	good_rules = 0;
   5215 
   5216 	if (act_props == NULL) {
   5217 		warn(gettext("memory"));
   5218 		return (-1);
   5219 	}
   5220 
   5221 	if (strcmp(filename, "-") == 0)
   5222 		fp = stdin;
   5223 	else
   5224 		fp = fopen(filename, "r");
   5225 
   5226 	/*
   5227 	 * Treat the non-existence of a policy file as a special
   5228 	 * case when ipsecconf is being managed by smf(5).
   5229 	 * The assumption is the administrator has not yet
   5230 	 * created a policy file, this should not force the service
   5231 	 * into maintenance mode.
   5232 	 */
   5233 
   5234 	if (fp == NULL) {
   5235 		if (smf_managed) {
   5236 			(void) fprintf(stdout, gettext(
   5237 			    "Policy configuration file (%s) does not exist.\n"
   5238 			    "IPsec policy not configured.\n"), filename);
   5239 			return (0);
   5240 		}
   5241 		warn(gettext("%s : Policy config file cannot be opened"),
   5242 		    filename);
   5243 		usage();
   5244 		return (-1);
   5245 	}
   5246 	/*
   5247 	 * This will create the file if it does not exist.
   5248 	 * Make sure the umask is right.
   5249 	 */
   5250 	(void) umask(0022);
   5251 	policy_fp = fopen(POLICY_CONF_FILE, "a");
   5252 	if (policy_fp == NULL) {
   5253 		warn(gettext("%s cannot be opened"), POLICY_CONF_FILE);
   5254 		return (-1);
   5255 	}
   5256 
   5257 	/*
   5258 	 * Pattern, action, and properties are allocated in
   5259 	 * parse_pattern_or_prop and in parse_action (called by
   5260 	 * parse_one) as we parse arguments.
   5261 	 */
   5262 	while ((ret = parse_one(fp, act_props)) != PARSE_EOF) {
   5263 		num_rules++;
   5264 		if (ret != 0) {
   5265 			(void) print_cmd_buf(stderr, NOERROR);
   5266 			continue;
   5267 		}
   5268 
   5269 		/*
   5270 		 * If there is no action and parse returned success,
   5271 		 * it means that there is nothing to add.
   5272 		 */
   5273 		if (act_props->pattern[0] == NULL &&
   5274 		    act_props->ap[0].act == NULL)
   5275 				break;
   5276 
   5277 		ret = form_ipsec_conf(act_props, &conf);
   5278 		if (ret != 0) {
   5279 			warnx(gettext("form_ipsec_conf error"));
   5280 			(void) print_cmd_buf(stderr, NOERROR);
   5281 			/* Reset globals before trying the next rule. */
   5282 			if (shp != NULL) {
   5283 				freehostent(shp);
   5284 				shp = NULL;
   5285 			}
   5286 			if (dhp != NULL) {
   5287 				freehostent(dhp);
   5288 				dhp = NULL;
   5289 			}
   5290 			splen = 0;
   5291 			dplen = 0;
   5292 			continue;
   5293 		}
   5294 
   5295 		good_rules++;
   5296 
   5297 		if (first_time) {
   5298 			/*
   5299 			 * Time to assume that there are valid policy entries.
   5300 			 * If the IPsec kernel modules are not loaded this
   5301 			 * will load them now.
   5302 			 */
   5303 			first_time = B_FALSE;
   5304 			fetch_algorithms();
   5305 			ipsec_conf_admin(SPD_CLONE);
   5306 
   5307 			/*
   5308 			 * The default behaviour for IPSEC_CONF_ADD is to append
   5309 			 * the new rules to the existing policy. If a new rule
   5310 			 * collides with an existing rule, the new rule won't be
   5311 			 * added.
   5312 			 *
   5313 			 * To perform an atomic policy replace, we really don't
   5314 			 * care what the existing policy was, just replace it
   5315 			 * with the new one. Remove all rules from the SPD_CLONE
   5316 			 * policy before checking the new rules.
   5317 			 */
   5318 			if (replace) {
   5319 				flushret = ipsec_conf_flush(SPD_STANDBY);
   5320 				if (flushret != 0)
   5321 					return (flushret);
   5322 			}
   5323 		}
   5324 
   5325 		/*
   5326 		 * shp, dhp, splen, and dplen are globals set by
   5327 		 * form_ipsec_conf() while parsing the addresses.
   5328 		 */
   5329 		if (shp == NULL && dhp == NULL) {
   5330 			switch (do_port_adds(&conf)) {
   5331 			case 0:
   5332 				/* no error */
   5333 				break;
   5334 			case EEXIST:
   5335 				/* duplicate entries, continue adds */
   5336 				(void) print_cmd_buf(stderr, EEXIST);
   5337 				goto next;
   5338 			default:
   5339 				/* other error, bail */
   5340 				ret = -1;
   5341 				goto bail;
   5342 			}
   5343 		} else {
   5344 			ret = do_address_adds(&conf, &diag);
   5345 			switch (ret) {
   5346 			case 0:
   5347 				/* no error. */
   5348 				break;
   5349 			case EEXIST:
   5350 				(void) print_cmd_buf(stderr, EEXIST);
   5351 				goto next;
   5352 			case EBUSY:
   5353 				warnx(gettext(
   5354 				    "Can't set mask and /NN prefix."));
   5355 				ret = -1;
   5356 				break;
   5357 			case ENOENT:
   5358 				warnx(gettext("Cannot find tunnel "
   5359 				    "interface %s."), interface_name);
   5360 				ret = -1;
   5361 				break;
   5362 			case EINVAL:
   5363 				/*
   5364 				 * PF_POLICY didn't like what we sent.  We
   5365 				 * can't check all input up here, but we
   5366 				 * do in-kernel.
   5367 				 */
   5368 				warnx(gettext("PF_POLICY invalid input:\n\t%s"),
   5369 				    spdsock_diag(diag));
   5370 				break;
   5371 			case EOPNOTSUPP:
   5372 				warnx(gettext("Can't set /NN"
   5373 				    " prefix on multi-host name."));
   5374 				ret = -1;
   5375 				break;
   5376 			case ERANGE:
   5377 				warnx(gettext("/NN prefix is too big!"));
   5378 				ret = -1;
   5379 				break;
   5380 			case ESRCH:
   5381 				warnx(gettext("No matching IPv4 or "
   5382 				    "IPv6 saddr/daddr pairs"));
   5383 				ret = -1;
   5384 				break;
   5385 			default:
   5386 				/* Should never get here. */
   5387 				errno = ret;
   5388 				warn(gettext("Misc. error"));
   5389 				ret = -1;
   5390 			}
   5391 			if (ret == -1)
   5392 				goto bail;
   5393 		}
   5394 
   5395 		/*
   5396 		 * Go ahead and add policy entries to config file.
   5397 		 * The # should help re-using the ipsecpolicy.conf
   5398 		 * for input again as # will be treated as comment.
   5399 		 */
   5400 		if (fprintf(policy_fp, "%s %lld \n", INDEX_TAG,
   5401 		    conf.ips_policy_index) == -1) {
   5402 			warn("fprintf");
   5403 			warnx(gettext("Addition incomplete, Please "
   5404 			    "flush all the entries and re-configure :"));
   5405 			reconfigure();
   5406 			ret = -1;
   5407 			break;
   5408 		}
   5409 		if (print_cmd_buf(policy_fp, NOERROR) == -1) {
   5410 			warnx(gettext("Addition incomplete. Please "
   5411 			    "flush all the entries and re-configure :"));
   5412 			reconfigure();
   5413 			ret = -1;
   5414 			break;
   5415 		}
   5416 		/*
   5417 		 * We add one newline by default to separate out the
   5418 		 * entries. If the last character is not a newline, we
   5419 		 * insert a newline for free. This makes sure that all
   5420 		 * entries look consistent in the file.
   5421 		 */
   5422 		if (*(cbuf + cbuf_offset - 1) == '\n') {
   5423 			if (fprintf(policy_fp, "\n") == -1) {
   5424 				warn("fprintf");
   5425 				warnx(gettext("Addition incomplete. "
   5426 				    "Please flush all the entries and "
   5427 				    "re-configure :"));
   5428 				reconfigure();
   5429 				ret = -1;
   5430 				break;
   5431 			}
   5432 		} else {
   5433 			if (fprintf(policy_fp, "\n\n") == -1) {
   5434 				warn("fprintf");
   5435 				warnx(gettext("Addition incomplete. "
   5436 				    "Please flush all the entries and "
   5437 				    "re-configure :"));
   5438 				reconfigure();
   5439 				ret = -1;
   5440 				break;
   5441 			}
   5442 		}
   5443 next:
   5444 		/*
   5445 		 * Make sure this gets to the disk before
   5446 		 * we parse the next entry.
   5447 		 */
   5448 		(void) fflush(policy_fp);
   5449 		for (i = 0; act_props->pattern[i] != NULL; i++)
   5450 			free(act_props->pattern[i]);
   5451 		for (j = 0; act_props->ap[j].act != NULL; j++) {
   5452 			free(act_props->ap[j].act);
   5453 			for (i = 0; act_props->ap[j].prop[i] != NULL; i++)
   5454 				free(act_props->ap[j].prop[i]);
   5455 		}
   5456 	}
   5457 	if (ret == PARSE_EOF)
   5458 		ret = 0; /* Not an error */
   5459 bail:
   5460 	if (ret == -1) {
   5461 		(void) print_cmd_buf(stderr, EINVAL);
   5462 		for (i = 0; act_props->pattern[i] != NULL; i++)
   5463 			free(act_props->pattern[i]);
   5464 		for (j = 0; act_props->ap[j].act != NULL; j++) {
   5465 			free(act_props->ap[j].act);
   5466 			for (i = 0; act_props->ap[j].prop[i] != NULL; i++)
   5467 				free(act_props->ap[j].prop[i]);
   5468 		}
   5469 	}
   5470 #ifdef DEBUG_HEAVY
   5471 	(void) printf("ipsec_conf_add: ret val = %d\n", ret);
   5472 	(void) fflush(stdout);
   5473 #endif
   5474 	if (num_rules == 0 && ret == 0) {
   5475 		nuke_adds();
   5476 		(void) restore_all_signals();
   5477 		(void) unlock(lfd);
   5478 		EXIT_OK("Policy file does not contain any valid rules.");
   5479 	}
   5480 	if (num_rules != good_rules) {
   5481 		/* This is an error */
   5482 		nuke_adds();
   5483 		(void) restore_all_signals();
   5484 		(void) unlock(lfd);
   5485 		EXIT_BADCONFIG2("%d policy rule(s) contained errors.",
   5486 		    num_rules - good_rules);
   5487 	}
   5488 	/* looks good, flip it in */
   5489 	if (ret == 0 && !just_check) {
   5490 		if (!ipsecconf_qflag) {
   5491 			(void) printf("%s", warning);
   5492 		}
   5493 		if (smf_managed)
   5494 			warnx(gettext("%d policy rules added."), good_rules);
   5495 		ipsec_conf_admin(SPD_FLIP);
   5496 	} else {
   5497 		nuke_adds();
   5498 		if (just_check) {
   5499 			(void) fprintf(stdout, gettext("IPsec configuration "
   5500 			    "does not contain any errors.\n"));
   5501 			(void) fprintf(stdout, gettext(
   5502 			    "IPsec policy was not modified.\n"));
   5503 			(void) fflush(stdout);
   5504 		}
   5505 	}
   5506 	flushret = ipsec_conf_flush(SPD_STANDBY);
   5507 	if (flushret != 0)
   5508 		return (flushret);
   5509 	return (ret);
   5510 }
   5511 
   5512 
   5513 static int
   5514 ipsec_conf_sub()
   5515 {
   5516 	act_prop_t *act_props = malloc(sizeof (act_prop_t));
   5517 	FILE *remove_fp, *policy_fp;
   5518 	char rbuf[MAXLEN], pbuf[MAXLEN], /* remove buffer, and policy buffer */
   5519 	    *warning = gettext(
   5520 	    "\tWARNING: Policy entries that are being removed may\n"
   5521 	    "\taffect the existing connections.  Existing connections\n"
   5522 	    "\tthat are subjected to policy constraints may no longer\n"
   5523 	    "\tbe subjected to policy contraints because of its\n"
   5524 	    "\tremoval.  This can compromise security, and disrupt\n"
   5525 	    "\tthe communication of the existing connection.\n"
   5526 	    "\tConnections that are latched will remain unaffected\n"
   5527 	    "\tuntil they close.\n");
   5528 	int ret = 0;
   5529 	int index_len, pindex = 0; /* init value in case of pfile error */
   5530 
   5531 	if (act_props == NULL) {
   5532 		warn(gettext("memory"));
   5533 		return (-1);
   5534 	}
   5535 
   5536 	/* clone into standby DB */
   5537 	(void) ipsec_conf_admin(SPD_CLONE);
   5538 
   5539 	if (strcmp(filename, "-") == 0)
   5540 		remove_fp = stdin;
   5541 	else
   5542 		remove_fp = fopen(filename, "r");
   5543 
   5544 	if (remove_fp == NULL) {
   5545 		warn(gettext("%s : Input file cannot be opened"), filename);
   5546 		usage();
   5547 		free(act_props);
   5548 		return (-1);
   5549 	}
   5550 
   5551 	/* open policy file so we can locate the correct policy */
   5552 	(void) umask(0022);  /* in case it gets created! */
   5553 	policy_fp = fopen(POLICY_CONF_FILE, "r+");
   5554 	if (policy_fp == NULL) {
   5555 		warn(gettext("%s cannot be opened"), POLICY_CONF_FILE);
   5556 		(void) fclose(remove_fp);
   5557 		free(act_props);
   5558 		return (-1);
   5559 	}
   5560 
   5561 	/* don't print the warning if we're in q[uiet] mode */
   5562 	if (!ipsecconf_qflag)
   5563 		(void) printf("%s", warning);
   5564 
   5565 	/* this bit is done primarily so we can read what we write */
   5566 	index_len = strlen(INDEX_TAG);
   5567 
   5568 	/*
   5569 	 * We want to look for the policy in rbuf in the policy file.
   5570 	 * Go through the list of policies to remove, locating each one.
   5571 	 */
   5572 	while (fgets(rbuf, MAXLEN, remove_fp) != NULL) {
   5573 		char *buf;
   5574 		int offset, prev_offset, prev_prev_offset, nlines;
   5575 		fpos_t ipos;
   5576 		int pbuf_len = 0;
   5577 		char *tmp;
   5578 		/* skip blanks here (so we don't need to do it below)! */
   5579 		for (tmp = rbuf; (*tmp != '\0') && isspace(*tmp); )
   5580 			tmp++;
   5581 
   5582 		if (*tmp == '\0')
   5583 			continue; /* while(); */
   5584 
   5585 		/* skip the INDEX_TAG lines in the remove buffer */
   5586 		if (strncasecmp(rbuf, INDEX_TAG, index_len) == 0)
   5587 			continue;
   5588 
   5589 		/* skip commented lines */
   5590 		if (*tmp == '#')
   5591 			continue; /* while(); */
   5592 
   5593 		/*
   5594 		 * We start by presuming only good policies are in the pfile,
   5595 		 * and so only good policies from the rfile will match them.
   5596 		 * ipsec_conf_del ensures this later by calling parse_one() on
   5597 		 * pfile before it deletes the entry.
   5598 		 */
   5599 		for (offset = prev_offset = prev_prev_offset = 0;
   5600 		    fgets(pbuf, MAXLEN, policy_fp) != NULL;
   5601 		    offset += pbuf_len) {
   5602 			prev_offset = offset;
   5603 			pbuf_len = strlen(pbuf);
   5604 
   5605 			/* skip blank lines which seperate policy entries */
   5606 			if (pbuf[0] == '\n')
   5607 				continue;
   5608 
   5609 			/* if we found an index, save it */
   5610 			if (strncasecmp(pbuf, INDEX_TAG, index_len) == 0) {
   5611 				buf = pbuf + index_len;
   5612 				buf++;
   5613 				if ((pindex = parse_index(buf, NULL)) == -1) {
   5614 					/* bad index, we can't continue */
   5615 					warnx(gettext(
   5616 					    "Invalid index in the file"));
   5617 					(void) fclose(remove_fp);
   5618 					(void) fclose(policy_fp);
   5619 					free(act_props);
   5620 					return (-1);
   5621 				}
   5622 
   5623 				/* save this position in case it's the one */
   5624 				if (fgetpos(policy_fp, &ipos) != 0) {
   5625 					(void) fclose(remove_fp);
   5626 					(void) fclose(policy_fp);
   5627 					free(act_props);
   5628 					return (-1);
   5629 				}
   5630 			}
   5631 
   5632 			/* Does pbuf contain the remove policy? */
   5633 			if (strncasecmp(rbuf, pbuf, pbuf_len) == 0) {
   5634 				/* we found the one to remove! */
   5635 				if (pindex == 0) {
   5636 					warnx(gettext("Didn't find a valid "
   5637 					    "index for policy"));
   5638 					(void) fclose(remove_fp);
   5639 					(void) fclose(policy_fp);
   5640 					free(act_props);
   5641 					return (-1);
   5642 				}
   5643 
   5644 				/* off it - back up to the last INDEX! */
   5645 				if (fsetpos(policy_fp, &ipos) != 0) {
   5646 					(void) fclose(remove_fp);
   5647 					(void) fclose(policy_fp);
   5648 					free(act_props);
   5649 					return (-1);
   5650 				}
   5651 
   5652 				/* parse_one sets linecount = #lines to off */
   5653 				if (parse_one(policy_fp, act_props) == -1) {
   5654 					warnx(gettext("Invalid policy entry "
   5655 					    "in the file"));
   5656 					(void) fclose(remove_fp);
   5657 					(void) fclose(policy_fp);
   5658 					free(act_props);
   5659 					return (-1);
   5660 				}
   5661 
   5662 				nlines = linecount + 2;
   5663 				goto delete;
   5664 			}
   5665 			/*
   5666 			 * When we find a match, we want to pass the offset
   5667 			 * of the line that is before it - the INDEX_TAG line.
   5668 			 */
   5669 			prev_prev_offset = prev_offset;
   5670 		}
   5671 		/* Didn't find a match - look at the next remove policy */
   5672 		continue; /* while(); */
   5673 
   5674 delete:
   5675 		(void) fclose(policy_fp);
   5676 
   5677 		if (delete_from_file(prev_prev_offset, nlines) != 0) {
   5678 			warnx(gettext("delete_from_file failure.  "
   5679 			    "Please flush all entries and re-configure :"));
   5680 			reconfigure();
   5681 			(void) fclose(remove_fp);
   5682 			free(act_props);
   5683 			return (-1);
   5684 		}
   5685 
   5686 		if (pfp_delete_rule(pindex) != 0) {
   5687 			warnx(gettext("Deletion incomplete. Please flush"
   5688 			    "all the entries and re-configure :"));
   5689 			reconfigure();
   5690 			(void) fclose(remove_fp);
   5691 			free(act_props);
   5692 			return (-1);
   5693 		}
   5694 
   5695 		/* reset the globals */
   5696 		linecount = 0;
   5697 		pindex = 0;
   5698 		/* free(NULL) also works. */
   5699 		free(interface_name);
   5700 		interface_name = NULL;
   5701 
   5702 		/* reopen for next pass, automagically starting over. */
   5703 		policy_fp = fopen(POLICY_CONF_FILE, "r");
   5704 		if (policy_fp == NULL) {
   5705 			warn(gettext("%s cannot be re-opened, can't continue"),
   5706 			    POLICY_CONF_FILE);
   5707 			(void) fclose(remove_fp);
   5708 			free(act_props);
   5709 			return (-1);
   5710 		}
   5711 
   5712 	} /* read next remove policy */
   5713 
   5714 	if ((ret = pfp_delete_rule(pindex)) != 0) {
   5715 		warnx(gettext("Removal incomplete.  Please flush "
   5716 		    "all the entries and re-configure :"));
   5717 		reconfigure();
   5718 		free(act_props);
   5719 		return (ret);
   5720 	}
   5721 
   5722 	/* nothing left to look for */
   5723 	(void) fclose(remove_fp);
   5724 	free(act_props);
   5725 
   5726 	return (0);
   5727 }
   5728 
   5729 /*
   5730  * Constructs a tunnel interface ID extension.  Returns the length
   5731  * of the extension in 64-bit-words.
   5732  */
   5733 static int
   5734 attach_tunname(spd_if_t *tunname)
   5735 {
   5736 	if (tunname == NULL || interface_name == NULL)
   5737 		return (0);
   5738 
   5739 	tunname->spd_if_exttype = SPD_EXT_TUN_NAME;
   5740 	/*
   5741 	 * Use "-3" because there's 4 bytes in the message itself, and
   5742 	 * we lose one because of the '\0' terminator.
   5743 	 */
   5744 	tunname->spd_if_len = SPD_8TO64(
   5745 	    P2ROUNDUP(sizeof (*tunname) + strlen(interface_name) - 3, 8));
   5746 	(void) strlcpy((char *)tunname->spd_if_name, interface_name, LIFNAMSIZ);
   5747 	return (tunname->spd_if_len);
   5748 }
   5749