Example #1
0
/** Address resolver.
 * Resolves an address - be it numeric or a hostname, IPv4 or IPv6.
 *
 * @param hostname is the host to resolve.
 * @param addr is the structure to put the result into.
 *
 * @returns Zero on success, -1 on error.
 */
static int
_crywrap_addr_get (const char *hostname, struct sockaddr_storage **addr)
{
  struct addrinfo *res;
  struct addrinfo hints;
  ssize_t len;
  char *lz = NULL;

  if (idna_to_ascii_lz (hostname, &lz, 0) != IDNA_SUCCESS)
    return -1;

  memset (&hints, 0, sizeof (hints));
  hints.ai_family = PF_UNSPEC;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_protocol = IPPROTO_IP;
  *addr = calloc (1, sizeof (struct sockaddr_storage));
  if (*addr == NULL)
    {
      free(lz);
      return -1;
    }

  if (getaddrinfo (lz, NULL, &hints, &res) != 0)
    {
      free (lz);
      return -1;
    }

  free (lz);

  switch (res->ai_addr->sa_family)
    {
    case AF_INET:
      len = sizeof (struct sockaddr_in);
      break;
    case AF_INET6:
      len = sizeof (struct sockaddr_in6);
      break;
    default:
      freeaddrinfo (res);
      return -1;
    }

  if (len < (ssize_t)res->ai_addrlen)
    {
      freeaddrinfo (res);
      return -1;
    }

  memcpy (*addr, res->ai_addr, res->ai_addrlen);
  freeaddrinfo (res);

  return 0;
}
Example #2
0
File: params.c Project: dnstap/knot
char* name_from_idn(const char *idn_name) {
#ifdef LIBIDN
	char *name = NULL;

	int rc = idna_to_ascii_lz(idn_name, &name, 0);
	if (rc != IDNA_SUCCESS) {
		ERR("IDNA (%s)\n", idna_strerror(rc));
		return NULL;
	}

	return name;
#endif
	return strdup(idn_name);
}
Example #3
0
/**
 * Encode a native string to IDN.  Handle the full string and do not split
 * off a namespace prefix.
 * @param in Input string in native locale encoding.
 * @return IDN encoded output string.
 */
std::string
IdnTool::encodeFull (const std::string& in) const
{
  char* buf = nullptr;

  const Idna_flags flags = static_cast<Idna_flags> (0);
  Idna_rc rc;
  rc = static_cast<Idna_rc> (idna_to_ascii_lz (in.c_str (), &buf, flags));

  if (rc != IDNA_SUCCESS)
    {
      std::free (buf);
      std::ostringstream msg;
      msg << "IDNA encoding failed: " << idna_strerror (rc);
      throw std::runtime_error (msg.str ());
    }
  assert (buf);

  const std::string res(buf);
  std::free (buf);

  return res;
}
Example #4
0
int
main (void)
{
  char buf[BUFSIZ];
  char *p;
  int rc;
  size_t i;

  setlocale (LC_ALL, "");

  printf ("Input domain encoded as `%s': ", stringprep_locale_charset ());
  fflush (stdout);
  if (!fgets (buf, BUFSIZ, stdin))
    perror ("fgets");
  buf[strlen (buf) - 1] = '\0';

  printf ("Read string (length %ld): ", (long int) strlen (buf));
  for (i = 0; i < strlen (buf); i++)
    printf ("%02x ", buf[i] & 0xFF);
  printf ("\n");

  rc = idna_to_ascii_lz (buf, &p, 0);
  if (rc != IDNA_SUCCESS)
    {
      printf ("ToASCII() failed (%d): %s\n", rc, idna_strerror (rc));
      return EXIT_FAILURE;
    }

  printf ("ACE label (length %ld): '%s'\n", (long int) strlen (p), p);
  for (i = 0; i < strlen (p); i++)
    printf ("%02x ", p[i] & 0xFF);
  printf ("\n");

  free (p);

  return 0;
}
Example #5
0
int
main (int argc, char *argv[])
{
  char buf[BUFSIZ];
  char *p;
  int rc;
  size_t i;

  setlocale (LC_ALL, "");

  printf ("Input domain encoded as `%s': ", stringprep_locale_charset ());
  fflush (stdout);
  fgets (buf, BUFSIZ, stdin);
  buf[strlen (buf) - 1] = '\0';

  printf ("Read string (length %d): ", strlen (buf));
  for (i = 0; i < strlen (buf); i++)
    printf ("%02x ", buf[i] & 0xFF);
  printf ("\n");

  rc = idna_to_ascii_lz (buf, &p, 0);
  if (rc != IDNA_SUCCESS)
    {
      printf ("ToASCII() failed... %d\n", rc);
      exit (1);
    }

  printf ("ACE label (length %d): '%s'\n", strlen (p), p);
  for (i = 0; i < strlen (p); i++)
    printf ("%02x ", p[i] & 0xFF);
  printf ("\n");

  free (p);

  return 0;
}
Example #6
0
/* port to mutt from msmtp's tls.c */
static int check_host (X509 *x509cert, const char *hostname, char *err, size_t errlen)
{
        int i, rc = 0;
/* hostname in ASCII format: */
        char *hostname_ascii = NULL;
/* needed to get the common name: */
        X509_NAME *x509_subject;
        char *buf = NULL;
        int bufsize;
/* needed to get the DNS subjectAltNames: */
        STACK_OF(GENERAL_NAME) *subj_alt_names;
        int subj_alt_names_count;
        GENERAL_NAME *subj_alt_name;
/* did we find a name matching hostname? */
        int match_found;

/* Check if 'hostname' matches the one of the subjectAltName extensions of
 * type DNS or the Common Name (CN). */

#ifdef HAVE_LIBIDN
        if (idna_to_ascii_lz(hostname, &hostname_ascii, 0) != IDNA_SUCCESS) {
                hostname_ascii = safe_strdup(hostname);
        }
#else
        hostname_ascii = safe_strdup(hostname);
#endif

/* Try the DNS subjectAltNames. */
        match_found = 0;
        if ((subj_alt_names = X509_get_ext_d2i(x509cert, NID_subject_alt_name,
        NULL, NULL))) {
                subj_alt_names_count = sk_GENERAL_NAME_num(subj_alt_names);
                for (i = 0; i < subj_alt_names_count; i++) {
                        subj_alt_name = sk_GENERAL_NAME_value(subj_alt_names, i);
                        if (subj_alt_name->type == GEN_DNS) {
                                if (subj_alt_name->d.ia5->length >= 0 &&
                                        mutt_strlen((char *)subj_alt_name->d.ia5->data) == (size_t)subj_alt_name->d.ia5->length &&
                                        (match_found = hostname_match(hostname_ascii,
                                (char *)(subj_alt_name->d.ia5->data)))) {
                                        break;
                                }
                        }
                }
        }

        if (!match_found) {
/* Try the common name */
                if (!(x509_subject = X509_get_subject_name(x509cert))) {
                        if (err && errlen)
                                strfcpy (err, _("cannot get certificate subject"), errlen);
                        goto out;
                }

/* first get the space requirements */
                bufsize = X509_NAME_get_text_by_NID(x509_subject, NID_commonName,
                        NULL, 0);
                if (bufsize == -1) {
                        if (err && errlen)
                                strfcpy (err, _("cannot get certificate common name"), errlen);
                        goto out;
                }
                bufsize++;                        /* space for the terminal nul char */
                buf = safe_malloc((size_t)bufsize);
                if (X509_NAME_get_text_by_NID(x509_subject, NID_commonName,
                buf, bufsize) == -1) {
                        if (err && errlen)
                                strfcpy (err, _("cannot get certificate common name"), errlen);
                        goto out;
                }
/* cast is safe since bufsize is incremented above, so bufsize-1 is always
 * zero or greater.
 */
                if (mutt_strlen(buf) == (size_t)bufsize - 1) {
                        match_found = hostname_match(hostname_ascii, buf);
                }
        }

        if (!match_found) {
                if (err && errlen)
                        snprintf (err, errlen, _("certificate owner does not match hostname %s"),
                                hostname);
                goto out;
        }

        rc = 1;

        out:
        FREE(&buf);
        FREE(&hostname_ascii);

        return rc;
}
Example #7
0
int net_open_socket(const char *hostname, int port, int timeout, int *ret_fd,
        char **canonical_name, char **address, char **errstr)
{
    int fd;
    char *port_string;
    struct addrinfo hints;
    struct addrinfo *res0;
    struct addrinfo *res;
    int error_code;
    int failure_errno;
    int cause;
    char nameinfo_buffer[NI_MAXHOST];
#ifdef HAVE_LIBIDN
    char *hostname_ascii;
#endif

    hints.ai_family = PF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = 0;
    hints.ai_protocol = 0;
    hints.ai_addrlen = 0;
    hints.ai_canonname = NULL;
    hints.ai_addr = NULL;
    hints.ai_next = NULL;
    port_string = xasprintf("%d", port);
#ifdef HAVE_LIBIDN
    if (idna_to_ascii_lz(hostname, &hostname_ascii, 0) != IDNA_SUCCESS)
    {
        hostname_ascii = xstrdup(hostname);
    }
    error_code = getaddrinfo(hostname_ascii, port_string, &hints, &res0);
    free(hostname_ascii);
#else
    error_code = getaddrinfo(hostname, port_string, &hints, &res0);
#endif
    free(port_string);
    if (error_code)
    {
#ifdef W32_NATIVE
        *errstr = xasprintf(_("cannot locate host %s: %s"),
                hostname, wsa_strerror(WSAGetLastError()));
#else
        if (error_code == EAI_SYSTEM && errno == EINTR)
        {
            *errstr = xasprintf(_("operation aborted"));
        }
        else
        {
            *errstr = xasprintf(_("cannot locate host %s: %s"), hostname,
                    error_code == EAI_SYSTEM ? strerror(errno)
                    : gai_strerror(error_code));
        }
#endif
        return NET_EHOSTNOTFOUND;
    }

    fd = -1;
    cause = 0;
    failure_errno = 0;
    for (res = res0; res; res = res->ai_next)
    {
        fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
        if (fd < 0)
        {
            cause = 1;
#ifdef W32_NATIVE
            failure_errno = WSAGetLastError();
#else
            failure_errno = errno;
#endif
            continue;
        }
        if (net_connect(fd, res->ai_addr, res->ai_addrlen, timeout) < 0)
        {
            cause = 2;
#ifdef W32_NATIVE
            if (WSAGetLastError() != WSAENETUNREACH)
            {
                failure_errno = WSAGetLastError();
            }
#else
            if (errno != ENETUNREACH)
            {
                failure_errno = errno;
            }
#endif
            close(fd);
            fd = -1;
            continue;
        }
        break;
    }

    if (fd >= 0)
    {
        if (canonical_name)
        {
            if (getnameinfo(res->ai_addr, res->ai_addrlen, nameinfo_buffer,
                        sizeof(nameinfo_buffer), NULL, 0, NI_NAMEREQD) == 0)
            {
                *canonical_name = xstrdup(nameinfo_buffer);
            }
            else
            {
                *canonical_name = NULL;
            }
        }
        if (address)
        {
            if (getnameinfo(res->ai_addr, res->ai_addrlen, nameinfo_buffer,
                        sizeof(nameinfo_buffer), NULL, 0, NI_NUMERICHOST) == 0)
            {
                *address = xstrdup(nameinfo_buffer);
            }
            else
            {
                *address = NULL;
            }
        }
    }

    freeaddrinfo(res0);

    if (fd < 0)
    {
        if (cause == 1)
        {
            *errstr = xasprintf(_("cannot create socket: %s"),
#ifdef W32_NATIVE
                    wsa_strerror(failure_errno)
#else
                    strerror(failure_errno)
#endif
                    );
            return NET_ESOCKET;
        }
        else /* cause == 2 */
        {
#ifdef W32_NATIVE
            if (failure_errno == 0)
            {
                failure_errno = WSAENETUNREACH;
            }
            *errstr = xasprintf(_("cannot connect to %s, port %d: %s"),
                    hostname, port, wsa_strerror(failure_errno));
#else
            if (failure_errno == EINTR)
            {
                *errstr = xasprintf(_("operation aborted"));
            }
            else
            {
                if (failure_errno == 0)
                {
                    failure_errno = ENETUNREACH;
                }
                *errstr = xasprintf(_("cannot connect to %s, port %d: %s"),
                        hostname, port, strerror(failure_errno));
            }
#endif
            return NET_ECONNECT;
        }
    }

    net_set_io_timeout(fd, timeout);
    *ret_fd = fd;
    return NET_EOK;
}
Example #8
0
int
ping_set_dest (PING * ping, char *host)
{
#if HAVE_DECL_GETADDRINFO
  int rc;
  struct addrinfo hints, *res;
  char *p;

# ifdef HAVE_IDN
  rc = idna_to_ascii_lz (host, &p, 0);	/* P is allocated.  */
  if (rc)
    return 1;
# else /* !HAVE_IDN */
  p = host;
# endif

  memset (&hints, 0, sizeof (hints));
  hints.ai_family = AF_INET;
  hints.ai_flags = AI_CANONNAME;
# ifdef AI_IDN
  hints.ai_flags |= AI_IDN;
# endif
# ifdef AI_CANONIDN
  hints.ai_flags |= AI_CANONIDN;
# endif

  rc = getaddrinfo (p, NULL, &hints, &res);
# ifdef HAVE_IDN
  free (p);
# endif

  if (rc)
    return 1;

  memcpy (&ping->ping_dest.ping_sockaddr, res->ai_addr, res->ai_addrlen);
  ping->ping_hostname = strdup (res->ai_canonname);
  freeaddrinfo (res);

  return 0;
#else /* !HAVE_DECL_GETADDRINFO */

  struct sockaddr_in *s_in = &ping->ping_dest.ping_sockaddr;
  s_in->sin_family = AF_INET;
# ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
  s_in->sin_len = sizeof (*s_in);
# endif
  if (inet_aton (host, &s_in->sin_addr))
    ping->ping_hostname = strdup (host);
  else
    {
      struct hostent *hp;
# ifdef HAVE_IDN
      char *p;
      int rc;

      rc = idna_to_ascii_lz (host, &p, 0);
      if (rc)
	return 1;
      hp = gethostbyname (p);
      free (p);
# else /* !HAVE_IDN */
      hp = gethostbyname (host);
# endif
      if (!hp)
	return 1;

      s_in->sin_family = hp->h_addrtype;
      if (hp->h_length > (int) sizeof (s_in->sin_addr))
	hp->h_length = sizeof (s_in->sin_addr);

      memcpy (&s_in->sin_addr, hp->h_addr, hp->h_length);
      ping->ping_hostname = strdup (hp->h_name);
    }
  return 0;
#endif /* !HAVE_DECL_GETADDRINFO */
}
Example #9
0
int raw_socket_open (CONNECTION* conn)
{
        int rc;
        int fd;

        char *host_idna = NULL;

#ifdef HAVE_GETADDRINFO
/* --- IPv4/6 --- */

/* "65536\0" */
        char port[6];
        struct addrinfo hints;
        struct addrinfo* res;
        struct addrinfo* cur;

/* we accept v4 or v6 STREAM sockets */
        memset (&hints, 0, sizeof (hints));

        if (option (OPTUSEIPV6))
                hints.ai_family = AF_UNSPEC;
        else
                hints.ai_family = AF_INET;

        hints.ai_socktype = SOCK_STREAM;

        snprintf (port, sizeof (port), "%d", conn->account.port);

# ifdef HAVE_LIBIDN
        if (idna_to_ascii_lz (conn->account.host, &host_idna, 1) != IDNA_SUCCESS) {
                mutt_error (_("Bad IDN \"%s\"."), conn->account.host);
                return -1;
        }
# else
        host_idna = conn->account.host;
# endif

        if (!option(OPTNOCURSES))
                mutt_message (_("Looking up %s..."), conn->account.host);

        rc = getaddrinfo (host_idna, port, &hints, &res);

# ifdef HAVE_LIBIDN
        FREE (&host_idna);
# endif

        if (rc) {
                mutt_error (_("Could not find the host \"%s\""), conn->account.host);
                mutt_sleep (2);
                return -1;
        }

        if (!option(OPTNOCURSES))
                mutt_message (_("Connecting to %s..."), conn->account.host);

        rc = -1;
        for (cur = res; cur != NULL; cur = cur->ai_next) {
                fd = socket (cur->ai_family, cur->ai_socktype, cur->ai_protocol);
                if (fd >= 0) {
                        if ((rc = socket_connect (fd, cur->ai_addr)) == 0) {
                                fcntl (fd, F_SETFD, FD_CLOEXEC);
                                conn->fd = fd;
                                break;
                        }
                        else
                                close (fd);
                }
        }

        freeaddrinfo (res);

#else
/* --- IPv4 only --- */

        struct sockaddr_in sin;
        struct hostent* he;
        int i;

        memset (&sin, 0, sizeof (sin));
        sin.sin_port = htons (conn->account.port);
        sin.sin_family = AF_INET;

# ifdef HAVE_LIBIDN
        if (idna_to_ascii_lz (conn->account.host, &host_idna, 1) != IDNA_SUCCESS) {
                mutt_error (_("Bad IDN \"%s\"."), conn->account.host);
                return -1;
        }
# else
        host_idna = conn->account.host;
# endif

        if (!option(OPTNOCURSES))
                mutt_message (_("Looking up %s..."), conn->account.host);

        he = gethostbyname (host_idna);

# ifdef HAVE_LIBIDN
        FREE (&host_idna);
# endif

        if (! he) {
                mutt_error (_("Could not find the host \"%s\""), conn->account.host);

                return -1;
        }

        if (!option(OPTNOCURSES))
                mutt_message (_("Connecting to %s..."), conn->account.host);

        rc = -1;
        for (i = 0; he->h_addr_list[i] != NULL; i++) {
                memcpy (&sin.sin_addr, he->h_addr_list[i], he->h_length);
                fd = socket (PF_INET, SOCK_STREAM, IPPROTO_IP);

                if (fd >= 0) {
                        if ((rc = socket_connect (fd, (struct sockaddr*) &sin)) == 0) {
                                fcntl (fd, F_SETFD, FD_CLOEXEC);
                                conn->fd = fd;
                                break;
                        }
                        else
                                close (fd);
                }
        }
#endif
        if (rc) {
                mutt_error (_("Could not connect to %s (%s)."), conn->account.host,
                        (rc > 0) ? strerror (rc) : _("unknown error"));
                mutt_sleep (2);
                return -1;
        }

        return 0;
}
Example #10
0
/* This function takes a hesiod (name, type) and returns a DNS
 * name which is to be resolved.
 */
char *hesiod_to_bind(void *context, const char *name, const char *type)
{
  struct hesiod_p *ctx = (struct hesiod_p *) context;
  char bindname[MAXDNAME], *p, *ret, *idn_ret, **rhs_list = NULL;
  const char *rhs;
  int len, rc;

  if (strlen(name) > sizeof(bindname) - 1)
    {
      errno = EMSGSIZE;
      return NULL;
    }
  strcpy(bindname, name);

  /* Find the right right hand side to use, possibly truncating bindname. */
  p = strchr(bindname, '@');
  if (p)
    {
      *p++ = 0;
      if (strchr(p, '.'))
	rhs = name + (p - bindname);
      else
	{
	  rhs_list = hesiod_resolve(context, p, "rhs-extension");
	  if (rhs_list)
	    rhs = *rhs_list;
	  else
	    {
	      errno = ENOENT;
	      return NULL;
	    }
	}
    } else
      rhs = ctx->rhs;

  /* See if we have enough room. */
  len = strlen(bindname) + 1 + strlen(type);
  if (ctx->lhs)
    len += strlen(ctx->lhs) + ((ctx->lhs[0] != '.') ? 1 : 0);
  len += strlen(rhs) + ((rhs[0] != '.') ? 1 : 0);
  if (len > sizeof(bindname) - 1)
    {
      if (rhs_list)
	hesiod_free_list(context, rhs_list);
      errno = EMSGSIZE;
      return NULL;
    }

  /* Put together the rest of the domain. */
  strcat(bindname, ".");
  strcat(bindname, type);
  if (ctx->lhs)
    {
      if (ctx->lhs[0] != '.')
	strcat(bindname, ".");
      strcat(bindname, ctx->lhs);
    }
  if (rhs[0] != '.')
    strcat(bindname, ".");
  strcat(bindname, rhs);

  /* rhs_list is no longer needed, since we're done with rhs. */
  if (rhs_list)
    hesiod_free_list(context, rhs_list);

  /* Make a copy of the result and return it to the caller. */
#ifdef HAVE_LIBIDN
  rc = idna_to_ascii_lz(bindname, &idn_ret, 0);
  if (rc != IDNA_SUCCESS)
    {
      errno = EINVAL;
      return NULL;
    }
  ret = strdup(idn_ret);
  idn_free(idn_ret);
#else
  ret = strdup(bindname);
#endif
  if (!ret)
    {
      errno = ENOMEM;
      return NULL;
    }
  return ret;
}
Example #11
0
File: tls.c Project: yomei-o/msmtp
int tls_check_cert(tls_t *tls, const char *hostname, char **errstr)
{
#ifdef HAVE_LIBGNUTLS
    int error_code;
    const char *error_msg;
    unsigned int status;
    const gnutls_datum_t *cert_list;
    unsigned int cert_list_size;
    unsigned int i;
    gnutls_x509_crt_t cert;
    time_t t1, t2;
    size_t size;
    unsigned char fingerprint[20];
    char *idn_hostname = NULL;

    if (tls->have_trust_file || tls->have_sha1_fingerprint
            || tls->have_md5_fingerprint)
    {
        error_msg = _("TLS certificate verification failed");
    }
    else
    {
        error_msg = _("TLS certificate check failed");
    }

    if (tls->have_sha1_fingerprint || tls->have_md5_fingerprint)
    {
        /* If one of these matches, we trust the peer and do not perform any
         * other checks. */
        if (!(cert_list = gnutls_certificate_get_peers(
                        tls->session, &cert_list_size)))
        {
            *errstr = xasprintf(_("%s: no certificate was found"), error_msg);
            return TLS_ECERT;
        }
        if (gnutls_x509_crt_init(&cert) < 0)
        {
            *errstr = xasprintf(
                    _("%s: cannot initialize certificate structure"),
                    error_msg);
            return TLS_ECERT;
        }
        if (gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER)
                < 0)
        {
            *errstr = xasprintf(_("%s: error parsing certificate %u of %u"),
                    error_msg, 0 + 1, cert_list_size);
            return TLS_ECERT;
        }
        if (tls->have_sha1_fingerprint)
        {
            size = 20;
            if (gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA,
                        fingerprint, &size) != 0)
            {
                *errstr = xasprintf(_("%s: error getting SHA1 fingerprint"),
                        error_msg);
                gnutls_x509_crt_deinit(cert);
                return TLS_ECERT;
            }
            if (memcmp(fingerprint, tls->fingerprint, 20) != 0)
            {
                *errstr = xasprintf(_("%s: the certificate fingerprint "
                            "does not match"), error_msg);
                gnutls_x509_crt_deinit(cert);
                return TLS_ECERT;
            }
        }
        else
        {
            size = 16;
            if (gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_MD5,
                        fingerprint, &size) != 0)
            {
                *errstr = xasprintf(_("%s: error getting MD5 fingerprint"),
                        error_msg);
                gnutls_x509_crt_deinit(cert);
                return TLS_ECERT;
            }
            if (memcmp(fingerprint, tls->fingerprint, 16) != 0)
            {
                *errstr = xasprintf(_("%s: the certificate fingerprint "
                            "does not match"), error_msg);
                gnutls_x509_crt_deinit(cert);
                return TLS_ECERT;
            }
        }
        gnutls_x509_crt_deinit(cert);
        return TLS_EOK;
    }

    /* If 'tls->have_trust_file' is true, this function uses the trusted CAs
     * in the credentials structure. So you must have installed one or more CA
     * certificates. */
    gnutls_certificate_set_verify_flags(tls->cred,
            GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
    if ((error_code = gnutls_certificate_verify_peers2(tls->session,
                    &status)) != 0)
    {
        *errstr = xasprintf("%s: %s", error_msg, gnutls_strerror(error_code));
        return TLS_ECERT;
    }
    if (tls->have_trust_file)
    {
        if (status & GNUTLS_CERT_REVOKED)
        {
            *errstr = xasprintf(_("%s: the certificate has been revoked"),
                    error_msg);
            return TLS_ECERT;
        }
        if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
        {
            *errstr = xasprintf(
                    _("%s: the certificate hasn't got a known issuer"),
                    error_msg);
            return TLS_ECERT;
        }
        if (status & GNUTLS_CERT_INVALID)
        {
            *errstr = xasprintf(_("%s: the certificate is not trusted"),
                    error_msg);
            return TLS_ECERT;
        }
    }
    if (gnutls_certificate_type_get(tls->session) != GNUTLS_CRT_X509)
    {
        *errstr = xasprintf(_("%s: the certificate type is not X509"),
                error_msg);
        return TLS_ECERT;
    }
    if (!(cert_list = gnutls_certificate_get_peers(
                    tls->session, &cert_list_size)))
    {
        *errstr = xasprintf(_("%s: no certificate was found"), error_msg);
        return TLS_ECERT;
    }
    /* Needed to check times: */
    if ((t1 = time(NULL)) < 0)
    {
        *errstr = xasprintf("%s: cannot get system time: %s", error_msg,
                strerror(errno));
        return TLS_ECERT;
    }
    /* Check the certificate chain. All certificates in the chain must have
     * valid activation/expiration times. The first certificate in the chain is
     * the host's certificate; it must match the hostname. */
    for (i = 0; i < cert_list_size; i++)
    {
        if (gnutls_x509_crt_init(&cert) < 0)
        {
            *errstr = xasprintf(
                    _("%s: cannot initialize certificate structure"),
                    error_msg);
            return TLS_ECERT;
        }
        if (gnutls_x509_crt_import(cert, &cert_list[i], GNUTLS_X509_FMT_DER)
                < 0)
        {
            *errstr = xasprintf(_("%s: error parsing certificate %u of %u"),
                    error_msg, i + 1, cert_list_size);
            return TLS_ECERT;
        }
        /* Check hostname */
        if (i == 0)
        {
#if GNUTLS_VERSION_NUMBER < 0x030400 && defined(HAVE_LIBIDN)
            idna_to_ascii_lz(hostname, &idn_hostname, 0);
#endif
            error_code = gnutls_x509_crt_check_hostname(cert,
                    idn_hostname ? idn_hostname : hostname);
            free(idn_hostname);
            if (error_code == 0)
            {
                *errstr = xasprintf(_("%s: the certificate owner does not "
                            "match hostname %s"), error_msg, hostname);
                return TLS_ECERT;
            }
        }
        /* Check certificate times */
        if ((t2 = gnutls_x509_crt_get_activation_time(cert)) < 0)
        {
            *errstr = xasprintf(_("%s: cannot get activation time for "
                        "certificate %u of %u"),
                    error_msg, i + 1, cert_list_size);
            return TLS_ECERT;
        }
        if (t2 > t1)
        {
            *errstr = xasprintf(
                    _("%s: certificate %u of %u is not yet activated"),
                    error_msg, i + 1, cert_list_size);
            return TLS_ECERT;
        }
        if ((t2 = gnutls_x509_crt_get_expiration_time(cert)) < 0)
        {
            *errstr = xasprintf(_("%s: cannot get expiration time for "
                        "certificate %u of %u"),
                    error_msg, i + 1, cert_list_size);
            return TLS_ECERT;
        }
        if (t2 < t1)
        {
            *errstr = xasprintf(_("%s: certificate %u of %u has expired"),
                    error_msg, i + 1, cert_list_size);
            return TLS_ECERT;
        }
        gnutls_x509_crt_deinit(cert);
    }

    return TLS_EOK;
#endif /* HAVE_LIBGNUTLS */

#ifdef HAVE_LIBSSL
    X509 *x509cert;
    long status;
    const char *error_msg;
    int i;
    /* hostname in ASCII format: */
    char *idn_hostname = NULL;
    /* needed to get the common name: */
    X509_NAME *x509_subject;
    char *buf;
    int length;
    /* needed to get the DNS subjectAltNames: */
    void *subj_alt_names;
    int subj_alt_names_count;
    GENERAL_NAME *subj_alt_name;
    /* did we find a name matching hostname? */
    int match_found;
    /* needed for fingerprint checking */
    unsigned int usize;
    unsigned char fingerprint[20];


    if (tls->have_trust_file)
    {
        error_msg = _("TLS certificate verification failed");
    }
    else
    {
        error_msg = _("TLS certificate check failed");
    }

    /* Get certificate */
    if (!(x509cert = SSL_get_peer_certificate(tls->ssl)))
    {
        *errstr = xasprintf(_("%s: no certificate was sent"), error_msg);
        return TLS_ECERT;
    }

    if (tls->have_sha1_fingerprint || tls->have_md5_fingerprint)
    {
        /* If one of these matches, we trust the peer and do not perform any
         * other checks. */
        if (tls->have_sha1_fingerprint)
        {
            usize = 20;
            if (!X509_digest(x509cert, EVP_sha1(), fingerprint, &usize))
            {
                *errstr = xasprintf(_("%s: error getting SHA1 fingerprint"),
                        error_msg);
                X509_free(x509cert);
                return TLS_ECERT;
            }
            if (memcmp(fingerprint, tls->fingerprint, 20) != 0)
            {
                *errstr = xasprintf(_("%s: the certificate fingerprint "
                            "does not match"), error_msg);
                X509_free(x509cert);
                return TLS_ECERT;
            }
        }
        else
        {
            usize = 16;
            if (!X509_digest(x509cert, EVP_md5(), fingerprint, &usize))
            {
                *errstr = xasprintf(_("%s: error getting MD5 fingerprint"),
                        error_msg);
                X509_free(x509cert);
                return TLS_ECERT;
            }
            if (memcmp(fingerprint, tls->fingerprint, 16) != 0)
            {
                *errstr = xasprintf(_("%s: the certificate fingerprint "
                            "does not match"), error_msg);
                X509_free(x509cert);
                return TLS_ECERT;
            }
        }
        X509_free(x509cert);
        return TLS_EOK;
    }

    /* Get result of OpenSSL's default verify function */
    if ((status = SSL_get_verify_result(tls->ssl)) != X509_V_OK)
    {
        if (tls->have_trust_file
                || (status != X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY
                    && status != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT
                    && status != X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN))
        {
            *errstr = xasprintf("%s: %s", error_msg,
                    X509_verify_cert_error_string(status));
            X509_free(x509cert);
            return TLS_ECERT;
        }
    }

    /* Check if 'hostname' matches the one of the subjectAltName extensions of
     * type DNS or the Common Name (CN). */

#ifdef HAVE_LIBIDN
    idna_to_ascii_lz(hostname, &idn_hostname, 0);
#endif

    /* Try the DNS subjectAltNames. */
    match_found = 0;
    if ((subj_alt_names =
                X509_get_ext_d2i(x509cert, NID_subject_alt_name, NULL, NULL)))
    {
        subj_alt_names_count = sk_GENERAL_NAME_num(subj_alt_names);
        for (i = 0; i < subj_alt_names_count; i++)
        {
            subj_alt_name = sk_GENERAL_NAME_value(subj_alt_names, i);
            if (subj_alt_name->type == GEN_DNS)
            {
                if ((size_t)(subj_alt_name->d.ia5->length)
                        != strlen((char *)(subj_alt_name->d.ia5->data)))
                {
                    *errstr = xasprintf(_("%s: certificate subject "
                                "alternative name contains NUL"), error_msg);
                    X509_free(x509cert);
                    free(idn_hostname);
                    return TLS_ECERT;
                }
                if ((match_found = hostname_match(
                                idn_hostname ? idn_hostname : hostname,
                                (char *)(subj_alt_name->d.ia5->data))))
                {
                    break;
                }
            }
        }
    }
    if (!match_found)
    {
        /* Try the common name */
        if (!(x509_subject = X509_get_subject_name(x509cert)))
        {
            *errstr = xasprintf(_("%s: cannot get certificate subject"),
                    error_msg);
            X509_free(x509cert);
            free(idn_hostname);
            return TLS_ECERT;
        }
        length = X509_NAME_get_text_by_NID(x509_subject, NID_commonName,
                NULL, 0);
        buf = xmalloc((size_t)length + 1);
        if (X509_NAME_get_text_by_NID(x509_subject, NID_commonName,
                    buf, length + 1) == -1)
        {
            *errstr = xasprintf(_("%s: cannot get certificate common name"),
                    error_msg);
            X509_free(x509cert);
            free(idn_hostname);
            free(buf);
            return TLS_ECERT;
        }
        if ((size_t)length != strlen(buf))
        {
            *errstr = xasprintf(_("%s: certificate common name contains NUL"),
                    error_msg);
            X509_free(x509cert);
            free(idn_hostname);
            free(buf);
            return TLS_ECERT;
        }
        match_found = hostname_match(idn_hostname ? idn_hostname : hostname,
                buf);
        free(buf);
    }
    X509_free(x509cert);
    free(idn_hostname);

    if (!match_found)
    {
        *errstr = xasprintf(
                _("%s: the certificate owner does not match hostname %s"),
                error_msg, hostname);
        return TLS_ECERT;
    }

    return TLS_EOK;
#endif /* HAVE_LIBSSL */
}
Example #12
0
int main(int argc, char *argv[])
{
	char pa[MAX_HOSTNAMELEN];
	extern char *optarg;
	extern int optind;
	struct hostent *hp;
	struct sockaddr_in6 from, *to;
	int ch, i, on, probe, seq, tos, ttl;
	int socket_errno;

	icmp_sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
	socket_errno = errno;

	if (setuid(getuid())) {
		perror("traceroute6: setuid");
		exit(-1);
	}
#ifdef CAPABILITIES
	{
		cap_t caps = cap_init();
		if (cap_set_proc(caps)) {
			perror("traceroute6: cap_set_proc");
			exit(-1);
		}
		cap_free(caps);
	}
#endif

#ifdef USE_IDN
	setlocale(LC_ALL, "");
#endif

	on = 1;
	seq = tos = 0;
	to = (struct sockaddr_in6 *)&whereto;
	while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:vi:g:V")) != EOF) {
		switch(ch) {
		case 'd':
			options |= SO_DEBUG;
			break;
		case 'm':
			max_ttl = atoi(optarg);
			if (max_ttl <= 1) {
				Fprintf(stderr,
				    "traceroute: max ttl must be >1.\n");
				exit(1);
			}
			break;
		case 'n':
			nflag++;
			break;
		case 'p':
			port = atoi(optarg);
			if (port < 1) {
				Fprintf(stderr,
				    "traceroute: port must be >0.\n");
				exit(1);
			}
			break;
		case 'q':
			nprobes = atoi(optarg);
			if (nprobes < 1) {
				Fprintf(stderr,
				    "traceroute: nprobes must be >0.\n");
				exit(1);
			}
			break;
		case 'r':
			options |= SO_DONTROUTE;
			break;
		case 's':
			/*
			 * set the ip source address of the outbound
			 * probe (e.g., on a multi-homed host).
			 */
			source = optarg;
			break;
		case 'i':
			device = optarg;
			break;
		case 'g':
			Fprintf(stderr, "Sorry, rthdr is not yet supported\n");
			break;
		case 'v':
			verbose++;
			break;
		case 'w':
			waittime = atoi(optarg);
			if (waittime <= 1) {
				Fprintf(stderr,
				    "traceroute: wait must be >1 sec.\n");
				exit(1);
			}
			break;
		case 'V':
			printf("traceroute6 utility, iputils-%s\n", SNAPSHOT);
			exit(0);
		default:
			usage();
		}
	}
	argc -= optind;
	argv += optind;

	if (argc < 1)
		usage();

	setlinebuf (stdout);

	(void) memset((char *)&whereto, 0, sizeof(whereto));

	to->sin6_family = AF_INET6;
	to->sin6_port = htons(port);

	if (inet_pton(AF_INET6, *argv, &to->sin6_addr) > 0) {
		hostname = *argv;
	} else {
		char *idn = NULL;
#ifdef USE_IDN
		if (idna_to_ascii_lz(*argv, &idn, 0) != IDNA_SUCCESS)
			idn = NULL;
#endif
		hp = gethostbyname2(idn ? idn : *argv, AF_INET6);
		if (hp) {
			memmove((caddr_t)&to->sin6_addr, hp->h_addr, sizeof(to->sin6_addr));
			hostname = (char *)hp->h_name;
		} else {
			(void)fprintf(stderr,
			    "traceroute: unknown host %s\n", *argv);
			exit(1);
		}
	}
	firsthop = *to;
	if (*++argv) {
		datalen = atoi(*argv);
		/* Message for rpm maintainers: have _shame_. If you want
		 * to fix something send the patch to me for sanity checking.
		 * "datalen" patch is a shit. */
		if (datalen == 0)
			datalen = sizeof(struct pkt_format);
		else if (datalen < (int)sizeof(struct pkt_format) ||
			 datalen >= MAXPACKET) {
			Fprintf(stderr,
			    "traceroute: packet size must be %d <= s < %d.\n",
				(int)sizeof(struct pkt_format), MAXPACKET);
			exit(1);
		}
	}

	ident = getpid();

	sendbuff = malloc(datalen);
	if (sendbuff == NULL) {
		fprintf(stderr, "malloc failed\n");
		exit(1);
	}

	if (icmp_sock < 0) {
		errno = socket_errno;
		perror("traceroute6: icmp socket");
		exit(1);
	}

#ifdef IPV6_RECVPKTINFO
	setsockopt(icmp_sock, SOL_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on));
	setsockopt(icmp_sock, SOL_IPV6, IPV6_2292PKTINFO, &on, sizeof(on));
#else
	setsockopt(icmp_sock, SOL_IPV6, IPV6_PKTINFO, &on, sizeof(on));
#endif

	if (options & SO_DEBUG)
		setsockopt(icmp_sock, SOL_SOCKET, SO_DEBUG,
			   (char *)&on, sizeof(on));
	if (options & SO_DONTROUTE)
		setsockopt(icmp_sock, SOL_SOCKET, SO_DONTROUTE,
			   (char *)&on, sizeof(on));

#ifdef __linux__
	on = 2;
	if (setsockopt(icmp_sock, SOL_RAW, IPV6_CHECKSUM, &on, sizeof(on)) < 0) {
		/* checksum should be enabled by default and setting this
		 * option might fail anyway.
		 */
		fprintf(stderr, "setsockopt(RAW_CHECKSUM) failed - try to continue.");
	}
#endif

	if ((sndsock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
		perror("traceroute: UDP socket");
		exit(5);
	}
#ifdef SO_SNDBUF
	if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
		       sizeof(datalen)) < 0) {
		perror("traceroute: SO_SNDBUF");
		exit(6);
	}
#endif /* SO_SNDBUF */

	if (options & SO_DEBUG)
		(void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
				  (char *)&on, sizeof(on));
	if (options & SO_DONTROUTE)
		(void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
				  (char *)&on, sizeof(on));

	if (source == NULL) {
		socklen_t alen;
		int probe_fd = socket(AF_INET6, SOCK_DGRAM, 0);

		if (probe_fd < 0) {
			perror("socket");
			exit(1);
		}
		if (device) {
			if (setsockopt(probe_fd, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device)+1) == -1)
				perror("WARNING: interface is ignored");
		}
		firsthop.sin6_port = htons(1025);
		if (connect(probe_fd, (struct sockaddr*)&firsthop, sizeof(firsthop)) == -1) {
			perror("connect");
			exit(1);
		}
		alen = sizeof(saddr);
		if (getsockname(probe_fd, (struct sockaddr*)&saddr, &alen) == -1) {
			perror("getsockname");
			exit(1);
		}
		saddr.sin6_port = 0;
		close(probe_fd);
	} else {
		(void) memset((char *)&saddr, 0, sizeof(saddr));
		saddr.sin6_family = AF_INET6;
		if (inet_pton(AF_INET6, source, &saddr.sin6_addr) <= 0)
		{
			Printf("traceroute: unknown addr %s\n", source);
			exit(1);
		}
	}

	if (bind(sndsock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
		perror ("traceroute: bind sending socket");
		exit (1);
	}
	if (bind(icmp_sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
		perror ("traceroute: bind icmp6 socket");
		exit (1);
	}

	Fprintf(stderr, "traceroute to %s (%s)", hostname,
		inet_ntop(AF_INET6, &to->sin6_addr, pa, sizeof(pa)));

	Fprintf(stderr, " from %s",
		inet_ntop(AF_INET6, &saddr.sin6_addr, pa, sizeof(pa)));
	Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);
	(void) fflush(stderr);

	for (ttl = 1; ttl <= max_ttl; ++ttl) {
		struct in6_addr lastaddr = {{{0,}}};
		int got_there = 0;
		int unreachable = 0;

		Printf("%2d ", ttl);
		for (probe = 0; probe < nprobes; ++probe) {
			int cc, reset_timer;
			struct timeval t1, t2;
			struct timezone tz;
			struct in6_addr to;

			gettimeofday(&t1, &tz);
			send_probe(++seq, ttl);
			reset_timer = 1;

			while ((cc = wait_for_reply(icmp_sock, &from, &to, reset_timer)) != 0) {
				gettimeofday(&t2, &tz);
				if ((i = packet_ok(packet, cc, &from, &to, seq, &t1))) {
					reset_timer = 1;
					if (memcmp(&from.sin6_addr, &lastaddr, sizeof(from.sin6_addr))) {
						print(packet, cc, &from);
						memcpy(&lastaddr,
						       &from.sin6_addr,
						       sizeof(lastaddr));
					}
					Printf("  %g ms", deltaT(&t1, &t2));
					switch(i - 1) {
					case ICMP6_DST_UNREACH_NOPORT:
						++got_there;
						break;

					case ICMP6_DST_UNREACH_NOROUTE:
						++unreachable;
						Printf(" !N");
						break;
					case ICMP6_DST_UNREACH_ADDR:
						++unreachable;
						Printf(" !H");
						break;

					case ICMP6_DST_UNREACH_ADMIN:
						++unreachable;
						Printf(" !S");
						break;
					}
					break;
				} else
					reset_timer = 0;
			}
			if (cc <= 0)
				Printf(" *");
			(void) fflush(stdout);
		}
		putchar('\n');
		if (got_there ||
		    (unreachable > 0 && unreachable >= nprobes-1))
			exit(0);
	}

	return 0;
}
Example #13
0
int
get_addrs (char *my_machine_name, char *his_machine_name)
{
#if HAVE_DECL_GETADDRINFO || defined HAVE_IDN
  int err;
#endif
  char *lhost, *rhost;
#if HAVE_DECL_GETADDRINFO
  struct addrinfo hints, *res, *ai;
#else /* !HAVE_DECL_GETADDRINFO */
  struct hostent *hp;
#endif
  struct servent *sp;

#ifdef HAVE_IDN
  err = idna_to_ascii_lz (my_machine_name, &lhost, 0);
  if (err)
    {
      fprintf (stderr, "talk: %s: %s\n",
	       my_machine_name, idna_strerror (err));
      exit (-1);
    }

  err = idna_to_ascii_lz (his_machine_name, &rhost, 0);
  if (err)
    {
      fprintf (stderr, "talk: %s: %s\n",
	       his_machine_name, idna_strerror (err));
      exit (-1);
    }
#else /* !HAVE_IDN */
  lhost = my_machine_name;
  rhost = his_machine_name;
#endif

  msg.pid = htonl (getpid ());

  /* Look up the address of the local host.  */

#if HAVE_DECL_GETADDRINFO
  memset (&hints, 0, sizeof (hints));

  /* The talk-protocol is IPv4 only!  */
  hints.ai_family = AF_INET;
  hints.ai_socktype = SOCK_DGRAM;
# ifdef AI_IDN
  hints.ai_flags |= AI_IDN;
# endif

  err = getaddrinfo (lhost, NULL, &hints, &res);
  if (err)
    {
      fprintf (stderr, "talk: %s: %s\n", lhost, gai_strerror (err));
      exit (-1);
    }

  /* Perform all sanity checks available.
   * Reduction of tests?
   */
  for (ai = res; ai; ai = ai->ai_next)
    {
      int f;

      if (ai->ai_family != AF_INET)
	continue;

      f = socket (ai->ai_family, ai->ai_socktype, ai->ai_protocol);
      if (f < 0)
	continue;

      /* Attempt binding to this local address.  */
      if (bind (f, ai->ai_addr, ai->ai_addrlen))
        {
	  close (f);
	  f = -1;
	  continue;
	}

      /* We have a usable address.  */
      close (f);
      break;
    }

  if (ai)
    memcpy (&my_machine_addr,
	    &((struct sockaddr_in *) ai->ai_addr)->sin_addr,
	    sizeof (my_machine_addr));

  freeaddrinfo (res);
  if (!ai)
    {
      fprintf (stderr, "talk: %s: %s\n", lhost, "address not found");
      exit (-1);
    }

#else /* !HAVE_DECL_GETADDRINFO */
  hp = gethostbyname (lhost);
  if (hp == NULL)
    {
      fprintf (stderr, "talk: %s(%s): ", lhost, my_machine_name);
      herror ((char *) NULL);
      exit (-1);
    }
  memmove (&my_machine_addr, hp->h_addr, hp->h_length);
#endif /* !HAVE_DECL_GETADDRINFO */

  /*
   * If the callee is on-machine, just copy the
   * network address, otherwise do a lookup...
   */
  if (strcmp (rhost, lhost))
    {
#if HAVE_DECL_GETADDRINFO
      err = getaddrinfo (rhost, NULL, &hints, &res);
      if (err)
	{
	  fprintf (stderr, "talk: %s: %s\n", rhost, gai_strerror (err));
	  exit (-1);
	}

      /* Perform all sanity checks available.  */
      for (ai = res; ai; ai = ai->ai_next)
	{
	  int f;

	  if (ai->ai_family != AF_INET)
	    continue;

	  f = socket (ai->ai_family, ai->ai_socktype, ai->ai_protocol);
	  if (f < 0)
	    continue;

	  /* We have a usable address family!  */
	  close (f);
	  break;
	}

      if (ai)
	memcpy (&his_machine_addr,
		&((struct sockaddr_in *) ai->ai_addr)->sin_addr,
		sizeof (his_machine_addr));

      freeaddrinfo (res);
      if (!ai)
	{
	  fprintf (stderr, "talk: %s: %s\n", rhost, "address not found");
	  exit (-1);
	}

#else /* !HAVE_DECL_GETADDRINFO */
      hp = gethostbyname (rhost);
      if (hp == NULL)
	{
	  fprintf (stderr, "talk: %s(%s): ", rhost, his_machine_name);
	  herror ((char *) NULL);
	  exit (-1);
	}
      memmove (&his_machine_addr, hp->h_addr, hp->h_length);
#endif /* !HAVE_DECL_GETADDRINFO */
    }
  else
    his_machine_addr = my_machine_addr;

  /* Find the server's port.  */
  sp = getservbyname ("ntalk", "udp");
  if (sp == 0)
    {
      fprintf (stderr, "talk: %s/%s: service is not registered.\n",
	       "ntalk", "udp");
      exit (-1);
    }
  daemon_port = ntohs (sp->s_port);

#ifdef HAVE_IDN
  free (lhost);
  free (rhost);
#endif

  return 0;
}