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