コード例 #1
0
ファイル: netacl.c プロジェクト: laoflch/proftpd
pr_netacl_t *pr_netacl_create(pool *p, char *aclstr) {
  pr_netacl_t *acl;
  char *cp, *aclstr_dup;

  if (p == NULL ||
      aclstr == NULL) {
    errno = EINVAL;
    return NULL;
  }

  if (strlen(aclstr) == 0) {
    errno = EINVAL;
    return NULL;
  }

  /* Parse the given rule into a netacl object. */
  acl = pcalloc(p, sizeof(pr_netacl_t));

  aclstr_dup = pstrdup(p, aclstr);

  if (strncasecmp(aclstr, "all", 4) == 0) {
    aclstr_dup = pstrdup(p, "all");
    acl->type = PR_NETACL_TYPE_ALL;

  } else if (strncasecmp(aclstr, "none", 5) == 0) {
    aclstr_dup = pstrdup(p, "none");
    acl->type = PR_NETACL_TYPE_NONE;

  } else if ((cp = strchr(aclstr, '/')) != NULL) {
    char *tmp;

    acl->type = PR_NETACL_TYPE_IPMASK;
    *cp = '\0';

    /* Check if the given rule is negated. */
    if (*aclstr == '!') {
      acl->negated = TRUE;
      aclstr++;
    }

    /* We have some type of IP/mask, either IPv4 or IPv6.  We know that colons
     * will only appear in IPv6 addresses, so...
     */

    if (strspn(aclstr, "0123456789ABCDEFabcdef.:") != strlen(aclstr)) {
      errno = EINVAL;
      return NULL;
    }

    acl->addr = pr_netaddr_get_addr(p, aclstr, NULL);
    if (acl->addr == NULL) {
      return NULL;
    }

    /* Determine what the given bitmask is. */
    acl->masklen = strtol(cp + 1, &tmp, 10);

    if (tmp && *tmp) {
      /* Invalid bitmask syntax. */
      errno = EINVAL;
      return NULL;
    }

    *cp = '/';

    /* Make sure the given mask length is appropriate for the address. */
    switch (pr_netaddr_get_family(acl->addr)) {
      case AF_INET: {
        /* Make sure that the given number of bits is not more than supported
         * for IPv4 addresses (32).
         */
        if (acl->masklen > 32) {
          errno = EINVAL;
          return NULL;
        }

        break;
      }

#ifdef PR_USE_IPV6
      case AF_INET6: {
        if (pr_netaddr_use_ipv6()) {
          if (acl->masklen > 128) {
            errno = EINVAL;
            return NULL;

          } else if (pr_netaddr_is_v4mappedv6(acl->addr) == TRUE &&
                     acl->masklen > 32) {
            /* The admin may be trying to use IPv6-style masks on IPv4-mapped
             * IPv6 addresses, which of course will not work as expected.
             * If the mask is 32 bits or more, warn the admin.
             */
            pr_log_pri(PR_LOG_WARNING, "warning: possibly using IPv6-style netmask on IPv4-mapped IPv6 address, which will not work as expected");
            pr_trace_msg(trace_channel, 1, "possibly using IPv6-style netmask on IPv4-mapped IPv6 address (%s), which will not work as expected", aclstr);

            break;
          }
        }
      }
#endif /* PR_USE_IPV6 */

      default:
        break;
    }

#ifdef PR_USE_IPV6
  } else if (pr_netaddr_use_ipv6() &&
             strspn(aclstr, "0123456789ABCDEFabcdef.:!") != strlen(aclstr)) {
#else
  } else if (strspn(aclstr, "0123456789.!") != strlen(aclstr)) {
#endif /* PR_USE_IPV6 */

    /* Check if the given rule is negated. */
    if (*aclstr == '!') {
      acl->negated = TRUE;
      aclstr++;
    }

    /* If there are any glob characters (e.g. '{', '[', '*', or '?'), or if the
     * first character is a '.', then treat the rule as a glob.
     */
    if (strpbrk(aclstr, "{[*?")) {
      register unsigned int i;
      size_t aclstr_len = strlen(aclstr);
      pr_netacl_type_t netacl_type = PR_NETACL_TYPE_IPGLOB;

      /* Is this a DNS glob, or an IP address glob?  To find out, see if there
       * are any non-IP characters (i.e. alphabetical characters, taking IPv6
       * into account).
       */
      for (i = 0; i < aclstr_len; i++) {
        if (PR_ISALPHA(aclstr[i])) {
#ifdef PR_USE_IPV6
          if (pr_netaddr_use_ipv6()) {
            if (aclstr[i] == 'A' || aclstr[i] == 'a' ||
                aclstr[i] == 'B' || aclstr[i] == 'b' ||
                aclstr[i] == 'C' || aclstr[i] == 'c' ||
                aclstr[i] == 'D' || aclstr[i] == 'd' ||
                aclstr[i] == 'E' || aclstr[i] == 'e' ||
                aclstr[i] == 'F' || aclstr[i] == 'f') {
              continue;
            }

            netacl_type = PR_NETACL_TYPE_DNSGLOB;
            break;

          } else {
            netacl_type = PR_NETACL_TYPE_DNSGLOB;
            break;
          }
#else
          netacl_type = PR_NETACL_TYPE_DNSGLOB;
          break;
#endif /* PR_USE_IPV6 */
        }
      }

      acl->type = netacl_type;
      acl->pattern = pstrdup(p, aclstr);

    } else if (*aclstr == '.') {
      acl->type = PR_NETACL_TYPE_DNSGLOB;
      acl->pattern = pstrcat(p, "*", aclstr, NULL);

    } else {
      acl->type = PR_NETACL_TYPE_DNSMATCH;
      acl->pattern = pstrdup(p, aclstr);
    }

  } else if (strchr(aclstr, '.') == NULL) {

    /* Check if the given rule is negated. */
    if (*aclstr == '!') {
      acl->negated = TRUE;
      aclstr++;
    }

    /* If there are any glob characters (e.g. '{', '[', '*', or '?'), or if the
     * first character is a '.', then treat the rule as a glob.
     */
    if (strpbrk(aclstr, "{[*?")) {
      acl->type = PR_NETACL_TYPE_DNSGLOB;
      acl->pattern = pstrdup(p, aclstr);

    } else {
      acl->type = PR_NETACL_TYPE_DNSMATCH;
      acl->pattern = pstrdup(p, aclstr);
    }

  } else {

    /* Check if the given rule is negated. */
    if (*aclstr == '!') {
      acl->negated = TRUE;
      aclstr++;
    }

    /* If the last character is a '.', then treat the rule as an IP glob. */
    if (aclstr[strlen(aclstr)-1] == '.') {
      acl->type = PR_NETACL_TYPE_IPGLOB;
      acl->pattern = pstrcat(p, aclstr, "*", NULL);

    } else {
      register unsigned int i;
      int use_glob = FALSE, use_dns = FALSE;
      size_t aclstr_len;

      /* Is this a DNS glob, DNS match, IP glob, or IP match?
       *
       * First, check for any glob characters.  After that, determine whether
       * it's a DNS or IP type ACL.
       */

      /* If there are any glob characters (e.g. '{', '[', '*', or '?'), or
       * if the first character is a '.', then treat the rule as a glob.
       */
      use_glob = (strpbrk(aclstr, "{[*?") != NULL);

      aclstr_len = strlen(aclstr);
      for (i = 0; i < aclstr_len; i++) {
        if (PR_ISALPHA(aclstr[i])) {
#ifdef PR_USE_IPV6
          if (pr_netaddr_use_ipv6()) {
            if (aclstr[i] == 'A' || aclstr[i] == 'a' ||
                aclstr[i] == 'B' || aclstr[i] == 'b' ||
                aclstr[i] == 'C' || aclstr[i] == 'c' ||
                aclstr[i] == 'D' || aclstr[i] == 'd' ||
                aclstr[i] == 'E' || aclstr[i] == 'e' ||
                aclstr[i] == 'F' || aclstr[i] == 'f') {
              continue;
            }

            use_dns = TRUE;
            break;

          } else {
            use_dns = TRUE;
            break;
          }
#else
          use_dns = TRUE;
          break;
#endif /* PR_USE_IPV6 */
        }
      }

      if (!use_dns) {
        acl->type = use_glob ? PR_NETACL_TYPE_IPGLOB : PR_NETACL_TYPE_IPMATCH;
        acl->addr = pr_netaddr_get_addr(p, aclstr, NULL);

        if (acl->addr == NULL) {
           return NULL;
        }

      } else {
        if (use_glob) {
          acl->type = PR_NETACL_TYPE_DNSGLOB;
          acl->pattern = pstrdup(p, aclstr);

        } else if (*aclstr == '.') {
          acl->type = PR_NETACL_TYPE_DNSGLOB;
          acl->pattern = pstrcat(p, "*", aclstr, NULL);

        } else {
          acl->type = PR_NETACL_TYPE_DNSMATCH;
          acl->pattern = pstrdup(p, aclstr);
        }
      }
    }
  }

  acl->aclstr = aclstr_dup;
  return acl;
}
コード例 #2
0
ファイル: mod_ifversion.c プロジェクト: Nubisa/JXPanel
static int parse_version(char *version_str, unsigned int *version,
    unsigned int *version_status) {
  register unsigned int i;
  char c, *ptr, *tmp;
  int have_suffix = FALSE;
  size_t revision_len = 0;

  /* Parse the given version string.  We expect to see:
   *
   *  major[.minor[.revision[suffix]]]
   *
   * Examples:
   *
   *  "1"
   *  "1.3"
   *  "1.3.3"
   *  "1.3.3rc1"
   *  "1.3.3a"
   */

  /* Quick sanity check */
  if (!PR_ISDIGIT(version_str[0])) {
    return -1;
  }

  /* Parse the major number */
  ptr = strchr(version_str, '.');
  if (ptr) {
    *ptr = '\0';

    tmp = NULL;
    version[0] = (int) strtoul(version_str, &tmp, 10);
    if (tmp && *tmp) {
      *ptr = '.';
      return -1;
    }

    *ptr = '.';

    /* Make sure that there is a character following the period. */
    if (*(ptr + 1) != '\0') {
      version_str = ptr + 1;

    } else {
      return -1;
    }

  } else {
    tmp = NULL;
    version[0] = (int) strtoul(version_str, &tmp, 10);
    if (tmp && *tmp) {
      return -1;
    }

    return 0;
  }

  /* Parse the minor number */
  ptr = strchr(version_str, '.');
  if (ptr) {
    *ptr = '\0';

    tmp = NULL;
    version[1] = (int) strtoul(version_str, &tmp, 10);
    if (tmp && *tmp) {
      *ptr = '.';
      return -1;
    }

    *ptr = '.';

    /* Make sure that there is a character following the period. */
    if (*(ptr + 1) != '\0') {
      version_str = ptr + 1;

    } else {
      return -1;
    }

  } else {
    tmp = NULL;
    version[1] = (int) strtoul(version_str, &tmp, 10);
    if (tmp && *tmp) {
      return -1;
    }

    return 0;
  }

  /* Parse the revision number.  This is trickier, since we have to also
   * account for the suffix, and there is no delimiter between the revision
   * number and the suffix characters.
   *
   * We thus scan every character from here on out.  If they are all digits,
   * then it is a "stable" release (no suffix).  Otherwise, it's either an
   * RC release, a maintenance release, or it's a badly formatted version
   * string.
   */

  for (i = 0; i < strlen(version_str); i++) {
    if (!PR_ISDIGIT(version_str[i])) {
      if (i > 0) {
        have_suffix = TRUE;
        break;
      }

      /* Syntax error */
      return -1;

    } else {
      /* Keep track of the number of characters in the revision number; this
       * is handy for afterwards, assuming we do have a suffix.
       */
      revision_len++;
    }
  }

  if (!have_suffix) {
    tmp = NULL;
    version[2] = (int) strtoul(version_str, &tmp, 10);
    if (tmp && *tmp) {
      return -1;
    }

    /* Stable release */
    *version_status = IFVERSION_STATUS_STABLE;
    return 0;
  }

  ptr = version_str + revision_len;
  c = *ptr;
  *ptr = '\0';

  tmp = NULL;
  version[2] = (int) strtoul(version_str, &tmp, 10);

  if (tmp && *tmp) {
    *ptr = c;
    return -1;
  }

  *ptr = c;

  /* We already know, based on the suffix check, that there are characters
   * after the revision number.
   */
  version_str = ptr;

  /* If the next two characters are "rc" (case-insensitive) followed by
   * digits, it's an RC release.  (If there are no digits, it's a syntax
   * error.)
   *
   * If there only a single character left, it is a maintenance release.
   */

  if (strlen(version_str) == 1) {
    if (!PR_ISALPHA(version_str[0])) {
      /* Syntax error */
      return -1;
    }

    /* Maintenance release. */
    c = toupper(version_str[0]);
    *version_status = IFVERSION_STATUS_STABLE + (c - 'A');
    return 0;
  }

  if (strncasecmp(version_str, "rc", 2) != 0) {
    return -1;
  }

  /* RC release */

  *version_status = IFVERSION_STATUS_RC;

  if (strlen(version_str) == 2) {
    return 0;
  }

  version_str += 2;

  for (i = 0; i < strlen(version_str); i++) {
    if (!PR_ISDIGIT(version_str[i])) {
      /* Syntax error */
      return -1;
    }
  }

  tmp = NULL;
  *version_status += strtoul(version_str, &tmp, 10);

  if (tmp && *tmp) {
    return -1;
  }

  return 0;
}