diff options
| author | Xavier Del Campo Romero <xavi.dcr@tutanota.com> | 2023-11-23 00:01:41 +0100 |
|---|---|---|
| committer | Xavier Del Campo Romero <xavi.dcr@tutanota.com> | 2023-11-23 00:01:41 +0100 |
| commit | daffea4660560f7420e57ecc40b29f6ef3c46f98 (patch) | |
| tree | e5c9e52ac7e39dc5e0b4944bc46621b383914c15 /main.c | |
| parent | 0854bc0030c145bebc9fcbc24ea9a4f3a7a67b3a (diff) | |
| download | slcl-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.c | 56 |
1 files changed, 52 insertions, 4 deletions
@@ -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); |
