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