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