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