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