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