Browse Source

cgi-io: use dynamic memory for post decoding, support proc files

Allocate dynamic buffer memory for decoding post data and allow post
requsts up to 128KB compared to the previos 1KB limit.

Also support downloading /proc and /sys files by falling back to
chunked transfer encoding when the file size cannot be determined.

Signed-off-by: Jo-Philipp Wich <jo@mein.io>
lilik-openwrt-22.03
Jo-Philipp Wich 4 years ago
committed by John Crispin
parent
commit
39087eba18
2 changed files with 97 additions and 45 deletions
  1. +1
    -1
      net/cgi-io/Makefile
  2. +96
    -44
      net/cgi-io/src/main.c

+ 1
- 1
net/cgi-io/Makefile View File

@ -8,7 +8,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=cgi-io
PKG_RELEASE:=16
PKG_RELEASE:=17
PKG_LICENSE:=GPL-2.0-or-later


+ 96
- 44
net/cgi-io/src/main.c View File

@ -38,6 +38,7 @@
#include "multipart_parser.h"
#define READ_BLOCK 4096
#define POST_LIMIT 131072
enum part {
PART_UNKNOWN,
@ -223,55 +224,86 @@ urldecode(char *buf)
return true;
}
static bool
static char *
postdecode(char **fields, int n_fields)
{
char *p;
const char *var;
static char buf[1024];
int i, len, field, found = 0;
char *p, *postbuf;
int i, field, found = 0;
ssize_t len = 0, rlen = 0, content_length = 0;
var = getenv("CONTENT_TYPE");
if (!var || strncmp(var, "application/x-www-form-urlencoded", 33))
return false;
return NULL;
var = getenv("CONTENT_LENGTH");
if (!var)
return NULL;
content_length = strtol(var, &p, 10);
if (p == var || content_length <= 0 || content_length >= POST_LIMIT)
return NULL;
postbuf = calloc(1, content_length + 1);
if (postbuf == NULL)
return NULL;
for (len = 0; len < content_length; )
{
rlen = read(0, postbuf + len, content_length - len);
if (rlen <= 0)
break;
memset(buf, 0, sizeof(buf));
len += rlen;
}
if ((len = read(0, buf, sizeof(buf) - 1)) > 0)
if (len < content_length)
{
for (p = buf, i = 0; i <= len; i++)
free(postbuf);
return NULL;
}
for (p = postbuf, i = 0; i <= len; i++)
{
if (postbuf[i] == '=')
{
if (buf[i] == '=')
{
buf[i] = 0;
postbuf[i] = 0;
for (field = 0; field < (n_fields * 2); field += 2)
for (field = 0; field < (n_fields * 2); field += 2)
{
if (!strcmp(p, fields[field]))
{
if (!strcmp(p, fields[field]))
{
fields[field + 1] = buf + i + 1;
found++;
}
fields[field + 1] = postbuf + i + 1;
found++;
}
}
else if (buf[i] == '&' || buf[i] == '\0')
{
buf[i] = 0;
}
else if (postbuf[i] == '&' || postbuf[i] == '\0')
{
postbuf[i] = 0;
if (found >= n_fields)
break;
if (found >= n_fields)
break;
p = buf + i + 1;
}
p = postbuf + i + 1;
}
}
for (field = 0; field < (n_fields * 2); field += 2)
{
if (!urldecode(fields[field + 1]))
return false;
{
free(postbuf);
return NULL;
}
}
return (found >= n_fields);
return postbuf;
}
static char *
@ -658,6 +690,14 @@ main_upload(int argc, char *argv[])
return 0;
}
static void
free_charp(char **ptr)
{
free(*ptr);
}
#define autochar __attribute__((__cleanup__(free_charp))) char
static int
main_download(int argc, char **argv)
{
@ -668,7 +708,7 @@ main_download(int argc, char **argv)
struct stat s;
int rfd;
postdecode(fields, 4);
autochar *post = postdecode(fields, 4);
if (!fields[1] || !session_access(fields[1], "cgi-io", "download", "read"))
return failure(403, 0, "Download permission denied");
@ -706,29 +746,39 @@ main_download(int argc, char **argv)
if (fields[5])
printf("Content-Disposition: attachment; filename=\"%s\"\r\n", fields[5]);
printf("Content-Length: %llu\r\n\r\n", size);
fflush(stdout);
if (size > 0) {
printf("Content-Length: %llu\r\n\r\n", size);
fflush(stdout);
while (size > 0) {
len = sendfile(1, rfd, NULL, size);
while (size > 0) {
len = sendfile(1, rfd, NULL, size);
if (len == -1) {
if (errno == ENOSYS || errno == EINVAL) {
while ((len = read(rfd, buf, sizeof(buf))) > 0)
fwrite(buf, len, 1, stdout);
if (len == -1) {
if (errno == ENOSYS || errno == EINVAL) {
while ((len = read(rfd, buf, sizeof(buf))) > 0)
fwrite(buf, len, 1, stdout);
fflush(stdout);
break;
fflush(stdout);
break;
}
if (errno == EINTR || errno == EAGAIN)
continue;
}
if (errno == EINTR || errno == EAGAIN)
continue;
if (len <= 0)
break;
size -= len;
}
}
else {
printf("\r\n");
if (len <= 0)
break;
while ((len = read(rfd, buf, sizeof(buf))) > 0)
fwrite(buf, len, 1, stdout);
size -= len;
fflush(stdout);
}
close(rfd);
@ -749,7 +799,9 @@ main_backup(int argc, char **argv)
char hostname[64] = { 0 };
char *fields[] = { "sessionid", NULL };
if (!postdecode(fields, 1) || !session_access(fields[1], "cgi-io", "backup", "read"))
autochar *post = postdecode(fields, 1);
if (!fields[1] || !session_access(fields[1], "cgi-io", "backup", "read"))
return failure(403, 0, "Backup permission denied");
if (pipe(fds))
@ -929,7 +981,7 @@ main_exec(int argc, char **argv)
char *p, **args;
pid_t pid;
postdecode(fields, 4);
autochar *post = postdecode(fields, 4);
if (!fields[1] || !session_access(fields[1], "cgi-io", "exec", "read"))
return failure(403, 0, "Exec permission denied");


Loading…
Cancel
Save