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