diff options
Diffstat (limited to 'www/temp.causal.agency/up.c')
-rw-r--r-- | www/temp.causal.agency/up.c | 143 |
1 files changed, 90 insertions, 53 deletions
diff --git a/www/temp.causal.agency/up.c b/www/temp.causal.agency/up.c index 885b8acd..561a8901 100644 --- a/www/temp.causal.agency/up.c +++ b/www/temp.causal.agency/up.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 C. McEnroe <june@causal.agency> +/* Copyright (C) 2020 June McEnroe <june@causal.agency> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by @@ -21,7 +21,6 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <sys/capsicum.h> #include <sys/types.h> #include <sysexits.h> #include <time.h> @@ -30,8 +29,7 @@ #include <kcgi.h> #include <kcgihtml.h> -static int cwd = -1; - +static const char *Page = "up"; static const struct kvalid Key = { NULL, "file" }; static enum kcgi_err head(struct kreq *req, enum khttp http, enum kmime mime) { @@ -45,6 +43,28 @@ static enum kcgi_err fail(struct kreq *req, enum khttp http) { || khttp_printf(req, "%s\n", khttps[http]); } +static int dir = -1; +static const char *upload(const char *ext, void *ptr, size_t len) { + static char name[256]; + snprintf( + name, sizeof(name), "%jx%08x%s%s", + (intmax_t)time(NULL), arc4random(), + (ext && ext[0] != '.' ? "." : ""), (ext ? ext : "") + ); + int fd = openat(dir, name, O_CREAT | O_EXCL | O_WRONLY, 0644); + if (fd < 0) { + warn("%s", name); + return NULL; + } + ssize_t n = write(fd, ptr, len); + int error = close(fd); + if (n < 0 || error) { + warn("%s", name); + return NULL; + } + return name; +} + static enum kcgi_err handle(struct kreq *req) { if (req->page) return fail(req, KHTTP_404); @@ -83,74 +103,91 @@ static enum kcgi_err handle(struct kreq *req) { struct kpair *field = req->fieldmap[0]; if (!field || !field->valsz) return fail(req, KHTTP_400); - char name[256]; const char *ext = strrchr(field->file, '.'); - if (!ext) ext = ""; - snprintf( - name, sizeof(name), "%jx%08x%s", - (intmax_t)time(NULL), arc4random(), ext - ); - - int fd = openat(cwd, name, O_CREAT | O_EXCL | O_WRONLY, 0644); - if (fd < 0) { - warn("openat"); - return fail(req, KHTTP_507); - } - ssize_t len = write(fd, field->val, field->valsz); - int error = close(fd); - if (len < 0 || error) { - warn("write"); - return fail(req, KHTTP_507); - } + const char *name = upload(ext, field->val, field->valsz); + if (!name) return fail(req, KHTTP_507); return head(req, KHTTP_303, KMIME_TEXT_PLAIN) || khttp_head(req, kresps[KRESP_LOCATION], "/%s", name) || khttp_body(req) || khttp_puts(req, name); + } else if (req->method == KMETHOD_PUT) { + struct kpair *field = req->fields; + if (!field || !field->valsz) return fail(req, KHTTP_400); + + const char *ext = req->suffix; + if (!ext[0]) ext = strrchr(field->file, '.'); + const char *name = upload(ext, field->val, field->valsz); + if (!name) return fail(req, KHTTP_507); + + return head(req, KHTTP_200, KMIME_TEXT_PLAIN) + || khttp_body(req) + || khttp_printf( + req, "%s://%s/%s\n", kschemes[req->scheme], req->host, name + ); + } else { return fail(req, KHTTP_405); } } -static void sandbox(void) { - cwd = open(".", O_DIRECTORY); - if (cwd < 0) err(EX_CONFIG, "."); +int main(int argc, char *argv[]) { + int error; + const char *path = (argc > 1 ? argv[1] : "."); + dir = open(path, O_DIRECTORY); + if (dir < 0) err(EX_NOINPUT, "%s", path); - int error = cap_enter(); - if (error) err(EX_OSERR, "cap_enter"); +#ifdef __OpenBSD__ + error = unveil(path, "wc"); + if (error) err(EX_OSERR, "unveil"); +#endif - cap_rights_t rights; - cap_rights_init(&rights, CAP_LOOKUP, CAP_CREATE, CAP_PWRITE); - error = cap_rights_limit(cwd, &rights); - if (error) err(EX_OSERR, "cap_rights_limit"); -} + if (!khttp_fcgi_test()) { +#ifdef __OpenBSD__ + error = pledge("stdio wpath cpath proc", NULL); + if (error) err(EX_OSERR, "pledge"); +#endif -int main(void) { - const char *page = "up"; - if (khttp_fcgi_test()) { - struct kfcgi *fcgi; - enum kcgi_err error = khttp_fcgi_init(&fcgi, &Key, 1, &page, 1, 0); - if (error) errx(EX_CONFIG, "khttp_fcgi_init: %s", kcgi_strerror(error)); - sandbox(); - for ( - struct kreq req; - KCGI_OK == (error = khttp_fcgi_parse(fcgi, &req)); - khttp_free(&req) - ) { - error = handle(&req); - if (error && error != KCGI_HUP) break; - } - if (error != KCGI_EXIT) { - errx(EX_PROTOCOL, "khttp_fcgi_parse: %s", kcgi_strerror(error)); - } - khttp_fcgi_free(fcgi); - } else { struct kreq req; - enum kcgi_err error = khttp_parse(&req, &Key, 1, &page, 1, 0); + error = khttp_parse(&req, &Key, 1, &Page, 1, 0); if (error) errx(EX_PROTOCOL, "khttp_parse: %s", kcgi_strerror(error)); + +#ifdef __OpenBSD__ + error = pledge("stdio wpath cpath", NULL); + if (error) err(EX_OSERR, "pledge"); +#endif + error = handle(&req); if (error) errx(EX_PROTOCOL, "%s", kcgi_strerror(error)); khttp_free(&req); + return EX_OK; + } + +#ifdef __OpenBSD__ + error = pledge("stdio wpath cpath unix sendfd recvfd proc", NULL); + if (error) err(EX_OSERR, "pledge"); +#endif + + struct kfcgi *fcgi; + error = khttp_fcgi_init(&fcgi, &Key, 1, &Page, 1, 0); + if (error) errx(EX_CONFIG, "khttp_fcgi_init: %s", kcgi_strerror(error)); + +#ifdef __OpenBSD__ + error = pledge("stdio wpath cpath recvfd", NULL); + if (error) err(EX_OSERR, "pledge"); +#endif + + for ( + struct kreq req; + !(error = khttp_fcgi_parse(fcgi, &req)); + khttp_free(&req) + ) { + error = handle(&req); + if (error && error != KCGI_HUP) break; + } + if (error != KCGI_EXIT) { + errx(EX_PROTOCOL, "khttp_fcgi_parse: %s", kcgi_strerror(error)); } + khttp_fcgi_free(fcgi); } |