ipsecconf.c revision c758f97ff8b15826787cfb3cd4ebd6251a90bf57
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <strings.h>
#include <stropts.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <locale.h>
#include <syslog.h>
#include <pwd.h>
#include <net/pfpolicy.h>
#include <inet/ipsec_impl.h>
#include <signal.h>
#include <errno.h>
#include <netdb.h>
#include <sys/systeminfo.h>
#include <nss_dbdefs.h> /* NSS_BUFLEN_HOSTS */
#include <assert.h>
#include <ipsec_util.h>
#include <netinet/in_systm.h>
/*
* Buffer length to read in pattern/properties.
*/
#define MAXLEN 1024
/*
* Used by parse_one and parse/parse_action to communicate
* the errors. -1 is failure, which is not defined here.
*/
/*
* For spdsock_get_ext() diagnostics.
*/
#define SPDSOCK_DIAG_BUF_LEN 128
static char spdsock_diag_buf[SPDSOCK_DIAG_BUF_LEN];
/*
* Define CURL here so that while you are reading
* this code, it does not affect "vi" in pattern
* matching.
*/
#define CURL_BEGIN '{'
#define CURL_END '}'
#define MAXARGS 20
#define NOERROR 0
/*
* IPSEC_CONF_ADD should start with 1, so that when multiple commands
* are given, we can fail the request.
*/
static const char policy_conf_file[] = "/var/run/ipsecpolicy.conf";
static const char lock_file[] = "/var/run/ipsecconf.lock";
static const char index_tag[] = "#INDEX";
#define POLICY_CONF_FILE policy_conf_file
/*
* Valid algorithm length.
*/
#define VALID_ALG_LEN 40
/* Types of Error messages */
static int cmd;
static char *filename;
/* Error reporting stuff */
/*
* Following are used for reporting errors with arguments.
* We store the line numbers of each argument as we parse them,
* so that the error reporting is more specific. We can have only
* MAXARGS -1 for pattern and properties and one for action.
*/
static int arg_indices[ARG_BUF_LEN];
static int argindex;
static int linecount;
static int cbuf_offset;
#define BYPASS_POLICY_BOOST 0x00800000
#define ESP_POLICY_BOOST 0x00400000
#define AH_POLICY_BOOST 0x00200000
#define INITIAL_BASE_PRIORITY 0x000fffff
/*
* the number used to order the
* rules starts at a certain base and
* goes down. i.e. rules earlier in
* the file are checked first
*/
#define AH_AUTH 0
#define ESP_ENCR 1
#define ESP_AUTH 2
/*
* for deleting adds on error
*/
typedef struct d_list_s
{
int index;
} d_list_t;
/*
*/
/* lexxed out action and related properties */
typedef struct ap_s
{
char *act;
} ap_t;
/* one lexxed out rule */
typedef struct act_prop_s {
} act_prop_t;
typedef struct
{
} algreq_t;
/* structure to hold all information for one act_prop_t */
typedef struct ips_act_props_s {
struct ips_act_props_s *iap_next;
struct ips_conf_s *iap_head;
/*
* IPsec action types (in SPD_ATTR_TYPE attribute)
* SPD_ACTTYPE_DROP 0x0001
* SPD_ACTTYPE_PASS 0x0002
* SPD_ACTTYPE_IPSEC 0x0003
*/
/*
* Action ATTR flags (in SPD_ATTR_FLAGS attribute)
* SPD_APPLY_AH 0x0001
* SPD_APPLY_ESP 0x0002
* SPD_APPLY_SE 0x0004 * self-encapsulation *
* SPD_APPLY_COMP 0x0008 * compression; NYI *
* SPD_APPLY_UNIQUE 0x0010 * unique per-flow SA *
* SPD_APPLY_BYPASS 0x0020 * bypass policy *
*/
typedef struct ips_conf_s {
/* selector */
struct in6_addr ips_src_addr_v6;
struct in6_addr ips_src_mask_v6;
struct in6_addr ips_dst_addr_v6;
struct in6_addr ips_dst_mask_v6;
/*
* SPD_RULE_FLAG_INBOUND 0x0001
* SPD_RULE_FLAG_OUTBOUND 0x0002
*/
} ips_conf_t;
static int ipsecconf_nflag; /* Used only with -l option */
static int ipsecconf_qflag; /* Used only with -a|-r option */
typedef struct str_val {
const char *string;
int value;
} str_val_t;
typedef struct str_tval {
const char *string;
int tok_val;
int value;
} str_tval_t;
static int parse_int(const char *);
static void usage(void);
static int ipsec_conf_del(int, boolean_t);
static int ipsec_conf_add(void);
static int ipsec_conf_sub(void);
static int ipsec_conf_flush(int);
static int ipsec_conf_view(void);
static int ipsec_conf_list(void);
static int lock(void);
static int unlock(int);
static void reconfigure();
static void in_prefixlentomask(unsigned int, uchar_t *);
static unsigned int in_getprefixlen(char *);
static int parse_address(int, char *);
#ifdef DEBUG_HEAVY
#endif /* DEBUG_HEAVY */
static void print_pfpol_msg(spd_msg_t *);
static int pfp_delete_rule(uint64_t);
static void ipsec_conf_admin(uint8_t);
static void print_bit_range(int, int);
static void nuke_adds();
#ifdef DEBUG
static void dump_conf(ips_conf_t *);
#endif
typedef struct
{
} alginfo_t;
static int ipsec_nalgs[3];
/*
* if inbound, src=remote, dst=local
* if outbound, src=local, dst=remote
*/
#define TOK_saddr 1
#define TOK_daddr 2
#define TOK_sport 3
#define TOK_dport 4
#define TOK_smask 5
#define TOK_dmask 6
#define TOK_ulp 7
#define TOK_local 8
#define TOK_lport 9
#define TOK_remote 10
#define TOK_rport 11
#define TOK_dir 12
#define TOK_type 13
#define TOK_code 14
#define IPS_SA SPD_ATTR_END
#define IPS_DIR SPD_ATTR_EMPTY
static str_tval_t pattern_table[] = {
{NULL, 0, 0},
};
#define TOK_apply 1
#define TOK_permit 2
#define TOK_ipsec 3
#define TOK_bypass 4
#define TOK_drop 5
#define TOK_or 6
static str_tval_t action_table[] = {
{"or", TOK_or, 0},
{NULL, 0, 0},
};
static str_val_t property_table[] = {
{"auth_algs", SPD_ATTR_AH_AUTH},
{"encr_algs", SPD_ATTR_ESP_ENCR},
{"encr_auth_algs", SPD_ATTR_ESP_AUTH},
{"sa", IPS_SA},
{"dir", IPS_DIR},
{NULL, 0},
};
static str_val_t icmp_type_table[] = {
{"unreach", ICMP_UNREACH},
{"echo", ICMP_ECHO},
{"echorep", ICMP_ECHOREPLY},
{"squench", ICMP_SOURCEQUENCH},
{"redir", ICMP_REDIRECT},
{"timex", ICMP_TIMXCEED},
{"paramprob", ICMP_PARAMPROB},
{"timest", ICMP_TSTAMP},
{"timestrep", ICMP_TSTAMPREPLY},
{"inforeq", ICMP_IREQ},
{"inforep", ICMP_IREQREPLY},
{"maskreq", ICMP_MASKREQ},
{"maskrep", ICMP_MASKREPLY},
{"unreach6", ICMP6_DST_UNREACH},
{"pkttoobig6", ICMP6_PACKET_TOO_BIG},
{"timex6", ICMP6_TIME_EXCEEDED},
{"paramprob6", ICMP6_PARAM_PROB},
{"echo6", ICMP6_ECHO_REQUEST},
{"echorep6", ICMP6_ECHO_REPLY},
{"router-sol6", ND_ROUTER_SOLICIT},
{"router-ad6", ND_ROUTER_ADVERT},
{"neigh-sol6", ND_NEIGHBOR_SOLICIT},
{"neigh-ad6", ND_NEIGHBOR_ADVERT},
{"redir6", ND_REDIRECT},
{NULL, 0},
};
static str_val_t icmp_code_table[] = {
{"net-unr", ICMP_UNREACH_NET},
{"host-unr", ICMP_UNREACH_HOST},
{"proto-unr", ICMP_UNREACH_PROTOCOL},
{"port-unr", ICMP_UNREACH_PORT},
{"needfrag", ICMP_UNREACH_NEEDFRAG},
{"srcfail", ICMP_UNREACH_SRCFAIL},
{"net-unk", ICMP_UNREACH_NET_UNKNOWN},
{"host-unk", ICMP_UNREACH_HOST_UNKNOWN},
{"isolate", ICMP_UNREACH_ISOLATED},
{"net-prohib", ICMP_UNREACH_NET_PROHIB},
{"host-prohib", ICMP_UNREACH_HOST_PROHIB},
{"net-tos", ICMP_UNREACH_TOSNET},
{"host-tos", ICMP_UNREACH_TOSHOST},
{"filter-prohib", ICMP_UNREACH_FILTER_PROHIB},
{"host-preced", ICMP_UNREACH_HOST_PRECEDENCE},
{"cutoff-preced", ICMP_UNREACH_PRECEDENCE_CUTOFF},
{"no-route6", ICMP6_DST_UNREACH_NOROUTE},
{"adm-prohib6", ICMP6_DST_UNREACH_ADMIN},
{"addr-unr6", ICMP6_DST_UNREACH_ADDR},
{"port-unr6", ICMP6_DST_UNREACH_NOPORT},
{"hop-limex6", ICMP6_TIME_EXCEED_TRANSIT},
{"frag-re-timex6", ICMP6_TIME_EXCEED_REASSEMBLY},
{"err-head6", ICMP6_PARAMPROB_HEADER},
{"unrec-head6", ICMP6_PARAMPROB_NEXTHEADER},
{"unreq-opt6", ICMP6_PARAMPROB_OPTION},
{NULL, 0},
};
static boolean_t
{
warn("malloc");
return (B_TRUE);
}
return (B_FALSE);
}
return (B_FALSE);
}
static int
{
warn("sigfillset");
return (-1);
}
warn("sigprocmask");
return (-1);
}
return (0);
}
static int
{
warn("sigprocmask");
return (-1);
}
return (0);
}
/* allocate an ips_act_props_t and link it in correctly */
static ips_act_props_t *
{
return (NULL);
}
else
parent->ips_act_cnt++;
return (ret);
}
/*
* This function exit()s if it fails.
*/
static void
{
struct spd_ext_actions *actp;
if (has_run)
return;
else
if (sfd < 0) {
}
if (cnt < 0) {
} else {
}
}
/*
* No algorithms are defined in the kernel, which caused
* the extension length to be zero, and spdsock_get_ext()
* to fail with a KGE_LEN error. This is not an error
* condition, so we return nicely.
*/
return;
} else if (retval != 0) {
if (strlen(spdsock_diag_buf) != 0)
}
if (!exts[SPD_EXT_ACTION]) {
}
algtype = 0;
switch (attr->spd_attr_tag) {
case SPD_ATTR_NOP:
case SPD_ATTR_EMPTY:
break;
case SPD_ATTR_END:
/* FALLTHRU */
case SPD_ATTR_NEXT:
ipsec_nalgs[algtype]++;
break;
case SPD_ATTR_ENCR_MINBITS:
case SPD_ATTR_AH_MINBITS:
case SPD_ATTR_ESPA_MINBITS:
break;
case SPD_ATTR_ENCR_MAXBITS:
case SPD_ATTR_AH_MAXBITS:
case SPD_ATTR_ESPA_MAXBITS:
break;
case SPD_ATTR_ENCR_DEFBITS:
case SPD_ATTR_AH_DEFBITS:
case SPD_ATTR_ESPA_DEFBITS:
break;
case SPD_ATTR_ENCR_INCRBITS:
case SPD_ATTR_AH_INCRBITS:
case SPD_ATTR_ESPA_INCRBITS:
break;
case SPD_ATTR_AH_AUTH:
case SPD_ATTR_ESP_AUTH:
case SPD_ATTR_ESP_ENCR:
break;
}
attr++;
}
}
/* data dependant transform (act_cnt) */
ap++; } while (0)
static struct spd_attribute *
{
int minbits, i;
if (id != 0) {
/* LINTED E_CONST_COND */
if (minbits == 0) {
for (i = 0; i < ipsec_nalgs[type]; i++) {
break;
}
if (i < ipsec_nalgs[type])
}
if (minbits != 0)
/* LINTED E_CONST_COND */
/* LINTED E_CONST_COND */
}
return (ap);
}
static struct spd_attribute *
const ips_act_props_t *act_ptr)
{
/* LINTED E_CONST_COND */
/* type */
/* LINTED E_CONST_COND */
/* flags */
/* LINTED E_CONST_COND */
/* esp */
/* encr */
/* auth */
}
/* ah */
/* auth */
}
/* lifetimes */
if (act_ptr->iap_life_soft_time != 0)
/* LINTED E_CONST_COND */
if (act_ptr->iap_life_hard_time != 0)
/* LINTED E_CONST_COND */
if (act_ptr->iap_life_soft_bytes != 0)
/* LINTED E_CONST_COND */
if (act_ptr->iap_life_hard_bytes != 0)
/* LINTED E_CONST_COND */
/* LINTED E_CONST_COND */
return (ap);
}
static boolean_t
{
int i;
for (i = 0; i < ipsec_nalgs[type]; i++) {
break;
}
if (i >= ipsec_nalgs[type]) {
/*
* The kernel (where we populate known_algs from) doesn't
* return the id's associated with NONE algorithms so we
* test here if this was the reason the algorithm wasn't
* found before wrongly failing.
*/
return (B_TRUE);
} else {
return (B_FALSE); /* not found */
}
}
return (B_TRUE);
/* we could also check key increments here.. */
}
/*
*/
static struct spd_attribute *
const ips_act_props_t *act_ptr)
{
/*
* set up for explosion.. for each dimension, expand output
* size by the explosion factor.
*/
if (wild_auth) {
auth_min = 0;
}
if (wild_eauth) {
eauth_min = 0;
}
if (wild_encr) {
encr_min = 0;
}
if (use_esp &&
continue;
if (use_ah &&
continue;
eauth_idx++) {
if (use_espa &&
continue;
(*act_cntp)++;
rule_priorityp, &tact);
}
}
}
return (ap);
}
/* huge, but not safe since no length checking is done */
#define MAX_POL_MSG_LEN 16384
/*
* hand in some ips_conf_t's, get back an
* iovec of pfpol messages.
* this function converts the internal ips_conf_t into
* a form that pf_pol can use.
* return 0 on success, 1 on failure
*/
static int
{
int i;
for (i = 0; i < num_ips; i++) {
struct spd_portrange *spd_portrange;
struct spd_ext_actions *spd_ext_actions;
struct spd_attribute *ap;
struct spd_typecode *spd_typecode;
uint32_t rule_priority = 0;
return (1);
}
switch (ipsec_cmd) {
case SPD_ADDRULE:
break;
default:
break;
}
/*
* SELECTOR
*/
/* rule */
/* proto */
if (conf->ips_ulp_prot != 0) {
}
SPD_8TO64(sizeof (struct spd_typecode));
} else {
= 255;
}
}
}
/* src port */
if (conf->ips_src_port_min != 0 ||
conf->ips_src_port_max != 0) {
SPD_8TO64(sizeof (struct spd_portrange));
}
/* dst port */
if (conf->ips_dst_port_min != 0 ||
conf->ips_dst_port_max != 0) {
SPD_8TO64(sizeof (struct spd_portrange));
}
/* saddr */
sizeof (ipaddr_t));
} else {
sizeof (in6_addr_t));
= 128;
}
}
/* daddr */
sizeof (ipaddr_t));
/* "+ 4" below is for padding. */
} else {
sizeof (in6_addr_t));
= 128;
}
}
/* actions */
rule_priority = priority--;
}
#ifdef DEBUG_HEAVY
"ips_conf_to_pfpol_msg");
#endif
}
return (0);
}
static int
get_pf_pol_socket(void)
{
if (s < 0) {
}
return (s);
}
static int
{
int retval;
int cnt;
int total_len;
int fd = get_pf_pol_socket();
if (fd < 0)
return (EBADF);
if (retval) {
return (ENOMEM);
}
#ifdef DEBUG_HEAVY
#endif
if (cnt < 0) {
} else {
if (return_buf == NULL) {
} else {
#ifdef DEBUG_HEAVY
#endif
if (!ipsecconf_qflag) {
warnx("%s: %s",
gettext("spd_msg return"),
}
if (diag != 0)
(void) printf("%s\n",
spdsock_diag(diag));
#ifdef DEBUG_HEAVY
"message in");
"send_pf_pol_message");
#endif
return (retval);
}
/* ignore retval */
if (exts[SPD_EXT_RULE]) {
((struct spd_rule *)
return (ENOMEM);
}
}
}
}
return (0);
}
int
{
int c;
int index;
int lfd;
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
(void) textdomain(TEXT_DOMAIN);
/*
* We don't immediately check for privilege here. This is done by IP
*/
if (argc == 1) {
goto done;
}
switch (c) {
case 'f':
/* Only one command at a time */
if (cmd != 0) {
usage();
exit(1);
}
break;
case 'l':
/* Only one command at a time */
if (cmd != 0) {
usage();
exit(1);
}
break;
case 'a':
/* Only one command at a time */
if (cmd != 0) {
usage();
exit(1);
}
break;
case 'd':
/* Only one command at a time */
if (cmd != 0) {
usage();
exit(1);
}
break;
case 'n' :
break;
case 'q' :
break;
case 'r' :
/* only one command at a time */
if (cmd != 0) {
usage();
exit(1);
}
break;
default :
usage();
exit(1);
}
}
done:
ret = 0;
if (lfd == -1) {
exit(1);
}
/*
* ADD, FLUSH, DELETE needs to do two operations.
*
* 2) Make an ioctl and tell IP to update its state.
*
* We already lock()ed so that only one instance of this
* program runs. We also need to make sure that the above
* operations are atomic i.e we don't want to update the file
* and get interrupted before we could tell IP. To make it
* atomic we block all the signals and restore them.
*/
switch (cmd) {
case IPSEC_CONF_LIST:
ret = ipsec_conf_list();
break;
case IPSEC_CONF_FLUSH:
break;
}
(void) restore_all_signals();
break;
case IPSEC_CONF_VIEW:
ret = ipsec_conf_view();
break;
case IPSEC_CONF_DEL:
if (index == -1) {
ret = -1;
break;
}
break;
}
(void) restore_all_signals();
break;
case IPSEC_CONF_ADD:
break;
}
ret = ipsec_conf_add();
(void) restore_all_signals();
break;
case IPSEC_CONF_SUB:
break;
}
ret = ipsec_conf_sub();
(void) restore_all_signals();
break;
default :
/* If no argument is given but a "-" */
usage();
exit(1);
}
/* flush standby db */
ipsec_conf_flush(SPD_STANDBY) : 0;
ret = 1;
return (ret);
}
static int
perm_check(void)
{
else
return (-1);
}
static int
lock()
{
int fd;
/*
* Open the file with O_CREAT|O_EXCL. If it exists already, it
* will fail. If it already exists, check whether it looks like
* the one we created.
*/
(void) umask(0077);
== -1) {
/* Some other problem. */
return (perm_check());
}
/*
* open() returned an EEXIST error. We don't fail yet
* as it could be a residual from a previous
* execution.
* File exists. make sure it is OK. We need to lstat()
* as fstat() stats the file pointed to by the symbolic
* link.
*/
return (-1);
}
/*
* Check whether it is a regular file and not a symbolic
* link. Its link count should be 1. The owner should be
* root and the file should be empty.
*/
return (-1);
}
return (perm_check());
}
/*
* Check whether we opened the file that we lstat()ed.
*/
return (-1);
}
/* File changed after we did the lstat() above */
return (-1);
}
}
warn("lockf");
return (-1);
}
return (fd);
}
static int
{
warn("lockf");
return (-1);
}
return (0);
}
/* send in TOK_* */
static void
print_pattern_string(int type)
{
int j;
return;
}
}
}
static void
{
else
(void) printf(" ");
if (code != 255) {
else
(void) printf(" ");
}
}
static void
{
if (flags == SPD_RULE_FLAG_OUTBOUND)
(void) printf("dir out ");
else if (flags == SPD_RULE_FLAG_INBOUND)
(void) printf("dir in ");
(void) printf("dir both ");
}
static void
{
(void) printf("(");
if (min != 0)
(void) printf("..");
}
(void) printf(")");
}
}
static void
{
struct ipsecalgent *alg;
/*
* This function won't be called with alg_id == 0, so we don't
* have to worry about ANY vs. NONE here.
*/
} else {
}
(void) printf(" ");
}
static void
{
if (proto == 0)
return;
if (!ipsecconf_nflag) {
}
else
}
/* needs to do ranges */
static void
{
if (port == 0)
return;
if (!ipsecconf_nflag)
else
}
#if 0
/*
* Print the mask (source or destination depending on the specified type)
* defined in the policy pointed to by cptr.
* We follow ifconfig's lead, i.e. we use the decimal dot notation for IPv4
* masks and the /N prefix length form for IPv6.
*/
static void
{
char buf[INET6_ADDRSTRLEN];
struct in6_addr *in_addr_ptr;
struct in6_addr *in_mask_ptr;
if (type == IPS_SRC_MASK) {
} else {
}
/*
* If the address is INADDR_ANY, don't print the mask.
*/
if (isv4) {
return;
} else {
addr6 = *in_addr_ptr;
if (IN6_IS_ADDR_UNSPECIFIED(&addr6))
return;
}
if (isv4) {
(void) printf(" ");
(void) printf("%s ",
} else {
(void) printf("/%d ",
}
}
/*
* Print the address and mask.
*/
static void
{
char *cp;
char abuf[INET6_ADDRSTRLEN];
int error_num;
struct in6_addr *in_addr_ptr;
int addr_len;
if (type == SPD_EXT_LCLADDR)
else
/* we don't print unspecified addresses */
return;
} else {
addr6 = *in_addr_ptr;
/* we don't print unspecified addresses */
if (IN6_IS_ADDR_UNSPECIFIED(&addr6))
return;
}
if (!ipsecconf_nflag) {
} else {
domain[0] = 0;
}
else {
*cp = 0;
}
}
if (cp) {
} else {
}
}
#endif
/*
* Print the address and mask.
*/
static void
{
char *cp;
char abuf[INET6_ADDRSTRLEN];
int error_num;
int addr_len;
if (isv4) {
/* we don't print unspecified addresses */
return;
} else {
/* we don't print unspecified addresses */
if (IN6_IS_ADDR_UNSPECIFIED(&addr6))
return;
}
if (!ipsecconf_nflag) {
} else {
domain[0] = 0;
}
if (hp) {
*cp = 0;
}
}
if (cp) {
} else {
}
}
/*
* Get the next SPD_DUMP message from the PF_POLICY socket. A single
* read may contain multiple messages. This function uses static buffers,
* and is therefore non-reentrant, so if you lift it for an MT application,
* be careful.
*
* Return NULL if there's an error.
*/
static spd_msg_t *
ipsec_read_dump(int pfd)
{
static int len; /* In uint64_t units. */
/* Assume offset and len are initialized to NULL and 0. */
/* read a new block from the socket. */
if (len == -1) {
return (NULL);
}
} /* Else I still have more messages from a previous read. */
" %d len exceeds %d boundary."),
return (NULL);
}
return (retval);
}
/*
* returns 0 on success
* -1 on read error
* >0 on invalid returned message
*/
static int
ipsec_conf_list(void)
{
int ret;
int pfd;
int cnt;
pfd = get_pf_pol_socket();
if (pfd == -1) {
return (-1);
}
if (cnt < 0) {
return (-1);
}
return (-1);
}
for (;;) {
/* read rule */
return (-1);
}
if (rmsg->spd_msg_errno != 0) {
return (-1);
}
if (ret != 0) {
if (strlen(spdsock_diag_buf) != 0)
return (ret);
}
/*
* End of dump..
*/
break; /* and return 0. */
}
return (0);
}
static void
{
/* action */
switch (iap->iap_action) {
case SPD_ACTTYPE_PASS:
(void) printf("pass ");
break;
case SPD_ACTTYPE_DROP:
(void) printf("drop ");
break;
case SPD_ACTTYPE_IPSEC:
(void) printf("ipsec ");
break;
}
/* properties */
}
(void) printf("sa unique ");
else
(void) printf("sa shared ");
}
}
static void
{
struct spd_portrange *spd_portrange;
struct spd_ext_actions *spd_ext_actions;
struct spd_typecode *spd_typecode;
struct spd_attribute *app;
} else {
if (strlen(spdsock_diag_buf) != 0)
return;
}
}
(void) printf("laddr ");
else
}
if (spd_portrange->spd_ports_minport != 0) {
}
}
(void) printf("raddr ");
else
}
if (spd_portrange->spd_ports_minport != 0) {
}
}
}
}
int or_needed = 0;
for (act_count = 0;
act_count++) {
switch (app->spd_attr_tag) {
case SPD_ATTR_NOP:
break;
case SPD_ATTR_END:
/* print */
if (or_needed) {
(void) printf("or ");
} else {
or_needed = 1;
}
break;
case SPD_ATTR_EMPTY:
/* clear */
break;
case SPD_ATTR_NEXT:
/* print */
if (or_needed) {
(void) printf("or ");
} else {
or_needed = 1;
}
break;
case SPD_ATTR_TYPE:
break;
case SPD_ATTR_FLAGS:
break;
case SPD_ATTR_AH_AUTH:
break;
case SPD_ATTR_ESP_ENCR:
break;
case SPD_ATTR_ESP_AUTH:
break;
case SPD_ATTR_ENCR_MINBITS:
break;
case SPD_ATTR_ENCR_MAXBITS:
break;
case SPD_ATTR_AH_MINBITS:
break;
case SPD_ATTR_AH_MAXBITS:
break;
case SPD_ATTR_ESPA_MINBITS:
break;
case SPD_ATTR_ESPA_MAXBITS:
break;
case SPD_ATTR_LIFE_SOFT_TIME:
case SPD_ATTR_LIFE_HARD_TIME:
case SPD_ATTR_LIFE_SOFT_BYTES:
case SPD_ATTR_LIFE_HARD_BYTES:
default:
(void) printf("\tattr %d: %X-%d\n",
break;
}
app++;
}
}
(void) printf("\n");
}
#ifdef DEBUG_HEAVY
static void
{
uint32_t i;
struct spd_portrange *spd_portrange;
struct spd_typecode *spd_typecode;
struct spd_ext_actions *spd_ext_actions;
struct spd_attribute *app;
char abuf[INET6_ADDRSTRLEN];
return;
for (i = 1; i <= SPD_EXT_MAX; i++) {
printf("skipped %d\n", i);
continue;
}
switch (i) {
case SPD_EXT_ICMP_TYPECODE:
(void) printf("icmp type %d-%d code %d-%d\n",
break;
case SPD_EXT_LCLPORT:
(void) printf("local ports %d-%d\n",
break;
case SPD_EXT_REMPORT:
(void) printf("remote ports %d-%d\n",
break;
case SPD_EXT_PROTO:
(void) printf("proto:spd_proto_exttype %d\n",
(void) printf("proto:spd_proto_number %d\n",
break;
case SPD_EXT_LCLADDR:
case SPD_EXT_REMADDR:
if (i == SPD_EXT_LCLADDR)
(void) printf("local addr ");
else
(void) printf("remote addr ");
(void) printf("%s\n",
(void) printf("prefixlen: %d\n",
break;
case SPD_EXT_ACTION:
(void) printf("spd_ext_action\n");
(void) printf("spd_actions_count %d\n",
for (act_count = 0;
act_count++) {
app++;
}
break;
case SPD_EXT_RULE:
(void) printf("spd_rule_priority: 0x%x\n",
(void) printf("spd_rule_flags: %d\n",
break;
case SPD_EXT_RULESET:
(void) printf("spd_ext_ruleset\n");
break;
default:
(void) printf("default\n");
break;
}
}
(void) printf("-------------------\n");
(void) printf("=========================\n");
}
#endif /* DEBUG_HEAVY */
static int
{
/*
* The absence of POLICY_CONF_FILE should
* not cause the command to exit with a
* non-zero status, since this condition
* is valid when no policies were previously
* defined.
*/
return (0);
}
return (-1);
}
/* Don't print removed entries */
if (*buf == ';')
continue;
}
return (0);
}
/*
* Delete nlines from start in the POLICY_CONF_FILE.
*/
static int
{
int len;
return (-1);
}
/*
* Insert a ";", read the line and discard it. Repeat
* this logic nlines - 1 times. For the last line there
* is just a newline character. We can't just insert a
* single ";" character instead of the newline character
* as it would affect the next line. Thus when we comment
* the last line we seek one less and insert a ";"
* character, which will replace the newline of the
* penultimate line with ; and newline of the last line
* will become part of the previous line.
*/
do {
/*
* It is not enough to seek just once and expect the
* subsequent fgets below to take you to the right
* offset of the next line. fgets below seems to affect
* the offset. Thus we need to seek, replace with ";",
* and discard a line using fgets for every line.
*/
warn("fseek");
return (-1);
}
warn("fputc");
return (-1);
}
/*
* Flush the above ";" character before we do the fgets().
* Without this, fgets() gets confused with offsets.
*/
len = 0;
/*
* We have read a complete line.
*/
break;
}
}
/*
* We read the line after ";" character has been inserted.
* Thus len does not count ";". To advance to the next line
* increment by 1.
*/
/*
* If nlines == 2, we will be commenting out the last
* line next, which has only one newline character.
* If we blindly replace it with ";", it will be
* read as part of the next line which could have
* a INDEX string and thus confusing ipsec_conf_view.
* Thus, we seek one less and replace the previous
* line's newline character with ";", and the
* last line's newline character will become part of
* the previous line.
*/
if (nlines == 2)
start--;
} while (--nlines != 0);
if (nlines != 0)
return (-1);
else
return (0);
}
/*
* Delete an entry from the file by inserting a ";" at the
* beginning of the lines to be removed.
*/
static int
{
char *buf;
int ret = 0;
int offset, prev_offset;
int nlines;
return (-1);
}
return (-1);
}
index = 0;
continue;
}
/*
* This line contains INDEX_TAG
*/
buf++; /* Skip the space */
if (index == -1) {
return (-1);
}
if (index == policy_index) {
if (!ignore_spd) {
if (ret == -1) {
"in the file"));
return (-1);
}
}
/*
* nlines is the number of lines we should comment
* out. linecount tells us how many lines this command
* spans. And we need to remove the line with INDEX
* and an extra line we added during ipsec_conf_add.
*
* NOTE : If somebody added a policy entry which does
* not have a newline, ipsec_conf_add() fills in the
* newline. Hence, there is always 2 extra lines
* to delete.
*/
goto delete;
}
}
if (!ignore_spd)
if (ret != 0) {
"flush all the entries and re-configure :"));
reconfigure();
return (ret);
}
return (ret);
/* Delete nlines from prev_offset */
if (ret != 0) {
"flush all the entries and re-configure :"));
reconfigure();
return (ret);
}
if (!ignore_spd)
if (ret != 0) {
"flush all the entries and re-configure :"));
reconfigure();
return (ret);
}
return (0);
}
static int
{
int cnt;
if (sfd < 0) {
return (-1);
}
+ sizeof (struct spd_rule));
warn("malloc");
return (-1);
}
+ sizeof (struct spd_rule));
if (cnt < 0) {
return (-1);
} else {
return (-1);
}
}
if (cnt < 0) {
return (-1);
} else {
return (-1);
}
}
if (msg->spd_msg_errno != 0) {
return (-1);
}
return (0);
}
static int
ipsec_conf_flush(int db)
{
if (sfd < 0) {
return (-1);
}
if (cnt < 0) {
return (-1);
} else {
return (-1);
}
}
if (cnt < 0) {
return (-1);
} else {
return (-1);
}
}
if (msg.spd_msg_errno != 0) {
return (-1);
}
/* Truncate the file */
if (db == SPD_ACTIVE) {
/*
* The absence of POLICY_CONF_FILE should
* not cause the command to exit with a
* non-zero status, since this condition
* is valid when no policies were previously
* defined.
*/
return (0);
}
return (-1);
}
}
return (0);
}
/* function to send SPD_FLIP and SPD_CLONE messages */
static void
{
int cnt;
if (sfd < 0) {
}
if (cnt < 0) {
} else {
}
}
if (cnt < 0) {
} else {
}
}
if (msg.spd_msg_errno != 0) {
}
}
static void
{
"\tipsecconf -f \n "
"\tipsecconf -a policy_file\n"));
}
static void
usage(void)
{
"Usage: ipsecconf\n"
"\tipsecconf -a ([-]|<filename>) [-q]\n"
"\tipsecconf -r ([-]|<filename>) [-q]\n"
"\tipsecconf -d <index>\n"
"\tipsecconf -l [-n]\n"
"\tipsecconf -f\n"));
}
/*
* a type consists of
* "type" <int>{ "-" <int>}
* or
* "type" keyword
*
* a code consists of
* "code" <int>{ "-" <int>}
* or
* "code" keyword
*/
static int
{
int i;
return (-1);
}
return (-1);
}
if (*end1 == '-') {
end1++;
return (-1);
}
} else {
}
end2++;
if (*end2 != '\0') {
return (-1);
}
}
}
}
return (-1);
}
static int
{
char *end;
int res;
return (-1);
end++;
if (*end != '\0')
return (-1);
return (res);
}
/*
* Convert a mask to a prefix length.
* Returns prefix length on success, 0 otherwise.
*/
static unsigned int
in_getprefixlen(char *mask)
{
long prefixlen;
char *end;
if (prefixlen < 0) {
return (0);
}
return (0);
}
if (*end != '\0') {
return (0);
}
return ((unsigned int)prefixlen);
}
/*
* Convert an IPv6 mask to a prefix len. I assume all IPv6 masks are
* contiguous, so I stop at the first bit!
*/
static int
{
int rc = 0;
int limit = IPV6_ABITS;
if (is_v4mapped) {
}
while (*mask == 0xff) {
rc += 8;
return (limit);
mask++;
}
while (last != 0) {
rc++;
}
return (rc);
}
/*
* Convert a prefix length to a mask.
* Assumes the mask array is zero'ed by the caller.
*/
static void
{
while (prefixlen > 0) {
if (prefixlen >= 8) {
*mask++ = 0xFF;
prefixlen -= 8;
continue;
}
prefixlen--;
}
}
static int
{
char *ptr;
unsigned int prefix_len = 0;
int h_errno;
if (prefix_len == 0)
return (-1);
}
/*
* getipnodebyname() is thread safe. This allows us to hold on to the
* returned hostent structure, which is pointed to by the shp and
* dhp globals for the source and destination addresses, respectively.
*/
/*
* We come here for both a hostname and
* any host address /network address.
*/
switch (ne->n_addrtype) {
case AF_INET:
/*
* Allocate a struct hostent and initialize
* it with the address corresponding to the
* network number previously returned by
* getnetbyname(). Freed by do_address_adds()
* once the policy is defined.
*/
warn("malloc");
return (-1);
}
warn("malloc");
return (-1);
}
warn("malloc");
return (-1);
}
break;
default:
return (-1);
}
} else {
return (-1);
}
if (type == IPSEC_CONF_SRC_ADDRESS) {
if (has_mask)
splen = prefix_len;
} else {
if (has_mask)
dplen = prefix_len;
}
return (0);
}
/*
* Add port-only entries. Make sure to add them in both the V6 and V4 tables!
*/
static int
{
int ret;
#ifdef DEBUG_HEAVY
#endif
if (ret != 0 && !ipsecconf_qflag) {
gettext("Could not add IPv4 policy for sport %d, dport %d"),
}
return (ret);
}
/*
* Nuke a list of policy entries.
* rewrite this to use flipping
* d_list isn't freed because we will be
* exiting the program soon.
*/
static void
{
}
}
}
/*
* Set mask info from the specified prefix len. Fail if multihomed.
*/
static int
{
return (EINVAL);
}
if (!IN6_IS_ADDR_UNSPECIFIED(mask_v6)) {
return (EBUSY);
}
if (IN6_IS_ADDR_V4MAPPED(&addr)) {
return (ERANGE);
}
} else {
if (plen > IPV6_ABITS) {
return (ERANGE);
}
/* mask_v6 is already zero (unspecified), see test above */
}
return (0);
}
/*
* Initialize the specified IPv6 address with all f's.
*/
static void
{
if (isv4) {
} else {
}
}
/*
* Called at the end to actually add policy. Handles single and multi-homed
* cases.
*/
static int
{
int i, j;
int ret = 0; /* For ioctl() call. */
int rc = 0; /* My own return code. */
char *ptr[2];
int add_count = 0;
/*
* dst_hent may not be initialized if a destination
* address was not given. It will be initalized with just
* one address if a destination address was given. In both
* the cases, we initialize here with ipsc_dst_addr and enter
* the loop below.
*/
}
/*
* Set mask info here. Bail if multihomed and there's a prefix len.
*/
if (has_saprefix) {
if (rc != 0)
goto bail;
}
if (has_daprefix) {
if (rc != 0)
goto bail;
}
sizeof (struct in6_addr));
}
sizeof (struct in6_addr));
/*
* Src was not specified, so update isv4 flag
* for this policy according to the family
* of the destination address.
*/
&cptr->ips_dst_addr_v6);
continue;
}
isv4);
}
if (ret == 0) {
add_count++;
} else {
/*
* We have an error where we added
* some, but had errors with others.
* Undo the previous adds, and
* bail.
*/
goto bail;
}
}
sizeof (struct in6_addr));
}
}
bail:
splen = 0;
dplen = 0;
/*
* No entries were added. We failed all adds
* because the entries already existed, or because
* we must fail here with an appropriate error
* to avoid a corresponding entry from being added
* to ipsecpolicy.conf.
*/
/* All adds failed with EEXIST */
} else {
}
}
return (rc);
}
static int
{
if (type == IPSEC_CONF_SRC_MASK) {
} else {
}
/* Is it in the form 0xff000000 ? */
char *end;
return (-1);
}
if (*end != '\0') {
return (-1);
}
} else {
/*
* Since inet_addr() returns -1 on error, we have
* to convert a broadcast address ourselves.
*/
} else {
return (-1);
}
}
/* Should we check for non-contiguous masks ? */
return (-1);
if (type == IPSEC_CONF_SRC_MASK) {
B_TRUE);
} else {
B_TRUE);
}
return (0);
}
static int
{
int ret;
return (-1);
}
} else {
}
if (type == IPSEC_CONF_SRC_PORT) {
} else {
}
return (0);
}
static int
{
const char *tmp;
int ret;
struct ipsecalgent *alg;
/* Short-circuit "none" */
return (-2);
return (ret);
}
/*
* Look whether it could be a valid number.
* We support numbers also so that users can
* load algorithms as they need it. We can't
* check for validity of numbers here. It will
* be checked when the SA is negotiated/looked up.
* parse_int uses strtol(str), which converts 3DES
* to a valid number i.e looks only at initial
* number part. If we come here we should expect
* only a decimal number.
*/
while (*tmp) {
return (-1);
tmp++;
}
return (ret);
else
return (-1);
}
static int
{
int alg_value;
char tstr[VALID_ALG_LEN];
char *l1_str;
int l1 = 0;
char *l2_str;
int l2 = SPD_MAX_MAXBITS;
/*
* Make sure that we get a null terminated string.
* For a bad input, we truncate at VALID_ALG_LEN.
*/
int len1 = 0;
int len2 = SPD_MAX_MAXBITS;
if (len1 < 0)
return (1);
}
if (len2 < 0)
return (1);
}
/* alg(n) */
} else if (dot_start) {
/* alg(..n) */
l1 = 0;
/* alg(n..) */
} /* else alg(n..m) */
}
if (alg_type == SPD_ATTR_AH_AUTH ||
alg_type == SPD_ATTR_ESP_AUTH) {
} else {
}
if (alg_value < 0) {
/* Invalid algorithm or "none" */
return (alg_value);
}
if (alg_type == SPD_ATTR_AH_AUTH) {
} else if (alg_type == SPD_ATTR_ESP_AUTH) {
} else {
}
return (1);
return (0);
}
static void
{
char *mesg;
switch (type) {
case IPSEC_CONF_SRC_ADDRESS:
break;
case IPSEC_CONF_DST_ADDRESS:
break;
case IPSEC_CONF_SRC_PORT:
break;
case IPSEC_CONF_DST_PORT:
break;
case IPSEC_CONF_SRC_MASK:
break;
case IPSEC_CONF_DST_MASK:
break;
case IPSEC_CONF_ULP:
break;
case IPSEC_CONF_IPSEC_AALGS:
break;
case IPSEC_CONF_IPSEC_EALGS:
break;
case IPSEC_CONF_IPSEC_EAALGS:
break;
case IPSEC_CONF_IPSEC_SA:
break;
case IPSEC_CONF_IPSEC_DIR:
break;
case IPSEC_CONF_ICMP_TYPE:
break;
case IPSEC_CONF_ICMP_CODE:
break;
default :
return;
}
/*
* If we never read a newline character, we don't want
* to print 0.
*/
mesg,
}
static int
{
if (!dir) {
"not found for bypass policy"));
}
if (is_alg) {
return (-1);
}
return (0);
}
if (!is_alg) {
return (-1);
}
return (-1);
}
return (0);
}
/*
* This function is called only to parse a single rule's worth of
* action strings. This is called after parsing pattern and before
* parsing properties. Thus we may have something in the leftover
* buffer while parsing the pattern, which we need to handle here.
*/
static int
{
char *cp;
char *tmp_buf;
char *buf;
goto scan;
}
linecount++;
scan:
/* Truncate at the beginning of a comment */
/* Skip any whitespace */
buf++;
/* Empty line */
continue;
/*
* Store the command for error reporting
* and ipsec_conf_add().
*/
if (new_stuff) {
/*
* Check for buffer overflow including the null
* terminating character.
*/
return (-1);
cbuf_offset += len;
}
/*
* Start of the non-empty non-space character.
*/
/* Skip until next whitespace or CURL_BEGIN */
*buf != CURL_BEGIN)
buf++;
if (*buf == CURL_BEGIN) {
/* Allocate an extra byte for the null also */
NULL) {
warn("malloc");
return (ENOMEM);
}
*buf = CURL_BEGIN;
} else {
/* We have hit a space */
/* Allocate an extra byte for the null also */
NULL) {
warn("malloc");
return (ENOMEM);
}
}
/*
* Copy the rest of the line into the
* leftover buffer.
*/
} else {
}
} else {
/* Allocate an extra byte for the null also */
NULL) {
warn("malloc");
return (ENOMEM);
}
}
if (argindex >= ARG_BUF_LEN)
return (-1);
return (PARSE_SUCCESS);
}
/*
* Return error, on an empty action field.
*/
return (-1);
}
/*
* This is called to parse pattern or properties that is enclosed
* between CURL_BEGIN and CURL_END.
*/
static int
{
char *cp;
int i = 0;
char *tmp_buf;
char *buf;
/*
* When parsing properties, leftover buffer could have the
* leftovers of the previous fgets().
*/
goto scan;
}
#ifdef DEBUG_HEAVY
#endif
linecount++;
scan:
/* Truncate at the beginning of a comment */
/* Skip any whitespace */
buf++;
/* Empty line */
continue;
/*
* Store the command for error reporting
* and ipsec_conf_add().
*/
if (new_stuff) {
/*
* Check for buffer overflow including the null
* terminating character.
*/
return (-1);
cbuf_offset += len;
}
/*
* First non-space character should be
* a curly bracket.
*/
if (!curl_begin_seen) {
if (*buf != CURL_BEGIN) {
/*
* If we never read a newline character,
* we don't want to print 0.
*/
return (-1);
}
buf++;
}
/*
* Arguments are separated by white spaces or
* newlines. Scan till you see a CURL_END.
*/
ret:
/*
* Copy the rest of the line into the
* leftover buffer if any.
*/
} else {
}
return (PARSE_SUCCESS);
}
/*
* Skip any trailing whitespace until we see a
* non white-space character.
*/
buf++;
goto ret;
/* Scan the next line as this buffer is empty */
break;
if (i >= MAXARGS) {
gettext("Number of Arguments exceeded %d"),
i);
return (-1);
}
/*
* Non-empty, Non-space buffer.
*/
/*
* Real scan of the argument takes place here.
* Skip past till space or CURL_END.
*/
buf++;
}
/*
* Either a space or we have hit the CURL_END or
* the real end.
*/
+ 1)) == NULL) {
warn("malloc");
return (ENOMEM);
}
/*
* Copy the rest of the line into the
* leftover buffer.
*/
} else {
}
tmp_buf);
if (argindex >= ARG_BUF_LEN)
return (-1);
arg_indices[argindex++] =
}
return (PARSE_SUCCESS);
} else {
}
}
/*
* Copy this argument and scan for the buffer more
* if it is non-empty. If it is empty scan for
* the next line.
*/
NULL) {
warn("malloc");
return (ENOMEM);
}
if (argindex >= ARG_BUF_LEN)
return (-1);
}
}
/*
* If nothing is given in the file, it is okay.
* If something is given in the file and it is
* not CURL_BEGIN, we would have returned error
* above. If curl_begin_seen and we are here,
* something is wrong.
*/
if (curl_begin_seen)
return (-1);
return (PARSE_EOF); /* Nothing more in the file */
}
/*
* Parse one command i.e {pattern} action {properties}.
*
* {pattern} ( action {prop} | pass | drop ) (or ...)*
*/
static int
{
char *leftover;
int ret;
int i;
int ap_num = 0;
ret = 0;
argindex = 0;
cbuf_offset = 0;
for (;;) {
switch (pstate) {
case pattern:
{
#ifdef DEBUG_HEAVY
(void) printf("pattern\n");
#endif
/* EOF reached */
return (0);
}
if (ret != 0) {
goto err;
}
break;
}
case action:
{
#ifdef DEBUG_HEAVY
(void) printf("action\n");
#endif
if (ret != 0) {
goto err;
}
/*
* Validate action now itself so that we don't
* proceed too much into the bad world.
*/
for (i = 0; action_table[i].string; i++) {
action_table[i].string) == 0)
break;
}
/* hit an or, go again */
break;
}
/*
* If we never read a newline
* character, we don't want
* to print 0.
*/
"Invalid action on line %d: %s"),
return (-1);
}
break;
}
case prop:
{
#ifdef DEBUG_HEAVY
(void) printf("prop\n");
#endif
if (ret != 0) {
goto err;
}
/* Accomodate spaces at the end */
if (*leftover == 'o') {
leftover++;
if (*leftover == 'r') {
leftover++;
ap_num++;
return (1);
goto again;
}
}
ret = -1;
goto err;
}
leftover++;
}
return (0);
}
ap_num++;
return (0);
break;
} /* case prop: */
} /* switch(pstate) */
return (0);
} /* while(1) */
err:
if (ret != 0) {
/*
* If we never read a newline character, we don't want
* to print 0.
*/
}
return (ret);
}
/*
* convert an act_propts_t to an ips_conf_t
*/
static int
{
int i, j, k;
int tok_count = 0;
int line_no;
int ret;
int ap_num = 0;
#ifdef DEBUG_HEAVY
/*
* pattern => act_props->pattern
* action => act_props->ap[].act
* properties => act_props->ap[].prop
*/
(void) printf("\npattern\n------------\n");
(void) printf("apz\n----------\n");
(void) printf("%dprop%d->%s\n",
}
(void) printf("------------\n\n");
#endif
/*
* Get the Pattern. NULL pattern is valid.
*/
for (j = 0; pattern_table[j].string; j++) {
pattern_table[j].string) == 0)
break;
}
/*
* If we never read a newline character, we don't want
* to print 0.
*/
return (-1);
}
switch (pattern_table[j].tok_val) {
case TOK_dir:
i++, line_no++;
return (-1);
}
} else if (strncmp(
} else if (strncmp(
if (old_style) {
return (-1);
}
} else {
return (-1);
}
break;
case TOK_local:
if (old_style) {
return (-1);
}
if (saddr) {
return (-1);
}
/*
* Use this to detect duplicates rather
* than 0 like other cases, because 0 for
* address means INADDR_ANY.
*/
/*
* Advance to the string containing
* the address.
*/
i++, line_no++;
return (-1);
}
return (-1);
}
break;
case TOK_remote:
if (old_style) {
return (-1);
}
if (daddr) {
return (-1);
}
/*
* Use this to detect duplicates rather
* than 0 like other cases, because 0 for
* address means INADDR_ANY.
*/
/*
* Advance to the string containing
* the address.
*/
i++, line_no++;
return (-1);
}
return (-1);
}
break;
case TOK_saddr:
if (new_style) {
return (-1);
}
if (saddr) {
return (-1);
}
/*
* Use this to detect duplicates rather
* than 0 like other cases, because 0 for
* address means INADDR_ANY.
*/
/*
* Advance to the string containing
* the address.
*/
i++, line_no++;
return (-1);
}
return (-1);
}
/* shp or bhp? */
break;
case TOK_daddr:
if (new_style) {
return (-1);
}
if (daddr) {
return (-1);
}
/*
* Use this to detect duplicates rather
* than 0 like other cases, because 0 for
* address means INADDR_ANY.
*/
/*
* Advance to the string containing
* the address.
*/
i++, line_no++;
return (-1);
}
return (-1);
}
break;
case TOK_sport:
if (new_style) {
return (-1);
}
if (cptr->ips_src_port_min != 0) {
line_no);
return (-1);
}
i++, line_no++;
line_no);
return (-1);
}
if (ret != 0) {
line_no);
return (-1);
}
break;
case TOK_dport:
if (new_style) {
return (-1);
}
if (cptr->ips_dst_port_min != 0) {
line_no);
return (-1);
}
i++, line_no++;
line_no);
return (-1);
}
cptr);
if (ret != 0) {
line_no);
return (-1);
}
break;
case TOK_lport:
if (old_style) {
return (-1);
}
if (cptr->ips_src_port_min != 0) {
line_no);
return (-1);
}
i++, line_no++;
line_no);
return (-1);
}
cptr);
if (ret != 0) {
line_no);
return (-1);
}
break;
case TOK_rport:
if (old_style) {
return (-1);
}
if (cptr->ips_dst_port_min != 0) {
line_no);
return (-1);
}
i++, line_no++;
line_no);
return (-1);
}
cptr);
if (ret != 0) {
line_no);
return (-1);
}
break;
case TOK_smask:
if (new_style) {
return (-1);
}
line_no);
return (-1);
}
i++, line_no++;
line_no);
return (-1);
}
cptr);
if (ret != 0) {
line_no);
return (-1);
}
break;
case TOK_dmask:
if (new_style) {
return (-1);
}
line_no);
return (-1);
}
i++, line_no++;
line_no);
return (-1);
}
cptr);
if (ret != 0) {
line_no);
return (-1);
}
break;
case TOK_ulp:
if (cptr->ips_ulp_prot != 0) {
return (-1);
}
i++, line_no++;
return (-1);
}
int ulp;
if (ulp == -1) {
return (-1);
}
} else {
}
break;
case TOK_type:
return (-1);
}
i++, line_no++;
return (-1);
}
break;
case TOK_code:
return (-1);
}
return (-1);
}
i++, line_no++;
return (-1);
}
break;
}
}
/*
* Get the actions.
*/
if (ap_num > 0) {
/* or's only with new style */
if (old_style) {
"or's only with new style"));
return (-1);
}
}
tok_count = 0;
for (k = 0; action_table[k].string; k++) {
action_table[k].string) == 0)
break;
}
/*
* The following thing should never happen as
* we have already tested for its validity in parse.
*/
return (-1);
}
/* we have a good action alloc an iap */
switch (action_table[k].tok_val) {
case TOK_apply:
break;
case TOK_permit:
break;
case TOK_ipsec:
if (old_style) {
if (!dir) {
/* No direction specified */
return (-1);
}
/*
* Need to swap addresses if
* 'dir in' or translation to
*/
}
if (!dir)
break;
case TOK_bypass:
/* do something? */
break;
}
line_no++;
/*
* Get the properties. NULL properties is not valid.
* Later checks will catch it.
*/
for (j = 0; property_table[j].string; j++) {
property_table[j].string) == 0) {
break;
}
}
"%d: %s"),
(arg_indices[line_no] == 0) ?
return (-1);
}
= property_table[j].value;
switch (property_table[j].value) {
case SPD_ATTR_AH_AUTH:
if (ipsec_aalg) {
return (-1);
}
i++, line_no++;
return (-1);
}
if (ret == -2) {
/* "none" - ignore */
break;
}
if (ret != 0) {
return (-1);
}
ipsec_aalg = B_TRUE;
break;
case SPD_ATTR_ESP_ENCR:
/*
* If this option was not given
* and encr_auth_algs was given,
* we provide null-encryption. We do the
* setting after we parse all the options.
*/
if (ipsec_ealg) {
return (-1);
}
i++, line_no++;
return (-1);
}
if (ret == -2) {
/* "none" - ignore */
break;
}
if (ret != 0) {
return (-1);
}
ipsec_ealg = B_TRUE;
break;
case SPD_ATTR_ESP_AUTH:
/*
* If this option was not given and encr_algs
* option was given, we still pass a default
* value in ipsc_esp_auth_algs. This is to
* encourage the use of authentication with
* ESP.
*/
if (ipsec_eaalg) {
return (-1);
}
i++, line_no++;
return (-1);
}
if (ret == -2) {
/* "none" - ignore */
break;
}
if (ret != 0) {
return (-1);
}
break;
case IPS_SA:
i++, line_no++;
return (-1);
}
"unique") == 0) {
"shared") != 0) {
/* "shared" is default. */
return (-1);
}
break;
case IPS_DIR:
if (dir) {
return (-1);
}
if (new_style) {
return (-1);
}
i++, line_no++;
return (-1);
}
"out") == 0) {
"in") == 0) {
} else {
return (-1);
}
" in conflict with action"));
return (-1);
}
"in conflict with action"));
return (-1);
}
break;
}
}
if (!ipsec_ealg && ipsec_eaalg) {
/*
* If the user has specified the auth alg to be used
* with encryption and did not provide a encryption
* algorithm, provide null encryption.
*/
ipsec_ealg = B_TRUE;
}
/* Set the level of IPSEC protection we want */
} else if (ipsec_aalg) {
} else if (ipsec_ealg || ipsec_eaalg) {
}
if (!new_style) {
case TOK_apply:
/* outbound */
/* src=local, dst=remote */
/* this is ok. */
break;
case TOK_permit:
/* inbound */
/* src=remote, dst=local */
/* switch */
break;
case TOK_bypass:
case TOK_drop:
/* check the direction for what to do */
break;
default:
break;
}
}
/* Validate the properties */
return (ret);
}
}
return (0);
}
static int
{
if (ipsecconf_qflag) {
return (0);
}
cbuf);
} else {
cbuf);
}
} else {
warn("fprintf");
return (-1);
}
}
return (0);
}
#ifdef DEBUG
static uchar_t *
{
if (isv4) {
} else {
}
}
static void
{
(void) printf("%s algid %d, bits %d..%d\n",
}
static void
{
char buf[INET6_ADDRSTRLEN];
int af;
(void) printf("Source Addr is %s\n",
buf, INET6_ADDRSTRLEN));
(void) printf("Dest Addr is %s\n",
buf, INET6_ADDRSTRLEN));
(void) printf("Source Mask is %s\n",
buf, INET6_ADDRSTRLEN));
(void) printf("Dest Mask is %s\n",
buf, INET6_ADDRSTRLEN));
(void) printf("------------------------------------\n");
(void) printf("------------------------------------\n");
}
}
#endif /* DEBUG */
static int
ipsec_conf_add(void)
{
int ret, i, j;
"\tWARNING : New policy entries that are being added may\n "
"\taffect the existing connections. Existing connections\n"
"\tthat are not subjected to policy constraints, may be\n"
"\tsubjected to policy constraints because of the new\n"
"\tpolicy. This can disrupt the communication of the\n"
"\texisting connections.\n\n");
return (-1);
}
/* clone into standby DB */
else
usage();
return (-1);
}
/*
* This will create the file if it does not exist.
* Make sure the umask is right.
*/
(void) umask(0022);
return (-1);
}
if (!ipsecconf_qflag) {
}
/*
* Pattern, action, and properties are allocated in
* parse_pattern_or_prop and in parse_action (called by
* parse_one) as we parse arguments.
*/
/*
* If there is no action and parse returned success,
* it means that there is nothing to add.
*/
break;
if (ret != 0) {
break;
}
/*
* shp, dhp, splen, and dplen are globals set by
* form_ipsec_conf() while parsing the addresses.
*/
switch (do_port_adds(&conf)) {
case 0:
/* no error */
break;
case EEXIST:
/* duplicate entries, continue adds */
goto next;
default:
/* other error, bail */
ret = -1;
goto bail;
}
} else {
switch (ret) {
case 0:
/* no error. */
break;
case EEXIST:
goto next;
case EBUSY:
"Can't set mask and /NN prefix."));
ret = -1;
break;
case EINVAL:
" prefix on multi-host name."));
ret = -1;
break;
case ERANGE:
ret = -1;
break;
case ESRCH:
ret = -1;
break;
default:
/* Should never get here. */
ret = -1;
}
if (ret == -1)
goto bail;
}
/*
* Go ahead and add policy entries to config file.
* The # should help re-using the ipsecpolicy.conf
* for input again as # will be treated as comment.
*/
warn("fprintf");
"flush all the entries and re-configure :"));
reconfigure();
ret = -1;
break;
}
"flush all the entries and re-configure :"));
reconfigure();
ret = -1;
break;
}
/*
* We add one newline by default to separate out the
* entries. If the last character is not a newline, we
* insert a newline for free. This makes sure that all
* entries look consistent in the file.
*/
warn("fprintf");
"Please flush all the entries and "
"re-configure :"));
reconfigure();
ret = -1;
break;
}
} else {
warn("fprintf");
"Please flush all the entries and "
"re-configure :"));
reconfigure();
ret = -1;
break;
}
}
/*
* Make sure this gets to the disk before
* we parse the next entry.
*/
next:
}
}
bail:
if (ret == -1) {
}
}
#ifdef DEBUG_HEAVY
#endif
/* looks good, flip it in */
if (ret == 0)
else
nuke_adds();
return (ret);
}
static int
{
"\tWARNING: Policy entries that are being removed may\n"
"\taffect the existing connections. Existing connections\n"
"\tthat are subjeced to policy constraints may no longer\n"
"\tbe subjected to policy contraints because of its\n"
"\tremoval. This can compromise security, and disrupt\n"
"\tthe communication of the existing connection.\n"
"\tConnections that are latched will remain unaffected\n"
"\tuntil they close.\n");
int ret = 0;
return (-1);
}
/* clone into standby DB */
(void) ipsec_conf_admin(SPD_CLONE);
else
usage();
return (-1);
}
/* open policy file so we can locate the correct policy */
return (-1);
}
/* don't print the warning if we're in q[uiet] mode */
if (!ipsecconf_qflag)
/* this bit is done primarily so we can read what we write */
/*
* We want to look for the policy in rbuf in the policy file.
* Go through the list of policies to remove, locating each one.
*/
char *buf;
int pbuf_len = 0;
char *tmp;
/* skip blanks here (so we don't need to do it below)! */
if (*tmp == '\0')
continue;
/* skip the INDEX_TAG lines in the remove buffer */
continue;
/* skip commented lines */
if (*tmp == '#')
continue;
/*
* We start by presuming only good policies are in the pfile,
* and so only good policies from the rfile will match them.
* ipsec_conf_del ensures this later by calling parse_one() on
* pfile before it deletes the entry.
*/
/* skip blank lines which seperate policy entries */
if (pbuf[0] == '\n')
continue;
/* if we found an index, save it */
buf++;
/* bad index, we can't continue */
"Invalid index in the file"));
return (-1);
}
/* save this position in case it's the one */
return (-1);
}
}
/* Does pbuf contain the remove policy? */
/* we found the one to remove! */
if (pindex == 0) {
"index for policy"));
return (-1);
}
/* off it - back up to the last INDEX! */
return (-1);
}
/* parse_one sets linecount = #lines to off */
"in the file"));
return (-1);
}
goto delete;
}
/*
* When we find a match, we want to pass the offset
* of the line that is before it - the INDEX_TAG line.
*/
}
/* Didn't find a match - look at the next remove policy */
continue;
"Please flush all entries and re-configure :"));
reconfigure();
return (-1);
}
if (pfp_delete_rule(pindex) != 0) {
"all the entries and re-configure :"));
reconfigure();
return (-1);
}
/* reset the globals */
linecount = 0;
pindex = 0;
/* reopen for next pass, automagically starting over. */
return (-1);
}
} /* read next remove policy */
"all the entries and re-configure :"));
reconfigure();
return (ret);
}
/* nothing left to look for */
return (0);
}