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