Пример #1
0
int pr_netaddr_is_loopback(const pr_netaddr_t *na) {
  if (!na) {
    errno = EINVAL;
    return -1;
  }

  switch (pr_netaddr_get_family(na)) {
    case AF_INET:
      return IN_IS_ADDR_LOOPBACK(
        (struct in_addr *) pr_netaddr_get_inaddr(na));

#ifdef PR_USE_IPV6
    case AF_INET6:
      /* XXX *sigh* Different platforms implement the IN6_IS_ADDR macros
       * differently.  For example, on Linux, those macros expect to operate
       * on s6_addr32, while on Solaris, the macros operate on struct in6_addr.
       * Certain Drafts define the macros to work on struct in6_addr *, as
       * Solaris does, so Linux may have it wrong.  Tentative research on
       * Google shows some BSD netinet6/in6.h headers that define these
       * macros in terms of struct in6_addr *, so I'll go with that for now.
       * Joy. =P
       */
# ifndef LINUX
      return IN6_IS_ADDR_LOOPBACK(
        (struct in6_addr *) pr_netaddr_get_inaddr(na));
# else
      return IN6_IS_ADDR_LOOPBACK(
        ((struct in6_addr *) pr_netaddr_get_inaddr(na))->s6_addr32);
# endif
#endif /* PR_USE_IPV6 */
  }

  return FALSE;
}
Пример #2
0
int pr_netaddr_is_v4mappedv6(const pr_netaddr_t *na) {
  if (!na) {
    errno = EINVAL;
    return -1;
  }

  switch (pr_netaddr_get_family(na)) {
    case AF_INET:

      /* This function tests only IPv6 addresses, not IPv4 addresses. */
      errno = EINVAL;
      return -1;

#ifdef PR_USE_IPV6
    case AF_INET6: {
      if (!use_ipv6) {
        errno = EINVAL;
        return -1;
      }

# ifndef LINUX
      return IN6_IS_ADDR_V4MAPPED(
        (struct in6_addr *) pr_netaddr_get_inaddr(na));
# else
      return IN6_IS_ADDR_V4MAPPED(
        ((struct in6_addr *) pr_netaddr_get_inaddr(na))->s6_addr32);
# endif
    }
#endif /* PR_USE_IPV6 */
  }

  errno = EPERM;
  return -1;
}
Пример #3
0
END_TEST

START_TEST (netaddr_get_inaddr_test) {
  pr_netaddr_t *addr;
  int family;
  void *inaddr;
  const char *name;

  inaddr = pr_netaddr_get_inaddr(NULL);
  fail_unless(inaddr == NULL, "Failed to handle null arguments");
  fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
    strerror(errno), errno);

  family = AF_INET;
  name = "127.0.0.1";
  addr = pr_netaddr_get_addr(p, name, NULL);
  fail_unless(addr != NULL, "Failed to resolve '%s': %s", name,
    strerror(errno));

  inaddr = pr_netaddr_get_inaddr(addr);
  fail_unless(inaddr != NULL, "Failed to get inaddr: %s", strerror(errno));

#ifdef PR_USE_IPV6
  family = AF_INET6;
  name = "::1";
  addr = pr_netaddr_get_addr(p, name, NULL);
  fail_unless(addr != NULL, "Failed to resolve '%s': %s", name,
    strerror(errno));

  inaddr = pr_netaddr_get_inaddr(addr);
  fail_unless(inaddr != NULL, "Failed to get inaddr: %s", strerror(errno));

  pr_netaddr_disable_ipv6();
  inaddr = pr_netaddr_get_inaddr(addr);
  fail_unless(inaddr == NULL, "Got inaddr unexpectedly");
  fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
    strerror(errno), errno);

  pr_netaddr_enable_ipv6();

  family = addr->na_family;
  addr->na_family = 777;
  inaddr = pr_netaddr_get_inaddr(addr);
  addr->na_family = family;

  fail_unless(inaddr == NULL, "Got inaddr unexpectedly");
  fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
    strerror(errno), errno);
#endif /* PR_USE_IPV6 */
}
Пример #4
0
/* A slightly naughty function that should go away. It relies too much on
 * knowledge of the internal structures of struct in_addr, struct in6_addr.
 */
unsigned int pr_netaddr_get_addrno(const pr_netaddr_t *na) {
  if (!na) {
    errno = EINVAL;
    return -1;
  }

  switch (pr_netaddr_get_family(na)) {
    case AF_INET:
      return na->na_addr.v4.sin_addr.s_addr;

#ifdef PR_USE_IPV6
    case AF_INET6: {

      /* Linux defines s6_addr32 in its netinet/in.h header.
       * FreeBSD defines s6_addr32 in KAME's netinet6/in6.h header.
       * Solaris defines s6_addr32 in its netinet/in.h header, but only
       * for kernel builds.
       */
#if 0
      int *addrs = ((struct sockaddr_in6 *) pr_netaddr_get_inaddr(na))->s6_addr32;
      return addrs[0];
#else
      return 0;
#endif
    }
#endif /* PR_USE_IPV6 */
  }

  errno = EPERM;
  return -1;
}
Пример #5
0
static void *get_v4inaddr(const pr_netaddr_t *na) {

  /* This function is specifically for IPv4 clients (when gethostbyname2(2) is
   * present) that have an IPv4-mapped IPv6 address, when performing reverse
   * DNS checks.  This function is called iff the given netaddr object is
   * indeed an IPv4-mapped IPv6 address.  IPv6 address have 128 bits in their
   * sin6_addr field.  For IPv4-mapped IPv6 addresses, the relevant 32 bits
   * are the last of those 128 bits (or, alternatively, the last 4 bytes of
   * those 16 bytes); hence the read of 12 bytes after the start of the
   * sin6_addr pointer.
   */

  return (((char *) pr_netaddr_get_inaddr(na)) + 12);
}
Пример #6
0
/* The hashing function for the hash table of bindings.  This algorithm
 * is stolen from Apache's http_vhost.c
 */
static unsigned int ipbind_hash_addr(pr_netaddr_t *addr) {
  size_t offset;
  unsigned int key;

  offset = pr_netaddr_get_inaddr_len(addr);

  /* The key is the last four bytes of the IP address.
   * For IPv4, this is the entire address, as always.
   * For IPv6, this is usually part of the MAC address.
   */
  key = *(unsigned *) ((char *) pr_netaddr_get_inaddr(addr) + offset - 4);

  key ^= (key >> 16);
  return ((key >> 8) ^ key) % PR_BINDINGS_TABLE_SIZE;
}
Пример #7
0
const pr_netaddr_t *proxy_ftp_msg_parse_ext_addr(pool *p, const char *msg,
    const pr_netaddr_t *addr, int cmd_id, const char *net_proto) {
  pr_netaddr_t *res = NULL, na;
  int family = 0;
  unsigned short port = 0;
  char delim, *msg_str, *ptr;
  size_t msglen;

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

  if (cmd_id == PR_CMD_EPSV_ID) {
    /* First, find the opening '(' character. */
    ptr = strchr(msg, '(');
    if (ptr == NULL) {
      pr_trace_msg(trace_channel, 12,
        "missing starting '(' character for extended address in '%s'", msg);
      errno = EINVAL;
      return NULL;
    }

    /* Make sure that the last character is a closing ')'. */
    msglen = strlen(ptr);
    if (ptr[msglen-1] != ')') {
      pr_trace_msg(trace_channel, 12,
        "missing ending ')' character for extended address in '%s'", msg);
      errno = EINVAL;
      return NULL;
    }

    msg_str = pstrndup(p, ptr+1, msglen-2);

  } else {
    msg_str = pstrdup(p, msg);
  }

  /* Format is <d>proto<d>ip address<d>port<d> (ASCII in network order),
   * where <d> is an arbitrary delimiter character.
   */
  delim = *msg_str++;

  /* If the network protocol string (e.g. sent by client in EPSV command) is
   * null, then determine the protocol family from the address family we were
   * given.
   */

  /* XXX Hack to skip "all", e.g. "EPSV ALL" commands. */
  if (net_proto != NULL) {
    if (strncasecmp(net_proto, "all", 4) == 0) {
      net_proto = NULL;
    }
  }

  if (net_proto == NULL) {
    if (*msg_str == delim) {
      switch (pr_netaddr_get_family(addr)) {
        case AF_INET:
          family = 1;
          break;

#ifdef PR_USE_IPV6
        case AF_INET6:
          if (pr_netaddr_use_ipv6()) {
            family = 2;
            break;
          }
#endif /* PR_USE_IPV6 */

        default:
          break;
      }

    } else {
      family = atoi(msg_str);
    }

  } else {
    family = atoi(net_proto);
  }

  switch (family) {
    case 1:
      pr_trace_msg(trace_channel, 19, "parsed IPv4 address from '%s'", msg);
      break;

#ifdef PR_USE_IPV6
    case 2:
      pr_trace_msg(trace_channel, 19, "parsed IPv6 address from '%s'", msg);
      if (pr_netaddr_use_ipv6()) {
        break;
      }
#endif /* PR_USE_IPV6 */

    default:
      pr_trace_msg(trace_channel, 12,
        "unsupported network protocol %d", family);
      errno = EPROTOTYPE;
      return NULL;
  }

  /* Now, skip past those numeric characters that atoi() used. */
  while (PR_ISDIGIT(*msg_str)) {
    msg_str++;
  }

  /* If the next character is not the delimiter, it's a badly formatted
   * parameter.
   */
  if (*msg_str == delim) {
    msg_str++;

  } else {
    pr_trace_msg(trace_channel, 17, "rejecting badly formatted message '%s'",
      msg_str);
    errno = EPERM;
    return NULL;
  }

  pr_netaddr_clear(&na);

  /* If the next character IS the delimiter, then the address portion is
   * omitted (which is permissible).
   */
  if (*msg_str == delim) {
    pr_netaddr_set_family(&na, pr_netaddr_get_family(addr));
    pr_netaddr_set_sockaddr(&na, pr_netaddr_get_sockaddr(addr));
    msg_str++;

  } else {
    ptr = strchr(msg_str, delim);
    if (ptr == NULL) {
      /* Badly formatted message. */
      errno = EINVAL;
      return NULL;
    }

    /* Twiddle the string so that just the address portion will be processed
     * by pr_inet_pton().
     */
    *ptr = '\0';

    /* Use pr_inet_pton() to translate the address string into the address
     * value.
     */
    switch (family) {
      case 1: {
        struct sockaddr *sa = NULL;

        pr_netaddr_set_family(&na, AF_INET);
        sa = pr_netaddr_get_sockaddr(&na);
        if (sa) {
          sa->sa_family = AF_INET;
        }

        if (pr_inet_pton(AF_INET, msg_str, pr_netaddr_get_inaddr(&na)) <= 0) {
          pr_trace_msg(trace_channel, 2,
            "error converting IPv4 address '%s': %s", msg_str, strerror(errno));
          errno = EPERM;
          return NULL;
        }

        break;
      }

      case 2: {
        struct sockaddr *sa = NULL;

        pr_netaddr_set_family(&na, AF_INET6);
        sa = pr_netaddr_get_sockaddr(&na);
        if (sa) {
          sa->sa_family = AF_INET6;
        }

        if (pr_inet_pton(AF_INET6, msg_str, pr_netaddr_get_inaddr(&na)) <= 0) {
          pr_trace_msg(trace_channel, 2,
            "error converting IPv6 address '%s': %s", msg_str, strerror(errno));
          errno = EPERM;
          return NULL;
        }

        break;
      }
    }

    /* Advance past the address portion of the argument. */
    msg_str = ++ptr;
  }

  port = atoi(msg_str);

  while (PR_ISDIGIT(*msg_str)) {
    msg_str++;
  }

  /* If the next character is not the delimiter, it's a badly formatted
   * parameter.
   */
  if (*msg_str != delim) {
    pr_trace_msg(trace_channel, 17, "rejecting badly formatted message '%s'",
      msg_str);
    errno = EPERM;
    return NULL;
  }

  /* XXX Use a pool other than session.pool here, in the future. */ 
  res = pr_netaddr_dup(session.pool, &na);
  pr_netaddr_set_port(res, htons(port));

  return res;
}
Пример #8
0
int log_wtmp(char *line, const char *name, const char *host,
    pr_netaddr_t *ip) {
  struct stat buf;
  struct utmp ut;
  int res = 0;
  static int fd = -1;

#if ((defined(SVR4) || defined(__SVR4)) || \
    (defined(__NetBSD__) && defined(HAVE_UTMPX_H))) && \
    !(defined(LINUX) || defined(__hpux) || defined (_AIX))
  /* This "auxilliary" utmp doesn't exist under linux. */
#ifdef __sparcv9
  struct futmpx utx;
  time_t t;
#else
  struct utmpx utx;
#endif
  static int fdx = -1;

#if !defined(WTMPX_FILE) && defined(_PATH_WTMPX)
# define WTMPX_FILE _PATH_WTMPX
#endif

  if (fdx < 0 &&
      (fdx = open(WTMPX_FILE, O_WRONLY|O_APPEND, 0)) < 0) {
    pr_log_pri(PR_LOG_WARNING, "wtmpx %s: %s", WTMPX_FILE, strerror(errno));
    return -1;
  }

  /* Unfortunately, utmp string fields are terminated by '\0' if they are
   * shorter than the size of the field, but if they are exactly the size of
   * the field they don't have to be terminated at all.  Frankly, this sucks.
   * Insane if you ask me.  Unless there's massive uproar, I prefer to err on
   * the side of caution and always null-terminate our strings.
   */
  if (fstat(fdx, &buf) == 0) {
    memset(&utx, 0, sizeof(utx));

    sstrncpy(utx.ut_user, name, sizeof(utx.ut_user));
    sstrncpy(utx.ut_id, "ftp", sizeof(utx.ut_user));
    sstrncpy(utx.ut_line, line, sizeof(utx.ut_line));
    sstrncpy(utx.ut_host, host, sizeof(utx.ut_host));
    utx.ut_pid = getpid();
#if defined(__NetBSD__) && defined(HAVE_UTMPX_H)
    memcpy(&utx.ut_ss, pr_netaddr_get_inaddr(ip), sizeof(utx.ut_ss));
    gettimeofday(&utx.ut_tv, NULL);
#else /* SVR4 */
    utx.ut_syslen = strlen(utx.ut_host)+1;
#  ifdef __sparcv9
    time(&t);
    utx.ut_tv.tv_sec = (time32_t)t;
#  else
    time(&utx.ut_tv.tv_sec);
#  endif
#endif /* SVR4 */

    if (*name)
      utx.ut_type = USER_PROCESS;
    else
      utx.ut_type = DEAD_PROCESS;
#ifdef HAVE_UT_UT_EXIT
    utx.ut_exit.e_termination = 0;
    utx.ut_exit.e_exit = 0;
#endif /* HAVE_UT_UT_EXIT */
    if (write(fdx, (char *)&utx, sizeof(utx)) != sizeof(utx))
      ftruncate(fdx, buf.st_size);

  } else {
    pr_log_debug(DEBUG0, "%s fstat(): %s", WTMPX_FILE, strerror(errno));
    res = -1;
  }

#else /* Non-SVR4 systems */

  if (fd < 0 &&
      (fd = open(WTMP_FILE, O_WRONLY|O_APPEND, 0)) < 0) {
    pr_log_pri(PR_LOG_WARNING, "wtmp %s: %s", WTMP_FILE, strerror(errno));
    return -1;
  }

  if (fstat(fd, &buf) == 0) {
    memset(&ut, 0, sizeof(ut));
#ifdef HAVE_UTMAXTYPE
# ifdef LINUX
    if (ip)
#  ifndef PR_USE_IPV6
      memcpy(&ut.ut_addr, pr_netaddr_get_inaddr(ip), sizeof(ut.ut_addr));
#  else
      memcpy(&ut.ut_addr_v6, pr_netaddr_get_inaddr(ip), sizeof(ut.ut_addr_v6));
#  endif /* !PR_USE_IPV6 */
# else
    sstrncpy(ut.ut_id, "ftp", sizeof(ut.ut_id));
#  ifdef HAVE_UT_UT_EXIT
    ut.ut_exit.e_termination = 0;
    ut.ut_exit.e_exit = 0;
#  endif /* !HAVE_UT_UT_EXIT */
# endif /* !LINUX */
    sstrncpy(ut.ut_line, line, sizeof(ut.ut_line));
    if (name && *name)
      sstrncpy(ut.ut_user, name, sizeof(ut.ut_user));
    ut.ut_pid = getpid();
    if (name && *name)
      ut.ut_type = USER_PROCESS;
    else
      ut.ut_type = DEAD_PROCESS;
#else  /* !HAVE_UTMAXTYPE */
    sstrncpy(ut.ut_line, line, sizeof(ut.ut_line));
    if (name && *name)
      sstrncpy(ut.ut_name, name, sizeof(ut.ut_name));
#endif /* HAVE_UTMAXTYPE */

#ifdef HAVE_UT_UT_HOST
    if (host && *host)
      sstrncpy(ut.ut_host, host, sizeof(ut.ut_host));
#endif /* HAVE_UT_UT_HOST */

    time(&ut.ut_time);
    if (write(fd, (char *)&ut, sizeof(ut)) != sizeof(ut))
      ftruncate(fd, buf.st_size);

  } else {
    pr_log_debug(DEBUG0, "%s fstat(): %s",WTMP_FILE,strerror(errno));
    res = -1;
  }
#endif /* SVR4 */

  return res;
}
Пример #9
0
int pr_netaddr_ncmp(const pr_netaddr_t *na1, const pr_netaddr_t *na2,
    unsigned int bitlen) {
  pool *tmp_pool = NULL;
  pr_netaddr_t *a, *b;
  unsigned int nbytes, nbits;
  const unsigned char *in1, *in2;

  if (na1 && !na2)
    return 1;

  if (!na1 && na2)
    return -1;

  if (!na1 && !na2)
    return 0;

  if (pr_netaddr_get_family(na1) != pr_netaddr_get_family(na2)) {

    /* Cannot compare addresses from different families, unless one
     * of the netaddrs has an AF_INET family, and the other has an
     * AF_INET6 family AND is an IPv4-mapped IPv6 address.
     */

    if (pr_netaddr_is_v4mappedv6(na1) != TRUE &&
        pr_netaddr_is_v4mappedv6(na2) != TRUE) {
      errno = EINVAL;
      return -1;
    }

    if (pr_netaddr_is_v4mappedv6(na1) == TRUE) {
      tmp_pool = make_sub_pool(permanent_pool);

      /* This case means that na1 is an IPv4-mapped IPv6 address, and
       * na2 is an IPv4 address.
       */
      a = pr_netaddr_alloc(tmp_pool);
      pr_netaddr_set_family(a, AF_INET);
      pr_netaddr_set_port(a, pr_netaddr_get_port(na1));
      memcpy(&a->na_addr.v4.sin_addr, get_v4inaddr(na1),
        sizeof(struct in_addr));

      b = (pr_netaddr_t *) na2;

      pr_trace_msg(trace_channel, 6, "comparing IPv4 address '%s' against "
        "IPv4-mapped IPv6 address '%s'", pr_netaddr_get_ipstr(b),
        pr_netaddr_get_ipstr(a));

    } else if (pr_netaddr_is_v4mappedv6(na2) == TRUE) {
      tmp_pool = make_sub_pool(permanent_pool);

      /* This case means that na is an IPv4 address, and na2 is an
       * IPv4-mapped IPv6 address.
       */
      a = (pr_netaddr_t *) na1;

      b = pr_netaddr_alloc(tmp_pool);
      pr_netaddr_set_family(b, AF_INET);
      pr_netaddr_set_port(b, pr_netaddr_get_port(na2));
      memcpy(&b->na_addr.v4.sin_addr, get_v4inaddr(na2),
        sizeof(struct in_addr));

      pr_trace_msg(trace_channel, 6, "comparing IPv4 address '%s' against "
        "IPv4-mapped IPv6 address '%s'", pr_netaddr_get_ipstr(a),
        pr_netaddr_get_ipstr(b));

    } else {
      a = (pr_netaddr_t *) na1;
      b = (pr_netaddr_t *) na2;
    }

  } else {
    a = (pr_netaddr_t *) na1;
    b = (pr_netaddr_t *) na2;
  }

  switch (pr_netaddr_get_family(a)) {
    case AF_INET: {
      /* Make sure that the given number of bits is not more than supported
       * for IPv4 addresses (32).
       */
      if (bitlen > 32) {
        errno = EINVAL;
        return -1;
      }

      break;
    }

#ifdef PR_USE_IPV6
    case AF_INET6: {
      if (use_ipv6) {
        /* Make sure that the given number of bits is not more than supported
         * for IPv6 addresses (128).
         */
        if (bitlen > 128) {
          errno = EINVAL;
          return -1;
        }

        break;
      }
    }
#endif /* PR_USE_IPV6 */

    default:
      errno = EPERM;
      return -1;
  }

  /* Retrieve pointers to the contained in_addrs. */
  in1 = (const unsigned char *) pr_netaddr_get_inaddr(a);
  in2 = (const unsigned char *) pr_netaddr_get_inaddr(b);

  /* Determine the number of bytes, and leftover bits, in the given
   * bit length.
   */
  nbytes = bitlen / 8;
  nbits = bitlen % 8;

  /* Compare bytes, using memcmp(3), first. */
  if (nbytes > 0) {
    int res = memcmp(in1, in2, nbytes);

    /* No need to continue comparing the addresses if they differ already. */
    if (res != 0) {
      if (tmp_pool)
        destroy_pool(tmp_pool);

      return res;
    }
  }

  /* Next, compare the remaining bits in the addresses. */
  if (nbits > 0) {
    unsigned char mask;

    /* Get the bytes in the addresses that have not yet been compared. */
    unsigned char in1byte = in1[nbytes];
    unsigned char in2byte = in2[nbytes];

    /* Build up a mask covering the bits left to be checked. */
    mask = (0xff << (8 - nbits)) & 0xff;

    if ((in1byte & mask) > (in2byte & mask)) {
      if (tmp_pool)
        destroy_pool(tmp_pool);

      return 1;
    }

    if ((in1byte & mask) < (in2byte & mask)) {
      if (tmp_pool)
        destroy_pool(tmp_pool);

      return -1;
    }
  }

  if (tmp_pool)
    destroy_pool(tmp_pool);

  /* If we've made it this far, the addresses match, for the given bit
   * length.
   */
  return 0;
}
Пример #10
0
/* This differs from pr_netaddr_get_ipstr() in that pr_netaddr_get_ipstr()
 * returns a string of the numeric form of the given network address, whereas
 * this function returns a string of the DNS name (if present).
 */
const char *pr_netaddr_get_dnsstr(pr_netaddr_t *na) {
  char *name = NULL;
  char buf[256];

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

  /* If this pr_netaddr_t has already been resolved to an DNS string, return the
   * cached string.
   */
  if (na->na_have_dnsstr)
    return na->na_dnsstr;

  if (reverse_dns) {
    int res = 0;

    pr_trace_msg(trace_channel, 3,
      "verifying DNS name for IP address %s via reverse DNS lookup",
      pr_netaddr_get_ipstr(na));

    memset(buf, '\0', sizeof(buf));
    res = pr_getnameinfo(pr_netaddr_get_sockaddr(na),
      pr_netaddr_get_sockaddr_len(na), buf, sizeof(buf), NULL, 0, NI_NAMEREQD);
    buf[sizeof(buf)-1] = '\0';

    if (res == 0) {
      char **checkaddr;
      struct hostent *hent = NULL;
      unsigned char ok = FALSE;
      int family = pr_netaddr_get_family(na);
      void *inaddr = pr_netaddr_get_inaddr(na);
    
#ifdef HAVE_GETHOSTBYNAME2
      if (pr_netaddr_is_v4mappedv6(na) == TRUE) {
        family = AF_INET;
        inaddr = get_v4inaddr(na);
      }

      hent = gethostbyname2(buf, family);
#else
      hent = gethostbyname(buf);
#endif /* HAVE_GETHOSTBYNAME2 */

      if (hent != NULL) {
        char **alias;

        pr_trace_msg(trace_channel, 10,
          "checking addresses associated with host '%s'",
          hent->h_name ? hent->h_name : "(null)");
        for (alias = hent->h_aliases; *alias; ++alias) {
          pr_trace_msg(trace_channel, 10, "host '%s' has alias '%s'",
            hent->h_name ? hent->h_name : "(null)", *alias);
        }
        
        switch (hent->h_addrtype) {
          case AF_INET:
            if (family == AF_INET) {
              for (checkaddr = hent->h_addr_list; *checkaddr; ++checkaddr) {
                if (memcmp(*checkaddr, inaddr, hent->h_length) == 0) {
                  ok = TRUE;
                  break;
                }
              }
            } 
            break;

#ifdef PR_USE_IPV6
          case AF_INET6:
            if (use_ipv6 && family == AF_INET6) {
              for (checkaddr = hent->h_addr_list; *checkaddr; ++checkaddr) {
                if (memcmp(*checkaddr, inaddr, hent->h_length) == 0) {
                  ok = TRUE;
                  break;
                }
              }
            } 
            break;
#endif /* PR_USE_IPV6 */
        }

        if (ok) {
          name = buf;
          pr_trace_msg(trace_channel, 8,
            "using DNS name '%s' for IP address '%s'", name,
            pr_netaddr_get_ipstr(na));

        } else {
          name = NULL;
          pr_trace_msg(trace_channel, 8,
            "unable to verify any DNS names for IP address '%s'",
            pr_netaddr_get_ipstr(na));
        }

      } else
        pr_log_debug(DEBUG1, "notice: unable to resolve '%s': %s", buf,
          hstrerror(errno));
    }

  } else
    pr_log_debug(DEBUG10,
      "UseReverseDNS off, returning IP address instead of DNS name");

  if (name) {
    name = pr_inet_validate(name);

  } else {
    name = (char *) pr_netaddr_get_ipstr(na);
  }

  /* Copy the string into the pr_netaddr_t cache as well, so we only
   * have to do this once for this pr_netaddr_t.
   */
  memset(na->na_dnsstr, '\0', sizeof(na->na_dnsstr));
  sstrncpy(na->na_dnsstr, name, sizeof(na->na_dnsstr));
  na->na_have_dnsstr = TRUE;

  return na->na_dnsstr;
}
Пример #11
0
/* This differs from pr_netaddr_get_ipstr() in that pr_netaddr_get_ipstr()
 * returns a string of the numeric form of the given network address, whereas
 * this function returns a string of the DNS name (if present).
 */
const char *pr_netaddr_get_dnsstr(pr_netaddr_t *na) {
  char *name = NULL;
  char buf[256];

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

  /* If this pr_netaddr_t has already been resolved to an DNS string, return the
   * cached string.
   */
  if (na->na_have_dnsstr)
    return na->na_dnsstr;

  if (reverse_dns) {
    int res = 0;

    memset(buf, '\0', sizeof(buf));
    res = pr_getnameinfo(pr_netaddr_get_sockaddr(na),
      pr_netaddr_get_sockaddr_len(na), buf, sizeof(buf), NULL, 0, NI_NAMEREQD);

    if (res == 0) {
      char **checkaddr;
      struct hostent *hent = NULL;
      unsigned char ok = FALSE;
      int family = pr_netaddr_get_family(na);
      void *inaddr = pr_netaddr_get_inaddr(na);
    
#ifdef HAVE_GETHOSTBYNAME2
      if (pr_netaddr_is_v4mappedv6(na) == TRUE) {
        family = AF_INET;
        inaddr = get_v4inaddr(na);
      }

      hent = gethostbyname2(buf, family);
#else
      hent = gethostbyname(buf);
#endif /* HAVE_GETHOSTBYNAME2 */

      if (hent != NULL) {
        switch (hent->h_addrtype) {
          case AF_INET:
            if (family == AF_INET) {
              for (checkaddr = hent->h_addr_list; *checkaddr; ++checkaddr) {
                if (memcmp(*checkaddr, inaddr, hent->h_length) == 0) {
                  ok = TRUE;
                  break;
                }
              }
            } 
            break;

#ifdef PR_USE_IPV6
          case AF_INET6:
            if (family == AF_INET6) {
              for (checkaddr = hent->h_addr_list; *checkaddr; ++checkaddr) {
                if (memcmp(*checkaddr, inaddr, hent->h_length) == 0) {
                  ok = TRUE;
                  break;
                }
              }
            } 
            break;
#endif /* PR_USE_IPV6 */
        }

        name = ok ? buf : NULL;

      } else
        pr_log_debug(DEBUG1, "notice: unable to resolve '%s': %s", buf,
          hstrerror(errno));
    }
  }

  if (!name)
    name = (char *) pr_netaddr_get_ipstr(na);

  name = pr_inet_validate(name);

  /* Copy the string into the pr_netaddr_t cache as well, so we only
   * have to do this once for this pr_netaddr_t.
   */
  memset(na->na_dnsstr, '\0', sizeof(na->na_dnsstr));
  sstrncpy(na->na_dnsstr, name, sizeof(na->na_dnsstr));
  na->na_have_dnsstr = TRUE;

  return na->na_dnsstr;
}
Пример #12
0
int pr_netaddr_ncmp(const pr_netaddr_t *na1, const pr_netaddr_t *na2,
    unsigned int bitlen) {
  unsigned int nbytes, nbits;
  const unsigned char *in1, *in2;

  if (na1 && !na2)
    return 1;

  if (!na1 && na2)
    return -1;

  if (!na1 && !na2)
    return 0;

  if (pr_netaddr_get_family(na1) != pr_netaddr_get_family(na2)) {
    /* Cannot compare addresses from different families. */
    errno = EINVAL;
    return -1;
  }

  switch (pr_netaddr_get_family(na1)) {
    case AF_INET: {
      /* Make sure that the given number of bits is not more than supported
       * for IPv4 addresses (32).
       */
      if (bitlen > 32) {
        errno = EINVAL;
        return -1;
      }

      break;
    }

#ifdef PR_USE_IPV6
    case AF_INET6: {
      /* Make sure that the given number of bits is not more than supported
       * for IPv6 addresses (128).
       */
      if (bitlen > 128) {
        errno = EINVAL;
        return -1;
      }

      break;
    }
#endif /* PR_USE_IPV6 */

    default:
      errno = EPERM;
      return -1;
  }

  /* Retrieve pointers to the contained in_addrs. */
  in1 = (const unsigned char *) pr_netaddr_get_inaddr(na1);
  in2 = (const unsigned char *) pr_netaddr_get_inaddr(na2);

  /* Determine the number of bytes, and leftover bits, in the given
   * bit length.
   */
  nbytes = bitlen / 8;
  nbits = bitlen % 8;

  /* Compare bytes, using memcmp(3), first. */
  if (nbytes > 0) {
    int res = memcmp(in1, in2, nbytes);

    /* No need to continue comparing the addresses if they differ already. */
    if (res != 0)
      return res;
  }

  /* Next, compare the remaining bits in the addresses. */
  if (nbits > 0) {
    unsigned char mask;

    /* Get the bytes in the addresses that have not yet been compared. */
    unsigned char in1byte = in1[nbytes];
    unsigned char in2byte = in2[nbytes];

    /* Build up a mask covering the bits left to be checked. */
    mask = (0xff << (8 - nbits)) & 0xff;

    if ((in1byte & mask) > (in2byte & mask))
      return 1;

    if ((in1byte & mask) < (in2byte & mask))
      return -1;
  }

  /* If we've made it this far, the addresses match, for the given bit
   * length.
   */
  return 0;
}
Пример #13
0
int log_wtmp(const char *line, const char *name, const char *host,
    pr_netaddr_t *ip) {
  struct stat buf;
  int res = 0;

#if ((defined(SVR4) || defined(__SVR4)) || \
    (defined(__NetBSD__) && defined(HAVE_UTMPX_H)) || \
    (defined(__FreeBSD_version) && __FreeBSD_version >= 900007 && defined(HAVE_UTMPX_H))) && \
    !(defined(LINUX) || defined(__hpux) || defined (_AIX))
  /* This "auxilliary" utmp doesn't exist under linux. */

#if defined(__sparcv9) && !defined(__NetBSD__) && !defined(__FreeBSD__)
  struct futmpx utx;
  time_t t;

#else
  struct utmpx utx;
#endif

  static int fdx = -1;

#if !defined(WTMPX_FILE)
# if defined(_PATH_WTMPX)
#   define WTMPX_FILE _PATH_WTMPX
# elif defined(_PATH_UTMPX)
#   define WTMPX_FILE _PATH_UTMPX
# else
/* This path works for FreeBSD; not sure what to do for other platforms which
 * don't define _PATH_WTMPX or _PATH_UTMPX.
 */
#   define WTMPX_FILE "/var/log/utx.log"
# endif
#endif

  if (fdx < 0 &&
      (fdx = open(WTMPX_FILE, O_WRONLY|O_APPEND, 0)) < 0) {
    int xerrno = errno;

    pr_log_pri(PR_LOG_WARNING, "failed to open wtmpx %s: %s", WTMPX_FILE,
      strerror(xerrno));

    errno = xerrno;
    return -1;
  }

  (void) pr_fs_get_usable_fd2(&fdx);

  /* Unfortunately, utmp string fields are terminated by '\0' if they are
   * shorter than the size of the field, but if they are exactly the size of
   * the field they don't have to be terminated at all.  Frankly, this sucks.
   * Insane if you ask me.  Unless there's massive uproar, I prefer to err on
   * the side of caution and always null-terminate our strings.
   */
  if (fstat(fdx, &buf) == 0) {
    memset(&utx, 0, sizeof(utx));

    sstrncpy(utx.ut_user, name, sizeof(utx.ut_user));
    sstrncpy(utx.ut_id, pr_session_get_protocol(PR_SESS_PROTO_FL_LOGOUT),
      sizeof(utx.ut_user));
    sstrncpy(utx.ut_line, line, sizeof(utx.ut_line));
    sstrncpy(utx.ut_host, host, sizeof(utx.ut_host));
    utx.ut_pid = session.pid ? session.pid : getpid();

#if defined(__NetBSD__) && defined(HAVE_UTMPX_H)
    memcpy(&utx.ut_ss, pr_netaddr_get_inaddr(ip), sizeof(utx.ut_ss));
    gettimeofday(&utx.ut_tv, NULL);

#elif defined(__FreeBSD_version) && __FreeBSD_version >= 900007 && defined(HAVE_UTMPX_H)
    gettimeofday(&utx.ut_tv, NULL);

#else /* SVR4 */
    utx.ut_syslen = strlen(utx.ut_host)+1;

#  if defined(__sparcv9) && !defined(__FreeBSD__)
    time(&t);
    utx.ut_tv.tv_sec = (time32_t)t;
#  else
    time(&utx.ut_tv.tv_sec);
#  endif

#endif /* SVR4 */

    if (*name)
      utx.ut_type = USER_PROCESS;
    else
      utx.ut_type = DEAD_PROCESS;

#ifdef HAVE_UT_UT_EXIT
    utx.ut_exit.e_termination = 0;
    utx.ut_exit.e_exit = 0;
#endif /* HAVE_UT_UT_EXIT */

    if (write(fdx, (char *) &utx, sizeof(utx)) != sizeof(utx)) {
      (void) ftruncate(fdx, buf.st_size);
    }

  } else {
    pr_log_debug(DEBUG0, "%s fstat(): %s", WTMPX_FILE, strerror(errno));
    res = -1;
  }

#else /* Non-SVR4 systems */
  struct utmp ut;
  static int fd = -1;

  if (fd < 0 &&
      (fd = open(WTMP_FILE, O_WRONLY|O_APPEND, 0)) < 0) {
    int xerrno = errno;

    pr_log_pri(PR_LOG_WARNING, "failed to open wtmp %s: %s", WTMP_FILE,
      strerror(xerrno));

    errno = xerrno;
    return -1;
  }

  (void) pr_fs_get_usable_fd2(&fd);

  if (fstat(fd, &buf) == 0) {
    memset(&ut, 0, sizeof(ut));

#ifdef HAVE_UTMAXTYPE

# ifdef LINUX
    if (ip)
#  ifndef PR_USE_IPV6
      memcpy(&ut.ut_addr, pr_netaddr_get_inaddr(ip), sizeof(ut.ut_addr));
#  else
      memcpy(&ut.ut_addr_v6, pr_netaddr_get_inaddr(ip), sizeof(ut.ut_addr_v6));
#  endif /* !PR_USE_IPV6 */

# else
    sstrncpy(ut.ut_id, pr_session_get_protocol(PR_SESS_PROTO_FL_LOGOUT),
      sizeof(ut.ut_id));

#  ifdef HAVE_UT_UT_EXIT
    ut.ut_exit.e_termination = 0;
    ut.ut_exit.e_exit = 0;
#  endif /* !HAVE_UT_UT_EXIT */

# endif /* !LINUX */
    sstrncpy(ut.ut_line, line, sizeof(ut.ut_line));

    if (name && *name)
      sstrncpy(ut.ut_user, name, sizeof(ut.ut_user));

    ut.ut_pid = session.pid ? session.pid : getpid();

    if (name && *name)
      ut.ut_type = USER_PROCESS;
    else
      ut.ut_type = DEAD_PROCESS;

#else  /* !HAVE_UTMAXTYPE */
    sstrncpy(ut.ut_line, line, sizeof(ut.ut_line));

    if (name && *name) {
      sstrncpy(ut.ut_name, name, sizeof(ut.ut_name));
    }
#endif /* HAVE_UTMAXTYPE */

#ifdef HAVE_UT_UT_HOST
    if (host && *host) {
      sstrncpy(ut.ut_host, host, sizeof(ut.ut_host));
    }
#endif /* HAVE_UT_UT_HOST */

    ut.ut_time = time(NULL);

    if (write(fd, (char *) &ut, sizeof(ut)) != sizeof(ut)) {
      if (ftruncate(fd, buf.st_size) < 0) {
        pr_log_debug(DEBUG0, "error truncating '%s': %s", WTMP_FILE,
          strerror(errno));
      }
    }

  } else {
    pr_log_debug(DEBUG0, "%s fstat(): %s", WTMP_FILE, strerror(errno));
    res = -1;
  }
#endif /* SVR4 */

  return res;
}