Magellan Linux

Annotation of /trunk/mkinitrd-magellan/busybox/networking/telnetd.c

Parent Directory Parent Directory | Revision Log Revision Log


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