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