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