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