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>
36 extern struct display
*display
, *displays
;
37 extern struct win
*fore
;
38 extern struct layer
*flayer
;
39 extern int real_uid
, eff_uid
;
40 extern int real_gid
, eff_gid
;
41 extern char *extra_incap
, *extra_outcap
;
42 extern char *home
, *RcFileName
;
43 extern char SockPath
[], *SockName
;
45 extern char *BufferFile
;
47 extern int hardcopy_append
;
48 extern char *hardcopydir
;
50 static char *CatExtra
__P((char *, char *));
51 static char *findrcfile
__P((char *));
59 register char *str1
, *str2
;
62 register int len1
, len2
, add_colon
;
67 add_colon
= (str1
[len1
- 1] != ':');
71 if ((cp
= realloc(str2
, (unsigned) len1
+ len2
+ add_colon
+ 1)) == NULL
)
73 bcopy(cp
, cp
+ len1
+ add_colon
, len2
+ 1);
79 if ((cp
= malloc((unsigned) len1
+ add_colon
+ 1)) == NULL
)
81 cp
[len1
+ add_colon
] = '\0';
83 bcopy(str1
, cp
, len1
);
99 char *rcend
= rindex(rc_name
, '/');
100 if (*rcfile
!= '/' && rcend
&& (rcend
- rc_name
) + strlen(rcfile
) + 2 < sizeof(buf
))
102 strncpy(buf
, rc_name
, rcend
- rc_name
+ 1);
103 strcpy(buf
+ (rcend
- rc_name
) + 1, rcfile
);
104 if (access(buf
, R_OK
) == 0)
107 debug1("findrcfile: you specified '%s'\n", rcfile
);
108 return SaveStr(rcfile
);
110 debug("findrcfile: you specified nothing...\n");
111 if ((p
= getenv("SCREENRC")) != NULL
&& *p
!= '\0')
113 debug1(" $SCREENRC has: '%s'\n", p
);
118 debug(" ...nothing in $SCREENRC, defaulting $HOME/.screenrc\n");
119 if (strlen(home
) > sizeof(buf
) - 12)
120 Panic(0, "Rc: home too large");
121 sprintf(buf
, "%s/.screenrc", home
);
127 * this will be called twice:
128 * 1) rcfilename = "/etc/screenrc"
129 * 2) rcfilename = RcFileName
132 StartRc(rcfilename
, nopanic
)
136 register int argc
, len
;
137 register char *p
, *cp
;
142 char *oldrc_name
= rc_name
;
144 /* always fix termcap/info capabilities */
145 extra_incap
= CatExtra("TF", extra_incap
);
147 /* Special settings for vt100 and others */
148 if (display
&& (!strncmp(D_termname
, "vt", 2) || !strncmp(D_termname
, "xterm", 5)))
149 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
);
151 rc_name
= findrcfile(rcfilename
);
153 if ((fp
= secfopen(rc_name
, "r")) == NULL
)
155 if (!rc_recursion
&& RcFileName
&& !strcmp(RcFileName
, rc_name
))
158 * User explicitly gave us that name,
159 * this is the only case, where we get angry, if we can't read
162 debug3("StartRc: '%s','%s', '%s'\n", RcFileName
, rc_name
, rcfilename
);
163 if (!nopanic
) Panic(0, "Unable to open \"%s\".", rc_name
);
164 /* possibly NOTREACHED */
166 debug1("StartRc: '%s' no good. ignored\n", rc_name
);
168 rc_name
= oldrc_name
;
171 while (fgets(buf
, sizeof buf
, fp
) != NULL
)
173 if ((p
= rindex(buf
, '\n')) != NULL
)
175 if ((argc
= Parse(buf
, sizeof buf
, args
, argl
)) == 0)
177 if (strcmp(args
[0], "echo") == 0)
181 if (argc
< 2 || (argc
== 3 && strcmp(args
[1], "-n")) || argc
> 3)
183 Msg(0, "%s: 'echo [-n] \"string\"' expected.", rc_name
);
186 AddStr(args
[argc
- 1]);
193 else if (strcmp(args
[0], "sleep") == 0)
197 debug("sleeeeeeep\n");
200 Msg(0, "%s: sleep: one numeric argument expected.", rc_name
);
203 DisplaySleep1000(1000 * atoi(args
[1]), 1);
206 else if (!strcmp(args
[0], "termcapinfo") || !strcmp(args
[0], "terminfo"))
208 else if (!strcmp(args
[0], "termcapinfo") || !strcmp(args
[0], "termcap"))
213 if (argc
< 3 || argc
> 4)
215 Msg(0, "%s: %s: incorrect number of arguments.", rc_name
, args
[0]);
218 for (p
= args
[1]; p
&& *p
; p
= cp
)
220 if ((cp
= index(p
, '|')) != 0)
223 if (p
[len
- 1] == '*')
225 if (!(len
- 1) || !strncmp(p
, D_termname
, len
- 1))
228 else if (!strcmp(p
, D_termname
))
233 extra_incap
= CatExtra(args
[2], extra_incap
);
235 extra_outcap
= CatExtra(args
[3], extra_outcap
);
237 else if (!strcmp(args
[0], "source"))
239 if (rc_recursion
<= 10)
242 (void)StartRc(args
[1], 0);
249 rc_name
= oldrc_name
;
259 char *oldrc_name
= rc_name
;
261 rc_name
= findrcfile(rcfilename
);
263 if ((fp
= secfopen(rc_name
, "r")) == NULL
)
266 Msg(errno
, "%s: source %s", oldrc_name
, rc_name
);
267 else if (RcFileName
&& !strcmp(RcFileName
, rc_name
))
270 * User explicitly gave us that name,
271 * this is the only case, where we get angry, if we can't read
274 debug3("FinishRc:'%s','%s','%s'\n", RcFileName
, rc_name
, rcfilename
);
275 Panic(0, "Unable to open \"%s\".", rc_name
);
278 debug1("FinishRc: '%s' no good. ignored\n", rc_name
);
280 rc_name
= oldrc_name
;
284 debug("finishrc is going...\n");
285 while (fgets(buf
, sizeof buf
, fp
) != NULL
)
286 RcLine(buf
, sizeof buf
);
289 rc_name
= oldrc_name
;
293 do_source(rcfilename
)
296 if (rc_recursion
> 10)
298 Msg(0, "%s: source: recursion limit reached", rc_name
);
302 FinishRc(rcfilename
);
308 * Running a Command Line in the environment determined by the display.
309 * The fore window is taken from the display as well as the user.
310 * This is bad when we run detached.
320 extern struct acluser
*EffectiveAclUser
; /* acl.c */
321 extern struct acluser
*users
; /* acl.c */
327 flayer
= D_forecv
->c_layer
;
330 flayer
= fore
? fore
->w_savelayer
: 0;
331 if (Parse(ubuf
, ubufl
, args
, argl
) <= 0)
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");
341 DoCommand(args
, argl
);
343 EffectiveAclUser
= 0;
348 * needs display for copybuffer access and termcap dumping
351 WriteFile(user
, fn
, dump
)
352 struct acluser
*user
;
356 /* dump==0: create .termcap,
359 * dump==2: BUFFERFILE
361 * dump==1: scrollback,
363 register int i
, j
, k
;
376 struct stat stb
, stb2
;
386 i
= SockName
- SockPath
;
387 if (i
> (int)sizeof(fnbuf
) - 9)
389 strncpy(fnbuf
, SockPath
, i
);
390 strcpy(fnbuf
+ i
, ".termcap");
395 case DUMP_SCROLLBACK
:
400 if (hardcopydir
&& *hardcopydir
&& strlen(hardcopydir
) < sizeof(fnbuf
) - 21)
401 sprintf(fnbuf
, "%s/hardcopy.%d", hardcopydir
, fore
->w_number
);
403 sprintf(fnbuf
, "hardcopy.%d", fore
->w_number
);
406 if (hardcopy_append
&& !access(fn
, W_OK
))
413 strncpy(fnbuf
, BufferFile
, sizeof(fnbuf
) - 1);
414 fnbuf
[sizeof(fnbuf
) - 1] = 0;
417 public = !strcmp(fn
, DEFAULT_BUFFERFILE
);
419 exists
= !lstat(fn
, &stb
);
420 if (public && exists
&& (S_ISLNK(stb
.st_mode
) || stb
.st_nlink
> 1))
422 Msg(0, "No write to links, please.");
430 debug2("WriteFile(%d) %s\n", dump
, fn
);
431 if (UserContext() > 0)
433 debug("Writefile: usercontext\n");
435 if (dump
== DUMP_EXCHANGE
&& public)
437 old_umask
= umask(0);
441 if ((fd
= open(fn
, O_WRONLY
, 0666)) >= 0)
443 if (fstat(fd
, &stb2
) == 0 && stb
.st_dev
== stb2
.st_dev
&& stb
.st_ino
== stb2
.st_ino
)
453 fd
= open(fn
, O_WRONLY
|O_CREAT
|O_EXCL
, 0666);
454 f
= fd
>= 0 ? fdopen(fd
, mode
) : 0;
461 #endif /* COPY_PASTE */
465 debug2("WriteFile: fopen(%s,\"%s\") failed\n", fn
, mode
);
473 case DUMP_SCROLLBACK
:
479 for (j
= fore
->w_width
- 2; j
> 0; j
--)
483 if (dump
== DUMP_SCROLLBACK
)
485 for (i
= 0; i
< fore
->w_histheight
; i
++)
487 p
= (char *)(WIN(i
)->image
);
488 for (k
= fore
->w_width
- 1; k
>= 0 && p
[k
] == ' '; k
--)
490 for (j
= 0; j
<= k
; j
++)
495 for (i
= 0; i
< fore
->w_height
; i
++)
497 p
= (char *)fore
->w_mlines
[i
].image
;
498 for (k
= fore
->w_width
- 1; k
>= 0 && p
[k
] == ' '; k
--)
500 for (j
= 0; j
<= k
; j
++)
506 if ((p
= index(MakeTermcap(fore
->w_aflag
), '=')) != NULL
)
514 p
= user
->u_plop
.buf
;
515 for (i
= user
->u_plop
.len
; i
-- > 0; p
++)
516 if (*p
== '\r' && (i
== 0 || p
[1] != '\n'))
527 if (UserStatus() <= 0)
528 Msg(0, "Cannot open \"%s\"", fn
);
529 else if (display
&& !*rc_name
)
534 Msg(0, "Termcap entry written to \"%s\".", fn
);
537 case DUMP_SCROLLBACK
:
538 Msg(0, "Screen image %s to \"%s\".",
539 (*mode
== 'a') ? "appended" : "written", fn
);
543 Msg(0, "Copybuffer written to \"%s\".", fn
);
552 * returns an allocated buffer which holds a copy of the file named fn.
553 * lenp (if nonzero) points to a location, where the buffer size should be
566 debug1("ReadFile(%s)\n", fn
);
567 if ((i
= secopen(fn
, O_RDONLY
, 0)) < 0)
569 Msg(errno
, "no %s -- no slurp", fn
);
574 Msg(errno
, "no good %s -- no slurp", fn
);
579 if ((buf
= malloc(size
)) == NULL
)
586 if ((l
= read(i
, buf
, size
)) != size
)
590 Msg(errno
, "Got only %d bytes from %s", l
, fn
);
595 if (read(i
, &c
, 1) > 0)
596 Msg(0, "Slurped only %d characters (of %d) into buffer - try again",
599 Msg(0, "Slurped %d characters into buffer", l
);
603 for (bp
= buf
; l
-- > 0; bp
++)
604 if (*bp
== '\n' && (bp
== buf
|| bp
[-1] != '\r'))
612 if (UserContext() > 0)
613 UserReturn(unlink(BufferFile
) ? errno
: 0);
614 errno
= UserStatus();
615 Msg(errno
, "%s %sremoved", BufferFile
, errno
? "not " : "");
617 #endif /* COPY_PASTE */
621 * (Almost) secure open and fopen...
634 debug2("secfopen(%s, %s)\n", name
, mode
);
638 fi
= fopen(name
, mode
);
643 if (eff_uid
== real_uid
)
644 return fopen(name
, mode
);
645 if (mode
[0] && mode
[1] == '+')
648 flags
= (mode
[0] == 'r') ? O_RDONLY
: O_WRONLY
;
650 flags
|= O_CREAT
| O_TRUNC
;
651 else if (mode
[0] == 'a')
652 flags
|= O_CREAT
| O_APPEND
;
653 else if (mode
[0] != 'r')
658 if ((fd
= secopen(name
, flags
, 0666)) < 0)
660 if ((fi
= fdopen(fd
, mode
)) == 0)
671 secopen(name
, flags
, mode
)
682 debug3("secopen(%s, 0x%x, 0%03o)\n", name
, flags
, mode
);
686 fd
= open(name
, flags
, mode
);
691 if (eff_uid
== real_uid
)
692 return open(name
, flags
, mode
);
693 /* Truncation/creation is done in UserContext */
694 if ((flags
& O_TRUNC
) || ((flags
& O_CREAT
) && access(name
, F_OK
)))
696 if (UserContext() > 0)
698 if ((fd
= open(name
, flags
, mode
)) >= 0)
707 if ((q
= UserStatus()))
714 if (access(name
, F_OK
))
716 if ((fd
= open(name
, flags
& ~(O_TRUNC
| O_CREAT
), 0)) < 0)
718 debug("open successful\n");
724 debug("fstat successful\n");
725 if (stb
.st_uid
!= real_uid
)
727 switch (flags
& (O_RDONLY
| O_WRONLY
| O_RDWR
))
739 if ((stb
.st_mode
& q
) != q
)
741 debug1("secopen: permission denied (%03o)\n", stb
.st_mode
& 07777);
747 debug1("secopen ok - returning %d\n", fd
);
761 WMsg(p
, errno
, "printing pipe");
767 WMsg(p
, errno
, "printing fork");
770 display
= p
->w_pdisplay
;
773 if (dfp
&& dfp
!= stderr
)
779 if (setgid(real_gid
) || setuid(real_uid
))
780 Panic(errno
, "printpipe setuid");
782 signal(SIGPIPE
, SIG_DFL
);
784 execl("/bin/sh", "sh", "-c", cmd
, (char *)0);
785 Panic(errno
, "/bin/sh");
812 if (dfp
&& dfp
!= stderr
)
822 if (setgid(real_gid
) || setuid(real_uid
))
825 Panic(errno
, "setuid/setgid");
828 signal(SIGPIPE
, SIG_DFL
);