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.12 (Berkeley) 01/19/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 if (his_state_is_will(TELOPT_LFLOW)) { 143 if (tty_flowmode() != flowmode) { 144 flowmode = tty_flowmode(); 145 (void) sprintf(nfrontp, "%c%c%c%c%c%c", 146 IAC, SB, TELOPT_LFLOW, 147 flowmode ? LFLOW_ON : LFLOW_OFF, 148 IAC, SE); 149 nfrontp += 6; 150 } 151 if (tty_restartany() != restartany) { 152 restartany = tty_restartany(); 153 (void) sprintf(nfrontp, "%c%c%c%c%c%c", 154 IAC, SB, TELOPT_LFLOW, 155 restartany ? LFLOW_RESTART_ANY 156 : LFLOW_RESTART_XON, 157 IAC, SE); 158 nfrontp += 6; 159 } 160 } 161 162 /* 163 * Check linemode on/off state 164 */ 165 uselinemode = tty_linemode(); 166 167 /* 168 * If alwayslinemode is on, and pty is changing to turn it off, then 169 * force linemode back on. 170 */ 171 if (alwayslinemode && linemode && !uselinemode) { 172 uselinemode = 1; 173 tty_setlinemode(uselinemode); 174 } 175 176 #if defined(ENCRYPTION) 177 /* 178 * If the terminal is not echoing, but editing is enabled, 179 * something like password input is going to happen, so 180 * if we the other side is not currently sending encrypted 181 * data, ask the other side to start encrypting. 182 */ 183 if (his_state_is_will(TELOPT_ENCRYPT)) { 184 static int enc_passwd = 0; 185 if (uselinemode && !tty_isecho() && tty_isediting() 186 && (enc_passwd == 0) && !decrypt_input) { 187 encrypt_send_request_start(); 188 enc_passwd = 1; 189 } else if (enc_passwd) { 190 encrypt_send_request_end(); 191 enc_passwd = 0; 192 } 193 } 194 #endif 195 196 /* 197 * Do echo mode handling as soon as we know what the 198 * linemode is going to be. 199 * If the pty has echo turned off, then tell the client that 200 * the server will echo. If echo is on, then the server 201 * will echo if in character mode, but in linemode the 202 * client should do local echoing. The state machine will 203 * not send anything if it is unnecessary, so don't worry 204 * about that here. 205 * 206 * If we need to send the WILL ECHO (because echo is off), 207 * then delay that until after we have changed the MODE. 208 * This way, when the user is turning off both editing 209 * and echo, the client will get editing turned off first. 210 * This keeps the client from going into encryption mode 211 * and then right back out if it is doing auto-encryption 212 * when passwords are being typed. 213 */ 214 if (uselinemode) { 215 if (tty_isecho()) 216 send_wont(TELOPT_ECHO, 1); 217 else 218 need_will_echo = 1; 219 #ifdef KLUDGELINEMODE 220 if (lmodetype == KLUDGE_OK) 221 lmodetype = KLUDGE_LINEMODE; 222 #endif 223 } 224 225 /* 226 * If linemode is being turned off, send appropriate 227 * command and then we're all done. 228 */ 229 if (!uselinemode && linemode) { 230 # ifdef KLUDGELINEMODE 231 if (lmodetype == REAL_LINEMODE) { 232 # endif /* KLUDGELINEMODE */ 233 send_dont(TELOPT_LINEMODE, 1); 234 # ifdef KLUDGELINEMODE 235 } else if (lmodetype == KLUDGE_LINEMODE) 236 send_will(TELOPT_SGA, 1); 237 # endif /* KLUDGELINEMODE */ 238 send_will(TELOPT_ECHO, 1); 239 linemode = uselinemode; 240 goto done; 241 } 242 243 # ifdef KLUDGELINEMODE 244 /* 245 * If using real linemode check edit modes for possible later use. 246 * If we are in kludge linemode, do the SGA negotiation. 247 */ 248 if (lmodetype == REAL_LINEMODE) { 249 # endif /* KLUDGELINEMODE */ 250 useeditmode = 0; 251 if (tty_isediting()) 252 useeditmode |= MODE_EDIT; 253 if (tty_istrapsig()) 254 useeditmode |= MODE_TRAPSIG; 255 if (tty_issofttab()) 256 useeditmode |= MODE_SOFT_TAB; 257 if (tty_islitecho()) 258 useeditmode |= MODE_LIT_ECHO; 259 # ifdef KLUDGELINEMODE 260 } else if (lmodetype == KLUDGE_LINEMODE) { 261 if (tty_isediting() && uselinemode) 262 send_wont(TELOPT_SGA, 1); 263 else 264 send_will(TELOPT_SGA, 1); 265 } 266 # endif /* KLUDGELINEMODE */ 267 268 /* 269 * Negotiate linemode on if pty state has changed to turn it on. 270 * Send appropriate command and send along edit mode, then all done. 271 */ 272 if (uselinemode && !linemode) { 273 # ifdef KLUDGELINEMODE 274 if (lmodetype == KLUDGE_LINEMODE) { 275 send_wont(TELOPT_SGA, 1); 276 } else if (lmodetype == REAL_LINEMODE) { 277 # endif /* KLUDGELINEMODE */ 278 send_do(TELOPT_LINEMODE, 1); 279 /* send along edit modes */ 280 (void) sprintf(nfrontp, "%c%c%c%c%c%c%c", IAC, SB, 281 TELOPT_LINEMODE, LM_MODE, useeditmode, 282 IAC, SE); 283 nfrontp += 7; 284 editmode = useeditmode; 285 # ifdef KLUDGELINEMODE 286 } 287 # endif /* KLUDGELINEMODE */ 288 linemode = uselinemode; 289 goto done; 290 } 291 292 # ifdef KLUDGELINEMODE 293 /* 294 * None of what follows is of any value if not using 295 * real linemode. 296 */ 297 if (lmodetype < REAL_LINEMODE) 298 goto done; 299 # endif /* KLUDGELINEMODE */ 300 301 if (linemode && his_state_is_will(TELOPT_LINEMODE)) { 302 /* 303 * If edit mode changed, send edit mode. 304 */ 305 if (useeditmode != editmode) { 306 /* 307 * Send along appropriate edit mode mask. 308 */ 309 (void) sprintf(nfrontp, "%c%c%c%c%c%c%c", IAC, SB, 310 TELOPT_LINEMODE, LM_MODE, useeditmode, 311 IAC, SE); 312 nfrontp += 7; 313 editmode = useeditmode; 314 } 315 316 317 /* 318 * Check for changes to special characters in use. 319 */ 320 start_slc(0); 321 check_slc(); 322 (void) end_slc(0); 323 } 324 325 done: 326 if (need_will_echo) 327 send_will(TELOPT_ECHO, 1); 328 /* 329 * Some things should be deferred until after the pty state has 330 * been set by the local process. Do those things that have been 331 * deferred now. This only happens once. 332 */ 333 if (_terminit == 0) { 334 _terminit = 1; 335 defer_terminit(); 336 } 337 338 netflush(); 339 set_termbuf(); 340 return; 341 342 } /* end of localstat */ 343 #endif /* LINEMODE */ 344 345 346 /* 347 * clientstat 348 * 349 * Process linemode related requests from the client. 350 * Client can request a change to only one of linemode, editmode or slc's 351 * at a time, and if using kludge linemode, then only linemode may be 352 * affected. 353 */ 354 void 355 clientstat(code, parm1, parm2) 356 register int code, parm1, parm2; 357 { 358 void netflush(); 359 360 /* 361 * Get a copy of terminal characteristics. 362 */ 363 init_termbuf(); 364 365 /* 366 * Process request from client. code tells what it is. 367 */ 368 switch (code) { 369 #ifdef LINEMODE 370 case TELOPT_LINEMODE: 371 /* 372 * Don't do anything unless client is asking us to change 373 * modes. 374 */ 375 uselinemode = (parm1 == WILL); 376 if (uselinemode != linemode) { 377 # ifdef KLUDGELINEMODE 378 /* 379 * If using kludge linemode, make sure that 380 * we can do what the client asks. 381 * We can not turn off linemode if alwayslinemode 382 * and the ICANON bit is set. 383 */ 384 if (lmodetype == KLUDGE_LINEMODE) { 385 if (alwayslinemode && tty_isediting()) { 386 uselinemode = 1; 387 } 388 } 389 390 /* 391 * Quit now if we can't do it. 392 */ 393 if (uselinemode == linemode) 394 return; 395 396 /* 397 * If using real linemode and linemode is being 398 * turned on, send along the edit mode mask. 399 */ 400 if (lmodetype == REAL_LINEMODE && uselinemode) 401 # else /* KLUDGELINEMODE */ 402 if (uselinemode) 403 # endif /* KLUDGELINEMODE */ 404 { 405 useeditmode = 0; 406 if (tty_isediting()) 407 useeditmode |= MODE_EDIT; 408 if (tty_istrapsig) 409 useeditmode |= MODE_TRAPSIG; 410 if (tty_issofttab()) 411 useeditmode |= MODE_SOFT_TAB; 412 if (tty_islitecho()) 413 useeditmode |= MODE_LIT_ECHO; 414 (void) sprintf(nfrontp, "%c%c%c%c%c%c%c", IAC, 415 SB, TELOPT_LINEMODE, LM_MODE, 416 useeditmode, IAC, SE); 417 nfrontp += 7; 418 editmode = useeditmode; 419 } 420 421 422 tty_setlinemode(uselinemode); 423 424 linemode = uselinemode; 425 426 if (!linemode) 427 send_will(TELOPT_ECHO, 1); 428 } 429 break; 430 431 case LM_MODE: 432 { 433 register int ack, changed; 434 435 /* 436 * Client has sent along a mode mask. If it agrees with 437 * what we are currently doing, ignore it; if not, it could 438 * be viewed as a request to change. Note that the server 439 * will change to the modes in an ack if it is different from 440 * what we currently have, but we will not ack the ack. 441 */ 442 useeditmode &= MODE_MASK; 443 ack = (useeditmode & MODE_ACK); 444 useeditmode &= ~MODE_ACK; 445 446 if (changed = (useeditmode ^ editmode)) { 447 /* 448 * This check is for a timing problem. If the 449 * state of the tty has changed (due to the user 450 * application) we need to process that info 451 * before we write in the state contained in the 452 * ack!!! This gets out the new MODE request, 453 * and when the ack to that command comes back 454 * we'll set it and be in the right mode. 455 */ 456 if (ack) 457 localstat(); 458 if (changed & MODE_EDIT) 459 tty_setedit(useeditmode & MODE_EDIT); 460 461 if (changed & MODE_TRAPSIG) 462 tty_setsig(useeditmode & MODE_TRAPSIG); 463 464 if (changed & MODE_SOFT_TAB) 465 tty_setsofttab(useeditmode & MODE_SOFT_TAB); 466 467 if (changed & MODE_LIT_ECHO) 468 tty_setlitecho(useeditmode & MODE_LIT_ECHO); 469 470 set_termbuf(); 471 472 if (!ack) { 473 (void) sprintf(nfrontp, "%c%c%c%c%c%c%c", IAC, 474 SB, TELOPT_LINEMODE, LM_MODE, 475 useeditmode|MODE_ACK, 476 IAC, SE); 477 nfrontp += 7; 478 } 479 480 editmode = useeditmode; 481 } 482 483 break; 484 485 } /* end of case LM_MODE */ 486 #endif /* LINEMODE */ 487 488 case TELOPT_NAWS: 489 #ifdef TIOCSWINSZ 490 { 491 struct winsize ws; 492 493 def_col = parm1; 494 def_row = parm2; 495 #ifdef LINEMODE 496 /* 497 * Defer changing window size until after terminal is 498 * initialized. 499 */ 500 if (terminit() == 0) 501 return; 502 #endif /* LINEMODE */ 503 504 /* 505 * Change window size as requested by client. 506 */ 507 508 ws.ws_col = parm1; 509 ws.ws_row = parm2; 510 (void) ioctl(pty, TIOCSWINSZ, (char *)&ws); 511 } 512 #endif /* TIOCSWINSZ */ 513 514 break; 515 516 case TELOPT_TSPEED: 517 { 518 def_tspeed = parm1; 519 def_rspeed = parm2; 520 #ifdef LINEMODE 521 /* 522 * Defer changing the terminal speed. 523 */ 524 if (terminit() == 0) 525 return; 526 #endif /* LINEMODE */ 527 /* 528 * Change terminal speed as requested by client. 529 * We set the receive speed first, so that if we can't 530 * store seperate receive and transmit speeds, the transmit 531 * speed will take precedence. 532 */ 533 tty_rspeed(parm2); 534 tty_tspeed(parm1); 535 set_termbuf(); 536 537 break; 538 539 } /* end of case TELOPT_TSPEED */ 540 541 default: 542 /* What? */ 543 break; 544 } /* end of switch */ 545 546 #if defined(CRAY2) && defined(UNICOS5) 547 /* 548 * Just in case of the likely event that we changed the pty state. 549 */ 550 rcv_ioctl(); 551 #endif /* defined(CRAY2) && defined(UNICOS5) */ 552 553 netflush(); 554 555 } /* end of clientstat */ 556 557 #if defined(CRAY2) && defined(UNICOS5) 558 void 559 termstat() 560 { 561 needtermstat = 1; 562 } 563 564 void 565 _termstat() 566 { 567 needtermstat = 0; 568 init_termbuf(); 569 localstat(); 570 rcv_ioctl(); 571 } 572 #endif /* defined(CRAY2) && defined(UNICOS5) */ 573 574 #ifdef LINEMODE 575 /* 576 * defer_terminit 577 * 578 * Some things should not be done until after the login process has started 579 * and all the pty modes are set to what they are supposed to be. This 580 * function is called when the pty state has been processed for the first time. 581 * It calls other functions that do things that were deferred in each module. 582 */ 583 void 584 defer_terminit() 585 { 586 587 /* 588 * local stuff that got deferred. 589 */ 590 if (def_tspeed != -1) { 591 clientstat(TELOPT_TSPEED, def_tspeed, def_rspeed); 592 def_tspeed = def_rspeed = 0; 593 } 594 595 #ifdef TIOCSWINSZ 596 if (def_col || def_row) { 597 struct winsize ws; 598 599 bzero((char *)&ws, sizeof(ws)); 600 ws.ws_col = def_col; 601 ws.ws_row = def_row; 602 (void) ioctl(pty, TIOCSWINSZ, (char *)&ws); 603 } 604 #endif 605 606 /* 607 * The only other module that currently defers anything. 608 */ 609 deferslc(); 610 611 } /* end of defer_terminit */ 612 613 /* 614 * terminit 615 * 616 * Returns true if the pty state has been processed yet. 617 */ 618 int 619 terminit() 620 { 621 return(_terminit); 622 623 } /* end of terminit */ 624 #endif /* LINEMODE */ 625