summaryrefslogtreecommitdiffstats
path: root/fileio.c
diff options
context:
space:
mode:
Diffstat (limited to 'fileio.c')
-rw-r--r--fileio.c776
1 files changed, 776 insertions, 0 deletions
diff --git a/fileio.c b/fileio.c
new file mode 100644
index 0000000..3d9da04
--- /dev/null
+++ b/fileio.c
@@ -0,0 +1,776 @@
+/* Copyright (c) 2008, 2009
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Micah Cowan (micah@cowan.name)
+ * Sadrul Habib Chowdhury (sadrul@users.sourceforge.net)
+ * Copyright (c) 1993-2002, 2003, 2005, 2006, 2007
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, see
+ * https://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ *
+ ****************************************************************
+ */
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <pwd.h>
+
+#ifndef SIGINT
+# include <signal.h>
+#endif
+
+#include "config.h"
+#include "screen.h"
+#include "extern.h"
+
+extern struct display *display, *displays;
+extern struct win *fore;
+extern struct layer *flayer;
+extern int ServerSocket;
+extern int real_uid, eff_uid;
+extern int real_gid, eff_gid;
+extern char *extra_incap, *extra_outcap;
+extern char *home, *RcFileName;
+extern char SockPath[], *SockName;
+#ifdef COPY_PASTE
+extern char *BufferFile;
+#endif
+extern int hardcopy_append;
+extern char *hardcopydir;
+
+static char *CatExtra __P((char *, char *));
+static char *findrcfile __P((char *));
+
+
+char *rc_name = "";
+int rc_recursion = 0;
+
+static char * CatExtra(register char *str1, register char *str2) {
+ register char *cp;
+ register int len1, len2, add_colon;
+
+ len1 = strlen(str1);
+ if (len1 == 0)
+ return str2;
+ add_colon = (str1[len1 - 1] != ':');
+ if (str2) {
+ len2 = strlen(str2);
+ if ((cp = realloc(str2, (unsigned) len1 + len2 + add_colon + 1)) == NULL)
+ Panic(0, "%s", strnomem);
+ bcopy(cp, cp + len1 + add_colon, len2 + 1);
+ }
+ else {
+ if ((cp = malloc((unsigned) len1 + add_colon + 1)) == NULL)
+ Panic(0, "%s", strnomem);
+ cp[len1 + add_colon] = '\0';
+ }
+ bcopy(str1, cp, len1);
+ if (add_colon)
+ cp[len1] = ':';
+ return cp;
+}
+
+static char *findrcfile(char *rcfile) {
+ char buf[256];
+ char *p;
+
+ /* Tilde prefix support courtesy <hesso@pool.math.tu-berlin.de>,
+ * taken from a Debian patch. */
+ if (rcfile && *rcfile == '~') {
+ static char rcfilename_tilde_exp[MAXPATHLEN+1];
+ char *slash_position = strchr(rcfile, '/');
+
+ if (slash_position == rcfile+1) {
+ char *home = getenv("HOME");
+ if (!home) {
+ Msg(0, "%s: source: tilde expansion failed", rc_name);
+ return NULL;
+ }
+ snprintf(rcfilename_tilde_exp, MAXPATHLEN, "%s/%s", home, rcfile+2);
+ }
+ else if (slash_position) {
+ struct passwd *p;
+ *slash_position = 0;
+ p = getpwnam(rcfile+1);
+ if (!p){
+ Msg(0, "%s: source: tilde expansion failed for user %s", rc_name, rcfile+1);
+ return NULL;
+ }
+ snprintf(rcfilename_tilde_exp, MAXPATHLEN, "%s/%s", p->pw_dir, slash_position+1);
+ }
+ else {
+ Msg(0, "%s: source: illegal tilde expression.", rc_name);
+ return NULL;
+ }
+ rcfile = rcfilename_tilde_exp;
+ }
+
+ if (rcfile) {
+ char *rcend = rindex(rc_name, '/');
+ if (*rcfile != '/' && rcend && (rcend - rc_name) + strlen(rcfile) + 2 < sizeof(buf)) {
+ strncpy(buf, rc_name, rcend - rc_name + 1);
+ strcpy(buf + (rcend - rc_name) + 1, rcfile);
+ if (access(buf, R_OK) == 0)
+ return SaveStr(buf);
+ }
+ debug1("findrcfile: you specified '%s'\n", rcfile);
+ return SaveStr(rcfile);
+ }
+
+ debug("findrcfile: you specified nothing...\n");
+ if ((p = getenv("SCREENRC")) != NULL && *p != '\0') {
+ debug1(" $SCREENRC has: '%s'\n", p);
+ return SaveStr(p);
+ }
+ else {
+ debug(" ...nothing in $SCREENRC, defaulting $HOME/.screenrc\n");
+ if (strlen(home) > sizeof(buf) - 12)
+ Panic(0, "Rc: home too large");
+ sprintf(buf, "%s/.screenrc", home);
+ return SaveStr(buf);
+ }
+}
+
+/*
+ * this will be called twice:
+ * 1) rcfilename = "/etc/screenrc"
+ * 2) rcfilename = RcFileName
+ */
+int StartRc(char *rcfilename, int nopanic) {
+ register int argc, len;
+ register char *p, *cp;
+ char buf[2048];
+ char *args[MAXARGS];
+ int argl[MAXARGS];
+ FILE *fp;
+ char *oldrc_name = rc_name;
+
+ /* always fix termcap/info capabilities */
+ extra_incap = CatExtra("TF", extra_incap);
+
+ /* Special settings for vt100 and others */
+ if (display && (!strncmp(D_termname, "vt", 2) || !strncmp(D_termname, "xterm", 5)))
+ extra_incap = CatExtra("xn:f0=\033Op:f1=\033Oq:f2=\033Or:f3=\033Os:f4=\033Ot:f5=\033Ou:f6=\033Ov:f7=\033Ow:f8=\033Ox:f9=\033Oy:f.=\033On:f,=\033Ol:fe=\033OM:f+=\033Ok:f-=\033Om:f*=\033Oj:f/=\033Oo:fq=\033OX", extra_incap);
+
+ rc_name = findrcfile(rcfilename);
+ if (rc_name == NULL || (fp = secfopen(rc_name, "r")) == NULL) {
+ const char *rc_nonnull = rc_name ? rc_name : rcfilename;
+ if (!rc_recursion && RcFileName && !strcmp(RcFileName, rc_nonnull)) {
+ /*
+ * User explicitly gave us that name,
+ * this is the only case, where we get angry, if we can't read
+ * the file.
+ */
+ debug3("StartRc: '%s','%s', '%s'\n", RcFileName, rc_name ? rc_name : "(null)", rcfilename);
+ if (!nopanic) Panic(0, "Unable to open \"%s\".", rc_nonnull);
+ /* possibly NOTREACHED */
+ }
+
+ debug1("StartRc: '%s' no good. ignored\n", rc_nonnull);
+ if (rc_name)
+ Free(rc_name);
+ rc_name = oldrc_name;
+ return 1;
+ }
+ while (fgets(buf, sizeof buf, fp) != NULL) {
+ if ((p = rindex(buf, '\n')) != NULL)
+ *p = '\0';
+
+ if ((argc = Parse(buf, sizeof buf, args, argl)) == 0)
+ continue;
+
+ if (strcmp(args[0], "echo") == 0) {
+ if (!display)
+ continue;
+ if (argc < 2 || (argc == 3 && strcmp(args[1], "-n")) || argc > 3) {
+ Msg(0, "%s: 'echo [-n] \"string\"' expected.", rc_name);
+ continue;
+ }
+ AddStr(args[argc - 1]);
+ if (argc != 3) {
+ AddStr("\r\n");
+ Flush(0);
+ }
+ }
+
+ else if (strcmp(args[0], "sleep") == 0) {
+ if (!display)
+ continue;
+ debug("sleeeeeeep\n");
+ if (argc != 2) {
+ Msg(0, "%s: sleep: one numeric argument expected.", rc_name);
+ continue;
+ }
+ DisplaySleep1000(1000 * atoi(args[1]), 1);
+ }
+#ifdef TERMINFO
+ else if (!strcmp(args[0], "termcapinfo") || !strcmp(args[0], "terminfo")) {
+#else
+ else if (!strcmp(args[0], "termcapinfo") || !strcmp(args[0], "termcap")) {
+#endif
+ if (!display)
+ continue;
+ if (argc < 3 || argc > 4) {
+ Msg(0, "%s: %s: incorrect number of arguments.", rc_name, args[0]);
+ continue;
+ }
+
+ for (p = args[1]; p && *p; p = cp) {
+ if ((cp = index(p, '|')) != 0)
+ *cp++ = '\0';
+ len = strlen(p);
+ if (p[len - 1] == '*') {
+ if (!(len - 1) || !strncmp(p, D_termname, len - 1))
+ break;
+ }
+ else if (!strcmp(p, D_termname))
+ break;
+ }
+ if (!(p && *p))
+ continue;
+ extra_incap = CatExtra(args[2], extra_incap);
+ if (argc == 4)
+ extra_outcap = CatExtra(args[3], extra_outcap);
+ }
+ else if (!strcmp(args[0], "source")) {
+ if (rc_recursion <= 10) {
+ rc_recursion++;
+ (void)StartRc(args[1], 0);
+ rc_recursion--;
+ }
+ }
+ }
+ fclose(fp);
+ Free(rc_name);
+ rc_name = oldrc_name;
+ return 0;
+}
+
+void FinishRc(char *rcfilename) {
+ char buf[2048];
+ FILE *fp;
+ char *oldrc_name = rc_name;
+
+ rc_name = findrcfile(rcfilename);
+
+ if (rc_name == NULL || (fp = secfopen(rc_name, "r")) == NULL) {
+ const char *rc_nonnull = rc_name ? rc_name : rcfilename;
+ if (rc_recursion)
+ Msg(errno, "%s: source %s", oldrc_name, rc_nonnull);
+ else if (RcFileName && !strcmp(RcFileName, rc_nonnull)) {
+ /*
+ * User explicitly gave us that name,
+ * this is the only case, where we get angry, if we can't read
+ * the file.
+ */
+ debug3("FinishRc:'%s','%s','%s'\n", RcFileName, rc_name ? rc_name : "(null)", rcfilename);
+ Panic(0, "Unable to open \"%s\".", rc_nonnull);
+ /* NOTREACHED */
+ }
+ debug1("FinishRc: '%s' no good. ignored\n", rc_nonnull);
+ if (rc_name)
+ Free(rc_name);
+ rc_name = oldrc_name;
+ return;
+ }
+
+ debug("finishrc is going...\n");
+ while (fgets(buf, sizeof buf, fp) != NULL)
+ RcLine(buf, sizeof buf);
+ (void) fclose(fp);
+ Free(rc_name);
+ rc_name = oldrc_name;
+}
+
+void do_source(char *rcfilename) {
+ if (rc_recursion > 10) {
+ Msg(0, "%s: source: recursion limit reached", rc_name);
+ return;
+ }
+ rc_recursion++;
+ FinishRc(rcfilename);
+ rc_recursion--;
+}
+
+
+/*
+ * Running a Command Line in the environment determined by the display.
+ * The fore window is taken from the display as well as the user.
+ * This is bad when we run detached.
+ */
+void RcLine(char *ubuf, int ubufl) {
+ char *args[MAXARGS];
+ int argl[MAXARGS];
+#ifdef MULTIUSER
+ extern struct acluser *EffectiveAclUser; /* acl.c */
+ extern struct acluser *users; /* acl.c */
+#endif
+
+ if (display) {
+ fore = D_fore;
+ flayer = D_forecv->c_layer;
+ }
+ else
+ flayer = fore ? fore->w_savelayer : 0;
+ if (Parse(ubuf, ubufl, args, argl) <= 0)
+ return;
+
+#ifdef MULTIUSER
+ if (!display) {
+ /* the session owner does it, when there is no display here */
+ EffectiveAclUser = users;
+ debug("RcLine: WARNING, no display no user! Session owner executes command\n");
+ }
+#endif
+
+ DoCommand(args, argl);
+
+#ifdef MULTIUSER
+ EffectiveAclUser = 0;
+#endif
+}
+
+/* needs display for copybuffer access and termcap dumping */
+void WriteFile(struct acluser *user, char *fn, int dump) {
+ /* dump==0: create .termcap,
+ * dump==1: hardcopy,
+ * #ifdef COPY_PASTE
+ * dump==2: BUFFERFILE
+ * #endif COPY_PASTE
+ * dump==1: scrollback,
+ */
+ register int i, j, k;
+ register char *p;
+ register FILE *f;
+ char fnbuf[1024];
+ char *mode = "w";
+
+#ifdef COPY_PASTE
+ int public = 0;
+# ifdef HAVE_LSTAT
+ struct stat stb, stb2;
+ int fd, exists = 0;
+# endif
+#endif
+
+ switch (dump) {
+ case DUMP_TERMCAP:
+ if (fn == 0) {
+ i = SockName - SockPath;
+ if (i > (int)sizeof(fnbuf) - 9)
+ i = 0;
+ strncpy(fnbuf, SockPath, i);
+ strcpy(fnbuf + i, ".termcap");
+ fn = fnbuf;
+ }
+ break;
+
+ case DUMP_HARDCOPY:
+ case DUMP_SCROLLBACK:
+ if (fn == 0) {
+ if (fore == 0)
+ return;
+ if (hardcopydir && *hardcopydir && strlen(hardcopydir) < sizeof(fnbuf) - 21)
+ sprintf(fnbuf, "%s/hardcopy.%d", hardcopydir, fore->w_number);
+ else
+ sprintf(fnbuf, "hardcopy.%d", fore->w_number);
+ fn = fnbuf;
+ }
+ if (hardcopy_append && !access(fn, W_OK))
+ mode = "a";
+ break;
+
+#ifdef COPY_PASTE
+ case DUMP_EXCHANGE:
+ if (fn == 0) {
+ strncpy(fnbuf, BufferFile, sizeof(fnbuf) - 1);
+ fnbuf[sizeof(fnbuf) - 1] = 0;
+ fn = fnbuf;
+ }
+ public = !strcmp(fn, DEFAULT_BUFFERFILE);
+# ifdef HAVE_LSTAT
+ exists = !lstat(fn, &stb);
+ if (public && exists && (S_ISLNK(stb.st_mode) || stb.st_nlink > 1)) {
+ Msg(0, "No write to links, please.");
+ return;
+ }
+# endif
+ break;
+#endif
+ }
+
+ debug2("WriteFile(%d) %s\n", dump, fn);
+ if (UserContext() > 0) {
+ debug("Writefile: usercontext\n");
+#ifdef COPY_PASTE
+ if (dump == DUMP_EXCHANGE && public) {
+# ifdef HAVE_LSTAT
+ if (exists) {
+ if ((fd = open(fn, O_WRONLY, 0666)) >= 0) {
+ if (fstat(fd, &stb2) == 0 && stb.st_dev == stb2.st_dev && stb.st_ino == stb2.st_ino)
+ ftruncate(fd, 0);
+ else {
+ close(fd);
+ fd = -1;
+ }
+ }
+ }
+ else
+ fd = open(fn, O_WRONLY|O_CREAT|O_EXCL, 0666);
+ f = fd >= 0 ? fdopen(fd, mode) : 0;
+# else
+ f = fopen(fn, mode);
+# endif
+ }
+ else
+#endif /* COPY_PASTE */
+ f = fopen(fn, mode);
+ if (f == NULL) {
+ debug2("WriteFile: fopen(%s,\"%s\") failed\n", fn, mode);
+ UserReturn(0);
+ }
+ else {
+ switch (dump) {
+ case DUMP_HARDCOPY:
+ case DUMP_SCROLLBACK:
+ if (!fore)
+ break;
+ if (*mode == 'a') {
+ putc('>', f);
+ for (j = fore->w_width - 2; j > 0; j--)
+ putc('=', f);
+ fputs("<\n", f);
+ }
+ if (dump == DUMP_SCROLLBACK) {
+#ifdef COPY_PASTE
+ for (i = fore->w_histheight - fore->w_scrollback_height; i < fore->w_histheight; i++) {
+ p = (char *)(WIN(i)->image);
+ for (k = fore->w_width - 1; k >= 0 && p[k] == ' '; k--)
+ ;
+ for (j = 0; j <= k; j++)
+ putc(p[j], f);
+ putc('\n', f);
+ }
+#endif
+ }
+ for (i = 0; i < fore->w_height; i++) {
+ p = (char *)fore->w_mlines[i].image;
+ for (k = fore->w_width - 1; k >= 0 && p[k] == ' '; k--)
+ ;
+ for (j = 0; j <= k; j++)
+ putc(p[j], f);
+ putc('\n', f);
+ }
+ break;
+
+ case DUMP_TERMCAP:
+ DumpTermcap(fore->w_aflag, f);
+ break;
+
+#ifdef COPY_PASTE
+ case DUMP_EXCHANGE:
+ p = user->u_plop.buf;
+ for (i = user->u_plop.len; i-- > 0; p++)
+ if (*p == '\r' && (i == 0 || p[1] != '\n'))
+ putc('\n', f);
+ else
+ putc(*p, f);
+ break;
+#endif
+ }
+ (void) fclose(f);
+ UserReturn(1);
+ }
+ }
+ if (UserStatus() <= 0)
+ Msg(0, "Cannot open \"%s\"", fn);
+ else if (display && !*rc_name) {
+ switch (dump) {
+ case DUMP_TERMCAP:
+ Msg(0, "Termcap entry written to \"%s\".", fn);
+ break;
+ case DUMP_HARDCOPY:
+ case DUMP_SCROLLBACK:
+ Msg(0, "Screen image %s to \"%s\".", (*mode == 'a') ? "appended" : "written", fn);
+ break;
+#ifdef COPY_PASTE
+ case DUMP_EXCHANGE:
+ Msg(0, "Copybuffer written to \"%s\".", fn);
+#endif
+ }
+ }
+}
+
+#ifdef COPY_PASTE
+
+/*
+ * returns an allocated buffer which holds a copy of the file named fn.
+ * lenp (if nonzero) points to a location, where the buffer size should be
+ * stored.
+ */
+char *ReadFile(char *fn, int *lenp) {
+ int i, l, size;
+ char c, *bp, *buf;
+ struct stat stb;
+
+ ASSERT(lenp);
+ debug1("ReadFile(%s)\n", fn);
+
+ if ((i = secopen(fn, O_RDONLY, 0)) < 0) {
+ Msg(errno, "no %s -- no slurp", fn);
+ return NULL;
+ }
+
+ if (fstat(i, &stb)) {
+ Msg(errno, "no good %s -- no slurp", fn);
+ close(i);
+ return NULL;
+ }
+ size = stb.st_size;
+
+ if ((buf = malloc(size)) == NULL) {
+ close(i);
+ Msg(0, "%s", strnomem);
+ return NULL;
+ }
+ errno = 0;
+
+ if ((l = read(i, buf, size)) != size) {
+ if (l < 0)
+ l = 0;
+ Msg(errno, "Got only %d bytes from %s", l, fn);
+ }
+ else {
+ if (read(i, &c, 1) > 0)
+ Msg(0, "Slurped only %d characters (of %d) into buffer - try again", l, size);
+ else
+ Msg(0, "Slurped %d characters into buffer", l);
+ }
+ close(i);
+ *lenp = l;
+ for (bp = buf; l-- > 0; bp++)
+ if (*bp == '\n' && (bp == buf || bp[-1] != '\r'))
+ *bp = '\r';
+ return buf;
+}
+
+void KillBuffers() {
+ if (UserContext() > 0)
+ UserReturn(unlink(BufferFile) ? errno : 0);
+ errno = UserStatus();
+ Msg(errno, "%s %sremoved", BufferFile, errno ? "not " : "");
+}
+#endif /* COPY_PASTE */
+
+
+/* (Almost) secure open and fopen... */
+
+FILE *secfopen(char *name, char *mode) {
+ FILE *fi;
+#ifndef USE_SETEUID
+ int flags, fd;
+#endif
+
+ debug2("secfopen(%s, %s)\n", name, mode);
+#ifdef USE_SETEUID
+ xseteuid(real_uid);
+ xsetegid(real_gid);
+ fi = fopen(name, mode);
+ xseteuid(eff_uid);
+ xsetegid(eff_gid);
+ return fi;
+
+#else
+ if (eff_uid == real_uid)
+ return fopen(name, mode);
+ if (mode[0] && mode[1] == '+')
+ flags = O_RDWR;
+ else
+ flags = (mode[0] == 'r') ? O_RDONLY : O_WRONLY;
+ if (mode[0] == 'w')
+ flags |= O_CREAT | O_TRUNC;
+ else if (mode[0] == 'a')
+ flags |= O_CREAT | O_APPEND;
+ else if (mode[0] != 'r') {
+ errno = EINVAL;
+ return 0;
+ }
+ if ((fd = secopen(name, flags, 0666)) < 0)
+ return 0;
+ if ((fi = fdopen(fd, mode)) == 0) {
+ close(fd);
+ return 0;
+ }
+ return fi;
+#endif
+}
+
+
+int secopen(char *name, int flags, int mode) {
+ int fd;
+#ifndef USE_SETEUID
+ int q;
+ struct stat stb;
+#endif
+
+ debug3("secopen(%s, 0x%x, 0%03o)\n", name, flags, mode);
+#ifdef USE_SETEUID
+ xseteuid(real_uid);
+ xsetegid(real_gid);
+ fd = open(name, flags, mode);
+ xseteuid(eff_uid);
+ xsetegid(eff_gid);
+ return fd;
+#else
+ if (eff_uid == real_uid)
+ return open(name, flags, mode);
+ /* Truncation/creation is done in UserContext */
+ if ((flags & O_TRUNC) || ((flags & O_CREAT) && access(name, F_OK))) {
+ if (UserContext() > 0) {
+ if ((fd = open(name, flags, mode)) >= 0) {
+ close(fd);
+ UserReturn(0);
+ }
+ if (errno == 0)
+ errno = EACCES;
+ UserReturn(errno);
+ }
+ if ((q = UserStatus())) {
+ if (q > 0)
+ errno = q;
+ return -1;
+ }
+ }
+ if (access(name, F_OK))
+ return -1;
+ if ((fd = open(name, flags & ~(O_TRUNC | O_CREAT), 0)) < 0)
+ return -1;
+ debug("open successful\n");
+ if (fstat(fd, &stb)) {
+ close(fd);
+ return -1;
+ }
+ debug("fstat successful\n");
+ if (stb.st_uid != real_uid) {
+ switch (flags & (O_RDONLY | O_WRONLY | O_RDWR)) {
+ case O_RDONLY:
+ q = 0004;
+ break;
+ case O_WRONLY:
+ q = 0002;
+ break;
+ default:
+ q = 0006;
+ break;
+ }
+ if ((stb.st_mode & q) != q) {
+ debug1("secopen: permission denied (%03o)\n", stb.st_mode & 07777);
+ close(fd);
+ errno = EACCES;
+ return -1;
+ }
+ }
+ debug1("secopen ok - returning %d\n", fd);
+ return fd;
+#endif
+}
+
+
+int printpipe(struct win *p, char *cmd) {
+ int pi[2];
+ if (pipe(pi)) {
+ WMsg(p, errno, "printing pipe");
+ return -1;
+ }
+ switch (fork()) {
+ case -1:
+ WMsg(p, errno, "printing fork");
+ return -1;
+ case 0:
+ display = p->w_pdisplay;
+ displays = 0;
+ ServerSocket = -1;
+#ifdef DEBUG
+ if (dfp && dfp != stderr)
+ fclose(dfp);
+#endif
+ close(0);
+ dup(pi[0]);
+ closeallfiles(0);
+ if (setgid(real_gid) || setuid(real_uid))
+ Panic(errno, "printpipe setuid");
+ eff_uid = real_uid;
+ eff_gid = real_gid;
+
+#ifdef SIGPIPE
+ signal(SIGPIPE, SIG_DFL);
+#endif
+ execl("/bin/sh", "sh", "-c", cmd, (char *)0);
+ Panic(errno, "/bin/sh");
+ default:
+ break;
+ }
+ close(pi[0]);
+ return pi[1];
+}
+
+int readpipe(char **cmdv) {
+ int pi[2];
+
+ if (pipe(pi)) {
+ Msg(errno, "pipe");
+ return -1;
+ }
+
+ switch (fork()) {
+ case -1:
+ Msg(errno, "fork");
+ return -1;
+ case 0:
+ displays = 0;
+ ServerSocket = -1;
+#ifdef DEBUG
+ if (dfp && dfp != stderr)
+ fclose(dfp);
+#endif
+ close(1);
+ if (dup(pi[1]) != 1) {
+ close(pi[1]);
+ Panic(0, "dup");
+ }
+ closeallfiles(1);
+
+ if (setgid(real_gid) || setuid(real_uid)) {
+ close(1);
+ Panic(errno, "setuid/setgid");
+ }
+ eff_uid = real_uid;
+ eff_gid = real_gid;
+#ifdef SIGPIPE
+ signal(SIGPIPE, SIG_DFL);
+#endif
+ execvp(*cmdv, cmdv);
+ close(1);
+ Panic(errno, "%s", *cmdv);
+ default:
+ break;
+ }
+ close(pi[1]);
+ return pi[0];
+}