applied Szabolcs patch, added him to LICENSE

This commit is contained in:
Anselm R Garbe 2011-02-13 12:46:34 +00:00
parent 0c7cc24c83
commit a61a51b91d
3 changed files with 48 additions and 28 deletions

View file

@ -1,6 +1,7 @@
MIT/X Consortium License MIT/X Consortium License
© 2009 Anselm R Garbe <anselm@garbe.us> © 2009-2011 Anselm R Garbe <anselm@garbe.us>
© 2011 Szabolcs Nagy <nszabolcs@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),

View file

@ -5,7 +5,7 @@ static const char serverport[] = "80";
static const char docroot[] = "."; static const char docroot[] = ".";
static const char docindex[] = "index.html"; static const char docindex[] = "index.html";
static const char user[] = "nobody"; static const char user[] = "nobody";
static const char group[] = "nobody"; static const char group[] = "nogroup";
static const char cgi_dir[] = "/var/www/werc-dev/bin"; static const char cgi_dir[] = "/var/www/werc-dev/bin";
static const char cgi_script[] = "./werc.rc"; static const char cgi_script[] = "./werc.rc";
static const int cgi_mode = 0; static const int cgi_mode = 0;

71
quark.c
View file

@ -5,6 +5,7 @@
#include <netdb.h> #include <netdb.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <pwd.h> #include <pwd.h>
#include <grp.h>
#include <signal.h> #include <signal.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
@ -38,9 +39,10 @@ static const char texthtml[] = "text/html";
static ssize_t writetext(const char *buf); static ssize_t writetext(const char *buf);
static ssize_t writedata(const char *buf, size_t buflen); static ssize_t writedata(const char *buf, size_t buflen);
static void atomiclog(int fd, const char *errstr, va_list ap);
static void die(const char *errstr, ...); static void die(const char *errstr, ...);
void logmsg(const char *errstr, ...); static void logmsg(const char *errstr, ...);
void logerrmsg(const char *errstr, ...); static void logerrmsg(const char *errstr, ...);
static void response(void); static void response(void);
static void responsecgi(void); static void responsecgi(void);
static void responsedir(void); static void responsedir(void);
@ -68,7 +70,7 @@ writedata(const char *buf, size_t buf_len) {
while(offset < buf_len) { while(offset < buf_len) {
if((r = write(cfd, buf + offset, buf_len - offset)) == -1) { if((r = write(cfd, buf + offset, buf_len - offset)) == -1) {
logerrmsg("%s: client %s closed connection\n", tstamp(), host); logerrmsg("client %s closed connection\n", host);
return -1; return -1;
} }
offset += r; offset += r;
@ -81,13 +83,28 @@ writetext(const char *buf) {
return writedata(buf, strlen(buf)); return writedata(buf, strlen(buf));
} }
void
atomiclog(int fd, const char *errstr, va_list ap) {
static char buf[512];
int n;
/*
assemble the message in buf and write it in one pass
to avoid interleaved concurrent writes on a shared fd.
*/
n = snprintf(buf, sizeof buf, "%s: ", tstamp());
n += vsnprintf(buf + n, sizeof buf - n, errstr, ap);
if (n >= sizeof buf)
n = sizeof buf - 1;
write(fd, buf, n);
}
void void
logmsg(const char *errstr, ...) { logmsg(const char *errstr, ...) {
va_list ap; va_list ap;
fprintf(stdout, "%s: ", tstamp());
va_start(ap, errstr); va_start(ap, errstr);
vfprintf(stdout, errstr, ap); atomiclog(STDOUT_FILENO, errstr, ap);
va_end(ap); va_end(ap);
} }
@ -95,9 +112,8 @@ void
logerrmsg(const char *errstr, ...) { logerrmsg(const char *errstr, ...) {
va_list ap; va_list ap;
fprintf(stderr, "%s: ", tstamp());
va_start(ap, errstr); va_start(ap, errstr);
vfprintf(stderr, errstr, ap); atomiclog(STDERR_FILENO, errstr, ap);
va_end(ap); va_end(ap);
} }
@ -105,9 +121,8 @@ void
die(const char *errstr, ...) { die(const char *errstr, ...) {
va_list ap; va_list ap;
fprintf(stderr, "%s: ", tstamp());
va_start(ap, errstr); va_start(ap, errstr);
vfprintf(stderr, errstr, ap); atomiclog(STDERR_FILENO, errstr, ap);
va_end(ap); va_end(ap);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -181,8 +196,7 @@ responsefile(void) {
int i, ffd; int i, ffd;
struct stat st; struct stat st;
stat(reqbuf, &st); if(stat(reqbuf, &st) == -1 || (ffd = open(reqbuf, O_RDONLY)) == -1) {
if((ffd = open(reqbuf, O_RDONLY)) == -1) {
logerrmsg("%s requests unknown path %s\n", host, reqbuf); logerrmsg("%s requests unknown path %s\n", host, reqbuf);
if(responsehdr(HttpNotFound) != -1 if(responsehdr(HttpNotFound) != -1
&& responsecontenttype(texthtml) != -1) && responsecontenttype(texthtml) != -1)
@ -269,6 +283,8 @@ responsedir(void) {
responsedirdata(d); responsedirdata(d);
closedir(d); closedir(d);
} }
else
logerrmsg("client %s requests %s but opendir failed: %s\n", host, reqbuf, strerror(errno));
} }
else else
responsefile(); /* docindex */ responsefile(); /* docindex */
@ -290,7 +306,8 @@ responsecgi(void) {
setenv("SCRIPT_NAME", cgi_script, 1); setenv("SCRIPT_NAME", cgi_script, 1);
setenv("REQUEST_URI", reqbuf, 1); setenv("REQUEST_URI", reqbuf, 1);
logmsg("CGI SERVER_NAME=%s SCRIPT_NAME=%s REQUEST_URI=%s\n", reqhost, cgi_script, reqbuf); logmsg("CGI SERVER_NAME=%s SCRIPT_NAME=%s REQUEST_URI=%s\n", reqhost, cgi_script, reqbuf);
chdir(cgi_dir); if(chdir(cgi_dir) == -1)
logerrmsg("chdir to cgi directory %s failed: %s\n", cgi_dir, strerror(errno));
if((cgi = popen(cgi_script, "r"))) { if((cgi = popen(cgi_script, "r"))) {
if(responsehdr(HttpOk) == -1) if(responsehdr(HttpOk) == -1)
return; return;
@ -335,8 +352,7 @@ response(void) {
if(cgi_mode) if(cgi_mode)
responsecgi(); responsecgi();
else { else {
stat(reqbuf, &st); if(stat(reqbuf, &st) != -1 && S_ISDIR(st.st_mode))
if(S_ISDIR(st.st_mode))
responsedir(); responsedir();
else else
responsefile(); responsefile();
@ -350,7 +366,7 @@ request(void) {
size_t offset = 0; size_t offset = 0;
do { /* MAXBUFLEN byte of reqbuf is emergency 0 terminator */ do { /* MAXBUFLEN byte of reqbuf is emergency 0 terminator */
if((r = read(cfd, reqbuf + offset, MAXBUFLEN - offset)) < 0) { if((r = read(cfd, reqbuf + offset, MAXBUFLEN - offset)) == -1) {
logerrmsg("read: %s\n", strerror(errno)); logerrmsg("read: %s\n", strerror(errno));
return -1; return -1;
} }
@ -362,7 +378,7 @@ request(void) {
for(res = res + 5; *res && (*res == ' ' || *res == '\t'); res++); for(res = res + 5; *res && (*res == ' ' || *res == '\t'); res++);
if(!*res) if(!*res)
goto invalid_request; goto invalid_request;
for(p = res; *p && *p != ' ' && *p != '\t' && *p != '\r' && *p != '\t'; p++); for(p = res; *p && *p != ' ' && *p != '\t' && *p != '\r' && *p != '\n'; p++);
if(!*p) if(!*p)
goto invalid_request; goto invalid_request;
*p = 0; *p = 0;
@ -372,8 +388,6 @@ request(void) {
reqhost[p - res] = 0; reqhost[p - res] = 0;
} }
for(p = reqbuf; *p && *p != '\r' && *p != '\n'; p++); for(p = reqbuf; *p && *p != '\r' && *p != '\n'; p++);
if(!*p)
goto invalid_request;
if(*p == '\r' || *p == '\n') { if(*p == '\r' || *p == '\n') {
*p = 0; *p = 0;
/* check command */ /* check command */
@ -407,15 +421,16 @@ serve(int fd) {
socklen_t salen; socklen_t salen;
struct sockaddr sa; struct sockaddr sa;
salen = sizeof sa;
while(running) { while(running) {
salen = sizeof sa;
if((cfd = accept(fd, &sa, &salen)) == -1) { if((cfd = accept(fd, &sa, &salen)) == -1) {
/* el cheapo socket release */ /* el cheapo socket release */
logerrmsg("cannot accept: %s, sleep a second...\n", strerror(errno)); logerrmsg("cannot accept: %s, sleep a second...\n", strerror(errno));
sleep(1); sleep(1);
continue; continue;
} }
if(fork() == 0) { result = fork();
if(result == 0) {
close(fd); close(fd);
host[0] = 0; host[0] = 0;
getnameinfo(&sa, salen, host, sizeof host, NULL, 0, NI_NOFQDN); getnameinfo(&sa, salen, host, sizeof host, NULL, 0, NI_NOFQDN);
@ -426,7 +441,8 @@ serve(int fd) {
shutdown(cfd, SHUT_WR); shutdown(cfd, SHUT_WR);
close(cfd); close(cfd);
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} } else if (result == -1)
logerrmsg("fork failed: %s\n", strerror(errno));
close(cfd); close(cfd);
} }
logmsg("shutting down\n"); logmsg("shutting down\n");
@ -472,7 +488,8 @@ tstamp(void) {
int int
main(int argc, char *argv[]) { main(int argc, char *argv[]) {
struct addrinfo hints, *ai; struct addrinfo hints, *ai;
struct passwd *upwd, *gpwd; struct passwd *upwd;
struct group *gpwd;
int i; int i;
/* arguments */ /* arguments */
@ -485,7 +502,7 @@ main(int argc, char *argv[]) {
/* sanity checks */ /* sanity checks */
if(!(upwd = getpwnam(user))) if(!(upwd = getpwnam(user)))
die("error: invalid user %s\n", user); die("error: invalid user %s\n", user);
if(!(gpwd = getpwnam(group))) if(!(gpwd = getgrnam(group)))
die("error: invalid group %s\n", group); die("error: invalid group %s\n", group);
signal(SIGCHLD, sighandler); signal(SIGCHLD, sighandler);
@ -529,10 +546,12 @@ main(int argc, char *argv[]) {
die("error: location too long\n"); die("error: location too long\n");
} }
if(chroot(docroot) == -1) if(chdir(docroot) == -1)
die("error: chroot %s: %s\n", docroot, strerror(errno)); die("error: chdir %s: %s\n", docroot, strerror(errno));
if(chroot(".") == -1)
die("error: chroot .: %s\n", strerror(errno));
if(setgid(gpwd->pw_gid) == -1) if(setgid(gpwd->gr_gid) == -1)
die("error: cannot set group id\n"); die("error: cannot set group id\n");
if(setuid(upwd->pw_uid) == -1) if(setuid(upwd->pw_uid) == -1)
die("error: cannot set user id\n"); die("error: cannot set user id\n");