1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.haxx.se/docs/copyright.html.
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.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ***************************************************************************/
23 #include "curl_setup.h"
25 #ifndef CURL_DISABLE_TELNET
27 #ifdef HAVE_NETINET_IN_H
28 #include <netinet/in.h>
33 #ifdef HAVE_ARPA_INET_H
34 #include <arpa/inet.h>
39 #ifdef HAVE_SYS_IOCTL_H
40 #include <sys/ioctl.h>
43 #ifdef HAVE_SYS_PARAM_H
44 #include <sys/param.h>
48 #include <curl/curl.h>
54 #include "system_win32.h"
59 #include "arpa_telnet.h"
64 /* The last 3 #include files should be in this order */
65 #include "curl_printf.h"
66 #include "curl_memory.h"
69 #define SUBBUFSIZE 512
71 #define CURL_SB_CLEAR(x) x->subpointer = x->subbuffer
72 #define CURL_SB_TERM(x) \
74 x->subend = x->subpointer; \
77 #define CURL_SB_ACCUM(x,c) \
79 if(x->subpointer < (x->subbuffer + sizeof x->subbuffer)) \
80 *x->subpointer++ = (c); \
83 #define CURL_SB_GET(x) ((*x->subpointer++)&0xff)
84 #define CURL_SB_LEN(x) (x->subend - x->subpointer)
87 #define CURL_SB_PEEK(x) ((*x->subpointer)&0xff)
88 #define CURL_SB_EOF(x) (x->subpointer >= x->subend) */
90 #ifdef CURL_DISABLE_VERBOSE_STRINGS
91 #define printoption(a,b,c,d) Curl_nop_stmt
95 typedef FARPROC WSOCK2_FUNC;
96 static CURLcode check_wsock2(struct Curl_easy *data);
100 CURLcode telrcv(struct connectdata *,
101 const unsigned char *inbuf, /* Data received from socket */
102 ssize_t count); /* Number of bytes received */
104 #ifndef CURL_DISABLE_VERBOSE_STRINGS
105 static void printoption(struct Curl_easy *data,
106 const char *direction,
107 int cmd, int option);
110 static void negotiate(struct connectdata *);
111 static void send_negotiation(struct connectdata *, int cmd, int option);
112 static void set_local_option(struct connectdata *, int cmd, int option);
113 static void set_remote_option(struct connectdata *, int cmd, int option);
115 static void printsub(struct Curl_easy *data,
116 int direction, unsigned char *pointer,
118 static void suboption(struct connectdata *);
119 static void sendsuboption(struct connectdata *conn, int option);
121 static CURLcode telnet_do(struct connectdata *conn, bool *done);
122 static CURLcode telnet_done(struct connectdata *conn,
123 CURLcode, bool premature);
124 static CURLcode send_telnet_data(struct connectdata *conn,
125 char *buffer, ssize_t nread);
127 /* For negotiation compliant to RFC 1143 */
130 #define CURL_WANTYES 2
131 #define CURL_WANTNO 3
134 #define CURL_OPPOSITE 1
137 * Telnet receiver states for fsm
148 CURL_TS_SB, /* sub-option collection */
149 CURL_TS_SE /* looking for sub-option end */
153 int please_negotiate;
154 int already_negotiated;
157 int us_preferred[256];
160 int him_preferred[256];
161 int subnegotiation[256];
162 char subopt_ttype[32]; /* Set with suboption TTYPE */
163 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 */
169 unsigned char subbuffer[SUBBUFSIZE];
170 unsigned char *subpointer, *subend; /* buffer for sub-options */
172 TelnetReceive telrcv_state;
177 * TELNET protocol handler.
180 const 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 */
191 ZERO_NULL, /* domore_getsock */
192 ZERO_NULL, /* perform_getsock */
193 ZERO_NULL, /* disconnect */
194 ZERO_NULL, /* readwrite */
195 ZERO_NULL, /* connection_check */
196 PORT_TELNET, /* defport */
197 CURLPROTO_TELNET, /* protocol */
198 PROTOPT_NONE | PROTOPT_NOURLQUERY /* flags */
204 check_wsock2(struct Curl_easy *data)
207 WORD wVersionRequested;
212 /* telnet requires at least WinSock 2.0 so ask for it. */
213 wVersionRequested = MAKEWORD(2, 0);
215 err = WSAStartup(wVersionRequested, &wsaData);
217 /* We must've called this once already, so this call */
218 /* should always succeed. But, just in case... */
220 failf(data,"WSAStartup failed (%d)",err);
221 return CURLE_FAILED_INIT;
224 /* We have to have a WSACleanup call for every successful */
225 /* WSAStartup call. */
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 */
232 failf(data, "insufficient winsock version to support "
234 return CURLE_FAILED_INIT;
237 /* Our version is supported */
243 CURLcode init_telnet(struct connectdata *conn)
247 tn = calloc(1, sizeof(struct TELNET));
249 return CURLE_OUT_OF_MEMORY;
251 conn->data->req.protop = tn; /* make us known */
253 tn->telrcv_state = CURL_TS_DATA;
255 /* Init suboptions */
258 /* Set the options we want by default */
259 tn->us_preferred[CURL_TELOPT_SGA] = CURL_YES;
260 tn->him_preferred[CURL_TELOPT_SGA] = CURL_YES;
262 /* 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
267 tn->us_preferred[CURL_TELOPT_BINARY] = CURL_YES;
268 tn->him_preferred[CURL_TELOPT_BINARY] = CURL_YES;
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
276 tn->him_preferred[CURL_TELOPT_ECHO] = CURL_YES;
278 /* Set the subnegotiation fields to send information
279 just after negotiation passed (do/will)
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;
293 static void negotiate(struct connectdata *conn)
296 struct TELNET *tn = (struct TELNET *) conn->data->req.protop;
298 for(i = 0; i < CURL_NTELOPTS; i++) {
299 if(i == CURL_TELOPT_ECHO)
302 if(tn->us_preferred[i] == CURL_YES)
303 set_local_option(conn, i, CURL_YES);
305 if(tn->him_preferred[i] == CURL_YES)
306 set_remote_option(conn, i, CURL_YES);
310 #ifndef CURL_DISABLE_VERBOSE_STRINGS
311 static void printoption(struct Curl_easy *data,
312 const char *direction, int cmd, int option)
317 if(data->set.verbose) {
318 if(cmd == CURL_IAC) {
319 if(CURL_TELCMD_OK(option))
320 infof(data, "%s IAC %s\n", direction, CURL_TELCMD(option));
322 infof(data, "%s IAC %d\n", direction, option);
325 fmt = (cmd == CURL_WILL) ? "WILL" : (cmd == CURL_WONT) ? "WONT" :
326 (cmd == CURL_DO) ? "DO" : (cmd == CURL_DONT) ? "DONT" : 0;
328 if(CURL_TELOPT_OK(option))
329 opt = CURL_TELOPT(option);
330 else if(option == CURL_TELOPT_EXOPL)
336 infof(data, "%s %s %s\n", direction, fmt, opt);
338 infof(data, "%s %s %d\n", direction, fmt, option);
341 infof(data, "%s %d %d\n", direction, cmd, option);
347 static void send_negotiation(struct connectdata *conn, int cmd, int option)
349 unsigned char buf[3];
350 ssize_t bytes_written;
352 struct Curl_easy *data = conn->data;
355 buf[1] = (unsigned char)cmd;
356 buf[2] = (unsigned char)option;
358 bytes_written = swrite(conn->sock[FIRSTSOCKET], buf, 3);
359 if(bytes_written < 0) {
361 failf(data,"Sending data failed (%d)",err);
364 printoption(conn->data, "SENT", cmd, option);
368 void set_remote_option(struct connectdata *conn, int option, int newstate)
370 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
371 if(newstate == CURL_YES) {
372 switch(tn->him[option]) {
374 tn->him[option] = CURL_WANTYES;
375 send_negotiation(conn, CURL_DO, option);
379 /* Already enabled */
383 switch(tn->himq[option]) {
385 /* Already negotiating for CURL_YES, queue the request */
386 tn->himq[option] = CURL_OPPOSITE;
389 /* Error: already queued an enable request */
395 switch(tn->himq[option]) {
397 /* Error: already negotiating for enable */
400 tn->himq[option] = CURL_EMPTY;
407 switch(tn->him[option]) {
409 /* Already disabled */
413 tn->him[option] = CURL_WANTNO;
414 send_negotiation(conn, CURL_DONT, option);
418 switch(tn->himq[option]) {
420 /* Already negotiating for NO */
423 tn->himq[option] = CURL_EMPTY;
429 switch(tn->himq[option]) {
431 tn->himq[option] = CURL_OPPOSITE;
442 void rec_will(struct connectdata *conn, int option)
444 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
445 switch(tn->him[option]) {
447 if(tn->him_preferred[option] == CURL_YES) {
448 tn->him[option] = CURL_YES;
449 send_negotiation(conn, CURL_DO, option);
452 send_negotiation(conn, CURL_DONT, option);
457 /* Already enabled */
461 switch(tn->himq[option]) {
463 /* Error: DONT answered by WILL */
464 tn->him[option] = CURL_NO;
467 /* Error: DONT answered by WILL */
468 tn->him[option] = CURL_YES;
469 tn->himq[option] = CURL_EMPTY;
475 switch(tn->himq[option]) {
477 tn->him[option] = CURL_YES;
480 tn->him[option] = CURL_WANTNO;
481 tn->himq[option] = CURL_EMPTY;
482 send_negotiation(conn, CURL_DONT, option);
490 void rec_wont(struct connectdata *conn, int option)
492 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
493 switch(tn->him[option]) {
495 /* Already disabled */
499 tn->him[option] = CURL_NO;
500 send_negotiation(conn, CURL_DONT, option);
504 switch(tn->himq[option]) {
506 tn->him[option] = CURL_NO;
510 tn->him[option] = CURL_WANTYES;
511 tn->himq[option] = CURL_EMPTY;
512 send_negotiation(conn, CURL_DO, option);
518 switch(tn->himq[option]) {
520 tn->him[option] = CURL_NO;
523 tn->him[option] = CURL_NO;
524 tn->himq[option] = CURL_EMPTY;
532 set_local_option(struct connectdata *conn, int option, int newstate)
534 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
535 if(newstate == CURL_YES) {
536 switch(tn->us[option]) {
538 tn->us[option] = CURL_WANTYES;
539 send_negotiation(conn, CURL_WILL, option);
543 /* Already enabled */
547 switch(tn->usq[option]) {
549 /* Already negotiating for CURL_YES, queue the request */
550 tn->usq[option] = CURL_OPPOSITE;
553 /* Error: already queued an enable request */
559 switch(tn->usq[option]) {
561 /* Error: already negotiating for enable */
564 tn->usq[option] = CURL_EMPTY;
571 switch(tn->us[option]) {
573 /* Already disabled */
577 tn->us[option] = CURL_WANTNO;
578 send_negotiation(conn, CURL_WONT, option);
582 switch(tn->usq[option]) {
584 /* Already negotiating for NO */
587 tn->usq[option] = CURL_EMPTY;
593 switch(tn->usq[option]) {
595 tn->usq[option] = CURL_OPPOSITE;
606 void rec_do(struct connectdata *conn, int option)
608 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
609 switch(tn->us[option]) {
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);
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);
625 send_negotiation(conn, CURL_WONT, option);
629 /* Already enabled */
633 switch(tn->usq[option]) {
635 /* Error: DONT answered by WILL */
636 tn->us[option] = CURL_NO;
639 /* Error: DONT answered by WILL */
640 tn->us[option] = CURL_YES;
641 tn->usq[option] = CURL_EMPTY;
647 switch(tn->usq[option]) {
649 tn->us[option] = CURL_YES;
650 if(tn->subnegotiation[option] == CURL_YES) {
651 /* transmission of data option */
652 sendsuboption(conn, option);
656 tn->us[option] = CURL_WANTNO;
657 tn->himq[option] = CURL_EMPTY;
658 send_negotiation(conn, CURL_WONT, option);
666 void rec_dont(struct connectdata *conn, int option)
668 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
669 switch(tn->us[option]) {
671 /* Already disabled */
675 tn->us[option] = CURL_NO;
676 send_negotiation(conn, CURL_WONT, option);
680 switch(tn->usq[option]) {
682 tn->us[option] = CURL_NO;
686 tn->us[option] = CURL_WANTYES;
687 tn->usq[option] = CURL_EMPTY;
688 send_negotiation(conn, CURL_WILL, option);
694 switch(tn->usq[option]) {
696 tn->us[option] = CURL_NO;
699 tn->us[option] = CURL_NO;
700 tn->usq[option] = CURL_EMPTY;
708 static void printsub(struct Curl_easy *data,
709 int direction, /* '<' or '>' */
710 unsigned char *pointer, /* where suboption data is */
711 size_t length) /* length of suboption data */
715 if(data->set.verbose) {
717 infof(data, "%s IAC SB ", (direction == '<')? "RCVD":"SENT");
721 i = pointer[length-2];
722 j = pointer[length-1];
724 if(i != CURL_IAC || j != CURL_SE) {
725 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));
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));
737 infof(data, "%d", j);
738 infof(data, ", not IAC SE!) ");
744 infof(data, "(Empty suboption?)");
748 if(CURL_TELOPT_OK(pointer[0])) {
750 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]));
757 infof(data, "%s (unsupported)", CURL_TELOPT(pointer[0]));
762 infof(data, "%d (unknown)", pointer[i]);
765 case CURL_TELOPT_NAWS:
767 infof(data, "Width: %hu ; Height: %hu", (pointer[1]<<8) | pointer[2],
768 (pointer[3]<<8) | pointer[4]);
772 case CURL_TELQUAL_IS:
775 case CURL_TELQUAL_SEND:
776 infof(data, " SEND");
778 case CURL_TELQUAL_INFO:
779 infof(data, " INFO/REPLY");
781 case CURL_TELQUAL_NAME:
782 infof(data, " NAME");
787 case CURL_TELOPT_TTYPE:
788 case CURL_TELOPT_XDISPLOC:
790 infof(data, " \"%s\"", &pointer[2]);
792 case CURL_TELOPT_NEW_ENVIRON:
793 if(pointer[1] == CURL_TELQUAL_IS) {
795 for(i = 3; i < length; i++) {
797 case CURL_NEW_ENV_VAR:
800 case CURL_NEW_ENV_VALUE:
804 infof(data, "%c", pointer[i]);
811 for(i = 2; i < length; i++)
812 infof(data, " %.2x", pointer[i]);
821 static CURLcode check_telnet_options(struct connectdata *conn)
823 struct curl_slist *head;
824 struct curl_slist *beg;
825 char option_keyword[128] = "";
826 char option_arg[256] = "";
827 struct Curl_easy *data = conn->data;
828 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
829 CURLcode result = CURLE_OK;
832 /* Add the user name as an environment variable if it
833 was given on the command line */
834 if(conn->bits.user_passwd) {
835 snprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user);
836 beg = curl_slist_append(tn->telnet_vars, option_arg);
838 curl_slist_free_all(tn->telnet_vars);
839 tn->telnet_vars = NULL;
840 return CURLE_OUT_OF_MEMORY;
842 tn->telnet_vars = beg;
843 tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
846 for(head = data->set.telnet_options; head; head = head->next) {
847 if(sscanf(head->data, "%127[^= ]%*[ =]%255s",
848 option_keyword, option_arg) == 2) {
851 if(strcasecompare(option_keyword, "TTYPE")) {
852 strncpy(tn->subopt_ttype, option_arg, 31);
853 tn->subopt_ttype[31] = 0; /* String termination */
854 tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES;
858 /* Display variable */
859 if(strcasecompare(option_keyword, "XDISPLOC")) {
860 strncpy(tn->subopt_xdisploc, option_arg, 127);
861 tn->subopt_xdisploc[127] = 0; /* String termination */
862 tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES;
866 /* Environment variable */
867 if(strcasecompare(option_keyword, "NEW_ENV")) {
868 beg = curl_slist_append(tn->telnet_vars, option_arg);
870 result = CURLE_OUT_OF_MEMORY;
873 tn->telnet_vars = beg;
874 tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
879 if(strcasecompare(option_keyword, "WS")) {
880 if(sscanf(option_arg, "%hu%*[xX]%hu",
881 &tn->subopt_wsx, &tn->subopt_wsy) == 2)
882 tn->us_preferred[CURL_TELOPT_NAWS] = CURL_YES;
884 failf(data, "Syntax error in telnet option: %s", head->data);
885 result = CURLE_TELNET_OPTION_SYNTAX;
891 /* To take care or not of the 8th bit in data exchange */
892 if(strcasecompare(option_keyword, "BINARY")) {
893 binary_option = atoi(option_arg);
894 if(binary_option != 1) {
895 tn->us_preferred[CURL_TELOPT_BINARY] = CURL_NO;
896 tn->him_preferred[CURL_TELOPT_BINARY] = CURL_NO;
901 failf(data, "Unknown telnet option %s", head->data);
902 result = CURLE_UNKNOWN_OPTION;
905 failf(data, "Syntax error in telnet option: %s", head->data);
906 result = CURLE_TELNET_OPTION_SYNTAX;
911 curl_slist_free_all(tn->telnet_vars);
912 tn->telnet_vars = NULL;
921 * Look at the sub-option buffer, and try to be helpful to the other
925 static void suboption(struct connectdata *conn)
927 struct curl_slist *v;
928 unsigned char temp[2048];
929 ssize_t bytes_written;
933 char varname[128] = "";
934 char varval[128] = "";
935 struct Curl_easy *data = conn->data;
936 struct TELNET *tn = (struct TELNET *)data->req.protop;
938 printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn) + 2);
939 switch(CURL_SB_GET(tn)) {
940 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) {
948 failf(data,"Sending data failed (%d)",err);
950 printsub(data, '>', &temp[2], len-2);
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) {
960 failf(data,"Sending data failed (%d)",err);
962 printsub(data, '>', &temp[2], len-2);
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,
970 for(v = tn->telnet_vars; v; v = v->next) {
971 tmplen = (strlen(v->data) + 1);
972 /* Add the variable only if it fits */
973 if(len + tmplen < (int)sizeof(temp)-6) {
974 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);
982 snprintf((char *)&temp[len], sizeof(temp) - len,
983 "%c%c", CURL_IAC, CURL_SE);
985 bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
986 if(bytes_written < 0) {
988 failf(data,"Sending data failed (%d)",err);
990 printsub(data, '>', &temp[2], len-2);
1000 * Send suboption information to the server side.
1003 static void sendsuboption(struct connectdata *conn, int option)
1005 ssize_t bytes_written;
1007 unsigned short x, y;
1008 unsigned char *uc1, *uc2;
1010 struct Curl_easy *data = conn->data;
1011 struct TELNET *tn = (struct TELNET *)data->req.protop;
1014 case CURL_TELOPT_NAWS:
1015 /* We prepare data to be sent */
1017 CURL_SB_ACCUM(tn, CURL_IAC);
1018 CURL_SB_ACCUM(tn, CURL_SB);
1019 CURL_SB_ACCUM(tn, CURL_TELOPT_NAWS);
1020 /* We must deal either with litte or big endian processors */
1021 /* Window size must be sent according to the 'network order' */
1022 x = htons(tn->subopt_wsx);
1023 y = htons(tn->subopt_wsy);
1024 uc1 = (unsigned char *)&x;
1025 uc2 = (unsigned char *)&y;
1026 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]);
1031 CURL_SB_ACCUM(tn, CURL_IAC);
1032 CURL_SB_ACCUM(tn, CURL_SE);
1034 /* data suboption is now ready */
1036 printsub(data, '>', (unsigned char *)tn->subbuffer + 2,
1039 /* we send the header of the suboption... */
1040 bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer, 3);
1041 if(bytes_written < 0) {
1043 failf(data, "Sending data failed (%d)", err);
1045 /* ... then the window size with the send_telnet_data() function
1046 to deal with 0xFF cases ... */
1047 send_telnet_data(conn, (char *)tn->subbuffer + 3, 4);
1048 /* ... and the footer */
1049 bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer + 7, 2);
1050 if(bytes_written < 0) {
1052 failf(data, "Sending data failed (%d)", err);
1060 CURLcode telrcv(struct connectdata *conn,
1061 const unsigned char *inbuf, /* Data received from socket */
1062 ssize_t count) /* Number of bytes received */
1067 int startwrite = -1;
1068 struct Curl_easy *data = conn->data;
1069 struct TELNET *tn = (struct TELNET *)data->req.protop;
1071 #define startskipping() \
1072 if(startwrite >= 0) { \
1073 result = Curl_client_write(conn, \
1075 (char *)&inbuf[startwrite], \
1082 #define writebyte() \
1083 if(startwrite < 0) \
1086 #define bufferflush() startskipping()
1091 switch(tn->telrcv_state) {
1093 tn->telrcv_state = CURL_TS_DATA;
1096 break; /* Ignore \0 after CR */
1103 tn->telrcv_state = CURL_TS_IAC;
1108 tn->telrcv_state = CURL_TS_CR;
1114 DEBUGASSERT(startwrite < 0);
1117 tn->telrcv_state = CURL_TS_WILL;
1120 tn->telrcv_state = CURL_TS_WONT;
1123 tn->telrcv_state = CURL_TS_DO;
1126 tn->telrcv_state = CURL_TS_DONT;
1130 tn->telrcv_state = CURL_TS_SB;
1133 tn->telrcv_state = CURL_TS_DATA;
1140 tn->telrcv_state = CURL_TS_DATA;
1141 printoption(data, "RCVD", CURL_IAC, c);
1147 printoption(data, "RCVD", CURL_WILL, c);
1148 tn->please_negotiate = 1;
1150 tn->telrcv_state = CURL_TS_DATA;
1154 printoption(data, "RCVD", CURL_WONT, c);
1155 tn->please_negotiate = 1;
1157 tn->telrcv_state = CURL_TS_DATA;
1161 printoption(data, "RCVD", CURL_DO, c);
1162 tn->please_negotiate = 1;
1164 tn->telrcv_state = CURL_TS_DATA;
1168 printoption(data, "RCVD", CURL_DONT, c);
1169 tn->please_negotiate = 1;
1171 tn->telrcv_state = CURL_TS_DATA;
1176 tn->telrcv_state = CURL_TS_SE;
1178 CURL_SB_ACCUM(tn, c);
1185 * This is an error. We only expect to get "IAC IAC" or "IAC SE".
1186 * Several things may have happened. An IAC was not doubled, the
1187 * 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
1190 * into an infinite loop here. So, instead, we terminate the
1191 * suboption, and process the partial suboption if we can.
1193 CURL_SB_ACCUM(tn, CURL_IAC);
1194 CURL_SB_ACCUM(tn, c);
1195 tn->subpointer -= 2;
1198 printoption(data, "In SUBOPTION processing, RCVD", CURL_IAC, c);
1199 suboption(conn); /* handle sub-option */
1200 tn->telrcv_state = CURL_TS_IAC;
1203 CURL_SB_ACCUM(tn, c);
1204 tn->telrcv_state = CURL_TS_SB;
1208 CURL_SB_ACCUM(tn, CURL_IAC);
1209 CURL_SB_ACCUM(tn, CURL_SE);
1210 tn->subpointer -= 2;
1212 suboption(conn); /* handle sub-option */
1213 tn->telrcv_state = CURL_TS_DATA;
1223 /* Escape and send a telnet data block */
1224 static CURLcode send_telnet_data(struct connectdata *conn,
1225 char *buffer, ssize_t nread)
1227 ssize_t escapes, i, j, outlen;
1228 unsigned char *outbuf = NULL;
1229 CURLcode result = CURLE_OK;
1230 ssize_t bytes_written, total_written;
1232 /* Determine size of new buffer after escaping */
1234 for(i = 0; i < nread; i++)
1235 if((unsigned char)buffer[i] == CURL_IAC)
1237 outlen = nread + escapes;
1240 outbuf = (unsigned char *)buffer;
1242 outbuf = malloc(nread + escapes + 1);
1244 return CURLE_OUT_OF_MEMORY;
1247 for(i = 0; i < nread; i++) {
1248 outbuf[j++] = buffer[i];
1249 if((unsigned char)buffer[i] == CURL_IAC)
1250 outbuf[j++] = CURL_IAC;
1256 while(!result && total_written < outlen) {
1257 /* Make sure socket is writable to avoid EWOULDBLOCK condition */
1258 struct pollfd pfd[1];
1259 pfd[0].fd = conn->sock[FIRSTSOCKET];
1260 pfd[0].events = POLLOUT;
1261 switch(Curl_poll(pfd, 1, -1)) {
1262 case -1: /* error, abort writing */
1263 case 0: /* timeout (will never happen) */
1264 result = CURLE_SEND_ERROR;
1266 default: /* write! */
1268 result = Curl_write(conn, conn->sock[FIRSTSOCKET],
1269 outbuf + total_written,
1270 outlen - total_written,
1272 total_written += bytes_written;
1277 /* Free malloc copy if escaped */
1278 if(outbuf != (unsigned char *)buffer)
1284 static CURLcode telnet_done(struct connectdata *conn,
1285 CURLcode status, bool premature)
1287 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
1288 (void)status; /* unused */
1289 (void)premature; /* not used */
1294 curl_slist_free_all(tn->telnet_vars);
1295 tn->telnet_vars = NULL;
1297 Curl_safefree(conn->data->req.protop);
1302 static CURLcode telnet_do(struct connectdata *conn, bool *done)
1305 struct Curl_easy *data = conn->data;
1306 curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
1309 WSOCK2_FUNC close_event_func;
1310 WSOCK2_FUNC create_event_func;
1311 WSOCK2_FUNC event_select_func;
1312 WSOCK2_FUNC enum_netevents_func;
1313 WSAEVENT event_handle;
1314 WSANETWORKEVENTS events;
1315 HANDLE stdin_handle;
1320 DWORD readfile_read;
1324 struct pollfd pfd[2];
1326 curl_off_t total_dl = 0;
1327 curl_off_t total_ul = 0;
1330 struct curltime now;
1332 char *buf = data->state.buffer;
1335 *done = TRUE; /* unconditionally */
1337 result = init_telnet(conn);
1341 tn = (struct TELNET *)data->req.protop;
1343 result = check_telnet_options(conn);
1349 ** This functionality only works with WinSock >= 2.0. So,
1350 ** make sure we have it.
1352 result = check_wsock2(data);
1356 /* OK, so we have WinSock 2.0. We need to dynamically */
1357 /* load ws2_32.dll and get the function pointers we need. */
1358 wsock2 = Curl_load_library(TEXT("WS2_32.DLL"));
1359 if(wsock2 == NULL) {
1360 failf(data, "failed to load WS2_32.DLL (%u)", GetLastError());
1361 return CURLE_FAILED_INIT;
1364 /* Grab a pointer to WSACreateEvent */
1365 create_event_func = GetProcAddress(wsock2, "WSACreateEvent");
1366 if(create_event_func == NULL) {
1367 failf(data, "failed to find WSACreateEvent function (%u)", GetLastError());
1368 FreeLibrary(wsock2);
1369 return CURLE_FAILED_INIT;
1372 /* And WSACloseEvent */
1373 close_event_func = GetProcAddress(wsock2, "WSACloseEvent");
1374 if(close_event_func == NULL) {
1375 failf(data, "failed to find WSACloseEvent function (%u)", GetLastError());
1376 FreeLibrary(wsock2);
1377 return CURLE_FAILED_INIT;
1380 /* And WSAEventSelect */
1381 event_select_func = GetProcAddress(wsock2, "WSAEventSelect");
1382 if(event_select_func == NULL) {
1383 failf(data, "failed to find WSAEventSelect function (%u)", GetLastError());
1384 FreeLibrary(wsock2);
1385 return CURLE_FAILED_INIT;
1388 /* And WSAEnumNetworkEvents */
1389 enum_netevents_func = GetProcAddress(wsock2, "WSAEnumNetworkEvents");
1390 if(enum_netevents_func == NULL) {
1391 failf(data, "failed to find WSAEnumNetworkEvents function (%u)",
1393 FreeLibrary(wsock2);
1394 return CURLE_FAILED_INIT;
1397 /* We want to wait for both stdin and the socket. Since
1398 ** the select() function in winsock only works on sockets
1399 ** we have to use the WaitForMultipleObjects() call.
1402 /* First, create a sockets event object */
1403 event_handle = (WSAEVENT)create_event_func();
1404 if(event_handle == WSA_INVALID_EVENT) {
1405 failf(data, "WSACreateEvent failed (%d)", SOCKERRNO);
1406 FreeLibrary(wsock2);
1407 return CURLE_FAILED_INIT;
1410 /* Tell winsock what events we want to listen to */
1411 if(event_select_func(sockfd, event_handle, FD_READ|FD_CLOSE) ==
1413 close_event_func(event_handle);
1414 FreeLibrary(wsock2);
1418 /* The get the Windows file handle for stdin */
1419 stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
1421 /* Create the list of objects to wait for */
1422 objs[0] = event_handle;
1423 objs[1] = stdin_handle;
1425 /* If stdin_handle is a pipe, use PeekNamedPipe() method to check it,
1426 else use the old WaitForMultipleObjects() way */
1427 if(GetFileType(stdin_handle) == FILE_TYPE_PIPE ||
1428 data->set.is_fread_set) {
1429 /* Don't wait for stdin_handle, just wait for event_handle */
1431 /* Check stdin_handle per 100 milliseconds */
1436 wait_timeout = 1000;
1439 /* Keep on listening and act on events */
1441 const DWORD buf_size = (DWORD)data->set.buffer_size;
1442 waitret = WaitForMultipleObjects(obj_count, objs, FALSE, wait_timeout);
1447 if(data->set.is_fread_set) {
1449 /* read from user-supplied method */
1450 n = data->state.fread_func(buf, 1, buf_size, data->state.in);
1451 if(n == CURL_READFUNC_ABORT) {
1453 result = CURLE_READ_ERROR;
1457 if(n == CURL_READFUNC_PAUSE)
1460 if(n == 0) /* no bytes */
1463 /* fall through with number of bytes read */
1464 readfile_read = (DWORD)n;
1467 /* read from stdin */
1468 if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL,
1469 &readfile_read, NULL)) {
1471 result = CURLE_READ_ERROR;
1478 if(!ReadFile(stdin_handle, buf, buf_size,
1479 &readfile_read, NULL)) {
1481 result = CURLE_READ_ERROR;
1486 result = send_telnet_data(conn, buf, readfile_read);
1495 case WAIT_OBJECT_0 + 1:
1497 if(!ReadFile(stdin_handle, buf, buf_size,
1498 &readfile_read, NULL)) {
1500 result = CURLE_READ_ERROR;
1504 result = send_telnet_data(conn, buf, readfile_read);
1514 events.lNetworkEvents = 0;
1515 if(SOCKET_ERROR == enum_netevents_func(sockfd, event_handle, &events)) {
1517 if(err != EINPROGRESS) {
1518 infof(data, "WSAEnumNetworkEvents failed (%d)", err);
1520 result = CURLE_READ_ERROR;
1524 if(events.lNetworkEvents & FD_READ) {
1525 /* read data from network */
1526 result = Curl_read(conn, sockfd, buf, data->set.buffer_size, &nread);
1527 /* read would've blocked. Loop again */
1528 if(result == CURLE_AGAIN)
1530 /* returned not-zero, this an error */
1535 /* returned zero but actually received 0 or less here,
1536 the server closed the connection and we bail out */
1537 else if(nread <= 0) {
1542 result = telrcv(conn, (unsigned char *) buf, nread);
1548 /* Negotiate if the peer has started negotiating,
1549 otherwise don't. We don't want to speak telnet with
1550 non-telnet servers, like POP or SMTP. */
1551 if(tn->please_negotiate && !tn->already_negotiated) {
1553 tn->already_negotiated = 1;
1556 if(events.lNetworkEvents & FD_CLOSE) {
1563 if(data->set.timeout) {
1565 if(Curl_timediff(now, conn->created) >= data->set.timeout) {
1566 failf(data, "Time-out");
1567 result = CURLE_OPERATION_TIMEDOUT;
1573 /* We called WSACreateEvent, so call WSACloseEvent */
1574 if(!close_event_func(event_handle)) {
1575 infof(data, "WSACloseEvent failed (%d)", SOCKERRNO);
1578 /* "Forget" pointers into the library we're about to free */
1579 create_event_func = NULL;
1580 close_event_func = NULL;
1581 event_select_func = NULL;
1582 enum_netevents_func = NULL;
1584 /* We called LoadLibrary, so call FreeLibrary */
1585 if(!FreeLibrary(wsock2))
1586 infof(data, "FreeLibrary(wsock2) failed (%u)", GetLastError());
1589 pfd[0].events = POLLIN;
1591 if(data->set.is_fread_set) {
1593 interval_ms = 100; /* poll user-supplied read function */
1596 /* really using fread, so infile is a FILE* */
1597 pfd[1].fd = fileno((FILE *)data->state.in);
1598 pfd[1].events = POLLIN;
1600 interval_ms = 1 * 1000;
1604 switch(Curl_poll(pfd, poll_cnt, interval_ms)) {
1605 case -1: /* error, stop reading */
1608 case 0: /* timeout */
1612 default: /* read! */
1613 if(pfd[0].revents & POLLIN) {
1614 /* read data from network */
1615 result = Curl_read(conn, sockfd, buf, data->set.buffer_size, &nread);
1616 /* read would've blocked. Loop again */
1617 if(result == CURLE_AGAIN)
1619 /* returned not-zero, this an error */
1624 /* returned zero but actually received 0 or less here,
1625 the server closed the connection and we bail out */
1626 else if(nread <= 0) {
1632 Curl_pgrsSetDownloadCounter(data, total_dl);
1633 result = telrcv(conn, (unsigned char *)buf, nread);
1639 /* Negotiate if the peer has started negotiating,
1640 otherwise don't. We don't want to speak telnet with
1641 non-telnet servers, like POP or SMTP. */
1642 if(tn->please_negotiate && !tn->already_negotiated) {
1644 tn->already_negotiated = 1;
1650 if(pfd[1].revents & POLLIN) { /* read from in file */
1651 nread = read(pfd[1].fd, buf, data->set.buffer_size);
1655 /* read from user-supplied method */
1656 nread = (int)data->state.fread_func(buf, 1, data->set.buffer_size,
1658 if(nread == CURL_READFUNC_ABORT) {
1662 if(nread == CURL_READFUNC_PAUSE)
1667 result = send_telnet_data(conn, buf, nread);
1673 Curl_pgrsSetUploadCounter(data, total_ul);
1679 } /* poll switch statement */
1681 if(data->set.timeout) {
1683 if(Curl_timediff(now, conn->created) >= data->set.timeout) {
1684 failf(data, "Time-out");
1685 result = CURLE_OPERATION_TIMEDOUT;
1690 if(Curl_pgrsUpdate(conn)) {
1691 result = CURLE_ABORTED_BY_CALLBACK;
1696 /* mark this as "no further transfer wanted" */
1697 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);