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