1 /* 2 * Copyright (c) 1989 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)termstat.c 5.14 (Berkeley) 05/20/93"; 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 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 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 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 569 termstat() 570 { 571 needtermstat = 1; 572 } 573 574 void 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 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 bzero((char *)&ws, 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 629 terminit() 630 { 631 return(_terminit); 632 633 } /* end of terminit */ 634 #endif /* LINEMODE */ 635