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 /* 22*10372Sdanmcd@sun.com * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 234235Smarkfen * Use is subject to license terms. 244235Smarkfen */ 254235Smarkfen 264235Smarkfen #include <stdio.h> 274235Smarkfen #include <sys/types.h> 284235Smarkfen #include <sys/stat.h> 294235Smarkfen #include <strings.h> 304235Smarkfen #include <stropts.h> 314235Smarkfen #include <fcntl.h> 324235Smarkfen #include <stdlib.h> 334235Smarkfen #include <unistd.h> 344235Smarkfen #include <string.h> 354235Smarkfen #include <ctype.h> 364235Smarkfen #include <arpa/inet.h> 374235Smarkfen #include <locale.h> 384235Smarkfen #include <syslog.h> 394235Smarkfen #include <pwd.h> 404235Smarkfen #include <sys/param.h> 414235Smarkfen #include <sys/sysmacros.h> /* MIN, MAX */ 424235Smarkfen #include <sys/sockio.h> 434235Smarkfen #include <net/pfkeyv2.h> 444235Smarkfen #include <net/pfpolicy.h> 454235Smarkfen #include <inet/ipsec_impl.h> 464235Smarkfen #include <signal.h> 474235Smarkfen #include <errno.h> 484235Smarkfen #include <netdb.h> 494235Smarkfen #include <sys/socket.h> 504235Smarkfen #include <sys/systeminfo.h> 514235Smarkfen #include <nss_dbdefs.h> /* NSS_BUFLEN_HOSTS */ 524235Smarkfen #include <netinet/in.h> 534235Smarkfen #include <assert.h> 544235Smarkfen #include <inet/ip.h> 554235Smarkfen #include <ipsec_util.h> 564235Smarkfen #include <netinet/in_systm.h> 574235Smarkfen #include <netinet/ip_icmp.h> 584235Smarkfen #include <netinet/icmp6.h> 594235Smarkfen 604235Smarkfen /* 614235Smarkfen * Globals 624235Smarkfen */ 634235Smarkfen int lfd; 644235Smarkfen char *my_fmri; 654235Smarkfen FILE *debugfile = stderr; 664235Smarkfen 674235Smarkfen #define USAGE() if (!smf_managed) usage() 684235Smarkfen /* 694235Smarkfen * Buffer length to read in pattern/properties. 704235Smarkfen */ 714235Smarkfen #define MAXLEN 1024 724235Smarkfen 734235Smarkfen /* Max length of tunnel interface string identifier */ 744235Smarkfen #define TUNNAMEMAXLEN LIFNAMSIZ 754235Smarkfen 764235Smarkfen /* 774235Smarkfen * Used by parse_one and parse/parse_action to communicate 784235Smarkfen * the errors. -1 is failure, which is not defined here. 794235Smarkfen */ 804235Smarkfen enum parse_errors {PARSE_SUCCESS, PARSE_EOF}; 814235Smarkfen 824235Smarkfen /* 834235Smarkfen * For spdsock_get_ext() diagnostics. 844235Smarkfen */ 854235Smarkfen #define SPDSOCK_DIAG_BUF_LEN 128 864235Smarkfen static char spdsock_diag_buf[SPDSOCK_DIAG_BUF_LEN]; 874235Smarkfen 884235Smarkfen /* 894235Smarkfen * Define CURL here so that while you are reading 904235Smarkfen * this code, it does not affect "vi" in pattern 914235Smarkfen * matching. 924235Smarkfen */ 934235Smarkfen #define CURL_BEGIN '{' 944235Smarkfen #define CURL_END '}' 955120Smarkfen #define BACK_SLASH '\\' 964235Smarkfen #define MAXARGS 20 974235Smarkfen #define NOERROR 0 984235Smarkfen 994235Smarkfen /* 1004235Smarkfen * IPSEC_CONF_ADD should start with 1, so that when multiple commands 1014235Smarkfen * are given, we can fail the request. 1024235Smarkfen */ 1034235Smarkfen 1044235Smarkfen enum ipsec_cmds {IPSEC_CONF_ADD = 1, IPSEC_CONF_DEL, IPSEC_CONF_VIEW, 1054235Smarkfen IPSEC_CONF_FLUSH, IPSEC_CONF_LIST, IPSEC_CONF_SUB}; 1064235Smarkfen 1074235Smarkfen static const char policy_conf_file[] = "/var/run/ipsecpolicy.conf"; 1084235Smarkfen static const char lock_file[] = "/var/run/ipsecconf.lock"; 1094235Smarkfen static const char index_tag[] = "#INDEX"; 1104235Smarkfen 1114235Smarkfen #define POLICY_CONF_FILE policy_conf_file 1124235Smarkfen #define LOCK_FILE lock_file 1134235Smarkfen #define INDEX_TAG index_tag 1144235Smarkfen 1154235Smarkfen /* 1164235Smarkfen * Valid algorithm length. 1174235Smarkfen */ 1184235Smarkfen #define VALID_ALG_LEN 40 1194235Smarkfen 1204235Smarkfen /* Types of Error messages */ 1214235Smarkfen typedef enum error_type {BAD_ERROR, DUP_ERROR, REQ_ERROR} error_type_t; 1224235Smarkfen 1234235Smarkfen /* Error message human readable conversions */ 1244235Smarkfen static char *sys_error_message(int); 1254235Smarkfen static void error_message(error_type_t, int, int); 1264235Smarkfen static int get_pf_pol_socket(void); 1274235Smarkfen 1284235Smarkfen static int cmd; 1294235Smarkfen static char *filename; 1304235Smarkfen static char lo_buf[MAXLEN]; /* Leftover buffer */ 1314235Smarkfen 1324235Smarkfen /* 1334235Smarkfen * The new SPD_EXT_TUN_NAME extension has a tunnel name in it. Use the empty 1344235Smarkfen * string ("", stored in the char value "all_polheads") for all policy heads 1354235Smarkfen * (global and all tunnels). Set interface_name to NULL for global-only, or 1364235Smarkfen * specify a name of an IP-in-IP tunnel. 1374235Smarkfen */ 1384235Smarkfen static char *interface_name; 1394235Smarkfen static char all_polheads; /* So we can easily get "". */ 1404235Smarkfen 1414235Smarkfen /* Error reporting stuff */ 1424235Smarkfen #define CBUF_LEN 4096 /* Maximum size of the cmd */ 1434235Smarkfen /* 1444235Smarkfen * Following are used for reporting errors with arguments. 1454235Smarkfen * We store the line numbers of each argument as we parse them, 1464235Smarkfen * so that the error reporting is more specific. We can have only 1475120Smarkfen * (MAXARGS - 1) arguments between any pair of CURL_BEGIN CURL_END. 1485120Smarkfen * Because a single command can be made up of multiple action/property 1495120Smarkfen * combinations, the maximum command size is (2 * (MAXARGS -1)) for each 1505120Smarkfen * of patterns, properties and actions. 1514235Smarkfen */ 1525120Smarkfen #define ARG_BUF_LEN ((2 * 3 * (MAXARGS - 1)) + 1) 1534235Smarkfen static int arg_indices[ARG_BUF_LEN]; 1544235Smarkfen static int argindex; 1554235Smarkfen static int linecount; 1564235Smarkfen static char cbuf[CBUF_LEN]; /* Command buffer */ 1574235Smarkfen static int cbuf_offset; 1584235Smarkfen 1594235Smarkfen 1604235Smarkfen #define BYPASS_POLICY_BOOST 0x00800000 1614235Smarkfen #define ESP_POLICY_BOOST 0x00400000 1624235Smarkfen #define AH_POLICY_BOOST 0x00200000 1634235Smarkfen #define INITIAL_BASE_PRIORITY 0x000fffff 1644235Smarkfen 1654235Smarkfen /* 1664235Smarkfen * the number used to order the 1674235Smarkfen * rules starts at a certain base and 1684235Smarkfen * goes down. i.e. rules earlier in 1694235Smarkfen * the file are checked first 1704235Smarkfen */ 1714235Smarkfen static uint32_t priority = INITIAL_BASE_PRIORITY; 1724235Smarkfen 1734235Smarkfen #define AH_AUTH 0 1744235Smarkfen #define ESP_ENCR 1 1754235Smarkfen #define ESP_AUTH 2 1764235Smarkfen 1774235Smarkfen 1784235Smarkfen /* 1794235Smarkfen * for deleting adds on error 1804235Smarkfen */ 1814235Smarkfen 1824235Smarkfen typedef struct d_list_s 1834235Smarkfen { 1844235Smarkfen struct d_list_s *next; 1854235Smarkfen int index; 1864235Smarkfen } d_list_t; 1874235Smarkfen 1884235Smarkfen static d_list_t *d_list = NULL; 1894235Smarkfen static d_list_t *d_tail = NULL; 1904235Smarkfen 1914235Smarkfen 1924235Smarkfen /* 1934235Smarkfen * Used for multi-homed source/dest hosts. 1944235Smarkfen */ 1954235Smarkfen static struct hostent *shp, *dhp; 1964235Smarkfen static unsigned int splen, dplen; 1974235Smarkfen static char tunif[TUNNAMEMAXLEN]; 1984235Smarkfen static boolean_t has_saprefix, has_daprefix; 1994235Smarkfen static uint32_t seq_cnt = 0; 2004235Smarkfen 2014235Smarkfen /* lexxed out action and related properties */ 2024235Smarkfen typedef struct ap_s 2034235Smarkfen { 2044235Smarkfen char *act; 2054235Smarkfen char *prop[MAXARGS + 1]; 2064235Smarkfen } ap_t; 2074235Smarkfen 2084235Smarkfen 2094235Smarkfen /* one lexxed out rule */ 2104235Smarkfen typedef struct act_prop_s { 2115120Smarkfen char *pattern[MAXARGS + 1]; 2124235Smarkfen ap_t ap[MAXARGS + 1]; 2134235Smarkfen } act_prop_t; 2144235Smarkfen 2154235Smarkfen typedef struct 2164235Smarkfen { 2174235Smarkfen uint8_t alg_id; 2184235Smarkfen uint32_t alg_minbits; 2194235Smarkfen uint32_t alg_maxbits; 2204235Smarkfen } algreq_t; 2214235Smarkfen 2224235Smarkfen /* structure to hold all information for one act_prop_t */ 2234235Smarkfen typedef struct ips_act_props_s { 2244235Smarkfen struct ips_act_props_s *iap_next; 2254235Smarkfen struct ips_conf_s *iap_head; 2264235Smarkfen 2274235Smarkfen /* 2284235Smarkfen * IPsec action types (in SPD_ATTR_TYPE attribute) 2294235Smarkfen * SPD_ACTTYPE_DROP 0x0001 2304235Smarkfen * SPD_ACTTYPE_PASS 0x0002 2314235Smarkfen * SPD_ACTTYPE_IPSEC 0x0003 2324235Smarkfen */ 2334235Smarkfen uint16_t iap_action; 2344235Smarkfen uint16_t iap_act_tok; 2354235Smarkfen 2364235Smarkfen /* 2374235Smarkfen * Action ATTR flags (in SPD_ATTR_FLAGS attribute) 2384235Smarkfen * SPD_APPLY_AH 0x0001 2394235Smarkfen * SPD_APPLY_ESP 0x0002 2404235Smarkfen * SPD_APPLY_SE 0x0004 * self-encapsulation * 2414235Smarkfen * SPD_APPLY_COMP 0x0008 * compression; NYI * 2424235Smarkfen * SPD_APPLY_UNIQUE 0x0010 * unique per-flow SA * 2434235Smarkfen * SPD_APPLY_BYPASS 0x0020 * bypass policy * 2444235Smarkfen */ 2454235Smarkfen uint16_t iap_attr; 2464235Smarkfen uint16_t iap_attr_tok[5]; 2474235Smarkfen 2484235Smarkfen algreq_t iap_aauth; 2494235Smarkfen algreq_t iap_eencr; 2504235Smarkfen algreq_t iap_eauth; 2514235Smarkfen 2524235Smarkfen uint32_t iap_life_soft_time; 2534235Smarkfen uint32_t iap_life_hard_time; 2544235Smarkfen uint32_t iap_life_soft_bytes; 2554235Smarkfen uint32_t iap_life_hard_bytes; 2564235Smarkfen 2574235Smarkfen } ips_act_props_t; 2584235Smarkfen 2594235Smarkfen #define V4_PART_OF_V6(v6) v6._S6_un._S6_u32[3] 2604235Smarkfen 2614235Smarkfen typedef struct ips_conf_s { 2624235Smarkfen /* selector */ 2634235Smarkfen uint16_t patt_tok[8]; 2644235Smarkfen uint8_t has_saddr; 2654235Smarkfen uint8_t has_daddr; 2664235Smarkfen uint8_t has_smask; 2674235Smarkfen uint8_t has_dmask; 2684235Smarkfen uint8_t has_type; 2694235Smarkfen uint8_t has_code; 2704235Smarkfen uint8_t has_negotiate; 2714235Smarkfen uint8_t has_tunnel; 2724235Smarkfen uint16_t swap; 2734235Smarkfen 2744235Smarkfen struct in6_addr ips_src_addr_v6; 2754235Smarkfen struct in6_addr ips_src_mask_v6; 2764235Smarkfen struct in6_addr ips_dst_addr_v6; 2774235Smarkfen struct in6_addr ips_dst_mask_v6; 2784235Smarkfen uint8_t ips_src_mask_len; 2794235Smarkfen uint8_t ips_dst_mask_len; 2804235Smarkfen in_port_t ips_src_port_min; 2814235Smarkfen in_port_t ips_src_port_max; 2824235Smarkfen in_port_t ips_dst_port_min; 2834235Smarkfen in_port_t ips_dst_port_max; 2844235Smarkfen uint8_t ips_icmp_type; 2854235Smarkfen uint8_t ips_icmp_type_end; 2864235Smarkfen uint8_t ips_icmp_code; 2874235Smarkfen uint8_t ips_icmp_code_end; 2884235Smarkfen uint8_t ips_ulp_prot; 2894235Smarkfen uint8_t ips_ipsec_prot; 2904235Smarkfen uint8_t ips_isv4; 2914235Smarkfen /* 2924235Smarkfen * SPD_RULE_FLAG_INBOUND 0x0001 2934235Smarkfen * SPD_RULE_FLAG_OUTBOUND 0x0002 2944235Smarkfen */ 2954235Smarkfen uint8_t ips_dir; 2964235Smarkfen /* 2974235Smarkfen * Keep track of tunnel separately due to explosion of ways to set 2984235Smarkfen * inbound/outbound. 2994235Smarkfen */ 3004235Smarkfen boolean_t ips_tunnel; 3014235Smarkfen uint64_t ips_policy_index; 3024235Smarkfen uint32_t ips_act_cnt; 3034235Smarkfen ips_act_props_t *ips_acts; 3044235Smarkfen } ips_conf_t; 3054235Smarkfen 3064235Smarkfen #define ips_src_addr V4_PART_OF_V6(ips_src_addr_v6) 3074235Smarkfen #define ips_dst_addr V4_PART_OF_V6(ips_dst_addr_v6) 3084235Smarkfen 3094235Smarkfen static int ipsecconf_nflag; /* Used only with -l option */ 3104235Smarkfen static int ipsecconf_qflag; /* Used only with -a|-r option */ 3114235Smarkfen 3124235Smarkfen typedef struct str_val { 3134235Smarkfen const char *string; 3144235Smarkfen int value; 3154235Smarkfen } str_val_t; 3164235Smarkfen 3174235Smarkfen typedef struct str_tval { 3184235Smarkfen const char *string; 3194235Smarkfen int tok_val; 3204235Smarkfen int value; 3214235Smarkfen } str_tval_t; 3224235Smarkfen 3234235Smarkfen static int parse_int(const char *); 3244235Smarkfen static int parse_index(const char *, char *); 3254235Smarkfen static int attach_tunname(spd_if_t *); 3264235Smarkfen static void usage(void); 3274235Smarkfen static int ipsec_conf_del(int, boolean_t); 3284235Smarkfen static int ipsec_conf_add(boolean_t, boolean_t); 3294235Smarkfen static int ipsec_conf_sub(void); 3304235Smarkfen static int ipsec_conf_flush(int); 3314235Smarkfen static int ipsec_conf_view(void); 3324235Smarkfen static int ipsec_conf_list(void); 3334235Smarkfen static int lock(void); 3344235Smarkfen static int unlock(int); 3354235Smarkfen static int parse_one(FILE *, act_prop_t *); 3364235Smarkfen static void reconfigure(); 3374235Smarkfen static void in_prefixlentomask(unsigned int, uchar_t *); 3384235Smarkfen static int in_getprefixlen(char *); 3394235Smarkfen static int parse_address(int, char *); 3404235Smarkfen #ifdef DEBUG_HEAVY 3414235Smarkfen static void pfpol_msg_dump(spd_msg_t *msg, char *); 3424235Smarkfen #endif /* DEBUG_HEAVY */ 3434235Smarkfen static void print_pfpol_msg(spd_msg_t *); 3444235Smarkfen static int pfp_delete_rule(uint64_t); 3454235Smarkfen static void ipsec_conf_admin(uint8_t); 3464235Smarkfen static void print_bit_range(int, int); 3474235Smarkfen static void nuke_adds(); 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 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 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 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 * 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 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 * 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 * 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 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 * 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; 8674235Smarkfen boolean_t use_ah, use_esp, use_espa; 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 9144235Smarkfen for (auth_idx = auth_min; auth_idx <= auth_max; auth_idx++) { 9154235Smarkfen auth_alg = WHICH_ALG(AH_AUTH, wild_auth, auth_idx); 9164235Smarkfen 9174235Smarkfen if (use_ah && 9184235Smarkfen !alg_rangecheck(AH_AUTH, auth_alg, 9195120Smarkfen &act_ptr->iap_aauth)) 9204235Smarkfen continue; 9214235Smarkfen 9224235Smarkfen 9234235Smarkfen for (eauth_idx = eauth_min; eauth_idx <= eauth_max; 9244235Smarkfen eauth_idx++) { 9254235Smarkfen eauth_alg = WHICH_ALG(ESP_AUTH, wild_eauth, 9264235Smarkfen eauth_idx); 9274235Smarkfen 9284235Smarkfen if (use_espa && 9294235Smarkfen !alg_rangecheck(ESP_AUTH, eauth_alg, 9304235Smarkfen &act_ptr->iap_eauth)) 9314235Smarkfen continue; 9324235Smarkfen 9334235Smarkfen tact.iap_eencr.alg_id = encr_alg; 9344235Smarkfen tact.iap_eauth.alg_id = eauth_alg; 9354235Smarkfen tact.iap_aauth.alg_id = auth_alg; 9364235Smarkfen 9374235Smarkfen (*act_cntp)++; 9384235Smarkfen ap = ips_act_props_to_action(ap, 9394235Smarkfen rule_priorityp, &tact); 9404235Smarkfen } 9414235Smarkfen } 9424235Smarkfen } 9434235Smarkfen 9444235Smarkfen #undef WHICH_ALG 9454235Smarkfen 9464235Smarkfen return (ap); 9474235Smarkfen } 9484235Smarkfen 9494235Smarkfen /* huge, but not safe since no length checking is done */ 9504235Smarkfen #define MAX_POL_MSG_LEN 16384 9514235Smarkfen 9524235Smarkfen 9534235Smarkfen /* 9544235Smarkfen * hand in some ips_conf_t's, get back an 9554235Smarkfen * iovec of pfpol messages. 9564235Smarkfen * this function converts the internal ips_conf_t into 9574235Smarkfen * a form that pf_pol can use. 9584235Smarkfen * return 0 on success, 1 on failure 9594235Smarkfen */ 9604235Smarkfen static int 9614235Smarkfen ips_conf_to_pfpol_msg(int ipsec_cmd, ips_conf_t *inConf, int num_ips, 9624235Smarkfen struct iovec *msg) 9634235Smarkfen { 9644235Smarkfen int i; 9654235Smarkfen ips_conf_t *conf; 9664235Smarkfen uint64_t *scratch = NULL; 9674235Smarkfen 9684235Smarkfen for (i = 0; i < num_ips; i++) { 9694235Smarkfen uint16_t *msg_len; 9704235Smarkfen uint16_t act_cnt = 0; 9714235Smarkfen uint64_t *next = NULL; 9724235Smarkfen spd_msg_t *spd_msg; 9734235Smarkfen spd_address_t *spd_address; 9744235Smarkfen struct spd_rule *spd_rule; 9754235Smarkfen struct spd_proto *spd_proto; 9764235Smarkfen struct spd_portrange *spd_portrange; 9774235Smarkfen struct spd_ext_actions *spd_ext_actions; 9784235Smarkfen struct spd_attribute *ap; 9794235Smarkfen struct spd_typecode *spd_typecode; 9804235Smarkfen spd_if_t *spd_if; 9814235Smarkfen ips_act_props_t *act_ptr; 9824235Smarkfen uint32_t rule_priority = 0; 9834235Smarkfen 9844235Smarkfen scratch = calloc(1, MAX_POL_MSG_LEN); 9854235Smarkfen msg[i].iov_base = (char *)scratch; 9864235Smarkfen if (scratch == NULL) { 9874235Smarkfen warn(gettext("memory")); 9884235Smarkfen return (1); 9894235Smarkfen } 9904235Smarkfen conf = &(inConf[i]); 9914235Smarkfen 9924235Smarkfen spd_msg = (spd_msg_t *)scratch; 9934235Smarkfen next = (uint64_t *)&(spd_msg[1]); 9944235Smarkfen 9954235Smarkfen msg_len = &(spd_msg->spd_msg_len); 9964235Smarkfen 9974235Smarkfen spd_msg->spd_msg_version = PF_POLICY_V1; 9984235Smarkfen spd_msg->spd_msg_pid = getpid(); 9994235Smarkfen spd_msg->spd_msg_seq = ++seq_cnt; 10004235Smarkfen 10014235Smarkfen switch (ipsec_cmd) { 10024235Smarkfen case SPD_ADDRULE: 10034235Smarkfen spd_msg->spd_msg_type = SPD_ADDRULE; 10044235Smarkfen break; 10054235Smarkfen 10064235Smarkfen default: 10074235Smarkfen warnx("%s %d", gettext("bad command:"), ipsec_cmd); 10084235Smarkfen spd_msg->spd_msg_type = SPD_ADDRULE; 10094235Smarkfen break; 10104235Smarkfen } 10114235Smarkfen 10124235Smarkfen /* 10134235Smarkfen * SELECTOR 10144235Smarkfen */ 10154235Smarkfen 10164235Smarkfen spd_msg->spd_msg_spdid = SPD_STANDBY; 10174235Smarkfen 10184235Smarkfen /* rule */ 10194235Smarkfen spd_rule = (struct spd_rule *)next; 10204235Smarkfen 10214235Smarkfen spd_rule->spd_rule_len = SPD_8TO64(sizeof (struct spd_rule)); 10224235Smarkfen spd_rule->spd_rule_type = SPD_EXT_RULE; 10234235Smarkfen spd_rule->spd_rule_flags = conf->ips_dir; 10244235Smarkfen if (conf->ips_tunnel) 10254235Smarkfen spd_rule->spd_rule_flags |= SPD_RULE_FLAG_TUNNEL; 10264235Smarkfen 10274235Smarkfen next = (uint64_t *)&(spd_rule[1]); 10284235Smarkfen 10294235Smarkfen /* proto */ 10304235Smarkfen if (conf->ips_ulp_prot != 0) { 10314235Smarkfen spd_proto = (struct spd_proto *)next; 10324235Smarkfen spd_proto->spd_proto_len = 10335120Smarkfen SPD_8TO64(sizeof (struct spd_proto)); 10344235Smarkfen spd_proto->spd_proto_exttype = SPD_EXT_PROTO; 10354235Smarkfen spd_proto->spd_proto_number = conf->ips_ulp_prot; 10364235Smarkfen next = (uint64_t *)&(spd_proto[1]); 10374235Smarkfen } 10384235Smarkfen 10394235Smarkfen /* tunnel */ 10404235Smarkfen if (conf->has_tunnel != 0) { 10414235Smarkfen spd_if = (spd_if_t *)next; 10424235Smarkfen spd_if->spd_if_len = 10434235Smarkfen SPD_8TO64(P2ROUNDUP(strlen(tunif) + 1, 8) + 10444235Smarkfen sizeof (spd_if_t)); 10454235Smarkfen spd_if->spd_if_exttype = SPD_EXT_TUN_NAME; 10464235Smarkfen (void) strlcpy((char *)spd_if->spd_if_name, tunif, 10475120Smarkfen TUNNAMEMAXLEN); 10484235Smarkfen next = (uint64_t *)(spd_if) + spd_if->spd_if_len; 10494235Smarkfen } 10504235Smarkfen 10514235Smarkfen /* icmp type/code */ 10524235Smarkfen if (conf->ips_ulp_prot == IPPROTO_ICMP || 10534235Smarkfen conf->ips_ulp_prot == IPPROTO_ICMPV6) { 10544235Smarkfen if (conf->has_type) { 10554235Smarkfen spd_typecode = (struct spd_typecode *)next; 10564235Smarkfen spd_typecode->spd_typecode_len = 10574235Smarkfen SPD_8TO64(sizeof (struct spd_typecode)); 10584235Smarkfen spd_typecode->spd_typecode_exttype = 10594235Smarkfen SPD_EXT_ICMP_TYPECODE; 10604235Smarkfen spd_typecode->spd_typecode_type = 10614235Smarkfen conf->ips_icmp_type; 10624235Smarkfen spd_typecode->spd_typecode_type_end = 10634235Smarkfen conf->ips_icmp_type_end; 10644235Smarkfen if (conf->has_code) { 10654235Smarkfen spd_typecode->spd_typecode_code = 10664235Smarkfen conf->ips_icmp_code; 10674235Smarkfen spd_typecode->spd_typecode_code_end = 10684235Smarkfen conf->ips_icmp_code_end; 10694235Smarkfen } else { 10704235Smarkfen spd_typecode->spd_typecode_code = 255; 10714235Smarkfen spd_typecode->spd_typecode_code_end 10724235Smarkfen = 255; 10734235Smarkfen } 10744235Smarkfen next = (uint64_t *)&(spd_typecode[1]); 10754235Smarkfen } 10764235Smarkfen } 10774235Smarkfen 10784235Smarkfen /* src port */ 10794235Smarkfen if (conf->ips_src_port_min != 0 || 10804235Smarkfen conf->ips_src_port_max != 0) { 10814235Smarkfen spd_portrange = (struct spd_portrange *)next; 10824235Smarkfen spd_portrange->spd_ports_len = 10835120Smarkfen SPD_8TO64(sizeof (struct spd_portrange)); 10844235Smarkfen spd_portrange->spd_ports_exttype = 10855120Smarkfen (conf->swap)?SPD_EXT_REMPORT:SPD_EXT_LCLPORT; 10864235Smarkfen spd_portrange->spd_ports_minport = 10875120Smarkfen conf->ips_src_port_min; 10884235Smarkfen spd_portrange->spd_ports_maxport = 10895120Smarkfen conf->ips_src_port_max; 10904235Smarkfen next = (uint64_t *)&(spd_portrange[1]); 10914235Smarkfen } 10924235Smarkfen /* dst port */ 10934235Smarkfen if (conf->ips_dst_port_min != 0 || 10944235Smarkfen conf->ips_dst_port_max != 0) { 10954235Smarkfen spd_portrange = (struct spd_portrange *)next; 10964235Smarkfen spd_portrange->spd_ports_len = 10975120Smarkfen SPD_8TO64(sizeof (struct spd_portrange)); 10984235Smarkfen spd_portrange->spd_ports_exttype = 10995120Smarkfen (conf->swap)?SPD_EXT_LCLPORT:SPD_EXT_REMPORT; 11004235Smarkfen spd_portrange->spd_ports_minport = 11015120Smarkfen conf->ips_dst_port_min; 11024235Smarkfen spd_portrange->spd_ports_maxport = 11035120Smarkfen conf->ips_dst_port_max; 11044235Smarkfen next = (uint64_t *)&(spd_portrange[1]); 11054235Smarkfen } 11064235Smarkfen 11074235Smarkfen /* saddr */ 11084235Smarkfen if (conf->has_saddr) { 11094235Smarkfen spd_address = (spd_address_t *)next; 11104235Smarkfen next = (uint64_t *)(spd_address + 1); 11114235Smarkfen 11124235Smarkfen spd_address->spd_address_exttype = 11135120Smarkfen (conf->swap)?SPD_EXT_REMADDR:SPD_EXT_LCLADDR; 11144235Smarkfen spd_address->spd_address_prefixlen = 11155120Smarkfen conf->ips_src_mask_len; 11164235Smarkfen 11174235Smarkfen if (conf->ips_isv4) { 11184235Smarkfen spd_address->spd_address_af = AF_INET; 11194235Smarkfen (void) memcpy(next, &(conf->ips_src_addr), 11205120Smarkfen sizeof (ipaddr_t)); 11214235Smarkfen spd_address->spd_address_len = 2; 11224235Smarkfen next += SPD_8TO64(sizeof (ipaddr_t) + 4); 11234235Smarkfen if (!conf->has_smask) 11244235Smarkfen spd_address->spd_address_prefixlen = 32; 11254235Smarkfen } else { 11264235Smarkfen spd_address->spd_address_af = AF_INET6; 11274235Smarkfen (void) memcpy(next, &(conf->ips_src_addr_v6), 11284235Smarkfen sizeof (in6_addr_t)); 11294235Smarkfen spd_address->spd_address_len = 3; 11304235Smarkfen next += SPD_8TO64(sizeof (in6_addr_t)); 11314235Smarkfen if (!conf->has_smask) 11324235Smarkfen spd_address->spd_address_prefixlen 11335120Smarkfen = 128; 11344235Smarkfen } 11354235Smarkfen } 11364235Smarkfen 11374235Smarkfen /* daddr */ 11384235Smarkfen if (conf->has_daddr) { 11394235Smarkfen spd_address = (spd_address_t *)next; 11404235Smarkfen 11414235Smarkfen next = (uint64_t *)(spd_address + 1); 11424235Smarkfen 11434235Smarkfen spd_address->spd_address_exttype = 11445120Smarkfen (conf->swap)?SPD_EXT_LCLADDR:SPD_EXT_REMADDR; 11454235Smarkfen spd_address->spd_address_prefixlen = 11465120Smarkfen conf->ips_dst_mask_len; 11474235Smarkfen 11484235Smarkfen if (conf->ips_isv4) { 11494235Smarkfen spd_address->spd_address_af = AF_INET; 11504235Smarkfen (void) memcpy(next, &conf->ips_dst_addr, 11514235Smarkfen sizeof (ipaddr_t)); 11524235Smarkfen spd_address->spd_address_len = 2; 11534235Smarkfen /* "+ 4" below is for padding. */ 11544235Smarkfen next += SPD_8TO64(sizeof (ipaddr_t) + 4); 11554235Smarkfen if (!conf->has_dmask) 11564235Smarkfen spd_address->spd_address_prefixlen = 32; 11574235Smarkfen } else { 11584235Smarkfen spd_address->spd_address_af = AF_INET6; 11594235Smarkfen (void) memcpy(next, &(conf->ips_dst_addr_v6), 11604235Smarkfen sizeof (in6_addr_t)); 11614235Smarkfen spd_address->spd_address_len = 3; 11624235Smarkfen next += SPD_8TO64(sizeof (in6_addr_t)); 11634235Smarkfen if (!conf->has_dmask) 11644235Smarkfen spd_address->spd_address_prefixlen 11655120Smarkfen = 128; 11664235Smarkfen } 11674235Smarkfen } 11684235Smarkfen 11694235Smarkfen /* actions */ 11704235Smarkfen spd_ext_actions = (struct spd_ext_actions *)next; 11714235Smarkfen 11724235Smarkfen spd_ext_actions->spd_actions_exttype = SPD_EXT_ACTION; 11734235Smarkfen 11744235Smarkfen act_ptr = conf->ips_acts; 11754235Smarkfen ap = (struct spd_attribute *)(&spd_ext_actions[1]); 11764235Smarkfen 11774235Smarkfen rule_priority = priority--; 11784235Smarkfen 11794235Smarkfen for (act_ptr = conf->ips_acts; act_ptr != NULL; 11804235Smarkfen act_ptr = act_ptr->iap_next) { 11814235Smarkfen ap = ips_act_wild_props_to_action(ap, &rule_priority, 11824235Smarkfen &act_cnt, act_ptr); 11834235Smarkfen } 11844235Smarkfen ap[-1].spd_attr_tag = SPD_ATTR_END; 11854235Smarkfen 11864235Smarkfen next = (uint64_t *)ap; 11874235Smarkfen 11884235Smarkfen spd_rule->spd_rule_priority = rule_priority; 11894235Smarkfen 11904235Smarkfen msg[i].iov_len = (uintptr_t)next - (uintptr_t)msg[i].iov_base; 11914235Smarkfen *msg_len = (uint16_t)SPD_8TO64(msg[i].iov_len); 11924235Smarkfen spd_ext_actions->spd_actions_count = act_cnt; 11934235Smarkfen spd_ext_actions->spd_actions_len = 11944235Smarkfen SPD_8TO64((uintptr_t)next - (uintptr_t)spd_ext_actions); 11954235Smarkfen #ifdef DEBUG_HEAVY 11964235Smarkfen printf("pfpol msg len in uint64_t's = %d\n", *msg_len); 11974235Smarkfen printf("pfpol test_len in bytes = %d\n", msg[i].iov_len); 11984235Smarkfen pfpol_msg_dump((spd_msg_t *)scratch, 11994235Smarkfen "ips_conf_to_pfpol_msg"); 12004235Smarkfen #endif 12014235Smarkfen } 12024235Smarkfen 12034235Smarkfen #undef ATTR 12044235Smarkfen return (0); 12054235Smarkfen } 12064235Smarkfen 12074235Smarkfen static int 12084235Smarkfen get_pf_pol_socket(void) 12094235Smarkfen { 12104235Smarkfen int s = socket(PF_POLICY, SOCK_RAW, PF_POLICY_V1); 12114235Smarkfen if (s < 0) { 12124235Smarkfen if (errno == EPERM) { 12134235Smarkfen EXIT_BADPERM("Insufficient privileges to open " 12144235Smarkfen "PF_POLICY socket."); 12154235Smarkfen } else { 12164235Smarkfen warn(gettext("(loading pf_policy) socket:")); 12174235Smarkfen } 12184235Smarkfen } 12194235Smarkfen 12204235Smarkfen return (s); 12214235Smarkfen } 12224235Smarkfen 12234235Smarkfen 12244235Smarkfen static int 12254235Smarkfen send_pf_pol_message(int ipsec_cmd, ips_conf_t *conf, int *diag) 12264235Smarkfen { 12274235Smarkfen int retval; 12284235Smarkfen int cnt; 12294235Smarkfen int total_len; 12304235Smarkfen struct iovec polmsg; 12314235Smarkfen spd_msg_t *return_buf; 12324235Smarkfen spd_ext_t *exts[SPD_EXT_MAX+1]; 12334235Smarkfen int fd = get_pf_pol_socket(); 12344235Smarkfen 12354235Smarkfen *diag = 0; 12364235Smarkfen 12374235Smarkfen if (fd < 0) 12384235Smarkfen return (EBADF); 12394235Smarkfen 12404235Smarkfen retval = ips_conf_to_pfpol_msg(ipsec_cmd, conf, 1, &polmsg); 12414235Smarkfen 12424235Smarkfen if (retval) { 12434235Smarkfen (void) close(fd); 12444235Smarkfen return (ENOMEM); 12454235Smarkfen } 12464235Smarkfen 12474235Smarkfen total_len = polmsg.iov_len; 12484235Smarkfen 12494235Smarkfen cnt = writev(fd, &polmsg, 1); 12504235Smarkfen 12514235Smarkfen #ifdef DEBUG_HEAVY 12524235Smarkfen (void) printf("cnt = %d\n", cnt); 12534235Smarkfen #endif 12544235Smarkfen if (cnt < 0) { 12554235Smarkfen warn(gettext("pf_pol write")); 12564235Smarkfen } else { 12574235Smarkfen return_buf = (spd_msg_t *)calloc(total_len, 1); 12584235Smarkfen 12594235Smarkfen if (return_buf == NULL) { 12604235Smarkfen warn(gettext("memory")); 12614235Smarkfen } else { 12624235Smarkfen cnt = read(fd, (void*)return_buf, total_len); 12634235Smarkfen #ifdef DEBUG_HEAVY 12644235Smarkfen (void) printf("pf_pol read: cnt = %d(%d)\n", cnt, 12654235Smarkfen total_len); 12664235Smarkfen #endif 12674235Smarkfen 12684235Smarkfen if (cnt > 8 && return_buf->spd_msg_errno) { 12694235Smarkfen *diag = return_buf->spd_msg_diagnostic; 12704235Smarkfen if (!ipsecconf_qflag) { 12714235Smarkfen warnx("%s: %s", 12724235Smarkfen gettext("Kernel returned"), 12734235Smarkfen sys_error_message( 12744235Smarkfen return_buf->spd_msg_errno)); 12754235Smarkfen } 12764235Smarkfen if (*diag != 0) 12774235Smarkfen (void) printf(gettext( 12784235Smarkfen "\t(spdsock diagnostic: %s)\n"), 12794235Smarkfen spdsock_diag(*diag)); 12804235Smarkfen #ifdef DEBUG_HEAVY 12814235Smarkfen pfpol_msg_dump((spd_msg_t *)polmsg.iov_base, 12824235Smarkfen "message in"); 12834235Smarkfen pfpol_msg_dump(return_buf, 12844235Smarkfen "send_pf_pol_message"); 12854235Smarkfen #endif 12864235Smarkfen retval = return_buf->spd_msg_errno; 12874235Smarkfen free(return_buf); 12884235Smarkfen free(polmsg.iov_base); 12894235Smarkfen (void) close(fd); 12904235Smarkfen return (retval); 12914235Smarkfen } 12924235Smarkfen 12934235Smarkfen retval = spdsock_get_ext(exts, return_buf, 12944235Smarkfen return_buf->spd_msg_len, NULL, 0); 12954235Smarkfen /* ignore retval */ 12964235Smarkfen 12974235Smarkfen if (exts[SPD_EXT_RULE]) { 12984235Smarkfen conf->ips_policy_index = 12994235Smarkfen ((struct spd_rule *) 13005120Smarkfen exts[SPD_EXT_RULE])->spd_rule_index; 13014235Smarkfen 13024235Smarkfen if (add_index(conf->ips_policy_index)) { 13034235Smarkfen free(return_buf); 13044235Smarkfen free(polmsg.iov_base); 13054235Smarkfen (void) close(fd); 13064235Smarkfen return (ENOMEM); 13074235Smarkfen } 13084235Smarkfen } 13094235Smarkfen 13104235Smarkfen free(return_buf); 13114235Smarkfen } 13124235Smarkfen } 13134235Smarkfen 13144235Smarkfen free(polmsg.iov_base); 13154235Smarkfen (void) close(fd); 13164235Smarkfen 13174235Smarkfen return (0); 13184235Smarkfen 13194235Smarkfen } 13204235Smarkfen 13214235Smarkfen int 13224235Smarkfen main(int argc, char *argv[]) 13234235Smarkfen { 13244235Smarkfen int ret, flushret; 13254235Smarkfen int c; 13264235Smarkfen int index; 13274235Smarkfen boolean_t smf_managed; 13284235Smarkfen boolean_t just_check = B_FALSE; 13294235Smarkfen 13304235Smarkfen char *smf_warning = gettext( 13315120Smarkfen "\n\tIPsec policy should be managed using smf(5). Modifying\n" 13325120Smarkfen "\tthe IPsec policy from the command line while the 'policy'\n" 13335120Smarkfen "\tservice is enabled could result in an inconsistent\n" 13345120Smarkfen "\tsecurity policy.\n\n"); 13354235Smarkfen 13364235Smarkfen flushret = 0; 13374235Smarkfen 13384235Smarkfen (void) setlocale(LC_ALL, ""); 13394235Smarkfen #if !defined(TEXT_DOMAIN) 13404235Smarkfen #define TEXT_DOMAIN "SYS_TEST" 13414235Smarkfen #endif 13424235Smarkfen (void) textdomain(TEXT_DOMAIN); 13434235Smarkfen 13444235Smarkfen openlog("ipsecconf", LOG_CONS, LOG_AUTH); 13454235Smarkfen 13464235Smarkfen /* 13474235Smarkfen * We don't immediately check for privilege here. This is done by IP 13484235Smarkfen * when we open /dev/ip below. 13494235Smarkfen */ 13504235Smarkfen 13514235Smarkfen if (argc == 1) { 13524235Smarkfen cmd = IPSEC_CONF_VIEW; 13534235Smarkfen goto done; 13544235Smarkfen } 13554235Smarkfen my_fmri = getenv("SMF_FMRI"); 13564235Smarkfen if (my_fmri == NULL) 13574235Smarkfen smf_managed = B_FALSE; 13584235Smarkfen else 13594235Smarkfen smf_managed = B_TRUE; 13604235Smarkfen 13614235Smarkfen while ((c = getopt(argc, argv, "nlfLFa:qd:r:i:c:")) != EOF) { 13624235Smarkfen switch (c) { 13634235Smarkfen case 'F': 13644235Smarkfen if (interface_name != NULL) { 13654235Smarkfen USAGE(); 13664235Smarkfen EXIT_FATAL("interface name not required."); 13674235Smarkfen } 13684235Smarkfen /* Apply to all policy heads - global and tunnels. */ 13694235Smarkfen interface_name = &all_polheads; 13704235Smarkfen /* FALLTHRU */ 13714235Smarkfen case 'f': 13724235Smarkfen /* Only one command at a time */ 13734235Smarkfen if (cmd != 0) { 13744235Smarkfen USAGE(); 13754235Smarkfen EXIT_FATAL("Multiple commands specified"); 13764235Smarkfen } 13774235Smarkfen cmd = IPSEC_CONF_FLUSH; 13784235Smarkfen break; 13794235Smarkfen case 'L': 13804235Smarkfen if (interface_name != NULL) { 13814235Smarkfen USAGE(); 13824235Smarkfen EXIT_FATAL("interface name not required."); 13834235Smarkfen } 13844235Smarkfen /* Apply to all policy heads - global and tunnels. */ 13854235Smarkfen interface_name = &all_polheads; 13864235Smarkfen /* FALLTHRU */ 13874235Smarkfen case 'l': 13884235Smarkfen /* Only one command at a time */ 13894235Smarkfen if (cmd != 0) { 13904235Smarkfen USAGE(); 13914235Smarkfen EXIT_FATAL("Multiple commands specified"); 13924235Smarkfen } 13934235Smarkfen cmd = IPSEC_CONF_LIST; 13944235Smarkfen break; 13954235Smarkfen case 'c': 13964235Smarkfen just_check = B_TRUE; 13974235Smarkfen ipsecconf_qflag++; 13984235Smarkfen /* FALLTHRU */ 13994235Smarkfen case 'a': 14004235Smarkfen /* Only one command at a time, and no interface name */ 14014235Smarkfen if (cmd != 0 || interface_name != NULL) { 14024235Smarkfen USAGE(); 14034235Smarkfen EXIT_FATAL("Multiple commands or interface " 14044235Smarkfen "not required."); 14054235Smarkfen } 14064235Smarkfen cmd = IPSEC_CONF_ADD; 14074235Smarkfen filename = optarg; 14084235Smarkfen break; 14094235Smarkfen case 'd': 14104235Smarkfen /* 14114235Smarkfen * Only one command at a time. Interface name is 14124235Smarkfen * optional. 14134235Smarkfen */ 14144235Smarkfen if (cmd != 0) { 14154235Smarkfen USAGE(); 14164235Smarkfen EXIT_FATAL("Multiple commands specified"); 14174235Smarkfen } 14184235Smarkfen cmd = IPSEC_CONF_DEL; 14194235Smarkfen index = parse_index(optarg, NULL); 14204235Smarkfen break; 14214235Smarkfen case 'n' : 14224235Smarkfen ipsecconf_nflag++; 14234235Smarkfen break; 14244235Smarkfen case 'q' : 14254235Smarkfen ipsecconf_qflag++; 14264235Smarkfen break; 14274235Smarkfen case 'r' : 14284235Smarkfen /* Only one command at a time, and no interface name */ 14294235Smarkfen if (cmd != 0 || interface_name != NULL) { 14304235Smarkfen USAGE(); 14314235Smarkfen EXIT_FATAL("Multiple commands or interface " 14324235Smarkfen "not required."); 14334235Smarkfen } 14344235Smarkfen cmd = IPSEC_CONF_SUB; 14354235Smarkfen filename = optarg; 14364235Smarkfen break; 14374235Smarkfen case 'i': 14384235Smarkfen if (interface_name != NULL) { 14394235Smarkfen EXIT_FATAL("Interface name already selected"); 14404235Smarkfen } 14414235Smarkfen interface_name = optarg; 14424235Smarkfen /* Check for some cretin using the all-polheads name. */ 14434235Smarkfen if (strlen(optarg) == 0) { 14444235Smarkfen USAGE(); 14454235Smarkfen EXIT_FATAL("Invalid interface name."); 14464235Smarkfen } 14474235Smarkfen break; 14484235Smarkfen default : 14494235Smarkfen USAGE(); 14504235Smarkfen EXIT_FATAL("Bad usage."); 14514235Smarkfen } 14524235Smarkfen } 14534235Smarkfen 14544235Smarkfen done: 14554235Smarkfen ret = 0; 14564235Smarkfen lfd = lock(); 14574235Smarkfen 14584235Smarkfen /* 14594235Smarkfen * ADD, FLUSH, DELETE needs to do two operations. 14604235Smarkfen * 14614235Smarkfen * 1) Update/delete/empty the POLICY_CONF_FILE. 14624235Smarkfen * 2) Make an ioctl and tell IP to update its state. 14634235Smarkfen * 14644235Smarkfen * We already lock()ed so that only one instance of this 14654235Smarkfen * program runs. We also need to make sure that the above 14664235Smarkfen * operations are atomic i.e we don't want to update the file 14674235Smarkfen * and get interrupted before we could tell IP. To make it 14684235Smarkfen * atomic we block all the signals and restore them. 14694235Smarkfen */ 14704235Smarkfen switch (cmd) { 14714235Smarkfen case IPSEC_CONF_LIST: 14724235Smarkfen fetch_algorithms(); 14734235Smarkfen ret = ipsec_conf_list(); 14744235Smarkfen break; 14754235Smarkfen case IPSEC_CONF_FLUSH: 14764235Smarkfen if ((ret = block_all_signals()) == -1) { 14774235Smarkfen break; 14784235Smarkfen } 14794235Smarkfen if (!smf_managed && !ipsecconf_qflag) 14804235Smarkfen (void) fprintf(stdout, "%s", smf_warning); 14814235Smarkfen ret = ipsec_conf_flush(SPD_ACTIVE); 14824235Smarkfen (void) restore_all_signals(); 14834235Smarkfen break; 14844235Smarkfen case IPSEC_CONF_VIEW: 14854235Smarkfen if (interface_name != NULL) { 14864235Smarkfen EXIT_FATAL("Cannot view for one interface only."); 14874235Smarkfen } 14884235Smarkfen ret = ipsec_conf_view(); 14894235Smarkfen break; 14904235Smarkfen case IPSEC_CONF_DEL: 14914235Smarkfen if (index == -1) { 14924235Smarkfen warnx(gettext("Invalid index")); 14934235Smarkfen ret = -1; 14944235Smarkfen break; 14954235Smarkfen } 14964235Smarkfen if ((ret = block_all_signals()) == -1) { 14974235Smarkfen break; 14984235Smarkfen } 14994235Smarkfen if (!smf_managed && !ipsecconf_qflag) 15004235Smarkfen (void) fprintf(stdout, "%s", smf_warning); 15014235Smarkfen ret = ipsec_conf_del(index, B_FALSE); 15024235Smarkfen (void) restore_all_signals(); 15034235Smarkfen flushret = ipsec_conf_flush(SPD_STANDBY); 15044235Smarkfen break; 15054235Smarkfen case IPSEC_CONF_ADD: 15064235Smarkfen /* 15074235Smarkfen * The IPsec kernel modules should only be loaded 15084235Smarkfen * if there is a policy to install, for this 15094235Smarkfen * reason ipsec_conf_add() calls fetch_algorithms() 15104235Smarkfen * and ipsec_conf_flush() only when appropriate. 15114235Smarkfen */ 15124235Smarkfen if ((ret = block_all_signals()) == -1) { 15134235Smarkfen break; 15144235Smarkfen } 15154235Smarkfen if (!smf_managed && !ipsecconf_qflag) 15164235Smarkfen (void) fprintf(stdout, "%s", smf_warning); 15174235Smarkfen ret = ipsec_conf_add(just_check, smf_managed); 15184235Smarkfen (void) restore_all_signals(); 15194235Smarkfen break; 15204235Smarkfen case IPSEC_CONF_SUB: 15214235Smarkfen fetch_algorithms(); 15224235Smarkfen if ((ret = block_all_signals()) == -1) { 15234235Smarkfen break; 15244235Smarkfen } 15254235Smarkfen if (!smf_managed && !ipsecconf_qflag) 15264235Smarkfen (void) fprintf(stdout, "%s", smf_warning); 15274235Smarkfen ret = ipsec_conf_sub(); 15284235Smarkfen (void) restore_all_signals(); 15294235Smarkfen flushret = ipsec_conf_flush(SPD_STANDBY); 15304235Smarkfen break; 15314235Smarkfen default : 15324235Smarkfen /* If no argument is given but a "-" */ 15334235Smarkfen USAGE(); 15344235Smarkfen EXIT_FATAL("Bad usage."); 15354235Smarkfen } 15364235Smarkfen 15374235Smarkfen (void) unlock(lfd); 15384235Smarkfen if (ret != 0 || flushret != 0) 15394235Smarkfen ret = 1; 15404235Smarkfen return (ret); 15414235Smarkfen } 15424235Smarkfen 15434235Smarkfen static void 15444235Smarkfen perm_check(void) 15454235Smarkfen { 15464235Smarkfen if (errno == EACCES) 15474235Smarkfen EXIT_BADPERM("Insufficient privilege to run ipsecconf."); 15484235Smarkfen else 15494235Smarkfen warn(gettext("Cannot open lock file %s"), LOCK_FILE); 15504235Smarkfen 15514235Smarkfen EXIT_BADPERM(NULL); 15524235Smarkfen } 15534235Smarkfen 15544235Smarkfen static int 15554235Smarkfen lock() 15564235Smarkfen { 15574235Smarkfen int fd; 15584235Smarkfen struct stat sbuf1; 15594235Smarkfen struct stat sbuf2; 15604235Smarkfen 15614235Smarkfen /* 15624235Smarkfen * Open the file with O_CREAT|O_EXCL. If it exists already, it 15634235Smarkfen * will fail. If it already exists, check whether it looks like 15644235Smarkfen * the one we created. 15654235Smarkfen */ 15664235Smarkfen (void) umask(0077); 15674235Smarkfen if ((fd = open(LOCK_FILE, O_EXCL|O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)) 15684235Smarkfen == -1) { 15694235Smarkfen if (errno != EEXIST) { 15704235Smarkfen /* Some other problem. Will exit. */ 15714235Smarkfen perm_check(); 15724235Smarkfen } 15734235Smarkfen 15744235Smarkfen /* 15754235Smarkfen * open() returned an EEXIST error. We don't fail yet 15764235Smarkfen * as it could be a residual from a previous 15774235Smarkfen * execution. 15784235Smarkfen * File exists. make sure it is OK. We need to lstat() 15794235Smarkfen * as fstat() stats the file pointed to by the symbolic 15804235Smarkfen * link. 15814235Smarkfen */ 15824235Smarkfen if (lstat(LOCK_FILE, &sbuf1) == -1) { 15834235Smarkfen EXIT_FATAL2("Cannot lstat lock file %s", LOCK_FILE); 15844235Smarkfen } 15854235Smarkfen /* 15864235Smarkfen * Check whether it is a regular file and not a symbolic 15874235Smarkfen * link. Its link count should be 1. The owner should be 15884235Smarkfen * root and the file should be empty. 15894235Smarkfen */ 15904235Smarkfen if (!S_ISREG(sbuf1.st_mode) || 15914235Smarkfen sbuf1.st_nlink != 1 || 15924235Smarkfen sbuf1.st_uid != 0 || 15934235Smarkfen sbuf1.st_size != 0) { 15944235Smarkfen EXIT_FATAL2("Bad lock file %s", LOCK_FILE); 15954235Smarkfen } 15964235Smarkfen if ((fd = open(LOCK_FILE, O_CREAT|O_RDWR, 15974235Smarkfen S_IRUSR|S_IWUSR)) == -1) { 15984235Smarkfen /* Will exit */ 15994235Smarkfen perm_check(); 16004235Smarkfen } 16014235Smarkfen /* 16024235Smarkfen * Check whether we opened the file that we lstat()ed. 16034235Smarkfen */ 16044235Smarkfen if (fstat(fd, &sbuf2) == -1) { 16054235Smarkfen EXIT_FATAL2("Cannot lstat lock file %s", LOCK_FILE); 16064235Smarkfen } 16074235Smarkfen if (sbuf1.st_dev != sbuf2.st_dev || 16084235Smarkfen sbuf1.st_ino != sbuf2.st_ino) { 16094235Smarkfen /* File changed after we did the lstat() above */ 16104235Smarkfen EXIT_FATAL2("Bad lock file %s", LOCK_FILE); 16114235Smarkfen } 16124235Smarkfen } 16134235Smarkfen if (lockf(fd, F_LOCK, 0) == -1) { 16144235Smarkfen EXIT_FATAL2("Cannot lockf %s", LOCK_FILE); 16154235Smarkfen } 16164235Smarkfen return (fd); 16174235Smarkfen } 16184235Smarkfen 16194235Smarkfen static int 16204235Smarkfen unlock(int fd) 16214235Smarkfen { 16224235Smarkfen if (lockf(fd, F_ULOCK, 0) == -1) { 16234235Smarkfen warn("lockf"); 16244235Smarkfen return (-1); 16254235Smarkfen } 16264235Smarkfen return (0); 16274235Smarkfen } 16284235Smarkfen 16294235Smarkfen /* send in TOK_* */ 16304235Smarkfen static void 16314235Smarkfen print_pattern_string(int type) 16324235Smarkfen { 16334235Smarkfen int j; 16344235Smarkfen 16354235Smarkfen for (j = 0; pattern_table[j].string != NULL; j++) { 16364235Smarkfen if (type == pattern_table[j].tok_val) { 16374235Smarkfen (void) printf("%s ", pattern_table[j].string); 16384235Smarkfen return; 16394235Smarkfen } 16404235Smarkfen } 16414235Smarkfen } 16424235Smarkfen 16434235Smarkfen static void 16444235Smarkfen print_icmp_typecode(uint8_t type, uint8_t type_end, uint8_t code, 16454235Smarkfen uint8_t code_end) 16464235Smarkfen { 16474235Smarkfen (void) printf("type %d", type); 16484235Smarkfen if (type_end != type) 16494235Smarkfen (void) printf("-%d ", type_end); 16504235Smarkfen else 16514235Smarkfen (void) printf(" "); 16524235Smarkfen if (code != 255) { 16534235Smarkfen (void) printf("code %d", code); 16544235Smarkfen if (code_end != code) 16554235Smarkfen (void) printf("-%d ", code_end); 16564235Smarkfen else 16574235Smarkfen (void) printf(" "); 16584235Smarkfen } 16594235Smarkfen } 16604235Smarkfen 16614235Smarkfen 16624235Smarkfen static void 16634235Smarkfen print_spd_flags(uint32_t flags) 16644235Smarkfen { 16654235Smarkfen flags &= (SPD_RULE_FLAG_INBOUND|SPD_RULE_FLAG_OUTBOUND); 16664235Smarkfen 16674235Smarkfen if (flags == SPD_RULE_FLAG_OUTBOUND) 16684235Smarkfen (void) printf("dir out "); 16694235Smarkfen else if (flags == SPD_RULE_FLAG_INBOUND) 16704235Smarkfen (void) printf("dir in "); 16714235Smarkfen else if (flags == (SPD_RULE_FLAG_INBOUND|SPD_RULE_FLAG_OUTBOUND)) 16724235Smarkfen (void) printf("dir both "); 16734235Smarkfen } 16744235Smarkfen 16754235Smarkfen static void 16764235Smarkfen print_bit_range(int min, int max) 16774235Smarkfen { 16784235Smarkfen if (min != 0 || (max != 0 && max != SPD_MAX_MAXBITS)) { 16794235Smarkfen (void) printf("("); 16804235Smarkfen if (min != 0) 16814235Smarkfen (void) printf("%d", min); 16824235Smarkfen if (min != 0 && max != 0 && min != max) { 16834235Smarkfen (void) printf(".."); 16844235Smarkfen if (max != 0 && max != SPD_MAX_MAXBITS) 16854235Smarkfen (void) printf("%d", max); 16864235Smarkfen } 16874235Smarkfen (void) printf(")"); 16884235Smarkfen } 16894235Smarkfen } 16904235Smarkfen 16914235Smarkfen static void 16924235Smarkfen print_alg(const char *tag, algreq_t *algreq, int proto_num) 16934235Smarkfen { 16944235Smarkfen int min = algreq->alg_minbits; 16954235Smarkfen int max = algreq->alg_maxbits; 16964235Smarkfen struct ipsecalgent *alg; 16974235Smarkfen 16984235Smarkfen /* 16994235Smarkfen * This function won't be called with alg_id == 0, so we don't 17004235Smarkfen * have to worry about ANY vs. NONE here. 17014235Smarkfen */ 17024235Smarkfen 17034235Smarkfen (void) printf("%s ", tag); 17044235Smarkfen 17054235Smarkfen alg = getipsecalgbynum(algreq->alg_id, proto_num, NULL); 17064235Smarkfen if (alg == NULL) { 17074235Smarkfen (void) printf("%d", algreq->alg_id); 17084235Smarkfen } else { 17094235Smarkfen (void) printf("%s", alg->a_names[0]); 17104235Smarkfen freeipsecalgent(alg); 17114235Smarkfen } 17124235Smarkfen 17134235Smarkfen print_bit_range(min, max); 17144235Smarkfen (void) printf(" "); 17154235Smarkfen } 17164235Smarkfen 17174235Smarkfen static void 17184235Smarkfen print_ulp(uint8_t proto) 17194235Smarkfen { 17204235Smarkfen struct protoent *pe; 17214235Smarkfen 17224235Smarkfen if (proto == 0) 17234235Smarkfen return; 17244235Smarkfen 17254235Smarkfen print_pattern_string(TOK_ulp); 17264235Smarkfen pe = NULL; 17274235Smarkfen if (!ipsecconf_nflag) { 17284235Smarkfen pe = getprotobynumber(proto); 17294235Smarkfen } 17304235Smarkfen if (pe != NULL) 17314235Smarkfen (void) printf("%s ", pe->p_name); 17324235Smarkfen else 17334235Smarkfen (void) printf("%d ", proto); 17344235Smarkfen } 17354235Smarkfen 17364235Smarkfen /* needs to do ranges */ 17374235Smarkfen static void 17384235Smarkfen print_port(uint16_t in_port, int type) 17394235Smarkfen { 17404235Smarkfen in_port_t port = ntohs(in_port); 17414235Smarkfen struct servent *sp; 17424235Smarkfen 17434235Smarkfen if (port == 0) 17444235Smarkfen return; 17454235Smarkfen 17464235Smarkfen print_pattern_string(type); 17474235Smarkfen sp = NULL; 17484235Smarkfen if (!ipsecconf_nflag) 17494235Smarkfen sp = getservbyport(port, NULL); 17504235Smarkfen 17514235Smarkfen if (sp != NULL) 17524235Smarkfen (void) printf("%s ", sp->s_name); 17534235Smarkfen else 17544235Smarkfen (void) printf("%d ", port); 17554235Smarkfen } 17564235Smarkfen 17574235Smarkfen /* 17584235Smarkfen * Print the address, given as "raw" input via the void pointer. 17594235Smarkfen */ 17604235Smarkfen static void 17614235Smarkfen print_raw_address(void *input, boolean_t isv4) 17624235Smarkfen { 17634235Smarkfen char *cp; 17644235Smarkfen struct hostent *hp; 17654235Smarkfen char domain[MAXHOSTNAMELEN + 1]; 17664235Smarkfen struct in_addr addr; 17674235Smarkfen struct in6_addr addr6; 17684235Smarkfen char abuf[INET6_ADDRSTRLEN]; 17694235Smarkfen int error_num; 17704235Smarkfen struct in6_addr in_addr; 17714235Smarkfen uchar_t *addr_ptr; 17724235Smarkfen sa_family_t af; 17734235Smarkfen int addr_len; 17744235Smarkfen 17754235Smarkfen if (isv4) { 17764235Smarkfen af = AF_INET; 17774235Smarkfen (void) memcpy(&V4_PART_OF_V6(in_addr), input, 4); 17784235Smarkfen /* we don't print unspecified addresses */ 17794235Smarkfen IN6_V4MAPPED_TO_INADDR(&in_addr, &addr); 17804235Smarkfen if (addr.s_addr == INADDR_ANY) 17814235Smarkfen return; 17824235Smarkfen addr_ptr = (uchar_t *)&addr.s_addr; 17834235Smarkfen addr_len = IPV4_ADDR_LEN; 17844235Smarkfen } else { 17854235Smarkfen (void) memcpy(&addr6, input, 16); 17864235Smarkfen af = AF_INET6; 17874235Smarkfen /* we don't print unspecified addresses */ 17884235Smarkfen if (IN6_IS_ADDR_UNSPECIFIED(&addr6)) 17894235Smarkfen return; 17904235Smarkfen addr_ptr = (uchar_t *)&addr6.s6_addr; 17914235Smarkfen addr_len = sizeof (struct in6_addr); 17924235Smarkfen } 17934235Smarkfen 17944235Smarkfen cp = NULL; 17954235Smarkfen if (!ipsecconf_nflag) { 17964235Smarkfen if (sysinfo(SI_HOSTNAME, domain, MAXHOSTNAMELEN) != -1 && 17975120Smarkfen (cp = strchr(domain, '.')) != NULL) { 17984235Smarkfen (void) strlcpy(domain, cp + 1, sizeof (domain)); 17994235Smarkfen } else { 18004235Smarkfen domain[0] = 0; 18014235Smarkfen } 18027174Spwernau cp = NULL; 18034235Smarkfen hp = getipnodebyaddr(addr_ptr, addr_len, af, &error_num); 18044235Smarkfen if (hp) { 18054235Smarkfen if ((cp = strchr(hp->h_name, '.')) != 0 && 18065120Smarkfen strcasecmp(cp + 1, domain) == 0) 18074235Smarkfen *cp = 0; 18084235Smarkfen cp = hp->h_name; 18094235Smarkfen } 18104235Smarkfen } 18114235Smarkfen 18124235Smarkfen if (cp) { 18134235Smarkfen (void) printf("%s", cp); 18144235Smarkfen } else { 18154235Smarkfen (void) printf("%s", inet_ntop(af, addr_ptr, abuf, 18164235Smarkfen INET6_ADDRSTRLEN)); 18174235Smarkfen } 18184235Smarkfen } 18194235Smarkfen 18204235Smarkfen /* 18214235Smarkfen * Get the next SPD_DUMP message from the PF_POLICY socket. A single 18224235Smarkfen * read may contain multiple messages. This function uses static buffers, 18234235Smarkfen * and is therefore non-reentrant, so if you lift it for an MT application, 18244235Smarkfen * be careful. 18254235Smarkfen * 18264235Smarkfen * Return NULL if there's an error. 18274235Smarkfen */ 18284235Smarkfen static spd_msg_t * 18294235Smarkfen ipsec_read_dump(int pfd) 18304235Smarkfen { 18314235Smarkfen static uint64_t buf[SADB_8TO64(CBUF_LEN)]; 18324235Smarkfen static uint64_t *offset; 18334235Smarkfen static int len; /* In uint64_t units. */ 18344235Smarkfen spd_msg_t *retval; 18354235Smarkfen 18364235Smarkfen /* Assume offset and len are initialized to NULL and 0. */ 18374235Smarkfen 18384235Smarkfen if ((offset - len == buf) || (offset == NULL)) { 18394235Smarkfen /* read a new block from the socket. */ 18404235Smarkfen len = read(pfd, &buf, sizeof (buf)); 18414235Smarkfen if (len == -1) { 18424235Smarkfen warn(gettext("rule dump: bad read")); 18434235Smarkfen return (NULL); 18444235Smarkfen } 18454235Smarkfen offset = buf; 18464235Smarkfen len = SADB_8TO64(len); 18474235Smarkfen } /* Else I still have more messages from a previous read. */ 18484235Smarkfen 18494235Smarkfen retval = (spd_msg_t *)offset; 18504235Smarkfen offset += retval->spd_msg_len; 18514235Smarkfen if (offset > buf + len) { 18524235Smarkfen warnx(gettext("dump read: message corruption," 18534235Smarkfen " %d len exceeds %d boundary."), 18544235Smarkfen SADB_64TO8((uintptr_t)(offset - buf)), 18554235Smarkfen SADB_64TO8((uintptr_t)(buf + len))); 18564235Smarkfen return (NULL); 18574235Smarkfen } 18584235Smarkfen 18594235Smarkfen return (retval); 18604235Smarkfen } 18614235Smarkfen 18624235Smarkfen /* 18634235Smarkfen * returns 0 on success 18644235Smarkfen * -1 on read error 18654235Smarkfen * >0 on invalid returned message 18664235Smarkfen */ 18674235Smarkfen 18684235Smarkfen static int 18694235Smarkfen ipsec_conf_list(void) 18704235Smarkfen { 18714235Smarkfen int ret; 18724235Smarkfen int pfd; 18734235Smarkfen struct spd_msg *msg; 18744235Smarkfen int cnt; 18754235Smarkfen spd_msg_t *rmsg; 18764235Smarkfen spd_ext_t *exts[SPD_EXT_MAX+1]; 18774235Smarkfen /* 18784235Smarkfen * Add an extra 8 bytes of space (+1 uint64_t) to avoid truncation 18794235Smarkfen * issues. 18804235Smarkfen */ 18814235Smarkfen uint64_t buffer[ 18824235Smarkfen SPD_8TO64(sizeof (*msg) + sizeof (spd_if_t) + LIFNAMSIZ) + 1]; 18834235Smarkfen 18844235Smarkfen pfd = get_pf_pol_socket(); 18854235Smarkfen 18864235Smarkfen if (pfd == -1) { 18874235Smarkfen warnx(gettext("Error getting list of policies from kernel")); 18884235Smarkfen return (-1); 18894235Smarkfen } 18904235Smarkfen 18914235Smarkfen (void) memset(buffer, 0, sizeof (buffer)); 18924235Smarkfen msg = (struct spd_msg *)buffer; 18934235Smarkfen msg->spd_msg_version = PF_POLICY_V1; 18944235Smarkfen msg->spd_msg_type = SPD_DUMP; 18954235Smarkfen msg->spd_msg_len = SPD_8TO64(sizeof (*msg)); 18964235Smarkfen 18974235Smarkfen msg->spd_msg_len += attach_tunname((spd_if_t *)(msg + 1)); 18984235Smarkfen 18994235Smarkfen cnt = write(pfd, msg, SPD_64TO8(msg->spd_msg_len)); 19004235Smarkfen 19014235Smarkfen if (cnt < 0) { 19024235Smarkfen warn(gettext("dump: invalid write() return")); 19034235Smarkfen (void) close(pfd); 19044235Smarkfen return (-1); 19054235Smarkfen } 19064235Smarkfen 19074235Smarkfen rmsg = ipsec_read_dump(pfd); 19084235Smarkfen 19094235Smarkfen if (rmsg == NULL || rmsg->spd_msg_errno != 0) { 19104235Smarkfen warnx("%s: %s", gettext("ruleset dump failed"), 19114235Smarkfen (rmsg == NULL ? 19125120Smarkfen gettext("read error") : 19135120Smarkfen sys_error_message(rmsg->spd_msg_errno))); 19144235Smarkfen (void) close(pfd); 19154235Smarkfen return (-1); 19164235Smarkfen } 19174235Smarkfen 19184235Smarkfen 19194235Smarkfen for (;;) { 19204235Smarkfen /* read rule */ 19214235Smarkfen rmsg = ipsec_read_dump(pfd); 19224235Smarkfen 19234235Smarkfen if (rmsg == NULL) { 19244235Smarkfen (void) close(pfd); 19254235Smarkfen return (-1); 19264235Smarkfen } 19274235Smarkfen 19284235Smarkfen if (rmsg->spd_msg_errno != 0) { 19294235Smarkfen warnx("%s: %s", gettext("dump read: bad message"), 19304235Smarkfen sys_error_message(rmsg->spd_msg_errno)); 19314235Smarkfen (void) close(pfd); 19324235Smarkfen return (-1); 19334235Smarkfen } 19344235Smarkfen 19354235Smarkfen ret = spdsock_get_ext(exts, rmsg, rmsg->spd_msg_len, 19364235Smarkfen spdsock_diag_buf, SPDSOCK_DIAG_BUF_LEN); 19374235Smarkfen if (ret != 0) { 19384235Smarkfen if (strlen(spdsock_diag_buf) != 0) 19394235Smarkfen warnx(spdsock_diag_buf); 19404235Smarkfen warnx("%s: %s", gettext("dump read: bad message"), 19414235Smarkfen sys_error_message(rmsg->spd_msg_errno)); 19424235Smarkfen (void) close(pfd); 19434235Smarkfen return (ret); 19444235Smarkfen } 19454235Smarkfen 19464235Smarkfen /* 19474235Smarkfen * End of dump.. 19484235Smarkfen */ 19494235Smarkfen if (exts[SPD_EXT_RULESET] != NULL) 19504235Smarkfen break; /* and return 0. */ 19514235Smarkfen 19524235Smarkfen print_pfpol_msg(rmsg); 19534235Smarkfen } 19544235Smarkfen 19554235Smarkfen (void) close(pfd); 19564235Smarkfen return (0); 19574235Smarkfen } 19584235Smarkfen 19594235Smarkfen static void 19604235Smarkfen print_iap(ips_act_props_t *iap) 19614235Smarkfen { 19624235Smarkfen 19634235Smarkfen /* action */ 19644235Smarkfen switch (iap->iap_action) { 19654235Smarkfen case SPD_ACTTYPE_PASS: 19664235Smarkfen (void) printf("pass "); 19674235Smarkfen break; 19684235Smarkfen case SPD_ACTTYPE_DROP: 19694235Smarkfen (void) printf("drop "); 19704235Smarkfen break; 19714235Smarkfen case SPD_ACTTYPE_IPSEC: 19724235Smarkfen (void) printf("ipsec "); 19734235Smarkfen break; 19744235Smarkfen } 19754235Smarkfen 19764235Smarkfen /* properties */ 19774235Smarkfen (void) printf("%c ", CURL_BEGIN); 19784235Smarkfen if (iap->iap_action == SPD_ACTTYPE_IPSEC) { 19794235Smarkfen if (iap->iap_attr & SPD_APPLY_AH && 19804235Smarkfen iap->iap_aauth.alg_id != 0) 19814235Smarkfen print_alg("auth_algs", &iap->iap_aauth, 19824235Smarkfen IPSEC_PROTO_AH); 19834235Smarkfen 19844235Smarkfen if (iap->iap_attr & SPD_APPLY_ESP) { 19854235Smarkfen print_alg("encr_algs", &iap->iap_eencr, 19864235Smarkfen IPSEC_PROTO_ESP); 19874235Smarkfen if (iap->iap_eauth.alg_id != 0) 19884235Smarkfen print_alg("encr_auth_algs", &iap->iap_eauth, 19894235Smarkfen IPSEC_PROTO_AH); 19904235Smarkfen } 19914235Smarkfen if (iap->iap_attr & SPD_APPLY_UNIQUE) 19924235Smarkfen (void) printf("sa unique "); 19934235Smarkfen else 19944235Smarkfen (void) printf("sa shared "); 19954235Smarkfen } 19964235Smarkfen (void) printf("%c ", CURL_END); 19974235Smarkfen } 19984235Smarkfen 19994235Smarkfen 20004235Smarkfen static void 20014235Smarkfen print_pfpol_msg(spd_msg_t *msg) 20024235Smarkfen { 20034235Smarkfen spd_ext_t *exts[SPD_EXT_MAX+1]; 20044235Smarkfen spd_address_t *spd_address; 20054235Smarkfen struct spd_rule *spd_rule; 20064235Smarkfen struct spd_proto *spd_proto; 20074235Smarkfen struct spd_portrange *spd_portrange; 20084235Smarkfen struct spd_ext_actions *spd_ext_actions; 20094235Smarkfen struct spd_typecode *spd_typecode; 20104235Smarkfen struct spd_attribute *app; 20114235Smarkfen spd_if_t *spd_if; 20124235Smarkfen uint32_t rv; 20134235Smarkfen uint16_t act_count; 20144235Smarkfen 20154235Smarkfen rv = spdsock_get_ext(exts, msg, msg->spd_msg_len, spdsock_diag_buf, 20164235Smarkfen SPDSOCK_DIAG_BUF_LEN); 20174235Smarkfen 20184235Smarkfen if (rv == KGE_OK && exts[SPD_EXT_RULE] != NULL) { 20194235Smarkfen spd_if = (spd_if_t *)exts[SPD_EXT_TUN_NAME]; 20204235Smarkfen spd_rule = (struct spd_rule *)exts[SPD_EXT_RULE]; 20214235Smarkfen if (spd_if == NULL) { 20224235Smarkfen (void) printf("%s %lld\n", INDEX_TAG, 20234235Smarkfen spd_rule->spd_rule_index); 20244235Smarkfen } else { 20254235Smarkfen (void) printf("%s %s,%lld\n", INDEX_TAG, 20264235Smarkfen (char *)spd_if->spd_if_name, 20274235Smarkfen spd_rule->spd_rule_index); 20284235Smarkfen } 20294235Smarkfen } else { 20304235Smarkfen if (strlen(spdsock_diag_buf) != 0) 20314235Smarkfen warnx(spdsock_diag_buf); 20324235Smarkfen warnx(gettext("print_pfpol_msg: malformed PF_POLICY message.")); 20334235Smarkfen return; 20344235Smarkfen } 20354235Smarkfen 20364235Smarkfen (void) printf("%c ", CURL_BEGIN); 20374235Smarkfen 20384235Smarkfen if (spd_if != NULL) { 20394235Smarkfen (void) printf("tunnel %s negotiate %s ", 20404235Smarkfen (char *)spd_if->spd_if_name, 20414235Smarkfen (spd_rule->spd_rule_flags & SPD_RULE_FLAG_TUNNEL) ? 20424235Smarkfen "tunnel" : "transport"); 20434235Smarkfen } 20444235Smarkfen 20454235Smarkfen if (exts[SPD_EXT_PROTO] != NULL) { 20464235Smarkfen spd_proto = (struct spd_proto *)exts[SPD_EXT_PROTO]; 20474235Smarkfen print_ulp(spd_proto->spd_proto_number); 20484235Smarkfen } 20494235Smarkfen 20504235Smarkfen if (exts[SPD_EXT_LCLADDR] != NULL) { 20514235Smarkfen spd_address = (spd_address_t *)exts[SPD_EXT_LCLADDR]; 20524235Smarkfen 20534235Smarkfen (void) printf("laddr "); 20544235Smarkfen print_raw_address((spd_address + 1), 20554235Smarkfen (spd_address->spd_address_len == 2)); 20564235Smarkfen (void) printf("/%d ", spd_address->spd_address_prefixlen); 20574235Smarkfen } 20584235Smarkfen 20594235Smarkfen if (exts[SPD_EXT_LCLPORT] != NULL) { 20604235Smarkfen spd_portrange = (struct spd_portrange *)exts[SPD_EXT_LCLPORT]; 20614235Smarkfen if (spd_portrange->spd_ports_minport != 0) { 20624235Smarkfen print_port(spd_portrange->spd_ports_minport, 20634235Smarkfen TOK_lport); 20644235Smarkfen } 20654235Smarkfen } 20664235Smarkfen 20674235Smarkfen 20684235Smarkfen if (exts[SPD_EXT_REMADDR] != NULL) { 20694235Smarkfen spd_address = (spd_address_t *)exts[SPD_EXT_REMADDR]; 20704235Smarkfen 20714235Smarkfen (void) printf("raddr "); 20724235Smarkfen print_raw_address((spd_address + 1), 20734235Smarkfen (spd_address->spd_address_len == 2)); 20744235Smarkfen (void) printf("/%d ", spd_address->spd_address_prefixlen); 20754235Smarkfen } 20764235Smarkfen 20774235Smarkfen if (exts[SPD_EXT_REMPORT] != NULL) { 20784235Smarkfen spd_portrange = 20795120Smarkfen (struct spd_portrange *)exts[SPD_EXT_REMPORT]; 20804235Smarkfen if (spd_portrange->spd_ports_minport != 0) { 20814235Smarkfen print_port( 20825120Smarkfen spd_portrange->spd_ports_minport, TOK_rport); 20834235Smarkfen } 20844235Smarkfen } 20854235Smarkfen 20864235Smarkfen if (exts[SPD_EXT_ICMP_TYPECODE] != NULL) { 20874235Smarkfen spd_typecode = 20884235Smarkfen (struct spd_typecode *)exts[SPD_EXT_ICMP_TYPECODE]; 20894235Smarkfen print_icmp_typecode(spd_typecode->spd_typecode_type, 20904235Smarkfen spd_typecode->spd_typecode_type_end, 20914235Smarkfen spd_typecode->spd_typecode_code, 20924235Smarkfen spd_typecode->spd_typecode_code_end); 20934235Smarkfen } 20944235Smarkfen 20954235Smarkfen if (exts[SPD_EXT_RULE] != NULL) { 20964235Smarkfen spd_rule = (struct spd_rule *)exts[SPD_EXT_RULE]; 20974235Smarkfen print_spd_flags(spd_rule->spd_rule_flags); 20984235Smarkfen } 20994235Smarkfen 21004235Smarkfen 21014235Smarkfen (void) printf("%c ", CURL_END); 21024235Smarkfen 21034235Smarkfen if (exts[SPD_EXT_ACTION] != NULL) { 21044235Smarkfen ips_act_props_t iap; 21054235Smarkfen int or_needed = 0; 21064235Smarkfen 21074235Smarkfen (void) memset(&iap, 0, sizeof (iap)); 21084235Smarkfen spd_ext_actions = 21094235Smarkfen (struct spd_ext_actions *)exts[SPD_EXT_ACTION]; 21104235Smarkfen app = (struct spd_attribute *)(spd_ext_actions + 1); 21114235Smarkfen 21124235Smarkfen for (act_count = 0; 21134235Smarkfen act_count < spd_ext_actions->spd_actions_len -1; 21145120Smarkfen act_count++) { 21154235Smarkfen 21164235Smarkfen switch (app->spd_attr_tag) { 21174235Smarkfen 21184235Smarkfen case SPD_ATTR_NOP: 21194235Smarkfen break; 21204235Smarkfen 21214235Smarkfen case SPD_ATTR_END: 21224235Smarkfen /* print */ 21234235Smarkfen if (or_needed) { 21244235Smarkfen (void) printf("or "); 21254235Smarkfen } else { 21264235Smarkfen or_needed = 1; 21274235Smarkfen } 21284235Smarkfen print_iap(&iap); 21294235Smarkfen break; 21304235Smarkfen 21314235Smarkfen case SPD_ATTR_EMPTY: 21324235Smarkfen /* clear */ 21334235Smarkfen (void) memset(&iap, 0, sizeof (iap)); 21344235Smarkfen break; 21354235Smarkfen 21364235Smarkfen case SPD_ATTR_NEXT: 21374235Smarkfen /* print */ 21384235Smarkfen if (or_needed) { 21394235Smarkfen (void) printf("or "); 21404235Smarkfen } else { 21414235Smarkfen or_needed = 1; 21424235Smarkfen } 21434235Smarkfen 21444235Smarkfen print_iap(&iap); 21454235Smarkfen break; 21464235Smarkfen 21474235Smarkfen case SPD_ATTR_TYPE: 21484235Smarkfen iap.iap_action = app->spd_attr_value; 21494235Smarkfen break; 21504235Smarkfen 21514235Smarkfen case SPD_ATTR_FLAGS: 21524235Smarkfen iap.iap_attr = app->spd_attr_value; 21534235Smarkfen break; 21544235Smarkfen 21554235Smarkfen case SPD_ATTR_AH_AUTH: 21564235Smarkfen iap.iap_aauth.alg_id = app->spd_attr_value; 21574235Smarkfen break; 21584235Smarkfen 21594235Smarkfen case SPD_ATTR_ESP_ENCR: 21604235Smarkfen iap.iap_eencr.alg_id = app->spd_attr_value; 21614235Smarkfen break; 21624235Smarkfen 21634235Smarkfen case SPD_ATTR_ESP_AUTH: 21644235Smarkfen iap.iap_eauth.alg_id = app->spd_attr_value; 21654235Smarkfen break; 21664235Smarkfen 21674235Smarkfen case SPD_ATTR_ENCR_MINBITS: 21684235Smarkfen iap.iap_eencr.alg_minbits = app->spd_attr_value; 21694235Smarkfen break; 21704235Smarkfen 21714235Smarkfen case SPD_ATTR_ENCR_MAXBITS: 21724235Smarkfen iap.iap_eencr.alg_maxbits = app->spd_attr_value; 21734235Smarkfen break; 21744235Smarkfen 21754235Smarkfen case SPD_ATTR_AH_MINBITS: 21764235Smarkfen iap.iap_aauth.alg_minbits = app->spd_attr_value; 21774235Smarkfen break; 21784235Smarkfen 21794235Smarkfen case SPD_ATTR_AH_MAXBITS: 21804235Smarkfen iap.iap_aauth.alg_maxbits = app->spd_attr_value; 21814235Smarkfen break; 21824235Smarkfen 21834235Smarkfen case SPD_ATTR_ESPA_MINBITS: 21844235Smarkfen iap.iap_eauth.alg_minbits = app->spd_attr_value; 21854235Smarkfen break; 21864235Smarkfen 21874235Smarkfen case SPD_ATTR_ESPA_MAXBITS: 21884235Smarkfen iap.iap_eauth.alg_maxbits = app->spd_attr_value; 21894235Smarkfen break; 21904235Smarkfen 21914235Smarkfen case SPD_ATTR_LIFE_SOFT_TIME: 21924235Smarkfen case SPD_ATTR_LIFE_HARD_TIME: 21934235Smarkfen case SPD_ATTR_LIFE_SOFT_BYTES: 21944235Smarkfen case SPD_ATTR_LIFE_HARD_BYTES: 21954235Smarkfen default: 21964235Smarkfen (void) printf("\tattr %d: %X-%d\n", 21974235Smarkfen act_count, 21984235Smarkfen app->spd_attr_tag, 21994235Smarkfen app->spd_attr_value); 22004235Smarkfen break; 22014235Smarkfen } 22024235Smarkfen app++; 22034235Smarkfen } 22044235Smarkfen } 22054235Smarkfen 22064235Smarkfen (void) printf("\n"); 22074235Smarkfen } 22084235Smarkfen 22094235Smarkfen #ifdef DEBUG_HEAVY 22104235Smarkfen static void 22114235Smarkfen pfpol_msg_dump(spd_msg_t *msg, char *tag) 22124235Smarkfen { 22134235Smarkfen spd_ext_t *exts[SPD_EXT_MAX+1]; 22144235Smarkfen uint32_t i; 22154235Smarkfen spd_address_t *spd_address; 22164235Smarkfen struct spd_rule *spd_rule; 22174235Smarkfen struct spd_proto *spd_proto; 22184235Smarkfen struct spd_portrange *spd_portrange; 22194235Smarkfen struct spd_typecode *spd_typecode; 22204235Smarkfen struct spd_ext_actions *spd_ext_actions; 22214235Smarkfen struct spd_attribute *app; 22224235Smarkfen spd_if_t *spd_if; 22234235Smarkfen char abuf[INET6_ADDRSTRLEN]; 22244235Smarkfen uint32_t rv; 22254235Smarkfen uint16_t act_count; 22264235Smarkfen 22274235Smarkfen rv = spdsock_get_ext(exts, msg, msg->spd_msg_len, NULL, 0); 22284235Smarkfen if (rv != KGE_OK) 22294235Smarkfen return; 22304235Smarkfen 22314235Smarkfen (void) printf("===========%s==============\n", tag); 22324235Smarkfen (void) printf("pfpol_msg_dump %d\n-------------------\n", rv); 22334235Smarkfen 22344235Smarkfen (void) printf("spd_msg_version:%d\n", msg->spd_msg_version); 22354235Smarkfen (void) printf("spd_msg_type:%d\n", msg->spd_msg_type); 22364235Smarkfen (void) printf("spd_msg_errno:%d\n", msg->spd_msg_errno); 22374235Smarkfen (void) printf("spd_msg_spdid:%d\n", msg->spd_msg_spdid); 22384235Smarkfen (void) printf("spd_msg_len:%d\n", msg->spd_msg_len); 22394235Smarkfen (void) printf("spd_msg_diagnostic:%d\n", msg->spd_msg_diagnostic); 22404235Smarkfen (void) printf("spd_msg_seq:%d\n", msg->spd_msg_seq); 22414235Smarkfen (void) printf("spd_msg_pid:%d\n", msg->spd_msg_pid); 22424235Smarkfen 22434235Smarkfen for (i = 1; i <= SPD_EXT_MAX; i++) { 22444235Smarkfen if (exts[i] == NULL) { 22454235Smarkfen printf("skipped %d\n", i); 22464235Smarkfen continue; 22474235Smarkfen } 22484235Smarkfen 22494235Smarkfen switch (i) { 22504235Smarkfen case SPD_EXT_TUN_NAME: 22514235Smarkfen spd_if = (spd_if_t *)exts[i]; 22524235Smarkfen (void) printf("spd_if = %s\n", spd_if->spd_if_name); 22534235Smarkfen break; 22544235Smarkfen 22554235Smarkfen case SPD_EXT_ICMP_TYPECODE: 22564235Smarkfen spd_typecode = (struct spd_typecode *)exts[i]; 22574235Smarkfen (void) printf("icmp type %d-%d code %d-%d\n", 22584235Smarkfen spd_typecode->spd_typecode_type, 22594235Smarkfen spd_typecode->spd_typecode_type_end, 22604235Smarkfen spd_typecode->spd_typecode_code, 22614235Smarkfen spd_typecode->spd_typecode_code_end); 22624235Smarkfen break; 22634235Smarkfen 22644235Smarkfen case SPD_EXT_LCLPORT: 22654235Smarkfen spd_portrange = (struct spd_portrange *)exts[i]; 22664235Smarkfen (void) printf("local ports %d-%d\n", 22674235Smarkfen spd_portrange->spd_ports_minport, 22684235Smarkfen spd_portrange->spd_ports_maxport); 22694235Smarkfen 22704235Smarkfen break; 22714235Smarkfen 22724235Smarkfen case SPD_EXT_REMPORT: 22734235Smarkfen spd_portrange = (struct spd_portrange *)exts[i]; 22744235Smarkfen (void) printf("remote ports %d-%d\n", 22754235Smarkfen spd_portrange->spd_ports_minport, 22764235Smarkfen spd_portrange->spd_ports_maxport); 22774235Smarkfen 22784235Smarkfen break; 22794235Smarkfen 22804235Smarkfen case SPD_EXT_PROTO: 22814235Smarkfen spd_proto = (struct spd_proto *)exts[i]; 22824235Smarkfen (void) printf("proto:spd_proto_exttype %d\n", 22834235Smarkfen spd_proto->spd_proto_exttype); 22844235Smarkfen (void) printf("proto:spd_proto_number %d\n", 22854235Smarkfen spd_proto->spd_proto_number); 22864235Smarkfen break; 22874235Smarkfen 22884235Smarkfen case SPD_EXT_LCLADDR: 22894235Smarkfen case SPD_EXT_REMADDR: 22904235Smarkfen spd_address = (spd_address_t *)exts[i]; 22914235Smarkfen if (i == SPD_EXT_LCLADDR) 22924235Smarkfen (void) printf("local addr "); 22934235Smarkfen else 22944235Smarkfen (void) printf("remote addr "); 22954235Smarkfen 22964235Smarkfen 22974235Smarkfen (void) printf("%s\n", 22984235Smarkfen inet_ntop(spd_address->spd_address_af, 22995120Smarkfen (void *) (spd_address +1), abuf, 23005120Smarkfen INET6_ADDRSTRLEN)); 23014235Smarkfen 23024235Smarkfen (void) printf("prefixlen: %d\n", 23034235Smarkfen spd_address->spd_address_prefixlen); 23044235Smarkfen break; 23054235Smarkfen 23064235Smarkfen case SPD_EXT_ACTION: 23074235Smarkfen spd_ext_actions = (struct spd_ext_actions *)exts[i]; 23084235Smarkfen (void) printf("spd_ext_action\n"); 23094235Smarkfen (void) printf("spd_actions_count %d\n", 23104235Smarkfen spd_ext_actions->spd_actions_count); 23114235Smarkfen app = (struct spd_attribute *)(spd_ext_actions + 1); 23124235Smarkfen 23134235Smarkfen for (act_count = 0; 23144235Smarkfen act_count < spd_ext_actions->spd_actions_len -1; 23154235Smarkfen act_count++) { 23164235Smarkfen (void) printf("\tattr %d: %X-%d\n", act_count, 23174235Smarkfen app->spd_attr_tag, app->spd_attr_value); 23184235Smarkfen app++; 23194235Smarkfen } 23204235Smarkfen 23214235Smarkfen break; 23224235Smarkfen 23234235Smarkfen case SPD_EXT_RULE: 23244235Smarkfen spd_rule = (struct spd_rule *)exts[i]; 23254235Smarkfen (void) printf("spd_rule_priority: 0x%x\n", 23264235Smarkfen spd_rule->spd_rule_priority); 23274235Smarkfen (void) printf("spd_rule_flags: %d\n", 23284235Smarkfen spd_rule->spd_rule_flags); 23294235Smarkfen break; 23304235Smarkfen 23314235Smarkfen case SPD_EXT_RULESET: 23324235Smarkfen (void) printf("spd_ext_ruleset\n"); 23334235Smarkfen break; 23344235Smarkfen default: 23354235Smarkfen (void) printf("default\n"); 23364235Smarkfen break; 23374235Smarkfen } 23384235Smarkfen } 23394235Smarkfen 23404235Smarkfen (void) printf("-------------------\n"); 23414235Smarkfen (void) printf("=========================\n"); 23424235Smarkfen } 23434235Smarkfen #endif /* DEBUG_HEAVY */ 23444235Smarkfen 23454235Smarkfen static int 23464235Smarkfen ipsec_conf_view() 23474235Smarkfen { 23484235Smarkfen char buf[MAXLEN]; 23494235Smarkfen FILE *fp; 23504235Smarkfen 23514235Smarkfen fp = fopen(POLICY_CONF_FILE, "r"); 23524235Smarkfen if (fp == NULL) { 23534235Smarkfen if (errno == ENOENT) { 23544235Smarkfen /* 23554235Smarkfen * The absence of POLICY_CONF_FILE should 23564235Smarkfen * not cause the command to exit with a 23574235Smarkfen * non-zero status, since this condition 23584235Smarkfen * is valid when no policies were previously 23594235Smarkfen * defined. 23604235Smarkfen */ 23614235Smarkfen return (0); 23624235Smarkfen } 23634235Smarkfen warn(gettext("%s cannot be opened"), POLICY_CONF_FILE); 23644235Smarkfen return (-1); 23654235Smarkfen } 23664235Smarkfen while (fgets(buf, MAXLEN, fp) != NULL) { 23674235Smarkfen /* Don't print removed entries */ 23684235Smarkfen if (*buf == ';') 23694235Smarkfen continue; 23704235Smarkfen if (strlen(buf) != 0) 23714235Smarkfen buf[strlen(buf) - 1] = '\0'; 23724235Smarkfen (void) puts(buf); 23734235Smarkfen } 23744235Smarkfen return (0); 23754235Smarkfen } 23764235Smarkfen 23774235Smarkfen /* 23784235Smarkfen * Delete nlines from start in the POLICY_CONF_FILE. 23794235Smarkfen */ 23804235Smarkfen static int 23814235Smarkfen delete_from_file(int start, int nlines) 23824235Smarkfen { 23834235Smarkfen FILE *fp; 23844235Smarkfen char ibuf[MAXLEN]; 23854235Smarkfen int len; 23864235Smarkfen 23874235Smarkfen if ((fp = fopen(POLICY_CONF_FILE, "r+b")) == NULL) { 23884235Smarkfen warn(gettext("%s cannot be opened"), POLICY_CONF_FILE); 23894235Smarkfen return (-1); 23904235Smarkfen } 23914235Smarkfen 23924235Smarkfen /* 23934235Smarkfen * Insert a ";", read the line and discard it. Repeat 23944235Smarkfen * this logic nlines - 1 times. For the last line there 23954235Smarkfen * is just a newline character. We can't just insert a 23964235Smarkfen * single ";" character instead of the newline character 23974235Smarkfen * as it would affect the next line. Thus when we comment 23984235Smarkfen * the last line we seek one less and insert a ";" 23994235Smarkfen * character, which will replace the newline of the 24004235Smarkfen * penultimate line with ; and newline of the last line 24014235Smarkfen * will become part of the previous line. 24024235Smarkfen */ 24034235Smarkfen do { 24044235Smarkfen /* 24054235Smarkfen * It is not enough to seek just once and expect the 24064235Smarkfen * subsequent fgets below to take you to the right 24074235Smarkfen * offset of the next line. fgets below seems to affect 24084235Smarkfen * the offset. Thus we need to seek, replace with ";", 24094235Smarkfen * and discard a line using fgets for every line. 24104235Smarkfen */ 24114235Smarkfen if (fseek(fp, start, SEEK_SET) == -1) { 24124235Smarkfen warn("fseek"); 24134235Smarkfen return (-1); 24144235Smarkfen } 24154235Smarkfen if (fputc(';', fp) < 0) { 24164235Smarkfen warn("fputc"); 24174235Smarkfen return (-1); 24184235Smarkfen } 24194235Smarkfen /* 24204235Smarkfen * Flush the above ";" character before we do the fgets(). 24214235Smarkfen * Without this, fgets() gets confused with offsets. 24224235Smarkfen */ 24234235Smarkfen (void) fflush(fp); 24244235Smarkfen len = 0; 24254235Smarkfen while (fgets(ibuf, MAXLEN, fp) != NULL) { 24264235Smarkfen len += strlen(ibuf); 24274235Smarkfen if (ibuf[len - 1] == '\n') { 24284235Smarkfen /* 24294235Smarkfen * We have read a complete line. 24304235Smarkfen */ 24314235Smarkfen break; 24324235Smarkfen } 24334235Smarkfen } 24344235Smarkfen /* 24354235Smarkfen * We read the line after ";" character has been inserted. 24364235Smarkfen * Thus len does not count ";". To advance to the next line 24374235Smarkfen * increment by 1. 24384235Smarkfen */ 24394235Smarkfen start += (len + 1); 24404235Smarkfen /* 24414235Smarkfen * If nlines == 2, we will be commenting out the last 24424235Smarkfen * line next, which has only one newline character. 24434235Smarkfen * If we blindly replace it with ";", it will be 24444235Smarkfen * read as part of the next line which could have 24454235Smarkfen * a INDEX string and thus confusing ipsec_conf_view. 24464235Smarkfen * Thus, we seek one less and replace the previous 24474235Smarkfen * line's newline character with ";", and the 24484235Smarkfen * last line's newline character will become part of 24494235Smarkfen * the previous line. 24504235Smarkfen */ 24514235Smarkfen if (nlines == 2) 24524235Smarkfen start--; 24534235Smarkfen } while (--nlines != 0); 24544235Smarkfen (void) fclose(fp); 24554235Smarkfen if (nlines != 0) 24564235Smarkfen return (-1); 24574235Smarkfen else 24584235Smarkfen return (0); 24594235Smarkfen } 24604235Smarkfen 24614235Smarkfen /* 24624235Smarkfen * Delete an entry from the file by inserting a ";" at the 24634235Smarkfen * beginning of the lines to be removed. 24644235Smarkfen */ 24654235Smarkfen static int 24664235Smarkfen ipsec_conf_del(int policy_index, boolean_t ignore_spd) 24674235Smarkfen { 24684235Smarkfen act_prop_t *act_props = malloc(sizeof (act_prop_t)); 24694235Smarkfen char *buf; 24704235Smarkfen FILE *fp; 24714235Smarkfen char ibuf[MAXLEN]; 24724235Smarkfen int ibuf_len, index_len, index; 24734235Smarkfen int ret = 0; 24744235Smarkfen int offset, prev_offset; 24754235Smarkfen int nlines; 24764235Smarkfen char lifname[LIFNAMSIZ]; 24774235Smarkfen 24784235Smarkfen if (act_props == NULL) { 24794235Smarkfen warn(gettext("memory")); 24804235Smarkfen return (-1); 24814235Smarkfen } 24824235Smarkfen 24834235Smarkfen fp = fopen(POLICY_CONF_FILE, "r"); 24844235Smarkfen if (fp == NULL) { 24854235Smarkfen warn(gettext("%s cannot be opened"), POLICY_CONF_FILE); 24864235Smarkfen free(act_props); 24874235Smarkfen return (-1); 24884235Smarkfen } 24894235Smarkfen 24904235Smarkfen index_len = strlen(INDEX_TAG); 24914235Smarkfen index = 0; 24924235Smarkfen for (offset = prev_offset = 0; fgets(ibuf, MAXLEN, fp) != NULL; 24934235Smarkfen offset += ibuf_len) { 24944235Smarkfen prev_offset = offset; 24954235Smarkfen ibuf_len = strlen(ibuf); 24964235Smarkfen 24974235Smarkfen if (strncmp(ibuf, INDEX_TAG, index_len) != 0) { 24984235Smarkfen continue; 24994235Smarkfen } 25004235Smarkfen 25014235Smarkfen /* 25024235Smarkfen * This line contains INDEX_TAG 25034235Smarkfen */ 25044235Smarkfen buf = ibuf + index_len; 25054235Smarkfen buf++; /* Skip the space */ 25064235Smarkfen index = parse_index(buf, lifname); 25074235Smarkfen if (index == -1) { 25084235Smarkfen warnx(gettext("Invalid index in the file")); 25094235Smarkfen free(act_props); 25104235Smarkfen return (-1); 25114235Smarkfen } 25124235Smarkfen if (index == policy_index && 25134235Smarkfen (interface_name == NULL || 25145120Smarkfen strncmp(interface_name, lifname, LIFNAMSIZ) == 0)) { 25154235Smarkfen if (!ignore_spd) { 25164235Smarkfen ret = parse_one(fp, act_props); 25174235Smarkfen if (ret == -1) { 25184235Smarkfen warnx(gettext("Invalid policy entry " 25194235Smarkfen "in the file")); 25204235Smarkfen free(act_props); 25214235Smarkfen return (-1); 25224235Smarkfen } 25234235Smarkfen } 25244235Smarkfen /* 25254235Smarkfen * nlines is the number of lines we should comment 25264235Smarkfen * out. linecount tells us how many lines this command 25274235Smarkfen * spans. And we need to remove the line with INDEX 25284235Smarkfen * and an extra line we added during ipsec_conf_add. 25294235Smarkfen * 25304235Smarkfen * NOTE : If somebody added a policy entry which does 25314235Smarkfen * not have a newline, ipsec_conf_add() fills in the 25324235Smarkfen * newline. Hence, there is always 2 extra lines 25334235Smarkfen * to delete. 25344235Smarkfen */ 25354235Smarkfen nlines = linecount + 2; 25364235Smarkfen goto delete; 25374235Smarkfen } 25384235Smarkfen } 25394235Smarkfen 25404235Smarkfen if (!ignore_spd) 25414235Smarkfen ret = pfp_delete_rule(policy_index); 25424235Smarkfen 25434235Smarkfen if (ret != 0) { 25444235Smarkfen warnx(gettext("Deletion incomplete. Please " 25454235Smarkfen "flush all the entries and re-configure :")); 25464235Smarkfen reconfigure(); 25474235Smarkfen free(act_props); 25484235Smarkfen return (ret); 25494235Smarkfen } 25504235Smarkfen free(act_props); 25514235Smarkfen return (ret); 25524235Smarkfen 25534235Smarkfen delete: 25544235Smarkfen /* Delete nlines from prev_offset */ 25554235Smarkfen (void) fclose(fp); 25564235Smarkfen ret = delete_from_file(prev_offset, nlines); 25574235Smarkfen 25584235Smarkfen if (ret != 0) { 25594235Smarkfen warnx(gettext("Deletion incomplete. Please " 25604235Smarkfen "flush all the entries and re-configure :")); 25614235Smarkfen reconfigure(); 25624235Smarkfen free(act_props); 25634235Smarkfen return (ret); 25644235Smarkfen } 25654235Smarkfen 25664235Smarkfen if (!ignore_spd) 25674235Smarkfen ret = pfp_delete_rule(policy_index); 25684235Smarkfen 25694235Smarkfen if (ret != 0) { 25704235Smarkfen warnx(gettext("Deletion incomplete. Please " 25714235Smarkfen "flush all the entries and re-configure :")); 25724235Smarkfen reconfigure(); 25734235Smarkfen free(act_props); 25744235Smarkfen return (ret); 25754235Smarkfen } 25764235Smarkfen free(act_props); 25774235Smarkfen return (0); 25784235Smarkfen } 25794235Smarkfen 25804235Smarkfen static int 25814235Smarkfen pfp_delete_rule(uint64_t index) 25824235Smarkfen { 25834235Smarkfen struct spd_msg *msg; 25844235Smarkfen struct spd_rule *rule; 25854235Smarkfen int sfd; 25864235Smarkfen int cnt, len, alloclen; 25874235Smarkfen 25884235Smarkfen sfd = get_pf_pol_socket(); 25894235Smarkfen if (sfd < 0) { 25904235Smarkfen warn(gettext("unable to open policy socket")); 25914235Smarkfen return (-1); 25924235Smarkfen } 25934235Smarkfen 25944235Smarkfen /* 25954235Smarkfen * Add an extra 8 bytes of space (+1 uint64_t) to avoid truncation 25964235Smarkfen * issues. 25974235Smarkfen */ 25984235Smarkfen alloclen = sizeof (spd_msg_t) + sizeof (struct spd_rule) + 25994235Smarkfen sizeof (spd_if_t) + LIFNAMSIZ + 8; 26004235Smarkfen msg = (spd_msg_t *)malloc(alloclen); 26014235Smarkfen 26024235Smarkfen if (msg == NULL) { 26034235Smarkfen warn("malloc"); 26044235Smarkfen return (-1); 26054235Smarkfen } 26064235Smarkfen 26074235Smarkfen rule = (struct spd_rule *)(msg + 1); 26084235Smarkfen 26094235Smarkfen (void) memset(msg, 0, alloclen); 26104235Smarkfen msg->spd_msg_version = PF_POLICY_V1; 26114235Smarkfen msg->spd_msg_type = SPD_DELETERULE; 26124235Smarkfen msg->spd_msg_len = SPD_8TO64(sizeof (spd_msg_t) 26134235Smarkfen + sizeof (struct spd_rule)); 26144235Smarkfen 26154235Smarkfen rule->spd_rule_type = SPD_EXT_RULE; 26164235Smarkfen rule->spd_rule_len = SPD_8TO64(sizeof (struct spd_rule)); 26174235Smarkfen rule->spd_rule_index = index; 26184235Smarkfen 26194235Smarkfen msg->spd_msg_len += attach_tunname((spd_if_t *)(rule + 1)); 26204235Smarkfen 26214235Smarkfen len = SPD_64TO8(msg->spd_msg_len); 26224235Smarkfen cnt = write(sfd, msg, len); 26234235Smarkfen 26244235Smarkfen if (cnt != len) { 26254235Smarkfen if (cnt < 0) { 26264235Smarkfen (void) close(sfd); 26274235Smarkfen free(msg); 26284235Smarkfen warn(gettext("Delete failed: write")); 26294235Smarkfen return (-1); 26304235Smarkfen } else { 26314235Smarkfen (void) close(sfd); 26324235Smarkfen free(msg); 26334235Smarkfen warnx(gettext("Delete failed: short write")); 26344235Smarkfen return (-1); 26354235Smarkfen } 26364235Smarkfen } 26374235Smarkfen 26384235Smarkfen cnt = read(sfd, msg, len); 26394235Smarkfen if (cnt != len) { 26404235Smarkfen if (cnt < 0) { 26414235Smarkfen (void) close(sfd); 26424235Smarkfen free(msg); 26434235Smarkfen warn(gettext("Delete failed: read")); 26444235Smarkfen return (-1); 26454235Smarkfen } else { 26464235Smarkfen (void) close(sfd); 26474235Smarkfen free(msg); 26484235Smarkfen warnx(gettext("Delete failed while reading reply")); 26494235Smarkfen return (-1); 26504235Smarkfen } 26514235Smarkfen } 26524235Smarkfen (void) close(sfd); 26534235Smarkfen if (msg->spd_msg_errno != 0) { 26544235Smarkfen free(msg); 26554235Smarkfen errno = msg->spd_msg_errno; 26564235Smarkfen warn(gettext("Delete failed: SPD_FLUSH")); 26574235Smarkfen return (-1); 26584235Smarkfen } 26594235Smarkfen 26604235Smarkfen free(msg); 26614235Smarkfen return (0); 26624235Smarkfen } 26634235Smarkfen 26644235Smarkfen static int 26654235Smarkfen ipsec_conf_flush(int db) 26664235Smarkfen { 26674235Smarkfen int pfd, cnt, len; 26684235Smarkfen int sfd; 26694235Smarkfen struct spd_msg *msg; 26704235Smarkfen /* 26714235Smarkfen * Add an extra 8 bytes of space (+1 uint64_t) to avoid truncation 26724235Smarkfen * issues. 26734235Smarkfen */ 26744235Smarkfen uint64_t buffer[ 26754235Smarkfen SPD_8TO64(sizeof (*msg) + sizeof (spd_if_t) + LIFNAMSIZ) + 1]; 26764235Smarkfen 26774235Smarkfen sfd = get_pf_pol_socket(); 26784235Smarkfen if (sfd < 0) { 26794235Smarkfen warn(gettext("unable to open policy socket")); 26804235Smarkfen return (-1); 26814235Smarkfen } 26824235Smarkfen 26834235Smarkfen (void) memset(buffer, 0, sizeof (buffer)); 26844235Smarkfen msg = (struct spd_msg *)buffer; 26854235Smarkfen msg->spd_msg_version = PF_POLICY_V1; 26864235Smarkfen msg->spd_msg_type = SPD_FLUSH; 26874235Smarkfen msg->spd_msg_len = SPD_8TO64(sizeof (*msg)); 26884235Smarkfen msg->spd_msg_spdid = db; 26894235Smarkfen 26904235Smarkfen msg->spd_msg_len += attach_tunname((spd_if_t *)(msg + 1)); 26914235Smarkfen 26924235Smarkfen len = SPD_64TO8(msg->spd_msg_len); 26934235Smarkfen cnt = write(sfd, msg, len); 26944235Smarkfen if (cnt != len) { 26954235Smarkfen if (cnt < 0) { 26964235Smarkfen warn(gettext("Flush failed: write")); 26974235Smarkfen return (-1); 26984235Smarkfen } else { 26994235Smarkfen warnx(gettext("Flush failed: short write")); 27004235Smarkfen return (-1); 27014235Smarkfen } 27024235Smarkfen } 27034235Smarkfen 27044235Smarkfen cnt = read(sfd, msg, len); 27054235Smarkfen if (cnt != len) { 27064235Smarkfen if (cnt < 0) { 27074235Smarkfen warn(gettext("Flush failed: read")); 27084235Smarkfen return (-1); 27094235Smarkfen } else { 27104235Smarkfen warnx(gettext("Flush failed while reading reply")); 27114235Smarkfen return (-1); 27124235Smarkfen } 27134235Smarkfen } 27144235Smarkfen (void) close(sfd); 27154235Smarkfen if (msg->spd_msg_errno != 0) { 27164235Smarkfen warnx("%s: %s", gettext("Flush failed: SPD_FLUSH"), 27174235Smarkfen sys_error_message(msg->spd_msg_errno)); 27184235Smarkfen return (-1); 27194235Smarkfen } 27204235Smarkfen 27214235Smarkfen /* Truncate the file */ 27224235Smarkfen if (db == SPD_ACTIVE) { 27234235Smarkfen if ((pfd = open(POLICY_CONF_FILE, O_TRUNC|O_RDWR)) == -1) { 27244235Smarkfen if (errno == ENOENT) { 27254235Smarkfen /* 27264235Smarkfen * The absence of POLICY_CONF_FILE should 27274235Smarkfen * not cause the command to exit with a 27284235Smarkfen * non-zero status, since this condition 27294235Smarkfen * is valid when no policies were previously 27304235Smarkfen * defined. 27314235Smarkfen */ 27324235Smarkfen return (0); 27334235Smarkfen } 27344235Smarkfen warn(gettext("%s cannot be truncated"), 27354235Smarkfen POLICY_CONF_FILE); 27364235Smarkfen return (-1); 27374235Smarkfen } 27384235Smarkfen (void) close(pfd); 27394235Smarkfen } 27404235Smarkfen return (0); 27414235Smarkfen } 27424235Smarkfen 27434235Smarkfen /* 27444235Smarkfen * function to send SPD_FLIP and SPD_CLONE messages 27454235Smarkfen * Do it for ALL polheads for simplicity's sake. 27464235Smarkfen */ 27474235Smarkfen static void 27484235Smarkfen ipsec_conf_admin(uint8_t type) 27494235Smarkfen { 27504235Smarkfen int cnt; 27514235Smarkfen int sfd; 27524235Smarkfen struct spd_msg *msg; 27534235Smarkfen uint64_t buffer[ 27544235Smarkfen SPD_8TO64(sizeof (struct spd_msg) + sizeof (spd_if_t))]; 27554235Smarkfen char *save_ifname; 27564235Smarkfen 27574235Smarkfen sfd = get_pf_pol_socket(); 27584235Smarkfen if (sfd < 0) { 27594235Smarkfen err(-1, gettext("unable to open policy socket")); 27604235Smarkfen } 27614235Smarkfen 27624235Smarkfen (void) memset(buffer, 0, sizeof (buffer)); 27634235Smarkfen msg = (struct spd_msg *)buffer; 27644235Smarkfen msg->spd_msg_version = PF_POLICY_V1; 27654235Smarkfen msg->spd_msg_type = type; 27664235Smarkfen msg->spd_msg_len = SPD_8TO64(sizeof (buffer)); 27674235Smarkfen 27684235Smarkfen save_ifname = interface_name; 27694235Smarkfen /* Apply to all policy heads - global and tunnels. */ 27704235Smarkfen interface_name = &all_polheads; 27714235Smarkfen (void) attach_tunname((spd_if_t *)(msg + 1)); 27724235Smarkfen interface_name = save_ifname; 27734235Smarkfen 27744235Smarkfen cnt = write(sfd, msg, sizeof (buffer)); 27754235Smarkfen if (cnt != sizeof (buffer)) { 27764235Smarkfen if (cnt < 0) { 27774235Smarkfen err(-1, gettext("admin failed: write")); 27784235Smarkfen } else { 27794235Smarkfen errx(-1, gettext("admin failed: short write")); 27804235Smarkfen } 27814235Smarkfen } 27824235Smarkfen 27834235Smarkfen cnt = read(sfd, msg, sizeof (buffer)); 27844235Smarkfen if (cnt != sizeof (buffer)) { 27854235Smarkfen if (cnt < 0) { 27864235Smarkfen err(-1, gettext("admin failed: read")); 27874235Smarkfen } else { 27884235Smarkfen errx(-1, gettext("admin failed while reading reply")); 27894235Smarkfen } 27904235Smarkfen } 27914235Smarkfen (void) close(sfd); 27924235Smarkfen if (msg->spd_msg_errno != 0) { 27934235Smarkfen errno = msg->spd_msg_errno; 27944235Smarkfen err(-1, gettext("admin failed")); 27954235Smarkfen } 27964235Smarkfen } 27974235Smarkfen 27984235Smarkfen static void 27994235Smarkfen reconfigure() 28004235Smarkfen { 28014235Smarkfen (void) fprintf(stderr, gettext( 28025120Smarkfen "\tipsecconf -f \n " 28035120Smarkfen "\tipsecconf -a policy_file\n")); 28044235Smarkfen } 28054235Smarkfen 28064235Smarkfen static void 28074235Smarkfen usage(void) 28084235Smarkfen { 28094235Smarkfen (void) fprintf(stderr, gettext( 28104235Smarkfen "Usage: ipsecconf\n" 28114235Smarkfen "\tipsecconf -a ([-]|<filename>) [-q]\n" 28124235Smarkfen "\tipsecconf -c <filename>\n" 28134235Smarkfen "\tipsecconf -r ([-]|<filename>) [-q]\n" 28144235Smarkfen "\tipsecconf -d [-i tunnel-interface] <index>\n" 28154235Smarkfen "\tipsecconf -d <tunnel-interface,index>\n" 28164235Smarkfen "\tipsecconf -l [-n] [-i tunnel-interface]\n" 28174235Smarkfen "\tipsecconf -f [-i tunnel-interface]\n" 28184235Smarkfen "\tipsecconf -L [-n]\n" 28194235Smarkfen "\tipsecconf -F\n")); 28204235Smarkfen } 28214235Smarkfen 28224235Smarkfen /* 28234235Smarkfen * a type consists of 28244235Smarkfen * "type" <int>{ "-" <int>} 28254235Smarkfen * or 28264235Smarkfen * "type" keyword 28274235Smarkfen * 28284235Smarkfen * a code consists of 28294235Smarkfen * "code" <int>{ "-" <int>} 28304235Smarkfen * or 28314235Smarkfen * "code" keyword 28324235Smarkfen */ 28334235Smarkfen 28344235Smarkfen 28354235Smarkfen static int 28364235Smarkfen parse_type_code(const char *str, const str_val_t *table) 28374235Smarkfen { 28384235Smarkfen char *end1, *end2; 28394235Smarkfen int res1 = 0, res2 = 0; 28404235Smarkfen int i; 28414235Smarkfen 28424235Smarkfen if (isdigit(str[0])) { 28434235Smarkfen res1 = strtol(str, &end1, 0); 28444235Smarkfen 28454235Smarkfen if (end1 == str) { 28464235Smarkfen return (-1); 28474235Smarkfen } 28484235Smarkfen 28494235Smarkfen if (res1 > 255 || res1 < 0) { 28504235Smarkfen return (-1); 28514235Smarkfen } 28524235Smarkfen 28534235Smarkfen if (*end1 == '-') { 28544235Smarkfen end1++; 28554235Smarkfen res2 = strtol(end1, &end2, 0); 28564235Smarkfen if (res2 > 255 || res2 < 0) { 28574235Smarkfen return (-1); 28584235Smarkfen } 28594235Smarkfen } else { 28604235Smarkfen end2 = end1; 28614235Smarkfen } 28624235Smarkfen 28634235Smarkfen while (isspace(*end2)) 28644235Smarkfen end2++; 28654235Smarkfen 28664235Smarkfen if (*end2 != '\0') { 28674235Smarkfen return (-1); 28684235Smarkfen } 28694235Smarkfen 28704235Smarkfen return (res1 + (res2 << 8)); 28714235Smarkfen } 28724235Smarkfen 28734235Smarkfen for (i = 0; table[i].string; i++) { 28744235Smarkfen if (strcmp(str, table[i].string) == 0) { 28754235Smarkfen return (table[i].value); 28764235Smarkfen } 28774235Smarkfen } 28784235Smarkfen 28794235Smarkfen return (-1); 28804235Smarkfen } 28814235Smarkfen 28824235Smarkfen static int 28834235Smarkfen parse_int(const char *str) 28844235Smarkfen { 28854235Smarkfen char *end; 28864235Smarkfen int res; 28874235Smarkfen 28884235Smarkfen res = strtol(str, &end, 0); 28894235Smarkfen if (end == str) 28904235Smarkfen return (-1); 28914235Smarkfen while (isspace(*end)) 28924235Smarkfen end++; 28934235Smarkfen if (*end != '\0') 28944235Smarkfen return (-1); 28954235Smarkfen return (res); 28964235Smarkfen } 28974235Smarkfen 28984235Smarkfen /* 28994235Smarkfen * Parses <interface>,<index>. Sets iname or the global interface_name (if 29004235Smarkfen * iname == NULL) to <interface> and returns <index>. Calls exit() if we have 29014235Smarkfen * an interface_name already set. 29024235Smarkfen */ 29034235Smarkfen static int 29044235Smarkfen parse_index(const char *str, char *iname) 29054235Smarkfen { 29064235Smarkfen char *intf, *num, *copy; 29074235Smarkfen int rc; 29084235Smarkfen 29094235Smarkfen copy = strdup(str); 29104235Smarkfen if (copy == NULL) { 29114235Smarkfen EXIT_FATAL("Out of memory."); 29124235Smarkfen } 29134235Smarkfen 29144235Smarkfen intf = strtok(copy, ","); 29154235Smarkfen /* Just want the rest of the string unmolested, so use "" for arg2. */ 29164235Smarkfen num = strtok(NULL, ""); 29174235Smarkfen if (num == NULL) { 29184235Smarkfen /* No comma found, just parse it like an int. */ 29194235Smarkfen free(copy); 29204235Smarkfen return (parse_int(str)); 29214235Smarkfen } 29224235Smarkfen 29234235Smarkfen if (iname != NULL) { 29244235Smarkfen (void) strlcpy(iname, intf, LIFNAMSIZ); 29254235Smarkfen } else { 29264235Smarkfen if (interface_name != NULL) { 29274235Smarkfen EXIT_FATAL("Interface name already selected"); 29284235Smarkfen } 29294235Smarkfen 29304235Smarkfen interface_name = strdup(intf); 29314235Smarkfen if (interface_name == NULL) { 29324235Smarkfen EXIT_FATAL("Out of memory."); 29334235Smarkfen } 29344235Smarkfen } 29354235Smarkfen 29364235Smarkfen rc = parse_int(num); 29374235Smarkfen free(copy); 29384235Smarkfen return (rc); 29394235Smarkfen } 29404235Smarkfen 29414235Smarkfen /* 29424235Smarkfen * Convert a mask to a prefix length. 29434235Smarkfen * Returns prefix length on success, -1 otherwise. 29444235Smarkfen */ 29454235Smarkfen static int 29464235Smarkfen in_getprefixlen(char *mask) 29474235Smarkfen { 29484235Smarkfen int prefixlen; 29494235Smarkfen char *end; 29504235Smarkfen 29514235Smarkfen prefixlen = (int)strtol(mask, &end, 10); 29524235Smarkfen if (prefixlen < 0) { 29534235Smarkfen return (-1); 29544235Smarkfen } 29554235Smarkfen if (mask == end) { 29564235Smarkfen return (-1); 29574235Smarkfen } 29584235Smarkfen if (*end != '\0') { 29594235Smarkfen return (-1); 29604235Smarkfen } 29614235Smarkfen return (prefixlen); 29624235Smarkfen } 29634235Smarkfen 29644235Smarkfen /* 29654235Smarkfen * Convert a prefix length to a mask. 29664235Smarkfen * Assumes the mask array is zero'ed by the caller. 29674235Smarkfen */ 29684235Smarkfen static void 29694235Smarkfen in_prefixlentomask(unsigned int prefixlen, uchar_t *mask) 29704235Smarkfen { 29714235Smarkfen while (prefixlen > 0) { 29724235Smarkfen if (prefixlen >= 8) { 29734235Smarkfen *mask++ = 0xFF; 29744235Smarkfen prefixlen -= 8; 29754235Smarkfen continue; 29764235Smarkfen } 29774235Smarkfen *mask |= 1 << (8 - prefixlen); 29784235Smarkfen prefixlen--; 29794235Smarkfen } 29804235Smarkfen } 29814235Smarkfen 29824235Smarkfen 29834235Smarkfen static int 29844235Smarkfen parse_address(int type, char *addr_str) 29854235Smarkfen { 29864235Smarkfen char *ptr; 29874235Smarkfen int prefix_len = 0; 29884235Smarkfen struct netent *ne = NULL; 29894235Smarkfen struct hostent *hp = NULL; 29904235Smarkfen int h_errno; 29914235Smarkfen struct in_addr netaddr; 29924235Smarkfen struct in6_addr *netaddr6; 29934235Smarkfen struct hostent *ne_hent; 29944235Smarkfen boolean_t has_mask = B_FALSE; 29954235Smarkfen 29964235Smarkfen ptr = strchr(addr_str, '/'); 29974235Smarkfen if (ptr != NULL) { 29984235Smarkfen has_mask = B_TRUE; 29994235Smarkfen *ptr++ = NULL; 30004235Smarkfen 30014235Smarkfen prefix_len = in_getprefixlen(ptr); 30024235Smarkfen if (prefix_len < 0) 30034235Smarkfen return (-1); 30044235Smarkfen } 30054235Smarkfen 30064235Smarkfen /* 30074235Smarkfen * getipnodebyname() is thread safe. This allows us to hold on to the 30084235Smarkfen * returned hostent structure, which is pointed to by the shp and 30094235Smarkfen * dhp globals for the source and destination addresses, respectively. 30104235Smarkfen */ 30114235Smarkfen hp = getipnodebyname(addr_str, AF_INET6, AI_DEFAULT | AI_ALL, &h_errno); 30124235Smarkfen if (hp != NULL) { 30134235Smarkfen /* 30144235Smarkfen * We come here for both a hostname and 30154235Smarkfen * any host address /network address. 30164235Smarkfen */ 30174235Smarkfen assert(hp->h_addrtype == AF_INET6); 30184235Smarkfen } else if ((ne = getnetbyname(addr_str)) != NULL) { 30194235Smarkfen switch (ne->n_addrtype) { 30204235Smarkfen case AF_INET: 30214235Smarkfen /* 30224235Smarkfen * Allocate a struct hostent and initialize 30234235Smarkfen * it with the address corresponding to the 30244235Smarkfen * network number previously returned by 30254235Smarkfen * getnetbyname(). Freed by do_address_adds() 30264235Smarkfen * once the policy is defined. 30274235Smarkfen */ 30284235Smarkfen ne_hent = malloc(sizeof (struct hostent)); 30294235Smarkfen if (ne_hent == NULL) { 30304235Smarkfen warn("malloc"); 30314235Smarkfen return (-1); 30324235Smarkfen } 30334235Smarkfen ne_hent->h_addr_list = malloc(2*sizeof (char *)); 30344235Smarkfen if (ne_hent->h_addr_list == NULL) { 30354235Smarkfen warn("malloc"); 30364235Smarkfen free(ne_hent); 30374235Smarkfen return (-1); 30384235Smarkfen } 30394235Smarkfen netaddr6 = malloc(sizeof (struct in6_addr)); 30404235Smarkfen if (netaddr6 == NULL) { 30414235Smarkfen warn("malloc"); 30424235Smarkfen free(ne_hent->h_addr_list); 30434235Smarkfen free(ne_hent); 30444235Smarkfen return (-1); 30454235Smarkfen } 30464235Smarkfen ne_hent->h_addr_list[0] = (char *)netaddr6; 30474235Smarkfen ne_hent->h_addr_list[1] = NULL; 30484235Smarkfen netaddr = inet_makeaddr(ne->n_net, INADDR_ANY); 30494235Smarkfen IN6_INADDR_TO_V4MAPPED(&netaddr, netaddr6); 30504235Smarkfen hp = ne_hent; 30514235Smarkfen break; 30524235Smarkfen default: 30534235Smarkfen warnx("Address type %d not supported.", ne->n_addrtype); 30544235Smarkfen return (-1); 30554235Smarkfen } 30564235Smarkfen } else { 30574235Smarkfen return (-1); 30584235Smarkfen } 30594235Smarkfen 30604235Smarkfen if (type == IPSEC_CONF_SRC_ADDRESS) { 30614235Smarkfen shp = hp; 30624235Smarkfen if (has_mask) 30634235Smarkfen splen = prefix_len; 30644235Smarkfen has_saprefix = has_mask; 30654235Smarkfen } else { 30664235Smarkfen dhp = hp; 30674235Smarkfen if (has_mask) 30684235Smarkfen dplen = prefix_len; 30694235Smarkfen has_daprefix = has_mask; 30704235Smarkfen } 30714235Smarkfen 30724235Smarkfen return (0); 30734235Smarkfen } 30744235Smarkfen 30754235Smarkfen /* 30764235Smarkfen * Add port-only entries. Make sure to add them in both the V6 and V4 tables! 30774235Smarkfen */ 30784235Smarkfen static int 30794235Smarkfen do_port_adds(ips_conf_t *cptr) 30804235Smarkfen { 30814235Smarkfen int ret, diag; 30824235Smarkfen 30834235Smarkfen assert(IN6_IS_ADDR_UNSPECIFIED(&cptr->ips_src_addr_v6)); 30844235Smarkfen assert(IN6_IS_ADDR_UNSPECIFIED(&cptr->ips_dst_addr_v6)); 30854235Smarkfen 30864235Smarkfen #ifdef DEBUG_HEAVY 30874235Smarkfen (void) dump_conf(cptr); 30884235Smarkfen #endif 30894235Smarkfen 30904235Smarkfen ret = send_pf_pol_message(SPD_ADDRULE, cptr, &diag); 30914235Smarkfen if (ret != 0 && !ipsecconf_qflag) { 30924235Smarkfen warnx( 30934235Smarkfen gettext("Could not add IPv4 policy for sport %d, dport %d " 30945120Smarkfen "- diagnostic %d - %s"), ntohs(cptr->ips_src_port_min), 30954235Smarkfen ntohs(cptr->ips_dst_port_min), diag, spdsock_diag(diag)); 30964235Smarkfen } 30974235Smarkfen 30984235Smarkfen return (ret); 30994235Smarkfen } 31004235Smarkfen 31014235Smarkfen /* 31024235Smarkfen * Nuke a list of policy entries. 31034235Smarkfen * rewrite this to use flipping 31044235Smarkfen * d_list isn't freed because we will be 31054235Smarkfen * exiting the program soon. 31064235Smarkfen */ 31074235Smarkfen static void 31084235Smarkfen nuke_adds() 31094235Smarkfen { 31104235Smarkfen d_list_t *temp = d_list; 31114235Smarkfen FILE *policy_fp; 31124235Smarkfen 31134235Smarkfen policy_fp = fopen(POLICY_CONF_FILE, "a"); 31144235Smarkfen if (policy_fp == NULL) { 31154235Smarkfen warn(gettext("%s cannot be opened"), POLICY_CONF_FILE); 31165494Spwernau } else { 31175494Spwernau (void) fprintf(policy_fp, "\n\n"); 31185494Spwernau (void) fflush(policy_fp); 31194235Smarkfen } 31204235Smarkfen 31214235Smarkfen while (temp != NULL) { 31224235Smarkfen (void) ipsec_conf_del(temp->index, B_TRUE); 31234235Smarkfen temp = temp->next; 31244235Smarkfen } 31254235Smarkfen } 31264235Smarkfen 31274235Smarkfen /* 31284235Smarkfen * Set mask info from the specified prefix len. Fail if multihomed. 31294235Smarkfen */ 31304235Smarkfen static int 31314235Smarkfen set_mask_info(struct hostent *hp, unsigned int plen, struct in6_addr *mask_v6) 31324235Smarkfen { 31334235Smarkfen struct in6_addr addr; 31344235Smarkfen struct in_addr mask_v4; 31354235Smarkfen 31364235Smarkfen if (hp->h_addr_list[1] != NULL) { 31374235Smarkfen return (EOPNOTSUPP); 31384235Smarkfen } 31394235Smarkfen 31404235Smarkfen if (!IN6_IS_ADDR_UNSPECIFIED(mask_v6)) { 31414235Smarkfen return (EBUSY); 31424235Smarkfen } 31434235Smarkfen 31444235Smarkfen bcopy(hp->h_addr_list[0], &addr, sizeof (struct in6_addr)); 31454235Smarkfen if (IN6_IS_ADDR_V4MAPPED(&addr)) { 31464235Smarkfen if (plen > IP_ABITS) { 31474235Smarkfen return (ERANGE); 31484235Smarkfen } 31494235Smarkfen (void) memset(&mask_v4, 0, sizeof (mask_v4)); 31504235Smarkfen in_prefixlentomask(plen, (uchar_t *)&mask_v4); 31514235Smarkfen IN6_INADDR_TO_V4MAPPED(&mask_v4, mask_v6); 31524235Smarkfen } else { 31534235Smarkfen if (plen > IPV6_ABITS) { 31544235Smarkfen return (ERANGE); 31554235Smarkfen } 31564235Smarkfen /* mask_v6 is already zero (unspecified), see test above */ 31574235Smarkfen in_prefixlentomask(plen, (uchar_t *)mask_v6); 31584235Smarkfen } 31594235Smarkfen return (0); 31604235Smarkfen } 31614235Smarkfen 31624235Smarkfen /* 31634235Smarkfen * Initialize the specified IPv6 address with all f's. 31644235Smarkfen */ 31654235Smarkfen static void 31664235Smarkfen init_addr_wildcard(struct in6_addr *addr_v6, boolean_t isv4) 31674235Smarkfen { 31684235Smarkfen if (isv4) { 31694235Smarkfen uint32_t addr_v4 = 0xffffffff; 31704235Smarkfen IN6_INADDR_TO_V4MAPPED((struct in_addr *)&addr_v4, addr_v6); 31714235Smarkfen } else { 31724235Smarkfen (void) memset(addr_v6, 0xff, sizeof (struct in6_addr)); 31734235Smarkfen } 31744235Smarkfen } 31754235Smarkfen 31764235Smarkfen /* 31774235Smarkfen * Called at the end to actually add policy. Handles single and multi-homed 31784235Smarkfen * cases. 31794235Smarkfen */ 31804235Smarkfen static int 31814235Smarkfen do_address_adds(ips_conf_t *cptr, int *diag) 31824235Smarkfen { 31834235Smarkfen int i, j; 31844235Smarkfen int ret = 0; /* For ioctl() call. */ 31854235Smarkfen int rc = 0; /* My own return code. */ 31864235Smarkfen struct in6_addr zeroes = {0, 0, 0, 0}; 31874235Smarkfen char *ptr[2]; 31884235Smarkfen struct hostent hent; 31894235Smarkfen boolean_t isv4; 31904235Smarkfen int add_count = 0; 31914235Smarkfen 31924235Smarkfen /* 31934235Smarkfen * dst_hent may not be initialized if a destination 31944235Smarkfen * address was not given. It will be initalized with just 31954235Smarkfen * one address if a destination address was given. In both 31964235Smarkfen * the cases, we initialize here with ipsc_dst_addr and enter 31974235Smarkfen * the loop below. 31984235Smarkfen */ 31994235Smarkfen if (dhp == NULL) { 32004235Smarkfen assert(shp != NULL); 32014235Smarkfen hent.h_addr_list = ptr; 32024235Smarkfen ptr[0] = (char *)&zeroes.s6_addr; 32034235Smarkfen ptr[1] = NULL; 32044235Smarkfen dhp = &hent; 32054235Smarkfen } else if (shp == NULL) { 32064235Smarkfen assert(dhp != NULL); 32074235Smarkfen hent.h_addr_list = ptr; 32084235Smarkfen ptr[0] = (char *)&zeroes.s6_addr; 32094235Smarkfen ptr[1] = NULL; 32104235Smarkfen shp = &hent; 32114235Smarkfen } 32124235Smarkfen 32134235Smarkfen /* 32144235Smarkfen * Set mask info here. Bail if multihomed and there's a prefix len. 32154235Smarkfen */ 32164235Smarkfen if (has_saprefix) { 32174235Smarkfen rc = set_mask_info(shp, splen, &cptr->ips_src_mask_v6); 32184235Smarkfen if (rc != 0) 32194235Smarkfen goto bail; 32204235Smarkfen cptr->ips_src_mask_len = splen; 32214235Smarkfen } 32224235Smarkfen 32234235Smarkfen if (has_daprefix) { 32244235Smarkfen rc = set_mask_info(dhp, dplen, &cptr->ips_dst_mask_v6); 32254235Smarkfen if (rc != 0) 32264235Smarkfen goto bail; 32274235Smarkfen cptr->ips_dst_mask_len = dplen; 32284235Smarkfen } 32294235Smarkfen 32304235Smarkfen for (i = 0; shp->h_addr_list[i] != NULL; i++) { 32314235Smarkfen bcopy(shp->h_addr_list[i], &cptr->ips_src_addr_v6, 32324235Smarkfen sizeof (struct in6_addr)); 32334235Smarkfen isv4 = cptr->ips_isv4 = 32344235Smarkfen IN6_IS_ADDR_V4MAPPED(&cptr->ips_src_addr_v6); 32354235Smarkfen if (IN6_IS_ADDR_UNSPECIFIED(&cptr->ips_src_mask_v6) && 32364235Smarkfen shp != &hent) { 32374235Smarkfen init_addr_wildcard(&cptr->ips_src_mask_v6, isv4); 32384235Smarkfen } 32394235Smarkfen 32404235Smarkfen for (j = 0; dhp->h_addr_list[j] != NULL; j++) { 32414235Smarkfen bcopy(dhp->h_addr_list[j], &cptr->ips_dst_addr_v6, 32424235Smarkfen sizeof (struct in6_addr)); 32434235Smarkfen if (IN6_IS_ADDR_UNSPECIFIED(&cptr->ips_src_addr_v6)) { 32444235Smarkfen /* 32454235Smarkfen * Src was not specified, so update isv4 flag 32464235Smarkfen * for this policy according to the family 32474235Smarkfen * of the destination address. 32484235Smarkfen */ 32494235Smarkfen isv4 = cptr->ips_isv4 = 32504235Smarkfen IN6_IS_ADDR_V4MAPPED( 32515120Smarkfen &cptr->ips_dst_addr_v6); 32524235Smarkfen } else if ((dhp != &hent) && (isv4 != 32534235Smarkfen IN6_IS_ADDR_V4MAPPED(&cptr->ips_dst_addr_v6))) { 32544235Smarkfen /* v6/v4 mismatch. */ 32554235Smarkfen continue; 32564235Smarkfen } 32574235Smarkfen if (IN6_IS_ADDR_UNSPECIFIED(&cptr->ips_dst_mask_v6) && 32584235Smarkfen dhp != &hent) { 32594235Smarkfen init_addr_wildcard(&cptr->ips_dst_mask_v6, 32604235Smarkfen isv4); 32614235Smarkfen } 32624235Smarkfen 32634235Smarkfen ret = send_pf_pol_message(SPD_ADDRULE, cptr, diag); 32644235Smarkfen 32654235Smarkfen if (ret == 0) { 32664235Smarkfen add_count++; 32674235Smarkfen } else { 32684235Smarkfen /* For now, allow duplicate/overlap policies. */ 32694235Smarkfen if (ret != EEXIST) { 32704235Smarkfen /* 32714235Smarkfen * We have an error where we added 32724235Smarkfen * some, but had errors with others. 32734235Smarkfen * Undo the previous adds, and 32744235Smarkfen * bail. 32754235Smarkfen */ 32764235Smarkfen rc = ret; 32774235Smarkfen goto bail; 32784235Smarkfen } 32794235Smarkfen } 32804235Smarkfen 32814235Smarkfen bzero(&cptr->ips_dst_mask_v6, 32824235Smarkfen sizeof (struct in6_addr)); 32834235Smarkfen } 32844235Smarkfen 32854235Smarkfen bzero(&cptr->ips_src_mask_v6, sizeof (struct in6_addr)); 32864235Smarkfen } 32874235Smarkfen 32884235Smarkfen bail: 32894235Smarkfen if (shp != &hent) 32904235Smarkfen freehostent(shp); 32914235Smarkfen shp = NULL; 32924235Smarkfen if (dhp != &hent) 32934235Smarkfen freehostent(dhp); 32944235Smarkfen dhp = NULL; 32954235Smarkfen splen = 0; 32964235Smarkfen dplen = 0; 32974235Smarkfen 32984235Smarkfen if ((add_count == 0) && (rc == 0)) { 32994235Smarkfen /* 33004235Smarkfen * No entries were added. We failed all adds 33014235Smarkfen * because the entries already existed, or because 33024235Smarkfen * no v4 or v6 src/dst pairs were found. Either way, 33034235Smarkfen * we must fail here with an appropriate error 33044235Smarkfen * to avoid a corresponding entry from being added 33054235Smarkfen * to ipsecpolicy.conf. 33064235Smarkfen */ 33074235Smarkfen if ((ret == EEXIST)) { 33084235Smarkfen /* All adds failed with EEXIST */ 33094235Smarkfen rc = EEXIST; 33104235Smarkfen } else { 33114235Smarkfen /* No matching v4 or v6 src/dst pairs */ 33124235Smarkfen rc = ESRCH; 33134235Smarkfen } 33144235Smarkfen } 33154235Smarkfen 33164235Smarkfen return (rc); 33174235Smarkfen } 33184235Smarkfen 33194235Smarkfen static int 33204235Smarkfen parse_mask(int type, char *mask_str, ips_conf_t *cptr) 33214235Smarkfen { 33224235Smarkfen struct in_addr mask; 33234235Smarkfen struct in6_addr *mask6; 33244235Smarkfen 33254235Smarkfen if (type == IPSEC_CONF_SRC_MASK) { 33264235Smarkfen mask6 = &cptr->ips_src_mask_v6; 33274235Smarkfen } else { 33284235Smarkfen mask6 = &cptr->ips_dst_mask_v6; 33294235Smarkfen } 33304235Smarkfen 33314235Smarkfen if ((strncasecmp(mask_str, "0x", 2) == 0) && 33324235Smarkfen (strchr(mask_str, '.') == NULL)) { 33334235Smarkfen /* Is it in the form 0xff000000 ? */ 33344235Smarkfen char *end; 33354235Smarkfen 33364235Smarkfen mask.s_addr = strtoul(mask_str, &end, 0); 33374235Smarkfen if (end == mask_str) { 33384235Smarkfen return (-1); 33394235Smarkfen } 33404235Smarkfen if (*end != '\0') { 33414235Smarkfen return (-1); 33424235Smarkfen } 33434235Smarkfen mask.s_addr = htonl(mask.s_addr); 33444235Smarkfen } else { 33454235Smarkfen /* 33464235Smarkfen * Since inet_addr() returns -1 on error, we have 33474235Smarkfen * to convert a broadcast address ourselves. 33484235Smarkfen */ 33494235Smarkfen if (strcmp(mask_str, "255.255.255.255") == 0) { 33504235Smarkfen mask.s_addr = 0xffffffff; 33514235Smarkfen } else { 33524235Smarkfen mask.s_addr = inet_addr(mask_str); 33534235Smarkfen if (mask.s_addr == (unsigned int)-1) 33544235Smarkfen return (-1); 33554235Smarkfen } 33564235Smarkfen } 33574235Smarkfen 33584235Smarkfen /* Should we check for non-contiguous masks ? */ 33594235Smarkfen if (mask.s_addr == 0) 33604235Smarkfen return (-1); 33614235Smarkfen IN6_INADDR_TO_V4MAPPED(&mask, mask6); 33624235Smarkfen 33634235Smarkfen 33644235Smarkfen if (type == IPSEC_CONF_SRC_MASK) { 33654235Smarkfen cptr->ips_src_mask_len = in_masktoprefix(mask6->s6_addr, 33664235Smarkfen B_TRUE); 33674235Smarkfen } else { 33684235Smarkfen cptr->ips_dst_mask_len = in_masktoprefix(mask6->s6_addr, 33694235Smarkfen B_TRUE); 33704235Smarkfen } 33714235Smarkfen 33724235Smarkfen return (0); 33734235Smarkfen } 33744235Smarkfen 33754235Smarkfen static int 33764235Smarkfen parse_port(int type, char *port_str, ips_conf_t *conf) 33774235Smarkfen { 33784235Smarkfen struct servent *sent; 33794235Smarkfen in_port_t port; 33804235Smarkfen int ret; 33814235Smarkfen 33824235Smarkfen sent = getservbyname(port_str, NULL); 33834235Smarkfen if (sent == NULL) { 33844235Smarkfen ret = parse_int(port_str); 33854235Smarkfen if (ret < 0 || ret >= 65536) { 33864235Smarkfen return (-1); 33874235Smarkfen } 33884235Smarkfen port = htons((in_port_t)ret); 33894235Smarkfen } else { 33904235Smarkfen port = sent->s_port; 33914235Smarkfen } 33924235Smarkfen if (type == IPSEC_CONF_SRC_PORT) { 33934235Smarkfen conf->ips_src_port_min = conf->ips_src_port_max = port; 33944235Smarkfen } else { 33954235Smarkfen conf->ips_dst_port_min = conf->ips_dst_port_max = port; 33964235Smarkfen } 33974235Smarkfen return (0); 33984235Smarkfen } 33994235Smarkfen 34004235Smarkfen static int 34014235Smarkfen valid_algorithm(int proto_num, const char *str) 34024235Smarkfen { 34034235Smarkfen const char *tmp; 34044235Smarkfen int ret; 34054235Smarkfen struct ipsecalgent *alg; 34064235Smarkfen 34074235Smarkfen /* Short-circuit "none" */ 34084235Smarkfen if (strncasecmp("none", str, 5) == 0) 34094235Smarkfen return (-2); 34104235Smarkfen 34114235Smarkfen alg = getipsecalgbyname(str, proto_num, NULL); 34124235Smarkfen if (alg != NULL) { 34134235Smarkfen ret = alg->a_alg_num; 34144235Smarkfen freeipsecalgent(alg); 34154235Smarkfen return (ret); 34164235Smarkfen } 34174235Smarkfen 34184235Smarkfen /* 34194235Smarkfen * Look whether it could be a valid number. 34204235Smarkfen * We support numbers also so that users can 34214235Smarkfen * load algorithms as they need it. We can't 34224235Smarkfen * check for validity of numbers here. It will 34234235Smarkfen * be checked when the SA is negotiated/looked up. 34244235Smarkfen * parse_int uses strtol(str), which converts 3DES 34254235Smarkfen * to a valid number i.e looks only at initial 34264235Smarkfen * number part. If we come here we should expect 34274235Smarkfen * only a decimal number. 34284235Smarkfen */ 34294235Smarkfen tmp = str; 34304235Smarkfen while (*tmp) { 34314235Smarkfen if (!isdigit(*tmp)) 34324235Smarkfen return (-1); 34334235Smarkfen tmp++; 34344235Smarkfen } 34354235Smarkfen 34364235Smarkfen ret = parse_int(str); 34374235Smarkfen if (ret > 0 && ret <= 255) 34384235Smarkfen return (ret); 34394235Smarkfen else 34404235Smarkfen return (-1); 34414235Smarkfen } 34424235Smarkfen 34434235Smarkfen static int 34444235Smarkfen parse_ipsec_alg(char *str, ips_act_props_t *iap, int alg_type) 34454235Smarkfen { 34464235Smarkfen int alg_value; 34474235Smarkfen char tstr[VALID_ALG_LEN]; 34484235Smarkfen char *lens = NULL; 34494235Smarkfen char *l1_str; 34504235Smarkfen int l1 = 0; 34514235Smarkfen char *l2_str; 34524235Smarkfen int l2 = SPD_MAX_MAXBITS; 34534235Smarkfen algreq_t *ap; 34544235Smarkfen uint_t a_type; 34554235Smarkfen 34564235Smarkfen fetch_algorithms(); 34574235Smarkfen 34584235Smarkfen /* 34594235Smarkfen * Make sure that we get a null terminated string. 34604235Smarkfen * For a bad input, we truncate at VALID_ALG_LEN. 34614235Smarkfen */ 34624235Smarkfen (void) strlcpy(tstr, str, VALID_ALG_LEN); 34634235Smarkfen lens = strtok(tstr, "()"); 34644235Smarkfen lens = strtok(NULL, "()"); 34654235Smarkfen 34664235Smarkfen if (lens != NULL) { 34674235Smarkfen int len1 = 0; 34684235Smarkfen int len2 = SPD_MAX_MAXBITS; 34694235Smarkfen int len_all = strlen(lens); 34704235Smarkfen int dot_start = (lens[0] == '.'); 34714235Smarkfen l1_str = strtok(lens, "."); 34724235Smarkfen l2_str = strtok(NULL, "."); 34734235Smarkfen if (l1_str != NULL) { 34744235Smarkfen l1 = parse_int(l1_str); 34754235Smarkfen len1 = strlen(l1_str); 34764235Smarkfen if (len1 < 0) 34774235Smarkfen return (1); 34784235Smarkfen } 34794235Smarkfen if (l2_str != NULL) { 34804235Smarkfen l2 = parse_int(l2_str); 34814235Smarkfen len2 = strlen(l2_str); 34824235Smarkfen if (len2 < 0) 34834235Smarkfen return (1); 34844235Smarkfen } 34854235Smarkfen 34864235Smarkfen if (len_all == len1) { 34874235Smarkfen /* alg(n) */ 34884235Smarkfen l2 = l1; 34894235Smarkfen } else if (dot_start) { 34904235Smarkfen /* alg(..n) */ 34914235Smarkfen l2 = l1; 34924235Smarkfen l1 = 0; 34934235Smarkfen } else if ((len_all - 2) == len1) { 34944235Smarkfen /* alg(n..) */ 34954235Smarkfen l2 = SPD_MAX_MAXBITS; 34964235Smarkfen } /* else alg(n..m) */ 34974235Smarkfen } 34984235Smarkfen 34994235Smarkfen if (alg_type == SPD_ATTR_AH_AUTH || 35004235Smarkfen alg_type == SPD_ATTR_ESP_AUTH) { 35014235Smarkfen alg_value = valid_algorithm(IPSEC_PROTO_AH, tstr); 35024235Smarkfen } else { 35034235Smarkfen alg_value = valid_algorithm(IPSEC_PROTO_ESP, tstr); 35044235Smarkfen } 35054235Smarkfen if (alg_value < 0) { 35064235Smarkfen /* Invalid algorithm or "none" */ 35074235Smarkfen return (alg_value); 35084235Smarkfen } 35094235Smarkfen 35104235Smarkfen if (alg_type == SPD_ATTR_AH_AUTH) { 35114235Smarkfen a_type = AH_AUTH; 35124235Smarkfen iap->iap_attr |= SPD_APPLY_AH; 35134235Smarkfen ap = &(iap->iap_aauth); 35144235Smarkfen } else if (alg_type == SPD_ATTR_ESP_AUTH) { 35154235Smarkfen a_type = ESP_AUTH; 35164235Smarkfen iap->iap_attr |= SPD_APPLY_ESP|SPD_APPLY_ESPA; 35174235Smarkfen ap = &(iap->iap_eauth); 35184235Smarkfen } else { 35194235Smarkfen a_type = ESP_ENCR; 35204235Smarkfen iap->iap_attr |= SPD_APPLY_ESP; 35214235Smarkfen ap = &(iap->iap_eencr); 35224235Smarkfen } 35234235Smarkfen 35244235Smarkfen ap->alg_id = alg_value; 35254235Smarkfen ap->alg_minbits = l1; 35264235Smarkfen ap->alg_maxbits = l2; 35274235Smarkfen 35284235Smarkfen if (!alg_rangecheck(a_type, alg_value, ap)) 35294235Smarkfen return (1); 35304235Smarkfen 35314235Smarkfen return (0); 35324235Smarkfen } 35334235Smarkfen 35344235Smarkfen static char * 35354235Smarkfen sys_error_message(int syserr) 35364235Smarkfen { 35374235Smarkfen char *mesg; 35384235Smarkfen 35394235Smarkfen switch (syserr) { 35404235Smarkfen case EEXIST: 35414235Smarkfen mesg = gettext("Entry already exists"); 35424235Smarkfen break; 35434235Smarkfen case ENOENT: 35444235Smarkfen mesg = gettext("Tunnel not found"); 35454235Smarkfen break; 35464235Smarkfen case EINVAL: 35474235Smarkfen mesg = gettext("Invalid entry"); 35484235Smarkfen break; 35494235Smarkfen default : 35504235Smarkfen mesg = strerror(syserr); 35514235Smarkfen } 35524235Smarkfen return (mesg); 35534235Smarkfen } 35544235Smarkfen 35554235Smarkfen static void 35564235Smarkfen error_message(error_type_t error, int type, int line) 35574235Smarkfen { 35584235Smarkfen char *mesg; 35594235Smarkfen 35604235Smarkfen switch (type) { 35614235Smarkfen case IPSEC_CONF_SRC_ADDRESS: 35624235Smarkfen mesg = gettext("Source Address"); 35634235Smarkfen break; 35644235Smarkfen case IPSEC_CONF_DST_ADDRESS: 35654235Smarkfen mesg = gettext("Destination Address"); 35664235Smarkfen break; 35674235Smarkfen case IPSEC_CONF_SRC_PORT: 35684235Smarkfen mesg = gettext("Source Port"); 35694235Smarkfen break; 35704235Smarkfen case IPSEC_CONF_DST_PORT: 35714235Smarkfen mesg = gettext("Destination Port"); 35724235Smarkfen break; 35734235Smarkfen case IPSEC_CONF_SRC_MASK: 35744235Smarkfen mesg = gettext("Source Mask"); 35754235Smarkfen break; 35764235Smarkfen case IPSEC_CONF_DST_MASK: 35774235Smarkfen mesg = gettext("Destination Mask"); 35784235Smarkfen break; 35794235Smarkfen case IPSEC_CONF_ULP: 35804235Smarkfen mesg = gettext("Upper Layer Protocol"); 35814235Smarkfen break; 35824235Smarkfen case IPSEC_CONF_IPSEC_AALGS: 35834235Smarkfen mesg = gettext("Authentication Algorithm"); 35844235Smarkfen break; 35854235Smarkfen case IPSEC_CONF_IPSEC_EALGS: 35864235Smarkfen mesg = gettext("Encryption Algorithm"); 35874235Smarkfen break; 35884235Smarkfen case IPSEC_CONF_IPSEC_EAALGS: 35894235Smarkfen mesg = gettext("ESP Authentication Algorithm"); 35904235Smarkfen break; 35914235Smarkfen case IPSEC_CONF_IPSEC_SA: 35924235Smarkfen mesg = gettext("SA"); 35934235Smarkfen break; 35944235Smarkfen case IPSEC_CONF_IPSEC_DIR: 35954235Smarkfen mesg = gettext("Direction"); 35964235Smarkfen break; 35974235Smarkfen case IPSEC_CONF_ICMP_TYPE: 35984235Smarkfen mesg = gettext("ICMP type"); 35994235Smarkfen break; 36004235Smarkfen case IPSEC_CONF_ICMP_CODE: 36014235Smarkfen mesg = gettext("ICMP code"); 36024235Smarkfen break; 36034235Smarkfen case IPSEC_CONF_NEGOTIATE: 36044235Smarkfen mesg = gettext("Negotiate"); 36054235Smarkfen break; 36064235Smarkfen case IPSEC_CONF_TUNNEL: 36074235Smarkfen mesg = gettext("Tunnel"); 36084235Smarkfen break; 36094235Smarkfen default : 36104235Smarkfen return; 36114235Smarkfen } 36124235Smarkfen /* 36134235Smarkfen * If we never read a newline character, we don't want 36144235Smarkfen * to print 0. 36154235Smarkfen */ 36164235Smarkfen warnx(gettext("%s%s%s %s on line: %d"), 36174235Smarkfen (error == BAD_ERROR) ? gettext("Bad") : "", 36184235Smarkfen (error == DUP_ERROR) ? gettext("Duplicate") : "", 36194235Smarkfen (error == REQ_ERROR) ? gettext("Requires") : "", 36204235Smarkfen mesg, 36214235Smarkfen (arg_indices[line] == 0) ? 1 : arg_indices[line]); 36224235Smarkfen } 36234235Smarkfen 36244235Smarkfen static int 36254235Smarkfen validate_properties(ips_act_props_t *cptr, boolean_t dir, boolean_t is_alg) 36264235Smarkfen { 36274235Smarkfen if (cptr->iap_action == SPD_ACTTYPE_PASS || 36285120Smarkfen cptr->iap_action == SPD_ACTTYPE_DROP) { 36294235Smarkfen if (!dir) { 36304235Smarkfen warnx(gettext("dir string " 36314235Smarkfen "not found for bypass policy")); 36324235Smarkfen } 36334235Smarkfen 36344235Smarkfen if (is_alg) { 36354235Smarkfen warnx(gettext("Algorithms found for bypass policy")); 36364235Smarkfen return (-1); 36374235Smarkfen } 36384235Smarkfen return (0); 36394235Smarkfen } 36404235Smarkfen if (!is_alg) { 36414235Smarkfen warnx(gettext("No IPsec algorithms given")); 36424235Smarkfen return (-1); 36434235Smarkfen } 36444235Smarkfen if (cptr->iap_attr == 0) { 36454235Smarkfen warnx(gettext("No SA attribute")); 36464235Smarkfen return (-1); 36474235Smarkfen } 36484235Smarkfen return (0); 36494235Smarkfen } 36504235Smarkfen 36514235Smarkfen /* 36524235Smarkfen * This function is called only to parse a single rule's worth of 36534235Smarkfen * action strings. This is called after parsing pattern and before 36544235Smarkfen * parsing properties. Thus we may have something in the leftover 36554235Smarkfen * buffer while parsing the pattern, which we need to handle here. 36564235Smarkfen */ 36574235Smarkfen static int 36584235Smarkfen parse_action(FILE *fp, char **action, char **leftover) 36594235Smarkfen { 36604235Smarkfen char *cp; 36614235Smarkfen char ibuf[MAXLEN]; 36624235Smarkfen char *tmp_buf; 36634235Smarkfen char *buf; 36644235Smarkfen boolean_t new_stuff; 36654235Smarkfen 36664235Smarkfen if (*leftover != NULL) { 36674235Smarkfen buf = *leftover; 36684235Smarkfen new_stuff = B_FALSE; 36694235Smarkfen goto scan; 36704235Smarkfen } 36714235Smarkfen while (fgets(ibuf, MAXLEN, fp) != NULL) { 36724235Smarkfen new_stuff = B_TRUE; 36734235Smarkfen if (ibuf[strlen(ibuf) - 1] == '\n') 36744235Smarkfen linecount++; 36754235Smarkfen buf = ibuf; 36764235Smarkfen scan: 36774235Smarkfen /* Truncate at the beginning of a comment */ 36784235Smarkfen cp = strchr(buf, '#'); 36794235Smarkfen if (cp != NULL) 36804235Smarkfen *cp = NULL; 36814235Smarkfen 36824235Smarkfen /* Skip any whitespace */ 36834235Smarkfen while (*buf != NULL && isspace(*buf)) 36844235Smarkfen buf++; 36854235Smarkfen 36864235Smarkfen /* Empty line */ 36874235Smarkfen if (*buf == NULL) 36884235Smarkfen continue; 36894235Smarkfen 36904235Smarkfen /* 36914235Smarkfen * Store the command for error reporting 36924235Smarkfen * and ipsec_conf_add(). 36934235Smarkfen */ 36944235Smarkfen if (new_stuff) { 36954235Smarkfen /* 36964235Smarkfen * Check for buffer overflow including the null 36974235Smarkfen * terminating character. 36984235Smarkfen */ 36994235Smarkfen int len = strlen(ibuf); 37004235Smarkfen if ((cbuf_offset + len + 1) >= CBUF_LEN) 37014235Smarkfen return (-1); 37025120Smarkfen 37034235Smarkfen (void) strcpy(cbuf + cbuf_offset, ibuf); 37044235Smarkfen cbuf_offset += len; 37054235Smarkfen } 37064235Smarkfen /* 37074235Smarkfen * Start of the non-empty non-space character. 37084235Smarkfen */ 37095120Smarkfen tmp_buf = buf; 37104235Smarkfen 37114235Smarkfen /* Skip until next whitespace or CURL_BEGIN */ 37124235Smarkfen while (*buf != NULL && !isspace(*buf) && 37134235Smarkfen *buf != CURL_BEGIN) 37144235Smarkfen buf++; 37154235Smarkfen 37164235Smarkfen if (*buf != NULL) { 37175120Smarkfen if (tmp_buf == buf) /* No action token */ 37185120Smarkfen goto error; 37194235Smarkfen if (*buf == CURL_BEGIN) { 37204235Smarkfen *buf = NULL; 37214235Smarkfen /* Allocate an extra byte for the null also */ 37224235Smarkfen if ((*action = malloc(strlen(tmp_buf) + 1)) == 37234235Smarkfen NULL) { 37244235Smarkfen warn("malloc"); 37254235Smarkfen return (ENOMEM); 37264235Smarkfen } 37274235Smarkfen (void) strcpy(*action, tmp_buf); 37284235Smarkfen *buf = CURL_BEGIN; 37294235Smarkfen } else { 37304235Smarkfen /* We have hit a space */ 37314235Smarkfen *buf++ = NULL; 37324235Smarkfen /* Allocate an extra byte for the null also */ 37334235Smarkfen if ((*action = malloc(strlen(tmp_buf) + 1)) == 37344235Smarkfen NULL) { 37354235Smarkfen warn("malloc"); 37364235Smarkfen return (ENOMEM); 37374235Smarkfen } 37384235Smarkfen (void) strcpy(*action, tmp_buf); 37394235Smarkfen } 37404235Smarkfen /* 37414235Smarkfen * Copy the rest of the line into the 37424235Smarkfen * leftover buffer. 37434235Smarkfen */ 37444235Smarkfen if (*buf != NULL) { 37454235Smarkfen (void) strlcpy(lo_buf, buf, sizeof (lo_buf)); 37464235Smarkfen *leftover = lo_buf; 37474235Smarkfen } else { 37484235Smarkfen *leftover = NULL; 37494235Smarkfen } 37504235Smarkfen } else { 37514235Smarkfen /* Allocate an extra byte for the null also */ 37524235Smarkfen if ((*action = malloc(strlen(tmp_buf) + 1)) == 37534235Smarkfen NULL) { 37544235Smarkfen warn("malloc"); 37554235Smarkfen return (ENOMEM); 37564235Smarkfen } 37574235Smarkfen (void) strcpy(*action, tmp_buf); 37584235Smarkfen *leftover = NULL; 37594235Smarkfen } 37605120Smarkfen if (argindex >= ARG_BUF_LEN) { 37615120Smarkfen warnx(gettext("(parsing one command) " 37625120Smarkfen "Too many selectors before action.")); 37634235Smarkfen return (-1); 37645120Smarkfen } 37654235Smarkfen arg_indices[argindex++] = linecount; 37664235Smarkfen return (PARSE_SUCCESS); 37674235Smarkfen } 37684235Smarkfen /* 37694235Smarkfen * Return error, on an empty action field. 37704235Smarkfen */ 37715120Smarkfen error: 37725120Smarkfen warnx(gettext("(parsing one command) " 37735120Smarkfen "Missing action token.")); 37744235Smarkfen return (-1); 37754235Smarkfen } 37764235Smarkfen 37774235Smarkfen /* 37784235Smarkfen * This is called to parse pattern or properties that is enclosed 37794235Smarkfen * between CURL_BEGIN and CURL_END. 37804235Smarkfen */ 37814235Smarkfen static int 37824235Smarkfen parse_pattern_or_prop(FILE *fp, char *argvec[], char **leftover) 37834235Smarkfen { 37844235Smarkfen char *cp; 37854235Smarkfen int i = 0; 37864235Smarkfen boolean_t curl_begin_seen = B_FALSE; 37874235Smarkfen char ibuf[MAXLEN]; 37884235Smarkfen char *tmp_buf; 37894235Smarkfen char *buf; 37904235Smarkfen boolean_t new_stuff; 37914235Smarkfen 37924235Smarkfen /* 37934235Smarkfen * When parsing properties, leftover buffer could have the 37944235Smarkfen * leftovers of the previous fgets(). 37954235Smarkfen */ 37964235Smarkfen if (*leftover != NULL) { 37974235Smarkfen buf = *leftover; 37984235Smarkfen new_stuff = B_FALSE; 37994235Smarkfen goto scan; 38004235Smarkfen } 38014235Smarkfen while (fgets(ibuf, MAXLEN, fp) != NULL) { 38024235Smarkfen new_stuff = B_TRUE; 38034235Smarkfen #ifdef DEBUG_HEAVY 38044235Smarkfen (void) printf("%s\n", ibuf); 38054235Smarkfen #endif 38064235Smarkfen if (ibuf[strlen(ibuf) - 1] == '\n') 38074235Smarkfen linecount++; 38084235Smarkfen buf = ibuf; 38094235Smarkfen scan: 38104235Smarkfen /* Truncate at the beginning of a comment */ 38114235Smarkfen cp = strchr(buf, '#'); 38124235Smarkfen if (cp != NULL) 38134235Smarkfen *cp = NULL; 38144235Smarkfen 38154235Smarkfen /* Skip any whitespace */ 38164235Smarkfen while (*buf != NULL && isspace(*buf)) 38174235Smarkfen buf++; 38184235Smarkfen 38194235Smarkfen /* Empty line */ 38204235Smarkfen if (*buf == NULL) 38214235Smarkfen continue; 38224235Smarkfen /* 38234235Smarkfen * Store the command for error reporting 38244235Smarkfen * and ipsec_conf_add(). 38254235Smarkfen */ 38264235Smarkfen if (new_stuff) { 38274235Smarkfen /* 38284235Smarkfen * Check for buffer overflow including the null 38294235Smarkfen * terminating character. 38304235Smarkfen */ 38314235Smarkfen int len = strlen(ibuf); 38324235Smarkfen if ((cbuf_offset + len + 1) >= CBUF_LEN) 38334235Smarkfen return (-1); 38344235Smarkfen (void) strcpy(cbuf + cbuf_offset, ibuf); 38354235Smarkfen cbuf_offset += len; 38364235Smarkfen } 38374235Smarkfen /* 38384235Smarkfen * First non-space character should be 38394235Smarkfen * a curly bracket. 38404235Smarkfen */ 38414235Smarkfen if (!curl_begin_seen) { 38424235Smarkfen if (*buf != CURL_BEGIN) { 38434235Smarkfen /* 38444235Smarkfen * If we never read a newline character, 38454235Smarkfen * we don't want to print 0. 38464235Smarkfen */ 38475120Smarkfen warnx(gettext("line %d : pattern must start " 38485120Smarkfen "with \"%c\" character"), 38495120Smarkfen (linecount == 0) ? 1 : linecount, 38505120Smarkfen CURL_BEGIN); 38514235Smarkfen return (-1); 38524235Smarkfen } 38534235Smarkfen buf++; 38544235Smarkfen curl_begin_seen = B_TRUE; 38554235Smarkfen } 38564235Smarkfen /* 38574235Smarkfen * Arguments are separated by white spaces or 38584235Smarkfen * newlines. Scan till you see a CURL_END. 38594235Smarkfen */ 38604235Smarkfen while (*buf != NULL) { 38614235Smarkfen if (*buf == CURL_END) { 38624235Smarkfen ret: 38634235Smarkfen *buf++ = NULL; 38644235Smarkfen /* 38654235Smarkfen * Copy the rest of the line into the 38664235Smarkfen * leftover buffer if any. 38674235Smarkfen */ 38684235Smarkfen if (*buf != NULL) { 38694235Smarkfen (void) strlcpy(lo_buf, buf, 38704235Smarkfen sizeof (lo_buf)); 38714235Smarkfen *leftover = lo_buf; 38724235Smarkfen } else { 38734235Smarkfen *leftover = NULL; 38744235Smarkfen } 38754235Smarkfen return (PARSE_SUCCESS); 38764235Smarkfen } 38774235Smarkfen /* 38784235Smarkfen * Skip any trailing whitespace until we see a 38794235Smarkfen * non white-space character. 38804235Smarkfen */ 38814235Smarkfen while (*buf != NULL && isspace(*buf)) 38824235Smarkfen buf++; 38834235Smarkfen 38844235Smarkfen if (*buf == CURL_END) 38854235Smarkfen goto ret; 38864235Smarkfen 38874235Smarkfen /* Scan the next line as this buffer is empty */ 38884235Smarkfen if (*buf == NULL) 38894235Smarkfen break; 38904235Smarkfen 38914235Smarkfen if (i >= MAXARGS) { 38924235Smarkfen warnx( 38934235Smarkfen gettext("Number of Arguments exceeded %d"), 38944235Smarkfen i); 38954235Smarkfen return (-1); 38964235Smarkfen } 38974235Smarkfen /* 38984235Smarkfen * Non-empty, Non-space buffer. 38994235Smarkfen */ 39004235Smarkfen tmp_buf = buf++; 39014235Smarkfen /* 39024235Smarkfen * Real scan of the argument takes place here. 39034235Smarkfen * Skip past till space or CURL_END. 39044235Smarkfen */ 39054235Smarkfen while (*buf != NULL && !isspace(*buf) && 39064235Smarkfen *buf != CURL_END) { 39074235Smarkfen buf++; 39084235Smarkfen } 39094235Smarkfen /* 39104235Smarkfen * Either a space or we have hit the CURL_END or 39114235Smarkfen * the real end. 39124235Smarkfen */ 39134235Smarkfen if (*buf != NULL) { 39144235Smarkfen if (*buf == CURL_END) { 39154235Smarkfen *buf++ = NULL; 39164235Smarkfen if ((argvec[i] = malloc(strlen(tmp_buf) 39174235Smarkfen + 1)) == NULL) { 39184235Smarkfen warn("malloc"); 39194235Smarkfen return (ENOMEM); 39204235Smarkfen } 39214235Smarkfen if (strlen(tmp_buf) != 0) { 39224235Smarkfen (void) strcpy(argvec[i], 39234235Smarkfen tmp_buf); 39244235Smarkfen if (argindex >= ARG_BUF_LEN) 39255120Smarkfen goto toomanyargs; 39264235Smarkfen arg_indices[argindex++] = 39274235Smarkfen linecount; 39284235Smarkfen } 39294235Smarkfen /* 39304235Smarkfen * Copy the rest of the line into the 39314235Smarkfen * leftover buffer. 39324235Smarkfen */ 39334235Smarkfen if (*buf != NULL) { 39344235Smarkfen (void) strlcpy(lo_buf, buf, 39354235Smarkfen sizeof (lo_buf)); 39364235Smarkfen *leftover = lo_buf; 39374235Smarkfen } else { 39384235Smarkfen *leftover = NULL; 39394235Smarkfen } 39404235Smarkfen return (PARSE_SUCCESS); 39414235Smarkfen } else { 39424235Smarkfen *buf++ = NULL; 39434235Smarkfen } 39444235Smarkfen } 39454235Smarkfen /* 39464235Smarkfen * Copy this argument and scan for the buffer more 39474235Smarkfen * if it is non-empty. If it is empty scan for 39484235Smarkfen * the next line. 39494235Smarkfen */ 39504235Smarkfen if ((argvec[i] = malloc(strlen(tmp_buf) + 1)) == 39514235Smarkfen NULL) { 39524235Smarkfen warn("malloc"); 39534235Smarkfen return (ENOMEM); 39544235Smarkfen } 39554235Smarkfen (void) strcpy(argvec[i++], tmp_buf); 39565120Smarkfen if (argindex >= ARG_BUF_LEN) { 39575120Smarkfen /* 39585120Smarkfen * The number of tokens in a single policy entry 39595120Smarkfen * exceeds the number of buffers available to fully 39605120Smarkfen * parse the policy entry. 39615120Smarkfen */ 39625120Smarkfen toomanyargs: 39635120Smarkfen warnx(gettext("(parsing one command) " 39645120Smarkfen "Too many tokens in single policy entry.")); 39654235Smarkfen return (-1); 39665120Smarkfen } 39674235Smarkfen arg_indices[argindex++] = linecount; 39684235Smarkfen } 39694235Smarkfen } 39704235Smarkfen /* 39714235Smarkfen * If nothing is given in the file, it is okay. 39724235Smarkfen * If something is given in the file and it is 39734235Smarkfen * not CURL_BEGIN, we would have returned error 39744235Smarkfen * above. If curl_begin_seen and we are here, 39754235Smarkfen * something is wrong. 39764235Smarkfen */ 39775120Smarkfen if (curl_begin_seen) { 39785120Smarkfen warnx(gettext("(parsing one command) " 39795120Smarkfen "Pattern or Properties incomplete.")); 39804235Smarkfen return (-1); 39815120Smarkfen } 39824235Smarkfen return (PARSE_EOF); /* Nothing more in the file */ 39834235Smarkfen } 39844235Smarkfen 39854235Smarkfen /* 39864235Smarkfen * Parse one command i.e {pattern} action {properties}. 39874235Smarkfen * 39884235Smarkfen * {pattern} ( action {prop} | pass | drop ) (or ...)* 39894235Smarkfen */ 39904235Smarkfen static int 39914235Smarkfen parse_one(FILE *fp, act_prop_t *act_props) 39924235Smarkfen { 39934235Smarkfen char *leftover; 39944235Smarkfen int ret; 39954235Smarkfen int i; 39964235Smarkfen int ap_num = 0; 39974235Smarkfen enum parse_state {pattern, action, prop } pstate; 39984235Smarkfen 39994235Smarkfen has_daprefix = has_saprefix = B_FALSE; 40004235Smarkfen 40014235Smarkfen (void) memset(act_props, 0, sizeof (act_prop_t)); 40024235Smarkfen pstate = pattern; 40034235Smarkfen 40044235Smarkfen ret = 0; 40054235Smarkfen leftover = NULL; 40064235Smarkfen argindex = 0; 40074235Smarkfen cbuf_offset = 0; 40084235Smarkfen assert(shp == NULL && dhp == NULL); 40094235Smarkfen 40104235Smarkfen for (;;) { 40114235Smarkfen switch (pstate) { 40124235Smarkfen case pattern: 40134235Smarkfen { 40144235Smarkfen #ifdef DEBUG_HEAVY 40154235Smarkfen (void) printf("pattern\n"); 40164235Smarkfen #endif 40174235Smarkfen ret = parse_pattern_or_prop(fp, 40184235Smarkfen act_props->pattern, &leftover); 40194235Smarkfen if (ret == PARSE_EOF) { 40204235Smarkfen /* EOF reached */ 40215120Smarkfen return (PARSE_EOF); 40224235Smarkfen } 40234235Smarkfen if (ret != 0) { 40245120Smarkfen ret = -1; 40254235Smarkfen goto err; 40264235Smarkfen } 40274235Smarkfen pstate = action; 40284235Smarkfen break; 40294235Smarkfen } 40304235Smarkfen case action: 40314235Smarkfen { 40324235Smarkfen #ifdef DEBUG_HEAVY 40334235Smarkfen (void) printf("action\n"); 40344235Smarkfen #endif 40354235Smarkfen ret = parse_action(fp, 40364235Smarkfen &act_props->ap[ap_num].act, &leftover); 40374235Smarkfen if (ret != 0) { 40385120Smarkfen ret = -1; 40394235Smarkfen goto err; 40404235Smarkfen } 40414235Smarkfen 40424235Smarkfen /* 40434235Smarkfen * Validate action now itself so that we don't 40444235Smarkfen * proceed too much into the bad world. 40454235Smarkfen */ 40464235Smarkfen for (i = 0; action_table[i].string; i++) { 40474235Smarkfen if (strcmp(act_props->ap[ap_num].act, 40484235Smarkfen action_table[i].string) == 0) 40494235Smarkfen break; 40504235Smarkfen } 40514235Smarkfen 40524235Smarkfen if (action_table[i].tok_val == TOK_or) { 40534235Smarkfen /* hit an or, go again */ 40544235Smarkfen break; 40554235Smarkfen } 40564235Smarkfen 40574235Smarkfen if (action_table[i].string == NULL) { 40584235Smarkfen /* 40594235Smarkfen * If we never read a newline 40604235Smarkfen * character, we don't want 40614235Smarkfen * to print 0. 40624235Smarkfen */ 40635120Smarkfen warnx(gettext("(parsing one command) " 40644235Smarkfen "Invalid action on line %d: %s"), 40654235Smarkfen (linecount == 0) ? 1 : linecount, 40664235Smarkfen act_props->ap[ap_num].act); 40674235Smarkfen return (-1); 40684235Smarkfen } 40694235Smarkfen 40704235Smarkfen pstate = prop; 40714235Smarkfen break; 40724235Smarkfen } 40734235Smarkfen case prop: 40744235Smarkfen { 40754235Smarkfen #ifdef DEBUG_HEAVY 40764235Smarkfen (void) printf("prop\n"); 40774235Smarkfen #endif 40784235Smarkfen ret = parse_pattern_or_prop(fp, 40794235Smarkfen act_props->ap[ap_num].prop, &leftover); 40804235Smarkfen if (ret != 0) { 40815120Smarkfen if (ret == PARSE_EOF) { 40825120Smarkfen warnx(gettext("(parsing one command) " 40835120Smarkfen "Missing properties.")); 40845120Smarkfen } 40855120Smarkfen ret = -1; 40864235Smarkfen goto err; 40874235Smarkfen } 40884235Smarkfen 40894235Smarkfen if (leftover != NULL) { 40904235Smarkfen /* Accomodate spaces at the end */ 40914235Smarkfen while (*leftover != NULL) { 40925120Smarkfen if (*leftover == BACK_SLASH) { 40935120Smarkfen warnx(gettext("Invalid line " 40945120Smarkfen "continuation character.")); 40955120Smarkfen ret = -1; 40965120Smarkfen goto err; 40975120Smarkfen } 40984235Smarkfen if (*leftover == 'o') { 40994235Smarkfen leftover++; 41004235Smarkfen if (*leftover == 'r') { 41014235Smarkfen leftover++; 41024235Smarkfen ap_num++; 41034235Smarkfen pstate = action; 41044235Smarkfen goto again; 41054235Smarkfen } 41064235Smarkfen } 41074235Smarkfen if (!isspace(*leftover)) { 41084235Smarkfen ret = -1; 41094235Smarkfen goto err; 41104235Smarkfen } 41114235Smarkfen leftover++; 41124235Smarkfen } 41134235Smarkfen return (0); 41144235Smarkfen } 41154235Smarkfen ap_num++; 41164235Smarkfen if (ap_num > MAXARGS) 41174235Smarkfen return (0); 41184235Smarkfen pstate = action; /* or */ 41194235Smarkfen break; 41204235Smarkfen } /* case prop: */ 41214235Smarkfen } /* switch(pstate) */ 41224235Smarkfen 41234235Smarkfen again: 41245120Smarkfen if (ap_num > MAXARGS) { 41255120Smarkfen warnx(gettext("Too many actions.")); 41265120Smarkfen return (-1); 41275120Smarkfen } 41285120Smarkfen } /* for(;;) */ 41294235Smarkfen err: 41304235Smarkfen if (ret != 0) { 41314235Smarkfen /* 41324235Smarkfen * If we never read a newline character, we don't want 41334235Smarkfen * to print 0. 41344235Smarkfen */ 41354235Smarkfen warnx(gettext("Error before or at line %d"), 41364235Smarkfen (linecount == 0) ? 1 : linecount); 41374235Smarkfen } 41384235Smarkfen return (ret); 41394235Smarkfen } 41404235Smarkfen 41414235Smarkfen /* 41424235Smarkfen * convert an act_propts_t to an ips_conf_t 41434235Smarkfen */ 41444235Smarkfen 41454235Smarkfen static int 41464235Smarkfen form_ipsec_conf(act_prop_t *act_props, ips_conf_t *cptr) 41474235Smarkfen { 41484235Smarkfen int i, j, k; 41494235Smarkfen int tok_count = 0; 41504235Smarkfen struct protoent *pent; 41514235Smarkfen boolean_t saddr, daddr, ipsec_aalg, ipsec_ealg, ipsec_eaalg, dir; 4152*10372Sdanmcd@sun.com boolean_t old_style, new_style, auth_covered, is_no_alg; 41534235Smarkfen struct in_addr mask; 41544235Smarkfen int line_no; 41554235Smarkfen int ret; 41564235Smarkfen int ap_num = 0; 41574235Smarkfen int type, code, type_end, code_end; 41584235Smarkfen #ifdef DEBUG_HEAVY 41594235Smarkfen /* 41604235Smarkfen * pattern => act_props->pattern 41614235Smarkfen * action => act_props->ap[].act 41624235Smarkfen * properties => act_props->ap[].prop 41634235Smarkfen */ 41644235Smarkfen (void) printf("\npattern\n------------\n"); 41654235Smarkfen for (i = 0; act_props->pattern[i] != NULL; i++) 41664235Smarkfen (void) printf("%s\n", act_props->pattern[i]); 41674235Smarkfen (void) printf("apz\n----------\n"); 41684235Smarkfen for (j = 0; act_props->ap[j].act != NULL; j++) { 41694235Smarkfen 41704235Smarkfen (void) printf("act%d->%s\n", j, act_props->ap[j].act); 41714235Smarkfen for (i = 0; act_props->ap[j].prop[i] != NULL; i++) 41724235Smarkfen (void) printf("%dprop%d->%s\n", 41734235Smarkfen j, i, act_props->ap[j].prop[i]); 41744235Smarkfen } 41754235Smarkfen (void) printf("------------\n\n"); 41764235Smarkfen #endif 41774235Smarkfen 41784235Smarkfen (void) memset(cptr, 0, sizeof (ips_conf_t)); 41794235Smarkfen saddr = daddr = ipsec_aalg = ipsec_ealg = ipsec_eaalg = dir = B_FALSE; 4180*10372Sdanmcd@sun.com old_style = new_style = is_no_alg = B_FALSE; 41814235Smarkfen /* 41824235Smarkfen * Get the Pattern. NULL pattern is valid. 41834235Smarkfen */ 41844235Smarkfen for (i = 0, line_no = 0; act_props->pattern[i]; i++, line_no++) { 41854235Smarkfen for (j = 0; pattern_table[j].string; j++) { 41864235Smarkfen if (strcmp(act_props->pattern[i], 41874235Smarkfen pattern_table[j].string) == 0) 41884235Smarkfen break; 41894235Smarkfen } 41904235Smarkfen 41914235Smarkfen if (pattern_table[j].string == NULL) { 41924235Smarkfen /* 41934235Smarkfen * If we never read a newline character, we don't want 41944235Smarkfen * to print 0. 41954235Smarkfen */ 41964235Smarkfen warnx(gettext("Invalid pattern on line %d: %s"), 41974235Smarkfen (arg_indices[line_no] == 0) ? 1 : 41984235Smarkfen arg_indices[line_no], act_props->pattern[i]); 41994235Smarkfen return (-1); 42004235Smarkfen } 42014235Smarkfen 42024235Smarkfen cptr->patt_tok[tok_count++] = pattern_table[j].tok_val; 42034235Smarkfen 42044235Smarkfen switch (pattern_table[j].tok_val) { 42054235Smarkfen 42064235Smarkfen case TOK_dir: 42074235Smarkfen i++, line_no++; 42084235Smarkfen if (act_props->pattern[i] == NULL) { 42094235Smarkfen error_message(BAD_ERROR, 42104235Smarkfen IPSEC_CONF_IPSEC_DIR, line_no); 42114235Smarkfen return (-1); 42124235Smarkfen } 42134235Smarkfen 42144235Smarkfen if (strncmp(act_props->pattern[i], "in", 2) == 0) { 42154235Smarkfen cptr->ips_dir = SPD_RULE_FLAG_INBOUND; 42164235Smarkfen } else if (strncmp( 42174235Smarkfen act_props->pattern[i], "out", 3) == 0) { 42184235Smarkfen cptr->ips_dir = SPD_RULE_FLAG_OUTBOUND; 42194235Smarkfen } else if (strncmp( 42204235Smarkfen act_props->pattern[i], "both", 4) == 0) { 42214235Smarkfen if (old_style) { 42224235Smarkfen error_message(BAD_ERROR, 42234235Smarkfen IPSEC_CONF_IPSEC_DIR, line_no); 42244235Smarkfen return (-1); 42254235Smarkfen } 42264235Smarkfen new_style = B_TRUE; 42274235Smarkfen cptr->ips_dir = 42284235Smarkfen SPD_RULE_FLAG_OUTBOUND | 42294235Smarkfen SPD_RULE_FLAG_INBOUND; 42304235Smarkfen } else { 42314235Smarkfen error_message(BAD_ERROR, 42324235Smarkfen IPSEC_CONF_IPSEC_DIR, line_no); 42334235Smarkfen return (-1); 42344235Smarkfen } 42354235Smarkfen dir = B_TRUE; 42364235Smarkfen break; 42374235Smarkfen 42384235Smarkfen case TOK_local: 42394235Smarkfen if (old_style) { 42404235Smarkfen error_message(BAD_ERROR, 42414235Smarkfen IPSEC_CONF_SRC_ADDRESS, line_no); 42424235Smarkfen return (-1); 42434235Smarkfen } 42444235Smarkfen new_style = B_TRUE; 42454235Smarkfen 42464235Smarkfen if (saddr) { 42474235Smarkfen error_message(DUP_ERROR, 42484235Smarkfen IPSEC_CONF_SRC_ADDRESS, line_no); 42494235Smarkfen return (-1); 42504235Smarkfen } 42514235Smarkfen /* 42524235Smarkfen * Use this to detect duplicates rather 42534235Smarkfen * than 0 like other cases, because 0 for 42544235Smarkfen * address means INADDR_ANY. 42554235Smarkfen */ 42564235Smarkfen saddr = B_TRUE; 42574235Smarkfen cptr->has_saddr = 1; 42584235Smarkfen /* 42594235Smarkfen * Advance to the string containing 42604235Smarkfen * the address. 42614235Smarkfen */ 42624235Smarkfen i++, line_no++; 42634235Smarkfen if (act_props->pattern[i] == NULL) { 42644235Smarkfen error_message(BAD_ERROR, 42654235Smarkfen IPSEC_CONF_SRC_ADDRESS, line_no); 42664235Smarkfen return (-1); 42674235Smarkfen } 42684235Smarkfen if (parse_address(IPSEC_CONF_SRC_ADDRESS, 42694235Smarkfen act_props->pattern[i]) != 0) { 42704235Smarkfen error_message(BAD_ERROR, 42714235Smarkfen IPSEC_CONF_SRC_ADDRESS, line_no); 42724235Smarkfen return (-1); 42734235Smarkfen } 42744235Smarkfen if (!cptr->has_smask) 42754235Smarkfen cptr->has_smask = has_saprefix; 42764235Smarkfen 42774235Smarkfen break; 42784235Smarkfen case TOK_remote: 42794235Smarkfen if (old_style) { 42804235Smarkfen error_message(BAD_ERROR, 42814235Smarkfen IPSEC_CONF_DST_ADDRESS, line_no); 42824235Smarkfen return (-1); 42834235Smarkfen } 42844235Smarkfen new_style = B_TRUE; 42854235Smarkfen 42864235Smarkfen if (daddr) { 42874235Smarkfen error_message(DUP_ERROR, 42884235Smarkfen IPSEC_CONF_DST_ADDRESS, line_no); 42894235Smarkfen return (-1); 42904235Smarkfen } 42914235Smarkfen /* 42924235Smarkfen * Use this to detect duplicates rather 42934235Smarkfen * than 0 like other cases, because 0 for 42944235Smarkfen * address means INADDR_ANY. 42954235Smarkfen */ 42964235Smarkfen daddr = B_TRUE; 42974235Smarkfen cptr->has_daddr = 1; 42984235Smarkfen /* 42994235Smarkfen * Advance to the string containing 43004235Smarkfen * the address. 43014235Smarkfen */ 43024235Smarkfen i++, line_no++; 43034235Smarkfen if (act_props->pattern[i] == NULL) { 43044235Smarkfen error_message(BAD_ERROR, 43054235Smarkfen IPSEC_CONF_DST_ADDRESS, line_no); 43064235Smarkfen return (-1); 43074235Smarkfen } 43084235Smarkfen if (parse_address(IPSEC_CONF_DST_ADDRESS, 43094235Smarkfen act_props->pattern[i]) != 0) { 43104235Smarkfen error_message(BAD_ERROR, 43114235Smarkfen IPSEC_CONF_DST_ADDRESS, line_no); 43124235Smarkfen return (-1); 43134235Smarkfen } 43144235Smarkfen if (!cptr->has_dmask) 43154235Smarkfen cptr->has_dmask = has_daprefix; 43164235Smarkfen break; 43174235Smarkfen 43184235Smarkfen case TOK_saddr: 43194235Smarkfen if (new_style) { 43204235Smarkfen error_message(BAD_ERROR, 43214235Smarkfen IPSEC_CONF_SRC_ADDRESS, line_no); 43224235Smarkfen return (-1); 43234235Smarkfen } 43244235Smarkfen old_style = B_TRUE; 43254235Smarkfen 43264235Smarkfen if (saddr) { 43274235Smarkfen error_message(DUP_ERROR, 43284235Smarkfen IPSEC_CONF_SRC_ADDRESS, line_no); 43294235Smarkfen return (-1); 43304235Smarkfen } 43314235Smarkfen /* 43324235Smarkfen * Use this to detect duplicates rather 43334235Smarkfen * than 0 like other cases, because 0 for 43344235Smarkfen * address means INADDR_ANY. 43354235Smarkfen */ 43364235Smarkfen saddr = B_TRUE; 43374235Smarkfen cptr->has_saddr = 1; 43384235Smarkfen /* 43394235Smarkfen * Advance to the string containing 43404235Smarkfen * the address. 43414235Smarkfen */ 43424235Smarkfen i++, line_no++; 43434235Smarkfen if (act_props->pattern[i] == NULL) { 43444235Smarkfen error_message(BAD_ERROR, 43454235Smarkfen IPSEC_CONF_SRC_ADDRESS, line_no); 43464235Smarkfen return (-1); 43474235Smarkfen } 43484235Smarkfen 43494235Smarkfen if (parse_address(IPSEC_CONF_SRC_ADDRESS, 43504235Smarkfen act_props->pattern[i]) != 0) { 43514235Smarkfen error_message(BAD_ERROR, 43524235Smarkfen IPSEC_CONF_SRC_ADDRESS, line_no); 43534235Smarkfen return (-1); 43544235Smarkfen } 43554235Smarkfen /* shp or bhp? */ 43564235Smarkfen if (!cptr->has_smask) 43574235Smarkfen cptr->has_smask = has_saprefix; 43584235Smarkfen break; 43594235Smarkfen 43604235Smarkfen case TOK_daddr: 43614235Smarkfen if (new_style) { 43624235Smarkfen error_message(BAD_ERROR, 43634235Smarkfen IPSEC_CONF_DST_ADDRESS, line_no); 43644235Smarkfen return (-1); 43654235Smarkfen } 43664235Smarkfen old_style = B_TRUE; 43674235Smarkfen 43684235Smarkfen if (daddr) { 43694235Smarkfen error_message(DUP_ERROR, 43704235Smarkfen IPSEC_CONF_DST_ADDRESS, line_no); 43714235Smarkfen return (-1); 43724235Smarkfen } 43734235Smarkfen /* 43744235Smarkfen * Use this to detect duplicates rather 43754235Smarkfen * than 0 like other cases, because 0 for 43764235Smarkfen * address means INADDR_ANY. 43774235Smarkfen */ 43784235Smarkfen daddr = B_TRUE; 43794235Smarkfen cptr->has_daddr = 1; 43804235Smarkfen /* 43814235Smarkfen * Advance to the string containing 43824235Smarkfen * the address. 43834235Smarkfen */ 43844235Smarkfen i++, line_no++; 43854235Smarkfen if (act_props->pattern[i] == NULL) { 43864235Smarkfen error_message(BAD_ERROR, 43874235Smarkfen IPSEC_CONF_DST_ADDRESS, line_no); 43884235Smarkfen return (-1); 43894235Smarkfen } 43904235Smarkfen if (parse_address(IPSEC_CONF_DST_ADDRESS, 43914235Smarkfen act_props->pattern[i]) != 0) { 43924235Smarkfen error_message(BAD_ERROR, 43934235Smarkfen IPSEC_CONF_DST_ADDRESS, line_no); 43944235Smarkfen return (-1); 43954235Smarkfen } 43964235Smarkfen if (!cptr->has_dmask) 43974235Smarkfen cptr->has_dmask = has_daprefix; 43984235Smarkfen break; 43994235Smarkfen 44004235Smarkfen case TOK_sport: 44014235Smarkfen if (new_style) { 44024235Smarkfen error_message(BAD_ERROR, 44034235Smarkfen IPSEC_CONF_SRC_PORT, line_no); 44044235Smarkfen return (-1); 44054235Smarkfen } 44064235Smarkfen old_style = B_TRUE; 44074235Smarkfen 44084235Smarkfen if (cptr->ips_src_port_min != 0) { 44094235Smarkfen error_message(DUP_ERROR, IPSEC_CONF_SRC_PORT, 44104235Smarkfen line_no); 44114235Smarkfen return (-1); 44124235Smarkfen } 44134235Smarkfen i++, line_no++; 44144235Smarkfen if (act_props->pattern[i] == NULL) { 44154235Smarkfen error_message(BAD_ERROR, IPSEC_CONF_SRC_PORT, 44164235Smarkfen line_no); 44174235Smarkfen return (-1); 44184235Smarkfen } 44194235Smarkfen ret = parse_port(IPSEC_CONF_SRC_PORT, 44204235Smarkfen act_props->pattern[i], cptr); 44214235Smarkfen if (ret != 0) { 44224235Smarkfen error_message(BAD_ERROR, IPSEC_CONF_SRC_PORT, 44234235Smarkfen line_no); 44244235Smarkfen return (-1); 44254235Smarkfen } 44264235Smarkfen break; 44274235Smarkfen case TOK_dport: 44284235Smarkfen if (new_style) { 44294235Smarkfen error_message(BAD_ERROR, 44304235Smarkfen IPSEC_CONF_DST_PORT, line_no); 44314235Smarkfen return (-1); 44324235Smarkfen } 44334235Smarkfen old_style = B_TRUE; 44344235Smarkfen 44354235Smarkfen if (cptr->ips_dst_port_min != 0) { 44364235Smarkfen error_message(DUP_ERROR, IPSEC_CONF_DST_PORT, 44374235Smarkfen line_no); 44384235Smarkfen return (-1); 44394235Smarkfen } 44404235Smarkfen i++, line_no++; 44414235Smarkfen if (act_props->pattern[i] == NULL) { 44424235Smarkfen error_message(BAD_ERROR, IPSEC_CONF_DST_PORT, 44434235Smarkfen line_no); 44444235Smarkfen return (-1); 44454235Smarkfen } 44464235Smarkfen ret = parse_port(IPSEC_CONF_DST_PORT, 44474235Smarkfen act_props->pattern[i], 44484235Smarkfen cptr); 44494235Smarkfen if (ret != 0) { 44504235Smarkfen error_message(BAD_ERROR, IPSEC_CONF_DST_PORT, 44514235Smarkfen line_no); 44524235Smarkfen return (-1); 44534235Smarkfen } 44544235Smarkfen break; 44554235Smarkfen 44564235Smarkfen case TOK_lport: 44574235Smarkfen if (old_style) { 44584235Smarkfen error_message(BAD_ERROR, 44594235Smarkfen IPSEC_CONF_SRC_PORT, line_no); 44604235Smarkfen return (-1); 44614235Smarkfen } 44624235Smarkfen new_style = B_TRUE; 44634235Smarkfen 44644235Smarkfen if (cptr->ips_src_port_min != 0) { 44654235Smarkfen error_message(DUP_ERROR, IPSEC_CONF_SRC_PORT, 44664235Smarkfen line_no); 44674235Smarkfen return (-1); 44684235Smarkfen } 44694235Smarkfen i++, line_no++; 44704235Smarkfen if (act_props->pattern[i] == NULL) { 44714235Smarkfen error_message(BAD_ERROR, IPSEC_CONF_SRC_PORT, 44724235Smarkfen line_no); 44734235Smarkfen return (-1); 44744235Smarkfen } 44754235Smarkfen ret = parse_port(IPSEC_CONF_SRC_PORT, 44764235Smarkfen act_props->pattern[i], 44774235Smarkfen cptr); 44784235Smarkfen if (ret != 0) { 44794235Smarkfen error_message(BAD_ERROR, IPSEC_CONF_SRC_PORT, 44804235Smarkfen line_no); 44814235Smarkfen return (-1); 44824235Smarkfen } 44834235Smarkfen break; 44844235Smarkfen 44854235Smarkfen case TOK_rport: 44864235Smarkfen if (old_style) { 44874235Smarkfen error_message(BAD_ERROR, 44884235Smarkfen IPSEC_CONF_DST_PORT, line_no); 44894235Smarkfen return (-1); 44904235Smarkfen } 44914235Smarkfen new_style = B_TRUE; 44924235Smarkfen 44934235Smarkfen if (cptr->ips_dst_port_min != 0) { 44944235Smarkfen error_message(DUP_ERROR, IPSEC_CONF_DST_PORT, 44954235Smarkfen line_no); 44964235Smarkfen return (-1); 44974235Smarkfen } 44984235Smarkfen i++, line_no++; 44994235Smarkfen if (act_props->pattern[i] == NULL) { 45004235Smarkfen error_message(BAD_ERROR, IPSEC_CONF_DST_PORT, 45014235Smarkfen line_no); 45024235Smarkfen return (-1); 45034235Smarkfen } 45044235Smarkfen ret = parse_port(IPSEC_CONF_DST_PORT, 45054235Smarkfen act_props->pattern[i], 45064235Smarkfen cptr); 45074235Smarkfen if (ret != 0) { 45084235Smarkfen error_message(BAD_ERROR, IPSEC_CONF_DST_PORT, 45094235Smarkfen line_no); 45104235Smarkfen return (-1); 45114235Smarkfen } 45124235Smarkfen break; 45134235Smarkfen 45144235Smarkfen case TOK_smask: 45154235Smarkfen if (new_style) { 45164235Smarkfen error_message(BAD_ERROR, 45174235Smarkfen IPSEC_CONF_SRC_MASK, line_no); 45184235Smarkfen return (-1); 45194235Smarkfen } 45204235Smarkfen old_style = B_TRUE; 45214235Smarkfen cptr->has_smask = B_TRUE; 45224235Smarkfen 45234235Smarkfen IN6_V4MAPPED_TO_INADDR(&cptr->ips_src_mask_v6, &mask); 45244235Smarkfen if (mask.s_addr != 0) { 45254235Smarkfen error_message(DUP_ERROR, IPSEC_CONF_SRC_MASK, 45264235Smarkfen line_no); 45274235Smarkfen return (-1); 45284235Smarkfen } 45294235Smarkfen i++, line_no++; 45304235Smarkfen if (act_props->pattern[i] == NULL) { 45314235Smarkfen error_message(BAD_ERROR, IPSEC_CONF_SRC_MASK, 45324235Smarkfen line_no); 45334235Smarkfen return (-1); 45344235Smarkfen } 45354235Smarkfen ret = parse_mask(IPSEC_CONF_SRC_MASK, 45364235Smarkfen act_props->pattern[i], 45374235Smarkfen cptr); 45384235Smarkfen if (ret != 0) { 45394235Smarkfen error_message(BAD_ERROR, IPSEC_CONF_SRC_MASK, 45404235Smarkfen line_no); 45414235Smarkfen return (-1); 45424235Smarkfen } 45434235Smarkfen break; 45444235Smarkfen case TOK_dmask: 45454235Smarkfen if (new_style) { 45464235Smarkfen error_message(BAD_ERROR, 45474235Smarkfen IPSEC_CONF_DST_MASK, line_no); 45484235Smarkfen return (-1); 45494235Smarkfen } 45504235Smarkfen old_style = B_TRUE; 45514235Smarkfen cptr->has_dmask = B_TRUE; 45524235Smarkfen 45534235Smarkfen IN6_V4MAPPED_TO_INADDR(&cptr->ips_dst_mask_v6, &mask); 45544235Smarkfen if (mask.s_addr != 0) { 45554235Smarkfen error_message(DUP_ERROR, IPSEC_CONF_DST_MASK, 45564235Smarkfen line_no); 45574235Smarkfen return (-1); 45584235Smarkfen } 45594235Smarkfen i++, line_no++; 45604235Smarkfen if (act_props->pattern[i] == NULL) { 45614235Smarkfen error_message(BAD_ERROR, IPSEC_CONF_DST_MASK, 45624235Smarkfen line_no); 45634235Smarkfen return (-1); 45644235Smarkfen } 45654235Smarkfen ret = parse_mask(IPSEC_CONF_DST_MASK, 45664235Smarkfen act_props->pattern[i], 45674235Smarkfen cptr); 45684235Smarkfen if (ret != 0) { 45694235Smarkfen error_message(BAD_ERROR, IPSEC_CONF_DST_MASK, 45704235Smarkfen line_no); 45714235Smarkfen return (-1); 45724235Smarkfen } 45734235Smarkfen break; 45744235Smarkfen case TOK_ulp: 45754235Smarkfen if (cptr->ips_ulp_prot != 0) { 45764235Smarkfen error_message(DUP_ERROR, 45774235Smarkfen IPSEC_CONF_ULP, line_no); 45784235Smarkfen return (-1); 45794235Smarkfen } 45804235Smarkfen i++, line_no++; 45814235Smarkfen if (act_props->pattern[i] == NULL) { 45824235Smarkfen error_message(BAD_ERROR, 45834235Smarkfen IPSEC_CONF_ULP, line_no); 45844235Smarkfen return (-1); 45854235Smarkfen } 45864235Smarkfen pent = getprotobyname(act_props->pattern[i]); 45874235Smarkfen if (pent == NULL) { 45884235Smarkfen int ulp; 45894235Smarkfen ulp = parse_int(act_props->pattern[i]); 45904235Smarkfen if (ulp == -1) { 45914235Smarkfen error_message(BAD_ERROR, 45924235Smarkfen IPSEC_CONF_ULP, line_no); 45934235Smarkfen return (-1); 45944235Smarkfen } 45954235Smarkfen cptr->ips_ulp_prot = ulp; 45964235Smarkfen } else { 45974235Smarkfen cptr->ips_ulp_prot = pent->p_proto; 45984235Smarkfen } 45994235Smarkfen break; 46004235Smarkfen case TOK_type: 46014235Smarkfen if (cptr->has_type) { 46024235Smarkfen error_message(DUP_ERROR, 46034235Smarkfen IPSEC_CONF_ICMP_TYPE, line_no); 46044235Smarkfen return (-1); 46054235Smarkfen } 46064235Smarkfen 46074235Smarkfen i++, line_no++; 46084235Smarkfen type = parse_type_code(act_props->pattern[i], 46094235Smarkfen icmp_type_table); 46104235Smarkfen 46114235Smarkfen if (type > 65536 || type < 0) { 46124235Smarkfen error_message(BAD_ERROR, 46134235Smarkfen IPSEC_CONF_ICMP_TYPE, line_no); 46144235Smarkfen return (-1); 46154235Smarkfen } 46164235Smarkfen 46174235Smarkfen type_end = type / 256; 46184235Smarkfen type = type % 256; 46194235Smarkfen 46204235Smarkfen if (type_end < type) 46214235Smarkfen type_end = type; 46224235Smarkfen 46234235Smarkfen cptr->has_type = 1; 46244235Smarkfen cptr->ips_icmp_type = (uint8_t)type; 46254235Smarkfen cptr->ips_icmp_type_end = (uint8_t)type_end; 46264235Smarkfen break; 46274235Smarkfen case TOK_code: 46284235Smarkfen if (!cptr->has_type) { 46294235Smarkfen error_message(BAD_ERROR, 46304235Smarkfen IPSEC_CONF_ICMP_CODE, line_no); 46314235Smarkfen return (-1); 46324235Smarkfen } 46334235Smarkfen 46344235Smarkfen if (cptr->has_code) { 46354235Smarkfen error_message(DUP_ERROR, 46364235Smarkfen IPSEC_CONF_ICMP_CODE, line_no); 46374235Smarkfen return (-1); 46384235Smarkfen } 46394235Smarkfen 46404235Smarkfen i++, line_no++; 46414235Smarkfen 46424235Smarkfen code = parse_type_code(act_props->pattern[i], 46434235Smarkfen icmp_code_table); 46444235Smarkfen if (type > 65536 || type < 0) { 46454235Smarkfen error_message(BAD_ERROR, 46464235Smarkfen IPSEC_CONF_ICMP_CODE, line_no); 46474235Smarkfen return (-1); 46484235Smarkfen } 46494235Smarkfen code_end = code / 256; 46504235Smarkfen code = code % 256; 46514235Smarkfen 46524235Smarkfen if (code_end < code) 46534235Smarkfen code_end = code; 46544235Smarkfen 46554235Smarkfen cptr->has_code = 1; 46564235Smarkfen cptr->ips_icmp_code = (uint8_t)code; 46574235Smarkfen cptr->ips_icmp_code_end = (uint8_t)code_end; 46584235Smarkfen break; 46594235Smarkfen case TOK_tunnel: 46604235Smarkfen if (cptr->has_tunnel == 1) { 46614235Smarkfen error_message(BAD_ERROR, 46624235Smarkfen IPSEC_CONF_TUNNEL, line_no); 46634235Smarkfen return (-1); 46644235Smarkfen } 46654235Smarkfen i++, line_no++; 46664235Smarkfen if (act_props->pattern[i] == NULL) { 46674235Smarkfen error_message(BAD_ERROR, 46684235Smarkfen IPSEC_CONF_TUNNEL, line_no); 46694235Smarkfen return (-1); 46704235Smarkfen } 46714235Smarkfen 46724235Smarkfen if (strlcpy(tunif, act_props->pattern[i], 46734235Smarkfen TUNNAMEMAXLEN) >= TUNNAMEMAXLEN) { 46744235Smarkfen error_message(BAD_ERROR, 46754235Smarkfen IPSEC_CONF_TUNNEL, line_no); 46764235Smarkfen return (-1); 46774235Smarkfen } 46784235Smarkfen cptr->has_tunnel = 1; 46794235Smarkfen break; 46804235Smarkfen case TOK_negotiate: 46814235Smarkfen if (cptr->has_negotiate == 1) { 46824235Smarkfen error_message(BAD_ERROR, 46834235Smarkfen IPSEC_CONF_NEGOTIATE, line_no); 46844235Smarkfen return (-1); 46854235Smarkfen } 46864235Smarkfen i++, line_no++; 46874235Smarkfen if (act_props->pattern[i] == NULL) { 46884235Smarkfen error_message(BAD_ERROR, 46894235Smarkfen IPSEC_CONF_NEGOTIATE, line_no); 46904235Smarkfen return (-1); 46914235Smarkfen } 46924235Smarkfen 46934235Smarkfen if (strncmp(act_props->pattern[i], "tunnel", 6) == 0) { 46944235Smarkfen cptr->ips_tunnel = B_TRUE; 46954235Smarkfen } else if (strncmp( 46964235Smarkfen act_props->pattern[i], "transport", 9) != 0) { 46974235Smarkfen error_message(BAD_ERROR, 46984235Smarkfen IPSEC_CONF_NEGOTIATE, line_no); 46994235Smarkfen return (-1); 47004235Smarkfen } 47014235Smarkfen cptr->has_negotiate = 1; 47024235Smarkfen break; 47034235Smarkfen } 47044235Smarkfen 47054235Smarkfen } 47064235Smarkfen 47074235Smarkfen /* Sanity check that certain tokens occur together */ 47084235Smarkfen if (cptr->has_tunnel + cptr->has_negotiate == 1) { 47094235Smarkfen if (cptr->has_negotiate == 0) { 47104235Smarkfen error_message(REQ_ERROR, IPSEC_CONF_NEGOTIATE, line_no); 47114235Smarkfen } else { 47124235Smarkfen error_message(REQ_ERROR, IPSEC_CONF_TUNNEL, line_no); 47134235Smarkfen } 47144235Smarkfen errx(1, gettext( 47154235Smarkfen "tunnel and negotiate tokens must occur together")); 47164235Smarkfen return (-1); 47174235Smarkfen } 47184235Smarkfen 47194235Smarkfen /* 47204235Smarkfen * Get the actions. 47214235Smarkfen */ 47224235Smarkfen 47234235Smarkfen for (ap_num = 0; act_props->ap[ap_num].act != NULL; ap_num++) { 47244235Smarkfen ips_act_props_t *iap; 47254235Smarkfen 47264235Smarkfen if (ap_num > 0) { 47274235Smarkfen /* or's only with new style */ 47284235Smarkfen if (old_style) { 47294235Smarkfen (void) printf("%s\n", gettext( 47304235Smarkfen "or's only with new style")); 47314235Smarkfen return (-1); 47324235Smarkfen } 47334235Smarkfen new_style = B_TRUE; 47344235Smarkfen } 47354235Smarkfen 4736*10372Sdanmcd@sun.com ipsec_aalg = ipsec_ealg = ipsec_eaalg = auth_covered = B_FALSE; 47374235Smarkfen tok_count = 0; 47384235Smarkfen 47394235Smarkfen for (k = 0; action_table[k].string; k++) { 47404235Smarkfen if (strcmp(act_props->ap[ap_num].act, 47414235Smarkfen action_table[k].string) == 0) 47424235Smarkfen break; 47434235Smarkfen } 47444235Smarkfen /* 47454235Smarkfen * The following thing should never happen as 47464235Smarkfen * we have already tested for its validity in parse. 47474235Smarkfen */ 47484235Smarkfen if (action_table[k].string == NULL) { 47494235Smarkfen warnx(gettext("(form act)Invalid action on line " 47504235Smarkfen "%d: %s"), (arg_indices[line_no] == 0) ? 1 : 47514235Smarkfen arg_indices[line_no], 47524235Smarkfen act_props->ap[ap_num].act); 47534235Smarkfen warnx("%s", act_props->ap[ap_num].act); 47544235Smarkfen return (-1); 47554235Smarkfen } 47564235Smarkfen 47574235Smarkfen /* we have a good action alloc an iap */ 47584235Smarkfen iap = alloc_iap(cptr); 47594235Smarkfen 47604235Smarkfen iap->iap_action = action_table[k].value; 47614235Smarkfen iap->iap_act_tok = action_table[k].tok_val; 47624235Smarkfen 47634235Smarkfen switch (action_table[k].tok_val) { 47644235Smarkfen case TOK_apply: 47654235Smarkfen cptr->ips_dir = SPD_RULE_FLAG_OUTBOUND; 47664235Smarkfen break; 47674235Smarkfen case TOK_permit: 47684235Smarkfen cptr->ips_dir = SPD_RULE_FLAG_INBOUND; 47694235Smarkfen break; 47704235Smarkfen case TOK_ipsec: 47714235Smarkfen if (old_style) { 47724235Smarkfen /* Using saddr/daddr with ipsec action. */ 47734235Smarkfen if (!dir) { 47744235Smarkfen /* No direction specified */ 47754235Smarkfen error_message(REQ_ERROR, 47764235Smarkfen IPSEC_CONF_IPSEC_DIR, line_no); 47774235Smarkfen return (-1); 47784235Smarkfen } 47794235Smarkfen if (cptr->ips_dir == SPD_RULE_FLAG_INBOUND) 47804235Smarkfen /* 47814235Smarkfen * Need to swap addresses if 47824235Smarkfen * 'dir in' or translation to 47834235Smarkfen * laddr/raddr will be incorrect. 47844235Smarkfen */ 47854235Smarkfen cptr->swap = 1; 47864235Smarkfen } 47874235Smarkfen if (!dir) 47884235Smarkfen cptr->ips_dir = 47894235Smarkfen SPD_RULE_FLAG_INBOUND 47904235Smarkfen |SPD_RULE_FLAG_OUTBOUND; 47914235Smarkfen break; 47924235Smarkfen case TOK_bypass: 4793*10372Sdanmcd@sun.com case TOK_drop: 4794*10372Sdanmcd@sun.com is_no_alg = B_TRUE; 47954235Smarkfen break; 47964235Smarkfen } 47974235Smarkfen 47984235Smarkfen line_no++; 47994235Smarkfen /* 48004235Smarkfen * Get the properties. NULL properties is not valid. 48014235Smarkfen * Later checks will catch it. 48024235Smarkfen */ 48034235Smarkfen for (i = 0; act_props->ap[ap_num].prop[i]; i++, line_no++) { 48044235Smarkfen for (j = 0; property_table[j].string; j++) { 48054235Smarkfen if (strcmp(act_props->ap[ap_num].prop[i], 48064235Smarkfen property_table[j].string) == 0) { 48074235Smarkfen break; 48084235Smarkfen } 48094235Smarkfen } 48104235Smarkfen if (property_table[j].string == NULL) { 48114235Smarkfen warnx(gettext("Invalid properties on line " 48124235Smarkfen "%d: %s"), 48135120Smarkfen (arg_indices[line_no] == 0) ? 48144235Smarkfen 1 : arg_indices[line_no], 48154235Smarkfen act_props->ap[ap_num].prop[i]); 48164235Smarkfen return (-1); 48174235Smarkfen } 48184235Smarkfen 48194235Smarkfen iap->iap_attr_tok[tok_count++] 48204235Smarkfen = property_table[j].value; 48214235Smarkfen 48224235Smarkfen switch (property_table[j].value) { 48234235Smarkfen case SPD_ATTR_AH_AUTH: 48244235Smarkfen if (ipsec_aalg) { 48254235Smarkfen error_message(DUP_ERROR, 48264235Smarkfen IPSEC_CONF_IPSEC_AALGS, line_no); 48274235Smarkfen return (-1); 48284235Smarkfen } 48294235Smarkfen i++, line_no++; 48304235Smarkfen if (act_props->ap[ap_num].prop[i] == NULL) { 48314235Smarkfen error_message(BAD_ERROR, 48324235Smarkfen IPSEC_CONF_IPSEC_AALGS, line_no); 48334235Smarkfen return (-1); 48344235Smarkfen } 48354235Smarkfen ret = parse_ipsec_alg( 48364235Smarkfen act_props->ap[ap_num].prop[i], 48374235Smarkfen iap, SPD_ATTR_AH_AUTH); 48384235Smarkfen if (ret == -2) { 48394235Smarkfen /* "none" - ignore */ 48404235Smarkfen break; 48414235Smarkfen } 48424235Smarkfen if (ret != 0) { 48434235Smarkfen error_message(BAD_ERROR, 48444235Smarkfen IPSEC_CONF_IPSEC_AALGS, line_no); 48454235Smarkfen return (-1); 48464235Smarkfen } 48474235Smarkfen ipsec_aalg = B_TRUE; 4848*10372Sdanmcd@sun.com auth_covered = B_TRUE; 48494235Smarkfen break; 48504235Smarkfen case SPD_ATTR_ESP_ENCR: 48514235Smarkfen /* 48524235Smarkfen * If this option was not given 48534235Smarkfen * and encr_auth_algs was given, 48544235Smarkfen * we provide null-encryption. We do the 48554235Smarkfen * setting after we parse all the options. 48564235Smarkfen */ 48574235Smarkfen if (ipsec_ealg) { 48584235Smarkfen error_message(DUP_ERROR, 48594235Smarkfen IPSEC_CONF_IPSEC_EALGS, line_no); 48604235Smarkfen return (-1); 48614235Smarkfen } 48624235Smarkfen i++, line_no++; 48634235Smarkfen if (act_props->ap[ap_num].prop[i] == NULL) { 48644235Smarkfen error_message(BAD_ERROR, 48654235Smarkfen IPSEC_CONF_IPSEC_EALGS, line_no); 48664235Smarkfen return (-1); 48674235Smarkfen } 48684235Smarkfen ret = parse_ipsec_alg( 48694235Smarkfen act_props->ap[ap_num].prop[i], 48704235Smarkfen iap, SPD_ATTR_ESP_ENCR); 48714235Smarkfen if (ret == -2) { 48724235Smarkfen /* "none" - ignore */ 48734235Smarkfen break; 48744235Smarkfen } 48754235Smarkfen if (ret != 0) { 48764235Smarkfen error_message(BAD_ERROR, 48774235Smarkfen IPSEC_CONF_IPSEC_EALGS, line_no); 48784235Smarkfen return (-1); 48794235Smarkfen } 4880*10372Sdanmcd@sun.com /* 4881*10372Sdanmcd@sun.com * XXX FUTURE TODO -- set auth_covered here 4882*10372Sdanmcd@sun.com * if the encryption algorithm is self- 4883*10372Sdanmcd@sun.com * authenticating, e.g. AES-CCM/GCM. 4884*10372Sdanmcd@sun.com */ 48854235Smarkfen ipsec_ealg = B_TRUE; 48864235Smarkfen break; 48874235Smarkfen case SPD_ATTR_ESP_AUTH: 48884235Smarkfen /* 48894235Smarkfen * If this option was not given and encr_algs 48904235Smarkfen * option was given, we still pass a default 48914235Smarkfen * value in ipsc_esp_auth_algs. This is to 48924235Smarkfen * encourage the use of authentication with 48934235Smarkfen * ESP. 48944235Smarkfen */ 48954235Smarkfen if (ipsec_eaalg) { 48964235Smarkfen error_message(DUP_ERROR, 48974235Smarkfen IPSEC_CONF_IPSEC_EAALGS, line_no); 48984235Smarkfen return (-1); 48994235Smarkfen } 4900*10372Sdanmcd@sun.com /* 4901*10372Sdanmcd@sun.com * XXX FUTURE QUESTION -- error if 4902*10372Sdanmcd@sun.com * auth_covered and ipsec_aalg false 4903*10372Sdanmcd@sun.com * (e.g. AES-CCM/GCM)? 4904*10372Sdanmcd@sun.com */ 49054235Smarkfen i++, line_no++; 49064235Smarkfen if (act_props->ap[ap_num].prop[i] == NULL) { 49074235Smarkfen error_message(BAD_ERROR, 49084235Smarkfen IPSEC_CONF_IPSEC_EAALGS, line_no); 49094235Smarkfen return (-1); 49104235Smarkfen } 49114235Smarkfen ret = parse_ipsec_alg( 49124235Smarkfen act_props->ap[ap_num].prop[i], 49134235Smarkfen iap, SPD_ATTR_ESP_AUTH); 49144235Smarkfen if (ret == -2) { 49154235Smarkfen /* "none" - ignore */ 49164235Smarkfen break; 49174235Smarkfen } 49184235Smarkfen if (ret != 0) { 49194235Smarkfen error_message(BAD_ERROR, 49204235Smarkfen IPSEC_CONF_IPSEC_EAALGS, line_no); 49214235Smarkfen return (-1); 49224235Smarkfen } 49234235Smarkfen ipsec_eaalg = B_TRUE; 4924*10372Sdanmcd@sun.com auth_covered = B_TRUE; 49254235Smarkfen break; 49264235Smarkfen case IPS_SA: 49274235Smarkfen i++, line_no++; 49284235Smarkfen if (act_props->ap[ap_num].prop[i] == NULL) { 49294235Smarkfen error_message(BAD_ERROR, 49304235Smarkfen IPSEC_CONF_IPSEC_SA, line_no); 49314235Smarkfen return (-1); 49324235Smarkfen } 49334235Smarkfen 49344235Smarkfen if (strcmp(act_props->ap[ap_num].prop[i], 49354235Smarkfen "unique") == 0) { 49364235Smarkfen iap->iap_attr |= SPD_APPLY_UNIQUE; 49374235Smarkfen } else if (strcmp(act_props->ap[ap_num].prop[i], 49384235Smarkfen "shared") != 0) { 49394235Smarkfen /* "shared" is default. */ 49404235Smarkfen error_message(BAD_ERROR, 49414235Smarkfen IPSEC_CONF_IPSEC_SA, line_no); 49424235Smarkfen return (-1); 49434235Smarkfen } 49444235Smarkfen 49454235Smarkfen break; 49464235Smarkfen case IPS_DIR: 49474235Smarkfen if (dir) { 49484235Smarkfen error_message(DUP_ERROR, 49494235Smarkfen IPSEC_CONF_IPSEC_DIR, line_no); 49504235Smarkfen return (-1); 49514235Smarkfen } 49524235Smarkfen if (new_style) { 49534235Smarkfen error_message(BAD_ERROR, 49544235Smarkfen IPSEC_CONF_IPSEC_DIR, line_no); 49554235Smarkfen return (-1); 49564235Smarkfen } 49574235Smarkfen old_style = B_TRUE; 49584235Smarkfen dir = B_TRUE; 49594235Smarkfen i++, line_no++; 49604235Smarkfen if (act_props->ap[ap_num].prop[i] == NULL) { 49614235Smarkfen error_message(BAD_ERROR, 49624235Smarkfen IPSEC_CONF_IPSEC_DIR, line_no); 49634235Smarkfen return (-1); 49644235Smarkfen } 49654235Smarkfen if (strcmp(act_props->ap[ap_num].prop[i], 49664235Smarkfen "out") == 0) { 49674235Smarkfen cptr->ips_dir = SPD_RULE_FLAG_OUTBOUND; 49684235Smarkfen } else if (strcmp(act_props->ap[ap_num].prop[i], 49694235Smarkfen "in") == 0) { 49704235Smarkfen cptr->ips_dir = SPD_RULE_FLAG_INBOUND; 49714235Smarkfen } else { 49724235Smarkfen error_message(BAD_ERROR, 49735120Smarkfen IPSEC_CONF_IPSEC_DIR, line_no); 49744235Smarkfen return (-1); 49754235Smarkfen } 49764235Smarkfen if ((cptr->ips_dir & SPD_RULE_FLAG_INBOUND) && 49775120Smarkfen iap->iap_act_tok == TOK_apply) { 49784235Smarkfen warnx(gettext("Direction" 49794235Smarkfen " in conflict with action")); 49804235Smarkfen return (-1); 49814235Smarkfen } 49824235Smarkfen if ((cptr->ips_dir & SPD_RULE_FLAG_OUTBOUND) && 49835120Smarkfen iap->iap_act_tok == TOK_permit) { 49844235Smarkfen warnx(gettext("Direction" 49854235Smarkfen "in conflict with action")); 49864235Smarkfen return (-1); 49874235Smarkfen } 49884235Smarkfen 49894235Smarkfen break; 49904235Smarkfen } 49914235Smarkfen } 49924235Smarkfen 4993*10372Sdanmcd@sun.com /* Warn here about no authentication! */ 4994*10372Sdanmcd@sun.com if (!auth_covered && !is_no_alg) { 4995*10372Sdanmcd@sun.com warnx(gettext("DANGER: Rule on line %d " 4996*10372Sdanmcd@sun.com "has encryption with no authentication."), 4997*10372Sdanmcd@sun.com arg_indices[line_no] == 0 ? 1 : 4998*10372Sdanmcd@sun.com arg_indices[line_no]); 4999*10372Sdanmcd@sun.com } 5000*10372Sdanmcd@sun.com 50014235Smarkfen if (!ipsec_ealg && ipsec_eaalg) { 50024235Smarkfen /* 50034235Smarkfen * If the user has specified the auth alg to be used 50044235Smarkfen * with encryption and did not provide a encryption 50054235Smarkfen * algorithm, provide null encryption. 50064235Smarkfen */ 50074235Smarkfen iap->iap_eencr.alg_id = SADB_EALG_NULL; 50084235Smarkfen ipsec_ealg = B_TRUE; 50094235Smarkfen } 50104235Smarkfen 50114235Smarkfen /* Set the level of IPSEC protection we want */ 50124235Smarkfen if (ipsec_aalg && (ipsec_ealg || ipsec_eaalg)) { 50134235Smarkfen iap->iap_attr |= SPD_APPLY_AH|SPD_APPLY_ESP; 50144235Smarkfen } else if (ipsec_aalg) { 50154235Smarkfen iap->iap_attr |= SPD_APPLY_AH; 50164235Smarkfen } else if (ipsec_ealg || ipsec_eaalg) { 50174235Smarkfen iap->iap_attr |= SPD_APPLY_ESP; 50184235Smarkfen } 50194235Smarkfen 50204235Smarkfen /* convert src/dst to local/remote */ 50214235Smarkfen if (!new_style) { 50224235Smarkfen switch (cptr->ips_acts->iap_act_tok) { 50234235Smarkfen case TOK_apply: 50244235Smarkfen /* outbound */ 50254235Smarkfen /* src=local, dst=remote */ 50264235Smarkfen /* this is ok. */ 50274235Smarkfen break; 50284235Smarkfen 50294235Smarkfen case TOK_permit: 50304235Smarkfen /* inbound */ 50314235Smarkfen /* src=remote, dst=local */ 50324235Smarkfen /* switch */ 50334235Smarkfen cptr->swap = 1; 50344235Smarkfen break; 50354235Smarkfen case TOK_bypass: 50364235Smarkfen case TOK_drop: 50374235Smarkfen /* check the direction for what to do */ 50384235Smarkfen if (cptr->ips_dir == SPD_RULE_FLAG_INBOUND) 50394235Smarkfen cptr->swap = 1; 50404235Smarkfen break; 50414235Smarkfen default: 50424235Smarkfen break; 50434235Smarkfen } 50444235Smarkfen } 50454235Smarkfen /* Validate the properties */ 50464235Smarkfen if (ret = validate_properties(iap, dir, 50474235Smarkfen (ipsec_aalg || ipsec_ealg || ipsec_eaalg))) { 50484235Smarkfen return (ret); 50494235Smarkfen } 50504235Smarkfen } 50514235Smarkfen 50524235Smarkfen return (0); 50534235Smarkfen 50544235Smarkfen } 50554235Smarkfen 50564235Smarkfen static int 50574235Smarkfen print_cmd_buf(FILE *fp, int error) 50584235Smarkfen { 50594235Smarkfen *(cbuf + cbuf_offset) = '\0'; 50604235Smarkfen 50614235Smarkfen if (fp == stderr) { 50624235Smarkfen if (error != EEXIST) { 50634235Smarkfen warnx(gettext("Malformed command (fatal):\n%s"), cbuf); 50644235Smarkfen return (0); 50654235Smarkfen } 50664235Smarkfen if (ipsecconf_qflag) { 50674235Smarkfen return (0); 50684235Smarkfen } 50694235Smarkfen warnx(gettext("Duplicate policy entry (ignored):\n%s"), cbuf); 50704235Smarkfen } else { 50714235Smarkfen if (fprintf(fp, "%s", cbuf) == -1) { 50724235Smarkfen warn("fprintf"); 50734235Smarkfen return (-1); 50744235Smarkfen } 50754235Smarkfen } 50764235Smarkfen 50774235Smarkfen return (0); 50784235Smarkfen } 50794235Smarkfen 50804235Smarkfen #ifdef DEBUG 50814235Smarkfen 50824235Smarkfen static uchar_t * 50834235Smarkfen addr_ptr(int isv4, struct in6_addr *addr6, struct in_addr *addr4) 50844235Smarkfen { 50854235Smarkfen if (isv4) { 50864235Smarkfen IN6_V4MAPPED_TO_INADDR(addr6, addr4); 50874235Smarkfen return ((uchar_t *)&addr4->s_addr); 50884235Smarkfen } else { 50894235Smarkfen return ((uchar_t *)&addr6->s6_addr); 50904235Smarkfen } 50914235Smarkfen } 50924235Smarkfen 50934235Smarkfen static void 50944235Smarkfen dump_algreq(const char *tag, algreq_t *alg) 50954235Smarkfen { 50964235Smarkfen (void) printf("%s algid %d, bits %d..%d\n", 50974235Smarkfen tag, alg->alg_id, alg->alg_minbits, alg->alg_maxbits); 50984235Smarkfen } 50994235Smarkfen 51004235Smarkfen static void 51014235Smarkfen dump_conf(ips_conf_t *conf) 51024235Smarkfen { 51034235Smarkfen boolean_t isv4 = conf->ips_isv4; 51044235Smarkfen struct in_addr addr; 51054235Smarkfen char buf[INET6_ADDRSTRLEN]; 51064235Smarkfen int af; 51074235Smarkfen ips_act_props_t *iap = conf->ips_acts; 51084235Smarkfen 51094235Smarkfen af = isv4 ? AF_INET : AF_INET6; 51104235Smarkfen 51114235Smarkfen (void) printf("Source Addr is %s\n", 51124235Smarkfen inet_ntop(af, addr_ptr(isv4, &conf->ips_src_addr_v6, &addr), 51135120Smarkfen buf, INET6_ADDRSTRLEN)); 51144235Smarkfen 51154235Smarkfen (void) printf("Dest Addr is %s\n", 51164235Smarkfen inet_ntop(af, addr_ptr(isv4, &conf->ips_dst_addr_v6, &addr), 51175120Smarkfen buf, INET6_ADDRSTRLEN)); 51184235Smarkfen 51194235Smarkfen (void) printf("Source Mask is %s\n", 51204235Smarkfen inet_ntop(af, addr_ptr(isv4, &conf->ips_src_mask_v6, &addr), 51215120Smarkfen buf, INET6_ADDRSTRLEN)); 51224235Smarkfen 51234235Smarkfen (void) printf("Dest Mask is %s\n", 51244235Smarkfen inet_ntop(af, addr_ptr(isv4, &conf->ips_dst_mask_v6, &addr), 51255120Smarkfen buf, INET6_ADDRSTRLEN)); 51264235Smarkfen 51274235Smarkfen (void) printf("Source port %d\n", ntohs(conf->ips_src_port_min)); 51284235Smarkfen (void) printf("Dest port %d\n", ntohs(conf->ips_dst_port_min)); 51294235Smarkfen (void) printf("ULP %d\n", conf->ips_ulp_prot); 51304235Smarkfen 51314235Smarkfen (void) printf("ICMP type %d-%d code %d-%d", conf->ips_icmp_type, 51324235Smarkfen conf->ips_icmp_type_end, 51334235Smarkfen conf->ips_icmp_code, 51344235Smarkfen conf->ips_icmp_code_end); 51354235Smarkfen 51364235Smarkfen while (iap != NULL) { 51374235Smarkfen (void) printf("------------------------------------\n"); 51384235Smarkfen (void) printf("IPsec act is %d\n", iap->iap_action); 51394235Smarkfen (void) printf("IPsec attr is %d\n", iap->iap_attr); 51404235Smarkfen dump_algreq("AH authentication", &iap->iap_aauth); 51414235Smarkfen dump_algreq("ESP authentication", &iap->iap_eauth); 51424235Smarkfen dump_algreq("ESP encryption", &iap->iap_eencr); 51434235Smarkfen (void) printf("------------------------------------\n"); 51444235Smarkfen iap = iap->iap_next; 51454235Smarkfen } 51464235Smarkfen 51474235Smarkfen (void) fflush(stdout); 51484235Smarkfen } 51494235Smarkfen #endif /* DEBUG */ 51504235Smarkfen 51514235Smarkfen 51524235Smarkfen static int 51534235Smarkfen ipsec_conf_add(boolean_t just_check, boolean_t smf_managed) 51544235Smarkfen { 51554235Smarkfen act_prop_t *act_props = malloc(sizeof (act_prop_t)); 51564235Smarkfen ips_conf_t conf; 51574235Smarkfen FILE *fp, *policy_fp; 51584235Smarkfen int ret, flushret, i, j, diag, num_rules, good_rules; 51594235Smarkfen char *warning = gettext( 51605120Smarkfen "\tWARNING : New policy entries that are being added may\n " 51615120Smarkfen "\taffect the existing connections. Existing connections\n" 51625120Smarkfen "\tthat are not subjected to policy constraints, may be\n" 51635120Smarkfen "\tsubjected to policy constraints because of the new\n" 51645120Smarkfen "\tpolicy. This can disrupt the communication of the\n" 51655120Smarkfen "\texisting connections.\n\n"); 51664235Smarkfen 51674235Smarkfen boolean_t first_time = B_TRUE; 51684235Smarkfen num_rules = 0; 51694235Smarkfen good_rules = 0; 51704235Smarkfen 51714235Smarkfen if (act_props == NULL) { 51724235Smarkfen warn(gettext("memory")); 51734235Smarkfen return (-1); 51744235Smarkfen } 51754235Smarkfen 51764235Smarkfen if (strcmp(filename, "-") == 0) 51774235Smarkfen fp = stdin; 51784235Smarkfen else 51794235Smarkfen fp = fopen(filename, "r"); 51804235Smarkfen 51814235Smarkfen /* 51824235Smarkfen * Treat the non-existence of a policy file as a special 51834235Smarkfen * case when ipsecconf is being managed by smf(5). 51844235Smarkfen * The assumption is the administrator has not yet 51854235Smarkfen * created a policy file, this should not force the service 51864235Smarkfen * into maintenance mode. 51874235Smarkfen */ 51884235Smarkfen 51894235Smarkfen if (fp == NULL) { 51904235Smarkfen if (smf_managed) { 51914235Smarkfen (void) fprintf(stdout, gettext( 51924235Smarkfen "Policy configuration file (%s) does not exist.\n" 51934235Smarkfen "IPsec policy not configured.\n"), filename); 51944235Smarkfen return (0); 51954235Smarkfen } 51964235Smarkfen warn(gettext("%s : Policy config file cannot be opened"), 51974235Smarkfen filename); 51984235Smarkfen usage(); 51994235Smarkfen return (-1); 52004235Smarkfen } 52014235Smarkfen /* 52024235Smarkfen * This will create the file if it does not exist. 52034235Smarkfen * Make sure the umask is right. 52044235Smarkfen */ 52054235Smarkfen (void) umask(0022); 52064235Smarkfen policy_fp = fopen(POLICY_CONF_FILE, "a"); 52074235Smarkfen if (policy_fp == NULL) { 52084235Smarkfen warn(gettext("%s cannot be opened"), POLICY_CONF_FILE); 52094235Smarkfen return (-1); 52104235Smarkfen } 52114235Smarkfen 52124235Smarkfen /* 52134235Smarkfen * Pattern, action, and properties are allocated in 52144235Smarkfen * parse_pattern_or_prop and in parse_action (called by 52154235Smarkfen * parse_one) as we parse arguments. 52164235Smarkfen */ 52175120Smarkfen while ((ret = parse_one(fp, act_props)) != PARSE_EOF) { 52185120Smarkfen num_rules++; 52195120Smarkfen if (ret != 0) { 52205120Smarkfen (void) print_cmd_buf(stderr, NOERROR); 52215120Smarkfen continue; 52225120Smarkfen } 52234235Smarkfen 52244235Smarkfen /* 52254235Smarkfen * If there is no action and parse returned success, 52264235Smarkfen * it means that there is nothing to add. 52274235Smarkfen */ 52284235Smarkfen if (act_props->pattern[0] == NULL && 52294235Smarkfen act_props->ap[0].act == NULL) 52304235Smarkfen break; 52314235Smarkfen 52324235Smarkfen ret = form_ipsec_conf(act_props, &conf); 52334235Smarkfen if (ret != 0) { 52344235Smarkfen warnx(gettext("form_ipsec_conf error")); 52354235Smarkfen (void) print_cmd_buf(stderr, NOERROR); 52364475Spwernau /* Reset globals before trying the next rule. */ 52374475Spwernau if (shp != NULL) { 52384475Spwernau freehostent(shp); 52394475Spwernau shp = NULL; 52404475Spwernau } 52414475Spwernau if (dhp != NULL) { 52424475Spwernau freehostent(dhp); 52434475Spwernau dhp = NULL; 52444475Spwernau } 52454475Spwernau splen = 0; 52464475Spwernau dplen = 0; 52474235Smarkfen continue; 52484235Smarkfen } 52494235Smarkfen 52504235Smarkfen good_rules++; 52514235Smarkfen 52524235Smarkfen if (first_time) { 52534235Smarkfen /* 52544235Smarkfen * Time to assume that there are valid policy entries. 52554235Smarkfen * If the IPsec kernel modules are not loaded this 52564235Smarkfen * will load them now. 52574235Smarkfen */ 52584235Smarkfen first_time = B_FALSE; 52594235Smarkfen fetch_algorithms(); 52604235Smarkfen ipsec_conf_admin(SPD_CLONE); 52614235Smarkfen } 52624235Smarkfen 52634235Smarkfen /* 52644235Smarkfen * shp, dhp, splen, and dplen are globals set by 52654235Smarkfen * form_ipsec_conf() while parsing the addresses. 52664235Smarkfen */ 52674235Smarkfen if (shp == NULL && dhp == NULL) { 52684235Smarkfen switch (do_port_adds(&conf)) { 52694235Smarkfen case 0: 52704235Smarkfen /* no error */ 52714235Smarkfen break; 52724235Smarkfen case EEXIST: 52734235Smarkfen /* duplicate entries, continue adds */ 52744235Smarkfen (void) print_cmd_buf(stderr, EEXIST); 52754235Smarkfen goto next; 52764235Smarkfen default: 52774235Smarkfen /* other error, bail */ 52784235Smarkfen ret = -1; 52794235Smarkfen goto bail; 52804235Smarkfen } 52814235Smarkfen } else { 52824235Smarkfen ret = do_address_adds(&conf, &diag); 52834235Smarkfen switch (ret) { 52844235Smarkfen case 0: 52854235Smarkfen /* no error. */ 52864235Smarkfen break; 52874235Smarkfen case EEXIST: 52884235Smarkfen (void) print_cmd_buf(stderr, EEXIST); 52894235Smarkfen goto next; 52904235Smarkfen case EBUSY: 52914235Smarkfen warnx(gettext( 52925120Smarkfen "Can't set mask and /NN prefix.")); 52934235Smarkfen ret = -1; 52944235Smarkfen break; 52954235Smarkfen case ENOENT: 52964235Smarkfen warnx(gettext("Cannot find tunnel " 52974235Smarkfen "interface %s."), interface_name); 52984235Smarkfen ret = -1; 52994235Smarkfen break; 53004235Smarkfen case EINVAL: 53014235Smarkfen /* 53024235Smarkfen * PF_POLICY didn't like what we sent. We 53034235Smarkfen * can't check all input up here, but we 53044235Smarkfen * do in-kernel. 53054235Smarkfen */ 53064235Smarkfen warnx(gettext("PF_POLICY invalid input:\n\t%s"), 53074235Smarkfen spdsock_diag(diag)); 53084235Smarkfen break; 53094235Smarkfen case EOPNOTSUPP: 53104235Smarkfen warnx(gettext("Can't set /NN" 53115120Smarkfen " prefix on multi-host name.")); 53124235Smarkfen ret = -1; 53134235Smarkfen break; 53144235Smarkfen case ERANGE: 53154235Smarkfen warnx(gettext("/NN prefix is too big!")); 53164235Smarkfen ret = -1; 53174235Smarkfen break; 53184235Smarkfen case ESRCH: 53194235Smarkfen warnx(gettext("No matching IPv4 or " 53205120Smarkfen "IPv6 saddr/daddr pairs")); 53214235Smarkfen ret = -1; 53224235Smarkfen break; 53234235Smarkfen default: 53244235Smarkfen /* Should never get here. */ 53254235Smarkfen errno = ret; 53264235Smarkfen warn(gettext("Misc. error")); 53274235Smarkfen ret = -1; 53284235Smarkfen } 53294235Smarkfen if (ret == -1) 53304235Smarkfen goto bail; 53314235Smarkfen } 53324235Smarkfen 53334235Smarkfen /* 53344235Smarkfen * Go ahead and add policy entries to config file. 53354235Smarkfen * The # should help re-using the ipsecpolicy.conf 53364235Smarkfen * for input again as # will be treated as comment. 53374235Smarkfen */ 53384235Smarkfen if (fprintf(policy_fp, "%s %lld \n", INDEX_TAG, 53394235Smarkfen conf.ips_policy_index) == -1) { 53404235Smarkfen warn("fprintf"); 53414235Smarkfen warnx(gettext("Addition incomplete, Please " 53424235Smarkfen "flush all the entries and re-configure :")); 53434235Smarkfen reconfigure(); 53444235Smarkfen ret = -1; 53454235Smarkfen break; 53464235Smarkfen } 53474235Smarkfen if (print_cmd_buf(policy_fp, NOERROR) == -1) { 53484235Smarkfen warnx(gettext("Addition incomplete. Please " 53494235Smarkfen "flush all the entries and re-configure :")); 53504235Smarkfen reconfigure(); 53514235Smarkfen ret = -1; 53524235Smarkfen break; 53534235Smarkfen } 53544235Smarkfen /* 53554235Smarkfen * We add one newline by default to separate out the 53564235Smarkfen * entries. If the last character is not a newline, we 53574235Smarkfen * insert a newline for free. This makes sure that all 53584235Smarkfen * entries look consistent in the file. 53594235Smarkfen */ 53604235Smarkfen if (*(cbuf + cbuf_offset - 1) == '\n') { 53614235Smarkfen if (fprintf(policy_fp, "\n") == -1) { 53624235Smarkfen warn("fprintf"); 53634235Smarkfen warnx(gettext("Addition incomplete. " 53644235Smarkfen "Please flush all the entries and " 53654235Smarkfen "re-configure :")); 53664235Smarkfen reconfigure(); 53674235Smarkfen ret = -1; 53684235Smarkfen break; 53694235Smarkfen } 53704235Smarkfen } else { 53714235Smarkfen if (fprintf(policy_fp, "\n\n") == -1) { 53724235Smarkfen warn("fprintf"); 53734235Smarkfen warnx(gettext("Addition incomplete. " 53744235Smarkfen "Please flush all the entries and " 53754235Smarkfen "re-configure :")); 53764235Smarkfen reconfigure(); 53774235Smarkfen ret = -1; 53784235Smarkfen break; 53794235Smarkfen } 53804235Smarkfen } 53814235Smarkfen next: 53824235Smarkfen /* 53834235Smarkfen * Make sure this gets to the disk before 53844235Smarkfen * we parse the next entry. 53854235Smarkfen */ 53864235Smarkfen (void) fflush(policy_fp); 53874235Smarkfen for (i = 0; act_props->pattern[i] != NULL; i++) 53884235Smarkfen free(act_props->pattern[i]); 53894235Smarkfen for (j = 0; act_props->ap[j].act != NULL; j++) { 53904235Smarkfen free(act_props->ap[j].act); 53914235Smarkfen for (i = 0; act_props->ap[j].prop[i] != NULL; i++) 53924235Smarkfen free(act_props->ap[j].prop[i]); 53934235Smarkfen } 53944235Smarkfen } 53955120Smarkfen if (ret == PARSE_EOF) 53965120Smarkfen ret = 0; /* Not an error */ 53974235Smarkfen bail: 53984235Smarkfen if (ret == -1) { 53994235Smarkfen (void) print_cmd_buf(stderr, EINVAL); 54004235Smarkfen for (i = 0; act_props->pattern[i] != NULL; i++) 54014235Smarkfen free(act_props->pattern[i]); 54024235Smarkfen for (j = 0; act_props->ap[j].act != NULL; j++) { 54034235Smarkfen free(act_props->ap[j].act); 54044235Smarkfen for (i = 0; act_props->ap[j].prop[i] != NULL; i++) 54054235Smarkfen free(act_props->ap[j].prop[i]); 54064235Smarkfen } 54074235Smarkfen } 54084235Smarkfen #ifdef DEBUG_HEAVY 54094235Smarkfen (void) printf("ipsec_conf_add: ret val = %d\n", ret); 54104235Smarkfen (void) fflush(stdout); 54114235Smarkfen #endif 54125120Smarkfen if (num_rules == 0 && ret == 0) { 54134475Spwernau nuke_adds(); 54144235Smarkfen (void) restore_all_signals(); 54154235Smarkfen (void) unlock(lfd); 54164235Smarkfen EXIT_OK("Policy file does not contain any valid rules."); 54174235Smarkfen } 54184235Smarkfen if (num_rules != good_rules) { 54194235Smarkfen /* This is an error */ 54204475Spwernau nuke_adds(); 54214235Smarkfen (void) restore_all_signals(); 54224235Smarkfen (void) unlock(lfd); 54234235Smarkfen EXIT_BADCONFIG2("%d policy rule(s) contained errors.", 54244235Smarkfen num_rules - good_rules); 54254235Smarkfen } 54264235Smarkfen /* looks good, flip it in */ 54274235Smarkfen if (ret == 0 && !just_check) { 54284235Smarkfen if (!ipsecconf_qflag) { 54294235Smarkfen (void) printf("%s", warning); 54304235Smarkfen } 54315120Smarkfen if (smf_managed) 54325120Smarkfen warnx(gettext("%d policy rules added."), good_rules); 54334235Smarkfen ipsec_conf_admin(SPD_FLIP); 54344235Smarkfen } else { 54354235Smarkfen nuke_adds(); 54364235Smarkfen if (just_check) { 54375120Smarkfen (void) fprintf(stdout, gettext("IPsec configuration " 54385120Smarkfen "does not contain any errors.\n")); 54394235Smarkfen (void) fprintf(stdout, gettext( 54404235Smarkfen "IPsec policy was not modified.\n")); 54414235Smarkfen (void) fflush(stdout); 54424235Smarkfen } 54434235Smarkfen } 54444235Smarkfen flushret = ipsec_conf_flush(SPD_STANDBY); 54454235Smarkfen if (flushret != 0) 54464235Smarkfen return (flushret); 54474235Smarkfen return (ret); 54484235Smarkfen } 54494235Smarkfen 54504235Smarkfen 54514235Smarkfen static int 54524235Smarkfen ipsec_conf_sub() 54534235Smarkfen { 54544235Smarkfen act_prop_t *act_props = malloc(sizeof (act_prop_t)); 54554235Smarkfen FILE *remove_fp, *policy_fp; 54564235Smarkfen char rbuf[MAXLEN], pbuf[MAXLEN], /* remove buffer, and policy buffer */ 54574235Smarkfen *warning = gettext( 54585120Smarkfen "\tWARNING: Policy entries that are being removed may\n" 54595120Smarkfen "\taffect the existing connections. Existing connections\n" 54605120Smarkfen "\tthat are subjected to policy constraints may no longer\n" 54615120Smarkfen "\tbe subjected to policy contraints because of its\n" 54625120Smarkfen "\tremoval. This can compromise security, and disrupt\n" 54635120Smarkfen "\tthe communication of the existing connection.\n" 54645120Smarkfen "\tConnections that are latched will remain unaffected\n" 54655120Smarkfen "\tuntil they close.\n"); 54664235Smarkfen int ret = 0; 54674235Smarkfen int index_len, pindex = 0; /* init value in case of pfile error */ 54684235Smarkfen 54694235Smarkfen if (act_props == NULL) { 54704235Smarkfen warn(gettext("memory")); 54714235Smarkfen return (-1); 54724235Smarkfen } 54734235Smarkfen 54744235Smarkfen /* clone into standby DB */ 54754235Smarkfen (void) ipsec_conf_admin(SPD_CLONE); 54764235Smarkfen 54774235Smarkfen if (strcmp(filename, "-") == 0) 54784235Smarkfen remove_fp = stdin; 54794235Smarkfen else 54804235Smarkfen remove_fp = fopen(filename, "r"); 54814235Smarkfen 54824235Smarkfen if (remove_fp == NULL) { 54834235Smarkfen warn(gettext("%s : Input file cannot be opened"), filename); 54844235Smarkfen usage(); 54854235Smarkfen free(act_props); 54864235Smarkfen return (-1); 54874235Smarkfen } 54884235Smarkfen 54894235Smarkfen /* open policy file so we can locate the correct policy */ 54904235Smarkfen (void) umask(0022); /* in case it gets created! */ 54914235Smarkfen policy_fp = fopen(POLICY_CONF_FILE, "r+"); 54924235Smarkfen if (policy_fp == NULL) { 54934235Smarkfen warn(gettext("%s cannot be opened"), POLICY_CONF_FILE); 54944235Smarkfen (void) fclose(remove_fp); 54954235Smarkfen free(act_props); 54964235Smarkfen return (-1); 54974235Smarkfen } 54984235Smarkfen 54994235Smarkfen /* don't print the warning if we're in q[uiet] mode */ 55004235Smarkfen if (!ipsecconf_qflag) 55014235Smarkfen (void) printf("%s", warning); 55024235Smarkfen 55034235Smarkfen /* this bit is done primarily so we can read what we write */ 55044235Smarkfen index_len = strlen(INDEX_TAG); 55054235Smarkfen 55064235Smarkfen /* 55074235Smarkfen * We want to look for the policy in rbuf in the policy file. 55084235Smarkfen * Go through the list of policies to remove, locating each one. 55094235Smarkfen */ 55104235Smarkfen while (fgets(rbuf, MAXLEN, remove_fp) != NULL) { 55114235Smarkfen char *buf; 55124235Smarkfen int offset, prev_offset, prev_prev_offset, nlines; 55134235Smarkfen fpos_t ipos; 55144235Smarkfen int pbuf_len = 0; 55154235Smarkfen char *tmp; 55164235Smarkfen /* skip blanks here (so we don't need to do it below)! */ 55175120Smarkfen for (tmp = rbuf; (*tmp != '\0') && isspace(*tmp); ) 55185120Smarkfen tmp++; 55195120Smarkfen 55204235Smarkfen if (*tmp == '\0') 55215120Smarkfen continue; /* while(); */ 55224235Smarkfen 55234235Smarkfen /* skip the INDEX_TAG lines in the remove buffer */ 55244235Smarkfen if (strncasecmp(rbuf, INDEX_TAG, index_len) == 0) 55254235Smarkfen continue; 55264235Smarkfen 55274235Smarkfen /* skip commented lines */ 55284235Smarkfen if (*tmp == '#') 55295120Smarkfen continue; /* while(); */ 55304235Smarkfen 55314235Smarkfen /* 55324235Smarkfen * We start by presuming only good policies are in the pfile, 55334235Smarkfen * and so only good policies from the rfile will match them. 55344235Smarkfen * ipsec_conf_del ensures this later by calling parse_one() on 55354235Smarkfen * pfile before it deletes the entry. 55364235Smarkfen */ 55374235Smarkfen for (offset = prev_offset = prev_prev_offset = 0; 55384235Smarkfen fgets(pbuf, MAXLEN, policy_fp) != NULL; 55394235Smarkfen offset += pbuf_len) { 55404235Smarkfen prev_offset = offset; 55414235Smarkfen pbuf_len = strlen(pbuf); 55424235Smarkfen 55434235Smarkfen /* skip blank lines which seperate policy entries */ 55444235Smarkfen if (pbuf[0] == '\n') 55454235Smarkfen continue; 55464235Smarkfen 55474235Smarkfen /* if we found an index, save it */ 55484235Smarkfen if (strncasecmp(pbuf, INDEX_TAG, index_len) == 0) { 55494235Smarkfen buf = pbuf + index_len; 55504235Smarkfen buf++; 55514235Smarkfen if ((pindex = parse_index(buf, NULL)) == -1) { 55524235Smarkfen /* bad index, we can't continue */ 55534235Smarkfen warnx(gettext( 55545120Smarkfen "Invalid index in the file")); 55554235Smarkfen (void) fclose(remove_fp); 55564235Smarkfen (void) fclose(policy_fp); 55574235Smarkfen free(act_props); 55584235Smarkfen return (-1); 55594235Smarkfen } 55604235Smarkfen 55614235Smarkfen /* save this position in case it's the one */ 55624235Smarkfen if (fgetpos(policy_fp, &ipos) != 0) { 55634235Smarkfen (void) fclose(remove_fp); 55644235Smarkfen (void) fclose(policy_fp); 55654235Smarkfen free(act_props); 55664235Smarkfen return (-1); 55674235Smarkfen } 55684235Smarkfen } 55694235Smarkfen 55704235Smarkfen /* Does pbuf contain the remove policy? */ 55714235Smarkfen if (strncasecmp(rbuf, pbuf, pbuf_len) == 0) { 55724235Smarkfen /* we found the one to remove! */ 55734235Smarkfen if (pindex == 0) { 55744235Smarkfen warnx(gettext("Didn't find a valid " 55754235Smarkfen "index for policy")); 55764235Smarkfen (void) fclose(remove_fp); 55774235Smarkfen (void) fclose(policy_fp); 55784235Smarkfen free(act_props); 55794235Smarkfen return (-1); 55804235Smarkfen } 55814235Smarkfen 55824235Smarkfen /* off it - back up to the last INDEX! */ 55834235Smarkfen if (fsetpos(policy_fp, &ipos) != 0) { 55844235Smarkfen (void) fclose(remove_fp); 55854235Smarkfen (void) fclose(policy_fp); 55864235Smarkfen free(act_props); 55874235Smarkfen return (-1); 55884235Smarkfen } 55894235Smarkfen 55904235Smarkfen /* parse_one sets linecount = #lines to off */ 55914235Smarkfen if (parse_one(policy_fp, act_props) == -1) { 55924235Smarkfen warnx(gettext("Invalid policy entry " 55934235Smarkfen "in the file")); 55944235Smarkfen (void) fclose(remove_fp); 55954235Smarkfen (void) fclose(policy_fp); 55964235Smarkfen free(act_props); 55974235Smarkfen return (-1); 55984235Smarkfen } 55994235Smarkfen 56004235Smarkfen nlines = linecount + 2; 56014235Smarkfen goto delete; 56024235Smarkfen } 56034235Smarkfen /* 56044235Smarkfen * When we find a match, we want to pass the offset 56054235Smarkfen * of the line that is before it - the INDEX_TAG line. 56064235Smarkfen */ 56074235Smarkfen prev_prev_offset = prev_offset; 56084235Smarkfen } 56094235Smarkfen /* Didn't find a match - look at the next remove policy */ 56105120Smarkfen continue; /* while(); */ 56114235Smarkfen 56124235Smarkfen delete: 56134235Smarkfen (void) fclose(policy_fp); 56144235Smarkfen 56154235Smarkfen if (delete_from_file(prev_prev_offset, nlines) != 0) { 56164235Smarkfen warnx(gettext("delete_from_file failure. " 56174235Smarkfen "Please flush all entries and re-configure :")); 56184235Smarkfen reconfigure(); 56194235Smarkfen (void) fclose(remove_fp); 56204235Smarkfen free(act_props); 56214235Smarkfen return (-1); 56224235Smarkfen } 56234235Smarkfen 56244235Smarkfen if (pfp_delete_rule(pindex) != 0) { 56254235Smarkfen warnx(gettext("Deletion incomplete. Please flush" 56264235Smarkfen "all the entries and re-configure :")); 56274235Smarkfen reconfigure(); 56284235Smarkfen (void) fclose(remove_fp); 56294235Smarkfen free(act_props); 56304235Smarkfen return (-1); 56314235Smarkfen } 56324235Smarkfen 56334235Smarkfen /* reset the globals */ 56344235Smarkfen linecount = 0; 56354235Smarkfen pindex = 0; 56364235Smarkfen /* free(NULL) also works. */ 56374235Smarkfen free(interface_name); 56384235Smarkfen interface_name = NULL; 56394235Smarkfen 56404235Smarkfen /* reopen for next pass, automagically starting over. */ 56414235Smarkfen policy_fp = fopen(POLICY_CONF_FILE, "r"); 56424235Smarkfen if (policy_fp == NULL) { 56434235Smarkfen warn(gettext("%s cannot be re-opened, can't continue"), 56444235Smarkfen POLICY_CONF_FILE); 56454235Smarkfen (void) fclose(remove_fp); 56464235Smarkfen free(act_props); 56474235Smarkfen return (-1); 56484235Smarkfen } 56494235Smarkfen 56504235Smarkfen } /* read next remove policy */ 56514235Smarkfen 56524235Smarkfen if ((ret = pfp_delete_rule(pindex)) != 0) { 56534235Smarkfen warnx(gettext("Removal incomplete. Please flush " 56544235Smarkfen "all the entries and re-configure :")); 56554235Smarkfen reconfigure(); 56564235Smarkfen free(act_props); 56574235Smarkfen return (ret); 56584235Smarkfen } 56594235Smarkfen 56604235Smarkfen /* nothing left to look for */ 56614235Smarkfen (void) fclose(remove_fp); 56624235Smarkfen free(act_props); 56634235Smarkfen 56644235Smarkfen return (0); 56654235Smarkfen } 56664235Smarkfen 56674235Smarkfen /* 56684235Smarkfen * Constructs a tunnel interface ID extension. Returns the length 56694235Smarkfen * of the extension in 64-bit-words. 56704235Smarkfen */ 56714235Smarkfen static int 56724235Smarkfen attach_tunname(spd_if_t *tunname) 56734235Smarkfen { 56744235Smarkfen if (tunname == NULL || interface_name == NULL) 56754235Smarkfen return (0); 56764235Smarkfen 56774235Smarkfen tunname->spd_if_exttype = SPD_EXT_TUN_NAME; 56784235Smarkfen /* 56794235Smarkfen * Use "-3" because there's 4 bytes in the message itself, and 56804235Smarkfen * we lose one because of the '\0' terminator. 56814235Smarkfen */ 56824235Smarkfen tunname->spd_if_len = SPD_8TO64( 56834235Smarkfen P2ROUNDUP(sizeof (*tunname) + strlen(interface_name) - 3, 8)); 56844235Smarkfen (void) strlcpy((char *)tunname->spd_if_name, interface_name, LIFNAMSIZ); 56854235Smarkfen return (tunname->spd_if_len); 56864235Smarkfen } 5687