[PATCH] Initial work on automatically reallocated buffer size for CSD script
David Woodhouse
dwmw2 at infradead.org
Thu Feb 11 19:07:04 EST 2010
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
More information about the openconnect-devel
mailing list