Exemplo n.º 1
0
int pr_netaddr_fnmatch(pr_netaddr_t *na, const char *pattern, int flags) {

  /* Note: I'm still not sure why proftpd bundles an fnmatch(3)
   * implementation rather than using the system library's implementation.
   * Needs looking into.
   *
   * The FNM_CASEFOLD flag is a GNU extension; perhaps the bundled
   * implementation was added to make that flag available on other platforms.
   */
  int match_flags = PR_FNM_NOESCAPE|PR_FNM_CASEFOLD;

  if (!na || !pattern) {
    errno = EINVAL;
    return -1;
  }

  if (flags & PR_NETADDR_MATCH_DNS) {
    const char *dnsstr = pr_netaddr_get_dnsstr(na);

    if (pr_fnmatch(pattern, dnsstr, match_flags) == 0) {
      pr_trace_msg(trace_channel, 6, "DNS name '%s' matches pattern '%s'",
        dnsstr, pattern);
      return TRUE;
    }
  }

  if (flags & PR_NETADDR_MATCH_IP) {
    const char *ipstr = pr_netaddr_get_ipstr(na);

    if (pr_fnmatch(pattern, ipstr, match_flags) == 0) {
      pr_trace_msg(trace_channel, 6, "DNS name '%s' matches pattern '%s'",
        ipstr, pattern);
      return TRUE;
    }
  }

  pr_trace_msg(trace_channel, 4, "addr %s does not match pattern '%s'",
    pr_netaddr_get_ipstr(na), pattern);
  return FALSE;
}
Exemplo n.º 2
0
END_TEST

START_TEST (netacl_match_test) {
  pr_netacl_t *acl;
  pr_netaddr_t *addr;
  char *acl_str;
  int have_localdomain = FALSE, res;

  res = pr_netacl_match(NULL, NULL);
  fail_unless(res == -2, "Failed to handle NULL arguments");
  fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");

  acl_str = "all";
  acl = pr_netacl_create(p, acl_str);
  fail_unless(acl != NULL, "Failed to handle ACL string '%s': %s", acl_str,
    strerror(errno));

  res = pr_netacl_match(acl, NULL);
  fail_unless(res == -2, "Failed to handle NULL addr");
  fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");

  addr = pr_netaddr_get_addr(p, "localhost", NULL);
  fail_unless(addr != NULL, "Failed to get addr for '%s': %s", "localhost",
    strerror(errno));

  /* It's possible that the DNS name for 'localhost' that is used will
   * actually be 'localhost.localdomain', depending on the contents of
   * the host's /etc/hosts file.
   */
  if (strcmp(pr_netaddr_get_dnsstr(addr), "localhost.localdomain") == 0) {
    have_localdomain = TRUE;
  }

  res = pr_netacl_match(NULL, addr);
  fail_unless(res == -2, "Failed to handle NULL ACL");
  fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");

  res = pr_netacl_match(acl, addr);
  fail_unless(res == 1, "Failed to positively match ACL to addr: %s",
    strerror(errno));

  acl_str = "none";
  acl = pr_netacl_create(p, acl_str);
  fail_unless(acl != NULL, "Failed to handle ACL string '%s': %s", acl_str,
    strerror(errno));

  res = pr_netacl_match(acl, addr);
  fail_unless(res == -1, "Failed to negatively match ACL to addr: %s",
    strerror(errno));

  acl_str = pstrdup(p, "127.0.0.1");
  acl = pr_netacl_create(p, acl_str);
  fail_unless(acl != NULL, "Failed to handle ACL string '%s': %s", acl_str,
    strerror(errno));

  res = pr_netacl_match(acl, addr);
  fail_unless(res == 1, "Failed to positively match ACL to addr: %s",
    strerror(errno));

  acl_str = pstrdup(p, "!127.0.0.1");
  acl = pr_netacl_create(p, acl_str);
  fail_unless(acl != NULL, "Failed to handle ACL string '%s': %s", acl_str,
    strerror(errno));

  res = pr_netacl_match(acl, addr);
  fail_unless(res == -1, "Failed to negatively match ACL to addr: %s",
    strerror(errno));

  acl_str = pstrdup(p, "192.168.0.1");
  acl = pr_netacl_create(p, acl_str);
  fail_unless(acl != NULL, "Failed to handle ACL string '%s': %s", acl_str,
    strerror(errno));

  res = pr_netacl_match(acl, addr);
  fail_unless(res == 0, "Failed to match ACL to addr: %s", strerror(errno));

  acl_str = pstrdup(p, "!192.168.0.1");
  acl = pr_netacl_create(p, acl_str);
  fail_unless(acl != NULL, "Failed to handle ACL string '%s': %s", acl_str,
    strerror(errno));

  res = pr_netacl_match(acl, addr);
  fail_unless(res == 1, "Failed to positively match ACL to addr: %s",
    strerror(errno));

  acl_str = pstrdup(p, "127.0.0.0/24");
  acl = pr_netacl_create(p, acl_str);
  fail_unless(acl != NULL, "Failed to handle ACL string '%s': %s", acl_str,
    strerror(errno));

  res = pr_netacl_match(acl, addr);
  fail_unless(res == 1, "Failed to positively match ACL to addr: %s",
    strerror(errno));

  acl_str = pstrdup(p, "!127.0.0.0/24");
  acl = pr_netacl_create(p, acl_str);
  fail_unless(acl != NULL, "Failed to handle ACL string '%s': %s", acl_str,
    strerror(errno));

  res = pr_netacl_match(acl, addr);
  fail_unless(res == -1, "Failed to negatively match ACL to addr: %s",
    strerror(errno));

  acl_str = pstrdup(p, "127.0.0.");
  acl = pr_netacl_create(p, acl_str);
  fail_unless(acl != NULL, "Failed to handle ACL string '%s': %s", acl_str,
    strerror(errno));

  res = pr_netacl_match(acl, addr);
  fail_unless(res == 1, "Failed to positively match ACL to addr: %s",
    strerror(errno));

  acl_str = pstrdup(p, "!127.0.0.");
  acl = pr_netacl_create(p, acl_str);
  fail_unless(acl != NULL, "Failed to handle ACL string '%s': %s", acl_str,
    strerror(errno));

  res = pr_netacl_match(acl, addr);
  fail_unless(res == -1, "Failed to negatively match ACL to addr: %s",
    strerror(errno));

  if (!have_localdomain) {
    acl_str = pstrdup(p, "localhost");

  } else {
    acl_str = pstrdup(p, "localhost.localdomain");
  }

  acl = pr_netacl_create(p, acl_str);
  fail_unless(acl != NULL, "Failed to handle ACL string '%s': %s", acl_str,
    strerror(errno));

  res = pr_netacl_match(acl, addr);
  fail_unless(res == 1, "Failed to positively match ACL to addr: %s",
    strerror(errno));

  if (!have_localdomain) {
    acl_str = pstrdup(p, "!localhost");

  } else {
    acl_str = pstrdup(p, "!localhost.localdomain");
  }

  acl = pr_netacl_create(p, acl_str);
  fail_unless(acl != NULL, "Failed to handle ACL string '%s': %s", acl_str,
    strerror(errno));

  res = pr_netacl_match(acl, addr);
  fail_unless(res == -1, "Failed to negatively match ACL to addr: %s",
    strerror(errno));

  if (!have_localdomain) {
    acl_str = pstrdup(p, "loc*st");

  } else {
    acl_str = pstrdup(p, "loc*st.loc*in");
  }

  acl = pr_netacl_create(p, acl_str);
  fail_unless(acl != NULL, "Failed to handle ACL string '%s': %s", acl_str,
    strerror(errno));

  res = pr_netacl_match(acl, addr);
  fail_unless(res == 1, "Failed to positively match ACL to addr: %s",
    strerror(errno));

  if (!have_localdomain) {
    acl_str = pstrdup(p, "!loc*st");

  } else {
    acl_str = pstrdup(p, "!loc*st.loc*in");
  }

  acl = pr_netacl_create(p, acl_str);
  fail_unless(acl != NULL, "Failed to handle ACL string '%s': %s", acl_str,
    strerror(errno));

  res = pr_netacl_match(acl, addr);
  fail_unless(res == -1, "Failed to negatively match ACL to addr: %s",
    strerror(errno));
}
Exemplo n.º 3
0
pr_class_t *pr_class_match_addr(pr_netaddr_t *addr) {
  pr_class_t *cls;
  pool *tmp_pool;

  if (!addr) {
    errno = EINVAL;
    return NULL;
  }

  tmp_pool = make_sub_pool(permanent_pool);

  for (cls = class_list; cls; cls = cls->cls_next) {
    array_header *acl_list = cls->cls_acls;
    pr_netacl_t **acls = acl_list->elts;
    register int i;
    int next_class = FALSE;

    /* For each ACL rule in this class, compare the rule against the given
     * address.  The address matches the given class depending on the
     * Satisfy setting: if "any", the class matches if any rule matches;
     * if "all", the class matches only if _all_ rules match.
     */
    for (i = 0; i < acl_list->nelts; i++) {
      int res;

      if (next_class)
        break;

      if (acls[i] == NULL)
        continue;

      switch (cls->cls_satisfy) {
        case PR_CLASS_SATISFY_ANY:
          pr_trace_msg(trace_channel, 6,
            "checking addr '%s' (%s) against class '%s' rule: %s "
            "(requires any ACL matching)", pr_netaddr_get_ipstr(addr),
            pr_netaddr_get_dnsstr(addr), cls->cls_name,
            pr_netacl_get_str(tmp_pool, acls[i]));

          res = pr_netacl_match(acls[i], addr);
          if (res == 1) {
            destroy_pool(tmp_pool);
            return cls;
          }
          break;

        case PR_CLASS_SATISFY_ALL:
          pr_trace_msg(trace_channel, 6,
            "checking addr '%s' (%s) against class '%s' ACL: %s "
            "(requires all ACLs matching)", pr_netaddr_get_ipstr(addr),
            pr_netaddr_get_dnsstr(addr), cls->cls_name,
            pr_netacl_get_str(tmp_pool, acls[i]));

          res = pr_netacl_match(acls[i], addr);

          if (res <= 0)
            next_class = TRUE;
          break;
      }
    }

    /* If this is a "Satisfy all" class, and all rules have matched
     * (positively or negatively), then it matches the address.
     */
    if (next_class == FALSE &&
        cls->cls_satisfy == PR_CLASS_SATISFY_ALL &&
        i == acl_list->nelts) {
      destroy_pool(tmp_pool);
      return cls;
    }
  }

  destroy_pool(tmp_pool);

  errno = ENOENT;
  return NULL;
}
Exemplo n.º 4
0
END_TEST

#ifdef PR_USE_IPV6
START_TEST (netaddr_get_dnsstr_ipv6_test) {
  pr_netaddr_t *addr;
  const char *ip, *res;

  ip = "::1";

  res = pr_netaddr_get_dnsstr(NULL);
  fail_unless(res == NULL, "Failed to handle null argument");
  fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");

  addr = pr_netaddr_get_addr(p, ip, NULL);
  fail_unless(addr != NULL, "Failed to get addr for '%s': %s", ip,
    strerror(errno));

  pr_netaddr_set_reverse_dns(FALSE);

  res = pr_netaddr_get_dnsstr(addr);
  fail_unless(res != NULL, "Failed to get DNS str for addr: %s",
    strerror(errno));
  fail_unless(strcmp(res, ip) == 0, "Expected '%s', got '%s'", ip, res);

  pr_netaddr_set_reverse_dns(TRUE);

  /* Even though we should expect a DNS name, not an IP address, the
   * previous call to pr_netaddr_get_dnsstr() cached the IP address.
   */
  res = pr_netaddr_get_dnsstr(addr);
  fail_unless(res != NULL, "Failed to get DNS str for addr: %s",
    strerror(errno));
  fail_unless(strcmp(res, ip) == 0, "Expected '%s', got '%s'", ip, res);

  pr_netaddr_clear(addr);

  /* Clearing the address doesn't work, since that removes even the address
   * info, in addition to the cached strings.
   */
  res = pr_netaddr_get_dnsstr(addr);
  fail_unless(res != NULL, "Failed to get DNS str for addr: %s",
    strerror(errno));
  fail_unless(strcmp(res, "") == 0, "Expected '%s', got '%s'", "", res);

  /* We need to clear the netaddr internal cache as well. */
  pr_netaddr_clear_ipcache(ip);
  addr = pr_netaddr_get_addr(p, ip, NULL);
  fail_unless(addr != NULL, "Failed to get addr for '%s': %s", ip,
    strerror(errno));

  mark_point();
  fail_unless(addr->na_have_dnsstr == 0, "addr already has cached DNS str");

  mark_point();
  res = pr_netaddr_get_dnsstr(addr);
  fail_unless(res != NULL, "Failed to get DNS str for addr: %s",
    strerror(errno));

  mark_point();

  /* Depending on the contents of /etc/hosts, resolving ::1 could
   * return either "localhost" or "localhost.localdomain".  Perhaps even
   * other variations, although these should be the most common.
   */
  fail_unless(strcmp(res, "localhost") == 0 ||
              strcmp(res, "localhost.localdomain") == 0 ||
              strcmp(res, "localhost6") == 0 ||
              strcmp(res, "localhost6.localdomain") == 0 ||
              strcmp(res, "ip6-localhost") == 0 ||
              strcmp(res, "ip6-loopback") == 0 ||
              strcmp(res, ip) == 0,
    "Expected '%s', got '%s'", "localhost, localhost.localdomain et al", res);
}
Exemplo n.º 5
0
/* Returns 1 if there was a positive match, -1 if there was a negative
 * match, -2 if there was an error, and zero if there was no match at all.
 */
int pr_netacl_match(const pr_netacl_t *acl, const pr_netaddr_t *addr) {
  pool *tmp_pool;

  if (acl == NULL ||
      addr == NULL) {
    errno = EINVAL;
    return -2;
  }

  tmp_pool = make_sub_pool(permanent_pool);

  switch (acl->type) {
    case PR_NETACL_TYPE_ALL:
      pr_trace_msg(trace_channel, 10, "addr '%s' matched rule 'ALL' ('%s')",
        pr_netaddr_get_ipstr(addr), pr_netacl_get_str(tmp_pool, acl));
      destroy_pool(tmp_pool);
      return 1;

    case PR_NETACL_TYPE_NONE:
      pr_trace_msg(trace_channel, 10, "addr '%s' matched rule 'NONE'",
        pr_netaddr_get_ipstr(addr));
      destroy_pool(tmp_pool);
      return -1;

    case PR_NETACL_TYPE_IPMASK:
      pr_trace_msg(trace_channel, 10,
        "checking addr '%s' against IP mask rule '%s'",
        pr_netaddr_get_ipstr(addr), acl->aclstr);

      if (pr_netaddr_ncmp(addr, acl->addr, acl->masklen) == 0) {
        pr_trace_msg(trace_channel, 10, "addr '%s' matched IP mask rule '%s'",
          pr_netaddr_get_ipstr(addr), acl->aclstr);
        destroy_pool(tmp_pool);

        if (acl->negated)
          return -1;

        return 1;

      } else {
        if (acl->negated) {
          destroy_pool(tmp_pool);
          return 1;
        }
      }
      break;

    case PR_NETACL_TYPE_IPMATCH:
      pr_trace_msg(trace_channel, 10,
        "checking addr '%s' against IP address rule '%s'",
        pr_netaddr_get_ipstr(addr), acl->aclstr);

      if (pr_netaddr_cmp(addr, acl->addr) == 0) {
        pr_trace_msg(trace_channel, 10,
          "addr '%s' matched IP address rule '%s'",
          pr_netaddr_get_ipstr(addr), acl->aclstr);
        destroy_pool(tmp_pool);

        if (acl->negated)
          return -1;

        return 1;

      } else {
        if (acl->negated) {
          destroy_pool(tmp_pool);
          return 1;
        }
      }
      break;
 
    case PR_NETACL_TYPE_DNSMATCH:
      pr_trace_msg(trace_channel, 10,
        "checking addr '%s' against DNS name rule '%s'",
        pr_netaddr_get_dnsstr(addr), acl->pattern);

      if (strcmp(pr_netaddr_get_dnsstr(addr), acl->pattern) == 0) {
        pr_trace_msg(trace_channel, 10,
          "addr '%s' (%s) matched DNS name rule '%s'",
          pr_netaddr_get_ipstr(addr), pr_netaddr_get_dnsstr(addr),
          acl->aclstr);
        destroy_pool(tmp_pool);

        if (acl->negated)
          return -1;

        return 1;

      } else {
        if (acl->negated) {
          destroy_pool(tmp_pool);
          return 1;
        }
      }
      break;

    case PR_NETACL_TYPE_IPGLOB:
      pr_trace_msg(trace_channel, 10,
        "checking addr '%s' against IP glob rule '%s'",
        pr_netaddr_get_ipstr(addr), acl->aclstr);

      if (pr_netaddr_fnmatch(addr, acl->pattern,
          PR_NETADDR_MATCH_IP) == TRUE) {
        pr_trace_msg(trace_channel, 10,
          "addr '%s' matched IP glob rule '%s'",
          pr_netaddr_get_ipstr(addr), acl->aclstr);
        destroy_pool(tmp_pool);

        if (acl->negated)
          return -1;

        return 1;

      } else {
        if (acl->negated) {
          destroy_pool(tmp_pool);
          return 1;
        }
      }
      break;

    case PR_NETACL_TYPE_DNSGLOB:
      if (ServerUseReverseDNS) {
        pr_trace_msg(trace_channel, 10,
          "checking addr '%s' against DNS glob rule '%s'",
          pr_netaddr_get_dnsstr(addr), acl->pattern);

        if (pr_netaddr_fnmatch(addr, acl->pattern,
            PR_NETADDR_MATCH_DNS) == TRUE) {
          pr_trace_msg(trace_channel, 10,
            "addr '%s' (%s) matched DNS glob rule '%s'",
            pr_netaddr_get_ipstr(addr), pr_netaddr_get_dnsstr(addr),
            acl->aclstr);
          destroy_pool(tmp_pool);

          if (acl->negated)
            return -1;

          return 1;

        } else {
          if (acl->negated) {
            destroy_pool(tmp_pool);
            return 1;
          }
        }

      } else {
        pr_trace_msg(trace_channel, 10,
          "skipping comparing addr '%s' (%s) against DNS glob rule '%s' "
          "because UseReverseDNS is off", pr_netaddr_get_ipstr(addr),
          pr_netaddr_get_dnsstr(addr), acl->aclstr);
      }
      break;
  }

  destroy_pool(tmp_pool);
  return 0;
}