blob: e9052875218343348a155aa958728524ea71340f [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,
52 const unsigned 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 Middleditch5cf66662009-03-15 20:02:14 -040082 0, (unsigned 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 Middleditch72cc9642009-03-15 11:50:36 -040087/* initialize the zlib box for a telnet box; if deflate is non-zero, it
88 * initializes zlib for delating (compression), otherwise for inflating
Sean Middleditchfbe93e32009-03-15 23:39:31 -040089 * (decompression). returns LIBTELNET_EOK on success, something else on
90 * failure.
Sean Middleditch72cc9642009-03-15 11:50:36 -040091 */
Sean Middleditchfbe93e32009-03-15 23:39:31 -040092libtelnet_error_t _init_zlib(libtelnet_t *telnet, int deflate, int err_fatal) {
93 z_stream *z;
Sean Middleditch72cc9642009-03-15 11:50:36 -040094 int rs;
95
Sean Middleditchfbe93e32009-03-15 23:39:31 -040096 /* if compression is already enabled, fail loudly */
97 if (telnet->z != 0)
98 return _error(telnet, __LINE__, __func__, LIBTELNET_EBADVAL,
99 err_fatal, "cannot initialize compression twice");
100
Sean Middleditch72cc9642009-03-15 11:50:36 -0400101 /* allocate zstream box */
Sean Middleditchfbe93e32009-03-15 23:39:31 -0400102 if ((z= (z_stream *)calloc(1, sizeof(z_stream))) == 0)
103 return _error(telnet, __LINE__, __func__, LIBTELNET_ENOMEM, err_fatal,
Sean Middleditch16992272009-03-15 19:42:03 -0400104 "malloc() failed: %s", strerror(errno));
Sean Middleditch72cc9642009-03-15 11:50:36 -0400105
106 /* initialize */
107 if (deflate) {
Sean Middleditchfbe93e32009-03-15 23:39:31 -0400108 if ((rs = deflateInit(z, Z_DEFAULT_COMPRESSION)) != Z_OK) {
109 free(z);
110 return _error(telnet, __LINE__, __func__, LIBTELNET_ECOMPRESS,
111 err_fatal, "deflateInit() failed: %s", zError(rs));
Sean Middleditch72cc9642009-03-15 11:50:36 -0400112 }
Sean Middleditchfbe93e32009-03-15 23:39:31 -0400113 telnet->flags |= LIBTELNET_PFLAG_DEFLATE;
Sean Middleditch72cc9642009-03-15 11:50:36 -0400114 } else {
Sean Middleditchfbe93e32009-03-15 23:39:31 -0400115 if ((rs = inflateInit(z)) != Z_OK) {
116 free(z);
117 return _error(telnet, __LINE__, __func__, LIBTELNET_ECOMPRESS,
118 err_fatal, "inflateInit() failed: %s", zError(rs));
Sean Middleditch72cc9642009-03-15 11:50:36 -0400119 }
Sean Middleditchfbe93e32009-03-15 23:39:31 -0400120 telnet->flags &= ~LIBTELNET_PFLAG_DEFLATE;
Sean Middleditch72cc9642009-03-15 11:50:36 -0400121 }
122
Sean Middleditchfbe93e32009-03-15 23:39:31 -0400123 telnet->z = z;
124
125 return LIBTELNET_EOK;
Sean Middleditch72cc9642009-03-15 11:50:36 -0400126}
127
Sean Middleditch8b788962009-03-16 01:06:27 -0400128/* push bytes out, compressing them first if need be */
Sean Middleditch97a8cb22009-03-16 16:51:41 -0400129static void _send(libtelnet_t *telnet, const unsigned char *buffer,
Sean Middleditch8b788962009-03-16 01:06:27 -0400130 unsigned int size) {
131#ifdef HAVE_ZLIB
132 /* if we have a deflate (compression) zlib box, use it */
Sean Middleditch823bc002009-03-16 01:09:26 -0400133 if (telnet->z != 0 && telnet->flags & LIBTELNET_PFLAG_DEFLATE) {
Sean Middleditch8b788962009-03-16 01:06:27 -0400134 unsigned char deflate_buffer[1024];
135 int rs;
136
137 /* initialize z state */
Sean Middleditch97a8cb22009-03-16 16:51:41 -0400138 telnet->z->next_in = (unsigned char *)buffer;
Sean Middleditch8b788962009-03-16 01:06:27 -0400139 telnet->z->avail_in = size;
140 telnet->z->next_out = deflate_buffer;
141 telnet->z->avail_out = sizeof(deflate_buffer);
142
143 /* deflate until buffer exhausted and all output is produced */
144 while (telnet->z->avail_in > 0 || telnet->z->avail_out == 0) {
145 /* compress */
146 if ((rs = deflate(telnet->z, Z_SYNC_FLUSH)) != Z_OK) {
147 _error(telnet, __LINE__, __func__, LIBTELNET_ECOMPRESS, 1,
148 "deflate() failed: %s", zError(rs));
149 deflateEnd(telnet->z);
150 free(telnet->z);
151 telnet->z = 0;
152 break;
153 }
154
155 _event(telnet, LIBTELNET_EV_SEND, 0, 0, deflate_buffer,
156 sizeof(deflate_buffer) - telnet->z->avail_out);
157
158 /* prepare output buffer for next run */
159 telnet->z->next_out = deflate_buffer;
160 telnet->z->avail_out = sizeof(deflate_buffer);
161 }
162
163 /* COMPRESS2 is not negotiated, just send */
164 } else
165#endif /* HAVE_ZLIB */
166 _event(telnet, LIBTELNET_EV_SEND, 0, 0, buffer, size);
167}
168
169/* retrieve RFC1143 option state */
170libtelnet_rfc1143_t _get_rfc1143(libtelnet_t *telnet, unsigned char telopt) {
171 static const libtelnet_rfc1143_t empty = { 0, 0, 0};
172 int i;
173
174 /* search for entry */
175 for (i = 0; i != telnet->q_size; ++i)
176 if (telnet->q[i].telopt == telopt)
177 return telnet->q[i];
178
179 /* not found, return empty value */
180 return empty;
181}
182
183/* save RFC1143 option state */
184void _set_rfc1143(libtelnet_t *telnet, libtelnet_rfc1143_t q) {
185 libtelnet_rfc1143_t *qtmp;
186 int i;
187
188 /* search for entry */
189 for (i = 0; i != telnet->q_size; ++i) {
190 if (telnet->q[i].telopt == q.telopt) {
191 telnet->q[i] = q;
192 return;
193 }
194 }
195
196 /* we're going to need to track state for it, so grow the queue
197 * and put the telopt into it; bail on allocation error
198 */
199 if ((qtmp = (libtelnet_rfc1143_t *)malloc(sizeof(
200 libtelnet_rfc1143_t) * (telnet->q_size + 1))) == 0) {
201 _error(telnet, __LINE__, __func__, LIBTELNET_ENOMEM, 0,
202 "malloc() failed: %s", strerror(errno));
203 return;
204 }
205 telnet->q = qtmp;
206 telnet->q[telnet->q_size++] = q;
207}
208
Sean Middleditch8b788962009-03-16 01:06:27 -0400209/* negotiation handling magic for RFC1143 */
210static void _negotiate(libtelnet_t *telnet, unsigned char cmd,
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400211 unsigned char telopt) {
Sean Middleditch8b788962009-03-16 01:06:27 -0400212 libtelnet_rfc1143_t q;
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400213
214 /* in PROXY mode, just pass it thru and do nothing */
Sean Middleditch562257e2009-03-15 23:56:25 -0400215 if (telnet->flags & LIBTELNET_FLAG_PROXY) {
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400216 switch (cmd) {
217 case LIBTELNET_WILL:
Sean Middleditch562257e2009-03-15 23:56:25 -0400218 _event(telnet, LIBTELNET_EV_WILL, 0, telopt, 0, 0);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400219 break;
220 case LIBTELNET_WONT:
Sean Middleditch562257e2009-03-15 23:56:25 -0400221 _event(telnet, LIBTELNET_EV_WONT, 0, telopt, 0, 0);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400222 break;
223 case LIBTELNET_DO:
Sean Middleditch562257e2009-03-15 23:56:25 -0400224 _event(telnet, LIBTELNET_EV_DO, 0, telopt, 0, 0);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400225 break;
226 case LIBTELNET_DONT:
Sean Middleditch562257e2009-03-15 23:56:25 -0400227 _event(telnet, LIBTELNET_EV_DONT, 0, telopt, 0, 0);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400228 break;
229 }
230 return;
231 }
232
233 /* lookup the current state of the option */
Sean Middleditch8b788962009-03-16 01:06:27 -0400234 q = _get_rfc1143(telnet, telopt);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400235
236 /* start processing... */
237 switch (cmd) {
238 /* request to enable option on remote end or confirm DO */
239 case LIBTELNET_WILL:
Sean Middleditch8b788962009-03-16 01:06:27 -0400240 switch (q.him) {
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400241 case RFC1143_NO:
242 if (_event(telnet, LIBTELNET_EV_WILL, cmd, telopt, 0, 0) == 1) {
Sean Middleditch8b788962009-03-16 01:06:27 -0400243 q.him = RFC1143_YES;
244 _set_rfc1143(telnet, q);
Sean Middleditch2b4bfc42009-03-16 01:25:52 -0400245 libtelnet_send_telopt(telnet, LIBTELNET_DO, telopt);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400246 } else
Sean Middleditch2b4bfc42009-03-16 01:25:52 -0400247 libtelnet_send_telopt(telnet, LIBTELNET_DONT, telopt);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400248 break;
249 case RFC1143_YES:
250 break;
251 case RFC1143_WANTNO:
Sean Middleditch8b788962009-03-16 01:06:27 -0400252 q.him = RFC1143_NO;
253 _set_rfc1143(telnet, q);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400254 _error(telnet, __LINE__, __func__, LIBTELNET_EPROTOCOL, 0,
255 "DONT answered by WILL");
256 break;
257 case RFC1143_WANTNO_OP:
Sean Middleditch8b788962009-03-16 01:06:27 -0400258 q.him = RFC1143_YES;
259 _set_rfc1143(telnet, q);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400260 _error(telnet, __LINE__, __func__, LIBTELNET_EPROTOCOL, 0,
261 "DONT answered by WILL");
262 break;
263 case RFC1143_WANTYES:
Sean Middleditch8b788962009-03-16 01:06:27 -0400264 q.him = RFC1143_YES;
265 _set_rfc1143(telnet, q);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400266 break;
267 case RFC1143_WANTYES_OP:
Sean Middleditch8b788962009-03-16 01:06:27 -0400268 q.him = RFC1143_WANTNO;
269 _set_rfc1143(telnet, q);
Sean Middleditch2b4bfc42009-03-16 01:25:52 -0400270 libtelnet_send_telopt(telnet, LIBTELNET_DONT, telopt);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400271 break;
272 }
273 break;
274
275 /* request to disable option on remote end, confirm DONT, reject DO */
276 case LIBTELNET_WONT:
Sean Middleditch8b788962009-03-16 01:06:27 -0400277 switch (q.him) {
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400278 case RFC1143_NO:
279 break;
280 case RFC1143_YES:
Sean Middleditch8b788962009-03-16 01:06:27 -0400281 q.him = RFC1143_NO;
282 _set_rfc1143(telnet, q);
Sean Middleditch2b4bfc42009-03-16 01:25:52 -0400283 libtelnet_send_telopt(telnet, LIBTELNET_DONT, telopt);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400284 _event(telnet, LIBTELNET_EV_WONT, 0, telopt,
285 0, 0);
286 break;
287 case RFC1143_WANTNO:
Sean Middleditch8b788962009-03-16 01:06:27 -0400288 q.him = RFC1143_NO;
289 _set_rfc1143(telnet, q);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400290 _event(telnet, LIBTELNET_EV_WONT, 0, telopt,
291 0, 0);
292 break;
293 case RFC1143_WANTNO_OP:
Sean Middleditch8b788962009-03-16 01:06:27 -0400294 q.him = RFC1143_WANTYES;
295 _set_rfc1143(telnet, q);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400296 _event(telnet, LIBTELNET_EV_DO, 0, telopt,
297 0, 0);
298 break;
299 case RFC1143_WANTYES:
300 case RFC1143_WANTYES_OP:
Sean Middleditch8b788962009-03-16 01:06:27 -0400301 q.him = RFC1143_NO;
302 _set_rfc1143(telnet, q);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400303 break;
304 }
305 break;
306
307 /* request to enable option on local end or confirm WILL */
308 case LIBTELNET_DO:
Sean Middleditch8b788962009-03-16 01:06:27 -0400309 switch (q.us) {
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400310 case RFC1143_NO:
311 if (_event(telnet, LIBTELNET_EV_DO, cmd, telopt, 0, 0) == 1) {
Sean Middleditch8b788962009-03-16 01:06:27 -0400312 q.us = RFC1143_YES;
313 _set_rfc1143(telnet, q);
Sean Middleditch2b4bfc42009-03-16 01:25:52 -0400314 libtelnet_send_telopt(telnet, LIBTELNET_WILL, telopt);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400315 } else
Sean Middleditch2b4bfc42009-03-16 01:25:52 -0400316 libtelnet_send_telopt(telnet, LIBTELNET_WONT, telopt);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400317 break;
318 case RFC1143_YES:
319 break;
320 case RFC1143_WANTNO:
Sean Middleditch8b788962009-03-16 01:06:27 -0400321 q.us = RFC1143_NO;
322 _set_rfc1143(telnet, q);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400323 _error(telnet, __LINE__, __func__, LIBTELNET_EPROTOCOL, 0,
324 "WONT answered by DO");
325 break;
326 case RFC1143_WANTNO_OP:
Sean Middleditch8b788962009-03-16 01:06:27 -0400327 q.us = RFC1143_YES;
328 _set_rfc1143(telnet, q);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400329 _error(telnet, __LINE__, __func__, LIBTELNET_EPROTOCOL, 0,
330 "WONT answered by DO");
331 break;
332 case RFC1143_WANTYES:
Sean Middleditch8b788962009-03-16 01:06:27 -0400333 q.us = RFC1143_YES;
334 _set_rfc1143(telnet, q);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400335 break;
336 case RFC1143_WANTYES_OP:
Sean Middleditch8b788962009-03-16 01:06:27 -0400337 q.us = RFC1143_WANTNO;
338 _set_rfc1143(telnet, q);
Sean Middleditch2b4bfc42009-03-16 01:25:52 -0400339 libtelnet_send_telopt(telnet, LIBTELNET_WONT, telopt);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400340 break;
341 }
342 break;
343
344 /* request to disable option on local end, confirm WONT, reject WILL */
345 case LIBTELNET_DONT:
Sean Middleditch8b788962009-03-16 01:06:27 -0400346 switch (q.us) {
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400347 case RFC1143_NO:
348 break;
349 case RFC1143_YES:
Sean Middleditch8b788962009-03-16 01:06:27 -0400350 q.us = RFC1143_NO;
351 _set_rfc1143(telnet, q);
Sean Middleditch2b4bfc42009-03-16 01:25:52 -0400352 libtelnet_send_telopt(telnet, LIBTELNET_WONT, telopt);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400353 _event(telnet, LIBTELNET_EV_DONT, 0, telopt, 0, 0);
354 break;
355 case RFC1143_WANTNO:
Sean Middleditch8b788962009-03-16 01:06:27 -0400356 q.us = RFC1143_NO;
357 _set_rfc1143(telnet, q);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400358 _event(telnet, LIBTELNET_EV_WONT, 0, telopt, 0, 0);
359 break;
360 case RFC1143_WANTNO_OP:
Sean Middleditch8b788962009-03-16 01:06:27 -0400361 q.us = RFC1143_WANTYES;
362 _set_rfc1143(telnet, q);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400363 _event(telnet, LIBTELNET_EV_WILL, 0, telopt, 0, 0);
364 break;
365 case RFC1143_WANTYES:
366 case RFC1143_WANTYES_OP:
Sean Middleditch8b788962009-03-16 01:06:27 -0400367 q.us = RFC1143_NO;
368 _set_rfc1143(telnet, q);
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400369 break;
370 }
371 break;
372 }
373}
374
Sean Middleditch29144852009-03-12 23:14:47 -0400375/* initialize a telnet state tracker */
Sean Middleditch812358d2009-03-15 23:24:03 -0400376void libtelnet_init(libtelnet_t *telnet, libtelnet_event_handler_t eh,
Sean Middleditch08bb05f2009-03-15 23:29:46 -0400377 unsigned char flags, void *user_data) {
Sean Middleditch812358d2009-03-15 23:24:03 -0400378 memset(telnet, 0, sizeof(libtelnet_t));
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400379 telnet->ud = user_data;
Sean Middleditch637df7f2009-03-15 12:57:32 -0400380 telnet->eh = eh;
Sean Middleditch08bb05f2009-03-15 23:29:46 -0400381 telnet->flags = flags;
Sean Middleditch29144852009-03-12 23:14:47 -0400382}
383
384/* free up any memory allocated by a state tracker */
Sean Middleditch812358d2009-03-15 23:24:03 -0400385void libtelnet_free(libtelnet_t *telnet) {
Sean Middleditch9de15982009-03-14 03:35:49 -0400386 /* free sub-request buffer */
Sean Middleditch51ad6792009-03-13 20:15:59 -0400387 if (telnet->buffer != 0) {
Sean Middleditch29144852009-03-12 23:14:47 -0400388 free(telnet->buffer);
389 telnet->buffer = 0;
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400390 telnet->buffer_size = 0;
391 telnet->buffer_pos = 0;
Sean Middleditch29144852009-03-12 23:14:47 -0400392 }
Sean Middleditch9de15982009-03-14 03:35:49 -0400393
Sean Middleditchfbe93e32009-03-15 23:39:31 -0400394 /* free zlib box */
395 if (telnet->z != 0) {
396 if (telnet->flags & LIBTELNET_PFLAG_DEFLATE)
397 deflateEnd(telnet->z);
398 else
399 inflateEnd(telnet->z);
400 free(telnet->z);
401 telnet->z = 0;
Sean Middleditch9de15982009-03-14 03:35:49 -0400402 }
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400403
404 /* free RFC1143 queue */
405 if (telnet->q) {
406 free(telnet->q);
407 telnet->q = 0;
408 telnet->q_size = 0;
409 }
Sean Middleditch29144852009-03-12 23:14:47 -0400410}
411
Sean Middleditch51ad6792009-03-13 20:15:59 -0400412/* push a byte into the telnet buffer */
Sean Middleditch812358d2009-03-15 23:24:03 -0400413static libtelnet_error_t _buffer_byte(libtelnet_t *telnet,
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400414 unsigned char byte) {
Sean Middleditch4d9444d2009-03-13 22:48:05 -0400415 unsigned char *new_buffer;
416 int i;
417
Sean Middleditch51ad6792009-03-13 20:15:59 -0400418 /* check if we're out of room */
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400419 if (telnet->buffer_pos == telnet->buffer_size) {
Sean Middleditch4d9444d2009-03-13 22:48:05 -0400420 /* find the next buffer size */
421 for (i = 0; i != _buffer_sizes_count; ++i) {
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400422 if (_buffer_sizes[i] == telnet->buffer_size)
Sean Middleditch4d9444d2009-03-13 22:48:05 -0400423 break;
424 }
425
426 /* overflow -- can't grow any more */
427 if (i >= _buffer_sizes_count - 1) {
Sean Middleditch16992272009-03-15 19:42:03 -0400428 _error(telnet, __LINE__, __func__, LIBTELNET_EOVERFLOW, 0,
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400429 "subnegotiation buffer size limit reached");
Sean Middleditch51ad6792009-03-13 20:15:59 -0400430 libtelnet_free(telnet);
Sean Middleditchf66a7ee2009-03-15 11:54:07 -0400431 return LIBTELNET_EOVERFLOW;
Sean Middleditch51ad6792009-03-13 20:15:59 -0400432 }
Sean Middleditch4d9444d2009-03-13 22:48:05 -0400433
434 /* (re)allocate buffer */
435 new_buffer = (unsigned char *)realloc(telnet->buffer,
436 _buffer_sizes[i + 1]);
437 if (new_buffer == 0) {
Sean Middleditch16992272009-03-15 19:42:03 -0400438 _error(telnet, __LINE__, __func__, LIBTELNET_ENOMEM, 0,
439 "realloc() failed");
Sean Middleditch4d9444d2009-03-13 22:48:05 -0400440 libtelnet_free(telnet);
Sean Middleditchf66a7ee2009-03-15 11:54:07 -0400441 return LIBTELNET_ENOMEM;
Sean Middleditch4d9444d2009-03-13 22:48:05 -0400442 }
443
444 telnet->buffer = new_buffer;
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400445 telnet->buffer_size = _buffer_sizes[i + 1];
Sean Middleditch51ad6792009-03-13 20:15:59 -0400446 }
447
448 /* push the byte, all set */
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400449 telnet->buffer[telnet->buffer_pos++] = byte;
Sean Middleditchf66a7ee2009-03-15 11:54:07 -0400450 return LIBTELNET_EOK;
Sean Middleditch51ad6792009-03-13 20:15:59 -0400451}
452
Sean Middleditch97a8cb22009-03-16 16:51:41 -0400453static void _process(libtelnet_t *telnet, const unsigned char *buffer,
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400454 unsigned int size) {
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400455 unsigned char byte;
456 unsigned int i, start;
457 for (i = start = 0; i != size; ++i) {
458 byte = buffer[i];
459 switch (telnet->state) {
460 /* regular data */
Sean Middleditch9de15982009-03-14 03:35:49 -0400461 case LIBTELNET_STATE_DATA:
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400462 /* on an IAC byte, pass through all pending bytes and
463 * switch states */
464 if (byte == LIBTELNET_IAC) {
465 if (i != start)
Sean Middleditch637df7f2009-03-15 12:57:32 -0400466 _event(telnet, LIBTELNET_EV_DATA, 0, 0, &buffer[start],
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400467 i - start);
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400468 telnet->state = LIBTELNET_STATE_IAC;
469 }
470 break;
471
472 /* IAC command */
473 case LIBTELNET_STATE_IAC:
474 switch (byte) {
Sean Middleditch6b372882009-03-14 13:06:47 -0400475 /* subnegotiation */
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400476 case LIBTELNET_SB:
477 telnet->state = LIBTELNET_STATE_SB;
478 break;
479 /* negotiation commands */
480 case LIBTELNET_WILL:
481 telnet->state = LIBTELNET_STATE_WILL;
482 break;
483 case LIBTELNET_WONT:
484 telnet->state = LIBTELNET_STATE_WONT;
485 break;
486 case LIBTELNET_DO:
487 telnet->state = LIBTELNET_STATE_DO;
488 break;
489 case LIBTELNET_DONT:
490 telnet->state = LIBTELNET_STATE_DONT;
491 break;
492 /* IAC escaping */
493 case LIBTELNET_IAC:
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400494 _event(telnet, LIBTELNET_EV_DATA, 0, 0, &byte, 1);
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400495 start = i + 1;
Sean Middleditch9de15982009-03-14 03:35:49 -0400496 telnet->state = LIBTELNET_STATE_DATA;
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400497 break;
498 /* some other command */
499 default:
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400500 _event(telnet, LIBTELNET_EV_IAC, byte, 0, 0, 0);
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400501 start = i + 1;
Sean Middleditch9de15982009-03-14 03:35:49 -0400502 telnet->state = LIBTELNET_STATE_DATA;
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400503 }
504 break;
505
506 /* negotiation commands */
507 case LIBTELNET_STATE_DO:
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400508 _negotiate(telnet, LIBTELNET_DO, byte);
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400509 start = i + 1;
Sean Middleditch9de15982009-03-14 03:35:49 -0400510 telnet->state = LIBTELNET_STATE_DATA;
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400511 break;
512 case LIBTELNET_STATE_DONT:
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400513 _negotiate(telnet, LIBTELNET_DONT, byte);
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400514 start = i + 1;
Sean Middleditch9de15982009-03-14 03:35:49 -0400515 telnet->state = LIBTELNET_STATE_DATA;
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400516 break;
517 case LIBTELNET_STATE_WILL:
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400518 _negotiate(telnet, LIBTELNET_WILL, byte);
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400519 start = i + 1;
Sean Middleditch9de15982009-03-14 03:35:49 -0400520 telnet->state = LIBTELNET_STATE_DATA;
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400521 break;
522 case LIBTELNET_STATE_WONT:
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400523 _negotiate(telnet, LIBTELNET_WONT, byte);
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400524 start = i + 1;
Sean Middleditch9de15982009-03-14 03:35:49 -0400525 telnet->state = LIBTELNET_STATE_DATA;
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400526 break;
527
Sean Middleditchda0e6952009-03-15 13:28:09 -0400528 /* subnegotiation -- determine subnegotiation telopt */
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400529 case LIBTELNET_STATE_SB:
Sean Middleditchda0e6952009-03-15 13:28:09 -0400530 telnet->sb_telopt = byte;
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400531 telnet->buffer_pos = 0;
Sean Middleditchda0e6952009-03-15 13:28:09 -0400532 telnet->state = LIBTELNET_STATE_SB_DATA;
533 break;
534
535 /* subnegotiation -- buffer bytes until end request */
536 case LIBTELNET_STATE_SB_DATA:
Sean Middleditch6b372882009-03-14 13:06:47 -0400537 /* IAC command in subnegotiation -- either IAC SE or IAC IAC */
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400538 if (byte == LIBTELNET_IAC) {
Sean Middleditchda0e6952009-03-15 13:28:09 -0400539 telnet->state = LIBTELNET_STATE_SB_DATA_IAC;
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400540 /* buffer the byte, or bail if we can't */
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400541 } else if (_buffer_byte(telnet, byte) != LIBTELNET_EOK) {
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400542 start = i + 1;
Sean Middleditch9de15982009-03-14 03:35:49 -0400543 telnet->state = LIBTELNET_STATE_DATA;
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400544 }
545 break;
546
Sean Middleditch6b372882009-03-14 13:06:47 -0400547 /* IAC escaping inside a subnegotiation */
Sean Middleditchda0e6952009-03-15 13:28:09 -0400548 case LIBTELNET_STATE_SB_DATA_IAC:
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400549 switch (byte) {
Sean Middleditch6b372882009-03-14 13:06:47 -0400550 /* end subnegotiation */
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400551 case LIBTELNET_SE:
Sean Middleditch9de15982009-03-14 03:35:49 -0400552 /* return to default state */
553 start = i + 1;
554 telnet->state = LIBTELNET_STATE_DATA;
555
Sean Middleditch9de15982009-03-14 03:35:49 -0400556 /* invoke callback */
Sean Middleditch637df7f2009-03-15 12:57:32 -0400557 _event(telnet, LIBTELNET_EV_SUBNEGOTIATION, 0,
Sean Middleditch5b5bc922009-03-15 23:02:10 -0400558 telnet->sb_telopt, telnet->buffer, telnet->buffer_pos);
Sean Middleditch9de15982009-03-14 03:35:49 -0400559
Sean Middleditch61f8eb62009-03-14 04:57:27 -0400560#ifdef HAVE_ZLIB
Sean Middleditch3df17f92009-03-16 01:12:16 -0400561 /* received COMPRESS2 begin marker, setup our zlib box and
562 * start handling the compressed stream if it's not already.
Sean Middleditch61f8eb62009-03-14 04:57:27 -0400563 */
Sean Middleditch3df17f92009-03-16 01:12:16 -0400564 if (telnet->sb_telopt == LIBTELNET_TELOPT_COMPRESS2) {
Sean Middleditchfbe93e32009-03-15 23:39:31 -0400565 if (_init_zlib(telnet, 0, 1) != LIBTELNET_EOK)
Sean Middleditch9de15982009-03-14 03:35:49 -0400566 break;
Sean Middleditch9de15982009-03-14 03:35:49 -0400567
Sean Middleditch61f8eb62009-03-14 04:57:27 -0400568 /* notify app that compression was enabled */
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400569 _event(telnet, LIBTELNET_EV_COMPRESS, 1, 0, 0, 0);
Sean Middleditch61f8eb62009-03-14 04:57:27 -0400570
Sean Middleditch9de15982009-03-14 03:35:49 -0400571 /* any remaining bytes in the buffer are compressed.
572 * we have to re-invoke libtelnet_push to get those
573 * bytes inflated and abort trying to process the
574 * remaining compressed bytes in the current _process
575 * buffer argument
576 */
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400577 libtelnet_push(telnet, &buffer[start], size - start);
Sean Middleditch9de15982009-03-14 03:35:49 -0400578 return;
579 }
Sean Middleditch61f8eb62009-03-14 04:57:27 -0400580#endif /* HAVE_ZLIB */
581
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400582 break;
583 /* escaped IAC byte */
584 case LIBTELNET_IAC:
585 /* push IAC into buffer */
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400586 if (_buffer_byte(telnet, LIBTELNET_IAC) !=
Sean Middleditchf66a7ee2009-03-15 11:54:07 -0400587 LIBTELNET_EOK) {
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400588 start = i + 1;
Sean Middleditch9de15982009-03-14 03:35:49 -0400589 telnet->state = LIBTELNET_STATE_DATA;
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400590 } else {
Sean Middleditchda0e6952009-03-15 13:28:09 -0400591 telnet->state = LIBTELNET_STATE_SB_DATA;
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400592 }
593 break;
594 /* something else -- protocol error */
595 default:
Sean Middleditch16992272009-03-15 19:42:03 -0400596 _error(telnet, __LINE__, __func__, LIBTELNET_EPROTOCOL, 0,
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400597 "unexpected byte after IAC inside SB: %d",
Sean Middleditchd922c6f2009-03-14 22:35:01 -0400598 byte);
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400599 start = i + 1;
Sean Middleditch9de15982009-03-14 03:35:49 -0400600 telnet->state = LIBTELNET_STATE_DATA;
Sean Middleditch8b5e2b12009-03-13 23:39:18 -0400601 break;
602 }
603 break;
604 }
605 }
606
607 /* pass through any remaining bytes */
Sean Middleditchd30fd572009-03-14 12:55:17 -0400608 if (telnet->state == LIBTELNET_STATE_DATA && i != start)
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400609 _event(telnet, LIBTELNET_EV_DATA, 0, 0, buffer + start, i - start);
Sean Middleditch29144852009-03-12 23:14:47 -0400610}
611
Sean Middleditch9de15982009-03-14 03:35:49 -0400612/* push a bytes into the state tracker */
Sean Middleditch97a8cb22009-03-16 16:51:41 -0400613void libtelnet_push(libtelnet_t *telnet, const unsigned char *buffer,
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400614 unsigned int size) {
Sean Middleditch61f8eb62009-03-14 04:57:27 -0400615#ifdef HAVE_ZLIB
Sean Middleditch72cc9642009-03-15 11:50:36 -0400616 /* if we have an inflate (decompression) zlib stream, use it */
Sean Middleditch4611d912009-03-16 00:53:57 -0400617 if (telnet->z != 0 && !(telnet->flags & LIBTELNET_PFLAG_DEFLATE)) {
Sean Middleditch9de15982009-03-14 03:35:49 -0400618 unsigned char inflate_buffer[4096];
619 int rs;
620
621 /* initialize zlib state */
Sean Middleditch97a8cb22009-03-16 16:51:41 -0400622 telnet->z->next_in = (unsigned char *)buffer;
Sean Middleditchfbe93e32009-03-15 23:39:31 -0400623 telnet->z->avail_in = size;
624 telnet->z->next_out = inflate_buffer;
625 telnet->z->avail_out = sizeof(inflate_buffer);
Sean Middleditch9de15982009-03-14 03:35:49 -0400626
627 /* inflate until buffer exhausted and all output is produced */
Sean Middleditchfbe93e32009-03-15 23:39:31 -0400628 while (telnet->z->avail_in > 0 || telnet->z->avail_out == 0) {
Sean Middleditch9de15982009-03-14 03:35:49 -0400629 /* reset output buffer */
630
631 /* decompress */
Sean Middleditchfbe93e32009-03-15 23:39:31 -0400632 rs = inflate(telnet->z, Z_SYNC_FLUSH);
Sean Middleditch9de15982009-03-14 03:35:49 -0400633
634 /* process the decompressed bytes on success */
635 if (rs == Z_OK || rs == Z_STREAM_END)
636 _process(telnet, inflate_buffer, sizeof(inflate_buffer) -
Sean Middleditchfbe93e32009-03-15 23:39:31 -0400637 telnet->z->avail_out);
Sean Middleditch9de15982009-03-14 03:35:49 -0400638 else
Sean Middleditch16992272009-03-15 19:42:03 -0400639 _error(telnet, __LINE__, __func__, LIBTELNET_ECOMPRESS, 1,
640 "inflate() failed: %s", zError(rs));
Sean Middleditch9de15982009-03-14 03:35:49 -0400641
642 /* prepare output buffer for next run */
Sean Middleditchfbe93e32009-03-15 23:39:31 -0400643 telnet->z->next_out = inflate_buffer;
644 telnet->z->avail_out = sizeof(inflate_buffer);
Sean Middleditch9de15982009-03-14 03:35:49 -0400645
646 /* on error (or on end of stream) disable further inflation */
647 if (rs != Z_OK) {
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400648 _event(telnet, LIBTELNET_EV_COMPRESS, 0, 0, 0, 0);
Sean Middleditch61f8eb62009-03-14 04:57:27 -0400649
Sean Middleditchfbe93e32009-03-15 23:39:31 -0400650 inflateEnd(telnet->z);
651 free(telnet->z);
652 telnet->z = 0;
Sean Middleditch9de15982009-03-14 03:35:49 -0400653 break;
654 }
655 }
656
Sean Middleditch61f8eb62009-03-14 04:57:27 -0400657 /* COMPRESS2 is not negotiated, just process */
658 } else
659#endif /* HAVE_ZLIB */
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400660 _process(telnet, buffer, size);
Sean Middleditch61f8eb62009-03-14 04:57:27 -0400661}
662
Sean Middleditch29144852009-03-12 23:14:47 -0400663/* send an iac command */
Sean Middleditch812358d2009-03-15 23:24:03 -0400664void libtelnet_send_command(libtelnet_t *telnet, unsigned char cmd) {
Sean Middleditchf9cebec2009-03-13 20:17:31 -0400665 unsigned char bytes[2] = { LIBTELNET_IAC, cmd };
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400666 _send(telnet, bytes, 2);
Sean Middleditch29144852009-03-12 23:14:47 -0400667}
668
Sean Middleditch2b4bfc42009-03-16 01:25:52 -0400669/* send an iac command with telopt */
670void libtelnet_send_telopt(libtelnet_t *telnet, unsigned char cmd,
671 unsigned char telopt) {
672 unsigned char bytes[3] = { LIBTELNET_IAC, cmd, telopt };
673 _send(telnet, bytes, 3);
674}
675
Sean Middleditch29144852009-03-12 23:14:47 -0400676/* send negotiation */
Sean Middleditch812358d2009-03-15 23:24:03 -0400677void libtelnet_send_negotiate(libtelnet_t *telnet, unsigned char cmd,
Sean Middleditch8b788962009-03-16 01:06:27 -0400678 unsigned char telopt) {
679 libtelnet_rfc1143_t q;
680
681 /* if we're in proxy mode, just send it now */
682 if (telnet->flags & LIBTELNET_FLAG_PROXY) {
683 unsigned char bytes[3] = { LIBTELNET_IAC, cmd, telopt };
684 _send(telnet, bytes, 3);
685 return;
686 }
687
688 /* get current option states */
689 q = _get_rfc1143(telnet, telopt);
690
691 switch (cmd) {
692 /* advertise willingess to support an option */
693 case LIBTELNET_WILL:
694 switch (q.us) {
695 case RFC1143_NO:
696 q.us = RFC1143_WANTYES;
697 _set_rfc1143(telnet, q);
698 _negotiate(telnet, LIBTELNET_WILL, telopt);
699 break;
700 case RFC1143_YES:
701 break;
702 case RFC1143_WANTNO:
703 q.us = RFC1143_WANTNO_OP;
704 _set_rfc1143(telnet, q);
705 break;
706 case RFC1143_WANTYES:
707 break;
708 case RFC1143_WANTNO_OP:
709 break;
710 case RFC1143_WANTYES_OP:
711 q.us = RFC1143_WANTYES;
712 _set_rfc1143(telnet, q);
713 break;
714 }
715 break;
716
717 /* force turn-off of locally enabled option */
718 case LIBTELNET_WONT:
719 switch (q.us) {
720 case RFC1143_NO:
721 break;
722 case RFC1143_YES:
723 q.us = RFC1143_WANTNO;
724 _set_rfc1143(telnet, q);
725 _negotiate(telnet, LIBTELNET_WONT, telopt);
726 break;
727 case RFC1143_WANTNO:
728 break;
729 case RFC1143_WANTYES:
730 q.us = RFC1143_WANTYES_OP;
731 _set_rfc1143(telnet, q);
732 break;
733 case RFC1143_WANTNO_OP:
734 q.us = RFC1143_WANTNO;
735 _set_rfc1143(telnet, q);
736 break;
737 case RFC1143_WANTYES_OP:
738 break;
739 }
740 break;
741
742 /* ask remote end to enable an option */
743 case LIBTELNET_DO:
744 switch (q.him) {
745 case RFC1143_NO:
746 q.him = RFC1143_WANTYES;
747 _set_rfc1143(telnet, q);
748 _negotiate(telnet, LIBTELNET_DO, telopt);
749 break;
750 case RFC1143_YES:
751 break;
752 case RFC1143_WANTNO:
753 q.him = RFC1143_WANTNO_OP;
754 _set_rfc1143(telnet, q);
755 break;
756 case RFC1143_WANTYES:
757 break;
758 case RFC1143_WANTNO_OP:
759 break;
760 case RFC1143_WANTYES_OP:
761 q.him = RFC1143_WANTYES;
762 _set_rfc1143(telnet, q);
763 break;
764 }
765 break;
766
767 /* demand remote end disable an option */
768 case LIBTELNET_DONT:
769 switch (q.him) {
770 case RFC1143_NO:
771 break;
772 case RFC1143_YES:
773 q.him = RFC1143_WANTNO;
774 _set_rfc1143(telnet, q);
775 _negotiate(telnet, LIBTELNET_DONT, telopt);
776 break;
777 case RFC1143_WANTNO:
778 break;
779 case RFC1143_WANTYES:
780 q.him = RFC1143_WANTYES_OP;
781 _set_rfc1143(telnet, q);
782 break;
783 case RFC1143_WANTNO_OP:
784 q.him = RFC1143_WANTNO;
785 _set_rfc1143(telnet, q);
786 break;
787 case RFC1143_WANTYES_OP:
788 break;
789 }
790 break;
791 }
Sean Middleditch29144852009-03-12 23:14:47 -0400792}
793
794/* send non-command data (escapes IAC bytes) */
Sean Middleditch97a8cb22009-03-16 16:51:41 -0400795void libtelnet_send_data(libtelnet_t *telnet, const unsigned char *buffer,
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400796 unsigned int size) {
Sean Middleditch4d9444d2009-03-13 22:48:05 -0400797 unsigned int i, l;
Sean Middleditchc337ba62009-03-16 16:47:27 -0400798
Sean Middleditch29144852009-03-12 23:14:47 -0400799 for (l = i = 0; i != size; ++i) {
800 /* dump prior portion of text, send escaped bytes */
801 if (buffer[i] == LIBTELNET_IAC) {
802 /* dump prior text if any */
803 if (i != l)
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400804 _send(telnet, buffer + l, i - l);
Sean Middleditch29144852009-03-12 23:14:47 -0400805 l = i + 1;
806
807 /* send escape */
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400808 libtelnet_send_command(telnet, LIBTELNET_IAC);
Sean Middleditch29144852009-03-12 23:14:47 -0400809 }
810 }
811
812 /* send whatever portion of buffer is left */
813 if (i != l)
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400814 _send(telnet, buffer + l, i - l);
Sean Middleditch29144852009-03-12 23:14:47 -0400815}
816
817/* send sub-request */
Sean Middleditch2b4bfc42009-03-16 01:25:52 -0400818void libtelnet_send_subnegotiation(libtelnet_t *telnet, unsigned char telopt,
Sean Middleditch97a8cb22009-03-16 16:51:41 -0400819 const unsigned char *buffer, unsigned int size) {
Sean Middleditch2b4bfc42009-03-16 01:25:52 -0400820 libtelnet_send_telopt(telnet, LIBTELNET_SB, telopt);
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400821 libtelnet_send_data(telnet, buffer, size);
822 libtelnet_send_command(telnet, LIBTELNET_SE);
Sean Middleditch61f8eb62009-03-14 04:57:27 -0400823
824#ifdef HAVE_ZLIB
Sean Middleditch72cc9642009-03-15 11:50:36 -0400825 /* if we're a proxy and we just sent the COMPRESS2 marker, we must
826 * make sure all further data is compressed if not already.
Sean Middleditch61f8eb62009-03-14 04:57:27 -0400827 */
Sean Middleditch08bb05f2009-03-15 23:29:46 -0400828 if (telnet->flags & LIBTELNET_FLAG_PROXY &&
Sean Middleditch2b4bfc42009-03-16 01:25:52 -0400829 telopt == LIBTELNET_TELOPT_COMPRESS2) {
Sean Middleditchd922c6f2009-03-14 22:35:01 -0400830
Sean Middleditchfbe93e32009-03-15 23:39:31 -0400831 if (_init_zlib(telnet, 1, 1) != LIBTELNET_EOK)
Sean Middleditchd922c6f2009-03-14 22:35:01 -0400832 return;
Sean Middleditch61f8eb62009-03-14 04:57:27 -0400833
834 /* notify app that compression was enabled */
Sean Middleditch9f79cc52009-03-15 13:39:24 -0400835 _event(telnet, LIBTELNET_EV_COMPRESS, 1, 0, 0, 0);
Sean Middleditch61f8eb62009-03-14 04:57:27 -0400836 }
837#endif /* HAVE_ZLIB */
Sean Middleditch29144852009-03-12 23:14:47 -0400838}
Sean Middleditch124a1c22009-03-15 13:20:03 -0400839
Sean Middleditch812358d2009-03-15 23:24:03 -0400840void libtelnet_begin_compress2(libtelnet_t *telnet) {
Sean Middleditch124a1c22009-03-15 13:20:03 -0400841#ifdef HAVE_ZLIB
Sean Middleditch97a8cb22009-03-16 16:51:41 -0400842 static const unsigned char compress2[] = { LIBTELNET_IAC, LIBTELNET_SB,
Sean Middleditchfbe93e32009-03-15 23:39:31 -0400843 LIBTELNET_TELOPT_COMPRESS2, LIBTELNET_IAC, LIBTELNET_SE };
Sean Middleditch124a1c22009-03-15 13:20:03 -0400844
Sean Middleditch124a1c22009-03-15 13:20:03 -0400845 /* attempt to create output stream first, bail if we can't */
Sean Middleditchfbe93e32009-03-15 23:39:31 -0400846 if (_init_zlib(telnet, 1, 0) != LIBTELNET_EOK)
Sean Middleditch124a1c22009-03-15 13:20:03 -0400847 return;
848
Sean Middleditchfbe93e32009-03-15 23:39:31 -0400849 /* send compression marker. we send directly to the event handler
850 * instead of passing through _send because _send would result in
851 * the compress marker itself being compressed.
852 */
853 _event(telnet, LIBTELNET_EV_SEND, 0, 0, compress2, sizeof(compress2));
Sean Middleditch2b4bfc42009-03-16 01:25:52 -0400854
855 /* notify app that compression was successfully enabled */
856 _event(telnet, LIBTELNET_EV_COMPRESS, 1, 0, 0, 0);
Sean Middleditch124a1c22009-03-15 13:20:03 -0400857#endif /* HAVE_ZLIB */
858}
Sean Middleditchd58f49f2009-03-16 12:49:35 -0400859
860/* send formatted data through libtelnet_send_data */
Sean Middleditch4a156042009-03-16 17:10:58 -0400861int libtelnet_printf(libtelnet_t *telnet, const char *fmt, ...) {
Sean Middleditchd58f49f2009-03-16 12:49:35 -0400862 char buffer[4096];
863 va_list va;
864 int rs;
865
866 /* format */
867 va_start(va, fmt);
868 rs = vsnprintf(buffer, sizeof(buffer), fmt, va);
869 va_end(va);
870
871 /* send */
872 libtelnet_send_data(telnet, (unsigned char *)buffer, rs);
873
874 return rs;
875}
Sean Middleditch4a156042009-03-16 17:10:58 -0400876
877/* send formatted data with \r and \n translation in addition to IAC IAC */
878int libtelnet_printf2(libtelnet_t *telnet, const char *fmt, ...) {
879 static const unsigned char CRLF[] = { '\r', '\n' };
880 static const unsigned char CRNUL[] = { '\r', '\0' };
881 char buffer[4096];
882 va_list va;
883 int rs, i, l;
884
885 /* format */
886 va_start(va, fmt);
887 rs = vsnprintf(buffer, sizeof(buffer), fmt, va);
888 va_end(va);
889
890 /* send */
891 for (l = i = 0; i != rs; ++i) {
892 /* special characters */
893 if (buffer[i] == LIBTELNET_IAC || buffer[i] == '\r' ||
894 buffer[i] == '\n') {
895 /* dump prior portion of text */
896 if (i != l)
897 _send(telnet, (unsigned char *)buffer + l, i - l);
898 l = i + 1;
899
900 /* IAC -> IAC IAC */
901 if (buffer[i] == LIBTELNET_IAC)
902 libtelnet_send_command(telnet, LIBTELNET_IAC);
903 /* automatic translation of \r -> CRNUL */
904 else if (buffer[i] == '\r')
905 _send(telnet, CRNUL, 2);
906 /* automatic translation of \n -> CRLF */
907 else if (buffer[i] == '\n')
908 _send(telnet, CRLF, 2);
909 }
910 }
911
912 /* send whatever portion of buffer is left */
913 if (i != l)
914 _send(telnet, (unsigned char *)buffer + l, i - l);
915
916 return rs;
917}