1 /*****************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * The contents of this file are subject to the Mozilla Public License
9 * Version 1.0 (the "License"); you may not use this file except in
10 * compliance with the License. You may obtain a copy of the License at
11 * http://www.mozilla.org/MPL/
13 * Software distributed under the License is distributed on an "AS IS"
14 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
15 * License for the specific language governing rights and limitations
18 * The Original Code is Curl.
20 * The Initial Developer of the Original Code is Daniel Stenberg.
22 * Portions created by the Initial Developer are Copyright (C) 1998.
23 * All Rights Reserved.
25 * ------------------------------------------------------------
27 * - Daniel Stenberg <Daniel.Stenberg@haxx.nu>
31 * $Source: /cvsroot/curl/curl/lib/telnet.c,v $
32 * $Revision: 1.1.1.1 $
33 * $Date: 1999-12-29 14:21:38 $
38 * ------------------------------------------------------------
40 * This implementation of the TELNET protocol is written by
41 * Linus Nielsen <Linus.Nielsen@haxx.nu>,
42 * with some code snippets stolen from the BSD Telnet client.
44 * The negotiation is performed according to RFC 1143 (D. Bernstein,
45 * "The Q Method of Implementing TELNET Option Negotiation")
47 ****************************************************************************/
49 /* -- WIN32 approved -- */
55 #include <sys/types.h>
62 #if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
67 #ifdef HAVE_SYS_SOCKET_H
68 #include <sys/socket.h>
70 #include <netinet/in.h>
72 #include <sys/resource.h>
77 #ifdef HAVE_ARPA_INET_H
78 #include <arpa/inet.h>
83 #include <sys/ioctl.h>
86 #ifdef HAVE_SYS_PARAM_H
87 #include <sys/param.h>
90 #ifdef HAVE_SYS_SELECT_H
91 #include <sys/select.h>
98 #include <curl/curl.h>
101 #include "formdata.h"
102 #include "progress.h"
104 #define _MPRINTF_REPLACE /* use our functions only */
105 #include <curl/mprintf.h>
111 #include "arpa_telnet.h"
113 #define SUBBUFSIZE 512
115 #define SB_CLEAR() subpointer = subbuffer;
116 #define SB_TERM() { subend = subpointer; SB_CLEAR(); }
117 #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \
118 *subpointer++ = (c); \
121 #define SB_GET() ((*subpointer++)&0xff)
122 #define SB_PEEK() ((*subpointer)&0xff)
123 #define SB_EOF() (subpointer >= subend)
124 #define SB_LEN() (subend - subpointer)
126 void telwrite(struct UrlData
*data
,
127 unsigned char *buffer
, /* Data to write */
128 int count
); /* Number of bytes to write */
130 void telrcv(struct UrlData
*data
,
131 unsigned char *inbuf
, /* Data received from socket */
132 int count
); /* Number of bytes received */
134 static void printoption(struct UrlData
*data
,
135 const char *direction
,
136 int cmd
, int option
);
138 static void negotiate(struct UrlData
*data
);
139 static void send_negotiation(struct UrlData
*data
, int cmd
, int option
);
140 static void set_local_option(struct UrlData
*data
, int cmd
, int option
);
141 static void set_remote_option(struct UrlData
*data
, int cmd
, int option
);
143 static void printsub(struct UrlData
*data
,
144 int direction
, unsigned char *pointer
, int length
);
145 static void suboption(struct UrlData
*data
);
148 static char subbuffer
[SUBBUFSIZE
];
149 static char *subpointer
, *subend
; /* buffer for sub-options */
152 * Telnet receiver states for fsm
163 TS_SB
, /* sub-option collection */
164 TS_SE
/* looking for sub-option end */
167 /* For negotiation compliant to RFC 1143 */
178 static int us_preferred
[256];
180 static int himq
[256];
181 static int him_preferred
[256];
183 void init_telnet(struct UrlData
*data
)
185 telrcv_state
= TS_DATA
;
187 /* Init suboptions */
190 /* Set all options to NO */
192 memset(usq
, NO
, 256);
193 memset(us_preferred
, NO
, 256);
194 memset(him
, NO
, 256);
195 memset(himq
, NO
, 256);
196 memset(him_preferred
, NO
, 256);
198 /* Set the options we want */
199 us_preferred
[TELOPT_BINARY
] = YES
;
200 us_preferred
[TELOPT_SGA
] = YES
;
201 him_preferred
[TELOPT_BINARY
] = YES
;
202 him_preferred
[TELOPT_SGA
] = YES
;
204 /* Start negotiating */
208 static void negotiate(struct UrlData
*data
)
212 for(i
= 0;i
< NTELOPTS
;i
++)
214 if(us_preferred
[i
] == YES
)
215 set_local_option(data
, i
, YES
);
217 if(him_preferred
[i
] == YES
)
218 set_remote_option(data
, i
, YES
);
222 static void printoption(struct UrlData
*data
,
223 const char *direction
, int cmd
, int option
)
228 if (data
->conf
& CONF_VERBOSE
)
232 if (TELCMD_OK(option
))
233 printf("%s IAC %s\n", direction
, TELCMD(option
));
235 printf("%s IAC %d\n", direction
, option
);
239 fmt
= (cmd
== WILL
) ? "WILL" : (cmd
== WONT
) ? "WONT" :
240 (cmd
== DO
) ? "DO" : (cmd
== DONT
) ? "DONT" : 0;
243 if (TELOPT_OK(option
))
244 opt
= TELOPT(option
);
245 else if (option
== TELOPT_EXOPL
)
251 printf("%s %s %s\n", direction
, fmt
, opt
);
253 printf("%s %s %d\n", direction
, fmt
, option
);
256 printf("%s %d %d\n", direction
, cmd
, option
);
261 static void send_negotiation(struct UrlData
*data
, int cmd
, int option
)
263 unsigned char buf
[3];
269 swrite(data
->firstsocket
, buf
, 3);
271 printoption(data
, "SENT", cmd
, option
);
274 void set_remote_option(struct UrlData
*data
, int option
, int newstate
)
281 him
[option
] = WANTYES
;
282 send_negotiation(data
, DO
, option
);
286 /* Already enabled */
293 /* Already negotiating for YES, queue the request */
294 himq
[option
] = OPPOSITE
;
297 /* Error: already queued an enable request */
306 /* Error: already negotiating for enable */
309 himq
[option
] = EMPTY
;
320 /* Already disabled */
324 him
[option
] = WANTNO
;
325 send_negotiation(data
, DONT
, option
);
332 /* Already negotiating for NO */
335 himq
[option
] = EMPTY
;
344 himq
[option
] = OPPOSITE
;
354 void rec_will(struct UrlData
*data
, int option
)
359 if(him_preferred
[option
] == YES
)
362 send_negotiation(data
, DO
, option
);
366 send_negotiation(data
, DONT
, option
);
371 /* Already enabled */
378 /* Error: DONT answered by WILL */
382 /* Error: DONT answered by WILL */
384 himq
[option
] = EMPTY
;
396 him
[option
] = WANTNO
;
397 himq
[option
] = EMPTY
;
398 send_negotiation(data
, DONT
, option
);
405 void rec_wont(struct UrlData
*data
, int option
)
410 /* Already disabled */
415 send_negotiation(data
, DONT
, option
);
426 him
[option
] = WANTYES
;
427 himq
[option
] = EMPTY
;
428 send_negotiation(data
, DO
, option
);
441 himq
[option
] = EMPTY
;
448 void set_local_option(struct UrlData
*data
, int option
, int newstate
)
455 us
[option
] = WANTYES
;
456 send_negotiation(data
, WILL
, option
);
460 /* Already enabled */
467 /* Already negotiating for YES, queue the request */
468 usq
[option
] = OPPOSITE
;
471 /* Error: already queued an enable request */
480 /* Error: already negotiating for enable */
494 /* Already disabled */
499 send_negotiation(data
, WONT
, option
);
506 /* Already negotiating for NO */
518 usq
[option
] = OPPOSITE
;
528 void rec_do(struct UrlData
*data
, int option
)
533 if(us_preferred
[option
] == YES
)
536 send_negotiation(data
, WILL
, option
);
540 send_negotiation(data
, WONT
, option
);
545 /* Already enabled */
552 /* Error: DONT answered by WILL */
556 /* Error: DONT answered by WILL */
571 himq
[option
] = EMPTY
;
572 send_negotiation(data
, WONT
, option
);
579 void rec_dont(struct UrlData
*data
, int option
)
584 /* Already disabled */
589 send_negotiation(data
, WONT
, option
);
600 us
[option
] = WANTYES
;
602 send_negotiation(data
, WILL
, option
);
623 static void printsub(struct UrlData
*data
,
624 int direction
, /* '<' or '>' */
625 unsigned char *pointer
, /* where suboption data is */
626 int length
) /* length of suboption data */
631 if (data
->conf
& CONF_VERBOSE
)
635 printf("%s IAC SB ", (direction
== '<')? "RCVD":"SENT");
640 i
= pointer
[length
-2];
641 j
= pointer
[length
-1];
643 if (i
!= IAC
|| j
!= SE
)
645 printf("(terminated by ");
647 printf("%s ", TELOPT(i
));
648 else if (TELCMD_OK(i
))
649 printf("%s ", TELCMD(i
));
653 printf("%s", TELOPT(j
));
654 else if (TELCMD_OK(j
))
655 printf("%s", TELCMD(j
));
658 printf(", not IAC SE!) ");
665 printf("(Empty suboption?)");
669 if (TELOPT_OK(pointer
[0]))
670 printf("%s (unknown)", TELOPT(pointer
[0]));
672 printf("%d (unknown)", pointer
[i
]);
673 for (i
= 1; i
< length
; i
++)
674 printf(" %d", pointer
[i
]);
686 * Look at the sub-option buffer, and try to be helpful to the other
688 * No suboptions are supported yet.
691 static void suboption(struct UrlData
*data
)
693 printsub(data
, '<', (unsigned char *)subbuffer
, SB_LEN()+2);
697 void telrcv(struct UrlData
*data
,
698 unsigned char *inbuf
, /* Data received from socket */
699 int count
) /* Number of bytes received */
708 switch (telrcv_state
)
711 telrcv_state
= TS_DATA
;
714 break; /* Ignore \0 after CR */
717 data
->fwrite((char *)&c
, 1, 1, data
->out
);
723 telrcv_state
= TS_IAC
;
728 telrcv_state
= TS_CR
;
731 data
->fwrite((char *)&c
, 1, 1, data
->out
);
739 telrcv_state
= TS_WILL
;
742 telrcv_state
= TS_WONT
;
745 telrcv_state
= TS_DO
;
748 telrcv_state
= TS_DONT
;
752 telrcv_state
= TS_SB
;
755 data
->fwrite((char *)&c
, 1, 1, data
->out
);
761 printoption(data
, "RCVD", IAC
, c
);
764 telrcv_state
= TS_DATA
;
768 printoption(data
, "RCVD", WILL
, c
);
770 telrcv_state
= TS_DATA
;
774 printoption(data
, "RCVD", WONT
, c
);
776 telrcv_state
= TS_DATA
;
780 printoption(data
, "RCVD", DO
, c
);
782 telrcv_state
= TS_DATA
;
786 printoption(data
, "RCVD", DONT
, c
);
788 telrcv_state
= TS_DATA
;
794 telrcv_state
= TS_SE
;
808 * This is an error. We only expect to get
809 * "IAC IAC" or "IAC SE". Several things may
810 * have happend. An IAC was not doubled, the
811 * IAC SE was left off, or another option got
812 * inserted into the suboption are all possibilities.
813 * If we assume that the IAC was not doubled,
814 * and really the IAC SE was left off, we could
815 * get into an infinate loop here. So, instead,
816 * we terminate the suboption, and process the
817 * partial suboption if we can.
819 SB_ACCUM((unsigned char)IAC
);
824 printoption(data
, "In SUBOPTION processing, RCVD", IAC
, c
);
825 suboption(data
); /* handle sub-option */
826 telrcv_state
= TS_IAC
;
830 telrcv_state
= TS_SB
;
834 SB_ACCUM((unsigned char)IAC
);
835 SB_ACCUM((unsigned char)SE
);
838 suboption(data
); /* handle sub-option */
839 telrcv_state
= TS_DATA
;
846 void telwrite(struct UrlData
*data
,
847 unsigned char *buffer
, /* Data to write */
848 int count
) /* Number of bytes to write */
850 unsigned char outbuf
[2];
856 outbuf
[0] = *buffer
++;
859 outbuf
[out_count
++] = IAC
;
862 bytes_written
= swrite(data
->firstsocket
, outbuf
, out_count
);
865 bytes_written
= SSL_write(data
->ssl
, (char *)outbuf
, out_count
);
868 bytes_written
= swrite(data
->firstsocket
, outbuf
, out_count
);
870 #endif /* USE_SSLEAY */
874 UrgError
telnet(struct UrlData
*data
)
876 int sockfd
= data
->firstsocket
;
881 char *buf
= data
->buffer
;
886 FD_ZERO (&readfd
); /* clear it */
887 FD_SET (sockfd
, &readfd
);
894 readfd
= keepfd
; /* set this every lap in the loop */
896 switch (select (sockfd
+ 1, &readfd
, NULL
, NULL
, NULL
))
898 case -1: /* error, stop reading */
901 case 0: /* timeout */
904 if(FD_ISSET(1, &readfd
))
906 nread
= read(1, buf
, 255);
907 telwrite(data
, (unsigned char *)buf
, nread
);
910 if(FD_ISSET(sockfd
, &readfd
))
913 nread
= sread (sockfd
, buf
, BUFSIZE
- 1);
916 nread
= SSL_read (data
->ssl
, buf
, BUFSIZE
- 1);
919 nread
= sread (sockfd
, buf
, BUFSIZE
- 1);
921 #endif /* USE_SSLEAY */
924 /* if we receive 0 or less here, the server closed the connection and
925 we bail out from this! */
931 telrcv(data
, (unsigned char *)buf
, nread
);