X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=networking%2Ftelnetd.c;h=33020f1b416436d6ad1315459704637401ca4a40;hb=3a9365e2732f5df2cdef758bc1f6e5e9da8fbcef;hp=163efaa4213f5f6406838319ca280f8930ce1fdb;hpb=36df04837ad54a4eb559e5c69a81aeeb4d981a72;p=oweals%2Fbusybox.git diff --git a/networking/telnetd.c b/networking/telnetd.c index 163efaa42..33020f1b4 100644 --- a/networking/telnetd.c +++ b/networking/telnetd.c @@ -3,7 +3,7 @@ * Simple telnet server * Bjorn Wesen, Axis Communications AB (bjornw@axis.com) * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. * * --------------------------------------------------------------------------- * (C) Copyright 2000, Axis Communications AB, LUND, SWEDEN @@ -21,17 +21,38 @@ * Set process group corrections, initial busybox port */ +//usage:#define telnetd_trivial_usage +//usage: "[OPTIONS]" +//usage:#define telnetd_full_usage "\n\n" +//usage: "Handle incoming telnet connections" +//usage: IF_NOT_FEATURE_TELNETD_STANDALONE(" via inetd") "\n" +//usage: "\n -l LOGIN Exec LOGIN on connect" +//usage: "\n -f ISSUE_FILE Display ISSUE_FILE instead of /etc/issue" +//usage: "\n -K Close connection as soon as login exits" +//usage: "\n (normally wait until all programs close slave pty)" +//usage: IF_FEATURE_TELNETD_STANDALONE( +//usage: "\n -p PORT Port to listen on" +//usage: "\n -b ADDR[:PORT] Address to bind to" +//usage: "\n -F Run in foreground" +//usage: "\n -i Inetd mode" +//usage: IF_FEATURE_TELNETD_INETD_WAIT( +//usage: "\n -w SEC Inetd 'wait' mode, linger time SEC" +//usage: "\n -S Log to syslog (implied by -i or without -F and -w)" +//usage: ) +//usage: ) + #define DEBUG 0 #include "libbb.h" #include #if DEBUG -#define TELCMDS -#define TELOPTS +# define TELCMDS +# define TELOPTS #endif #include + struct tsession { struct tsession *next; pid_t shell_pid; @@ -60,7 +81,7 @@ struct globals { const char *loginpath; const char *issuefile; int maxfd; -}; +} FIX_ALIASING; #define G (*(struct globals*)&bb_common_bufsiz1) #define INIT_G() do { \ G.loginpath = "/bin/login"; \ @@ -74,11 +95,11 @@ struct globals { string of characters fit for the terminal. Do this by packing all characters meant for the terminal sequentially towards the end of buf. - Return a pointer to the beginning of the characters meant for the terminal. + Return a pointer to the beginning of the characters meant for the terminal and make *num_totty the number of characters that should be sent to the terminal. - Note - If an IAC (3 byte quantity) starts before (bf + len) but extends + Note - if an IAC (3 byte quantity) starts before (bf + len) but extends past (bf + len) then that IAC will be left unprocessed and *processed will be less than len. @@ -137,7 +158,7 @@ remove_iacs(struct tsession *ts, int *pnum_totty) 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]; ioctl(ts->ptyfd, TIOCSWINSZ, (char *)&ws); @@ -222,6 +243,9 @@ make_new_session( IF_FEATURE_TELNETD_STANDALONE(int sock) IF_NOT_FEATURE_TELNETD_STANDALONE(void) ) { +#if !ENABLE_FEATURE_TELNETD_STANDALONE + enum { sock = 0 }; +#endif const char *login_argv[2]; struct termios termbuf; int fd, pid; @@ -239,9 +263,9 @@ make_new_session( ndelay_on(fd); close_on_exec_on(fd); -#if ENABLE_FEATURE_TELNETD_STANDALONE /* SO_KEEPALIVE by popular demand */ setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1)); +#if ENABLE_FEATURE_TELNETD_STANDALONE ts->sockfd_read = sock; ndelay_on(sock); if (sock == 0) { /* We are called with fd 0 - we are in inetd mode */ @@ -252,8 +276,6 @@ make_new_session( if (sock > G.maxfd) G.maxfd = sock; #else - /* SO_KEEPALIVE by popular demand */ - setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1)); /* ts->sockfd_read = 0; - done by xzalloc */ ts->sockfd_write = 1; ndelay_on(0); @@ -268,8 +290,8 @@ make_new_session( static const char iacs_to_send[] ALIGN1 = { IAC, DO, TELOPT_ECHO, IAC, DO, TELOPT_NAWS, - /* This requires telnetd.ctrlSQ.patch (incomplete) */ - /* IAC, DO, TELOPT_LFLOW, */ + /* This requires telnetd.ctrlSQ.patch (incomplete) */ + /*IAC, DO, TELOPT_LFLOW,*/ IAC, WILL, TELOPT_ECHO, IAC, WILL, TELOPT_SGA }; @@ -288,7 +310,7 @@ make_new_session( /*ts->size2 = 0;*/ } - fflush(NULL); /* flush all streams */ + fflush_all(); pid = vfork(); /* NOMMU-friendly */ if (pid < 0) { free(ts); @@ -309,6 +331,19 @@ make_new_session( /* Restore default signal handling ASAP */ bb_signals((1 << SIGCHLD) + (1 << SIGPIPE), SIG_DFL); + pid = getpid(); + + if (ENABLE_FEATURE_UTMP) { + len_and_sockaddr *lsa = get_peer_lsa(sock); + char *hostname = NULL; + if (lsa) { + hostname = xmalloc_sockaddr2dotted(&lsa->u.sa); + free(lsa); + } + write_new_utmp(pid, LOGIN_PROCESS, tty_name, /*username:*/ "LOGIN", hostname); + free(hostname); + } + /* Make new session and process group */ setsid(); @@ -319,7 +354,7 @@ make_new_session( xopen(tty_name, O_RDWR); /* becomes our ctty */ xdup2(0, 1); xdup2(0, 2); - tcsetpgrp(0, getpid()); /* switch this tty's process group to us */ + tcsetpgrp(0, pid); /* switch this tty's process group to us */ /* The pseudo-terminal allocated to the client is configured to operate * in cooked mode, and with XTABS CRMOD enabled (see tty(4)) */ @@ -331,7 +366,7 @@ make_new_session( /*termbuf.c_lflag &= ~ICANON;*/ tcsetattr_stdin_TCSANOW(&termbuf); - /* Uses FILE-based I/O to stdout, but does fflush(stdout), + /* Uses FILE-based I/O to stdout, but does fflush_all(), * so should be safe with vfork. * I fear, though, that some users will have ridiculously big * issue files, and they may block writing to fd 1, @@ -358,12 +393,13 @@ make_new_session( static void free_session(struct tsession *ts) { - struct tsession *t = G.sessions; + struct tsession *t; if (option_mask32 & OPT_INETD) exit(EXIT_SUCCESS); /* Unlink this telnet session from the session list */ + t = G.sessions; if (t == ts) G.sessions = ts->next; else { @@ -414,6 +450,7 @@ static void handle_sigchld(int sig UNUSED_PARAM) { pid_t pid; struct tsession *ts; + int save_errno = errno; /* Looping: more than one child may have exited */ while (1) { @@ -424,11 +461,22 @@ static void handle_sigchld(int sig UNUSED_PARAM) while (ts) { if (ts->shell_pid == pid) { ts->shell_pid = -1; +// man utmp: +// When init(8) finds that a process has exited, it locates its utmp entry +// by ut_pid, sets ut_type to DEAD_PROCESS, and clears ut_user, ut_host +// and ut_time with null bytes. +// [same applies to other processes which maintain utmp entries, like telnetd] +// +// We do not bother actually clearing fields: +// it might be interesting to know who was logged in and from where + update_utmp(pid, DEAD_PROCESS, /*tty_name:*/ NULL, /*username:*/ NULL, /*hostname:*/ NULL); break; } ts = ts->next; } } + + errno = save_errno; } int telnetd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; @@ -689,6 +737,8 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv) ts = next; continue; kill_session: + if (ts->shell_pid > 0) + update_utmp(ts->shell_pid, DEAD_PROCESS, /*tty_name:*/ NULL, /*username:*/ NULL, /*hostname:*/ NULL); free_session(ts); ts = next; }