diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2016-10-12 17:36:57 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2016-10-12 17:36:57 +0200 |
commit | 0190c41bb297e8120e217cb531fb34d5035f17d2 (patch) | |
tree | 9782683f56e68a9034e97831d6960df028c356fa | |
parent | 2a54b3e86ebf71d5d5dce7eb95d1aa04a636e780 (diff) | |
download | busybox-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.c | 49 |
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++; |