📄 telnetlib.c
字号:
if (telnetOutTaskId != ERROR) taskDelete (telnetOutTaskId); telnetdExit (FALSE); /* try to do a tidy clean-up */ } } }/********************************************************************************* telnetOutTask - stdout to socket process** This routine gets spawned by the telnet daemon to move data between the* client socket and the pseudo-terminal. The created task is deleted* when the client disconnects.** NOMANUAL* but not LOCAL for i()*/void telnetOutTask ( FAST int sock, /* socket to copy output to */ FAST int ptyMfd /* pty Master fd */ ) { FAST int n; char buf [STDOUT_BUF_SIZE]; while ((n = read (ptyMfd, buf, sizeof (buf))) > 0) { /* XXX should scan for IAC and double 'em to escape 'em */ write (sock, buf, n); } }/********************************************************************************* telnetInTask - socket to stdin process** This routine gets spawned by the telnet daemon to move data between the* pseudo-terminal and the client socket. The task exits, calling* telnetdExit(), when the client disconnects.** RETURNS: N/A.** NOMANUAL* but not LOCAL for i()*/void telnetInTask ( FAST int sock, /* socket to copy input from */ int ptyMfd /* pty Master fd */ ) { int n; int state = TS_DATA; char buf [STDIN_BUF_SIZE]; cleanupFlag = FALSE; /* exit cleanup has not been done... */ /* Loop, reading from the socket and writing to the pty. */ while ((n = read (sock, buf, sizeof (buf))) > 0) state = tnInput (state, sock, ptyMfd, buf, n); /* Exit and cleanup. The above loop will exit when the socket is * closed. The socket can be closed as a result of the connection * terminating from the remote host, or as a result of the logout() * command issued to our shell. When the logout() command is used, * the telnetdExit() routine below is called and the socket is explicitly * closed. In this case, there is no need to call telnetdExit() again. * We use the cleanupFlag to determine this case. To summarize, if the * cleanupFlag is set, we are here because the connection was terminated * remotely and cleanup is required. */ if (!cleanupFlag) telnetdExit (FALSE); }/********************************************************************************* telnetdExit - exit and cleanup routine for telnetd()** This is the support routine for logout(). The client socket is closed,* shell standard I/O is redirected back to the console, and the shell is* restarted by sending an EOF.** RETURNS: N/A.*/LOCAL void telnetdExit ( BOOL usedLogout /* true if called from logout() */ ) { /* This routine is called either as a result of the logout() command * being issued from the shell, or from the telnetInTask above. It is * therefore run in the context of the shell or telnetInTask. The * caller indicates itself to us by the usedLogout argument. The * state of this argument affects our behavior, as explained below. */ cleanupFlag = TRUE; /* release telnetInTask() from duty */ shellLogoutInstall ((FUNCPTR) NULL, 0); /* uninstall logout function */ if (logFdFromRlogin != NONE) { logFdDelete (logFdFromRlogin); /* cancel extra log device */ logFdFromRlogin = NONE; /* reset fd */ } shellOrigStdSet (STD_IN, shellInFd); /* restore shell's stnd I/O */ shellOrigStdSet (STD_OUT, shellOutFd); shellOrigStdSet (STD_ERR, shellErrFd); shellLock (FALSE); /* unlock shell */ write (telnetdSocket, "\n", 1); close (telnetdSocket); /* close the socket */ /* For typical remote sessions, there is no need to restart the shell. * If we are in shell context, simply restoring the standard I/O * descriptors is enough to get the shell back on track upon return * from this function. If we are in telnetInTask context, the closing * of the pty device will cause the shell to unblock from its read() * and do subsequent I/O from the restored descriptors. * However, problems can occur upon logout if the remote user has * disabled the line editor and/or put the pty device in raw mode. * The problem caused is that the shell does not resume properly. * It is therefore deemed prudent to always restart the shell, thereby * avoiding any funny business. * * The previous version attempted to send a ctrl-D up the pty device * to wakeup and restart the shell. Unfortunately, ctrl-D only has * special meaning when the device is in line mode, and hence did * not work in raw mode. * * The pty device is closed after the shell is restarted, when called * from telnetInTask, to avoid waking the existing shell and causing an * additional prompt to appear on the console. */ if (usedLogout) /* called from shell */ { close (telnetdM); close (telnetdS); activeFlag = FALSE; /* allow new connection */ taskRestart (0); /* never returns */ } else /* called from telnetInTask */ { excJobAdd (shellRestart, FALSE, 0, 0, 0, 0, 0); close (telnetdM); close (telnetdS); activeFlag = FALSE; /* allow new connection */ } }/********************************************************************************* tnInput - process input from remote** RETURNS: state*/LOCAL int tnInput ( FAST int state, /* state of input stream */ FAST int remFd, /* fd of socket to otherside */ FAST int ptyFd, /* fd of pty to this side */ FAST char *buf, /* ptr to input chars */ FAST int n /* number of chars input */ ) { char cc; int ci; while (--n >= 0) { cc = *buf++; /* get next character */ ci = (unsigned char) cc; /* convert to int since many values * are negative characters */ switch (state) { case TS_CR: /* doing crmod; ignore add'l linefeed */ state = TS_DATA; if ((cc != EOS) && (cc != '\n')) sendToPty (ptyFd, &cc, 1); /* forward char */ break; case TS_DATA: /* just pass data */ if (ci == IAC) state = TS_IAC; else { sendToPty (ptyFd, &cc, 1); /* forward char */ if (!myOpts [TELOPT_BINARY] && (cc == '\r')) state = TS_CR; } break; case TS_IAC: switch (ci) { case BREAK: /* interrupt from remote */ case IP: /* XXX interrupt (); */ logMsg ("telnetInTask: interrupt\n", 0, 0, 0, 0, 0, 0); state = TS_DATA; break; case AYT: /* Are You There? */ { static char aytAnswer [] = "\r\n[yes]\r\n"; sendToRem (remFd, aytAnswer, sizeof (aytAnswer) - 1); state = TS_DATA; break; } case EC: /* erase character */ sendToPty (ptyFd, "\b", 1); state = TS_DATA; break; case EL: /* erase line */ sendToPty (ptyFd, "\025", 1); state = TS_DATA; break; case DM: /* data mark */ state = TS_DATA; break; case SB: /* sub-option negotiation begin */ state = TS_BEGINNEG; break; case WILL: state = TS_WILL; break; /* remote will do opt */ case WONT: state = TS_WONT; break; /* remote wont do opt */ case DO: state = TS_DO; break; /* req we do opt */ case DONT: state = TS_DONT; break; /* req we dont do opt */ case IAC: sendToPty (ptyFd, &cc, 1); /* forward char */ state = TS_DATA; break; } break; case TS_BEGINNEG: /* ignore sub-option stuff for now */ if (ci == IAC) state = TS_ENDNEG; break; case TS_ENDNEG: state = (ci == SE) ? TS_DATA : TS_BEGINNEG; break; case TS_WILL: /* remote side said it will do opt */ (void)remDoOpt (ci, TRUE, remFd, ptyFd, TRUE); state = TS_DATA; break; case TS_WONT: /* remote side said it wont do opt */ (void)remDoOpt (ci, FALSE, remFd, ptyFd, TRUE); state = TS_DATA; break; case TS_DO: /* remote wants us to do opt */ (void)localDoOpt (ci, TRUE, remFd, ptyFd, TRUE); state = TS_DATA; break; case TS_DONT: /* remote wants us to not do opt */ (void)localDoOpt (ci, FALSE, remFd, ptyFd, TRUE); state = TS_DATA; break; default: printErr ("telnetd: invalid state = %d\n", state); break; } } return (state); }/********************************************************************************* remDoOpt - request/acknowledge remote enable/disable of option** This routine will try to accept the remote's enable or disable,* as specified by "will", of the remote's support for the specified option.* If the request is to disable the option, the option will always be disabled.* If the request is to enable the option, the option will be enabled, IF we* are capable of supporting it. The remote is notified to DO/DONT support* the option.** RETURNS: OK or ERROR.*/LOCAL STATUS remDoOpt ( FAST int option, /* option to be enabled/disabled */ BOOL enable, /* TRUE = enable option, FALSE = disable */ int remFd, /* fd to remote */ int ptyFd, /* fd to local pseudo-terminal */ BOOL reqFromRem /* TRUE = request is from remote */ ) { BOOL doOpt = enable; if (remOpts [option] == enable) return (OK); switch (option) { case TELOPT_BINARY: case TELOPT_ECHO: setMode (option, enable); break; case TELOPT_SGA: break; default: doOpt = FALSE; break; } if ((remOpts [option] != doOpt) || reqFromRem) { char msg[3]; msg[0] = IAC; msg[1] = doOpt ? DO : DONT; msg[2] = option; sendToRem (remFd, msg, 3); remOpts [option] = doOpt; } return ((enable == doOpt) ? OK : ERROR); }/********************************************************************************* localDoOpt - offer/acknowledge local support of option** This routine will try to enable or disable local support for the specified* option. If local support of the option is already in the desired mode, no* action is taken. If the request is to disable the option, the option will* always be disabled. If the request is to enable the option, the option* will be enabled, IF we are capable of supporting it. The remote is* notified that we WILL/WONT support the option.** RETURNS: OK or ERROR.*/LOCAL STATUS localDoOpt ( FAST int option, /* option to be enabled/disabled */ BOOL enable, /* TRUE = enable option, FALSE = disable */ int remFd, /* fd to remote */ int ptyFd, /* fd to local pseudo-terminal */ BOOL reqFromRem /* TRUE = request is from remote */ ) { BOOL will = enable; if (myOpts [option] == enable) return (OK); switch (option) { case TELOPT_BINARY: case TELOPT_ECHO: setMode (option, enable); break; case TELOPT_SGA: break; default: will = FALSE; break; } if ((myOpts [option] != will) || reqFromRem) { char msg[3]; msg[0] = IAC; msg[1] = will ? WILL : WONT; msg[2] = option; sendToRem (remFd, msg, 3); myOpts [option] = will; } return ((will == enable) ? OK : ERROR); }/********************************************************************************* setMode -** RETURNS: N/A.*/LOCAL void setMode ( int telnetOption, BOOL enable ) { FAST int ioOptions; switch (telnetOption) { case TELOPT_BINARY: raw = enable; break; case TELOPT_ECHO: echo = enable; break; } if (raw) ioOptions = 0; else { ioOptions = OPT_7_BIT | OPT_ABORT | OPT_TANDEM | OPT_LINE; if (echo) ioOptions |= OPT_ECHO | OPT_CRMOD; } (void) ioctl (STD_IN, FIOOPTIONS, ioOptions); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -