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
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
);
103 /* Tilde prefix support courtesy <hesso@pool.math.tu-berlin.de>,
104 * taken from a Debian patch. */
105 if (rcfile
&& *rcfile
== '~')
107 static char rcfilename_tilde_exp
[MAXPATHLEN
+1];
108 char *slash_position
= strchr(rcfile
, '/');
109 if (slash_position
== rcfile
+1)
111 char *home
= getenv("HOME");
114 Msg(0, "%s: source: tilde expansion failed", rc_name
);
117 snprintf(rcfilename_tilde_exp
, MAXPATHLEN
, "%s/%s", home
, rcfile
+2);
119 else if (slash_position
)
123 p
= getpwnam(rcfile
+1);
126 Msg(0, "%s: source: tilde expansion failed for user %s", rc_name
, rcfile
+1);
129 snprintf(rcfilename_tilde_exp
, MAXPATHLEN
, "%s/%s", p
->pw_dir
, slash_position
+1);
133 Msg(0, "%s: source: illegal tilde expression.", rc_name
);
136 rcfile
= rcfilename_tilde_exp
;
141 char *rcend
= rindex(rc_name
, '/');
142 if (*rcfile
!= '/' && rcend
&& (rcend
- rc_name
) + strlen(rcfile
) + 2 < sizeof(buf
))
144 strncpy(buf
, rc_name
, rcend
- rc_name
+ 1);
145 strcpy(buf
+ (rcend
- rc_name
) + 1, rcfile
);
146 if (access(buf
, R_OK
) == 0)
149 debug1("findrcfile: you specified '%s'\n", rcfile
);
150 return SaveStr(rcfile
);
152 debug("findrcfile: you specified nothing...\n");
153 if ((p
= getenv("SCREENRC")) != NULL
&& *p
!= '\0')
155 debug1(" $SCREENRC has: '%s'\n", p
);
160 debug(" ...nothing in $SCREENRC, defaulting $HOME/.screenrc\n");
161 if (strlen(home
) > sizeof(buf
) - 12)
162 Panic(0, "Rc: home too large");
163 sprintf(buf
, "%s/.screenrc", home
);
169 * this will be called twice:
170 * 1) rcfilename = "/etc/screenrc"
171 * 2) rcfilename = RcFileName
174 StartRc(rcfilename
, nopanic
)
178 register int argc
, len
;
179 register char *p
, *cp
;
184 char *oldrc_name
= rc_name
;
186 /* always fix termcap/info capabilities */
187 extra_incap
= CatExtra("TF", extra_incap
);
189 /* Special settings for vt100 and others */
190 if (display
&& (!strncmp(D_termname
, "vt", 2) || !strncmp(D_termname
, "xterm", 5)))
191 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
);
193 rc_name
= findrcfile(rcfilename
);
195 if ((fp
= secfopen(rc_name
, "r")) == NULL
)
197 if (!rc_recursion
&& RcFileName
&& !strcmp(RcFileName
, rc_name
))
200 * User explicitly gave us that name,
201 * this is the only case, where we get angry, if we can't read
204 debug3("StartRc: '%s','%s', '%s'\n", RcFileName
, rc_name
, rcfilename
);
205 if (!nopanic
) Panic(0, "Unable to open \"%s\".", rc_name
);
206 /* possibly NOTREACHED */
208 debug1("StartRc: '%s' no good. ignored\n", rc_name
);
210 rc_name
= oldrc_name
;
213 while (fgets(buf
, sizeof buf
, fp
) != NULL
)
215 if ((p
= rindex(buf
, '\n')) != NULL
)
217 if ((argc
= Parse(buf
, sizeof buf
, args
, argl
)) == 0)
219 if (strcmp(args
[0], "echo") == 0)
223 if (argc
< 2 || (argc
== 3 && strcmp(args
[1], "-n")) || argc
> 3)
225 Msg(0, "%s: 'echo [-n] \"string\"' expected.", rc_name
);
228 AddStr(args
[argc
- 1]);
235 else if (strcmp(args
[0], "sleep") == 0)
239 debug("sleeeeeeep\n");
242 Msg(0, "%s: sleep: one numeric argument expected.", rc_name
);
245 DisplaySleep1000(1000 * atoi(args
[1]), 1);
248 else if (!strcmp(args
[0], "termcapinfo") || !strcmp(args
[0], "terminfo"))
250 else if (!strcmp(args
[0], "termcapinfo") || !strcmp(args
[0], "termcap"))
255 if (argc
< 3 || argc
> 4)
257 Msg(0, "%s: %s: incorrect number of arguments.", rc_name
, args
[0]);
260 for (p
= args
[1]; p
&& *p
; p
= cp
)
262 if ((cp
= index(p
, '|')) != 0)
265 if (p
[len
- 1] == '*')
267 if (!(len
- 1) || !strncmp(p
, D_termname
, len
- 1))
270 else if (!strcmp(p
, D_termname
))
275 extra_incap
= CatExtra(args
[2], extra_incap
);
277 extra_outcap
= CatExtra(args
[3], extra_outcap
);
279 else if (!strcmp(args
[0], "source"))
281 if (rc_recursion
<= 10)
284 (void)StartRc(args
[1], 0);
291 rc_name
= oldrc_name
;
301 char *oldrc_name
= rc_name
;
303 rc_name
= findrcfile(rcfilename
);
305 if ((fp
= secfopen(rc_name
, "r")) == NULL
)
308 Msg(errno
, "%s: source %s", oldrc_name
, rc_name
);
309 else if (RcFileName
&& !strcmp(RcFileName
, rc_name
))
312 * User explicitly gave us that name,
313 * this is the only case, where we get angry, if we can't read
316 debug3("FinishRc:'%s','%s','%s'\n", RcFileName
, rc_name
, rcfilename
);
317 Panic(0, "Unable to open \"%s\".", rc_name
);
320 debug1("FinishRc: '%s' no good. ignored\n", rc_name
);
322 rc_name
= oldrc_name
;
326 debug("finishrc is going...\n");
327 while (fgets(buf
, sizeof buf
, fp
) != NULL
)
328 RcLine(buf
, sizeof buf
);
331 rc_name
= oldrc_name
;
335 do_source(rcfilename
)
338 if (rc_recursion
> 10)
340 Msg(0, "%s: source: recursion limit reached", rc_name
);
344 FinishRc(rcfilename
);
350 * Running a Command Line in the environment determined by the display.
351 * The fore window is taken from the display as well as the user.
352 * This is bad when we run detached.
362 extern struct acluser
*EffectiveAclUser
; /* acl.c */
363 extern struct acluser
*users
; /* acl.c */
369 flayer
= D_forecv
->c_layer
;
372 flayer
= fore
? fore
->w_savelayer
: 0;
373 if (Parse(ubuf
, ubufl
, args
, argl
) <= 0)
378 /* the session owner does it, when there is no display here */
379 EffectiveAclUser
= users
;
380 debug("RcLine: WARNING, no display no user! Session owner executes command\n");
383 DoCommand(args
, argl
);
385 EffectiveAclUser
= 0;
390 * needs display for copybuffer access and termcap dumping
393 WriteFile(user
, fn
, dump
)
394 struct acluser
*user
;
398 /* dump==0: create .termcap,
401 * dump==2: BUFFERFILE
403 * dump==1: scrollback,
405 register int i
, j
, k
;
418 struct stat stb
, stb2
;
428 i
= SockName
- SockPath
;
429 if (i
> (int)sizeof(fnbuf
) - 9)
431 strncpy(fnbuf
, SockPath
, i
);
432 strcpy(fnbuf
+ i
, ".termcap");
437 case DUMP_SCROLLBACK
:
442 if (hardcopydir
&& *hardcopydir
&& strlen(hardcopydir
) < sizeof(fnbuf
) - 21)
443 sprintf(fnbuf
, "%s/hardcopy.%d", hardcopydir
, fore
->w_number
);
445 sprintf(fnbuf
, "hardcopy.%d", fore
->w_number
);
448 if (hardcopy_append
&& !access(fn
, W_OK
))
455 strncpy(fnbuf
, BufferFile
, sizeof(fnbuf
) - 1);
456 fnbuf
[sizeof(fnbuf
) - 1] = 0;
459 public = !strcmp(fn
, DEFAULT_BUFFERFILE
);
461 exists
= !lstat(fn
, &stb
);
462 if (public && exists
&& (S_ISLNK(stb
.st_mode
) || stb
.st_nlink
> 1))
464 Msg(0, "No write to links, please.");
472 debug2("WriteFile(%d) %s\n", dump
, fn
);
473 if (UserContext() > 0)
475 debug("Writefile: usercontext\n");
477 if (dump
== DUMP_EXCHANGE
&& public)
479 old_umask
= umask(0);
483 if ((fd
= open(fn
, O_WRONLY
, 0666)) >= 0)
485 if (fstat(fd
, &stb2
) == 0 && stb
.st_dev
== stb2
.st_dev
&& stb
.st_ino
== stb2
.st_ino
)
495 fd
= open(fn
, O_WRONLY
|O_CREAT
|O_EXCL
, 0666);
496 f
= fd
>= 0 ? fdopen(fd
, mode
) : 0;
503 #endif /* COPY_PASTE */
507 debug2("WriteFile: fopen(%s,\"%s\") failed\n", fn
, mode
);
515 case DUMP_SCROLLBACK
:
521 for (j
= fore
->w_width
- 2; j
> 0; j
--)
525 if (dump
== DUMP_SCROLLBACK
)
528 for (i
= 0; i
< fore
->w_histheight
; i
++)
530 p
= (char *)(WIN(i
)->image
);
531 for (k
= fore
->w_width
- 1; k
>= 0 && p
[k
] == ' '; k
--)
533 for (j
= 0; j
<= k
; j
++)
539 for (i
= 0; i
< fore
->w_height
; i
++)
541 p
= (char *)fore
->w_mlines
[i
].image
;
542 for (k
= fore
->w_width
- 1; k
>= 0 && p
[k
] == ' '; k
--)
544 for (j
= 0; j
<= k
; j
++)
550 if ((p
= index(MakeTermcap(fore
->w_aflag
), '=')) != NULL
)
558 p
= user
->u_plop
.buf
;
559 for (i
= user
->u_plop
.len
; i
-- > 0; p
++)
560 if (*p
== '\r' && (i
== 0 || p
[1] != '\n'))
571 if (UserStatus() <= 0)
572 Msg(0, "Cannot open \"%s\"", fn
);
573 else if (display
&& !*rc_name
)
578 Msg(0, "Termcap entry written to \"%s\".", fn
);
581 case DUMP_SCROLLBACK
:
582 Msg(0, "Screen image %s to \"%s\".",
583 (*mode
== 'a') ? "appended" : "written", fn
);
587 Msg(0, "Copybuffer written to \"%s\".", fn
);
596 * returns an allocated buffer which holds a copy of the file named fn.
597 * lenp (if nonzero) points to a location, where the buffer size should be
610 debug1("ReadFile(%s)\n", fn
);
611 if ((i
= secopen(fn
, O_RDONLY
, 0)) < 0)
613 Msg(errno
, "no %s -- no slurp", fn
);
618 Msg(errno
, "no good %s -- no slurp", fn
);
623 if ((buf
= malloc(size
)) == NULL
)
630 if ((l
= read(i
, buf
, size
)) != size
)
634 Msg(errno
, "Got only %d bytes from %s", l
, fn
);
639 if (read(i
, &c
, 1) > 0)
640 Msg(0, "Slurped only %d characters (of %d) into buffer - try again",
643 Msg(0, "Slurped %d characters into buffer", l
);
647 for (bp
= buf
; l
-- > 0; bp
++)
648 if (*bp
== '\n' && (bp
== buf
|| bp
[-1] != '\r'))
656 if (UserContext() > 0)
657 UserReturn(unlink(BufferFile
) ? errno
: 0);
658 errno
= UserStatus();
659 Msg(errno
, "%s %sremoved", BufferFile
, errno
? "not " : "");
661 #endif /* COPY_PASTE */
665 * (Almost) secure open and fopen...
678 debug2("secfopen(%s, %s)\n", name
, mode
);
682 fi
= fopen(name
, mode
);
687 if (eff_uid
== real_uid
)
688 return fopen(name
, mode
);
689 if (mode
[0] && mode
[1] == '+')
692 flags
= (mode
[0] == 'r') ? O_RDONLY
: O_WRONLY
;
694 flags
|= O_CREAT
| O_TRUNC
;
695 else if (mode
[0] == 'a')
696 flags
|= O_CREAT
| O_APPEND
;
697 else if (mode
[0] != 'r')
702 if ((fd
= secopen(name
, flags
, 0666)) < 0)
704 if ((fi
= fdopen(fd
, mode
)) == 0)
715 secopen(name
, flags
, mode
)
726 debug3("secopen(%s, 0x%x, 0%03o)\n", name
, flags
, mode
);
730 fd
= open(name
, flags
, mode
);
735 if (eff_uid
== real_uid
)
736 return open(name
, flags
, mode
);
737 /* Truncation/creation is done in UserContext */
738 if ((flags
& O_TRUNC
) || ((flags
& O_CREAT
) && access(name
, F_OK
)))
740 if (UserContext() > 0)
742 if ((fd
= open(name
, flags
, mode
)) >= 0)
751 if ((q
= UserStatus()))
758 if (access(name
, F_OK
))
760 if ((fd
= open(name
, flags
& ~(O_TRUNC
| O_CREAT
), 0)) < 0)
762 debug("open successful\n");
768 debug("fstat successful\n");
769 if (stb
.st_uid
!= real_uid
)
771 switch (flags
& (O_RDONLY
| O_WRONLY
| O_RDWR
))
783 if ((stb
.st_mode
& q
) != q
)
785 debug1("secopen: permission denied (%03o)\n", stb
.st_mode
& 07777);
791 debug1("secopen ok - returning %d\n", fd
);
805 WMsg(p
, errno
, "printing pipe");
811 WMsg(p
, errno
, "printing fork");
814 display
= p
->w_pdisplay
;
817 if (dfp
&& dfp
!= stderr
)
823 if (setgid(real_gid
) || setuid(real_uid
))
824 Panic(errno
, "printpipe setuid");
826 signal(SIGPIPE
, SIG_DFL
);
828 execl("/bin/sh", "sh", "-c", cmd
, (char *)0);
829 Panic(errno
, "/bin/sh");
856 if (dfp
&& dfp
!= stderr
)
866 if (setgid(real_gid
) || setuid(real_uid
))
869 Panic(errno
, "setuid/setgid");
872 signal(SIGPIPE
, SIG_DFL
);
876 Panic(errno
, "%s", *cmdv
);