00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "setup.h"
00025
00026 #ifndef CURL_DISABLE_TELNET
00027
00028 #include <stdio.h>
00029 #include <string.h>
00030 #include <stdarg.h>
00031 #include <stdlib.h>
00032 #include <ctype.h>
00033
00034 #if defined(WIN32)
00035 #include <time.h>
00036 #include <io.h>
00037 #else
00038 #ifdef HAVE_SYS_SOCKET_H
00039 #include <sys/socket.h>
00040 #endif
00041 #include <netinet/in.h>
00042 #ifdef HAVE_SYS_TIME_H
00043 #include <sys/time.h>
00044 #endif
00045 #ifdef HAVE_UNISTD_H
00046 #include <unistd.h>
00047 #endif
00048 #include <netdb.h>
00049 #ifdef HAVE_ARPA_INET_H
00050 #include <arpa/inet.h>
00051 #endif
00052 #ifdef HAVE_NET_IF_H
00053 #include <net/if.h>
00054 #endif
00055 #include <sys/ioctl.h>
00056 #include <signal.h>
00057
00058 #ifdef HAVE_SYS_PARAM_H
00059 #include <sys/param.h>
00060 #endif
00061
00062 #endif
00063
00064 #include "urldata.h"
00065 #include <curl/curl.h>
00066 #include "transfer.h"
00067 #include "sendf.h"
00068 #include "telnet.h"
00069 #include "connect.h"
00070
00071 #define _MPRINTF_REPLACE
00072 #include <curl/mprintf.h>
00073
00074 #define TELOPTS
00075 #define TELCMDS
00076
00077 #include "arpa_telnet.h"
00078 #include "memory.h"
00079 #include "select.h"
00080
00081
00082 #include "memdebug.h"
00083
00084 #define SUBBUFSIZE 512
00085
00086 #define CURL_SB_CLEAR(x) x->subpointer = x->subbuffer;
00087 #define CURL_SB_TERM(x) { x->subend = x->subpointer; CURL_SB_CLEAR(x); }
00088 #define CURL_SB_ACCUM(x,c) \
00089 if (x->subpointer < (x->subbuffer+sizeof x->subbuffer)) { \
00090 *x->subpointer++ = (c); \
00091 }
00092
00093 #define CURL_SB_GET(x) ((*x->subpointer++)&0xff)
00094 #define CURL_SB_PEEK(x) ((*x->subpointer)&0xff)
00095 #define CURL_SB_EOF(x) (x->subpointer >= x->subend)
00096 #define CURL_SB_LEN(x) (x->subend - x->subpointer)
00097
00098 #ifdef CURL_DISABLE_VERBOSE_STRINGS
00099 #define printoption(a,b,c,d) do { } while (0)
00100 #endif
00101
00102 #ifdef USE_WINSOCK
00103 typedef FARPROC WSOCK2_FUNC;
00104 static CURLcode check_wsock2 ( struct SessionHandle *data );
00105 #endif
00106
00107 static
00108 void telrcv(struct connectdata *,
00109 unsigned char *inbuf,
00110 ssize_t count);
00111
00112 #ifndef CURL_DISABLE_VERBOSE_STRINGS
00113 static void printoption(struct SessionHandle *data,
00114 const char *direction,
00115 int cmd, int option);
00116 #endif
00117
00118 static void negotiate(struct connectdata *);
00119 static void send_negotiation(struct connectdata *, int cmd, int option);
00120 static void set_local_option(struct connectdata *, int cmd, int option);
00121 static void set_remote_option(struct connectdata *, int cmd, int option);
00122
00123 static void printsub(struct SessionHandle *data,
00124 int direction, unsigned char *pointer,
00125 size_t length);
00126 static void suboption(struct connectdata *);
00127
00128
00129 #define CURL_NO 0
00130 #define CURL_YES 1
00131 #define CURL_WANTYES 2
00132 #define CURL_WANTNO 3
00133
00134 #define CURL_EMPTY 0
00135 #define CURL_OPPOSITE 1
00136
00137
00138
00139
00140 typedef enum
00141 {
00142 CURL_TS_DATA = 0,
00143 CURL_TS_IAC,
00144 CURL_TS_WILL,
00145 CURL_TS_WONT,
00146 CURL_TS_DO,
00147 CURL_TS_DONT,
00148 CURL_TS_CR,
00149 CURL_TS_SB,
00150 CURL_TS_SE
00151 } TelnetReceive;
00152
00153 struct TELNET {
00154 int please_negotiate;
00155 int already_negotiated;
00156 int us[256];
00157 int usq[256];
00158 int us_preferred[256];
00159 int him[256];
00160 int himq[256];
00161 int him_preferred[256];
00162 char subopt_ttype[32];
00163 char subopt_xdisploc[128];
00164 struct curl_slist *telnet_vars;
00165
00166
00167 unsigned char subbuffer[SUBBUFSIZE];
00168 unsigned char *subpointer, *subend;
00169
00170 TelnetReceive telrcv_state;
00171 };
00172
00173 #ifdef USE_WINSOCK
00174 static CURLcode
00175 check_wsock2 ( struct SessionHandle *data )
00176 {
00177 int err;
00178 WORD wVersionRequested;
00179 WSADATA wsaData;
00180
00181 DEBUGASSERT(data);
00182
00183
00184 wVersionRequested = MAKEWORD(2, 0);
00185
00186 err = WSAStartup(wVersionRequested, &wsaData);
00187
00188
00189
00190 if (err != 0) {
00191 failf(data,"WSAStartup failed (%d)",err);
00192 return CURLE_FAILED_INIT;
00193 }
00194
00195
00196
00197 WSACleanup();
00198
00199
00200 if (LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) ||
00201 HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested)) {
00202
00203 failf(data,"insufficient winsock version to support "
00204 "telnet");
00205 return CURLE_FAILED_INIT;
00206 }
00207
00208
00209 return CURLE_OK;
00210 }
00211 #endif
00212
00213 static
00214 CURLcode init_telnet(struct connectdata *conn)
00215 {
00216 struct TELNET *tn;
00217
00218 tn = (struct TELNET *)calloc(1, sizeof(struct TELNET));
00219 if(!tn)
00220 return CURLE_OUT_OF_MEMORY;
00221
00222 conn->data->reqdata.proto.telnet = (void *)tn;
00223
00224 tn->telrcv_state = CURL_TS_DATA;
00225
00226
00227 CURL_SB_CLEAR(tn);
00228
00229
00230 tn->us_preferred[CURL_TELOPT_BINARY] = CURL_YES;
00231 tn->us_preferred[CURL_TELOPT_SGA] = CURL_YES;
00232 tn->him_preferred[CURL_TELOPT_BINARY] = CURL_YES;
00233 tn->him_preferred[CURL_TELOPT_SGA] = CURL_YES;
00234
00235 return CURLE_OK;
00236 }
00237
00238 static void negotiate(struct connectdata *conn)
00239 {
00240 int i;
00241 struct TELNET *tn = (struct TELNET *) conn->data->reqdata.proto.telnet;
00242
00243 for(i = 0;i < CURL_NTELOPTS;i++)
00244 {
00245 if(tn->us_preferred[i] == CURL_YES)
00246 set_local_option(conn, i, CURL_YES);
00247
00248 if(tn->him_preferred[i] == CURL_YES)
00249 set_remote_option(conn, i, CURL_YES);
00250 }
00251 }
00252
00253 #ifndef CURL_DISABLE_VERBOSE_STRINGS
00254 static void printoption(struct SessionHandle *data,
00255 const char *direction, int cmd, int option)
00256 {
00257 const char *fmt;
00258 const char *opt;
00259
00260 if (data->set.verbose)
00261 {
00262 if (cmd == CURL_IAC)
00263 {
00264 if (CURL_TELCMD_OK(option))
00265 infof(data, "%s IAC %s\n", direction, CURL_TELCMD(option));
00266 else
00267 infof(data, "%s IAC %d\n", direction, option);
00268 }
00269 else
00270 {
00271 fmt = (cmd == CURL_WILL) ? "WILL" : (cmd == CURL_WONT) ? "WONT" :
00272 (cmd == CURL_DO) ? "DO" : (cmd == CURL_DONT) ? "DONT" : 0;
00273 if (fmt)
00274 {
00275 if (CURL_TELOPT_OK(option))
00276 opt = CURL_TELOPT(option);
00277 else if (option == CURL_TELOPT_EXOPL)
00278 opt = "EXOPL";
00279 else
00280 opt = NULL;
00281
00282 if(opt)
00283 infof(data, "%s %s %s\n", direction, fmt, opt);
00284 else
00285 infof(data, "%s %s %d\n", direction, fmt, option);
00286 }
00287 else
00288 infof(data, "%s %d %d\n", direction, cmd, option);
00289 }
00290 }
00291 }
00292 #endif
00293
00294 static void send_negotiation(struct connectdata *conn, int cmd, int option)
00295 {
00296 unsigned char buf[3];
00297 ssize_t bytes_written;
00298 int err;
00299 struct SessionHandle *data = conn->data;
00300
00301 buf[0] = CURL_IAC;
00302 buf[1] = (unsigned char)cmd;
00303 buf[2] = (unsigned char)option;
00304
00305 bytes_written = swrite(conn->sock[FIRSTSOCKET], buf, 3);
00306 if(bytes_written < 0) {
00307 err = SOCKERRNO;
00308 failf(data,"Sending data failed (%d)",err);
00309 }
00310
00311 printoption(conn->data, "SENT", cmd, option);
00312 }
00313
00314 static
00315 void set_remote_option(struct connectdata *conn, int option, int newstate)
00316 {
00317 struct TELNET *tn = (struct TELNET *)conn->data->reqdata.proto.telnet;
00318 if(newstate == CURL_YES)
00319 {
00320 switch(tn->him[option])
00321 {
00322 case CURL_NO:
00323 tn->him[option] = CURL_WANTYES;
00324 send_negotiation(conn, CURL_DO, option);
00325 break;
00326
00327 case CURL_YES:
00328
00329 break;
00330
00331 case CURL_WANTNO:
00332 switch(tn->himq[option])
00333 {
00334 case CURL_EMPTY:
00335
00336 tn->himq[option] = CURL_OPPOSITE;
00337 break;
00338 case CURL_OPPOSITE:
00339
00340 break;
00341 }
00342 break;
00343
00344 case CURL_WANTYES:
00345 switch(tn->himq[option])
00346 {
00347 case CURL_EMPTY:
00348
00349 break;
00350 case CURL_OPPOSITE:
00351 tn->himq[option] = CURL_EMPTY;
00352 break;
00353 }
00354 break;
00355 }
00356 }
00357 else
00358 {
00359 switch(tn->him[option])
00360 {
00361 case CURL_NO:
00362
00363 break;
00364
00365 case CURL_YES:
00366 tn->him[option] = CURL_WANTNO;
00367 send_negotiation(conn, CURL_DONT, option);
00368 break;
00369
00370 case CURL_WANTNO:
00371 switch(tn->himq[option])
00372 {
00373 case CURL_EMPTY:
00374
00375 break;
00376 case CURL_OPPOSITE:
00377 tn->himq[option] = CURL_EMPTY;
00378 break;
00379 }
00380 break;
00381
00382 case CURL_WANTYES:
00383 switch(tn->himq[option])
00384 {
00385 case CURL_EMPTY:
00386 tn->himq[option] = CURL_OPPOSITE;
00387 break;
00388 case CURL_OPPOSITE:
00389 break;
00390 }
00391 break;
00392 }
00393 }
00394 }
00395
00396 static
00397 void rec_will(struct connectdata *conn, int option)
00398 {
00399 struct TELNET *tn = (struct TELNET *)conn->data->reqdata.proto.telnet;
00400 switch(tn->him[option])
00401 {
00402 case CURL_NO:
00403 if(tn->him_preferred[option] == CURL_YES)
00404 {
00405 tn->him[option] = CURL_YES;
00406 send_negotiation(conn, CURL_DO, option);
00407 }
00408 else
00409 {
00410 send_negotiation(conn, CURL_DONT, option);
00411 }
00412 break;
00413
00414 case CURL_YES:
00415
00416 break;
00417
00418 case CURL_WANTNO:
00419 switch(tn->himq[option])
00420 {
00421 case CURL_EMPTY:
00422
00423 tn->him[option] = CURL_NO;
00424 break;
00425 case CURL_OPPOSITE:
00426
00427 tn->him[option] = CURL_YES;
00428 tn->himq[option] = CURL_EMPTY;
00429 break;
00430 }
00431 break;
00432
00433 case CURL_WANTYES:
00434 switch(tn->himq[option])
00435 {
00436 case CURL_EMPTY:
00437 tn->him[option] = CURL_YES;
00438 break;
00439 case CURL_OPPOSITE:
00440 tn->him[option] = CURL_WANTNO;
00441 tn->himq[option] = CURL_EMPTY;
00442 send_negotiation(conn, CURL_DONT, option);
00443 break;
00444 }
00445 break;
00446 }
00447 }
00448
00449 static
00450 void rec_wont(struct connectdata *conn, int option)
00451 {
00452 struct TELNET *tn = (struct TELNET *)conn->data->reqdata.proto.telnet;
00453 switch(tn->him[option])
00454 {
00455 case CURL_NO:
00456
00457 break;
00458
00459 case CURL_YES:
00460 tn->him[option] = CURL_NO;
00461 send_negotiation(conn, CURL_DONT, option);
00462 break;
00463
00464 case CURL_WANTNO:
00465 switch(tn->himq[option])
00466 {
00467 case CURL_EMPTY:
00468 tn->him[option] = CURL_NO;
00469 break;
00470
00471 case CURL_OPPOSITE:
00472 tn->him[option] = CURL_WANTYES;
00473 tn->himq[option] = CURL_EMPTY;
00474 send_negotiation(conn, CURL_DO, option);
00475 break;
00476 }
00477 break;
00478
00479 case CURL_WANTYES:
00480 switch(tn->himq[option])
00481 {
00482 case CURL_EMPTY:
00483 tn->him[option] = CURL_NO;
00484 break;
00485 case CURL_OPPOSITE:
00486 tn->him[option] = CURL_NO;
00487 tn->himq[option] = CURL_EMPTY;
00488 break;
00489 }
00490 break;
00491 }
00492 }
00493
00494 static void
00495 set_local_option(struct connectdata *conn, int option, int newstate)
00496 {
00497 struct TELNET *tn = (struct TELNET *)conn->data->reqdata.proto.telnet;
00498 if(newstate == CURL_YES)
00499 {
00500 switch(tn->us[option])
00501 {
00502 case CURL_NO:
00503 tn->us[option] = CURL_WANTYES;
00504 send_negotiation(conn, CURL_WILL, option);
00505 break;
00506
00507 case CURL_YES:
00508
00509 break;
00510
00511 case CURL_WANTNO:
00512 switch(tn->usq[option])
00513 {
00514 case CURL_EMPTY:
00515
00516 tn->usq[option] = CURL_OPPOSITE;
00517 break;
00518 case CURL_OPPOSITE:
00519
00520 break;
00521 }
00522 break;
00523
00524 case CURL_WANTYES:
00525 switch(tn->usq[option])
00526 {
00527 case CURL_EMPTY:
00528
00529 break;
00530 case CURL_OPPOSITE:
00531 tn->usq[option] = CURL_EMPTY;
00532 break;
00533 }
00534 break;
00535 }
00536 }
00537 else
00538 {
00539 switch(tn->us[option])
00540 {
00541 case CURL_NO:
00542
00543 break;
00544
00545 case CURL_YES:
00546 tn->us[option] = CURL_WANTNO;
00547 send_negotiation(conn, CURL_WONT, option);
00548 break;
00549
00550 case CURL_WANTNO:
00551 switch(tn->usq[option])
00552 {
00553 case CURL_EMPTY:
00554
00555 break;
00556 case CURL_OPPOSITE:
00557 tn->usq[option] = CURL_EMPTY;
00558 break;
00559 }
00560 break;
00561
00562 case CURL_WANTYES:
00563 switch(tn->usq[option])
00564 {
00565 case CURL_EMPTY:
00566 tn->usq[option] = CURL_OPPOSITE;
00567 break;
00568 case CURL_OPPOSITE:
00569 break;
00570 }
00571 break;
00572 }
00573 }
00574 }
00575
00576 static
00577 void rec_do(struct connectdata *conn, int option)
00578 {
00579 struct TELNET *tn = (struct TELNET *)conn->data->reqdata.proto.telnet;
00580 switch(tn->us[option])
00581 {
00582 case CURL_NO:
00583 if(tn->us_preferred[option] == CURL_YES)
00584 {
00585 tn->us[option] = CURL_YES;
00586 send_negotiation(conn, CURL_WILL, option);
00587 }
00588 else
00589 {
00590 send_negotiation(conn, CURL_WONT, option);
00591 }
00592 break;
00593
00594 case CURL_YES:
00595
00596 break;
00597
00598 case CURL_WANTNO:
00599 switch(tn->usq[option])
00600 {
00601 case CURL_EMPTY:
00602
00603 tn->us[option] = CURL_NO;
00604 break;
00605 case CURL_OPPOSITE:
00606
00607 tn->us[option] = CURL_YES;
00608 tn->usq[option] = CURL_EMPTY;
00609 break;
00610 }
00611 break;
00612
00613 case CURL_WANTYES:
00614 switch(tn->usq[option])
00615 {
00616 case CURL_EMPTY:
00617 tn->us[option] = CURL_YES;
00618 break;
00619 case CURL_OPPOSITE:
00620 tn->us[option] = CURL_WANTNO;
00621 tn->himq[option] = CURL_EMPTY;
00622 send_negotiation(conn, CURL_WONT, option);
00623 break;
00624 }
00625 break;
00626 }
00627 }
00628
00629 static
00630 void rec_dont(struct connectdata *conn, int option)
00631 {
00632 struct TELNET *tn = (struct TELNET *)conn->data->reqdata.proto.telnet;
00633 switch(tn->us[option])
00634 {
00635 case CURL_NO:
00636
00637 break;
00638
00639 case CURL_YES:
00640 tn->us[option] = CURL_NO;
00641 send_negotiation(conn, CURL_WONT, option);
00642 break;
00643
00644 case CURL_WANTNO:
00645 switch(tn->usq[option])
00646 {
00647 case CURL_EMPTY:
00648 tn->us[option] = CURL_NO;
00649 break;
00650
00651 case CURL_OPPOSITE:
00652 tn->us[option] = CURL_WANTYES;
00653 tn->usq[option] = CURL_EMPTY;
00654 send_negotiation(conn, CURL_WILL, option);
00655 break;
00656 }
00657 break;
00658
00659 case CURL_WANTYES:
00660 switch(tn->usq[option])
00661 {
00662 case CURL_EMPTY:
00663 tn->us[option] = CURL_NO;
00664 break;
00665 case CURL_OPPOSITE:
00666 tn->us[option] = CURL_NO;
00667 tn->usq[option] = CURL_EMPTY;
00668 break;
00669 }
00670 break;
00671 }
00672 }
00673
00674
00675 static void printsub(struct SessionHandle *data,
00676 int direction,
00677 unsigned char *pointer,
00678 size_t length)
00679 {
00680 unsigned int i = 0;
00681
00682 if (data->set.verbose)
00683 {
00684 if (direction)
00685 {
00686 infof(data, "%s IAC SB ", (direction == '<')? "RCVD":"SENT");
00687 if (length >= 3)
00688 {
00689 int j;
00690
00691 i = pointer[length-2];
00692 j = pointer[length-1];
00693
00694 if (i != CURL_IAC || j != CURL_SE)
00695 {
00696 infof(data, "(terminated by ");
00697 if (CURL_TELOPT_OK(i))
00698 infof(data, "%s ", CURL_TELOPT(i));
00699 else if (CURL_TELCMD_OK(i))
00700 infof(data, "%s ", CURL_TELCMD(i));
00701 else
00702 infof(data, "%d ", i);
00703 if (CURL_TELOPT_OK(j))
00704 infof(data, "%s", CURL_TELOPT(j));
00705 else if (CURL_TELCMD_OK(j))
00706 infof(data, "%s", CURL_TELCMD(j));
00707 else
00708 infof(data, "%d", j);
00709 infof(data, ", not IAC SE!) ");
00710 }
00711 }
00712 length -= 2;
00713 }
00714 if (length < 1)
00715 {
00716 infof(data, "(Empty suboption?)");
00717 return;
00718 }
00719
00720 if (CURL_TELOPT_OK(pointer[0])) {
00721 switch(pointer[0]) {
00722 case CURL_TELOPT_TTYPE:
00723 case CURL_TELOPT_XDISPLOC:
00724 case CURL_TELOPT_NEW_ENVIRON:
00725 infof(data, "%s", CURL_TELOPT(pointer[0]));
00726 break;
00727 default:
00728 infof(data, "%s (unsupported)", CURL_TELOPT(pointer[0]));
00729 break;
00730 }
00731 }
00732 else
00733 infof(data, "%d (unknown)", pointer[i]);
00734
00735 switch(pointer[1]) {
00736 case CURL_TELQUAL_IS:
00737 infof(data, " IS");
00738 break;
00739 case CURL_TELQUAL_SEND:
00740 infof(data, " SEND");
00741 break;
00742 case CURL_TELQUAL_INFO:
00743 infof(data, " INFO/REPLY");
00744 break;
00745 case CURL_TELQUAL_NAME:
00746 infof(data, " NAME");
00747 break;
00748 }
00749
00750 switch(pointer[0]) {
00751 case CURL_TELOPT_TTYPE:
00752 case CURL_TELOPT_XDISPLOC:
00753 pointer[length] = 0;
00754 infof(data, " \"%s\"", &pointer[2]);
00755 break;
00756 case CURL_TELOPT_NEW_ENVIRON:
00757 if(pointer[1] == CURL_TELQUAL_IS) {
00758 infof(data, " ");
00759 for(i = 3;i < length;i++) {
00760 switch(pointer[i]) {
00761 case CURL_NEW_ENV_VAR:
00762 infof(data, ", ");
00763 break;
00764 case CURL_NEW_ENV_VALUE:
00765 infof(data, " = ");
00766 break;
00767 default:
00768 infof(data, "%c", pointer[i]);
00769 break;
00770 }
00771 }
00772 }
00773 break;
00774 default:
00775 for (i = 2; i < length; i++)
00776 infof(data, " %.2x", pointer[i]);
00777 break;
00778 }
00779
00780 if (direction)
00781 {
00782 infof(data, "\n");
00783 }
00784 }
00785 }
00786
00787 static CURLcode check_telnet_options(struct connectdata *conn)
00788 {
00789 struct curl_slist *head;
00790 char option_keyword[128];
00791 char option_arg[256];
00792 char *buf;
00793 struct SessionHandle *data = conn->data;
00794 struct TELNET *tn = (struct TELNET *)conn->data->reqdata.proto.telnet;
00795
00796
00797
00798 if(conn->bits.user_passwd)
00799 {
00800 snprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user);
00801 tn->telnet_vars = curl_slist_append(tn->telnet_vars, option_arg);
00802
00803 tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
00804 }
00805
00806 for(head = data->set.telnet_options; head; head=head->next) {
00807 if(sscanf(head->data, "%127[^= ]%*[ =]%255s",
00808 option_keyword, option_arg) == 2) {
00809
00810
00811 if(curl_strequal(option_keyword, "TTYPE")) {
00812 strncpy(tn->subopt_ttype, option_arg, 31);
00813 tn->subopt_ttype[31] = 0;
00814 tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES;
00815 continue;
00816 }
00817
00818
00819 if(curl_strequal(option_keyword, "XDISPLOC")) {
00820 strncpy(tn->subopt_xdisploc, option_arg, 127);
00821 tn->subopt_xdisploc[127] = 0;
00822 tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES;
00823 continue;
00824 }
00825
00826
00827 if(curl_strequal(option_keyword, "NEW_ENV")) {
00828 buf = strdup(option_arg);
00829 if(!buf)
00830 return CURLE_OUT_OF_MEMORY;
00831 tn->telnet_vars = curl_slist_append(tn->telnet_vars, buf);
00832 tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
00833 continue;
00834 }
00835
00836 failf(data, "Unknown telnet option %s", head->data);
00837 return CURLE_UNKNOWN_TELNET_OPTION;
00838 } else {
00839 failf(data, "Syntax error in telnet option: %s", head->data);
00840 return CURLE_TELNET_OPTION_SYNTAX;
00841 }
00842 }
00843
00844 return CURLE_OK;
00845 }
00846
00847
00848
00849
00850
00851
00852
00853
00854 static void suboption(struct connectdata *conn)
00855 {
00856 struct curl_slist *v;
00857 unsigned char temp[2048];
00858 ssize_t bytes_written;
00859 size_t len;
00860 size_t tmplen;
00861 int err;
00862 char varname[128];
00863 char varval[128];
00864 struct SessionHandle *data = conn->data;
00865 struct TELNET *tn = (struct TELNET *)data->reqdata.proto.telnet;
00866
00867 printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn)+2);
00868 switch (CURL_SB_GET(tn)) {
00869 case CURL_TELOPT_TTYPE:
00870 len = strlen(tn->subopt_ttype) + 4 + 2;
00871 snprintf((char *)temp, sizeof(temp),
00872 "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE,
00873 CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE);
00874 bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
00875 if(bytes_written < 0) {
00876 err = SOCKERRNO;
00877 failf(data,"Sending data failed (%d)",err);
00878 }
00879 printsub(data, '>', &temp[2], len-2);
00880 break;
00881 case CURL_TELOPT_XDISPLOC:
00882 len = strlen(tn->subopt_xdisploc) + 4 + 2;
00883 snprintf((char *)temp, sizeof(temp),
00884 "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC,
00885 CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE);
00886 bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
00887 if(bytes_written < 0) {
00888 err = SOCKERRNO;
00889 failf(data,"Sending data failed (%d)",err);
00890 }
00891 printsub(data, '>', &temp[2], len-2);
00892 break;
00893 case CURL_TELOPT_NEW_ENVIRON:
00894 snprintf((char *)temp, sizeof(temp),
00895 "%c%c%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON,
00896 CURL_TELQUAL_IS);
00897 len = 4;
00898
00899 for(v = tn->telnet_vars;v;v = v->next) {
00900 tmplen = (strlen(v->data) + 1);
00901
00902 if(len + tmplen < (int)sizeof(temp)-6) {
00903 sscanf(v->data, "%127[^,],%127s", varname, varval);
00904 snprintf((char *)&temp[len], sizeof(temp) - len,
00905 "%c%s%c%s", CURL_NEW_ENV_VAR, varname,
00906 CURL_NEW_ENV_VALUE, varval);
00907 len += tmplen;
00908 }
00909 }
00910 snprintf((char *)&temp[len], sizeof(temp) - len,
00911 "%c%c", CURL_IAC, CURL_SE);
00912 len += 2;
00913 bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
00914 if(bytes_written < 0) {
00915 err = SOCKERRNO;
00916 failf(data,"Sending data failed (%d)",err);
00917 }
00918 printsub(data, '>', &temp[2], len-2);
00919 break;
00920 }
00921 return;
00922 }
00923
00924 static
00925 void telrcv(struct connectdata *conn,
00926 unsigned char *inbuf,
00927 ssize_t count)
00928 {
00929 unsigned char c;
00930 int in = 0;
00931 struct SessionHandle *data = conn->data;
00932 struct TELNET *tn = (struct TELNET *)data->reqdata.proto.telnet;
00933
00934 while(count--)
00935 {
00936 c = inbuf[in++];
00937
00938 switch (tn->telrcv_state)
00939 {
00940 case CURL_TS_CR:
00941 tn->telrcv_state = CURL_TS_DATA;
00942 if (c == '\0')
00943 {
00944 break;
00945 }
00946
00947 Curl_client_write(conn, CLIENTWRITE_BODY, (char *)&c, 1);
00948 continue;
00949
00950 case CURL_TS_DATA:
00951 if (c == CURL_IAC)
00952 {
00953 tn->telrcv_state = CURL_TS_IAC;
00954 break;
00955 }
00956 else if(c == '\r')
00957 {
00958 tn->telrcv_state = CURL_TS_CR;
00959 }
00960
00961 Curl_client_write(conn, CLIENTWRITE_BODY, (char *)&c, 1);
00962 continue;
00963
00964 case CURL_TS_IAC:
00965 process_iac:
00966 switch (c)
00967 {
00968 case CURL_WILL:
00969 tn->telrcv_state = CURL_TS_WILL;
00970 continue;
00971 case CURL_WONT:
00972 tn->telrcv_state = CURL_TS_WONT;
00973 continue;
00974 case CURL_DO:
00975 tn->telrcv_state = CURL_TS_DO;
00976 continue;
00977 case CURL_DONT:
00978 tn->telrcv_state = CURL_TS_DONT;
00979 continue;
00980 case CURL_SB:
00981 CURL_SB_CLEAR(tn);
00982 tn->telrcv_state = CURL_TS_SB;
00983 continue;
00984 case CURL_IAC:
00985 Curl_client_write(conn, CLIENTWRITE_BODY, (char *)&c, 1);
00986 break;
00987 case CURL_DM:
00988 case CURL_NOP:
00989 case CURL_GA:
00990 default:
00991 printoption(data, "RCVD", CURL_IAC, c);
00992 break;
00993 }
00994 tn->telrcv_state = CURL_TS_DATA;
00995 continue;
00996
00997 case CURL_TS_WILL:
00998 printoption(data, "RCVD", CURL_WILL, c);
00999 tn->please_negotiate = 1;
01000 rec_will(conn, c);
01001 tn->telrcv_state = CURL_TS_DATA;
01002 continue;
01003
01004 case CURL_TS_WONT:
01005 printoption(data, "RCVD", CURL_WONT, c);
01006 tn->please_negotiate = 1;
01007 rec_wont(conn, c);
01008 tn->telrcv_state = CURL_TS_DATA;
01009 continue;
01010
01011 case CURL_TS_DO:
01012 printoption(data, "RCVD", CURL_DO, c);
01013 tn->please_negotiate = 1;
01014 rec_do(conn, c);
01015 tn->telrcv_state = CURL_TS_DATA;
01016 continue;
01017
01018 case CURL_TS_DONT:
01019 printoption(data, "RCVD", CURL_DONT, c);
01020 tn->please_negotiate = 1;
01021 rec_dont(conn, c);
01022 tn->telrcv_state = CURL_TS_DATA;
01023 continue;
01024
01025 case CURL_TS_SB:
01026 if (c == CURL_IAC)
01027 {
01028 tn->telrcv_state = CURL_TS_SE;
01029 }
01030 else
01031 {
01032 CURL_SB_ACCUM(tn,c);
01033 }
01034 continue;
01035
01036 case CURL_TS_SE:
01037 if (c != CURL_SE)
01038 {
01039 if (c != CURL_IAC)
01040 {
01041
01042
01043
01044
01045
01046
01047
01048
01049
01050 CURL_SB_ACCUM(tn, CURL_IAC);
01051 CURL_SB_ACCUM(tn, c);
01052 tn->subpointer -= 2;
01053 CURL_SB_TERM(tn);
01054
01055 printoption(data, "In SUBOPTION processing, RCVD", CURL_IAC, c);
01056 suboption(conn);
01057 tn->telrcv_state = CURL_TS_IAC;
01058 goto process_iac;
01059 }
01060 CURL_SB_ACCUM(tn,c);
01061 tn->telrcv_state = CURL_TS_SB;
01062 }
01063 else
01064 {
01065 CURL_SB_ACCUM(tn, CURL_IAC);
01066 CURL_SB_ACCUM(tn, CURL_SE);
01067 tn->subpointer -= 2;
01068 CURL_SB_TERM(tn);
01069 suboption(conn);
01070 tn->telrcv_state = CURL_TS_DATA;
01071 }
01072 break;
01073 }
01074 }
01075 }
01076
01077 CURLcode Curl_telnet_done(struct connectdata *conn, CURLcode status, bool premature)
01078 {
01079 struct TELNET *tn = (struct TELNET *)conn->data->reqdata.proto.telnet;
01080 (void)status;
01081 (void)premature;
01082
01083 curl_slist_free_all(tn->telnet_vars);
01084
01085 free(conn->data->reqdata.proto.telnet);
01086 conn->data->reqdata.proto.telnet = NULL;
01087
01088 return CURLE_OK;
01089 }
01090
01091 CURLcode Curl_telnet(struct connectdata *conn, bool *done)
01092 {
01093 CURLcode code;
01094 struct SessionHandle *data = conn->data;
01095 curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
01096 #ifdef USE_WINSOCK
01097 HMODULE wsock2;
01098 WSOCK2_FUNC close_event_func;
01099 WSOCK2_FUNC create_event_func;
01100 WSOCK2_FUNC event_select_func;
01101 WSOCK2_FUNC enum_netevents_func;
01102 WSAEVENT event_handle;
01103 WSANETWORKEVENTS events;
01104 HANDLE stdin_handle;
01105 HANDLE objs[2];
01106 DWORD obj_count;
01107 DWORD wait_timeout;
01108 DWORD waitret;
01109 DWORD readfile_read;
01110 #else
01111 int interval_ms;
01112 struct pollfd pfd[2];
01113 #endif
01114 ssize_t nread;
01115 bool keepon = TRUE;
01116 char *buf = data->state.buffer;
01117 struct TELNET *tn;
01118
01119 *done = TRUE;
01120
01121 code = init_telnet(conn);
01122 if(code)
01123 return code;
01124
01125 tn = (struct TELNET *)data->reqdata.proto.telnet;
01126
01127 code = check_telnet_options(conn);
01128 if(code)
01129 return code;
01130
01131 #ifdef USE_WINSOCK
01132
01133
01134
01135
01136 code = check_wsock2(data);
01137 if (code)
01138 return code;
01139
01140
01141
01142 wsock2 = LoadLibrary("WS2_32.DLL");
01143 if (wsock2 == NULL) {
01144 failf(data,"failed to load WS2_32.DLL (%d)", ERRNO);
01145 return CURLE_FAILED_INIT;
01146 }
01147
01148
01149 create_event_func = GetProcAddress(wsock2,"WSACreateEvent");
01150 if (create_event_func == NULL) {
01151 failf(data,"failed to find WSACreateEvent function (%d)",
01152 ERRNO);
01153 FreeLibrary(wsock2);
01154 return CURLE_FAILED_INIT;
01155 }
01156
01157
01158 close_event_func = GetProcAddress(wsock2,"WSACloseEvent");
01159 if (close_event_func == NULL) {
01160 failf(data,"failed to find WSACloseEvent function (%d)",
01161 ERRNO);
01162 FreeLibrary(wsock2);
01163 return CURLE_FAILED_INIT;
01164 }
01165
01166
01167 event_select_func = GetProcAddress(wsock2,"WSAEventSelect");
01168 if (event_select_func == NULL) {
01169 failf(data,"failed to find WSAEventSelect function (%d)",
01170 ERRNO);
01171 FreeLibrary(wsock2);
01172 return CURLE_FAILED_INIT;
01173 }
01174
01175
01176 enum_netevents_func = GetProcAddress(wsock2,"WSAEnumNetworkEvents");
01177 if (enum_netevents_func == NULL) {
01178 failf(data,"failed to find WSAEnumNetworkEvents function (%d)",
01179 ERRNO);
01180 FreeLibrary(wsock2);
01181 return CURLE_FAILED_INIT;
01182 }
01183
01184
01185
01186
01187
01188
01189
01190 event_handle = (WSAEVENT)create_event_func();
01191 if (event_handle == WSA_INVALID_EVENT) {
01192 failf(data,"WSACreateEvent failed (%d)", SOCKERRNO);
01193 FreeLibrary(wsock2);
01194 return CURLE_FAILED_INIT;
01195 }
01196
01197
01198 stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
01199
01200
01201 objs[0] = event_handle;
01202 objs[1] = stdin_handle;
01203
01204
01205 if(event_select_func(sockfd, event_handle, FD_READ|FD_CLOSE) == SOCKET_ERROR) {
01206 close_event_func(event_handle);
01207 FreeLibrary(wsock2);
01208 return 0;
01209 }
01210
01211
01212
01213 if(GetFileType(stdin_handle) == FILE_TYPE_PIPE) {
01214
01215 obj_count = 1;
01216
01217 wait_timeout = 100;
01218 } else {
01219 obj_count = 2;
01220 wait_timeout = INFINITE;
01221 }
01222
01223
01224 while(keepon) {
01225 waitret = WaitForMultipleObjects(obj_count, objs, FALSE, wait_timeout);
01226 switch(waitret) {
01227 case WAIT_TIMEOUT:
01228 {
01229 unsigned char outbuf[2];
01230 int out_count = 0;
01231 ssize_t bytes_written;
01232 char *buffer = buf;
01233
01234 while(1) {
01235 if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL, &readfile_read, NULL)) {
01236 keepon = FALSE;
01237 break;
01238 }
01239 nread = readfile_read;
01240
01241 if(!nread)
01242 break;
01243
01244 if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
01245 &readfile_read, NULL)) {
01246 keepon = FALSE;
01247 break;
01248 }
01249 nread = readfile_read;
01250
01251 while(nread--) {
01252 outbuf[0] = *buffer++;
01253 out_count = 1;
01254 if(outbuf[0] == CURL_IAC)
01255 outbuf[out_count++] = CURL_IAC;
01256
01257 Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf,
01258 out_count, &bytes_written);
01259 }
01260 }
01261 }
01262 break;
01263
01264 case WAIT_OBJECT_0 + 1:
01265 {
01266 unsigned char outbuf[2];
01267 int out_count = 0;
01268 ssize_t bytes_written;
01269 char *buffer = buf;
01270
01271 if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
01272 &readfile_read, NULL)) {
01273 keepon = FALSE;
01274 break;
01275 }
01276 nread = readfile_read;
01277
01278 while(nread--) {
01279 outbuf[0] = *buffer++;
01280 out_count = 1;
01281 if(outbuf[0] == CURL_IAC)
01282 outbuf[out_count++] = CURL_IAC;
01283
01284 Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf,
01285 out_count, &bytes_written);
01286 }
01287 }
01288 break;
01289
01290 case WAIT_OBJECT_0:
01291 if(enum_netevents_func(sockfd, event_handle, &events)
01292 != SOCKET_ERROR) {
01293 if(events.lNetworkEvents & FD_READ) {
01294
01295 (void)Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
01296
01297 telrcv(conn, (unsigned char *)buf, nread);
01298
01299 fflush(stdout);
01300
01301
01302
01303
01304 if(tn->please_negotiate && !tn->already_negotiated) {
01305 negotiate(conn);
01306 tn->already_negotiated = 1;
01307 }
01308 }
01309
01310 if(events.lNetworkEvents & FD_CLOSE) {
01311 keepon = FALSE;
01312 }
01313 }
01314 break;
01315 }
01316 }
01317
01318
01319 if (close_event_func(event_handle) == FALSE) {
01320 infof(data,"WSACloseEvent failed (%d)", SOCKERRNO);
01321 }
01322
01323
01324 create_event_func = NULL;
01325 close_event_func = NULL;
01326 event_select_func = NULL;
01327 enum_netevents_func = NULL;
01328
01329
01330 if (!FreeLibrary(wsock2))
01331 infof(data,"FreeLibrary(wsock2) failed (%d)", ERRNO);
01332 #else
01333 pfd[0].fd = sockfd;
01334 pfd[0].events = POLLIN;
01335 pfd[1].fd = 0;
01336 pfd[1].events = POLLIN;
01337 interval_ms = 1 * 1000;
01338
01339 while (keepon) {
01340 switch (Curl_poll(pfd, 2, interval_ms)) {
01341 case -1:
01342 keepon = FALSE;
01343 continue;
01344 case 0:
01345 break;
01346 default:
01347 if(pfd[1].revents & POLLIN) {
01348 unsigned char outbuf[2];
01349 int out_count = 0;
01350 ssize_t bytes_written;
01351 char *buffer = buf;
01352
01353 nread = read(0, buf, 255);
01354
01355 while(nread--) {
01356 outbuf[0] = *buffer++;
01357 out_count = 1;
01358 if(outbuf[0] == CURL_IAC)
01359 outbuf[out_count++] = CURL_IAC;
01360
01361 Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf,
01362 out_count, &bytes_written);
01363 }
01364 }
01365
01366 if(pfd[0].revents & POLLIN) {
01367
01368 (void)Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
01369
01370
01371
01372 if (nread <= 0) {
01373 keepon = FALSE;
01374 break;
01375 }
01376
01377 telrcv(conn, (unsigned char *)buf, nread);
01378
01379
01380
01381
01382 if(tn->please_negotiate && !tn->already_negotiated) {
01383 negotiate(conn);
01384 tn->already_negotiated = 1;
01385 }
01386 }
01387 }
01388 if(data->set.timeout) {
01389 struct timeval now;
01390 now = Curl_tvnow();
01391 if(Curl_tvdiff(now, conn->created) >= data->set.timeout) {
01392 failf(data, "Time-out");
01393 code = CURLE_OPERATION_TIMEOUTED;
01394 keepon = FALSE;
01395 }
01396 }
01397 }
01398 #endif
01399
01400 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
01401
01402 return code;
01403 }
01404 #endif