/*----------------------------------------------------------------------+*/ SPC_Channel_Ptr open_pty_channel_object(SPC_Channel_Ptr channel, int iomode, XeString hostname) /*----------------------------------------------------------------------+*/ { Wire *tmpwire, *newwire; SPC_Channel_Ptr result; call_parent_method(channel, open, (channel, iomode, hostname), result); if(result==SPC_ERROR) return(SPC_ERROR); /* We know that we are going to use one of STDIN, STDOUT, or STDERR (or else we would be a NOIO channel), so allocate at least one pty pair */ if(!(tmpwire=getpty(NULL))) return(SPC_ERROR); if (IS_SPCIO_STDIN(iomode)) { channel->wires[STDIN]=tmpwire; } if (IS_SPCIO_STDOUT(iomode)) { channel->wires[STDOUT]=tmpwire; } if (IS_SPCIO_SEPARATE(iomode)) { if(!(newwire=getpty(tmpwire))) { spc_close(tmpwire->fd[MASTER_SIDE]); free_wire(tmpwire); return(SPC_ERROR); } else tmpwire=newwire; } if (IS_SPCIO_STDERR(iomode)) { channel->wires[STDERR]=tmpwire; } channel->wire_list=tmpwire; /* set up the channel file descriptors */ channel->file_descs[STDIN] = (channel->wires[STDIN]) ->fd[MASTER_SIDE]; channel->file_descs[STDOUT] = (channel->wires[STDOUT])->fd[MASTER_SIDE]; channel->file_descs[STDERR] = (channel->wires[STDERR])->fd[MASTER_SIDE]; for(tmpwire=channel->wire_list; tmpwire; tmpwire=tmpwire->next) { init_termio(&tmpwire->master_termio); init_termio(&tmpwire->slave_termio); } return(channel); }
bool SpawningUploadClient::SpawnCommand() { char ptypath[20]; char ttypath[20]; //XXX: should use a system-provided TerminalCommand class BString shellcmd = "exec"; const char *args[] = { "/bin/sh", "-c", NULL, NULL }; fPty = getpty(ptypath, ttypath); if (fPty < 0) return B_ERROR; shellcmd << " 0<" << ttypath; shellcmd << " 1>" << ttypath; shellcmd += " 2>&1"; shellcmd << " ; "; shellcmd << "export TTY=" << ttypath << "; "; // BeOS hack shellcmd << "export LC_ALL=C; export LANG=C; "; shellcmd << "exec "; shellcmd << fCommand.c_str(); printf("spawning: '%s'\n", shellcmd.String()); args[2] = shellcmd.String(); fCommandPid = load_image(3, args, (const char **)environ); if (fCommandPid < 0) return false; resume_thread(fCommandPid); return true; }
int openpty(int *master, int *slave, char *name, struct termios *term, struct winsize *winsz) { if (getpty(master, slave, name) == -1) { return (-1); } if (term) { (void) tcsetattr(*slave, TCSANOW, term); } if (winsz) { (void) ioctl(*slave, TIOCSWINSZ, winsz); } return (0); }
/* We rely on that there is space in the buffer for now. */ char *b = ts->buf2 + ts->rdidx2; *b++ = IAC; *b++ = command; *b++ = option; ts->rdidx2 += 3; ts->size2 += 3; } static struct tsession * #ifdef CONFIG_FEATURE_TELNETD_INETD make_new_session(void) #else /* CONFIG_FEATURE_TELNETD_INETD */ make_new_session(int sockfd) #endif /* CONFIG_FEATURE_TELNETD_INETD */ { struct termios termbuf; int pty, pid; char tty_name[32]; struct tsession *ts = malloc(sizeof(struct tsession) + BUFSIZE * 2); ts->buf1 = (char *)(&ts[1]); ts->buf2 = ts->buf1 + BUFSIZE; #ifdef CONFIG_FEATURE_TELNETD_INETD ts->sockfd_read = 0; ts->sockfd_write = 1; #else /* CONFIG_FEATURE_TELNETD_INETD */ ts->sockfd = sockfd; #endif /* CONFIG_FEATURE_TELNETD_INETD */ ts->rdidx1 = ts->wridx1 = ts->size1 = 0; ts->rdidx2 = ts->wridx2 = ts->size2 = 0; #ifdef CONFIG_FEATURE_TELNETD_INACTIVE_TIMEOUT /* initialize it with the timeout value*/ ts->timeout_time = time(NULL) + TIMEOUT; #endif /* CONFIG_FEATURE_TELNETD_INACTIVE_TIMEOUT */ /* Got a new connection, set up a tty and spawn a shell. */ pty = getpty(tty_name); if (pty < 0) { syslog(LOG_ERR, "All network ports in use!"); return 0; } if (pty > maxfd) maxfd = pty; ts->ptyfd = pty; /* Make the telnet client understand we will echo characters so it * should not do it locally. We don't tell the client to run linemode, * because we want to handle line editing and tab completion and other * stuff that requires char-by-char support. */ send_iac(ts, DO, TELOPT_ECHO); send_iac(ts, DO, TELOPT_NAWS); send_iac(ts, DO, TELOPT_LFLOW); send_iac(ts, WILL, TELOPT_ECHO); send_iac(ts, WILL, TELOPT_SGA); if ((pid = fork()) < 0) { syslog(LOG_ERR, "Can`t forking"); } if (pid == 0) { /* In child, open the child's side of the tty. */ int i; for(i = 0; i <= maxfd; i++) close(i); /* make new process group */ setsid(); if (open(tty_name, O_RDWR /*| O_NOCTTY*/) < 0) { syslog(LOG_ERR, "Could not open tty"); exit(1); } dup(0); dup(0); tcsetpgrp(0, getpid()); /* The pseudo-terminal allocated to the client is configured to operate in * cooked mode, and with XTABS CRMOD enabled (see tty(4)). */ tcgetattr(0, &termbuf); termbuf.c_lflag |= ECHO; /* if we use readline we dont want this */ termbuf.c_oflag |= ONLCR|XTABS; termbuf.c_iflag |= ICRNL; termbuf.c_iflag &= ~IXOFF; /*termbuf.c_lflag &= ~ICANON;*/ tcsetattr(0, TCSANOW, &termbuf); print_login_issue(issuefile, NULL); /* exec shell, with correct argv and env */ execv(loginpath, (char *const *)argv_init); /* NOT REACHED */ syslog(LOG_ERR, "execv error"); exit(1); } ts->shell_pid = pid; return ts; }
static struct tsession * make_new_session(int sockfd) { struct termios termbuf; int pty, pid; static char tty_name[32]; struct tsession *ts = (struct tsession *)malloc(sizeof(struct tsession)); int t1, t2; #ifdef USE_ISSUE FILE *fp; int chr; #endif ts->buf1 = (char *)malloc(BUFSIZE); ts->buf2 = (char *)malloc(BUFSIZE); ts->sockfd = sockfd; ts->rdidx1 = ts->wridx1 = ts->size1 = 0; ts->rdidx2 = ts->wridx2 = ts->size2 = 0; /* Got a new connection, set up a tty and spawn a shell. */ pty = getpty(tty_name); if (pty < 0) { fprintf(stderr, "All network ports in use!\n"); return 0; } if (pty > maxfd) maxfd = pty; ts->ptyfd = pty; /* Make the telnet client understand we will echo characters so it * should not do it locally. We don't tell the client to run linemode, * because we want to handle line editing and tab completion and other * stuff that requires char-by-char support. */ send_iac(ts, DO, TELOPT_ECHO); send_iac(ts, DO, TELOPT_LFLOW); send_iac(ts, WILL, TELOPT_ECHO); send_iac(ts, WILL, TELOPT_SGA); if ((pid = fork()) < 0) { perror("fork"); } if (pid == 0) { /* In child, open the child's side of the tty. */ int i, t; for(i = 0; i <= maxfd; i++) close(i); /* make new process group */ if (setsid() < 0) perror_msg_and_die("setsid"); t = open(tty_name, O_RDWR | O_NOCTTY); //t = open(tty_name, O_RDWR); if (t < 0) perror_msg_and_die("Could not open tty"); t1 = dup(0); t2 = dup(1); tcsetpgrp(0, getpid()); if (ioctl(t, TIOCSCTTY, NULL)) { perror_msg_and_die("could not set controlling tty"); } /* The pseudo-terminal allocated to the client is configured to operate in * cooked mode, and with XTABS CRMOD enabled (see tty(4)). */ tcgetattr(t, &termbuf); termbuf.c_lflag |= ECHO; /* if we use readline we dont want this */ termbuf.c_oflag |= ONLCR|XTABS; termbuf.c_iflag |= ICRNL; termbuf.c_iflag &= ~IXOFF; /* termbuf.c_lflag &= ~ICANON; */ tcsetattr(t, TCSANOW, &termbuf); DEBUG_OUT("stdin, stdout, stderr: %d %d %d\n", t, t1, t2); #ifdef USE_ISSUE /* Display ISSUE_FILE */ if ((fp = fopen(ISSUE_FILE, "r")) != NULL) { DEBUG_OUT(" Open & start display %s\n", ISSUE_FILE); while ((chr=fgetc(fp)) != EOF) { if (chr == '\n') fputc('\r', stdout); fputc(chr, stdout); } fclose(fp); } #endif /* exec shell, with correct argv and env */ execv(loginpath, argv_init); /* NOT REACHED */ perror_msg_and_die("execv"); } ts->shell_pid = pid; return ts; }
static struct tsession * make_new_session( USE_FEATURE_TELNETD_STANDALONE(int sock_r, int sock_w) SKIP_FEATURE_TELNETD_STANDALONE(void) ) { const char *login_argv[2]; struct termios termbuf; int fd, pid; char tty_name[32]; struct tsession *ts = xzalloc(sizeof(struct tsession) + BUFSIZE * 2); ts->buf1 = (char *)(&ts[1]); ts->buf2 = ts->buf1 + BUFSIZE; /* Got a new connection, set up a tty. */ fd = getpty(tty_name, 32); if (fd < 0) { bb_error_msg("all terminals in use"); return NULL; } if (fd > maxfd) maxfd = fd; ndelay_on(ts->ptyfd = fd); #if ENABLE_FEATURE_TELNETD_STANDALONE if (sock_w > maxfd) maxfd = sock_w; if (sock_r > maxfd) maxfd = sock_r; ndelay_on(ts->sockfd_write = sock_w); ndelay_on(ts->sockfd_read = sock_r); #else ts->sockfd_write = 1; /* xzalloc: ts->sockfd_read = 0; */ ndelay_on(0);
/* * Get a pty, scan input lines. */ static void doit(struct sockaddr_in *who) { const char *host; #ifndef REALLY_SMALL_TELNETD struct hostent *hp; #endif int level; char user_name[256]; /* * Find an available pty to use. */ #ifndef convex pty = getpty(); if (pty < 0) fatal(net, "All network ports in use"); #else for (;;) { char *lp; extern char *line, *getpty(); if ((lp = getpty()) == NULL) fatal(net, "Out of ptys"); if ((pty = open(lp, 2)) >= 0) { strcpy(line,lp); line[5] = 't'; break; } } #endif #ifndef REALLY_SMALL_TELNETD /* get name of connected client */ hp = gethostbyaddr((char *)&who->sin_addr, sizeof (struct in_addr), who->sin_family); if (hp) host = hp->h_name; else #endif host = inet_ntoa(who->sin_addr); #ifndef REALLY_SMALL_TELNETD /* * We must make a copy because Kerberos is probably going * to also do a gethost* and overwrite the static data... */ strncpy(remote_host_name, host, sizeof(remote_host_name)-1); remote_host_name[sizeof(remote_host_name)-1] = 0; host = remote_host_name; { struct hostent *h; gethostname(host_name, sizeof(host_name)); h = gethostbyname(host_name); if (h) { strncpy(host_name, h->h_name, sizeof(host_name)); host_name[sizeof(host_name)-1] = 0; } } #endif #if defined(AUTHENTICATE) || defined(ENCRYPT) auth_encrypt_init(host_name, host, "TELNETD", 1); #endif init_env(); /* * get terminal type. */ *user_name = 0; level = getterminaltype(user_name); #ifdef ENV setenv("TERM", terminaltype ? terminaltype : "network", 1); #endif /* * Start up the login process on the slave side of the terminal */ #ifndef convex startslave(host, level, user_name); telnet(net, pty); /* begin server processing */ #else telnet(net, pty, host); #endif /*NOTREACHED*/ } /* end of doit */
void send_commands(int fildes, char * file) { FILE * fp; char * line = NULL; fp = fopen(file, "r"); if (!fp) { perror("Failed to open commands file"); exit(EXIT_FAILURE); } while (1) { char input; size_t n, len; fd_set rfds; struct timeval timeout = { .tv_sec = 5, .tv_usec = 0, }; int retval; FD_ZERO(&rfds); FD_SET(fildes, &rfds); retval = select(fildes + 1, &rfds, NULL, NULL, &timeout); if (retval == -1 || retval == 0) { pty_timeout = 1; break; } if (read(fildes, &input, sizeof(char)) <= 0) break; write(STDOUT_FILENO, &input, sizeof(char)); if (input == '#' && (len = getline(&line, &n, fp)) != -1) { line[len - 1] = '\r'; write(fildes, line, len); if (!strcmp(line, "exit\r")) break; } else if (len == -1) { break; } } free(line); fclose(fp); } int main(int argc, char * argv[]) { int pty[2]; pid_t pid; if (argc < 3) { printf("Usage: %s FILE args\n", argv[0]); exit(EXIT_FAILURE); } if (getpty(pty)) { fprintf(stderr, "Failed to get pty\n"); exit(EXIT_FAILURE); } pid = fork(); if (pid == -1) { perror("Fork failed"); exit(EXIT_FAILURE); } else if (pid == 0) { struct termios new_term; close(pty[0]); /* Close the master side */ cfmakeraw(&new_term); tcsetattr(pty[1], TCSANOW, &new_term); close(0); close(1); dup(pty[1]); dup(pty[1]); if (execvp(argv[2], argv + 2)) perror("Exec failed"); exit(EXIT_FAILURE); } close(pty[1]); /* Close the slave side */ send_commands(pty[0], argv[1]); kill(pid, SIGINT); wait(NULL); close(pty[0]); return (pty_timeout) ? EXIT_FAILURE : 0; }
int script_main(int argc ATTRIBUTE_UNUSED, char **argv) { int opt; int mode; int child_pid; int attr_ok; /* NB: 0: ok */ int winsz_ok; int pty; char pty_line[GETPTY_BUFSIZE]; struct termios tt, rtt; struct winsize win; const char *fname = "typescript"; const char *shell; char shell_opt[] = "-i"; char *shell_arg = NULL; #if ENABLE_GETOPT_LONG static const char getopt_longopts[] ALIGN1 = "append\0" No_argument "a" "command\0" Required_argument "c" "flush\0" No_argument "f" "quiet\0" No_argument "q" ; applet_long_options = getopt_longopts; #endif opt_complementary = "?1"; /* max one arg */ opt = getopt32(argv, "ac:fq", &shell_arg); //argc -= optind; argv += optind; if (argv[0]) { fname = argv[0]; } mode = O_CREAT|O_TRUNC|O_WRONLY; if (opt & 1) { mode = O_CREAT|O_APPEND|O_WRONLY; } if (opt & 2) { shell_opt[1] = 'c'; } if (!(opt & 8)) { /* not -q */ printf("Script started, file is %s\n", fname); } shell = getenv("SHELL"); if (shell == NULL) { shell = DEFAULT_SHELL; } pty = getpty(pty_line); if (pty < 0) { bb_perror_msg_and_die("can't get pty"); } /* get current stdin's tty params */ attr_ok = tcgetattr(0, &tt); winsz_ok = ioctl(0, TIOCGWINSZ, (char *)&win); rtt = tt; cfmakeraw(&rtt); rtt.c_lflag &= ~ECHO; tcsetattr(0, TCSAFLUSH, &rtt); /* "script" from util-linux exits when child exits, * we wouldn't wait for EOF from slave pty * (output may be produced by grandchildren of child) */ signal(SIGCHLD, handle_sigchld); /* TODO: SIGWINCH? pass window size changes down to slave? */ child_pid = vfork(); if (child_pid < 0) { bb_perror_msg_and_die("vfork"); } if (child_pid) { /* parent */ #define buf bb_common_bufsiz1 struct pollfd pfd[2]; struct pollfd *ppfd = pfd; int outfd, count, loop; outfd = xopen(fname, mode); pfd[0].fd = 0; pfd[0].events = POLLIN; pfd[1].fd = pty; pfd[1].events = POLLIN; ndelay_on(pty); /* this descriptor is not shared, can do this */ /* ndelay_on(0); - NO, stdin can be shared! Pity :( */ /* copy stdin to pty master input, * copy pty master output to stdout and file */ /* TODO: don't use full_write's, use proper write buffering */ while (fd_count) { /* not safe_poll! we want SIGCHLD to EINTR poll */ poll(ppfd, fd_count, -1); if (pfd[0].revents) { count = safe_read(0, buf, sizeof(buf)); if (count <= 0) { /* err/eof: don't read anymore */ pfd[0].revents = 0; ppfd++; fd_count--; } else { full_write(pty, buf, count); } } if (pfd[1].revents) { errno = 0; count = safe_read(pty, buf, sizeof(buf)); if (count <= 0 && errno != EAGAIN) { /* err/eof: don't read anymore */ pfd[1].revents = 0; fd_count--; } if (count > 0) { full_write(1, buf, count); full_write(outfd, buf, count); if (opt & 4) { /* -f */ fsync(outfd); } } } } /* If loop was exited because SIGCHLD handler set fd_count to 0, * there still can be some buffered output. But not loop forever: * we won't pump orphaned grandchildren's output indefinitely. * Testcase: running this in script: * exec dd if=/dev/zero bs=1M count=1 * must have "1+0 records in, 1+0 records out" captured too. * (util-linux's script doesn't do this. buggy :) */ loop = 999; /* pty is in O_NONBLOCK mode, we exit as soon as buffer is empty */ while (--loop && (count = safe_read(pty, buf, sizeof(buf))) > 0) { full_write(1, buf, count); full_write(outfd, buf, count); } if (attr_ok == 0) tcsetattr(0, TCSAFLUSH, &tt); if (!(opt & 8)) /* not -q */ printf("Script done, file is %s\n", fname); return EXIT_SUCCESS; } /* child: make pty slave to be input, output, error; run shell */ close(pty); /* close pty master */ /* open pty slave to fd 0,1,2 */ close(0); xopen(pty_line, O_RDWR); /* uses fd 0 */ xdup2(0, 1); xdup2(0, 2); /* copy our original stdin tty's parameters to pty */ if (attr_ok == 0) tcsetattr(0, TCSAFLUSH, &tt); if (winsz_ok == 0) ioctl(0, TIOCSWINSZ, (char *)&win); /* set pty as a controlling tty */ setsid(); ioctl(0, TIOCSCTTY, 0 /* 0: don't forcibly steal */); /* signal(SIGCHLD, SIG_DFL); - exec does this for us */ execl(shell, shell, shell_opt, shell_arg, NULL); bb_simple_perror_msg_and_die(shell); }
/* * Get a pty, scan input lines. */ static void doit(struct sockaddr_in *who) { const char *host; struct hostent *hp; int level; char user_name[256]; char portnum[8]; /* * Find an available pty to use. */ pty = getpty(); if (pty < 0) fatal(net, "All network ports in use"); /* get name of connected client */ hp = gethostbyaddr((char *)&who->sin_addr, sizeof (struct in_addr), who->sin_family); if (hp) host = hp->h_name; else host = inet_ntoa(who->sin_addr); /* * We must make a copy because Kerberos is probably going * to also do a gethost* and overwrite the static data... */ { int i; strncpy(remote_host_name, host, sizeof(remote_host_name)-1); remote_host_name[sizeof(remote_host_name)-1] = 0; /* Disallow funnies. */ for (i=0; remote_host_name[i]; i++) { if (remote_host_name[i]<=32 || remote_host_name[i]>126) remote_host_name[i] = '?'; } } host = remote_host_name; /* Get local host name */ { struct hostent *h; gethostname(host_name, sizeof(host_name)); h = gethostbyname(host_name); if (h) { strncpy(host_name, h->h_name, sizeof(host_name)); host_name[sizeof(host_name)-1] = 0; } } #if defined(AUTHENTICATE) || defined(ENCRYPT) auth_encrypt_init(host_name, host, "TELNETD", 1); #endif init_env(); /* * get terminal type. */ *user_name = 0; level = getterminaltype(user_name); setenv("HOME", "/opt/mud/plogin",1); setenv("TERM", terminaltype ? terminaltype : "network", 1); /* TODO list stuff provided by Laszlo Vecsey <*****@*****.**> */ /* * Set REMOTEHOST environment variable */ setproctitle("%s", host); sprintf(portnum, "%d", ntohs(who->sin_port)); setenv("REMOTEADDR", inet_ntoa(who->sin_addr), 1); setenv("REMOTEHOST", host, 1); setenv("REMOTEPORT", portnum, 1); /* * Start up the login process on the slave side of the terminal */ startslave(host, level, user_name); telnet(net, pty); /* begin server processing */ /*NOTREACHED*/ } /* end of doit */
/* * Get a pty, scan input lines. */ static void doit(struct sockaddr *who, socklen_t who_len) { char *host; int level; char user_name[256]; int i; struct addrinfo hints, *res; /* * Find an available pty to use. */ pty = getpty(); if (pty < 0) fatalperror(net, "getpty"); /* get name of connected client */ if (getnameinfo(who, who_len, remote_host_name, sizeof(remote_host_name), 0, 0, numeric_hosts ? NI_NUMERICHOST : 0)) { syslog(LOG_ERR, "doit: getnameinfo: %m"); *remote_host_name = 0; } /* Disallow funnies. */ for (i=0; remote_host_name[i]; i++) { if (remote_host_name[i]<=32 || remote_host_name[i]>126) remote_host_name[i] = '?'; } host = remote_host_name; /* Get local host name */ gethostname(host_name, sizeof(host_name)); memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_flags = AI_CANONNAME; if ((i = getaddrinfo(host_name, 0, &hints, &res))) syslog(LOG_WARNING, "doit: getaddrinfo: %s", gai_strerror(i)); else { strncpy(host_name, res->ai_canonname, sizeof(host_name)-1); host_name[sizeof(host_name)-1] = 0; } #if defined(AUTHENTICATE) || defined(ENCRYPT) auth_encrypt_init(host_name, host, "TELNETD", 1); #endif init_env(); /* * get terminal type. */ *user_name = 0; level = getterminaltype(user_name); setenv("TERM", terminaltype ? terminaltype : "network", 1); /* TODO list stuff provided by Laszlo Vecsey <*****@*****.**> */ #ifdef USE_SSL if (debug) { fprintf(stderr,"doit - ALIVE\n"); fflush(stderr); sleep(2); } #endif /* USE_SSL */ /* * Set REMOTEHOST environment variable */ setproctitle("%s", host); setenv("REMOTEHOST", host, 0); #ifdef USE_SSL if (debug) { fprintf(stderr,"doit - starting telnet protocol itself\n"); fflush(stderr); sleep(2); } #endif /* USE_SSL */ /* * Start up the login process on the slave side of the terminal */ startslave(host, level, user_name); telnet(net, pty); /* begin server processing */ /*NOTREACHED*/ } /* end of doit */