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(
1344*bbf21555SRichard Lowe "\n\tIPsec policy should be managed using smf(7). 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) {
2656f02131e0SVladimir 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) {
2671f02131e0SVladimir 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"));
2686f02131e0SVladimir 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;
302995c74518SToomas Soome *ptr++ = '\0';
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)
374395c74518SToomas Soome *cp = '\0';
3744e3320f40Smarkfen
3745e3320f40Smarkfen /* Skip any whitespace */
374695c74518SToomas Soome while (*buf != '\0' && isspace(*buf))
3747e3320f40Smarkfen buf++;
3748e3320f40Smarkfen
3749e3320f40Smarkfen /* Empty line */
375095c74518SToomas Soome if (*buf == '\0')
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 */
377595c74518SToomas Soome while (*buf != '\0' && !isspace(*buf) &&
3776e3320f40Smarkfen *buf != CURL_BEGIN)
3777e3320f40Smarkfen buf++;
3778e3320f40Smarkfen
377995c74518SToomas Soome if (*buf != '\0') {
3780d5751483Smarkfen if (tmp_buf == buf) /* No action token */
3781d5751483Smarkfen goto error;
3782e3320f40Smarkfen if (*buf == CURL_BEGIN) {
378395c74518SToomas Soome *buf = '\0';
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 */
379495c74518SToomas Soome *buf++ = '\0';
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 */
380795c74518SToomas Soome if (*buf != '\0') {
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)
387695c74518SToomas Soome *cp = '\0';
3877e3320f40Smarkfen
3878e3320f40Smarkfen /* Skip any whitespace */
387995c74518SToomas Soome while (*buf != '\0' && isspace(*buf))
3880e3320f40Smarkfen buf++;
3881e3320f40Smarkfen
3882e3320f40Smarkfen /* Empty line */
388395c74518SToomas Soome if (*buf == '\0')
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 */
392395c74518SToomas Soome while (*buf != '\0') {
3924e3320f40Smarkfen if (*buf == CURL_END) {
3925e3320f40Smarkfen ret:
392695c74518SToomas Soome *buf++ = '\0';
3927e3320f40Smarkfen /*
3928e3320f40Smarkfen * Copy the rest of the line into the
3929e3320f40Smarkfen * leftover buffer if any.
3930e3320f40Smarkfen */
393195c74518SToomas Soome if (*buf != '\0') {
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 */
394495c74518SToomas Soome while (*buf != '\0' && isspace(*buf))
3945e3320f40Smarkfen buf++;
3946e3320f40Smarkfen
3947e3320f40Smarkfen if (*buf == CURL_END)
3948e3320f40Smarkfen goto ret;
3949e3320f40Smarkfen
3950e3320f40Smarkfen /* Scan the next line as this buffer is empty */
395195c74518SToomas Soome if (*buf == '\0')
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 */
396895c74518SToomas Soome while (*buf != '\0' && !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 */
397695c74518SToomas Soome if (*buf != '\0') {
3977e3320f40Smarkfen if (*buf == CURL_END) {
397895c74518SToomas Soome *buf++ = '\0';
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 */
399695c74518SToomas Soome if (*buf != '\0') {
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 {
400595c74518SToomas Soome *buf++ = '\0';
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 */
415495c74518SToomas Soome while (*leftover != '\0') {
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
5250*bbf21555SRichard Lowe * case when ipsecconf is being managed by smf(7).
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