#include "multipart_parser.h"
#define READ_BLOCK 4096
+#define POST_LIMIT 131072
enum part {
PART_UNKNOWN,
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 *
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)
{
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");
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);
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))
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");