📄 interceptty.c
字号:
/* interceptty.c * * This file is an adaptation of ttysnoops.c, from the ttysnoop-0.12d * package It was originally written by Carl Declerck, Ulrich * Callmeir, Carl Declerck, and Josh Bailey. They deserve all of the * credit for the clever parts. I, on the other hand, deserve all of * the blame for whatever I broke. Please do not email the original * authors of ttysnoop about any problems with interceptty. * *//* $Id: interceptty.c,v 7.12 2004/09/05 23:01:35 gifford Exp $ */#include "config.h"#include <sys/types.h>#include <stdlib.h>#include <sys/wait.h>#include <sys/stat.h>#include <stdio.h>#include <ctype.h>#include <unistd.h>#include <signal.h>#include <fcntl.h>#include <errno.h>#include <string.h>#include <grp.h>#include <sys/socket.h>#include <netinet/in.h>#include <sys/un.h>#include <netdb.h>#include <pwd.h>#include <grp.h>#include "bsd-openpty.h"#include "common.h"#ifndef O_NOCTTY#define O_NOCTTY 0#endif#define DEFAULT_FRONTEND "/tmp/interceptty"struct sockaddr_in inet_resolve(const char *sockname);#define BUFF_SIZE 256char buff[BUFF_SIZE];char ttynam[TTYLEN+1] = "";int ptyfd = -1;int fdmax = 0;char *backend = NULL, *frontend = DEFAULT_FRONTEND, *settings = NULL, *outfilename = NULL, *opt_ptyname = NULL, *opt_ttyname = NULL;int verbose = 0, linebuff = 0, quiet = 0;int created_link = 0;char last_pty[TTYLEN] = "", last_tty[TTYLEN] = "";pid_t child_pid = 0;int please_die_now = 0;int listenfd = 0;mode_t frontend_mode = -1;uid_t frontend_owner = -1;gid_t frontend_group = -1;uid_t switch_uid = -1;gid_t switch_gid = -1;char *switch_root = NULL;int no_closedown = 0;FILE *outfile;/* find & open a pty to be used by the pty-master */int find_ptyxx (char *ptyname){ int fd, ttyfd; if (my_openpty(&fd,&ttyfd,ptyname) < 0) errorf("Couldn't openpty: %s\n",strerror(errno)); if (stty_raw(ttyfd) != 0) errorf("Couldn't put pty into raw mode: %s\n",strerror(errno)); /* Throw away the ttyfd. We'll keep it open because it prevents * errors when the client disconnects, but we don't ever plan to * read or write any data, so we needn't remember it. */ return fd;}/* Create the pty */int create_pty (int *ptyfd, char *ttynam){ char name[TTYLEN+1]; if (opt_ptyname) { if (strlen(opt_ptyname) > TTYLEN) errorf("Specified pty name is too long!"); strcpy(name, opt_ptyname); if (opt_ttyname) { if (strlen(opt_ttyname) > TTYLEN) errorf("Specified tty name is too long!"); strcpy(ttynam, opt_ttyname); } else if (strncmp(name,"/dev/pty",8) == 0) { /* Hacky, or heuristic? */ strcpy(ttynam, name); ttynam[5] = 't'; } else if (frontend) { errorf("A pty was specified with -p, but I couldn't figure out a tty to go with it.\nEither give me a tty with the -t switch, \nor else tell me not to create a front-end device by passing '-' as the front-device."); } else { ttynam[0]='\0'; } *ptyfd = open(opt_ptyname,O_RDWR|O_NOCTTY); } else { *ptyfd = find_ptyxx(name); strcpy(ttynam, name); } if (*ptyfd < 0) errorf("can't open pty '%s'\n",name); return 1;} /* do a graceful closedown */void closedown (void){ if (no_closedown) return; stty_orig (); if (created_link) unlink(frontend); if (child_pid) { if (verbose) fprintf(stderr,"Sending signal %d to child pid %ld\n",SIGTERM,(long)child_pid); kill(child_pid,SIGTERM); } if (verbose) fprintf(stderr,"closing down everything\n");}/* signal handlers */void sighup (int sig){ sig = sig; closedown ();}void sigpipe (int sig){ sig = sig; signal (SIGPIPE, sigpipe);}void sigint(int sig){ sig = sig; closedown(); _exit(1);}void sigdeath(int sig){ please_die_now=1;}void sigchld(int sig){ child_pid = 0; sigdeath(sig);}int alldigits(const char *s){ while(isdigit(*s)) s++; return *s == '\0';}uid_t find_uid(const char *u){ struct passwd *pw; if (alldigits(u)) return atoi(u); if (!(pw = getpwnam(u))) errorf("Error finding user '%s': %s\n",u,strerror(errno)); return pw->pw_uid;}gid_t find_gid(const char *g){ struct group *gr; if (alldigits(g)) return atoi(g); if (!(gr = getgrnam(g))) errorf("Error finding group '%s': %s\n",g,strerror(errno)); return gr->gr_gid;}/* main program */void dumpbuff(int dir, char *buf, int buflen){ int i; int ic; for (i=0;i<buflen;i++) { if (dir) { fprintf(outfile, "> \t"); } else { fprintf(outfile, "< "); } ic=(unsigned char)buf[i]; fprintf(outfile, "0x%02x",ic); if ( (buf[i] >= 33) && (buf[i] <= 126) ) { fprintf(outfile, " (%c)",buf[i]); } fprintf(outfile, "\n"); } fflush(outfile);}/* Run stty on the given file descriptor with the given arguments */int fstty(int fd, char *stty_args){ int child_status; int pid; char *stty_cmd; stty_cmd = malloc(strlen(stty_args)+1+strlen("stty ")); if (!stty_cmd) errorf("Couldn't malloc for stty_cmd: %s\n",strerror(errno)); strcpy(stty_cmd,"stty "); strcat(stty_cmd,stty_args); if ((pid=fork()) == 0) { /* Child */ if (dup2(fd,STDIN_FILENO) < 0) errorf("Couldn't dup2(%d,STDIN_FILENO=%d): %s\n",fd,STDIN_FILENO,strerror(errno)); if (execlp("sh","sh","-c",stty_cmd,NULL) < 0) errorf("Couldn't exec stty command: %s\n",strerror(errno)); /* Should never reach here. */ exit(-1); } else if (pid == -1) { errorf("Couldn't fork: %s\n",strerror(errno)); } free(stty_cmd); /* Parent */ if (wait(&child_status) <= 0) errorf("Error waiting for forked stty process: '%s'\n",strerror(errno)); if (!(WIFEXITED(child_status) && WEXITSTATUS(child_status) == 0) ) errorf("stty %s failed\n",stty_args); return 0;} /************************************* * Set up backend device ************************************/int setup_back_inet_socket(char *backend, int f[2]){ struct sockaddr_in sa; int fd; sa = inet_resolve(backend); if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 3) errorf("Couldn't open socket: %s\n",strerror(errno)); if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != 0) errorf("Couldn't connect socket: %s\n", strerror(errno)); return f[0]=f[1]=fd;}int setup_back_unix_socket(char *sockname, int f[2]){ int fd; struct sockaddr_un sa; if ((strlen(sockname)+1) > sizeof(sa.sun_path)) errorf("Path name is too long for a Unix socket.\n"); sa.sun_family = AF_UNIX; strcpy(sa.sun_path,sockname); if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 3) errorf("Couldn't open socket: %s\n",strerror(errno)); if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != 0) errorf("Couldn't connect socket: %s\n", strerror(errno)); return f[0]=f[1]=fd;}struct sockaddr_in inet_resolve(const char *sockname){ struct sockaddr_in sa; char *hostname, *netport; struct hostent *he; if (strchr(sockname,':') == NULL) errorf("Internet hostname must be @host:port\n"); if (!(hostname = strdup(sockname))) errorf("Couldn't dup string: %s\n",strerror(errno)); netport = strchr(hostname,':'); *netport='\0'; netport++; sa.sin_family=AF_INET; if (!(he = gethostbyname(hostname))) errorf("Couldn't resolve name '%s': %s.\n",hostname, (h_errno == HOST_NOT_FOUND) ? "Host not found" : ((h_errno == NO_ADDRESS)||(h_errno == NO_DATA)) ? "No data available" : (h_errno == NO_RECOVERY) ? "A non-recoverable name server error occured" : (h_errno == TRY_AGAIN) ? "A temporary error occured." : "An unknown error occured"); memcpy(&(sa.sin_addr),he->h_addr,he->h_length); #if 0 if (!(se = getservbyname(netport))) errorf("Couldn't resolve port.\n"); host_port=htons(se->s_port);#endif if (!(sa.sin_port = htons(atoi(netport)))) errorf("Couldn't figure out port number.\n"); free(hostname); return sa;}int setup_back_tty(char *backend, int f[2]){ int serialfd; /* Open the serial port */ serialfd = open(backend, O_RDWR | O_NOCTTY | O_SYNC | O_NOCTTY); if (serialfd < 0) errorf("error opening backend device '%s': %s\n",backend,strerror(errno)); if (stty_raw(serialfd) != 0) errorf("Error putting serial device '%s' in raw mode: %s\n",backend,strerror(errno)); /* Process settings from the -s switch */ if (settings) { fstty(serialfd,settings); } return f[0]=f[1]=serialfd;}int setup_back_program(char *backend, int f[2]){ int sock[2]; if (socketpair(PF_UNIX,SOCK_STREAM,0,sock) != 0) errorf("Couldn't create socket: %s\n",strerror(errno)); /* Now run the program */ switch (child_pid=fork()) { case -1: /* Error */ errorf("Error in fork(): %s\n",strerror(errno)); case 0: /* Child */ if (close(sock[0]) != 0) { errorf("Error in close(sock[0]): %s\n",strerror(errno)); } if (close(STDIN_FILENO) != 0) { errorf("Error in close(STDIN_FILENO): %s\n",strerror(errno)); } if (dup2(sock[1],STDIN_FILENO) != STDIN_FILENO) { errorf("Error in dup2(sock[1],STDIN_FILENO): %s\n",strerror(errno)); } if (close(STDOUT_FILENO) != 0) { errorf("Error in close(STDOUT_FILENO): %s\n",strerror(errno)); } if (dup2(sock[1],STDOUT_FILENO) != STDOUT_FILENO) { errorf("Error in dup2(sock[1],STDOUT_FILENO): %s\n",strerror(errno)); } if (close(sock[1]) != 0) { errorf("Error in close(sock[1]): %s\n",strerror(errno)); } execl("/bin/sh","sh","-c",backend,NULL); /* Only returns if there is an error. */ errorf("exec error: %s\n",strerror(errno)); } /* Parent */ return f[0]=f[1]=sock[0];}/* This can also do front fds */int setup_back_fds(char *backend, int f[2]){ char *fd1_s,*fd2_s; if (!(fd1_s = strdup(backend))) errorf("Couldn't dup string: %s\n",strerror(errno)); if ((fd2_s = strchr(fd1_s,',')) != 0) { *fd2_s='\0'; fd2_s++; } else { fd2_s = fd1_s; } f[1]=atoi(fd2_s); return f[0]=atoi(fd1_s);}int setup_backend(int f[2]){ switch(backend[0]) { case '@': if (strchr(backend,'/')!=0) return setup_back_unix_socket(backend+1,f); else return setup_back_inet_socket(backend+1,f); case '!': return setup_back_program(backend+1,f); case '=': return setup_back_fds(backend+1,f); default:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -