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