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