void PTYPars::read_from_packet (CoreConnection* con) { u_int len; int n_bytes; #if 0 // FIXME if (s->ttyfd != -1) { packet_disconnect("Protocol error: you already have a pty."); return 0; } #endif const char* term2 = con-> packet_get_string(&len); term = term2; xfree ((void*) term2); col = con-> packet_get_int(); row = con-> packet_get_int(); xpixel = con-> packet_get_int(); ypixel = con-> packet_get_int(); #if 0 /* Allocate a pty and open it. */ debug("Allocating pty."); if (!PRIVSEP(pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty)))) { if (s->term) xfree(s->term); s->term = NULL; s->ptyfd = -1; s->ttyfd = -1; error("session_pty_req: session %d alloc failed", s->self); return 0; } debug("session_pty_req: session %d alloc %s", s->self, s->tty); #endif PTY::tty_parse_modes(con, &n_bytes); #if 0 /* Set window size from the packet. */ pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel); #endif packet_check_eom (con); }
bool XSERDPort::open_pty(void) { // Talk to a process via a pty char slave[128]; int slavefd; protocol = pty; if (!pty_allocate(&fd, &slavefd, slave, sizeof(slave))) return false; fflush(stdout); fflush(stderr); switch (pid = fork()) { case -1: // error return false; break; case 0: // child ::close(fd); /* Make the pseudo tty our controlling tty. */ pty_make_controlling_tty(&slavefd, slave); ::close(0); dup(slavefd); // Use the slave fd for stdin, ::close(1); dup(slavefd); // stdout, ::close(2); dup(slavefd); // and stderr. // <should we be more paranoid about closing unused fds?> // <should we drop privileges if running setuid?> // Let the shell do the dirty work execlp("/bin/sh", "/bin/sh", "-c", ++device_name, (char *)NULL); // exec failed! printf("serial_open: could not exec %s: %s\n", "/bin/sh", strerror(errno)); exit(1); break; default: // parent // Pid was stored above break; } return true; }
int mm_answer_pty(int sock, Buffer *m) { extern struct monitor *pmonitor; Session *s; int res, fd0; debug3("%s entering", __func__); buffer_clear(m); s = session_new(); if (s == NULL) goto error; s->authctxt = authctxt; s->pw = authctxt->pw; s->pid = pmonitor->m_pid; res = pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty)); if (res == 0) goto error; pty_setowner(authctxt->pw, s->tty); buffer_put_int(m, 1); buffer_put_cstring(m, s->tty); /* We need to trick ttyslot */ if (dup2(s->ttyfd, 0) == -1) fatal("%s: dup2", __func__); mm_record_login(s, authctxt->pw); /* Now we can close the file descriptor again */ close(0); /* send messages generated by record_login */ buffer_put_string(m, buffer_ptr(&loginmsg), buffer_len(&loginmsg)); buffer_clear(&loginmsg); mm_request_send(sock, MONITOR_ANS_PTY, m); mm_send_fd(sock, s->ptyfd); mm_send_fd(sock, s->ttyfd); /* make sure nothing uses fd 0 */ if ((fd0 = open(_PATH_DEVNULL, O_RDONLY)) < 0) fatal("%s: open(/dev/null): %s", __func__, strerror(errno)); if (fd0 != 0) error("%s: fd0 %d != 0", __func__, fd0); /* slave is not needed */ close(s->ttyfd); s->ttyfd = s->ptyfd; /* no need to dup() because nobody closes ptyfd */ s->ptymaster = s->ptyfd; debug3("%s: tty %s ptyfd %d", __func__, s->tty, s->ttyfd); return (0); error: if (s != NULL) mm_session_close(s); buffer_put_int(m, 0); mm_request_send(sock, MONITOR_ANS_PTY, m); return (0); }
static int connect_local(CLI *c) { /* spawn local process */ #if defined (USE_WIN32) || defined (__vms) s_log(LOG_ERR, "LOCAL MODE NOT SUPPORTED ON WIN32 and OpenVMS PLATFORM"); return -1; #else /* USE_WIN32, __vms */ char env[3][STRLEN], name[STRLEN], *portname; int fd[2], pid; X509 *peer; #ifdef HAVE_PTHREAD_SIGMASK sigset_t newmask; #endif if (c->opt->option.pty) { char tty[STRLEN]; if(pty_allocate(fd, fd+1, tty, STRLEN)) { return -1; } s_log(LOG_DEBUG, "%s allocated", tty); } else { if(make_sockets(fd)) return -1; } pid=fork(); c->pid=(unsigned long)pid; switch(pid) { case -1: /* error */ closesocket(fd[0]); closesocket(fd[1]); ioerror("fork"); return -1; case 0: /* child */ closesocket(fd[0]); dup2(fd[1], 0); dup2(fd[1], 1); if(!options.option.foreground) dup2(fd[1], 2); closesocket(fd[1]); safecopy(env[0], "REMOTE_HOST="); safeconcat(env[0], c->accepting_address); portname=strrchr(env[0], ':'); if(portname) /* strip the port name */ *portname='\0'; putenv(env[0]); if(c->opt->option.transparent) { putenv("LD_PRELOAD=" LIBDIR "/libstunnel.so"); /* For Tru64 _RLD_LIST is used instead */ putenv("_RLD_LIST=" LIBDIR "/libstunnel.so:DEFAULT"); } if(c->ssl) { peer=SSL_get_peer_certificate(c->ssl); if(peer) { safecopy(env[1], "SSL_CLIENT_DN="); X509_NAME_oneline(X509_get_subject_name(peer), name, STRLEN); safestring(name); safeconcat(env[1], name); putenv(env[1]); safecopy(env[2], "SSL_CLIENT_I_DN="); X509_NAME_oneline(X509_get_issuer_name(peer), name, STRLEN); safestring(name); safeconcat(env[2], name); putenv(env[2]); X509_free(peer); } } #ifdef HAVE_PTHREAD_SIGMASK sigemptyset(&newmask); sigprocmask(SIG_SETMASK, &newmask, NULL); #endif execvp(c->opt->execname, c->opt->execargs); ioerror(c->opt->execname); /* execv failed */ _exit(1); default: break; } /* parent */ s_log(LOG_INFO, "Local mode child started (PID=%lu)", c->pid); closesocket(fd[1]); #ifdef FD_CLOEXEC fcntl(fd[0], F_SETFD, FD_CLOEXEC); #endif return fd[0]; #endif /* USE_WIN32,__vms */ }
/* Set up a session pty which will be used to execute the shell or program. * The pty is allocated now, and kept for when the shell/program executes. * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ static int sessionpty(struct ChanSess * chansess) { unsigned int termlen; unsigned char namebuf[65]; struct termios termio; TRACE(("enter sessionpty")); chansess->term = buf_getstring(ses.payload, &termlen); if (termlen > MAX_TERM_LEN) { /* TODO send disconnect ? */ TRACE(("leave sessionpty: term len too long")); return DROPBEAR_FAILURE; } chansess->termc = buf_getint(ses.payload); chansess->termr = buf_getint(ses.payload); chansess->termw = buf_getint(ses.payload); chansess->termh = buf_getint(ses.payload); /* allocate the pty */ assert(chansess->master == -1); /* haven't already got one */ if (pty_allocate(&chansess->master, &chansess->slave, namebuf, 64) == 0) { TRACE(("leave sessionpty: failed to allocate pty")); return DROPBEAR_FAILURE; } chansess->tty = (char*)strdup(namebuf); if (!chansess->tty) { dropbear_exit("out of memory"); /* TODO disconnect */ } pty_setowner(ses.authstate.pw, chansess->tty); pty_change_window_size(chansess->master, chansess->termr, chansess->termc, chansess->termw, chansess->termh); /* Term modes */ /* We'll ignore errors and continue if we can't set modes. * We're ignoring baud rates since they seem evil */ if (tcgetattr(chansess->master, &termio) == 0) { unsigned char opcode; unsigned int value; const struct TermCode * termcode; while (((opcode = buf_getbyte(ses.payload)) != 0x00) && opcode <= 159) { /* handle types of code */ if (opcode > MAX_TERMCODE) { continue; } termcode = &termcodes[(unsigned int)opcode]; value = buf_getint(ses.payload); switch (termcode->type) { case TERMCODE_NONE: break; case TERMCODE_CONTROLCHAR: termio.c_cc[termcode->mapcode] = value; break; case TERMCODE_INPUT: if (value) { termio.c_iflag |= termcode->mapcode; } else { termio.c_iflag &= ~(termcode->mapcode); } break; case TERMCODE_OUTPUT: if (value) { termio.c_oflag |= termcode->mapcode; } else { termio.c_oflag &= ~(termcode->mapcode); } break; case TERMCODE_LOCAL: if (value) { termio.c_lflag |= termcode->mapcode; } else { termio.c_lflag &= ~(termcode->mapcode); } break; case TERMCODE_CONTROL: if (value) { termio.c_cflag |= termcode->mapcode; } else { termio.c_cflag &= ~(termcode->mapcode); } break; } } if (tcsetattr(chansess->master, TCSANOW, &termio) < 0) { dropbear_log(LOG_INFO, "error setting terminal attributes"); } } TRACE(("leave sessionpty")); return DROPBEAR_SUCCESS; }
static int connect_local(CLI *c) { /* spawn local process */ char *name, *portname; int fd[2], pid; X509 *peer; #ifdef HAVE_PTHREAD_SIGMASK sigset_t newmask; #endif if(c->opt->option.pty) { char tty[64]; if(pty_allocate(fd, fd+1, tty)) longjmp(c->err, 1); s_log(LOG_DEBUG, "TTY=%s allocated", tty); } else make_sockets(c, fd); pid=fork(); c->pid=(unsigned long)pid; switch(pid) { case -1: /* error */ closesocket(fd[0]); closesocket(fd[1]); ioerror("fork"); longjmp(c->err, 1); case 0: /* child */ closesocket(fd[0]); set_nonblock(fd[1], 0); /* switch back to blocking mode */ /* dup2() does not copy FD_CLOEXEC flag */ dup2(fd[1], 0); dup2(fd[1], 1); if(!global_options.option.foreground) dup2(fd[1], 2); closesocket(fd[1]); /* not really needed due to FD_CLOEXEC */ name=str_dup(c->accepted_address); portname=strrchr(name, ':'); if(portname) /* strip the port name */ *portname='\0'; putenv(str_printf("REMOTE_HOST=%s", name)); if(c->opt->option.transparent_src) { putenv("LD_PRELOAD=" LIBDIR "/libstunnel.so"); /* for Tru64 _RLD_LIST is used instead */ putenv("_RLD_LIST=" LIBDIR "/libstunnel.so:DEFAULT"); } if(c->ssl) { peer=SSL_get_peer_certificate(c->ssl); if(peer) { name=X509_NAME_oneline(X509_get_subject_name(peer), NULL, 0); safestring(name); putenv(str_printf("SSL_CLIENT_DN=%s", name)); name=X509_NAME_oneline(X509_get_issuer_name(peer), NULL, 0); safestring(name); putenv(str_printf("SSL_CLIENT_I_DN=%s", name)); X509_free(peer); } } #ifdef HAVE_PTHREAD_SIGMASK sigemptyset(&newmask); sigprocmask(SIG_SETMASK, &newmask, NULL); #endif execvp(c->opt->execname, c->opt->execargs); ioerror(c->opt->execname); /* execv failed */ _exit(1); default: /* parent */ s_log(LOG_INFO, "Local mode child started (PID=%lu)", c->pid); closesocket(fd[1]); return fd[0]; } }
NOEXPORT int connect_local(CLI *c) { /* spawn local process */ char *name, host[40]; int fd[2], pid; X509 *peer; #ifdef HAVE_PTHREAD_SIGMASK sigset_t newmask; #endif if(c->opt->option.pty) { char tty[64]; if(pty_allocate(fd, fd+1, tty)) longjmp(c->err, 1); s_log(LOG_DEBUG, "TTY=%s allocated", tty); } else if(make_sockets(fd)) longjmp(c->err, 1); pid=fork(); c->pid=(unsigned long)pid; switch(pid) { case -1: /* error */ closesocket(fd[0]); closesocket(fd[1]); ioerror("fork"); longjmp(c->err, 1); case 0: /* child */ closesocket(fd[0]); set_nonblock(fd[1], 0); /* switch back to blocking mode */ /* dup2() does not copy FD_CLOEXEC flag */ dup2(fd[1], 0); dup2(fd[1], 1); if(!global_options.option.foreground) dup2(fd[1], 2); closesocket(fd[1]); /* not really needed due to FD_CLOEXEC */ if(!getnameinfo(&c->peer_addr.sa, c->peer_addr_len, host, 40, NULL, 0, NI_NUMERICHOST)) { /* just don't set these variables if getnameinfo() fails */ putenv(str_printf("REMOTE_HOST=%s", host)); if(c->opt->option.transparent_src) { #ifndef LIBDIR #define LIBDIR "." #endif #ifdef MACH64 putenv("LD_PRELOAD_32=" LIBDIR "/libstunnel.so"); putenv("LD_PRELOAD_64=" LIBDIR "/" MACH64 "/libstunnel.so"); #elif __osf /* for Tru64 _RLD_LIST is used instead */ putenv("_RLD_LIST=" LIBDIR "/libstunnel.so:DEFAULT"); #else putenv("LD_PRELOAD=" LIBDIR "/libstunnel.so"); #endif } } if(c->ssl) { peer=SSL_get_peer_certificate(c->ssl); if(peer) { name=X509_NAME_oneline(X509_get_subject_name(peer), NULL, 0); safestring(name); putenv(str_printf("SSL_CLIENT_DN=%s", name)); name=X509_NAME_oneline(X509_get_issuer_name(peer), NULL, 0); safestring(name); putenv(str_printf("SSL_CLIENT_I_DN=%s", name)); X509_free(peer); } } #ifdef HAVE_PTHREAD_SIGMASK sigemptyset(&newmask); sigprocmask(SIG_SETMASK, &newmask, NULL); #endif signal(SIGCHLD, SIG_DFL); signal(SIGHUP, SIG_DFL); signal(SIGUSR1, SIG_DFL); signal(SIGPIPE, SIG_DFL); signal(SIGTERM, SIG_DFL); signal(SIGQUIT, SIG_DFL); signal(SIGINT, SIG_DFL); execvp(c->opt->execname, c->opt->execargs); ioerror(c->opt->execname); /* execvp failed */ _exit(1); default: /* parent */ s_log(LOG_INFO, "Local mode child started (PID=%lu)", c->pid); closesocket(fd[1]); return fd[0]; } }