1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright (c) 2017, Joyent, Inc.
  14  */
  15 #include <sys/types.h>
  16 #include <sys/debug.h>
  17 #include <pthread.h>
  18 #include "defs.h"
  19 #include "config.h"
  20 #include "ikev2_enum.h"
  21 
  22 pthread_rwlock_t cfg_lock = PTHREAD_RWLOCK_INITIALIZER;
  23 config_t *config;
  24 
  25 static boolean_t cfg_addr_match(const sockaddr_u_t *restrict,
  26     const config_addr_t *restrict);
  27 
  28 config_t *
  29 config_get(void)
  30 {
  31         config_t *cfg = NULL;
  32 
  33         PTH(pthread_rwlock_rdlock(&cfg_lock));
  34         cfg = config;
  35         CONFIG_REFHOLD(cfg);
  36         PTH(pthread_rwlock_unlock(&cfg_lock));
  37         return (cfg);
  38 }
  39 
  40 void
  41 config_xf_log(bunyan_logger_t *b, bunyan_level_t level, const char *msg,
  42     const config_xf_t *xf)
  43 {
  44         getlog(level)(b, msg,
  45             BUNYAN_T_STRING, "xf_encralg", ikev2_xf_encr_str(xf->xf_encr),
  46             BUNYAN_T_UINT32, "xf_minbits", (uint32_t)xf->xf_minbits,
  47             BUNYAN_T_UINT32, "xf_maxbits", (uint32_t)xf->xf_maxbits,
  48             BUNYAN_T_STRING, "xf_authalg", ikev2_xf_auth_str(xf->xf_auth),
  49             BUNYAN_T_STRING, "xf_authtype",
  50             ikev2_auth_type_str(xf->xf_authtype),
  51             BUNYAN_T_STRING, "xf_dh", ikev2_dh_str(xf->xf_dh),
  52             BUNYAN_T_END);
  53 }
  54 
  55 /*
  56  * Return the first rule that matches the given local and remote addresses.
  57  * If no rule matches, NULL is returned.  The config_t instance that holds
  58  * the given rule is refheld.
  59  */
  60 config_rule_t *
  61 config_get_rule(sockaddr_u_t *restrict local, sockaddr_u_t *restrict remote)
  62 {
  63         config_t *cfg = config_get();
  64 
  65         for (size_t i = 0; cfg->cfg_rules[i] != NULL; i++) {
  66                 config_rule_t *rule = cfg->cfg_rules[i];
  67                 boolean_t local_match = B_FALSE;
  68                 boolean_t remote_match = B_FALSE;
  69 
  70                 for (size_t j = 0; j < rule->rule_nlocal_addr; j++) {
  71                         if (cfg_addr_match(local, &rule->rule_local_addr[j])) {
  72                                 local_match = B_TRUE;
  73                                 break;
  74                         }
  75                 }
  76                 for (size_t j = 0; j < rule->rule_nremote_addr; j++) {
  77                         if (cfg_addr_match(remote,
  78                             &rule->rule_remote_addr[j])) {
  79                                 remote_match = B_TRUE;
  80                                 break;
  81                         }
  82                 }
  83                 if (local_match && remote_match)
  84                         return (rule);
  85         }
  86 
  87         CONFIG_REFRELE(cfg);
  88         return (NULL);
  89 }
  90 
  91 static boolean_t
  92 cfg_addr_match(const sockaddr_u_t *restrict l, const config_addr_t *restrict r)
  93 {
  94         uint32_t mask;
  95 
  96         switch (r->cfa_type) {
  97         case CFG_ADDR_IPV4:
  98                 if (l->sau_ss->ss_family != AF_INET)
  99                         return (B_FALSE);
 100                 if (l->sau_sin->sin_addr.s_addr != r->cfa_startu.cfa_ip4)
 101                         return (B_FALSE);
 102                 return (B_TRUE);
 103         case CFG_ADDR_IPV4_PREFIX:
 104                 /* XXX: this needs testing */
 105                 if (l->sau_ss->ss_family != AF_INET)
 106                         return (B_FALSE);
 107                 mask = (0xffffffff << (32 - r->cfa_endu.cfa_num)) &
 108                     0xffffffff;
 109                 if ((l->sau_sin->sin_addr.s_addr & mask) ==
 110                     (r->cfa_startu.cfa_ip4 &mask))
 111                         return (B_TRUE);
 112                 return (B_FALSE);
 113         case CFG_ADDR_IPV4_RANGE:
 114                 if (l->sau_ss->ss_family != AF_INET)
 115                         return (B_FALSE);
 116                 if (l->sau_sin->sin_addr.s_addr >= r->cfa_startu.cfa_ip4 &&
 117                     l->sau_sin->sin_addr.s_addr <= r->cfa_endu.cfa_ip4)
 118                         return (B_TRUE);
 119                 return (B_FALSE);
 120         case CFG_ADDR_IPV6:
 121                 if (l->sau_ss->ss_family != AF_INET6)
 122                         return (B_FALSE);
 123                 if (IN6_ARE_ADDR_EQUAL(&l->sau_sin6->sin6_addr,
 124                     &r->cfa_startu.cfa_ip6))
 125                         return (B_TRUE);
 126                 return (B_FALSE);
 127         case CFG_ADDR_IPV6_PREFIX:
 128                 if (l->sau_ss->ss_family != AF_INET6)
 129                         return (B_FALSE);
 130                 if (IN6_ARE_PREFIXEDADDR_EQUAL(&l->sau_sin6->sin6_addr,
 131                     &r->cfa_startu.cfa_ip6, r->cfa_endu.cfa_num))
 132                         return (B_TRUE);
 133                 return (B_FALSE);
 134         case CFG_ADDR_IPV6_RANGE:
 135                 if (l->sau_ss->ss_family != AF_INET6)
 136                         return (B_FALSE);
 137                 for (size_t i = 0; i < 16; i++) {
 138                         if ((l->sau_sin6->sin6_addr.s6_addr[i] <
 139                             r->cfa_startu.cfa_ip6.s6_addr[i]) ||
 140                             (l->sau_sin6->sin6_addr.s6_addr[i] >
 141                             r->cfa_endu.cfa_ip6.s6_addr[i]))
 142                                 return (B_FALSE);
 143                 }
 144                 return (B_TRUE);
 145         }
 146         return (B_FALSE);
 147 }
 148 
 149 void
 150 cfg_rule_free(config_rule_t *rule)
 151 {
 152         if (rule == NULL)
 153                 return;
 154 
 155         if (rule->rule_xf != NULL) {
 156                 for (size_t i = 0; rule->rule_xf[i] != NULL; i++)
 157                         free(rule->rule_xf[i]);
 158         }
 159 
 160         free(rule->rule_xf);
 161         free(rule->rule_local_addr);
 162         free(rule->rule_remote_addr);
 163         free(rule->rule_label);
 164         free(rule);
 165 }
 166 
 167 void
 168 cfg_free(config_t *cfg)
 169 {
 170         if (cfg == NULL)
 171                 return;
 172 
 173         size_t i;
 174 
 175         VERIFY3U(cfg->cfg_refcnt, ==, 0);
 176         
 177         for (i = 0;
 178             cfg->cfg_cert_root != NULL && cfg->cfg_cert_root[i] != NULL;
 179             i++)
 180                 free(cfg->cfg_cert_root[i]);
 181 
 182         if (cfg->cfg_cert_trust != NULL) {
 183                 for (i = 0; cfg->cfg_cert_trust[i] != NULL; i++)
 184                         free(cfg->cfg_cert_trust[i]);
 185         }
 186 
 187         if (cfg->cfg_xforms != NULL) {
 188                 for (i = 0; cfg->cfg_xforms[i] != NULL; i++)
 189                         free(cfg->cfg_xforms[i]);
 190         }
 191 
 192         if (cfg->cfg_rules != NULL) {
 193                 for (i = 0; cfg->cfg_rules[i] != NULL; i++)
 194                         cfg_rule_free(cfg->cfg_rules[i]);
 195         }
 196 
 197         free(cfg->cfg_rules);
 198         free(cfg->cfg_xforms);
 199         free(cfg->cfg_proxy);
 200         free(cfg->cfg_socks);
 201         free(cfg->cfg_cert_root);
 202         free(cfg->cfg_cert_trust);
 203         free(cfg);
 204 }