static char *dirname = NULL;
static char **childspec;
static uid_t minuid = 0;
+static int usesyslog = 0;
static struct user *users = NULL;
static void login(struct passwd *pwd)
{
int fd;
+ setsid();
if(getuid() == 0) {
if(initgroups(pwd->pw_name, pwd->pw_gid)) {
flog(LOG_ERR, "could not init group list for %s: %s", pwd->pw_name, strerror(errno));
flog(LOG_ERR, "could not change to home directory for %s: %s", pwd->pw_name, strerror(errno));
exit(1);
}
+ if(usesyslog)
+ putenv("ASHD_USESYSLOG=1");
+ else
+ unsetenv("ASHD_USESYSLOG");
putenv(sprintf2("HOME=%s", pwd->pw_dir));
putenv(sprintf2("SHELL=%s", pwd->pw_shell));
putenv(sprintf2("USER=%s", pwd->pw_name));
* getting Kerberos credentials, running PAM session modules, and
* who knows what. I'll add them along as I find them useful. */
if(((fd = open(".ashd/output", O_WRONLY | O_APPEND)) >= 0) ||
- ((fd = open("/dev/null", 0)) >= 0)) {
+ ((fd = open("/dev/null", O_WRONLY)) >= 0)) {
dup2(fd, 1);
close(fd);
}
if(((fd = open(".ashd/error", O_WRONLY | O_APPEND)) >= 0) ||
- ((fd = open("/dev/null", 0)) >= 0)) {
+ ((fd = open("/dev/null", O_WRONLY)) >= 0)) {
dup2(fd, 2);
close(fd);
}
}
-static void execchild(struct passwd *pwd)
+static void discardreq(int fromfd)
+{
+ struct hthead *req;
+ int fd;
+
+ if((fd = recvreq(fromfd, &req)) >= 0) {
+ freehthead(req);
+ close(fd);
+ }
+}
+
+static void execchild(struct passwd *pwd, struct hthead *forreq, int reqfd)
{
if(!ignore)
execl(".ashd/handler", ".ashd/handler", NULL);
if(dirname != NULL) {
- if(access(dirname, X_OK | R_OK))
+ if(access(dirname, X_OK | R_OK)) {
+ discardreq(0);
+ simpleerror(reqfd, 404, "Not Found", "No such resource could be found.");
return;
+ }
}
execvp(childspec[0], childspec);
+ discardreq(0);
+ flog(LOG_ERR, "could not start request handler for user `%s': %s", pwd->pw_name, strerror(errno));
+ simpleerror(reqfd, 500, "User Error", "Could not start any request handler for that user.");
}
-static int forkchild(char *usrnm)
+static int forkchild(char *usrnm, struct hthead *forreq, int reqfd)
{
struct passwd *pwd;
pid_t pid;
- int i, fd[2];
+ int fd[2];
/* XXX: There should be a way for the child to report errors (like
* 404 when htpub doesn't exist), but for now I don't bother with
if((pid = fork()) < 0)
return(-1);
if(pid == 0) {
- for(i = 3; i < FD_SETSIZE; i++) {
- if(i != fd[0])
- close(i);
- }
dup2(fd[0], 0);
close(fd[0]);
+ close(fd[1]);
login(pwd);
- execchild(pwd);
+ execchild(pwd, forreq, reqfd);
exit(127);
}
close(fd[0]);
+ fcntl(fd[1], F_SETFD, FD_CLOEXEC);
return(fd[1]);
}
static void serve2(struct user *usr, struct hthead *req, int fd)
{
+ int serr;
+
if(usr->fd < 0)
- usr->fd = forkchild(usr->name);
- if(sendreq(usr->fd, req, fd)) {
- if(errno == EPIPE) {
+ usr->fd = forkchild(usr->name, req, fd);
+ if(sendreq2(usr->fd, req, fd, MSG_NOSIGNAL | MSG_DONTWAIT)) {
+ serr = errno;
+ if((serr == EPIPE) || (serr == ECONNRESET)) {
/* Assume that the child has crashed and restart it. */
close(usr->fd);
- usr->fd = forkchild(usr->name);
- if(!sendreq(usr->fd, req, fd))
+ usr->fd = forkchild(usr->name, req, fd);
+ if(!sendreq2(usr->fd, req, fd, MSG_NOSIGNAL | MSG_DONTWAIT))
return;
}
- flog(LOG_ERR, "could not pass on request to user `%s': %s", usr->name, strerror(errno));
- close(usr->fd);
- usr->fd = -1;
- simpleerror(fd, 500, "User Error", "The request handler for that user keeps crashing.");
+ flog(LOG_ERR, "could not pass on request to user `%s': %s", usr->name, strerror(serr));
+ if(serr != EAGAIN) {
+ close(usr->fd);
+ usr->fd = -1;
+ }
}
}
free(usrnm);
}
+static void sighandler(int sig)
+{
+}
+
static void usage(FILE *out)
{
- fprintf(out, "usage: userplex [-hI] [-g GROUP] [-m MIN-UID] [-d PUB-DIR] [PROGRAM ARGS...]\n");
+ fprintf(out, "usage: userplex [-hIs] [-g GROUP] [-m MIN-UID] [-d PUB-DIR] [PROGRAM ARGS...]\n");
}
int main(int argc, char **argv)
int fd;
struct charvbuf csbuf;
- while((c = getopt(argc, argv, "+hIg:m:d:")) >= 0) {
+ while((c = getopt(argc, argv, "+hIsg:m:d:")) >= 0) {
switch(c) {
case 'I':
ignore = 1;
break;
+ case 's':
+ usesyslog = 1;
+ break;
case 'm':
if((minuid = atoi(optarg)) < 1) {
fprintf(stderr, "userplex: argument to -m must be greater than 0\n");
childspec = csbuf.b;
}
signal(SIGCHLD, SIG_IGN);
+ signal(SIGPIPE, sighandler);
while(1) {
if((fd = recvreq(0, &req)) < 0) {
if(errno != 0)