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