aboutsummaryrefslogtreecommitdiff
path: root/networking/telnetd.c
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2009-06-10 13:38:08 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2009-06-10 13:38:08 +0200
commit1d77db8459e1948cdde407f5010f772b81048dbd (patch)
tree549eeafb42f220047f931237207851693d87c825 /networking/telnetd.c
parenta4bcbd0e0416bb4965488ec1f16039aa302f8b91 (diff)
downloadbusybox-w32-1d77db8459e1948cdde407f5010f772b81048dbd.tar.gz
busybox-w32-1d77db8459e1948cdde407f5010f772b81048dbd.tar.bz2
busybox-w32-1d77db8459e1948cdde407f5010f772b81048dbd.zip
telnetd: more compact version of the fix for stray open fds
function old new delta telnetd_main 1520 1527 +7 make_new_session 510 416 -94 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/1 up/down: 7/-94) Total: -87 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'networking/telnetd.c')
-rw-r--r--networking/telnetd.c90
1 files changed, 39 insertions, 51 deletions
diff --git a/networking/telnetd.c b/networking/telnetd.c
index 6a8190b14..540387f1a 100644
--- a/networking/telnetd.c
+++ b/networking/telnetd.c
@@ -32,11 +32,12 @@
32#endif 32#endif
33#include <arpa/telnet.h> 33#include <arpa/telnet.h>
34 34
35/* Structure that describes a session */
36struct tsession { 35struct tsession {
37 struct tsession *next; 36 struct tsession *next;
38 pid_t shell_pid; 37 pid_t shell_pid;
39 int sockfd_read, sockfd_write, ptyfd; 38 int sockfd_read;
39 int sockfd_write;
40 int ptyfd;
40 41
41 /* two circular buffers */ 42 /* two circular buffers */
42 /*char *buf1, *buf2;*/ 43 /*char *buf1, *buf2;*/
@@ -125,9 +126,9 @@ remove_iacs(struct tsession *ts, int *pnum_totty)
125 * TELOPT_NAWS support! 126 * TELOPT_NAWS support!
126 */ 127 */
127 if ((ptr+2) >= end) { 128 if ((ptr+2) >= end) {
128 /* only the beginning of the IAC is in the 129 /* Only the beginning of the IAC is in the
129 buffer we were asked to process, we can't 130 buffer we were asked to process, we can't
130 process this char. */ 131 process this char */
131 break; 132 break;
132 } 133 }
133 /* 134 /*
@@ -153,13 +154,13 @@ remove_iacs(struct tsession *ts, int *pnum_totty)
153 154
154 num_totty = totty - ptr0; 155 num_totty = totty - ptr0;
155 *pnum_totty = num_totty; 156 *pnum_totty = num_totty;
156 /* the difference between ptr and totty is number of iacs 157 /* The difference between ptr and totty is number of iacs
157 we removed from the stream. Adjust buf1 accordingly. */ 158 we removed from the stream. Adjust buf1 accordingly */
158 if ((ptr - totty) == 0) /* 99.999% of cases */ 159 if ((ptr - totty) == 0) /* 99.999% of cases */
159 return ptr0; 160 return ptr0;
160 ts->wridx1 += ptr - totty; 161 ts->wridx1 += ptr - totty;
161 ts->size1 -= ptr - totty; 162 ts->size1 -= ptr - totty;
162 /* move chars meant for the terminal towards the end of the buffer */ 163 /* Move chars meant for the terminal towards the end of the buffer */
163 return memmove(ptr - num_totty, ptr0, num_totty); 164 return memmove(ptr - num_totty, ptr0, num_totty);
164} 165}
165 166
@@ -216,7 +217,7 @@ enum {
216 217
217static struct tsession * 218static struct tsession *
218make_new_session( 219make_new_session(
219 IF_FEATURE_TELNETD_STANDALONE(int master_fd, int sock) 220 IF_FEATURE_TELNETD_STANDALONE(int sock)
220 IF_NOT_FEATURE_TELNETD_STANDALONE(void) 221 IF_NOT_FEATURE_TELNETD_STANDALONE(void)
221) { 222) {
222 const char *login_argv[2]; 223 const char *login_argv[2];
@@ -228,18 +229,20 @@ make_new_session(
228 /*ts->buf1 = (char *)(ts + 1);*/ 229 /*ts->buf1 = (char *)(ts + 1);*/
229 /*ts->buf2 = ts->buf1 + BUFSIZE;*/ 230 /*ts->buf2 = ts->buf1 + BUFSIZE;*/
230 231
231 /* Got a new connection, set up a tty. */ 232 /* Got a new connection, set up a tty */
232 fd = xgetpty(tty_name); 233 fd = xgetpty(tty_name);
233 if (fd > G.maxfd) 234 if (fd > G.maxfd)
234 G.maxfd = fd; 235 G.maxfd = fd;
235 ts->ptyfd = fd; 236 ts->ptyfd = fd;
236 ndelay_on(fd); 237 ndelay_on(fd);
238 close_on_exec_on(fd);
239
237#if ENABLE_FEATURE_TELNETD_STANDALONE 240#if ENABLE_FEATURE_TELNETD_STANDALONE
238 ts->sockfd_read = sock;
239 /* SO_KEEPALIVE by popular demand */ 241 /* SO_KEEPALIVE by popular demand */
240 setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1)); 242 setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1));
243 ts->sockfd_read = sock;
241 ndelay_on(sock); 244 ndelay_on(sock);
242 if (!sock) { /* We are called with fd 0 - we are in inetd mode */ 245 if (sock == 0) { /* We are called with fd 0 - we are in inetd mode */
243 sock++; /* so use fd 1 for output */ 246 sock++; /* so use fd 1 for output */
244 ndelay_on(sock); 247 ndelay_on(sock);
245 } 248 }
@@ -254,6 +257,7 @@ make_new_session(
254 ndelay_on(0); 257 ndelay_on(0);
255 ndelay_on(1); 258 ndelay_on(1);
256#endif 259#endif
260
257 /* Make the telnet client understand we will echo characters so it 261 /* Make the telnet client understand we will echo characters so it
258 * should not do it locally. We don't tell the client to run linemode, 262 * should not do it locally. We don't tell the client to run linemode,
259 * because we want to handle line editing and tab completion and other 263 * because we want to handle line editing and tab completion and other
@@ -303,42 +307,20 @@ make_new_session(
303 /* Restore default signal handling ASAP */ 307 /* Restore default signal handling ASAP */
304 bb_signals((1 << SIGCHLD) + (1 << SIGPIPE), SIG_DFL); 308 bb_signals((1 << SIGCHLD) + (1 << SIGPIPE), SIG_DFL);
305 309
306#if ENABLE_FEATURE_TELNETD_STANDALONE
307 if (!(option_mask32 & OPT_INETD)) {
308 struct tsession *tp = G.sessions;
309 while (tp) {
310 close(tp->ptyfd);
311 close(tp->sockfd_read);
312 /* sockfd_write == sockfd_read for standalone telnetd */
313 /*close(tp->sockfd_write);*/
314 tp = tp->next;
315 }
316 }
317#endif
318
319 /* Make new session and process group */ 310 /* Make new session and process group */
320 setsid(); 311 setsid();
321 312
322 close(fd); 313 /* Open the child's side of the tty */
323#if ENABLE_FEATURE_TELNETD_STANDALONE
324 if (master_fd >= 0)
325 close(master_fd);
326 close(sock);
327#endif
328 /* Open the child's side of the tty. */
329 /* NB: setsid() disconnects from any previous ctty's. Therefore 314 /* NB: setsid() disconnects from any previous ctty's. Therefore
330 * we must open child's side of the tty AFTER setsid! */ 315 * we must open child's side of the tty AFTER setsid! */
331#if ENABLE_FEATURE_TELNETD_STANDALONE 316 close(0);
332 if (sock != 0) /* if we did not close 0 already */
333#endif
334 close(0);
335 xopen(tty_name, O_RDWR); /* becomes our ctty */ 317 xopen(tty_name, O_RDWR); /* becomes our ctty */
336 xdup2(0, 1); 318 xdup2(0, 1);
337 xdup2(0, 2); 319 xdup2(0, 2);
338 tcsetpgrp(0, getpid()); /* switch this tty's process group to us */ 320 tcsetpgrp(0, getpid()); /* switch this tty's process group to us */
339 321
340 /* The pseudo-terminal allocated to the client is configured to operate in 322 /* The pseudo-terminal allocated to the client is configured to operate
341 * cooked mode, and with XTABS CRMOD enabled (see tty(4)). */ 323 * in cooked mode, and with XTABS CRMOD enabled (see tty(4)) */
342 tcgetattr(0, &termbuf); 324 tcgetattr(0, &termbuf);
343 termbuf.c_lflag |= ECHO; /* if we use readline we dont want this */ 325 termbuf.c_lflag |= ECHO; /* if we use readline we dont want this */
344 termbuf.c_oflag |= ONLCR | XTABS; 326 termbuf.c_oflag |= ONLCR | XTABS;
@@ -359,7 +341,10 @@ make_new_session(
359 login_argv[0] = G.loginpath; 341 login_argv[0] = G.loginpath;
360 login_argv[1] = NULL; 342 login_argv[1] = NULL;
361 /* exec busybox applet (if PREFER_APPLETS=y), if that fails, 343 /* exec busybox applet (if PREFER_APPLETS=y), if that fails,
362 * exec external program */ 344 * exec external program.
345 * NB: sock is either 0 or has CLOEXEC set on it.
346 * fd has CLOEXEC set on it too. These two fds will be closed here.
347 */
363 BB_EXECVP(G.loginpath, (char **)login_argv); 348 BB_EXECVP(G.loginpath, (char **)login_argv);
364 /* _exit is safer with vfork, and we shouldn't send message 349 /* _exit is safer with vfork, and we shouldn't send message
365 * to remote clients anyway */ 350 * to remote clients anyway */
@@ -496,12 +481,13 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv)
496 481
497#if ENABLE_FEATURE_TELNETD_STANDALONE 482#if ENABLE_FEATURE_TELNETD_STANDALONE
498 if (IS_INETD) { 483 if (IS_INETD) {
499 G.sessions = make_new_session(-1, 0); 484 G.sessions = make_new_session(0);
500 if (!G.sessions) /* pty opening or vfork problem, exit */ 485 if (!G.sessions) /* pty opening or vfork problem, exit */
501 return 1; /* make_new_session prints error message */ 486 return 1; /* make_new_session prints error message */
502 } else { 487 } else {
503 master_fd = create_and_bind_stream_or_die(opt_bindaddr, portnbr); 488 master_fd = create_and_bind_stream_or_die(opt_bindaddr, portnbr);
504 xlisten(master_fd, 1); 489 xlisten(master_fd, 1);
490 close_on_exec_on(master_fd);
505 } 491 }
506#else 492#else
507 G.sessions = make_new_session(); 493 G.sessions = make_new_session();
@@ -518,8 +504,8 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv)
518 signal(SIGCHLD, SIG_IGN); 504 signal(SIGCHLD, SIG_IGN);
519 505
520/* 506/*
521 This is how the buffers are used. The arrows indicate the movement 507 This is how the buffers are used. The arrows indicate data flow.
522 of data. 508
523 +-------+ wridx1++ +------+ rdidx1++ +----------+ 509 +-------+ wridx1++ +------+ rdidx1++ +----------+
524 | | <-------------- | buf1 | <-------------- | | 510 | | <-------------- | buf1 | <-------------- | |
525 | | size1-- +------+ size1++ | | 511 | | size1-- +------+ size1++ | |
@@ -545,7 +531,7 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv)
545 * before each select. Can be a problem with 500+ connections. */ 531 * before each select. Can be a problem with 500+ connections. */
546 ts = G.sessions; 532 ts = G.sessions;
547 while (ts) { 533 while (ts) {
548 struct tsession *next = ts->next; /* in case we free ts. */ 534 struct tsession *next = ts->next; /* in case we free ts */
549 if (ts->shell_pid == -1) { 535 if (ts->shell_pid == -1) {
550 /* Child died and we detected that */ 536 /* Child died and we detected that */
551 free_session(ts); 537 free_session(ts);
@@ -575,7 +561,7 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv)
575 goto again; /* EINTR or ENOMEM */ 561 goto again; /* EINTR or ENOMEM */
576 562
577#if ENABLE_FEATURE_TELNETD_STANDALONE 563#if ENABLE_FEATURE_TELNETD_STANDALONE
578 /* First check for and accept new sessions. */ 564 /* Check for and accept new sessions */
579 if (!IS_INETD && FD_ISSET(master_fd, &rdfdset)) { 565 if (!IS_INETD && FD_ISSET(master_fd, &rdfdset)) {
580 int fd; 566 int fd;
581 struct tsession *new_ts; 567 struct tsession *new_ts;
@@ -583,8 +569,10 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv)
583 fd = accept(master_fd, NULL, NULL); 569 fd = accept(master_fd, NULL, NULL);
584 if (fd < 0) 570 if (fd < 0)
585 goto again; 571 goto again;
586 /* Create a new session and link it into our active list */ 572 close_on_exec_on(fd);
587 new_ts = make_new_session(master_fd, fd); 573
574 /* Create a new session and link it into active list */
575 new_ts = make_new_session(fd);
588 if (new_ts) { 576 if (new_ts) {
589 new_ts->next = G.sessions; 577 new_ts->next = G.sessions;
590 G.sessions = new_ts; 578 G.sessions = new_ts;
@@ -594,15 +582,15 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv)
594 } 582 }
595#endif 583#endif
596 584
597 /* Then check for data tunneling. */ 585 /* Then check for data tunneling */
598 ts = G.sessions; 586 ts = G.sessions;
599 while (ts) { /* For all sessions... */ 587 while (ts) { /* For all sessions... */
600 struct tsession *next = ts->next; /* in case we free ts. */ 588 struct tsession *next = ts->next; /* in case we free ts */
601 589
602 if (/*ts->size1 &&*/ FD_ISSET(ts->ptyfd, &wrfdset)) { 590 if (/*ts->size1 &&*/ FD_ISSET(ts->ptyfd, &wrfdset)) {
603 int num_totty; 591 int num_totty;
604 unsigned char *ptr; 592 unsigned char *ptr;
605 /* Write to pty from buffer 1. */ 593 /* Write to pty from buffer 1 */
606 ptr = remove_iacs(ts, &num_totty); 594 ptr = remove_iacs(ts, &num_totty);
607 count = safe_write(ts->ptyfd, ptr, num_totty); 595 count = safe_write(ts->ptyfd, ptr, num_totty);
608 if (count < 0) { 596 if (count < 0) {
@@ -617,7 +605,7 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv)
617 } 605 }
618 skip1: 606 skip1:
619 if (/*ts->size2 &&*/ FD_ISSET(ts->sockfd_write, &wrfdset)) { 607 if (/*ts->size2 &&*/ FD_ISSET(ts->sockfd_write, &wrfdset)) {
620 /* Write to socket from buffer 2. */ 608 /* Write to socket from buffer 2 */
621 count = MIN(BUFSIZE - ts->wridx2, ts->size2); 609 count = MIN(BUFSIZE - ts->wridx2, ts->size2);
622 count = iac_safe_write(ts->sockfd_write, (void*)(TS_BUF2(ts) + ts->wridx2), count); 610 count = iac_safe_write(ts->sockfd_write, (void*)(TS_BUF2(ts) + ts->wridx2), count);
623 if (count < 0) { 611 if (count < 0) {
@@ -647,7 +635,7 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv)
647 } 635 }
648 636
649 if (/*ts->size1 < BUFSIZE &&*/ FD_ISSET(ts->sockfd_read, &rdfdset)) { 637 if (/*ts->size1 < BUFSIZE &&*/ FD_ISSET(ts->sockfd_read, &rdfdset)) {
650 /* Read from socket to buffer 1. */ 638 /* Read from socket to buffer 1 */
651 count = MIN(BUFSIZE - ts->rdidx1, BUFSIZE - ts->size1); 639 count = MIN(BUFSIZE - ts->rdidx1, BUFSIZE - ts->size1);
652 count = safe_read(ts->sockfd_read, TS_BUF1(ts) + ts->rdidx1, count); 640 count = safe_read(ts->sockfd_read, TS_BUF1(ts) + ts->rdidx1, count);
653 if (count <= 0) { 641 if (count <= 0) {
@@ -666,7 +654,7 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv)
666 } 654 }
667 skip3: 655 skip3:
668 if (/*ts->size2 < BUFSIZE &&*/ FD_ISSET(ts->ptyfd, &rdfdset)) { 656 if (/*ts->size2 < BUFSIZE &&*/ FD_ISSET(ts->ptyfd, &rdfdset)) {
669 /* Read from pty to buffer 2. */ 657 /* Read from pty to buffer 2 */
670 count = MIN(BUFSIZE - ts->rdidx2, BUFSIZE - ts->size2); 658 count = MIN(BUFSIZE - ts->rdidx2, BUFSIZE - ts->size2);
671 count = safe_read(ts->ptyfd, TS_BUF2(ts) + ts->rdidx2, count); 659 count = safe_read(ts->ptyfd, TS_BUF2(ts) + ts->rdidx2, count);
672 if (count <= 0) { 660 if (count <= 0) {