blob: 7235975247b39b39b9f234dfa9f94b39ff8d7c88 [file] [log] [blame]
Sean Middleditch6aef0732009-03-12 23:27:35 -04001/*
Sean Middleditch9de15982009-03-14 03:35:49 -04002 * Sean Middleditch
3 * sean@sourcemud.org
4 *
Sean Middleditch6aef0732009-03-12 23:27:35 -04005 * The author or authors of this code dedicate any and all copyright interest
6 * in this code to the public domain. We make this dedication for the benefit
7 * of the public at large and to the detriment of our heirs and successors. We
8 * intend this dedication to be an overt act of relinquishment in perpetuity of
9 * all present and future rights to this code under copyright law.
10 */
11
Sean Middleditch4d9444d2009-03-13 22:48:05 -040012#include <malloc.h>
Sean Middleditch9de15982009-03-14 03:35:49 -040013#include <string.h>
Sean Middleditchd922c6f2009-03-14 22:35:01 -040014#include <stdio.h>
15#include <errno.h>
16#include <string.h>
17#include <stdarg.h>
Sean Middleditch9de15982009-03-14 03:35:49 -040018
19#ifdef HAVE_ZLIB
20#include "zlib.h"
21#endif
22
Sean Middleditch29144852009-03-12 23:14:47 -040023#include "libtelnet.h"
24
Sean Middleditch5b5bc922009-03-15 23:02:10 -040025/* RFC1143 state names */
26#define RFC1143_NO 0x00
27#define RFC1143_YES 0x01
28
29#define RFC1143_WANT 0x02
30#define RFC1143_OP 0x04
31
32#define RFC1143_WANTNO (RFC1143_WANT|RFC1143_YES)
33#define RFC1143_WANTYES (RFC1143_WANT|RFC1143_NO)
34#define RFC1143_WANTNO_OP (RFC1143_WANTNO|RFC1143_OP)
35#define RFC1143_WANTYES_OP (RFC1143_WANTYES|RFC1143_OP)
36
Sean Middleditch4d9444d2009-03-13 22:48:05 -040037/* buffer sizes */
38static const unsigned int _buffer_sizes[] = {
39 0,
40 512,
41 2048,
42 8192,
43 16384,
44};
Sean Middleditch812358d2009-03-15 23:24:03 -040045static const unsigned int _buffer_sizes_count = sizeof(_buffer_sizes) /
46 sizeof(_buffer_sizes[0]);
Sean Middleditch4d9444d2009-03-13 22:48:05 -040047
Sean Middleditch5b5bc922009-03-15 23:02:10 -040048/* event dispatch helper; return value is value of the accept field of the
49 * event struct after dispatch; used for the funky REQUEST event */
Sean Middleditch35b95be2009-03-15 23:46:31 -040050static int _event(libtelnet_t *telnet, libtelnet_event_type_t type,
Sean Middleditch97a8cb22009-03-16 16:51:41 -040051 unsigned char command, unsigned char telopt,
Sean Middleditch8daf7742009-03-19 02:05:24 -040052 const char *buffer, unsigned int size) {
Sean Middleditch812358d2009-03-15 23:24:03 -040053 libtelnet_event_t ev;
Sean Middleditch5b5bc922009-03-15 23:02:10 -040054 ev.buffer = buffer;
55 ev.size = size;
Sean Middleditch637df7f2009-03-15 12:57:32 -040056 ev.type = type;
57 ev.command = command;
58 ev.telopt = telopt;
Sean Middleditch5b5bc922009-03-15 23:02:10 -040059 ev.accept = 0;
Sean Middleditch637df7f2009-03-15 12:57:32 -040060
Sean Middleditch9f79cc52009-03-15 13:39:24 -040061 telnet->eh(telnet, &ev, telnet->ud);
Sean Middleditch5b5bc922009-03-15 23:02:10 -040062
63 return ev.accept;
Sean Middleditch637df7f2009-03-15 12:57:32 -040064}
65
Sean Middleditchd922c6f2009-03-14 22:35:01 -040066/* error generation function */
Sean Middleditchfbe93e32009-03-15 23:39:31 -040067static libtelnet_error_t _error(libtelnet_t *telnet, unsigned line,
68 const char* func, libtelnet_error_t err, int fatal, const char *fmt,
69 ...) {
Sean Middleditchd922c6f2009-03-14 22:35:01 -040070 char buffer[512];
71 va_list va;
72
73 /* format error intro */
Sean Middleditch812358d2009-03-15 23:24:03 -040074 snprintf(buffer, sizeof(buffer), "%s:%u in %s: ", __FILE__, line, func);
Sean Middleditchd922c6f2009-03-14 22:35:01 -040075
76 va_start(va, fmt);
77 vsnprintf(buffer + strlen(buffer), sizeof(buffer) - strlen(buffer),
78 fmt, va);
79 va_end(va);
80
Sean Middleditch16992272009-03-15 19:42:03 -040081 _event(telnet, fatal ? LIBTELNET_EV_ERROR : LIBTELNET_EV_WARNING, err,
Sean Middleditch8daf7742009-03-19 02:05:24 -040082 0, (char *)buffer, strlen(buffer));
Sean Middleditchfbe93e32009-03-15 23:39:31 -040083
84 return err;
Sean Middleditchd922c6f2009-03-14 22:35:01 -040085}
86
Sean Middleditche5b47592009-03-16 17:37:43 -040087#ifdef HAVE_ZLIB
Sean Middleditch72cc9642009-03-15 11:50:36 -040088/* initialize the zlib box for a telnet box; if deflate is non-zero, it
89 * initializes zlib for delating (compression), otherwise for inflating
Sean Middleditchfbe93e32009-03-15 23:39:31 -040090 * (decompression). returns LIBTELNET_EOK on success, something else on
91 * failure.
Sean Middleditch72cc9642009-03-15 11:50:36 -040092 */
Sean Middleditchfbe93e32009-03-15 23:39:31 -040093libtelnet_error_t _init_zlib(libtelnet_t *telnet, int deflate, int err_fatal) {
94 z_stream *z;
Sean Middleditch72cc9642009-03-15 11:50:36 -040095 int rs;
96
Sean Middleditchfbe93e32009-03-15 23:39:31 -040097 /* if compression is already enabled, fail loudly */
98 if (telnet->z != 0)
99 return _error(telnet, __LINE__, __func__, LIBTELNET_EBADVAL,
100 err_fatal, "cannot initialize compression twice");
101
Sean Middleditch72cc9642009-03-15 11:50:36 -0400102 /* allocate zstream box */
Sean Middleditchfbe93e32009-03-15 23:39:31 -0400103 if ((z= (z_stream *)calloc(1, sizeof(z_stream))) == 0)
104 return _error(telnet, __LINE__, __func__, LIBTELNET_ENOMEM, err_fatal,
Sean Middleditch16992272009-03-15 19:42:03 -0400105 "malloc() failed: %s", strerror(errno));
Sean Middleditch72cc9642009-03-15 11:50:36 -0400106
107 /* initialize */
108 if (deflate) {
Sean Middleditchfbe93e32009-03-15 23:39:31 -0400109 if ((rs = deflateInit(z, Z_DEFAULT_COMPRESSION)) != Z_OK) {
110 free(z);
111 return _error(telnet, __LINE__, __func__, LIBTELNET_ECOMPRESS,
112 err_fatal, "deflateInit() failed: %s", zError(rs));
Sean Middleditch72cc9642009-03-15 11:50:36 -0400113 }
Sean Middleditchfbe93e32009-03-15 23:39:31 -0400114 telnet->flags |= LIBTELNET_PFLAG_DEFLATE;
Sean Middleditch72cc9642009-03-15 11:50:36 -0400115 } else {
Sean Middleditchfbe93e32009-03-15 23:39:31 -0400116 if ((rs = inflateInit(z)) != Z_OK) {
117 free(z);
118 return _error(telnet, __LINE__, __func__, LIBTELNET_ECOMPRESS,
119 err_fatal, "inflateInit() failed: %s", zError(rs));
Sean Middleditch72cc9642009-03-15 11:50:36 -0400120 }
Sean Middleditchfbe93e32009-03-15 23:39:31 -0400121 telnet->flags &= ~LIBTELNET_PFLAG_DEFLATE;
Sean Middleditch72cc9642009-03-15 11:50:36 -0400122 }
123
Sean Middleditchfbe93e32009-03-15 23:39:31 -0400124 telnet->z = z;
125
126 return LIBTELNET_EOK;
Sean Middleditch72cc9642009-03-15 11:50:36 -0400127}
Sean Middleditche5b47592009-03-16 17:37:43 -0400128#endif
Sean Middleditch72cc9642009-03-15 11:50:36 -0400129
Sean Middleditch8b788962009-03-16 01:06:27 -0400130/* push bytes out, compressing them first if need be */
Sean Middleditch8daf7742009-03-19 02:05:24 -0400131static void _send(libtelnet_t *telnet, const char *buffer,
Sean Middleditch8b788962009-03-16 01:06:27 -0400132 unsigned int size) {
133#ifdef HAVE_ZLIB
134 /* if we have a deflate (compression) zlib box, use it */
Sean Middleditch823bc002009-03-16 01:09:26 -0400135 if (telnet->z != 0 && telnet->flags & LIBTELNET_PFLAG_DEFLATE) {
Sean Middleditch8daf7742009-03-19 02:05:24 -0400136 char deflate_buffer[1024];
Sean Middleditch8b788962009-03-16 01:06:27 -0400137 int rs;
138
139 /* initialize z state */
Sean Middleditch97a8cb22009-03-16 16:51:41 -0400140 telnet->z->next_in = (unsigned char *)buffer;
Sean Middleditch8b788962009-03-16 01:06:27 -0400141 telnet->z->avail_in = size;
Sean Middleditch8daf7742009-03-19 02:05:24 -0400142 telnet->z->next_out = (unsigned char *)deflate_buffer;
Sean Middleditch8b788962009-03-16 01:06:27 -0400143 telnet->z->avail_out = sizeof(deflate_buffer);
144
145 /* deflate until buffer exhausted and all output is produced */
146 while (telnet->z->avail_in > 0 || telnet->z->avail_out == 0) {
147 /* compress */
148 if ((rs = deflate(telnet->z, Z_SYNC_FLUSH)) != Z_OK) {
149 _error(telnet, __LINE__, __func__, LIBTELNET_ECOMPRESS, 1,
150 "deflate() failed: %s", zError(rs));
151 deflateEnd(telnet->z);
152 free(telnet->z);
153 telnet->z = 0;
154 break;
155 }
156
157 _event(telnet, LIBTELNET_EV_SEND, 0, 0, deflate_buffer,
158 sizeof(deflate_buffer) - telnet->z->avail_out);
159
160 /* prepare output buffer for next run */
Sean Middleditch8daf7742009-03-19 02:05:24 -0400161 telnet->z->next_out = (unsigned char *)deflate_buffer;
Sean Middleditch8b788962009-03-16 01:06:27 -0400162 telnet->z->avail_out = sizeof(deflate_buffer);
163 }
164
165 /* COMPRESS2 is not negotiated, just send */
166 } else
167#endif /* HAVE_ZLIB */
168 _event(telnet, LIBTELNET_EV_SEND, 0, 0, buffer, size);
169}
170
171/* retrieve RFC1143 option state */
172libtelnet_rfc1143_t _get_rfc1143(libtelnet_t *telnet, unsigned char telopt) {
173 static const libtelnet_rfc1143_t empty = { 0, 0, 0};
174 int i;
175
176 /* search for entry */
177 for (i = 0; i != telnet->q_size; ++i)
178 if (telnet->q[i].telopt == telopt)
179 return telnet->q[i];
180
181 /* not found, return empty value */
182 return empty;
183}
184
185/* save RFC1143 option state */
186void _set_rfc1143(libtelnet_t *telnet, libtelnet_rfc1143_t q) {
187 libtelnet_rfc1143_t *qtmp;
188 int i;
189
190 /* search for entry */
191 for (i = 0; i != telnet->q_size; ++i) {
192 if (telnet->q[i].telopt == q.telopt) {
193 telnet->q[i] = q;
194 return;
195 }
196 }
197
198 /* we're going to need to track state for it, so grow the queue
199 * and put the telopt into it; bail on allocation error
200 */
201 if ((qtmp = (libtelnet_rfc1143_t *)malloc(sizeof(
202 libtelnet_rfc1143_t) * (telnet->q_size + 1))) == 0) {
203 _error(telnet, __LINE__, __func__, LIBTELNET_ENOMEM, 0,
204 "malloc() failed: %s", strerror(errno));
205 return;
206 }
207 telnet->q = qtmp;
208 telnet->q[telnet->q_size++] = q;
209}
210
Sean Middleditch8b788962009-03-16 01:06:27 -0400211/* negotiation handling magic for RFC1143 */
212static void _negotiate(libtelnet_t *telnet, unsigned char cmd,
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400213 unsigned char telopt) {
Sean Middleditch8b788962009-03-16 01:06:27 -0400214 libtelnet_rfc1143_t q;
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400215
216 /* in PROXY mode, just pass it thru and do nothing */
Sean Middleditch562257e2009-03-15 23:56:25 -0400217 if (telnet->flags & LIBTELNET_FLAG_PROXY) {
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400218 switch (cmd) {
219 case LIBTELNET_WILL:
Sean Middleditch562257e2009-03-15 23:56:25 -0400220 _event(telnet, LIBTELNET_EV_WILL, 0, telopt, 0, 0);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400221 break;
222 case LIBTELNET_WONT:
Sean Middleditch562257e2009-03-15 23:56:25 -0400223 _event(telnet, LIBTELNET_EV_WONT, 0, telopt, 0, 0);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400224 break;
225 case LIBTELNET_DO:
Sean Middleditch562257e2009-03-15 23:56:25 -0400226 _event(telnet, LIBTELNET_EV_DO, 0, telopt, 0, 0);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400227 break;
228 case LIBTELNET_DONT:
Sean Middleditch562257e2009-03-15 23:56:25 -0400229 _event(telnet, LIBTELNET_EV_DONT, 0, telopt, 0, 0);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400230 break;
231 }
232 return;
233 }
234
235 /* lookup the current state of the option */
Sean Middleditch8b788962009-03-16 01:06:27 -0400236 q = _get_rfc1143(telnet, telopt);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400237
238 /* start processing... */
239 switch (cmd) {
240 /* request to enable option on remote end or confirm DO */
241 case LIBTELNET_WILL:
Sean Middleditch8b788962009-03-16 01:06:27 -0400242 switch (q.him) {
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400243 case RFC1143_NO:
244 if (_event(telnet, LIBTELNET_EV_WILL, cmd, telopt, 0, 0) == 1) {
Sean Middleditch8b788962009-03-16 01:06:27 -0400245 q.him = RFC1143_YES;
246 _set_rfc1143(telnet, q);
Sean Middleditch2b4bfc42009-03-16 01:25:52 -0400247 libtelnet_send_telopt(telnet, LIBTELNET_DO, telopt);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400248 } else
Sean Middleditch2b4bfc42009-03-16 01:25:52 -0400249 libtelnet_send_telopt(telnet, LIBTELNET_DONT, telopt);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400250 break;
251 case RFC1143_YES:
252 break;
253 case RFC1143_WANTNO:
Sean Middleditch8b788962009-03-16 01:06:27 -0400254 q.him = RFC1143_NO;
255 _set_rfc1143(telnet, q);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400256 _error(telnet, __LINE__, __func__, LIBTELNET_EPROTOCOL, 0,
257 "DONT answered by WILL");
258 break;
259 case RFC1143_WANTNO_OP:
Sean Middleditch8b788962009-03-16 01:06:27 -0400260 q.him = RFC1143_YES;
261 _set_rfc1143(telnet, q);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400262 _error(telnet, __LINE__, __func__, LIBTELNET_EPROTOCOL, 0,
263 "DONT answered by WILL");
264 break;
265 case RFC1143_WANTYES:
Sean Middleditch8b788962009-03-16 01:06:27 -0400266 q.him = RFC1143_YES;
267 _set_rfc1143(telnet, q);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400268 break;
269 case RFC1143_WANTYES_OP:
Sean Middleditch8b788962009-03-16 01:06:27 -0400270 q.him = RFC1143_WANTNO;
271 _set_rfc1143(telnet, q);
Sean Middleditch2b4bfc42009-03-16 01:25:52 -0400272 libtelnet_send_telopt(telnet, LIBTELNET_DONT, telopt);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400273 break;
274 }
275 break;
276
277 /* request to disable option on remote end, confirm DONT, reject DO */
278 case LIBTELNET_WONT:
Sean Middleditch8b788962009-03-16 01:06:27 -0400279 switch (q.him) {
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400280 case RFC1143_NO:
281 break;
282 case RFC1143_YES:
Sean Middleditch8b788962009-03-16 01:06:27 -0400283 q.him = RFC1143_NO;
284 _set_rfc1143(telnet, q);
Sean Middleditch2b4bfc42009-03-16 01:25:52 -0400285 libtelnet_send_telopt(telnet, LIBTELNET_DONT, telopt);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400286 _event(telnet, LIBTELNET_EV_WONT, 0, telopt,
287 0, 0);
288 break;
289 case RFC1143_WANTNO:
Sean Middleditch8b788962009-03-16 01:06:27 -0400290 q.him = RFC1143_NO;
291 _set_rfc1143(telnet, q);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400292 _event(telnet, LIBTELNET_EV_WONT, 0, telopt,
293 0, 0);
294 break;
295 case RFC1143_WANTNO_OP:
Sean Middleditch8b788962009-03-16 01:06:27 -0400296 q.him = RFC1143_WANTYES;
297 _set_rfc1143(telnet, q);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400298 _event(telnet, LIBTELNET_EV_DO, 0, telopt,
299 0, 0);
300 break;
301 case RFC1143_WANTYES:
302 case RFC1143_WANTYES_OP:
Sean Middleditch8b788962009-03-16 01:06:27 -0400303 q.him = RFC1143_NO;
304 _set_rfc1143(telnet, q);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400305 break;
306 }
307 break;
308
309 /* request to enable option on local end or confirm WILL */
310 case LIBTELNET_DO:
Sean Middleditch8b788962009-03-16 01:06:27 -0400311 switch (q.us) {
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400312 case RFC1143_NO:
313 if (_event(telnet, LIBTELNET_EV_DO, cmd, telopt, 0, 0) == 1) {
Sean Middleditch8b788962009-03-16 01:06:27 -0400314 q.us = RFC1143_YES;
315 _set_rfc1143(telnet, q);
Sean Middleditch2b4bfc42009-03-16 01:25:52 -0400316 libtelnet_send_telopt(telnet, LIBTELNET_WILL, telopt);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400317 } else
Sean Middleditch2b4bfc42009-03-16 01:25:52 -0400318 libtelnet_send_telopt(telnet, LIBTELNET_WONT, telopt);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400319 break;
320 case RFC1143_YES:
321 break;
322 case RFC1143_WANTNO:
Sean Middleditch8b788962009-03-16 01:06:27 -0400323 q.us = RFC1143_NO;
324 _set_rfc1143(telnet, q);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400325 _error(telnet, __LINE__, __func__, LIBTELNET_EPROTOCOL, 0,
326 "WONT answered by DO");
327 break;
328 case RFC1143_WANTNO_OP:
Sean Middleditch8b788962009-03-16 01:06:27 -0400329 q.us = RFC1143_YES;
330 _set_rfc1143(telnet, q);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400331 _error(telnet, __LINE__, __func__, LIBTELNET_EPROTOCOL, 0,
332 "WONT answered by DO");
333 break;
334 case RFC1143_WANTYES:
Sean Middleditch8b788962009-03-16 01:06:27 -0400335 q.us = RFC1143_YES;
336 _set_rfc1143(telnet, q);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400337 break;
338 case RFC1143_WANTYES_OP:
Sean Middleditch8b788962009-03-16 01:06:27 -0400339 q.us = RFC1143_WANTNO;
340 _set_rfc1143(telnet, q);
Sean Middleditch2b4bfc42009-03-16 01:25:52 -0400341 libtelnet_send_telopt(telnet, LIBTELNET_WONT, telopt);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400342 break;
343 }
344 break;
345
346 /* request to disable option on local end, confirm WONT, reject WILL */
347 case LIBTELNET_DONT:
Sean Middleditch8b788962009-03-16 01:06:27 -0400348 switch (q.us) {
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400349 case RFC1143_NO:
350 break;
351 case RFC1143_YES:
Sean Middleditch8b788962009-03-16 01:06:27 -0400352 q.us = RFC1143_NO;
353 _set_rfc1143(telnet, q);
Sean Middleditch2b4bfc42009-03-16 01:25:52 -0400354 libtelnet_send_telopt(telnet, LIBTELNET_WONT, telopt);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400355 _event(telnet, LIBTELNET_EV_DONT, 0, telopt, 0, 0);
356 break;
357 case RFC1143_WANTNO:
Sean Middleditch8b788962009-03-16 01:06:27 -0400358 q.us = RFC1143_NO;
359 _set_rfc1143(telnet, q);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400360 _event(telnet, LIBTELNET_EV_WONT, 0, telopt, 0, 0);
361 break;
362 case RFC1143_WANTNO_OP:
Sean Middleditch8b788962009-03-16 01:06:27 -0400363 q.us = RFC1143_WANTYES;
364 _set_rfc1143(telnet, q);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400365 _event(telnet, LIBTELNET_EV_WILL, 0, telopt, 0, 0);
366 break;
367 case RFC1143_WANTYES:
368 case RFC1143_WANTYES_OP:
Sean Middleditch8b788962009-03-16 01:06:27 -0400369 q.us = RFC1143_NO;
370 _set_rfc1143(telnet, q);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400371 break;
372 }
373 break;
374 }
375}
376
Sean Middleditch29144852009-03-12 23:14:47 -0400377/* initialize a telnet state tracker */
Sean Middleditch812358d2009-03-15 23:24:03 -0400378void libtelnet_init(libtelnet_t *telnet, libtelnet_event_handler_t eh,
Sean Middleditch08bb05f2009-03-15 23:29:46 -0400379 unsigned char flags, void *user_data) {
Sean Middleditch812358d2009-03-15 23:24:03 -0400380 memset(telnet, 0, sizeof(libtelnet_t));
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400381 telnet->ud = user_data;
Sean Middleditch637df7f2009-03-15 12:57:32 -0400382 telnet->eh = eh;
Sean Middleditch08bb05f2009-03-15 23:29:46 -0400383 telnet->flags = flags;
Sean Middleditch29144852009-03-12 23:14:47 -0400384}
385
386/* free up any memory allocated by a state tracker */
Sean Middleditch812358d2009-03-15 23:24:03 -0400387void libtelnet_free(libtelnet_t *telnet) {
Sean Middleditch9de15982009-03-14 03:35:49 -0400388 /* free sub-request buffer */
Sean Middleditch51ad6792009-03-13 20:15:59 -0400389 if (telnet->buffer != 0) {
Sean Middleditch29144852009-03-12 23:14:47 -0400390 free(telnet->buffer);
391 telnet->buffer = 0;
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400392 telnet->buffer_size = 0;
393 telnet->buffer_pos = 0;
Sean Middleditch29144852009-03-12 23:14:47 -0400394 }
Sean Middleditch9de15982009-03-14 03:35:49 -0400395
Sean Middleditche5b47592009-03-16 17:37:43 -0400396#ifdef HAVE_ZLIB
Sean Middleditchfbe93e32009-03-15 23:39:31 -0400397 /* free zlib box */
398 if (telnet->z != 0) {
399 if (telnet->flags & LIBTELNET_PFLAG_DEFLATE)
400 deflateEnd(telnet->z);
401 else
402 inflateEnd(telnet->z);
403 free(telnet->z);
404 telnet->z = 0;
Sean Middleditch9de15982009-03-14 03:35:49 -0400405 }
Sean Middleditche5b47592009-03-16 17:37:43 -0400406#endif
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400407
408 /* free RFC1143 queue */
409 if (telnet->q) {
410 free(telnet->q);
411 telnet->q = 0;
412 telnet->q_size = 0;
413 }
Sean Middleditch29144852009-03-12 23:14:47 -0400414}
415
Sean Middleditch51ad6792009-03-13 20:15:59 -0400416/* push a byte into the telnet buffer */
Sean Middleditch812358d2009-03-15 23:24:03 -0400417static libtelnet_error_t _buffer_byte(libtelnet_t *telnet,
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400418 unsigned char byte) {
Sean Middleditch8daf7742009-03-19 02:05:24 -0400419 char *new_buffer;
Sean Middleditch80f119b2009-03-16 18:02:35 -0400420 unsigned int i;
Sean Middleditch4d9444d2009-03-13 22:48:05 -0400421
Sean Middleditch51ad6792009-03-13 20:15:59 -0400422 /* check if we're out of room */
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400423 if (telnet->buffer_pos == telnet->buffer_size) {
Sean Middleditch4d9444d2009-03-13 22:48:05 -0400424 /* find the next buffer size */
425 for (i = 0; i != _buffer_sizes_count; ++i) {
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400426 if (_buffer_sizes[i] == telnet->buffer_size)
Sean Middleditch4d9444d2009-03-13 22:48:05 -0400427 break;
428 }
429
430 /* overflow -- can't grow any more */
431 if (i >= _buffer_sizes_count - 1) {
Sean Middleditch16992272009-03-15 19:42:03 -0400432 _error(telnet, __LINE__, __func__, LIBTELNET_EOVERFLOW, 0,
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400433 "subnegotiation buffer size limit reached");
Sean Middleditch51ad6792009-03-13 20:15:59 -0400434 libtelnet_free(telnet);
Sean Middleditchf66a7ee2009-03-15 11:54:07 -0400435 return LIBTELNET_EOVERFLOW;
Sean Middleditch51ad6792009-03-13 20:15:59 -0400436 }
Sean Middleditch4d9444d2009-03-13 22:48:05 -0400437
438 /* (re)allocate buffer */
Sean Middleditch8daf7742009-03-19 02:05:24 -0400439 new_buffer = (char *)realloc(telnet->buffer,
Sean Middleditch4d9444d2009-03-13 22:48:05 -0400440 _buffer_sizes[i + 1]);
441 if (new_buffer == 0) {
Sean Middleditch16992272009-03-15 19:42:03 -0400442 _error(telnet, __LINE__, __func__, LIBTELNET_ENOMEM, 0,
443 "realloc() failed");
Sean Middleditch4d9444d2009-03-13 22:48:05 -0400444 libtelnet_free(telnet);
Sean Middleditchf66a7ee2009-03-15 11:54:07 -0400445 return LIBTELNET_ENOMEM;
Sean Middleditch4d9444d2009-03-13 22:48:05 -0400446 }
447
448 telnet->buffer = new_buffer;
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400449 telnet->buffer_size = _buffer_sizes[i + 1];
Sean Middleditch51ad6792009-03-13 20:15:59 -0400450 }
451
452 /* push the byte, all set */
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400453 telnet->buffer[telnet->buffer_pos++] = byte;
Sean Middleditchf66a7ee2009-03-15 11:54:07 -0400454 return LIBTELNET_EOK;
Sean Middleditch51ad6792009-03-13 20:15:59 -0400455}
456
Sean Middleditch8daf7742009-03-19 02:05:24 -0400457static void _process(libtelnet_t *telnet, const char *buffer,
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400458 unsigned int size) {
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400459 unsigned char byte;
460 unsigned int i, start;
461 for (i = start = 0; i != size; ++i) {
462 byte = buffer[i];
463 switch (telnet->state) {
464 /* regular data */
Sean Middleditch9de15982009-03-14 03:35:49 -0400465 case LIBTELNET_STATE_DATA:
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400466 /* on an IAC byte, pass through all pending bytes and
467 * switch states */
468 if (byte == LIBTELNET_IAC) {
469 if (i != start)
Sean Middleditch637df7f2009-03-15 12:57:32 -0400470 _event(telnet, LIBTELNET_EV_DATA, 0, 0, &buffer[start],
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400471 i - start);
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400472 telnet->state = LIBTELNET_STATE_IAC;
473 }
474 break;
475
476 /* IAC command */
477 case LIBTELNET_STATE_IAC:
478 switch (byte) {
Sean Middleditch6b372882009-03-14 13:06:47 -0400479 /* subnegotiation */
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400480 case LIBTELNET_SB:
481 telnet->state = LIBTELNET_STATE_SB;
482 break;
483 /* negotiation commands */
484 case LIBTELNET_WILL:
485 telnet->state = LIBTELNET_STATE_WILL;
486 break;
487 case LIBTELNET_WONT:
488 telnet->state = LIBTELNET_STATE_WONT;
489 break;
490 case LIBTELNET_DO:
491 telnet->state = LIBTELNET_STATE_DO;
492 break;
493 case LIBTELNET_DONT:
494 telnet->state = LIBTELNET_STATE_DONT;
495 break;
496 /* IAC escaping */
497 case LIBTELNET_IAC:
Sean Middleditch8daf7742009-03-19 02:05:24 -0400498 _event(telnet, LIBTELNET_EV_DATA, 0, 0, (char*)&byte, 1);
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400499 start = i + 1;
Sean Middleditch9de15982009-03-14 03:35:49 -0400500 telnet->state = LIBTELNET_STATE_DATA;
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400501 break;
502 /* some other command */
503 default:
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400504 _event(telnet, LIBTELNET_EV_IAC, byte, 0, 0, 0);
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400505 start = i + 1;
Sean Middleditch9de15982009-03-14 03:35:49 -0400506 telnet->state = LIBTELNET_STATE_DATA;
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400507 }
508 break;
509
510 /* negotiation commands */
511 case LIBTELNET_STATE_DO:
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400512 _negotiate(telnet, LIBTELNET_DO, byte);
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400513 start = i + 1;
Sean Middleditch9de15982009-03-14 03:35:49 -0400514 telnet->state = LIBTELNET_STATE_DATA;
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400515 break;
516 case LIBTELNET_STATE_DONT:
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400517 _negotiate(telnet, LIBTELNET_DONT, byte);
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400518 start = i + 1;
Sean Middleditch9de15982009-03-14 03:35:49 -0400519 telnet->state = LIBTELNET_STATE_DATA;
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400520 break;
521 case LIBTELNET_STATE_WILL:
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400522 _negotiate(telnet, LIBTELNET_WILL, byte);
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400523 start = i + 1;
Sean Middleditch9de15982009-03-14 03:35:49 -0400524 telnet->state = LIBTELNET_STATE_DATA;
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400525 break;
526 case LIBTELNET_STATE_WONT:
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400527 _negotiate(telnet, LIBTELNET_WONT, byte);
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400528 start = i + 1;
Sean Middleditch9de15982009-03-14 03:35:49 -0400529 telnet->state = LIBTELNET_STATE_DATA;
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400530 break;
531
Sean Middleditchda0e6952009-03-15 13:28:09 -0400532 /* subnegotiation -- determine subnegotiation telopt */
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400533 case LIBTELNET_STATE_SB:
Sean Middleditchda0e6952009-03-15 13:28:09 -0400534 telnet->sb_telopt = byte;
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400535 telnet->buffer_pos = 0;
Sean Middleditchda0e6952009-03-15 13:28:09 -0400536 telnet->state = LIBTELNET_STATE_SB_DATA;
537 break;
538
539 /* subnegotiation -- buffer bytes until end request */
540 case LIBTELNET_STATE_SB_DATA:
Sean Middleditch6b372882009-03-14 13:06:47 -0400541 /* IAC command in subnegotiation -- either IAC SE or IAC IAC */
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400542 if (byte == LIBTELNET_IAC) {
Sean Middleditchda0e6952009-03-15 13:28:09 -0400543 telnet->state = LIBTELNET_STATE_SB_DATA_IAC;
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400544 /* buffer the byte, or bail if we can't */
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400545 } else if (_buffer_byte(telnet, byte) != LIBTELNET_EOK) {
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400546 start = i + 1;
Sean Middleditch9de15982009-03-14 03:35:49 -0400547 telnet->state = LIBTELNET_STATE_DATA;
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400548 }
549 break;
550
Sean Middleditch6b372882009-03-14 13:06:47 -0400551 /* IAC escaping inside a subnegotiation */
Sean Middleditchda0e6952009-03-15 13:28:09 -0400552 case LIBTELNET_STATE_SB_DATA_IAC:
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400553 switch (byte) {
Sean Middleditch6b372882009-03-14 13:06:47 -0400554 /* end subnegotiation */
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400555 case LIBTELNET_SE:
Sean Middleditch9de15982009-03-14 03:35:49 -0400556 /* return to default state */
557 start = i + 1;
558 telnet->state = LIBTELNET_STATE_DATA;
559
Sean Middleditch9de15982009-03-14 03:35:49 -0400560 /* invoke callback */
Sean Middleditch637df7f2009-03-15 12:57:32 -0400561 _event(telnet, LIBTELNET_EV_SUBNEGOTIATION, 0,
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400562 telnet->sb_telopt, telnet->buffer, telnet->buffer_pos);
Sean Middleditch9de15982009-03-14 03:35:49 -0400563
Sean Middleditch61f8eb62009-03-14 04:57:27 -0400564#ifdef HAVE_ZLIB
Sean Middleditch3df17f92009-03-16 01:12:16 -0400565 /* received COMPRESS2 begin marker, setup our zlib box and
566 * start handling the compressed stream if it's not already.
Sean Middleditch61f8eb62009-03-14 04:57:27 -0400567 */
Sean Middleditch3df17f92009-03-16 01:12:16 -0400568 if (telnet->sb_telopt == LIBTELNET_TELOPT_COMPRESS2) {
Sean Middleditchfbe93e32009-03-15 23:39:31 -0400569 if (_init_zlib(telnet, 0, 1) != LIBTELNET_EOK)
Sean Middleditch9de15982009-03-14 03:35:49 -0400570 break;
Sean Middleditch9de15982009-03-14 03:35:49 -0400571
Sean Middleditch61f8eb62009-03-14 04:57:27 -0400572 /* notify app that compression was enabled */
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400573 _event(telnet, LIBTELNET_EV_COMPRESS, 1, 0, 0, 0);
Sean Middleditch61f8eb62009-03-14 04:57:27 -0400574
Sean Middleditch9de15982009-03-14 03:35:49 -0400575 /* any remaining bytes in the buffer are compressed.
576 * we have to re-invoke libtelnet_push to get those
577 * bytes inflated and abort trying to process the
578 * remaining compressed bytes in the current _process
579 * buffer argument
580 */
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400581 libtelnet_push(telnet, &buffer[start], size - start);
Sean Middleditch9de15982009-03-14 03:35:49 -0400582 return;
583 }
Sean Middleditch61f8eb62009-03-14 04:57:27 -0400584#endif /* HAVE_ZLIB */
585
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400586 break;
587 /* escaped IAC byte */
588 case LIBTELNET_IAC:
589 /* push IAC into buffer */
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400590 if (_buffer_byte(telnet, LIBTELNET_IAC) !=
Sean Middleditchf66a7ee2009-03-15 11:54:07 -0400591 LIBTELNET_EOK) {
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400592 start = i + 1;
Sean Middleditch9de15982009-03-14 03:35:49 -0400593 telnet->state = LIBTELNET_STATE_DATA;
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400594 } else {
Sean Middleditchda0e6952009-03-15 13:28:09 -0400595 telnet->state = LIBTELNET_STATE_SB_DATA;
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400596 }
597 break;
598 /* something else -- protocol error */
599 default:
Sean Middleditch16992272009-03-15 19:42:03 -0400600 _error(telnet, __LINE__, __func__, LIBTELNET_EPROTOCOL, 0,
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400601 "unexpected byte after IAC inside SB: %d",
Sean Middleditchd922c6f2009-03-14 22:35:01 -0400602 byte);
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400603 start = i + 1;
Sean Middleditch9de15982009-03-14 03:35:49 -0400604 telnet->state = LIBTELNET_STATE_DATA;
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400605 break;
606 }
607 break;
608 }
609 }
610
611 /* pass through any remaining bytes */
Sean Middleditchd30fd572009-03-14 12:55:17 -0400612 if (telnet->state == LIBTELNET_STATE_DATA && i != start)
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400613 _event(telnet, LIBTELNET_EV_DATA, 0, 0, buffer + start, i - start);
Sean Middleditch29144852009-03-12 23:14:47 -0400614}
615
Sean Middleditch9de15982009-03-14 03:35:49 -0400616/* push a bytes into the state tracker */
Sean Middleditch8daf7742009-03-19 02:05:24 -0400617void libtelnet_push(libtelnet_t *telnet, const char *buffer,
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400618 unsigned int size) {
Sean Middleditch61f8eb62009-03-14 04:57:27 -0400619#ifdef HAVE_ZLIB
Sean Middleditch72cc9642009-03-15 11:50:36 -0400620 /* if we have an inflate (decompression) zlib stream, use it */
Sean Middleditch4611d912009-03-16 00:53:57 -0400621 if (telnet->z != 0 && !(telnet->flags & LIBTELNET_PFLAG_DEFLATE)) {
Sean Middleditch8daf7742009-03-19 02:05:24 -0400622 char inflate_buffer[4096];
Sean Middleditch9de15982009-03-14 03:35:49 -0400623 int rs;
624
625 /* initialize zlib state */
Sean Middleditch8daf7742009-03-19 02:05:24 -0400626 telnet->z->next_in = (unsigned char*)buffer;
Sean Middleditchfbe93e32009-03-15 23:39:31 -0400627 telnet->z->avail_in = size;
Sean Middleditch8daf7742009-03-19 02:05:24 -0400628 telnet->z->next_out = (unsigned char *)inflate_buffer;
Sean Middleditchfbe93e32009-03-15 23:39:31 -0400629 telnet->z->avail_out = sizeof(inflate_buffer);
Sean Middleditch9de15982009-03-14 03:35:49 -0400630
631 /* inflate until buffer exhausted and all output is produced */
Sean Middleditchfbe93e32009-03-15 23:39:31 -0400632 while (telnet->z->avail_in > 0 || telnet->z->avail_out == 0) {
Sean Middleditch9de15982009-03-14 03:35:49 -0400633 /* reset output buffer */
634
635 /* decompress */
Sean Middleditchfbe93e32009-03-15 23:39:31 -0400636 rs = inflate(telnet->z, Z_SYNC_FLUSH);
Sean Middleditch9de15982009-03-14 03:35:49 -0400637
638 /* process the decompressed bytes on success */
639 if (rs == Z_OK || rs == Z_STREAM_END)
640 _process(telnet, inflate_buffer, sizeof(inflate_buffer) -
Sean Middleditchfbe93e32009-03-15 23:39:31 -0400641 telnet->z->avail_out);
Sean Middleditch9de15982009-03-14 03:35:49 -0400642 else
Sean Middleditch16992272009-03-15 19:42:03 -0400643 _error(telnet, __LINE__, __func__, LIBTELNET_ECOMPRESS, 1,
644 "inflate() failed: %s", zError(rs));
Sean Middleditch9de15982009-03-14 03:35:49 -0400645
646 /* prepare output buffer for next run */
Sean Middleditch8daf7742009-03-19 02:05:24 -0400647 telnet->z->next_out = (unsigned char *)inflate_buffer;
Sean Middleditchfbe93e32009-03-15 23:39:31 -0400648 telnet->z->avail_out = sizeof(inflate_buffer);
Sean Middleditch9de15982009-03-14 03:35:49 -0400649
650 /* on error (or on end of stream) disable further inflation */
651 if (rs != Z_OK) {
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400652 _event(telnet, LIBTELNET_EV_COMPRESS, 0, 0, 0, 0);
Sean Middleditch61f8eb62009-03-14 04:57:27 -0400653
Sean Middleditchfbe93e32009-03-15 23:39:31 -0400654 inflateEnd(telnet->z);
655 free(telnet->z);
656 telnet->z = 0;
Sean Middleditch9de15982009-03-14 03:35:49 -0400657 break;
658 }
659 }
660
Sean Middleditch61f8eb62009-03-14 04:57:27 -0400661 /* COMPRESS2 is not negotiated, just process */
662 } else
663#endif /* HAVE_ZLIB */
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400664 _process(telnet, buffer, size);
Sean Middleditch61f8eb62009-03-14 04:57:27 -0400665}
666
Sean Middleditch29144852009-03-12 23:14:47 -0400667/* send an iac command */
Sean Middleditch812358d2009-03-15 23:24:03 -0400668void libtelnet_send_command(libtelnet_t *telnet, unsigned char cmd) {
Sean Middleditch8daf7742009-03-19 02:05:24 -0400669 char bytes[2] = { LIBTELNET_IAC, cmd };
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400670 _send(telnet, bytes, 2);
Sean Middleditch29144852009-03-12 23:14:47 -0400671}
672
Sean Middleditch2b4bfc42009-03-16 01:25:52 -0400673/* send an iac command with telopt */
674void libtelnet_send_telopt(libtelnet_t *telnet, unsigned char cmd,
675 unsigned char telopt) {
Sean Middleditch8daf7742009-03-19 02:05:24 -0400676 char bytes[3] = { LIBTELNET_IAC, cmd, telopt };
Sean Middleditch2b4bfc42009-03-16 01:25:52 -0400677 _send(telnet, bytes, 3);
678}
679
Sean Middleditch29144852009-03-12 23:14:47 -0400680/* send negotiation */
Sean Middleditch812358d2009-03-15 23:24:03 -0400681void libtelnet_send_negotiate(libtelnet_t *telnet, unsigned char cmd,
Sean Middleditch8b788962009-03-16 01:06:27 -0400682 unsigned char telopt) {
683 libtelnet_rfc1143_t q;
684
685 /* if we're in proxy mode, just send it now */
686 if (telnet->flags & LIBTELNET_FLAG_PROXY) {
Sean Middleditch8daf7742009-03-19 02:05:24 -0400687 char bytes[3] = { LIBTELNET_IAC, cmd, telopt };
Sean Middleditch8b788962009-03-16 01:06:27 -0400688 _send(telnet, bytes, 3);
689 return;
690 }
691
692 /* get current option states */
693 q = _get_rfc1143(telnet, telopt);
694
695 switch (cmd) {
696 /* advertise willingess to support an option */
697 case LIBTELNET_WILL:
698 switch (q.us) {
699 case RFC1143_NO:
700 q.us = RFC1143_WANTYES;
701 _set_rfc1143(telnet, q);
702 _negotiate(telnet, LIBTELNET_WILL, telopt);
703 break;
704 case RFC1143_YES:
705 break;
706 case RFC1143_WANTNO:
707 q.us = RFC1143_WANTNO_OP;
708 _set_rfc1143(telnet, q);
709 break;
710 case RFC1143_WANTYES:
711 break;
712 case RFC1143_WANTNO_OP:
713 break;
714 case RFC1143_WANTYES_OP:
715 q.us = RFC1143_WANTYES;
716 _set_rfc1143(telnet, q);
717 break;
718 }
719 break;
720
721 /* force turn-off of locally enabled option */
722 case LIBTELNET_WONT:
723 switch (q.us) {
724 case RFC1143_NO:
725 break;
726 case RFC1143_YES:
727 q.us = RFC1143_WANTNO;
728 _set_rfc1143(telnet, q);
729 _negotiate(telnet, LIBTELNET_WONT, telopt);
730 break;
731 case RFC1143_WANTNO:
732 break;
733 case RFC1143_WANTYES:
734 q.us = RFC1143_WANTYES_OP;
735 _set_rfc1143(telnet, q);
736 break;
737 case RFC1143_WANTNO_OP:
738 q.us = RFC1143_WANTNO;
739 _set_rfc1143(telnet, q);
740 break;
741 case RFC1143_WANTYES_OP:
742 break;
743 }
744 break;
745
746 /* ask remote end to enable an option */
747 case LIBTELNET_DO:
748 switch (q.him) {
749 case RFC1143_NO:
750 q.him = RFC1143_WANTYES;
751 _set_rfc1143(telnet, q);
752 _negotiate(telnet, LIBTELNET_DO, telopt);
753 break;
754 case RFC1143_YES:
755 break;
756 case RFC1143_WANTNO:
757 q.him = RFC1143_WANTNO_OP;
758 _set_rfc1143(telnet, q);
759 break;
760 case RFC1143_WANTYES:
761 break;
762 case RFC1143_WANTNO_OP:
763 break;
764 case RFC1143_WANTYES_OP:
765 q.him = RFC1143_WANTYES;
766 _set_rfc1143(telnet, q);
767 break;
768 }
769 break;
770
771 /* demand remote end disable an option */
772 case LIBTELNET_DONT:
773 switch (q.him) {
774 case RFC1143_NO:
775 break;
776 case RFC1143_YES:
777 q.him = RFC1143_WANTNO;
778 _set_rfc1143(telnet, q);
779 _negotiate(telnet, LIBTELNET_DONT, telopt);
780 break;
781 case RFC1143_WANTNO:
782 break;
783 case RFC1143_WANTYES:
784 q.him = RFC1143_WANTYES_OP;
785 _set_rfc1143(telnet, q);
786 break;
787 case RFC1143_WANTNO_OP:
788 q.him = RFC1143_WANTNO;
789 _set_rfc1143(telnet, q);
790 break;
791 case RFC1143_WANTYES_OP:
792 break;
793 }
794 break;
795 }
Sean Middleditch29144852009-03-12 23:14:47 -0400796}
797
798/* send non-command data (escapes IAC bytes) */
Sean Middleditch8daf7742009-03-19 02:05:24 -0400799void libtelnet_send_data(libtelnet_t *telnet, const char *buffer,
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400800 unsigned int size) {
Sean Middleditch4d9444d2009-03-13 22:48:05 -0400801 unsigned int i, l;
Sean Middleditchc337ba62009-03-16 16:47:27 -0400802
Sean Middleditch29144852009-03-12 23:14:47 -0400803 for (l = i = 0; i != size; ++i) {
804 /* dump prior portion of text, send escaped bytes */
805 if (buffer[i] == LIBTELNET_IAC) {
806 /* dump prior text if any */
807 if (i != l)
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400808 _send(telnet, buffer + l, i - l);
Sean Middleditch29144852009-03-12 23:14:47 -0400809 l = i + 1;
810
811 /* send escape */
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400812 libtelnet_send_command(telnet, LIBTELNET_IAC);
Sean Middleditch29144852009-03-12 23:14:47 -0400813 }
814 }
815
816 /* send whatever portion of buffer is left */
817 if (i != l)
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400818 _send(telnet, buffer + l, i - l);
Sean Middleditch29144852009-03-12 23:14:47 -0400819}
820
821/* send sub-request */
Sean Middleditch2b4bfc42009-03-16 01:25:52 -0400822void libtelnet_send_subnegotiation(libtelnet_t *telnet, unsigned char telopt,
Sean Middleditch8daf7742009-03-19 02:05:24 -0400823 const char *buffer, unsigned int size) {
Sean Middleditch2b4bfc42009-03-16 01:25:52 -0400824 libtelnet_send_telopt(telnet, LIBTELNET_SB, telopt);
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400825 libtelnet_send_data(telnet, buffer, size);
826 libtelnet_send_command(telnet, LIBTELNET_SE);
Sean Middleditch61f8eb62009-03-14 04:57:27 -0400827
828#ifdef HAVE_ZLIB
Sean Middleditch72cc9642009-03-15 11:50:36 -0400829 /* if we're a proxy and we just sent the COMPRESS2 marker, we must
830 * make sure all further data is compressed if not already.
Sean Middleditch61f8eb62009-03-14 04:57:27 -0400831 */
Sean Middleditch08bb05f2009-03-15 23:29:46 -0400832 if (telnet->flags & LIBTELNET_FLAG_PROXY &&
Sean Middleditch2b4bfc42009-03-16 01:25:52 -0400833 telopt == LIBTELNET_TELOPT_COMPRESS2) {
Sean Middleditchd922c6f2009-03-14 22:35:01 -0400834
Sean Middleditchfbe93e32009-03-15 23:39:31 -0400835 if (_init_zlib(telnet, 1, 1) != LIBTELNET_EOK)
Sean Middleditchd922c6f2009-03-14 22:35:01 -0400836 return;
Sean Middleditch61f8eb62009-03-14 04:57:27 -0400837
838 /* notify app that compression was enabled */
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400839 _event(telnet, LIBTELNET_EV_COMPRESS, 1, 0, 0, 0);
Sean Middleditch61f8eb62009-03-14 04:57:27 -0400840 }
841#endif /* HAVE_ZLIB */
Sean Middleditch29144852009-03-12 23:14:47 -0400842}
Sean Middleditch124a1c22009-03-15 13:20:03 -0400843
Sean Middleditch812358d2009-03-15 23:24:03 -0400844void libtelnet_begin_compress2(libtelnet_t *telnet) {
Sean Middleditch124a1c22009-03-15 13:20:03 -0400845#ifdef HAVE_ZLIB
Sean Middleditch8daf7742009-03-19 02:05:24 -0400846 static const char compress2[] = { LIBTELNET_IAC, LIBTELNET_SB,
Sean Middleditchfbe93e32009-03-15 23:39:31 -0400847 LIBTELNET_TELOPT_COMPRESS2, LIBTELNET_IAC, LIBTELNET_SE };
Sean Middleditch124a1c22009-03-15 13:20:03 -0400848
Sean Middleditch124a1c22009-03-15 13:20:03 -0400849 /* attempt to create output stream first, bail if we can't */
Sean Middleditchfbe93e32009-03-15 23:39:31 -0400850 if (_init_zlib(telnet, 1, 0) != LIBTELNET_EOK)
Sean Middleditch124a1c22009-03-15 13:20:03 -0400851 return;
852
Sean Middleditchfbe93e32009-03-15 23:39:31 -0400853 /* send compression marker. we send directly to the event handler
854 * instead of passing through _send because _send would result in
855 * the compress marker itself being compressed.
856 */
857 _event(telnet, LIBTELNET_EV_SEND, 0, 0, compress2, sizeof(compress2));
Sean Middleditch2b4bfc42009-03-16 01:25:52 -0400858
859 /* notify app that compression was successfully enabled */
860 _event(telnet, LIBTELNET_EV_COMPRESS, 1, 0, 0, 0);
Sean Middleditch124a1c22009-03-15 13:20:03 -0400861#endif /* HAVE_ZLIB */
862}
Sean Middleditchd58f49f2009-03-16 12:49:35 -0400863
864/* send formatted data through libtelnet_send_data */
Sean Middleditch4a156042009-03-16 17:10:58 -0400865int libtelnet_printf(libtelnet_t *telnet, const char *fmt, ...) {
Sean Middleditchd58f49f2009-03-16 12:49:35 -0400866 char buffer[4096];
867 va_list va;
868 int rs;
869
870 /* format */
871 va_start(va, fmt);
872 rs = vsnprintf(buffer, sizeof(buffer), fmt, va);
873 va_end(va);
874
875 /* send */
Sean Middleditch8daf7742009-03-19 02:05:24 -0400876 libtelnet_send_data(telnet, (char *)buffer, rs);
Sean Middleditchd58f49f2009-03-16 12:49:35 -0400877
878 return rs;
879}
Sean Middleditch4a156042009-03-16 17:10:58 -0400880
881/* send formatted data with \r and \n translation in addition to IAC IAC */
882int libtelnet_printf2(libtelnet_t *telnet, const char *fmt, ...) {
Sean Middleditch8daf7742009-03-19 02:05:24 -0400883 static const char CRLF[] = { '\r', '\n' };
884 static const char CRNUL[] = { '\r', '\0' };
Sean Middleditch4a156042009-03-16 17:10:58 -0400885 char buffer[4096];
886 va_list va;
887 int rs, i, l;
888
889 /* format */
890 va_start(va, fmt);
891 rs = vsnprintf(buffer, sizeof(buffer), fmt, va);
892 va_end(va);
893
894 /* send */
895 for (l = i = 0; i != rs; ++i) {
896 /* special characters */
897 if (buffer[i] == LIBTELNET_IAC || buffer[i] == '\r' ||
898 buffer[i] == '\n') {
899 /* dump prior portion of text */
900 if (i != l)
Sean Middleditch8daf7742009-03-19 02:05:24 -0400901 _send(telnet, (char *)buffer + l, i - l);
Sean Middleditch4a156042009-03-16 17:10:58 -0400902 l = i + 1;
903
904 /* IAC -> IAC IAC */
905 if (buffer[i] == LIBTELNET_IAC)
906 libtelnet_send_command(telnet, LIBTELNET_IAC);
907 /* automatic translation of \r -> CRNUL */
908 else if (buffer[i] == '\r')
909 _send(telnet, CRNUL, 2);
910 /* automatic translation of \n -> CRLF */
911 else if (buffer[i] == '\n')
912 _send(telnet, CRLF, 2);
913 }
914 }
915
916 /* send whatever portion of buffer is left */
917 if (i != l)
Sean Middleditch8daf7742009-03-19 02:05:24 -0400918 _send(telnet, (char *)buffer + l, i - l);
Sean Middleditch4a156042009-03-16 17:10:58 -0400919
920 return rs;
921}