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