A good start; thanks. Try something like this... diff --git a/http.c b/http.c index d653aff..005ee84 100644 --- a/http.c +++ b/http.c @@ -99,9 +99,10 @@ int http_add_cookie(struct openconnect_info *vpninfo, const char *option, const static int process_http_response(struct openconnect_info *vpninfo, int *result, int (*header_cb)(struct openconnect_info *, char *, char *), - char *body, int buf_len) + char **body_ret) { char buf[MAX_BUF_LEN]; + char *body = NULL; int bodylen = BODY_HTTP10; int done = 0; int closeconn = 0; @@ -155,9 +156,9 @@ static int process_http_response(struct openconnect_info *vpninfo, int *result, } if (!strcasecmp(buf, "Content-Length")) { bodylen = atoi(colon); - if (bodylen < 0 || bodylen > buf_len) { - vpninfo->progress(vpninfo, PRG_ERR, "Response body too large for buffer (%d > %d)\n", - bodylen, buf_len); + if (bodylen < 0) { + vpninfo->progress(vpninfo, PRG_ERR, "Response body has negative size (%d)\n", + bodylen); return -EINVAL; } } @@ -203,6 +204,9 @@ static int process_http_response(struct openconnect_info *vpninfo, int *result, /* If we were given Content-Length, it's nice and easy... */ if (bodylen > 0) { + body = malloc(bodylen + 1); + if (!body) + return -ENOMEM; while (done < bodylen) { i = SSL_read(vpninfo->https_ssl, body + done, bodylen - done); if (i < 0) { @@ -225,11 +229,9 @@ static int process_http_response(struct openconnect_info *vpninfo, int *result, lastchunk = 1; goto skip; } - if (chunklen + done > buf_len) { - vpninfo->progress(vpninfo, PRG_ERR, "Response body too large for buffer (%d > %d)\n", - chunklen + done, buf_len); - return -EINVAL; - } + body = realloc(body, done + chunklen + 1); + if (!body) + return -ENOMEM; while (chunklen) { i = SSL_read(vpninfo->https_ssl, body + done, chunklen); if (i < 0) { @@ -259,9 +261,10 @@ static int process_http_response(struct openconnect_info *vpninfo, int *result, return -EINVAL; } - /* HTTP 1.0 response. Just eat all we can. */ + /* HTTP 1.0 response. Just eat all we can in 16KiB chunks */ while (1) { - i = SSL_read(vpninfo->https_ssl, body + done, buf_len - done); + body = realloc(body, done + 16385); + i = SSL_read(vpninfo->https_ssl, body + done, 16384); if (i <= 0) break; done += i; @@ -274,7 +277,10 @@ static int process_http_response(struct openconnect_info *vpninfo, int *result, close(vpninfo->ssl_fd); vpninfo->ssl_fd = -1; } - body[done] = 0; + + if (body) + body[done] = 0; + *body_ret = body; return done; } @@ -283,6 +289,7 @@ static int fetch_config(struct openconnect_info *vpninfo, char *fu, char *bu, { struct vpn_option *opt; char buf[MAX_BUF_LEN]; + char *config_buf = NULL; int result, buflen; unsigned char local_sha1_bin[SHA_DIGEST_LENGTH]; char local_sha1_ascii[(SHA_DIGEST_LENGTH * 2)+1]; @@ -305,18 +312,19 @@ static int fetch_config(struct openconnect_info *vpninfo, char *fu, char *bu, SSL_write(vpninfo->https_ssl, buf, strlen(buf)); - buflen = process_http_response(vpninfo, &result, NULL, buf, MAX_BUF_LEN); + buflen = process_http_response(vpninfo, &result, NULL, &config_buf); if (buflen < 0) { /* We'll already have complained about whatever offended us */ return -EINVAL; } - if (result != 200) + if (result != 200) { + free(config_buf); return -EINVAL; - + } EVP_MD_CTX_init(&c); - EVP_Digest(buf, buflen, local_sha1_bin, NULL, EVP_sha1(), NULL); + EVP_Digest(config_buf, buflen, local_sha1_bin, NULL, EVP_sha1(), NULL); EVP_MD_CTX_cleanup(&c); for (i = 0; i < SHA_DIGEST_LENGTH; i++) @@ -324,10 +332,13 @@ static int fetch_config(struct openconnect_info *vpninfo, char *fu, char *bu, if (strcasecmp(server_sha1, local_sha1_ascii)) { vpninfo->progress(vpninfo, PRG_ERR, "Downloaded config file did not match intended SHA1\n"); + free(config_buf); return -EINVAL; } - return vpninfo->write_new_config(vpninfo, buf, buflen); + result = vpninfo->write_new_config(vpninfo, config_buf, buflen); + free(config_buf); + return result; } static int run_csd_script(struct openconnect_info *vpninfo, char *buf, int buflen) @@ -355,7 +366,13 @@ static int run_csd_script(struct openconnect_info *vpninfo, char *buf, int bufle strerror(errno)); return err; } - write(fd, buf, buflen); + int write_status = write(fd, buf, buflen); + if (write_status < 0) { + int err = -errno; + vpninfo->progress(vpninfo, PRG_ERR, "Failed to write temporary CSD script file: %s\n", + strerror(errno)); + return err; + } fchmod(fd, 0755); close(fd); @@ -534,6 +551,7 @@ int openconnect_obtain_cookie(struct openconnect_info *vpninfo) { struct vpn_option *opt, *next; char buf[MAX_BUF_LEN]; + char *form_buf = NULL; int result, buflen; char request_body[2048]; char *request_body_type = NULL; @@ -588,7 +606,7 @@ int openconnect_obtain_cookie(struct openconnect_info *vpninfo) SSL_write(vpninfo->https_ssl, buf, strlen(buf)); - buflen = process_http_response(vpninfo, &result, NULL, buf, MAX_BUF_LEN); + buflen = process_http_response(vpninfo, &result, NULL, &form_buf); if (buflen < 0) { /* We'll already have complained about whatever offended us */ exit(1); @@ -610,6 +628,7 @@ int openconnect_obtain_cookie(struct openconnect_info *vpninfo) vpninfo->progress(vpninfo, PRG_ERR, "Failed to parse redirected URL '%s': %s\n", vpninfo->redirect_url, strerror(-ret)); free(vpninfo->redirect_url); + free(form_buf); return ret; } @@ -653,38 +672,46 @@ int openconnect_obtain_cookie(struct openconnect_info *vpninfo) } else { vpninfo->progress(vpninfo, PRG_ERR, "Relative redirect (to '%s') not supported\n", vpninfo->redirect_url); + free(form_buf); return -EINVAL; } } if (vpninfo->csd_stuburl) { /* This is the CSD stub script, which we now need to run */ - result = run_csd_script(vpninfo, buf, buflen); - if (result) + result = run_csd_script(vpninfo, form_buf, buflen); + if (result) { + free(form_buf); return result; + } /* Now we'll be redirected to the waiturl */ goto retry; } - if (strncmp(buf, "<?xml", 5)) { + if (strncmp(form_buf, "<?xml", 5)) { /* Not XML? Perhaps it's HTML with a refresh... */ - if (strcasestr(buf, "http-equiv=\"refresh\"")) { + if (strcasestr(form_buf, "http-equiv=\"refresh\"")) { vpninfo->progress(vpninfo, PRG_INFO, "Refreshing %s after 1 second...\n", vpninfo->urlpath); sleep(1); goto retry; } vpninfo->progress(vpninfo, PRG_ERR, "Unknown response from server\n"); + free(form_buf); return -EINVAL; } request_body[0] = 0; - result = parse_xml_response(vpninfo, buf, request_body, sizeof(request_body), + result = parse_xml_response(vpninfo, form_buf, request_body, sizeof(request_body), &method, &request_body_type); + free(form_buf); + form_buf = NULL; + if (!result) goto redirect; if (result != 2) return result; + /* A return value of 2 means the XML form indicated success. We _should_ have a cookie... */ @@ -776,6 +803,7 @@ static int proxy_write(int fd, unsigned char *buf, size_t len) count += i; } + free(buf); return 0; } -- dwmw2