fileio.c (screen-4.8.0) | : | fileio.c (screen-4.9.0) | ||
---|---|---|---|---|
skipping to change at line 45 | skipping to change at line 45 | |||
# include <signal.h> | # include <signal.h> | |||
#endif | #endif | |||
#include "config.h" | #include "config.h" | |||
#include "screen.h" | #include "screen.h" | |||
#include "extern.h" | #include "extern.h" | |||
extern struct display *display, *displays; | extern struct display *display, *displays; | |||
extern struct win *fore; | extern struct win *fore; | |||
extern struct layer *flayer; | extern struct layer *flayer; | |||
extern int ServerSocket; | extern int ServerSocket; | |||
extern int real_uid, eff_uid; | extern int real_uid, eff_uid; | |||
extern int real_gid, eff_gid; | extern int real_gid, eff_gid; | |||
extern char *extra_incap, *extra_outcap; | extern char *extra_incap, *extra_outcap; | |||
extern char *home, *RcFileName; | extern char *home, *RcFileName; | |||
extern char SockPath[], *SockName; | extern char SockPath[], *SockName; | |||
#ifdef COPY_PASTE | #ifdef COPY_PASTE | |||
extern char *BufferFile; | extern char *BufferFile; | |||
#endif | #endif | |||
extern int hardcopy_append; | extern int hardcopy_append; | |||
extern char *hardcopydir; | extern char *hardcopydir; | |||
static char *CatExtra __P((char *, char *)); | static char *CatExtra __P((char *, char *)); | |||
static char *findrcfile __P((char *)); | static char *findrcfile __P((char *)); | |||
char *rc_name = ""; | char *rc_name = ""; | |||
int rc_recursion = 0; | int rc_recursion = 0; | |||
static char * CatExtra(register char *str1, register char *str2) { | static char * | |||
register char *cp; | CatExtra(register char *str1, register char *str2) | |||
register int len1, len2, add_colon; | { | |||
register char *cp; | ||||
len1 = strlen(str1); | register int len1, len2, add_colon; | |||
if (len1 == 0) | ||||
return str2; | len1 = strlen(str1); | |||
add_colon = (str1[len1 - 1] != ':'); | if (len1 == 0) | |||
if (str2) { | return str2; | |||
len2 = strlen(str2); | add_colon = (str1[len1 - 1] != ':'); | |||
if ((cp = realloc(str2, (unsigned) len1 + len2 + add_colon + 1)) == NULL) | if (str2) { | |||
Panic(0, "%s", strnomem); | len2 = strlen(str2); | |||
bcopy(cp, cp + len1 + add_colon, len2 + 1); | if ((cp = realloc(str2, (unsigned)len1 + len2 + add_colon + 1)) = | |||
} | = NULL) | |||
else { | Panic(0, "%s", strnomem); | |||
if ((cp = malloc((unsigned) len1 + add_colon + 1)) == NULL) | bcopy(cp, cp + len1 + add_colon, len2 + 1); | |||
Panic(0, "%s", strnomem); | } else { | |||
cp[len1 + add_colon] = '\0'; | if ((cp = malloc((unsigned)len1 + add_colon + 1)) == NULL) | |||
} | Panic(0, "%s", strnomem); | |||
bcopy(str1, cp, len1); | cp[len1 + add_colon] = '\0'; | |||
if (add_colon) | } | |||
cp[len1] = ':'; | bcopy(str1, cp, len1); | |||
return cp; | if (add_colon) | |||
} | cp[len1] = ':'; | |||
return cp; | ||||
static char *findrcfile(char *rcfile) { | } | |||
char buf[256]; | ||||
char *p; | static char * | |||
findrcfile(char *rcfile) | ||||
/* Tilde prefix support courtesy <hesso@pool.math.tu-berlin.de>, | { | |||
* taken from a Debian patch. */ | char buf[256]; | |||
if (rcfile && *rcfile == '~') { | char *p; | |||
static char rcfilename_tilde_exp[MAXPATHLEN+1]; | ||||
char *slash_position = strchr(rcfile, '/'); | /* Tilde prefix support courtesy <hesso@pool.math.tu-berlin.de>, | |||
* taken from a Debian patch. */ | ||||
if (slash_position == rcfile+1) { | if (rcfile && *rcfile == '~') { | |||
char *home = getenv("HOME"); | static char rcfilename_tilde_exp[MAXPATHLEN + 1]; | |||
if (!home) { | char *slash_position = strchr(rcfile, '/'); | |||
Msg(0, "%s: source: tilde expansion failed", rc_name); | ||||
return NULL; | if (slash_position == rcfile + 1) { | |||
} | char *home = getenv("HOME"); | |||
snprintf(rcfilename_tilde_exp, MAXPATHLEN, "%s/%s", home, rcfile+2); | if (!home) { | |||
} | Msg(0, "%s: source: tilde expansion failed", rc_n | |||
else if (slash_position) { | ame); | |||
struct passwd *p; | return NULL; | |||
*slash_position = 0; | } | |||
p = getpwnam(rcfile+1); | snprintf(rcfilename_tilde_exp, MAXPATHLEN, "%s/%s", home, | |||
if (!p){ | rcfile + 2); | |||
Msg(0, "%s: source: tilde expansion failed for user %s", rc_name, rcfile | } else if (slash_position) { | |||
+1); | struct passwd *p; | |||
return NULL; | *slash_position = 0; | |||
} | p = getpwnam(rcfile + 1); | |||
snprintf(rcfilename_tilde_exp, MAXPATHLEN, "%s/%s", p->pw_dir, slash_posit | if (!p) { | |||
ion+1); | Msg(0, "%s: source: tilde expansion failed for us | |||
} | er %s", rc_name, rcfile + 1); | |||
else { | return NULL; | |||
Msg(0, "%s: source: illegal tilde expression.", rc_name); | } | |||
return NULL; | snprintf(rcfilename_tilde_exp, MAXPATHLEN, "%s/%s", p->pw | |||
} | _dir, slash_position + 1); | |||
rcfile = rcfilename_tilde_exp; | } else { | |||
} | Msg(0, "%s: source: illegal tilde expression.", rc_name); | |||
return NULL; | ||||
if (rcfile) { | } | |||
char *rcend = rindex(rc_name, '/'); | rcfile = rcfilename_tilde_exp; | |||
if (*rcfile != '/' && rcend && (rcend - rc_name) + strlen(rcfile) + 2 < size | } | |||
of(buf)) { | ||||
strncpy(buf, rc_name, rcend - rc_name + 1); | if (rcfile) { | |||
strcpy(buf + (rcend - rc_name) + 1, rcfile); | char *rcend = rindex(rc_name, '/'); | |||
if (access(buf, R_OK) == 0) | if (*rcfile != '/' && rcend && (rcend - rc_name) + strlen(rcfile) | |||
return SaveStr(buf); | + 2 < sizeof(buf)) { | |||
} | strncpy(buf, rc_name, rcend - rc_name + 1); | |||
debug1("findrcfile: you specified '%s'\n", rcfile); | strcpy(buf + (rcend - rc_name) + 1, rcfile); | |||
return SaveStr(rcfile); | if (access(buf, R_OK) == 0) | |||
} | return SaveStr(buf); | |||
} | ||||
debug("findrcfile: you specified nothing...\n"); | debug1("findrcfile: you specified '%s'\n", rcfile); | |||
if ((p = getenv("SCREENRC")) != NULL && *p != '\0') { | return SaveStr(rcfile); | |||
debug1(" $SCREENRC has: '%s'\n", p); | } | |||
return SaveStr(p); | ||||
} | debug("findrcfile: you specified nothing...\n"); | |||
else { | if ((p = getenv("SCREENRC")) != NULL && *p != '\0') { | |||
debug(" ...nothing in $SCREENRC, defaulting $HOME/.screenrc\n"); | debug1(" $SCREENRC has: '%s'\n", p); | |||
if (strlen(home) > sizeof(buf) - 12) | return SaveStr(p); | |||
Panic(0, "Rc: home too large"); | } else { | |||
sprintf(buf, "%s/.screenrc", home); | debug(" ...nothing in $SCREENRC, defaulting $HOME/.screenrc\n"); | |||
return SaveStr(buf); | if (strlen(home) > sizeof(buf) - 12) | |||
} | Panic(0, "Rc: home too large"); | |||
sprintf(buf, "%s/.screenrc", home); | ||||
return SaveStr(buf); | ||||
} | ||||
} | } | |||
/* | /* | |||
* this will be called twice: | * this will be called twice: | |||
* 1) rcfilename = "/etc/screenrc" | * 1) rcfilename = "/etc/screenrc" | |||
* 2) rcfilename = RcFileName | * 2) rcfilename = RcFileName | |||
*/ | */ | |||
int StartRc(char *rcfilename, int nopanic) { | int | |||
register int argc, len; | StartRc(char *rcfilename, int nopanic) | |||
register char *p, *cp; | { | |||
char buf[2048]; | register int argc, len; | |||
char *args[MAXARGS]; | register char *p, *cp; | |||
int argl[MAXARGS]; | char buf[2048]; | |||
FILE *fp; | char *args[MAXARGS]; | |||
char *oldrc_name = rc_name; | int argl[MAXARGS]; | |||
FILE *fp; | ||||
/* always fix termcap/info capabilities */ | char *oldrc_name = rc_name; | |||
extra_incap = CatExtra("TF", extra_incap); | ||||
/* always fix termcap/info capabilities */ | ||||
/* Special settings for vt100 and others */ | extra_incap = CatExtra("TF", extra_incap); | |||
if (display && (!strncmp(D_termname, "vt", 2) || !strncmp(D_termname, "xterm", | ||||
5))) | /* Special settings for vt100 and others */ | |||
extra_incap = CatExtra("xn:f0=\033Op:f1=\033Oq:f2=\033Or:f3=\033Os:f4=\033Ot | if (display && (!strncmp(D_termname, "vt", 2) || !strncmp(D_termname, "xt | |||
:f5=\033Ou:f6=\033Ov:f7=\033Ow:f8=\033Ox:f9=\033Oy:f.=\033On:f,=\033Ol:fe=\033OM | erm", 5))) | |||
:f+=\033Ok:f-=\033Om:f*=\033Oj:f/=\033Oo:fq=\033OX", extra_incap); | extra_incap = CatExtra("xn:f0=\033Op:f1=\033Oq:f2=\033Or:f3=\033O | |||
s:f4=\033Ot:f5=\033Ou:f6=\033Ov:f7=\033Ow:f8=\033Ox:f9=\033Oy:f.=\033On:f,=\033O | ||||
rc_name = findrcfile(rcfilename); | l:fe=\033OM:f+=\033Ok:f-=\033Om:f*=\033Oj:f/=\033Oo:fq=\033OX", extra_incap); | |||
if (rc_name == NULL || (fp = secfopen(rc_name, "r")) == NULL) { | ||||
const char *rc_nonnull = rc_name ? rc_name : rcfilename; | rc_name = findrcfile(rcfilename); | |||
if (!rc_recursion && RcFileName && !strcmp(RcFileName, rc_nonnull)) { | if (rc_name == NULL || (fp = secfopen(rc_name, "r")) == NULL) { | |||
/* | const char *rc_nonnull = rc_name ? rc_name : rcfilename; | |||
* User explicitly gave us that name, | if (!rc_recursion && RcFileName && !strcmp(RcFileName, rc_nonnull | |||
* this is the only case, where we get angry, if we can't read | )) { | |||
* the file. | /* | |||
*/ | * User explicitly gave us that name, | |||
debug3("StartRc: '%s','%s', '%s'\n", RcFileName, rc_name ? rc_name : "(nul | * this is the only case, where we get angry, if we can't read | |||
l)", rcfilename); | * the file. | |||
if (!nopanic) Panic(0, "Unable to open \"%s\".", rc_nonnull); | */ | |||
/* possibly NOTREACHED */ | debug3("StartRc: '%s','%s', '%s'\n", RcFileName, rc_name | |||
} | ? rc_name : "(null)", rcfilename); | |||
if (!nopanic) | ||||
debug1("StartRc: '%s' no good. ignored\n", rc_nonnull); | Panic(0, "Unable to open \"%s\".", rc_nonnull); | |||
if (rc_name) | /* possibly NOTREACHED */ | |||
Free(rc_name); | } | |||
rc_name = oldrc_name; | ||||
return 1; | debug1("StartRc: '%s' no good. ignored\n", rc_nonnull); | |||
} | if (rc_name) | |||
while (fgets(buf, sizeof buf, fp) != NULL) { | Free(rc_name); | |||
if ((p = rindex(buf, '\n')) != NULL) | rc_name = oldrc_name; | |||
*p = '\0'; | return 1; | |||
} | ||||
if ((argc = Parse(buf, sizeof buf, args, argl)) == 0) | while (fgets(buf, sizeof buf, fp) != NULL) { | |||
continue; | if ((p = rindex(buf, '\n')) != NULL) | |||
*p = '\0'; | ||||
if (strcmp(args[0], "echo") == 0) { | ||||
if (!display) | if ((argc = Parse(buf, sizeof buf, args, argl)) == 0) | |||
continue; | continue; | |||
if (argc < 2 || (argc == 3 && strcmp(args[1], "-n")) || argc > 3) { | ||||
Msg(0, "%s: 'echo [-n] \"string\"' expected.", rc_name); | if (strcmp(args[0], "echo") == 0) { | |||
continue; | if (!display) | |||
} | continue; | |||
AddStr(args[argc - 1]); | if (argc < 2 || (argc == 3 && strcmp(args[1], "-n")) || a | |||
if (argc != 3) { | rgc > 3) { | |||
AddStr("\r\n"); | Msg(0, "%s: 'echo [-n] \"string\"' expected.", rc | |||
Flush(0); | _name); | |||
} | continue; | |||
} | } | |||
AddStr(args[argc - 1]); | ||||
else if (strcmp(args[0], "sleep") == 0) { | if (argc != 3) { | |||
if (!display) | AddStr("\r\n"); | |||
continue; | Flush(0); | |||
debug("sleeeeeeep\n"); | } | |||
if (argc != 2) { | } else if (strcmp(args[0], "sleep") == 0) { | |||
Msg(0, "%s: sleep: one numeric argument expected.", rc_name); | if (!display) | |||
continue; | continue; | |||
} | debug("sleeeeeeep\n"); | |||
DisplaySleep1000(1000 * atoi(args[1]), 1); | if (argc != 2) { | |||
} | Msg(0, "%s: sleep: one numeric argument expected. | |||
", rc_name); | ||||
continue; | ||||
} | ||||
DisplaySleep1000(1000 * atoi(args[1]), 1); | ||||
} | ||||
#ifdef TERMINFO | #ifdef TERMINFO | |||
else if (!strcmp(args[0], "termcapinfo") || !strcmp(args[0], "terminfo")) { | else if (!strcmp(args[0], "termcapinfo") || !strcmp(args[0], "terminfo")) { | |||
#else | #else | |||
else if (!strcmp(args[0], "termcapinfo") || !strcmp(args[0], "termcap")) { | else if (!strcmp(args[0], "termcapinfo") || !strcmp(args[0], "ter mcap")) { | |||
#endif | #endif | |||
if (!display) | if (!display) | |||
continue; | continue; | |||
if (argc < 3 || argc > 4) { | if (argc < 3 || argc > 4) { | |||
Msg(0, "%s: %s: incorrect number of arguments.", rc_name, args[0]); | Msg(0, "%s: %s: incorrect number of arguments.", | |||
continue; | rc_name, args[0]); | |||
} | continue; | |||
} | ||||
for (p = args[1]; p && *p; p = cp) { | ||||
if ((cp = index(p, '|')) != 0) | for (p = args[1]; p && *p; p = cp) { | |||
*cp++ = '\0'; | if ((cp = index(p, '|')) != 0) | |||
len = strlen(p); | *cp++ = '\0'; | |||
if (p[len - 1] == '*') { | len = strlen(p); | |||
if (!(len - 1) || !strncmp(p, D_termname, len - 1)) | if (p[len - 1] == '*') { | |||
break; | if (!(len - 1) || !strncmp(p, D_termname, | |||
} | len - 1)) | |||
else if (!strcmp(p, D_termname)) | break; | |||
break; | } else if (!strcmp(p, D_termname)) | |||
} | break; | |||
if (!(p && *p)) | } | |||
continue; | if (!(p && *p)) | |||
extra_incap = CatExtra(args[2], extra_incap); | continue; | |||
if (argc == 4) | extra_incap = CatExtra(args[2], extra_incap); | |||
extra_outcap = CatExtra(args[3], extra_outcap); | if (argc == 4) | |||
} | extra_outcap = CatExtra(args[3], extra_outcap); | |||
else if (!strcmp(args[0], "source")) { | } else if (!strcmp(args[0], "source")) { | |||
if (rc_recursion <= 10) { | if (rc_recursion <= 10) { | |||
rc_recursion++; | rc_recursion++; | |||
(void)StartRc(args[1], 0); | (void)StartRc(args[1], 0); | |||
rc_recursion--; | rc_recursion--; | |||
} | } | |||
} | } | |||
} | } | |||
fclose(fp); | fclose(fp); | |||
Free(rc_name); | Free(rc_name); | |||
rc_name = oldrc_name; | rc_name = oldrc_name; | |||
return 0; | return 0; | |||
} | } | |||
void FinishRc(char *rcfilename) { | void | |||
char buf[2048]; | FinishRc(char *rcfilename) | |||
FILE *fp; | { | |||
char *oldrc_name = rc_name; | char buf[2048]; | |||
FILE *fp; | ||||
rc_name = findrcfile(rcfilename); | char *oldrc_name = rc_name; | |||
if (rc_name == NULL || (fp = secfopen(rc_name, "r")) == NULL) { | rc_name = findrcfile(rcfilename); | |||
const char *rc_nonnull = rc_name ? rc_name : rcfilename; | ||||
if (rc_recursion) | if (rc_name == NULL || (fp = secfopen(rc_name, "r")) == NULL) { | |||
Msg(errno, "%s: source %s", oldrc_name, rc_nonnull); | const char *rc_nonnull = rc_name ? rc_name : rcfilename; | |||
else if (RcFileName && !strcmp(RcFileName, rc_nonnull)) { | if (rc_recursion) | |||
Msg(errno, "%s: source %s", oldrc_name, rc_nonnull); | ||||
else if (RcFileName && !strcmp(RcFileName, rc_nonnull)) { | ||||
/* | /* | |||
* User explicitly gave us that name, | * User explicitly gave us that name, | |||
* this is the only case, where we get angry, if we can't read | * this is the only case, where we get angry, if we can't read | |||
* the file. | * the file. | |||
*/ | */ | |||
debug3("FinishRc:'%s','%s','%s'\n", RcFileName, rc_name ? rc_name : "(nul | debug3("FinishRc:'%s','%s','%s'\n", RcFileName, rc_name ? | |||
l)", rcfilename); | rc_name : "(null)", rcfilename); | |||
Panic(0, "Unable to open \"%s\".", rc_nonnull); | Panic(0, "Unable to open \"%s\".", rc_nonnull); | |||
/* NOTREACHED */ | /* NOTREACHED */ | |||
} | } | |||
debug1("FinishRc: '%s' no good. ignored\n", rc_nonnull); | debug1("FinishRc: '%s' no good. ignored\n", rc_nonnull); | |||
if (rc_name) | if (rc_name) | |||
Free(rc_name); | Free(rc_name); | |||
rc_name = oldrc_name; | rc_name = oldrc_name; | |||
return; | return; | |||
} | } | |||
debug("finishrc is going...\n"); | debug("finishrc is going...\n"); | |||
while (fgets(buf, sizeof buf, fp) != NULL) | while (fgets(buf, sizeof buf, fp) != NULL) | |||
RcLine(buf, sizeof buf); | RcLine(buf, sizeof buf); | |||
(void) fclose(fp); | (void)fclose(fp); | |||
Free(rc_name); | Free(rc_name); | |||
rc_name = oldrc_name; | rc_name = oldrc_name; | |||
} | } | |||
void do_source(char *rcfilename) { | void | |||
if (rc_recursion > 10) { | do_source(char *rcfilename) | |||
Msg(0, "%s: source: recursion limit reached", rc_name); | { | |||
return; | if (rc_recursion > 10) { | |||
} | Msg(0, "%s: source: recursion limit reached", rc_name); | |||
rc_recursion++; | return; | |||
FinishRc(rcfilename); | } | |||
rc_recursion--; | rc_recursion++; | |||
FinishRc(rcfilename); | ||||
rc_recursion--; | ||||
} | } | |||
/* | /* | |||
* Running a Command Line in the environment determined by the display. | * Running a Command Line in the environment determined by the display. | |||
* The fore window is taken from the display as well as the user. | * The fore window is taken from the display as well as the user. | |||
* This is bad when we run detached. | * This is bad when we run detached. | |||
*/ | */ | |||
void RcLine(char *ubuf, int ubufl) { | void | |||
char *args[MAXARGS]; | RcLine(char *ubuf, int ubufl) | |||
int argl[MAXARGS]; | { | |||
char *args[MAXARGS]; | ||||
int argl[MAXARGS]; | ||||
#ifdef MULTIUSER | #ifdef MULTIUSER | |||
extern struct acluser *EffectiveAclUser; /* acl.c */ | extern struct acluser *EffectiveAclUser; /* acl.c */ | |||
extern struct acluser *users; /* acl.c */ | extern struct acluser *users; /* acl.c */ | |||
#endif | #endif | |||
if (display) { | if (display) { | |||
fore = D_fore; | fore = D_fore; | |||
flayer = D_forecv->c_layer; | flayer = D_forecv->c_layer; | |||
} | } else | |||
else | flayer = fore ? fore->w_savelayer : 0; | |||
flayer = fore ? fore->w_savelayer : 0; | if (Parse(ubuf, ubufl, args, argl) <= 0) | |||
if (Parse(ubuf, ubufl, args, argl) <= 0) | return; | |||
return; | ||||
#ifdef MULTIUSER | #ifdef MULTIUSER | |||
if (!display) { | if (!display) { | |||
/* the session owner does it, when there is no display here */ | /* the session owner does it, when there is no display here */ | |||
EffectiveAclUser = users; | EffectiveAclUser = users; | |||
debug("RcLine: WARNING, no display no user! Session owner executes command | debug("RcLine: WARNING, no display no user! Session owner execute | |||
\n"); | s command\n"); | |||
} | } | |||
#endif | #endif | |||
DoCommand(args, argl); | DoCommand(args, argl); | |||
#ifdef MULTIUSER | #ifdef MULTIUSER | |||
EffectiveAclUser = 0; | EffectiveAclUser = 0; | |||
#endif | #endif | |||
} | } | |||
/* needs display for copybuffer access and termcap dumping */ | /* needs display for copybuffer access and termcap dumping */ | |||
void WriteFile(struct acluser *user, char *fn, int dump) { | void | |||
WriteFile(struct acluser *user, char *fn, int dump) | ||||
{ | ||||
/* dump==0: create .termcap, | /* dump==0: create .termcap, | |||
* dump==1: hardcopy, | * dump==1: hardcopy, | |||
* #ifdef COPY_PASTE | * #ifdef COPY_PASTE | |||
* dump==2: BUFFERFILE | * dump==2: BUFFERFILE | |||
* #endif COPY_PASTE | * #endif COPY_PASTE | |||
* dump==1: scrollback, | * dump==1: scrollback, | |||
*/ | */ | |||
register int i, j, k; | register int i, j, k; | |||
register char *p; | register char *p; | |||
register FILE *f; | register FILE *f; | |||
char fnbuf[1024]; | char fnbuf[1024]; | |||
char *mode = "w"; | char *mode = "w"; | |||
#ifdef COPY_PASTE | #ifdef COPY_PASTE | |||
int public = 0; | int public = 0; | |||
# ifdef HAVE_LSTAT | # ifdef HAVE_LSTAT | |||
struct stat stb, stb2; | struct stat stb, stb2; | |||
int fd, exists = 0; | int fd, exists = 0; | |||
# endif | # endif | |||
#endif | #endif | |||
switch (dump) { | switch (dump) { | |||
case DUMP_TERMCAP: | case DUMP_TERMCAP: | |||
if (fn == 0) { | if (fn == 0) { | |||
i = SockName - SockPath; | i = SockName - SockPath; | |||
if (i > (int)sizeof(fnbuf) - 9) | if (i > (int)sizeof(fnbuf) - 9) | |||
i = 0; | i = 0; | |||
strncpy(fnbuf, SockPath, i); | strncpy(fnbuf, SockPath, i); | |||
strcpy(fnbuf + i, ".termcap"); | strcpy(fnbuf + i, ".termcap"); | |||
fn = fnbuf; | fn = fnbuf; | |||
} | } | |||
break; | break; | |||
case DUMP_HARDCOPY: | case DUMP_HARDCOPY: | |||
case DUMP_SCROLLBACK: | case DUMP_SCROLLBACK: | |||
if (fn == 0) { | if (fn == 0) { | |||
if (fore == 0) | if (fore == 0) | |||
return; | return; | |||
if (hardcopydir && *hardcopydir && strlen(hardcopydir) < sizeof(fnbuf) - | if (hardcopydir && *hardcopydir && strlen(hardcopydir) < | |||
21) | sizeof(fnbuf) - 21) | |||
sprintf(fnbuf, "%s/hardcopy.%d", hardcopydir, fore->w_number); | sprintf(fnbuf, "%s/hardcopy.%d", hardcopydir, for | |||
else | e->w_number); | |||
sprintf(fnbuf, "hardcopy.%d", fore->w_number); | else | |||
fn = fnbuf; | sprintf(fnbuf, "hardcopy.%d", fore->w_number); | |||
} | fn = fnbuf; | |||
if (hardcopy_append && !access(fn, W_OK)) | } | |||
mode = "a"; | if (hardcopy_append && !access(fn, W_OK)) | |||
break; | mode = "a"; | |||
break; | ||||
#ifdef COPY_PASTE | #ifdef COPY_PASTE | |||
case DUMP_EXCHANGE: | case DUMP_EXCHANGE: | |||
if (fn == 0) { | if (fn == 0) { | |||
strncpy(fnbuf, BufferFile, sizeof(fnbuf) - 1); | strncpy(fnbuf, BufferFile, sizeof(fnbuf) - 1); | |||
fnbuf[sizeof(fnbuf) - 1] = 0; | fnbuf[sizeof(fnbuf) - 1] = 0; | |||
fn = fnbuf; | fn = fnbuf; | |||
} | } | |||
public = !strcmp(fn, DEFAULT_BUFFERFILE); | public = !strcmp(fn, DEFAULT_BUFFERFILE); | |||
# ifdef HAVE_LSTAT | # ifdef HAVE_LSTAT | |||
exists = !lstat(fn, &stb); | exists = !lstat(fn, &stb); | |||
if (public && exists && (S_ISLNK(stb.st_mode) || stb.st_nlink > 1)) { | if (public && exists && (S_ISLNK(stb.st_mode) || stb.st_nlink > 1 | |||
Msg(0, "No write to links, please."); | )) { | |||
return; | Msg(0, "No write to links, please."); | |||
} | return; | |||
} | ||||
# endif | # endif | |||
break; | break; | |||
#endif | #endif | |||
} | } | |||
debug2("WriteFile(%d) %s\n", dump, fn); | debug2("WriteFile(%d) %s\n", dump, fn); | |||
if (UserContext() > 0) { | if (UserContext() > 0) { | |||
debug("Writefile: usercontext\n"); | debug("Writefile: usercontext\n"); | |||
#ifdef COPY_PASTE | #ifdef COPY_PASTE | |||
if (dump == DUMP_EXCHANGE && public) { | if (dump == DUMP_EXCHANGE && public) { | |||
# ifdef HAVE_LSTAT | # ifdef HAVE_LSTAT | |||
if (exists) { | if (exists) { | |||
if ((fd = open(fn, O_WRONLY, 0666)) >= 0) { | if ((fd = open(fn, O_WRONLY, 0666)) >= 0) { | |||
if (fstat(fd, &stb2) == 0 && stb.st_dev == stb2.st_dev && stb.st_ino = | if (fstat(fd, &stb2) == 0 && stb.st_dev = | |||
= stb2.st_ino) | = stb2.st_dev && stb.st_ino == stb2.st_ino) | |||
ftruncate(fd, 0); | ftruncate(fd, 0); | |||
else { | else { | |||
close(fd); | close(fd); | |||
fd = -1; | fd = -1; | |||
} | } | |||
} | } | |||
} | } else | |||
else | fd = open(fn, O_WRONLY|O_CREAT|O_EXCL, 0666); | |||
fd = open(fn, O_WRONLY|O_CREAT|O_EXCL, 0666); | f = fd >= 0 ? fdopen(fd, mode) : 0; | |||
f = fd >= 0 ? fdopen(fd, mode) : 0; | ||||
# else | # else | |||
f = fopen(fn, mode); | f = fopen(fn, mode); | |||
# endif | # endif | |||
} | } else | |||
else | ||||
#endif /* COPY_PASTE */ | #endif /* COPY_PASTE */ | |||
f = fopen(fn, mode); | f = fopen(fn, mode); | |||
if (f == NULL) { | if (f == NULL) { | |||
debug2("WriteFile: fopen(%s,\"%s\") failed\n", fn, mode); | debug2("WriteFile: fopen(%s,\"%s\") failed\n", fn, mode); | |||
UserReturn(0); | UserReturn(0); | |||
} | } else { | |||
else { | switch (dump) { | |||
switch (dump) { | case DUMP_HARDCOPY: | |||
case DUMP_HARDCOPY: | case DUMP_SCROLLBACK: | |||
case DUMP_SCROLLBACK: | if (!fore) | |||
if (!fore) | break; | |||
break; | if (*mode == 'a') { | |||
if (*mode == 'a') { | putc('>', f); | |||
putc('>', f); | for (j = fore->w_width - 2; j > 0; j--) | |||
for (j = fore->w_width - 2; j > 0; j--) | putc('=', f); | |||
putc('=', f); | fputs("<\n", f); | |||
fputs("<\n", f); | } | |||
} | if (dump == DUMP_SCROLLBACK) { | |||
if (dump == DUMP_SCROLLBACK) { | ||||
#ifdef COPY_PASTE | #ifdef COPY_PASTE | |||
for (i = fore->w_histheight - fore->w_scrollback_height; i < for | for (i = fore->w_histheight - fore->w_scr | |||
e->w_histheight; i++) { | ollback_height; i < fore->w_histheight; i++) { | |||
p = (char *)(WIN(i)->image); | p = (char *)(WIN(i)->image); | |||
for (k = fore->w_width - 1; k >= 0 && p[k] == ' '; k--) | for (k = fore->w_width - 1; | |||
; | k >= 0 && p[k] == ' '; k--) | |||
for (j = 0; j <= k; j++) | ; | |||
putc(p[j], f); | for (j = 0; j <= k; j++) | |||
putc('\n', f); | putc(p[j], f); | |||
} | putc('\n', f); | |||
#endif | } | |||
} | #endif | |||
for (i = 0; i < fore->w_height; i++) { | } | |||
p = (char *)fore->w_mlines[i].image; | for (i = 0; i < fore->w_height; i++) { | |||
for (k = fore->w_width - 1; k >= 0 && p[k] == ' '; k--) | p = (char *)fore->w_mlines[i].image; | |||
; | for (k = fore->w_width - 1; | |||
for (j = 0; j <= k; j++) | k >= 0 && p[k] == ' '; k--) | |||
putc(p[j], f); | ; | |||
putc('\n', f); | for (j = 0; j <= k; j++) | |||
} | putc(p[j], f); | |||
break; | putc('\n', f); | |||
} | ||||
case DUMP_TERMCAP: | break; | |||
DumpTermcap(fore->w_aflag, f); | ||||
break; | case DUMP_TERMCAP: | |||
DumpTermcap(fore->w_aflag, f); | ||||
break; | ||||
#ifdef COPY_PASTE | #ifdef COPY_PASTE | |||
case DUMP_EXCHANGE: | case DUMP_EXCHANGE: | |||
p = user->u_plop.buf; | p = user->u_plop.buf; | |||
for (i = user->u_plop.len; i-- > 0; p++) | for (i = user->u_plop.len; i-- > 0; p++) | |||
if (*p == '\r' && (i == 0 || p[1] != '\n')) | if (*p == '\r' && (i == 0 || p[1] != '\n' | |||
putc('\n', f); | )) | |||
else | putc('\n', f); | |||
putc(*p, f); | else | |||
break; | putc(*p, f); | |||
#endif | break; | |||
} | #endif | |||
(void) fclose(f); | } | |||
UserReturn(1); | (void)fclose(f); | |||
} | UserReturn(1); | |||
} | } | |||
if (UserStatus() <= 0) | } | |||
Msg(0, "Cannot open \"%s\"", fn); | if (UserStatus() <= 0) | |||
else if (display && !*rc_name) { | Msg(0, "Cannot open \"%s\"", fn); | |||
switch (dump) { | else if (display && !*rc_name) { | |||
case DUMP_TERMCAP: | switch (dump) { | |||
Msg(0, "Termcap entry written to \"%s\".", fn); | case DUMP_TERMCAP: | |||
break; | Msg(0, "Termcap entry written to \"%s\".", fn); | |||
case DUMP_HARDCOPY: | break; | |||
case DUMP_SCROLLBACK: | case DUMP_HARDCOPY: | |||
Msg(0, "Screen image %s to \"%s\".", (*mode == 'a') ? "appended" : "writ | case DUMP_SCROLLBACK: | |||
ten", fn); | Msg(0, "Screen image %s to \"%s\".", (*mode == 'a') ? "ap | |||
break; | pended" : "written", fn); | |||
break; | ||||
#ifdef COPY_PASTE | #ifdef COPY_PASTE | |||
case DUMP_EXCHANGE: | case DUMP_EXCHANGE: | |||
Msg(0, "Copybuffer written to \"%s\".", fn); | Msg(0, "Copybuffer written to \"%s\".", fn); | |||
#endif | #endif | |||
} | } | |||
} | } | |||
} | } | |||
#ifdef COPY_PASTE | #ifdef COPY_PASTE | |||
/* | /* | |||
* returns an allocated buffer which holds a copy of the file named fn. | * returns an allocated buffer which holds a copy of the file named fn. | |||
* lenp (if nonzero) points to a location, where the buffer size should be | * lenp (if nonzero) points to a location, where the buffer size should be | |||
* stored. | * stored. | |||
*/ | */ | |||
char *ReadFile(char *fn, int *lenp) { | char * | |||
int i, l, size; | ReadFile(char *fn, int *lenp) | |||
char c, *bp, *buf; | { | |||
struct stat stb; | int i, l, size; | |||
char c, *bp, *buf; | ||||
ASSERT(lenp); | struct stat stb; | |||
debug1("ReadFile(%s)\n", fn); | ||||
ASSERT(lenp); | ||||
if ((i = secopen(fn, O_RDONLY, 0)) < 0) { | debug1("ReadFile(%s)\n", fn); | |||
Msg(errno, "no %s -- no slurp", fn); | ||||
return NULL; | if ((i = secopen(fn, O_RDONLY, 0)) < 0) { | |||
} | Msg(errno, "no %s -- no slurp", fn); | |||
return NULL; | ||||
if (fstat(i, &stb)) { | } | |||
Msg(errno, "no good %s -- no slurp", fn); | ||||
close(i); | if (fstat(i, &stb)) { | |||
return NULL; | Msg(errno, "no good %s -- no slurp", fn); | |||
} | close(i); | |||
size = stb.st_size; | return NULL; | |||
} | ||||
if ((buf = malloc(size)) == NULL) { | size = stb.st_size; | |||
close(i); | ||||
Msg(0, "%s", strnomem); | if ((buf = malloc(size)) == NULL) { | |||
return NULL; | close(i); | |||
} | Msg(0, "%s", strnomem); | |||
errno = 0; | return NULL; | |||
} | ||||
if ((l = read(i, buf, size)) != size) { | errno = 0; | |||
if (l < 0) | ||||
l = 0; | if ((l = read(i, buf, size)) != size) { | |||
Msg(errno, "Got only %d bytes from %s", l, fn); | if (l < 0) | |||
} | l = 0; | |||
else { | Msg(errno, "Got only %d bytes from %s", l, fn); | |||
if (read(i, &c, 1) > 0) | } else { | |||
Msg(0, "Slurped only %d characters (of %d) into buffer - try again", l, si | if (read(i, &c, 1) > 0) | |||
ze); | Msg(0, "Slurped only %d characters (of %d) into buffer - | |||
else | try again", l, size); | |||
Msg(0, "Slurped %d characters into buffer", l); | else | |||
} | Msg(0, "Slurped %d characters into buffer", l); | |||
close(i); | } | |||
*lenp = l; | close(i); | |||
for (bp = buf; l-- > 0; bp++) | *lenp = l; | |||
if (*bp == '\n' && (bp == buf || bp[-1] != '\r')) | for (bp = buf; l-- > 0; bp++) | |||
*bp = '\r'; | if (*bp == '\n' && (bp == buf || bp[-1] != '\r')) | |||
return buf; | *bp = '\r'; | |||
} | return buf; | |||
} | ||||
void KillBuffers() { | ||||
if (UserContext() > 0) | void | |||
UserReturn(unlink(BufferFile) ? errno : 0); | KillBuffers() | |||
errno = UserStatus(); | { | |||
Msg(errno, "%s %sremoved", BufferFile, errno ? "not " : ""); | if (UserContext() > 0) | |||
UserReturn(unlink(BufferFile) ? errno : 0); | ||||
errno = UserStatus(); | ||||
Msg(errno, "%s %sremoved", BufferFile, errno ? "not " : ""); | ||||
} | } | |||
#endif /* COPY_PASTE */ | #endif /* COPY_PASTE */ | |||
/* (Almost) secure open and fopen... */ | /* (Almost) secure open and fopen... */ | |||
FILE *secfopen(char *name, char *mode) { | FILE * | |||
FILE *fi; | secfopen(char *name, char *mode) | |||
{ | ||||
FILE *fi; | ||||
#ifndef USE_SETEUID | #ifndef USE_SETEUID | |||
int flags, fd; | int flags, fd; | |||
#endif | #endif | |||
debug2("secfopen(%s, %s)\n", name, mode); | debug2("secfopen(%s, %s)\n", name, mode); | |||
#ifdef USE_SETEUID | #ifdef USE_SETEUID | |||
xseteuid(real_uid); | xseteuid(real_uid); | |||
xsetegid(real_gid); | xsetegid(real_gid); | |||
fi = fopen(name, mode); | fi = fopen(name, mode); | |||
xseteuid(eff_uid); | xseteuid(eff_uid); | |||
xsetegid(eff_gid); | xsetegid(eff_gid); | |||
return fi; | return fi; | |||
#else | #else | |||
if (eff_uid == real_uid) | if (eff_uid == real_uid) | |||
return fopen(name, mode); | return fopen(name, mode); | |||
if (mode[0] && mode[1] == '+') | if (mode[0] && mode[1] == '+') | |||
flags = O_RDWR; | flags = O_RDWR; | |||
else | else | |||
flags = (mode[0] == 'r') ? O_RDONLY : O_WRONLY; | flags = (mode[0] == 'r') ? O_RDONLY : O_WRONLY; | |||
if (mode[0] == 'w') | if (mode[0] == 'w') | |||
flags |= O_CREAT | O_TRUNC; | flags |= O_CREAT | O_TRUNC; | |||
else if (mode[0] == 'a') | else if (mode[0] == 'a') | |||
flags |= O_CREAT | O_APPEND; | flags |= O_CREAT | O_APPEND; | |||
else if (mode[0] != 'r') { | else if (mode[0] != 'r') { | |||
errno = EINVAL; | errno = EINVAL; | |||
return 0; | return 0; | |||
} | } | |||
if ((fd = secopen(name, flags, 0666)) < 0) | if ((fd = secopen(name, flags, 0666)) < 0) | |||
return 0; | return 0; | |||
if ((fi = fdopen(fd, mode)) == 0) { | if ((fi = fdopen(fd, mode)) == 0) { | |||
close(fd); | close(fd); | |||
return 0; | return 0; | |||
} | } | |||
return fi; | return fi; | |||
#endif | #endif | |||
} | } | |||
int secopen(char *name, int flags, int mode) { | int | |||
int fd; | secopen(char *name, int flags, int mode) | |||
{ | ||||
int fd; | ||||
#ifndef USE_SETEUID | #ifndef USE_SETEUID | |||
int q; | int q; | |||
struct stat stb; | struct stat stb; | |||
#endif | #endif | |||
debug3("secopen(%s, 0x%x, 0%03o)\n", name, flags, mode); | debug3("secopen(%s, 0x%x, 0%03o)\n", name, flags, mode); | |||
#ifdef USE_SETEUID | #ifdef USE_SETEUID | |||
xseteuid(real_uid); | xseteuid(real_uid); | |||
xsetegid(real_gid); | xsetegid(real_gid); | |||
fd = open(name, flags, mode); | fd = open(name, flags, mode); | |||
xseteuid(eff_uid); | xseteuid(eff_uid); | |||
xsetegid(eff_gid); | xsetegid(eff_gid); | |||
return fd; | return fd; | |||
#else | #else | |||
if (eff_uid == real_uid) | if (eff_uid == real_uid) | |||
return open(name, flags, mode); | return open(name, flags, mode); | |||
/* Truncation/creation is done in UserContext */ | ||||
if ((flags & O_TRUNC) || ((flags & O_CREAT) && access(name, F_OK))) { | /* Truncation/creation is done in UserContext */ | |||
if (UserContext() > 0) { | if ((flags & O_TRUNC) || ((flags & O_CREAT) && access(name, F_OK))) { | |||
if ((fd = open(name, flags, mode)) >= 0) { | if (UserContext() > 0) { | |||
close(fd); | if ((fd = open(name, flags, mode)) >= 0) { | |||
UserReturn(0); | close(fd); | |||
} | UserReturn(0); | |||
if (errno == 0) | } | |||
errno = EACCES; | if (errno == 0) | |||
UserReturn(errno); | errno = EACCES; | |||
} | UserReturn(errno); | |||
if ((q = UserStatus())) { | } | |||
if (q > 0) | if ((q = UserStatus())) { | |||
errno = q; | if (q > 0) | |||
return -1; | errno = q; | |||
} | return -1; | |||
} | } | |||
if (access(name, F_OK)) | } | |||
return -1; | if (access(name, F_OK)) | |||
if ((fd = open(name, flags & ~(O_TRUNC | O_CREAT), 0)) < 0) | return -1; | |||
return -1; | if ((fd = open(name, flags & ~(O_TRUNC | O_CREAT), 0)) < 0) | |||
debug("open successful\n"); | return -1; | |||
if (fstat(fd, &stb)) { | debug("open successful\n"); | |||
close(fd); | if (fstat(fd, &stb)) { | |||
return -1; | close(fd); | |||
} | return -1; | |||
debug("fstat successful\n"); | } | |||
if (stb.st_uid != real_uid) { | debug("fstat successful\n"); | |||
switch (flags & (O_RDONLY | O_WRONLY | O_RDWR)) { | if (stb.st_uid != real_uid) { | |||
case O_RDONLY: | switch (flags & (O_RDONLY | O_WRONLY | O_RDWR)) { | |||
q = 0004; | case O_RDONLY: | |||
break; | q = 0004; | |||
case O_WRONLY: | break; | |||
q = 0002; | case O_WRONLY: | |||
break; | q = 0002; | |||
default: | break; | |||
q = 0006; | default: | |||
break; | q = 0006; | |||
} | break; | |||
if ((stb.st_mode & q) != q) { | } | |||
debug1("secopen: permission denied (%03o)\n", stb.st_mode & 07777); | if ((stb.st_mode & q) != q) { | |||
close(fd); | debug1("secopen: permission denied (%03o)\n", stb.st_mode | |||
errno = EACCES; | & 07777); | |||
return -1; | close(fd); | |||
} | errno = EACCES; | |||
} | return -1; | |||
debug1("secopen ok - returning %d\n", fd); | } | |||
return fd; | } | |||
#endif | debug1("secopen ok - returning %d\n", fd); | |||
} | return fd; | |||
#endif | ||||
int printpipe(struct win *p, char *cmd) { | } | |||
int pi[2]; | ||||
if (pipe(pi)) { | int | |||
WMsg(p, errno, "printing pipe"); | printpipe(struct win *p, char *cmd) | |||
return -1; | { | |||
} | int pi[2]; | |||
switch (fork()) { | if (pipe(pi)) { | |||
case -1: | WMsg(p, errno, "printing pipe"); | |||
WMsg(p, errno, "printing fork"); | return -1; | |||
return -1; | } | |||
case 0: | switch (fork()) { | |||
display = p->w_pdisplay; | case -1: | |||
displays = 0; | WMsg(p, errno, "printing fork"); | |||
ServerSocket = -1; | return -1; | |||
case 0: | ||||
display = p->w_pdisplay; | ||||
displays = 0; | ||||
ServerSocket = -1; | ||||
#ifdef DEBUG | #ifdef DEBUG | |||
if (dfp && dfp != stderr) | if (dfp && dfp != stderr) | |||
fclose(dfp); | fclose(dfp); | |||
#endif | #endif | |||
close(0); | close(0); | |||
dup(pi[0]); | dup(pi[0]); | |||
closeallfiles(0); | closeallfiles(0); | |||
if (setgid(real_gid) || setuid(real_uid)) | if (setgid(real_gid) || setuid(real_uid)) | |||
Panic(errno, "printpipe setuid"); | Panic(errno, "printpipe setuid"); | |||
eff_uid = real_uid; | eff_uid = real_uid; | |||
eff_gid = real_gid; | eff_gid = real_gid; | |||
#ifdef SIGPIPE | #ifdef SIGPIPE | |||
signal(SIGPIPE, SIG_DFL); | signal(SIGPIPE, SIG_DFL); | |||
#endif | #endif | |||
execl("/bin/sh", "sh", "-c", cmd, (char *)0); | execl("/bin/sh", "sh", "-c", cmd, (char *)0); | |||
Panic(errno, "/bin/sh"); | Panic(errno, "/bin/sh"); | |||
default: | default: | |||
break; | break; | |||
} | } | |||
close(pi[0]); | close(pi[0]); | |||
return pi[1]; | return pi[1]; | |||
} | } | |||
int readpipe(char **cmdv) { | int | |||
int pi[2]; | readpipe(char **cmdv) | |||
{ | ||||
if (pipe(pi)) { | int pi[2]; | |||
Msg(errno, "pipe"); | ||||
return -1; | if (pipe(pi)) { | |||
} | Msg(errno, "pipe"); | |||
return -1; | ||||
switch (fork()) { | } | |||
case -1: | ||||
Msg(errno, "fork"); | switch (fork()) { | |||
return -1; | case -1: | |||
case 0: | Msg(errno, "fork"); | |||
displays = 0; | return -1; | |||
ServerSocket = -1; | case 0: | |||
displays = 0; | ||||
ServerSocket = -1; | ||||
#ifdef DEBUG | #ifdef DEBUG | |||
if (dfp && dfp != stderr) | if (dfp && dfp != stderr) | |||
fclose(dfp); | fclose(dfp); | |||
#endif | #endif | |||
close(1); | close(1); | |||
if (dup(pi[1]) != 1) { | if (dup(pi[1]) != 1) { | |||
close(pi[1]); | close(pi[1]); | |||
Panic(0, "dup"); | Panic(0, "dup"); | |||
} | } | |||
closeallfiles(1); | closeallfiles(1); | |||
if (setgid(real_gid) || setuid(real_uid)) { | if (setgid(real_gid) || setuid(real_uid)) { | |||
close(1); | close(1); | |||
Panic(errno, "setuid/setgid"); | Panic(errno, "setuid/setgid"); | |||
} | } | |||
eff_uid = real_uid; | eff_uid = real_uid; | |||
eff_gid = real_gid; | eff_gid = real_gid; | |||
#ifdef SIGPIPE | #ifdef SIGPIPE | |||
signal(SIGPIPE, SIG_DFL); | signal(SIGPIPE, SIG_DFL); | |||
#endif | #endif | |||
execvp(*cmdv, cmdv); | execvp(*cmdv, cmdv); | |||
close(1); | close(1); | |||
Panic(errno, "%s", *cmdv); | Panic(errno, "%s", *cmdv); | |||
default: | default: | |||
break; | break; | |||
} | } | |||
close(pi[1]); | close(pi[1]); | |||
return pi[0]; | return pi[0]; | |||
} | } | |||
End of changes. 54 change blocks. | ||||
631 lines changed or deleted | 660 lines changed or added |