aboutsummaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
authorXavier Del Campo Romero <xavi.dcr@tutanota.com>2023-11-23 00:01:41 +0100
committerXavier Del Campo Romero <xavi.dcr@tutanota.com>2023-11-23 00:01:41 +0100
commitdaffea4660560f7420e57ecc40b29f6ef3c46f98 (patch)
treee5c9e52ac7e39dc5e0b4944bc46621b383914c15 /main.c
parent0854bc0030c145bebc9fcbc24ea9a4f3a7a67b3a (diff)
downloadslcl-daffea4660560f7420e57ecc40b29f6ef3c46f98.tar.gz
main.c: Treat non-existing upload dir as non-fatal
When a user attempts to upload a file into a non-existing directory, slcl would not check whether the directory exists. Then, rename(3) would fail and slcl would treat this as a fatal error, effectively closing itself. Since this is an example of ill-formed user input, it must be treated as a non-fatal error, and instead slcl should return a bad request page.
Diffstat (limited to 'main.c')
-rw-r--r--main.c56
1 files changed, 52 insertions, 4 deletions
diff --git a/main.c b/main.c
index 5abf848..0c7be51 100644
--- a/main.c
+++ b/main.c
@@ -1131,12 +1131,43 @@ static int rename_or_move(const char *const old, const char *const new)
return res;
}
+static int check_upload_dir(const char *const dir)
+{
+ struct stat sb;
+
+ if (stat(dir, &sb))
+ {
+ switch (errno)
+ {
+ case ENOENT:
+ /* Fall through. */
+ case ENOTDIR:
+ fprintf(stderr, "%s: cannot upload to non-existing dir %s\n",
+ __func__, dir);
+ return 1;
+
+ default:
+ fprintf(stderr, "%s: stat(2) %s: %s\n",
+ __func__, dir, strerror(errno));
+ return -1;
+ }
+ }
+ else if (!S_ISDIR(sb.st_mode))
+ {
+ fprintf(stderr, "%s: %s not a dir\n", __func__, dir);
+ return 1;
+ }
+
+ return 0;
+}
+
static int upload_file(const struct http_post_file *const f,
const char *const user, const char *const root, const char *const dir)
{
int ret = -1;
- struct dynstr d;
+ struct dynstr dird, d;
+ dynstr_init(&dird);
dynstr_init(&d);
if (!root)
@@ -1144,9 +1175,21 @@ static int upload_file(const struct http_post_file *const f,
fprintf(stderr, "%s: auth_dir failed\n", __func__);
goto end;
}
- else if (dynstr_append(&d, "%s/user/%s/%s%s", root, user, dir, f->filename))
+ else if (dynstr_append(&dird, "%s/user/%s/%s", root, user, dir))
{
- fprintf(stderr, "%s: dynstr_append failed\n", __func__);
+ fprintf(stderr, "%s: dynstr_append dird failed\n", __func__);
+ goto end;
+ }
+ else if ((ret = check_upload_dir(dird.str)))
+ {
+ if (ret < 0)
+ fprintf(stderr, "%s: check_upload_dir failed\n", __func__);
+
+ goto end;
+ }
+ else if (dynstr_append(&d, "%s%s", dird.str, f->filename))
+ {
+ fprintf(stderr, "%s: dynstr_append d failed\n", __func__);
goto end;
}
else if (rename_or_move(f->tmpname, d.str))
@@ -1158,6 +1201,7 @@ static int upload_file(const struct http_post_file *const f,
ret = 0;
end:
+ dynstr_free(&dird);
dynstr_free(&d);
return ret;
}
@@ -1257,11 +1301,15 @@ static int upload_files(const struct http_payload *const p,
for (size_t i = 0; i < po->nfiles; i++)
{
- if (upload_file(&po->files[i], user, root, dir))
+ const int ret = upload_file(&po->files[i], user, root, dir);
+
+ if (ret < 0)
{
fprintf(stderr, "%s: upload_file failed\n", __func__);
return -1;
}
+ else if (ret)
+ return page_bad_request(r);
}
return redirect_to_dir(dir, r);