diff --git a/src/syncterm/webget.c b/src/syncterm/webget.c index b0d9c0e39979d9c0a8fed26e71b613f22ec65091..22a212aeb01634a5c1d4a1ceca2da9bfca06eb11 100644 --- a/src/syncterm/webget.c +++ b/src/syncterm/webget.c @@ -1,6 +1,8 @@ #include <assert.h> #include <stdbool.h> +#include <cryptlib.h> + #include "bbslist.h" #include "conn.h" #include "datewrap.h" @@ -36,6 +38,7 @@ struct http_session { struct bbslist hacky_list_entry; struct http_cache_info cache; SOCKET sock; + CRYPT_SESSION tls; bool is_tls; bool is_chunked; bool not_modified; @@ -78,14 +81,26 @@ recv_nbytes(struct http_session *sess, uint8_t *buf, size_t chunk_size, bool *eo ssize_t received = 0; while (received < chunk_size) { - if (!socket_readable(sess->sock, 5000)) { - set_msg(sess->req, "Socket Unreadable"); - goto error_return; + ssize_t rc; + if (sess->is_tls) { + int copied = 0; + int status = cryptPopData(sess->tls, &buf[received], chunk_size - received, &copied); + if (cryptStatusError(status)) { + set_msg(sess->req, "Error Popping Data"); + goto error_return; + } + rc = copied; } - ssize_t rc = recv(sess->sock, &buf[received], chunk_size - received, 0); - if (rc < 0) { - set_msg(sess->req, "recv() error"); - goto error_return; + else { + if (!socket_readable(sess->sock, 5000)) { + set_msg(sess->req, "Socket Unreadable"); + goto error_return; + } + rc = recv(sess->sock, &buf[received], chunk_size - received, 0); + if (rc < 0) { + set_msg(sess->req, "recv() error"); + goto error_return; + } } if (rc == 0) { if (eof) { @@ -112,7 +127,7 @@ static void close_socket(struct http_session *sess) { if (sess->sock != INVALID_SOCKET) { - close(sess->sock); + closesocket(sess->sock); sess->sock = INVALID_SOCKET; } } @@ -120,6 +135,11 @@ close_socket(struct http_session *sess) static void free_session(struct http_session *sess) { + if (sess->is_tls && sess->tls != -1) { + cryptSetAttribute(sess->tls, CRYPT_SESSINFO_ACTIVE, 0); + cryptDestroySession(sess->tls); + sess->tls = -1; + } close_socket(sess); if (sess->cache_info) { fclose(sess->cache_info); @@ -189,13 +209,31 @@ send_request(struct http_session *sess) return false; } sess->cache.request_time = time(NULL); - ssize_t sent = send(sess->sock, reqstr, len, 0); + ssize_t sent; + if (sess->is_tls) { + int copied; + int ret = cryptPushData(sess->tls, reqstr, len, &copied); + if (cryptStatusError(ret)) { +fprintf(stderr, "Ret: %d\n", ret); + sent = -1; + } + else + sent = copied; + ret = cryptFlushData(sess->tls); + if (cryptStatusError(ret)) { +fprintf(stderr, "ret: %d\n", ret); + sent = -1; + } + } + else { + sent = send(sess->sock, reqstr, len, 0); + shutdown(sess->sock, SHUT_WR); + } free(reqstr); if (sent != len) { set_msg(sess->req, "send() failure"); return false; } - shutdown(sess->sock, SHUT_WR); #ifdef _WIN32 unsigned long nb = 1; #else @@ -222,14 +260,14 @@ recv_line(struct http_session *sess, int timeout, size_t *len) set_msg(sess->req, "Socket not readable."); goto error_return; } - ssize_t rc = recv(sess->sock, &ret[retpos], 1, 0); + bool eof = false; + ssize_t rc = recv_nbytes(sess, (uint8_t *)&ret[retpos], 1, &eof); if (rc == -1) { if (SOCKET_ERRNO == EINTR) continue; - set_msg(sess->req, "recv() failure."); goto error_return; } - if (rc == 0) { + if (rc == 0 || eof) { if (retpos == 0) { *len = 1; goto special_return; @@ -413,7 +451,7 @@ find_end(const char *val, const char ** sep) bool had_quotes = false; bool in_value = false; *sep = NULL; - for (; *val; val++) { + for (; *val && *val != '\r'; val++) { if (!in_value) { if (*val == '=') { *sep = val; @@ -454,7 +492,7 @@ find_end(const char *val, const char ** sep) static bool parse_cache_control(struct http_session *sess, const char *val) { - while (*val) { + while (*val && *val != '\r') { val = skipws(val); const char *sep; const char *end = find_end(val, &sep); @@ -481,6 +519,7 @@ parse_cache_control(struct http_session *sess, const char *val) if (sz == 15 && sep == NULL && strnicmp(val, "must-revalidate", 15) == 0) { sess->cache.must_revalidate = true; } + val = end; } return true; @@ -886,6 +925,40 @@ error_return: return false; } +static bool +tls_setup(struct http_session *sess) +{ + int status; + status = cryptCreateSession(&sess->tls, CRYPT_UNUSED, CRYPT_SESSION_SSL); + if (cryptStatusError(status)) { + set_msg(sess->req, "Unable To Create Session"); + goto error_return; + } + int off = 1; + setsockopt(sess->sock, IPPROTO_TCP, TCP_NODELAY, (char *)&off, sizeof(off)); + status = cryptSetAttribute(sess->tls, CRYPT_SESSINFO_NETWORKSOCKET, sess->sock); + if (cryptStatusError(status)) { + set_msg(sess->req, "Unable To Set Socket"); + goto error_return; + } + cryptSetAttribute(sess->tls, CRYPT_OPTION_NET_READTIMEOUT, 5); + cryptSetAttributeString(sess->tls, CRYPT_SESSINFO_SERVER_NAME, sess->hostname, strlen(sess->hostname)); + status = cryptSetAttribute(sess->tls, CRYPT_SESSINFO_ACTIVE, 1); + if (cryptStatusError(status)) { + set_msg(sess->req, "Unable To Activate Session"); + goto error_return; + } + status = cryptSetAttribute(sess->tls, CRYPT_PROPERTY_OWNER, CRYPT_UNUSED); + if (cryptStatusError(status)) { + set_msg(sess->req, "Unable Clear Ownership"); + goto error_return; + } + return true; + +error_return: + return false; +} + static bool do_request(struct http_session *sess) { @@ -903,6 +976,11 @@ do_request(struct http_session *sess) set_msg(sess->req, "Connection Failed"); goto error_return; } + if (sess->is_tls) { + set_state(sess->req, "TLS Setup"); + if (!tls_setup(sess)) + goto error_return; + } set_state(sess->req, "Requesting"); if (!send_request(sess)) goto error_return; @@ -1008,6 +1086,7 @@ iniReadHttp(struct webget_request *req) { struct http_session sess = { .req = req, + .tls = -1, .hacky_list_entry = { .hidepopups = true, .address_family = PF_UNSPEC, @@ -1027,8 +1106,10 @@ iniReadHttp(struct webget_request *req) if (!do_request(&sess)) goto error_return; } + set_state(req, "Writing Cache Info"); write_cacheinfo(&sess); free_session(&sess); + set_state(req, "Done"); return true; error_return: diff --git a/src/syncterm/webget.h b/src/syncterm/webget.h index dc8b8ace1c70b9877cf47b6d7617f936a7c76c4c..450d24bf55b1fd14c597172021d9be877e6d45d9 100644 --- a/src/syncterm/webget.h +++ b/src/syncterm/webget.h @@ -10,6 +10,7 @@ struct webget_request { pthread_mutex_t mtx; size_t remote_size; size_t received_size; + uint64_t cb_data; }; bool iniReadHttp(struct webget_request *req);