1
1
/***************************************************************************
3
* Project ___| | | | _ \| |
5
* | (__| |_| | _ <| |___
3
* Project ___| | | | _ \| |
5
* | (__| |_| | _ <| |___
6
6
* \___|\___/|_| \_\_____|
8
8
* Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
10
10
* This software is licensed as described in the file COPYING, which
11
11
* you should have received as part of this distribution. The terms
12
12
* are also available at http://curl.haxx.se/docs/copyright.html.
14
14
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
15
15
* copies of the Software, and permit persons to whom the Software is
16
16
* furnished to do so, under the terms of the COPYING file.
18
18
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19
19
* KIND, either express or implied.
21
* $Id: telnet.c,v 1.58 2004/03/23 15:28:31 bagder Exp $
21
* $Id: telnet.c,v 1.71 2004/11/19 08:52:33 bagder Exp $
22
22
***************************************************************************/
110
109
void telrcv(struct connectdata *,
111
unsigned char *inbuf, /* Data received from socket */
112
int count); /* Number of bytes received */
110
unsigned char *inbuf, /* Data received from socket */
111
ssize_t count); /* Number of bytes received */
114
113
static void printoption(struct SessionHandle *data,
115
const char *direction,
116
int cmd, int option);
114
const char *direction,
115
int cmd, int option);
118
117
static void negotiate(struct connectdata *);
119
118
static void send_negotiation(struct connectdata *, int cmd, int option);
121
120
static void set_remote_option(struct connectdata *, int cmd, int option);
123
122
static void printsub(struct SessionHandle *data,
124
int direction, unsigned char *pointer, int length);
123
int direction, unsigned char *pointer,
125
125
static void suboption(struct connectdata *);
127
127
/* For negotiation compliant to RFC 1143 */
130
#define CURL_WANTYES 2
131
#define CURL_WANTNO 3
130
#define CURL_WANTYES 2
131
#define CURL_WANTNO 3
134
134
#define CURL_OPPOSITE 1
174
174
check_wsock2 ( struct SessionHandle *data )
177
WORD wVersionRequested;
177
WORD wVersionRequested;
180
180
curlassert(data);
182
182
/* telnet requires at least WinSock 2.0 so ask for it. */
183
183
wVersionRequested = MAKEWORD(2, 0);
185
err = WSAStartup(wVersionRequested, &wsaData);
185
err = WSAStartup(wVersionRequested, &wsaData);
187
187
/* We must've called this once already, so this call */
188
188
/* should always succeed. But, just in case... */
190
190
failf(data,"WSAStartup failed (%d)",err);
191
return CURLE_FAILED_INIT;
191
return CURLE_FAILED_INIT;
194
194
/* We have to have a WSACleanup call for every successful */
214
214
struct TELNET *tn;
216
tn = (struct TELNET *)malloc(sizeof(struct TELNET));
216
tn = (struct TELNET *)calloc(1, sizeof(struct TELNET));
218
218
return CURLE_OUT_OF_MEMORY;
220
220
conn->proto.telnet = (void *)tn; /* make us known */
222
memset(tn, 0, sizeof(struct TELNET));
224
222
tn->telrcv_state = CURL_TS_DATA;
226
224
/* Init suboptions */
227
225
CURL_SB_CLEAR(tn);
229
/* Set all options to NO */
231
/* NO is zero => default fill pattern */
232
memset(tn->us, CURL_NO, 256);
233
memset(tn->usq, CURL_NO, 256);
234
memset(tn->us_preferred, CURL_NO, 256);
235
memset(tn->him, CURL_NO, 256);
236
memset(tn->himq, CURL_NO, 256);
237
memset(tn->him_preferred, CURL_NO, 256);
239
227
/* Set the options we want by default */
240
228
tn->us_preferred[CURL_TELOPT_BINARY] = CURL_YES;
241
229
tn->us_preferred[CURL_TELOPT_SGA] = CURL_YES;
251
239
struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
253
241
for(i = 0;i < CURL_NTELOPTS;i++)
255
243
if(tn->us_preferred[i] == CURL_YES)
256
244
set_local_option(conn, i, CURL_YES);
258
246
if(tn->him_preferred[i] == CURL_YES)
259
247
set_remote_option(conn, i, CURL_YES);
263
251
static void printoption(struct SessionHandle *data,
264
const char *direction, int cmd, int option)
252
const char *direction, int cmd, int option)
269
257
if (data->set.verbose)
271
259
if (cmd == CURL_IAC)
273
261
if (CURL_TELCMD_OK(option))
274
Curl_infof(data, "%s IAC %s\n", direction, CURL_TELCMD(option));
262
infof(data, "%s IAC %s\n", direction, CURL_TELCMD(option));
276
Curl_infof(data, "%s IAC %d\n", direction, option);
264
infof(data, "%s IAC %d\n", direction, option);
292
Curl_infof(data, "%s %s %s\n", direction, fmt, opt);
280
infof(data, "%s %s %s\n", direction, fmt, opt);
294
Curl_infof(data, "%s %s %d\n", direction, fmt, option);
282
infof(data, "%s %s %d\n", direction, fmt, option);
297
Curl_infof(data, "%s %d %d\n", direction, cmd, option);
285
infof(data, "%s %d %d\n", direction, cmd, option);
306
294
buf[0] = CURL_IAC;
310
(void)swrite(conn->sock[FIRSTSOCKET], buf, 3);
298
(void)swrite(conn->sock[FIRSTSOCKET], (char *)buf, 3);
312
300
printoption(conn->data, "SENT", cmd, option);
457
445
/* Already disabled */
461
449
tn->him[option] = CURL_NO;
462
450
send_negotiation(conn, CURL_DONT, option);
465
453
case CURL_WANTNO:
466
454
switch(tn->himq[option])
469
457
tn->him[option] = CURL_NO;
472
460
case CURL_OPPOSITE:
473
461
tn->him[option] = CURL_WANTYES;
474
462
tn->himq[option] = CURL_EMPTY;
637
625
/* Already disabled */
641
629
tn->us[option] = CURL_NO;
642
630
send_negotiation(conn, CURL_WONT, option);
645
633
case CURL_WANTNO:
646
634
switch(tn->usq[option])
649
637
tn->us[option] = CURL_NO;
652
640
case CURL_OPPOSITE:
653
641
tn->us[option] = CURL_WANTYES;
654
642
tn->usq[option] = CURL_EMPTY;
676
664
static void printsub(struct SessionHandle *data,
677
int direction, /* '<' or '>' */
678
unsigned char *pointer, /* where suboption data is */
679
int length) /* length of suboption data */
665
int direction, /* '<' or '>' */
666
unsigned char *pointer, /* where suboption data is */
667
size_t length) /* length of suboption data */
683
671
if (data->set.verbose)
687
Curl_infof(data, "%s IAC SB ", (direction == '<')? "RCVD":"SENT");
675
infof(data, "%s IAC SB ", (direction == '<')? "RCVD":"SENT");
695
683
if (i != CURL_IAC || j != CURL_SE)
697
Curl_infof(data, "(terminated by ");
685
infof(data, "(terminated by ");
698
686
if (CURL_TELOPT_OK(i))
699
Curl_infof(data, "%s ", CURL_TELOPT(i));
687
infof(data, "%s ", CURL_TELOPT(i));
700
688
else if (CURL_TELCMD_OK(i))
701
Curl_infof(data, "%s ", CURL_TELCMD(i));
689
infof(data, "%s ", CURL_TELCMD(i));
703
Curl_infof(data, "%d ", i);
691
infof(data, "%d ", i);
704
692
if (CURL_TELOPT_OK(j))
705
Curl_infof(data, "%s", CURL_TELOPT(j));
693
infof(data, "%s", CURL_TELOPT(j));
706
694
else if (CURL_TELCMD_OK(j))
707
Curl_infof(data, "%s", CURL_TELCMD(j));
695
infof(data, "%s", CURL_TELCMD(j));
709
Curl_infof(data, "%d", j);
710
Curl_infof(data, ", not IAC SE!) ");
697
infof(data, "%d", j);
698
infof(data, ", not IAC SE!) ");
717
Curl_infof(data, "(Empty suboption?)");
705
infof(data, "(Empty suboption?)");
723
711
case CURL_TELOPT_TTYPE:
724
712
case CURL_TELOPT_XDISPLOC:
725
713
case CURL_TELOPT_NEW_ENVIRON:
726
Curl_infof(data, "%s", CURL_TELOPT(pointer[0]));
714
infof(data, "%s", CURL_TELOPT(pointer[0]));
729
Curl_infof(data, "%s (unsupported)", CURL_TELOPT(pointer[0]));
717
infof(data, "%s (unsupported)", CURL_TELOPT(pointer[0]));
734
Curl_infof(data, "%d (unknown)", pointer[i]);
722
infof(data, "%d (unknown)", pointer[i]);
736
724
switch(pointer[1]) {
737
725
case CURL_TELQUAL_IS:
738
Curl_infof(data, " IS");
740
728
case CURL_TELQUAL_SEND:
741
Curl_infof(data, " SEND");
729
infof(data, " SEND");
743
731
case CURL_TELQUAL_INFO:
744
Curl_infof(data, " INFO/REPLY");
732
infof(data, " INFO/REPLY");
746
734
case CURL_TELQUAL_NAME:
747
Curl_infof(data, " NAME");
735
infof(data, " NAME");
751
739
switch(pointer[0]) {
752
740
case CURL_TELOPT_TTYPE:
753
741
case CURL_TELOPT_XDISPLOC:
754
742
pointer[length] = 0;
755
Curl_infof(data, " \"%s\"", &pointer[2]);
743
infof(data, " \"%s\"", &pointer[2]);
757
745
case CURL_TELOPT_NEW_ENVIRON:
758
746
if(pointer[1] == CURL_TELQUAL_IS) {
759
Curl_infof(data, " ");
760
748
for(i = 3;i < length;i++) {
761
749
switch(pointer[i]) {
762
750
case CURL_NEW_ENV_VAR:
763
Curl_infof(data, ", ");
765
753
case CURL_NEW_ENV_VALUE:
766
Curl_infof(data, " = ");
769
Curl_infof(data, "%c", pointer[i]);
757
infof(data, "%c", pointer[i]);
870
858
snprintf((char *)temp, sizeof(temp),
871
859
"%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE,
872
860
CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE);
873
(void)swrite(conn->sock[FIRSTSOCKET], temp, len);
861
(void)swrite(conn->sock[FIRSTSOCKET], (char *)temp, len);
874
862
printsub(data, '>', &temp[2], len-2);
876
864
case CURL_TELOPT_XDISPLOC:
878
866
snprintf((char *)temp, sizeof(temp),
879
867
"%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC,
880
868
CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE);
881
(void)swrite(conn->sock[FIRSTSOCKET], temp, len);
869
(void)swrite(conn->sock[FIRSTSOCKET], (char *)temp, len);
882
870
printsub(data, '>', &temp[2], len-2);
884
872
case CURL_TELOPT_NEW_ENVIRON:
891
879
tmplen = (strlen(v->data) + 1);
892
880
/* Add the variable only if it fits */
893
881
if(len + tmplen < (int)sizeof(temp)-6) {
894
sscanf(v->data, "%127[^,],%s", varname, varval);
882
sscanf(v->data, "%127[^,],%127s", varname, varval);
895
883
snprintf((char *)&temp[len], sizeof(temp) - len,
896
884
"%c%s%c%s", CURL_NEW_ENV_VAR, varname,
897
885
CURL_NEW_ENV_VALUE, varval);
901
889
snprintf((char *)&temp[len], sizeof(temp) - len,
902
890
"%c%c", CURL_IAC, CURL_SE);
904
(void)swrite(conn->sock[FIRSTSOCKET], temp, len);
892
(void)swrite(conn->sock[FIRSTSOCKET], (char *)temp, len);
905
893
printsub(data, '>', &temp[2], len-2);
912
900
void telrcv(struct connectdata *conn,
913
unsigned char *inbuf, /* Data received from socket */
914
int count) /* Number of bytes received */
901
unsigned char *inbuf, /* Data received from socket */
902
ssize_t count) /* Number of bytes received */
987
975
rec_will(conn, c);
988
976
tn->telrcv_state = CURL_TS_DATA;
991
979
case CURL_TS_WONT:
992
980
printoption(data, "RCVD", CURL_WONT, c);
993
981
tn->please_negotiate = 1;
994
982
rec_wont(conn, c);
995
983
tn->telrcv_state = CURL_TS_DATA;
999
987
printoption(data, "RCVD", CURL_DO, c);
1000
988
tn->please_negotiate = 1;
1001
989
rec_do(conn, c);
1002
990
tn->telrcv_state = CURL_TS_DATA;
1005
993
case CURL_TS_DONT:
1006
994
printoption(data, "RCVD", CURL_DONT, c);
1007
995
tn->please_negotiate = 1;
1067
CURLcode Curl_telnet_done(struct connectdata *conn)
1055
CURLcode Curl_telnet_done(struct connectdata *conn, CURLcode status)
1069
1057
struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
1058
(void)status; /* unused */
1070
1060
curl_slist_free_all(tn->telnet_vars);
1072
1062
free(conn->proto.telnet);
1186
/* If stdin_handle is a pipe, use PeekNamedPipe() method to check it,
1187
else use the old WaitForMultipleObjects() way */
1188
if(GetFileType(stdin_handle) == FILE_TYPE_PIPE) {
1189
/* Don't wait for stdin_handle, just wait for event_handle */
1191
/* Check stdin_handle per 100 milliseconds */
1195
wait_timeout = INFINITE;
1194
1198
/* Keep on listening and act on events */
1195
1199
while(keepon) {
1196
waitret = WaitForMultipleObjects(2, objs, FALSE, INFINITE);
1197
switch(waitret - WAIT_OBJECT_0) {
1200
unsigned char outbuf[2];
1202
ssize_t bytes_written;
1200
waitret = WaitForMultipleObjects(obj_count, objs, FALSE, wait_timeout);
1204
unsigned char outbuf[2];
1206
ssize_t bytes_written;
1210
if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL, &readfile_read, NULL)) {
1214
nread = readfile_read;
1219
if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
1220
&readfile_read, NULL)) {
1224
nread = readfile_read;
1227
outbuf[0] = *buffer++;
1229
if(outbuf[0] == CURL_IAC)
1230
outbuf[out_count++] = CURL_IAC;
1232
Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf,
1233
out_count, &bytes_written);
1239
case WAIT_OBJECT_0 + 1:
1241
unsigned char outbuf[2];
1243
ssize_t bytes_written;
1205
1246
if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
1206
1247
&readfile_read, NULL)) {
1207
1248
keepon = FALSE;
1210
1251
nread = readfile_read;
1212
1253
while(nread--) {
1213
1254
outbuf[0] = *buffer++;
1215
1256
if(outbuf[0] == CURL_IAC)
1216
1257
outbuf[out_count++] = CURL_IAC;
1218
1259
Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf,
1219
1260
out_count, &bytes_written);
1225
1266
if(enum_netevents_func(sockfd, event_handle, &events)
1226
1267
!= SOCKET_ERROR) {
1227
1268
if(events.lNetworkEvents & FD_READ) {
1228
1269
/* This reallu OUGHT to check its return code. */
1229
1270
(void)Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
1231
1272
telrcv(conn, (unsigned char *)buf, nread);
1233
1274
fflush(stdout);
1235
1276
/* Negotiate if the peer has started negotiating,
1236
1277
otherwise don't. We don't want to speak telnet with
1237
1278
non-telnet servers, like POP or SMTP. */
1264
1305
if (!FreeLibrary(wsock2))
1265
1306
infof(data,"FreeLibrary(wsock2) failed (%d)",GetLastError());
1267
FD_ZERO (&readfd); /* clear it */
1268
FD_SET (sockfd, &readfd);
1269
FD_SET (0, &readfd);
1309
pfd[0].events = POLLIN;
1311
pfd[1].events = POLLIN;
1312
interval_ms = 1 * 1000;
1273
1314
while (keepon) {
1274
struct timeval interval;
1276
readfd = keepfd; /* set this every lap in the loop */
1277
interval.tv_sec = 1;
1278
interval.tv_usec = 0;
1280
switch (select (sockfd + 1, &readfd, NULL, NULL, &interval)) {
1281
case -1: /* error, stop reading */
1315
switch (Curl_poll(pfd, 2, interval_ms)) {
1316
case -1: /* error, stop reading */
1282
1317
keepon = FALSE;
1284
case 0: /* timeout */
1319
case 0: /* timeout */
1286
default: /* read! */
1287
if(FD_ISSET(0, &readfd)) { /* read from stdin */
1321
default: /* read! */
1322
if(pfd[1].revents & POLLIN) { /* read from stdin */
1288
1323
unsigned char outbuf[2];
1289
1324
int out_count = 0;
1290
1325
ssize_t bytes_written;
1291
1326
char *buffer = buf;
1293
1328
nread = read(0, buf, 255);
1295
1330
while(nread--) {
1298
1333
if(outbuf[0] == CURL_IAC)
1299
1334
outbuf[out_count++] = CURL_IAC;
1301
1336
Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf,
1302
1337
out_count, &bytes_written);
1306
if(FD_ISSET(sockfd, &readfd)) {
1341
if(pfd[0].revents & POLLIN) {
1307
1342
/* This OUGHT to check the return code... */
1308
1343
(void)Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);