aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2016-10-12 17:36:57 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2016-10-12 17:36:57 +0200
commit0190c41bb297e8120e217cb531fb34d5035f17d2 (patch)
tree9782683f56e68a9034e97831d6960df028c356fa
parent2a54b3e86ebf71d5d5dce7eb95d1aa04a636e780 (diff)
downloadbusybox-w32-0190c41bb297e8120e217cb531fb34d5035f17d2.tar.gz
busybox-w32-0190c41bb297e8120e217cb531fb34d5035f17d2.tar.bz2
busybox-w32-0190c41bb297e8120e217cb531fb34d5035f17d2.zip
telnetd: fix a corner case where CRLF->CR translation can misbehave
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--networking/telnetd.c49
1 files changed, 35 insertions, 14 deletions
diff --git a/networking/telnetd.c b/networking/telnetd.c
index 68fccdca8..fa618a9d7 100644
--- a/networking/telnetd.c
+++ b/networking/telnetd.c
@@ -125,48 +125,67 @@ safe_write_to_pty_decode_iac(struct tsession *ts)
125 rc = safe_write(ts->ptyfd, buf, rc); 125 rc = safe_write(ts->ptyfd, buf, rc);
126 if (rc <= 0) 126 if (rc <= 0)
127 return rc; 127 return rc;
128 if (rc < wr && (buf[rc] == '\n' || buf[rc] == '\0')) 128 if (rc < wr /* don't look past available data */
129 && buf[rc-1] == '\r' /* need this: imagine that write was _short_ */
130 && (buf[rc] == '\n' || buf[rc] == '\0')
131 ) {
129 rc++; 132 rc++;
130 133 }
131 goto update_and_return; 134 goto update_and_return;
132 } 135 }
133 136
134 /* buf starts with IAC char. Process that sequence. 137 /* buf starts with IAC char. Process that sequence.
135 * Example: we get this from our own (bbox) telnet client: 138 * Example: we get this from our own (bbox) telnet client:
136 * read(5, "\377\374\1""\377\373\37""\377\372\37\0\262\0@\377\360""\377\375\1""\377\375\3") = 21 139 * read(5, "\377\374\1""\377\373\37""\377\372\37\0\262\0@\377\360""\377\375\1""\377\375\3"):
140 * IAC WONT ECHO, IAC WILL NAWS, IAC SB NAWS <cols> <rows> IAC SE, IAC DO SGA
137 */ 141 */
138 if (wr <= 1) { 142 if (wr <= 1) {
139 /* Only the beginning of the IAC is in the 143/* BUG: only the single IAC byte is in the buffer, we just eat IAC */
140 * buffer we were asked to process, we can't
141 * process this char */
142 rc = 1; 144 rc = 1;
143 goto update_and_return; 145 goto update_and_return;
144 } 146 }
145 147
146 if (buf[1] == IAC) { /* Literal IAC (emacs M-DEL) */ 148 /* 2-byte commands (240..250 and 255):
149 * IAC IAC (255) Literal 255. Supported.
150 * IAC NOP (241) NOP. Supported.
151 * IAC BRK (243) Break. Like serial line break. TODO via tcsendbreak()?
152 * IAC AYT (246) Are you there. Send back evidence that AYT was seen. TODO (send NOP back)?
153 * Implemented only as part of NAWS:
154 * IAC SB (250) Subnegotiation of an option follows.
155 * IAC SE (240) End of subnegotiation.
156 * These don't look useful:
157 * IAC DM (242) Data mark. What is this?
158 * IAC IP (244) Suspend, interrupt or abort the process. (Ancient cousin of ^C).
159 * IAC AO (245) Abort output. "You can continue running, but do not send me the output".
160 * IAC EC (247) Erase character. The receiver should delete the last received char.
161 * IAC EL (248) Erase line. The receiver should delete everything up tp last newline.
162 * IAC GA (249) Go ahead. For half-duplex lines: "now you talk".
163 */
164 if (buf[1] == IAC) { /* Literal 255 (emacs M-DEL) */
147 rc = safe_write(ts->ptyfd, buf, 1); 165 rc = safe_write(ts->ptyfd, buf, 1);
148 if (rc <= 0) 166 if (rc <= 0)
149 return rc; 167 return rc;
150 rc = 2; 168 rc = 2;
151 goto update_and_return; 169 goto update_and_return;
152 } 170 }
153 171 if (buf[1] == NOP) { /* NOP (241). Ignore (putty keepalive, etc) */
154 if (buf[1] == NOP) { /* NOP. Ignore (putty keepalive, etc) */
155 rc = 2; 172 rc = 2;
156 goto update_and_return; 173 goto update_and_return;
157 } 174 }
158 175
159 if (wr <= 2) { 176 if (wr <= 2) {
177/* BUG: only 2 bytes of the IAC is in the buffer, we just eat them */
160 rc = 2; 178 rc = 2;
161 goto update_and_return; 179 goto update_and_return;
162 } 180 }
163 181
164 /* TELOPT_NAWS support */ 182 /* TELOPT_NAWS support */
165 /* IAC, SB, TELOPT_NAWS, 4-byte, IAC, SE */ 183 /* IAC SB, TELOPT_NAWS, 4-byte, IAC SE */
166 if (buf[1] == SB && buf[2] == TELOPT_NAWS) { 184 if (buf[1] == SB && buf[2] == TELOPT_NAWS) {
167 struct winsize ws; 185 struct winsize ws;
168 if (wr <= 8) { 186 if (wr <= 8) {
169 rc = wr; /* incomplete, can't process */ 187/* BUG: incomplete, can't process */
188 rc = wr;
170 goto update_and_return; 189 goto update_and_return;
171 } 190 }
172 memset(&ws, 0, sizeof(ws)); 191 memset(&ws, 0, sizeof(ws));
@@ -176,7 +195,8 @@ safe_write_to_pty_decode_iac(struct tsession *ts)
176 rc = 9; 195 rc = 9;
177 goto update_and_return; 196 goto update_and_return;
178 } 197 }
179 /* Skip 3-byte IAC non-SB cmds */ 198
199 /* Skip 3-byte cmds (assume they are WILL/WONT/DO/DONT 251..254 codes) */
180#if DEBUG 200#if DEBUG
181 fprintf(stderr, "Ignoring IAC %s,%s\n", 201 fprintf(stderr, "Ignoring IAC %s,%s\n",
182 TELCMD(buf[1]), TELOPT(buf[2])); 202 TELCMD(buf[1]), TELOPT(buf[2]));
@@ -189,10 +209,10 @@ safe_write_to_pty_decode_iac(struct tsession *ts)
189 ts->wridx1 = 0; 209 ts->wridx1 = 0;
190 ts->size1 -= rc; 210 ts->size1 -= rc;
191 /* 211 /*
192 * Hack. We cannot process iacs which wrap around buffer's end. 212 * Hack. We cannot process IACs which wrap around buffer's end.
193 * Since properly fixing it requires writing bigger code, 213 * Since properly fixing it requires writing bigger code,
194 * we rely instead on this code making it virtually impossible 214 * we rely instead on this code making it virtually impossible
195 * to have wrapped iac (people don't type at 2k/second). 215 * to have wrapped IAC (people don't type at 2k/second).
196 * It also allows for bigger reads in common case. 216 * It also allows for bigger reads in common case.
197 */ 217 */
198 if (ts->size1 == 0) { /* very typical */ 218 if (ts->size1 == 0) { /* very typical */
@@ -229,6 +249,7 @@ static size_t safe_write_double_iac(int fd, const char *buf, size_t count)
229 if (*buf == (char)IAC) { 249 if (*buf == (char)IAC) {
230 static const char IACIAC[] ALIGN1 = { IAC, IAC }; 250 static const char IACIAC[] ALIGN1 = { IAC, IAC };
231 rc = safe_write(fd, IACIAC, 2); 251 rc = safe_write(fd, IACIAC, 2);
252/* BUG: if partial write was only 1 byte long, we end up emitting just one IAC */
232 if (rc != 2) 253 if (rc != 2)
233 break; 254 break;
234 buf++; 255 buf++;