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