#define SERVER_FILE "/usr/local/lib/rn/server"
#endif /* SERVER_FILE */
+#ifdef USE_SSL
+#define free_func free__func
+#include <openssl/ssl.h>
+#undef free_func
+extern SSL_CTX * ssl_ctx;
+extern SSL * HTGetSSLHandle NOPARAMS;
+PRIVATE SSL * Handle = NULL;
+PRIVATE int channel_s = 1;
+#define NEWS_NETWRITE(sock, buff, size) \
+ (Handle ? SSL_write(Handle, buff, size) : NETWRITE(sock, buff, size))
+#define NEWS_NETCLOSE(sock) \
+ { (void)NETCLOSE(sock); if (Handle) SSL_free(Handle); Handle = NULL; }
+extern char HTGetSSLCharacter PARAMS((void *handle));
+PRIVATE char HTNewsGetCharacter NOPARAMS;
+#define NEXT_CHAR HTNewsGetCharacter()
+#else
#define NEWS_NETWRITE NETWRITE
#define NEWS_NETCLOSE NETCLOSE
#define NEXT_CHAR HTGetCharacter()
+#endif /* USE_SSL */
#include <HTML.h>
#include <HTParse.h>
group_wanted) &&
strchr(arg, '@') == NULL) && (strchr(arg, '*') != NULL);
+#ifndef USE_SSL
if (!strncasecomp(arg, "snewspost:", 10) ||
!strncasecomp(arg, "snewsreply:", 11)) {
HTAlert(FAILED_CANNOT_POST_SSL);
return HT_NOT_LOADED;
}
+#endif /* !USE_SSL */
if (post_wanted || reply_wanted || spost_wanted || sreply_wanted) {
/*
** Make sure we have a non-zero path for the newsgroup(s). - FM
StrAllocCopy(NewsHREF, command);
}
else if (!strncasecomp(arg, "snews:", 6)) {
+#ifdef USE_SSL
+ if (((*(arg + 6) == '\0') ||
+ (!strcmp((arg + 6), "/") ||
+ !strcmp((arg + 6), "//") ||
+ !strcmp((arg + 6), "///"))) ||
+ ((!strncmp((arg + 6), "//", 2)) &&
+ (!(cp = strchr((arg + 8), '/')) || *(cp + 1) == '\0'))) {
+ p1 = "*";
+ group_wanted = FALSE;
+ list_wanted = TRUE;
+ } else if (*(arg + 6) != '/') {
+ p1 = (arg + 6);
+ } else if (*(arg + 6) == '/' && *(arg + 7) != '/') {
+ p1 = (arg + 7);
+ } else {
+ p1 = (cp + 1);
+ }
+ if (!(cp = HTParse(arg, "", PARSE_HOST)) || *cp == '\0') {
+ if (s >= 0 && NewsHost && strcasecomp(NewsHost, HTNewsHost)) {
+ NEWS_NETCLOSE(s);
+ s = -1;
+ }
+ StrAllocCopy(NewsHost, HTNewsHost);
+ } else {
+ if (s >= 0 && NewsHost && strcasecomp(NewsHost, cp)) {
+ NEWS_NETCLOSE(s);
+ s = -1;
+ }
+ StrAllocCopy(NewsHost, cp);
+ }
+ FREE(cp);
+ sprintf(command, "snews://%.250s/", NewsHost);
+ StrAllocCopy(NewsHREF, command);
+#else
HTAlert(gettext("This client does not contain support for SNEWS URLs."));
return HT_NOT_LOADED;
+#endif /* USE_SSL */
}
else if (!strncasecomp (arg, "news:/", 6)) {
if (((*(arg + 6) == '\0') ||
_HTProgress(gettext("Connecting to NewsHost ..."));
+#ifdef USE_SSL
+ if (!using_proxy &&
+ (!strncmp(arg, "snews:", 6) ||
+ !strncmp(arg, "snewspost:", 10) ||
+ !strncmp(arg, "snewsreply:", 11)))
+ status = HTDoConnect (url, "NNTPS", SNEWS_PORT, &s);
+ else
+ status = HTDoConnect (url, "NNTP", NEWS_PORT, &s);
+#else
status = HTDoConnect (url, "NNTP", NEWS_PORT, &s);
+#endif /* USE_SSL */
+
if (status == HT_INTERRUPTED) {
/*
** Interrupt cleanly.
FREE(ProxyHost);
FREE(ProxyHREF);
FREE(ListArg);
+#ifdef USE_SSL
+ if (Handle) {
+ SSL_free(Handle);
+ Handle = NULL;
+ }
+#endif /* USE_SSL */
if (postfile) {
HTSYS_remove(postfile);
FREE(postfile);
} else {
CTRACE(tfp, "HTNews: Connected to news host %s.\n",
NewsHost);
+#ifdef USE_SSL
+ /*
+ ** If this is an snews url,
+ ** then do the SSL stuff here
+ */
+ if (!using_proxy &&
+ (!strncmp(url, "snews", 5) ||
+ !strncmp(url, "snewspost:", 10) ||
+ !strncmp(url, "snewsreply:", 11))) {
+ Handle = HTGetSSLHandle();
+ SSL_set_fd(Handle, s);
+ status = SSL_connect(Handle);
+
+ if (status <= 0) {
+ CTRACE(tfp,
+"HTNews: Unable to complete SSL handshake for remote host '%s' (SSLerror = %d)\n",
+ url, status);
+ HTAlert(
+ "Unable to make secure connection to remote host.");
+ NEWS_NETCLOSE(s);
+ s = -1;
+ if (!(post_wanted || reply_wanted ||
+ spost_wanted || sreply_wanted))
+ (*targetClass._abort)(target, NULL);
+ FREE(NewsHost);
+ FREE(NewsHREF);
+ FREE(ProxyHost);
+ FREE(ProxyHREF);
+ FREE(ListArg);
+ if (postfile) {
+#ifdef VMS
+ while (remove(postfile) == 0)
+ ; /* loop through all versions */
+#else
+ remove(postfile);
+#endif /* VMS */
+ FREE(postfile);
+ }
+ return HT_NOT_LOADED;
+ }
+ _HTProgress(SSL_get_cipher(Handle));
+ }
+#endif /* USE_SSL */
HTInitInput(s); /* set up buffering */
if (proxycmd[0]) {
status = NEWS_NETWRITE(s, proxycmd, strlen(proxycmd));
free_NNTP_AuthInfo();
}
+#ifdef USE_SSL
+PRIVATE char HTNewsGetCharacter NOARGS
+{
+ if (!Handle)
+ return HTGetCharacter();
+ else
+ return HTGetSSLCharacter((void *)Handle);
+}
+
+PUBLIC int HTNewsProxyConnect ARGS5 (int, sock, CONST char *, url,
+ HTParentAnchor *, anAnchor,
+ HTFormat, format_out,
+ HTStream *, sink)
+{
+ int status;
+ CONST char * arg = url;
+
+ s = channel_s = sock;
+ Handle = HTGetSSLHandle();
+ SSL_set_fd(Handle, s);
+ status = SSL_connect(Handle);
+
+ if (status <= 0) {
+ channel_s = -1;
+ CTRACE(tfp,
+"HTTP: Unable to complete SSL handshake for remote host '%s' (SSLerror = %d)\n",
+ url, status);
+ HTAlert("Unable to make secure connection to remote host.");
+ NEWS_NETCLOSE(s);
+ s = -1;
+ return HT_NOT_LOADED;
+ }
+ _HTProgress(SSL_get_cipher(Handle));
+ status = HTLoadNews(arg, anAnchor, format_out, sink);
+ channel_s = -1;
+ return status;
+}
+#endif /* USE_SSL */
+
#ifdef GLOBALDEF_IS_MACRO
#define _HTNEWS_C_1_INIT { "news", HTLoadNews, NULL }
GLOBALDEF (HTProtocol,HTNews,_HTNEWS_C_1_INIT);
#include <HTTP.h>
#include <LYUtils.h>
+#ifdef USE_SSL
+#define free_func free__func
+#include <openssl/ssl.h>
+#include <openssl/crypto.h>
+#undef free_func
+#endif /* USE_SSL */
+
#define HTTP_VERSION "HTTP/1.0"
#define HTTP_PORT 80
extern BOOL traversal; /* TRUE if we are doing a traversal */
extern BOOL dump_output_immediately; /* TRUE if no interactive user */
+#ifdef USE_SSL
+PUBLIC SSL_CTX * ssl_ctx = NULL; /* SSL ctx */
+
+PRIVATE void free_ssl_ctx NOARGS
+{
+ if (ssl_ctx != NULL)
+ SSL_CTX_free(ssl_ctx);
+}
+
+PUBLIC SSL * HTGetSSLHandle NOARGS
+{
+ if (ssl_ctx == NULL) {
+ /*
+ * First time only.
+ */
+#if SSLEAY_VERSION_NUMBER < 0x0800
+ ssl_ctx = SSL_CTX_new();
+ X509_set_default_verify_paths(ssl_ctx->cert);
+#else
+ SSLeay_add_ssl_algorithms();
+ ssl_ctx = SSL_CTX_new(SSLv23_client_method());
+ SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL);
+ SSL_CTX_set_default_verify_paths(ssl_ctx);
+#endif /* SSLEAY_VERSION_NUMBER < 0x0800 */
+ atexit(free_ssl_ctx);
+ }
+ return(SSL_new(ssl_ctx));
+}
+
+#define HTTP_NETREAD(sock, buff, size, handle) \
+ (handle ? SSL_read(handle, buff, size) : NETREAD(sock, buff, size))
+#define HTTP_NETWRITE(sock, buff, size, handle) \
+ (handle ? SSL_write(handle, buff, size) : NETWRITE(sock, buff, size))
+#define HTTP_NETCLOSE(sock, handle) \
+ { (void)NETCLOSE(sock); if (handle) SSL_free(handle); handle = NULL; }
+
+extern int HTNewsProxyConnect PARAMS (( int sock, CONST char *url,
+ HTParentAnchor *anAnchor,
+ HTFormat format_out,
+ HTStream *sink ));
+#else
#define HTTP_NETREAD(a, b, c, d) NETREAD(a, b, c)
#define HTTP_NETWRITE(a, b, c, d) NETWRITE(a, b, c)
#define HTTP_NETCLOSE(a, b) (void)NETCLOSE(a)
+#endif /* USE_SSL */
/* Load Document from HTTP Server HTLoadHTTP()
BOOL doing_redirect, already_retrying = FALSE, bad_location = FALSE;
int len = 0;
+#ifdef USE_SSL
+ BOOL do_connect = FALSE; /* ARE WE going to use a proxy tunnel ? */
+ BOOL did_connect = FALSE; /* ARE WE actually using a proxy tunnel ? */
+ CONST char *connect_url = NULL; /* The URL being proxied */
+ char *connect_host = NULL; /* The host being proxied */
+ SSL * handle = NULL; /* The SSL handle */
+#if SSLEAY_VERSION_NUMBER >= 0x0900
+ BOOL try_tls = TRUE;
+#endif /* SSLEAY_VERSION_NUMBER >= 0x0900 */
+#else
void * handle = NULL;
+#endif /* USE_SSL */
if (anAnchor->isHEAD)
do_head = TRUE;
goto done;
}
+#ifdef USE_SSL
+ if (using_proxy && !strncmp(url, "http://", 7)) {
+ if (connect_url = strstr((url+7), "https://")) {
+ do_connect = TRUE;
+ connect_host = HTParse(connect_url, "https", PARSE_HOST);
+ if (!strchr(connect_host, ':')) {
+ sprintf(temp, ":%d", HTTPS_PORT);
+ StrAllocCat(connect_host, temp);
+ }
+ CTRACE(tfp, "HTTP: connect_url = '%s'\n", connect_url);
+ CTRACE(tfp, "HTTP: connect_host = '%s'\n", connect_host);
+ } else if (connect_url = strstr((url+7), "snews://")) {
+ do_connect = TRUE;
+ connect_host = HTParse(connect_url, "snews", PARSE_HOST);
+ if (!strchr(connect_host, ':')) {
+ sprintf(temp, ":%d", SNEWS_PORT);
+ StrAllocCat(connect_host, temp);
+ }
+ CTRACE(tfp, "HTTP: connect_url = '%s'\n", connect_url);
+ CTRACE(tfp, "HTTP: connect_host = '%s'\n", connect_host);
+ }
+ }
+#endif /* USE_SSL */
+
sprintf(crlf, "%c%c", CR, LF);
/*
line_kept_clean = NULL;
if (!strncmp(url, "https", 5))
+#ifdef USE_SSL
+ status = HTDoConnect (url, "HTTPS", HTTPS_PORT, &s);
+ else
+ status = HTDoConnect (url, "HTTP", HTTP_PORT, &s);
+#else
{
HTAlert(gettext("This client does not contain support for HTTPS URLs."));
status = HT_NOT_LOADED;
goto done;
}
status = HTDoConnect (arg, "HTTP", HTTP_PORT, &s);
+#endif /* USE_SSL */
if (status == HT_INTERRUPTED) {
/*
** Interrupt cleanly.
goto done;
}
+#ifdef USE_SSL
+use_tunnel:
+ /*
+ ** If this is an https document
+ ** then do the SSL stuff here
+ */
+ if (did_connect || !strncmp(url, "https", 5)) {
+ handle = HTGetSSLHandle();
+ SSL_set_fd(handle, s);
+#if SSLEAY_VERSION_NUMBER >= 0x0900
+ if (!try_tls)
+ handle->options|=SSL_OP_NO_TLSv1;
+#endif /* SSLEAY_VERSION_NUMBER >= 0x0900 */
+ status = SSL_connect(handle);
+
+ if (status <= 0) {
+#if SSLEAY_VERSION_NUMBER >= 0x0900
+ if (try_tls) {
+ CTRACE(tfp, "HTTP: Retrying connection without TLS\n");
+ _HTProgress("Retrying connection.");
+ try_tls = FALSE;
+ if (did_connect)
+ HTTP_NETCLOSE(s, handle);
+ goto try_again;
+ } else {
+ CTRACE(tfp,
+"HTTP: Unable to complete SSL handshake for remote host '%s' (SSLerror = %d)\n",
+ url, status);
+ HTAlert("Unable to make secure connection to remote host.");
+ if (did_connect)
+ HTTP_NETCLOSE(s, handle);
+ status = HT_NOT_LOADED;
+ goto done;
+ }
+#else
+ CTRACE(tfp,
+"HTTP: Unable to complete SSL handshake for remote host '%s' (SSLerror = %d)\n",
+ url, status);
+ HTAlert("Unable to make secure connection to remote host.");
+ if (did_connect)
+ HTTP_NETCLOSE(s, handle);
+ status = HT_NOT_LOADED;
+ goto done;
+#endif /* SSLEAY_VERSION_NUMBER >= 0x0900 */
+ }
+ _HTProgress (SSL_get_cipher(handle));
+
+#ifdef NOTDEFINED
+ if (strcmp(HTParse(url, "", PARSE_HOST),
+ strstr(X509_NAME_oneline(
+ X509_get_subject_name(
+ handle->session->peer)),"/CN=")+4)) {
+ HTAlert("Certificate is for different host name");
+ HTAlert(strstr(X509_NAME_oneline(
+ X509_get_subject_name(
+ handle->session->peer)),"/CN=")+4);
+ }
+#endif /* NOTDEFINED */
+ }
+#endif /* USE_SSL */
+
/* Ask that node for the document,
** omitting the host name & anchor
*/
{
char * p1 = (HTParse(url, "", PARSE_PATH|PARSE_PUNCTUATION));
+#ifdef USE_SSL
+ if (do_connect) {
+ METHOD = "CONNECT";
+ StrAllocCopy(command, "CONNECT ");
+ } else
+#endif /* USE_SSL */
if (do_post) {
METHOD = "POST";
StrAllocCopy(command, "POST ");
** of say: /gopher://a;lkdjfl;ajdf;lkj/;aldk/adflj
** so that just gopher://.... is sent.
*/
+#ifdef USE_SSL
+ if (using_proxy && !did_connect) {
+ if (do_connect)
+ StrAllocCat(command, connect_host);
+ else
+ StrAllocCat(command, p1+1);
+ }
+#else
if (using_proxy)
StrAllocCat(command, p1+1);
+#endif /* USE_SSL */
else
StrAllocCat(command, p1);
FREE(p1);
} else {
if (traversal || dump_output_immediately)
HTAlert(FAILED_NEED_PASSWD);
+#ifdef USE_SSL
+ if(did_connect)
+ HTTP_NETCLOSE(s, handle);
+#endif /* USE_SSL */
FREE(command);
FREE(hostname);
FREE(docname);
auth_proxy = NO;
}
+#ifdef USE_SSL
+ if (!do_connect && do_post) {
+#else
if (do_post) {
+#endif /* USE_SSL */
CTRACE (tfp, "HTTP: Doing post, content-type '%s'\n",
anAnchor->post_content_type ? anAnchor->post_content_type
: "lose");
else
StrAllocCat(command, crlf); /* Blank line means "end" of headers */
+#ifdef USE_SSL
+ CTRACE (tfp, "Writing:\n%s%s----------------------------------\n",
+ command,
+ (anAnchor->post_data && !do_connect ? crlf : ""));
+#else
CTRACE (tfp, "Writing:\n%s%s----------------------------------\n",
command,
(anAnchor->post_data ? crlf : ""));
+#endif /* USE_SSL */
_HTProgress (gettext("Sending HTTP request."));
* > 206 is unknown.
* All should return something to display.
*/
+#ifdef USE_SSL
+ if (do_connect) {
+ CTRACE(tfp, "HTTP: Proxy tunnel to '%s' established.\n",
+ connect_host);
+ do_connect = FALSE;
+ url = connect_url;
+ FREE(line_buffer);
+ FREE(line_kept_clean);
+ if (!strncmp(connect_url, "snews", 5)) {
+ CTRACE(tfp,
+ " Will attempt handshake and snews connection.\n");
+ status = HTNewsProxyConnect(s, url, anAnchor,
+ format_out, sink);
+ goto done;
+ }
+ did_connect = TRUE;
+ already_retrying = TRUE;
+ eol = 0;
+ bytes_already_read = 0;
+ had_header = NO;
+ length = 0;
+ doing_redirect = FALSE;
+ permanent_redirection = FALSE;
+ target = NULL;
+ CTRACE(tfp,
+ " Will attempt handshake and resubmit headers.\n");
+ goto use_tunnel;
+ }
+#endif /* USE_SSL */
HTProgress(line_buffer);
} /* case 2 switch */
break;
gettext("Retrying with access authorization information."));
FREE(line_buffer);
FREE(line_kept_clean);
+#ifdef USE_SSL
+ if (using_proxy && !strncmp(url, "https://", 8)) {
+ url = arg;
+ do_connect = TRUE;
+ did_connect = FALSE;
+ }
+#endif /* USE_SSL */
goto try_again;
} else if (!(traversal || dump_output_immediately) &&
HTConfirm(gettext("Show the 401 message body?"))) {
do_head = FALSE;
do_post = FALSE;
reloading = FALSE;
+#ifdef USE_SSL
+ do_connect = FALSE;
+ did_connect = FALSE;
+ FREE(connect_host);
+ if (handle) {
+ SSL_free(handle);
+ handle = NULL;
+ }
+#endif /* USE_SSL */
return status;
}