David Phillips' FD_SETSIZE fix
[platform/upstream/curl.git] / lib / telnet.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
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 http://curl.haxx.se/docs/copyright.html.
13  *
14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15  * copies of the Software, and permit persons to whom the Software is
16  * furnished to do so, under the terms of the COPYING file.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  * $Id$
22  ***************************************************************************/
23
24 #include "setup.h"
25
26 #ifndef CURL_DISABLE_TELNET
27 /* -- WIN32 approved -- */
28 #include <stdio.h>
29 #include <string.h>
30 #include <stdarg.h>
31 #include <stdlib.h>
32 #include <ctype.h>
33 #ifdef HAVE_SYS_TYPES_H
34 #include <sys/types.h>
35 #endif
36 #ifdef HAVE_SYS_STAT_H
37 #include <sys/stat.h>
38 #endif
39 #include <errno.h>
40
41 #if defined(WIN32)
42 #include <time.h>
43 #include <io.h>
44 #else
45 #ifdef HAVE_SYS_SOCKET_H
46 #include <sys/socket.h>
47 #endif
48 #include <netinet/in.h>
49 #include <sys/time.h>
50 #ifdef HAVE_UNISTD_H
51 #include <unistd.h>
52 #endif
53 #include <netdb.h>
54 #ifdef HAVE_ARPA_INET_H
55 #include <arpa/inet.h>
56 #endif
57 #ifdef HAVE_NET_IF_H
58 #include <net/if.h>
59 #endif
60 #include <sys/ioctl.h>
61 #include <signal.h>
62
63 #ifdef HAVE_SYS_PARAM_H
64 #include <sys/param.h>
65 #endif
66
67
68 #endif
69
70 #include "urldata.h"
71 #include <curl/curl.h>
72 #include "transfer.h"
73 #include "sendf.h"
74 #include "telnet.h"
75
76 #define _MPRINTF_REPLACE /* use our functions only */
77 #include <curl/mprintf.h>
78
79 #define  TELOPTS
80 #define  TELCMDS
81
82 #include "arpa_telnet.h"
83 #include "memory.h"
84 #include "select.h"
85
86 /* The last #include file should be: */
87 #include "memdebug.h"
88
89 #define SUBBUFSIZE 512
90
91 #define CURL_SB_CLEAR(x)  x->subpointer = x->subbuffer;
92 #define CURL_SB_TERM(x)   { x->subend = x->subpointer; CURL_SB_CLEAR(x); }
93 #define CURL_SB_ACCUM(x,c) \
94   if (x->subpointer < (x->subbuffer+sizeof x->subbuffer)) { \
95     *x->subpointer++ = (c); \
96   }
97
98 #define  CURL_SB_GET(x) ((*x->subpointer++)&0xff)
99 #define  CURL_SB_PEEK(x)   ((*x->subpointer)&0xff)
100 #define  CURL_SB_EOF(x) (x->subpointer >= x->subend)
101 #define  CURL_SB_LEN(x) (x->subend - x->subpointer)
102
103 #ifdef WIN32
104 typedef FARPROC WSOCK2_FUNC;
105 static CURLcode check_wsock2 ( struct SessionHandle *data );
106 #endif
107
108 static
109 void telrcv(struct connectdata *,
110             unsigned char *inbuf,       /* Data received from socket */
111             ssize_t count);             /* Number of bytes received */
112
113 static void printoption(struct SessionHandle *data,
114                         const char *direction,
115                         int cmd, int option);
116
117 static void negotiate(struct connectdata *);
118 static void send_negotiation(struct connectdata *, int cmd, int option);
119 static void set_local_option(struct connectdata *, int cmd, int option);
120 static void set_remote_option(struct connectdata *, int cmd, int option);
121
122 static void printsub(struct SessionHandle *data,
123                      int direction, unsigned char *pointer,
124                      size_t length);
125 static void suboption(struct connectdata *);
126
127 /* For negotiation compliant to RFC 1143 */
128 #define CURL_NO          0
129 #define CURL_YES         1
130 #define CURL_WANTYES     2
131 #define CURL_WANTNO      3
132
133 #define CURL_EMPTY       0
134 #define CURL_OPPOSITE    1
135
136 /*
137  * Telnet receiver states for fsm
138  */
139 typedef enum
140 {
141    CURL_TS_DATA = 0,
142    CURL_TS_IAC,
143    CURL_TS_WILL,
144    CURL_TS_WONT,
145    CURL_TS_DO,
146    CURL_TS_DONT,
147    CURL_TS_CR,
148    CURL_TS_SB,   /* sub-option collection */
149    CURL_TS_SE   /* looking for sub-option end */
150 } TelnetReceive;
151
152 struct TELNET {
153   int please_negotiate;
154   int already_negotiated;
155   int us[256];
156   int usq[256];
157   int us_preferred[256];
158   int him[256];
159   int himq[256];
160   int him_preferred[256];
161   char subopt_ttype[32];             /* Set with suboption TTYPE */
162   char subopt_xdisploc[128];          /* Set with suboption XDISPLOC */
163   struct curl_slist *telnet_vars; /* Environment variables */
164
165   /* suboptions */
166   char subbuffer[SUBBUFSIZE];
167   char *subpointer, *subend;      /* buffer for sub-options */
168
169   TelnetReceive telrcv_state;
170 };
171
172 #ifdef WIN32
173 static CURLcode
174 check_wsock2 ( struct SessionHandle *data )
175 {
176   int err;
177   WORD wVersionRequested;
178   WSADATA wsaData;
179
180   curlassert(data);
181
182   /* telnet requires at least WinSock 2.0 so ask for it. */
183   wVersionRequested = MAKEWORD(2, 0);
184
185   err = WSAStartup(wVersionRequested, &wsaData);
186
187   /* We must've called this once already, so this call */
188   /* should always succeed.  But, just in case... */
189   if (err != 0) {
190     failf(data,"WSAStartup failed (%d)",err);
191     return CURLE_FAILED_INIT;
192   }
193
194   /* We have to have a WSACleanup call for every successful */
195   /* WSAStartup call. */
196   WSACleanup();
197
198   /* Check that our version is supported */
199   if (LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) ||
200       HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested)) {
201       /* Our version isn't supported */
202       failf(data,"insufficient winsock version to support "
203             "telnet");
204       return CURLE_FAILED_INIT;
205   }
206
207   /* Our version is supported */
208   return CURLE_OK;
209 }
210 #endif
211 static
212 CURLcode init_telnet(struct connectdata *conn)
213 {
214   struct TELNET *tn;
215
216   tn = (struct TELNET *)calloc(1, sizeof(struct TELNET));
217   if(!tn)
218     return CURLE_OUT_OF_MEMORY;
219
220   conn->proto.telnet = (void *)tn; /* make us known */
221
222   tn->telrcv_state = CURL_TS_DATA;
223
224   /* Init suboptions */
225   CURL_SB_CLEAR(tn);
226
227   /* Set the options we want by default */
228   tn->us_preferred[CURL_TELOPT_BINARY] = CURL_YES;
229   tn->us_preferred[CURL_TELOPT_SGA] = CURL_YES;
230   tn->him_preferred[CURL_TELOPT_BINARY] = CURL_YES;
231   tn->him_preferred[CURL_TELOPT_SGA] = CURL_YES;
232
233   return CURLE_OK;
234 }
235
236 static void negotiate(struct connectdata *conn)
237 {
238   int i;
239   struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
240
241   for(i = 0;i < CURL_NTELOPTS;i++)
242   {
243     if(tn->us_preferred[i] == CURL_YES)
244       set_local_option(conn, i, CURL_YES);
245
246     if(tn->him_preferred[i] == CURL_YES)
247       set_remote_option(conn, i, CURL_YES);
248   }
249 }
250
251 static void printoption(struct SessionHandle *data,
252                         const char *direction, int cmd, int option)
253 {
254   const char *fmt;
255   const char *opt;
256
257   if (data->set.verbose)
258   {
259     if (cmd == CURL_IAC)
260     {
261       if (CURL_TELCMD_OK(option))
262         infof(data, "%s IAC %s\n", direction, CURL_TELCMD(option));
263       else
264         infof(data, "%s IAC %d\n", direction, option);
265     }
266     else
267     {
268       fmt = (cmd == CURL_WILL) ? "WILL" : (cmd == CURL_WONT) ? "WONT" :
269         (cmd == CURL_DO) ? "DO" : (cmd == CURL_DONT) ? "DONT" : 0;
270       if (fmt)
271       {
272         if (CURL_TELOPT_OK(option))
273           opt = CURL_TELOPT(option);
274         else if (option == CURL_TELOPT_EXOPL)
275           opt = "EXOPL";
276         else
277           opt = NULL;
278
279         if(opt)
280           infof(data, "%s %s %s\n", direction, fmt, opt);
281         else
282           infof(data, "%s %s %d\n", direction, fmt, option);
283       }
284       else
285         infof(data, "%s %d %d\n", direction, cmd, option);
286     }
287   }
288 }
289
290 static void send_negotiation(struct connectdata *conn, int cmd, int option)
291 {
292    unsigned char buf[3];
293
294    buf[0] = CURL_IAC;
295    buf[1] = cmd;
296    buf[2] = option;
297
298    (void)swrite(conn->sock[FIRSTSOCKET], (char *)buf, 3);
299
300    printoption(conn->data, "SENT", cmd, option);
301 }
302
303 static
304 void set_remote_option(struct connectdata *conn, int option, int newstate)
305 {
306   struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
307   if(newstate == CURL_YES)
308   {
309     switch(tn->him[option])
310     {
311       case CURL_NO:
312         tn->him[option] = CURL_WANTYES;
313         send_negotiation(conn, CURL_DO, option);
314         break;
315
316       case CURL_YES:
317         /* Already enabled */
318         break;
319
320       case CURL_WANTNO:
321         switch(tn->himq[option])
322         {
323           case CURL_EMPTY:
324             /* Already negotiating for CURL_YES, queue the request */
325             tn->himq[option] = CURL_OPPOSITE;
326             break;
327           case CURL_OPPOSITE:
328             /* Error: already queued an enable request */
329             break;
330         }
331         break;
332
333       case CURL_WANTYES:
334         switch(tn->himq[option])
335         {
336           case CURL_EMPTY:
337             /* Error: already negotiating for enable */
338             break;
339           case CURL_OPPOSITE:
340             tn->himq[option] = CURL_EMPTY;
341             break;
342         }
343         break;
344     }
345   }
346   else /* NO */
347   {
348     switch(tn->him[option])
349     {
350       case CURL_NO:
351         /* Already disabled */
352         break;
353
354       case CURL_YES:
355         tn->him[option] = CURL_WANTNO;
356         send_negotiation(conn, CURL_DONT, option);
357         break;
358
359       case CURL_WANTNO:
360         switch(tn->himq[option])
361         {
362           case CURL_EMPTY:
363             /* Already negotiating for NO */
364             break;
365           case CURL_OPPOSITE:
366             tn->himq[option] = CURL_EMPTY;
367             break;
368         }
369         break;
370
371       case CURL_WANTYES:
372         switch(tn->himq[option])
373         {
374           case CURL_EMPTY:
375             tn->himq[option] = CURL_OPPOSITE;
376             break;
377           case CURL_OPPOSITE:
378             break;
379         }
380         break;
381     }
382   }
383 }
384
385 static
386 void rec_will(struct connectdata *conn, int option)
387 {
388   struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
389   switch(tn->him[option])
390   {
391     case CURL_NO:
392       if(tn->him_preferred[option] == CURL_YES)
393       {
394         tn->him[option] = CURL_YES;
395         send_negotiation(conn, CURL_DO, option);
396       }
397       else
398       {
399         send_negotiation(conn, CURL_DONT, option);
400       }
401       break;
402
403     case CURL_YES:
404       /* Already enabled */
405       break;
406
407     case CURL_WANTNO:
408       switch(tn->himq[option])
409       {
410         case CURL_EMPTY:
411           /* Error: DONT answered by WILL */
412           tn->him[option] = CURL_NO;
413           break;
414         case CURL_OPPOSITE:
415           /* Error: DONT answered by WILL */
416           tn->him[option] = CURL_YES;
417           tn->himq[option] = CURL_EMPTY;
418           break;
419       }
420       break;
421
422     case CURL_WANTYES:
423       switch(tn->himq[option])
424       {
425         case CURL_EMPTY:
426           tn->him[option] = CURL_YES;
427           break;
428         case CURL_OPPOSITE:
429           tn->him[option] = CURL_WANTNO;
430           tn->himq[option] = CURL_EMPTY;
431           send_negotiation(conn, CURL_DONT, option);
432           break;
433       }
434       break;
435   }
436 }
437
438 static
439 void rec_wont(struct connectdata *conn, int option)
440 {
441   struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
442   switch(tn->him[option])
443   {
444     case CURL_NO:
445       /* Already disabled */
446       break;
447
448     case CURL_YES:
449       tn->him[option] = CURL_NO;
450       send_negotiation(conn, CURL_DONT, option);
451       break;
452
453     case CURL_WANTNO:
454       switch(tn->himq[option])
455       {
456         case CURL_EMPTY:
457           tn->him[option] = CURL_NO;
458           break;
459
460         case CURL_OPPOSITE:
461           tn->him[option] = CURL_WANTYES;
462           tn->himq[option] = CURL_EMPTY;
463           send_negotiation(conn, CURL_DO, option);
464           break;
465       }
466       break;
467
468     case CURL_WANTYES:
469       switch(tn->himq[option])
470       {
471         case CURL_EMPTY:
472           tn->him[option] = CURL_NO;
473           break;
474         case CURL_OPPOSITE:
475           tn->him[option] = CURL_NO;
476           tn->himq[option] = CURL_EMPTY;
477           break;
478       }
479       break;
480   }
481 }
482
483 static void
484 set_local_option(struct connectdata *conn, int option, int newstate)
485 {
486   struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
487   if(newstate == CURL_YES)
488   {
489     switch(tn->us[option])
490     {
491       case CURL_NO:
492         tn->us[option] = CURL_WANTYES;
493         send_negotiation(conn, CURL_WILL, option);
494         break;
495
496       case CURL_YES:
497         /* Already enabled */
498         break;
499
500       case CURL_WANTNO:
501         switch(tn->usq[option])
502         {
503           case CURL_EMPTY:
504             /* Already negotiating for CURL_YES, queue the request */
505             tn->usq[option] = CURL_OPPOSITE;
506             break;
507           case CURL_OPPOSITE:
508             /* Error: already queued an enable request */
509             break;
510         }
511         break;
512
513       case CURL_WANTYES:
514         switch(tn->usq[option])
515         {
516           case CURL_EMPTY:
517             /* Error: already negotiating for enable */
518             break;
519           case CURL_OPPOSITE:
520             tn->usq[option] = CURL_EMPTY;
521             break;
522         }
523         break;
524     }
525   }
526   else /* NO */
527   {
528     switch(tn->us[option])
529     {
530       case CURL_NO:
531         /* Already disabled */
532         break;
533
534       case CURL_YES:
535         tn->us[option] = CURL_WANTNO;
536         send_negotiation(conn, CURL_WONT, option);
537         break;
538
539       case CURL_WANTNO:
540         switch(tn->usq[option])
541         {
542           case CURL_EMPTY:
543             /* Already negotiating for NO */
544             break;
545           case CURL_OPPOSITE:
546             tn->usq[option] = CURL_EMPTY;
547             break;
548         }
549         break;
550
551       case CURL_WANTYES:
552         switch(tn->usq[option])
553         {
554           case CURL_EMPTY:
555             tn->usq[option] = CURL_OPPOSITE;
556             break;
557           case CURL_OPPOSITE:
558             break;
559         }
560         break;
561     }
562   }
563 }
564
565 static
566 void rec_do(struct connectdata *conn, int option)
567 {
568   struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
569   switch(tn->us[option])
570   {
571     case CURL_NO:
572       if(tn->us_preferred[option] == CURL_YES)
573       {
574         tn->us[option] = CURL_YES;
575         send_negotiation(conn, CURL_WILL, option);
576       }
577       else
578       {
579         send_negotiation(conn, CURL_WONT, option);
580       }
581       break;
582
583     case CURL_YES:
584       /* Already enabled */
585       break;
586
587     case CURL_WANTNO:
588       switch(tn->usq[option])
589       {
590         case CURL_EMPTY:
591           /* Error: DONT answered by WILL */
592           tn->us[option] = CURL_NO;
593           break;
594         case CURL_OPPOSITE:
595           /* Error: DONT answered by WILL */
596           tn->us[option] = CURL_YES;
597           tn->usq[option] = CURL_EMPTY;
598           break;
599       }
600       break;
601
602     case CURL_WANTYES:
603       switch(tn->usq[option])
604       {
605         case CURL_EMPTY:
606           tn->us[option] = CURL_YES;
607           break;
608         case CURL_OPPOSITE:
609           tn->us[option] = CURL_WANTNO;
610           tn->himq[option] = CURL_EMPTY;
611           send_negotiation(conn, CURL_WONT, option);
612           break;
613       }
614       break;
615   }
616 }
617
618 static
619 void rec_dont(struct connectdata *conn, int option)
620 {
621   struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
622   switch(tn->us[option])
623   {
624     case CURL_NO:
625       /* Already disabled */
626       break;
627
628     case CURL_YES:
629       tn->us[option] = CURL_NO;
630       send_negotiation(conn, CURL_WONT, option);
631       break;
632
633     case CURL_WANTNO:
634       switch(tn->usq[option])
635       {
636         case CURL_EMPTY:
637           tn->us[option] = CURL_NO;
638           break;
639
640         case CURL_OPPOSITE:
641           tn->us[option] = CURL_WANTYES;
642           tn->usq[option] = CURL_EMPTY;
643           send_negotiation(conn, CURL_WILL, option);
644           break;
645       }
646       break;
647
648     case CURL_WANTYES:
649       switch(tn->usq[option])
650       {
651         case CURL_EMPTY:
652           tn->us[option] = CURL_NO;
653           break;
654         case CURL_OPPOSITE:
655           tn->us[option] = CURL_NO;
656           tn->usq[option] = CURL_EMPTY;
657           break;
658       }
659       break;
660   }
661 }
662
663
664 static void printsub(struct SessionHandle *data,
665                      int direction,             /* '<' or '>' */
666                      unsigned char *pointer,    /* where suboption data is */
667                      size_t length)             /* length of suboption data */
668 {
669   unsigned int i = 0;
670
671   if (data->set.verbose)
672   {
673     if (direction)
674     {
675       infof(data, "%s IAC SB ", (direction == '<')? "RCVD":"SENT");
676       if (length >= 3)
677       {
678         int j;
679
680         i = pointer[length-2];
681         j = pointer[length-1];
682
683         if (i != CURL_IAC || j != CURL_SE)
684         {
685           infof(data, "(terminated by ");
686           if (CURL_TELOPT_OK(i))
687             infof(data, "%s ", CURL_TELOPT(i));
688           else if (CURL_TELCMD_OK(i))
689             infof(data, "%s ", CURL_TELCMD(i));
690           else
691             infof(data, "%d ", i);
692           if (CURL_TELOPT_OK(j))
693             infof(data, "%s", CURL_TELOPT(j));
694           else if (CURL_TELCMD_OK(j))
695             infof(data, "%s", CURL_TELCMD(j));
696           else
697             infof(data, "%d", j);
698           infof(data, ", not IAC SE!) ");
699         }
700       }
701       length -= 2;
702     }
703     if (length < 1)
704     {
705       infof(data, "(Empty suboption?)");
706       return;
707     }
708
709     if (CURL_TELOPT_OK(pointer[0])) {
710       switch(pointer[0]) {
711         case CURL_TELOPT_TTYPE:
712         case CURL_TELOPT_XDISPLOC:
713         case CURL_TELOPT_NEW_ENVIRON:
714           infof(data, "%s", CURL_TELOPT(pointer[0]));
715           break;
716         default:
717           infof(data, "%s (unsupported)", CURL_TELOPT(pointer[0]));
718           break;
719       }
720     }
721     else
722       infof(data, "%d (unknown)", pointer[i]);
723
724     switch(pointer[1]) {
725       case CURL_TELQUAL_IS:
726         infof(data, " IS");
727         break;
728       case CURL_TELQUAL_SEND:
729         infof(data, " SEND");
730         break;
731       case CURL_TELQUAL_INFO:
732         infof(data, " INFO/REPLY");
733         break;
734       case CURL_TELQUAL_NAME:
735         infof(data, " NAME");
736         break;
737     }
738
739     switch(pointer[0]) {
740       case CURL_TELOPT_TTYPE:
741       case CURL_TELOPT_XDISPLOC:
742         pointer[length] = 0;
743         infof(data, " \"%s\"", &pointer[2]);
744         break;
745       case CURL_TELOPT_NEW_ENVIRON:
746         if(pointer[1] == CURL_TELQUAL_IS) {
747           infof(data, " ");
748           for(i = 3;i < length;i++) {
749             switch(pointer[i]) {
750               case CURL_NEW_ENV_VAR:
751                 infof(data, ", ");
752                 break;
753               case CURL_NEW_ENV_VALUE:
754                 infof(data, " = ");
755                 break;
756               default:
757                 infof(data, "%c", pointer[i]);
758                 break;
759             }
760           }
761         }
762         break;
763       default:
764         for (i = 2; i < length; i++)
765           infof(data, " %.2x", pointer[i]);
766         break;
767     }
768
769     if (direction)
770     {
771       infof(data, "\n");
772     }
773   }
774 }
775
776 static CURLcode check_telnet_options(struct connectdata *conn)
777 {
778   struct curl_slist *head;
779   char option_keyword[128];
780   char option_arg[256];
781   char *buf;
782   struct SessionHandle *data = conn->data;
783   struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
784
785   /* Add the user name as an environment variable if it
786      was given on the command line */
787   if(conn->bits.user_passwd)
788   {
789     snprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user);
790     tn->telnet_vars = curl_slist_append(tn->telnet_vars, option_arg);
791
792     tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
793   }
794
795   for(head = data->set.telnet_options; head; head=head->next) {
796     if(sscanf(head->data, "%127[^= ]%*[ =]%255s",
797               option_keyword, option_arg) == 2) {
798
799       /* Terminal type */
800       if(curl_strequal(option_keyword, "TTYPE")) {
801         strncpy(tn->subopt_ttype, option_arg, 31);
802         tn->subopt_ttype[31] = 0; /* String termination */
803         tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES;
804         continue;
805       }
806
807       /* Display variable */
808       if(curl_strequal(option_keyword, "XDISPLOC")) {
809         strncpy(tn->subopt_xdisploc, option_arg, 127);
810         tn->subopt_xdisploc[127] = 0; /* String termination */
811         tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES;
812         continue;
813       }
814
815       /* Environment variable */
816       if(curl_strequal(option_keyword, "NEW_ENV")) {
817         buf = strdup(option_arg);
818         if(!buf)
819           return CURLE_OUT_OF_MEMORY;
820         tn->telnet_vars = curl_slist_append(tn->telnet_vars, buf);
821         tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
822         continue;
823       }
824
825       failf(data, "Unknown telnet option %s", head->data);
826       return CURLE_UNKNOWN_TELNET_OPTION;
827     } else {
828       failf(data, "Syntax error in telnet option: %s", head->data);
829       return CURLE_TELNET_OPTION_SYNTAX;
830     }
831   }
832
833   return CURLE_OK;
834 }
835
836 /*
837  * suboption()
838  *
839  * Look at the sub-option buffer, and try to be helpful to the other
840  * side.
841  */
842
843 static void suboption(struct connectdata *conn)
844 {
845   struct curl_slist *v;
846   unsigned char temp[2048];
847   size_t len;
848   size_t tmplen;
849   char varname[128];
850   char varval[128];
851   struct SessionHandle *data = conn->data;
852   struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
853
854   printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn)+2);
855   switch (CURL_SB_GET(tn)) {
856     case CURL_TELOPT_TTYPE:
857       len = strlen(tn->subopt_ttype) + 4 + 2;
858       snprintf((char *)temp, sizeof(temp),
859                "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE,
860                CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE);
861       (void)swrite(conn->sock[FIRSTSOCKET], (char *)temp, len);
862       printsub(data, '>', &temp[2], len-2);
863       break;
864     case CURL_TELOPT_XDISPLOC:
865       len = strlen(tn->subopt_xdisploc) + 4 + 2;
866       snprintf((char *)temp, sizeof(temp),
867                "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC,
868                CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE);
869       (void)swrite(conn->sock[FIRSTSOCKET], (char *)temp, len);
870       printsub(data, '>', &temp[2], len-2);
871       break;
872     case CURL_TELOPT_NEW_ENVIRON:
873       snprintf((char *)temp, sizeof(temp),
874                "%c%c%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON,
875                CURL_TELQUAL_IS);
876       len = 4;
877
878       for(v = tn->telnet_vars;v;v = v->next) {
879         tmplen = (strlen(v->data) + 1);
880         /* Add the variable only if it fits */
881         if(len + tmplen < (int)sizeof(temp)-6) {
882           sscanf(v->data, "%127[^,],%127s", varname, varval);
883           snprintf((char *)&temp[len], sizeof(temp) - len,
884                    "%c%s%c%s", CURL_NEW_ENV_VAR, varname,
885                    CURL_NEW_ENV_VALUE, varval);
886           len += tmplen;
887         }
888       }
889       snprintf((char *)&temp[len], sizeof(temp) - len,
890                "%c%c", CURL_IAC, CURL_SE);
891       len += 2;
892       (void)swrite(conn->sock[FIRSTSOCKET], (char *)temp, len);
893       printsub(data, '>', &temp[2], len-2);
894       break;
895   }
896   return;
897 }
898
899 static
900 void telrcv(struct connectdata *conn,
901             unsigned char *inbuf,       /* Data received from socket */
902             ssize_t count)              /* Number of bytes received */
903 {
904   unsigned char c;
905   int in = 0;
906   struct SessionHandle *data = conn->data;
907   struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
908
909   while(count--)
910   {
911     c = inbuf[in++];
912
913     switch (tn->telrcv_state)
914     {
915       case CURL_TS_CR:
916         tn->telrcv_state = CURL_TS_DATA;
917         if (c == '\0')
918         {
919           break;   /* Ignore \0 after CR */
920         }
921
922         Curl_client_write(data, CLIENTWRITE_BODY, (char *)&c, 1);
923         continue;
924
925       case CURL_TS_DATA:
926         if (c == CURL_IAC)
927         {
928           tn->telrcv_state = CURL_TS_IAC;
929           break;
930         }
931         else if(c == '\r')
932         {
933           tn->telrcv_state = CURL_TS_CR;
934         }
935
936         Curl_client_write(data, CLIENTWRITE_BODY, (char *)&c, 1);
937         continue;
938
939       case CURL_TS_IAC:
940       process_iac:
941       switch (c)
942       {
943         case CURL_WILL:
944           tn->telrcv_state = CURL_TS_WILL;
945           continue;
946         case CURL_WONT:
947           tn->telrcv_state = CURL_TS_WONT;
948           continue;
949         case CURL_DO:
950           tn->telrcv_state = CURL_TS_DO;
951           continue;
952         case CURL_DONT:
953           tn->telrcv_state = CURL_TS_DONT;
954           continue;
955         case CURL_SB:
956           CURL_SB_CLEAR(tn);
957           tn->telrcv_state = CURL_TS_SB;
958           continue;
959         case CURL_IAC:
960           Curl_client_write(data, CLIENTWRITE_BODY, (char *)&c, 1);
961           break;
962         case CURL_DM:
963         case CURL_NOP:
964         case CURL_GA:
965         default:
966           printoption(data, "RCVD", CURL_IAC, c);
967           break;
968       }
969       tn->telrcv_state = CURL_TS_DATA;
970       continue;
971
972       case CURL_TS_WILL:
973         printoption(data, "RCVD", CURL_WILL, c);
974         tn->please_negotiate = 1;
975         rec_will(conn, c);
976         tn->telrcv_state = CURL_TS_DATA;
977         continue;
978
979       case CURL_TS_WONT:
980         printoption(data, "RCVD", CURL_WONT, c);
981         tn->please_negotiate = 1;
982         rec_wont(conn, c);
983         tn->telrcv_state = CURL_TS_DATA;
984         continue;
985
986       case CURL_TS_DO:
987         printoption(data, "RCVD", CURL_DO, c);
988         tn->please_negotiate = 1;
989         rec_do(conn, c);
990         tn->telrcv_state = CURL_TS_DATA;
991         continue;
992
993       case CURL_TS_DONT:
994         printoption(data, "RCVD", CURL_DONT, c);
995         tn->please_negotiate = 1;
996         rec_dont(conn, c);
997         tn->telrcv_state = CURL_TS_DATA;
998         continue;
999
1000       case CURL_TS_SB:
1001         if (c == CURL_IAC)
1002         {
1003           tn->telrcv_state = CURL_TS_SE;
1004         }
1005         else
1006         {
1007           CURL_SB_ACCUM(tn,c);
1008         }
1009         continue;
1010
1011       case CURL_TS_SE:
1012         if (c != CURL_SE)
1013         {
1014           if (c != CURL_IAC)
1015           {
1016             /*
1017              * This is an error.  We only expect to get
1018              * "IAC IAC" or "IAC SE".  Several things may
1019              * have happend.  An IAC was not doubled, the
1020              * IAC SE was left off, or another option got
1021              * inserted into the suboption are all possibilities.
1022              * If we assume that the IAC was not doubled,
1023              * and really the IAC SE was left off, we could
1024              * get into an infinate loop here.  So, instead,
1025              * we terminate the suboption, and process the
1026              * partial suboption if we can.
1027              */
1028             CURL_SB_ACCUM(tn, (unsigned char)CURL_IAC);
1029             CURL_SB_ACCUM(tn, c);
1030             tn->subpointer -= 2;
1031             CURL_SB_TERM(tn);
1032
1033             printoption(data, "In SUBOPTION processing, RCVD", CURL_IAC, c);
1034             suboption(conn);   /* handle sub-option */
1035             tn->telrcv_state = CURL_TS_IAC;
1036             goto process_iac;
1037           }
1038           CURL_SB_ACCUM(tn,c);
1039           tn->telrcv_state = CURL_TS_SB;
1040         }
1041         else
1042         {
1043           CURL_SB_ACCUM(tn, (unsigned char)CURL_IAC);
1044           CURL_SB_ACCUM(tn, (unsigned char)CURL_SE);
1045           tn->subpointer -= 2;
1046           CURL_SB_TERM(tn);
1047           suboption(conn);   /* handle sub-option */
1048           tn->telrcv_state = CURL_TS_DATA;
1049         }
1050         break;
1051     }
1052   }
1053 }
1054
1055 CURLcode Curl_telnet_done(struct connectdata *conn, CURLcode status)
1056 {
1057   struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
1058   (void)status; /* unused */
1059
1060   curl_slist_free_all(tn->telnet_vars);
1061
1062   free(conn->proto.telnet);
1063   conn->proto.telnet = NULL;
1064
1065   return CURLE_OK;
1066 }
1067
1068 CURLcode Curl_telnet(struct connectdata *conn)
1069 {
1070   CURLcode code;
1071   struct SessionHandle *data = conn->data;
1072   curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
1073 #ifdef WIN32
1074   HMODULE wsock2;
1075   WSOCK2_FUNC close_event_func;
1076   WSOCK2_FUNC create_event_func;
1077   WSOCK2_FUNC event_select_func;
1078   WSOCK2_FUNC enum_netevents_func;
1079   WSAEVENT event_handle;
1080   WSANETWORKEVENTS events;
1081   HANDLE stdin_handle;
1082   HANDLE objs[2];
1083   DWORD  obj_count;
1084   DWORD  wait_timeout;
1085   DWORD waitret;
1086   DWORD readfile_read;
1087 #else
1088   int interval_ms;
1089   struct pollfd pfd[2];
1090 #endif
1091   ssize_t nread;
1092   bool keepon = TRUE;
1093   char *buf = data->state.buffer;
1094   struct TELNET *tn;
1095
1096   code = init_telnet(conn);
1097   if(code)
1098     return code;
1099
1100   tn = (struct TELNET *)conn->proto.telnet;
1101
1102   code = check_telnet_options(conn);
1103   if(code)
1104     return code;
1105
1106 #ifdef WIN32
1107   /*
1108   ** This functionality only works with WinSock >= 2.0.  So,
1109   ** make sure have it.
1110   */
1111   code = check_wsock2(data);
1112   if (code)
1113     return code;
1114
1115   /* OK, so we have WinSock 2.0.  We need to dynamically */
1116   /* load ws2_32.dll and get the function pointers we need. */
1117   wsock2 = LoadLibrary("WS2_32.DLL");
1118   if (wsock2 == NULL) {
1119     failf(data,"failed to load WS2_32.DLL (%d)",GetLastError());
1120     return CURLE_FAILED_INIT;
1121   }
1122
1123   /* Grab a pointer to WSACreateEvent */
1124   create_event_func = GetProcAddress(wsock2,"WSACreateEvent");
1125   if (create_event_func == NULL) {
1126     failf(data,"failed to find WSACreateEvent function (%d)",
1127           GetLastError());
1128     FreeLibrary(wsock2);
1129     return CURLE_FAILED_INIT;
1130   }
1131
1132   /* And WSACloseEvent */
1133   close_event_func = GetProcAddress(wsock2,"WSACloseEvent");
1134   if (create_event_func == NULL) {
1135     failf(data,"failed to find WSACloseEvent function (%d)",
1136           GetLastError());
1137     FreeLibrary(wsock2);
1138     return CURLE_FAILED_INIT;
1139   }
1140
1141   /* And WSAEventSelect */
1142   event_select_func = GetProcAddress(wsock2,"WSAEventSelect");
1143   if (event_select_func == NULL) {
1144     failf(data,"failed to find WSAEventSelect function (%d)",
1145           GetLastError());
1146     FreeLibrary(wsock2);
1147     return CURLE_FAILED_INIT;
1148   }
1149
1150   /* And WSAEnumNetworkEvents */
1151   enum_netevents_func = GetProcAddress(wsock2,"WSAEnumNetworkEvents");
1152   if (enum_netevents_func == NULL) {
1153     failf(data,"failed to find WSAEnumNetworkEvents function (%d)",
1154           GetLastError());
1155     FreeLibrary(wsock2);
1156     return CURLE_FAILED_INIT;
1157   }
1158
1159   /* We want to wait for both stdin and the socket. Since
1160   ** the select() function in winsock only works on sockets
1161   ** we have to use the WaitForMultipleObjects() call.
1162   */
1163
1164   /* First, create a sockets event object */
1165   event_handle = (WSAEVENT)create_event_func();
1166   if (event_handle == WSA_INVALID_EVENT) {
1167     failf(data,"WSACreateEvent failed (%d)",WSAGetLastError());
1168     FreeLibrary(wsock2);
1169     return CURLE_FAILED_INIT;
1170   }
1171
1172   /* The get the Windows file handle for stdin */
1173   stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
1174
1175   /* Create the list of objects to wait for */
1176   objs[0] = event_handle;
1177   objs[1] = stdin_handle;
1178
1179   /* Tell winsock what events we want to listen to */
1180   if(event_select_func(sockfd, event_handle, FD_READ|FD_CLOSE) == SOCKET_ERROR) {
1181     close_event_func(event_handle);
1182     FreeLibrary(wsock2);
1183     return 0;
1184   }
1185
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 */
1190     obj_count = 1;
1191     /* Check stdin_handle per 100 milliseconds */
1192     wait_timeout = 100;
1193   } else {
1194     obj_count = 2;
1195     wait_timeout = INFINITE;
1196   }
1197
1198   /* Keep on listening and act on events */
1199   while(keepon) {
1200     waitret = WaitForMultipleObjects(obj_count, objs, FALSE, wait_timeout);
1201     switch(waitret) {
1202     case WAIT_TIMEOUT:
1203     {
1204       unsigned char outbuf[2];
1205       int out_count = 0;
1206       ssize_t bytes_written;
1207       char *buffer = buf;
1208
1209       for(;;) {
1210         if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL, &readfile_read, NULL)) {
1211           keepon = FALSE;
1212           break;
1213         }
1214         nread = readfile_read;
1215
1216         if(!nread)
1217           break;
1218
1219         if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
1220                      &readfile_read, NULL)) {
1221           keepon = FALSE;
1222           break;
1223         }
1224         nread = readfile_read;
1225
1226         while(nread--) {
1227           outbuf[0] = *buffer++;
1228           out_count = 1;
1229           if(outbuf[0] == CURL_IAC)
1230             outbuf[out_count++] = CURL_IAC;
1231
1232           Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf,
1233                      out_count, &bytes_written);
1234         }
1235       }
1236     }
1237     break;
1238
1239     case WAIT_OBJECT_0 + 1:
1240     {
1241       unsigned char outbuf[2];
1242       int out_count = 0;
1243       ssize_t bytes_written;
1244       char *buffer = buf;
1245
1246       if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
1247                    &readfile_read, NULL)) {
1248         keepon = FALSE;
1249         break;
1250       }
1251       nread = readfile_read;
1252
1253       while(nread--) {
1254         outbuf[0] = *buffer++;
1255         out_count = 1;
1256         if(outbuf[0] == CURL_IAC)
1257           outbuf[out_count++] = CURL_IAC;
1258
1259         Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf,
1260                    out_count, &bytes_written);
1261       }
1262     }
1263     break;
1264
1265     case WAIT_OBJECT_0:
1266       if(enum_netevents_func(sockfd, event_handle, &events)
1267          != SOCKET_ERROR) {
1268         if(events.lNetworkEvents & FD_READ) {
1269           /* This reallu OUGHT to check its return code. */
1270           (void)Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
1271
1272           telrcv(conn, (unsigned char *)buf, nread);
1273
1274           fflush(stdout);
1275
1276           /* Negotiate if the peer has started negotiating,
1277              otherwise don't. We don't want to speak telnet with
1278              non-telnet servers, like POP or SMTP. */
1279           if(tn->please_negotiate && !tn->already_negotiated) {
1280             negotiate(conn);
1281             tn->already_negotiated = 1;
1282           }
1283         }
1284
1285         if(events.lNetworkEvents & FD_CLOSE) {
1286           keepon = FALSE;
1287         }
1288       }
1289       break;
1290     }
1291   }
1292
1293   /* We called WSACreateEvent, so call WSACloseEvent */
1294   if (close_event_func(event_handle) == FALSE) {
1295     infof(data,"WSACloseEvent failed (%d)",WSAGetLastError());
1296   }
1297
1298   /* "Forget" pointers into the library we're about to free */
1299   create_event_func = NULL;
1300   close_event_func = NULL;
1301   event_select_func = NULL;
1302   enum_netevents_func = NULL;
1303
1304   /* We called LoadLibrary, so call FreeLibrary */
1305   if (!FreeLibrary(wsock2))
1306     infof(data,"FreeLibrary(wsock2) failed (%d)",GetLastError());
1307 #else
1308   pfd[0].fd = sockfd;
1309   pfd[0].events = POLLIN;
1310   pfd[1].fd = 0;
1311   pfd[1].events = POLLIN;
1312   interval_ms = 1 * 1000;
1313
1314   while (keepon) {
1315     switch (Curl_poll(pfd, 2, interval_ms)) {
1316     case -1:                    /* error, stop reading */
1317       keepon = FALSE;
1318       continue;
1319     case 0:                     /* timeout */
1320       break;
1321     default:                    /* read! */
1322       if(pfd[1].revents & POLLIN) { /* read from stdin */
1323         unsigned char outbuf[2];
1324         int out_count = 0;
1325         ssize_t bytes_written;
1326         char *buffer = buf;
1327
1328         nread = read(0, buf, 255);
1329
1330         while(nread--) {
1331           outbuf[0] = *buffer++;
1332           out_count = 1;
1333           if(outbuf[0] == CURL_IAC)
1334             outbuf[out_count++] = CURL_IAC;
1335
1336           Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf,
1337                      out_count, &bytes_written);
1338         }
1339       }
1340
1341       if(pfd[0].revents & POLLIN) {
1342         /* This OUGHT to check the return code... */
1343         (void)Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
1344
1345         /* if we receive 0 or less here, the server closed the connection and
1346            we bail out from this! */
1347         if (nread <= 0) {
1348           keepon = FALSE;
1349           break;
1350         }
1351
1352         telrcv(conn, (unsigned char *)buf, nread);
1353
1354         /* Negotiate if the peer has started negotiating,
1355            otherwise don't. We don't want to speak telnet with
1356            non-telnet servers, like POP or SMTP. */
1357         if(tn->please_negotiate && !tn->already_negotiated) {
1358           negotiate(conn);
1359           tn->already_negotiated = 1;
1360         }
1361       }
1362     }
1363     if(data->set.timeout) {
1364       struct timeval now;           /* current time */
1365       now = Curl_tvnow();
1366       if(Curl_tvdiff(now, conn->created)/1000 >= data->set.timeout) {
1367         failf(data, "Time-out");
1368         code = CURLE_OPERATION_TIMEOUTED;
1369         keepon = FALSE;
1370       }
1371     }
1372   }
1373 #endif
1374   /* mark this as "no further transfer wanted" */
1375   Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1376
1377   return code;
1378 }
1379 #endif