|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1989 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms are permitted provided ! 6: * that: (1) source distributions retain this entire copyright notice and ! 7: * comment, and (2) distributions including binaries display the following ! 8: * acknowledgement: ``This product includes software developed by the ! 9: * University of California, Berkeley and its contributors'' in the ! 10: * documentation or other materials provided with the distribution and in ! 11: * all advertising materials mentioning features or use of this software. ! 12: * Neither the name of the University nor the names of its contributors may ! 13: * be used to endorse or promote products derived from this software without ! 14: * specific prior written permission. ! 15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 16: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 17: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 18: */ ! 19: ! 20: #ifndef lint ! 21: static char sccsid[] = "@(#)termstat.c 5.6 (Berkeley) 6/28/90"; ! 22: #endif /* not lint */ ! 23: ! 24: #include "telnetd.h" ! 25: ! 26: /* ! 27: * local variables ! 28: */ ! 29: #ifdef LINEMODE ! 30: static int _terminit = 0; ! 31: static int def_tspeed = -1, def_rspeed = -1; ! 32: #ifdef TIOCSWINSZ ! 33: static int def_row = 0, def_col = 0; ! 34: #endif ! 35: #endif LINEMODE ! 36: ! 37: #if defined(CRAY2) && defined(UNICOS5) ! 38: int newmap = 1; /* nonzero if \n maps to ^M^J */ ! 39: #endif ! 40: ! 41: #ifdef LINEMODE ! 42: /* ! 43: * localstat ! 44: * ! 45: * This function handles all management of linemode. ! 46: * ! 47: * Linemode allows the client to do the local editing of data ! 48: * and send only complete lines to the server. Linemode state is ! 49: * based on the state of the pty driver. If the pty is set for ! 50: * external processing, then we can use linemode. Further, if we ! 51: * can use real linemode, then we can look at the edit control bits ! 52: * in the pty to determine what editing the client should do. ! 53: * ! 54: * Linemode support uses the following state flags to keep track of ! 55: * current and desired linemode state. ! 56: * alwayslinemode : true if -l was specified on the telnetd ! 57: * command line. It means to have linemode on as much as ! 58: * possible. ! 59: * ! 60: * lmodetype: signifies whether the client can ! 61: * handle real linemode, or if use of kludgeomatic linemode ! 62: * is preferred. It will be set to one of the following: ! 63: * REAL_LINEMODE : use linemode option ! 64: * KLUDGE_LINEMODE : use kludge linemode ! 65: * NO_LINEMODE : client is ignorant of linemode ! 66: * ! 67: * linemode, uselinemode : linemode is true if linemode ! 68: * is currently on, uselinemode is the state that we wish ! 69: * to be in. If another function wishes to turn linemode ! 70: * on or off, it sets or clears uselinemode. ! 71: * ! 72: * editmode, useeditmode : like linemode/uselinemode, but ! 73: * these contain the edit mode states (edit and trapsig). ! 74: * ! 75: * The state variables correspond to some of the state information ! 76: * in the pty. ! 77: * linemode: ! 78: * In real linemode, this corresponds to whether the pty ! 79: * expects external processing of incoming data. ! 80: * In kludge linemode, this more closely corresponds to the ! 81: * whether normal processing is on or not. (ICANON in ! 82: * system V, or COOKED mode in BSD.) ! 83: * If the -l option was specified (alwayslinemode), then ! 84: * an attempt is made to force external processing on at ! 85: * all times. ! 86: * ! 87: * The following heuristics are applied to determine linemode ! 88: * handling within the server. ! 89: * 1) Early on in starting up the server, an attempt is made ! 90: * to negotiate the linemode option. If this succeeds ! 91: * then lmodetype is set to REAL_LINEMODE and all linemode ! 92: * processing occurs in the context of the linemode option. ! 93: * 2) If the attempt to negotiate the linemode option failed, ! 94: * then we try to use kludge linemode. We test for this ! 95: * capability by sending "do Timing Mark". If a positive ! 96: * response comes back, then we assume that the client ! 97: * understands kludge linemode (ech!) and the ! 98: * lmodetype flag is set to KLUDGE_LINEMODE. ! 99: * 3) Otherwise, linemode is not supported at all and ! 100: * lmodetype remains set to NO_LINEMODE (which happens ! 101: * to be 0 for convenience). ! 102: * 4) At any time a command arrives that implies a higher ! 103: * state of linemode support in the client, we move to that ! 104: * linemode support. ! 105: * ! 106: * A short explanation of kludge linemode is in order here. ! 107: * 1) The heuristic to determine support for kludge linemode ! 108: * is to send a do timing mark. We assume that a client ! 109: * that supports timing marks also supports kludge linemode. ! 110: * A risky proposition at best. ! 111: * 2) Further negotiation of linemode is done by changing the ! 112: * the server's state regarding SGA. If server will SGA, ! 113: * then linemode is off, if server won't SGA, then linemode ! 114: * is on. ! 115: */ ! 116: localstat() ! 117: { ! 118: void netflush(); ! 119: ! 120: #if defined(CRAY2) && defined(UNICOS5) ! 121: /* ! 122: * Keep track of that ol' CR/NL mapping while we're in the ! 123: * neighborhood. ! 124: */ ! 125: newmap = tty_isnewmap(); ! 126: #endif defined(CRAY2) && defined(UNICOS5) ! 127: ! 128: /* ! 129: * Check for state of BINARY options. ! 130: */ ! 131: if (tty_isbinaryin()) { ! 132: if (his_want_state_is_wont(TELOPT_BINARY)) ! 133: send_do(TELOPT_BINARY, 1); ! 134: } else { ! 135: if (his_want_state_is_will(TELOPT_BINARY)) ! 136: send_dont(TELOPT_BINARY, 1); ! 137: } ! 138: ! 139: if (tty_isbinaryout()) { ! 140: if (my_want_state_is_wont(TELOPT_BINARY)) ! 141: send_will(TELOPT_BINARY, 1); ! 142: } else { ! 143: if (my_want_state_is_will(TELOPT_BINARY)) ! 144: send_wont(TELOPT_BINARY, 1); ! 145: } ! 146: ! 147: /* ! 148: * Check for changes to flow control if client supports it. ! 149: */ ! 150: if (his_state_is_will(TELOPT_LFLOW)) { ! 151: if (tty_flowmode() != flowmode) { ! 152: flowmode = tty_flowmode(); ! 153: (void) sprintf(nfrontp, "%c%c%c%c%c%c", IAC, SB, ! 154: TELOPT_LFLOW, flowmode, IAC, SE); ! 155: nfrontp += 6; ! 156: } ! 157: } ! 158: ! 159: /* ! 160: * Check linemode on/off state ! 161: */ ! 162: uselinemode = tty_linemode(); ! 163: ! 164: /* ! 165: * If alwayslinemode is on, and pty is changing to turn it off, then ! 166: * force linemode back on. ! 167: */ ! 168: if (alwayslinemode && linemode && !uselinemode) { ! 169: uselinemode = 1; ! 170: tty_setlinemode(uselinemode); ! 171: } ! 172: ! 173: /* ! 174: * Do echo mode handling as soon as we know what the ! 175: * linemode is going to be. ! 176: * If the pty has echo turned off, then tell the client that ! 177: * the server will echo. If echo is on, then the server ! 178: * will echo if in character mode, but in linemode the ! 179: * client should do local echoing. The state machine will ! 180: * not send anything if it is unnecessary, so don't worry ! 181: * about that here. ! 182: */ ! 183: if (tty_isecho() && uselinemode) ! 184: send_wont(TELOPT_ECHO, 1); ! 185: else ! 186: send_will(TELOPT_ECHO, 1); ! 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: linemode = uselinemode; ! 202: goto done; ! 203: } ! 204: ! 205: # ifdef KLUDGELINEMODE ! 206: /* ! 207: * If using real linemode check edit modes for possible later use. ! 208: * If we are in kludge linemode, do the SGA negotiation. ! 209: */ ! 210: if (lmodetype == REAL_LINEMODE) { ! 211: # endif /* KLUDGELINEMODE */ ! 212: useeditmode = 0; ! 213: if (tty_isediting()) ! 214: useeditmode |= MODE_EDIT; ! 215: if (tty_istrapsig()) ! 216: useeditmode |= MODE_TRAPSIG; ! 217: if (tty_issofttab()) ! 218: useeditmode |= MODE_SOFT_TAB; ! 219: if (tty_islitecho()) ! 220: useeditmode |= MODE_LIT_ECHO; ! 221: # ifdef KLUDGELINEMODE ! 222: } else if (lmodetype == KLUDGE_LINEMODE) { ! 223: if (tty_isediting() && uselinemode) ! 224: send_wont(TELOPT_SGA, 1); ! 225: else ! 226: send_will(TELOPT_SGA, 1); ! 227: } ! 228: # endif /* KLUDGELINEMODE */ ! 229: ! 230: /* ! 231: * Negotiate linemode on if pty state has changed to turn it on. ! 232: * Send appropriate command and send along edit mode, then all done. ! 233: */ ! 234: if (uselinemode && !linemode) { ! 235: # ifdef KLUDGELINEMODE ! 236: if (lmodetype == KLUDGE_LINEMODE) { ! 237: send_wont(TELOPT_SGA, 1); ! 238: } else if (lmodetype == REAL_LINEMODE) { ! 239: # endif /* KLUDGELINEMODE */ ! 240: send_do(TELOPT_LINEMODE, 1); ! 241: /* send along edit modes */ ! 242: (void) sprintf(nfrontp, "%c%c%c%c%c%c%c", IAC, SB, ! 243: TELOPT_LINEMODE, LM_MODE, useeditmode, ! 244: IAC, SE); ! 245: nfrontp += 7; ! 246: editmode = useeditmode; ! 247: # ifdef KLUDGELINEMODE ! 248: } ! 249: # endif /* KLUDGELINEMODE */ ! 250: linemode = uselinemode; ! 251: goto done; ! 252: } ! 253: ! 254: # ifdef KLUDGELINEMODE ! 255: /* ! 256: * None of what follows is of any value if not using ! 257: * real linemode. ! 258: */ ! 259: if (lmodetype < REAL_LINEMODE) ! 260: goto done; ! 261: # endif /* KLUDGELINEMODE */ ! 262: ! 263: if (linemode) { ! 264: /* ! 265: * If edit mode changed, send edit mode. ! 266: */ ! 267: if (useeditmode != editmode) { ! 268: /* ! 269: * Send along appropriate edit mode mask. ! 270: */ ! 271: (void) sprintf(nfrontp, "%c%c%c%c%c%c%c", IAC, SB, ! 272: TELOPT_LINEMODE, LM_MODE, useeditmode, ! 273: IAC, SE); ! 274: nfrontp += 7; ! 275: editmode = useeditmode; ! 276: } ! 277: ! 278: ! 279: /* ! 280: * Check for changes to special characters in use. ! 281: */ ! 282: start_slc(0); ! 283: check_slc(); ! 284: end_slc(0); ! 285: } ! 286: ! 287: done: ! 288: /* ! 289: * Some things should be deferred until after the pty state has ! 290: * been set by the local process. Do those things that have been ! 291: * deferred now. This only happens once. ! 292: */ ! 293: if (_terminit == 0) { ! 294: _terminit = 1; ! 295: defer_terminit(); ! 296: } ! 297: ! 298: netflush(); ! 299: set_termbuf(); ! 300: return; ! 301: ! 302: } /* end of localstat */ ! 303: #endif /* LINEMODE */ ! 304: ! 305: ! 306: /* ! 307: * clientstat ! 308: * ! 309: * Process linemode related requests from the client. ! 310: * Client can request a change to only one of linemode, editmode or slc's ! 311: * at a time, and if using kludge linemode, then only linemode may be ! 312: * affected. ! 313: */ ! 314: clientstat(code, parm1, parm2) ! 315: register int code, parm1, parm2; ! 316: { ! 317: void netflush(); ! 318: ! 319: /* ! 320: * Get a copy of terminal characteristics. ! 321: */ ! 322: init_termbuf(); ! 323: ! 324: /* ! 325: * Process request from client. code tells what it is. ! 326: */ ! 327: switch (code) { ! 328: #ifdef LINEMODE ! 329: case TELOPT_LINEMODE: ! 330: /* ! 331: * Don't do anything unless client is asking us to change ! 332: * modes. ! 333: */ ! 334: uselinemode = (parm1 == WILL); ! 335: if (uselinemode != linemode) { ! 336: # ifdef KLUDGELINEMODE ! 337: /* ! 338: * If using kludge linemode, make sure that ! 339: * we can do what the client asks. ! 340: * We can not turn off linemode if alwayslinemode ! 341: * and the ICANON bit is set. ! 342: */ ! 343: if (lmodetype == KLUDGE_LINEMODE) { ! 344: if (alwayslinemode && tty_isediting()) { ! 345: uselinemode = 1; ! 346: } ! 347: } ! 348: ! 349: /* ! 350: * Quit now if we can't do it. ! 351: */ ! 352: if (uselinemode == linemode) ! 353: return; ! 354: ! 355: /* ! 356: * If using real linemode and linemode is being ! 357: * turned on, send along the edit mode mask. ! 358: */ ! 359: if (lmodetype == REAL_LINEMODE && uselinemode) ! 360: # else /* KLUDGELINEMODE */ ! 361: if (uselinemode) ! 362: # endif /* KLUDGELINEMODE */ ! 363: { ! 364: useeditmode = 0; ! 365: if (tty_isediting()) ! 366: useeditmode |= MODE_EDIT; ! 367: if (tty_istrapsig) ! 368: useeditmode |= MODE_TRAPSIG; ! 369: if (tty_issofttab()) ! 370: useeditmode |= MODE_SOFT_TAB; ! 371: if (tty_islitecho()) ! 372: useeditmode |= MODE_LIT_ECHO; ! 373: (void) sprintf(nfrontp, "%c%c%c%c%c%c%c", IAC, ! 374: SB, TELOPT_LINEMODE, LM_MODE, ! 375: useeditmode, IAC, SE); ! 376: nfrontp += 7; ! 377: editmode = useeditmode; ! 378: } ! 379: ! 380: ! 381: tty_setlinemode(uselinemode); ! 382: ! 383: linemode = uselinemode; ! 384: ! 385: } ! 386: break; ! 387: ! 388: case LM_MODE: ! 389: { ! 390: register int ack, changed; ! 391: ! 392: /* ! 393: * Client has sent along a mode mask. If it agrees with ! 394: * what we are currently doing, ignore it; if not, it could ! 395: * be viewed as a request to change. Note that the server ! 396: * will change to the modes in an ack if it is different from ! 397: * what we currently have, but we will not ack the ack. ! 398: */ ! 399: useeditmode &= MODE_MASK; ! 400: ack = (useeditmode & MODE_ACK); ! 401: useeditmode &= ~MODE_ACK; ! 402: ! 403: if (changed = (useeditmode ^ editmode)) { ! 404: if (changed & MODE_EDIT) ! 405: tty_setedit(useeditmode & MODE_EDIT); ! 406: ! 407: if (changed & MODE_TRAPSIG) ! 408: tty_setsig(useeditmode & MODE_TRAPSIG); ! 409: ! 410: if (changed & MODE_SOFT_TAB) ! 411: tty_setsofttab(useeditmode & MODE_SOFT_TAB); ! 412: ! 413: if (changed & MODE_LIT_ECHO) ! 414: tty_setlitecho(useeditmode & MODE_LIT_ECHO); ! 415: ! 416: set_termbuf(); ! 417: ! 418: if (!ack) { ! 419: (void) sprintf(nfrontp, "%c%c%c%c%c%c%c", IAC, ! 420: SB, TELOPT_LINEMODE, LM_MODE, ! 421: useeditmode|MODE_ACK, ! 422: IAC, SE); ! 423: nfrontp += 7; ! 424: } ! 425: ! 426: editmode = useeditmode; ! 427: } ! 428: ! 429: break; ! 430: ! 431: } /* end of case LM_MODE */ ! 432: #endif /* LINEMODE */ ! 433: ! 434: case TELOPT_NAWS: ! 435: #ifdef TIOCSWINSZ ! 436: { ! 437: struct winsize ws; ! 438: ! 439: #ifdef LINEMODE ! 440: /* ! 441: * Defer changing window size until after terminal is ! 442: * initialized. ! 443: */ ! 444: if (terminit() == 0) { ! 445: def_col = parm1; ! 446: def_row = parm2; ! 447: return; ! 448: } ! 449: #endif /* LINEMODE */ ! 450: ! 451: /* ! 452: * Change window size as requested by client. ! 453: */ ! 454: ! 455: ws.ws_col = parm1; ! 456: ws.ws_row = parm2; ! 457: (void) ioctl(pty, TIOCSWINSZ, (char *)&ws); ! 458: } ! 459: #endif /* TIOCSWINSZ */ ! 460: ! 461: break; ! 462: ! 463: case TELOPT_TSPEED: ! 464: { ! 465: #ifdef LINEMODE ! 466: /* ! 467: * Defer changing the terminal speed. ! 468: */ ! 469: if (terminit() == 0) { ! 470: def_tspeed = parm1; ! 471: def_rspeed = parm2; ! 472: return; ! 473: } ! 474: #endif /* LINEMODE */ ! 475: /* ! 476: * Change terminal speed as requested by client. ! 477: */ ! 478: tty_tspeed(parm1); ! 479: tty_rspeed(parm2); ! 480: set_termbuf(); ! 481: ! 482: break; ! 483: ! 484: } /* end of case TELOPT_TSPEED */ ! 485: ! 486: default: ! 487: /* What? */ ! 488: break; ! 489: } /* end of switch */ ! 490: ! 491: #if defined(CRAY2) && defined(UNICOS5) ! 492: /* ! 493: * Just in case of the likely event that we changed the pty state. ! 494: */ ! 495: rcv_ioctl(); ! 496: #endif /* defined(CRAY2) && defined(UNICOS5) */ ! 497: ! 498: netflush(); ! 499: ! 500: } /* end of clientstat */ ! 501: ! 502: #if defined(CRAY2) && defined(UNICOS5) ! 503: termstat() ! 504: { ! 505: needtermstat = 1; ! 506: } ! 507: ! 508: _termstat() ! 509: { ! 510: needtermstat = 0; ! 511: init_termbuf(); ! 512: localstat(); ! 513: rcv_ioctl(); ! 514: } ! 515: #endif /* defined(CRAY2) && defined(UNICOS5) */ ! 516: ! 517: #ifdef LINEMODE ! 518: /* ! 519: * defer_terminit ! 520: * ! 521: * Some things should not be done until after the login process has started ! 522: * and all the pty modes are set to what they are supposed to be. This ! 523: * function is called when the pty state has been processed for the first time. ! 524: * It calls other functions that do things that were deferred in each module. ! 525: */ ! 526: defer_terminit() ! 527: { ! 528: ! 529: /* ! 530: * local stuff that got deferred. ! 531: */ ! 532: if (def_tspeed != -1) { ! 533: clientstat(TELOPT_TSPEED, def_tspeed, def_rspeed); ! 534: def_tspeed = def_rspeed = 0; ! 535: } ! 536: ! 537: #ifdef TIOCSWINSZ ! 538: if (def_col || def_row) { ! 539: struct winsize ws; ! 540: ! 541: ws.ws_col = def_col; ! 542: ws.ws_row = def_row; ! 543: (void) ioctl(pty, TIOCSWINSZ, (char *)&ws); ! 544: } ! 545: #endif ! 546: ! 547: /* ! 548: * The only other module that currently defers anything. ! 549: */ ! 550: deferslc(); ! 551: ! 552: } /* end of defer_terminit */ ! 553: ! 554: /* ! 555: * terminit ! 556: * ! 557: * Returns true if the pty state has been processed yet. ! 558: */ ! 559: int terminit() ! 560: { ! 561: return _terminit; ! 562: ! 563: } /* end of terminit */ ! 564: #endif /* LINEMODE */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.