new copyright notice
[unix-history] / usr / src / libexec / telnetd / telnetd.c
CommitLineData
8c5eec2f 1/*
ea139302 2 * Copyright (c) 1989 Regents of the University of California.
897ce52e
KB
3 * All rights reserved.
4 *
836fe169 5 * %sccs.include.redist.c%
8c5eec2f
DF
6 */
7
8#ifndef lint
9char copyright[] =
ea139302 10"@(#) Copyright (c) 1989 Regents of the University of California.\n\
8c5eec2f 11 All rights reserved.\n";
897ce52e 12#endif /* not lint */
8c5eec2f 13
ac6e6727 14#ifndef lint
836fe169 15static char sccsid[] = "@(#)telnetd.c 5.43 (Berkeley) %G%";
897ce52e 16#endif /* not lint */
ac6e6727 17
ea139302 18#include "telnetd.h"
66b878f6
BJ
19
20/*
ea139302
PB
21 * I/O data buffers,
22 * pointers, and counters.
66b878f6
BJ
23 */
24char ptyibuf[BUFSIZ], *ptyip = ptyibuf;
ea139302 25char ptyibuf2[BUFSIZ];
affdaa4e 26
ea139302
PB
27#ifdef CRAY
28int hostinfo = 1; /* do we print login banner? */
29#endif
affdaa4e 30
ea139302
PB
31#ifdef CRAY
32extern int newmap; /* nonzero if \n maps to ^M^J */
ed8f31c1 33int lowpty = 0, highpty; /* low, high pty numbers */
ea139302 34#endif /* CRAY */
affdaa4e 35
ea139302
PB
36int debug = 0;
37char *progname;
66b878f6 38
ed8f31c1
PB
39#if defined(IP_TOS) && defined(NEED_GETTOS)
40struct tosent {
41 char *t_name; /* name */
42 char **t_aliases; /* alias list */
43 char *t_proto; /* protocol */
44 int t_tos; /* Type Of Service bits */
45};
46
47struct tosent *
48gettosbyname(name, proto)
49char *name, *proto;
50{
51 static struct tosent te;
52 static char *aliasp = 0;
53
54 te.t_name = name;
55 te.t_aliases = &aliasp;
56 te.t_proto = proto;
57 te.t_tos = 020; /* Low Delay bit */
58 return(&te);
59}
60#endif
61
66b878f6
BJ
62main(argc, argv)
63 char *argv[];
64{
bb933cc2 65 struct sockaddr_in from;
bcb894cb 66 int on = 1, fromlen;
ed8f31c1
PB
67#ifdef IP_TOS
68 struct tosent *tp;
69#endif /* IP_TOS */
bb933cc2 70
ea139302
PB
71 pfrontp = pbackp = ptyobuf;
72 netip = netibuf;
73 nfrontp = nbackp = netobuf;
74
75 progname = *argv;
ed8f31c1
PB
76
77#ifdef CRAY
78 /*
79 * Get number of pty's before trying to process options,
80 * which may include changing pty range.
81 */
82 highpty = getnpty();
83#endif /* CRAY */
84
ea139302
PB
85top:
86 argc--, argv++;
87
88 if (argc > 0 && strcmp(*argv, "-debug") == 0) {
89 debug++;
90 goto top;
91 }
92
93#ifdef LINEMODE
94 if (argc > 0 && !strcmp(*argv, "-l")) {
95 alwayslinemode = 1;
96 goto top;
97 }
98#endif /* LINEMODE */
99
100#ifdef CRAY
101 if (argc > 0 && !strcmp(*argv, "-h")) {
102 hostinfo = 0;
103 goto top;
104 }
105
106 if (argc > 0 && !strncmp(*argv, "-r", 2)) {
107 char *strchr();
108 char *c;
109
ed8f31c1
PB
110 /*
111 * Allow the specification of alterations to the pty search
112 * range. It is legal to specify only one, and not change the
113 * other from its default.
114 */
ea139302
PB
115 *argv += 2;
116 if (**argv == '\0' && argc)
117 argv++, argc--;
118 c = strchr(*argv, '-');
119 if (c) {
120 *c++ = '\0';
121 highpty = atoi(c);
ed8f31c1
PB
122 }
123 if (**argv != '\0')
124 lowpty = atoi(*argv);
125 if ((lowpty > highpty) || (lowpty < 0) || (highpty > 32767)) {
ea139302
PB
126 usage:
127 fprintf(stderr, "Usage: telnetd [-debug] [-h] ");
128# ifdef NEWINIT
129 fprintf(stderr, "[-Iinitid] ");
130# endif /* NEWINIT */
ed8f31c1 131 fprintf(stderr, "[-l] [-r[lowpty]-[highpty]] [port]\n");
ea139302
PB
132 exit(1);
133 }
134 goto top;
135 }
136# ifdef NEWINIT
137 if (argc > 0 && !strncmp(*argv, "-I", 2)) {
138 extern char *gen_id;
139
140 *argv += 2;
141 if (**argv == '\0') {
142 if (argc < 2)
143 goto usage;
144 argv++, argc--;
145 if (**argv == '\0')
146 goto usage;
147 }
148 gen_id = *argv;
149 goto top;
150 }
151# endif /* NEWINIT */
152#endif /* CRAY */
153
154 if (debug) {
5d78ef73
GM
155 int s, ns, foo;
156 struct servent *sp;
157 static struct sockaddr_in sin = { AF_INET };
158
ea139302
PB
159 if (argc > 0) {
160 if (sp = getservbyname(*argv, "tcp")) {
161 sin.sin_port = sp->s_port;
162 } else {
163 sin.sin_port = atoi(*argv);
164 if ((int)sin.sin_port <= 0) {
165 fprintf(stderr, "telnetd: %s: bad port #\n", *argv);
166 exit(1);
167 }
168 sin.sin_port = htons((u_short)sin.sin_port);
169 }
31004941
GM
170 } else {
171 sp = getservbyname("telnet", "tcp");
172 if (sp == 0) {
173 fprintf(stderr,
174 "telnetd: tcp/telnet: unknown service\n");
ea139302 175 exit(1);
31004941
GM
176 }
177 sin.sin_port = sp->s_port;
5d78ef73
GM
178 }
179
180 s = socket(AF_INET, SOCK_STREAM, 0);
181 if (s < 0) {
182 perror("telnetd: socket");;
183 exit(1);
184 }
ea139302
PB
185 (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
186 if (bind(s, (struct sockaddr *)&sin, sizeof sin) < 0) {
5d78ef73
GM
187 perror("bind");
188 exit(1);
189 }
190 if (listen(s, 1) < 0) {
191 perror("listen");
192 exit(1);
193 }
194 foo = sizeof sin;
ea139302 195 ns = accept(s, (struct sockaddr *)&sin, &foo);
5d78ef73
GM
196 if (ns < 0) {
197 perror("accept");
198 exit(1);
199 }
ea139302
PB
200 (void) dup2(ns, 0);
201 (void) close(ns);
202 (void) close(s);
5d78ef73 203 }
ea139302 204
076ae92c 205 openlog("telnetd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
bb933cc2 206 fromlen = sizeof (from);
ea139302
PB
207 if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
208 fprintf(stderr, "%s: ", progname);
bb933cc2
MK
209 perror("getpeername");
210 _exit(1);
de3b21e8 211 }
bcb894cb 212 if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) {
3f99c0f7 213 syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
de3b21e8 214 }
ed8f31c1
PB
215
216#ifdef IP_TOS
217 if ((tp = gettosbyname("telnet", "tcp")) &&
218 (setsockopt(0, IPPROTO_IP, IP_TOS, &tp->t_tos, sizeof(int)) < 0))
219 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
220#endif /* IP_TOS */
ea139302
PB
221 net = 0;
222 doit(&from);
223 /* NOTREACHED */
224} /* end of main */
f553aca8 225
ed8f31c1 226void cleanup();
affdaa4e 227
d8b5e42c
GM
228/*
229 * getterminaltype
affdaa4e 230 *
ea139302 231 * Ask the other end to send along its terminal type and speed.
d8b5e42c 232 * Output is the variable terminaltype filled in.
affdaa4e 233 */
ea139302 234static char ttytype_sbbuf[] = { IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE };
d8b5e42c
GM
235void
236getterminaltype()
affdaa4e 237{
ea139302 238 void ttloop();
affdaa4e 239
ea139302 240 settimer(baseline);
053fd49d
PB
241 send_do(TELOPT_TTYPE, 1);
242 send_do(TELOPT_TSPEED, 1);
ea139302
PB
243 while ((hiswants[TELOPT_TTYPE] != hisopts[TELOPT_TTYPE]) ||
244 (hiswants[TELOPT_TSPEED] != hisopts[TELOPT_TSPEED])) {
d8b5e42c 245 ttloop();
affdaa4e 246 }
ea139302
PB
247 if (hisopts[TELOPT_TSPEED] == OPT_YES) {
248 static char sbbuf[] = { IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE };
affdaa4e 249
d8b5e42c
GM
250 bcopy(sbbuf, nfrontp, sizeof sbbuf);
251 nfrontp += sizeof sbbuf;
ea139302
PB
252 }
253 if (hisopts[TELOPT_TTYPE] == OPT_YES) {
254
255 bcopy(ttytype_sbbuf, nfrontp, sizeof ttytype_sbbuf);
256 nfrontp += sizeof ttytype_sbbuf;
257 }
258 if (hisopts[TELOPT_TSPEED] == OPT_YES) {
259 while (sequenceIs(tspeedsubopt, baseline))
260 ttloop();
261 }
262 if (hisopts[TELOPT_TTYPE] == OPT_YES) {
263 char first[256], last[256];
264
265 while (sequenceIs(ttypesubopt, baseline))
d8b5e42c 266 ttloop();
ea139302
PB
267
268 if (!terminaltypeok(&terminaltype[5])) {
269 (void) strncpy(first, terminaltype, sizeof(first));
270 for(;;) {
271 /*
272 * Save the unknown name, and request the next name.
273 */
274 (void) strncpy(last, terminaltype, sizeof(last));
275 _gettermname();
276 if (terminaltypeok(&terminaltype[5]))
277 break;
278 if (strncmp(last, terminaltype, sizeof(last)) == 0) {
279 /*
280 * We've hit the end. If this is the same as
281 * the first name, just go with it.
282 */
283 if (strncmp(first, terminaltype, sizeof(first) == 0))
284 break;
285 /*
286 * Get the terminal name one more type, so that
287 * RFC1091 compliant telnets will cycle back to
288 * the start of the list.
289 */
290 _gettermname();
291 if (strncmp(first, terminaltype, sizeof(first) != 0))
292 (void) strncpy(terminaltype, first, sizeof(first));
293 break;
294 }
295 }
d8b5e42c
GM
296 }
297 }
ea139302
PB
298} /* end of getterminaltype */
299
300_gettermname()
301{
302 settimer(baseline);
303 bcopy(ttytype_sbbuf, nfrontp, sizeof ttytype_sbbuf);
304 nfrontp += sizeof ttytype_sbbuf;
305 while (sequenceIs(ttypesubopt, baseline))
306 ttloop();
307}
308
309terminaltypeok(s)
310char *s;
311{
312 char buf[1024];
313
314 if (terminaltype == NULL)
315 return(1);
316
317 /*
318 * tgetent() will return 1 if the type is known, and
319 * 0 if it is not known. If it returns -1, it couldn't
320 * open the database. But if we can't open the database,
321 * it won't help to say we failed, because we won't be
322 * able to verify anything else. So, we treat -1 like 1.
323 */
324 if (tgetent(buf, s) == 0)
325 return(0);
326 return(1);
d8b5e42c 327}
66b878f6
BJ
328
329/*
330 * Get a pty, scan input lines.
331 */
ea139302 332doit(who)
37c640e2 333 struct sockaddr_in *who;
66b878f6 334{
c29f876c 335 char *host, *inet_ntoa();
ea139302 336 int t;
37c640e2 337 struct hostent *hp;
1a33b848 338
ea139302
PB
339 /*
340 * Find an available pty to use.
341 */
342 pty = getpty();
343 if (pty < 0)
344 fatal(net, "All network ports in use");
c29f876c 345
ea139302
PB
346 t = getptyslave();
347
348 /* get name of connected client */
349 hp = gethostbyaddr((char *)&who->sin_addr, sizeof (struct in_addr),
37c640e2
SL
350 who->sin_family);
351 if (hp)
352 host = hp->h_name;
353 else
05fa5465 354 host = inet_ntoa(who->sin_addr);
d8b5e42c 355
d8b5e42c 356 /*
ea139302 357 * get terminal type.
d8b5e42c
GM
358 */
359 getterminaltype();
ea139302
PB
360 if (terminaltype == NULL)
361 terminaltype = "TERM=network";
d8b5e42c 362
affdaa4e 363 /*
ea139302 364 * Start up the login process on the slave side of the terminal
affdaa4e 365 */
ea139302 366 startslave(t, host);
5d78ef73 367
ea139302
PB
368 telnet(net, pty); /* begin server processing */
369 /*NOTREACHED*/
370} /* end of doit */
5d78ef73 371
ea139302
PB
372#ifndef MAXHOSTNAMELEN
373#define MAXHOSTNAMELEN 64
374#endif MAXHOSTNAMELEN
66b878f6
BJ
375/*
376 * Main loop. Select from pty and network, and
377 * hand data to telnet receiver finite state machine.
378 */
379telnet(f, p)
ea139302 380int f, p;
66b878f6
BJ
381{
382 int on = 1;
5eddff6d 383 char hostname[MAXHOSTNAMELEN];
ed8f31c1 384#if defined(CRAY2) && defined(UNICOS5)
ea139302
PB
385 int termstat();
386 int interrupt(), sendbrk();
387#endif
d0a64c71
GM
388#define TABBUFSIZ 512
389 char defent[TABBUFSIZ];
390 char defstrs[TABBUFSIZ];
391#undef TABBUFSIZ
392 char *HE;
393 char *HN;
394 char *IM;
ea139302
PB
395 void netflush();
396
9eebc521 397 /*
ea139302 398 * Initialize the slc mapping table.
9eebc521 399 */
ea139302 400 get_slc_defaults();
66b878f6 401
da96b661 402 /*
ea139302
PB
403 * Do some tests where it is desireable to wait for a response.
404 * Rather than doing them slowly, one at a time, do them all
405 * at once.
da96b661 406 */
ea139302 407 if (!myopts[TELOPT_SGA])
053fd49d 408 send_will(TELOPT_SGA, 1);
affdaa4e
GM
409 /*
410 * Is the client side a 4.2 (NOT 4.3) system? We need to know this
411 * because 4.2 clients are unable to deal with TCP urgent data.
412 *
413 * To find out, we send out a "DO ECHO". If the remote system
414 * answers "WILL ECHO" it is probably a 4.2 client, and we note
415 * that fact ("WILL ECHO" ==> that the client will echo what
416 * WE, the server, sends it; it does NOT mean that the client will
417 * echo the terminal input).
418 */
053fd49d 419 send_do(TELOPT_ECHO, 1);
ea139302
PB
420
421#ifdef LINEMODE
422 if (hisopts[TELOPT_LINEMODE] == OPT_NO) {
423 /* Query the peer for linemode support by trying to negotiate
424 * the linemode option.
425 */
426 linemode = 1;
427 editmode = 0;
053fd49d 428 send_do(TELOPT_LINEMODE, 1); /* send do linemode */
ea139302
PB
429 }
430#endif /* LINEMODE */
431
432 /*
433 * Send along a couple of other options that we wish to negotiate.
434 */
053fd49d
PB
435 send_do(TELOPT_NAWS, 1);
436 send_will(TELOPT_STATUS, 1);
ea139302 437 flowmode = 1; /* default flow control state */
053fd49d 438 send_do(TELOPT_LFLOW, 1);
ea139302
PB
439
440 /*
441 * Spin, waiting for a response from the DO ECHO. However,
442 * some REALLY DUMB telnets out there might not respond
443 * to the DO ECHO. So, we spin looking for NAWS, (most dumb
444 * telnets so far seem to respond with WONT for a DO that
445 * they don't understand...) because by the time we get the
446 * response, it will already have processed the DO ECHO.
447 * Kludge upon kludge.
448 */
449 while (hiswants[TELOPT_NAWS] != hisopts[TELOPT_NAWS])
450 ttloop();
451
86b6dfea
PB
452 /*
453 * On the off chance that the telnet client is broken and does not
454 * respond to the DO ECHO we sent, (after all, we did send the
455 * DO NAWS negotiation after the DO ECHO, and we won't get here
456 * until a response to the DO NAWS comes back) simulate the
457 * receipt of a will echo. This will also send a WONT ECHO
458 * to the client, since we assume that the client failed to
459 * respond because it believes that it is already in DO ECHO
460 * mode, which we do not want.
461 */
ed8f31c1 462 if (hiswants[TELOPT_ECHO] == OPT_YES) {
053fd49d 463 willoption(TELOPT_ECHO);
ed8f31c1 464 }
86b6dfea
PB
465
466 /*
467 * Finally, to clean things up, we turn on our echo. This
468 * will break stupid 4.2 telnets out of local terminal echo.
469 */
470
471 if (!myopts[TELOPT_ECHO])
053fd49d 472 send_will(TELOPT_ECHO, 1);
86b6dfea 473
ea139302
PB
474 /*
475 * Turn on packet mode, and default to line at at time mode.
476 */
477 (void) ioctl(p, TIOCPKT, (char *)&on);
478#ifdef LINEMODE
479 tty_setlinemode(1);
480
481# ifdef KLUDGELINEMODE
482 /*
483 * Continuing line mode support. If client does not support
484 * real linemode, attempt to negotiate kludge linemode by sending
485 * the do timing mark sequence.
486 */
487 if (lmodetype < REAL_LINEMODE)
053fd49d 488 send_do(TELOPT_TM, 1);
ea139302
PB
489# endif /* KLUDGELINEMODE */
490#endif /* LINEMODE */
491
492 /*
493 * Call telrcv() once to pick up anything received during
494 * terminal type negotiation, 4.2/4.3 determination, and
495 * linemode negotiation.
496 */
497 telrcv();
498
499 (void) ioctl(f, FIONBIO, (char *)&on);
500 (void) ioctl(p, FIONBIO, (char *)&on);
ed8f31c1 501#if defined(CRAY2) && defined(UNICOS5)
ea139302
PB
502 init_termdriver(f, p, interrupt, sendbrk);
503#endif
504
505#if defined(SO_OOBINLINE)
506 (void) setsockopt(net, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on);
507#endif /* defined(SO_OOBINLINE) */
508
509#ifdef SIGTSTP
510 (void) signal(SIGTSTP, SIG_IGN);
511#endif
512#ifdef SIGTTOU
513 /*
514 * Ignoring SIGTTOU keeps the kernel from blocking us
515 * in ttioct() in /sys/tty.c.
516 */
517 (void) signal(SIGTTOU, SIG_IGN);
518#endif
519
520 (void) signal(SIGCHLD, cleanup);
521
ed8f31c1 522#if defined(CRAY2) && defined(UNICOS5)
ea139302
PB
523 /*
524 * Cray-2 will send a signal when pty modes are changed by slave
525 * side. Set up signal handler now.
526 */
527 if ((int)signal(SIGUSR1, termstat) < 0)
528 perror("signal");
529 else if (ioctl(p, TCSIGME, (char *)SIGUSR1) < 0)
530 perror("ioctl:TCSIGME");
531 /*
532 * Make processing loop check terminal characteristics early on.
533 */
534 termstat();
535#endif
536
537 (void) setpgrp(0, 0);
ed8f31c1
PB
538#ifdef TCSETCTTY
539 ioctl(p, TCSETCTTY, 0);
540#endif
affdaa4e 541
0c285f22
SL
542 /*
543 * Show banner that getty never gave.
10dc182f 544 *
d0a64c71
GM
545 * We put the banner in the pty input buffer. This way, it
546 * gets carriage return null processing, etc., just like all
547 * other pty --> client data.
0c285f22 548 */
10dc182f 549
ea139302
PB
550 (void) gethostname(hostname, sizeof (hostname));
551
d0a64c71
GM
552 if (getent(defent, "default") == 1) {
553 char *getstr();
ea139302 554 char *cp=defstrs;
d0a64c71 555
ea139302
PB
556 HE = getstr("he", &cp);
557 HN = getstr("hn", &cp);
558 IM = getstr("im", &cp);
d0a64c71 559 if (HN && *HN)
ea139302
PB
560 (void) strcpy(hostname, HN);
561 if (IM == 0)
562 IM = "";
d0a64c71 563 } else {
ea139302
PB
564#ifdef CRAY
565 if (hostinfo == 0)
566 IM = 0;
567 else
568#endif
569 IM = DEFAULT_IM;
570 HE = 0;
571 }
572 edithost(HE, hostname);
573 if (IM && *IM)
574 putf(IM, ptyibuf2);
575
576 if (pcc)
577 (void) strncat(ptyibuf2, ptyip, pcc+1);
578 ptyip = ptyibuf2;
579 pcc = strlen(ptyip);
ed8f31c1
PB
580#ifdef LINEMODE
581 /*
582 * Last check to make sure all our states are correct.
583 */
584 init_termbuf();
585 localstat();
586#endif /* LINEMODE */
affdaa4e 587
66b878f6 588 for (;;) {
5d78ef73 589 fd_set ibits, obits, xbits;
66b878f6
BJ
590 register int c;
591
5d78ef73
GM
592 if (ncc < 0 && pcc < 0)
593 break;
594
ed8f31c1 595#if defined(CRAY2) && defined(UNICOS5)
ea139302
PB
596 if (needtermstat)
597 _termstat();
ed8f31c1 598#endif /* defined(CRAY2) && defined(UNICOS5) */
5d78ef73
GM
599 FD_ZERO(&ibits);
600 FD_ZERO(&obits);
601 FD_ZERO(&xbits);
66b878f6
BJ
602 /*
603 * Never look for input if there's still
604 * stuff in the corresponding output buffer
605 */
5d78ef73
GM
606 if (nfrontp - nbackp || pcc > 0) {
607 FD_SET(f, &obits);
608 } else {
609 FD_SET(p, &ibits);
610 }
611 if (pfrontp - pbackp || ncc > 0) {
612 FD_SET(p, &obits);
613 } else {
614 FD_SET(f, &ibits);
615 }
616 if (!SYNCHing) {
617 FD_SET(f, &xbits);
618 }
619 if ((c = select(16, &ibits, &obits, &xbits,
620 (struct timeval *)0)) < 1) {
621 if (c == -1) {
622 if (errno == EINTR) {
623 continue;
624 }
625 }
66b878f6
BJ
626 sleep(5);
627 continue;
628 }
629
5d78ef73
GM
630 /*
631 * Any urgent data?
632 */
633 if (FD_ISSET(net, &xbits)) {
634 SYNCHing = 1;
635 }
636
66b878f6
BJ
637 /*
638 * Something to read from the network...
639 */
5d78ef73 640 if (FD_ISSET(net, &ibits)) {
affdaa4e 641#if !defined(SO_OOBINLINE)
5d78ef73 642 /*
5eddff6d 643 * In 4.2 (and 4.3 beta) systems, the
5d78ef73
GM
644 * OOB indication and data handling in the kernel
645 * is such that if two separate TCP Urgent requests
646 * come in, one byte of TCP data will be overlaid.
647 * This is fatal for Telnet, but we try to live
648 * with it.
649 *
650 * In addition, in 4.2 (and...), a special protocol
651 * is needed to pick up the TCP Urgent data in
652 * the correct sequence.
653 *
654 * What we do is: if we think we are in urgent
655 * mode, we look to see if we are "at the mark".
656 * If we are, we do an OOB receive. If we run
657 * this twice, we will do the OOB receive twice,
658 * but the second will fail, since the second
659 * time we were "at the mark", but there wasn't
660 * any data there (the kernel doesn't reset
661 * "at the mark" until we do a normal read).
662 * Once we've read the OOB data, we go ahead
663 * and do normal reads.
664 *
665 * There is also another problem, which is that
666 * since the OOB byte we read doesn't put us
667 * out of OOB state, and since that byte is most
668 * likely the TELNET DM (data mark), we would
669 * stay in the TELNET SYNCH (SYNCHing) state.
670 * So, clocks to the rescue. If we've "just"
671 * received a DM, then we test for the
672 * presence of OOB data when the receive OOB
673 * fails (and AFTER we did the normal mode read
674 * to clear "at the mark").
675 */
676 if (SYNCHing) {
677 int atmark;
678
ea139302 679 (void) ioctl(net, SIOCATMARK, (char *)&atmark);
5d78ef73
GM
680 if (atmark) {
681 ncc = recv(net, netibuf, sizeof (netibuf), MSG_OOB);
682 if ((ncc == -1) && (errno == EINVAL)) {
683 ncc = read(net, netibuf, sizeof (netibuf));
d8b5e42c 684 if (sequenceIs(didnetreceive, gotDM)) {
5d78ef73
GM
685 SYNCHing = stilloob(net);
686 }
687 }
688 } else {
689 ncc = read(net, netibuf, sizeof (netibuf));
66b878f6 690 }
5d78ef73
GM
691 } else {
692 ncc = read(net, netibuf, sizeof (netibuf));
693 }
694 settimer(didnetreceive);
affdaa4e 695#else /* !defined(SO_OOBINLINE)) */
5d78ef73 696 ncc = read(net, netibuf, sizeof (netibuf));
affdaa4e 697#endif /* !defined(SO_OOBINLINE)) */
5d78ef73
GM
698 if (ncc < 0 && errno == EWOULDBLOCK)
699 ncc = 0;
700 else {
701 if (ncc <= 0) {
702 break;
703 }
704 netip = netibuf;
705 }
66b878f6
BJ
706 }
707
708 /*
709 * Something to read from the pty...
710 */
ea139302 711 if (FD_ISSET(p, &ibits)) {
66b878f6
BJ
712 pcc = read(p, ptyibuf, BUFSIZ);
713 if (pcc < 0 && errno == EWOULDBLOCK)
714 pcc = 0;
715 else {
716 if (pcc <= 0)
717 break;
ed8f31c1 718#if !defined(CRAY2) || !defined(UNICOS5)
ea139302
PB
719#ifdef LINEMODE
720 /*
721 * If ioctl from pty, pass it through net
722 */
723 if (ptyibuf[0] & TIOCPKT_IOCTL) {
724 copy_termbuf(ptyibuf+1, pcc-1);
725 localstat();
726 pcc = 1;
727 }
728#endif LINEMODE
31004941 729 if (ptyibuf[0] & TIOCPKT_FLUSHWRITE) {
ea139302 730 netclear(); /* clear buffer back */
ed8f31c1
PB
731#ifdef notdef
732 /*
733 * We really should have this in, but
734 * there are client telnets on some
735 * operating systems get screwed up
736 * royally if we send them urgent
737 * mode data. So, for now, we'll not
738 * do this...
739 */
31004941
GM
740 *nfrontp++ = IAC;
741 *nfrontp++ = DM;
742 neturg = nfrontp-1; /* off by one XXX */
ed8f31c1 743#endif
31004941
GM
744 }
745 if (hisopts[TELOPT_LFLOW] &&
746 (ptyibuf[0] &
ea139302
PB
747 (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))) {
748 (void) sprintf(nfrontp, "%c%c%c%c%c%c",
31004941
GM
749 IAC, SB, TELOPT_LFLOW,
750 ptyibuf[0] & TIOCPKT_DOSTOP ? 1 : 0,
751 IAC, SE);
752 nfrontp += 6;
753 }
4701a1c1
GM
754 pcc--;
755 ptyip = ptyibuf+1;
ed8f31c1 756#else /* defined(CRAY2) && defined(UNICOS5) */
ea139302 757 if (!uselinemode) {
cb781470
PB
758 unpcc = pcc;
759 unptyip = ptyibuf;
760 pcc = term_output(&unptyip, ptyibuf2,
761 &unpcc, BUFSIZ);
ea139302
PB
762 ptyip = ptyibuf2;
763 } else
764 ptyip = ptyibuf;
ed8f31c1 765#endif /* defined(CRAY2) && defined(UNICOS5) */
ea139302 766 }
4701a1c1 767 }
66b878f6
BJ
768
769 while (pcc > 0) {
770 if ((&netobuf[BUFSIZ] - nfrontp) < 2)
771 break;
772 c = *ptyip++ & 0377, pcc--;
773 if (c == IAC)
774 *nfrontp++ = c;
ed8f31c1 775#if defined(CRAY2) && defined(UNICOS5)
ea139302
PB
776 else if (c == '\n' &&
777 myopts[TELOPT_BINARY] == OPT_NO && newmap)
778 *nfrontp++ = '\r';
ed8f31c1 779#endif /* defined(CRAY2) && defined(UNICOS5) */
66b878f6 780 *nfrontp++ = c;
bdb993e7 781 if ((c == '\r') && (myopts[TELOPT_BINARY] == OPT_NO)) {
9f515693
GM
782 if (pcc > 0 && ((*ptyip & 0377) == '\n')) {
783 *nfrontp++ = *ptyip++ & 0377;
784 pcc--;
785 } else
786 *nfrontp++ = '\0';
787 }
66b878f6 788 }
ed8f31c1 789#if defined(CRAY2) && defined(UNICOS5)
cb781470
PB
790 /*
791 * If chars were left over from the terminal driver,
792 * note their existence.
793 */
794 if (!uselinemode && unpcc) {
795 pcc = unpcc;
796 unpcc = 0;
797 ptyip = unptyip;
798 }
ed8f31c1 799#endif /* defined(CRAY2) && defined(UNICOS5) */
cb781470 800
5d78ef73 801 if (FD_ISSET(f, &obits) && (nfrontp - nbackp) > 0)
66b878f6
BJ
802 netflush();
803 if (ncc > 0)
804 telrcv();
5d78ef73 805 if (FD_ISSET(p, &obits) && (pfrontp - pbackp) > 0)
66b878f6
BJ
806 ptyflush();
807 }
808 cleanup();
ea139302 809} /* end of telnet */
66b878f6 810
ea139302
PB
811#ifndef TCSIG
812# ifdef TIOCSIG
813# define TCSIG TIOCSIG
814# endif
815#endif
66b878f6
BJ
816
817/*
818 * Send interrupt to process on other side of pty.
819 * If it is in raw mode, just write NULL;
820 * otherwise, write intr char.
821 */
822interrupt()
823{
66b878f6 824 ptyflush(); /* half-hearted */
ea139302
PB
825
826#ifdef TCSIG
827 (void) ioctl(pty, TCSIG, (char *)SIGINT);
828#else /* TCSIG */
829 init_termbuf();
ed8f31c1
PB
830 *pfrontp++ = slctab[SLC_IP].sptr ?
831 (unsigned char)*slctab[SLC_IP].sptr : '\177';
ea139302 832#endif /* TCSIG */
66b878f6
BJ
833}
834
a65453b7
GM
835/*
836 * Send quit to process on other side of pty.
837 * If it is in raw mode, just write NULL;
838 * otherwise, write quit char.
839 */
840sendbrk()
841{
a65453b7 842 ptyflush(); /* half-hearted */
ea139302
PB
843#ifdef TCSIG
844 (void) ioctl(pty, TCSIG, (char *)SIGQUIT);
845#else /* TCSIG */
846 init_termbuf();
ed8f31c1
PB
847 *pfrontp++ = slctab[SLC_ABORT].sptr ?
848 (unsigned char)*slctab[SLC_ABORT].sptr : '\034';
ea139302 849#endif /* TCSIG */
615dc3cd 850}
5d78ef73 851
ea139302 852sendsusp()
5d78ef73 853{
ea139302
PB
854#ifdef SIGTSTP
855 ptyflush(); /* half-hearted */
856# ifdef TCSIG
857 (void) ioctl(pty, TCSIG, (char *)SIGTSTP);
858# else /* TCSIG */
ed8f31c1
PB
859 *pfrontp++ = slctab[SLC_SUSP].sptr ?
860 (unsigned char)*slctab[SLC_SUSP].sptr : '\032';
ea139302
PB
861# endif /* TCSIG */
862#endif /* SIGTSTP */
d0a64c71
GM
863}
864
ea139302 865doeof()
d0a64c71 866{
ed8f31c1
PB
867#if defined(USE_TERMIO) && defined(SYSV_TERMIO)
868 extern char oldeofc;
869#endif
ea139302 870 init_termbuf();
d0a64c71 871
ed8f31c1
PB
872#if defined(USE_TERMIO) && defined(SYSV_TERMIO)
873 if (!tty_isediting()) {
874 *pfrontp++ = oldeofc;
875 return;
876 }
877#endif
878 *pfrontp++ = slctab[SLC_EOF].sptr ?
879 (unsigned char)*slctab[SLC_EOF].sptr : '\004';
d0a64c71 880}