#include %s
\n", title);
hprint(hout, "%s\n", buf);
hprint(hout, "\n");
hprint(hout, "\n");
hflush(hout);
writelog(connect, "Reply: 404\nReason: %s\n", title);
exits(nil);
}
/*
* Are we actually allowed to look in here?
*
* Rules:
* 1) If neither allowed nor denied files exist, access is granted.
* 2) If allowed exists and denied does not, dir *must* be in allowed
* for access to be granted, otherwise, access is denied.
* 3) If denied exists and allowed does not, dir *must not* be in
* denied for access to be granted, otherwise, access is enied.
* 4) If both exist, okay if either (a) file is not in denied, or
* (b) in denied and in allowed. Otherwise, access is denied.
*/
static int
allowed(char *dir)
{
char *p, *t;
Reprog *re;
int okay;
Resub match;
Biobuf aio, dio;
if (okfd < 0 && notokfd < 0)
return(1);
Binit(&aio, okfd, OREAD);
Binit(&dio, notokfd, OREAD);
okay = !(notokfd < 0);
while (okay && (p = Brdstr(&dio, '\n', 0)) != nil) {
t = strchr(p, '#');
if (t != nil)
*t = '\0';
t = p + strlen(p);
while(--t > p && isspace(*t))
*t = '\0';
if (strlen(p) == 0) {
free(p);
continue;
}
re = regcomp(p);
if (re == nil) {
free(p);
continue;
}
if (regexec(re, dir, &match, 1) == 1)
okay = 0;
free(re);
free(p);
}
if (okfd < 0)
return(okay);
while (!okay && (p = Brdstr(&aio, '\n', 0)) != nil) {
t = strchr(p, '#');
if (t != nil)
*t = '\0';
t = p + strlen(p);
while(--t > p && isspace(*t))
*t = '\0';
if (strlen(p) == 0) {
free(p);
continue;
}
re = regcomp(p);
if (re == nil) {
free(p);
continue;
}
if (regexec(re, dir, &match, 1))
okay = 1;
free(re);
free(p);
}
return(okay);
}
/*
* Comparison routine for sorting the directory.
*/
static int
compar(Dir *a, Dir *b)
{
return(strcmp(a->name, b->name));
}
/*
* These is for formating; how wide are variable-length
* fields?
*/
static void
maxwidths(Dir *dp, long n)
{
long i;
char scratch[64];
for (i = 0; i < n; i++) {
if (snprint(scratch, sizeof scratch, "%ud", dp[i].dev) > devwidth)
devwidth = strlen(scratch);
if (strlen(dp[i].uid) > uidwidth)
uidwidth = strlen(dp[i].uid);
if (strlen(dp[i].gid) > gidwidth)
gidwidth = strlen(dp[i].gid);
if (snprint(scratch, sizeof scratch, "%lld", dp[i].length) > lenwidth)
lenwidth = strlen(scratch);
}
}
/*
* Do an actual directory listing.
* asciitime is lifted directly out of ls.
*/
char *
asciitime(long l)
{
ulong clk;
static char buf[32];
char *t;
clk = time(nil);
t = ctime(l);
/* 6 months in the past or a day in the future */
if(l
\n"); for (i = 0; i < n; i++) { f = smprint("%s/%s", dir, d[i].name); cleanname(f); if (d[i].mode & DMDIR) { p = smprint("/magic/webls?dir=%H", f); free(f); f = p; } hprint(hout, "%M %C %*ud %-*s %-*s %*lld %s %s\n", d[i].mode, d[i].type, devwidth, d[i].dev, uidwidth, d[i].uid, gidwidth, d[i].gid, lenwidth, d[i].length, asciitime(d[i].mtime), f, d[i].name); free(f); } f = smprint("%s/..", dir); cleanname(f); hprint(hout, "\nGo to parent directory\n", f); free(f); hprint(hout, "\n\n\n"); hflush(hout); free(d); } /* * Handle unpacking the request in the URI and * invoking the actual handler. */ static void dosearch(char *search) { if (strncmp(search, "dir=", 4) == 0){ search = hurlunesc(connect, search+4); dols(search); return; } /* * Otherwise, we've gotten an illegal request. * spit out a non-apologetic error. */ search = hurlunesc(connect, search); error("Bad directory listing request", "
Illegal formatted directory listing request:
\n" "%H
\n", search); } void main(int argc, char **argv) { fmtinstall('H', httpfmt); fmtinstall('U', hurlfmt); fmtinstall('M', dirmodefmt); if(argc == 2){ hinit(&houtb, 1, Hwrite); hout = &houtb; dols(argv[1]); exits(nil); } close(2); connect = init(argc, argv); hout = &connect->hout; vermaj = connect->req.vermaj; if(hparseheaders(connect, HSTIMEOUT) < 0) exits("failed"); if(strcmp(connect->req.meth, "GET") != 0 && strcmp(connect->req.meth, "HEAD") != 0){ hunallowed(connect, "GET, HEAD"); exits("not allowed"); } if(connect->head.expectother || connect->head.expectcont){ hfail(connect, HExpectFail, nil); exits("failed"); } okfd = open("/sys/lib/webls.allowed", OREAD); notokfd = open("/sys/lib/webls.denied", OREAD); bind("/usr/web", "/", MREPL); if(connect->req.search != nil) dosearch(connect->req.search); else error("Bad argument", "Need a search argument"); hflush(hout); writelog(connect, "200 webls %ld %ld\n", hout->seek, hout->seek); exits(nil); }