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
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)
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.
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 * http://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
26 ****************************************************************
29 #include <sys/types.h>
42 extern struct display
*display
, *displays
;
43 extern struct win
*fore
;
44 extern struct layer
*flayer
;
45 extern int real_uid
, eff_uid
;
46 extern int real_gid
, eff_gid
;
47 extern char *extra_incap
, *extra_outcap
;
48 extern char *home
, *RcFileName
;
49 extern char SockPath
[], *SockName
;
51 extern char *BufferFile
;
53 extern int hardcopy_append
;
54 extern char *hardcopydir
;
56 static char *CatExtra
__P((char *, char *));
57 static char *findrcfile
__P((char *));
65 register char *str1
, *str2
;
68 register int len1
, len2
, add_colon
;
73 add_colon
= (str1
[len1
- 1] != ':');
77 if ((cp
= realloc(str2
, (unsigned) len1
+ len2
+ add_colon
+ 1)) == NULL
)
79 bcopy(cp
, cp
+ len1
+ add_colon
, len2
+ 1);
85 if ((cp
= malloc((unsigned) len1
+ add_colon
+ 1)) == NULL
)
87 cp
[len1
+ add_colon
] = '\0';
89 bcopy(str1
, cp
, len1
);
105 char *rcend
= rindex(rc_name
, '/');
106 if (*rcfile
!= '/' && rcend
&& (rcend
- rc_name
) + strlen(rcfile
) + 2 < sizeof(buf
))
108 strncpy(buf
, rc_name
, rcend
- rc_name
+ 1);
109 strcpy(buf
+ (rcend
- rc_name
) + 1, rcfile
);
110 if (access(buf
, R_OK
) == 0)
113 debug1("findrcfile: you specified '%s'\n", rcfile
);
114 return SaveStr(rcfile
);
116 debug("findrcfile: you specified nothing...\n");
117 if ((p
= getenv("SCREENRC")) != NULL
&& *p
!= '\0')
119 debug1(" $SCREENRC has: '%s'\n", p
);
124 debug(" ...nothing in $SCREENRC, defaulting $HOME/.screenrc\n");
125 if (strlen(home
) > sizeof(buf
) - 12)
126 Panic(0, "Rc: home too large");
127 sprintf(buf
, "%s/.screenrc", home
);
133 * this will be called twice:
134 * 1) rcfilename = "/etc/screenrc"
135 * 2) rcfilename = RcFileName
138 StartRc(rcfilename
, nopanic
)
142 register int argc
, len
;
143 register char *p
, *cp
;
148 char *oldrc_name
= rc_name
;
150 /* always fix termcap/info capabilities */
151 extra_incap
= CatExtra("TF", extra_incap
);
153 /* Special settings for vt100 and others */
154 if (display
&& (!strncmp(D_termname
, "vt", 2) || !strncmp(D_termname
, "xterm", 5)))
155 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
);
157 rc_name
= findrcfile(rcfilename
);
159 if ((fp
= secfopen(rc_name
, "r")) == NULL
)
161 if (!rc_recursion
&& RcFileName
&& !strcmp(RcFileName
, rc_name
))
164 * User explicitly gave us that name,
165 * this is the only case, where we get angry, if we can't read
168 debug3("StartRc: '%s','%s', '%s'\n", RcFileName
, rc_name
, rcfilename
);
169 if (!nopanic
) Panic(0, "Unable to open \"%s\".", rc_name
);
170 /* possibly NOTREACHED */
172 debug1("StartRc: '%s' no good. ignored\n", rc_name
);
174 rc_name
= oldrc_name
;
177 while (fgets(buf
, sizeof buf
, fp
) != NULL
)
179 if ((p
= rindex(buf
, '\n')) != NULL
)
181 if ((argc
= Parse(buf
, sizeof buf
, args
, argl
)) == 0)
183 if (strcmp(args
[0], "echo") == 0)
187 if (argc
< 2 || (argc
== 3 && strcmp(args
[1], "-n")) || argc
> 3)
189 Msg(0, "%s: 'echo [-n] \"string\"' expected.", rc_name
);
192 AddStr(args
[argc
- 1]);
199 else if (strcmp(args
[0], "sleep") == 0)
203 debug("sleeeeeeep\n");
206 Msg(0, "%s: sleep: one numeric argument expected.", rc_name
);
209 DisplaySleep1000(1000 * atoi(args
[1]), 1);
212 else if (!strcmp(args
[0], "termcapinfo") || !strcmp(args
[0], "terminfo"))
214 else if (!strcmp(args
[0], "termcapinfo") || !strcmp(args
[0], "termcap"))
219 if (argc
< 3 || argc
> 4)
221 Msg(0, "%s: %s: incorrect number of arguments.", rc_name
, args
[0]);
224 for (p
= args
[1]; p
&& *p
; p
= cp
)
226 if ((cp
= index(p
, '|')) != 0)
229 if (p
[len
- 1] == '*')
231 if (!(len
- 1) || !strncmp(p
, D_termname
, len
- 1))
234 else if (!strcmp(p
, D_termname
))
239 extra_incap
= CatExtra(args
[2], extra_incap
);
241 extra_outcap
= CatExtra(args
[3], extra_outcap
);
243 else if (!strcmp(args
[0], "source"))
245 if (rc_recursion
<= 10)
248 (void)StartRc(args
[1], 0);
255 rc_name
= oldrc_name
;
265 char *oldrc_name
= rc_name
;
267 rc_name
= findrcfile(rcfilename
);
269 if ((fp
= secfopen(rc_name
, "r")) == NULL
)
272 Msg(errno
, "%s: source %s", oldrc_name
, rc_name
);
273 else if (RcFileName
&& !strcmp(RcFileName
, rc_name
))
276 * User explicitly gave us that name,
277 * this is the only case, where we get angry, if we can't read
280 debug3("FinishRc:'%s','%s','%s'\n", RcFileName
, rc_name
, rcfilename
);
281 Panic(0, "Unable to open \"%s\".", rc_name
);
284 debug1("FinishRc: '%s' no good. ignored\n", rc_name
);
286 rc_name
= oldrc_name
;
290 debug("finishrc is going...\n");
291 while (fgets(buf
, sizeof buf
, fp
) != NULL
)
292 RcLine(buf
, sizeof buf
);
295 rc_name
= oldrc_name
;
299 do_source(rcfilename
)
302 if (rc_recursion
> 10)
304 Msg(0, "%s: source: recursion limit reached", rc_name
);
307 /* Tilde prefix support courtesy <hesso@pool.math.tu-berlin.de>,
308 * taken from a Debian patch. */
309 if (*rcfilename
== '~')
311 char rcfilename_tilde_exp
[MAXPATHLEN
+1];
312 char *slash_position
= strchr(rcfilename
, '/');
313 if (slash_position
== rcfilename
+1)
315 char *home
= getenv("HOME");
318 Msg(0, "%s: source: tilde expansion failed", rc_name
);
321 snprintf(rcfilename_tilde_exp
, MAXPATHLEN
, "%s/%s", home
, rcfilename
+2);
323 else if (slash_position
)
327 p
= getpwnam(rcfilename
+1);
330 Msg(0, "%s: source: tilde expansion failed for user %s", rc_name
, rcfilename
+1);
333 snprintf(rcfilename_tilde_exp
, MAXPATHLEN
, "%s/%s", p
->pw_dir
, slash_position
+1);
337 Msg(0, "%s: source: illegal tilde expression.", rc_name
);
341 FinishRc(rcfilename_tilde_exp
);
347 FinishRc(rcfilename
);
354 * Running a Command Line in the environment determined by the display.
355 * The fore window is taken from the display as well as the user.
356 * This is bad when we run detached.
366 extern struct acluser
*EffectiveAclUser
; /* acl.c */
367 extern struct acluser
*users
; /* acl.c */
373 flayer
= D_forecv
->c_layer
;
376 flayer
= fore
? fore
->w_savelayer
: 0;
377 if (Parse(ubuf
, ubufl
, args
, argl
) <= 0)
382 /* the session owner does it, when there is no display here */
383 EffectiveAclUser
= users
;
384 debug("RcLine: WARNING, no display no user! Session owner executes command\n");
387 DoCommand(args
, argl
);
389 EffectiveAclUser
= 0;
394 * needs display for copybuffer access and termcap dumping
397 WriteFile(user
, fn
, dump
)
398 struct acluser
*user
;
402 /* dump==0: create .termcap,
405 * dump==2: BUFFERFILE
407 * dump==1: scrollback,
409 register int i
, j
, k
;
422 struct stat stb
, stb2
;
432 i
= SockName
- SockPath
;
433 if (i
> (int)sizeof(fnbuf
) - 9)
435 strncpy(fnbuf
, SockPath
, i
);
436 strcpy(fnbuf
+ i
, ".termcap");
441 case DUMP_SCROLLBACK
:
446 if (hardcopydir
&& *hardcopydir
&& strlen(hardcopydir
) < sizeof(fnbuf
) - 21)
447 sprintf(fnbuf
, "%s/hardcopy.%d", hardcopydir
, fore
->w_number
);
449 sprintf(fnbuf
, "hardcopy.%d", fore
->w_number
);
452 if (hardcopy_append
&& !access(fn
, W_OK
))
459 strncpy(fnbuf
, BufferFile
, sizeof(fnbuf
) - 1);
460 fnbuf
[sizeof(fnbuf
) - 1] = 0;
463 public = !strcmp(fn
, DEFAULT_BUFFERFILE
);
465 exists
= !lstat(fn
, &stb
);
466 if (public && exists
&& (S_ISLNK(stb
.st_mode
) || stb
.st_nlink
> 1))
468 Msg(0, "No write to links, please.");
476 debug2("WriteFile(%d) %s\n", dump
, fn
);
477 if (UserContext() > 0)
479 debug("Writefile: usercontext\n");
481 if (dump
== DUMP_EXCHANGE
&& public)
483 old_umask
= umask(0);
487 if ((fd
= open(fn
, O_WRONLY
, 0666)) >= 0)
489 if (fstat(fd
, &stb2
) == 0 && stb
.st_dev
== stb2
.st_dev
&& stb
.st_ino
== stb2
.st_ino
)
499 fd
= open(fn
, O_WRONLY
|O_CREAT
|O_EXCL
, 0666);
500 f
= fd
>= 0 ? fdopen(fd
, mode
) : 0;
507 #endif /* COPY_PASTE */
511 debug2("WriteFile: fopen(%s,\"%s\") failed\n", fn
, mode
);
519 case DUMP_SCROLLBACK
:
525 for (j
= fore
->w_width
- 2; j
> 0; j
--)
529 if (dump
== DUMP_SCROLLBACK
)
532 for (i
= 0; i
< fore
->w_histheight
; i
++)
534 p
= (char *)(WIN(i
)->image
);
535 for (k
= fore
->w_width
- 1; k
>= 0 && p
[k
] == ' '; k
--)
537 for (j
= 0; j
<= k
; j
++)
543 for (i
= 0; i
< fore
->w_height
; i
++)
545 p
= (char *)fore
->w_mlines
[i
].image
;
546 for (k
= fore
->w_width
- 1; k
>= 0 && p
[k
] == ' '; k
--)
548 for (j
= 0; j
<= k
; j
++)
554 if ((p
= index(MakeTermcap(fore
->w_aflag
), '=')) != NULL
)
562 p
= user
->u_plop
.buf
;
563 for (i
= user
->u_plop
.len
; i
-- > 0; p
++)
564 if (*p
== '\r' && (i
== 0 || p
[1] != '\n'))
575 if (UserStatus() <= 0)
576 Msg(0, "Cannot open \"%s\"", fn
);
577 else if (display
&& !*rc_name
)
582 Msg(0, "Termcap entry written to \"%s\".", fn
);
585 case DUMP_SCROLLBACK
:
586 Msg(0, "Screen image %s to \"%s\".",
587 (*mode
== 'a') ? "appended" : "written", fn
);
591 Msg(0, "Copybuffer written to \"%s\".", fn
);
600 * returns an allocated buffer which holds a copy of the file named fn.
601 * lenp (if nonzero) points to a location, where the buffer size should be
614 debug1("ReadFile(%s)\n", fn
);
615 if ((i
= secopen(fn
, O_RDONLY
, 0)) < 0)
617 Msg(errno
, "no %s -- no slurp", fn
);
622 Msg(errno
, "no good %s -- no slurp", fn
);
627 if ((buf
= malloc(size
)) == NULL
)
634 if ((l
= read(i
, buf
, size
)) != size
)
638 Msg(errno
, "Got only %d bytes from %s", l
, fn
);
643 if (read(i
, &c
, 1) > 0)
644 Msg(0, "Slurped only %d characters (of %d) into buffer - try again",
647 Msg(0, "Slurped %d characters into buffer", l
);
651 for (bp
= buf
; l
-- > 0; bp
++)
652 if (*bp
== '\n' && (bp
== buf
|| bp
[-1] != '\r'))
660 if (UserContext() > 0)
661 UserReturn(unlink(BufferFile
) ? errno
: 0);
662 errno
= UserStatus();
663 Msg(errno
, "%s %sremoved", BufferFile
, errno
? "not " : "");
665 #endif /* COPY_PASTE */
669 * (Almost) secure open and fopen...
682 debug2("secfopen(%s, %s)\n", name
, mode
);
686 fi
= fopen(name
, mode
);
691 if (eff_uid
== real_uid
)
692 return fopen(name
, mode
);
693 if (mode
[0] && mode
[1] == '+')
696 flags
= (mode
[0] == 'r') ? O_RDONLY
: O_WRONLY
;
698 flags
|= O_CREAT
| O_TRUNC
;
699 else if (mode
[0] == 'a')
700 flags
|= O_CREAT
| O_APPEND
;
701 else if (mode
[0] != 'r')
706 if ((fd
= secopen(name
, flags
, 0666)) < 0)
708 if ((fi
= fdopen(fd
, mode
)) == 0)
719 secopen(name
, flags
, mode
)
730 debug3("secopen(%s, 0x%x, 0%03o)\n", name
, flags
, mode
);
734 fd
= open(name
, flags
, mode
);
739 if (eff_uid
== real_uid
)
740 return open(name
, flags
, mode
);
741 /* Truncation/creation is done in UserContext */
742 if ((flags
& O_TRUNC
) || ((flags
& O_CREAT
) && access(name
, F_OK
)))
744 if (UserContext() > 0)
746 if ((fd
= open(name
, flags
, mode
)) >= 0)
755 if ((q
= UserStatus()))
762 if (access(name
, F_OK
))
764 if ((fd
= open(name
, flags
& ~(O_TRUNC
| O_CREAT
), 0)) < 0)
766 debug("open successful\n");
772 debug("fstat successful\n");
773 if (stb
.st_uid
!= real_uid
)
775 switch (flags
& (O_RDONLY
| O_WRONLY
| O_RDWR
))
787 if ((stb
.st_mode
& q
) != q
)
789 debug1("secopen: permission denied (%03o)\n", stb
.st_mode
& 07777);
795 debug1("secopen ok - returning %d\n", fd
);
809 WMsg(p
, errno
, "printing pipe");
815 WMsg(p
, errno
, "printing fork");
818 display
= p
->w_pdisplay
;
821 if (dfp
&& dfp
!= stderr
)
827 if (setgid(real_gid
) || setuid(real_uid
))
828 Panic(errno
, "printpipe setuid");
830 signal(SIGPIPE
, SIG_DFL
);
832 execl("/bin/sh", "sh", "-c", cmd
, (char *)0);
833 Panic(errno
, "/bin/sh");
860 if (dfp
&& dfp
!= stderr
)
870 if (setgid(real_gid
) || setuid(real_uid
))
873 Panic(errno
, "setuid/setgid");
876 signal(SIGPIPE
, SIG_DFL
);