aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--networking/httpd.c2
-rw-r--r--networking/telnetd.c157
2 files changed, 95 insertions, 64 deletions
diff --git a/networking/httpd.c b/networking/httpd.c
index 5cd98a573..956eecaf2 100644
--- a/networking/httpd.c
+++ b/networking/httpd.c
@@ -718,7 +718,7 @@ static void parse_conf(const char *path, int flag)
718 /* form "/path/file" */ 718 /* form "/path/file" */
719 sprintf(cur->before_colon, "/%s%.*s", 719 sprintf(cur->before_colon, "/%s%.*s",
720 path, 720 path,
721 after_colon - buf - 1, /* includes "/", but not ":" */ 721 (int) (after_colon - buf - 1), /* includes "/", but not ":" */
722 buf); 722 buf);
723 /* canonicalize it */ 723 /* canonicalize it */
724 p = bb_simplify_abs_path_inplace(cur->before_colon); 724 p = bb_simplify_abs_path_inplace(cur->before_colon);
diff --git a/networking/telnetd.c b/networking/telnetd.c
index b7162ad36..6a8190b14 100644
--- a/networking/telnetd.c
+++ b/networking/telnetd.c
@@ -11,14 +11,14 @@
11 * 11 *
12 * The telnetd manpage says it all: 12 * The telnetd manpage says it all:
13 * 13 *
14 * Telnetd operates by allocating a pseudo-terminal device (see pty(4)) for 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 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 16 * pseudo-terminal as stdin, stdout, and stderr. Telnetd manipulates the
17 * master side of the pseudo-terminal, implementing the telnet protocol and 17 * master side of the pseudo-terminal, implementing the telnet protocol and
18 * passing characters between the remote client and the login process. 18 * passing characters between the remote client and the login process.
19 * 19 *
20 * Vladimir Oleynik <dzo@simtreas.ru> 2001 20 * Vladimir Oleynik <dzo@simtreas.ru> 2001
21 * Set process group corrections, initial busybox port 21 * Set process group corrections, initial busybox port
22 */ 22 */
23 23
24#define DEBUG 0 24#define DEBUG 0
@@ -40,10 +40,10 @@ struct tsession {
40 40
41 /* two circular buffers */ 41 /* two circular buffers */
42 /*char *buf1, *buf2;*/ 42 /*char *buf1, *buf2;*/
43/*#define TS_BUF1 ts->buf1*/ 43/*#define TS_BUF1(ts) ts->buf1*/
44/*#define TS_BUF2 TS_BUF2*/ 44/*#define TS_BUF2(ts) TS_BUF2(ts)*/
45#define TS_BUF1 ((unsigned char*)(ts + 1)) 45#define TS_BUF1(ts) ((unsigned char*)(ts + 1))
46#define TS_BUF2 (((unsigned char*)(ts + 1)) + BUFSIZE) 46#define TS_BUF2(ts) (((unsigned char*)(ts + 1)) + BUFSIZE)
47 int rdidx1, wridx1, size1; 47 int rdidx1, wridx1, size1;
48 int rdidx2, wridx2, size2; 48 int rdidx2, wridx2, size2;
49}; 49};
@@ -54,10 +54,17 @@ enum { BUFSIZE = (4 * 1024 - sizeof(struct tsession)) / 2 };
54 54
55 55
56/* Globals */ 56/* Globals */
57static int maxfd; 57struct globals {
58static struct tsession *sessions; 58 struct tsession *sessions;
59static const char *loginpath = "/bin/login"; 59 const char *loginpath;
60static const char *issuefile = "/etc/issue.net"; 60 const char *issuefile;
61 int maxfd;
62};
63#define G (*(struct globals*)&bb_common_bufsiz1)
64#define INIT_G() do { \
65 G.loginpath = "/bin/login"; \
66 G.issuefile = "/etc/issue.net"; \
67} while (0)
61 68
62 69
63/* 70/*
@@ -81,7 +88,7 @@ static const char *issuefile = "/etc/issue.net";
81static unsigned char * 88static unsigned char *
82remove_iacs(struct tsession *ts, int *pnum_totty) 89remove_iacs(struct tsession *ts, int *pnum_totty)
83{ 90{
84 unsigned char *ptr0 = TS_BUF1 + ts->wridx1; 91 unsigned char *ptr0 = TS_BUF1(ts) + ts->wridx1;
85 unsigned char *ptr = ptr0; 92 unsigned char *ptr = ptr0;
86 unsigned char *totty = ptr; 93 unsigned char *totty = ptr;
87 unsigned char *end = ptr + MIN(BUFSIZE - ts->wridx1, ts->size1); 94 unsigned char *end = ptr + MIN(BUFSIZE - ts->wridx1, ts->size1);
@@ -199,9 +206,17 @@ static size_t iac_safe_write(int fd, const char *buf, size_t count)
199 return total + rc; 206 return total + rc;
200} 207}
201 208
209/* Must match getopt32 string */
210enum {
211 OPT_WATCHCHILD = (1 << 2), /* -K */
212 OPT_INETD = (1 << 3) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -i */
213 OPT_PORT = (1 << 4) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -p */
214 OPT_FOREGROUND = (1 << 6) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -F */
215};
216
202static struct tsession * 217static struct tsession *
203make_new_session( 218make_new_session(
204 IF_FEATURE_TELNETD_STANDALONE(int sock) 219 IF_FEATURE_TELNETD_STANDALONE(int master_fd, int sock)
205 IF_NOT_FEATURE_TELNETD_STANDALONE(void) 220 IF_NOT_FEATURE_TELNETD_STANDALONE(void)
206) { 221) {
207 const char *login_argv[2]; 222 const char *login_argv[2];
@@ -215,8 +230,8 @@ make_new_session(
215 230
216 /* Got a new connection, set up a tty. */ 231 /* Got a new connection, set up a tty. */
217 fd = xgetpty(tty_name); 232 fd = xgetpty(tty_name);
218 if (fd > maxfd) 233 if (fd > G.maxfd)
219 maxfd = fd; 234 G.maxfd = fd;
220 ts->ptyfd = fd; 235 ts->ptyfd = fd;
221 ndelay_on(fd); 236 ndelay_on(fd);
222#if ENABLE_FEATURE_TELNETD_STANDALONE 237#if ENABLE_FEATURE_TELNETD_STANDALONE
@@ -229,8 +244,8 @@ make_new_session(
229 ndelay_on(sock); 244 ndelay_on(sock);
230 } 245 }
231 ts->sockfd_write = sock; 246 ts->sockfd_write = sock;
232 if (sock > maxfd) 247 if (sock > G.maxfd)
233 maxfd = sock; 248 G.maxfd = sock;
234#else 249#else
235 /* SO_KEEPALIVE by popular demand */ 250 /* SO_KEEPALIVE by popular demand */
236 setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1)); 251 setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1));
@@ -254,7 +269,7 @@ make_new_session(
254 }; 269 };
255 /* This confuses iac_safe_write(), it will try to duplicate 270 /* This confuses iac_safe_write(), it will try to duplicate
256 * each IAC... */ 271 * each IAC... */
257 //memcpy(TS_BUF2, iacs_to_send, sizeof(iacs_to_send)); 272 //memcpy(TS_BUF2(ts), iacs_to_send, sizeof(iacs_to_send));
258 //ts->rdidx2 = sizeof(iacs_to_send); 273 //ts->rdidx2 = sizeof(iacs_to_send);
259 //ts->size2 = sizeof(iacs_to_send); 274 //ts->size2 = sizeof(iacs_to_send);
260 /* So just stuff it into TCP stream! (no error check...) */ 275 /* So just stuff it into TCP stream! (no error check...) */
@@ -288,13 +303,35 @@ make_new_session(
288 /* Restore default signal handling ASAP */ 303 /* Restore default signal handling ASAP */
289 bb_signals((1 << SIGCHLD) + (1 << SIGPIPE), SIG_DFL); 304 bb_signals((1 << SIGCHLD) + (1 << SIGPIPE), SIG_DFL);
290 305
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
291 /* Make new session and process group */ 319 /* Make new session and process group */
292 setsid(); 320 setsid();
293 321
322 close(fd);
323#if ENABLE_FEATURE_TELNETD_STANDALONE
324 if (master_fd >= 0)
325 close(master_fd);
326 close(sock);
327#endif
294 /* Open the child's side of the tty. */ 328 /* Open the child's side of the tty. */
295 /* NB: setsid() disconnects from any previous ctty's. Therefore 329 /* NB: setsid() disconnects from any previous ctty's. Therefore
296 * we must open child's side of the tty AFTER setsid! */ 330 * we must open child's side of the tty AFTER setsid! */
297 close(0); 331#if ENABLE_FEATURE_TELNETD_STANDALONE
332 if (sock != 0) /* if we did not close 0 already */
333#endif
334 close(0);
298 xopen(tty_name, O_RDWR); /* becomes our ctty */ 335 xopen(tty_name, O_RDWR); /* becomes our ctty */
299 xdup2(0, 1); 336 xdup2(0, 1);
300 xdup2(0, 2); 337 xdup2(0, 2);
@@ -316,40 +353,32 @@ make_new_session(
316 * issue files, and they may block writing to fd 1, 353 * issue files, and they may block writing to fd 1,
317 * (parent is supposed to read it, but parent waits 354 * (parent is supposed to read it, but parent waits
318 * for vforked child to exec!) */ 355 * for vforked child to exec!) */
319 print_login_issue(issuefile, tty_name); 356 print_login_issue(G.issuefile, tty_name);
320 357
321 /* Exec shell / login / whatever */ 358 /* Exec shell / login / whatever */
322 login_argv[0] = loginpath; 359 login_argv[0] = G.loginpath;
323 login_argv[1] = NULL; 360 login_argv[1] = NULL;
324 /* exec busybox applet (if PREFER_APPLETS=y), if that fails, 361 /* exec busybox applet (if PREFER_APPLETS=y), if that fails,
325 * exec external program */ 362 * exec external program */
326 BB_EXECVP(loginpath, (char **)login_argv); 363 BB_EXECVP(G.loginpath, (char **)login_argv);
327 /* _exit is safer with vfork, and we shouldn't send message 364 /* _exit is safer with vfork, and we shouldn't send message
328 * to remote clients anyway */ 365 * to remote clients anyway */
329 _exit(EXIT_FAILURE); /*bb_perror_msg_and_die("execv %s", loginpath);*/ 366 _exit(EXIT_FAILURE); /*bb_perror_msg_and_die("execv %s", G.loginpath);*/
330} 367}
331 368
332/* Must match getopt32 string */
333enum {
334 OPT_WATCHCHILD = (1 << 2), /* -K */
335 OPT_INETD = (1 << 3) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -i */
336 OPT_PORT = (1 << 4) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -p */
337 OPT_FOREGROUND = (1 << 6) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -F */
338};
339
340#if ENABLE_FEATURE_TELNETD_STANDALONE 369#if ENABLE_FEATURE_TELNETD_STANDALONE
341 370
342static void 371static void
343free_session(struct tsession *ts) 372free_session(struct tsession *ts)
344{ 373{
345 struct tsession *t = sessions; 374 struct tsession *t = G.sessions;
346 375
347 if (option_mask32 & OPT_INETD) 376 if (option_mask32 & OPT_INETD)
348 exit(EXIT_SUCCESS); 377 exit(EXIT_SUCCESS);
349 378
350 /* Unlink this telnet session from the session list */ 379 /* Unlink this telnet session from the session list */
351 if (t == ts) 380 if (t == ts)
352 sessions = ts->next; 381 G.sessions = ts->next;
353 else { 382 else {
354 while (t->next != ts) 383 while (t->next != ts)
355 t = t->next; 384 t = t->next;
@@ -371,17 +400,17 @@ free_session(struct tsession *ts)
371 free(ts); 400 free(ts);
372 401
373 /* Scan all sessions and find new maxfd */ 402 /* Scan all sessions and find new maxfd */
374 maxfd = 0; 403 G.maxfd = 0;
375 ts = sessions; 404 ts = G.sessions;
376 while (ts) { 405 while (ts) {
377 if (maxfd < ts->ptyfd) 406 if (G.maxfd < ts->ptyfd)
378 maxfd = ts->ptyfd; 407 G.maxfd = ts->ptyfd;
379 if (maxfd < ts->sockfd_read) 408 if (G.maxfd < ts->sockfd_read)
380 maxfd = ts->sockfd_read; 409 G.maxfd = ts->sockfd_read;
381#if 0 410#if 0
382 /* Again, sockfd_write == sockfd_read here */ 411 /* Again, sockfd_write == sockfd_read here */
383 if (maxfd < ts->sockfd_write) 412 if (G.maxfd < ts->sockfd_write)
384 maxfd = ts->sockfd_write; 413 G.maxfd = ts->sockfd_write;
385#endif 414#endif
386 ts = ts->next; 415 ts = ts->next;
387 } 416 }
@@ -404,7 +433,7 @@ static void handle_sigchld(int sig UNUSED_PARAM)
404 pid = wait_any_nohang(NULL); 433 pid = wait_any_nohang(NULL);
405 if (pid <= 0) 434 if (pid <= 0)
406 break; 435 break;
407 ts = sessions; 436 ts = G.sessions;
408 while (ts) { 437 while (ts) {
409 if (ts->shell_pid == pid) { 438 if (ts->shell_pid == pid) {
410 ts->shell_pid = -1; 439 ts->shell_pid = -1;
@@ -435,10 +464,12 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv)
435 portnbr = 23, 464 portnbr = 23,
436 }; 465 };
437#endif 466#endif
467 INIT_G();
468
438 /* Even if !STANDALONE, we accept (and ignore) -i, thus people 469 /* Even if !STANDALONE, we accept (and ignore) -i, thus people
439 * don't need to guess whether it's ok to pass -i to us */ 470 * don't need to guess whether it's ok to pass -i to us */
440 opt = getopt32(argv, "f:l:Ki" IF_FEATURE_TELNETD_STANDALONE("p:b:F"), 471 opt = getopt32(argv, "f:l:Ki" IF_FEATURE_TELNETD_STANDALONE("p:b:F"),
441 &issuefile, &loginpath 472 &G.issuefile, &G.loginpath
442 IF_FEATURE_TELNETD_STANDALONE(, &opt_portnbr, &opt_bindaddr)); 473 IF_FEATURE_TELNETD_STANDALONE(, &opt_portnbr, &opt_bindaddr));
443 if (!IS_INETD /*&& !re_execed*/) { 474 if (!IS_INETD /*&& !re_execed*/) {
444 /* inform that we start in standalone mode? 475 /* inform that we start in standalone mode?
@@ -460,21 +491,21 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv)
460 portnbr = xatou16(opt_portnbr); 491 portnbr = xatou16(opt_portnbr);
461 ); 492 );
462 493
463 /* Used to check access(loginpath, X_OK) here. Pointless. 494 /* Used to check access(G.loginpath, X_OK) here. Pointless.
464 * exec will do this for us for free later. */ 495 * exec will do this for us for free later. */
465 496
466#if ENABLE_FEATURE_TELNETD_STANDALONE 497#if ENABLE_FEATURE_TELNETD_STANDALONE
467 if (IS_INETD) { 498 if (IS_INETD) {
468 sessions = make_new_session(0); 499 G.sessions = make_new_session(-1, 0);
469 if (!sessions) /* pty opening or vfork problem, exit */ 500 if (!G.sessions) /* pty opening or vfork problem, exit */
470 return 1; /* make_new_session prints error message */ 501 return 1; /* make_new_session prints error message */
471 } else { 502 } else {
472 master_fd = create_and_bind_stream_or_die(opt_bindaddr, portnbr); 503 master_fd = create_and_bind_stream_or_die(opt_bindaddr, portnbr);
473 xlisten(master_fd, 1); 504 xlisten(master_fd, 1);
474 } 505 }
475#else 506#else
476 sessions = make_new_session(); 507 G.sessions = make_new_session();
477 if (!sessions) /* pty opening or vfork problem, exit */ 508 if (!G.sessions) /* pty opening or vfork problem, exit */
478 return 1; /* make_new_session prints error message */ 509 return 1; /* make_new_session prints error message */
479#endif 510#endif
480 511
@@ -512,7 +543,7 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv)
512 * ptys if there is room in their session buffers. 543 * ptys if there is room in their session buffers.
513 * NB: scalability problem: we recalculate entire bitmap 544 * NB: scalability problem: we recalculate entire bitmap
514 * before each select. Can be a problem with 500+ connections. */ 545 * before each select. Can be a problem with 500+ connections. */
515 ts = sessions; 546 ts = G.sessions;
516 while (ts) { 547 while (ts) {
517 struct tsession *next = ts->next; /* in case we free ts. */ 548 struct tsession *next = ts->next; /* in case we free ts. */
518 if (ts->shell_pid == -1) { 549 if (ts->shell_pid == -1) {
@@ -535,11 +566,11 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv)
535 /* This is needed because free_session() does not 566 /* This is needed because free_session() does not
536 * take master_fd into account when it finds new 567 * take master_fd into account when it finds new
537 * maxfd among remaining fd's */ 568 * maxfd among remaining fd's */
538 if (master_fd > maxfd) 569 if (master_fd > G.maxfd)
539 maxfd = master_fd; 570 G.maxfd = master_fd;
540 } 571 }
541 572
542 count = select(maxfd + 1, &rdfdset, &wrfdset, NULL, NULL); 573 count = select(G.maxfd + 1, &rdfdset, &wrfdset, NULL, NULL);
543 if (count < 0) 574 if (count < 0)
544 goto again; /* EINTR or ENOMEM */ 575 goto again; /* EINTR or ENOMEM */
545 576
@@ -553,10 +584,10 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv)
553 if (fd < 0) 584 if (fd < 0)
554 goto again; 585 goto again;
555 /* Create a new session and link it into our active list */ 586 /* Create a new session and link it into our active list */
556 new_ts = make_new_session(fd); 587 new_ts = make_new_session(master_fd, fd);
557 if (new_ts) { 588 if (new_ts) {
558 new_ts->next = sessions; 589 new_ts->next = G.sessions;
559 sessions = new_ts; 590 G.sessions = new_ts;
560 } else { 591 } else {
561 close(fd); 592 close(fd);
562 } 593 }
@@ -564,7 +595,7 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv)
564#endif 595#endif
565 596
566 /* Then check for data tunneling. */ 597 /* Then check for data tunneling. */
567 ts = sessions; 598 ts = G.sessions;
568 while (ts) { /* For all sessions... */ 599 while (ts) { /* For all sessions... */
569 struct tsession *next = ts->next; /* in case we free ts. */ 600 struct tsession *next = ts->next; /* in case we free ts. */
570 601
@@ -588,7 +619,7 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv)
588 if (/*ts->size2 &&*/ FD_ISSET(ts->sockfd_write, &wrfdset)) { 619 if (/*ts->size2 &&*/ FD_ISSET(ts->sockfd_write, &wrfdset)) {
589 /* Write to socket from buffer 2. */ 620 /* Write to socket from buffer 2. */
590 count = MIN(BUFSIZE - ts->wridx2, ts->size2); 621 count = MIN(BUFSIZE - ts->wridx2, ts->size2);
591 count = iac_safe_write(ts->sockfd_write, (void*)(TS_BUF2 + ts->wridx2), count); 622 count = iac_safe_write(ts->sockfd_write, (void*)(TS_BUF2(ts) + ts->wridx2), count);
592 if (count < 0) { 623 if (count < 0) {
593 if (errno == EAGAIN) 624 if (errno == EAGAIN)
594 goto skip2; 625 goto skip2;
@@ -618,14 +649,14 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv)
618 if (/*ts->size1 < BUFSIZE &&*/ FD_ISSET(ts->sockfd_read, &rdfdset)) { 649 if (/*ts->size1 < BUFSIZE &&*/ FD_ISSET(ts->sockfd_read, &rdfdset)) {
619 /* Read from socket to buffer 1. */ 650 /* Read from socket to buffer 1. */
620 count = MIN(BUFSIZE - ts->rdidx1, BUFSIZE - ts->size1); 651 count = MIN(BUFSIZE - ts->rdidx1, BUFSIZE - ts->size1);
621 count = safe_read(ts->sockfd_read, TS_BUF1 + ts->rdidx1, count); 652 count = safe_read(ts->sockfd_read, TS_BUF1(ts) + ts->rdidx1, count);
622 if (count <= 0) { 653 if (count <= 0) {
623 if (count < 0 && errno == EAGAIN) 654 if (count < 0 && errno == EAGAIN)
624 goto skip3; 655 goto skip3;
625 goto kill_session; 656 goto kill_session;
626 } 657 }
627 /* Ignore trailing NUL if it is there */ 658 /* Ignore trailing NUL if it is there */
628 if (!TS_BUF1[ts->rdidx1 + count - 1]) { 659 if (!TS_BUF1(ts)[ts->rdidx1 + count - 1]) {
629 --count; 660 --count;
630 } 661 }
631 ts->size1 += count; 662 ts->size1 += count;
@@ -637,7 +668,7 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv)
637 if (/*ts->size2 < BUFSIZE &&*/ FD_ISSET(ts->ptyfd, &rdfdset)) { 668 if (/*ts->size2 < BUFSIZE &&*/ FD_ISSET(ts->ptyfd, &rdfdset)) {
638 /* Read from pty to buffer 2. */ 669 /* Read from pty to buffer 2. */
639 count = MIN(BUFSIZE - ts->rdidx2, BUFSIZE - ts->size2); 670 count = MIN(BUFSIZE - ts->rdidx2, BUFSIZE - ts->size2);
640 count = safe_read(ts->ptyfd, TS_BUF2 + ts->rdidx2, count); 671 count = safe_read(ts->ptyfd, TS_BUF2(ts) + ts->rdidx2, count);
641 if (count <= 0) { 672 if (count <= 0) {
642 if (count < 0 && errno == EAGAIN) 673 if (count < 0 && errno == EAGAIN)
643 goto skip4; 674 goto skip4;