X-Git-Url: http://www.dolda2000.com/gitweb/?a=blobdiff_plain;f=src%2Fuserplex.c;h=48a8ed3287c27879ab7c804aa4ea91c264f4117d;hb=595adb9922885c2a05bc6917ee8f8f02f496e618;hp=565884d0d0632a31506a3d5f2935e7e7ee2613d9;hpb=42384d2a2870e2cc119fdaa4db42de9865c6cea1;p=ashd.git diff --git a/src/userplex.c b/src/userplex.c index 565884d..48a8ed3 100644 --- a/src/userplex.c +++ b/src/userplex.c @@ -43,15 +43,17 @@ struct user { static int ignore = 0; static char *mgroup = NULL; -static char *dirname = "htpub"; +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)); @@ -73,6 +75,10 @@ static void login(struct passwd *pwd) 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)); @@ -80,34 +86,51 @@ static void login(struct passwd *pwd) /* There's whole load of other stuff one could want to do here -- * 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_APPEND)) >= 0) || - ((fd = open("/dev/null", 0)) >= 0)) { + if(((fd = open(".ashd/output", O_WRONLY | O_APPEND)) >= 0) || + ((fd = open("/dev/null", O_WRONLY)) >= 0)) { dup2(fd, 1); close(fd); } - if(((fd = open(".ashd/error", O_APPEND)) >= 0) || - ((fd = open("/dev/null", 0)) >= 0)) { + if(((fd = open(".ashd/error", O_WRONLY | O_APPEND)) >= 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 @@ -121,36 +144,38 @@ static int forkchild(char *usrnm) 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; + } } } @@ -230,9 +255,13 @@ out: 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) @@ -242,11 +271,14 @@ 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"); @@ -269,8 +301,9 @@ int main(int argc, char **argv) } if(optind < argc) { childspec = argv + optind; - dirname = NULL; } else { + if(dirname == NULL) + dirname = "htpub"; bufinit(csbuf); bufadd(csbuf, "dirplex"); bufadd(csbuf, dirname); @@ -278,6 +311,7 @@ int main(int argc, char **argv) childspec = csbuf.b; } signal(SIGCHLD, SIG_IGN); + signal(SIGPIPE, sighandler); while(1) { if((fd = recvreq(0, &req)) < 0) { if(errno != 0)