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