- patch from Denis Vlasenko to add and use bb_xchdir()
[oweals/busybox.git] / networking / telnetd.c
index 3051cfa1e4da2716310608056749b0b7be7b9fbd..1a53c0c0ccf3ed830fb86f6988ced32f8debee36 100644 (file)
@@ -1,10 +1,9 @@
-/* $Id: telnetd.c,v 1.10 2004/02/22 09:45:57 bug1 Exp $
- *
+/* vi: set sw=4 ts=4: */
+/*
  * Simple telnet server
  * Bjorn Wesen, Axis Communications AB (bjornw@axis.com)
  *
- * This file is distributed under the Gnu Public License (GPL),
- * please see the file LICENSE for further information.
+ * Licensed under GPL, see file LICENSE in this tarball for details.
  *
  * ---------------------------------------------------------------------------
  * (C) Copyright 2000, Axis Communications AB, LUND, SWEDEN
@@ -33,6 +32,7 @@
 #include <unistd.h>
 #include <errno.h>
 #include <netinet/in.h>
+#include <arpa/inet.h>
 #include <fcntl.h>
 #include <stdio.h>
 #include <signal.h>
 
 #define BUFSIZE 4000
 
-static const char *loginpath 
+#ifdef CONFIG_FEATURE_IPV6
+#define SOCKET_TYPE    AF_INET6
+typedef struct sockaddr_in6 sockaddr_type;
+#else
+#define SOCKET_TYPE    AF_INET
+typedef struct sockaddr_in sockaddr_type;
+#endif
+
+
 #ifdef CONFIG_LOGIN
- = "/bin/login";
+static const char *loginpath = "/bin/login";
 #else
-;
+static const char *loginpath;
 #endif
 static const char *issuefile = "/etc/issue.net";
 
@@ -85,7 +93,7 @@ struct tsession {
    +-------+     wridx1++     +------+     rdidx1++     +----------+
    |       | <--------------  | buf1 | <--------------  |          |
    |       |     size1--      +------+     size1++      |          |
-   |  pty  |                                            |  socket  |
+   |  pty  |                                       |  socket  |
    |       |     rdidx2++     +------+     wridx2++     |          |
    |       |  --------------> | buf2 |  --------------> |          |
    +-------+     size2++      +------+     size2--      +----------+
@@ -122,7 +130,7 @@ static struct tsession *sessions;
   */
 static char *
 remove_iacs(struct tsession *ts, int *pnum_totty) {
-       unsigned char *ptr0 = ts->buf1 + ts->wridx1;
+       unsigned char *ptr0 = (unsigned char *)ts->buf1 + ts->wridx1;
        unsigned char *ptr = ptr0;
        unsigned char *totty = ptr;
        unsigned char *end = ptr + MIN(BUFSIZE - ts->wridx1, ts->size1);
@@ -157,7 +165,7 @@ remove_iacs(struct tsession *ts, int *pnum_totty) {
                        else if (ptr[1] == SB && ptr[2] == TELOPT_NAWS) {
                                struct winsize ws;
                                if ((ptr+8) >= end)
-                                       break;  /* incomplete, can't process */
+                                       break;  /* incomplete, can't process */
                                ws.ws_col = (ptr[3] << 8) | ptr[4];
                                ws.ws_row = (ptr[5] << 8) | ptr[6];
                                (void) ioctl(ts->ptyfd, TIOCSWINSZ, (char *)&ws);
@@ -269,7 +277,7 @@ make_new_session(int sockfd)
        pty = getpty(tty_name);
 
        if (pty < 0) {
-               syslog_msg(LOG_USER, LOG_ERR, "All network ports in use!");
+               syslog(LOG_ERR, "All network ports in use!");
                return 0;
        }
 
@@ -292,7 +300,7 @@ make_new_session(int sockfd)
 
 
        if ((pid = fork()) < 0) {
-               syslog_msg(LOG_USER, LOG_ERR, "Can`t forking");
+               syslog(LOG_ERR, "Can`t forking");
        }
        if (pid == 0) {
                /* In child, open the child's side of the tty.  */
@@ -304,7 +312,7 @@ make_new_session(int sockfd)
                setsid();
 
                if (open(tty_name, O_RDWR /*| O_NOCTTY*/) < 0) {
-                       syslog_msg(LOG_USER, LOG_ERR, "Could not open tty");
+                       syslog(LOG_ERR, "Could not open tty");
                        exit(1);
                        }
                dup(0);
@@ -330,7 +338,7 @@ make_new_session(int sockfd)
                execv(loginpath, (char *const *)argv_init);
 
                /* NOT REACHED */
-               syslog_msg(LOG_USER, LOG_ERR, "execv error");
+               syslog(LOG_ERR, "execv error");
                exit(1);
        }
 
@@ -374,7 +382,7 @@ int
 telnetd_main(int argc, char **argv)
 {
 #ifndef CONFIG_FEATURE_TELNETD_INETD
-       struct sockaddr_in sa;
+       sockaddr_type sa;
        int master_fd;
 #endif /* CONFIG_FEATURE_TELNETD_INETD */
        fd_set rdfdset, wrfdset;
@@ -382,13 +390,14 @@ telnetd_main(int argc, char **argv)
 #ifndef CONFIG_FEATURE_TELNETD_INETD
        int on = 1;
        int portnbr = 23;
+       struct in_addr bind_addr = { .s_addr = 0x0 };
 #endif /* CONFIG_FEATURE_TELNETD_INETD */
        int c;
        static const char options[] =
 #ifdef CONFIG_FEATURE_TELNETD_INETD
                "f:l:";
 #else /* CONFIG_EATURE_TELNETD_INETD */
-               "f:l:p:";
+               "f:l:p:b:";
 #endif /* CONFIG_FEATURE_TELNETD_INETD */
        int maxlen, w, r;
 
@@ -401,15 +410,19 @@ telnetd_main(int argc, char **argv)
                if (c == EOF) break;
                switch (c) {
                        case 'f':
-                               issuefile = strdup (optarg);
+                               issuefile = optarg;
                                break;
                        case 'l':
-                               loginpath = strdup (optarg);
+                               loginpath = optarg;
                                break;
 #ifndef CONFIG_FEATURE_TELNETD_INETD
                        case 'p':
                                portnbr = atoi(optarg);
                                break;
+                       case 'b':
+                               if (inet_aton(optarg, &bind_addr) == 0)
+                                       bb_show_usage();
+                               break;
 #endif /* CONFIG_FEATURE_TELNETD_INETD */
                        default:
                                bb_show_usage();
@@ -422,6 +435,8 @@ telnetd_main(int argc, char **argv)
 
        argv_init[0] = loginpath;
 
+       openlog(bb_applet_name, 0, LOG_USER);
+
 #ifdef CONFIG_FEATURE_TELNETD_INETD
        maxfd = 1;
        sessions = make_new_session();
@@ -430,29 +445,25 @@ telnetd_main(int argc, char **argv)
 
        /* Grab a TCP socket.  */
 
-       master_fd = socket(AF_INET, SOCK_STREAM, 0);
-       if (master_fd < 0) {
-               bb_perror_msg_and_die("socket");
-       }
+       master_fd = bb_xsocket(SOCKET_TYPE, SOCK_STREAM, 0);
        (void)setsockopt(master_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
 
        /* Set it to listen to specified port.  */
 
        memset((void *)&sa, 0, sizeof(sa));
+#ifdef CONFIG_FEATURE_IPV6
+       sa.sin6_family = AF_INET6;
+       sa.sin6_port = htons(portnbr);
+       /* sa.sin6_addr = bind_addr6; */
+#else
        sa.sin_family = AF_INET;
        sa.sin_port = htons(portnbr);
+       sa.sin_addr = bind_addr;
+#endif
 
-       if (bind(master_fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
-               bb_perror_msg_and_die("bind");
-       }
-
-       if (listen(master_fd, 1) < 0) {
-               bb_perror_msg_and_die("listen");
-       }
-
-       if (daemon(0, 0) < 0)
-               bb_perror_msg_and_die("daemon");
-
+       bb_xbind(master_fd, (struct sockaddr *) &sa, sizeof(sa));
+       bb_xlisten(master_fd, 1);
+       bb_xdaemon(0, 0);
 
        maxfd = master_fd;
 #endif /* CONFIG_FEATURE_TELNETD_INETD */
@@ -540,7 +551,7 @@ telnetd_main(int argc, char **argv)
 #ifndef CONFIG_FEATURE_TELNETD_INETD
                        struct tsession *next = ts->next; /* in case we free ts. */
 #endif /* CONFIG_FEATURE_TELNETD_INETD */
-                       
+
                        if (ts->size1 && FD_ISSET(ts->ptyfd, &wrfdset)) {
                                int num_totty;
                                char *ptr;