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