#if HAVE_AFINET6 -> #ifdef HAVE_AFINET6
[oweals/busybox.git] / networking / telnetd.c
index d51560bfb97ed18d6bb3d5f74206c3d5c01c105a..da7911fcc88156807f4ff5a5c0e61d02006b70e2 100644 (file)
@@ -3,7 +3,7 @@
  * Simple telnet server
  * Bjorn Wesen, Axis Communications AB (bjornw@axis.com)
  *
- * Licensed under GPL, see file LICENSE in this tarball for details.
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
  *
  * ---------------------------------------------------------------------------
  * (C) Copyright 2000, Axis Communications AB, LUND, SWEDEN
 /*#define DEBUG 1 */
 #undef DEBUG
 
-#include <sys/time.h>
-#include <sys/socket.h>
-#include <sys/wait.h>
-#include <sys/ioctl.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <signal.h>
-#include <termios.h>
+#include "busybox.h"
+
 #ifdef DEBUG
 #define TELCMDS
 #define TELOPTS
 #endif
 #include <arpa/telnet.h>
-#include <ctype.h>
 #include <sys/syslog.h>
 
-#include "busybox.h"
 
 #define BUFSIZE 4000
 
@@ -110,7 +96,7 @@ static struct tsession *sessions;
 
 /*
 
-   Remove all IAC's from the buffer pointed to by bf (recieved IACs are ignored
+   Remove all IAC's from the buffer pointed to by bf (received IACs are ignored
    and must be removed so as to not be interpreted by the terminal).  Make an
    uninterrupted string of characters fit for the terminal.  Do this by packing
    all characters meant for the terminal sequentially towards the end of bf.
@@ -202,12 +188,18 @@ getpty(char *line)
 {
        int p;
 #ifdef CONFIG_FEATURE_DEVPTS
-       p = open("/dev/ptmx", 2);
+       p = open("/dev/ptmx", O_RDWR);
        if (p > 0) {
+               const char *name;
                grantpt(p);
                unlockpt(p);
-               strcpy(line, ptsname(p));
-               return(p);
+               name = ptsname(p);
+               if (!name) {
+                       bb_perror_msg("ptsname error (is /dev/pts mounted?)");
+                       return -1;
+               }
+               strcpy(line, name);
+               return p;
        }
 #else
        struct stat stb;
@@ -227,7 +219,8 @@ getpty(char *line)
 #ifdef DEBUG
                        fprintf(stderr, "Trying to open device: %s\n", line);
 #endif
-                       if ((p = open(line, O_RDWR | O_NOCTTY)) >= 0) {
+                       p = open(line, O_RDWR | O_NOCTTY);
+                       if (p >= 0) {
                                line[5] = 't';
                                return p;
                        }
@@ -261,27 +254,23 @@ make_new_session(int sockfd)
        struct termios termbuf;
        int pty, pid;
        char tty_name[32];
-       struct tsession *ts = malloc(sizeof(struct tsession) + BUFSIZE * 2);
+       struct tsession *ts = xzalloc(sizeof(struct tsession) + BUFSIZE * 2);
 
        ts->buf1 = (char *)(&ts[1]);
        ts->buf2 = ts->buf1 + BUFSIZE;
 
 #ifdef CONFIG_FEATURE_TELNETD_INETD
-       ts->sockfd_read = 0;
        ts->sockfd_write = 1;
 #else /* CONFIG_FEATURE_TELNETD_INETD */
        ts->sockfd = sockfd;
 #endif /* CONFIG_FEATURE_TELNETD_INETD */
 
-       ts->rdidx1 = ts->wridx1 = ts->size1 = 0;
-       ts->rdidx2 = ts->wridx2 = ts->size2 = 0;
-
        /* Got a new connection, set up a tty and spawn a shell.  */
 
        pty = getpty(tty_name);
 
        if (pty < 0) {
-               syslog(LOG_ERR, "All terminals in use!");
+               bb_error_msg("all terminals in use");
                return 0;
        }
 
@@ -303,7 +292,7 @@ make_new_session(int sockfd)
        send_iac(ts, WILL, TELOPT_SGA);
 
        if ((pid = fork()) < 0) {
-               syslog(LOG_ERR, "Could not fork");
+               bb_perror_msg("fork");
        }
        if (pid == 0) {
                /* In child, open the child's side of the tty.  */
@@ -314,10 +303,7 @@ make_new_session(int sockfd)
                /* make new process group */
                setsid();
 
-               if (open(tty_name, O_RDWR /*| O_NOCTTY*/) < 0) {
-                       syslog(LOG_ERR, "Could not open tty");
-                       exit(1);
-               }
+               xopen(tty_name, O_RDWR /*| O_NOCTTY*/);
                dup(0);
                dup(0);
 
@@ -341,8 +327,7 @@ make_new_session(int sockfd)
                execv(loginpath, (char *const *)argv_init);
 
                /* NOT REACHED */
-               syslog(LOG_ERR, "execv error");
-               exit(1);
+               bb_perror_msg_and_die("execv");
        }
 
        ts->shell_pid = pid;
@@ -384,23 +369,16 @@ free_session(struct tsession *ts)
 int
 telnetd_main(int argc, char **argv)
 {
-#ifndef CONFIG_FEATURE_TELNETD_INETD
-       sockaddr_type sa;
-       int master_fd;
-#endif /* CONFIG_FEATURE_TELNETD_INETD */
+       unsigned opt;
        fd_set rdfdset, wrfdset;
        int selret;
 #ifndef CONFIG_FEATURE_TELNETD_INETD
+       sockaddr_type sa;
+       int master_fd;
        int on = 1;
-       int portnbr = 23;
+       unsigned 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:b:";
+       char *opt_portnbr, *opt_bindaddr;
 #endif /* CONFIG_FEATURE_TELNETD_INETD */
        int maxlen, w, r;
 
@@ -408,38 +386,31 @@ telnetd_main(int argc, char **argv)
        loginpath = DEFAULT_SHELL;
 #endif
 
-       for (;;) {
-               c = getopt( argc, argv, options);
-               if (c == EOF) break;
-               switch (c) {
-                       case 'f':
-                               issuefile = optarg;
-                               break;
-                       case 'l':
-                               loginpath = optarg;
-                               break;
+       /* We use inetd-style operation unconditionally
+        * (no --foreground option), user most likely will
+        * look into syslog for all errors, even early ones.
+        * Direct all output to syslog at once.
+        */
+       openlog(applet_name, 0, LOG_USER);
+       logmode = LOGMODE_SYSLOG;
+
+       opt = getopt32(argc, argv, "f:l:" SKIP_FEATURE_TELNETD_INETD("p:b:"),
+                       &issuefile, &loginpath
+                       SKIP_FEATURE_TELNETD_INETD(, &opt_portnbr, &opt_bindaddr));
+       //if (opt & 1) // -f
+       //if (opt & 2) // -l
 #ifndef CONFIG_FEATURE_TELNETD_INETD
-                       case 'p':
-                               portnbr = atoi(optarg);
-                               break;
-                       case 'b':
-                               if (inet_aton(optarg, &bind_addr) == 0)
-                                       bb_show_usage();
-                               break;
+       if (opt & 4) portnbr = xatou16(opt_portnbr); // -p
+       if (opt & 8) // -b
+               if (inet_aton(opt_bindaddr, &bind_addr) == 0) bb_show_usage();
 #endif /* CONFIG_FEATURE_TELNETD_INETD */
-                       default:
-                               bb_show_usage();
-               }
-       }
 
        if (access(loginpath, X_OK) < 0) {
-               bb_error_msg_and_die ("'%s' unavailable.", loginpath);
+               bb_error_msg_and_die("'%s' unavailable", loginpath);
        }
 
        argv_init[0] = loginpath;
 
-       openlog(bb_applet_name, 0, LOG_USER);
-
 #ifdef CONFIG_FEATURE_TELNETD_INETD
        maxfd = 1;
        sessions = make_new_session();
@@ -448,7 +419,7 @@ telnetd_main(int argc, char **argv)
 
        /* Grab a TCP socket.  */
 
-       master_fd = bb_xsocket(SOCKET_TYPE, SOCK_STREAM, 0);
+       master_fd = xsocket(SOCKET_TYPE, SOCK_STREAM, 0);
        (void)setsockopt(master_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
 
        /* Set it to listen to specified port.  */
@@ -464,14 +435,14 @@ telnetd_main(int argc, char **argv)
        sa.sin_addr = bind_addr;
 #endif
 
-       bb_xbind(master_fd, (struct sockaddr *) &sa, sizeof(sa));
-       bb_xlisten(master_fd, 1);
-       bb_xdaemon(0, 0);
+       xbind(master_fd, (struct sockaddr *) &sa, sizeof(sa));
+       xlisten(master_fd, 1);
+       xdaemon(0, 0);
 
        maxfd = master_fd;
 #endif /* CONFIG_FEATURE_TELNETD_INETD */
 
-       do {
+       while(1) {
                struct tsession *ts;
 
                FD_ZERO(&rdfdset);
@@ -529,8 +500,8 @@ telnetd_main(int argc, char **argv)
                        socklen_t salen;
 
                        salen = sizeof(sa);
-                       if ((fd = accept(master_fd, (struct sockaddr *)&sa,
-                                               &salen)) < 0) {
+                       fd = accept(master_fd, (struct sockaddr *)&sa, &salen);
+                       if (fd < 0) {
                                continue;
                        } else {
                                /* Create a new session and link it into
@@ -668,7 +639,7 @@ telnetd_main(int argc, char **argv)
                }
 #endif /* CONFIG_FEATURE_TELNETD_INETD */
 
-       } while (1);
+       } /* while(1) */
 
        return 0;
 }