1 /* Copyright (c) 1993-2002
2 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
3 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
4 * Copyright (c) 1987 Oliver Laumann
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program (see the file COPYING); if not, write to the
18 * Free Software Foundation, Inc.,
19 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
21 ****************************************************************
24 #include <sys/types.h>
37 extern struct display
*display
, *displays
;
38 extern struct win
*fore
;
39 extern struct layer
*flayer
;
40 extern int real_uid
, eff_uid
;
41 extern int real_gid
, eff_gid
;
42 extern char *extra_incap
, *extra_outcap
;
43 extern char *home
, *RcFileName
;
44 extern char SockPath
[], *SockName
;
46 extern char *BufferFile
;
48 extern int hardcopy_append
;
49 extern char *hardcopydir
;
51 static char *CatExtra
__P((char *, char *));
52 static char *findrcfile
__P((char *));
60 register char *str1
, *str2
;
63 register int len1
, len2
, add_colon
;
68 add_colon
= (str1
[len1
- 1] != ':');
72 if ((cp
= realloc(str2
, (unsigned) len1
+ len2
+ add_colon
+ 1)) == NULL
)
74 bcopy(cp
, cp
+ len1
+ add_colon
, len2
+ 1);
80 if ((cp
= malloc((unsigned) len1
+ add_colon
+ 1)) == NULL
)
82 cp
[len1
+ add_colon
] = '\0';
84 bcopy(str1
, cp
, len1
);
100 char *rcend
= rindex(rc_name
, '/');
101 if (*rcfile
!= '/' && rcend
&& (rcend
- rc_name
) + strlen(rcfile
) + 2 < sizeof(buf
))
103 strncpy(buf
, rc_name
, rcend
- rc_name
+ 1);
104 strcpy(buf
+ (rcend
- rc_name
) + 1, rcfile
);
105 if (access(buf
, R_OK
) == 0)
108 debug1("findrcfile: you specified '%s'\n", rcfile
);
109 return SaveStr(rcfile
);
111 debug("findrcfile: you specified nothing...\n");
112 if ((p
= getenv("SCREENRC")) != NULL
&& *p
!= '\0')
114 debug1(" $SCREENRC has: '%s'\n", p
);
119 debug(" ...nothing in $SCREENRC, defaulting $HOME/.screenrc\n");
120 if (strlen(home
) > sizeof(buf
) - 12)
121 Panic(0, "Rc: home too large");
122 sprintf(buf
, "%s/.screenrc", home
);
128 * this will be called twice:
129 * 1) rcfilename = "/etc/screenrc"
130 * 2) rcfilename = RcFileName
133 StartRc(rcfilename
, nopanic
)
137 register int argc
, len
;
138 register char *p
, *cp
;
143 char *oldrc_name
= rc_name
;
145 /* always fix termcap/info capabilities */
146 extra_incap
= CatExtra("TF", extra_incap
);
148 /* Special settings for vt100 and others */
149 if (display
&& (!strncmp(D_termname
, "vt", 2) || !strncmp(D_termname
, "xterm", 5)))
150 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
);
152 rc_name
= findrcfile(rcfilename
);
154 if ((fp
= secfopen(rc_name
, "r")) == NULL
)
156 if (!rc_recursion
&& RcFileName
&& !strcmp(RcFileName
, rc_name
))
159 * User explicitly gave us that name,
160 * this is the only case, where we get angry, if we can't read
163 debug3("StartRc: '%s','%s', '%s'\n", RcFileName
, rc_name
, rcfilename
);
164 if (!nopanic
) Panic(0, "Unable to open \"%s\".", rc_name
);
165 /* possibly NOTREACHED */
167 debug1("StartRc: '%s' no good. ignored\n", rc_name
);
169 rc_name
= oldrc_name
;
172 while (fgets(buf
, sizeof buf
, fp
) != NULL
)
174 if ((p
= rindex(buf
, '\n')) != NULL
)
176 if ((argc
= Parse(buf
, sizeof buf
, args
, argl
)) == 0)
178 if (strcmp(args
[0], "echo") == 0)
182 if (argc
< 2 || (argc
== 3 && strcmp(args
[1], "-n")) || argc
> 3)
184 Msg(0, "%s: 'echo [-n] \"string\"' expected.", rc_name
);
187 AddStr(args
[argc
- 1]);
194 else if (strcmp(args
[0], "sleep") == 0)
198 debug("sleeeeeeep\n");
201 Msg(0, "%s: sleep: one numeric argument expected.", rc_name
);
204 DisplaySleep1000(1000 * atoi(args
[1]), 1);
207 else if (!strcmp(args
[0], "termcapinfo") || !strcmp(args
[0], "terminfo"))
209 else if (!strcmp(args
[0], "termcapinfo") || !strcmp(args
[0], "termcap"))
214 if (argc
< 3 || argc
> 4)
216 Msg(0, "%s: %s: incorrect number of arguments.", rc_name
, args
[0]);
219 for (p
= args
[1]; p
&& *p
; p
= cp
)
221 if ((cp
= index(p
, '|')) != 0)
224 if (p
[len
- 1] == '*')
226 if (!(len
- 1) || !strncmp(p
, D_termname
, len
- 1))
229 else if (!strcmp(p
, D_termname
))
234 extra_incap
= CatExtra(args
[2], extra_incap
);
236 extra_outcap
= CatExtra(args
[3], extra_outcap
);
238 else if (!strcmp(args
[0], "source"))
240 if (rc_recursion
<= 10)
243 (void)StartRc(args
[1], 0);
250 rc_name
= oldrc_name
;
260 char *oldrc_name
= rc_name
;
262 rc_name
= findrcfile(rcfilename
);
264 if ((fp
= secfopen(rc_name
, "r")) == NULL
)
267 Msg(errno
, "%s: source %s", oldrc_name
, rc_name
);
268 else if (RcFileName
&& !strcmp(RcFileName
, rc_name
))
271 * User explicitly gave us that name,
272 * this is the only case, where we get angry, if we can't read
275 debug3("FinishRc:'%s','%s','%s'\n", RcFileName
, rc_name
, rcfilename
);
276 Panic(0, "Unable to open \"%s\".", rc_name
);
279 debug1("FinishRc: '%s' no good. ignored\n", rc_name
);
281 rc_name
= oldrc_name
;
285 debug("finishrc is going...\n");
286 while (fgets(buf
, sizeof buf
, fp
) != NULL
)
287 RcLine(buf
, sizeof buf
);
290 rc_name
= oldrc_name
;
294 do_source(rcfilename
)
297 if (rc_recursion
> 10)
299 Msg(0, "%s: source: recursion limit reached", rc_name
);
302 /* Tilde prefix support courtesy <hesso@pool.math.tu-berlin.de>,
303 * taken from a Debian patch. */
304 if (*rcfilename
== '~')
306 char rcfilename_tilde_exp
[MAXPATHLEN
+1];
307 char *slash_position
= strchr(rcfilename
, '/');
308 if (slash_position
== rcfilename
+1)
310 char *home
= getenv("HOME");
313 Msg(0, "%s: source: tilde expansion failed", rc_name
);
316 snprintf(rcfilename_tilde_exp
, MAXPATHLEN
, "%s/%s", home
, rcfilename
+2);
318 else if (slash_position
)
322 p
= getpwnam(rcfilename
+1);
325 Msg(0, "%s: source: tilde expansion failed for user %s", rc_name
, rcfilename
+1);
328 snprintf(rcfilename_tilde_exp
, MAXPATHLEN
, "%s/%s", p
->pw_dir
, slash_position
+1);
332 Msg(0, "%s: source: illegal tilde expression.", rc_name
);
336 FinishRc(rcfilename_tilde_exp
);
342 FinishRc(rcfilename
);
349 * Running a Command Line in the environment determined by the display.
350 * The fore window is taken from the display as well as the user.
351 * This is bad when we run detached.
361 extern struct acluser
*EffectiveAclUser
; /* acl.c */
362 extern struct acluser
*users
; /* acl.c */
368 flayer
= D_forecv
->c_layer
;
371 flayer
= fore
? fore
->w_savelayer
: 0;
372 if (Parse(ubuf
, ubufl
, args
, argl
) <= 0)
377 /* the session owner does it, when there is no display here */
378 EffectiveAclUser
= users
;
379 debug("RcLine: WARNING, no display no user! Session owner executes command\n");
382 DoCommand(args
, argl
);
384 EffectiveAclUser
= 0;
389 * needs display for copybuffer access and termcap dumping
392 WriteFile(user
, fn
, dump
)
393 struct acluser
*user
;
397 /* dump==0: create .termcap,
400 * dump==2: BUFFERFILE
402 * dump==1: scrollback,
404 register int i
, j
, k
;
417 struct stat stb
, stb2
;
427 i
= SockName
- SockPath
;
428 if (i
> (int)sizeof(fnbuf
) - 9)
430 strncpy(fnbuf
, SockPath
, i
);
431 strcpy(fnbuf
+ i
, ".termcap");
436 case DUMP_SCROLLBACK
:
441 if (hardcopydir
&& *hardcopydir
&& strlen(hardcopydir
) < sizeof(fnbuf
) - 21)
442 sprintf(fnbuf
, "%s/hardcopy.%d", hardcopydir
, fore
->w_number
);
444 sprintf(fnbuf
, "hardcopy.%d", fore
->w_number
);
447 if (hardcopy_append
&& !access(fn
, W_OK
))
454 strncpy(fnbuf
, BufferFile
, sizeof(fnbuf
) - 1);
455 fnbuf
[sizeof(fnbuf
) - 1] = 0;
458 public = !strcmp(fn
, DEFAULT_BUFFERFILE
);
460 exists
= !lstat(fn
, &stb
);
461 if (public && exists
&& (S_ISLNK(stb
.st_mode
) || stb
.st_nlink
> 1))
463 Msg(0, "No write to links, please.");
471 debug2("WriteFile(%d) %s\n", dump
, fn
);
472 if (UserContext() > 0)
474 debug("Writefile: usercontext\n");
476 if (dump
== DUMP_EXCHANGE
&& public)
478 old_umask
= umask(0);
482 if ((fd
= open(fn
, O_WRONLY
, 0666)) >= 0)
484 if (fstat(fd
, &stb2
) == 0 && stb
.st_dev
== stb2
.st_dev
&& stb
.st_ino
== stb2
.st_ino
)
494 fd
= open(fn
, O_WRONLY
|O_CREAT
|O_EXCL
, 0666);
495 f
= fd
>= 0 ? fdopen(fd
, mode
) : 0;
502 #endif /* COPY_PASTE */
506 debug2("WriteFile: fopen(%s,\"%s\") failed\n", fn
, mode
);
514 case DUMP_SCROLLBACK
:
520 for (j
= fore
->w_width
- 2; j
> 0; j
--)
524 if (dump
== DUMP_SCROLLBACK
)
526 for (i
= 0; i
< fore
->w_histheight
; i
++)
528 p
= (char *)(WIN(i
)->image
);
529 for (k
= fore
->w_width
- 1; k
>= 0 && p
[k
] == ' '; k
--)
531 for (j
= 0; j
<= k
; j
++)
536 for (i
= 0; i
< fore
->w_height
; i
++)
538 p
= (char *)fore
->w_mlines
[i
].image
;
539 for (k
= fore
->w_width
- 1; k
>= 0 && p
[k
] == ' '; k
--)
541 for (j
= 0; j
<= k
; j
++)
547 if ((p
= index(MakeTermcap(fore
->w_aflag
), '=')) != NULL
)
555 p
= user
->u_plop
.buf
;
556 for (i
= user
->u_plop
.len
; i
-- > 0; p
++)
557 if (*p
== '\r' && (i
== 0 || p
[1] != '\n'))
568 if (UserStatus() <= 0)
569 Msg(0, "Cannot open \"%s\"", fn
);
570 else if (display
&& !*rc_name
)
575 Msg(0, "Termcap entry written to \"%s\".", fn
);
578 case DUMP_SCROLLBACK
:
579 Msg(0, "Screen image %s to \"%s\".",
580 (*mode
== 'a') ? "appended" : "written", fn
);
584 Msg(0, "Copybuffer written to \"%s\".", fn
);
593 * returns an allocated buffer which holds a copy of the file named fn.
594 * lenp (if nonzero) points to a location, where the buffer size should be
607 debug1("ReadFile(%s)\n", fn
);
608 if ((i
= secopen(fn
, O_RDONLY
, 0)) < 0)
610 Msg(errno
, "no %s -- no slurp", fn
);
615 Msg(errno
, "no good %s -- no slurp", fn
);
620 if ((buf
= malloc(size
)) == NULL
)
627 if ((l
= read(i
, buf
, size
)) != size
)
631 Msg(errno
, "Got only %d bytes from %s", l
, fn
);
636 if (read(i
, &c
, 1) > 0)
637 Msg(0, "Slurped only %d characters (of %d) into buffer - try again",
640 Msg(0, "Slurped %d characters into buffer", l
);
644 for (bp
= buf
; l
-- > 0; bp
++)
645 if (*bp
== '\n' && (bp
== buf
|| bp
[-1] != '\r'))
653 if (UserContext() > 0)
654 UserReturn(unlink(BufferFile
) ? errno
: 0);
655 errno
= UserStatus();
656 Msg(errno
, "%s %sremoved", BufferFile
, errno
? "not " : "");
658 #endif /* COPY_PASTE */
662 * (Almost) secure open and fopen...
675 debug2("secfopen(%s, %s)\n", name
, mode
);
679 fi
= fopen(name
, mode
);
684 if (eff_uid
== real_uid
)
685 return fopen(name
, mode
);
686 if (mode
[0] && mode
[1] == '+')
689 flags
= (mode
[0] == 'r') ? O_RDONLY
: O_WRONLY
;
691 flags
|= O_CREAT
| O_TRUNC
;
692 else if (mode
[0] == 'a')
693 flags
|= O_CREAT
| O_APPEND
;
694 else if (mode
[0] != 'r')
699 if ((fd
= secopen(name
, flags
, 0666)) < 0)
701 if ((fi
= fdopen(fd
, mode
)) == 0)
712 secopen(name
, flags
, mode
)
723 debug3("secopen(%s, 0x%x, 0%03o)\n", name
, flags
, mode
);
727 fd
= open(name
, flags
, mode
);
732 if (eff_uid
== real_uid
)
733 return open(name
, flags
, mode
);
734 /* Truncation/creation is done in UserContext */
735 if ((flags
& O_TRUNC
) || ((flags
& O_CREAT
) && access(name
, F_OK
)))
737 if (UserContext() > 0)
739 if ((fd
= open(name
, flags
, mode
)) >= 0)
748 if ((q
= UserStatus()))
755 if (access(name
, F_OK
))
757 if ((fd
= open(name
, flags
& ~(O_TRUNC
| O_CREAT
), 0)) < 0)
759 debug("open successful\n");
765 debug("fstat successful\n");
766 if (stb
.st_uid
!= real_uid
)
768 switch (flags
& (O_RDONLY
| O_WRONLY
| O_RDWR
))
780 if ((stb
.st_mode
& q
) != q
)
782 debug1("secopen: permission denied (%03o)\n", stb
.st_mode
& 07777);
788 debug1("secopen ok - returning %d\n", fd
);
802 WMsg(p
, errno
, "printing pipe");
808 WMsg(p
, errno
, "printing fork");
811 display
= p
->w_pdisplay
;
814 if (dfp
&& dfp
!= stderr
)
820 if (setgid(real_gid
) || setuid(real_uid
))
821 Panic(errno
, "printpipe setuid");
823 signal(SIGPIPE
, SIG_DFL
);
825 execl("/bin/sh", "sh", "-c", cmd
, (char *)0);
826 Panic(errno
, "/bin/sh");
853 if (dfp
&& dfp
!= stderr
)
863 if (setgid(real_gid
) || setuid(real_uid
))
866 Panic(errno
, "setuid/setgid");
869 signal(SIGPIPE
, SIG_DFL
);