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