From a3cdde2c345267577ca2c69081c00f5fc13579c2 Mon Sep 17 00:00:00 2001 From: Camden Dixie O'Brien Date: Thu, 13 Oct 2022 17:56:41 +0100 Subject: [PATCH] Construct full path of requested resource Also detects .. in the selector string, as this could be used to see files outside of srvroot, otherwise. --- main.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 56 insertions(+), 4 deletions(-) diff --git a/main.c b/main.c index 4982080..269af0d 100644 --- a/main.c +++ b/main.c @@ -61,6 +61,26 @@ static int retrying_write(int fd, const char *buf, size_t len) return n; } +static int append_selector_part(const char *part, size_t partlen, char *buf, + size_t bufsize) +{ + if (partlen == 0) + return 0; + + if (strncmp(part, "..", partlen) == 0) { + fprintf(stderr, "Selector string contains \"..\"\n"); + return -1; + } else if (partlen + 1 > bufsize) { + fprintf(stderr, "Path buffer too small\n"); + return -1; + } + + *buf++ = '/'; + memcpy(buf, part, partlen); + + return partlen + 1; +} + int main(int argc, char *argv[]) { (void)argc; @@ -190,9 +210,42 @@ int main(int argc, char *argv[]) } /* - * Open the requested resource. + * Construct the full path to the requested resource. * - * For now, this is just opening srvroot. + * This is needed in order to pass it to stat() and open() or + * opendir() later. It must be null-terminated. We also need + * to make sure that none of the path's parts are "..", as + * this could be used to escape the srvroot directory. + */ + char *sp = sbuf; + unsigned splen = 0, ppos = srvroot_len; + for (unsigned i = 0; i < slen; ++i) { + if (sbuf[i] != '/') { + ++splen; + continue; + } + n = append_selector_part(sp, splen, &pbuf[ppos], PBUF_SIZE - ppos); + if (n == -1) + goto close_client_socket; + ppos += n; + sp = &sbuf[i + 1]; + splen = 0; + } + n = append_selector_part(sp, splen, &pbuf[ppos], PBUF_SIZE - ppos); + if (n == -1) + goto close_client_socket; + ppos += n; + + // UNSAFE! + pbuf[ppos] = '\0'; + printf("Requested path: %s\n", pbuf); + + /* + * Determine the resource's type. + */ + + /* + * Open the resource. */ if (srvroot_len + 1 > PBUF_SIZE) { fprintf(stderr, "Path buffer is too small\n"); @@ -260,8 +313,7 @@ int main(int argc, char *argv[]) continue; } if (retrying_write(cfd, rbuf, n) != n) { - fprintf(stderr, - "Error sending respose line to client\n"); + fprintf(stderr, "Error sending respose line to client\n"); continue; } }