nslookup: set default DNS server again. Hopefully helps with 675
[platform/upstream/busybox.git] / networking / telnetd.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Simple telnet server
4  * Bjorn Wesen, Axis Communications AB (bjornw@axis.com)
5  *
6  * Licensed under GPLv2 or later, see file LICENSE in this source tree.
7  *
8  * ---------------------------------------------------------------------------
9  * (C) Copyright 2000, Axis Communications AB, LUND, SWEDEN
10  ****************************************************************************
11  *
12  * The telnetd manpage says it all:
13  *
14  * Telnetd operates by allocating a pseudo-terminal device (see pty(4)) for
15  * a client, then creating a login process which has the slave side of the
16  * pseudo-terminal as stdin, stdout, and stderr. Telnetd manipulates the
17  * master side of the pseudo-terminal, implementing the telnet protocol and
18  * passing characters between the remote client and the login process.
19  *
20  * Vladimir Oleynik <dzo@simtreas.ru> 2001
21  * Set process group corrections, initial busybox port
22  */
23
24 //usage:#define telnetd_trivial_usage
25 //usage:       "[OPTIONS]"
26 //usage:#define telnetd_full_usage "\n\n"
27 //usage:       "Handle incoming telnet connections"
28 //usage:        IF_NOT_FEATURE_TELNETD_STANDALONE(" via inetd") "\n"
29 //usage:     "\n        -l LOGIN        Exec LOGIN on connect"
30 //usage:     "\n        -f ISSUE_FILE   Display ISSUE_FILE instead of /etc/issue"
31 //usage:     "\n        -K              Close connection as soon as login exits"
32 //usage:     "\n                        (normally wait until all programs close slave pty)"
33 //usage:        IF_FEATURE_TELNETD_STANDALONE(
34 //usage:     "\n        -p PORT         Port to listen on"
35 //usage:     "\n        -b ADDR[:PORT]  Address to bind to"
36 //usage:     "\n        -F              Run in foreground"
37 //usage:     "\n        -i              Inetd mode"
38 //usage:        IF_FEATURE_TELNETD_INETD_WAIT(
39 //usage:     "\n        -w SEC          Inetd 'wait' mode, linger time SEC"
40 //usage:     "\n        -S              Log to syslog (implied by -i or without -F and -w)"
41 //usage:        )
42 //usage:        )
43
44 #define DEBUG 0
45
46 #include "libbb.h"
47 #include <syslog.h>
48
49 #if DEBUG
50 # define TELCMDS
51 # define TELOPTS
52 #endif
53 #include <arpa/telnet.h>
54
55
56 struct tsession {
57         struct tsession *next;
58         pid_t shell_pid;
59         int sockfd_read;
60         int sockfd_write;
61         int ptyfd;
62
63         /* two circular buffers */
64         /*char *buf1, *buf2;*/
65 /*#define TS_BUF1(ts) ts->buf1*/
66 /*#define TS_BUF2(ts) TS_BUF2(ts)*/
67 #define TS_BUF1(ts) ((unsigned char*)(ts + 1))
68 #define TS_BUF2(ts) (((unsigned char*)(ts + 1)) + BUFSIZE)
69         int rdidx1, wridx1, size1;
70         int rdidx2, wridx2, size2;
71 };
72
73 /* Two buffers are directly after tsession in malloced memory.
74  * Make whole thing fit in 4k */
75 enum { BUFSIZE = (4 * 1024 - sizeof(struct tsession)) / 2 };
76
77
78 /* Globals */
79 struct globals {
80         struct tsession *sessions;
81         const char *loginpath;
82         const char *issuefile;
83         int maxfd;
84 } FIX_ALIASING;
85 #define G (*(struct globals*)&bb_common_bufsiz1)
86 #define INIT_G() do { \
87         G.loginpath = "/bin/login"; \
88         G.issuefile = "/etc/issue.net"; \
89 } while (0)
90
91
92 /*
93    Remove all IAC's from buf1 (received IACs are ignored and must be removed
94    so as to not be interpreted by the terminal).  Make an uninterrupted
95    string of characters fit for the terminal.  Do this by packing
96    all characters meant for the terminal sequentially towards the end of buf.
97
98    Return a pointer to the beginning of the characters meant for the terminal
99    and make *num_totty the number of characters that should be sent to
100    the terminal.
101
102    Note - if an IAC (3 byte quantity) starts before (bf + len) but extends
103    past (bf + len) then that IAC will be left unprocessed and *processed
104    will be less than len.
105
106    CR-LF ->'s CR mapping is also done here, for convenience.
107
108    NB: may fail to remove iacs which wrap around buffer!
109  */
110 static unsigned char *
111 remove_iacs(struct tsession *ts, int *pnum_totty)
112 {
113         unsigned char *ptr0 = TS_BUF1(ts) + ts->wridx1;
114         unsigned char *ptr = ptr0;
115         unsigned char *totty = ptr;
116         unsigned char *end = ptr + MIN(BUFSIZE - ts->wridx1, ts->size1);
117         int num_totty;
118
119         while (ptr < end) {
120                 if (*ptr != IAC) {
121                         char c = *ptr;
122
123                         *totty++ = c;
124                         ptr++;
125                         /* We map \r\n ==> \r for pragmatic reasons.
126                          * Many client implementations send \r\n when
127                          * the user hits the CarriageReturn key.
128                          * See RFC 1123 3.3.1 Telnet End-of-Line Convention.
129                          */
130                         if (c == '\r' && ptr < end && (*ptr == '\n' || *ptr == '\0'))
131                                 ptr++;
132                         continue;
133                 }
134
135                 if ((ptr+1) >= end)
136                         break;
137                 if (ptr[1] == NOP) { /* Ignore? (putty keepalive, etc.) */
138                         ptr += 2;
139                         continue;
140                 }
141                 if (ptr[1] == IAC) { /* Literal IAC? (emacs M-DEL) */
142                         *totty++ = ptr[1];
143                         ptr += 2;
144                         continue;
145                 }
146
147                 /*
148                  * TELOPT_NAWS support!
149                  */
150                 if ((ptr+2) >= end) {
151                         /* Only the beginning of the IAC is in the
152                         buffer we were asked to process, we can't
153                         process this char */
154                         break;
155                 }
156                 /*
157                  * IAC -> SB -> TELOPT_NAWS -> 4-byte -> IAC -> SE
158                  */
159                 if (ptr[1] == SB && ptr[2] == TELOPT_NAWS) {
160                         struct winsize ws;
161                         if ((ptr+8) >= end)
162                                 break;  /* incomplete, can't process */
163                         ws.ws_col = (ptr[3] << 8) | ptr[4];
164                         ws.ws_row = (ptr[5] << 8) | ptr[6];
165                         ioctl(ts->ptyfd, TIOCSWINSZ, (char *)&ws);
166                         ptr += 9;
167                         continue;
168                 }
169                 /* skip 3-byte IAC non-SB cmd */
170 #if DEBUG
171                 fprintf(stderr, "Ignoring IAC %s,%s\n",
172                                 TELCMD(ptr[1]), TELOPT(ptr[2]));
173 #endif
174                 ptr += 3;
175         }
176
177         num_totty = totty - ptr0;
178         *pnum_totty = num_totty;
179         /* The difference between ptr and totty is number of iacs
180            we removed from the stream. Adjust buf1 accordingly */
181         if ((ptr - totty) == 0) /* 99.999% of cases */
182                 return ptr0;
183         ts->wridx1 += ptr - totty;
184         ts->size1 -= ptr - totty;
185         /* Move chars meant for the terminal towards the end of the buffer */
186         return memmove(ptr - num_totty, ptr0, num_totty);
187 }
188
189 /*
190  * Converting single IAC into double on output
191  */
192 static size_t iac_safe_write(int fd, const char *buf, size_t count)
193 {
194         const char *IACptr;
195         size_t wr, rc, total;
196
197         total = 0;
198         while (1) {
199                 if (count == 0)
200                         return total;
201                 if (*buf == (char)IAC) {
202                         static const char IACIAC[] ALIGN1 = { IAC, IAC };
203                         rc = safe_write(fd, IACIAC, 2);
204                         if (rc != 2)
205                                 break;
206                         buf++;
207                         total++;
208                         count--;
209                         continue;
210                 }
211                 /* count != 0, *buf != IAC */
212                 IACptr = memchr(buf, IAC, count);
213                 wr = count;
214                 if (IACptr)
215                         wr = IACptr - buf;
216                 rc = safe_write(fd, buf, wr);
217                 if (rc != wr)
218                         break;
219                 buf += rc;
220                 total += rc;
221                 count -= rc;
222         }
223         /* here: rc - result of last short write */
224         if ((ssize_t)rc < 0) { /* error? */
225                 if (total == 0)
226                         return rc;
227                 rc = 0;
228         }
229         return total + rc;
230 }
231
232 /* Must match getopt32 string */
233 enum {
234         OPT_WATCHCHILD = (1 << 2), /* -K */
235         OPT_INETD      = (1 << 3) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -i */
236         OPT_PORT       = (1 << 4) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -p PORT */
237         OPT_FOREGROUND = (1 << 6) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -F */
238         OPT_SYSLOG     = (1 << 7) * ENABLE_FEATURE_TELNETD_INETD_WAIT, /* -S */
239         OPT_WAIT       = (1 << 8) * ENABLE_FEATURE_TELNETD_INETD_WAIT, /* -w SEC */
240 };
241
242 static struct tsession *
243 make_new_session(
244                 IF_FEATURE_TELNETD_STANDALONE(int sock)
245                 IF_NOT_FEATURE_TELNETD_STANDALONE(void)
246 ) {
247 #if !ENABLE_FEATURE_TELNETD_STANDALONE
248         enum { sock = 0 };
249 #endif
250         const char *login_argv[2];
251         struct termios termbuf;
252         int fd, pid;
253         char tty_name[GETPTY_BUFSIZE];
254         struct tsession *ts = xzalloc(sizeof(struct tsession) + BUFSIZE * 2);
255
256         /*ts->buf1 = (char *)(ts + 1);*/
257         /*ts->buf2 = ts->buf1 + BUFSIZE;*/
258
259         /* Got a new connection, set up a tty */
260         fd = xgetpty(tty_name);
261         if (fd > G.maxfd)
262                 G.maxfd = fd;
263         ts->ptyfd = fd;
264         ndelay_on(fd);
265         close_on_exec_on(fd);
266
267         /* SO_KEEPALIVE by popular demand */
268         setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1));
269 #if ENABLE_FEATURE_TELNETD_STANDALONE
270         ts->sockfd_read = sock;
271         ndelay_on(sock);
272         if (sock == 0) { /* We are called with fd 0 - we are in inetd mode */
273                 sock++; /* so use fd 1 for output */
274                 ndelay_on(sock);
275         }
276         ts->sockfd_write = sock;
277         if (sock > G.maxfd)
278                 G.maxfd = sock;
279 #else
280         /* ts->sockfd_read = 0; - done by xzalloc */
281         ts->sockfd_write = 1;
282         ndelay_on(0);
283         ndelay_on(1);
284 #endif
285
286         /* Make the telnet client understand we will echo characters so it
287          * should not do it locally. We don't tell the client to run linemode,
288          * because we want to handle line editing and tab completion and other
289          * stuff that requires char-by-char support. */
290         {
291                 static const char iacs_to_send[] ALIGN1 = {
292                         IAC, DO, TELOPT_ECHO,
293                         IAC, DO, TELOPT_NAWS,
294                         /* This requires telnetd.ctrlSQ.patch (incomplete) */
295                         /*IAC, DO, TELOPT_LFLOW,*/
296                         IAC, WILL, TELOPT_ECHO,
297                         IAC, WILL, TELOPT_SGA
298                 };
299                 /* This confuses iac_safe_write(), it will try to duplicate
300                  * each IAC... */
301                 //memcpy(TS_BUF2(ts), iacs_to_send, sizeof(iacs_to_send));
302                 //ts->rdidx2 = sizeof(iacs_to_send);
303                 //ts->size2 = sizeof(iacs_to_send);
304                 /* So just stuff it into TCP stream! (no error check...) */
305 #if ENABLE_FEATURE_TELNETD_STANDALONE
306                 safe_write(sock, iacs_to_send, sizeof(iacs_to_send));
307 #else
308                 safe_write(1, iacs_to_send, sizeof(iacs_to_send));
309 #endif
310                 /*ts->rdidx2 = 0; - xzalloc did it */
311                 /*ts->size2 = 0;*/
312         }
313
314         fflush_all();
315         pid = vfork(); /* NOMMU-friendly */
316         if (pid < 0) {
317                 free(ts);
318                 close(fd);
319                 /* sock will be closed by caller */
320                 bb_perror_msg("vfork");
321                 return NULL;
322         }
323         if (pid > 0) {
324                 /* Parent */
325                 ts->shell_pid = pid;
326                 return ts;
327         }
328
329         /* Child */
330         /* Careful - we are after vfork! */
331
332         /* Restore default signal handling ASAP */
333         bb_signals((1 << SIGCHLD) + (1 << SIGPIPE), SIG_DFL);
334
335         pid = getpid();
336
337         if (ENABLE_FEATURE_UTMP) {
338                 len_and_sockaddr *lsa = get_peer_lsa(sock);
339                 char *hostname = NULL;
340                 if (lsa) {
341                         hostname = xmalloc_sockaddr2dotted(&lsa->u.sa);
342                         free(lsa);
343                 }
344                 write_new_utmp(pid, LOGIN_PROCESS, tty_name, /*username:*/ "LOGIN", hostname);
345                 free(hostname);
346         }
347
348         /* Make new session and process group */
349         setsid();
350
351         /* Open the child's side of the tty */
352         /* NB: setsid() disconnects from any previous ctty's. Therefore
353          * we must open child's side of the tty AFTER setsid! */
354         close(0);
355         xopen(tty_name, O_RDWR); /* becomes our ctty */
356         xdup2(0, 1);
357         xdup2(0, 2);
358         tcsetpgrp(0, pid); /* switch this tty's process group to us */
359
360         /* The pseudo-terminal allocated to the client is configured to operate
361          * in cooked mode, and with XTABS CRMOD enabled (see tty(4)) */
362         tcgetattr(0, &termbuf);
363         termbuf.c_lflag |= ECHO; /* if we use readline we dont want this */
364         termbuf.c_oflag |= ONLCR | XTABS;
365         termbuf.c_iflag |= ICRNL;
366         termbuf.c_iflag &= ~IXOFF;
367         /*termbuf.c_lflag &= ~ICANON;*/
368         tcsetattr_stdin_TCSANOW(&termbuf);
369
370         /* Uses FILE-based I/O to stdout, but does fflush_all(),
371          * so should be safe with vfork.
372          * I fear, though, that some users will have ridiculously big
373          * issue files, and they may block writing to fd 1,
374          * (parent is supposed to read it, but parent waits
375          * for vforked child to exec!) */
376         print_login_issue(G.issuefile, tty_name);
377
378         /* Exec shell / login / whatever */
379         login_argv[0] = G.loginpath;
380         login_argv[1] = NULL;
381         /* exec busybox applet (if PREFER_APPLETS=y), if that fails,
382          * exec external program.
383          * NB: sock is either 0 or has CLOEXEC set on it.
384          * fd has CLOEXEC set on it too. These two fds will be closed here.
385          */
386         BB_EXECVP(G.loginpath, (char **)login_argv);
387         /* _exit is safer with vfork, and we shouldn't send message
388          * to remote clients anyway */
389         _exit(EXIT_FAILURE); /*bb_perror_msg_and_die("execv %s", G.loginpath);*/
390 }
391
392 #if ENABLE_FEATURE_TELNETD_STANDALONE
393
394 static void
395 free_session(struct tsession *ts)
396 {
397         struct tsession *t;
398
399         if (option_mask32 & OPT_INETD)
400                 exit(EXIT_SUCCESS);
401
402         /* Unlink this telnet session from the session list */
403         t = G.sessions;
404         if (t == ts)
405                 G.sessions = ts->next;
406         else {
407                 while (t->next != ts)
408                         t = t->next;
409                 t->next = ts->next;
410         }
411
412 #if 0
413         /* It was said that "normal" telnetd just closes ptyfd,
414          * doesn't send SIGKILL. When we close ptyfd,
415          * kernel sends SIGHUP to processes having slave side opened. */
416         kill(ts->shell_pid, SIGKILL);
417         waitpid(ts->shell_pid, NULL, 0);
418 #endif
419         close(ts->ptyfd);
420         close(ts->sockfd_read);
421         /* We do not need to close(ts->sockfd_write), it's the same
422          * as sockfd_read unless we are in inetd mode. But in inetd mode
423          * we do not reach this */
424         free(ts);
425
426         /* Scan all sessions and find new maxfd */
427         G.maxfd = 0;
428         ts = G.sessions;
429         while (ts) {
430                 if (G.maxfd < ts->ptyfd)
431                         G.maxfd = ts->ptyfd;
432                 if (G.maxfd < ts->sockfd_read)
433                         G.maxfd = ts->sockfd_read;
434 #if 0
435                 /* Again, sockfd_write == sockfd_read here */
436                 if (G.maxfd < ts->sockfd_write)
437                         G.maxfd = ts->sockfd_write;
438 #endif
439                 ts = ts->next;
440         }
441 }
442
443 #else /* !FEATURE_TELNETD_STANDALONE */
444
445 /* Used in main() only, thus "return 0" actually is exit(EXIT_SUCCESS). */
446 #define free_session(ts) return 0
447
448 #endif
449
450 static void handle_sigchld(int sig UNUSED_PARAM)
451 {
452         pid_t pid;
453         struct tsession *ts;
454         int save_errno = errno;
455
456         /* Looping: more than one child may have exited */
457         while (1) {
458                 pid = wait_any_nohang(NULL);
459                 if (pid <= 0)
460                         break;
461                 ts = G.sessions;
462                 while (ts) {
463                         if (ts->shell_pid == pid) {
464                                 ts->shell_pid = -1;
465 // man utmp:
466 // When init(8) finds that a process has exited, it locates its utmp entry
467 // by ut_pid, sets ut_type to DEAD_PROCESS, and clears ut_user, ut_host
468 // and ut_time with null bytes.
469 // [same applies to other processes which maintain utmp entries, like telnetd]
470 //
471 // We do not bother actually clearing fields:
472 // it might be interesting to know who was logged in and from where
473                                 update_utmp(pid, DEAD_PROCESS, /*tty_name:*/ NULL, /*username:*/ NULL, /*hostname:*/ NULL);
474                                 break;
475                         }
476                         ts = ts->next;
477                 }
478         }
479
480         errno = save_errno;
481 }
482
483 int telnetd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
484 int telnetd_main(int argc UNUSED_PARAM, char **argv)
485 {
486         fd_set rdfdset, wrfdset;
487         unsigned opt;
488         int count;
489         struct tsession *ts;
490 #if ENABLE_FEATURE_TELNETD_STANDALONE
491 #define IS_INETD (opt & OPT_INETD)
492         int master_fd = master_fd; /* for compiler */
493         int sec_linger = sec_linger;
494         char *opt_bindaddr = NULL;
495         char *opt_portnbr;
496 #else
497         enum {
498                 IS_INETD = 1,
499                 master_fd = -1,
500         };
501 #endif
502         INIT_G();
503
504         /* -w NUM, and implies -F. -w and -i don't mix */
505         IF_FEATURE_TELNETD_INETD_WAIT(opt_complementary = "wF:w+:i--w:w--i";)
506         /* Even if !STANDALONE, we accept (and ignore) -i, thus people
507          * don't need to guess whether it's ok to pass -i to us */
508         opt = getopt32(argv, "f:l:Ki"
509                         IF_FEATURE_TELNETD_STANDALONE("p:b:F")
510                         IF_FEATURE_TELNETD_INETD_WAIT("Sw:"),
511                         &G.issuefile, &G.loginpath
512                         IF_FEATURE_TELNETD_STANDALONE(, &opt_portnbr, &opt_bindaddr)
513                         IF_FEATURE_TELNETD_INETD_WAIT(, &sec_linger)
514         );
515         if (!IS_INETD /*&& !re_execed*/) {
516                 /* inform that we start in standalone mode?
517                  * May be useful when people forget to give -i */
518                 /*bb_error_msg("listening for connections");*/
519                 if (!(opt & OPT_FOREGROUND)) {
520                         /* DAEMON_CHDIR_ROOT was giving inconsistent
521                          * behavior with/without -F, -i */
522                         bb_daemonize_or_rexec(0 /*was DAEMON_CHDIR_ROOT*/, argv);
523                 }
524         }
525         /* Redirect log to syslog early, if needed */
526         if (IS_INETD || (opt & OPT_SYSLOG) || !(opt & OPT_FOREGROUND)) {
527                 openlog(applet_name, LOG_PID, LOG_DAEMON);
528                 logmode = LOGMODE_SYSLOG;
529         }
530 #if ENABLE_FEATURE_TELNETD_STANDALONE
531         if (IS_INETD) {
532                 G.sessions = make_new_session(0);
533                 if (!G.sessions) /* pty opening or vfork problem, exit */
534                         return 1; /* make_new_session printed error message */
535         } else {
536                 master_fd = 0;
537                 if (!(opt & OPT_WAIT)) {
538                         unsigned portnbr = 23;
539                         if (opt & OPT_PORT)
540                                 portnbr = xatou16(opt_portnbr);
541                         master_fd = create_and_bind_stream_or_die(opt_bindaddr, portnbr);
542                         xlisten(master_fd, 1);
543                 }
544                 close_on_exec_on(master_fd);
545         }
546 #else
547         G.sessions = make_new_session();
548         if (!G.sessions) /* pty opening or vfork problem, exit */
549                 return 1; /* make_new_session printed error message */
550 #endif
551
552         /* We don't want to die if just one session is broken */
553         signal(SIGPIPE, SIG_IGN);
554
555         if (opt & OPT_WATCHCHILD)
556                 signal(SIGCHLD, handle_sigchld);
557         else /* prevent dead children from becoming zombies */
558                 signal(SIGCHLD, SIG_IGN);
559
560 /*
561    This is how the buffers are used. The arrows indicate data flow.
562
563    +-------+     wridx1++     +------+     rdidx1++     +----------+
564    |       | <--------------  | buf1 | <--------------  |          |
565    |       |     size1--      +------+     size1++      |          |
566    |  pty  |                                            |  socket  |
567    |       |     rdidx2++     +------+     wridx2++     |          |
568    |       |  --------------> | buf2 |  --------------> |          |
569    +-------+     size2++      +------+     size2--      +----------+
570
571    size1: "how many bytes are buffered for pty between rdidx1 and wridx1?"
572    size2: "how many bytes are buffered for socket between rdidx2 and wridx2?"
573
574    Each session has got two buffers. Buffers are circular. If sizeN == 0,
575    buffer is empty. If sizeN == BUFSIZE, buffer is full. In both these cases
576    rdidxN == wridxN.
577 */
578  again:
579         FD_ZERO(&rdfdset);
580         FD_ZERO(&wrfdset);
581
582         /* Select on the master socket, all telnet sockets and their
583          * ptys if there is room in their session buffers.
584          * NB: scalability problem: we recalculate entire bitmap
585          * before each select. Can be a problem with 500+ connections. */
586         ts = G.sessions;
587         while (ts) {
588                 struct tsession *next = ts->next; /* in case we free ts */
589                 if (ts->shell_pid == -1) {
590                         /* Child died and we detected that */
591                         free_session(ts);
592                 } else {
593                         if (ts->size1 > 0)       /* can write to pty */
594                                 FD_SET(ts->ptyfd, &wrfdset);
595                         if (ts->size1 < BUFSIZE) /* can read from socket */
596                                 FD_SET(ts->sockfd_read, &rdfdset);
597                         if (ts->size2 > 0)       /* can write to socket */
598                                 FD_SET(ts->sockfd_write, &wrfdset);
599                         if (ts->size2 < BUFSIZE) /* can read from pty */
600                                 FD_SET(ts->ptyfd, &rdfdset);
601                 }
602                 ts = next;
603         }
604         if (!IS_INETD) {
605                 FD_SET(master_fd, &rdfdset);
606                 /* This is needed because free_session() does not
607                  * take master_fd into account when it finds new
608                  * maxfd among remaining fd's */
609                 if (master_fd > G.maxfd)
610                         G.maxfd = master_fd;
611         }
612
613         {
614                 struct timeval *tv_ptr = NULL;
615 #if ENABLE_FEATURE_TELNETD_INETD_WAIT
616                 struct timeval tv;
617                 if ((opt & OPT_WAIT) && !G.sessions) {
618                         tv.tv_sec = sec_linger;
619                         tv.tv_usec = 0;
620                         tv_ptr = &tv;
621                 }
622 #endif
623                 count = select(G.maxfd + 1, &rdfdset, &wrfdset, NULL, tv_ptr);
624         }
625         if (count == 0) /* "telnetd -w SEC" timed out */
626                 return 0;
627         if (count < 0)
628                 goto again; /* EINTR or ENOMEM */
629
630 #if ENABLE_FEATURE_TELNETD_STANDALONE
631         /* Check for and accept new sessions */
632         if (!IS_INETD && FD_ISSET(master_fd, &rdfdset)) {
633                 int fd;
634                 struct tsession *new_ts;
635
636                 fd = accept(master_fd, NULL, NULL);
637                 if (fd < 0)
638                         goto again;
639                 close_on_exec_on(fd);
640
641                 /* Create a new session and link it into active list */
642                 new_ts = make_new_session(fd);
643                 if (new_ts) {
644                         new_ts->next = G.sessions;
645                         G.sessions = new_ts;
646                 } else {
647                         close(fd);
648                 }
649         }
650 #endif
651
652         /* Then check for data tunneling */
653         ts = G.sessions;
654         while (ts) { /* For all sessions... */
655                 struct tsession *next = ts->next; /* in case we free ts */
656
657                 if (/*ts->size1 &&*/ FD_ISSET(ts->ptyfd, &wrfdset)) {
658                         int num_totty;
659                         unsigned char *ptr;
660                         /* Write to pty from buffer 1 */
661                         ptr = remove_iacs(ts, &num_totty);
662                         count = safe_write(ts->ptyfd, ptr, num_totty);
663                         if (count < 0) {
664                                 if (errno == EAGAIN)
665                                         goto skip1;
666                                 goto kill_session;
667                         }
668                         ts->size1 -= count;
669                         ts->wridx1 += count;
670                         if (ts->wridx1 >= BUFSIZE) /* actually == BUFSIZE */
671                                 ts->wridx1 = 0;
672                 }
673  skip1:
674                 if (/*ts->size2 &&*/ FD_ISSET(ts->sockfd_write, &wrfdset)) {
675                         /* Write to socket from buffer 2 */
676                         count = MIN(BUFSIZE - ts->wridx2, ts->size2);
677                         count = iac_safe_write(ts->sockfd_write, (void*)(TS_BUF2(ts) + ts->wridx2), count);
678                         if (count < 0) {
679                                 if (errno == EAGAIN)
680                                         goto skip2;
681                                 goto kill_session;
682                         }
683                         ts->size2 -= count;
684                         ts->wridx2 += count;
685                         if (ts->wridx2 >= BUFSIZE) /* actually == BUFSIZE */
686                                 ts->wridx2 = 0;
687                 }
688  skip2:
689                 /* Should not be needed, but... remove_iacs is actually buggy
690                  * (it cannot process iacs which wrap around buffer's end)!
691                  * Since properly fixing it requires writing bigger code,
692                  * we rely instead on this code making it virtually impossible
693                  * to have wrapped iac (people don't type at 2k/second).
694                  * It also allows for bigger reads in common case. */
695                 if (ts->size1 == 0) {
696                         ts->rdidx1 = 0;
697                         ts->wridx1 = 0;
698                 }
699                 if (ts->size2 == 0) {
700                         ts->rdidx2 = 0;
701                         ts->wridx2 = 0;
702                 }
703
704                 if (/*ts->size1 < BUFSIZE &&*/ FD_ISSET(ts->sockfd_read, &rdfdset)) {
705                         /* Read from socket to buffer 1 */
706                         count = MIN(BUFSIZE - ts->rdidx1, BUFSIZE - ts->size1);
707                         count = safe_read(ts->sockfd_read, TS_BUF1(ts) + ts->rdidx1, count);
708                         if (count <= 0) {
709                                 if (count < 0 && errno == EAGAIN)
710                                         goto skip3;
711                                 goto kill_session;
712                         }
713                         /* Ignore trailing NUL if it is there */
714                         if (!TS_BUF1(ts)[ts->rdidx1 + count - 1]) {
715                                 --count;
716                         }
717                         ts->size1 += count;
718                         ts->rdidx1 += count;
719                         if (ts->rdidx1 >= BUFSIZE) /* actually == BUFSIZE */
720                                 ts->rdidx1 = 0;
721                 }
722  skip3:
723                 if (/*ts->size2 < BUFSIZE &&*/ FD_ISSET(ts->ptyfd, &rdfdset)) {
724                         /* Read from pty to buffer 2 */
725                         count = MIN(BUFSIZE - ts->rdidx2, BUFSIZE - ts->size2);
726                         count = safe_read(ts->ptyfd, TS_BUF2(ts) + ts->rdidx2, count);
727                         if (count <= 0) {
728                                 if (count < 0 && errno == EAGAIN)
729                                         goto skip4;
730                                 goto kill_session;
731                         }
732                         ts->size2 += count;
733                         ts->rdidx2 += count;
734                         if (ts->rdidx2 >= BUFSIZE) /* actually == BUFSIZE */
735                                 ts->rdidx2 = 0;
736                 }
737  skip4:
738                 ts = next;
739                 continue;
740  kill_session:
741                 if (ts->shell_pid > 0)
742                         update_utmp(ts->shell_pid, DEAD_PROCESS, /*tty_name:*/ NULL, /*username:*/ NULL, /*hostname:*/ NULL);
743                 free_session(ts);
744                 ts = next;
745         }
746
747         goto again;
748 }