state.c revision 1.2 1 /*
2 * Copyright (c) 1989 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
34 * -------------------- ----- ----------------------
35 * CURRENT PATCH LEVEL: 1 00035
36 * -------------------- ----- ----------------------
37 *
38 * 27 Nov 1992 Felix Gaehtgens Removed KLUDGELINEMODE
39 *
40 */
41
42 #ifndef lint
43 static char sccsid[] = "@(#)state.c 5.10 (Berkeley) 3/22/91";
44 #endif /* not lint */
45
46 #include "telnetd.h"
47 #if defined(AUTHENTICATE)
48 #include <libtelnet/auth.h>
49 #endif
50
51 char doopt[] = { IAC, DO, '%', 'c', 0 };
52 char dont[] = { IAC, DONT, '%', 'c', 0 };
53 char will[] = { IAC, WILL, '%', 'c', 0 };
54 char wont[] = { IAC, WONT, '%', 'c', 0 };
55 int not42 = 1;
56
57 /*
58 * Buffer for sub-options, and macros
59 * for suboptions buffer manipulations
60 */
61 unsigned char subbuffer[512], *subpointer= subbuffer, *subend= subbuffer;
62
63 #define SB_CLEAR() subpointer = subbuffer;
64 #define SB_TERM() { subend = subpointer; SB_CLEAR(); }
65 #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \
66 *subpointer++ = (c); \
67 }
68 #define SB_GET() ((*subpointer++)&0xff)
69 #define SB_EOF() (subpointer >= subend)
70 #define SB_LEN() (subend - subpointer)
71
72
73
74 /*
75 * State for recv fsm
76 */
77 #define TS_DATA 0 /* base state */
78 #define TS_IAC 1 /* look for double IAC's */
79 #define TS_CR 2 /* CR-LF ->'s CR */
80 #define TS_SB 3 /* throw away begin's... */
81 #define TS_SE 4 /* ...end's (suboption negotiation) */
82 #define TS_WILL 5 /* will option negotiation */
83 #define TS_WONT 6 /* wont " */
84 #define TS_DO 7 /* do " */
85 #define TS_DONT 8 /* dont " */
86
87 void
88 telrcv()
89 {
90 register int c;
91 static int state = TS_DATA;
92 #if defined(CRAY2) && defined(UNICOS5)
93 char *opfrontp = pfrontp;
94 #endif
95
96 while (ncc > 0) {
97 if ((&ptyobuf[BUFSIZ] - pfrontp) < 2)
98 break;
99 c = *netip++ & 0377, ncc--;
100 #if defined(ENCRYPT)
101 if (decrypt_input)
102 c = (*decrypt_input)(c);
103 #endif
104 switch (state) {
105
106 case TS_CR:
107 state = TS_DATA;
108 /* Strip off \n or \0 after a \r */
109 if ((c == 0) || (c == '\n')) {
110 break;
111 }
112 /* FALL THROUGH */
113
114 case TS_DATA:
115 if (c == IAC) {
116 state = TS_IAC;
117 break;
118 }
119 /*
120 * We now map \r\n ==> \r for pragmatic reasons.
121 * Many client implementations send \r\n when
122 * the user hits the CarriageReturn key.
123 *
124 * We USED to map \r\n ==> \n, since \r\n says
125 * that we want to be in column 1 of the next
126 * printable line, and \n is the standard
127 * unix way of saying that (\r is only good
128 * if CRMOD is set, which it normally is).
129 */
130 if ((c == '\r') && his_state_is_wont(TELOPT_BINARY)) {
131 int nc = *netip;
132 #if defined(ENCRYPT)
133 if (decrypt_input)
134 nc = (*decrypt_input)(nc & 0xff);
135 #endif
136 #ifdef LINEMODE
137 /*
138 * If we are operating in linemode,
139 * convert to local end-of-line.
140 */
141 if (linemode && (ncc > 0) && (('\n' == nc) ||
142 ((0 == nc) && tty_iscrnl())) ) {
143 netip++; ncc--;
144 c = '\n';
145 } else
146 #endif
147 {
148 #if defined(ENCRYPT)
149 if (decrypt_input)
150 (void)(*decrypt_input)(-1);
151 #endif
152 state = TS_CR;
153 }
154 }
155 *pfrontp++ = c;
156 break;
157
158 case TS_IAC:
159 gotiac: switch (c) {
160
161 /*
162 * Send the process on the pty side an
163 * interrupt. Do this with a NULL or
164 * interrupt char; depending on the tty mode.
165 */
166 case IP:
167 DIAG(TD_OPTIONS,
168 printoption("td: recv IAC", c));
169 interrupt();
170 break;
171
172 case BREAK:
173 DIAG(TD_OPTIONS,
174 printoption("td: recv IAC", c));
175 sendbrk();
176 break;
177
178 /*
179 * Are You There?
180 */
181 case AYT:
182 DIAG(TD_OPTIONS,
183 printoption("td: recv IAC", c));
184 recv_ayt();
185 break;
186
187 /*
188 * Abort Output
189 */
190 case AO:
191 {
192 DIAG(TD_OPTIONS,
193 printoption("td: recv IAC", c));
194 ptyflush(); /* half-hearted */
195 init_termbuf();
196
197 if (slctab[SLC_AO].sptr &&
198 *slctab[SLC_AO].sptr != (cc_t)(_POSIX_VDISABLE)) {
199 *pfrontp++ =
200 (unsigned char)*slctab[SLC_AO].sptr;
201 }
202
203 netclear(); /* clear buffer back */
204 *nfrontp++ = IAC;
205 *nfrontp++ = DM;
206 neturg = nfrontp-1; /* off by one XXX */
207 DIAG(TD_OPTIONS,
208 printoption("td: send IAC", DM));
209 break;
210 }
211
212 /*
213 * Erase Character and
214 * Erase Line
215 */
216 case EC:
217 case EL:
218 {
219 cc_t ch;
220
221 DIAG(TD_OPTIONS,
222 printoption("td: recv IAC", c));
223 ptyflush(); /* half-hearted */
224 init_termbuf();
225 if (c == EC)
226 ch = *slctab[SLC_EC].sptr;
227 else
228 ch = *slctab[SLC_EL].sptr;
229 if (ch != (cc_t)(_POSIX_VDISABLE))
230 *pfrontp++ = (unsigned char)ch;
231 break;
232 }
233
234 /*
235 * Check for urgent data...
236 */
237 case DM:
238 DIAG(TD_OPTIONS,
239 printoption("td: recv IAC", c));
240 SYNCHing = stilloob(net);
241 settimer(gotDM);
242 break;
243
244
245 /*
246 * Begin option subnegotiation...
247 */
248 case SB:
249 state = TS_SB;
250 SB_CLEAR();
251 continue;
252
253 case WILL:
254 state = TS_WILL;
255 continue;
256
257 case WONT:
258 state = TS_WONT;
259 continue;
260
261 case DO:
262 state = TS_DO;
263 continue;
264
265 case DONT:
266 state = TS_DONT;
267 continue;
268 case EOR:
269 if (his_state_is_will(TELOPT_EOR))
270 doeof();
271 break;
272
273 /*
274 * Handle RFC 10xx Telnet linemode option additions
275 * to command stream (EOF, SUSP, ABORT).
276 */
277 case xEOF:
278 doeof();
279 break;
280
281 case SUSP:
282 sendsusp();
283 break;
284
285 case ABORT:
286 sendbrk();
287 break;
288
289 case IAC:
290 *pfrontp++ = c;
291 break;
292 }
293 state = TS_DATA;
294 break;
295
296 case TS_SB:
297 if (c == IAC) {
298 state = TS_SE;
299 } else {
300 SB_ACCUM(c);
301 }
302 break;
303
304 case TS_SE:
305 if (c != SE) {
306 if (c != IAC) {
307 /*
308 * bad form of suboption negotiation.
309 * handle it in such a way as to avoid
310 * damage to local state. Parse
311 * suboption buffer found so far,
312 * then treat remaining stream as
313 * another command sequence.
314 */
315
316 /* for DIAGNOSTICS */
317 SB_ACCUM(IAC);
318 SB_ACCUM(c);
319 subpointer -= 2;
320
321 SB_TERM();
322 suboption();
323 state = TS_IAC;
324 goto gotiac;
325 }
326 SB_ACCUM(c);
327 state = TS_SB;
328 } else {
329 /* for DIAGNOSTICS */
330 SB_ACCUM(IAC);
331 SB_ACCUM(SE);
332 subpointer -= 2;
333
334 SB_TERM();
335 suboption(); /* handle sub-option */
336 state = TS_DATA;
337 }
338 break;
339
340 case TS_WILL:
341 willoption(c);
342 state = TS_DATA;
343 continue;
344
345 case TS_WONT:
346 wontoption(c);
347 state = TS_DATA;
348 continue;
349
350 case TS_DO:
351 dooption(c);
352 state = TS_DATA;
353 continue;
354
355 case TS_DONT:
356 dontoption(c);
357 state = TS_DATA;
358 continue;
359
360 default:
361 syslog(LOG_ERR, "telnetd: panic state=%d\n", state);
362 printf("telnetd: panic state=%d\n", state);
363 exit(1);
364 }
365 }
366 #if defined(CRAY2) && defined(UNICOS5)
367 if (!linemode) {
368 char xptyobuf[BUFSIZ+NETSLOP];
369 char xbuf2[BUFSIZ];
370 register char *cp;
371 int n = pfrontp - opfrontp, oc;
372 bcopy(opfrontp, xptyobuf, n);
373 pfrontp = opfrontp;
374 pfrontp += term_input(xptyobuf, pfrontp, n, BUFSIZ+NETSLOP,
375 xbuf2, &oc, BUFSIZ);
376 for (cp = xbuf2; oc > 0; --oc)
377 if ((*nfrontp++ = *cp++) == IAC)
378 *nfrontp++ = IAC;
379 }
380 #endif /* defined(CRAY2) && defined(UNICOS5) */
381 } /* end of telrcv */
382
383 /*
384 * The will/wont/do/dont state machines are based on Dave Borman's
385 * Telnet option processing state machine.
386 *
387 * These correspond to the following states:
388 * my_state = the last negotiated state
389 * want_state = what I want the state to go to
390 * want_resp = how many requests I have sent
391 * All state defaults are negative, and resp defaults to 0.
392 *
393 * When initiating a request to change state to new_state:
394 *
395 * if ((want_resp == 0 && new_state == my_state) || want_state == new_state) {
396 * do nothing;
397 * } else {
398 * want_state = new_state;
399 * send new_state;
400 * want_resp++;
401 * }
402 *
403 * When receiving new_state:
404 *
405 * if (want_resp) {
406 * want_resp--;
407 * if (want_resp && (new_state == my_state))
408 * want_resp--;
409 * }
410 * if ((want_resp == 0) && (new_state != want_state)) {
411 * if (ok_to_switch_to new_state)
412 * want_state = new_state;
413 * else
414 * want_resp++;
415 * send want_state;
416 * }
417 * my_state = new_state;
418 *
419 * Note that new_state is implied in these functions by the function itself.
420 * will and do imply positive new_state, wont and dont imply negative.
421 *
422 * Finally, there is one catch. If we send a negative response to a
423 * positive request, my_state will be the positive while want_state will
424 * remain negative. my_state will revert to negative when the negative
425 * acknowlegment arrives from the peer. Thus, my_state generally tells
426 * us not only the last negotiated state, but also tells us what the peer
427 * wants to be doing as well. It is important to understand this difference
428 * as we may wish to be processing data streams based on our desired state
429 * (want_state) or based on what the peer thinks the state is (my_state).
430 *
431 * This all works fine because if the peer sends a positive request, the data
432 * that we receive prior to negative acknowlegment will probably be affected
433 * by the positive state, and we can process it as such (if we can; if we
434 * can't then it really doesn't matter). If it is that important, then the
435 * peer probably should be buffering until this option state negotiation
436 * is complete.
437 *
438 */
439 void
440 send_do(option, init)
441 int option, init;
442 {
443 if (init) {
444 if ((do_dont_resp[option] == 0 && his_state_is_will(option)) ||
445 his_want_state_is_will(option))
446 return;
447 /*
448 * Special case for TELOPT_TM: We send a DO, but pretend
449 * that we sent a DONT, so that we can send more DOs if
450 * we want to.
451 */
452 if (option == TELOPT_TM)
453 set_his_want_state_wont(option);
454 else
455 set_his_want_state_will(option);
456 do_dont_resp[option]++;
457 }
458 (void) sprintf(nfrontp, doopt, option);
459 nfrontp += sizeof (dont) - 2;
460
461 DIAG(TD_OPTIONS, printoption("td: send do", option));
462 }
463
464 #ifdef AUTHENTICATE
465 extern void auth_request();
466 #endif
467 #ifdef LINEMODE
468 extern void doclientstat();
469 #endif
470 #ifdef ENCRYPT
471 extern void encrypt_send_support();
472 #endif
473
474 void
475 willoption(option)
476 int option;
477 {
478 int changeok = 0;
479 void (*func)() = 0;
480
481 /*
482 * process input from peer.
483 */
484
485 DIAG(TD_OPTIONS, printoption("td: recv will", option));
486
487 if (do_dont_resp[option]) {
488 do_dont_resp[option]--;
489 if (do_dont_resp[option] && his_state_is_will(option))
490 do_dont_resp[option]--;
491 }
492 if (do_dont_resp[option] == 0) {
493 if (his_want_state_is_wont(option)) {
494 switch (option) {
495
496 case TELOPT_BINARY:
497 init_termbuf();
498 tty_binaryin(1);
499 set_termbuf();
500 changeok++;
501 break;
502
503 case TELOPT_ECHO:
504 /*
505 * See comments below for more info.
506 */
507 not42 = 0; /* looks like a 4.2 system */
508 break;
509
510 case TELOPT_TM:
511 #if defined(LINEMODE) && defined(KLUDGELINEMODE)
512 /*
513 * This telnetd implementation does not really
514 * support timing marks, it just uses them to
515 * support the kludge linemode stuff. If we
516 * receive a will or wont TM in response to our
517 * do TM request that may have been sent to
518 * determine kludge linemode support, process
519 * it, otherwise TM should get a negative
520 * response back.
521 */
522 /*
523 * Handle the linemode kludge stuff.
524 * If we are not currently supporting any
525 * linemode at all, then we assume that this
526 * is the client telling us to use kludge
527 * linemode in response to our query. Set the
528 * linemode type that is to be supported, note
529 * that the client wishes to use linemode, and
530 * eat the will TM as though it never arrived.
531 */
532 if (lmodetype < KLUDGE_LINEMODE) {
533 lmodetype = KLUDGE_LINEMODE;
534 clientstat(TELOPT_LINEMODE, WILL, 0);
535 send_wont(TELOPT_SGA, 1);
536 }
537 #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
538 /*
539 * We never respond to a WILL TM, and
540 * we leave the state WONT.
541 */
542 return;
543
544 case TELOPT_LFLOW:
545 /*
546 * If we are going to support flow control
547 * option, then don't worry peer that we can't
548 * change the flow control characters.
549 */
550 slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS;
551 slctab[SLC_XON].defset.flag |= SLC_DEFAULT;
552 slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS;
553 slctab[SLC_XOFF].defset.flag |= SLC_DEFAULT;
554 case TELOPT_TTYPE:
555 case TELOPT_SGA:
556 case TELOPT_NAWS:
557 case TELOPT_TSPEED:
558 case TELOPT_XDISPLOC:
559 case TELOPT_ENVIRON:
560 changeok++;
561 break;
562
563 #ifdef LINEMODE
564 case TELOPT_LINEMODE:
565 # ifdef KLUDGELINEMODE
566 /*
567 * Note client's desire to use linemode.
568 */
569 lmodetype = REAL_LINEMODE;
570 # endif /* KLUDGELINEMODE */
571 func = doclientstat;
572 changeok++;
573 break;
574 #endif /* LINEMODE */
575
576 #ifdef AUTHENTICATE
577 case TELOPT_AUTHENTICATION:
578 func = auth_request;
579 changeok++;
580 break;
581 #endif
582
583 #ifdef ENCRYPT
584 case TELOPT_ENCRYPT:
585 func = encrypt_send_support;
586 changeok++;
587 break;
588 #endif
589
590 default:
591 break;
592 }
593 if (changeok) {
594 set_his_want_state_will(option);
595 send_do(option, 0);
596 } else {
597 do_dont_resp[option]++;
598 send_dont(option, 0);
599 }
600 } else {
601 /*
602 * Option processing that should happen when
603 * we receive conformation of a change in
604 * state that we had requested.
605 */
606 switch (option) {
607 case TELOPT_ECHO:
608 not42 = 0; /* looks like a 4.2 system */
609 /*
610 * Egads, he responded "WILL ECHO". Turn
611 * it off right now!
612 */
613 send_dont(option, 1);
614 /*
615 * "WILL ECHO". Kludge upon kludge!
616 * A 4.2 client is now echoing user input at
617 * the tty. This is probably undesireable and
618 * it should be stopped. The client will
619 * respond WONT TM to the DO TM that we send to
620 * check for kludge linemode. When the WONT TM
621 * arrives, linemode will be turned off and a
622 * change propogated to the pty. This change
623 * will cause us to process the new pty state
624 * in localstat(), which will notice that
625 * linemode is off and send a WILL ECHO
626 * so that we are properly in character mode and
627 * all is well.
628 */
629 break;
630 #ifdef LINEMODE
631 case TELOPT_LINEMODE:
632 # ifdef KLUDGELINEMODE
633 /*
634 * Note client's desire to use linemode.
635 */
636 lmodetype = REAL_LINEMODE;
637 # endif /* KLUDGELINEMODE */
638 func = doclientstat;
639 break;
640 #endif /* LINEMODE */
641
642 #ifdef AUTHENTICATE
643 case TELOPT_AUTHENTICATION:
644 func = auth_request;
645 break;
646 #endif
647
648 #ifdef ENCRYPT
649 case TELOPT_ENCRYPT:
650 func = encrypt_send_support;
651 break;
652 #endif
653 }
654 }
655 }
656 set_his_state_will(option);
657 if (func)
658 (*func)();
659 } /* end of willoption */
660
661 void
662 send_dont(option, init)
663 int option, init;
664 {
665 if (init) {
666 if ((do_dont_resp[option] == 0 && his_state_is_wont(option)) ||
667 his_want_state_is_wont(option))
668 return;
669 set_his_want_state_wont(option);
670 do_dont_resp[option]++;
671 }
672 (void) sprintf(nfrontp, dont, option);
673 nfrontp += sizeof (doopt) - 2;
674
675 DIAG(TD_OPTIONS, printoption("td: send dont", option));
676 }
677
678 void
679 wontoption(option)
680 int option;
681 {
682 /*
683 * Process client input.
684 */
685
686 DIAG(TD_OPTIONS, printoption("td: recv wont", option));
687
688 if (do_dont_resp[option]) {
689 do_dont_resp[option]--;
690 if (do_dont_resp[option] && his_state_is_wont(option))
691 do_dont_resp[option]--;
692 }
693 if (do_dont_resp[option] == 0) {
694 if (his_want_state_is_will(option)) {
695 /* it is always ok to change to negative state */
696 switch (option) {
697 case TELOPT_ECHO:
698 not42 = 1; /* doesn't seem to be a 4.2 system */
699 break;
700
701 case TELOPT_BINARY:
702 init_termbuf();
703 tty_binaryin(0);
704 set_termbuf();
705 break;
706
707 #ifdef LINEMODE
708 case TELOPT_LINEMODE:
709 # ifdef KLUDGELINEMODE
710 /*
711 * If real linemode is supported, then client is
712 * asking to turn linemode off.
713 */
714 if (lmodetype != REAL_LINEMODE)
715 break;
716 lmodetype = KLUDGE_LINEMODE;
717 # endif /* KLUDGELINEMODE */
718 clientstat(TELOPT_LINEMODE, WONT, 0);
719 break;
720 #endif /* LINEMODE */
721
722 case TELOPT_TM:
723 /*
724 * If we get a WONT TM, and had sent a DO TM,
725 * don't respond with a DONT TM, just leave it
726 * as is. Short circut the state machine to
727 * achive this.
728 */
729 set_his_want_state_wont(TELOPT_TM);
730 return;
731
732 case TELOPT_LFLOW:
733 /*
734 * If we are not going to support flow control
735 * option, then let peer know that we can't
736 * change the flow control characters.
737 */
738 slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS;
739 slctab[SLC_XON].defset.flag |= SLC_CANTCHANGE;
740 slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS;
741 slctab[SLC_XOFF].defset.flag |= SLC_CANTCHANGE;
742 break;
743
744 #if defined(AUTHENTICATE)
745 case TELOPT_AUTHENTICATION:
746 auth_finished(0, AUTH_REJECT);
747 break;
748 #endif
749
750 /*
751 * For options that we might spin waiting for
752 * sub-negotiation, if the client turns off the
753 * option rather than responding to the request,
754 * we have to treat it here as if we got a response
755 * to the sub-negotiation, (by updating the timers)
756 * so that we'll break out of the loop.
757 */
758 case TELOPT_TTYPE:
759 settimer(ttypesubopt);
760 break;
761
762 case TELOPT_TSPEED:
763 settimer(tspeedsubopt);
764 break;
765
766 case TELOPT_XDISPLOC:
767 settimer(xdisplocsubopt);
768 break;
769
770 case TELOPT_ENVIRON:
771 settimer(environsubopt);
772 break;
773
774 default:
775 break;
776 }
777 set_his_want_state_wont(option);
778 if (his_state_is_will(option))
779 send_dont(option, 0);
780 } else {
781 switch (option) {
782 case TELOPT_TM:
783 #if defined(LINEMODE) && defined(KLUDGELINEMODE)
784 if (lmodetype < REAL_LINEMODE) {
785 lmodetype = NO_LINEMODE;
786 clientstat(TELOPT_LINEMODE, WONT, 0);
787 send_will(TELOPT_SGA, 1);
788 send_will(TELOPT_ECHO, 1);
789 }
790 #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
791 break;
792
793 #if defined(AUTHENTICATE)
794 case TELOPT_AUTHENTICATION:
795 auth_finished(0, AUTH_REJECT);
796 break;
797 #endif
798 default:
799 break;
800 }
801 }
802 }
803 set_his_state_wont(option);
804
805 } /* end of wontoption */
806
807 void
808 send_will(option, init)
809 int option, init;
810 {
811 if (init) {
812 if ((will_wont_resp[option] == 0 && my_state_is_will(option))||
813 my_want_state_is_will(option))
814 return;
815 set_my_want_state_will(option);
816 will_wont_resp[option]++;
817 }
818 (void) sprintf(nfrontp, will, option);
819 nfrontp += sizeof (doopt) - 2;
820
821 DIAG(TD_OPTIONS, printoption("td: send will", option));
822 }
823
824 #if !defined(LINEMODE) || !defined(KLUDGELINEMODE)
825 /*
826 * When we get a DONT SGA, we will try once to turn it
827 * back on. If the other side responds DONT SGA, we
828 * leave it at that. This is so that when we talk to
829 * clients that understand KLUDGELINEMODE but not LINEMODE,
830 * we'll keep them in char-at-a-time mode.
831 */
832 int turn_on_sga = 0;
833 #endif
834
835 void
836 dooption(option)
837 int option;
838 {
839 int changeok = 0;
840
841 /*
842 * Process client input.
843 */
844
845 DIAG(TD_OPTIONS, printoption("td: recv do", option));
846
847 if (will_wont_resp[option]) {
848 will_wont_resp[option]--;
849 if (will_wont_resp[option] && my_state_is_will(option))
850 will_wont_resp[option]--;
851 }
852 if ((will_wont_resp[option] == 0) && (my_want_state_is_wont(option))) {
853 switch (option) {
854 case TELOPT_ECHO:
855 #ifdef LINEMODE
856 # ifdef KLUDGELINEMODE
857 if (lmodetype == NO_LINEMODE)
858 # else
859 if (his_state_is_wont(TELOPT_LINEMODE))
860 # endif
861 #endif
862 {
863 init_termbuf();
864 tty_setecho(1);
865 set_termbuf();
866 }
867 changeok++;
868 break;
869
870 case TELOPT_BINARY:
871 init_termbuf();
872 tty_binaryout(1);
873 set_termbuf();
874 changeok++;
875 break;
876
877 case TELOPT_SGA:
878 #if defined(LINEMODE) && defined(KLUDGELINEMODE)
879 /*
880 * If kludge linemode is in use, then we must
881 * process an incoming do SGA for linemode
882 * purposes.
883 */
884 if (lmodetype == KLUDGE_LINEMODE) {
885 /*
886 * Receipt of "do SGA" in kludge
887 * linemode is the peer asking us to
888 * turn off linemode. Make note of
889 * the request.
890 */
891 clientstat(TELOPT_LINEMODE, WONT, 0);
892 /*
893 * If linemode did not get turned off
894 * then don't tell peer that we did.
895 * Breaking here forces a wont SGA to
896 * be returned.
897 */
898 if (linemode)
899 break;
900 }
901 #else
902 turn_on_sga = 0;
903 #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
904 changeok++;
905 break;
906
907 case TELOPT_STATUS:
908 changeok++;
909 break;
910
911 case TELOPT_TM:
912 /*
913 * Special case for TM. We send a WILL, but
914 * pretend we sent a WONT.
915 */
916 send_will(option, 0);
917 set_my_want_state_wont(option);
918 set_my_state_wont(option);
919 return;
920
921 case TELOPT_LOGOUT:
922 /*
923 * When we get a LOGOUT option, respond
924 * with a WILL LOGOUT, make sure that
925 * it gets written out to the network,
926 * and then just go away...
927 */
928 set_my_want_state_will(TELOPT_LOGOUT);
929 send_will(TELOPT_LOGOUT, 0);
930 set_my_state_will(TELOPT_LOGOUT);
931 (void)netflush();
932 cleanup(0);
933 /* NOT REACHED */
934 break;
935
936 #if defined(ENCRYPT)
937 case TELOPT_ENCRYPT:
938 changeok++;
939 break;
940 #endif
941 case TELOPT_LINEMODE:
942 case TELOPT_TTYPE:
943 case TELOPT_NAWS:
944 case TELOPT_TSPEED:
945 case TELOPT_LFLOW:
946 case TELOPT_XDISPLOC:
947 case TELOPT_ENVIRON:
948 default:
949 break;
950 }
951 if (changeok) {
952 set_my_want_state_will(option);
953 send_will(option, 0);
954 } else {
955 will_wont_resp[option]++;
956 send_wont(option, 0);
957 }
958 }
959 set_my_state_will(option);
960
961 } /* end of dooption */
962
963 void
964 send_wont(option, init)
965 int option, init;
966 {
967 if (init) {
968 if ((will_wont_resp[option] == 0 && my_state_is_wont(option)) ||
969 my_want_state_is_wont(option))
970 return;
971 set_my_want_state_wont(option);
972 will_wont_resp[option]++;
973 }
974 (void) sprintf(nfrontp, wont, option);
975 nfrontp += sizeof (wont) - 2;
976
977 DIAG(TD_OPTIONS, printoption("td: send wont", option));
978 }
979
980 void
981 dontoption(option)
982 int option;
983 {
984 /*
985 * Process client input.
986 */
987
988
989 DIAG(TD_OPTIONS, printoption("td: recv dont", option));
990
991 if (will_wont_resp[option]) {
992 will_wont_resp[option]--;
993 if (will_wont_resp[option] && my_state_is_wont(option))
994 will_wont_resp[option]--;
995 }
996 if ((will_wont_resp[option] == 0) && (my_want_state_is_will(option))) {
997 switch (option) {
998 case TELOPT_BINARY:
999 init_termbuf();
1000 tty_binaryout(0);
1001 set_termbuf();
1002 break;
1003
1004 case TELOPT_ECHO: /* we should stop echoing */
1005 #ifdef LINEMODE
1006 # ifdef KLUDGELINEMODE
1007 if (lmodetype == NO_LINEMODE)
1008 # else
1009 if (his_state_is_wont(TELOPT_LINEMODE))
1010 # endif
1011 #endif
1012 {
1013 init_termbuf();
1014 tty_setecho(0);
1015 set_termbuf();
1016 }
1017 break;
1018
1019 case TELOPT_SGA:
1020 #if defined(LINEMODE) && defined(KLUDGELINEMODE)
1021 /*
1022 * If kludge linemode is in use, then we
1023 * must process an incoming do SGA for
1024 * linemode purposes.
1025 */
1026 if (lmodetype == KLUDGE_LINEMODE) {
1027 /*
1028 * The client is asking us to turn
1029 * linemode on.
1030 */
1031 clientstat(TELOPT_LINEMODE, WILL, 0);
1032 /*
1033 * If we did not turn line mode on,
1034 * then what do we say? Will SGA?
1035 * This violates design of telnet.
1036 * Gross. Very Gross.
1037 */
1038 }
1039 break;
1040 #else
1041 set_my_want_state_wont(option);
1042 if (my_state_is_will(option))
1043 send_wont(option, 0);
1044 set_my_state_wont(option);
1045 if (turn_on_sga ^= 1)
1046 send_will(option,1);
1047 return;
1048 #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
1049
1050 default:
1051 break;
1052 }
1053
1054 set_my_want_state_wont(option);
1055 if (my_state_is_will(option))
1056 send_wont(option, 0);
1057 }
1058 set_my_state_wont(option);
1059
1060 } /* end of dontoption */
1061
1062 /*
1063 * suboption()
1064 *
1065 * Look at the sub-option buffer, and try to be helpful to the other
1066 * side.
1067 *
1068 * Currently we recognize:
1069 *
1070 * Terminal type is
1071 * Linemode
1072 * Window size
1073 * Terminal speed
1074 */
1075 void
1076 suboption()
1077 {
1078 register int subchar;
1079
1080 DIAG(TD_OPTIONS, {netflush(); printsub('<', subpointer, SB_LEN()+2);});
1081
1082 subchar = SB_GET();
1083 switch (subchar) {
1084 case TELOPT_TSPEED: {
1085 register int xspeed, rspeed;
1086
1087 if (his_state_is_wont(TELOPT_TSPEED)) /* Ignore if option disabled */
1088 break;
1089
1090 settimer(tspeedsubopt);
1091
1092 if (SB_EOF() || SB_GET() != TELQUAL_IS)
1093 return;
1094
1095 xspeed = atoi((char *)subpointer);
1096
1097 while (SB_GET() != ',' && !SB_EOF());
1098 if (SB_EOF())
1099 return;
1100
1101 rspeed = atoi((char *)subpointer);
1102 clientstat(TELOPT_TSPEED, xspeed, rspeed);
1103
1104 break;
1105
1106 } /* end of case TELOPT_TSPEED */
1107
1108 case TELOPT_TTYPE: { /* Yaaaay! */
1109 static char terminalname[41];
1110
1111 if (his_state_is_wont(TELOPT_TTYPE)) /* Ignore if option disabled */
1112 break;
1113 settimer(ttypesubopt);
1114
1115 if (SB_EOF() || SB_GET() != TELQUAL_IS) {
1116 return; /* ??? XXX but, this is the most robust */
1117 }
1118
1119 terminaltype = terminalname;
1120
1121 while ((terminaltype < (terminalname + sizeof terminalname-1)) &&
1122 !SB_EOF()) {
1123 register int c;
1124
1125 c = SB_GET();
1126 if (isupper(c)) {
1127 c = tolower(c);
1128 }
1129 *terminaltype++ = c; /* accumulate name */
1130 }
1131 *terminaltype = 0;
1132 terminaltype = terminalname;
1133 break;
1134 } /* end of case TELOPT_TTYPE */
1135
1136 case TELOPT_NAWS: {
1137 register int xwinsize, ywinsize;
1138
1139 if (his_state_is_wont(TELOPT_NAWS)) /* Ignore if option disabled */
1140 break;
1141
1142 if (SB_EOF())
1143 return;
1144 xwinsize = SB_GET() << 8;
1145 if (SB_EOF())
1146 return;
1147 xwinsize |= SB_GET();
1148 if (SB_EOF())
1149 return;
1150 ywinsize = SB_GET() << 8;
1151 if (SB_EOF())
1152 return;
1153 ywinsize |= SB_GET();
1154 clientstat(TELOPT_NAWS, xwinsize, ywinsize);
1155
1156 break;
1157
1158 } /* end of case TELOPT_NAWS */
1159
1160 #ifdef LINEMODE
1161 case TELOPT_LINEMODE: {
1162 register int request;
1163
1164 if (his_state_is_wont(TELOPT_LINEMODE)) /* Ignore if option disabled */
1165 break;
1166 /*
1167 * Process linemode suboptions.
1168 */
1169 if (SB_EOF())
1170 break; /* garbage was sent */
1171 request = SB_GET(); /* get will/wont */
1172
1173 if (SB_EOF())
1174 break; /* another garbage check */
1175
1176 if (request == LM_SLC) { /* SLC is not preceeded by WILL or WONT */
1177 /*
1178 * Process suboption buffer of slc's
1179 */
1180 start_slc(1);
1181 do_opt_slc(subpointer, subend - subpointer);
1182 (void) end_slc(0);
1183 break;
1184 } else if (request == LM_MODE) {
1185 if (SB_EOF())
1186 return;
1187 useeditmode = SB_GET(); /* get mode flag */
1188 clientstat(LM_MODE, 0, 0);
1189 break;
1190 }
1191
1192 if (SB_EOF())
1193 break;
1194 switch (SB_GET()) { /* what suboption? */
1195 case LM_FORWARDMASK:
1196 /*
1197 * According to spec, only server can send request for
1198 * forwardmask, and client can only return a positive response.
1199 * So don't worry about it.
1200 */
1201
1202 default:
1203 break;
1204 }
1205 break;
1206 } /* end of case TELOPT_LINEMODE */
1207 #endif
1208 case TELOPT_STATUS: {
1209 int mode;
1210
1211 if (SB_EOF())
1212 break;
1213 mode = SB_GET();
1214 switch (mode) {
1215 case TELQUAL_SEND:
1216 if (my_state_is_will(TELOPT_STATUS))
1217 send_status();
1218 break;
1219
1220 case TELQUAL_IS:
1221 break;
1222
1223 default:
1224 break;
1225 }
1226 break;
1227 } /* end of case TELOPT_STATUS */
1228
1229 case TELOPT_XDISPLOC: {
1230 if (SB_EOF() || SB_GET() != TELQUAL_IS)
1231 return;
1232 settimer(xdisplocsubopt);
1233 subpointer[SB_LEN()] = '\0';
1234 (void)setenv("DISPLAY", (char *)subpointer, 1);
1235 break;
1236 } /* end of case TELOPT_XDISPLOC */
1237
1238 case TELOPT_ENVIRON: {
1239 register int c;
1240 register char *cp, *varp, *valp;
1241
1242 if (SB_EOF())
1243 return;
1244 c = SB_GET();
1245 if (c == TELQUAL_IS)
1246 settimer(environsubopt);
1247 else if (c != TELQUAL_INFO)
1248 return;
1249
1250 while (!SB_EOF() && SB_GET() != ENV_VAR)
1251 ;
1252
1253 if (SB_EOF())
1254 return;
1255
1256 cp = varp = (char *)subpointer;
1257 valp = 0;
1258
1259 while (!SB_EOF()) {
1260 switch (c = SB_GET()) {
1261 case ENV_VALUE:
1262 *cp = '\0';
1263 cp = valp = (char *)subpointer;
1264 break;
1265
1266 case ENV_VAR:
1267 *cp = '\0';
1268 if (valp)
1269 (void)setenv(varp, valp, 1);
1270 else
1271 unsetenv(varp);
1272 cp = varp = (char *)subpointer;
1273 valp = 0;
1274 break;
1275
1276 case ENV_ESC:
1277 if (SB_EOF())
1278 break;
1279 c = SB_GET();
1280 /* FALL THROUGH */
1281 default:
1282 *cp++ = c;
1283 break;
1284 }
1285 }
1286 *cp = '\0';
1287 if (valp)
1288 (void)setenv(varp, valp, 1);
1289 else
1290 unsetenv(varp);
1291 break;
1292 } /* end of case TELOPT_ENVIRON */
1293 #if defined(AUTHENTICATE)
1294 case TELOPT_AUTHENTICATION:
1295 if (SB_EOF())
1296 break;
1297 switch(SB_GET()) {
1298 case TELQUAL_SEND:
1299 case TELQUAL_REPLY:
1300 /*
1301 * These are sent by us and cannot be sent by
1302 * the client.
1303 */
1304 break;
1305 case TELQUAL_IS:
1306 auth_is(subpointer, SB_LEN());
1307 break;
1308 case TELQUAL_NAME:
1309 auth_name(subpointer, SB_LEN());
1310 break;
1311 }
1312 break;
1313 #endif
1314 #if defined(ENCRYPT)
1315 case TELOPT_ENCRYPT:
1316 if (SB_EOF())
1317 break;
1318 switch(SB_GET()) {
1319 case ENCRYPT_SUPPORT:
1320 encrypt_support(subpointer, SB_LEN());
1321 break;
1322 case ENCRYPT_IS:
1323 encrypt_is(subpointer, SB_LEN());
1324 break;
1325 case ENCRYPT_REPLY:
1326 encrypt_reply(subpointer, SB_LEN());
1327 break;
1328 case ENCRYPT_START:
1329 encrypt_start(subpointer, SB_LEN());
1330 break;
1331 case ENCRYPT_END:
1332 encrypt_end();
1333 break;
1334 case ENCRYPT_REQSTART:
1335 encrypt_request_start(subpointer, SB_LEN());
1336 break;
1337 case ENCRYPT_REQEND:
1338 /*
1339 * We can always send an REQEND so that we cannot
1340 * get stuck encrypting. We should only get this
1341 * if we have been able to get in the correct mode
1342 * anyhow.
1343 */
1344 encrypt_request_end();
1345 break;
1346 case ENCRYPT_ENC_KEYID:
1347 encrypt_enc_keyid(subpointer, SB_LEN());
1348 break;
1349 case ENCRYPT_DEC_KEYID:
1350 encrypt_dec_keyid(subpointer, SB_LEN());
1351 break;
1352 default:
1353 break;
1354 }
1355 break;
1356 #endif
1357
1358 default:
1359 break;
1360 } /* end of switch */
1361
1362 } /* end of suboption */
1363
1364 void
1365 doclientstat()
1366 {
1367 clientstat(TELOPT_LINEMODE, WILL, 0);
1368 }
1369
1370 #define ADD(c) *ncp++ = c;
1371 #define ADD_DATA(c) { *ncp++ = c; if (c == SE) *ncp++ = c; }
1372 void
1373 send_status()
1374 {
1375 unsigned char statusbuf[256];
1376 register unsigned char *ncp;
1377 register unsigned char i;
1378
1379 ncp = statusbuf;
1380
1381 netflush(); /* get rid of anything waiting to go out */
1382
1383 ADD(IAC);
1384 ADD(SB);
1385 ADD(TELOPT_STATUS);
1386 ADD(TELQUAL_IS);
1387
1388 /*
1389 * We check the want_state rather than the current state,
1390 * because if we received a DO/WILL for an option that we
1391 * don't support, and the other side didn't send a DONT/WONT
1392 * in response to our WONT/DONT, then the "state" will be
1393 * WILL/DO, and the "want_state" will be WONT/DONT. We
1394 * need to go by the latter.
1395 */
1396 for (i = 0; i < NTELOPTS; i++) {
1397 if (my_want_state_is_will(i)) {
1398 ADD(WILL);
1399 ADD_DATA(i);
1400 if (i == IAC)
1401 ADD(IAC);
1402 }
1403 if (his_want_state_is_will(i)) {
1404 ADD(DO);
1405 ADD_DATA(i);
1406 if (i == IAC)
1407 ADD(IAC);
1408 }
1409 }
1410
1411 if (his_want_state_is_will(TELOPT_LFLOW)) {
1412 ADD(SB);
1413 ADD(TELOPT_LFLOW);
1414 ADD(flowmode);
1415 ADD(SE);
1416 }
1417
1418 #ifdef LINEMODE
1419 if (his_want_state_is_will(TELOPT_LINEMODE)) {
1420 unsigned char *cp, *cpe;
1421 int len;
1422
1423 ADD(SB);
1424 ADD(TELOPT_LINEMODE);
1425 ADD(LM_MODE);
1426 ADD_DATA(editmode);
1427 if (editmode == IAC)
1428 ADD(IAC);
1429 ADD(SE);
1430
1431 ADD(SB);
1432 ADD(TELOPT_LINEMODE);
1433 ADD(LM_SLC);
1434 start_slc(0);
1435 send_slc();
1436 len = end_slc(&cp);
1437 for (cpe = cp + len; cp < cpe; cp++)
1438 ADD_DATA(*cp);
1439 ADD(SE);
1440 }
1441 #endif /* LINEMODE */
1442
1443 ADD(IAC);
1444 ADD(SE);
1445
1446 writenet(statusbuf, ncp - statusbuf);
1447 netflush(); /* Send it on its way */
1448
1449 DIAG(TD_OPTIONS,
1450 {printsub('>', statusbuf, ncp - statusbuf); netflush();});
1451 }
1452