Magellan Linux

Annotation of /tags/mkinitrd-6_3_1/busybox/networking/telnetd.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1143 - (hide annotations) (download)
Thu Aug 19 12:44:27 2010 UTC (13 years, 10 months ago) by niro
File MIME type: text/plain
File size: 20641 byte(s)
tagged 'mkinitrd-6_3_1'
1 niro 532 /* vi: set sw=4 ts=4: */
2     /*
3     * Simple telnet server
4     * Bjorn Wesen, Axis Communications AB (bjornw@axis.com)
5     *
6     * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
7     *
8     * ---------------------------------------------------------------------------
9     * (C) Copyright 2000, Axis Communications AB, LUND, SWEDEN
10     ****************************************************************************
11     *
12     * The telnetd manpage says it all:
13     *
14 niro 984 * 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
16     * pseudo-terminal as stdin, stdout, and stderr. Telnetd manipulates the
17     * master side of the pseudo-terminal, implementing the telnet protocol and
18     * passing characters between the remote client and the login process.
19 niro 532 *
20     * Vladimir Oleynik <dzo@simtreas.ru> 2001
21 niro 984 * Set process group corrections, initial busybox port
22 niro 532 */
23     #define DEBUG 0
24    
25 niro 816 #include "libbb.h"
26     #include <syslog.h>
27 niro 532
28     #if DEBUG
29 niro 1123 # define TELCMDS
30     # define TELOPTS
31 niro 532 #endif
32     #include <arpa/telnet.h>
33    
34 niro 1123 #if ENABLE_FEATURE_UTMP
35     # include <utmp.h> /* LOGIN_PROCESS */
36     #endif
37    
38    
39 niro 532 struct tsession {
40     struct tsession *next;
41 niro 984 pid_t shell_pid;
42     int sockfd_read;
43     int sockfd_write;
44     int ptyfd;
45 niro 816
46 niro 532 /* two circular buffers */
47 niro 816 /*char *buf1, *buf2;*/
48 niro 984 /*#define TS_BUF1(ts) ts->buf1*/
49     /*#define TS_BUF2(ts) TS_BUF2(ts)*/
50     #define TS_BUF1(ts) ((unsigned char*)(ts + 1))
51     #define TS_BUF2(ts) (((unsigned char*)(ts + 1)) + BUFSIZE)
52 niro 532 int rdidx1, wridx1, size1;
53     int rdidx2, wridx2, size2;
54     };
55    
56 niro 816 /* Two buffers are directly after tsession in malloced memory.
57     * Make whole thing fit in 4k */
58     enum { BUFSIZE = (4 * 1024 - sizeof(struct tsession)) / 2 };
59 niro 532
60    
61 niro 816 /* Globals */
62 niro 984 struct globals {
63     struct tsession *sessions;
64     const char *loginpath;
65     const char *issuefile;
66     int maxfd;
67 niro 1123 } FIX_ALIASING;
68 niro 984 #define G (*(struct globals*)&bb_common_bufsiz1)
69     #define INIT_G() do { \
70     G.loginpath = "/bin/login"; \
71     G.issuefile = "/etc/issue.net"; \
72     } while (0)
73 niro 532
74    
75     /*
76 niro 816 Remove all IAC's from buf1 (received IACs are ignored and must be removed
77     so as to not be interpreted by the terminal). Make an uninterrupted
78     string of characters fit for the terminal. Do this by packing
79     all characters meant for the terminal sequentially towards the end of buf.
80 niro 532
81 niro 1123 Return a pointer to the beginning of the characters meant for the terminal
82 niro 532 and make *num_totty the number of characters that should be sent to
83     the terminal.
84    
85 niro 1123 Note - if an IAC (3 byte quantity) starts before (bf + len) but extends
86 niro 816 past (bf + len) then that IAC will be left unprocessed and *processed
87     will be less than len.
88 niro 532
89 niro 816 CR-LF ->'s CR mapping is also done here, for convenience.
90    
91     NB: may fail to remove iacs which wrap around buffer!
92 niro 532 */
93 niro 816 static unsigned char *
94 niro 532 remove_iacs(struct tsession *ts, int *pnum_totty)
95     {
96 niro 984 unsigned char *ptr0 = TS_BUF1(ts) + ts->wridx1;
97 niro 532 unsigned char *ptr = ptr0;
98     unsigned char *totty = ptr;
99     unsigned char *end = ptr + MIN(BUFSIZE - ts->wridx1, ts->size1);
100     int num_totty;
101    
102     while (ptr < end) {
103     if (*ptr != IAC) {
104 niro 816 char c = *ptr;
105    
106     *totty++ = c;
107     ptr++;
108     /* We map \r\n ==> \r for pragmatic reasons.
109 niro 532 * Many client implementations send \r\n when
110     * the user hits the CarriageReturn key.
111     */
112 niro 816 if (c == '\r' && ptr < end && (*ptr == '\n' || *ptr == '\0'))
113 niro 532 ptr++;
114 niro 816 continue;
115     }
116 niro 532
117 niro 816 if ((ptr+1) >= end)
118     break;
119     if (ptr[1] == NOP) { /* Ignore? (putty keepalive, etc.) */
120     ptr += 2;
121     continue;
122     }
123     if (ptr[1] == IAC) { /* Literal IAC? (emacs M-DEL) */
124     *totty++ = ptr[1];
125     ptr += 2;
126     continue;
127     }
128    
129     /*
130     * TELOPT_NAWS support!
131     */
132     if ((ptr+2) >= end) {
133 niro 984 /* Only the beginning of the IAC is in the
134 niro 816 buffer we were asked to process, we can't
135 niro 984 process this char */
136 niro 816 break;
137     }
138     /*
139     * IAC -> SB -> TELOPT_NAWS -> 4-byte -> IAC -> SE
140     */
141     if (ptr[1] == SB && ptr[2] == TELOPT_NAWS) {
142     struct winsize ws;
143     if ((ptr+8) >= end)
144     break; /* incomplete, can't process */
145     ws.ws_col = (ptr[3] << 8) | ptr[4];
146     ws.ws_row = (ptr[5] << 8) | ptr[6];
147     ioctl(ts->ptyfd, TIOCSWINSZ, (char *)&ws);
148     ptr += 9;
149     continue;
150     }
151     /* skip 3-byte IAC non-SB cmd */
152 niro 532 #if DEBUG
153 niro 816 fprintf(stderr, "Ignoring IAC %s,%s\n",
154     TELCMD(ptr[1]), TELOPT(ptr[2]));
155 niro 532 #endif
156 niro 816 ptr += 3;
157 niro 532 }
158    
159     num_totty = totty - ptr0;
160     *pnum_totty = num_totty;
161 niro 984 /* The difference between ptr and totty is number of iacs
162     we removed from the stream. Adjust buf1 accordingly */
163 niro 816 if ((ptr - totty) == 0) /* 99.999% of cases */
164     return ptr0;
165     ts->wridx1 += ptr - totty;
166     ts->size1 -= ptr - totty;
167 niro 984 /* Move chars meant for the terminal towards the end of the buffer */
168 niro 532 return memmove(ptr - num_totty, ptr0, num_totty);
169     }
170    
171 niro 984 /*
172     * Converting single IAC into double on output
173     */
174     static size_t iac_safe_write(int fd, const char *buf, size_t count)
175     {
176     const char *IACptr;
177     size_t wr, rc, total;
178 niro 532
179 niro 984 total = 0;
180     while (1) {
181     if (count == 0)
182     return total;
183     if (*buf == (char)IAC) {
184     static const char IACIAC[] ALIGN1 = { IAC, IAC };
185     rc = safe_write(fd, IACIAC, 2);
186     if (rc != 2)
187     break;
188     buf++;
189     total++;
190     count--;
191     continue;
192     }
193     /* count != 0, *buf != IAC */
194     IACptr = memchr(buf, IAC, count);
195     wr = count;
196     if (IACptr)
197     wr = IACptr - buf;
198     rc = safe_write(fd, buf, wr);
199     if (rc != wr)
200     break;
201     buf += rc;
202     total += rc;
203     count -= rc;
204     }
205     /* here: rc - result of last short write */
206     if ((ssize_t)rc < 0) { /* error? */
207     if (total == 0)
208     return rc;
209     rc = 0;
210     }
211     return total + rc;
212     }
213    
214     /* Must match getopt32 string */
215     enum {
216     OPT_WATCHCHILD = (1 << 2), /* -K */
217     OPT_INETD = (1 << 3) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -i */
218     OPT_PORT = (1 << 4) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -p PORT */
219     OPT_FOREGROUND = (1 << 6) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -F */
220     OPT_SYSLOG = (1 << 7) * ENABLE_FEATURE_TELNETD_INETD_WAIT, /* -S */
221     OPT_WAIT = (1 << 8) * ENABLE_FEATURE_TELNETD_INETD_WAIT, /* -w SEC */
222     };
223    
224 niro 532 static struct tsession *
225     make_new_session(
226 niro 984 IF_FEATURE_TELNETD_STANDALONE(int sock)
227     IF_NOT_FEATURE_TELNETD_STANDALONE(void)
228 niro 532 ) {
229 niro 1123 #if !ENABLE_FEATURE_TELNETD_STANDALONE
230     enum { sock = 0 };
231     #endif
232 niro 816 const char *login_argv[2];
233 niro 532 struct termios termbuf;
234     int fd, pid;
235 niro 816 char tty_name[GETPTY_BUFSIZE];
236 niro 532 struct tsession *ts = xzalloc(sizeof(struct tsession) + BUFSIZE * 2);
237    
238 niro 816 /*ts->buf1 = (char *)(ts + 1);*/
239     /*ts->buf2 = ts->buf1 + BUFSIZE;*/
240 niro 532
241 niro 984 /* Got a new connection, set up a tty */
242 niro 816 fd = xgetpty(tty_name);
243 niro 984 if (fd > G.maxfd)
244     G.maxfd = fd;
245 niro 816 ts->ptyfd = fd;
246     ndelay_on(fd);
247 niro 984 close_on_exec_on(fd);
248    
249 niro 816 /* SO_KEEPALIVE by popular demand */
250     setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1));
251 niro 1123 #if ENABLE_FEATURE_TELNETD_STANDALONE
252 niro 984 ts->sockfd_read = sock;
253 niro 816 ndelay_on(sock);
254 niro 984 if (sock == 0) { /* We are called with fd 0 - we are in inetd mode */
255 niro 816 sock++; /* so use fd 1 for output */
256     ndelay_on(sock);
257 niro 532 }
258 niro 816 ts->sockfd_write = sock;
259 niro 984 if (sock > G.maxfd)
260     G.maxfd = sock;
261 niro 532 #else
262 niro 816 /* ts->sockfd_read = 0; - done by xzalloc */
263 niro 532 ts->sockfd_write = 1;
264     ndelay_on(0);
265     ndelay_on(1);
266     #endif
267 niro 984
268 niro 532 /* Make the telnet client understand we will echo characters so it
269     * should not do it locally. We don't tell the client to run linemode,
270     * because we want to handle line editing and tab completion and other
271     * stuff that requires char-by-char support. */
272 niro 816 {
273     static const char iacs_to_send[] ALIGN1 = {
274     IAC, DO, TELOPT_ECHO,
275     IAC, DO, TELOPT_NAWS,
276 niro 984 /* This requires telnetd.ctrlSQ.patch (incomplete) */
277     /* IAC, DO, TELOPT_LFLOW, */
278 niro 816 IAC, WILL, TELOPT_ECHO,
279     IAC, WILL, TELOPT_SGA
280     };
281 niro 984 /* This confuses iac_safe_write(), it will try to duplicate
282     * each IAC... */
283     //memcpy(TS_BUF2(ts), iacs_to_send, sizeof(iacs_to_send));
284     //ts->rdidx2 = sizeof(iacs_to_send);
285     //ts->size2 = sizeof(iacs_to_send);
286     /* So just stuff it into TCP stream! (no error check...) */
287     #if ENABLE_FEATURE_TELNETD_STANDALONE
288     safe_write(sock, iacs_to_send, sizeof(iacs_to_send));
289     #else
290     safe_write(1, iacs_to_send, sizeof(iacs_to_send));
291     #endif
292     /*ts->rdidx2 = 0; - xzalloc did it */
293     /*ts->size2 = 0;*/
294 niro 816 }
295 niro 532
296 niro 984 fflush_all();
297 niro 816 pid = vfork(); /* NOMMU-friendly */
298 niro 532 if (pid < 0) {
299     free(ts);
300     close(fd);
301 niro 816 /* sock will be closed by caller */
302     bb_perror_msg("vfork");
303 niro 532 return NULL;
304     }
305     if (pid > 0) {
306 niro 816 /* Parent */
307 niro 532 ts->shell_pid = pid;
308     return ts;
309     }
310    
311 niro 816 /* Child */
312     /* Careful - we are after vfork! */
313 niro 532
314 niro 984 /* Restore default signal handling ASAP */
315     bb_signals((1 << SIGCHLD) + (1 << SIGPIPE), SIG_DFL);
316    
317 niro 1123 if (ENABLE_FEATURE_UTMP) {
318     len_and_sockaddr *lsa = get_peer_lsa(sock);
319     char *hostname = NULL;
320     if (lsa) {
321     hostname = xmalloc_sockaddr2dotted(&lsa->u.sa);
322     free(lsa);
323     }
324     write_new_utmp(pid, LOGIN_PROCESS, tty_name, /*username:*/ "LOGIN", hostname);
325     free(hostname);
326     }
327    
328 niro 984 /* Make new session and process group */
329 niro 532 setsid();
330    
331 niro 984 /* Open the child's side of the tty */
332 niro 532 /* NB: setsid() disconnects from any previous ctty's. Therefore
333     * we must open child's side of the tty AFTER setsid! */
334 niro 816 close(0);
335     xopen(tty_name, O_RDWR); /* becomes our ctty */
336     xdup2(0, 1);
337     xdup2(0, 2);
338 niro 1123 pid = getpid();
339     tcsetpgrp(0, pid); /* switch this tty's process group to us */
340 niro 532
341 niro 984 /* The pseudo-terminal allocated to the client is configured to operate
342     * in cooked mode, and with XTABS CRMOD enabled (see tty(4)) */
343 niro 532 tcgetattr(0, &termbuf);
344     termbuf.c_lflag |= ECHO; /* if we use readline we dont want this */
345 niro 816 termbuf.c_oflag |= ONLCR | XTABS;
346 niro 532 termbuf.c_iflag |= ICRNL;
347     termbuf.c_iflag &= ~IXOFF;
348     /*termbuf.c_lflag &= ~ICANON;*/
349 niro 816 tcsetattr_stdin_TCSANOW(&termbuf);
350 niro 532
351 niro 984 /* Uses FILE-based I/O to stdout, but does fflush_all(),
352 niro 816 * so should be safe with vfork.
353     * I fear, though, that some users will have ridiculously big
354     * issue files, and they may block writing to fd 1,
355     * (parent is supposed to read it, but parent waits
356     * for vforked child to exec!) */
357 niro 984 print_login_issue(G.issuefile, tty_name);
358 niro 532
359 niro 816 /* Exec shell / login / whatever */
360 niro 984 login_argv[0] = G.loginpath;
361 niro 816 login_argv[1] = NULL;
362     /* exec busybox applet (if PREFER_APPLETS=y), if that fails,
363 niro 984 * exec external program.
364     * NB: sock is either 0 or has CLOEXEC set on it.
365     * fd has CLOEXEC set on it too. These two fds will be closed here.
366     */
367     BB_EXECVP(G.loginpath, (char **)login_argv);
368 niro 816 /* _exit is safer with vfork, and we shouldn't send message
369     * to remote clients anyway */
370 niro 984 _exit(EXIT_FAILURE); /*bb_perror_msg_and_die("execv %s", G.loginpath);*/
371 niro 532 }
372    
373     #if ENABLE_FEATURE_TELNETD_STANDALONE
374    
375     static void
376     free_session(struct tsession *ts)
377     {
378 niro 1123 struct tsession *t;
379 niro 532
380 niro 816 if (option_mask32 & OPT_INETD)
381     exit(EXIT_SUCCESS);
382    
383     /* Unlink this telnet session from the session list */
384 niro 1123 t = G.sessions;
385 niro 532 if (t == ts)
386 niro 984 G.sessions = ts->next;
387 niro 532 else {
388     while (t->next != ts)
389     t = t->next;
390     t->next = ts->next;
391     }
392    
393 niro 816 #if 0
394     /* It was said that "normal" telnetd just closes ptyfd,
395     * doesn't send SIGKILL. When we close ptyfd,
396     * kernel sends SIGHUP to processes having slave side opened. */
397 niro 532 kill(ts->shell_pid, SIGKILL);
398 niro 984 waitpid(ts->shell_pid, NULL, 0);
399 niro 816 #endif
400 niro 532 close(ts->ptyfd);
401     close(ts->sockfd_read);
402 niro 816 /* We do not need to close(ts->sockfd_write), it's the same
403     * as sockfd_read unless we are in inetd mode. But in inetd mode
404     * we do not reach this */
405 niro 532 free(ts);
406    
407 niro 816 /* Scan all sessions and find new maxfd */
408 niro 984 G.maxfd = 0;
409     ts = G.sessions;
410 niro 532 while (ts) {
411 niro 984 if (G.maxfd < ts->ptyfd)
412     G.maxfd = ts->ptyfd;
413     if (G.maxfd < ts->sockfd_read)
414     G.maxfd = ts->sockfd_read;
415 niro 816 #if 0
416     /* Again, sockfd_write == sockfd_read here */
417 niro 984 if (G.maxfd < ts->sockfd_write)
418     G.maxfd = ts->sockfd_write;
419 niro 816 #endif
420 niro 532 ts = ts->next;
421     }
422     }
423    
424     #else /* !FEATURE_TELNETD_STANDALONE */
425    
426 niro 816 /* Used in main() only, thus "return 0" actually is exit(EXIT_SUCCESS). */
427     #define free_session(ts) return 0
428 niro 532
429     #endif
430    
431 niro 816 static void handle_sigchld(int sig UNUSED_PARAM)
432     {
433     pid_t pid;
434     struct tsession *ts;
435 niro 1123 int save_errno = errno;
436 niro 532
437 niro 816 /* Looping: more than one child may have exited */
438     while (1) {
439     pid = wait_any_nohang(NULL);
440     if (pid <= 0)
441     break;
442 niro 984 ts = G.sessions;
443 niro 816 while (ts) {
444     if (ts->shell_pid == pid) {
445     ts->shell_pid = -1;
446 niro 1123 // man utmp:
447     // When init(8) finds that a process has exited, it locates its utmp entry
448     // by ut_pid, sets ut_type to DEAD_PROCESS, and clears ut_user, ut_host
449     // and ut_time with null bytes.
450     // [same applies to other processes which maintain utmp entries, like telnetd]
451     //
452     // We do not bother actually clearing fields:
453     // it might be interesting to know who was logged in and from where
454     update_utmp(pid, DEAD_PROCESS, /*tty_name:*/ NULL, /*username:*/ NULL, /*hostname:*/ NULL);
455 niro 816 break;
456     }
457     ts = ts->next;
458     }
459     }
460 niro 1123
461     errno = save_errno;
462 niro 816 }
463    
464     int telnetd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
465     int telnetd_main(int argc UNUSED_PARAM, char **argv)
466 niro 532 {
467     fd_set rdfdset, wrfdset;
468     unsigned opt;
469 niro 816 int count;
470 niro 532 struct tsession *ts;
471     #if ENABLE_FEATURE_TELNETD_STANDALONE
472     #define IS_INETD (opt & OPT_INETD)
473 niro 984 int master_fd = master_fd; /* for compiler */
474     int sec_linger = sec_linger;
475 niro 532 char *opt_bindaddr = NULL;
476     char *opt_portnbr;
477     #else
478     enum {
479     IS_INETD = 1,
480     master_fd = -1,
481     };
482     #endif
483 niro 984 INIT_G();
484    
485     /* -w NUM, and implies -F. -w and -i don't mix */
486     IF_FEATURE_TELNETD_INETD_WAIT(opt_complementary = "wF:w+:i--w:w--i";)
487 niro 816 /* Even if !STANDALONE, we accept (and ignore) -i, thus people
488     * don't need to guess whether it's ok to pass -i to us */
489 niro 984 opt = getopt32(argv, "f:l:Ki"
490     IF_FEATURE_TELNETD_STANDALONE("p:b:F")
491     IF_FEATURE_TELNETD_INETD_WAIT("Sw:"),
492     &G.issuefile, &G.loginpath
493     IF_FEATURE_TELNETD_STANDALONE(, &opt_portnbr, &opt_bindaddr)
494     IF_FEATURE_TELNETD_INETD_WAIT(, &sec_linger)
495     );
496 niro 816 if (!IS_INETD /*&& !re_execed*/) {
497     /* inform that we start in standalone mode?
498     * May be useful when people forget to give -i */
499     /*bb_error_msg("listening for connections");*/
500     if (!(opt & OPT_FOREGROUND)) {
501     /* DAEMON_CHDIR_ROOT was giving inconsistent
502     * behavior with/without -F, -i */
503     bb_daemonize_or_rexec(0 /*was DAEMON_CHDIR_ROOT*/, argv);
504     }
505     }
506 niro 532 /* Redirect log to syslog early, if needed */
507 niro 984 if (IS_INETD || (opt & OPT_SYSLOG) || !(opt & OPT_FOREGROUND)) {
508     openlog(applet_name, LOG_PID, LOG_DAEMON);
509 niro 532 logmode = LOGMODE_SYSLOG;
510     }
511     #if ENABLE_FEATURE_TELNETD_STANDALONE
512     if (IS_INETD) {
513 niro 984 G.sessions = make_new_session(0);
514     if (!G.sessions) /* pty opening or vfork problem, exit */
515     return 1; /* make_new_session printed error message */
516 niro 532 } else {
517 niro 984 master_fd = 0;
518     if (!(opt & OPT_WAIT)) {
519     unsigned portnbr = 23;
520     if (opt & OPT_PORT)
521     portnbr = xatou16(opt_portnbr);
522     master_fd = create_and_bind_stream_or_die(opt_bindaddr, portnbr);
523     xlisten(master_fd, 1);
524     }
525     close_on_exec_on(master_fd);
526 niro 532 }
527     #else
528 niro 984 G.sessions = make_new_session();
529     if (!G.sessions) /* pty opening or vfork problem, exit */
530     return 1; /* make_new_session printed error message */
531 niro 532 #endif
532    
533     /* We don't want to die if just one session is broken */
534     signal(SIGPIPE, SIG_IGN);
535    
536 niro 816 if (opt & OPT_WATCHCHILD)
537     signal(SIGCHLD, handle_sigchld);
538     else /* prevent dead children from becoming zombies */
539     signal(SIGCHLD, SIG_IGN);
540    
541     /*
542 niro 984 This is how the buffers are used. The arrows indicate data flow.
543    
544 niro 816 +-------+ wridx1++ +------+ rdidx1++ +----------+
545     | | <-------------- | buf1 | <-------------- | |
546     | | size1-- +------+ size1++ | |
547     | pty | | socket |
548     | | rdidx2++ +------+ wridx2++ | |
549     | | --------------> | buf2 | --------------> | |
550     +-------+ size2++ +------+ size2-- +----------+
551    
552     size1: "how many bytes are buffered for pty between rdidx1 and wridx1?"
553     size2: "how many bytes are buffered for socket between rdidx2 and wridx2?"
554    
555     Each session has got two buffers. Buffers are circular. If sizeN == 0,
556     buffer is empty. If sizeN == BUFSIZE, buffer is full. In both these cases
557     rdidxN == wridxN.
558     */
559 niro 532 again:
560     FD_ZERO(&rdfdset);
561     FD_ZERO(&wrfdset);
562 niro 816
563     /* Select on the master socket, all telnet sockets and their
564     * ptys if there is room in their session buffers.
565     * NB: scalability problem: we recalculate entire bitmap
566     * before each select. Can be a problem with 500+ connections. */
567 niro 984 ts = G.sessions;
568 niro 816 while (ts) {
569 niro 984 struct tsession *next = ts->next; /* in case we free ts */
570 niro 816 if (ts->shell_pid == -1) {
571     /* Child died and we detected that */
572     free_session(ts);
573     } else {
574     if (ts->size1 > 0) /* can write to pty */
575     FD_SET(ts->ptyfd, &wrfdset);
576     if (ts->size1 < BUFSIZE) /* can read from socket */
577     FD_SET(ts->sockfd_read, &rdfdset);
578     if (ts->size2 > 0) /* can write to socket */
579     FD_SET(ts->sockfd_write, &wrfdset);
580     if (ts->size2 < BUFSIZE) /* can read from pty */
581     FD_SET(ts->ptyfd, &rdfdset);
582     }
583     ts = next;
584     }
585 niro 532 if (!IS_INETD) {
586     FD_SET(master_fd, &rdfdset);
587     /* This is needed because free_session() does not
588 niro 816 * take master_fd into account when it finds new
589     * maxfd among remaining fd's */
590 niro 984 if (master_fd > G.maxfd)
591     G.maxfd = master_fd;
592 niro 532 }
593    
594 niro 984 {
595     struct timeval *tv_ptr = NULL;
596     #if ENABLE_FEATURE_TELNETD_INETD_WAIT
597     struct timeval tv;
598     if ((opt & OPT_WAIT) && !G.sessions) {
599     tv.tv_sec = sec_linger;
600     tv.tv_usec = 0;
601     tv_ptr = &tv;
602     }
603     #endif
604     count = select(G.maxfd + 1, &rdfdset, &wrfdset, NULL, tv_ptr);
605     }
606     if (count == 0) /* "telnetd -w SEC" timed out */
607     return 0;
608 niro 816 if (count < 0)
609     goto again; /* EINTR or ENOMEM */
610 niro 532
611     #if ENABLE_FEATURE_TELNETD_STANDALONE
612 niro 984 /* Check for and accept new sessions */
613 niro 532 if (!IS_INETD && FD_ISSET(master_fd, &rdfdset)) {
614     int fd;
615     struct tsession *new_ts;
616    
617 niro 816 fd = accept(master_fd, NULL, NULL);
618 niro 532 if (fd < 0)
619     goto again;
620 niro 984 close_on_exec_on(fd);
621    
622     /* Create a new session and link it into active list */
623 niro 816 new_ts = make_new_session(fd);
624 niro 532 if (new_ts) {
625 niro 984 new_ts->next = G.sessions;
626     G.sessions = new_ts;
627 niro 532 } else {
628     close(fd);
629     }
630     }
631     #endif
632    
633 niro 984 /* Then check for data tunneling */
634     ts = G.sessions;
635 niro 532 while (ts) { /* For all sessions... */
636 niro 984 struct tsession *next = ts->next; /* in case we free ts */
637 niro 532
638 niro 816 if (/*ts->size1 &&*/ FD_ISSET(ts->ptyfd, &wrfdset)) {
639 niro 532 int num_totty;
640 niro 816 unsigned char *ptr;
641 niro 984 /* Write to pty from buffer 1 */
642 niro 532 ptr = remove_iacs(ts, &num_totty);
643 niro 816 count = safe_write(ts->ptyfd, ptr, num_totty);
644     if (count < 0) {
645     if (errno == EAGAIN)
646     goto skip1;
647     goto kill_session;
648 niro 532 }
649 niro 816 ts->size1 -= count;
650     ts->wridx1 += count;
651     if (ts->wridx1 >= BUFSIZE) /* actually == BUFSIZE */
652 niro 532 ts->wridx1 = 0;
653     }
654 niro 816 skip1:
655     if (/*ts->size2 &&*/ FD_ISSET(ts->sockfd_write, &wrfdset)) {
656 niro 984 /* Write to socket from buffer 2 */
657 niro 816 count = MIN(BUFSIZE - ts->wridx2, ts->size2);
658 niro 984 count = iac_safe_write(ts->sockfd_write, (void*)(TS_BUF2(ts) + ts->wridx2), count);
659 niro 816 if (count < 0) {
660     if (errno == EAGAIN)
661     goto skip2;
662     goto kill_session;
663 niro 532 }
664 niro 816 ts->size2 -= count;
665     ts->wridx2 += count;
666     if (ts->wridx2 >= BUFSIZE) /* actually == BUFSIZE */
667 niro 532 ts->wridx2 = 0;
668     }
669 niro 816 skip2:
670     /* Should not be needed, but... remove_iacs is actually buggy
671     * (it cannot process iacs which wrap around buffer's end)!
672     * Since properly fixing it requires writing bigger code,
673     * we rely instead on this code making it virtually impossible
674     * to have wrapped iac (people don't type at 2k/second).
675     * It also allows for bigger reads in common case. */
676     if (ts->size1 == 0) {
677     ts->rdidx1 = 0;
678     ts->wridx1 = 0;
679     }
680     if (ts->size2 == 0) {
681     ts->rdidx2 = 0;
682     ts->wridx2 = 0;
683     }
684 niro 532
685 niro 816 if (/*ts->size1 < BUFSIZE &&*/ FD_ISSET(ts->sockfd_read, &rdfdset)) {
686 niro 984 /* Read from socket to buffer 1 */
687 niro 816 count = MIN(BUFSIZE - ts->rdidx1, BUFSIZE - ts->size1);
688 niro 984 count = safe_read(ts->sockfd_read, TS_BUF1(ts) + ts->rdidx1, count);
689 niro 816 if (count <= 0) {
690     if (count < 0 && errno == EAGAIN)
691     goto skip3;
692     goto kill_session;
693 niro 532 }
694 niro 816 /* Ignore trailing NUL if it is there */
695 niro 984 if (!TS_BUF1(ts)[ts->rdidx1 + count - 1]) {
696 niro 816 --count;
697     }
698     ts->size1 += count;
699     ts->rdidx1 += count;
700     if (ts->rdidx1 >= BUFSIZE) /* actually == BUFSIZE */
701 niro 532 ts->rdidx1 = 0;
702     }
703 niro 816 skip3:
704     if (/*ts->size2 < BUFSIZE &&*/ FD_ISSET(ts->ptyfd, &rdfdset)) {
705 niro 984 /* Read from pty to buffer 2 */
706 niro 816 count = MIN(BUFSIZE - ts->rdidx2, BUFSIZE - ts->size2);
707 niro 984 count = safe_read(ts->ptyfd, TS_BUF2(ts) + ts->rdidx2, count);
708 niro 816 if (count <= 0) {
709     if (count < 0 && errno == EAGAIN)
710     goto skip4;
711     goto kill_session;
712 niro 532 }
713 niro 816 ts->size2 += count;
714     ts->rdidx2 += count;
715     if (ts->rdidx2 >= BUFSIZE) /* actually == BUFSIZE */
716 niro 532 ts->rdidx2 = 0;
717     }
718 niro 816 skip4:
719 niro 532 ts = next;
720 niro 816 continue;
721     kill_session:
722 niro 1123 if (ts->shell_pid > 0)
723     update_utmp(ts->shell_pid, DEAD_PROCESS, /*tty_name:*/ NULL, /*username:*/ NULL, /*hostname:*/ NULL);
724 niro 816 free_session(ts);
725     ts = next;
726 niro 532 }
727 niro 816
728 niro 532 goto again;
729     }