1c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley/* telnetd.c - Telnet Server 2c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley * 3c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley * Copyright 2013 Sandeep Sharma <sandeep.jack2756@gmail.com> 4c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley * Copyright 2013 Kyungwan Han <asura321@gmail.com> 5c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley * 6c3cc96479f0ccadb48731d15b7236b82bd6278eaRob LandleyUSE_TELNETD(NEWTOY(telnetd, "w#<0b:p#<0>65535=23f:l:FSKi[!wi]", TOYFLAG_USR|TOYFLAG_BIN)) 7c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 8c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landleyconfig TELNETD 9c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley bool "telnetd" 10c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley default n 11c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley help 12c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley Handle incoming telnet connections 13c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 14c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley -l LOGIN Exec LOGIN on connect 15c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley -f ISSUE_FILE Display ISSUE_FILE instead of /etc/issue 16c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley -K Close connection as soon as login exits 17c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley -p PORT Port to listen on 18c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley -b ADDR[:PORT] Address to bind to 19c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley -F Run in foreground 20c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley -i Inetd mode 21c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley -w SEC Inetd 'wait' mode, linger time SEC 22c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley -S Log to syslog (implied by -i or without -F and -w) 23c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley*/ 24c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 25c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley#define FOR_telnetd 26c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley#include "toys.h" 27c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley#include <utmp.h> 28c3cc96479f0ccadb48731d15b7236b82bd6278eaRob LandleyGLOBALS( 29c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley char *login_path; 30c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley char *issue_path; 31c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley int port; 32c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley char *host_addr; 33c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley long w_sec; 34c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 35c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley int gmax_fd; 36c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley pid_t fork_pid; 37c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley) 38c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 39c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 40c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley# define IAC 255 /* interpret as command: */ 41c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley# define DONT 254 /* you are not to use option */ 42c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley# define DO 253 /* please, you use option */ 43c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley# define WONT 252 /* I won't use option */ 44c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley# define WILL 251 /* I will use option */ 45c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley# define SB 250 /* interpret as subnegotiation */ 46c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley# define SE 240 /* end sub negotiation */ 47c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley# define NOP 241 /* No Operation */ 48c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley# define TELOPT_ECHO 1 /* echo */ 49c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley# define TELOPT_SGA 3 /* suppress go ahead */ 50c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley# define TELOPT_TTYPE 24 /* terminal type */ 51c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley# define TELOPT_NAWS 31 /* window size */ 52c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 53c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley#define BUFSIZE 4*1024 54c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landleystruct term_session { 55c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley int new_fd, pty_fd; 56c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley pid_t child_pid; 57c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley int buff1_avail, buff2_avail; 58c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley int buff1_written, buff2_written; 59c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley int rem; //unprocessed data from socket 60c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley char buff1[BUFSIZE], buff2[BUFSIZE]; 61c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley struct term_session *next; 62c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley}; 63c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 64c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landleystruct term_session *session_list = NULL; 65c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 66c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landleystatic void get_sockaddr(char *host, void *buf) 67c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley{ 68c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley in_port_t port_num = htons(TT.port); 69c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley struct addrinfo hints, *result; 70c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley int status, af = AF_UNSPEC; 71c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley char *s; 72c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 73c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley // [ipv6]:port or exactly one : 74c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (*host == '[') { 75c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley host++; 76c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley s = strchr(host, ']'); 77c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (s) *s++ = 0; 78c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley else error_exit("bad address '%s'", host-1); 79c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley af = AF_INET6; 80c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley } else { 81c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley s = strrchr(host, ':'); 82c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (s && strchr(host, ':') == s) { 83c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley *s = 0; 84c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley af = AF_INET; 85c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley } else if (s && strchr(host, ':') != s) { 86c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley af = AF_INET6; 87c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley s = 0; 88c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley } 89c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley } 90c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 91c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (s++) { 92c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley char *ss; 93c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley unsigned long p = strtoul(s, &ss, 0); 94c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (!*s || *ss || p > 65535) error_exit("bad port '%s'", s); 95c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley port_num = htons(p); 96c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley } 97c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 98c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley memset(&hints, 0 , sizeof(struct addrinfo)); 99c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley hints.ai_family = af; 100c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley hints.ai_socktype = SOCK_STREAM; 101c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 102c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley status = getaddrinfo(host, NULL, &hints, &result); 103c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (status) error_exit("bad address '%s' : %s", host, gai_strerror(status)); 104c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 105c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley memcpy(buf, result->ai_addr, result->ai_addrlen); 106c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley freeaddrinfo(result); 107c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 108c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (af == AF_INET) ((struct sockaddr_in*)buf)->sin_port = port_num; 109c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley else ((struct sockaddr_in6*)buf)->sin6_port = port_num; 110c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley} 111c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 112bf30fe981772d97e6399b3ce9aeafffe35848c89Rob Landleystatic void utmp_entry(void) 113c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley{ 114c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley struct utmp entry; 115c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley struct utmp *utp_ptr; 116c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley pid_t pid = getpid(); 117c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 118c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley utmpname(_PATH_UTMP); 119c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley setutent(); //start from start 120c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley while ((utp_ptr = getutent()) != NULL) { 121c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (utp_ptr->ut_pid == pid && utp_ptr->ut_type >= INIT_PROCESS) break; 122c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley } 123c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (!utp_ptr) entry.ut_type = DEAD_PROCESS; 124c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley time(&entry.ut_time); 125c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley setutent(); 126c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley pututline(&entry); 127c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley} 128c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 129c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landleystatic int listen_socket(void) 130c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley{ 131c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley int s, af = AF_INET, yes = 1; 132c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley char buf[sizeof(struct sockaddr_storage)]; 133c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 134c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley memset(buf, 0, sizeof(buf)); 135c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (toys.optflags & FLAG_b) { 136c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley get_sockaddr(TT.host_addr, buf); 137c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley af = ((struct sockaddr *)buf)->sa_family; 138c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley } else { 139c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley ((struct sockaddr_in*)buf)->sin_port = htons(TT.port); 140c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley ((struct sockaddr_in*)buf)->sin_family = af; 141c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley } 142c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley s = xsocket(af, SOCK_STREAM, 0); 143c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) == -1) 144c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley perror_exit("setsockopt"); 145c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 146c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (bind(s, (struct sockaddr *)buf, ((af == AF_INET)? 147c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley (sizeof(struct sockaddr_in)):(sizeof(struct sockaddr_in6)))) == -1) { 148c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley close(s); 149c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley perror_exit("bind"); 150c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley } 151c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 152c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (listen(s, 1) < 0) perror_exit("listen"); 153c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley return s; 154c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley} 155c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 156c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landleystatic void write_issue(char *tty) 157c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley{ 158c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley int size; 159c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley char ch = 0; 160c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley struct utsname u; 161c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley int fd = open(TT.issue_path, O_RDONLY); 162c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 163c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (fd < 0) return ; 164c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley uname(&u); 165c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley while ((size = readall(fd, &ch, 1)) > 0) { 166c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (ch == '\\' || ch == '%') { 167c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (readall(fd, &ch, 1) <= 0) perror_exit("readall!"); 168c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (ch == 's') fputs(u.sysname, stdout); 169c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (ch == 'n'|| ch == 'h') fputs(u.nodename, stdout); 170c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (ch == 'r') fputs(u.release, stdout); 171c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (ch == 'm') fputs(u.machine, stdout); 172c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (ch == 'l') fputs(tty, stdout); 173c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley } 174c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley else if (ch == '\n') { 175c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley fputs("\n\r\0", stdout); 176c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley } else fputc(ch, stdout); 177c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley } 178c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley fflush(NULL); 179c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley close(fd); 180c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley} 181c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 182c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landleystatic int new_session(int sockfd) 183c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley{ 184c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley char *argv_login[2]; //arguments for execvp cmd, NULL 185c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley char tty_name[30]; //tty name length. 186c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley int fd, flags, i = 1; 187c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley char intial_iacs[] = {IAC, DO, TELOPT_ECHO, IAC, DO, TELOPT_NAWS, 188c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley IAC, WILL, TELOPT_ECHO, IAC, WILL, TELOPT_SGA }; 189c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 190c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &i, sizeof(i)); 191c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley flags = fcntl(sockfd, F_GETFL); 192c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); 193c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (toys.optflags & FLAG_i) fcntl((sockfd + 1), F_SETFL, flags | O_NONBLOCK); 194c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 195c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley writeall((toys.optflags & FLAG_i)?1:sockfd, intial_iacs, sizeof(intial_iacs)); 196c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if ((TT.fork_pid = forkpty(&fd, tty_name, NULL, NULL)) > 0) { 197c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley flags = fcntl(fd, F_GETFL); 198c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley fcntl(fd, F_SETFL, flags | O_NONBLOCK); 199c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley return fd; 200c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley } 201c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (TT.fork_pid < 0) perror_exit("fork"); 202c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley write_issue(tty_name); 203c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley argv_login[0] = strdup(TT.login_path); 204c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley argv_login[1] = NULL; 205c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley execvp(argv_login[0], argv_login); 206c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley exit(EXIT_FAILURE); 207c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley} 208c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 209c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landleystatic int handle_iacs(struct term_session *tm, int c, int fd) 210c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley{ 211c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley char *curr ,*start,*end; 212c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley int i = 0; 213c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 214c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley curr = start = tm->buff2+tm->buff2_avail; 215c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley end = tm->buff2 + c -1; 216c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley tm->rem = 0; 217c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley while (curr <= end) { 218c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (*curr != IAC){ 219c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 220c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (*curr != '\r') { 221c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley toybuf[i++] = *curr++; 222c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley continue; 223c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley } else { 224c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley toybuf[i++] = *curr++; 225c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley curr++; 226c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (curr < end && (*curr == '\n' || *curr == '\0')) 227c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley curr++; 228c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley continue; 229c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley } 230c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley } 231c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 232c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if ((curr + 1) > end) { 233c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley tm->rem = 1; 234c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley break; 235c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley } 236c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (*(curr+1) == IAC) { //IAC as data --> IAC IAC 237c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley toybuf[i++] = *(curr+1); 238c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley curr += 2; //IAC IAC --> 2 bytes 239c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley continue; 240c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley } 241c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (*(curr + 1) == NOP || *(curr + 1) == SE) { 242c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley curr += 2; 243c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley continue; 244c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley } 245c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 246c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (*(curr + 1) == SB ) { 247c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (*(curr+2) == TELOPT_NAWS) { 248c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley struct winsize ws; 249c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if ((curr+8) >= end) { //ensure we have data to process. 250c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley tm->rem = end - curr; 251c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley break; 252c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley } 253c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley ws.ws_col = (curr[3] << 8) | curr[4]; 254c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley ws.ws_row = (curr[5] << 8) | curr[6]; 255c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley ioctl(fd, TIOCSWINSZ, (char *)&ws); 256c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley curr += 9; 257c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley continue; 258c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley } else { //eat non-supported sub neg. options. 259c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley curr++, tm->rem++; 260c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley while (*curr != IAC && curr <= end) { 261c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley curr++; 262c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley tm->rem++; 263c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley } 264c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (*curr == IAC) { 265c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley tm->rem = 0; 266c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley continue; 267c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley } else break; 268c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley } 269c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley } 270c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley curr += 3; //skip non-supported 3 bytes. 271c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley } 272c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley memcpy(start, toybuf, i); 273c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley memcpy(start + i, end - tm->rem, tm->rem); //put remaining if we break; 274c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley return i; 275c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley} 276c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 277c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landleystatic int dup_iacs(char *start, int fd, int len) 278c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley{ 279c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley char arr[] = {IAC, IAC}; 280c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley char *needle = NULL; 281c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley int ret = 0, c, count = 0; 282c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 283c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley while (len) { 284c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (*start == IAC) { 285c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley count = writeall(fd, arr, sizeof(arr)); 286c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (count != 2) break; //short write 287c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley start++; 288c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley ret++; 289c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley len--; 290c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley continue; 291c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley } 292c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley needle = memchr(start, IAC, len); 293c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (needle) c = needle - start; 294c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley else c = len; 295c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley count = writeall(fd, start, c); 296c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (count < 0) break; 297c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley len -= count; 298c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley ret += count; 299c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley start += count; 300c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley } 301c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley return ret; 302c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley} 303c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 304c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landleyvoid telnetd_main(void) 305c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley{ 306c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley errno = 0; 307c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley fd_set rd, wr; 308c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley struct term_session *tm = NULL; 309c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley struct timeval tv, *tv_ptr = NULL; 310c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley int pty_fd, new_fd, c = 0, w, master_fd = 0; 311bf30fe981772d97e6399b3ce9aeafffe35848c89Rob Landley int inetd_m = toys.optflags & FLAG_i; 312c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 313c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (!(toys.optflags & FLAG_l)) TT.login_path = "/bin/login"; 314c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (!(toys.optflags & FLAG_f)) TT.issue_path = "/etc/issue.net"; 315c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (toys.optflags & FLAG_w) toys.optflags |= FLAG_F; 316c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (!inetd_m) { 317c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley master_fd = listen_socket(); 318c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley fcntl(master_fd, F_SETFD, FD_CLOEXEC); 319c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (master_fd > TT.gmax_fd) TT.gmax_fd = master_fd; 320c880061f511e85d55afe3966f5eda0df7c3ebb56Rob Landley if (!(toys.optflags & FLAG_F)) daemon(0, 0); 321c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley } else { 322c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley pty_fd = new_session(master_fd); //master_fd = 0 323c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (pty_fd > TT.gmax_fd) TT.gmax_fd = pty_fd; 324c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley tm = xzalloc(sizeof(struct term_session)); 325c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley tm->child_pid = TT.fork_pid; 326c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley tm->new_fd = 0; 327c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley tm->pty_fd = pty_fd; 328c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (session_list) { 329c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley tm->next = session_list; 330c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley session_list = tm; 331c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley } else session_list = tm; 332c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley } 333c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 334c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if ((toys.optflags & FLAG_w) && !session_list) { 335c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley tv.tv_sec = TT.w_sec; 336c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley tv.tv_usec = 0; 337c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley tv_ptr = &tv; 338c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley } 339bf30fe981772d97e6399b3ce9aeafffe35848c89Rob Landley signal(SIGCHLD, generic_signal); 340c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 341c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley for (;;) { 342c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley FD_ZERO(&rd); 343c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley FD_ZERO(&wr); 344c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (!inetd_m) FD_SET(master_fd, &rd); 345c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 346c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley tm = session_list; 347c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley while (tm) { 348c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 349c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (tm->pty_fd > 0 && tm->buff1_avail < BUFSIZE) FD_SET(tm->pty_fd, &rd); 350c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (tm->new_fd >= 0 && tm->buff2_avail < BUFSIZE) FD_SET(tm->new_fd, &rd); 351c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (tm->pty_fd > 0 && (tm->buff2_avail - tm->buff2_written) > 0) 352c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley FD_SET(tm->pty_fd, &wr); 353c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (tm->new_fd >= 0 && (tm->buff1_avail - tm->buff1_written) > 0) 354c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley FD_SET(tm->new_fd, &wr); 355c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley tm = tm->next; 356c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley } 357c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 358c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 359c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley int r = select(TT.gmax_fd + 1, &rd, &wr, NULL, tv_ptr); 360c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (!r) return; //timeout 361c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (r < -1) continue; 362c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 363c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (!inetd_m && FD_ISSET(master_fd, &rd)) { //accept new connection 364c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley new_fd = accept(master_fd, NULL, NULL); 365c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (new_fd < 0) continue; 366c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley tv_ptr = NULL; 367c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley fcntl(new_fd, F_SETFD, FD_CLOEXEC); 368c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (new_fd > TT.gmax_fd) TT.gmax_fd = new_fd; 369c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley pty_fd = new_session(new_fd); 370c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (pty_fd > TT.gmax_fd) TT.gmax_fd = pty_fd; 371c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 372c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley tm = xzalloc(sizeof(struct term_session)); 373c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley tm->child_pid = TT.fork_pid; 374c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley tm->new_fd = new_fd; 375c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley tm->pty_fd = pty_fd; 376c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (session_list) { 377c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley tm->next = session_list; 378c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley session_list = tm; 379c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley } else session_list = tm; 380c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley } 381c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley 382c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley tm = session_list; 383c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley for (;tm;tm=tm->next) { 384c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (FD_ISSET(tm->pty_fd, &rd)) { 385c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if ((c = read(tm->pty_fd, tm->buff1 + tm->buff1_avail, 386c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley BUFSIZE-tm->buff1_avail)) <= 0) break; 387c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley tm->buff1_avail += c; 388c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if ((w = dup_iacs(tm->buff1 + tm->buff1_written, tm->new_fd + inetd_m, 389c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley tm->buff1_avail - tm->buff1_written)) < 0) break; 390c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley tm->buff1_written += w; 391c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley } 392c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (FD_ISSET(tm->new_fd, &rd)) { 393c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if ((c = read(tm->new_fd, tm->buff2+tm->buff2_avail, 394c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley BUFSIZE-tm->buff2_avail)) <= 0) break; 395c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley c = handle_iacs(tm, c, tm->pty_fd); 396c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley tm->buff2_avail += c; 397c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if ((w = write(tm->pty_fd, tm->buff2+ tm->buff2_written, 398c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley tm->buff2_avail - tm->buff2_written)) < 0) break; 399c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley tm->buff2_written += w; 400c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley } 401c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (FD_ISSET(tm->pty_fd, &wr)) { 402c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if ((w = write(tm->pty_fd, tm->buff2 + tm->buff2_written, 403c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley tm->buff2_avail - tm->buff2_written)) < 0) break; 404c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley tm->buff2_written += w; 405c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley } 406c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (FD_ISSET(tm->new_fd, &wr)) { 407c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if ((w = dup_iacs(tm->buff1 + tm->buff1_written, tm->new_fd + inetd_m, 408c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley tm->buff1_avail - tm->buff1_written)) < 0) break; 409c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley tm->buff1_written += w; 410c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley } 411c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (tm->buff1_written == tm->buff1_avail) 412c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley tm->buff1_written = tm->buff1_avail = 0; 413c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley if (tm->buff2_written == tm->buff2_avail) 414c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley tm->buff2_written = tm->buff2_avail = 0; 415c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley fflush(NULL); 416c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley } 417bf30fe981772d97e6399b3ce9aeafffe35848c89Rob Landley 418bf30fe981772d97e6399b3ce9aeafffe35848c89Rob Landley // Loop to handle (unknown number of) SIGCHLD notifications 419bf30fe981772d97e6399b3ce9aeafffe35848c89Rob Landley while (toys.signal) { 420bf30fe981772d97e6399b3ce9aeafffe35848c89Rob Landley int status; 421bf30fe981772d97e6399b3ce9aeafffe35848c89Rob Landley struct term_session *prev = NULL; 422bf30fe981772d97e6399b3ce9aeafffe35848c89Rob Landley pid_t pid; 423bf30fe981772d97e6399b3ce9aeafffe35848c89Rob Landley 424bf30fe981772d97e6399b3ce9aeafffe35848c89Rob Landley // funny little dance to avoid race conditions. 425bf30fe981772d97e6399b3ce9aeafffe35848c89Rob Landley toys.signal = 0; 426bf30fe981772d97e6399b3ce9aeafffe35848c89Rob Landley pid = waitpid(-1, &status, WNOHANG); 427bf30fe981772d97e6399b3ce9aeafffe35848c89Rob Landley if (pid < 0) break; 428bf30fe981772d97e6399b3ce9aeafffe35848c89Rob Landley toys.signal++; 429bf30fe981772d97e6399b3ce9aeafffe35848c89Rob Landley 430bf30fe981772d97e6399b3ce9aeafffe35848c89Rob Landley 431bf30fe981772d97e6399b3ce9aeafffe35848c89Rob Landley for (tm = session_list; tm; tm = tm->next) { 432bf30fe981772d97e6399b3ce9aeafffe35848c89Rob Landley if (tm->child_pid == pid) break; 433bf30fe981772d97e6399b3ce9aeafffe35848c89Rob Landley prev = tm; 434bf30fe981772d97e6399b3ce9aeafffe35848c89Rob Landley } 435bf30fe981772d97e6399b3ce9aeafffe35848c89Rob Landley if (!tm) return; // reparented child we don't care about 436bf30fe981772d97e6399b3ce9aeafffe35848c89Rob Landley 437bf30fe981772d97e6399b3ce9aeafffe35848c89Rob Landley if (toys.optflags & FLAG_i) exit(EXIT_SUCCESS); 438bf30fe981772d97e6399b3ce9aeafffe35848c89Rob Landley if (!prev) session_list = session_list->next; 439bf30fe981772d97e6399b3ce9aeafffe35848c89Rob Landley else prev->next = tm->next; 440bf30fe981772d97e6399b3ce9aeafffe35848c89Rob Landley utmp_entry(); 441bf30fe981772d97e6399b3ce9aeafffe35848c89Rob Landley xclose(tm->pty_fd); 442bf30fe981772d97e6399b3ce9aeafffe35848c89Rob Landley xclose(tm->new_fd); 443bf30fe981772d97e6399b3ce9aeafffe35848c89Rob Landley free(tm); 444bf30fe981772d97e6399b3ce9aeafffe35848c89Rob Landley } 445c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley } 446c3cc96479f0ccadb48731d15b7236b82bd6278eaRob Landley} 447