xref: /titanic_41/usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/ipsecconf.c (revision edf0039d316aafc2c1128aca35079119ecf024f1)
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 	char tstr[VALID_ALG_LEN];
3460 	char *lens = NULL;
3461 	char *l1_str;
3462 	int l1 = 0;
3463 	char *l2_str;
3464 	int l2 = SPD_MAX_MAXBITS;
3465 	algreq_t *ap;
3466 	uint_t a_type;
3467 
3468 	fetch_algorithms();
3469 
3470 	/*
3471 	 * Make sure that we get a null terminated string.
3472 	 * For a bad input, we truncate at VALID_ALG_LEN.
3473 	 */
3474 	(void) strlcpy(tstr, str, VALID_ALG_LEN);
3475 	lens = strtok(tstr, "()");
3476 	lens = strtok(NULL, "()");
3477 
3478 	if (lens != NULL) {
3479 		int len1 = 0;
3480 		int len2 = SPD_MAX_MAXBITS;
3481 		int len_all = strlen(lens);
3482 		int dot_start = (lens[0] == '.');
3483 		l1_str = strtok(lens, ".");
3484 		l2_str = strtok(NULL, ".");
3485 		if (l1_str != NULL) {
3486 			l1 = parse_int(l1_str);
3487 			len1 = strlen(l1_str);
3488 			if (len1 < 0)
3489 				return (1);
3490 		}
3491 		if (l2_str != NULL) {
3492 			l2 = parse_int(l2_str);
3493 			len2 = strlen(l2_str);
3494 			if (len2 < 0)
3495 				return (1);
3496 		}
3497 
3498 		if (len_all == len1) {
3499 			/* alg(n) */
3500 			l2 = l1;
3501 		} else if (dot_start) {
3502 			/* alg(..n) */
3503 			l2 = l1;
3504 			l1 = 0;
3505 		} else if ((len_all - 2) == len1) {
3506 			/* alg(n..) */
3507 			l2 = SPD_MAX_MAXBITS;
3508 		} /* else alg(n..m) */
3509 	}
3510 
3511 	if (alg_type == SPD_ATTR_AH_AUTH ||
3512 	    alg_type == SPD_ATTR_ESP_AUTH) {
3513 		alg_value = valid_algorithm(IPSEC_PROTO_AH, tstr);
3514 	} else {
3515 		alg_value = valid_algorithm(IPSEC_PROTO_ESP, tstr);
3516 	}
3517 	if (alg_value < 0) {
3518 		/* Invalid algorithm or "none" */
3519 		return (alg_value);
3520 	}
3521 
3522 	if (alg_type == SPD_ATTR_AH_AUTH) {
3523 		a_type = AH_AUTH;
3524 		iap->iap_attr |= SPD_APPLY_AH;
3525 		ap = &(iap->iap_aauth);
3526 	} else if (alg_type == SPD_ATTR_ESP_AUTH) {
3527 		a_type = ESP_AUTH;
3528 		iap->iap_attr |= SPD_APPLY_ESP|SPD_APPLY_ESPA;
3529 		ap = &(iap->iap_eauth);
3530 	} else {
3531 		a_type = ESP_ENCR;
3532 		iap->iap_attr |= SPD_APPLY_ESP;
3533 		ap = &(iap->iap_eencr);
3534 	}
3535 
3536 	ap->alg_id = alg_value;
3537 	ap->alg_minbits = l1;
3538 	ap->alg_maxbits = l2;
3539 
3540 	if (!alg_rangecheck(a_type, alg_value, ap))
3541 		return (1);
3542 
3543 	return (0);
3544 }
3545 
3546 static char *
3547 sys_error_message(int syserr)
3548 {
3549 	char *mesg;
3550 
3551 	switch (syserr) {
3552 	case EEXIST:
3553 		mesg = gettext("Entry already exists");
3554 		break;
3555 	case ENOENT:
3556 		mesg = gettext("Tunnel not found");
3557 		break;
3558 	case EINVAL:
3559 		mesg = gettext("Invalid entry");
3560 		break;
3561 	default :
3562 		mesg = strerror(syserr);
3563 	}
3564 	return (mesg);
3565 }
3566 
3567 static void
3568 error_message(error_type_t error, int type, int line)
3569 {
3570 	char *mesg;
3571 
3572 	switch (type) {
3573 	case IPSEC_CONF_SRC_ADDRESS:
3574 		mesg = gettext("Source Address");
3575 		break;
3576 	case IPSEC_CONF_DST_ADDRESS:
3577 		mesg = gettext("Destination Address");
3578 		break;
3579 	case IPSEC_CONF_SRC_PORT:
3580 		mesg = gettext("Source Port");
3581 		break;
3582 	case IPSEC_CONF_DST_PORT:
3583 		mesg = gettext("Destination Port");
3584 		break;
3585 	case IPSEC_CONF_SRC_MASK:
3586 		mesg = gettext("Source Mask");
3587 		break;
3588 	case IPSEC_CONF_DST_MASK:
3589 		mesg = gettext("Destination Mask");
3590 		break;
3591 	case IPSEC_CONF_ULP:
3592 		mesg = gettext("Upper Layer Protocol");
3593 		break;
3594 	case IPSEC_CONF_IPSEC_AALGS:
3595 		mesg = gettext("Authentication Algorithm");
3596 		break;
3597 	case IPSEC_CONF_IPSEC_EALGS:
3598 		mesg = gettext("Encryption Algorithm");
3599 		break;
3600 	case IPSEC_CONF_IPSEC_EAALGS:
3601 		mesg = gettext("ESP Authentication Algorithm");
3602 		break;
3603 	case IPSEC_CONF_IPSEC_SA:
3604 		mesg = gettext("SA");
3605 		break;
3606 	case IPSEC_CONF_IPSEC_DIR:
3607 		mesg = gettext("Direction");
3608 		break;
3609 	case IPSEC_CONF_ICMP_TYPE:
3610 		mesg = gettext("ICMP type");
3611 		break;
3612 	case IPSEC_CONF_ICMP_CODE:
3613 		mesg = gettext("ICMP code");
3614 		break;
3615 	case IPSEC_CONF_NEGOTIATE:
3616 		mesg = gettext("Negotiate");
3617 		break;
3618 	case IPSEC_CONF_TUNNEL:
3619 		mesg = gettext("Tunnel");
3620 		break;
3621 	default :
3622 		return;
3623 	}
3624 	/*
3625 	 * If we never read a newline character, we don't want
3626 	 * to print 0.
3627 	 */
3628 	warnx(gettext("%s%s%s %s on line: %d"),
3629 	    (error == BAD_ERROR) ? gettext("Bad") : "",
3630 	    (error == DUP_ERROR) ? gettext("Duplicate") : "",
3631 	    (error == REQ_ERROR) ? gettext("Requires") : "",
3632 	    mesg,
3633 	    (arg_indices[line] == 0) ? 1 : arg_indices[line]);
3634 }
3635 
3636 static int
3637 validate_properties(ips_act_props_t *cptr, boolean_t dir, boolean_t is_alg)
3638 {
3639 	if (cptr->iap_action == SPD_ACTTYPE_PASS ||
3640 	    cptr->iap_action == SPD_ACTTYPE_DROP) {
3641 		if (!dir) {
3642 			warnx(gettext("dir string "
3643 			    "not found for bypass policy"));
3644 		}
3645 
3646 		if (is_alg) {
3647 			warnx(gettext("Algorithms found for bypass policy"));
3648 			return (-1);
3649 		}
3650 		return (0);
3651 	}
3652 	if (!is_alg) {
3653 		warnx(gettext("No IPsec algorithms given"));
3654 		return (-1);
3655 	}
3656 	if (cptr->iap_attr == 0) {
3657 		warnx(gettext("No SA attribute"));
3658 		return (-1);
3659 	}
3660 	return (0);
3661 }
3662 
3663 /*
3664  * This function is called only to parse a single rule's worth of
3665  * action strings.  This is called after parsing pattern and before
3666  * parsing properties.  Thus we may have something in the leftover
3667  * buffer while parsing the pattern, which we need to handle here.
3668  */
3669 static int
3670 parse_action(FILE *fp, char **action, char **leftover)
3671 {
3672 	char *cp;
3673 	char ibuf[MAXLEN];
3674 	char *tmp_buf;
3675 	char *buf;
3676 	boolean_t new_stuff;
3677 
3678 	if (*leftover != NULL) {
3679 		buf = *leftover;
3680 		new_stuff = B_FALSE;
3681 		goto scan;
3682 	}
3683 	while (fgets(ibuf, MAXLEN, fp) != NULL) {
3684 		new_stuff = B_TRUE;
3685 		if (ibuf[strlen(ibuf) - 1] == '\n')
3686 			linecount++;
3687 		buf = ibuf;
3688 scan:
3689 		/* Truncate at the beginning of a comment */
3690 		cp = strchr(buf, '#');
3691 		if (cp != NULL)
3692 			*cp = NULL;
3693 
3694 		/* Skip any whitespace */
3695 		while (*buf != NULL && isspace(*buf))
3696 			buf++;
3697 
3698 		/* Empty line */
3699 		if (*buf == NULL)
3700 			continue;
3701 
3702 		/*
3703 		 * Store the command for error reporting
3704 		 * and ipsec_conf_add().
3705 		 */
3706 		if (new_stuff) {
3707 			/*
3708 			 * Check for buffer overflow including the null
3709 			 * terminating character.
3710 			 */
3711 			int len = strlen(ibuf);
3712 			if ((cbuf_offset + len + 1) >= CBUF_LEN)
3713 				return (-1);
3714 
3715 			(void) strcpy(cbuf + cbuf_offset, ibuf);
3716 			cbuf_offset += len;
3717 		}
3718 		/*
3719 		 * Start of the non-empty non-space character.
3720 		 */
3721 		tmp_buf = buf;
3722 
3723 		/* Skip until next whitespace or CURL_BEGIN */
3724 		while (*buf != NULL && !isspace(*buf) &&
3725 		    *buf != CURL_BEGIN)
3726 			buf++;
3727 
3728 		if (*buf != NULL) {
3729 			if (tmp_buf == buf) /* No action token */
3730 				goto error;
3731 			if (*buf == CURL_BEGIN) {
3732 				*buf = NULL;
3733 				/* Allocate an extra byte for the null also */
3734 				if ((*action = malloc(strlen(tmp_buf) + 1)) ==
3735 				    NULL) {
3736 					warn("malloc");
3737 					return (ENOMEM);
3738 				}
3739 				(void) strcpy(*action, tmp_buf);
3740 				*buf = CURL_BEGIN;
3741 			} else {
3742 				/* We have hit a space */
3743 				*buf++ = NULL;
3744 				/* Allocate an extra byte for the null also */
3745 				if ((*action = malloc(strlen(tmp_buf) + 1)) ==
3746 				    NULL) {
3747 					warn("malloc");
3748 					return (ENOMEM);
3749 				}
3750 				(void) strcpy(*action, tmp_buf);
3751 			}
3752 			/*
3753 			 * Copy the rest of the line into the
3754 			 * leftover buffer.
3755 			 */
3756 			if (*buf != NULL) {
3757 				(void) strlcpy(lo_buf, buf, sizeof (lo_buf));
3758 				*leftover = lo_buf;
3759 			} else {
3760 				*leftover = NULL;
3761 			}
3762 		} else {
3763 			/* Allocate an extra byte for the null also */
3764 			if ((*action = malloc(strlen(tmp_buf) + 1)) ==
3765 			    NULL) {
3766 				warn("malloc");
3767 				return (ENOMEM);
3768 			}
3769 			(void) strcpy(*action, tmp_buf);
3770 			*leftover = NULL;
3771 		}
3772 		if (argindex >= ARG_BUF_LEN) {
3773 			warnx(gettext("(parsing one command) "
3774 			    "Too many selectors before action."));
3775 			return (-1);
3776 		}
3777 		arg_indices[argindex++] = linecount;
3778 		return (PARSE_SUCCESS);
3779 	}
3780 	/*
3781 	 * Return error, on an empty action field.
3782 	 */
3783 error:
3784 	warnx(gettext("(parsing one command) "
3785 	    "Missing action token."));
3786 	return (-1);
3787 }
3788 
3789 /*
3790  * This is called to parse pattern or properties that is enclosed
3791  * between CURL_BEGIN and CURL_END.
3792  */
3793 static int
3794 parse_pattern_or_prop(FILE *fp, char *argvec[], char **leftover)
3795 {
3796 	char *cp;
3797 	int i = 0;
3798 	boolean_t curl_begin_seen = B_FALSE;
3799 	char ibuf[MAXLEN];
3800 	char *tmp_buf;
3801 	char *buf;
3802 	boolean_t new_stuff;
3803 
3804 	/*
3805 	 * When parsing properties, leftover buffer could have the
3806 	 * leftovers of the previous fgets().
3807 	 */
3808 	if (*leftover != NULL) {
3809 		buf = *leftover;
3810 		new_stuff = B_FALSE;
3811 		goto scan;
3812 	}
3813 	while (fgets(ibuf, MAXLEN, fp) != NULL) {
3814 		new_stuff = B_TRUE;
3815 #ifdef DEBUG_HEAVY
3816 		(void) printf("%s\n", ibuf);
3817 #endif
3818 		if (ibuf[strlen(ibuf) - 1] == '\n')
3819 			linecount++;
3820 		buf = ibuf;
3821 scan:
3822 		/* Truncate at the beginning of a comment */
3823 		cp = strchr(buf, '#');
3824 		if (cp != NULL)
3825 			*cp = NULL;
3826 
3827 		/* Skip any whitespace */
3828 		while (*buf != NULL && isspace(*buf))
3829 			buf++;
3830 
3831 		/* Empty line */
3832 		if (*buf == NULL)
3833 			continue;
3834 		/*
3835 		 * Store the command for error reporting
3836 		 * and ipsec_conf_add().
3837 		 */
3838 		if (new_stuff) {
3839 			/*
3840 			 * Check for buffer overflow including the null
3841 			 * terminating character.
3842 			 */
3843 			int len = strlen(ibuf);
3844 			if ((cbuf_offset + len + 1) >= CBUF_LEN)
3845 				return (-1);
3846 			(void) strcpy(cbuf + cbuf_offset, ibuf);
3847 			cbuf_offset += len;
3848 		}
3849 		/*
3850 		 * First non-space character should be
3851 		 * a curly bracket.
3852 		 */
3853 		if (!curl_begin_seen) {
3854 			if (*buf != CURL_BEGIN) {
3855 				/*
3856 				 * If we never read a newline character,
3857 				 * we don't want to print 0.
3858 				 */
3859 				warnx(gettext("line %d : pattern must start "
3860 				    "with \"%c\" character"),
3861 				    (linecount == 0) ? 1 : linecount,
3862 				    CURL_BEGIN);
3863 				return (-1);
3864 			}
3865 			buf++;
3866 			curl_begin_seen = B_TRUE;
3867 		}
3868 		/*
3869 		 * Arguments are separated by white spaces or
3870 		 * newlines. Scan till you see a CURL_END.
3871 		 */
3872 		while (*buf != NULL) {
3873 			if (*buf == CURL_END) {
3874 ret:
3875 				*buf++ = NULL;
3876 				/*
3877 				 * Copy the rest of the line into the
3878 				 * leftover buffer if any.
3879 				 */
3880 				if (*buf != NULL) {
3881 					(void) strlcpy(lo_buf, buf,
3882 					    sizeof (lo_buf));
3883 					*leftover = lo_buf;
3884 				} else {
3885 					*leftover = NULL;
3886 				}
3887 				return (PARSE_SUCCESS);
3888 			}
3889 			/*
3890 			 * Skip any trailing whitespace until we see a
3891 			 * non white-space character.
3892 			 */
3893 			while (*buf != NULL && isspace(*buf))
3894 				buf++;
3895 
3896 			if (*buf == CURL_END)
3897 				goto ret;
3898 
3899 			/* Scan the next line as this buffer is empty */
3900 			if (*buf == NULL)
3901 				break;
3902 
3903 			if (i >= MAXARGS) {
3904 				warnx(
3905 				    gettext("Number of Arguments exceeded %d"),
3906 				    i);
3907 				return (-1);
3908 			}
3909 			/*
3910 			 * Non-empty, Non-space buffer.
3911 			 */
3912 			tmp_buf = buf++;
3913 			/*
3914 			 * Real scan of the argument takes place here.
3915 			 * Skip past till space or CURL_END.
3916 			 */
3917 			while (*buf != NULL && !isspace(*buf) &&
3918 			    *buf != CURL_END) {
3919 				buf++;
3920 			}
3921 			/*
3922 			 * Either a space or we have hit the CURL_END or
3923 			 * the real end.
3924 			 */
3925 			if (*buf != NULL) {
3926 				if (*buf == CURL_END) {
3927 					*buf++ = NULL;
3928 					if ((argvec[i] = malloc(strlen(tmp_buf)
3929 					    + 1)) == NULL) {
3930 						warn("malloc");
3931 						return (ENOMEM);
3932 					}
3933 					if (strlen(tmp_buf) != 0) {
3934 						(void) strcpy(argvec[i],
3935 						    tmp_buf);
3936 						if (argindex >= ARG_BUF_LEN)
3937 							goto toomanyargs;
3938 						arg_indices[argindex++] =
3939 						    linecount;
3940 					}
3941 					/*
3942 					 * Copy the rest of the line into the
3943 					 * leftover buffer.
3944 					 */
3945 					if (*buf != NULL) {
3946 						(void) strlcpy(lo_buf, buf,
3947 						    sizeof (lo_buf));
3948 						*leftover = lo_buf;
3949 					} else {
3950 						*leftover = NULL;
3951 					}
3952 					return (PARSE_SUCCESS);
3953 				} else {
3954 					*buf++ = NULL;
3955 				}
3956 			}
3957 			/*
3958 			 * Copy this argument and scan for the buffer more
3959 			 * if it is non-empty. If it is empty scan for
3960 			 * the next line.
3961 			 */
3962 			if ((argvec[i] = malloc(strlen(tmp_buf) + 1)) ==
3963 			    NULL) {
3964 				warn("malloc");
3965 				return (ENOMEM);
3966 			}
3967 			(void) strcpy(argvec[i++], tmp_buf);
3968 			if (argindex >= ARG_BUF_LEN) {
3969 			/*
3970 			 * The number of tokens in a single policy entry
3971 			 * exceeds the number of buffers available to fully
3972 			 * parse the policy entry.
3973 			 */
3974 toomanyargs:
3975 				warnx(gettext("(parsing one command) "
3976 				    "Too many tokens in single policy entry."));
3977 				return (-1);
3978 			}
3979 			arg_indices[argindex++] = linecount;
3980 		}
3981 	}
3982 	/*
3983 	 * If nothing is given in the file, it is okay.
3984 	 * If something is given in the file and it is
3985 	 * not CURL_BEGIN, we would have returned error
3986 	 * above. If curl_begin_seen and we are here,
3987 	 * something is wrong.
3988 	 */
3989 	if (curl_begin_seen) {
3990 		warnx(gettext("(parsing one command) "
3991 		    "Pattern or Properties incomplete."));
3992 		return (-1);
3993 	}
3994 	return (PARSE_EOF);		/* Nothing more in the file */
3995 }
3996 
3997 /*
3998  * Parse one command i.e {pattern} action {properties}.
3999  *
4000  * {pattern} ( action {prop} | pass | drop ) (or ...)*
4001  */
4002 static int
4003 parse_one(FILE *fp, act_prop_t *act_props)
4004 {
4005 	char *leftover;
4006 	int ret;
4007 	int i;
4008 	int ap_num = 0;
4009 	enum parse_state {pattern, action, prop } pstate;
4010 
4011 	has_daprefix = has_saprefix = B_FALSE;
4012 
4013 	(void) memset(act_props, 0, sizeof (act_prop_t));
4014 	pstate = pattern;
4015 
4016 	ret = 0;
4017 	leftover = NULL;
4018 	argindex = 0;
4019 	cbuf_offset = 0;
4020 	assert(shp == NULL && dhp == NULL);
4021 
4022 	for (;;) {
4023 		switch (pstate) {
4024 		case pattern:
4025 		{
4026 #ifdef DEBUG_HEAVY
4027 			(void) printf("pattern\n");
4028 #endif
4029 			ret = parse_pattern_or_prop(fp,
4030 			    act_props->pattern, &leftover);
4031 			if (ret == PARSE_EOF) {
4032 				/* EOF reached */
4033 				return (PARSE_EOF);
4034 			}
4035 			if (ret != 0) {
4036 				ret = -1;
4037 				goto err;
4038 			}
4039 			pstate = action;
4040 			break;
4041 		}
4042 		case action:
4043 		{
4044 #ifdef DEBUG_HEAVY
4045 			(void) printf("action\n");
4046 #endif
4047 			ret = parse_action(fp,
4048 			    &act_props->ap[ap_num].act, &leftover);
4049 			if (ret != 0) {
4050 				ret = -1;
4051 				goto err;
4052 			}
4053 
4054 			/*
4055 			 * Validate action now itself so that we don't
4056 			 * proceed too much into the bad world.
4057 			 */
4058 			for (i = 0; action_table[i].string; i++) {
4059 				if (strcmp(act_props->ap[ap_num].act,
4060 				    action_table[i].string) == 0)
4061 					break;
4062 			}
4063 
4064 			if (action_table[i].tok_val == TOK_or) {
4065 				/* hit an or, go again */
4066 				break;
4067 			}
4068 
4069 			if (action_table[i].string == NULL) {
4070 				/*
4071 				 * If we never read a newline
4072 				 * character, we don't want
4073 				 * to print 0.
4074 				 */
4075 				warnx(gettext("(parsing one command) "
4076 				    "Invalid action on line %d: %s"),
4077 				    (linecount == 0) ? 1 : linecount,
4078 				    act_props->ap[ap_num].act);
4079 				return (-1);
4080 			}
4081 
4082 			pstate = prop;
4083 			break;
4084 		}
4085 		case prop:
4086 		{
4087 #ifdef DEBUG_HEAVY
4088 			(void) printf("prop\n");
4089 #endif
4090 			ret = parse_pattern_or_prop(fp,
4091 			    act_props->ap[ap_num].prop, &leftover);
4092 			if (ret != 0) {
4093 				if (ret == PARSE_EOF) {
4094 					warnx(gettext("(parsing one command) "
4095 					    "Missing properties."));
4096 				}
4097 				ret = -1;
4098 				goto err;
4099 			}
4100 
4101 			if (leftover != NULL) {
4102 				/* Accomodate spaces at the end */
4103 				while (*leftover != NULL) {
4104 					if (*leftover == BACK_SLASH) {
4105 						warnx(gettext("Invalid line "
4106 						    "continuation character."));
4107 						ret = -1;
4108 						goto err;
4109 					}
4110 					if (*leftover == 'o') {
4111 						leftover++;
4112 						if (*leftover == 'r') {
4113 							leftover++;
4114 							ap_num++;
4115 							pstate = action;
4116 							goto again;
4117 						}
4118 					}
4119 					if (!isspace(*leftover)) {
4120 						ret = -1;
4121 						goto err;
4122 					}
4123 					leftover++;
4124 				}
4125 				return (0);
4126 			}
4127 			ap_num++;
4128 			if (ap_num > MAXARGS)
4129 				return (0);
4130 			pstate = action; /* or */
4131 			break;
4132 		} /* case prop: */
4133 		} /* switch(pstate) */
4134 
4135 again:
4136 		if (ap_num > MAXARGS) {
4137 			warnx(gettext("Too many actions."));
4138 			return (-1);
4139 		}
4140 	} /* for(;;) */
4141 err:
4142 	if (ret != 0) {
4143 		/*
4144 		 * If we never read a newline character, we don't want
4145 		 * to print 0.
4146 		 */
4147 		warnx(gettext("Error before or at line %d"),
4148 		    (linecount == 0) ? 1 : linecount);
4149 	}
4150 	return (ret);
4151 }
4152 
4153 /*
4154  * convert an act_propts_t to an ips_conf_t
4155  */
4156 
4157 static int
4158 form_ipsec_conf(act_prop_t *act_props, ips_conf_t *cptr)
4159 {
4160 	int i, j, k;
4161 	int tok_count = 0;
4162 	struct protoent *pent;
4163 	boolean_t saddr, daddr, ipsec_aalg, ipsec_ealg, ipsec_eaalg, dir;
4164 	boolean_t old_style, new_style, auth_covered, is_no_alg;
4165 	boolean_t is_combined_mode;
4166 	struct in_addr mask;
4167 	int line_no;
4168 	int ret;
4169 	int ap_num = 0;
4170 	int type, code, type_end, code_end;
4171 #ifdef DEBUG_HEAVY
4172 	/*
4173 	 * pattern => act_props->pattern
4174 	 * action => act_props->ap[].act
4175 	 * properties => act_props->ap[].prop
4176 	 */
4177 	(void) printf("\npattern\n------------\n");
4178 	for (i = 0; act_props->pattern[i] != NULL; i++)
4179 		(void) printf("%s\n", act_props->pattern[i]);
4180 	(void) printf("apz\n----------\n");
4181 	for (j = 0; act_props->ap[j].act != NULL; j++) {
4182 
4183 		(void) printf("act%d->%s\n", j, act_props->ap[j].act);
4184 		for (i = 0; act_props->ap[j].prop[i] != NULL; i++)
4185 			(void) printf("%dprop%d->%s\n",
4186 			    j, i, act_props->ap[j].prop[i]);
4187 	}
4188 	(void) printf("------------\n\n");
4189 #endif
4190 
4191 	(void) memset(cptr, 0, sizeof (ips_conf_t));
4192 	saddr = daddr = ipsec_aalg = ipsec_ealg = ipsec_eaalg = dir = B_FALSE;
4193 	old_style = new_style = is_no_alg = is_combined_mode = B_FALSE;
4194 	/*
4195 	 * Get the Pattern. NULL pattern is valid.
4196 	 */
4197 	for (i = 0, line_no = 0; act_props->pattern[i]; i++, line_no++) {
4198 		for (j = 0; pattern_table[j].string; j++) {
4199 			if (strcmp(act_props->pattern[i],
4200 			    pattern_table[j].string) == 0)
4201 				break;
4202 		}
4203 
4204 		if (pattern_table[j].string == NULL) {
4205 			/*
4206 			 * If we never read a newline character, we don't want
4207 			 * to print 0.
4208 			 */
4209 			warnx(gettext("Invalid pattern on line %d: %s"),
4210 			    (arg_indices[line_no] == 0) ? 1 :
4211 			    arg_indices[line_no], act_props->pattern[i]);
4212 			return (-1);
4213 		}
4214 
4215 		cptr->patt_tok[tok_count++] = pattern_table[j].tok_val;
4216 
4217 		switch (pattern_table[j].tok_val) {
4218 
4219 		case TOK_dir:
4220 			i++, line_no++;
4221 			if (act_props->pattern[i] == NULL) {
4222 				error_message(BAD_ERROR,
4223 				    IPSEC_CONF_IPSEC_DIR, line_no);
4224 				return (-1);
4225 			}
4226 
4227 			if (strncmp(act_props->pattern[i], "in", 2) == 0) {
4228 				cptr->ips_dir = SPD_RULE_FLAG_INBOUND;
4229 			} else if (strncmp(
4230 			    act_props->pattern[i], "out", 3) == 0) {
4231 				cptr->ips_dir = SPD_RULE_FLAG_OUTBOUND;
4232 			} else if (strncmp(
4233 			    act_props->pattern[i], "both", 4) == 0) {
4234 				if (old_style) {
4235 					error_message(BAD_ERROR,
4236 					    IPSEC_CONF_IPSEC_DIR, line_no);
4237 					return (-1);
4238 				}
4239 				new_style = B_TRUE;
4240 				cptr->ips_dir =
4241 				    SPD_RULE_FLAG_OUTBOUND |
4242 				    SPD_RULE_FLAG_INBOUND;
4243 			} else {
4244 				error_message(BAD_ERROR,
4245 				    IPSEC_CONF_IPSEC_DIR, line_no);
4246 				return (-1);
4247 			}
4248 			dir = B_TRUE;
4249 			break;
4250 
4251 		case TOK_local:
4252 			if (old_style) {
4253 				error_message(BAD_ERROR,
4254 				    IPSEC_CONF_SRC_ADDRESS, line_no);
4255 				return (-1);
4256 			}
4257 			new_style = B_TRUE;
4258 
4259 			if (saddr) {
4260 				error_message(DUP_ERROR,
4261 				    IPSEC_CONF_SRC_ADDRESS, line_no);
4262 				return (-1);
4263 			}
4264 			/*
4265 			 * Use this to detect duplicates rather
4266 			 * than 0 like other cases, because 0 for
4267 			 * address means INADDR_ANY.
4268 			 */
4269 			saddr = B_TRUE;
4270 			cptr->has_saddr = 1;
4271 			/*
4272 			 * Advance to the string containing
4273 			 * the address.
4274 			 */
4275 			i++, line_no++;
4276 			if (act_props->pattern[i] == NULL) {
4277 				error_message(BAD_ERROR,
4278 				    IPSEC_CONF_SRC_ADDRESS, line_no);
4279 				return (-1);
4280 			}
4281 			if (parse_address(IPSEC_CONF_SRC_ADDRESS,
4282 			    act_props->pattern[i]) != 0) {
4283 				error_message(BAD_ERROR,
4284 				    IPSEC_CONF_SRC_ADDRESS, line_no);
4285 				return (-1);
4286 			}
4287 			if (!cptr->has_smask)
4288 				cptr->has_smask = has_saprefix;
4289 
4290 			break;
4291 		case TOK_remote:
4292 			if (old_style) {
4293 				error_message(BAD_ERROR,
4294 				    IPSEC_CONF_DST_ADDRESS, line_no);
4295 				return (-1);
4296 			}
4297 			new_style = B_TRUE;
4298 
4299 			if (daddr) {
4300 				error_message(DUP_ERROR,
4301 				    IPSEC_CONF_DST_ADDRESS, line_no);
4302 				return (-1);
4303 			}
4304 			/*
4305 			 * Use this to detect duplicates rather
4306 			 * than 0 like other cases, because 0 for
4307 			 * address means INADDR_ANY.
4308 			 */
4309 			daddr = B_TRUE;
4310 			cptr->has_daddr = 1;
4311 			/*
4312 			 * Advance to the string containing
4313 			 * the address.
4314 			 */
4315 			i++, line_no++;
4316 			if (act_props->pattern[i] == NULL) {
4317 				error_message(BAD_ERROR,
4318 				    IPSEC_CONF_DST_ADDRESS, line_no);
4319 				return (-1);
4320 			}
4321 			if (parse_address(IPSEC_CONF_DST_ADDRESS,
4322 			    act_props->pattern[i]) != 0) {
4323 				error_message(BAD_ERROR,
4324 				    IPSEC_CONF_DST_ADDRESS, line_no);
4325 				return (-1);
4326 			}
4327 			if (!cptr->has_dmask)
4328 				cptr->has_dmask = has_daprefix;
4329 			break;
4330 
4331 		case TOK_saddr:
4332 			if (new_style) {
4333 				error_message(BAD_ERROR,
4334 				    IPSEC_CONF_SRC_ADDRESS, line_no);
4335 				return (-1);
4336 			}
4337 			old_style = B_TRUE;
4338 
4339 			if (saddr) {
4340 				error_message(DUP_ERROR,
4341 				    IPSEC_CONF_SRC_ADDRESS, line_no);
4342 				return (-1);
4343 			}
4344 			/*
4345 			 * Use this to detect duplicates rather
4346 			 * than 0 like other cases, because 0 for
4347 			 * address means INADDR_ANY.
4348 			 */
4349 			saddr = B_TRUE;
4350 			cptr->has_saddr = 1;
4351 			/*
4352 			 * Advance to the string containing
4353 			 * the address.
4354 			 */
4355 			i++, line_no++;
4356 			if (act_props->pattern[i] == NULL) {
4357 				error_message(BAD_ERROR,
4358 				    IPSEC_CONF_SRC_ADDRESS, line_no);
4359 				return (-1);
4360 			}
4361 
4362 			if (parse_address(IPSEC_CONF_SRC_ADDRESS,
4363 			    act_props->pattern[i]) != 0) {
4364 				error_message(BAD_ERROR,
4365 				    IPSEC_CONF_SRC_ADDRESS, line_no);
4366 				return (-1);
4367 			}
4368 			/* shp or bhp? */
4369 			if (!cptr->has_smask)
4370 				cptr->has_smask = has_saprefix;
4371 			break;
4372 
4373 		case TOK_daddr:
4374 			if (new_style) {
4375 				error_message(BAD_ERROR,
4376 				    IPSEC_CONF_DST_ADDRESS, line_no);
4377 				return (-1);
4378 			}
4379 			old_style = B_TRUE;
4380 
4381 			if (daddr) {
4382 				error_message(DUP_ERROR,
4383 				    IPSEC_CONF_DST_ADDRESS, line_no);
4384 				return (-1);
4385 			}
4386 			/*
4387 			 * Use this to detect duplicates rather
4388 			 * than 0 like other cases, because 0 for
4389 			 * address means INADDR_ANY.
4390 			 */
4391 			daddr = B_TRUE;
4392 			cptr->has_daddr = 1;
4393 			/*
4394 			 * Advance to the string containing
4395 			 * the address.
4396 			 */
4397 			i++, line_no++;
4398 			if (act_props->pattern[i] == NULL) {
4399 				error_message(BAD_ERROR,
4400 				    IPSEC_CONF_DST_ADDRESS, line_no);
4401 				return (-1);
4402 			}
4403 			if (parse_address(IPSEC_CONF_DST_ADDRESS,
4404 			    act_props->pattern[i]) != 0) {
4405 				error_message(BAD_ERROR,
4406 				    IPSEC_CONF_DST_ADDRESS, line_no);
4407 				return (-1);
4408 			}
4409 			if (!cptr->has_dmask)
4410 				cptr->has_dmask = has_daprefix;
4411 			break;
4412 
4413 		case TOK_sport:
4414 			if (new_style) {
4415 				error_message(BAD_ERROR,
4416 				    IPSEC_CONF_SRC_PORT, line_no);
4417 				return (-1);
4418 			}
4419 			old_style = B_TRUE;
4420 
4421 			if (cptr->ips_src_port_min != 0) {
4422 				error_message(DUP_ERROR, IPSEC_CONF_SRC_PORT,
4423 				    line_no);
4424 				return (-1);
4425 			}
4426 			i++, line_no++;
4427 			if (act_props->pattern[i] == NULL) {
4428 				error_message(BAD_ERROR, IPSEC_CONF_SRC_PORT,
4429 				    line_no);
4430 				return (-1);
4431 			}
4432 			ret = parse_port(IPSEC_CONF_SRC_PORT,
4433 			    act_props->pattern[i], cptr);
4434 			if (ret != 0) {
4435 				error_message(BAD_ERROR, IPSEC_CONF_SRC_PORT,
4436 				    line_no);
4437 				return (-1);
4438 			}
4439 			break;
4440 		case TOK_dport:
4441 			if (new_style) {
4442 				error_message(BAD_ERROR,
4443 				    IPSEC_CONF_DST_PORT, line_no);
4444 				return (-1);
4445 			}
4446 			old_style = B_TRUE;
4447 
4448 			if (cptr->ips_dst_port_min != 0) {
4449 				error_message(DUP_ERROR, IPSEC_CONF_DST_PORT,
4450 				    line_no);
4451 				return (-1);
4452 			}
4453 			i++, line_no++;
4454 			if (act_props->pattern[i] == NULL) {
4455 				error_message(BAD_ERROR, IPSEC_CONF_DST_PORT,
4456 				    line_no);
4457 				return (-1);
4458 			}
4459 			ret = parse_port(IPSEC_CONF_DST_PORT,
4460 			    act_props->pattern[i],
4461 			    cptr);
4462 			if (ret != 0) {
4463 				error_message(BAD_ERROR, IPSEC_CONF_DST_PORT,
4464 				    line_no);
4465 				return (-1);
4466 			}
4467 			break;
4468 
4469 		case TOK_lport:
4470 			if (old_style) {
4471 				error_message(BAD_ERROR,
4472 				    IPSEC_CONF_SRC_PORT, line_no);
4473 				return (-1);
4474 			}
4475 			new_style = B_TRUE;
4476 
4477 			if (cptr->ips_src_port_min != 0) {
4478 				error_message(DUP_ERROR, IPSEC_CONF_SRC_PORT,
4479 				    line_no);
4480 				return (-1);
4481 			}
4482 			i++, line_no++;
4483 			if (act_props->pattern[i] == NULL) {
4484 				error_message(BAD_ERROR, IPSEC_CONF_SRC_PORT,
4485 				    line_no);
4486 				return (-1);
4487 			}
4488 			ret = parse_port(IPSEC_CONF_SRC_PORT,
4489 			    act_props->pattern[i],
4490 			    cptr);
4491 			if (ret != 0) {
4492 				error_message(BAD_ERROR, IPSEC_CONF_SRC_PORT,
4493 				    line_no);
4494 				return (-1);
4495 			}
4496 			break;
4497 
4498 		case TOK_rport:
4499 			if (old_style) {
4500 				error_message(BAD_ERROR,
4501 				    IPSEC_CONF_DST_PORT, line_no);
4502 				return (-1);
4503 			}
4504 			new_style = B_TRUE;
4505 
4506 			if (cptr->ips_dst_port_min != 0) {
4507 				error_message(DUP_ERROR, IPSEC_CONF_DST_PORT,
4508 				    line_no);
4509 				return (-1);
4510 			}
4511 			i++, line_no++;
4512 			if (act_props->pattern[i] == NULL) {
4513 				error_message(BAD_ERROR, IPSEC_CONF_DST_PORT,
4514 				    line_no);
4515 				return (-1);
4516 			}
4517 			ret = parse_port(IPSEC_CONF_DST_PORT,
4518 			    act_props->pattern[i],
4519 			    cptr);
4520 			if (ret != 0) {
4521 				error_message(BAD_ERROR, IPSEC_CONF_DST_PORT,
4522 				    line_no);
4523 				return (-1);
4524 			}
4525 			break;
4526 
4527 		case TOK_smask:
4528 			if (new_style) {
4529 				error_message(BAD_ERROR,
4530 				    IPSEC_CONF_SRC_MASK, line_no);
4531 				return (-1);
4532 			}
4533 			old_style = B_TRUE;
4534 			cptr->has_smask = B_TRUE;
4535 
4536 			IN6_V4MAPPED_TO_INADDR(&cptr->ips_src_mask_v6, &mask);
4537 			if (mask.s_addr != 0) {
4538 				error_message(DUP_ERROR, IPSEC_CONF_SRC_MASK,
4539 				    line_no);
4540 				return (-1);
4541 			}
4542 			i++, line_no++;
4543 			if (act_props->pattern[i] == NULL) {
4544 				error_message(BAD_ERROR, IPSEC_CONF_SRC_MASK,
4545 				    line_no);
4546 				return (-1);
4547 			}
4548 			ret = parse_mask(IPSEC_CONF_SRC_MASK,
4549 			    act_props->pattern[i],
4550 			    cptr);
4551 			if (ret != 0) {
4552 				error_message(BAD_ERROR, IPSEC_CONF_SRC_MASK,
4553 				    line_no);
4554 				return (-1);
4555 			}
4556 			break;
4557 		case TOK_dmask:
4558 			if (new_style) {
4559 				error_message(BAD_ERROR,
4560 				    IPSEC_CONF_DST_MASK, line_no);
4561 				return (-1);
4562 			}
4563 			old_style = B_TRUE;
4564 			cptr->has_dmask = B_TRUE;
4565 
4566 			IN6_V4MAPPED_TO_INADDR(&cptr->ips_dst_mask_v6, &mask);
4567 			if (mask.s_addr != 0) {
4568 				error_message(DUP_ERROR, IPSEC_CONF_DST_MASK,
4569 				    line_no);
4570 				return (-1);
4571 			}
4572 			i++, line_no++;
4573 			if (act_props->pattern[i] == NULL) {
4574 				error_message(BAD_ERROR, IPSEC_CONF_DST_MASK,
4575 				    line_no);
4576 				return (-1);
4577 			}
4578 			ret = parse_mask(IPSEC_CONF_DST_MASK,
4579 			    act_props->pattern[i],
4580 			    cptr);
4581 			if (ret != 0) {
4582 				error_message(BAD_ERROR, IPSEC_CONF_DST_MASK,
4583 				    line_no);
4584 				return (-1);
4585 			}
4586 			break;
4587 		case TOK_ulp:
4588 			if (cptr->ips_ulp_prot != 0) {
4589 				error_message(DUP_ERROR,
4590 				    IPSEC_CONF_ULP, line_no);
4591 				return (-1);
4592 			}
4593 			i++, line_no++;
4594 			if (act_props->pattern[i] == NULL) {
4595 				error_message(BAD_ERROR,
4596 				    IPSEC_CONF_ULP, line_no);
4597 				return (-1);
4598 			}
4599 			pent = getprotobyname(act_props->pattern[i]);
4600 			if (pent == NULL) {
4601 				int ulp;
4602 				ulp = parse_int(act_props->pattern[i]);
4603 				if (ulp == -1) {
4604 					error_message(BAD_ERROR,
4605 					    IPSEC_CONF_ULP, line_no);
4606 					return (-1);
4607 				}
4608 				cptr->ips_ulp_prot = ulp;
4609 			} else {
4610 				cptr->ips_ulp_prot = pent->p_proto;
4611 			}
4612 			break;
4613 		case TOK_type:
4614 			if (cptr->has_type) {
4615 				error_message(DUP_ERROR,
4616 				    IPSEC_CONF_ICMP_TYPE, line_no);
4617 				return (-1);
4618 			}
4619 
4620 			i++, line_no++;
4621 			type = parse_type_code(act_props->pattern[i],
4622 			    icmp_type_table);
4623 
4624 			if (type > 65536 || type < 0) {
4625 				error_message(BAD_ERROR,
4626 				    IPSEC_CONF_ICMP_TYPE, line_no);
4627 				return (-1);
4628 			}
4629 
4630 			type_end = type / 256;
4631 			type = type % 256;
4632 
4633 			if (type_end < type)
4634 				type_end = type;
4635 
4636 			cptr->has_type = 1;
4637 			cptr->ips_icmp_type = (uint8_t)type;
4638 			cptr->ips_icmp_type_end = (uint8_t)type_end;
4639 			break;
4640 		case TOK_code:
4641 			if (!cptr->has_type) {
4642 				error_message(BAD_ERROR,
4643 				    IPSEC_CONF_ICMP_CODE, line_no);
4644 				return (-1);
4645 			}
4646 
4647 			if (cptr->has_code) {
4648 				error_message(DUP_ERROR,
4649 				    IPSEC_CONF_ICMP_CODE, line_no);
4650 				return (-1);
4651 			}
4652 
4653 			i++, line_no++;
4654 
4655 			code = parse_type_code(act_props->pattern[i],
4656 			    icmp_code_table);
4657 			if (type > 65536 || type < 0) {
4658 				error_message(BAD_ERROR,
4659 				    IPSEC_CONF_ICMP_CODE, line_no);
4660 				return (-1);
4661 			}
4662 			code_end = code / 256;
4663 			code = code % 256;
4664 
4665 			if (code_end < code)
4666 				code_end = code;
4667 
4668 			cptr->has_code = 1;
4669 			cptr->ips_icmp_code = (uint8_t)code;
4670 			cptr->ips_icmp_code_end = (uint8_t)code_end;
4671 			break;
4672 		case TOK_tunnel:
4673 			if (cptr->has_tunnel == 1) {
4674 				error_message(BAD_ERROR,
4675 				    IPSEC_CONF_TUNNEL, line_no);
4676 				return (-1);
4677 			}
4678 			i++, line_no++;
4679 			if (act_props->pattern[i] == NULL) {
4680 				error_message(BAD_ERROR,
4681 				    IPSEC_CONF_TUNNEL, line_no);
4682 				return (-1);
4683 			}
4684 
4685 			if (strlcpy(tunif, act_props->pattern[i],
4686 			    TUNNAMEMAXLEN) >= TUNNAMEMAXLEN) {
4687 				error_message(BAD_ERROR,
4688 				    IPSEC_CONF_TUNNEL, line_no);
4689 				return (-1);
4690 			}
4691 			cptr->has_tunnel = 1;
4692 			break;
4693 		case TOK_negotiate:
4694 			if (cptr->has_negotiate == 1) {
4695 				error_message(BAD_ERROR,
4696 				    IPSEC_CONF_NEGOTIATE, line_no);
4697 				return (-1);
4698 			}
4699 			i++, line_no++;
4700 			if (act_props->pattern[i] == NULL) {
4701 				error_message(BAD_ERROR,
4702 				    IPSEC_CONF_NEGOTIATE, line_no);
4703 				return (-1);
4704 			}
4705 
4706 			if (strncmp(act_props->pattern[i], "tunnel", 6) == 0) {
4707 				cptr->ips_tunnel = B_TRUE;
4708 			} else if (strncmp(
4709 			    act_props->pattern[i], "transport", 9) != 0) {
4710 				error_message(BAD_ERROR,
4711 				    IPSEC_CONF_NEGOTIATE, line_no);
4712 				return (-1);
4713 			}
4714 			cptr->has_negotiate = 1;
4715 			break;
4716 		}
4717 
4718 	}
4719 
4720 	/* Sanity check that certain tokens occur together */
4721 	if (cptr->has_tunnel + cptr->has_negotiate == 1) {
4722 		if (cptr->has_negotiate == 0) {
4723 			error_message(REQ_ERROR, IPSEC_CONF_NEGOTIATE, line_no);
4724 		} else {
4725 			error_message(REQ_ERROR, IPSEC_CONF_TUNNEL, line_no);
4726 		}
4727 		errx(1, gettext(
4728 		    "tunnel and negotiate tokens must occur together"));
4729 		return (-1);
4730 	}
4731 
4732 	/*
4733 	 * Get the actions.
4734 	 */
4735 
4736 	for (ap_num = 0; act_props->ap[ap_num].act != NULL; ap_num++) {
4737 		ips_act_props_t *iap;
4738 
4739 		if (ap_num > 0) {
4740 			/* or's only with new style */
4741 			if (old_style) {
4742 				(void) printf("%s\n", gettext(
4743 				    "or's only with new style"));
4744 				return (-1);
4745 			}
4746 			new_style = B_TRUE;
4747 		}
4748 
4749 		ipsec_aalg = ipsec_ealg = ipsec_eaalg = auth_covered = B_FALSE;
4750 		tok_count = 0;
4751 
4752 		for (k = 0; action_table[k].string; k++) {
4753 			if (strcmp(act_props->ap[ap_num].act,
4754 			    action_table[k].string) == 0)
4755 				break;
4756 		}
4757 		/*
4758 		 * The following thing should never happen as
4759 		 * we have already tested for its validity in parse.
4760 		 */
4761 		if (action_table[k].string == NULL) {
4762 			warnx(gettext("(form act)Invalid action on line "
4763 			    "%d: %s"), (arg_indices[line_no] == 0) ? 1 :
4764 			    arg_indices[line_no],
4765 			    act_props->ap[ap_num].act);
4766 			warnx("%s", act_props->ap[ap_num].act);
4767 			return (-1);
4768 		}
4769 
4770 		/* we have a good action alloc an iap */
4771 		iap = alloc_iap(cptr);
4772 
4773 		iap->iap_action = action_table[k].value;
4774 		iap->iap_act_tok = action_table[k].tok_val;
4775 
4776 		switch (action_table[k].tok_val) {
4777 		case TOK_apply:
4778 			cptr->ips_dir = SPD_RULE_FLAG_OUTBOUND;
4779 			break;
4780 		case TOK_permit:
4781 			cptr->ips_dir = SPD_RULE_FLAG_INBOUND;
4782 			break;
4783 		case TOK_ipsec:
4784 			if (old_style) {
4785 				/* Using saddr/daddr with ipsec action. */
4786 				if (!dir) {
4787 					/* No direction specified */
4788 					error_message(REQ_ERROR,
4789 					    IPSEC_CONF_IPSEC_DIR, line_no);
4790 					return (-1);
4791 				}
4792 				if (cptr->ips_dir == SPD_RULE_FLAG_INBOUND)
4793 					/*
4794 					 * Need to swap addresses if
4795 					 * 'dir in' or translation to
4796 					 * laddr/raddr will be incorrect.
4797 					 */
4798 					cptr->swap = 1;
4799 			}
4800 			if (!dir)
4801 				cptr->ips_dir =
4802 				    SPD_RULE_FLAG_INBOUND
4803 				    |SPD_RULE_FLAG_OUTBOUND;
4804 			break;
4805 		case TOK_bypass:
4806 		case TOK_drop:
4807 			is_no_alg = B_TRUE;
4808 			break;
4809 		}
4810 
4811 		line_no++;
4812 		/*
4813 		 * Get the properties. NULL properties is not valid.
4814 		 * Later checks will catch it.
4815 		 */
4816 		for (i = 0; act_props->ap[ap_num].prop[i]; i++, line_no++) {
4817 			for (j = 0; property_table[j].string; j++) {
4818 				if (strcmp(act_props->ap[ap_num].prop[i],
4819 				    property_table[j].string) == 0) {
4820 					break;
4821 				}
4822 			}
4823 			if (property_table[j].string == NULL) {
4824 				warnx(gettext("Invalid properties on line "
4825 				    "%d: %s"),
4826 				    (arg_indices[line_no] == 0) ?
4827 				    1 : arg_indices[line_no],
4828 				    act_props->ap[ap_num].prop[i]);
4829 				return (-1);
4830 			}
4831 
4832 			iap->iap_attr_tok[tok_count++]
4833 			    = property_table[j].value;
4834 
4835 			switch (property_table[j].value) {
4836 			case SPD_ATTR_AH_AUTH:
4837 				if (ipsec_aalg) {
4838 					error_message(DUP_ERROR,
4839 					    IPSEC_CONF_IPSEC_AALGS, line_no);
4840 					return (-1);
4841 				}
4842 				i++, line_no++;
4843 				if (act_props->ap[ap_num].prop[i] == NULL) {
4844 					error_message(BAD_ERROR,
4845 					    IPSEC_CONF_IPSEC_AALGS, line_no);
4846 					return (-1);
4847 				}
4848 				ret = parse_ipsec_alg(
4849 				    act_props->ap[ap_num].prop[i],
4850 				    iap, SPD_ATTR_AH_AUTH);
4851 				if (ret == -2) {
4852 					/* "none" - ignore */
4853 					break;
4854 				}
4855 				if (ret != 0) {
4856 					error_message(BAD_ERROR,
4857 					    IPSEC_CONF_IPSEC_AALGS, line_no);
4858 					return (-1);
4859 				}
4860 				ipsec_aalg = B_TRUE;
4861 				auth_covered = B_TRUE;
4862 				break;
4863 			case SPD_ATTR_ESP_ENCR:
4864 				/*
4865 				 * If this option was not given
4866 				 * and encr_auth_algs was given,
4867 				 * we provide null-encryption.  We do the
4868 				 * setting after we parse all the options.
4869 				 */
4870 				if (ipsec_ealg) {
4871 					error_message(DUP_ERROR,
4872 					    IPSEC_CONF_IPSEC_EALGS, line_no);
4873 					return (-1);
4874 				}
4875 				i++, line_no++;
4876 				if (act_props->ap[ap_num].prop[i] == NULL) {
4877 					error_message(BAD_ERROR,
4878 					    IPSEC_CONF_IPSEC_EALGS, line_no);
4879 					return (-1);
4880 				}
4881 				ret = parse_ipsec_alg(
4882 				    act_props->ap[ap_num].prop[i],
4883 				    iap, SPD_ATTR_ESP_ENCR);
4884 				if (ret == -2) {
4885 					/* "none" - ignore */
4886 					break;
4887 				}
4888 				if (ret != 0) {
4889 					error_message(BAD_ERROR,
4890 					    IPSEC_CONF_IPSEC_EALGS, line_no);
4891 					return (-1);
4892 				}
4893 				is_combined_mode = combined_mode(iap);
4894 				ipsec_ealg = B_TRUE;
4895 				break;
4896 			case SPD_ATTR_ESP_AUTH:
4897 				/*
4898 				 * If this option was not given and encr_algs
4899 				 * option was given, we still pass a default
4900 				 * value in ipsc_esp_auth_algs. This is to
4901 				 * encourage the use of authentication with
4902 				 * ESP.
4903 				 */
4904 				if (ipsec_eaalg) {
4905 					error_message(DUP_ERROR,
4906 					    IPSEC_CONF_IPSEC_EAALGS, line_no);
4907 					return (-1);
4908 				}
4909 				i++, line_no++;
4910 				if (act_props->ap[ap_num].prop[i] == NULL) {
4911 					error_message(BAD_ERROR,
4912 					    IPSEC_CONF_IPSEC_EAALGS, line_no);
4913 					return (-1);
4914 				}
4915 				ret = parse_ipsec_alg(
4916 				    act_props->ap[ap_num].prop[i],
4917 				    iap, SPD_ATTR_ESP_AUTH);
4918 				if (ret == -2) {
4919 					/* "none" - ignore */
4920 					break;
4921 				}
4922 				if (ret != 0) {
4923 					error_message(BAD_ERROR,
4924 					    IPSEC_CONF_IPSEC_EAALGS, line_no);
4925 					return (-1);
4926 				}
4927 				ipsec_eaalg = B_TRUE;
4928 				auth_covered = B_TRUE;
4929 				break;
4930 			case IPS_SA:
4931 				i++, line_no++;
4932 				if (act_props->ap[ap_num].prop[i] == NULL) {
4933 					error_message(BAD_ERROR,
4934 					    IPSEC_CONF_IPSEC_SA, line_no);
4935 					return (-1);
4936 				}
4937 
4938 				if (strcmp(act_props->ap[ap_num].prop[i],
4939 				    "unique") == 0) {
4940 					iap->iap_attr |= SPD_APPLY_UNIQUE;
4941 				} else if (strcmp(act_props->ap[ap_num].prop[i],
4942 				    "shared") != 0) {
4943 					/* "shared" is default. */
4944 					error_message(BAD_ERROR,
4945 					    IPSEC_CONF_IPSEC_SA, line_no);
4946 					return (-1);
4947 				}
4948 
4949 				break;
4950 			case IPS_DIR:
4951 				if (dir) {
4952 					error_message(DUP_ERROR,
4953 					    IPSEC_CONF_IPSEC_DIR, line_no);
4954 					return (-1);
4955 				}
4956 				if (new_style) {
4957 					error_message(BAD_ERROR,
4958 					    IPSEC_CONF_IPSEC_DIR, line_no);
4959 					return (-1);
4960 				}
4961 				old_style = B_TRUE;
4962 				dir = B_TRUE;
4963 				i++, line_no++;
4964 				if (act_props->ap[ap_num].prop[i] == NULL) {
4965 					error_message(BAD_ERROR,
4966 					    IPSEC_CONF_IPSEC_DIR, line_no);
4967 					return (-1);
4968 				}
4969 				if (strcmp(act_props->ap[ap_num].prop[i],
4970 				    "out") == 0) {
4971 					cptr->ips_dir = SPD_RULE_FLAG_OUTBOUND;
4972 				} else if (strcmp(act_props->ap[ap_num].prop[i],
4973 				    "in") == 0) {
4974 					cptr->ips_dir = SPD_RULE_FLAG_INBOUND;
4975 				} else {
4976 					error_message(BAD_ERROR,
4977 					    IPSEC_CONF_IPSEC_DIR, line_no);
4978 					return (-1);
4979 				}
4980 				if ((cptr->ips_dir & SPD_RULE_FLAG_INBOUND) &&
4981 				    iap->iap_act_tok == TOK_apply) {
4982 					warnx(gettext("Direction"
4983 					    " in conflict with action"));
4984 					return (-1);
4985 				}
4986 				if ((cptr->ips_dir & SPD_RULE_FLAG_OUTBOUND) &&
4987 				    iap->iap_act_tok == TOK_permit) {
4988 					warnx(gettext("Direction"
4989 					    "in conflict with action"));
4990 					return (-1);
4991 				}
4992 
4993 				break;
4994 			}
4995 		}
4996 
4997 		if (is_combined_mode) {
4998 			if (ipsec_eaalg) {
4999 				warnx(gettext("ERROR: Rule on line %d: "
5000 				    "Combined mode and esp authentication not "
5001 				    "supported together."),
5002 				    arg_indices[line_no] == 0 ? 1 :
5003 				    arg_indices[line_no]);
5004 				return (-1);
5005 			}
5006 			auth_covered = B_TRUE;
5007 		}
5008 		/* Warn here about no authentication! */
5009 		if (!auth_covered && !is_no_alg) {
5010 			warnx(gettext("DANGER:  Rule on line %d "
5011 			    "has encryption with no authentication."),
5012 			    arg_indices[line_no] == 0 ? 1 :
5013 			    arg_indices[line_no]);
5014 		}
5015 
5016 		if (!ipsec_ealg && ipsec_eaalg) {
5017 			/*
5018 			 * If the user has specified the auth alg to be used
5019 			 * with encryption and did not provide a encryption
5020 			 * algorithm, provide null encryption.
5021 			 */
5022 			iap->iap_eencr.alg_id = SADB_EALG_NULL;
5023 			ipsec_ealg = B_TRUE;
5024 		}
5025 
5026 		/* Set the level of IPSEC protection we want */
5027 		if (ipsec_aalg && (ipsec_ealg || ipsec_eaalg)) {
5028 			iap->iap_attr |= SPD_APPLY_AH|SPD_APPLY_ESP;
5029 		} else if (ipsec_aalg) {
5030 			iap->iap_attr |= SPD_APPLY_AH;
5031 		} else if (ipsec_ealg || ipsec_eaalg) {
5032 			iap->iap_attr |= SPD_APPLY_ESP;
5033 		}
5034 
5035 		/* convert src/dst to local/remote */
5036 		if (!new_style) {
5037 			switch (cptr->ips_acts->iap_act_tok) {
5038 			case TOK_apply:
5039 				/* outbound */
5040 				/* src=local, dst=remote */
5041 				/* this is ok. */
5042 				break;
5043 
5044 			case TOK_permit:
5045 				/* inbound */
5046 				/* src=remote, dst=local */
5047 				/* switch */
5048 				cptr->swap = 1;
5049 				break;
5050 			case TOK_bypass:
5051 			case TOK_drop:
5052 				/* check the direction for what to do */
5053 				if (cptr->ips_dir == SPD_RULE_FLAG_INBOUND)
5054 					cptr->swap = 1;
5055 				break;
5056 			default:
5057 				break;
5058 			}
5059 		}
5060 		/* Validate the properties */
5061 		if (ret = validate_properties(iap, dir,
5062 		    (ipsec_aalg || ipsec_ealg || ipsec_eaalg))) {
5063 			return (ret);
5064 		}
5065 	}
5066 
5067 	return (0);
5068 
5069 }
5070 
5071 static int
5072 print_cmd_buf(FILE *fp, int error)
5073 {
5074 	*(cbuf + cbuf_offset) = '\0';
5075 
5076 	if (fp == stderr) {
5077 		if (error != EEXIST) {
5078 			warnx(gettext("Malformed command (fatal):\n%s"), cbuf);
5079 			return (0);
5080 		}
5081 		if (ipsecconf_qflag) {
5082 			return (0);
5083 		}
5084 		warnx(gettext("Duplicate policy entry (ignored):\n%s"), cbuf);
5085 	} else {
5086 		if (fprintf(fp, "%s", cbuf) == -1) {
5087 			warn("fprintf");
5088 			return (-1);
5089 		}
5090 	}
5091 
5092 	return (0);
5093 }
5094 
5095 #ifdef	DEBUG
5096 
5097 static uchar_t *
5098 addr_ptr(int isv4, struct in6_addr *addr6, struct in_addr *addr4)
5099 {
5100 	if (isv4) {
5101 		IN6_V4MAPPED_TO_INADDR(addr6, addr4);
5102 		return ((uchar_t *)&addr4->s_addr);
5103 	} else {
5104 		return ((uchar_t *)&addr6->s6_addr);
5105 	}
5106 }
5107 
5108 static void
5109 dump_algreq(const char *tag, algreq_t *alg)
5110 {
5111 	(void) printf("%s algid %d, bits %d..%d\n",
5112 	    tag, alg->alg_id, alg->alg_minbits, alg->alg_maxbits);
5113 }
5114 
5115 static void
5116 dump_conf(ips_conf_t *conf)
5117 {
5118 	boolean_t isv4 = conf->ips_isv4;
5119 	struct in_addr addr;
5120 	char buf[INET6_ADDRSTRLEN];
5121 	int af;
5122 	ips_act_props_t *iap = conf->ips_acts;
5123 
5124 	af = isv4 ? AF_INET : AF_INET6;
5125 
5126 	(void) printf("Source Addr is %s\n",
5127 	    inet_ntop(af, addr_ptr(isv4, &conf->ips_src_addr_v6, &addr),
5128 	    buf, INET6_ADDRSTRLEN));
5129 
5130 	(void) printf("Dest Addr is %s\n",
5131 	    inet_ntop(af, addr_ptr(isv4, &conf->ips_dst_addr_v6, &addr),
5132 	    buf, INET6_ADDRSTRLEN));
5133 
5134 	(void) printf("Source Mask is %s\n",
5135 	    inet_ntop(af, addr_ptr(isv4, &conf->ips_src_mask_v6, &addr),
5136 	    buf, INET6_ADDRSTRLEN));
5137 
5138 	(void) printf("Dest Mask is %s\n",
5139 	    inet_ntop(af, addr_ptr(isv4, &conf->ips_dst_mask_v6, &addr),
5140 	    buf, INET6_ADDRSTRLEN));
5141 
5142 	(void) printf("Source port %d\n", ntohs(conf->ips_src_port_min));
5143 	(void) printf("Dest port %d\n", ntohs(conf->ips_dst_port_min));
5144 	(void) printf("ULP %d\n", conf->ips_ulp_prot);
5145 
5146 	(void) printf("ICMP type %d-%d code %d-%d", conf->ips_icmp_type,
5147 	    conf->ips_icmp_type_end,
5148 	    conf->ips_icmp_code,
5149 	    conf->ips_icmp_code_end);
5150 
5151 	while (iap != NULL) {
5152 		(void) printf("------------------------------------\n");
5153 		(void) printf("IPsec act is %d\n", iap->iap_action);
5154 		(void) printf("IPsec attr is %d\n", iap->iap_attr);
5155 		dump_algreq("AH authentication", &iap->iap_aauth);
5156 		dump_algreq("ESP authentication", &iap->iap_eauth);
5157 		dump_algreq("ESP encryption", &iap->iap_eencr);
5158 		(void) printf("------------------------------------\n");
5159 		iap = iap->iap_next;
5160 	}
5161 
5162 	(void) fflush(stdout);
5163 }
5164 #endif	/* DEBUG */
5165 
5166 
5167 static int
5168 ipsec_conf_add(boolean_t just_check, boolean_t smf_managed)
5169 {
5170 	act_prop_t *act_props = malloc(sizeof (act_prop_t));
5171 	ips_conf_t conf;
5172 	FILE *fp, *policy_fp;
5173 	int ret, flushret, i, j, diag, num_rules, good_rules;
5174 	char *warning = gettext(
5175 	    "\tWARNING : New policy entries that are being added may\n "
5176 	    "\taffect the existing connections. Existing connections\n"
5177 	    "\tthat are not subjected to policy constraints, may be\n"
5178 	    "\tsubjected to policy constraints because of the new\n"
5179 	    "\tpolicy. This can disrupt the communication of the\n"
5180 	    "\texisting connections.\n\n");
5181 
5182 	boolean_t first_time = B_TRUE;
5183 	num_rules = 0;
5184 	good_rules = 0;
5185 
5186 	if (act_props == NULL) {
5187 		warn(gettext("memory"));
5188 		return (-1);
5189 	}
5190 
5191 	if (strcmp(filename, "-") == 0)
5192 		fp = stdin;
5193 	else
5194 		fp = fopen(filename, "r");
5195 
5196 	/*
5197 	 * Treat the non-existence of a policy file as a special
5198 	 * case when ipsecconf is being managed by smf(5).
5199 	 * The assumption is the administrator has not yet
5200 	 * created a policy file, this should not force the service
5201 	 * into maintenance mode.
5202 	 */
5203 
5204 	if (fp == NULL) {
5205 		if (smf_managed) {
5206 			(void) fprintf(stdout, gettext(
5207 			    "Policy configuration file (%s) does not exist.\n"
5208 			    "IPsec policy not configured.\n"), filename);
5209 			return (0);
5210 		}
5211 		warn(gettext("%s : Policy config file cannot be opened"),
5212 		    filename);
5213 		usage();
5214 		return (-1);
5215 	}
5216 	/*
5217 	 * This will create the file if it does not exist.
5218 	 * Make sure the umask is right.
5219 	 */
5220 	(void) umask(0022);
5221 	policy_fp = fopen(POLICY_CONF_FILE, "a");
5222 	if (policy_fp == NULL) {
5223 		warn(gettext("%s cannot be opened"), POLICY_CONF_FILE);
5224 		return (-1);
5225 	}
5226 
5227 	/*
5228 	 * Pattern, action, and properties are allocated in
5229 	 * parse_pattern_or_prop and in parse_action (called by
5230 	 * parse_one) as we parse arguments.
5231 	 */
5232 	while ((ret = parse_one(fp, act_props)) != PARSE_EOF) {
5233 		num_rules++;
5234 		if (ret != 0) {
5235 			(void) print_cmd_buf(stderr, NOERROR);
5236 			continue;
5237 		}
5238 
5239 		/*
5240 		 * If there is no action and parse returned success,
5241 		 * it means that there is nothing to add.
5242 		 */
5243 		if (act_props->pattern[0] == NULL &&
5244 		    act_props->ap[0].act == NULL)
5245 				break;
5246 
5247 		ret = form_ipsec_conf(act_props, &conf);
5248 		if (ret != 0) {
5249 			warnx(gettext("form_ipsec_conf error"));
5250 			(void) print_cmd_buf(stderr, NOERROR);
5251 			/* Reset globals before trying the next rule. */
5252 			if (shp != NULL) {
5253 				freehostent(shp);
5254 				shp = NULL;
5255 			}
5256 			if (dhp != NULL) {
5257 				freehostent(dhp);
5258 				dhp = NULL;
5259 			}
5260 			splen = 0;
5261 			dplen = 0;
5262 			continue;
5263 		}
5264 
5265 		good_rules++;
5266 
5267 		if (first_time) {
5268 			/*
5269 			 * Time to assume that there are valid policy entries.
5270 			 * If the IPsec kernel modules are not loaded this
5271 			 * will load them now.
5272 			 */
5273 			first_time = B_FALSE;
5274 			fetch_algorithms();
5275 			ipsec_conf_admin(SPD_CLONE);
5276 		}
5277 
5278 		/*
5279 		 * shp, dhp, splen, and dplen are globals set by
5280 		 * form_ipsec_conf() while parsing the addresses.
5281 		 */
5282 		if (shp == NULL && dhp == NULL) {
5283 			switch (do_port_adds(&conf)) {
5284 			case 0:
5285 				/* no error */
5286 				break;
5287 			case EEXIST:
5288 				/* duplicate entries, continue adds */
5289 				(void) print_cmd_buf(stderr, EEXIST);
5290 				goto next;
5291 			default:
5292 				/* other error, bail */
5293 				ret = -1;
5294 				goto bail;
5295 			}
5296 		} else {
5297 			ret = do_address_adds(&conf, &diag);
5298 			switch (ret) {
5299 			case 0:
5300 				/* no error. */
5301 				break;
5302 			case EEXIST:
5303 				(void) print_cmd_buf(stderr, EEXIST);
5304 				goto next;
5305 			case EBUSY:
5306 				warnx(gettext(
5307 				    "Can't set mask and /NN prefix."));
5308 				ret = -1;
5309 				break;
5310 			case ENOENT:
5311 				warnx(gettext("Cannot find tunnel "
5312 				    "interface %s."), interface_name);
5313 				ret = -1;
5314 				break;
5315 			case EINVAL:
5316 				/*
5317 				 * PF_POLICY didn't like what we sent.  We
5318 				 * can't check all input up here, but we
5319 				 * do in-kernel.
5320 				 */
5321 				warnx(gettext("PF_POLICY invalid input:\n\t%s"),
5322 				    spdsock_diag(diag));
5323 				break;
5324 			case EOPNOTSUPP:
5325 				warnx(gettext("Can't set /NN"
5326 				    " prefix on multi-host name."));
5327 				ret = -1;
5328 				break;
5329 			case ERANGE:
5330 				warnx(gettext("/NN prefix is too big!"));
5331 				ret = -1;
5332 				break;
5333 			case ESRCH:
5334 				warnx(gettext("No matching IPv4 or "
5335 				    "IPv6 saddr/daddr pairs"));
5336 				ret = -1;
5337 				break;
5338 			default:
5339 				/* Should never get here. */
5340 				errno = ret;
5341 				warn(gettext("Misc. error"));
5342 				ret = -1;
5343 			}
5344 			if (ret == -1)
5345 				goto bail;
5346 		}
5347 
5348 		/*
5349 		 * Go ahead and add policy entries to config file.
5350 		 * The # should help re-using the ipsecpolicy.conf
5351 		 * for input again as # will be treated as comment.
5352 		 */
5353 		if (fprintf(policy_fp, "%s %lld \n", INDEX_TAG,
5354 		    conf.ips_policy_index) == -1) {
5355 			warn("fprintf");
5356 			warnx(gettext("Addition incomplete, Please "
5357 			    "flush all the entries and re-configure :"));
5358 			reconfigure();
5359 			ret = -1;
5360 			break;
5361 		}
5362 		if (print_cmd_buf(policy_fp, NOERROR) == -1) {
5363 			warnx(gettext("Addition incomplete. Please "
5364 			    "flush all the entries and re-configure :"));
5365 			reconfigure();
5366 			ret = -1;
5367 			break;
5368 		}
5369 		/*
5370 		 * We add one newline by default to separate out the
5371 		 * entries. If the last character is not a newline, we
5372 		 * insert a newline for free. This makes sure that all
5373 		 * entries look consistent in the file.
5374 		 */
5375 		if (*(cbuf + cbuf_offset - 1) == '\n') {
5376 			if (fprintf(policy_fp, "\n") == -1) {
5377 				warn("fprintf");
5378 				warnx(gettext("Addition incomplete. "
5379 				    "Please flush all the entries and "
5380 				    "re-configure :"));
5381 				reconfigure();
5382 				ret = -1;
5383 				break;
5384 			}
5385 		} else {
5386 			if (fprintf(policy_fp, "\n\n") == -1) {
5387 				warn("fprintf");
5388 				warnx(gettext("Addition incomplete. "
5389 				    "Please flush all the entries and "
5390 				    "re-configure :"));
5391 				reconfigure();
5392 				ret = -1;
5393 				break;
5394 			}
5395 		}
5396 next:
5397 		/*
5398 		 * Make sure this gets to the disk before
5399 		 * we parse the next entry.
5400 		 */
5401 		(void) fflush(policy_fp);
5402 		for (i = 0; act_props->pattern[i] != NULL; i++)
5403 			free(act_props->pattern[i]);
5404 		for (j = 0; act_props->ap[j].act != NULL; j++) {
5405 			free(act_props->ap[j].act);
5406 			for (i = 0; act_props->ap[j].prop[i] != NULL; i++)
5407 				free(act_props->ap[j].prop[i]);
5408 		}
5409 	}
5410 	if (ret == PARSE_EOF)
5411 		ret = 0; /* Not an error */
5412 bail:
5413 	if (ret == -1) {
5414 		(void) print_cmd_buf(stderr, EINVAL);
5415 		for (i = 0; act_props->pattern[i] != NULL; i++)
5416 			free(act_props->pattern[i]);
5417 		for (j = 0; act_props->ap[j].act != NULL; j++) {
5418 			free(act_props->ap[j].act);
5419 			for (i = 0; act_props->ap[j].prop[i] != NULL; i++)
5420 				free(act_props->ap[j].prop[i]);
5421 		}
5422 	}
5423 #ifdef DEBUG_HEAVY
5424 	(void) printf("ipsec_conf_add: ret val = %d\n", ret);
5425 	(void) fflush(stdout);
5426 #endif
5427 	if (num_rules == 0 && ret == 0) {
5428 		nuke_adds();
5429 		(void) restore_all_signals();
5430 		(void) unlock(lfd);
5431 		EXIT_OK("Policy file does not contain any valid rules.");
5432 	}
5433 	if (num_rules != good_rules) {
5434 		/* This is an error */
5435 		nuke_adds();
5436 		(void) restore_all_signals();
5437 		(void) unlock(lfd);
5438 		EXIT_BADCONFIG2("%d policy rule(s) contained errors.",
5439 		    num_rules - good_rules);
5440 	}
5441 	/* looks good, flip it in */
5442 	if (ret == 0 && !just_check) {
5443 		if (!ipsecconf_qflag) {
5444 			(void) printf("%s", warning);
5445 		}
5446 		if (smf_managed)
5447 			warnx(gettext("%d policy rules added."), good_rules);
5448 		ipsec_conf_admin(SPD_FLIP);
5449 	} else {
5450 		nuke_adds();
5451 		if (just_check) {
5452 			(void) fprintf(stdout, gettext("IPsec configuration "
5453 			    "does not contain any errors.\n"));
5454 			(void) fprintf(stdout, gettext(
5455 			    "IPsec policy was not modified.\n"));
5456 			(void) fflush(stdout);
5457 		}
5458 	}
5459 	flushret = ipsec_conf_flush(SPD_STANDBY);
5460 	if (flushret != 0)
5461 		return (flushret);
5462 	return (ret);
5463 }
5464 
5465 
5466 static int
5467 ipsec_conf_sub()
5468 {
5469 	act_prop_t *act_props = malloc(sizeof (act_prop_t));
5470 	FILE *remove_fp, *policy_fp;
5471 	char rbuf[MAXLEN], pbuf[MAXLEN], /* remove buffer, and policy buffer */
5472 	    *warning = gettext(
5473 	    "\tWARNING: Policy entries that are being removed may\n"
5474 	    "\taffect the existing connections.  Existing connections\n"
5475 	    "\tthat are subjected to policy constraints may no longer\n"
5476 	    "\tbe subjected to policy contraints because of its\n"
5477 	    "\tremoval.  This can compromise security, and disrupt\n"
5478 	    "\tthe communication of the existing connection.\n"
5479 	    "\tConnections that are latched will remain unaffected\n"
5480 	    "\tuntil they close.\n");
5481 	int ret = 0;
5482 	int index_len, pindex = 0; /* init value in case of pfile error */
5483 
5484 	if (act_props == NULL) {
5485 		warn(gettext("memory"));
5486 		return (-1);
5487 	}
5488 
5489 	/* clone into standby DB */
5490 	(void) ipsec_conf_admin(SPD_CLONE);
5491 
5492 	if (strcmp(filename, "-") == 0)
5493 		remove_fp = stdin;
5494 	else
5495 		remove_fp = fopen(filename, "r");
5496 
5497 	if (remove_fp == NULL) {
5498 		warn(gettext("%s : Input file cannot be opened"), filename);
5499 		usage();
5500 		free(act_props);
5501 		return (-1);
5502 	}
5503 
5504 	/* open policy file so we can locate the correct policy */
5505 	(void) umask(0022);  /* in case it gets created! */
5506 	policy_fp = fopen(POLICY_CONF_FILE, "r+");
5507 	if (policy_fp == NULL) {
5508 		warn(gettext("%s cannot be opened"), POLICY_CONF_FILE);
5509 		(void) fclose(remove_fp);
5510 		free(act_props);
5511 		return (-1);
5512 	}
5513 
5514 	/* don't print the warning if we're in q[uiet] mode */
5515 	if (!ipsecconf_qflag)
5516 		(void) printf("%s", warning);
5517 
5518 	/* this bit is done primarily so we can read what we write */
5519 	index_len = strlen(INDEX_TAG);
5520 
5521 	/*
5522 	 * We want to look for the policy in rbuf in the policy file.
5523 	 * Go through the list of policies to remove, locating each one.
5524 	 */
5525 	while (fgets(rbuf, MAXLEN, remove_fp) != NULL) {
5526 		char *buf;
5527 		int offset, prev_offset, prev_prev_offset, nlines;
5528 		fpos_t ipos;
5529 		int pbuf_len = 0;
5530 		char *tmp;
5531 		/* skip blanks here (so we don't need to do it below)! */
5532 		for (tmp = rbuf; (*tmp != '\0') && isspace(*tmp); )
5533 			tmp++;
5534 
5535 		if (*tmp == '\0')
5536 			continue; /* while(); */
5537 
5538 		/* skip the INDEX_TAG lines in the remove buffer */
5539 		if (strncasecmp(rbuf, INDEX_TAG, index_len) == 0)
5540 			continue;
5541 
5542 		/* skip commented lines */
5543 		if (*tmp == '#')
5544 			continue; /* while(); */
5545 
5546 		/*
5547 		 * We start by presuming only good policies are in the pfile,
5548 		 * and so only good policies from the rfile will match them.
5549 		 * ipsec_conf_del ensures this later by calling parse_one() on
5550 		 * pfile before it deletes the entry.
5551 		 */
5552 		for (offset = prev_offset = prev_prev_offset = 0;
5553 		    fgets(pbuf, MAXLEN, policy_fp) != NULL;
5554 		    offset += pbuf_len) {
5555 			prev_offset = offset;
5556 			pbuf_len = strlen(pbuf);
5557 
5558 			/* skip blank lines which seperate policy entries */
5559 			if (pbuf[0] == '\n')
5560 				continue;
5561 
5562 			/* if we found an index, save it */
5563 			if (strncasecmp(pbuf, INDEX_TAG, index_len) == 0) {
5564 				buf = pbuf + index_len;
5565 				buf++;
5566 				if ((pindex = parse_index(buf, NULL)) == -1) {
5567 					/* bad index, we can't continue */
5568 					warnx(gettext(
5569 					    "Invalid index in the file"));
5570 					(void) fclose(remove_fp);
5571 					(void) fclose(policy_fp);
5572 					free(act_props);
5573 					return (-1);
5574 				}
5575 
5576 				/* save this position in case it's the one */
5577 				if (fgetpos(policy_fp, &ipos) != 0) {
5578 					(void) fclose(remove_fp);
5579 					(void) fclose(policy_fp);
5580 					free(act_props);
5581 					return (-1);
5582 				}
5583 			}
5584 
5585 			/* Does pbuf contain the remove policy? */
5586 			if (strncasecmp(rbuf, pbuf, pbuf_len) == 0) {
5587 				/* we found the one to remove! */
5588 				if (pindex == 0) {
5589 					warnx(gettext("Didn't find a valid "
5590 					    "index for policy"));
5591 					(void) fclose(remove_fp);
5592 					(void) fclose(policy_fp);
5593 					free(act_props);
5594 					return (-1);
5595 				}
5596 
5597 				/* off it - back up to the last INDEX! */
5598 				if (fsetpos(policy_fp, &ipos) != 0) {
5599 					(void) fclose(remove_fp);
5600 					(void) fclose(policy_fp);
5601 					free(act_props);
5602 					return (-1);
5603 				}
5604 
5605 				/* parse_one sets linecount = #lines to off */
5606 				if (parse_one(policy_fp, act_props) == -1) {
5607 					warnx(gettext("Invalid policy entry "
5608 					    "in the file"));
5609 					(void) fclose(remove_fp);
5610 					(void) fclose(policy_fp);
5611 					free(act_props);
5612 					return (-1);
5613 				}
5614 
5615 				nlines = linecount + 2;
5616 				goto delete;
5617 			}
5618 			/*
5619 			 * When we find a match, we want to pass the offset
5620 			 * of the line that is before it - the INDEX_TAG line.
5621 			 */
5622 			prev_prev_offset = prev_offset;
5623 		}
5624 		/* Didn't find a match - look at the next remove policy */
5625 		continue; /* while(); */
5626 
5627 delete:
5628 		(void) fclose(policy_fp);
5629 
5630 		if (delete_from_file(prev_prev_offset, nlines) != 0) {
5631 			warnx(gettext("delete_from_file failure.  "
5632 			    "Please flush all entries and re-configure :"));
5633 			reconfigure();
5634 			(void) fclose(remove_fp);
5635 			free(act_props);
5636 			return (-1);
5637 		}
5638 
5639 		if (pfp_delete_rule(pindex) != 0) {
5640 			warnx(gettext("Deletion incomplete. Please flush"
5641 			    "all the entries and re-configure :"));
5642 			reconfigure();
5643 			(void) fclose(remove_fp);
5644 			free(act_props);
5645 			return (-1);
5646 		}
5647 
5648 		/* reset the globals */
5649 		linecount = 0;
5650 		pindex = 0;
5651 		/* free(NULL) also works. */
5652 		free(interface_name);
5653 		interface_name = NULL;
5654 
5655 		/* reopen for next pass, automagically starting over. */
5656 		policy_fp = fopen(POLICY_CONF_FILE, "r");
5657 		if (policy_fp == NULL) {
5658 			warn(gettext("%s cannot be re-opened, can't continue"),
5659 			    POLICY_CONF_FILE);
5660 			(void) fclose(remove_fp);
5661 			free(act_props);
5662 			return (-1);
5663 		}
5664 
5665 	} /* read next remove policy */
5666 
5667 	if ((ret = pfp_delete_rule(pindex)) != 0) {
5668 		warnx(gettext("Removal incomplete.  Please flush "
5669 		    "all the entries and re-configure :"));
5670 		reconfigure();
5671 		free(act_props);
5672 		return (ret);
5673 	}
5674 
5675 	/* nothing left to look for */
5676 	(void) fclose(remove_fp);
5677 	free(act_props);
5678 
5679 	return (0);
5680 }
5681 
5682 /*
5683  * Constructs a tunnel interface ID extension.  Returns the length
5684  * of the extension in 64-bit-words.
5685  */
5686 static int
5687 attach_tunname(spd_if_t *tunname)
5688 {
5689 	if (tunname == NULL || interface_name == NULL)
5690 		return (0);
5691 
5692 	tunname->spd_if_exttype = SPD_EXT_TUN_NAME;
5693 	/*
5694 	 * Use "-3" because there's 4 bytes in the message itself, and
5695 	 * we lose one because of the '\0' terminator.
5696 	 */
5697 	tunname->spd_if_len = SPD_8TO64(
5698 	    P2ROUNDUP(sizeof (*tunname) + strlen(interface_name) - 3, 8));
5699 	(void) strlcpy((char *)tunname->spd_if_name, interface_name, LIFNAMSIZ);
5700 	return (tunname->spd_if_len);
5701 }
5702