#include #include #include #include #include #include #include #include #include #include #include #define INIT "export TERM=tty43 EDITOR=ed PAGER='pr -ptl23'\n" #define MAXBUF 2048 char *getpw(void); void sigchld(); int main(int argc, char *argv[]) { char bufin[MAXBUF], bufout[MAXBUF], *bi, *bo, in[30], **nargv, out[30]; fd_set rfds0, rfds1; int fdin, fdout, i, n, offset, sshpass; struct timeval tv; signal(SIGCHLD, sigchld); /* Create named pipes. */ sprintf(in, "/var/tmp/rtty.in.%d", getpid()); sprintf(out, "/var/tmp/rtty.out.%d", getpid()); if(mkfifo(in, 0644) == -1 || mkfifo(out, 0664) == -1) if(errno != EEXIST) err(1, "mkfifo"); /* Ask for password on -P. */ sshpass = 0; if(strcmp(argv[1], "-P") == 0){ sshpass = 1; setenv("SSHPASS", getpw(), 1); /* Remove -P from argv. */ argv[1] = argv[0]; argv++; argc--; } if(fork() == 0){ /* Redirect standard in, out. */ if(!(fdin = open(in, O_RDONLY))) err(1, "open"); if(!(fdout = open(out, O_WRONLY))) err(1, "open"); dup2(fdin, 0); dup2(fdout, 1); /* Create new argument vector. */ if(!(nargv = malloc(sizeof(char *)*(argc+10)))) err(1, "malloc"); offset = -1; if(sshpass){ nargv[++offset] = "sshpass"; nargv[++offset] = "-ePass"; } nargv[++offset] = "ssh"; nargv[++offset] = "-tt"; if(!sshpass) nargv[++offset] = "-oBatchMode=yes"; for(i = 1; i < argc; i++) nargv[i+offset] = argv[i]; nargv[argc+offset] = NULL; /* Exec into ssh. */ execvp(nargv[0], nargv); err(1, "%s", nargv[0]); } if(!(fdin = open(in, O_WRONLY))) err(1, "open"); if(!(fdout = open(out, O_RDONLY))) err(1, "open"); dprintf(fdin, INIT); FD_ZERO(&rfds0); FD_ZERO(&rfds1); tv.tv_sec = 0; tv.tv_usec = 1; for(;;){ /* * User input is read from standard in and copied the * input pipe. It is saved in bufin for later use. */ FD_SET(0, &rfds0); if(select(0+1, &rfds0, NULL, NULL, &tv) > 0){ n = read(0, bufin, MAXBUF); bufin[n] = 0; dprintf(fdin, "%s", bufin); fflush(stdout); } /* * System output is read from the output pipe and copied * to standard out for the user to see. */ FD_SET(fdout, &rfds1); if(select(fdout+1, &rfds1, NULL, NULL, &tv) > 0){ n = read(fdout, bufout, MAXBUF); if(!n) continue; bufout[n] = 0; /* * Bufin and bufout are copied to the temporary * pointers bi and bo. Bo is incremented in order * to skip any potential repetition of the command * given by the user on standard in. (It is assumed * that the typed command fits in bufin, i.e. is * not larger than MAXBUF.) */ bi = bufin; bo = bufout; for(;;){ if(*bo == '\n'){ bo++; break; } if(*bo == 13){ bo++; continue; } if(*bi != *bo){ bo = bufout; break; } bi++; bo++; } /* * Bo is printed and bufin is cleared, so as not * to perform the skip again, incorrectly. */ printf("%s", bo); fflush(stdout); bufin[0] = 0; } } } char * getpw() { char *pw; struct termios orig, term; /* * This pointer will never be freed, but eh... whatever. */ if(!(pw = malloc(255))) err(1, "malloc"); tcgetattr(0, &orig); tcgetattr(0, &term); term.c_lflag &= ~ECHO; tcsetattr(0, TCSANOW, &term); printf("password: "); fgets(pw, 255, stdin); pw[strcspn(pw, "\n")] = 0; printf("\n"); tcsetattr(0, TCSAFLUSH, &orig); return pw; } void sigchld() { exit(0); }