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