home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
unix
/
volume26
/
screen-3.5
/
part03
/
attacher.c
next >
Wrap
C/C++ Source or Header
|
1993-07-25
|
19KB
|
835 lines
/* Copyright (c) 1993
* Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
* Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
* Copyright (c) 1987 Oliver Laumann
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (see the file COPYING); if not, write to the
* Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
****************************************************************
*/
#include "rcs.h"
RCS_ID("$Id: attacher.c,v 1.3 1993/07/21 15:42:48 mlschroe Exp $ FAU")
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <pwd.h>
#include "config.h"
#include "screen.h"
#include "extern.h"
#ifdef SHADOWPW
# include <shadow.h>
#endif /* SHADOWPW */
static sig_t AttacherSigInt __P(SIGPROTOARG);
#ifdef PASSWORD
static void trysend __P((int, struct msg *, char *));
#endif
#if defined(SIGWINCH) && defined(TIOCGWINSZ)
static sig_t AttacherWinch __P(SIGPROTOARG);
#endif
#ifdef LOCK
static sig_t DoLock __P(SIGPROTOARG);
static void LockTerminal __P((void));
static sig_t LockHup __P(SIGPROTOARG);
static void screen_builtin_lck __P((void));
#endif
#ifdef DEBUG
static sig_t AttacherChld __P(SIGPROTOARG);
#endif
extern int real_uid, real_gid, eff_uid, eff_gid;
extern char *SockName, *SockNamePtr, SockPath[];
extern struct passwd *ppp;
extern char *attach_tty, *attach_term, *LoginName;
extern int xflag, dflag, rflag, quietflag, adaptflag;
extern struct mode attach_Mode;
extern int MasterPid;
extern int nethackflag;
#ifdef MULTIUSER
extern char *multi;
extern int multiattach, multi_uid, own_uid;
extern int tty_mode, tty_oldmode;
# ifdef NOREUID
static int multipipe[2];
# endif
#endif
/*
* Send message to a screen backend.
* returns 1 if we could attach one, or 0 if none.
*/
int
Attach(how)
int how;
{
int lasts;
struct msg m;
struct stat st;
char *s;
debug2("Attach: how=%d, tty=%s\n", how, attach_tty);
#ifdef MULTIUSER
# ifdef NOREUID
while ((how == MSG_ATTACH || how == MSG_CONT) && multiattach)
{
int ret;
if (pipe(multipipe))
Panic(errno, "pipe");
eff_uid = -1; /* make UserContext fork */
real_uid = multi_uid;
if ((ret = UserContext()) <= 0)
{
char dummy;
eff_uid = 0;
real_uid = own_uid;
if (ret < 0)
Panic(errno, "UserContext");
close(multipipe[1]);
read(multipipe[0], &dummy, 1);
if (tty_oldmode >= 0)
{
chmod(attach_tty, tty_oldmode);
tty_oldmode = -1;
}
ret = UserStatus();
#ifdef LOCK
if (ret == SIG_LOCK)
LockTerminal();
else
#endif
#ifdef SIGTSTP
if (ret == SIG_STOP)
kill(getpid(), SIGTSTP);
else
#endif
if (ret == SIG_POWER_BYE)
{
int ppid;
setuid(real_uid);
setgid(real_gid);
if ((ppid = getppid()) > 1)
Kill(ppid, SIGHUP);
exit(0);
}
else
exit(ret);
dflag = 0;
#ifdef MULTI
xflag = 1;
#endif
how = MSG_ATTACH;
continue;
}
close(multipipe[0]);
eff_uid = real_uid;
break;
}
# else /* NOREUID */
if ((how == MSG_ATTACH || how == MSG_CONT) && multiattach)
{
real_uid = multi_uid;
eff_uid = own_uid;
setreuid(real_uid, eff_uid);
if (chmod(attach_tty, 0666))
Panic(errno, "chmod %s", attach_tty);
tty_oldmode = tty_mode;
}
# endif /* NOREUID */
#endif /* MULTIUSER */
bzero((char *) &m, sizeof(m));
m.type = how;
strcpy(m.m_tty, attach_tty);
if (how == MSG_WINCH)
{
if ((lasts = MakeClientSocket(0, SockName)) >= 0)
{
write(lasts, (char *)&m, sizeof(m));
close(lasts);
}
return 0;
}
if (how == MSG_CONT)
{
if ((lasts = MakeClientSocket(0, SockName)) < 0)
{
Panic(0, "Sorry, cannot contact session \"%s\" again\r\n",
SockName ? SockName : "<NULL>");
}
}
else
{
switch (FindSocket(how, &lasts))
{
case 0:
if (rflag == 2)
return 0;
if (quietflag)
eexit(10);
Panic(0, SockName && *SockName ? "There is no screen to be %sed matching %s." : "There is no screen to be %sed.",
xflag ? "attach" :
dflag ? "detach" :
"resum", SockName);
/* NOTREACHED */
case 1:
break;
default:
Panic(0, "Type \"screen [-d] -r [pid.]tty.host\" to resume one of them.");
/* NOTREACHED */
}
}
/*
* Go in UserContext. Advantage is, you can kill your attacher
* when things go wrong. Any disadvantages? jw.
* Do this before the attach to prevent races!
*/
#ifdef MULTIUSER
if (!multiattach)
#endif
setuid(real_uid);
#if defined(MULTIUSER) && !defined(NOREUID)
else
setreuid(eff_uid, real_uid);
#endif
setgid(real_gid);
debug2("Attach: uid %d euid %d\n", getuid(), geteuid());
SockName = SockNamePtr;
MasterPid = 0;
while (*SockName)
{
if (*SockName > '9' || *SockName < '0')
break;
MasterPid = 10 * MasterPid + *SockName - '0';
SockName++;
}
SockName = SockNamePtr;
debug1("Attach decided, it is '%s'\n", SockPath);
debug1("Attach found MasterPid == %d\n", MasterPid);
if (stat(SockPath, &st) == -1)
Panic(errno, "stat %s", SockPath);
if ((st.st_mode & 0600) != 0600)
Panic(0, "Socket is in wrong mode (%03o)", st.st_mode);
if ((dflag || !xflag) && (st.st_mode & 0700) != (dflag ? 0700 : 0600))
Panic(0, "That screen is %sdetached.", dflag ? "already " : "not ");
#ifdef REMOTE_DETACH
if (dflag &&
(how == MSG_ATTACH || how == MSG_DETACH || how == MSG_POW_DETACH))
{
m.m.detach.dpid = getpid();
strncpy(m.m.detach.duser, LoginName, sizeof(m.m.detach.duser) - 1);
m.m.detach.duser[sizeof(m.m.detach.duser) - 1] = 0;
# ifdef POW_DETACH
if (dflag == 2)
m.type = MSG_POW_DETACH;
else
# endif
m.type = MSG_DETACH;
if (write(lasts, (char *) &m, sizeof(m)) != sizeof(m))
Panic(errno, "write");
close(lasts);
if (how != MSG_ATTACH)
return 0; /* we detached it. jw. */
sleep(1); /* we dont want to overrun our poor backend. jw. */
if ((lasts = MakeClientSocket(0, SockName)) == -1)
Panic(0, "Cannot contact screen again. Shit.");
m.type = how;
}
#endif
strcpy(m.m.attach.envterm, attach_term);
debug1("attach: sending %d bytes... ", sizeof m);
strncpy(m.m.attach.auser, LoginName, sizeof(m.m.attach.auser) - 1);
m.m.attach.auser[sizeof(m.m.attach.auser) - 1] = 0;
m.m.attach.apid = getpid();
m.m.attach.adaptflag = adaptflag;
m.m.attach.lines = m.m.attach.columns = 0;
if ((s = getenv("LINES")))
m.m.attach.lines = atoi(s);
if ((s = getenv("COLUMNS")))
m.m.attach.columns = atoi(s);
#ifdef PASSWORD
if (how == MSG_ATTACH || how == MSG_CONT)
trysend(lasts, &m, m.m.attach.password);
else
#endif
{
if (write(lasts, (char *) &m, sizeof(m)) != sizeof(m))
Panic(errno, "write");
close(lasts);
}
debug1("Attach(%d): sent\n", m.type);
#ifdef MULTIUSER
if (multi && (how == MSG_ATTACH || how == MSG_CONT))
{
# ifndef PASSWORD
pause();
# endif
# ifdef NOREUID
close(multipipe[1]);
# else
setreuid(real_uid, eff_uid);
if (tty_oldmode >= 0)
if (chmod(attach_tty, tty_oldmode))
Panic(errno, "chmod %s", attach_tty);
tty_oldmode = -1;
setreuid(eff_uid, real_uid);
# endif
}
#endif
rflag = 0;
return 1;
}
#ifdef PASSWORD
static trysendstatok, trysendstatfail;
static sig_t
trysendok(SIGDEFARG)
{
trysendstatok = 1;
}
static sig_t
trysendfail(SIGDEFARG)
{
# ifdef SYSVSIGS
signal(SIG_PW_FAIL, trysendfail);
# endif /* SYSVSIGS */
trysendstatfail = 1;
}
static char screenpw[9];
static void
trysend(fd, m, pwto)
int fd;
struct msg *m;
char *pwto;
{
char *npw = NULL;
sig_t (*sighup)__P(SIGPROTOARG);
sig_t (*sigusr1)__P(SIGPROTOARG);
int tries;
sigusr1 = signal(SIG_PW_OK, trysendok);
sighup = signal(SIG_PW_FAIL, trysendfail);
for (tries = 0; ; )
{
strcpy(pwto, screenpw);
trysendstatok = trysendstatfail = 0;
if (write(fd, (char *) m, sizeof(*m)) != sizeof(*m))
Panic(errno, "write");
close(fd);
while (trysendstatok == 0 && trysendstatfail == 0)
pause();
if (trysendstatok)
{
signal(SIG_PW_OK, sigusr1);
signal(SIG_PW_FAIL, sighup);
if (trysendstatfail)
kill(getpid(), SIG_PW_FAIL);
return;
}
if (++tries > 1 || (npw = getpass("Screen Password:")) == 0 || *npw == 0)
{
#ifdef NETHACK
if (nethackflag)
Panic(0, "The guard slams the door in your face.");
else
#endif
Panic(0, "Password incorrect.");
}
strncpy(screenpw, npw, 8);
if ((fd = MakeClientSocket(0, SockName)) == -1)
Panic(0, "Cannot contact screen again. Shit.");
}
}
#endif /* PASSWORD */
#ifdef DEBUG
static int AttacherPanic;
static sig_t
AttacherChld(SIGDEFARG)
{
AttacherPanic=1;
#ifndef SIGVOID
return((sig_t) 0);
#endif
}
#endif
/*
* the frontend's Interrupt handler
* we forward SIGINT to the poor backend
*/
static sig_t
AttacherSigInt(SIGDEFARG)
{
signal(SIGINT, AttacherSigInt);
Kill(MasterPid, SIGINT);
# ifndef SIGVOID
return (sig_t) 0;
# endif
}
/*
* Unfortunatelly this is also the SIGHUP handler, so we have to
* check, if the backend is already detached.
*/
sig_t
AttacherFinit(SIGDEFARG)
{
struct stat statb;
struct msg m;
int s;
debug("AttacherFinit();\n");
signal(SIGHUP, SIG_IGN);
/* Check if signal comes from backend */
if (SockName)
{
strcpy(SockNamePtr, SockName);
if (stat(SockPath, &statb) == 0 && (statb.st_mode & 0777) != 0600)
{
debug("Detaching backend!\n");
bzero((char *) &m, sizeof(m));
strcpy(m.m_tty, attach_tty);
debug1("attach_tty is %s\n", attach_tty);
m.m.detach.dpid = getpid();
m.type = MSG_HANGUP;
if ((s = MakeClientSocket(0, SockName)) >= 0)
{
write(s, (char *)&m, sizeof(m));
close(s);
}
}
}
#ifdef MULTIUSER
if (tty_oldmode >= 0)
{
setuid(own_uid);
chmod(attach_tty, tty_oldmode);
}
#endif
exit(0);
#ifndef SIGVOID
return((sig_t) 0);
#endif
}
#ifdef POW_DETACH
static sig_t
AttacherFinitBye(SIGDEFARG)
{
int ppid;
debug("AttacherFintBye()\n");
#if defined(MULTIUSER) && defined(NOREUID)
if (multiattach)
exit(SIG_POWER_BYE);
#endif
#ifdef MULTIUSER
setuid(own_uid);
#else
setuid(real_uid);
#endif
setgid(real_gid);
/* we don't want to disturb init (even if we were root), eh? jw */
if ((ppid = getppid()) > 1)
Kill(ppid, SIGHUP); /* carefully say good bye. jw. */
exit(0);
#ifndef SIGVOID
return((sig_t) 0);
#endif
}
#endif
static int SuspendPlease;
static sig_t
SigStop(SIGDEFARG)
{
debug("SigStop()\n");
SuspendPlease = 1;
#ifndef SIGVOID
return((sig_t) 0);
#endif
}
#ifdef LOCK
static int LockPlease;
static sig_t
DoLock(SIGDEFARG)
{
# ifdef SYSVSIGS
signal(SIG_LOCK, DoLock);
# endif
debug("DoLock()\n");
LockPlease = 1;
# ifndef SIGVOID
return((sig_t) 0);
# endif
}
#endif
#if defined(SIGWINCH) && defined(TIOCGWINSZ)
static int SigWinchPlease;
static sig_t
AttacherWinch(SIGDEFARG)
{
debug("AttacherWinch()\n");
SigWinchPlease = 1;
# ifndef SIGVOID
return((sig_t) 0);
# endif
}
#endif
/*
* Attacher loop - no return
*/
void
Attacher()
{
signal(SIGHUP, AttacherFinit);
signal(SIG_BYE, AttacherFinit);
#ifdef POW_DETACH
signal(SIG_POWER_BYE, AttacherFinitBye);
#endif
#ifdef LOCK
signal(SIG_LOCK, DoLock);
#endif
signal(SIGINT, AttacherSigInt);
#ifdef BSDJOBS
signal(SIG_STOP, SigStop);
#endif
#if defined(SIGWINCH) && defined(TIOCGWINSZ)
signal(SIGWINCH, AttacherWinch);
#endif
#ifdef DEBUG
signal(SIGCHLD, AttacherChld);
#endif
debug("attacher: going for a nap.\n");
dflag = 0;
#ifdef MULTI
xflag = 1;
#endif
for (;;)
{
pause();
debug("attacher: huh! a signal!\n");
#ifdef DEBUG
if (AttacherPanic)
{
fcntl(0, F_SETFL, 0);
SetTTY(0, &attach_Mode);
printf("\nSuddenly the Dungeon collapses!! - You die...\n");
eexit(1);
}
#endif
#ifdef BSDJOBS
if (SuspendPlease)
{
SuspendPlease = 0;
#if defined(MULTIUSER) && defined(NOREUID)
if (multiattach)
exit(SIG_STOP);
#endif
signal(SIGTSTP, SIG_DFL);
debug("attacher: killing myself SIGTSTP\n");
kill(getpid(), SIGTSTP);
debug("attacher: continuing from stop\n");
signal(SIG_STOP, SigStop);
(void) Attach(MSG_CONT);
}
#endif
#ifdef LOCK
if (LockPlease)
{
LockPlease = 0;
#if defined(MULTIUSER) && defined(NOREUID)
if (multiattach)
exit(SIG_LOCK);
#endif
LockTerminal();
# ifdef SYSVSIGS
signal(SIG_LOCK, DoLock);
# endif
(void) Attach(MSG_CONT);
}
#endif /* LOCK */
#if defined(SIGWINCH) && defined(TIOCGWINSZ)
if (SigWinchPlease)
{
SigWinchPlease = 0;
# ifdef SYSVSIGS
signal(SIGWINCH, AttacherWinch);
# endif
(void) Attach(MSG_WINCH);
}
#endif /* SIGWINCH */
}
}
#ifdef LOCK
/* ADDED by Rainer Pruy 10/15/87 */
/* POLISHED by mls. 03/10/91 */
static char LockEnd[] = "Welcome back to screen !!\n";
static sig_t
LockHup(SIGDEFARG)
{
int ppid = getppid();
setuid(real_uid);
setgid(real_gid);
if (ppid > 1)
Kill(ppid, SIGHUP);
exit(0);
}
static void
LockTerminal()
{
char *prg;
int sig, pid;
sig_t (*sigs[NSIG])__P(SIGPROTOARG);
for (sig = 1; sig < NSIG; sig++)
{
sigs[sig] = signal(sig, SIG_IGN);
}
signal(SIGHUP, LockHup);
printf("\n");
prg = getenv("LOCKPRG");
if (prg && strcmp(prg, "builtin") && !access(prg, X_OK))
{
signal(SIGCHLD, SIG_DFL);
debug1("lockterminal: '%s' seems executable, execl it!\n", prg);
if ((pid = fork()) == 0)
{
/* Child */
setuid(real_uid); /* this should be done already */
setgid(real_gid);
closeallfiles(0); /* important: /etc/shadow may be open */
execl(prg, "SCREEN-LOCK", NULL);
exit(errno);
}
if (pid == -1)
{
#ifdef NETHACK
if (nethackflag)
Msg(errno, "Cannot fork terminal - lock failed");
else
#endif
Msg(errno, "Cannot lock terminal - fork failed");
}
else
{
#ifdef BSDWAIT
union wait wstat;
#else
int wstat;
#endif
int wret;
#ifdef hpux
signal(SIGCHLD, SIG_DFL);
#endif
errno = 0;
while (((wret = wait(&wstat)) != pid) ||
((wret == -1) && (errno == EINTR))
)
errno = 0;
if (errno)
{
Msg(errno, "Lock");
sleep(2);
}
else if (WTERMSIG(wstat) != 0)
{
fprintf(stderr, "Lock: %s: Killed by signal: %d%s\n", prg,
WTERMSIG(wstat), WIFCORESIG(wstat) ? " (Core dumped)" : "");
sleep(2);
}
else if (WEXITSTATUS(wstat))
{
debug2("Lock: %s: return code %d\n", prg, WEXITSTATUS(wstat));
}
else
printf(LockEnd);
}
}
else
{
if (prg)
{
debug1("lockterminal: '%s' seems NOT executable, we use our builtin\n", prg);
}
else
{
debug("lockterminal: using buitin.\n");
}
screen_builtin_lck();
}
/* reset signals */
for (sig = 1; sig < NSIG; sig++)
{
if (sigs[sig] != (sig_t(*)__P(SIGPROTOARG)) -1)
signal(sig, sigs[sig]);
}
} /* LockTerminal */
/* -- original copyright by Luigi Cannelloni 1985 (luigi@faui70.UUCP) -- */
static void
screen_builtin_lck()
{
char fullname[100], *cp1, message[BUFSIZ];
char c, *pass, mypass[9];
#ifdef SHADOWPW
struct spwd *sss = NULL;
#endif
int t;
#ifdef undef
/* get password entry */
if ((ppp = getpwuid(real_uid)) == NULL)
{
fprintf(stderr, "screen_builtin_lck: No passwd entry.\007\n");
sleep(2);
return;
}
if (!isatty(0))
{
fprintf(stderr, "screen_builtin_lck: Not a tty.\007\n");
sleep(2);
return;
}
#endif
pass = ppp->pw_passwd;
#ifdef SHADOWPW
realpw:
#endif /* SHADOWPW */
for (t = 0; t < 13; t++)
{
c = pass[t];
if (!(c == '.' || c == '/' ||
(c >= '0' && c <= '9') ||
(c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z')))
break;
}
if (t < 13)
{
debug("builtin_lock: ppp->pw_passwd bad, has it a shadow?\n");
#ifdef SHADOWPW
setspent(); /* rewind shadow file */
if ((sss == NULL) && (sss = getspnam(ppp->pw_name)))
{
pass = sss->sp_pwdp;
goto realpw;
}
#endif /* SHADOWPW */
if ((pass = getpass("Key: ")))
{
strncpy(mypass, pass, 8);
mypass[8] = 0;
if (*mypass == 0)
return;
if ((pass = getpass("Again: ")))
{
if (strcmp(mypass, pass))
{
fprintf(stderr, "Passwords don't match.\007\n");
sleep(2);
return;
}
}
}
if (pass == 0)
{
fprintf(stderr, "Getpass error.\007\n");
sleep(2);
return;
}
pass = 0;
}
debug("screen_builtin_lck looking in gcos field\n");
strcpy(fullname, ppp->pw_gecos);
if ((cp1 = index(fullname, ',')) != NULL)
*cp1 = '\0';
if ((cp1 = index(fullname, '&')) != NULL)
{
sprintf(cp1, "%s", ppp->pw_name);
if (*cp1 >= 'a' && *cp1 <= 'z')
*cp1 -= 'a' - 'A';
}
sprintf(message, "Screen used by %s <%s>.\nPassword:\007",
fullname, ppp->pw_name);
/* loop here to wait for correct password */
for (;;)
{
debug("screen_builtin_lck awaiting password\n");
errno = 0;
if ((cp1 = getpass(message)) == NULL)
{
AttacherFinit(SIGARG);
/* NOTREACHED */
}
debug3("getpass(%d): %x == %s\n", errno, (unsigned int)cp1, cp1);
if (pass)
{
if (!strcmp(crypt(cp1, pass), pass))
break;
}
else
{
if (!strcmp(cp1, mypass))
break;
}
debug("screen_builtin_lck: NO!!!!!\n");
}
debug("password ok.\n");
}
#endif /* LOCK */