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