blob: d71c8e067a7b069b730e4a7c58e5197458828108 [file] [log] [blame]
Kristian Monsen5ab50182010-05-14 18:53:44 +01001/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
Elliott Hughes82be86d2017-09-20 17:00:17 -07008 * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
Kristian Monsen5ab50182010-05-14 18:53:44 +01009 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
Alex Deymod15eaac2016-06-28 14:49:26 -070012 * are also available at https://curl.haxx.se/docs/copyright.html.
Kristian Monsen5ab50182010-05-14 18:53:44 +010013 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ***************************************************************************/
22
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070023#include "curl_setup.h"
Kristian Monsen5ab50182010-05-14 18:53:44 +010024
25#ifndef CURL_DISABLE_TELNET
Kristian Monsen5ab50182010-05-14 18:53:44 +010026
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070027#ifdef HAVE_NETINET_IN_H
Kristian Monsen5ab50182010-05-14 18:53:44 +010028#include <netinet/in.h>
Kristian Monsen5ab50182010-05-14 18:53:44 +010029#endif
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070030#ifdef HAVE_NETDB_H
Kristian Monsen5ab50182010-05-14 18:53:44 +010031#include <netdb.h>
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070032#endif
Kristian Monsen5ab50182010-05-14 18:53:44 +010033#ifdef HAVE_ARPA_INET_H
34#include <arpa/inet.h>
35#endif
36#ifdef HAVE_NET_IF_H
37#include <net/if.h>
38#endif
39#ifdef HAVE_SYS_IOCTL_H
40#include <sys/ioctl.h>
41#endif
42
43#ifdef HAVE_SYS_PARAM_H
44#include <sys/param.h>
45#endif
46
Kristian Monsen5ab50182010-05-14 18:53:44 +010047#include "urldata.h"
48#include <curl/curl.h>
49#include "transfer.h"
50#include "sendf.h"
51#include "telnet.h"
52#include "connect.h"
Lucas Eckels9bd90e62012-08-06 15:07:02 -070053#include "progress.h"
Alex Deymod15eaac2016-06-28 14:49:26 -070054#include "system_win32.h"
Kristian Monsen5ab50182010-05-14 18:53:44 +010055
56#define TELOPTS
57#define TELCMDS
58
59#include "arpa_telnet.h"
Kristian Monsen5ab50182010-05-14 18:53:44 +010060#include "select.h"
Elliott Hughescee03382017-06-23 12:17:18 -070061#include "strcase.h"
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070062#include "warnless.h"
Kristian Monsen5ab50182010-05-14 18:53:44 +010063
Alex Deymod15eaac2016-06-28 14:49:26 -070064/* The last 3 #include files should be in this order */
65#include "curl_printf.h"
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070066#include "curl_memory.h"
Kristian Monsen5ab50182010-05-14 18:53:44 +010067#include "memdebug.h"
68
69#define SUBBUFSIZE 512
70
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070071#define CURL_SB_CLEAR(x) x->subpointer = x->subbuffer
72#define CURL_SB_TERM(x) \
73 do { \
74 x->subend = x->subpointer; \
75 CURL_SB_CLEAR(x); \
76 } WHILE_FALSE
77#define CURL_SB_ACCUM(x,c) \
78 do { \
Alex Deymo486467e2017-12-19 19:04:07 +010079 if(x->subpointer < (x->subbuffer + sizeof x->subbuffer)) \
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070080 *x->subpointer++ = (c); \
81 } WHILE_FALSE
Kristian Monsen5ab50182010-05-14 18:53:44 +010082
83#define CURL_SB_GET(x) ((*x->subpointer++)&0xff)
Kristian Monsen5ab50182010-05-14 18:53:44 +010084#define CURL_SB_LEN(x) (x->subend - x->subpointer)
85
Elliott Hughes82be86d2017-09-20 17:00:17 -070086/* For posterity:
87#define CURL_SB_PEEK(x) ((*x->subpointer)&0xff)
88#define CURL_SB_EOF(x) (x->subpointer >= x->subend) */
89
Kristian Monsen5ab50182010-05-14 18:53:44 +010090#ifdef CURL_DISABLE_VERBOSE_STRINGS
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070091#define printoption(a,b,c,d) Curl_nop_stmt
Kristian Monsen5ab50182010-05-14 18:53:44 +010092#endif
93
94#ifdef USE_WINSOCK
95typedef FARPROC WSOCK2_FUNC;
Elliott Hughes82be86d2017-09-20 17:00:17 -070096static CURLcode check_wsock2(struct Curl_easy *data);
Kristian Monsen5ab50182010-05-14 18:53:44 +010097#endif
98
99static
100CURLcode telrcv(struct connectdata *,
101 const unsigned char *inbuf, /* Data received from socket */
102 ssize_t count); /* Number of bytes received */
103
104#ifndef CURL_DISABLE_VERBOSE_STRINGS
Alex Deymoe3149cc2016-10-05 11:18:42 -0700105static void printoption(struct Curl_easy *data,
Kristian Monsen5ab50182010-05-14 18:53:44 +0100106 const char *direction,
107 int cmd, int option);
108#endif
109
110static void negotiate(struct connectdata *);
111static void send_negotiation(struct connectdata *, int cmd, int option);
112static void set_local_option(struct connectdata *, int cmd, int option);
113static void set_remote_option(struct connectdata *, int cmd, int option);
114
Alex Deymoe3149cc2016-10-05 11:18:42 -0700115static void printsub(struct Curl_easy *data,
Kristian Monsen5ab50182010-05-14 18:53:44 +0100116 int direction, unsigned char *pointer,
117 size_t length);
118static void suboption(struct connectdata *);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700119static void sendsuboption(struct connectdata *conn, int option);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100120
121static CURLcode telnet_do(struct connectdata *conn, bool *done);
122static CURLcode telnet_done(struct connectdata *conn,
123 CURLcode, bool premature);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700124static CURLcode send_telnet_data(struct connectdata *conn,
125 char *buffer, ssize_t nread);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100126
127/* For negotiation compliant to RFC 1143 */
128#define CURL_NO 0
129#define CURL_YES 1
130#define CURL_WANTYES 2
131#define CURL_WANTNO 3
132
133#define CURL_EMPTY 0
134#define CURL_OPPOSITE 1
135
136/*
137 * Telnet receiver states for fsm
138 */
139typedef enum
140{
141 CURL_TS_DATA = 0,
142 CURL_TS_IAC,
143 CURL_TS_WILL,
144 CURL_TS_WONT,
145 CURL_TS_DO,
146 CURL_TS_DONT,
147 CURL_TS_CR,
148 CURL_TS_SB, /* sub-option collection */
149 CURL_TS_SE /* looking for sub-option end */
150} TelnetReceive;
151
152struct TELNET {
153 int please_negotiate;
154 int already_negotiated;
155 int us[256];
156 int usq[256];
157 int us_preferred[256];
158 int him[256];
159 int himq[256];
160 int him_preferred[256];
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700161 int subnegotiation[256];
Kristian Monsen5ab50182010-05-14 18:53:44 +0100162 char subopt_ttype[32]; /* Set with suboption TTYPE */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700163 char subopt_xdisploc[128]; /* Set with suboption XDISPLOC */
164 unsigned short subopt_wsx; /* Set with suboption NAWS */
165 unsigned short subopt_wsy; /* Set with suboption NAWS */
166 struct curl_slist *telnet_vars; /* Environment variables */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100167
168 /* suboptions */
169 unsigned char subbuffer[SUBBUFSIZE];
170 unsigned char *subpointer, *subend; /* buffer for sub-options */
171
172 TelnetReceive telrcv_state;
173};
174
175
176/*
177 * TELNET protocol handler.
178 */
179
180const struct Curl_handler Curl_handler_telnet = {
181 "TELNET", /* scheme */
182 ZERO_NULL, /* setup_connection */
183 telnet_do, /* do_it */
184 telnet_done, /* done */
185 ZERO_NULL, /* do_more */
186 ZERO_NULL, /* connect_it */
187 ZERO_NULL, /* connecting */
188 ZERO_NULL, /* doing */
189 ZERO_NULL, /* proto_getsock */
190 ZERO_NULL, /* doing_getsock */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700191 ZERO_NULL, /* domore_getsock */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100192 ZERO_NULL, /* perform_getsock */
193 ZERO_NULL, /* disconnect */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700194 ZERO_NULL, /* readwrite */
Elliott Hughes82be86d2017-09-20 17:00:17 -0700195 ZERO_NULL, /* connection_check */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100196 PORT_TELNET, /* defport */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700197 CURLPROTO_TELNET, /* protocol */
198 PROTOPT_NONE | PROTOPT_NOURLQUERY /* flags */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100199};
200
201
202#ifdef USE_WINSOCK
203static CURLcode
Alex Deymoe3149cc2016-10-05 11:18:42 -0700204check_wsock2(struct Curl_easy *data)
Kristian Monsen5ab50182010-05-14 18:53:44 +0100205{
206 int err;
207 WORD wVersionRequested;
208 WSADATA wsaData;
209
210 DEBUGASSERT(data);
211
212 /* telnet requires at least WinSock 2.0 so ask for it. */
213 wVersionRequested = MAKEWORD(2, 0);
214
215 err = WSAStartup(wVersionRequested, &wsaData);
216
217 /* We must've called this once already, so this call */
218 /* should always succeed. But, just in case... */
219 if(err != 0) {
220 failf(data,"WSAStartup failed (%d)",err);
221 return CURLE_FAILED_INIT;
222 }
223
224 /* We have to have a WSACleanup call for every successful */
225 /* WSAStartup call. */
226 WSACleanup();
227
228 /* Check that our version is supported */
229 if(LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) ||
230 HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested)) {
231 /* Our version isn't supported */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700232 failf(data, "insufficient winsock version to support "
233 "telnet");
234 return CURLE_FAILED_INIT;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100235 }
236
237 /* Our version is supported */
238 return CURLE_OK;
239}
240#endif
241
242static
243CURLcode init_telnet(struct connectdata *conn)
244{
245 struct TELNET *tn;
246
247 tn = calloc(1, sizeof(struct TELNET));
248 if(!tn)
249 return CURLE_OUT_OF_MEMORY;
250
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700251 conn->data->req.protop = tn; /* make us known */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100252
253 tn->telrcv_state = CURL_TS_DATA;
254
255 /* Init suboptions */
256 CURL_SB_CLEAR(tn);
257
258 /* Set the options we want by default */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100259 tn->us_preferred[CURL_TELOPT_SGA] = CURL_YES;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100260 tn->him_preferred[CURL_TELOPT_SGA] = CURL_YES;
261
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700262 /* To be compliant with previous releases of libcurl
263 we enable this option by default. This behaviour
264 can be changed thanks to the "BINARY" option in
265 CURLOPT_TELNETOPTIONS
266 */
267 tn->us_preferred[CURL_TELOPT_BINARY] = CURL_YES;
268 tn->him_preferred[CURL_TELOPT_BINARY] = CURL_YES;
269
270 /* We must allow the server to echo what we sent
271 but it is not necessary to request the server
272 to do so (it might forces the server to close
273 the connection). Hence, we ignore ECHO in the
274 negotiate function
275 */
276 tn->him_preferred[CURL_TELOPT_ECHO] = CURL_YES;
277
278 /* Set the subnegotiation fields to send information
279 just after negotiation passed (do/will)
280
281 Default values are (0,0) initialized by calloc.
282 According to the RFC1013 it is valid:
283 A value equal to zero is acceptable for the width (or height),
284 and means that no character width (or height) is being sent.
285 In this case, the width (or height) that will be assumed by the
286 Telnet server is operating system specific (it will probably be
287 based upon the terminal type information that may have been sent
288 using the TERMINAL TYPE Telnet option). */
289 tn->subnegotiation[CURL_TELOPT_NAWS] = CURL_YES;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100290 return CURLE_OK;
291}
292
293static void negotiate(struct connectdata *conn)
294{
295 int i;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700296 struct TELNET *tn = (struct TELNET *) conn->data->req.protop;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100297
Alex Deymo486467e2017-12-19 19:04:07 +0100298 for(i = 0; i < CURL_NTELOPTS; i++) {
299 if(i == CURL_TELOPT_ECHO)
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700300 continue;
301
Kristian Monsen5ab50182010-05-14 18:53:44 +0100302 if(tn->us_preferred[i] == CURL_YES)
303 set_local_option(conn, i, CURL_YES);
304
305 if(tn->him_preferred[i] == CURL_YES)
306 set_remote_option(conn, i, CURL_YES);
307 }
308}
309
310#ifndef CURL_DISABLE_VERBOSE_STRINGS
Alex Deymoe3149cc2016-10-05 11:18:42 -0700311static void printoption(struct Curl_easy *data,
Kristian Monsen5ab50182010-05-14 18:53:44 +0100312 const char *direction, int cmd, int option)
313{
314 const char *fmt;
315 const char *opt;
316
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700317 if(data->set.verbose) {
318 if(cmd == CURL_IAC) {
Kristian Monsen5ab50182010-05-14 18:53:44 +0100319 if(CURL_TELCMD_OK(option))
320 infof(data, "%s IAC %s\n", direction, CURL_TELCMD(option));
321 else
322 infof(data, "%s IAC %d\n", direction, option);
323 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700324 else {
Kristian Monsen5ab50182010-05-14 18:53:44 +0100325 fmt = (cmd == CURL_WILL) ? "WILL" : (cmd == CURL_WONT) ? "WONT" :
326 (cmd == CURL_DO) ? "DO" : (cmd == CURL_DONT) ? "DONT" : 0;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700327 if(fmt) {
Kristian Monsen5ab50182010-05-14 18:53:44 +0100328 if(CURL_TELOPT_OK(option))
329 opt = CURL_TELOPT(option);
330 else if(option == CURL_TELOPT_EXOPL)
331 opt = "EXOPL";
332 else
333 opt = NULL;
334
335 if(opt)
336 infof(data, "%s %s %s\n", direction, fmt, opt);
337 else
338 infof(data, "%s %s %d\n", direction, fmt, option);
339 }
340 else
341 infof(data, "%s %d %d\n", direction, cmd, option);
342 }
343 }
344}
345#endif
346
347static void send_negotiation(struct connectdata *conn, int cmd, int option)
348{
349 unsigned char buf[3];
350 ssize_t bytes_written;
351 int err;
Alex Deymoe3149cc2016-10-05 11:18:42 -0700352 struct Curl_easy *data = conn->data;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100353
354 buf[0] = CURL_IAC;
355 buf[1] = (unsigned char)cmd;
356 buf[2] = (unsigned char)option;
357
358 bytes_written = swrite(conn->sock[FIRSTSOCKET], buf, 3);
359 if(bytes_written < 0) {
360 err = SOCKERRNO;
361 failf(data,"Sending data failed (%d)",err);
362 }
363
364 printoption(conn->data, "SENT", cmd, option);
365}
366
367static
368void set_remote_option(struct connectdata *conn, int option, int newstate)
369{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700370 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
371 if(newstate == CURL_YES) {
372 switch(tn->him[option]) {
373 case CURL_NO:
374 tn->him[option] = CURL_WANTYES;
375 send_negotiation(conn, CURL_DO, option);
376 break;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100377
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700378 case CURL_YES:
379 /* Already enabled */
380 break;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100381
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700382 case CURL_WANTNO:
383 switch(tn->himq[option]) {
384 case CURL_EMPTY:
385 /* Already negotiating for CURL_YES, queue the request */
386 tn->himq[option] = CURL_OPPOSITE;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100387 break;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700388 case CURL_OPPOSITE:
389 /* Error: already queued an enable request */
390 break;
391 }
392 break;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100393
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700394 case CURL_WANTYES:
395 switch(tn->himq[option]) {
396 case CURL_EMPTY:
397 /* Error: already negotiating for enable */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100398 break;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700399 case CURL_OPPOSITE:
400 tn->himq[option] = CURL_EMPTY;
401 break;
402 }
403 break;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100404 }
405 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700406 else { /* NO */
407 switch(tn->him[option]) {
408 case CURL_NO:
409 /* Already disabled */
410 break;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100411
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700412 case CURL_YES:
413 tn->him[option] = CURL_WANTNO;
414 send_negotiation(conn, CURL_DONT, option);
415 break;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100416
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700417 case CURL_WANTNO:
418 switch(tn->himq[option]) {
419 case CURL_EMPTY:
420 /* Already negotiating for NO */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100421 break;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700422 case CURL_OPPOSITE:
423 tn->himq[option] = CURL_EMPTY;
424 break;
425 }
426 break;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100427
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700428 case CURL_WANTYES:
429 switch(tn->himq[option]) {
430 case CURL_EMPTY:
431 tn->himq[option] = CURL_OPPOSITE;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100432 break;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700433 case CURL_OPPOSITE:
434 break;
435 }
436 break;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100437 }
438 }
439}
440
441static
442void rec_will(struct connectdata *conn, int option)
443{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700444 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
445 switch(tn->him[option]) {
446 case CURL_NO:
447 if(tn->him_preferred[option] == CURL_YES) {
448 tn->him[option] = CURL_YES;
449 send_negotiation(conn, CURL_DO, option);
450 }
451 else
452 send_negotiation(conn, CURL_DONT, option);
453
454 break;
455
456 case CURL_YES:
457 /* Already enabled */
458 break;
459
460 case CURL_WANTNO:
461 switch(tn->himq[option]) {
462 case CURL_EMPTY:
463 /* Error: DONT answered by WILL */
464 tn->him[option] = CURL_NO;
465 break;
466 case CURL_OPPOSITE:
467 /* Error: DONT answered by WILL */
468 tn->him[option] = CURL_YES;
469 tn->himq[option] = CURL_EMPTY;
470 break;
471 }
472 break;
473
474 case CURL_WANTYES:
475 switch(tn->himq[option]) {
476 case CURL_EMPTY:
477 tn->him[option] = CURL_YES;
478 break;
479 case CURL_OPPOSITE:
480 tn->him[option] = CURL_WANTNO;
481 tn->himq[option] = CURL_EMPTY;
482 send_negotiation(conn, CURL_DONT, option);
483 break;
484 }
485 break;
486 }
487}
488
489static
490void rec_wont(struct connectdata *conn, int option)
491{
492 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
493 switch(tn->him[option]) {
494 case CURL_NO:
495 /* Already disabled */
496 break;
497
498 case CURL_YES:
499 tn->him[option] = CURL_NO;
500 send_negotiation(conn, CURL_DONT, option);
501 break;
502
503 case CURL_WANTNO:
504 switch(tn->himq[option]) {
505 case CURL_EMPTY:
506 tn->him[option] = CURL_NO;
507 break;
508
509 case CURL_OPPOSITE:
510 tn->him[option] = CURL_WANTYES;
511 tn->himq[option] = CURL_EMPTY;
512 send_negotiation(conn, CURL_DO, option);
513 break;
514 }
515 break;
516
517 case CURL_WANTYES:
518 switch(tn->himq[option]) {
519 case CURL_EMPTY:
520 tn->him[option] = CURL_NO;
521 break;
522 case CURL_OPPOSITE:
523 tn->him[option] = CURL_NO;
524 tn->himq[option] = CURL_EMPTY;
525 break;
526 }
527 break;
528 }
529}
530
531static void
532set_local_option(struct connectdata *conn, int option, int newstate)
533{
534 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
535 if(newstate == CURL_YES) {
536 switch(tn->us[option]) {
Kristian Monsen5ab50182010-05-14 18:53:44 +0100537 case CURL_NO:
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700538 tn->us[option] = CURL_WANTYES;
539 send_negotiation(conn, CURL_WILL, option);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100540 break;
541
542 case CURL_YES:
543 /* Already enabled */
544 break;
545
546 case CURL_WANTNO:
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700547 switch(tn->usq[option]) {
548 case CURL_EMPTY:
549 /* Already negotiating for CURL_YES, queue the request */
550 tn->usq[option] = CURL_OPPOSITE;
551 break;
552 case CURL_OPPOSITE:
553 /* Error: already queued an enable request */
554 break;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100555 }
556 break;
557
558 case CURL_WANTYES:
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700559 switch(tn->usq[option]) {
560 case CURL_EMPTY:
561 /* Error: already negotiating for enable */
562 break;
563 case CURL_OPPOSITE:
564 tn->usq[option] = CURL_EMPTY;
565 break;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100566 }
567 break;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700568 }
Kristian Monsen5ab50182010-05-14 18:53:44 +0100569 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700570 else { /* NO */
571 switch(tn->us[option]) {
Kristian Monsen5ab50182010-05-14 18:53:44 +0100572 case CURL_NO:
573 /* Already disabled */
574 break;
575
576 case CURL_YES:
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700577 tn->us[option] = CURL_WANTNO;
578 send_negotiation(conn, CURL_WONT, option);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100579 break;
580
581 case CURL_WANTNO:
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700582 switch(tn->usq[option]) {
583 case CURL_EMPTY:
584 /* Already negotiating for NO */
585 break;
586 case CURL_OPPOSITE:
587 tn->usq[option] = CURL_EMPTY;
588 break;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100589 }
590 break;
591
592 case CURL_WANTYES:
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700593 switch(tn->usq[option]) {
594 case CURL_EMPTY:
595 tn->usq[option] = CURL_OPPOSITE;
596 break;
597 case CURL_OPPOSITE:
598 break;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100599 }
600 break;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100601 }
602 }
603}
604
605static
606void rec_do(struct connectdata *conn, int option)
607{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700608 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
609 switch(tn->us[option]) {
610 case CURL_NO:
611 if(tn->us_preferred[option] == CURL_YES) {
612 tn->us[option] = CURL_YES;
613 send_negotiation(conn, CURL_WILL, option);
614 if(tn->subnegotiation[option] == CURL_YES)
615 /* transmission of data option */
616 sendsuboption(conn, option);
617 }
618 else if(tn->subnegotiation[option] == CURL_YES) {
619 /* send information to achieve this option*/
620 tn->us[option] = CURL_YES;
621 send_negotiation(conn, CURL_WILL, option);
622 sendsuboption(conn, option);
623 }
624 else
625 send_negotiation(conn, CURL_WONT, option);
626 break;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100627
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700628 case CURL_YES:
629 /* Already enabled */
630 break;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100631
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700632 case CURL_WANTNO:
633 switch(tn->usq[option]) {
634 case CURL_EMPTY:
635 /* Error: DONT answered by WILL */
636 tn->us[option] = CURL_NO;
637 break;
638 case CURL_OPPOSITE:
639 /* Error: DONT answered by WILL */
640 tn->us[option] = CURL_YES;
641 tn->usq[option] = CURL_EMPTY;
642 break;
643 }
644 break;
645
646 case CURL_WANTYES:
647 switch(tn->usq[option]) {
648 case CURL_EMPTY:
649 tn->us[option] = CURL_YES;
650 if(tn->subnegotiation[option] == CURL_YES) {
651 /* transmission of data option */
652 sendsuboption(conn, option);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100653 }
654 break;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700655 case CURL_OPPOSITE:
656 tn->us[option] = CURL_WANTNO;
657 tn->himq[option] = CURL_EMPTY;
658 send_negotiation(conn, CURL_WONT, option);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100659 break;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700660 }
661 break;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100662 }
663}
664
665static
666void rec_dont(struct connectdata *conn, int option)
667{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700668 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
669 switch(tn->us[option]) {
670 case CURL_NO:
671 /* Already disabled */
672 break;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100673
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700674 case CURL_YES:
675 tn->us[option] = CURL_NO;
676 send_negotiation(conn, CURL_WONT, option);
677 break;
678
679 case CURL_WANTNO:
680 switch(tn->usq[option]) {
681 case CURL_EMPTY:
Kristian Monsen5ab50182010-05-14 18:53:44 +0100682 tn->us[option] = CURL_NO;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100683 break;
684
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700685 case CURL_OPPOSITE:
686 tn->us[option] = CURL_WANTYES;
687 tn->usq[option] = CURL_EMPTY;
688 send_negotiation(conn, CURL_WILL, option);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100689 break;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700690 }
691 break;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100692
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700693 case CURL_WANTYES:
694 switch(tn->usq[option]) {
695 case CURL_EMPTY:
696 tn->us[option] = CURL_NO;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100697 break;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700698 case CURL_OPPOSITE:
699 tn->us[option] = CURL_NO;
700 tn->usq[option] = CURL_EMPTY;
701 break;
702 }
703 break;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100704 }
705}
706
707
Alex Deymoe3149cc2016-10-05 11:18:42 -0700708static void printsub(struct Curl_easy *data,
Kristian Monsen5ab50182010-05-14 18:53:44 +0100709 int direction, /* '<' or '>' */
710 unsigned char *pointer, /* where suboption data is */
711 size_t length) /* length of suboption data */
712{
713 unsigned int i = 0;
714
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700715 if(data->set.verbose) {
716 if(direction) {
Kristian Monsen5ab50182010-05-14 18:53:44 +0100717 infof(data, "%s IAC SB ", (direction == '<')? "RCVD":"SENT");
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700718 if(length >= 3) {
Kristian Monsen5ab50182010-05-14 18:53:44 +0100719 int j;
720
721 i = pointer[length-2];
722 j = pointer[length-1];
723
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700724 if(i != CURL_IAC || j != CURL_SE) {
Kristian Monsen5ab50182010-05-14 18:53:44 +0100725 infof(data, "(terminated by ");
726 if(CURL_TELOPT_OK(i))
727 infof(data, "%s ", CURL_TELOPT(i));
728 else if(CURL_TELCMD_OK(i))
729 infof(data, "%s ", CURL_TELCMD(i));
730 else
731 infof(data, "%u ", i);
732 if(CURL_TELOPT_OK(j))
733 infof(data, "%s", CURL_TELOPT(j));
734 else if(CURL_TELCMD_OK(j))
735 infof(data, "%s", CURL_TELCMD(j));
736 else
737 infof(data, "%d", j);
738 infof(data, ", not IAC SE!) ");
739 }
740 }
741 length -= 2;
742 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700743 if(length < 1) {
Kristian Monsen5ab50182010-05-14 18:53:44 +0100744 infof(data, "(Empty suboption?)");
745 return;
746 }
747
748 if(CURL_TELOPT_OK(pointer[0])) {
749 switch(pointer[0]) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700750 case CURL_TELOPT_TTYPE:
751 case CURL_TELOPT_XDISPLOC:
752 case CURL_TELOPT_NEW_ENVIRON:
753 case CURL_TELOPT_NAWS:
754 infof(data, "%s", CURL_TELOPT(pointer[0]));
755 break;
756 default:
757 infof(data, "%s (unsupported)", CURL_TELOPT(pointer[0]));
758 break;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100759 }
760 }
761 else
762 infof(data, "%d (unknown)", pointer[i]);
763
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700764 switch(pointer[0]) {
765 case CURL_TELOPT_NAWS:
766 if(length > 4)
767 infof(data, "Width: %hu ; Height: %hu", (pointer[1]<<8) | pointer[2],
768 (pointer[3]<<8) | pointer[4]);
769 break;
770 default:
771 switch(pointer[1]) {
Kristian Monsen5ab50182010-05-14 18:53:44 +0100772 case CURL_TELQUAL_IS:
773 infof(data, " IS");
774 break;
775 case CURL_TELQUAL_SEND:
776 infof(data, " SEND");
777 break;
778 case CURL_TELQUAL_INFO:
779 infof(data, " INFO/REPLY");
780 break;
781 case CURL_TELQUAL_NAME:
782 infof(data, " NAME");
783 break;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700784 }
Kristian Monsen5ab50182010-05-14 18:53:44 +0100785
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700786 switch(pointer[0]) {
Kristian Monsen5ab50182010-05-14 18:53:44 +0100787 case CURL_TELOPT_TTYPE:
788 case CURL_TELOPT_XDISPLOC:
789 pointer[length] = 0;
790 infof(data, " \"%s\"", &pointer[2]);
791 break;
792 case CURL_TELOPT_NEW_ENVIRON:
793 if(pointer[1] == CURL_TELQUAL_IS) {
794 infof(data, " ");
Alex Deymo486467e2017-12-19 19:04:07 +0100795 for(i = 3; i < length; i++) {
Kristian Monsen5ab50182010-05-14 18:53:44 +0100796 switch(pointer[i]) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700797 case CURL_NEW_ENV_VAR:
798 infof(data, ", ");
799 break;
800 case CURL_NEW_ENV_VALUE:
801 infof(data, " = ");
802 break;
803 default:
804 infof(data, "%c", pointer[i]);
805 break;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100806 }
807 }
808 }
809 break;
810 default:
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700811 for(i = 2; i < length; i++)
Kristian Monsen5ab50182010-05-14 18:53:44 +0100812 infof(data, " %.2x", pointer[i]);
813 break;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700814 }
Kristian Monsen5ab50182010-05-14 18:53:44 +0100815 }
Kristian Monsen5ab50182010-05-14 18:53:44 +0100816 if(direction)
Kristian Monsen5ab50182010-05-14 18:53:44 +0100817 infof(data, "\n");
Kristian Monsen5ab50182010-05-14 18:53:44 +0100818 }
819}
820
821static CURLcode check_telnet_options(struct connectdata *conn)
822{
823 struct curl_slist *head;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700824 struct curl_slist *beg;
825 char option_keyword[128] = "";
826 char option_arg[256] = "";
Alex Deymoe3149cc2016-10-05 11:18:42 -0700827 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700828 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
829 CURLcode result = CURLE_OK;
830 int binary_option;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100831
832 /* Add the user name as an environment variable if it
833 was given on the command line */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700834 if(conn->bits.user_passwd) {
Kristian Monsen5ab50182010-05-14 18:53:44 +0100835 snprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700836 beg = curl_slist_append(tn->telnet_vars, option_arg);
837 if(!beg) {
838 curl_slist_free_all(tn->telnet_vars);
839 tn->telnet_vars = NULL;
840 return CURLE_OUT_OF_MEMORY;
841 }
842 tn->telnet_vars = beg;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100843 tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
844 }
845
Alex Deymo486467e2017-12-19 19:04:07 +0100846 for(head = data->set.telnet_options; head; head = head->next) {
Kristian Monsen5ab50182010-05-14 18:53:44 +0100847 if(sscanf(head->data, "%127[^= ]%*[ =]%255s",
848 option_keyword, option_arg) == 2) {
849
850 /* Terminal type */
Elliott Hughescee03382017-06-23 12:17:18 -0700851 if(strcasecompare(option_keyword, "TTYPE")) {
Kristian Monsen5ab50182010-05-14 18:53:44 +0100852 strncpy(tn->subopt_ttype, option_arg, 31);
853 tn->subopt_ttype[31] = 0; /* String termination */
854 tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES;
855 continue;
856 }
857
858 /* Display variable */
Elliott Hughescee03382017-06-23 12:17:18 -0700859 if(strcasecompare(option_keyword, "XDISPLOC")) {
Kristian Monsen5ab50182010-05-14 18:53:44 +0100860 strncpy(tn->subopt_xdisploc, option_arg, 127);
861 tn->subopt_xdisploc[127] = 0; /* String termination */
862 tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES;
863 continue;
864 }
865
866 /* Environment variable */
Elliott Hughescee03382017-06-23 12:17:18 -0700867 if(strcasecompare(option_keyword, "NEW_ENV")) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700868 beg = curl_slist_append(tn->telnet_vars, option_arg);
869 if(!beg) {
870 result = CURLE_OUT_OF_MEMORY;
871 break;
872 }
873 tn->telnet_vars = beg;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100874 tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
875 continue;
876 }
877
Elliott Hughes82be86d2017-09-20 17:00:17 -0700878 /* Window Size */
Elliott Hughescee03382017-06-23 12:17:18 -0700879 if(strcasecompare(option_keyword, "WS")) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700880 if(sscanf(option_arg, "%hu%*[xX]%hu",
881 &tn->subopt_wsx, &tn->subopt_wsy) == 2)
882 tn->us_preferred[CURL_TELOPT_NAWS] = CURL_YES;
883 else {
884 failf(data, "Syntax error in telnet option: %s", head->data);
885 result = CURLE_TELNET_OPTION_SYNTAX;
886 break;
887 }
888 continue;
889 }
890
891 /* To take care or not of the 8th bit in data exchange */
Elliott Hughescee03382017-06-23 12:17:18 -0700892 if(strcasecompare(option_keyword, "BINARY")) {
Alex Deymo486467e2017-12-19 19:04:07 +0100893 binary_option = atoi(option_arg);
894 if(binary_option != 1) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700895 tn->us_preferred[CURL_TELOPT_BINARY] = CURL_NO;
896 tn->him_preferred[CURL_TELOPT_BINARY] = CURL_NO;
897 }
898 continue;
899 }
900
Kristian Monsen5ab50182010-05-14 18:53:44 +0100901 failf(data, "Unknown telnet option %s", head->data);
Elliott Hughes82be86d2017-09-20 17:00:17 -0700902 result = CURLE_UNKNOWN_OPTION;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700903 break;
904 }
Elliott Hughes82be86d2017-09-20 17:00:17 -0700905 failf(data, "Syntax error in telnet option: %s", head->data);
906 result = CURLE_TELNET_OPTION_SYNTAX;
907 break;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100908 }
909
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700910 if(result) {
911 curl_slist_free_all(tn->telnet_vars);
912 tn->telnet_vars = NULL;
913 }
914
915 return result;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100916}
917
918/*
919 * suboption()
920 *
921 * Look at the sub-option buffer, and try to be helpful to the other
922 * side.
923 */
924
925static void suboption(struct connectdata *conn)
926{
927 struct curl_slist *v;
928 unsigned char temp[2048];
929 ssize_t bytes_written;
930 size_t len;
931 size_t tmplen;
932 int err;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700933 char varname[128] = "";
934 char varval[128] = "";
Alex Deymoe3149cc2016-10-05 11:18:42 -0700935 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700936 struct TELNET *tn = (struct TELNET *)data->req.protop;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100937
Alex Deymo486467e2017-12-19 19:04:07 +0100938 printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn) + 2);
Elliott Hughes82be86d2017-09-20 17:00:17 -0700939 switch(CURL_SB_GET(tn)) {
Kristian Monsen5ab50182010-05-14 18:53:44 +0100940 case CURL_TELOPT_TTYPE:
941 len = strlen(tn->subopt_ttype) + 4 + 2;
942 snprintf((char *)temp, sizeof(temp),
943 "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE,
944 CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE);
945 bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
946 if(bytes_written < 0) {
947 err = SOCKERRNO;
948 failf(data,"Sending data failed (%d)",err);
949 }
950 printsub(data, '>', &temp[2], len-2);
951 break;
952 case CURL_TELOPT_XDISPLOC:
953 len = strlen(tn->subopt_xdisploc) + 4 + 2;
954 snprintf((char *)temp, sizeof(temp),
955 "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC,
956 CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE);
957 bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
958 if(bytes_written < 0) {
959 err = SOCKERRNO;
960 failf(data,"Sending data failed (%d)",err);
961 }
962 printsub(data, '>', &temp[2], len-2);
963 break;
964 case CURL_TELOPT_NEW_ENVIRON:
965 snprintf((char *)temp, sizeof(temp),
966 "%c%c%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON,
967 CURL_TELQUAL_IS);
968 len = 4;
969
Alex Deymo486467e2017-12-19 19:04:07 +0100970 for(v = tn->telnet_vars; v; v = v->next) {
Kristian Monsen5ab50182010-05-14 18:53:44 +0100971 tmplen = (strlen(v->data) + 1);
972 /* Add the variable only if it fits */
973 if(len + tmplen < (int)sizeof(temp)-6) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700974 if(sscanf(v->data, "%127[^,],%127s", varname, varval)) {
975 snprintf((char *)&temp[len], sizeof(temp) - len,
976 "%c%s%c%s", CURL_NEW_ENV_VAR, varname,
977 CURL_NEW_ENV_VALUE, varval);
978 len += tmplen;
979 }
Kristian Monsen5ab50182010-05-14 18:53:44 +0100980 }
981 }
982 snprintf((char *)&temp[len], sizeof(temp) - len,
983 "%c%c", CURL_IAC, CURL_SE);
984 len += 2;
985 bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
986 if(bytes_written < 0) {
987 err = SOCKERRNO;
988 failf(data,"Sending data failed (%d)",err);
989 }
990 printsub(data, '>', &temp[2], len-2);
991 break;
992 }
993 return;
994}
995
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700996
997/*
998 * sendsuboption()
999 *
1000 * Send suboption information to the server side.
1001 */
1002
1003static void sendsuboption(struct connectdata *conn, int option)
1004{
1005 ssize_t bytes_written;
1006 int err;
1007 unsigned short x, y;
Elliott Hughescee03382017-06-23 12:17:18 -07001008 unsigned char *uc1, *uc2;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001009
Alex Deymoe3149cc2016-10-05 11:18:42 -07001010 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001011 struct TELNET *tn = (struct TELNET *)data->req.protop;
1012
Elliott Hughes82be86d2017-09-20 17:00:17 -07001013 switch(option) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001014 case CURL_TELOPT_NAWS:
1015 /* We prepare data to be sent */
1016 CURL_SB_CLEAR(tn);
1017 CURL_SB_ACCUM(tn, CURL_IAC);
1018 CURL_SB_ACCUM(tn, CURL_SB);
1019 CURL_SB_ACCUM(tn, CURL_TELOPT_NAWS);
Elliott Hughes82be86d2017-09-20 17:00:17 -07001020 /* We must deal either with litte or big endian processors */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001021 /* Window size must be sent according to the 'network order' */
Alex Deymo486467e2017-12-19 19:04:07 +01001022 x = htons(tn->subopt_wsx);
1023 y = htons(tn->subopt_wsy);
Elliott Hughescee03382017-06-23 12:17:18 -07001024 uc1 = (unsigned char *)&x;
1025 uc2 = (unsigned char *)&y;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001026 CURL_SB_ACCUM(tn, uc1[0]);
1027 CURL_SB_ACCUM(tn, uc1[1]);
1028 CURL_SB_ACCUM(tn, uc2[0]);
1029 CURL_SB_ACCUM(tn, uc2[1]);
1030
1031 CURL_SB_ACCUM(tn, CURL_IAC);
1032 CURL_SB_ACCUM(tn, CURL_SE);
1033 CURL_SB_TERM(tn);
1034 /* data suboption is now ready */
1035
Alex Deymo486467e2017-12-19 19:04:07 +01001036 printsub(data, '>', (unsigned char *)tn->subbuffer + 2,
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001037 CURL_SB_LEN(tn)-2);
1038
1039 /* we send the header of the suboption... */
1040 bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer, 3);
1041 if(bytes_written < 0) {
1042 err = SOCKERRNO;
1043 failf(data, "Sending data failed (%d)", err);
1044 }
1045 /* ... then the window size with the send_telnet_data() function
1046 to deal with 0xFF cases ... */
Alex Deymo486467e2017-12-19 19:04:07 +01001047 send_telnet_data(conn, (char *)tn->subbuffer + 3, 4);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001048 /* ... and the footer */
Alex Deymo486467e2017-12-19 19:04:07 +01001049 bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer + 7, 2);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001050 if(bytes_written < 0) {
1051 err = SOCKERRNO;
1052 failf(data, "Sending data failed (%d)", err);
1053 }
1054 break;
1055 }
1056}
1057
1058
Kristian Monsen5ab50182010-05-14 18:53:44 +01001059static
1060CURLcode telrcv(struct connectdata *conn,
1061 const unsigned char *inbuf, /* Data received from socket */
1062 ssize_t count) /* Number of bytes received */
1063{
1064 unsigned char c;
1065 CURLcode result;
1066 int in = 0;
Alex Deymo486467e2017-12-19 19:04:07 +01001067 int startwrite = -1;
Alex Deymoe3149cc2016-10-05 11:18:42 -07001068 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001069 struct TELNET *tn = (struct TELNET *)data->req.protop;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001070
Lucas Eckels9bd90e62012-08-06 15:07:02 -07001071#define startskipping() \
1072 if(startwrite >= 0) { \
1073 result = Curl_client_write(conn, \
1074 CLIENTWRITE_BODY, \
1075 (char *)&inbuf[startwrite], \
1076 in-startwrite); \
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001077 if(result) \
Lucas Eckels9bd90e62012-08-06 15:07:02 -07001078 return result; \
1079 } \
1080 startwrite = -1
Kristian Monsen5ab50182010-05-14 18:53:44 +01001081
1082#define writebyte() \
1083 if(startwrite < 0) \
1084 startwrite = in
1085
1086#define bufferflush() startskipping()
1087
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001088 while(count--) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01001089 c = inbuf[in];
1090
Elliott Hughes82be86d2017-09-20 17:00:17 -07001091 switch(tn->telrcv_state) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001092 case CURL_TS_CR:
1093 tn->telrcv_state = CURL_TS_DATA;
1094 if(c == '\0') {
1095 startskipping();
1096 break; /* Ignore \0 after CR */
1097 }
1098 writebyte();
1099 break;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001100
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001101 case CURL_TS_DATA:
1102 if(c == CURL_IAC) {
1103 tn->telrcv_state = CURL_TS_IAC;
1104 startskipping();
Kristian Monsen5ab50182010-05-14 18:53:44 +01001105 break;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001106 }
1107 else if(c == '\r')
1108 tn->telrcv_state = CURL_TS_CR;
1109 writebyte();
1110 break;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001111
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001112 case CURL_TS_IAC:
1113 process_iac:
Kristian Monsen5ab50182010-05-14 18:53:44 +01001114 DEBUGASSERT(startwrite < 0);
Elliott Hughes82be86d2017-09-20 17:00:17 -07001115 switch(c) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001116 case CURL_WILL:
1117 tn->telrcv_state = CURL_TS_WILL;
1118 break;
1119 case CURL_WONT:
1120 tn->telrcv_state = CURL_TS_WONT;
1121 break;
1122 case CURL_DO:
1123 tn->telrcv_state = CURL_TS_DO;
1124 break;
1125 case CURL_DONT:
1126 tn->telrcv_state = CURL_TS_DONT;
1127 break;
1128 case CURL_SB:
1129 CURL_SB_CLEAR(tn);
1130 tn->telrcv_state = CURL_TS_SB;
1131 break;
1132 case CURL_IAC:
1133 tn->telrcv_state = CURL_TS_DATA;
1134 writebyte();
1135 break;
1136 case CURL_DM:
1137 case CURL_NOP:
1138 case CURL_GA:
1139 default:
1140 tn->telrcv_state = CURL_TS_DATA;
1141 printoption(data, "RCVD", CURL_IAC, c);
1142 break;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001143 }
1144 break;
1145
1146 case CURL_TS_WILL:
1147 printoption(data, "RCVD", CURL_WILL, c);
1148 tn->please_negotiate = 1;
1149 rec_will(conn, c);
1150 tn->telrcv_state = CURL_TS_DATA;
1151 break;
1152
1153 case CURL_TS_WONT:
1154 printoption(data, "RCVD", CURL_WONT, c);
1155 tn->please_negotiate = 1;
1156 rec_wont(conn, c);
1157 tn->telrcv_state = CURL_TS_DATA;
1158 break;
1159
1160 case CURL_TS_DO:
1161 printoption(data, "RCVD", CURL_DO, c);
1162 tn->please_negotiate = 1;
1163 rec_do(conn, c);
1164 tn->telrcv_state = CURL_TS_DATA;
1165 break;
1166
1167 case CURL_TS_DONT:
1168 printoption(data, "RCVD", CURL_DONT, c);
1169 tn->please_negotiate = 1;
1170 rec_dont(conn, c);
1171 tn->telrcv_state = CURL_TS_DATA;
1172 break;
1173
1174 case CURL_TS_SB:
1175 if(c == CURL_IAC)
Kristian Monsen5ab50182010-05-14 18:53:44 +01001176 tn->telrcv_state = CURL_TS_SE;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001177 else
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001178 CURL_SB_ACCUM(tn, c);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001179 break;
1180
1181 case CURL_TS_SE:
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001182 if(c != CURL_SE) {
1183 if(c != CURL_IAC) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01001184 /*
1185 * This is an error. We only expect to get "IAC IAC" or "IAC SE".
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001186 * Several things may have happened. An IAC was not doubled, the
Kristian Monsen5ab50182010-05-14 18:53:44 +01001187 * IAC SE was left off, or another option got inserted into the
1188 * suboption are all possibilities. If we assume that the IAC was
1189 * not doubled, and really the IAC SE was left off, we could get
Elliott Hughes82be86d2017-09-20 17:00:17 -07001190 * into an infinite loop here. So, instead, we terminate the
Kristian Monsen5ab50182010-05-14 18:53:44 +01001191 * suboption, and process the partial suboption if we can.
1192 */
1193 CURL_SB_ACCUM(tn, CURL_IAC);
1194 CURL_SB_ACCUM(tn, c);
1195 tn->subpointer -= 2;
1196 CURL_SB_TERM(tn);
1197
1198 printoption(data, "In SUBOPTION processing, RCVD", CURL_IAC, c);
1199 suboption(conn); /* handle sub-option */
1200 tn->telrcv_state = CURL_TS_IAC;
1201 goto process_iac;
1202 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001203 CURL_SB_ACCUM(tn, c);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001204 tn->telrcv_state = CURL_TS_SB;
1205 }
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07001206 else {
Kristian Monsen5ab50182010-05-14 18:53:44 +01001207 CURL_SB_ACCUM(tn, CURL_IAC);
1208 CURL_SB_ACCUM(tn, CURL_SE);
1209 tn->subpointer -= 2;
1210 CURL_SB_TERM(tn);
1211 suboption(conn); /* handle sub-option */
1212 tn->telrcv_state = CURL_TS_DATA;
1213 }
1214 break;
1215 }
1216 ++in;
1217 }
1218 bufferflush();
1219 return CURLE_OK;
1220}
1221
1222/* Escape and send a telnet data block */
Kristian Monsen5ab50182010-05-14 18:53:44 +01001223static CURLcode send_telnet_data(struct connectdata *conn,
1224 char *buffer, ssize_t nread)
1225{
Elliott Hughes82be86d2017-09-20 17:00:17 -07001226 ssize_t escapes, i, j, outlen;
1227 unsigned char *outbuf = NULL;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001228 CURLcode result = CURLE_OK;
Elliott Hughes82be86d2017-09-20 17:00:17 -07001229 ssize_t bytes_written, total_written;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001230
Elliott Hughes82be86d2017-09-20 17:00:17 -07001231 /* Determine size of new buffer after escaping */
1232 escapes = 0;
1233 for(i = 0; i < nread; i++)
1234 if((unsigned char)buffer[i] == CURL_IAC)
1235 escapes++;
1236 outlen = nread + escapes;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001237
Elliott Hughes82be86d2017-09-20 17:00:17 -07001238 if(outlen == nread)
1239 outbuf = (unsigned char *)buffer;
1240 else {
1241 outbuf = malloc(nread + escapes + 1);
1242 if(!outbuf)
1243 return CURLE_OUT_OF_MEMORY;
1244
1245 j = 0;
1246 for(i = 0; i < nread; i++) {
1247 outbuf[j++] = buffer[i];
1248 if((unsigned char)buffer[i] == CURL_IAC)
1249 outbuf[j++] = CURL_IAC;
1250 }
1251 outbuf[j] = '\0';
Kristian Monsen5ab50182010-05-14 18:53:44 +01001252 }
Elliott Hughes82be86d2017-09-20 17:00:17 -07001253
1254 total_written = 0;
1255 while(!result && total_written < outlen) {
1256 /* Make sure socket is writable to avoid EWOULDBLOCK condition */
1257 struct pollfd pfd[1];
1258 pfd[0].fd = conn->sock[FIRSTSOCKET];
1259 pfd[0].events = POLLOUT;
1260 switch(Curl_poll(pfd, 1, -1)) {
1261 case -1: /* error, abort writing */
1262 case 0: /* timeout (will never happen) */
1263 result = CURLE_SEND_ERROR;
1264 break;
1265 default: /* write! */
1266 bytes_written = 0;
1267 result = Curl_write(conn, conn->sock[FIRSTSOCKET],
1268 outbuf + total_written,
1269 outlen - total_written,
1270 &bytes_written);
1271 total_written += bytes_written;
1272 break;
1273 }
1274 }
1275
1276 /* Free malloc copy if escaped */
1277 if(outbuf != (unsigned char *)buffer)
1278 free(outbuf);
1279
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001280 return result;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001281}
1282
1283static CURLcode telnet_done(struct connectdata *conn,
1284 CURLcode status, bool premature)
1285{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001286 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001287 (void)status; /* unused */
1288 (void)premature; /* not used */
1289
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001290 if(!tn)
1291 return CURLE_OK;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001292
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001293 curl_slist_free_all(tn->telnet_vars);
1294 tn->telnet_vars = NULL;
1295
1296 Curl_safefree(conn->data->req.protop);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001297
1298 return CURLE_OK;
1299}
1300
1301static CURLcode telnet_do(struct connectdata *conn, bool *done)
1302{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001303 CURLcode result;
Alex Deymoe3149cc2016-10-05 11:18:42 -07001304 struct Curl_easy *data = conn->data;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001305 curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
1306#ifdef USE_WINSOCK
1307 HMODULE wsock2;
1308 WSOCK2_FUNC close_event_func;
1309 WSOCK2_FUNC create_event_func;
1310 WSOCK2_FUNC event_select_func;
1311 WSOCK2_FUNC enum_netevents_func;
1312 WSAEVENT event_handle;
1313 WSANETWORKEVENTS events;
1314 HANDLE stdin_handle;
1315 HANDLE objs[2];
1316 DWORD obj_count;
1317 DWORD wait_timeout;
1318 DWORD waitret;
1319 DWORD readfile_read;
1320 int err;
1321#else
1322 int interval_ms;
1323 struct pollfd pfd[2];
Lucas Eckels9bd90e62012-08-06 15:07:02 -07001324 int poll_cnt;
1325 curl_off_t total_dl = 0;
1326 curl_off_t total_ul = 0;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001327#endif
Kristian Monsen5ab50182010-05-14 18:53:44 +01001328 ssize_t nread;
Elliott Hughes82be86d2017-09-20 17:00:17 -07001329 struct curltime now;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001330 bool keepon = TRUE;
1331 char *buf = data->state.buffer;
1332 struct TELNET *tn;
1333
1334 *done = TRUE; /* unconditionally */
1335
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001336 result = init_telnet(conn);
1337 if(result)
1338 return result;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001339
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001340 tn = (struct TELNET *)data->req.protop;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001341
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001342 result = check_telnet_options(conn);
1343 if(result)
1344 return result;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001345
1346#ifdef USE_WINSOCK
1347 /*
1348 ** This functionality only works with WinSock >= 2.0. So,
Elliott Hughes82be86d2017-09-20 17:00:17 -07001349 ** make sure we have it.
Kristian Monsen5ab50182010-05-14 18:53:44 +01001350 */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001351 result = check_wsock2(data);
1352 if(result)
1353 return result;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001354
1355 /* OK, so we have WinSock 2.0. We need to dynamically */
1356 /* load ws2_32.dll and get the function pointers we need. */
Alex Deymod15eaac2016-06-28 14:49:26 -07001357 wsock2 = Curl_load_library(TEXT("WS2_32.DLL"));
Kristian Monsen5ab50182010-05-14 18:53:44 +01001358 if(wsock2 == NULL) {
Elliott Hughes82be86d2017-09-20 17:00:17 -07001359 failf(data, "failed to load WS2_32.DLL (%u)", GetLastError());
Kristian Monsen5ab50182010-05-14 18:53:44 +01001360 return CURLE_FAILED_INIT;
1361 }
1362
1363 /* Grab a pointer to WSACreateEvent */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001364 create_event_func = GetProcAddress(wsock2, "WSACreateEvent");
Kristian Monsen5ab50182010-05-14 18:53:44 +01001365 if(create_event_func == NULL) {
Elliott Hughes82be86d2017-09-20 17:00:17 -07001366 failf(data, "failed to find WSACreateEvent function (%u)", GetLastError());
Kristian Monsen5ab50182010-05-14 18:53:44 +01001367 FreeLibrary(wsock2);
1368 return CURLE_FAILED_INIT;
1369 }
1370
1371 /* And WSACloseEvent */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001372 close_event_func = GetProcAddress(wsock2, "WSACloseEvent");
Kristian Monsen5ab50182010-05-14 18:53:44 +01001373 if(close_event_func == NULL) {
Elliott Hughes82be86d2017-09-20 17:00:17 -07001374 failf(data, "failed to find WSACloseEvent function (%u)", GetLastError());
Kristian Monsen5ab50182010-05-14 18:53:44 +01001375 FreeLibrary(wsock2);
1376 return CURLE_FAILED_INIT;
1377 }
1378
1379 /* And WSAEventSelect */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001380 event_select_func = GetProcAddress(wsock2, "WSAEventSelect");
Kristian Monsen5ab50182010-05-14 18:53:44 +01001381 if(event_select_func == NULL) {
Elliott Hughes82be86d2017-09-20 17:00:17 -07001382 failf(data, "failed to find WSAEventSelect function (%u)", GetLastError());
Kristian Monsen5ab50182010-05-14 18:53:44 +01001383 FreeLibrary(wsock2);
1384 return CURLE_FAILED_INIT;
1385 }
1386
1387 /* And WSAEnumNetworkEvents */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001388 enum_netevents_func = GetProcAddress(wsock2, "WSAEnumNetworkEvents");
Kristian Monsen5ab50182010-05-14 18:53:44 +01001389 if(enum_netevents_func == NULL) {
Elliott Hughes82be86d2017-09-20 17:00:17 -07001390 failf(data, "failed to find WSAEnumNetworkEvents function (%u)",
1391 GetLastError());
Kristian Monsen5ab50182010-05-14 18:53:44 +01001392 FreeLibrary(wsock2);
1393 return CURLE_FAILED_INIT;
1394 }
1395
1396 /* We want to wait for both stdin and the socket. Since
1397 ** the select() function in winsock only works on sockets
1398 ** we have to use the WaitForMultipleObjects() call.
1399 */
1400
1401 /* First, create a sockets event object */
1402 event_handle = (WSAEVENT)create_event_func();
1403 if(event_handle == WSA_INVALID_EVENT) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001404 failf(data, "WSACreateEvent failed (%d)", SOCKERRNO);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001405 FreeLibrary(wsock2);
1406 return CURLE_FAILED_INIT;
1407 }
1408
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001409 /* Tell winsock what events we want to listen to */
1410 if(event_select_func(sockfd, event_handle, FD_READ|FD_CLOSE) ==
1411 SOCKET_ERROR) {
1412 close_event_func(event_handle);
1413 FreeLibrary(wsock2);
1414 return CURLE_OK;
1415 }
1416
Kristian Monsen5ab50182010-05-14 18:53:44 +01001417 /* The get the Windows file handle for stdin */
1418 stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
1419
1420 /* Create the list of objects to wait for */
1421 objs[0] = event_handle;
1422 objs[1] = stdin_handle;
1423
Kristian Monsen5ab50182010-05-14 18:53:44 +01001424 /* If stdin_handle is a pipe, use PeekNamedPipe() method to check it,
1425 else use the old WaitForMultipleObjects() way */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001426 if(GetFileType(stdin_handle) == FILE_TYPE_PIPE ||
1427 data->set.is_fread_set) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01001428 /* Don't wait for stdin_handle, just wait for event_handle */
1429 obj_count = 1;
1430 /* Check stdin_handle per 100 milliseconds */
1431 wait_timeout = 100;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001432 }
1433 else {
Kristian Monsen5ab50182010-05-14 18:53:44 +01001434 obj_count = 2;
1435 wait_timeout = 1000;
1436 }
1437
1438 /* Keep on listening and act on events */
1439 while(keepon) {
Elliott Hughes82be86d2017-09-20 17:00:17 -07001440 const DWORD buf_size = (DWORD)data->set.buffer_size;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001441 waitret = WaitForMultipleObjects(obj_count, objs, FALSE, wait_timeout);
1442 switch(waitret) {
1443 case WAIT_TIMEOUT:
1444 {
1445 for(;;) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001446 if(data->set.is_fread_set) {
Elliott Hughes82be86d2017-09-20 17:00:17 -07001447 size_t n;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001448 /* read from user-supplied method */
Elliott Hughes82be86d2017-09-20 17:00:17 -07001449 n = data->state.fread_func(buf, 1, buf_size, data->state.in);
1450 if(n == CURL_READFUNC_ABORT) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001451 keepon = FALSE;
1452 result = CURLE_READ_ERROR;
1453 break;
1454 }
1455
Elliott Hughes82be86d2017-09-20 17:00:17 -07001456 if(n == CURL_READFUNC_PAUSE)
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001457 break;
1458
Elliott Hughes82be86d2017-09-20 17:00:17 -07001459 if(n == 0) /* no bytes */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001460 break;
1461
Elliott Hughescac39802018-04-27 16:19:43 -07001462 /* fall through with number of bytes read */
1463 readfile_read = (DWORD)n;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001464 }
1465 else {
1466 /* read from stdin */
1467 if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL,
1468 &readfile_read, NULL)) {
1469 keepon = FALSE;
1470 result = CURLE_READ_ERROR;
1471 break;
1472 }
1473
1474 if(!readfile_read)
1475 break;
1476
Elliott Hughes82be86d2017-09-20 17:00:17 -07001477 if(!ReadFile(stdin_handle, buf, buf_size,
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001478 &readfile_read, NULL)) {
1479 keepon = FALSE;
1480 result = CURLE_READ_ERROR;
1481 break;
1482 }
Kristian Monsen5ab50182010-05-14 18:53:44 +01001483 }
1484
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001485 result = send_telnet_data(conn, buf, readfile_read);
1486 if(result) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01001487 keepon = FALSE;
1488 break;
1489 }
1490 }
1491 }
1492 break;
1493
1494 case WAIT_OBJECT_0 + 1:
1495 {
Elliott Hughes82be86d2017-09-20 17:00:17 -07001496 if(!ReadFile(stdin_handle, buf, buf_size,
Kristian Monsen5ab50182010-05-14 18:53:44 +01001497 &readfile_read, NULL)) {
1498 keepon = FALSE;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001499 result = CURLE_READ_ERROR;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001500 break;
1501 }
1502
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001503 result = send_telnet_data(conn, buf, readfile_read);
1504 if(result) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01001505 keepon = FALSE;
1506 break;
1507 }
1508 }
1509 break;
1510
1511 case WAIT_OBJECT_0:
1512
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001513 events.lNetworkEvents = 0;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001514 if(SOCKET_ERROR == enum_netevents_func(sockfd, event_handle, &events)) {
Elliott Hughes82be86d2017-09-20 17:00:17 -07001515 err = SOCKERRNO;
1516 if(err != EINPROGRESS) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001517 infof(data, "WSAEnumNetworkEvents failed (%d)", err);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001518 keepon = FALSE;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001519 result = CURLE_READ_ERROR;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001520 }
1521 break;
1522 }
1523 if(events.lNetworkEvents & FD_READ) {
1524 /* read data from network */
Elliott Hughes82be86d2017-09-20 17:00:17 -07001525 result = Curl_read(conn, sockfd, buf, data->set.buffer_size, &nread);
Lucas Eckels9bd90e62012-08-06 15:07:02 -07001526 /* read would've blocked. Loop again */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001527 if(result == CURLE_AGAIN)
Kristian Monsen5ab50182010-05-14 18:53:44 +01001528 break;
1529 /* returned not-zero, this an error */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001530 else if(result) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01001531 keepon = FALSE;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001532 break;
1533 }
1534 /* returned zero but actually received 0 or less here,
1535 the server closed the connection and we bail out */
1536 else if(nread <= 0) {
1537 keepon = FALSE;
1538 break;
1539 }
1540
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001541 result = telrcv(conn, (unsigned char *) buf, nread);
1542 if(result) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01001543 keepon = FALSE;
1544 break;
1545 }
1546
Kristian Monsen5ab50182010-05-14 18:53:44 +01001547 /* Negotiate if the peer has started negotiating,
1548 otherwise don't. We don't want to speak telnet with
1549 non-telnet servers, like POP or SMTP. */
1550 if(tn->please_negotiate && !tn->already_negotiated) {
1551 negotiate(conn);
1552 tn->already_negotiated = 1;
1553 }
1554 }
1555 if(events.lNetworkEvents & FD_CLOSE) {
1556 keepon = FALSE;
1557 }
1558 break;
1559
1560 }
1561
1562 if(data->set.timeout) {
Alex Deymo486467e2017-12-19 19:04:07 +01001563 now = Curl_now();
1564 if(Curl_timediff(now, conn->created) >= data->set.timeout) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01001565 failf(data, "Time-out");
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001566 result = CURLE_OPERATION_TIMEDOUT;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001567 keepon = FALSE;
1568 }
1569 }
1570 }
1571
1572 /* We called WSACreateEvent, so call WSACloseEvent */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001573 if(!close_event_func(event_handle)) {
1574 infof(data, "WSACloseEvent failed (%d)", SOCKERRNO);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001575 }
1576
1577 /* "Forget" pointers into the library we're about to free */
1578 create_event_func = NULL;
1579 close_event_func = NULL;
1580 event_select_func = NULL;
1581 enum_netevents_func = NULL;
1582
1583 /* We called LoadLibrary, so call FreeLibrary */
1584 if(!FreeLibrary(wsock2))
Elliott Hughes82be86d2017-09-20 17:00:17 -07001585 infof(data, "FreeLibrary(wsock2) failed (%u)", GetLastError());
Kristian Monsen5ab50182010-05-14 18:53:44 +01001586#else
1587 pfd[0].fd = sockfd;
1588 pfd[0].events = POLLIN;
Lucas Eckels9bd90e62012-08-06 15:07:02 -07001589
Alex Deymod15eaac2016-06-28 14:49:26 -07001590 if(data->set.is_fread_set) {
Lucas Eckels9bd90e62012-08-06 15:07:02 -07001591 poll_cnt = 1;
1592 interval_ms = 100; /* poll user-supplied read function */
1593 }
1594 else {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001595 /* really using fread, so infile is a FILE* */
Alex Deymod15eaac2016-06-28 14:49:26 -07001596 pfd[1].fd = fileno((FILE *)data->state.in);
Lucas Eckels9bd90e62012-08-06 15:07:02 -07001597 pfd[1].events = POLLIN;
1598 poll_cnt = 2;
1599 interval_ms = 1 * 1000;
1600 }
Kristian Monsen5ab50182010-05-14 18:53:44 +01001601
1602 while(keepon) {
Elliott Hughes82be86d2017-09-20 17:00:17 -07001603 switch(Curl_poll(pfd, poll_cnt, interval_ms)) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01001604 case -1: /* error, stop reading */
1605 keepon = FALSE;
1606 continue;
1607 case 0: /* timeout */
Lucas Eckels9bd90e62012-08-06 15:07:02 -07001608 pfd[0].revents = 0;
1609 pfd[1].revents = 0;
1610 /* fall through */
Kristian Monsen5ab50182010-05-14 18:53:44 +01001611 default: /* read! */
Kristian Monsen5ab50182010-05-14 18:53:44 +01001612 if(pfd[0].revents & POLLIN) {
1613 /* read data from network */
Elliott Hughes82be86d2017-09-20 17:00:17 -07001614 result = Curl_read(conn, sockfd, buf, data->set.buffer_size, &nread);
Lucas Eckels9bd90e62012-08-06 15:07:02 -07001615 /* read would've blocked. Loop again */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001616 if(result == CURLE_AGAIN)
Kristian Monsen5ab50182010-05-14 18:53:44 +01001617 break;
1618 /* returned not-zero, this an error */
Elliott Hughes82be86d2017-09-20 17:00:17 -07001619 if(result) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01001620 keepon = FALSE;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001621 break;
1622 }
1623 /* returned zero but actually received 0 or less here,
1624 the server closed the connection and we bail out */
1625 else if(nread <= 0) {
1626 keepon = FALSE;
1627 break;
1628 }
1629
Lucas Eckels9bd90e62012-08-06 15:07:02 -07001630 total_dl += nread;
1631 Curl_pgrsSetDownloadCounter(data, total_dl);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001632 result = telrcv(conn, (unsigned char *)buf, nread);
1633 if(result) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01001634 keepon = FALSE;
1635 break;
1636 }
1637
1638 /* Negotiate if the peer has started negotiating,
1639 otherwise don't. We don't want to speak telnet with
1640 non-telnet servers, like POP or SMTP. */
1641 if(tn->please_negotiate && !tn->already_negotiated) {
1642 negotiate(conn);
1643 tn->already_negotiated = 1;
1644 }
1645 }
Lucas Eckels9bd90e62012-08-06 15:07:02 -07001646
1647 nread = 0;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001648 if(poll_cnt == 2) {
1649 if(pfd[1].revents & POLLIN) { /* read from in file */
Elliott Hughes82be86d2017-09-20 17:00:17 -07001650 nread = read(pfd[1].fd, buf, data->set.buffer_size);
Lucas Eckels9bd90e62012-08-06 15:07:02 -07001651 }
1652 }
1653 else {
1654 /* read from user-supplied method */
Elliott Hughes82be86d2017-09-20 17:00:17 -07001655 nread = (int)data->state.fread_func(buf, 1, data->set.buffer_size,
Alex Deymod15eaac2016-06-28 14:49:26 -07001656 data->state.in);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001657 if(nread == CURL_READFUNC_ABORT) {
Lucas Eckels9bd90e62012-08-06 15:07:02 -07001658 keepon = FALSE;
1659 break;
1660 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001661 if(nread == CURL_READFUNC_PAUSE)
Lucas Eckels9bd90e62012-08-06 15:07:02 -07001662 break;
1663 }
1664
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001665 if(nread > 0) {
1666 result = send_telnet_data(conn, buf, nread);
1667 if(result) {
Lucas Eckels9bd90e62012-08-06 15:07:02 -07001668 keepon = FALSE;
1669 break;
1670 }
1671 total_ul += nread;
1672 Curl_pgrsSetUploadCounter(data, total_ul);
1673 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001674 else if(nread < 0)
Lucas Eckels9bd90e62012-08-06 15:07:02 -07001675 keepon = FALSE;
1676
1677 break;
1678 } /* poll switch statement */
1679
Kristian Monsen5ab50182010-05-14 18:53:44 +01001680 if(data->set.timeout) {
Alex Deymo486467e2017-12-19 19:04:07 +01001681 now = Curl_now();
1682 if(Curl_timediff(now, conn->created) >= data->set.timeout) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01001683 failf(data, "Time-out");
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001684 result = CURLE_OPERATION_TIMEDOUT;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001685 keepon = FALSE;
1686 }
1687 }
Lucas Eckels9bd90e62012-08-06 15:07:02 -07001688
1689 if(Curl_pgrsUpdate(conn)) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001690 result = CURLE_ABORTED_BY_CALLBACK;
1691 break;
Lucas Eckels9bd90e62012-08-06 15:07:02 -07001692 }
Kristian Monsen5ab50182010-05-14 18:53:44 +01001693 }
1694#endif
1695 /* mark this as "no further transfer wanted" */
1696 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1697
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001698 return result;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001699}
1700#endif