📄 sync-rw.c
字号:
/* sync-rw.c -- Magic C++ sync program between socket and tty (Mostly) portable public-domain implementation -- Copyright(C) 2003 Magicunix Infomation Technology Limited This file is part of magicd. magicd is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. For details, see the Magic C++ World-Wide-Web page, `http://www.magicunix.com', or send a mail to the Magic C++ developers <support@magicunix.com>. */#include <stdio.h>#include <stdlib.h>#include <string.h> #include <termios.h>#include <sys/ioctl.h>#include <unistd.h>#include "tcp.h"#include <time.h>#include <setjmp.h>#include <sys/types.h>#include <sys/wait.h>#include "config.h"#include "tools.h"#include "errno.h" #define TIMEOUT 10/* Function declarations. */void outa_here(), setup_tty();int release_licencecnt(char *clientip);int clearuputmpx();extern int childpid, newfd, telnet;extern int doutmp;extern char remotehost[];int writen(register int fd, register char *ptr, register int nbytes);int get_pty_master();void dropctty();int get_pty_slave();int tty_reset(int fd);int tty_sane(int fd);int login_exec(char *args[], struct passwd *pw);int utmp1(char *line, char name[], char *host,time_t date, int cleanup);static jmp_buf timejmp3;void time_jump3(int n){ (void) longjmp(timejmp3, 1);}/* * Read a stream socket one line at a time, and write each line back * to another stream socket./* * Return when the connection is terminated. */extern int newfd;extern int login;extern int telnet_col;extern int telnet_row;extern int debug;void killed2( int sig ){ util_log("close newfd = %d\n",newfd ); close ( newfd );}static int at_cr=0; /* State of telnet input */int getlicence = 0;int sync_rw(sockfd, streamfd , clientip)int sockfd; /* network connection file descriptor */int streamfd; /* pty file descriptor */char *clientip;{ extern int errno; int i ; int n; char line[BUFSIZ]; fd_set readfds; struct Buf_Len received, *newbuflen; char dupline[BUFSIZ]; int mapped=0; int j; int first; int cr_cnt = 0; /*cnt of 'cr'*/ struct winsize size; /* Zero out fdset for select() */ FD_ZERO(&readfds); /* * Now do that I/O thang. */ /*setup size of terminal*/ if( telnet_row != 0 && telnet_col != 0 ) { if( debug ) util_log("try to setup tty size\n"); size.ws_row = telnet_row; size.ws_col = telnet_col; /*I don't know why sometimes the former success */ /*and sometime the later success*/ /*so I set winsz twice.*/ if (ioctl(streamfd , TIOCSWINSZ, (char *) &size) < 0) { util_err_log("TIOCSWINSZ (streamfd) error",__FILE__,__LINE__,errno); if (ioctl(0, TIOCSWINSZ, (char *) &size) < 0) { util_err_log("TIOCSWINSZ (0) error",__FILE__,__LINE__,errno); } } } first = 1; if( signal( SIGTERM , killed2 ) == SIG_ERR ) { util_err_log( "Can not catch SIGTERM!\n",__FILE__,__LINE__,errno); } if( setjmp(timejmp3) == 1) { util_err_log("Read from tty time out!\n",__FILE__ , __LINE__,errno ); util_log("The client :%s has left\n",clientip );#ifdef HAVE_UTMPX_H clearuputmpx(); #endif if( getlicence ) release_licencecnt(clientip); exit(3); } for ( ; ; ) { FD_SET(sockfd, &readfds); FD_SET(streamfd, &readfds); select(10, &readfds, 0, 0, NULL); if ( FD_ISSET(sockfd, &readfds) ) { if ( (n=read(sockfd, line, BUFSIZ)) <= 0 ) { if (n == 0) {#ifdef HAVE_UTMPX_H clearuputmpx();#endif util_log("The client :%s Disconnect \n",clientip ); if( getlicence ) release_licencecnt(clientip); exit(0); /* connection terminated */ } else if (n < 0) {#ifdef HAVE_UTMPX_H clearuputmpx();#endif util_err_log("socket read error",__FILE__,__LINE__,errno); util_log("The client :%s has left\n",clientip ); if( getlicence ) release_licencecnt(clientip); exit(3); } } if(debug) { util_log("read from socket:\n"); /*convert line to a string which can be output*/ util_checkline( line , n ); } memcpy((void*)received.buffer, (void *)line, n); received.len=n; if ( telnet ) newbuflen=negotiate(sockfd, &received ,clientip); else newbuflen=(&received); if(debug) util_checkline( newbuflen->buffer , newbuflen->len ); if ( telnet ) { /* Map cr-null, cr-lf to cr */ for ( i=0, j=0; i<newbuflen->len; ++i ) { if ( at_cr ) { at_cr=0; cr_cnt++; switch (newbuflen->buffer[i]) { case '\0': case '\n': mapped=1; continue; default: break; } } if ( newbuflen->buffer[i] == '\r' ) at_cr=1; line[j++]=newbuflen->buffer[i]; } /* Only bother re-copying if we mapped a NUL */ if ( mapped ) { strncpy(newbuflen->buffer, line, j); newbuflen->len=j; mapped=0; } } if( debug ) { util_log("write to tty:\n"); util_checkline( newbuflen->buffer , newbuflen->len ); } if (writen(streamfd, newbuflen->buffer, newbuflen->len) != newbuflen->len) { if( getlicence ) release_licencecnt(clientip); return(-1); } } if ( FD_ISSET(streamfd, &readfds) ) { n=read(streamfd, line, BUFSIZ); if ( n == 0 ) {#ifdef HAVE_UTMPX_H clearuputmpx(); #endif if( getlicence ) release_licencecnt(clientip); exit(0); } else if (n < 0) { if ( errno == EIO ) { /*第一次进入设置超时*/ if( first == 1) { signal(SIGALRM, time_jump3); alarm(TIMEOUT); first = 0; } continue; } else {#ifdef HAVE_UTMPX_H clearuputmpx();#endif util_err_log("pty read error", __FILE__,__LINE__ , errno); if( getlicence ) release_licencecnt(clientip); exit(3); } } if(debug) { util_log("read from tty\n "); util_checkline( line , n ); } first = 1; alarm(0); if(debug) { util_log("write to socket:\n "); util_checkline(line , n ); } if (writen(sockfd, line, n) != n) { util_log("write sockfd error"); if( getlicence ) release_licencecnt(clientip); exit(3); } } }}/* * Initialize a pty, fork a command running under it, and then * return the master file descriptor */int setup(argv, pw)char *argv[];struct passwd *pw;{ int master_fd, slave_fd; int flags; /*struct sigaction act,oact;*/ if ( (master_fd=get_pty_master()) < 0 ) { util_log("get_pty_master() error\n"); exit(3); } if(debug) util_log("Enter setup\n");/*#if defined(SOLARIS) || defined( FREEBSD )*/ if( signal( SIGCLD , outa_here ) == SIG_ERR ) { util_err_log( "Can not signal!\n",__FILE__,__LINE__,errno); exit(3); }/* #else if( signal( SIGCLD , SIG_IGN ) == SIG_ERR ) { util_err_log( "Can not signal!\n",__FILE__,__LINE__,errno); exit(3); }#endif*/ if ( (childpid=fork()) < 0 ) { util_log("fork error\n"); exit(3); } else if ( childpid == 0 ) { dropctty(); /* Lose controlling tty */ /* Gain slave as controlling tty */ if ( (slave_fd=get_pty_slave()) < 0 ) { util_log("get_pty_slave()\n"); exit(3); }#if defined(TIOCSCTTY) && !defined(CIBAUD) if ( ioctl(slave_fd, TIOCSCTTY, NULL) < 0 ) util_log("TIOCSCTTY error\n");#endif /* BSD */ /* Rearrange file descriptors */ close(0); dup(slave_fd); close(1); dup(slave_fd); close(master_fd); if ( ! netdebug ) close(2), dup(slave_fd); close(slave_fd); /* Reset the terminal */ if ( tty_reset(0) < 0 ) (void) tty_sane(0);#ifdef SIGTSTP /* Prevent non-job-control programs from dying on SIGTSTP */ signal(SIGTSTP, SIG_IGN);#endif if ( login_exec(argv, pw) < 0 ) { util_log("login_exec() error\n"); exit(255); } /* NOTREACHED */ } dropctty(); /* Lose controlling tty */ setup_tty(pw); /* Change ownership of the tty and log utmp */ return(master_fd);}/* These functions take care of the tty */extern char tty_name[]; /* from misc.c */extern int doutmp; /* from tcpserv.c */char *log_name=NULL;int ttyowner=0; /* The owner of the tty */void setup_tty(pw)struct passwd *pw;{ struct stat sb; time_t now; int newowner; struct winsize size; int nrow = 0; int ncol = 0; /* Make sure the tty exists */ if ( stat(tty_name, &sb) < 0 ) return; else ttyowner=sb.st_uid; if ( doutmp ) /* Set up the user to log in utmp */ { if ( pw ) log_name=pw->pw_name; else if ( (pw=(struct passwd *)getpwuid(getuid())) != NULL ) log_name=pw->pw_name; else log_name="nobody"; (void) time(&now); /*(void) utmp1(tty_name, log_name, remotehost, now, 0);*/ } if ( pw ) newowner=pw->pw_uid; else if ( (pw=(struct passwd *)getpwuid(getuid())) != NULL ) newowner=pw->pw_uid; else newowner=0; /* chown to root as last resort */ (void) chmod(tty_name, 0620); (void) chown(tty_name, newowner, sb.st_gid); }/* Cleanup function */char clientip[16];void outa_here(int sig){ struct stat sb; time_t now; int status; int pid; if ( childpid ) kill(childpid, SIGHUP); if ( stat(tty_name, &sb) == 0 ) { if ( doutmp && log_name ) { (void) time(&now); /*(void) utmp1(tty_name, log_name, NULL, now, 1);*/ } (void) chmod(tty_name, 0666); (void) chown(tty_name, ttyowner, sb.st_gid); } close( 2 ); close( newfd );#ifdef HAVE_UTMPX_H clearuputmpx();#endif util_log("The client :%s has left\n",clientip ); if( ( pid = wait( &status ) ) < 0 ) util_err_log( "wait error!",__FILE__,__LINE__ , errno ); exit(0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -