diff options
-rw-r--r-- | networking/telnetd.c | 17 | ||||
-rw-r--r-- | networking/telnetd.ctrlSQ.patch | 175 |
2 files changed, 184 insertions, 8 deletions
diff --git a/networking/telnetd.c b/networking/telnetd.c index 481c932db..59d609bc8 100644 --- a/networking/telnetd.c +++ b/networking/telnetd.c | |||
@@ -35,8 +35,8 @@ | |||
35 | /* Structure that describes a session */ | 35 | /* Structure that describes a session */ |
36 | struct tsession { | 36 | struct tsession { |
37 | struct tsession *next; | 37 | struct tsession *next; |
38 | pid_t shell_pid; | ||
38 | int sockfd_read, sockfd_write, ptyfd; | 39 | int sockfd_read, sockfd_write, ptyfd; |
39 | int shell_pid; | ||
40 | 40 | ||
41 | /* two circular buffers */ | 41 | /* two circular buffers */ |
42 | /*char *buf1, *buf2;*/ | 42 | /*char *buf1, *buf2;*/ |
@@ -247,7 +247,8 @@ make_new_session( | |||
247 | static const char iacs_to_send[] ALIGN1 = { | 247 | static const char iacs_to_send[] ALIGN1 = { |
248 | IAC, DO, TELOPT_ECHO, | 248 | IAC, DO, TELOPT_ECHO, |
249 | IAC, DO, TELOPT_NAWS, | 249 | IAC, DO, TELOPT_NAWS, |
250 | IAC, DO, TELOPT_LFLOW, | 250 | /* This requires telnetd.ctrlSQ.patch (incomplete) */ |
251 | /* IAC, DO, TELOPT_LFLOW, */ | ||
251 | IAC, WILL, TELOPT_ECHO, | 252 | IAC, WILL, TELOPT_ECHO, |
252 | IAC, WILL, TELOPT_SGA | 253 | IAC, WILL, TELOPT_SGA |
253 | }; | 254 | }; |
@@ -284,13 +285,13 @@ make_new_session( | |||
284 | /* Child */ | 285 | /* Child */ |
285 | /* Careful - we are after vfork! */ | 286 | /* Careful - we are after vfork! */ |
286 | 287 | ||
287 | /* make new session and process group */ | 288 | /* Restore default signal handling ASAP */ |
288 | setsid(); | ||
289 | |||
290 | /* Restore default signal handling */ | ||
291 | bb_signals((1 << SIGCHLD) + (1 << SIGPIPE), SIG_DFL); | 289 | bb_signals((1 << SIGCHLD) + (1 << SIGPIPE), SIG_DFL); |
292 | 290 | ||
293 | /* open the child's side of the tty. */ | 291 | /* Make new session and process group */ |
292 | setsid(); | ||
293 | |||
294 | /* Open the child's side of the tty. */ | ||
294 | /* NB: setsid() disconnects from any previous ctty's. Therefore | 295 | /* NB: setsid() disconnects from any previous ctty's. Therefore |
295 | * we must open child's side of the tty AFTER setsid! */ | 296 | * we must open child's side of the tty AFTER setsid! */ |
296 | close(0); | 297 | close(0); |
@@ -360,7 +361,7 @@ free_session(struct tsession *ts) | |||
360 | * doesn't send SIGKILL. When we close ptyfd, | 361 | * doesn't send SIGKILL. When we close ptyfd, |
361 | * kernel sends SIGHUP to processes having slave side opened. */ | 362 | * kernel sends SIGHUP to processes having slave side opened. */ |
362 | kill(ts->shell_pid, SIGKILL); | 363 | kill(ts->shell_pid, SIGKILL); |
363 | wait4(ts->shell_pid, NULL, 0, NULL); | 364 | waitpid(ts->shell_pid, NULL, 0); |
364 | #endif | 365 | #endif |
365 | close(ts->ptyfd); | 366 | close(ts->ptyfd); |
366 | close(ts->sockfd_read); | 367 | close(ts->sockfd_read); |
diff --git a/networking/telnetd.ctrlSQ.patch b/networking/telnetd.ctrlSQ.patch new file mode 100644 index 000000000..885e10523 --- /dev/null +++ b/networking/telnetd.ctrlSQ.patch | |||
@@ -0,0 +1,175 @@ | |||
1 | From: "Doug Graham" <dgraham@nortel.com> | ||
2 | Date: 2009-01-22 07:20 | ||
3 | |||
4 | Hello, | ||
5 | |||
6 | Busybox's telnetd does not disable local (client-side) flow control | ||
7 | properly. It does not put the pty into packet mode and then notify the | ||
8 | client whenever flow control is disabled by an application running under | ||
9 | its control. The result is that ^S/^Q are not passed through to the | ||
10 | application, which is painful when the application is an emacs variant. | ||
11 | |||
12 | I suppose that support for this might be considered bloat, but the | ||
13 | included patch only adds about 200 bytes of text to x86 busybox and 300 | ||
14 | bytes to mipsel busybox. Please consider applying. | ||
15 | |||
16 | ============================= | ||
17 | |||
18 | NB: the patch doesn't work as-is because we now have iac_safe_write() | ||
19 | which quotes IACs on output. | ||
20 | |||
21 | ============================= | ||
22 | Docs: | ||
23 | |||
24 | The following ioctl(2) calls apply only to pseudo terminals: | ||
25 | |||
26 | TIOCSTOP Stops output to a terminal (e.g. like typing ^S). Takes no parameter. | ||
27 | |||
28 | TIOCSTART Restarts output (stopped by TIOCSTOP or by typing ^S). Takes no parameter. | ||
29 | |||
30 | TIOCPKT Enable/disable packet mode. When applied to the master side of a pseudo terminal, each | ||
31 | subsequent read(2) from the terminal will return data written on the slave part of the pseudo terminal preceded by a | ||
32 | zero byte (symbolically defined as TIOCPKT_DATA), or a single byte reflecting control status information. | ||
33 | In the latter case, the byte is an inclusive-or of zero or more of the bits: | ||
34 | |||
35 | TIOCPKT_FLUSHREAD whenever the read queue for the terminal is flushed. | ||
36 | TIOCPKT_FLUSHWRITE whenever the write queue for the terminal is flushed. | ||
37 | TIOCPKT_STOP whenever output to the terminal is stopped a la ^S. | ||
38 | TIOCPKT_START whenever output to the terminal is restarted. | ||
39 | TIOCPKT_DOSTOP whenever t_stopc is ^S and t_startc is ^Q. | ||
40 | TIOCPKT_NOSTOP whenever the start and stop characters are not ^S/^Q. | ||
41 | |||
42 | While this mode is in use, the presence of control status information to be read from the master side may be detected | ||
43 | by a select(2) for exceptional conditions. | ||
44 | |||
45 | This mode is used by rlogin(1) and rlogind(8) to implement a remote-echoed, locally ^S/^Q flow-controlled remote login | ||
46 | with proper back-flushing of output; it can be used by other similar programs. | ||
47 | |||
48 | TIOCUCNTL Enable/disable a mode that allows a small number of simple user ioctl(2) commands to be passed through | ||
49 | the pseudo-terminal, using a protocol similar to that of TIOCPKT. The TIOCUCNTL and TIOCPKT modes are mutually | ||
50 | exclusive. This mode is enabled from the master side of a pseudo terminal. Each subsequent read(2) from the master side | ||
51 | will return data written on the slave part of the pseudo terminal preceded by a zero byte, or a single byte reflecting a | ||
52 | user control operation on the slave side. A user control command consists of a special ioctl(2) operation with no data; | ||
53 | the command is given as UIOCCMD (n), where n is a number in the range 1-255. The operation value n will be received as | ||
54 | a single byte on the next read(2) from the master side. The ioctl(2) UIOCCMD (0) is a no-op that may be used to probe | ||
55 | for the existence of this facility. As with TIOCPKT mode, command operations may be detected with a select(2) for | ||
56 | exceptional conditions. | ||
57 | |||
58 | --- busybox-1.13.2/networking/telnetd.c 2009/01/21 20:02:39 1.1 | ||
59 | +++ busybox-1.13.2/networking/telnetd.c 2009/01/22 00:35:28 | ||
60 | @@ -38,6 +38,9 @@ | ||
61 | int sockfd_read, sockfd_write, ptyfd; | ||
62 | int shell_pid; | ||
63 | |||
64 | +#ifdef TIOCPKT | ||
65 | + int flowstate; | ||
66 | +#endif | ||
67 | /* two circular buffers */ | ||
68 | /*char *buf1, *buf2;*/ | ||
69 | /*#define TS_BUF1 ts->buf1*/ | ||
70 | @@ -170,6 +173,9 @@ | ||
71 | int fd, pid; | ||
72 | char tty_name[GETPTY_BUFSIZE]; | ||
73 | struct tsession *ts = xzalloc(sizeof(struct tsession) + BUFSIZE * 2); | ||
74 | +#ifdef TIOCPKT | ||
75 | + int on = 1; | ||
76 | +#endif | ||
77 | |||
78 | /*ts->buf1 = (char *)(ts + 1);*/ | ||
79 | /*ts->buf2 = ts->buf1 + BUFSIZE;*/ | ||
80 | @@ -180,6 +186,10 @@ | ||
81 | maxfd = fd; | ||
82 | ts->ptyfd = fd; | ||
83 | ndelay_on(fd); | ||
84 | +#ifdef TIOCPKT | ||
85 | + ioctl(fd, TIOCPKT, &on); | ||
86 | + ts->flowstate = TIOCPKT_DOSTOP; | ||
87 | +#endif | ||
88 | #if ENABLE_FEATURE_TELNETD_STANDALONE | ||
89 | ts->sockfd_read = sock; | ||
90 | /* SO_KEEPALIVE by popular demand */ | ||
91 | @@ -385,6 +395,16 @@ | ||
92 | portnbr = 23, | ||
93 | }; | ||
94 | #endif | ||
95 | +#ifdef TIOCPKT | ||
96 | + int control; | ||
97 | + static const char lflow_on[] = | ||
98 | + {IAC, SB, TELOPT_LFLOW, LFLOW_ON, IAC, SE}; | ||
99 | + static const char lflow_off[] = | ||
100 | + {IAC, SB, TELOPT_LFLOW, LFLOW_OFF, IAC, SE}; | ||
101 | +# define RESERVED sizeof(lflow_on) | ||
102 | +#else | ||
103 | +# define RESERVED 0 | ||
104 | +#endif | ||
105 | /* Even if !STANDALONE, we accept (and ignore) -i, thus people | ||
106 | * don't need to guess whether it's ok to pass -i to us */ | ||
107 | opt = getopt32(argv, "f:l:Ki" USE_FEATURE_TELNETD_STANDALONE("p:b:F"), | ||
108 | @@ -475,7 +495,7 @@ | ||
109 | FD_SET(ts->sockfd_read, &rdfdset); | ||
110 | if (ts->size2 > 0) /* can write to socket */ | ||
111 | FD_SET(ts->sockfd_write, &wrfdset); | ||
112 | - if (ts->size2 < BUFSIZE) /* can read from pty */ | ||
113 | + if (ts->size2 < (BUFSIZE - RESERVED)) /* can read from pty */ | ||
114 | FD_SET(ts->ptyfd, &rdfdset); | ||
115 | } | ||
116 | ts = next; | ||
117 | @@ -593,6 +613,52 @@ | ||
118 | goto skip4; | ||
119 | goto kill_session; | ||
120 | } | ||
121 | +#ifdef TIOCPKT | ||
122 | + control = TS_BUF2[ts->rdidx2]; | ||
123 | + if (--count > 0 && control == TIOCPKT_DATA) { | ||
124 | + /* | ||
125 | + * If we are in packet mode, and we have | ||
126 | + * just read a chunk of actual data from | ||
127 | + * the pty, then there is the TIOCPKT_DATA | ||
128 | + * byte (zero) that we have got to remove | ||
129 | + * somehow. If there were no chars in | ||
130 | + * TS_BUF2 before we did this read, then | ||
131 | + * we can optimize by just advancing wridx2. | ||
132 | + * Otherwise we have to copy the new data down | ||
133 | + * to close the gap (Could use readv() instead). | ||
134 | + */ | ||
135 | + if (ts->size2 == 0) | ||
136 | + ts->wridx2++; | ||
137 | + else { | ||
138 | + memmove(TS_BUF2 + ts->rdidx2, | ||
139 | + TS_BUF2 + ts->rdidx2 + 1, count); | ||
140 | + } | ||
141 | + } | ||
142 | + | ||
143 | + /* | ||
144 | + * If the flow control state changed, notify | ||
145 | + * the client. If "control" is not TIOCPKT_DATA, | ||
146 | + * then there are no data bytes to worry about. | ||
147 | + */ | ||
148 | + if ((control & (TIOCPKT_DOSTOP|TIOCPKT_NOSTOP)) != 0 | ||
149 | + && ts->flowstate != (control & TIOCPKT_DOSTOP)) { | ||
150 | + const char *p = ts->flowstate ? lflow_off : lflow_on; | ||
151 | + | ||
152 | + /* | ||
153 | + * We know we have enough free slots available | ||
154 | + * (see RESERVED) but they are not necessarily | ||
155 | + * contiguous; we may have to wrap. | ||
156 | + */ | ||
157 | + for (count = sizeof(lflow_on); count > 0; count--) { | ||
158 | + TS_BUF2[ts->rdidx2++] = *p++; | ||
159 | + if (ts->rdidx2 >= BUFSIZE) | ||
160 | + ts->rdidx2 = 0; | ||
161 | + ts->size2++; | ||
162 | + } | ||
163 | + | ||
164 | + ts->flowstate = control & TIOCPKT_DOSTOP; | ||
165 | + } | ||
166 | +#endif /* TIOCPKT */ | ||
167 | ts->size2 += count; | ||
168 | ts->rdidx2 += count; | ||
169 | if (ts->rdidx2 >= BUFSIZE) /* actually == BUFSIZE */ | ||
170 | |||
171 | --Doug | ||
172 | _______________________________________________ | ||
173 | busybox mailing list | ||
174 | busybox@busybox.net | ||
175 | http://lists.busybox.net/mailman/listinfo/busybox | ||