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