xttn.c
上传用户:duobangkj
上传日期:2007-01-07
资源大小:70k
文件大小:12k
- /* xttn.c -- telnet module for XT
- This file uses 4-character tabstops
- */
- #include <stdio.h>
- #include <string.h>
- #include <netdb.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/telnet.h>
- #include <sys/time.h>
- #include <sys/select.h>
- #include <unistd.h>
- #include <signal.h>
- #include <setjmp.h>
- #include <errno.h>
- #include "xt.h"
- FILE *cfp, /* capture file pointer */
- *fp; /* file to transmit */
- int sfd = -1; /* socket file descriptor */
- char captfile[SM_BUFF] = CAPTFILE, /* capture file's name */
- proto[8];
- extern short autoflag, cismode, nl2cr;
- extern char hostname[];
- extern jmp_buf erret;
- short capture = FALSE;
- static jmp_buf stop;
- static RETSIGTYPE (*oldvec)();
- #define SB_IAC 256 /* This is not a TELNET code - it is used to indicated
- that an IAC has been received during an SB sequence. */
- #define CAN_WILL (1 << 0) /* Can WILL this protocol. */
- #define CAN_DO (1 << 1) /* Can DO this protocol. */
- #define DONE_WILL (1 << 2) /* WILL done. */
- #define DONE_DO (1 << 3) /* DO done. */
- #define REC_WILL (1 << 4) /* Received a WILL. */
- #define REC_DO (1 << 5) /* Received a DO. */
- /* Attach standard input and output to the socket. This only gets called
- after a fork by the child process, which then exec's a program that uses
- standard i/o for some data transfer protocol.
- */
- void
- sattach()
- {
- dup2(sfd, 0); /* close local stdin and connect to socket */
- dup2(sfd, 1); /* close local stdout and connect to socket */
- close(sfd); /* close the old socket descriptor */
- }
- static
- userdatum(c)
- unsigned c;
- {
- static int state=0;
- switch(state){
- case 0:
- case 'r':
- {
- if(c != IAC){ /* Output character, but suppress a NUL byte after a
- carriage return character, because it is put in by
- the other end to meet protocol requirements. */
- if(state != 'r' || c != 0)
- return (SUCCESS);
- /* Set the new state to 'r' if a 'r' was
- received and we're not in binary mode. */
- state =
- !(proto[TELOPT_BINARY] & REC_WILL) && c == 'r'
- ? 'r'
- : 0;
- }
- else
- state = IAC;
- break;
- }
- case IAC:
- {
- switch(c) {
- case SE:
- case NOP:
- case DM:
- case BREAK:
- case IP:
- case AO:
- case AYT:
- case EC:
- case EL:
- case GA:
- state = 0;
- break;
- case SB:
- state = SB;
- break;
- case IAC:
- state = 0;
- return (SUCCESS);
- case WILL:
- state = WILL;
- break;
- case WONT:
- state = WONT;
- break;
- case DO:
- state = DO;
- break;
- case DONT:
- state = DONT;
- break;
- default:
- state = 0;
- }
- break;
- }
- case SB:
- case SB_IAC:
- {
- if(state == SB_IAC) {
- if(c == IAC)
- state = SB;
- else if(c == SE)
- state = 0;
- } else if(c == IAC)
- state = SB_IAC;
- break;
- }
- case WILL:
- {
- unsigned char rbuf[3];
- rbuf[1] = 0;
- if(c < sizeof(proto) && proto[c] & CAN_DO) {
- proto[c] |= REC_WILL;
- if(!(proto[c] & DONE_DO)) {
- rbuf[1] = DO;
- proto[c] |= DONE_DO;
- }
- } else
- rbuf[1] = DONT;
- if(rbuf[1]) {
- rbuf[0] = (unsigned char) IAC;
- rbuf[2] = (unsigned char) c;
- send_string(rbuf, sizeof(rbuf));
- }
- state = 0;
- break;
- }
- case DO:
- {
- unsigned char rbuf[3];
- rbuf[1] = 0;
- if(c < sizeof(proto) && proto[c] & CAN_WILL) {
- proto[c] |= REC_DO;
- if(!(proto[c] & DONE_WILL)) {
- rbuf[1] = WILL;
- proto[c] |= DONE_WILL;
- }
- }
- else rbuf[1] = WONT;
- if(rbuf[1]) {
- rbuf[0] = (unsigned char) IAC;
- rbuf[2] = (unsigned char) c;
- send_string(rbuf, sizeof(rbuf));
- }
- state = 0;
- break;
- }
- case WONT:
- if(c < sizeof(proto))
- proto[c] &= ~(REC_WILL | DONE_DO);
- state = 0;
- break;
- case DONT:
- if(c < sizeof(proto))
- proto[c] &= ~(REC_DO | DONE_WILL);
- state = 0;
- break;
- }
- return (FAILURE);
- }
- static void
- alrm(junk)
- int junk;
- { /* do nothing */
- }
- /* Get a byte from the socket within 'seconds' or return -1.
- All data read from the socket are input through this routine.
- */
- readbyte(seconds)
- unsigned seconds;
- {
- static int count = 0;
- static char *p, rxbuf[LG_BUFF];
- unsigned alarm();
- if (count-- > 0){
- return(*p++ & 0xff);
- }
- if (seconds){
- signal(SIGALRM, alrm);
- alarm(seconds);
- }
- if ((count = read(sfd, p = rxbuf, LG_BUFF)) < 1)
- return(-1);
- if (seconds)
- alarm(0);
- if (count-- > 0){
- return(*p++ & 0xff);
- }
- }
- void
- sendbyte(ch)
- int ch;
- {
- char c = ch & 0xff;
- send_string(&c, 1);
- }
- /* Write data to the remote host. If an error (other than EPIPE) occurs, then
- abort, and don't return. EPIPE errors are ignored. */
- void
- send_string(data, len)
- char *data;
- int len;
- {
- if(write(sfd, data, len) < 0 && errno != EPIPE){
- S1("Cannot write to host");
- s_exit();
- }
- }
- /* start capturing */
- static void
- capt_on()
- {
- if (capture)
- sprintf(Msg,"Already capturing to "%s"",captfile);
- else {
- if (!(cfp = fopen(captfile, "a")))
- sprintf(Msg,"Can't open "%s" for capturing",captfile);
- else
- capture = TRUE,
- sprintf(Msg,"Capturing to "%s"",captfile),
- setbuf(cfp, NIL(char));
- }
- S2(Msg);
- }
- /* stop capturing */
- static RETSIGTYPE
- capt_off()
- {
- if (!capture)
- sprintf(Msg,"Sorry, we haven't been capturing lately");
- else
- fclose(cfp),
- capture = FALSE,
- sprintf(Msg,""%s" closed for capturing",captfile);
- S2(Msg);
- }
- /* cleanup, flush and exit */
- static RETSIGTYPE
- cleanup()
- {
- if (capture)
- fclose(cfp),
- sprintf(Msg,""%s" closed for capturing",captfile),
- S2(Msg);
- capture = FALSE;
- }
- static void
- end_divert(junk)
- int junk;
- {
- show_abort();
- fclose(fp);
- signal(SIGINT, oldvec);
- longjmp(stop,1);
- }
- /* Divert file into input stream */
- void
- divert(script)
- short script;
- {
- int c;
- if (!script)
- fputc('r',tfp),
- fputc('n',tfp),
- show(-1,"File?"),
- getline(),
- getword();
- if (word[0] == ' ')
- return;
- if (!(fp = fopen(word, "r"))){
- sprintf(Msg,"Can't access '%s'",word);
- S2(Msg);
- return;
- }
- oldvec = signal(SIGINT,end_divert);
- if (setjmp(stop))
- return;
- while ((c = getc(fp)) != EOF){
- if (c != 'n')
- sendbyte(c);
- else
- sendbyte(nl2cr ? 'r' : 'n');
- }
- fclose(fp);
- signal(SIGINT,oldvec);
- }
- xttn()
- {
- /* Request string for a binary path. */
- static char req_bin[] = {
- (char) IAC, (char) DO, (char) TELOPT_BINARY,
- (char) IAC, (char) WILL, (char) TELOPT_BINARY
- };
- /* Request string for ECHO and Suppress GA. */
- static char req_opt[] = {
- (char) IAC, (char) DO, (char) TELOPT_ECHO,
- (char) IAC, (char) DO, (char) TELOPT_SGA
- };
- int i, port;
- long netnum;
- struct hostent *n;
- struct sockaddr_in in;
- if (sfd > 0)
- close (sfd);
- sfd = -1;
- port = 23; /* Default TELNET port. */
- netnum = inet_addr(hostname);
- if(netnum == -1) {
- n = gethostbyname(hostname);
- if(!n) {
- sprintf(Msg,"Host %s is not known",hostname);
- S;
- return(FALSE);
- }
- for(i = 0; n->h_addr_list[i]; i++){
- sfd = socket(AF_INET, SOCK_STREAM, 0);
- if(sfd < 0){
- S1("Cannot create a socket");
- s_exit();
- }
- memcpy(&netnum, n->h_addr_list[i], sizeof(netnum));
- memset(&in, 0, sizeof(in));
- in.sin_family = AF_INET;
- in.sin_port = htons(port);
- in.sin_addr.s_addr = netnum;
- sprintf(Msg,"Trying %s...",inet_ntoa(in.sin_addr));
- S;
- if(connect(sfd, &in, sizeof(in)) >= 0)
- break;
- close(sfd);
- }
- if(!n->h_addr_list[i])
- s_exit();
- } else {
- sfd = socket(AF_INET, SOCK_STREAM, 0);
- if(sfd < 0){
- S1("Cannot create a socket");
- s_exit();
- }
- memset(&in, 0, sizeof(in));
- in.sin_family = AF_INET;
- in.sin_port = htons(port);
- in.sin_addr.s_addr = netnum;
- sprintf(Msg,"Trying %s...",hostname);
- S;
- if(connect(sfd, &in, sizeof(in)) < 0)
- s_exit();
- }
- /* Ignore broken pipes on writing, we'll spot the eof on input instead. */
- signal(SIGPIPE, SIG_IGN);
- memset(proto, 0, sizeof(proto));
- /* Request remote echo and suppress GA. */
- proto[TELOPT_ECHO] = DONE_DO | CAN_DO;
- proto[TELOPT_SGA] = DONE_DO | CAN_DO;
- send_string(req_opt, sizeof(req_opt));
- /* Request binary link */
- proto[TELOPT_BINARY] = DONE_DO | DONE_WILL | CAN_DO | CAN_WILL;
- send_string(req_bin, sizeof(req_bin));
- return(tninit());
- }
- tnterm()
- {
- int res, i, rdy_kbd, rdy_host;
- fd_set readfds, writefds, exceptfds;
- struct timeval select_timout = {0L,0L};
- unsigned cu;
- if (sfd < 0)
- return(FAILURE);
- if (autoflag)
- capt_on();
- FD_ZERO(&readfds);
- FD_ZERO(&writefds);
- FD_ZERO(&exceptfds);
- mode(NEWMODE);
- while (1) {
- FD_SET(0, &readfds);
- FD_SET(sfd, &readfds);
- FD_SET(0, &exceptfds);
- FD_SET(sfd, &exceptfds);
- select_timout.tv_sec = 600L;
- res = select(sfd+1, &readfds, &writefds, &exceptfds, &select_timout);
- if(res == 0) {
- if(FD_ISSET(0, &exceptfds) || FD_ISSET(sfd, &exceptfds))
- res = -1; /* Exception raisied */
- }
- rdy_kbd = FD_ISSET(0, &readfds);
- rdy_host = FD_ISSET(sfd, &readfds);
- if(res < 0){
- S1("Error on Telnet");
- longjmp(erret,1);
- }
- if(rdy_host){ /* Data available from the host, so read some. */
- char buf[LG_BUFF];
- res = read(sfd, buf, sizeof(buf));
- if(res == 0)
- break;
- if(res < 0){
- S1("Error on socket read");
- s_exit();
- }
- for (i=0;i<res;i++){
- cu = (unchar)buf[i];
- if (cismode && cu == ENQ) {
- cleanup();
- cismode = 2;
- return(SUCCESS);
- }
- fputc(cu,tfp);
- if (capture && cu != 'r')
- fputc(cu,cfp);
- }
- }
- if(rdy_kbd) {
- char buf[LG_BUFF / 2];
- char obuf[LG_BUFF];
- binding_t *ptr;
- extern binding_t *first_binding;
- int lc, xcape, olen = 0;
- res = read(0, buf, sizeof(buf));
- if(res < 0){
- S1("Error on stdin read");
- s_exit();
- }
- if(res == 0)
- /* End of file on input - so just exit. */
- s_exit();
- for (i=0;i<res;i++){
- cu = (int) buf[i] & 0xff;
- if (! xcape && cu == my_escape){
- xcape++;
- continue;
- }
- if (xcape){
- xcape=0;
- lc = tolower(cu);
- for (ptr = first_binding; ptr; ptr = ptr->bs_next){
- if (ptr->bs_c == lc){
- switch (ptr->bs_function){
- case CAPTYES:
- capt_on();
- cu = 0;
- break;
- case CAPTEND:
- capt_off();
- cu = 0;
- break;
- case DIVCHAR:
- mode(SIGMODE);
- divert(FALSE);
- mode(NEWMODE);
- cu = 0;
- break;
- case HLPCHAR:
- show_bindings();
- cu = 0;
- break;
- case ENDCHAR:
- cleanup();
- return(FALSE);
- case QUITCHR:
- cleanup();
- s_exit();
- default: /* just use the next character */
- ;
- }
- }
- }
- }
- if(cu)
- obuf[olen++] = (char) cu;
- if(cu == IAC) { /* Force the IAC escape character. */
- obuf[olen++] = (char) IAC;
- } else if(cu == 'r' && !(proto[TELOPT_BINARY] & REC_DO)) {
- /* Always insert a NUL byte after a carriage return.
- Strictly speaking this is necessary only if a line
- feed does not follow. Don't do this in binary mode/ */
- obuf[olen++] = 0;
- }
- }
- if(olen)
- send_string(obuf, olen);
- }
- }
- S2("Connection closed by remote host.");
- *hostname = ' ';
- close (sfd);
- sfd = -1;
- return(FALSE);
- }
- tninit()
- {
- int res, i, rdy;
- fd_set readfds, writefds, exceptfds;
- struct timeval select_timout= {0L,0L};
- unsigned cu;
- if (sfd < 0)
- return(FAILURE);
- FD_ZERO(&readfds);
- FD_ZERO(&writefds);
- FD_ZERO(&exceptfds);
- FD_SET(sfd, &readfds);
- FD_SET(sfd, &exceptfds);
- while (1) {
- select_timout.tv_sec = 200L;
- res = select(sfd+1, &readfds, &writefds, &exceptfds, &select_timout);
- if(res == 0) {
- if(FD_ISSET(sfd, &exceptfds))
- res = -1; /* Exception raisied */
- }
- rdy = FD_ISSET(sfd, &readfds);
- if(res < 0){
- S1("Error on Telnet");
- s_exit();
- }
- if(rdy) {
- /* Data available from the host, so read some. */
- char buf[LG_BUFF];
- res = read(sfd, buf, 1);
- if(res == 0)
- break;
- if(res < 0){
- S1("Error on socket read");
- s_exit();
- }
- for (i=0;i<res;i++){
- cu = (unchar)buf[i];
- if (userdatum(cu))
- return(SUCCESS);
- }
- }
- }
- return(SUCCESS);
- }