/** 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; }
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); }
/** * 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; }
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; }
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; }
/* 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; }
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; }
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 */ }
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; }
/* 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; }
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 */ }
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; }
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; }