#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(char *); void sigchld(); int main(int argc, char *argv[]) { char bufin[MAXBUF], bufout[MAXBUF], *bi, *bo, in[30], **nargv, out[30], pw[255]; fd_set rfds0, rfds1; int detect, 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"); /* Process rtty-specific flags. */ detect = sshpass = 0; for(;argv[1][0] == '+';){ if(strchr(argv[1], 'd')) detect = 1; if(strchr(argv[1], 'p')) sshpass = 1; /* Remove flag argument from argv. */ argv[1] = argv[0]; argv++; argc--; } /* Ask for password on +p. */ if(sshpass){ printf("password: "); getpw(pw); setenv("SSHPASS", pw, 1); sshpass = 1; } 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; if(!detect) continue; /* * As the +d flag is given, rtty tries to detect * password prompts and hide the user's input. */ if(bo[strlen(bo)-1] == ':' || strcmp(bo+strlen(bo)-2, ": ") == 0){ if(!(bo = strrchr(bufout, '\n'))) bo = bufout; if(strstr(bo, "password") || strstr(bo, "Password") || strstr(bo, "passphrase") || strstr(bo, "Passphrase")){ getpw(pw); dprintf(fdin, "%s\n", pw); } } } } } char * getpw(char *pw) { struct termios orig, term; tcgetattr(0, &orig); tcgetattr(0, &term); term.c_lflag &= ~ECHO; tcsetattr(0, TCSANOW, &term); fgets(pw, 255, stdin); pw[strcspn(pw, "\n")] = 0; printf("\n"); tcsetattr(0, TCSAFLUSH, &orig); return pw; } void sigchld() { exit(0); }