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.
This commit is contained in:
Xavier Del Campo Romero 2023-11-23 00:01:41 +01:00
parent 0854bc0030
commit daffea4660
Signed by: xavi
GPG Key ID: 84FF3612A9BF43F2
1 changed files with 52 additions and 4 deletions

56
main.c
View File

@ -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);