137da2899SCharles.Forsyth #include <sys/types.h>
237da2899SCharles.Forsyth #include <signal.h>
337da2899SCharles.Forsyth #include <pwd.h>
437da2899SCharles.Forsyth #include <sys/time.h>
537da2899SCharles.Forsyth #include <sys/resource.h>
637da2899SCharles.Forsyth #include <sys/wait.h>
737da2899SCharles.Forsyth #include <fcntl.h>
837da2899SCharles.Forsyth
937da2899SCharles.Forsyth #include "dat.h"
1037da2899SCharles.Forsyth #include "fns.h"
1137da2899SCharles.Forsyth #include "error.h"
1237da2899SCharles.Forsyth
1337da2899SCharles.Forsyth enum
1437da2899SCharles.Forsyth {
1537da2899SCharles.Forsyth Debug = 0
1637da2899SCharles.Forsyth };
1737da2899SCharles.Forsyth
1837da2899SCharles.Forsyth /*
1937da2899SCharles.Forsyth * os-specific devcmd support.
2037da2899SCharles.Forsyth * this version should be reasonably portable across Unix systems.
2137da2899SCharles.Forsyth */
2237da2899SCharles.Forsyth typedef struct Targ Targ;
2337da2899SCharles.Forsyth struct Targ
2437da2899SCharles.Forsyth {
25*6e425a9dSCharles.Forsyth int fd[3]; /* fd[0] is standard input, fd[1] is standard output, fd[2] is standard error */
2637da2899SCharles.Forsyth char** args;
2737da2899SCharles.Forsyth char* dir;
2837da2899SCharles.Forsyth int pid;
2937da2899SCharles.Forsyth int wfd; /* child writes errors that occur after the fork or on exec */
3037da2899SCharles.Forsyth int uid;
3137da2899SCharles.Forsyth int gid;
3237da2899SCharles.Forsyth };
3337da2899SCharles.Forsyth
3437da2899SCharles.Forsyth extern int gidnobody;
3537da2899SCharles.Forsyth extern int uidnobody;
3637da2899SCharles.Forsyth
3737da2899SCharles.Forsyth static int
childproc(Targ * t)3837da2899SCharles.Forsyth childproc(Targ *t)
3937da2899SCharles.Forsyth {
4037da2899SCharles.Forsyth int i, nfd;
4137da2899SCharles.Forsyth
4237da2899SCharles.Forsyth if(Debug)
4337da2899SCharles.Forsyth print("devcmd: '%s'", t->args[0]);
4437da2899SCharles.Forsyth
4537da2899SCharles.Forsyth nfd = getdtablesize();
4637da2899SCharles.Forsyth for(i = 0; i < nfd; i++)
47*6e425a9dSCharles.Forsyth if(i != t->fd[0] && i != t->fd[1] && i != t->fd[2] && i != t->wfd)
4837da2899SCharles.Forsyth close(i);
4937da2899SCharles.Forsyth
5037da2899SCharles.Forsyth dup2(t->fd[0], 0);
5137da2899SCharles.Forsyth dup2(t->fd[1], 1);
52*6e425a9dSCharles.Forsyth dup2(t->fd[2], 2);
5337da2899SCharles.Forsyth close(t->fd[0]);
5437da2899SCharles.Forsyth close(t->fd[1]);
55*6e425a9dSCharles.Forsyth close(t->fd[2]);
5637da2899SCharles.Forsyth
57*6e425a9dSCharles.Forsyth /* should have an auth file to do host-specific authorisation? */
5837da2899SCharles.Forsyth if(t->gid != -1){
5937da2899SCharles.Forsyth if(setgid(t->gid) < 0 && getegid() == 0){
6037da2899SCharles.Forsyth fprint(t->wfd, "can't set gid %d: %s", t->gid, strerror(errno));
6137da2899SCharles.Forsyth _exit(1);
6237da2899SCharles.Forsyth }
6337da2899SCharles.Forsyth }
6437da2899SCharles.Forsyth
6537da2899SCharles.Forsyth if(t->uid != -1){
6637da2899SCharles.Forsyth if(setuid(t->uid) < 0 && geteuid() == 0){
6737da2899SCharles.Forsyth fprint(t->wfd, "can't set uid %d: %s", t->uid, strerror(errno));
6837da2899SCharles.Forsyth _exit(1);
6937da2899SCharles.Forsyth }
7037da2899SCharles.Forsyth }
7137da2899SCharles.Forsyth
7237da2899SCharles.Forsyth if(t->dir != nil && chdir(t->dir) < 0){
7337da2899SCharles.Forsyth fprint(t->wfd, "can't chdir to %s: %s", t->dir, strerror(errno));
7437da2899SCharles.Forsyth _exit(1);
7537da2899SCharles.Forsyth }
7637da2899SCharles.Forsyth
7737da2899SCharles.Forsyth signal(SIGPIPE, SIG_DFL);
7837da2899SCharles.Forsyth
7937da2899SCharles.Forsyth execvp(t->args[0], t->args);
8037da2899SCharles.Forsyth if(Debug)
8137da2899SCharles.Forsyth print("execvp: %s\n",strerror(errno));
8237da2899SCharles.Forsyth fprint(t->wfd, "exec failed: %s", strerror(errno));
8337da2899SCharles.Forsyth
8437da2899SCharles.Forsyth _exit(1);
8537da2899SCharles.Forsyth }
8637da2899SCharles.Forsyth
8737da2899SCharles.Forsyth void*
oscmd(char ** args,int nice,char * dir,int * fd)88*6e425a9dSCharles.Forsyth oscmd(char **args, int nice, char *dir, int *fd)
8937da2899SCharles.Forsyth {
9037da2899SCharles.Forsyth Targ *t;
91*6e425a9dSCharles.Forsyth int r, fd0[2], fd1[2], fd2[2], wfd[2], n, pid;
9237da2899SCharles.Forsyth
9337da2899SCharles.Forsyth t = mallocz(sizeof(*t), 1);
9437da2899SCharles.Forsyth if(t == nil)
9537da2899SCharles.Forsyth return nil;
9637da2899SCharles.Forsyth
9737da2899SCharles.Forsyth fd0[0] = fd0[1] = -1;
9837da2899SCharles.Forsyth fd1[0] = fd1[1] = -1;
99*6e425a9dSCharles.Forsyth fd2[0] = fd2[1] = -1;
10037da2899SCharles.Forsyth wfd[0] = wfd[1] = -1;
101*6e425a9dSCharles.Forsyth if(pipe(fd0) < 0 || pipe(fd1) < 0 || pipe(fd2) < 0 || pipe(wfd) < 0)
10237da2899SCharles.Forsyth goto Error;
10337da2899SCharles.Forsyth if(fcntl(wfd[1], F_SETFD, FD_CLOEXEC) < 0) /* close on exec to give end of file on success */
10437da2899SCharles.Forsyth goto Error;
10537da2899SCharles.Forsyth
10637da2899SCharles.Forsyth t->fd[0] = fd0[0];
10737da2899SCharles.Forsyth t->fd[1] = fd1[1];
108*6e425a9dSCharles.Forsyth t->fd[2] = fd2[1];
10937da2899SCharles.Forsyth t->wfd = wfd[1];
11037da2899SCharles.Forsyth t->args = args;
11137da2899SCharles.Forsyth t->dir = dir;
11237da2899SCharles.Forsyth t->gid = up->env->gid;
11337da2899SCharles.Forsyth if(t->gid == -1)
11437da2899SCharles.Forsyth t->gid = gidnobody;
11537da2899SCharles.Forsyth t->uid = up->env->uid;
11637da2899SCharles.Forsyth if(t->uid == -1)
11737da2899SCharles.Forsyth t->uid = uidnobody;
11837da2899SCharles.Forsyth
11937da2899SCharles.Forsyth signal(SIGCHLD, SIG_DFL);
12037da2899SCharles.Forsyth switch(pid = fork()) {
12137da2899SCharles.Forsyth case -1:
12237da2899SCharles.Forsyth goto Error;
12337da2899SCharles.Forsyth case 0:
12437da2899SCharles.Forsyth setpgid(0, getpid());
12537da2899SCharles.Forsyth if(nice)
12637da2899SCharles.Forsyth oslopri();
12737da2899SCharles.Forsyth childproc(t);
12837da2899SCharles.Forsyth _exit(1);
12937da2899SCharles.Forsyth default:
13037da2899SCharles.Forsyth t->pid = pid;
13137da2899SCharles.Forsyth if(Debug)
13237da2899SCharles.Forsyth print("cmd pid %d\n", t->pid);
13337da2899SCharles.Forsyth break;
13437da2899SCharles.Forsyth }
13537da2899SCharles.Forsyth
13637da2899SCharles.Forsyth close(fd0[0]);
13737da2899SCharles.Forsyth close(fd1[1]);
138*6e425a9dSCharles.Forsyth close(fd2[1]);
13937da2899SCharles.Forsyth close(wfd[1]);
14037da2899SCharles.Forsyth
14137da2899SCharles.Forsyth n = read(wfd[0], up->genbuf, sizeof(up->genbuf)-1);
14237da2899SCharles.Forsyth close(wfd[0]);
14337da2899SCharles.Forsyth if(n > 0){
14437da2899SCharles.Forsyth close(fd0[1]);
14537da2899SCharles.Forsyth close(fd1[0]);
146*6e425a9dSCharles.Forsyth close(fd2[0]);
14737da2899SCharles.Forsyth free(t);
14837da2899SCharles.Forsyth up->genbuf[n] = 0;
14937da2899SCharles.Forsyth if(Debug)
15037da2899SCharles.Forsyth print("oscmd: bad exec: %q\n", up->genbuf);
15137da2899SCharles.Forsyth error(up->genbuf);
15237da2899SCharles.Forsyth return nil;
15337da2899SCharles.Forsyth }
15437da2899SCharles.Forsyth
155*6e425a9dSCharles.Forsyth fd[0] = fd0[1];
156*6e425a9dSCharles.Forsyth fd[1] = fd1[0];
157*6e425a9dSCharles.Forsyth fd[2] = fd2[0];
15837da2899SCharles.Forsyth return t;
15937da2899SCharles.Forsyth
16037da2899SCharles.Forsyth Error:
16137da2899SCharles.Forsyth r = errno;
16237da2899SCharles.Forsyth if(Debug)
16337da2899SCharles.Forsyth print("oscmd: %q\n",strerror(r));
16437da2899SCharles.Forsyth close(fd0[0]);
16537da2899SCharles.Forsyth close(fd0[1]);
16637da2899SCharles.Forsyth close(fd1[0]);
16737da2899SCharles.Forsyth close(fd1[1]);
168*6e425a9dSCharles.Forsyth close(fd2[0]);
169*6e425a9dSCharles.Forsyth close(fd2[1]);
17037da2899SCharles.Forsyth close(wfd[0]);
17137da2899SCharles.Forsyth close(wfd[1]);
17237da2899SCharles.Forsyth error(strerror(r));
17337da2899SCharles.Forsyth return nil;
17437da2899SCharles.Forsyth }
17537da2899SCharles.Forsyth
17637da2899SCharles.Forsyth int
oscmdkill(void * a)17737da2899SCharles.Forsyth oscmdkill(void *a)
17837da2899SCharles.Forsyth {
17937da2899SCharles.Forsyth Targ *t = a;
18037da2899SCharles.Forsyth
18137da2899SCharles.Forsyth if(Debug)
18237da2899SCharles.Forsyth print("kill: %d\n", t->pid);
18337da2899SCharles.Forsyth return kill(-t->pid, SIGTERM);
18437da2899SCharles.Forsyth }
18537da2899SCharles.Forsyth
18637da2899SCharles.Forsyth int
oscmdwait(void * a,char * buf,int n)18737da2899SCharles.Forsyth oscmdwait(void *a, char *buf, int n)
18837da2899SCharles.Forsyth {
18937da2899SCharles.Forsyth Targ *t = a;
19037da2899SCharles.Forsyth int s;
19137da2899SCharles.Forsyth
19237da2899SCharles.Forsyth if(waitpid(t->pid, &s, 0) == -1){
19337da2899SCharles.Forsyth if(Debug)
19437da2899SCharles.Forsyth print("wait error: %d [in %d] %q\n", t->pid, getpid(), strerror(errno));
19537da2899SCharles.Forsyth return -1;
19637da2899SCharles.Forsyth }
19737da2899SCharles.Forsyth if(WIFEXITED(s)){
19837da2899SCharles.Forsyth if(WEXITSTATUS(s) == 0)
19937da2899SCharles.Forsyth return snprint(buf, n, "%d 0 0 0 ''", t->pid);
20037da2899SCharles.Forsyth return snprint(buf, n, "%d 0 0 0 'exit: %d'", t->pid, WEXITSTATUS(s));
20137da2899SCharles.Forsyth }
20237da2899SCharles.Forsyth if(WIFSIGNALED(s)){
20337da2899SCharles.Forsyth if(WTERMSIG(s) == SIGTERM || WTERMSIG(s) == SIGKILL)
20437da2899SCharles.Forsyth return snprint(buf, n, "%d 0 0 0 killed", t->pid);
20537da2899SCharles.Forsyth return snprint(buf, n, "%d 0 0 0 'signal: %d'", t->pid, WTERMSIG(s));
20637da2899SCharles.Forsyth }
20737da2899SCharles.Forsyth return snprint(buf, n, "%d 0 0 0 'odd status: 0x%x'", t->pid, s);
20837da2899SCharles.Forsyth }
20937da2899SCharles.Forsyth
21037da2899SCharles.Forsyth void
oscmdfree(void * a)21137da2899SCharles.Forsyth oscmdfree(void *a)
21237da2899SCharles.Forsyth {
21337da2899SCharles.Forsyth free(a);
21437da2899SCharles.Forsyth }
215