|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T v
Length: 16765 (0x417d)
Types: TextFile
Names: »vtd.c«
└─⟦2d1937cfd⟧ Bits:30007241 EUUGD22: P.P 5.0
└─⟦35176feda⟧ »EurOpenD22/isode/isode-6.tar.Z«
└─⟦de7628f85⟧
└─⟦this⟧ »isode-6.0/vt/vtd.c«
/* vtd.c - VT responder */
#ifndef lint
static char *rcsid = "$Header: /f/osi/vt/RCS/vtd.c,v 7.1 89/11/30 23:51:42 mrose Exp $";
#endif
/*
* $Header: /f/osi/vt/RCS/vtd.c,v 7.1 89/11/30 23:51:42 mrose Exp $
*
*
* $Log: vtd.c,v $
* Revision 7.1 89/11/30 23:51:42 mrose
* pa2str
*
* Revision 7.0 89/11/23 22:31:55 mrose
* Release 6.0
*
*/
/*
* NOTICE
*
* Acquisition, use, and distribution of this module and related
* materials are subject to the restrictions of a license agreement.
* Consult the Preface in the User's Manual for the full terms of
* this agreement.
*
*/
#undef NOTROOT /*So crashes won't have to be killed by root*/
#undef MAP_BACKSPACE /*Map backspace character to VT ERASE CHAR*/
#include <signal.h>
#include "vtpm.h"
#include "sector1.h"
#include "tailor.h"
#include <sys/ioctl.h>
#ifdef BSD44
#include <sys/termios.h>
#include <sys/ttydefaults.h>
#endif
#include <arpa/telnet.h>
#include <ctype.h>
#include <setjmp.h>
#include <pwd.h>
#include <varargs.h>
#define BELL '\07'
#ifndef SUNOS4
#define BANNER "\r\n\r\n4.2 BSD UNIX (%s)\r\n\r\n\r%s"
#else
#define BANNER "\r\n\r\nSunOS UNIX (%s)\r\n\r\n\r%s"
#endif
int connected = FALSE;
char command[256];
/*
* I/O data buffers, pointers, and counters.
*/
char ptyobuf[BUFSIZ], *pfrontp = ptyobuf, *pbackp = ptyobuf;
char netobuf[BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf;
int pcc;
VT_PROFILE vtp_profile;
int rflag = 0;
char erase_char;
char erase_line;
char intr_char;
char *crp = "\r";
char *my_displayobj = "D"; /*Acceptor's Display Object Name*/
char *my_echo_obj = "NA"; /*Acceptor's Negotiation Control Object Name*/
char *my_signal_obj = "DI"; /*Acceptor's Signal Control Object*/
char *his_echo_obj = "NI"; /*Initiator's Negotiation Control Object*/
char *his_signal_obj = "KB"; /*Initiator/s Signal control Object*/
int my_right = ACCEPTOR;
char kb_image; /*KB Control Object image*/
char di_image; /*DI Control Object Image*/
char ni_image; /*NI Control Object image*/
char na_image; /*NA Control Object image*/
char nego_state; /*Current state of NA affected options*/
char sync_image; /*SY Control Object image*/
char ga_image;
int transparent = 0; /*Flag for Transparent repertoire*/
int telnet_profile =1;
int do_break = 1; /*If VT-BREAK agreed to*/
int showoptions = 0;
int debug = 0;
#ifdef BSD44
struct termios oterm;
#else
struct tchars otc;
struct ltchars oltc;
struct sgttyb ottyb;
#endif
char *myhostname;
char peerhost[BUFSIZ];
struct PSAPaddr ts_bound;
struct passwd *pwd;
int pty, net;
int inter;
extern char **environ;
extern int errno;
char line[] = "/dev/ptyp0";
char *envinit[] = { "TERM=network", 0 };
SFD cleanup();
static int do_cleaning = 0;
char *myname;
LLog _vt_log = {
"vt.log", NULLCP, NULLCP,
LLOG_FATAL | LLOG_EXCEPTIONS | LLOG_NOTICE, LLOG_FATAL, -1,
LLOGCLS | LLOGCRT | LLOGZER, NOTOK
};
LLog *vt_log = &_vt_log;
main(argc, argv)
int argc;
char *argv[];
{
int f = 0;
char *cp = line;
char *logname = NULLCP;
int i, p, t;
char j;
#ifdef BSD44
struct termios term;
#else
struct sgttyb b;
#endif
if (myname = rindex (*argv, '/'))
myname++;
if (myname == NULL || *myname == NULL)
myname = *argv;
isodetailor (myname, 0);
if (debug = isatty (fileno (stderr)))
ll_dbinit (vt_log, myname);
else
ll_hdinit (vt_log, myname);
for(i=1; i<(argc - 2); i++)
{
if (!strcmp(argv[i], "-d"))
{
if (!isdigit(argv[++i][0])
|| sscanf(argv[i], "%d", &debug) != 1)
adios (NULLCP, "usage: %s -d 0-7", myname);
advise(LLOG_DEBUG,NULLCP, "setting debug level to %d", debug);
if (debug)
ll_dbinit (vt_log, myname);
}
else if(!strcmp(argv[i], "-F"))
{
if ((logname = argv[++i]) == NULL || *logname == '-')
adios (NULLCP, "usage: %s -F logfile", myname);
vt_log -> ll_file = logname;
(void) ll_close (vt_log);
advise(LLOG_DEBUG,NULLCP, "logging to %s",logname);
}
else
adios(NULLCP, "usage: %s [-F logfile] [-d N]",
myname);
}
advise (LLOG_NOTICE,NULLCP, "starting");
acc = &accs;
acr = &acrs;
aci = &acis;
acs = &acss;
if (ass_ind(argc,argv) == OK) {
connected = TRUE;
if( !strcmp(vtp_profile.profile_name,"default") )
telnet_profile = 0;
}
else
exit(1);
/*
* Get a pty, scan input lines.
*/
for (j = 'p' ; j <= 't'; j++) {
cp[strlen ("/dev/pty")] = j;
for (i = 0; i < 16; i++) {
cp[strlen("/dev/ptyp")] = "0123456789abcdef"[i];
p = open(cp, 2);
if (p >= 0)
goto gotpty;
}
}
perror("All network ports in use");
vrelreq();
/*NOTREACHED*/
gotpty:
cp[strlen("/dev/")] = 't';
#ifndef BSD44
t = open("/dev/tty", 2);
if (t >= 0) {
if (ioctl(t, TIOCNOTTY, 0) == -1) {
perror("ioctl (TIOCNOTTY)");
}
(void)close(t);
}
#endif
t = open(cp, 2);
if (t < 0)
fatalperror(f, cp, errno);
#ifdef BSD44
if (tcgetattr(t, &term) == -1)
perror("tcgetattr");
else {
term.c_iflag = TTYDEF_IFLAG;
term.c_oflag = TTYDEF_OFLAG;
term.c_lflag = TTYDEF_LFLAG;
if (telnet_profile)
term.c_lflag &= ECHO;
else
term.c_lflag |= ECHO;
if (tcsetattr(t, TCSADFLUSH, &term) == -1)
perror("tcsetattr");
}
#else
if (ioctl(t, TIOCGETP, (char*)&b) == -1) {
perror("ioctl (TIOCGETP)");
adios(NULLCP, "ioctl failed (TIOCGETP)");
}
b.sg_flags = CRMOD|XTABS|ANYP;
if (ioctl(t, TIOCSETP, (char*)&b) == -1) {
perror("ioctl (TIOCSETP)");
adios(NULLCP, "ioctl failed (TIOCSETP)");
}
if (ioctl(p, TIOCGETP, (char*)&b) == -1) { /* XXX why is this done on the controller */
perror("ioctl (TIOCGETP)");
adios(NULLCP, "ioctl failed (TIOCGETP)");
}
if(telnet_profile)
b.sg_flags &= ~ECHO;
else
b.sg_flags |= ECHO; /*Remote echo for Default*/
if (ioctl(p, TIOCSETP, (char*)&b) == -1) {
perror("ioctl (TIOCSETP)");
adios(NULLCP, "ioctl failed (TIOCSETP)");
}
#endif
na_image = 0;
nego_state = 0; /*Start off in Local echo*/
if ((i = fork()) < 0)
fatalperror(f, "fork", errno);
if (i)
vtd(sd, p);
(void)close(sd);
(void)close(p);
#ifdef BSD44
if (setsid()== -1)
perror("setsid");
if (ioctl(t, TIOCSCTTY, 0) == -1)
perror("ioctl (TIOCSCTTY)");
#endif
if (dup2(t, 0) == -1) {
perror("dup2");
adios(NULLCP, "dup2 failed");
}
if (dup2(t, 1) == -1) {
perror("dup2");
adios(NULLCP, "dup2 failed");
}
if (dup2(t, 2) == -1) {
perror("dup2");
adios(NULLCP, "dup2 failed");
}
(void)close(t);
environ = envinit;
#ifndef NOTROOT
execl("/bin/login","login","-h",peerhost,NULLCP);
fatalperror(f, "/bin/login", errno);
#else
execl("/usr/mitre-sun/dchiriel/vtp/login","login","-h",peerhost,
NULLCP);
fatalperror(f, "/usr/mitre-sun/dchiriel/vtp/login", errno);
#endif
/*NOTREACHED*/
}
fatal(f, msg)
int f;
char *msg;
{
char buf[BUFSIZ];
(void) sprintf(buf, "%s: %s.\n", myname, msg);
(void) write(f, buf, strlen(buf));
adios (NULLCP, msg);
}
fatalperror(f, msg, errnum)
int f;
char *msg;
int errnum;
{
char buf[BUFSIZ];
extern char *sys_errlist[];
(void) sprintf(buf, "%s: %s", msg, sys_errlist[errnum]);
fatal(f, buf);
}
/*
* Main loop. Select from pty and network.
*/
vtd(f, p)
{
int on = 1;
int nfds, result;
do_cleaning = 1;
net = f, pty = p;
nfds = (f > p ? f : p) + 1;
if (ioctl(p, FIONBIO, (char*)&on) == -1) {
perror("ioctl");
adios(NULLCP, "ioctl failed (FIONBIO)");
}
#ifdef SIGTSTP
(void) signal(SIGTSTP, SIG_IGN);
#endif
#ifdef SIGCHLD
(void) signal(SIGCHLD, cleanup);
#endif
/*
* Show banner that getty never gave.
*/
myhostname = PLocalHostName ();
(void) sprintf(nfrontp, BANNER, myhostname, "");
nfrontp += strlen(nfrontp);
#ifdef BSD44
if (tcgetattr(pty, &oterm) == -1)
perror("tcgetattr");
erase_char = oterm.c_cc[VERASE];
erase_line = oterm.c_cc[VKILL];
intr_char = oterm.c_cc[VINTR];
#else
if (ioctl(pty,TIOCGETP,(char*)&ottyb) == -1) {
perror("ioctl");
adios(NULLCP, "ioctl failed (TIOCGETP)");
}
if (ioctl(pty,TIOCGETC,(char*)&otc) == -1) {
perror("ioctl");
adios(NULLCP, "ioctl failed (TIOCGETC)");
}
if (ioctl(pty,TIOCGLTC,(char*)&oltc) == -1) {
perror("ioctl");
adios(NULLCP, "ioctl failed (TIOCGLTC)");
}
erase_char = ottyb.sg_erase;
erase_line = ottyb.sg_kill;
intr_char = otc.t_intrc;
#endif
for (;;) {
fd_set ibits, obits;
register int c;
FD_ZERO (&ibits);
FD_ZERO (&obits);
/*
* Never look for input if there's still
* stuff in the corresponding output buffer
*/
if (nfrontp - nbackp) {
FD_SET (f, &obits);
}
else {
FD_SET (p, &ibits);
}
if (pfrontp - pbackp) {
FD_SET (p, &obits);
}
else {
FD_SET (f, &ibits);
}
if (FD_ISSET (f, &ibits) && data_pending()) {
FD_CLR (f, &ibits);
result = xselect(nfds, &ibits, &obits,
(fd_set *)NULL, OK);
if (result < 0)
adios("failed", "xselect");
FD_SET (f, &ibits);
}
else {
if (xselect(nfds, &ibits, &obits, (fd_set *)NULL,
NOTOK) == -1)
adios("failed", "xselect");
}
if (!FD_ISSET (f, &ibits)
&& !FD_ISSET (p, &ibits)
&& !FD_ISSET (f, &obits)
&& !FD_ISSET (p, &obits)) {
sleep(5);
continue;
}
/*
* Something to read from the network...
*/
if (FD_ISSET (f, &ibits)) {
while ((c = getch()) > 0)
*pfrontp++ = c;
}
if (c == E_EOF) {
break;
}
/*
* Something to read from the pty...
*/
if (FD_ISSET (p, &ibits)) {
pcc = read(p, nfrontp, (&netobuf[BUFSIZ] - nfrontp));
if (pcc < 0 && errno == EWOULDBLOCK)
pcc = 0;
else {
if (pcc <= 0) {
if (debug)
advise(LLOG_EXCEPTIONS,NULLCP,
"problem reading from pty");
break;
}
}
nfrontp += pcc;
}
if (FD_ISSET (f, &obits) && (nfrontp - nbackp) > 0)
netflush();
if (FD_ISSET (p, &obits) && (pfrontp - pbackp) > 0)
ptyflush();
}
if (debug)
advise(LLOG_DEBUG,NULLCP, "finished loop in vtp");
cleanup();
}
/*
* Send interrupt to process on other side of pty.
* If it is in raw mode, just write NULL;
* otherwise, write intr char.
*/
interrupt()
{
#ifdef BSD44
struct termios term;
ptyflush();
if (tcgetattr(pty, &term) == -1) {
perror("tcgetattr");
return;
}
if ((term.c_lflag&ISIG) && term.c_cc[VINTR] != _POSIX_VDISABLE)
*pfrontp++ = term.c_cc[VINTR];
else
*pfrontp++ = '\0';
#else
struct sgttyb b;
struct tchars tchars;
ptyflush(); /* half-hearted */
if (ioctl(pty, TIOCGETP, (char*)&b) == -1) {
perror("ioctl");
adios(NULLCP, "ioctl failed");
}
if (b.sg_flags & RAW) {
*pfrontp++ = '\0';
return;
}
*pfrontp++ = ioctl(pty, TIOCGETC, (char*)&tchars) < 0 ?
'\177' : tchars.t_intrc;
#endif
}
netflush()
{
register char *cp;
int n;
int i, j;
int nl_flag; /*Records if Newline is included in current PDU to
decide if Deliver Request should follow it. Should
not be required but some implementations may wait
for it before delivering NDQ to application*/
nl_flag = 0;
if ((n = nfrontp - nbackp) > 0) {
if (debug) {
(void) ll_log (vt_log, LLOG_DEBUG, NULLCP,
("writing to the net"));
(void) ll_printf (vt_log, "<<");
for(i=0; i<(nfrontp-nbackp); i++)
(void)ll_printf (vt_log, "%02x ",*(nbackp+i));
(void)ll_printf (vt_log, ">>\n");
(void)ll_sync (vt_log);
}
if(transparent)
{
(void)vt_text(nbackp,n);
vtsend();
cp = nbackp;
for(i=0; i<n; i++)
{
if((*cp == '\r') ||
(*cp == '\n'))
{
vdelreq(FALSE);
break;
}
++cp;
}
nbackp += n;
}
else
{
cp = nbackp;
for(i=0,j=0; i<n; i++)
{
if(*cp == '\r')
{
if(rflag) (void)vt_text(crp,1);
/*Previous char was CR so put one in NDQ*/
if(j)
(void)vt_text(nbackp,j);
nbackp += (j+1); /*Skip over current CR*/
cp = nbackp;
j = 0;
if(i == (n-1) ) (void)vt_text(crp,1);
/*If CR is last char in buffer, send it*/
else rflag = 1;
/*If not last char in buffer, read next one*/
continue;
}
else if(rflag) /*If previous character was CR*/
{
if(*cp == '\n') /*Got CR-LF -- map to Next X-Array*/
{
nbackp += (j+1);
cp = nbackp;
rflag = 0;
vt_newline();
++nl_flag;
continue;
}
else /*Preceeding char was CR but not followed by
LF. Put CR in buffer*/
(void) vt_text(crp,1);
rflag = 0;
}
if(telnet_profile)
{
rflag = 0;
#ifdef MAP_BACKSPACE
if(*cp == 0x08) /*If believed to be erase*/
{
if(j)
(void)vt_text(nbackp,j);
nbackp += (j+1);
cp = nbackp;
j = 0;
vt_char_erase();
continue;
}
#endif
if(!vtp_profile.arg_val.tel_arg_list.full_ascii)
/*If ASCII GO, dump ctrl chars*/
{
if((*cp < 0x20) || (*cp > 0x7e))
{
if(j)
(void)vt_text(nbackp,j);
nbackp += (j+1);
cp = nbackp;
j = 0;
}
else
{
++j; ++cp;
}
}
else
{
++j;
++cp;
}
}
else /*Else Default Profile*/
{
if((*cp < 0x20) || (*cp > 0x7e))
{
if(j)
(void)vt_text(nbackp,j);
nbackp += (j+1);
cp = nbackp;
j = 0;
}
else
{
++j;
++cp;
}
}
} /*End for loop*/
if(j)
(void)vt_text(nbackp,j); /*Load anything left if CR or LF
wasn't last char in buffer*/
nbackp += j;
vtsend(); /*Send the whole NDQ*/
if(nl_flag && telnet_profile) vdelreq(FALSE);
}
}
if (n < 0) {
if (errno != ENOBUFS && errno != EWOULDBLOCK) {
adios("closed", "association");
/*NOTREACHED*/
}
n = 0;
}
if (nbackp == nfrontp)
nbackp = nfrontp = netobuf;
}
SFD cleanup()
{
sleep(1);
while(getch() > 0); /*Clean out unread VT-DATA PDU's still held
in network. Kludge to overcome deficiency
in Session Release. */
rmut();
vhangup(); /* XXX */
vrelreq();
(void)kill(0, SIGKILL);
exit(1);
}
#include <utmp.h>
struct utmp wtmp;
char wtmpf[] = "/usr/adm/wtmp";
char utmp[] = "/etc/utmp";
#define SCPYN(a, b) strncpy(a, b, sizeof (a))
#define SCMPN(a, b) strncmp(a, b, sizeof (a))
long lseek (), time ();
rmut()
{
register f;
int found = 0;
f = open(utmp, 2);
if (f >= 0) {
while(read(f, (char *)&wtmp, sizeof (wtmp)) == sizeof (wtmp)) {
if (SCMPN(wtmp.ut_line, line+5) || wtmp.ut_name[0]==0)
continue;
(void)lseek(f, -(long)sizeof (wtmp), 1);
(void)SCPYN(wtmp.ut_name, "");
#if !defined(SYS5) && !defined(bsd43_ut_host)
(void)SCPYN(wtmp.ut_host, "");
#endif
(void)time(&wtmp.ut_time);
(void) write(f, (char *)&wtmp, sizeof (wtmp));
found++;
}
(void)close(f);
}
if (found) {
f = open(wtmpf, 1);
if (f >= 0) {
(void)SCPYN(wtmp.ut_line, line+5);
(void)SCPYN(wtmp.ut_name, "");
#if !defined(SYS5) && !defined(bsd43_ut_host)
(void)SCPYN(wtmp.ut_host, "");
#endif
(void)time(&wtmp.ut_time);
(void)lseek(f, (long)0, 2);
(void) write(f, (char *)&wtmp, sizeof (wtmp));
(void)close(f);
}
}
(void)chmod(line, 0666);
(void)chown(line, 0, 0);
line[strlen("/dev/")] = 'p';
(void)chmod(line, 0666);
(void)chown(line, 0, 0);
}
bye()
{
if(do_cleaning) {
rmut();
(void)kill(0, SIGKILL);
}
exit(0);
}
flushbufs()
{
pcc = 0;
pfrontp = pbackp = ptyobuf;
nfrontp = nbackp = netobuf;
while (getch() > 0)
continue;
}
/* \f
ERRORS */
void finalbye ()
{
bye ();
}
#ifndef lint
void adios (va_alist)
va_dcl
{
va_list ap;
va_start (ap);
(void) _ll_log (vt_log, LLOG_FATAL, ap);
va_end (ap);
bye ();
_exit (1);
}
#else
/* VARARGS2 */
void adios (what, fmt)
char *what,
*fmt;
{
adios (what, fmt);
}
#endif
#ifndef lint
void advise (va_alist)
va_dcl
{
int code;
va_list ap;
va_start (ap);
code = va_arg (ap, int);
(void) _ll_log (vt_log, code, ap);
va_end (ap);
}
#else
/* VARARGS3 */
void advise (code, what, fmt)
int code;
char *what,
*fmt;
{
advise (code, what, fmt);
}
#endif
ptyflush()
{
int n;
if ((n = pfrontp - pbackp) > 0)
{
n = write(pty, pbackp, n);
}
if (n < 0)
return;
pbackp += n;
if (pbackp == pfrontp)
pbackp = pfrontp = ptyobuf;
}
#ifdef BSD44
ptyecho(on)
{
struct termios term;
ptyflush();
if (tcgetattr(pty, &term) == -1) {
perror("tcgetattr");
return;
}
if (on)
term.c_lflag |= ECHO;
else
term.c_lflag &= ECHO;
if (tcsetattr(pty, TCSADFLUSH, &term) == -1) {
perror("tcsetattr");
return;
}
}
#else
setmode(on, off)
int on, off;
{
struct sgttyb b;
ptyflush();
if(ioctl(pty, TIOCGETP, (char*)&b) < 0) {
perror("ioctl");
adios(NULLCP, "ioctl failed");
}
b.sg_flags |= on;
b.sg_flags &= ~off;
if (ioctl(pty, TIOCSETP, (char*)&b) == -1) {
perror("ioctl");
adios(NULLCP, "ioctl failed");
}
}
#endif