14235Smarkfen /*
24235Smarkfen * CDDL HEADER START
34235Smarkfen *
44235Smarkfen * The contents of this file are subject to the terms of the
54235Smarkfen * Common Development and Distribution License (the "License").
64235Smarkfen * You may not use this file except in compliance with the License.
74235Smarkfen *
84235Smarkfen * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
94235Smarkfen * or http://www.opensolaris.org/os/licensing.
104235Smarkfen * See the License for the specific language governing permissions
114235Smarkfen * and limitations under the License.
124235Smarkfen *
134235Smarkfen * When distributing Covered Code, include this CDDL HEADER in each
144235Smarkfen * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
154235Smarkfen * If applicable, add the following below this CDDL HEADER, with the
164235Smarkfen * fields enclosed by brackets "[]" replaced with your own identifying
174235Smarkfen * information: Portions Copyright [yyyy] [name of copyright owner]
184235Smarkfen *
194235Smarkfen * CDDL HEADER END
204235Smarkfen */
214235Smarkfen /*
2212131Sdanmcd@opensolaris.org * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
234235Smarkfen */
244235Smarkfen
254235Smarkfen #include <stdio.h>
264235Smarkfen #include <sys/types.h>
274235Smarkfen #include <sys/stat.h>
284235Smarkfen #include <strings.h>
294235Smarkfen #include <stropts.h>
304235Smarkfen #include <fcntl.h>
314235Smarkfen #include <stdlib.h>
324235Smarkfen #include <unistd.h>
334235Smarkfen #include <string.h>
344235Smarkfen #include <ctype.h>
354235Smarkfen #include <arpa/inet.h>
364235Smarkfen #include <locale.h>
374235Smarkfen #include <syslog.h>
384235Smarkfen #include <pwd.h>
394235Smarkfen #include <sys/param.h>
404235Smarkfen #include <sys/sysmacros.h> /* MIN, MAX */
414235Smarkfen #include <sys/sockio.h>
424235Smarkfen #include <net/pfkeyv2.h>
434235Smarkfen #include <net/pfpolicy.h>
444235Smarkfen #include <inet/ipsec_impl.h>
454235Smarkfen #include <signal.h>
464235Smarkfen #include <errno.h>
474235Smarkfen #include <netdb.h>
484235Smarkfen #include <sys/socket.h>
494235Smarkfen #include <sys/systeminfo.h>
504235Smarkfen #include <nss_dbdefs.h> /* NSS_BUFLEN_HOSTS */
514235Smarkfen #include <netinet/in.h>
524235Smarkfen #include <assert.h>
534235Smarkfen #include <inet/ip.h>
544235Smarkfen #include <ipsec_util.h>
554235Smarkfen #include <netinet/in_systm.h>
564235Smarkfen #include <netinet/ip_icmp.h>
574235Smarkfen #include <netinet/icmp6.h>
584235Smarkfen
594235Smarkfen /*
604235Smarkfen * Globals
614235Smarkfen */
624235Smarkfen int lfd;
634235Smarkfen char *my_fmri;
644235Smarkfen FILE *debugfile = stderr;
654235Smarkfen
664235Smarkfen #define USAGE() if (!smf_managed) usage()
674235Smarkfen /*
684235Smarkfen * Buffer length to read in pattern/properties.
694235Smarkfen */
704235Smarkfen #define MAXLEN 1024
714235Smarkfen
724235Smarkfen /* Max length of tunnel interface string identifier */
734235Smarkfen #define TUNNAMEMAXLEN LIFNAMSIZ
744235Smarkfen
754235Smarkfen /*
764235Smarkfen * Used by parse_one and parse/parse_action to communicate
774235Smarkfen * the errors. -1 is failure, which is not defined here.
784235Smarkfen */
794235Smarkfen enum parse_errors {PARSE_SUCCESS, PARSE_EOF};
804235Smarkfen
814235Smarkfen /*
824235Smarkfen * For spdsock_get_ext() diagnostics.
834235Smarkfen */
844235Smarkfen #define SPDSOCK_DIAG_BUF_LEN 128
854235Smarkfen static char spdsock_diag_buf[SPDSOCK_DIAG_BUF_LEN];
864235Smarkfen
874235Smarkfen /*
884235Smarkfen * Define CURL here so that while you are reading
894235Smarkfen * this code, it does not affect "vi" in pattern
904235Smarkfen * matching.
914235Smarkfen */
924235Smarkfen #define CURL_BEGIN '{'
934235Smarkfen #define CURL_END '}'
945120Smarkfen #define BACK_SLASH '\\'
954235Smarkfen #define MAXARGS 20
964235Smarkfen #define NOERROR 0
974235Smarkfen
984235Smarkfen /*
994235Smarkfen * IPSEC_CONF_ADD should start with 1, so that when multiple commands
1004235Smarkfen * are given, we can fail the request.
1014235Smarkfen */
1024235Smarkfen
1034235Smarkfen enum ipsec_cmds {IPSEC_CONF_ADD = 1, IPSEC_CONF_DEL, IPSEC_CONF_VIEW,
10411278SMark.Fenwick@Sun.COM IPSEC_CONF_FLUSH, IPSEC_CONF_LIST, IPSEC_CONF_SUB, IPSEC_CONF_REPLACE};
1054235Smarkfen
1064235Smarkfen static const char policy_conf_file[] = "/var/run/ipsecpolicy.conf";
1074235Smarkfen static const char lock_file[] = "/var/run/ipsecconf.lock";
1084235Smarkfen static const char index_tag[] = "#INDEX";
1094235Smarkfen
1104235Smarkfen #define POLICY_CONF_FILE policy_conf_file
1114235Smarkfen #define LOCK_FILE lock_file
1124235Smarkfen #define INDEX_TAG index_tag
1134235Smarkfen
1144235Smarkfen /*
1154235Smarkfen * Valid algorithm length.
1164235Smarkfen */
1174235Smarkfen #define VALID_ALG_LEN 40
1184235Smarkfen
1194235Smarkfen /* Types of Error messages */
1204235Smarkfen typedef enum error_type {BAD_ERROR, DUP_ERROR, REQ_ERROR} error_type_t;
1214235Smarkfen
1224235Smarkfen /* Error message human readable conversions */
1234235Smarkfen static char *sys_error_message(int);
1244235Smarkfen static void error_message(error_type_t, int, int);
1254235Smarkfen static int get_pf_pol_socket(void);
1264235Smarkfen
1274235Smarkfen static int cmd;
1284235Smarkfen static char *filename;
1294235Smarkfen static char lo_buf[MAXLEN]; /* Leftover buffer */
1304235Smarkfen
1314235Smarkfen /*
1324235Smarkfen * The new SPD_EXT_TUN_NAME extension has a tunnel name in it. Use the empty
1334235Smarkfen * string ("", stored in the char value "all_polheads") for all policy heads
1344235Smarkfen * (global and all tunnels). Set interface_name to NULL for global-only, or
1354235Smarkfen * specify a name of an IP-in-IP tunnel.
1364235Smarkfen */
1374235Smarkfen static char *interface_name;
1384235Smarkfen static char all_polheads; /* So we can easily get "". */
1394235Smarkfen
1404235Smarkfen /* Error reporting stuff */
14112131Sdanmcd@opensolaris.org #define CBUF_LEN 8192 /* Maximum size of the cmd */
1424235Smarkfen /*
1434235Smarkfen * Following are used for reporting errors with arguments.
1444235Smarkfen * We store the line numbers of each argument as we parse them,
1454235Smarkfen * so that the error reporting is more specific. We can have only
1465120Smarkfen * (MAXARGS - 1) arguments between any pair of CURL_BEGIN CURL_END.
1475120Smarkfen * Because a single command can be made up of multiple action/property
1485120Smarkfen * combinations, the maximum command size is (2 * (MAXARGS -1)) for each
1495120Smarkfen * of patterns, properties and actions.
1504235Smarkfen */
1515120Smarkfen #define ARG_BUF_LEN ((2 * 3 * (MAXARGS - 1)) + 1)
1524235Smarkfen static int arg_indices[ARG_BUF_LEN];
1534235Smarkfen static int argindex;
1544235Smarkfen static int linecount;
1554235Smarkfen static char cbuf[CBUF_LEN]; /* Command buffer */
1564235Smarkfen static int cbuf_offset;
1574235Smarkfen
1584235Smarkfen
1594235Smarkfen #define BYPASS_POLICY_BOOST 0x00800000
1604235Smarkfen #define ESP_POLICY_BOOST 0x00400000
1614235Smarkfen #define AH_POLICY_BOOST 0x00200000
1624235Smarkfen #define INITIAL_BASE_PRIORITY 0x000fffff
1634235Smarkfen
1644235Smarkfen /*
1654235Smarkfen * the number used to order the
1664235Smarkfen * rules starts at a certain base and
1674235Smarkfen * goes down. i.e. rules earlier in
1684235Smarkfen * the file are checked first
1694235Smarkfen */
1704235Smarkfen static uint32_t priority = INITIAL_BASE_PRIORITY;
1714235Smarkfen
1724235Smarkfen #define AH_AUTH 0
1734235Smarkfen #define ESP_ENCR 1
1744235Smarkfen #define ESP_AUTH 2
1754235Smarkfen
1764235Smarkfen
1774235Smarkfen /*
1784235Smarkfen * for deleting adds on error
1794235Smarkfen */
1804235Smarkfen
1814235Smarkfen typedef struct d_list_s
1824235Smarkfen {
1834235Smarkfen struct d_list_s *next;
1844235Smarkfen int index;
1854235Smarkfen } d_list_t;
1864235Smarkfen
1874235Smarkfen static d_list_t *d_list = NULL;
1884235Smarkfen static d_list_t *d_tail = NULL;
1894235Smarkfen
1904235Smarkfen
1914235Smarkfen /*
1924235Smarkfen * Used for multi-homed source/dest hosts.
1934235Smarkfen */
1944235Smarkfen static struct hostent *shp, *dhp;
1954235Smarkfen static unsigned int splen, dplen;
1964235Smarkfen static char tunif[TUNNAMEMAXLEN];
1974235Smarkfen static boolean_t has_saprefix, has_daprefix;
1984235Smarkfen static uint32_t seq_cnt = 0;
1994235Smarkfen
2004235Smarkfen /* lexxed out action and related properties */
2014235Smarkfen typedef struct ap_s
2024235Smarkfen {
2034235Smarkfen char *act;
2044235Smarkfen char *prop[MAXARGS + 1];
2054235Smarkfen } ap_t;
2064235Smarkfen
2074235Smarkfen
2084235Smarkfen /* one lexxed out rule */
2094235Smarkfen typedef struct act_prop_s {
2105120Smarkfen char *pattern[MAXARGS + 1];
2114235Smarkfen ap_t ap[MAXARGS + 1];
2124235Smarkfen } act_prop_t;
2134235Smarkfen
2144235Smarkfen typedef struct
2154235Smarkfen {
2164235Smarkfen uint8_t alg_id;
2174235Smarkfen uint32_t alg_minbits;
2184235Smarkfen uint32_t alg_maxbits;
2194235Smarkfen } algreq_t;
2204235Smarkfen
2214235Smarkfen /* structure to hold all information for one act_prop_t */
2224235Smarkfen typedef struct ips_act_props_s {
2234235Smarkfen struct ips_act_props_s *iap_next;
2244235Smarkfen struct ips_conf_s *iap_head;
2254235Smarkfen
2264235Smarkfen /*
2274235Smarkfen * IPsec action types (in SPD_ATTR_TYPE attribute)
2284235Smarkfen * SPD_ACTTYPE_DROP 0x0001
2294235Smarkfen * SPD_ACTTYPE_PASS 0x0002
2304235Smarkfen * SPD_ACTTYPE_IPSEC 0x0003
2314235Smarkfen */
2324235Smarkfen uint16_t iap_action;
2334235Smarkfen uint16_t iap_act_tok;
2344235Smarkfen
2354235Smarkfen /*
2364235Smarkfen * Action ATTR flags (in SPD_ATTR_FLAGS attribute)
2374235Smarkfen * SPD_APPLY_AH 0x0001
2384235Smarkfen * SPD_APPLY_ESP 0x0002
2394235Smarkfen * SPD_APPLY_SE 0x0004 * self-encapsulation *
2404235Smarkfen * SPD_APPLY_COMP 0x0008 * compression; NYI *
2414235Smarkfen * SPD_APPLY_UNIQUE 0x0010 * unique per-flow SA *
2424235Smarkfen * SPD_APPLY_BYPASS 0x0020 * bypass policy *
2434235Smarkfen */
2444235Smarkfen uint16_t iap_attr;
2454235Smarkfen uint16_t iap_attr_tok[5];
2464235Smarkfen
2474235Smarkfen algreq_t iap_aauth;
2484235Smarkfen algreq_t iap_eencr;
2494235Smarkfen algreq_t iap_eauth;
2504235Smarkfen
2514235Smarkfen uint32_t iap_life_soft_time;
2524235Smarkfen uint32_t iap_life_hard_time;
2534235Smarkfen uint32_t iap_life_soft_bytes;
2544235Smarkfen uint32_t iap_life_hard_bytes;
2554235Smarkfen
2564235Smarkfen } ips_act_props_t;
2574235Smarkfen
2584235Smarkfen #define V4_PART_OF_V6(v6) v6._S6_un._S6_u32[3]
2594235Smarkfen
2604235Smarkfen typedef struct ips_conf_s {
2614235Smarkfen /* selector */
2624235Smarkfen uint16_t patt_tok[8];
2634235Smarkfen uint8_t has_saddr;
2644235Smarkfen uint8_t has_daddr;
2654235Smarkfen uint8_t has_smask;
2664235Smarkfen uint8_t has_dmask;
2674235Smarkfen uint8_t has_type;
2684235Smarkfen uint8_t has_code;
2694235Smarkfen uint8_t has_negotiate;
2704235Smarkfen uint8_t has_tunnel;
2714235Smarkfen uint16_t swap;
2724235Smarkfen
2734235Smarkfen struct in6_addr ips_src_addr_v6;
2744235Smarkfen struct in6_addr ips_src_mask_v6;
2754235Smarkfen struct in6_addr ips_dst_addr_v6;
2764235Smarkfen struct in6_addr ips_dst_mask_v6;
2774235Smarkfen uint8_t ips_src_mask_len;
2784235Smarkfen uint8_t ips_dst_mask_len;
2794235Smarkfen in_port_t ips_src_port_min;
2804235Smarkfen in_port_t ips_src_port_max;
2814235Smarkfen in_port_t ips_dst_port_min;
2824235Smarkfen in_port_t ips_dst_port_max;
2834235Smarkfen uint8_t ips_icmp_type;
2844235Smarkfen uint8_t ips_icmp_type_end;
2854235Smarkfen uint8_t ips_icmp_code;
2864235Smarkfen uint8_t ips_icmp_code_end;
2874235Smarkfen uint8_t ips_ulp_prot;
2884235Smarkfen uint8_t ips_ipsec_prot;
2894235Smarkfen uint8_t ips_isv4;
2904235Smarkfen /*
2914235Smarkfen * SPD_RULE_FLAG_INBOUND 0x0001
2924235Smarkfen * SPD_RULE_FLAG_OUTBOUND 0x0002
2934235Smarkfen */
2944235Smarkfen uint8_t ips_dir;
2954235Smarkfen /*
2964235Smarkfen * Keep track of tunnel separately due to explosion of ways to set
2974235Smarkfen * inbound/outbound.
2984235Smarkfen */
2994235Smarkfen boolean_t ips_tunnel;
3004235Smarkfen uint64_t ips_policy_index;
3014235Smarkfen uint32_t ips_act_cnt;
3024235Smarkfen ips_act_props_t *ips_acts;
3034235Smarkfen } ips_conf_t;
3044235Smarkfen
3054235Smarkfen #define ips_src_addr V4_PART_OF_V6(ips_src_addr_v6)
3064235Smarkfen #define ips_dst_addr V4_PART_OF_V6(ips_dst_addr_v6)
3074235Smarkfen
3084235Smarkfen static int ipsecconf_nflag; /* Used only with -l option */
3094235Smarkfen static int ipsecconf_qflag; /* Used only with -a|-r option */
3104235Smarkfen
3114235Smarkfen typedef struct str_val {
3124235Smarkfen const char *string;
3134235Smarkfen int value;
3144235Smarkfen } str_val_t;
3154235Smarkfen
3164235Smarkfen typedef struct str_tval {
3174235Smarkfen const char *string;
3184235Smarkfen int tok_val;
3194235Smarkfen int value;
3204235Smarkfen } str_tval_t;
3214235Smarkfen
3224235Smarkfen static int parse_int(const char *);
3234235Smarkfen static int parse_index(const char *, char *);
3244235Smarkfen static int attach_tunname(spd_if_t *);
3254235Smarkfen static void usage(void);
3264235Smarkfen static int ipsec_conf_del(int, boolean_t);
32711278SMark.Fenwick@Sun.COM static int ipsec_conf_add(boolean_t, boolean_t, boolean_t);
3284235Smarkfen static int ipsec_conf_sub(void);
3294235Smarkfen static int ipsec_conf_flush(int);
3304235Smarkfen static int ipsec_conf_view(void);
3314235Smarkfen static int ipsec_conf_list(void);
3324235Smarkfen static int lock(void);
3334235Smarkfen static int unlock(int);
3344235Smarkfen static int parse_one(FILE *, act_prop_t *);
3354235Smarkfen static void reconfigure();
3364235Smarkfen static void in_prefixlentomask(unsigned int, uchar_t *);
3374235Smarkfen static int in_getprefixlen(char *);
3384235Smarkfen static int parse_address(int, char *);
3394235Smarkfen #ifdef DEBUG_HEAVY
3404235Smarkfen static void pfpol_msg_dump(spd_msg_t *msg, char *);
3414235Smarkfen #endif /* DEBUG_HEAVY */
3424235Smarkfen static void print_pfpol_msg(spd_msg_t *);
3434235Smarkfen static int pfp_delete_rule(uint64_t);
3444235Smarkfen static void ipsec_conf_admin(uint8_t);
3454235Smarkfen static void print_bit_range(int, int);
3464235Smarkfen static void nuke_adds();
34712131Sdanmcd@opensolaris.org static boolean_t combined_mode(uint_t);
3484235Smarkfen
3494235Smarkfen #ifdef DEBUG
3504235Smarkfen static void dump_conf(ips_conf_t *);
3514235Smarkfen #endif
3524235Smarkfen
3534235Smarkfen typedef struct
3544235Smarkfen {
3554235Smarkfen uint32_t id;
3564235Smarkfen uint32_t minkeybits;
3574235Smarkfen uint32_t maxkeybits;
3584235Smarkfen uint32_t defkeybits;
3594235Smarkfen uint32_t incr;
3604235Smarkfen } alginfo_t;
3614235Smarkfen
3624235Smarkfen static int ipsec_nalgs[3];
3634235Smarkfen static alginfo_t known_algs[3][256];
3644235Smarkfen
3654235Smarkfen #define IPS_SRC_MASK SPD_EXT_LCLADDR + 100
3664235Smarkfen #define IPS_DST_MASK SPD_EXT_REMADDR + 100
3674235Smarkfen
3684235Smarkfen /*
3694235Smarkfen * if inbound, src=remote, dst=local
3704235Smarkfen * if outbound, src=local, dst=remote
3714235Smarkfen */
3724235Smarkfen
3734235Smarkfen #define TOK_saddr 1
3744235Smarkfen #define TOK_daddr 2
3754235Smarkfen #define TOK_sport 3
3764235Smarkfen #define TOK_dport 4
3774235Smarkfen #define TOK_smask 5
3784235Smarkfen #define TOK_dmask 6
3794235Smarkfen #define TOK_ulp 7
3804235Smarkfen #define TOK_local 8
3814235Smarkfen #define TOK_lport 9
3824235Smarkfen #define TOK_remote 10
3834235Smarkfen #define TOK_rport 11
3844235Smarkfen #define TOK_dir 12
3854235Smarkfen #define TOK_type 13
3864235Smarkfen #define TOK_code 14
3874235Smarkfen #define TOK_negotiate 15
3884235Smarkfen #define TOK_tunnel 16
3894235Smarkfen
3904235Smarkfen #define IPS_SA SPD_ATTR_END
3914235Smarkfen #define IPS_DIR SPD_ATTR_EMPTY
3924235Smarkfen #define IPS_NEG SPD_ATTR_NOP
3934235Smarkfen
3944235Smarkfen
3954235Smarkfen static str_tval_t pattern_table[] = {
3964235Smarkfen {"saddr", TOK_saddr, SPD_EXT_LCLADDR},
3974235Smarkfen {"src", TOK_saddr, SPD_EXT_LCLADDR},
3984235Smarkfen {"srcaddr", TOK_saddr, SPD_EXT_LCLADDR},
3994235Smarkfen {"daddr", TOK_daddr, SPD_EXT_REMADDR},
4004235Smarkfen {"dst", TOK_daddr, SPD_EXT_REMADDR},
4014235Smarkfen {"dstaddr", TOK_daddr, SPD_EXT_REMADDR},
4024235Smarkfen {"sport", TOK_sport, SPD_EXT_LCLPORT},
4034235Smarkfen {"dport", TOK_dport, SPD_EXT_REMPORT},
4044235Smarkfen {"smask", TOK_smask, IPS_SRC_MASK},
4054235Smarkfen {"dmask", TOK_dmask, IPS_DST_MASK},
4064235Smarkfen {"ulp", TOK_ulp, SPD_EXT_PROTO},
4074235Smarkfen {"proto", TOK_ulp, SPD_EXT_PROTO},
4084235Smarkfen {"local", TOK_local, SPD_EXT_LCLADDR},
4094235Smarkfen {"laddr", TOK_local, SPD_EXT_LCLADDR},
4104235Smarkfen {"lport", TOK_lport, SPD_EXT_LCLPORT},
4114235Smarkfen {"remote", TOK_remote, SPD_EXT_REMADDR},
4124235Smarkfen {"raddr", TOK_remote, SPD_EXT_REMADDR},
4134235Smarkfen {"rport", TOK_rport, SPD_EXT_REMPORT},
4144235Smarkfen {"dir", TOK_dir, IPS_DIR},
4154235Smarkfen {"type", TOK_type, SPD_EXT_ICMP_TYPECODE},
4164235Smarkfen {"code", TOK_code, SPD_EXT_ICMP_TYPECODE},
4174235Smarkfen {"negotiate", TOK_negotiate, IPS_NEG},
4184235Smarkfen {"tunnel", TOK_tunnel, SPD_EXT_TUN_NAME},
4194235Smarkfen {NULL, 0, 0},
4204235Smarkfen };
4214235Smarkfen
4224235Smarkfen #define TOK_apply 1
4234235Smarkfen #define TOK_permit 2
4244235Smarkfen #define TOK_ipsec 3
4254235Smarkfen #define TOK_bypass 4
4264235Smarkfen #define TOK_drop 5
4274235Smarkfen #define TOK_or 6
4284235Smarkfen
4294235Smarkfen static str_tval_t action_table[] = {
4304235Smarkfen {"apply", TOK_apply, SPD_ACTTYPE_IPSEC},
4314235Smarkfen {"permit", TOK_permit, SPD_ACTTYPE_IPSEC},
4324235Smarkfen {"ipsec", TOK_ipsec, SPD_ACTTYPE_IPSEC},
4334235Smarkfen {"bypass", TOK_bypass, SPD_ACTTYPE_PASS},
4344235Smarkfen {"pass", TOK_bypass, SPD_ACTTYPE_PASS},
4354235Smarkfen {"drop", TOK_drop, SPD_ACTTYPE_DROP},
4364235Smarkfen {"or", TOK_or, 0},
4374235Smarkfen {NULL, 0, 0},
4384235Smarkfen };
4394235Smarkfen
4404235Smarkfen static str_val_t property_table[] = {
4414235Smarkfen {"auth_algs", SPD_ATTR_AH_AUTH},
4424235Smarkfen {"encr_algs", SPD_ATTR_ESP_ENCR},
4434235Smarkfen {"encr_auth_algs", SPD_ATTR_ESP_AUTH},
4444235Smarkfen {"sa", IPS_SA},
4454235Smarkfen {"dir", IPS_DIR},
4464235Smarkfen {NULL, 0},
4474235Smarkfen };
4484235Smarkfen
4494235Smarkfen static str_val_t icmp_type_table[] = {
4504235Smarkfen {"unreach", ICMP_UNREACH},
4514235Smarkfen {"echo", ICMP_ECHO},
4524235Smarkfen {"echorep", ICMP_ECHOREPLY},
4534235Smarkfen {"squench", ICMP_SOURCEQUENCH},
4544235Smarkfen {"redir", ICMP_REDIRECT},
4554235Smarkfen {"timex", ICMP_TIMXCEED},
4564235Smarkfen {"paramprob", ICMP_PARAMPROB},
4574235Smarkfen {"timest", ICMP_TSTAMP},
4584235Smarkfen {"timestrep", ICMP_TSTAMPREPLY},
4594235Smarkfen {"inforeq", ICMP_IREQ},
4604235Smarkfen {"inforep", ICMP_IREQREPLY},
4614235Smarkfen {"maskreq", ICMP_MASKREQ},
4624235Smarkfen {"maskrep", ICMP_MASKREPLY},
4634235Smarkfen {"unreach6", ICMP6_DST_UNREACH},
4644235Smarkfen {"pkttoobig6", ICMP6_PACKET_TOO_BIG},
4654235Smarkfen {"timex6", ICMP6_TIME_EXCEEDED},
4664235Smarkfen {"paramprob6", ICMP6_PARAM_PROB},
4674235Smarkfen {"echo6", ICMP6_ECHO_REQUEST},
4684235Smarkfen {"echorep6", ICMP6_ECHO_REPLY},
4694235Smarkfen {"router-sol6", ND_ROUTER_SOLICIT},
4704235Smarkfen {"router-ad6", ND_ROUTER_ADVERT},
4714235Smarkfen {"neigh-sol6", ND_NEIGHBOR_SOLICIT},
4724235Smarkfen {"neigh-ad6", ND_NEIGHBOR_ADVERT},
4734235Smarkfen {"redir6", ND_REDIRECT},
4744235Smarkfen {NULL, 0},
4754235Smarkfen };
4764235Smarkfen
4774235Smarkfen static str_val_t icmp_code_table[] = {
4784235Smarkfen {"net-unr", ICMP_UNREACH_NET},
4794235Smarkfen {"host-unr", ICMP_UNREACH_HOST},
4804235Smarkfen {"proto-unr", ICMP_UNREACH_PROTOCOL},
4814235Smarkfen {"port-unr", ICMP_UNREACH_PORT},
4824235Smarkfen {"needfrag", ICMP_UNREACH_NEEDFRAG},
4834235Smarkfen {"srcfail", ICMP_UNREACH_SRCFAIL},
4844235Smarkfen {"net-unk", ICMP_UNREACH_NET_UNKNOWN},
4854235Smarkfen {"host-unk", ICMP_UNREACH_HOST_UNKNOWN},
4864235Smarkfen {"isolate", ICMP_UNREACH_ISOLATED},
4874235Smarkfen {"net-prohib", ICMP_UNREACH_NET_PROHIB},
4884235Smarkfen {"host-prohib", ICMP_UNREACH_HOST_PROHIB},
4894235Smarkfen {"net-tos", ICMP_UNREACH_TOSNET},
4904235Smarkfen {"host-tos", ICMP_UNREACH_TOSHOST},
4914235Smarkfen {"filter-prohib", ICMP_UNREACH_FILTER_PROHIB},
4924235Smarkfen {"host-preced", ICMP_UNREACH_HOST_PRECEDENCE},
4934235Smarkfen {"cutoff-preced", ICMP_UNREACH_PRECEDENCE_CUTOFF},
4944235Smarkfen {"no-route6", ICMP6_DST_UNREACH_NOROUTE},
4954235Smarkfen {"adm-prohib6", ICMP6_DST_UNREACH_ADMIN},
4964235Smarkfen {"addr-unr6", ICMP6_DST_UNREACH_ADDR},
4974235Smarkfen {"port-unr6", ICMP6_DST_UNREACH_NOPORT},
4984235Smarkfen {"hop-limex6", ICMP6_TIME_EXCEED_TRANSIT},
4994235Smarkfen {"frag-re-timex6", ICMP6_TIME_EXCEED_REASSEMBLY},
5004235Smarkfen {"err-head6", ICMP6_PARAMPROB_HEADER},
5014235Smarkfen {"unrec-head6", ICMP6_PARAMPROB_NEXTHEADER},
5024235Smarkfen {"unreq-opt6", ICMP6_PARAMPROB_OPTION},
5034235Smarkfen {NULL, 0},
5044235Smarkfen };
5054235Smarkfen
5064235Smarkfen static sigset_t set, oset;
5074235Smarkfen
5084235Smarkfen
5094235Smarkfen static boolean_t
add_index(int index)5104235Smarkfen add_index(int index)
5114235Smarkfen {
5124235Smarkfen d_list_t *temp = malloc(sizeof (d_list_t));
5134235Smarkfen
5144235Smarkfen if (temp == NULL) {
5154235Smarkfen warn("malloc");
5164235Smarkfen return (B_TRUE);
5174235Smarkfen }
5184235Smarkfen
5194235Smarkfen temp->index = index;
5204235Smarkfen temp->next = NULL;
5214235Smarkfen
5224235Smarkfen if (d_tail == NULL) {
5234235Smarkfen d_list = d_tail = temp;
5244235Smarkfen return (B_FALSE);
5254235Smarkfen }
5264235Smarkfen
5274235Smarkfen d_tail->next = temp;
5284235Smarkfen d_tail = temp;
5294235Smarkfen
5304235Smarkfen return (B_FALSE);
5314235Smarkfen }
5324235Smarkfen
5334235Smarkfen static int
block_all_signals()5344235Smarkfen block_all_signals()
5354235Smarkfen {
5364235Smarkfen if (sigfillset(&set) == -1) {
5374235Smarkfen warn("sigfillset");
5384235Smarkfen return (-1);
5394235Smarkfen }
5404235Smarkfen if (sigprocmask(SIG_SETMASK, &set, &oset) == -1) {
5414235Smarkfen warn("sigprocmask");
5424235Smarkfen return (-1);
5434235Smarkfen }
5444235Smarkfen return (0);
5454235Smarkfen }
5464235Smarkfen
5474235Smarkfen static int
restore_all_signals()5484235Smarkfen restore_all_signals()
5494235Smarkfen {
5504235Smarkfen if (sigprocmask(SIG_SETMASK, &oset, NULL) == -1) {
5514235Smarkfen warn("sigprocmask");
5524235Smarkfen return (-1);
5534235Smarkfen }
5544235Smarkfen return (0);
5554235Smarkfen }
5564235Smarkfen
5574235Smarkfen /* allocate an ips_act_props_t and link it in correctly */
5584235Smarkfen static ips_act_props_t *
alloc_iap(ips_conf_t * parent)5594235Smarkfen alloc_iap(ips_conf_t *parent)
5604235Smarkfen {
5614235Smarkfen ips_act_props_t *ret;
5624235Smarkfen ips_act_props_t *next = parent->ips_acts;
5634235Smarkfen ips_act_props_t *current = NULL;
5644235Smarkfen
5654235Smarkfen ret = (ips_act_props_t *)calloc(sizeof (ips_act_props_t), 1);
5664235Smarkfen
5674235Smarkfen if (ret == NULL)
5684235Smarkfen return (NULL);
5694235Smarkfen
5704235Smarkfen ret->iap_head = parent;
5714235Smarkfen
5724235Smarkfen while (next != NULL) {
5734235Smarkfen current = next;
5744235Smarkfen next = next->iap_next;
5754235Smarkfen }
5764235Smarkfen
5774235Smarkfen if (current != NULL)
5784235Smarkfen current->iap_next = ret;
5794235Smarkfen else
5804235Smarkfen parent->ips_acts = ret;
5814235Smarkfen
5824235Smarkfen parent->ips_act_cnt++;
5834235Smarkfen
5844235Smarkfen return (ret);
5854235Smarkfen }
5864235Smarkfen
5874235Smarkfen /*
5884235Smarkfen * This function exit()s if it fails.
5894235Smarkfen */
5904235Smarkfen static void
fetch_algorithms()5914235Smarkfen fetch_algorithms()
5924235Smarkfen {
5934235Smarkfen struct spd_msg msg;
5944235Smarkfen struct spd_ext_actions *actp;
5954235Smarkfen struct spd_attribute *attr, *endattr;
5964235Smarkfen spd_ext_t *exts[SPD_EXT_MAX+1];
5974235Smarkfen uint64_t reply_buf[256];
5984235Smarkfen int sfd;
5994235Smarkfen int cnt, retval;
6004235Smarkfen uint64_t *start, *end;
6014235Smarkfen alginfo_t alg = {0, 0, 0, 0, 0};
6024235Smarkfen uint_t algtype;
6034235Smarkfen static boolean_t has_run = B_FALSE;
6044235Smarkfen
6054235Smarkfen if (has_run)
6064235Smarkfen return;
6074235Smarkfen else
6084235Smarkfen has_run = B_TRUE;
6094235Smarkfen
6104235Smarkfen sfd = get_pf_pol_socket();
6114235Smarkfen if (sfd < 0) {
6124235Smarkfen err(-1, gettext("unable to open policy socket"));
6134235Smarkfen }
6144235Smarkfen
6154235Smarkfen (void) memset(&msg, 0, sizeof (msg));
6164235Smarkfen msg.spd_msg_version = PF_POLICY_V1;
6174235Smarkfen msg.spd_msg_type = SPD_ALGLIST;
6184235Smarkfen msg.spd_msg_len = SPD_8TO64(sizeof (msg));
6194235Smarkfen
6204235Smarkfen cnt = write(sfd, &msg, sizeof (msg));
6214235Smarkfen if (cnt != sizeof (msg)) {
6224235Smarkfen if (cnt < 0) {
6234235Smarkfen err(-1, gettext("alglist failed: write"));
6244235Smarkfen } else {
6254235Smarkfen errx(-1, gettext("alglist failed: short write"));
6264235Smarkfen }
6274235Smarkfen }
6284235Smarkfen
6294235Smarkfen cnt = read(sfd, reply_buf, sizeof (reply_buf));
6304235Smarkfen
6314235Smarkfen retval = spdsock_get_ext(exts, (spd_msg_t *)reply_buf, SPD_8TO64(cnt),
6324235Smarkfen spdsock_diag_buf, SPDSOCK_DIAG_BUF_LEN);
6334235Smarkfen
6344235Smarkfen if (retval == KGE_LEN && exts[0]->spd_ext_len == 0) {
6354235Smarkfen /*
6364235Smarkfen * No algorithms are defined in the kernel, which caused
6374235Smarkfen * the extension length to be zero, and spdsock_get_ext()
6384235Smarkfen * to fail with a KGE_LEN error. This is not an error
6394235Smarkfen * condition, so we return nicely.
6404235Smarkfen */
6415494Spwernau (void) close(sfd);
6424235Smarkfen return;
6434235Smarkfen } else if (retval != 0) {
6444235Smarkfen if (strlen(spdsock_diag_buf) != 0)
6454235Smarkfen warnx(spdsock_diag_buf);
6464235Smarkfen err(1, gettext("fetch_algorithms failed"));
6474235Smarkfen }
6484235Smarkfen
6494235Smarkfen if (!exts[SPD_EXT_ACTION]) {
6504235Smarkfen errx(1, gettext("fetch_algorithms: action missing?!"));
6514235Smarkfen }
6524235Smarkfen
6534235Smarkfen actp = (struct spd_ext_actions *)exts[SPD_EXT_ACTION];
6544235Smarkfen start = (uint64_t *)actp;
6554235Smarkfen end = (start + actp->spd_actions_len);
6564235Smarkfen endattr = (struct spd_attribute *)end;
6574235Smarkfen attr = (struct spd_attribute *)&actp[1];
6584235Smarkfen
6594235Smarkfen algtype = 0;
6604235Smarkfen
6614235Smarkfen while (attr < endattr) {
6624235Smarkfen switch (attr->spd_attr_tag) {
6634235Smarkfen case SPD_ATTR_NOP:
6644235Smarkfen case SPD_ATTR_EMPTY:
6654235Smarkfen break;
6664235Smarkfen case SPD_ATTR_END:
6674235Smarkfen attr = endattr;
6684235Smarkfen /* FALLTHRU */
6694235Smarkfen case SPD_ATTR_NEXT:
6704235Smarkfen known_algs[algtype][ipsec_nalgs[algtype]] = alg;
6714235Smarkfen ipsec_nalgs[algtype]++;
6724235Smarkfen break;
6734235Smarkfen
6744235Smarkfen case SPD_ATTR_ENCR_MINBITS:
6754235Smarkfen case SPD_ATTR_AH_MINBITS:
6764235Smarkfen case SPD_ATTR_ESPA_MINBITS:
6774235Smarkfen alg.minkeybits = attr->spd_attr_value;
6784235Smarkfen break;
6794235Smarkfen
6804235Smarkfen case SPD_ATTR_ENCR_MAXBITS:
6814235Smarkfen case SPD_ATTR_AH_MAXBITS:
6824235Smarkfen case SPD_ATTR_ESPA_MAXBITS:
6834235Smarkfen alg.maxkeybits = attr->spd_attr_value;
6844235Smarkfen break;
6854235Smarkfen
6864235Smarkfen case SPD_ATTR_ENCR_DEFBITS:
6874235Smarkfen case SPD_ATTR_AH_DEFBITS:
6884235Smarkfen case SPD_ATTR_ESPA_DEFBITS:
6894235Smarkfen alg.defkeybits = attr->spd_attr_value;
6904235Smarkfen break;
6914235Smarkfen
6924235Smarkfen case SPD_ATTR_ENCR_INCRBITS:
6934235Smarkfen case SPD_ATTR_AH_INCRBITS:
6944235Smarkfen case SPD_ATTR_ESPA_INCRBITS:
6954235Smarkfen alg.incr = attr->spd_attr_value;
6964235Smarkfen break;
6974235Smarkfen
6984235Smarkfen case SPD_ATTR_AH_AUTH:
6994235Smarkfen case SPD_ATTR_ESP_AUTH:
7004235Smarkfen case SPD_ATTR_ESP_ENCR:
7014235Smarkfen alg.id = attr->spd_attr_value;
7024235Smarkfen algtype = attr->spd_attr_tag - SPD_ATTR_AH_AUTH;
7034235Smarkfen break;
7044235Smarkfen }
7054235Smarkfen attr++;
7064235Smarkfen }
7074235Smarkfen
7084235Smarkfen (void) close(sfd);
7094235Smarkfen }
7104235Smarkfen
7114235Smarkfen /* data dependant transform (act_cnt) */
7124235Smarkfen #define ATTR(ap, tag, value) \
7134235Smarkfen do { (ap)->spd_attr_tag = (tag); \
7144235Smarkfen (ap)->spd_attr_value = (value); \
7154235Smarkfen ap++; } while (0)
7164235Smarkfen
7174235Smarkfen static struct spd_attribute *
emit_alg(struct spd_attribute * ap,int type,const algreq_t * ar,int algattr,int minbitattr,int maxbitattr)7184235Smarkfen emit_alg(struct spd_attribute *ap, int type, const algreq_t *ar,
7194235Smarkfen int algattr, int minbitattr, int maxbitattr)
7204235Smarkfen {
7214235Smarkfen int id = ar->alg_id;
7224235Smarkfen int minbits, i;
7234235Smarkfen
7244235Smarkfen if (id != 0) {
7254235Smarkfen /* LINTED E_CONST_COND */
7264235Smarkfen ATTR(ap, algattr, ar->alg_id);
7274235Smarkfen
7284235Smarkfen minbits = ar->alg_minbits;
7294235Smarkfen if (minbits == 0) {
7304235Smarkfen for (i = 0; i < ipsec_nalgs[type]; i++) {
7314235Smarkfen if (known_algs[type][i].id == id)
7324235Smarkfen break;
7334235Smarkfen }
7344235Smarkfen if (i < ipsec_nalgs[type])
7354235Smarkfen minbits = known_algs[type][i].defkeybits;
7364235Smarkfen }
7374235Smarkfen if (minbits != 0)
7384235Smarkfen /* LINTED E_CONST_COND */
7394235Smarkfen ATTR(ap, minbitattr, minbits);
7404235Smarkfen if (ar->alg_maxbits != SPD_MAX_MAXBITS)
7414235Smarkfen /* LINTED E_CONST_COND */
7424235Smarkfen ATTR(ap, maxbitattr, ar->alg_maxbits);
7434235Smarkfen }
7444235Smarkfen
7454235Smarkfen return (ap);
7464235Smarkfen }
7474235Smarkfen
7484235Smarkfen
7494235Smarkfen
7504235Smarkfen static struct spd_attribute *
ips_act_props_to_action(struct spd_attribute * ap,uint32_t * rule_priorityp,const ips_act_props_t * act_ptr)7514235Smarkfen ips_act_props_to_action(struct spd_attribute *ap, uint32_t *rule_priorityp,
7524235Smarkfen const ips_act_props_t *act_ptr)
7534235Smarkfen {
7544235Smarkfen uint32_t rule_priority = *rule_priorityp;
7554235Smarkfen
7564235Smarkfen /* LINTED E_CONST_COND */
7574235Smarkfen ATTR(ap, SPD_ATTR_EMPTY, 0);
7584235Smarkfen
7594235Smarkfen /* type */
7604235Smarkfen /* LINTED E_CONST_COND */
7614235Smarkfen ATTR(ap, SPD_ATTR_TYPE, act_ptr->iap_action);
7624235Smarkfen
7634235Smarkfen if (act_ptr->iap_action == SPD_ACTTYPE_PASS)
7644235Smarkfen rule_priority |= BYPASS_POLICY_BOOST;
7654235Smarkfen
7664235Smarkfen /* flags */
7674235Smarkfen if (act_ptr->iap_attr != 0)
7684235Smarkfen /* LINTED E_CONST_COND */
7694235Smarkfen ATTR(ap, SPD_ATTR_FLAGS, act_ptr->iap_attr);
7704235Smarkfen
7714235Smarkfen /* esp */
7724235Smarkfen if (act_ptr->iap_attr & SPD_APPLY_ESP) {
7734235Smarkfen rule_priority |= ESP_POLICY_BOOST;
7744235Smarkfen
7754235Smarkfen /* encr */
7764235Smarkfen ap = emit_alg(ap, ESP_ENCR, &act_ptr->iap_eencr,
7774235Smarkfen SPD_ATTR_ESP_ENCR,
7784235Smarkfen SPD_ATTR_ENCR_MINBITS, SPD_ATTR_ENCR_MAXBITS);
7794235Smarkfen
7804235Smarkfen /* auth */
7814235Smarkfen ap = emit_alg(ap, ESP_AUTH, &act_ptr->iap_eauth,
7824235Smarkfen SPD_ATTR_ESP_AUTH,
7834235Smarkfen SPD_ATTR_ESPA_MINBITS, SPD_ATTR_ESPA_MAXBITS);
7844235Smarkfen }
7854235Smarkfen
7864235Smarkfen /* ah */
7874235Smarkfen if (act_ptr->iap_attr & SPD_APPLY_AH) {
7884235Smarkfen rule_priority |= AH_POLICY_BOOST;
7894235Smarkfen /* auth */
7904235Smarkfen ap = emit_alg(ap, AH_AUTH, &act_ptr->iap_aauth,
7914235Smarkfen SPD_ATTR_AH_AUTH,
7924235Smarkfen SPD_ATTR_AH_MINBITS, SPD_ATTR_AH_MAXBITS);
7934235Smarkfen }
7944235Smarkfen
7954235Smarkfen /* lifetimes */
7964235Smarkfen if (act_ptr->iap_life_soft_time != 0)
7974235Smarkfen /* LINTED E_CONST_COND */
7984235Smarkfen ATTR(ap, SPD_ATTR_LIFE_SOFT_TIME, act_ptr->iap_life_soft_time);
7994235Smarkfen if (act_ptr->iap_life_hard_time != 0)
8004235Smarkfen /* LINTED E_CONST_COND */
8014235Smarkfen ATTR(ap, SPD_ATTR_LIFE_HARD_TIME, act_ptr->iap_life_hard_time);
8024235Smarkfen if (act_ptr->iap_life_soft_bytes != 0)
8034235Smarkfen /* LINTED E_CONST_COND */
8044235Smarkfen ATTR(ap, SPD_ATTR_LIFE_SOFT_BYTES,
8054235Smarkfen act_ptr->iap_life_soft_bytes);
8064235Smarkfen if (act_ptr->iap_life_hard_bytes != 0)
8074235Smarkfen /* LINTED E_CONST_COND */
8084235Smarkfen ATTR(ap, SPD_ATTR_LIFE_HARD_BYTES,
8094235Smarkfen act_ptr->iap_life_hard_bytes);
8104235Smarkfen
8114235Smarkfen /* LINTED E_CONST_COND */
8124235Smarkfen ATTR(ap, SPD_ATTR_NEXT, 0);
8134235Smarkfen
8144235Smarkfen *rule_priorityp = rule_priority;
8154235Smarkfen
8164235Smarkfen return (ap);
8174235Smarkfen }
8184235Smarkfen
8194235Smarkfen static boolean_t
alg_rangecheck(uint_t type,uint_t algid,const algreq_t * ar)8204235Smarkfen alg_rangecheck(uint_t type, uint_t algid, const algreq_t *ar)
8214235Smarkfen {
8224235Smarkfen int i;
8234235Smarkfen uint_t minbits = ar->alg_minbits;
8244235Smarkfen uint_t maxbits = ar->alg_maxbits;
8254235Smarkfen
8264235Smarkfen for (i = 0; i < ipsec_nalgs[type]; i++) {
8274235Smarkfen if (known_algs[type][i].id == algid)
8284235Smarkfen break;
8294235Smarkfen }
8304235Smarkfen
8314235Smarkfen if (i >= ipsec_nalgs[type]) {
8324235Smarkfen /*
8334235Smarkfen * The kernel (where we populate known_algs from) doesn't
8344235Smarkfen * return the id's associated with NONE algorithms so we
8354235Smarkfen * test here if this was the reason the algorithm wasn't
8364235Smarkfen * found before wrongly failing.
8374235Smarkfen */
8384235Smarkfen if (((type == ESP_ENCR) && (algid == SADB_EALG_NONE)) ||
8394235Smarkfen ((type == ESP_AUTH) && (algid == SADB_AALG_NONE)) ||
8404235Smarkfen ((type == AH_AUTH) && (algid == SADB_AALG_NONE))) {
8414235Smarkfen return (B_TRUE);
8424235Smarkfen } else {
8434235Smarkfen return (B_FALSE); /* not found */
8444235Smarkfen }
8454235Smarkfen }
8464235Smarkfen
8474235Smarkfen if ((minbits == 0) && (maxbits == 0))
8484235Smarkfen return (B_TRUE);
8494235Smarkfen
8504235Smarkfen minbits = MAX(minbits, known_algs[type][i].minkeybits);
8514235Smarkfen maxbits = MIN(maxbits, known_algs[type][i].maxkeybits);
8524235Smarkfen
8534235Smarkfen /* we could also check key increments here.. */
8544235Smarkfen return (minbits <= maxbits); /* non-null intersection */
8554235Smarkfen }
8564235Smarkfen
8574235Smarkfen /*
8584235Smarkfen * Inspired by uts/common/inet/spd.c:ipsec_act_wildcard_expand()
8594235Smarkfen */
8604235Smarkfen
8614235Smarkfen 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)8624235Smarkfen ips_act_wild_props_to_action(struct spd_attribute *ap,
8634235Smarkfen uint32_t *rule_priorityp, uint16_t *act_cntp,
8644235Smarkfen const ips_act_props_t *act_ptr)
8654235Smarkfen {
8664235Smarkfen ips_act_props_t tact = *act_ptr;
86712131Sdanmcd@opensolaris.org boolean_t use_ah, use_esp, use_espa, combined;
8684235Smarkfen boolean_t wild_auth, wild_encr, wild_eauth;
8694235Smarkfen uint_t auth_alg, auth_idx, auth_min, auth_max;
8704235Smarkfen uint_t eauth_alg, eauth_idx, eauth_min, eauth_max;
8714235Smarkfen uint_t encr_alg, encr_idx, encr_min, encr_max;
8724235Smarkfen
8734235Smarkfen use_ah = !!(act_ptr->iap_attr & SPD_APPLY_AH);
8744235Smarkfen use_esp = !!(act_ptr->iap_attr & SPD_APPLY_ESP);
8754235Smarkfen use_espa = !!(act_ptr->iap_attr & SPD_APPLY_ESPA);
8764235Smarkfen auth_alg = act_ptr->iap_aauth.alg_id;
8774235Smarkfen eauth_alg = act_ptr->iap_eauth.alg_id;
8784235Smarkfen encr_alg = act_ptr->iap_eencr.alg_id;
8794235Smarkfen
8804235Smarkfen wild_auth = use_ah && (auth_alg == SADB_AALG_NONE);
8814235Smarkfen wild_eauth = use_espa && (eauth_alg == SADB_AALG_NONE);
8824235Smarkfen wild_encr = use_esp && (encr_alg == SADB_EALG_NONE);
8834235Smarkfen
8844235Smarkfen auth_min = auth_max = auth_alg;
8854235Smarkfen eauth_min = eauth_max = eauth_alg;
8864235Smarkfen encr_min = encr_max = encr_alg;
8874235Smarkfen
8884235Smarkfen /*
8894235Smarkfen * set up for explosion.. for each dimension, expand output
8904235Smarkfen * size by the explosion factor.
8914235Smarkfen */
8924235Smarkfen if (wild_auth) {
8934235Smarkfen auth_min = 0;
8944235Smarkfen auth_max = ipsec_nalgs[AH_AUTH] - 1;
8954235Smarkfen }
8964235Smarkfen if (wild_eauth) {
8974235Smarkfen eauth_min = 0;
8984235Smarkfen eauth_max = ipsec_nalgs[ESP_AUTH] - 1;
8994235Smarkfen }
9004235Smarkfen if (wild_encr) {
9014235Smarkfen encr_min = 0;
9024235Smarkfen encr_max = ipsec_nalgs[ESP_ENCR] - 1;
9034235Smarkfen }
9044235Smarkfen
9054235Smarkfen #define WHICH_ALG(type, wild, idx) ((wild)?(known_algs[type][idx].id):(idx))
9064235Smarkfen
9074235Smarkfen for (encr_idx = encr_min; encr_idx <= encr_max; encr_idx++) {
9084235Smarkfen encr_alg = WHICH_ALG(ESP_ENCR, wild_encr, encr_idx);
9094235Smarkfen
9104235Smarkfen if (use_esp &&
9114235Smarkfen !alg_rangecheck(ESP_ENCR, encr_alg, &act_ptr->iap_eencr))
9124235Smarkfen continue;
9134235Smarkfen
91412131Sdanmcd@opensolaris.org combined = combined_mode(encr_alg);
91512131Sdanmcd@opensolaris.org
9164235Smarkfen for (auth_idx = auth_min; auth_idx <= auth_max; auth_idx++) {
9174235Smarkfen auth_alg = WHICH_ALG(AH_AUTH, wild_auth, auth_idx);
9184235Smarkfen
9194235Smarkfen if (use_ah &&
9204235Smarkfen !alg_rangecheck(AH_AUTH, auth_alg,
9215120Smarkfen &act_ptr->iap_aauth))
9224235Smarkfen continue;
9234235Smarkfen
9244235Smarkfen
9254235Smarkfen for (eauth_idx = eauth_min; eauth_idx <= eauth_max;
9264235Smarkfen eauth_idx++) {
9274235Smarkfen eauth_alg = WHICH_ALG(ESP_AUTH, wild_eauth,
9284235Smarkfen eauth_idx);
9294235Smarkfen
93012131Sdanmcd@opensolaris.org if (!combined && use_espa &&
9314235Smarkfen !alg_rangecheck(ESP_AUTH, eauth_alg,
9324235Smarkfen &act_ptr->iap_eauth))
9334235Smarkfen continue;
9344235Smarkfen
9354235Smarkfen tact.iap_eencr.alg_id = encr_alg;
9364235Smarkfen tact.iap_aauth.alg_id = auth_alg;
9374235Smarkfen
93812131Sdanmcd@opensolaris.org /*
93912131Sdanmcd@opensolaris.org * If the cipher is combined-mode don't do any
94012131Sdanmcd@opensolaris.org * ESP authentication.
94112131Sdanmcd@opensolaris.org */
94212131Sdanmcd@opensolaris.org tact.iap_eauth.alg_id =
94312131Sdanmcd@opensolaris.org combined ? SADB_AALG_NONE : eauth_alg;
94412131Sdanmcd@opensolaris.org
9454235Smarkfen (*act_cntp)++;
9464235Smarkfen ap = ips_act_props_to_action(ap,
9474235Smarkfen rule_priorityp, &tact);
94812131Sdanmcd@opensolaris.org
94912131Sdanmcd@opensolaris.org /* Stop now if the cipher is combined-mode. */
95012131Sdanmcd@opensolaris.org if (combined)
95112131Sdanmcd@opensolaris.org break; /* Out of for loop. */
9524235Smarkfen }
9534235Smarkfen }
9544235Smarkfen }
9554235Smarkfen
9564235Smarkfen #undef WHICH_ALG
9574235Smarkfen
9584235Smarkfen return (ap);
9594235Smarkfen }
9604235Smarkfen
9614235Smarkfen /* huge, but not safe since no length checking is done */
9624235Smarkfen #define MAX_POL_MSG_LEN 16384
9634235Smarkfen
9644235Smarkfen
9654235Smarkfen /*
9664235Smarkfen * hand in some ips_conf_t's, get back an
9674235Smarkfen * iovec of pfpol messages.
9684235Smarkfen * this function converts the internal ips_conf_t into
9694235Smarkfen * a form that pf_pol can use.
9704235Smarkfen * return 0 on success, 1 on failure
9714235Smarkfen */
9724235Smarkfen static int
ips_conf_to_pfpol_msg(int ipsec_cmd,ips_conf_t * inConf,int num_ips,struct iovec * msg)9734235Smarkfen ips_conf_to_pfpol_msg(int ipsec_cmd, ips_conf_t *inConf, int num_ips,
9744235Smarkfen struct iovec *msg)
9754235Smarkfen {
9764235Smarkfen int i;
9774235Smarkfen ips_conf_t *conf;
9784235Smarkfen uint64_t *scratch = NULL;
9794235Smarkfen
9804235Smarkfen for (i = 0; i < num_ips; i++) {
9814235Smarkfen uint16_t *msg_len;
9824235Smarkfen uint16_t act_cnt = 0;
9834235Smarkfen uint64_t *next = NULL;
9844235Smarkfen spd_msg_t *spd_msg;
9854235Smarkfen spd_address_t *spd_address;
9864235Smarkfen struct spd_rule *spd_rule;
9874235Smarkfen struct spd_proto *spd_proto;
9884235Smarkfen struct spd_portrange *spd_portrange;
9894235Smarkfen struct spd_ext_actions *spd_ext_actions;
9904235Smarkfen struct spd_attribute *ap;
9914235Smarkfen struct spd_typecode *spd_typecode;
9924235Smarkfen spd_if_t *spd_if;
9934235Smarkfen ips_act_props_t *act_ptr;
9944235Smarkfen uint32_t rule_priority = 0;
9954235Smarkfen
9964235Smarkfen scratch = calloc(1, MAX_POL_MSG_LEN);
9974235Smarkfen msg[i].iov_base = (char *)scratch;
9984235Smarkfen if (scratch == NULL) {
9994235Smarkfen warn(gettext("memory"));
10004235Smarkfen return (1);
10014235Smarkfen }
10024235Smarkfen conf = &(inConf[i]);
10034235Smarkfen
10044235Smarkfen spd_msg = (spd_msg_t *)scratch;
10054235Smarkfen next = (uint64_t *)&(spd_msg[1]);
10064235Smarkfen
10074235Smarkfen msg_len = &(spd_msg->spd_msg_len);
10084235Smarkfen
10094235Smarkfen spd_msg->spd_msg_version = PF_POLICY_V1;
10104235Smarkfen spd_msg->spd_msg_pid = getpid();
10114235Smarkfen spd_msg->spd_msg_seq = ++seq_cnt;
10124235Smarkfen
10134235Smarkfen switch (ipsec_cmd) {
10144235Smarkfen case SPD_ADDRULE:
10154235Smarkfen spd_msg->spd_msg_type = SPD_ADDRULE;
10164235Smarkfen break;
10174235Smarkfen
10184235Smarkfen default:
10194235Smarkfen warnx("%s %d", gettext("bad command:"), ipsec_cmd);
10204235Smarkfen spd_msg->spd_msg_type = SPD_ADDRULE;
10214235Smarkfen break;
10224235Smarkfen }
10234235Smarkfen
10244235Smarkfen /*
10254235Smarkfen * SELECTOR
10264235Smarkfen */
10274235Smarkfen
10284235Smarkfen spd_msg->spd_msg_spdid = SPD_STANDBY;
10294235Smarkfen
10304235Smarkfen /* rule */
10314235Smarkfen spd_rule = (struct spd_rule *)next;
10324235Smarkfen
10334235Smarkfen spd_rule->spd_rule_len = SPD_8TO64(sizeof (struct spd_rule));
10344235Smarkfen spd_rule->spd_rule_type = SPD_EXT_RULE;
10354235Smarkfen spd_rule->spd_rule_flags = conf->ips_dir;
10364235Smarkfen if (conf->ips_tunnel)
10374235Smarkfen spd_rule->spd_rule_flags |= SPD_RULE_FLAG_TUNNEL;
10384235Smarkfen
10394235Smarkfen next = (uint64_t *)&(spd_rule[1]);
10404235Smarkfen
10414235Smarkfen /* proto */
10424235Smarkfen if (conf->ips_ulp_prot != 0) {
10434235Smarkfen spd_proto = (struct spd_proto *)next;
10444235Smarkfen spd_proto->spd_proto_len =
10455120Smarkfen SPD_8TO64(sizeof (struct spd_proto));
10464235Smarkfen spd_proto->spd_proto_exttype = SPD_EXT_PROTO;
10474235Smarkfen spd_proto->spd_proto_number = conf->ips_ulp_prot;
10484235Smarkfen next = (uint64_t *)&(spd_proto[1]);
10494235Smarkfen }
10504235Smarkfen
10514235Smarkfen /* tunnel */
10524235Smarkfen if (conf->has_tunnel != 0) {
10534235Smarkfen spd_if = (spd_if_t *)next;
10544235Smarkfen spd_if->spd_if_len =
10554235Smarkfen SPD_8TO64(P2ROUNDUP(strlen(tunif) + 1, 8) +
10564235Smarkfen sizeof (spd_if_t));
10574235Smarkfen spd_if->spd_if_exttype = SPD_EXT_TUN_NAME;
10584235Smarkfen (void) strlcpy((char *)spd_if->spd_if_name, tunif,
10595120Smarkfen TUNNAMEMAXLEN);
10604235Smarkfen next = (uint64_t *)(spd_if) + spd_if->spd_if_len;
10614235Smarkfen }
10624235Smarkfen
10634235Smarkfen /* icmp type/code */
10644235Smarkfen if (conf->ips_ulp_prot == IPPROTO_ICMP ||
10654235Smarkfen conf->ips_ulp_prot == IPPROTO_ICMPV6) {
10664235Smarkfen if (conf->has_type) {
10674235Smarkfen spd_typecode = (struct spd_typecode *)next;
10684235Smarkfen spd_typecode->spd_typecode_len =
10694235Smarkfen SPD_8TO64(sizeof (struct spd_typecode));
10704235Smarkfen spd_typecode->spd_typecode_exttype =
10714235Smarkfen SPD_EXT_ICMP_TYPECODE;
10724235Smarkfen spd_typecode->spd_typecode_type =
10734235Smarkfen conf->ips_icmp_type;
10744235Smarkfen spd_typecode->spd_typecode_type_end =
10754235Smarkfen conf->ips_icmp_type_end;
10764235Smarkfen if (conf->has_code) {
10774235Smarkfen spd_typecode->spd_typecode_code =
10784235Smarkfen conf->ips_icmp_code;
10794235Smarkfen spd_typecode->spd_typecode_code_end =
10804235Smarkfen conf->ips_icmp_code_end;
10814235Smarkfen } else {
10824235Smarkfen spd_typecode->spd_typecode_code = 255;
10834235Smarkfen spd_typecode->spd_typecode_code_end
10844235Smarkfen = 255;
10854235Smarkfen }
10864235Smarkfen next = (uint64_t *)&(spd_typecode[1]);
10874235Smarkfen }
10884235Smarkfen }
10894235Smarkfen
10904235Smarkfen /* src port */
10914235Smarkfen if (conf->ips_src_port_min != 0 ||
10924235Smarkfen conf->ips_src_port_max != 0) {
10934235Smarkfen spd_portrange = (struct spd_portrange *)next;
10944235Smarkfen spd_portrange->spd_ports_len =
10955120Smarkfen SPD_8TO64(sizeof (struct spd_portrange));
10964235Smarkfen spd_portrange->spd_ports_exttype =
10975120Smarkfen (conf->swap)?SPD_EXT_REMPORT:SPD_EXT_LCLPORT;
10984235Smarkfen spd_portrange->spd_ports_minport =
10995120Smarkfen conf->ips_src_port_min;
11004235Smarkfen spd_portrange->spd_ports_maxport =
11015120Smarkfen conf->ips_src_port_max;
11024235Smarkfen next = (uint64_t *)&(spd_portrange[1]);
11034235Smarkfen }
11044235Smarkfen /* dst port */
11054235Smarkfen if (conf->ips_dst_port_min != 0 ||
11064235Smarkfen conf->ips_dst_port_max != 0) {
11074235Smarkfen spd_portrange = (struct spd_portrange *)next;
11084235Smarkfen spd_portrange->spd_ports_len =
11095120Smarkfen SPD_8TO64(sizeof (struct spd_portrange));
11104235Smarkfen spd_portrange->spd_ports_exttype =
11115120Smarkfen (conf->swap)?SPD_EXT_LCLPORT:SPD_EXT_REMPORT;
11124235Smarkfen spd_portrange->spd_ports_minport =
11135120Smarkfen conf->ips_dst_port_min;
11144235Smarkfen spd_portrange->spd_ports_maxport =
11155120Smarkfen conf->ips_dst_port_max;
11164235Smarkfen next = (uint64_t *)&(spd_portrange[1]);
11174235Smarkfen }
11184235Smarkfen
11194235Smarkfen /* saddr */
11204235Smarkfen if (conf->has_saddr) {
11214235Smarkfen spd_address = (spd_address_t *)next;
11224235Smarkfen next = (uint64_t *)(spd_address + 1);
11234235Smarkfen
11244235Smarkfen spd_address->spd_address_exttype =
11255120Smarkfen (conf->swap)?SPD_EXT_REMADDR:SPD_EXT_LCLADDR;
11264235Smarkfen spd_address->spd_address_prefixlen =
11275120Smarkfen conf->ips_src_mask_len;
11284235Smarkfen
11294235Smarkfen if (conf->ips_isv4) {
11304235Smarkfen spd_address->spd_address_af = AF_INET;
11314235Smarkfen (void) memcpy(next, &(conf->ips_src_addr),
11325120Smarkfen sizeof (ipaddr_t));
11334235Smarkfen spd_address->spd_address_len = 2;
11344235Smarkfen next += SPD_8TO64(sizeof (ipaddr_t) + 4);
11354235Smarkfen if (!conf->has_smask)
11364235Smarkfen spd_address->spd_address_prefixlen = 32;
11374235Smarkfen } else {
11384235Smarkfen spd_address->spd_address_af = AF_INET6;
11394235Smarkfen (void) memcpy(next, &(conf->ips_src_addr_v6),
11404235Smarkfen sizeof (in6_addr_t));
11414235Smarkfen spd_address->spd_address_len = 3;
11424235Smarkfen next += SPD_8TO64(sizeof (in6_addr_t));
11434235Smarkfen if (!conf->has_smask)
11444235Smarkfen spd_address->spd_address_prefixlen
11455120Smarkfen = 128;
11464235Smarkfen }
11474235Smarkfen }
11484235Smarkfen
11494235Smarkfen /* daddr */
11504235Smarkfen if (conf->has_daddr) {
11514235Smarkfen spd_address = (spd_address_t *)next;
11524235Smarkfen
11534235Smarkfen next = (uint64_t *)(spd_address + 1);
11544235Smarkfen
11554235Smarkfen spd_address->spd_address_exttype =
11565120Smarkfen (conf->swap)?SPD_EXT_LCLADDR:SPD_EXT_REMADDR;
11574235Smarkfen spd_address->spd_address_prefixlen =
11585120Smarkfen conf->ips_dst_mask_len;
11594235Smarkfen
11604235Smarkfen if (conf->ips_isv4) {
11614235Smarkfen spd_address->spd_address_af = AF_INET;
11624235Smarkfen (void) memcpy(next, &conf->ips_dst_addr,
11634235Smarkfen sizeof (ipaddr_t));
11644235Smarkfen spd_address->spd_address_len = 2;
11654235Smarkfen /* "+ 4" below is for padding. */
11664235Smarkfen next += SPD_8TO64(sizeof (ipaddr_t) + 4);
11674235Smarkfen if (!conf->has_dmask)
11684235Smarkfen spd_address->spd_address_prefixlen = 32;
11694235Smarkfen } else {
11704235Smarkfen spd_address->spd_address_af = AF_INET6;
11714235Smarkfen (void) memcpy(next, &(conf->ips_dst_addr_v6),
11724235Smarkfen sizeof (in6_addr_t));
11734235Smarkfen spd_address->spd_address_len = 3;
11744235Smarkfen next += SPD_8TO64(sizeof (in6_addr_t));
11754235Smarkfen if (!conf->has_dmask)
11764235Smarkfen spd_address->spd_address_prefixlen
11775120Smarkfen = 128;
11784235Smarkfen }
11794235Smarkfen }
11804235Smarkfen
11814235Smarkfen /* actions */
11824235Smarkfen spd_ext_actions = (struct spd_ext_actions *)next;
11834235Smarkfen
11844235Smarkfen spd_ext_actions->spd_actions_exttype = SPD_EXT_ACTION;
11854235Smarkfen
11864235Smarkfen act_ptr = conf->ips_acts;
11874235Smarkfen ap = (struct spd_attribute *)(&spd_ext_actions[1]);
11884235Smarkfen
11894235Smarkfen rule_priority = priority--;
11904235Smarkfen
11914235Smarkfen for (act_ptr = conf->ips_acts; act_ptr != NULL;
11924235Smarkfen act_ptr = act_ptr->iap_next) {
11934235Smarkfen ap = ips_act_wild_props_to_action(ap, &rule_priority,
11944235Smarkfen &act_cnt, act_ptr);
11954235Smarkfen }
11964235Smarkfen ap[-1].spd_attr_tag = SPD_ATTR_END;
11974235Smarkfen
11984235Smarkfen next = (uint64_t *)ap;
11994235Smarkfen
12004235Smarkfen spd_rule->spd_rule_priority = rule_priority;
12014235Smarkfen
12024235Smarkfen msg[i].iov_len = (uintptr_t)next - (uintptr_t)msg[i].iov_base;
12034235Smarkfen *msg_len = (uint16_t)SPD_8TO64(msg[i].iov_len);
12044235Smarkfen spd_ext_actions->spd_actions_count = act_cnt;
12054235Smarkfen spd_ext_actions->spd_actions_len =
12064235Smarkfen SPD_8TO64((uintptr_t)next - (uintptr_t)spd_ext_actions);
12074235Smarkfen #ifdef DEBUG_HEAVY
12084235Smarkfen printf("pfpol msg len in uint64_t's = %d\n", *msg_len);
12094235Smarkfen printf("pfpol test_len in bytes = %d\n", msg[i].iov_len);
12104235Smarkfen pfpol_msg_dump((spd_msg_t *)scratch,
12114235Smarkfen "ips_conf_to_pfpol_msg");
12124235Smarkfen #endif
12134235Smarkfen }
12144235Smarkfen
12154235Smarkfen #undef ATTR
12164235Smarkfen return (0);
12174235Smarkfen }
12184235Smarkfen
12194235Smarkfen static int
get_pf_pol_socket(void)12204235Smarkfen get_pf_pol_socket(void)
12214235Smarkfen {
12224235Smarkfen int s = socket(PF_POLICY, SOCK_RAW, PF_POLICY_V1);
12234235Smarkfen if (s < 0) {
12244235Smarkfen if (errno == EPERM) {
12254235Smarkfen EXIT_BADPERM("Insufficient privileges to open "
12264235Smarkfen "PF_POLICY socket.");
12274235Smarkfen } else {
12284235Smarkfen warn(gettext("(loading pf_policy) socket:"));
12294235Smarkfen }
12304235Smarkfen }
12314235Smarkfen
12324235Smarkfen return (s);
12334235Smarkfen }
12344235Smarkfen
12354235Smarkfen
12364235Smarkfen static int
send_pf_pol_message(int ipsec_cmd,ips_conf_t * conf,int * diag)12374235Smarkfen send_pf_pol_message(int ipsec_cmd, ips_conf_t *conf, int *diag)
12384235Smarkfen {
12394235Smarkfen int retval;
12404235Smarkfen int cnt;
12414235Smarkfen int total_len;
12424235Smarkfen struct iovec polmsg;
12434235Smarkfen spd_msg_t *return_buf;
12444235Smarkfen spd_ext_t *exts[SPD_EXT_MAX+1];
12454235Smarkfen int fd = get_pf_pol_socket();
12464235Smarkfen
12474235Smarkfen *diag = 0;
12484235Smarkfen
12494235Smarkfen if (fd < 0)
12504235Smarkfen return (EBADF);
12514235Smarkfen
12524235Smarkfen retval = ips_conf_to_pfpol_msg(ipsec_cmd, conf, 1, &polmsg);
12534235Smarkfen
12544235Smarkfen if (retval) {
12554235Smarkfen (void) close(fd);
12564235Smarkfen return (ENOMEM);
12574235Smarkfen }
12584235Smarkfen
12594235Smarkfen total_len = polmsg.iov_len;
12604235Smarkfen
12614235Smarkfen cnt = writev(fd, &polmsg, 1);
12624235Smarkfen
12634235Smarkfen #ifdef DEBUG_HEAVY
12644235Smarkfen (void) printf("cnt = %d\n", cnt);
12654235Smarkfen #endif
12664235Smarkfen if (cnt < 0) {
12674235Smarkfen warn(gettext("pf_pol write"));
12684235Smarkfen } else {
12694235Smarkfen return_buf = (spd_msg_t *)calloc(total_len, 1);
12704235Smarkfen
12714235Smarkfen if (return_buf == NULL) {
12724235Smarkfen warn(gettext("memory"));
12734235Smarkfen } else {
12744235Smarkfen cnt = read(fd, (void*)return_buf, total_len);
12754235Smarkfen #ifdef DEBUG_HEAVY
12764235Smarkfen (void) printf("pf_pol read: cnt = %d(%d)\n", cnt,
12774235Smarkfen total_len);
12784235Smarkfen #endif
12794235Smarkfen
12804235Smarkfen if (cnt > 8 && return_buf->spd_msg_errno) {
12814235Smarkfen *diag = return_buf->spd_msg_diagnostic;
12824235Smarkfen if (!ipsecconf_qflag) {
12834235Smarkfen warnx("%s: %s",
12844235Smarkfen gettext("Kernel returned"),
12854235Smarkfen sys_error_message(
12864235Smarkfen return_buf->spd_msg_errno));
12874235Smarkfen }
12884235Smarkfen if (*diag != 0)
12894235Smarkfen (void) printf(gettext(
12904235Smarkfen "\t(spdsock diagnostic: %s)\n"),
12914235Smarkfen spdsock_diag(*diag));
12924235Smarkfen #ifdef DEBUG_HEAVY
12934235Smarkfen pfpol_msg_dump((spd_msg_t *)polmsg.iov_base,
12944235Smarkfen "message in");
12954235Smarkfen pfpol_msg_dump(return_buf,
12964235Smarkfen "send_pf_pol_message");
12974235Smarkfen #endif
12984235Smarkfen retval = return_buf->spd_msg_errno;
12994235Smarkfen free(return_buf);
13004235Smarkfen free(polmsg.iov_base);
13014235Smarkfen (void) close(fd);
13024235Smarkfen return (retval);
13034235Smarkfen }
13044235Smarkfen
13054235Smarkfen retval = spdsock_get_ext(exts, return_buf,
13064235Smarkfen return_buf->spd_msg_len, NULL, 0);
13074235Smarkfen /* ignore retval */
13084235Smarkfen
13094235Smarkfen if (exts[SPD_EXT_RULE]) {
13104235Smarkfen conf->ips_policy_index =
13114235Smarkfen ((struct spd_rule *)
13125120Smarkfen exts[SPD_EXT_RULE])->spd_rule_index;
13134235Smarkfen
13144235Smarkfen if (add_index(conf->ips_policy_index)) {
13154235Smarkfen free(return_buf);
13164235Smarkfen free(polmsg.iov_base);
13174235Smarkfen (void) close(fd);
13184235Smarkfen return (ENOMEM);
13194235Smarkfen }
13204235Smarkfen }
13214235Smarkfen
13224235Smarkfen free(return_buf);
13234235Smarkfen }
13244235Smarkfen }
13254235Smarkfen
13264235Smarkfen free(polmsg.iov_base);
13274235Smarkfen (void) close(fd);
13284235Smarkfen
13294235Smarkfen return (0);
13304235Smarkfen
13314235Smarkfen }
13324235Smarkfen
13334235Smarkfen int
main(int argc,char * argv[])13344235Smarkfen main(int argc, char *argv[])
13354235Smarkfen {
13364235Smarkfen int ret, flushret;
13374235Smarkfen int c;
13384235Smarkfen int index;
13394235Smarkfen boolean_t smf_managed;
13404235Smarkfen boolean_t just_check = B_FALSE;
134111278SMark.Fenwick@Sun.COM boolean_t replace_policy = B_FALSE;
13424235Smarkfen
13434235Smarkfen char *smf_warning = gettext(
13445120Smarkfen "\n\tIPsec policy should be managed using smf(5). Modifying\n"
13455120Smarkfen "\tthe IPsec policy from the command line while the 'policy'\n"
13465120Smarkfen "\tservice is enabled could result in an inconsistent\n"
13475120Smarkfen "\tsecurity policy.\n\n");
13484235Smarkfen
13494235Smarkfen flushret = 0;
135011278SMark.Fenwick@Sun.COM cmd = 0;
13514235Smarkfen
13524235Smarkfen (void) setlocale(LC_ALL, "");
13534235Smarkfen #if !defined(TEXT_DOMAIN)
13544235Smarkfen #define TEXT_DOMAIN "SYS_TEST"
13554235Smarkfen #endif
13564235Smarkfen (void) textdomain(TEXT_DOMAIN);
13574235Smarkfen
13584235Smarkfen openlog("ipsecconf", LOG_CONS, LOG_AUTH);
13594235Smarkfen
13604235Smarkfen /*
13614235Smarkfen * We don't immediately check for privilege here. This is done by IP
13624235Smarkfen * when we open /dev/ip below.
13634235Smarkfen */
13644235Smarkfen
13654235Smarkfen if (argc == 1) {
13664235Smarkfen cmd = IPSEC_CONF_VIEW;
13674235Smarkfen goto done;
13684235Smarkfen }
13694235Smarkfen my_fmri = getenv("SMF_FMRI");
13704235Smarkfen if (my_fmri == NULL)
13714235Smarkfen smf_managed = B_FALSE;
13724235Smarkfen else
13734235Smarkfen smf_managed = B_TRUE;
13744235Smarkfen
13754235Smarkfen while ((c = getopt(argc, argv, "nlfLFa:qd:r:i:c:")) != EOF) {
13764235Smarkfen switch (c) {
13774235Smarkfen case 'F':
13784235Smarkfen if (interface_name != NULL) {
13794235Smarkfen USAGE();
13804235Smarkfen EXIT_FATAL("interface name not required.");
13814235Smarkfen }
13824235Smarkfen /* Apply to all policy heads - global and tunnels. */
13834235Smarkfen interface_name = &all_polheads;
13844235Smarkfen /* FALLTHRU */
13854235Smarkfen case 'f':
138611278SMark.Fenwick@Sun.COM /*
138711278SMark.Fenwick@Sun.COM * The policy flush command can be specified with -a
138811278SMark.Fenwick@Sun.COM * to perform an atomic policy replace. It can't be
138911278SMark.Fenwick@Sun.COM * specified with any other flags.
139011278SMark.Fenwick@Sun.COM */
139111278SMark.Fenwick@Sun.COM if (cmd == IPSEC_CONF_ADD) {
139211278SMark.Fenwick@Sun.COM cmd = IPSEC_CONF_REPLACE;
139311278SMark.Fenwick@Sun.COM break;
139411278SMark.Fenwick@Sun.COM }
13954235Smarkfen if (cmd != 0) {
13964235Smarkfen USAGE();
13974235Smarkfen EXIT_FATAL("Multiple commands specified");
13984235Smarkfen }
13994235Smarkfen cmd = IPSEC_CONF_FLUSH;
14004235Smarkfen break;
14014235Smarkfen case 'L':
14024235Smarkfen if (interface_name != NULL) {
14034235Smarkfen USAGE();
14044235Smarkfen EXIT_FATAL("interface name not required.");
14054235Smarkfen }
14064235Smarkfen /* Apply to all policy heads - global and tunnels. */
14074235Smarkfen interface_name = &all_polheads;
14084235Smarkfen /* FALLTHRU */
14094235Smarkfen case 'l':
14104235Smarkfen /* Only one command at a time */
14114235Smarkfen if (cmd != 0) {
14124235Smarkfen USAGE();
14134235Smarkfen EXIT_FATAL("Multiple commands specified");
14144235Smarkfen }
14154235Smarkfen cmd = IPSEC_CONF_LIST;
14164235Smarkfen break;
14174235Smarkfen case 'c':
14184235Smarkfen just_check = B_TRUE;
14194235Smarkfen ipsecconf_qflag++;
14204235Smarkfen /* FALLTHRU */
14214235Smarkfen case 'a':
142211278SMark.Fenwick@Sun.COM if (cmd == IPSEC_CONF_FLUSH) {
142311278SMark.Fenwick@Sun.COM cmd = IPSEC_CONF_REPLACE;
142411278SMark.Fenwick@Sun.COM filename = optarg;
142511278SMark.Fenwick@Sun.COM break;
142611278SMark.Fenwick@Sun.COM }
14274235Smarkfen /* Only one command at a time, and no interface name */
14284235Smarkfen if (cmd != 0 || interface_name != NULL) {
14294235Smarkfen USAGE();
14304235Smarkfen EXIT_FATAL("Multiple commands or interface "
14314235Smarkfen "not required.");
14324235Smarkfen }
14334235Smarkfen cmd = IPSEC_CONF_ADD;
14344235Smarkfen filename = optarg;
14354235Smarkfen break;
14364235Smarkfen case 'd':
14374235Smarkfen /*
14384235Smarkfen * Only one command at a time. Interface name is
14394235Smarkfen * optional.
14404235Smarkfen */
14414235Smarkfen if (cmd != 0) {
14424235Smarkfen USAGE();
14434235Smarkfen EXIT_FATAL("Multiple commands specified");
14444235Smarkfen }
14454235Smarkfen cmd = IPSEC_CONF_DEL;
14464235Smarkfen index = parse_index(optarg, NULL);
14474235Smarkfen break;
14484235Smarkfen case 'n' :
14494235Smarkfen ipsecconf_nflag++;
14504235Smarkfen break;
14514235Smarkfen case 'q' :
14524235Smarkfen ipsecconf_qflag++;
14534235Smarkfen break;
14544235Smarkfen case 'r' :
14554235Smarkfen /* Only one command at a time, and no interface name */
14564235Smarkfen if (cmd != 0 || interface_name != NULL) {
14574235Smarkfen USAGE();
14584235Smarkfen EXIT_FATAL("Multiple commands or interface "
14594235Smarkfen "not required.");
14604235Smarkfen }
14614235Smarkfen cmd = IPSEC_CONF_SUB;
14624235Smarkfen filename = optarg;
14634235Smarkfen break;
14644235Smarkfen case 'i':
14654235Smarkfen if (interface_name != NULL) {
14664235Smarkfen EXIT_FATAL("Interface name already selected");
14674235Smarkfen }
14684235Smarkfen interface_name = optarg;
14694235Smarkfen /* Check for some cretin using the all-polheads name. */
14704235Smarkfen if (strlen(optarg) == 0) {
14714235Smarkfen USAGE();
14724235Smarkfen EXIT_FATAL("Invalid interface name.");
14734235Smarkfen }
14744235Smarkfen break;
14754235Smarkfen default :
14764235Smarkfen USAGE();
14774235Smarkfen EXIT_FATAL("Bad usage.");
14784235Smarkfen }
14794235Smarkfen }
14804235Smarkfen
14814235Smarkfen done:
14824235Smarkfen ret = 0;
14834235Smarkfen lfd = lock();
14844235Smarkfen
14854235Smarkfen /*
14864235Smarkfen * ADD, FLUSH, DELETE needs to do two operations.
14874235Smarkfen *
14884235Smarkfen * 1) Update/delete/empty the POLICY_CONF_FILE.
14894235Smarkfen * 2) Make an ioctl and tell IP to update its state.
14904235Smarkfen *
14914235Smarkfen * We already lock()ed so that only one instance of this
14924235Smarkfen * program runs. We also need to make sure that the above
14934235Smarkfen * operations are atomic i.e we don't want to update the file
14944235Smarkfen * and get interrupted before we could tell IP. To make it
14954235Smarkfen * atomic we block all the signals and restore them.
14964235Smarkfen */
14974235Smarkfen switch (cmd) {
14984235Smarkfen case IPSEC_CONF_LIST:
14994235Smarkfen fetch_algorithms();
15004235Smarkfen ret = ipsec_conf_list();
15014235Smarkfen break;
15024235Smarkfen case IPSEC_CONF_FLUSH:
15034235Smarkfen if ((ret = block_all_signals()) == -1) {
15044235Smarkfen break;
15054235Smarkfen }
15064235Smarkfen if (!smf_managed && !ipsecconf_qflag)
15074235Smarkfen (void) fprintf(stdout, "%s", smf_warning);
15084235Smarkfen ret = ipsec_conf_flush(SPD_ACTIVE);
15094235Smarkfen (void) restore_all_signals();
15104235Smarkfen break;
15114235Smarkfen case IPSEC_CONF_VIEW:
15124235Smarkfen if (interface_name != NULL) {
15134235Smarkfen EXIT_FATAL("Cannot view for one interface only.");
15144235Smarkfen }
15154235Smarkfen ret = ipsec_conf_view();
15164235Smarkfen break;
15174235Smarkfen case IPSEC_CONF_DEL:
15184235Smarkfen if (index == -1) {
15194235Smarkfen warnx(gettext("Invalid index"));
15204235Smarkfen ret = -1;
15214235Smarkfen break;
15224235Smarkfen }
15234235Smarkfen if ((ret = block_all_signals()) == -1) {
15244235Smarkfen break;
15254235Smarkfen }
15264235Smarkfen if (!smf_managed && !ipsecconf_qflag)
15274235Smarkfen (void) fprintf(stdout, "%s", smf_warning);
15284235Smarkfen ret = ipsec_conf_del(index, B_FALSE);
15294235Smarkfen (void) restore_all_signals();
15304235Smarkfen flushret = ipsec_conf_flush(SPD_STANDBY);
15314235Smarkfen break;
153211278SMark.Fenwick@Sun.COM case IPSEC_CONF_REPLACE:
153311278SMark.Fenwick@Sun.COM replace_policy = B_TRUE;
153411278SMark.Fenwick@Sun.COM /* FALLTHRU */
15354235Smarkfen case IPSEC_CONF_ADD:
15364235Smarkfen /*
15374235Smarkfen * The IPsec kernel modules should only be loaded
15384235Smarkfen * if there is a policy to install, for this
15394235Smarkfen * reason ipsec_conf_add() calls fetch_algorithms()
15404235Smarkfen * and ipsec_conf_flush() only when appropriate.
15414235Smarkfen */
15424235Smarkfen if ((ret = block_all_signals()) == -1) {
15434235Smarkfen break;
15444235Smarkfen }
15454235Smarkfen if (!smf_managed && !ipsecconf_qflag)
15464235Smarkfen (void) fprintf(stdout, "%s", smf_warning);
154711278SMark.Fenwick@Sun.COM ret = ipsec_conf_add(just_check, smf_managed, replace_policy);
15484235Smarkfen (void) restore_all_signals();
15494235Smarkfen break;
15504235Smarkfen case IPSEC_CONF_SUB:
15514235Smarkfen fetch_algorithms();
15524235Smarkfen if ((ret = block_all_signals()) == -1) {
15534235Smarkfen break;
15544235Smarkfen }
15554235Smarkfen if (!smf_managed && !ipsecconf_qflag)
15564235Smarkfen (void) fprintf(stdout, "%s", smf_warning);
15574235Smarkfen ret = ipsec_conf_sub();
15584235Smarkfen (void) restore_all_signals();
15594235Smarkfen flushret = ipsec_conf_flush(SPD_STANDBY);
15604235Smarkfen break;
15614235Smarkfen default :
15624235Smarkfen /* If no argument is given but a "-" */
15634235Smarkfen USAGE();
15644235Smarkfen EXIT_FATAL("Bad usage.");
15654235Smarkfen }
15664235Smarkfen
15674235Smarkfen (void) unlock(lfd);
15684235Smarkfen if (ret != 0 || flushret != 0)
15694235Smarkfen ret = 1;
15704235Smarkfen return (ret);
15714235Smarkfen }
15724235Smarkfen
15734235Smarkfen static void
perm_check(void)15744235Smarkfen perm_check(void)
15754235Smarkfen {
15764235Smarkfen if (errno == EACCES)
15774235Smarkfen EXIT_BADPERM("Insufficient privilege to run ipsecconf.");
15784235Smarkfen else
15794235Smarkfen warn(gettext("Cannot open lock file %s"), LOCK_FILE);
15804235Smarkfen
15814235Smarkfen EXIT_BADPERM(NULL);
15824235Smarkfen }
15834235Smarkfen
15844235Smarkfen static int
lock()15854235Smarkfen lock()
15864235Smarkfen {
15874235Smarkfen int fd;
15884235Smarkfen struct stat sbuf1;
15894235Smarkfen struct stat sbuf2;
15904235Smarkfen
15914235Smarkfen /*
15924235Smarkfen * Open the file with O_CREAT|O_EXCL. If it exists already, it
15934235Smarkfen * will fail. If it already exists, check whether it looks like
15944235Smarkfen * the one we created.
15954235Smarkfen */
15964235Smarkfen (void) umask(0077);
15974235Smarkfen if ((fd = open(LOCK_FILE, O_EXCL|O_CREAT|O_RDWR, S_IRUSR|S_IWUSR))
15984235Smarkfen == -1) {
15994235Smarkfen if (errno != EEXIST) {
16004235Smarkfen /* Some other problem. Will exit. */
16014235Smarkfen perm_check();
16024235Smarkfen }
16034235Smarkfen
16044235Smarkfen /*
16054235Smarkfen * open() returned an EEXIST error. We don't fail yet
16064235Smarkfen * as it could be a residual from a previous
16074235Smarkfen * execution.
16084235Smarkfen * File exists. make sure it is OK. We need to lstat()
16094235Smarkfen * as fstat() stats the file pointed to by the symbolic
16104235Smarkfen * link.
16114235Smarkfen */
16124235Smarkfen if (lstat(LOCK_FILE, &sbuf1) == -1) {
16134235Smarkfen EXIT_FATAL2("Cannot lstat lock file %s", LOCK_FILE);
16144235Smarkfen }
16154235Smarkfen /*
16164235Smarkfen * Check whether it is a regular file and not a symbolic
16174235Smarkfen * link. Its link count should be 1. The owner should be
16184235Smarkfen * root and the file should be empty.
16194235Smarkfen */
16204235Smarkfen if (!S_ISREG(sbuf1.st_mode) ||
16214235Smarkfen sbuf1.st_nlink != 1 ||
16224235Smarkfen sbuf1.st_uid != 0 ||
16234235Smarkfen sbuf1.st_size != 0) {
16244235Smarkfen EXIT_FATAL2("Bad lock file %s", LOCK_FILE);
16254235Smarkfen }
16264235Smarkfen if ((fd = open(LOCK_FILE, O_CREAT|O_RDWR,
16274235Smarkfen S_IRUSR|S_IWUSR)) == -1) {
16284235Smarkfen /* Will exit */
16294235Smarkfen perm_check();
16304235Smarkfen }
16314235Smarkfen /*
16324235Smarkfen * Check whether we opened the file that we lstat()ed.
16334235Smarkfen */
16344235Smarkfen if (fstat(fd, &sbuf2) == -1) {
16354235Smarkfen EXIT_FATAL2("Cannot lstat lock file %s", LOCK_FILE);
16364235Smarkfen }
16374235Smarkfen if (sbuf1.st_dev != sbuf2.st_dev ||
16384235Smarkfen sbuf1.st_ino != sbuf2.st_ino) {
16394235Smarkfen /* File changed after we did the lstat() above */
16404235Smarkfen EXIT_FATAL2("Bad lock file %s", LOCK_FILE);
16414235Smarkfen }
16424235Smarkfen }
16434235Smarkfen if (lockf(fd, F_LOCK, 0) == -1) {
16444235Smarkfen EXIT_FATAL2("Cannot lockf %s", LOCK_FILE);
16454235Smarkfen }
16464235Smarkfen return (fd);
16474235Smarkfen }
16484235Smarkfen
16494235Smarkfen static int
unlock(int fd)16504235Smarkfen unlock(int fd)
16514235Smarkfen {
16524235Smarkfen if (lockf(fd, F_ULOCK, 0) == -1) {
16534235Smarkfen warn("lockf");
16544235Smarkfen return (-1);
16554235Smarkfen }
16564235Smarkfen return (0);
16574235Smarkfen }
16584235Smarkfen
16594235Smarkfen /* send in TOK_* */
16604235Smarkfen static void
print_pattern_string(int type)16614235Smarkfen print_pattern_string(int type)
16624235Smarkfen {
16634235Smarkfen int j;
16644235Smarkfen
16654235Smarkfen for (j = 0; pattern_table[j].string != NULL; j++) {
16664235Smarkfen if (type == pattern_table[j].tok_val) {
16674235Smarkfen (void) printf("%s ", pattern_table[j].string);
16684235Smarkfen return;
16694235Smarkfen }
16704235Smarkfen }
16714235Smarkfen }
16724235Smarkfen
16734235Smarkfen static void
print_icmp_typecode(uint8_t type,uint8_t type_end,uint8_t code,uint8_t code_end)16744235Smarkfen print_icmp_typecode(uint8_t type, uint8_t type_end, uint8_t code,
16754235Smarkfen uint8_t code_end)
16764235Smarkfen {
16774235Smarkfen (void) printf("type %d", type);
16784235Smarkfen if (type_end != type)
16794235Smarkfen (void) printf("-%d ", type_end);
16804235Smarkfen else
16814235Smarkfen (void) printf(" ");
16824235Smarkfen if (code != 255) {
16834235Smarkfen (void) printf("code %d", code);
16844235Smarkfen if (code_end != code)
16854235Smarkfen (void) printf("-%d ", code_end);
16864235Smarkfen else
16874235Smarkfen (void) printf(" ");
16884235Smarkfen }
16894235Smarkfen }
16904235Smarkfen
16914235Smarkfen
16924235Smarkfen static void
print_spd_flags(uint32_t flags)16934235Smarkfen print_spd_flags(uint32_t flags)
16944235Smarkfen {
16954235Smarkfen flags &= (SPD_RULE_FLAG_INBOUND|SPD_RULE_FLAG_OUTBOUND);
16964235Smarkfen
16974235Smarkfen if (flags == SPD_RULE_FLAG_OUTBOUND)
16984235Smarkfen (void) printf("dir out ");
16994235Smarkfen else if (flags == SPD_RULE_FLAG_INBOUND)
17004235Smarkfen (void) printf("dir in ");
17014235Smarkfen else if (flags == (SPD_RULE_FLAG_INBOUND|SPD_RULE_FLAG_OUTBOUND))
17024235Smarkfen (void) printf("dir both ");
17034235Smarkfen }
17044235Smarkfen
17054235Smarkfen static void
print_bit_range(int min,int max)17064235Smarkfen print_bit_range(int min, int max)
17074235Smarkfen {
17084235Smarkfen if (min != 0 || (max != 0 && max != SPD_MAX_MAXBITS)) {
17094235Smarkfen (void) printf("(");
17104235Smarkfen if (min != 0)
17114235Smarkfen (void) printf("%d", min);
17124235Smarkfen if (min != 0 && max != 0 && min != max) {
17134235Smarkfen (void) printf("..");
17144235Smarkfen if (max != 0 && max != SPD_MAX_MAXBITS)
17154235Smarkfen (void) printf("%d", max);
17164235Smarkfen }
17174235Smarkfen (void) printf(")");
17184235Smarkfen }
17194235Smarkfen }
17204235Smarkfen
17214235Smarkfen static void
print_alg(const char * tag,algreq_t * algreq,int proto_num)17224235Smarkfen print_alg(const char *tag, algreq_t *algreq, int proto_num)
17234235Smarkfen {
17244235Smarkfen int min = algreq->alg_minbits;
17254235Smarkfen int max = algreq->alg_maxbits;
17264235Smarkfen struct ipsecalgent *alg;
17274235Smarkfen
17284235Smarkfen /*
17294235Smarkfen * This function won't be called with alg_id == 0, so we don't
17304235Smarkfen * have to worry about ANY vs. NONE here.
17314235Smarkfen */
17324235Smarkfen
17334235Smarkfen (void) printf("%s ", tag);
17344235Smarkfen
17354235Smarkfen alg = getipsecalgbynum(algreq->alg_id, proto_num, NULL);
17364235Smarkfen if (alg == NULL) {
17374235Smarkfen (void) printf("%d", algreq->alg_id);
17384235Smarkfen } else {
17394235Smarkfen (void) printf("%s", alg->a_names[0]);
17404235Smarkfen freeipsecalgent(alg);
17414235Smarkfen }
17424235Smarkfen
17434235Smarkfen print_bit_range(min, max);
17444235Smarkfen (void) printf(" ");
17454235Smarkfen }
17464235Smarkfen
17474235Smarkfen static void
print_ulp(uint8_t proto)17484235Smarkfen print_ulp(uint8_t proto)
17494235Smarkfen {
17504235Smarkfen struct protoent *pe;
17514235Smarkfen
17524235Smarkfen if (proto == 0)
17534235Smarkfen return;
17544235Smarkfen
17554235Smarkfen print_pattern_string(TOK_ulp);
17564235Smarkfen pe = NULL;
17574235Smarkfen if (!ipsecconf_nflag) {
17584235Smarkfen pe = getprotobynumber(proto);
17594235Smarkfen }
17604235Smarkfen if (pe != NULL)
17614235Smarkfen (void) printf("%s ", pe->p_name);
17624235Smarkfen else
17634235Smarkfen (void) printf("%d ", proto);
17644235Smarkfen }
17654235Smarkfen
17664235Smarkfen /* needs to do ranges */
17674235Smarkfen static void
print_port(uint16_t in_port,int type)17684235Smarkfen print_port(uint16_t in_port, int type)
17694235Smarkfen {
17704235Smarkfen in_port_t port = ntohs(in_port);
17714235Smarkfen struct servent *sp;
17724235Smarkfen
17734235Smarkfen if (port == 0)
17744235Smarkfen return;
17754235Smarkfen
17764235Smarkfen print_pattern_string(type);
17774235Smarkfen sp = NULL;
17784235Smarkfen if (!ipsecconf_nflag)
17794235Smarkfen sp = getservbyport(port, NULL);
17804235Smarkfen
17814235Smarkfen if (sp != NULL)
17824235Smarkfen (void) printf("%s ", sp->s_name);
17834235Smarkfen else
17844235Smarkfen (void) printf("%d ", port);
17854235Smarkfen }
17864235Smarkfen
17874235Smarkfen /*
17884235Smarkfen * Print the address, given as "raw" input via the void pointer.
17894235Smarkfen */
17904235Smarkfen static void
print_raw_address(void * input,boolean_t isv4)17914235Smarkfen print_raw_address(void *input, boolean_t isv4)
17924235Smarkfen {
17934235Smarkfen char *cp;
17944235Smarkfen struct hostent *hp;
17954235Smarkfen char domain[MAXHOSTNAMELEN + 1];
17964235Smarkfen struct in_addr addr;
17974235Smarkfen struct in6_addr addr6;
17984235Smarkfen char abuf[INET6_ADDRSTRLEN];
17994235Smarkfen int error_num;
18004235Smarkfen struct in6_addr in_addr;
18014235Smarkfen uchar_t *addr_ptr;
18024235Smarkfen sa_family_t af;
18034235Smarkfen int addr_len;
18044235Smarkfen
18054235Smarkfen if (isv4) {
18064235Smarkfen af = AF_INET;
18074235Smarkfen (void) memcpy(&V4_PART_OF_V6(in_addr), input, 4);
18084235Smarkfen /* we don't print unspecified addresses */
18094235Smarkfen IN6_V4MAPPED_TO_INADDR(&in_addr, &addr);
18104235Smarkfen if (addr.s_addr == INADDR_ANY)
18114235Smarkfen return;
18124235Smarkfen addr_ptr = (uchar_t *)&addr.s_addr;
18134235Smarkfen addr_len = IPV4_ADDR_LEN;
18144235Smarkfen } else {
18154235Smarkfen (void) memcpy(&addr6, input, 16);
18164235Smarkfen af = AF_INET6;
18174235Smarkfen /* we don't print unspecified addresses */
18184235Smarkfen if (IN6_IS_ADDR_UNSPECIFIED(&addr6))
18194235Smarkfen return;
18204235Smarkfen addr_ptr = (uchar_t *)&addr6.s6_addr;
18214235Smarkfen addr_len = sizeof (struct in6_addr);
18224235Smarkfen }
18234235Smarkfen
18244235Smarkfen cp = NULL;
18254235Smarkfen if (!ipsecconf_nflag) {
18264235Smarkfen if (sysinfo(SI_HOSTNAME, domain, MAXHOSTNAMELEN) != -1 &&
18275120Smarkfen (cp = strchr(domain, '.')) != NULL) {
18284235Smarkfen (void) strlcpy(domain, cp + 1, sizeof (domain));
18294235Smarkfen } else {
18304235Smarkfen domain[0] = 0;
18314235Smarkfen }
18327174Spwernau cp = NULL;
18334235Smarkfen hp = getipnodebyaddr(addr_ptr, addr_len, af, &error_num);
18344235Smarkfen if (hp) {
18354235Smarkfen if ((cp = strchr(hp->h_name, '.')) != 0 &&
18365120Smarkfen strcasecmp(cp + 1, domain) == 0)
18374235Smarkfen *cp = 0;
18384235Smarkfen cp = hp->h_name;
18394235Smarkfen }
18404235Smarkfen }
18414235Smarkfen
18424235Smarkfen if (cp) {
18434235Smarkfen (void) printf("%s", cp);
18444235Smarkfen } else {
18454235Smarkfen (void) printf("%s", inet_ntop(af, addr_ptr, abuf,
18464235Smarkfen INET6_ADDRSTRLEN));
18474235Smarkfen }
18484235Smarkfen }
18494235Smarkfen
18504235Smarkfen /*
18514235Smarkfen * Get the next SPD_DUMP message from the PF_POLICY socket. A single
18524235Smarkfen * read may contain multiple messages. This function uses static buffers,
18534235Smarkfen * and is therefore non-reentrant, so if you lift it for an MT application,
18544235Smarkfen * be careful.
18554235Smarkfen *
18564235Smarkfen * Return NULL if there's an error.
18574235Smarkfen */
18584235Smarkfen static spd_msg_t *
ipsec_read_dump(int pfd)18594235Smarkfen ipsec_read_dump(int pfd)
18604235Smarkfen {
18614235Smarkfen static uint64_t buf[SADB_8TO64(CBUF_LEN)];
18624235Smarkfen static uint64_t *offset;
18634235Smarkfen static int len; /* In uint64_t units. */
18644235Smarkfen spd_msg_t *retval;
18654235Smarkfen
18664235Smarkfen /* Assume offset and len are initialized to NULL and 0. */
18674235Smarkfen
18684235Smarkfen if ((offset - len == buf) || (offset == NULL)) {
18694235Smarkfen /* read a new block from the socket. */
18704235Smarkfen len = read(pfd, &buf, sizeof (buf));
18714235Smarkfen if (len == -1) {
18724235Smarkfen warn(gettext("rule dump: bad read"));
18734235Smarkfen return (NULL);
18744235Smarkfen }
18754235Smarkfen offset = buf;
18764235Smarkfen len = SADB_8TO64(len);
18774235Smarkfen } /* Else I still have more messages from a previous read. */
18784235Smarkfen
18794235Smarkfen retval = (spd_msg_t *)offset;
18804235Smarkfen offset += retval->spd_msg_len;
18814235Smarkfen if (offset > buf + len) {
18824235Smarkfen warnx(gettext("dump read: message corruption,"
18834235Smarkfen " %d len exceeds %d boundary."),
18844235Smarkfen SADB_64TO8((uintptr_t)(offset - buf)),
188512131Sdanmcd@opensolaris.org SADB_64TO8((uintptr_t)(len)));
18864235Smarkfen return (NULL);
18874235Smarkfen }
18884235Smarkfen
18894235Smarkfen return (retval);
18904235Smarkfen }
18914235Smarkfen
18924235Smarkfen /*
18934235Smarkfen * returns 0 on success
18944235Smarkfen * -1 on read error
18954235Smarkfen * >0 on invalid returned message
18964235Smarkfen */
18974235Smarkfen
18984235Smarkfen static int
ipsec_conf_list(void)18994235Smarkfen ipsec_conf_list(void)
19004235Smarkfen {
19014235Smarkfen int ret;
19024235Smarkfen int pfd;
19034235Smarkfen struct spd_msg *msg;
19044235Smarkfen int cnt;
19054235Smarkfen spd_msg_t *rmsg;
19064235Smarkfen spd_ext_t *exts[SPD_EXT_MAX+1];
19074235Smarkfen /*
19084235Smarkfen * Add an extra 8 bytes of space (+1 uint64_t) to avoid truncation
19094235Smarkfen * issues.
19104235Smarkfen */
19114235Smarkfen uint64_t buffer[
19124235Smarkfen SPD_8TO64(sizeof (*msg) + sizeof (spd_if_t) + LIFNAMSIZ) + 1];
19134235Smarkfen
19144235Smarkfen pfd = get_pf_pol_socket();
19154235Smarkfen
19164235Smarkfen if (pfd == -1) {
19174235Smarkfen warnx(gettext("Error getting list of policies from kernel"));
19184235Smarkfen return (-1);
19194235Smarkfen }
19204235Smarkfen
19214235Smarkfen (void) memset(buffer, 0, sizeof (buffer));
19224235Smarkfen msg = (struct spd_msg *)buffer;
19234235Smarkfen msg->spd_msg_version = PF_POLICY_V1;
19244235Smarkfen msg->spd_msg_type = SPD_DUMP;
19254235Smarkfen msg->spd_msg_len = SPD_8TO64(sizeof (*msg));
19264235Smarkfen
19274235Smarkfen msg->spd_msg_len += attach_tunname((spd_if_t *)(msg + 1));
19284235Smarkfen
19294235Smarkfen cnt = write(pfd, msg, SPD_64TO8(msg->spd_msg_len));
19304235Smarkfen
19314235Smarkfen if (cnt < 0) {
19324235Smarkfen warn(gettext("dump: invalid write() return"));
19334235Smarkfen (void) close(pfd);
19344235Smarkfen return (-1);
19354235Smarkfen }
19364235Smarkfen
19374235Smarkfen rmsg = ipsec_read_dump(pfd);
19384235Smarkfen
19394235Smarkfen if (rmsg == NULL || rmsg->spd_msg_errno != 0) {
19404235Smarkfen warnx("%s: %s", gettext("ruleset dump failed"),
19414235Smarkfen (rmsg == NULL ?
19425120Smarkfen gettext("read error") :
19435120Smarkfen sys_error_message(rmsg->spd_msg_errno)));
19444235Smarkfen (void) close(pfd);
19454235Smarkfen return (-1);
19464235Smarkfen }
19474235Smarkfen
19484235Smarkfen
19494235Smarkfen for (;;) {
19504235Smarkfen /* read rule */
19514235Smarkfen rmsg = ipsec_read_dump(pfd);
19524235Smarkfen
19534235Smarkfen if (rmsg == NULL) {
19544235Smarkfen (void) close(pfd);
19554235Smarkfen return (-1);
19564235Smarkfen }
19574235Smarkfen
19584235Smarkfen if (rmsg->spd_msg_errno != 0) {
19594235Smarkfen warnx("%s: %s", gettext("dump read: bad message"),
19604235Smarkfen sys_error_message(rmsg->spd_msg_errno));
19614235Smarkfen (void) close(pfd);
19624235Smarkfen return (-1);
19634235Smarkfen }
19644235Smarkfen
19654235Smarkfen ret = spdsock_get_ext(exts, rmsg, rmsg->spd_msg_len,
19664235Smarkfen spdsock_diag_buf, SPDSOCK_DIAG_BUF_LEN);
19674235Smarkfen if (ret != 0) {
19684235Smarkfen if (strlen(spdsock_diag_buf) != 0)
19694235Smarkfen warnx(spdsock_diag_buf);
19704235Smarkfen warnx("%s: %s", gettext("dump read: bad message"),
19714235Smarkfen sys_error_message(rmsg->spd_msg_errno));
19724235Smarkfen (void) close(pfd);
19734235Smarkfen return (ret);
19744235Smarkfen }
19754235Smarkfen
19764235Smarkfen /*
19774235Smarkfen * End of dump..
19784235Smarkfen */
19794235Smarkfen if (exts[SPD_EXT_RULESET] != NULL)
19804235Smarkfen break; /* and return 0. */
19814235Smarkfen
19824235Smarkfen print_pfpol_msg(rmsg);
19834235Smarkfen }
19844235Smarkfen
19854235Smarkfen (void) close(pfd);
19864235Smarkfen return (0);
19874235Smarkfen }
19884235Smarkfen
19894235Smarkfen static void
print_iap(ips_act_props_t * iap)19904235Smarkfen print_iap(ips_act_props_t *iap)
19914235Smarkfen {
19924235Smarkfen
19934235Smarkfen /* action */
19944235Smarkfen switch (iap->iap_action) {
19954235Smarkfen case SPD_ACTTYPE_PASS:
19964235Smarkfen (void) printf("pass ");
19974235Smarkfen break;
19984235Smarkfen case SPD_ACTTYPE_DROP:
19994235Smarkfen (void) printf("drop ");
20004235Smarkfen break;
20014235Smarkfen case SPD_ACTTYPE_IPSEC:
20024235Smarkfen (void) printf("ipsec ");
20034235Smarkfen break;
20044235Smarkfen }
20054235Smarkfen
20064235Smarkfen /* properties */
20074235Smarkfen (void) printf("%c ", CURL_BEGIN);
20084235Smarkfen if (iap->iap_action == SPD_ACTTYPE_IPSEC) {
20094235Smarkfen if (iap->iap_attr & SPD_APPLY_AH &&
20104235Smarkfen iap->iap_aauth.alg_id != 0)
20114235Smarkfen print_alg("auth_algs", &iap->iap_aauth,
20124235Smarkfen IPSEC_PROTO_AH);
20134235Smarkfen
20144235Smarkfen if (iap->iap_attr & SPD_APPLY_ESP) {
20154235Smarkfen print_alg("encr_algs", &iap->iap_eencr,
20164235Smarkfen IPSEC_PROTO_ESP);
20174235Smarkfen if (iap->iap_eauth.alg_id != 0)
20184235Smarkfen print_alg("encr_auth_algs", &iap->iap_eauth,
20194235Smarkfen IPSEC_PROTO_AH);
20204235Smarkfen }
20214235Smarkfen if (iap->iap_attr & SPD_APPLY_UNIQUE)
20224235Smarkfen (void) printf("sa unique ");
20234235Smarkfen else
20244235Smarkfen (void) printf("sa shared ");
20254235Smarkfen }
20264235Smarkfen (void) printf("%c ", CURL_END);
20274235Smarkfen }
20284235Smarkfen
20294235Smarkfen
20304235Smarkfen static void
print_pfpol_msg(spd_msg_t * msg)20314235Smarkfen print_pfpol_msg(spd_msg_t *msg)
20324235Smarkfen {
20334235Smarkfen spd_ext_t *exts[SPD_EXT_MAX+1];
20344235Smarkfen spd_address_t *spd_address;
20354235Smarkfen struct spd_rule *spd_rule;
20364235Smarkfen struct spd_proto *spd_proto;
20374235Smarkfen struct spd_portrange *spd_portrange;
20384235Smarkfen struct spd_ext_actions *spd_ext_actions;
20394235Smarkfen struct spd_typecode *spd_typecode;
20404235Smarkfen struct spd_attribute *app;
20414235Smarkfen spd_if_t *spd_if;
20424235Smarkfen uint32_t rv;
20434235Smarkfen uint16_t act_count;
20444235Smarkfen
20454235Smarkfen rv = spdsock_get_ext(exts, msg, msg->spd_msg_len, spdsock_diag_buf,
20464235Smarkfen SPDSOCK_DIAG_BUF_LEN);
20474235Smarkfen
20484235Smarkfen if (rv == KGE_OK && exts[SPD_EXT_RULE] != NULL) {
20494235Smarkfen spd_if = (spd_if_t *)exts[SPD_EXT_TUN_NAME];
20504235Smarkfen spd_rule = (struct spd_rule *)exts[SPD_EXT_RULE];
20514235Smarkfen if (spd_if == NULL) {
20524235Smarkfen (void) printf("%s %lld\n", INDEX_TAG,
20534235Smarkfen spd_rule->spd_rule_index);
20544235Smarkfen } else {
20554235Smarkfen (void) printf("%s %s,%lld\n", INDEX_TAG,
20564235Smarkfen (char *)spd_if->spd_if_name,
20574235Smarkfen spd_rule->spd_rule_index);
20584235Smarkfen }
20594235Smarkfen } else {
20604235Smarkfen if (strlen(spdsock_diag_buf) != 0)
20614235Smarkfen warnx(spdsock_diag_buf);
20624235Smarkfen warnx(gettext("print_pfpol_msg: malformed PF_POLICY message."));
20634235Smarkfen return;
20644235Smarkfen }
20654235Smarkfen
20664235Smarkfen (void) printf("%c ", CURL_BEGIN);
20674235Smarkfen
20684235Smarkfen if (spd_if != NULL) {
20694235Smarkfen (void) printf("tunnel %s negotiate %s ",
20704235Smarkfen (char *)spd_if->spd_if_name,
20714235Smarkfen (spd_rule->spd_rule_flags & SPD_RULE_FLAG_TUNNEL) ?
20724235Smarkfen "tunnel" : "transport");
20734235Smarkfen }
20744235Smarkfen
20754235Smarkfen if (exts[SPD_EXT_PROTO] != NULL) {
20764235Smarkfen spd_proto = (struct spd_proto *)exts[SPD_EXT_PROTO];
20774235Smarkfen print_ulp(spd_proto->spd_proto_number);
20784235Smarkfen }
20794235Smarkfen
20804235Smarkfen if (exts[SPD_EXT_LCLADDR] != NULL) {
20814235Smarkfen spd_address = (spd_address_t *)exts[SPD_EXT_LCLADDR];
20824235Smarkfen
20834235Smarkfen (void) printf("laddr ");
20844235Smarkfen print_raw_address((spd_address + 1),
20854235Smarkfen (spd_address->spd_address_len == 2));
20864235Smarkfen (void) printf("/%d ", spd_address->spd_address_prefixlen);
20874235Smarkfen }
20884235Smarkfen
20894235Smarkfen if (exts[SPD_EXT_LCLPORT] != NULL) {
20904235Smarkfen spd_portrange = (struct spd_portrange *)exts[SPD_EXT_LCLPORT];
20914235Smarkfen if (spd_portrange->spd_ports_minport != 0) {
20924235Smarkfen print_port(spd_portrange->spd_ports_minport,
20934235Smarkfen TOK_lport);
20944235Smarkfen }
20954235Smarkfen }
20964235Smarkfen
20974235Smarkfen
20984235Smarkfen if (exts[SPD_EXT_REMADDR] != NULL) {
20994235Smarkfen spd_address = (spd_address_t *)exts[SPD_EXT_REMADDR];
21004235Smarkfen
21014235Smarkfen (void) printf("raddr ");
21024235Smarkfen print_raw_address((spd_address + 1),
21034235Smarkfen (spd_address->spd_address_len == 2));
21044235Smarkfen (void) printf("/%d ", spd_address->spd_address_prefixlen);
21054235Smarkfen }
21064235Smarkfen
21074235Smarkfen if (exts[SPD_EXT_REMPORT] != NULL) {
21084235Smarkfen spd_portrange =
21095120Smarkfen (struct spd_portrange *)exts[SPD_EXT_REMPORT];
21104235Smarkfen if (spd_portrange->spd_ports_minport != 0) {
21114235Smarkfen print_port(
21125120Smarkfen spd_portrange->spd_ports_minport, TOK_rport);
21134235Smarkfen }
21144235Smarkfen }
21154235Smarkfen
21164235Smarkfen if (exts[SPD_EXT_ICMP_TYPECODE] != NULL) {
21174235Smarkfen spd_typecode =
21184235Smarkfen (struct spd_typecode *)exts[SPD_EXT_ICMP_TYPECODE];
21194235Smarkfen print_icmp_typecode(spd_typecode->spd_typecode_type,
21204235Smarkfen spd_typecode->spd_typecode_type_end,
21214235Smarkfen spd_typecode->spd_typecode_code,
21224235Smarkfen spd_typecode->spd_typecode_code_end);
21234235Smarkfen }
21244235Smarkfen
21254235Smarkfen if (exts[SPD_EXT_RULE] != NULL) {
21264235Smarkfen spd_rule = (struct spd_rule *)exts[SPD_EXT_RULE];
21274235Smarkfen print_spd_flags(spd_rule->spd_rule_flags);
21284235Smarkfen }
21294235Smarkfen
21304235Smarkfen
21314235Smarkfen (void) printf("%c ", CURL_END);
21324235Smarkfen
21334235Smarkfen if (exts[SPD_EXT_ACTION] != NULL) {
21344235Smarkfen ips_act_props_t iap;
21354235Smarkfen int or_needed = 0;
21364235Smarkfen
21374235Smarkfen (void) memset(&iap, 0, sizeof (iap));
21384235Smarkfen spd_ext_actions =
21394235Smarkfen (struct spd_ext_actions *)exts[SPD_EXT_ACTION];
21404235Smarkfen app = (struct spd_attribute *)(spd_ext_actions + 1);
21414235Smarkfen
21424235Smarkfen for (act_count = 0;
21434235Smarkfen act_count < spd_ext_actions->spd_actions_len -1;
21445120Smarkfen act_count++) {
21454235Smarkfen
21464235Smarkfen switch (app->spd_attr_tag) {
21474235Smarkfen
21484235Smarkfen case SPD_ATTR_NOP:
21494235Smarkfen break;
21504235Smarkfen
21514235Smarkfen case SPD_ATTR_END:
21524235Smarkfen /* print */
21534235Smarkfen if (or_needed) {
21544235Smarkfen (void) printf("or ");
21554235Smarkfen } else {
21564235Smarkfen or_needed = 1;
21574235Smarkfen }
21584235Smarkfen print_iap(&iap);
21594235Smarkfen break;
21604235Smarkfen
21614235Smarkfen case SPD_ATTR_EMPTY:
21624235Smarkfen /* clear */
21634235Smarkfen (void) memset(&iap, 0, sizeof (iap));
21644235Smarkfen break;
21654235Smarkfen
21664235Smarkfen case SPD_ATTR_NEXT:
21674235Smarkfen /* print */
21684235Smarkfen if (or_needed) {
21694235Smarkfen (void) printf("or ");
21704235Smarkfen } else {
21714235Smarkfen or_needed = 1;
21724235Smarkfen }
21734235Smarkfen
21744235Smarkfen print_iap(&iap);
21754235Smarkfen break;
21764235Smarkfen
21774235Smarkfen case SPD_ATTR_TYPE:
21784235Smarkfen iap.iap_action = app->spd_attr_value;
21794235Smarkfen break;
21804235Smarkfen
21814235Smarkfen case SPD_ATTR_FLAGS:
21824235Smarkfen iap.iap_attr = app->spd_attr_value;
21834235Smarkfen break;
21844235Smarkfen
21854235Smarkfen case SPD_ATTR_AH_AUTH:
21864235Smarkfen iap.iap_aauth.alg_id = app->spd_attr_value;
21874235Smarkfen break;
21884235Smarkfen
21894235Smarkfen case SPD_ATTR_ESP_ENCR:
21904235Smarkfen iap.iap_eencr.alg_id = app->spd_attr_value;
21914235Smarkfen break;
21924235Smarkfen
21934235Smarkfen case SPD_ATTR_ESP_AUTH:
21944235Smarkfen iap.iap_eauth.alg_id = app->spd_attr_value;
21954235Smarkfen break;
21964235Smarkfen
21974235Smarkfen case SPD_ATTR_ENCR_MINBITS:
21984235Smarkfen iap.iap_eencr.alg_minbits = app->spd_attr_value;
21994235Smarkfen break;
22004235Smarkfen
22014235Smarkfen case SPD_ATTR_ENCR_MAXBITS:
22024235Smarkfen iap.iap_eencr.alg_maxbits = app->spd_attr_value;
22034235Smarkfen break;
22044235Smarkfen
22054235Smarkfen case SPD_ATTR_AH_MINBITS:
22064235Smarkfen iap.iap_aauth.alg_minbits = app->spd_attr_value;
22074235Smarkfen break;
22084235Smarkfen
22094235Smarkfen case SPD_ATTR_AH_MAXBITS:
22104235Smarkfen iap.iap_aauth.alg_maxbits = app->spd_attr_value;
22114235Smarkfen break;
22124235Smarkfen
22134235Smarkfen case SPD_ATTR_ESPA_MINBITS:
22144235Smarkfen iap.iap_eauth.alg_minbits = app->spd_attr_value;
22154235Smarkfen break;
22164235Smarkfen
22174235Smarkfen case SPD_ATTR_ESPA_MAXBITS:
22184235Smarkfen iap.iap_eauth.alg_maxbits = app->spd_attr_value;
22194235Smarkfen break;
22204235Smarkfen
22214235Smarkfen case SPD_ATTR_LIFE_SOFT_TIME:
22224235Smarkfen case SPD_ATTR_LIFE_HARD_TIME:
22234235Smarkfen case SPD_ATTR_LIFE_SOFT_BYTES:
22244235Smarkfen case SPD_ATTR_LIFE_HARD_BYTES:
22254235Smarkfen default:
22264235Smarkfen (void) printf("\tattr %d: %X-%d\n",
22274235Smarkfen act_count,
22284235Smarkfen app->spd_attr_tag,
22294235Smarkfen app->spd_attr_value);
22304235Smarkfen break;
22314235Smarkfen }
22324235Smarkfen app++;
22334235Smarkfen }
22344235Smarkfen }
22354235Smarkfen
22364235Smarkfen (void) printf("\n");
22374235Smarkfen }
22384235Smarkfen
22394235Smarkfen #ifdef DEBUG_HEAVY
22404235Smarkfen static void
pfpol_msg_dump(spd_msg_t * msg,char * tag)22414235Smarkfen pfpol_msg_dump(spd_msg_t *msg, char *tag)
22424235Smarkfen {
22434235Smarkfen spd_ext_t *exts[SPD_EXT_MAX+1];
22444235Smarkfen uint32_t i;
22454235Smarkfen spd_address_t *spd_address;
22464235Smarkfen struct spd_rule *spd_rule;
22474235Smarkfen struct spd_proto *spd_proto;
22484235Smarkfen struct spd_portrange *spd_portrange;
22494235Smarkfen struct spd_typecode *spd_typecode;
22504235Smarkfen struct spd_ext_actions *spd_ext_actions;
22514235Smarkfen struct spd_attribute *app;
22524235Smarkfen spd_if_t *spd_if;
22534235Smarkfen char abuf[INET6_ADDRSTRLEN];
22544235Smarkfen uint32_t rv;
22554235Smarkfen uint16_t act_count;
22564235Smarkfen
22574235Smarkfen rv = spdsock_get_ext(exts, msg, msg->spd_msg_len, NULL, 0);
22584235Smarkfen if (rv != KGE_OK)
22594235Smarkfen return;
22604235Smarkfen
22614235Smarkfen (void) printf("===========%s==============\n", tag);
22624235Smarkfen (void) printf("pfpol_msg_dump %d\n-------------------\n", rv);
22634235Smarkfen
22644235Smarkfen (void) printf("spd_msg_version:%d\n", msg->spd_msg_version);
22654235Smarkfen (void) printf("spd_msg_type:%d\n", msg->spd_msg_type);
22664235Smarkfen (void) printf("spd_msg_errno:%d\n", msg->spd_msg_errno);
22674235Smarkfen (void) printf("spd_msg_spdid:%d\n", msg->spd_msg_spdid);
22684235Smarkfen (void) printf("spd_msg_len:%d\n", msg->spd_msg_len);
22694235Smarkfen (void) printf("spd_msg_diagnostic:%d\n", msg->spd_msg_diagnostic);
22704235Smarkfen (void) printf("spd_msg_seq:%d\n", msg->spd_msg_seq);
22714235Smarkfen (void) printf("spd_msg_pid:%d\n", msg->spd_msg_pid);
22724235Smarkfen
22734235Smarkfen for (i = 1; i <= SPD_EXT_MAX; i++) {
22744235Smarkfen if (exts[i] == NULL) {
22754235Smarkfen printf("skipped %d\n", i);
22764235Smarkfen continue;
22774235Smarkfen }
22784235Smarkfen
22794235Smarkfen switch (i) {
22804235Smarkfen case SPD_EXT_TUN_NAME:
22814235Smarkfen spd_if = (spd_if_t *)exts[i];
22824235Smarkfen (void) printf("spd_if = %s\n", spd_if->spd_if_name);
22834235Smarkfen break;
22844235Smarkfen
22854235Smarkfen case SPD_EXT_ICMP_TYPECODE:
22864235Smarkfen spd_typecode = (struct spd_typecode *)exts[i];
22874235Smarkfen (void) printf("icmp type %d-%d code %d-%d\n",
22884235Smarkfen spd_typecode->spd_typecode_type,
22894235Smarkfen spd_typecode->spd_typecode_type_end,
22904235Smarkfen spd_typecode->spd_typecode_code,
22914235Smarkfen spd_typecode->spd_typecode_code_end);
22924235Smarkfen break;
22934235Smarkfen
22944235Smarkfen case SPD_EXT_LCLPORT:
22954235Smarkfen spd_portrange = (struct spd_portrange *)exts[i];
22964235Smarkfen (void) printf("local ports %d-%d\n",
22974235Smarkfen spd_portrange->spd_ports_minport,
22984235Smarkfen spd_portrange->spd_ports_maxport);
22994235Smarkfen
23004235Smarkfen break;
23014235Smarkfen
23024235Smarkfen case SPD_EXT_REMPORT:
23034235Smarkfen spd_portrange = (struct spd_portrange *)exts[i];
23044235Smarkfen (void) printf("remote ports %d-%d\n",
23054235Smarkfen spd_portrange->spd_ports_minport,
23064235Smarkfen spd_portrange->spd_ports_maxport);
23074235Smarkfen
23084235Smarkfen break;
23094235Smarkfen
23104235Smarkfen case SPD_EXT_PROTO:
23114235Smarkfen spd_proto = (struct spd_proto *)exts[i];
23124235Smarkfen (void) printf("proto:spd_proto_exttype %d\n",
23134235Smarkfen spd_proto->spd_proto_exttype);
23144235Smarkfen (void) printf("proto:spd_proto_number %d\n",
23154235Smarkfen spd_proto->spd_proto_number);
23164235Smarkfen break;
23174235Smarkfen
23184235Smarkfen case SPD_EXT_LCLADDR:
23194235Smarkfen case SPD_EXT_REMADDR:
23204235Smarkfen spd_address = (spd_address_t *)exts[i];
23214235Smarkfen if (i == SPD_EXT_LCLADDR)
23224235Smarkfen (void) printf("local addr ");
23234235Smarkfen else
23244235Smarkfen (void) printf("remote addr ");
23254235Smarkfen
23264235Smarkfen
23274235Smarkfen (void) printf("%s\n",
23284235Smarkfen inet_ntop(spd_address->spd_address_af,
23295120Smarkfen (void *) (spd_address +1), abuf,
23305120Smarkfen INET6_ADDRSTRLEN));
23314235Smarkfen
23324235Smarkfen (void) printf("prefixlen: %d\n",
23334235Smarkfen spd_address->spd_address_prefixlen);
23344235Smarkfen break;
23354235Smarkfen
23364235Smarkfen case SPD_EXT_ACTION:
23374235Smarkfen spd_ext_actions = (struct spd_ext_actions *)exts[i];
23384235Smarkfen (void) printf("spd_ext_action\n");
23394235Smarkfen (void) printf("spd_actions_count %d\n",
23404235Smarkfen spd_ext_actions->spd_actions_count);
23414235Smarkfen app = (struct spd_attribute *)(spd_ext_actions + 1);
23424235Smarkfen
23434235Smarkfen for (act_count = 0;
23444235Smarkfen act_count < spd_ext_actions->spd_actions_len -1;
23454235Smarkfen act_count++) {
23464235Smarkfen (void) printf("\tattr %d: %X-%d\n", act_count,
23474235Smarkfen app->spd_attr_tag, app->spd_attr_value);
23484235Smarkfen app++;
23494235Smarkfen }
23504235Smarkfen
23514235Smarkfen break;
23524235Smarkfen
23534235Smarkfen case SPD_EXT_RULE:
23544235Smarkfen spd_rule = (struct spd_rule *)exts[i];
23554235Smarkfen (void) printf("spd_rule_priority: 0x%x\n",
23564235Smarkfen spd_rule->spd_rule_priority);
23574235Smarkfen (void) printf("spd_rule_flags: %d\n",
23584235Smarkfen spd_rule->spd_rule_flags);
23594235Smarkfen break;
23604235Smarkfen
23614235Smarkfen case SPD_EXT_RULESET:
23624235Smarkfen (void) printf("spd_ext_ruleset\n");
23634235Smarkfen break;
23644235Smarkfen default:
23654235Smarkfen (void) printf("default\n");
23664235Smarkfen break;
23674235Smarkfen }
23684235Smarkfen }
23694235Smarkfen
23704235Smarkfen (void) printf("-------------------\n");
23714235Smarkfen (void) printf("=========================\n");
23724235Smarkfen }
23734235Smarkfen #endif /* DEBUG_HEAVY */
23744235Smarkfen
23754235Smarkfen static int
ipsec_conf_view()23764235Smarkfen ipsec_conf_view()
23774235Smarkfen {
23784235Smarkfen char buf[MAXLEN];
23794235Smarkfen FILE *fp;
23804235Smarkfen
23814235Smarkfen fp = fopen(POLICY_CONF_FILE, "r");
23824235Smarkfen if (fp == NULL) {
23834235Smarkfen if (errno == ENOENT) {
23844235Smarkfen /*
23854235Smarkfen * The absence of POLICY_CONF_FILE should
23864235Smarkfen * not cause the command to exit with a
23874235Smarkfen * non-zero status, since this condition
23884235Smarkfen * is valid when no policies were previously
23894235Smarkfen * defined.
23904235Smarkfen */
23914235Smarkfen return (0);
23924235Smarkfen }
23934235Smarkfen warn(gettext("%s cannot be opened"), POLICY_CONF_FILE);
23944235Smarkfen return (-1);
23954235Smarkfen }
23964235Smarkfen while (fgets(buf, MAXLEN, fp) != NULL) {
23974235Smarkfen /* Don't print removed entries */
23984235Smarkfen if (*buf == ';')
23994235Smarkfen continue;
24004235Smarkfen if (strlen(buf) != 0)
24014235Smarkfen buf[strlen(buf) - 1] = '\0';
24024235Smarkfen (void) puts(buf);
24034235Smarkfen }
24044235Smarkfen return (0);
24054235Smarkfen }
24064235Smarkfen
24074235Smarkfen /*
24084235Smarkfen * Delete nlines from start in the POLICY_CONF_FILE.
24094235Smarkfen */
24104235Smarkfen static int
delete_from_file(int start,int nlines)24114235Smarkfen delete_from_file(int start, int nlines)
24124235Smarkfen {
24134235Smarkfen FILE *fp;
24144235Smarkfen char ibuf[MAXLEN];
24154235Smarkfen int len;
24164235Smarkfen
24174235Smarkfen if ((fp = fopen(POLICY_CONF_FILE, "r+b")) == NULL) {
24184235Smarkfen warn(gettext("%s cannot be opened"), POLICY_CONF_FILE);
24194235Smarkfen return (-1);
24204235Smarkfen }
24214235Smarkfen
24224235Smarkfen /*
24234235Smarkfen * Insert a ";", read the line and discard it. Repeat
24244235Smarkfen * this logic nlines - 1 times. For the last line there
24254235Smarkfen * is just a newline character. We can't just insert a
24264235Smarkfen * single ";" character instead of the newline character
24274235Smarkfen * as it would affect the next line. Thus when we comment
24284235Smarkfen * the last line we seek one less and insert a ";"
24294235Smarkfen * character, which will replace the newline of the
24304235Smarkfen * penultimate line with ; and newline of the last line
24314235Smarkfen * will become part of the previous line.
24324235Smarkfen */
24334235Smarkfen do {
24344235Smarkfen /*
24354235Smarkfen * It is not enough to seek just once and expect the
24364235Smarkfen * subsequent fgets below to take you to the right
24374235Smarkfen * offset of the next line. fgets below seems to affect
24384235Smarkfen * the offset. Thus we need to seek, replace with ";",
24394235Smarkfen * and discard a line using fgets for every line.
24404235Smarkfen */
24414235Smarkfen if (fseek(fp, start, SEEK_SET) == -1) {
24424235Smarkfen warn("fseek");
24434235Smarkfen return (-1);
24444235Smarkfen }
24454235Smarkfen if (fputc(';', fp) < 0) {
24464235Smarkfen warn("fputc");
24474235Smarkfen return (-1);
24484235Smarkfen }
24494235Smarkfen /*
24504235Smarkfen * Flush the above ";" character before we do the fgets().
24514235Smarkfen * Without this, fgets() gets confused with offsets.
24524235Smarkfen */
24534235Smarkfen (void) fflush(fp);
24544235Smarkfen len = 0;
24554235Smarkfen while (fgets(ibuf, MAXLEN, fp) != NULL) {
24564235Smarkfen len += strlen(ibuf);
24574235Smarkfen if (ibuf[len - 1] == '\n') {
24584235Smarkfen /*
24594235Smarkfen * We have read a complete line.
24604235Smarkfen */
24614235Smarkfen break;
24624235Smarkfen }
24634235Smarkfen }
24644235Smarkfen /*
24654235Smarkfen * We read the line after ";" character has been inserted.
24664235Smarkfen * Thus len does not count ";". To advance to the next line
24674235Smarkfen * increment by 1.
24684235Smarkfen */
24694235Smarkfen start += (len + 1);
24704235Smarkfen /*
24714235Smarkfen * If nlines == 2, we will be commenting out the last
24724235Smarkfen * line next, which has only one newline character.
24734235Smarkfen * If we blindly replace it with ";", it will be
24744235Smarkfen * read as part of the next line which could have
24754235Smarkfen * a INDEX string and thus confusing ipsec_conf_view.
24764235Smarkfen * Thus, we seek one less and replace the previous
24774235Smarkfen * line's newline character with ";", and the
24784235Smarkfen * last line's newline character will become part of
24794235Smarkfen * the previous line.
24804235Smarkfen */
24814235Smarkfen if (nlines == 2)
24824235Smarkfen start--;
24834235Smarkfen } while (--nlines != 0);
24844235Smarkfen (void) fclose(fp);
24854235Smarkfen if (nlines != 0)
24864235Smarkfen return (-1);
24874235Smarkfen else
24884235Smarkfen return (0);
24894235Smarkfen }
24904235Smarkfen
24914235Smarkfen /*
24924235Smarkfen * Delete an entry from the file by inserting a ";" at the
24934235Smarkfen * beginning of the lines to be removed.
24944235Smarkfen */
24954235Smarkfen static int
ipsec_conf_del(int policy_index,boolean_t ignore_spd)24964235Smarkfen ipsec_conf_del(int policy_index, boolean_t ignore_spd)
24974235Smarkfen {
24984235Smarkfen act_prop_t *act_props = malloc(sizeof (act_prop_t));
24994235Smarkfen char *buf;
25004235Smarkfen FILE *fp;
25014235Smarkfen char ibuf[MAXLEN];
25024235Smarkfen int ibuf_len, index_len, index;
25034235Smarkfen int ret = 0;
25044235Smarkfen int offset, prev_offset;
25054235Smarkfen int nlines;
25064235Smarkfen char lifname[LIFNAMSIZ];
25074235Smarkfen
25084235Smarkfen if (act_props == NULL) {
25094235Smarkfen warn(gettext("memory"));
25104235Smarkfen return (-1);
25114235Smarkfen }
25124235Smarkfen
25134235Smarkfen fp = fopen(POLICY_CONF_FILE, "r");
25144235Smarkfen if (fp == NULL) {
25154235Smarkfen warn(gettext("%s cannot be opened"), POLICY_CONF_FILE);
25164235Smarkfen free(act_props);
25174235Smarkfen return (-1);
25184235Smarkfen }
25194235Smarkfen
25204235Smarkfen index_len = strlen(INDEX_TAG);
25214235Smarkfen index = 0;
25224235Smarkfen for (offset = prev_offset = 0; fgets(ibuf, MAXLEN, fp) != NULL;
25234235Smarkfen offset += ibuf_len) {
25244235Smarkfen prev_offset = offset;
25254235Smarkfen ibuf_len = strlen(ibuf);
25264235Smarkfen
25274235Smarkfen if (strncmp(ibuf, INDEX_TAG, index_len) != 0) {
25284235Smarkfen continue;
25294235Smarkfen }
25304235Smarkfen
25314235Smarkfen /*
25324235Smarkfen * This line contains INDEX_TAG
25334235Smarkfen */
25344235Smarkfen buf = ibuf + index_len;
25354235Smarkfen buf++; /* Skip the space */
25364235Smarkfen index = parse_index(buf, lifname);
25374235Smarkfen if (index == -1) {
25384235Smarkfen warnx(gettext("Invalid index in the file"));
25394235Smarkfen free(act_props);
25404235Smarkfen return (-1);
25414235Smarkfen }
25424235Smarkfen if (index == policy_index &&
25434235Smarkfen (interface_name == NULL ||
25445120Smarkfen strncmp(interface_name, lifname, LIFNAMSIZ) == 0)) {
25454235Smarkfen if (!ignore_spd) {
25464235Smarkfen ret = parse_one(fp, act_props);
25474235Smarkfen if (ret == -1) {
25484235Smarkfen warnx(gettext("Invalid policy entry "
25494235Smarkfen "in the file"));
25504235Smarkfen free(act_props);
25514235Smarkfen return (-1);
25524235Smarkfen }
25534235Smarkfen }
25544235Smarkfen /*
25554235Smarkfen * nlines is the number of lines we should comment
25564235Smarkfen * out. linecount tells us how many lines this command
25574235Smarkfen * spans. And we need to remove the line with INDEX
25584235Smarkfen * and an extra line we added during ipsec_conf_add.
25594235Smarkfen *
25604235Smarkfen * NOTE : If somebody added a policy entry which does
25614235Smarkfen * not have a newline, ipsec_conf_add() fills in the
25624235Smarkfen * newline. Hence, there is always 2 extra lines
25634235Smarkfen * to delete.
25644235Smarkfen */
25654235Smarkfen nlines = linecount + 2;
25664235Smarkfen goto delete;
25674235Smarkfen }
25684235Smarkfen }
25694235Smarkfen
25704235Smarkfen if (!ignore_spd)
25714235Smarkfen ret = pfp_delete_rule(policy_index);
25724235Smarkfen
25734235Smarkfen if (ret != 0) {
25744235Smarkfen warnx(gettext("Deletion incomplete. Please "
25754235Smarkfen "flush all the entries and re-configure :"));
25764235Smarkfen reconfigure();
25774235Smarkfen free(act_props);
25784235Smarkfen return (ret);
25794235Smarkfen }
25804235Smarkfen free(act_props);
25814235Smarkfen return (ret);
25824235Smarkfen
25834235Smarkfen delete:
25844235Smarkfen /* Delete nlines from prev_offset */
25854235Smarkfen (void) fclose(fp);
25864235Smarkfen ret = delete_from_file(prev_offset, nlines);
25874235Smarkfen
25884235Smarkfen if (ret != 0) {
25894235Smarkfen warnx(gettext("Deletion incomplete. Please "
25904235Smarkfen "flush all the entries and re-configure :"));
25914235Smarkfen reconfigure();
25924235Smarkfen free(act_props);
25934235Smarkfen return (ret);
25944235Smarkfen }
25954235Smarkfen
25964235Smarkfen if (!ignore_spd)
25974235Smarkfen ret = pfp_delete_rule(policy_index);
25984235Smarkfen
25994235Smarkfen if (ret != 0) {
26004235Smarkfen warnx(gettext("Deletion incomplete. Please "
26014235Smarkfen "flush all the entries and re-configure :"));
26024235Smarkfen reconfigure();
26034235Smarkfen free(act_props);
26044235Smarkfen return (ret);
26054235Smarkfen }
26064235Smarkfen free(act_props);
26074235Smarkfen return (0);
26084235Smarkfen }
26094235Smarkfen
26104235Smarkfen static int
pfp_delete_rule(uint64_t index)26114235Smarkfen pfp_delete_rule(uint64_t index)
26124235Smarkfen {
26134235Smarkfen struct spd_msg *msg;
26144235Smarkfen struct spd_rule *rule;
26154235Smarkfen int sfd;
26164235Smarkfen int cnt, len, alloclen;
26174235Smarkfen
26184235Smarkfen sfd = get_pf_pol_socket();
26194235Smarkfen if (sfd < 0) {
26204235Smarkfen warn(gettext("unable to open policy socket"));
26214235Smarkfen return (-1);
26224235Smarkfen }
26234235Smarkfen
26244235Smarkfen /*
26254235Smarkfen * Add an extra 8 bytes of space (+1 uint64_t) to avoid truncation
26264235Smarkfen * issues.
26274235Smarkfen */
26284235Smarkfen alloclen = sizeof (spd_msg_t) + sizeof (struct spd_rule) +
26294235Smarkfen sizeof (spd_if_t) + LIFNAMSIZ + 8;
26304235Smarkfen msg = (spd_msg_t *)malloc(alloclen);
26314235Smarkfen
26324235Smarkfen if (msg == NULL) {
26334235Smarkfen warn("malloc");
26344235Smarkfen return (-1);
26354235Smarkfen }
26364235Smarkfen
26374235Smarkfen rule = (struct spd_rule *)(msg + 1);
26384235Smarkfen
26394235Smarkfen (void) memset(msg, 0, alloclen);
26404235Smarkfen msg->spd_msg_version = PF_POLICY_V1;
26414235Smarkfen msg->spd_msg_type = SPD_DELETERULE;
26424235Smarkfen msg->spd_msg_len = SPD_8TO64(sizeof (spd_msg_t)
26434235Smarkfen + sizeof (struct spd_rule));
26444235Smarkfen
26454235Smarkfen rule->spd_rule_type = SPD_EXT_RULE;
26464235Smarkfen rule->spd_rule_len = SPD_8TO64(sizeof (struct spd_rule));
26474235Smarkfen rule->spd_rule_index = index;
26484235Smarkfen
26494235Smarkfen msg->spd_msg_len += attach_tunname((spd_if_t *)(rule + 1));
26504235Smarkfen
26514235Smarkfen len = SPD_64TO8(msg->spd_msg_len);
26524235Smarkfen cnt = write(sfd, msg, len);
26534235Smarkfen
26544235Smarkfen if (cnt != len) {
26554235Smarkfen if (cnt < 0) {
2656*12655SVladimir.Kotal@Sun.COM warn(gettext("Delete failed: write"));
26574235Smarkfen (void) close(sfd);
26584235Smarkfen free(msg);
26594235Smarkfen return (-1);
26604235Smarkfen } else {
26614235Smarkfen (void) close(sfd);
26624235Smarkfen free(msg);
26634235Smarkfen warnx(gettext("Delete failed: short write"));
26644235Smarkfen return (-1);
26654235Smarkfen }
26664235Smarkfen }
26674235Smarkfen
26684235Smarkfen cnt = read(sfd, msg, len);
26694235Smarkfen if (cnt != len) {
26704235Smarkfen if (cnt < 0) {
2671*12655SVladimir.Kotal@Sun.COM warn(gettext("Delete failed: read"));
26724235Smarkfen (void) close(sfd);
26734235Smarkfen free(msg);
26744235Smarkfen return (-1);
26754235Smarkfen } else {
26764235Smarkfen (void) close(sfd);
26774235Smarkfen free(msg);
26784235Smarkfen warnx(gettext("Delete failed while reading reply"));
26794235Smarkfen return (-1);
26804235Smarkfen }
26814235Smarkfen }
26824235Smarkfen (void) close(sfd);
26834235Smarkfen if (msg->spd_msg_errno != 0) {
26844235Smarkfen errno = msg->spd_msg_errno;
26854235Smarkfen warn(gettext("Delete failed: SPD_FLUSH"));
2686*12655SVladimir.Kotal@Sun.COM free(msg);
26874235Smarkfen return (-1);
26884235Smarkfen }
26894235Smarkfen
26904235Smarkfen free(msg);
26914235Smarkfen return (0);
26924235Smarkfen }
26934235Smarkfen
26944235Smarkfen static int
ipsec_conf_flush(int db)26954235Smarkfen ipsec_conf_flush(int db)
26964235Smarkfen {
26974235Smarkfen int pfd, cnt, len;
26984235Smarkfen int sfd;
26994235Smarkfen struct spd_msg *msg;
27004235Smarkfen /*
27014235Smarkfen * Add an extra 8 bytes of space (+1 uint64_t) to avoid truncation
27024235Smarkfen * issues.
27034235Smarkfen */
27044235Smarkfen uint64_t buffer[
27054235Smarkfen SPD_8TO64(sizeof (*msg) + sizeof (spd_if_t) + LIFNAMSIZ) + 1];
27064235Smarkfen
27074235Smarkfen sfd = get_pf_pol_socket();
27084235Smarkfen if (sfd < 0) {
27094235Smarkfen warn(gettext("unable to open policy socket"));
27104235Smarkfen return (-1);
27114235Smarkfen }
27124235Smarkfen
27134235Smarkfen (void) memset(buffer, 0, sizeof (buffer));
27144235Smarkfen msg = (struct spd_msg *)buffer;
27154235Smarkfen msg->spd_msg_version = PF_POLICY_V1;
27164235Smarkfen msg->spd_msg_type = SPD_FLUSH;
27174235Smarkfen msg->spd_msg_len = SPD_8TO64(sizeof (*msg));
27184235Smarkfen msg->spd_msg_spdid = db;
27194235Smarkfen
27204235Smarkfen msg->spd_msg_len += attach_tunname((spd_if_t *)(msg + 1));
27214235Smarkfen
27224235Smarkfen len = SPD_64TO8(msg->spd_msg_len);
27234235Smarkfen cnt = write(sfd, msg, len);
27244235Smarkfen if (cnt != len) {
27254235Smarkfen if (cnt < 0) {
27264235Smarkfen warn(gettext("Flush failed: write"));
27274235Smarkfen return (-1);
27284235Smarkfen } else {
27294235Smarkfen warnx(gettext("Flush failed: short write"));
27304235Smarkfen return (-1);
27314235Smarkfen }
27324235Smarkfen }
27334235Smarkfen
27344235Smarkfen cnt = read(sfd, msg, len);
27354235Smarkfen if (cnt != len) {
27364235Smarkfen if (cnt < 0) {
27374235Smarkfen warn(gettext("Flush failed: read"));
27384235Smarkfen return (-1);
27394235Smarkfen } else {
27404235Smarkfen warnx(gettext("Flush failed while reading reply"));
27414235Smarkfen return (-1);
27424235Smarkfen }
27434235Smarkfen }
27444235Smarkfen (void) close(sfd);
27454235Smarkfen if (msg->spd_msg_errno != 0) {
27464235Smarkfen warnx("%s: %s", gettext("Flush failed: SPD_FLUSH"),
27474235Smarkfen sys_error_message(msg->spd_msg_errno));
27484235Smarkfen return (-1);
27494235Smarkfen }
27504235Smarkfen
27514235Smarkfen /* Truncate the file */
27524235Smarkfen if (db == SPD_ACTIVE) {
27534235Smarkfen if ((pfd = open(POLICY_CONF_FILE, O_TRUNC|O_RDWR)) == -1) {
27544235Smarkfen if (errno == ENOENT) {
27554235Smarkfen /*
27564235Smarkfen * The absence of POLICY_CONF_FILE should
27574235Smarkfen * not cause the command to exit with a
27584235Smarkfen * non-zero status, since this condition
27594235Smarkfen * is valid when no policies were previously
27604235Smarkfen * defined.
27614235Smarkfen */
27624235Smarkfen return (0);
27634235Smarkfen }
27644235Smarkfen warn(gettext("%s cannot be truncated"),
27654235Smarkfen POLICY_CONF_FILE);
27664235Smarkfen return (-1);
27674235Smarkfen }
27684235Smarkfen (void) close(pfd);
27694235Smarkfen }
27704235Smarkfen return (0);
27714235Smarkfen }
27724235Smarkfen
27734235Smarkfen /*
27744235Smarkfen * function to send SPD_FLIP and SPD_CLONE messages
27754235Smarkfen * Do it for ALL polheads for simplicity's sake.
27764235Smarkfen */
27774235Smarkfen static void
ipsec_conf_admin(uint8_t type)27784235Smarkfen ipsec_conf_admin(uint8_t type)
27794235Smarkfen {
27804235Smarkfen int cnt;
27814235Smarkfen int sfd;
27824235Smarkfen struct spd_msg *msg;
27834235Smarkfen uint64_t buffer[
27844235Smarkfen SPD_8TO64(sizeof (struct spd_msg) + sizeof (spd_if_t))];
27854235Smarkfen char *save_ifname;
27864235Smarkfen
27874235Smarkfen sfd = get_pf_pol_socket();
27884235Smarkfen if (sfd < 0) {
27894235Smarkfen err(-1, gettext("unable to open policy socket"));
27904235Smarkfen }
27914235Smarkfen
27924235Smarkfen (void) memset(buffer, 0, sizeof (buffer));
27934235Smarkfen msg = (struct spd_msg *)buffer;
27944235Smarkfen msg->spd_msg_version = PF_POLICY_V1;
27954235Smarkfen msg->spd_msg_type = type;
27964235Smarkfen msg->spd_msg_len = SPD_8TO64(sizeof (buffer));
27974235Smarkfen
27984235Smarkfen save_ifname = interface_name;
27994235Smarkfen /* Apply to all policy heads - global and tunnels. */
28004235Smarkfen interface_name = &all_polheads;
28014235Smarkfen (void) attach_tunname((spd_if_t *)(msg + 1));
28024235Smarkfen interface_name = save_ifname;
28034235Smarkfen
28044235Smarkfen cnt = write(sfd, msg, sizeof (buffer));
28054235Smarkfen if (cnt != sizeof (buffer)) {
28064235Smarkfen if (cnt < 0) {
28074235Smarkfen err(-1, gettext("admin failed: write"));
28084235Smarkfen } else {
28094235Smarkfen errx(-1, gettext("admin failed: short write"));
28104235Smarkfen }
28114235Smarkfen }
28124235Smarkfen
28134235Smarkfen cnt = read(sfd, msg, sizeof (buffer));
28144235Smarkfen if (cnt != sizeof (buffer)) {
28154235Smarkfen if (cnt < 0) {
28164235Smarkfen err(-1, gettext("admin failed: read"));
28174235Smarkfen } else {
28184235Smarkfen errx(-1, gettext("admin failed while reading reply"));
28194235Smarkfen }
28204235Smarkfen }
28214235Smarkfen (void) close(sfd);
28224235Smarkfen if (msg->spd_msg_errno != 0) {
28234235Smarkfen errno = msg->spd_msg_errno;
28244235Smarkfen err(-1, gettext("admin failed"));
28254235Smarkfen }
28264235Smarkfen }
28274235Smarkfen
28284235Smarkfen static void
reconfigure()28294235Smarkfen reconfigure()
28304235Smarkfen {
28314235Smarkfen (void) fprintf(stderr, gettext(
28325120Smarkfen "\tipsecconf -f \n "
28335120Smarkfen "\tipsecconf -a policy_file\n"));
28344235Smarkfen }
28354235Smarkfen
28364235Smarkfen static void
usage(void)28374235Smarkfen usage(void)
28384235Smarkfen {
28394235Smarkfen (void) fprintf(stderr, gettext(
28404235Smarkfen "Usage: ipsecconf\n"
28414235Smarkfen "\tipsecconf -a ([-]|<filename>) [-q]\n"
28424235Smarkfen "\tipsecconf -c <filename>\n"
28434235Smarkfen "\tipsecconf -r ([-]|<filename>) [-q]\n"
28444235Smarkfen "\tipsecconf -d [-i tunnel-interface] <index>\n"
28454235Smarkfen "\tipsecconf -d <tunnel-interface,index>\n"
28464235Smarkfen "\tipsecconf -l [-n] [-i tunnel-interface]\n"
28474235Smarkfen "\tipsecconf -f [-i tunnel-interface]\n"
28484235Smarkfen "\tipsecconf -L [-n]\n"
28494235Smarkfen "\tipsecconf -F\n"));
28504235Smarkfen }
28514235Smarkfen
28524235Smarkfen /*
28534235Smarkfen * a type consists of
28544235Smarkfen * "type" <int>{ "-" <int>}
28554235Smarkfen * or
28564235Smarkfen * "type" keyword
28574235Smarkfen *
28584235Smarkfen * a code consists of
28594235Smarkfen * "code" <int>{ "-" <int>}
28604235Smarkfen * or
28614235Smarkfen * "code" keyword
28624235Smarkfen */
28634235Smarkfen
28644235Smarkfen
28654235Smarkfen static int
parse_type_code(const char * str,const str_val_t * table)28664235Smarkfen parse_type_code(const char *str, const str_val_t *table)
28674235Smarkfen {
28684235Smarkfen char *end1, *end2;
28694235Smarkfen int res1 = 0, res2 = 0;
28704235Smarkfen int i;
28714235Smarkfen
28724235Smarkfen if (isdigit(str[0])) {
28734235Smarkfen res1 = strtol(str, &end1, 0);
28744235Smarkfen
28754235Smarkfen if (end1 == str) {
28764235Smarkfen return (-1);
28774235Smarkfen }
28784235Smarkfen
28794235Smarkfen if (res1 > 255 || res1 < 0) {
28804235Smarkfen return (-1);
28814235Smarkfen }
28824235Smarkfen
28834235Smarkfen if (*end1 == '-') {
28844235Smarkfen end1++;
28854235Smarkfen res2 = strtol(end1, &end2, 0);
28864235Smarkfen if (res2 > 255 || res2 < 0) {
28874235Smarkfen return (-1);
28884235Smarkfen }
28894235Smarkfen } else {
28904235Smarkfen end2 = end1;
28914235Smarkfen }
28924235Smarkfen
28934235Smarkfen while (isspace(*end2))
28944235Smarkfen end2++;
28954235Smarkfen
28964235Smarkfen if (*end2 != '\0') {
28974235Smarkfen return (-1);
28984235Smarkfen }
28994235Smarkfen
29004235Smarkfen return (res1 + (res2 << 8));
29014235Smarkfen }
29024235Smarkfen
29034235Smarkfen for (i = 0; table[i].string; i++) {
29044235Smarkfen if (strcmp(str, table[i].string) == 0) {
29054235Smarkfen return (table[i].value);
29064235Smarkfen }
29074235Smarkfen }
29084235Smarkfen
29094235Smarkfen return (-1);
29104235Smarkfen }
29114235Smarkfen
29124235Smarkfen static int
parse_int(const char * str)29134235Smarkfen parse_int(const char *str)
29144235Smarkfen {
29154235Smarkfen char *end;
29164235Smarkfen int res;
29174235Smarkfen
29184235Smarkfen res = strtol(str, &end, 0);
29194235Smarkfen if (end == str)
29204235Smarkfen return (-1);
29214235Smarkfen while (isspace(*end))
29224235Smarkfen end++;
29234235Smarkfen if (*end != '\0')
29244235Smarkfen return (-1);
29254235Smarkfen return (res);
29264235Smarkfen }
29274235Smarkfen
29284235Smarkfen /*
29294235Smarkfen * Parses <interface>,<index>. Sets iname or the global interface_name (if
29304235Smarkfen * iname == NULL) to <interface> and returns <index>. Calls exit() if we have
29314235Smarkfen * an interface_name already set.
29324235Smarkfen */
29334235Smarkfen static int
parse_index(const char * str,char * iname)29344235Smarkfen parse_index(const char *str, char *iname)
29354235Smarkfen {
29364235Smarkfen char *intf, *num, *copy;
29374235Smarkfen int rc;
29384235Smarkfen
29394235Smarkfen copy = strdup(str);
29404235Smarkfen if (copy == NULL) {
29414235Smarkfen EXIT_FATAL("Out of memory.");
29424235Smarkfen }
29434235Smarkfen
29444235Smarkfen intf = strtok(copy, ",");
29454235Smarkfen /* Just want the rest of the string unmolested, so use "" for arg2. */
29464235Smarkfen num = strtok(NULL, "");
29474235Smarkfen if (num == NULL) {
29484235Smarkfen /* No comma found, just parse it like an int. */
29494235Smarkfen free(copy);
29504235Smarkfen return (parse_int(str));
29514235Smarkfen }
29524235Smarkfen
29534235Smarkfen if (iname != NULL) {
29544235Smarkfen (void) strlcpy(iname, intf, LIFNAMSIZ);
29554235Smarkfen } else {
29564235Smarkfen if (interface_name != NULL) {
29574235Smarkfen EXIT_FATAL("Interface name already selected");
29584235Smarkfen }
29594235Smarkfen
29604235Smarkfen interface_name = strdup(intf);
29614235Smarkfen if (interface_name == NULL) {
29624235Smarkfen EXIT_FATAL("Out of memory.");
29634235Smarkfen }
29644235Smarkfen }
29654235Smarkfen
29664235Smarkfen rc = parse_int(num);
29674235Smarkfen free(copy);
29684235Smarkfen return (rc);
29694235Smarkfen }
29704235Smarkfen
29714235Smarkfen /*
29724235Smarkfen * Convert a mask to a prefix length.
29734235Smarkfen * Returns prefix length on success, -1 otherwise.
29744235Smarkfen */
29754235Smarkfen static int
in_getprefixlen(char * mask)29764235Smarkfen in_getprefixlen(char *mask)
29774235Smarkfen {
29784235Smarkfen int prefixlen;
29794235Smarkfen char *end;
29804235Smarkfen
29814235Smarkfen prefixlen = (int)strtol(mask, &end, 10);
29824235Smarkfen if (prefixlen < 0) {
29834235Smarkfen return (-1);
29844235Smarkfen }
29854235Smarkfen if (mask == end) {
29864235Smarkfen return (-1);
29874235Smarkfen }
29884235Smarkfen if (*end != '\0') {
29894235Smarkfen return (-1);
29904235Smarkfen }
29914235Smarkfen return (prefixlen);
29924235Smarkfen }
29934235Smarkfen
29944235Smarkfen /*
29954235Smarkfen * Convert a prefix length to a mask.
29964235Smarkfen * Assumes the mask array is zero'ed by the caller.
29974235Smarkfen */
29984235Smarkfen static void
in_prefixlentomask(unsigned int prefixlen,uchar_t * mask)29994235Smarkfen in_prefixlentomask(unsigned int prefixlen, uchar_t *mask)
30004235Smarkfen {
30014235Smarkfen while (prefixlen > 0) {
30024235Smarkfen if (prefixlen >= 8) {
30034235Smarkfen *mask++ = 0xFF;
30044235Smarkfen prefixlen -= 8;
30054235Smarkfen continue;
30064235Smarkfen }
30074235Smarkfen *mask |= 1 << (8 - prefixlen);
30084235Smarkfen prefixlen--;
30094235Smarkfen }
30104235Smarkfen }
30114235Smarkfen
30124235Smarkfen
30134235Smarkfen static int
parse_address(int type,char * addr_str)30144235Smarkfen parse_address(int type, char *addr_str)
30154235Smarkfen {
30164235Smarkfen char *ptr;
30174235Smarkfen int prefix_len = 0;
30184235Smarkfen struct netent *ne = NULL;
30194235Smarkfen struct hostent *hp = NULL;
30204235Smarkfen int h_errno;
30214235Smarkfen struct in_addr netaddr;
30224235Smarkfen struct in6_addr *netaddr6;
30234235Smarkfen struct hostent *ne_hent;
30244235Smarkfen boolean_t has_mask = B_FALSE;
30254235Smarkfen
30264235Smarkfen ptr = strchr(addr_str, '/');
30274235Smarkfen if (ptr != NULL) {
30284235Smarkfen has_mask = B_TRUE;
30294235Smarkfen *ptr++ = NULL;
30304235Smarkfen
30314235Smarkfen prefix_len = in_getprefixlen(ptr);
303212131Sdanmcd@opensolaris.org if (prefix_len < 0) {
303312131Sdanmcd@opensolaris.org warnx(gettext("Unparseable prefix: '%s'."), ptr);
30344235Smarkfen return (-1);
303512131Sdanmcd@opensolaris.org }
30364235Smarkfen }
30374235Smarkfen
30384235Smarkfen /*
30394235Smarkfen * getipnodebyname() is thread safe. This allows us to hold on to the
30404235Smarkfen * returned hostent structure, which is pointed to by the shp and
30414235Smarkfen * dhp globals for the source and destination addresses, respectively.
30424235Smarkfen */
30434235Smarkfen hp = getipnodebyname(addr_str, AF_INET6, AI_DEFAULT | AI_ALL, &h_errno);
30444235Smarkfen if (hp != NULL) {
30454235Smarkfen /*
30464235Smarkfen * We come here for both a hostname and
30474235Smarkfen * any host address /network address.
30484235Smarkfen */
30494235Smarkfen assert(hp->h_addrtype == AF_INET6);
30504235Smarkfen } else if ((ne = getnetbyname(addr_str)) != NULL) {
30514235Smarkfen switch (ne->n_addrtype) {
30524235Smarkfen case AF_INET:
30534235Smarkfen /*
30544235Smarkfen * Allocate a struct hostent and initialize
30554235Smarkfen * it with the address corresponding to the
30564235Smarkfen * network number previously returned by
30574235Smarkfen * getnetbyname(). Freed by do_address_adds()
30584235Smarkfen * once the policy is defined.
30594235Smarkfen */
30604235Smarkfen ne_hent = malloc(sizeof (struct hostent));
30614235Smarkfen if (ne_hent == NULL) {
30624235Smarkfen warn("malloc");
30634235Smarkfen return (-1);
30644235Smarkfen }
30654235Smarkfen ne_hent->h_addr_list = malloc(2*sizeof (char *));
30664235Smarkfen if (ne_hent->h_addr_list == NULL) {
30674235Smarkfen warn("malloc");
30684235Smarkfen free(ne_hent);
30694235Smarkfen return (-1);
30704235Smarkfen }
30714235Smarkfen netaddr6 = malloc(sizeof (struct in6_addr));
30724235Smarkfen if (netaddr6 == NULL) {
30734235Smarkfen warn("malloc");
30744235Smarkfen free(ne_hent->h_addr_list);
30754235Smarkfen free(ne_hent);
30764235Smarkfen return (-1);
30774235Smarkfen }
30784235Smarkfen ne_hent->h_addr_list[0] = (char *)netaddr6;
30794235Smarkfen ne_hent->h_addr_list[1] = NULL;
30804235Smarkfen netaddr = inet_makeaddr(ne->n_net, INADDR_ANY);
30814235Smarkfen IN6_INADDR_TO_V4MAPPED(&netaddr, netaddr6);
30824235Smarkfen hp = ne_hent;
30834235Smarkfen break;
30844235Smarkfen default:
308512131Sdanmcd@opensolaris.org warnx(gettext("Address type %d not supported."),
308612131Sdanmcd@opensolaris.org ne->n_addrtype);
30874235Smarkfen return (-1);
30884235Smarkfen }
30894235Smarkfen } else {
309012131Sdanmcd@opensolaris.org warnx(gettext("Could not resolve address %s."), addr_str);
30914235Smarkfen return (-1);
30924235Smarkfen }
30934235Smarkfen
30944235Smarkfen if (type == IPSEC_CONF_SRC_ADDRESS) {
30954235Smarkfen shp = hp;
30964235Smarkfen if (has_mask)
30974235Smarkfen splen = prefix_len;
30984235Smarkfen has_saprefix = has_mask;
30994235Smarkfen } else {
31004235Smarkfen dhp = hp;
31014235Smarkfen if (has_mask)
31024235Smarkfen dplen = prefix_len;
31034235Smarkfen has_daprefix = has_mask;
31044235Smarkfen }
31054235Smarkfen
31064235Smarkfen return (0);
31074235Smarkfen }
31084235Smarkfen
31094235Smarkfen /*
31104235Smarkfen * Add port-only entries. Make sure to add them in both the V6 and V4 tables!
31114235Smarkfen */
31124235Smarkfen static int
do_port_adds(ips_conf_t * cptr)31134235Smarkfen do_port_adds(ips_conf_t *cptr)
31144235Smarkfen {
31154235Smarkfen int ret, diag;
31164235Smarkfen
31174235Smarkfen assert(IN6_IS_ADDR_UNSPECIFIED(&cptr->ips_src_addr_v6));
31184235Smarkfen assert(IN6_IS_ADDR_UNSPECIFIED(&cptr->ips_dst_addr_v6));
31194235Smarkfen
31204235Smarkfen #ifdef DEBUG_HEAVY
31214235Smarkfen (void) dump_conf(cptr);
31224235Smarkfen #endif
31234235Smarkfen
31244235Smarkfen ret = send_pf_pol_message(SPD_ADDRULE, cptr, &diag);
31254235Smarkfen if (ret != 0 && !ipsecconf_qflag) {
31264235Smarkfen warnx(
31274235Smarkfen gettext("Could not add IPv4 policy for sport %d, dport %d "
31285120Smarkfen "- diagnostic %d - %s"), ntohs(cptr->ips_src_port_min),
31294235Smarkfen ntohs(cptr->ips_dst_port_min), diag, spdsock_diag(diag));
31304235Smarkfen }
31314235Smarkfen
31324235Smarkfen return (ret);
31334235Smarkfen }
31344235Smarkfen
31354235Smarkfen /*
31364235Smarkfen * Nuke a list of policy entries.
31374235Smarkfen * rewrite this to use flipping
31384235Smarkfen * d_list isn't freed because we will be
31394235Smarkfen * exiting the program soon.
31404235Smarkfen */
31414235Smarkfen static void
nuke_adds()31424235Smarkfen nuke_adds()
31434235Smarkfen {
31444235Smarkfen d_list_t *temp = d_list;
31454235Smarkfen FILE *policy_fp;
31464235Smarkfen
31474235Smarkfen policy_fp = fopen(POLICY_CONF_FILE, "a");
31484235Smarkfen if (policy_fp == NULL) {
31494235Smarkfen warn(gettext("%s cannot be opened"), POLICY_CONF_FILE);
31505494Spwernau } else {
31515494Spwernau (void) fprintf(policy_fp, "\n\n");
31525494Spwernau (void) fflush(policy_fp);
31534235Smarkfen }
31544235Smarkfen
31554235Smarkfen while (temp != NULL) {
31564235Smarkfen (void) ipsec_conf_del(temp->index, B_TRUE);
31574235Smarkfen temp = temp->next;
31584235Smarkfen }
31594235Smarkfen }
31604235Smarkfen
31614235Smarkfen /*
31624235Smarkfen * Set mask info from the specified prefix len. Fail if multihomed.
31634235Smarkfen */
31644235Smarkfen static int
set_mask_info(struct hostent * hp,unsigned int plen,struct in6_addr * mask_v6)31654235Smarkfen set_mask_info(struct hostent *hp, unsigned int plen, struct in6_addr *mask_v6)
31664235Smarkfen {
31674235Smarkfen struct in6_addr addr;
31684235Smarkfen struct in_addr mask_v4;
31694235Smarkfen
31704235Smarkfen if (hp->h_addr_list[1] != NULL) {
31714235Smarkfen return (EOPNOTSUPP);
31724235Smarkfen }
31734235Smarkfen
31744235Smarkfen if (!IN6_IS_ADDR_UNSPECIFIED(mask_v6)) {
31754235Smarkfen return (EBUSY);
31764235Smarkfen }
31774235Smarkfen
31784235Smarkfen bcopy(hp->h_addr_list[0], &addr, sizeof (struct in6_addr));
31794235Smarkfen if (IN6_IS_ADDR_V4MAPPED(&addr)) {
31804235Smarkfen if (plen > IP_ABITS) {
31814235Smarkfen return (ERANGE);
31824235Smarkfen }
31834235Smarkfen (void) memset(&mask_v4, 0, sizeof (mask_v4));
31844235Smarkfen in_prefixlentomask(plen, (uchar_t *)&mask_v4);
31854235Smarkfen IN6_INADDR_TO_V4MAPPED(&mask_v4, mask_v6);
31864235Smarkfen } else {
31874235Smarkfen if (plen > IPV6_ABITS) {
31884235Smarkfen return (ERANGE);
31894235Smarkfen }
31904235Smarkfen /* mask_v6 is already zero (unspecified), see test above */
31914235Smarkfen in_prefixlentomask(plen, (uchar_t *)mask_v6);
31924235Smarkfen }
31934235Smarkfen return (0);
31944235Smarkfen }
31954235Smarkfen
31964235Smarkfen /*
31974235Smarkfen * Initialize the specified IPv6 address with all f's.
31984235Smarkfen */
31994235Smarkfen static void
init_addr_wildcard(struct in6_addr * addr_v6,boolean_t isv4)32004235Smarkfen init_addr_wildcard(struct in6_addr *addr_v6, boolean_t isv4)
32014235Smarkfen {
32024235Smarkfen if (isv4) {
32034235Smarkfen uint32_t addr_v4 = 0xffffffff;
32044235Smarkfen IN6_INADDR_TO_V4MAPPED((struct in_addr *)&addr_v4, addr_v6);
32054235Smarkfen } else {
32064235Smarkfen (void) memset(addr_v6, 0xff, sizeof (struct in6_addr));
32074235Smarkfen }
32084235Smarkfen }
32094235Smarkfen
32104235Smarkfen /*
32114235Smarkfen * Called at the end to actually add policy. Handles single and multi-homed
32124235Smarkfen * cases.
32134235Smarkfen */
32144235Smarkfen static int
do_address_adds(ips_conf_t * cptr,int * diag)32154235Smarkfen do_address_adds(ips_conf_t *cptr, int *diag)
32164235Smarkfen {
32174235Smarkfen int i, j;
32184235Smarkfen int ret = 0; /* For ioctl() call. */
32194235Smarkfen int rc = 0; /* My own return code. */
32204235Smarkfen struct in6_addr zeroes = {0, 0, 0, 0};
32214235Smarkfen char *ptr[2];
32224235Smarkfen struct hostent hent;
32234235Smarkfen boolean_t isv4;
32244235Smarkfen int add_count = 0;
32254235Smarkfen
32264235Smarkfen /*
32274235Smarkfen * dst_hent may not be initialized if a destination
32284235Smarkfen * address was not given. It will be initalized with just
32294235Smarkfen * one address if a destination address was given. In both
32304235Smarkfen * the cases, we initialize here with ipsc_dst_addr and enter
32314235Smarkfen * the loop below.
32324235Smarkfen */
32334235Smarkfen if (dhp == NULL) {
32344235Smarkfen assert(shp != NULL);
32354235Smarkfen hent.h_addr_list = ptr;
32364235Smarkfen ptr[0] = (char *)&zeroes.s6_addr;
32374235Smarkfen ptr[1] = NULL;
32384235Smarkfen dhp = &hent;
32394235Smarkfen } else if (shp == NULL) {
32404235Smarkfen assert(dhp != NULL);
32414235Smarkfen hent.h_addr_list = ptr;
32424235Smarkfen ptr[0] = (char *)&zeroes.s6_addr;
32434235Smarkfen ptr[1] = NULL;
32444235Smarkfen shp = &hent;
32454235Smarkfen }
32464235Smarkfen
32474235Smarkfen /*
32484235Smarkfen * Set mask info here. Bail if multihomed and there's a prefix len.
32494235Smarkfen */
32504235Smarkfen if (has_saprefix) {
32514235Smarkfen rc = set_mask_info(shp, splen, &cptr->ips_src_mask_v6);
32524235Smarkfen if (rc != 0)
32534235Smarkfen goto bail;
32544235Smarkfen cptr->ips_src_mask_len = splen;
32554235Smarkfen }
32564235Smarkfen
32574235Smarkfen if (has_daprefix) {
32584235Smarkfen rc = set_mask_info(dhp, dplen, &cptr->ips_dst_mask_v6);
32594235Smarkfen if (rc != 0)
32604235Smarkfen goto bail;
32614235Smarkfen cptr->ips_dst_mask_len = dplen;
32624235Smarkfen }
32634235Smarkfen
32644235Smarkfen for (i = 0; shp->h_addr_list[i] != NULL; i++) {
32654235Smarkfen bcopy(shp->h_addr_list[i], &cptr->ips_src_addr_v6,
32664235Smarkfen sizeof (struct in6_addr));
32674235Smarkfen isv4 = cptr->ips_isv4 =
32684235Smarkfen IN6_IS_ADDR_V4MAPPED(&cptr->ips_src_addr_v6);
32694235Smarkfen if (IN6_IS_ADDR_UNSPECIFIED(&cptr->ips_src_mask_v6) &&
32704235Smarkfen shp != &hent) {
32714235Smarkfen init_addr_wildcard(&cptr->ips_src_mask_v6, isv4);
32724235Smarkfen }
32734235Smarkfen
32744235Smarkfen for (j = 0; dhp->h_addr_list[j] != NULL; j++) {
32754235Smarkfen bcopy(dhp->h_addr_list[j], &cptr->ips_dst_addr_v6,
32764235Smarkfen sizeof (struct in6_addr));
32774235Smarkfen if (IN6_IS_ADDR_UNSPECIFIED(&cptr->ips_src_addr_v6)) {
32784235Smarkfen /*
32794235Smarkfen * Src was not specified, so update isv4 flag
32804235Smarkfen * for this policy according to the family
32814235Smarkfen * of the destination address.
32824235Smarkfen */
32834235Smarkfen isv4 = cptr->ips_isv4 =
32844235Smarkfen IN6_IS_ADDR_V4MAPPED(
32855120Smarkfen &cptr->ips_dst_addr_v6);
32864235Smarkfen } else if ((dhp != &hent) && (isv4 !=
32874235Smarkfen IN6_IS_ADDR_V4MAPPED(&cptr->ips_dst_addr_v6))) {
32884235Smarkfen /* v6/v4 mismatch. */
32894235Smarkfen continue;
32904235Smarkfen }
32914235Smarkfen if (IN6_IS_ADDR_UNSPECIFIED(&cptr->ips_dst_mask_v6) &&
32924235Smarkfen dhp != &hent) {
32934235Smarkfen init_addr_wildcard(&cptr->ips_dst_mask_v6,
32944235Smarkfen isv4);
32954235Smarkfen }
32964235Smarkfen
32974235Smarkfen ret = send_pf_pol_message(SPD_ADDRULE, cptr, diag);
32984235Smarkfen
32994235Smarkfen if (ret == 0) {
33004235Smarkfen add_count++;
33014235Smarkfen } else {
33024235Smarkfen /* For now, allow duplicate/overlap policies. */
33034235Smarkfen if (ret != EEXIST) {
33044235Smarkfen /*
33054235Smarkfen * We have an error where we added
33064235Smarkfen * some, but had errors with others.
33074235Smarkfen * Undo the previous adds, and
33084235Smarkfen * bail.
33094235Smarkfen */
33104235Smarkfen rc = ret;
33114235Smarkfen goto bail;
33124235Smarkfen }
33134235Smarkfen }
33144235Smarkfen
33154235Smarkfen bzero(&cptr->ips_dst_mask_v6,
33164235Smarkfen sizeof (struct in6_addr));
33174235Smarkfen }
33184235Smarkfen
33194235Smarkfen bzero(&cptr->ips_src_mask_v6, sizeof (struct in6_addr));
33204235Smarkfen }
33214235Smarkfen
33224235Smarkfen bail:
33234235Smarkfen if (shp != &hent)
33244235Smarkfen freehostent(shp);
33254235Smarkfen shp = NULL;
33264235Smarkfen if (dhp != &hent)
33274235Smarkfen freehostent(dhp);
33284235Smarkfen dhp = NULL;
33294235Smarkfen splen = 0;
33304235Smarkfen dplen = 0;
33314235Smarkfen
33324235Smarkfen if ((add_count == 0) && (rc == 0)) {
33334235Smarkfen /*
33344235Smarkfen * No entries were added. We failed all adds
33354235Smarkfen * because the entries already existed, or because
33364235Smarkfen * no v4 or v6 src/dst pairs were found. Either way,
33374235Smarkfen * we must fail here with an appropriate error
33384235Smarkfen * to avoid a corresponding entry from being added
33394235Smarkfen * to ipsecpolicy.conf.
33404235Smarkfen */
33414235Smarkfen if ((ret == EEXIST)) {
33424235Smarkfen /* All adds failed with EEXIST */
33434235Smarkfen rc = EEXIST;
33444235Smarkfen } else {
33454235Smarkfen /* No matching v4 or v6 src/dst pairs */
33464235Smarkfen rc = ESRCH;
33474235Smarkfen }
33484235Smarkfen }
33494235Smarkfen
33504235Smarkfen return (rc);
33514235Smarkfen }
33524235Smarkfen
33534235Smarkfen static int
parse_mask(int type,char * mask_str,ips_conf_t * cptr)33544235Smarkfen parse_mask(int type, char *mask_str, ips_conf_t *cptr)
33554235Smarkfen {
33564235Smarkfen struct in_addr mask;
33574235Smarkfen struct in6_addr *mask6;
33584235Smarkfen
33594235Smarkfen if (type == IPSEC_CONF_SRC_MASK) {
33604235Smarkfen mask6 = &cptr->ips_src_mask_v6;
33614235Smarkfen } else {
33624235Smarkfen mask6 = &cptr->ips_dst_mask_v6;
33634235Smarkfen }
33644235Smarkfen
33654235Smarkfen if ((strncasecmp(mask_str, "0x", 2) == 0) &&
33664235Smarkfen (strchr(mask_str, '.') == NULL)) {
33674235Smarkfen /* Is it in the form 0xff000000 ? */
33684235Smarkfen char *end;
33694235Smarkfen
33704235Smarkfen mask.s_addr = strtoul(mask_str, &end, 0);
33714235Smarkfen if (end == mask_str) {
33724235Smarkfen return (-1);
33734235Smarkfen }
33744235Smarkfen if (*end != '\0') {
33754235Smarkfen return (-1);
33764235Smarkfen }
33774235Smarkfen mask.s_addr = htonl(mask.s_addr);
33784235Smarkfen } else {
33794235Smarkfen /*
33804235Smarkfen * Since inet_addr() returns -1 on error, we have
33814235Smarkfen * to convert a broadcast address ourselves.
33824235Smarkfen */
33834235Smarkfen if (strcmp(mask_str, "255.255.255.255") == 0) {
33844235Smarkfen mask.s_addr = 0xffffffff;
33854235Smarkfen } else {
33864235Smarkfen mask.s_addr = inet_addr(mask_str);
33874235Smarkfen if (mask.s_addr == (unsigned int)-1)
33884235Smarkfen return (-1);
33894235Smarkfen }
33904235Smarkfen }
33914235Smarkfen
33924235Smarkfen /* Should we check for non-contiguous masks ? */
33934235Smarkfen if (mask.s_addr == 0)
33944235Smarkfen return (-1);
33954235Smarkfen IN6_INADDR_TO_V4MAPPED(&mask, mask6);
33964235Smarkfen
33974235Smarkfen
33984235Smarkfen if (type == IPSEC_CONF_SRC_MASK) {
33994235Smarkfen cptr->ips_src_mask_len = in_masktoprefix(mask6->s6_addr,
34004235Smarkfen B_TRUE);
34014235Smarkfen } else {
34024235Smarkfen cptr->ips_dst_mask_len = in_masktoprefix(mask6->s6_addr,
34034235Smarkfen B_TRUE);
34044235Smarkfen }
34054235Smarkfen
34064235Smarkfen return (0);
34074235Smarkfen }
34084235Smarkfen
34094235Smarkfen static int
parse_port(int type,char * port_str,ips_conf_t * conf)34104235Smarkfen parse_port(int type, char *port_str, ips_conf_t *conf)
34114235Smarkfen {
34124235Smarkfen struct servent *sent;
34134235Smarkfen in_port_t port;
34144235Smarkfen int ret;
34154235Smarkfen
34164235Smarkfen sent = getservbyname(port_str, NULL);
34174235Smarkfen if (sent == NULL) {
34184235Smarkfen ret = parse_int(port_str);
34194235Smarkfen if (ret < 0 || ret >= 65536) {
34204235Smarkfen return (-1);
34214235Smarkfen }
34224235Smarkfen port = htons((in_port_t)ret);
34234235Smarkfen } else {
34244235Smarkfen port = sent->s_port;
34254235Smarkfen }
34264235Smarkfen if (type == IPSEC_CONF_SRC_PORT) {
34274235Smarkfen conf->ips_src_port_min = conf->ips_src_port_max = port;
34284235Smarkfen } else {
34294235Smarkfen conf->ips_dst_port_min = conf->ips_dst_port_max = port;
34304235Smarkfen }
34314235Smarkfen return (0);
34324235Smarkfen }
34334235Smarkfen
343410824SMark.Fenwick@Sun.COM static boolean_t
combined_mode(uint_t alg_id)343512131Sdanmcd@opensolaris.org combined_mode(uint_t alg_id)
343610824SMark.Fenwick@Sun.COM {
343710824SMark.Fenwick@Sun.COM struct ipsecalgent *alg;
343812131Sdanmcd@opensolaris.org boolean_t rc;
343912131Sdanmcd@opensolaris.org
344012131Sdanmcd@opensolaris.org alg = getipsecalgbynum(alg_id, IPSEC_PROTO_ESP, NULL);
344112131Sdanmcd@opensolaris.org if (alg != NULL) {
344212131Sdanmcd@opensolaris.org rc = (ALG_FLAG_COMBINED & alg->a_alg_flags);
344310824SMark.Fenwick@Sun.COM freeipsecalgent(alg);
344412131Sdanmcd@opensolaris.org } else {
344512131Sdanmcd@opensolaris.org rc = B_FALSE;
344612131Sdanmcd@opensolaris.org }
344712131Sdanmcd@opensolaris.org
344812131Sdanmcd@opensolaris.org return (rc);
344910824SMark.Fenwick@Sun.COM }
345010824SMark.Fenwick@Sun.COM
34514235Smarkfen static int
valid_algorithm(int proto_num,const char * str)34524235Smarkfen valid_algorithm(int proto_num, const char *str)
34534235Smarkfen {
34544235Smarkfen const char *tmp;
34554235Smarkfen int ret;
34564235Smarkfen struct ipsecalgent *alg;
34574235Smarkfen
34584235Smarkfen /* Short-circuit "none" */
34594235Smarkfen if (strncasecmp("none", str, 5) == 0)
34604235Smarkfen return (-2);
34614235Smarkfen
34624235Smarkfen alg = getipsecalgbyname(str, proto_num, NULL);
34634235Smarkfen if (alg != NULL) {
34644235Smarkfen ret = alg->a_alg_num;
34654235Smarkfen freeipsecalgent(alg);
34664235Smarkfen return (ret);
34674235Smarkfen }
34684235Smarkfen
34694235Smarkfen /*
34704235Smarkfen * Look whether it could be a valid number.
34714235Smarkfen * We support numbers also so that users can
34724235Smarkfen * load algorithms as they need it. We can't
34734235Smarkfen * check for validity of numbers here. It will
34744235Smarkfen * be checked when the SA is negotiated/looked up.
34754235Smarkfen * parse_int uses strtol(str), which converts 3DES
34764235Smarkfen * to a valid number i.e looks only at initial
34774235Smarkfen * number part. If we come here we should expect
34784235Smarkfen * only a decimal number.
34794235Smarkfen */
34804235Smarkfen tmp = str;
34814235Smarkfen while (*tmp) {
34824235Smarkfen if (!isdigit(*tmp))
34834235Smarkfen return (-1);
34844235Smarkfen tmp++;
34854235Smarkfen }
34864235Smarkfen
34874235Smarkfen ret = parse_int(str);
34884235Smarkfen if (ret > 0 && ret <= 255)
34894235Smarkfen return (ret);
34904235Smarkfen else
34914235Smarkfen return (-1);
34924235Smarkfen }
34934235Smarkfen
34944235Smarkfen static int
parse_ipsec_alg(char * str,ips_act_props_t * iap,int alg_type)34954235Smarkfen parse_ipsec_alg(char *str, ips_act_props_t *iap, int alg_type)
34964235Smarkfen {
34974235Smarkfen int alg_value;
349811136SMark.Fenwick@Sun.COM int remainder;
34994235Smarkfen char tstr[VALID_ALG_LEN];
35004235Smarkfen char *lens = NULL;
35014235Smarkfen char *l1_str;
35024235Smarkfen int l1 = 0;
35034235Smarkfen char *l2_str;
35044235Smarkfen int l2 = SPD_MAX_MAXBITS;
35054235Smarkfen algreq_t *ap;
35064235Smarkfen uint_t a_type;
35074235Smarkfen
35084235Smarkfen fetch_algorithms();
35094235Smarkfen
35104235Smarkfen /*
35114235Smarkfen * Make sure that we get a null terminated string.
35124235Smarkfen * For a bad input, we truncate at VALID_ALG_LEN.
35134235Smarkfen */
351411136SMark.Fenwick@Sun.COM remainder = strlen(str);
35154235Smarkfen (void) strlcpy(tstr, str, VALID_ALG_LEN);
35164235Smarkfen lens = strtok(tstr, "()");
351711136SMark.Fenwick@Sun.COM remainder -= strlen(lens);
35184235Smarkfen lens = strtok(NULL, "()");
35194235Smarkfen
35204235Smarkfen if (lens != NULL) {
35214235Smarkfen int len1 = 0;
35224235Smarkfen int len2 = SPD_MAX_MAXBITS;
35234235Smarkfen int len_all = strlen(lens);
35244235Smarkfen int dot_start = (lens[0] == '.');
352511136SMark.Fenwick@Sun.COM
352611136SMark.Fenwick@Sun.COM /*
352711136SMark.Fenwick@Sun.COM * Check to see if the keylength arg is at the end of the
352811136SMark.Fenwick@Sun.COM * token, the "()" is 2 characters.
352911136SMark.Fenwick@Sun.COM */
353011136SMark.Fenwick@Sun.COM remainder -= strlen(lens);
353111136SMark.Fenwick@Sun.COM if (remainder > 2)
353211136SMark.Fenwick@Sun.COM return (1);
353311136SMark.Fenwick@Sun.COM
35344235Smarkfen l1_str = strtok(lens, ".");
35354235Smarkfen l2_str = strtok(NULL, ".");
35364235Smarkfen if (l1_str != NULL) {
35374235Smarkfen l1 = parse_int(l1_str);
35384235Smarkfen len1 = strlen(l1_str);
35394235Smarkfen if (len1 < 0)
35404235Smarkfen return (1);
35414235Smarkfen }
35424235Smarkfen if (l2_str != NULL) {
35434235Smarkfen l2 = parse_int(l2_str);
35444235Smarkfen len2 = strlen(l2_str);
35454235Smarkfen if (len2 < 0)
35464235Smarkfen return (1);
35474235Smarkfen }
35484235Smarkfen
35494235Smarkfen if (len_all == len1) {
35504235Smarkfen /* alg(n) */
35514235Smarkfen l2 = l1;
35524235Smarkfen } else if (dot_start) {
35534235Smarkfen /* alg(..n) */
35544235Smarkfen l2 = l1;
35554235Smarkfen l1 = 0;
35564235Smarkfen } else if ((len_all - 2) == len1) {
35574235Smarkfen /* alg(n..) */
35584235Smarkfen l2 = SPD_MAX_MAXBITS;
35594235Smarkfen } /* else alg(n..m) */
35604235Smarkfen }
35614235Smarkfen
35624235Smarkfen if (alg_type == SPD_ATTR_AH_AUTH ||
35634235Smarkfen alg_type == SPD_ATTR_ESP_AUTH) {
35644235Smarkfen alg_value = valid_algorithm(IPSEC_PROTO_AH, tstr);
35654235Smarkfen } else {
35664235Smarkfen alg_value = valid_algorithm(IPSEC_PROTO_ESP, tstr);
35674235Smarkfen }
35684235Smarkfen if (alg_value < 0) {
35694235Smarkfen /* Invalid algorithm or "none" */
35704235Smarkfen return (alg_value);
35714235Smarkfen }
35724235Smarkfen
35734235Smarkfen if (alg_type == SPD_ATTR_AH_AUTH) {
35744235Smarkfen a_type = AH_AUTH;
35754235Smarkfen iap->iap_attr |= SPD_APPLY_AH;
35764235Smarkfen ap = &(iap->iap_aauth);
35774235Smarkfen } else if (alg_type == SPD_ATTR_ESP_AUTH) {
35784235Smarkfen a_type = ESP_AUTH;
35794235Smarkfen iap->iap_attr |= SPD_APPLY_ESP|SPD_APPLY_ESPA;
35804235Smarkfen ap = &(iap->iap_eauth);
35814235Smarkfen } else {
35824235Smarkfen a_type = ESP_ENCR;
35834235Smarkfen iap->iap_attr |= SPD_APPLY_ESP;
35844235Smarkfen ap = &(iap->iap_eencr);
35854235Smarkfen }
35864235Smarkfen
35874235Smarkfen ap->alg_id = alg_value;
35884235Smarkfen ap->alg_minbits = l1;
35894235Smarkfen ap->alg_maxbits = l2;
35904235Smarkfen
35914235Smarkfen if (!alg_rangecheck(a_type, alg_value, ap))
35924235Smarkfen return (1);
35934235Smarkfen
35944235Smarkfen return (0);
35954235Smarkfen }
35964235Smarkfen
35974235Smarkfen static char *
sys_error_message(int syserr)35984235Smarkfen sys_error_message(int syserr)
35994235Smarkfen {
36004235Smarkfen char *mesg;
36014235Smarkfen
36024235Smarkfen switch (syserr) {
36034235Smarkfen case EEXIST:
36044235Smarkfen mesg = gettext("Entry already exists");
36054235Smarkfen break;
36064235Smarkfen case ENOENT:
36074235Smarkfen mesg = gettext("Tunnel not found");
36084235Smarkfen break;
36094235Smarkfen case EINVAL:
36104235Smarkfen mesg = gettext("Invalid entry");
36114235Smarkfen break;
36124235Smarkfen default :
36134235Smarkfen mesg = strerror(syserr);
36144235Smarkfen }
36154235Smarkfen return (mesg);
36164235Smarkfen }
36174235Smarkfen
36184235Smarkfen static void
error_message(error_type_t error,int type,int line)36194235Smarkfen error_message(error_type_t error, int type, int line)
36204235Smarkfen {
36214235Smarkfen char *mesg;
36224235Smarkfen
36234235Smarkfen switch (type) {
36244235Smarkfen case IPSEC_CONF_SRC_ADDRESS:
36254235Smarkfen mesg = gettext("Source Address");
36264235Smarkfen break;
36274235Smarkfen case IPSEC_CONF_DST_ADDRESS:
36284235Smarkfen mesg = gettext("Destination Address");
36294235Smarkfen break;
36304235Smarkfen case IPSEC_CONF_SRC_PORT:
36314235Smarkfen mesg = gettext("Source Port");
36324235Smarkfen break;
36334235Smarkfen case IPSEC_CONF_DST_PORT:
36344235Smarkfen mesg = gettext("Destination Port");
36354235Smarkfen break;
36364235Smarkfen case IPSEC_CONF_SRC_MASK:
36374235Smarkfen mesg = gettext("Source Mask");
36384235Smarkfen break;
36394235Smarkfen case IPSEC_CONF_DST_MASK:
36404235Smarkfen mesg = gettext("Destination Mask");
36414235Smarkfen break;
36424235Smarkfen case IPSEC_CONF_ULP:
36434235Smarkfen mesg = gettext("Upper Layer Protocol");
36444235Smarkfen break;
36454235Smarkfen case IPSEC_CONF_IPSEC_AALGS:
36464235Smarkfen mesg = gettext("Authentication Algorithm");
36474235Smarkfen break;
36484235Smarkfen case IPSEC_CONF_IPSEC_EALGS:
36494235Smarkfen mesg = gettext("Encryption Algorithm");
36504235Smarkfen break;
36514235Smarkfen case IPSEC_CONF_IPSEC_EAALGS:
36524235Smarkfen mesg = gettext("ESP Authentication Algorithm");
36534235Smarkfen break;
36544235Smarkfen case IPSEC_CONF_IPSEC_SA:
36554235Smarkfen mesg = gettext("SA");
36564235Smarkfen break;
36574235Smarkfen case IPSEC_CONF_IPSEC_DIR:
36584235Smarkfen mesg = gettext("Direction");
36594235Smarkfen break;
36604235Smarkfen case IPSEC_CONF_ICMP_TYPE:
36614235Smarkfen mesg = gettext("ICMP type");
36624235Smarkfen break;
36634235Smarkfen case IPSEC_CONF_ICMP_CODE:
36644235Smarkfen mesg = gettext("ICMP code");
36654235Smarkfen break;
36664235Smarkfen case IPSEC_CONF_NEGOTIATE:
36674235Smarkfen mesg = gettext("Negotiate");
36684235Smarkfen break;
36694235Smarkfen case IPSEC_CONF_TUNNEL:
36704235Smarkfen mesg = gettext("Tunnel");
36714235Smarkfen break;
36724235Smarkfen default :
36734235Smarkfen return;
36744235Smarkfen }
36754235Smarkfen /*
36764235Smarkfen * If we never read a newline character, we don't want
36774235Smarkfen * to print 0.
36784235Smarkfen */
36794235Smarkfen warnx(gettext("%s%s%s %s on line: %d"),
36804235Smarkfen (error == BAD_ERROR) ? gettext("Bad") : "",
36814235Smarkfen (error == DUP_ERROR) ? gettext("Duplicate") : "",
36824235Smarkfen (error == REQ_ERROR) ? gettext("Requires") : "",
36834235Smarkfen mesg,
36844235Smarkfen (arg_indices[line] == 0) ? 1 : arg_indices[line]);
36854235Smarkfen }
36864235Smarkfen
36874235Smarkfen static int
validate_properties(ips_act_props_t * cptr,boolean_t dir,boolean_t is_alg)36884235Smarkfen validate_properties(ips_act_props_t *cptr, boolean_t dir, boolean_t is_alg)
36894235Smarkfen {
36904235Smarkfen if (cptr->iap_action == SPD_ACTTYPE_PASS ||
36915120Smarkfen cptr->iap_action == SPD_ACTTYPE_DROP) {
36924235Smarkfen if (!dir) {
36934235Smarkfen warnx(gettext("dir string "
36944235Smarkfen "not found for bypass policy"));
36954235Smarkfen }
36964235Smarkfen
36974235Smarkfen if (is_alg) {
36984235Smarkfen warnx(gettext("Algorithms found for bypass policy"));
36994235Smarkfen return (-1);
37004235Smarkfen }
37014235Smarkfen return (0);
37024235Smarkfen }
37034235Smarkfen if (!is_alg) {
37044235Smarkfen warnx(gettext("No IPsec algorithms given"));
37054235Smarkfen return (-1);
37064235Smarkfen }
37074235Smarkfen if (cptr->iap_attr == 0) {
37084235Smarkfen warnx(gettext("No SA attribute"));
37094235Smarkfen return (-1);
37104235Smarkfen }
37114235Smarkfen return (0);
37124235Smarkfen }
37134235Smarkfen
37144235Smarkfen /*
37154235Smarkfen * This function is called only to parse a single rule's worth of
37164235Smarkfen * action strings. This is called after parsing pattern and before
37174235Smarkfen * parsing properties. Thus we may have something in the leftover
37184235Smarkfen * buffer while parsing the pattern, which we need to handle here.
37194235Smarkfen */
37204235Smarkfen static int
parse_action(FILE * fp,char ** action,char ** leftover)37214235Smarkfen parse_action(FILE *fp, char **action, char **leftover)
37224235Smarkfen {
37234235Smarkfen char *cp;
37244235Smarkfen char ibuf[MAXLEN];
37254235Smarkfen char *tmp_buf;
37264235Smarkfen char *buf;
37274235Smarkfen boolean_t new_stuff;
37284235Smarkfen
37294235Smarkfen if (*leftover != NULL) {
37304235Smarkfen buf = *leftover;
37314235Smarkfen new_stuff = B_FALSE;
37324235Smarkfen goto scan;
37334235Smarkfen }
37344235Smarkfen while (fgets(ibuf, MAXLEN, fp) != NULL) {
37354235Smarkfen new_stuff = B_TRUE;
37364235Smarkfen if (ibuf[strlen(ibuf) - 1] == '\n')
37374235Smarkfen linecount++;
37384235Smarkfen buf = ibuf;
37394235Smarkfen scan:
37404235Smarkfen /* Truncate at the beginning of a comment */
37414235Smarkfen cp = strchr(buf, '#');
37424235Smarkfen if (cp != NULL)
37434235Smarkfen *cp = NULL;
37444235Smarkfen
37454235Smarkfen /* Skip any whitespace */
37464235Smarkfen while (*buf != NULL && isspace(*buf))
37474235Smarkfen buf++;
37484235Smarkfen
37494235Smarkfen /* Empty line */
37504235Smarkfen if (*buf == NULL)
37514235Smarkfen continue;
37524235Smarkfen
37534235Smarkfen /*
37544235Smarkfen * Store the command for error reporting
37554235Smarkfen * and ipsec_conf_add().
37564235Smarkfen */
37574235Smarkfen if (new_stuff) {
37584235Smarkfen /*
37594235Smarkfen * Check for buffer overflow including the null
37604235Smarkfen * terminating character.
37614235Smarkfen */
37624235Smarkfen int len = strlen(ibuf);
37634235Smarkfen if ((cbuf_offset + len + 1) >= CBUF_LEN)
37644235Smarkfen return (-1);
37655120Smarkfen
37664235Smarkfen (void) strcpy(cbuf + cbuf_offset, ibuf);
37674235Smarkfen cbuf_offset += len;
37684235Smarkfen }
37694235Smarkfen /*
37704235Smarkfen * Start of the non-empty non-space character.
37714235Smarkfen */
37725120Smarkfen tmp_buf = buf;
37734235Smarkfen
37744235Smarkfen /* Skip until next whitespace or CURL_BEGIN */
37754235Smarkfen while (*buf != NULL && !isspace(*buf) &&
37764235Smarkfen *buf != CURL_BEGIN)
37774235Smarkfen buf++;
37784235Smarkfen
37794235Smarkfen if (*buf != NULL) {
37805120Smarkfen if (tmp_buf == buf) /* No action token */
37815120Smarkfen goto error;
37824235Smarkfen if (*buf == CURL_BEGIN) {
37834235Smarkfen *buf = NULL;
37844235Smarkfen /* Allocate an extra byte for the null also */
37854235Smarkfen if ((*action = malloc(strlen(tmp_buf) + 1)) ==
37864235Smarkfen NULL) {
37874235Smarkfen warn("malloc");
37884235Smarkfen return (ENOMEM);
37894235Smarkfen }
37904235Smarkfen (void) strcpy(*action, tmp_buf);
37914235Smarkfen *buf = CURL_BEGIN;
37924235Smarkfen } else {
37934235Smarkfen /* We have hit a space */
37944235Smarkfen *buf++ = NULL;
37954235Smarkfen /* Allocate an extra byte for the null also */
37964235Smarkfen if ((*action = malloc(strlen(tmp_buf) + 1)) ==
37974235Smarkfen NULL) {
37984235Smarkfen warn("malloc");
37994235Smarkfen return (ENOMEM);
38004235Smarkfen }
38014235Smarkfen (void) strcpy(*action, tmp_buf);
38024235Smarkfen }
38034235Smarkfen /*
38044235Smarkfen * Copy the rest of the line into the
38054235Smarkfen * leftover buffer.
38064235Smarkfen */
38074235Smarkfen if (*buf != NULL) {
38084235Smarkfen (void) strlcpy(lo_buf, buf, sizeof (lo_buf));
38094235Smarkfen *leftover = lo_buf;
38104235Smarkfen } else {
38114235Smarkfen *leftover = NULL;
38124235Smarkfen }
38134235Smarkfen } else {
38144235Smarkfen /* Allocate an extra byte for the null also */
38154235Smarkfen if ((*action = malloc(strlen(tmp_buf) + 1)) ==
38164235Smarkfen NULL) {
38174235Smarkfen warn("malloc");
38184235Smarkfen return (ENOMEM);
38194235Smarkfen }
38204235Smarkfen (void) strcpy(*action, tmp_buf);
38214235Smarkfen *leftover = NULL;
38224235Smarkfen }
38235120Smarkfen if (argindex >= ARG_BUF_LEN) {
38245120Smarkfen warnx(gettext("(parsing one command) "
38255120Smarkfen "Too many selectors before action."));
38264235Smarkfen return (-1);
38275120Smarkfen }
38284235Smarkfen arg_indices[argindex++] = linecount;
38294235Smarkfen return (PARSE_SUCCESS);
38304235Smarkfen }
38314235Smarkfen /*
38324235Smarkfen * Return error, on an empty action field.
38334235Smarkfen */
38345120Smarkfen error:
38355120Smarkfen warnx(gettext("(parsing one command) "
38365120Smarkfen "Missing action token."));
38374235Smarkfen return (-1);
38384235Smarkfen }
38394235Smarkfen
38404235Smarkfen /*
38414235Smarkfen * This is called to parse pattern or properties that is enclosed
38424235Smarkfen * between CURL_BEGIN and CURL_END.
38434235Smarkfen */
38444235Smarkfen static int
parse_pattern_or_prop(FILE * fp,char * argvec[],char ** leftover)38454235Smarkfen parse_pattern_or_prop(FILE *fp, char *argvec[], char **leftover)
38464235Smarkfen {
38474235Smarkfen char *cp;
38484235Smarkfen int i = 0;
38494235Smarkfen boolean_t curl_begin_seen = B_FALSE;
38504235Smarkfen char ibuf[MAXLEN];
38514235Smarkfen char *tmp_buf;
38524235Smarkfen char *buf;
38534235Smarkfen boolean_t new_stuff;
38544235Smarkfen
38554235Smarkfen /*
38564235Smarkfen * When parsing properties, leftover buffer could have the
38574235Smarkfen * leftovers of the previous fgets().
38584235Smarkfen */
38594235Smarkfen if (*leftover != NULL) {
38604235Smarkfen buf = *leftover;
38614235Smarkfen new_stuff = B_FALSE;
38624235Smarkfen goto scan;
38634235Smarkfen }
38644235Smarkfen while (fgets(ibuf, MAXLEN, fp) != NULL) {
38654235Smarkfen new_stuff = B_TRUE;
38664235Smarkfen #ifdef DEBUG_HEAVY
38674235Smarkfen (void) printf("%s\n", ibuf);
38684235Smarkfen #endif
38694235Smarkfen if (ibuf[strlen(ibuf) - 1] == '\n')
38704235Smarkfen linecount++;
38714235Smarkfen buf = ibuf;
38724235Smarkfen scan:
38734235Smarkfen /* Truncate at the beginning of a comment */
38744235Smarkfen cp = strchr(buf, '#');
38754235Smarkfen if (cp != NULL)
38764235Smarkfen *cp = NULL;
38774235Smarkfen
38784235Smarkfen /* Skip any whitespace */
38794235Smarkfen while (*buf != NULL && isspace(*buf))
38804235Smarkfen buf++;
38814235Smarkfen
38824235Smarkfen /* Empty line */
38834235Smarkfen if (*buf == NULL)
38844235Smarkfen continue;
38854235Smarkfen /*
38864235Smarkfen * Store the command for error reporting
38874235Smarkfen * and ipsec_conf_add().
38884235Smarkfen */
38894235Smarkfen if (new_stuff) {
38904235Smarkfen /*
38914235Smarkfen * Check for buffer overflow including the null
38924235Smarkfen * terminating character.
38934235Smarkfen */
38944235Smarkfen int len = strlen(ibuf);
38954235Smarkfen if ((cbuf_offset + len + 1) >= CBUF_LEN)
38964235Smarkfen return (-1);
38974235Smarkfen (void) strcpy(cbuf + cbuf_offset, ibuf);
38984235Smarkfen cbuf_offset += len;
38994235Smarkfen }
39004235Smarkfen /*
39014235Smarkfen * First non-space character should be
39024235Smarkfen * a curly bracket.
39034235Smarkfen */
39044235Smarkfen if (!curl_begin_seen) {
39054235Smarkfen if (*buf != CURL_BEGIN) {
39064235Smarkfen /*
39074235Smarkfen * If we never read a newline character,
39084235Smarkfen * we don't want to print 0.
39094235Smarkfen */
39105120Smarkfen warnx(gettext("line %d : pattern must start "
39115120Smarkfen "with \"%c\" character"),
39125120Smarkfen (linecount == 0) ? 1 : linecount,
39135120Smarkfen CURL_BEGIN);
39144235Smarkfen return (-1);
39154235Smarkfen }
39164235Smarkfen buf++;
39174235Smarkfen curl_begin_seen = B_TRUE;
39184235Smarkfen }
39194235Smarkfen /*
39204235Smarkfen * Arguments are separated by white spaces or
39214235Smarkfen * newlines. Scan till you see a CURL_END.
39224235Smarkfen */
39234235Smarkfen while (*buf != NULL) {
39244235Smarkfen if (*buf == CURL_END) {
39254235Smarkfen ret:
39264235Smarkfen *buf++ = NULL;
39274235Smarkfen /*
39284235Smarkfen * Copy the rest of the line into the
39294235Smarkfen * leftover buffer if any.
39304235Smarkfen */
39314235Smarkfen if (*buf != NULL) {
39324235Smarkfen (void) strlcpy(lo_buf, buf,
39334235Smarkfen sizeof (lo_buf));
39344235Smarkfen *leftover = lo_buf;
39354235Smarkfen } else {
39364235Smarkfen *leftover = NULL;
39374235Smarkfen }
39384235Smarkfen return (PARSE_SUCCESS);
39394235Smarkfen }
39404235Smarkfen /*
39414235Smarkfen * Skip any trailing whitespace until we see a
39424235Smarkfen * non white-space character.
39434235Smarkfen */
39444235Smarkfen while (*buf != NULL && isspace(*buf))
39454235Smarkfen buf++;
39464235Smarkfen
39474235Smarkfen if (*buf == CURL_END)
39484235Smarkfen goto ret;
39494235Smarkfen
39504235Smarkfen /* Scan the next line as this buffer is empty */
39514235Smarkfen if (*buf == NULL)
39524235Smarkfen break;
39534235Smarkfen
39544235Smarkfen if (i >= MAXARGS) {
39554235Smarkfen warnx(
39564235Smarkfen gettext("Number of Arguments exceeded %d"),
39574235Smarkfen i);
39584235Smarkfen return (-1);
39594235Smarkfen }
39604235Smarkfen /*
39614235Smarkfen * Non-empty, Non-space buffer.
39624235Smarkfen */
39634235Smarkfen tmp_buf = buf++;
39644235Smarkfen /*
39654235Smarkfen * Real scan of the argument takes place here.
39664235Smarkfen * Skip past till space or CURL_END.
39674235Smarkfen */
39684235Smarkfen while (*buf != NULL && !isspace(*buf) &&
39694235Smarkfen *buf != CURL_END) {
39704235Smarkfen buf++;
39714235Smarkfen }
39724235Smarkfen /*
39734235Smarkfen * Either a space or we have hit the CURL_END or
39744235Smarkfen * the real end.
39754235Smarkfen */
39764235Smarkfen if (*buf != NULL) {
39774235Smarkfen if (*buf == CURL_END) {
39784235Smarkfen *buf++ = NULL;
39794235Smarkfen if ((argvec[i] = malloc(strlen(tmp_buf)
39804235Smarkfen + 1)) == NULL) {
39814235Smarkfen warn("malloc");
39824235Smarkfen return (ENOMEM);
39834235Smarkfen }
39844235Smarkfen if (strlen(tmp_buf) != 0) {
39854235Smarkfen (void) strcpy(argvec[i],
39864235Smarkfen tmp_buf);
39874235Smarkfen if (argindex >= ARG_BUF_LEN)
39885120Smarkfen goto toomanyargs;
39894235Smarkfen arg_indices[argindex++] =
39904235Smarkfen linecount;
39914235Smarkfen }
39924235Smarkfen /*
39934235Smarkfen * Copy the rest of the line into the
39944235Smarkfen * leftover buffer.
39954235Smarkfen */
39964235Smarkfen if (*buf != NULL) {
39974235Smarkfen (void) strlcpy(lo_buf, buf,
39984235Smarkfen sizeof (lo_buf));
39994235Smarkfen *leftover = lo_buf;
40004235Smarkfen } else {
40014235Smarkfen *leftover = NULL;
40024235Smarkfen }
40034235Smarkfen return (PARSE_SUCCESS);
40044235Smarkfen } else {
40054235Smarkfen *buf++ = NULL;
40064235Smarkfen }
40074235Smarkfen }
40084235Smarkfen /*
40094235Smarkfen * Copy this argument and scan for the buffer more
40104235Smarkfen * if it is non-empty. If it is empty scan for
40114235Smarkfen * the next line.
40124235Smarkfen */
40134235Smarkfen if ((argvec[i] = malloc(strlen(tmp_buf) + 1)) ==
40144235Smarkfen NULL) {
40154235Smarkfen warn("malloc");
40164235Smarkfen return (ENOMEM);
40174235Smarkfen }
40184235Smarkfen (void) strcpy(argvec[i++], tmp_buf);
40195120Smarkfen if (argindex >= ARG_BUF_LEN) {
40205120Smarkfen /*
40215120Smarkfen * The number of tokens in a single policy entry
40225120Smarkfen * exceeds the number of buffers available to fully
40235120Smarkfen * parse the policy entry.
40245120Smarkfen */
40255120Smarkfen toomanyargs:
40265120Smarkfen warnx(gettext("(parsing one command) "
40275120Smarkfen "Too many tokens in single policy entry."));
40284235Smarkfen return (-1);
40295120Smarkfen }
40304235Smarkfen arg_indices[argindex++] = linecount;
40314235Smarkfen }
40324235Smarkfen }
40334235Smarkfen /*
40344235Smarkfen * If nothing is given in the file, it is okay.
40354235Smarkfen * If something is given in the file and it is
40364235Smarkfen * not CURL_BEGIN, we would have returned error
40374235Smarkfen * above. If curl_begin_seen and we are here,
40384235Smarkfen * something is wrong.
40394235Smarkfen */
40405120Smarkfen if (curl_begin_seen) {
40415120Smarkfen warnx(gettext("(parsing one command) "
40425120Smarkfen "Pattern or Properties incomplete."));
40434235Smarkfen return (-1);
40445120Smarkfen }
40454235Smarkfen return (PARSE_EOF); /* Nothing more in the file */
40464235Smarkfen }
40474235Smarkfen
40484235Smarkfen /*
40494235Smarkfen * Parse one command i.e {pattern} action {properties}.
40504235Smarkfen *
40514235Smarkfen * {pattern} ( action {prop} | pass | drop ) (or ...)*
40524235Smarkfen */
40534235Smarkfen static int
parse_one(FILE * fp,act_prop_t * act_props)40544235Smarkfen parse_one(FILE *fp, act_prop_t *act_props)
40554235Smarkfen {
40564235Smarkfen char *leftover;
40574235Smarkfen int ret;
40584235Smarkfen int i;
40594235Smarkfen int ap_num = 0;
40604235Smarkfen enum parse_state {pattern, action, prop } pstate;
40614235Smarkfen
40624235Smarkfen has_daprefix = has_saprefix = B_FALSE;
40634235Smarkfen
40644235Smarkfen (void) memset(act_props, 0, sizeof (act_prop_t));
40654235Smarkfen pstate = pattern;
40664235Smarkfen
40674235Smarkfen ret = 0;
40684235Smarkfen leftover = NULL;
40694235Smarkfen argindex = 0;
40704235Smarkfen cbuf_offset = 0;
40714235Smarkfen assert(shp == NULL && dhp == NULL);
40724235Smarkfen
40734235Smarkfen for (;;) {
40744235Smarkfen switch (pstate) {
40754235Smarkfen case pattern:
40764235Smarkfen {
40774235Smarkfen #ifdef DEBUG_HEAVY
40784235Smarkfen (void) printf("pattern\n");
40794235Smarkfen #endif
40804235Smarkfen ret = parse_pattern_or_prop(fp,
40814235Smarkfen act_props->pattern, &leftover);
40824235Smarkfen if (ret == PARSE_EOF) {
40834235Smarkfen /* EOF reached */
40845120Smarkfen return (PARSE_EOF);
40854235Smarkfen }
40864235Smarkfen if (ret != 0) {
40875120Smarkfen ret = -1;
40884235Smarkfen goto err;
40894235Smarkfen }
40904235Smarkfen pstate = action;
40914235Smarkfen break;
40924235Smarkfen }
40934235Smarkfen case action:
40944235Smarkfen {
40954235Smarkfen #ifdef DEBUG_HEAVY
40964235Smarkfen (void) printf("action\n");
40974235Smarkfen #endif
40984235Smarkfen ret = parse_action(fp,
40994235Smarkfen &act_props->ap[ap_num].act, &leftover);
41004235Smarkfen if (ret != 0) {
41015120Smarkfen ret = -1;
41024235Smarkfen goto err;
41034235Smarkfen }
41044235Smarkfen
41054235Smarkfen /*
41064235Smarkfen * Validate action now itself so that we don't
41074235Smarkfen * proceed too much into the bad world.
41084235Smarkfen */
41094235Smarkfen for (i = 0; action_table[i].string; i++) {
41104235Smarkfen if (strcmp(act_props->ap[ap_num].act,
41114235Smarkfen action_table[i].string) == 0)
41124235Smarkfen break;
41134235Smarkfen }
41144235Smarkfen
41154235Smarkfen if (action_table[i].tok_val == TOK_or) {
41164235Smarkfen /* hit an or, go again */
41174235Smarkfen break;
41184235Smarkfen }
41194235Smarkfen
41204235Smarkfen if (action_table[i].string == NULL) {
41214235Smarkfen /*
41224235Smarkfen * If we never read a newline
41234235Smarkfen * character, we don't want
41244235Smarkfen * to print 0.
41254235Smarkfen */
41265120Smarkfen warnx(gettext("(parsing one command) "
41274235Smarkfen "Invalid action on line %d: %s"),
41284235Smarkfen (linecount == 0) ? 1 : linecount,
41294235Smarkfen act_props->ap[ap_num].act);
41304235Smarkfen return (-1);
41314235Smarkfen }
41324235Smarkfen
41334235Smarkfen pstate = prop;
41344235Smarkfen break;
41354235Smarkfen }
41364235Smarkfen case prop:
41374235Smarkfen {
41384235Smarkfen #ifdef DEBUG_HEAVY
41394235Smarkfen (void) printf("prop\n");
41404235Smarkfen #endif
41414235Smarkfen ret = parse_pattern_or_prop(fp,
41424235Smarkfen act_props->ap[ap_num].prop, &leftover);
41434235Smarkfen if (ret != 0) {
41445120Smarkfen if (ret == PARSE_EOF) {
41455120Smarkfen warnx(gettext("(parsing one command) "
41465120Smarkfen "Missing properties."));
41475120Smarkfen }
41485120Smarkfen ret = -1;
41494235Smarkfen goto err;
41504235Smarkfen }
41514235Smarkfen
41524235Smarkfen if (leftover != NULL) {
41534235Smarkfen /* Accomodate spaces at the end */
41544235Smarkfen while (*leftover != NULL) {
41555120Smarkfen if (*leftover == BACK_SLASH) {
41565120Smarkfen warnx(gettext("Invalid line "
41575120Smarkfen "continuation character."));
41585120Smarkfen ret = -1;
41595120Smarkfen goto err;
41605120Smarkfen }
41614235Smarkfen if (*leftover == 'o') {
41624235Smarkfen leftover++;
41634235Smarkfen if (*leftover == 'r') {
41644235Smarkfen leftover++;
41654235Smarkfen ap_num++;
41664235Smarkfen pstate = action;
41674235Smarkfen goto again;
41684235Smarkfen }
41694235Smarkfen }
41704235Smarkfen if (!isspace(*leftover)) {
41714235Smarkfen ret = -1;
41724235Smarkfen goto err;
41734235Smarkfen }
41744235Smarkfen leftover++;
41754235Smarkfen }
41764235Smarkfen return (0);
41774235Smarkfen }
41784235Smarkfen ap_num++;
41794235Smarkfen if (ap_num > MAXARGS)
41804235Smarkfen return (0);
41814235Smarkfen pstate = action; /* or */
41824235Smarkfen break;
41834235Smarkfen } /* case prop: */
41844235Smarkfen } /* switch(pstate) */
41854235Smarkfen
41864235Smarkfen again:
41875120Smarkfen if (ap_num > MAXARGS) {
41885120Smarkfen warnx(gettext("Too many actions."));
41895120Smarkfen return (-1);
41905120Smarkfen }
41915120Smarkfen } /* for(;;) */
41924235Smarkfen err:
41934235Smarkfen if (ret != 0) {
41944235Smarkfen /*
41954235Smarkfen * If we never read a newline character, we don't want
41964235Smarkfen * to print 0.
41974235Smarkfen */
41984235Smarkfen warnx(gettext("Error before or at line %d"),
41994235Smarkfen (linecount == 0) ? 1 : linecount);
42004235Smarkfen }
42014235Smarkfen return (ret);
42024235Smarkfen }
42034235Smarkfen
42044235Smarkfen /*
42054235Smarkfen * convert an act_propts_t to an ips_conf_t
42064235Smarkfen */
42074235Smarkfen
42084235Smarkfen static int
form_ipsec_conf(act_prop_t * act_props,ips_conf_t * cptr)42094235Smarkfen form_ipsec_conf(act_prop_t *act_props, ips_conf_t *cptr)
42104235Smarkfen {
42114235Smarkfen int i, j, k;
42124235Smarkfen int tok_count = 0;
42134235Smarkfen struct protoent *pent;
42144235Smarkfen boolean_t saddr, daddr, ipsec_aalg, ipsec_ealg, ipsec_eaalg, dir;
421510372Sdanmcd@sun.com boolean_t old_style, new_style, auth_covered, is_no_alg;
421610824SMark.Fenwick@Sun.COM boolean_t is_combined_mode;
42174235Smarkfen struct in_addr mask;
42184235Smarkfen int line_no;
42194235Smarkfen int ret;
42204235Smarkfen int ap_num = 0;
42214235Smarkfen int type, code, type_end, code_end;
42224235Smarkfen #ifdef DEBUG_HEAVY
42234235Smarkfen /*
42244235Smarkfen * pattern => act_props->pattern
42254235Smarkfen * action => act_props->ap[].act
42264235Smarkfen * properties => act_props->ap[].prop
42274235Smarkfen */
42284235Smarkfen (void) printf("\npattern\n------------\n");
42294235Smarkfen for (i = 0; act_props->pattern[i] != NULL; i++)
42304235Smarkfen (void) printf("%s\n", act_props->pattern[i]);
42314235Smarkfen (void) printf("apz\n----------\n");
42324235Smarkfen for (j = 0; act_props->ap[j].act != NULL; j++) {
42334235Smarkfen
42344235Smarkfen (void) printf("act%d->%s\n", j, act_props->ap[j].act);
42354235Smarkfen for (i = 0; act_props->ap[j].prop[i] != NULL; i++)
42364235Smarkfen (void) printf("%dprop%d->%s\n",
42374235Smarkfen j, i, act_props->ap[j].prop[i]);
42384235Smarkfen }
42394235Smarkfen (void) printf("------------\n\n");
42404235Smarkfen #endif
42414235Smarkfen
42424235Smarkfen (void) memset(cptr, 0, sizeof (ips_conf_t));
42434235Smarkfen saddr = daddr = ipsec_aalg = ipsec_ealg = ipsec_eaalg = dir = B_FALSE;
424410824SMark.Fenwick@Sun.COM old_style = new_style = is_no_alg = is_combined_mode = B_FALSE;
42454235Smarkfen /*
42464235Smarkfen * Get the Pattern. NULL pattern is valid.
42474235Smarkfen */
42484235Smarkfen for (i = 0, line_no = 0; act_props->pattern[i]; i++, line_no++) {
42494235Smarkfen for (j = 0; pattern_table[j].string; j++) {
42504235Smarkfen if (strcmp(act_props->pattern[i],
42514235Smarkfen pattern_table[j].string) == 0)
42524235Smarkfen break;
42534235Smarkfen }
42544235Smarkfen
42554235Smarkfen if (pattern_table[j].string == NULL) {
42564235Smarkfen /*
42574235Smarkfen * If we never read a newline character, we don't want
42584235Smarkfen * to print 0.
42594235Smarkfen */
42604235Smarkfen warnx(gettext("Invalid pattern on line %d: %s"),
42614235Smarkfen (arg_indices[line_no] == 0) ? 1 :
42624235Smarkfen arg_indices[line_no], act_props->pattern[i]);
42634235Smarkfen return (-1);
42644235Smarkfen }
42654235Smarkfen
42664235Smarkfen cptr->patt_tok[tok_count++] = pattern_table[j].tok_val;
42674235Smarkfen
42684235Smarkfen switch (pattern_table[j].tok_val) {
42694235Smarkfen
42704235Smarkfen case TOK_dir:
42714235Smarkfen i++, line_no++;
42724235Smarkfen if (act_props->pattern[i] == NULL) {
42734235Smarkfen error_message(BAD_ERROR,
42744235Smarkfen IPSEC_CONF_IPSEC_DIR, line_no);
42754235Smarkfen return (-1);
42764235Smarkfen }
42774235Smarkfen
42784235Smarkfen if (strncmp(act_props->pattern[i], "in", 2) == 0) {
42794235Smarkfen cptr->ips_dir = SPD_RULE_FLAG_INBOUND;
42804235Smarkfen } else if (strncmp(
42814235Smarkfen act_props->pattern[i], "out", 3) == 0) {
42824235Smarkfen cptr->ips_dir = SPD_RULE_FLAG_OUTBOUND;
42834235Smarkfen } else if (strncmp(
42844235Smarkfen act_props->pattern[i], "both", 4) == 0) {
42854235Smarkfen if (old_style) {
42864235Smarkfen error_message(BAD_ERROR,
42874235Smarkfen IPSEC_CONF_IPSEC_DIR, line_no);
42884235Smarkfen return (-1);
42894235Smarkfen }
42904235Smarkfen new_style = B_TRUE;
42914235Smarkfen cptr->ips_dir =
42924235Smarkfen SPD_RULE_FLAG_OUTBOUND |
42934235Smarkfen SPD_RULE_FLAG_INBOUND;
42944235Smarkfen } else {
42954235Smarkfen error_message(BAD_ERROR,
42964235Smarkfen IPSEC_CONF_IPSEC_DIR, line_no);
42974235Smarkfen return (-1);
42984235Smarkfen }
42994235Smarkfen dir = B_TRUE;
43004235Smarkfen break;
43014235Smarkfen
43024235Smarkfen case TOK_local:
43034235Smarkfen if (old_style) {
43044235Smarkfen error_message(BAD_ERROR,
43054235Smarkfen IPSEC_CONF_SRC_ADDRESS, line_no);
43064235Smarkfen return (-1);
43074235Smarkfen }
43084235Smarkfen new_style = B_TRUE;
43094235Smarkfen
43104235Smarkfen if (saddr) {
43114235Smarkfen error_message(DUP_ERROR,
43124235Smarkfen IPSEC_CONF_SRC_ADDRESS, line_no);
43134235Smarkfen return (-1);
43144235Smarkfen }
43154235Smarkfen /*
43164235Smarkfen * Use this to detect duplicates rather
43174235Smarkfen * than 0 like other cases, because 0 for
43184235Smarkfen * address means INADDR_ANY.
43194235Smarkfen */
43204235Smarkfen saddr = B_TRUE;
43214235Smarkfen cptr->has_saddr = 1;
43224235Smarkfen /*
43234235Smarkfen * Advance to the string containing
43244235Smarkfen * the address.
43254235Smarkfen */
43264235Smarkfen i++, line_no++;
43274235Smarkfen if (act_props->pattern[i] == NULL) {
43284235Smarkfen error_message(BAD_ERROR,
43294235Smarkfen IPSEC_CONF_SRC_ADDRESS, line_no);
43304235Smarkfen return (-1);
43314235Smarkfen }
43324235Smarkfen if (parse_address(IPSEC_CONF_SRC_ADDRESS,
43334235Smarkfen act_props->pattern[i]) != 0) {
43344235Smarkfen error_message(BAD_ERROR,
43354235Smarkfen IPSEC_CONF_SRC_ADDRESS, line_no);
43364235Smarkfen return (-1);
43374235Smarkfen }
43384235Smarkfen if (!cptr->has_smask)
43394235Smarkfen cptr->has_smask = has_saprefix;
43404235Smarkfen
43414235Smarkfen break;
43424235Smarkfen case TOK_remote:
43434235Smarkfen if (old_style) {
43444235Smarkfen error_message(BAD_ERROR,
43454235Smarkfen IPSEC_CONF_DST_ADDRESS, line_no);
43464235Smarkfen return (-1);
43474235Smarkfen }
43484235Smarkfen new_style = B_TRUE;
43494235Smarkfen
43504235Smarkfen if (daddr) {
43514235Smarkfen error_message(DUP_ERROR,
43524235Smarkfen IPSEC_CONF_DST_ADDRESS, line_no);
43534235Smarkfen return (-1);
43544235Smarkfen }
43554235Smarkfen /*
43564235Smarkfen * Use this to detect duplicates rather
43574235Smarkfen * than 0 like other cases, because 0 for
43584235Smarkfen * address means INADDR_ANY.
43594235Smarkfen */
43604235Smarkfen daddr = B_TRUE;
43614235Smarkfen cptr->has_daddr = 1;
43624235Smarkfen /*
43634235Smarkfen * Advance to the string containing
43644235Smarkfen * the address.
43654235Smarkfen */
43664235Smarkfen i++, line_no++;
43674235Smarkfen if (act_props->pattern[i] == NULL) {
43684235Smarkfen error_message(BAD_ERROR,
43694235Smarkfen IPSEC_CONF_DST_ADDRESS, line_no);
43704235Smarkfen return (-1);
43714235Smarkfen }
43724235Smarkfen if (parse_address(IPSEC_CONF_DST_ADDRESS,
43734235Smarkfen act_props->pattern[i]) != 0) {
43744235Smarkfen error_message(BAD_ERROR,
43754235Smarkfen IPSEC_CONF_DST_ADDRESS, line_no);
43764235Smarkfen return (-1);
43774235Smarkfen }
43784235Smarkfen if (!cptr->has_dmask)
43794235Smarkfen cptr->has_dmask = has_daprefix;
43804235Smarkfen break;
43814235Smarkfen
43824235Smarkfen case TOK_saddr:
43834235Smarkfen if (new_style) {
43844235Smarkfen error_message(BAD_ERROR,
43854235Smarkfen IPSEC_CONF_SRC_ADDRESS, line_no);
43864235Smarkfen return (-1);
43874235Smarkfen }
43884235Smarkfen old_style = B_TRUE;
43894235Smarkfen
43904235Smarkfen if (saddr) {
43914235Smarkfen error_message(DUP_ERROR,
43924235Smarkfen IPSEC_CONF_SRC_ADDRESS, line_no);
43934235Smarkfen return (-1);
43944235Smarkfen }
43954235Smarkfen /*
43964235Smarkfen * Use this to detect duplicates rather
43974235Smarkfen * than 0 like other cases, because 0 for
43984235Smarkfen * address means INADDR_ANY.
43994235Smarkfen */
44004235Smarkfen saddr = B_TRUE;
44014235Smarkfen cptr->has_saddr = 1;
44024235Smarkfen /*
44034235Smarkfen * Advance to the string containing
44044235Smarkfen * the address.
44054235Smarkfen */
44064235Smarkfen i++, line_no++;
44074235Smarkfen if (act_props->pattern[i] == NULL) {
44084235Smarkfen error_message(BAD_ERROR,
44094235Smarkfen IPSEC_CONF_SRC_ADDRESS, line_no);
44104235Smarkfen return (-1);
44114235Smarkfen }
44124235Smarkfen
44134235Smarkfen if (parse_address(IPSEC_CONF_SRC_ADDRESS,
44144235Smarkfen act_props->pattern[i]) != 0) {
44154235Smarkfen error_message(BAD_ERROR,
44164235Smarkfen IPSEC_CONF_SRC_ADDRESS, line_no);
44174235Smarkfen return (-1);
44184235Smarkfen }
44194235Smarkfen /* shp or bhp? */
44204235Smarkfen if (!cptr->has_smask)
44214235Smarkfen cptr->has_smask = has_saprefix;
44224235Smarkfen break;
44234235Smarkfen
44244235Smarkfen case TOK_daddr:
44254235Smarkfen if (new_style) {
44264235Smarkfen error_message(BAD_ERROR,
44274235Smarkfen IPSEC_CONF_DST_ADDRESS, line_no);
44284235Smarkfen return (-1);
44294235Smarkfen }
44304235Smarkfen old_style = B_TRUE;
44314235Smarkfen
44324235Smarkfen if (daddr) {
44334235Smarkfen error_message(DUP_ERROR,
44344235Smarkfen IPSEC_CONF_DST_ADDRESS, line_no);
44354235Smarkfen return (-1);
44364235Smarkfen }
44374235Smarkfen /*
44384235Smarkfen * Use this to detect duplicates rather
44394235Smarkfen * than 0 like other cases, because 0 for
44404235Smarkfen * address means INADDR_ANY.
44414235Smarkfen */
44424235Smarkfen daddr = B_TRUE;
44434235Smarkfen cptr->has_daddr = 1;
44444235Smarkfen /*
44454235Smarkfen * Advance to the string containing
44464235Smarkfen * the address.
44474235Smarkfen */
44484235Smarkfen i++, line_no++;
44494235Smarkfen if (act_props->pattern[i] == NULL) {
44504235Smarkfen error_message(BAD_ERROR,
44514235Smarkfen IPSEC_CONF_DST_ADDRESS, line_no);
44524235Smarkfen return (-1);
44534235Smarkfen }
44544235Smarkfen if (parse_address(IPSEC_CONF_DST_ADDRESS,
44554235Smarkfen act_props->pattern[i]) != 0) {
44564235Smarkfen error_message(BAD_ERROR,
44574235Smarkfen IPSEC_CONF_DST_ADDRESS, line_no);
44584235Smarkfen return (-1);
44594235Smarkfen }
44604235Smarkfen if (!cptr->has_dmask)
44614235Smarkfen cptr->has_dmask = has_daprefix;
44624235Smarkfen break;
44634235Smarkfen
44644235Smarkfen case TOK_sport:
44654235Smarkfen if (new_style) {
44664235Smarkfen error_message(BAD_ERROR,
44674235Smarkfen IPSEC_CONF_SRC_PORT, line_no);
44684235Smarkfen return (-1);
44694235Smarkfen }
44704235Smarkfen old_style = B_TRUE;
44714235Smarkfen
44724235Smarkfen if (cptr->ips_src_port_min != 0) {
44734235Smarkfen error_message(DUP_ERROR, IPSEC_CONF_SRC_PORT,
44744235Smarkfen line_no);
44754235Smarkfen return (-1);
44764235Smarkfen }
44774235Smarkfen i++, line_no++;
44784235Smarkfen if (act_props->pattern[i] == NULL) {
44794235Smarkfen error_message(BAD_ERROR, IPSEC_CONF_SRC_PORT,
44804235Smarkfen line_no);
44814235Smarkfen return (-1);
44824235Smarkfen }
44834235Smarkfen ret = parse_port(IPSEC_CONF_SRC_PORT,
44844235Smarkfen act_props->pattern[i], cptr);
44854235Smarkfen if (ret != 0) {
44864235Smarkfen error_message(BAD_ERROR, IPSEC_CONF_SRC_PORT,
44874235Smarkfen line_no);
44884235Smarkfen return (-1);
44894235Smarkfen }
44904235Smarkfen break;
44914235Smarkfen case TOK_dport:
44924235Smarkfen if (new_style) {
44934235Smarkfen error_message(BAD_ERROR,
44944235Smarkfen IPSEC_CONF_DST_PORT, line_no);
44954235Smarkfen return (-1);
44964235Smarkfen }
44974235Smarkfen old_style = B_TRUE;
44984235Smarkfen
44994235Smarkfen if (cptr->ips_dst_port_min != 0) {
45004235Smarkfen error_message(DUP_ERROR, IPSEC_CONF_DST_PORT,
45014235Smarkfen line_no);
45024235Smarkfen return (-1);
45034235Smarkfen }
45044235Smarkfen i++, line_no++;
45054235Smarkfen if (act_props->pattern[i] == NULL) {
45064235Smarkfen error_message(BAD_ERROR, IPSEC_CONF_DST_PORT,
45074235Smarkfen line_no);
45084235Smarkfen return (-1);
45094235Smarkfen }
45104235Smarkfen ret = parse_port(IPSEC_CONF_DST_PORT,
45114235Smarkfen act_props->pattern[i],
45124235Smarkfen cptr);
45134235Smarkfen if (ret != 0) {
45144235Smarkfen error_message(BAD_ERROR, IPSEC_CONF_DST_PORT,
45154235Smarkfen line_no);
45164235Smarkfen return (-1);
45174235Smarkfen }
45184235Smarkfen break;
45194235Smarkfen
45204235Smarkfen case TOK_lport:
45214235Smarkfen if (old_style) {
45224235Smarkfen error_message(BAD_ERROR,
45234235Smarkfen IPSEC_CONF_SRC_PORT, line_no);
45244235Smarkfen return (-1);
45254235Smarkfen }
45264235Smarkfen new_style = B_TRUE;
45274235Smarkfen
45284235Smarkfen if (cptr->ips_src_port_min != 0) {
45294235Smarkfen error_message(DUP_ERROR, IPSEC_CONF_SRC_PORT,
45304235Smarkfen line_no);
45314235Smarkfen return (-1);
45324235Smarkfen }
45334235Smarkfen i++, line_no++;
45344235Smarkfen if (act_props->pattern[i] == NULL) {
45354235Smarkfen error_message(BAD_ERROR, IPSEC_CONF_SRC_PORT,
45364235Smarkfen line_no);
45374235Smarkfen return (-1);
45384235Smarkfen }
45394235Smarkfen ret = parse_port(IPSEC_CONF_SRC_PORT,
45404235Smarkfen act_props->pattern[i],
45414235Smarkfen cptr);
45424235Smarkfen if (ret != 0) {
45434235Smarkfen error_message(BAD_ERROR, IPSEC_CONF_SRC_PORT,
45444235Smarkfen line_no);
45454235Smarkfen return (-1);
45464235Smarkfen }
45474235Smarkfen break;
45484235Smarkfen
45494235Smarkfen case TOK_rport:
45504235Smarkfen if (old_style) {
45514235Smarkfen error_message(BAD_ERROR,
45524235Smarkfen IPSEC_CONF_DST_PORT, line_no);
45534235Smarkfen return (-1);
45544235Smarkfen }
45554235Smarkfen new_style = B_TRUE;
45564235Smarkfen
45574235Smarkfen if (cptr->ips_dst_port_min != 0) {
45584235Smarkfen error_message(DUP_ERROR, IPSEC_CONF_DST_PORT,
45594235Smarkfen line_no);
45604235Smarkfen return (-1);
45614235Smarkfen }
45624235Smarkfen i++, line_no++;
45634235Smarkfen if (act_props->pattern[i] == NULL) {
45644235Smarkfen error_message(BAD_ERROR, IPSEC_CONF_DST_PORT,
45654235Smarkfen line_no);
45664235Smarkfen return (-1);
45674235Smarkfen }
45684235Smarkfen ret = parse_port(IPSEC_CONF_DST_PORT,
45694235Smarkfen act_props->pattern[i],
45704235Smarkfen cptr);
45714235Smarkfen if (ret != 0) {
45724235Smarkfen error_message(BAD_ERROR, IPSEC_CONF_DST_PORT,
45734235Smarkfen line_no);
45744235Smarkfen return (-1);
45754235Smarkfen }
45764235Smarkfen break;
45774235Smarkfen
45784235Smarkfen case TOK_smask:
45794235Smarkfen if (new_style) {
45804235Smarkfen error_message(BAD_ERROR,
45814235Smarkfen IPSEC_CONF_SRC_MASK, line_no);
45824235Smarkfen return (-1);
45834235Smarkfen }
45844235Smarkfen old_style = B_TRUE;
45854235Smarkfen cptr->has_smask = B_TRUE;
45864235Smarkfen
45874235Smarkfen IN6_V4MAPPED_TO_INADDR(&cptr->ips_src_mask_v6, &mask);
45884235Smarkfen if (mask.s_addr != 0) {
45894235Smarkfen error_message(DUP_ERROR, IPSEC_CONF_SRC_MASK,
45904235Smarkfen line_no);
45914235Smarkfen return (-1);
45924235Smarkfen }
45934235Smarkfen i++, line_no++;
45944235Smarkfen if (act_props->pattern[i] == NULL) {
45954235Smarkfen error_message(BAD_ERROR, IPSEC_CONF_SRC_MASK,
45964235Smarkfen line_no);
45974235Smarkfen return (-1);
45984235Smarkfen }
45994235Smarkfen ret = parse_mask(IPSEC_CONF_SRC_MASK,
46004235Smarkfen act_props->pattern[i],
46014235Smarkfen cptr);
46024235Smarkfen if (ret != 0) {
46034235Smarkfen error_message(BAD_ERROR, IPSEC_CONF_SRC_MASK,
46044235Smarkfen line_no);
46054235Smarkfen return (-1);
46064235Smarkfen }
46074235Smarkfen break;
46084235Smarkfen case TOK_dmask:
46094235Smarkfen if (new_style) {
46104235Smarkfen error_message(BAD_ERROR,
46114235Smarkfen IPSEC_CONF_DST_MASK, line_no);
46124235Smarkfen return (-1);
46134235Smarkfen }
46144235Smarkfen old_style = B_TRUE;
46154235Smarkfen cptr->has_dmask = B_TRUE;
46164235Smarkfen
46174235Smarkfen IN6_V4MAPPED_TO_INADDR(&cptr->ips_dst_mask_v6, &mask);
46184235Smarkfen if (mask.s_addr != 0) {
46194235Smarkfen error_message(DUP_ERROR, IPSEC_CONF_DST_MASK,
46204235Smarkfen line_no);
46214235Smarkfen return (-1);
46224235Smarkfen }
46234235Smarkfen i++, line_no++;
46244235Smarkfen if (act_props->pattern[i] == NULL) {
46254235Smarkfen error_message(BAD_ERROR, IPSEC_CONF_DST_MASK,
46264235Smarkfen line_no);
46274235Smarkfen return (-1);
46284235Smarkfen }
46294235Smarkfen ret = parse_mask(IPSEC_CONF_DST_MASK,
46304235Smarkfen act_props->pattern[i],
46314235Smarkfen cptr);
46324235Smarkfen if (ret != 0) {
46334235Smarkfen error_message(BAD_ERROR, IPSEC_CONF_DST_MASK,
46344235Smarkfen line_no);
46354235Smarkfen return (-1);
46364235Smarkfen }
46374235Smarkfen break;
46384235Smarkfen case TOK_ulp:
46394235Smarkfen if (cptr->ips_ulp_prot != 0) {
46404235Smarkfen error_message(DUP_ERROR,
46414235Smarkfen IPSEC_CONF_ULP, line_no);
46424235Smarkfen return (-1);
46434235Smarkfen }
46444235Smarkfen i++, line_no++;
46454235Smarkfen if (act_props->pattern[i] == NULL) {
46464235Smarkfen error_message(BAD_ERROR,
46474235Smarkfen IPSEC_CONF_ULP, line_no);
46484235Smarkfen return (-1);
46494235Smarkfen }
46504235Smarkfen pent = getprotobyname(act_props->pattern[i]);
46514235Smarkfen if (pent == NULL) {
46524235Smarkfen int ulp;
46534235Smarkfen ulp = parse_int(act_props->pattern[i]);
46544235Smarkfen if (ulp == -1) {
46554235Smarkfen error_message(BAD_ERROR,
46564235Smarkfen IPSEC_CONF_ULP, line_no);
46574235Smarkfen return (-1);
46584235Smarkfen }
46594235Smarkfen cptr->ips_ulp_prot = ulp;
46604235Smarkfen } else {
46614235Smarkfen cptr->ips_ulp_prot = pent->p_proto;
46624235Smarkfen }
46634235Smarkfen break;
46644235Smarkfen case TOK_type:
46654235Smarkfen if (cptr->has_type) {
46664235Smarkfen error_message(DUP_ERROR,
46674235Smarkfen IPSEC_CONF_ICMP_TYPE, line_no);
46684235Smarkfen return (-1);
46694235Smarkfen }
46704235Smarkfen
46714235Smarkfen i++, line_no++;
46724235Smarkfen type = parse_type_code(act_props->pattern[i],
46734235Smarkfen icmp_type_table);
46744235Smarkfen
46754235Smarkfen if (type > 65536 || type < 0) {
46764235Smarkfen error_message(BAD_ERROR,
46774235Smarkfen IPSEC_CONF_ICMP_TYPE, line_no);
46784235Smarkfen return (-1);
46794235Smarkfen }
46804235Smarkfen
46814235Smarkfen type_end = type / 256;
46824235Smarkfen type = type % 256;
46834235Smarkfen
46844235Smarkfen if (type_end < type)
46854235Smarkfen type_end = type;
46864235Smarkfen
46874235Smarkfen cptr->has_type = 1;
46884235Smarkfen cptr->ips_icmp_type = (uint8_t)type;
46894235Smarkfen cptr->ips_icmp_type_end = (uint8_t)type_end;
46904235Smarkfen break;
46914235Smarkfen case TOK_code:
46924235Smarkfen if (!cptr->has_type) {
46934235Smarkfen error_message(BAD_ERROR,
46944235Smarkfen IPSEC_CONF_ICMP_CODE, line_no);
46954235Smarkfen return (-1);
46964235Smarkfen }
46974235Smarkfen
46984235Smarkfen if (cptr->has_code) {
46994235Smarkfen error_message(DUP_ERROR,
47004235Smarkfen IPSEC_CONF_ICMP_CODE, line_no);
47014235Smarkfen return (-1);
47024235Smarkfen }
47034235Smarkfen
47044235Smarkfen i++, line_no++;
47054235Smarkfen
47064235Smarkfen code = parse_type_code(act_props->pattern[i],
47074235Smarkfen icmp_code_table);
47084235Smarkfen if (type > 65536 || type < 0) {
47094235Smarkfen error_message(BAD_ERROR,
47104235Smarkfen IPSEC_CONF_ICMP_CODE, line_no);
47114235Smarkfen return (-1);
47124235Smarkfen }
47134235Smarkfen code_end = code / 256;
47144235Smarkfen code = code % 256;
47154235Smarkfen
47164235Smarkfen if (code_end < code)
47174235Smarkfen code_end = code;
47184235Smarkfen
47194235Smarkfen cptr->has_code = 1;
47204235Smarkfen cptr->ips_icmp_code = (uint8_t)code;
47214235Smarkfen cptr->ips_icmp_code_end = (uint8_t)code_end;
47224235Smarkfen break;
47234235Smarkfen case TOK_tunnel:
47244235Smarkfen if (cptr->has_tunnel == 1) {
47254235Smarkfen error_message(BAD_ERROR,
47264235Smarkfen IPSEC_CONF_TUNNEL, line_no);
47274235Smarkfen return (-1);
47284235Smarkfen }
47294235Smarkfen i++, line_no++;
47304235Smarkfen if (act_props->pattern[i] == NULL) {
47314235Smarkfen error_message(BAD_ERROR,
47324235Smarkfen IPSEC_CONF_TUNNEL, line_no);
47334235Smarkfen return (-1);
47344235Smarkfen }
47354235Smarkfen
47364235Smarkfen if (strlcpy(tunif, act_props->pattern[i],
47374235Smarkfen TUNNAMEMAXLEN) >= TUNNAMEMAXLEN) {
47384235Smarkfen error_message(BAD_ERROR,
47394235Smarkfen IPSEC_CONF_TUNNEL, line_no);
47404235Smarkfen return (-1);
47414235Smarkfen }
47424235Smarkfen cptr->has_tunnel = 1;
47434235Smarkfen break;
47444235Smarkfen case TOK_negotiate:
47454235Smarkfen if (cptr->has_negotiate == 1) {
47464235Smarkfen error_message(BAD_ERROR,
47474235Smarkfen IPSEC_CONF_NEGOTIATE, line_no);
47484235Smarkfen return (-1);
47494235Smarkfen }
47504235Smarkfen i++, line_no++;
47514235Smarkfen if (act_props->pattern[i] == NULL) {
47524235Smarkfen error_message(BAD_ERROR,
47534235Smarkfen IPSEC_CONF_NEGOTIATE, line_no);
47544235Smarkfen return (-1);
47554235Smarkfen }
47564235Smarkfen
47574235Smarkfen if (strncmp(act_props->pattern[i], "tunnel", 6) == 0) {
47584235Smarkfen cptr->ips_tunnel = B_TRUE;
47594235Smarkfen } else if (strncmp(
47604235Smarkfen act_props->pattern[i], "transport", 9) != 0) {
47614235Smarkfen error_message(BAD_ERROR,
47624235Smarkfen IPSEC_CONF_NEGOTIATE, line_no);
47634235Smarkfen return (-1);
47644235Smarkfen }
47654235Smarkfen cptr->has_negotiate = 1;
47664235Smarkfen break;
47674235Smarkfen }
47684235Smarkfen
47694235Smarkfen }
47704235Smarkfen
47714235Smarkfen /* Sanity check that certain tokens occur together */
47724235Smarkfen if (cptr->has_tunnel + cptr->has_negotiate == 1) {
47734235Smarkfen if (cptr->has_negotiate == 0) {
47744235Smarkfen error_message(REQ_ERROR, IPSEC_CONF_NEGOTIATE, line_no);
47754235Smarkfen } else {
47764235Smarkfen error_message(REQ_ERROR, IPSEC_CONF_TUNNEL, line_no);
47774235Smarkfen }
47784235Smarkfen errx(1, gettext(
47794235Smarkfen "tunnel and negotiate tokens must occur together"));
47804235Smarkfen return (-1);
47814235Smarkfen }
47824235Smarkfen
47834235Smarkfen /*
47844235Smarkfen * Get the actions.
47854235Smarkfen */
47864235Smarkfen
47874235Smarkfen for (ap_num = 0; act_props->ap[ap_num].act != NULL; ap_num++) {
47884235Smarkfen ips_act_props_t *iap;
47894235Smarkfen
47904235Smarkfen if (ap_num > 0) {
47914235Smarkfen /* or's only with new style */
47924235Smarkfen if (old_style) {
47934235Smarkfen (void) printf("%s\n", gettext(
47944235Smarkfen "or's only with new style"));
47954235Smarkfen return (-1);
47964235Smarkfen }
47974235Smarkfen new_style = B_TRUE;
47984235Smarkfen }
47994235Smarkfen
480010372Sdanmcd@sun.com ipsec_aalg = ipsec_ealg = ipsec_eaalg = auth_covered = B_FALSE;
48014235Smarkfen tok_count = 0;
48024235Smarkfen
48034235Smarkfen for (k = 0; action_table[k].string; k++) {
48044235Smarkfen if (strcmp(act_props->ap[ap_num].act,
48054235Smarkfen action_table[k].string) == 0)
48064235Smarkfen break;
48074235Smarkfen }
48084235Smarkfen /*
48094235Smarkfen * The following thing should never happen as
48104235Smarkfen * we have already tested for its validity in parse.
48114235Smarkfen */
48124235Smarkfen if (action_table[k].string == NULL) {
48134235Smarkfen warnx(gettext("(form act)Invalid action on line "
48144235Smarkfen "%d: %s"), (arg_indices[line_no] == 0) ? 1 :
48154235Smarkfen arg_indices[line_no],
48164235Smarkfen act_props->ap[ap_num].act);
48174235Smarkfen warnx("%s", act_props->ap[ap_num].act);
48184235Smarkfen return (-1);
48194235Smarkfen }
48204235Smarkfen
48214235Smarkfen /* we have a good action alloc an iap */
48224235Smarkfen iap = alloc_iap(cptr);
48234235Smarkfen
48244235Smarkfen iap->iap_action = action_table[k].value;
48254235Smarkfen iap->iap_act_tok = action_table[k].tok_val;
48264235Smarkfen
48274235Smarkfen switch (action_table[k].tok_val) {
48284235Smarkfen case TOK_apply:
48294235Smarkfen cptr->ips_dir = SPD_RULE_FLAG_OUTBOUND;
48304235Smarkfen break;
48314235Smarkfen case TOK_permit:
48324235Smarkfen cptr->ips_dir = SPD_RULE_FLAG_INBOUND;
48334235Smarkfen break;
48344235Smarkfen case TOK_ipsec:
48354235Smarkfen if (old_style) {
48364235Smarkfen /* Using saddr/daddr with ipsec action. */
48374235Smarkfen if (!dir) {
48384235Smarkfen /* No direction specified */
48394235Smarkfen error_message(REQ_ERROR,
48404235Smarkfen IPSEC_CONF_IPSEC_DIR, line_no);
48414235Smarkfen return (-1);
48424235Smarkfen }
48434235Smarkfen if (cptr->ips_dir == SPD_RULE_FLAG_INBOUND)
48444235Smarkfen /*
48454235Smarkfen * Need to swap addresses if
48464235Smarkfen * 'dir in' or translation to
48474235Smarkfen * laddr/raddr will be incorrect.
48484235Smarkfen */
48494235Smarkfen cptr->swap = 1;
48504235Smarkfen }
48514235Smarkfen if (!dir)
48524235Smarkfen cptr->ips_dir =
48534235Smarkfen SPD_RULE_FLAG_INBOUND
48544235Smarkfen |SPD_RULE_FLAG_OUTBOUND;
48554235Smarkfen break;
48564235Smarkfen case TOK_bypass:
485710372Sdanmcd@sun.com case TOK_drop:
485810372Sdanmcd@sun.com is_no_alg = B_TRUE;
48594235Smarkfen break;
48604235Smarkfen }
48614235Smarkfen
48624235Smarkfen line_no++;
48634235Smarkfen /*
48644235Smarkfen * Get the properties. NULL properties is not valid.
48654235Smarkfen * Later checks will catch it.
48664235Smarkfen */
48674235Smarkfen for (i = 0; act_props->ap[ap_num].prop[i]; i++, line_no++) {
48684235Smarkfen for (j = 0; property_table[j].string; j++) {
48694235Smarkfen if (strcmp(act_props->ap[ap_num].prop[i],
48704235Smarkfen property_table[j].string) == 0) {
48714235Smarkfen break;
48724235Smarkfen }
48734235Smarkfen }
48744235Smarkfen if (property_table[j].string == NULL) {
48754235Smarkfen warnx(gettext("Invalid properties on line "
48764235Smarkfen "%d: %s"),
48775120Smarkfen (arg_indices[line_no] == 0) ?
48784235Smarkfen 1 : arg_indices[line_no],
48794235Smarkfen act_props->ap[ap_num].prop[i]);
48804235Smarkfen return (-1);
48814235Smarkfen }
48824235Smarkfen
48834235Smarkfen iap->iap_attr_tok[tok_count++]
48844235Smarkfen = property_table[j].value;
48854235Smarkfen
48864235Smarkfen switch (property_table[j].value) {
48874235Smarkfen case SPD_ATTR_AH_AUTH:
48884235Smarkfen if (ipsec_aalg) {
48894235Smarkfen error_message(DUP_ERROR,
48904235Smarkfen IPSEC_CONF_IPSEC_AALGS, line_no);
48914235Smarkfen return (-1);
48924235Smarkfen }
48934235Smarkfen i++, line_no++;
48944235Smarkfen if (act_props->ap[ap_num].prop[i] == NULL) {
48954235Smarkfen error_message(BAD_ERROR,
48964235Smarkfen IPSEC_CONF_IPSEC_AALGS, line_no);
48974235Smarkfen return (-1);
48984235Smarkfen }
48994235Smarkfen ret = parse_ipsec_alg(
49004235Smarkfen act_props->ap[ap_num].prop[i],
49014235Smarkfen iap, SPD_ATTR_AH_AUTH);
49024235Smarkfen if (ret == -2) {
49034235Smarkfen /* "none" - ignore */
49044235Smarkfen break;
49054235Smarkfen }
49064235Smarkfen if (ret != 0) {
49074235Smarkfen error_message(BAD_ERROR,
49084235Smarkfen IPSEC_CONF_IPSEC_AALGS, line_no);
49094235Smarkfen return (-1);
49104235Smarkfen }
49114235Smarkfen ipsec_aalg = B_TRUE;
491210372Sdanmcd@sun.com auth_covered = B_TRUE;
49134235Smarkfen break;
49144235Smarkfen case SPD_ATTR_ESP_ENCR:
49154235Smarkfen /*
49164235Smarkfen * If this option was not given
49174235Smarkfen * and encr_auth_algs was given,
49184235Smarkfen * we provide null-encryption. We do the
49194235Smarkfen * setting after we parse all the options.
49204235Smarkfen */
49214235Smarkfen if (ipsec_ealg) {
49224235Smarkfen error_message(DUP_ERROR,
49234235Smarkfen IPSEC_CONF_IPSEC_EALGS, line_no);
49244235Smarkfen return (-1);
49254235Smarkfen }
49264235Smarkfen i++, line_no++;
49274235Smarkfen if (act_props->ap[ap_num].prop[i] == NULL) {
49284235Smarkfen error_message(BAD_ERROR,
49294235Smarkfen IPSEC_CONF_IPSEC_EALGS, line_no);
49304235Smarkfen return (-1);
49314235Smarkfen }
49324235Smarkfen ret = parse_ipsec_alg(
49334235Smarkfen act_props->ap[ap_num].prop[i],
49344235Smarkfen iap, SPD_ATTR_ESP_ENCR);
49354235Smarkfen if (ret == -2) {
49364235Smarkfen /* "none" - ignore */
49374235Smarkfen break;
49384235Smarkfen }
49394235Smarkfen if (ret != 0) {
49404235Smarkfen error_message(BAD_ERROR,
49414235Smarkfen IPSEC_CONF_IPSEC_EALGS, line_no);
49424235Smarkfen return (-1);
49434235Smarkfen }
494412131Sdanmcd@opensolaris.org is_combined_mode =
494512131Sdanmcd@opensolaris.org combined_mode(iap->iap_eencr.alg_id);
49464235Smarkfen ipsec_ealg = B_TRUE;
49474235Smarkfen break;
49484235Smarkfen case SPD_ATTR_ESP_AUTH:
49494235Smarkfen /*
49504235Smarkfen * If this option was not given and encr_algs
49514235Smarkfen * option was given, we still pass a default
49524235Smarkfen * value in ipsc_esp_auth_algs. This is to
49534235Smarkfen * encourage the use of authentication with
49544235Smarkfen * ESP.
49554235Smarkfen */
49564235Smarkfen if (ipsec_eaalg) {
49574235Smarkfen error_message(DUP_ERROR,
49584235Smarkfen IPSEC_CONF_IPSEC_EAALGS, line_no);
49594235Smarkfen return (-1);
49604235Smarkfen }
49614235Smarkfen i++, line_no++;
49624235Smarkfen if (act_props->ap[ap_num].prop[i] == NULL) {
49634235Smarkfen error_message(BAD_ERROR,
49644235Smarkfen IPSEC_CONF_IPSEC_EAALGS, line_no);
49654235Smarkfen return (-1);
49664235Smarkfen }
49674235Smarkfen ret = parse_ipsec_alg(
49684235Smarkfen act_props->ap[ap_num].prop[i],
49694235Smarkfen iap, SPD_ATTR_ESP_AUTH);
49704235Smarkfen if (ret == -2) {
49714235Smarkfen /* "none" - ignore */
49724235Smarkfen break;
49734235Smarkfen }
49744235Smarkfen if (ret != 0) {
49754235Smarkfen error_message(BAD_ERROR,
49764235Smarkfen IPSEC_CONF_IPSEC_EAALGS, line_no);
49774235Smarkfen return (-1);
49784235Smarkfen }
49794235Smarkfen ipsec_eaalg = B_TRUE;
498010372Sdanmcd@sun.com auth_covered = B_TRUE;
49814235Smarkfen break;
49824235Smarkfen case IPS_SA:
49834235Smarkfen i++, line_no++;
49844235Smarkfen if (act_props->ap[ap_num].prop[i] == NULL) {
49854235Smarkfen error_message(BAD_ERROR,
49864235Smarkfen IPSEC_CONF_IPSEC_SA, line_no);
49874235Smarkfen return (-1);
49884235Smarkfen }
49894235Smarkfen
49904235Smarkfen if (strcmp(act_props->ap[ap_num].prop[i],
49914235Smarkfen "unique") == 0) {
49924235Smarkfen iap->iap_attr |= SPD_APPLY_UNIQUE;
49934235Smarkfen } else if (strcmp(act_props->ap[ap_num].prop[i],
49944235Smarkfen "shared") != 0) {
49954235Smarkfen /* "shared" is default. */
49964235Smarkfen error_message(BAD_ERROR,
49974235Smarkfen IPSEC_CONF_IPSEC_SA, line_no);
49984235Smarkfen return (-1);
49994235Smarkfen }
50004235Smarkfen
50014235Smarkfen break;
50024235Smarkfen case IPS_DIR:
50034235Smarkfen if (dir) {
50044235Smarkfen error_message(DUP_ERROR,
50054235Smarkfen IPSEC_CONF_IPSEC_DIR, line_no);
50064235Smarkfen return (-1);
50074235Smarkfen }
50084235Smarkfen if (new_style) {
50094235Smarkfen error_message(BAD_ERROR,
50104235Smarkfen IPSEC_CONF_IPSEC_DIR, line_no);
50114235Smarkfen return (-1);
50124235Smarkfen }
50134235Smarkfen old_style = B_TRUE;
50144235Smarkfen dir = B_TRUE;
50154235Smarkfen i++, line_no++;
50164235Smarkfen if (act_props->ap[ap_num].prop[i] == NULL) {
50174235Smarkfen error_message(BAD_ERROR,
50184235Smarkfen IPSEC_CONF_IPSEC_DIR, line_no);
50194235Smarkfen return (-1);
50204235Smarkfen }
50214235Smarkfen if (strcmp(act_props->ap[ap_num].prop[i],
50224235Smarkfen "out") == 0) {
50234235Smarkfen cptr->ips_dir = SPD_RULE_FLAG_OUTBOUND;
50244235Smarkfen } else if (strcmp(act_props->ap[ap_num].prop[i],
50254235Smarkfen "in") == 0) {
50264235Smarkfen cptr->ips_dir = SPD_RULE_FLAG_INBOUND;
50274235Smarkfen } else {
50284235Smarkfen error_message(BAD_ERROR,
50295120Smarkfen IPSEC_CONF_IPSEC_DIR, line_no);
50304235Smarkfen return (-1);
50314235Smarkfen }
50324235Smarkfen if ((cptr->ips_dir & SPD_RULE_FLAG_INBOUND) &&
50335120Smarkfen iap->iap_act_tok == TOK_apply) {
50344235Smarkfen warnx(gettext("Direction"
50354235Smarkfen " in conflict with action"));
50364235Smarkfen return (-1);
50374235Smarkfen }
50384235Smarkfen if ((cptr->ips_dir & SPD_RULE_FLAG_OUTBOUND) &&
50395120Smarkfen iap->iap_act_tok == TOK_permit) {
50404235Smarkfen warnx(gettext("Direction"
50414235Smarkfen "in conflict with action"));
50424235Smarkfen return (-1);
50434235Smarkfen }
50444235Smarkfen
50454235Smarkfen break;
50464235Smarkfen }
50474235Smarkfen }
50484235Smarkfen
504910824SMark.Fenwick@Sun.COM if (is_combined_mode) {
505010824SMark.Fenwick@Sun.COM if (ipsec_eaalg) {
505110824SMark.Fenwick@Sun.COM warnx(gettext("ERROR: Rule on line %d: "
505210824SMark.Fenwick@Sun.COM "Combined mode and esp authentication not "
505310824SMark.Fenwick@Sun.COM "supported together."),
505410824SMark.Fenwick@Sun.COM arg_indices[line_no] == 0 ? 1 :
505510824SMark.Fenwick@Sun.COM arg_indices[line_no]);
505610824SMark.Fenwick@Sun.COM return (-1);
505710824SMark.Fenwick@Sun.COM }
505810824SMark.Fenwick@Sun.COM auth_covered = B_TRUE;
505910824SMark.Fenwick@Sun.COM }
506010372Sdanmcd@sun.com /* Warn here about no authentication! */
506110372Sdanmcd@sun.com if (!auth_covered && !is_no_alg) {
506210372Sdanmcd@sun.com warnx(gettext("DANGER: Rule on line %d "
506310372Sdanmcd@sun.com "has encryption with no authentication."),
506410372Sdanmcd@sun.com arg_indices[line_no] == 0 ? 1 :
506510372Sdanmcd@sun.com arg_indices[line_no]);
506610372Sdanmcd@sun.com }
506710372Sdanmcd@sun.com
50684235Smarkfen if (!ipsec_ealg && ipsec_eaalg) {
50694235Smarkfen /*
50704235Smarkfen * If the user has specified the auth alg to be used
50714235Smarkfen * with encryption and did not provide a encryption
50724235Smarkfen * algorithm, provide null encryption.
50734235Smarkfen */
50744235Smarkfen iap->iap_eencr.alg_id = SADB_EALG_NULL;
50754235Smarkfen ipsec_ealg = B_TRUE;
50764235Smarkfen }
50774235Smarkfen
50784235Smarkfen /* Set the level of IPSEC protection we want */
50794235Smarkfen if (ipsec_aalg && (ipsec_ealg || ipsec_eaalg)) {
50804235Smarkfen iap->iap_attr |= SPD_APPLY_AH|SPD_APPLY_ESP;
50814235Smarkfen } else if (ipsec_aalg) {
50824235Smarkfen iap->iap_attr |= SPD_APPLY_AH;
50834235Smarkfen } else if (ipsec_ealg || ipsec_eaalg) {
50844235Smarkfen iap->iap_attr |= SPD_APPLY_ESP;
50854235Smarkfen }
50864235Smarkfen
50874235Smarkfen /* convert src/dst to local/remote */
50884235Smarkfen if (!new_style) {
50894235Smarkfen switch (cptr->ips_acts->iap_act_tok) {
50904235Smarkfen case TOK_apply:
50914235Smarkfen /* outbound */
50924235Smarkfen /* src=local, dst=remote */
50934235Smarkfen /* this is ok. */
50944235Smarkfen break;
50954235Smarkfen
50964235Smarkfen case TOK_permit:
50974235Smarkfen /* inbound */
50984235Smarkfen /* src=remote, dst=local */
50994235Smarkfen /* switch */
51004235Smarkfen cptr->swap = 1;
51014235Smarkfen break;
51024235Smarkfen case TOK_bypass:
51034235Smarkfen case TOK_drop:
51044235Smarkfen /* check the direction for what to do */
51054235Smarkfen if (cptr->ips_dir == SPD_RULE_FLAG_INBOUND)
51064235Smarkfen cptr->swap = 1;
51074235Smarkfen break;
51084235Smarkfen default:
51094235Smarkfen break;
51104235Smarkfen }
51114235Smarkfen }
51124235Smarkfen /* Validate the properties */
51134235Smarkfen if (ret = validate_properties(iap, dir,
51144235Smarkfen (ipsec_aalg || ipsec_ealg || ipsec_eaalg))) {
51154235Smarkfen return (ret);
51164235Smarkfen }
51174235Smarkfen }
51184235Smarkfen
51194235Smarkfen return (0);
51204235Smarkfen
51214235Smarkfen }
51224235Smarkfen
51234235Smarkfen static int
print_cmd_buf(FILE * fp,int error)51244235Smarkfen print_cmd_buf(FILE *fp, int error)
51254235Smarkfen {
51264235Smarkfen *(cbuf + cbuf_offset) = '\0';
51274235Smarkfen
51284235Smarkfen if (fp == stderr) {
51294235Smarkfen if (error != EEXIST) {
51304235Smarkfen warnx(gettext("Malformed command (fatal):\n%s"), cbuf);
51314235Smarkfen return (0);
51324235Smarkfen }
51334235Smarkfen if (ipsecconf_qflag) {
51344235Smarkfen return (0);
51354235Smarkfen }
51364235Smarkfen warnx(gettext("Duplicate policy entry (ignored):\n%s"), cbuf);
51374235Smarkfen } else {
51384235Smarkfen if (fprintf(fp, "%s", cbuf) == -1) {
51394235Smarkfen warn("fprintf");
51404235Smarkfen return (-1);
51414235Smarkfen }
51424235Smarkfen }
51434235Smarkfen
51444235Smarkfen return (0);
51454235Smarkfen }
51464235Smarkfen
51474235Smarkfen #ifdef DEBUG
51484235Smarkfen
51494235Smarkfen static uchar_t *
addr_ptr(int isv4,struct in6_addr * addr6,struct in_addr * addr4)51504235Smarkfen addr_ptr(int isv4, struct in6_addr *addr6, struct in_addr *addr4)
51514235Smarkfen {
51524235Smarkfen if (isv4) {
51534235Smarkfen IN6_V4MAPPED_TO_INADDR(addr6, addr4);
51544235Smarkfen return ((uchar_t *)&addr4->s_addr);
51554235Smarkfen } else {
51564235Smarkfen return ((uchar_t *)&addr6->s6_addr);
51574235Smarkfen }
51584235Smarkfen }
51594235Smarkfen
51604235Smarkfen static void
dump_algreq(const char * tag,algreq_t * alg)51614235Smarkfen dump_algreq(const char *tag, algreq_t *alg)
51624235Smarkfen {
51634235Smarkfen (void) printf("%s algid %d, bits %d..%d\n",
51644235Smarkfen tag, alg->alg_id, alg->alg_minbits, alg->alg_maxbits);
51654235Smarkfen }
51664235Smarkfen
51674235Smarkfen static void
dump_conf(ips_conf_t * conf)51684235Smarkfen dump_conf(ips_conf_t *conf)
51694235Smarkfen {
51704235Smarkfen boolean_t isv4 = conf->ips_isv4;
51714235Smarkfen struct in_addr addr;
51724235Smarkfen char buf[INET6_ADDRSTRLEN];
51734235Smarkfen int af;
51744235Smarkfen ips_act_props_t *iap = conf->ips_acts;
51754235Smarkfen
51764235Smarkfen af = isv4 ? AF_INET : AF_INET6;
51774235Smarkfen
51784235Smarkfen (void) printf("Source Addr is %s\n",
51794235Smarkfen inet_ntop(af, addr_ptr(isv4, &conf->ips_src_addr_v6, &addr),
51805120Smarkfen buf, INET6_ADDRSTRLEN));
51814235Smarkfen
51824235Smarkfen (void) printf("Dest Addr is %s\n",
51834235Smarkfen inet_ntop(af, addr_ptr(isv4, &conf->ips_dst_addr_v6, &addr),
51845120Smarkfen buf, INET6_ADDRSTRLEN));
51854235Smarkfen
51864235Smarkfen (void) printf("Source Mask is %s\n",
51874235Smarkfen inet_ntop(af, addr_ptr(isv4, &conf->ips_src_mask_v6, &addr),
51885120Smarkfen buf, INET6_ADDRSTRLEN));
51894235Smarkfen
51904235Smarkfen (void) printf("Dest Mask is %s\n",
51914235Smarkfen inet_ntop(af, addr_ptr(isv4, &conf->ips_dst_mask_v6, &addr),
51925120Smarkfen buf, INET6_ADDRSTRLEN));
51934235Smarkfen
51944235Smarkfen (void) printf("Source port %d\n", ntohs(conf->ips_src_port_min));
51954235Smarkfen (void) printf("Dest port %d\n", ntohs(conf->ips_dst_port_min));
51964235Smarkfen (void) printf("ULP %d\n", conf->ips_ulp_prot);
51974235Smarkfen
51984235Smarkfen (void) printf("ICMP type %d-%d code %d-%d", conf->ips_icmp_type,
51994235Smarkfen conf->ips_icmp_type_end,
52004235Smarkfen conf->ips_icmp_code,
52014235Smarkfen conf->ips_icmp_code_end);
52024235Smarkfen
52034235Smarkfen while (iap != NULL) {
52044235Smarkfen (void) printf("------------------------------------\n");
52054235Smarkfen (void) printf("IPsec act is %d\n", iap->iap_action);
52064235Smarkfen (void) printf("IPsec attr is %d\n", iap->iap_attr);
52074235Smarkfen dump_algreq("AH authentication", &iap->iap_aauth);
52084235Smarkfen dump_algreq("ESP authentication", &iap->iap_eauth);
52094235Smarkfen dump_algreq("ESP encryption", &iap->iap_eencr);
52104235Smarkfen (void) printf("------------------------------------\n");
52114235Smarkfen iap = iap->iap_next;
52124235Smarkfen }
52134235Smarkfen
52144235Smarkfen (void) fflush(stdout);
52154235Smarkfen }
52164235Smarkfen #endif /* DEBUG */
52174235Smarkfen
52184235Smarkfen
52194235Smarkfen static int
ipsec_conf_add(boolean_t just_check,boolean_t smf_managed,boolean_t replace)522011278SMark.Fenwick@Sun.COM ipsec_conf_add(boolean_t just_check, boolean_t smf_managed, boolean_t replace)
52214235Smarkfen {
52224235Smarkfen act_prop_t *act_props = malloc(sizeof (act_prop_t));
52234235Smarkfen ips_conf_t conf;
52244235Smarkfen FILE *fp, *policy_fp;
52254235Smarkfen int ret, flushret, i, j, diag, num_rules, good_rules;
52264235Smarkfen char *warning = gettext(
52275120Smarkfen "\tWARNING : New policy entries that are being added may\n "
52285120Smarkfen "\taffect the existing connections. Existing connections\n"
52295120Smarkfen "\tthat are not subjected to policy constraints, may be\n"
52305120Smarkfen "\tsubjected to policy constraints because of the new\n"
52315120Smarkfen "\tpolicy. This can disrupt the communication of the\n"
52325120Smarkfen "\texisting connections.\n\n");
52334235Smarkfen
52344235Smarkfen boolean_t first_time = B_TRUE;
52354235Smarkfen num_rules = 0;
52364235Smarkfen good_rules = 0;
52374235Smarkfen
52384235Smarkfen if (act_props == NULL) {
52394235Smarkfen warn(gettext("memory"));
52404235Smarkfen return (-1);
52414235Smarkfen }
52424235Smarkfen
52434235Smarkfen if (strcmp(filename, "-") == 0)
52444235Smarkfen fp = stdin;
52454235Smarkfen else
52464235Smarkfen fp = fopen(filename, "r");
52474235Smarkfen
52484235Smarkfen /*
52494235Smarkfen * Treat the non-existence of a policy file as a special
52504235Smarkfen * case when ipsecconf is being managed by smf(5).
52514235Smarkfen * The assumption is the administrator has not yet
52524235Smarkfen * created a policy file, this should not force the service
52534235Smarkfen * into maintenance mode.
52544235Smarkfen */
52554235Smarkfen
52564235Smarkfen if (fp == NULL) {
52574235Smarkfen if (smf_managed) {
52584235Smarkfen (void) fprintf(stdout, gettext(
52594235Smarkfen "Policy configuration file (%s) does not exist.\n"
52604235Smarkfen "IPsec policy not configured.\n"), filename);
52614235Smarkfen return (0);
52624235Smarkfen }
52634235Smarkfen warn(gettext("%s : Policy config file cannot be opened"),
52644235Smarkfen filename);
52654235Smarkfen usage();
52664235Smarkfen return (-1);
52674235Smarkfen }
52684235Smarkfen /*
52694235Smarkfen * This will create the file if it does not exist.
52704235Smarkfen * Make sure the umask is right.
52714235Smarkfen */
52724235Smarkfen (void) umask(0022);
52734235Smarkfen policy_fp = fopen(POLICY_CONF_FILE, "a");
52744235Smarkfen if (policy_fp == NULL) {
52754235Smarkfen warn(gettext("%s cannot be opened"), POLICY_CONF_FILE);
52764235Smarkfen return (-1);
52774235Smarkfen }
52784235Smarkfen
52794235Smarkfen /*
52804235Smarkfen * Pattern, action, and properties are allocated in
52814235Smarkfen * parse_pattern_or_prop and in parse_action (called by
52824235Smarkfen * parse_one) as we parse arguments.
52834235Smarkfen */
52845120Smarkfen while ((ret = parse_one(fp, act_props)) != PARSE_EOF) {
52855120Smarkfen num_rules++;
52865120Smarkfen if (ret != 0) {
52875120Smarkfen (void) print_cmd_buf(stderr, NOERROR);
52885120Smarkfen continue;
52895120Smarkfen }
52904235Smarkfen
52914235Smarkfen /*
52924235Smarkfen * If there is no action and parse returned success,
52934235Smarkfen * it means that there is nothing to add.
52944235Smarkfen */
52954235Smarkfen if (act_props->pattern[0] == NULL &&
52964235Smarkfen act_props->ap[0].act == NULL)
52974235Smarkfen break;
52984235Smarkfen
52994235Smarkfen ret = form_ipsec_conf(act_props, &conf);
53004235Smarkfen if (ret != 0) {
53014235Smarkfen warnx(gettext("form_ipsec_conf error"));
53024235Smarkfen (void) print_cmd_buf(stderr, NOERROR);
53034475Spwernau /* Reset globals before trying the next rule. */
53044475Spwernau if (shp != NULL) {
53054475Spwernau freehostent(shp);
53064475Spwernau shp = NULL;
53074475Spwernau }
53084475Spwernau if (dhp != NULL) {
53094475Spwernau freehostent(dhp);
53104475Spwernau dhp = NULL;
53114475Spwernau }
53124475Spwernau splen = 0;
53134475Spwernau dplen = 0;
53144235Smarkfen continue;
53154235Smarkfen }
53164235Smarkfen
53174235Smarkfen good_rules++;
53184235Smarkfen
53194235Smarkfen if (first_time) {
53204235Smarkfen /*
53214235Smarkfen * Time to assume that there are valid policy entries.
53224235Smarkfen * If the IPsec kernel modules are not loaded this
53234235Smarkfen * will load them now.
53244235Smarkfen */
53254235Smarkfen first_time = B_FALSE;
53264235Smarkfen fetch_algorithms();
53274235Smarkfen ipsec_conf_admin(SPD_CLONE);
532811278SMark.Fenwick@Sun.COM
532911278SMark.Fenwick@Sun.COM /*
533011278SMark.Fenwick@Sun.COM * The default behaviour for IPSEC_CONF_ADD is to append
533111278SMark.Fenwick@Sun.COM * the new rules to the existing policy. If a new rule
533211278SMark.Fenwick@Sun.COM * collides with an existing rule, the new rule won't be
533311278SMark.Fenwick@Sun.COM * added.
533411278SMark.Fenwick@Sun.COM *
533511278SMark.Fenwick@Sun.COM * To perform an atomic policy replace, we really don't
533611278SMark.Fenwick@Sun.COM * care what the existing policy was, just replace it
533711278SMark.Fenwick@Sun.COM * with the new one. Remove all rules from the SPD_CLONE
533811278SMark.Fenwick@Sun.COM * policy before checking the new rules.
533911278SMark.Fenwick@Sun.COM */
534011278SMark.Fenwick@Sun.COM if (replace) {
534111278SMark.Fenwick@Sun.COM flushret = ipsec_conf_flush(SPD_STANDBY);
534211278SMark.Fenwick@Sun.COM if (flushret != 0)
534311278SMark.Fenwick@Sun.COM return (flushret);
534411278SMark.Fenwick@Sun.COM }
53454235Smarkfen }
53464235Smarkfen
53474235Smarkfen /*
53484235Smarkfen * shp, dhp, splen, and dplen are globals set by
53494235Smarkfen * form_ipsec_conf() while parsing the addresses.
53504235Smarkfen */
53514235Smarkfen if (shp == NULL && dhp == NULL) {
53524235Smarkfen switch (do_port_adds(&conf)) {
53534235Smarkfen case 0:
53544235Smarkfen /* no error */
53554235Smarkfen break;
53564235Smarkfen case EEXIST:
53574235Smarkfen /* duplicate entries, continue adds */
53584235Smarkfen (void) print_cmd_buf(stderr, EEXIST);
53594235Smarkfen goto next;
53604235Smarkfen default:
53614235Smarkfen /* other error, bail */
53624235Smarkfen ret = -1;
53634235Smarkfen goto bail;
53644235Smarkfen }
53654235Smarkfen } else {
53664235Smarkfen ret = do_address_adds(&conf, &diag);
53674235Smarkfen switch (ret) {
53684235Smarkfen case 0:
53694235Smarkfen /* no error. */
53704235Smarkfen break;
53714235Smarkfen case EEXIST:
53724235Smarkfen (void) print_cmd_buf(stderr, EEXIST);
53734235Smarkfen goto next;
53744235Smarkfen case EBUSY:
53754235Smarkfen warnx(gettext(
53765120Smarkfen "Can't set mask and /NN prefix."));
53774235Smarkfen ret = -1;
53784235Smarkfen break;
53794235Smarkfen case ENOENT:
53804235Smarkfen warnx(gettext("Cannot find tunnel "
53814235Smarkfen "interface %s."), interface_name);
53824235Smarkfen ret = -1;
53834235Smarkfen break;
53844235Smarkfen case EINVAL:
53854235Smarkfen /*
53864235Smarkfen * PF_POLICY didn't like what we sent. We
53874235Smarkfen * can't check all input up here, but we
53884235Smarkfen * do in-kernel.
53894235Smarkfen */
53904235Smarkfen warnx(gettext("PF_POLICY invalid input:\n\t%s"),
53914235Smarkfen spdsock_diag(diag));
53924235Smarkfen break;
53934235Smarkfen case EOPNOTSUPP:
53944235Smarkfen warnx(gettext("Can't set /NN"
53955120Smarkfen " prefix on multi-host name."));
53964235Smarkfen ret = -1;
53974235Smarkfen break;
53984235Smarkfen case ERANGE:
53994235Smarkfen warnx(gettext("/NN prefix is too big!"));
54004235Smarkfen ret = -1;
54014235Smarkfen break;
54024235Smarkfen case ESRCH:
54034235Smarkfen warnx(gettext("No matching IPv4 or "
54045120Smarkfen "IPv6 saddr/daddr pairs"));
54054235Smarkfen ret = -1;
54064235Smarkfen break;
54074235Smarkfen default:
54084235Smarkfen /* Should never get here. */
54094235Smarkfen errno = ret;
54104235Smarkfen warn(gettext("Misc. error"));
54114235Smarkfen ret = -1;
54124235Smarkfen }
54134235Smarkfen if (ret == -1)
54144235Smarkfen goto bail;
54154235Smarkfen }
54164235Smarkfen
54174235Smarkfen /*
54184235Smarkfen * Go ahead and add policy entries to config file.
54194235Smarkfen * The # should help re-using the ipsecpolicy.conf
54204235Smarkfen * for input again as # will be treated as comment.
54214235Smarkfen */
54224235Smarkfen if (fprintf(policy_fp, "%s %lld \n", INDEX_TAG,
54234235Smarkfen conf.ips_policy_index) == -1) {
54244235Smarkfen warn("fprintf");
54254235Smarkfen warnx(gettext("Addition incomplete, Please "
54264235Smarkfen "flush all the entries and re-configure :"));
54274235Smarkfen reconfigure();
54284235Smarkfen ret = -1;
54294235Smarkfen break;
54304235Smarkfen }
54314235Smarkfen if (print_cmd_buf(policy_fp, NOERROR) == -1) {
54324235Smarkfen warnx(gettext("Addition incomplete. Please "
54334235Smarkfen "flush all the entries and re-configure :"));
54344235Smarkfen reconfigure();
54354235Smarkfen ret = -1;
54364235Smarkfen break;
54374235Smarkfen }
54384235Smarkfen /*
54394235Smarkfen * We add one newline by default to separate out the
54404235Smarkfen * entries. If the last character is not a newline, we
54414235Smarkfen * insert a newline for free. This makes sure that all
54424235Smarkfen * entries look consistent in the file.
54434235Smarkfen */
54444235Smarkfen if (*(cbuf + cbuf_offset - 1) == '\n') {
54454235Smarkfen if (fprintf(policy_fp, "\n") == -1) {
54464235Smarkfen warn("fprintf");
54474235Smarkfen warnx(gettext("Addition incomplete. "
54484235Smarkfen "Please flush all the entries and "
54494235Smarkfen "re-configure :"));
54504235Smarkfen reconfigure();
54514235Smarkfen ret = -1;
54524235Smarkfen break;
54534235Smarkfen }
54544235Smarkfen } else {
54554235Smarkfen if (fprintf(policy_fp, "\n\n") == -1) {
54564235Smarkfen warn("fprintf");
54574235Smarkfen warnx(gettext("Addition incomplete. "
54584235Smarkfen "Please flush all the entries and "
54594235Smarkfen "re-configure :"));
54604235Smarkfen reconfigure();
54614235Smarkfen ret = -1;
54624235Smarkfen break;
54634235Smarkfen }
54644235Smarkfen }
54654235Smarkfen next:
54664235Smarkfen /*
54674235Smarkfen * Make sure this gets to the disk before
54684235Smarkfen * we parse the next entry.
54694235Smarkfen */
54704235Smarkfen (void) fflush(policy_fp);
54714235Smarkfen for (i = 0; act_props->pattern[i] != NULL; i++)
54724235Smarkfen free(act_props->pattern[i]);
54734235Smarkfen for (j = 0; act_props->ap[j].act != NULL; j++) {
54744235Smarkfen free(act_props->ap[j].act);
54754235Smarkfen for (i = 0; act_props->ap[j].prop[i] != NULL; i++)
54764235Smarkfen free(act_props->ap[j].prop[i]);
54774235Smarkfen }
54784235Smarkfen }
54795120Smarkfen if (ret == PARSE_EOF)
54805120Smarkfen ret = 0; /* Not an error */
54814235Smarkfen bail:
54824235Smarkfen if (ret == -1) {
54834235Smarkfen (void) print_cmd_buf(stderr, EINVAL);
54844235Smarkfen for (i = 0; act_props->pattern[i] != NULL; i++)
54854235Smarkfen free(act_props->pattern[i]);
54864235Smarkfen for (j = 0; act_props->ap[j].act != NULL; j++) {
54874235Smarkfen free(act_props->ap[j].act);
54884235Smarkfen for (i = 0; act_props->ap[j].prop[i] != NULL; i++)
54894235Smarkfen free(act_props->ap[j].prop[i]);
54904235Smarkfen }
54914235Smarkfen }
54924235Smarkfen #ifdef DEBUG_HEAVY
54934235Smarkfen (void) printf("ipsec_conf_add: ret val = %d\n", ret);
54944235Smarkfen (void) fflush(stdout);
54954235Smarkfen #endif
54965120Smarkfen if (num_rules == 0 && ret == 0) {
54974475Spwernau nuke_adds();
54984235Smarkfen (void) restore_all_signals();
54994235Smarkfen (void) unlock(lfd);
55004235Smarkfen EXIT_OK("Policy file does not contain any valid rules.");
55014235Smarkfen }
55024235Smarkfen if (num_rules != good_rules) {
55034235Smarkfen /* This is an error */
55044475Spwernau nuke_adds();
55054235Smarkfen (void) restore_all_signals();
55064235Smarkfen (void) unlock(lfd);
55074235Smarkfen EXIT_BADCONFIG2("%d policy rule(s) contained errors.",
55084235Smarkfen num_rules - good_rules);
55094235Smarkfen }
55104235Smarkfen /* looks good, flip it in */
55114235Smarkfen if (ret == 0 && !just_check) {
55124235Smarkfen if (!ipsecconf_qflag) {
55134235Smarkfen (void) printf("%s", warning);
55144235Smarkfen }
55155120Smarkfen if (smf_managed)
55165120Smarkfen warnx(gettext("%d policy rules added."), good_rules);
55174235Smarkfen ipsec_conf_admin(SPD_FLIP);
55184235Smarkfen } else {
55194235Smarkfen nuke_adds();
55204235Smarkfen if (just_check) {
55215120Smarkfen (void) fprintf(stdout, gettext("IPsec configuration "
55225120Smarkfen "does not contain any errors.\n"));
55234235Smarkfen (void) fprintf(stdout, gettext(
55244235Smarkfen "IPsec policy was not modified.\n"));
55254235Smarkfen (void) fflush(stdout);
55264235Smarkfen }
55274235Smarkfen }
55284235Smarkfen flushret = ipsec_conf_flush(SPD_STANDBY);
55294235Smarkfen if (flushret != 0)
55304235Smarkfen return (flushret);
55314235Smarkfen return (ret);
55324235Smarkfen }
55334235Smarkfen
55344235Smarkfen
55354235Smarkfen static int
ipsec_conf_sub()55364235Smarkfen ipsec_conf_sub()
55374235Smarkfen {
55384235Smarkfen act_prop_t *act_props = malloc(sizeof (act_prop_t));
55394235Smarkfen FILE *remove_fp, *policy_fp;
55404235Smarkfen char rbuf[MAXLEN], pbuf[MAXLEN], /* remove buffer, and policy buffer */
55414235Smarkfen *warning = gettext(
55425120Smarkfen "\tWARNING: Policy entries that are being removed may\n"
55435120Smarkfen "\taffect the existing connections. Existing connections\n"
55445120Smarkfen "\tthat are subjected to policy constraints may no longer\n"
55455120Smarkfen "\tbe subjected to policy contraints because of its\n"
55465120Smarkfen "\tremoval. This can compromise security, and disrupt\n"
55475120Smarkfen "\tthe communication of the existing connection.\n"
55485120Smarkfen "\tConnections that are latched will remain unaffected\n"
55495120Smarkfen "\tuntil they close.\n");
55504235Smarkfen int ret = 0;
55514235Smarkfen int index_len, pindex = 0; /* init value in case of pfile error */
55524235Smarkfen
55534235Smarkfen if (act_props == NULL) {
55544235Smarkfen warn(gettext("memory"));
55554235Smarkfen return (-1);
55564235Smarkfen }
55574235Smarkfen
55584235Smarkfen /* clone into standby DB */
55594235Smarkfen (void) ipsec_conf_admin(SPD_CLONE);
55604235Smarkfen
55614235Smarkfen if (strcmp(filename, "-") == 0)
55624235Smarkfen remove_fp = stdin;
55634235Smarkfen else
55644235Smarkfen remove_fp = fopen(filename, "r");
55654235Smarkfen
55664235Smarkfen if (remove_fp == NULL) {
55674235Smarkfen warn(gettext("%s : Input file cannot be opened"), filename);
55684235Smarkfen usage();
55694235Smarkfen free(act_props);
55704235Smarkfen return (-1);
55714235Smarkfen }
55724235Smarkfen
55734235Smarkfen /* open policy file so we can locate the correct policy */
55744235Smarkfen (void) umask(0022); /* in case it gets created! */
55754235Smarkfen policy_fp = fopen(POLICY_CONF_FILE, "r+");
55764235Smarkfen if (policy_fp == NULL) {
55774235Smarkfen warn(gettext("%s cannot be opened"), POLICY_CONF_FILE);
55784235Smarkfen (void) fclose(remove_fp);
55794235Smarkfen free(act_props);
55804235Smarkfen return (-1);
55814235Smarkfen }
55824235Smarkfen
55834235Smarkfen /* don't print the warning if we're in q[uiet] mode */
55844235Smarkfen if (!ipsecconf_qflag)
55854235Smarkfen (void) printf("%s", warning);
55864235Smarkfen
55874235Smarkfen /* this bit is done primarily so we can read what we write */
55884235Smarkfen index_len = strlen(INDEX_TAG);
55894235Smarkfen
55904235Smarkfen /*
55914235Smarkfen * We want to look for the policy in rbuf in the policy file.
55924235Smarkfen * Go through the list of policies to remove, locating each one.
55934235Smarkfen */
55944235Smarkfen while (fgets(rbuf, MAXLEN, remove_fp) != NULL) {
55954235Smarkfen char *buf;
55964235Smarkfen int offset, prev_offset, prev_prev_offset, nlines;
55974235Smarkfen fpos_t ipos;
55984235Smarkfen int pbuf_len = 0;
55994235Smarkfen char *tmp;
56004235Smarkfen /* skip blanks here (so we don't need to do it below)! */
56015120Smarkfen for (tmp = rbuf; (*tmp != '\0') && isspace(*tmp); )
56025120Smarkfen tmp++;
56035120Smarkfen
56044235Smarkfen if (*tmp == '\0')
56055120Smarkfen continue; /* while(); */
56064235Smarkfen
56074235Smarkfen /* skip the INDEX_TAG lines in the remove buffer */
56084235Smarkfen if (strncasecmp(rbuf, INDEX_TAG, index_len) == 0)
56094235Smarkfen continue;
56104235Smarkfen
56114235Smarkfen /* skip commented lines */
56124235Smarkfen if (*tmp == '#')
56135120Smarkfen continue; /* while(); */
56144235Smarkfen
56154235Smarkfen /*
56164235Smarkfen * We start by presuming only good policies are in the pfile,
56174235Smarkfen * and so only good policies from the rfile will match them.
56184235Smarkfen * ipsec_conf_del ensures this later by calling parse_one() on
56194235Smarkfen * pfile before it deletes the entry.
56204235Smarkfen */
56214235Smarkfen for (offset = prev_offset = prev_prev_offset = 0;
56224235Smarkfen fgets(pbuf, MAXLEN, policy_fp) != NULL;
56234235Smarkfen offset += pbuf_len) {
56244235Smarkfen prev_offset = offset;
56254235Smarkfen pbuf_len = strlen(pbuf);
56264235Smarkfen
56274235Smarkfen /* skip blank lines which seperate policy entries */
56284235Smarkfen if (pbuf[0] == '\n')
56294235Smarkfen continue;
56304235Smarkfen
56314235Smarkfen /* if we found an index, save it */
56324235Smarkfen if (strncasecmp(pbuf, INDEX_TAG, index_len) == 0) {
56334235Smarkfen buf = pbuf + index_len;
56344235Smarkfen buf++;
56354235Smarkfen if ((pindex = parse_index(buf, NULL)) == -1) {
56364235Smarkfen /* bad index, we can't continue */
56374235Smarkfen warnx(gettext(
56385120Smarkfen "Invalid index in the file"));
56394235Smarkfen (void) fclose(remove_fp);
56404235Smarkfen (void) fclose(policy_fp);
56414235Smarkfen free(act_props);
56424235Smarkfen return (-1);
56434235Smarkfen }
56444235Smarkfen
56454235Smarkfen /* save this position in case it's the one */
56464235Smarkfen if (fgetpos(policy_fp, &ipos) != 0) {
56474235Smarkfen (void) fclose(remove_fp);
56484235Smarkfen (void) fclose(policy_fp);
56494235Smarkfen free(act_props);
56504235Smarkfen return (-1);
56514235Smarkfen }
56524235Smarkfen }
56534235Smarkfen
56544235Smarkfen /* Does pbuf contain the remove policy? */
56554235Smarkfen if (strncasecmp(rbuf, pbuf, pbuf_len) == 0) {
56564235Smarkfen /* we found the one to remove! */
56574235Smarkfen if (pindex == 0) {
56584235Smarkfen warnx(gettext("Didn't find a valid "
56594235Smarkfen "index for policy"));
56604235Smarkfen (void) fclose(remove_fp);
56614235Smarkfen (void) fclose(policy_fp);
56624235Smarkfen free(act_props);
56634235Smarkfen return (-1);
56644235Smarkfen }
56654235Smarkfen
56664235Smarkfen /* off it - back up to the last INDEX! */
56674235Smarkfen if (fsetpos(policy_fp, &ipos) != 0) {
56684235Smarkfen (void) fclose(remove_fp);
56694235Smarkfen (void) fclose(policy_fp);
56704235Smarkfen free(act_props);
56714235Smarkfen return (-1);
56724235Smarkfen }
56734235Smarkfen
56744235Smarkfen /* parse_one sets linecount = #lines to off */
56754235Smarkfen if (parse_one(policy_fp, act_props) == -1) {
56764235Smarkfen warnx(gettext("Invalid policy entry "
56774235Smarkfen "in the file"));
56784235Smarkfen (void) fclose(remove_fp);
56794235Smarkfen (void) fclose(policy_fp);
56804235Smarkfen free(act_props);
56814235Smarkfen return (-1);
56824235Smarkfen }
56834235Smarkfen
56844235Smarkfen nlines = linecount + 2;
56854235Smarkfen goto delete;
56864235Smarkfen }
56874235Smarkfen /*
56884235Smarkfen * When we find a match, we want to pass the offset
56894235Smarkfen * of the line that is before it - the INDEX_TAG line.
56904235Smarkfen */
56914235Smarkfen prev_prev_offset = prev_offset;
56924235Smarkfen }
56934235Smarkfen /* Didn't find a match - look at the next remove policy */
56945120Smarkfen continue; /* while(); */
56954235Smarkfen
56964235Smarkfen delete:
56974235Smarkfen (void) fclose(policy_fp);
56984235Smarkfen
56994235Smarkfen if (delete_from_file(prev_prev_offset, nlines) != 0) {
57004235Smarkfen warnx(gettext("delete_from_file failure. "
57014235Smarkfen "Please flush all entries and re-configure :"));
57024235Smarkfen reconfigure();
57034235Smarkfen (void) fclose(remove_fp);
57044235Smarkfen free(act_props);
57054235Smarkfen return (-1);
57064235Smarkfen }
57074235Smarkfen
57084235Smarkfen if (pfp_delete_rule(pindex) != 0) {
57094235Smarkfen warnx(gettext("Deletion incomplete. Please flush"
57104235Smarkfen "all the entries and re-configure :"));
57114235Smarkfen reconfigure();
57124235Smarkfen (void) fclose(remove_fp);
57134235Smarkfen free(act_props);
57144235Smarkfen return (-1);
57154235Smarkfen }
57164235Smarkfen
57174235Smarkfen /* reset the globals */
57184235Smarkfen linecount = 0;
57194235Smarkfen pindex = 0;
57204235Smarkfen /* free(NULL) also works. */
57214235Smarkfen free(interface_name);
57224235Smarkfen interface_name = NULL;
57234235Smarkfen
57244235Smarkfen /* reopen for next pass, automagically starting over. */
57254235Smarkfen policy_fp = fopen(POLICY_CONF_FILE, "r");
57264235Smarkfen if (policy_fp == NULL) {
57274235Smarkfen warn(gettext("%s cannot be re-opened, can't continue"),
57284235Smarkfen POLICY_CONF_FILE);
57294235Smarkfen (void) fclose(remove_fp);
57304235Smarkfen free(act_props);
57314235Smarkfen return (-1);
57324235Smarkfen }
57334235Smarkfen
57344235Smarkfen } /* read next remove policy */
57354235Smarkfen
57364235Smarkfen if ((ret = pfp_delete_rule(pindex)) != 0) {
57374235Smarkfen warnx(gettext("Removal incomplete. Please flush "
57384235Smarkfen "all the entries and re-configure :"));
57394235Smarkfen reconfigure();
57404235Smarkfen free(act_props);
57414235Smarkfen return (ret);
57424235Smarkfen }
57434235Smarkfen
57444235Smarkfen /* nothing left to look for */
57454235Smarkfen (void) fclose(remove_fp);
57464235Smarkfen free(act_props);
57474235Smarkfen
57484235Smarkfen return (0);
57494235Smarkfen }
57504235Smarkfen
57514235Smarkfen /*
57524235Smarkfen * Constructs a tunnel interface ID extension. Returns the length
57534235Smarkfen * of the extension in 64-bit-words.
57544235Smarkfen */
57554235Smarkfen static int
attach_tunname(spd_if_t * tunname)57564235Smarkfen attach_tunname(spd_if_t *tunname)
57574235Smarkfen {
57584235Smarkfen if (tunname == NULL || interface_name == NULL)
57594235Smarkfen return (0);
57604235Smarkfen
57614235Smarkfen tunname->spd_if_exttype = SPD_EXT_TUN_NAME;
57624235Smarkfen /*
57634235Smarkfen * Use "-3" because there's 4 bytes in the message itself, and
57644235Smarkfen * we lose one because of the '\0' terminator.
57654235Smarkfen */
57664235Smarkfen tunname->spd_if_len = SPD_8TO64(
57674235Smarkfen P2ROUNDUP(sizeof (*tunname) + strlen(interface_name) - 3, 8));
57684235Smarkfen (void) strlcpy((char *)tunname->spd_if_name, interface_name, LIFNAMSIZ);
57694235Smarkfen return (tunname->spd_if_len);
57704235Smarkfen }
5771