1 /*
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 */
7
8 #ifndef lint
9 static char sccsid[] = "@(#)termstat.c 8.2 (Berkeley) 05/30/95";
10 #endif /* not lint */
11
12 #include "telnetd.h"
13
14 /*
15 * local variables
16 */
17 int def_tspeed = -1, def_rspeed = -1;
18 #ifdef TIOCSWINSZ
19 int def_row = 0, def_col = 0;
20 #endif
21 #ifdef LINEMODE
22 static int _terminit = 0;
23 #endif /* LINEMODE */
24
25 #if defined(CRAY2) && defined(UNICOS5)
26 int newmap = 1; /* nonzero if \n maps to ^M^J */
27 #endif
28
29 #ifdef LINEMODE
30 /*
31 * localstat
32 *
33 * This function handles all management of linemode.
34 *
35 * Linemode allows the client to do the local editing of data
36 * and send only complete lines to the server. Linemode state is
37 * based on the state of the pty driver. If the pty is set for
38 * external processing, then we can use linemode. Further, if we
39 * can use real linemode, then we can look at the edit control bits
40 * in the pty to determine what editing the client should do.
41 *
42 * Linemode support uses the following state flags to keep track of
43 * current and desired linemode state.
44 * alwayslinemode : true if -l was specified on the telnetd
45 * command line. It means to have linemode on as much as
46 * possible.
47 *
48 * lmodetype: signifies whether the client can
49 * handle real linemode, or if use of kludgeomatic linemode
50 * is preferred. It will be set to one of the following:
51 * REAL_LINEMODE : use linemode option
52 * NO_KLUDGE : don't initiate kludge linemode.
53 * KLUDGE_LINEMODE : use kludge linemode
54 * NO_LINEMODE : client is ignorant of linemode
55 *
56 * linemode, uselinemode : linemode is true if linemode
57 * is currently on, uselinemode is the state that we wish
58 * to be in. If another function wishes to turn linemode
59 * on or off, it sets or clears uselinemode.
60 *
61 * editmode, useeditmode : like linemode/uselinemode, but
62 * these contain the edit mode states (edit and trapsig).
63 *
64 * The state variables correspond to some of the state information
65 * in the pty.
66 * linemode:
67 * In real linemode, this corresponds to whether the pty
68 * expects external processing of incoming data.
69 * In kludge linemode, this more closely corresponds to the
70 * whether normal processing is on or not. (ICANON in
71 * system V, or COOKED mode in BSD.)
72 * If the -l option was specified (alwayslinemode), then
73 * an attempt is made to force external processing on at
74 * all times.
75 *
76 * The following heuristics are applied to determine linemode
77 * handling within the server.
78 * 1) Early on in starting up the server, an attempt is made
79 * to negotiate the linemode option. If this succeeds
80 * then lmodetype is set to REAL_LINEMODE and all linemode
81 * processing occurs in the context of the linemode option.
82 * 2) If the attempt to negotiate the linemode option failed,
83 * and the "-k" (don't initiate kludge linemode) isn't set,
84 * then we try to use kludge linemode. We test for this
85 * capability by sending "do Timing Mark". If a positive
86 * response comes back, then we assume that the client
87 * understands kludge linemode (ech!) and the
88 * lmodetype flag is set to KLUDGE_LINEMODE.
89 * 3) Otherwise, linemode is not supported at all and
90 * lmodetype remains set to NO_LINEMODE (which happens
91 * to be 0 for convenience).
92 * 4) At any time a command arrives that implies a higher
93 * state of linemode support in the client, we move to that
94 * linemode support.
95 *
96 * A short explanation of kludge linemode is in order here.
97 * 1) The heuristic to determine support for kludge linemode
98 * is to send a do timing mark. We assume that a client
99 * that supports timing marks also supports kludge linemode.
100 * A risky proposition at best.
101 * 2) Further negotiation of linemode is done by changing the
102 * the server's state regarding SGA. If server will SGA,
103 * then linemode is off, if server won't SGA, then linemode
104 * is on.
105 */
106 void
localstat()107 localstat()
108 {
109 void netflush();
110 int need_will_echo = 0;
111
112 #if defined(CRAY2) && defined(UNICOS5)
113 /*
114 * Keep track of that ol' CR/NL mapping while we're in the
115 * neighborhood.
116 */
117 newmap = tty_isnewmap();
118 #endif /* defined(CRAY2) && defined(UNICOS5) */
119
120 /*
121 * Check for state of BINARY options.
122 */
123 if (tty_isbinaryin()) {
124 if (his_want_state_is_wont(TELOPT_BINARY))
125 send_do(TELOPT_BINARY, 1);
126 } else {
127 if (his_want_state_is_will(TELOPT_BINARY))
128 send_dont(TELOPT_BINARY, 1);
129 }
130
131 if (tty_isbinaryout()) {
132 if (my_want_state_is_wont(TELOPT_BINARY))
133 send_will(TELOPT_BINARY, 1);
134 } else {
135 if (my_want_state_is_will(TELOPT_BINARY))
136 send_wont(TELOPT_BINARY, 1);
137 }
138
139 /*
140 * Check for changes to flow control if client supports it.
141 */
142 flowstat();
143
144 /*
145 * Check linemode on/off state
146 */
147 uselinemode = tty_linemode();
148
149 /*
150 * If alwayslinemode is on, and pty is changing to turn it off, then
151 * force linemode back on.
152 */
153 if (alwayslinemode && linemode && !uselinemode) {
154 uselinemode = 1;
155 tty_setlinemode(uselinemode);
156 }
157
158 #ifdef ENCRYPTION
159 /*
160 * If the terminal is not echoing, but editing is enabled,
161 * something like password input is going to happen, so
162 * if we the other side is not currently sending encrypted
163 * data, ask the other side to start encrypting.
164 */
165 if (his_state_is_will(TELOPT_ENCRYPT)) {
166 static int enc_passwd = 0;
167 if (uselinemode && !tty_isecho() && tty_isediting()
168 && (enc_passwd == 0) && !decrypt_input) {
169 encrypt_send_request_start();
170 enc_passwd = 1;
171 } else if (enc_passwd) {
172 encrypt_send_request_end();
173 enc_passwd = 0;
174 }
175 }
176 #endif /* ENCRYPTION */
177
178 /*
179 * Do echo mode handling as soon as we know what the
180 * linemode is going to be.
181 * If the pty has echo turned off, then tell the client that
182 * the server will echo. If echo is on, then the server
183 * will echo if in character mode, but in linemode the
184 * client should do local echoing. The state machine will
185 * not send anything if it is unnecessary, so don't worry
186 * about that here.
187 *
188 * If we need to send the WILL ECHO (because echo is off),
189 * then delay that until after we have changed the MODE.
190 * This way, when the user is turning off both editing
191 * and echo, the client will get editing turned off first.
192 * This keeps the client from going into encryption mode
193 * and then right back out if it is doing auto-encryption
194 * when passwords are being typed.
195 */
196 if (uselinemode) {
197 if (tty_isecho())
198 send_wont(TELOPT_ECHO, 1);
199 else
200 need_will_echo = 1;
201 #ifdef KLUDGELINEMODE
202 if (lmodetype == KLUDGE_OK)
203 lmodetype = KLUDGE_LINEMODE;
204 #endif
205 }
206
207 /*
208 * If linemode is being turned off, send appropriate
209 * command and then we're all done.
210 */
211 if (!uselinemode && linemode) {
212 # ifdef KLUDGELINEMODE
213 if (lmodetype == REAL_LINEMODE) {
214 # endif /* KLUDGELINEMODE */
215 send_dont(TELOPT_LINEMODE, 1);
216 # ifdef KLUDGELINEMODE
217 } else if (lmodetype == KLUDGE_LINEMODE)
218 send_will(TELOPT_SGA, 1);
219 # endif /* KLUDGELINEMODE */
220 send_will(TELOPT_ECHO, 1);
221 linemode = uselinemode;
222 goto done;
223 }
224
225 # ifdef KLUDGELINEMODE
226 /*
227 * If using real linemode check edit modes for possible later use.
228 * If we are in kludge linemode, do the SGA negotiation.
229 */
230 if (lmodetype == REAL_LINEMODE) {
231 # endif /* KLUDGELINEMODE */
232 useeditmode = 0;
233 if (tty_isediting())
234 useeditmode |= MODE_EDIT;
235 if (tty_istrapsig())
236 useeditmode |= MODE_TRAPSIG;
237 if (tty_issofttab())
238 useeditmode |= MODE_SOFT_TAB;
239 if (tty_islitecho())
240 useeditmode |= MODE_LIT_ECHO;
241 # ifdef KLUDGELINEMODE
242 } else if (lmodetype == KLUDGE_LINEMODE) {
243 if (tty_isediting() && uselinemode)
244 send_wont(TELOPT_SGA, 1);
245 else
246 send_will(TELOPT_SGA, 1);
247 }
248 # endif /* KLUDGELINEMODE */
249
250 /*
251 * Negotiate linemode on if pty state has changed to turn it on.
252 * Send appropriate command and send along edit mode, then all done.
253 */
254 if (uselinemode && !linemode) {
255 # ifdef KLUDGELINEMODE
256 if (lmodetype == KLUDGE_LINEMODE) {
257 send_wont(TELOPT_SGA, 1);
258 } else if (lmodetype == REAL_LINEMODE) {
259 # endif /* KLUDGELINEMODE */
260 send_do(TELOPT_LINEMODE, 1);
261 /* send along edit modes */
262 (void) sprintf(nfrontp, "%c%c%c%c%c%c%c", IAC, SB,
263 TELOPT_LINEMODE, LM_MODE, useeditmode,
264 IAC, SE);
265 nfrontp += 7;
266 editmode = useeditmode;
267 # ifdef KLUDGELINEMODE
268 }
269 # endif /* KLUDGELINEMODE */
270 linemode = uselinemode;
271 goto done;
272 }
273
274 # ifdef KLUDGELINEMODE
275 /*
276 * None of what follows is of any value if not using
277 * real linemode.
278 */
279 if (lmodetype < REAL_LINEMODE)
280 goto done;
281 # endif /* KLUDGELINEMODE */
282
283 if (linemode && his_state_is_will(TELOPT_LINEMODE)) {
284 /*
285 * If edit mode changed, send edit mode.
286 */
287 if (useeditmode != editmode) {
288 /*
289 * Send along appropriate edit mode mask.
290 */
291 (void) sprintf(nfrontp, "%c%c%c%c%c%c%c", IAC, SB,
292 TELOPT_LINEMODE, LM_MODE, useeditmode,
293 IAC, SE);
294 nfrontp += 7;
295 editmode = useeditmode;
296 }
297
298
299 /*
300 * Check for changes to special characters in use.
301 */
302 start_slc(0);
303 check_slc();
304 (void) end_slc(0);
305 }
306
307 done:
308 if (need_will_echo)
309 send_will(TELOPT_ECHO, 1);
310 /*
311 * Some things should be deferred until after the pty state has
312 * been set by the local process. Do those things that have been
313 * deferred now. This only happens once.
314 */
315 if (_terminit == 0) {
316 _terminit = 1;
317 defer_terminit();
318 }
319
320 netflush();
321 set_termbuf();
322 return;
323
324 } /* end of localstat */
325 #endif /* LINEMODE */
326
327 /*
328 * flowstat
329 *
330 * Check for changes to flow control
331 */
332 void
flowstat()333 flowstat()
334 {
335 if (his_state_is_will(TELOPT_LFLOW)) {
336 if (tty_flowmode() != flowmode) {
337 flowmode = tty_flowmode();
338 (void) sprintf(nfrontp, "%c%c%c%c%c%c",
339 IAC, SB, TELOPT_LFLOW,
340 flowmode ? LFLOW_ON : LFLOW_OFF,
341 IAC, SE);
342 nfrontp += 6;
343 }
344 if (tty_restartany() != restartany) {
345 restartany = tty_restartany();
346 (void) sprintf(nfrontp, "%c%c%c%c%c%c",
347 IAC, SB, TELOPT_LFLOW,
348 restartany ? LFLOW_RESTART_ANY
349 : LFLOW_RESTART_XON,
350 IAC, SE);
351 nfrontp += 6;
352 }
353 }
354 }
355
356 /*
357 * clientstat
358 *
359 * Process linemode related requests from the client.
360 * Client can request a change to only one of linemode, editmode or slc's
361 * at a time, and if using kludge linemode, then only linemode may be
362 * affected.
363 */
364 void
clientstat(code,parm1,parm2)365 clientstat(code, parm1, parm2)
366 register int code, parm1, parm2;
367 {
368 void netflush();
369
370 /*
371 * Get a copy of terminal characteristics.
372 */
373 init_termbuf();
374
375 /*
376 * Process request from client. code tells what it is.
377 */
378 switch (code) {
379 #ifdef LINEMODE
380 case TELOPT_LINEMODE:
381 /*
382 * Don't do anything unless client is asking us to change
383 * modes.
384 */
385 uselinemode = (parm1 == WILL);
386 if (uselinemode != linemode) {
387 # ifdef KLUDGELINEMODE
388 /*
389 * If using kludge linemode, make sure that
390 * we can do what the client asks.
391 * We can not turn off linemode if alwayslinemode
392 * and the ICANON bit is set.
393 */
394 if (lmodetype == KLUDGE_LINEMODE) {
395 if (alwayslinemode && tty_isediting()) {
396 uselinemode = 1;
397 }
398 }
399
400 /*
401 * Quit now if we can't do it.
402 */
403 if (uselinemode == linemode)
404 return;
405
406 /*
407 * If using real linemode and linemode is being
408 * turned on, send along the edit mode mask.
409 */
410 if (lmodetype == REAL_LINEMODE && uselinemode)
411 # else /* KLUDGELINEMODE */
412 if (uselinemode)
413 # endif /* KLUDGELINEMODE */
414 {
415 useeditmode = 0;
416 if (tty_isediting())
417 useeditmode |= MODE_EDIT;
418 if (tty_istrapsig)
419 useeditmode |= MODE_TRAPSIG;
420 if (tty_issofttab())
421 useeditmode |= MODE_SOFT_TAB;
422 if (tty_islitecho())
423 useeditmode |= MODE_LIT_ECHO;
424 (void) sprintf(nfrontp, "%c%c%c%c%c%c%c", IAC,
425 SB, TELOPT_LINEMODE, LM_MODE,
426 useeditmode, IAC, SE);
427 nfrontp += 7;
428 editmode = useeditmode;
429 }
430
431
432 tty_setlinemode(uselinemode);
433
434 linemode = uselinemode;
435
436 if (!linemode)
437 send_will(TELOPT_ECHO, 1);
438 }
439 break;
440
441 case LM_MODE:
442 {
443 register int ack, changed;
444
445 /*
446 * Client has sent along a mode mask. If it agrees with
447 * what we are currently doing, ignore it; if not, it could
448 * be viewed as a request to change. Note that the server
449 * will change to the modes in an ack if it is different from
450 * what we currently have, but we will not ack the ack.
451 */
452 useeditmode &= MODE_MASK;
453 ack = (useeditmode & MODE_ACK);
454 useeditmode &= ~MODE_ACK;
455
456 if (changed = (useeditmode ^ editmode)) {
457 /*
458 * This check is for a timing problem. If the
459 * state of the tty has changed (due to the user
460 * application) we need to process that info
461 * before we write in the state contained in the
462 * ack!!! This gets out the new MODE request,
463 * and when the ack to that command comes back
464 * we'll set it and be in the right mode.
465 */
466 if (ack)
467 localstat();
468 if (changed & MODE_EDIT)
469 tty_setedit(useeditmode & MODE_EDIT);
470
471 if (changed & MODE_TRAPSIG)
472 tty_setsig(useeditmode & MODE_TRAPSIG);
473
474 if (changed & MODE_SOFT_TAB)
475 tty_setsofttab(useeditmode & MODE_SOFT_TAB);
476
477 if (changed & MODE_LIT_ECHO)
478 tty_setlitecho(useeditmode & MODE_LIT_ECHO);
479
480 set_termbuf();
481
482 if (!ack) {
483 (void) sprintf(nfrontp, "%c%c%c%c%c%c%c", IAC,
484 SB, TELOPT_LINEMODE, LM_MODE,
485 useeditmode|MODE_ACK,
486 IAC, SE);
487 nfrontp += 7;
488 }
489
490 editmode = useeditmode;
491 }
492
493 break;
494
495 } /* end of case LM_MODE */
496 #endif /* LINEMODE */
497
498 case TELOPT_NAWS:
499 #ifdef TIOCSWINSZ
500 {
501 struct winsize ws;
502
503 def_col = parm1;
504 def_row = parm2;
505 #ifdef LINEMODE
506 /*
507 * Defer changing window size until after terminal is
508 * initialized.
509 */
510 if (terminit() == 0)
511 return;
512 #endif /* LINEMODE */
513
514 /*
515 * Change window size as requested by client.
516 */
517
518 ws.ws_col = parm1;
519 ws.ws_row = parm2;
520 (void) ioctl(pty, TIOCSWINSZ, (char *)&ws);
521 }
522 #endif /* TIOCSWINSZ */
523
524 break;
525
526 case TELOPT_TSPEED:
527 {
528 def_tspeed = parm1;
529 def_rspeed = parm2;
530 #ifdef LINEMODE
531 /*
532 * Defer changing the terminal speed.
533 */
534 if (terminit() == 0)
535 return;
536 #endif /* LINEMODE */
537 /*
538 * Change terminal speed as requested by client.
539 * We set the receive speed first, so that if we can't
540 * store seperate receive and transmit speeds, the transmit
541 * speed will take precedence.
542 */
543 tty_rspeed(parm2);
544 tty_tspeed(parm1);
545 set_termbuf();
546
547 break;
548
549 } /* end of case TELOPT_TSPEED */
550
551 default:
552 /* What? */
553 break;
554 } /* end of switch */
555
556 #if defined(CRAY2) && defined(UNICOS5)
557 /*
558 * Just in case of the likely event that we changed the pty state.
559 */
560 rcv_ioctl();
561 #endif /* defined(CRAY2) && defined(UNICOS5) */
562
563 netflush();
564
565 } /* end of clientstat */
566
567 #if defined(CRAY2) && defined(UNICOS5)
568 void
termstat()569 termstat()
570 {
571 needtermstat = 1;
572 }
573
574 void
_termstat()575 _termstat()
576 {
577 needtermstat = 0;
578 init_termbuf();
579 localstat();
580 rcv_ioctl();
581 }
582 #endif /* defined(CRAY2) && defined(UNICOS5) */
583
584 #ifdef LINEMODE
585 /*
586 * defer_terminit
587 *
588 * Some things should not be done until after the login process has started
589 * and all the pty modes are set to what they are supposed to be. This
590 * function is called when the pty state has been processed for the first time.
591 * It calls other functions that do things that were deferred in each module.
592 */
593 void
defer_terminit()594 defer_terminit()
595 {
596
597 /*
598 * local stuff that got deferred.
599 */
600 if (def_tspeed != -1) {
601 clientstat(TELOPT_TSPEED, def_tspeed, def_rspeed);
602 def_tspeed = def_rspeed = 0;
603 }
604
605 #ifdef TIOCSWINSZ
606 if (def_col || def_row) {
607 struct winsize ws;
608
609 memset((char *)&ws, 0, sizeof(ws));
610 ws.ws_col = def_col;
611 ws.ws_row = def_row;
612 (void) ioctl(pty, TIOCSWINSZ, (char *)&ws);
613 }
614 #endif
615
616 /*
617 * The only other module that currently defers anything.
618 */
619 deferslc();
620
621 } /* end of defer_terminit */
622
623 /*
624 * terminit
625 *
626 * Returns true if the pty state has been processed yet.
627 */
628 int
terminit()629 terminit()
630 {
631 return(_terminit);
632
633 } /* end of terminit */
634 #endif /* LINEMODE */
635