1 /* Copyright (c) 2008, 2009
2 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
3 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
4 * Micah Cowan (micah@cowan.name)
5 * Sadrul Habib Chowdhury (sadrul@users.sourceforge.net)
6 * Copyright (c) 1993-2002, 2003, 2005, 2006, 2007
7 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
8 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
9 * Copyright (c) 1987 Oliver Laumann
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 3, or (at your option)
14 * any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program (see the file COPYING); if not, see
23 * https://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
25 *
26 ****************************************************************
27 */
28
29 #include <sys/types.h>
30 #include <fcntl.h>
31 #include <sys/stat.h>
32 #include <pwd.h>
33
34 #ifndef SIGINT
35 # include <signal.h>
36 #endif
37
38 #include "config.h"
39 #include "screen.h"
40 #include "extern.h"
41
42 extern struct display *display, *displays;
43 extern struct win *fore;
44 extern struct layer *flayer;
45 extern int ServerSocket;
46 extern int real_uid, eff_uid;
47 extern int real_gid, eff_gid;
48 extern char *extra_incap, *extra_outcap;
49 extern char *home, *RcFileName;
50 extern char SockPath[], *SockName;
51 #ifdef COPY_PASTE
52 extern char *BufferFile;
53 #endif
54 extern int hardcopy_append;
55 extern char *hardcopydir;
56
57 static char *CatExtra __P((char *, char *));
58 static char *findrcfile __P((char *));
59
60
61 char *rc_name = "";
62 int rc_recursion = 0;
63
CatExtra(register char * str1,register char * str2)64 static char * CatExtra(register char *str1, register char *str2) {
65 register char *cp;
66 register int len1, len2, add_colon;
67
68 len1 = strlen(str1);
69 if (len1 == 0)
70 return str2;
71 add_colon = (str1[len1 - 1] != ':');
72 if (str2) {
73 len2 = strlen(str2);
74 if ((cp = realloc(str2, (unsigned) len1 + len2 + add_colon + 1)) == NULL)
75 Panic(0, "%s", strnomem);
76 bcopy(cp, cp + len1 + add_colon, len2 + 1);
77 }
78 else {
79 if ((cp = malloc((unsigned) len1 + add_colon + 1)) == NULL)
80 Panic(0, "%s", strnomem);
81 cp[len1 + add_colon] = '\0';
82 }
83 bcopy(str1, cp, len1);
84 if (add_colon)
85 cp[len1] = ':';
86 return cp;
87 }
88
findrcfile(char * rcfile)89 static char *findrcfile(char *rcfile) {
90 char buf[256];
91 char *p;
92
93 /* Tilde prefix support courtesy <hesso@pool.math.tu-berlin.de>,
94 * taken from a Debian patch. */
95 if (rcfile && *rcfile == '~') {
96 static char rcfilename_tilde_exp[MAXPATHLEN+1];
97 char *slash_position = strchr(rcfile, '/');
98
99 if (slash_position == rcfile+1) {
100 char *home = getenv("HOME");
101 if (!home) {
102 Msg(0, "%s: source: tilde expansion failed", rc_name);
103 return NULL;
104 }
105 snprintf(rcfilename_tilde_exp, MAXPATHLEN, "%s/%s", home, rcfile+2);
106 }
107 else if (slash_position) {
108 struct passwd *p;
109 *slash_position = 0;
110 p = getpwnam(rcfile+1);
111 if (!p){
112 Msg(0, "%s: source: tilde expansion failed for user %s", rc_name, rcfile+1);
113 return NULL;
114 }
115 snprintf(rcfilename_tilde_exp, MAXPATHLEN, "%s/%s", p->pw_dir, slash_position+1);
116 }
117 else {
118 Msg(0, "%s: source: illegal tilde expression.", rc_name);
119 return NULL;
120 }
121 rcfile = rcfilename_tilde_exp;
122 }
123
124 if (rcfile) {
125 char *rcend = rindex(rc_name, '/');
126 if (*rcfile != '/' && rcend && (rcend - rc_name) + strlen(rcfile) + 2 < sizeof(buf)) {
127 strncpy(buf, rc_name, rcend - rc_name + 1);
128 strcpy(buf + (rcend - rc_name) + 1, rcfile);
129 if (access(buf, R_OK) == 0)
130 return SaveStr(buf);
131 }
132 debug1("findrcfile: you specified '%s'\n", rcfile);
133 return SaveStr(rcfile);
134 }
135
136 debug("findrcfile: you specified nothing...\n");
137 if ((p = getenv("SCREENRC")) != NULL && *p != '\0') {
138 debug1(" $SCREENRC has: '%s'\n", p);
139 return SaveStr(p);
140 }
141 else {
142 debug(" ...nothing in $SCREENRC, defaulting $HOME/.screenrc\n");
143 if (strlen(home) > sizeof(buf) - 12)
144 Panic(0, "Rc: home too large");
145 sprintf(buf, "%s/.screenrc", home);
146 return SaveStr(buf);
147 }
148 }
149
150 /*
151 * this will be called twice:
152 * 1) rcfilename = "/etc/screenrc"
153 * 2) rcfilename = RcFileName
154 */
StartRc(char * rcfilename,int nopanic)155 int StartRc(char *rcfilename, int nopanic) {
156 register int argc, len;
157 register char *p, *cp;
158 char buf[2048];
159 char *args[MAXARGS];
160 int argl[MAXARGS];
161 FILE *fp;
162 char *oldrc_name = rc_name;
163
164 /* always fix termcap/info capabilities */
165 extra_incap = CatExtra("TF", extra_incap);
166
167 /* Special settings for vt100 and others */
168 if (display && (!strncmp(D_termname, "vt", 2) || !strncmp(D_termname, "xterm", 5)))
169 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);
170
171 rc_name = findrcfile(rcfilename);
172 if (rc_name == NULL || (fp = secfopen(rc_name, "r")) == NULL) {
173 const char *rc_nonnull = rc_name ? rc_name : rcfilename;
174 if (!rc_recursion && RcFileName && !strcmp(RcFileName, rc_nonnull)) {
175 /*
176 * User explicitly gave us that name,
177 * this is the only case, where we get angry, if we can't read
178 * the file.
179 */
180 debug3("StartRc: '%s','%s', '%s'\n", RcFileName, rc_name ? rc_name : "(null)", rcfilename);
181 if (!nopanic) Panic(0, "Unable to open \"%s\".", rc_nonnull);
182 /* possibly NOTREACHED */
183 }
184
185 debug1("StartRc: '%s' no good. ignored\n", rc_nonnull);
186 if (rc_name)
187 Free(rc_name);
188 rc_name = oldrc_name;
189 return 1;
190 }
191 while (fgets(buf, sizeof buf, fp) != NULL) {
192 if ((p = rindex(buf, '\n')) != NULL)
193 *p = '\0';
194
195 if ((argc = Parse(buf, sizeof buf, args, argl)) == 0)
196 continue;
197
198 if (strcmp(args[0], "echo") == 0) {
199 if (!display)
200 continue;
201 if (argc < 2 || (argc == 3 && strcmp(args[1], "-n")) || argc > 3) {
202 Msg(0, "%s: 'echo [-n] \"string\"' expected.", rc_name);
203 continue;
204 }
205 AddStr(args[argc - 1]);
206 if (argc != 3) {
207 AddStr("\r\n");
208 Flush(0);
209 }
210 }
211
212 else if (strcmp(args[0], "sleep") == 0) {
213 if (!display)
214 continue;
215 debug("sleeeeeeep\n");
216 if (argc != 2) {
217 Msg(0, "%s: sleep: one numeric argument expected.", rc_name);
218 continue;
219 }
220 DisplaySleep1000(1000 * atoi(args[1]), 1);
221 }
222 #ifdef TERMINFO
223 else if (!strcmp(args[0], "termcapinfo") || !strcmp(args[0], "terminfo")) {
224 #else
225 else if (!strcmp(args[0], "termcapinfo") || !strcmp(args[0], "termcap")) {
226 #endif
227 if (!display)
228 continue;
229 if (argc < 3 || argc > 4) {
230 Msg(0, "%s: %s: incorrect number of arguments.", rc_name, args[0]);
231 continue;
232 }
233
234 for (p = args[1]; p && *p; p = cp) {
235 if ((cp = index(p, '|')) != 0)
236 *cp++ = '\0';
237 len = strlen(p);
238 if (p[len - 1] == '*') {
239 if (!(len - 1) || !strncmp(p, D_termname, len - 1))
240 break;
241 }
242 else if (!strcmp(p, D_termname))
243 break;
244 }
245 if (!(p && *p))
246 continue;
247 extra_incap = CatExtra(args[2], extra_incap);
248 if (argc == 4)
249 extra_outcap = CatExtra(args[3], extra_outcap);
250 }
251 else if (!strcmp(args[0], "source")) {
252 if (rc_recursion <= 10) {
253 rc_recursion++;
254 (void)StartRc(args[1], 0);
255 rc_recursion--;
256 }
257 }
258 }
259 fclose(fp);
260 Free(rc_name);
261 rc_name = oldrc_name;
262 return 0;
263 }
264
265 void FinishRc(char *rcfilename) {
266 char buf[2048];
267 FILE *fp;
268 char *oldrc_name = rc_name;
269
270 rc_name = findrcfile(rcfilename);
271
272 if (rc_name == NULL || (fp = secfopen(rc_name, "r")) == NULL) {
273 const char *rc_nonnull = rc_name ? rc_name : rcfilename;
274 if (rc_recursion)
275 Msg(errno, "%s: source %s", oldrc_name, rc_nonnull);
276 else if (RcFileName && !strcmp(RcFileName, rc_nonnull)) {
277 /*
278 * User explicitly gave us that name,
279 * this is the only case, where we get angry, if we can't read
280 * the file.
281 */
282 debug3("FinishRc:'%s','%s','%s'\n", RcFileName, rc_name ? rc_name : "(null)", rcfilename);
283 Panic(0, "Unable to open \"%s\".", rc_nonnull);
284 /* NOTREACHED */
285 }
286 debug1("FinishRc: '%s' no good. ignored\n", rc_nonnull);
287 if (rc_name)
288 Free(rc_name);
289 rc_name = oldrc_name;
290 return;
291 }
292
293 debug("finishrc is going...\n");
294 while (fgets(buf, sizeof buf, fp) != NULL)
295 RcLine(buf, sizeof buf);
296 (void) fclose(fp);
297 Free(rc_name);
298 rc_name = oldrc_name;
299 }
300
301 void do_source(char *rcfilename) {
302 if (rc_recursion > 10) {
303 Msg(0, "%s: source: recursion limit reached", rc_name);
304 return;
305 }
306 rc_recursion++;
307 FinishRc(rcfilename);
308 rc_recursion--;
309 }
310
311
312 /*
313 * Running a Command Line in the environment determined by the display.
314 * The fore window is taken from the display as well as the user.
315 * This is bad when we run detached.
316 */
317 void RcLine(char *ubuf, int ubufl) {
318 char *args[MAXARGS];
319 int argl[MAXARGS];
320 #ifdef MULTIUSER
321 extern struct acluser *EffectiveAclUser; /* acl.c */
322 extern struct acluser *users; /* acl.c */
323 #endif
324
325 if (display) {
326 fore = D_fore;
327 flayer = D_forecv->c_layer;
328 }
329 else
330 flayer = fore ? fore->w_savelayer : 0;
331 if (Parse(ubuf, ubufl, args, argl) <= 0)
332 return;
333
334 #ifdef MULTIUSER
335 if (!display) {
336 /* the session owner does it, when there is no display here */
337 EffectiveAclUser = users;
338 debug("RcLine: WARNING, no display no user! Session owner executes command\n");
339 }
340 #endif
341
342 DoCommand(args, argl);
343
344 #ifdef MULTIUSER
345 EffectiveAclUser = 0;
346 #endif
347 }
348
349 /* needs display for copybuffer access and termcap dumping */
350 void WriteFile(struct acluser *user, char *fn, int dump) {
351 /* dump==0: create .termcap,
352 * dump==1: hardcopy,
353 * #ifdef COPY_PASTE
354 * dump==2: BUFFERFILE
355 * #endif COPY_PASTE
356 * dump==1: scrollback,
357 */
358 register int i, j, k;
359 register char *p;
360 register FILE *f;
361 char fnbuf[1024];
362 char *mode = "w";
363
364 #ifdef COPY_PASTE
365 int public = 0;
366 # ifdef HAVE_LSTAT
367 struct stat stb, stb2;
368 int fd, exists = 0;
369 # endif
370 #endif
371
372 switch (dump) {
373 case DUMP_TERMCAP:
374 if (fn == 0) {
375 i = SockName - SockPath;
376 if (i > (int)sizeof(fnbuf) - 9)
377 i = 0;
378 strncpy(fnbuf, SockPath, i);
379 strcpy(fnbuf + i, ".termcap");
380 fn = fnbuf;
381 }
382 break;
383
384 case DUMP_HARDCOPY:
385 case DUMP_SCROLLBACK:
386 if (fn == 0) {
387 if (fore == 0)
388 return;
389 if (hardcopydir && *hardcopydir && strlen(hardcopydir) < sizeof(fnbuf) - 21)
390 sprintf(fnbuf, "%s/hardcopy.%d", hardcopydir, fore->w_number);
391 else
392 sprintf(fnbuf, "hardcopy.%d", fore->w_number);
393 fn = fnbuf;
394 }
395 if (hardcopy_append && !access(fn, W_OK))
396 mode = "a";
397 break;
398
399 #ifdef COPY_PASTE
400 case DUMP_EXCHANGE:
401 if (fn == 0) {
402 strncpy(fnbuf, BufferFile, sizeof(fnbuf) - 1);
403 fnbuf[sizeof(fnbuf) - 1] = 0;
404 fn = fnbuf;
405 }
406 public = !strcmp(fn, DEFAULT_BUFFERFILE);
407 # ifdef HAVE_LSTAT
408 exists = !lstat(fn, &stb);
409 if (public && exists && (S_ISLNK(stb.st_mode) || stb.st_nlink > 1)) {
410 Msg(0, "No write to links, please.");
411 return;
412 }
413 # endif
414 break;
415 #endif
416 }
417
418 debug2("WriteFile(%d) %s\n", dump, fn);
419 if (UserContext() > 0) {
420 debug("Writefile: usercontext\n");
421 #ifdef COPY_PASTE
422 if (dump == DUMP_EXCHANGE && public) {
423 # ifdef HAVE_LSTAT
424 if (exists) {
425 if ((fd = open(fn, O_WRONLY, 0666)) >= 0) {
426 if (fstat(fd, &stb2) == 0 && stb.st_dev == stb2.st_dev && stb.st_ino == stb2.st_ino)
427 ftruncate(fd, 0);
428 else {
429 close(fd);
430 fd = -1;
431 }
432 }
433 }
434 else
435 fd = open(fn, O_WRONLY|O_CREAT|O_EXCL, 0666);
436 f = fd >= 0 ? fdopen(fd, mode) : 0;
437 # else
438 f = fopen(fn, mode);
439 # endif
440 }
441 else
442 #endif /* COPY_PASTE */
443 f = fopen(fn, mode);
444 if (f == NULL) {
445 debug2("WriteFile: fopen(%s,\"%s\") failed\n", fn, mode);
446 UserReturn(0);
447 }
448 else {
449 switch (dump) {
450 case DUMP_HARDCOPY:
451 case DUMP_SCROLLBACK:
452 if (!fore)
453 break;
454 if (*mode == 'a') {
455 putc('>', f);
456 for (j = fore->w_width - 2; j > 0; j--)
457 putc('=', f);
458 fputs("<\n", f);
459 }
460 if (dump == DUMP_SCROLLBACK) {
461 #ifdef COPY_PASTE
462 for (i = fore->w_histheight - fore->w_scrollback_height; i < fore->w_histheight; i++) {
463 p = (char *)(WIN(i)->image);
464 for (k = fore->w_width - 1; k >= 0 && p[k] == ' '; k--)
465 ;
466 for (j = 0; j <= k; j++)
467 putc(p[j], f);
468 putc('\n', f);
469 }
470 #endif
471 }
472 for (i = 0; i < fore->w_height; i++) {
473 p = (char *)fore->w_mlines[i].image;
474 for (k = fore->w_width - 1; k >= 0 && p[k] == ' '; k--)
475 ;
476 for (j = 0; j <= k; j++)
477 putc(p[j], f);
478 putc('\n', f);
479 }
480 break;
481
482 case DUMP_TERMCAP:
483 DumpTermcap(fore->w_aflag, f);
484 break;
485
486 #ifdef COPY_PASTE
487 case DUMP_EXCHANGE:
488 p = user->u_plop.buf;
489 for (i = user->u_plop.len; i-- > 0; p++)
490 if (*p == '\r' && (i == 0 || p[1] != '\n'))
491 putc('\n', f);
492 else
493 putc(*p, f);
494 break;
495 #endif
496 }
497 (void) fclose(f);
498 UserReturn(1);
499 }
500 }
501 if (UserStatus() <= 0)
502 Msg(0, "Cannot open \"%s\"", fn);
503 else if (display && !*rc_name) {
504 switch (dump) {
505 case DUMP_TERMCAP:
506 Msg(0, "Termcap entry written to \"%s\".", fn);
507 break;
508 case DUMP_HARDCOPY:
509 case DUMP_SCROLLBACK:
510 Msg(0, "Screen image %s to \"%s\".", (*mode == 'a') ? "appended" : "written", fn);
511 break;
512 #ifdef COPY_PASTE
513 case DUMP_EXCHANGE:
514 Msg(0, "Copybuffer written to \"%s\".", fn);
515 #endif
516 }
517 }
518 }
519
520 #ifdef COPY_PASTE
521
522 /*
523 * returns an allocated buffer which holds a copy of the file named fn.
524 * lenp (if nonzero) points to a location, where the buffer size should be
525 * stored.
526 */
527 char *ReadFile(char *fn, int *lenp) {
528 int i, l, size;
529 char c, *bp, *buf;
530 struct stat stb;
531
532 ASSERT(lenp);
533 debug1("ReadFile(%s)\n", fn);
534
535 if ((i = secopen(fn, O_RDONLY, 0)) < 0) {
536 Msg(errno, "no %s -- no slurp", fn);
537 return NULL;
538 }
539
540 if (fstat(i, &stb)) {
541 Msg(errno, "no good %s -- no slurp", fn);
542 close(i);
543 return NULL;
544 }
545 size = stb.st_size;
546
547 if ((buf = malloc(size)) == NULL) {
548 close(i);
549 Msg(0, "%s", strnomem);
550 return NULL;
551 }
552 errno = 0;
553
554 if ((l = read(i, buf, size)) != size) {
555 if (l < 0)
556 l = 0;
557 Msg(errno, "Got only %d bytes from %s", l, fn);
558 }
559 else {
560 if (read(i, &c, 1) > 0)
561 Msg(0, "Slurped only %d characters (of %d) into buffer - try again", l, size);
562 else
563 Msg(0, "Slurped %d characters into buffer", l);
564 }
565 close(i);
566 *lenp = l;
567 for (bp = buf; l-- > 0; bp++)
568 if (*bp == '\n' && (bp == buf || bp[-1] != '\r'))
569 *bp = '\r';
570 return buf;
571 }
572
573 void KillBuffers() {
574 if (UserContext() > 0)
575 UserReturn(unlink(BufferFile) ? errno : 0);
576 errno = UserStatus();
577 Msg(errno, "%s %sremoved", BufferFile, errno ? "not " : "");
578 }
579 #endif /* COPY_PASTE */
580
581
582 /* (Almost) secure open and fopen... */
583
584 FILE *secfopen(char *name, char *mode) {
585 FILE *fi;
586 #ifndef USE_SETEUID
587 int flags, fd;
588 #endif
589
590 debug2("secfopen(%s, %s)\n", name, mode);
591 #ifdef USE_SETEUID
592 xseteuid(real_uid);
593 xsetegid(real_gid);
594 fi = fopen(name, mode);
595 xseteuid(eff_uid);
596 xsetegid(eff_gid);
597 return fi;
598
599 #else
600 if (eff_uid == real_uid)
601 return fopen(name, mode);
602 if (mode[0] && mode[1] == '+')
603 flags = O_RDWR;
604 else
605 flags = (mode[0] == 'r') ? O_RDONLY : O_WRONLY;
606 if (mode[0] == 'w')
607 flags |= O_CREAT | O_TRUNC;
608 else if (mode[0] == 'a')
609 flags |= O_CREAT | O_APPEND;
610 else if (mode[0] != 'r') {
611 errno = EINVAL;
612 return 0;
613 }
614 if ((fd = secopen(name, flags, 0666)) < 0)
615 return 0;
616 if ((fi = fdopen(fd, mode)) == 0) {
617 close(fd);
618 return 0;
619 }
620 return fi;
621 #endif
622 }
623
624
625 int secopen(char *name, int flags, int mode) {
626 int fd;
627 #ifndef USE_SETEUID
628 int q;
629 struct stat stb;
630 #endif
631
632 debug3("secopen(%s, 0x%x, 0%03o)\n", name, flags, mode);
633 #ifdef USE_SETEUID
634 xseteuid(real_uid);
635 xsetegid(real_gid);
636 fd = open(name, flags, mode);
637 xseteuid(eff_uid);
638 xsetegid(eff_gid);
639 return fd;
640 #else
641 if (eff_uid == real_uid)
642 return open(name, flags, mode);
643 /* Truncation/creation is done in UserContext */
644 if ((flags & O_TRUNC) || ((flags & O_CREAT) && access(name, F_OK))) {
645 if (UserContext() > 0) {
646 if ((fd = open(name, flags, mode)) >= 0) {
647 close(fd);
648 UserReturn(0);
649 }
650 if (errno == 0)
651 errno = EACCES;
652 UserReturn(errno);
653 }
654 if ((q = UserStatus())) {
655 if (q > 0)
656 errno = q;
657 return -1;
658 }
659 }
660 if (access(name, F_OK))
661 return -1;
662 if ((fd = open(name, flags & ~(O_TRUNC | O_CREAT), 0)) < 0)
663 return -1;
664 debug("open successful\n");
665 if (fstat(fd, &stb)) {
666 close(fd);
667 return -1;
668 }
669 debug("fstat successful\n");
670 if (stb.st_uid != real_uid) {
671 switch (flags & (O_RDONLY | O_WRONLY | O_RDWR)) {
672 case O_RDONLY:
673 q = 0004;
674 break;
675 case O_WRONLY:
676 q = 0002;
677 break;
678 default:
679 q = 0006;
680 break;
681 }
682 if ((stb.st_mode & q) != q) {
683 debug1("secopen: permission denied (%03o)\n", stb.st_mode & 07777);
684 close(fd);
685 errno = EACCES;
686 return -1;
687 }
688 }
689 debug1("secopen ok - returning %d\n", fd);
690 return fd;
691 #endif
692 }
693
694
695 int printpipe(struct win *p, char *cmd) {
696 int pi[2];
697 if (pipe(pi)) {
698 WMsg(p, errno, "printing pipe");
699 return -1;
700 }
701 switch (fork()) {
702 case -1:
703 WMsg(p, errno, "printing fork");
704 return -1;
705 case 0:
706 display = p->w_pdisplay;
707 displays = 0;
708 ServerSocket = -1;
709 #ifdef DEBUG
710 if (dfp && dfp != stderr)
711 fclose(dfp);
712 #endif
713 close(0);
714 dup(pi[0]);
715 closeallfiles(0);
716 if (setgid(real_gid) || setuid(real_uid))
717 Panic(errno, "printpipe setuid");
718 eff_uid = real_uid;
719 eff_gid = real_gid;
720
721 #ifdef SIGPIPE
722 signal(SIGPIPE, SIG_DFL);
723 #endif
724 execl("/bin/sh", "sh", "-c", cmd, (char *)0);
725 Panic(errno, "/bin/sh");
726 default:
727 break;
728 }
729 close(pi[0]);
730 return pi[1];
731 }
732
733 int readpipe(char **cmdv) {
734 int pi[2];
735
736 if (pipe(pi)) {
737 Msg(errno, "pipe");
738 return -1;
739 }
740
741 switch (fork()) {
742 case -1:
743 Msg(errno, "fork");
744 return -1;
745 case 0:
746 displays = 0;
747 ServerSocket = -1;
748 #ifdef DEBUG
749 if (dfp && dfp != stderr)
750 fclose(dfp);
751 #endif
752 close(1);
753 if (dup(pi[1]) != 1) {
754 close(pi[1]);
755 Panic(0, "dup");
756 }
757 closeallfiles(1);
758
759 if (setgid(real_gid) || setuid(real_uid)) {
760 close(1);
761 Panic(errno, "setuid/setgid");
762 }
763 eff_uid = real_uid;
764 eff_gid = real_gid;
765 #ifdef SIGPIPE
766 signal(SIGPIPE, SIG_DFL);
767 #endif
768 execvp(*cmdv, cmdv);
769 close(1);
770 Panic(errno, "%s", *cmdv);
771 default:
772 break;
773 }
774 close(pi[1]);
775 return pi[0];
776 }
777