blob: 34a6479790d253a6b7f81134cebd5f9d5fd685e9 [file] [log] [blame]
Patrick Williamsb48b7b42016-08-17 15:04:38 -05001From f09a6460a62aacb87bb8683d16aa3ce55848bf7e Mon Sep 17 00:00:00 2001
2From: Li xin <lixin.fnst@cn.fujitsu.com>
3Date: Fri, 28 Nov 2014 07:06:24 +0900
4Subject: [PATCH 1/2] To aviod buffer overflow in telnet
5
6This patch is from Fedora.
7
Andrew Geissler6aa7eec2023-03-03 12:41:14 -06008Upstream-Status: Pending
Patrick Williamsb48b7b42016-08-17 15:04:38 -05009
10Signed-off-by: Li Xin <lixin.fnst@cn.fujitsu.com>
11---
12 telnet/Makefile | 4 +-
13 telnet/commands.cc | 270 +++++++++++++++++++++++++++++++++++-----------------
14 telnet/defines.h | 2 +
15 telnet/externs.h | 7 +-
16 telnet/main.cc | 65 ++++++++++---
17 telnet/netlink.cc | 78 +++++++++------
18 telnet/netlink.h | 7 +-
19 telnet/network.cc | 1 +
20 telnet/proto.h | 2 +-
21 telnet/ring.cc | 2 +-
22 telnet/ring.h | 2 +-
23 telnet/sys_bsd.cc | 11 +++
24 telnet/telnet.1 | 37 +++++--
25 telnet/telnet.cc | 45 +++++----
26 telnet/terminal.cc | 17 +++-
27 telnet/utilities.cc | 2 +
28 16 files changed, 380 insertions(+), 172 deletions(-)
29
30diff --git a/telnet/Makefile b/telnet/Makefile
31index cef866f..39249e1 100644
32--- a/telnet/Makefile
33+++ b/telnet/Makefile
34@@ -7,7 +7,7 @@ include ../MRULES
35
36 # -DAUTHENTICATE
37 CXXFLAGS += -DUSE_TERMIO -DKLUDGELINEMODE
38-LIBS += $(LIBTERMCAP)
39+LIBS = $(LIBTERMCAP)
40
41 SRCS = commands.cc main.cc network.cc ring.cc sys_bsd.cc telnet.cc \
42 terminal.cc tn3270.cc utilities.cc genget.cc environ.cc netlink.cc
43@@ -22,7 +22,7 @@ depend:
44 $(CXX) $(CXXFLAGS) -MM $(SRCS) >depend.mk
45
46 install: telnet
47- install -s -m$(BINMODE) telnet $(INSTALLROOT)$(BINDIR)
48+ install -m$(BINMODE) telnet $(INSTALLROOT)$(BINDIR)
49 install -m$(MANMODE) telnet.1 $(INSTALLROOT)$(MANDIR)/man1
50
51 clean:
52diff --git a/telnet/commands.cc b/telnet/commands.cc
53index d92bccd..02c593e 100644
54--- a/telnet/commands.cc
55+++ b/telnet/commands.cc
56@@ -86,10 +86,6 @@ char cmd_rcsid[] =
57
58 #define HELPINDENT ((int) sizeof ("connect"))
59
60-#ifndef MAXHOSTNAMELEN
61-#define MAXHOSTNAMELEN 64
62-#endif MAXHOSTNAMELEN
63-
64 #if defined(HAS_IPPROTO_IP) && defined(IP_TOS)
65 int tos = -1;
66 #endif /* defined(HAS_IPPROTO_IP) && defined(IP_TOS) */
67@@ -98,7 +94,7 @@ static unsigned long sourceroute(char *arg, char **cpp, int *lenp);
68
69
70 char *hostname;
71-static char _hostname[MAXHOSTNAMELEN];
72+static char *_hostname;
73
74 //typedef int (*intrtn_t)(int argc, const char *argv[]);
75
76@@ -161,7 +157,7 @@ class command_entry {
77 assert(argc>=1);
78 if (nargs>=0 && argc!=nargs+1) {
79 fprintf(stderr, "Wrong number of arguments for command.\n");
80- fprintf(stderr, "Try %s ? for help\n", argv[0]);
81+ fprintf(stderr, "Try ? %s for help\n", argv[0]);
82 return 0; /* is this right? */
83 }
84 if (nargs==-2) {
85@@ -480,6 +476,7 @@ static int send_wontcmd(const char *name, const char *) {
86 int send_tncmd(int (*func)(int, int), const char *cmd, const char *name) {
87 char **cpp;
88 extern char *telopts[];
89+ long opt;
90
91 if (isprefix(name, "help") || isprefix(name, "?")) {
92 register int col, len;
93@@ -506,16 +503,23 @@ int send_tncmd(int (*func)(int, int), const char *cmd, const char *name) {
94 name, cmd);
95 return 0;
96 }
97+
98+ opt = cpp - telopts;
99 if (cpp == 0) {
100- fprintf(stderr, "'%s': unknown argument ('send %s ?' for help).\n",
101+ char *end;
102+
103+ opt = strtol(name, &end, 10);
104+ if (*end || opt < 0 || opt > 255) {
105+ fprintf(stderr, "'%s': unknown argument ('send %s ?' for help).\n",
106 name, cmd);
107- return 0;
108+ return 0;
109+ }
110 }
111 if (!connected) {
112 printf("?Need to be connected first.\n");
113 return 0;
114 }
115- (*func)(cpp - telopts, 1);
116+ (*func)(opt, 1);
117 return 1;
118 }
119
120@@ -689,9 +693,9 @@ static struct togglelist Togglelist[] = {
121 "print encryption debugging information" },
122 #endif
123
124- { "skiprc", "don't read ~/.telnetrc file",
125+ { "skiprc", "don't read the telnetrc files",
126 NULL, &skiprc,
127- "read ~/.telnetrc file" },
128+ "read the telnetrc files" },
129 { "binary",
130 "sending and receiving of binary data",
131 togbinary, NULL,
132@@ -1615,15 +1619,20 @@ void ayt_status(int) {
133 #endif
134
135 int tn(int argc, const char *argv[]) {
136- register struct hostent *host = 0;
137 struct sockaddr_in sn;
138- struct servent *sp = 0;
139 char *srp = NULL;
140 int srlen;
141-
142- const char *cmd, *volatile user = 0;
143+ int family = 0;
144+ const char *cmd, *volatile user = 0, *srchostp = 0;
145 const char *portp = NULL;
146 char *hostp = NULL;
147+ char *resolv_hostp;
148+ struct addrinfo hints;
149+ struct addrinfo *hostaddr = 0;
150+ int res;
151+ char name[NI_MAXHOST];
152+ char service[NI_MAXSERV];
153+ struct addrinfo *tmpaddr;
154
155 /* clear the socket address prior to use */
156 memset(&sn, 0, sizeof(sn));
157@@ -1632,6 +1641,10 @@ int tn(int argc, const char *argv[]) {
158 printf("?Already connected to %s\n", hostname);
159 return 0;
160 }
161+ if (_hostname) {
162+ delete[] _hostname;
163+ _hostname = 0;
164+ }
165 if (argc < 2) {
166 (void) strcpy(line, "open ");
167 printf("(to) ");
168@@ -1657,11 +1670,33 @@ int tn(int argc, const char *argv[]) {
169 --argc;
170 continue;
171 }
172+ if (strcmp(*argv, "-b") == 0) {
173+ --argc; ++argv;
174+ if (argc == 0)
175+ goto usage;
176+ srchostp = *argv++;
177+ --argc;
178+ continue;
179+ }
180 if (strcmp(*argv, "-a") == 0) {
181 --argc; ++argv;
182 autologin = 1;
183 continue;
184 }
185+ if (strcmp(*argv, "-6") == 0) {
186+ --argc; ++argv;
187+#ifdef AF_INET6
188+ family = AF_INET6;
189+#else
190+ puts("IPv6 unsupported");
191+#endif
192+ continue;
193+ }
194+ if (strcmp(*argv, "-4") == 0) {
195+ --argc; ++argv;
196+ family = AF_INET;
197+ continue;
198+ }
199 if (hostp == 0) {
200 /* this leaks memory - FIXME */
201 hostp = strdup(*argv++);
202@@ -1680,6 +1715,8 @@ int tn(int argc, const char *argv[]) {
203 if (hostp == 0)
204 goto usage;
205
206+ resolv_hostp = hostp;
207+
208 #if defined(IP_OPTIONS) && defined(HAS_IPPROTO_IP)
209 if (hostp[0] == '@' || hostp[0] == '!') {
210 if ((hostname = strrchr(hostp, ':')) == NULL)
211@@ -1696,78 +1733,122 @@ int tn(int argc, const char *argv[]) {
212 } else {
213 sn.sin_addr.s_addr = temp;
214 sn.sin_family = AF_INET;
215+ /*
216+ * For source route we just make sure to get the IP given
217+ * on the command line when looking up the port.
218+ */
219+ resolv_hostp = inet_ntoa(sn.sin_addr);
220 }
221 }
222- else {
223-#endif
224- if (inet_aton(hostp, &sn.sin_addr)) {
225- sn.sin_family = AF_INET;
226- strcpy(_hostname, hostp);
227- hostname = _hostname;
228- }
229- else {
230- host = gethostbyname(hostp);
231- if (host) {
232- sn.sin_family = host->h_addrtype;
233- if (host->h_length > (int)sizeof(sn.sin_addr)) {
234- host->h_length = sizeof(sn.sin_addr);
235- }
236-#if defined(h_addr) /* In 4.3, this is a #define */
237- memcpy((caddr_t)&sn.sin_addr,
238- host->h_addr_list[0], host->h_length);
239-#else /* defined(h_addr) */
240- memcpy((caddr_t)&sn.sin_addr, host->h_addr, host->h_length);
241-#endif /* defined(h_addr) */
242- strncpy(_hostname, host->h_name, sizeof(_hostname));
243- _hostname[sizeof(_hostname)-1] = '\0';
244- hostname = _hostname;
245- } else {
246- herror(hostp);
247- return 0;
248- }
249- }
250-#if defined(IP_OPTIONS) && defined(HAS_IPPROTO_IP)
251- }
252 #endif
253+
254+ /* User port or the default name of telnet. */
255 if (portp) {
256 if (*portp == '-') {
257 portp++;
258 telnetport = 1;
259- } else
260+ } else {
261 telnetport = 0;
262- sn.sin_port = atoi(portp);
263- if (sn.sin_port == 0) {
264- sp = getservbyname(portp, "tcp");
265- if (sp)
266- sn.sin_port = sp->s_port;
267- else {
268- printf("%s: bad port number\n", portp);
269- return 0;
270+ if (*portp >='0' && *portp<='9') {
271+ char *end;
272+ long int p;
273+
274+ p=strtol(portp, &end, 10);
275+ if (ERANGE==errno && (LONG_MIN==p || LONG_MAX==p)) {
276+ fprintf(stderr, "telnet: port %s overflows\n", portp);
277+ return 0;
278+ } else if (p<=0 || p>=65536) {
279+ fprintf(stderr, "telnet: port %s out of range\n", portp);
280+ return 0;
281+ }
282 }
283- }
284- else {
285- sn.sin_port = htons(sn.sin_port);
286 }
287- }
288+ }
289 else {
290- if (sp == 0) {
291- sp = getservbyname("telnet", "tcp");
292- if (sp == 0) {
293- fprintf(stderr, "telnet: tcp/telnet: unknown service\n");
294- return 0;
295- }
296- sn.sin_port = sp->s_port;
297- }
298+ portp = "telnet";
299 telnetport = 1;
300 }
301- printf("Trying %s...\n", inet_ntoa(sn.sin_addr));
302+
303+ /* We only understand SOCK_STREAM sockets. */
304+ memset(&hints, 0, sizeof(hints));
305+ hints.ai_socktype = SOCK_STREAM;
306+ hints.ai_flags = AI_NUMERICHOST;
307+ hints.ai_family = family;
308+
309+ if (srchostp) {
310+ res = getaddrinfo(srchostp, "0", &hints, &hostaddr);
311+ if (res) {
312+ fprintf(stderr, "telnet: could not resolve %s: %s\n", srchostp,
313+ gai_strerror(res));
314+ return 0;
315+ }
316+ hints.ai_family = hostaddr->ai_family;
317+ res = nlink.bind(hostaddr);
318+ freeaddrinfo(hostaddr);
319+ if (res < 0)
320+ return 0;
321+ }
322+
323+ /* Resolve both the host and service simultaneously. */
324+ res = getaddrinfo(resolv_hostp, portp, &hints, &hostaddr);
325+ if (res == EAI_NONAME) {
326+ hints.ai_flags = AI_CANONNAME;
327+ res = getaddrinfo(resolv_hostp, portp, &hints, &hostaddr);
328+ } else if (hostaddr) {
329+ hostaddr->ai_canonname = 0;
330+ }
331+ if (res || !hostaddr) {
332+ fprintf(stderr, "telnet: could not resolve %s/%s: %s\n", resolv_hostp, portp, gai_strerror(res));
333+ return 0;
334+ }
335+
336+ /* Try to connect to every listed round robin IP. */
337+ tmpaddr = hostaddr;
338+ errno = 0;
339 do {
340- int x = nlink.connect(debug, host, &sn, srp, srlen, tos);
341- if (!x) return 0;
342- else if (x==1) continue;
343+ int x;
344+
345+ if (!tmpaddr) {
346+ if (errno)
347+ perror("telnet: Unable to connect to remote host");
348+ else
349+ fputs("telnet: Unable to connect to remote host: "
350+ "Bad port number\n", stderr);
351+err:
352+ freeaddrinfo(hostaddr);
353+ return 0;
354+ }
355+
356+ if (tmpaddr->ai_family == AF_UNIX) {
357+nextaddr:
358+ tmpaddr = tmpaddr->ai_next;
359+ continue;
360+ }
361+
362+ getnameinfo(tmpaddr->ai_addr, tmpaddr->ai_addrlen,
363+ name, sizeof(name), service, sizeof(service),
364+ NI_NUMERICHOST | NI_NUMERICSERV);
365+
366+ printf("Trying %s...\n", name);
367+ x = nlink.connect(debug, tmpaddr, srp, srlen, tos);
368+ if (!x)
369+ goto err;
370+ else if (x==1)
371+ goto nextaddr;
372+
373 connected++;
374 } while (connected == 0);
375- cmdrc(hostp, hostname);
376+ if (tmpaddr->ai_canonname == 0) {
377+ hostname = new char[strlen(hostp)+1];
378+ strcpy(hostname, hostp);
379+ }
380+ else {
381+ hostname = new char[strlen(tmpaddr->ai_canonname)+1];
382+ strcpy(hostname, tmpaddr->ai_canonname);
383+ }
384+
385+ cmdrc(hostp, hostname, portp);
386+ freeaddrinfo(hostaddr);
387 if (autologin && user == NULL) {
388 struct passwd *pw;
389
390@@ -2013,30 +2094,21 @@ static int help(command_table *tab, int argc, const char *argv[]) {
391 return 0;
392 }
393
394-static char *rcname = 0;
395-static char rcbuf[128];
396-
397-void cmdrc(const char *m1, const char *m2) {
398+static void readrc(const char *m1, const char *m2, const char *port,
399+ const char *rcname)
400+{
401 FILE *rcfile;
402 int gotmachine = 0;
403 int l1 = strlen(m1);
404 int l2 = strlen(m2);
405- char m1save[64];
406-
407- if (skiprc) return;
408+ int lport = strlen(port);
409+ char m1save[l1 + 1];
410+ char portsave[lport + 1];
411
412 strcpy(m1save, m1);
413 m1 = m1save;
414-
415- if (rcname == 0) {
416- rcname = getenv("HOME");
417- if (rcname)
418- strcpy(rcbuf, rcname);
419- else
420- rcbuf[0] = '\0';
421- strcat(rcbuf, "/.telnetrc");
422- rcname = rcbuf;
423- }
424+ strcpy(portsave, port);
425+ port = portsave;
426
427 rcfile = fopen(rcname, "r");
428 if (!rcfile) return;
429@@ -2061,6 +2133,13 @@ void cmdrc(const char *m1, const char *m2) {
430 strncpy(line, &line[7], sizeof(line) - 7);
431 else
432 continue;
433+
434+ if (line[0] == ':') {
435+ if (!strncasecmp(&line[1], port, lport))
436+ continue;
437+ strncpy(line, &line[lport + 1], sizeof(line) - lport - 1);
438+ }
439+
440 if (line[0] != ' ' && line[0] != '\t' && line[0] != '\n')
441 continue;
442 gotmachine = 1;
443@@ -2073,6 +2152,21 @@ void cmdrc(const char *m1, const char *m2) {
444 fclose(rcfile);
445 }
446
447+void cmdrc(const char *m1, const char *m2, const char *port) {
448+ char *rcname = NULL;
449+
450+ if (skiprc) return;
451+
452+ readrc(m1, m2, port, "/etc/telnetrc");
453+ if (asprintf (&rcname, "%s/.telnetrc", getenv ("HOME")) == -1)
454+ {
455+ perror ("asprintf");
456+ return;
457+ }
458+ readrc(m1, m2, port, rcname);
459+ free (rcname);
460+}
461+
462 #if defined(IP_OPTIONS) && defined(HAS_IPPROTO_IP)
463
464 /*
465diff --git a/telnet/defines.h b/telnet/defines.h
466index 2784400..d5edc46 100644
467--- a/telnet/defines.h
468+++ b/telnet/defines.h
469@@ -50,3 +50,5 @@
470 #define MODE_COMMAND_LINE(m) ((m)==-1)
471
472 #define CONTROL(x) ((x)&0x1f) /* CTRL(x) is not portable */
473+
474+#define MODE_OUT8 0x8000 /* binary mode sans -opost */
475diff --git a/telnet/externs.h b/telnet/externs.h
476index 955df79..0730e8a 100644
477--- a/telnet/externs.h
478+++ b/telnet/externs.h
479@@ -48,9 +48,7 @@
480 typedef unsigned char cc_t;
481 #endif
482
483-#ifdef __linux__
484 #include <unistd.h> /* get _POSIX_VDISABLE */
485-#endif
486
487 #ifndef _POSIX_VDISABLE
488 #error "Please fix externs.h to define _POSIX_VDISABLE"
489@@ -60,7 +58,8 @@ typedef unsigned char cc_t;
490
491 extern int autologin; /* Autologin enabled */
492 extern int skiprc; /* Don't process the ~/.telnetrc file */
493-extern int eight; /* use eight bit mode (binary in and/or out */
494+extern int eight; /* use eight bit mode (binary in and/or out) */
495+extern int binary; /* use binary option (in and/or out) */
496 extern int flushout; /* flush output */
497 extern int connected; /* Are we connected to the other side? */
498 extern int globalmode; /* Mode tty should be in */
499@@ -225,6 +224,8 @@ cc_t *tcval(int);
500
501 //#if 0
502 extern struct termios new_tc;
503+extern struct termios old_tc;
504+
505
506 #define termEofChar new_tc.c_cc[VEOF]
507 #define termEraseChar new_tc.c_cc[VERASE]
508diff --git a/telnet/main.cc b/telnet/main.cc
509index b67f2ce..b626e54 100644
510--- a/telnet/main.cc
511+++ b/telnet/main.cc
512@@ -45,7 +45,10 @@ char main_rcsid[] =
513
514 #include <sys/types.h>
515 #include <getopt.h>
516+#include <stdlib.h>
517 #include <string.h>
518+#include <netdb.h>
519+#include <errno.h>
520
521 #include "ring.h"
522 #include "externs.h"
523@@ -80,12 +83,13 @@ tninit(void)
524 void usage(void) {
525 fprintf(stderr, "Usage: %s %s%s%s%s\n",
526 prompt,
527- " [-8] [-E] [-L] [-a] [-d] [-e char] [-l user] [-n tracefile]",
528- "\n\t",
529+ "[-4] [-6] [-8] [-E] [-L] [-a] [-d] [-e char] [-l user]",
530+ "\n\t[-n tracefile] [ -b addr ]",
531 #ifdef TN3270
532+ "\n\t"
533 "[-noasynch] [-noasynctty] [-noasyncnet] [-r] [-t transcom]\n\t",
534 #else
535- "[-r] ",
536+ " [-r] ",
537 #endif
538 "[host-name [port]]"
539 );
540@@ -102,7 +106,8 @@ main(int argc, char *argv[])
541 extern char *optarg;
542 extern int optind;
543 int ch;
544- char *user;
545+ char *user, *srcaddr;
546+ int family;
547
548 tninit(); /* Clear out things */
549 #if defined(CRAY) && !defined(__STDC__)
550@@ -110,21 +115,38 @@ main(int argc, char *argv[])
551 #endif
552
553 TerminalSaveState();
554+ if ((old_tc.c_cflag & (CSIZE|PARENB)) != CS8)
555+ eight = 0;
556
557 if ((prompt = strrchr(argv[0], '/'))!=NULL)
558 ++prompt;
559 else
560 prompt = argv[0];
561
562- user = NULL;
563+ user = srcaddr = NULL;
564+ family = 0;
565
566 rlogin = (strncmp(prompt, "rlog", 4) == 0) ? '~' : _POSIX_VDISABLE;
567 autologin = -1;
568
569- while ((ch = getopt(argc, argv, "8EKLS:X:ade:k:l:n:rt:x")) != EOF) {
570+ while ((ch = getopt(argc, argv,
571+ "4678EKLS:X:ab:de:k:l:n:rt:x")) != EOF) {
572 switch(ch) {
573+ case '4':
574+ family = AF_INET;
575+ break;
576+ case '6':
577+#ifdef AF_INET6
578+ family = AF_INET6;
579+#else
580+ fputs("IPv6 unsupported\n", stderr);
581+#endif
582+ break;
583+ case '7':
584+ eight = 0; /* 7-bit ouput and input */
585+ break;
586 case '8':
587- eight = 3; /* binary output and input */
588+ binary = 3; /* binary output and input */
589 break;
590 case 'E':
591 rlogin = escapechar = _POSIX_VDISABLE;
592@@ -133,23 +155,26 @@ main(int argc, char *argv[])
593 //autologin = 0;
594 break;
595 case 'L':
596- eight |= 2; /* binary output only */
597+ binary |= 2; /* binary output only */
598 break;
599 case 'S':
600 {
601-#ifdef HAS_GETTOS
602 extern int tos;
603+ int num;
604
605- if ((tos = parsetos(optarg, "tcp")) < 0)
606+#ifdef HAS_GETTOS
607+ if ((num = parsetos(optarg, "tcp")) < 0) {
608+#else
609+ errno = 0;
610+ num = strtol(optarg, 0, 0);
611+ if (errno) {
612+#endif
613 fprintf(stderr, "%s%s%s%s\n",
614 prompt, ": Bad TOS argument '",
615 optarg,
616 "; will try to use default TOS");
617-#else
618- fprintf(stderr,
619- "%s: Warning: -S ignored, no parsetos() support.\n",
620- prompt);
621-#endif
622+ } else
623+ tos = num;
624 }
625 break;
626 case 'X':
627@@ -210,6 +235,9 @@ main(int argc, char *argv[])
628 "%s: -x ignored, no encryption support.\n",
629 prompt);
630 break;
631+ case 'b':
632+ srcaddr = optarg;
633+ break;
634 case '?':
635 default:
636 usage();
637@@ -233,6 +261,13 @@ main(int argc, char *argv[])
638 *argp++ = "-l";
639 *argp++ = user;
640 }
641+ if (srcaddr) {
642+ *argp++ = "-b";
643+ *argp++ = srcaddr;
644+ }
645+ if (family) {
646+ *argp++ = family == AF_INET ? "-4" : "-6";
647+ }
648 *argp++ = argv[0]; /* host */
649 if (argc > 1)
650 *argp++ = argv[1]; /* port */
651diff --git a/telnet/netlink.cc b/telnet/netlink.cc
652index f439cff..f839747 100644
653--- a/telnet/netlink.cc
654+++ b/telnet/netlink.cc
655@@ -79,22 +79,61 @@ void netlink::close(int doshutdown) {
656 shutdown(net, 2);
657 }
658 ::close(net);
659+ net = -1;
660 }
661
662-int netlink::connect(int debug, struct hostent *host,
663- struct sockaddr_in *sn,
664- char *srcroute, int srlen, int tos)
665+int netlink::bind(struct addrinfo *addr)
666 {
667- int on=1;
668+ int res;
669+
670+ res = socket(addr->ai_family);
671+ if (res < 2) {
672+ if (res == 1)
673+ perror("telnet: socket");
674+ return -1;
675+ }
676+
677+ if (::bind(net, addr->ai_addr, addr->ai_addrlen) < 0) {
678+ perror("telnet: bind");
679+ return -1;
680+ }
681+
682+ return 0;
683+}
684+
685+int netlink::socket(int family)
686+{
687+ if (this->family != family)
688+ close(0);
689
690- net = socket(AF_INET, SOCK_STREAM, 0);
691 if (net < 0) {
692- perror("telnet: socket");
693- return 0;
694+ this->family = family;
695+ net = ::socket(family, SOCK_STREAM, 0);
696+ if (net < 0) {
697+ if (errno == EAFNOSUPPORT)
698+ return 1;
699+ perror("telnet: socket");
700+ return 0;
701+ }
702 }
703
704+ return 2;
705+}
706+
707+int netlink::connect(int debug, struct addrinfo *addr,
708+ char *srcroute, int srlen, int tos)
709+{
710+ int on=1;
711+ int res;
712+
713+ res = socket(addr->ai_family);
714+ if (res < 2)
715+ return res;
716+
717 #if defined(IP_OPTIONS) && defined(HAS_IPPROTO_IP)
718 if (srcroute) {
719+ if (addr->ai_family != AF_INET)
720+ fputs("Source route is only supported for IPv4\n", stderr);
721 if (setsockopt(net, IPPROTO_IP, IP_OPTIONS, srcroute, srlen) < 0)
722 perror("setsockopt (IP_OPTIONS)");
723 }
724@@ -108,7 +147,7 @@ int netlink::connect(int debug, struct hostent *host,
725 #endif
726 if (tos < 0) tos = 020; /* Low Delay bit */
727 if (tos && (setsockopt(net, IPPROTO_IP, IP_TOS, &tos, sizeof(int)) < 0)
728- && (errno != ENOPROTOOPT))
729+ && (errno != ENOPROTOOPT) && (errno != EOPNOTSUPP))
730 perror("telnet: setsockopt (IP_TOS) (ignored)");
731 #endif /* defined(IPPROTO_IP) && defined(IP_TOS) */
732
733@@ -116,27 +155,8 @@ int netlink::connect(int debug, struct hostent *host,
734 perror("setsockopt (SO_DEBUG)");
735 }
736
737- if (::connect(net, (struct sockaddr *)sn, sizeof(*sn)) < 0) {
738-#if defined(h_addr) /* In 4.3, this is a #define */
739- if (host && host->h_addr_list[1]) {
740- int oerrno = errno;
741-
742- fprintf(stderr, "telnet: connect to address %s: ",
743- inet_ntoa(sn->sin_addr));
744- errno = oerrno;
745- perror(NULL);
746- host->h_addr_list++;
747- if (host->h_length > (int)sizeof(sn->sin_addr)) {
748- host->h_length = sizeof(sn->sin_addr);
749- }
750- memcpy(&sn->sin_addr, host->h_addr_list[0], host->h_length);
751- close(net);
752- return 1;
753- }
754-#endif /* defined(h_addr) */
755-
756- perror("telnet: Unable to connect to remote host");
757- return 0;
758+ if (::connect(net, addr->ai_addr, addr->ai_addrlen) < 0) {
759+ return 1;
760 }
761 return 2;
762 }
763diff --git a/telnet/netlink.h b/telnet/netlink.h
764index 9852b30..0ac8a08 100644
765--- a/telnet/netlink.h
766+++ b/telnet/netlink.h
767@@ -1,13 +1,16 @@
768
769 class netlink {
770+ private:
771+ int family;
772 protected:
773 int net;
774 public:
775 netlink();
776 ~netlink();
777
778- int connect(int debug, struct hostent *host,
779- struct sockaddr_in *sin,
780+ int bind(struct addrinfo *hostaddr);
781+ int socket(int family);
782+ int connect(int debug, struct addrinfo *hostaddr,
783 char *srcroute, int srlen,
784 int tos);
785 void close(int doshutdown);
786diff --git a/telnet/network.cc b/telnet/network.cc
787index 6a2c374..0dcf3e2 100644
788--- a/telnet/network.cc
789+++ b/telnet/network.cc
790@@ -40,6 +40,7 @@ char net_rcsid[] =
791 #include <sys/types.h>
792 #include <sys/socket.h>
793 #include <sys/time.h>
794+#include <stdlib.h>
795 #include <errno.h>
796 #include <arpa/telnet.h>
797
798diff --git a/telnet/proto.h b/telnet/proto.h
799index 8be4a39..92f2419 100644
800--- a/telnet/proto.h
801+++ b/telnet/proto.h
802@@ -13,7 +13,7 @@ int TerminalWindowSize(long *rows, long *cols);
803 void auth_encrypt_user(char *);
804 void auth_name(unsigned char *, int);
805 void auth_printsub(unsigned char *, int, unsigned char *, int);
806-void cmdrc(const char *m1, const char *m2);
807+void cmdrc(const char *, const char *, const char *);
808 void env_init(void);
809 int getconnmode(void);
810 void init_network(void);
811diff --git a/telnet/ring.cc b/telnet/ring.cc
812index be57396..772c6c5 100644
813--- a/telnet/ring.cc
814+++ b/telnet/ring.cc
815@@ -165,7 +165,7 @@ int ringbuf::flush() {
816
817 /////////////////////////////////////////////////// supply //////////////
818
819-void ringbuf::printf(const char *format, ...) {
820+void ringbuf::xprintf(const char *format, ...) {
821 char xbuf[256];
822 va_list ap;
823 va_start(ap, format);
824diff --git a/telnet/ring.h b/telnet/ring.h
825index 15d3f3f..049377e 100644
826--- a/telnet/ring.h
827+++ b/telnet/ring.h
828@@ -83,7 +83,7 @@ class ringbuf {
829 // manual supply
830 void putch(char c) { write(&c, 1); }
831 void write(const char *buffer, int ct);
832- void printf(const char *format, ...);
833+ void xprintf(const char *format, ...);
834 int empty_count() { return size - count; }
835
836 // automatic supply
837diff --git a/telnet/sys_bsd.cc b/telnet/sys_bsd.cc
838index 93fba7e..a8c9aab 100644
839--- a/telnet/sys_bsd.cc
840+++ b/telnet/sys_bsd.cc
841@@ -189,18 +189,25 @@ void NetSetPgrp(int fd) {
842 * Various signal handling routines.
843 */
844
845+#if 0
846 static void deadpeer(int /*sig*/) {
847 setcommandmode();
848 siglongjmp(peerdied, -1);
849 }
850+#endif
851
852 static void intr(int /*sig*/) {
853 if (localchars) {
854 intp();
855 }
856 else {
857+#if 0
858 setcommandmode();
859 siglongjmp(toplevel, -1);
860+#else
861+ signal(SIGINT, SIG_DFL);
862+ raise(SIGINT);
863+#endif
864 }
865 }
866
867@@ -214,6 +221,8 @@ static void intr2(int /*sig*/) {
868 sendabort();
869 return;
870 }
871+ signal(SIGQUIT, SIG_DFL);
872+ raise(SIGQUIT);
873 }
874
875 #ifdef SIGWINCH
876@@ -238,7 +247,9 @@ void ayt(int sig) {
877 void sys_telnet_init(void) {
878 signal(SIGINT, intr);
879 signal(SIGQUIT, intr2);
880+#if 0
881 signal(SIGPIPE, deadpeer);
882+#endif
883 #ifdef SIGWINCH
884 signal(SIGWINCH, sendwin);
885 #endif
886diff --git a/telnet/telnet.1 b/telnet/telnet.1
887index 54a47fb..8365e42 100644
888--- a/telnet/telnet.1
889+++ b/telnet/telnet.1
890@@ -42,8 +42,9 @@
891 protocol
892 .Sh SYNOPSIS
893 .Nm telnet
894-.Op Fl 8ELadr
895+.Op Fl 468ELadr
896 .Op Fl S Ar tos
897+.Op Fl b Ar address
898 .Op Fl e Ar escapechar
899 .Op Fl l Ar user
900 .Op Fl n Ar tracefile
901@@ -68,6 +69,10 @@ command implicitly; see the description below.
902 .Pp
903 Options:
904 .Bl -tag -width indent
905+.It Fl 4
906+Force IPv4 address resolution.
907+.It Fl 6
908+Force IPv6 address resolution.
909 .It Fl 8
910 Request 8-bit operation. This causes an attempt to negotiate the
911 .Dv TELNET BINARY
912@@ -89,6 +94,8 @@ of the
913 option if supported by the remote system. The username is retrieved
914 via
915 .Xr getlogin 3 .
916+.It Fl b Ar address
917+Use bind(2) on the local socket to bind it to a specific local address.
918 .It Fl d
919 Sets the initial value of the
920 .Ic debug
921@@ -474,17 +481,29 @@ protocol without making a mess. Protocol negotiation can be forced by
922 placing a dash before the port number.
923 .Pp
924 After establishing a connection, any commands associated with the
925-remote host in the user's
926+remote host in
927+.Pa /etc/telnetrc
928+and the user's
929 .Pa .telnetrc
930-file are executed.
931+file are executed, in that order.
932 .Pp
933-The format of the .telnetrc file is as follows: Lines beginning with a
934+The format of the telnetrc files is as follows: Lines beginning with a
935 #, and blank lines, are ignored. The rest of the file should consist
936 of hostnames and sequences of
937 .Nm telnet
938 commands to use with that host. Commands should be one per line,
939 indented by whitespace; lines beginning without whitespace are
940-interpreted as hostnames. Upon connecting to a particular host, the
941+interpreted as hostnames. Lines beginning with the special hostname
942+.Ql DEFAULT
943+will apply to all hosts. Hostnames including
944+.Ql DEFAULT
945+may be followed immediately by a colon and a port number or string.
946+If a port is specified it must match exactly with what is specified
947+on the command line. If no port was specified on the command line,
948+then the value
949+.Ql telnet
950+is used.
951+Upon connecting to a particular host, the
952 commands associated with that host are executed.
953 .It Ic quit
954 Close any open session and exit
955@@ -1184,9 +1203,7 @@ escape sequences are preceded by a '*' to aid in locating them.
956 When the skiprc toggle is
957 .Dv TRUE ,
958 .Tn telnet
959-does not read the
960-.Pa \&.telnetrc
961-file. The initial value for this toggle is
962+does not read the telnetrc files. The initial value for this toggle is
963 .Dv FALSE.
964 .It Ic termdata
965 Toggles the display of all terminal data (in hexadecimal format).
966@@ -1239,7 +1256,9 @@ to the other side via the
967 .Dv TELNET ENVIRON
968 option.
969 .Sh FILES
970-.Bl -tag -width ~/.telnetrc -compact
971+.Bl -tag -width /etc/telnetrc -compact
972+.It Pa /etc/telnetrc
973+global telnet startup values
974 .It Pa ~/.telnetrc
975 user customized telnet startup values
976 .El
977diff --git a/telnet/telnet.cc b/telnet/telnet.cc
978index 4fc3b1f..7eca811 100644
979--- a/telnet/telnet.cc
980+++ b/telnet/telnet.cc
981@@ -88,7 +88,8 @@ char do_dont_resp[256];
982 char will_wont_resp[256];
983
984 int
985-eight = 0,
986+ eight = 3,
987+ binary = 0,
988 autologin = 0, /* Autologin anyone? */
989 skiprc = 0,
990 connected,
991@@ -639,14 +640,14 @@ static const char *gettermname(void) {
992 if (resettermname) {
993 resettermname = 0;
994 tname = env_getvalue("TERM", 0);
995- if (!tname || my_setupterm(tname, 1, &err)) {
996+ if (!tname /* || my_setupterm(tname, 1, &err) */) {
997 termbuf[0] = 0;
998 tname = "UNKNOWN";
999 }
1000 mklist(termbuf, tname, termtypes);
1001 next = 0;
1002 }
1003- if (next==termtypes.num()) next = 0;
1004+ if (next==termtypes.num()-1) next = 0;
1005 return termtypes[next++];
1006 }
1007 /*
1008@@ -681,7 +682,7 @@ static void suboption(void) {
1009 }
1010 #endif /* TN3270 */
1011 name = gettermname();
1012- netoring.printf("%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
1013+ netoring.xprintf("%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
1014 TELQUAL_IS, name, IAC, SE);
1015 }
1016 break;
1017@@ -693,7 +694,7 @@ static void suboption(void) {
1018 if (SB_GET() == TELQUAL_SEND) {
1019 long oospeed, iispeed;
1020 TerminalSpeeds(&iispeed, &oospeed);
1021- netoring.printf("%c%c%c%c%ld,%ld%c%c", IAC, SB, TELOPT_TSPEED,
1022+ netoring.xprintf("%c%c%c%c%ld,%ld%c%c", IAC, SB, TELOPT_TSPEED,
1023 TELQUAL_IS, oospeed, iispeed, IAC, SE);
1024 }
1025 break;
1026@@ -780,7 +781,7 @@ static void suboption(void) {
1027 send_wont(TELOPT_XDISPLOC, 1);
1028 break;
1029 }
1030- netoring.printf("%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC,
1031+ netoring.xprintf("%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC,
1032 TELQUAL_IS, dp, IAC, SE);
1033 }
1034 break;
1035@@ -798,7 +799,7 @@ void lm_will(unsigned char *cmd, int len) {
1036 return;
1037 }
1038
1039- netoring.printf("%c%c%c%c%c%c%c", IAC, SB, TELOPT_LINEMODE,
1040+ netoring.xprintf("%c%c%c%c%c%c%c", IAC, SB, TELOPT_LINEMODE,
1041 DONT, cmd[0], IAC, SE);
1042 }
1043
1044@@ -815,7 +816,7 @@ void lm_do(unsigned char *cmd, int len) {
1045 /*@*/ printf("lm_do: no command!!!\n"); /* Should not happen... */
1046 return;
1047 }
1048- netoring.printf("%c%c%c%c%c%c%c", IAC, SB, TELOPT_LINEMODE,
1049+ netoring.xprintf("%c%c%c%c%c%c%c", IAC, SB, TELOPT_LINEMODE,
1050 WONT, cmd[0], IAC, SE);
1051 }
1052
1053@@ -838,7 +839,7 @@ void lm_mode(unsigned char *cmd, int len, int init) {
1054 k |= MODE_ACK;
1055 }
1056
1057- netoring.printf("%c%c%c%c%c%c%c", IAC, SB, TELOPT_LINEMODE, LM_MODE,
1058+ netoring.xprintf("%c%c%c%c%c%c%c", IAC, SB, TELOPT_LINEMODE, LM_MODE,
1059 k, IAC, SE);
1060
1061 setconnmode(0); /* set changed mode */
1062@@ -933,11 +934,11 @@ void slc_mode_import(int def) {
1063
1064 void slc_import(int def) {
1065 if (def) {
1066- netoring.printf("%c%c%c%c%c%c%c%c%c", IAC, SB, TELOPT_LINEMODE,
1067+ netoring.xprintf("%c%c%c%c%c%c%c%c%c", IAC, SB, TELOPT_LINEMODE,
1068 LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE);
1069 }
1070 else {
1071- netoring.printf("%c%c%c%c%c%c%c%c%c", IAC, SB, TELOPT_LINEMODE,
1072+ netoring.xprintf("%c%c%c%c%c%c%c%c%c", IAC, SB, TELOPT_LINEMODE,
1073 LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE);
1074 }
1075 }
1076@@ -1050,6 +1051,7 @@ void slc_check(void) {
1077
1078
1079 unsigned char slc_reply[128];
1080+unsigned char const * const slc_reply_eom = &slc_reply[sizeof(slc_reply)];
1081 unsigned char *slc_replyp;
1082
1083 void slc_start_reply(void) {
1084@@ -1061,6 +1063,14 @@ void slc_start_reply(void) {
1085 }
1086
1087 void slc_add_reply(int func, int flags, int value) {
1088+ /* A sequence of up to 6 bytes my be written for this member of the SLC
1089+ * suboption list by this function. The end of negotiation command,
1090+ * which is written by slc_end_reply(), will require 2 additional
1091+ * bytes. Do not proceed unless there is sufficient space for these
1092+ * items.
1093+ */
1094+ if (&slc_replyp[6+2] > slc_reply_eom)
1095+ return;
1096 if ((*slc_replyp++ = func) == IAC)
1097 *slc_replyp++ = IAC;
1098 if ((*slc_replyp++ = flags) == IAC)
1099@@ -1142,6 +1152,7 @@ void env_opt(unsigned char *buf, int len) {
1100 }
1101 }
1102
1103+/* OPT_REPLY_SIZE must be a multiple of 2. */
1104 #define OPT_REPLY_SIZE 256
1105 unsigned char *opt_reply;
1106 unsigned char *opt_replyp;
1107@@ -1173,6 +1184,7 @@ void env_opt_start_info(void) {
1108
1109 void env_opt_add(const char *ep) {
1110 const char *vp;
1111+ const unsigned char *tp;
1112 unsigned char c;
1113
1114 if (opt_reply == NULL) /*XXX*/
1115@@ -1185,11 +1197,12 @@ void env_opt_add(const char *ep) {
1116 return;
1117 }
1118 vp = env_getvalue(ep, 1);
1119- if (opt_replyp + (vp ? strlen(vp) : 0) + strlen(ep) + 6 > opt_replyend)
1120+ tp = opt_replyp + (vp ? strlen(vp) * 2 : 0) + strlen(ep) * 2 + 6;
1121+ if (tp > opt_replyend)
1122 {
1123 register int len;
1124- opt_replyend += OPT_REPLY_SIZE;
1125- len = opt_replyend - opt_reply;
1126+ len = ((tp - opt_reply) + OPT_REPLY_SIZE - 1) & ~(OPT_REPLY_SIZE - 1);
1127+ opt_replyend = opt_reply + len;
1128 opt_reply = (unsigned char *)realloc(opt_reply, len);
1129 if (opt_reply == NULL) {
1130 /*@*/ printf("env_opt_add: realloc() failed!!!\n");
1131@@ -1740,8 +1753,8 @@ void telnet(const char * /*user*/) {
1132 send_do(TELOPT_STATUS, 1);
1133 if (env_getvalue("DISPLAY", 0))
1134 send_will(TELOPT_XDISPLOC, 1);
1135- if (eight)
1136- tel_enter_binary(eight);
1137+ if (binary)
1138+ tel_enter_binary(binary);
1139 }
1140 #endif /* !defined(TN3270) */
1141
1142diff --git a/telnet/terminal.cc b/telnet/terminal.cc
1143index 9eb47ae..764f18f 100644
1144--- a/telnet/terminal.cc
1145+++ b/telnet/terminal.cc
1146@@ -45,6 +45,8 @@ char terminal_rcsid[] =
1147 #include <signal.h>
1148 #include <errno.h>
1149 #include <stdio.h>
1150+#include <string.h>
1151+#include <stdlib.h>
1152
1153 #include "ring.h"
1154 #include "defines.h"
1155@@ -155,9 +157,11 @@ int getconnmode(void) {
1156 if (localflow)
1157 mode |= MODE_FLOW;
1158
1159- if (my_want_state_is_will(TELOPT_BINARY))
1160+ if ((eight & 1) || my_want_state_is_will(TELOPT_BINARY))
1161 mode |= MODE_INBIN;
1162
1163+ if (eight & 2)
1164+ mode |= MODE_OUT8;
1165 if (his_want_state_is_will(TELOPT_BINARY))
1166 mode |= MODE_OUTBIN;
1167
1168@@ -449,10 +453,13 @@ void TerminalNewMode(int f)
1169 // breaks SunOS.
1170 tmp_tc.c_iflag |= ISTRIP;
1171 }
1172- if (f & MODE_OUTBIN) {
1173+ if (f & (MODE_OUTBIN|MODE_OUT8)) {
1174 tmp_tc.c_cflag &= ~(CSIZE|PARENB);
1175 tmp_tc.c_cflag |= CS8;
1176- tmp_tc.c_oflag &= ~OPOST;
1177+ if (f & MODE_OUTBIN)
1178+ tmp_tc.c_oflag &= ~OPOST;
1179+ else
1180+ tmp_tc.c_oflag |= OPOST;
1181 } else {
1182 tmp_tc.c_cflag &= ~(CSIZE|PARENB);
1183 tmp_tc.c_cflag |= old_tc.c_cflag & (CSIZE|PARENB);
1184@@ -468,7 +475,7 @@ void TerminalNewMode(int f)
1185
1186 #ifdef SIGINFO
1187 signal(SIGINFO, ayt);
1188-#endif SIGINFO
1189+#endif /* SIGINFO */
1190
1191 #if defined(NOKERNINFO)
1192 tmp_tc.c_lflag |= NOKERNINFO;
1193@@ -504,7 +511,7 @@ void TerminalNewMode(int f)
1194
1195 #ifdef SIGINFO
1196 signal(SIGINFO, ayt_status);
1197-#endif SIGINFO
1198+#endif /* SIGINFO */
1199
1200 #ifdef SIGTSTP
1201 signal(SIGTSTP, SIG_DFL);
1202diff --git a/telnet/utilities.cc b/telnet/utilities.cc
1203index 0448f0a..66839ab 100644
1204--- a/telnet/utilities.cc
1205+++ b/telnet/utilities.cc
1206@@ -47,6 +47,8 @@ char util_rcsid[] =
1207 #include <sys/socket.h>
1208 #include <unistd.h>
1209 #include <ctype.h>
1210+#include <string.h>
1211+#include <stdlib.h>
1212
1213 #include "ring.h"
1214 #include "defines.h"
1215--
12161.8.4.2
1217