* Copyright (c) 1989 Regents of the University of California.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
"@(#) Copyright (c) 1989 Regents of the University of California.\n\
static char sccsid
[] = "@(#)telnetd.c 5.48 (Berkeley) 3/1/91";
#if defined(AUTHENTICATE)
#include <libtelnet/auth.h>
* pointers, and counters.
char ptyibuf
[BUFSIZ
], *ptyip
= ptyibuf
;
int hostinfo
= 1; /* do we print login banner? */
extern int newmap
; /* nonzero if \n maps to ^M^J */
int lowpty
= 0, highpty
; /* low, high pty numbers */
extern void usage
P((void));
#if defined(IPPROTO_IP) && defined(IP_TOS)
pfrontp
= pbackp
= ptyobuf
;
nfrontp
= nbackp
= netobuf
;
* Get number of pty's before trying to process options,
* which may include changing pty range.
while ((ch
= getopt(argc
, argv
, "d:a:e:lhnr:I:D:B:sS:a:X:")) != EOF
) {
* Check for required authentication level
if (strcmp(optarg
, "debug") == 0) {
extern int auth_debug_mode
;
} else if (strcasecmp(optarg
, "none") == 0) {
} else if (strcasecmp(optarg
, "other") == 0) {
} else if (strcasecmp(optarg
, "user") == 0) {
} else if (strcasecmp(optarg
, "valid") == 0) {
} else if (strcasecmp(optarg
, "off") == 0) {
* This hack turns off authentication
"telnetd: unknown authorization level for -a\n");
#endif /* AUTHENTICATE */
if (strcmp(optarg
, "ebug") == 0) {
* Check for desired diagnostics capabilities.
if (!strcmp(optarg
, "report")) {
diagnostic
|= TD_REPORT
|TD_OPTIONS
;
} else if (!strcmp(optarg
, "exercise")) {
diagnostic
|= TD_EXERCISE
;
} else if (!strcmp(optarg
, "netdata")) {
diagnostic
|= TD_NETDATA
;
} else if (!strcmp(optarg
, "ptydata")) {
diagnostic
|= TD_PTYDATA
;
} else if (!strcmp(optarg
, "options")) {
diagnostic
|= TD_OPTIONS
;
if (strcmp(optarg
, "debug") == 0) {
extern int encrypt_debug_mode
;
#endif /* AUTHENTICATE */
#if defined(CRAY) && defined(NEWINIT)
#endif /* defined(CRAY) && defined(NEWINIT) */
* Allow the specification of alterations
* to the pty search range. It is legal to
* specify only one, and not change the
* other from its default.
if ((lowpty
> highpty
) || (lowpty
< 0) ||
if ((tos
= parsetos(optarg
, "tcp")) < 0)
fprintf(stderr
, "%s%s%s\n",
"telnetd: Bad TOS argument '", optarg
,
"'; will try to use default TOS");
fprintf(stderr
, "%s%s\n", "TOS option unavailable; ",
"-S flag not supported\n");
* Check for invalid authentication types
auth_disable_name(optarg
);
#endif /* AUTHENTICATE */
fprintf(stderr
, "telnetd: %s: unknown option\n", ch
);
static struct sockaddr_in sin
= { AF_INET
};
if (sp
= getservbyname(*argv
, "tcp")) {
sin
.sin_port
= sp
->s_port
;
sin
.sin_port
= atoi(*argv
);
if ((int)sin
.sin_port
<= 0) {
fprintf(stderr
, "telnetd: %s: bad port #\n", *argv
);
sin
.sin_port
= htons((u_short
)sin
.sin_port
);
sp
= getservbyname("telnet", "tcp");
fprintf(stderr
, "telnetd: tcp/telnet: unknown service\n");
sin
.sin_port
= sp
->s_port
;
s
= socket(AF_INET
, SOCK_STREAM
, 0);
perror("telnetd: socket");;
(void) setsockopt(s
, SOL_SOCKET
, SO_REUSEADDR
, &on
, sizeof(on
));
if (bind(s
, (struct sockaddr
*)&sin
, sizeof sin
) < 0) {
ns
= accept(s
, (struct sockaddr
*)&sin
, &foo
);
; /* VOID*/ /* Just ignore the host/port name */
openlog("telnetd", LOG_PID
| LOG_ODELAY
, LOG_DAEMON
);
if (getpeername(0, (struct sockaddr
*)&from
, &fromlen
) < 0) {
fprintf(stderr
, "%s: ", progname
);
setsockopt(0, SOL_SOCKET
, SO_KEEPALIVE
, &on
, sizeof (on
)) < 0) {
syslog(LOG_WARNING
, "setsockopt (SO_KEEPALIVE): %m");
#if defined(IPPROTO_IP) && defined(IP_TOS)
if (tos
< 0 && (tp
= gettosbyname("telnet", "tcp")))
tos
= 020; /* Low Delay bit */
&& (setsockopt(0, IPPROTO_IP
, IP_TOS
, &tos
, sizeof(tos
)) < 0)
&& (errno
!= ENOPROTOOPT
) )
syslog(LOG_WARNING
, "setsockopt (IP_TOS): %m");
#endif /* defined(IPPROTO_IP) && defined(IP_TOS) */
fprintf(stderr
, "Usage: telnetd");
fprintf(stderr
, " [-a (debug|other|user|valid|off)]\n\t");
fprintf(stderr
, " [-B]");
fprintf(stderr
, " [-debug]");
fprintf(stderr
, " [-D (options|report|exercise|netdata|ptydata)]\n\t");
fprintf(stderr
, " [-edebug]");
fprintf(stderr
, " [-h]");
#if defined(CRAY) && defined(NEWINIT)
fprintf(stderr
, " [-Iinitid]");
fprintf(stderr
, " [-l]");
fprintf(stderr
, " [-n]");
fprintf(stderr
, " [-r[lowpty]-[highpty]]");
fprintf(stderr
, " [-s]");
fprintf(stderr
, " [-X auth-type]");
fprintf(stderr
, " [port]\n");
* Ask the other end to send along its terminal type and speed.
* Output is the variable terminaltype filled in.
static char ttytype_sbbuf
[] = { IAC
, SB
, TELOPT_TTYPE
, TELQUAL_SEND
, IAC
, SE
};
#if defined(AUTHENTICATE)
* Handle the Authentication option before we do anything else.
send_do(TELOPT_AUTHENTICATION
, 1);
while (his_will_wont_is_changing(TELOPT_AUTHENTICATION
))
if (his_state_is_will(TELOPT_AUTHENTICATION
)) {
retval
= auth_wait(name
);
send_will(TELOPT_ENCRYPT
, 1);
send_do(TELOPT_TTYPE
, 1);
send_do(TELOPT_TSPEED
, 1);
send_do(TELOPT_XDISPLOC
, 1);
send_do(TELOPT_ENVIRON
, 1);
his_do_dont_is_changing(TELOPT_ENCRYPT
) ||
his_will_wont_is_changing(TELOPT_TTYPE
) ||
his_will_wont_is_changing(TELOPT_TSPEED
) ||
his_will_wont_is_changing(TELOPT_XDISPLOC
) ||
his_will_wont_is_changing(TELOPT_ENVIRON
)) {
* Wait for the negotiation of what type of encryption we can
* send with. If autoencrypt is not set, this will just return.
if (his_state_is_will(TELOPT_ENCRYPT
)) {
if (his_state_is_will(TELOPT_TSPEED
)) {
static char sbbuf
[] = { IAC
, SB
, TELOPT_TSPEED
, TELQUAL_SEND
, IAC
, SE
};
bcopy(sbbuf
, nfrontp
, sizeof sbbuf
);
if (his_state_is_will(TELOPT_XDISPLOC
)) {
static char sbbuf
[] = { IAC
, SB
, TELOPT_XDISPLOC
, TELQUAL_SEND
, IAC
, SE
};
bcopy(sbbuf
, nfrontp
, sizeof sbbuf
);
if (his_state_is_will(TELOPT_ENVIRON
)) {
static char sbbuf
[] = { IAC
, SB
, TELOPT_ENVIRON
, TELQUAL_SEND
, IAC
, SE
};
bcopy(sbbuf
, nfrontp
, sizeof sbbuf
);
if (his_state_is_will(TELOPT_TTYPE
)) {
bcopy(ttytype_sbbuf
, nfrontp
, sizeof ttytype_sbbuf
);
nfrontp
+= sizeof ttytype_sbbuf
;
if (his_state_is_will(TELOPT_TSPEED
)) {
while (sequenceIs(tspeedsubopt
, baseline
))
if (his_state_is_will(TELOPT_XDISPLOC
)) {
while (sequenceIs(xdisplocsubopt
, baseline
))
if (his_state_is_will(TELOPT_ENVIRON
)) {
while (sequenceIs(environsubopt
, baseline
))
if (his_state_is_will(TELOPT_TTYPE
)) {
char first
[256], last
[256];
while (sequenceIs(ttypesubopt
, baseline
))
* If the other side has already disabled the option, then
* we have to just go with what we (might) have already gotten.
if (his_state_is_will(TELOPT_TTYPE
) && !terminaltypeok(terminaltype
)) {
(void) strncpy(first
, terminaltype
, sizeof(first
));
* Save the unknown name, and request the next name.
(void) strncpy(last
, terminaltype
, sizeof(last
));
if (terminaltypeok(terminaltype
))
if ((strncmp(last
, terminaltype
, sizeof(last
)) == 0) ||
his_state_is_wont(TELOPT_TTYPE
)) {
* We've hit the end. If this is the same as
* the first name, just go with it.
if (strncmp(first
, terminaltype
, sizeof(first
)) == 0)
* Get the terminal name one more time, so that
* RFC1091 compliant telnets will cycle back to
if (strncmp(first
, terminaltype
, sizeof(first
)) != 0)
(void) strncpy(terminaltype
, first
, sizeof(first
));
} /* end of getterminaltype */
* If the client turned off the option,
* we can't send another request, so we
if (his_state_is_wont(TELOPT_TTYPE
))
bcopy(ttytype_sbbuf
, nfrontp
, sizeof ttytype_sbbuf
);
nfrontp
+= sizeof ttytype_sbbuf
;
while (sequenceIs(ttypesubopt
, baseline
))
if (terminaltype
== NULL
)
* tgetent() will return 1 if the type is known, and
* 0 if it is not known. If it returns -1, it couldn't
* open the database. But if we can't open the database,
* it won't help to say we failed, because we won't be
* able to verify anything else. So, we treat -1 like 1.
if (tgetent(buf
, s
) == 0)
#define MAXHOSTNAMELEN 64
#endif /* MAXHOSTNAMELEN */
char host_name
[MAXHOSTNAMELEN
];
char remote_host_name
[MAXHOSTNAMELEN
];
extern void telnet
P((int, int));
extern void telnet
P((int, int, char *));
* Get a pty, scan input lines.
char *host
, *inet_ntoa();
* Find an available pty to use.
fatal(net
, "All network ports in use");
extern char *line
, *getpty();
if ((lp
= getpty()) == NULL
)
fatal(net
, "Out of ptys");
if ((pty
= open(lp
, 2)) >= 0) {
/* get name of connected client */
hp
= gethostbyaddr((char *)&who
->sin_addr
, sizeof (struct in_addr
),
host
= inet_ntoa(who
->sin_addr
);
* We must make a copy because Kerberos is probably going
* to also do a gethost* and overwrite the static data...
strncpy(remote_host_name
, host
, sizeof(remote_host_name
)-1);
remote_host_name
[sizeof(remote_host_name
)-1] = 0;
(void) gethostname(host_name
, sizeof (host_name
));
#if defined(AUTHENTICATE) || defined(ENCRYPT)
auth_encrypt_init(hostname
, host
, "TELNETD", 1);
level
= getterminaltype(user_name
);
setenv("TERM", terminaltype
? terminaltype
: "network", 1);
* Start up the login process on the slave side of the terminal
startslave(host
, level
, user_name
);
telnet(net
, pty
); /* begin server processing */
#if defined(CRAY2) && defined(UNICOS5) && defined(UNICOS50)
Xterm_output(ibufp
, obuf
, icountp
, ocount
)
ret
= term_output(*ibufp
, obuf
, *icountp
, ocount
);
#define term_output Xterm_output
#endif /* defined(CRAY2) && defined(UNICOS5) && defined(UNICOS50) */
* Main loop. Select from pty and network, and
* hand data to telnet receiver finite state machine.
* Initialize the slc mapping table.
* Do some tests where it is desireable to wait for a response.
* Rather than doing them slowly, one at a time, do them all
if (my_state_is_wont(TELOPT_SGA
))
send_will(TELOPT_SGA
, 1);
* Is the client side a 4.2 (NOT 4.3) system? We need to know this
* because 4.2 clients are unable to deal with TCP urgent data.
* To find out, we send out a "DO ECHO". If the remote system
* answers "WILL ECHO" it is probably a 4.2 client, and we note
* that fact ("WILL ECHO" ==> that the client will echo what
* WE, the server, sends it; it does NOT mean that the client will
* echo the terminal input).
if (his_state_is_wont(TELOPT_LINEMODE
)) {
/* Query the peer for linemode support by trying to negotiate
send_do(TELOPT_LINEMODE
, 1); /* send do linemode */
* Send along a couple of other options that we wish to negotiate.
send_will(TELOPT_STATUS
, 1);
flowmode
= 1; /* default flow control state */
send_do(TELOPT_LFLOW
, 1);
* Spin, waiting for a response from the DO ECHO. However,
* some REALLY DUMB telnets out there might not respond
* to the DO ECHO. So, we spin looking for NAWS, (most dumb
* telnets so far seem to respond with WONT for a DO that
* they don't understand...) because by the time we get the
* response, it will already have processed the DO ECHO.
while (his_will_wont_is_changing(TELOPT_NAWS
))
* The client might have sent a WILL NAWS as part of its
* startup code; if so, we'll be here before we get the
* response to the DO ECHO. We'll make the assumption
* that any implementation that understands about NAWS
* is a modern enough implementation that it will respond
* to our DO ECHO request; hence we'll do another spin
* waiting for the ECHO option to settle down, which is
* what we wanted to do in the first place...
if (his_want_state_is_will(TELOPT_ECHO
) &&
his_state_is_will(TELOPT_NAWS
)) {
while (his_will_wont_is_changing(TELOPT_ECHO
))
* On the off chance that the telnet client is broken and does not
* respond to the DO ECHO we sent, (after all, we did send the
* DO NAWS negotiation after the DO ECHO, and we won't get here
* until a response to the DO NAWS comes back) simulate the
* receipt of a will echo. This will also send a WONT ECHO
* to the client, since we assume that the client failed to
* respond because it believes that it is already in DO ECHO
* mode, which we do not want.
if (his_want_state_is_will(TELOPT_ECHO
)) {
{sprintf(nfrontp
, "td: simulating recv\r\n");
nfrontp
+= strlen(nfrontp
);});
* Finally, to clean things up, we turn on our echo. This
* will break stupid 4.2 telnets out of local terminal echo.
if (my_state_is_wont(TELOPT_ECHO
))
send_will(TELOPT_ECHO
, 1);
(void) ioctl(p
, TIOCPKT
, (char *)&on
);
#if defined(LINEMODE) && defined(KLUDGELINEMODE)
* Continuing line mode support. If client does not support
* real linemode, attempt to negotiate kludge linemode by sending
* the do timing mark sequence.
if (lmodetype
< REAL_LINEMODE
)
#endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
* Call telrcv() once to pick up anything received during
* terminal type negotiation, 4.2/4.3 determination, and
(void) ioctl(f
, FIONBIO
, (char *)&on
);
(void) ioctl(p
, FIONBIO
, (char *)&on
);
#if defined(CRAY2) && defined(UNICOS5)
init_termdriver(f
, p
, interrupt
, sendbrk
);
#if defined(SO_OOBINLINE)
(void) setsockopt(net
, SOL_SOCKET
, SO_OOBINLINE
, &on
, sizeof on
);
#endif /* defined(SO_OOBINLINE) */
(void) signal(SIGTSTP
, SIG_IGN
);
* Ignoring SIGTTOU keeps the kernel from blocking us
* in ttioct() in /sys/tty.c.
(void) signal(SIGTTOU
, SIG_IGN
);
(void) signal(SIGCHLD
, cleanup
);
#if defined(CRAY2) && defined(UNICOS5)
* Cray-2 will send a signal when pty modes are changed by slave
* side. Set up signal handler now.
if ((int)signal(SIGUSR1
, termstat
) < 0)
else if (ioctl(p
, TCSIGME
, (char *)SIGUSR1
) < 0)
* Make processing loop check terminal characteristics early on.
t
= open(_PATH_TTY
, O_RDWR
);
(void) ioctl(t
, TIOCNOTTY
, (char *)0);
#if defined(CRAY) && defined(NEWINIT) && defined(TIOCSCTTY)
* Show banner that getty never gave.
* We put the banner in the pty input buffer. This way, it
* gets carriage return null processing, etc., just like all
* other pty --> client data.
#if !defined(CRAY) || !defined(NEWINIT)
if (getent(defent
, "default") == 1) {
(void) strcpy(host_name
, HN
);
static char issue_message
[256];
extern char *_osnamever();
snprintf(issue_message
, sizeof issue_message
,
DEFAULT_IM
, _osnamever());
(void) strncat(ptyibuf2
, ptyip
, pcc
+1);
* Last check to make sure all our states are correct.
{sprintf(nfrontp
, "td: Entering processing loop\r\n");
nfrontp
+= strlen(nfrontp
);});
fd_set ibits
, obits
, xbits
;
#if defined(CRAY2) && defined(UNICOS5)
#endif /* defined(CRAY2) && defined(UNICOS5) */
* Never look for input if there's still
* stuff in the corresponding output buffer
if (nfrontp
- nbackp
|| pcc
> 0) {
if (pfrontp
- pbackp
|| ncc
> 0) {
if ((c
= select(16, &ibits
, &obits
, &xbits
,
(struct timeval
*)0)) < 1) {
if (FD_ISSET(net
, &xbits
)) {
* Something to read from the network...
if (FD_ISSET(net
, &ibits
)) {
#if !defined(SO_OOBINLINE)
* In 4.2 (and 4.3 beta) systems, the
* OOB indication and data handling in the kernel
* is such that if two separate TCP Urgent requests
* come in, one byte of TCP data will be overlaid.
* This is fatal for Telnet, but we try to live
* In addition, in 4.2 (and...), a special protocol
* is needed to pick up the TCP Urgent data in
* What we do is: if we think we are in urgent
* mode, we look to see if we are "at the mark".
* If we are, we do an OOB receive. If we run
* this twice, we will do the OOB receive twice,
* but the second will fail, since the second
* time we were "at the mark", but there wasn't
* any data there (the kernel doesn't reset
* "at the mark" until we do a normal read).
* Once we've read the OOB data, we go ahead
* There is also another problem, which is that
* since the OOB byte we read doesn't put us
* out of OOB state, and since that byte is most
* likely the TELNET DM (data mark), we would
* stay in the TELNET SYNCH (SYNCHing) state.
* So, clocks to the rescue. If we've "just"
* received a DM, then we test for the
* presence of OOB data when the receive OOB
* fails (and AFTER we did the normal mode read
* to clear "at the mark").
(void) ioctl(net
, SIOCATMARK
, (char *)&atmark
);
ncc
= recv(net
, netibuf
, sizeof (netibuf
), MSG_OOB
);
if ((ncc
== -1) && (errno
== EINVAL
)) {
ncc
= read(net
, netibuf
, sizeof (netibuf
));
if (sequenceIs(didnetreceive
, gotDM
)) {
SYNCHing
= stilloob(net
);
ncc
= read(net
, netibuf
, sizeof (netibuf
));
ncc
= read(net
, netibuf
, sizeof (netibuf
));
#else /* !defined(SO_OOBINLINE)) */
ncc
= read(net
, netibuf
, sizeof (netibuf
));
#endif /* !defined(SO_OOBINLINE)) */
if (ncc
< 0 && errno
== EWOULDBLOCK
)
DIAG((TD_REPORT
| TD_NETDATA
),
{sprintf(nfrontp
, "td: netread %d chars\r\n", ncc
);
nfrontp
+= strlen(nfrontp
);});
DIAG(TD_NETDATA
, printdata("nd", netip
, ncc
));
* Something to read from the pty...
if (FD_ISSET(p
, &ibits
)) {
pcc
= read(p
, ptyibuf
, BUFSIZ
);
* On some systems, if we try to read something
* off the master side before the slave side is
if (pcc
< 0 && (errno
== EWOULDBLOCK
|| errno
== EIO
)) {
#if !defined(CRAY2) || !defined(UNICOS5)
* If ioctl from pty, pass it through net
if (ptyibuf
[0] & TIOCPKT_IOCTL
) {
copy_termbuf(ptyibuf
+1, pcc
-1);
if (ptyibuf
[0] & TIOCPKT_FLUSHWRITE
) {
netclear(); /* clear buffer back */
* There are client telnets on some
* operating systems get screwed up
* royally if we send them urgent
neturg
= nfrontp
-1; /* off by one XXX */
if (his_state_is_will(TELOPT_LFLOW
) &&
(TIOCPKT_NOSTOP
|TIOCPKT_DOSTOP
))) {
(void) sprintf(nfrontp
, "%c%c%c%c%c%c",
ptyibuf
[0] & TIOCPKT_DOSTOP
? 1 : 0,
#else /* defined(CRAY2) && defined(UNICOS5) */
pcc
= term_output(&unptyip
, ptyibuf2
,
#endif /* defined(CRAY2) && defined(UNICOS5) */
if ((&netobuf
[BUFSIZ
] - nfrontp
) < 2)
c
= *ptyip
++ & 0377, pcc
--;
#if defined(CRAY2) && defined(UNICOS5)
my_state_is_wont(TELOPT_BINARY
) && newmap
)
#endif /* defined(CRAY2) && defined(UNICOS5) */
if ((c
== '\r') && (my_state_is_wont(TELOPT_BINARY
))) {
if (pcc
> 0 && ((*ptyip
& 0377) == '\n')) {
*nfrontp
++ = *ptyip
++ & 0377;
#if defined(CRAY2) && defined(UNICOS5)
* If chars were left over from the terminal driver,
if (!uselinemode
&& unpcc
) {
#endif /* defined(CRAY2) && defined(UNICOS5) */
if (FD_ISSET(f
, &obits
) && (nfrontp
- nbackp
) > 0)
if (FD_ISSET(p
, &obits
) && (pfrontp
- pbackp
) > 0)
* Send interrupt to process on other side of pty.
* If it is in raw mode, just write NULL;
* otherwise, write intr char.
ptyflush(); /* half-hearted */
(void) ioctl(pty
, TCSIG
, (char *)SIGINT
);
*pfrontp
++ = slctab
[SLC_IP
].sptr
?
(unsigned char)*slctab
[SLC_IP
].sptr
: '\177';
* Send quit to process on other side of pty.
* If it is in raw mode, just write NULL;
* otherwise, write quit char.
ptyflush(); /* half-hearted */
(void) ioctl(pty
, TCSIG
, (char *)SIGQUIT
);
*pfrontp
++ = slctab
[SLC_ABORT
].sptr
?
(unsigned char)*slctab
[SLC_ABORT
].sptr
: '\034';
ptyflush(); /* half-hearted */
(void) ioctl(pty
, TCSIG
, (char *)SIGTSTP
);
*pfrontp
++ = slctab
[SLC_SUSP
].sptr
?
(unsigned char)*slctab
[SLC_SUSP
].sptr
: '\032';
* When we get an AYT, if ^T is enabled, use that. Otherwise,
* just send back "[Yes]".
#if defined(SIGINFO) && defined(TCSIG)
if (slctab
[SLC_AYT
].sptr
&& *slctab
[SLC_AYT
].sptr
!= _POSIX_VDISABLE
) {
(void) ioctl(pty
, TCSIG
, (char *)SIGINFO
);
(void) strcpy(nfrontp
, "\r\n[Yes]\r\n");
#if defined(LINEMODE) && defined(USE_TERMIO) && (VEOF == VMIN)
*pfrontp
++ = slctab
[SLC_EOF
].sptr
?
(unsigned char)*slctab
[SLC_EOF
].sptr
: '\004';