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 /* 2210372Sdanmcd@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 3400*10824SMark.Fenwick@Sun.COM static boolean_t 3401*10824SMark.Fenwick@Sun.COM combined_mode(ips_act_props_t *iap) 3402*10824SMark.Fenwick@Sun.COM { 3403*10824SMark.Fenwick@Sun.COM struct ipsecalgent *alg; 3404*10824SMark.Fenwick@Sun.COM 3405*10824SMark.Fenwick@Sun.COM alg = getipsecalgbynum(iap->iap_eencr.alg_id, IPSEC_PROTO_ESP, NULL); 3406*10824SMark.Fenwick@Sun.COM if (alg != NULL) 3407*10824SMark.Fenwick@Sun.COM freeipsecalgent(alg); 3408*10824SMark.Fenwick@Sun.COM 3409*10824SMark.Fenwick@Sun.COM return (ALG_FLAG_COMBINED & alg->a_alg_flags); 3410*10824SMark.Fenwick@Sun.COM } 3411*10824SMark.Fenwick@Sun.COM 34124235Smarkfen static int 34134235Smarkfen valid_algorithm(int proto_num, const char *str) 34144235Smarkfen { 34154235Smarkfen const char *tmp; 34164235Smarkfen int ret; 34174235Smarkfen struct ipsecalgent *alg; 34184235Smarkfen 34194235Smarkfen /* Short-circuit "none" */ 34204235Smarkfen if (strncasecmp("none", str, 5) == 0) 34214235Smarkfen return (-2); 34224235Smarkfen 34234235Smarkfen alg = getipsecalgbyname(str, proto_num, NULL); 34244235Smarkfen if (alg != NULL) { 34254235Smarkfen ret = alg->a_alg_num; 34264235Smarkfen freeipsecalgent(alg); 34274235Smarkfen return (ret); 34284235Smarkfen } 34294235Smarkfen 34304235Smarkfen /* 34314235Smarkfen * Look whether it could be a valid number. 34324235Smarkfen * We support numbers also so that users can 34334235Smarkfen * load algorithms as they need it. We can't 34344235Smarkfen * check for validity of numbers here. It will 34354235Smarkfen * be checked when the SA is negotiated/looked up. 34364235Smarkfen * parse_int uses strtol(str), which converts 3DES 34374235Smarkfen * to a valid number i.e looks only at initial 34384235Smarkfen * number part. If we come here we should expect 34394235Smarkfen * only a decimal number. 34404235Smarkfen */ 34414235Smarkfen tmp = str; 34424235Smarkfen while (*tmp) { 34434235Smarkfen if (!isdigit(*tmp)) 34444235Smarkfen return (-1); 34454235Smarkfen tmp++; 34464235Smarkfen } 34474235Smarkfen 34484235Smarkfen ret = parse_int(str); 34494235Smarkfen if (ret > 0 && ret <= 255) 34504235Smarkfen return (ret); 34514235Smarkfen else 34524235Smarkfen return (-1); 34534235Smarkfen } 34544235Smarkfen 34554235Smarkfen static int 34564235Smarkfen parse_ipsec_alg(char *str, ips_act_props_t *iap, int alg_type) 34574235Smarkfen { 34584235Smarkfen int alg_value; 34594235Smarkfen char tstr[VALID_ALG_LEN]; 34604235Smarkfen char *lens = NULL; 34614235Smarkfen char *l1_str; 34624235Smarkfen int l1 = 0; 34634235Smarkfen char *l2_str; 34644235Smarkfen int l2 = SPD_MAX_MAXBITS; 34654235Smarkfen algreq_t *ap; 34664235Smarkfen uint_t a_type; 34674235Smarkfen 34684235Smarkfen fetch_algorithms(); 34694235Smarkfen 34704235Smarkfen /* 34714235Smarkfen * Make sure that we get a null terminated string. 34724235Smarkfen * For a bad input, we truncate at VALID_ALG_LEN. 34734235Smarkfen */ 34744235Smarkfen (void) strlcpy(tstr, str, VALID_ALG_LEN); 34754235Smarkfen lens = strtok(tstr, "()"); 34764235Smarkfen lens = strtok(NULL, "()"); 34774235Smarkfen 34784235Smarkfen if (lens != NULL) { 34794235Smarkfen int len1 = 0; 34804235Smarkfen int len2 = SPD_MAX_MAXBITS; 34814235Smarkfen int len_all = strlen(lens); 34824235Smarkfen int dot_start = (lens[0] == '.'); 34834235Smarkfen l1_str = strtok(lens, "."); 34844235Smarkfen l2_str = strtok(NULL, "."); 34854235Smarkfen if (l1_str != NULL) { 34864235Smarkfen l1 = parse_int(l1_str); 34874235Smarkfen len1 = strlen(l1_str); 34884235Smarkfen if (len1 < 0) 34894235Smarkfen return (1); 34904235Smarkfen } 34914235Smarkfen if (l2_str != NULL) { 34924235Smarkfen l2 = parse_int(l2_str); 34934235Smarkfen len2 = strlen(l2_str); 34944235Smarkfen if (len2 < 0) 34954235Smarkfen return (1); 34964235Smarkfen } 34974235Smarkfen 34984235Smarkfen if (len_all == len1) { 34994235Smarkfen /* alg(n) */ 35004235Smarkfen l2 = l1; 35014235Smarkfen } else if (dot_start) { 35024235Smarkfen /* alg(..n) */ 35034235Smarkfen l2 = l1; 35044235Smarkfen l1 = 0; 35054235Smarkfen } else if ((len_all - 2) == len1) { 35064235Smarkfen /* alg(n..) */ 35074235Smarkfen l2 = SPD_MAX_MAXBITS; 35084235Smarkfen } /* else alg(n..m) */ 35094235Smarkfen } 35104235Smarkfen 35114235Smarkfen if (alg_type == SPD_ATTR_AH_AUTH || 35124235Smarkfen alg_type == SPD_ATTR_ESP_AUTH) { 35134235Smarkfen alg_value = valid_algorithm(IPSEC_PROTO_AH, tstr); 35144235Smarkfen } else { 35154235Smarkfen alg_value = valid_algorithm(IPSEC_PROTO_ESP, tstr); 35164235Smarkfen } 35174235Smarkfen if (alg_value < 0) { 35184235Smarkfen /* Invalid algorithm or "none" */ 35194235Smarkfen return (alg_value); 35204235Smarkfen } 35214235Smarkfen 35224235Smarkfen if (alg_type == SPD_ATTR_AH_AUTH) { 35234235Smarkfen a_type = AH_AUTH; 35244235Smarkfen iap->iap_attr |= SPD_APPLY_AH; 35254235Smarkfen ap = &(iap->iap_aauth); 35264235Smarkfen } else if (alg_type == SPD_ATTR_ESP_AUTH) { 35274235Smarkfen a_type = ESP_AUTH; 35284235Smarkfen iap->iap_attr |= SPD_APPLY_ESP|SPD_APPLY_ESPA; 35294235Smarkfen ap = &(iap->iap_eauth); 35304235Smarkfen } else { 35314235Smarkfen a_type = ESP_ENCR; 35324235Smarkfen iap->iap_attr |= SPD_APPLY_ESP; 35334235Smarkfen ap = &(iap->iap_eencr); 35344235Smarkfen } 35354235Smarkfen 35364235Smarkfen ap->alg_id = alg_value; 35374235Smarkfen ap->alg_minbits = l1; 35384235Smarkfen ap->alg_maxbits = l2; 35394235Smarkfen 35404235Smarkfen if (!alg_rangecheck(a_type, alg_value, ap)) 35414235Smarkfen return (1); 35424235Smarkfen 35434235Smarkfen return (0); 35444235Smarkfen } 35454235Smarkfen 35464235Smarkfen static char * 35474235Smarkfen sys_error_message(int syserr) 35484235Smarkfen { 35494235Smarkfen char *mesg; 35504235Smarkfen 35514235Smarkfen switch (syserr) { 35524235Smarkfen case EEXIST: 35534235Smarkfen mesg = gettext("Entry already exists"); 35544235Smarkfen break; 35554235Smarkfen case ENOENT: 35564235Smarkfen mesg = gettext("Tunnel not found"); 35574235Smarkfen break; 35584235Smarkfen case EINVAL: 35594235Smarkfen mesg = gettext("Invalid entry"); 35604235Smarkfen break; 35614235Smarkfen default : 35624235Smarkfen mesg = strerror(syserr); 35634235Smarkfen } 35644235Smarkfen return (mesg); 35654235Smarkfen } 35664235Smarkfen 35674235Smarkfen static void 35684235Smarkfen error_message(error_type_t error, int type, int line) 35694235Smarkfen { 35704235Smarkfen char *mesg; 35714235Smarkfen 35724235Smarkfen switch (type) { 35734235Smarkfen case IPSEC_CONF_SRC_ADDRESS: 35744235Smarkfen mesg = gettext("Source Address"); 35754235Smarkfen break; 35764235Smarkfen case IPSEC_CONF_DST_ADDRESS: 35774235Smarkfen mesg = gettext("Destination Address"); 35784235Smarkfen break; 35794235Smarkfen case IPSEC_CONF_SRC_PORT: 35804235Smarkfen mesg = gettext("Source Port"); 35814235Smarkfen break; 35824235Smarkfen case IPSEC_CONF_DST_PORT: 35834235Smarkfen mesg = gettext("Destination Port"); 35844235Smarkfen break; 35854235Smarkfen case IPSEC_CONF_SRC_MASK: 35864235Smarkfen mesg = gettext("Source Mask"); 35874235Smarkfen break; 35884235Smarkfen case IPSEC_CONF_DST_MASK: 35894235Smarkfen mesg = gettext("Destination Mask"); 35904235Smarkfen break; 35914235Smarkfen case IPSEC_CONF_ULP: 35924235Smarkfen mesg = gettext("Upper Layer Protocol"); 35934235Smarkfen break; 35944235Smarkfen case IPSEC_CONF_IPSEC_AALGS: 35954235Smarkfen mesg = gettext("Authentication Algorithm"); 35964235Smarkfen break; 35974235Smarkfen case IPSEC_CONF_IPSEC_EALGS: 35984235Smarkfen mesg = gettext("Encryption Algorithm"); 35994235Smarkfen break; 36004235Smarkfen case IPSEC_CONF_IPSEC_EAALGS: 36014235Smarkfen mesg = gettext("ESP Authentication Algorithm"); 36024235Smarkfen break; 36034235Smarkfen case IPSEC_CONF_IPSEC_SA: 36044235Smarkfen mesg = gettext("SA"); 36054235Smarkfen break; 36064235Smarkfen case IPSEC_CONF_IPSEC_DIR: 36074235Smarkfen mesg = gettext("Direction"); 36084235Smarkfen break; 36094235Smarkfen case IPSEC_CONF_ICMP_TYPE: 36104235Smarkfen mesg = gettext("ICMP type"); 36114235Smarkfen break; 36124235Smarkfen case IPSEC_CONF_ICMP_CODE: 36134235Smarkfen mesg = gettext("ICMP code"); 36144235Smarkfen break; 36154235Smarkfen case IPSEC_CONF_NEGOTIATE: 36164235Smarkfen mesg = gettext("Negotiate"); 36174235Smarkfen break; 36184235Smarkfen case IPSEC_CONF_TUNNEL: 36194235Smarkfen mesg = gettext("Tunnel"); 36204235Smarkfen break; 36214235Smarkfen default : 36224235Smarkfen return; 36234235Smarkfen } 36244235Smarkfen /* 36254235Smarkfen * If we never read a newline character, we don't want 36264235Smarkfen * to print 0. 36274235Smarkfen */ 36284235Smarkfen warnx(gettext("%s%s%s %s on line: %d"), 36294235Smarkfen (error == BAD_ERROR) ? gettext("Bad") : "", 36304235Smarkfen (error == DUP_ERROR) ? gettext("Duplicate") : "", 36314235Smarkfen (error == REQ_ERROR) ? gettext("Requires") : "", 36324235Smarkfen mesg, 36334235Smarkfen (arg_indices[line] == 0) ? 1 : arg_indices[line]); 36344235Smarkfen } 36354235Smarkfen 36364235Smarkfen static int 36374235Smarkfen validate_properties(ips_act_props_t *cptr, boolean_t dir, boolean_t is_alg) 36384235Smarkfen { 36394235Smarkfen if (cptr->iap_action == SPD_ACTTYPE_PASS || 36405120Smarkfen cptr->iap_action == SPD_ACTTYPE_DROP) { 36414235Smarkfen if (!dir) { 36424235Smarkfen warnx(gettext("dir string " 36434235Smarkfen "not found for bypass policy")); 36444235Smarkfen } 36454235Smarkfen 36464235Smarkfen if (is_alg) { 36474235Smarkfen warnx(gettext("Algorithms found for bypass policy")); 36484235Smarkfen return (-1); 36494235Smarkfen } 36504235Smarkfen return (0); 36514235Smarkfen } 36524235Smarkfen if (!is_alg) { 36534235Smarkfen warnx(gettext("No IPsec algorithms given")); 36544235Smarkfen return (-1); 36554235Smarkfen } 36564235Smarkfen if (cptr->iap_attr == 0) { 36574235Smarkfen warnx(gettext("No SA attribute")); 36584235Smarkfen return (-1); 36594235Smarkfen } 36604235Smarkfen return (0); 36614235Smarkfen } 36624235Smarkfen 36634235Smarkfen /* 36644235Smarkfen * This function is called only to parse a single rule's worth of 36654235Smarkfen * action strings. This is called after parsing pattern and before 36664235Smarkfen * parsing properties. Thus we may have something in the leftover 36674235Smarkfen * buffer while parsing the pattern, which we need to handle here. 36684235Smarkfen */ 36694235Smarkfen static int 36704235Smarkfen parse_action(FILE *fp, char **action, char **leftover) 36714235Smarkfen { 36724235Smarkfen char *cp; 36734235Smarkfen char ibuf[MAXLEN]; 36744235Smarkfen char *tmp_buf; 36754235Smarkfen char *buf; 36764235Smarkfen boolean_t new_stuff; 36774235Smarkfen 36784235Smarkfen if (*leftover != NULL) { 36794235Smarkfen buf = *leftover; 36804235Smarkfen new_stuff = B_FALSE; 36814235Smarkfen goto scan; 36824235Smarkfen } 36834235Smarkfen while (fgets(ibuf, MAXLEN, fp) != NULL) { 36844235Smarkfen new_stuff = B_TRUE; 36854235Smarkfen if (ibuf[strlen(ibuf) - 1] == '\n') 36864235Smarkfen linecount++; 36874235Smarkfen buf = ibuf; 36884235Smarkfen scan: 36894235Smarkfen /* Truncate at the beginning of a comment */ 36904235Smarkfen cp = strchr(buf, '#'); 36914235Smarkfen if (cp != NULL) 36924235Smarkfen *cp = NULL; 36934235Smarkfen 36944235Smarkfen /* Skip any whitespace */ 36954235Smarkfen while (*buf != NULL && isspace(*buf)) 36964235Smarkfen buf++; 36974235Smarkfen 36984235Smarkfen /* Empty line */ 36994235Smarkfen if (*buf == NULL) 37004235Smarkfen continue; 37014235Smarkfen 37024235Smarkfen /* 37034235Smarkfen * Store the command for error reporting 37044235Smarkfen * and ipsec_conf_add(). 37054235Smarkfen */ 37064235Smarkfen if (new_stuff) { 37074235Smarkfen /* 37084235Smarkfen * Check for buffer overflow including the null 37094235Smarkfen * terminating character. 37104235Smarkfen */ 37114235Smarkfen int len = strlen(ibuf); 37124235Smarkfen if ((cbuf_offset + len + 1) >= CBUF_LEN) 37134235Smarkfen return (-1); 37145120Smarkfen 37154235Smarkfen (void) strcpy(cbuf + cbuf_offset, ibuf); 37164235Smarkfen cbuf_offset += len; 37174235Smarkfen } 37184235Smarkfen /* 37194235Smarkfen * Start of the non-empty non-space character. 37204235Smarkfen */ 37215120Smarkfen tmp_buf = buf; 37224235Smarkfen 37234235Smarkfen /* Skip until next whitespace or CURL_BEGIN */ 37244235Smarkfen while (*buf != NULL && !isspace(*buf) && 37254235Smarkfen *buf != CURL_BEGIN) 37264235Smarkfen buf++; 37274235Smarkfen 37284235Smarkfen if (*buf != NULL) { 37295120Smarkfen if (tmp_buf == buf) /* No action token */ 37305120Smarkfen goto error; 37314235Smarkfen if (*buf == CURL_BEGIN) { 37324235Smarkfen *buf = NULL; 37334235Smarkfen /* Allocate an extra byte for the null also */ 37344235Smarkfen if ((*action = malloc(strlen(tmp_buf) + 1)) == 37354235Smarkfen NULL) { 37364235Smarkfen warn("malloc"); 37374235Smarkfen return (ENOMEM); 37384235Smarkfen } 37394235Smarkfen (void) strcpy(*action, tmp_buf); 37404235Smarkfen *buf = CURL_BEGIN; 37414235Smarkfen } else { 37424235Smarkfen /* We have hit a space */ 37434235Smarkfen *buf++ = NULL; 37444235Smarkfen /* Allocate an extra byte for the null also */ 37454235Smarkfen if ((*action = malloc(strlen(tmp_buf) + 1)) == 37464235Smarkfen NULL) { 37474235Smarkfen warn("malloc"); 37484235Smarkfen return (ENOMEM); 37494235Smarkfen } 37504235Smarkfen (void) strcpy(*action, tmp_buf); 37514235Smarkfen } 37524235Smarkfen /* 37534235Smarkfen * Copy the rest of the line into the 37544235Smarkfen * leftover buffer. 37554235Smarkfen */ 37564235Smarkfen if (*buf != NULL) { 37574235Smarkfen (void) strlcpy(lo_buf, buf, sizeof (lo_buf)); 37584235Smarkfen *leftover = lo_buf; 37594235Smarkfen } else { 37604235Smarkfen *leftover = NULL; 37614235Smarkfen } 37624235Smarkfen } else { 37634235Smarkfen /* Allocate an extra byte for the null also */ 37644235Smarkfen if ((*action = malloc(strlen(tmp_buf) + 1)) == 37654235Smarkfen NULL) { 37664235Smarkfen warn("malloc"); 37674235Smarkfen return (ENOMEM); 37684235Smarkfen } 37694235Smarkfen (void) strcpy(*action, tmp_buf); 37704235Smarkfen *leftover = NULL; 37714235Smarkfen } 37725120Smarkfen if (argindex >= ARG_BUF_LEN) { 37735120Smarkfen warnx(gettext("(parsing one command) " 37745120Smarkfen "Too many selectors before action.")); 37754235Smarkfen return (-1); 37765120Smarkfen } 37774235Smarkfen arg_indices[argindex++] = linecount; 37784235Smarkfen return (PARSE_SUCCESS); 37794235Smarkfen } 37804235Smarkfen /* 37814235Smarkfen * Return error, on an empty action field. 37824235Smarkfen */ 37835120Smarkfen error: 37845120Smarkfen warnx(gettext("(parsing one command) " 37855120Smarkfen "Missing action token.")); 37864235Smarkfen return (-1); 37874235Smarkfen } 37884235Smarkfen 37894235Smarkfen /* 37904235Smarkfen * This is called to parse pattern or properties that is enclosed 37914235Smarkfen * between CURL_BEGIN and CURL_END. 37924235Smarkfen */ 37934235Smarkfen static int 37944235Smarkfen parse_pattern_or_prop(FILE *fp, char *argvec[], char **leftover) 37954235Smarkfen { 37964235Smarkfen char *cp; 37974235Smarkfen int i = 0; 37984235Smarkfen boolean_t curl_begin_seen = B_FALSE; 37994235Smarkfen char ibuf[MAXLEN]; 38004235Smarkfen char *tmp_buf; 38014235Smarkfen char *buf; 38024235Smarkfen boolean_t new_stuff; 38034235Smarkfen 38044235Smarkfen /* 38054235Smarkfen * When parsing properties, leftover buffer could have the 38064235Smarkfen * leftovers of the previous fgets(). 38074235Smarkfen */ 38084235Smarkfen if (*leftover != NULL) { 38094235Smarkfen buf = *leftover; 38104235Smarkfen new_stuff = B_FALSE; 38114235Smarkfen goto scan; 38124235Smarkfen } 38134235Smarkfen while (fgets(ibuf, MAXLEN, fp) != NULL) { 38144235Smarkfen new_stuff = B_TRUE; 38154235Smarkfen #ifdef DEBUG_HEAVY 38164235Smarkfen (void) printf("%s\n", ibuf); 38174235Smarkfen #endif 38184235Smarkfen if (ibuf[strlen(ibuf) - 1] == '\n') 38194235Smarkfen linecount++; 38204235Smarkfen buf = ibuf; 38214235Smarkfen scan: 38224235Smarkfen /* Truncate at the beginning of a comment */ 38234235Smarkfen cp = strchr(buf, '#'); 38244235Smarkfen if (cp != NULL) 38254235Smarkfen *cp = NULL; 38264235Smarkfen 38274235Smarkfen /* Skip any whitespace */ 38284235Smarkfen while (*buf != NULL && isspace(*buf)) 38294235Smarkfen buf++; 38304235Smarkfen 38314235Smarkfen /* Empty line */ 38324235Smarkfen if (*buf == NULL) 38334235Smarkfen continue; 38344235Smarkfen /* 38354235Smarkfen * Store the command for error reporting 38364235Smarkfen * and ipsec_conf_add(). 38374235Smarkfen */ 38384235Smarkfen if (new_stuff) { 38394235Smarkfen /* 38404235Smarkfen * Check for buffer overflow including the null 38414235Smarkfen * terminating character. 38424235Smarkfen */ 38434235Smarkfen int len = strlen(ibuf); 38444235Smarkfen if ((cbuf_offset + len + 1) >= CBUF_LEN) 38454235Smarkfen return (-1); 38464235Smarkfen (void) strcpy(cbuf + cbuf_offset, ibuf); 38474235Smarkfen cbuf_offset += len; 38484235Smarkfen } 38494235Smarkfen /* 38504235Smarkfen * First non-space character should be 38514235Smarkfen * a curly bracket. 38524235Smarkfen */ 38534235Smarkfen if (!curl_begin_seen) { 38544235Smarkfen if (*buf != CURL_BEGIN) { 38554235Smarkfen /* 38564235Smarkfen * If we never read a newline character, 38574235Smarkfen * we don't want to print 0. 38584235Smarkfen */ 38595120Smarkfen warnx(gettext("line %d : pattern must start " 38605120Smarkfen "with \"%c\" character"), 38615120Smarkfen (linecount == 0) ? 1 : linecount, 38625120Smarkfen CURL_BEGIN); 38634235Smarkfen return (-1); 38644235Smarkfen } 38654235Smarkfen buf++; 38664235Smarkfen curl_begin_seen = B_TRUE; 38674235Smarkfen } 38684235Smarkfen /* 38694235Smarkfen * Arguments are separated by white spaces or 38704235Smarkfen * newlines. Scan till you see a CURL_END. 38714235Smarkfen */ 38724235Smarkfen while (*buf != NULL) { 38734235Smarkfen if (*buf == CURL_END) { 38744235Smarkfen ret: 38754235Smarkfen *buf++ = NULL; 38764235Smarkfen /* 38774235Smarkfen * Copy the rest of the line into the 38784235Smarkfen * leftover buffer if any. 38794235Smarkfen */ 38804235Smarkfen if (*buf != NULL) { 38814235Smarkfen (void) strlcpy(lo_buf, buf, 38824235Smarkfen sizeof (lo_buf)); 38834235Smarkfen *leftover = lo_buf; 38844235Smarkfen } else { 38854235Smarkfen *leftover = NULL; 38864235Smarkfen } 38874235Smarkfen return (PARSE_SUCCESS); 38884235Smarkfen } 38894235Smarkfen /* 38904235Smarkfen * Skip any trailing whitespace until we see a 38914235Smarkfen * non white-space character. 38924235Smarkfen */ 38934235Smarkfen while (*buf != NULL && isspace(*buf)) 38944235Smarkfen buf++; 38954235Smarkfen 38964235Smarkfen if (*buf == CURL_END) 38974235Smarkfen goto ret; 38984235Smarkfen 38994235Smarkfen /* Scan the next line as this buffer is empty */ 39004235Smarkfen if (*buf == NULL) 39014235Smarkfen break; 39024235Smarkfen 39034235Smarkfen if (i >= MAXARGS) { 39044235Smarkfen warnx( 39054235Smarkfen gettext("Number of Arguments exceeded %d"), 39064235Smarkfen i); 39074235Smarkfen return (-1); 39084235Smarkfen } 39094235Smarkfen /* 39104235Smarkfen * Non-empty, Non-space buffer. 39114235Smarkfen */ 39124235Smarkfen tmp_buf = buf++; 39134235Smarkfen /* 39144235Smarkfen * Real scan of the argument takes place here. 39154235Smarkfen * Skip past till space or CURL_END. 39164235Smarkfen */ 39174235Smarkfen while (*buf != NULL && !isspace(*buf) && 39184235Smarkfen *buf != CURL_END) { 39194235Smarkfen buf++; 39204235Smarkfen } 39214235Smarkfen /* 39224235Smarkfen * Either a space or we have hit the CURL_END or 39234235Smarkfen * the real end. 39244235Smarkfen */ 39254235Smarkfen if (*buf != NULL) { 39264235Smarkfen if (*buf == CURL_END) { 39274235Smarkfen *buf++ = NULL; 39284235Smarkfen if ((argvec[i] = malloc(strlen(tmp_buf) 39294235Smarkfen + 1)) == NULL) { 39304235Smarkfen warn("malloc"); 39314235Smarkfen return (ENOMEM); 39324235Smarkfen } 39334235Smarkfen if (strlen(tmp_buf) != 0) { 39344235Smarkfen (void) strcpy(argvec[i], 39354235Smarkfen tmp_buf); 39364235Smarkfen if (argindex >= ARG_BUF_LEN) 39375120Smarkfen goto toomanyargs; 39384235Smarkfen arg_indices[argindex++] = 39394235Smarkfen linecount; 39404235Smarkfen } 39414235Smarkfen /* 39424235Smarkfen * Copy the rest of the line into the 39434235Smarkfen * leftover buffer. 39444235Smarkfen */ 39454235Smarkfen if (*buf != NULL) { 39464235Smarkfen (void) strlcpy(lo_buf, buf, 39474235Smarkfen sizeof (lo_buf)); 39484235Smarkfen *leftover = lo_buf; 39494235Smarkfen } else { 39504235Smarkfen *leftover = NULL; 39514235Smarkfen } 39524235Smarkfen return (PARSE_SUCCESS); 39534235Smarkfen } else { 39544235Smarkfen *buf++ = NULL; 39554235Smarkfen } 39564235Smarkfen } 39574235Smarkfen /* 39584235Smarkfen * Copy this argument and scan for the buffer more 39594235Smarkfen * if it is non-empty. If it is empty scan for 39604235Smarkfen * the next line. 39614235Smarkfen */ 39624235Smarkfen if ((argvec[i] = malloc(strlen(tmp_buf) + 1)) == 39634235Smarkfen NULL) { 39644235Smarkfen warn("malloc"); 39654235Smarkfen return (ENOMEM); 39664235Smarkfen } 39674235Smarkfen (void) strcpy(argvec[i++], tmp_buf); 39685120Smarkfen if (argindex >= ARG_BUF_LEN) { 39695120Smarkfen /* 39705120Smarkfen * The number of tokens in a single policy entry 39715120Smarkfen * exceeds the number of buffers available to fully 39725120Smarkfen * parse the policy entry. 39735120Smarkfen */ 39745120Smarkfen toomanyargs: 39755120Smarkfen warnx(gettext("(parsing one command) " 39765120Smarkfen "Too many tokens in single policy entry.")); 39774235Smarkfen return (-1); 39785120Smarkfen } 39794235Smarkfen arg_indices[argindex++] = linecount; 39804235Smarkfen } 39814235Smarkfen } 39824235Smarkfen /* 39834235Smarkfen * If nothing is given in the file, it is okay. 39844235Smarkfen * If something is given in the file and it is 39854235Smarkfen * not CURL_BEGIN, we would have returned error 39864235Smarkfen * above. If curl_begin_seen and we are here, 39874235Smarkfen * something is wrong. 39884235Smarkfen */ 39895120Smarkfen if (curl_begin_seen) { 39905120Smarkfen warnx(gettext("(parsing one command) " 39915120Smarkfen "Pattern or Properties incomplete.")); 39924235Smarkfen return (-1); 39935120Smarkfen } 39944235Smarkfen return (PARSE_EOF); /* Nothing more in the file */ 39954235Smarkfen } 39964235Smarkfen 39974235Smarkfen /* 39984235Smarkfen * Parse one command i.e {pattern} action {properties}. 39994235Smarkfen * 40004235Smarkfen * {pattern} ( action {prop} | pass | drop ) (or ...)* 40014235Smarkfen */ 40024235Smarkfen static int 40034235Smarkfen parse_one(FILE *fp, act_prop_t *act_props) 40044235Smarkfen { 40054235Smarkfen char *leftover; 40064235Smarkfen int ret; 40074235Smarkfen int i; 40084235Smarkfen int ap_num = 0; 40094235Smarkfen enum parse_state {pattern, action, prop } pstate; 40104235Smarkfen 40114235Smarkfen has_daprefix = has_saprefix = B_FALSE; 40124235Smarkfen 40134235Smarkfen (void) memset(act_props, 0, sizeof (act_prop_t)); 40144235Smarkfen pstate = pattern; 40154235Smarkfen 40164235Smarkfen ret = 0; 40174235Smarkfen leftover = NULL; 40184235Smarkfen argindex = 0; 40194235Smarkfen cbuf_offset = 0; 40204235Smarkfen assert(shp == NULL && dhp == NULL); 40214235Smarkfen 40224235Smarkfen for (;;) { 40234235Smarkfen switch (pstate) { 40244235Smarkfen case pattern: 40254235Smarkfen { 40264235Smarkfen #ifdef DEBUG_HEAVY 40274235Smarkfen (void) printf("pattern\n"); 40284235Smarkfen #endif 40294235Smarkfen ret = parse_pattern_or_prop(fp, 40304235Smarkfen act_props->pattern, &leftover); 40314235Smarkfen if (ret == PARSE_EOF) { 40324235Smarkfen /* EOF reached */ 40335120Smarkfen return (PARSE_EOF); 40344235Smarkfen } 40354235Smarkfen if (ret != 0) { 40365120Smarkfen ret = -1; 40374235Smarkfen goto err; 40384235Smarkfen } 40394235Smarkfen pstate = action; 40404235Smarkfen break; 40414235Smarkfen } 40424235Smarkfen case action: 40434235Smarkfen { 40444235Smarkfen #ifdef DEBUG_HEAVY 40454235Smarkfen (void) printf("action\n"); 40464235Smarkfen #endif 40474235Smarkfen ret = parse_action(fp, 40484235Smarkfen &act_props->ap[ap_num].act, &leftover); 40494235Smarkfen if (ret != 0) { 40505120Smarkfen ret = -1; 40514235Smarkfen goto err; 40524235Smarkfen } 40534235Smarkfen 40544235Smarkfen /* 40554235Smarkfen * Validate action now itself so that we don't 40564235Smarkfen * proceed too much into the bad world. 40574235Smarkfen */ 40584235Smarkfen for (i = 0; action_table[i].string; i++) { 40594235Smarkfen if (strcmp(act_props->ap[ap_num].act, 40604235Smarkfen action_table[i].string) == 0) 40614235Smarkfen break; 40624235Smarkfen } 40634235Smarkfen 40644235Smarkfen if (action_table[i].tok_val == TOK_or) { 40654235Smarkfen /* hit an or, go again */ 40664235Smarkfen break; 40674235Smarkfen } 40684235Smarkfen 40694235Smarkfen if (action_table[i].string == NULL) { 40704235Smarkfen /* 40714235Smarkfen * If we never read a newline 40724235Smarkfen * character, we don't want 40734235Smarkfen * to print 0. 40744235Smarkfen */ 40755120Smarkfen warnx(gettext("(parsing one command) " 40764235Smarkfen "Invalid action on line %d: %s"), 40774235Smarkfen (linecount == 0) ? 1 : linecount, 40784235Smarkfen act_props->ap[ap_num].act); 40794235Smarkfen return (-1); 40804235Smarkfen } 40814235Smarkfen 40824235Smarkfen pstate = prop; 40834235Smarkfen break; 40844235Smarkfen } 40854235Smarkfen case prop: 40864235Smarkfen { 40874235Smarkfen #ifdef DEBUG_HEAVY 40884235Smarkfen (void) printf("prop\n"); 40894235Smarkfen #endif 40904235Smarkfen ret = parse_pattern_or_prop(fp, 40914235Smarkfen act_props->ap[ap_num].prop, &leftover); 40924235Smarkfen if (ret != 0) { 40935120Smarkfen if (ret == PARSE_EOF) { 40945120Smarkfen warnx(gettext("(parsing one command) " 40955120Smarkfen "Missing properties.")); 40965120Smarkfen } 40975120Smarkfen ret = -1; 40984235Smarkfen goto err; 40994235Smarkfen } 41004235Smarkfen 41014235Smarkfen if (leftover != NULL) { 41024235Smarkfen /* Accomodate spaces at the end */ 41034235Smarkfen while (*leftover != NULL) { 41045120Smarkfen if (*leftover == BACK_SLASH) { 41055120Smarkfen warnx(gettext("Invalid line " 41065120Smarkfen "continuation character.")); 41075120Smarkfen ret = -1; 41085120Smarkfen goto err; 41095120Smarkfen } 41104235Smarkfen if (*leftover == 'o') { 41114235Smarkfen leftover++; 41124235Smarkfen if (*leftover == 'r') { 41134235Smarkfen leftover++; 41144235Smarkfen ap_num++; 41154235Smarkfen pstate = action; 41164235Smarkfen goto again; 41174235Smarkfen } 41184235Smarkfen } 41194235Smarkfen if (!isspace(*leftover)) { 41204235Smarkfen ret = -1; 41214235Smarkfen goto err; 41224235Smarkfen } 41234235Smarkfen leftover++; 41244235Smarkfen } 41254235Smarkfen return (0); 41264235Smarkfen } 41274235Smarkfen ap_num++; 41284235Smarkfen if (ap_num > MAXARGS) 41294235Smarkfen return (0); 41304235Smarkfen pstate = action; /* or */ 41314235Smarkfen break; 41324235Smarkfen } /* case prop: */ 41334235Smarkfen } /* switch(pstate) */ 41344235Smarkfen 41354235Smarkfen again: 41365120Smarkfen if (ap_num > MAXARGS) { 41375120Smarkfen warnx(gettext("Too many actions.")); 41385120Smarkfen return (-1); 41395120Smarkfen } 41405120Smarkfen } /* for(;;) */ 41414235Smarkfen err: 41424235Smarkfen if (ret != 0) { 41434235Smarkfen /* 41444235Smarkfen * If we never read a newline character, we don't want 41454235Smarkfen * to print 0. 41464235Smarkfen */ 41474235Smarkfen warnx(gettext("Error before or at line %d"), 41484235Smarkfen (linecount == 0) ? 1 : linecount); 41494235Smarkfen } 41504235Smarkfen return (ret); 41514235Smarkfen } 41524235Smarkfen 41534235Smarkfen /* 41544235Smarkfen * convert an act_propts_t to an ips_conf_t 41554235Smarkfen */ 41564235Smarkfen 41574235Smarkfen static int 41584235Smarkfen form_ipsec_conf(act_prop_t *act_props, ips_conf_t *cptr) 41594235Smarkfen { 41604235Smarkfen int i, j, k; 41614235Smarkfen int tok_count = 0; 41624235Smarkfen struct protoent *pent; 41634235Smarkfen boolean_t saddr, daddr, ipsec_aalg, ipsec_ealg, ipsec_eaalg, dir; 416410372Sdanmcd@sun.com boolean_t old_style, new_style, auth_covered, is_no_alg; 4165*10824SMark.Fenwick@Sun.COM boolean_t is_combined_mode; 41664235Smarkfen struct in_addr mask; 41674235Smarkfen int line_no; 41684235Smarkfen int ret; 41694235Smarkfen int ap_num = 0; 41704235Smarkfen int type, code, type_end, code_end; 41714235Smarkfen #ifdef DEBUG_HEAVY 41724235Smarkfen /* 41734235Smarkfen * pattern => act_props->pattern 41744235Smarkfen * action => act_props->ap[].act 41754235Smarkfen * properties => act_props->ap[].prop 41764235Smarkfen */ 41774235Smarkfen (void) printf("\npattern\n------------\n"); 41784235Smarkfen for (i = 0; act_props->pattern[i] != NULL; i++) 41794235Smarkfen (void) printf("%s\n", act_props->pattern[i]); 41804235Smarkfen (void) printf("apz\n----------\n"); 41814235Smarkfen for (j = 0; act_props->ap[j].act != NULL; j++) { 41824235Smarkfen 41834235Smarkfen (void) printf("act%d->%s\n", j, act_props->ap[j].act); 41844235Smarkfen for (i = 0; act_props->ap[j].prop[i] != NULL; i++) 41854235Smarkfen (void) printf("%dprop%d->%s\n", 41864235Smarkfen j, i, act_props->ap[j].prop[i]); 41874235Smarkfen } 41884235Smarkfen (void) printf("------------\n\n"); 41894235Smarkfen #endif 41904235Smarkfen 41914235Smarkfen (void) memset(cptr, 0, sizeof (ips_conf_t)); 41924235Smarkfen saddr = daddr = ipsec_aalg = ipsec_ealg = ipsec_eaalg = dir = B_FALSE; 4193*10824SMark.Fenwick@Sun.COM old_style = new_style = is_no_alg = is_combined_mode = B_FALSE; 41944235Smarkfen /* 41954235Smarkfen * Get the Pattern. NULL pattern is valid. 41964235Smarkfen */ 41974235Smarkfen for (i = 0, line_no = 0; act_props->pattern[i]; i++, line_no++) { 41984235Smarkfen for (j = 0; pattern_table[j].string; j++) { 41994235Smarkfen if (strcmp(act_props->pattern[i], 42004235Smarkfen pattern_table[j].string) == 0) 42014235Smarkfen break; 42024235Smarkfen } 42034235Smarkfen 42044235Smarkfen if (pattern_table[j].string == NULL) { 42054235Smarkfen /* 42064235Smarkfen * If we never read a newline character, we don't want 42074235Smarkfen * to print 0. 42084235Smarkfen */ 42094235Smarkfen warnx(gettext("Invalid pattern on line %d: %s"), 42104235Smarkfen (arg_indices[line_no] == 0) ? 1 : 42114235Smarkfen arg_indices[line_no], act_props->pattern[i]); 42124235Smarkfen return (-1); 42134235Smarkfen } 42144235Smarkfen 42154235Smarkfen cptr->patt_tok[tok_count++] = pattern_table[j].tok_val; 42164235Smarkfen 42174235Smarkfen switch (pattern_table[j].tok_val) { 42184235Smarkfen 42194235Smarkfen case TOK_dir: 42204235Smarkfen i++, line_no++; 42214235Smarkfen if (act_props->pattern[i] == NULL) { 42224235Smarkfen error_message(BAD_ERROR, 42234235Smarkfen IPSEC_CONF_IPSEC_DIR, line_no); 42244235Smarkfen return (-1); 42254235Smarkfen } 42264235Smarkfen 42274235Smarkfen if (strncmp(act_props->pattern[i], "in", 2) == 0) { 42284235Smarkfen cptr->ips_dir = SPD_RULE_FLAG_INBOUND; 42294235Smarkfen } else if (strncmp( 42304235Smarkfen act_props->pattern[i], "out", 3) == 0) { 42314235Smarkfen cptr->ips_dir = SPD_RULE_FLAG_OUTBOUND; 42324235Smarkfen } else if (strncmp( 42334235Smarkfen act_props->pattern[i], "both", 4) == 0) { 42344235Smarkfen if (old_style) { 42354235Smarkfen error_message(BAD_ERROR, 42364235Smarkfen IPSEC_CONF_IPSEC_DIR, line_no); 42374235Smarkfen return (-1); 42384235Smarkfen } 42394235Smarkfen new_style = B_TRUE; 42404235Smarkfen cptr->ips_dir = 42414235Smarkfen SPD_RULE_FLAG_OUTBOUND | 42424235Smarkfen SPD_RULE_FLAG_INBOUND; 42434235Smarkfen } else { 42444235Smarkfen error_message(BAD_ERROR, 42454235Smarkfen IPSEC_CONF_IPSEC_DIR, line_no); 42464235Smarkfen return (-1); 42474235Smarkfen } 42484235Smarkfen dir = B_TRUE; 42494235Smarkfen break; 42504235Smarkfen 42514235Smarkfen case TOK_local: 42524235Smarkfen if (old_style) { 42534235Smarkfen error_message(BAD_ERROR, 42544235Smarkfen IPSEC_CONF_SRC_ADDRESS, line_no); 42554235Smarkfen return (-1); 42564235Smarkfen } 42574235Smarkfen new_style = B_TRUE; 42584235Smarkfen 42594235Smarkfen if (saddr) { 42604235Smarkfen error_message(DUP_ERROR, 42614235Smarkfen IPSEC_CONF_SRC_ADDRESS, line_no); 42624235Smarkfen return (-1); 42634235Smarkfen } 42644235Smarkfen /* 42654235Smarkfen * Use this to detect duplicates rather 42664235Smarkfen * than 0 like other cases, because 0 for 42674235Smarkfen * address means INADDR_ANY. 42684235Smarkfen */ 42694235Smarkfen saddr = B_TRUE; 42704235Smarkfen cptr->has_saddr = 1; 42714235Smarkfen /* 42724235Smarkfen * Advance to the string containing 42734235Smarkfen * the address. 42744235Smarkfen */ 42754235Smarkfen i++, line_no++; 42764235Smarkfen if (act_props->pattern[i] == NULL) { 42774235Smarkfen error_message(BAD_ERROR, 42784235Smarkfen IPSEC_CONF_SRC_ADDRESS, line_no); 42794235Smarkfen return (-1); 42804235Smarkfen } 42814235Smarkfen if (parse_address(IPSEC_CONF_SRC_ADDRESS, 42824235Smarkfen act_props->pattern[i]) != 0) { 42834235Smarkfen error_message(BAD_ERROR, 42844235Smarkfen IPSEC_CONF_SRC_ADDRESS, line_no); 42854235Smarkfen return (-1); 42864235Smarkfen } 42874235Smarkfen if (!cptr->has_smask) 42884235Smarkfen cptr->has_smask = has_saprefix; 42894235Smarkfen 42904235Smarkfen break; 42914235Smarkfen case TOK_remote: 42924235Smarkfen if (old_style) { 42934235Smarkfen error_message(BAD_ERROR, 42944235Smarkfen IPSEC_CONF_DST_ADDRESS, line_no); 42954235Smarkfen return (-1); 42964235Smarkfen } 42974235Smarkfen new_style = B_TRUE; 42984235Smarkfen 42994235Smarkfen if (daddr) { 43004235Smarkfen error_message(DUP_ERROR, 43014235Smarkfen IPSEC_CONF_DST_ADDRESS, line_no); 43024235Smarkfen return (-1); 43034235Smarkfen } 43044235Smarkfen /* 43054235Smarkfen * Use this to detect duplicates rather 43064235Smarkfen * than 0 like other cases, because 0 for 43074235Smarkfen * address means INADDR_ANY. 43084235Smarkfen */ 43094235Smarkfen daddr = B_TRUE; 43104235Smarkfen cptr->has_daddr = 1; 43114235Smarkfen /* 43124235Smarkfen * Advance to the string containing 43134235Smarkfen * the address. 43144235Smarkfen */ 43154235Smarkfen i++, line_no++; 43164235Smarkfen if (act_props->pattern[i] == NULL) { 43174235Smarkfen error_message(BAD_ERROR, 43184235Smarkfen IPSEC_CONF_DST_ADDRESS, line_no); 43194235Smarkfen return (-1); 43204235Smarkfen } 43214235Smarkfen if (parse_address(IPSEC_CONF_DST_ADDRESS, 43224235Smarkfen act_props->pattern[i]) != 0) { 43234235Smarkfen error_message(BAD_ERROR, 43244235Smarkfen IPSEC_CONF_DST_ADDRESS, line_no); 43254235Smarkfen return (-1); 43264235Smarkfen } 43274235Smarkfen if (!cptr->has_dmask) 43284235Smarkfen cptr->has_dmask = has_daprefix; 43294235Smarkfen break; 43304235Smarkfen 43314235Smarkfen case TOK_saddr: 43324235Smarkfen if (new_style) { 43334235Smarkfen error_message(BAD_ERROR, 43344235Smarkfen IPSEC_CONF_SRC_ADDRESS, line_no); 43354235Smarkfen return (-1); 43364235Smarkfen } 43374235Smarkfen old_style = B_TRUE; 43384235Smarkfen 43394235Smarkfen if (saddr) { 43404235Smarkfen error_message(DUP_ERROR, 43414235Smarkfen IPSEC_CONF_SRC_ADDRESS, line_no); 43424235Smarkfen return (-1); 43434235Smarkfen } 43444235Smarkfen /* 43454235Smarkfen * Use this to detect duplicates rather 43464235Smarkfen * than 0 like other cases, because 0 for 43474235Smarkfen * address means INADDR_ANY. 43484235Smarkfen */ 43494235Smarkfen saddr = B_TRUE; 43504235Smarkfen cptr->has_saddr = 1; 43514235Smarkfen /* 43524235Smarkfen * Advance to the string containing 43534235Smarkfen * the address. 43544235Smarkfen */ 43554235Smarkfen i++, line_no++; 43564235Smarkfen if (act_props->pattern[i] == NULL) { 43574235Smarkfen error_message(BAD_ERROR, 43584235Smarkfen IPSEC_CONF_SRC_ADDRESS, line_no); 43594235Smarkfen return (-1); 43604235Smarkfen } 43614235Smarkfen 43624235Smarkfen if (parse_address(IPSEC_CONF_SRC_ADDRESS, 43634235Smarkfen act_props->pattern[i]) != 0) { 43644235Smarkfen error_message(BAD_ERROR, 43654235Smarkfen IPSEC_CONF_SRC_ADDRESS, line_no); 43664235Smarkfen return (-1); 43674235Smarkfen } 43684235Smarkfen /* shp or bhp? */ 43694235Smarkfen if (!cptr->has_smask) 43704235Smarkfen cptr->has_smask = has_saprefix; 43714235Smarkfen break; 43724235Smarkfen 43734235Smarkfen case TOK_daddr: 43744235Smarkfen if (new_style) { 43754235Smarkfen error_message(BAD_ERROR, 43764235Smarkfen IPSEC_CONF_DST_ADDRESS, line_no); 43774235Smarkfen return (-1); 43784235Smarkfen } 43794235Smarkfen old_style = B_TRUE; 43804235Smarkfen 43814235Smarkfen if (daddr) { 43824235Smarkfen error_message(DUP_ERROR, 43834235Smarkfen IPSEC_CONF_DST_ADDRESS, line_no); 43844235Smarkfen return (-1); 43854235Smarkfen } 43864235Smarkfen /* 43874235Smarkfen * Use this to detect duplicates rather 43884235Smarkfen * than 0 like other cases, because 0 for 43894235Smarkfen * address means INADDR_ANY. 43904235Smarkfen */ 43914235Smarkfen daddr = B_TRUE; 43924235Smarkfen cptr->has_daddr = 1; 43934235Smarkfen /* 43944235Smarkfen * Advance to the string containing 43954235Smarkfen * the address. 43964235Smarkfen */ 43974235Smarkfen i++, line_no++; 43984235Smarkfen if (act_props->pattern[i] == NULL) { 43994235Smarkfen error_message(BAD_ERROR, 44004235Smarkfen IPSEC_CONF_DST_ADDRESS, line_no); 44014235Smarkfen return (-1); 44024235Smarkfen } 44034235Smarkfen if (parse_address(IPSEC_CONF_DST_ADDRESS, 44044235Smarkfen act_props->pattern[i]) != 0) { 44054235Smarkfen error_message(BAD_ERROR, 44064235Smarkfen IPSEC_CONF_DST_ADDRESS, line_no); 44074235Smarkfen return (-1); 44084235Smarkfen } 44094235Smarkfen if (!cptr->has_dmask) 44104235Smarkfen cptr->has_dmask = has_daprefix; 44114235Smarkfen break; 44124235Smarkfen 44134235Smarkfen case TOK_sport: 44144235Smarkfen if (new_style) { 44154235Smarkfen error_message(BAD_ERROR, 44164235Smarkfen IPSEC_CONF_SRC_PORT, line_no); 44174235Smarkfen return (-1); 44184235Smarkfen } 44194235Smarkfen old_style = B_TRUE; 44204235Smarkfen 44214235Smarkfen if (cptr->ips_src_port_min != 0) { 44224235Smarkfen error_message(DUP_ERROR, IPSEC_CONF_SRC_PORT, 44234235Smarkfen line_no); 44244235Smarkfen return (-1); 44254235Smarkfen } 44264235Smarkfen i++, line_no++; 44274235Smarkfen if (act_props->pattern[i] == NULL) { 44284235Smarkfen error_message(BAD_ERROR, IPSEC_CONF_SRC_PORT, 44294235Smarkfen line_no); 44304235Smarkfen return (-1); 44314235Smarkfen } 44324235Smarkfen ret = parse_port(IPSEC_CONF_SRC_PORT, 44334235Smarkfen act_props->pattern[i], cptr); 44344235Smarkfen if (ret != 0) { 44354235Smarkfen error_message(BAD_ERROR, IPSEC_CONF_SRC_PORT, 44364235Smarkfen line_no); 44374235Smarkfen return (-1); 44384235Smarkfen } 44394235Smarkfen break; 44404235Smarkfen case TOK_dport: 44414235Smarkfen if (new_style) { 44424235Smarkfen error_message(BAD_ERROR, 44434235Smarkfen IPSEC_CONF_DST_PORT, line_no); 44444235Smarkfen return (-1); 44454235Smarkfen } 44464235Smarkfen old_style = B_TRUE; 44474235Smarkfen 44484235Smarkfen if (cptr->ips_dst_port_min != 0) { 44494235Smarkfen error_message(DUP_ERROR, IPSEC_CONF_DST_PORT, 44504235Smarkfen line_no); 44514235Smarkfen return (-1); 44524235Smarkfen } 44534235Smarkfen i++, line_no++; 44544235Smarkfen if (act_props->pattern[i] == NULL) { 44554235Smarkfen error_message(BAD_ERROR, IPSEC_CONF_DST_PORT, 44564235Smarkfen line_no); 44574235Smarkfen return (-1); 44584235Smarkfen } 44594235Smarkfen ret = parse_port(IPSEC_CONF_DST_PORT, 44604235Smarkfen act_props->pattern[i], 44614235Smarkfen cptr); 44624235Smarkfen if (ret != 0) { 44634235Smarkfen error_message(BAD_ERROR, IPSEC_CONF_DST_PORT, 44644235Smarkfen line_no); 44654235Smarkfen return (-1); 44664235Smarkfen } 44674235Smarkfen break; 44684235Smarkfen 44694235Smarkfen case TOK_lport: 44704235Smarkfen if (old_style) { 44714235Smarkfen error_message(BAD_ERROR, 44724235Smarkfen IPSEC_CONF_SRC_PORT, line_no); 44734235Smarkfen return (-1); 44744235Smarkfen } 44754235Smarkfen new_style = B_TRUE; 44764235Smarkfen 44774235Smarkfen if (cptr->ips_src_port_min != 0) { 44784235Smarkfen error_message(DUP_ERROR, IPSEC_CONF_SRC_PORT, 44794235Smarkfen line_no); 44804235Smarkfen return (-1); 44814235Smarkfen } 44824235Smarkfen i++, line_no++; 44834235Smarkfen if (act_props->pattern[i] == NULL) { 44844235Smarkfen error_message(BAD_ERROR, IPSEC_CONF_SRC_PORT, 44854235Smarkfen line_no); 44864235Smarkfen return (-1); 44874235Smarkfen } 44884235Smarkfen ret = parse_port(IPSEC_CONF_SRC_PORT, 44894235Smarkfen act_props->pattern[i], 44904235Smarkfen cptr); 44914235Smarkfen if (ret != 0) { 44924235Smarkfen error_message(BAD_ERROR, IPSEC_CONF_SRC_PORT, 44934235Smarkfen line_no); 44944235Smarkfen return (-1); 44954235Smarkfen } 44964235Smarkfen break; 44974235Smarkfen 44984235Smarkfen case TOK_rport: 44994235Smarkfen if (old_style) { 45004235Smarkfen error_message(BAD_ERROR, 45014235Smarkfen IPSEC_CONF_DST_PORT, line_no); 45024235Smarkfen return (-1); 45034235Smarkfen } 45044235Smarkfen new_style = B_TRUE; 45054235Smarkfen 45064235Smarkfen if (cptr->ips_dst_port_min != 0) { 45074235Smarkfen error_message(DUP_ERROR, IPSEC_CONF_DST_PORT, 45084235Smarkfen line_no); 45094235Smarkfen return (-1); 45104235Smarkfen } 45114235Smarkfen i++, line_no++; 45124235Smarkfen if (act_props->pattern[i] == NULL) { 45134235Smarkfen error_message(BAD_ERROR, IPSEC_CONF_DST_PORT, 45144235Smarkfen line_no); 45154235Smarkfen return (-1); 45164235Smarkfen } 45174235Smarkfen ret = parse_port(IPSEC_CONF_DST_PORT, 45184235Smarkfen act_props->pattern[i], 45194235Smarkfen cptr); 45204235Smarkfen if (ret != 0) { 45214235Smarkfen error_message(BAD_ERROR, IPSEC_CONF_DST_PORT, 45224235Smarkfen line_no); 45234235Smarkfen return (-1); 45244235Smarkfen } 45254235Smarkfen break; 45264235Smarkfen 45274235Smarkfen case TOK_smask: 45284235Smarkfen if (new_style) { 45294235Smarkfen error_message(BAD_ERROR, 45304235Smarkfen IPSEC_CONF_SRC_MASK, line_no); 45314235Smarkfen return (-1); 45324235Smarkfen } 45334235Smarkfen old_style = B_TRUE; 45344235Smarkfen cptr->has_smask = B_TRUE; 45354235Smarkfen 45364235Smarkfen IN6_V4MAPPED_TO_INADDR(&cptr->ips_src_mask_v6, &mask); 45374235Smarkfen if (mask.s_addr != 0) { 45384235Smarkfen error_message(DUP_ERROR, IPSEC_CONF_SRC_MASK, 45394235Smarkfen line_no); 45404235Smarkfen return (-1); 45414235Smarkfen } 45424235Smarkfen i++, line_no++; 45434235Smarkfen if (act_props->pattern[i] == NULL) { 45444235Smarkfen error_message(BAD_ERROR, IPSEC_CONF_SRC_MASK, 45454235Smarkfen line_no); 45464235Smarkfen return (-1); 45474235Smarkfen } 45484235Smarkfen ret = parse_mask(IPSEC_CONF_SRC_MASK, 45494235Smarkfen act_props->pattern[i], 45504235Smarkfen cptr); 45514235Smarkfen if (ret != 0) { 45524235Smarkfen error_message(BAD_ERROR, IPSEC_CONF_SRC_MASK, 45534235Smarkfen line_no); 45544235Smarkfen return (-1); 45554235Smarkfen } 45564235Smarkfen break; 45574235Smarkfen case TOK_dmask: 45584235Smarkfen if (new_style) { 45594235Smarkfen error_message(BAD_ERROR, 45604235Smarkfen IPSEC_CONF_DST_MASK, line_no); 45614235Smarkfen return (-1); 45624235Smarkfen } 45634235Smarkfen old_style = B_TRUE; 45644235Smarkfen cptr->has_dmask = B_TRUE; 45654235Smarkfen 45664235Smarkfen IN6_V4MAPPED_TO_INADDR(&cptr->ips_dst_mask_v6, &mask); 45674235Smarkfen if (mask.s_addr != 0) { 45684235Smarkfen error_message(DUP_ERROR, IPSEC_CONF_DST_MASK, 45694235Smarkfen line_no); 45704235Smarkfen return (-1); 45714235Smarkfen } 45724235Smarkfen i++, line_no++; 45734235Smarkfen if (act_props->pattern[i] == NULL) { 45744235Smarkfen error_message(BAD_ERROR, IPSEC_CONF_DST_MASK, 45754235Smarkfen line_no); 45764235Smarkfen return (-1); 45774235Smarkfen } 45784235Smarkfen ret = parse_mask(IPSEC_CONF_DST_MASK, 45794235Smarkfen act_props->pattern[i], 45804235Smarkfen cptr); 45814235Smarkfen if (ret != 0) { 45824235Smarkfen error_message(BAD_ERROR, IPSEC_CONF_DST_MASK, 45834235Smarkfen line_no); 45844235Smarkfen return (-1); 45854235Smarkfen } 45864235Smarkfen break; 45874235Smarkfen case TOK_ulp: 45884235Smarkfen if (cptr->ips_ulp_prot != 0) { 45894235Smarkfen error_message(DUP_ERROR, 45904235Smarkfen IPSEC_CONF_ULP, line_no); 45914235Smarkfen return (-1); 45924235Smarkfen } 45934235Smarkfen i++, line_no++; 45944235Smarkfen if (act_props->pattern[i] == NULL) { 45954235Smarkfen error_message(BAD_ERROR, 45964235Smarkfen IPSEC_CONF_ULP, line_no); 45974235Smarkfen return (-1); 45984235Smarkfen } 45994235Smarkfen pent = getprotobyname(act_props->pattern[i]); 46004235Smarkfen if (pent == NULL) { 46014235Smarkfen int ulp; 46024235Smarkfen ulp = parse_int(act_props->pattern[i]); 46034235Smarkfen if (ulp == -1) { 46044235Smarkfen error_message(BAD_ERROR, 46054235Smarkfen IPSEC_CONF_ULP, line_no); 46064235Smarkfen return (-1); 46074235Smarkfen } 46084235Smarkfen cptr->ips_ulp_prot = ulp; 46094235Smarkfen } else { 46104235Smarkfen cptr->ips_ulp_prot = pent->p_proto; 46114235Smarkfen } 46124235Smarkfen break; 46134235Smarkfen case TOK_type: 46144235Smarkfen if (cptr->has_type) { 46154235Smarkfen error_message(DUP_ERROR, 46164235Smarkfen IPSEC_CONF_ICMP_TYPE, line_no); 46174235Smarkfen return (-1); 46184235Smarkfen } 46194235Smarkfen 46204235Smarkfen i++, line_no++; 46214235Smarkfen type = parse_type_code(act_props->pattern[i], 46224235Smarkfen icmp_type_table); 46234235Smarkfen 46244235Smarkfen if (type > 65536 || type < 0) { 46254235Smarkfen error_message(BAD_ERROR, 46264235Smarkfen IPSEC_CONF_ICMP_TYPE, line_no); 46274235Smarkfen return (-1); 46284235Smarkfen } 46294235Smarkfen 46304235Smarkfen type_end = type / 256; 46314235Smarkfen type = type % 256; 46324235Smarkfen 46334235Smarkfen if (type_end < type) 46344235Smarkfen type_end = type; 46354235Smarkfen 46364235Smarkfen cptr->has_type = 1; 46374235Smarkfen cptr->ips_icmp_type = (uint8_t)type; 46384235Smarkfen cptr->ips_icmp_type_end = (uint8_t)type_end; 46394235Smarkfen break; 46404235Smarkfen case TOK_code: 46414235Smarkfen if (!cptr->has_type) { 46424235Smarkfen error_message(BAD_ERROR, 46434235Smarkfen IPSEC_CONF_ICMP_CODE, line_no); 46444235Smarkfen return (-1); 46454235Smarkfen } 46464235Smarkfen 46474235Smarkfen if (cptr->has_code) { 46484235Smarkfen error_message(DUP_ERROR, 46494235Smarkfen IPSEC_CONF_ICMP_CODE, line_no); 46504235Smarkfen return (-1); 46514235Smarkfen } 46524235Smarkfen 46534235Smarkfen i++, line_no++; 46544235Smarkfen 46554235Smarkfen code = parse_type_code(act_props->pattern[i], 46564235Smarkfen icmp_code_table); 46574235Smarkfen if (type > 65536 || type < 0) { 46584235Smarkfen error_message(BAD_ERROR, 46594235Smarkfen IPSEC_CONF_ICMP_CODE, line_no); 46604235Smarkfen return (-1); 46614235Smarkfen } 46624235Smarkfen code_end = code / 256; 46634235Smarkfen code = code % 256; 46644235Smarkfen 46654235Smarkfen if (code_end < code) 46664235Smarkfen code_end = code; 46674235Smarkfen 46684235Smarkfen cptr->has_code = 1; 46694235Smarkfen cptr->ips_icmp_code = (uint8_t)code; 46704235Smarkfen cptr->ips_icmp_code_end = (uint8_t)code_end; 46714235Smarkfen break; 46724235Smarkfen case TOK_tunnel: 46734235Smarkfen if (cptr->has_tunnel == 1) { 46744235Smarkfen error_message(BAD_ERROR, 46754235Smarkfen IPSEC_CONF_TUNNEL, line_no); 46764235Smarkfen return (-1); 46774235Smarkfen } 46784235Smarkfen i++, line_no++; 46794235Smarkfen if (act_props->pattern[i] == NULL) { 46804235Smarkfen error_message(BAD_ERROR, 46814235Smarkfen IPSEC_CONF_TUNNEL, line_no); 46824235Smarkfen return (-1); 46834235Smarkfen } 46844235Smarkfen 46854235Smarkfen if (strlcpy(tunif, act_props->pattern[i], 46864235Smarkfen TUNNAMEMAXLEN) >= TUNNAMEMAXLEN) { 46874235Smarkfen error_message(BAD_ERROR, 46884235Smarkfen IPSEC_CONF_TUNNEL, line_no); 46894235Smarkfen return (-1); 46904235Smarkfen } 46914235Smarkfen cptr->has_tunnel = 1; 46924235Smarkfen break; 46934235Smarkfen case TOK_negotiate: 46944235Smarkfen if (cptr->has_negotiate == 1) { 46954235Smarkfen error_message(BAD_ERROR, 46964235Smarkfen IPSEC_CONF_NEGOTIATE, line_no); 46974235Smarkfen return (-1); 46984235Smarkfen } 46994235Smarkfen i++, line_no++; 47004235Smarkfen if (act_props->pattern[i] == NULL) { 47014235Smarkfen error_message(BAD_ERROR, 47024235Smarkfen IPSEC_CONF_NEGOTIATE, line_no); 47034235Smarkfen return (-1); 47044235Smarkfen } 47054235Smarkfen 47064235Smarkfen if (strncmp(act_props->pattern[i], "tunnel", 6) == 0) { 47074235Smarkfen cptr->ips_tunnel = B_TRUE; 47084235Smarkfen } else if (strncmp( 47094235Smarkfen act_props->pattern[i], "transport", 9) != 0) { 47104235Smarkfen error_message(BAD_ERROR, 47114235Smarkfen IPSEC_CONF_NEGOTIATE, line_no); 47124235Smarkfen return (-1); 47134235Smarkfen } 47144235Smarkfen cptr->has_negotiate = 1; 47154235Smarkfen break; 47164235Smarkfen } 47174235Smarkfen 47184235Smarkfen } 47194235Smarkfen 47204235Smarkfen /* Sanity check that certain tokens occur together */ 47214235Smarkfen if (cptr->has_tunnel + cptr->has_negotiate == 1) { 47224235Smarkfen if (cptr->has_negotiate == 0) { 47234235Smarkfen error_message(REQ_ERROR, IPSEC_CONF_NEGOTIATE, line_no); 47244235Smarkfen } else { 47254235Smarkfen error_message(REQ_ERROR, IPSEC_CONF_TUNNEL, line_no); 47264235Smarkfen } 47274235Smarkfen errx(1, gettext( 47284235Smarkfen "tunnel and negotiate tokens must occur together")); 47294235Smarkfen return (-1); 47304235Smarkfen } 47314235Smarkfen 47324235Smarkfen /* 47334235Smarkfen * Get the actions. 47344235Smarkfen */ 47354235Smarkfen 47364235Smarkfen for (ap_num = 0; act_props->ap[ap_num].act != NULL; ap_num++) { 47374235Smarkfen ips_act_props_t *iap; 47384235Smarkfen 47394235Smarkfen if (ap_num > 0) { 47404235Smarkfen /* or's only with new style */ 47414235Smarkfen if (old_style) { 47424235Smarkfen (void) printf("%s\n", gettext( 47434235Smarkfen "or's only with new style")); 47444235Smarkfen return (-1); 47454235Smarkfen } 47464235Smarkfen new_style = B_TRUE; 47474235Smarkfen } 47484235Smarkfen 474910372Sdanmcd@sun.com ipsec_aalg = ipsec_ealg = ipsec_eaalg = auth_covered = B_FALSE; 47504235Smarkfen tok_count = 0; 47514235Smarkfen 47524235Smarkfen for (k = 0; action_table[k].string; k++) { 47534235Smarkfen if (strcmp(act_props->ap[ap_num].act, 47544235Smarkfen action_table[k].string) == 0) 47554235Smarkfen break; 47564235Smarkfen } 47574235Smarkfen /* 47584235Smarkfen * The following thing should never happen as 47594235Smarkfen * we have already tested for its validity in parse. 47604235Smarkfen */ 47614235Smarkfen if (action_table[k].string == NULL) { 47624235Smarkfen warnx(gettext("(form act)Invalid action on line " 47634235Smarkfen "%d: %s"), (arg_indices[line_no] == 0) ? 1 : 47644235Smarkfen arg_indices[line_no], 47654235Smarkfen act_props->ap[ap_num].act); 47664235Smarkfen warnx("%s", act_props->ap[ap_num].act); 47674235Smarkfen return (-1); 47684235Smarkfen } 47694235Smarkfen 47704235Smarkfen /* we have a good action alloc an iap */ 47714235Smarkfen iap = alloc_iap(cptr); 47724235Smarkfen 47734235Smarkfen iap->iap_action = action_table[k].value; 47744235Smarkfen iap->iap_act_tok = action_table[k].tok_val; 47754235Smarkfen 47764235Smarkfen switch (action_table[k].tok_val) { 47774235Smarkfen case TOK_apply: 47784235Smarkfen cptr->ips_dir = SPD_RULE_FLAG_OUTBOUND; 47794235Smarkfen break; 47804235Smarkfen case TOK_permit: 47814235Smarkfen cptr->ips_dir = SPD_RULE_FLAG_INBOUND; 47824235Smarkfen break; 47834235Smarkfen case TOK_ipsec: 47844235Smarkfen if (old_style) { 47854235Smarkfen /* Using saddr/daddr with ipsec action. */ 47864235Smarkfen if (!dir) { 47874235Smarkfen /* No direction specified */ 47884235Smarkfen error_message(REQ_ERROR, 47894235Smarkfen IPSEC_CONF_IPSEC_DIR, line_no); 47904235Smarkfen return (-1); 47914235Smarkfen } 47924235Smarkfen if (cptr->ips_dir == SPD_RULE_FLAG_INBOUND) 47934235Smarkfen /* 47944235Smarkfen * Need to swap addresses if 47954235Smarkfen * 'dir in' or translation to 47964235Smarkfen * laddr/raddr will be incorrect. 47974235Smarkfen */ 47984235Smarkfen cptr->swap = 1; 47994235Smarkfen } 48004235Smarkfen if (!dir) 48014235Smarkfen cptr->ips_dir = 48024235Smarkfen SPD_RULE_FLAG_INBOUND 48034235Smarkfen |SPD_RULE_FLAG_OUTBOUND; 48044235Smarkfen break; 48054235Smarkfen case TOK_bypass: 480610372Sdanmcd@sun.com case TOK_drop: 480710372Sdanmcd@sun.com is_no_alg = B_TRUE; 48084235Smarkfen break; 48094235Smarkfen } 48104235Smarkfen 48114235Smarkfen line_no++; 48124235Smarkfen /* 48134235Smarkfen * Get the properties. NULL properties is not valid. 48144235Smarkfen * Later checks will catch it. 48154235Smarkfen */ 48164235Smarkfen for (i = 0; act_props->ap[ap_num].prop[i]; i++, line_no++) { 48174235Smarkfen for (j = 0; property_table[j].string; j++) { 48184235Smarkfen if (strcmp(act_props->ap[ap_num].prop[i], 48194235Smarkfen property_table[j].string) == 0) { 48204235Smarkfen break; 48214235Smarkfen } 48224235Smarkfen } 48234235Smarkfen if (property_table[j].string == NULL) { 48244235Smarkfen warnx(gettext("Invalid properties on line " 48254235Smarkfen "%d: %s"), 48265120Smarkfen (arg_indices[line_no] == 0) ? 48274235Smarkfen 1 : arg_indices[line_no], 48284235Smarkfen act_props->ap[ap_num].prop[i]); 48294235Smarkfen return (-1); 48304235Smarkfen } 48314235Smarkfen 48324235Smarkfen iap->iap_attr_tok[tok_count++] 48334235Smarkfen = property_table[j].value; 48344235Smarkfen 48354235Smarkfen switch (property_table[j].value) { 48364235Smarkfen case SPD_ATTR_AH_AUTH: 48374235Smarkfen if (ipsec_aalg) { 48384235Smarkfen error_message(DUP_ERROR, 48394235Smarkfen IPSEC_CONF_IPSEC_AALGS, line_no); 48404235Smarkfen return (-1); 48414235Smarkfen } 48424235Smarkfen i++, line_no++; 48434235Smarkfen if (act_props->ap[ap_num].prop[i] == NULL) { 48444235Smarkfen error_message(BAD_ERROR, 48454235Smarkfen IPSEC_CONF_IPSEC_AALGS, line_no); 48464235Smarkfen return (-1); 48474235Smarkfen } 48484235Smarkfen ret = parse_ipsec_alg( 48494235Smarkfen act_props->ap[ap_num].prop[i], 48504235Smarkfen iap, SPD_ATTR_AH_AUTH); 48514235Smarkfen if (ret == -2) { 48524235Smarkfen /* "none" - ignore */ 48534235Smarkfen break; 48544235Smarkfen } 48554235Smarkfen if (ret != 0) { 48564235Smarkfen error_message(BAD_ERROR, 48574235Smarkfen IPSEC_CONF_IPSEC_AALGS, line_no); 48584235Smarkfen return (-1); 48594235Smarkfen } 48604235Smarkfen ipsec_aalg = B_TRUE; 486110372Sdanmcd@sun.com auth_covered = B_TRUE; 48624235Smarkfen break; 48634235Smarkfen case SPD_ATTR_ESP_ENCR: 48644235Smarkfen /* 48654235Smarkfen * If this option was not given 48664235Smarkfen * and encr_auth_algs was given, 48674235Smarkfen * we provide null-encryption. We do the 48684235Smarkfen * setting after we parse all the options. 48694235Smarkfen */ 48704235Smarkfen if (ipsec_ealg) { 48714235Smarkfen error_message(DUP_ERROR, 48724235Smarkfen IPSEC_CONF_IPSEC_EALGS, line_no); 48734235Smarkfen return (-1); 48744235Smarkfen } 48754235Smarkfen i++, line_no++; 48764235Smarkfen if (act_props->ap[ap_num].prop[i] == NULL) { 48774235Smarkfen error_message(BAD_ERROR, 48784235Smarkfen IPSEC_CONF_IPSEC_EALGS, line_no); 48794235Smarkfen return (-1); 48804235Smarkfen } 48814235Smarkfen ret = parse_ipsec_alg( 48824235Smarkfen act_props->ap[ap_num].prop[i], 48834235Smarkfen iap, SPD_ATTR_ESP_ENCR); 48844235Smarkfen if (ret == -2) { 48854235Smarkfen /* "none" - ignore */ 48864235Smarkfen break; 48874235Smarkfen } 48884235Smarkfen if (ret != 0) { 48894235Smarkfen error_message(BAD_ERROR, 48904235Smarkfen IPSEC_CONF_IPSEC_EALGS, line_no); 48914235Smarkfen return (-1); 48924235Smarkfen } 4893*10824SMark.Fenwick@Sun.COM is_combined_mode = combined_mode(iap); 48944235Smarkfen ipsec_ealg = B_TRUE; 48954235Smarkfen break; 48964235Smarkfen case SPD_ATTR_ESP_AUTH: 48974235Smarkfen /* 48984235Smarkfen * If this option was not given and encr_algs 48994235Smarkfen * option was given, we still pass a default 49004235Smarkfen * value in ipsc_esp_auth_algs. This is to 49014235Smarkfen * encourage the use of authentication with 49024235Smarkfen * ESP. 49034235Smarkfen */ 49044235Smarkfen if (ipsec_eaalg) { 49054235Smarkfen error_message(DUP_ERROR, 49064235Smarkfen IPSEC_CONF_IPSEC_EAALGS, line_no); 49074235Smarkfen return (-1); 49084235Smarkfen } 49094235Smarkfen i++, line_no++; 49104235Smarkfen if (act_props->ap[ap_num].prop[i] == NULL) { 49114235Smarkfen error_message(BAD_ERROR, 49124235Smarkfen IPSEC_CONF_IPSEC_EAALGS, line_no); 49134235Smarkfen return (-1); 49144235Smarkfen } 49154235Smarkfen ret = parse_ipsec_alg( 49164235Smarkfen act_props->ap[ap_num].prop[i], 49174235Smarkfen iap, SPD_ATTR_ESP_AUTH); 49184235Smarkfen if (ret == -2) { 49194235Smarkfen /* "none" - ignore */ 49204235Smarkfen break; 49214235Smarkfen } 49224235Smarkfen if (ret != 0) { 49234235Smarkfen error_message(BAD_ERROR, 49244235Smarkfen IPSEC_CONF_IPSEC_EAALGS, line_no); 49254235Smarkfen return (-1); 49264235Smarkfen } 49274235Smarkfen ipsec_eaalg = B_TRUE; 492810372Sdanmcd@sun.com auth_covered = B_TRUE; 49294235Smarkfen break; 49304235Smarkfen case IPS_SA: 49314235Smarkfen i++, line_no++; 49324235Smarkfen if (act_props->ap[ap_num].prop[i] == NULL) { 49334235Smarkfen error_message(BAD_ERROR, 49344235Smarkfen IPSEC_CONF_IPSEC_SA, line_no); 49354235Smarkfen return (-1); 49364235Smarkfen } 49374235Smarkfen 49384235Smarkfen if (strcmp(act_props->ap[ap_num].prop[i], 49394235Smarkfen "unique") == 0) { 49404235Smarkfen iap->iap_attr |= SPD_APPLY_UNIQUE; 49414235Smarkfen } else if (strcmp(act_props->ap[ap_num].prop[i], 49424235Smarkfen "shared") != 0) { 49434235Smarkfen /* "shared" is default. */ 49444235Smarkfen error_message(BAD_ERROR, 49454235Smarkfen IPSEC_CONF_IPSEC_SA, line_no); 49464235Smarkfen return (-1); 49474235Smarkfen } 49484235Smarkfen 49494235Smarkfen break; 49504235Smarkfen case IPS_DIR: 49514235Smarkfen if (dir) { 49524235Smarkfen error_message(DUP_ERROR, 49534235Smarkfen IPSEC_CONF_IPSEC_DIR, line_no); 49544235Smarkfen return (-1); 49554235Smarkfen } 49564235Smarkfen if (new_style) { 49574235Smarkfen error_message(BAD_ERROR, 49584235Smarkfen IPSEC_CONF_IPSEC_DIR, line_no); 49594235Smarkfen return (-1); 49604235Smarkfen } 49614235Smarkfen old_style = B_TRUE; 49624235Smarkfen dir = B_TRUE; 49634235Smarkfen i++, line_no++; 49644235Smarkfen if (act_props->ap[ap_num].prop[i] == NULL) { 49654235Smarkfen error_message(BAD_ERROR, 49664235Smarkfen IPSEC_CONF_IPSEC_DIR, line_no); 49674235Smarkfen return (-1); 49684235Smarkfen } 49694235Smarkfen if (strcmp(act_props->ap[ap_num].prop[i], 49704235Smarkfen "out") == 0) { 49714235Smarkfen cptr->ips_dir = SPD_RULE_FLAG_OUTBOUND; 49724235Smarkfen } else if (strcmp(act_props->ap[ap_num].prop[i], 49734235Smarkfen "in") == 0) { 49744235Smarkfen cptr->ips_dir = SPD_RULE_FLAG_INBOUND; 49754235Smarkfen } else { 49764235Smarkfen error_message(BAD_ERROR, 49775120Smarkfen IPSEC_CONF_IPSEC_DIR, line_no); 49784235Smarkfen return (-1); 49794235Smarkfen } 49804235Smarkfen if ((cptr->ips_dir & SPD_RULE_FLAG_INBOUND) && 49815120Smarkfen iap->iap_act_tok == TOK_apply) { 49824235Smarkfen warnx(gettext("Direction" 49834235Smarkfen " in conflict with action")); 49844235Smarkfen return (-1); 49854235Smarkfen } 49864235Smarkfen if ((cptr->ips_dir & SPD_RULE_FLAG_OUTBOUND) && 49875120Smarkfen iap->iap_act_tok == TOK_permit) { 49884235Smarkfen warnx(gettext("Direction" 49894235Smarkfen "in conflict with action")); 49904235Smarkfen return (-1); 49914235Smarkfen } 49924235Smarkfen 49934235Smarkfen break; 49944235Smarkfen } 49954235Smarkfen } 49964235Smarkfen 4997*10824SMark.Fenwick@Sun.COM if (is_combined_mode) { 4998*10824SMark.Fenwick@Sun.COM if (ipsec_eaalg) { 4999*10824SMark.Fenwick@Sun.COM warnx(gettext("ERROR: Rule on line %d: " 5000*10824SMark.Fenwick@Sun.COM "Combined mode and esp authentication not " 5001*10824SMark.Fenwick@Sun.COM "supported together."), 5002*10824SMark.Fenwick@Sun.COM arg_indices[line_no] == 0 ? 1 : 5003*10824SMark.Fenwick@Sun.COM arg_indices[line_no]); 5004*10824SMark.Fenwick@Sun.COM return (-1); 5005*10824SMark.Fenwick@Sun.COM } 5006*10824SMark.Fenwick@Sun.COM auth_covered = B_TRUE; 5007*10824SMark.Fenwick@Sun.COM } 500810372Sdanmcd@sun.com /* Warn here about no authentication! */ 500910372Sdanmcd@sun.com if (!auth_covered && !is_no_alg) { 501010372Sdanmcd@sun.com warnx(gettext("DANGER: Rule on line %d " 501110372Sdanmcd@sun.com "has encryption with no authentication."), 501210372Sdanmcd@sun.com arg_indices[line_no] == 0 ? 1 : 501310372Sdanmcd@sun.com arg_indices[line_no]); 501410372Sdanmcd@sun.com } 501510372Sdanmcd@sun.com 50164235Smarkfen if (!ipsec_ealg && ipsec_eaalg) { 50174235Smarkfen /* 50184235Smarkfen * If the user has specified the auth alg to be used 50194235Smarkfen * with encryption and did not provide a encryption 50204235Smarkfen * algorithm, provide null encryption. 50214235Smarkfen */ 50224235Smarkfen iap->iap_eencr.alg_id = SADB_EALG_NULL; 50234235Smarkfen ipsec_ealg = B_TRUE; 50244235Smarkfen } 50254235Smarkfen 50264235Smarkfen /* Set the level of IPSEC protection we want */ 50274235Smarkfen if (ipsec_aalg && (ipsec_ealg || ipsec_eaalg)) { 50284235Smarkfen iap->iap_attr |= SPD_APPLY_AH|SPD_APPLY_ESP; 50294235Smarkfen } else if (ipsec_aalg) { 50304235Smarkfen iap->iap_attr |= SPD_APPLY_AH; 50314235Smarkfen } else if (ipsec_ealg || ipsec_eaalg) { 50324235Smarkfen iap->iap_attr |= SPD_APPLY_ESP; 50334235Smarkfen } 50344235Smarkfen 50354235Smarkfen /* convert src/dst to local/remote */ 50364235Smarkfen if (!new_style) { 50374235Smarkfen switch (cptr->ips_acts->iap_act_tok) { 50384235Smarkfen case TOK_apply: 50394235Smarkfen /* outbound */ 50404235Smarkfen /* src=local, dst=remote */ 50414235Smarkfen /* this is ok. */ 50424235Smarkfen break; 50434235Smarkfen 50444235Smarkfen case TOK_permit: 50454235Smarkfen /* inbound */ 50464235Smarkfen /* src=remote, dst=local */ 50474235Smarkfen /* switch */ 50484235Smarkfen cptr->swap = 1; 50494235Smarkfen break; 50504235Smarkfen case TOK_bypass: 50514235Smarkfen case TOK_drop: 50524235Smarkfen /* check the direction for what to do */ 50534235Smarkfen if (cptr->ips_dir == SPD_RULE_FLAG_INBOUND) 50544235Smarkfen cptr->swap = 1; 50554235Smarkfen break; 50564235Smarkfen default: 50574235Smarkfen break; 50584235Smarkfen } 50594235Smarkfen } 50604235Smarkfen /* Validate the properties */ 50614235Smarkfen if (ret = validate_properties(iap, dir, 50624235Smarkfen (ipsec_aalg || ipsec_ealg || ipsec_eaalg))) { 50634235Smarkfen return (ret); 50644235Smarkfen } 50654235Smarkfen } 50664235Smarkfen 50674235Smarkfen return (0); 50684235Smarkfen 50694235Smarkfen } 50704235Smarkfen 50714235Smarkfen static int 50724235Smarkfen print_cmd_buf(FILE *fp, int error) 50734235Smarkfen { 50744235Smarkfen *(cbuf + cbuf_offset) = '\0'; 50754235Smarkfen 50764235Smarkfen if (fp == stderr) { 50774235Smarkfen if (error != EEXIST) { 50784235Smarkfen warnx(gettext("Malformed command (fatal):\n%s"), cbuf); 50794235Smarkfen return (0); 50804235Smarkfen } 50814235Smarkfen if (ipsecconf_qflag) { 50824235Smarkfen return (0); 50834235Smarkfen } 50844235Smarkfen warnx(gettext("Duplicate policy entry (ignored):\n%s"), cbuf); 50854235Smarkfen } else { 50864235Smarkfen if (fprintf(fp, "%s", cbuf) == -1) { 50874235Smarkfen warn("fprintf"); 50884235Smarkfen return (-1); 50894235Smarkfen } 50904235Smarkfen } 50914235Smarkfen 50924235Smarkfen return (0); 50934235Smarkfen } 50944235Smarkfen 50954235Smarkfen #ifdef DEBUG 50964235Smarkfen 50974235Smarkfen static uchar_t * 50984235Smarkfen addr_ptr(int isv4, struct in6_addr *addr6, struct in_addr *addr4) 50994235Smarkfen { 51004235Smarkfen if (isv4) { 51014235Smarkfen IN6_V4MAPPED_TO_INADDR(addr6, addr4); 51024235Smarkfen return ((uchar_t *)&addr4->s_addr); 51034235Smarkfen } else { 51044235Smarkfen return ((uchar_t *)&addr6->s6_addr); 51054235Smarkfen } 51064235Smarkfen } 51074235Smarkfen 51084235Smarkfen static void 51094235Smarkfen dump_algreq(const char *tag, algreq_t *alg) 51104235Smarkfen { 51114235Smarkfen (void) printf("%s algid %d, bits %d..%d\n", 51124235Smarkfen tag, alg->alg_id, alg->alg_minbits, alg->alg_maxbits); 51134235Smarkfen } 51144235Smarkfen 51154235Smarkfen static void 51164235Smarkfen dump_conf(ips_conf_t *conf) 51174235Smarkfen { 51184235Smarkfen boolean_t isv4 = conf->ips_isv4; 51194235Smarkfen struct in_addr addr; 51204235Smarkfen char buf[INET6_ADDRSTRLEN]; 51214235Smarkfen int af; 51224235Smarkfen ips_act_props_t *iap = conf->ips_acts; 51234235Smarkfen 51244235Smarkfen af = isv4 ? AF_INET : AF_INET6; 51254235Smarkfen 51264235Smarkfen (void) printf("Source Addr is %s\n", 51274235Smarkfen inet_ntop(af, addr_ptr(isv4, &conf->ips_src_addr_v6, &addr), 51285120Smarkfen buf, INET6_ADDRSTRLEN)); 51294235Smarkfen 51304235Smarkfen (void) printf("Dest Addr is %s\n", 51314235Smarkfen inet_ntop(af, addr_ptr(isv4, &conf->ips_dst_addr_v6, &addr), 51325120Smarkfen buf, INET6_ADDRSTRLEN)); 51334235Smarkfen 51344235Smarkfen (void) printf("Source Mask is %s\n", 51354235Smarkfen inet_ntop(af, addr_ptr(isv4, &conf->ips_src_mask_v6, &addr), 51365120Smarkfen buf, INET6_ADDRSTRLEN)); 51374235Smarkfen 51384235Smarkfen (void) printf("Dest Mask is %s\n", 51394235Smarkfen inet_ntop(af, addr_ptr(isv4, &conf->ips_dst_mask_v6, &addr), 51405120Smarkfen buf, INET6_ADDRSTRLEN)); 51414235Smarkfen 51424235Smarkfen (void) printf("Source port %d\n", ntohs(conf->ips_src_port_min)); 51434235Smarkfen (void) printf("Dest port %d\n", ntohs(conf->ips_dst_port_min)); 51444235Smarkfen (void) printf("ULP %d\n", conf->ips_ulp_prot); 51454235Smarkfen 51464235Smarkfen (void) printf("ICMP type %d-%d code %d-%d", conf->ips_icmp_type, 51474235Smarkfen conf->ips_icmp_type_end, 51484235Smarkfen conf->ips_icmp_code, 51494235Smarkfen conf->ips_icmp_code_end); 51504235Smarkfen 51514235Smarkfen while (iap != NULL) { 51524235Smarkfen (void) printf("------------------------------------\n"); 51534235Smarkfen (void) printf("IPsec act is %d\n", iap->iap_action); 51544235Smarkfen (void) printf("IPsec attr is %d\n", iap->iap_attr); 51554235Smarkfen dump_algreq("AH authentication", &iap->iap_aauth); 51564235Smarkfen dump_algreq("ESP authentication", &iap->iap_eauth); 51574235Smarkfen dump_algreq("ESP encryption", &iap->iap_eencr); 51584235Smarkfen (void) printf("------------------------------------\n"); 51594235Smarkfen iap = iap->iap_next; 51604235Smarkfen } 51614235Smarkfen 51624235Smarkfen (void) fflush(stdout); 51634235Smarkfen } 51644235Smarkfen #endif /* DEBUG */ 51654235Smarkfen 51664235Smarkfen 51674235Smarkfen static int 51684235Smarkfen ipsec_conf_add(boolean_t just_check, boolean_t smf_managed) 51694235Smarkfen { 51704235Smarkfen act_prop_t *act_props = malloc(sizeof (act_prop_t)); 51714235Smarkfen ips_conf_t conf; 51724235Smarkfen FILE *fp, *policy_fp; 51734235Smarkfen int ret, flushret, i, j, diag, num_rules, good_rules; 51744235Smarkfen char *warning = gettext( 51755120Smarkfen "\tWARNING : New policy entries that are being added may\n " 51765120Smarkfen "\taffect the existing connections. Existing connections\n" 51775120Smarkfen "\tthat are not subjected to policy constraints, may be\n" 51785120Smarkfen "\tsubjected to policy constraints because of the new\n" 51795120Smarkfen "\tpolicy. This can disrupt the communication of the\n" 51805120Smarkfen "\texisting connections.\n\n"); 51814235Smarkfen 51824235Smarkfen boolean_t first_time = B_TRUE; 51834235Smarkfen num_rules = 0; 51844235Smarkfen good_rules = 0; 51854235Smarkfen 51864235Smarkfen if (act_props == NULL) { 51874235Smarkfen warn(gettext("memory")); 51884235Smarkfen return (-1); 51894235Smarkfen } 51904235Smarkfen 51914235Smarkfen if (strcmp(filename, "-") == 0) 51924235Smarkfen fp = stdin; 51934235Smarkfen else 51944235Smarkfen fp = fopen(filename, "r"); 51954235Smarkfen 51964235Smarkfen /* 51974235Smarkfen * Treat the non-existence of a policy file as a special 51984235Smarkfen * case when ipsecconf is being managed by smf(5). 51994235Smarkfen * The assumption is the administrator has not yet 52004235Smarkfen * created a policy file, this should not force the service 52014235Smarkfen * into maintenance mode. 52024235Smarkfen */ 52034235Smarkfen 52044235Smarkfen if (fp == NULL) { 52054235Smarkfen if (smf_managed) { 52064235Smarkfen (void) fprintf(stdout, gettext( 52074235Smarkfen "Policy configuration file (%s) does not exist.\n" 52084235Smarkfen "IPsec policy not configured.\n"), filename); 52094235Smarkfen return (0); 52104235Smarkfen } 52114235Smarkfen warn(gettext("%s : Policy config file cannot be opened"), 52124235Smarkfen filename); 52134235Smarkfen usage(); 52144235Smarkfen return (-1); 52154235Smarkfen } 52164235Smarkfen /* 52174235Smarkfen * This will create the file if it does not exist. 52184235Smarkfen * Make sure the umask is right. 52194235Smarkfen */ 52204235Smarkfen (void) umask(0022); 52214235Smarkfen policy_fp = fopen(POLICY_CONF_FILE, "a"); 52224235Smarkfen if (policy_fp == NULL) { 52234235Smarkfen warn(gettext("%s cannot be opened"), POLICY_CONF_FILE); 52244235Smarkfen return (-1); 52254235Smarkfen } 52264235Smarkfen 52274235Smarkfen /* 52284235Smarkfen * Pattern, action, and properties are allocated in 52294235Smarkfen * parse_pattern_or_prop and in parse_action (called by 52304235Smarkfen * parse_one) as we parse arguments. 52314235Smarkfen */ 52325120Smarkfen while ((ret = parse_one(fp, act_props)) != PARSE_EOF) { 52335120Smarkfen num_rules++; 52345120Smarkfen if (ret != 0) { 52355120Smarkfen (void) print_cmd_buf(stderr, NOERROR); 52365120Smarkfen continue; 52375120Smarkfen } 52384235Smarkfen 52394235Smarkfen /* 52404235Smarkfen * If there is no action and parse returned success, 52414235Smarkfen * it means that there is nothing to add. 52424235Smarkfen */ 52434235Smarkfen if (act_props->pattern[0] == NULL && 52444235Smarkfen act_props->ap[0].act == NULL) 52454235Smarkfen break; 52464235Smarkfen 52474235Smarkfen ret = form_ipsec_conf(act_props, &conf); 52484235Smarkfen if (ret != 0) { 52494235Smarkfen warnx(gettext("form_ipsec_conf error")); 52504235Smarkfen (void) print_cmd_buf(stderr, NOERROR); 52514475Spwernau /* Reset globals before trying the next rule. */ 52524475Spwernau if (shp != NULL) { 52534475Spwernau freehostent(shp); 52544475Spwernau shp = NULL; 52554475Spwernau } 52564475Spwernau if (dhp != NULL) { 52574475Spwernau freehostent(dhp); 52584475Spwernau dhp = NULL; 52594475Spwernau } 52604475Spwernau splen = 0; 52614475Spwernau dplen = 0; 52624235Smarkfen continue; 52634235Smarkfen } 52644235Smarkfen 52654235Smarkfen good_rules++; 52664235Smarkfen 52674235Smarkfen if (first_time) { 52684235Smarkfen /* 52694235Smarkfen * Time to assume that there are valid policy entries. 52704235Smarkfen * If the IPsec kernel modules are not loaded this 52714235Smarkfen * will load them now. 52724235Smarkfen */ 52734235Smarkfen first_time = B_FALSE; 52744235Smarkfen fetch_algorithms(); 52754235Smarkfen ipsec_conf_admin(SPD_CLONE); 52764235Smarkfen } 52774235Smarkfen 52784235Smarkfen /* 52794235Smarkfen * shp, dhp, splen, and dplen are globals set by 52804235Smarkfen * form_ipsec_conf() while parsing the addresses. 52814235Smarkfen */ 52824235Smarkfen if (shp == NULL && dhp == NULL) { 52834235Smarkfen switch (do_port_adds(&conf)) { 52844235Smarkfen case 0: 52854235Smarkfen /* no error */ 52864235Smarkfen break; 52874235Smarkfen case EEXIST: 52884235Smarkfen /* duplicate entries, continue adds */ 52894235Smarkfen (void) print_cmd_buf(stderr, EEXIST); 52904235Smarkfen goto next; 52914235Smarkfen default: 52924235Smarkfen /* other error, bail */ 52934235Smarkfen ret = -1; 52944235Smarkfen goto bail; 52954235Smarkfen } 52964235Smarkfen } else { 52974235Smarkfen ret = do_address_adds(&conf, &diag); 52984235Smarkfen switch (ret) { 52994235Smarkfen case 0: 53004235Smarkfen /* no error. */ 53014235Smarkfen break; 53024235Smarkfen case EEXIST: 53034235Smarkfen (void) print_cmd_buf(stderr, EEXIST); 53044235Smarkfen goto next; 53054235Smarkfen case EBUSY: 53064235Smarkfen warnx(gettext( 53075120Smarkfen "Can't set mask and /NN prefix.")); 53084235Smarkfen ret = -1; 53094235Smarkfen break; 53104235Smarkfen case ENOENT: 53114235Smarkfen warnx(gettext("Cannot find tunnel " 53124235Smarkfen "interface %s."), interface_name); 53134235Smarkfen ret = -1; 53144235Smarkfen break; 53154235Smarkfen case EINVAL: 53164235Smarkfen /* 53174235Smarkfen * PF_POLICY didn't like what we sent. We 53184235Smarkfen * can't check all input up here, but we 53194235Smarkfen * do in-kernel. 53204235Smarkfen */ 53214235Smarkfen warnx(gettext("PF_POLICY invalid input:\n\t%s"), 53224235Smarkfen spdsock_diag(diag)); 53234235Smarkfen break; 53244235Smarkfen case EOPNOTSUPP: 53254235Smarkfen warnx(gettext("Can't set /NN" 53265120Smarkfen " prefix on multi-host name.")); 53274235Smarkfen ret = -1; 53284235Smarkfen break; 53294235Smarkfen case ERANGE: 53304235Smarkfen warnx(gettext("/NN prefix is too big!")); 53314235Smarkfen ret = -1; 53324235Smarkfen break; 53334235Smarkfen case ESRCH: 53344235Smarkfen warnx(gettext("No matching IPv4 or " 53355120Smarkfen "IPv6 saddr/daddr pairs")); 53364235Smarkfen ret = -1; 53374235Smarkfen break; 53384235Smarkfen default: 53394235Smarkfen /* Should never get here. */ 53404235Smarkfen errno = ret; 53414235Smarkfen warn(gettext("Misc. error")); 53424235Smarkfen ret = -1; 53434235Smarkfen } 53444235Smarkfen if (ret == -1) 53454235Smarkfen goto bail; 53464235Smarkfen } 53474235Smarkfen 53484235Smarkfen /* 53494235Smarkfen * Go ahead and add policy entries to config file. 53504235Smarkfen * The # should help re-using the ipsecpolicy.conf 53514235Smarkfen * for input again as # will be treated as comment. 53524235Smarkfen */ 53534235Smarkfen if (fprintf(policy_fp, "%s %lld \n", INDEX_TAG, 53544235Smarkfen conf.ips_policy_index) == -1) { 53554235Smarkfen warn("fprintf"); 53564235Smarkfen warnx(gettext("Addition incomplete, Please " 53574235Smarkfen "flush all the entries and re-configure :")); 53584235Smarkfen reconfigure(); 53594235Smarkfen ret = -1; 53604235Smarkfen break; 53614235Smarkfen } 53624235Smarkfen if (print_cmd_buf(policy_fp, NOERROR) == -1) { 53634235Smarkfen warnx(gettext("Addition incomplete. Please " 53644235Smarkfen "flush all the entries and re-configure :")); 53654235Smarkfen reconfigure(); 53664235Smarkfen ret = -1; 53674235Smarkfen break; 53684235Smarkfen } 53694235Smarkfen /* 53704235Smarkfen * We add one newline by default to separate out the 53714235Smarkfen * entries. If the last character is not a newline, we 53724235Smarkfen * insert a newline for free. This makes sure that all 53734235Smarkfen * entries look consistent in the file. 53744235Smarkfen */ 53754235Smarkfen if (*(cbuf + cbuf_offset - 1) == '\n') { 53764235Smarkfen if (fprintf(policy_fp, "\n") == -1) { 53774235Smarkfen warn("fprintf"); 53784235Smarkfen warnx(gettext("Addition incomplete. " 53794235Smarkfen "Please flush all the entries and " 53804235Smarkfen "re-configure :")); 53814235Smarkfen reconfigure(); 53824235Smarkfen ret = -1; 53834235Smarkfen break; 53844235Smarkfen } 53854235Smarkfen } else { 53864235Smarkfen if (fprintf(policy_fp, "\n\n") == -1) { 53874235Smarkfen warn("fprintf"); 53884235Smarkfen warnx(gettext("Addition incomplete. " 53894235Smarkfen "Please flush all the entries and " 53904235Smarkfen "re-configure :")); 53914235Smarkfen reconfigure(); 53924235Smarkfen ret = -1; 53934235Smarkfen break; 53944235Smarkfen } 53954235Smarkfen } 53964235Smarkfen next: 53974235Smarkfen /* 53984235Smarkfen * Make sure this gets to the disk before 53994235Smarkfen * we parse the next entry. 54004235Smarkfen */ 54014235Smarkfen (void) fflush(policy_fp); 54024235Smarkfen for (i = 0; act_props->pattern[i] != NULL; i++) 54034235Smarkfen free(act_props->pattern[i]); 54044235Smarkfen for (j = 0; act_props->ap[j].act != NULL; j++) { 54054235Smarkfen free(act_props->ap[j].act); 54064235Smarkfen for (i = 0; act_props->ap[j].prop[i] != NULL; i++) 54074235Smarkfen free(act_props->ap[j].prop[i]); 54084235Smarkfen } 54094235Smarkfen } 54105120Smarkfen if (ret == PARSE_EOF) 54115120Smarkfen ret = 0; /* Not an error */ 54124235Smarkfen bail: 54134235Smarkfen if (ret == -1) { 54144235Smarkfen (void) print_cmd_buf(stderr, EINVAL); 54154235Smarkfen for (i = 0; act_props->pattern[i] != NULL; i++) 54164235Smarkfen free(act_props->pattern[i]); 54174235Smarkfen for (j = 0; act_props->ap[j].act != NULL; j++) { 54184235Smarkfen free(act_props->ap[j].act); 54194235Smarkfen for (i = 0; act_props->ap[j].prop[i] != NULL; i++) 54204235Smarkfen free(act_props->ap[j].prop[i]); 54214235Smarkfen } 54224235Smarkfen } 54234235Smarkfen #ifdef DEBUG_HEAVY 54244235Smarkfen (void) printf("ipsec_conf_add: ret val = %d\n", ret); 54254235Smarkfen (void) fflush(stdout); 54264235Smarkfen #endif 54275120Smarkfen if (num_rules == 0 && ret == 0) { 54284475Spwernau nuke_adds(); 54294235Smarkfen (void) restore_all_signals(); 54304235Smarkfen (void) unlock(lfd); 54314235Smarkfen EXIT_OK("Policy file does not contain any valid rules."); 54324235Smarkfen } 54334235Smarkfen if (num_rules != good_rules) { 54344235Smarkfen /* This is an error */ 54354475Spwernau nuke_adds(); 54364235Smarkfen (void) restore_all_signals(); 54374235Smarkfen (void) unlock(lfd); 54384235Smarkfen EXIT_BADCONFIG2("%d policy rule(s) contained errors.", 54394235Smarkfen num_rules - good_rules); 54404235Smarkfen } 54414235Smarkfen /* looks good, flip it in */ 54424235Smarkfen if (ret == 0 && !just_check) { 54434235Smarkfen if (!ipsecconf_qflag) { 54444235Smarkfen (void) printf("%s", warning); 54454235Smarkfen } 54465120Smarkfen if (smf_managed) 54475120Smarkfen warnx(gettext("%d policy rules added."), good_rules); 54484235Smarkfen ipsec_conf_admin(SPD_FLIP); 54494235Smarkfen } else { 54504235Smarkfen nuke_adds(); 54514235Smarkfen if (just_check) { 54525120Smarkfen (void) fprintf(stdout, gettext("IPsec configuration " 54535120Smarkfen "does not contain any errors.\n")); 54544235Smarkfen (void) fprintf(stdout, gettext( 54554235Smarkfen "IPsec policy was not modified.\n")); 54564235Smarkfen (void) fflush(stdout); 54574235Smarkfen } 54584235Smarkfen } 54594235Smarkfen flushret = ipsec_conf_flush(SPD_STANDBY); 54604235Smarkfen if (flushret != 0) 54614235Smarkfen return (flushret); 54624235Smarkfen return (ret); 54634235Smarkfen } 54644235Smarkfen 54654235Smarkfen 54664235Smarkfen static int 54674235Smarkfen ipsec_conf_sub() 54684235Smarkfen { 54694235Smarkfen act_prop_t *act_props = malloc(sizeof (act_prop_t)); 54704235Smarkfen FILE *remove_fp, *policy_fp; 54714235Smarkfen char rbuf[MAXLEN], pbuf[MAXLEN], /* remove buffer, and policy buffer */ 54724235Smarkfen *warning = gettext( 54735120Smarkfen "\tWARNING: Policy entries that are being removed may\n" 54745120Smarkfen "\taffect the existing connections. Existing connections\n" 54755120Smarkfen "\tthat are subjected to policy constraints may no longer\n" 54765120Smarkfen "\tbe subjected to policy contraints because of its\n" 54775120Smarkfen "\tremoval. This can compromise security, and disrupt\n" 54785120Smarkfen "\tthe communication of the existing connection.\n" 54795120Smarkfen "\tConnections that are latched will remain unaffected\n" 54805120Smarkfen "\tuntil they close.\n"); 54814235Smarkfen int ret = 0; 54824235Smarkfen int index_len, pindex = 0; /* init value in case of pfile error */ 54834235Smarkfen 54844235Smarkfen if (act_props == NULL) { 54854235Smarkfen warn(gettext("memory")); 54864235Smarkfen return (-1); 54874235Smarkfen } 54884235Smarkfen 54894235Smarkfen /* clone into standby DB */ 54904235Smarkfen (void) ipsec_conf_admin(SPD_CLONE); 54914235Smarkfen 54924235Smarkfen if (strcmp(filename, "-") == 0) 54934235Smarkfen remove_fp = stdin; 54944235Smarkfen else 54954235Smarkfen remove_fp = fopen(filename, "r"); 54964235Smarkfen 54974235Smarkfen if (remove_fp == NULL) { 54984235Smarkfen warn(gettext("%s : Input file cannot be opened"), filename); 54994235Smarkfen usage(); 55004235Smarkfen free(act_props); 55014235Smarkfen return (-1); 55024235Smarkfen } 55034235Smarkfen 55044235Smarkfen /* open policy file so we can locate the correct policy */ 55054235Smarkfen (void) umask(0022); /* in case it gets created! */ 55064235Smarkfen policy_fp = fopen(POLICY_CONF_FILE, "r+"); 55074235Smarkfen if (policy_fp == NULL) { 55084235Smarkfen warn(gettext("%s cannot be opened"), POLICY_CONF_FILE); 55094235Smarkfen (void) fclose(remove_fp); 55104235Smarkfen free(act_props); 55114235Smarkfen return (-1); 55124235Smarkfen } 55134235Smarkfen 55144235Smarkfen /* don't print the warning if we're in q[uiet] mode */ 55154235Smarkfen if (!ipsecconf_qflag) 55164235Smarkfen (void) printf("%s", warning); 55174235Smarkfen 55184235Smarkfen /* this bit is done primarily so we can read what we write */ 55194235Smarkfen index_len = strlen(INDEX_TAG); 55204235Smarkfen 55214235Smarkfen /* 55224235Smarkfen * We want to look for the policy in rbuf in the policy file. 55234235Smarkfen * Go through the list of policies to remove, locating each one. 55244235Smarkfen */ 55254235Smarkfen while (fgets(rbuf, MAXLEN, remove_fp) != NULL) { 55264235Smarkfen char *buf; 55274235Smarkfen int offset, prev_offset, prev_prev_offset, nlines; 55284235Smarkfen fpos_t ipos; 55294235Smarkfen int pbuf_len = 0; 55304235Smarkfen char *tmp; 55314235Smarkfen /* skip blanks here (so we don't need to do it below)! */ 55325120Smarkfen for (tmp = rbuf; (*tmp != '\0') && isspace(*tmp); ) 55335120Smarkfen tmp++; 55345120Smarkfen 55354235Smarkfen if (*tmp == '\0') 55365120Smarkfen continue; /* while(); */ 55374235Smarkfen 55384235Smarkfen /* skip the INDEX_TAG lines in the remove buffer */ 55394235Smarkfen if (strncasecmp(rbuf, INDEX_TAG, index_len) == 0) 55404235Smarkfen continue; 55414235Smarkfen 55424235Smarkfen /* skip commented lines */ 55434235Smarkfen if (*tmp == '#') 55445120Smarkfen continue; /* while(); */ 55454235Smarkfen 55464235Smarkfen /* 55474235Smarkfen * We start by presuming only good policies are in the pfile, 55484235Smarkfen * and so only good policies from the rfile will match them. 55494235Smarkfen * ipsec_conf_del ensures this later by calling parse_one() on 55504235Smarkfen * pfile before it deletes the entry. 55514235Smarkfen */ 55524235Smarkfen for (offset = prev_offset = prev_prev_offset = 0; 55534235Smarkfen fgets(pbuf, MAXLEN, policy_fp) != NULL; 55544235Smarkfen offset += pbuf_len) { 55554235Smarkfen prev_offset = offset; 55564235Smarkfen pbuf_len = strlen(pbuf); 55574235Smarkfen 55584235Smarkfen /* skip blank lines which seperate policy entries */ 55594235Smarkfen if (pbuf[0] == '\n') 55604235Smarkfen continue; 55614235Smarkfen 55624235Smarkfen /* if we found an index, save it */ 55634235Smarkfen if (strncasecmp(pbuf, INDEX_TAG, index_len) == 0) { 55644235Smarkfen buf = pbuf + index_len; 55654235Smarkfen buf++; 55664235Smarkfen if ((pindex = parse_index(buf, NULL)) == -1) { 55674235Smarkfen /* bad index, we can't continue */ 55684235Smarkfen warnx(gettext( 55695120Smarkfen "Invalid index in the file")); 55704235Smarkfen (void) fclose(remove_fp); 55714235Smarkfen (void) fclose(policy_fp); 55724235Smarkfen free(act_props); 55734235Smarkfen return (-1); 55744235Smarkfen } 55754235Smarkfen 55764235Smarkfen /* save this position in case it's the one */ 55774235Smarkfen if (fgetpos(policy_fp, &ipos) != 0) { 55784235Smarkfen (void) fclose(remove_fp); 55794235Smarkfen (void) fclose(policy_fp); 55804235Smarkfen free(act_props); 55814235Smarkfen return (-1); 55824235Smarkfen } 55834235Smarkfen } 55844235Smarkfen 55854235Smarkfen /* Does pbuf contain the remove policy? */ 55864235Smarkfen if (strncasecmp(rbuf, pbuf, pbuf_len) == 0) { 55874235Smarkfen /* we found the one to remove! */ 55884235Smarkfen if (pindex == 0) { 55894235Smarkfen warnx(gettext("Didn't find a valid " 55904235Smarkfen "index for policy")); 55914235Smarkfen (void) fclose(remove_fp); 55924235Smarkfen (void) fclose(policy_fp); 55934235Smarkfen free(act_props); 55944235Smarkfen return (-1); 55954235Smarkfen } 55964235Smarkfen 55974235Smarkfen /* off it - back up to the last INDEX! */ 55984235Smarkfen if (fsetpos(policy_fp, &ipos) != 0) { 55994235Smarkfen (void) fclose(remove_fp); 56004235Smarkfen (void) fclose(policy_fp); 56014235Smarkfen free(act_props); 56024235Smarkfen return (-1); 56034235Smarkfen } 56044235Smarkfen 56054235Smarkfen /* parse_one sets linecount = #lines to off */ 56064235Smarkfen if (parse_one(policy_fp, act_props) == -1) { 56074235Smarkfen warnx(gettext("Invalid policy entry " 56084235Smarkfen "in the file")); 56094235Smarkfen (void) fclose(remove_fp); 56104235Smarkfen (void) fclose(policy_fp); 56114235Smarkfen free(act_props); 56124235Smarkfen return (-1); 56134235Smarkfen } 56144235Smarkfen 56154235Smarkfen nlines = linecount + 2; 56164235Smarkfen goto delete; 56174235Smarkfen } 56184235Smarkfen /* 56194235Smarkfen * When we find a match, we want to pass the offset 56204235Smarkfen * of the line that is before it - the INDEX_TAG line. 56214235Smarkfen */ 56224235Smarkfen prev_prev_offset = prev_offset; 56234235Smarkfen } 56244235Smarkfen /* Didn't find a match - look at the next remove policy */ 56255120Smarkfen continue; /* while(); */ 56264235Smarkfen 56274235Smarkfen delete: 56284235Smarkfen (void) fclose(policy_fp); 56294235Smarkfen 56304235Smarkfen if (delete_from_file(prev_prev_offset, nlines) != 0) { 56314235Smarkfen warnx(gettext("delete_from_file failure. " 56324235Smarkfen "Please flush all entries and re-configure :")); 56334235Smarkfen reconfigure(); 56344235Smarkfen (void) fclose(remove_fp); 56354235Smarkfen free(act_props); 56364235Smarkfen return (-1); 56374235Smarkfen } 56384235Smarkfen 56394235Smarkfen if (pfp_delete_rule(pindex) != 0) { 56404235Smarkfen warnx(gettext("Deletion incomplete. Please flush" 56414235Smarkfen "all the entries and re-configure :")); 56424235Smarkfen reconfigure(); 56434235Smarkfen (void) fclose(remove_fp); 56444235Smarkfen free(act_props); 56454235Smarkfen return (-1); 56464235Smarkfen } 56474235Smarkfen 56484235Smarkfen /* reset the globals */ 56494235Smarkfen linecount = 0; 56504235Smarkfen pindex = 0; 56514235Smarkfen /* free(NULL) also works. */ 56524235Smarkfen free(interface_name); 56534235Smarkfen interface_name = NULL; 56544235Smarkfen 56554235Smarkfen /* reopen for next pass, automagically starting over. */ 56564235Smarkfen policy_fp = fopen(POLICY_CONF_FILE, "r"); 56574235Smarkfen if (policy_fp == NULL) { 56584235Smarkfen warn(gettext("%s cannot be re-opened, can't continue"), 56594235Smarkfen POLICY_CONF_FILE); 56604235Smarkfen (void) fclose(remove_fp); 56614235Smarkfen free(act_props); 56624235Smarkfen return (-1); 56634235Smarkfen } 56644235Smarkfen 56654235Smarkfen } /* read next remove policy */ 56664235Smarkfen 56674235Smarkfen if ((ret = pfp_delete_rule(pindex)) != 0) { 56684235Smarkfen warnx(gettext("Removal incomplete. Please flush " 56694235Smarkfen "all the entries and re-configure :")); 56704235Smarkfen reconfigure(); 56714235Smarkfen free(act_props); 56724235Smarkfen return (ret); 56734235Smarkfen } 56744235Smarkfen 56754235Smarkfen /* nothing left to look for */ 56764235Smarkfen (void) fclose(remove_fp); 56774235Smarkfen free(act_props); 56784235Smarkfen 56794235Smarkfen return (0); 56804235Smarkfen } 56814235Smarkfen 56824235Smarkfen /* 56834235Smarkfen * Constructs a tunnel interface ID extension. Returns the length 56844235Smarkfen * of the extension in 64-bit-words. 56854235Smarkfen */ 56864235Smarkfen static int 56874235Smarkfen attach_tunname(spd_if_t *tunname) 56884235Smarkfen { 56894235Smarkfen if (tunname == NULL || interface_name == NULL) 56904235Smarkfen return (0); 56914235Smarkfen 56924235Smarkfen tunname->spd_if_exttype = SPD_EXT_TUN_NAME; 56934235Smarkfen /* 56944235Smarkfen * Use "-3" because there's 4 bytes in the message itself, and 56954235Smarkfen * we lose one because of the '\0' terminator. 56964235Smarkfen */ 56974235Smarkfen tunname->spd_if_len = SPD_8TO64( 56984235Smarkfen P2ROUNDUP(sizeof (*tunname) + strlen(interface_name) - 3, 8)); 56994235Smarkfen (void) strlcpy((char *)tunname->spd_if_name, interface_name, LIFNAMSIZ); 57004235Smarkfen return (tunname->spd_if_len); 57014235Smarkfen } 5702