1 /*
2 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6 /*
7 * Copyright (c) 1988, 1990, 1993
8 * The Regents of the University of California. All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 */
38
39 #ifndef lint
40 static char sccsid[] = "@(#)telnet.c 8.1 (Berkeley) 6/6/93";
41 #endif /* not lint */
42
43 #include <netdb.h>
44 #include <sys/types.h>
45
46 #include <curses.h>
47 #include <signal.h>
48 /*
49 * By the way, we need to include curses.h before telnet.h since,
50 * among other things, telnet.h #defines 'DO', which is a variable
51 * declared in curses.h.
52 */
53
54 #include <arpa/telnet.h>
55
56 #include <ctype.h>
57
58 #include "ring.h"
59
60 #include "defines.h"
61 #include "externs.h"
62 #include "types.h"
63 #include "general.h"
64
65 #include "auth.h"
66 #include "encrypt.h"
67
68 #define strip(x) ((x)&0x7f)
69
70 /* Buffer for sub-options */
71 static unsigned char subbuffer[SUBBUFSIZE];
72 static unsigned char *subpointer;
73 static unsigned char *subend;
74
75 #define SB_CLEAR() subpointer = subbuffer;
76 #define SB_TERM() { subend = subpointer; SB_CLEAR(); }
77 #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof (subbuffer))) { \
78 *subpointer++ = (c); \
79 }
80
81 #define SB_GET() ((*subpointer++)&0xff)
82 #define SB_PEEK() ((*subpointer)&0xff)
83 #define SB_EOF() (subpointer >= subend)
84 #define SB_LEN() (subend - subpointer)
85
86 char options[SUBBUFSIZE]; /* The combined options */
87 char do_dont_resp[SUBBUFSIZE];
88 char will_wont_resp[SUBBUFSIZE];
89
90 int eight = 0;
91 int autologin = 0; /* Autologin anyone? */
92 int skiprc = 0;
93 int connected;
94 int showoptions;
95 static int ISend; /* trying to send network data in */
96 int debug = 0;
97 int crmod;
98 int netdata; /* Print out network data flow */
99 int crlf; /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */
100 int telnetport;
101 int SYNCHing; /* we are in TELNET SYNCH mode */
102 int flushout; /* flush output */
103 int autoflush = 0; /* flush output when interrupting? */
104 int autosynch; /* send interrupt characters with SYNCH? */
105 int localflow; /* we handle flow control locally */
106 int restartany; /* if flow control enabled, restart on any character */
107 int localchars; /* we recognize interrupt/quit */
108 int donelclchars; /* the user has set "localchars" */
109 int donebinarytoggle; /* the user has put us in binary */
110 int dontlecho; /* do we suppress local echoing right now? */
111 int eof_pending = 0; /* we received a genuine EOF on input, send IAC-EOF */
112 int globalmode;
113
114 /* spin while waiting for authentication */
115 boolean_t scheduler_lockout_tty = B_FALSE;
116 int encrypt_flag = 0;
117 int forwardable_flag = 0;
118 int forward_flag = 0;
119 boolean_t wantencryption = B_FALSE;
120
121 char *prompt = 0;
122
123 cc_t escape;
124 cc_t rlogin;
125 boolean_t escape_valid = B_TRUE;
126 #ifdef KLUDGELINEMODE
127 cc_t echoc;
128 #endif
129
130 /*
131 * Telnet receiver states for fsm
132 */
133 #define TS_DATA 0
134 #define TS_IAC 1
135 #define TS_WILL 2
136 #define TS_WONT 3
137 #define TS_DO 4
138 #define TS_DONT 5
139 #define TS_CR 6
140 #define TS_SB 7 /* sub-option collection */
141 #define TS_SE 8 /* looking for sub-option end */
142
143 static int telrcv_state;
144 #ifdef OLD_ENVIRON
145 static unsigned char telopt_environ = TELOPT_NEW_ENVIRON;
146 #else
147 #define telopt_environ TELOPT_NEW_ENVIRON
148 #endif
149
150 jmp_buf toplevel = { 0 };
151 jmp_buf peerdied;
152
153 static int flushline;
154 int linemode;
155
156 int reqd_linemode = 0; /* Set if either new or old line mode in */
157 /* effect since before initial negotiations */
158
159 #ifdef KLUDGELINEMODE
160 int kludgelinemode = 1;
161 #endif
162
163 /*
164 * The following are some clocks used to decide how to interpret
165 * the relationship between various variables.
166 */
167
168 Clocks clocks;
169
170 #ifdef notdef
171 Modelist modelist[] = {
172 { "telnet command mode", COMMAND_LINE },
173 { "character-at-a-time mode", 0 },
174 { "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS },
175 { "line-by-line mode (remote echo)", LINE | LOCAL_CHARS },
176 { "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS },
177 { "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS },
178 { "3270 mode", 0 },
179 };
180 #endif
181
182 static void willoption(int);
183 static void wontoption(int);
184 static void lm_will(unsigned char *, int);
185 static void lm_wont(unsigned char *, int);
186 static void lm_do(unsigned char *, int);
187 static void lm_dont(unsigned char *, int);
188 static void slc_init(void);
189 static void slc_import(int);
190 static void slc_export(void);
191 static void slc_start_reply(size_t);
192 static void slc_add_reply(unsigned char, unsigned char, cc_t);
193 static void slc_end_reply(void);
194 static void slc(unsigned char *, int);
195 static int slc_update(void);
196 static void env_opt(unsigned char *, int);
197 static void env_opt_start(void);
198 static void sendeof(void);
199 static int is_unique(register char *, register char **, register char **);
200
201 /*
202 * Initialize telnet environment.
203 */
204
205 int
init_telnet()206 init_telnet()
207 {
208 if (env_init() == 0)
209 return (0);
210
211 SB_CLEAR();
212 ClearArray(options);
213
214 connected = ISend = localflow = donebinarytoggle = 0;
215 restartany = -1;
216
217 SYNCHing = 0;
218
219 /* Don't change NetTrace */
220
221 escape = CONTROL(']');
222 rlogin = _POSIX_VDISABLE;
223 #ifdef KLUDGELINEMODE
224 echoc = CONTROL('E');
225 #endif
226
227 flushline = 1;
228 telrcv_state = TS_DATA;
229
230 return (1);
231 }
232
233
234 #ifdef notdef
235 #include <varargs.h>
236
237 /*VARARGS*/
238 static void
printring(va_alist)239 printring(va_alist)
240 va_dcl
241 {
242 va_list ap;
243 char buffer[100]; /* where things go */
244 char *ptr;
245 char *format;
246 char *string;
247 Ring *ring;
248 int i;
249
250 va_start(ap);
251
252 ring = va_arg(ap, Ring *);
253 format = va_arg(ap, char *);
254 ptr = buffer;
255
256 while ((i = *format++) != 0) {
257 if (i == '%') {
258 i = *format++;
259 switch (i) {
260 case 'c':
261 *ptr++ = va_arg(ap, int);
262 break;
263 case 's':
264 string = va_arg(ap, char *);
265 ring_supply_data(ring, buffer, ptr-buffer);
266 ring_supply_data(ring, string, strlen(string));
267 ptr = buffer;
268 break;
269 case 0:
270 ExitString("printring: trailing %%.\n",
271 EXIT_FAILURE);
272 /*NOTREACHED*/
273 default:
274 ExitString("printring: unknown format "
275 "character.\n", EXIT_FAILURE);
276 /*NOTREACHED*/
277 }
278 } else {
279 *ptr++ = i;
280 }
281 }
282 ring_supply_data(ring, buffer, ptr-buffer);
283 }
284 #endif
285
286 /*
287 * These routines are in charge of sending option negotiations
288 * to the other side.
289 *
290 * The basic idea is that we send the negotiation if either side
291 * is in disagreement as to what the current state should be.
292 */
293
294 void
send_do(c,init)295 send_do(c, init)
296 register int c, init;
297 {
298 if (init) {
299 if (((do_dont_resp[c] == 0) && my_state_is_do(c)) ||
300 my_want_state_is_do(c))
301 return;
302 set_my_want_state_do(c);
303 do_dont_resp[c]++;
304 }
305 NET2ADD(IAC, DO);
306 NETADD(c);
307 printoption("SENT", DO, c);
308 }
309
310 void
send_dont(c,init)311 send_dont(c, init)
312 register int c, init;
313 {
314 if (init) {
315 if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) ||
316 my_want_state_is_dont(c))
317 return;
318 set_my_want_state_dont(c);
319 do_dont_resp[c]++;
320 }
321 NET2ADD(IAC, DONT);
322 NETADD(c);
323 printoption("SENT", DONT, c);
324 }
325
326 void
send_will(c,init)327 send_will(c, init)
328 register int c, init;
329 {
330 if (init) {
331 if (((will_wont_resp[c] == 0) && my_state_is_will(c)) ||
332 my_want_state_is_will(c))
333 return;
334 set_my_want_state_will(c);
335 will_wont_resp[c]++;
336 }
337 NET2ADD(IAC, WILL);
338 NETADD(c);
339 printoption("SENT", WILL, c);
340 }
341
342 void
send_wont(c,init)343 send_wont(c, init)
344 register int c, init;
345 {
346 if (init) {
347 if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) ||
348 my_want_state_is_wont(c))
349 return;
350 set_my_want_state_wont(c);
351 will_wont_resp[c]++;
352 }
353 NET2ADD(IAC, WONT);
354 NETADD(c);
355 printoption("SENT", WONT, c);
356 }
357
358
359 static void
willoption(option)360 willoption(option)
361 int option;
362 {
363 int new_state_ok = 0;
364
365 if (do_dont_resp[option]) {
366 --do_dont_resp[option];
367 if (do_dont_resp[option] && my_state_is_do(option))
368 --do_dont_resp[option];
369 }
370
371 if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) {
372
373 switch (option) {
374
375 case TELOPT_ECHO:
376 case TELOPT_SGA:
377 if (reqd_linemode && my_state_is_dont(option)) {
378 break;
379 }
380 /* FALLTHROUGH */
381 case TELOPT_BINARY:
382 settimer(modenegotiated);
383 /* FALLTHROUGH */
384 case TELOPT_STATUS:
385 case TELOPT_AUTHENTICATION:
386 /* FALLTHROUGH */
387 case TELOPT_ENCRYPT:
388 new_state_ok = 1;
389 break;
390
391 case TELOPT_TM:
392 if (flushout)
393 flushout = 0;
394 /*
395 * Special case for TM. If we get back a WILL,
396 * pretend we got back a WONT.
397 */
398 set_my_want_state_dont(option);
399 set_my_state_dont(option);
400 return; /* Never reply to TM will's/wont's */
401
402 case TELOPT_LINEMODE:
403 default:
404 break;
405 }
406
407 if (new_state_ok) {
408 set_my_want_state_do(option);
409 send_do(option, 0);
410 setconnmode(0); /* possibly set new tty mode */
411 } else {
412 do_dont_resp[option]++;
413 send_dont(option, 0);
414 }
415 }
416 set_my_state_do(option);
417 if (option == TELOPT_ENCRYPT)
418 encrypt_send_support();
419 }
420
421 static void
wontoption(option)422 wontoption(option)
423 int option;
424 {
425 if (do_dont_resp[option]) {
426 --do_dont_resp[option];
427 if (do_dont_resp[option] && my_state_is_dont(option))
428 --do_dont_resp[option];
429 }
430
431 if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) {
432
433 switch (option) {
434
435 #ifdef KLUDGELINEMODE
436 case TELOPT_SGA:
437 if (!kludgelinemode)
438 break;
439 /* FALLTHROUGH */
440 #endif
441 case TELOPT_ECHO:
442 settimer(modenegotiated);
443 break;
444
445 case TELOPT_TM:
446 if (flushout)
447 flushout = 0;
448 set_my_want_state_dont(option);
449 set_my_state_dont(option);
450 return; /* Never reply to TM will's/wont's */
451
452 default:
453 break;
454 }
455 set_my_want_state_dont(option);
456 if (my_state_is_do(option))
457 send_dont(option, 0);
458 setconnmode(0); /* Set new tty mode */
459 } else if (option == TELOPT_TM) {
460 /*
461 * Special case for TM.
462 */
463 if (flushout)
464 flushout = 0;
465 set_my_want_state_dont(option);
466 }
467 set_my_state_dont(option);
468 }
469
470 static void
dooption(option)471 dooption(option)
472 int option;
473 {
474 int new_state_ok = 0;
475
476 if (will_wont_resp[option]) {
477 --will_wont_resp[option];
478 if (will_wont_resp[option] && my_state_is_will(option))
479 --will_wont_resp[option];
480 }
481
482 if (will_wont_resp[option] == 0) {
483 if (my_want_state_is_wont(option)) {
484
485 switch (option) {
486
487 case TELOPT_TM:
488 /*
489 * Special case for TM. We send a WILL,
490 * but pretend we sent WONT.
491 */
492 send_will(option, 0);
493 set_my_want_state_wont(TELOPT_TM);
494 set_my_state_wont(TELOPT_TM);
495 return;
496
497 case TELOPT_BINARY: /* binary mode */
498 case TELOPT_NAWS: /* window size */
499 case TELOPT_TSPEED: /* terminal speed */
500 case TELOPT_LFLOW: /* local flow control */
501 case TELOPT_TTYPE: /* terminal type option */
502 case TELOPT_SGA: /* no big deal */
503 case TELOPT_ENCRYPT: /* encryption variable option */
504 new_state_ok = 1;
505 break;
506
507 case TELOPT_NEW_ENVIRON:
508 /* New environment variable option */
509 #ifdef OLD_ENVIRON
510 if (my_state_is_will(TELOPT_OLD_ENVIRON))
511 /* turn off the old */
512 send_wont(TELOPT_OLD_ENVIRON, 1);
513 goto env_common;
514 case TELOPT_OLD_ENVIRON:
515 /* Old environment variable option */
516 if (my_state_is_will(TELOPT_NEW_ENVIRON))
517 /* Don't enable if new one is in use! */
518 break;
519 env_common:
520 telopt_environ = option;
521 #endif
522 new_state_ok = 1;
523 break;
524
525 case TELOPT_AUTHENTICATION:
526 if (autologin)
527 new_state_ok = 1;
528 break;
529
530 case TELOPT_XDISPLOC: /* X Display location */
531 if (env_getvalue((unsigned char *)"DISPLAY"))
532 new_state_ok = 1;
533 break;
534
535 case TELOPT_LINEMODE:
536 #ifdef KLUDGELINEMODE
537 kludgelinemode = 0;
538 send_do(TELOPT_SGA, 1);
539 #endif
540 set_my_want_state_will(TELOPT_LINEMODE);
541 send_will(option, 0);
542 set_my_state_will(TELOPT_LINEMODE);
543 slc_init();
544 return;
545
546 case TELOPT_ECHO: /* We're never going to echo... */
547 default:
548 break;
549 }
550
551 if (new_state_ok) {
552 set_my_want_state_will(option);
553 send_will(option, 0);
554 setconnmode(0); /* Set new tty mode */
555 } else {
556 will_wont_resp[option]++;
557 send_wont(option, 0);
558 }
559 } else {
560 /*
561 * Handle options that need more things done after the
562 * other side has acknowledged the option.
563 */
564 switch (option) {
565 case TELOPT_LINEMODE:
566 #ifdef KLUDGELINEMODE
567 kludgelinemode = 0;
568 send_do(TELOPT_SGA, 1);
569 #endif
570 set_my_state_will(option);
571 slc_init();
572 send_do(TELOPT_SGA, 0);
573 return;
574 }
575 }
576 }
577 set_my_state_will(option);
578 }
579
580 static void
dontoption(option)581 dontoption(option)
582 int option;
583 {
584
585 if (will_wont_resp[option]) {
586 --will_wont_resp[option];
587 if (will_wont_resp[option] && my_state_is_wont(option))
588 --will_wont_resp[option];
589 }
590
591 if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) {
592 switch (option) {
593 case TELOPT_LINEMODE:
594 linemode = 0; /* put us back to the default state */
595 break;
596 #ifdef OLD_ENVIRON
597 case TELOPT_NEW_ENVIRON:
598 /*
599 * The new environ option wasn't recognized, try
600 * the old one.
601 */
602 send_will(TELOPT_OLD_ENVIRON, 1);
603 telopt_environ = TELOPT_OLD_ENVIRON;
604 break;
605 #endif
606 }
607 /* we always accept a DONT */
608 set_my_want_state_wont(option);
609 if (my_state_is_will(option))
610 send_wont(option, 0);
611 setconnmode(0); /* Set new tty mode */
612 }
613 set_my_state_wont(option);
614 }
615
616 /*
617 * Given a buffer returned by tgetent(), this routine will turn
618 * the pipe seperated list of names in the buffer into an array
619 * of pointers to null terminated names. We toss out any bad,
620 * duplicate, or verbose names (names with spaces).
621 */
622
623 static char *name_unknown = "UNKNOWN";
624 static char *unknown[] = { 0, 0 };
625
626 static char **
mklist(buf,name)627 mklist(buf, name)
628 char *buf, *name;
629 {
630 register int n;
631 register char c, *cp, **argvp, *cp2, **argv, **avt;
632
633 if (name) {
634 if (strlen(name) > 40u) {
635 name = 0;
636 unknown[0] = name_unknown;
637 } else {
638 unknown[0] = name;
639 upcase(name);
640 }
641 } else
642 unknown[0] = name_unknown;
643 /*
644 * Count up the number of names.
645 */
646 for (n = 1, cp = buf; *cp && *cp != ':'; cp++) {
647 if (*cp == '|')
648 n++;
649 }
650 /*
651 * Allocate an array to put the name pointers into
652 */
653 argv = malloc((n+3)*sizeof (char *));
654 if (argv == 0)
655 return (unknown);
656
657 /*
658 * Fill up the array of pointers to names.
659 */
660 *argv = 0;
661 argvp = argv+1;
662 n = 0;
663 for (cp = cp2 = buf; (c = *cp) != '\0'; cp++) {
664 if (c == '|' || c == ':') {
665 *cp++ = '\0';
666 /*
667 * Skip entries that have spaces or are over 40
668 * characters long. If this is our environment
669 * name, then put it up front. Otherwise, as
670 * long as this is not a duplicate name (case
671 * insensitive) add it to the list.
672 */
673 if (n || (cp - cp2 > 41))
674 /* EMPTY */;
675 else if (name && (strncasecmp(name, cp2, cp-cp2) == 0))
676 *argv = cp2;
677 else if (is_unique(cp2, argv+1, argvp))
678 *argvp++ = cp2;
679 if (c == ':')
680 break;
681 /*
682 * Skip multiple delimiters. Reset cp2 to
683 * the beginning of the next name. Reset n,
684 * the flag for names with spaces.
685 */
686 while ((c = *cp) == '|')
687 cp++;
688 cp2 = cp;
689 n = 0;
690 }
691 /*
692 * Skip entries with spaces or non-ascii values.
693 * Convert lower case letters to upper case.
694 */
695 if ((c == ' ') || !isascii(c))
696 n = 1;
697 else if (islower(c))
698 *cp = toupper(c);
699 }
700
701 /*
702 * Check for an old V6 2 character name. If the second
703 * name points to the beginning of the buffer, and is
704 * only 2 characters long, move it to the end of the array.
705 */
706 if ((argv[1] == buf) && (strlen(argv[1]) == 2)) {
707 --argvp;
708 for (avt = &argv[1]; avt < argvp; avt++)
709 *avt = *(avt+1);
710 *argvp++ = buf;
711 }
712
713 /*
714 * Duplicate last name, for TTYPE option, and null
715 * terminate the array. If we didn't find a match on
716 * our terminal name, put that name at the beginning.
717 */
718 cp = *(argvp-1);
719 *argvp++ = cp;
720 *argvp = 0;
721
722 if (*argv == 0) {
723 if (name)
724 *argv = name;
725 else {
726 --argvp;
727 for (avt = argv; avt < argvp; avt++)
728 *avt = *(avt+1);
729 }
730 }
731 if (*argv)
732 return (argv);
733 else
734 return (unknown);
735 }
736
737 static int
is_unique(name,as,ae)738 is_unique(name, as, ae)
739 register char *name, **as, **ae;
740 {
741 register char **ap;
742 register int n;
743
744 n = strlen(name) + 1;
745 for (ap = as; ap < ae; ap++)
746 if (strncasecmp(*ap, name, n) == 0)
747 return (0);
748 return (1);
749 }
750
751 #define termbuf ttytype
752 extern char ttytype[];
753
754 int resettermname = 1;
755
756 static char *
gettermname(void)757 gettermname(void)
758 {
759 char *tname;
760 static char **tnamep = 0;
761 static char **next;
762 int err;
763
764 if (resettermname) {
765 resettermname = 0;
766 if (tnamep && tnamep != unknown)
767 free(tnamep);
768 tname = (char *)env_getvalue((unsigned char *)"TERM");
769 if ((tname != NULL) && (setupterm(tname, 1, &err) == 0)) {
770 tnamep = mklist(termbuf, tname);
771 } else {
772 if (tname && (strlen(tname) <= 40u)) {
773 unknown[0] = tname;
774 upcase(tname);
775 } else
776 unknown[0] = name_unknown;
777 tnamep = unknown;
778 }
779 next = tnamep;
780 }
781 if (*next == 0)
782 next = tnamep;
783 return (*next++);
784 }
785 /*
786 * suboption()
787 *
788 * Look at the sub-option buffer, and try to be helpful to the other
789 * side.
790 *
791 * Currently we recognize:
792 *
793 * Terminal type, send request.
794 * Terminal speed (send request).
795 * Local flow control (is request).
796 * Linemode
797 */
798
799 static void
suboption()800 suboption()
801 {
802 unsigned char subchar;
803
804 printsub('<', subbuffer, SB_LEN()+2);
805 switch (subchar = SB_GET()) {
806 case TELOPT_TTYPE:
807 if (my_want_state_is_wont(TELOPT_TTYPE))
808 return;
809 if (SB_EOF() || SB_GET() != TELQUAL_SEND) {
810 return;
811 } else {
812 char *name;
813 unsigned char temp[50];
814 int len, bytes;
815
816 name = gettermname();
817 len = strlen(name) + 4 + 2;
818 bytes = snprintf((char *)temp, sizeof (temp),
819 "%c%c%c%c%s%c%c", IAC, SB,
820 TELOPT_TTYPE, TELQUAL_IS, name, IAC, SE);
821 if ((len < NETROOM()) && (bytes < sizeof (temp))) {
822 ring_supply_data(&netoring, temp, len);
823 printsub('>', &temp[2], len-2);
824 } else {
825 ExitString("No room in buffer for "
826 "terminal type.\n", EXIT_FAILURE);
827 /*NOTREACHED*/
828 }
829 }
830 break;
831 case TELOPT_TSPEED:
832 if (my_want_state_is_wont(TELOPT_TSPEED))
833 return;
834 if (SB_EOF())
835 return;
836 if (SB_GET() == TELQUAL_SEND) {
837 int ospeed, ispeed;
838 unsigned char temp[50];
839 int len, bytes;
840
841 TerminalSpeeds(&ispeed, &ospeed);
842
843 bytes = snprintf((char *)temp, sizeof (temp),
844 "%c%c%c%c%d,%d%c%c", IAC, SB,
845 TELOPT_TSPEED, TELQUAL_IS, ospeed, ispeed, IAC, SE);
846 len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */
847
848 if ((len < NETROOM()) && (bytes < sizeof (temp))) {
849 ring_supply_data(&netoring, temp, len);
850 printsub('>', temp+2, len - 2);
851 }
852 else
853 (void) printf(
854 "telnet: not enough room in buffer "
855 "for terminal speed option reply\n");
856 }
857 break;
858 case TELOPT_LFLOW:
859 if (my_want_state_is_wont(TELOPT_LFLOW))
860 return;
861 if (SB_EOF())
862 return;
863 switch (SB_GET()) {
864 case LFLOW_RESTART_ANY:
865 restartany = 1;
866 break;
867 case LFLOW_RESTART_XON:
868 restartany = 0;
869 break;
870 case LFLOW_ON:
871 localflow = 1;
872 break;
873 case LFLOW_OFF:
874 localflow = 0;
875 break;
876 default:
877 return;
878 }
879 setcommandmode();
880 setconnmode(0);
881 break;
882
883 case TELOPT_LINEMODE:
884 if (my_want_state_is_wont(TELOPT_LINEMODE))
885 return;
886 if (SB_EOF())
887 return;
888 switch (SB_GET()) {
889 case WILL:
890 lm_will(subpointer, SB_LEN());
891 break;
892 case WONT:
893 lm_wont(subpointer, SB_LEN());
894 break;
895 case DO:
896 lm_do(subpointer, SB_LEN());
897 break;
898 case DONT:
899 lm_dont(subpointer, SB_LEN());
900 break;
901 case LM_SLC:
902 slc(subpointer, SB_LEN());
903 break;
904 case LM_MODE:
905 lm_mode(subpointer, SB_LEN(), 0);
906 break;
907 default:
908 break;
909 }
910 break;
911
912 #ifdef OLD_ENVIRON
913 case TELOPT_OLD_ENVIRON:
914 #endif
915 case TELOPT_NEW_ENVIRON:
916 if (SB_EOF())
917 return;
918 switch (SB_PEEK()) {
919 case TELQUAL_IS:
920 case TELQUAL_INFO:
921 if (my_want_state_is_dont(subchar))
922 return;
923 break;
924 case TELQUAL_SEND:
925 if (my_want_state_is_wont(subchar)) {
926 return;
927 }
928 break;
929 default:
930 return;
931 }
932 env_opt(subpointer, SB_LEN());
933 break;
934
935 case TELOPT_XDISPLOC:
936 if (my_want_state_is_wont(TELOPT_XDISPLOC))
937 return;
938 if (SB_EOF())
939 return;
940 if (SB_GET() == TELQUAL_SEND) {
941 unsigned char temp[50], *dp;
942 int len, bytes;
943
944 if ((dp = env_getvalue((unsigned char *)"DISPLAY")) ==
945 NULL) {
946 /*
947 * Something happened, we no longer have a
948 * DISPLAY variable. So, turn off the option.
949 */
950 send_wont(TELOPT_XDISPLOC, 1);
951 break;
952 }
953 bytes = snprintf((char *)temp, sizeof (temp),
954 "%c%c%c%c%s%c%c", IAC, SB,
955 TELOPT_XDISPLOC, TELQUAL_IS, dp, IAC, SE);
956 len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */
957
958 if ((len < NETROOM()) && (bytes < sizeof (temp))) {
959 ring_supply_data(&netoring, temp, len);
960 printsub('>', temp+2, len - 2);
961 }
962 else
963 (void) printf(
964 "telnet: not enough room in buffer"
965 " for display location option reply\n");
966 }
967 break;
968
969 case TELOPT_AUTHENTICATION: {
970 if (!autologin)
971 break;
972 if (SB_EOF())
973 return;
974 switch (SB_GET()) {
975 case TELQUAL_SEND:
976 if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
977 return;
978 auth_send(subpointer, SB_LEN());
979 break;
980 case TELQUAL_REPLY:
981 if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
982 return;
983 auth_reply(subpointer, SB_LEN());
984 break;
985 }
986 }
987 break;
988
989 case TELOPT_ENCRYPT:
990 if (SB_EOF())
991 return;
992 switch (SB_GET()) {
993 case ENCRYPT_START:
994 if (my_want_state_is_dont(TELOPT_ENCRYPT))
995 return;
996 encrypt_start(subpointer, SB_LEN());
997 break;
998 case ENCRYPT_END:
999 if (my_want_state_is_dont(TELOPT_ENCRYPT))
1000 return;
1001 encrypt_end();
1002 break;
1003 case ENCRYPT_SUPPORT:
1004 if (my_want_state_is_wont(TELOPT_ENCRYPT))
1005 return;
1006 encrypt_support(subpointer, SB_LEN());
1007 break;
1008 case ENCRYPT_REQSTART:
1009 if (my_want_state_is_wont(TELOPT_ENCRYPT))
1010 return;
1011 encrypt_request_start(subpointer, SB_LEN());
1012 break;
1013 case ENCRYPT_REQEND:
1014 if (my_want_state_is_wont(TELOPT_ENCRYPT))
1015 return;
1016 /*
1017 * We can always send an REQEND so that we cannot
1018 * get stuck encrypting. We should only get this
1019 * if we have been able to get in the correct mode
1020 * anyhow.
1021 */
1022 encrypt_request_end();
1023 break;
1024 case ENCRYPT_IS:
1025 if (my_want_state_is_dont(TELOPT_ENCRYPT))
1026 return;
1027 encrypt_is(subpointer, SB_LEN());
1028 break;
1029 case ENCRYPT_REPLY:
1030 if (my_want_state_is_wont(TELOPT_ENCRYPT))
1031 return;
1032 encrypt_reply(subpointer, SB_LEN());
1033 break;
1034 case ENCRYPT_ENC_KEYID:
1035 if (my_want_state_is_dont(TELOPT_ENCRYPT))
1036 return;
1037 encrypt_enc_keyid(subpointer, SB_LEN());
1038 break;
1039 case ENCRYPT_DEC_KEYID:
1040 if (my_want_state_is_wont(TELOPT_ENCRYPT))
1041 return;
1042 encrypt_dec_keyid(subpointer, SB_LEN());
1043 break;
1044 default:
1045 break;
1046 }
1047 break;
1048 default:
1049 break;
1050 }
1051 }
1052
1053 static unsigned char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE };
1054
1055 static void
lm_will(cmd,len)1056 lm_will(cmd, len)
1057 unsigned char *cmd;
1058 int len;
1059 {
1060 if (len < 1) {
1061 /* Should not happen... */
1062 (void) printf(
1063 "telnet: command missing from linemode WILL request\n");
1064 return;
1065 }
1066 switch (cmd[0]) {
1067 case LM_FORWARDMASK: /* We shouldn't ever get this... */
1068 default:
1069 str_lm[3] = DONT;
1070 str_lm[4] = cmd[0];
1071 if (NETROOM() > sizeof (str_lm)) {
1072 ring_supply_data(&netoring, str_lm, sizeof (str_lm));
1073 printsub('>', &str_lm[2], sizeof (str_lm)-2);
1074 }
1075 else
1076 (void) printf("telnet: not enough room in buffer for"
1077 "reply to linemode WILL request\n");
1078 break;
1079 }
1080 }
1081
1082 static void
lm_wont(cmd,len)1083 lm_wont(cmd, len)
1084 unsigned char *cmd;
1085 int len;
1086 {
1087 if (len < 1) {
1088 /* Should not happen... */
1089 (void) printf(
1090 "telnet: command missing from linemode WONT request\n");
1091 return;
1092 }
1093 switch (cmd[0]) {
1094 case LM_FORWARDMASK: /* We shouldn't ever get this... */
1095 default:
1096 /* We are always DONT, so don't respond */
1097 return;
1098 }
1099 }
1100
1101 static void
lm_do(cmd,len)1102 lm_do(cmd, len)
1103 unsigned char *cmd;
1104 int len;
1105 {
1106 if (len < 1) {
1107 /* Should not happen... */
1108 (void) printf(
1109 "telnet: command missing from linemode DO request\n");
1110 return;
1111 }
1112 switch (cmd[0]) {
1113 case LM_FORWARDMASK:
1114 default:
1115 str_lm[3] = WONT;
1116 str_lm[4] = cmd[0];
1117 if (NETROOM() > sizeof (str_lm)) {
1118 ring_supply_data(&netoring, str_lm, sizeof (str_lm));
1119 printsub('>', &str_lm[2], sizeof (str_lm)-2);
1120 }
1121 else
1122 (void) printf("telnet: not enough room in buffer for"
1123 "reply to linemode DO request\n");
1124 break;
1125 }
1126 }
1127
1128 static void
lm_dont(cmd,len)1129 lm_dont(cmd, len)
1130 unsigned char *cmd;
1131 int len;
1132 {
1133 if (len < 1) {
1134 /* Should not happen... */
1135 (void) printf(
1136 "telnet: command missing from linemode DONT request\n");
1137 return;
1138 }
1139 switch (cmd[0]) {
1140 case LM_FORWARDMASK:
1141 default:
1142 /* we are always WONT, so don't respond */
1143 break;
1144 }
1145 }
1146
1147 static unsigned char str_lm_mode[] = {
1148 IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE
1149 };
1150
1151 void
lm_mode(cmd,len,init)1152 lm_mode(cmd, len, init)
1153 unsigned char *cmd;
1154 int len, init;
1155 {
1156 if (len != 1)
1157 return;
1158 if ((linemode&MODE_MASK&~MODE_ACK) == *cmd)
1159 return;
1160 linemode = *cmd&(MODE_MASK&~MODE_ACK);
1161 str_lm_mode[4] = linemode;
1162 if (!init)
1163 str_lm_mode[4] |= MODE_ACK;
1164 if (NETROOM() > sizeof (str_lm_mode)) {
1165 ring_supply_data(&netoring, str_lm_mode, sizeof (str_lm_mode));
1166 printsub('>', &str_lm_mode[2], sizeof (str_lm_mode)-2);
1167 }
1168 else
1169 (void) printf("telnet: not enough room in buffer for"
1170 "reply to linemode request\n");
1171 setconnmode(0); /* set changed mode */
1172 }
1173
1174
1175
1176 /*
1177 * slc()
1178 * Handle special character suboption of LINEMODE.
1179 */
1180
1181 static struct spc {
1182 cc_t val;
1183 cc_t *valp;
1184 char flags; /* Current flags & level */
1185 char mylevel; /* Maximum level & flags */
1186 } spc_data[NSLC+1];
1187
1188 #define SLC_IMPORT 0
1189 #define SLC_EXPORT 1
1190 #define SLC_RVALUE 2
1191 static int slc_mode = SLC_EXPORT;
1192
1193 static void
slc_init()1194 slc_init()
1195 {
1196 register struct spc *spcp;
1197
1198 localchars = 1;
1199 for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) {
1200 spcp->val = 0;
1201 spcp->valp = 0;
1202 spcp->flags = spcp->mylevel = SLC_NOSUPPORT;
1203 }
1204
1205 #define initfunc(func, flags) { \
1206 spcp = &spc_data[func]; \
1207 if (spcp->valp = tcval(func)) { \
1208 spcp->val = *spcp->valp; \
1209 spcp->mylevel = SLC_VARIABLE|(flags);\
1210 } else { \
1211 spcp->val = 0; \
1212 spcp->mylevel = SLC_DEFAULT; \
1213 } \
1214 }
1215
1216 initfunc(SLC_SYNCH, 0);
1217 /* No BRK */
1218 initfunc(SLC_AO, 0);
1219 initfunc(SLC_AYT, 0);
1220 /* No EOR */
1221 initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT);
1222 initfunc(SLC_EOF, 0);
1223 initfunc(SLC_SUSP, SLC_FLUSHIN);
1224 initfunc(SLC_EC, 0);
1225 initfunc(SLC_EL, 0);
1226 initfunc(SLC_EW, 0);
1227 initfunc(SLC_RP, 0);
1228 initfunc(SLC_LNEXT, 0);
1229 initfunc(SLC_XON, 0);
1230 initfunc(SLC_XOFF, 0);
1231 initfunc(SLC_FORW1, 0);
1232 #ifdef USE_TERMIO
1233 initfunc(SLC_FORW2, 0);
1234 /* No FORW2 */
1235 #endif
1236
1237 initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT);
1238 #undef initfunc
1239
1240 if (slc_mode == SLC_EXPORT)
1241 slc_export();
1242 else
1243 slc_import(1);
1244
1245 }
1246
1247 void
slcstate()1248 slcstate()
1249 {
1250 (void) printf("Special characters are %s values\n",
1251 slc_mode == SLC_IMPORT ? "remote default" :
1252 slc_mode == SLC_EXPORT ? "local" :
1253 "remote");
1254 }
1255
1256 void
slc_mode_export()1257 slc_mode_export()
1258 {
1259 slc_mode = SLC_EXPORT;
1260 if (my_state_is_will(TELOPT_LINEMODE))
1261 slc_export();
1262 }
1263
1264 void
slc_mode_import(def)1265 slc_mode_import(def)
1266 int def;
1267 {
1268 slc_mode = def ? SLC_IMPORT : SLC_RVALUE;
1269 if (my_state_is_will(TELOPT_LINEMODE))
1270 slc_import(def);
1271 }
1272
1273 static unsigned char slc_import_val[] = {
1274 IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE
1275 };
1276 static unsigned char slc_import_def[] = {
1277 IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE
1278 };
1279
1280 static void
slc_import(def)1281 slc_import(def)
1282 int def;
1283 {
1284 if (NETROOM() > sizeof (slc_import_val)) {
1285 if (def) {
1286 ring_supply_data(&netoring, slc_import_def,
1287 sizeof (slc_import_def));
1288 printsub('>', &slc_import_def[2],
1289 sizeof (slc_import_def)-2);
1290 } else {
1291 ring_supply_data(&netoring, slc_import_val,
1292 sizeof (slc_import_val));
1293 printsub('>', &slc_import_val[2],
1294 sizeof (slc_import_val)-2);
1295 }
1296 }
1297 else
1298 (void) printf(
1299 "telnet: not enough room in buffer for slc import"
1300 " request\n");
1301 }
1302
1303 static uchar_t *slc_reply = NULL;
1304 static uchar_t *slc_replyp = NULL;
1305 /*
1306 * The SLC reply consists of: IAC, SB, TELOPT_LINEMODE, LM_SLC,
1307 * SLC triplets[], IAC, SE. i.e. it has a 'wrapper' of 6 control characters.
1308 */
1309 #define SLC_WRAPPER_SIZE 6
1310
1311 static void
slc_export()1312 slc_export()
1313 {
1314 register struct spc *spcp;
1315
1316 TerminalDefaultChars();
1317
1318 slc_start_reply(NSLC * 3); /* 3 bytes needed per triplet */
1319 for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
1320 if (spcp->mylevel != SLC_NOSUPPORT) {
1321 if (spcp->val == (cc_t)(_POSIX_VDISABLE))
1322 spcp->flags = SLC_NOSUPPORT;
1323 else
1324 spcp->flags = spcp->mylevel;
1325 if (spcp->valp)
1326 spcp->val = *spcp->valp;
1327 slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
1328 }
1329 }
1330 slc_end_reply();
1331 (void) slc_update();
1332 setconnmode(1); /* Make sure the character values are set */
1333 }
1334
1335 static void
slc(cp,len)1336 slc(cp, len)
1337 register unsigned char *cp;
1338 int len;
1339 {
1340 register struct spc *spcp;
1341 register int func, level;
1342
1343 slc_start_reply(len);
1344
1345 for (; len >= 3; len -= 3, cp += 3) {
1346
1347 func = cp[SLC_FUNC];
1348
1349 if (func == 0) {
1350 /*
1351 * Client side: always ignore 0 function.
1352 */
1353 continue;
1354 }
1355 if (func > NSLC) {
1356 if ((cp[SLC_FLAGS] & SLC_LEVELBITS) != SLC_NOSUPPORT)
1357 slc_add_reply(func, SLC_NOSUPPORT, 0);
1358 continue;
1359 }
1360
1361 spcp = &spc_data[func];
1362
1363 level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK);
1364
1365 if ((cp[SLC_VALUE] == (unsigned char)spcp->val) &&
1366 ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) {
1367 continue;
1368 }
1369
1370 if (level == (SLC_DEFAULT|SLC_ACK)) {
1371 /*
1372 * This is an error condition, the SLC_ACK
1373 * bit should never be set for the SLC_DEFAULT
1374 * level. Our best guess to recover is to
1375 * ignore the SLC_ACK bit.
1376 */
1377 cp[SLC_FLAGS] &= ~SLC_ACK;
1378 }
1379
1380 if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) {
1381 spcp->val = (cc_t)cp[SLC_VALUE];
1382 spcp->flags = cp[SLC_FLAGS]; /* include SLC_ACK */
1383 continue;
1384 }
1385
1386 level &= ~SLC_ACK;
1387
1388 if (level <= (spcp->mylevel&SLC_LEVELBITS)) {
1389 spcp->flags = cp[SLC_FLAGS]|SLC_ACK;
1390 spcp->val = (cc_t)cp[SLC_VALUE];
1391 }
1392 if (level == SLC_DEFAULT) {
1393 if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT)
1394 spcp->flags = spcp->mylevel;
1395 else
1396 spcp->flags = SLC_NOSUPPORT;
1397 }
1398 slc_add_reply(func, spcp->flags, spcp->val);
1399 }
1400 slc_end_reply();
1401 if (slc_update())
1402 setconnmode(1); /* set the new character values */
1403 }
1404
1405 void
slc_check()1406 slc_check()
1407 {
1408 register struct spc *spcp;
1409
1410 slc_start_reply(NSLC * 3); /* 3 bytes needed per triplet */
1411 for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
1412 if (spcp->valp && spcp->val != *spcp->valp) {
1413 spcp->val = *spcp->valp;
1414 if (spcp->val == (cc_t)(_POSIX_VDISABLE))
1415 spcp->flags = SLC_NOSUPPORT;
1416 else
1417 spcp->flags = spcp->mylevel;
1418 slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
1419 }
1420 }
1421 slc_end_reply();
1422 setconnmode(1);
1423 }
1424
1425 static void
slc_start_reply(size_t len)1426 slc_start_reply(size_t len)
1427 {
1428 /*
1429 * SLC triplets may contain escaped characters, allow for
1430 * worst case by allocating 2 bytes for every character.
1431 */
1432 slc_reply = realloc(slc_reply, (len * 2) + SLC_WRAPPER_SIZE);
1433 if (slc_reply == NULL) {
1434 fprintf(stderr, "telnet: error allocating SLC reply memory\n");
1435 return;
1436 }
1437 slc_replyp = slc_reply;
1438 *slc_replyp++ = IAC;
1439 *slc_replyp++ = SB;
1440 *slc_replyp++ = TELOPT_LINEMODE;
1441 *slc_replyp++ = LM_SLC;
1442 }
1443
1444 static void
slc_add_reply(unsigned char func,unsigned char flags,cc_t value)1445 slc_add_reply(unsigned char func, unsigned char flags, cc_t value)
1446 {
1447 if ((*slc_replyp++ = func) == IAC)
1448 *slc_replyp++ = IAC;
1449 if ((*slc_replyp++ = flags) == IAC)
1450 *slc_replyp++ = IAC;
1451 if ((*slc_replyp++ = (unsigned char)value) == IAC)
1452 *slc_replyp++ = IAC;
1453 }
1454
1455 static void
slc_end_reply()1456 slc_end_reply()
1457 {
1458 register int len;
1459
1460 *slc_replyp++ = IAC;
1461 *slc_replyp++ = SE;
1462 len = slc_replyp - slc_reply;
1463 if (len <= SLC_WRAPPER_SIZE)
1464 return;
1465 if (NETROOM() > len) {
1466 ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply);
1467 printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2);
1468 }
1469 else
1470 (void) printf("telnet: not enough room in buffer for slc end "
1471 "reply\n");
1472 }
1473
1474 static int
slc_update()1475 slc_update()
1476 {
1477 register struct spc *spcp;
1478 int need_update = 0;
1479
1480 for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
1481 if (!(spcp->flags&SLC_ACK))
1482 continue;
1483 spcp->flags &= ~SLC_ACK;
1484 if (spcp->valp && (*spcp->valp != spcp->val)) {
1485 *spcp->valp = spcp->val;
1486 need_update = 1;
1487 }
1488 }
1489 return (need_update);
1490 }
1491
1492 #ifdef OLD_ENVIRON
1493 #ifdef ENV_HACK
1494 /*
1495 * Earlier version of telnet/telnetd from the BSD code had
1496 * the definitions of VALUE and VAR reversed. To ensure
1497 * maximum interoperability, we assume that the server is
1498 * an older BSD server, until proven otherwise. The newer
1499 * BSD servers should be able to handle either definition,
1500 * so it is better to use the wrong values if we don't
1501 * know what type of server it is.
1502 */
1503 int env_auto = 1;
1504 int old_env_var = OLD_ENV_VAR;
1505 int old_env_value = OLD_ENV_VALUE;
1506 #else
1507 #define old_env_var OLD_ENV_VAR
1508 #define old_env_value OLD_ENV_VALUE
1509 #endif
1510 #endif
1511
1512 static void
env_opt(buf,len)1513 env_opt(buf, len)
1514 register unsigned char *buf;
1515 register int len;
1516 {
1517 register unsigned char *ep = 0, *epc = 0;
1518 register int i;
1519
1520 switch (buf[0]&0xff) {
1521 case TELQUAL_SEND:
1522 env_opt_start();
1523 if (len == 1) {
1524 env_opt_add(NULL);
1525 } else for (i = 1; i < len; i++) {
1526 switch (buf[i]&0xff) {
1527 #ifdef OLD_ENVIRON
1528 case OLD_ENV_VAR:
1529 #ifdef ENV_HACK
1530 if (telopt_environ == TELOPT_OLD_ENVIRON &&
1531 env_auto) {
1532 /* Server has the same definitions */
1533 old_env_var = OLD_ENV_VAR;
1534 old_env_value = OLD_ENV_VALUE;
1535 }
1536 /* FALLTHROUGH */
1537 #endif
1538 case OLD_ENV_VALUE:
1539 /*
1540 * Although OLD_ENV_VALUE is not legal, we will
1541 * still recognize it, just in case it is an
1542 * old server that has VAR & VALUE mixed up...
1543 */
1544 /* FALLTHROUGH */
1545 #else
1546 case NEW_ENV_VAR:
1547 #endif
1548 case ENV_USERVAR:
1549 if (ep) {
1550 *epc = 0;
1551 env_opt_add(ep);
1552 }
1553 ep = epc = &buf[i+1];
1554 break;
1555 case ENV_ESC:
1556 i++;
1557 /*FALLTHROUGH*/
1558 default:
1559 if (epc)
1560 *epc++ = buf[i];
1561 break;
1562 }
1563 }
1564 if (ep) {
1565 *epc = 0;
1566 env_opt_add(ep);
1567 }
1568 env_opt_end(1);
1569 break;
1570
1571 case TELQUAL_IS:
1572 case TELQUAL_INFO:
1573 /* Ignore for now. We shouldn't get it anyway. */
1574 break;
1575
1576 default:
1577 break;
1578 }
1579 }
1580
1581 static unsigned char *opt_reply;
1582 static unsigned char *opt_replyp;
1583 static unsigned char *opt_replyend;
1584 #define OPT_REPLY_INITIAL_SIZE 256
1585 /*
1586 * The opt reply consists of: IAC, SB, telopt_environ, TELQUAL_IS,
1587 * value, IAC, SE. i.e. it has a 'wrapper' of 6 control characters.
1588 */
1589 #define OPT_WRAPPER_SIZE 6
1590
1591 static void
env_opt_start()1592 env_opt_start()
1593 {
1594 opt_reply = realloc(opt_reply, OPT_REPLY_INITIAL_SIZE);
1595 if (opt_reply == NULL) {
1596 (void) printf(
1597 "telnet: error allocating environment option memory\n");
1598 opt_reply = opt_replyp = opt_replyend = NULL;
1599 return;
1600 }
1601 opt_replyp = opt_reply;
1602 opt_replyend = opt_reply + OPT_REPLY_INITIAL_SIZE;
1603 *opt_replyp++ = IAC;
1604 *opt_replyp++ = SB;
1605 *opt_replyp++ = telopt_environ;
1606 *opt_replyp++ = TELQUAL_IS;
1607 }
1608
1609 void
env_opt_start_info()1610 env_opt_start_info()
1611 {
1612 env_opt_start();
1613 if (opt_replyp)
1614 opt_replyp[-1] = TELQUAL_INFO;
1615 }
1616
1617 void
env_opt_add(ep)1618 env_opt_add(ep)
1619 register unsigned char *ep;
1620 {
1621 register unsigned char *vp, c;
1622 int opt_reply_size;
1623 int opt_reply_used;
1624
1625 if (opt_reply == NULL) /* XXX */
1626 return; /* XXX */
1627
1628 if (ep == NULL || *ep == '\0') {
1629 /* Send user defined variables first. */
1630 (void) env_default(1, 0);
1631 while (ep = env_default(0, 0))
1632 env_opt_add(ep);
1633
1634 /* Now add the list of well know variables. */
1635 (void) env_default(1, 1);
1636 while (ep = env_default(0, 1))
1637 env_opt_add(ep);
1638 return;
1639 }
1640 vp = env_getvalue(ep);
1641
1642 /*
1643 * Calculate space required for opt_reply and allocate more if required.
1644 * Assume worst case that every character is escaped, so needs 2 bytes.
1645 */
1646 opt_reply_used = opt_replyp - opt_reply; /* existing contents */
1647 opt_reply_size = opt_reply_used + OPT_WRAPPER_SIZE +
1648 (2 * (strlen((char *)ep))) +
1649 (vp == NULL ? 0 : (2 * strlen((char *)vp)));
1650
1651 if (opt_reply_size > (opt_replyend - opt_reply)) {
1652 opt_reply = realloc(opt_reply, opt_reply_size);
1653 if (opt_reply == NULL) {
1654 (void) printf(
1655 "telnet: can't allocate environment option "
1656 "reply\n");
1657 opt_reply = opt_replyp = opt_replyend = NULL;
1658 return;
1659 }
1660 opt_replyp = opt_reply + opt_reply_used;
1661 opt_replyend = opt_reply + opt_reply_size;
1662 }
1663
1664 if (opt_welldefined((char *)ep))
1665 #ifdef OLD_ENVIRON
1666 if (telopt_environ == TELOPT_OLD_ENVIRON)
1667 *opt_replyp++ = old_env_var;
1668 else
1669 #endif
1670 *opt_replyp++ = NEW_ENV_VAR;
1671 else
1672 *opt_replyp++ = ENV_USERVAR;
1673 for (;;) {
1674 while ((c = *ep++) != '\0') {
1675 switch (c&0xff) {
1676 case IAC:
1677 *opt_replyp++ = IAC;
1678 break;
1679 case NEW_ENV_VAR:
1680 case NEW_ENV_VALUE:
1681 case ENV_ESC:
1682 case ENV_USERVAR:
1683 *opt_replyp++ = ENV_ESC;
1684 break;
1685 }
1686 *opt_replyp++ = c;
1687 }
1688 if ((ep = vp) != NULL) {
1689 #ifdef OLD_ENVIRON
1690 if (telopt_environ == TELOPT_OLD_ENVIRON)
1691 *opt_replyp++ = old_env_value;
1692 else
1693 #endif
1694 *opt_replyp++ = NEW_ENV_VALUE;
1695 vp = NULL;
1696 } else
1697 break;
1698 }
1699 }
1700
1701 int
opt_welldefined(ep)1702 opt_welldefined(ep)
1703 char *ep;
1704 {
1705 if ((strcmp(ep, "USER") == 0) ||
1706 (strcmp(ep, "DISPLAY") == 0) ||
1707 (strcmp(ep, "PRINTER") == 0) ||
1708 (strcmp(ep, "SYSTEMTYPE") == 0) ||
1709 (strcmp(ep, "JOB") == 0) ||
1710 (strcmp(ep, "ACCT") == 0))
1711 return (1);
1712 return (0);
1713 }
1714 void
env_opt_end(emptyok)1715 env_opt_end(emptyok)
1716 register int emptyok;
1717 {
1718 register int len;
1719
1720 len = opt_replyp - opt_reply + 2;
1721 if (emptyok || len > OPT_WRAPPER_SIZE) {
1722 *opt_replyp++ = IAC;
1723 *opt_replyp++ = SE;
1724 if (NETROOM() > len) {
1725 ring_supply_data(&netoring, opt_reply, len);
1726 printsub('>', &opt_reply[2], len - 2);
1727 }
1728 else
1729 (void) printf("telnet: not enough room in buffer for "
1730 "environment option end reply\n");
1731 }
1732 if (opt_reply) {
1733 free(opt_reply);
1734 opt_reply = opt_replyp = opt_replyend = NULL;
1735 }
1736 }
1737
1738
1739
1740 int
telrcv()1741 telrcv()
1742 {
1743 register int c;
1744 register int scc;
1745 register unsigned char *sbp;
1746 int count;
1747 int returnValue = 0;
1748 int min_room = 0;
1749
1750 scc = 0;
1751 count = 0;
1752 while (--min_room > 2 || (min_room = TTYROOM()) > 2) {
1753 if (scc == 0) {
1754 if (count) {
1755 ring_consumed(&netiring, count);
1756 returnValue = 1;
1757 count = 0;
1758 }
1759 sbp = netiring.consume;
1760 scc = ring_full_consecutive(&netiring);
1761 if (scc == 0) {
1762 /* No more data coming in */
1763 break;
1764 }
1765 }
1766
1767 c = *sbp++ & 0xff, scc--; count++;
1768
1769 if (decrypt_input)
1770 c = (*decrypt_input)(c);
1771
1772 switch (telrcv_state) {
1773
1774 case TS_CR:
1775 telrcv_state = TS_DATA;
1776 if (c == '\0') {
1777 break; /* Ignore \0 after CR */
1778 } else if ((c == '\n') &&
1779 my_want_state_is_dont(TELOPT_ECHO) && !crmod) {
1780 TTYADD(c);
1781 break;
1782 }
1783 /* FALLTHROUGH */
1784
1785 case TS_DATA:
1786 if (c == IAC) {
1787 telrcv_state = TS_IAC;
1788 break;
1789 }
1790 /*
1791 * The 'crmod' hack (see following) is needed
1792 * since we can't * set CRMOD on output only.
1793 * Machines like MULTICS like to send \r without
1794 * \n; since we must turn off CRMOD to get proper
1795 * input, the mapping is done here (sigh).
1796 */
1797 if ((c == '\r') &&
1798 my_want_state_is_dont(TELOPT_BINARY)) {
1799 if (scc > 0) {
1800 c = *sbp&0xff;
1801
1802 if (decrypt_input)
1803 c = (*decrypt_input)(c);
1804
1805 if (c == 0) {
1806 sbp++, scc--; count++;
1807 /* a "true" CR */
1808 TTYADD('\r');
1809 } else if (my_want_state_is_dont(
1810 TELOPT_ECHO) && (c == '\n')) {
1811 sbp++, scc--; count++;
1812 TTYADD('\n');
1813 } else {
1814
1815 if (decrypt_input)
1816 (*decrypt_input)(-1);
1817
1818 TTYADD('\r');
1819 if (crmod) {
1820 TTYADD('\n');
1821 }
1822 }
1823 } else {
1824 telrcv_state = TS_CR;
1825 TTYADD('\r');
1826 if (crmod) {
1827 TTYADD('\n');
1828 }
1829 }
1830 } else {
1831 TTYADD(c);
1832 }
1833 continue;
1834
1835 case TS_IAC:
1836 process_iac:
1837 switch (c) {
1838
1839 case WILL:
1840 telrcv_state = TS_WILL;
1841 continue;
1842
1843 case WONT:
1844 telrcv_state = TS_WONT;
1845 continue;
1846
1847 case DO:
1848 telrcv_state = TS_DO;
1849 continue;
1850
1851 case DONT:
1852 telrcv_state = TS_DONT;
1853 continue;
1854
1855 case DM:
1856 /*
1857 * We may have missed an urgent notification,
1858 * so make sure we flush whatever is in the
1859 * buffer currently.
1860 */
1861 printoption("RCVD", IAC, DM);
1862 SYNCHing = 1;
1863 if (ttyflush(1) == -2) {
1864 /* This will not return. */
1865 fatal_tty_error("write");
1866 }
1867 SYNCHing = stilloob();
1868 settimer(gotDM);
1869 break;
1870
1871 case SB:
1872 SB_CLEAR();
1873 telrcv_state = TS_SB;
1874 continue;
1875
1876 case IAC:
1877 TTYADD(IAC);
1878 break;
1879
1880 case NOP:
1881 case GA:
1882 default:
1883 printoption("RCVD", IAC, c);
1884 break;
1885 }
1886 telrcv_state = TS_DATA;
1887 continue;
1888
1889 case TS_WILL:
1890 printoption("RCVD", WILL, c);
1891 willoption(c);
1892 telrcv_state = TS_DATA;
1893 continue;
1894
1895 case TS_WONT:
1896 printoption("RCVD", WONT, c);
1897 wontoption(c);
1898 telrcv_state = TS_DATA;
1899 continue;
1900
1901 case TS_DO:
1902 printoption("RCVD", DO, c);
1903 dooption(c);
1904 if (c == TELOPT_NAWS) {
1905 sendnaws();
1906 } else if (c == TELOPT_LFLOW) {
1907 localflow = 1;
1908 setcommandmode();
1909 setconnmode(0);
1910 }
1911 telrcv_state = TS_DATA;
1912 continue;
1913
1914 case TS_DONT:
1915 printoption("RCVD", DONT, c);
1916 dontoption(c);
1917 flushline = 1;
1918 setconnmode(0); /* set new tty mode (maybe) */
1919 telrcv_state = TS_DATA;
1920 continue;
1921
1922 case TS_SB:
1923 if (c == IAC) {
1924 telrcv_state = TS_SE;
1925 } else {
1926 SB_ACCUM(c);
1927 }
1928 continue;
1929
1930 case TS_SE:
1931 if (c != SE) {
1932 if (c != IAC) {
1933 /*
1934 * This is an error. We only expect to get
1935 * "IAC IAC" or "IAC SE". Several things may
1936 * have happend. An IAC was not doubled, the
1937 * IAC SE was left off, or another option got
1938 * inserted into the suboption are all possibilities.
1939 * If we assume that the IAC was not doubled,
1940 * and really the IAC SE was left off, we could
1941 * get into an infinate loop here. So, instead,
1942 * we terminate the suboption, and process the
1943 * partial suboption if we can.
1944 */
1945 SB_ACCUM(IAC);
1946 SB_ACCUM(c);
1947 subpointer -= 2;
1948 SB_TERM();
1949
1950 printoption("In SUBOPTION processing, "
1951 "RCVD", IAC, c);
1952 suboption(); /* handle sub-option */
1953 telrcv_state = TS_IAC;
1954 goto process_iac;
1955 }
1956 SB_ACCUM(c);
1957 telrcv_state = TS_SB;
1958 } else {
1959 SB_ACCUM(IAC);
1960 SB_ACCUM(SE);
1961 subpointer -= 2;
1962 SB_TERM();
1963 suboption(); /* handle sub-option */
1964 telrcv_state = TS_DATA;
1965 }
1966 }
1967 }
1968 if (count)
1969 ring_consumed(&netiring, count);
1970 return (returnValue||count);
1971 }
1972
1973 static int bol = 1, local = 0;
1974
1975 int
rlogin_susp()1976 rlogin_susp()
1977 {
1978 if (local) {
1979 local = 0;
1980 bol = 1;
1981 command(0, "z\n", 2);
1982 return (1);
1983 }
1984 return (0);
1985 }
1986
1987 static int
telsnd()1988 telsnd()
1989 {
1990 int tcc;
1991 int count;
1992 int returnValue = 0;
1993 unsigned char *tbp;
1994
1995 tcc = 0;
1996 count = 0;
1997 while (NETROOM() > 2) {
1998 register int sc;
1999 register int c;
2000
2001 if (tcc == 0) {
2002 if (count) {
2003 ring_consumed(&ttyiring, count);
2004 returnValue = 1;
2005 count = 0;
2006 }
2007 tbp = ttyiring.consume;
2008 tcc = ring_full_consecutive(&ttyiring);
2009 if (tcc == 0) {
2010 break;
2011 }
2012 }
2013 c = *tbp++ & 0xff, sc = strip(c), tcc--; count++;
2014 if (rlogin != _POSIX_VDISABLE) {
2015 if (bol) {
2016 bol = 0;
2017 if (sc == rlogin) {
2018 local = 1;
2019 continue;
2020 }
2021 } else if (local) {
2022 local = 0;
2023 if (sc == '.' || c == termEofChar) {
2024 bol = 1;
2025 command(0, "close\n", 6);
2026 continue;
2027 }
2028 if (sc == termSuspChar) {
2029 bol = 1;
2030 command(0, "z\n", 2);
2031 continue;
2032 }
2033 if (sc == escape) {
2034 command(0, (char *)tbp, tcc);
2035 bol = 1;
2036 count += tcc;
2037 tcc = 0;
2038 flushline = 1;
2039 break;
2040 }
2041 if (sc != rlogin) {
2042 ++tcc;
2043 --tbp;
2044 --count;
2045 c = sc = rlogin;
2046 }
2047 }
2048 if ((sc == '\n') || (sc == '\r'))
2049 bol = 1;
2050 } else if (sc == escape && escape_valid) {
2051 /*
2052 * Double escape is a pass through of a single
2053 * escape character.
2054 */
2055 if (tcc && strip(*tbp) == escape) {
2056 tbp++;
2057 tcc--;
2058 count++;
2059 bol = 0;
2060 } else {
2061 command(0, (char *)tbp, tcc);
2062 bol = 1;
2063 count += tcc;
2064 tcc = 0;
2065 flushline = 1;
2066 break;
2067 }
2068 } else
2069 bol = 0;
2070 #ifdef KLUDGELINEMODE
2071 if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) {
2072 if (tcc > 0 && strip(*tbp) == echoc) {
2073 tcc--; tbp++; count++;
2074 } else {
2075 dontlecho = !dontlecho;
2076 settimer(echotoggle);
2077 setconnmode(0);
2078 flushline = 1;
2079 break;
2080 }
2081 }
2082 #endif
2083 if (MODE_LOCAL_CHARS(globalmode)) {
2084 if (TerminalSpecialChars(sc) == 0) {
2085 bol = 1;
2086 break;
2087 }
2088 }
2089 if (my_want_state_is_wont(TELOPT_BINARY)) {
2090 switch (c) {
2091 case '\n':
2092 /*
2093 * If we are in CRMOD mode (\r ==> \n)
2094 * on our local machine, then probably
2095 * a newline (unix) is CRLF (TELNET).
2096 */
2097 if (MODE_LOCAL_CHARS(globalmode)) {
2098 NETADD('\r');
2099 }
2100 NETADD('\n');
2101 bol = flushline = 1;
2102 break;
2103 case '\r':
2104 if (!crlf) {
2105 NET2ADD('\r', '\0');
2106 } else {
2107 NET2ADD('\r', '\n');
2108 }
2109 bol = flushline = 1;
2110 break;
2111 case IAC:
2112 NET2ADD(IAC, IAC);
2113 break;
2114 default:
2115 NETADD(c);
2116 break;
2117 }
2118 } else if (c == IAC) {
2119 NET2ADD(IAC, IAC);
2120 } else {
2121 NETADD(c);
2122 }
2123 }
2124 if (count)
2125 ring_consumed(&ttyiring, count);
2126 return (returnValue||count); /* Non-zero if we did anything */
2127 }
2128
2129 /*
2130 * Scheduler()
2131 *
2132 * Try to do something.
2133 *
2134 * If we do something useful, return 1; else return 0.
2135 *
2136 */
2137
2138
2139 int
Scheduler(block)2140 Scheduler(block)
2141 int block; /* should we block in the select ? */
2142 {
2143 /*
2144 * One wants to be a bit careful about setting returnValue
2145 * to one, since a one implies we did some useful work,
2146 * and therefore probably won't be called to block next
2147 * time (TN3270 mode only).
2148 */
2149 int returnValue;
2150 int netin, netout, netex, ttyin, ttyout;
2151
2152 /* Decide which rings should be processed */
2153
2154 netout = ring_full_count(&netoring) &&
2155 (flushline ||
2156 (my_want_state_is_wont(TELOPT_LINEMODE)
2157 #ifdef KLUDGELINEMODE
2158 /* X */ && (!kludgelinemode || my_want_state_is_do(TELOPT_SGA))
2159 #endif
2160 /* XXX */) ||
2161 my_want_state_is_will(TELOPT_BINARY));
2162 ttyout = ring_full_count(&ttyoring);
2163
2164 ttyin = (ring_empty_count(&ttyiring) && !eof_pending);
2165
2166 netin = !ISend && ring_empty_count(&netiring);
2167
2168 netex = !SYNCHing;
2169
2170 if (scheduler_lockout_tty) {
2171 ttyin = ttyout = 0;
2172 }
2173
2174 /* Call to system code to process rings */
2175
2176 returnValue = process_rings(netin, netout, netex, ttyin, ttyout,
2177 !block);
2178
2179 /* Now, look at the input rings, looking for work to do. */
2180
2181 if (ring_full_count(&ttyiring)) {
2182 returnValue |= telsnd();
2183 } else {
2184 /*
2185 * If ttyiring is empty, check to see if there is a real EOF
2186 * pending. If so, we can maybe do the EOF write now.
2187 */
2188 if (eof_pending) {
2189 eof_pending = 0;
2190 sendeof();
2191 }
2192 }
2193
2194 if (ring_full_count(&netiring)) {
2195 returnValue |= telrcv();
2196 }
2197 return (returnValue);
2198 }
2199
2200 /*
2201 * Select from tty and network...
2202 */
2203 void
telnet(user)2204 telnet(user)
2205 char *user;
2206 {
2207 sys_telnet_init();
2208
2209 {
2210 static char local_host[MAXHOSTNAMELEN] = { 0 };
2211
2212 if (!local_host[0]) {
2213 (void) gethostname(local_host, sizeof (local_host));
2214 local_host[sizeof (local_host)-1] = 0;
2215 }
2216 auth_encrypt_init(local_host, hostname, "TELNET");
2217 auth_encrypt_user(user);
2218 }
2219
2220 if (autologin)
2221 send_will(TELOPT_AUTHENTICATION, 1);
2222
2223 if (telnetport || wantencryption) {
2224 send_do(TELOPT_ENCRYPT, 1);
2225 send_will(TELOPT_ENCRYPT, 1);
2226 }
2227
2228 if (telnetport) {
2229 if (!reqd_linemode)
2230 send_do(TELOPT_SGA, 1);
2231 send_will(TELOPT_TTYPE, 1);
2232 send_will(TELOPT_NAWS, 1);
2233 send_will(TELOPT_TSPEED, 1);
2234 send_will(TELOPT_LFLOW, 1);
2235 if (!reqd_linemode)
2236 send_will(TELOPT_LINEMODE, 1);
2237 send_will(TELOPT_NEW_ENVIRON, 1);
2238 send_do(TELOPT_STATUS, 1);
2239 if (env_getvalue((unsigned char *)"DISPLAY"))
2240 send_will(TELOPT_XDISPLOC, 1);
2241 if (eight)
2242 tel_enter_binary(eight);
2243 }
2244
2245 /*
2246 * Note: we assume a tie to the authentication option here. This
2247 * is necessary so that authentication fails, we don't spin
2248 * forever.
2249 */
2250 if (wantencryption) {
2251 boolean_t printed_encrypt = B_FALSE;
2252 extern boolean_t auth_has_failed;
2253 time_t timeout = time(0) + 60;
2254
2255 send_do(TELOPT_ENCRYPT, 1);
2256 send_will(TELOPT_ENCRYPT, 1);
2257 for (;;) {
2258 if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) {
2259 (void) printf(gettext(
2260 "\nServer refused to negotiate "
2261 "authentication, which is required\n"
2262 "for encryption. Good-bye.\n\r"));
2263 Exit(EXIT_FAILURE);
2264 }
2265 if (auth_has_failed) {
2266 (void) printf(gettext(
2267 "\nAuthentication negotation has failed, "
2268 "which is required for\n"
2269 "encryption. Good-bye.\n\r"));
2270 Exit(EXIT_FAILURE);
2271 }
2272 if (my_want_state_is_dont(TELOPT_ENCRYPT) ||
2273 my_want_state_is_wont(TELOPT_ENCRYPT)) {
2274 (void) printf(gettext(
2275 "\nServer refused to negotiate encryption. "
2276 "Good-bye.\n\r"));
2277 Exit(EXIT_FAILURE);
2278 }
2279 if (encrypt_is_encrypting())
2280 break;
2281
2282 if (time(0) > timeout) {
2283 (void) printf(gettext(
2284 "\nEncryption could not be enabled. "
2285 "Good-bye.\n\r"));
2286 Exit(EXIT_FAILURE);
2287 }
2288 if (printed_encrypt == B_FALSE) {
2289 printed_encrypt = B_TRUE;
2290 (void) printf(gettext(
2291 "Waiting for encryption to be negotiated...\n"));
2292 /*
2293 * Turn on MODE_TRAPSIG and then turn off localchars
2294 * so that ^C will cause telnet to exit.
2295 */
2296 TerminalNewMode(getconnmode()|MODE_TRAPSIG);
2297 intr_waiting = 1;
2298 }
2299 if (intr_happened) {
2300 (void) printf(gettext(
2301 "\nUser requested an interrupt. Good-bye.\n\r"));
2302 Exit(EXIT_FAILURE);
2303 }
2304 telnet_spin();
2305 }
2306 if (printed_encrypt) {
2307 (void) printf(gettext("done.\n"));
2308 intr_waiting = 0;
2309 setconnmode(0);
2310 }
2311 }
2312
2313 for (;;) {
2314 int schedValue;
2315
2316 while ((schedValue = Scheduler(0)) != 0) {
2317 if (schedValue == -1) {
2318 setcommandmode();
2319 return;
2320 }
2321 }
2322
2323 if (Scheduler(1) == -1) {
2324 setcommandmode();
2325 return;
2326 }
2327 }
2328 }
2329
2330 #if 0 /* XXX - this not being in is a bug */
2331 /*
2332 * nextitem()
2333 *
2334 * Return the address of the next "item" in the TELNET data
2335 * stream. This will be the address of the next character if
2336 * the current address is a user data character, or it will
2337 * be the address of the character following the TELNET command
2338 * if the current address is a TELNET IAC ("I Am a Command")
2339 * character.
2340 */
2341
2342 static char *
2343 nextitem(current)
2344 char *current;
2345 {
2346 if ((*current&0xff) != IAC) {
2347 return (current+1);
2348 }
2349 switch (*(current+1)&0xff) {
2350 case DO:
2351 case DONT:
2352 case WILL:
2353 case WONT:
2354 return (current+3);
2355 case SB: /* loop forever looking for the SE */
2356 {
2357 register char *look = current+2;
2358
2359 for (;;) {
2360 if ((*look++&0xff) == IAC) {
2361 if ((*look++&0xff) == SE) {
2362 return (look);
2363 }
2364 }
2365 }
2366 }
2367 default:
2368 return (current+2);
2369 }
2370 }
2371 #endif /* 0 */
2372
2373 /*
2374 * netclear()
2375 *
2376 * We are about to do a TELNET SYNCH operation. Clear
2377 * the path to the network.
2378 *
2379 * Things are a bit tricky since we may have sent the first
2380 * byte or so of a previous TELNET command into the network.
2381 * So, we have to scan the network buffer from the beginning
2382 * until we are up to where we want to be.
2383 *
2384 * A side effect of what we do, just to keep things
2385 * simple, is to clear the urgent data pointer. The principal
2386 * caller should be setting the urgent data pointer AFTER calling
2387 * us in any case.
2388 */
2389
2390 static void
netclear()2391 netclear()
2392 {
2393 #if 0 /* XXX */
2394 register char *thisitem, *next;
2395 char *good;
2396 #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \
2397 ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
2398
2399 thisitem = netobuf;
2400
2401 while ((next = nextitem(thisitem)) <= netobuf.send) {
2402 thisitem = next;
2403 }
2404
2405 /* Now, thisitem is first before/at boundary. */
2406
2407 good = netobuf; /* where the good bytes go */
2408
2409 while (netoring.add > thisitem) {
2410 if (wewant(thisitem)) {
2411 int length;
2412
2413 next = thisitem;
2414 do {
2415 next = nextitem(next);
2416 } while (wewant(next) && (nfrontp > next));
2417 length = next-thisitem;
2418 memcpy(good, thisitem, length);
2419 good += length;
2420 thisitem = next;
2421 } else {
2422 thisitem = nextitem(thisitem);
2423 }
2424 }
2425
2426 #endif /* 0 */
2427 }
2428
2429 /*
2430 * These routines add various telnet commands to the data stream.
2431 */
2432
2433 /*
2434 * doflush - Send do timing mark (for network connection flush) & then
2435 * get rid of anything in the output buffer. Return -1 if there was a
2436 * non-EWOULDBLOCK error on the tty flush, and otherwise return 0.
2437 */
2438 static int
doflush()2439 doflush()
2440 {
2441 NET2ADD(IAC, DO);
2442 NETADD(TELOPT_TM);
2443 flushline = 1;
2444 flushout = 1;
2445
2446 /* Drop pending tty output */
2447 if (ttyflush(1) == -2)
2448 return (-1);
2449
2450 /* do printoption AFTER flush, otherwise the output gets tossed... */
2451 printoption("SENT", DO, TELOPT_TM);
2452 return (0);
2453 }
2454
2455 int
xmitAO()2456 xmitAO()
2457 {
2458 NET2ADD(IAC, AO);
2459 printoption("SENT", IAC, AO);
2460 if (autoflush) {
2461 if (doflush() == -1)
2462 return (-1);
2463 }
2464 return (0);
2465 }
2466
2467
2468 void
xmitEL()2469 xmitEL()
2470 {
2471 NET2ADD(IAC, EL);
2472 printoption("SENT", IAC, EL);
2473 }
2474
2475 void
xmitEC()2476 xmitEC()
2477 {
2478 NET2ADD(IAC, EC);
2479 printoption("SENT", IAC, EC);
2480 }
2481
2482
2483 int
dosynch()2484 dosynch()
2485 {
2486 netclear(); /* clear the path to the network */
2487 NETADD(IAC);
2488 setneturg();
2489 NETADD(DM);
2490 printoption("SENT", IAC, DM);
2491 return (1);
2492 }
2493
2494 int want_status_response = 0;
2495
2496 int
get_status()2497 get_status()
2498 {
2499 unsigned char tmp[16];
2500 register unsigned char *cp;
2501
2502 if (my_want_state_is_dont(TELOPT_STATUS)) {
2503 (void) printf("Remote side does not support STATUS option\n");
2504 return (0);
2505 }
2506 cp = tmp;
2507
2508 *cp++ = IAC;
2509 *cp++ = SB;
2510 *cp++ = TELOPT_STATUS;
2511 *cp++ = TELQUAL_SEND;
2512 *cp++ = IAC;
2513 *cp++ = SE;
2514 if (NETROOM() >= cp - tmp) {
2515 ring_supply_data(&netoring, tmp, cp-tmp);
2516 printsub('>', tmp+2, cp - tmp - 2);
2517 }
2518 ++want_status_response;
2519 return (1);
2520 }
2521
2522 void
intp()2523 intp()
2524 {
2525 NET2ADD(IAC, IP);
2526 printoption("SENT", IAC, IP);
2527 flushline = 1;
2528 if (autoflush) {
2529 /* Ignore return as we're ending off anyway. */
2530 (void) doflush();
2531 }
2532 if (autosynch) {
2533 (void) dosynch();
2534 }
2535 }
2536
2537 int
sendbrk()2538 sendbrk()
2539 {
2540 NET2ADD(IAC, BREAK);
2541 printoption("SENT", IAC, BREAK);
2542 flushline = 1;
2543 if (autoflush) {
2544 if (doflush() == -1)
2545 return (-1);
2546 }
2547 if (autosynch) {
2548 (void) dosynch();
2549 }
2550 return (0);
2551 }
2552
2553 void
sendabort()2554 sendabort()
2555 {
2556 NET2ADD(IAC, ABORT);
2557 printoption("SENT", IAC, ABORT);
2558 flushline = 1;
2559 if (autoflush) {
2560 /*
2561 * Since sendabort() gets called while aborting,
2562 * ignore the doflush() return
2563 */
2564 (void) doflush();
2565 }
2566 if (autosynch) {
2567 (void) dosynch();
2568 }
2569 }
2570
2571 void
sendsusp()2572 sendsusp()
2573 {
2574 NET2ADD(IAC, SUSP);
2575 printoption("SENT", IAC, SUSP);
2576 flushline = 1;
2577 if (autoflush) {
2578 if (doflush() == -1) {
2579 /* The following will not return. */
2580 fatal_tty_error("write");
2581 }
2582 }
2583 if (autosynch) {
2584 (void) dosynch();
2585 }
2586 }
2587
2588 static void
sendeof()2589 sendeof()
2590 {
2591 NET2ADD(IAC, xEOF);
2592 printoption("SENT", IAC, xEOF);
2593 }
2594
2595 /*
2596 * Send a window size update to the remote system.
2597 */
2598
2599 void
sendnaws()2600 sendnaws()
2601 {
2602 unsigned short rows, cols;
2603 unsigned char tmp[16];
2604 register unsigned char *cp;
2605
2606 if (my_state_is_wont(TELOPT_NAWS))
2607 return;
2608
2609 #define PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \
2610 if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; }
2611
2612 if (TerminalWindowSize(&rows, &cols) == 0) { /* Failed */
2613 return;
2614 }
2615
2616 cp = tmp;
2617
2618 *cp++ = IAC;
2619 *cp++ = SB;
2620 *cp++ = TELOPT_NAWS;
2621 PUTSHORT(cp, cols);
2622 PUTSHORT(cp, rows);
2623 *cp++ = IAC;
2624 *cp++ = SE;
2625 if (NETROOM() >= cp - tmp) {
2626 ring_supply_data(&netoring, tmp, cp-tmp);
2627 printsub('>', tmp+2, cp - tmp - 2);
2628 }
2629 }
2630
2631 void
tel_enter_binary(rw)2632 tel_enter_binary(rw)
2633 int rw;
2634 {
2635 if (rw&1)
2636 send_do(TELOPT_BINARY, 1);
2637 if (rw&2)
2638 send_will(TELOPT_BINARY, 1);
2639 }
2640
2641 void
tel_leave_binary(rw)2642 tel_leave_binary(rw)
2643 int rw;
2644 {
2645 if (rw&1)
2646 send_dont(TELOPT_BINARY, 1);
2647 if (rw&2)
2648 send_wont(TELOPT_BINARY, 1);
2649 }
2650