commit b12a77acd24fc170b1ad047986ffaf13592fb326
parent f66a8a67b9471909016d6f24ce93f39584130a67
Author: Christoph Lohmann <20h@r-36.net>
Date: Thu, 20 Jul 2023 06:30:24 +0200
First rework of path handling.
* Renaming the gph functions.
* Beware, still full of debug functions.
Diffstat:
M | handlr.c | | | 112 | ++++++++++++++++++++++++++++++++++++++++++++----------------------------------- |
M | handlr.h | | | 25 | ++++++++++++++++++++----- |
M | ind.c | | | 133 | ++++++++++++++++++++++++++++++++++++++++--------------------------------------- |
M | ind.h | | | 41 | +++++++++++++++++++++-------------------- |
M | index.gph | | | 4 | +++- |
M | main.c | | | 144 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------- |
6 files changed, 277 insertions(+), 182 deletions(-)
diff --git a/handlr.c b/handlr.c
@@ -17,6 +17,7 @@
#include <dirent.h>
#include <sys/wait.h>
#include <errno.h>
+#include <libgen.h>
#include "ind.h"
#include "arg.h"
@@ -25,7 +26,7 @@ void
handledir(int sock, char *path, char *port, char *base, char *args,
char *sear, char *ohost, char *chost, char *bhost, int istls)
{
- char *pa, *file, *e, *par, *b;
+ char *pa, *file, *e, *par;
struct dirent **dirent;
int ndir, i, ret = 0;
struct stat st;
@@ -35,22 +36,25 @@ handledir(int sock, char *path, char *port, char *base, char *args,
USED(sear);
USED(bhost);
- pa = xstrdup(path);
- e = pa + strlen(pa) - 1;
- if (e > pa && e[0] == '/')
- *e = '\0';
+ printf("handledir:\n");
+ printf("sock = %d; path = %s; port = %s; base = %s; args = %s;\n",
+ sock, path, port, base, args);
+ printf("sear = %s; ohost = %s; chost = %s; bhost = %s; istls = %d;\n",
+ sear, ohost, chost, bhost, istls);
- par = xstrdup(pa);
+ pa = xstrdup(path);
- b = strrchr(makebasepath(par, base), '/');
- if (b != NULL) {
- *b = '\0';
+ /* Is there any directory below the request? */
+ if (strlen(pa+strlen(base)) > 1) {
+ par = xstrdup(pa+strlen(base));
+ e = strrchr(par, '/');
+ *e = '\0';
dprintf(sock, "1..\t%s\t%s\t%s\r\n",
- makebasepath(par, base), ohost, port);
+ par, ohost, port);
+ free(par);
}
- free(par);
- ndir = scandir(pa[0] ? pa : ".", &dirent, 0, alphasort);
+ ndir = scandir(pa, &dirent, 0, alphasort);
if (ndir < 0) {
perror("scandir");
free(pa);
@@ -61,19 +65,21 @@ handledir(int sock, char *path, char *port, char *base, char *args,
continue;
type = gettype(dirent[i]->d_name);
- file = smprintf("%s%s%s", pa,
- pa[0] == '/' && pa[1] == '\0' ? "" : "/",
+
+ file = smprintf("%s%s%s",
+ pa,
+ pa[strlen(pa)-1] == '/'? "" : "/",
dirent[i]->d_name);
+ printf("handledir: smprintf file = %s\n", file);
if (stat(file, &st) >= 0 && S_ISDIR(st.st_mode))
type = gettype("index.gph");
- e = makebasepath(file, base);
ret = dprintf(sock,
"%c%-50.50s %10s %16s\t%s\t%s\t%s\r\n",
*type->type,
dirent[i]->d_name,
humansize(st.st_size),
humantime(&(st.st_mtime)),
- e, ohost, port);
+ file + strlen(base), ohost, port);
free(file);
}
for (i = 0; i < ndir; i++)
@@ -89,24 +95,30 @@ void
handlegph(int sock, char *file, char *port, char *base, char *args,
char *sear, char *ohost, char *chost, char *bhost, int istls)
{
- Indexs *act;
+ gphindex *act;
int i, ret = 0;
USED(args);
USED(sear);
USED(bhost);
- act = scanfile(file);
+ printf("handlegph:\n");
+ printf("sock = %d; file = %s; port = %s; base = %s; args = %s;\n",
+ sock, file, port, base, args);
+ printf("sear = %s; ohost = %s; chost = %s; bhost = %s; istls = %d;\n",
+ sear, ohost, chost, bhost, istls);
+
+ act = gph_scanfile(file);
if (act != NULL) {
for (i = 0; i < act->num && ret >= 0; i++)
- ret = printelem(sock, act->n[i], file, base, ohost, port);
+ ret = gph_printelem(sock, act->n[i], file, base, ohost, port);
dprintf(sock, ".\r\n");
for (i = 0; i < act->num; i++) {
- freeelem(act->n[i]);
+ gph_freeelem(act->n[i]);
act->n[i] = NULL;
}
- freeindex(act);
+ gph_freeindex(act);
}
}
@@ -135,21 +147,22 @@ void
handlecgi(int sock, char *file, char *port, char *base, char *args,
char *sear, char *ohost, char *chost, char *bhost, int istls)
{
- char *p, *path;
+ char *script, *path;
USED(base);
USED(port);
- path = xstrdup(file);
- p = strrchr(path, '/');
- if (p != NULL)
- p[1] = '\0';
- else {
- free(path);
- path = NULL;
- }
+ printf("handlecgi:\n");
+ printf("sock = %d; file = %s; port = %s; base = %s; args = %s;\n",
+ sock, file, port, base, args);
+ printf("sear = %s; ohost = %s; chost = %s; bhost = %s; istls = %d;\n",
+ sear, ohost, chost, bhost, istls);
- p = makebasepath(file, base);
+ path = xstrdup(file);
+ path = dirname(path);
+ script = path + strlen(path) + 1;
+ printf("path = %s\n", path);
+ printf("script = %s\n", script);
if (sear == NULL)
sear = "";
@@ -166,10 +179,10 @@ handlecgi(int sock, char *file, char *port, char *base, char *args,
break;
}
- setcgienviron(p, file, port, base, args, sear, ohost, chost,
+ setcgienviron(script, file, port, base, args, sear, ohost, chost,
bhost, istls);
- if (execl(file, p, sear, args, ohost, port,
+ if (execl(file, script, sear, args, ohost, port,
(char *)NULL) == -1) {
perror("execl");
_exit(1);
@@ -189,25 +202,24 @@ handledcgi(int sock, char *file, char *port, char *base, char *args,
char *sear, char *ohost, char *chost, char *bhost, int istls)
{
FILE *fp;
- char *p, *path, *ln = NULL;
+ char *script, *path, *ln = NULL;
size_t linesiz = 0;
ssize_t n;
int outsocks[2], ret = 0;
- Elems *el;
+ gphelem *el;
+
+ printf("handledcgi:\n");
+ printf("sock = %d; file = %s; port = %s; base = %s; args = %s;\n",
+ sock, file, port, base, args);
+ printf("sear = %s; ohost = %s; chost = %s; bhost = %s; istls = %d;\n",
+ sear, ohost, chost, bhost, istls);
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, outsocks) < 0)
return;
path = xstrdup(file);
- p = strrchr(path, '/');
- if (p != NULL)
- p[1] = '\0';
- else {
- free(path);
- path = NULL;
- }
-
- p = makebasepath(file, base);
+ path = dirname(path);
+ script = path + strlen(path) + 1;
if (sear == NULL)
sear = "";
@@ -225,10 +237,10 @@ handledcgi(int sock, char *file, char *port, char *base, char *args,
break;
}
- setcgienviron(p, file, port, base, args, sear, ohost, chost,
+ setcgienviron(script, file, port, base, args, sear, ohost, chost,
bhost, istls);
- if (execl(file, p, sear, args, ohost, port,
+ if (execl(file, script, sear, args, ohost, port,
(char *)NULL) == -1) {
perror("execl");
_exit(1);
@@ -251,21 +263,21 @@ handledcgi(int sock, char *file, char *port, char *base, char *args,
if (ln[n - 1] == '\n')
ln[--n] = '\0';
- el = getadv(ln);
+ el = gph_getadv(ln);
if (el == NULL)
continue;
- ret = printelem(sock, el, file, base, ohost, port);
- freeelem(el);
+ ret = gph_printelem(sock, el, file, base, ohost, port);
+ gph_freeelem(el);
}
if (ferror(fp))
perror("getline");
dprintf(sock, ".\r\n");
free(ln);
- free(path);
fclose(fp);
wait(NULL);
+ free(path);
break;
}
}
diff --git a/handlr.h b/handlr.h
@@ -9,16 +9,31 @@
/*
* Handler API definition
*
- * path .... absolute path to the script
+ * Sample: /get/some/script/with/dirs////?key=value\tsearch what?\r\n
+ * * in /get/some/script is a file "index.dcgi"
+ * * request to bitreich.org on port 70 using TLS
+ * * base is in /var/gopher
+ * * client from 85.65.4.2
+ *
+ * path/file absolute path to the script/directory, always starts with '/'
+ * Sample: /var/gopher/get/some/script/index.dcgi
* port .... port which the script should use when defining menu items
* (See -o and -p in geomyidae(8))
- * base .... base path of geomyidae ("" in case of chroot)
- * args .... query string parsed after »script?query«
- * sear .... search part of request (»selector\tsearch\r\n«)
- * ohost ... host of geomiydae (See -h in geomyidae(8))
+ * Sample: 70
+ * base .... base path of geomyidae, never ends in '/', so chroot is ''
+ * Sample: /var/gopher
+ * args .... Gives all variable input from the selector in some way.
+ * Sample: /with/dirs////?key=value
+ * sear .... search part of request
+ * Sample: search what?
+ * ohost ... host of geomyidae (See -h in geomyidae(8))
+ * Sample: bitreich.org
* chost ... IP of the client sending a request
+ * Sample: 85.65.4.2
* bhost ... server IP the server received the connection to
+ * Sample: 78.46.175.99
* istls ... set to 1, if TLS was used for thr request
+ * Sample: 1
*/
void handledir(int sock, char *path, char *port, char *base, char *args,
diff --git a/ind.c b/ind.c
@@ -24,6 +24,7 @@
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <limits.h>
+#include <errno.h>
#define PAGE_SHIFT 12
#define PAGE_SIZE (1UL << PAGE_SHIFT)
@@ -258,7 +259,7 @@ gettype(char *filename)
}
void
-freeelem(Elems *e)
+gph_freeelem(gphelem *e)
{
if (e != NULL) {
if (e->e != NULL) {
@@ -273,12 +274,12 @@ freeelem(Elems *e)
}
void
-freeindex(Indexs *i)
+gph_freeindex(gphindex *i)
{
if (i != NULL) {
if (i->n != NULL) {
for (;i->num > 0; i->num--)
- freeelem(i->n[i->num - 1]);
+ gph_freeelem(i->n[i->num - 1]);
free(i->n);
}
free(i);
@@ -288,7 +289,7 @@ freeindex(Indexs *i)
}
void
-addelem(Elems *e, char *s)
+gph_addelem(gphelem *e, char *s)
{
e->num++;
e->e = xrealloc(e->e, sizeof(char *) * e->num);
@@ -297,23 +298,23 @@ addelem(Elems *e, char *s)
return;
}
-Elems *
-getadv(char *str)
+gphelem *
+gph_getadv(char *str)
{
char *b, *e, *o, *bo;
- Elems *ret;
+ gphelem *ret;
- ret = xcalloc(1, sizeof(Elems));
+ ret = xcalloc(1, sizeof(gphelem));
if (strchr(str, '\t')) {
- addelem(ret, "i");
- addelem(ret, "Happy helping ☃ here: You tried to "
+ gph_addelem(ret, "i");
+ gph_addelem(ret, "Happy helping ☃ here: You tried to "
"output a spurious TAB character. This will "
"break gopher. Please review your scripts. "
"Have a nice day!");
- addelem(ret, "Err");
- addelem(ret, "server");
- addelem(ret, "port");
+ gph_addelem(ret, "Err");
+ gph_addelem(ret, "server");
+ gph_addelem(ret, "port");
return ret;
}
@@ -331,7 +332,7 @@ getadv(char *str)
}
*e = '\0';
e++;
- addelem(ret, b);
+ gph_addelem(ret, b);
b = e;
bo = b;
}
@@ -339,7 +340,7 @@ getadv(char *str)
e = strchr(b, ']');
if (e != NULL) {
*e = '\0';
- addelem(ret, b);
+ gph_addelem(ret, b);
}
free(o);
@@ -349,55 +350,55 @@ getadv(char *str)
}
/* Invalid entry: Give back the whole line. */
- freeelem(ret);
- ret = xcalloc(1, sizeof(Elems));
+ gph_freeelem(ret);
+ ret = xcalloc(1, sizeof(gphelem));
}
- addelem(ret, "i");
+ gph_addelem(ret, "i");
/* Jump over escape sequence. */
if (str[0] == '[' && str[1] == '|')
str += 2;
- addelem(ret, str);
- addelem(ret, "Err");
- addelem(ret, "server");
- addelem(ret, "port");
+ gph_addelem(ret, str);
+ gph_addelem(ret, "Err");
+ gph_addelem(ret, "server");
+ gph_addelem(ret, "port");
return ret;
}
void
-addindexs(Indexs *idx, Elems *el)
+gph_addindex(gphindex *idx, gphelem *el)
{
idx->num++;
- idx->n = xrealloc(idx->n, sizeof(Elems) * idx->num);
+ idx->n = xrealloc(idx->n, sizeof(gphelem *) * idx->num);
idx->n[idx->num - 1] = el;
return;
}
-Indexs *
-scanfile(char *fname)
+gphindex *
+gph_scanfile(char *fname)
{
char *ln = NULL;
size_t linesiz = 0;
ssize_t n;
FILE *fp;
- Indexs *ret;
- Elems *el;
+ gphindex *ret;
+ gphelem *el;
if (!(fp = fopen(fname, "r")))
return NULL;
- ret = xcalloc(1, sizeof(Indexs));
+ ret = xcalloc(1, sizeof(gphindex));
while ((n = getline(&ln, &linesiz, fp)) > 0) {
if (ln[n - 1] == '\n')
ln[--n] = '\0';
- el = getadv(ln);
+ el = gph_getadv(ln);
if (el == NULL)
continue;
- addindexs(ret, el);
+ gph_addindex(ret, el);
}
if (ferror(fp))
perror("getline");
@@ -413,9 +414,9 @@ scanfile(char *fname)
}
int
-printelem(int fd, Elems *el, char *file, char *base, char *addr, char *port)
+gph_printelem(int fd, gphelem *el, char *file, char *base, char *addr, char *port)
{
- char *path, *p, *argbase, buf[PATH_MAX+1], *argp, *realbase;
+ char *path, *p, *argbase, buf[PATH_MAX+1], *argp, *realbase, *rpath;
int len, blen;
if (!strcmp(el->e[3], "server")) {
@@ -432,10 +433,6 @@ printelem(int fd, Elems *el, char *file, char *base, char *addr, char *port)
* some URL and ignore various types that have different semantics,
* do not point to some file or directory.
*/
- /*
- * FUTURE: If ever special requests with no beginning '/' are used in
- * geomyidae, this is the place to control this.
- */
if ((el->e[2][0] != '\0'
&& el->e[2][0] != '/' /* Absolute Request. */
&& el->e[0][0] != 'i' /* Informational item. */
@@ -446,45 +443,50 @@ printelem(int fd, Elems *el, char *file, char *base, char *addr, char *port)
&& el->e[0][0] != 'T') && /* tn3270 */
!(el->e[0][0] == 'h' && !strncmp(el->e[2], "URL:", 4))) {
path = file + strlen(base);
- if ((p = strrchr(path, '/')))
- len = p - path;
- else
+
+ /* Strip off original gph file name. */
+ if ((p = strrchr(path, '/'))) {
+ len = strlen(path) - strlen(basename(path));
+ } else {
len = strlen(path);
+ }
/* Strip off arguments for realpath. */
argbase = strchr(el->e[2], '?');
- if (argbase != NULL)
+ if (argbase != NULL) {
blen = argbase - el->e[2];
- else
+ } else {
blen = strlen(el->e[2]);
+ }
- snprintf(buf, sizeof(buf), "%s%.*s/%.*s", base, len,
+ /*
+ * Print everything together. Realpath will resolve it.
+ */
+ snprintf(buf, sizeof(buf), "%s%.*s%.*s", base, len,
path, blen, el->e[2]);
- if ((path = realpath(buf, NULL)) &&
- (realbase = realpath(base, NULL)) &&
- !strncmp(realbase, path, strlen(realbase))) {
- p = path + strlen(realbase);
+ if ((rpath = realpath(buf, NULL)) &&
+ (realbase = realpath(*base? base : "/", NULL)) &&
+ !strncmp(realbase, rpath, strlen(realbase))) {
+ p = rpath + (*base? strlen(realbase) : 0);
/*
- * Do not forget to readd arguments which were
+ * Do not forget to re-add arguments which were
* stripped off.
*/
- if (argbase != NULL)
- argp = smprintf("%s%s", p[0]? p : "/", argbase);
- else
- argp = xstrdup(p[0]? p : "/");
+ argp = smprintf("%s%s", *p? p : "/", argbase? argbase : "");
free(el->e[2]);
el->e[2] = argp;
free(realbase);
}
- free(path);
+ if (rpath != NULL)
+ free(rpath);
}
if (dprintf(fd, "%.1s%s\t%s\t%s\t%s\r\n", el->e[0], el->e[1], el->e[2],
el->e[3], el->e[4]) < 0) {
- perror("printelem: dprintf");
+ perror("printgphelem: dprintf");
return -1;
}
return 0;
@@ -545,19 +547,26 @@ setcgienviron(char *file, char *path, char *port, char *base, char *args,
setenv("GATEWAY_INTERFACE", "CGI/1.1", 1);
/* TODO: Separate, if run like rest.dcgi. */
setenv("PATH_INFO", file, 1);
+ printf("PATH_INFO = %s\n", file);
setenv("PATH_TRANSLATED", path, 1);
+ printf("PATH_TRANSLATED = %s\n", path);
setenv("QUERY_STRING", args, 1);
+ printf("QUERY_STRING = %s\n", args);
/* legacy compatibility */
setenv("SELECTOR", args, 1);
+ printf("SELECTOR = %s\n", args);
setenv("REQUEST", args, 1);
+ printf("REQUEST = %s\n", args);
setenv("REMOTE_ADDR", chost, 1);
+ printf("REMOTE_ADDR = %s\n", chost);
/*
* Don't do a reverse lookup on every call. Only do when needed, in
* the script. The RFC allows us to set the IP to the value.
*/
setenv("REMOTE_HOST", chost, 1);
+ printf("REMOTE_HOST = %s\n", chost);
/* Please do not implement identd here. */
unsetenv("REMOTE_IDENT");
unsetenv("REMOTE_USER");
@@ -569,9 +578,12 @@ setcgienviron(char *file, char *path, char *port, char *base, char *args,
*/
setenv("REQUEST_METHOD", "GET", 1);
setenv("SCRIPT_NAME", file, 1);
+ printf("SCRIPT_NAME = %s\n", file);
setenv("SERVER_NAME", ohost, 1);
+ printf("SERVER_PORT = %s\n", port);
setenv("SERVER_PORT", port, 1);
setenv("SERVER_LISTEN_NAME", bhost, 1);
+ printf("SERVER_LISTEN_NAME = %s\n", bhost);
if (istls) {
setenv("SERVER_PROTOCOL", "gophers/1.0", 1);
} else {
@@ -580,8 +592,10 @@ setcgienviron(char *file, char *path, char *port, char *base, char *args,
setenv("SERVER_SOFTWARE", "geomyidae", 1);
setenv("X_GOPHER_SEARCH", sear, 1);
+ printf("X_GOPHER_SEARCH = %s\n", sear);
/* legacy compatibility */
setenv("SEARCHREQUEST", sear, 1);
+ printf("SEARCHREQUEST = %s\n", sear);
if (istls) {
setenv("GOPHERS", "on", 1);
@@ -626,14 +640,3 @@ humantime(const time_t *clock)
return buf;
}
-char *
-makebasepath(char *path, char *base)
-{
- if (!(base[0] == '/' && base[1] == '\0') &&
- strlen(path) > strlen(base)) {
- return path + strlen(base);
- } else {
- return path;
- }
-}
-
diff --git a/ind.h b/ind.h
@@ -10,18 +10,6 @@
extern int glfd;
-typedef struct Elems Elems;
-struct Elems {
- char **e;
- int num;
-};
-
-typedef struct Indexs Indexs;
-struct Indexs {
- Elems **n;
- int num;
-};
-
typedef struct filetype filetype;
struct filetype {
char *end;
@@ -31,20 +19,34 @@ struct filetype {
};
filetype *gettype(char *filename);
+
+typedef struct gphelem gphelem;
+struct gphelem {
+ char **e;
+ int num;
+};
+
+typedef struct gphindex gphindex;
+struct gphindex {
+ gphelem **n;
+ int num;
+};
+
+gphindex *gph_scanfile(char *fname);
+gphelem *gph_getadv(char *str);
+int gph_printelem(int fd, gphelem *el, char *file, char *base, char *addr, char *port);
+void gph_addindex(gphindex *idx, gphelem *el);
+void gph_addelem(gphelem *e, char *s);
+void gph_freeindex(gphindex *i);
+void gph_freeelem(gphelem *e);
+
void *xcalloc(size_t, size_t);
void *xmalloc(size_t);
void *xrealloc(void *, size_t);
char *xstrdup(const char *str);
int xsendfile(int, int);
-Indexs *scanfile(char *fname);
-Elems *getadv(char *str);
int pendingbytes(int sock);
void waitforpendingbytes(int sock);
-int printelem(int fd, Elems *el, char *file, char *base, char *addr, char *port);
-void addindexs(Indexs *idx, Elems *el);
-void addelem(Elems *e, char *s);
-void freeindex(Indexs *i);
-void freeelem(Elems *e);
char *smprintf(char *fmt, ...);
char *reverselookup(char *host);
void setcgienviron(char *file, char *path, char *port, char *base,
@@ -52,7 +54,6 @@ void setcgienviron(char *file, char *path, char *port, char *base,
char *bhost, int istls);
char *humansize(off_t n);
char *humantime(const time_t *clock);
-char *makebasepath(char *path, char *base);
#endif
diff --git a/index.gph b/index.gph
@@ -3,9 +3,11 @@ tcomment (old style comment)
[1|R-36|/|server|port]
[0|file - comment|/file.txt|server|port]
[h|http://www.heise.de|URL:http://www.heise.de|server|port]
-[0|some \| escape and [ special characters ] test|error|server|port]
+[0|some \| escape and [ special characters ] test|Err|server|port]
[9|binary data file|/file.dat|server|port]
[9|unclosed entry|/file.dat|server|port
+[9|some relative path with args|./legacy/caps.txt?key=value|server|port]
+[9|some other relative path|legacy/caps.txt|server|port]
[|empty type||server|port]
[|Escape something, [| is skipped.
some invalid line
diff --git a/main.c b/main.c
@@ -59,7 +59,7 @@ int nlistfds = 0;
char *argv0;
char stdbase[] = "/var/gopher";
char *stdport = "70";
-char *indexf[] = {"/index.gph", "/index.cgi", "/index.dcgi", "/index.bob", "/index.bin"};
+char *indexf[] = {"index.gph", "index.cgi", "index.dcgi", "index.bob", "index.bin"};
char *nocgierr = "3Sorry, execution of the token '%s' was requested, but this "
"is disabled in the server configuration.\tErr"
"\tlocalhost\t70\r\n";
@@ -83,7 +83,7 @@ char *htredir = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
" </body>\n"
"</html>\n";
char *selinval ="3Happy helping ☃ here: "
- "Sorry, your selector does not start with / or contains '..'. "
+ "Sorry, your selector does contains '..'. "
"That's illegal here.\tErr\tlocalhost\t70\r\n.\r\n\r\n";
int
@@ -142,12 +142,20 @@ handlerequest(int sock, char *req, int rlen, char *base, char *ohost,
int len = 0, fd, i, maxrecv, pathfallthrough = 0;
filetype *type;
+ printf("handlerequest:\n");
+ printf("sock = %d; req = '%s';\n", sock, req);
+ printf("rlen = %d; base = '%s'; ohost = '%s'; port = %s;\n", rlen,
+ base, ohost, port);
+ printf("clienth = %s; clientp = %s; serverh = %s; serverp = %s;\n",
+ clienth, clientp, serverh, serverp);
+ printf("nocgi = %d; istls = %d;\n", nocgi, istls);
+
if (!istls) {
/*
* If sticky bit is set on base dir and encryption is not
* used, do not serve.
*/
- if (stat(base, &dir) == -1)
+ if (stat(*base? base : "/", &dir) == -1)
return;
if (dir.st_mode & S_ISVTX) {
dprintf(sock, tlserr, recvc);
@@ -176,6 +184,7 @@ handlerequest(int sock, char *req, int rlen, char *base, char *ohost,
c = strchr(recvb, '\n');
if (c)
c[0] = '\0';
+
sear = strchr(recvb, '\t');
if (sear != NULL) {
*sear++ = '\0';
@@ -228,29 +237,32 @@ handlerequest(int sock, char *req, int rlen, char *base, char *ohost,
* selectors.
*/
+ /* Strip off the arguments of req?args style. */
c = strchr(recvb, '?');
if (c != NULL) {
*c++ = '\0';
- snprintf(args, sizeof(args), "%s", c);
+ snprintf(args, sizeof(args), "?%s", c);
}
+ printf("args = %s\n", args);
+ printf("recvb = %s\n", recvb);
- if (recvb[0] == '\0') {
- recvb[0] = '/';
- recvb[1] = '\0';
+ /* Strip '/' at the end of the request. */
+ for (c = recvb + strlen(recvb) - 1; c >= recvb && c[0] == '/'; c--) {
+ /* Prepend to args. */
+ snprintf(args, sizeof(args), "/%s", args);
+ c[0] = '\0';
}
+ printf("args = %s\n", args);
- /*
- * Do not allow requests not beginning with '/' or which contain
- * "..".
- */
- if (recvb[0] != '/' || strstr(recvb, "..")){
+ /* Do not allow requests including "..". */
+ if (strstr(recvb, "..")) {
dprintf(sock, "%s", selinval);
return;
}
- /* append base to request path (always starting with /), if base is a chroot don't append '/' */
- if (snprintf(path, sizeof(path), "%s%s",
- base[0] == '/' && base[1] == '\0' ? "" : base,
+ printf("recvb = %s\n", recvb);
+ if (snprintf(path, sizeof(path), "%s%s%s", base,
+ (*recvb != '/')? "/" : "",
recvb) > sizeof(path)) {
if (loglvl & ERRORS) {
logentry(clienth, clientp, recvc,
@@ -259,6 +271,8 @@ handlerequest(int sock, char *req, int rlen, char *base, char *ohost,
dprintf(sock, toolongerr, recvc);
return;
}
+ /* path is now always at least '/' */
+ printf("path = %s\n", path);
fd = -1;
/*
@@ -270,33 +284,54 @@ handlerequest(int sock, char *req, int rlen, char *base, char *ohost,
* $args = $rest_of_path + "?" + $args
*/
if (stat(path, &dir) == -1) {
+ printf("Not found. Try backtraversal.\n");
memmove(argsc, args, strlen(args));
snprintf(path, sizeof(path), "%s", base);
- recvbp = recvb + 1;
+ recvbp = recvb;
+
+ /*
+ * Walk into the selector until some directory or file
+ * does not exist. Then reconstruct the args, selector
+ * etc.
+ */
while (recvbp != NULL) {
- sep = strsep(&recvbp, "/");
+ /* Traverse multiple / in selector. */
+ for (sep = recvbp; sep != recvbp && sep != recvbp+1;
+ sep = strsep(&recvbp, "/"));
+ printf("traversal directory = %s\n", sep);
+
+ /* Append found directory to path. */
snprintf(path+strlen(path), sizeof(path)-strlen(path),
"/%s", sep);
+ /* path is now always at least '/' */
+ printf("full traversal path = %s\n", path);
+
if (stat(path, &dir) == -1) {
+ /*
+ * Current try was not found. Go back one
+ * step and finish.
+ */
c = strrchr(path, '/');
if (c != NULL) {
*c++ = '\0';
snprintf(args, sizeof(args),
- "/%s%s%s%s%s",
+ "/%s%s%s%s",
c,
(recvbp != NULL)? "/" : "",
(recvbp != NULL)? recvbp : "",
- (argsc[0] != '\0')? "?" : "",
(argsc[0] != '\0')? argsc : ""
);
+ printf("args = %s\n", args);
}
/* path fallthrough */
pathfallthrough = 1;
+ printf("pathfallthrough = 1\n");
break;
}
}
}
+ printf("path = %s\n", path);
if (stat(path, &dir) != -1) {
/*
* If sticky bit is set, only serve if this is encrypted.
@@ -311,9 +346,11 @@ handlerequest(int sock, char *req, int rlen, char *base, char *ohost,
}
if (S_ISDIR(dir.st_mode)) {
+ printf("S_ISDIR\n");
for (i = 0; i < sizeof(indexf)/sizeof(indexf[0]);
i++) {
- if (strlen(path) + strlen(indexf[i])
+ len = strlen(path);
+ if (len + strlen(indexf[i]) + (path[len-1] == '/')? 0 : 1
>= sizeof(path)) {
if (loglvl & ERRORS) {
logentry(clienth, clientp,
@@ -322,12 +359,18 @@ handlerequest(int sock, char *req, int rlen, char *base, char *ohost,
}
return;
}
- strncat(path, indexf[i],
- sizeof(path)-strlen(path)-1);
+ sprintf(path, "%s%s%s",
+ path,
+ (path[len-1] == '/')? "" : "/",
+ indexf[i]);
+ printf("path index = %s\n", path);
fd = open(path, O_RDONLY);
if (fd >= 0)
break;
- path[strlen(path)-strlen(indexf[i])] = '\0';
+
+ /* Not found. Clear path from indexf. */
+ printf("len = %d\n", len);
+ path[len] = '\0';
}
} else {
fd = open(path, O_RDONLY);
@@ -342,10 +385,9 @@ handlerequest(int sock, char *req, int rlen, char *base, char *ohost,
}
}
+ /* Some file was opened. Serve it. */
if (fd >= 0) {
close(fd);
- if (loglvl & FILES)
- logentry(clienth, clientp, recvc, "serving");
c = strrchr(path, '/');
if (c == NULL)
@@ -359,8 +401,10 @@ handlerequest(int sock, char *req, int rlen, char *base, char *ohost,
if (pathfallthrough &&
!(type->f == handledcgi || type->f == handlecgi)) {
dprintf(sock, notfounderr, recvc);
- if (loglvl & ERRORS)
- logentry(clienth, clientp, recvc, "not found");
+ if (loglvl & ERRORS) {
+ logentry(clienth, clientp, recvc,
+ "handler in path fallthrough not allowed");
+ }
return;
}
@@ -369,14 +413,21 @@ handlerequest(int sock, char *req, int rlen, char *base, char *ohost,
if (loglvl & ERRORS)
logentry(clienth, clientp, recvc, "nocgi error");
} else {
+ if (loglvl & FILES)
+ logentry(clienth, clientp, recvc, "serving");
+
type->f(sock, path, port, base, args, sear, ohost,
clienth, serverh, istls);
}
} else {
- /*
- * If we had to traverse the path, do not allow directory
- * listings, only dynamic content.
- */
+ if (pathfallthrough && S_ISDIR(dir.st_mode)) {
+ if (loglvl & ERRORS) {
+ logentry(clienth, clientp, recvc,
+ "directory listing in traversal not allowed");
+ }
+ return;
+ }
+
if (!pathfallthrough && S_ISDIR(dir.st_mode)) {
handledir(sock, path, port, base, args, sear, ohost,
clienth, serverh, istls);
@@ -791,7 +842,7 @@ main(int argc, char *argv[])
perror("chdir");
return 1;
}
- base = "/";
+ base = "";
if (chroot(".") < 0) {
perror("chroot");
return 1;
@@ -801,9 +852,9 @@ main(int argc, char *argv[])
return 1;
}
- /* strip / at the end, except if it is "/" */
- for (p = base + strlen(base); p > base + 1 && p[-1] == '/'; --p)
- p[-1] = '\0';
+ /* strip / at the end of base */
+ for (p = base + strlen(base) - 1; p >= base && p[0] == '/'; --p)
+ p[0] = '\0';
if (dropprivileges(gr, us) < 0) {
perror("dropprivileges");
@@ -1063,21 +1114,32 @@ read_selector_again:
close(tlssocks[tlsclientreader? 1 : 0]);
do {
if (tlsclientreader) {
- shuflen = read(tlssocks[0], shufbuf, sizeof(shufbuf)-1);
+ shuflen = read(tlssocks[0],
+ shufbuf,
+ sizeof(shufbuf)-1);
} else {
- shuflen = tls_read(tlsclientctx, shufbuf, sizeof(shufbuf)-1);
+ shuflen = tls_read(tlsclientctx,
+ shufbuf,
+ sizeof(shufbuf)-1);
}
if (shuflen == -1 && errno == EINTR)
continue;
- for (shufpos = 0; shufpos < shuflen; shufpos += wlen) {
+ for (shufpos = 0; shufpos < shuflen;
+ shufpos += wlen) {
if (tlsclientreader) {
- wlen = tls_write(tlsclientctx, shufbuf+shufpos, shuflen-shufpos);
+ wlen = tls_write(tlsclientctx,
+ shufbuf+shufpos,
+ shuflen-shufpos);
if (wlen < 0) {
- fprintf(stderr, "tls_write failed: %s\n", tls_error(tlsclientctx));
+ fprintf(stderr,
+ "tls_write failed: %s\n",
+ tls_error(tlsclientctx));
return 1;
}
} else {
- wlen = write(tlssocks[1], shufbuf+shufpos, shuflen-shufpos);
+ wlen = write(tlssocks[1],
+ shufbuf+shufpos,
+ shuflen-shufpos);
if (wlen < 0) {
perror("write");
return 1;