From 18e2662b50615c60e6c1ef0966569745fa111683 Mon Sep 17 00:00:00 2001 From: Neale Pickett Date: Wed, 15 Feb 2012 16:19:02 -0700 Subject: [PATCH] Gut compile-time options, add command-line options --- Makefile | 12 +- fnord.c | 371 +++++++++++++++++-------------------------------------- 2 files changed, 117 insertions(+), 266 deletions(-) diff --git a/Makefile b/Makefile index 842fc68..fb809c0 100644 --- a/Makefile +++ b/Makefile @@ -2,15 +2,7 @@ VERSION := $(shell head -n 1 CHANGES | tr -d :) CFLAGS = -DFNORD='"fnord/$(VERSION)"' -Wall -Werror -all: fnord fnord-cgi fnord-idx - -fnord-cgi: CFLAGS += -DCGI -fnord-cgi: fnord.c - $(CC) $(CFLAGS) -o $@ $(LDFLAGS) $< - -fnord-idx: CFLAGS += -DDIR_LIST -fnord-idx: fnord.c - $(CC) $(CFLAGS) -o $@ $(LDFLAGS) $< +all: fnord clean: - rm -f *.[oa] fnord fnord-cgi fnord-idx + rm -f *.[oa] fnord diff --git a/fnord.c b/fnord.c index 9272ac4..04481e2 100644 --- a/fnord.c +++ b/fnord.c @@ -39,77 +39,6 @@ #define DUMP_c(v) DUMPf("%s = %c", #v, v) #define DUMP_p(v) DUMPf("%s = %p", #v, v) -/* - * uncomment the following line to enable support for CGI - */ -// #define CGI - -#ifdef CGI -/* - * uncomment the following line to enable support for "index.cgi" That is: - * if "index.html" is not present then look for "index.cgi" - */ -#define INDEX_CGI -#endif - -/* - * the following switch will make fnord normalize the Host: HTTP header - * from "foo" to "foo:80" - */ -#define NORMALIZE_HOST - -/* - * uncomment the following line to enable support for autogenerated - * directory-listings for directories without index - */ -/* - * #define DIR_LIST - */ - -#ifdef DIR_LIST -/* - * uncomment the following line to enable support for system symlink - * dereferencingr. HOPE YOU KNOW WHAT YOU'RE LINKING ! e.g.: if a file - * foo is a symlink to /etc/passwd and you don't have a chroot enviroment - * then the system-wide /etc/passwd is provided !!! If the symlink is - * dangling OR this option is not active the symlink is provided as a new - * http-uri. e.g.: is foo a symlink to /etc/passwd than the clinet gets a - * href to http:///etc/passwd - */ -/* - * #define SYSTEM_SYMLINK_DEREF - */ -#endif - -/* - * uncomment the following line to get full-host redirection. If a file is - * not found locally, and $REDIRECT_HOST is set, fnord will issue a - * redirect to strcat($REDIRECT_HOST,uri). Otherwise, if $REDIRECT_URI is - * set, fnord will issue a redirect to $REDIRECT_URI. Only if those fail - * will a 404 error be returned. - */ -#define OLD_STYLE_REDIRECT - -/* - * uncomment the following line to get full-host redirection. if the - * virtual host directory/symlink is a broken symlink, fnord will issue a - * redirect. If the contents of the symlink starts with an equal sign - * ('='), fnord will throw away the URI part. - */ -#define REDIRECT - -/* - * uncomment the following line to make fnord chroot to the current - * working directory and drop privileges - */ -#define CHROOT - -/* - * uncomment the following line to make fnord support connection - * keep-alive - */ -#define KEEPALIVE - /* * the following is the time in seconds that fnord should wait for a valid * HTTP request @@ -165,12 +94,9 @@ char *ua = "?"; /* user-agent */ char *refer; /* Referrer: header */ char *accept_enc; /* Accept-Encoding */ int httpversion; /* 0 == 1.0, 1 == 1.1 */ -#ifdef KEEPALIVE int keepalive = 0; /* should we keep the connection alive? */ int rootdir; /* fd of root directory, so we can fchdir * * back for keep-alive */ -#endif -#ifdef CGI char *cookie; /* Referrer: header */ char *uri; /* copy of url before demangling */ char *content_type; @@ -179,7 +105,6 @@ char *auth_type; char *post_miss; unsigned long post_mlen; unsigned long post_len = 0; -#endif #if _FILE_OFFSET_BITS == 64 static unsigned long long rangestart, @@ -197,17 +122,16 @@ static const char months[] = "JanFebMarAprMayJunJulAugSepOctNovDec"; #define MAXHEADERLEN 8192 char *remote_ip; -#ifdef CGI char *remote_port; char *remote_ident; -#endif static void sanitize(char *ua) { /* replace strings with underscores for * * logging */ int j; - if (! ua) return; + if (!ua) + return; for (j = 0; ua[j]; ++j) if (isspace(ua[j])) ua[j] = '_'; @@ -222,7 +146,7 @@ dolog(off_t len) fprintf(stderr, "%s %ld %lu %s %s %s %s\n", remote_ip ? remote_ip : "0.0.0.0", - retcode, (unsigned long)len, host, ua, refer, url); + retcode, (unsigned long) len, host, ua, refer, url); } /* @@ -245,7 +169,6 @@ badrequest(long code, const char *httpcomment, const char *message) exit(0); } -#ifdef CGI #define CGIENVLEN 21 static const char *cgivars[CGIENVLEN] = { @@ -275,11 +198,11 @@ static const char *cgivars[CGIENVLEN] = { static int iscgivar(const char *s) { - int sl = strlen(s); + int sl = strlen(s); register unsigned int i = 0; for (; i < CGIENVLEN; i++) - if (! strncmp(s, cgivars[i], sl)) + if (!strncmp(s, cgivars[i], sl)) return 1; return 0; } @@ -293,14 +216,14 @@ elen(register const char *const *e) return i; } -char * +char * env_append(const char *key, const char *val) { - static char buf[MAXHEADERLEN * 2 + PATH_MAX + 200]; - static char *p = buf; - char *ret = p; + static char buf[MAXHEADERLEN * 2 + PATH_MAX + 200]; + static char *p = buf; + char *ret = p; - if (! key) { + if (!key) { p = buf; return NULL; } @@ -337,24 +260,35 @@ do_cgi(const char *pathinfo, const char *const *envp) cgi_env[i++] = env_append("REQUEST_METHOD", method_name[method]); cgi_env[i++] = env_append("REQUEST_URI", uri); cgi_env[i++] = env_append("SCRIPT_NAME", url); - if (remote_ip) cgi_env[i++] = env_append("REMOTE_ADDR", remote_ip); - if (remote_port) cgi_env[i++] = env_append("REMOTE_PORT", remote_port); - if (remote_ident) cgi_env[i++] = env_append("REMOTE_IDENT", remote_ident); - if (ua) cgi_env[i++] = env_append("HTTP_USER_AGENT", ua); - if (cookie) cgi_env[i++] = env_append("HTTP_COOKIE", cookie); - if (refer) cgi_env[i++] = env_append("HTTP_REFERER", refer); - if (accept_enc) cgi_env[i++] = env_append("HTTP_ACCEPT_ENCODING", accept_enc); - if (auth_type) cgi_env[i++] = env_append("AUTH_TYPE", auth_type); - if (content_type) cgi_env[i++] = env_append("CONTENT_TYPE", content_type); - if (content_type) cgi_env[i++] = env_append("CONTENT_LENGTH", content_len); - if (args) cgi_env[i++] = env_append("QUERY_STRING", args); + if (remote_ip) + cgi_env[i++] = env_append("REMOTE_ADDR", remote_ip); + if (remote_port) + cgi_env[i++] = env_append("REMOTE_PORT", remote_port); + if (remote_ident) + cgi_env[i++] = env_append("REMOTE_IDENT", remote_ident); + if (ua) + cgi_env[i++] = env_append("HTTP_USER_AGENT", ua); + if (cookie) + cgi_env[i++] = env_append("HTTP_COOKIE", cookie); + if (refer) + cgi_env[i++] = env_append("HTTP_REFERER", refer); + if (accept_enc) + cgi_env[i++] = env_append("HTTP_ACCEPT_ENCODING", accept_enc); + if (auth_type) + cgi_env[i++] = env_append("AUTH_TYPE", auth_type); + if (content_type) + cgi_env[i++] = env_append("CONTENT_TYPE", content_type); + if (content_type) + cgi_env[i++] = env_append("CONTENT_LENGTH", content_len); + if (args) + cgi_env[i++] = env_append("QUERY_STRING", args); if (pathinfo) { - char *rp = realpath(pathinfo, NULL); + char *rp = realpath(pathinfo, NULL); cgi_env[i++] = env_append("PATH_INFO", pathinfo); - if (! rp) rp = pathinfo; - cgi_env[i++] = env_append("PATH_TRANSLATED", rp); - if (rp != pathinfo) free(rp); + cgi_env[i++] = env_append("PATH_TRANSLATED", rp ? rp : pathinfo); + if (rp) + free(rp); } { @@ -389,7 +323,7 @@ do_cgi(const char *pathinfo, const char *const *envp) } { - char tmp[PATH_MAX]; + char tmp[PATH_MAX]; i = strrchr(url, '/') - url; strncpy(tmp, url + 1, i); @@ -397,8 +331,8 @@ do_cgi(const char *pathinfo, const char *const *envp) chdir(tmp); } - { - char tmp[PATH_MAX]; + { + char tmp[PATH_MAX]; /* * program name @@ -411,7 +345,7 @@ do_cgi(const char *pathinfo, const char *const *envp) * start cgi */ execve(cgi_arg[0], cgi_arg, cgi_env); - raise(SIGQUIT); /* gateway unavailable. */ + raise(SIGQUIT); /* gateway unavailable. */ } } @@ -604,7 +538,6 @@ start_cgi(int nph, const char *pathinfo, const char *const *envp) } exit(0); } -#endif static int fromhex(int c) @@ -629,9 +562,7 @@ header(char *buf, int buflen, const char *hname) int i; char *c; - DUMPf("buflen %d, slen %d", buflen, slen); for (i = 0; i < buflen - slen - 2; ++i) { - DUMPf("[%.*s] [%s]", slen, buf + i, hname); if (!strncasecmp(buf + i, hname, slen)) { if (i && (buf[i - 1] && buf[i - 1] != '\n')) continue; @@ -1083,9 +1014,7 @@ handleredirect(const char *url, const char *origurl) { char symlink[1024]; int len; -#ifdef OLD_STYLE_REDIRECT - char *env; -#endif + while (*url == '/') ++url; if ((len = readlink(url, symlink, 1023)) > 0) { @@ -1094,32 +1023,14 @@ handleredirect(const char *url, const char *origurl) */ redirectboilerplate(); printf("%.*s", len, symlink); -#ifdef OLD_STYLE_REDIRECT - fini: -#endif retcode = 301; printf("\r\n\r\n"); dolog(0); fflush(stdout); exit(0); } -#ifdef OLD_STYLE_REDIRECT - if ((env = getenv("REDIRECT_HOST"))) { - redirectboilerplate(); - fputs(env, stdout); - while (*origurl == '/') - ++origurl; - fputs(origurl, stdout); - goto fini; - } else if ((env = getenv("REDIRECT_URI"))) { - redirectboilerplate(); - fputs(env, stdout); - goto fini; - } -#endif } -#ifdef DIR_LIST static void hdl_encode_html(const char *s, unsigned int sl) { @@ -1127,8 +1038,7 @@ hdl_encode_html(const char *s, unsigned int sl) for (i = 0; i < sl; ++i) { unsigned char ch = s[i]; if (ch > 159) { - encode_dec: - printf("&#%lu;", ch); + printf("&#%u;", ch); } else if ((ch > 128) || (ch < 32)) { putchar('_'); } else if (ch == '"') @@ -1173,12 +1083,12 @@ handledirlist(const char *origurl) && ((st.st_mode & S_IRWXO) == 5)) { if (nl) chdir(nurl); - if (dir = opendir(".")) { + if ((dir = opendir("."))) { struct dirent *de; unsigned int i, size = 32 + nl; fputs("HTTP/1.0 200 OK\r\nServer: " FNORD - "\r\nConnection: close\r\n", stdout); + "\r\nConnection: close\r\n", stdout); fputs("Content-Type: text/html\r\n", stdout); fputs("\r\n

Directory Listing: /", stdout); hdl_encode_html(nurl, nl); @@ -1196,7 +1106,7 @@ handledirlist(const char *origurl) fputs("\n", stdout); size += 40 + i; } - while (de = readdir(dir)) { + while ((de = readdir(dir))) { char symlink[1024]; char *p = de->d_name; unsigned int pl, @@ -1209,14 +1119,9 @@ handledirlist(const char *origurl) if (S_ISDIR(st.st_mode)) fputs("[DIR] ", stdout); else if (S_ISLNK(st.st_mode)) { -#ifdef SYSTEM_SYMLINK_DEREF - if (stat(de->d_name, &st)) /* dangling symlink */ -#endif - { - if ((pl = readlink(de->d_name, symlink, 1023)) < 1) - continue; - p = symlink; - } + if ((pl = readlink(de->d_name, symlink, 1023)) < 1) + continue; + p = symlink; fputs("[LNK] ", stdout); /* a symlink to * * something ... */ } else if (S_ISREG(st.st_mode)) @@ -1246,9 +1151,7 @@ handledirlist(const char *origurl) } } } -#endif -#ifdef INDEX_CGI static int handleindexcgi(const char *testurl, const char *origurl, char *space) { @@ -1263,7 +1166,7 @@ handleindexcgi(const char *testurl, const char *origurl, char *space) test = space; ++test; ul -= 4; - byte_copy(test, ul, testurl); + memcpy(test, testurl, ul); test[ul] = 'c'; test[++ul] = 'g'; test[++ul] = 'i'; @@ -1281,39 +1184,34 @@ handleindexcgi(const char *testurl, const char *origurl, char *space) url = test; return 1; /* Wow... now start "index.cgi" */ } -#endif static void get_ucspi_env(void) { char *ucspi = getenv("PROTO"); if (ucspi) { - int protolen = strlen(ucspi); - char *buf = alloca(protolen + 20); + int protolen = strlen(ucspi); + char *buf = alloca(protolen + 20); strcpy(buf, ucspi); - + strcpy(buf + protolen, "REMOTEIP"); remote_ip = getenv(buf); -#ifdef CGI strcpy(buf + protolen, "REMOTEPORT"); remote_port = getenv(buf); strcpy(buf + protolen, "REMOTEINFO"); remote_ident = getenv(buf); -#endif } } -#ifdef CGI static int findcgi(const char *c) { return (c[0] == '.' && c[1] == 'c' && c[2] == 'g' && c[3] == 'i' && (c[4] == '/' || c[4] == 0)); } -#endif static int serve_read_write(int fd) @@ -1500,60 +1398,40 @@ int main(int argc, char *argv[], const char *const *envp) { char buf[MAXHEADERLEN]; -#if 0 - char buf2[MAXHEADERLEN]; -#endif char *nurl, *origurl; + int docgi = 0; + int dirlist = 0; + int redirect = 0; int len; int in; - if (argc > 1) - chdir(argv[1]); + { + int opt; -#ifdef CHROOT - if (chroot(".")) { - if (errno != EPERM) - goto error500; - /* - * else fnord was called with uid!=0, i.e. it already is chroot - */ - } else { - char *tmp; - if (chdir("/")) - goto error500; - if ((tmp = getenv("GID"))) { - long gid; - char *endptr; - - gid = strtoul(tmp, &endptr, 0); - if (*endptr == 0) { - gid_t gi = gid; - if (setgroups(1, &gi)) - goto error500; - } else - goto error500; - } - if ((tmp = getenv("UID"))) { - long uid; - char *endptr; - - uid = strtoul(tmp, &endptr, 0); - if (*endptr == 0) { - if (setuid(uid)) - goto error500; - } else - goto error500; + while (-1 != (opt = getopt(argc, argv, "cdr"))) { + switch (opt) { + case 'c': + docgi = 1; + break; + case 'd': + dirlist = 1; + break; + case 'r': + redirect = 1; + break; + default: + fprintf(stderr, "%d Usage: %s [-d] [-r]\n", opt, argv[0]); + return 69; + } } } -#endif + signal(SIGPIPE, SIG_IGN); get_ucspi_env(); -#ifdef KEEPALIVE handlenext: encoding = 0; -#endif // alarm(20); { @@ -1572,7 +1450,8 @@ main(int argc, char *argv[], const char *const *envp) if (time(&now) < fini) continue; /* fall through */ case -1: /* timeout or error */ - // badrequest(408,"Request Time-out","No request appeared + // badrequest(408,"Request Time-out","No request + // appeared // within a reasonable time period."); return 1; } @@ -1626,9 +1505,7 @@ main(int argc, char *argv[], const char *const *envp) "Bad RequestOnly HTTP 1.x supported"); *space = 0; httpversion = space[8] - '0'; -#ifdef KEEPALIVE keepalive = 0; -#endif /* * demangle path in-place @@ -1670,10 +1547,7 @@ main(int argc, char *argv[], const char *const *envp) */ } -#ifdef CGI - uri = alloca(space + 1); - byte_copy(uri, space + 1, url); -#endif + uri = strdup(url); } { @@ -1681,31 +1555,27 @@ main(int argc, char *argv[], const char *const *envp) ua = header(buf, len, "User-Agent"); refer = header(buf, len, "Referer"); accept_enc = header(buf, len, "Accept-Encoding"); -#ifdef KEEPALIVE if ((tmp = header(buf, len, "Connection"))) { /* see if it's - * "keep-alive" or - * * "close" */ + * "keep-alive" + * or * "close" */ if (!strcasecmp(tmp, "keep-alive")) keepalive = 1; else if (!strcasecmp(tmp, "close")) keepalive = -1; } -#endif -#ifdef CGI cookie = header(buf, len, "Cookie"); auth_type = header(buf, len, "Authorization"); if (method == POST) { content_type = header(buf, len, "Content-Type"); content_len = header(buf, len, "Content-Length"); if (content_len) { - scan_ulong(content_len, &post_len); + post_len = strtoul(content_len, NULL, 10); post_miss = buf + len + 1; post_mlen = in - len - 1; if (post_len <= post_mlen) post_mlen = post_len; } } -#endif } port = getenv("TCPLOCALPORT"); @@ -1728,14 +1598,12 @@ main(int argc, char *argv[], const char *const *envp) exit(101); sprintf(Buf, "%s:%s", ip, port); host = Buf; -#ifdef NORMALIZE_HOST } else { char *colon = strchr(host, ':'); - if (*colon == 0) { + if (!colon) { sprintf(Buf, "%s:%s", host, port); host = Buf; } -#endif } for (i = strlen(host); i >= 0; --i) if ((host[i] = tolower(host[i])) == '/') @@ -1745,36 +1613,35 @@ main(int argc, char *argv[], const char *const *envp) if (host[0] == '.') goto hostb0rken; // fprintf(stderr,"host %s\n",host); -#ifdef KEEPALIVE if (keepalive > 0) { if ((rootdir = open(".", O_RDONLY)) < 0) keepalive = -1; } -#endif if (chdir(host)) { -#ifdef REDIRECT - char symlink[1024]; - int linklen; - if ((linklen = readlink(host, symlink, sizeof symlink)) > 0) { - /* - * it is a broken symlink. Do a redirection - */ - redirectboilerplate(); - if (symlink[0] == '=') { - fwrite(symlink + 1, linklen - 1, 1, stdout); - } else { - fwrite(symlink, linklen, 1, stdout); - while (url[0] == '/') - ++url; - fputs(url, stdout); + if (redirect) { + char symlink[1024]; + int linklen; + if ((linklen = + readlink(host, symlink, sizeof symlink)) > 0) { + /* + * it is a broken symlink. Do a redirection + */ + redirectboilerplate(); + if (symlink[0] == '=') { + fwrite(symlink + 1, linklen - 1, 1, stdout); + } else { + fwrite(symlink, linklen, 1, stdout); + while (url[0] == '/') + ++url; + fputs(url, stdout); + } + retcode = 301; + fputs("\r\n\r\n", stdout); + dolog(0); + fflush(stdout); + exit(0); } - retcode = 301; - fputs("\r\n\r\n", stdout); - dolog(0); - fflush(stdout); - exit(0); } -#endif if (chdir("default") && argc < 2) { badrequest(404, "Not Found", "Not FoundThis host is not served here."); @@ -1815,11 +1682,11 @@ main(int argc, char *argv[], const char *const *envp) retcode = 401; dolog(0); fputs("HTTP/1.0 401 Authorization Required\r\n" - "WWW-Authenticate: Basic realm=\"", stdout); + "WWW-Authenticate: Basic realm=\"", stdout); fputs(host, stdout); fputs("\"\r\nConnection: close\r\n\r\n" - "Access to this site is restricted.\r\n" - "Please provide credentials.\r\n", stdout); + "Access to this site is restricted.\r\n" + "Please provide credentials.\r\n", stdout); fflush(stdout); exit(0); } @@ -1837,9 +1704,9 @@ main(int argc, char *argv[], const char *const *envp) url = nurl; nurl = url + i; } -#ifdef CGI nurl -= 3; - { + + if (docgi) { char *tmp, *pathinfo; pathinfo = 0; @@ -1876,13 +1743,10 @@ main(int argc, char *argv[], const char *const *envp) */ --nurl; } -#ifdef INDEX_CGI indexcgi: -#endif start_cgi(0, pathinfo, envp); /* start a CGI */ } } -#endif { int fd; @@ -1922,7 +1786,6 @@ main(int argc, char *argv[], const char *const *envp) fputs("Server: " FNORD "\r\nContent-Type: ", stdout); fputs(mimetype, stdout); fputs("\r\n", stdout); -#ifdef KEEPALIVE switch (keepalive) { case -1: fputs("Connection: close\r\n", stdout); @@ -1931,11 +1794,11 @@ main(int argc, char *argv[], const char *const *envp) fputs("Connection: Keep-Alive\r\n", stdout); break; } -#endif if (encoding) { printf("Content-Encoding: %s\r\n", encoding); } - printf("Content-Length: %llu\r\n", (unsigned long long)(rangeend - rangestart)); + printf("Content-Length: %llu\r\n", + (unsigned long long) (rangeend - rangestart)); printf("Last-Modified: "); { struct tm *x = gmtime(&st.st_mtime); @@ -1952,9 +1815,9 @@ main(int argc, char *argv[], const char *const *envp) if (rangestart || rangeend != st.st_size) { printf ("Accept-Ranges: bytes\r\nContent-Range: bytes %llu-%llu/%llu\r\n", - (unsigned long long)rangestart, - (unsigned long long)rangeend - 1, - (unsigned long long)st.st_size); + (unsigned long long) rangestart, + (unsigned long long) rangeend - 1, + (unsigned long long) st.st_size); } fputs("\r\n", stdout); if (method == GET || method == POST) { @@ -1966,7 +1829,6 @@ main(int argc, char *argv[], const char *const *envp) case 1: return 1; } -#ifdef KEEPALIVE #ifdef TCP_CORK if (corked) { int zero = 0; @@ -1980,7 +1842,6 @@ main(int argc, char *argv[], const char *const *envp) close(rootdir); goto handlenext; } -#endif exit(0); error500: retcode = 500; @@ -1991,16 +1852,14 @@ main(int argc, char *argv[], const char *const *envp) switch (retcode) { case 404: { -#ifdef INDEX_CGI char *space = alloca(strlen(url) + 2); if (handleindexcgi(url, origurl, space)) goto indexcgi; -#endif handleredirect(url, origurl); -#ifdef DIR_LIST - handledirlist(origurl); -#endif + if (dirlist) { + handledirlist(origurl); + } badrequest(404, "Not Found", "Not FoundNo such file or directory."); }